Skip to content

Commit 3d84015

Browse files
committed
Exclude tool call errors from last_message and all_messages subagent output
1 parent 011dee4 commit 3d84015

2 files changed

Lines changed: 33 additions & 13 deletions

File tree

packages/agent-runtime/src/tools/stream-parser.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,12 @@ export async function processStream(
114114
if (chunk.type === 'error') {
115115
hadToolCallError = true
116116
errorMessages.push(
117-
userMessage(
118-
withSystemTags(
117+
userMessage({
118+
content: withSystemTags(
119119
`Error during tool call: ${chunk.message}. Please check the tool name and arguments and try again.`,
120120
),
121-
),
121+
tags: ['TOOL_CALL_ERROR'],
122+
}),
122123
)
123124
}
124125
}
@@ -304,11 +305,12 @@ export async function processStream(
304305
onResponseChunk(chunk)
305306
hadToolCallError = true
306307
errorMessages.push(
307-
userMessage(
308-
withSystemTags(
308+
userMessage({
309+
content: withSystemTags(
309310
`Error during tool call: ${chunk.message}. Please check the tool name and arguments and try again.`,
310311
),
311-
),
312+
tags: ['TOOL_CALL_ERROR'],
313+
}),
312314
)
313315
} else if (chunk.type === 'tool-call') {
314316
} else {

packages/agent-runtime/src/util/agent-output.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,29 @@ import type {
55
AgentOutput,
66
} from '@codebuff/common/types/session-state'
77

8+
/** Messages tagged with these tags are stripped from agent output. */
9+
const EXCLUDED_OUTPUT_TAGS = ['TOOL_CALL_ERROR'] as const
10+
11+
function isExcludedFromOutput(message: Message): boolean {
12+
return !!message.tags?.some((t) =>
13+
(EXCLUDED_OUTPUT_TAGS as readonly string[]).includes(t),
14+
)
15+
}
16+
817
/**
9-
* Get the last assistant turn messages, which includes the last assistant message
10-
* and any subsequent tool messages that are responses to its tool calls.
18+
* Get the last assistant turn messages, which includes the last assistant
19+
* message and any subsequent tool messages that are responses to its tool
20+
* calls.
21+
*
22+
* Turn selection walks the raw `messageHistory` so that user-role messages
23+
* (including synthesized TOOL_CALL_ERROR ones) correctly bound the turn —
24+
* otherwise a failed attempt + its retry would get conflated into a single
25+
* "turn". Exclusion filtering is applied *after* selection: TOOL_CALL_ERROR
26+
* messages are user-role so they never enter `result` anyway (the role check
27+
* below stops at user messages), but keeping the filter explicit documents
28+
* the contract that no excluded tags leak into agent output.
1129
*/
1230
function getLastAssistantTurnMessages(messageHistory: Message[]): Message[] {
13-
// Find the index of the last assistant message
1431
let lastAssistantIndex = -1
1532
for (let i = messageHistory.length - 1; i >= 0; i--) {
1633
if (messageHistory[i].role === 'assistant') {
@@ -29,19 +46,18 @@ function getLastAssistantTurnMessages(messageHistory: Message[]): Message[] {
2946
return []
3047
}
3148

32-
// Collect the assistant message and all subsequent tool messages
3349
const result: Message[] = []
3450
for (let i = lastAssistantIndex; i < messageHistory.length; i++) {
3551
const message = messageHistory[i]
3652
if (message.role === 'assistant' || message.role === 'tool') {
3753
result.push(message)
3854
} else {
39-
// Stop if we hit a user or system message
55+
// Stop if we hit a user or system message.
4056
break
4157
}
4258
}
4359

44-
return result
60+
return result.filter((m) => !isExcludedFromOutput(m))
4561
}
4662

4763
export function getAgentOutput(
@@ -71,7 +87,9 @@ export function getAgentOutput(
7187
}
7288
if (agentTemplate.outputMode === 'all_messages') {
7389
// Remove the first message, which includes the previous conversation history.
74-
const agentMessages = agentState.messageHistory.slice(1)
90+
const agentMessages = agentState.messageHistory
91+
.slice(1)
92+
.filter((m) => !isExcludedFromOutput(m))
7593
return {
7694
type: 'allMessages',
7795
value: agentMessages,

0 commit comments

Comments
 (0)