diff --git a/TODO.md b/TODO.md index 4e3b07f6..d9be9060 100644 --- a/TODO.md +++ b/TODO.md @@ -16,6 +16,9 @@ - [ ] ユーザーマニフェストのモデル設定 wizard → [tickets/tui-user-model-setup.md](tickets/tui-user-model-setup.md) - [ ] サブミット入力 - [ ] FileRef リゾルバ → [tickets/submit-file-ref-resolver.md](tickets/submit-file-ref-resolver.md) +- [ ] Manifest: Tool Output / File Upload 上限の分離とデフォルト緩和 → [tickets/manifest-output-upload-limits.md](tickets/manifest-output-upload-limits.md) - [ ] メモリ機構 - [ ] 使用頻度メトリクス + Knowledge 化候補レポート → [tickets/memory-usage-metrics.md](tickets/memory-usage-metrics.md) +- [ ] セッション内 TODO ツール(注意機構付き) → [tickets/session-todo.md](tickets/session-todo.md) - ワークスペースのメモリーをLintするヘッドレスCLI +- system-reminder 注入機構の汎用化(2件目の利用者が出た時に検討。タグ形式と「履歴を汚さない」原則は session-todo で先行確立) diff --git a/tickets/manifest-output-upload-limits.md b/tickets/manifest-output-upload-limits.md new file mode 100644 index 00000000..5ce0cad9 --- /dev/null +++ b/tickets/manifest-output-upload-limits.md @@ -0,0 +1,36 @@ +# Manifest: Tool Output / File Upload 上限の分離とデフォルト緩和 + +## 背景 + +現在、tool result の本文上限は `manifest::defaults::TOOL_OUTPUT_MAX_BYTES` に集約され、`worker.tool_output.default_max_bytes` として manifest から設定できる。一方で submit 時の `FileRef` 添付(`@` を `[File: ]` system message に展開する経路)も同じ `TOOL_OUTPUT_MAX_BYTES` を直接使っており、upload / attachment 用の上限として独立して設定できない。 + +このため、tool output の安全な truncation と、ユーザーが明示的に添付したファイル本文の取り込み量を別々に調整できない。また現在の既定値 16 KiB は、ファイル添付・tool output の双方で実運用上やや厳しい。 + +## ゴール + +Tool Output と submit 時 FileRef upload / attachment の上限を manifest でそれぞれ設定できるようにし、既定値を現在の 16 KiB より緩和する。 + +## 要件 + +- Tool Output の上限は引き続き manifest から設定できること +- FileRef upload / attachment の上限を Tool Output とは別の manifest field として設定できること +- FileRef resolver は hard-coded な `manifest::defaults::TOOL_OUTPUT_MAX_BYTES` ではなく、解決済み manifest の upload / attachment 上限を使うこと +- Tool Output と FileRef upload / attachment の既定値を、現在の 16 KiB から引き上げること + - 正確な値は実装時に決めてよいが、docs / tests / manifest defaults の説明と一致させること +- manifest cascade / overlay / serde default のいずれの経路でも同じ既定値・同じ field semantics になること +- 既存 manifest で新 field が未指定の場合は、新しい既定値で動作すること +- 既存の per-tool override の挙動を壊さないこと + +## 完了条件 + +- Tool Output と FileRef upload / attachment を別々に manifest で設定できる +- FileRef upload / attachment の truncate テストが、新 field の値を使うことを検証している +- Tool Output の既存テストが、新しい既定値・既存 override semantics に合わせて更新されている +- `docs/pod-factory.md` など manifest 設定のドキュメントが更新されている +- 16 KiB を前提にしたコメント・テスト値・ドキュメントが残っていない + +## 範囲外 + +- 正確な token counting による上限管理への移行 +- UI 側で添付ファイルサイズを事前表示・警告する機能 +- compact / auto-read の token budget 設計変更 diff --git a/tickets/session-todo.md b/tickets/session-todo.md new file mode 100644 index 00000000..81994966 --- /dev/null +++ b/tickets/session-todo.md @@ -0,0 +1,74 @@ +# セッション内 TODO ツール + +## 背景 + +長めのタスクを LLM に進めさせる際、Claude Code / OpenCode が備える「セッション内 TODO リスト」相当の機構が無いため、エージェントが自分の作業計画を構造化された形で保持・更新できない。Reasoning や text 出力の中で擬似的に TODO を書くことはできるが、 + +- ターンを跨いだとき直近の TODO 状態が context から押し出される +- compact を跨ぐと完全に消える +- ツール結果ではないため、状態の上書き・部分更新の規約が決まらず、意図と乖離した「やったつもり」を引き起こす + +この用途のために、セッション内に正規化された TODO リストを保持し、ターンごとに LLM へ最新状態を再提示(注意機構)し、compact を跨いで保存される専用ツールを導入する。 + +## 方針 + +- **保存先は `tools` 層の session-lifetime 状態**。`Tracker` と同じ生存スコープで `Pod` が所有。`Arc>>` ベースの `TodoStore` を tool に注入する +- **永続化は専用レーンを持たない**。`tool_call.arguments` がセッションログに既に乗っているため、resume 時には履歴 replay の中で最後の `todo_write` 引数を `TodoStore` に再適用すれば状態が復元される +- **注意機構は `pre_llm_request` Interceptor**。直近の user message に `` ブロックを揮発的に append するだけ。履歴・ログには載せない +- **system-reminder 注入の汎用化はやらない**。利用者が TODO 1個しかない段階で抽象を立てない(CLAUDE.md「概念の追加は不在が問題になってから」)。ただし「タグ形式は `...` で揃える」「履歴は汚さない」の2点は本実装で確立し、将来の追加機構が同じ規約に乗れるようにする + +## 要件 + +### `todo_write` ツール + +- 入力は TODO リスト全体(全置換)。差分更新は受けない +- 各エントリは `id` / `content` / `status (pending | in_progress | completed)` の 3 フィールド +- `id` は LLM 側が一貫して採番できる文字列。同 id があれば置換、なければ新規。順序は配列順を信頼 +- 戻り値は更新後のスナップショットを summary に含める(次ターンで再確認可能) +- 読み出し専用ツール(`todo_read`)は作らない。注意機構と tool result snapshot で代替 + +### Resume 時の復元 + +- `Pod::resume` の履歴 replay 中に `todo_write` の `tool_call.arguments` を観測したら、`TodoStore` を引数値で上書き +- 専用 LogEntry / Persistence 型は追加しない(`Tracker` と同じ方針) +- `tool_call.arguments` のフォーマットが `todo_write` の引数 schema と乖離した場合(旧バージョンのログ)は、その call を無視してよい + +### Compact 跨ぎ + +- compact 起動時、Pod は現在の `TodoStore` スナップショットを compact worker context に渡す +- compact worker は summary を書く際、未完了 TODO を summary 文に取り込める情報源として参照する(強制ではない) +- compact 後の新セッション開始時、Pod は **`mark_read_required` と同じ system message 注入レーン**に「未完了 TODO スナップショット」を 1 メッセージとして注入する +- 新セッションは空の `TodoStore` で始まる。次に LLM が `todo_write` を呼び出した時点で再構築される(system message に書かれたスナップショットがその拠り所) +- compact worker に TODO 編集権限は与えない(消去・縮約はしない) + +### 注意機構(Interceptor) + +- `pre_llm_request` で `Vec` を受け取り、未完了 TODO(`pending` または `in_progress`)が 1 件でも存在する場合に発動 +- 直近の user message の content(または content[最終 text part])の末尾に `` ブロックを append +- ブロック内には現在の TODO リストを、status を含む簡潔な形式で列挙 +- 履歴 (`Worker` の保持する `Vec`) は変更しない。リクエスト送信時の Vec のみ加工 +- TODO が空の場合は何も差し込まない + +## 完了条件 + +- `todo_write` ツールが builtin tool として登録され、Pod で利用できる +- LLM が `todo_write` を呼ぶと TodoStore が更新され、その後の `pre_llm_request` で system-reminder として LLM に再提示される +- セッションを resume すると、最後の `todo_write` の状態から再開される +- compact を跨いでも、未完了 TODO が新セッション冒頭の system message として残る +- system-reminder の注入は揮発的で、`get_history` / セッションログには現れない +- 単体テストで `todo_write` の更新挙動 / replay 復元 / Interceptor の差し込みがカバーされる + +## 範囲外 + +- 差分更新 API(add / remove / patch)。全置換のみで十分 +- TODO 階層・優先度・タグ +- TUI / GUI での TODO 状態の可視化(ツール呼び出しのイベントは既に流れているので、クライアント側で表示するかは別軸) +- system-reminder 注入機構の汎用化(`TODO.md` に立項済み、別途検討) +- TODO の永続化を専用 LogEntry に分離する設計(現方針は tool_call replay で復元、追加レーン不要) +- 複数 Pod 間で TODO を共有する仕組み + +## 参照 + +- 設計指針: `CLAUDE.md`(最小の構造化 / 概念の追加は不在が問題になってから) +- 参考実装: Claude Code の TodoWrite、OpenCode の todo tool +- 関連: `crates/tools/src/tracker.rs`(session-lifetime 状態の前例)、`crates/pod/src/compact/worker.rs`(auto-injection レーン)