Skip to content

fix: drain tool results after stream disconnect#1252

Open
Astro-Han wants to merge 20 commits into
devfrom
codex/i927-tool-drain
Open

fix: drain tool results after stream disconnect#1252
Astro-Han wants to merge 20 commits into
devfrom
codex/i927-tool-drain

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

  • Decouple local tool execution from the provider stream abort signal during session processor runs.
  • Add tool lifecycle callbacks so completed and failed tool executions persist through the existing processor state even if the provider stream never yields a tool-result or tool-error event.
  • Drain started tools on stream cleanup with a bounded timeout and direct session-cancel abort propagation, while preserving interrupted semantics for user cancel and lifecycle close.

Why

A provider stream timeout or transport disconnect after tool execution starts could abort the tool's local signal and let cleanup mark the tool part as interrupted before the completed result was persisted. PR1 for #927 needs the tool execution/result path to survive stream lifecycle failure without adding recovery UI or replay behavior.

Related Issue

Part of #927.

Human Review Status

Pending

Review Focus

Please focus on the tool abort signal split, the idempotent lifecycle callbacks, the tool-call readiness gate before terminal lifecycle writes, the bounded cleanup drain for started tools after stream failure, and the run-state cancel observer that aborts tools even while cleanup is draining.

Risk Notes

Runtime behavior changes for session tool execution on both macOS and Windows, but no OS-specific paths or packaging surfaces changed. The main behavior tradeoff is intentional: after a non-interrupt stream failure, started tools are allowed to finish up to the recovery drain timeout instead of being forced into the old one-second cleanup path; genuinely dead tools are still finalized instead of hanging the session indefinitely, and user cancel/lifecycle close can abort the drain directly.

Fresh-eye and Claude review found races around fast tool completion, abort-aware tool failure, lifecycle-close drain semantics, unbounded drain, drain-time cancellation, started-but-not-materialized tool calls, leftover Deferred cleanup, and early failure persistence. This PR includes follow-up commits covering those with the readiness gate, abort-aware failure guard, lifecycle-close abort, bounded drain, session cancel observer, remaining Deferred cleanup, pending-start reconciliation, and regression tests.

Skipped conditional checklist items: screenshots are not applicable because there are no visible UI or copy changes; docs/release/dependencies are not applicable because none were touched.

Migration note: this PR intentionally keeps the recovery fix in the legacy packages/opencode processor/LLM bridge. The behavior aligns with the upstream Core v2 runtime direction: local tool execution is tracked independently from provider stream events, tool settlements are drained before continuation or recovery decisions, and unresolved tools are finalized instead of being left pending. If PawWork later ports the upstream packages/core session runner and unified tool runtime, the right migration path is to carry these regression scenarios into the Core runner and delete this bridge, not grow it into a parallel runtime.

How To Verify

Install: bun install --frozen-lockfile completed successfully in the isolated worktree
Diff check: git diff --check passed
Processor effect tests: bun --cwd packages/opencode test test/session/processor-effect.test.ts -> 39 pass, 0 fail
Prompt effect tests: bun --cwd packages/opencode test test/session/prompt-effect.test.ts -> 63 pass, 0 fail
Run state tests: bun --cwd packages/opencode test test/session/run-state.test.ts -> 22 pass, 0 fail
Compaction tests: bun --cwd packages/opencode test test/session/compaction.test.ts -> 51 pass, 0 fail
LLM tests: bun --cwd packages/opencode test test/session/llm.test.ts -> 21 pass, 0 fail
Tool failure tests: bun --cwd packages/opencode test test/session/tool-failure.test.ts -> 3 pass, 0 fail
Opencode typecheck: (cd packages/opencode && bun run typecheck) -> tsgo --noEmit passed

Screenshots or Recordings

Not applicable. No visible UI changes.

Checklist

How to use this checklist:

  • Tick a box by replacing [ ] with [x]. Do not edit, add, or remove items.
  • The bot-applied label items can only be honestly ticked AFTER the PR is opened and the labeler / priority-triage bots have run — return to the PR description and tick them then.
  • Most items are required. The few that are conditional are explicitly marked (conditional); for those, leave unticked if they truly do not apply and explain why in Risk Notes. All other items must be ticked before requesting human review.
  • Type label — this PR carries exactly one of bug, enhancement, task, documentation. Type labels are author-added; the labeler bot does NOT assign them. Add the label in the GitHub UI, then tick this.
  • Routing labels — this PR carries at least one of app, ui, platform, harness, ci. The labeler bot assigns these on PR open based on changed paths. Confirm the bot's choice (or override if wrong), then tick this.
  • Priority label — this PR carries exactly one of P0, P1, P2, P3. The priority-triage bot suggests one on PR open. Confirm or override if wrong, then tick this.
  • Human Review Status above is set to Pending, Approved by @<reviewer>, or Not required: <reason> (default is Pending; "not required" is restricted to bot-authored low-risk PRs).
  • I linked the related issue, or stated in Summary why there is no issue.
  • I described the review focus and any meaningful risks.
  • I replaced the example block in How To Verify with the real verification steps and the key result for each.
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope.
  • (conditional) I manually checked visible UI or copy changes when needed, with screenshots or recordings. Leave unticked only if no visible UI or copy changed.
  • (conditional) I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes. Leave unticked only if no platform/packaging surface was touched.
  • (conditional) I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant. Leave unticked only if none of those surfaces was touched.
  • I reviewed the final diff for unrelated changes and suspicious dependency changes.
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English.

Summary by CodeRabbit

  • New Features

    • Tool lifecycle hooks: started, completed, failed and an abort signal for cancelling in-flight tool calls.
    • Configurable tool drain timeout to bound cleanup.
  • Improvements

    • Better abort propagation and per-session cancel observers; cancellation now aborts active tools.
    • Tool lifecycle reporting normalizes outputs and includes tool input payloads.
  • Tests

    • Added coverage for lifecycle callbacks, abort behavior, and persistence of completed tool results.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Astro-Han, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 53 minutes and 38 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5a31bfd5-2313-4a39-ac9e-10bbd3866656

📥 Commits

Reviewing files that changed from the base of the PR and between f272304 and d8ae698.

📒 Files selected for processing (4)
  • packages/opencode/src/session/processor.ts
  • packages/opencode/test/session/message-v2.test.ts
  • packages/opencode/test/session/processor-effect.test.ts
  • packages/opencode/test/session/prompt-effect.test.ts
📝 Walkthrough

Walkthrough

Adds tool lifecycle callbacks, per-attempt abort signaling, bounded drain/cleanup, run-state cancel observers, prompt cancel wiring to abort active tools, LLM-level tool wrapping with normalized completion payloads, and tests covering timeout/abort/drain behaviors.

Changes

Tool Execution Lifecycle and Abortion

Layer / File(s) Summary
LLM StreamInput contract and tool wrapper
packages/opencode/src/session/llm.ts
StreamInput gains toolAbortSignal and toolLifecycle callbacks; wrapToolsWithLifecycle wraps each tool execute to call started/completed/failed and normalize outputs.
Assistant message conversion
packages/opencode/src/session/message-v2.ts
Errored assistant messages that include recoverable tool parts (completed/error) are no longer skipped by the early error guard.
Processor contracts and abort registry
packages/opencode/src/session/processor.ts
Adds TOOL_DRAIN_TIMEOUT_MS, ProcessInput.toolDrainTimeoutMs, Handle.abortTools?, and a per-session abort-callback registry.
Lifecycle helpers and idempotent recording
packages/opencode/src/session/processor.ts
Introduces lifecycle waiters (partCreated/ready/done), settle helpers, and idempotent recordToolExecutionStarted/Completed/Failed with persisted start/end times.
Tool event handlers (input/call/error)
packages/opencode/src/session/processor.ts
Updates tool-input-start, tool-call, and tool-error handlers to create/refresh lifecycle records, resolve readiness, materialize parts, and persist running->terminal transitions.
Cleanup drain and abort race
packages/opencode/src/session/processor.ts
Cleanup drains in-flight tool calls with bounded timeouts, resolves ready for started-but-not-materialized calls, races drain against abort-driven interruption, and releases waiters to avoid stuck deferreds.
Per-attempt abort wiring and propagation
packages/opencode/src/session/processor.ts
Per-attempt AbortController and abortProcessTools() implemented; toolAbortController.signal is passed to llm.stream, lifecycle handlers honor aborts, and interrupts/backoff paths invoke tool abort.
Run-state observers & prompt cancellation
packages/opencode/src/session/run-state.ts, packages/opencode/src/session/prompt.ts
ensureRunning accepts onCancel observers registered per session; prompt.loop stores active processor and calls activeProcessor?.abortTools?.() on cancel.
Tests and fixtures
packages/opencode/test/session/*, packages/opencode/test/permission-agent.test.ts
Adds wrapToolsWithLifecycle unit tests, many processor live tests for timeout/abort/drain, a TestDeferred helper, prompt-effect abort-aware live test, and minor test fixture adjustments (tmpdir options, abortTools noop).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Astro-Han/pawwork#1251: Overlaps in session/run-state.ts cancel observer and cancel timing changes related to run cancellation.
  • Astro-Han/pawwork#900: Related session run-state lifecycle and active-run cancellation semantics impacting abort/drain behavior.

Poem

🐰 I wrap each tool with tidy care,

started, completed, failed I share.
Abort the runners, drain with grace,
Deferreds released, no stuck embrace.
A rabbit cheers the tidy race.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding tool result draining after stream disconnection to prevent loss of completed tool results.
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.
Description check ✅ Passed The pull request description comprehensively addresses all template requirements with clear summary, rationale, linked issue, and verified review status.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/i927-tool-drain

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

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

@Astro-Han Astro-Han added enhancement New feature or request P1 High priority app Application behavior and product flows harness Model harness, prompts, tool descriptions, and session mechanics labels Jun 10, 2026
@github-actions github-actions Bot removed the app Application behavior and product flows label Jun 10, 2026

@github-actions github-actions 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.

Suggested priority: P2 (includes non-doc, non-test paths outside the low-risk bucket).

P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces tool lifecycle hooks (started, completed, failed) and abort signals to manage tool execution, tracking, and cleanup during LLM streams. It also adds robust state tracking to prevent duplicate execution records and includes a test verifying tool completion persistence after stream timeouts. The review feedback highlights two important improvements: decoupling the tool execution try-catch block from the completion callback to prevent incorrect failure reporting, and wrapping JSON.stringify in a try-catch block to handle potential serialization errors safely.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/opencode/src/session/llm.ts
Comment thread packages/opencode/src/session/llm.ts

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/opencode/src/session/run-state.ts (1)

217-225: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Queued ensureRunning() calls never receive the new onCancel hook.

ensureRunning() registers options.onCancel before withActiveRun(...), but cancel() returns on Line 220 unless this session already has a busy runner. A run that's still waiting on the directory lock has no runner yet, so its observer is skipped and the queued work can still start after the user cancels. Either notify observers before this early return, or register onCancel only once the run is actually active.

🤖 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 `@packages/opencode/src/session/run-state.ts` around lines 217 - 225, The
cancel() implementation in SessionRunState currently returns early when there is
no busy runner, skipping notifyCancelObservers and leaving queued
ensureRunning() tasks without the new onCancel hook; update cancel(sessionID,
meta) to ensure observers get notified even when no existing.busy runner exists
(e.g., call data.notifyCancelObservers(sessionID, meta) before the early return)
or alternatively change ensureRunning()/withActiveRun so onCancel is registered
only after a runner is created; reference functions/objects: cancel,
ensureRunning, withActiveRun, InstanceState.get(state), data.runners, and
data.notifyCancelObservers to locate and apply the fix.
packages/opencode/src/session/processor.ts (1)

913-939: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Wrap this switch case in its own block.

const executionStarted = ... is declared directly under case "tool-input-start":, so Biome's noSwitchDeclarations rule flags this as an error. If lint is gating CI, this change won't merge until the case is braced.

Suggested fix
-          case "tool-input-start":
+          case "tool-input-start": {
             if (ctx.assistantMessage.summary) {
               throw new Error(`Tool call not allowed while generating summary: ${value.toolName}`)
             }
             const part = yield* session.updatePart({
               id: ctx.toolcalls[value.id]?.partID ?? PartID.ascending(),
@@
             }
             yield* applyPendingToolUpdates(value.id)
             return
+          }

Static analysis already reports this as a Biome noSwitchDeclarations error.

🤖 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 `@packages/opencode/src/session/processor.ts` around lines 913 - 939, The
switch case for "tool-input-start" declares variables (e.g., const
executionStarted) directly under the case which triggers the Biome
noSwitchDeclarations rule; fix it by wrapping the entire case body in its own
block (add { ... } after case "tool-input-start":) so declarations like
executionStarted, part, and the ctx.toolcalls assignment are scoped properly;
ensure the existing calls to session.updatePart,
ctx.pendingStartedToolCalls.delete, Deferred.make, and
applyPendingToolUpdates(value.id) remain inside that new block.

Source: Linters/SAST tools

🤖 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.

Outside diff comments:
In `@packages/opencode/src/session/processor.ts`:
- Around line 913-939: The switch case for "tool-input-start" declares variables
(e.g., const executionStarted) directly under the case which triggers the Biome
noSwitchDeclarations rule; fix it by wrapping the entire case body in its own
block (add { ... } after case "tool-input-start":) so declarations like
executionStarted, part, and the ctx.toolcalls assignment are scoped properly;
ensure the existing calls to session.updatePart,
ctx.pendingStartedToolCalls.delete, Deferred.make, and
applyPendingToolUpdates(value.id) remain inside that new block.

In `@packages/opencode/src/session/run-state.ts`:
- Around line 217-225: The cancel() implementation in SessionRunState currently
returns early when there is no busy runner, skipping notifyCancelObservers and
leaving queued ensureRunning() tasks without the new onCancel hook; update
cancel(sessionID, meta) to ensure observers get notified even when no
existing.busy runner exists (e.g., call data.notifyCancelObservers(sessionID,
meta) before the early return) or alternatively change
ensureRunning()/withActiveRun so onCancel is registered only after a runner is
created; reference functions/objects: cancel, ensureRunning, withActiveRun,
InstanceState.get(state), data.runners, and data.notifyCancelObservers to locate
and apply the fix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 882645fc-04dd-4d16-a884-ad6e677ad5c8

📥 Commits

Reviewing files that changed from the base of the PR and between 036f1e7 and fba902d.

📒 Files selected for processing (6)
  • packages/opencode/src/session/llm.ts
  • packages/opencode/src/session/processor.ts
  • packages/opencode/src/session/prompt.ts
  • packages/opencode/src/session/run-state.ts
  • packages/opencode/test/session/compaction.test.ts
  • packages/opencode/test/session/processor-effect.test.ts

Astro-Han added a commit that referenced this pull request Jun 10, 2026
Provider-side ContextOverflowError handling now respects compaction.auto: false for normal assistant turns instead of setting needsCompaction and silently compacting.

This imports the Line B #30749 runtime correctness fix while keeping the scope isolated from #927/tool-drain/recovery work and from PR #1252, whose processor.ts collision was owner-accepted as rebase-later.

Changes:
- Stop normal assistant provider overflow with the provider ContextOverflowError when auto compaction is disabled.
- Preserve summary/compaction assistant overflow behavior so SessionCompaction still writes its explicit compact failure error.
- Add focused coverage for disabled-auto provider overflow and the summary-compaction boundary.

Verification:
- RED: bun --cwd packages/opencode test test/session/processor-effect.test.ts -t "stops structured context overflow when auto compaction is disabled" failed because the processor returned "compact".
- bun --cwd packages/opencode test test/session/processor-effect.test.ts -t "stop structured context overflow when auto compaction is disabled" -> pass.
- bun --cwd packages/opencode test test/session/processor-effect.test.ts -t "compact on structured context overflow" -> pass.
- bun --cwd packages/opencode test test/session/compaction.test.ts -t "marks summary message as errored on compact result when auto compaction is disabled" -> pass.
- bun --cwd packages/opencode test test/session/processor-effect.test.ts -> 36 pass.
- bun --cwd packages/opencode test test/session/compaction.test.ts -> 51 pass.
- bun run --cwd packages/opencode typecheck -> pass.
- git diff --check -> pass.
- Fresh-eye reviewer rerun after semantic diff change -> no issues found.
- CI run 27288199573 -> success.
- windows-advisory run 27288199605 -> success.
Astro-Han added a commit that referenced this pull request Jun 10, 2026
Root cause / goal:
SessionPrompt persists an assistant scaffold before processor handling fully owns the turn. Cancellation in that early window could leave an empty unfinished assistant message with no abort error or completion timestamp, poisoning later session history. This ports the focused upstream anomalyco/opencode#27254 behavior only.

Change boundary:
- Finalize the current unfinished assistant scaffold from the shared prompt-loop interrupt cleanup path when cancellation happens before processor cleanup owns the assistant.
- Preserve existing cancel semantics and diagnostics, and avoid importing #1252 tool-drain behavior, #30804 filtering, provider/MCP/UI/package changes, or adjacent refactors.
- Add regression coverage for cancellation after assistant scaffold persistence and after processor handle creation but before process starts.

Verification:
- RED proof: new regression first failed because the canceled scaffold had no MessageAbortedError.
- Focused regression: bun test --timeout 30000 ./test/session/prompt-effect.test.ts -t "cancel after assistant scaffold save finalizes before processor handle|cancel after processor handle creation finalizes before process starts" -> 2 passed.
- Prompt interruption suite: bun test --timeout 30000 ./test/session/prompt-effect.test.ts -> 65 passed.
- Processor abort slice: bun test --timeout 30000 ./test/session/processor-effect.test.ts -t "abort|interrupt" -> 6 passed.
- Typecheck: bun run typecheck in packages/opencode -> passed.
- Whitespace: git diff --check origin/dev...HEAD -> passed.
- PR CI: required checks green; full current check set including windows-advisory green.

Reviews:
- Terminal Claude review: PASS after final diff.
- Independent terminal Occam fresh-eye review: PASS, no P0/P1/P2 after addressing the post-handle/pre-process cancellation window.
- GitHub review threads: none unresolved.

Residual risk:
Canceled assistants still follow existing semantics and do not set finish; this PR only ensures aborted scaffolds carry MessageAbortedError and time.completed.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/opencode/src/session/processor.ts (1)

1056-1092: ⚠️ Potential issue | 🟠 Major

Wrap the tool-input-start switch case in braces

case "tool-input-start": declares const bindings (lifecycle, part, current) directly in the case without a block, which trips Biome’s noSwitchDeclarations pattern and can create shared TDZ/scope issues across cases. Wrap the case in { ... }.

🧩 Minimal fix
-          case "tool-input-start":
+          case "tool-input-start": {
             if (ctx.assistantMessage.summary) {
               throw new Error(`Tool call not allowed while generating summary: ${value.toolName}`)
             }
             const lifecycle = yield* getToolLifecycleRecord(value.id)
             if (lifecycle.settled) return
             const part = yield* session.updatePart({
               id: lifecycle.partID ?? PartID.ascending(),
               messageID: ctx.assistantMessage.id,
               sessionID: ctx.assistantMessage.sessionID,
               type: "tool",
               tool: value.toolName,
               callID: value.id,
               state: { status: "pending", input: {}, raw: "" },
               metadata: value.providerExecuted ? { providerExecuted: true } : undefined,
             } satisfies MessageV2.ToolPart)
             ctx.toolcalls[value.id] = {
               ...lifecycle,
               partID: part.id,
               messageID: part.messageID,
               sessionID: part.sessionID,
               attemptID,
             }
             const current = ctx.toolcalls[value.id]
             if (current.executionStarted && current.startedToolName && !current.executionStartedRecorded) {
               current.executionStartedRecorded = true
               ctx.runTrace.recordToolExecutionStarted({
                 attemptID,
                 at: Date.now(),
                 monotonicMs: performance.now(),
                 toolName: RunObservability.safeToolName(current.startedToolName),
                 effect: RunObservability.toolEffect(current.startedToolName),
               })
             }
             yield* Deferred.succeed(current.partCreated, undefined).pipe(Effect.ignore)
             yield* applyPendingToolUpdates(value.id)
             return
+          }
🤖 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 `@packages/opencode/src/session/processor.ts` around lines 1056 - 1092, The
switch case for "tool-input-start" declares block-scoped consts (lifecycle,
part, current) without its own block which violates noSwitchDeclarations; wrap
the entire case body in braces { ... } so those const bindings are scoped to
this case, preserving the existing flow/returns and ensuring you still call
getToolLifecycleRecord, session.updatePart, set ctx.toolcalls[value.id], record
executionStarted with ctx.runTrace, Deferred.succeed(...), and
applyPendingToolUpdates(value.id) as before.

Source: Linters/SAST tools

🤖 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 `@packages/opencode/src/session/processor.ts`:
- Around line 413-425: getToolLifecycleRecord currently creates new Deferreds
even after cleanup() clears ctx.toolcalls, causing callers like
completeToolExecution()/failToolExecution() and LLM.wrapToolsWithLifecycle() to
wait forever; change getToolLifecycleRecord to detect teardown (e.g.,
ctx.toolcalls missing or a ctx.draining/teardown flag set by cleanup) and return
a pre-resolved/pre-rejected lifecycle record whose partCreated/ready/done
deferreds are already completed so downstream awaits never block after teardown;
update cleanup() to set the teardown flag (or clear ctx.toolcalls) consistently
and ensure completeToolExecution()/failToolExecution() will work with the
pre-resolved record.

---

Outside diff comments:
In `@packages/opencode/src/session/processor.ts`:
- Around line 1056-1092: The switch case for "tool-input-start" declares
block-scoped consts (lifecycle, part, current) without its own block which
violates noSwitchDeclarations; wrap the entire case body in braces { ... } so
those const bindings are scoped to this case, preserving the existing
flow/returns and ensuring you still call getToolLifecycleRecord,
session.updatePart, set ctx.toolcalls[value.id], record executionStarted with
ctx.runTrace, Deferred.succeed(...), and applyPendingToolUpdates(value.id) as
before.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cd72894e-8aed-4e57-a1e8-a0ce7703b562

📥 Commits

Reviewing files that changed from the base of the PR and between fba902d and f272304.

📒 Files selected for processing (10)
  • packages/opencode/src/session/llm.ts
  • packages/opencode/src/session/message-v2.ts
  • packages/opencode/src/session/processor.ts
  • packages/opencode/src/session/prompt.ts
  • packages/opencode/src/session/run-state.ts
  • packages/opencode/test/permission-agent.test.ts
  • packages/opencode/test/session/compaction.test.ts
  • packages/opencode/test/session/llm.test.ts
  • packages/opencode/test/session/processor-effect.test.ts
  • packages/opencode/test/session/prompt-effect.test.ts
💤 Files with no reviewable changes (1)
  • packages/opencode/test/permission-agent.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/opencode/src/session/run-state.ts

Comment thread packages/opencode/src/session/processor.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request harness Model harness, prompts, tool descriptions, and session mechanics P1 High priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant