Skip to content

Commit 52075d6

Browse files
authored
Base 2!! (#244)
1 parent ef1cb6c commit 52075d6

18 files changed

+1076
-320
lines changed

.agents/base2/base2-factory.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { publisher } from '../constants'
2+
3+
import type { SecretAgentDefinition } from '../types/secret-agent-definition'
4+
import type { ModelName } from 'types/agent-definition'
5+
6+
export const base2 = (model: ModelName): Omit<SecretAgentDefinition, 'id'> => ({
7+
publisher,
8+
model,
9+
displayName: 'Base Agent v2',
10+
spawnerPrompt:
11+
'Advanced base agent that orchestrates planning, editing, and reviewing for complex coding tasks',
12+
inputSchema: {
13+
prompt: {
14+
type: 'string',
15+
description: 'A coding task to complete',
16+
},
17+
params: {
18+
type: 'object',
19+
properties: {
20+
maxContextLength: {
21+
type: 'number',
22+
},
23+
},
24+
required: [],
25+
},
26+
},
27+
outputMode: 'last_message',
28+
includeMessageHistory: true,
29+
toolNames: [
30+
'spawn_agents',
31+
'spawn_agent_inline',
32+
'run_terminal_command',
33+
'end_turn',
34+
],
35+
spawnableAgents: ['planner', 'editor', 'reviewer', 'context-pruner'],
36+
37+
systemPrompt: `You are a strategic base agent that orchestrates complex coding tasks through specialized sub-agents.
38+
39+
Your approach:
40+
1. **Planning Phase**: For complex tasks, spawn planner to create a comprehensive plan
41+
2. **Implementation Phase**: Spawn editor to implement the changes
42+
3. **Review Phase**: Spawn reviewer to validate and provide feedback
43+
44+
For trivial changes, you may skip planning and go directly to editing.
45+
46+
- You coordinate between agents but do not implement code yourself.
47+
- You are concise in your responses.`,
48+
49+
instructionsPrompt: `Orchestrate the completion of the coding task using your specialized sub-agents.
50+
51+
Workflow:
52+
1. Assess if the task is complex enough to require planning: if it's not a trivial change, you should spawn planner
53+
2. Spawn editor to implement the changes
54+
3. Spawn reviewer to validate the implementation
55+
4. Iterate if needed based on feedback by calling the editor again, or if you need to make significant changes, spawn the planner again
56+
57+
When prompting an agent, realize that they can already see the entire conversation history, so you can be brief on what they should do.
58+
`,
59+
60+
stepPrompt:
61+
'Continue orchestrating the task (spawn planner => editor => reviewer, iterate with editor if needed) or end turn when complete.',
62+
63+
handleSteps: function* ({ prompt, params }) {
64+
while (true) {
65+
// Run context-pruner before each step
66+
yield {
67+
toolName: 'spawn_agent_inline',
68+
input: {
69+
agent_type: 'context-pruner',
70+
params: params ?? {},
71+
},
72+
} as any
73+
74+
const { stepsComplete } = yield 'STEP'
75+
if (stepsComplete) break
76+
}
77+
},
78+
})

.agents/base2/base2.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { publisher } from '../constants'
2+
import { base2 } from './base2-factory'
3+
4+
import type { SecretAgentDefinition } from '../types/secret-agent-definition'
5+
6+
const definition: SecretAgentDefinition = {
7+
id: 'base2',
8+
publisher,
9+
...base2('anthropic/claude-4-sonnet-20250522'),
10+
}
11+
12+
export default definition

.agents/base2/editor.ts

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import { publisher } from '../constants'
2+
3+
import type { SecretAgentDefinition } from '../types/secret-agent-definition'
4+
5+
const editor: SecretAgentDefinition = {
6+
id: 'editor',
7+
publisher,
8+
model: 'anthropic/claude-4-sonnet-20250522',
9+
displayName: 'Code Editor',
10+
spawnerPrompt:
11+
'Expert code editor that reads files first, then implements changes with high precision. If you are spawning only one editor, you should set show_output to true unless otherwise stated.',
12+
inputSchema: {
13+
prompt: {
14+
type: 'string',
15+
description: 'The coding task to implement',
16+
},
17+
params: {
18+
type: 'object',
19+
properties: {
20+
maxContextLength: {
21+
type: 'number',
22+
},
23+
},
24+
required: [],
25+
},
26+
},
27+
outputMode: 'structured_output',
28+
includeMessageHistory: true,
29+
toolNames: [
30+
'read_files',
31+
'write_file',
32+
'str_replace',
33+
'run_terminal_command',
34+
'code_search',
35+
'spawn_agents',
36+
'add_message',
37+
'set_output',
38+
'end_turn',
39+
],
40+
spawnableAgents: ['file-explorer'],
41+
42+
systemPrompt: `You are an expert code editor with deep understanding of software engineering principles.
43+
44+
You are extremely skilled at:
45+
- Reading and understanding existing codebases
46+
- Making surgical code changes
47+
- Following established patterns
48+
- Ensuring code quality and correctness
49+
- Never duplicating existing code and always reusing existing code when possible
50+
- Making the minimal change necessary to implement the user request
51+
`,
52+
53+
instructionsPrompt: `Implement the requested coding changes with precision, especially following any plans that have been provided.
54+
55+
Workflow:
56+
1. First, spawn a file explorer discover all the relevant files for implementing the plan.
57+
2. Read all relevant files to understand the current state. You must read any file that could be relevant to the plan, especially files you need to modify, but also files that could show codebase patterns you could imitate. Try to read all the files in a single tool call. E.g. use read_files on 20 different files.
58+
3. Implement the changes using str_replace or write_file.
59+
4. End turn when complete.
60+
61+
Principles:
62+
- Read before you write
63+
- Make minimal changes
64+
- Follow existing patterns
65+
- Ensure correctness
66+
- IMPORTANT: Make as few changes as possible to satisfy the user request!
67+
- IMPORTANT: When you edit files, you must make all your edits in a single message. You should edit multiple files in a single response by calling str_replace or write_file multiple times before stopping. Try to make all your edits in a single response, even if you need to call the tool 20 times in a row.`,
68+
69+
handleSteps: function* ({ agentState: initialAgentState }) {
70+
const stepLimit = 15
71+
let stepCount = 0
72+
let agentState = initialAgentState
73+
74+
while (true) {
75+
stepCount++
76+
77+
const stepResult = yield 'STEP'
78+
agentState = stepResult.agentState // Capture the latest state
79+
80+
if (stepResult.stepsComplete) {
81+
break
82+
}
83+
84+
// If we've reached within one of the step limit, ask LLM to summarize progress
85+
if (stepCount === stepLimit - 1) {
86+
yield {
87+
toolName: 'add_message',
88+
input: {
89+
role: 'user',
90+
content:
91+
'You have reached the step limit. Please summarize your progress so far, what you still need to solve, and provide any insights that could help complete the remaining work. Please end your turn after producing this summary with the end_turn tool.',
92+
},
93+
}
94+
95+
// One final step to produce the summary
96+
const finalStepResult = yield 'STEP'
97+
agentState = finalStepResult.agentState
98+
break
99+
}
100+
}
101+
102+
// Collect all the edits from the conversation
103+
const { messageHistory } = agentState
104+
const editToolResults: string[] = []
105+
for (const message of messageHistory) {
106+
if (
107+
message.role === 'user' &&
108+
message.content.includes('<tool_result>')
109+
) {
110+
// Parse out tool results for write_file and str_replace
111+
const writeFileMatches = message.content.match(
112+
/<tool_result>\s*<tool>write_file<\/tool>\s*<result>([\s\S]*?)<\/result>\s*<\/tool_result>/g,
113+
)
114+
const strReplaceMatches = message.content.match(
115+
/<tool_result>\s*<tool>str_replace<\/tool>\s*<result>([\s\S]*?)<\/result>\s*<\/tool_result>/g,
116+
)
117+
118+
// Extract inner <result> content from write_file matches
119+
if (writeFileMatches) {
120+
for (const match of writeFileMatches) {
121+
const resultMatch = match.match(/<result>([\s\S]*?)<\/result>/)
122+
if (resultMatch) {
123+
editToolResults.push(resultMatch[1])
124+
}
125+
}
126+
}
127+
128+
// Extract inner <result> content from str_replace matches
129+
if (strReplaceMatches) {
130+
for (const match of strReplaceMatches) {
131+
const resultMatch = match.match(/<result>([\s\S]*?)<\/result>/)
132+
if (resultMatch) {
133+
editToolResults.push(resultMatch[1])
134+
}
135+
}
136+
}
137+
}
138+
}
139+
const lastAssistantMessage =
140+
messageHistory.findLast((message) => message.role === 'assistant')
141+
?.content ?? ''
142+
143+
yield {
144+
toolName: 'set_output',
145+
input: {
146+
message: lastAssistantMessage,
147+
edits: editToolResults,
148+
},
149+
}
150+
},
151+
}
152+
153+
export default editor

.agents/base2/planner.ts

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { ToolCall } from 'types/agent-definition'
2+
import { publisher } from '../constants'
3+
import {
4+
PLACEHOLDER,
5+
type SecretAgentDefinition,
6+
} from '../types/secret-agent-definition'
7+
8+
const planner: SecretAgentDefinition = {
9+
id: 'planner',
10+
publisher,
11+
12+
model: 'google/gemini-2.5-pro',
13+
displayName: 'Peter Plan',
14+
spawnerPrompt:
15+
'Creates comprehensive plans by exploring the codebase and deep thinking',
16+
inputSchema: {
17+
prompt: {
18+
type: 'string',
19+
description: 'The coding task to plan for',
20+
},
21+
},
22+
outputMode: 'last_message',
23+
includeMessageHistory: true,
24+
toolNames: ['spawn_agents', 'end_turn'],
25+
spawnableAgents: ['file-explorer', 'researcher', 'gemini-thinker-high'],
26+
27+
systemPrompt: `You are a strategic planner who creates comprehensive plans for coding tasks.
28+
You should spawn agents to help you gather information and think through the problem before creating your plan.
29+
${PLACEHOLDER.FILE_TREE_PROMPT}
30+
${PLACEHOLDER.KNOWLEDGE_FILES_CONTENTS}`,
31+
32+
instructionsPrompt: `Create a comprehensive plan for the given coding task.
33+
34+
Process:
35+
1. First, spawn a file-explorer to understand the relevant codebase. You may also spawn a researcher to search the web for relevant information at the same time.
36+
2. Then spawn a thinker to analyze the best approach
37+
3. Finally, write out a plan that focuses on the high level approach to the task, with short excerpts of code/types that help
38+
39+
Your plan should be specific, actionable, and account for the current codebase structure.`,
40+
41+
handleSteps: function* ({ prompt }) {
42+
// Step 1: Spawn file-explorer and parse out the file paths
43+
const { agentState: stateAfterFileExplorer } = yield 'STEP'
44+
const { messageHistory } = stateAfterFileExplorer
45+
const lastAssistantMessageIndex =
46+
stateAfterFileExplorer.messageHistory.findLastIndex(
47+
(message) => message.role === 'assistant',
48+
)
49+
const toolResultMessage = messageHistory[lastAssistantMessageIndex + 1] ?? {
50+
content: '',
51+
}
52+
const filePaths = parseFilePathsFromToolResult(toolResultMessage.content)
53+
54+
// Step 2: Read the files
55+
yield {
56+
toolName: 'read_files',
57+
input: {
58+
paths: filePaths,
59+
},
60+
} satisfies ToolCall
61+
62+
// Step 3: Spawn deep-thinker to analyze approach
63+
const { toolResult: deepThinkerToolResult } = yield {
64+
toolName: 'spawn_agents',
65+
input: {
66+
agents: [
67+
{
68+
agent_type: 'gemini-thinker-high',
69+
prompt: `Create a clear implementation plan for the following task, with a focus on simplicity and making the minimal changes necessary for an awesome implementation. Prompt: ${prompt}`,
70+
},
71+
],
72+
},
73+
}
74+
75+
yield {
76+
toolName: 'set_output',
77+
input: {
78+
plan: deepThinkerToolResult,
79+
},
80+
}
81+
82+
function parseFilePathsFromToolResult(content: string): string[] {
83+
const filePaths: string[] = []
84+
85+
// Match file paths that look like valid paths (containing / and file extensions)
86+
const filePathRegex =
87+
/(?:^|\s|\*\s*)((?:[\w-]+\/)*[\w.-]+\.[a-zA-Z]{1,4})(?=\s|$|,|\.|:)/gm
88+
89+
let match
90+
while ((match = filePathRegex.exec(content)) !== null) {
91+
const filePath = match[1]
92+
// Filter out obvious false positives and ensure reasonable path structure
93+
if (
94+
filePath &&
95+
!filePath.startsWith('http') &&
96+
!filePath.includes('@') &&
97+
filePath.length > 3 &&
98+
filePath.split('/').length <= 10
99+
) {
100+
filePaths.push(filePath)
101+
}
102+
}
103+
104+
// Also look for backtick-quoted file paths
105+
const backtickPathRegex = /`([^`]+\.[a-zA-Z]{1,4})`/g
106+
while ((match = backtickPathRegex.exec(content)) !== null) {
107+
const filePath = match[1]
108+
if (
109+
filePath &&
110+
!filePath.startsWith('http') &&
111+
!filePath.includes('@')
112+
) {
113+
filePaths.push(filePath)
114+
}
115+
}
116+
117+
// Remove duplicates and return
118+
return [...new Set(filePaths)]
119+
}
120+
},
121+
}
122+
123+
export default planner

0 commit comments

Comments
 (0)