Skip to content

Commit 1d36bdf

Browse files
committed
fix: reuse shared heartbeat reasoning detection
1 parent a48c176 commit 1d36bdf

3 files changed

Lines changed: 14 additions & 6 deletions

File tree

src/auto-reply/heartbeat-reply-payload.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ describe("resolveHeartbeatReplyPayload", () => {
2121
finalPayload,
2222
{ text: "Reasoning:\n_private details_" },
2323
{ text: "Thinking\n\n_private details_" },
24+
{ text: "> reasoning:\n> _private details_" },
2425
]),
2526
).toBe(finalPayload);
2627
});
@@ -34,6 +35,9 @@ describe("resolveHeartbeatReplyPayload", () => {
3435
expect(resolveHeartbeatReplyPayload(reasoningPayload)).toBeUndefined();
3536
expect(resolveHeartbeatReplyPayload([reasoningPayload])).toBeUndefined();
3637
expect(resolveHeartbeatReplyPayload({ text: "Reasoning:\n_private details_" })).toBeUndefined();
38+
expect(
39+
resolveHeartbeatReplyPayload({ text: "> thinking\n> _private details_" }),
40+
).toBeUndefined();
3741
});
3842

3943
it("continues scanning past empty and reasoning payloads", () => {

src/auto-reply/heartbeat-reply-payload.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
// Heartbeat reply payload selector for multi-payload auto-reply results.
2-
import { hasOutboundReplyContent } from "openclaw/plugin-sdk/reply-payload";
2+
import {
3+
hasOutboundReplyContent,
4+
isReasoningReplyPayload,
5+
} from "openclaw/plugin-sdk/reply-payload";
36
import type { ReplyPayload } from "./types.js";
47

5-
const HEARTBEAT_REASONING_PREFIX_PATTERN = /^(?:Reasoning:|Thinking\.{0,3}(?=\s*_))/u;
6-
78
export function hasHeartbeatReasoningPrefix(text: string): boolean {
8-
return HEARTBEAT_REASONING_PREFIX_PATTERN.test(text.trimStart());
9+
return isReasoningReplyPayload({ text });
910
}
1011

1112
export function isHeartbeatReasoningPayload(
1213
payload: Pick<ReplyPayload, "isReasoning" | "text">,
1314
): boolean {
14-
const text = typeof payload.text === "string" ? payload.text : "";
15-
return payload.isReasoning === true || hasHeartbeatReasoningPrefix(text);
15+
return isReasoningReplyPayload(payload);
1616
}
1717

1818
/** Pick the last non-reasoning outbound-capable reply payload for heartbeat delivery. */

src/infra/heartbeat-runner.returns-default-unset.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,10 @@ describe("runHeartbeatOnce", () => {
13631363
name: "legacy-prefixed reasoning after HEARTBEAT_OK",
13641364
replies: [{ text: "HEARTBEAT_OK" }, { text: "Reasoning:\n_Because it helps_" }],
13651365
},
1366+
{
1367+
name: "blockquoted reasoning after HEARTBEAT_OK",
1368+
replies: [{ text: "HEARTBEAT_OK" }, { text: "> reasoning:\n> _Because it helps_" }],
1369+
},
13661370
]),
13671371
)(
13681372
"does not deliver late reasoning payloads when includeReasoning is unset: $name",

0 commit comments

Comments
 (0)