# Pod Protocol 仕様 ## 概要 Pod の制御・監視に使う JSONL ベースのメッセージプロトコル。 トランスポートに依存しない。CLI は Pod を直接制御し、daemon は Unix socket 上でこのプロトコルを中継する。 - **フレーミング**: 1行 = 1 JSON オブジェクト(`\n` 区切り) - **方向**: 双方向。クライアントはメソッドを送信し、Pod はイベントを emit する ``` CLI → Pod Protocol (直接呼び出し) Native App → Pod Protocol (直接呼び出し) Web → 中央バックエンド → daemon (Unix socket) → Pod Protocol ``` ## 設計原則 - リクエストとレスポンスの紐付けはしない。Pod は1つであり、Pod の状態遷移(イベント)を見れば何が起きているか分かる - イベントは全リスナーに broadcast される。読み取り専用の監視も、操作側も同じストリームを受け取る - 操作の競合は先勝ち。run 中に別の run が来たらエラーイベントを返す ## メッセージ形式 ### クライアント → Pod(メソッド) ```json {"method": "", "params": {<...>}} ``` `params` はメソッドごとに異なる。省略可能な場合は `params` フィールド自体を省略できる。 ### Pod → クライアント(イベント) ```json {"event": "", "data": {<...>}} ``` 全リスナーに broadcast される。 ## メソッド一覧 ### `run` ユーザー入力を送信し、LLM ターンを開始する。 ```json {"method": "run", "params": {"input": "What is the capital of France?"}} ``` Pod が既に実行中の場合、エラーイベントが返る。 ### `resume` Paused 状態から再開する。 ```json {"method": "resume"} ``` ### `cancel` 実行中のターンをキャンセルする。 ```json {"method": "cancel"} ``` ### `get_status` Pod の現在の状態を要求する。応答は `status` イベントとして返る。 ```json {"method": "get_status"} ``` ### `get_history` 会話履歴を要求する。応答は `history` イベントとして返る。 ```json {"method": "get_history"} ``` ## イベント一覧 ### ターン制御 #### `turn_start` LLM ターンの開始。 ```json {"event": "turn_start", "data": {"turn": 1}} ``` #### `turn_end` LLM ターンの完了。 ```json {"event": "turn_end", "data": {"turn": 1, "result": "finished"}} ``` `result`: `"finished"` | `"paused"` ### ストリーミング #### `text_delta` テキスト応答の差分。 ```json {"event": "text_delta", "data": {"text": "The capital"}} ``` #### `text_done` テキストブロックの完了。全文を含む。 ```json {"event": "text_done", "data": {"text": "The capital of France is Paris."}} ``` #### `thinking_delta` 思考プロセスの差分(extended thinking 対応モデル)。 ```json {"event": "thinking_delta", "data": {"text": "Let me consider..."}} ``` #### `thinking_done` 思考ブロックの完了。 ```json {"event": "thinking_done", "data": {"text": "..."}} ``` ### ツール #### `tool_call_start` ツール呼び出しの開始。 ```json {"event": "tool_call_start", "data": {"id": "call_123", "name": "search"}} ``` #### `tool_call_args_delta` ツール引数の JSON 差分(ストリーミング中)。 ```json {"event": "tool_call_args_delta", "data": {"id": "call_123", "json": "{\"query\":"}} ``` #### `tool_call_done` ツール呼び出しの引数確定。 ```json {"event": "tool_call_done", "data": {"id": "call_123", "name": "search", "arguments": "{\"query\": \"Paris\"}"}} ``` #### `tool_result` ツール実行結果。 ```json {"event": "tool_result", "data": {"id": "call_123", "output": "Paris is the capital...", "is_error": false}} ``` ### 状態 #### `status` `get_status` への応答、または状態変化時に送信。 ```json {"event": "status", "data": {"state": "idle", "session_id": "019d6e91-...", "pod_name": "hello-pod"}} ``` `state`: `"idle"` | `"running"` | `"paused"` #### `history` `get_history` への応答。 ```json {"event": "history", "data": {"items": [...]}} ``` `items` は llm-worker の `Item` 配列をそのまま JSON シリアライズしたもの。 ### メタ #### `usage` トークン使用量。 ```json {"event": "usage", "data": {"input_tokens": 25, "output_tokens": 150}} ``` #### `error` エラー通知。 ```json {"event": "error", "data": {"code": "already_running", "message": "Pod is already executing a turn"}} ``` エラーコード: - `already_running` — run 中に run が来た - `not_running` — run していないのに resume/cancel が来た - `not_paused` — paused でないのに resume が来た - `provider_error` — LLM プロバイダからのエラー - `tool_error` — ツール実行エラー - `internal` — 内部エラー ## リスナーのライフサイクル 1. リスナーが登録される(直接呼び出しなら関数登録、daemon 経由なら socket 接続) 2. 登録直後から Pod のイベントが流れ始める(購読手続き不要) 3. クライアントはメソッドを任意のタイミングで送信できる 4. リスナーの解除は登録解除または接続切断で行う ## トランスポート: daemon (Unix socket) daemon は Pod Protocol を Unix domain socket 上で中継する薄い層。 - クライアントが socket に接続するとリスナーとして登録される - メソッドは socket 経由で Pod に転送される - 切断時にリスナーリストから除外するだけでクリーンアップ完了 ## イベントと llm-worker の対応 | イベント | llm-worker ソース | |---------------|-----------------| | `turn_start` | Subscriber `on_turn_start` | | `turn_end` | Subscriber `on_turn_end` + `WorkerResult` | | `text_delta` | `TextBlockEvent::Delta` | | `text_done` | Subscriber `on_text_complete` | | `thinking_delta` | `ThinkingBlockEvent::Delta` | | `thinking_done` | `ThinkingBlockEvent::Stop` | | `tool_call_start` | `ToolUseBlockEvent::Start` | | `tool_call_args_delta` | `ToolUseBlockEvent::InputJsonDelta` | | `tool_call_done` | Subscriber `on_tool_call_complete` | | `tool_result` | `PostToolCall` hook | | `usage` | `UsageEvent` | | `error` | `ErrorEvent` / `WorkerError` | | `status` | Pod 状態(Pod 層が管理) | | `history` | `Worker::history()` |