Skip to content

Commit eacc976

Browse files
committed
Propose str_replace / write_file
1 parent 03c1d9c commit eacc976

File tree

12 files changed

+1088
-1
lines changed

12 files changed

+1088
-1
lines changed

.agents/types/tools.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export type ToolName =
1010
| 'glob'
1111
| 'list_directory'
1212
| 'lookup_agent_info'
13+
| 'propose_str_replace'
14+
| 'propose_write_file'
1315
| 'read_docs'
1416
| 'read_files'
1517
| 'read_subtree'
@@ -38,6 +40,8 @@ export interface ToolParamsMap {
3840
glob: GlobParams
3941
list_directory: ListDirectoryParams
4042
lookup_agent_info: LookupAgentInfoParams
43+
propose_str_replace: ProposeStrReplaceParams
44+
propose_write_file: ProposeWriteFileParams
4145
read_docs: ReadDocsParams
4246
read_files: ReadFilesParams
4347
read_subtree: ReadSubtreeParams
@@ -149,6 +153,35 @@ export interface LookupAgentInfoParams {
149153
agentId: string
150154
}
151155

156+
/**
157+
* Propose string replacements in a file without actually applying them.
158+
*/
159+
export interface ProposeStrReplaceParams {
160+
/** The path to the file to edit. */
161+
path: string
162+
/** Array of replacements to make. */
163+
replacements: {
164+
/** The string to replace. This must be an *exact match* of the string you want to replace, including whitespace and punctuation. */
165+
old: string
166+
/** The string to replace the corresponding old string with. Can be empty to delete. */
167+
new: string
168+
/** Whether to allow multiple replacements of old string. */
169+
allowMultiple?: boolean
170+
}[]
171+
}
172+
173+
/**
174+
* Propose creating or editing a file without actually applying the changes.
175+
*/
176+
export interface ProposeWriteFileParams {
177+
/** Path to the file relative to the **project root** */
178+
path: string
179+
/** What the change is intended to do in only one sentence. */
180+
instructions: string
181+
/** Edit snippet to apply to the file. */
182+
content: string
183+
}
184+
152185
/**
153186
* Fetch up-to-date documentation for libraries and frameworks using Context7 API.
154187
*/

common/src/tools/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export const toolNames = [
3131
'glob',
3232
'list_directory',
3333
'lookup_agent_info',
34+
'propose_str_replace',
35+
'propose_write_file',
3436
'read_docs',
3537
'read_files',
3638
'read_subtree',

common/src/tools/list.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { findFilesParams } from './params/tool/find-files'
1212
import { globParams } from './params/tool/glob'
1313
import { listDirectoryParams } from './params/tool/list-directory'
1414
import { lookupAgentInfoParams } from './params/tool/lookup-agent-info'
15+
import { proposeStrReplaceParams } from './params/tool/propose-str-replace'
16+
import { proposeWriteFileParams } from './params/tool/propose-write-file'
1517
import { readDocsParams } from './params/tool/read-docs'
1618
import { readFilesParams } from './params/tool/read-files'
1719
import { readSubtreeParams } from './params/tool/read-subtree'
@@ -46,6 +48,8 @@ export const toolParams = {
4648
glob: globParams,
4749
list_directory: listDirectoryParams,
4850
lookup_agent_info: lookupAgentInfoParams,
51+
propose_str_replace: proposeStrReplaceParams,
52+
propose_write_file: proposeWriteFileParams,
4953
read_docs: readDocsParams,
5054
read_files: readFilesParams,
5155
read_subtree: readSubtreeParams,
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import z from 'zod/v4'
2+
3+
import { $getNativeToolCallExampleString, jsonToolResultSchema } from '../utils'
4+
5+
import type { $ToolParams } from '../../constants'
6+
7+
export const proposeUpdateFileResultSchema = z.union([
8+
z.object({
9+
file: z.string(),
10+
message: z.string(),
11+
unifiedDiff: z.string(),
12+
}),
13+
z.object({
14+
file: z.string(),
15+
errorMessage: z.string(),
16+
}),
17+
])
18+
19+
const toolName = 'propose_str_replace'
20+
const endsAgentStep = false
21+
const inputSchema = z
22+
.object({
23+
path: z
24+
.string()
25+
.min(1, 'Path cannot be empty')
26+
.describe(`The path to the file to edit.`),
27+
replacements: z
28+
.array(
29+
z
30+
.object({
31+
old: z
32+
.string()
33+
.min(1, 'Old cannot be empty')
34+
.describe(
35+
`The string to replace. This must be an *exact match* of the string you want to replace, including whitespace and punctuation.`,
36+
),
37+
new: z
38+
.string()
39+
.describe(
40+
`The string to replace the corresponding old string with. Can be empty to delete.`,
41+
),
42+
allowMultiple: z
43+
.boolean()
44+
.optional()
45+
.default(false)
46+
.describe(
47+
'Whether to allow multiple replacements of old string.',
48+
),
49+
})
50+
.describe('Pair of old and new strings.'),
51+
)
52+
.min(1, 'Replacements cannot be empty')
53+
.describe('Array of replacements to make.'),
54+
})
55+
.describe(`Propose string replacements in a file without actually applying them.`)
56+
const description = `
57+
Propose edits to a file without actually applying them. Use this tool when you want to draft changes that will be reviewed before being applied.
58+
59+
This tool works identically to str_replace but the changes are not written to disk. Instead, it returns the unified diff of what would change. Multiple propose calls on the same file will stack correctly.
60+
61+
Example:
62+
${$getNativeToolCallExampleString({
63+
toolName,
64+
inputSchema,
65+
input: {
66+
path: 'path/to/file',
67+
replacements: [
68+
{ old: 'This is the old string', new: 'This is the new string' },
69+
{
70+
old: '\nfoo:',
71+
new: '\nbar:',
72+
allowMultiple: true,
73+
},
74+
],
75+
},
76+
endsAgentStep,
77+
})}
78+
`.trim()
79+
80+
export const proposeStrReplaceParams = {
81+
toolName,
82+
endsAgentStep,
83+
description,
84+
inputSchema,
85+
outputSchema: jsonToolResultSchema(proposeUpdateFileResultSchema),
86+
} satisfies $ToolParams
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import z from 'zod/v4'
2+
3+
import { proposeUpdateFileResultSchema } from './propose-str-replace'
4+
import { $getNativeToolCallExampleString, jsonToolResultSchema } from '../utils'
5+
6+
import type { $ToolParams } from '../../constants'
7+
8+
const toolName = 'propose_write_file'
9+
const endsAgentStep = false
10+
const inputSchema = z
11+
.object({
12+
path: z
13+
.string()
14+
.min(1, 'Path cannot be empty')
15+
.describe(`Path to the file relative to the **project root**`),
16+
instructions: z
17+
.string()
18+
.describe('What the change is intended to do in only one sentence.'),
19+
content: z.string().describe(`Complete file content to write to the file.`),
20+
})
21+
.describe(
22+
`Propose creating or editing a file without actually applying the changes.`,
23+
)
24+
const description = `
25+
Propose creating or editing a file without actually applying the changes.
26+
27+
This tool works identically to write_file but the changes are not written to disk. Instead, it returns the unified diff of what would change. Each call overwrites the previous call.
28+
29+
Format the \`content\` parameter with the entire content of the file.
30+
31+
This tool is to be used in subagents.
32+
33+
Example - Simple file creation:
34+
${$getNativeToolCallExampleString({
35+
toolName,
36+
inputSchema,
37+
input: {
38+
path: 'new-file.ts',
39+
instructions: 'Prints Hello, world',
40+
content: 'console.log("Hello, world!");',
41+
},
42+
endsAgentStep,
43+
})}
44+
45+
Example - Overwriting a file:
46+
${$getNativeToolCallExampleString({
47+
toolName,
48+
inputSchema,
49+
input: {
50+
path: 'foo.ts',
51+
instructions: 'Update foo function',
52+
content: `function foo() {
53+
doSomethingNew();
54+
}
55+
56+
function bar() {
57+
doSomethingOld();
58+
}
59+
`,
60+
},
61+
endsAgentStep,
62+
})}
63+
`.trim()
64+
65+
export const proposeWriteFileParams = {
66+
toolName,
67+
endsAgentStep,
68+
description,
69+
inputSchema,
70+
outputSchema: jsonToolResultSchema(proposeUpdateFileResultSchema),
71+
} satisfies $ToolParams

0 commit comments

Comments
 (0)