takt/docs/data-flow.md
Takashi Morikubo 50935a1244
Remove worktree prompt from execute action (#414)
* fix: remove execute worktree prompt and deprecate create-worktree option

* test(e2e): align specs with removed --create-worktree

* fix: remove execute worktree leftovers and align docs/tests

---------

Co-authored-by: Takashi Morikubo <azurite0107@gmail.com>
2026-03-02 16:12:18 +09:00

47 KiB
Raw Blame History

TAKTデータフロー解析

このドキュメントでは、TAKTにおけるデータフロー、特にインタラクティブモードからピース実行に至るまでのデータの流れを説明します。

目次

  1. 概要
  2. 全体フロー図
  3. 各レイヤーの詳細
  4. データフローの段階
  5. 重要な変換ポイント

概要

TAKTのデータフローは以下の7つの主要なレイヤーで構成されています:

  1. CLI Layer - ユーザー入力の受付
  2. Interactive Layer - タスクの対話的な明確化
  3. Execution Orchestration Layer - ピース選択と実行開始
  4. Piece Execution Layer - セッション管理とイベント処理
  5. Engine Layer - ステートマシンによるステップ実行
  6. Instruction Building Layer - プロンプト生成
  7. Provider Layer - AIプロバイダーとの通信

全体フロー図

┌─────────────────────────────────────────────────────────────────┐
│ 1. CLI Layer (src/app/cli/index.ts)                             │
│   ユーザー入力 → 引数パース → コマンド振り分け                       │
└────────────────────────────┬────────────────────────────────────┘
                             │
                ┌────────────┴──────────────┐
                │                           │
     Direct Task Input            Short Input / No Args
                │                           │
                │                           ▼
                │              ┌─────────────────────────────────┐
                │              │ 2. Interactive Layer            │
                │              │    (interactive.ts)             │
                │              │                                 │
                │              │  ┌─────────────────────┐        │
                │              │  │ User Conversation   │        │
                │              │  │  - Clarification    │        │
                │              │  │  - Codebase Search  │        │
                │              │  │  - AI Response      │        │
                │              │  └──────┬──────────────┘        │
                │              │         │                        │
                │              │         ▼                        │
                │              │  User confirms with /go          │
                │              │         │                        │
                │              │         ▼                        │
                │              │  buildTaskFromHistory()          │
                │              │  (会話履歴 → タスク文字列)         │
                │              └─────────┬───────────────────────┘
                │                        │
                └────────────────────────┘
                             │
                             │ task: string
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│ 3. Execution Orchestration Layer                                │
│    (selectAndExecute.ts)                                        │
│                                                                 │
│  ┌──────────────────────┐                                      │
│  │ determinePiece()  │ ← piece選択 (interactive/override) │
│  └─────────┬────────────┘                                      │
│            │ pieceIdentifier: string                        │
│            ▼                                                    │
│  ┌──────────────────────────────────┐                         │
│  │ executeTask()                    │                         │
│  │  - task: string                  │                         │
│  │  - cwd: string (実行ディレクトリ)   │                         │
│  │  - pieceIdentifier: string    │                         │
│  │  - projectCwd: string (.takt/在処) │                         │
│  └─────────┬────────────────────────┘                         │
└────────────┼────────────────────────────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────────────────────────────┐
│ 4. Piece Execution Layer                                     │
│    (pieceExecution.ts, taskExecution.ts)                     │
│                                                                 │
│  ┌────────────────────────────────┐                            │
│  │ loadPieceByIdentifier()     │                            │
│  │  → PieceConfig              │                            │
│  └────────┬───────────────────────┘                            │
│           │                                                     │
│           ▼                                                     │
│  ┌────────────────────────────────┐                            │
│  │ Session Management             │                            │
│  │  - loadAgentSessions()         │ ← projectCwd or cwd       │
│  │  - generateSessionId()         │                            │
│  │  - createSessionLog()          │                            │
│  │  - initNdjsonLog()             │                            │
│  └────────┬───────────────────────┘                            │
│           │                                                     │
│           ▼                                                     │
│  ┌────────────────────────────────┐                            │
│  │ PieceEngine initialization  │                            │
│  │                                │                            │
│  │  new PieceEngine(           │                            │
│  │    config: PieceConfig,     │                            │
│  │    cwd: string,                │                            │
│  │    task: string,               │                            │
│  │    options: {                  │                            │
│  │      onStream,                 │ ← StreamDisplay handler   │
│  │      initialSessions,          │ ← 保存済みセッションID      │
│  │      onSessionUpdate,          │ ← セッション更新callback    │
│  │      projectCwd,               │                            │
│  │      language,                 │                            │
│  │      provider,                 │                            │
│  │      model                     │                            │
│  │    }                           │                            │
│  │  )                             │                            │
│  └────────┬───────────────────────┘                            │
│           │                                                     │
│           ▼                                                     │
│  ┌────────────────────────────────┐                            │
│  │ Event Subscription             │                            │
│  │  - step:start                  │                            │
│  │  - step:complete               │                            │
│  │  - step:report                 │                            │
│  │  - piece:complete           │                            │
│  │  - piece:abort              │                            │
│  └────────┬───────────────────────┘                            │
│           │                                                     │
│           ▼                                                     │
│  ┌────────────────────────────────┐                            │
│  │ engine.run()                   │                            │
│  └────────┬───────────────────────┘                            │
└───────────┼─────────────────────────────────────────────────────┘
            │
            ▼
┌─────────────────────────────────────────────────────────────────┐
│ 5. Engine Layer (PieceEngine.ts)                             │
│                                                                 │
│  ┌────────────────────────────────────────┐                    │
│  │ State Machine Loop                     │                    │
│  │                                        │                    │
│  │  while (state.status === 'running') {  │                    │
│  │    ┌────────────────────────────────┐ │                    │
│  │    │ 1. Iteration & Loop Check      │ │                    │
│  │    └────────────┬───────────────────┘ │                    │
│  │                 │                      │                    │
│  │                 ▼                      │                    │
│  │    ┌────────────────────────────────┐ │                    │
│  │    │ 2. Get Current Step            │ │                    │
│  │    │    step = getStep(             │ │                    │
│  │    │      state.currentStep         │ │                    │
│  │    │    )                           │ │                    │
│  │    └────────────┬───────────────────┘ │                    │
│  │                 │                      │                    │
│  │                 ▼                      │                    │
│  │    ┌────────────────────────────────┐ │                    │
│  │    │ 3. Build Instruction           │ │ ← InstructionBuilder
│  │    │    (if not parallel)           │ │                    │
│  │    └────────────┬───────────────────┘ │                    │
│  │                 │                      │                    │
│  │                 ▼                      │                    │
│  │    ┌────────────────────────────────┐ │                    │
│  │    │ 4. Emit step:start             │ │                    │
│  │    └────────────┬───────────────────┘ │                    │
│  │                 │                      │                    │
│  │                 ▼                      │                    │
│  │    ┌────────────────────────────────┐ │                    │
│  │    │ 5. runStep()                   │ │                    │
│  │    │    ├─ Normal: StepExecutor     │ │ ← 3-phase execution
│  │    │    └─ Parallel: ParallelRunner │ │                    │
│  │    └────────────┬───────────────────┘ │                    │
│  │                 │                      │                    │
│  │                 │ { response, instruction }                │
│  │                 ▼                      │                    │
│  │    ┌────────────────────────────────┐ │                    │
│  │    │ 6. Emit step:complete          │ │                    │
│  │    └────────────┬───────────────────┘ │                    │
│  │                 │                      │                    │
│  │                 ▼                      │                    │
│  │    ┌────────────────────────────────┐ │                    │
│  │    │ 7. Handle Blocked              │ │                    │
│  │    │    (if status === 'blocked')   │ │                    │
│  │    └────────────┬───────────────────┘ │                    │
│  │                 │                      │                    │
│  │                 ▼                      │                    │
│  │    ┌────────────────────────────────┐ │                    │
│  │    │ 8. Rule Evaluation             │ │ ← RuleEvaluator   │
│  │    │    resolveNextStep()           │ │                    │
│  │    └────────────┬───────────────────┘ │                    │
│  │                 │                      │                    │
│  │                 │ nextStep: string     │                    │
│  │                 ▼                      │                    │
│  │    ┌────────────────────────────────┐ │                    │
│  │    │ 9. Transition                  │ │                    │
│  │    │    - COMPLETE → break          │ │                    │
│  │    │    - ABORT → break             │ │                    │
│  │    │    - other → update state      │ │                    │
│  │    └────────────────────────────────┘ │                    │
│  │  }                                     │                    │
│  └────────────────────────────────────────┘                    │
└─────────────────────────────────────────────────────────────────┘
            │
            ▼ (from runStep)
┌─────────────────────────────────────────────────────────────────┐
│ 6. Instruction Building & Step Execution Layer                  │
│                                                                 │
│  ┌────────────────────────────────────────────────────────────┐│
│  │ StepExecutor.runNormalStep()                               ││
│  │                                                            ││
│  │  ┌──────────────────────────────────────────────────────┐ ││
│  │  │ Phase 1: Main Execution                              │ ││
│  │  │                                                      │ ││
│  │  │  InstructionBuilder.build()                         │ ││
│  │  │    ├─ Execution Context (cwd, permission)           │ ││
│  │  │    ├─ Piece Context (iteration, step, report)    │ ││
│  │  │    ├─ User Request ({task})                         │ ││
│  │  │    ├─ Previous Response ({previous_response})       │ ││
│  │  │    ├─ Additional User Inputs ({user_inputs})        │ ││
│  │  │    ├─ Instructions (instruction_template)           │ ││
│  │  │    └─ Status Output Rules (tag-based)               │ ││
│  │  │                                                      │ ││
│  │  │  → instruction: string                              │ ││
│  │  │                                                      │ ││
│  │  │  runAgent(agent, instruction, options)              │ ││
│  │  │    → response: AgentResponse                        │ ││
│  │  └──────────────────────┬───────────────────────────────┘ ││
│  │                         │                                  ││
│  │                         ▼                                  ││
│  │  ┌──────────────────────────────────────────────────────┐ ││
│  │  │ Phase 2: Report Output (if step.report defined)     │ ││
│  │  │                                                      │ ││
│  │  │  runReportPhase()                                   │ ││
│  │  │    - Resume session                                 │ ││
│  │  │    - Write-only tools                               │ ││
│  │  │    - ReportInstructionBuilder                       │ ││
│  │  └──────────────────────┬───────────────────────────────┘ ││
│  │                         │                                  ││
│  │                         ▼                                  ││
│  │  ┌──────────────────────────────────────────────────────┐ ││
│  │  │ Phase 3: Status Judgment (if tag-based rules)       │ ││
│  │  │                                                      │ ││
│  │  │  runStatusJudgmentPhase()                           │ ││
│  │  │    - Resume session                                 │ ││
│  │  │    - No tools (judgment only)                       │ ││
│  │  │    - StatusJudgmentBuilder                          │ ││
│  │  │    → tagContent: string                             │ ││
│  │  └──────────────────────┬───────────────────────────────┘ ││
│  │                         │                                  ││
│  │                         ▼                                  ││
│  │  ┌──────────────────────────────────────────────────────┐ ││
│  │  │ Rule Evaluation                                      │ ││
│  │  │                                                      │ ││
│  │  │  detectMatchedRule(step, content, tagContent)       │ ││
│  │  │    1. Aggregate (all()/any())                       │ ││
│  │  │    2. Phase 3 tag ([STEP:N])                        │ ││
│  │  │    3. Phase 1 tag (fallback)                        │ ││
│  │  │    4. AI judge (ai("..."))                          │ ││
│  │  │    5. AI judge fallback (all conditions)            │ ││
│  │  │    → { index, method }                              │ ││
│  │  └──────────────────────┬───────────────────────────────┘ ││
│  │                         │                                  ││
│  │                         ▼                                  ││
│  │  response with matchedRuleIndex & matchedRuleMethod        ││
│  └────────────────────────────────────────────────────────────┘│
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│ 7. Provider Layer (agents/runner.ts → providers/)               │
│                                                                 │
│  ┌────────────────────────────────────────┐                    │
│  │ runAgent()                             │                    │
│  │  - Resolve agent spec                  │                    │
│  │  - Get provider                        │                    │
│  │  - Call provider.call()                │                    │
│  └────────────┬───────────────────────────┘                    │
│               │                                                 │
│               ▼                                                 │
│  ┌────────────────────────────────────────┐                    │
│  │ Provider.call()                        │                    │
│  │  (Claude / Codex / OpenCode / etc.)    │                    │
│  │                                        │                    │
│  │  - Build system prompt                 │                    │
│  │  - Call SDK (provider-specific)        │                    │
│  │  - Stream handling (onStream callback) │                    │
│  │  - Error propagation                   │                    │
│  │                                        │                    │
│  │  → { status, content, sessionId, ... } │                    │
│  └────────────────────────────────────────┘                    │
└─────────────────────────────────────────────────────────────────┘

各レイヤーの詳細

1. CLI Layer (src/app/cli/index.ts)

役割: ユーザー入力の受付とコマンド振り分け

主要な処理:

  • コマンドライン引数のパース
  • 入力タイプの判定:
    • isDirectTask(): 複数単語またはissue参照 → 直接実行
    • 短い単語または引数なし → インタラクティブモード
  • グローバル設定の初期化 (initGlobalDirs, initProjectDirs)
  • パイプラインモード vs 通常モードの判定

データ入力:

  • CLI引数: task, --piece, --issue, など

データ出力:

  • task: string (タスク記述)
  • piece: string | undefined (ピース名またはパス)
  • createWorktree: boolean | undefined
  • その他オプション

2. Interactive Layer (src/features/interactive/interactive.ts)

役割: タスクの対話的な明確化

主要な処理:

  1. 会話ループ:

    • readLine(): ユーザー入力を1行ずつ読み込み
    • callAI(): AIプロバイダーを呼び出し
    • 履歴管理: ConversationMessage[]
  2. セッション管理:

    • loadAgentSessions(): 過去のセッションを復元
    • updateAgentSession(): セッションIDを更新・保存
  3. スラッシュコマンド:

    • /go: タスク確定、実行へ進む
    • /cancel: キャンセル
    • Ctrl+D: EOF、キャンセル
  4. タスク組み立て:

    • buildTaskFromHistory(): 会話履歴を結合してタスク文字列を生成

データ入力:

  • initialInput?: string (CLI引数から)
  • ユーザーの対話入力

データ出力:

  • InteractiveModeResult:
    • action: InteractiveModeAction ('execute' | 'save_task' | 'create_issue' | 'cancel')
    • task: string (会話履歴全体を結合した文字列)

3. Execution Orchestration Layer (src/features/tasks/execute/selectAndExecute.ts)

役割: ピース選択と実行オーケストレーション

主要な処理:

  1. ピース決定 (determinePiece()):

    • オーバーライド指定がある場合:
      • パス形式 → そのまま使用
      • 名前形式 → バリデーション
    • オーバーライドなし → インタラクティブ選択 (selectPiece())
  2. タスク実行開始 (selectAndExecuteTask()):

    • executeTask() を呼び出し
    • 成功/失敗を tasks.yaml に記録(skipTaskList 設定時を除く)

データ入力:

  • task: string
  • options?: SelectAndExecuteOptions:
    • piece?: string
    • skipTaskList?: boolean
  • agentOverrides?: TaskExecutionOptions

データ出力:

  • タスク実行成功/失敗

4. Piece Execution Layer

4.1 Task Execution (src/features/tasks/execute/taskExecution.ts)

役割: ピース読み込みと実行の橋渡し

主要な処理:

  1. loadPieceByIdentifier(): YAMLまたは名前からピース設定を読み込み
  2. executePiece() を呼び出し

データ入力:

  • ExecuteTaskOptions:
    • task: string
    • cwd: string (実行ディレクトリ、cloneまたはプロジェクトルート)
    • pieceIdentifier: string
    • projectCwd: string (.takt/がある場所)
    • agentOverrides?: TaskExecutionOptions

データ出力:

  • boolean (成功/失敗)

4.2 Piece Execution (src/features/tasks/execute/pieceExecution.ts)

役割: セッション管理、イベント購読、ログ記録

主要な処理:

  1. セッション管理:

    • generateSessionId(): ピースセッションID生成
    • loadAgentSessions() / loadWorktreeSessions(): エージェントセッション復元
    • updateAgentSession() / updateWorktreeSession(): セッション保存
  2. ログ初期化:

    • createSessionLog(): セッションログオブジェクト作成
    • initNdjsonLog(): NDJSON形式のログファイル初期化
    • meta.json 更新: 実行ステータスrunning/completed/abortedと時刻を保存
  3. PieceEngine初期化:

    new PieceEngine(pieceConfig, cwd, task, {
      onStream: streamHandler,           // UI表示用ストリームハンドラ
      initialSessions: savedSessions,    // 保存済みセッションID
      onSessionUpdate: sessionUpdateHandler,
      onIterationLimit: iterationLimitHandler,
      projectCwd,
      language,
      provider,
      model
    })
    
  4. イベント購読:

    • step:start: ステップ開始 → UI表示、NDJSON記録
    • step:complete: ステップ完了 → UI表示、NDJSON記録、セッション更新
    • step:report: レポートファイル出力
    • piece:complete: ピース完了 → 通知
    • piece:abort: ピース中断 → エラー通知
  5. SIGINT処理:

    • 1回目: Graceful abort (engine.abort())
    • 2回目: 強制終了

データ入力:

  • PieceConfig
  • task: string
  • cwd: string
  • PieceExecutionOptions

データ出力:

  • PieceExecutionResult:
    • success: boolean
    • reason?: string

5. Engine Layer (src/core/piece/engine/PieceEngine.ts)

役割: ステートマシンによるピース実行制御

主要な構成要素:

  1. State管理 (PieceState):

    • status: 'running' | 'completed' | 'aborted'
    • currentStep: 現在実行中のステップ名
    • iteration: ピース全体のイテレーション数
    • stepIterations: Map<stepName, count> (ステップごとの実行回数)
    • agentSessions: Map<agent, sessionId> (エージェントごとのセッションID)
    • stepOutputs: Map<stepName, AgentResponse> (各ステップの出力)
    • userInputs: string[] (blocked時のユーザー追加入力)
  2. コンポーネント:

    • OptionsBuilder: エージェント実行オプション構築
    • StepExecutor: 通常ステップの3フェーズ実行
    • ParallelRunner: 並列ステップの実行
  3. 主要メソッド:

    run(): メインループ

    while (state.status === 'running') {
      // 1. Abort & Iteration チェック
      if (abortRequested) { ... }
      if (iteration >= maxMovements) { ... }
    
      // 2. ステップ取得
      const step = getStep(state.currentStep);
    
      // 3. ループ検出
      const loopCheck = loopDetector.check(step.name);
    
      // 4. インストラクション構築 (非並列の場合)
      const instruction = stepExecutor.buildInstruction(...);
    
      // 5. イベント発行
      emit('step:start', step, iteration, instruction);
    
      // 6. ステップ実行
      const { response, instruction } = await runStep(step, instruction);
    
      // 7. イベント発行
      emit('step:complete', step, response, instruction);
    
      // 8. Blocked処理
      if (response.status === 'blocked') { ... }
    
      // 9. ルール評価
      const nextStep = resolveNextStep(step, response);
    
      // 10. 遷移
      if (nextStep === COMPLETE_STEP) { break; }
      if (nextStep === ABORT_STEP) { break; }
      state.currentStep = nextStep;
    }
    

    runStep(): ステップ実行の委譲

    • 並列ステップ → ParallelRunner.runParallelStep()
    • 通常ステップ → StepExecutor.runNormalStep()

    resolveNextStep(): ルール評価によるステップ遷移決定

    • response.matchedRuleIndex を使用
    • determineNextStepByRules() で次ステップ名を取得

データ入力:

  • PieceConfig
  • cwd: string
  • task: string
  • PieceEngineOptions

データ出力:

  • PieceState (最終状態)
  • イベント発行 (各ステップの進捗)

6. Instruction Building & Step Execution Layer

6.1 Step Execution (src/core/piece/engine/StepExecutor.ts)

役割: 3フェーズモデルによるステップ実行

3フェーズの詳細:

Phase 1: Main Execution

  • 目的: エージェントのメインタスク実行
  • Tools: ステップで指定されたツール (ただし step.report がある場合は Write を除外)
  • インストラクション: InstructionBuilder.build()

Phase 2: Report Output (オプション、step.report がある場合のみ)

  • 目的: レポートファイルへの出力
  • Tools: Writeのみ
  • インストラクション: ReportInstructionBuilder.build()
  • セッション: Phase 1と同じセッションを継続 (resume)

Phase 3: Status Judgment (オプション、tag-based rulesがある場合のみ)

  • 目的: ステータスタグの出力
  • Tools: なし (判断のみ)
  • インストラクション: StatusJudgmentBuilder.build()
  • セッション: Phase 1と同じセッションを継続 (resume)
  • 出力: [STEP:N] 形式のタグ

主要メソッド:

runNormalStep():

// Phase 1
const response = await runAgent(step.agent, instruction, options);
updateAgentSession(step.agent, response.sessionId);

// Phase 2 (if step.report)
if (step.report) {
  await runReportPhase(step, stepIteration, context);
}

// Phase 3 (if tag-based rules)
let tagContent = '';
if (needsStatusJudgmentPhase(step)) {
  tagContent = await runStatusJudgmentPhase(step, context);
}

// Rule evaluation
const match = await detectMatchedRule(step, response.content, tagContent, {...});

buildInstruction():

  • InstructionBuilder を使用してインストラクション文字列を生成
  • コンテキスト情報を渡す

6.2 Instruction Building (src/core/piece/instruction/InstructionBuilder.ts)

役割: Phase 1用のインストラクション文字列生成

自動注入セクション:

  1. Execution Context (実行環境メタデータ):

    • Working directory
    • Permission rules (edit mode)
  2. Piece Context:

    • Iteration (piece-wide)
    • Step Iteration (per-step)
    • Step name
    • Report Directory/File info
    • Run Source Paths (.takt/runs/{slug}/context/...)
  3. User Request (タスク本文):

    • {task} プレースホルダーがテンプレートにない場合のみ自動注入
  4. Previous Response (前ステップの出力):

    • step.passPreviousResponse === true かつ
    • {previous_response} プレースホルダーがテンプレートにない場合のみ自動注入
    • 長さ制御2000 chars...TRUNCATED... を適用
    • Source Path を常時注入
  5. Additional User Inputs (blocked時の追加入力):

    • {user_inputs} プレースホルダーがテンプレートにない場合のみ自動注入
  6. Instructions (ステップ固有のテンプレート):

    • step.instructionTemplate の内容
    • プレースホルダー置換: {task}, {previous_response}, {iteration}, など
  7. Status Output Rules (tag-based rules用):

    • hasTagBasedRules(step) の場合のみ
    • generateStatusRulesFromRules() で生成

プレースホルダー置換:

  • {task}: ユーザーリクエスト
  • {previous_response}: 前ステップの出力
  • {user_inputs}: 追加ユーザー入力
  • {iteration}: ピース全体のイテレーション
  • {max_movements}: 最大イテレーション
  • {step_iteration}: ステップのイテレーション
  • {report_dir}: レポートディレクトリ

ロケール対応:

  • language: 'en' | 'ja'
  • セクション見出しや説明文が言語に応じて切り替わる

7. Provider Layer

7.1 Agent Runner (src/agents/runner.ts)

役割: エージェント仕様の解決とプロバイダー呼び出し

主要な処理:

  1. エージェント仕様解決:

    • ビルトインエージェント (coder, architect, など)
    • カスタムエージェント(~/.takt/personas/<name>.md
    • プロンプトファイル (.md)
  2. プロバイダー取得:

    • getProvider(providerType): Claude / Codex / OpenCode / Cursor / Copilot / Mock
  3. エージェント呼び出し:

    • provider.call(agentName, instruction, options)

データ入力:

  • agent: string (エージェント名またはパス)
  • instruction: string (構築済みインストラクション)
  • AgentRunOptions:
    • cwd: string
    • sessionId?: string
    • allowedTools?: string[]
    • provider?: ProviderType
    • model?: string
    • onStream?: StreamHandler

データ出力:

  • AgentResponse:
    • agent: string
    • status: 'success' | 'blocked'
    • content: string
    • sessionId?: string
    • error?: string
    • timestamp: Date

7.2 Provider (src/infra/providers/)

役割: AIプロバイダー(Claude, Codex, OpenCode, Cursor, Copilot)とのSDK通信

主要なプロバイダー:

  • ClaudeProvider: Claude Code SDK (@anthropic-ai/claude-agent-sdk)
  • CodexProvider: Codex SDK (@openai/codex-sdk)
  • OpenCodeProvider: OpenCode SDK (@opencode-ai/sdk)
  • CursorProvider: Cursor Agent CLI
  • CopilotProvider: GitHub Copilot CLI
  • MockProvider: テスト用

主要メソッド:

call():

async call(
  agentName: string,
  instruction: string,
  options: ProviderCallOptions
): Promise<AgentResponse>

処理内容:

  1. システムプロンプト構築
  2. SDK呼び出しプロバイダー固有
  3. ストリーミング処理 (onStream callback)
  4. エラーハンドリング
  5. レスポンス変換

データ入力:

  • agentName: string
  • instruction: string
  • ProviderCallOptions:
    • cwd: string
    • sessionId?: string
    • systemPrompt?: string
    • allowedTools?: string[]
    • model?: string
    • onStream?: StreamHandler

データ出力:

  • AgentResponse (上記と同じ)

データフローの段階

ステージ1: タスク入力

入力方法:

  1. 直接タスク: takt "Fix the login bug"
  2. Issue参照: takt #123
  3. インタラクティブモード: takt または takt a

データ変換:

  • インタラクティブモード: ConversationMessage[]task: string
    • buildTaskFromHistory(): 会話履歴を結合

出力: task: string


ステージ2: 実行環境準備

ピース選択:

  • --piece フラグ → 検証
  • なし → インタラクティブ選択 (selectPiece())

データ:

  • pieceIdentifier: string
  • execCwd: string (実行ディレクトリ)

ステージ3: ピース実行初期化

セッション管理:

  • loadAgentSessions(): 保存済みセッション復元
  • generateSessionId(): ピースセッションID生成
  • initNdjsonLog(): NDJSON ログファイル作成

PieceEngine作成:

new PieceEngine(pieceConfig, cwd, task, {
  onStream,
  initialSessions,
  onSessionUpdate,
  projectCwd,
  language,
  provider,
  model
})

データ:

  • PieceState: 初期状態
    • currentStep = config.initialStep
    • iteration = 0
    • agentSessions = initialSessions

ステージ4: ステップ実行ループ

各イテレーション:

  1. ステップ取得: getStep(state.currentStep)
  2. インストラクション構築: InstructionBuilder.build()
  3. ステップ実行: 3フェーズ実行
  4. ルール評価: detectMatchedRule()
  5. ステップ遷移: resolveNextStep() → 次のステップ名

データ変換:

  • task + contextinstruction: string
  • instructionAgentResponse (via Provider)
  • AgentResponse + rulesmatchedRuleIndex
  • matchedRuleIndexnextStep: string

ステージ5: インストラクション生成

InstructionBuilder処理:

  1. コンテキスト収集:

    • task: 元のユーザーリクエスト
    • iteration, maxMovements: イテレーション情報
    • stepIteration: ステップごとの実行回数
    • cwd, projectCwd: ディレクトリ情報
    • userInputs: blocked時の追加入力
    • previousOutput: 前ステップの出力
    • reportDir: レポートディレクトリ
  2. セクション組み立て:

    • 自動注入セクション (上記7つ)
    • プレースホルダー置換
  3. 出力: 完全なインストラクション文字列


ステージ6: エージェント実行

Phase 1: Main Execution:

  • runAgent()provider.call()
  • ストリーミング → onStream callback → UI表示
  • 結果: AgentResponse

Phase 2: Report Output (オプション):

  • 同じセッションを継続 (resume)
  • Write-only ツール
  • レポートファイル出力

Phase 3: Status Judgment (オプション):

  • 同じセッションを継続 (resume)
  • ツールなし
  • [STEP:N] タグ出力

ステージ7: ルール評価と遷移

ルール評価 (detectMatchedRule()):

5段階のフォールバック:

  1. Aggregate (all()/any()) - 並列ステップ用
  2. Phase 3 tag - [STEP:N] from status judgment
  3. Phase 1 tag - [STEP:N] from main output (fallback)
  4. AI judge - ai("condition text") rules
  5. AI judge fallback - すべての条件をAIで評価

出力: { index: number, method: RuleMatchMethod }

遷移:

  • determineNextStepByRules(): rules[index].next を取得
  • 特殊ステップ:
    • COMPLETE: ピース完了
    • ABORT: ピース中断
  • 通常ステップ: state.currentStep = nextStep

重要な変換ポイント

1. 会話履歴 → タスク文字列

場所: src/features/interactive/interactive.ts

function buildTaskFromHistory(history: ConversationMessage[]): string {
  return history
    .map((msg) => `${msg.role === 'user' ? 'User' : 'Assistant'}: ${msg.content}`)
    .join('\n\n');
}

重要性: インタラクティブモードで蓄積された会話全体が、後続のピース実行で単一の task 文字列として扱われる。


2. タスク → ブランチスラグ (AI生成)

場所: src/infra/task/summarize.ts (呼び出し: selectAndExecute.ts, taskExecution.ts)

await summarizeTaskName(task, { cwd })

処理:

  • タスク文字列をAIに渡す
  • 英語の短いスラグに要約 (例: fix-login-bug)
  • ブランチ名として使用

重要性: ユーザーが日本語でタスクを書いても、Git-friendlyなブランチ名が自動生成される。


3. ピース設定 → PieceState

場所: src/core/piece/engine/state-manager.ts

function createInitialState(
  config: PieceConfig,
  options: PieceEngineOptions
): PieceState {
  return {
    status: 'running',
    currentStep: config.initialStep,
    iteration: 0,
    stepIterations: new Map(),
    agentSessions: new Map(Object.entries(options.initialSessions ?? {})),
    stepOutputs: new Map(),
    userInputs: [],
  };
}

重要性: YAMLで定義された静的な設定が、実行時のミュータブルな状態に変換される。


4. コンテキスト → インストラクション文字列

場所: src/core/piece/instruction/InstructionBuilder.ts

入力:

  • step: PieceStep
  • context: InstructionContext (task, iteration, previousOutput, userInputs, など)

処理:

  1. 7つのセクションを組み立て
  2. プレースホルダー置換
  3. ロケール対応

出力: 完全なMarkdown形式のインストラクション文字列

重要性: 散在するコンテキスト情報が、エージェントが理解できる単一の文字列に統合される。


5. AgentResponse → ルールマッチ

場所: src/core/piece/evaluation/RuleEvaluator.ts

入力:

  • step: PieceStep
  • content: string (Phase 1 output)
  • tagContent: string (Phase 3 output)
  • state: PieceState

処理:

  1. タグ検出 ([STEP:0], [STEP:1], ...)
  2. AI判断 (ai("condition") ルール)
  3. 集約評価 (all(), any())

出力: { index: number, method: RuleMatchMethod } | null

重要性: 自然言語の出力が、構造化されたステップ遷移決定に変換される。


6. ルールマッチ → 次ステップ名

場所: src/core/piece/engine/transitions.ts

function determineNextStepByRules(
  step: PieceStep,
  matchedRuleIndex: number
): string | null {
  const rule = step.rules?.[matchedRuleIndex];
  return rule?.next ?? null;
}

重要性: インデックス番号が、実際に実行すべきステップ名に変換される。


7. Provider Response → AgentResponse

場所: src/infra/providers/ (各プロバイダー実装)

入力: SDKレスポンスプロバイダー固有

処理:

  • status 変換
  • content 抽出
  • error 伝播 (重要!)
  • sessionId 保存

出力: AgentResponse (統一インターフェース)

重要性: 異なるプロバイダーのレスポンスが統一形式に正規化される。


まとめ

TAKTのデータフローは、7つのレイヤーを通じて、ユーザーの自然な入力を段階的に変換し、最終的にAIエージェントの協調的な実行に変えていきます。

主要な設計原則:

  1. Progressive Transformation: データは各レイヤーで少しずつ変換され、次のレイヤーに渡される
  2. Context Accumulation: タスク、イテレーション、ユーザー入力などのコンテキストが蓄積される
  3. Session Continuity: エージェントセッションIDが保存・復元され、会話の継続性を保つ
  4. Event-Driven Architecture: PieceEngineがイベントを発行し、UI、ログ、通知が連携
  5. 3-Phase Execution: メイン実行、レポート出力、ステータス判断の3段階で、明確な責任分離
  6. Rule-Based Routing: ルール評価の5段階フォールバックで、柔軟かつ予測可能な遷移

このアーキテクチャにより、TAKTは複雑な多エージェント協調を、ユーザーには透明で、開発者には拡張可能な形で実現しています。