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 {