Skip to content

fix(provider): retry transient response failures safely - #244

Merged
omarluq merged 3 commits into
mainfrom
fix/provider-transient-retries
Jul 29, 2026
Merged

fix(provider): retry transient response failures safely#244
omarluq merged 3 commits into
mainfrom
fix/provider-transient-retries

Conversation

@omarluq

@omarluq omarluq commented Jul 29, 2026

Copy link
Copy Markdown
Owner

No description provided.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0167c0e5-639d-4497-8a91-2df688ff5bef

📥 Commits

Reviewing files that changed from the base of the PR and between 8ad19b1 and c4e8146.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (25)
  • internal/assistant/client.go
  • internal/assistant/client_adapter.go
  • internal/assistant/client_adapter_internal_test.go
  • internal/assistant/context_build.go
  • internal/assistant/context_compaction.go
  • internal/assistant/context_overflow_compaction.go
  • internal/assistant/context_overflow_compaction_test.go
  • internal/assistant/export_test.go
  • internal/assistant/llm_conversion_internal_test.go
  • internal/assistant/provider_hooks_internal_test.go
  • internal/assistant/retry.go
  • internal/assistant/retry_internal_test.go
  • internal/assistant/retry_test.go
  • internal/assistant/runtime_events.go
  • internal/assistant/runtime_model.go
  • internal/assistant/runtime_test.go
  • internal/assistant/tool_schema_cache_internal_test.go
  • internal/provider/client_internal_test.go
  • internal/provider/errors.go
  • internal/provider/errors_internal_test.go
  • internal/provider/http.go
  • internal/provider/http_internal_test.go
  • internal/provider/openai_responses_sse.go
  • internal/terminal/async_events.go
  • internal/terminal/async_events_internal_test.go
🚧 Files skipped from review as they are similar to previous changes (20)
  • internal/assistant/context_overflow_compaction.go
  • internal/assistant/export_test.go
  • internal/assistant/provider_hooks_internal_test.go
  • internal/assistant/client.go
  • internal/assistant/llm_conversion_internal_test.go
  • internal/assistant/context_build.go
  • internal/assistant/tool_schema_cache_internal_test.go
  • internal/assistant/context_compaction.go
  • internal/terminal/async_events.go
  • internal/assistant/client_adapter_internal_test.go
  • internal/provider/http.go
  • internal/assistant/retry_test.go
  • internal/assistant/runtime_events.go
  • internal/provider/errors_internal_test.go
  • internal/provider/openai_responses_sse.go
  • internal/provider/errors.go
  • internal/assistant/context_overflow_compaction_test.go
  • internal/provider/client_internal_test.go
  • internal/assistant/retry.go
  • internal/assistant/runtime_model.go

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Prevented automatic retries or context recovery after tool execution starts, avoiding duplicate side effects.
    • Improved provider retry decisions by honoring bounded, provider-specified retry-after timing and refining retryable vs non-retryable classifications.
    • Enhanced provider error diagnostics by preserving/merging structured request and response details (including IDs and retry timing).
    • Reset streaming text/thinking and tool-related state when a prompt retry begins, ensuring clean restart behavior.

Walkthrough

The change adds tool-side-effect tracking, prevents retries and context recovery after tool execution, enriches provider errors with retry and request metadata, expands retry classification, adds structured provider logging, and resets terminal streaming state during retry starts.

Changes

Assistant runtime and provider error handling

Layer / File(s) Summary
Completion request state wiring
internal/assistant/client.go, internal/assistant/client_adapter.go, internal/assistant/context_*.go, internal/assistant/*_test.go
CompletionRequest now tracks ToolSideEffectsStarted, with request constructors and fixtures initializing the field.
Side-effect-aware completion recovery
internal/assistant/runtime_model.go, internal/assistant/context_overflow_compaction.go, internal/assistant/runtime_test.go, internal/assistant/context_overflow_compaction_test.go
Tool execution marks the request before delegation; retries and provider-context recovery are skipped after side effects begin.
Provider error metadata and retry policy
internal/provider/errors.go, internal/provider/http.go, internal/provider/openai_responses_sse.go, internal/assistant/retry.go, internal/assistant/runtime_events.go, internal/provider/*_test.go, internal/assistant/retry*_test.go
Provider errors retain request IDs and retry delays, SSE failures preserve structured metadata, retry classification and backoff use expanded provider signals, and provider failures are logged with structured attributes.
Terminal retry state reset
internal/terminal/async_events.go, internal/terminal/async_events_internal_test.go
Retry-start events clear streaming text, blocks, running tools, and streamed tool-event counts.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Completion
  participant ToolExecutor
  participant RetryController
  Completion->>ToolExecutor: Execute tools
  ToolExecutor-->>Completion: Tool execution begins
  Completion->>RetryController: Return completion error
  RetryController->>RetryController: Check ToolSideEffectsStarted
  RetryController-->>Completion: Return original error without retry
Loading
sequenceDiagram
  participant ProviderHTTP
  participant ProviderError
  participant RetryController
  ProviderHTTP->>ProviderError: Parse status, request ID, and retry headers
  ProviderError-->>RetryController: Return structured StatusError
  RetryController->>RetryController: Classify provider code and message
  RetryController-->>ProviderHTTP: Apply provider or fallback delay
Loading

Possibly related PRs

Poem

A rabbit hops where retries ran,
“No second burrow,” says the plan.
Tool tracks glow and errors call,
Provider clues now tell it all.
Fresh streams bloom when retries start.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No description was provided, so there is no meaningful summary to evaluate. Add a brief PR description summarizing the provider retry and error-handling changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: safer retries for transient provider response failures.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/provider-transient-retries

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.78261% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.78%. Comparing base (d1bcd4e) to head (c4e8146).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
internal/assistant/runtime_events.go 57.14% 3 Missing and 3 partials ⚠️
internal/assistant/retry.go 92.45% 2 Missing and 2 partials ⚠️
internal/provider/openai_responses_sse.go 95.23% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #244      +/-   ##
==========================================
+ Coverage   84.72%   84.78%   +0.06%     
==========================================
  Files         316      316              
  Lines       29553    29691     +138     
==========================================
+ Hits        25039    25174     +135     
- Misses       3093     3094       +1     
- Partials     1421     1423       +2     
Flag Coverage Δ
unittests 84.78% <94.78%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
internal/provider/errors.go (1)

23-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Provider error context-key strings are duplicated as magic literals across the package boundary instead of shared constants.

internal/provider/errors.go defines providerRequestIDContextKey/providerResponseIDContextKey (plus pre-existing providerCodeContextKey/providerTypeContextKey) as unexported constants, so internal/assistant cannot reference them and instead re-hardcodes the raw strings in two places. If these keys are ever renamed in the provider package, both consumers silently stop matching (no compile error), degrading retry classification and structured logging without any test failure signal.

  • internal/provider/errors.go#L23-L24: export these context-key constants (and the existing code/type ones) so consumers can reference them directly.
  • internal/assistant/retry.go#L213-L236: replace the "provider_code"/"provider_type" literals in providerFailureCode/providerErrorContextString calls with the exported constants.
  • internal/assistant/runtime_events.go#L88-L94: replace the "provider_request_id"/"provider_response_id" literals with the exported constants.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/provider/errors.go` around lines 23 - 24, Export all provider error
context-key constants in internal/provider/errors.go, including the existing
code/type keys and request/response ID keys. In internal/assistant/retry.go
lines 213-236, replace the provider_code and provider_type literals with the
exported constants; in internal/assistant/runtime_events.go lines 88-94, replace
the request/response ID literals similarly, using the exported symbols in
providerFailureCode and providerErrorContextString calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/assistant/retry.go`:
- Around line 110-117: The provider retry delay can overflow during parsing and
bypass configured retry limits. In internal/assistant/retry.go:110-117, update
providerRetryDelay to cap statusErr.RetryAfter at the configured sane maximum
before returning it; in internal/provider/http.go:87-108, add a fixed ceiling
before converting parsed Retry-After values to time.Duration to prevent
multiplication overflow, and update or remove the comment claiming callers
perform the cap.

In `@internal/assistant/runtime_events.go`:
- Around line 76-98: Update the provider failure logging in the runtime logger
block to replace slog.Any("error", err) with a sanitized slog.String containing
err.Error(). Preserve the existing provider, model, API, attempt, provider_code,
provider_request_id, and provider_response_id attributes.

In `@internal/assistant/runtime_test.go`:
- Line 7: Update the error wrapping in the affected test near the tool execution
assertion to use the existing oops.In("assistant_test").Code(...).Wrapf(...)
pattern instead of fmt.Errorf. Remove the fmt import if it is no longer used,
while preserving the existing error context and message.

---

Nitpick comments:
In `@internal/provider/errors.go`:
- Around line 23-24: Export all provider error context-key constants in
internal/provider/errors.go, including the existing code/type keys and
request/response ID keys. In internal/assistant/retry.go lines 213-236, replace
the provider_code and provider_type literals with the exported constants; in
internal/assistant/runtime_events.go lines 88-94, replace the request/response
ID literals similarly, using the exported symbols in providerFailureCode and
providerErrorContextString calls.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d0de0d54-dec0-4165-bfcc-8bde6ad1e8dc

📥 Commits

Reviewing files that changed from the base of the PR and between bb497cd and 8ad19b1.

📒 Files selected for processing (24)
  • internal/assistant/client.go
  • internal/assistant/client_adapter.go
  • internal/assistant/client_adapter_internal_test.go
  • internal/assistant/context_build.go
  • internal/assistant/context_compaction.go
  • internal/assistant/context_overflow_compaction.go
  • internal/assistant/context_overflow_compaction_test.go
  • internal/assistant/export_test.go
  • internal/assistant/llm_conversion_internal_test.go
  • internal/assistant/provider_hooks_internal_test.go
  • internal/assistant/retry.go
  • internal/assistant/retry_internal_test.go
  • internal/assistant/retry_test.go
  • internal/assistant/runtime_events.go
  • internal/assistant/runtime_model.go
  • internal/assistant/runtime_test.go
  • internal/assistant/tool_schema_cache_internal_test.go
  • internal/provider/client_internal_test.go
  • internal/provider/errors.go
  • internal/provider/errors_internal_test.go
  • internal/provider/http.go
  • internal/provider/openai_responses_sse.go
  • internal/terminal/async_events.go
  • internal/terminal/async_events_internal_test.go

Comment thread internal/assistant/retry.go
Comment thread internal/assistant/runtime_events.go
Comment thread internal/assistant/runtime_test.go Outdated
@omarluq
omarluq force-pushed the fix/provider-transient-retries branch from 8ad19b1 to c4e8146 Compare July 29, 2026 20:02
@sonarqubecloud

Copy link
Copy Markdown

@omarluq
omarluq merged commit f28ce46 into main Jul 29, 2026
13 checks passed
@omarluq
omarluq deleted the fix/provider-transient-retries branch July 29, 2026 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant