Skip to content

fix(cli): retry responses without finish reasons#12157

Closed
chrarnoldus wants to merge 5 commits into
mainfrom
fix/retry-missing-finish-reason
Closed

fix(cli): retry responses without finish reasons#12157
chrarnoldus wants to merge 5 commits into
mainfrom
fix/retry-missing-finish-reason

Conversation

@chrarnoldus

Copy link
Copy Markdown
Collaborator

What changed

Treat model streams that end without a finish reason as retryable and retry them three times before surfacing the existing incomplete-response error.

The dedicated cap is independent of the general provider retry limit, so this recovery path always gets three retries but cannot loop indefinitely. Successful retry attempts clear the prior unknown finish marker before processing the next stream.

Why

These streams complete without throwing, so the existing provider error retry policy never handled them. In the VS Code extension they appeared immediately as Response ended without a finish reason and may be incomplete. instead of being retried.

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
@chrarnoldus chrarnoldus self-assigned this Jul 13, 2026
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Comment thread packages/opencode/src/session/processor.ts Outdated
Comment thread packages/opencode/src/kilocode/session/processor.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 3 Issues Found | Recommendation: Address before merge

Overview

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

WARNING

File Line Issue
packages/opencode/src/kilocode/session/processor.ts 209 Incomplete tool-input framing suppresses the missing-finish retry
packages/opencode/src/session/processor.ts 1209 Retried framing leaves stale persisted parts behind
packages/opencode/src/session/retry.ts 144 Dedicated retries still consume the provider retry budget
Files Reviewed (6 files)
  • .changeset/retry-missing-finish.md - 0 issues
  • bun.lock - 0 issues
  • packages/opencode/src/kilocode/session/processor.ts - 1 issue
  • packages/opencode/src/session/processor.ts - 1 issue
  • packages/opencode/src/session/retry.ts - 1 issue
  • packages/opencode/test/kilocode/session-processor-retry-limit.test.ts - 0 issues

Fix these issues in Kilo Cloud

Previous Review Summaries (2 snapshots)

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

Previous review

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/kilocode/session/processor.ts 206 Parts from earlier steps suppress retries for a later empty stream
packages/opencode/src/kilocode/session/processor.ts 207 Empty text/reasoning shells count as visible output
Files Reviewed (3 files)
  • .changeset/retry-missing-finish.md - 0 issues
  • packages/opencode/src/kilocode/session/processor.ts - 2 issues
  • packages/opencode/test/kilocode/session-processor-retry-limit.test.ts - 0 issues

Fix these issues in Kilo Cloud

Previous review (commit 833875f)

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/processor.ts 1014 Retry can replay already-persisted output and tool side effects
packages/opencode/src/kilocode/session/processor.ts 204 unknown terminal reasons are treated as absent finish events
Files Reviewed (5 files)
  • .changeset/retry-missing-finish.md - 0 issues
  • packages/opencode/src/kilocode/session/processor.ts - 1 issue
  • packages/opencode/src/session/processor.ts - 1 issue
  • packages/opencode/src/session/retry.ts - 0 issues
  • packages/opencode/test/kilocode/session-processor-retry-limit.test.ts - 0 issues

Fix these issues in Kilo Cloud


Reviewed by gpt-5.6-sol · Input: 89K · Output: 7.9K · Cached: 579.1K

Review guidance: REVIEW.md from base branch main

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Comment thread packages/opencode/src/kilocode/session/processor.ts Outdated
Comment thread packages/opencode/src/kilocode/session/processor.ts Outdated
AlexOcculate pushed a commit to AlexOcculate/kilocode that referenced this pull request Jul 14, 2026
…ish-reason

# Conflicts:
#	packages/opencode/test/kilocode/session-processor-retry-limit.test.ts
) {
if (msg.finish) return Effect.void
msg.finish = "unknown"
if (step.reasoning || step.text || step.tool) return Effect.void

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WARNING: Incomplete tool-input framing suppresses the retry

step.tool is set by tool-input-start, before a complete tool call or executable input exists. If the provider disconnects after that start event, this condition accepts the response as partial output instead of retrying it; cleanup then records the pending call as Tool execution aborted, so the user receives a failed phantom tool call rather than the intended missing-finish recovery. Consider marking tool output observable only once a complete tool-call has arrived.


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

Stream.takeUntil(() => ctx.needsCompaction),
Stream.runDrain,
)
yield* KiloSessionProcessor.ensureFinish(ctx.assistantMessage, ctx.step)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WARNING: Retried framing leaves stale persisted parts behind

An empty response can still persist step-start, empty/whitespace text or reasoning parts, and partial tool-input state before this failure triggers. The next attempt clears only the in-memory references, so prior text/reasoning parts can remain without end timestamps and each retry adds another set of fragments; pending tool calls also survive until final cleanup. Please settle or remove all attempt-local parts and tool state at this retry boundary before replaying the request.


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

// kilocode_change start — enforce retry limit
if (opts.limit !== undefined && meta.attempt > opts.limit) {
const allowed = opts.allow?.(meta.input)
if (allowed === false || (allowed !== true && opts.limit !== undefined && meta.attempt > opts.limit)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WARNING: Dedicated retries still consume the provider retry budget

Although allowed === true bypasses the limit check for MissingFinishError, Effect's shared meta.attempt still increments. A missing-finish retry followed by retryable provider errors therefore reaches opts.limit early; with limit 2, one missing-finish response leaves only one provider retry before the next 429 is stopped. This conflicts with the intended independent caps. Track general-provider attempts separately from specially allowed missing-finish attempts.


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

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.

2 participants