Skip to content

feat: surface todo state before non-todo tool calls - #430

Merged
LeXwDeX merged 7 commits into
mainfrom
feat/429-surface-todo-state
Aug 24, 2026
Merged

feat: surface todo state before non-todo tool calls#430
LeXwDeX merged 7 commits into
mainfrom
feat/429-surface-todo-state

Conversation

@LeXwDeX

@LeXwDeXLeXwDeX commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Closes#429

Why

#389 交付的每模型步 todo 提醒在长回合中段存在盲区:一步内连续多次工具调用之间,列表漂移对模型不可见。本需求是 #389 探索记录中被搁置的原始接缝(pre-tool-call),按用户决策以受控形式落地:同一 assistant 轮内仅首次非 todowrite 工具调用前注入一次(按 messageID 去重,化解 #389 否决理由①并行重复 N 次;盲区②纯推理步仍由既有 per-step 提醒覆盖,两接缝互补)。

What changed

  • session/todo-reminders.ts:新增 turn 级去重状态与 preToolCall 导出——非 todowrite 工具、当前轮未注入过、且存在 uncompleted 项时返回启发式提醒字符串(复用 renderReminder)
  • session/tools.ts:两个 PreToolUse 站点(内置工具 / MCP 工具)把该字符串并入 additionalContexts 前置到工具结果;todowrite 自身永不注入也不消耗轮次名额

Evidence

  • bun test test/session/todo-reminders.test.ts:14/14 pass(9 既有 + 5 新增:首轮注入 / 同轮去重 / 新轮重臂 / todowrite 不注入不标记 / 全静默列表不注入)
  • bun typecheck(packages/opencode):通过;根 bun turbo typecheck:29/29
  • bun run lint:4839 warnings ≤ 4850 棘轮(与基线持平)

Checklist

  • Why, What changed, and Evidence are filled in.
  • specgit finish exits 0.

Extends the issue-#389 todo reminder feature with the pre-tool-call seam it
originally proposed and deliberately deferred. The per-step reminder covers
tool-free steps; this adds mid-turn coverage so long multi-tool turns keep
seeing the uncompleted list between calls.
- TodoReminders.preToolCall: returns the rendered reminder before a
non-todowrite tool call, at most once per assistant turn (turn-scoped
marker keyed by assistant messageID), never for todowrite itself
- tools.ts: both PreToolUse sites (native tools + MCP tools) prepend the
reminder to additionalContexts ahead of any hook contexts
Turn-scoped dedup answers #389's objection to this seam (N parallel calls ->
N duplicate reminders); pure-reasoning steps stay covered by the existing
per-step injection, so the two seams complement instead of compete.
Tests: first-call injects, same-turn repeat skips, new turn re-arms,
todowrite never injects nor consumes the turn shot, settled list stays quiet.
@LeXwDeX
LeXwDeX marked this pull request as ready for review August 24, 2026 06:09
snapshot-tool-race failed deterministically with the pre-tool-call reminder:
minimal server fixtures do not provide Todo.Service, so the unconditional
yield* died and took the whole tool execution down with it — the bash command
never ran. The reminder is decoration on top of execution; it now degrades to
no-reminder on any non-interrupt failure while interrupts still propagate.
Found by the existing snapshot race gate; no new test seam needed.
@LeXwDeX
LeXwDeX merged commit 7937072 into mainAug 24, 2026
9 checks passed
@LeXwDeX
LeXwDeX deleted the feat/429-surface-todo-state branch August 24, 2026 10:29
Sign up for freeto 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.

feat: surface todo state before non-todo tool calls

1 participant

@LeXwDeX