From e2ea20f86255df6b4a8a28469232fa8c05f88b3a Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 13 Jan 2026 00:36:39 +0000 Subject: [PATCH] fix: gate minimax XML stripping (#809) (thanks @latitudeki5223) --- CHANGELOG.md | 2 +- src/agents/pi-embedded-utils.test.ts | 34 ++++++++++++++++++++++++++++ src/agents/pi-embedded-utils.ts | 11 +++++---- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfc082ccf..5c0501029 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ - Sandbox: support tool-policy groups in `tools.sandbox.tools` (e.g. `group:memory`, `group:fs`) to reduce config churn. ### Fixes -- Models/MiniMax: strip malformed tool invocation XML (`...` and ``) from assistant text to prevent tool call leaks into user messages. +- Models/MiniMax: strip malformed tool invocation XML (`...` and ``) from assistant text to prevent tool call leaks into user messages. (#809 — thanks @latitudeki5223) - Tools/Models: MiniMax vision now uses the Coding Plan VLM endpoint (`/v1/coding_plan/vlm`) so the `image` tool works with MiniMax keys (also accepts `@/path/to/file.png`-style inputs). - Gateway/macOS: reduce noisy loopback WS "closed before connect" logs during tests. - Auto-reply: resolve ambiguous `/model` fuzzy matches by picking the best candidate instead of erroring. diff --git a/src/agents/pi-embedded-utils.test.ts b/src/agents/pi-embedded-utils.test.ts index 9d9ce2cc7..2b32c1466 100644 --- a/src/agents/pi-embedded-utils.test.ts +++ b/src/agents/pi-embedded-utils.test.ts @@ -41,6 +41,24 @@ describe("extractAssistantText", () => { expect(result).toBe("Let me check that."); }); + it("keeps invoke snippets without Minimax markers", () => { + const msg: AssistantMessage = { + role: "assistant", + content: [ + { + type: "text", + text: `Example:\n\nls\n`, + }, + ], + timestamp: Date.now(), + }; + + const result = extractAssistantText(msg); + expect(result).toBe( + `Example:\n\nls\n`, + ); + }); + it("preserves normal text without tool invocations", () => { const msg: AssistantMessage = { role: "assistant", @@ -57,6 +75,22 @@ describe("extractAssistantText", () => { expect(result).toBe("This is a normal response without any tool calls."); }); + it("strips Minimax tool invocations with extra attributes", () => { + const msg: AssistantMessage = { + role: "assistant", + content: [ + { + type: "text", + text: `Before\nls\n\nAfter`, + }, + ], + timestamp: Date.now(), + }; + + const result = extractAssistantText(msg); + expect(result).toBe("Before\nAfter"); + }); + it("strips tool XML mixed with regular content", () => { const msg: AssistantMessage = { role: "assistant", diff --git a/src/agents/pi-embedded-utils.ts b/src/agents/pi-embedded-utils.ts index c3b2d9234..19e7afd62 100644 --- a/src/agents/pi-embedded-utils.ts +++ b/src/agents/pi-embedded-utils.ts @@ -10,14 +10,15 @@ import { formatToolDetail, resolveToolDisplay } from "./tool-display.js"; */ function stripMinimaxToolCallXml(text: string): string { if (!text) return text; + if (!/minimax:tool_call/i.test(text)) return text; - // Remove ... blocks (non-greedy to handle multiple) - let cleaned = text.replace(/[\s\S]*?<\/invoke>/gi, ""); + // Remove ... blocks (non-greedy to handle multiple). + let cleaned = text.replace(/]*>[\s\S]*?<\/invoke>/gi, ""); - // Remove stray tags - cleaned = cleaned.replace(/<\/minimax:tool_call>/gi, ""); + // Remove stray minimax tool tags. + cleaned = cleaned.replace(/<\/?minimax:tool_call>/gi, ""); - return cleaned.trim(); + return cleaned; } export function extractAssistantText(msg: AssistantMessage): string {