1033 lines
48 KiB
Markdown
1033 lines
48 KiB
Markdown
# TAKTデータフロー解析
|
||
|
||
このドキュメントでは、TAKTにおけるデータフロー、特にインタラクティブモードからピース実行に至るまでのデータの流れを説明します。
|
||
|
||
## 目次
|
||
|
||
1. [概要](#概要)
|
||
2. [全体フロー図](#全体フロー図)
|
||
3. [各レイヤーの詳細](#各レイヤーの詳細)
|
||
4. [データフローの段階](#データフローの段階)
|
||
5. [重要な変換ポイント](#重要な変換ポイント)
|
||
|
||
---
|
||
|
||
## 概要
|
||
|
||
TAKTのデータフローは以下の7つの主要なレイヤーで構成されています:
|
||
|
||
1. **CLI Layer** - ユーザー入力の受付
|
||
2. **Interactive Layer** - タスクの対話的な明確化
|
||
3. **Execution Orchestration Layer** - ピース選択とworktree管理
|
||
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 │
|
||
│ ▼ │
|
||
│ ┌──────────────────────────────────┐ │
|
||
│ │ confirmAndCreateWorktree() │ │
|
||
│ │ - AI branchname generation │ │
|
||
│ │ - createSharedClone() │ │
|
||
│ └─────────┬────────────────────────┘ │
|
||
│ │ { execCwd, isWorktree, branch } │
|
||
│ ▼ │
|
||
│ ┌──────────────────────────────────┐ │
|
||
│ │ 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() │ │
|
||
│ │ (ClaudeProvider / CodexProvider) │ │
|
||
│ │ │ │
|
||
│ │ - Build system prompt │ │
|
||
│ │ - Call SDK (callClaude / callCodex) │ │
|
||
│ │ - 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`)
|
||
|
||
**役割**: ピース選択とworktree管理
|
||
|
||
**主要な処理**:
|
||
|
||
1. **ピース決定** (`determinePiece()`):
|
||
- オーバーライド指定がある場合:
|
||
- パス形式 → そのまま使用
|
||
- 名前形式 → バリデーション
|
||
- オーバーライドなし → インタラクティブ選択 (`selectPiece()`)
|
||
|
||
2. **Worktree作成** (`confirmAndCreateWorktree()`):
|
||
- ユーザー確認 (または `--create-worktree` フラグ)
|
||
- ブランチ名生成 (`summarizeTaskName()` - AIでタスクから英語スラグ生成)
|
||
- `createSharedClone()`: git clone --shared で軽量クローン作成
|
||
|
||
3. **タスク実行開始** (`selectAndExecuteTask()`):
|
||
- `executeTask()` を呼び出し
|
||
- 成功時: Auto-commit & Push
|
||
- PR作成 (オプション)
|
||
|
||
**データ入力**:
|
||
- `task: string`
|
||
- `options?: SelectAndExecuteOptions`:
|
||
- `piece?: string`
|
||
- `createWorktree?: boolean`
|
||
- `autoPr?: boolean`
|
||
- `agentOverrides?: TaskExecutionOptions`
|
||
|
||
**データ出力**:
|
||
- `{ execCwd, isWorktree, branch }`
|
||
- タスク実行成功/失敗
|
||
|
||
---
|
||
|
||
### 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初期化**:
|
||
```typescript
|
||
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()`**: メインループ
|
||
```typescript
|
||
while (state.status === 'running') {
|
||
// 1. Abort & Iteration チェック
|
||
if (abortRequested) { ... }
|
||
if (iteration >= maxIterations) { ... }
|
||
|
||
// 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()`**:
|
||
```typescript
|
||
// 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_iterations}`: 最大イテレーション
|
||
- `{step_iteration}`: ステップのイテレーション
|
||
- `{report_dir}`: レポートディレクトリ
|
||
|
||
**ロケール対応**:
|
||
- `language: 'en' | 'ja'`
|
||
- セクション見出しや説明文が言語に応じて切り替わる
|
||
|
||
---
|
||
|
||
### 7. Provider Layer
|
||
|
||
#### 7.1 Agent Runner (`src/agents/runner.ts`)
|
||
|
||
**役割**: エージェント仕様の解決とプロバイダー呼び出し
|
||
|
||
**主要な処理**:
|
||
1. **エージェント仕様解決**:
|
||
- ビルトインエージェント (`coder`, `architect`, など)
|
||
- カスタムエージェント (`.takt/agents.yaml`)
|
||
- プロンプトファイル (`.md`)
|
||
|
||
2. **プロバイダー取得**:
|
||
- `getProvider(providerType)`: ClaudeProvider / CodexProvider / MockProvider
|
||
|
||
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)とのSDK通信
|
||
|
||
**主要なプロバイダー**:
|
||
- `ClaudeProvider`: Claude Code SDK (`@anthropic-ai/claude-agent-sdk`)
|
||
- `CodexProvider`: Codex API
|
||
- `MockProvider`: テスト用
|
||
|
||
**主要メソッド**:
|
||
|
||
**`call()`**:
|
||
```typescript
|
||
async call(
|
||
agentName: string,
|
||
instruction: string,
|
||
options: ProviderCallOptions
|
||
): Promise<AgentResponse>
|
||
```
|
||
|
||
**処理内容**:
|
||
1. システムプロンプト構築
|
||
2. SDK呼び出し (`callClaude()` / `callCodex()`)
|
||
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()`)
|
||
|
||
**Worktree作成** (オプション):
|
||
- `confirmAndCreateWorktree()`:
|
||
- ユーザー確認または `--create-worktree` フラグ
|
||
- `summarizeTaskName()`: タスク → 英語スラグ (AI呼び出し)
|
||
- `createSharedClone()`: git clone --shared
|
||
|
||
**データ**:
|
||
- `pieceIdentifier: string`
|
||
- `{ execCwd, isWorktree, branch }`
|
||
|
||
---
|
||
|
||
### ステージ3: ピース実行初期化
|
||
|
||
**セッション管理**:
|
||
- `loadAgentSessions()`: 保存済みセッション復元
|
||
- `generateSessionId()`: ピースセッションID生成
|
||
- `initNdjsonLog()`: NDJSON ログファイル作成
|
||
|
||
**PieceEngine作成**:
|
||
```typescript
|
||
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 + context` → `instruction: string`
|
||
- `instruction` → `AgentResponse` (via Provider)
|
||
- `AgentResponse + rules` → `matchedRuleIndex`
|
||
- `matchedRuleIndex` → `nextStep: string`
|
||
|
||
---
|
||
|
||
### ステージ5: インストラクション生成
|
||
|
||
**InstructionBuilder処理**:
|
||
|
||
1. **コンテキスト収集**:
|
||
- `task`: 元のユーザーリクエスト
|
||
- `iteration`, `maxIterations`: イテレーション情報
|
||
- `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`
|
||
|
||
```typescript
|
||
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`)
|
||
|
||
```typescript
|
||
await summarizeTaskName(task, { cwd })
|
||
```
|
||
|
||
**処理**:
|
||
- タスク文字列をAIに渡す
|
||
- 英語の短いスラグに要約 (例: `fix-login-bug`)
|
||
- ブランチ名として使用
|
||
|
||
**重要性**: ユーザーが日本語でタスクを書いても、Git-friendlyなブランチ名が自動生成される。
|
||
|
||
---
|
||
|
||
### 3. ピース設定 → PieceState
|
||
|
||
**場所**: `src/core/piece/engine/state-manager.ts`
|
||
|
||
```typescript
|
||
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`
|
||
|
||
```typescript
|
||
function determineNextStepByRules(
|
||
step: PieceStep,
|
||
matchedRuleIndex: number
|
||
): string | null {
|
||
const rule = step.rules?.[matchedRuleIndex];
|
||
return rule?.next ?? null;
|
||
}
|
||
```
|
||
|
||
**重要性**: インデックス番号が、実際に実行すべきステップ名に変換される。
|
||
|
||
---
|
||
|
||
### 7. Provider Response → AgentResponse
|
||
|
||
**場所**: `src/infra/providers/claude.ts`, `src/infra/providers/codex.ts`
|
||
|
||
**入力**: SDKレスポンス (`ClaudeResult`)
|
||
|
||
**処理**:
|
||
- `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は複雑な多エージェント協調を、ユーザーには透明で、開発者には拡張可能な形で実現しています。
|