Skip to content

Commit 1be71b7

Browse files
committed
thinker best of n opus
1 parent d29325a commit 1be71b7

File tree

5 files changed

+128
-14
lines changed

5 files changed

+128
-14
lines changed

.agents/base2/base2.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export function createBase2(
6565
isDefault && 'editor-best-of-n',
6666
isMax && 'editor-best-of-n-max',
6767
isDefault && 'thinker-best-of-n',
68-
isMax && 'thinker-best-of-n-gpt-5',
68+
isMax && 'thinker-best-of-n-opus',
6969
isDefault && 'code-reviewer-gemini',
7070
isMax && 'code-reviewer-opus',
7171
'context-pruner',
@@ -118,7 +118,7 @@ Use the spawn_agents tool to spawn specialized agents to help you complete the u
118118
${buildArray(
119119
'- Spawn context-gathering agents (file pickers, code-searcher, directory-lister, glob-matcher, and web/docs researchers) before making edits.',
120120
isMax &&
121-
'- Spawn the thinker-best-of-n-gpt-5 after gathering context to solve complex problems.',
121+
'- Spawn the thinker-best-of-n-opus after gathering context to solve complex problems.',
122122
`- Spawn a ${isMax ? 'editor-best-of-n-max' : 'editor-best-of-n'} agent to implement the changes after you have gathered all the context you need. You must spawn this agent for non-trivial changes, since it writes much better code than you would with the str_replace or write_file tools. Don't spawn the editor in parallel with context-gathering agents.`,
123123
'- Spawn commanders sequentially if the second command depends on the the first.',
124124
!isFast &&
@@ -385,7 +385,7 @@ function buildImplementationStepPrompt({
385385
`Keep working until the user's request is completely satisfied${!hasNoValidation ? ' and validated' : ''}, or until you require more information from the user.`,
386386
!isFast &&
387387
`You must spawn the ${isMax ? 'editor-best-of-n-max' : 'editor-best-of-n'} agent to implement code changes, since it will generate the best code changes.`,
388-
isMax && 'Spawn the thinker-best-of-n-gpt-5 to solve complex problems.',
388+
isMax && 'Spawn the thinker-best-of-n-opus to solve complex problems.',
389389
`After completing the user request, summarize your changes in a sentence${isFast ? '' : ' or a few short bullet points'}.${isSonnet ? " Don't create any summary markdown files or example documentation files, unless asked by the user." : ''}. Don't repeat yourself, especially if you have already concluded and summarized the changes in a previous step -- just end your turn.`,
390390
).join('\n')
391391
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createThinkerBestOfN } from './thinker-best-of-n'
2+
3+
const definition = {
4+
...createThinkerBestOfN('opus'),
5+
id: 'thinker-best-of-n-opus',
6+
}
7+
export default definition

.agents/thinker/best-of-n/thinker-best-of-n.ts

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function createThinkerBestOfN(
3232
inheritParentSystemPrompt: true,
3333

3434
toolNames: ['spawn_agents'],
35-
spawnableAgents: ['thinker-selector'],
35+
spawnableAgents: [isOpus ? 'thinker-selector-opus' : 'thinker-selector'],
3636

3737
inputSchema: {
3838
prompt: {
@@ -58,17 +58,102 @@ Answer the user's query to the best of your ability and be extremely concise and
5858
5959
**Important**: Do not use any tools! You are only thinking!`,
6060

61-
handleSteps,
61+
handleSteps: isOpus ? handleStepsOpus : handleStepsDefault,
62+
}
63+
}
64+
function* handleStepsDefault({
65+
agentState,
66+
prompt,
67+
params,
68+
}: AgentStepContext): ReturnType<
69+
NonNullable<SecretAgentDefinition['handleSteps']>
70+
> {
71+
const selectorAgentType = 'thinker-selector'
72+
const n = Math.min(10, Math.max(1, (params?.n as number | undefined) ?? 5))
73+
74+
// Use GENERATE_N to generate n thinking outputs
75+
const { nResponses = [] } = yield {
76+
type: 'GENERATE_N',
77+
n,
78+
}
79+
80+
// Extract all the thinking outputs
81+
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
82+
const thoughts = nResponses.map((content, index) => ({
83+
id: letters[index],
84+
content,
85+
}))
86+
87+
// Spawn selector with thoughts as params
88+
const { toolResult: selectorResult } = yield {
89+
toolName: 'spawn_agents',
90+
input: {
91+
agents: [
92+
{
93+
agent_type: selectorAgentType,
94+
params: { thoughts },
95+
},
96+
],
97+
},
98+
includeToolCall: false,
99+
} satisfies ToolCall<'spawn_agents'>
100+
101+
const selectorOutput = extractSpawnResults<{
102+
thoughtId: string
103+
}>(selectorResult)[0]
104+
105+
if ('errorMessage' in selectorOutput) {
106+
yield {
107+
type: 'STEP_TEXT',
108+
text: selectorOutput.errorMessage,
109+
} satisfies StepText
110+
return
111+
}
112+
const { thoughtId } = selectorOutput
113+
const chosenThought = thoughts.find((thought) => thought.id === thoughtId)
114+
if (!chosenThought) {
115+
yield {
116+
type: 'STEP_TEXT',
117+
text: 'Failed to find chosen thinking output.',
118+
} satisfies StepText
119+
return
120+
}
121+
122+
yield {
123+
type: 'STEP_TEXT',
124+
text: chosenThought.content,
125+
} satisfies StepText
126+
127+
function extractSpawnResults<T>(
128+
results: any[] | undefined,
129+
): (T | { errorMessage: string })[] {
130+
if (!results) return []
131+
const spawnedResults = results
132+
.filter((result) => result.type === 'json')
133+
.map((result) => result.value)
134+
.flat() as {
135+
agentType: string
136+
value: { value?: T; errorMessage?: string }
137+
}[]
138+
return spawnedResults.map(
139+
(result) =>
140+
result.value.value ??
141+
({
142+
errorMessage:
143+
result.value.errorMessage ?? 'Error extracting spawn results',
144+
} as { errorMessage: string }),
145+
)
62146
}
63147
}
64148

65-
function* handleSteps({
149+
function* handleStepsOpus({
66150
agentState,
67151
prompt,
68152
params,
69153
}: AgentStepContext): ReturnType<
70154
NonNullable<SecretAgentDefinition['handleSteps']>
71155
> {
156+
const selectorAgentType = 'thinker-selector-opus'
72157
const n = Math.min(10, Math.max(1, (params?.n as number | undefined) ?? 5))
73158

74159
// Use GENERATE_N to generate n thinking outputs
@@ -90,7 +175,7 @@ function* handleSteps({
90175
input: {
91176
agents: [
92177
{
93-
agent_type: 'thinker-selector',
178+
agent_type: selectorAgentType,
94179
params: { thoughts },
95180
},
96181
],
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createThinkerSelector } from './thinker-selector'
2+
3+
const definition = {
4+
...createThinkerSelector('opus'),
5+
id: 'thinker-selector-opus',
6+
}
7+
8+
export default definition

.agents/thinker/best-of-n/thinker-selector.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
import { type SecretAgentDefinition } from '../../types/secret-agent-definition'
22
import { publisher } from '../../constants'
33

4-
const definition: SecretAgentDefinition = {
5-
id: 'thinker-selector',
6-
publisher,
7-
model: 'anthropic/claude-sonnet-4.5',
8-
displayName: 'Thinker Output Selector',
9-
spawnerPrompt: 'Analyzes multiple thinking outputs and selects the best one',
4+
export function createThinkerSelector(
5+
model: 'sonnet' | 'opus',
6+
): Omit<SecretAgentDefinition, 'id'> {
7+
const isOpus = model === 'opus'
8+
9+
return {
10+
publisher,
11+
model: isOpus
12+
? 'anthropic/claude-opus-4.5'
13+
: 'anthropic/claude-sonnet-4.5',
14+
displayName: isOpus
15+
? 'Opus Thinker Output Selector'
16+
: 'Thinker Output Selector',
17+
spawnerPrompt: 'Analyzes multiple thinking outputs and selects the best one',
1018

1119
includeMessageHistory: true,
1220
inheritParentSystemPrompt: true,
@@ -45,7 +53,7 @@ const definition: SecretAgentDefinition = {
4553
required: ['thoughtId'],
4654
},
4755

48-
instructionsPrompt: `As part of the best-of-n workflow for thinking agents, you are the thinking selector agent.
56+
instructionsPrompt: `As part of the best-of-n workflow for thinking agents, you are the thinking selector agent.
4957
5058
## Task Instructions
5159
@@ -74,6 +82,12 @@ Use <think> tags to briefly consider the thinking outputs as needed to pick the
7482
If the best one is obvious or the outputs are very similar, you may not need to think very much (a few words suffice) or you may not need to use think tags at all, just pick the best one and output it. You have a dual goal of picking the best thinking and being fast (using as few words as possible).
7583
7684
Then, do not write any other explanations AT ALL. You should directly output a single tool call to set_output with the selected thoughtId.`,
85+
}
86+
}
87+
88+
const definition: SecretAgentDefinition = {
89+
...createThinkerSelector('sonnet'),
90+
id: 'thinker-selector',
7791
}
7892

7993
export default definition

0 commit comments

Comments
 (0)