@aalis/plugin-adapter-onebot 0.4.1
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/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/attachment-cache.d.ts +24 -0
- package/dist/attachment-cache.d.ts.map +1 -0
- package/dist/attachment-cache.js +144 -0
- package/dist/attachment-cache.js.map +1 -0
- package/dist/attachments.d.ts +12 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +163 -0
- package/dist/attachments.js.map +1 -0
- package/dist/forward-expand.d.ts +68 -0
- package/dist/forward-expand.d.ts.map +1 -0
- package/dist/forward-expand.js +275 -0
- package/dist/forward-expand.js.map +1 -0
- package/dist/forward.d.ts +79 -0
- package/dist/forward.d.ts.map +1 -0
- package/dist/forward.js +329 -0
- package/dist/forward.js.map +1 -0
- package/dist/i18n.d.ts +3 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +23 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1948 -0
- package/dist/index.js.map +1 -0
- package/dist/sent-messages.d.ts +28 -0
- package/dist/sent-messages.d.ts.map +1 -0
- package/dist/sent-messages.js +74 -0
- package/dist/sent-messages.js.map +1 -0
- package/dist/types.d.ts +199 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +309 -0
- package/dist/types.js.map +1 -0
- package/dist/v11.d.ts +29 -0
- package/dist/v11.d.ts.map +1 -0
- package/dist/v11.js +263 -0
- package/dist/v11.js.map +1 -0
- package/dist/v12.d.ts +30 -0
- package/dist/v12.d.ts.map +1 -0
- package/dist/v12.js +189 -0
- package/dist/v12.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { resolveLLMModel } from '@aalis/plugin-llm-api';
|
|
2
|
+
import { buildEnvelope, expandForward } from './forward.js';
|
|
3
|
+
import { collectForwardSegments } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* 合并转发摘要默认 system prompt。
|
|
6
|
+
*
|
|
7
|
+
* 设计重点:明确要求保留多人互动结构(谁说了什么 / 态度 / 回应关系),
|
|
8
|
+
* 避免出现 “Alice 表达了对…” 这种压成一句、丢掉互动的退化摘要。
|
|
9
|
+
*
|
|
10
|
+
* 用户可通过配置 `forward.summaryPrompt` 完全覆盖本默认值。
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_FORWARD_SUMMARY_PROMPT = '你是聊天记录摘要助手。给定一段合并转发的原始内容,用简体中文输出一段含多人互动细节的摘要:\n' +
|
|
13
|
+
'- 按时间顺序串联主线,使用“某人:……”或“某人对某人说……”这种紧凑句式保留发言人轮次与互动关系,但不要逐条复述每句寒暄;\n' +
|
|
14
|
+
'- 明确点出每位主要参与人的关键发言 / 立场 / 情绪变化,以及他们互相同意、反驳、调侃、追问的点;\n' +
|
|
15
|
+
'- 原文里出现的请求 / 指令 / 待执行事项 / 希望机器人代发或转告的内容,必须原文输出并保留具体目标对象 / 群聊 / 要表达的观点;\n' +
|
|
16
|
+
'- 图片识别结果、链接、文件名等视觉 / 附件信息也要写进来;\n' +
|
|
17
|
+
'- 不要寒暄、不要解释自己、不要使用 markdown 列表或标题;输出单段落纯文本;\n' +
|
|
18
|
+
'- 控制在目标字数以内,优先保留互动细节与可引用发言,寒暄/重复信息略去。';
|
|
19
|
+
const FORWARD_CACHE_TTL_MS = 60 * 60 * 1000;
|
|
20
|
+
const FORWARD_METADATA_NS = 'onebot:forward';
|
|
21
|
+
/**
|
|
22
|
+
* 把一个异步函数包成"同时最多 N 路"的并发受限版本。
|
|
23
|
+
* 用于合并转发内大量图片识别请求时削峰,避免压垮上游 / 触发限流。
|
|
24
|
+
*/
|
|
25
|
+
function createConcurrencyLimited(fn, limit) {
|
|
26
|
+
let active = 0;
|
|
27
|
+
const queue = [];
|
|
28
|
+
const acquire = () => {
|
|
29
|
+
if (active < limit) {
|
|
30
|
+
active++;
|
|
31
|
+
return Promise.resolve();
|
|
32
|
+
}
|
|
33
|
+
return new Promise(resolve => {
|
|
34
|
+
queue.push(() => {
|
|
35
|
+
active++;
|
|
36
|
+
resolve();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const release = () => {
|
|
41
|
+
active--;
|
|
42
|
+
const next = queue.shift();
|
|
43
|
+
if (next)
|
|
44
|
+
next();
|
|
45
|
+
};
|
|
46
|
+
return async (arg) => {
|
|
47
|
+
await acquire();
|
|
48
|
+
try {
|
|
49
|
+
return await fn(arg);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
release();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 合并转发展开器工厂。
|
|
58
|
+
*
|
|
59
|
+
* 收到一条带 forward 段的消息时,立即递归拉取原文、做图像识别、生成摘要,
|
|
60
|
+
* 并把完整原文写入此缓存(也会同步到 MemoryService.saveMetadata 做持久化),
|
|
61
|
+
* 这样:
|
|
62
|
+
* 1) LLM 在对话上下文里看到的是"信封 + 摘要",不被超长原文淹没;
|
|
63
|
+
* 2) 想看细节时调 onebot_get_forward_msg 工具直接命中缓存/持久化层;
|
|
64
|
+
* 3) 摘要会随 inbound:message 进入历史归档与向量库,被语义召回。
|
|
65
|
+
*
|
|
66
|
+
* 内存缓存 1h TTL;持久化由 memory metadata 兜底(如果实现支持)。
|
|
67
|
+
*/
|
|
68
|
+
export function createForwardExpander(deps) {
|
|
69
|
+
const { ctx, sendAction, forwardCfg } = deps;
|
|
70
|
+
const forwardCache = new Map();
|
|
71
|
+
function getCachedForward(id) {
|
|
72
|
+
const c = forwardCache.get(id);
|
|
73
|
+
if (!c)
|
|
74
|
+
return undefined;
|
|
75
|
+
if (c.expiresAt < Date.now()) {
|
|
76
|
+
forwardCache.delete(id);
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return c.entry;
|
|
80
|
+
}
|
|
81
|
+
function setCachedForward(id, entry) {
|
|
82
|
+
forwardCache.set(id, { entry, expiresAt: Date.now() + FORWARD_CACHE_TTL_MS });
|
|
83
|
+
const memory = ctx.getService('memory');
|
|
84
|
+
if (memory?.saveMetadata) {
|
|
85
|
+
memory
|
|
86
|
+
.saveMetadata(FORWARD_METADATA_NS, id, entry)
|
|
87
|
+
.catch((err) => ctx.logger.debug(`forward metadata 持久化失败 id=${id}: ${err}`));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** 从持久化层加载(缓存未命中时尝试) */
|
|
91
|
+
async function loadPersistedForward(id) {
|
|
92
|
+
const memory = ctx.getService('memory');
|
|
93
|
+
if (!memory?.getMetadata)
|
|
94
|
+
return undefined;
|
|
95
|
+
try {
|
|
96
|
+
const data = await memory.getMetadata(FORWARD_METADATA_NS, id);
|
|
97
|
+
if (data && typeof data === 'object' && typeof data.fullText === 'string') {
|
|
98
|
+
return data;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
ctx.logger.debug(`forward metadata 读取失败 id=${id}: ${err}`);
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 拉取一条合并转发的内容,依次尝试多种参数键。
|
|
108
|
+
* 不同 OneBot 实现接受的字段不同:标准为 id,NapCat/Lagrange 部分版本接受
|
|
109
|
+
* message_id / res_id / m_resid。
|
|
110
|
+
*/
|
|
111
|
+
async function fetchForwardOnce(state, id) {
|
|
112
|
+
const attempts = [{ id }, { message_id: id }, { res_id: id }, { m_resid: id }];
|
|
113
|
+
let lastErr;
|
|
114
|
+
for (const params of attempts) {
|
|
115
|
+
try {
|
|
116
|
+
return await sendAction(state, 'get_forward_msg', params);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
lastErr = err;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
ctx.logger.debug(`get_forward_msg 全部参数尝试失败 id=${id}: ${lastErr}`);
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
/** 用 LLM 给一段 forward 原文生成摘要;失败/未配置则返回 null。 */
|
|
126
|
+
async function summarizeForward(text, hint) {
|
|
127
|
+
if (!forwardCfg.summarize)
|
|
128
|
+
return null;
|
|
129
|
+
const entry = resolveLLMModel(ctx, forwardCfg.summaryLLM, ['chat']);
|
|
130
|
+
if (!entry) {
|
|
131
|
+
ctx.logger.debug('forward 摘要:无可用 LLM 服务,跳过');
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const llm = entry.instance;
|
|
135
|
+
const inputLimit = forwardCfg.summaryInputLimit;
|
|
136
|
+
const trimmedInput = inputLimit > 0 && text.length > inputLimit ? `${text.slice(0, inputLimit)}\n…(原文已截断)` : text;
|
|
137
|
+
// 摘要 prompt:用户可通过 forward.summaryPrompt 覆盖默认值,默认 prompt
|
|
138
|
+
// 明确要求保留多人互动结构,避免压成一句的退化摘要。
|
|
139
|
+
const sys = forwardCfg.summaryPrompt && forwardCfg.summaryPrompt.trim().length > 0
|
|
140
|
+
? forwardCfg.summaryPrompt
|
|
141
|
+
: DEFAULT_FORWARD_SUMMARY_PROMPT;
|
|
142
|
+
const userPrompt = `合并转发包含 ${hint.count} 条消息,主要参与人:${hint.participants.join(', ') || '未知'}。\n目标字数:≤${forwardCfg.summaryMaxChars} 字(可超出 10% 以完整保留互动结构)。\n\n原文:\n${trimmedInput}`;
|
|
143
|
+
try {
|
|
144
|
+
const resp = await llm.chat({
|
|
145
|
+
messages: [
|
|
146
|
+
{ role: 'system', content: sys },
|
|
147
|
+
{ role: 'user', content: userPrompt },
|
|
148
|
+
],
|
|
149
|
+
temperature: 0.3,
|
|
150
|
+
think: false,
|
|
151
|
+
maxTokens: Math.max(800, Math.ceil(forwardCfg.summaryMaxChars * 1.5)),
|
|
152
|
+
});
|
|
153
|
+
const out = (resp.content ?? '').trim();
|
|
154
|
+
if (!out) {
|
|
155
|
+
ctx.logger.debug(`forward 摘要返回空内容: model=${forwardCfg.summaryLLM ? `${forwardCfg.summaryLLM.provider}/${forwardCfg.summaryLLM.model}` : 'default'}, chars=${forwardCfg.summaryMaxChars}`);
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
ctx.logger.warn(`forward 摘要生成失败: ${err}`);
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 把 event.text 中所有 <forward id="X">[合并转发消息]</forward> 占位符
|
|
167
|
+
* 替换为"信封文本"(含摘要);完整原文写入 forwardCache + memory metadata。
|
|
168
|
+
*
|
|
169
|
+
* 优先使用消息段里随帧带来的 inline content(部分 NapCat 版本会内嵌),
|
|
170
|
+
* 这种情况下顶层无需走网络。
|
|
171
|
+
*/
|
|
172
|
+
async function expandForwardsInText(state, text, rawSegments) {
|
|
173
|
+
if (!forwardCfg.enabled)
|
|
174
|
+
return text;
|
|
175
|
+
if (!text.includes('<forward id='))
|
|
176
|
+
return text;
|
|
177
|
+
const inlineMap = new Map();
|
|
178
|
+
if (rawSegments && Array.isArray(rawSegments)) {
|
|
179
|
+
for (const f of collectForwardSegments(rawSegments)) {
|
|
180
|
+
if (f.inlineNodes && f.inlineNodes.length > 0)
|
|
181
|
+
inlineMap.set(f.id, f.inlineNodes);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const idRe = /<forward id="([^"]+)">\[合并转发消息\]<\/forward>/g;
|
|
185
|
+
const ids = new Set();
|
|
186
|
+
let m = idRe.exec(text);
|
|
187
|
+
while (m !== null) {
|
|
188
|
+
ids.add(m[1]);
|
|
189
|
+
m = idRe.exec(text);
|
|
190
|
+
}
|
|
191
|
+
if (ids.size === 0)
|
|
192
|
+
return text;
|
|
193
|
+
const mediaSvc = ctx.getService('media');
|
|
194
|
+
const rawRecognize = forwardCfg.imageRecognition && mediaSvc?.describeImage ? (src) => mediaSvc.describeImage(src) : undefined;
|
|
195
|
+
const concurrency = Math.max(1, forwardCfg.imageRecognitionConcurrency);
|
|
196
|
+
// 用一个简单 semaphore 限制单次展开内的图片/音频/视频识别并发,避免 OOM/触发上游限流
|
|
197
|
+
const recognizeImage = rawRecognize ? createConcurrencyLimited(rawRecognize, concurrency) : undefined;
|
|
198
|
+
const recognizeAudio = mediaSvc?.transcribe
|
|
199
|
+
? createConcurrencyLimited((src) => mediaSvc.transcribe({ kind: 'audio', data: src }), concurrency)
|
|
200
|
+
: undefined;
|
|
201
|
+
const recognizeVideo = mediaSvc?.describeVideo
|
|
202
|
+
? createConcurrencyLimited(async (src) => (await mediaSvc.describeVideo(src)) || undefined, concurrency)
|
|
203
|
+
: undefined;
|
|
204
|
+
const envelopeMap = new Map();
|
|
205
|
+
for (const id of ids) {
|
|
206
|
+
let entry = getCachedForward(id);
|
|
207
|
+
if (!entry) {
|
|
208
|
+
const persisted = await loadPersistedForward(id);
|
|
209
|
+
if (persisted) {
|
|
210
|
+
setCachedForward(id, persisted);
|
|
211
|
+
entry = persisted;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (entry) {
|
|
215
|
+
envelopeMap.set(id, buildEnvelope({
|
|
216
|
+
id,
|
|
217
|
+
count: entry.count,
|
|
218
|
+
participants: entry.participants,
|
|
219
|
+
fullText: entry.fullText,
|
|
220
|
+
truncatedDepth: false,
|
|
221
|
+
truncatedNodes: false,
|
|
222
|
+
}, entry.summary));
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
const expanded = await expandForward(id, inlineMap.get(id) ?? null, {
|
|
227
|
+
fetchForward: (childId) => fetchForwardOnce(state, childId),
|
|
228
|
+
recognizeImage,
|
|
229
|
+
recognizeAudio,
|
|
230
|
+
recognizeVideo,
|
|
231
|
+
maxDepth: forwardCfg.maxDepth,
|
|
232
|
+
maxNodesPerLevel: forwardCfg.maxNodesPerLevel,
|
|
233
|
+
imageRecognitionEnabled: forwardCfg.imageRecognition,
|
|
234
|
+
});
|
|
235
|
+
if (!expanded.fullText.trim()) {
|
|
236
|
+
envelopeMap.set(id, `<forward id="${id}">[合并转发消息:协议端无法读取(可能已过期/不在当前会话作用域)]</forward>`);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const summary = await summarizeForward(expanded.fullText, {
|
|
240
|
+
count: expanded.count,
|
|
241
|
+
participants: expanded.participants,
|
|
242
|
+
});
|
|
243
|
+
const stored = {
|
|
244
|
+
fullText: expanded.fullText,
|
|
245
|
+
summary,
|
|
246
|
+
count: expanded.count,
|
|
247
|
+
participants: expanded.participants,
|
|
248
|
+
expandedAt: Date.now(),
|
|
249
|
+
};
|
|
250
|
+
setCachedForward(id, stored);
|
|
251
|
+
const truncFlag = expanded.truncatedDepth || expanded.truncatedNodes ? ' [truncated]' : '';
|
|
252
|
+
// 日志里输出完整摘要(或在无摘要时输出完整原文),便于排查 forward 实际入库内容;
|
|
253
|
+
// 不再做 80 字 preview 截断,避免「日志看不到全貌」。原文/摘要都已入库到
|
|
254
|
+
// forwardCache + memory metadata,后续 onebot_get_forward_msg 可直接取回。
|
|
255
|
+
const fullPreview = (summary ?? expanded.fullText).replace(/\n/g, ' ');
|
|
256
|
+
ctx.logger.debug(`forward 展开完成 id=${id} count=${expanded.count} participants=[${expanded.participants.join(',')}]` +
|
|
257
|
+
` summary=${summary ? `${summary.length}字` : 'null'}${truncFlag} content="${fullPreview}"`);
|
|
258
|
+
envelopeMap.set(id, buildEnvelope(expanded, summary));
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
ctx.logger.warn(`forward 展开失败 id=${id}: ${err}`);
|
|
262
|
+
envelopeMap.set(id, `<forward id="${id}">[合并转发消息:展开过程出错]</forward>`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return text.replace(idRe, (raw, id) => envelopeMap.get(id) ?? raw);
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
getCachedForward,
|
|
269
|
+
setCachedForward,
|
|
270
|
+
loadPersistedForward,
|
|
271
|
+
fetchForwardOnce,
|
|
272
|
+
expandForwardsInText,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=forward-expand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward-expand.js","sourceRoot":"","sources":["../src/forward-expand.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GACzC,iDAAiD;IACjD,mEAAmE;IACnE,uDAAuD;IACvD,0EAA0E;IAC1E,mCAAmC;IACnC,+CAA+C;IAC/C,uCAAuC,CAAC;AA8C1C,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5C,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAE7C;;;GAGG;AACH,SAAS,wBAAwB,CAC/B,EAAgC,EAChC,KAAa;IAEb,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,KAAK,GAAsB,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,GAAkB,EAAE;QAClC,IAAI,MAAM,GAAG,KAAK,EAAE,CAAC;YACnB,MAAM,EAAE,CAAC;YACT,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;YACjC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;gBACd,MAAM,EAAE,CAAC;gBACT,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,GAAS,EAAE;QACzB,MAAM,EAAE,CAAC;QACT,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,IAAI;YAAE,IAAI,EAAE,CAAC;IACnB,CAAC,CAAC;IACF,OAAO,KAAK,EAAE,GAAS,EAAE,EAAE;QACzB,MAAM,OAAO,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CAAS,IAAiC;IAC7E,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAC7C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAsD,CAAC;IAEnF,SAAS,gBAAgB,CAAC,EAAU;QAClC,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;QACzB,IAAI,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAC7B,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,CAAC,CAAC,KAAK,CAAC;IACjB,CAAC;IAED,SAAS,gBAAgB,CAAC,EAAU,EAAE,KAAmB;QACvD,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,oBAAoB,EAAE,CAAC,CAAC;QAC9E,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAgB,QAAQ,CAAC,CAAC;QACvD,IAAI,MAAM,EAAE,YAAY,EAAE,CAAC;YACzB,MAAM;iBACH,YAAY,CAAC,mBAAmB,EAAE,EAAE,EAAE,KAA2C,CAAC;iBAClF,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,KAAK,UAAU,oBAAoB,CAAC,EAAU;QAC5C,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAgB,QAAQ,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,EAAE,WAAW;YAAE,OAAO,SAAS,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;YAC/D,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAQ,IAA+B,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACtG,OAAO,IAA+B,CAAC;YACzC,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,KAAK,UAAU,gBAAgB,CAAC,KAAa,EAAE,EAAU;QACvD,MAAM,QAAQ,GAAmC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/G,IAAI,OAAgB,CAAC;QACrB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,OAAO,MAAM,UAAU,CAAC,KAAK,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAC;YAC5D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,GAAG,GAAG,CAAC;YAChB,CAAC;QACH,CAAC;QACD,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,OAAO,EAAE,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+CAA+C;IAC/C,KAAK,UAAU,gBAAgB,CAC7B,IAAY,EACZ,IAA+C;QAE/C,IAAI,CAAC,UAAU,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QAEvC,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,EAAE,UAAU,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QACpE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC;QAE3B,MAAM,UAAU,GAAG,UAAU,CAAC,iBAAiB,CAAC;QAChD,MAAM,YAAY,GAChB,UAAU,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;QAE/F,wDAAwD;QACxD,4BAA4B;QAC5B,MAAM,GAAG,GACP,UAAU,CAAC,aAAa,IAAI,UAAU,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YACpE,CAAC,CAAC,UAAU,CAAC,aAAa;YAC1B,CAAC,CAAC,8BAA8B,CAAC;QACrC,MAAM,UAAU,GAAG,UAAU,IAAI,CAAC,KAAK,cAAc,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,YAAY,UAAU,CAAC,eAAe,kCAAkC,YAAY,EAAE,CAAC;QAEhL,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC;gBAC1B,QAAQ,EAAE;oBACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE;oBAChC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;iBACtC;gBACD,WAAW,EAAE,GAAG;gBAChB,KAAK,EAAE,KAAK;gBACZ,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,GAAG,GAAG,CAAC,CAAC;aACtE,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACxC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,GAAG,CAAC,MAAM,CAAC,KAAK,CACd,0BAA0B,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,WAAW,UAAU,CAAC,eAAe,EAAE,CACxK,CAAC;gBACF,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;YAC1C,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,KAAK,UAAU,oBAAoB,CACjC,KAAa,EACb,IAAY,EACZ,WAA+C;QAE/C,IAAI,CAAC,UAAU,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;YAAE,OAAO,IAAI,CAAC;QAEhD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAqB,CAAC;QAC/C,IAAI,WAAW,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9C,KAAK,MAAM,CAAC,IAAI,sBAAsB,CAAC,WAAW,CAAC,EAAE,CAAC;gBACpD,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;oBAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;YACpF,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,8CAA8C,CAAC;QAC5D,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;QAC9B,IAAI,CAAC,GAA2B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;YAClB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACd,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAEhC,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAe,OAAO,CAAC,CAAC;QACvD,MAAM,YAAY,GAChB,UAAU,CAAC,gBAAgB,IAAI,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACpH,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,2BAA2B,CAAC,CAAC;QACxE,qDAAqD;QACrD,MAAM,cAAc,GAAG,YAAY,CAAC,CAAC,CAAC,wBAAwB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACtG,MAAM,cAAc,GAAG,QAAQ,EAAE,UAAU;YACzC,CAAC,CAAC,wBAAwB,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,WAAW,CAAC;YAC3G,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,cAAc,GAAG,QAAQ,EAAE,aAAa;YAC5C,CAAC,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC,MAAM,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,SAAS,EAAE,WAAW,CAAC;YAChH,CAAC,CAAC,SAAS,CAAC;QAEd,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC9C,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,IAAI,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;YACjC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,EAAE,CAAC,CAAC;gBACjD,IAAI,SAAS,EAAE,CAAC;oBACd,gBAAgB,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;oBAChC,KAAK,GAAG,SAAS,CAAC;gBACpB,CAAC;YACH,CAAC;YACD,IAAI,KAAK,EAAE,CAAC;gBACV,WAAW,CAAC,GAAG,CACb,EAAE,EACF,aAAa,CACX;oBACE,EAAE;oBACF,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,YAAY,EAAE,KAAK,CAAC,YAAY;oBAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,cAAc,EAAE,KAAK;oBACrB,cAAc,EAAE,KAAK;iBACtB,EACD,KAAK,CAAC,OAAO,CACd,CACF,CAAC;gBACF,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,EAAE,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE;oBAClE,YAAY,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC;oBACnE,cAAc;oBACd,cAAc;oBACd,cAAc;oBACd,QAAQ,EAAE,UAAU,CAAC,QAAQ;oBAC7B,gBAAgB,EAAE,UAAU,CAAC,gBAAgB;oBAC7C,uBAAuB,EAAE,UAAU,CAAC,gBAAgB;iBACrD,CAAC,CAAC;gBAEH,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;oBAC9B,WAAW,CAAC,GAAG,CACb,EAAE,EACF,gBAAgB,EAAE,+CAA+C,CAClE,CAAC;oBACF,SAAS;gBACX,CAAC;gBAED,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,EAAE;oBACxD,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,YAAY,EAAE,QAAQ,CAAC,YAAY;iBACpC,CAAC,CAAC;gBAEH,MAAM,MAAM,GAAiB;oBAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;oBAC3B,OAAO;oBACP,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,YAAY,EAAE,QAAQ,CAAC,YAAY;oBACnC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;iBACvB,CAAC;gBACF,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;gBAE7B,MAAM,SAAS,GAAG,QAAQ,CAAC,cAAc,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3F,+CAA+C;gBAC/C,6CAA6C;gBAC7C,kEAAkE;gBAClE,MAAM,WAAW,GAAG,CAAC,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBACvE,GAAG,CAAC,MAAM,CAAC,KAAK,CACd,mBAAmB,EAAE,UAAU,QAAQ,CAAC,KAAK,kBAAkB,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG;oBAC/F,YAAY,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,SAAS,aAAa,WAAW,GAAG,CAC7F,CAAC;gBAEF,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;YACxD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;gBACjD,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,gBAAgB,EAAE,6BAA6B,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAU,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO;QACL,gBAAgB;QAChB,gBAAgB;QAChB,oBAAoB;QACpB,gBAAgB;QAChB,oBAAoB;KACrB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 合并转发(forward)展开、图片识别与摘要生成。
|
|
3
|
+
*
|
|
4
|
+
* 设计目标:让 agent 处理合并转发更接近"人类阅读"的方式:
|
|
5
|
+
* - 进入对话上下文 / 历史归档的是一份摘要(信封),而非整块原文,
|
|
6
|
+
* 避免长转发淹没真正对话;
|
|
7
|
+
* - 内部图片走 media 服务转写为文字描述,保证多模态信息
|
|
8
|
+
* 不在摘要里丢失;
|
|
9
|
+
* - 嵌套转发递归展开(带深度上限与已访问 id 集合防环),让摘要能反映
|
|
10
|
+
* 多层结构;
|
|
11
|
+
* - 完整原文仍保留在缓存与 memory metadata 中,agent 想看细节时通过
|
|
12
|
+
* onebot_get_forward_msg 工具 / 缓存命中拿回。
|
|
13
|
+
*
|
|
14
|
+
* 本模块仅做"纯逻辑",不直接依赖 Context;适配器通过依赖注入提供
|
|
15
|
+
* fetchForward / recognizeImage / summarize 三个能力函数。
|
|
16
|
+
*/
|
|
17
|
+
/** 单个转发节点的扁平表示 */
|
|
18
|
+
export interface ForwardLine {
|
|
19
|
+
/** 缩进层级(顶层=0,嵌套+1) */
|
|
20
|
+
depth: number;
|
|
21
|
+
index: number;
|
|
22
|
+
nickname: string;
|
|
23
|
+
userId?: string;
|
|
24
|
+
/** 已替换图片为 [图片: 描述] / [图片] 的纯文本 */
|
|
25
|
+
text: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ExpandedForward {
|
|
28
|
+
/** forward id */
|
|
29
|
+
id: string;
|
|
30
|
+
/** 顶层节点条数(嵌套不计入) */
|
|
31
|
+
count: number;
|
|
32
|
+
/** 去重后的参与人列表(昵称(uid) 形式,最多前 8 个) */
|
|
33
|
+
participants: string[];
|
|
34
|
+
/** 完整渲染文本(用于缓存 / 工具回看 / 摘要输入) */
|
|
35
|
+
fullText: string;
|
|
36
|
+
/** 嵌套转发是否被截断(命中深度上限) */
|
|
37
|
+
truncatedDepth: boolean;
|
|
38
|
+
/** 是否有节点被截断(命中 maxNodesPerLevel) */
|
|
39
|
+
truncatedNodes: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface ForwardExpandOptions {
|
|
42
|
+
/** 抓取一个 forward id 的原始数据(成功则返回 OneBot 返回的 data) */
|
|
43
|
+
fetchForward: (id: string) => Promise<unknown | null>;
|
|
44
|
+
/** 把图片源转为文字描述(不可用则可返回 undefined) */
|
|
45
|
+
recognizeImage?: (source: string) => Promise<string | undefined>;
|
|
46
|
+
/** 把音频源(record 段)转为文字(转写或描述) */
|
|
47
|
+
recognizeAudio?: (source: string) => Promise<string | undefined>;
|
|
48
|
+
/** 把视频源转为文字描述(抽帧+音轨综合) */
|
|
49
|
+
recognizeVideo?: (source: string) => Promise<string | undefined>;
|
|
50
|
+
/** 嵌套展开深度上限(顶层为 1) */
|
|
51
|
+
maxDepth: number;
|
|
52
|
+
/** 单层节点数上限 */
|
|
53
|
+
maxNodesPerLevel: number;
|
|
54
|
+
/** 是否启用图片识别 */
|
|
55
|
+
imageRecognitionEnabled: boolean;
|
|
56
|
+
/** 是否启用音频识别(默认随 recognizeAudio 是否提供) */
|
|
57
|
+
audioRecognitionEnabled?: boolean;
|
|
58
|
+
/** 是否启用视频识别(默认随 recognizeVideo 是否提供) */
|
|
59
|
+
videoRecognitionEnabled?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 递归展开一个 forward。返回扁平行(含 depth)便于直接拼接文本。
|
|
63
|
+
*
|
|
64
|
+
* @param topId 顶层 forward id
|
|
65
|
+
* @param topNodes 顶层节点数组(如果调用方已抓到了,可直接传入;否则将通过 fetchForward 抓取)
|
|
66
|
+
*/
|
|
67
|
+
export declare function expandForward(topId: string, topNodes: unknown[] | null, opts: ForwardExpandOptions): Promise<ExpandedForward>;
|
|
68
|
+
export interface SummarizeOptions {
|
|
69
|
+
/** 调用 LLM 生成摘要(输入完整 forward 文本,输出摘要文本)。返回 null 表示不生成。 */
|
|
70
|
+
summarize?: (text: string, hint: {
|
|
71
|
+
count: number;
|
|
72
|
+
participants: string[];
|
|
73
|
+
}) => Promise<string | null>;
|
|
74
|
+
/** 摘要不可用 / 失败时的回退渲染:把完整文本截断为信封。 */
|
|
75
|
+
fallbackFullTextMaxChars: number;
|
|
76
|
+
}
|
|
77
|
+
/** 把展开结果包装成最终注入到 event.text 的"信封文本"。 */
|
|
78
|
+
export declare function buildEnvelope(expanded: ExpandedForward, summary: string | null, truncatedFallbackChars?: number): string;
|
|
79
|
+
//# sourceMappingURL=forward.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../src/forward.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,kBAAkB;AAClB,MAAM,WAAW,WAAW;IAC1B,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,oCAAoC;IACpC,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACtD,oCAAoC;IACpC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjE,gCAAgC;IAChC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjE,0BAA0B;IAC1B,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjE,sBAAsB;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe;IACf,uBAAuB,EAAE,OAAO,CAAC;IACjC,wCAAwC;IACxC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,wCAAwC;IACxC,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AA2OD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,EAC1B,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,eAAe,CAAC,CA6F1B;AAID,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACtG,mCAAmC;IACnC,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAED,wCAAwC;AACxC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,sBAAsB,SAAM,GAAG,MAAM,CAarH"}
|