Skip to content

Commit e94c9d5

Browse files
authored
fix: Don't retry OpenAI calls on 400 errors; Better Error Messages (#213)
* better error messages * don't retry on 400 errors * BadRequest errors should be HTTP400 responses
1 parent d6e6c8d commit e94c9d5

File tree

7 files changed

+60
-10
lines changed

7 files changed

+60
-10
lines changed

pkg/extractors/summarizer.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,10 @@ func incrementalSummarizer(
316316
return summary, tokensUsed, nil
317317
}
318318

319-
func generateProgressiveSummarizerPrompt(appState *models.AppState, promptData SummaryPromptTemplateData) (string, error) {
319+
func generateProgressiveSummarizerPrompt(
320+
appState *models.AppState,
321+
promptData SummaryPromptTemplateData,
322+
) (string, error) {
320323
customSummaryPromptTemplateAnthropic := appState.Config.CustomPrompts.SummarizerPrompts.Anthropic
321324
customSummaryPromptTemplateOpenAI := appState.Config.CustomPrompts.SummarizerPrompts.OpenAI
322325

pkg/llms/llm_base.go

+26-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package llms
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"time"
78

89
"github.com/getzep/zep/pkg/models"
@@ -131,13 +132,32 @@ func Float64ToFloat32Matrix(in [][]float64) [][]float32 {
131132
}
132133

133134
func NewRetryableHTTPClient(retryMax int, timeout time.Duration) *retryablehttp.Client {
134-
retryableHttpClient := retryablehttp.NewClient()
135-
retryableHttpClient.RetryMax = retryMax
136-
retryableHttpClient.HTTPClient.Timeout = timeout
137-
retryableHttpClient.Logger = log
138-
retryableHttpClient.Backoff = retryablehttp.DefaultBackoff
135+
retryableHTTPClient := retryablehttp.NewClient()
136+
retryableHTTPClient.RetryMax = retryMax
137+
retryableHTTPClient.HTTPClient.Timeout = timeout
138+
retryableHTTPClient.Logger = log
139+
retryableHTTPClient.Backoff = retryablehttp.DefaultBackoff
140+
retryableHTTPClient.CheckRetry = retryPolicy
141+
142+
return retryableHTTPClient
143+
}
144+
145+
// retryPolicy is a retryablehttp.CheckRetry function. It is used to determine
146+
// whether a request should be retried or not.
147+
func retryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
148+
// do not retry on context.Canceled or context.DeadlineExceeded
149+
if ctx.Err() != nil {
150+
return false, ctx.Err()
151+
}
152+
153+
// Do not retry 400 errors as they're used by OpenAI to indicate maximum
154+
// context length exceeded
155+
if resp != nil && resp.StatusCode == 400 {
156+
return false, err
157+
}
139158

140-
return retryableHttpClient
159+
shouldRetry, _ := retryablehttp.DefaultRetryPolicy(ctx, resp, err)
160+
return shouldRetry, nil
141161
}
142162

143163
// useOpenAIEmbeddings is true if OpenAI embeddings are enabled

pkg/server/handlertools/tools.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010

1111
"github.com/getzep/zep/internal"
12+
"github.com/getzep/zep/pkg/models"
1213

1314
"github.com/go-chi/chi/v5"
1415
"github.com/google/uuid"
@@ -71,7 +72,7 @@ func RenderError(w http.ResponseWriter, err error, status int) {
7172
// Don't log not found errors
7273
log.Error(err)
7374
}
74-
if strings.Contains(err.Error(), "is deleted") {
75+
if strings.Contains(err.Error(), "is deleted") || errors.Is(err, models.ErrBadRequest) {
7576
status = http.StatusBadRequest
7677
}
7778
http.Error(w, err.Error(), status)

pkg/store/postgres/documents.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/getzep/zep/pkg/models"
1212
"github.com/google/uuid"
1313
"github.com/uptrace/bun"
14+
"github.com/uptrace/bun/driver/pgdriver"
1415
)
1516

1617
func NewDocumentCollectionDAO(
@@ -65,8 +66,8 @@ func (dc *DocumentCollectionDAO) Create(
6566
Returning("*").
6667
Exec(ctx)
6768
if err != nil {
68-
if strings.Contains(err.Error(), "duplicate key value violates unique constraint") {
69-
return fmt.Errorf("collection with name %s already exists", dc.Name)
69+
if err, ok := err.(pgdriver.Error); ok && err.IntegrityViolation() {
70+
return models.NewBadRequestError("collection already exists: " + dc.Name)
7071
}
7172
return fmt.Errorf("failed to insert collection: %w", err)
7273
}
@@ -270,6 +271,9 @@ func (dc *DocumentCollectionDAO) CreateDocuments(
270271
Returning("uuid").
271272
Exec(ctx)
272273
if err != nil {
274+
if err, ok := err.(pgdriver.Error); ok && err.IntegrityViolation() {
275+
return nil, models.NewBadRequestError("document_id already exists")
276+
}
273277
if strings.Contains(err.Error(), "different vector dimensions") {
274278
return nil, store.NewEmbeddingMismatchError(err)
275279
}

pkg/store/postgres/session.go

+12
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import (
55
"database/sql"
66
"errors"
77
"fmt"
8+
"strings"
89
"sync"
910
"time"
1011

1112
"github.com/getzep/zep/pkg/models"
1213
"github.com/uptrace/bun"
14+
"github.com/uptrace/bun/driver/pgdriver"
1315
)
1416

1517
var _ models.SessionManager = &SessionDAO{}
@@ -47,6 +49,16 @@ func (dao *SessionDAO) Create(
4749
Returning("*").
4850
Exec(ctx)
4951
if err != nil {
52+
if err, ok := err.(pgdriver.Error); ok && err.IntegrityViolation() {
53+
if strings.Contains(err.Error(), "user") {
54+
return nil, models.NewBadRequestError(
55+
"user does not exist with user_id: " + *session.UserID,
56+
)
57+
}
58+
return nil, models.NewBadRequestError(
59+
"session already exists with session_id: " + session.SessionID,
60+
)
61+
}
5062
return nil, fmt.Errorf("failed to create session: %w", err)
5163
}
5264

pkg/store/postgres/userstore.go

+6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/getzep/zep/pkg/models"
1111
"github.com/uptrace/bun"
12+
"github.com/uptrace/bun/driver/pgdriver"
1213
)
1314

1415
var _ models.UserStore = &UserStoreDAO{}
@@ -37,6 +38,11 @@ func (dao *UserStoreDAO) Create(
3738
}
3839
_, err := dao.db.NewInsert().Model(userDB).Returning("*").Exec(ctx)
3940
if err != nil {
41+
if err, ok := err.(pgdriver.Error); ok && err.IntegrityViolation() {
42+
return nil, models.NewBadRequestError(
43+
"user already exists with user_id: " + user.UserID,
44+
)
45+
}
4046
return nil, err
4147
}
4248

pkg/store/postgres/userstore_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package postgres
33
import (
44
"context"
55
"testing"
6+
"time"
67

78
"github.com/getzep/zep/pkg/testutils"
89

@@ -66,6 +67,9 @@ func TestUserStoreDAO(t *testing.T) {
6667
createdUser, err := userStore.Create(ctx, user)
6768
assert.NoError(t, err)
6869

70+
// Wait a second
71+
<-time.After(1 * time.Second)
72+
6973
// Update the user with zero values
7074
userUpdate := &models.UpdateUserRequest{
7175
UserID: user.UserID,

0 commit comments

Comments
 (0)