ylib-wecom-openclaw-plugin 2026.4.29

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 (180) hide show
  1. package/README.md +596 -0
  2. package/dist/index.d.ts +10 -0
  3. package/dist/index.js +99 -0
  4. package/dist/src/accounts.d.ts +57 -0
  5. package/dist/src/accounts.js +247 -0
  6. package/dist/src/agent/api-client.d.ts +95 -0
  7. package/dist/src/agent/api-client.js +425 -0
  8. package/dist/src/agent/handler.d.ts +64 -0
  9. package/dist/src/agent/handler.js +731 -0
  10. package/dist/src/agent/index.d.ts +5 -0
  11. package/dist/src/agent/index.js +21 -0
  12. package/dist/src/agent/webhook.d.ts +25 -0
  13. package/dist/src/agent/webhook.js +294 -0
  14. package/dist/src/agent/xml.d.ts +21 -0
  15. package/dist/src/agent/xml.js +43 -0
  16. package/dist/src/channel.d.ts +5 -0
  17. package/dist/src/channel.js +815 -0
  18. package/dist/src/chat-queue.d.ts +31 -0
  19. package/dist/src/chat-queue.js +53 -0
  20. package/dist/src/config-schema.d.ts +587 -0
  21. package/dist/src/config-schema.js +146 -0
  22. package/dist/src/const.d.ts +128 -0
  23. package/dist/src/const.js +168 -0
  24. package/dist/src/dm-policy.d.ts +29 -0
  25. package/dist/src/dm-policy.js +146 -0
  26. package/dist/src/dynamic-agent.d.ts +37 -0
  27. package/dist/src/dynamic-agent.js +67 -0
  28. package/dist/src/dynamic-routing.d.ts +65 -0
  29. package/dist/src/dynamic-routing.js +62 -0
  30. package/dist/src/endpoint-dispatch.d.ts +54 -0
  31. package/dist/src/endpoint-dispatch.js +967 -0
  32. package/dist/src/endpoint-event-adapter.d.ts +15 -0
  33. package/dist/src/endpoint-event-adapter.js +427 -0
  34. package/dist/src/group-policy.d.ts +30 -0
  35. package/dist/src/group-policy.js +126 -0
  36. package/dist/src/http.d.ts +27 -0
  37. package/dist/src/http.js +168 -0
  38. package/dist/src/im-runtime-telemetry.d.ts +25 -0
  39. package/dist/src/im-runtime-telemetry.js +68 -0
  40. package/dist/src/interface.d.ts +192 -0
  41. package/dist/src/interface.js +5 -0
  42. package/dist/src/markdown-chunk.d.ts +1 -0
  43. package/dist/src/markdown-chunk.js +396 -0
  44. package/dist/src/mcp/index.d.ts +6 -0
  45. package/dist/src/mcp/index.js +28 -0
  46. package/dist/src/mcp/interceptors/biz-error.d.ts +11 -0
  47. package/dist/src/mcp/interceptors/biz-error.js +73 -0
  48. package/dist/src/mcp/interceptors/doc-auth-error.d.ts +10 -0
  49. package/dist/src/mcp/interceptors/doc-auth-error.js +235 -0
  50. package/dist/src/mcp/interceptors/index.d.ts +35 -0
  51. package/dist/src/mcp/interceptors/index.js +143 -0
  52. package/dist/src/mcp/interceptors/msg-media.d.ts +11 -0
  53. package/dist/src/mcp/interceptors/msg-media.js +201 -0
  54. package/dist/src/mcp/interceptors/smartpage-create.d.ts +30 -0
  55. package/dist/src/mcp/interceptors/smartpage-create.js +252 -0
  56. package/dist/src/mcp/interceptors/smartpage-export.d.ts +17 -0
  57. package/dist/src/mcp/interceptors/smartpage-export.js +135 -0
  58. package/dist/src/mcp/interceptors/smartsheet-upload.d.ts +22 -0
  59. package/dist/src/mcp/interceptors/smartsheet-upload.js +388 -0
  60. package/dist/src/mcp/interceptors/types.d.ts +64 -0
  61. package/dist/src/mcp/interceptors/types.js +8 -0
  62. package/dist/src/mcp/schema.d.ts +11 -0
  63. package/dist/src/mcp/schema.js +115 -0
  64. package/dist/src/mcp/tool.d.ts +63 -0
  65. package/dist/src/mcp/tool.js +318 -0
  66. package/dist/src/mcp/transport.d.ts +94 -0
  67. package/dist/src/mcp/transport.js +702 -0
  68. package/dist/src/media-handler.d.ts +55 -0
  69. package/dist/src/media-handler.js +306 -0
  70. package/dist/src/media-uploader.d.ts +142 -0
  71. package/dist/src/media-uploader.js +446 -0
  72. package/dist/src/message-parser.d.ts +104 -0
  73. package/dist/src/message-parser.js +232 -0
  74. package/dist/src/message-sender.d.ts +54 -0
  75. package/dist/src/message-sender.js +210 -0
  76. package/dist/src/monitor.d.ts +69 -0
  77. package/dist/src/monitor.js +1846 -0
  78. package/dist/src/onboarding.d.ts +8 -0
  79. package/dist/src/onboarding.js +248 -0
  80. package/dist/src/openclaw-compat.d.ts +148 -0
  81. package/dist/src/openclaw-compat.js +839 -0
  82. package/dist/src/proactive-markdown-send.d.ts +14 -0
  83. package/dist/src/proactive-markdown-send.js +205 -0
  84. package/dist/src/reqid-store.d.ts +23 -0
  85. package/dist/src/reqid-store.js +136 -0
  86. package/dist/src/runtime.d.ts +2 -0
  87. package/dist/src/runtime.js +7 -0
  88. package/dist/src/shared/command-auth.d.ts +23 -0
  89. package/dist/src/shared/command-auth.js +112 -0
  90. package/dist/src/shared/xml-parser.d.ts +46 -0
  91. package/dist/src/shared/xml-parser.js +228 -0
  92. package/dist/src/state-dir-resolve.d.ts +2 -0
  93. package/dist/src/state-dir-resolve.js +33 -0
  94. package/dist/src/state-manager.d.ts +115 -0
  95. package/dist/src/state-manager.js +413 -0
  96. package/dist/src/target.d.ts +35 -0
  97. package/dist/src/target.js +71 -0
  98. package/dist/src/template-card-manager.d.ts +55 -0
  99. package/dist/src/template-card-manager.js +316 -0
  100. package/dist/src/template-card-parser.d.ts +37 -0
  101. package/dist/src/template-card-parser.js +672 -0
  102. package/dist/src/timeout.d.ts +20 -0
  103. package/dist/src/timeout.js +57 -0
  104. package/dist/src/types/account.d.ts +29 -0
  105. package/dist/src/types/account.js +5 -0
  106. package/dist/src/types/config.d.ts +98 -0
  107. package/dist/src/types/config.js +8 -0
  108. package/dist/src/types/constants.d.ts +42 -0
  109. package/dist/src/types/constants.js +45 -0
  110. package/dist/src/types/index.d.ts +7 -0
  111. package/dist/src/types/index.js +17 -0
  112. package/dist/src/types/message.d.ts +238 -0
  113. package/dist/src/types/message.js +6 -0
  114. package/dist/src/utils.d.ts +148 -0
  115. package/dist/src/utils.js +92 -0
  116. package/dist/src/version.d.ts +2 -0
  117. package/dist/src/version.js +28 -0
  118. package/dist/src/webhook/command-auth.d.ts +47 -0
  119. package/dist/src/webhook/command-auth.js +137 -0
  120. package/dist/src/webhook/gateway.d.ts +36 -0
  121. package/dist/src/webhook/gateway.js +297 -0
  122. package/dist/src/webhook/handler.d.ts +19 -0
  123. package/dist/src/webhook/handler.js +481 -0
  124. package/dist/src/webhook/helpers.d.ts +157 -0
  125. package/dist/src/webhook/helpers.js +936 -0
  126. package/dist/src/webhook/http.d.ts +27 -0
  127. package/dist/src/webhook/http.js +168 -0
  128. package/dist/src/webhook/index.d.ts +11 -0
  129. package/dist/src/webhook/index.js +43 -0
  130. package/dist/src/webhook/media.d.ts +30 -0
  131. package/dist/src/webhook/media.js +152 -0
  132. package/dist/src/webhook/monitor.d.ts +59 -0
  133. package/dist/src/webhook/monitor.js +1672 -0
  134. package/dist/src/webhook/state.d.ts +220 -0
  135. package/dist/src/webhook/state.js +568 -0
  136. package/dist/src/webhook/target.d.ts +41 -0
  137. package/dist/src/webhook/target.js +165 -0
  138. package/dist/src/webhook/types.d.ts +348 -0
  139. package/dist/src/webhook/types.js +36 -0
  140. package/dist/src/webhook/video-frame.d.ts +13 -0
  141. package/dist/src/webhook/video-frame.js +108 -0
  142. package/openclaw.plugin.json +19 -0
  143. package/package.json +96 -0
  144. package/schema.json +534 -0
  145. package/scripts/generate-schema.mjs +33 -0
  146. package/skills/wecom-contact/SKILL.md +162 -0
  147. package/skills/wecom-doc/SKILL.md +162 -0
  148. package/skills/wecom-doc/references/create-doc.md +56 -0
  149. package/skills/wecom-doc/references/edit-doc-content.md +68 -0
  150. package/skills/wecom-doc/references/get-doc-content.md +88 -0
  151. package/skills/wecom-doc/references/smartpage-create.md +125 -0
  152. package/skills/wecom-doc/references/smartpage-export.md +160 -0
  153. package/skills/wecom-meeting/SKILL.md +441 -0
  154. package/skills/wecom-meeting/references/example-full.md +30 -0
  155. package/skills/wecom-meeting/references/example-reminder.md +46 -0
  156. package/skills/wecom-meeting/references/example-security.md +22 -0
  157. package/skills/wecom-meeting/references/response-get-meeting-info.md +148 -0
  158. package/skills/wecom-msg/SKILL.md +157 -0
  159. package/skills/wecom-msg/references/api-get-messages.md +93 -0
  160. package/skills/wecom-msg/references/api-get-msg-chat-list.md +58 -0
  161. package/skills/wecom-msg/references/api-get-msg-media.md +44 -0
  162. package/skills/wecom-msg/references/api-send-message.md +39 -0
  163. package/skills/wecom-preflight/SKILL.md +141 -0
  164. package/skills/wecom-schedule/SKILL.md +161 -0
  165. package/skills/wecom-schedule/references/api-check-availability.md +56 -0
  166. package/skills/wecom-schedule/references/api-create-schedule.md +38 -0
  167. package/skills/wecom-schedule/references/api-get-schedule-detail.md +81 -0
  168. package/skills/wecom-schedule/references/api-update-schedule.md +32 -0
  169. package/skills/wecom-schedule/references/ref-reminders.md +24 -0
  170. package/skills/wecom-send-media/SKILL.md +68 -0
  171. package/skills/wecom-send-template-card/SKILL.md +157 -0
  172. package/skills/wecom-send-template-card/references/api-template-card-types.md +358 -0
  173. package/skills/wecom-smartsheet/SKILL.md +164 -0
  174. package/skills/wecom-smartsheet/references/smartsheet-cell-value-formats.md +163 -0
  175. package/skills/wecom-smartsheet/references/smartsheet-field-types.md +44 -0
  176. package/skills/wecom-smartsheet/references/smartsheet-get-records.md +96 -0
  177. package/skills/wecom-smartsheet/references/webhook-examples.md +185 -0
  178. package/skills/wecom-smartsheet/references/webhook-fallback.md +184 -0
  179. package/skills/wecom-todo/SKILL.md +392 -0
  180. package/skills/wecom-todo/examples/workflows.md +163 -0
@@ -0,0 +1,1672 @@
1
+ "use strict";
2
+ /**
3
+ * Webhook 核心消息处理
4
+ *
5
+ * 从 @mocrane/wecom monitor.ts 部分迁移 + 重构。
6
+ * 负责:入站消息解析、防抖聚合、Agent 调度、流式输出、超时兜底。
7
+ */
8
+ var __assign = (this && this.__assign) || function () {
9
+ __assign = Object.assign || function(t) {
10
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
11
+ s = arguments[i];
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
13
+ t[p] = s[p];
14
+ }
15
+ return t;
16
+ };
17
+ return __assign.apply(this, arguments);
18
+ };
19
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
39
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
40
+ return new (P || (P = Promise))(function (resolve, reject) {
41
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
42
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
43
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
44
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
45
+ });
46
+ };
47
+ var __generator = (this && this.__generator) || function (thisArg, body) {
48
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
49
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
50
+ function verb(n) { return function (v) { return step([n, v]); }; }
51
+ function step(op) {
52
+ if (f) throw new TypeError("Generator is already executing.");
53
+ while (_) try {
54
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
55
+ if (y = 0, t) op = [op[0] & 2, t.value];
56
+ switch (op[0]) {
57
+ case 0: case 1: t = op; break;
58
+ case 4: _.label++; return { value: op[1], done: false };
59
+ case 5: _.label++; y = op[1]; op = [0]; continue;
60
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
61
+ default:
62
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
63
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
64
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
65
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
66
+ if (t[2]) _.ops.pop();
67
+ _.trys.pop(); continue;
68
+ }
69
+ op = body.call(thisArg, _);
70
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
71
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
72
+ }
73
+ };
74
+ var __spreadArrays = (this && this.__spreadArrays) || function () {
75
+ for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
76
+ for (var r = Array(s), k = 0, i = 0; i < il; i++)
77
+ for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
78
+ r[k] = a[j];
79
+ return r;
80
+ };
81
+ var __importDefault = (this && this.__importDefault) || function (mod) {
82
+ return (mod && mod.__esModule) ? mod : { "default": mod };
83
+ };
84
+ exports.__esModule = true;
85
+ exports.startAgentForStream = exports.handleTemplateCardEvent = exports.handleEnterChat = exports.handleStreamRefresh = exports.handleInboundMessage = void 0;
86
+ var node_url_1 = require("node:url");
87
+ var node_os_1 = __importDefault(require("node:os"));
88
+ var command_auth_js_1 = require("./command-auth.js");
89
+ var types_js_1 = require("./types.js");
90
+ var gateway_js_1 = require("./gateway.js");
91
+ var api_client_js_1 = require("../agent/api-client.js");
92
+ var http_js_1 = require("./http.js");
93
+ var helpers_js_1 = require("./helpers.js");
94
+ var dynamic_routing_js_1 = require("../dynamic-routing.js");
95
+ var endpoint_event_adapter_js_1 = require("../endpoint-event-adapter.js");
96
+ var utils_js_1 = require("../utils.js");
97
+ function resolveWebhookSenderDisplayName(msg) {
98
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
99
+ var raw = msg;
100
+ var from = ((_a = msg.from) !== null && _a !== void 0 ? _a : {});
101
+ var fields = {
102
+ from_name: (_b = from.name) !== null && _b !== void 0 ? _b : null,
103
+ from_userid: (_c = from.userid) !== null && _c !== void 0 ? _c : null,
104
+ sender_name: (_d = raw.sender_name) !== null && _d !== void 0 ? _d : null,
105
+ sender_nickname: (_e = raw.sender_nickname) !== null && _e !== void 0 ? _e : null,
106
+ sender_nick: (_f = raw.sender_nick) !== null && _f !== void 0 ? _f : null,
107
+ display_name: (_g = raw.display_name) !== null && _g !== void 0 ? _g : null,
108
+ user_name: (_h = raw.user_name) !== null && _h !== void 0 ? _h : null,
109
+ nickname: (_j = raw.nickname) !== null && _j !== void 0 ? _j : null,
110
+ name: (_k = raw.name) !== null && _k !== void 0 ? _k : null
111
+ };
112
+ var candidates = [
113
+ fields.from_name,
114
+ fields.sender_name,
115
+ fields.sender_nickname,
116
+ fields.sender_nick,
117
+ fields.display_name,
118
+ fields.user_name,
119
+ fields.nickname,
120
+ fields.name,
121
+ fields.from_userid,
122
+ ];
123
+ for (var _i = 0, candidates_1 = candidates; _i < candidates_1.length; _i++) {
124
+ var item = candidates_1[_i];
125
+ var text = String(item !== null && item !== void 0 ? item : "").trim();
126
+ if (text) {
127
+ return { selected: text, fields: fields };
128
+ }
129
+ }
130
+ return { selected: "", fields: fields };
131
+ }
132
+ // ============================================================================
133
+ // 入站消息处理
134
+ // ============================================================================
135
+ /**
136
+ * 处理入站消息
137
+ *
138
+ * 解析消息类型和内容,创建/获取 stream,加入防抖队列,返回占位符响应。
139
+ */
140
+ function handleInboundMessage(target, message, timestamp, nonce, proxyUrl, msgFilterData) {
141
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
142
+ return __awaiter(this, void 0, void 0, function () {
143
+ var state, streamStore, activeReplyStore, msgid, existingStreamId, existingStream, msgContent, userid, chatType, chatId, resolvedChatId, conversationKey, result, streamId, status, defaultPlaceholder, queuedPlaceholder, mergedQueuedPlaceholder, ackStreamId;
144
+ return __generator(this, function (_u) {
145
+ state = gateway_js_1.getMonitorState();
146
+ streamStore = state.streamStore, activeReplyStore = state.activeReplyStore;
147
+ msgid = message.msgid;
148
+ // msgid 去重检查
149
+ if (msgid) {
150
+ existingStreamId = streamStore.getStreamByMsgId(msgid);
151
+ if (existingStreamId) {
152
+ existingStream = streamStore.getStream(existingStreamId);
153
+ if (existingStream) {
154
+ (_b = (_a = target.runtime).log) === null || _b === void 0 ? void 0 : _b.call(_a, "[webhook] \u6D88\u606F\u53BB\u91CD: msgid=" + msgid + " \u5DF2\u5173\u8054 streamId=" + existingStreamId);
155
+ return [2 /*return*/, helpers_js_1.buildStreamResponse(existingStream)];
156
+ }
157
+ }
158
+ }
159
+ msgContent = helpers_js_1.buildInboundBody(message);
160
+ if (!msgContent && !helpers_js_1.hasMedia(message)) {
161
+ (_d = (_c = target.runtime).log) === null || _d === void 0 ? void 0 : _d.call(_c, "[webhook] \u7A7A\u6D88\u606F\u5185\u5BB9 (type=" + message.msgtype + ", msgid=" + msgid + ")");
162
+ return [2 /*return*/, null];
163
+ }
164
+ userid = (_e = msgFilterData === null || msgFilterData === void 0 ? void 0 : msgFilterData.senderUserId) !== null && _e !== void 0 ? _e : "";
165
+ chatType = String((_f = message.chattype) !== null && _f !== void 0 ? _f : "").trim().toLowerCase();
166
+ chatId = (_h = (_g = msgFilterData === null || msgFilterData === void 0 ? void 0 : msgFilterData.chatId) !== null && _g !== void 0 ? _g : message.chatid) !== null && _h !== void 0 ? _h : "";
167
+ resolvedChatId = chatId || userid;
168
+ conversationKey = "wecom:" + target.account.accountId + ":" + userid + ":" + resolvedChatId;
169
+ result = streamStore.addPendingMessage({
170
+ conversationKey: conversationKey,
171
+ target: target,
172
+ msg: message,
173
+ msgContent: msgContent !== null && msgContent !== void 0 ? msgContent : "",
174
+ nonce: nonce,
175
+ timestamp: timestamp,
176
+ debounceMs: (_j = target.account.config) === null || _j === void 0 ? void 0 : _j.debounceMs
177
+ });
178
+ streamId = result.streamId, status = result.status;
179
+ (_l = (_k = target.runtime).log) === null || _l === void 0 ? void 0 : _l.call(_k, "[webhook] \u6D88\u606F\u5165\u961F (status=" + status + ", streamId=" + streamId + ", convKey=" + conversationKey + ")");
180
+ // 存储 response_url(对齐原版:同时保存 proxyUrl 用于后续出站请求的代理)
181
+ if (message.response_url) {
182
+ activeReplyStore.store(streamId, message.response_url, proxyUrl);
183
+ }
184
+ // 更新 stream 的元数据
185
+ streamStore.updateStream(streamId, function (s) {
186
+ s.userId = userid;
187
+ s.chatType = chatType === "group" ? "group" : "direct";
188
+ s.chatId = resolvedChatId;
189
+ s.aibotid = target.account.botId;
190
+ });
191
+ defaultPlaceholder = (_m = target.account.config) === null || _m === void 0 ? void 0 : _m.streamPlaceholderContent;
192
+ queuedPlaceholder = "已收到,已排队处理中...";
193
+ mergedQueuedPlaceholder = "已收到,已合并排队处理中...";
194
+ if (status === "active_new") {
195
+ // 第一条消息,返回默认占位符
196
+ return [2 /*return*/, helpers_js_1.buildStreamPlaceholderReply(streamId, defaultPlaceholder)];
197
+ }
198
+ if (status === "queued_new") {
199
+ // 进入排队批次,返回排队提示
200
+ (_p = (_o = target.runtime).log) === null || _p === void 0 ? void 0 : _p.call(_o, "[webhook] queue: \u5DF2\u8FDB\u5165\u4E0B\u4E00\u6279\u6B21 streamId=" + streamId + " msgid=" + String((_q = message.msgid) !== null && _q !== void 0 ? _q : ""));
201
+ return [2 /*return*/, helpers_js_1.buildStreamPlaceholderReply(streamId, queuedPlaceholder)];
202
+ }
203
+ ackStreamId = streamStore.createStream({ msgid: message.msgid ? String(message.msgid) : undefined });
204
+ streamStore.updateStream(ackStreamId, function (s) {
205
+ s.finished = false;
206
+ s.started = true;
207
+ s.content = mergedQueuedPlaceholder;
208
+ });
209
+ if (message.msgid) {
210
+ streamStore.setStreamIdForMsgId(String(message.msgid), ackStreamId);
211
+ }
212
+ streamStore.addAckStreamForBatch({ batchStreamId: streamId, ackStreamId: ackStreamId });
213
+ (_s = (_r = target.runtime).log) === null || _s === void 0 ? void 0 : _s.call(_r, "[webhook] queue: \u5DF2\u5408\u5E76\u6392\u961F\uFF08\u56DE\u6267\u6D41\uFF09ackStreamId=" + ackStreamId + " mergedIntoStreamId=" + streamId + " msgid=" + String((_t = message.msgid) !== null && _t !== void 0 ? _t : ""));
214
+ return [2 /*return*/, helpers_js_1.buildStreamTextPlaceholderReply(ackStreamId, mergedQueuedPlaceholder)];
215
+ });
216
+ });
217
+ }
218
+ exports.handleInboundMessage = handleInboundMessage;
219
+ // ============================================================================
220
+ // stream_refresh 处理
221
+ // ============================================================================
222
+ /**
223
+ * 处理 stream_refresh 请求
224
+ *
225
+ * 返回 StreamState 中的当前累积内容、图片附件和 finish 标记。
226
+ */
227
+ function handleStreamRefresh(target, message) {
228
+ var _a, _b, _c, _d, _e, _f, _g, _h;
229
+ return __awaiter(this, void 0, void 0, function () {
230
+ var state, streamId, stream;
231
+ return __generator(this, function (_j) {
232
+ state = gateway_js_1.getMonitorState();
233
+ streamId = String((_b = (_a = message.stream) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : "").trim();
234
+ if (!streamId) {
235
+ (_d = (_c = target.runtime).log) === null || _d === void 0 ? void 0 : _d.call(_c, "[webhook] stream_refresh 缺少 stream_id");
236
+ return [2 /*return*/, null];
237
+ }
238
+ stream = state.streamStore.getStream(streamId);
239
+ if (!stream) {
240
+ (_f = (_e = target.runtime).log) === null || _f === void 0 ? void 0 : _f.call(_e, "[webhook] stream_refresh: stream " + streamId + " \u4E0D\u5B58\u5728");
241
+ // 返回 finish=true 以通知客户端停止轮询
242
+ return [2 /*return*/, {
243
+ msgtype: "stream",
244
+ stream: { id: streamId, finish: true, content: "" }
245
+ }];
246
+ }
247
+ (_h = (_g = target.runtime).log) === null || _h === void 0 ? void 0 : _h.call(_g, "[webhook] stream_refresh (streamId=" + streamId + ", started=" + stream.started + ", finished=" + stream.finished + ", len=" + stream.content.length + ")");
248
+ return [2 /*return*/, helpers_js_1.buildStreamResponse(stream)];
249
+ });
250
+ });
251
+ }
252
+ exports.handleStreamRefresh = handleStreamRefresh;
253
+ // ============================================================================
254
+ // enter_chat 处理
255
+ // ============================================================================
256
+ /**
257
+ * 处理 enter_chat 事件
258
+ *
259
+ * 返回可配置的欢迎消息。
260
+ */
261
+ function handleEnterChat(target, message) {
262
+ var _a, _b, _c, _d;
263
+ return __awaiter(this, void 0, void 0, function () {
264
+ var welcomeText, userId;
265
+ return __generator(this, function (_e) {
266
+ welcomeText = target.account.welcomeText;
267
+ userId = (_b = (_a = message.from) === null || _a === void 0 ? void 0 : _a.userid) !== null && _b !== void 0 ? _b : "unknown";
268
+ (_d = (_c = target.runtime).log) === null || _d === void 0 ? void 0 : _d.call(_c, "[webhook] enter_chat (userId=" + userId + ", account=" + target.account.accountId + ")");
269
+ if (welcomeText) {
270
+ return [2 /*return*/, {
271
+ msgtype: "text",
272
+ text: { content: welcomeText }
273
+ }];
274
+ }
275
+ // 无欢迎消息配置,返回空回复
276
+ return [2 /*return*/, null];
277
+ });
278
+ });
279
+ }
280
+ exports.handleEnterChat = handleEnterChat;
281
+ // ============================================================================
282
+ // template_card_event 处理
283
+ // ============================================================================
284
+ /**
285
+ * 处理模板卡片事件(对齐原版 template_card_event 逻辑)
286
+ *
287
+ * 原版流程:
288
+ * 1. msgid 去重:跳过已处理的卡片事件
289
+ * 2. 解析卡片交互数据:event_key、selected_items、task_id
290
+ * 3. 立即返回空加密回复(非阻塞)
291
+ * 4. 创建 stream 并标记开始
292
+ * 5. 存储 response_url(用于后续推送)
293
+ * 6. 构造交互描述文本,作为文本消息启动 Agent 处理
294
+ */
295
+ function handleTemplateCardEvent(target, message, timestamp, nonce, proxyUrl) {
296
+ var _a, _b, _c, _d, _e, _f, _g;
297
+ return __awaiter(this, void 0, void 0, function () {
298
+ var state, streamStore, activeReplyStore, msgid, cardEvent, interactionDesc, selectedItems, selectedItemList, selects, streamId, syntheticMessage;
299
+ return __generator(this, function (_h) {
300
+ state = gateway_js_1.getMonitorState();
301
+ streamStore = state.streamStore, activeReplyStore = state.activeReplyStore;
302
+ msgid = message.msgid ? String(message.msgid) : undefined;
303
+ // 1. msgid 去重:跳过已处理的卡片事件
304
+ if (msgid && streamStore.getStreamByMsgId(msgid)) {
305
+ (_b = (_a = target.runtime).log) === null || _b === void 0 ? void 0 : _b.call(_a, "[webhook] template_card_event: already processed msgid=" + msgid + ", skipping");
306
+ return [2 /*return*/, {}];
307
+ }
308
+ cardEvent = (_c = message.event) === null || _c === void 0 ? void 0 : _c.template_card_event;
309
+ interactionDesc = "[\u5361\u7247\u4EA4\u4E92] \u6309\u94AE: " + String((_d = cardEvent === null || cardEvent === void 0 ? void 0 : cardEvent.event_key) !== null && _d !== void 0 ? _d : "unknown");
310
+ selectedItems = cardEvent === null || cardEvent === void 0 ? void 0 : cardEvent.selected_items;
311
+ selectedItemList = selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.selected_item;
312
+ if (Array.isArray(selectedItemList) && selectedItemList.length > 0) {
313
+ selects = selectedItemList.map(function (i) {
314
+ var _a, _b;
315
+ var questionKey = String((_a = i.question_key) !== null && _a !== void 0 ? _a : "");
316
+ var optionIds = (_b = i.option_ids) === null || _b === void 0 ? void 0 : _b.option_id;
317
+ var optionStr = Array.isArray(optionIds) ? optionIds.join(",") : String(optionIds !== null && optionIds !== void 0 ? optionIds : "");
318
+ return questionKey + "=" + optionStr;
319
+ });
320
+ interactionDesc += " \u9009\u62E9: " + selects.join("; ");
321
+ }
322
+ // 解析任务 ID
323
+ if (cardEvent === null || cardEvent === void 0 ? void 0 : cardEvent.task_id) {
324
+ interactionDesc += " (\u4EFB\u52A1ID: " + String(cardEvent.task_id) + ")";
325
+ }
326
+ (_f = (_e = target.runtime).log) === null || _f === void 0 ? void 0 : _f.call(_e, "[webhook] template_card_event (event_key=" + String((_g = cardEvent === null || cardEvent === void 0 ? void 0 : cardEvent.event_key) !== null && _g !== void 0 ? _g : "N/A") + ", msgid=" + (msgid !== null && msgid !== void 0 ? msgid : "N/A") + ")");
327
+ streamId = streamStore.createStream({ msgid: msgid });
328
+ streamStore.markStarted(streamId);
329
+ // 4. 存储 response_url(用于后续 Agent 输出推送)
330
+ if (message.response_url) {
331
+ activeReplyStore.store(streamId, message.response_url, proxyUrl);
332
+ }
333
+ syntheticMessage = __assign(__assign({}, message), { msgtype: "text", text: { content: interactionDesc } });
334
+ // 异步启动 Agent(不阻塞 HTTP 响应)
335
+ startAgentForStream({
336
+ target: target,
337
+ accountId: target.account.accountId,
338
+ msg: syntheticMessage,
339
+ streamId: streamId,
340
+ mergedContents: undefined,
341
+ mergedMsgids: undefined
342
+ })["catch"](function (err) {
343
+ var _a, _b;
344
+ (_b = (_a = target.runtime).error) === null || _b === void 0 ? void 0 : _b.call(_a, "[webhook] template_card_event Agent failed: " + String(err));
345
+ });
346
+ // 6. 立即返回空回复(非阻塞,原版返回 {} 加密后的)
347
+ return [2 /*return*/, {}];
348
+ });
349
+ });
350
+ }
351
+ exports.handleTemplateCardEvent = handleTemplateCardEvent;
352
+ // ============================================================================
353
+ // Agent 调度(startAgentForStream)
354
+ // ============================================================================
355
+ /**
356
+ * **startAgentForStream (启动 Agent 处理流程)**
357
+ *
358
+ * 将接收到的(或聚合的)消息转换为 OpenClaw 内部格式,并分发给对应的 Agent。
359
+ * 包含:
360
+ * 1. 消息解密与媒体保存。
361
+ * 2. 路由解析 (Agent Route)。
362
+ * 3. 会话记录 (Session Recording)。
363
+ * 4. 触发 Agent 响应 (Dispatch Reply)。
364
+ * 5. 处理 Agent 输出(包括文本、Markdown 表格转换、<think> 标签保护、模板卡片识别)。
365
+ */
366
+ function startAgentForStream(params) {
367
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48;
368
+ return __awaiter(this, void 0, void 0, function () {
369
+ var target, msg, streamId, state, streamStore, handledConfirmationKeys, ignoredSubAgentRunIds, stream, isWsMode, core, config, account, userid, senderInfo, senderName, chatType, chatId, taskKey, aibotid, _49, rawBody, media, directLocalPaths, fs, pathModule_1, imageExts, imagePaths, otherPaths, _i, directLocalPaths_1, p, ext, loaded_1, _50, imagePaths_1, p, buf, base64, md5, err_1, responseUrl_1, finalReply_1, err_2, agentOk, fallbackName, prompt_1, err_3, _loop_1, _51, imagePaths_2, p, agentOk, filename, prompt_2, err_4, _loop_2, _52, otherPaths_1, p, mediaPath, mediaType, maxBytes, saved, err_5, videoFirstFramePath, extractVideoFirstFrame, err_6, sessionPeerId, route, routingResult, fromLabel, storePath, envelopeOptions, previousTimestamp, body, authz, commandAuthorized, prompt_3, err_7, rawBodyNormalized, isResetCommand, resetCommandKind, attachments, pathModule, ctxPayload, tableMode, cfgForDispatch, current, ackText_1, finishedState, dmText, err_8, stateAfterFinish, responseUrl, err_9, ackStreamIds, mergedDoneHint_1, _53, ackStreamIds_1, ackId;
370
+ var _this = this;
371
+ return __generator(this, function (_54) {
372
+ switch (_54.label) {
373
+ case 0:
374
+ target = params.target, msg = params.msg, streamId = params.streamId;
375
+ state = gateway_js_1.getMonitorState();
376
+ streamStore = state.streamStore;
377
+ handledConfirmationKeys = new Set();
378
+ ignoredSubAgentRunIds = new Set();
379
+ stream = streamStore.getStream(streamId);
380
+ if (!stream) {
381
+ (_b = (_a = target.runtime).log) === null || _b === void 0 ? void 0 : _b.call(_a, "[webhook] stream " + streamId + " \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7 Agent \u8C03\u5EA6");
382
+ return [2 /*return*/];
383
+ }
384
+ isWsMode = Boolean(stream.wsMode);
385
+ core = target.core;
386
+ config = target.config;
387
+ account = target.account;
388
+ userid = helpers_js_1.resolveWecomSenderUserId(msg) || "unknown";
389
+ senderInfo = resolveWebhookSenderDisplayName(msg);
390
+ senderName = senderInfo.selected || userid;
391
+ (_d = (_c = target.runtime).log) === null || _d === void 0 ? void 0 : _d.call(_c, "[wecom][inbound][sender-name] account=" + account.accountId + " from=" + userid + " selected=\"" + senderName + "\" fields=" + JSON.stringify(senderInfo.fields));
392
+ chatType = msg.chattype === "group" ? "group" : "direct";
393
+ chatId = msg.chattype === "group" ? (((_e = msg.chatid) === null || _e === void 0 ? void 0 : _e.trim()) || "unknown") : userid;
394
+ taskKey = helpers_js_1.computeTaskKey(target, msg);
395
+ aibotid = String((_f = msg.aibotid) !== null && _f !== void 0 ? _f : "").trim() || undefined;
396
+ // 更新 Stream 状态:记录上下文信息(用户ID、ChatType等)
397
+ streamStore.updateStream(streamId, function (s) {
398
+ s.userId = userid;
399
+ s.chatType = chatType === "group" ? "group" : "direct";
400
+ s.chatId = chatId;
401
+ s.taskKey = taskKey;
402
+ s.aibotid = aibotid;
403
+ });
404
+ return [4 /*yield*/, helpers_js_1.processInboundMessage(target, msg)];
405
+ case 1:
406
+ _49 = _54.sent(), rawBody = _49.body, media = _49.media;
407
+ // 若存在从防抖逻辑聚合来的多条消息内容,则覆盖 rawBody
408
+ if (params.mergedContents) {
409
+ rawBody = params.mergedContents;
410
+ }
411
+ directLocalPaths = helpers_js_1.extractLocalFilePathsFromText(rawBody);
412
+ if (directLocalPaths.length) {
413
+ (_h = (_g = target.runtime).log) === null || _h === void 0 ? void 0 : _h.call(_g, "local-path: \u68C0\u6D4B\u5230\u7528\u6237\u6D88\u606F\u5305\u542B\u672C\u673A\u8DEF\u5F84 count=" + directLocalPaths.length + " intent=" + helpers_js_1.looksLikeSendLocalFileIntent(rawBody));
414
+ }
415
+ if (!(directLocalPaths.length && helpers_js_1.looksLikeSendLocalFileIntent(rawBody))) return [3 /*break*/, 34];
416
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:fs/promises")); })];
417
+ case 2:
418
+ fs = _54.sent();
419
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:path")); })];
420
+ case 3:
421
+ pathModule_1 = _54.sent();
422
+ imageExts = new Set(["png", "jpg", "jpeg", "gif", "webp", "bmp"]);
423
+ imagePaths = [];
424
+ otherPaths = [];
425
+ for (_i = 0, directLocalPaths_1 = directLocalPaths; _i < directLocalPaths_1.length; _i++) {
426
+ p = directLocalPaths_1[_i];
427
+ ext = pathModule_1.extname(p).slice(1).toLowerCase();
428
+ if (imageExts.has(ext))
429
+ imagePaths.push(p);
430
+ else
431
+ otherPaths.push(p);
432
+ }
433
+ if (!(imagePaths.length > 0 && otherPaths.length === 0)) return [3 /*break*/, 25];
434
+ loaded_1 = [];
435
+ _50 = 0, imagePaths_1 = imagePaths;
436
+ _54.label = 4;
437
+ case 4:
438
+ if (!(_50 < imagePaths_1.length)) return [3 /*break*/, 9];
439
+ p = imagePaths_1[_50];
440
+ _54.label = 5;
441
+ case 5:
442
+ _54.trys.push([5, 7, , 8]);
443
+ return [4 /*yield*/, fs.readFile(p)];
444
+ case 6:
445
+ buf = _54.sent();
446
+ base64 = buf.toString("base64");
447
+ md5 = helpers_js_1.computeMd5(buf);
448
+ loaded_1.push({ base64: base64, md5: md5, path: p });
449
+ return [3 /*break*/, 8];
450
+ case 7:
451
+ err_1 = _54.sent();
452
+ (_k = (_j = target.runtime).error) === null || _k === void 0 ? void 0 : _k.call(_j, "[webhook] local-path: \u8BFB\u53D6\u56FE\u7247\u5931\u8D25 path=" + p + ": " + String(err_1));
453
+ return [3 /*break*/, 8];
454
+ case 8:
455
+ _50++;
456
+ return [3 /*break*/, 4];
457
+ case 9:
458
+ if (!(loaded_1.length > 0)) return [3 /*break*/, 16];
459
+ streamStore.updateStream(streamId, function (s) {
460
+ s.images = loaded_1.map(function (_a) {
461
+ var base64 = _a.base64, md5 = _a.md5;
462
+ return ({ base64: base64, md5: md5 });
463
+ });
464
+ s.content = loaded_1.length === 1
465
+ ? "\u5DF2\u53D1\u9001\u56FE\u7247\uFF08" + pathModule_1.basename(loaded_1[0].path) + "\uFF09"
466
+ : "\u5DF2\u53D1\u9001 " + loaded_1.length + " \u5F20\u56FE\u7247";
467
+ s.finished = true;
468
+ });
469
+ responseUrl_1 = getActiveReplyUrl(streamId);
470
+ if (!responseUrl_1) return [3 /*break*/, 14];
471
+ _54.label = 10;
472
+ case 10:
473
+ _54.trys.push([10, 12, , 13]);
474
+ finalReply_1 = helpers_js_1.buildStreamReplyFromState(streamStore.getStream(streamId), types_js_1.STREAM_MAX_BYTES);
475
+ return [4 /*yield*/, useActiveReplyOnce(streamId, function (_a) {
476
+ var responseUrl = _a.responseUrl, proxyUrl = _a.proxyUrl;
477
+ return __awaiter(_this, void 0, void 0, function () {
478
+ var res;
479
+ return __generator(this, function (_b) {
480
+ switch (_b.label) {
481
+ case 0: return [4 /*yield*/, http_js_1.wecomFetch(responseUrl, {
482
+ method: "POST",
483
+ headers: { "Content-Type": "application/json" },
484
+ body: JSON.stringify(finalReply_1)
485
+ }, { proxyUrl: proxyUrl, timeoutMs: types_js_1.REQUEST_TIMEOUT_MS })];
486
+ case 1:
487
+ res = _b.sent();
488
+ if (!res.ok)
489
+ throw new Error("local-path image push failed: " + res.status);
490
+ return [2 /*return*/];
491
+ }
492
+ });
493
+ });
494
+ })];
495
+ case 11:
496
+ _54.sent();
497
+ (_m = (_l = target.runtime).log) === null || _m === void 0 ? void 0 : _m.call(_l, "[webhook] local-path: \u5DF2\u901A\u8FC7 Bot response_url \u63A8\u9001\u56FE\u7247 frames=final images=" + loaded_1.length);
498
+ return [3 /*break*/, 13];
499
+ case 12:
500
+ err_2 = _54.sent();
501
+ (_p = (_o = target.runtime).error) === null || _p === void 0 ? void 0 : _p.call(_o, "[webhook] local-path: Bot \u4E3B\u52A8\u63A8\u9001\u56FE\u7247\u5931\u8D25\uFF08\u5C06\u4F9D\u8D56 stream_refresh \u62C9\u53D6\uFF09: " + String(err_2));
502
+ return [3 /*break*/, 13];
503
+ case 13: return [3 /*break*/, 15];
504
+ case 14:
505
+ (_r = (_q = target.runtime).log) === null || _r === void 0 ? void 0 : _r.call(_q, "[webhook] local-path: \u65E0 response_url\uFF0C\u7B49\u5F85 stream_refresh \u62C9\u53D6\u6700\u7EC8\u56FE\u7247");
506
+ _54.label = 15;
507
+ case 15:
508
+ // 该消息已完成,推进队列处理下一批
509
+ streamStore.onStreamFinished(streamId);
510
+ return [2 /*return*/];
511
+ case 16:
512
+ agentOk = helpers_js_1.isAgentConfigured(target);
513
+ fallbackName = imagePaths.length === 1
514
+ ? (imagePaths[0].split("/").pop() || "image")
515
+ : imagePaths.length + " \u5F20\u56FE\u7247";
516
+ prompt_1 = helpers_js_1.buildFallbackPrompt({
517
+ kind: "media",
518
+ agentConfigured: agentOk,
519
+ userId: userid,
520
+ filename: fallbackName,
521
+ chatType: chatType
522
+ });
523
+ streamStore.updateStream(streamId, function (s) {
524
+ var _a;
525
+ s.fallbackMode = "error";
526
+ s.finished = true;
527
+ s.content = prompt_1;
528
+ s.fallbackPromptSentAt = (_a = s.fallbackPromptSentAt) !== null && _a !== void 0 ? _a : Date.now();
529
+ });
530
+ _54.label = 17;
531
+ case 17:
532
+ _54.trys.push([17, 19, , 20]);
533
+ return [4 /*yield*/, sendBotFallbackPromptNow({ streamId: streamId, text: prompt_1 })];
534
+ case 18:
535
+ _54.sent();
536
+ (_t = (_s = target.runtime).log) === null || _t === void 0 ? void 0 : _t.call(_s, "[webhook] local-path: \u56FE\u7247\u8BFB\u53D6\u5931\u8D25\u540E\u5DF2\u63A8\u9001\u515C\u5E95\u63D0\u793A");
537
+ return [3 /*break*/, 20];
538
+ case 19:
539
+ err_3 = _54.sent();
540
+ (_v = (_u = target.runtime).error) === null || _v === void 0 ? void 0 : _v.call(_u, "[webhook] local-path: \u56FE\u7247\u8BFB\u53D6\u5931\u8D25\u540E\u7684\u515C\u5E95\u63D0\u793A\u63A8\u9001\u5931\u8D25: " + String(err_3));
541
+ return [3 /*break*/, 20];
542
+ case 20:
543
+ if (!(agentOk && userid && userid !== "unknown")) return [3 /*break*/, 24];
544
+ _loop_1 = function (p) {
545
+ var guessedType, err_10;
546
+ return __generator(this, function (_a) {
547
+ switch (_a.label) {
548
+ case 0:
549
+ guessedType = helpers_js_1.guessContentTypeFromPath(p);
550
+ _a.label = 1;
551
+ case 1:
552
+ _a.trys.push([1, 3, , 4]);
553
+ return [4 /*yield*/, agentDmMedia({
554
+ target: target,
555
+ userId: userid,
556
+ mediaUrlOrPath: p,
557
+ contentType: guessedType,
558
+ filename: p.split("/").pop() || "image"
559
+ })];
560
+ case 2:
561
+ _a.sent();
562
+ streamStore.updateStream(streamId, function (s) {
563
+ var _a;
564
+ s.agentMediaKeys = Array.from(new Set(__spreadArrays(((_a = s.agentMediaKeys) !== null && _a !== void 0 ? _a : []), [p])));
565
+ });
566
+ (_x = (_w = target.runtime).log) === null || _x === void 0 ? void 0 : _x.call(_w, "[webhook] local-path: \u56FE\u7247\u5DF2\u901A\u8FC7 Agent \u79C1\u4FE1\u53D1\u9001 user=" + userid + " path=" + p + " contentType=" + (guessedType !== null && guessedType !== void 0 ? guessedType : "unknown"));
567
+ return [3 /*break*/, 4];
568
+ case 3:
569
+ err_10 = _a.sent();
570
+ (_z = (_y = target.runtime).error) === null || _z === void 0 ? void 0 : _z.call(_y, "[webhook] local-path: \u56FE\u7247 Agent \u79C1\u4FE1\u515C\u5E95\u5931\u8D25 path=" + p + ": " + String(err_10));
571
+ return [3 /*break*/, 4];
572
+ case 4: return [2 /*return*/];
573
+ }
574
+ });
575
+ };
576
+ _51 = 0, imagePaths_2 = imagePaths;
577
+ _54.label = 21;
578
+ case 21:
579
+ if (!(_51 < imagePaths_2.length)) return [3 /*break*/, 24];
580
+ p = imagePaths_2[_51];
581
+ return [5 /*yield**/, _loop_1(p)];
582
+ case 22:
583
+ _54.sent();
584
+ _54.label = 23;
585
+ case 23:
586
+ _51++;
587
+ return [3 /*break*/, 21];
588
+ case 24:
589
+ streamStore.onStreamFinished(streamId);
590
+ return [2 /*return*/];
591
+ case 25:
592
+ if (!(otherPaths.length > 0)) return [3 /*break*/, 34];
593
+ agentOk = helpers_js_1.isAgentConfigured(target);
594
+ filename = otherPaths.length === 1 ? otherPaths[0].split("/").pop() : otherPaths.length + " \u4E2A\u6587\u4EF6";
595
+ prompt_2 = helpers_js_1.buildFallbackPrompt({
596
+ kind: "media",
597
+ agentConfigured: agentOk,
598
+ userId: userid,
599
+ filename: filename,
600
+ chatType: chatType
601
+ });
602
+ streamStore.updateStream(streamId, function (s) {
603
+ var _a;
604
+ s.fallbackMode = "media";
605
+ s.finished = true;
606
+ s.content = prompt_2;
607
+ s.fallbackPromptSentAt = (_a = s.fallbackPromptSentAt) !== null && _a !== void 0 ? _a : Date.now();
608
+ });
609
+ _54.label = 26;
610
+ case 26:
611
+ _54.trys.push([26, 28, , 29]);
612
+ return [4 /*yield*/, sendBotFallbackPromptNow({ streamId: streamId, text: prompt_2 })];
613
+ case 27:
614
+ _54.sent();
615
+ (_1 = (_0 = target.runtime).log) === null || _1 === void 0 ? void 0 : _1.call(_0, "[webhook] local-path: \u6587\u4EF6\u515C\u5E95\u63D0\u793A\u5DF2\u63A8\u9001");
616
+ return [3 /*break*/, 29];
617
+ case 28:
618
+ err_4 = _54.sent();
619
+ (_3 = (_2 = target.runtime).error) === null || _3 === void 0 ? void 0 : _3.call(_2, "[webhook] local-path: \u6587\u4EF6\u515C\u5E95\u63D0\u793A\u63A8\u9001\u5931\u8D25: " + String(err_4));
620
+ return [3 /*break*/, 29];
621
+ case 29:
622
+ if (!agentOk) {
623
+ streamStore.onStreamFinished(streamId);
624
+ return [2 /*return*/];
625
+ }
626
+ if (!userid || userid === "unknown") {
627
+ (_5 = (_4 = target.runtime).error) === null || _5 === void 0 ? void 0 : _5.call(_4, "[webhook] local-path: \u65E0\u6CD5\u8BC6\u522B\u89E6\u53D1\u8005 userId\uFF0C\u65E0\u6CD5 Agent \u79C1\u4FE1\u53D1\u9001\u6587\u4EF6");
628
+ streamStore.onStreamFinished(streamId);
629
+ return [2 /*return*/];
630
+ }
631
+ _loop_2 = function (p) {
632
+ var alreadySent, guessedType, err_11;
633
+ return __generator(this, function (_a) {
634
+ switch (_a.label) {
635
+ case 0:
636
+ alreadySent = (_7 = (_6 = streamStore.getStream(streamId)) === null || _6 === void 0 ? void 0 : _6.agentMediaKeys) === null || _7 === void 0 ? void 0 : _7.includes(p);
637
+ if (alreadySent)
638
+ return [2 /*return*/, "continue"];
639
+ guessedType = helpers_js_1.guessContentTypeFromPath(p);
640
+ _a.label = 1;
641
+ case 1:
642
+ _a.trys.push([1, 3, , 4]);
643
+ return [4 /*yield*/, agentDmMedia({
644
+ target: target,
645
+ userId: userid,
646
+ mediaUrlOrPath: p,
647
+ contentType: guessedType,
648
+ filename: p.split("/").pop() || "file"
649
+ })];
650
+ case 2:
651
+ _a.sent();
652
+ streamStore.updateStream(streamId, function (s) {
653
+ var _a;
654
+ s.agentMediaKeys = Array.from(new Set(__spreadArrays(((_a = s.agentMediaKeys) !== null && _a !== void 0 ? _a : []), [p])));
655
+ });
656
+ (_9 = (_8 = target.runtime).log) === null || _9 === void 0 ? void 0 : _9.call(_8, "[webhook] local-path: \u6587\u4EF6\u5DF2\u901A\u8FC7 Agent \u79C1\u4FE1\u53D1\u9001 user=" + userid + " path=" + p + " contentType=" + (guessedType !== null && guessedType !== void 0 ? guessedType : "unknown"));
657
+ return [3 /*break*/, 4];
658
+ case 3:
659
+ err_11 = _a.sent();
660
+ (_11 = (_10 = target.runtime).error) === null || _11 === void 0 ? void 0 : _11.call(_10, "[webhook] local-path: Agent \u79C1\u4FE1\u53D1\u9001\u6587\u4EF6\u5931\u8D25 path=" + p + ": " + String(err_11));
661
+ return [3 /*break*/, 4];
662
+ case 4: return [2 /*return*/];
663
+ }
664
+ });
665
+ };
666
+ _52 = 0, otherPaths_1 = otherPaths;
667
+ _54.label = 30;
668
+ case 30:
669
+ if (!(_52 < otherPaths_1.length)) return [3 /*break*/, 33];
670
+ p = otherPaths_1[_52];
671
+ return [5 /*yield**/, _loop_2(p)];
672
+ case 31:
673
+ _54.sent();
674
+ _54.label = 32;
675
+ case 32:
676
+ _52++;
677
+ return [3 /*break*/, 30];
678
+ case 33:
679
+ streamStore.onStreamFinished(streamId);
680
+ return [2 /*return*/];
681
+ case 34:
682
+ if (!media) return [3 /*break*/, 38];
683
+ _54.label = 35;
684
+ case 35:
685
+ _54.trys.push([35, 37, , 38]);
686
+ maxBytes = helpers_js_1.resolveWecomMediaMaxBytes(config);
687
+ return [4 /*yield*/, core.channel.media.saveMediaBuffer(media.buffer, media.contentType, "inbound", maxBytes, media.filename)];
688
+ case 36:
689
+ saved = _54.sent();
690
+ mediaPath = saved.path;
691
+ mediaType = saved.contentType;
692
+ (_13 = (_12 = target.runtime).log) === null || _13 === void 0 ? void 0 : _13.call(_12, "[webhook] \u5165\u7AD9\u5A92\u4F53\u5DF2\u4FDD\u5B58: " + mediaPath + " (" + mediaType + ")");
693
+ return [3 /*break*/, 38];
694
+ case 37:
695
+ err_5 = _54.sent();
696
+ (_15 = (_14 = target.runtime).error) === null || _15 === void 0 ? void 0 : _15.call(_14, "[webhook] \u5165\u7AD9\u5A92\u4F53\u4FDD\u5B58\u5931\u8D25: " + String(err_5));
697
+ return [3 /*break*/, 38];
698
+ case 38:
699
+ if (!(mediaPath && (mediaType === null || mediaType === void 0 ? void 0 : mediaType.startsWith("video/")))) return [3 /*break*/, 43];
700
+ _54.label = 39;
701
+ case 39:
702
+ _54.trys.push([39, 42, , 43]);
703
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./video-frame.js")); })];
704
+ case 40:
705
+ extractVideoFirstFrame = (_54.sent()).extractVideoFirstFrame;
706
+ return [4 /*yield*/, extractVideoFirstFrame(mediaPath)];
707
+ case 41:
708
+ videoFirstFramePath = _54.sent();
709
+ if (videoFirstFramePath) {
710
+ (_17 = (_16 = target.runtime).log) === null || _17 === void 0 ? void 0 : _17.call(_16, "[webhook] video: \u7B2C\u4E00\u5E27\u63D0\u53D6\u6210\u529F " + videoFirstFramePath);
711
+ }
712
+ return [3 /*break*/, 43];
713
+ case 42:
714
+ err_6 = _54.sent();
715
+ (_19 = (_18 = target.runtime).log) === null || _19 === void 0 ? void 0 : _19.call(_18, "[webhook] video: \u7B2C\u4E00\u5E27\u63D0\u53D6\u5931\u8D25\uFF08ffmpeg \u53EF\u80FD\u4E0D\u53EF\u7528\uFF09: " + String(err_6));
716
+ return [3 /*break*/, 43];
717
+ case 43:
718
+ sessionPeerId = utils_js_1.resolveWecomSessionPeerId({
719
+ chatType: chatType === "group" ? "group" : "direct",
720
+ chatId: chatId,
721
+ senderId: userid,
722
+ separateSessionByConversation: account.config.separateSessionByConversation,
723
+ groupSessionScope: account.config.groupSessionScope
724
+ });
725
+ route = core.channel.routing.resolveAgentRoute({
726
+ cfg: config,
727
+ channel: "wecom",
728
+ accountId: account.accountId,
729
+ peer: { kind: chatType === "group" ? "group" : "direct", id: sessionPeerId }
730
+ });
731
+ routingResult = dynamic_routing_js_1.processDynamicRouting({
732
+ route: route,
733
+ config: config,
734
+ core: core,
735
+ accountId: account.accountId,
736
+ chatType: chatType === "group" ? "group" : "dm",
737
+ chatId: chatId,
738
+ senderId: userid,
739
+ log: function (msg) { var _a, _b; return (_b = (_a = target.runtime).log) === null || _b === void 0 ? void 0 : _b.call(_a, msg.replace(/^\[dynamic-routing\]/, "[webhook]")); },
740
+ error: function (msg) { var _a, _b; return (_b = (_a = target.runtime).error) === null || _b === void 0 ? void 0 : _b.call(_a, msg.replace(/^\[dynamic-routing\]/, "[webhook]")); }
741
+ });
742
+ // 应用动态路由结果
743
+ if (routingResult.routeModified) {
744
+ route.agentId = routingResult.finalAgentId;
745
+ route.sessionKey = routingResult.finalSessionKey;
746
+ }
747
+ fromLabel = chatType === "group" ? "group:" + chatId : "user:" + userid;
748
+ storePath = core.channel.session.resolveStorePath((_20 = config.session) === null || _20 === void 0 ? void 0 : _20.store, {
749
+ agentId: route.agentId
750
+ });
751
+ envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(config);
752
+ previousTimestamp = core.channel.session.readSessionUpdatedAt({
753
+ storePath: storePath,
754
+ sessionKey: route.sessionKey
755
+ });
756
+ body = core.channel.reply.formatAgentEnvelope({
757
+ channel: "WeCom",
758
+ from: fromLabel,
759
+ previousTimestamp: previousTimestamp,
760
+ envelope: envelopeOptions,
761
+ body: rawBody
762
+ });
763
+ return [4 /*yield*/, command_auth_js_1.resolveWecomCommandAuthorization({
764
+ core: core,
765
+ cfg: config,
766
+ accountConfig: account.config,
767
+ rawBody: rawBody,
768
+ senderUserId: userid
769
+ })];
770
+ case 44:
771
+ authz = _54.sent();
772
+ commandAuthorized = authz.commandAuthorized;
773
+ (_22 = (_21 = target.runtime).log) === null || _22 === void 0 ? void 0 : _22.call(_21, "[webhook] authz: dmPolicy=" + authz.dmPolicy + " shouldCompute=" + authz.shouldComputeAuth + " sender=" + userid.toLowerCase() + " senderAllowed=" + authz.senderAllowed + " authorizerConfigured=" + authz.authorizerConfigured + " commandAuthorized=" + String(commandAuthorized));
774
+ if (!(authz.shouldComputeAuth && authz.commandAuthorized !== true)) return [3 /*break*/, 49];
775
+ prompt_3 = command_auth_js_1.buildWecomUnauthorizedCommandPrompt({
776
+ senderUserId: userid,
777
+ dmPolicy: authz.dmPolicy,
778
+ scope: "bot"
779
+ });
780
+ streamStore.updateStream(streamId, function (s) {
781
+ s.finished = true;
782
+ s.content = prompt_3;
783
+ });
784
+ _54.label = 45;
785
+ case 45:
786
+ _54.trys.push([45, 47, , 48]);
787
+ return [4 /*yield*/, sendBotFallbackPromptNow({ streamId: streamId, text: prompt_3 })];
788
+ case 46:
789
+ _54.sent();
790
+ (_24 = (_23 = target.runtime).log) === null || _24 === void 0 ? void 0 : _24.call(_23, "[webhook] authz: \u672A\u6388\u6743\u547D\u4EE4\u5DF2\u63D0\u793A\u7528\u6237 streamId=" + streamId);
791
+ return [3 /*break*/, 48];
792
+ case 47:
793
+ err_7 = _54.sent();
794
+ (_26 = (_25 = target.runtime).error) === null || _26 === void 0 ? void 0 : _26.call(_25, "[webhook] authz: \u672A\u6388\u6743\u547D\u4EE4\u63D0\u793A\u63A8\u9001\u5931\u8D25 streamId=" + streamId + ": " + String(err_7));
795
+ return [3 /*break*/, 48];
796
+ case 48:
797
+ streamStore.onStreamFinished(streamId);
798
+ return [2 /*return*/];
799
+ case 49:
800
+ rawBodyNormalized = rawBody.trim();
801
+ isResetCommand = /^\/(new|reset)(?:\s|$)/i.test(rawBodyNormalized);
802
+ resetCommandKind = isResetCommand ? ((_29 = (_28 = (_27 = rawBodyNormalized.match(/^\/(new|reset)/i)) === null || _27 === void 0 ? void 0 : _27[1]) === null || _28 === void 0 ? void 0 : _28.toLowerCase()) !== null && _29 !== void 0 ? _29 : "new") : null;
803
+ attachments = mediaPath ? [{
804
+ name: (media === null || media === void 0 ? void 0 : media.filename) || "file",
805
+ mimeType: mediaType,
806
+ url: node_url_1.pathToFileURL(mediaPath).href
807
+ }] : undefined;
808
+ if (!(videoFirstFramePath && attachments)) return [3 /*break*/, 51];
809
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:path")); })];
810
+ case 50:
811
+ pathModule = _54.sent();
812
+ attachments.push({
813
+ name: pathModule.basename(videoFirstFramePath),
814
+ mimeType: "image/jpeg",
815
+ url: node_url_1.pathToFileURL(videoFirstFramePath).href
816
+ });
817
+ _54.label = 51;
818
+ case 51:
819
+ ctxPayload = core.channel.reply.finalizeInboundContext({
820
+ Body: body,
821
+ RawBody: rawBody,
822
+ CommandBody: rawBody,
823
+ Attachments: attachments,
824
+ From: chatType === "group" ? "wecom:group:" + chatId : "wecom:" + userid,
825
+ To: "wecom:" + chatId,
826
+ SessionKey: route.sessionKey,
827
+ AccountId: route.accountId,
828
+ ChatType: chatType,
829
+ ConversationLabel: fromLabel,
830
+ SenderName: senderName,
831
+ SenderId: userid,
832
+ Provider: "wecom",
833
+ Surface: "wecom",
834
+ MessageSid: msg.msgid,
835
+ CommandAuthorized: commandAuthorized,
836
+ OriginatingChannel: "wecom",
837
+ OriginatingTo: "wecom:" + chatId,
838
+ MediaPath: mediaPath,
839
+ MediaType: mediaType,
840
+ MediaUrl: mediaPath
841
+ });
842
+ // ──────────────────────────────────────────────────────────────────
843
+ // 9. 会话记录
844
+ // ──────────────────────────────────────────────────────────────────
845
+ return [4 /*yield*/, core.channel.session.recordInboundSession({
846
+ storePath: storePath,
847
+ sessionKey: (_30 = ctxPayload.SessionKey) !== null && _30 !== void 0 ? _30 : route.sessionKey,
848
+ ctx: ctxPayload,
849
+ onRecordError: function (err) {
850
+ var _a, _b;
851
+ (_b = (_a = target.runtime).error) === null || _b === void 0 ? void 0 : _b.call(_a, "[webhook] session meta update failed: " + String(err));
852
+ }
853
+ })];
854
+ case 52:
855
+ // ──────────────────────────────────────────────────────────────────
856
+ // 9. 会话记录
857
+ // ──────────────────────────────────────────────────────────────────
858
+ _54.sent();
859
+ tableMode = core.channel.text.resolveMarkdownTableMode({
860
+ cfg: config,
861
+ channel: "wecom",
862
+ accountId: account.accountId
863
+ });
864
+ cfgForDispatch = helpers_js_1.buildCfgForDispatch(config);
865
+ // ──────────────────────────────────────────────────────────────────
866
+ // 12. 调度 Agent 回复(核心 deliver 回调)
867
+ // ──────────────────────────────────────────────────────────────────
868
+ return [4 /*yield*/, core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
869
+ ctx: ctxPayload,
870
+ cfg: cfgForDispatch,
871
+ replyOptions: {
872
+ disableBlockStreaming: false
873
+ },
874
+ dispatcherOptions: {
875
+ deliver: function (payload, info) { return __awaiter(_this, void 0, void 0, function () {
876
+ var text, adapted, lineText_1, confirmText_1, err_12, thinkRegex, thinks, trimmedText, parsed_1, isSingleChat, responseUrl_2, cardTitle, cardDesc, buttons, _a, current, candidates, _i, candidates_2, p, fs, pathModule, buf, ext, imageExts, contentType, base64, md5, err_13, now, deadline, switchAt, nearTimeout, agentOk, prompt_4, err_14, mediaDirectivePaths, mediaDirectiveRe, _mdMatch, p, home, mediaUrls, _loop_3, _b, mediaUrls_1, mPath, state_1, mode, nextText;
877
+ var _this = this;
878
+ var _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37;
879
+ return __generator(this, function (_38) {
880
+ switch (_38.label) {
881
+ case 0:
882
+ text = (_c = payload.text) !== null && _c !== void 0 ? _c : "";
883
+ adapted = endpoint_event_adapter_js_1.adaptEndpointEvent({
884
+ rawText: text,
885
+ currentEventType: info.kind
886
+ });
887
+ if (adapted.subAgentStartLine) {
888
+ if (adapted.subAgentRunId)
889
+ ignoredSubAgentRunIds.add(adapted.subAgentRunId);
890
+ lineText_1 = adapted.subAgentStartLine.trim();
891
+ streamStore.updateStream(streamId, function (s) {
892
+ helpers_js_1.appendDmContent(s, lineText_1);
893
+ var nextText = s.content ? (s.content + "\n\n" + lineText_1).trim() : lineText_1;
894
+ s.content = helpers_js_1.truncateUtf8Bytes(nextText, types_js_1.STREAM_MAX_BYTES);
895
+ });
896
+ (_d = target.statusSink) === null || _d === void 0 ? void 0 : _d.call(target, { lastOutboundAt: Date.now() });
897
+ return [2 /*return*/];
898
+ }
899
+ if (adapted.subAgentRunId && ignoredSubAgentRunIds.has(adapted.subAgentRunId)) {
900
+ (_f = (_e = target.runtime).log) === null || _f === void 0 ? void 0 : _f.call(_e, "[webhook] ignore sub-agent event: agent_run_id=" + adapted.subAgentRunId + " event=" + (adapted.eventType || info.kind));
901
+ return [2 /*return*/];
902
+ }
903
+ if (!adapted.confirmationText) return [3 /*break*/, 5];
904
+ if (adapted.confirmationDedupKey && handledConfirmationKeys.has(adapted.confirmationDedupKey)) {
905
+ (_h = (_g = target.runtime).log) === null || _h === void 0 ? void 0 : _h.call(_g, "[webhook] confirmation duplicate skipped: " + adapted.confirmationDedupKey);
906
+ return [2 /*return*/];
907
+ }
908
+ if (adapted.confirmationDedupKey)
909
+ handledConfirmationKeys.add(adapted.confirmationDedupKey);
910
+ confirmText_1 = adapted.confirmationText.trim();
911
+ if (!confirmText_1) return [3 /*break*/, 4];
912
+ streamStore.updateStream(streamId, function (s) {
913
+ helpers_js_1.appendDmContent(s, confirmText_1);
914
+ });
915
+ _38.label = 1;
916
+ case 1:
917
+ _38.trys.push([1, 3, , 4]);
918
+ return [4 /*yield*/, sendBotImmediateTextNow({ streamId: streamId, text: confirmText_1 })];
919
+ case 2:
920
+ _38.sent();
921
+ (_k = (_j = target.runtime).log) === null || _k === void 0 ? void 0 : _k.call(_j, "[webhook] confirmation pushed immediately streamId=" + streamId);
922
+ return [3 /*break*/, 4];
923
+ case 3:
924
+ err_12 = _38.sent();
925
+ (_m = (_l = target.runtime).error) === null || _m === void 0 ? void 0 : _m.call(_l, "[webhook] confirmation immediate push failed streamId=" + streamId + ": " + String(err_12));
926
+ return [3 /*break*/, 4];
927
+ case 4: return [2 /*return*/];
928
+ case 5:
929
+ if (adapted.ignoreAsNoise) {
930
+ (_p = (_o = target.runtime).log) === null || _p === void 0 ? void 0 : _p.call(_o, "[webhook] passthrough event ignored for outbound: " + (adapted.eventType || info.kind));
931
+ return [2 /*return*/];
932
+ }
933
+ thinkRegex = /<think>([\s\S]*?)<\/think>/g;
934
+ thinks = [];
935
+ text = text.replace(thinkRegex, function (match) {
936
+ thinks.push(match);
937
+ return "__THINK_PLACEHOLDER_" + (thinks.length - 1) + "__";
938
+ });
939
+ trimmedText = text.trim();
940
+ if (!(trimmedText.startsWith("{") && trimmedText.includes('"template_card"'))) return [3 /*break*/, 11];
941
+ _38.label = 6;
942
+ case 6:
943
+ _38.trys.push([6, 10, , 11]);
944
+ parsed_1 = JSON.parse(trimmedText);
945
+ if (!parsed_1.template_card) return [3 /*break*/, 9];
946
+ isSingleChat = chatType !== "group";
947
+ responseUrl_2 = getActiveReplyUrl(streamId);
948
+ if (!(responseUrl_2 && isSingleChat)) return [3 /*break*/, 8];
949
+ // 单聊且有 response_url:发送卡片
950
+ return [4 /*yield*/, useActiveReplyOnce(streamId, function (_a) {
951
+ var responseUrl = _a.responseUrl, proxyUrl = _a.proxyUrl;
952
+ return __awaiter(_this, void 0, void 0, function () {
953
+ var res;
954
+ return __generator(this, function (_b) {
955
+ switch (_b.label) {
956
+ case 0: return [4 /*yield*/, http_js_1.wecomFetch(responseUrl, {
957
+ method: "POST",
958
+ headers: { "Content-Type": "application/json" },
959
+ body: JSON.stringify({
960
+ msgtype: "template_card",
961
+ template_card: parsed_1.template_card
962
+ })
963
+ }, { proxyUrl: proxyUrl, timeoutMs: types_js_1.REQUEST_TIMEOUT_MS })];
964
+ case 1:
965
+ res = _b.sent();
966
+ if (!res.ok) {
967
+ throw new Error("template_card send failed: " + res.status);
968
+ }
969
+ return [2 /*return*/];
970
+ }
971
+ });
972
+ });
973
+ })];
974
+ case 7:
975
+ // 单聊且有 response_url:发送卡片
976
+ _38.sent();
977
+ (_r = (_q = target.runtime).log) === null || _r === void 0 ? void 0 : _r.call(_q, "[webhook] sent template_card: task_id=" + parsed_1.template_card.task_id);
978
+ streamStore.updateStream(streamId, function (s) {
979
+ s.finished = true;
980
+ s.content = "[已发送交互卡片]";
981
+ });
982
+ (_s = target.statusSink) === null || _s === void 0 ? void 0 : _s.call(target, { lastOutboundAt: Date.now() });
983
+ return [2 /*return*/];
984
+ case 8:
985
+ // 群聊 或 无 response_url:降级为文本描述
986
+ (_u = (_t = target.runtime).log) === null || _u === void 0 ? void 0 : _u.call(_t, "[webhook] template_card fallback to text (group=" + !isSingleChat + ", hasUrl=" + !!responseUrl_2 + ")");
987
+ cardTitle = ((_v = parsed_1.template_card.main_title) === null || _v === void 0 ? void 0 : _v.title) || "交互卡片";
988
+ cardDesc = ((_w = parsed_1.template_card.main_title) === null || _w === void 0 ? void 0 : _w.desc) || "";
989
+ buttons = ((_x = parsed_1.template_card.button_list) === null || _x === void 0 ? void 0 : _x.map(function (b) { return b.text; }).join(" / ")) || "";
990
+ text = "\uD83D\uDCCB **" + cardTitle + "**" + (cardDesc ? "\n" + cardDesc : "") + (buttons ? "\n\n\u9009\u9879: " + buttons : "");
991
+ _38.label = 9;
992
+ case 9: return [3 /*break*/, 11];
993
+ case 10:
994
+ _a = _38.sent();
995
+ return [3 /*break*/, 11];
996
+ case 11:
997
+ // ── Markdown 表格转换 ──
998
+ text = core.channel.text.convertMarkdownTables(text, tableMode);
999
+ // ── 还原 <think> 标签 ──
1000
+ thinks.forEach(function (think, i) {
1001
+ text = text.replace("__THINK_PLACEHOLDER_" + i + "__", think);
1002
+ });
1003
+ current = streamStore.getStream(streamId);
1004
+ if (!current)
1005
+ return [2 /*return*/];
1006
+ if (!current.images)
1007
+ current.images = [];
1008
+ if (!current.agentMediaKeys)
1009
+ current.agentMediaKeys = [];
1010
+ if (!(!payload.mediaUrl && !((_z = (_y = payload.mediaUrls) === null || _y === void 0 ? void 0 : _y.length) !== null && _z !== void 0 ? _z : 0) && text.includes("/"))) return [3 /*break*/, 19];
1011
+ candidates = helpers_js_1.extractLocalImagePathsFromText({ text: text, mustAlsoAppearIn: rawBody });
1012
+ if (!(candidates.length > 0)) return [3 /*break*/, 19];
1013
+ (_1 = (_0 = target.runtime).log) === null || _1 === void 0 ? void 0 : _1.call(_0, "media: \u4ECE\u8F93\u51FA\u6587\u672C\u63A8\u65AD\u5230\u672C\u673A\u56FE\u7247\u8DEF\u5F84\uFF08\u6765\u81EA\u7528\u6237\u539F\u6D88\u606F\uFF09count=" + candidates.length);
1014
+ _i = 0, candidates_2 = candidates;
1015
+ _38.label = 12;
1016
+ case 12:
1017
+ if (!(_i < candidates_2.length)) return [3 /*break*/, 19];
1018
+ p = candidates_2[_i];
1019
+ _38.label = 13;
1020
+ case 13:
1021
+ _38.trys.push([13, 17, , 18]);
1022
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:fs/promises")); })];
1023
+ case 14:
1024
+ fs = _38.sent();
1025
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:path")); })];
1026
+ case 15:
1027
+ pathModule = _38.sent();
1028
+ return [4 /*yield*/, fs.readFile(p)];
1029
+ case 16:
1030
+ buf = _38.sent();
1031
+ ext = pathModule.extname(p).slice(1).toLowerCase();
1032
+ imageExts = {
1033
+ jpg: "image/jpeg",
1034
+ jpeg: "image/jpeg",
1035
+ png: "image/png",
1036
+ gif: "image/gif",
1037
+ webp: "image/webp",
1038
+ bmp: "image/bmp"
1039
+ };
1040
+ contentType = (_2 = imageExts[ext]) !== null && _2 !== void 0 ? _2 : "application/octet-stream";
1041
+ if (!contentType.startsWith("image/")) {
1042
+ return [3 /*break*/, 18];
1043
+ }
1044
+ base64 = buf.toString("base64");
1045
+ md5 = helpers_js_1.computeMd5(buf);
1046
+ current.images.push({ base64: base64, md5: md5 });
1047
+ return [3 /*break*/, 18];
1048
+ case 17:
1049
+ err_13 = _38.sent();
1050
+ (_4 = (_3 = target.runtime).error) === null || _4 === void 0 ? void 0 : _4.call(_3, "[webhook] media: \u8BFB\u53D6\u672C\u673A\u56FE\u7247\u5931\u8D25 path=" + p + ": " + String(err_13));
1051
+ return [3 /*break*/, 18];
1052
+ case 18:
1053
+ _i++;
1054
+ return [3 /*break*/, 12];
1055
+ case 19:
1056
+ // ── 每次 deliver 都追加到 dmContent(不受 STREAM_MAX_BYTES 限制) ──
1057
+ if (text.trim()) {
1058
+ streamStore.updateStream(streamId, function (s) {
1059
+ helpers_js_1.appendDmContent(s, text);
1060
+ });
1061
+ }
1062
+ now = Date.now();
1063
+ deadline = current.createdAt + types_js_1.BOT_WINDOW_MS;
1064
+ switchAt = deadline - types_js_1.BOT_SWITCH_MARGIN_MS;
1065
+ nearTimeout = !current.fallbackMode && !current.finished && now >= switchAt;
1066
+ if (!nearTimeout) return [3 /*break*/, 24];
1067
+ agentOk = helpers_js_1.isAgentConfigured(target);
1068
+ prompt_4 = helpers_js_1.buildFallbackPrompt({
1069
+ kind: "timeout",
1070
+ agentConfigured: agentOk,
1071
+ userId: current.userId,
1072
+ chatType: current.chatType
1073
+ });
1074
+ (_6 = (_5 = target.runtime).log) === null || _6 === void 0 ? void 0 : _6.call(_5, "[webhook] fallback(timeout): \u89E6\u53D1\u5207\u6362\uFF08\u63A5\u8FD1 6 \u5206\u949F\uFF09chatType=" + current.chatType + " agentConfigured=" + agentOk + " hasResponseUrl=" + Boolean(getActiveReplyUrl(streamId)));
1075
+ streamStore.updateStream(streamId, function (s) {
1076
+ var _a;
1077
+ s.fallbackMode = "timeout";
1078
+ s.finished = true;
1079
+ s.content = prompt_4;
1080
+ s.fallbackPromptSentAt = (_a = s.fallbackPromptSentAt) !== null && _a !== void 0 ? _a : Date.now();
1081
+ });
1082
+ _38.label = 20;
1083
+ case 20:
1084
+ _38.trys.push([20, 22, , 23]);
1085
+ return [4 /*yield*/, sendBotFallbackPromptNow({ streamId: streamId, text: prompt_4 })];
1086
+ case 21:
1087
+ _38.sent();
1088
+ (_8 = (_7 = target.runtime).log) === null || _8 === void 0 ? void 0 : _8.call(_7, "[webhook] fallback(timeout): \u7FA4\u5185\u63D0\u793A\u5DF2\u63A8\u9001");
1089
+ return [3 /*break*/, 23];
1090
+ case 22:
1091
+ err_14 = _38.sent();
1092
+ (_10 = (_9 = target.runtime).error) === null || _10 === void 0 ? void 0 : _10.call(_9, "[webhook] fallback(timeout) prompt push failed streamId=" + streamId + ": " + String(err_14));
1093
+ return [3 /*break*/, 23];
1094
+ case 23: return [2 /*return*/];
1095
+ case 24:
1096
+ mediaDirectivePaths = [];
1097
+ mediaDirectiveRe = /^MEDIA:\s*`?([^\n`]+?)`?\s*$/gm;
1098
+ while ((_mdMatch = mediaDirectiveRe.exec(text)) !== null) {
1099
+ p = ((_11 = _mdMatch[1]) !== null && _11 !== void 0 ? _11 : "").trim();
1100
+ if (!p)
1101
+ continue;
1102
+ if (p.startsWith("~/") || p === "~") {
1103
+ home = node_os_1["default"].homedir() || "/root";
1104
+ p = p.replace(/^~/, home);
1105
+ }
1106
+ if (!mediaDirectivePaths.includes(p))
1107
+ mediaDirectivePaths.push(p);
1108
+ }
1109
+ if (mediaDirectivePaths.length > 0) {
1110
+ text = text.replace(/^MEDIA:\s*`?[^\n`]+?`?\s*$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
1111
+ }
1112
+ mediaUrls = Array.from(new Set(__spreadArrays((payload.mediaUrls || []), (payload.mediaUrl ? [payload.mediaUrl] : []), mediaDirectivePaths)));
1113
+ _loop_3 = function (mPath) {
1114
+ var contentType, filename, buf, looksLikeUrl, loaded, fs, pathMod, ext, base64, md5, agentOk, alreadySent, err_15, prompt_5, err_16, err_17, agentOk, fallbackFilename, sendErr_1, prompt_6, pushErr_1;
1115
+ return __generator(this, function (_a) {
1116
+ switch (_a.label) {
1117
+ case 0:
1118
+ contentType = void 0;
1119
+ filename = mPath.split("/").pop() || "attachment";
1120
+ _a.label = 1;
1121
+ case 1:
1122
+ _a.trys.push([1, 18, , 27]);
1123
+ buf = void 0;
1124
+ looksLikeUrl = /^https?:\/\//i.test(mPath);
1125
+ if (!looksLikeUrl) return [3 /*break*/, 3];
1126
+ return [4 /*yield*/, core.channel.media.fetchRemoteMedia({ url: mPath })];
1127
+ case 2:
1128
+ loaded = _a.sent();
1129
+ buf = loaded.buffer;
1130
+ contentType = loaded.contentType;
1131
+ filename = (_12 = loaded.fileName) !== null && _12 !== void 0 ? _12 : "attachment";
1132
+ return [3 /*break*/, 7];
1133
+ case 3: return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:fs/promises")); })];
1134
+ case 4:
1135
+ fs = _a.sent();
1136
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:path")); })];
1137
+ case 5:
1138
+ pathMod = _a.sent();
1139
+ return [4 /*yield*/, fs.readFile(mPath)];
1140
+ case 6:
1141
+ buf = _a.sent();
1142
+ filename = pathMod.basename(mPath);
1143
+ ext = pathMod.extname(mPath).slice(1).toLowerCase();
1144
+ contentType = (_13 = helpers_js_1.MIME_BY_EXT[ext]) !== null && _13 !== void 0 ? _13 : "application/octet-stream";
1145
+ _a.label = 7;
1146
+ case 7:
1147
+ if (!(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith("image/"))) return [3 /*break*/, 8];
1148
+ base64 = buf.toString("base64");
1149
+ md5 = helpers_js_1.computeMd5(buf);
1150
+ current.images.push({ base64: base64, md5: md5 });
1151
+ (_15 = (_14 = target.runtime).log) === null || _15 === void 0 ? void 0 : _15.call(_14, "[webhook] media: \u8BC6\u522B\u4E3A\u56FE\u7247 contentType=" + contentType + " filename=" + filename);
1152
+ return [3 /*break*/, 17];
1153
+ case 8:
1154
+ agentOk = helpers_js_1.isAgentConfigured(target);
1155
+ alreadySent = current.agentMediaKeys.includes(mPath);
1156
+ (_17 = (_16 = target.runtime).log) === null || _17 === void 0 ? void 0 : _17.call(_16, "[webhook] fallback(media): \u68C0\u6D4B\u5230\u975E\u56FE\u7247\u6587\u4EF6 chatType=" + current.chatType + " contentType=" + (contentType !== null && contentType !== void 0 ? contentType : "unknown") + " filename=" + filename + " agentConfigured=" + agentOk + " alreadySent=" + alreadySent + " hasResponseUrl=" + Boolean(getActiveReplyUrl(streamId)));
1157
+ if (!(agentOk && !alreadySent && current.userId)) return [3 /*break*/, 12];
1158
+ _a.label = 9;
1159
+ case 9:
1160
+ _a.trys.push([9, 11, , 12]);
1161
+ return [4 /*yield*/, agentDmMedia({
1162
+ target: target,
1163
+ userId: current.userId,
1164
+ mediaUrlOrPath: mPath,
1165
+ contentType: contentType,
1166
+ filename: filename
1167
+ })];
1168
+ case 10:
1169
+ _a.sent();
1170
+ (_19 = (_18 = target.runtime).log) === null || _19 === void 0 ? void 0 : _19.call(_18, "[webhook] fallback(media): \u6587\u4EF6\u5DF2\u901A\u8FC7 Agent \u79C1\u4FE1\u53D1\u9001 user=" + current.userId);
1171
+ streamStore.updateStream(streamId, function (s) {
1172
+ var _a;
1173
+ s.agentMediaKeys = Array.from(new Set(__spreadArrays(((_a = s.agentMediaKeys) !== null && _a !== void 0 ? _a : []), [mPath])));
1174
+ });
1175
+ return [3 /*break*/, 12];
1176
+ case 11:
1177
+ err_15 = _a.sent();
1178
+ (_21 = (_20 = target.runtime).error) === null || _21 === void 0 ? void 0 : _21.call(_20, "[webhook] Agent DM \u5A92\u4F53\u53D1\u9001\u5931\u8D25: " + String(err_15));
1179
+ return [3 /*break*/, 12];
1180
+ case 12:
1181
+ if (!!current.fallbackMode) return [3 /*break*/, 16];
1182
+ prompt_5 = helpers_js_1.buildFallbackPrompt({
1183
+ kind: "media",
1184
+ agentConfigured: agentOk,
1185
+ userId: current.userId,
1186
+ filename: filename,
1187
+ chatType: current.chatType
1188
+ });
1189
+ streamStore.updateStream(streamId, function (s) {
1190
+ var _a;
1191
+ s.fallbackMode = "media";
1192
+ s.finished = true;
1193
+ s.content = prompt_5;
1194
+ s.fallbackPromptSentAt = (_a = s.fallbackPromptSentAt) !== null && _a !== void 0 ? _a : Date.now();
1195
+ });
1196
+ _a.label = 13;
1197
+ case 13:
1198
+ _a.trys.push([13, 15, , 16]);
1199
+ return [4 /*yield*/, sendBotFallbackPromptNow({ streamId: streamId, text: prompt_5 })];
1200
+ case 14:
1201
+ _a.sent();
1202
+ (_23 = (_22 = target.runtime).log) === null || _23 === void 0 ? void 0 : _23.call(_22, "[webhook] fallback(media): \u7FA4\u5185\u63D0\u793A\u5DF2\u63A8\u9001");
1203
+ return [3 /*break*/, 16];
1204
+ case 15:
1205
+ err_16 = _a.sent();
1206
+ (_25 = (_24 = target.runtime).error) === null || _25 === void 0 ? void 0 : _25.call(_24, "[webhook] fallback(media) prompt push failed streamId=" + streamId + ": " + String(err_16));
1207
+ return [3 /*break*/, 16];
1208
+ case 16: return [2 /*return*/, { value: void 0 }];
1209
+ case 17: return [3 /*break*/, 27];
1210
+ case 18:
1211
+ err_17 = _a.sent();
1212
+ (_27 = (_26 = target.runtime).error) === null || _27 === void 0 ? void 0 : _27.call(_26, "[webhook] \u5A92\u4F53\u5904\u7406\u5931\u8D25: " + mPath + ": " + String(err_17));
1213
+ agentOk = helpers_js_1.isAgentConfigured(target);
1214
+ fallbackFilename = filename || mPath.split("/").pop() || "attachment";
1215
+ if (!(agentOk && current.userId && !current.agentMediaKeys.includes(mPath))) return [3 /*break*/, 22];
1216
+ _a.label = 19;
1217
+ case 19:
1218
+ _a.trys.push([19, 21, , 22]);
1219
+ return [4 /*yield*/, agentDmMedia({
1220
+ target: target,
1221
+ userId: current.userId,
1222
+ mediaUrlOrPath: mPath,
1223
+ contentType: contentType,
1224
+ filename: fallbackFilename
1225
+ })];
1226
+ case 20:
1227
+ _a.sent();
1228
+ streamStore.updateStream(streamId, function (s) {
1229
+ var _a;
1230
+ s.agentMediaKeys = Array.from(new Set(__spreadArrays(((_a = s.agentMediaKeys) !== null && _a !== void 0 ? _a : []), [mPath])));
1231
+ });
1232
+ (_29 = (_28 = target.runtime).log) === null || _29 === void 0 ? void 0 : _29.call(_28, "[webhook] fallback(error): \u5A92\u4F53\u5904\u7406\u5931\u8D25\u540E\u5DF2\u901A\u8FC7 Agent \u79C1\u4FE1\u53D1\u9001 user=" + current.userId);
1233
+ return [3 /*break*/, 22];
1234
+ case 21:
1235
+ sendErr_1 = _a.sent();
1236
+ (_31 = (_30 = target.runtime).error) === null || _31 === void 0 ? void 0 : _31.call(_30, "[webhook] fallback(error): \u5A92\u4F53\u5904\u7406\u5931\u8D25\u540E\u7684 Agent \u79C1\u4FE1\u53D1\u9001\u4E5F\u5931\u8D25: " + String(sendErr_1));
1237
+ return [3 /*break*/, 22];
1238
+ case 22:
1239
+ if (!!current.fallbackMode) return [3 /*break*/, 26];
1240
+ prompt_6 = helpers_js_1.buildFallbackPrompt({
1241
+ kind: "error",
1242
+ agentConfigured: agentOk,
1243
+ userId: current.userId,
1244
+ filename: fallbackFilename,
1245
+ chatType: current.chatType
1246
+ });
1247
+ streamStore.updateStream(streamId, function (s) {
1248
+ var _a;
1249
+ s.fallbackMode = "error";
1250
+ s.finished = true;
1251
+ s.content = prompt_6;
1252
+ s.fallbackPromptSentAt = (_a = s.fallbackPromptSentAt) !== null && _a !== void 0 ? _a : Date.now();
1253
+ });
1254
+ _a.label = 23;
1255
+ case 23:
1256
+ _a.trys.push([23, 25, , 26]);
1257
+ return [4 /*yield*/, sendBotFallbackPromptNow({ streamId: streamId, text: prompt_6 })];
1258
+ case 24:
1259
+ _a.sent();
1260
+ (_33 = (_32 = target.runtime).log) === null || _33 === void 0 ? void 0 : _33.call(_32, "[webhook] fallback(error): \u7FA4\u5185\u63D0\u793A\u5DF2\u63A8\u9001");
1261
+ return [3 /*break*/, 26];
1262
+ case 25:
1263
+ pushErr_1 = _a.sent();
1264
+ (_35 = (_34 = target.runtime).error) === null || _35 === void 0 ? void 0 : _35.call(_34, "[webhook] fallback(error) prompt push failed streamId=" + streamId + ": " + String(pushErr_1));
1265
+ return [3 /*break*/, 26];
1266
+ case 26: return [2 /*return*/, { value: void 0 }];
1267
+ case 27: return [2 /*return*/];
1268
+ }
1269
+ });
1270
+ };
1271
+ _b = 0, mediaUrls_1 = mediaUrls;
1272
+ _38.label = 25;
1273
+ case 25:
1274
+ if (!(_b < mediaUrls_1.length)) return [3 /*break*/, 28];
1275
+ mPath = mediaUrls_1[_b];
1276
+ return [5 /*yield**/, _loop_3(mPath)];
1277
+ case 26:
1278
+ state_1 = _38.sent();
1279
+ if (typeof state_1 === "object")
1280
+ return [2 /*return*/, state_1.value];
1281
+ _38.label = 27;
1282
+ case 27:
1283
+ _b++;
1284
+ return [3 /*break*/, 25];
1285
+ case 28:
1286
+ mode = (_36 = streamStore.getStream(streamId)) === null || _36 === void 0 ? void 0 : _36.fallbackMode;
1287
+ if (mode)
1288
+ return [2 /*return*/];
1289
+ nextText = current.content
1290
+ ? (current.content + "\n\n" + text).trim()
1291
+ : text.trim();
1292
+ streamStore.updateStream(streamId, function (s) {
1293
+ var _a;
1294
+ s.content = helpers_js_1.truncateUtf8Bytes(nextText, types_js_1.STREAM_MAX_BYTES);
1295
+ if ((_a = current.images) === null || _a === void 0 ? void 0 : _a.length)
1296
+ s.images = current.images;
1297
+ });
1298
+ (_37 = target.statusSink) === null || _37 === void 0 ? void 0 : _37.call(target, { lastOutboundAt: Date.now() });
1299
+ return [2 /*return*/];
1300
+ }
1301
+ });
1302
+ }); },
1303
+ onError: function (err) {
1304
+ var _a, _b;
1305
+ (_b = (_a = target.runtime).error) === null || _b === void 0 ? void 0 : _b.call(_a, "[webhook] Agent reply failed (streamId=" + streamId + "): " + String(err));
1306
+ }
1307
+ }
1308
+ })];
1309
+ case 53:
1310
+ // ──────────────────────────────────────────────────────────────────
1311
+ // 12. 调度 Agent 回复(核心 deliver 回调)
1312
+ // ──────────────────────────────────────────────────────────────────
1313
+ _54.sent();
1314
+ // ──────────────────────────────────────────────────────────────────
1315
+ // 13. 后处理:/new /reset 中文回执
1316
+ // ──────────────────────────────────────────────────────────────────
1317
+ if (isResetCommand) {
1318
+ current = streamStore.getStream(streamId);
1319
+ if (current && !((_31 = current.content) === null || _31 === void 0 ? void 0 : _31.trim())) {
1320
+ ackText_1 = resetCommandKind === "reset" ? "✅ 已重置会话。" : "✅ 已开启新会话。";
1321
+ streamStore.updateStream(streamId, function (s) { s.content = ackText_1; s.finished = true; });
1322
+ }
1323
+ }
1324
+ // 空内容兜底
1325
+ streamStore.updateStream(streamId, function (s) {
1326
+ var _a, _b, _c, _d;
1327
+ if (!s.content.trim() && !((_b = (_a = s.images) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0)) {
1328
+ var hasMediaDelivered = ((_d = (_c = s.agentMediaKeys) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) > 0;
1329
+ var hasFallback = Boolean(s.fallbackMode);
1330
+ if (hasMediaDelivered) {
1331
+ s.content = "✅ 文件已发送。";
1332
+ }
1333
+ else if (!hasFallback) {
1334
+ s.content = "当前没有可展示的回复内容";
1335
+ }
1336
+ }
1337
+ });
1338
+ streamStore.markFinished(streamId);
1339
+ finishedState = streamStore.getStream(streamId);
1340
+ if (!((finishedState === null || finishedState === void 0 ? void 0 : finishedState.fallbackMode) === "timeout" && !finishedState.finalDeliveredAt)) return [3 /*break*/, 59];
1341
+ if (!!helpers_js_1.isAgentConfigured(target)) return [3 /*break*/, 54];
1342
+ // Agent not configured - group prompt already explains the situation.
1343
+ streamStore.updateStream(streamId, function (s) { s.finalDeliveredAt = Date.now(); });
1344
+ return [3 /*break*/, 59];
1345
+ case 54:
1346
+ if (!finishedState.userId) return [3 /*break*/, 59];
1347
+ dmText = ((_32 = finishedState.dmContent) !== null && _32 !== void 0 ? _32 : "").trim();
1348
+ if (!dmText) return [3 /*break*/, 58];
1349
+ _54.label = 55;
1350
+ case 55:
1351
+ _54.trys.push([55, 57, , 58]);
1352
+ (_34 = (_33 = target.runtime).log) === null || _34 === void 0 ? void 0 : _34.call(_33, "[webhook] fallback(timeout): \u5F00\u59CB\u901A\u8FC7 Agent \u79C1\u4FE1\u53D1\u9001\u5269\u4F59\u5185\u5BB9 user=" + finishedState.userId + " len=" + dmText.length);
1353
+ return [4 /*yield*/, agentDmText({ target: target, userId: finishedState.userId, text: dmText })];
1354
+ case 56:
1355
+ _54.sent();
1356
+ (_36 = (_35 = target.runtime).log) === null || _36 === void 0 ? void 0 : _36.call(_35, "[webhook] fallback(timeout): Agent \u79C1\u4FE1\u53D1\u9001\u5B8C\u6210 user=" + finishedState.userId);
1357
+ return [3 /*break*/, 58];
1358
+ case 57:
1359
+ err_8 = _54.sent();
1360
+ (_38 = (_37 = target.runtime).error) === null || _38 === void 0 ? void 0 : _38.call(_37, "[webhook] fallback(timeout): Agent \u79C1\u4FE1\u53D1\u9001\u5931\u8D25: " + String(err_8));
1361
+ return [3 /*break*/, 58];
1362
+ case 58:
1363
+ streamStore.updateStream(streamId, function (s) { s.finalDeliveredAt = Date.now(); });
1364
+ _54.label = 59;
1365
+ case 59:
1366
+ stateAfterFinish = streamStore.getStream(streamId);
1367
+ responseUrl = getActiveReplyUrl(streamId);
1368
+ if (!(stateAfterFinish && responseUrl)) return [3 /*break*/, 63];
1369
+ _54.label = 60;
1370
+ case 60:
1371
+ _54.trys.push([60, 62, , 63]);
1372
+ return [4 /*yield*/, pushFinalStreamReplyNow(streamId)];
1373
+ case 61:
1374
+ _54.sent();
1375
+ (_40 = (_39 = target.runtime).log) === null || _40 === void 0 ? void 0 : _40.call(_39, "[webhook] final stream pushed via response_url streamId=" + streamId + ", chatType=" + chatType + ", images=" + ((_42 = (_41 = stateAfterFinish.images) === null || _41 === void 0 ? void 0 : _41.length) !== null && _42 !== void 0 ? _42 : 0));
1376
+ return [3 /*break*/, 63];
1377
+ case 62:
1378
+ err_9 = _54.sent();
1379
+ (_44 = (_43 = target.runtime).error) === null || _44 === void 0 ? void 0 : _44.call(_43, "[webhook] final stream push via response_url failed streamId=" + streamId + ": " + String(err_9));
1380
+ return [3 /*break*/, 63];
1381
+ case 63:
1382
+ // ──────────────────────────────────────────────────────────────────
1383
+ // 16. 更新回执流 + 推进队列
1384
+ // ──────────────────────────────────────────────────────────────────
1385
+ (_46 = (_45 = target.runtime).log) === null || _46 === void 0 ? void 0 : _46.call(_45, "[webhook] queue: \u5F53\u524D\u6279\u6B21\u7ED3\u675F\uFF0C\u5C1D\u8BD5\u63A8\u8FDB\u4E0B\u4E00\u6279 streamId=" + streamId);
1386
+ ackStreamIds = streamStore.drainAckStreamsForBatch(streamId);
1387
+ if (ackStreamIds.length > 0) {
1388
+ mergedDoneHint_1 = "✅ 已合并处理完成,请查看上一条回复。";
1389
+ for (_53 = 0, ackStreamIds_1 = ackStreamIds; _53 < ackStreamIds_1.length; _53++) {
1390
+ ackId = ackStreamIds_1[_53];
1391
+ streamStore.updateStream(ackId, function (s) { s.content = mergedDoneHint_1; s.finished = true; });
1392
+ }
1393
+ (_48 = (_47 = target.runtime).log) === null || _48 === void 0 ? void 0 : _48.call(_47, "[webhook] queue: \u5DF2\u66F4\u65B0\u56DE\u6267\u6D41 count=" + ackStreamIds.length + " batchStreamId=" + streamId);
1394
+ }
1395
+ streamStore.onStreamFinished(streamId);
1396
+ return [2 /*return*/];
1397
+ }
1398
+ });
1399
+ });
1400
+ }
1401
+ exports.startAgentForStream = startAgentForStream;
1402
+ // ============================================================================
1403
+ // 内部辅助:response_url 推送)
1404
+ // ============================================================================
1405
+ /**
1406
+ * 获取 response_url
1407
+ */
1408
+ function getActiveReplyUrl(streamId) {
1409
+ return gateway_js_1.getMonitorState().activeReplyStore.getUrl(streamId);
1410
+ }
1411
+ /**
1412
+ * 使用 response_url 发送一次性请求
1413
+ */
1414
+ function useActiveReplyOnce(streamId, fn) {
1415
+ return __awaiter(this, void 0, void 0, function () {
1416
+ return __generator(this, function (_a) {
1417
+ return [2 /*return*/, gateway_js_1.getMonitorState().activeReplyStore.use(streamId, fn)];
1418
+ });
1419
+ });
1420
+ }
1421
+ /**
1422
+ * 通过 response_url 推送 Bot 兜底提示
1423
+ *
1424
+ * 对齐 lh 版:直接 POST JSON,不加密。
1425
+ */
1426
+ function sendBotFallbackPromptNow(params) {
1427
+ return __awaiter(this, void 0, void 0, function () {
1428
+ var responseUrl;
1429
+ var _this = this;
1430
+ return __generator(this, function (_a) {
1431
+ switch (_a.label) {
1432
+ case 0:
1433
+ responseUrl = getActiveReplyUrl(params.streamId);
1434
+ if (!responseUrl) {
1435
+ throw new Error("no response_url(无法主动推送群内提示)");
1436
+ }
1437
+ return [4 /*yield*/, useActiveReplyOnce(params.streamId, function (_a) {
1438
+ var responseUrl = _a.responseUrl, proxyUrl = _a.proxyUrl;
1439
+ return __awaiter(_this, void 0, void 0, function () {
1440
+ var payload, res;
1441
+ return __generator(this, function (_b) {
1442
+ switch (_b.label) {
1443
+ case 0:
1444
+ payload = {
1445
+ msgtype: "stream",
1446
+ stream: {
1447
+ id: params.streamId,
1448
+ finish: true,
1449
+ content: helpers_js_1.truncateUtf8Bytes(params.text, types_js_1.STREAM_MAX_BYTES) || "1"
1450
+ }
1451
+ };
1452
+ return [4 /*yield*/, http_js_1.wecomFetch(responseUrl, {
1453
+ method: "POST",
1454
+ headers: { "Content-Type": "application/json" },
1455
+ body: JSON.stringify(payload)
1456
+ }, { proxyUrl: proxyUrl, timeoutMs: types_js_1.REQUEST_TIMEOUT_MS })];
1457
+ case 1:
1458
+ res = _b.sent();
1459
+ if (!res.ok) {
1460
+ throw new Error("fallback prompt push failed: " + res.status);
1461
+ }
1462
+ return [2 /*return*/];
1463
+ }
1464
+ });
1465
+ });
1466
+ })];
1467
+ case 1:
1468
+ _a.sent();
1469
+ return [2 /*return*/];
1470
+ }
1471
+ });
1472
+ });
1473
+ }
1474
+ /**
1475
+ * 通过 response_url 立即推送一条独立文本(用于确认请求/确认动作)。
1476
+ * 使用独立 stream.id,避免覆盖主回复流内容。
1477
+ */
1478
+ function sendBotImmediateTextNow(params) {
1479
+ return __awaiter(this, void 0, void 0, function () {
1480
+ var responseUrl, independentId;
1481
+ var _this = this;
1482
+ return __generator(this, function (_a) {
1483
+ switch (_a.label) {
1484
+ case 0:
1485
+ responseUrl = getActiveReplyUrl(params.streamId);
1486
+ if (!responseUrl) {
1487
+ throw new Error("no response_url(无法主动推送确认消息)");
1488
+ }
1489
+ independentId = params.streamId + "-confirm-" + Date.now().toString(36);
1490
+ return [4 /*yield*/, useActiveReplyOnce(params.streamId, function (_a) {
1491
+ var responseUrl = _a.responseUrl, proxyUrl = _a.proxyUrl;
1492
+ return __awaiter(_this, void 0, void 0, function () {
1493
+ var payload, res;
1494
+ return __generator(this, function (_b) {
1495
+ switch (_b.label) {
1496
+ case 0:
1497
+ payload = {
1498
+ msgtype: "stream",
1499
+ stream: {
1500
+ id: independentId,
1501
+ finish: true,
1502
+ content: helpers_js_1.truncateUtf8Bytes(params.text, types_js_1.STREAM_MAX_BYTES) || "1"
1503
+ }
1504
+ };
1505
+ return [4 /*yield*/, http_js_1.wecomFetch(responseUrl, {
1506
+ method: "POST",
1507
+ headers: { "Content-Type": "application/json" },
1508
+ body: JSON.stringify(payload)
1509
+ }, { proxyUrl: proxyUrl, timeoutMs: types_js_1.REQUEST_TIMEOUT_MS })];
1510
+ case 1:
1511
+ res = _b.sent();
1512
+ if (!res.ok) {
1513
+ throw new Error("immediate confirmation push failed: " + res.status);
1514
+ }
1515
+ return [2 /*return*/];
1516
+ }
1517
+ });
1518
+ });
1519
+ })];
1520
+ case 1:
1521
+ _a.sent();
1522
+ return [2 /*return*/];
1523
+ }
1524
+ });
1525
+ });
1526
+ }
1527
+ /**
1528
+ * 通过 response_url 推送最终流帧(对齐 lh 版 pushFinalStreamReplyNow)
1529
+ *
1530
+ * 对齐 lh 版:从 StreamState 构建完整响应,直接 POST JSON,不加密。
1531
+ */
1532
+ function pushFinalStreamReplyNow(streamId) {
1533
+ return __awaiter(this, void 0, void 0, function () {
1534
+ var state, responseUrl, finalReply;
1535
+ var _this = this;
1536
+ return __generator(this, function (_a) {
1537
+ switch (_a.label) {
1538
+ case 0:
1539
+ state = gateway_js_1.getMonitorState().streamStore.getStream(streamId);
1540
+ responseUrl = getActiveReplyUrl(streamId);
1541
+ if (!state || !responseUrl)
1542
+ return [2 /*return*/];
1543
+ finalReply = helpers_js_1.buildStreamReplyFromState(state, types_js_1.STREAM_MAX_BYTES);
1544
+ return [4 /*yield*/, useActiveReplyOnce(streamId, function (_a) {
1545
+ var responseUrl = _a.responseUrl, proxyUrl = _a.proxyUrl;
1546
+ return __awaiter(_this, void 0, void 0, function () {
1547
+ var res;
1548
+ return __generator(this, function (_b) {
1549
+ switch (_b.label) {
1550
+ case 0: return [4 /*yield*/, http_js_1.wecomFetch(responseUrl, {
1551
+ method: "POST",
1552
+ headers: { "Content-Type": "application/json" },
1553
+ body: JSON.stringify(finalReply)
1554
+ }, { proxyUrl: proxyUrl, timeoutMs: types_js_1.REQUEST_TIMEOUT_MS })];
1555
+ case 1:
1556
+ res = _b.sent();
1557
+ if (!res.ok) {
1558
+ throw new Error("final stream push failed: " + res.status);
1559
+ }
1560
+ return [2 /*return*/];
1561
+ }
1562
+ });
1563
+ });
1564
+ })];
1565
+ case 1:
1566
+ _a.sent();
1567
+ return [2 /*return*/];
1568
+ }
1569
+ });
1570
+ });
1571
+ }
1572
+ /**
1573
+ * 通过 Agent 私信发送文本(对齐 lh 版 sendAgentDmText)
1574
+ *
1575
+ * 对齐 lh 版:使用 core.channel.text.chunkText 进行文本分块。
1576
+ */
1577
+ function agentDmText(params) {
1578
+ var _a;
1579
+ return __awaiter(this, void 0, void 0, function () {
1580
+ var target, userId, text, agent, chunks, _i, chunks_1, chunk, trimmed;
1581
+ return __generator(this, function (_b) {
1582
+ switch (_b.label) {
1583
+ case 0:
1584
+ target = params.target, userId = params.userId, text = params.text;
1585
+ if (!((_a = target.account.agent) === null || _a === void 0 ? void 0 : _a.configured)) {
1586
+ throw new Error("Agent credentials not configured");
1587
+ }
1588
+ agent = target.account.agent;
1589
+ chunks = target.core.channel.text.chunkText(text, 20480);
1590
+ _i = 0, chunks_1 = chunks;
1591
+ _b.label = 1;
1592
+ case 1:
1593
+ if (!(_i < chunks_1.length)) return [3 /*break*/, 4];
1594
+ chunk = chunks_1[_i];
1595
+ trimmed = chunk.trim();
1596
+ if (!trimmed)
1597
+ return [3 /*break*/, 3];
1598
+ return [4 /*yield*/, api_client_js_1.sendText({
1599
+ agent: agent,
1600
+ toUser: userId,
1601
+ text: trimmed
1602
+ })];
1603
+ case 2:
1604
+ _b.sent();
1605
+ _b.label = 3;
1606
+ case 3:
1607
+ _i++;
1608
+ return [3 /*break*/, 1];
1609
+ case 4: return [2 /*return*/];
1610
+ }
1611
+ });
1612
+ });
1613
+ }
1614
+ /**
1615
+ * 通过 Agent 私信发送媒体(对齐 lh 版 sendAgentDmMedia)
1616
+ *
1617
+ * 对齐 lh 版:接受 mediaUrlOrPath,内部判断 URL 或本地路径。
1618
+ */
1619
+ function agentDmMedia(params) {
1620
+ var _a;
1621
+ return __awaiter(this, void 0, void 0, function () {
1622
+ var target, userId, mediaUrlOrPath, filename, agent, buffer, inferredContentType, looksLikeUrl, res, _b, _c, fs, mediaType, ct, mediaId;
1623
+ return __generator(this, function (_d) {
1624
+ switch (_d.label) {
1625
+ case 0:
1626
+ target = params.target, userId = params.userId, mediaUrlOrPath = params.mediaUrlOrPath, filename = params.filename;
1627
+ if (!((_a = target.account.agent) === null || _a === void 0 ? void 0 : _a.configured)) {
1628
+ throw new Error("Agent credentials not configured");
1629
+ }
1630
+ agent = target.account.agent;
1631
+ inferredContentType = params.contentType;
1632
+ looksLikeUrl = /^https?:\/\//i.test(mediaUrlOrPath);
1633
+ if (!looksLikeUrl) return [3 /*break*/, 3];
1634
+ return [4 /*yield*/, fetch(mediaUrlOrPath, { signal: AbortSignal.timeout(30000) })];
1635
+ case 1:
1636
+ res = _d.sent();
1637
+ if (!res.ok)
1638
+ throw new Error("media download failed: " + res.status);
1639
+ _c = (_b = Buffer).from;
1640
+ return [4 /*yield*/, res.arrayBuffer()];
1641
+ case 2:
1642
+ buffer = _c.apply(_b, [_d.sent()]);
1643
+ inferredContentType = inferredContentType || res.headers.get("content-type") || "application/octet-stream";
1644
+ return [3 /*break*/, 6];
1645
+ case 3: return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:fs/promises")); })];
1646
+ case 4:
1647
+ fs = _d.sent();
1648
+ return [4 /*yield*/, fs.readFile(mediaUrlOrPath)];
1649
+ case 5:
1650
+ buffer = _d.sent();
1651
+ _d.label = 6;
1652
+ case 6:
1653
+ mediaType = "file";
1654
+ ct = (inferredContentType || "").toLowerCase();
1655
+ if (ct.startsWith("image/"))
1656
+ mediaType = "image";
1657
+ else if (ct.startsWith("audio/"))
1658
+ mediaType = "voice";
1659
+ else if (ct.startsWith("video/"))
1660
+ mediaType = "video";
1661
+ return [4 /*yield*/, api_client_js_1.uploadMedia({ agent: agent, type: mediaType, buffer: buffer, filename: filename })];
1662
+ case 7:
1663
+ mediaId = _d.sent();
1664
+ return [4 /*yield*/, api_client_js_1.sendMedia(__assign({ agent: agent, toUser: userId, mediaId: mediaId,
1665
+ mediaType: mediaType }, (mediaType === "video" ? { title: filename, description: "" } : {})))];
1666
+ case 8:
1667
+ _d.sent();
1668
+ return [2 /*return*/];
1669
+ }
1670
+ });
1671
+ });
1672
+ }