376 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TAKT 実行エンジン詳細
## 通常 Movement の実行
通常の movement`parallel` フィールドを持たない movementは、Task tool で1つのエージェントを起動する。
### Task tool の呼び出し
```
Task tool:
subagent_type: "general-purpose"
description: "{movement名} - {ピース名}" 3-5語
prompt: <後述のプロンプト構築で組み立てた内容>
mode: <permission_mode から決定>
```
### permission_mode の決定
movement の `edit` フィールドと `permission_mode` フィールドから決定する:
| edit | permission_mode | Task tool の mode |
|------|----------------|-------------------|
| true | 未指定 | "bypassPermissions" |
| true | "edit" | "bypassPermissions" |
| true | "full" | "bypassPermissions" |
| false | 未指定 | "default" |
| false | "readonly" | "default" |
`edit: false` の movement は読み取り専用。`edit: true` の movement はファイル編集が可能。
## Parallel Movement の実行
`parallel` フィールドを持つ movement は、複数のサブステップを並列実行する。
### 実行手順
1. parallel 配列の各サブステップに対して Task tool を起動する
2. **全ての Task tool を1つのメッセージで並列に呼び出す**(依存関係がないため)
3. 全エージェントの完了を待つ
4. 各サブステップの出力を収集する
5. 各サブステップの出力に対して、そのサブステップの `rules` で条件マッチを判定する
6. 親 movement の `rules` で aggregate 評価all()/any())を行う
### サブステップの条件マッチ判定
各サブステップの出力テキストに対して、そのサブステップの `rules` の中からマッチする condition を特定する。
判定方法(通常 movement の Rule 評価と同じ優先順位):
1. `[STEP:N]` タグがあればインデックスで照合(最後のタグを採用)
2. タグがなければ、出力全体を読んでどの condition に最も近いかを判断する
マッチした condition 文字列を記録する(次の aggregate 評価で使う)。
## プロンプト構築
各 movement のエージェント起動時、以下を結合してプロンプトを組み立てる。
### 構成要素(上から順に結合)
```
1. エージェントプロンプトagent: で参照される .md の全内容)
2. ---(区切り線)
3. 実行コンテキスト情報
4. instruction_template の内容(テンプレート変数を展開済み)
5. ユーザーのタスク({task} が template に含まれない場合、末尾に自動追加)
6. 前の movement の出力pass_previous_response: true の場合、自動追加)
7. レポート出力指示report フィールドがある場合、自動追加)
8. ステータスタグ出力指示rules がある場合、自動追加)
```
### 実行コンテキスト情報
```
## 実行コンテキスト
- ワーキングディレクトリ: {cwd}
- ピース: {piece_name}
- Movement: {movement_name}
- イテレーション: {iteration} / {max_iterations}
- Movement イテレーション: {movement_iteration} 回目
```
### テンプレート変数の展開
`instruction_template` 内の以下のプレースホルダーを置換する:
| 変数 | 値 |
|-----|-----|
| `{task}` | ユーザーが入力したタスク内容 |
| `{previous_response}` | 前の movement のエージェント出力 |
| `{iteration}` | ピース全体のイテレーション数1始まり |
| `{max_iterations}` | ピースの max_iterations 値 |
| `{movement_iteration}` | この movement が実行された回数1始まり |
| `{report_dir}` | レポートディレクトリパス |
| `{report:ファイル名}` | 指定レポートファイルの内容Read で取得) |
### {report:ファイル名} の処理
`instruction_template` 内に `{report:04-ai-review.md}` のような記法がある場合:
1. レポートディレクトリ内に対応するレポートファイルがあれば Read で読む
2. 読み込んだ内容をプレースホルダーに展開する
3. ファイルが存在しない場合は「(レポート未作成)」に置換する
### agent フィールドがない場合
`agent:` が指定されていない movement の場合、エージェントプロンプト部分を省略し、`instruction_template` の内容のみでプロンプトを構成する。
## レポート出力指示の自動注入
movement に `report` フィールドがある場合、プロンプト末尾にレポート出力指示を自動追加する。これにより、takt 本体の Phase 2レポート出力フェーズを1回の呼び出しに統合する。
### 形式1: name + format
```yaml
report:
name: 01-plan.md
format: |
# タスク計画
## 元の要求
...
```
→ プロンプトに追加する指示:
```
---
## レポート出力(必須)
作業完了後、以下のフォーマットに従ってレポートを出力してください。
レポートは ```markdown ブロックで囲んで出力してください。
ファイル名: 01-plan.md
フォーマット:
# タスク計画
## 元の要求
...
```
### 形式2: 配列(複数レポート)
```yaml
report:
- Summary: summary.md
- Scope: 01-scope.md
```
→ プロンプトに追加する指示:
```
---
## レポート出力(必須)
作業完了後、以下の各レポートを出力してください。
各レポートは見出し付きの ```markdown ブロックで囲んで出力してください。
1. Summary → ファイル名: summary.md
2. Scope → ファイル名: 01-scope.md
```
### レポートの抽出と保存
エージェントの出力からレポート内容を抽出し、Write tool でレポートディレクトリに保存する。
**レポートディレクトリ**: `.takt/reports/{timestamp}-{slug}/` に作成するtakt 本体と同じ構造)。
- `{timestamp}`: `YYYYMMDD-HHmmss` 形式
- `{slug}`: タスク内容の先頭30文字をスラグ化
抽出方法:
- 出力内の ```markdown ブロックからレポート内容を取得する
- ファイル名の手がかり(見出しやコメント)から対応するレポートを特定する
- 特定できない場合は出力全体をレポートとして保存する
## ステータスタグ出力指示の自動注入
movement に `rules` がある場合、プロンプト末尾にステータスタグ出力指示を自動追加する。これにより、takt 本体の Phase 3ステータス判定フェーズを1回の呼び出しに統合する。
### 注入する指示
```
---
## ステータス出力(必須)
全ての作業とレポート出力が完了した後、最後に以下のいずれかのタグを出力してください。
あなたの作業結果に最も合致するものを1つだけ選んでください。
[STEP:0] = {rules[0].condition}
[STEP:1] = {rules[1].condition}
[STEP:2] = {rules[2].condition}
...
```
### ai() 条件の場合
condition が `ai("条件テキスト")` 形式の場合でも、同じくタグ出力指示に含める:
```
[STEP:0] = 条件テキスト
[STEP:1] = 別の条件テキスト
```
これにより、エージェントが自ら判断して適切なタグを出力する。ai() の括弧は除去して condition テキストのみを表示する。
### サブステップの場合
parallel のサブステップにも同様にタグ出力指示を注入する。サブステップの rules からタグリストを生成する。
## Rule 評価
movement 実行後、エージェントの出力テキストからどの rule にマッチするかを判定する。
### 通常 Movement の Rule 評価
判定優先順位(最初にマッチしたものを採用):
#### 1. タグベース検出(優先)
エージェント出力に `[STEP:N]` タグN は 0始まりのインデックスが含まれる場合、そのインデックスに対応する rule を選択する。複数のタグがある場合は **最後のタグ** を採用する。
例: rules が `["タスク完了", "進行できない"]` で出力に `[STEP:0]` → "タスク完了" を選択
#### 2. フォールバックAI 判定)
タグが出力に含まれない場合、出力テキスト全体を読み、全ての condition と比較して最もマッチするものを選択する。
**出力テキストの判定例**:
- rules: `["実装完了", "判断できない"]`
- 出力: 「全てのファイルを修正し、テストもパスしました。」
- → "実装完了" にマッチ
### Parallel Movement の Rule 評価Aggregate
親 movement の rules に `all()` / `any()` の aggregate 条件を使用する。
#### all() の評価
```yaml
- condition: all("approved")
next: COMPLETE
```
**引数が1つ**: 全サブステップのマッチ条件が "approved" であれば true。
```yaml
- condition: all("AI特有の問題なし", "すべて問題なし")
next: COMPLETE
```
**引数が複数(位置対応)**: サブステップ1が "AI特有の問題なし" にマッチ AND サブステップ2が "すべて問題なし" にマッチ であれば true。
#### any() の評価
```yaml
- condition: any("needs_fix")
next: fix
```
いずれかのサブステップのマッチ条件が "needs_fix" であれば true。
```yaml
- condition: any("AI特有の問題あり")
next: ai_fix
```
**引数が1つ**: いずれかのサブステップが "AI特有の問題あり" にマッチすれば true。
#### Aggregate 評価の順序
親 rules を上から順に評価し、最初にマッチした rule を採用する。
### Rule にマッチしない場合
全ての rule を評価してもマッチしない場合は ABORT する。エラーメッセージとともに、マッチしなかった出力の要約をユーザーに報告する。
## ループ検出
### 基本ルール
- 同じ movement が連続3回以上実行されたら警告を表示する
- `max_iterations` に到達したら強制終了ABORTする
### カウンター管理
以下のカウンターを管理する:
| カウンター | 説明 | リセットタイミング |
|-----------|------|-------------------|
| `iteration` | ピース全体の movement 実行回数 | リセットしない |
| `movement_iteration[name]` | 各 movement の実行回数 | リセットしない |
| `consecutive_count[name]` | 同じ movement の連続実行回数 | 別の movement に遷移したとき |
## Loop Monitors
ピースに `loop_monitors` が定義されている場合、特定の movement サイクルを監視する。
### 動作
```yaml
loop_monitors:
- cycle: [ai_review, ai_fix]
threshold: 3
judge:
agent: ../agents/default/supervisor.md
instruction_template: |
サイクルが {cycle_count} 回繰り返されました...
rules:
- condition: 健全
next: ai_review
- condition: 非生産的
next: reviewers
```
### 検出ロジック
1. movement 遷移履歴を記録する(例: `[plan, implement, ai_review, ai_fix, ai_review, ai_fix, ...]`
2. 各 loop_monitor の `cycle` パターン(例: `[ai_review, ai_fix]`)が履歴の末尾に `threshold` 回以上連続で出現するかチェックする
3. 閾値に達した場合:
a. judge の `agent` を Read で読み込む
b. `instruction_template``{cycle_count}` を実際のサイクル回数に置換する
c. Task tool で judge エージェントを起動する
d. judge の出力を judge の `rules` で評価する
e. マッチした rule の `next` に遷移する(通常のルール評価をオーバーライドする)
## レポート管理
### レポートディレクトリの作成
ピース実行開始時にレポートディレクトリを作成する:
```
.takt/reports/{YYYYMMDD-HHmmss}-{slug}/
```
このパスを `{report_dir}` 変数として全 movement から参照可能にする。
### レポートの保存
エージェント出力からレポート内容を抽出し、Write tool でレポートディレクトリに保存する。
抽出手順:
1. 出力内の ```markdown ブロックを検索する
2. レポートのファイル名やセクション見出しから対応するレポートを特定する
3. Write tool で `{report_dir}/{ファイル名}` に保存する
### レポートの参照
後続の movement の `instruction_template` 内で `{report:ファイル名}` として参照すると、engine がそのレポートファイルを Read して内容をプレースホルダーに展開する。
## 状態遷移の全体像
```
[開始]
レポートディレクトリ作成
initial_movement を取得
┌─→ movement を実行
│ ├── 通常: Task tool (1エージェント)
│ │ prompt = agent.md + context + instruction + task
│ │ + previous_response + レポート指示 + タグ指示
│ └── parallel: Task tool (複数エージェント並列)
│ 各サブステップも同様のプロンプト構築
│ ↓
│ 出力からレポート抽出 → Write で保存
│ ↓
│ Loop Monitor チェック(該当サイクルがあれば judge 介入)
│ ↓
│ Rule 評価
│ ├── タグ検出 [STEP:N] → rule 選択
│ └── タグなし → AI フォールバック判定
│ ├── parallel: サブステップ条件 → aggregate(all/any)
│ ↓
│ next を決定
│ ├── COMPLETE → [成功終了] ユーザーに結果報告
│ ├── ABORT → [失敗終了] ユーザーにエラー報告
│ └── movement名 → ループ検出チェック → 次の movement
│ ↓
└──────────────────────────────────────────────┘
```