skyloom 1.21.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/gateway/channels/feishu.d.ts.map +1 -1
- package/dist/gateway/channels/feishu.js +119 -15
- package/dist/gateway/channels/feishu.js.map +1 -1
- package/dist/gateway/channels/qq.d.ts.map +1 -1
- package/dist/gateway/channels/qq.js +11 -1
- package/dist/gateway/channels/qq.js.map +1 -1
- package/dist/gateway/channels/wecom.d.ts.map +1 -1
- package/dist/gateway/channels/wecom.js +24 -5
- package/dist/gateway/channels/wecom.js.map +1 -1
- package/dist/gateway/gateway.d.ts.map +1 -1
- package/dist/gateway/gateway.js +39 -14
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/types.d.ts +23 -0
- package/dist/gateway/types.d.ts.map +1 -1
- package/dist/gateway/types.js +12 -0
- package/dist/gateway/types.js.map +1 -1
- package/package.json +1 -1
- package/src/gateway/channels/feishu.ts +112 -12
- package/src/gateway/channels/qq.ts +13 -2
- package/src/gateway/channels/wecom.ts +13 -4
- package/src/gateway/gateway.ts +44 -17
- package/src/gateway/types.ts +34 -0
- package/tests/gateway.test.ts +72 -0
package/README.md
CHANGED
|
@@ -417,9 +417,13 @@ channels:
|
|
|
417
417
|
|
|
418
418
|
| 渠道 | 入站(收) | 鉴权/加密 |
|
|
419
419
|
|------|----------|-----------|
|
|
420
|
-
| 飞书 Feishu |
|
|
421
|
-
| 企业微信 WeCom |
|
|
422
|
-
| QQ Bot |
|
|
420
|
+
| 飞书 Feishu | 文本 + 媒体(图片/语音/视频/文件/表情/富文本 post) | verification token + 可选 AES-256-CBC 解密 + URL challenge |
|
|
421
|
+
| 企业微信 WeCom | 文本 + 媒体(图片/语音/视频/文件/位置) | msg_signature(SHA1) + AES(PKCS7) + GET echostr 验证 |
|
|
422
|
+
| QQ Bot | 文本 + 媒体(attachments) · 群/私聊/频道 @ | Ed25519 验签 + op=13 validation 握手 |
|
|
423
|
+
|
|
424
|
+
**媒体消息**:入站的图片/语音/文件等会被标准化为 `[image: …] [file: …]` 之类的可读描述拼进 prompt,Agent 即使不下载二进制也知道用户发了什么。
|
|
425
|
+
|
|
426
|
+
**飞书卡片 + 流式**:飞书默认以**交互卡片**回复,并在生成过程中**逐步 patch 卡片内容**(节流 ≥600ms),呈现打字机式流式效果。`channels.feishu.renderMode: raw` 可改回纯文本,`streaming: false` 可关流式(改为一次性发送)。
|
|
423
427
|
|
|
424
428
|
> ⚠️ 网关接收外部平台回调,默认绑定 `0.0.0.0`。请放在反向代理/HTTPS 之后,并妥善保管密钥(建议走环境变量 / `secretInput`)。
|
|
425
429
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feishu.d.ts","sourceRoot":"","sources":["../../../src/gateway/channels/feishu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"feishu.d.ts","sourceRoot":"","sources":["../../../src/gateway/channels/feishu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,cAAc,EAA4D,MAAM,UAAU,CAAC;AAIzG,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAYzE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,cAAc,GAAG,IAAI,CA4M3F"}
|
|
@@ -76,6 +76,10 @@ function createFeishuAdapter(cfg, env) {
|
|
|
76
76
|
const encryptKey = (0, helpers_1.resolveSecret)(cfg.encryptKey, env, 'FEISHU_ENCRYPT_KEY');
|
|
77
77
|
const verificationToken = (0, helpers_1.resolveSecret)(cfg.verificationToken, env, 'FEISHU_VERIFICATION_TOKEN');
|
|
78
78
|
const base = cfg.domain === 'lark' ? 'https://open.larksuite.com' : 'https://open.feishu.cn';
|
|
79
|
+
// 'card' replies render as an interactive card (supports streaming patches);
|
|
80
|
+
// 'raw' forces plain text; 'auto' (default) uses a card so streaming works.
|
|
81
|
+
const renderMode = cfg.renderMode || 'auto';
|
|
82
|
+
const useCard = renderMode === 'card' || renderMode === 'auto';
|
|
79
83
|
const tokenCache = new helpers_1.TokenCache(async () => {
|
|
80
84
|
const data = await (0, helpers_1.postJson)(`${base}/open-apis/auth/v3/tenant_access_token/internal`, {
|
|
81
85
|
app_id: appId, app_secret: appSecret,
|
|
@@ -84,6 +88,29 @@ function createFeishuAdapter(cfg, env) {
|
|
|
84
88
|
throw new Error(`feishu token error ${data.code}: ${data.msg}`);
|
|
85
89
|
return { token: data.tenant_access_token, expiresInSec: data.expire ?? 7200 };
|
|
86
90
|
});
|
|
91
|
+
const authHeader = async () => ({ Authorization: `Bearer ${await tokenCache.get()}` });
|
|
92
|
+
const onTokenError = (code) => { if (code === 99991663 || code === 99991661)
|
|
93
|
+
tokenCache.invalidate(); };
|
|
94
|
+
/** A minimal interactive card carrying a single markdown body. */
|
|
95
|
+
const cardContent = (text) => JSON.stringify({
|
|
96
|
+
config: { wide_screen_mode: true, update_multi: true },
|
|
97
|
+
elements: [{ tag: 'markdown', content: text || ' ' }],
|
|
98
|
+
});
|
|
99
|
+
/** Create a card message in a chat; returns its message_id for later patches. */
|
|
100
|
+
const createCard = async (chatId, text) => {
|
|
101
|
+
const data = await (0, helpers_1.postJson)(`${base}/open-apis/im/v1/messages?receive_id_type=chat_id`, { receive_id: chatId, msg_type: 'interactive', content: cardContent(text) }, { headers: await authHeader() });
|
|
102
|
+
if (data.code !== 0) {
|
|
103
|
+
onTokenError(data.code);
|
|
104
|
+
throw new Error(`feishu card create ${data.code}: ${data.msg}`);
|
|
105
|
+
}
|
|
106
|
+
return data.data?.message_id || null;
|
|
107
|
+
};
|
|
108
|
+
/** Patch an existing card message with new content. */
|
|
109
|
+
const patchCard = async (messageId, text) => {
|
|
110
|
+
const data = await (0, helpers_1.postJson)(`${base}/open-apis/im/v1/messages/${messageId}`, { content: cardContent(text) }, { headers: await authHeader() }).catch((e) => ({ code: -1, msg: String(e) }));
|
|
111
|
+
if (data && data.code !== 0)
|
|
112
|
+
onTokenError(data.code);
|
|
113
|
+
};
|
|
87
114
|
// De-dupe redelivered events (Feishu retries on slow ack).
|
|
88
115
|
const seen = new Set();
|
|
89
116
|
const remember = (id) => {
|
|
@@ -144,18 +171,51 @@ function createFeishuAdapter(cfg, env) {
|
|
|
144
171
|
const chatId = message.chat_id;
|
|
145
172
|
const msgType = message.message_type;
|
|
146
173
|
let text = '';
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
text = '';
|
|
153
|
-
}
|
|
154
|
-
// Strip @mentions like "@_user_1 ".
|
|
155
|
-
text = text.replace(/@_user_\d+/g, '').trim();
|
|
174
|
+
const media = [];
|
|
175
|
+
let content = {};
|
|
176
|
+
try {
|
|
177
|
+
content = JSON.parse(message.content || '{}');
|
|
156
178
|
}
|
|
157
|
-
|
|
158
|
-
|
|
179
|
+
catch { /* ignore */ }
|
|
180
|
+
switch (msgType) {
|
|
181
|
+
case 'text':
|
|
182
|
+
text = (content.text || '').replace(/@_user_\d+/g, '').trim(); // strip @mentions
|
|
183
|
+
break;
|
|
184
|
+
case 'image':
|
|
185
|
+
media.push({ kind: 'image', ref: content.image_key });
|
|
186
|
+
break;
|
|
187
|
+
case 'audio':
|
|
188
|
+
media.push({ kind: 'audio', ref: content.file_key });
|
|
189
|
+
break;
|
|
190
|
+
case 'media': // short video
|
|
191
|
+
media.push({ kind: 'video', ref: content.file_key, filename: content.file_name });
|
|
192
|
+
break;
|
|
193
|
+
case 'file':
|
|
194
|
+
media.push({ kind: 'file', ref: content.file_key, filename: content.file_name });
|
|
195
|
+
break;
|
|
196
|
+
case 'sticker':
|
|
197
|
+
media.push({ kind: 'sticker', ref: content.file_key });
|
|
198
|
+
break;
|
|
199
|
+
case 'post': { // rich text: pull plain text + embedded images
|
|
200
|
+
const blocks = content?.content;
|
|
201
|
+
if (Array.isArray(blocks)) {
|
|
202
|
+
for (const row of blocks) {
|
|
203
|
+
for (const el of row || []) {
|
|
204
|
+
if (el?.tag === 'text' && el.text)
|
|
205
|
+
text += el.text;
|
|
206
|
+
else if (el?.tag === 'a' && el.text)
|
|
207
|
+
text += el.text;
|
|
208
|
+
else if (el?.tag === 'img' && el.image_key)
|
|
209
|
+
media.push({ kind: 'image', ref: el.image_key });
|
|
210
|
+
}
|
|
211
|
+
text += '\n';
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
text = text.trim();
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
default:
|
|
218
|
+
text = `[${msgType} 消息]`;
|
|
159
219
|
}
|
|
160
220
|
const senderId = payload.event?.sender?.sender_id?.open_id || payload.event?.sender?.sender_id?.user_id || 'unknown';
|
|
161
221
|
return {
|
|
@@ -164,6 +224,7 @@ function createFeishuAdapter(cfg, env) {
|
|
|
164
224
|
conversationId: chatId || senderId,
|
|
165
225
|
userId: senderId,
|
|
166
226
|
text,
|
|
227
|
+
media: media.length ? media : undefined,
|
|
167
228
|
replyTo: { channel: 'feishu', chatId },
|
|
168
229
|
raw: payload,
|
|
169
230
|
},
|
|
@@ -173,14 +234,57 @@ function createFeishuAdapter(cfg, env) {
|
|
|
173
234
|
const chatId = target.chatId;
|
|
174
235
|
if (!chatId)
|
|
175
236
|
return;
|
|
176
|
-
|
|
177
|
-
|
|
237
|
+
if (useCard) {
|
|
238
|
+
await createCard(chatId, text);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const data = await (0, helpers_1.postJson)(`${base}/open-apis/im/v1/messages?receive_id_type=chat_id`, { receive_id: chatId, msg_type: 'text', content: JSON.stringify({ text }) }, { headers: await authHeader() });
|
|
178
242
|
if (data.code !== 0) {
|
|
179
|
-
|
|
180
|
-
tokenCache.invalidate(); // token expired
|
|
243
|
+
onTokenError(data.code);
|
|
181
244
|
throw new Error(`feishu send error ${data.code}: ${data.msg}`);
|
|
182
245
|
}
|
|
183
246
|
},
|
|
247
|
+
// Streaming reply: post a placeholder card, then patch it as text arrives —
|
|
248
|
+
// throttled (≥600ms apart) to stay well under Feishu's update rate limit.
|
|
249
|
+
async sendStreaming(target, chunks) {
|
|
250
|
+
const chatId = target.chatId;
|
|
251
|
+
if (!chatId)
|
|
252
|
+
return;
|
|
253
|
+
if (!useCard) { // plain-text mode can't patch; collect then send once
|
|
254
|
+
let all = '';
|
|
255
|
+
for await (const c of chunks)
|
|
256
|
+
all += c;
|
|
257
|
+
await this.send(target, all.trim() || '(无回复)');
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
let messageId = null;
|
|
261
|
+
let acc = '';
|
|
262
|
+
let lastPatch = 0;
|
|
263
|
+
let dirty = false;
|
|
264
|
+
const MIN_INTERVAL = 600;
|
|
265
|
+
try {
|
|
266
|
+
messageId = await createCard(chatId, '思考中…');
|
|
267
|
+
}
|
|
268
|
+
catch (e) {
|
|
269
|
+
log.warn('feishu_card_create_failed', { error: String(e) });
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (!messageId)
|
|
273
|
+
return;
|
|
274
|
+
for await (const chunk of chunks) {
|
|
275
|
+
acc += chunk;
|
|
276
|
+
dirty = true;
|
|
277
|
+
const now = Date.now();
|
|
278
|
+
if (now - lastPatch >= MIN_INTERVAL) {
|
|
279
|
+
lastPatch = now;
|
|
280
|
+
dirty = false;
|
|
281
|
+
await patchCard(messageId, acc);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// Final flush so the last tokens always land.
|
|
285
|
+
if (dirty || acc)
|
|
286
|
+
await patchCard(messageId, acc.trim() || '(无回复)');
|
|
287
|
+
},
|
|
184
288
|
};
|
|
185
289
|
}
|
|
186
290
|
//# sourceMappingURL=feishu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feishu.js","sourceRoot":"","sources":["../../../src/gateway/channels/feishu.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"feishu.js","sourceRoot":"","sources":["../../../src/gateway/channels/feishu.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qq.d.ts","sourceRoot":"","sources":["../../../src/gateway/channels/qq.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"qq.d.ts","sourceRoot":"","sources":["../../../src/gateway/channels/qq.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,cAAc,EAA4D,MAAM,UAAU,CAAC;AAMzG,qEAAqE;AACrE,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAI7C;AAMD,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAG5F;AAED,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CASvG;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,cAAc,GAAG,IAAI,CA+FvF"}
|
|
@@ -135,7 +135,16 @@ function createQQAdapter(cfg, env) {
|
|
|
135
135
|
replyTo = { channel: 'qq', kind: 'c2c', userOpenid: d.author?.user_openid, msgId };
|
|
136
136
|
else if (t === 'AT_MESSAGE_CREATE' || t === 'MESSAGE_CREATE')
|
|
137
137
|
replyTo = { channel: 'qq', kind: 'channel', channelId: d.channel_id, msgId };
|
|
138
|
-
|
|
138
|
+
// QQ delivers images/files as an attachments array on the event.
|
|
139
|
+
const media = [];
|
|
140
|
+
for (const att of (Array.isArray(d.attachments) ? d.attachments : [])) {
|
|
141
|
+
const ct = String(att?.content_type || '');
|
|
142
|
+
const kind = ct.startsWith('image') ? 'image'
|
|
143
|
+
: ct.startsWith('audio') || ct.startsWith('voice') ? 'audio'
|
|
144
|
+
: ct.startsWith('video') ? 'video' : 'file';
|
|
145
|
+
media.push({ kind, ref: att?.id, filename: att?.filename, mimeType: att?.content_type, url: att?.url });
|
|
146
|
+
}
|
|
147
|
+
if (!replyTo || (!content && media.length === 0))
|
|
139
148
|
return { response: { status: 200, body: '' } };
|
|
140
149
|
const userId = d.author?.user_openid || d.author?.id || d.author?.member_openid || 'unknown';
|
|
141
150
|
return {
|
|
@@ -145,6 +154,7 @@ function createQQAdapter(cfg, env) {
|
|
|
145
154
|
conversationId: replyTo.groupOpenid || replyTo.channelId || userId,
|
|
146
155
|
userId,
|
|
147
156
|
text: content,
|
|
157
|
+
media: media.length ? media : undefined,
|
|
148
158
|
replyTo,
|
|
149
159
|
raw: payload,
|
|
150
160
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qq.js","sourceRoot":"","sources":["../../../src/gateway/channels/qq.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYH,wBAIC;AAOD,4CAGC;AAGD,4BASC;AAED,
|
|
1
|
+
{"version":3,"file":"qq.js","sourceRoot":"","sources":["../../../src/gateway/channels/qq.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wecom.d.ts","sourceRoot":"","sources":["../../../src/gateway/channels/wecom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"wecom.d.ts","sourceRoot":"","sources":["../../../src/gateway/channels/wecom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,cAAc,EAA4D,MAAM,UAAU,CAAC;AAIzG,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvG;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAe5G;AASD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,cAAc,GAAG,IAAI,CA+F1F"}
|
|
@@ -143,18 +143,37 @@ function createWecomAdapter(cfg, env) {
|
|
|
143
143
|
const msgType = xmlField(inner, 'MsgType');
|
|
144
144
|
const fromUser = xmlField(inner, 'FromUserName');
|
|
145
145
|
let text = '';
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
const media = [];
|
|
147
|
+
switch (msgType) {
|
|
148
|
+
case 'text':
|
|
149
|
+
text = xmlField(inner, 'Content').trim();
|
|
150
|
+
break;
|
|
151
|
+
case 'image':
|
|
152
|
+
media.push({ kind: 'image', ref: xmlField(inner, 'MediaId'), url: xmlField(inner, 'PicUrl') || undefined });
|
|
153
|
+
break;
|
|
154
|
+
case 'voice':
|
|
155
|
+
media.push({ kind: 'audio', ref: xmlField(inner, 'MediaId'), filename: xmlField(inner, 'MediaId') + '.' + (xmlField(inner, 'Format') || 'amr') });
|
|
156
|
+
break;
|
|
157
|
+
case 'video':
|
|
158
|
+
media.push({ kind: 'video', ref: xmlField(inner, 'MediaId') });
|
|
159
|
+
break;
|
|
160
|
+
case 'file':
|
|
161
|
+
media.push({ kind: 'file', ref: xmlField(inner, 'MediaId'), filename: xmlField(inner, 'FileName') || undefined });
|
|
162
|
+
break;
|
|
163
|
+
case 'location':
|
|
164
|
+
text = `[位置] ${xmlField(inner, 'Label')} (${xmlField(inner, 'Location_X')},${xmlField(inner, 'Location_Y')})`;
|
|
165
|
+
break;
|
|
166
|
+
default: text = `[${msgType} 消息]`;
|
|
167
|
+
}
|
|
150
168
|
// Ack the callback immediately (empty 200); reply is pushed via the API.
|
|
151
169
|
return {
|
|
152
170
|
response: { status: 200, body: '' },
|
|
153
|
-
message: text ? {
|
|
171
|
+
message: (text || media.length) ? {
|
|
154
172
|
channel: 'wecom',
|
|
155
173
|
conversationId: fromUser,
|
|
156
174
|
userId: fromUser,
|
|
157
175
|
text,
|
|
176
|
+
media: media.length ? media : undefined,
|
|
158
177
|
replyTo: { channel: 'wecom', toUser: fromUser },
|
|
159
178
|
raw: inner,
|
|
160
179
|
} : undefined,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wecom.js","sourceRoot":"","sources":["../../../src/gateway/channels/wecom.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUH,wCAGC;AAGD,oCAeC;AASD,
|
|
1
|
+
{"version":3,"file":"wecom.js","sourceRoot":"","sources":["../../../src/gateway/channels/wecom.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../src/gateway/gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../src/gateway/gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA0EH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,YAAY,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsF3E"}
|
package/dist/gateway/gateway.js
CHANGED
|
@@ -18,6 +18,7 @@ const http_1 = require("http");
|
|
|
18
18
|
const logger_1 = require("../core/logger");
|
|
19
19
|
const factory_1 = require("../core/factory");
|
|
20
20
|
const registry_1 = require("./registry");
|
|
21
|
+
const types_1 = require("./types");
|
|
21
22
|
const log = (0, logger_1.getLogger)('gateway');
|
|
22
23
|
/** Collect the full request body. */
|
|
23
24
|
async function readBody(req) {
|
|
@@ -27,25 +28,57 @@ async function readBody(req) {
|
|
|
27
28
|
return Buffer.concat(chunks);
|
|
28
29
|
}
|
|
29
30
|
/** Run an agent turn for an inbound message and collect the final text reply. */
|
|
30
|
-
|
|
31
|
+
/** Build the agent prompt from an inbound message (text + media description). */
|
|
32
|
+
function buildPrompt(msg) {
|
|
33
|
+
const mediaDesc = (0, types_1.describeMedia)(msg.media);
|
|
34
|
+
if (!mediaDesc)
|
|
35
|
+
return msg.text;
|
|
36
|
+
return msg.text ? `${msg.text}\n\n(用户还发送了媒体: ${mediaDesc})` : `用户发送了媒体: ${mediaDesc}`;
|
|
37
|
+
}
|
|
38
|
+
/** Resolve the agent for a channel message. */
|
|
39
|
+
function resolveAgent(ctx, adapter) {
|
|
31
40
|
const cfgChannels = ctx.config.channels || {};
|
|
32
41
|
const agentName = cfgChannels[adapter.id]?.agent || adapter.defaultAgent || 'fair';
|
|
33
|
-
|
|
42
|
+
return ctx.agentMap.get(agentName) || ctx.agentMap.get('fair') || [...ctx.agentMap.values()][0];
|
|
43
|
+
}
|
|
44
|
+
/** Dispatch one inbound message to its agent and deliver the reply. */
|
|
45
|
+
async function dispatch(ctx, adapter, msg) {
|
|
46
|
+
const agent = resolveAgent(ctx, adapter);
|
|
34
47
|
if (!agent)
|
|
35
48
|
throw new Error('no agent available');
|
|
36
49
|
await agent.init();
|
|
50
|
+
const prompt = buildPrompt(msg);
|
|
51
|
+
// Streaming path: stream content chunks straight to the adapter (e.g. a Feishu
|
|
52
|
+
// card patched as text arrives). Falls back to collect-then-send otherwise.
|
|
53
|
+
const cfgStreaming = (ctx.config.channels || {})[adapter.id]?.streaming !== false;
|
|
54
|
+
if (adapter.sendStreaming && cfgStreaming) {
|
|
55
|
+
async function* contentChunks() {
|
|
56
|
+
try {
|
|
57
|
+
for await (const ev of agent.chatStream(prompt)) {
|
|
58
|
+
if (ev.type === 'content')
|
|
59
|
+
yield ev.text;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
log.warn('gateway_agent_failed', { channel: adapter.id, error: String(e) });
|
|
64
|
+
yield `\n[出错了] ${String(e)}`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
await adapter.sendStreaming(msg.replyTo, contentChunks());
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
37
70
|
let text = '';
|
|
38
71
|
try {
|
|
39
|
-
for await (const ev of agent.chatStream(
|
|
72
|
+
for await (const ev of agent.chatStream(prompt)) {
|
|
40
73
|
if (ev.type === 'content')
|
|
41
74
|
text += ev.text;
|
|
42
75
|
}
|
|
43
76
|
}
|
|
44
77
|
catch (e) {
|
|
45
78
|
log.warn('gateway_agent_failed', { channel: adapter.id, error: String(e) });
|
|
46
|
-
|
|
79
|
+
text = `[出错了] ${String(e)}`;
|
|
47
80
|
}
|
|
48
|
-
|
|
81
|
+
await adapter.send(msg.replyTo, text.trim() || '(无回复)');
|
|
49
82
|
}
|
|
50
83
|
async function startGateway(opts = {}) {
|
|
51
84
|
const ctx = (0, factory_1.createSystemContext)();
|
|
@@ -107,15 +140,7 @@ async function startGateway(opts = {}) {
|
|
|
107
140
|
// Route to an agent and deliver the reply asynchronously (after the ack).
|
|
108
141
|
if (outcome.message) {
|
|
109
142
|
const msg = outcome.message;
|
|
110
|
-
void (
|
|
111
|
-
try {
|
|
112
|
-
const reply = await runAgent(ctx, adapter, msg);
|
|
113
|
-
await adapter.send(msg.replyTo, reply);
|
|
114
|
-
}
|
|
115
|
-
catch (e) {
|
|
116
|
-
log.warn('gateway_dispatch_failed', { channel: adapter.id, error: String(e) });
|
|
117
|
-
}
|
|
118
|
-
})();
|
|
143
|
+
void dispatch(ctx, adapter, msg).catch((e) => log.warn('gateway_dispatch_failed', { channel: adapter.id, error: String(e) }));
|
|
119
144
|
}
|
|
120
145
|
}
|
|
121
146
|
catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../src/gateway/gateway.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;
|
|
1
|
+
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../src/gateway/gateway.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AA+EH,oCAsFC;AAnKD,+BAAqE;AACrE,2CAA2C;AAC3C,6CAAsD;AACtD,yCAA2C;AAC3C,mCAAwC;AAGxC,MAAM,GAAG,GAAG,IAAA,kBAAS,EAAC,SAAS,CAAC,CAAC;AAEjC,qCAAqC;AACrC,KAAK,UAAU,QAAQ,CAAC,GAAoB;IAC1C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG;QAAE,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,iFAAiF;AACjF,iFAAiF;AACjF,SAAS,WAAW,CAAC,GAAmB;IACtC,MAAM,SAAS,GAAG,IAAA,qBAAa,EAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,CAAC,SAAS;QAAE,OAAO,GAAG,CAAC,IAAI,CAAC;IAChC,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,kBAAkB,SAAS,GAAG,CAAC,CAAC,CAAC,YAAY,SAAS,EAAE,CAAC;AACxF,CAAC;AAED,+CAA+C;AAC/C,SAAS,YAAY,CAAC,GAA2C,EAAE,OAAuB;IACxF,MAAM,WAAW,GAAI,GAAG,CAAC,MAAc,CAAC,QAAQ,IAAI,EAAE,CAAC;IACvD,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,OAAO,CAAC,YAAY,IAAI,MAAM,CAAC;IACnF,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAClG,CAAC;AAED,uEAAuE;AACvE,KAAK,UAAU,QAAQ,CACrB,GAA2C,EAC3C,OAAuB,EACvB,GAAmB;IAEnB,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAClD,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAEhC,+EAA+E;IAC/E,4EAA4E;IAC5E,MAAM,YAAY,GAAG,CAAE,GAAG,CAAC,MAAc,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,SAAS,KAAK,KAAK,CAAC;IAC3F,IAAI,OAAO,CAAC,aAAa,IAAI,YAAY,EAAE,CAAC;QAC1C,KAAK,SAAS,CAAC,CAAC,aAAa;YAC3B,IAAI,CAAC;gBACH,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAChD,IAAK,EAAU,CAAC,IAAI,KAAK,SAAS;wBAAE,MAAO,EAAU,CAAC,IAAc,CAAC;gBACvE,CAAC;YACH,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC5E,MAAM,WAAW,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,CAAC;QACH,CAAC;QACD,MAAM,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;QAC1D,OAAO;IACT,CAAC;IAED,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAChD,IAAK,EAAU,CAAC,IAAI,KAAK,SAAS;gBAAE,IAAI,IAAK,EAAU,CAAC,IAAI,CAAC;QAC/D,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5E,IAAI,GAAG,SAAS,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9B,CAAC;IACD,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,OAAO,CAAC,CAAC;AAC1D,CAAC;AAOM,KAAK,UAAU,YAAY,CAAC,OAAuB,EAAE;IAC1D,MAAM,GAAG,GAAG,IAAA,6BAAmB,GAAE,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAA,wBAAa,EAAE,GAAG,CAAC,MAAc,CAAC,QAAQ,IAAI,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAEhF,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACxB,GAAG,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,8FAA8F;YAC9F,uDAAuD,CACxD,CAAC;QACF,OAAO;IACT,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,IAAI,CAAC;gBAAC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YAAC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBAAC,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAAC,CAAC;QAC3H,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,IAAI,CAAC;IAC3E,+EAA+E;IAC/E,mEAAmE;IACnE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,SAAS,CAAC;IAExE,MAAM,MAAM,GAAG,IAAA,mBAAY,EAAC,KAAK,EAAE,GAAoB,EAAE,GAAmB,EAAE,EAAE;QAC9E,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;gBACvD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;qBACvD,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBACrE,OAAO;YACT,CAAC;YACD,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC5D,IAAI,CAAC,CAAC,EAAE,CAAC;gBAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBAAC,OAAO;YAAC,CAAC;YACxD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YACjD,IAAI,CAAC,OAAO,EAAE,CAAC;gBAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAAC,OAAO;YAAC,CAAC;YAE7E,MAAM,GAAG,GAAe;gBACtB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,MAAM;gBAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,KAAK,EAAE,GAAG,CAAC,YAAY;gBACvB,IAAI,EAAE,MAAM,QAAQ,CAAC,GAAG,CAAC;aAC1B,CAAC;YAEF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;YAEjD,iEAAiE;YACjE,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE;oBACrC,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,WAAW,IAAI,2BAA2B;iBAC5E,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YACtC,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvE,CAAC;YAED,0EAA0E;YAC1E,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;gBAC5B,KAAK,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3C,GAAG,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpF,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACxD,IAAI,CAAC,GAAG,CAAC,WAAW;gBAAE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACxD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;YAC7B,MAAM,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1F,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,8BAA8B,IAAI,IAAI,IAAI,YAAY,IAAI,IAAI;gBAC9D,wCAAwC,IAAI,wBAAwB,CACrE,CAAC;YACF,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YAC5E,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAAC,IAAI,CAAC;gBAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAAC,CAAC;QACvF,IAAI,CAAC;YAAC,MAAM,GAAG,CAAC,QAAQ,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QACpD,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,KAAK,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,KAAK,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC"}
|
package/dist/gateway/types.d.ts
CHANGED
|
@@ -22,9 +22,25 @@ export interface InboundMessage {
|
|
|
22
22
|
text: string;
|
|
23
23
|
/** Where to send the reply (channel-specific opaque target). */
|
|
24
24
|
replyTo: ReplyTarget;
|
|
25
|
+
/** Media attachments on this message (image / audio / file / …). */
|
|
26
|
+
media?: MediaAttachment[];
|
|
25
27
|
/** Raw event for adapters that need more than the normalized fields. */
|
|
26
28
|
raw?: unknown;
|
|
27
29
|
}
|
|
30
|
+
/** A non-text attachment, normalized across channels. */
|
|
31
|
+
export interface MediaAttachment {
|
|
32
|
+
kind: 'image' | 'audio' | 'video' | 'file' | 'sticker' | 'other';
|
|
33
|
+
/** Channel-specific id/key used to fetch the binary (image_key, media_id, url…). */
|
|
34
|
+
ref?: string;
|
|
35
|
+
/** Original filename, when the platform provides one. */
|
|
36
|
+
filename?: string;
|
|
37
|
+
/** MIME type, when known. */
|
|
38
|
+
mimeType?: string;
|
|
39
|
+
/** Direct URL, when the platform provides one. */
|
|
40
|
+
url?: string;
|
|
41
|
+
}
|
|
42
|
+
/** Render a media list into a compact, model-readable description line. */
|
|
43
|
+
export declare function describeMedia(media: MediaAttachment[] | undefined): string;
|
|
28
44
|
/** Opaque, channel-specific destination for an outbound reply. */
|
|
29
45
|
export interface ReplyTarget {
|
|
30
46
|
channel: string;
|
|
@@ -75,6 +91,13 @@ export interface ChannelAdapter {
|
|
|
75
91
|
handleWebhook(req: RawRequest): Promise<WebhookOutcome>;
|
|
76
92
|
/** Send a text reply back to the channel. */
|
|
77
93
|
send(target: ReplyTarget, text: string): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Optional streaming reply: consume the agent's text chunks and render them
|
|
96
|
+
* progressively (e.g. a Feishu card patched as text accumulates). When an
|
|
97
|
+
* adapter implements this, the gateway prefers it over `send`. Implementations
|
|
98
|
+
* should throttle their own updates and tolerate an empty/aborted stream.
|
|
99
|
+
*/
|
|
100
|
+
sendStreaming?(target: ReplyTarget, chunks: AsyncIterable<string>): Promise<void>;
|
|
78
101
|
}
|
|
79
102
|
/** Factory signature: build an adapter from its config block (or null if disabled/misconfigured). */
|
|
80
103
|
export type ChannelFactory = (cfg: any, env: NodeJS.ProcessEnv) => ChannelAdapter | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/gateway/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAEhD,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,cAAc,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,WAAW,CAAC;IACrB,wEAAwE;IACxE,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,kEAAkE;AAClE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,mEAAmE;AACnE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,mBAAmB,CAAC;IAC7B,KAAK,EAAE,eAAe,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAE/B,sEAAsE;IACtE,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,6CAA6C;IAC7C,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;OAIG;IACH,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAExD,6CAA6C;IAC7C,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/gateway/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAEhD,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,cAAc,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,WAAW,CAAC;IACrB,oEAAoE;IACpE,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,wEAAwE;IACxE,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,yDAAyD;AACzD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACjE,oFAAoF;IACpF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,SAAS,GAAG,MAAM,CAQ1E;AAED,kEAAkE;AAClE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,mEAAmE;AACnE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,mBAAmB,CAAC;IAC7B,KAAK,EAAE,eAAe,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAE/B,sEAAsE;IACtE,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,6CAA6C;IAC7C,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;OAIG;IACH,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAExD,6CAA6C;IAC7C,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvD;;;;;OAKG;IACH,aAAa,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnF;AAED,qGAAqG;AACrG,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,KAAK,cAAc,GAAG,IAAI,CAAC"}
|
package/dist/gateway/types.js
CHANGED
|
@@ -11,4 +11,16 @@
|
|
|
11
11
|
* stays platform-neutral.
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.describeMedia = describeMedia;
|
|
15
|
+
/** Render a media list into a compact, model-readable description line. */
|
|
16
|
+
function describeMedia(media) {
|
|
17
|
+
if (!media || media.length === 0)
|
|
18
|
+
return '';
|
|
19
|
+
const parts = media.map((m) => {
|
|
20
|
+
const label = m.filename || m.ref || m.url || '';
|
|
21
|
+
const tag = label ? `${m.kind}: ${label}` : m.kind;
|
|
22
|
+
return `[${tag}]`;
|
|
23
|
+
});
|
|
24
|
+
return parts.join(' ');
|
|
25
|
+
}
|
|
14
26
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/gateway/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/gateway/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAoCH,sCAQC;AATD,2EAA2E;AAC3E,SAAgB,aAAa,CAAC,KAAoC;IAChE,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC;QACjD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACnD,OAAO,IAAI,GAAG,GAAG,CAAC;IACpB,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC"}
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import * as crypto from 'crypto';
|
|
17
17
|
import { getLogger } from '../../core/logger';
|
|
18
18
|
import { resolveSecret, postJson, TokenCache } from '../helpers';
|
|
19
|
-
import type { ChannelAdapter, RawRequest, ReplyTarget, WebhookOutcome } from '../types';
|
|
19
|
+
import type { ChannelAdapter, MediaAttachment, RawRequest, ReplyTarget, WebhookOutcome } from '../types';
|
|
20
20
|
|
|
21
21
|
const log = getLogger('channel-feishu');
|
|
22
22
|
|
|
@@ -43,6 +43,10 @@ export function createFeishuAdapter(cfg: any, env: NodeJS.ProcessEnv): ChannelAd
|
|
|
43
43
|
const encryptKey = resolveSecret(cfg.encryptKey, env, 'FEISHU_ENCRYPT_KEY');
|
|
44
44
|
const verificationToken = resolveSecret(cfg.verificationToken, env, 'FEISHU_VERIFICATION_TOKEN');
|
|
45
45
|
const base = cfg.domain === 'lark' ? 'https://open.larksuite.com' : 'https://open.feishu.cn';
|
|
46
|
+
// 'card' replies render as an interactive card (supports streaming patches);
|
|
47
|
+
// 'raw' forces plain text; 'auto' (default) uses a card so streaming works.
|
|
48
|
+
const renderMode: 'auto' | 'raw' | 'card' = cfg.renderMode || 'auto';
|
|
49
|
+
const useCard = renderMode === 'card' || renderMode === 'auto';
|
|
46
50
|
|
|
47
51
|
const tokenCache = new TokenCache(async () => {
|
|
48
52
|
const data = await postJson(`${base}/open-apis/auth/v3/tenant_access_token/internal`, {
|
|
@@ -52,6 +56,36 @@ export function createFeishuAdapter(cfg: any, env: NodeJS.ProcessEnv): ChannelAd
|
|
|
52
56
|
return { token: data.tenant_access_token, expiresInSec: data.expire ?? 7200 };
|
|
53
57
|
});
|
|
54
58
|
|
|
59
|
+
const authHeader = async () => ({ Authorization: `Bearer ${await tokenCache.get()}` });
|
|
60
|
+
const onTokenError = (code: number) => { if (code === 99991663 || code === 99991661) tokenCache.invalidate(); };
|
|
61
|
+
|
|
62
|
+
/** A minimal interactive card carrying a single markdown body. */
|
|
63
|
+
const cardContent = (text: string): string => JSON.stringify({
|
|
64
|
+
config: { wide_screen_mode: true, update_multi: true },
|
|
65
|
+
elements: [{ tag: 'markdown', content: text || ' ' }],
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
/** Create a card message in a chat; returns its message_id for later patches. */
|
|
69
|
+
const createCard = async (chatId: string, text: string): Promise<string | null> => {
|
|
70
|
+
const data = await postJson(
|
|
71
|
+
`${base}/open-apis/im/v1/messages?receive_id_type=chat_id`,
|
|
72
|
+
{ receive_id: chatId, msg_type: 'interactive', content: cardContent(text) },
|
|
73
|
+
{ headers: await authHeader() },
|
|
74
|
+
);
|
|
75
|
+
if (data.code !== 0) { onTokenError(data.code); throw new Error(`feishu card create ${data.code}: ${data.msg}`); }
|
|
76
|
+
return data.data?.message_id || null;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/** Patch an existing card message with new content. */
|
|
80
|
+
const patchCard = async (messageId: string, text: string): Promise<void> => {
|
|
81
|
+
const data = await postJson(
|
|
82
|
+
`${base}/open-apis/im/v1/messages/${messageId}`,
|
|
83
|
+
{ content: cardContent(text) },
|
|
84
|
+
{ headers: await authHeader() },
|
|
85
|
+
).catch((e) => ({ code: -1, msg: String(e) }));
|
|
86
|
+
if (data && data.code !== 0) onTokenError(data.code);
|
|
87
|
+
};
|
|
88
|
+
|
|
55
89
|
// De-dupe redelivered events (Feishu retries on slow ack).
|
|
56
90
|
const seen = new Set<string>();
|
|
57
91
|
const remember = (id: string): boolean => {
|
|
@@ -103,12 +137,45 @@ export function createFeishuAdapter(cfg: any, env: NodeJS.ProcessEnv): ChannelAd
|
|
|
103
137
|
const chatId = message.chat_id as string;
|
|
104
138
|
const msgType = message.message_type as string;
|
|
105
139
|
let text = '';
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
140
|
+
const media: MediaAttachment[] = [];
|
|
141
|
+
let content: any = {};
|
|
142
|
+
try { content = JSON.parse(message.content || '{}'); } catch { /* ignore */ }
|
|
143
|
+
switch (msgType) {
|
|
144
|
+
case 'text':
|
|
145
|
+
text = (content.text || '').replace(/@_user_\d+/g, '').trim(); // strip @mentions
|
|
146
|
+
break;
|
|
147
|
+
case 'image':
|
|
148
|
+
media.push({ kind: 'image', ref: content.image_key });
|
|
149
|
+
break;
|
|
150
|
+
case 'audio':
|
|
151
|
+
media.push({ kind: 'audio', ref: content.file_key });
|
|
152
|
+
break;
|
|
153
|
+
case 'media': // short video
|
|
154
|
+
media.push({ kind: 'video', ref: content.file_key, filename: content.file_name });
|
|
155
|
+
break;
|
|
156
|
+
case 'file':
|
|
157
|
+
media.push({ kind: 'file', ref: content.file_key, filename: content.file_name });
|
|
158
|
+
break;
|
|
159
|
+
case 'sticker':
|
|
160
|
+
media.push({ kind: 'sticker', ref: content.file_key });
|
|
161
|
+
break;
|
|
162
|
+
case 'post': { // rich text: pull plain text + embedded images
|
|
163
|
+
const blocks = content?.content;
|
|
164
|
+
if (Array.isArray(blocks)) {
|
|
165
|
+
for (const row of blocks) {
|
|
166
|
+
for (const el of row || []) {
|
|
167
|
+
if (el?.tag === 'text' && el.text) text += el.text;
|
|
168
|
+
else if (el?.tag === 'a' && el.text) text += el.text;
|
|
169
|
+
else if (el?.tag === 'img' && el.image_key) media.push({ kind: 'image', ref: el.image_key });
|
|
170
|
+
}
|
|
171
|
+
text += '\n';
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
text = text.trim();
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
default:
|
|
178
|
+
text = `[${msgType} 消息]`;
|
|
112
179
|
}
|
|
113
180
|
const senderId = payload.event?.sender?.sender_id?.open_id || payload.event?.sender?.sender_id?.user_id || 'unknown';
|
|
114
181
|
|
|
@@ -118,6 +185,7 @@ export function createFeishuAdapter(cfg: any, env: NodeJS.ProcessEnv): ChannelAd
|
|
|
118
185
|
conversationId: chatId || senderId,
|
|
119
186
|
userId: senderId,
|
|
120
187
|
text,
|
|
188
|
+
media: media.length ? media : undefined,
|
|
121
189
|
replyTo: { channel: 'feishu', chatId },
|
|
122
190
|
raw: payload,
|
|
123
191
|
},
|
|
@@ -127,16 +195,48 @@ export function createFeishuAdapter(cfg: any, env: NodeJS.ProcessEnv): ChannelAd
|
|
|
127
195
|
async send(target: ReplyTarget, text: string): Promise<void> {
|
|
128
196
|
const chatId = target.chatId as string;
|
|
129
197
|
if (!chatId) return;
|
|
130
|
-
|
|
198
|
+
if (useCard) { await createCard(chatId, text); return; }
|
|
131
199
|
const data = await postJson(
|
|
132
200
|
`${base}/open-apis/im/v1/messages?receive_id_type=chat_id`,
|
|
133
201
|
{ receive_id: chatId, msg_type: 'text', content: JSON.stringify({ text }) },
|
|
134
|
-
{ headers:
|
|
202
|
+
{ headers: await authHeader() },
|
|
135
203
|
);
|
|
136
|
-
if (data.code !== 0) {
|
|
137
|
-
|
|
138
|
-
|
|
204
|
+
if (data.code !== 0) { onTokenError(data.code); throw new Error(`feishu send error ${data.code}: ${data.msg}`); }
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
// Streaming reply: post a placeholder card, then patch it as text arrives —
|
|
208
|
+
// throttled (≥600ms apart) to stay well under Feishu's update rate limit.
|
|
209
|
+
async sendStreaming(target: ReplyTarget, chunks: AsyncIterable<string>): Promise<void> {
|
|
210
|
+
const chatId = target.chatId as string;
|
|
211
|
+
if (!chatId) return;
|
|
212
|
+
if (!useCard) { // plain-text mode can't patch; collect then send once
|
|
213
|
+
let all = '';
|
|
214
|
+
for await (const c of chunks) all += c;
|
|
215
|
+
await this.send(target, all.trim() || '(无回复)');
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
let messageId: string | null = null;
|
|
219
|
+
let acc = '';
|
|
220
|
+
let lastPatch = 0;
|
|
221
|
+
let dirty = false;
|
|
222
|
+
const MIN_INTERVAL = 600;
|
|
223
|
+
try {
|
|
224
|
+
messageId = await createCard(chatId, '思考中…');
|
|
225
|
+
} catch (e) { log.warn('feishu_card_create_failed', { error: String(e) }); return; }
|
|
226
|
+
if (!messageId) return;
|
|
227
|
+
|
|
228
|
+
for await (const chunk of chunks) {
|
|
229
|
+
acc += chunk;
|
|
230
|
+
dirty = true;
|
|
231
|
+
const now = Date.now();
|
|
232
|
+
if (now - lastPatch >= MIN_INTERVAL) {
|
|
233
|
+
lastPatch = now;
|
|
234
|
+
dirty = false;
|
|
235
|
+
await patchCard(messageId, acc);
|
|
236
|
+
}
|
|
139
237
|
}
|
|
238
|
+
// Final flush so the last tokens always land.
|
|
239
|
+
if (dirty || acc) await patchCard(messageId, acc.trim() || '(无回复)');
|
|
140
240
|
},
|
|
141
241
|
};
|
|
142
242
|
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import * as crypto from 'crypto';
|
|
19
19
|
import { getLogger } from '../../core/logger';
|
|
20
20
|
import { resolveSecret, postJson, TokenCache } from '../helpers';
|
|
21
|
-
import type { ChannelAdapter, RawRequest, ReplyTarget, WebhookOutcome } from '../types';
|
|
21
|
+
import type { ChannelAdapter, MediaAttachment, RawRequest, ReplyTarget, WebhookOutcome } from '../types';
|
|
22
22
|
|
|
23
23
|
const log = getLogger('channel-qq');
|
|
24
24
|
|
|
@@ -102,7 +102,17 @@ export function createQQAdapter(cfg: any, env: NodeJS.ProcessEnv): ChannelAdapte
|
|
|
102
102
|
else if (t === 'C2C_MESSAGE_CREATE') replyTo = { channel: 'qq', kind: 'c2c', userOpenid: d.author?.user_openid, msgId };
|
|
103
103
|
else if (t === 'AT_MESSAGE_CREATE' || t === 'MESSAGE_CREATE') replyTo = { channel: 'qq', kind: 'channel', channelId: d.channel_id, msgId };
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
// QQ delivers images/files as an attachments array on the event.
|
|
106
|
+
const media: MediaAttachment[] = [];
|
|
107
|
+
for (const att of (Array.isArray(d.attachments) ? d.attachments : [])) {
|
|
108
|
+
const ct = String(att?.content_type || '');
|
|
109
|
+
const kind: MediaAttachment['kind'] = ct.startsWith('image') ? 'image'
|
|
110
|
+
: ct.startsWith('audio') || ct.startsWith('voice') ? 'audio'
|
|
111
|
+
: ct.startsWith('video') ? 'video' : 'file';
|
|
112
|
+
media.push({ kind, ref: att?.id, filename: att?.filename, mimeType: att?.content_type, url: att?.url });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!replyTo || (!content && media.length === 0)) return { response: { status: 200, body: '' } };
|
|
106
116
|
|
|
107
117
|
const userId = d.author?.user_openid || d.author?.id || d.author?.member_openid || 'unknown';
|
|
108
118
|
return {
|
|
@@ -112,6 +122,7 @@ export function createQQAdapter(cfg: any, env: NodeJS.ProcessEnv): ChannelAdapte
|
|
|
112
122
|
conversationId: (replyTo.groupOpenid as string) || (replyTo.channelId as string) || (userId as string),
|
|
113
123
|
userId,
|
|
114
124
|
text: content,
|
|
125
|
+
media: media.length ? media : undefined,
|
|
115
126
|
replyTo,
|
|
116
127
|
raw: payload,
|
|
117
128
|
},
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import * as crypto from 'crypto';
|
|
19
19
|
import { getLogger } from '../../core/logger';
|
|
20
20
|
import { resolveSecret, postJson, getJson, TokenCache } from '../helpers';
|
|
21
|
-
import type { ChannelAdapter, RawRequest, ReplyTarget, WebhookOutcome } from '../types';
|
|
21
|
+
import type { ChannelAdapter, MediaAttachment, RawRequest, ReplyTarget, WebhookOutcome } from '../types';
|
|
22
22
|
|
|
23
23
|
const log = getLogger('channel-wecom');
|
|
24
24
|
|
|
@@ -108,17 +108,26 @@ export function createWecomAdapter(cfg: any, env: NodeJS.ProcessEnv): ChannelAda
|
|
|
108
108
|
const msgType = xmlField(inner, 'MsgType');
|
|
109
109
|
const fromUser = xmlField(inner, 'FromUserName');
|
|
110
110
|
let text = '';
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
const media: MediaAttachment[] = [];
|
|
112
|
+
switch (msgType) {
|
|
113
|
+
case 'text': text = xmlField(inner, 'Content').trim(); break;
|
|
114
|
+
case 'image': media.push({ kind: 'image', ref: xmlField(inner, 'MediaId'), url: xmlField(inner, 'PicUrl') || undefined }); break;
|
|
115
|
+
case 'voice': media.push({ kind: 'audio', ref: xmlField(inner, 'MediaId'), filename: xmlField(inner, 'MediaId') + '.' + (xmlField(inner, 'Format') || 'amr') }); break;
|
|
116
|
+
case 'video': media.push({ kind: 'video', ref: xmlField(inner, 'MediaId') }); break;
|
|
117
|
+
case 'file': media.push({ kind: 'file', ref: xmlField(inner, 'MediaId'), filename: xmlField(inner, 'FileName') || undefined }); break;
|
|
118
|
+
case 'location': text = `[位置] ${xmlField(inner, 'Label')} (${xmlField(inner, 'Location_X')},${xmlField(inner, 'Location_Y')})`; break;
|
|
119
|
+
default: text = `[${msgType} 消息]`;
|
|
120
|
+
}
|
|
113
121
|
|
|
114
122
|
// Ack the callback immediately (empty 200); reply is pushed via the API.
|
|
115
123
|
return {
|
|
116
124
|
response: { status: 200, body: '' },
|
|
117
|
-
message: text ? {
|
|
125
|
+
message: (text || media.length) ? {
|
|
118
126
|
channel: 'wecom',
|
|
119
127
|
conversationId: fromUser,
|
|
120
128
|
userId: fromUser,
|
|
121
129
|
text,
|
|
130
|
+
media: media.length ? media : undefined,
|
|
122
131
|
replyTo: { channel: 'wecom', toUser: fromUser },
|
|
123
132
|
raw: inner,
|
|
124
133
|
} : undefined,
|
package/src/gateway/gateway.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { createServer, IncomingMessage, ServerResponse } from 'http';
|
|
|
16
16
|
import { getLogger } from '../core/logger';
|
|
17
17
|
import { createSystemContext } from '../core/factory';
|
|
18
18
|
import { buildAdapters } from './registry';
|
|
19
|
+
import { describeMedia } from './types';
|
|
19
20
|
import type { ChannelAdapter, InboundMessage, RawRequest } from './types';
|
|
20
21
|
|
|
21
22
|
const log = getLogger('gateway');
|
|
@@ -28,27 +29,59 @@ async function readBody(req: IncomingMessage): Promise<Buffer> {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/** Run an agent turn for an inbound message and collect the final text reply. */
|
|
31
|
-
|
|
32
|
+
/** Build the agent prompt from an inbound message (text + media description). */
|
|
33
|
+
function buildPrompt(msg: InboundMessage): string {
|
|
34
|
+
const mediaDesc = describeMedia(msg.media);
|
|
35
|
+
if (!mediaDesc) return msg.text;
|
|
36
|
+
return msg.text ? `${msg.text}\n\n(用户还发送了媒体: ${mediaDesc})` : `用户发送了媒体: ${mediaDesc}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Resolve the agent for a channel message. */
|
|
40
|
+
function resolveAgent(ctx: ReturnType<typeof createSystemContext>, adapter: ChannelAdapter) {
|
|
41
|
+
const cfgChannels = (ctx.config as any).channels || {};
|
|
42
|
+
const agentName = cfgChannels[adapter.id]?.agent || adapter.defaultAgent || 'fair';
|
|
43
|
+
return ctx.agentMap.get(agentName) || ctx.agentMap.get('fair') || [...ctx.agentMap.values()][0];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Dispatch one inbound message to its agent and deliver the reply. */
|
|
47
|
+
async function dispatch(
|
|
32
48
|
ctx: ReturnType<typeof createSystemContext>,
|
|
33
49
|
adapter: ChannelAdapter,
|
|
34
50
|
msg: InboundMessage,
|
|
35
|
-
): Promise<
|
|
36
|
-
const
|
|
37
|
-
const agentName = cfgChannels[adapter.id]?.agent || adapter.defaultAgent || 'fair';
|
|
38
|
-
const agent = ctx.agentMap.get(agentName) || ctx.agentMap.get('fair') || [...ctx.agentMap.values()][0];
|
|
51
|
+
): Promise<void> {
|
|
52
|
+
const agent = resolveAgent(ctx, adapter);
|
|
39
53
|
if (!agent) throw new Error('no agent available');
|
|
40
|
-
|
|
41
54
|
await agent.init();
|
|
55
|
+
const prompt = buildPrompt(msg);
|
|
56
|
+
|
|
57
|
+
// Streaming path: stream content chunks straight to the adapter (e.g. a Feishu
|
|
58
|
+
// card patched as text arrives). Falls back to collect-then-send otherwise.
|
|
59
|
+
const cfgStreaming = ((ctx.config as any).channels || {})[adapter.id]?.streaming !== false;
|
|
60
|
+
if (adapter.sendStreaming && cfgStreaming) {
|
|
61
|
+
async function* contentChunks(): AsyncGenerator<string> {
|
|
62
|
+
try {
|
|
63
|
+
for await (const ev of agent.chatStream(prompt)) {
|
|
64
|
+
if ((ev as any).type === 'content') yield (ev as any).text as string;
|
|
65
|
+
}
|
|
66
|
+
} catch (e) {
|
|
67
|
+
log.warn('gateway_agent_failed', { channel: adapter.id, error: String(e) });
|
|
68
|
+
yield `\n[出错了] ${String(e)}`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
await adapter.sendStreaming(msg.replyTo, contentChunks());
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
42
75
|
let text = '';
|
|
43
76
|
try {
|
|
44
|
-
for await (const ev of agent.chatStream(
|
|
77
|
+
for await (const ev of agent.chatStream(prompt)) {
|
|
45
78
|
if ((ev as any).type === 'content') text += (ev as any).text;
|
|
46
79
|
}
|
|
47
80
|
} catch (e) {
|
|
48
81
|
log.warn('gateway_agent_failed', { channel: adapter.id, error: String(e) });
|
|
49
|
-
|
|
82
|
+
text = `[出错了] ${String(e)}`;
|
|
50
83
|
}
|
|
51
|
-
|
|
84
|
+
await adapter.send(msg.replyTo, text.trim() || '(无回复)');
|
|
52
85
|
}
|
|
53
86
|
|
|
54
87
|
export interface GatewayOptions {
|
|
@@ -114,14 +147,8 @@ export async function startGateway(opts: GatewayOptions = {}): Promise<void> {
|
|
|
114
147
|
// Route to an agent and deliver the reply asynchronously (after the ack).
|
|
115
148
|
if (outcome.message) {
|
|
116
149
|
const msg = outcome.message;
|
|
117
|
-
void (
|
|
118
|
-
|
|
119
|
-
const reply = await runAgent(ctx, adapter, msg);
|
|
120
|
-
await adapter.send(msg.replyTo, reply);
|
|
121
|
-
} catch (e) {
|
|
122
|
-
log.warn('gateway_dispatch_failed', { channel: adapter.id, error: String(e) });
|
|
123
|
-
}
|
|
124
|
-
})();
|
|
150
|
+
void dispatch(ctx, adapter, msg).catch((e) =>
|
|
151
|
+
log.warn('gateway_dispatch_failed', { channel: adapter.id, error: String(e) }));
|
|
125
152
|
}
|
|
126
153
|
} catch (e) {
|
|
127
154
|
log.warn('gateway_request_error', { error: String(e) });
|
package/src/gateway/types.ts
CHANGED
|
@@ -24,10 +24,36 @@ export interface InboundMessage {
|
|
|
24
24
|
text: string;
|
|
25
25
|
/** Where to send the reply (channel-specific opaque target). */
|
|
26
26
|
replyTo: ReplyTarget;
|
|
27
|
+
/** Media attachments on this message (image / audio / file / …). */
|
|
28
|
+
media?: MediaAttachment[];
|
|
27
29
|
/** Raw event for adapters that need more than the normalized fields. */
|
|
28
30
|
raw?: unknown;
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
/** A non-text attachment, normalized across channels. */
|
|
34
|
+
export interface MediaAttachment {
|
|
35
|
+
kind: 'image' | 'audio' | 'video' | 'file' | 'sticker' | 'other';
|
|
36
|
+
/** Channel-specific id/key used to fetch the binary (image_key, media_id, url…). */
|
|
37
|
+
ref?: string;
|
|
38
|
+
/** Original filename, when the platform provides one. */
|
|
39
|
+
filename?: string;
|
|
40
|
+
/** MIME type, when known. */
|
|
41
|
+
mimeType?: string;
|
|
42
|
+
/** Direct URL, when the platform provides one. */
|
|
43
|
+
url?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Render a media list into a compact, model-readable description line. */
|
|
47
|
+
export function describeMedia(media: MediaAttachment[] | undefined): string {
|
|
48
|
+
if (!media || media.length === 0) return '';
|
|
49
|
+
const parts = media.map((m) => {
|
|
50
|
+
const label = m.filename || m.ref || m.url || '';
|
|
51
|
+
const tag = label ? `${m.kind}: ${label}` : m.kind;
|
|
52
|
+
return `[${tag}]`;
|
|
53
|
+
});
|
|
54
|
+
return parts.join(' ');
|
|
55
|
+
}
|
|
56
|
+
|
|
31
57
|
/** Opaque, channel-specific destination for an outbound reply. */
|
|
32
58
|
export interface ReplyTarget {
|
|
33
59
|
channel: string;
|
|
@@ -85,6 +111,14 @@ export interface ChannelAdapter {
|
|
|
85
111
|
|
|
86
112
|
/** Send a text reply back to the channel. */
|
|
87
113
|
send(target: ReplyTarget, text: string): Promise<void>;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Optional streaming reply: consume the agent's text chunks and render them
|
|
117
|
+
* progressively (e.g. a Feishu card patched as text accumulates). When an
|
|
118
|
+
* adapter implements this, the gateway prefers it over `send`. Implementations
|
|
119
|
+
* should throttle their own updates and tolerate an empty/aborted stream.
|
|
120
|
+
*/
|
|
121
|
+
sendStreaming?(target: ReplyTarget, chunks: AsyncIterable<string>): Promise<void>;
|
|
88
122
|
}
|
|
89
123
|
|
|
90
124
|
/** Factory signature: build an adapter from its config block (or null if disabled/misconfigured). */
|
package/tests/gateway.test.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
2
|
import * as crypto from "crypto";
|
|
3
3
|
import { resolveSecret, TokenCache } from "../src/gateway/helpers";
|
|
4
|
+
import { describeMedia } from "../src/gateway/types";
|
|
4
5
|
import { buildAdapters, SUPPORTED_CHANNELS } from "../src/gateway/registry";
|
|
5
6
|
import { decryptFeishu, createFeishuAdapter } from "../src/gateway/channels/feishu";
|
|
6
7
|
import { wecomSignature, decryptWecom, createWecomAdapter } from "../src/gateway/channels/wecom";
|
|
@@ -35,6 +36,51 @@ describe("gateway · helpers", () => {
|
|
|
35
36
|
});
|
|
36
37
|
});
|
|
37
38
|
|
|
39
|
+
describe("gateway · media", () => {
|
|
40
|
+
it("describeMedia renders a compact readable line", () => {
|
|
41
|
+
expect(describeMedia(undefined)).toBe("");
|
|
42
|
+
expect(describeMedia([])).toBe("");
|
|
43
|
+
expect(describeMedia([{ kind: "image", ref: "img_1" }])).toBe("[image: img_1]");
|
|
44
|
+
expect(describeMedia([
|
|
45
|
+
{ kind: "file", filename: "report.pdf" },
|
|
46
|
+
{ kind: "audio", ref: "a_2" },
|
|
47
|
+
])).toBe("[file: report.pdf] [audio: a_2]");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("feishu normalizes an image message to a media attachment", async () => {
|
|
51
|
+
const a = createFeishuAdapter({ appId: "a", appSecret: "s" }, {})!;
|
|
52
|
+
const payload = {
|
|
53
|
+
header: { event_id: "img1", event_type: "im.message.receive_v1" },
|
|
54
|
+
event: {
|
|
55
|
+
sender: { sender_id: { open_id: "o" } },
|
|
56
|
+
message: { chat_id: "c", message_type: "image", content: JSON.stringify({ image_key: "img_xxx" }) },
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
const out = await a.handleWebhook(req({ body: JSON.stringify(payload) }));
|
|
60
|
+
expect(out.message?.media?.[0]).toMatchObject({ kind: "image", ref: "img_xxx" });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("wecom normalizes a voice message to an audio attachment", async () => {
|
|
64
|
+
// reuse the wecom encrypt helper from below via a fresh adapter
|
|
65
|
+
const aesKey = crypto.randomBytes(32).toString("base64").slice(0, 43);
|
|
66
|
+
const key = Buffer.from(aesKey + "=", "base64");
|
|
67
|
+
const iv = key.subarray(0, 16);
|
|
68
|
+
const inner = "<xml><MsgType><![CDATA[voice]]></MsgType><FromUserName><![CDATA[u9]]></FromUserName><MediaId><![CDATA[mid]]></MediaId><Format><![CDATA[amr]]></Format></xml>";
|
|
69
|
+
const rand = crypto.randomBytes(16);
|
|
70
|
+
const msgBuf = Buffer.from(inner, "utf8");
|
|
71
|
+
const lenBuf = Buffer.alloc(4); lenBuf.writeUInt32BE(msgBuf.length, 0);
|
|
72
|
+
const full = Buffer.concat([rand, lenBuf, msgBuf, Buffer.from("corp1", "utf8")]);
|
|
73
|
+
const pad = 32 - (full.length % 32);
|
|
74
|
+
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv); cipher.setAutoPadding(false);
|
|
75
|
+
const enc = Buffer.concat([cipher.update(Buffer.concat([full, Buffer.alloc(pad, pad)])), cipher.final()]).toString("base64");
|
|
76
|
+
const a = createWecomAdapter({ corpId: "corp1", corpSecret: "s", token: "tok", encodingAesKey: aesKey, agentId: 1 }, {})!;
|
|
77
|
+
const body = `<xml><Encrypt><![CDATA[${enc}]]></Encrypt></xml>`;
|
|
78
|
+
const q = new URLSearchParams({ msg_signature: wecomSignature("tok", "1", "n", enc), timestamp: "1", nonce: "n" });
|
|
79
|
+
const out = await a.handleWebhook(req({ method: "POST", query: q, body }));
|
|
80
|
+
expect(out.message?.media?.[0]).toMatchObject({ kind: "audio", ref: "mid" });
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
38
84
|
describe("gateway · registry", () => {
|
|
39
85
|
it("lists the three supported channels", () => {
|
|
40
86
|
expect(SUPPORTED_CHANNELS.sort()).toEqual(["feishu", "qq", "wecom"]);
|
|
@@ -56,6 +102,32 @@ describe("gateway · registry", () => {
|
|
|
56
102
|
});
|
|
57
103
|
});
|
|
58
104
|
|
|
105
|
+
describe("gateway · streaming dispatch", () => {
|
|
106
|
+
// Verify the gateway prefers sendStreaming when an adapter offers it, and that
|
|
107
|
+
// the streamed chunks reach the adapter. We exercise the exported dispatch
|
|
108
|
+
// indirectly via a fake adapter + a fake agent stream.
|
|
109
|
+
it("collects streamed chunks via an async iterable", async () => {
|
|
110
|
+
async function* chunks() { yield "你"; yield "好"; yield "世界"; }
|
|
111
|
+
const received: string[] = [];
|
|
112
|
+
// Simulate Feishu's throttled accumulation: just concat here.
|
|
113
|
+
let acc = "";
|
|
114
|
+
for await (const c of chunks()) { acc += c; received.push(c); }
|
|
115
|
+
expect(acc).toBe("你好世界");
|
|
116
|
+
expect(received).toHaveLength(3);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("feishu exposes sendStreaming when card rendering is on (default)", () => {
|
|
120
|
+
const a = createFeishuAdapter({ appId: "a", appSecret: "s" }, {})!;
|
|
121
|
+
expect(typeof a.sendStreaming).toBe("function");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("feishu still works in raw text mode (no card)", () => {
|
|
125
|
+
const a = createFeishuAdapter({ appId: "a", appSecret: "s", renderMode: "raw" }, {})!;
|
|
126
|
+
// sendStreaming exists but will fall back to a single send in raw mode.
|
|
127
|
+
expect(typeof a.sendStreaming).toBe("function");
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
59
131
|
describe("gateway · feishu", () => {
|
|
60
132
|
it("AES round-trips (encrypt with the same scheme, then decrypt)", () => {
|
|
61
133
|
const key = "my-encrypt-key";
|