Skip to content

fix(chat): end background-subagent turns and correlate completions - #98

Merged
luoxuanzao merged 1 commit into
mainfrom
fix/background-subagent-stop-hook
Nov 12, 2026
Merged

luoxuanzao merged 1 commit into
mainfrom
fix/background-subagent-stop-hook

Conversation

@luoxuanzao

Copy link
Copy Markdown
Member

Summary

  • Drop the Stop hook that demanded an unavailable tool. It blocked every turn end while a background subagent was alive and told the model to wait on TaskOutput, which qodercli never exposed. Turns that launched background work looped on the same explanation until interrupted, and interrupts left the state behind, so the session stayed unusable (only a new conversation helped). The CLI already feeds completion notifications back into the model's context on its own and runs a follow-up turn; removing the hook lets turns end normally. Removes subagent-hooks.ts and all wiring (buildHooks, setSubagentStateSource, SubagentRuntimeState, hasRunningSubagents).
  • Correlate background task notifications by tool_use_id. The CLI reports completion with a task_id from its own registry, which shares no id space with the agentId parsed out of the Agent tool result that the block is keyed by — so the block was never released and stayed on "Running" for the rest of the conversation (and was falsely marked orphaned on switch). The notification's tool_use_id is the launching Agent call, which is already our key; prefer it, keep the agentId lookup as a fallback, and let a notification claim a block whose agentId was never parsed.

Verification

  • npm run typecheck
  • npm run lint
  • npm run test (3611 passed)
  • npm run build (renderer-safe-unref patch applied; no bare heartbeatWatchdog.unref())
  • npm run release:check
  • npm run audit:prod (0 vulnerabilities)
  • Tested affected qodercli behavior against a real CLI when applicable — real Obsidian end-to-end with qodercli 1.1.87 + SDK 1.0.58: a background subagent turn ends normally (no loop, zero TaskOutput mentions), the card transitions Running → completed with the result, and the CLI's follow-up turn delivers it. Session jsonl confirms the notification's tool-use-id matches the launching Agent call while task-id differs.

Safety

  • No credentials, private vault content, internal URLs, or personal paths are included
  • User-visible changes are documented in CHANGELOG.md

The Stop hook blocked every turn end while a background subagent was alive
and told the model to wait on TaskOutput, a tool qodercli never exposed.
Turns that launched background work looped on the same explanation until
interrupted, and interrupts left the state behind, so the session stayed
unusable. The CLI already feeds completion notifications back into the
model's context on its own; drop the hook and let turns end normally.

The notification's task_id comes from the CLI's task registry and shares no
id space with the agentId parsed out of the Agent tool result, so the block
was never released and stayed on Running for the rest of the conversation.
Correlate by the notification's tool_use_id — the launching Agent call,
which is already our key — keeping the agentId lookup as a fallback and
letting a notification claim a block whose agentId was never parsed.

Co-authored-by: QoderAI (Qwen 3.8 Max) <qoder_ai@qoder.com>
@luoxuanzao
luoxuanzao merged commit 02d68bd into main Nov 12, 2026
10 checks passed
@luoxuanzao
luoxuanzao deleted the fix/background-subagent-stop-hook branch November 12, 2026 07:44
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