@tencent-weixin/openclaw-weixin 2.4.4 → 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.
Files changed (58) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/CHANGELOG.zh_CN.md +34 -0
  3. package/dist/src/api/api.js +35 -1
  4. package/dist/src/api/api.js.map +1 -1
  5. package/dist/src/api/session-guard.js +3 -3
  6. package/dist/src/api/session-guard.js.map +1 -1
  7. package/dist/src/api/types.js.map +1 -1
  8. package/dist/src/cdn/cdn-upload.js +3 -2
  9. package/dist/src/cdn/cdn-upload.js.map +1 -1
  10. package/dist/src/cdn/upload.js +12 -3
  11. package/dist/src/cdn/upload.js.map +1 -1
  12. package/dist/src/monitor/monitor.js +8 -8
  13. package/dist/src/monitor/monitor.js.map +1 -1
  14. package/npm-shrinkwrap.json +21848 -0
  15. package/openclaw.plugin.json +1 -1
  16. package/package.json +7 -5
  17. package/src/api/api.ts +50 -1
  18. package/src/api/session-guard.ts +3 -3
  19. package/src/api/types.ts +2 -1
  20. package/src/cdn/cdn-upload.ts +8 -2
  21. package/src/cdn/upload.ts +14 -3
  22. package/src/monitor/monitor.ts +9 -11
  23. package/dist/src/media/voice-outbound.js +0 -274
  24. package/dist/src/media/voice-outbound.js.map +0 -1
  25. package/dist/src/messaging/abort-fence.js +0 -70
  26. package/dist/src/messaging/abort-fence.js.map +0 -1
  27. package/dist/src/messaging/batch-session.js +0 -271
  28. package/dist/src/messaging/batch-session.js.map +0 -1
  29. package/dist/src/messaging/buttons.js +0 -117
  30. package/dist/src/messaging/buttons.js.map +0 -1
  31. package/dist/src/messaging/lane-key.js +0 -66
  32. package/dist/src/messaging/lane-key.js.map +0 -1
  33. package/dist/src/messaging/merged-record.js +0 -149
  34. package/dist/src/messaging/merged-record.js.map +0 -1
  35. package/dist/src/messaging/model-buttons.js +0 -182
  36. package/dist/src/messaging/model-buttons.js.map +0 -1
  37. package/dist/src/messaging/model-callback-handler.js +0 -133
  38. package/dist/src/messaging/model-callback-handler.js.map +0 -1
  39. package/dist/src/messaging/run-context.js +0 -9
  40. package/dist/src/messaging/run-context.js.map +0 -1
  41. package/dist/src/messaging/run-report-session.js +0 -123
  42. package/dist/src/messaging/run-report-session.js.map +0 -1
  43. package/dist/src/monitor/lane-scheduler.js +0 -46
  44. package/dist/src/monitor/lane-scheduler.js.map +0 -1
  45. package/dist/src/runtime.js +0 -54
  46. package/dist/src/runtime.js.map +0 -1
  47. package/dist/src/streaming/batch-session.js +0 -271
  48. package/dist/src/streaming/batch-session.js.map +0 -1
  49. package/dist/src/streaming/stream-piece.js +0 -54
  50. package/dist/src/streaming/stream-piece.js.map +0 -1
  51. package/dist/src/streaming/stream-pipeline.js +0 -431
  52. package/dist/src/streaming/stream-pipeline.js.map +0 -1
  53. package/dist/src/streaming/stream-session.js +0 -260
  54. package/dist/src/streaming/stream-session.js.map +0 -1
  55. package/dist/src/streaming/stream.js +0 -239
  56. package/dist/src/streaming/stream.js.map +0 -1
  57. package/dist/src/util/markdown-fences.js +0 -54
  58. package/dist/src/util/markdown-fences.js.map +0 -1
@@ -1,271 +0,0 @@
1
- import crypto from "node:crypto";
2
- import { onAgentEvent, } from "openclaw/plugin-sdk/agent-harness-runtime";
3
- import { MessageItemType } from "../api/types.js";
4
- import { logger } from "../util/logger.js";
5
- /** Max chars for a tool result summary before truncation. */
6
- const TOOL_OUTPUT_CHAR_LIMIT = 120_000;
7
- /** Default size budget for a single batch sendMessage (bytes, JSON estimate). */
8
- export const BATCH_SIZE_LIMIT_BYTES = 200 * 1024;
9
- function estimateSizeBytes(items) {
10
- try {
11
- return Buffer.byteLength(JSON.stringify(items), "utf8");
12
- }
13
- catch {
14
- return 0;
15
- }
16
- }
17
- function truncateText(text, limit) {
18
- if (text.length <= limit)
19
- return text;
20
- return `${text.slice(0, limit)}\n\n… truncated (${text.length} chars, showing first ${limit}).`;
21
- }
22
- function formatToolOutput(value) {
23
- if (value === null || value === undefined)
24
- return "";
25
- if (typeof value === "number" || typeof value === "boolean")
26
- return String(value);
27
- let text;
28
- if (typeof value === "string") {
29
- text = value;
30
- }
31
- else {
32
- if (typeof value === "object") {
33
- const rec = value;
34
- if (typeof rec.text === "string") {
35
- text = rec.text;
36
- }
37
- else if (Array.isArray(rec.content)) {
38
- const parts = rec.content
39
- .map((item) => {
40
- if (item && typeof item === "object") {
41
- const e = item;
42
- if (e.type === "text" && typeof e.text === "string")
43
- return e.text;
44
- }
45
- return null;
46
- })
47
- .filter((p) => p !== null);
48
- text = parts.length > 0 ? parts.join("\n") : JSON.stringify(value, null, 2);
49
- }
50
- else {
51
- text = JSON.stringify(value, null, 2);
52
- }
53
- }
54
- else {
55
- text = String(value);
56
- }
57
- }
58
- return truncateText(text, TOOL_OUTPUT_CHAR_LIMIT);
59
- }
60
- function tryStringifyArgs(args) {
61
- if (args === undefined)
62
- return undefined;
63
- try {
64
- return JSON.stringify(args);
65
- }
66
- catch {
67
- return undefined;
68
- }
69
- }
70
- /**
71
- * BatchSession — accumulates thinking, tool calls, and text payloads during
72
- * an AI turn and sends them all in a single sendMessage at finalize time.
73
- *
74
- * Drop priority when item_list > BATCH_SIZE_LIMIT_BYTES:
75
- * 1. Drop ThinkingItem (largest, optional for client UX)
76
- * 2. Drop all ToolCallStart/Result items
77
- * 3. Always keep TextItem(s) — the actual reply
78
- *
79
- * Usage:
80
- * const session = new BatchSession({ onSendBatch });
81
- * // spread replyCallbacks + runId into replyOptions
82
- * replyOptions = { ...replyOptions, runId: session.runId, ...session.replyCallbacks }
83
- * // in deliver(): session.addTextPayload(text)
84
- * // after dispatchReplyFromConfig: await session.finalize()
85
- * // on error: await session.abort()
86
- */
87
- export class BatchSession {
88
- /** Run id this session listens for on the global agent event bus. */
89
- runId;
90
- thinkingText = null;
91
- toolStarts = [];
92
- toolResults = [];
93
- textPayloads = [];
94
- done = false;
95
- unsubscribeAgentEvent;
96
- onSendBatch;
97
- constructor(deps) {
98
- this.runId = deps.runId ?? crypto.randomUUID();
99
- this.onSendBatch = deps.onSendBatch;
100
- this.unsubscribeAgentEvent = onAgentEvent((evt) => this.handleRawAgentEvent(evt));
101
- logger.debug(`BatchSession.ctor: runId=${this.runId} agentEventListener=registered`);
102
- }
103
- /**
104
- * Spread into replyOptions so the SDK delivers thinking/tool events here.
105
- * Also set `replyOptions.runId = session.runId` so agent events carry the
106
- * matching runId.
107
- */
108
- get replyCallbacks() {
109
- return {
110
- onReasoningStream: (payload) => this.handleReasoningStream(payload),
111
- onReasoningEnd: () => { },
112
- };
113
- }
114
- /**
115
- * Store a text payload from deliver(). Each call appends one TextItem to the
116
- * final item_list in call order. Skips empty strings.
117
- */
118
- addTextPayload(text) {
119
- if (!text.trim())
120
- return;
121
- this.textPayloads.push(text);
122
- logger.debug(`BatchSession.addTextPayload: len=${text.length} total=${this.textPayloads.length}`);
123
- }
124
- // ---- private callbacks --------------------------------------------------
125
- handleReasoningStream(payload) {
126
- if (this.done)
127
- return;
128
- const text = typeof payload.text === "string" ? payload.text : "";
129
- if (text) {
130
- this.thinkingText = text;
131
- }
132
- }
133
- handleRawAgentEvent(evt) {
134
- if (this.done)
135
- return;
136
- if (evt.runId !== this.runId)
137
- return;
138
- if (evt.stream !== "tool")
139
- return;
140
- const data = evt.data;
141
- if (typeof data.toolCallId !== "string" || !data.toolCallId)
142
- return;
143
- if (data.phase === "start") {
144
- this.toolStarts.push({
145
- tool_call_id: data.toolCallId,
146
- tool_name: typeof data.name === "string" && data.name ? data.name : "tool",
147
- args_json: tryStringifyArgs(data.args),
148
- });
149
- logger.debug(`BatchSession: tool_call_start tool=${data.name ?? "?"} id=${data.toolCallId}` +
150
- ` totalStarts=${this.toolStarts.length}`);
151
- return;
152
- }
153
- if (data.phase === "result") {
154
- this.toolResults.push({
155
- tool_call_id: data.toolCallId,
156
- summary: formatToolOutput(data.result),
157
- });
158
- logger.debug(`BatchSession: tool_call_result id=${data.toolCallId}` +
159
- ` totalResults=${this.toolResults.length}`);
160
- }
161
- }
162
- // ---- item_list assembly -------------------------------------------------
163
- /**
164
- * Build the item_list applying the 200 KB budget.
165
- *
166
- * Order: [ThinkingItem?, ToolCallStart+Result pairs..., TextItem(s)...]
167
- *
168
- * If full list > maxBytes:
169
- * - drop ThinkingItem and retry
170
- * - if still > maxBytes, drop all tool items too
171
- * - TextItem(s) are always kept
172
- */
173
- buildItemList(maxBytes = BATCH_SIZE_LIMIT_BYTES) {
174
- const textItems = this.textPayloads.map((t) => ({
175
- type: MessageItemType.TEXT,
176
- text_item: { text: t },
177
- }));
178
- const toolItems = [];
179
- for (const start of this.toolStarts) {
180
- toolItems.push({
181
- type: MessageItemType.TOOL_CALL_START,
182
- tool_call_start_item: {
183
- tool_name: start.tool_name,
184
- tool_call_id: start.tool_call_id,
185
- args_json: start.args_json,
186
- },
187
- });
188
- const result = this.toolResults.find((r) => r.tool_call_id === start.tool_call_id);
189
- if (result) {
190
- toolItems.push({
191
- type: MessageItemType.TOOL_CALL_RESULT,
192
- tool_call_result_item: {
193
- tool_call_id: result.tool_call_id,
194
- summary: result.summary,
195
- },
196
- });
197
- }
198
- }
199
- const thinkingItem = this.thinkingText
200
- ? { type: MessageItemType.THINKING, thinking_item: { text: this.thinkingText } }
201
- : null;
202
- // Attempt 1: full list
203
- const full = [
204
- ...(thinkingItem ? [thinkingItem] : []),
205
- ...toolItems,
206
- ...textItems,
207
- ];
208
- if (full.length === 0)
209
- return [];
210
- const fullSize = estimateSizeBytes(full);
211
- logger.debug(`BatchSession.buildItemList: items=${full.length} size=${fullSize}B` +
212
- ` thinking=${thinkingItem !== null} tools=${this.toolStarts.length}` +
213
- ` texts=${this.textPayloads.length}`);
214
- if (fullSize <= maxBytes)
215
- return full;
216
- // Attempt 2: drop thinking
217
- logger.warn(`BatchSession.buildItemList: size=${fullSize}B > limit=${maxBytes}B,` +
218
- ` dropping ThinkingItem (len=${this.thinkingText?.length ?? 0} chars).` +
219
- ` Full thinking content is in the log: ${logger.getLogFilePath()}`);
220
- const withoutThinking = [...toolItems, ...textItems];
221
- if (withoutThinking.length === 0)
222
- return [];
223
- const noThinkingSize = estimateSizeBytes(withoutThinking);
224
- if (noThinkingSize <= maxBytes)
225
- return withoutThinking;
226
- // Attempt 3: drop tool items too
227
- logger.warn(`BatchSession.buildItemList: size=${noThinkingSize}B still > limit=${maxBytes}B,` +
228
- ` dropping ${this.toolStarts.length} tool call(s) (${toolItems.length} items).` +
229
- ` Full tool content is in the log: ${logger.getLogFilePath()}`);
230
- return textItems.length > 0 ? textItems : [];
231
- }
232
- // ---- lifecycle ----------------------------------------------------------
233
- /**
234
- * Assemble item_list, call onSendBatch once, then clean up. Idempotent.
235
- */
236
- async finalize() {
237
- if (this.done)
238
- return;
239
- this.done = true;
240
- this.cleanup();
241
- const items = this.buildItemList();
242
- if (items.length === 0) {
243
- logger.debug("BatchSession.finalize: item_list empty, skipping send");
244
- return;
245
- }
246
- logger.debug(`BatchSession.finalize: sending ${items.length} item(s)` +
247
- ` thinking=${this.thinkingText !== null}` +
248
- ` toolStarts=${this.toolStarts.length}` +
249
- ` texts=${this.textPayloads.length}`);
250
- await this.onSendBatch(items);
251
- }
252
- /**
253
- * Discard all buffered data, release event listener. Does not send. Idempotent.
254
- */
255
- async abort() {
256
- if (this.done)
257
- return;
258
- this.done = true;
259
- this.cleanup();
260
- logger.debug("BatchSession.abort: discarded without send");
261
- }
262
- cleanup() {
263
- try {
264
- this.unsubscribeAgentEvent();
265
- }
266
- catch (err) {
267
- logger.warn(`BatchSession.cleanup: unsubscribe failed err=${String(err)}`);
268
- }
269
- }
270
- }
271
- //# sourceMappingURL=batch-session.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"batch-session.js","sourceRoot":"","sources":["../../../src/messaging/batch-session.ts"],"names":[],"mappings":"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"}
@@ -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":"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"}
@@ -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 ? `![图片](${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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"}