on main help sign in
chore: small fix
c5d7e90Kujtim Hoxha
internal/llm/agent/agent.go+6
@@ -420,6 +420,12 @@ func (a *agent) processGeneration(ctx context.Context, sessionID, content string
420 msgHistory = append(msgHistory, agentMessage, *toolResults)
420 msgHistory = append(msgHistory, agentMessage, *toolResults)
421 continue
421 continue
422 }
422 }
423+ if agentMessage.FinishReason() == "" {
424+ // Kujtim: could not track down where this is happening but this means its cancelled
425+ agentMessage.AddFinish(message.FinishReasonCanceled, "Request cancelled", "")
426+ _ = a.messages.Update(context.Background(), agentMessage)
427+ return a.err(ErrRequestCancelled)
428+ }
423 return AgentEvent{
429 return AgentEvent{
424 Type: AgentEventTypeResponse,
430 Type: AgentEventTypeResponse,
425 Message: agentMessage,
431 Message: agentMessage,
internal/llm/provider/openai.go+31−17
@@ -319,6 +319,10 @@ func (o *openaiClient) stream(ctx context.Context, messages []message.Message, t
319 go func() {
319 go func() {
320 for {
320 for {
321 attempts++
321 attempts++
322+ // Kujtim: fixes an issue with anthropig models on openrouter
323+ if len(params.Tools) == 0 {
324+ params.Tools = nil
325+ }
322 openaiStream := o.client.Chat.Completions.NewStreaming(
326 openaiStream := o.client.Chat.Completions.NewStreaming(
323 ctx,
327 ctx,
324 params,
328 params,
@@ -484,31 +488,41 @@ func (o *openaiClient) stream(ctx context.Context, messages []message.Message, t
484}
488}
485
489
486func (o *openaiClient) shouldRetry(attempts int, err error) (bool, int64, error) {
490func (o *openaiClient) shouldRetry(attempts int, err error) (bool, int64, error) {
487− var apiErr *openai.Error
488− if !errors.As(err, &apiErr) {
489− return false, 0, err
490− }
491−
492 if attempts > maxRetries {
491 if attempts > maxRetries {
493 return false, 0, fmt.Errorf("maximum retry attempts reached for rate limit: %d retries", maxRetries)
492 return false, 0, fmt.Errorf("maximum retry attempts reached for rate limit: %d retries", maxRetries)
494 }
493 }
494+ if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
495+ return false, 0, err
496+ }
497+ var apiErr *openai.Error
498+ retryMs := 0
499+ retryAfterValues := []string{}
500+ if errors.As(err, &apiErr) {
501+ // Check for token expiration (401 Unauthorized)
502+ if apiErr.StatusCode == 401 {
503+ o.providerOptions.apiKey, err = config.Get().Resolve(o.providerOptions.config.APIKey)
504+ if err != nil {
505+ return false, 0, fmt.Errorf("failed to resolve API key: %w", err)
506+ }
507+ o.client = createOpenAIClient(o.providerOptions)
508+ return true, 0, nil
509+ }
495
510
496− // Check for token expiration (401 Unauthorized)
497− if apiErr.StatusCode == 401 {
511+ if apiErr.StatusCode != 429 && apiErr.StatusCode != 500 {
498− o.providerOptions.apiKey, err = config.Get().Resolve(o.providerOptions.config.APIKey)
499− if err != nil {
500− return false, 0, fmt.Errorf("failed to resolve API key: %w", err)
512+ return false, 0, err
501 }
513 }
502− o.client = createOpenAIClient(o.providerOptions)
503− return true, 0, nil
504− }
505
514
506− if apiErr.StatusCode != 429 && apiErr.StatusCode != 500 {
515+ retryAfterValues = apiErr.Response.Header.Values("Retry-After")
507− return false, 0, err
508 }
516 }
509
517
510− retryMs := 0
518+ if apiErr != nil {
511− retryAfterValues := apiErr.Response.Header.Values("Retry-After")
519+ slog.Warn("OpenAI API error", "status_code", apiErr.StatusCode, "message", apiErr.Message, "type", apiErr.Type)
520+ if len(retryAfterValues) > 0 {
521+ slog.Warn("Retry-After header", "values", retryAfterValues)
522+ }
523+ } else {
524+ slog.Warn("OpenAI API error", "error", err.Error())
525+ }
512
526
513 backoffMs := 2000 * (1 << (attempts - 1))
527 backoffMs := 2000 * (1 << (attempts - 1))
514 jitterMs := int(float64(backoffMs) * 0.2)
528 jitterMs := int(float64(backoffMs) * 0.2)