Skip to content

Commit c1b1b39

Browse files
committed
best of n fast
1 parent 80d8bc8 commit c1b1b39

File tree

4 files changed

+210
-2
lines changed

4 files changed

+210
-2
lines changed

.agents/base2/base2.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ export const createBase2: (
1111
options?: {
1212
hasNoValidation?: boolean
1313
bestOfN?: boolean
14+
bestOfNFast?: boolean
1415
},
1516
) => Omit<SecretAgentDefinition, 'id'> = (mode, options) => {
16-
const { hasNoValidation = false, bestOfN = false } = options ?? {}
17+
const { hasNoValidation = false, bestOfN = false, bestOfNFast = false } = options ?? {}
1718
const isFast = mode === 'fast'
1819
const isMax = mode === 'max'
1920

@@ -58,6 +59,7 @@ export const createBase2: (
5859
'researcher-docs',
5960
'commander',
6061
bestOfN && 'base2-best-of-n-orchestrator',
62+
bestOfNFast && 'base2-best-of-n-fast-orchestrator',
6163
isMax && 'base2-gpt-5-worker',
6264
'context-pruner',
6365
),
@@ -149,7 +151,9 @@ ${buildArray(
149151
`- Use the write_todos tool to write out your step-by-step implementation plan.${hasNoValidation ? '' : ' You should include at least one step to validate/test your changes: be specific about whether to typecheck, run tests, run lints, etc.'}`,
150152
bestOfN &&
151153
`- You must spawn the base2-best-of-n-orchestrator agent to implement the code changes, since it will generate multiple implementation proposals and select the best one, which the user wants you to do.`,
152-
!bestOfN &&
154+
bestOfNFast &&
155+
`- You must spawn the base2-best-of-n-fast-orchestrator agent to implement the code changes, since it will generate multiple implementation proposals and select the best one, which the user wants you to do.`,
156+
!bestOfN && !bestOfNFast &&
153157
isFast &&
154158
`- Use the str_replace or write_file tool to make the changes. (Pause after making all the changes to see the tool results of your edits and double check they went through correctly.)`,
155159
isMax &&
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import type { SecretAgentDefinition } from '../../types/secret-agent-definition'
2+
import { publisher } from '../../constants'
3+
import { StepText, ToolCall } from 'types/agent-definition'
4+
5+
const definition: SecretAgentDefinition = {
6+
id: 'base2-best-of-n-fast-orchestrator',
7+
publisher,
8+
model: 'anthropic/claude-sonnet-4.5',
9+
displayName: 'Best-of-N Fast Implementation Orchestrator',
10+
spawnerPrompt:
11+
'Orchestrates multiple implementor agents to generate implementation proposals and selects the best one',
12+
13+
includeMessageHistory: true,
14+
inheritParentSystemPrompt: true,
15+
16+
toolNames: [
17+
'spawn_agents',
18+
'str_replace',
19+
'write_file',
20+
'set_messages',
21+
'set_output',
22+
],
23+
spawnableAgents: [
24+
'base2-implementor-step',
25+
'base2-implementor-step-gpt-5',
26+
'base2-selector-fast',
27+
],
28+
29+
inputSchema: {},
30+
outputMode: 'structured_output',
31+
32+
handleSteps: function* ({ agentState }) {
33+
// Remove userInstruction message for this agent.
34+
const messages = agentState.messageHistory.concat()
35+
messages.pop()
36+
yield {
37+
toolName: 'set_messages',
38+
input: {
39+
messages,
40+
},
41+
includeToolCall: false,
42+
} satisfies ToolCall<'set_messages'>
43+
44+
// Spawn 1 of each model for easy prompt caching
45+
const { toolResult: implementorsResult1 } = yield {
46+
toolName: 'spawn_agents',
47+
input: {
48+
agents: [
49+
{ agent_type: 'base2-implementor-step' },
50+
{ agent_type: 'base2-implementor-step' },
51+
{ agent_type: 'base2-implementor-step' },
52+
{ agent_type: 'base2-implementor-step' },
53+
{ agent_type: 'base2-implementor-step' },
54+
],
55+
},
56+
includeToolCall: false,
57+
}
58+
const implementorsResult = extractSpawnResults<string>(implementorsResult1)
59+
60+
// Extract all the plans from the structured outputs
61+
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
62+
// Parse implementations from tool results
63+
const implementations = implementorsResult.map((content, index) => ({
64+
id: letters[index],
65+
content,
66+
}))
67+
68+
// Spawn selector with implementations as params
69+
const { toolResult: selectorResult } = yield {
70+
toolName: 'spawn_agents',
71+
input: {
72+
agents: [
73+
{
74+
agent_type: 'base2-selector-fast',
75+
params: { implementations },
76+
},
77+
],
78+
},
79+
includeToolCall: false,
80+
} satisfies ToolCall<'spawn_agents'>
81+
82+
const selectorOutput = extractSpawnResults<{
83+
implementationId: string
84+
reasoning: string
85+
}>(selectorResult)[0]
86+
87+
if ('errorMessage' in selectorOutput) {
88+
yield {
89+
toolName: 'set_output',
90+
input: { error: selectorOutput.errorMessage },
91+
} satisfies ToolCall<'set_output'>
92+
return
93+
}
94+
const { implementationId } = selectorOutput
95+
const chosenImplementation = implementations.find(
96+
(implementation) => implementation.id === implementationId,
97+
)
98+
if (!chosenImplementation) {
99+
yield {
100+
toolName: 'set_output',
101+
input: { error: 'Failed to find chosen implementation.' },
102+
} satisfies ToolCall<'set_output'>
103+
return
104+
}
105+
106+
// Spawn editor to apply the chosen implementation
107+
const { agentState: postEditsAgentState } = yield {
108+
type: 'STEP_TEXT',
109+
text: chosenImplementation.content,
110+
} as StepText
111+
const { messageHistory } = postEditsAgentState
112+
const lastAssistantMessageIndex = messageHistory.findLastIndex(
113+
(message) => message.role === 'assistant',
114+
)
115+
const editToolResults = messageHistory
116+
.slice(lastAssistantMessageIndex)
117+
.filter((message) => message.role === 'tool')
118+
.flatMap((message) => message.content.output)
119+
.filter((output) => output.type === 'json')
120+
.map((output) => output.value)
121+
122+
// Set output with the chosen implementation and reasoning
123+
yield {
124+
toolName: 'set_output',
125+
input: {
126+
response: chosenImplementation.content,
127+
toolResults: editToolResults,
128+
},
129+
} satisfies ToolCall<'set_output'>
130+
131+
function extractSpawnResults<T>(
132+
results: any[] | undefined,
133+
): (T | { errorMessage: string })[] {
134+
if (!results) return []
135+
const spawnedResults = results
136+
.filter((result) => result.type === 'json')
137+
.map((result) => result.value)
138+
.flat() as {
139+
agentType: string
140+
value: { value?: T; errorMessage?: string }
141+
}[]
142+
return spawnedResults.map(
143+
(result) =>
144+
result.value.value ?? {
145+
errorMessage:
146+
result.value.errorMessage ?? 'Error extracting spawn results',
147+
},
148+
)
149+
}
150+
},
151+
}
152+
153+
export default definition
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createBase2 } from '../base2'
2+
import type { SecretAgentDefinition } from '../../types/secret-agent-definition'
3+
4+
const base2 = createBase2('fast', { bestOfNFast: true })
5+
const definition: SecretAgentDefinition = {
6+
...base2,
7+
id: 'base2-best-of-n-fast',
8+
displayName: 'Buffy Best-of-N Orchestrator',
9+
}
10+
11+
export default definition
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type { SecretAgentDefinition } from '../../types/secret-agent-definition'
2+
import base2Selector from './base2-selector'
3+
4+
const definition: SecretAgentDefinition = {
5+
...base2Selector,
6+
id: 'base2-selector-fast',
7+
model: 'anthropic/claude-sonnet-4.5',
8+
displayName: 'Best-of-N Fast Implementation Selector',
9+
outputSchema: {
10+
type: 'object',
11+
properties: {
12+
implementationId: {
13+
type: 'string',
14+
description: 'The id of the chosen implementation',
15+
},
16+
},
17+
required: ['implementationId'],
18+
},
19+
20+
instructionsPrompt: `As part of the best-of-n workflow of agents, you are the implementation selector agent. You have been provided with multiple implementation proposals via params.
21+
22+
The implementations are available in the params.implementations array, where each has:
23+
- id: A unique identifier for the implementation
24+
- content: The full implementation text with tool calls
25+
26+
Your task is to analyze each implementation proposal carefully, compare them against the original user requirements, and select the best implementation.
27+
Evaluate each based on:
28+
- Correctness and completeness
29+
- Simplicity and maintainability
30+
- Code quality and adherence to project conventions
31+
- Minimal changes to existing code
32+
- Proper reuse of existing helpers and patterns
33+
- Clarity and readability
34+
35+
Do not write any reasoning or explanations AT ALL.
36+
37+
Your response should be only a single tool call to set_output with the selected implementationId.`,
38+
}
39+
40+
export default definition

0 commit comments

Comments
 (0)