fix: sanitize tool call text in sessions-helpers extractAssistantText

Adds sanitization to extractAssistantText in sessions-helpers.ts to
prevent tool call text from leaking to users. Previously, messages
retrieved from chat history via sessions-helpers.ts could expose:

- Minimax XML tool calls (<invoke>...</invoke>)
- Downgraded tool call markers ([Tool Call: name (ID: ...)])
- Thinking tags (<think>...</think>)

This fix:
- Exports the stripping functions from pi-embedded-utils.ts
- Adds a new sanitizeTextContent helper in sessions-helpers.ts
- Updates extractAssistantText to sanitize before returning
- Updates extractMessageText in commands-subagents.ts to sanitize

Fixes #1269

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zerone0x
2026-01-23 01:03:54 +08:00
committed by Peter Steinberger
parent 6779ba2367
commit 03bec49299
3 changed files with 34 additions and 10 deletions

View File

@@ -1,4 +1,10 @@
import type { ClawdbotConfig } from "../../config/config.js";
import { sanitizeUserFacingText } from "../pi-embedded-helpers.js";
import {
stripDowngradedToolCallText,
stripMinimaxToolCallXml,
stripThinkingTagsFromText,
} from "../pi-embedded-utils.js";
import { normalizeMainKey } from "../../routing/session-key.js";
export type SessionKind = "main" | "group" | "cron" | "hook" | "node" | "other";
@@ -100,6 +106,16 @@ export function stripToolMessages(messages: unknown[]): unknown[] {
});
}
/**
* Sanitize text content to strip tool call markers and thinking tags.
* This ensures user-facing text doesn't leak internal tool representations.
*/
export function sanitizeTextContent(text: string): string {
return stripThinkingTagsFromText(
stripDowngradedToolCallText(stripMinimaxToolCallXml(text)),
).trim();
}
export function extractAssistantText(message: unknown): string | undefined {
if (!message || typeof message !== "object") return undefined;
if ((message as { role?: unknown }).role !== "assistant") return undefined;
@@ -110,10 +126,13 @@ export function extractAssistantText(message: unknown): string | undefined {
if (!block || typeof block !== "object") continue;
if ((block as { type?: unknown }).type !== "text") continue;
const text = (block as { text?: unknown }).text;
if (typeof text === "string" && text.trim()) {
chunks.push(text);
if (typeof text === "string") {
const sanitized = sanitizeTextContent(text);
if (sanitized) {
chunks.push(sanitized);
}
}
}
const joined = chunks.join("").trim();
return joined ? joined : undefined;
const joined = chunks.join("\n").trim();
return joined ? sanitizeUserFacingText(joined) : undefined;
}