モデルを選択可能に変更
This commit is contained in:
parent
351327a779
commit
dad627ef03
17
CLAUDE.md
17
CLAUDE.md
@ -107,6 +107,8 @@ steps:
|
||||
- name: step-name
|
||||
agent: ~/.takt/agents/default/coder.md # Path to agent prompt
|
||||
agent_name: coder # Display name (optional)
|
||||
provider: codex # claude|codex (optional)
|
||||
model: opus # Model name (optional)
|
||||
instruction_template: |
|
||||
{task}
|
||||
{previous_response}
|
||||
@ -131,6 +133,21 @@ steps:
|
||||
| `{git_diff}` | Current git diff (uncommitted changes) |
|
||||
| `{report_dir}` | Report directory name (e.g., `20250126-143052-task-summary`) |
|
||||
|
||||
### Model Resolution
|
||||
|
||||
Model is resolved in the following priority order:
|
||||
|
||||
1. **Workflow step `model`** - Highest priority (specified in step YAML)
|
||||
2. **Custom agent `model`** - Agent-level model in `.takt/agents.yaml`
|
||||
3. **Global config `model`** - Default model in `~/.takt/config.yaml`
|
||||
4. **Provider default** - Falls back to provider's default (Claude: sonnet, Codex: gpt-5.2-codex)
|
||||
|
||||
Example `~/.takt/config.yaml`:
|
||||
```yaml
|
||||
provider: claude
|
||||
model: opus # Default model for all steps (unless overridden)
|
||||
```
|
||||
|
||||
## TypeScript Notes
|
||||
|
||||
- ESM modules with `.js` extensions in imports
|
||||
|
||||
82
README.md
82
README.md
@ -1,12 +1,18 @@
|
||||
# TAKT
|
||||
|
||||
**T**ask **A**gent **K**oordination **T**ool - Multi-agent orchestration system for Claude Code (Codex support planned).
|
||||
🇯🇵 [日本語ドキュメント](./docs/README.ja.md)
|
||||
|
||||
**T**ask **A**gent **K**oordination **T**ool - Multi-agent orchestration system for Claude Code and OpenAI Codex.
|
||||
|
||||
> **Note**: This project is developed at my own pace. See [Disclaimer](#disclaimer) for details.
|
||||
|
||||
TAKT is built with TAKT (dogfooding).
|
||||
|
||||
## Requirements
|
||||
|
||||
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) must be installed and configured
|
||||
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) or Codex must be installed and configured
|
||||
|
||||
TAKT supports both Claude Code and Codex as providers; you can choose the provider during setup.
|
||||
|
||||
## Installation
|
||||
|
||||
@ -50,8 +56,20 @@ name: default
|
||||
max_iterations: 10
|
||||
|
||||
steps:
|
||||
- name: plan
|
||||
agent: planner
|
||||
provider: claude # Optional: claude or codex
|
||||
model: opus # Claude: opus/sonnet/haiku, Codex: gpt-5.2-codex/gpt-5.1-codex
|
||||
instruction_template: |
|
||||
{task}
|
||||
transitions:
|
||||
- condition: done
|
||||
next_step: implement
|
||||
|
||||
- name: implement
|
||||
agent: coder
|
||||
provider: codex
|
||||
model: gpt-5.2-codex # Codex model example
|
||||
instruction_template: |
|
||||
{task}
|
||||
transitions:
|
||||
@ -62,6 +80,7 @@ steps:
|
||||
|
||||
- name: review
|
||||
agent: architect
|
||||
model: sonnet # Model alias (no provider = uses global default)
|
||||
transitions:
|
||||
- condition: approved
|
||||
next_step: COMPLETE
|
||||
@ -84,20 +103,76 @@ agents:
|
||||
- name: my-reviewer
|
||||
prompt_file: .takt/prompts/reviewer.md
|
||||
allowed_tools: [Read, Glob, Grep]
|
||||
provider: claude # Optional: claude or codex
|
||||
model: opus # Claude: opus/sonnet/haiku or full name (claude-opus-4-5-20251101)
|
||||
status_patterns:
|
||||
approved: "\\[APPROVE\\]"
|
||||
rejected: "\\[REJECT\\]"
|
||||
|
||||
- name: my-codex-agent
|
||||
prompt_file: .takt/prompts/analyzer.md
|
||||
provider: codex
|
||||
model: gpt-5.2-codex # Codex: gpt-5.2-codex, gpt-5.1-codex, etc.
|
||||
```
|
||||
|
||||
## Model Selection
|
||||
|
||||
### Claude Models
|
||||
|
||||
You can specify models using either **aliases** or **full model names**:
|
||||
|
||||
**Aliases** (recommended for simplicity):
|
||||
- `opus` - Claude Opus 4.5 (highest reasoning capability)
|
||||
- `sonnet` - Claude Sonnet 4.5 (balanced, best for most tasks)
|
||||
- `haiku` - Claude Haiku 4.5 (fast and efficient)
|
||||
- `opusplan` - Opus for planning, Sonnet for execution
|
||||
- `default` - Recommended model for your account type
|
||||
|
||||
**Full model names** (recommended for production):
|
||||
- `claude-opus-4-5-20251101`
|
||||
- `claude-sonnet-4-5-20250929`
|
||||
- `claude-haiku-4-5-20250101`
|
||||
|
||||
### Codex Models
|
||||
|
||||
Available Codex models:
|
||||
- `gpt-5.2-codex` - Latest agentic coding model (default)
|
||||
- `gpt-5.1-codex` - Previous generation
|
||||
- `gpt-5.1-codex-max` - Optimized for long-running tasks
|
||||
- `gpt-5.1-codex-mini` - Smaller, cost-effective version
|
||||
- `codex-1` - Specialized model aligned with coding preferences
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
~/.takt/
|
||||
├── config.yaml # Global config
|
||||
├── config.yaml # Global config (provider, model, workflows, etc.)
|
||||
├── workflows/ # Workflow definitions
|
||||
└── agents/ # Agent prompt files
|
||||
```
|
||||
|
||||
### Global Configuration
|
||||
|
||||
Configure default provider and model in `~/.takt/config.yaml`:
|
||||
|
||||
```yaml
|
||||
# ~/.takt/config.yaml
|
||||
language: en
|
||||
default_workflow: default
|
||||
log_level: info
|
||||
provider: claude # Default provider: claude or codex
|
||||
model: sonnet # Default model (optional)
|
||||
trusted_directories:
|
||||
- /path/to/trusted/dir
|
||||
```
|
||||
|
||||
**Model Resolution Priority:**
|
||||
1. Workflow step `model` (highest priority)
|
||||
2. Custom agent `model`
|
||||
3. Global config `model`
|
||||
4. Provider default (Claude: sonnet, Codex: gpt-5.2-codex)
|
||||
|
||||
|
||||
## Practical Usage Guide
|
||||
|
||||
### Resuming Sessions with `-r`
|
||||
@ -296,7 +371,6 @@ This ensures the project works correctly in a clean Node.js 20 environment.
|
||||
|
||||
## Documentation
|
||||
|
||||
- 🇯🇵 [日本語ドキュメント](./docs/README.ja.md) - Japanese documentation
|
||||
- [Workflow Guide](./docs/workflows.md) - Create and customize workflows
|
||||
- [Agent Guide](./docs/agents.md) - Configure custom agents
|
||||
- [Changelog](./CHANGELOG.md) - Version history
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
"types": "dist/index.d.ts",
|
||||
"bin": {
|
||||
"takt": "./bin/takt",
|
||||
"takt-dev": "./bin/takt",
|
||||
"takt-cli": "./dist/cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@ -16,6 +16,11 @@ log_level: info
|
||||
# Provider runtime: claude or codex
|
||||
provider: claude
|
||||
|
||||
# Default model (optional)
|
||||
# Claude: opus, sonnet, haiku, opusplan, default, or full model name
|
||||
# Codex: gpt-5.2-codex, gpt-5.1-codex, etc.
|
||||
# model: sonnet
|
||||
|
||||
# Debug settings (optional)
|
||||
# debug:
|
||||
# enabled: false
|
||||
|
||||
@ -16,6 +16,11 @@ log_level: info
|
||||
# プロバイダー: claude または codex
|
||||
provider: claude
|
||||
|
||||
# デフォルトモデル (オプション)
|
||||
# Claude: opus, sonnet, haiku, opusplan, default, またはフルモデル名
|
||||
# Codex: gpt-5.2-codex, gpt-5.1-codex など
|
||||
# model: sonnet
|
||||
|
||||
# デバッグ設定 (オプション)
|
||||
# debug:
|
||||
# enabled: false
|
||||
|
||||
@ -54,6 +54,18 @@ function resolveProvider(cwd: string, options?: RunAgentOptions, agentConfig?: C
|
||||
return 'claude';
|
||||
}
|
||||
|
||||
function resolveModel(cwd: string, options?: RunAgentOptions, agentConfig?: CustomAgentConfig): string | undefined {
|
||||
if (options?.model) return options.model;
|
||||
if (agentConfig?.model) return agentConfig.model;
|
||||
try {
|
||||
const globalConfig = loadGlobalConfig();
|
||||
if (globalConfig.model) return globalConfig.model;
|
||||
} catch {
|
||||
// Ignore missing global config
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Get git diff for review context */
|
||||
export function getGitDiff(cwd: string): string {
|
||||
try {
|
||||
@ -91,7 +103,7 @@ export async function runCustomAgent(
|
||||
cwd: options.cwd,
|
||||
sessionId: options.sessionId,
|
||||
allowedTools,
|
||||
model: options.model || agentConfig.model,
|
||||
model: resolveModel(options.cwd, options, agentConfig),
|
||||
onStream: options.onStream,
|
||||
onPermissionRequest: options.onPermissionRequest,
|
||||
onAskUserQuestion: options.onAskUserQuestion,
|
||||
@ -106,7 +118,7 @@ export async function runCustomAgent(
|
||||
cwd: options.cwd,
|
||||
sessionId: options.sessionId,
|
||||
allowedTools,
|
||||
model: options.model || agentConfig.model,
|
||||
model: resolveModel(options.cwd, options, agentConfig),
|
||||
onStream: options.onStream,
|
||||
onPermissionRequest: options.onPermissionRequest,
|
||||
onAskUserQuestion: options.onAskUserQuestion,
|
||||
@ -119,11 +131,12 @@ export async function runCustomAgent(
|
||||
const systemPrompt = loadAgentPrompt(agentConfig);
|
||||
const tools = allowedTools;
|
||||
const provider = resolveProvider(options.cwd, options, agentConfig);
|
||||
const model = resolveModel(options.cwd, options, agentConfig);
|
||||
if (provider === 'codex') {
|
||||
const callOptions: CodexCallOptions = {
|
||||
cwd: options.cwd,
|
||||
sessionId: options.sessionId,
|
||||
model: options.model || agentConfig.model,
|
||||
model,
|
||||
statusPatterns: agentConfig.statusPatterns,
|
||||
onStream: options.onStream,
|
||||
};
|
||||
@ -134,7 +147,7 @@ export async function runCustomAgent(
|
||||
cwd: options.cwd,
|
||||
sessionId: options.sessionId,
|
||||
allowedTools: tools,
|
||||
model: options.model || agentConfig.model,
|
||||
model,
|
||||
statusPatterns: agentConfig.statusPatterns,
|
||||
onStream: options.onStream,
|
||||
onPermissionRequest: options.onPermissionRequest,
|
||||
@ -196,12 +209,13 @@ export async function runAgent(
|
||||
const systemPrompt = loadAgentPromptFromPath(options.agentPath);
|
||||
const tools = options.allowedTools;
|
||||
const provider = resolveProvider(options.cwd, options);
|
||||
const model = resolveModel(options.cwd, options);
|
||||
|
||||
if (provider === 'codex') {
|
||||
const callOptions: CodexCallOptions = {
|
||||
cwd: options.cwd,
|
||||
sessionId: options.sessionId,
|
||||
model: options.model,
|
||||
model,
|
||||
systemPrompt,
|
||||
onStream: options.onStream,
|
||||
};
|
||||
@ -212,7 +226,7 @@ export async function runAgent(
|
||||
cwd: options.cwd,
|
||||
sessionId: options.sessionId,
|
||||
allowedTools: tools,
|
||||
model: options.model,
|
||||
model,
|
||||
systemPrompt,
|
||||
onStream: options.onStream,
|
||||
onPermissionRequest: options.onPermissionRequest,
|
||||
|
||||
@ -367,6 +367,7 @@ export async function callCodex(
|
||||
|
||||
const { events } = await thread.runStreamed(fullPrompt);
|
||||
let content = '';
|
||||
const contentOffsets = new Map<string, number>();
|
||||
let success = true;
|
||||
let failureMessage = '';
|
||||
const startedItems = new Set<string>();
|
||||
@ -406,6 +407,20 @@ export async function callCodex(
|
||||
if (event.type === 'item.updated') {
|
||||
const item = event.item as CodexItem | undefined;
|
||||
if (item) {
|
||||
if (item.type === 'agent_message' && typeof item.text === 'string') {
|
||||
const itemId = item.id;
|
||||
const text = item.text;
|
||||
if (itemId) {
|
||||
const prev = contentOffsets.get(itemId) ?? 0;
|
||||
if (text.length > prev) {
|
||||
if (prev === 0 && content.length > 0) {
|
||||
content += '\n';
|
||||
}
|
||||
content += text.slice(prev);
|
||||
contentOffsets.set(itemId, text.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
emitCodexItemUpdate(item, options.onStream, startedItems, outputOffsets, textOffsets, thinkingOffsets);
|
||||
}
|
||||
continue;
|
||||
@ -415,7 +430,23 @@ export async function callCodex(
|
||||
const item = event.item as CodexItem | undefined;
|
||||
if (item) {
|
||||
if (item.type === 'agent_message' && typeof item.text === 'string') {
|
||||
content = item.text;
|
||||
const itemId = item.id;
|
||||
const text = item.text;
|
||||
if (itemId) {
|
||||
const prev = contentOffsets.get(itemId) ?? 0;
|
||||
if (text.length > prev) {
|
||||
if (prev === 0 && content.length > 0) {
|
||||
content += '\n';
|
||||
}
|
||||
content += text.slice(prev);
|
||||
contentOffsets.set(itemId, text.length);
|
||||
}
|
||||
} else if (text) {
|
||||
if (content.length > 0) {
|
||||
content += '\n';
|
||||
}
|
||||
content += text;
|
||||
}
|
||||
}
|
||||
emitCodexItemCompleted(
|
||||
item,
|
||||
|
||||
@ -30,6 +30,7 @@ export function loadGlobalConfig(): GlobalConfig {
|
||||
defaultWorkflow: parsed.default_workflow,
|
||||
logLevel: parsed.log_level,
|
||||
provider: parsed.provider,
|
||||
model: parsed.model,
|
||||
debug: parsed.debug ? {
|
||||
enabled: parsed.debug.enabled,
|
||||
logFile: parsed.debug.log_file,
|
||||
@ -47,6 +48,9 @@ export function saveGlobalConfig(config: GlobalConfig): void {
|
||||
log_level: config.logLevel,
|
||||
provider: config.provider,
|
||||
};
|
||||
if (config.model) {
|
||||
raw.model = config.model;
|
||||
}
|
||||
if (config.debug) {
|
||||
raw.debug = {
|
||||
enabled: config.debug.enabled,
|
||||
|
||||
@ -68,6 +68,7 @@ function normalizeWorkflowConfig(raw: unknown, workflowDir: string): WorkflowCon
|
||||
agentPath: resolveAgentPathForWorkflow(step.agent, workflowDir),
|
||||
allowedTools: step.allowed_tools,
|
||||
provider: step.provider,
|
||||
model: step.model,
|
||||
instructionTemplate: step.instruction_template || step.instruction || '{task}',
|
||||
transitions: step.transitions.map((t) => ({
|
||||
condition: t.condition,
|
||||
|
||||
@ -61,6 +61,7 @@ export const WorkflowStepRawSchema = z.object({
|
||||
agent_name: z.string().optional(),
|
||||
allowed_tools: z.array(z.string()).optional(),
|
||||
provider: z.enum(['claude', 'codex']).optional(),
|
||||
model: z.string().optional(),
|
||||
instruction: z.string().optional(),
|
||||
instruction_template: z.string().optional(),
|
||||
pass_previous_response: z.boolean().optional().default(true),
|
||||
@ -115,6 +116,7 @@ export const GlobalConfigSchema = z.object({
|
||||
default_workflow: z.string().optional().default('default'),
|
||||
log_level: z.enum(['debug', 'info', 'warn', 'error']).optional().default('info'),
|
||||
provider: z.enum(['claude', 'codex']).optional().default('claude'),
|
||||
model: z.string().optional(),
|
||||
debug: DebugConfigSchema.optional(),
|
||||
});
|
||||
|
||||
|
||||
@ -66,6 +66,8 @@ export interface WorkflowStep {
|
||||
agentPath?: string;
|
||||
/** Provider override for this step */
|
||||
provider?: 'claude' | 'codex';
|
||||
/** Model override for this step */
|
||||
model?: string;
|
||||
instructionTemplate: string;
|
||||
transitions: WorkflowTransition[];
|
||||
passPreviousResponse: boolean;
|
||||
@ -143,6 +145,7 @@ export interface GlobalConfig {
|
||||
defaultWorkflow: string;
|
||||
logLevel: 'debug' | 'info' | 'warn' | 'error';
|
||||
provider?: 'claude' | 'codex';
|
||||
model?: string;
|
||||
debug?: DebugConfig;
|
||||
}
|
||||
|
||||
|
||||
@ -149,6 +149,7 @@ export class WorkflowEngine extends EventEmitter {
|
||||
agentPath: step.agentPath,
|
||||
allowedTools: step.allowedTools,
|
||||
provider: step.provider,
|
||||
model: step.model,
|
||||
onStream: this.options.onStream,
|
||||
onPermissionRequest: this.options.onPermissionRequest,
|
||||
onAskUserQuestion: this.options.onAskUserQuestion,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user