Skip to content

Commit baa0d70

Browse files
committed
Iterative orchestrator
1 parent dfc1803 commit baa0d70

File tree

4 files changed

+242
-2
lines changed

4 files changed

+242
-2
lines changed

.agents/base2/base2-implementor-gpt-5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,6 @@ Important: you *must* make at least one tool call in every response message unle
169169

170170
const definition = {
171171
...createBase2Implementor(),
172-
id: 'base2-implementor',
172+
id: 'base2-implementor-gpt-5',
173173
}
174174
export default definition
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { publisher } from '../../constants'
2+
3+
import type { SecretAgentDefinition } from '../../types/secret-agent-definition'
4+
5+
const definition: SecretAgentDefinition = {
6+
id: 'iterative-orchestrator-step',
7+
publisher,
8+
model: 'openai/gpt-5',
9+
displayName: 'Iterative Orchestrator Step',
10+
spawnerPrompt:
11+
'Orchestrates the completion of a large task through batches of independent steps.',
12+
toolNames: ['spawn_agents', 'read_files', 'set_output'],
13+
spawnableAgents: [
14+
'file-picker-max',
15+
'code-searcher',
16+
'directory-lister',
17+
'glob-matcher',
18+
'researcher-web',
19+
'researcher-docs',
20+
'commander',
21+
],
22+
inputSchema: {
23+
prompt: {
24+
type: 'string',
25+
description:
26+
'Context bundle including: overall goal, progress summary so far, constraints.',
27+
},
28+
},
29+
outputMode: 'structured_output',
30+
outputSchema: {
31+
type: 'object',
32+
properties: {
33+
isDone: { type: 'boolean' },
34+
nextSteps: {
35+
type: 'array',
36+
items: {
37+
type: 'object',
38+
properties: {
39+
title: { type: 'string' },
40+
prompt: { type: 'string' },
41+
type: { type: 'string', enum: ['implementation', 'decision'] },
42+
successCriteria: { type: 'array', items: { type: 'string' } },
43+
filesToReadHints: { type: 'array', items: { type: 'string' } },
44+
},
45+
required: ['title', 'prompt', 'type'],
46+
},
47+
},
48+
notes: { type: 'string' },
49+
},
50+
required: ['isDone', 'nextSteps', 'notes'],
51+
},
52+
systemPrompt: `You are an expert orchestrator that orchestrates the completion of a large task. You spawn the batches of independent steps (implementation or decision-making) that can be executed in parallel and iteratively progresses until the task is complete. Give this task your absolute best shot!
53+
54+
Important: you *must* make at least one tool call, via <codebuff_tool_call> syntax, in every response message! If you do not, you will be cut off prematurely before the task is complete.`,
55+
instructionsPrompt: `You decide the next batch of independent steps that can be executed in parallel for a large task.
56+
- Each step should be small, focused, and objectively verifiable.
57+
- Steps can be either:
58+
1. Implementation steps (coding tasks)
59+
2. Decision-making steps (e.g., "Decide which authentication framework to use", "How should we architecture this feature?")
60+
- Only return steps that are truly independent and can be done concurrently.
61+
- If only one step is needed next, return a single-item array.
62+
- Mark isDone=true only when the overall task is truly complete.
63+
64+
Return JSON via set_output with:
65+
{
66+
isDone: boolean,
67+
nextSteps: [
68+
{
69+
title: string,
70+
prompt: string, // exact prompt to give to the implementor or decision maker
71+
type: 'implementation' | 'decision', // whether this is a coding task or decision
72+
successCriteria?: string[] // 3-6 bullet checks that show this step is done
73+
filesToReadHints?: string[] // optional globs/paths hints
74+
}
75+
],
76+
notes: string // short rationale for these steps
77+
}
78+
`,
79+
stepPrompt: `Important: you *must* make at least one tool call, via <codebuff_tool_call> syntax, in every response message!`,
80+
}
81+
82+
export default definition
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import { publisher } from '../../constants'
2+
3+
import type { ToolCall, AgentState } from '../../types/agent-definition'
4+
import type { SecretAgentDefinition } from '../../types/secret-agent-definition'
5+
6+
type SpawnResult = { agentType: string; value: any }
7+
8+
type StepInfo = {
9+
title: string
10+
prompt: string
11+
type: 'implementation' | 'decision'
12+
successCriteria?: string[]
13+
filesToReadHints?: string[]
14+
}
15+
16+
const definition: SecretAgentDefinition = {
17+
id: 'iterative-orchestrator',
18+
publisher,
19+
model: 'anthropic/claude-sonnet-4.5',
20+
displayName: 'Iterative Orchestrator',
21+
spawnerPrompt:
22+
'Orchestrates the completion of a large task through batches of independent steps.',
23+
outputMode: 'structured_output',
24+
toolNames: ['spawn_agents', 'set_output'],
25+
spawnableAgents: ['iterative-orchestrator-step', 'base2-fast'],
26+
27+
inputSchema: {
28+
prompt: { type: 'string', description: 'Overall task to complete' },
29+
},
30+
31+
handleSteps: function* ({ prompt, params, logger }) {
32+
const overallGoal = prompt || 'No prompt provided'
33+
34+
const progress: {
35+
iteration: number
36+
steps: StepInfo[]
37+
plannerNotes: string
38+
}[] = []
39+
let completed = false
40+
let iteration = 0
41+
42+
while (!completed) {
43+
iteration++
44+
// 1) Plan next step
45+
const planningBundle = [
46+
'Overall Goal:',
47+
overallGoal,
48+
'',
49+
'Progress so far:',
50+
JSON.stringify(progress, null, 2),
51+
].join('\n')
52+
53+
const { toolResult } = yield {
54+
toolName: 'spawn_agents',
55+
input: {
56+
agents: [
57+
{
58+
agent_type: 'iterative-orchestrator-step',
59+
prompt: planningBundle,
60+
},
61+
],
62+
},
63+
} satisfies ToolCall<'spawn_agents'>
64+
const spawnResults =
65+
(toolResult ?? [])
66+
.filter((r) => r.type === 'json')
67+
.map((r) => r.value as SpawnResult[])[0] ?? []
68+
const stepOutput = spawnResults.find(
69+
(r) => r.agentType === 'iterative-orchestrator-step',
70+
)?.value?.value
71+
72+
logger.debug({ stepOutput }, 'step output')
73+
74+
if (!stepOutput) {
75+
logger.warn('No iterative-orchestrator-step result; aborting early.')
76+
break
77+
}
78+
if (stepOutput.isDone) {
79+
completed = true
80+
progress.push({
81+
iteration,
82+
steps: [],
83+
plannerNotes: stepOutput.notes || '',
84+
})
85+
break
86+
}
87+
88+
const steps: StepInfo[] = stepOutput.nextSteps || []
89+
if (steps.length === 0) {
90+
logger.warn(
91+
'No next steps returned by iterative-orchestrator-step; aborting early.',
92+
)
93+
break
94+
}
95+
96+
// 3) Execute all steps in parallel
97+
const executionAgents = steps.map((step) => {
98+
if (step.type === 'decision') {
99+
return {
100+
agent_type: 'base2-fast',
101+
prompt: `DECISION TASK: ${step.prompt}\n\nThis is a decision-making step, not an implementation step. Your job is to research options, analyze trade-offs, and make a clear recommendation with rationale. Write out your decision in the last message. Do not create a file with your decision.`,
102+
params: { filesToRead: step.filesToReadHints || [] },
103+
}
104+
} else {
105+
return {
106+
agent_type: 'base2-fast',
107+
prompt: step.prompt,
108+
params: { filesToRead: step.filesToReadHints || [] },
109+
}
110+
}
111+
})
112+
113+
const { toolResult: executionToolResult } = yield {
114+
toolName: 'spawn_agents',
115+
input: { agents: executionAgents },
116+
} satisfies ToolCall<'spawn_agents'>
117+
118+
const executionResults =
119+
(executionToolResult ?? [])
120+
.filter((r) => r.type === 'json')
121+
.map((r) => r.value as SpawnResult[])[0] ?? []
122+
123+
logger.debug({ executionResults }, 'execution results')
124+
125+
// 5) Record progress for all steps
126+
progress.push({
127+
iteration,
128+
steps: steps.map((step, idx: number) => ({
129+
...step,
130+
executionSummary: executionResults[idx]?.value || {},
131+
})),
132+
plannerNotes: stepOutput.notes || '',
133+
})
134+
}
135+
136+
// 6) Final output
137+
yield {
138+
toolName: 'set_output',
139+
input: {
140+
completed,
141+
iterations: iteration,
142+
progress,
143+
},
144+
} satisfies ToolCall<'set_output'>
145+
146+
function getSpawnResults(agentState: AgentState): SpawnResult[] {
147+
const toolMsgs = agentState.messageHistory.filter(
148+
(m: any) => m.role === 'tool' && m.content?.toolName === 'spawn_agents',
149+
)
150+
const flat = toolMsgs.flatMap((m: any) => m.content.output || [])
151+
return flat
152+
.filter((o: any) => o?.type === 'json')
153+
.map((o: any) => o.value)[0] as SpawnResult[]
154+
}
155+
},
156+
}
157+
158+
export default definition

.agents/orchestrator/research-implement-orchestrator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const createResearchImplementOrchestrator: () => Omit<
3434
outputMode: 'last_message',
3535
includeMessageHistory: false,
3636
toolNames: ['spawn_agents'],
37-
spawnableAgents: buildArray('task-researcher', 'base2-implementor'),
37+
spawnableAgents: buildArray('task-researcher', 'base2-implementor-gpt-5'),
3838

3939
systemPrompt: `You are Buffy, a strategic coding assistant that orchestrates complex coding tasks through specialized sub-agents.
4040

0 commit comments

Comments
 (0)