Pod操作ツール実装完了
This commit is contained in:
parent
2af7089396
commit
cc9fa2d632
1
TODO.md
1
TODO.md
|
|
@ -5,7 +5,6 @@
|
|||
- [ ] Protocol の設計 → [tickets/protocol-design.md](tickets/protocol-design.md)
|
||||
- [ ] パーミッション: パターンベースのツール実行制御 → [tickets/permission-extension-point.md](tickets/permission-extension-point.md)
|
||||
- [ ] Pod オーケストレーション
|
||||
- [ ] Pod 間通信ツール: SendToPod / ReadPodOutput / StopPod / ListPods → [tickets/pod-comm-tools.md](tickets/pod-comm-tools.md)
|
||||
- [ ] Pod 間コールバック通知 → [tickets/pod-callback.md](tickets/pod-callback.md)
|
||||
- [ ] 動的 Scope 変更 → [tickets/dynamic-scope.md](tickets/dynamic-scope.md)
|
||||
- [ ] ネイティブ GUI クライアント MVP → [tickets/native-gui-mvp.md](tickets/native-gui-mvp.md)
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
# Pod 間通信ツール: SendToPod / ReadPodOutput / StopPod / ListPods
|
||||
|
||||
レビュー中: [pod-comm-tools.review.md](pod-comm-tools.review.md)
|
||||
|
||||
## 背景
|
||||
|
||||
`SpawnPod` で Pod を生成した後、spawner の LLM が spawned Pod に指示を送り、結果を読み、完了したら停止させる手段が必要。
|
||||
|
||||
## 依存
|
||||
|
||||
- `tickets/spawn-pod-tool.md`: SpawnPod による Pod 生成と spawn 記録
|
||||
|
||||
## ツール群
|
||||
|
||||
すべて**都度接続の request-response** で動作する。spawned Pod の socket に接続し、操作を行い、切断する。
|
||||
|
||||
### `SendToPod`
|
||||
|
||||
既知の Pod にメッセージを送る。
|
||||
|
||||
入力:
|
||||
- `name`: 対象の Pod
|
||||
- `message`: 送信するテキスト
|
||||
|
||||
出力:
|
||||
- 送信確認
|
||||
|
||||
内部動作:
|
||||
- spawn 記録から `name` の socket path を引く
|
||||
- socket に接続 → `Method::Run { input: message }` を送信 → ack 受信 → 切断
|
||||
|
||||
### `ReadPodOutput`
|
||||
|
||||
既知の Pod の出力を読む。前回読んだ位置を自動追跡(カーソルベース)。
|
||||
|
||||
入力:
|
||||
- `name`: 対象の Pod
|
||||
|
||||
出力:
|
||||
- 前回読んだ位置以降の assistant テキスト出力
|
||||
- 現在の到達性(`alive` / `stopped`)
|
||||
|
||||
内部動作:
|
||||
- spawn 記録から socket path を引く
|
||||
- socket に接続 → `Method::GetHistory` で履歴取得 → 前回カーソル以降の assistant text を抽出 → カーソル更新 → 切断
|
||||
- 接続できなければ `stopped` として返す
|
||||
|
||||
### `StopPod`
|
||||
|
||||
既知の Pod を終了させ、譲渡した scope を回収する。
|
||||
|
||||
入力:
|
||||
- `name`: 対象の Pod
|
||||
|
||||
出力:
|
||||
- 終了要求を送った旨
|
||||
- 回収された scope の要約
|
||||
|
||||
内部動作:
|
||||
- socket に接続 → `Method::Shutdown` 送信(応答は待たない)→ 切断
|
||||
- scope lock file を flock → 対象の allocation 削除 → spawner の deny を解除 → unlock
|
||||
- spawn 記録から対象を削除
|
||||
|
||||
### `ListPods`
|
||||
|
||||
自分が知っている Pod の一覧と状態を返す。
|
||||
|
||||
入力: なし
|
||||
|
||||
出力:
|
||||
- 各 Pod の `name`、`name`、`status`、譲渡中の scope 要約、最終応答の要約
|
||||
|
||||
内部動作:
|
||||
- spawn 記録を元にリストを構築
|
||||
- 各 Pod に都度接続して health check(`Method::GetHistory` でステータス取得、接続できなければ `stopped`)
|
||||
- stopped な Pod は scope lock file の stale 回収をトリガー
|
||||
|
||||
## 設計で決めること
|
||||
|
||||
- **ReadPodOutput のカーソル管理**: spawn 記録内に `last_read_hash` を持つか、別の場所で管理するか
|
||||
- **StopPod と scope 回収の順序**: 先に Shutdown してから lock file を更新するか、lock file を先に更新するか(Shutdown が失敗した場合の整合性)
|
||||
- **ListPods の health check コスト**: 大量の Pod がいるとき全部に接続するのは重い。キャッシュ戦略
|
||||
|
||||
## 完了条件
|
||||
|
||||
- `SendToPod` で spawned Pod にメッセージを送り、Pod がそれを処理する
|
||||
- `ReadPodOutput` で spawned Pod の最新出力を読め、カーソルベースの差分取得が動作する
|
||||
- `StopPod` で spawned Pod を graceful に停止でき、scope が spawner に返却される
|
||||
- `ListPods` で既知の Pod の状態を一覧でき、health check が機能する
|
||||
- 接続できない Pod は `stopped` として扱われ、scope の stale 回収がトリガーされる
|
||||
- 単体テストで各ツールの正常系・異常系が検証される
|
||||
|
||||
## 範囲外
|
||||
|
||||
- コールバック通知は `tickets/pod-callback.md`
|
||||
- Pod ネットワークの GUI / TUI 可視化
|
||||
- spawner プロセス再起動後の `spawned_pods.json` からの復旧(現状は write-through のみ)
|
||||
- `ReadPodOutput` カーソルの永続化(インメモリのみ、再起動で 0 に戻る)
|
||||
- Pod の詳細ステータス(`running` / `idle`)を `Event::History` に含める拡張
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
# Review: pod-comm-tools
|
||||
|
||||
実装コミット前レビュー。`cargo build -p pod` clean、`cargo test -p pod --test pod_comm_tools_test` 8/8 pass。
|
||||
|
||||
## 総評
|
||||
|
||||
チケット要件の中核(4 ツールの wire 動作、`SpawnedPodRegistry` の共有、scope 回収、stale reclaim トリガー)は達成。テスト構成もモックソケットで実 `pod` バイナリ非依存で速い。ただし以下のうち修正必須項目を解消してから完了にしたい。
|
||||
|
||||
## 指摘と判断
|
||||
|
||||
### 修正必須
|
||||
|
||||
#### 1. `SendToPod` が RUNNING 状態を検知しない(設計合意違反)
|
||||
|
||||
**状況**: `connect_and_send` は `Method::Run` を書いて即切断し、応答 event を読まない。Controller は RUNNING 中の `Run` に対し `Event::Error { code: AlreadyRunning }` を返すが、tool 側はそれを見ないので LLM に「送信成功」と返る。
|
||||
|
||||
**設計合意**: pod-comm-tools 議論の結論は「A. SendToPod は `Method::Run` を使い、Pod が IDLE でなければエラーを返す」。
|
||||
|
||||
**判断**: 修正必要。書き込み後に short timeout で 1 event 読み、`Error { AlreadyRunning }` を検知したら `ToolError::ExecutionFailed` に変換する。正常時は `TurnStart` など先頭 event を見て「受け付けられた」ことを確認して戻る。
|
||||
|
||||
### チケット文言と実装の整合
|
||||
|
||||
#### 2. Pod status (`running / idle / stopped`) の取得手段がない
|
||||
|
||||
**状況**: チケットは `ReadPodOutput`/`ListPods` 出力に `running / idle / stopped` を含めることを求めているが、`Event::History` にはステータスが乗っておらず、実装は「接続可=alive / 接続不可=stopped」の 2 値のみ。
|
||||
|
||||
**判断**: 今回のスコープからは外す。`Greeting` または別 event に `PodStatus` を載せる改修は `Method::GetHistory` のレスポンス設計変更を伴うので、別チケット化する。本チケット文言を `alive / stopped` に揃えて実装と一致させる。
|
||||
|
||||
#### 3. `StopPod` は終了確認を待たない
|
||||
|
||||
**状況**: チケット本文は「`Method::Shutdown` 送信 → 終了確認受信 → 切断」だが、実装は fire-and-forget。scope の明示 release と `scope_lock` 上の stale reclaim で整合性は担保されているので実害なし。
|
||||
|
||||
**判断**: チケット文言を「`Method::Shutdown` 送信(応答は待たない)」に修正。
|
||||
|
||||
### 範囲外として明文化
|
||||
|
||||
#### 4. `spawned_pods.json` からの再起動復旧は未実装
|
||||
|
||||
**状況**: `spawned_pod_registry.rs` のモジュールコメントに「today only write-through is implemented」と明記されている。spawner プロセス再起動後、`ListPods` は空リストを返す。
|
||||
|
||||
**判断**: 今回のスコープ外。チケットの範囲外に「spawner 再起動時の `spawned_pods.json` からの復旧」を明記し、必要になったタイミングで別チケットを切る。
|
||||
|
||||
#### 5. `ReadPodOutput` cursor の非永続性
|
||||
|
||||
**状況**: `SpawnedPodRegistry::cursors` は `HashMap<String, usize>` でインメモリのみ。spawner 再起動後、カーソルは 0 にリセットされ、既読だった assistant text が再送される。モジュールコメントに「cursors intentionally do not persist」と明記されている。
|
||||
|
||||
**判断**: 現状のままで OK。設計判断としてレビューで合意し、チケットの「設計で決めること」の回答として本 review に残す。チケット側には残さない(gitで追える)。
|
||||
|
||||
### 軽微
|
||||
|
||||
#### 6. `extract_assistant_text` のメッセージ境界
|
||||
|
||||
**状況**: 複数の assistant message を `\n` で連結するのみ。メッセージ境界が曖昧になる。
|
||||
|
||||
**判断**: `\n\n` に変更して境界を明確にする。修正コスト小。
|
||||
|
||||
#### 7. blocking `flock` を async から呼んでいる
|
||||
|
||||
**状況**: `release_scope` / stale reclaim 経路で `LockFileGuard::open`(内部で `flock(2)`)を async fn から直接呼ぶ。通常は瞬時だが厳密には tokio runtime を一瞬止める。
|
||||
|
||||
**判断**: 既存コード全体が同じ慣習なので今回は踏襲。気になったら別タイミングで `spawn_blocking` 化を検討。本チケットでは対応しない。
|
||||
|
||||
#### 8. `SpawnedPodRegistry::new` が `Arc<Self>` を返す
|
||||
|
||||
**状況**: コンストラクタが smart pointer を返す API は珍しい。
|
||||
|
||||
**判断**: consumer が全員 `Arc` で持つ設計なので許容。リファクタは不要。
|
||||
|
||||
## 完了条件との対応
|
||||
|
||||
| 完了条件 | 状態 |
|
||||
|---|---|
|
||||
| SendToPod で spawned Pod にメッセージ送信・Pod が処理 | ✅(指摘 #1 の修正後) |
|
||||
| ReadPodOutput でカーソルベース差分取得 | ✅ |
|
||||
| StopPod で graceful 停止 + scope 返却 | ✅ |
|
||||
| ListPods で既知 Pod の状態一覧 + health check | ⚠️ `alive/stopped` のみ(指摘 #2) |
|
||||
| 接続不可 Pod は `stopped` 扱い + stale 回収トリガー | ✅ |
|
||||
| 各ツール正常系・異常系の単体テスト | ✅(8/8 pass) |
|
||||
|
||||
## 完了に向けた作業
|
||||
|
||||
1. 指摘 #1: `SendToPod` に応答確認を実装
|
||||
2. 指摘 #2, #3: チケット本文の文言修正(`running/idle/stopped` → `alive/stopped`、Shutdown 応答待ちの記述削除)
|
||||
3. 指摘 #4: チケットの「範囲外」に `spawned_pods.json` 復旧を追記
|
||||
4. 指摘 #6: `extract_assistant_text` の区切りを `\n\n` に
|
||||
Loading…
Reference in New Issue
Block a user