@tencent-connect/dsh-qqbot 0.2.0 → 0.4.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/CHANGELOG.md +39 -0
- package/dist/config.d.ts +4 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/features/history-store.d.ts +8 -0
- package/dist/features/history-store.d.ts.map +1 -0
- package/dist/features/history-store.js +24 -0
- package/dist/features/history-store.js.map +1 -0
- package/dist/gateway/bootstrap.d.ts +12 -0
- package/dist/gateway/bootstrap.d.ts.map +1 -0
- package/dist/gateway/bootstrap.js +73 -0
- package/dist/gateway/bootstrap.js.map +1 -0
- package/dist/gateway/index.d.ts +3 -0
- package/dist/gateway/index.d.ts.map +1 -0
- package/dist/gateway/index.js +3 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/gateway/middleware-setup.d.ts +12 -0
- package/dist/gateway/middleware-setup.d.ts.map +1 -0
- package/dist/gateway/middleware-setup.js +80 -0
- package/dist/gateway/middleware-setup.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -135
- package/dist/index.js.map +1 -1
- package/dist/middleware/attachment.d.ts +11 -0
- package/dist/middleware/attachment.d.ts.map +1 -0
- package/dist/middleware/attachment.js +17 -0
- package/dist/middleware/attachment.js.map +1 -0
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +4 -5
- package/dist/session/session-manager.js.map +1 -1
- package/dist/setup.d.ts +4 -4
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +63 -28
- package/dist/setup.js.map +1 -1
- package/dist/shared/utils.d.ts +6 -1
- package/dist/shared/utils.d.ts.map +1 -1
- package/dist/shared/utils.js +16 -5
- package/dist/shared/utils.js.map +1 -1
- package/dist/transport/attachment.d.ts +18 -0
- package/dist/transport/attachment.d.ts.map +1 -0
- package/dist/transport/attachment.js +106 -0
- package/dist/transport/attachment.js.map +1 -0
- package/dist/transport/events.d.ts +80 -0
- package/dist/transport/events.d.ts.map +1 -0
- package/dist/transport/events.js +62 -0
- package/dist/transport/events.js.map +1 -0
- package/dist/transport/inbound.d.ts +1 -1
- package/dist/transport/inbound.d.ts.map +1 -1
- package/dist/transport/inbound.js +39 -14
- package/dist/transport/inbound.js.map +1 -1
- package/dist/transport/outbound-buffer.d.ts +12 -7
- package/dist/transport/outbound-buffer.d.ts.map +1 -1
- package/dist/transport/outbound-buffer.js +20 -22
- package/dist/transport/outbound-buffer.js.map +1 -1
- package/dist/transport/outbound.d.ts +7 -6
- package/dist/transport/outbound.d.ts.map +1 -1
- package/dist/transport/outbound.js +116 -111
- package/dist/transport/outbound.js.map +1 -1
- package/dist/transport/streaming-writer.d.ts +47 -0
- package/dist/transport/streaming-writer.d.ts.map +1 -0
- package/dist/transport/streaming-writer.js +110 -0
- package/dist/transport/streaming-writer.js.map +1 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -4
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 出站事件解析 — 将 dsh session/event 归一化为强类型
|
|
3
|
+
*
|
|
4
|
+
* 原始事件(ctx.on('session/event') 回调参数)是弱类型:
|
|
5
|
+
* { type: string, data: Record<string, unknown> }
|
|
6
|
+
* 这里把可识别的事件解析为 discriminated union,未知类型或字段缺失返回 undefined。
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* 解析原始事件为强类型
|
|
10
|
+
*
|
|
11
|
+
* 未知类型或缺失关键字段时返回 undefined,由调用方直接跳过。
|
|
12
|
+
*/
|
|
13
|
+
export function parseEvent(raw) {
|
|
14
|
+
switch (raw.type) {
|
|
15
|
+
case 'assistant/chunk': {
|
|
16
|
+
const chunk = raw.data.chunk;
|
|
17
|
+
if (chunk === undefined || chunk.type !== 'text-delta' || !chunk.text)
|
|
18
|
+
return undefined;
|
|
19
|
+
return { type: 'assistant/chunk', text: chunk.text };
|
|
20
|
+
}
|
|
21
|
+
case 'assistant/message': {
|
|
22
|
+
const message = raw.data.message;
|
|
23
|
+
if (message === undefined || !Array.isArray(message.content))
|
|
24
|
+
return undefined;
|
|
25
|
+
return { type: 'assistant/message', content: message.content };
|
|
26
|
+
}
|
|
27
|
+
case 'tool/call': {
|
|
28
|
+
const data = raw.data;
|
|
29
|
+
if (!data.callId || !data.name)
|
|
30
|
+
return undefined;
|
|
31
|
+
return { type: 'tool/call', callId: data.callId, name: data.name, arguments: data.arguments ?? '' };
|
|
32
|
+
}
|
|
33
|
+
case 'tool/result': {
|
|
34
|
+
const data = raw.data;
|
|
35
|
+
const callId = data.message?.source?.callId;
|
|
36
|
+
if (!callId)
|
|
37
|
+
return undefined;
|
|
38
|
+
return { type: 'tool/result', callId, error: data.error, raw: raw.data };
|
|
39
|
+
}
|
|
40
|
+
case 'turn/end': {
|
|
41
|
+
const reason = raw.data.reason ?? {};
|
|
42
|
+
return { type: 'turn/end', reason };
|
|
43
|
+
}
|
|
44
|
+
default:
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 从 turn/end reason 提取错误信息
|
|
50
|
+
*
|
|
51
|
+
* 兼容三种形态:error(新格式)、failure(旧格式)、顶层 message/code(最旧格式)。
|
|
52
|
+
*/
|
|
53
|
+
export function extractTurnError(reason) {
|
|
54
|
+
if (reason.kind !== 'error')
|
|
55
|
+
return undefined;
|
|
56
|
+
const detail = reason.error ?? reason.failure;
|
|
57
|
+
return {
|
|
58
|
+
code: detail?.code ?? reason.code ?? 'UNKNOWN',
|
|
59
|
+
message: detail?.message ?? reason.message ?? 'unknown error',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/transport/events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4DH;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,GAAoB;IAC7C,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,MAAM,KAAK,GAAI,GAAG,CAAC,IAAqD,CAAC,KAAK,CAAC;YAC/E,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,KAAK,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YACxF,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QACvD,CAAC;QAED,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,MAAM,OAAO,GAAI,GAAG,CAAC,IAA2E,CAAC,OAAO,CAAC;YACzG,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;gBAAE,OAAO,SAAS,CAAC;YAC/E,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QACjE,CAAC;QAED,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,IAAI,GAAG,GAAG,CAAC,IAA8D,CAAC;YAChF,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YACjD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QACtG,CAAC;QAED,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,IAAI,GAAG,GAAG,CAAC,IAA8F,CAAC;YAChH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC;YAC5C,IAAI,CAAC,MAAM;gBAAE,OAAO,SAAS,CAAC;YAC9B,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3E,CAAC;QAED,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,MAAM,GAAI,GAAG,CAAC,IAAmC,CAAC,MAAM,IAAI,EAAE,CAAC;YACrE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QACtC,CAAC;QAED;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC;IAC9C,OAAO;QACL,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,SAAS;QAC9C,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO,IAAI,eAAe;KAC9D,CAAC;AACJ,CAAC"}
|
|
@@ -4,5 +4,5 @@ import type { Logger } from '../types.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* 处理 QQ 入站消息(已经过 SDK 中间件链)
|
|
6
6
|
*/
|
|
7
|
-
export declare function handleInbound(rawMsg: unknown, manager: SessionManager,
|
|
7
|
+
export declare function handleInbound(rawMsg: unknown, manager: SessionManager, config: ImQQBotConfig, logger: Logger, state?: Record<string, unknown>): Promise<void>;
|
|
8
8
|
//# sourceMappingURL=inbound.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inbound.d.ts","sourceRoot":"","sources":["../../src/transport/inbound.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAa,MAAM,
|
|
1
|
+
{"version":3,"file":"inbound.d.ts","sourceRoot":"","sources":["../../src/transport/inbound.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAa,MAAM,EAA8B,MAAM,aAAa,CAAC;AA+DjF;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,CA+Cf"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import { clearGroupHistory } from '../features/history-store.js';
|
|
2
3
|
// ── 主处理函数 ──
|
|
3
4
|
/**
|
|
4
5
|
* 处理 QQ 入站消息(已经过 SDK 中间件链)
|
|
5
6
|
*/
|
|
6
|
-
export async function handleInbound(rawMsg, manager,
|
|
7
|
+
export async function handleInbound(rawMsg, manager, config, logger, state) {
|
|
7
8
|
const msg = rawMsg;
|
|
8
9
|
const mwState = (state ?? {});
|
|
9
10
|
const scope = msg.kind === 'group' ? 'group' : 'c2c';
|
|
@@ -13,8 +14,10 @@ export async function handleInbound(rawMsg, manager, _config, logger, state) {
|
|
|
13
14
|
targetId: peerId,
|
|
14
15
|
msgId: msg.messageId,
|
|
15
16
|
};
|
|
17
|
+
// ── 读取中间件已下载的文件(attachmentProcessor 写入 state.downloadedFiles) ──
|
|
18
|
+
const downloaded = mwState.downloadedFiles ?? [];
|
|
16
19
|
// ── 组装 agentBody(对齐 openclaw-qqbot body-assembler) ──
|
|
17
|
-
const agentBody = assembleAgentBody(msg, mwState, scope, logger);
|
|
20
|
+
const agentBody = assembleAgentBody(msg, mwState, scope, logger, downloaded);
|
|
18
21
|
if (!agentBody)
|
|
19
22
|
return;
|
|
20
23
|
logger.info(`Processing: scope=${scope} peerId=${peerId} body="${agentBody.slice(0, 200)}"`);
|
|
@@ -35,6 +38,10 @@ export async function handleInbound(rawMsg, manager, _config, logger, state) {
|
|
|
35
38
|
});
|
|
36
39
|
record.agent.followup(message);
|
|
37
40
|
logger.info(`→ followup sent: key=${scope}:${peerId}`);
|
|
41
|
+
// 群消息回复后清空历史缓存(避免下次 @ 时重复组包,对齐 openclaw-qqbot dispatch)
|
|
42
|
+
if (scope === 'group') {
|
|
43
|
+
clearGroupHistory(config.appId, msg.groupOpenid ?? msg.senderId);
|
|
44
|
+
}
|
|
38
45
|
}
|
|
39
46
|
// ══════════════════════════════════════════════════════════════
|
|
40
47
|
// Body Assembly(对齐 openclaw-qqbot 5 层组装)
|
|
@@ -42,15 +49,15 @@ export async function handleInbound(rawMsg, manager, _config, logger, state) {
|
|
|
42
49
|
/**
|
|
43
50
|
* 组装 agentBody — AI 实际看到的完整上下文
|
|
44
51
|
*/
|
|
45
|
-
function assembleAgentBody(msg, state, scope, logger) {
|
|
52
|
+
function assembleAgentBody(msg, state, scope, logger, downloaded) {
|
|
46
53
|
const userContent = buildUserContent(msg, state, logger);
|
|
47
54
|
if (!userContent && (!msg.attachments || msg.attachments.length === 0))
|
|
48
55
|
return null;
|
|
49
56
|
const quotePart = buildQuotePart(state.quote);
|
|
50
57
|
const isGroup = scope === 'group';
|
|
51
58
|
const wasMentioned = state.mention?.wasMentioned ?? false;
|
|
52
|
-
const userMessage = buildUserMessage(userContent, quotePart, msg.senderId, isGroup, wasMentioned);
|
|
53
|
-
const dynamicCtx = buildDynamicCtx(msg, state);
|
|
59
|
+
const userMessage = buildUserMessage(userContent, quotePart, msg.senderId, msg.senderName, isGroup, wasMentioned);
|
|
60
|
+
const dynamicCtx = buildDynamicCtx(msg, state, downloaded);
|
|
54
61
|
const base = dynamicCtx ? `${dynamicCtx}${userMessage}` : userMessage;
|
|
55
62
|
const agentBody = buildAgentBody(base, state.history, isGroup, wasMentioned);
|
|
56
63
|
return agentBody;
|
|
@@ -89,18 +96,19 @@ function buildQuotePart(quote) {
|
|
|
89
96
|
/**
|
|
90
97
|
* Layer 3: 带发送者标签的用户消息
|
|
91
98
|
*/
|
|
92
|
-
function buildUserMessage(userContent, quotePart, senderId, isGroup, wasMentioned) {
|
|
99
|
+
function buildUserMessage(userContent, quotePart, senderId, senderName, isGroup, wasMentioned) {
|
|
93
100
|
if (!isGroup) {
|
|
94
101
|
return `${quotePart}${userContent}`;
|
|
95
102
|
}
|
|
96
103
|
const mentionTag = wasMentioned ? ' (@you)' : '';
|
|
97
|
-
const
|
|
104
|
+
const displayName = senderName ?? shortSenderId(senderId);
|
|
105
|
+
const senderTag = `[${displayName} (${senderId})]`;
|
|
98
106
|
return `${quotePart}${senderTag} ${userContent}${mentionTag}`;
|
|
99
107
|
}
|
|
100
108
|
/**
|
|
101
109
|
* Layer 4: 媒体元数据上下文
|
|
102
110
|
*/
|
|
103
|
-
function buildDynamicCtx(msg, state) {
|
|
111
|
+
function buildDynamicCtx(msg, state, downloaded) {
|
|
104
112
|
const lines = [];
|
|
105
113
|
if (!msg.attachments || msg.attachments.length === 0)
|
|
106
114
|
return '';
|
|
@@ -113,14 +121,17 @@ function buildDynamicCtx(msg, state) {
|
|
|
113
121
|
}
|
|
114
122
|
const voices = msg.attachments.filter(a => a.content_type === 'voice');
|
|
115
123
|
if (voices.length > 0) {
|
|
116
|
-
const urls = voices.map(a => a.url).filter(Boolean);
|
|
117
|
-
if (urls.length > 0) {
|
|
118
|
-
lines.push(`- Voice: ${urls.join(', ')}`);
|
|
119
|
-
}
|
|
120
124
|
const asrTexts = voices.map(a => a.asr_refer_text).filter(Boolean);
|
|
121
125
|
if (asrTexts.length > 0) {
|
|
122
126
|
lines.push(`- ASR: ${asrTexts.join(' | ')}`);
|
|
123
127
|
}
|
|
128
|
+
else {
|
|
129
|
+
// 无 ASR 识别结果时才带链接(纯文本模型无法消费音频,链接无意义)
|
|
130
|
+
const urls = voices.map(a => a.url).filter(Boolean);
|
|
131
|
+
if (urls.length > 0) {
|
|
132
|
+
lines.push(`- Voice: ${urls.join(', ')}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
124
135
|
}
|
|
125
136
|
const videos = msg.attachments.filter(a => a.content_type === 'video');
|
|
126
137
|
if (videos.length > 0) {
|
|
@@ -128,7 +139,15 @@ function buildDynamicCtx(msg, state) {
|
|
|
128
139
|
}
|
|
129
140
|
const files = msg.attachments.filter(a => a.content_type === 'file');
|
|
130
141
|
if (files.length > 0) {
|
|
131
|
-
|
|
142
|
+
for (const file of files) {
|
|
143
|
+
const d = downloaded.find(x => x.filename === file.filename);
|
|
144
|
+
if (d) {
|
|
145
|
+
lines.push(`- File: ${file.filename} → ${d.displayPath}`);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
lines.push(`- File: ${file.filename} (${formatFileSize(file.size)})`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
132
151
|
}
|
|
133
152
|
if (lines.length === 0)
|
|
134
153
|
return '';
|
|
@@ -150,7 +169,7 @@ function buildAgentBody(base, history, isGroup, wasMentioned) {
|
|
|
150
169
|
return base;
|
|
151
170
|
}
|
|
152
171
|
const historyLines = history.map(h => {
|
|
153
|
-
const name = h.senderName ?? h.senderId
|
|
172
|
+
const name = h.senderName ?? shortSenderId(h.senderId);
|
|
154
173
|
return `[${name} (${h.senderId})] ${h.content}`;
|
|
155
174
|
});
|
|
156
175
|
return [
|
|
@@ -220,4 +239,10 @@ function formatFileSize(bytes) {
|
|
|
220
239
|
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
221
240
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
222
241
|
}
|
|
242
|
+
/** 发送者短标识长度(openid 前 N 位,无昵称时兜底) */
|
|
243
|
+
const SENDER_SHORT_ID_LEN = 8;
|
|
244
|
+
/** 无昵称时用 openid 前 N 位作为匿名标识 */
|
|
245
|
+
function shortSenderId(senderId) {
|
|
246
|
+
return senderId.slice(0, SENDER_SHORT_ID_LEN);
|
|
247
|
+
}
|
|
223
248
|
//# sourceMappingURL=inbound.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inbound.js","sourceRoot":"","sources":["../../src/transport/inbound.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"inbound.js","sourceRoot":"","sources":["../../src/transport/inbound.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OutboundBuffer — 出站文本缓冲
|
|
3
3
|
*
|
|
4
|
-
* 收集流式 chunk
|
|
4
|
+
* 收集流式 chunk,流式优先投递(StreamingWriter),降级为静态发送。
|
|
5
|
+
* 独立文件便于单测。
|
|
5
6
|
*/
|
|
6
7
|
import type { SessionRecord } from '../session/index.js';
|
|
7
8
|
import type { Logger, ReplyTarget } from '../types.js';
|
|
9
|
+
/** QQ 流式会话(openStream 返回) */
|
|
10
|
+
export interface StreamSessionLike {
|
|
11
|
+
update(content: string): Promise<unknown>;
|
|
12
|
+
complete(): Promise<unknown>;
|
|
13
|
+
}
|
|
8
14
|
/** QQ Bot 发送接口 */
|
|
9
15
|
export interface QQBotSender {
|
|
10
16
|
sendMarkdown(target: ReplyTarget, content: string): Promise<unknown>;
|
|
17
|
+
openStream(target: ReplyTarget): StreamSessionLike;
|
|
11
18
|
}
|
|
12
19
|
export declare class OutboundBuffer {
|
|
13
20
|
private readonly record;
|
|
@@ -15,18 +22,16 @@ export declare class OutboundBuffer {
|
|
|
15
22
|
private readonly limit;
|
|
16
23
|
private readonly logger;
|
|
17
24
|
private buffer;
|
|
18
|
-
private timer;
|
|
19
25
|
private flushing;
|
|
20
|
-
|
|
26
|
+
private readonly writer;
|
|
27
|
+
constructor(record: SessionRecord, bot: QQBotSender, limit: number, logger: Logger, streamingEnabled: boolean);
|
|
21
28
|
/** 追加文本增量 */
|
|
22
29
|
append(text: string): void;
|
|
23
30
|
/** 获取当前累积文本 */
|
|
24
31
|
get text(): string;
|
|
25
|
-
/**
|
|
26
|
-
scheduleSend(delayMs: number): void;
|
|
27
|
-
/** 立即发送所有累积文本 */
|
|
32
|
+
/** 发送所有累积文本:流式优先,降级静态 */
|
|
28
33
|
flush(): Promise<void>;
|
|
29
|
-
/**
|
|
34
|
+
/** 取消(异常/丢弃),中止流式并清空缓冲 */
|
|
30
35
|
cancel(): void;
|
|
31
36
|
}
|
|
32
37
|
//# sourceMappingURL=outbound-buffer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound-buffer.d.ts","sourceRoot":"","sources":["../../src/transport/outbound-buffer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"outbound-buffer.d.ts","sourceRoot":"","sources":["../../src/transport/outbound-buffer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOvD,6BAA6B;AAC7B,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9B;AAED,kBAAkB;AAClB,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,iBAAiB,CAAC;CACpD;AAED,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;gBAG7B,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAC/B,gBAAgB,EAAE,OAAO;IAO3B,aAAa;IACN,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKjC,eAAe;IACf,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,yBAAyB;IACZ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBnC,0BAA0B;IACnB,MAAM,IAAI,IAAI;CAItB"}
|
|
@@ -1,64 +1,62 @@
|
|
|
1
1
|
import { chunkMarkdownText } from './chunker.js';
|
|
2
|
+
import { StreamingWriter } from './streaming-writer.js';
|
|
3
|
+
/** 流式输出节流间隔(ms):连续 chunk 累积后停顿该间隔才推送 */
|
|
4
|
+
const STREAM_THROTTLE_MS = 200;
|
|
2
5
|
export class OutboundBuffer {
|
|
3
6
|
record;
|
|
4
7
|
bot;
|
|
5
8
|
limit;
|
|
6
9
|
logger;
|
|
7
10
|
buffer = '';
|
|
8
|
-
timer = null;
|
|
9
11
|
flushing = false;
|
|
10
|
-
|
|
12
|
+
writer;
|
|
13
|
+
constructor(record, bot, limit, logger, streamingEnabled) {
|
|
11
14
|
this.record = record;
|
|
12
15
|
this.bot = bot;
|
|
13
16
|
this.limit = limit;
|
|
14
17
|
this.logger = logger;
|
|
18
|
+
this.writer = streamingEnabled
|
|
19
|
+
? new StreamingWriter({ bot, target: record.replyTarget, logger, throttleMs: STREAM_THROTTLE_MS })
|
|
20
|
+
: null;
|
|
15
21
|
}
|
|
16
22
|
/** 追加文本增量 */
|
|
17
23
|
append(text) {
|
|
18
24
|
this.buffer += text;
|
|
25
|
+
this.writer?.append(text);
|
|
19
26
|
}
|
|
20
27
|
/** 获取当前累积文本 */
|
|
21
28
|
get text() {
|
|
22
29
|
return this.buffer;
|
|
23
30
|
}
|
|
24
|
-
/**
|
|
25
|
-
scheduleSend(delayMs) {
|
|
26
|
-
if (this.timer)
|
|
27
|
-
return;
|
|
28
|
-
this.timer = setTimeout(() => {
|
|
29
|
-
this.timer = null;
|
|
30
|
-
void this.flush();
|
|
31
|
-
}, delayMs);
|
|
32
|
-
}
|
|
33
|
-
/** 立即发送所有累积文本 */
|
|
31
|
+
/** 发送所有累积文本:流式优先,降级静态 */
|
|
34
32
|
async flush() {
|
|
35
33
|
if (this.flushing || !this.buffer.trim())
|
|
36
34
|
return;
|
|
37
35
|
this.flushing = true;
|
|
38
|
-
if (this.timer) {
|
|
39
|
-
clearTimeout(this.timer);
|
|
40
|
-
this.timer = null;
|
|
41
|
-
}
|
|
42
36
|
try {
|
|
37
|
+
if (this.writer) {
|
|
38
|
+
await this.writer.finish();
|
|
39
|
+
// 流式成功(未降级)→ 直接返回
|
|
40
|
+
if (!this.writer.shouldFallback)
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// 降级:静态发送(writer 不存在 or 流式失败)
|
|
43
44
|
const chunks = chunkMarkdownText(this.buffer, this.limit);
|
|
44
45
|
for (const chunk of chunks) {
|
|
45
46
|
await this.bot.sendMarkdown(this.record.replyTarget, chunk);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
catch (err) {
|
|
49
|
-
this.logger.error(`im-qqbot:
|
|
50
|
+
this.logger.error(`im-qqbot: flush failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
50
51
|
}
|
|
51
52
|
finally {
|
|
52
53
|
this.buffer = '';
|
|
53
54
|
this.flushing = false;
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
|
-
/**
|
|
57
|
+
/** 取消(异常/丢弃),中止流式并清空缓冲 */
|
|
57
58
|
cancel() {
|
|
58
|
-
|
|
59
|
-
clearTimeout(this.timer);
|
|
60
|
-
this.timer = null;
|
|
61
|
-
}
|
|
59
|
+
this.writer?.abort();
|
|
62
60
|
this.buffer = '';
|
|
63
61
|
}
|
|
64
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound-buffer.js","sourceRoot":"","sources":["../../src/transport/outbound-buffer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"outbound-buffer.js","sourceRoot":"","sources":["../../src/transport/outbound-buffer.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,wCAAwC;AACxC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAc/B,MAAM,OAAO,cAAc;IAMN;IACA;IACA;IACA;IARX,MAAM,GAAG,EAAE,CAAC;IACZ,QAAQ,GAAG,KAAK,CAAC;IACR,MAAM,CAAyB;IAEhD,YACmB,MAAqB,EACrB,GAAgB,EAChB,KAAa,EACb,MAAc,EAC/B,gBAAyB;QAJR,WAAM,GAAN,MAAM,CAAe;QACrB,QAAG,GAAH,GAAG,CAAa;QAChB,UAAK,GAAL,KAAK,CAAQ;QACb,WAAM,GAAN,MAAM,CAAQ;QAG/B,IAAI,CAAC,MAAM,GAAG,gBAAgB;YAC5B,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;YAClG,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAED,aAAa;IACN,MAAM,CAAC,IAAY;QACxB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,eAAe;IACf,IAAW,IAAI;QACb,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,yBAAyB;IAClB,KAAK,CAAC,KAAK;QAChB,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAAE,OAAO;QACjD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC3B,kBAAkB;gBAClB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc;oBAAE,OAAO;YAC1C,CAAC;YAED,8BAA8B;YAC9B,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnG,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC;IAED,0BAA0B;IACnB,MAAM;QACX,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 出站处理器 — dsh session/event → QQ 消息发送
|
|
3
|
+
*
|
|
4
|
+
* 采用路由器模式:OutboundRouter 持有会话级状态(文本缓冲、工具调用记录),
|
|
5
|
+
* 事件解析归一化在 events.ts,路由按事件类型分发到私有方法。
|
|
3
6
|
*/
|
|
4
7
|
import type { SessionManager } from '../session/index.js';
|
|
5
8
|
import type { ImQQBotConfig } from '../config.js';
|
|
6
9
|
import type { Logger } from '../types.js';
|
|
7
10
|
import { type QQBotSender } from './outbound-buffer.js';
|
|
8
11
|
import { type ToolsRegistryLike } from './tool-presenter.js';
|
|
12
|
+
import { type RawSessionEvent } from './events.js';
|
|
9
13
|
export type { QQBotSender } from './outbound-buffer.js';
|
|
10
14
|
export type { ToolsRegistryLike } from './tool-presenter.js';
|
|
11
|
-
/**
|
|
12
|
-
export
|
|
13
|
-
type: string;
|
|
14
|
-
data: Record<string, unknown>;
|
|
15
|
-
}
|
|
15
|
+
/** 出站处理器签名(注册到 ctx.on('session/event')) */
|
|
16
|
+
export type OutboundHandler = (session: SessionLike, event: RawSessionEvent) => void;
|
|
16
17
|
/** dsh Session 简化类型 */
|
|
17
18
|
export interface SessionLike {
|
|
18
19
|
header: {
|
|
@@ -25,5 +26,5 @@ export interface SessionLike {
|
|
|
25
26
|
* 返回一个 handler 函数,应注册到 ctx.on('session/event', handler)。
|
|
26
27
|
* toolsRegistry 用于工具结果的结构化展示(参考 dsh-TUI 的 presentResult)。
|
|
27
28
|
*/
|
|
28
|
-
export declare function createOutboundHandler(manager: SessionManager, bot: QQBotSender, config: ImQQBotConfig, logger: Logger, toolsRegistry?: ToolsRegistryLike):
|
|
29
|
+
export declare function createOutboundHandler(manager: SessionManager, bot: QQBotSender, config: ImQQBotConfig, logger: Logger, toolsRegistry?: ToolsRegistryLike): OutboundHandler;
|
|
29
30
|
//# sourceMappingURL=outbound.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../../src/transport/outbound.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../../src/transport/outbound.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAoB,KAAK,iBAAiB,EAAuB,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAQL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,2CAA2C;AAC3C,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AAErF,uBAAuB;AACvB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CACxB;AAoJD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,iBAAiB,GAChC,eAAe,CAGjB"}
|