Skip to content

Commit 74b7758

Browse files
committed
typecheck for tool call strings
1 parent 30d237e commit 74b7758

File tree

10 files changed

+38
-25
lines changed

10 files changed

+38
-25
lines changed

backend/src/__tests__/main-prompt.integration.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ describe.skip('mainPrompt (Integration)', () => {
8383
},
8484
}
8585

86-
8786
spyOn(websocketAction, 'requestToolCall').mockImplementation(
8887
async (
8988
ws: WebSocket,
@@ -349,7 +348,7 @@ export function getMessagesSubset(messages: Message[], otherTokens: number) {
349348
{
350349
role: 'assistant',
351350
content: getToolCallString('read_files', {
352-
paths: 'src/util/messages.ts',
351+
paths: ['src/util/messages.ts'],
353352
}),
354353
},
355354
{
@@ -434,7 +433,7 @@ export function getMessagesSubset(messages: Message[], otherTokens: number) {
434433
{
435434
role: 'assistant',
436435
content: getToolCallString('read_files', {
437-
paths: 'packages/backend/src/index.ts',
436+
paths: ['packages/backend/src/index.ts'],
438437
}),
439438
},
440439
{

backend/src/templates/base-prompts.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,21 @@ ${getToolCallString('read_files', { paths: ['src/components/foo.tsx'] })}
115115
116116
Now, I'll add the console.log at the beginning of the Foo component:
117117
118-
${getToolCallString('write_file', {
118+
${getToolCallString('str_replace', {
119119
path: 'src/components/foo.tsx',
120-
content: `// ... existing code ...
121-
function Foo(props: {
122-
bar: string
120+
replacements: [
121+
{
122+
old: `function Foo(props: {
123+
bar: string
123124
}) {
124-
console.log("Foo props:", props);
125-
// ... rest of the function ...
126-
}
127-
// ... existing code ...
128125
`,
126+
new: `function Foo(props: {
127+
bar: string
128+
})
129+
console.log("Foo props:", props);
130+
`,
131+
},
132+
],
129133
})}
130134
131135
Let me check my changes

backend/src/tools/definitions/tool/find-files.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const findFilesTool = {
88
description: `
99
Example:
1010
${getToolCallString(toolName, {
11-
description: 'The implementation of function foo',
11+
prompt: 'The implementation of function foo',
1212
})}
1313
1414
Purpose: Better fulfill the user request by reading files which could contain information relevant to the user's request.

backend/src/tools/definitions/tool/send-agent-message.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ Example:
1818
${getToolCallString(toolName, {
1919
target_agent_id: 'PARENT_ID',
2020
prompt: 'Found 5 authentication-related files',
21-
params: JSON.stringify({
21+
params: {
2222
files: ['src/auth.ts', 'src/login.ts'],
2323
confidence: 0.9,
24-
}),
24+
},
2525
})}
2626
`.trim(),
2727
} satisfies ToolDescription

backend/src/tools/definitions/tool/spawn-agents-async.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Prefer to use spawn_agents unless you really need this ability to spawn asynchro
1414
1515
Example:
1616
${getToolCallString(toolName, {
17-
agents: JSON.stringify([
17+
agents: [
1818
{
1919
agent_type: 'file_picker',
2020
prompt: 'Find files related to authentication',
@@ -24,7 +24,7 @@ ${getToolCallString(toolName, {
2424
prompt: 'Research best practices for user authentication',
2525
params: { keywords: ['authentication', 'nextjs', 'auth0'] },
2626
},
27-
]),
27+
],
2828
})}
2929
`.trim(),
3030
} satisfies ToolDescription

backend/src/tools/definitions/tool/spawn-agents.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ The prompt field is a simple string, while params is a JSON object that gets val
1212
1313
Example:
1414
${getToolCallString(toolName, {
15-
agents: JSON.stringify([
15+
agents: [
1616
{
1717
agent_type: 'planner',
1818
prompt: 'Create a plan for implementing user authentication',
1919
params: { filePaths: ['src/auth.ts', 'src/user.ts'] },
2020
},
21-
]),
21+
],
2222
})}
2323
`.trim(),
2424
} satisfies ToolDescription

backend/src/tools/prompts.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,14 @@ However, **DO NOT** narrate the tool or parameter names themselves.
9696
User: can you update the console logs in example/file.ts?
9797
Assistant: Sure thing! Let's update that file!
9898
99-
${getToolCallString('write_file', {
99+
${getToolCallString('str_replace', {
100100
path: 'path/to/example/file.ts',
101-
instructions: 'Update the console logs',
102-
content: "console.log('Hello from Buffy!');",
101+
replacements: [
102+
{
103+
old: "console.log('Hello world!');\n",
104+
new: "console.log('Hello from Buffy!');\n",
105+
},
106+
],
103107
})}
104108
105109
All done with the update!

common/src/tools/utils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ import { llmToolCallSchema } from './list'
88
import { closeXml } from '../util/xml'
99

1010
import type { StringToolResultPart, ToolName } from './constants'
11+
import type z from 'zod/v4'
1112

1213
export function getToolCallString<T extends ToolName | (string & {})>(
1314
toolName: T,
14-
params: Record<string, any>,
15+
params: T extends ToolName
16+
? z.input<(typeof llmToolCallSchema)[T]['parameters']>
17+
: Record<string, any>,
1518
...endsAgentStep: T extends ToolName ? [] : [boolean]
1619
): string {
1720
const endsAgentStepValue =

npm-app/src/utils/__tests__/tool-renderers.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,13 @@ describe('Tool renderers with XML parser', () => {
5555
const xml = getToolCallString('write_file', {
5656
path: 'test.ts',
5757
content: 'console.log("test");\n',
58+
instructions: 'add a console.log statement',
5859
})
5960
const output = await processXML(xml)
6061
const stripped = stripAnsi(output)
61-
expect(stripped).toBe('\n\n[Write File]\nEditing file at test.ts...\n\n')
62+
expect(stripped).toBe(
63+
'\n\n[Write File]\nEditing file at test.ts...\nadd a console.log statement\n\n',
64+
)
6265
})
6366

6467
test('formats read_files tool call', async () => {

npm-app/src/utils/__tests__/xml-stream-parser.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('createXMLStreamParser', () => {
4747
test('handles multiple tool calls in sequence', async () => {
4848
const xml =
4949
getToolCallString('run_terminal_command', { command: 'ls' }) +
50-
getToolCallString('read_files', { paths: 'file.txt' })
50+
getToolCallString('read_files', { paths: ['file.txt'] })
5151
let result = ''
5252

5353
const processor = createXMLStreamParser(toolRenderers)
@@ -78,7 +78,7 @@ describe('createXMLStreamParser', () => {
7878
const xml =
7979
getToolCallString('run_terminal_command', { command: 'ls' }) +
8080
'Some text between tool calls' +
81-
getToolCallString('read_files', { paths: 'file.txt' })
81+
getToolCallString('read_files', { paths: ['file.txt'] })
8282
let result = ''
8383

8484
const processor = createXMLStreamParser(toolRenderers)

0 commit comments

Comments
 (0)