When creating agents that use handleSteps generators to programmatically execute tool calls, follow these exact patterns to avoid TypeScript compilation errors.
import type { AgentDefinition } from '../types/agent-definition'
const definition: AgentDefinition = {
// ... other fields
handleSteps: function* ({ agentState, prompt, params }) {
// Generator body
},
}Yield objects with toolName and input properties. The input schema must match the tool's expected parameters exactly.
handleSteps: function* ({ agentState, prompt, params }) {
const promptWithDefault = prompt ?? 'Default prompt'
yield {
toolName: 'spawn_agents',
input: {
agents: [
{
agent_type: 'agent-id-1',
prompt: promptWithDefault,
},
{
agent_type: 'agent-id-2',
prompt: promptWithDefault,
},
],
},
}
// After tool execution, yield 'STEP' to let the agent process results
yield 'STEP'
},WRONG: Using incorrect property names or nested structures
// ❌ Incorrect - wrong tool call structure
yield {
type: 'tool_call',
name: 'spawn_agents',
arguments: { ... }
}WRONG: Using think_deeply or custom tool names that don't exist
// ❌ Incorrect - this tool doesn't exist
yield {
toolName: 'think_deeply',
input: { ... }
}CORRECT: Use toolName and input at the top level
// ✅ Correct
yield {
toolName: 'spawn_agents',
input: {
agents: [{ agent_type: 'my-agent', prompt: 'Do something' }]
}
}After yielding tool calls, yield the string 'STEP' to let the main agent process the results:
handleSteps: function* ({ prompt }) {
yield {
toolName: 'spawn_agents',
input: { agents: [...] },
}
// This tells the runtime to run an LLM step to process spawn results
yield 'STEP'
},Agents that spawn sub-agents must include:
toolNames: ['spawn_agents']- Enable the spawn toolspawnableAgents: ['agent-id-1', 'agent-id-2']- List allowed sub-agents
const definition: AgentDefinition = {
id: 'coordinator',
model: 'openai/gpt-5',
toolNames: ['spawn_agents'],
spawnableAgents: ['sub-agent-1', 'sub-agent-2', 'sub-agent-3'],
// ...
}See .agents/deep-thinking/deep-thinker.ts for a working example:
import type { AgentDefinition } from '../types/agent-definition'
const definition: AgentDefinition = {
id: 'deep-thinker',
displayName: 'Deep Thinker Agent',
model: 'openai/gpt-5',
toolNames: ['spawn_agents'],
spawnableAgents: ['gpt5-thinker', 'sonnet-thinker', 'gemini-thinker'],
inputSchema: {
prompt: {
type: 'string',
description: 'The topic to analyze',
},
},
outputMode: 'last_message',
handleSteps: function* ({ prompt }) {
const promptWithDefault = prompt ?? 'Think about this topic'
yield {
toolName: 'spawn_agents',
input: {
agents: [
{ agent_type: 'gpt5-thinker', prompt: promptWithDefault },
{ agent_type: 'sonnet-thinker', prompt: promptWithDefault },
{ agent_type: 'gemini-thinker', prompt: promptWithDefault },
],
},
}
yield 'STEP'
},
}
export default definitionPlace related agents in subdirectories under .agents/:
.agents/
└── deep-thinking/
├── deep-thinker.ts # Coordinator
├── deepest-thinker.ts # Meta-coordinator
├── gpt5-thinker.ts # Sub-agent
├── sonnet-thinker.ts # Sub-agent
└── gemini-thinker.ts # Sub-agent
When implementing agents:
- Only create files that are directly requested
- Don't add documentation files unless explicitly asked
- Keep agent definitions simple - use
AgentDefinitiontype, not custom wrappers - Don't create factory patterns unless there's clear reuse need