Skip to content

feat(local-agent-loop): 止めた呼び出しの途中までの使用量と session ID を残す - #297

Merged
coji merged 8 commits into
mainfrom
feat/296-local-agent-loop-stopped-call-usage
Oct 10, 2026
Merged

coji merged 8 commits into
mainfrom
feat/296-local-agent-loop-stopped-call-usage

Conversation

@coji

@coji coji commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Summary

examples/local-agent-loop で、supersede(検査の失敗で止めたレビュー)、factory の時間切れ、run の取り消しで止めた agent 呼び出しにも、止めるまでに受け取ったモデル別の使用量と provider の session ID を残す(#296)。止めた呼び出しの結果は今までどおり使わない。

原因は runner ではなく provider だった。runner は途中の使用量を受け取れば残す作りだったが、Claude と Codex の provider はどちらも呼び出しの途中で使用量を通知していなかった(partialUsage = false)。ADR-0032 の「時間切れの試行は途中の使用量を保つ」も、実際の provider では空振りしていた。

  • Claude:API の応答ごとに累計を作る。assistant メッセージの usage は応答を始めた時点の値で output がほぼ 0 なので、途中の使用量を記録する呼び出しでは includePartialMessages を有効にし、message_start で応答を、message_delta でその応答の output を読む(各 leg は応答内で最大の値)。同じ message ID は 1 回だけ数え、<synthetic> と token のないフレームは数えない。subagent は command-mode review だけで数える(最終の modelUsage と同じ範囲)。session ID は各メッセージから早めに取る。実 provider で、最後まで走らせた呼び出しの最後の途中値が最終 usage と全 leg で一致すること(output 2,529 = 2,529、修正前は 19 対 3,322)と、supersede した呼び出しの output が checkpoint・replay・集計に残ること(11 秒で 474)を確認した。
  • Codex:app-server の raw 通知を受け取り、thread/tokenUsage/updated から当該 turn の累計を作る(再開した thread の過去 turn は含めない、token のない更新は無視)。raw の部品は generateText に渡さず、活動にも数えない。token のある使用量の通知は ADR-0032 どおり無通信タイマーを数え直す。thread ID は onSessionCreated から取る。1 呼び出し 1 モデルなので、モデル別の内訳は解決済みモデルで記録する(reportedModel にはしない)。
  • runner:受け取った累計・内訳・session ID・通知の件数と最後の時刻をメモリに持ち、metadata の書き込みが失敗しても失わない。supersede と時間切れでは、それを完了 checkpoint の partial に保存し、replay で provider を呼ばずに復元する。run の取り消しと lease 喪失は今までどおり start-only checkpoint の uncertain のままで、値は attempt の measurement にだけ残す。最終結果を受けた呼び出しは最終の使用量で置き換え、途中だけの内訳は消す。
  • measurement と report:止めた呼び出しに usageUntilStop(理由、通知件数、最後の通知の時刻と開始からの時間)を付ける。通知が 1 つもなければ usage は null のまま。JSON の stoppedCalls と Markdown の「Usage of stopped calls」節に出す。止めた呼び出しを含む集計は complete: false / costComplete: false(下限)として扱う。
  • 採点・承認・レビュー上限・realInvocationIds・fullLoopVerified は変えない。送る前に止めたレビュー(not-sent)は集計に入らない。
  • ADR-0034(accepted)、README の計測の節。

Test plan

  • 検査の失敗で止めたレビューの attempt、完了 checkpoint、JSON / Markdown report に、止めるまでのモデル別使用量と session ID が出る(fake の e2e)
  • 同じ完了 checkpoint の replay は provider を呼ばずに使用量・内訳・session ID・範囲を復元し、集計に一度だけ入る
  • 使用量の通知が 1 つもない止めた呼び出しは usage: null で、report で区別できる
  • run の取り消し・lease 喪失は完了 checkpoint を作らず uncertain のまま、値は measurement に残る
  • Claude の重複 message ID・synthetic frame・subagent の範囲、Codex の再開 thread・ゼロ token・raw 通知を活動に数えないこと
  • 最終結果に内訳がない呼び出しで途中の内訳が残らない
  • 止めた呼び出しを含む集計は complete / costComplete が false
  • pnpm validate

Review gate

GO in round 5. Reviewed head: ab9e00fab5b58091ccfa271015843a2edb2b9e95. Base: 0f163298f6eae52b8398dcb231cdcc12dfeb8d0d. pnpm validate: pass. CI: pass.

  • Round 1 (06b4d3a): NO-GO. Both tracks independently found two P2s. A call that finished with no final usage after partial reports was summed as complete (B1). After a worker died between the stop checkpoint and the terminal write, dedupe kept the stale started row, so the stopped call was missing from the report (B2). Fixed: any provider-partial usage makes a sum a lower bound, and dedupe prefers settled stop rows.
  • Round 2 (362eb40): NO-GO. The Markdown aggregate line used its own dedupe (R2-1). A finished call without final usage or session lost its early values on replay (R2-2). Fixed: one shared invocation selection, and the result checkpoint keeps partial when the result lacks usage or session.
  • Round 3 (1849555): NO-GO. The run summary printed an incomplete token total unmarked (R3-1). Fixed: summary.tokensComplete and (PARTIAL); demo compare treats incomplete totals as unknown.
  • Round 4 (cc2eb94): NO-GO. demo compare still counted an incomplete stage's cache reads (R4-1). Fixed.
  • Round 5 (ab9e00f): Codex CLEAR, Opus no blocker.

Non-blocking findings (P3):

  • A repair call stopped by the factory timeout shows its running-total input and cache-read ratio in the "Repair calls" table without a partial marker. These are one call's numbers, not a sum, and the call is also listed under "Usage of stopped calls".
  • A finished call that fails the drift or requireSession check after its checkpoint, if its worker dies before the terminal write, replays without usage. This was possible before this PR, and the window is tiny.
  • Codex raw chunks also enable experimentalRawEvents. The library offers no other public API for this, and ADR-0034 records it.
  • On the first API-key Codex call, an early zero cache write is recorded as unknown until the login probe returns. The final usage replaces it.
  • Each usage report triggers one metadata write.
  • The StoppedCallUsage / UsageUntilStop fields are duplicated, and usageTotals repeats the cost calculation.

Closes #296

Generated with spec-implement-accept skill

🤖 Generated with Claude Code

https://claude.ai/code/session_013YE1FnUCruD4Mtwbjx3nyq

@vercel

vercel Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated
durably-demo Ignored Ignored Preview Oct 10, 2026 12:00pm UTC
durably-demo-vercel-turso Ignored Ignored Preview Oct 10, 2026 12:00pm UTC

@coji
coji marked this pull request as ready for review October 10, 2026 09:48
@coji
coji marked this pull request as draft October 10, 2026 11:54
assistant メッセージの usage は応答を始めた時点の値で output がほぼ入らないため、
止めた Claude 呼び出しの output が 0 近くで記録されていた。途中の使用量を記録する
呼び出しでは includePartialMessages を有効にし、message_start と message_delta から
応答ごとの output を数える。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YE1FnUCruD4Mtwbjx3nyq
@coji
coji marked this pull request as ready for review October 10, 2026 12:05
@coji
coji merged commit abe0c0b into main Oct 10, 2026
5 checks passed
@coji
coji deleted the feat/296-local-agent-loop-stopped-call-usage branch October 10, 2026 13:04
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.

local-agent-loop: 止めたレビュー(supersede・cancel)の途中までの使用量と session ID を残す

1 participant