This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
# Movement 制御フローツールと park シグナル
|
||||
|
||||
エンジン内部リファレンス。「ツールを呼ぶと movement が**待機/終了状態に遷移**するが、その遷移先は**ピース毎の `rules` に書かなくてよい**」という仕組みのまとめ。BrowseWeb のログイン待ち・RequestTool の承認待ち・(提案中の)WaitSubTask が同じ骨格を共有する。今後この型を流用する時の下敷き。
|
||||
|
||||
## 要点
|
||||
|
||||
movement の遷移には **2 系統**ある。
|
||||
|
||||
| 系統 | 遷移先の決まり方 | LLM への提示 | 例 |
|
||||
|------|------------------|--------------|-----|
|
||||
| **rules ベース** | ピースの `rules[].next` を `buildTransitionTool` が enum 化 | `transition` ツールの選択肢として提示 | 別 movement への中間遷移 |
|
||||
| **sentinel `next`(park/terminal)** | ツールまたは engine が `MovementResult.next` に**特別な値**を直接セット | 専用ツール(`complete` 等)として提示。`rules` 不要 | 終了・各種待機 |
|
||||
|
||||
後者が今回の主題。**ツールが「作業をする」のではなく「movement を畳む制御シグナルを出す」**。`complete` がまさにこれで、`BrowseWeb`(ログイン待ち)・`RequestTool`(承認待ち)も同じ。`rules` に依存しないので、`rules: []` の単一 movement ピース(`chat` 等)でも一律に効く。
|
||||
|
||||
## 仕組みの流れ
|
||||
|
||||
```
|
||||
agent-loop.ts
|
||||
LLM が制御フローツールを呼ぶ
|
||||
└─ finishMovement({ next: '<SENTINEL>', resumeMovement?, waitReason? }) を返す
|
||||
│ MovementResult.next に sentinel を載せる
|
||||
▼
|
||||
piece-runner.ts mapMovementResult(result, ...)
|
||||
└─ next の値で分岐し PieceRunResult を返す
|
||||
├─ 終了系 → kind:'done' / status: completed|aborted|cancelled
|
||||
└─ 待機系 → kind:'done' / status: waiting_* + resumeMovement(+waitReason)
|
||||
▼
|
||||
worker.ts
|
||||
└─ waiting_* のジョブを停車。条件成立で resumeMovement から再開
|
||||
(waiting_subtasks=子全完了 / waiting_human=ユーザー回答・ログイン・承認)
|
||||
```
|
||||
|
||||
ポイントは、**待機系も「ジョブを停車してワーカーを解放」する**こと。ツール内で同期ブロックして待つのではない(後述の鉄則)。
|
||||
|
||||
## sentinel カタログ(`mapMovementResult` の分岐・origin/main 時点)
|
||||
|
||||
| `next` | 生成元 | 結果 status | resumeMovement | waitReason | 種別 |
|
||||
|--------|--------|-------------|----------------|-----------|------|
|
||||
| `COMPLETE` | `complete` ツール | `completed` | — | — | 終了 |
|
||||
| `ABORT`(`cancelled` 含む) | キャンセル経路 | `cancelled` | — | — | 終了 |
|
||||
| `ABORT` | `complete`/各種ガード(`text_only_limit`・`max_iterations` 等) | `aborted` | — | — | 終了 |
|
||||
| `ASK` | `complete({status:'needs_user_input'})` | `waiting_human`(上限超で `aborted`) | 現在の movement | — | 待機 |
|
||||
| `WAIT_SUBTASKS` | `transition`(rules 経由)/**WaitSubTask ツール(提案)** | `waiting_subtasks` | `default_next`(ツール版は現在の movement に変更予定) | — | 待機 |
|
||||
| `WAITING_HUMAN_BROWSER` | `BrowseWeb`(ログイン要求時) | `waiting_human` | 現在の movement | `browser_login` | 待機 |
|
||||
| `WAITING_HUMAN_TOOL_REQUEST` | `RequestTool` | `waiting_human` | 現在の movement | `tool_request` | 待機 |
|
||||
| `null` | 異常(ツール未決着) | `error` | — | — | 異常 |
|
||||
|
||||
> `WAIT_SUBTASKS` だけは現状 `rules[].next` にも書ける(rules ベース経由)。ツール版(WaitSubTask)を足すと、**同じ sentinel に「ルール不要の入口」**が増える。下流の `mapMovementResult` 分岐は共有。
|
||||
|
||||
## 新しい park ツールを足すレシピ
|
||||
|
||||
1. **ツール定義**を該当モジュール(例 `orchestration.ts`)の `TOOL_DEFS` に追加。
|
||||
2. **agent-loop で制御フローツールとして識別**し、`finishMovement({ next: '<新SENTINEL>', resumeMovement, waitReason })` を返す(`WAITING_HUMAN_BROWSER` の実装が雛形)。
|
||||
3. **`mapMovementResult` に分岐を追加**(piece-runner.ts)。終了なら `status: 'aborted'|'completed'`、待機なら `status: 'waiting_*'` + `resumeMovement`(+`waitReason`)。
|
||||
4. **worker の再開条件**を実装/再利用。既存の `waiting_human` / `waiting_subtasks` のどちらかに寄せられるなら新 status は不要。
|
||||
5. **型**(`MovementResult.next` のユニオン、`waitReason`)を更新。
|
||||
|
||||
既存の待機 status(`waiting_human` / `waiting_subtasks`)に相乗りできるなら、3〜4 は分岐追加だけで済むことが多い。
|
||||
|
||||
## 鉄則・gotcha
|
||||
|
||||
- **ツール内で同期ブロックして待たない。** 待機は必ず「停車=ワーカー解放」で表現する。in-tool で `await` し続けると親ワーカーを占有し、最悪ワーカー枯渇でデッドロックする(`WAIT_SUBTASKS` が遷移=停車である理由)。
|
||||
- **resume 先を意識する。** `default_next` が `COMPLETE` のピース(単一 movement)で再開させると終了に飛ぶ。多くの待機ツールは**現在の movement に再入**させて、再開後に結果を読んで `complete` させる。
|
||||
- **terminal と park を混同しない。** `COMPLETE`/`ABORT` はジョブを終わらせる(再開なし)。`WAITING_*`/`WAIT_SUBTASKS` は停車→再開。`resumeMovement` の有無が分かれ目。
|
||||
- **sentinel は `rules` の enum に出さない。** これらは engine-internal。`rules[].next` に書けるのは別 movement 名と `WAIT_SUBTASKS` のみ(`loadPiece`/lint が `COMPLETE`/`ABORT`/`ASK` を reject する)。
|
||||
|
||||
## 関連
|
||||
|
||||
- 設計: `docs/design/2026-06-26-subtask-wait-and-safety.html`(WaitSubTask ツール=この型の新規適用例)
|
||||
- 実装: `src/engine/agent-loop.ts`(`finishMovement` / 制御フローツール識別)、`src/engine/piece-runner.ts`(`mapMovementResult`)、`src/worker.ts`(待機ジョブの停車・再開)
|
||||
+11
-3
@@ -2,6 +2,8 @@
|
||||
|
||||
サブエージェントを同期的にインライン実行して、重い処理を委譲し本体のコンテキストを節約する。サブエージェントの中間ターンは親に見えないため、複雑な作業の最終結果だけを取得できる。
|
||||
|
||||
**タスク分解の既定手段**。research / general / brainstorming など調査・分析系のピースは、重いサブ調査を Delegate で **1 件ずつ直列に** こなす設計になっている。並列の別ジョブ(SpawnSubTask)はデフォルト無効で、本当に並列が必要なワークスペースだけが **設定 → ツール** タブで明示的に有効化する。ほとんどのタスクは Delegate で分解が完結するため、まず Delegate を検討する。
|
||||
|
||||
## 基本
|
||||
|
||||
```js
|
||||
@@ -27,12 +29,18 @@ Delegate({
|
||||
- 「特定キーワードで 30 件検索し, 記事要約→集約」→ 重い WebFetch も delegate 内で完結
|
||||
- 「複数 PDF を OCR → テキスト抽出 → 解析」→ 前処理を delegate, 後続は親が実行
|
||||
|
||||
### SpawnSubTask が向いているケース
|
||||
### SpawnSubTask が向いているケース(opt-in)
|
||||
|
||||
- **複数の独立したテーマ**(A, B, C に分解)→ 並列実行が必須
|
||||
> SpawnSubTask はデフォルト無効。使うにはワークスペースの **設定 → ツール** タブで有効化する(Bash などと同じセンシティブ扱いの opt-in ツール)。有効化していないワークスペースでは Delegate での直列分解だけになる。
|
||||
|
||||
並列の別ジョブが本当に効く、次のようなケースに限って有効化を検討する:
|
||||
|
||||
- **複数の独立したテーマ**(A, B, C に分解)で、壁時計時間の短縮が重要
|
||||
- **サブタスク間に依存がない**(A が完了してから B という制約がない)
|
||||
- **各サブの成果物がそれぞれ意味を持つ**(集約不要または集約が簡単)
|
||||
|
||||
GPU・実行枠を多く消費するため、逐次で足りる場合は Delegate を優先する。
|
||||
|
||||
### Delegate が向かないケース
|
||||
|
||||
- **対話が必要**(ASK ツールを呼ぶ)→ 子の ASK は親に bubbles up する
|
||||
@@ -77,7 +85,7 @@ Bash({ command: "cat logs/activity.log | tail -20" })
|
||||
|
||||
## 制限
|
||||
|
||||
- **直列実行**: Delegate × N 個を呼ぶとシリアルに実行される(並列不可)。高速化は SpawnSubTask で並列化
|
||||
- **直列実行**: Delegate × N 個を呼ぶとシリアルに実行される(並列不可)。並列が必要なら SpawnSubTask(要 opt-in 有効化)を使う。直列のぶん壁時計時間はやや長くなるが、GPU 負荷は軽く、各サブが綺麗なコンテキストで動くので品質は揃いやすい
|
||||
- **ネスト深さ**: 約 2 レベル(delegate 内からさらに delegate を呼ぶのは許可だが, 3 段階目以上は危険)
|
||||
- **完了待ちブロック**: 親は子が完了するまでブロックされるため、1 回の delegate は焦点を絞ること
|
||||
- **ASK 必須情報**: サブエージェントが ASK を呼んだら, 親に `[delegate 要追加情報] ...` と bubble up される。親が回答を `transition({lessons: "..." })` で与える
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
タスクを並列サブタスクに分解して実行する。各サブタスクは独立した worker(ジョブ)で動き、完了後に親タスクが結果を集約する。
|
||||
|
||||
> **デフォルト無効(opt-in)**。SpawnSubTask は Bash などと同じセンシティブ扱いのツールで、初期状態ではエージェントに提示されない。使うにはワークスペースの **設定 → ツール** タブで明示的に有効化する。有効化していない場合、SpawnSubTask は呼べず、分解は [`Delegate`](./delegate.md)(直列・インプロセス)で行う。
|
||||
>
|
||||
> タスク分解の既定手段は Delegate(直列)。research / general / brainstorming などのピースは Delegate でサブ調査を 1 件ずつこなす。SpawnSubTask は「壁時計時間の短縮のために独立テーマを本当に並列で走らせたい」ワークスペースだけが有効化する。
|
||||
|
||||
## 基本
|
||||
|
||||
```js
|
||||
@@ -16,11 +20,14 @@ SpawnSubTask({
|
||||
|
||||
## いつ使うか
|
||||
|
||||
まず Delegate(直列)で足りるかを検討する。SpawnSubTask は opt-in で有効化したうえで、**並列の別ジョブで壁時計時間を縮めたい**場合に限って使う。
|
||||
|
||||
### 並列分解が効果的なケース
|
||||
|
||||
- 2 つ以上の **独立したテーマ**(互いに参照しない)
|
||||
- 各テーマが軽くなく、調査・処理に時間がかかる
|
||||
- 分解後の各タスクが単独でも意味を持つ成果物になる
|
||||
- 壁時計時間の短縮が GPU・実行枠の追加消費に見合う
|
||||
|
||||
例:
|
||||
- 「3 つの製品比較レポート」→ 製品ごとに 3 サブタスク
|
||||
@@ -47,11 +54,66 @@ SpawnSubTask({
|
||||
- 省略時: 親と同じ classifier ロジックで自動選択
|
||||
- 明示する場合: `research`, `general`, `office-process` 等の piece 名を指定
|
||||
|
||||
## WaitSubTask(完了待ち)
|
||||
|
||||
`SpawnSubTask` でサブタスクを起動したあとは、**`WaitSubTask`(引数なし)を 1 回呼んで全サブタスクの完了を待つ**。
|
||||
|
||||
```js
|
||||
SpawnSubTask({ title: "A の調査", instruction: "..." })
|
||||
SpawnSubTask({ title: "B の調査", instruction: "..." })
|
||||
SpawnSubTask({ title: "C の調査", instruction: "..." })
|
||||
WaitSubTask() // ここで全部の完了を待つ
|
||||
// 再開後、subtasks/*/result.md を Read して集約 → complete
|
||||
```
|
||||
|
||||
- `WaitSubTask` は **同期的にブロックしない**。呼ぶとジョブはいったん停止(park)して worker を解放し、全サブタスクが終わると **同じ movement のまま再開** する
|
||||
- 再開時、各サブタスクの結果は `subtasks/{index}/result.md` に書き出されている。Read で読んで集約レポートを作る
|
||||
- 起動した分の成果物は `subtasks/{index}/output/` 以下にも残る
|
||||
|
||||
### ワークフロー
|
||||
|
||||
1. `SpawnSubTask` を必要な数だけ呼ぶ(並列に起動される)
|
||||
2. `WaitSubTask()` を 1 回呼ぶ
|
||||
3. 再開後、`subtasks/*/result.md` を読んで集約する
|
||||
4. `complete` で終了する
|
||||
|
||||
### auto-park(取りこぼし防止)
|
||||
|
||||
サブタスクがまだ走っている最中に `complete`(success)を呼んでも、エンジンが**偽の完了を返さず、自動で park して完了を待つ**。`WaitSubTask` を呼び忘れても結果を取りこぼさない安全網。とはいえ意図を明示するため、原則 `WaitSubTask` を明示的に呼ぶこと。
|
||||
|
||||
### orphan の自動キャンセル
|
||||
|
||||
親ジョブが**失敗・キャンセル・リトライ**したとき、まだ走っているサブタスクは**自動でキャンセル**される。親が消えたのに子だけ GPU を使い続ける「ゾンビサブタスク」は発生しない。
|
||||
|
||||
ただし **ASK(ユーザー回答待ち)で停止した場合は子を残す**。親があとで再開して結果を使うため。
|
||||
|
||||
### delegate との違い
|
||||
|
||||
| | delegate | SpawnSubTask + WaitSubTask |
|
||||
|---|---|---|
|
||||
| 既定 | **デフォルト有効**(分解の既定手段) | **デフォルト無効**(要 opt-in 有効化) |
|
||||
| 実行 | 直列・インプロセス | 並列・別ジョブ |
|
||||
| 待機 | 自動(1 ツール呼び出しで完結) | `WaitSubTask` で待つ |
|
||||
| 負荷 | GPU・実行枠が軽い | 並列ぶん多く消費する |
|
||||
| 向く用途 | 逐次の分解・重い委譲全般 | 独立テーマを並列で短時間化したいとき |
|
||||
|
||||
## 起動の間隔(spawn_stagger_ms)
|
||||
|
||||
短時間に大量の `SpawnSubTask` を呼ぶと、その一団が GPU スロットの優先順位を一気に奪ってしまう。これを避けるため、`SpawnSubTask` のキュー投入の間に既定で 1 秒の間隔を入れる。
|
||||
|
||||
```yaml
|
||||
subtasks:
|
||||
spawn_stagger_ms: 1000 # SpawnSubTask 投入間の間隔(ミリ秒、デフォルト 1000、0 で無効)
|
||||
```
|
||||
|
||||
- `0` にすると間隔を入れず即時に投入する
|
||||
- エージェントから見た呼び出し方は変わらない(透過的に間隔が入るだけ)
|
||||
|
||||
## 結果の参照
|
||||
|
||||
サブタスク完了後、親タスクは:
|
||||
- `subtasks/{index}/result.md` にサブタスクの要約結果がある(Read で読む)
|
||||
- `subtasks/{index}/output/` 以下にサブタスクの成果物がある
|
||||
- Read で参照して集約レポートを作成する
|
||||
|
||||
## 制限
|
||||
|
||||
|
||||
+30
-1
@@ -4,7 +4,8 @@ twitter-cli を内部で呼び出して X (旧 Twitter) のデータを取得す
|
||||
|
||||
## 認証設定(必須)
|
||||
|
||||
twitter-cli を動かすには Cookie 認証が必要。Settings UI の "Tools" セクションで設定:
|
||||
X ツールは `tools.x_cli_command` で指定した外部 CLI を呼び出す。どちらの CLI でも
|
||||
Cookie 認証が必要。Settings UI の "Tools" セクションで設定:
|
||||
- **X Auth Token**: ブラウザの `auth_token` cookie の値
|
||||
- **X ct0**: ブラウザの `ct0` cookie の値
|
||||
|
||||
@@ -14,6 +15,34 @@ twitter-cli を動かすには Cookie 認証が必要。Settings UI の "Tools"
|
||||
|
||||
設定が無いと「認証エラー」で失敗する。
|
||||
|
||||
## バックエンド CLI(x-adapter / twitter-cli)
|
||||
|
||||
2026 年に X.com が Web クライアントを新バンドル(x-web / `sign.o*.js`)へ移行し、
|
||||
従来の twitter-cli が依存する `x_client_transaction` の transaction-id 生成が壊れた
|
||||
(`Failed to init ClientTransaction` → 全リクエストが HTTP 404 → `exited with code 1`)。
|
||||
|
||||
復旧のため、新バンドルに追従している **twscrape**(transaction-id 生成 `XClIdGen` +
|
||||
検索/ユーザー投稿/詳細)と **twikit**(ホームタイムラインの GraphQL endpoint 定義)を
|
||||
使う twitter-cli 互換アダプタ `x-adapter` を導入した。x.ts は無改修で、`x_cli_command`
|
||||
を切り替えるだけ。
|
||||
|
||||
セットアップ:
|
||||
```bash
|
||||
./scripts/install-x-adapter.sh # 隔離 venv に twscrape/twikit を入れ ~/.local/bin/x-adapter を作る
|
||||
# config.yaml:
|
||||
# tools:
|
||||
# x_cli_command: [x-adapter]
|
||||
```
|
||||
|
||||
X が再び取得を壊した場合(おおむね 2〜4 週ごと)の修復レバー:
|
||||
```bash
|
||||
./scripts/install-x-adapter.sh --upgrade # twscrape / twikit を最新へ
|
||||
```
|
||||
|
||||
`x-adapter` のサブコマンドは twitter-cli と同じ(`search` / `user-posts` / `tweet` /
|
||||
`feed`)で、同じ YAML を stdout に吐く。実装は `scripts/x-adapter/x_adapter.py`、
|
||||
pure マッピング関数の単体テストは `scripts/x-adapter/test_x_adapter.py`。
|
||||
|
||||
## XSearch — 投稿検索
|
||||
|
||||
```js
|
||||
|
||||
Reference in New Issue
Block a user