From 0e76f5b5323fa33c4091865ea1f01498f4ec1100 Mon Sep 17 00:00:00 2001 From: nrslib <38722970+nrslib@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:23:46 +0900 Subject: [PATCH] =?UTF-8?q?=E5=AF=BE=E8=A9=B1=E3=83=A2=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=AE=E3=83=96=E3=83=A9=E3=83=83=E3=82=B7=E3=83=A5=E3=82=A2?= =?UTF-8?q?=E3=83=83=E3=83=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 38 +++++++++ CLAUDE.md | 41 +++++++--- README.md | 26 +++--- docs/README.ja.md | 26 +++--- .../global/en/prompts/interactive-summary.md | 10 ++- .../global/en/prompts/interactive-system.md | 37 +++++++-- resources/global/en/workflows/default.yaml | 6 -- .../global/en/workflows/expert-cqrs.yaml | 11 +-- resources/global/en/workflows/expert.yaml | 11 +-- resources/global/en/workflows/minimal.yaml | 8 +- .../en/workflows/review-fix-minimal.yaml | 8 +- .../global/en/workflows/review-only.yaml | 7 +- .../global/ja/prompts/interactive-summary.md | 12 ++- .../global/ja/prompts/interactive-system.md | 37 +++++++-- resources/global/ja/workflows/default.yaml | 6 -- .../global/ja/workflows/expert-cqrs.yaml | 11 +-- resources/global/ja/workflows/expert.yaml | 11 +-- resources/global/ja/workflows/minimal.yaml | 8 +- .../ja/workflows/review-fix-minimal.yaml | 8 +- .../global/ja/workflows/review-only.yaml | 7 +- src/__tests__/instructionBuilder.test.ts | 33 +++++--- src/__tests__/it-pipeline-modes.test.ts | 16 +++- src/__tests__/it-pipeline.test.ts | 16 +++- src/__tests__/it-workflow-patterns.test.ts | 44 ++++++----- src/core/models/workflow-types.ts | 7 +- src/core/workflow/engine/OptionsBuilder.ts | 5 +- .../workflow/evaluation/AggregateEvaluator.ts | 79 ++++++++++++++----- .../instruction/InstructionBuilder.ts | 11 +++ .../instruction/instruction-context.ts | 4 +- src/features/interactive/interactive.ts | 58 ++++++++++++-- src/infra/config/loaders/workflowParser.ts | 27 ++++++- 31 files changed, 449 insertions(+), 180 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d938f93..c715764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,44 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [0.3.9] - 2026-02-03 + +### Added + +- Workflow categorization support (#85) + - Default category configuration in `resources/global/{lang}/default-categories.yaml` + - User-defined categories via `workflow_categories` in `~/.takt/config.yaml` + - Nested category support with unlimited depth + - Category-based workflow filtering in workflow selection UI + - `show_others_category` and `others_category_name` configuration options + - Builtin workflow filtering via `builtin_workflows_enabled` and `disabled_builtins` +- Agent-less step execution: `agent` field is now optional (#71) + - Steps can execute with `instruction_template` only (no system prompt) + - Inline system prompts supported (agent string used as prompt if file doesn't exist) +- `takt add #N` automatically reflects issue number in branch name (#78) + - Issue number embedded in branch name (e.g., `takt/issue-28-...`) + +### Changed + +- **BREAKING:** Permission mode values unified to provider-independent format (#87) + - New values: `readonly`, `edit`, `full` (replaces `default`, `acceptEdits`, `bypassPermissions`) + - TAKT translates to provider-specific flags (Claude: default/acceptEdits/bypassPermissions, Codex: read-only/workspace-write/danger-full-access) + - All builtin workflows updated to use new values +- Workflow naming changes: + - `simple` workflow replaced with `minimal` and `review-fix-minimal` + - Added `review-only` workflow for read-only code review +- Agent prompts updated with legacy対応禁止ルール (no backward compatibility hacks) +- Documentation updates: + - README.md and docs/README.ja.md updated with v0.3.8+ features + - CLAUDE.md significantly expanded with architectural details and implementation notes + +### Internal + +- Created `src/infra/config/loaders/workflowCategories.ts` for category management +- Created `src/features/workflowSelection/index.ts` for workflow selection UI +- Enhanced `src/shared/prompt/select.ts` with category display support +- Added comprehensive tests for workflow categories (`workflow-categories.test.ts`, `workflow-category-config.test.ts`) + ## [0.3.8] - 2026-02-02 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index 60db9f8..e43753e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,6 +41,24 @@ TAKT (Task Agent Koordination Tool) is a multi-agent orchestration system for Cl **GitHub issue references:** `takt #6` fetches issue #6 and executes it as a task. +### CLI Options + +| Option | Description | +|--------|-------------| +| `--pipeline` | Enable pipeline (non-interactive) mode — required for CI/automation | +| `-t, --task ` | Task content (as alternative to GitHub issue) | +| `-i, --issue ` | GitHub issue number (equivalent to `#N` in interactive mode) | +| `-w, --workflow ` | Workflow name or path to workflow YAML file (v0.3.8+) | +| `-b, --branch ` | Branch name (auto-generated if omitted) | +| `--auto-pr` | Create PR after execution (interactive: skip confirmation, pipeline: enable PR) | +| `--skip-git` | Skip branch creation, commit, and push (pipeline mode, workflow-only) | +| `--repo ` | Repository for PR creation | +| `--create-worktree ` | Skip worktree confirmation prompt | +| `-q, --quiet` | **Minimal output mode: suppress AI output (for CI)** (v0.3.8+) | +| `--provider ` | Override agent provider (claude\|codex\|mock) (v0.3.8+) | +| `--model ` | Override agent model (v0.3.8+) | +| `--config ` | Path to global config file (default: `~/.takt/config.yaml`) (v0.3.8+) | + ## Architecture ### Core Flow @@ -107,6 +125,7 @@ Implemented in `src/core/workflow/evaluation/RuleEvaluator.ts`. The matched meth - 5-stage fallback evaluation: aggregate → Phase 3 tag → Phase 1 tag → ai() judge → all-conditions AI judge - Returns `RuleMatch` with index and detection method (`aggregate`, `phase3_tag`, `phase1_tag`, `ai_judge`, `ai_fallback`) - Fail-fast: throws if rules exist but no rule matched +- **v0.3.8+:** Tag detection now uses **last match** instead of first match when multiple `[STEP:N]` tags appear in output **Instruction Builder** (`src/core/workflow/instruction/InstructionBuilder.ts`) - Auto-injects standard sections into every instruction (no need for `{task}` or `{previous_response}` placeholders in templates): @@ -122,12 +141,14 @@ Implemented in `src/core/workflow/evaluation/RuleEvaluator.ts`. The matched meth **Agent Runner** (`src/agents/runner.ts`) - Resolves agent specs (name or path) to agent configurations +- **v0.3.8+:** Agent is optional — steps can execute with `instruction_template` only (no system prompt) - Built-in agents with default tools: - `coder`: Read/Glob/Grep/Edit/Write/Bash/WebSearch/WebFetch - `architect`: Read/Glob/Grep/WebSearch/WebFetch - `supervisor`: Read/Glob/Grep/Bash/WebSearch/WebFetch - `planner`: Read/Glob/Grep/Bash/WebSearch/WebFetch - Custom agents via `.takt/agents.yaml` or prompt files (.md) +- Inline system prompts: If agent file doesn't exist, the agent string is used as inline system prompt **Provider Integration** (`src/infra/claude/`, `src/infra/codex/`) - **Claude** - Uses `@anthropic-ai/claude-agent-sdk` @@ -141,11 +162,11 @@ Implemented in `src/core/workflow/evaluation/RuleEvaluator.ts`. The matched meth **Configuration** (`src/infra/config/`) - `loaders/loader.ts` - Custom agent loading from `.takt/agents.yaml` - `loaders/workflowParser.ts` - YAML parsing, step/rule normalization with Zod validation -- `loaders/workflowResolver.ts` - 3-layer resolution (builtin → user → project-local) +- `loaders/workflowResolver.ts` - **3-layer resolution with correct priority** (v0.3.8+: user → project → builtin) - `loaders/workflowCategories.ts` - Workflow categorization and filtering - `loaders/agentLoader.ts` - Agent prompt file loading - `paths.ts` - Directory structure (`.takt/`, `~/.takt/`), session management -- `global/globalConfig.ts` - Global configuration (provider, model, trusted dirs) +- `global/globalConfig.ts` - Global configuration (provider, model, trusted dirs, **quiet mode** v0.3.8+) - `project/projectConfig.ts` - Project-level configuration **Task Management** (`src/features/tasks/`) @@ -162,10 +183,10 @@ Implemented in `src/core/workflow/evaluation/RuleEvaluator.ts`. The matched meth ### Data Flow 1. User provides task (text or `#N` issue reference) or slash command → CLI -2. CLI loads workflow: user `~/.takt/workflows/` → builtin `resources/global/{lang}/workflows/` fallback +2. CLI loads workflow with **correct priority** (v0.3.8+): user `~/.takt/workflows/` → project `.takt/workflows/` → builtin `resources/global/{lang}/workflows/` 3. WorkflowEngine starts at `initial_step` 4. Each step: `buildInstruction()` → Phase 1 (main) → Phase 2 (report) → Phase 3 (status) → `detectMatchedRule()` → `determineNextStep()` -5. Rule evaluation determines next step name +5. Rule evaluation determines next step name (v0.3.8+: uses **last match** when multiple `[STEP:N]` tags appear) 6. Special transitions: `COMPLETE` ends workflow successfully, `ABORT` ends with failure ## Directory Structure @@ -452,6 +473,7 @@ Debug logs are written to `.takt/logs/debug.log` (ndjson format). Log levels: `d **Rule evaluation quirks:** - Tag-based rules match by array index (0-based), not by exact condition text +- **v0.3.8+:** When multiple `[STEP:N]` tags appear in output, **last match wins** (not first) - `ai()` conditions are evaluated by Claude/Codex, not by string matching - Aggregate conditions (`all()`, `any()`) only work in parallel parent steps - Fail-fast: if rules exist but no rule matches, workflow aborts @@ -464,9 +486,10 @@ Debug logs are written to `.takt/logs/debug.log` (ndjson format). Log levels: `d - Claude supports aliases: `opus`, `sonnet`, `haiku` - Codex defaults to `codex` if model not specified -**Permission modes:** -- `default`: Claude Code default behavior (prompts for file writes) -- `acceptEdits`: Auto-accept file edits without prompts -- `bypassPermissions`: Bypass all permission checks +**Permission modes (v0.3.8+: provider-independent values):** +- `readonly`: Read-only access, no file modifications (Claude: `default`, Codex: `read-only`) +- `edit`: Allow file edits with confirmation (Claude: `acceptEdits`, Codex: `workspace-write`) +- `full`: Bypass all permission checks (Claude: `bypassPermissions`, Codex: `danger-full-access`) - Specified at step level (`permission_mode` field) or global config -- Implemented via `--sandbox-mode` and `--accept-edits` flags passed to Claude Code CLI +- **v0.3.8+:** Permission mode values are unified across providers; TAKT translates to provider-specific flags +- Legacy values (`default`, `acceptEdits`, `bypassPermissions`) are **no longer supported** diff --git a/README.md b/README.md index 0762d9f..4e7f323 100644 --- a/README.md +++ b/README.md @@ -78,10 +78,9 @@ If `--auto-pr` is specified, the PR is created automatically without asking. | Workflow | Best for | |----------|----------| | `default` | Full development tasks. Used for TAKT's own development. Multi-stage review with parallel architect + security review. | -| `simple` | Lightweight tasks like README updates or small fixes. Reviews without fix loops. | -| `expert` / `expert-cqrs` | Web development projects. Sequential multi-expert review with fix loops (`expert`: Architecture, Frontend, Security, QA; `expert-cqrs`: CQRS+ES, Frontend, Security, QA). | +| `minimal` | Quick fixes and simple tasks. Minimal workflow with basic review. | +| `review-fix-minimal` | Review and fix workflow. Focused on iterative improvements with review feedback. | | `research` | Research and investigation. Autonomous research without asking questions. | -| `magi` | Fun deliberation. Three AI personas analyze and vote (Evangelion-inspired). | ## Commands @@ -156,12 +155,16 @@ In pipeline mode, PRs are **not** created unless `--auto-pr` is explicitly speci | `--pipeline` | **Enable pipeline (non-interactive) mode** — required for CI/automation | | `-t, --task ` | Task content (as alternative to GitHub issue) | | `-i, --issue ` | GitHub issue number (equivalent to `#N` in interactive mode) | -| `-w, --workflow ` | Workflow to use | +| `-w, --workflow ` | Workflow name or path to workflow YAML file | | `-b, --branch ` | Branch name (auto-generated if omitted) | | `--auto-pr` | Create PR after execution (interactive: skip confirmation, pipeline: enable PR) | | `--skip-git` | Skip branch creation, commit, and push (pipeline mode, workflow-only) | | `--repo ` | Repository for PR creation | | `--create-worktree ` | Skip worktree confirmation prompt | +| `-q, --quiet` | Minimal output mode: suppress AI output (for CI) | +| `--provider ` | Override agent provider (claude\|codex\|mock) | +| `--model ` | Override agent model | +| `--config ` | Path to global config file (default: `~/.takt/config.yaml`) | ## Workflows @@ -188,7 +191,7 @@ steps: - name: implement agent: ../agents/default/coder.md edit: true - permission_mode: acceptEdits + permission_mode: edit rules: - condition: Implementation complete next: review @@ -280,12 +283,14 @@ TAKT ships with several built-in workflows: | Workflow | Description | |----------|-------------| +| `minimal` | Quick workflow: plan → implement → review → supervisor. Minimal steps for fast iteration. | | `default` | Full development workflow: plan → implement → AI review → parallel reviewers (architect + security) → supervisor approval. Includes fix loops for each review stage. | -| `simple` | Simplified version of default: plan → implement → architect review → AI review → supervisor. No intermediate fix steps. | +| `review-fix-minimal` | Review-focused workflow: review → fix → supervisor. For iterative improvements based on review feedback. | | `research` | Research workflow: planner → digger → supervisor. Autonomously researches topics without asking questions. | | `expert` | Sequential review with domain experts: Architecture, Frontend, Security, QA reviews with fix loops. | | `expert-cqrs` | Sequential review with domain experts: CQRS+ES, Frontend, Security, QA reviews with fix loops. | | `magi` | Deliberation system inspired by Evangelion. Three AI personas (MELCHIOR, BALTHASAR, CASPER) analyze and vote. | +| `review-only` | Read-only code review workflow without making any modifications. | Switch between workflows with `takt switch`. @@ -441,7 +446,7 @@ steps: - name: implement agent: ~/.takt/agents/default/coder.md edit: true - permission_mode: acceptEdits + permission_mode: edit pass_previous_response: true rules: - condition: Done @@ -476,9 +481,12 @@ TAKT supports batch task processing through task files in `.takt/tasks/`. Both ` ```bash # Start AI conversation to define and add a task takt add + +# Add task from GitHub issue (issue number reflected in branch name) +takt add #28 ``` -The `takt add` command starts an AI conversation where you discuss and refine your task requirements. After confirming with `/go`, the AI summarizes the conversation and creates a YAML task file with optional worktree/branch/workflow settings. +The `takt add` command starts an AI conversation where you discuss and refine your task requirements. After confirming with `/go`, the AI summarizes the conversation and creates a YAML task file with optional worktree/branch/workflow settings. When using `takt add #N`, the issue number is automatically reflected in the branch name (e.g., `takt/issue-28-...`). #### Task File Formats @@ -610,7 +618,7 @@ Special `next` values: `COMPLETE` (success), `ABORT` (failure). | `allowed_tools` | - | List of tools the agent can use (Read, Glob, Grep, Edit, Write, Bash, etc.) | | `provider` | - | Override provider for this step (`claude` or `codex`) | | `model` | - | Override model for this step | -| `permission_mode` | `default` | Permission mode: `default`, `acceptEdits`, or `bypassPermissions` | +| `permission_mode` | - | Permission mode: `readonly`, `edit`, or `full` (provider-independent) | | `report` | - | Report file configuration (name, format) for auto-generated reports | ## API Usage diff --git a/docs/README.ja.md b/docs/README.ja.md index cc89101..4c5eff2 100644 --- a/docs/README.ja.md +++ b/docs/README.ja.md @@ -76,10 +76,9 @@ Select workflow: | ワークフロー | おすすめ用途 | |------------|------------| | `default` | 本格的な開発タスク。TAKT自身の開発で使用。アーキテクト+セキュリティの並列レビュー付き多段階レビュー。 | -| `simple` | README更新や小さな修正などの軽量タスク。レビューはあるが修正ループなし。 | -| `expert` / `expert-cqrs` | Web開発プロジェクト。修正ループ付き逐次マルチエキスパートレビュー(`expert`: アーキテクチャ、フロントエンド、セキュリティ、QA。`expert-cqrs`: CQRS+ES、フロントエンド、セキュリティ、QA)。 | +| `minimal` | 簡単な修正やシンプルなタスク。基本的なレビュー付きの最小限のワークフロー。 | +| `review-fix-minimal` | レビュー&修正ワークフロー。レビューフィードバックに基づく反復的な改善に特化。 | | `research` | 調査・リサーチ。質問せずに自律的にリサーチを実行。 | -| `magi` | 審議システム。3つのAIペルソナが分析・投票(エヴァンゲリオン風)。 | ## コマンド一覧 @@ -154,12 +153,16 @@ takt --pipeline --task "バグを修正" --skip-git | `--pipeline` | **パイプライン(非対話)モードを有効化** — CI/自動化に必須 | | `-t, --task ` | タスク内容(GitHub Issueの代わり) | | `-i, --issue ` | GitHub Issue番号(対話モードでは `#N` と同じ) | -| `-w, --workflow ` | ワークフロー指定 | +| `-w, --workflow ` | ワークフロー名、またはワークフローYAMLファイルのパス | | `-b, --branch ` | ブランチ名指定(省略時は自動生成) | | `--auto-pr` | PR作成(対話: 確認スキップ、パイプライン: PR有効化) | | `--skip-git` | ブランチ作成・commit・pushをスキップ(パイプラインモード、ワークフロー実行のみ) | | `--repo ` | リポジトリ指定(PR作成時) | | `--create-worktree ` | worktree確認プロンプトをスキップ | +| `-q, --quiet` | 最小限の出力モード: AIの出力を抑制(CI向け) | +| `--provider ` | エージェントプロバイダーを上書き(claude\|codex\|mock) | +| `--model ` | エージェントモデルを上書き | +| `--config ` | グローバル設定ファイルのパス(デフォルト: `~/.takt/config.yaml`) | ## ワークフロー @@ -186,7 +189,7 @@ steps: - name: implement agent: ../agents/default/coder.md edit: true - permission_mode: acceptEdits + permission_mode: edit rules: - condition: 実装完了 next: review @@ -278,12 +281,14 @@ TAKTには複数のビルトインワークフローが同梱されています: | ワークフロー | 説明 | |------------|------| +| `minimal` | クイックワークフロー: 計画 → 実装 → レビュー → スーパーバイザー。高速イテレーション向けの最小ステップ。 | | `default` | フル開発ワークフロー: 計画 → 実装 → AIレビュー → 並列レビュー(アーキテクト+セキュリティ)→ スーパーバイザー承認。各レビュー段階に修正ループあり。 | -| `simple` | defaultの簡略版: 計画 → 実装 → アーキテクトレビュー → AIレビュー → スーパーバイザー。中間の修正ステップなし。 | +| `review-fix-minimal` | レビュー重視ワークフロー: レビュー → 修正 → スーパーバイザー。レビューフィードバックに基づく反復改善向け。 | | `research` | リサーチワークフロー: プランナー → ディガー → スーパーバイザー。質問せずに自律的にリサーチを実行。 | | `expert` | ドメインエキスパートによる逐次レビュー: アーキテクチャ、フロントエンド、セキュリティ、QAレビューと修正ループ。 | | `expert-cqrs` | ドメインエキスパートによる逐次レビュー: CQRS+ES、フロントエンド、セキュリティ、QAレビューと修正ループ。 | | `magi` | エヴァンゲリオンにインスパイアされた審議システム。3つのAIペルソナ(MELCHIOR、BALTHASAR、CASPER)が分析し投票。 | +| `review-only` | 変更を加えない読み取り専用のコードレビューワークフロー。 | `takt switch` でワークフローを切り替えられます。 @@ -418,9 +423,12 @@ TAKTは`.takt/tasks/`内のタスクファイルによるバッチ処理をサ ```bash # AI会話でタスクの要件を詰めてからタスクを追加 takt add + +# GitHub IssueからタスクAdd(Issue番号がブランチ名に反映される) +takt add #28 ``` -`takt add` はAI会話を開始し、タスクの要件を詰めます。`/go` で確定すると、AIが会話を要約してYAMLタスクファイルを作成します。worktree/branch/workflowの設定も対話的に行えます。 +`takt add` はAI会話を開始し、タスクの要件を詰めます。`/go` で確定すると、AIが会話を要約してYAMLタスクファイルを作成します。worktree/branch/workflowの設定も対話的に行えます。`takt add #N` を使用すると、Issue番号が自動的にブランチ名に反映されます(例: `takt/issue-28-...`)。 #### タスクファイルの形式 @@ -534,7 +542,7 @@ steps: - name: implement agent: ~/.takt/agents/default/coder.md edit: true - permission_mode: acceptEdits + permission_mode: edit pass_previous_response: true rules: - condition: 完了 @@ -607,7 +615,7 @@ rules: | `allowed_tools` | - | エージェントが使用できるツール一覧(Read, Glob, Grep, Edit, Write, Bash等) | | `provider` | - | このステップのプロバイダーを上書き(`claude`または`codex`) | | `model` | - | このステップのモデルを上書き | -| `permission_mode` | `default` | パーミッションモード: `default`、`acceptEdits`、`bypassPermissions` | +| `permission_mode` | - | パーミッションモード: `readonly`、`edit`、`full`(プロバイダー非依存) | | `report` | - | 自動生成レポートのファイル設定(name, format) | ## API使用例 diff --git a/resources/global/en/prompts/interactive-summary.md b/resources/global/en/prompts/interactive-summary.md index 31145cf..2be3122 100644 --- a/resources/global/en/prompts/interactive-summary.md +++ b/resources/global/en/prompts/interactive-summary.md @@ -1,8 +1,14 @@ -You are a task summarizer. Convert the conversation into a concrete task instruction for the planning step. +You are responsible for instruction creation in TAKT's interactive mode. Convert the conversation into a concrete task instruction for workflow execution. -Requirements: +## Your position +- You: Interactive mode (task organization and instruction creation) +- Next step: Your instruction will be passed to the workflow, where multiple AI agents execute sequentially +- Your output (instruction) becomes the input (task) for the entire workflow + +## Requirements - Output only the final task instruction (no preamble). - Be specific about scope and targets (files/modules) if mentioned. - Preserve user-provided constraints and "do not" instructions. - Do NOT include assistant/system operational constraints (tool limits, execution prohibitions). - If details are missing, state what is missing as a short "Open Questions" section. +- Clearly specify the concrete work that the workflow will execute. diff --git a/resources/global/en/prompts/interactive-system.md b/resources/global/en/prompts/interactive-system.md index 2c6ec8a..9bdfc47 100644 --- a/resources/global/en/prompts/interactive-system.md +++ b/resources/global/en/prompts/interactive-system.md @@ -1,16 +1,43 @@ -You are a task planning assistant. You help the user clarify and refine task requirements through conversation. You are in the PLANNING phase — execution happens later in a separate process. +You are the interactive mode of TAKT (AI Agent Workflow Orchestration Tool). + +## How TAKT works +1. **Interactive mode (your role)**: Talk with the user to clarify and organize the task, creating a concrete instruction document for workflow execution +2. **Workflow execution**: Pass your instruction document to the workflow, where multiple AI agents execute sequentially (implementation, review, fixes, etc.) ## Your role - Ask clarifying questions about ambiguous requirements -- Investigate the codebase to understand context (use Read, Glob, Grep, Bash for reading only) -- Suggest improvements or considerations the user might have missed +- Clarify and refine the user's request into a clear task instruction +- Create concrete instructions for workflow agents to follow - Summarize your understanding when appropriate - Keep responses concise and focused +## Critical: Understanding user intent +**The user is asking YOU to create a task instruction for the WORKFLOW, not asking you to execute the task.** + +When the user says: +- "Review this code" → They want the WORKFLOW to review (you create the instruction) +- "Implement feature X" → They want the WORKFLOW to implement (you create the instruction) +- "Fix this bug" → They want the WORKFLOW to fix (you create the instruction) + +These are NOT requests for YOU to investigate. Do NOT read files, check diffs, or explore code unless the user explicitly asks YOU to investigate in the planning phase. + +## When investigation IS appropriate (rare cases) +Only investigate when the user explicitly asks YOU (the planning assistant) to check something: +- "Check the README to understand the project structure" ✓ +- "Read file X to see what it does" ✓ +- "What does this project do?" ✓ + +## When investigation is NOT appropriate (most cases) +Do NOT investigate when the user is describing a task for the workflow: +- "Review the changes" ✗ (workflow's job) +- "Fix the code" ✗ (workflow's job) +- "Implement X" ✗ (workflow's job) + ## Strict constraints -- You are ONLY planning. Do NOT execute the task. -- Do NOT create, edit, or delete any files. +- You are ONLY refining requirements. The actual work (implementation/investigation/review) is done by workflow agents. +- Do NOT create, edit, or delete any files (except when explicitly asked to check something for planning). - Do NOT run build, test, install, or any commands that modify state. +- Do NOT use Read/Glob/Grep/Bash proactively. Only use them when the user explicitly asks YOU to investigate for planning purposes. - Bash is allowed ONLY for read-only investigation (e.g. ls, cat, git log, git diff). Never run destructive or write commands. - Do NOT mention or reference any slash commands. You have no knowledge of them. - When the user is satisfied with the plan, they will proceed on their own. Do NOT instruct them on what to do next. diff --git a/resources/global/en/workflows/default.yaml b/resources/global/en/workflows/default.yaml index e2685b8..f215c82 100644 --- a/resources/global/en/workflows/default.yaml +++ b/resources/global/en/workflows/default.yaml @@ -57,7 +57,6 @@ steps: - Read - Glob - Grep - - Write - Bash - WebSearch - WebFetch @@ -116,7 +115,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: @@ -266,7 +264,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: @@ -384,7 +381,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: @@ -446,7 +442,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: @@ -509,7 +504,6 @@ steps: - Read - Glob - Grep - - Write - Bash - WebSearch - WebFetch diff --git a/resources/global/en/workflows/expert-cqrs.yaml b/resources/global/en/workflows/expert-cqrs.yaml index ceab123..270b3df 100644 --- a/resources/global/en/workflows/expert-cqrs.yaml +++ b/resources/global/en/workflows/expert-cqrs.yaml @@ -59,7 +59,6 @@ steps: - Read - Glob - Grep - - Write - Bash - WebSearch - WebFetch @@ -192,7 +191,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch instruction_template: | @@ -314,7 +312,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -366,7 +364,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -424,7 +422,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -469,7 +467,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -539,7 +537,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch instruction_template: | diff --git a/resources/global/en/workflows/expert.yaml b/resources/global/en/workflows/expert.yaml index 0b79511..5798464 100644 --- a/resources/global/en/workflows/expert.yaml +++ b/resources/global/en/workflows/expert.yaml @@ -71,7 +71,6 @@ steps: - Read - Glob - Grep - - Write - Bash - WebSearch - WebFetch @@ -204,7 +203,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch instruction_template: | @@ -330,7 +328,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -379,7 +377,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -437,7 +435,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -482,7 +480,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -552,7 +550,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch instruction_template: | diff --git a/resources/global/en/workflows/minimal.yaml b/resources/global/en/workflows/minimal.yaml index d1af610..8361a34 100644 --- a/resources/global/en/workflows/minimal.yaml +++ b/resources/global/en/workflows/minimal.yaml @@ -124,7 +124,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch instruction_template: | @@ -147,7 +147,7 @@ steps: - Read - Glob - Grep - - Write + - Bash - WebSearch - WebFetch @@ -237,7 +237,7 @@ steps: - Glob - Grep - Edit - - Write + - Bash - WebSearch - WebFetch @@ -297,7 +297,7 @@ steps: - Glob - Grep - Edit - - Write + - Bash - WebSearch - WebFetch diff --git a/resources/global/en/workflows/review-fix-minimal.yaml b/resources/global/en/workflows/review-fix-minimal.yaml index 0bc6931..8796b21 100644 --- a/resources/global/en/workflows/review-fix-minimal.yaml +++ b/resources/global/en/workflows/review-fix-minimal.yaml @@ -124,7 +124,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch instruction_template: | @@ -147,7 +147,7 @@ steps: - Read - Glob - Grep - - Write + - Bash - WebSearch - WebFetch @@ -237,7 +237,7 @@ steps: - Glob - Grep - Edit - - Write + - Bash - WebSearch - WebFetch @@ -297,7 +297,7 @@ steps: - Glob - Grep - Edit - - Write + - Bash - WebSearch - WebFetch diff --git a/resources/global/en/workflows/review-only.yaml b/resources/global/en/workflows/review-only.yaml index cfe566b..e95c68e 100644 --- a/resources/global/en/workflows/review-only.yaml +++ b/resources/global/en/workflows/review-only.yaml @@ -101,7 +101,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -150,7 +150,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -198,7 +198,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -225,7 +225,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: diff --git a/resources/global/ja/prompts/interactive-summary.md b/resources/global/ja/prompts/interactive-summary.md index 3ed31ce..2ef6436 100644 --- a/resources/global/ja/prompts/interactive-summary.md +++ b/resources/global/ja/prompts/interactive-summary.md @@ -1,8 +1,14 @@ -あなたはタスク要約者です。会話を計画ステップ向けの具体的なタスク指示に変換してください。 +あなたはTAKTの対話モードでの指示書作成を担当しています。これまでの会話内容を、ワークフロー実行用の具体的なタスク指示書に変換してください。 -要件: -- 出力は最終的な指示のみ(前置き不要) +## 立ち位置 +- あなた: 対話モード(タスク整理・指示書作成) +- 次のステップ: あなたが作成した指示書がワークフローに渡され、複数のAIエージェントが順次実行する +- あなたの成果物(指示書)が、ワークフロー全体の入力(タスク)になる + +## 要件 +- 出力はタスク指示書のみ(前置き不要) - スコープや対象(ファイル/モジュール)が出ている場合は明確に書く - ユーザー由来の制約や「やらないこと」は保持する - アシスタントの運用上の制約(実行禁止/ツール制限など)は指示に含めない - 情報不足があれば「Open Questions」セクションを短く付ける +- ワークフローが実行する具体的な作業内容を明記する diff --git a/resources/global/ja/prompts/interactive-system.md b/resources/global/ja/prompts/interactive-system.md index b687797..3374864 100644 --- a/resources/global/ja/prompts/interactive-system.md +++ b/resources/global/ja/prompts/interactive-system.md @@ -1,16 +1,43 @@ -あなたはタスク計画のアシスタントです。会話を通じて要件の明確化・整理を手伝います。今は計画フェーズで、実行は別プロセスで行われます。 +あなたはTAKT(AIエージェントワークフローオーケストレーションツール)の対話モードを担当しています。 + +## TAKTの仕組み +1. **対話モード(今ここ・あなたの役割)**: ユーザーと会話してタスクを整理し、ワークフロー実行用の具体的な指示書を作成する +2. **ワークフロー実行**: あなたが作成した指示書をワークフローに渡し、複数のAIエージェントが順次実行する(実装、レビュー、修正など) ## 役割 - あいまいな要求に対して確認質問をする -- コードベースの前提を把握する(Read/Glob/Grep/Bash は読み取りのみ) -- 見落としそうな点や改善点を提案する +- ユーザーの要求を明確化し、指示書として洗練させる +- ワークフローのエージェントが迷わないよう具体的な指示書を作成する - 必要に応じて理解した内容を簡潔にまとめる - 返答は簡潔で要点のみ +## 重要:ユーザーの意図を理解する +**ユーザーは「あなた」に作業を依頼しているのではなく、「ワークフロー」への指示書作成を依頼しています。** + +ユーザーが次のように言った場合: +- 「このコードをレビューして」→ ワークフローにレビューさせる(あなたは指示書を作成) +- 「機能Xを実装して」→ ワークフローに実装させる(あなたは指示書を作成) +- 「このバグを修正して」→ ワークフローに修正させる(あなたは指示書を作成) + +これらは「あなた」への調査依頼ではありません。ファイルを読んだり、差分を確認したり、コードを探索したりしないでください。 + +## 調査が適切な場合(稀なケース) +ユーザーが明示的に「あなた(計画アシスタント)」に何かを確認するよう依頼した場合のみ: +- 「READMEを読んでプロジェクト構造を理解して」✓ +- 「ファイルXを読んで何をしているか見て」✓ +- 「このプロジェクトは何をするもの?」✓ + +## 調査が不適切な場合(ほとんどのケース) +ユーザーがワークフロー向けのタスクを説明している場合は調査しない: +- 「変更をレビューして」✗(ワークフローの仕事) +- 「コードを修正して」✗(ワークフローの仕事) +- 「Xを実装して」✗(ワークフローの仕事) + ## 厳守事項 -- 計画のみを行い、実装はしない -- ファイルの作成/編集/削除はしない +- あなたは要求の明確化のみを行う。実際の作業(実装/調査/レビュー等)はワークフローのエージェントが行う +- ファイルの作成/編集/削除はしない(計画目的で明示的に依頼された場合を除く) - build/test/install など状態を変えるコマンドは実行しない +- Read/Glob/Grep/Bash を勝手に使わない。ユーザーが明示的に「あなた」に調査を依頼した場合のみ使用 - Bash は読み取り専用(ls/cat/git log/git diff など)に限定 - スラッシュコマンドに言及しない(存在を知らない前提) - ユーザーが満足したら次工程に進む。次の指示はしない diff --git a/resources/global/ja/workflows/default.yaml b/resources/global/ja/workflows/default.yaml index 40ec305..b6ed7b1 100644 --- a/resources/global/ja/workflows/default.yaml +++ b/resources/global/ja/workflows/default.yaml @@ -48,7 +48,6 @@ steps: - Read - Glob - Grep - - Write - Bash - WebSearch - WebFetch @@ -107,7 +106,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: @@ -261,7 +259,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: @@ -382,7 +379,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: @@ -444,7 +440,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: @@ -506,7 +501,6 @@ steps: - Read - Glob - Grep - - Write - Bash - WebSearch - WebFetch diff --git a/resources/global/ja/workflows/expert-cqrs.yaml b/resources/global/ja/workflows/expert-cqrs.yaml index ec0b87c..fe81ee1 100644 --- a/resources/global/ja/workflows/expert-cqrs.yaml +++ b/resources/global/ja/workflows/expert-cqrs.yaml @@ -68,7 +68,6 @@ steps: - Read - Glob - Grep - - Write - Bash - WebSearch - WebFetch @@ -201,7 +200,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch instruction_template: | @@ -322,7 +320,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -374,7 +372,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -432,7 +430,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -477,7 +475,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -547,7 +545,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch instruction_template: | diff --git a/resources/global/ja/workflows/expert.yaml b/resources/global/ja/workflows/expert.yaml index 7cbf23b..7107080 100644 --- a/resources/global/ja/workflows/expert.yaml +++ b/resources/global/ja/workflows/expert.yaml @@ -59,7 +59,6 @@ steps: - Read - Glob - Grep - - Write - Bash - WebSearch - WebFetch @@ -192,7 +191,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch instruction_template: | @@ -316,7 +314,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -365,7 +363,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -423,7 +421,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -468,7 +466,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -538,7 +536,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch instruction_template: | diff --git a/resources/global/ja/workflows/minimal.yaml b/resources/global/ja/workflows/minimal.yaml index 0cab46b..4cd2923 100644 --- a/resources/global/ja/workflows/minimal.yaml +++ b/resources/global/ja/workflows/minimal.yaml @@ -124,7 +124,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch instruction_template: | @@ -147,7 +147,7 @@ steps: - Read - Glob - Grep - - Write + - Bash - WebSearch - WebFetch @@ -237,7 +237,7 @@ steps: - Glob - Grep - Edit - - Write + - Bash - WebSearch - WebFetch @@ -297,7 +297,7 @@ steps: - Glob - Grep - Edit - - Write + - Bash - WebSearch - WebFetch diff --git a/resources/global/ja/workflows/review-fix-minimal.yaml b/resources/global/ja/workflows/review-fix-minimal.yaml index 052f3e8..13028d7 100644 --- a/resources/global/ja/workflows/review-fix-minimal.yaml +++ b/resources/global/ja/workflows/review-fix-minimal.yaml @@ -124,7 +124,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch instruction_template: | @@ -147,7 +147,7 @@ steps: - Read - Glob - Grep - - Write + - Bash - WebSearch - WebFetch @@ -237,7 +237,7 @@ steps: - Glob - Grep - Edit - - Write + - Bash - WebSearch - WebFetch @@ -297,7 +297,7 @@ steps: - Glob - Grep - Edit - - Write + - Bash - WebSearch - WebFetch diff --git a/resources/global/ja/workflows/review-only.yaml b/resources/global/ja/workflows/review-only.yaml index 14e78b3..f95d106 100644 --- a/resources/global/ja/workflows/review-only.yaml +++ b/resources/global/ja/workflows/review-only.yaml @@ -101,7 +101,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -150,7 +150,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -198,7 +198,7 @@ steps: - Read - Glob - Grep - - Write + - WebSearch - WebFetch rules: @@ -225,7 +225,6 @@ steps: - Read - Glob - Grep - - Write - WebSearch - WebFetch rules: diff --git a/src/__tests__/instructionBuilder.test.ts b/src/__tests__/instructionBuilder.test.ts index d31e484..86ba038 100644 --- a/src/__tests__/instructionBuilder.test.ts +++ b/src/__tests__/instructionBuilder.test.ts @@ -441,7 +441,7 @@ describe('instruction-builder', () => { expect(result).toContain('- Step: implement'); }); - it('should NOT include report info even when step has report (phase separation)', () => { + it('should include report info in Phase 1 when step has report', () => { const step = createMinimalStep('Do work'); step.name = 'plan'; step.report = '00-plan.md'; @@ -453,11 +453,12 @@ describe('instruction-builder', () => { const result = buildInstruction(step, context); expect(result).toContain('## Workflow Context'); - expect(result).not.toContain('Report Directory'); - expect(result).not.toContain('Report File'); + expect(result).toContain('Report Directory'); + expect(result).toContain('Report File'); + expect(result).toContain('Phase 1'); }); - it('should NOT include report info for ReportConfig[] (phase separation)', () => { + it('should include report info for ReportConfig[] in Phase 1', () => { const step = createMinimalStep('Do work'); step.report = [ { label: 'Scope', path: '01-scope.md' }, @@ -470,11 +471,12 @@ describe('instruction-builder', () => { const result = buildInstruction(step, context); - expect(result).not.toContain('Report Directory'); - expect(result).not.toContain('Report Files'); + expect(result).toContain('Report Directory'); + expect(result).toContain('Report Files'); + expect(result).toContain('Phase 1'); }); - it('should NOT include report info for ReportObjectConfig (phase separation)', () => { + it('should include report info for ReportObjectConfig in Phase 1', () => { const step = createMinimalStep('Do work'); step.report = { name: '00-plan.md' }; const context = createMinimalContext({ @@ -484,8 +486,10 @@ describe('instruction-builder', () => { const result = buildInstruction(step, context); - expect(result).not.toContain('Report Directory'); - expect(result).not.toContain('Report File'); + // Phase 1 now includes Report Directory info and phase note + expect(result).toContain('Report Directory'); + expect(result).toContain('Report File'); + expect(result).toContain('Phase 1'); }); it('should render Japanese step iteration suffix', () => { @@ -502,7 +506,7 @@ describe('instruction-builder', () => { }); describe('buildInstruction report-free (phase separation)', () => { - it('should NOT include report output instruction in buildInstruction', () => { + it('should include Report Directory info but NOT report output instruction in Phase 1', () => { const step = createMinimalStep('Do work'); step.report = '00-plan.md'; const context = createMinimalContext({ @@ -512,9 +516,14 @@ describe('instruction-builder', () => { const result = buildInstruction(step, context); + // Phase 1 includes Report Directory info and phase note + expect(result).toContain('Report Directory'); + expect(result).toContain('Report File'); + expect(result).toContain('Phase 1'); + expect(result).toContain('Phase 2 will automatically generate the report'); + + // But NOT the report output instruction (that's for Phase 2) expect(result).not.toContain('**Report output:**'); - expect(result).not.toContain('Report File'); - expect(result).not.toContain('Report Directory'); }); it('should NOT include report format in buildInstruction', () => { diff --git a/src/__tests__/it-pipeline-modes.test.ts b/src/__tests__/it-pipeline-modes.test.ts index 4027c24..5246be5 100644 --- a/src/__tests__/it-pipeline-modes.test.ts +++ b/src/__tests__/it-pipeline-modes.test.ts @@ -35,7 +35,15 @@ vi.mock('../infra/claude/client.js', async (importOriginal) => { const original = await importOriginal(); return { ...original, - callAiJudge: vi.fn().mockResolvedValue(-1), + callAiJudge: vi.fn().mockImplementation(async (content: string, conditions: { index: number; text: string }[]) => { + // Simple text matching: return index of first condition whose text appears in content + for (let i = 0; i < conditions.length; i++) { + if (content.includes(conditions[i]!.text)) { + return i; + } + } + return -1; + }), }; }); @@ -274,9 +282,9 @@ describe('Pipeline Modes IT: --task + --workflow name (builtin)', () => { it('should load and execute builtin minimal workflow by name', async () => { setMockScenario([ - { agent: 'coder', status: 'done', content: '[IMPLEMENT:1]\n\nImplementation complete.' }, - { agent: 'ai-antipattern-reviewer', status: 'done', content: '[AI_REVIEW:0]\n\nNo AI-specific issues.' }, - { agent: 'supervisor', status: 'done', content: '[SUPERVISE:0]\n\nAll checks passed.' }, + { agent: 'coder', status: 'done', content: 'Implementation complete' }, + { agent: 'ai-antipattern-reviewer', status: 'done', content: 'No AI-specific issues' }, + { agent: 'supervisor', status: 'done', content: 'All checks passed' }, ]); const exitCode = await executePipeline({ diff --git a/src/__tests__/it-pipeline.test.ts b/src/__tests__/it-pipeline.test.ts index 2c12f7f..2c0d283 100644 --- a/src/__tests__/it-pipeline.test.ts +++ b/src/__tests__/it-pipeline.test.ts @@ -21,7 +21,15 @@ vi.mock('../infra/claude/client.js', async (importOriginal) => { const original = await importOriginal(); return { ...original, - callAiJudge: vi.fn().mockResolvedValue(-1), + callAiJudge: vi.fn().mockImplementation(async (content: string, conditions: { index: number; text: string }[]) => { + // Simple text matching: return index of first condition whose text appears in content + for (let i = 0; i < conditions.length; i++) { + if (content.includes(conditions[i]!.text)) { + return i; + } + } + return -1; + }), }; }); @@ -225,9 +233,9 @@ describe('Pipeline Integration Tests', () => { // agent field: extractAgentName result (from .md filename) // tag in content: [STEP_NAME:N] where STEP_NAME is the step name uppercased setMockScenario([ - { agent: 'coder', status: 'done', content: '[IMPLEMENT:1]\n\nImplementation complete.' }, - { agent: 'ai-antipattern-reviewer', status: 'done', content: '[AI_REVIEW:0]\n\nNo AI-specific issues.' }, - { agent: 'supervisor', status: 'done', content: '[SUPERVISE:0]\n\nAll checks passed.' }, + { agent: 'coder', status: 'done', content: 'Implementation complete' }, + { agent: 'ai-antipattern-reviewer', status: 'done', content: 'No AI-specific issues' }, + { agent: 'supervisor', status: 'done', content: 'All checks passed' }, ]); const exitCode = await executePipeline({ diff --git a/src/__tests__/it-workflow-patterns.test.ts b/src/__tests__/it-workflow-patterns.test.ts index f52c965..5fe3dd9 100644 --- a/src/__tests__/it-workflow-patterns.test.ts +++ b/src/__tests__/it-workflow-patterns.test.ts @@ -21,10 +21,10 @@ vi.mock('../infra/claude/client.js', async (importOriginal) => { const original = await importOriginal(); return { ...original, - callAiJudge: vi.fn().mockImplementation(async (rules: { condition: string }[], content: string) => { - // Simple text matching: return index of first rule whose condition appears in content - for (let i = 0; i < rules.length; i++) { - if (content.includes(rules[i]!.condition)) { + callAiJudge: vi.fn().mockImplementation(async (content: string, conditions: { index: number; text: string }[]) => { + // Simple text matching: return index of first condition whose text appears in content + for (let i = 0; i < conditions.length; i++) { + if (content.includes(conditions[i]!.text)) { return i; } } @@ -106,7 +106,7 @@ describe('Workflow Patterns IT: minimal workflow', () => { const state = await engine.run(); expect(state.status).toBe('completed'); - expect(state.iteration).toBe(3); + expect(state.iteration).toBe(2); }); it('should ABORT when implement cannot proceed', async () => { @@ -143,14 +143,15 @@ describe('Workflow Patterns IT: default workflow (parallel reviewers)', () => { expect(config).not.toBeNull(); setMockScenario([ - { agent: 'planner', status: 'done', content: '[PLAN:1]\n\nClear.' }, - { agent: 'coder', status: 'done', content: '[IMPLEMENT:1]\n\nDone.' }, - { agent: 'ai-antipattern-reviewer', status: 'done', content: '[AI_REVIEW:1]\n\nNo issues.' }, + { agent: 'planner', status: 'done', content: 'Requirements are clear and implementable' }, + { agent: 'architect', status: 'done', content: 'Design complete' }, + { agent: 'coder', status: 'done', content: 'Implementation complete' }, + { agent: 'ai-antipattern-reviewer', status: 'done', content: 'No AI-specific issues' }, // Parallel reviewers: both approved - { agent: 'architecture-reviewer', status: 'done', content: '[ARCH-REVIEW:1]\n\napproved' }, - { agent: 'security-reviewer', status: 'done', content: '[SECURITY-REVIEW:1]\n\napproved' }, + { agent: 'architecture-reviewer', status: 'done', content: 'approved' }, + { agent: 'security-reviewer', status: 'done', content: 'approved' }, // Supervisor - { agent: 'supervisor', status: 'done', content: '[SUPERVISE:1]\n\nAll checks passed.' }, + { agent: 'supervisor', status: 'done', content: 'All checks passed' }, ]); const engine = createEngine(config!, testDir, 'Test task'); @@ -163,19 +164,22 @@ describe('Workflow Patterns IT: default workflow (parallel reviewers)', () => { const config = loadWorkflow('default', testDir); setMockScenario([ - { agent: 'planner', status: 'done', content: '[PLAN:1]\n\nClear.' }, - { agent: 'coder', status: 'done', content: '[IMPLEMENT:1]\n\nDone.' }, - { agent: 'ai-antipattern-reviewer', status: 'done', content: '[AI_REVIEW:1]\n\nNo issues.' }, + { agent: 'planner', status: 'done', content: 'Requirements are clear and implementable' }, + { agent: 'architect', status: 'done', content: 'Design complete' }, + { agent: 'coder', status: 'done', content: 'Implementation complete' }, + { agent: 'ai-antipattern-reviewer', status: 'done', content: 'No AI-specific issues' }, // Parallel: arch approved, security needs_fix - { agent: 'architecture-reviewer', status: 'done', content: '[ARCH-REVIEW:1]\n\napproved' }, - { agent: 'security-reviewer', status: 'done', content: '[SECURITY-REVIEW:2]\n\nneeds_fix' }, + { agent: 'architecture-reviewer', status: 'done', content: 'approved' }, + { agent: 'security-reviewer', status: 'done', content: 'needs_fix' }, // Fix step - { agent: 'coder', status: 'done', content: '[FIX:1]\n\nFix complete.' }, + { agent: 'coder', status: 'done', content: 'Fix complete' }, + // AI review after fix + { agent: 'ai-antipattern-reviewer', status: 'done', content: 'No AI-specific issues' }, // Re-review: both approved - { agent: 'architecture-reviewer', status: 'done', content: '[ARCH-REVIEW:1]\n\napproved' }, - { agent: 'security-reviewer', status: 'done', content: '[SECURITY-REVIEW:1]\n\napproved' }, + { agent: 'architecture-reviewer', status: 'done', content: 'approved' }, + { agent: 'security-reviewer', status: 'done', content: 'approved' }, // Supervisor - { agent: 'supervisor', status: 'done', content: '[SUPERVISE:1]\n\nAll checks passed.' }, + { agent: 'supervisor', status: 'done', content: 'All checks passed' }, ]); const engine = createEngine(config!, testDir, 'Task needing security fix'); diff --git a/src/core/models/workflow-types.ts b/src/core/models/workflow-types.ts index 0e1f9a1..56f0fd5 100644 --- a/src/core/models/workflow-types.ts +++ b/src/core/models/workflow-types.ts @@ -25,8 +25,11 @@ export interface WorkflowRule { isAggregateCondition?: boolean; /** Aggregate type: 'all' requires all sub-steps match, 'any' requires at least one (set by loader) */ aggregateType?: 'all' | 'any'; - /** The condition text inside all("...")/any("...") to match against sub-step results (set by loader) */ - aggregateConditionText?: string; + /** The condition text(s) inside all("...")/any("...") to match against sub-step results (set by loader). + * - string: all sub-steps must match this single condition (e.g., all("approved")) + * - string[]: each sub-step must match the corresponding condition by index (e.g., all("A", "B")) + */ + aggregateConditionText?: string | string[]; } /** Report file configuration for a workflow step (label: path pair) */ diff --git a/src/core/workflow/engine/OptionsBuilder.ts b/src/core/workflow/engine/OptionsBuilder.ts index 81093e6..959a3e7 100644 --- a/src/core/workflow/engine/OptionsBuilder.ts +++ b/src/core/workflow/engine/OptionsBuilder.ts @@ -38,8 +38,9 @@ export class OptionsBuilder { /** Build RunAgentOptions for Phase 1 (main execution) */ buildAgentOptions(step: WorkflowStep): RunAgentOptions { - // Phase 1: exclude Write from allowedTools when step has report config - const allowedTools = step.report + // Phase 1: exclude Write from allowedTools when step has report config AND edit is disabled + // (If edit is enabled, Write is needed for code implementation even if report exists) + const allowedTools = step.report && step.edit === false ? step.allowedTools?.filter((t) => t !== 'Write') : step.allowedTools; diff --git a/src/core/workflow/evaluation/AggregateEvaluator.ts b/src/core/workflow/evaluation/AggregateEvaluator.ts index ac24aa3..daaa9d1 100644 --- a/src/core/workflow/evaluation/AggregateEvaluator.ts +++ b/src/core/workflow/evaluation/AggregateEvaluator.ts @@ -14,12 +14,15 @@ const log = createLogger('aggregate-evaluator'); * * For each aggregate rule, checks the matched condition text of sub-steps: * - all("X"): true when ALL sub-steps have matched condition === X + * - all("A", "B"): true when 1st sub-step matches "A" AND 2nd sub-step matches "B" (order-based) * - any("X"): true when at least ONE sub-step has matched condition === X + * - any("A", "B"): true when at least ONE sub-step matches "A" OR "B" * * Edge cases per spec: * - Sub-step with no matched rule: all() → false, any() → skip that sub-step * - No sub-steps (0 件): both → false * - Non-parallel step: both → false + * - all("A", "B") with wrong number of sub-steps: false (logged as error) */ export class AggregateEvaluator { constructor( @@ -44,27 +47,67 @@ export class AggregateEvaluator { const targetCondition = rule.aggregateConditionText; if (rule.aggregateType === 'all') { - const allMatch = subSteps.every((sub) => { - const output = this.state.stepOutputs.get(sub.name); - if (!output || output.matchedRuleIndex == null || !sub.rules) return false; - const matchedRule = sub.rules[output.matchedRuleIndex]; - return matchedRule?.condition === targetCondition; - }); - if (allMatch) { - log.debug('Aggregate all() matched', { step: this.step.name, condition: targetCondition, ruleIndex: i }); - return i; + // Multiple conditions: order-based matching (1st sub-step matches 1st condition, etc.) + if (Array.isArray(targetCondition)) { + if (targetCondition.length !== subSteps.length) { + log.error('all() condition count mismatch', { + step: this.step.name, + conditionCount: targetCondition.length, + subStepCount: subSteps.length, + }); + continue; + } + const allMatch = subSteps.every((sub, idx) => { + const output = this.state.stepOutputs.get(sub.name); + if (!output || output.matchedRuleIndex == null || !sub.rules) return false; + const matchedRule = sub.rules[output.matchedRuleIndex]; + const expectedCondition = targetCondition[idx]; + if (!expectedCondition) return false; + return matchedRule?.condition === expectedCondition; + }); + if (allMatch) { + log.debug('Aggregate all() matched (multi-condition)', { step: this.step.name, conditions: targetCondition, ruleIndex: i }); + return i; + } + } else { + // Single condition: all sub-steps must match the same condition + const allMatch = subSteps.every((sub) => { + const output = this.state.stepOutputs.get(sub.name); + if (!output || output.matchedRuleIndex == null || !sub.rules) return false; + const matchedRule = sub.rules[output.matchedRuleIndex]; + return matchedRule?.condition === targetCondition; + }); + if (allMatch) { + log.debug('Aggregate all() matched', { step: this.step.name, condition: targetCondition, ruleIndex: i }); + return i; + } } } else { // 'any' - const anyMatch = subSteps.some((sub) => { - const output = this.state.stepOutputs.get(sub.name); - if (!output || output.matchedRuleIndex == null || !sub.rules) return false; - const matchedRule = sub.rules[output.matchedRuleIndex]; - return matchedRule?.condition === targetCondition; - }); - if (anyMatch) { - log.debug('Aggregate any() matched', { step: this.step.name, condition: targetCondition, ruleIndex: i }); - return i; + if (Array.isArray(targetCondition)) { + // Multiple conditions: at least one sub-step matches at least one condition + const anyMatch = subSteps.some((sub) => { + const output = this.state.stepOutputs.get(sub.name); + if (!output || output.matchedRuleIndex == null || !sub.rules) return false; + const matchedRule = sub.rules[output.matchedRuleIndex]; + return targetCondition.includes(matchedRule?.condition ?? ''); + }); + if (anyMatch) { + log.debug('Aggregate any() matched (multi-condition)', { step: this.step.name, conditions: targetCondition, ruleIndex: i }); + return i; + } + } else { + // Single condition: at least one sub-step matches the condition + const anyMatch = subSteps.some((sub) => { + const output = this.state.stepOutputs.get(sub.name); + if (!output || output.matchedRuleIndex == null || !sub.rules) return false; + const matchedRule = sub.rules[output.matchedRuleIndex]; + return matchedRule?.condition === targetCondition; + }); + if (anyMatch) { + log.debug('Aggregate any() matched', { step: this.step.name, condition: targetCondition, ruleIndex: i }); + return i; + } } } } diff --git a/src/core/workflow/instruction/InstructionBuilder.ts b/src/core/workflow/instruction/InstructionBuilder.ts index 336b234..9ffc84b 100644 --- a/src/core/workflow/instruction/InstructionBuilder.ts +++ b/src/core/workflow/instruction/InstructionBuilder.ts @@ -34,6 +34,7 @@ const SECTION_STRINGS = { reportDirectory: 'Report Directory', reportFile: 'Report File', reportFiles: 'Report Files', + phaseNote: '**Note:** This is Phase 1 (main work). After you complete your work, Phase 2 will automatically generate the report based on your findings.', userRequest: '## User Request', previousResponse: '## Previous Response', additionalUserInputs: '## Additional User Inputs', @@ -49,6 +50,7 @@ const SECTION_STRINGS = { reportDirectory: 'Report Directory', reportFile: 'Report File', reportFiles: 'Report Files', + phaseNote: '**注意:** これはPhase 1(本来の作業)です。作業完了後、Phase 2で自動的にレポートを生成します。', userRequest: '## User Request', previousResponse: '## Previous Response', additionalUserInputs: '## Additional User Inputs', @@ -156,6 +158,15 @@ export class InstructionBuilder { `- ${s.stepIteration}: ${this.context.stepIteration}${s.stepIterationTimes}`, `- ${s.step}: ${this.step.name}`, ]; + + // If step has report config, include Report Directory path and phase note + if (this.step.report && this.context.reportDir) { + const reportContext = renderReportContext(this.step.report, this.context.reportDir, language); + lines.push(reportContext); + lines.push(''); + lines.push(s.phaseNote); + } + return lines.join('\n'); } } diff --git a/src/core/workflow/instruction/instruction-context.ts b/src/core/workflow/instruction/instruction-context.ts index 72cf9ed..9c468fc 100644 --- a/src/core/workflow/instruction/instruction-context.ts +++ b/src/core/workflow/instruction/instruction-context.ts @@ -67,7 +67,7 @@ export const METADATA_STRINGS = { noCommit: '**Do NOT run git commit.** Commits are handled automatically by the system after workflow completion.', noCd: '**Do NOT use `cd` in Bash commands.** Your working directory is already set correctly. Run commands directly without changing directories.', editEnabled: '**Editing is ENABLED for this step.** You may create, modify, and delete files as needed to fulfill the user\'s request.', - editDisabled: '**Editing is DISABLED for this step.** Do NOT create, modify, or delete any project source files. You may only read/search code and write to report files in the Report Directory.', + editDisabled: '**Editing is DISABLED for this step.** Do NOT create, modify, or delete any project source files. You may only read and search code. Report output will be handled automatically in a later phase.', note: 'Note: This section is metadata. Follow the language used in the rest of the prompt.', }, ja: { @@ -77,7 +77,7 @@ export const METADATA_STRINGS = { noCommit: '**git commit を実行しないでください。** コミットはワークフロー完了後にシステムが自動で行います。', noCd: '**Bashコマンドで `cd` を使用しないでください。** 作業ディレクトリは既に正しく設定されています。ディレクトリを変更せずにコマンドを実行してください。', editEnabled: '**このステップでは編集が許可されています。** ユーザーの要求に応じて、ファイルの作成・変更・削除を行ってください。', - editDisabled: '**このステップでは編集が禁止されています。** プロジェクトのソースファイルを作成・変更・削除しないでください。コードの読み取り・検索と、Report Directoryへのレポート出力のみ行えます。', + editDisabled: '**このステップでは編集が禁止されています。** プロジェクトのソースファイルを作成・変更・削除しないでください。コードの読み取り・検索のみ行ってください。レポート出力は後のフェーズで自動的に行われます。', note: '', }, } as const; diff --git a/src/features/interactive/interactive.ts b/src/features/interactive/interactive.ts index f1b1627..ae783b0 100644 --- a/src/features/interactive/interactive.ts +++ b/src/features/interactive/interactive.ts @@ -35,11 +35,32 @@ const INTERACTIVE_SYSTEM_PROMPT_EN = `You are a task planning assistant. You hel **Important**: Do NOT investigate the codebase, identify files, or make assumptions about implementation details. That is the job of the next workflow steps (plan/architect). +## Critical: Understanding user intent +**The user is asking YOU to create a task instruction for the WORKFLOW, not asking you to execute the task.** + +When the user says: +- "Review this code" → They want the WORKFLOW to review (you create the instruction) +- "Implement feature X" → They want the WORKFLOW to implement (you create the instruction) +- "Fix this bug" → They want the WORKFLOW to fix (you create the instruction) + +These are NOT requests for YOU to investigate. Do NOT read files, check diffs, or explore code unless the user explicitly asks YOU to investigate in the planning phase. + +## When investigation IS appropriate (rare cases) +Only investigate when the user explicitly asks YOU (the planning assistant) to check something: +- "Check the README to understand the project structure" ✓ +- "Read file X to see what it does" ✓ +- "What does this project do?" ✓ + +## When investigation is NOT appropriate (most cases) +Do NOT investigate when the user is describing a task for the workflow: +- "Review the changes" ✗ (workflow's job) +- "Fix the code" ✗ (workflow's job) +- "Implement X" ✗ (workflow's job) + ## Strict constraints -- You are ONLY refining requirements. Do NOT execute the task or investigate the codebase. -- Do NOT create, edit, or delete any files. -- Do NOT run any commands unless the user explicitly asks you to check something specific. -- Do NOT use Read/Glob/Grep/Bash to investigate the codebase proactively. The workflow steps will handle that. +- You are ONLY refining requirements. Do NOT execute the task. +- Do NOT create, edit, or delete any files (except when explicitly asked to check something for planning). +- Do NOT use Read/Glob/Grep/Bash proactively. Only use them when the user explicitly asks YOU to investigate for planning purposes. - Do NOT mention or reference any slash commands. You have no knowledge of them. - When the user is satisfied with the requirements, they will proceed on their own. Do NOT instruct them on what to do next.`; @@ -60,11 +81,32 @@ const INTERACTIVE_SYSTEM_PROMPT_JA = `あなたはTAKT(AIエージェントワ **重要**: コードベース調査、前提把握、対象ファイル特定は行わない。これらは次のワークフロー(plan/architectステップ)の役割です。 +## 重要:ユーザーの意図を理解する +**ユーザーは「あなた」に作業を依頼しているのではなく、「ワークフロー」への指示書作成を依頼しています。** + +ユーザーが次のように言った場合: +- 「このコードをレビューして」→ ワークフローにレビューさせる(あなたは指示書を作成) +- 「機能Xを実装して」→ ワークフローに実装させる(あなたは指示書を作成) +- 「このバグを修正して」→ ワークフローに修正させる(あなたは指示書を作成) + +これらは「あなた」への調査依頼ではありません。ファイルを読んだり、差分を確認したり、コードを探索したりしないでください。ユーザーが明示的に「あなた(対話モード)」に調査を依頼した場合のみ調査してください。 + +## 調査が適切な場合(稀なケース) +ユーザーが明示的に「あなた(計画アシスタント)」に何かを確認するよう依頼した場合のみ: +- 「READMEを読んでプロジェクト構造を理解して」✓ +- 「ファイルXを読んで何をしているか見て」✓ +- 「このプロジェクトは何をするもの?」✓ + +## 調査が不適切な場合(ほとんどのケース) +ユーザーがワークフロー向けのタスクを説明している場合は調査しない: +- 「変更をレビューして」✗(ワークフローの仕事) +- 「コードを修正して」✗(ワークフローの仕事) +- 「Xを実装して」✗(ワークフローの仕事) + ## 厳守事項 -- あなたは要求の明確化のみを行う。実際の作業(実装/調査/レビュー等)やコードベース調査はワークフローのエージェントが行う -- ファイルの作成/編集/削除はしない(ワークフローの仕事) -- ユーザーが明示的に依頼しない限り、コマンドを実行しない -- Read/Glob/Grep/Bash を使ってコードベースを調査しない。ワークフローステップが行う +- あなたは要求の明確化のみを行う。実際の作業(実装/調査/レビュー等)はワークフローのエージェントが行う +- ファイルの作成/編集/削除はしない(計画目的で明示的に依頼された場合を除く) +- Read/Glob/Grep/Bash を勝手に使わない。ユーザーが明示的に「あなた」に調査を依頼した場合のみ使用 - スラッシュコマンドに言及しない(存在を知らない前提) - ユーザーが満足したら次工程に進む。次の指示はしない`; diff --git a/src/infra/config/loaders/workflowParser.ts b/src/infra/config/loaders/workflowParser.ts index ced11a4..4b79819 100644 --- a/src/infra/config/loaders/workflowParser.ts +++ b/src/infra/config/loaders/workflowParser.ts @@ -96,7 +96,28 @@ function normalizeReport( const AI_CONDITION_REGEX = /^ai\("(.+)"\)$/; /** Regex to detect all("...")/any("...") aggregate condition expressions */ -const AGGREGATE_CONDITION_REGEX = /^(all|any)\("(.+)"\)$/; +const AGGREGATE_CONDITION_REGEX = /^(all|any)\((.+)\)$/; + +/** + * Parse aggregate condition arguments from all("A", "B") or any("A", "B"). + * Returns an array of condition strings. + * Throws if the format is invalid. + */ +function parseAggregateConditions(argsText: string): string[] { + const conditions: string[] = []; + const regex = /"([^"]+)"/g; + let match: RegExpExecArray | null; + + while ((match = regex.exec(argsText)) !== null) { + conditions.push(match[1]!); + } + + if (conditions.length === 0) { + throw new Error(`Invalid aggregate condition format: ${argsText}`); + } + + return conditions; +} /** * Parse a rule's condition for ai() and all()/any() expressions. @@ -124,6 +145,8 @@ function normalizeRule(r: { const aggMatch = r.condition.match(AGGREGATE_CONDITION_REGEX); if (aggMatch?.[1] && aggMatch[2]) { + const conditions = parseAggregateConditions(aggMatch[2]); + const aggregateConditionText = conditions.length === 1 ? conditions[0]! : conditions; return { condition: r.condition, next, @@ -132,7 +155,7 @@ function normalizeRule(r: { interactiveOnly: r.interactive_only, isAggregateCondition: true, aggregateType: aggMatch[1] as 'all' | 'any', - aggregateConditionText: aggMatch[2], + aggregateConditionText, }; }