Build: sync main manifests and harden Matrix reasoning suppression

This commit is contained in:
Gustavo Madeira Santana
2026-03-12 00:57:09 +00:00
parent 2f71349c03
commit 3d82e38d9d
6 changed files with 94 additions and 9 deletions

View File

@@ -137,6 +137,29 @@ describe("deliverMatrixReplies", () => {
);
});
it("suppresses reasoning-only text before Matrix sends", async () => {
await deliverMatrixReplies({
cfg,
replies: [
{ text: "Reasoning:\n_hidden_" },
{ text: "<think>still hidden</think>" },
{ text: "Visible answer" },
],
roomId: "room:5",
client: {} as MatrixClient,
runtime: runtimeEnv,
textLimit: 4000,
replyToMode: "off",
});
expect(sendMessageMatrixMock).toHaveBeenCalledTimes(1);
expect(sendMessageMatrixMock).toHaveBeenCalledWith(
"room:5",
"Visible answer",
expect.objectContaining({ cfg }),
);
});
it("uses supplied cfg for chunking and send delivery without reloading runtime config", async () => {
const explicitCfg = {
channels: {

View File

@@ -8,6 +8,31 @@ import { getMatrixRuntime } from "../../runtime.js";
import type { MatrixClient } from "../sdk.js";
import { sendMessageMatrix } from "../send.js";
const THINKING_TAG_RE = /<\s*\/?\s*(?:think(?:ing)?|thought|antthinking)\b[^<>]*>/gi;
const THINKING_BLOCK_RE =
/<\s*(?:think(?:ing)?|thought|antthinking)\b[^<>]*>[\s\S]*?<\s*\/\s*(?:think(?:ing)?|thought|antthinking)\s*>/gi;
function shouldSuppressReasoningReplyText(text?: string): boolean {
if (typeof text !== "string") {
return false;
}
const trimmedStart = text.trimStart();
if (!trimmedStart) {
return false;
}
if (trimmedStart.toLowerCase().startsWith("reasoning:")) {
return true;
}
THINKING_TAG_RE.lastIndex = 0;
if (!THINKING_TAG_RE.test(text)) {
return false;
}
THINKING_BLOCK_RE.lastIndex = 0;
const withoutThinkingBlocks = text.replace(THINKING_BLOCK_RE, "");
THINKING_TAG_RE.lastIndex = 0;
return !withoutThinkingBlocks.replace(THINKING_TAG_RE, "").trim();
}
export async function deliverMatrixReplies(params: {
cfg: OpenClawConfig;
replies: ReplyPayload[];
@@ -37,6 +62,10 @@ export async function deliverMatrixReplies(params: {
const chunkMode = core.channel.text.resolveChunkMode(params.cfg, "matrix", params.accountId);
let hasReplied = false;
for (const reply of params.replies) {
if (reply.isReasoning === true || shouldSuppressReasoningReplyText(reply.text)) {
logVerbose("matrix reply suppressed as reasoning-only");
continue;
}
const hasMedia = Boolean(reply?.mediaUrl) || (reply?.mediaUrls?.length ?? 0) > 0;
if (!reply?.text && !hasMedia) {
if (reply?.audioAsVoice) {