mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:50:43 +00:00
fix(agents): strip antml thinking tags in streaming
This commit is contained in:
@@ -13,6 +13,7 @@ export const THINKING_TAG_CASES = [
|
||||
{ tag: "thinking", open: "<thinking>", close: "</thinking>" },
|
||||
{ tag: "thought", open: "<thought>", close: "</thought>" },
|
||||
{ tag: "antthinking", open: "<antthinking>", close: "</antthinking>" },
|
||||
{ tag: "antml:thinking", open: "<antml:thinking>", close: "</antml:thinking>" },
|
||||
] as const;
|
||||
|
||||
export function createStubSessionHarness(): {
|
||||
|
||||
@@ -36,7 +36,8 @@ import type { SubscribeEmbeddedPiSessionParams } from "./pi-embedded-subscribe.t
|
||||
import { formatReasoningMessage, stripDowngradedToolCallText } from "./pi-embedded-utils.js";
|
||||
import { hasNonzeroUsage, normalizeUsage, type UsageLike } from "./usage.js";
|
||||
|
||||
const THINKING_TAG_SCAN_RE = /<\s*(\/?)\s*(?:think(?:ing)?|thought|antthinking)\s*>/gi;
|
||||
const THINKING_TAG_SCAN_RE =
|
||||
/<\s*(\/?)\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/gi;
|
||||
const FINAL_TAG_SCAN_RE = /<\s*(\/?)\s*final\s*>/gi;
|
||||
const log = createSubsystemLogger("agent/embedded");
|
||||
|
||||
|
||||
@@ -806,6 +806,20 @@ describe("promoteThinkingTagsToBlocks", () => {
|
||||
expect(types).toContain("text");
|
||||
});
|
||||
|
||||
it("splits antml namespaced thinking tags into thinking blocks", () => {
|
||||
const msg = makeAssistantMessage({
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "<antml:thinking>hidden</antml:thinking>Visible" }],
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
promoteThinkingTagsToBlocks(msg);
|
||||
expect(msg.content).toEqual([
|
||||
{ type: "thinking", thinking: "hidden" },
|
||||
{ type: "text", text: "Visible" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not crash on undefined content entries", () => {
|
||||
const msg = makeAssistantMessage({
|
||||
role: "assistant",
|
||||
|
||||
@@ -189,8 +189,8 @@ export function splitThinkingTaggedText(text: string): ThinkTaggedSplitBlock[] |
|
||||
if (!trimmedStart.startsWith("<")) {
|
||||
return null;
|
||||
}
|
||||
const openRe = /<\s*(?:think(?:ing)?|thought|antthinking)\s*>/i;
|
||||
const closeRe = /<\s*\/\s*(?:think(?:ing)?|thought|antthinking)\s*>/i;
|
||||
const openRe = /<\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/i;
|
||||
const closeRe = /<\s*\/\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/i;
|
||||
if (!openRe.test(trimmedStart)) {
|
||||
return null;
|
||||
}
|
||||
@@ -198,7 +198,7 @@ export function splitThinkingTaggedText(text: string): ThinkTaggedSplitBlock[] |
|
||||
return null;
|
||||
}
|
||||
|
||||
const scanRe = /<\s*(\/?)\s*(?:think(?:ing)?|thought|antthinking)\s*>/gi;
|
||||
const scanRe = /<\s*(\/?)\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/gi;
|
||||
let inThinking = false;
|
||||
let cursor = 0;
|
||||
let thinkingStart = 0;
|
||||
@@ -299,7 +299,7 @@ export function extractThinkingFromTaggedText(text: string): string {
|
||||
if (!text) {
|
||||
return "";
|
||||
}
|
||||
const scanRe = /<\s*(\/?)\s*(?:think(?:ing)?|thought|antthinking)\s*>/gi;
|
||||
const scanRe = /<\s*(\/?)\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/gi;
|
||||
let result = "";
|
||||
let lastIndex = 0;
|
||||
let inThinking = false;
|
||||
@@ -324,8 +324,8 @@ export function extractThinkingFromTaggedStream(text: string): string {
|
||||
return closed;
|
||||
}
|
||||
|
||||
const openRe = /<\s*(?:think(?:ing)?|thought|antthinking)\s*>/gi;
|
||||
const closeRe = /<\s*\/\s*(?:think(?:ing)?|thought|antthinking)\s*>/gi;
|
||||
const openRe = /<\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/gi;
|
||||
const closeRe = /<\s*\/\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/gi;
|
||||
const openMatches = [...text.matchAll(openRe)];
|
||||
if (openMatches.length === 0) {
|
||||
return "";
|
||||
|
||||
Reference in New Issue
Block a user