|
1 | 1 | // Heartbeat reply payload selector for multi-payload auto-reply results. |
2 | | -import { hasOutboundReplyContent } from "openclaw/plugin-sdk/reply-payload"; |
| 2 | +import { hasOutboundReplyContent, isReasoningReplyPayload } from "openclaw/plugin-sdk/reply-payload"; |
3 | 3 | import type { ReplyPayload } from "./types.js"; |
4 | 4 |
|
5 | | -// Formatted reasoning prefixes the heartbeat reasoning lane classifies as |
6 | | -// reasoning even when the `isReasoning` flag is absent: legacy "Reasoning:" |
7 | | -// text and blockquoted "Thinking..._". Kept in sync with |
8 | | -// resolveHeartbeatReasoningPayloads (heartbeat-runner) so the selector skips |
9 | | -// exactly the payloads the reasoning lane delivers separately. |
10 | | -const FORMATTED_REASONING_PREFIX = /^(?:Reasoning:|Thinking\.{0,3}(?=\s*_))/u; |
11 | | - |
12 | | -/** Whether text already carries a formatted reasoning prefix (legacy reasoning). */ |
13 | | -export function hasFormattedReasoningPrefix(text: string): boolean { |
14 | | - return FORMATTED_REASONING_PREFIX.test(text.trimStart()); |
15 | | -} |
16 | | - |
17 | | -/** |
18 | | - * Whether a payload is reasoning (flagged or legacy-formatted) and so must not |
19 | | - * become the user-visible heartbeat reply. |
20 | | - */ |
21 | | -export function isReasoningReplyPayload(payload: ReplyPayload): boolean { |
22 | | - if (payload.isReasoning === true) { |
23 | | - return true; |
24 | | - } |
25 | | - const text = typeof payload.text === "string" ? payload.text : ""; |
26 | | - return hasFormattedReasoningPrefix(text); |
27 | | -} |
28 | | - |
29 | 5 | /** |
30 | 6 | * Pick the last outbound-capable reply payload for heartbeat delivery. |
31 | 7 | * |
32 | | - * Reasoning payloads are skipped: heartbeat reasoning is delivered separately |
33 | | - * and only when `includeReasoning` is enabled. Without this guard a trailing |
34 | | - * reasoning payload (flagged via `isReasoning` or legacy "Reasoning:" / |
35 | | - * blockquoted "Thinking" text, which reasoning models can emit after the final |
36 | | - * answer) would be selected as the user-visible heartbeat reply. |
| 8 | + * Reasoning payloads are skipped using the shared SDK classifier |
| 9 | + * `isReasoningReplyPayload`, which recognizes the `isReasoning` flag plus the |
| 10 | + * common reasoning/thinking text prefixes (including lowercased and Markdown |
| 11 | + * blockquoted forms). Heartbeat reasoning is delivered separately and only when |
| 12 | + * `includeReasoning` is enabled; without this guard a trailing reasoning |
| 13 | + * payload (which reasoning models can emit after the final answer) would be |
| 14 | + * selected as the user-visible heartbeat reply. |
37 | 15 | */ |
38 | 16 | export function resolveHeartbeatReplyPayload( |
39 | 17 | replyResult: ReplyPayload | ReplyPayload[] | undefined, |
|
0 commit comments