Agents: strip leaked function-call preludes from assistant text

This commit is contained in:
Alexander Davydov 2026-03-16 10:55:01 +03:00
parent 704f76e53a
commit dcee753a02
2 changed files with 26 additions and 4 deletions

View File

@ -329,6 +329,24 @@ Arguments: { "command": "git status", "timeout": 120000 }`,
expect(result).toBe("");
});
it("strips leaked assistant function-call preludes while preserving user text", () => {
const msg = makeAssistantMessage({
role: "assistant",
content: [
{
type: "text",
text: 'assistant function callrecipient{The task "setup openclaw" has been successfully added to Things. Let me know if you need further assistance!',
},
],
timestamp: Date.now(),
});
const result = extractAssistantText(msg);
expect(result).toBe(
'The task "setup openclaw" has been successfully added to Things. Let me know if you need further assistance!',
);
});
it("strips multiple downgraded tool calls", () => {
const msg = makeAssistantMessage({
role: "assistant",

View File

@ -69,9 +69,8 @@ export function stripDowngradedToolCallText(text: string): string {
if (!text) {
return text;
}
if (!/\[Tool (?:Call|Result)/i.test(text) && !/\[Historical context/i.test(text)) {
return text;
}
const stripLeakedFunctionCallPrelude = (input: string): string =>
input.replace(/^\s*assistant\s+function\s+call\s*([A-Za-z0-9_.:/-]+)\s*\{\s*/i, "");
const consumeJsonish = (
input: string,
@ -157,6 +156,11 @@ export function stripDowngradedToolCallText(text: string): string {
return end;
};
let cleaned = stripLeakedFunctionCallPrelude(text);
if (!/\[Tool (?:Call|Result)/i.test(cleaned) && !/\[Historical context/i.test(cleaned)) {
return cleaned.trim();
}
const stripToolCalls = (input: string): string => {
const markerRe = /\[Tool Call:[^\]]*\]/gi;
let result = "";
@ -213,7 +217,7 @@ export function stripDowngradedToolCallText(text: string): string {
};
// Remove [Tool Call: name (ID: ...)] blocks and their Arguments.
let cleaned = stripToolCalls(text);
cleaned = stripToolCalls(cleaned);
// Remove [Tool Result for ID ...] blocks and their content.
cleaned = cleaned.replace(/\[Tool Result for ID[^\]]*\]\n?[\s\S]*?(?=\n*\[Tool |\n*$)/gi, "");