Skip to content

Commit ee4dde9

Browse files
committed
fix: file update tool results
1 parent 2f3d493 commit ee4dde9

File tree

5 files changed

+133
-42
lines changed

5 files changed

+133
-42
lines changed

backend/src/run-agent-step.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ import { countTokensJson } from './util/token-counter'
3636
import { getRequestContext } from './websockets/request-context'
3737

3838
import type { AgentResponseTrace } from '@codebuff/bigquery'
39-
import type { CodebuffToolMessage } from '@codebuff/common/tools/list'
39+
import type {
40+
CodebuffToolMessage,
41+
CodebuffToolOutput,
42+
} from '@codebuff/common/tools/list'
4043
import type { AgentTemplate } from '@codebuff/common/types/agent-template'
4144
import type {
4245
AssistantMessage,
@@ -195,7 +198,7 @@ export const runAgentStep = async (
195198
),
196199
},
197200
},
198-
],
201+
] satisfies CodebuffToolOutput<'file_updates'>,
199202
})
200203
}
201204

backend/src/util/messages.ts

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -297,36 +297,71 @@ export function getPreviouslyReadFiles(messages: Message[]): {
297297
content: string
298298
referencedBy?: Record<string, string[]>
299299
}[] {
300-
return buildArray(
301-
messages
302-
.filter(
303-
(
304-
m,
305-
): m is ToolMessage & {
306-
content: { toolName: 'read_files' }
307-
} =>
308-
m.role === 'tool' &&
309-
(m.content.toolName === 'read_files' ||
310-
m.content.toolName === 'find_files' ||
311-
m.content.toolName === 'file_updates'),
312-
)
313-
.map((m) => {
314-
try {
315-
return (
316-
m as CodebuffToolMessage<'read_files'>
317-
).content.output[0].value.map((file) => {
318-
if ('contentOmittedForLength' in file) {
319-
return undefined
320-
}
321-
return file
322-
})
323-
} catch (error) {
324-
logger.error(
325-
{ error: errorToObject(error), m },
326-
'Error parsing read_files output from message',
327-
)
328-
return []
300+
const files: ReturnType<typeof getPreviouslyReadFiles> = []
301+
for (const message of messages) {
302+
if (message.role !== 'tool') continue
303+
if (message.content.toolName === 'read_files') {
304+
try {
305+
files.push(
306+
...(
307+
message as CodebuffToolMessage<'read_files'>
308+
).content.output[0].value.filter(
309+
(
310+
file,
311+
): file is typeof file & { contentOmittedForLength: undefined } =>
312+
!('contentOmittedForLength' in file),
313+
),
314+
)
315+
} catch (error) {
316+
logger.error(
317+
{ error: errorToObject(error), message },
318+
'Error parsing read_files output from message',
319+
)
320+
}
321+
}
322+
323+
if (message.content.toolName === 'find_files') {
324+
try {
325+
const v = (message as CodebuffToolMessage<'find_files'>).content
326+
.output[0].value
327+
if ('message' in v) {
328+
continue
329329
}
330-
}),
331-
)
330+
files.push(
331+
...v.filter(
332+
(
333+
file,
334+
): file is typeof file & { contentOmittedForLength: undefined } =>
335+
!('contentOmittedForLength' in file),
336+
),
337+
)
338+
} catch (error) {
339+
logger.error(
340+
{ error: errorToObject(error), message },
341+
'Error parsing find_files output from message',
342+
)
343+
}
344+
}
345+
346+
if (message.content.toolName === 'file_updates') {
347+
try {
348+
files.push(
349+
...(
350+
message as CodebuffToolMessage<'file_updates'>
351+
).content.output[0].value.files.filter(
352+
(
353+
file,
354+
): file is typeof file & { contentOmittedForLength: undefined } =>
355+
!('contentOmittedForLength' in file),
356+
),
357+
)
358+
} catch (error) {
359+
logger.error(
360+
{ error: errorToObject(error), message },
361+
'Error parsing find_files output from message',
362+
)
363+
}
364+
}
365+
}
366+
return files
332367
}

common/src/tools/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,8 @@ export type $ToolParams<T extends ToolName = ToolName> = {
7171
parameters: z.ZodType
7272
outputs: z.ZodType<ToolResultOutput[]>
7373
}
74+
75+
export type $ToolResults = {
76+
toolName: string
77+
outputs: $ToolParams['outputs']
78+
}

common/src/tools/list.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { browserLogsParams } from './params/tool/browser-logs'
77
import { codeSearchParams } from './params/tool/code-search'
88
import { createPlanParams } from './params/tool/create-plan'
99
import { endTurnParams } from './params/tool/end-turn'
10+
import { fileUpdatesResultSchema } from './params/tool/file-updates'
1011
import { findFilesParams } from './params/tool/find-files'
1112
import { readDocsParams } from './params/tool/read-docs'
1213
import { readFilesParams } from './params/tool/read-files'
@@ -23,7 +24,12 @@ import { updateSubgoalParams } from './params/tool/update-subgoal'
2324
import { webSearchParams } from './params/tool/web-search'
2425
import { writeFileParams } from './params/tool/write-file'
2526

26-
import type { ToolName, $ToolParams, PublishedToolName } from './constants'
27+
import type {
28+
$ToolParams,
29+
$ToolResults,
30+
PublishedToolName,
31+
ToolName,
32+
} from './constants'
2733
import type { ToolMessage } from '../types/messages/codebuff-message'
2834
import type {
2935
ToolCallPart,
@@ -56,6 +62,11 @@ export const $toolParams = {
5662
[K in ToolName]: $ToolParams<K>
5763
}
5864

65+
export const additionalToolResultSchemas = {
66+
file_updates: fileUpdatesResultSchema,
67+
} satisfies Record<string, $ToolResults>
68+
type ResultOnlyToolName = keyof typeof additionalToolResultSchemas
69+
5970
// Tool call from LLM
6071
export type CodebuffToolCall<T extends ToolName = ToolName> = {
6172
[K in ToolName]: {
@@ -64,19 +75,33 @@ export type CodebuffToolCall<T extends ToolName = ToolName> = {
6475
} & Omit<ToolCallPart, 'type'>
6576
}[T]
6677

67-
export type CodebuffToolOutput<T extends ToolName = ToolName> = {
68-
[K in ToolName]: z.infer<(typeof $toolParams)[K]['outputs']>
69-
}[T]
70-
export type CodebuffToolResult<T extends ToolName = ToolName> = {
71-
[K in ToolName]: {
78+
export type CodebuffToolOutput<
79+
T extends ToolName | ResultOnlyToolName = ToolName,
80+
> = T extends ToolName
81+
? {
82+
[K in ToolName]: z.infer<(typeof $toolParams)[K]['outputs']>
83+
}[T]
84+
: T extends ResultOnlyToolName
85+
? {
86+
[K in ResultOnlyToolName]: z.infer<
87+
(typeof additionalToolResultSchemas)[K]['outputs']
88+
>
89+
}[T]
90+
: never
91+
export type CodebuffToolResult<
92+
T extends ToolName | ResultOnlyToolName = ToolName,
93+
> = {
94+
[K in ToolName | ResultOnlyToolName]: {
7295
toolName: K
7396
output: CodebuffToolOutput<K>
7497
} & Omit<ToolResultPart, 'type'>
7598
}[T]
7699

77-
export type CodebuffToolMessage<T extends ToolName = ToolName> = ToolMessage &
100+
export type CodebuffToolMessage<
101+
T extends ToolName | ResultOnlyToolName = ToolName,
102+
> = ToolMessage &
78103
{
79-
[K in ToolName]: {
104+
[K in ToolName | ResultOnlyToolName]: {
80105
toolName: K
81106
content: {
82107
output: CodebuffToolOutput<K>
@@ -126,4 +151,4 @@ export type ClientToolCall<T extends ClientToolName = ClientToolName> = z.infer<
126151
typeof clientToolCallSchema
127152
> & { toolName: T } & Omit<ToolCallPart, 'type'>
128153

129-
export type PublishedClientToolName = ClientToolName & PublishedToolName
154+
export type PublishedClientToolName = ClientToolName & PublishedToolName
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import z from 'zod/v4'
2+
3+
import type { $ToolResults } from '../../../tools/constants'
4+
5+
const toolName = 'file_updates'
6+
export const fileUpdatesResultSchema = {
7+
toolName: toolName,
8+
outputs: z.tuple([
9+
z.object({
10+
type: z.literal('json'),
11+
value: z.object({
12+
message: z.string().optional(),
13+
files: z.array(
14+
z.object({
15+
path: z.string(),
16+
content: z.string(),
17+
referencedBy: z.record(z.string(), z.array(z.string())),
18+
}),
19+
),
20+
}),
21+
}),
22+
]),
23+
} as const satisfies $ToolResults

0 commit comments

Comments
 (0)