@@ -6,6 +6,8 @@ import (
66 "errors"
77 "fmt"
88 "io"
9+ "regexp"
10+ "strconv"
911 "time"
1012
1113 "github.com/anthropics/anthropic-sdk-go"
@@ -19,9 +21,10 @@ import (
1921)
2022
2123type anthropicClient struct {
22− providerOptions providerClientOptions
23− useBedrock bool
24− client anthropic.Client
24+ providerOptions providerClientOptions
25+ useBedrock bool
26+ client anthropic.Client
27+ adjustedMaxTokens int // Used when context limit is hit
2528}
2629
2730type AnthropicClient ProviderClient
@@ -171,6 +174,11 @@ func (a *anthropicClient) preparedMessages(messages []anthropic.MessageParam, to
171174 maxTokens = a.providerOptions.maxTokens
172175 }
173176
177+ // Use adjusted max tokens if context limit was hit
178+ if a.adjustedMaxTokens > 0 {
179+ maxTokens = int64(a.adjustedMaxTokens)
180+ }
181+
174182 return anthropic.MessageNewParams{
175183 Model: anthropic.Model(model.ID),
176184 MaxTokens: maxTokens,
@@ -190,16 +198,18 @@ func (a *anthropicClient) preparedMessages(messages []anthropic.MessageParam, to
190198}
191199
192200func (a *anthropicClient) send(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (response *ProviderResponse, err error) {
193− preparedMessages := a.preparedMessages(a.convertMessages(messages), a.convertTools(tools))
194201 cfg := config.Get()
195− if cfg.Options.Debug {
196− jsonData, _ := json.Marshal(preparedMessages)
197− logging.Debug("Prepared messages", "messages", string(jsonData))
198− }
199202
200203 attempts := 0
201204 for {
202205 attempts++
206+ // Prepare messages on each attempt in case max_tokens was adjusted
207+ preparedMessages := a.preparedMessages(a.convertMessages(messages), a.convertTools(tools))
208+ if cfg.Options.Debug {
209+ jsonData, _ := json.Marshal(preparedMessages)
210+ logging.Debug("Prepared messages", "messages", string(jsonData))
211+ }
212+
203213 anthropicResponse, err := a.client.Messages.New(
204214 ctx,
205215 preparedMessages,
@@ -239,17 +249,19 @@ func (a *anthropicClient) send(ctx context.Context, messages []message.Message,
239249}
240250
241251func (a *anthropicClient) stream(ctx context.Context, messages []message.Message, tools []tools.BaseTool) <-chan ProviderEvent {
242− preparedMessages := a.preparedMessages(a.convertMessages(messages), a.convertTools(tools))
243252 cfg := config.Get()
244− if cfg.Options.Debug {
245− // jsonData, _ := json.Marshal(preparedMessages)
246− // logging.Debug("Prepared messages", "messages", string(jsonData))
247− }
248253 attempts := 0
249254 eventChan := make(chan ProviderEvent)
250255 go func() {
251256 for {
252257 attempts++
258+ // Prepare messages on each attempt in case max_tokens was adjusted
259+ preparedMessages := a.preparedMessages(a.convertMessages(messages), a.convertTools(tools))
260+ if cfg.Options.Debug {
261+ jsonData, _ := json.Marshal(preparedMessages)
262+ logging.Debug("Prepared messages", "messages", string(jsonData))
263+ }
264+
253265 anthropicStream := a.client.Messages.NewStreaming(
254266 ctx,
255267 preparedMessages,
@@ -395,6 +407,15 @@ func (a *anthropicClient) shouldRetry(attempts int, err error) (bool, int64, err
395407 return true, 0, nil
396408 }
397409
410+ // Handle context limit exceeded error (400 Bad Request)
411+ if apiErr.StatusCode == 400 {
412+ if adjusted, ok := a.handleContextLimitError(apiErr); ok {
413+ a.adjustedMaxTokens = adjusted
414+ logging.Debug("Adjusted max_tokens due to context limit", "new_max_tokens", adjusted)
415+ return true, 0, nil
416+ }
417+ }
418+
398419 if apiErr.StatusCode != 429 && apiErr.StatusCode != 529 {
399420 return false, 0, err
400421 }
@@ -413,6 +434,33 @@ func (a *anthropicClient) shouldRetry(attempts int, err error) (bool, int64, err
413434 return true, int64(retryMs), nil
414435}
415436
437+// handleContextLimitError parses context limit error and returns adjusted max_tokens
438+func (a *anthropicClient) handleContextLimitError(apiErr *anthropic.Error) (int, bool) {
439+ // Parse error message like: "input length and max_tokens exceed context limit: 154978 + 50000 > 200000"
440+ errorMsg := apiErr.Error()
441+ re := regexp.MustCompile(`input length and max_tokens exceed context limit: (\d+) \+ (\d+) > (\d+)`)
442+ matches := re.FindStringSubmatch(errorMsg)
443+
444+ if len(matches) != 4 {
445+ return 0, false
446+ }
447+
448+ inputTokens, err1 := strconv.Atoi(matches[1])
449+ contextLimit, err2 := strconv.Atoi(matches[3])
450+
451+ if err1 != nil || err2 != nil {
452+ return 0, false
453+ }
454+
455+ // Calculate safe max_tokens with a buffer of 1000 tokens
456+ safeMaxTokens := contextLimit - inputTokens - 1000
457+
458+ // Ensure we don't go below a minimum threshold
459+ safeMaxTokens = max(safeMaxTokens, 1000)
460+
461+ return safeMaxTokens, true
462+}
463+
416464func (a *anthropicClient) toolCalls(msg anthropic.Message) []message.ToolCall {
417465 var toolCalls []message.ToolCall
418466