mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:40:44 +00:00
refactor: share chat content text coercion
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
parseApiErrorInfo,
|
||||
parseApiErrorPayload,
|
||||
} from "../../shared/assistant-error-format.js";
|
||||
import { coerceChatContentText } from "../../shared/chat-content.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalLowercaseString,
|
||||
@@ -300,33 +301,8 @@ function shouldRewriteRawPayloadWithoutErrorContext(raw: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
function coerceText(value: unknown): string {
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
if (
|
||||
typeof value === "number" ||
|
||||
typeof value === "boolean" ||
|
||||
typeof value === "bigint" ||
|
||||
typeof value === "symbol"
|
||||
) {
|
||||
return String(value);
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
try {
|
||||
return JSON.stringify(value) ?? "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function stripFinalTagsFromText(text: unknown): string {
|
||||
const normalized = coerceText(text);
|
||||
const normalized = coerceChatContentText(text);
|
||||
if (!normalized) {
|
||||
return normalized;
|
||||
}
|
||||
@@ -378,7 +354,7 @@ export function isLikelyHttpErrorText(raw: string): boolean {
|
||||
}
|
||||
|
||||
export function sanitizeUserFacingText(text: unknown, opts?: { errorContext?: boolean }): string {
|
||||
const raw = coerceText(text);
|
||||
const raw = coerceChatContentText(text);
|
||||
if (!raw) {
|
||||
return raw;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { parseReplyDirectives } from "../auto-reply/reply/reply-directives.js";
|
||||
import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
|
||||
import { emitAgentEvent } from "../infra/agent-events.js";
|
||||
import { createInlineCodeState } from "../markdown/code-spans.js";
|
||||
import { coerceChatContentText } from "../shared/chat-content.js";
|
||||
import {
|
||||
parseAssistantTextSignature,
|
||||
resolveAssistantMessagePhase,
|
||||
@@ -47,31 +48,6 @@ const stripTrailingDirective = (text: string): string => {
|
||||
return text.slice(0, openIndex);
|
||||
};
|
||||
|
||||
const coerceText = (value: unknown): string => {
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
if (
|
||||
typeof value === "number" ||
|
||||
typeof value === "boolean" ||
|
||||
typeof value === "bigint" ||
|
||||
typeof value === "symbol"
|
||||
) {
|
||||
return String(value);
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
try {
|
||||
return JSON.stringify(value) ?? "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
function shouldSuppressAssistantVisibleOutput(message: AgentMessage | undefined): boolean {
|
||||
return resolveAssistantMessagePhase(message) === "commentary";
|
||||
}
|
||||
@@ -189,12 +165,12 @@ export function resolveSilentReplyFallbackText(params: {
|
||||
text: unknown;
|
||||
messagingToolSentTexts: string[];
|
||||
}): string {
|
||||
const text = coerceText(params.text);
|
||||
const text = coerceChatContentText(params.text);
|
||||
const trimmed = text.trim();
|
||||
if (trimmed !== SILENT_REPLY_TOKEN) {
|
||||
return text;
|
||||
}
|
||||
const fallback = coerceText(params.messagingToolSentTexts.at(-1)).trim();
|
||||
const fallback = coerceChatContentText(params.messagingToolSentTexts.at(-1)).trim();
|
||||
if (!fallback) {
|
||||
return text;
|
||||
}
|
||||
@@ -397,7 +373,9 @@ export function handleMessageUpdate(
|
||||
if (deliveryPhase === "commentary") {
|
||||
return;
|
||||
}
|
||||
const phaseAwareVisibleText = coerceText(extractAssistantVisibleText(partialAssistant)).trim();
|
||||
const phaseAwareVisibleText = coerceChatContentText(
|
||||
extractAssistantVisibleText(partialAssistant),
|
||||
).trim();
|
||||
const shouldUsePhaseAwareBlockReply = Boolean(deliveryPhase);
|
||||
|
||||
if (chunk) {
|
||||
@@ -543,8 +521,8 @@ export function handleMessageEnd(
|
||||
}
|
||||
promoteThinkingTagsToBlocks(assistantMessage);
|
||||
|
||||
const rawText = coerceText(extractAssistantText(assistantMessage));
|
||||
const rawVisibleText = coerceText(extractAssistantVisibleText(assistantMessage));
|
||||
const rawText = coerceChatContentText(extractAssistantText(assistantMessage));
|
||||
const rawVisibleText = coerceChatContentText(extractAssistantVisibleText(assistantMessage));
|
||||
appendRawStream({
|
||||
ts: Date.now(),
|
||||
event: "assistant_message_end",
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
export function coerceChatContentText(value: unknown): string {
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
if (
|
||||
typeof value === "number" ||
|
||||
typeof value === "boolean" ||
|
||||
typeof value === "bigint" ||
|
||||
typeof value === "symbol"
|
||||
) {
|
||||
return String(value);
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
try {
|
||||
return JSON.stringify(value) ?? "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
export function extractTextFromChatContent(
|
||||
content: unknown,
|
||||
opts?: {
|
||||
@@ -8,36 +33,13 @@ export function extractTextFromChatContent(
|
||||
): string | null {
|
||||
const normalizeText = opts?.normalizeText ?? ((text: string) => text.replace(/\s+/g, " ").trim());
|
||||
const joinWith = opts?.joinWith ?? " ";
|
||||
const coerceText = (value: unknown): string => {
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
if (
|
||||
typeof value === "number" ||
|
||||
typeof value === "boolean" ||
|
||||
typeof value === "bigint" ||
|
||||
typeof value === "symbol"
|
||||
) {
|
||||
return String(value);
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
try {
|
||||
return JSON.stringify(value) ?? "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
};
|
||||
const sanitize = (text: unknown): string => {
|
||||
const raw = coerceText(text);
|
||||
const raw = coerceChatContentText(text);
|
||||
const sanitized = opts?.sanitizeText ? opts.sanitizeText(raw) : raw;
|
||||
return coerceText(sanitized);
|
||||
return coerceChatContentText(sanitized);
|
||||
};
|
||||
const normalize = (text: unknown): string => coerceText(normalizeText(coerceText(text)));
|
||||
const normalize = (text: unknown): string =>
|
||||
coerceChatContentText(normalizeText(coerceChatContentText(text)));
|
||||
|
||||
if (typeof content === "string") {
|
||||
const value = sanitize(content);
|
||||
|
||||
Reference in New Issue
Block a user