maestro/docs/context-flow.md
2026-06-03 05:08:00 +00:00

8.9 KiB

コンテキスト構築と溢れ時動作

この資料は、新規メッセージ送信時に何が LLM へ渡るか、movement 間で何が引き継がれるか、コンテキストが逼迫した時にどう動くかをまとめたものです。

全体像

flowchart TD
  U[UI / API からタスク・コメント送信] --> DB[(SQLite jobs / comments)]
  DB --> W[Worker が job を取得]
  W --> C[会話コンテキストを組み立て]
  C --> P[piece-runner が Piece を実行]
  P --> M[Movement 開始]
  M --> A[agent-loop: LLM に送信]
  A --> T{LLM 応答}
  T -->|tool_call| X[許可されたツールを実行]
  X --> H[ツール結果を movement 内履歴へ追加]
  H --> A
  T -->|transition| N{next_step}
  N -->|次 movement| P
  N -->|COMPLETE| S[Job succeeded]
  N -->|ASK| Q[waiting_human]
  N -->|ABORT| F[failed / aborted]
  N -->|WAIT_SUBTASKS| ST[waiting_subtasks]

新規メッセージで送られる内容

ローカルタスクでは、Worker が job.instruction をそのまま送るのではなく、現在時刻、直近コメント、workspace 状況、タスク本文をまとめた enrichedInstruction を作ります。

flowchart TD
  J[job.instruction] --> E[enrichedInstruction]
  Time[現在日時ブロック] --> E
  Comments[直近コメント最大5件] --> Trunc[各コメント最大500文字に切り詰め]
  Trunc --> E
  Files[input/ と output/ のファイル一覧] --> E
  E --> Piece[runPiece]

含まれるもの:

種別 内容
現在時刻 buildTimeContextBlock() の結果
これまでのやり取り Local task comments の末尾 5 件
コメント本文 1 コメントあたり最大 500 文字
workspace 状況 input/output/ のファイル一覧
タスク本文 現在の job.instruction

含まれないもの:

  • すべての過去コメント全文
  • 過去 movement の LLM 会話履歴全文
  • logs/ 配下のログ全文
  • input/ / output/ のファイル本文そのもの

ファイル本文が必要な場合は、movement 内で Read などのツールを使って取得します。

Movement 内で送られる内容

各 movement は、system prompt と user prompt から開始します。movement の中では、LLM がツールを呼ぶたびに assistant の tool call と tool result が同じ movement の messages に追加され、次の LLM 呼び出しへ再送されます。

sequenceDiagram
  participant R as piece-runner
  participant L as agent-loop
  participant M as LLM
  participant T as Tool

  R->>L: movement + enrichedInstruction
  L->>M: system prompt + user prompt
  M-->>L: tool_call
  L->>T: executeTool
  T-->>L: tool result
  L->>M: これまでの messages + tool result
  M-->>L: transition(next_step, summary, lessons)
  L-->>R: MovementResult

movement 内で保持されるもの:

  • system prompt
  • user prompt
  • LLM の tool call
  • ツール結果
  • ReadImage などが返した画像コンテキスト
  • transition までのリマインド文

movement が終わると、この messages 全体は次 movement にそのまま渡されません。

Movement 間で引き継がれる内容

movement 間では、会話履歴全文ではなく、限定された要約情報だけが引き継がれます。

flowchart LR
  M1[Movement A] --> TR[transition]
  TR --> Lessons[lessons / summary]
  Lessons --> Log[logs/lessons.jsonl]
  Lessons --> Inject[次 movement の prompt に注入]
  Inject --> M2[Movement B]

主な引き継ぎ:

引き継ぎ元 次 movement への渡り方
transition の lessons ## 前のステップで得た教訓 として注入
lessons 未指定で COMPLETE summary / output を lesson として扱う
verify 系の指摘 対象 movement へフィードバックとして追記
チェックリスト logs/checklists/*.json から現在状態を注入
workspace の変更状況 一部の verify 後に git status / diff 抜粋を付加

Lessons は最大 2000 文字程度に抑えられ、古いものから削られます。

コンテキスト逼迫時の動作

ContextManager は LLM の usage が取れる場合は prompt_tokens、取れない場合は文字数推定で使用率を見ます。

デフォルト閾値:

使用率 action 動作
70% warn progress に警告を記録
85% prompt 「作業をまとめて transition してください」という user message を追加
95% force_transition 現 movement を強制的に defaultNext へ進める。defaultNext がなければ ABORT
99% exhausted 判定 内部判定用。直接の圧縮処理ではない
flowchart TD
  LLM[LLM 応答完了] --> Usage{usage あり?}
  Usage -->|あり| Tokens[prompt_tokens を記録]
  Usage -->|なし・3 iteration 以降| Chars[messages 文字数から推定]
  Tokens --> Ratio[context 使用率を計算]
  Chars --> Ratio
  Ratio --> Warn{70%以上?}
  Warn -->|warn 未発火| W[warn action]
  Ratio --> Prompt{85%以上?}
  Prompt -->|prompt 未発火| P[transition 促しを messages に追加]
  Ratio --> Force{95%以上?}
  Force -->|force_transition 未発火| F[defaultNext へ強制遷移]

現状の重要点:

  • コンテキスト逼迫時に、会話全体を自動要約して同じ movement を継続する処理はありません。
  • force_transition は「完了した」と判断するのではなく、movement.defaultNext へ進める機械的な退避です。
  • defaultNextCOMPLETE の movement では、結果として完了扱いになる場合があります。
  • defaultNext がない場合は ABORT になります。

ツール出力の切り詰め

大きなファイルやコマンド出力をそのまま入れると movement 内の messages が膨らむため、一部ツールは残コンテキストに応じて出力を自動切り詰めします。

flowchart TD
  Tool[Read / Bash / Office 系ツール] --> Budget[残コンテキストから tool result 予算を計算]
  Budget --> Fit{予算内?}
  Fit -->|Yes| Full[全文または要求範囲を返す]
  Fit -->|No| Cut[先頭側を返し、自動切り詰め注記を付ける]
  Cut --> Hint[続きを読む offset / byte_offset / grep 等を案内]

予算計算:

  • ContextManager がある場合: getAvailableTokens() の 50% を 1 回の tool result 予算にする
  • 予算の上限: 60,000 tokens
  • 予算の下限: 最低返却 tokens を確保
  • Read は行指向なら行境界、改行が少ないファイルは byte/char 境界で切ります
  • Bashhead / tail / grep / awk / sed などで絞る案内を付けます

よくあるパターン

1. 通常の新規タスク

flowchart TD
  Create[タスク作成] --> Recent[直近コメント最大5件 + workspace 状況]
  Recent --> Initial[initial_movement]
  Initial --> Tools[必要なファイルだけツールで読む]
  Tools --> Transition[transition]
  Transition --> Next[次 movement]

この場合、過去コメント全文やファイル本文は最初から全部送られません。

2. ユーザーへの ASK 後に再開

flowchart TD
  Ask[transition: ASK] --> Wait[Job waiting_human]
  Wait --> Reply[ユーザーが返信]
  Reply --> Queue[Job queued]
  Queue --> Worker[Worker が再取得]
  Worker --> Context[直近コメント最大5件を再構築]
  Context --> Resume[resumeMovement から再開]

ASK 再開時も、基本は直近コメントから再構築します。前回 movement 内の LLM メッセージ全文を保存して再投入する方式ではありません。

3. 長いファイルを読む

flowchart TD
  Read[Read large file] --> Budget{tool result 予算}
  Budget --> Truncated[自動切り詰め]
  Truncated --> Notice[続きの読み方を表示]
  Notice --> Targeted[必要範囲だけ再 Read / Grep]

長文を読む場合は、全文を一度に入れるより、検索や範囲指定で必要箇所を絞る前提です。

4. コンテキストが 95% を超える

flowchart TD
  High[Context 95%以上] --> Force[force_transition]
  Force --> HasDefault{defaultNext あり?}
  HasDefault -->|Yes| Next[defaultNext へ移動]
  HasDefault -->|No| Abort[ABORT]
  Next --> Runner[piece-runner が遷移判定を続行]

これは現状の退避動作です。圧縮サマリを作って同じ movement を継続する動作は未実装です。

参照実装

内容 ファイル
新規タスクの enrichedInstruction 構築 src/worker.ts
Piece / movement 遷移、Lessons 注入 src/engine/piece-runner.ts
movement 内の LLM messages と tool result 追加 src/engine/agent-loop.ts
コンテキスト閾値管理 src/engine/context-manager.ts
Read / Bash 等の tool result 切り詰め src/engine/tools/core.ts