14 KiB
Raw Blame History

TAKT 実行エンジン詳細

通常 Movement の実行

通常の movementparallel フィールドを持たない 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

report:
  name: 01-plan.md
  format: |
    # タスク計画
    ## 元の要求
    ...

→ プロンプトに追加する指示:

---
## レポート出力(必須)
作業完了後、以下のフォーマットに従ってレポートを出力してください。
レポートは ```markdown ブロックで囲んで出力してください。

ファイル名: 01-plan.md
フォーマット:
# タスク計画
## 元の要求
...

形式2: 配列(複数レポート)

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() の評価

- condition: all("approved")
  next: COMPLETE

引数が1つ: 全サブステップのマッチ条件が "approved" であれば true。

- condition: all("AI特有の問題なし", "すべて問題なし")
  next: COMPLETE

引数が複数(位置対応): サブステップ1が "AI特有の問題なし" にマッチ AND サブステップ2が "すべて問題なし" にマッチ であれば true。

any() の評価

- condition: any("needs_fix")
  next: fix

いずれかのサブステップのマッチ条件が "needs_fix" であれば true。

- 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 サイクルを監視する。

動作

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
│                                              ↓
└──────────────────────────────────────────────┘