@tencent-weixin/openclaw-weixin 2.4.3 → 2.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/CHANGELOG.zh_CN.md +34 -0
- package/dist/src/api/api.js +79 -4
- package/dist/src/api/api.js.map +1 -1
- package/dist/src/api/session-guard.js +3 -3
- package/dist/src/api/session-guard.js.map +1 -1
- package/dist/src/api/types.js +2 -0
- package/dist/src/api/types.js.map +1 -1
- package/dist/src/cdn/cdn-upload.js +3 -2
- package/dist/src/cdn/cdn-upload.js.map +1 -1
- package/dist/src/cdn/upload.js +12 -3
- package/dist/src/cdn/upload.js.map +1 -1
- package/dist/src/channel.js +7 -1
- package/dist/src/channel.js.map +1 -1
- package/dist/src/config/config-schema.js +1 -0
- package/dist/src/config/config-schema.js.map +1 -1
- package/dist/src/config/reply-progress.js +5 -0
- package/dist/src/config/reply-progress.js.map +1 -0
- package/dist/src/messaging/error-notice.js +1 -0
- package/dist/src/messaging/error-notice.js.map +1 -1
- package/dist/src/messaging/outbound-hooks.js +2 -0
- package/dist/src/messaging/outbound-hooks.js.map +1 -1
- package/dist/src/messaging/process-message.js +32 -7
- package/dist/src/messaging/process-message.js.map +1 -1
- package/dist/src/messaging/reply-progress-sender.js +93 -0
- package/dist/src/messaging/reply-progress-sender.js.map +1 -0
- package/dist/src/messaging/send.js +40 -2
- package/dist/src/messaging/send.js.map +1 -1
- package/dist/src/monitor/monitor.js +11 -8
- package/dist/src/monitor/monitor.js.map +1 -1
- package/npm-shrinkwrap.json +21848 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +7 -5
- package/src/api/api.ts +102 -4
- package/src/api/session-guard.ts +3 -3
- package/src/api/types.ts +18 -1
- package/src/cdn/cdn-upload.ts +8 -2
- package/src/cdn/upload.ts +14 -3
- package/src/channel.ts +7 -1
- package/src/config/config-schema.ts +1 -0
- package/src/config/reply-progress.ts +10 -0
- package/src/messaging/error-notice.ts +2 -0
- package/src/messaging/outbound-hooks.ts +4 -0
- package/src/messaging/process-message.ts +32 -7
- package/src/messaging/reply-progress-sender.ts +122 -0
- package/src/messaging/send-media.ts +1 -1
- package/src/messaging/send.ts +60 -7
- package/src/monitor/monitor.ts +12 -11
- package/dist/src/media/voice-outbound.js +0 -177
- package/dist/src/media/voice-outbound.js.map +0 -1
- package/dist/src/messaging/abort-fence.js +0 -70
- package/dist/src/messaging/abort-fence.js.map +0 -1
- package/dist/src/messaging/buttons.js +0 -117
- package/dist/src/messaging/buttons.js.map +0 -1
- package/dist/src/messaging/lane-key.js +0 -66
- package/dist/src/messaging/lane-key.js.map +0 -1
- package/dist/src/messaging/merged-record.js +0 -149
- package/dist/src/messaging/merged-record.js.map +0 -1
- package/dist/src/messaging/model-buttons.js +0 -182
- package/dist/src/messaging/model-buttons.js.map +0 -1
- package/dist/src/messaging/model-callback-handler.js +0 -133
- package/dist/src/messaging/model-callback-handler.js.map +0 -1
- package/dist/src/monitor/lane-scheduler.js +0 -46
- package/dist/src/monitor/lane-scheduler.js.map +0 -1
- package/dist/src/runtime.js +0 -54
- package/dist/src/runtime.js.map +0 -1
- package/dist/src/streaming/stream-pipeline.js +0 -431
- package/dist/src/streaming/stream-pipeline.js.map +0 -1
- package/dist/src/streaming/stream-session.js +0 -260
- package/dist/src/streaming/stream-session.js.map +0 -1
- package/dist/src/streaming/stream.js +0 -239
- package/dist/src/streaming/stream.js.map +0 -1
- package/dist/src/util/markdown-fences.js +0 -54
- package/dist/src/util/markdown-fences.js.map +0 -1
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared button normalisation helpers used by both the channel action handler
|
|
3
|
-
* (channel.ts) and the inbound message dispatch path (process-message.ts).
|
|
4
|
-
*/
|
|
5
|
-
import { logger } from "../util/logger.js";
|
|
6
|
-
import { findFenceSpanAt, parseFenceSpans } from "../util/markdown-fences.js";
|
|
7
|
-
/**
|
|
8
|
-
* Normalize a single button-like object to {text, callback_data, style?}.
|
|
9
|
-
* Handles field name variants: label→text, value/callbackData→callback_data.
|
|
10
|
-
*/
|
|
11
|
-
export function normalizeButtonObject(b) {
|
|
12
|
-
const text = String(b.text ?? b.label ?? "");
|
|
13
|
-
const callbackData = String(b.callback_data ?? b.callbackData ?? b.value ?? b.action ?? b.data ?? "");
|
|
14
|
-
if (!text && !callbackData)
|
|
15
|
-
return null;
|
|
16
|
-
const style = typeof b.style === "string" && b.style ? b.style : undefined;
|
|
17
|
-
return style
|
|
18
|
-
? { text, callback_data: callbackData, style }
|
|
19
|
-
: { text, callback_data: callbackData };
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Normalize any button-like value to the canonical [[{text, callback_data}]] format.
|
|
23
|
-
* Handles all known AI malformations:
|
|
24
|
-
* - [[{text, callback_data}]] → already correct
|
|
25
|
-
* - [{text, callback_data}] → flat array, wrap into single row
|
|
26
|
-
* - {text, callback_data} → single button object
|
|
27
|
-
* - {buttons: [...]} → unwrap .buttons
|
|
28
|
-
* - [{type:"button", label, value}] → normalize fields
|
|
29
|
-
*/
|
|
30
|
-
export function normalizeButtonsParam(raw) {
|
|
31
|
-
if (raw == null)
|
|
32
|
-
return undefined;
|
|
33
|
-
if (Array.isArray(raw)) {
|
|
34
|
-
if (raw.length === 0)
|
|
35
|
-
return undefined;
|
|
36
|
-
if (Array.isArray(raw[0])) {
|
|
37
|
-
return raw;
|
|
38
|
-
}
|
|
39
|
-
const flatButtons = raw.filter((b) => b != null && typeof b === "object" && !Array.isArray(b));
|
|
40
|
-
if (flatButtons.length === 0)
|
|
41
|
-
return undefined;
|
|
42
|
-
const row = flatButtons.map(normalizeButtonObject).filter(Boolean);
|
|
43
|
-
return row.length > 0 ? [row] : undefined;
|
|
44
|
-
}
|
|
45
|
-
if (typeof raw === "object") {
|
|
46
|
-
const obj = raw;
|
|
47
|
-
if (Array.isArray(obj.buttons)) {
|
|
48
|
-
return normalizeButtonsParam(obj.buttons);
|
|
49
|
-
}
|
|
50
|
-
const btn = normalizeButtonObject(obj);
|
|
51
|
-
return btn ? [[btn]] : undefined;
|
|
52
|
-
}
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Parse and strip the inline WEIXIN_BUTTONS marker from outbound text.
|
|
57
|
-
*
|
|
58
|
-
* Agents writing plain-text responses (deliver / cron / streaming) can embed
|
|
59
|
-
* buttons by appending a line of the form:
|
|
60
|
-
*
|
|
61
|
-
* WEIXIN_BUTTONS:[{"label":"Yes","value":"yes"},{"label":"No","value":"no"}]
|
|
62
|
-
*
|
|
63
|
-
* Returns:
|
|
64
|
-
* - `cleanText`: the original text with the marker line removed and any
|
|
65
|
-
* resulting extra blank lines collapsed.
|
|
66
|
-
* - `buttons`: the normalised button array (canonical [[{text,callback_data}]]
|
|
67
|
-
* form) ready to pass to sendMessageWeixin / sendFinalMessageWithStreamId,
|
|
68
|
-
* or undefined when no valid marker is found.
|
|
69
|
-
*/
|
|
70
|
-
const INLINE_BUTTONS_RE = /^WEIXIN_BUTTONS:(\[[\s\S]*?\])\s*$/gm;
|
|
71
|
-
export function parseInlineButtons(text) {
|
|
72
|
-
// Mirror openclaw core's MEDIA: handling: a marker that lives inside a
|
|
73
|
-
// fenced code block is treated as literal documentation, not a directive.
|
|
74
|
-
const fenceSpans = parseFenceSpans(text);
|
|
75
|
-
const re = new RegExp(INLINE_BUTTONS_RE.source, INLINE_BUTTONS_RE.flags);
|
|
76
|
-
let match;
|
|
77
|
-
while ((match = re.exec(text)) !== null) {
|
|
78
|
-
if (findFenceSpanAt(fenceSpans, match.index))
|
|
79
|
-
continue;
|
|
80
|
-
try {
|
|
81
|
-
const parsed = JSON.parse(match[1]);
|
|
82
|
-
const buttons = normalizeButtonsParam(parsed);
|
|
83
|
-
const cleanText = text
|
|
84
|
-
.replace(match[0], "")
|
|
85
|
-
.replace(/\n{3,}/g, "\n\n")
|
|
86
|
-
.trim();
|
|
87
|
-
logger.debug(`parseInlineButtons: extracted ${buttons?.length ?? 0} button rows from inline marker`);
|
|
88
|
-
return { cleanText, buttons };
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
logger.warn(`parseInlineButtons: JSON parse failed, keeping marker as-is`);
|
|
92
|
-
return { cleanText: text, buttons: undefined };
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return { cleanText: text, buttons: undefined };
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Unified outbound helper: strip any inline WEIXIN_BUTTONS marker from `text`
|
|
99
|
-
* and merge the resulting buttons with any explicitly-provided buttons.
|
|
100
|
-
*
|
|
101
|
-
* Explicit buttons always win over marker-parsed buttons — an agent that calls
|
|
102
|
-
* the `message` tool with a structured `buttons` param is making a more
|
|
103
|
-
* deliberate choice than one that embeds a marker in free-text.
|
|
104
|
-
*
|
|
105
|
-
* Every outbound entry point (sendText / sendMedia / sendPayload / handleAction
|
|
106
|
-
* / streaming deliver) should route text through this helper so the marker is
|
|
107
|
-
* never leaked to the wire regardless of which code path delivered it.
|
|
108
|
-
*/
|
|
109
|
-
export function resolveOutboundButtons(text, explicitButtons) {
|
|
110
|
-
const explicitNormalised = explicitButtons != null ? normalizeButtonsParam(explicitButtons) : undefined;
|
|
111
|
-
const { cleanText, buttons: inlineButtons } = parseInlineButtons(text);
|
|
112
|
-
return {
|
|
113
|
-
text: cleanText,
|
|
114
|
-
buttons: explicitNormalised ?? inlineButtons,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
//# sourceMappingURL=buttons.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"buttons.js","sourceRoot":"","sources":["../../../src/messaging/buttons.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE9E;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,CAA0B;IAE1B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,MAAM,CACzB,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,CACzE,CAAC;IACF,IAAI,CAAC,IAAI,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IACxC,MAAM,KAAK,GACT,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,OAAO,KAAK;QACV,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,KAAK,EAAE;QAC9C,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAY;IAChD,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC;IAElC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QACvC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1B,OAAO,GAAG,CAAC;QACb,CAAC;QACD,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAC5B,CAAC,CAAC,EAAgC,EAAE,CAClC,CAAC,IAAI,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAC1D,CAAC;QACF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC/C,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnE,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,GAA8B,CAAC;QAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,OAAO,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,GAAG,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;QACvC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACnC,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,iBAAiB,GAAG,sCAAsC,CAAC;AAEjE,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAI7C,uEAAuE;IACvE,0EAA0E;IAC1E,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACzE,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACxC,IAAI,eAAe,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC;YAAE,SAAS;QACvD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAE,CAAY,CAAC;YAChD,MAAM,OAAO,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,SAAS,GAAG,IAAI;iBACnB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;iBACrB,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;iBAC1B,IAAI,EAAE,CAAC;YACV,MAAM,CAAC,KAAK,CACV,iCAAiC,OAAO,EAAE,MAAM,IAAI,CAAC,iCAAiC,CACvF,CAAC;YACF,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;YAC3E,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;QACjD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAY,EACZ,eAAyB;IAEzB,MAAM,kBAAkB,GACtB,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC,qBAAqB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/E,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACvE,OAAO;QACL,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,kBAAkB,IAAI,aAAa;KAC7C,CAAC;AACJ,CAAC"}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { isAbortRequestText } from "openclaw/plugin-sdk/reply-runtime";
|
|
2
|
-
import { MessageItemType } from "../api/types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Lane key for Weixin message scheduling.
|
|
5
|
-
*
|
|
6
|
-
* Mirrors the Telegram channel's `getTelegramSequentialKey` (see
|
|
7
|
-
* extensions/telegram/src/sequential-key.ts in the openclaw main repo).
|
|
8
|
-
*
|
|
9
|
-
* Design:
|
|
10
|
-
* - Different users get different lane keys -> processed concurrently.
|
|
11
|
-
* - Same user, regular messages -> share `wx:<account>:<user>` lane,
|
|
12
|
-
* processed strictly in arrival order so AI replies, typing state and
|
|
13
|
-
* inbound session writes do not interleave.
|
|
14
|
-
* - Abort requests (e.g. "stop", "中止") are routed to a separate
|
|
15
|
-
* `wx:<account>:<user>:control` lane so they can run immediately even when
|
|
16
|
-
* the main lane is occupied by a long-running tool turn. The actual
|
|
17
|
-
* "stopping" is implemented via the abort-fence mechanism (see
|
|
18
|
-
* `abort-fence.ts`).
|
|
19
|
-
*/
|
|
20
|
-
function extractFirstTextBody(itemList) {
|
|
21
|
-
if (!itemList?.length)
|
|
22
|
-
return "";
|
|
23
|
-
for (const item of itemList) {
|
|
24
|
-
if (item.type === MessageItemType.TEXT && item.text_item?.text != null) {
|
|
25
|
-
return String(item.text_item.text);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return "";
|
|
29
|
-
}
|
|
30
|
-
/** Extract text body suitable for abort detection from an inbound message. */
|
|
31
|
-
export function extractTextBodyForLane(msg) {
|
|
32
|
-
return extractFirstTextBody(msg.item_list);
|
|
33
|
-
}
|
|
34
|
-
/** Returns true when the message text is an abort intent (stop / 中止 / ...). */
|
|
35
|
-
export function isWeixinAbortMessage(msg) {
|
|
36
|
-
const text = extractTextBodyForLane(msg);
|
|
37
|
-
if (!text)
|
|
38
|
-
return false;
|
|
39
|
-
return isAbortRequestText(text);
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Compute the lane key used by the per-key scheduler. Abort requests get the
|
|
43
|
-
* `:control` suffix to bypass the main lane.
|
|
44
|
-
*
|
|
45
|
-
* Note: the fallback `unknown` user happens for malformed payloads. Keep them
|
|
46
|
-
* on a shared lane so they cannot fan out and exhaust resources.
|
|
47
|
-
*/
|
|
48
|
-
export function getWeixinLaneKey(ctx) {
|
|
49
|
-
const userId = ctx.msg.from_user_id?.trim() || "unknown";
|
|
50
|
-
const baseKey = `wx:${ctx.accountId}:${userId}`;
|
|
51
|
-
if (isWeixinAbortMessage(ctx.msg)) {
|
|
52
|
-
return `${baseKey}:control`;
|
|
53
|
-
}
|
|
54
|
-
return baseKey;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Per-user fence key shared by all dispatches that should be aborted as a
|
|
58
|
-
* group when the user sends an abort. This is intentionally the *base* key
|
|
59
|
-
* (without `:control`) so that an abort dispatched on the control lane bumps
|
|
60
|
-
* the same generation that the long-running main-lane dispatch is checking.
|
|
61
|
-
*/
|
|
62
|
-
export function getWeixinFenceKey(ctx) {
|
|
63
|
-
const userId = ctx.msg.from_user_id?.trim() || "unknown";
|
|
64
|
-
return `wx:${ctx.accountId}:${userId}`;
|
|
65
|
-
}
|
|
66
|
-
//# sourceMappingURL=lane-key.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lane-key.js","sourceRoot":"","sources":["../../../src/messaging/lane-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGlD;;;;;;;;;;;;;;;;GAgBG;AAEH,SAAS,oBAAoB,CAAC,QAAwB;IACpD,IAAI,CAAC,QAAQ,EAAE,MAAM;QAAE,OAAO,EAAE,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC;YACvE,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,sBAAsB,CAAC,GAAkB;IACvD,OAAO,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC7C,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,oBAAoB,CAAC,GAAkB;IACrD,MAAM,IAAI,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAOD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAyB;IACxD,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IACzD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;IAChD,IAAI,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,GAAG,OAAO,UAAU,CAAC;IAC9B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAyB;IACzD,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IACzD,OAAO,MAAM,GAAG,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { MessageItemType } from "../api/types.js";
|
|
2
|
-
import { downloadMediaFromItem } from "../media/media-download.js";
|
|
3
|
-
import { logger } from "../util/logger.js";
|
|
4
|
-
const MAX_DEPTH = 5;
|
|
5
|
-
function formatTimestamp(ms) {
|
|
6
|
-
if (!ms)
|
|
7
|
-
return "";
|
|
8
|
-
const d = new Date(ms);
|
|
9
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
10
|
-
const date = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
11
|
-
const time = `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
12
|
-
const tz = new Intl.DateTimeFormat("en", { timeZoneName: "short" })
|
|
13
|
-
.formatToParts(d)
|
|
14
|
-
.find((p) => p.type === "timeZoneName")?.value ?? "";
|
|
15
|
-
return `${date} ${time}${tz ? ` ${tz}` : ""}`;
|
|
16
|
-
}
|
|
17
|
-
function formatSubItemContent(item) {
|
|
18
|
-
switch (item.type) {
|
|
19
|
-
case MessageItemType.TEXT:
|
|
20
|
-
return item.text_item?.text ?? "";
|
|
21
|
-
case MessageItemType.VOICE:
|
|
22
|
-
if (item.voice_item?.text)
|
|
23
|
-
return item.voice_item.text;
|
|
24
|
-
return undefined;
|
|
25
|
-
case MessageItemType.UNSUPPORTED:
|
|
26
|
-
return item.unsupported_item?.text || "[不支持的消息类型]";
|
|
27
|
-
default:
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
async function formatMediaContent(item, deps) {
|
|
32
|
-
const downloaded = await downloadMediaFromItem(item, {
|
|
33
|
-
cdnBaseUrl: deps.cdnBaseUrl,
|
|
34
|
-
saveMedia: deps.saveMedia,
|
|
35
|
-
log: deps.log,
|
|
36
|
-
errLog: deps.errLog,
|
|
37
|
-
label: "merged-record",
|
|
38
|
-
});
|
|
39
|
-
const filePath = downloaded.decryptedPicPath ??
|
|
40
|
-
downloaded.decryptedVideoPath ??
|
|
41
|
-
downloaded.decryptedFilePath ??
|
|
42
|
-
downloaded.decryptedVoicePath;
|
|
43
|
-
let text;
|
|
44
|
-
let mediaType;
|
|
45
|
-
switch (item.type) {
|
|
46
|
-
case MessageItemType.IMAGE:
|
|
47
|
-
text = filePath ? `` : "[图片]";
|
|
48
|
-
mediaType = "image/*";
|
|
49
|
-
break;
|
|
50
|
-
case MessageItemType.VIDEO:
|
|
51
|
-
text = filePath ? `[视频](${filePath})` : "[视频]";
|
|
52
|
-
mediaType = "video/mp4";
|
|
53
|
-
break;
|
|
54
|
-
case MessageItemType.FILE: {
|
|
55
|
-
const name = item.file_item?.file_name;
|
|
56
|
-
if (name && filePath)
|
|
57
|
-
text = `[${name}](${filePath})`;
|
|
58
|
-
else if (name)
|
|
59
|
-
text = `[文件: ${name}]`;
|
|
60
|
-
else if (filePath)
|
|
61
|
-
text = `[文件](${filePath})`;
|
|
62
|
-
else
|
|
63
|
-
text = "[文件]";
|
|
64
|
-
mediaType = downloaded.fileMediaType ?? "application/octet-stream";
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
case MessageItemType.VOICE:
|
|
68
|
-
text = filePath ? `[语音](${filePath})` : "[语音]";
|
|
69
|
-
mediaType = downloaded.voiceMediaType ?? "audio/wav";
|
|
70
|
-
break;
|
|
71
|
-
default:
|
|
72
|
-
text = "[不支持的消息]";
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
return { text, mediaPath: filePath, mediaType: filePath ? mediaType : undefined };
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Format a MergedRecordItem into a readable text body with nested structure.
|
|
79
|
-
*
|
|
80
|
-
* Each nesting level is represented by `│ ` prefixes. Media sub-items are
|
|
81
|
-
* downloaded via CDN; the body contains text placeholders (e.g. `[图片]`)
|
|
82
|
-
* while actual file paths are returned in `mediaPaths` / `mediaTypes`
|
|
83
|
-
* for populating `ctx.MediaPaths` / `ctx.MediaTypes`.
|
|
84
|
-
*/
|
|
85
|
-
export async function formatMergedRecordBody(record, deps, depth = 0) {
|
|
86
|
-
const title = record.title ?? "聊天记录";
|
|
87
|
-
const lines = [`[合并转发: ${title}]`];
|
|
88
|
-
const mediaPaths = [];
|
|
89
|
-
const mediaTypes = [];
|
|
90
|
-
if (depth >= MAX_DEPTH) {
|
|
91
|
-
lines.push("│ [嵌套层级过深,省略]");
|
|
92
|
-
return { body: lines.join("\n"), mediaPaths, mediaTypes };
|
|
93
|
-
}
|
|
94
|
-
for (const sub of record.sub_item_list ?? []) {
|
|
95
|
-
const nick = sub.from_nick_name ?? "未知";
|
|
96
|
-
const item = sub.item;
|
|
97
|
-
if (!item)
|
|
98
|
-
continue;
|
|
99
|
-
const ts = formatTimestamp(item.create_time_ms);
|
|
100
|
-
const header = ts ? `${nick} (${ts}):` : `${nick}:`;
|
|
101
|
-
if (item.type === MessageItemType.MERGED_RECORD && item.merged_record) {
|
|
102
|
-
lines.push(`│ ${header}`);
|
|
103
|
-
const nested = await formatMergedRecordBody(item.merged_record, deps, depth + 1);
|
|
104
|
-
for (const nestedLine of nested.body.split("\n")) {
|
|
105
|
-
lines.push(`│ ${nestedLine}`);
|
|
106
|
-
}
|
|
107
|
-
mediaPaths.push(...nested.mediaPaths);
|
|
108
|
-
mediaTypes.push(...nested.mediaTypes);
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
const syncContent = formatSubItemContent(item);
|
|
112
|
-
if (syncContent !== undefined) {
|
|
113
|
-
lines.push(`│ ${header}`);
|
|
114
|
-
for (const contentLine of syncContent.split("\n")) {
|
|
115
|
-
lines.push(`│ ${contentLine}`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
else if (item.type === MessageItemType.IMAGE ||
|
|
119
|
-
item.type === MessageItemType.VIDEO ||
|
|
120
|
-
item.type === MessageItemType.FILE ||
|
|
121
|
-
item.type === MessageItemType.VOICE) {
|
|
122
|
-
try {
|
|
123
|
-
const media = await formatMediaContent(item, deps);
|
|
124
|
-
lines.push(`│ ${header}`);
|
|
125
|
-
lines.push(`│ ${media.text}`);
|
|
126
|
-
if (media.mediaPath && media.mediaType) {
|
|
127
|
-
mediaPaths.push(media.mediaPath);
|
|
128
|
-
mediaTypes.push(media.mediaType);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
catch (err) {
|
|
132
|
-
logger.error(`merged-record: media format failed: ${String(err)}`);
|
|
133
|
-
lines.push(`│ ${header}`);
|
|
134
|
-
lines.push("│ [媒体加载失败]");
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
lines.push(`│ ${header}`);
|
|
139
|
-
lines.push("│ [不支持的消息]");
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
lines.push("│");
|
|
143
|
-
}
|
|
144
|
-
if (lines.length > 1 && lines[lines.length - 1] === "│") {
|
|
145
|
-
lines.pop();
|
|
146
|
-
}
|
|
147
|
-
return { body: lines.join("\n"), mediaPaths, mediaTypes };
|
|
148
|
-
}
|
|
149
|
-
//# sourceMappingURL=merged-record.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"merged-record.js","sourceRoot":"","sources":["../../../src/messaging/merged-record.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Model selection buttons for Weixin.
|
|
3
|
-
*
|
|
4
|
-
* Reuses the same mdl_* callback_data format as Telegram so that core
|
|
5
|
-
* helpers (buildModelsProviderData, formatModelsAvailableHeader) can be
|
|
6
|
-
* shared directly.
|
|
7
|
-
*
|
|
8
|
-
* Callback data patterns:
|
|
9
|
-
* - mdl_prov - show providers list
|
|
10
|
-
* - mdl_list_{prov}_{pg} - show models for provider (page N, 1-indexed)
|
|
11
|
-
* - mdl_sel_{provider/id} - select model
|
|
12
|
-
* - mdl_back - back to providers list
|
|
13
|
-
*/
|
|
14
|
-
const MODELS_PAGE_SIZE = 8;
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
// Callback data parsing
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
export function parseModelCallbackData(data) {
|
|
19
|
-
const trimmed = data.trim();
|
|
20
|
-
if (!trimmed.startsWith("mdl_"))
|
|
21
|
-
return null;
|
|
22
|
-
if (trimmed === "mdl_prov" || trimmed === "mdl_back") {
|
|
23
|
-
return { type: trimmed === "mdl_prov" ? "providers" : "back" };
|
|
24
|
-
}
|
|
25
|
-
const listMatch = trimmed.match(/^mdl_list_([a-z0-9_-]+)_(\d+)$/i);
|
|
26
|
-
if (listMatch) {
|
|
27
|
-
const [, provider, pageStr] = listMatch;
|
|
28
|
-
const page = Number.parseInt(pageStr ?? "1", 10);
|
|
29
|
-
if (provider && Number.isFinite(page) && page >= 1) {
|
|
30
|
-
return { type: "list", provider, page };
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
const selMatch = trimmed.match(/^mdl_sel_(.+)$/);
|
|
34
|
-
if (selMatch) {
|
|
35
|
-
const modelRef = selMatch[1];
|
|
36
|
-
if (modelRef) {
|
|
37
|
-
const slashIndex = modelRef.indexOf("/");
|
|
38
|
-
if (slashIndex > 0 && slashIndex < modelRef.length - 1) {
|
|
39
|
-
return {
|
|
40
|
-
type: "select",
|
|
41
|
-
provider: modelRef.slice(0, slashIndex),
|
|
42
|
-
model: modelRef.slice(slashIndex + 1),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
return { type: "select", model: modelRef };
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
// Keyboard builders
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
export function buildProviderKeyboard(providers) {
|
|
54
|
-
if (providers.length === 0)
|
|
55
|
-
return [];
|
|
56
|
-
const rows = [];
|
|
57
|
-
let currentRow = [];
|
|
58
|
-
for (const provider of providers) {
|
|
59
|
-
currentRow.push({
|
|
60
|
-
text: `${provider.id} (${provider.count})`,
|
|
61
|
-
callback_data: `mdl_list_${provider.id}_1`,
|
|
62
|
-
});
|
|
63
|
-
if (currentRow.length === 2) {
|
|
64
|
-
rows.push(currentRow);
|
|
65
|
-
currentRow = [];
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
if (currentRow.length > 0)
|
|
69
|
-
rows.push(currentRow);
|
|
70
|
-
return rows;
|
|
71
|
-
}
|
|
72
|
-
function truncateModelId(modelId, maxLen) {
|
|
73
|
-
if (modelId.length <= maxLen)
|
|
74
|
-
return modelId;
|
|
75
|
-
return `…${modelId.slice(-(maxLen - 1))}`;
|
|
76
|
-
}
|
|
77
|
-
export function buildModelsKeyboard(params) {
|
|
78
|
-
const { provider, models, currentModel, currentPage, totalPages, modelNames } = params;
|
|
79
|
-
const pageSize = params.pageSize ?? MODELS_PAGE_SIZE;
|
|
80
|
-
if (models.length === 0) {
|
|
81
|
-
return [[{ text: "<< Back", callback_data: "mdl_back" }]];
|
|
82
|
-
}
|
|
83
|
-
const rows = [];
|
|
84
|
-
const startIndex = (currentPage - 1) * pageSize;
|
|
85
|
-
const endIndex = Math.min(startIndex + pageSize, models.length);
|
|
86
|
-
const pageModels = models.slice(startIndex, endIndex);
|
|
87
|
-
for (const model of pageModels) {
|
|
88
|
-
const callbackData = `mdl_sel_${provider}/${model}`;
|
|
89
|
-
const isCurrentModel = currentModel
|
|
90
|
-
? currentModel.includes("/")
|
|
91
|
-
? currentModel === `${provider}/${model}`
|
|
92
|
-
: currentModel === model
|
|
93
|
-
: false;
|
|
94
|
-
const displayLabel = modelNames?.get(`${provider}/${model}`) ?? model;
|
|
95
|
-
const displayText = truncateModelId(displayLabel, 38);
|
|
96
|
-
const text = isCurrentModel ? `${displayText} ✓` : displayText;
|
|
97
|
-
rows.push([{ text, callback_data: callbackData }]);
|
|
98
|
-
}
|
|
99
|
-
if (totalPages > 1) {
|
|
100
|
-
const paginationRow = [];
|
|
101
|
-
if (currentPage > 1) {
|
|
102
|
-
paginationRow.push({
|
|
103
|
-
text: "◀ Prev",
|
|
104
|
-
callback_data: `mdl_list_${provider}_${currentPage - 1}`,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
paginationRow.push({
|
|
108
|
-
text: `${currentPage}/${totalPages}`,
|
|
109
|
-
callback_data: `mdl_list_${provider}_${currentPage}`,
|
|
110
|
-
});
|
|
111
|
-
if (currentPage < totalPages) {
|
|
112
|
-
paginationRow.push({
|
|
113
|
-
text: "Next ▶",
|
|
114
|
-
callback_data: `mdl_list_${provider}_${currentPage + 1}`,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
rows.push(paginationRow);
|
|
118
|
-
}
|
|
119
|
-
rows.push([{ text: "<< Back", callback_data: "mdl_back" }]);
|
|
120
|
-
return rows;
|
|
121
|
-
}
|
|
122
|
-
export function buildBrowseProvidersButton() {
|
|
123
|
-
return [[{ text: "Browse providers", callback_data: "mdl_prov" }]];
|
|
124
|
-
}
|
|
125
|
-
export function getModelsPageSize() {
|
|
126
|
-
return MODELS_PAGE_SIZE;
|
|
127
|
-
}
|
|
128
|
-
export function calculateTotalPages(totalModels, pageSize) {
|
|
129
|
-
const size = pageSize ?? MODELS_PAGE_SIZE;
|
|
130
|
-
return size > 0 ? Math.ceil(totalModels / size) : 1;
|
|
131
|
-
}
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
|
-
// channelData builders (used by plugin.commands adapter)
|
|
134
|
-
// ---------------------------------------------------------------------------
|
|
135
|
-
export function buildWeixinModelsProviderChannelData(params) {
|
|
136
|
-
if (params.providers.length === 0)
|
|
137
|
-
return null;
|
|
138
|
-
return { "openclaw-weixin": { buttons: buildProviderKeyboard(params.providers) } };
|
|
139
|
-
}
|
|
140
|
-
export function buildWeixinModelsListChannelData(params) {
|
|
141
|
-
return { "openclaw-weixin": { buttons: buildModelsKeyboard(params) } };
|
|
142
|
-
}
|
|
143
|
-
export function buildWeixinModelBrowseChannelData() {
|
|
144
|
-
return { "openclaw-weixin": { buttons: buildBrowseProvidersButton() } };
|
|
145
|
-
}
|
|
146
|
-
export function buildWeixinCommandsListChannelData(params) {
|
|
147
|
-
if (params.totalPages <= 1)
|
|
148
|
-
return null;
|
|
149
|
-
const buttons = [];
|
|
150
|
-
const suffix = params.agentId ? `:${params.agentId}` : "";
|
|
151
|
-
if (params.currentPage > 1) {
|
|
152
|
-
buttons.push({
|
|
153
|
-
text: "◀ Prev",
|
|
154
|
-
callback_data: `commands_page_${params.currentPage - 1}${suffix}`,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
buttons.push({
|
|
158
|
-
text: `${params.currentPage}/${params.totalPages}`,
|
|
159
|
-
callback_data: `commands_page_noop${suffix}`,
|
|
160
|
-
});
|
|
161
|
-
if (params.currentPage < params.totalPages) {
|
|
162
|
-
buttons.push({
|
|
163
|
-
text: "Next ▶",
|
|
164
|
-
callback_data: `commands_page_${params.currentPage + 1}${suffix}`,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
return { "openclaw-weixin": { buttons: [buttons] } };
|
|
168
|
-
}
|
|
169
|
-
// ---------------------------------------------------------------------------
|
|
170
|
-
// Model selection resolution (when provider is ambiguous)
|
|
171
|
-
// ---------------------------------------------------------------------------
|
|
172
|
-
export function resolveModelSelection(params) {
|
|
173
|
-
if (params.callback.provider) {
|
|
174
|
-
return { kind: "resolved", provider: params.callback.provider, model: params.callback.model };
|
|
175
|
-
}
|
|
176
|
-
const matchingProviders = params.providers.filter((id) => params.byProvider.get(id)?.has(params.callback.model));
|
|
177
|
-
if (matchingProviders.length === 1) {
|
|
178
|
-
return { kind: "resolved", provider: matchingProviders[0], model: params.callback.model };
|
|
179
|
-
}
|
|
180
|
-
return { kind: "ambiguous", model: params.callback.model, matchingProviders };
|
|
181
|
-
}
|
|
182
|
-
//# sourceMappingURL=model-buttons.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"model-buttons.js","sourceRoot":"","sources":["../../../src/messaging/model-buttons.ts"],"names":[],"mappings":"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"}
|