Skip to content

fix(session): recover from stalled model requests - #1426

Open
anandgupta42 wants to merge 11 commits into
mainfrom
fix/stalled-request-timeout
Open

anandgupta42 wants to merge 11 commits into
mainfrom
fix/stalled-request-timeout

Conversation

@anandgupta42

@anandgupta42 anandgupta42 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

Closes #1424

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Why. A session never recovers when a model request goes quiet. In a recorded benchmark, 10 of 135 sessions on one model (GPT-6.1 Sol via Bedrock Mantle) logged a request and then nothing until the harness killed them at its 30 minute limit: no error, no retry, and in 7 of the 10 the finish-time validators never ran. (10 of 135: estimate from recorded data.)

Root cause (verified in code).

  • No first-byte timeout was armed for most providers (only OpenAI and Altimate Base set one), so a request the server never answered waited forever.
  • The existing 5 minute idle watchdog fired, but its error became an unknown error that was not retried, so the session ended.
  • Bedrock Converse event streams are binary, not SSE, and bypassed the idle watchdog.
  • A retry after a mid-stream failure left the failed attempt's text and reasoning in the message, and re-requesting after a dispatched tool call could re-run the tool.

What changed (before, after).

  • Never answered: hung, now aborted at 300s and retried. Silent mid-stream: ended as an error, now retried. Reset mid-stream: retried but partial output stayed, now removed first.
  • Upstream OpenCode already maps both timeouts to retryable errors and defaults the header timeout to 300s (dev #46903). This aligns with that (here only the idle watchdog's stream error is made retryable) and adds the partial-output rule and the Converse coverage. Defaults: first byte 300s (new), idle 300s (unchanged). The slowest healthy generation in 6,586 recorded steps was 51s.
  • Partial-output rule: before a retry, text, reasoning, step-start and still-pending tool parts written by the failed attempt are removed. If a tool's execute() began (counted at the tool wrapper) or a step finished, it is not retried (a tool is never re-run) and the error says why.
  • After 5 retries the session ends with "The model stopped responding ... gave up after 5 retries". A user cancel is never retried and still ends the wait at once.
  • Config: provider options headerTimeout and chunkTimeout (ms; headerTimeout false disables the check), see providers.md.

Spec. A stalled request is aborted and retried with the existing backoff at most 5 times; partial output is never duplicated; a dispatched tool is never re-run; exhaustion ends with a clear error; cancel is immediate.

Tenant/user impact. A request silent for 300s is now retried instead of hanging. Users could also notice: (1) a persistent stall takes about 31 minutes to surface at the default (6 attempts of 300s plus backoff), so lower headerTimeout where that matters; (2) the 300s first-byte deadline now also bounds custom fetches such as Vertex credential acquisition; a healthy request silent for over 300s before headers (slow local prompt evaluation, non-streaming calls) would be cut off, so raise headerTimeout there; (3) the no-retry-after-started-tool rule covers every retryable error: a mid-stream 5xx after a tool started used to be retried (re-running the tool) and now ends with an error, and, as for any errored step, its tool history is not replayed next turn; (4) the TUI shows "Model stopped responding" for the exhausted error; (5) a Stop just before a backoff ends the wait at once. Validators are unchanged: they run after a clean stop, so a recovered stall reaches them; an exhausted one skips them.

Deployment readiness. No migration, dependency or config; revert restores old behaviour.

How did you verify your code works?

  • Unit: error classification, abort stays an abort, discard rule, tool-call ids.
  • Integration with real components: the real session processor, LLM stream, provider fetch wrapper and AI SDK against a local raw TCP server speaking the OpenAI-compatible streaming protocol: never answered, silent mid-stream, Converse content type, socket reset, partial, dispatched and in-flight tool calls (tool runs once), bounded retries (6 requests), cancel during the wait and the backoff, a slow healthy stream not cut off, all timers cleared, the 300s default armed. 26 tests in the new file pass; on main 13 of the first 19 fail (the rest are guards and tests of the new module).
  • Reproduction with defaults: on main a silent server left the session pending for 170s until stopped; with the change it recovered after 300s.
  • Also run: typecheck, test/session, test/provider, TUI, chunk-timeout tests; marker check.
  • Live provider and Bedrock SDK frame decoding: Not run (no model spend). Recovery was verified against a fake server reproducing the stall shapes, not the real provider; real gateways may stall differently.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code


Note

Medium Risk
Changes core provider fetch timeouts, session retry semantics, and tool-call safety rules; mis-tuned headerTimeout could cut off legitimately slow streams, and the no-retry-after-tool-start rule alters behavior for any retryable error mid-step.

Overview
Sessions that hung or died on silent providers now abort stalled requests, retry with backoff (up to 5 times), and clean up partial output so retries do not duplicate streamed text or re-run tools.

Provider layer: Most providers get a 300s default headerTimeout (configurable via options.headerTimeout, or false to disable). The stream idle watchdog now covers Amazon Bedrock event streams as well as SSE. Custom fetches that ignore abort signals (e.g. Vertex credential work) are raced against the first-byte deadline.

Session layer: Header and idle-stream timeouts map to retryable "The model stopped responding" errors. Before each retry, StallRecovery removes text, reasoning, step-start, and pending tool parts from the failed attempt; retries are blocked once a tool has started executing or a step has finished, with a clear error message. User cancel skips retry and fails fast during retry backoff if the signal is already aborted.

Docs / TUI: providers.md documents headerTimeout and chunkTimeout; notifications treat the new exhausted-stall message as "Model stopped responding".

Reviewed by Cursor Bugbot for commit a689e5a. Bugbot is set up for automated code reviews on this repo. Configure here.

anandgupta42 and others added 2 commits October 7, 2026 11:38
A model request that never answered hung the session until an external
kill, an idle-stream timeout ended it as an unknown error, and a stream
that died part-way left its partial output in the message on retry.

- Arm a 300s first-byte (response headers) timeout by default; it is
  configurable per provider through `options.headerTimeout`.
- Watch Bedrock Converse binary event streams with the idle timeout too,
  not only SSE.
- Classify a header timeout and an idle-stream timeout as retryable
  `APIError`s that say "The model stopped responding" (same mapping as
  upstream OpenCode), so the existing backoff retries them.
- Before a retry, discard what the failed attempt streamed (text,
  reasoning, step-start, tool calls still pending). If the attempt
  already dispatched a tool call, do not retry, so the tool is never
  re-run; the session ends with an error naming the tool.
- Never retry after a user cancel.

Closes #1424

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Refuse a retry once the failed attempt finished its step, so cost and
  tokens are not counted twice and the answer is not produced twice.
- Explain on any `APIError` why a retry was refused, and stop logging
  that case as exhausted retries.
- Keep a failed partial-output cleanup from escaping the catch block.
- Do not append "gave up after N retries" when the user cancelled.
- Test the discard rule directly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 17a6a27b-2e36-4ae9-99c8-b63852e2a9a2
📥 Commits

Reviewing files that changed from the base of the PR and between 689b47e and b852ba4.

📒 Files selected for processing (7)
  • packages/opencode/src/provider/provider.ts
  • packages/opencode/src/session/processor.ts
  • packages/opencode/src/session/stall-recovery.ts
  • packages/opencode/test/release-validation/chunk-timeout-844.test.ts
  • packages/opencode/test/session/stall-recovery.test.ts
  • packages/tui/src/feature-plugins/system/notifications.ts
  • packages/tui/test/cli/cmd/tui/notifications.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The provider now applies header and stream timeouts, including to Bedrock event streams. Timeout errors can trigger bounded session retries. Before retrying, the session removes eligible partial output and prevents retry when a tool call has already been dispatched.

Changes

Stalled request recovery

Layer / File(s) Summary
Timeout detection and classification
docs/docs/configure/providers.md, packages/opencode/src/provider/error.ts, packages/opencode/src/provider/provider.ts, packages/opencode/src/session/message-v2.ts, packages/opencode/test/release-validation/chunk-timeout-844.test.ts, packages/opencode/test/session/stall-recovery.test.ts
The provider defaults an unspecified header timeout to 300,000 ms and watches SSE and Amazon event streams for stalled reads. Timeout errors map to retryable API errors. Documentation and tests cover timeout settings, error classification, and timeout behavior.
Partial attempt cleanup and retry
packages/opencode/src/session/processor.ts, packages/opencode/src/session/retry.ts, packages/opencode/src/session/stall-recovery.ts, packages/opencode/test/session/retry.test.ts, packages/opencode/test/session/stall-recovery.test.ts, docs/docs/configure/providers.md
The processor snapshots message parts before streaming. It removes eligible partial output before retrying and stops retrying if a tool was dispatched or cleanup fails. Tests cover retries, cancellation, retry limits, and tool-call handling.
Stopped-response notification
packages/tui/src/feature-plugins/system/notifications.ts, packages/tui/test/cli/cmd/tui/notifications.test.ts
The TUI maps stopped-responding errors to a “Model stopped responding” notification. A test covers the notification and error sound after retries are exhausted.

Priority: ⬆️ High

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

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant SessionProcessor
  participant ProviderFetch
  participant MessageV2
  participant StallRecovery
  participant SessionRetry
  SessionProcessor->>ProviderFetch: start stream attempt
  ProviderFetch->>MessageV2: timeout or stream error
  MessageV2-->>SessionProcessor: retryable APIError
  SessionProcessor->>StallRecovery: discard partial attempt
  StallRecovery-->>SessionProcessor: removed parts or dispatched action
  SessionProcessor->>SessionRetry: wait before eligible retry
  SessionRetry-->>SessionProcessor: backoff completed
Loading

Merge Risk: 🟡 Moderate · up to b852b

After a tool acts and the model stalls, the next turn can lack the tool’s history, allowing the model to repeat the action. Preserve that history before merging unless this limitation is explicitly accepted.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 11 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue #1424 is open and directly linked. The changes add a default 300-second header timeout, monitor SSE and Bedrock Converse streams, and classify header and idle-stream failures as retryable. The s…
Out of Scope Changes check ✅ Passed The changes stay within issue #1424. Provider timeout configuration, retry classification, partial-attempt cleanup, cancellation handling, tool safeguards, user notification mapping, documentation, an…
Title check ✅ Passed The title clearly and concisely describes the main change: recovering sessions from stalled model requests.
Description check ✅ Passed The description completes the required sections, identifies the issue, explains the root cause and implementation, documents verification, and includes the checklist. It also clearly notes that live-p…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

I’m a rabbit watching headers arrive,
I nibble the timeout and keep streams alive.
If partial words vanish, I hop to retry,
But dispatched tools stay safely nearby.
Five turns are counted; the message is clear,
“Model stopped responding” now reaches the ear.

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

@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: b5139e51-571b-463a-9747-dbdede1b5289)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-07T21:29:23.812461Z a689e5a New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 8 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/opencode/src/session/stall-recovery.ts Outdated
Comment thread packages/opencode/src/session/processor.ts
Comment thread packages/opencode/src/session/message-v2.ts Outdated
Comment thread packages/opencode/src/provider/provider.ts
Comment thread packages/opencode/src/session/processor.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a0e99ddc5b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/opencode/src/session/stall-recovery.ts Outdated
Comment thread packages/opencode/test/session/stall-recovery.test.ts Outdated
Comment thread packages/opencode/src/session/processor.ts Outdated
Comment thread packages/opencode/src/session/message-v2.ts Outdated
- Use flat exports with a self re-export in `stall-recovery.ts`, per the
  package conventions.
- Only the idle watchdog's `ResponseStreamError` is retryable; websocket
  transport errors keep their previous handling.
- Make `SessionRetry.sleep` reject at once on an already-aborted signal so
  a Stop that lands just before the backoff is not delayed.
- Log "max retry attempts reached" and append "gave up after N retries"
  only when attempts were actually exhausted.
- Document that `headerTimeout: false` removes the hang protection.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 71f9c537-4c70-4831-8b74-8145ece3058e)

Replace the coercer reset on retry with `discardUnstarted()`, which drops
only tool inputs that started streaming but were never called. Ids already
allocated (including by earlier calls in the same message) stay reserved, so
a retry that reuses a raw provider id can neither pair with the discarded
start nor collide with an earlier call.

Also make the stall tests deterministic: disable snapshot tracking in the
test config (its background git work was what leaked an "All fibers
interrupted" error at scope close) instead of sleeping.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 7e582a30-82d2-4e20-a0a2-403013fd8df3)

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/opencode/src/session/processor.ts
`discardUnstarted()` now removes the discarded attempt's allocations, so the
per-id slot ordinals that `settled()` and `executionID()` index by stay
aligned with what actually executes, while ids of earlier calls remain
reserved. Tests cover both the collision and the ordinal alignment cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: f57ef6bb-8c5c-4794-80c4-8e832ac34505)

Comment thread packages/opencode/src/session/stall-recovery.ts
Comment thread packages/opencode/src/provider/provider.ts
Comment thread packages/opencode/test/session/stall-recovery.test.ts
Comment thread packages/opencode/test/session/stall-recovery.test.ts Outdated
Comment thread packages/opencode/src/session/message-v2.ts
Comment thread packages/opencode/test/session/stall-recovery.test.ts Outdated
Comment thread packages/opencode/test/session/stall-recovery.test.ts Outdated
Comment thread packages/opencode/test/session/stall-recovery.test.ts
@kilo-code-bot

kilo-code-bot Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 2
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
packages/opencode/src/session/stall-recovery.ts 44 A refused retry still omits acted-on tool history from the next model turn; previously reported on the PR.
packages/opencode/src/session/stall-recovery.ts 52 Bulk cleanup deletes local parts without durable removal events, so workspace sync can retain the discarded attempt.
Files Reviewed (5 files)
  • packages/opencode/src/provider/provider.ts - 0 issues
  • packages/opencode/src/session/processor.ts - 0 issues
  • packages/opencode/src/session/stall-recovery.ts - 2 issues
  • packages/opencode/test/release-validation/chunk-timeout-844.test.ts - 0 issues
  • packages/opencode/test/session/stall-recovery.test.ts - 0 issues

Fix these issues in Kilo Cloud

Review based on HEAD a689e5ad8cc518906cc1e27be7ab8367005840e0. The previous SDK execution guard, partial-delete failure, and custom-fetch credential timeout findings were rechecked and are resolved. The existing next-turn tool-history issue remains. Read-only review: code and tests were not executed; real Bedrock SDK frame decoding remains unverified.

Previous Review Summaries (4 snapshots, latest commit f4a5cc7)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit f4a5cc7)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 2
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
packages/opencode/src/session/stall-recovery.ts 37 A tool can start in the SDK before its persisted part becomes running; retry can execute the same side effect twice.
packages/opencode/src/session/stall-recovery.ts 39 A refused retry still omits the acted-on tool from the next turn's model history; already reported in current PR comments.

WARNING

File Line Issue
packages/opencode/src/session/stall-recovery.ts 45 Partial cleanup failure can leave persisted assistant output partly deleted without retrying.
packages/opencode/src/provider/provider.ts 1980 Header timeout does not bound the shipped Google Vertex custom fetch's pre-fetch credential acquisition.
Files Reviewed (12 files)
  • docs/docs/configure/providers.md - 0 issues
  • packages/opencode/src/provider/error.ts - 0 issues
  • packages/opencode/src/provider/provider.ts - 1 issue
  • packages/opencode/src/session/message-v2.ts - 0 issues
  • packages/opencode/src/session/processor.ts - 0 issues
  • packages/opencode/src/session/retry.ts - 0 issues
  • packages/opencode/src/session/stall-recovery.ts - 3 issues
  • packages/opencode/test/release-validation/chunk-timeout-844.test.ts - 0 issues
  • packages/opencode/test/session/retry.test.ts - 0 issues
  • packages/opencode/test/session/stall-recovery.test.ts - 0 issues
  • packages/tui/src/feature-plugins/system/notifications.ts - 0 issues
  • packages/tui/test/cli/cmd/tui/notifications.test.ts - 0 issues

Fix these issues in Kilo Cloud

Review based on HEAD f4a5cc725158489d594a81e6ddfbbaba9b5d8db9. Previous replay-exception findings were dropped because the exception was reverted; the separate next-turn loss after a refused retry remains. Read-only review: no code or tests executed. The incremental diff fetch returned HTTP 429; the complete current PR patch and base-to-head diff were available. Real Bedrock SDK frame decoding remains unverified.

Previous review (commit 2613ba5)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 2
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
packages/opencode/src/session/message-v2.ts 774 An error-only dispatched tool is omitted from replay after a refused retry; the model may repeat its side effects.
packages/opencode/src/session/message-v2.ts 775 An acted-on tool is omitted from replay when the retryable failure is not a stalled-response error; already reported in current PR comments.

WARNING

File Line Issue
packages/opencode/src/session/message-v2.ts 776 A completed tool admits unfinished text or an unexecuted tool from the same stalled step into replay; already reported in current PR comments.
Files Reviewed (3 files)
  • packages/opencode/src/session/message-v2.ts - 3 issues
  • packages/opencode/test/session/message-v2.test.ts - 0 issues
  • packages/opencode/test/session/stall-recovery.test.ts - 0 issues

Fix these issues in Kilo Cloud

Review based on HEAD 2613ba519ba6192a0009332ed409ffb304b0916d. Prior text-only replay and socket-close race findings are fixed. Read-only review: no code or tests executed; real Bedrock SDK frame decoding remains unverified.

Previous review (commit fc5f189)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/session/message-v2.ts 773 A stalled final attempt with only partial text or an unexecuted tool is replayed as completed assistant history; already reported in active PR comments.
packages/opencode/test/session/stall-recovery.test.ts 383 Socket-close assertions can race the server's asynchronous close event because only cancellation tests wait for it.
Files Reviewed (7 files)
  • packages/opencode/src/provider/provider.ts - 0 issues
  • packages/opencode/src/session/message-v2.ts - 1 issue
  • packages/opencode/test/release-validation/chunk-timeout-844.test.ts - 0 issues
  • packages/opencode/test/session/message-v2.test.ts - 0 issues
  • packages/opencode/test/session/stall-recovery.test.ts - 1 issue
  • packages/tui/src/feature-plugins/system/notifications.ts - 0 issues
  • packages/tui/test/cli/cmd/tui/notifications.test.ts - 0 issues

Fix these issues in Kilo Cloud

Review based on current HEAD fc5f18953dbb4cf276f127bbf01d4afd1ab244a2. Read-only review: no code or tests were executed. Real Bedrock SDK frame decoding was not verified.

Previous review (commit 689b47e)

Status: 8 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 3
SUGGESTION 4
Issue Details (click to expand)

CRITICAL

File Line Issue
packages/opencode/src/session/stall-recovery.ts 39 A dispatched tool's invocation and result vanish from the next model turn when the non-retried assistant is marked errored.

WARNING

File Line Issue
packages/opencode/src/provider/provider.ts 154 A mixed-case Bedrock event-stream media type bypasses the idle watchdog.
packages/opencode/test/session/stall-recovery.test.ts 274 Cancellation polling interval survives a failed setup that sends no request.
packages/opencode/test/session/stall-recovery.test.ts 387 Bedrock binary-stream test instead feeds SSE to the OpenAI-compatible SDK.

SUGGESTION

File Line Issue
packages/opencode/src/session/message-v2.ts 1191 New timeout error loses the TUI's model-stopped notification.
packages/opencode/test/session/stall-recovery.test.ts 535 Cancellation test can pass without entering retry backoff.
packages/opencode/test/session/stall-recovery.test.ts 353 Aggregate close count does not prove the stalled socket was aborted.
packages/opencode/test/session/stall-recovery.test.ts 651 Discard tests never assert that earlier attempt's parts survive.
Files Reviewed (10 files)
  • docs/docs/configure/providers.md - 0 issues
  • packages/opencode/src/provider/error.ts - 0 issues
  • packages/opencode/src/provider/provider.ts - 1 issue
  • packages/opencode/src/session/message-v2.ts - 1 issue
  • packages/opencode/src/session/processor.ts - 0 issues
  • packages/opencode/src/session/retry.ts - 0 issues
  • packages/opencode/src/session/stall-recovery.ts - 1 issue
  • packages/opencode/test/release-validation/chunk-timeout-844.test.ts - 0 issues
  • packages/opencode/test/session/retry.test.ts - 0 issues
  • packages/opencode/test/session/stall-recovery.test.ts - 5 issues

Fix these issues in Kilo Cloud

Review based on current HEAD 689b47e8548c828db624ca6edad284af28685b82; no code or tests were executed in read-only mode. The Bedrock SDK runtime case remains unverified.


Reviewed by gpt-6-sol · Input: 92 · Output: 33K · Cached: 7.6M

Review guidance: REVIEW.md from base branch main

anandgupta42 and others added 2 commits October 7, 2026 12:58
- Replay an assistant step that ended with "The model stopped responding"
  and already ran tools, as an aborted step is, so the next turn knows those
  side effects happened instead of losing them from context.
- Match the Bedrock event-stream content type case-insensitively.
- Show "Model stopped responding" in the TUI for the retried-out error too.
- Tighten the stall tests: assert the stalled request's own socket closed,
  start the backoff cancel only after the stall fired, clear test timers on
  every exit, and cover parts that predate the failed attempt.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: cdcb5346-922f-4c25-8e34-2372b02837e9)

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 7 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/opencode/src/session/message-v2.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc5f18953d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/opencode/src/session/message-v2.ts
Comment thread packages/opencode/test/session/stall-recovery.test.ts
Narrow the replay exception for a stalled step to messages where a tool
actually completed, so partial text or tool input that never ran is not fed
to the next turn. Also wait for the torn-down requests' close events in the
stall tests before asserting on them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 0987efd5-5531-46d2-add5-9c4cff0fee3c)

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2613ba519b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/opencode/src/session/message-v2.ts Outdated
Comment thread packages/opencode/src/session/message-v2.ts Outdated
Comment thread packages/opencode/src/session/message-v2.ts Outdated
The replay of an errored assistant step is a pre-existing limitation for every
error, and handling it correctly (per-part filtering, all retryable errors,
errored tools) is a separate change. Keep this PR to stall detection and the
retry rules; the known limit is documented in the PR.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 47e20d98-838e-40d0-a999-ba84bdf9f5db)

Comment thread packages/opencode/src/session/stall-recovery.ts
Comment thread packages/opencode/src/session/stall-recovery.ts Outdated
Comment thread packages/opencode/src/provider/provider.ts
…lean up atomically

- The retry guard now also refuses once any tool's execute() began during the
  attempt, counted in the processor from the tool wrapper's
  `beginToolExecution`, because the AI SDK can start a tool before its part
  leaves `pending` or its tool-call event is persisted.
- Remove a failed attempt's parts in one delete statement so a cleanup
  failure cannot leave the attempt half deleted.
- Race the whole custom fetch against the first-byte deadline, so work such
  as Vertex credential acquisition that ignores the abort signal is bounded.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 3e45f513-52a4-4e14-92ec-8fed25cfd73f)

@cubic-dev-ai cubic-dev-ai 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.

2 issues found across 5 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/opencode/test/session/stall-recovery.test.ts">

<violation number="1" location="packages/opencode/test/session/stall-recovery.test.ts:555">
P3: This callback is triggered by request arrival, not by creation of the pending tool part, so it can mark execution before any part exists. Wait for and assert the `call_1` part is pending before invoking `beginToolExecution`; the final `parts.some(...)` only checks state after the attempt.</violation>
</file>

<file name="packages/opencode/src/provider/provider.ts">

<violation number="1" location="packages/opencode/src/provider/provider.ts:2049">
P2: This race only observes the header deadline, so caller cancellation cannot settle the wrapper while a custom fetch is awaiting work that ignores `init.signal`. Vertex awaits credential acquisition before forwarding the signal, leaving the request pending until credentials resolve or the 300-second timeout; race the request signal as well.</violation>
</file>

Comment thread packages/opencode/src/provider/provider.ts
Comment thread packages/opencode/test/session/stall-recovery.test.ts

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b852ba47d6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/opencode/src/provider/provider.ts Outdated
Race the custom fetch against the combined request signal (first-byte
deadline, caller cancel, timeouts), not only the deadline, so a Stop is not
held up by pre-request work that ignores the signal. The tool-race test now
waits for the pending tool part before reporting the execution started.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: f4e7bfbf-6fb1-4f17-a074-5a8c4ea5300d)

const removed = new Set<string>(stale.map((part) => part.id))
if (stale.length > 0) {
Database.use((db) => {
db.delete(PartTable)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CRITICAL: Persist retry cleanup in the synchronized session event log

This raw PartTable delete removes the failed attempt locally, but the following Bus.publish(MessageV2.Event.PartRemoved, ...) is only a legacy notification; it does not append SessionV1.Event.PartRemoved to the durable core event log. The shipped workspace sync replays that log into another workspace via SessionProjector, which has the original PartUpdated events but no removal. After a stalled attempt is retried, the other workspace therefore retains the discarded text, step-start, or pending tool alongside the retry's output, and future sync cannot correct it. Publish/project durable part-removal events as part of the atomic cleanup, rather than deleting only the local projection.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not changed in this PR. The cleanup persists a removal the same way the existing Session.removePart in session/index.ts does: a delete on PartTable followed by Bus.publish(MessageV2.Event.PartRemoved, ...). Session.updatePart writes parts through the same path. The bulk delete replaced a loop over Session.removePart so the cleanup is one statement; it did not change which event log the removal reaches. If removals made through this path are not replayed by workspace sync, that applies to every existing caller of Session.removePart and is a separate change to how this module persists part events, outside the stall-retry fix.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Session hangs or dies when a model request stalls (no first-byte timeout, idle timeout not retried)

1 participant