@my-life-buddies/buddy-runtime 0.4.2 → 0.6.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.
Files changed (47) hide show
  1. package/README.md +2 -0
  2. package/dist/conversation/agentMessageLLMMessageConverter.d.ts +2 -1
  3. package/dist/conversation/agentMessageLLMMessageConverter.d.ts.map +1 -1
  4. package/dist/conversation/agentMessageLLMMessageConverter.js +14 -3
  5. package/dist/conversation/agentMessageLLMMessageConverter.js.map +1 -1
  6. package/dist/conversation/compaction.d.ts +73 -0
  7. package/dist/conversation/compaction.d.ts.map +1 -0
  8. package/dist/conversation/compaction.js +178 -0
  9. package/dist/conversation/compaction.js.map +1 -0
  10. package/dist/conversation/history.d.ts +16 -2
  11. package/dist/conversation/history.d.ts.map +1 -1
  12. package/dist/conversation/history.js +26 -3
  13. package/dist/conversation/history.js.map +1 -1
  14. package/dist/conversation/index.d.ts +7 -1
  15. package/dist/conversation/index.d.ts.map +1 -1
  16. package/dist/conversation/index.js +32 -12
  17. package/dist/conversation/index.js.map +1 -1
  18. package/dist/conversation/mlbMessageAgentMessageConverter.d.ts +16 -5
  19. package/dist/conversation/mlbMessageAgentMessageConverter.d.ts.map +1 -1
  20. package/dist/conversation/mlbMessageAgentMessageConverter.js +36 -16
  21. package/dist/conversation/mlbMessageAgentMessageConverter.js.map +1 -1
  22. package/dist/conversation/readMLBMessages.d.ts +8 -1
  23. package/dist/conversation/readMLBMessages.d.ts.map +1 -1
  24. package/dist/conversation/readMLBMessages.js +55 -9
  25. package/dist/conversation/readMLBMessages.js.map +1 -1
  26. package/dist/conversation/writeMLBMessage.d.ts +2 -2
  27. package/dist/conversation/writeMLBMessage.d.ts.map +1 -1
  28. package/dist/conversation/writeMLBMessage.js +2 -2
  29. package/dist/conversation/writeMLBMessage.js.map +1 -1
  30. package/dist/mlbClient.d.ts +176 -1
  31. package/dist/mlbClient.d.ts.map +1 -1
  32. package/dist/mlbClient.js +535 -2
  33. package/dist/mlbClient.js.map +1 -1
  34. package/dist/server.d.ts.map +1 -1
  35. package/dist/server.js +26 -4
  36. package/dist/server.js.map +1 -1
  37. package/dist/tools/widgets.d.ts +1 -1
  38. package/dist/tools/widgets.d.ts.map +1 -1
  39. package/dist/tools/widgets.js +1 -1
  40. package/dist/tools/widgets.js.map +1 -1
  41. package/dist/types.d.ts +8 -8
  42. package/dist/types.d.ts.map +1 -1
  43. package/package.json +2 -2
  44. package/dist/platform/mlbClient.d.ts +0 -172
  45. package/dist/platform/mlbClient.d.ts.map +0 -1
  46. package/dist/platform/mlbClient.js +0 -523
  47. package/dist/platform/mlbClient.js.map +0 -1
package/dist/mlbClient.js CHANGED
@@ -1,3 +1,536 @@
1
- // Internal compatibility path. Platform protocol implementation lives in platform/.
2
- export * from "./platform/mlbClient.js";
1
+ // 平台 面的 HTTP 客户端与事件流。
2
+ // 管:拼请求路径与 query、每个请求带 Authorization: Bearer 令牌、解响应体、把非 2xx 分成「拒绝」与「该重试」;
3
+ // GET /internal/v1/events 的 SSE 长连——手工切帧解析、过滤掉心跳与 welcome / data-access、校验 convoKey、断线退避重连。
4
+ // 不管:会话纪律(什么时候拉、拉到怎么办)、消息形状转换、幂等键分配、模型调用——那些在 conversation/ 目录 / model.ts。
5
+ import { errorText } from "./log.js";
6
+ /** 除事件流以外的请求都限时 30 秒:卡死的请求超时后按网络错误处理,调用方决定重不重发 */
7
+ const REQUEST_TIMEOUT_MS = 30_000;
8
+ export const MAX_DATASETS_PER_QUERY = 8;
9
+ export const MAX_DATA_ACCESS_RESPONSE_BYTES = 512 * 1024;
10
+ /** 会话键:p_ 私聊、g_ 群,后面 24 位十六进制 */
11
+ const CONVO_KEY = /^[gp]_[0-9a-f]{24}$/;
12
+ /** 事件流重连退避:1 秒起步,每次翻倍,封顶 30 秒,再加 0–500 毫秒抖动 */
13
+ const RETRY_MIN_MS = 1_000;
14
+ const RETRY_MAX_MS = 30_000;
15
+ const RETRY_JITTER_MS = 500;
16
+ function baseUrlOf(gatewayUrl) {
17
+ return `${gatewayUrl.replace(/\/+$/, "")}/internal/v1`;
18
+ }
19
+ /** 不向模型暴露服务端原文、凭据或临时媒体地址。写入失败不自动重试。 */
20
+ export class PlatformRequestError extends Error {
21
+ status;
22
+ constructor(status) {
23
+ super(status === undefined ? "平台请求未完成,请查询最新状态后再操作" : `平台请求失败(HTTP ${status}),请查询最新状态后再操作`);
24
+ this.name = "PlatformRequestError";
25
+ this.status = status;
26
+ }
27
+ }
28
+ export class MLBClient {
29
+ base;
30
+ token;
31
+ log;
32
+ constructor(options) {
33
+ this.base = baseUrlOf(options.gatewayUrl);
34
+ this.token = options.token;
35
+ this.log = options.log;
36
+ }
37
+ /**
38
+ * GET /internal/v1/messages?convoKey=&after=&limit=。after 为平台消息时间(毫秒),不是 seq。
39
+ * 网络错误与非 2xx 都 throw,交给调用方等下次通知再拉;2xx 原样回响应体:messages 里图片记录带图片内容,hasMore 说这一页之外还有没有;
40
+ * 平台的场合交代是流内 type 为 situation 的记录。
41
+ */
42
+ async pullMessages(convoKey, after, limit = 200) {
43
+ const query = new URLSearchParams({ convoKey, after: String(after), limit: String(limit) });
44
+ // 明确声明时间游标,兼容尚未迁移的网关;时间游标主线会忽略此参数。
45
+ query.set("cursor", "timestamp");
46
+ const reply = await this.call("GET", `/messages?${query}`);
47
+ if (!reply.ok)
48
+ throw new Error(`GET /internal/v1/messages 回 ${reply.status}:${reply.text}`);
49
+ return JSON.parse(reply.text);
50
+ }
51
+ /**
52
+ * GET /internal/v1/messages?convoKey=&limit=[&before=]:不带 before 取尾窗(最近 limit 条),带 before(消息时间)取更早的一页;
53
+ * 都按时间升序回,hasMore 说这一页最旧那条之前还有没有。重建从尾往回翻用它(readMLBMessages.ts)。网络错误与非 2xx 都 throw
54
+ */
55
+ async pullTail(convoKey, before, limit = 200) {
56
+ const query = new URLSearchParams({ convoKey, limit: String(limit) });
57
+ if (before !== undefined)
58
+ query.set("before", String(before));
59
+ const reply = await this.call("GET", `/messages?${query}`);
60
+ if (!reply.ok)
61
+ throw new Error(`GET /internal/v1/messages 回 ${reply.status}:${reply.text}`);
62
+ return JSON.parse(reply.text);
63
+ }
64
+ /**
65
+ * POST /internal/v1/messages { convoKey, messages }。
66
+ * 2xx → delivered;4xx → rejected(带 status 与响应体,调用方丢弃);网络错误 / 5xx → throw(调用方带同一幂等键重发)。
67
+ */
68
+ async writeMessages(convoKey, messages) {
69
+ const reply = await this.call("POST", "/messages", { convoKey, messages });
70
+ if (reply.ok)
71
+ return { kind: "delivered", timestamps: timestampsOf(reply.text) };
72
+ if (reply.status >= 400 && reply.status < 500)
73
+ return { kind: "rejected", status: reply.status, body: reply.text };
74
+ throw new Error(`POST /internal/v1/messages 回 ${reply.status}:${reply.text}`);
75
+ }
76
+ async push(convoKey, event, data) {
77
+ try {
78
+ const reply = await this.call("POST", "/push", { convoKey, event, data });
79
+ if (!reply.ok)
80
+ this.log.warn("POST /internal/v1/push 非 2xx", { convoKey, event, status: reply.status, body: reply.text });
81
+ }
82
+ catch (e) {
83
+ this.log.warn("POST /internal/v1/push 失败", { convoKey, event, error: errorText(e) });
84
+ }
85
+ }
86
+ /** GET /internal/v1/widget-types → types 数组。非 2xx、网络错误、响应体解析不了都回 [] 并记 warn */
87
+ async widgetTypes() {
88
+ try {
89
+ const reply = await this.call("GET", "/widget-types");
90
+ if (!reply.ok) {
91
+ this.log.warn("GET /internal/v1/widget-types 非 2xx", { status: reply.status, body: reply.text });
92
+ return [];
93
+ }
94
+ const body = JSON.parse(reply.text);
95
+ if (!Array.isArray(body.types)) {
96
+ this.log.warn("GET /internal/v1/widget-types 响应体里没有 types 数组", { body: reply.text });
97
+ return [];
98
+ }
99
+ return body.types;
100
+ }
101
+ catch (e) {
102
+ this.log.warn("GET /internal/v1/widget-types 失败", { error: errorText(e) });
103
+ return [];
104
+ }
105
+ }
106
+ /** POST /internal/v1/widgets { type, title, idempotencyKey?, convoKey }:建一个小挂件,回平台给的 id;同一个 idempotencyKey 重复建回同一个 id */
107
+ async widgetCreate(convoKey, input, signal) {
108
+ const result = await this.widgetCall(convoKey, "POST", "/widgets", {
109
+ type: input.type, title: input.title, ...(input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}),
110
+ }, signal);
111
+ if (typeof result?.id !== "string" || !result.id)
112
+ throw new Error("Widget 未创建:会话无效或响应缺少 id");
113
+ return { id: result.id };
114
+ }
115
+ /** GET /internal/v1/widgets/:widgetId?convoKey=:整个小挂件,响应体里 modules 是各模块的记录 */
116
+ async widgetRead(convoKey, widgetId, signal) {
117
+ const widget = await this.widgetCall(convoKey, "GET", `/widgets/${widgetSegment(widgetId)}`, undefined, signal);
118
+ if (!widget || widget.id !== widgetId || typeof widget.type !== "string" || !widget.modules || typeof widget.modules !== "object" || Array.isArray(widget.modules))
119
+ throw new Error("Widget 读取响应无效");
120
+ return widget;
121
+ }
122
+ /** GET /internal/v1/widgets/:widgetId/:module?convoKey=:一个模块的记录,响应体的 records */
123
+ async widgetReadModule(convoKey, widgetId, module, signal) {
124
+ const body = await this.widgetCall(convoKey, "GET", `/widgets/${widgetSegment(widgetId)}/${widgetSegment(module)}`, undefined, signal);
125
+ if (!Array.isArray(body?.records))
126
+ throw new Error("Widget 模块响应无效");
127
+ return { records: body.records };
128
+ }
129
+ /** GET /internal/v1/widgets?convoKey=:这场会话里的小挂件,不带记录,响应体的 widgets;会话键作废时平台回空表 */
130
+ async widgetList(convoKey) {
131
+ const body = await this.widgetCall(convoKey, "GET", "/widgets", undefined);
132
+ if (!Array.isArray(body?.widgets))
133
+ throw new Error("Widget 列表响应无效");
134
+ return body.widgets;
135
+ }
136
+ /** PUT /internal/v1/widgets/:widgetId { title, convoKey }:改标题,id 不变 */
137
+ async widgetRename(convoKey, widgetId, title) {
138
+ await this.widgetMutation(convoKey, "PUT", `/widgets/${widgetSegment(widgetId)}`, { title });
139
+ }
140
+ /** PUT /internal/v1/widgets/:widgetId/presentation { summary, imageMediaId, convoKey }:聊天流里卡片的摘要与封面图,imageMediaId 传空串去掉封面 */
141
+ async widgetSetPresentation(convoKey, widgetId, input) {
142
+ await this.widgetMutation(convoKey, "PUT", `/widgets/${widgetSegment(widgetId)}/presentation`, { summary: input.summary, imageMediaId: input.imageMediaId });
143
+ }
144
+ /** DELETE /internal/v1/widgets/:widgetId?convoKey=:删整个小挂件连记录,删不存在的也回 ok */
145
+ async widgetDelete(convoKey, widgetId) {
146
+ await this.widgetMutation(convoKey, "DELETE", `/widgets/${widgetSegment(widgetId)}`, undefined);
147
+ }
148
+ /** PUT /internal/v1/widgets/:widgetId/:module/:recordId { data, expectedRevision?, convoKey }:写一条记录,已存在就整条覆盖;带 expectedRevision 而版本对不上时平台回 409 */
149
+ async widgetWrite(convoKey, widgetId, input, signal) {
150
+ const path = `/widgets/${widgetSegment(widgetId)}/${widgetSegment(input.module)}/${widgetSegment(input.recordId)}`;
151
+ const result = await this.widgetMutation(convoKey, "PUT", path, {
152
+ data: input.data, ...(input.expectedRevision === undefined ? {} : { expectedRevision: input.expectedRevision }),
153
+ }, signal);
154
+ return { revision: result.revision };
155
+ }
156
+ /** DELETE /internal/v1/widgets/:widgetId/:module/:recordId?convoKey=:删一条记录 */
157
+ async widgetDeleteRecord(convoKey, widgetId, module, recordId, signal) {
158
+ await this.widgetMutation(convoKey, "DELETE", `/widgets/${widgetSegment(widgetId)}/${widgetSegment(module)}/${widgetSegment(recordId)}`, undefined, signal);
159
+ }
160
+ /** 小挂件的写操作:响应体的 ok 不是 true 就 throw */
161
+ async widgetMutation(convoKey, method, path, body, signal) {
162
+ const result = await this.widgetCall(convoKey, method, path, body, signal);
163
+ if (result?.ok !== true)
164
+ throw new Error("Widget 操作未被平台确认");
165
+ return result;
166
+ }
167
+ /**
168
+ * 小挂件接口共用:没有请求体的把 convoKey 放进 query,有请求体的并进请求体。
169
+ * 非 2xx、网络错误、超时、响应超过 4 MiB、响应体不是 JSON 都 throw PlatformRequestError,只带 HTTP 状态码、不带平台原文;
170
+ * signal 触发时 throw 它的中止原因。写操作不重试。
171
+ */
172
+ async widgetCall(convoKey, method, path, body, signal) {
173
+ const url = body === undefined ? `${this.base}${path}?${new URLSearchParams({ convoKey })}` : `${this.base}${path}`;
174
+ const timed = AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), ...(signal ? [signal] : [])]);
175
+ try {
176
+ timed.throwIfAborted();
177
+ const response = await fetch(url, {
178
+ method, headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json" },
179
+ body: body === undefined ? undefined : JSON.stringify({ ...body, convoKey }), signal: timed, redirect: "error",
180
+ });
181
+ if (!response.ok) {
182
+ await response.body?.cancel();
183
+ throw new PlatformRequestError(response.status);
184
+ }
185
+ const bytes = await readLimited(response, 4 * 1024 * 1024);
186
+ timed.throwIfAborted();
187
+ return JSON.parse(Buffer.from(bytes).toString("utf8"));
188
+ }
189
+ catch (error) {
190
+ signal?.throwIfAborted();
191
+ throw error instanceof PlatformRequestError ? error : new PlatformRequestError();
192
+ }
193
+ }
194
+ /** GET /internal/v1/memory?convoKey= → entries(全量,按 key 字典序)。会话键作废时平台回空表 */
195
+ async memoryList(convoKey, signal) {
196
+ const body = (await this.memoryCall("GET", `/memory?${new URLSearchParams({ convoKey })}`, undefined, signal));
197
+ return body.entries;
198
+ }
199
+ /** PUT /internal/v1/memory/:key { convoKey, text }:覆盖写一条(后写赢) */
200
+ async memoryWrite(convoKey, key, text, signal) {
201
+ await this.memoryCall("PUT", `/memory/${seg(key)}`, { convoKey, text }, signal);
202
+ }
203
+ /** DELETE /internal/v1/memory/:key?convoKey=:删一条,删不存在的也回 ok */
204
+ async memoryDelete(convoKey, key, signal) {
205
+ await this.memoryCall("DELETE", `/memory/${seg(key)}?${new URLSearchParams({ convoKey })}`, undefined, signal);
206
+ }
207
+ /**
208
+ * POST /internal/v1/data-access/query:按当前会话读取用户已授权的 Dataset。
209
+ * 私聊不传 memberId;群聊传消息前缀里的稳定 memberId。非 2xx、坏 JSON 或响应缺 datasets 都 throw。
210
+ */
211
+ async queryDataAccess(convoKey, datasets, memberId, signal) {
212
+ const unique = [...new Set(datasets)];
213
+ if (unique.length === 0)
214
+ throw new Error("DataAccess 至少需要一个 Dataset");
215
+ if (unique.length > MAX_DATASETS_PER_QUERY)
216
+ throw new Error(`DataAccess 一次最多查询 ${MAX_DATASETS_PER_QUERY} 个 Dataset`);
217
+ const body = { convoKey, datasets: unique };
218
+ if (memberId !== undefined)
219
+ body.memberId = memberId;
220
+ const reply = await this.call("POST", "/data-access/query", body, signal);
221
+ if (!reply.ok)
222
+ throw new Error(errorOf(reply));
223
+ if (Buffer.byteLength(reply.text, "utf8") > MAX_DATA_ACCESS_RESPONSE_BYTES) {
224
+ throw new Error(`DataAccess 响应超过 ${MAX_DATA_ACCESS_RESPONSE_BYTES} 字节,请减少 Dataset 后重试`);
225
+ }
226
+ let parsed;
227
+ try {
228
+ parsed = JSON.parse(reply.text);
229
+ }
230
+ catch {
231
+ throw new Error("DataAccess 响应体不是 JSON");
232
+ }
233
+ const result = typeof parsed === "object" && parsed !== null ? parsed.datasets : undefined;
234
+ if (!Array.isArray(result))
235
+ throw new Error("DataAccess 响应体里没有 datasets 数组");
236
+ return result;
237
+ }
238
+ /** GET /internal/v1/data-access/requirements:当前搭子声明的 Dataset;失败由调用方决定是否降级。 */
239
+ async dataRequirements() {
240
+ const reply = await this.call("GET", "/data-access/requirements");
241
+ if (!reply.ok)
242
+ throw new Error(errorOf(reply));
243
+ const parsed = JSON.parse(reply.text);
244
+ if (!Array.isArray(parsed.datasets))
245
+ throw new Error("DataAccess 声明响应体里没有 datasets 数组");
246
+ return parsed.datasets;
247
+ }
248
+ async claimProactiveRun(runId) {
249
+ const reply = await this.call("GET", `/proactive/runs/${seg(runId)}`);
250
+ if (!reply.ok)
251
+ throw new PlatformRequestError(reply.status);
252
+ return JSON.parse(reply.text);
253
+ }
254
+ async proposeProactiveSubscription(sessionId, request, signal) {
255
+ const reply = await this.call("POST", "/proactive/subscriptions", { ...request, sessionId }, signal);
256
+ if (!reply.ok)
257
+ throw new PlatformRequestError(reply.status);
258
+ return JSON.parse(reply.text);
259
+ }
260
+ async queryProactiveData(runId, capabilityToken, datasets, signal) {
261
+ if (datasets.length === 0 || datasets.length > MAX_DATASETS_PER_QUERY)
262
+ throw new Error("Proactive 查询需要 1..8 个 Dataset");
263
+ const reply = await this.call("POST", `/proactive/runs/${seg(runId)}/data`, { capabilityToken, datasets: [...new Set(datasets)] }, signal);
264
+ if (!reply.ok)
265
+ throw new PlatformRequestError(reply.status);
266
+ if (Buffer.byteLength(reply.text, "utf8") > MAX_DATA_ACCESS_RESPONSE_BYTES)
267
+ throw new Error("Proactive DataAccess 响应过大");
268
+ const parsed = JSON.parse(reply.text);
269
+ if (!Array.isArray(parsed.datasets))
270
+ throw new Error("Proactive DataAccess 响应体里没有 datasets 数组");
271
+ return parsed.datasets;
272
+ }
273
+ async finishProactiveRun(runId, capabilityToken, decision) {
274
+ const reply = await this.call("POST", `/proactive/runs/${seg(runId)}/result`, { ...decision, capabilityToken });
275
+ if (!reply.ok)
276
+ throw new PlatformRequestError(reply.status);
277
+ }
278
+ /** GET /internal/v1/system-prompt?convoKey=:这场会话的平台 system prompt(私聊与群各一版),拼在开发者的前面。非 2xx、响应体没有 systemPrompt 字符串都 throw */
279
+ async systemPrompt(convoKey) {
280
+ const reply = await this.call("GET", `/system-prompt?${new URLSearchParams({ convoKey })}`);
281
+ if (!reply.ok)
282
+ throw new Error(`GET /internal/v1/system-prompt 回 ${reply.status}:${reply.text}`);
283
+ const body = JSON.parse(reply.text);
284
+ if (typeof body.systemPrompt !== "string")
285
+ throw new Error("GET /internal/v1/system-prompt 响应体里没有 systemPrompt 字符串");
286
+ return body.systemPrompt;
287
+ }
288
+ /** memory 接口共用:2xx 回解析后的响应体;非 2xx throw 平台错误体的 error 字段(超配额、key 不合法都在这);网络错误、超时原样 throw */
289
+ async memoryCall(method, path, body, signal) {
290
+ const reply = await this.call(method, path, body, signal);
291
+ if (!reply.ok)
292
+ throw new Error(errorOf(reply));
293
+ return JSON.parse(reply.text);
294
+ }
295
+ /** 发一个请求并把响应体读完。网络错误、超时直接 throw;HTTP 状态不在这里判 */
296
+ async call(method, path, body, signal) {
297
+ const headers = { Authorization: `Bearer ${this.token}` };
298
+ if (body !== undefined)
299
+ headers["Content-Type"] = "application/json";
300
+ const res = await fetch(`${this.base}${path}`, {
301
+ method,
302
+ headers,
303
+ body: body === undefined ? undefined : JSON.stringify(body),
304
+ signal: AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), ...(signal ? [signal] : [])]),
305
+ redirect: "error",
306
+ });
307
+ const text = await res.text();
308
+ return { status: res.status, ok: res.ok, text };
309
+ }
310
+ }
311
+ function timestampsOf(text) {
312
+ try {
313
+ const parsed = JSON.parse(text);
314
+ return Array.isArray(parsed.timestamps) ? parsed.timestamps.filter((t) => typeof t === "number") : [];
315
+ }
316
+ catch {
317
+ return [];
318
+ }
319
+ }
320
+ function seg(value) {
321
+ return encodeURIComponent(value);
322
+ }
323
+ /** 小挂件路径里的一段:空串、「.」「..」直接 throw,其余 encodeURIComponent */
324
+ function widgetSegment(value) {
325
+ if (!value || value === "." || value === "..")
326
+ throw new Error("Widget 标识无效");
327
+ return encodeURIComponent(value);
328
+ }
329
+ /** 读完响应体,超过 limit 字节就中止并 throw */
330
+ async function readLimited(response, limit) {
331
+ if (!response.body || Number(response.headers.get("content-length") || 0) > limit) {
332
+ await response.body?.cancel();
333
+ throw new Error(`响应超过 ${limit} 字节`);
334
+ }
335
+ const reader = response.body.getReader();
336
+ const chunks = [];
337
+ let size = 0;
338
+ try {
339
+ for (;;) {
340
+ const { done, value } = await reader.read();
341
+ if (done)
342
+ break;
343
+ size += value.length;
344
+ if (size > limit)
345
+ throw new Error(`响应超过 ${limit} 字节`);
346
+ chunks.push(value);
347
+ }
348
+ }
349
+ finally {
350
+ await reader.cancel().catch(() => { });
351
+ reader.releaseLock();
352
+ }
353
+ return Buffer.concat(chunks);
354
+ }
355
+ /** 非 2xx 的错误文案:取平台错误体的 error 字段;错误体不是 JSON 或没有这个字段,退回状态码加原文 */
356
+ function errorOf(reply) {
357
+ try {
358
+ const parsed = JSON.parse(reply.text);
359
+ if (typeof parsed.error === "string")
360
+ return parsed.error;
361
+ }
362
+ catch {
363
+ // 错误体不是 JSON,下面退回用原文
364
+ }
365
+ return `HTTP ${reply.status}${reply.text === "" ? "" : `:${reply.text}`}`;
366
+ }
367
+ export class EventStream {
368
+ includeWelcome;
369
+ base;
370
+ token;
371
+ log;
372
+ onEvent;
373
+ run;
374
+ constructor(options) {
375
+ this.includeWelcome = options.includeWelcome === true;
376
+ this.base = baseUrlOf(options.gatewayUrl);
377
+ this.token = options.token;
378
+ this.log = options.log;
379
+ this.onEvent = options.onEvent;
380
+ }
381
+ /** 连上 GET /internal/v1/events 并一直保持;已经在跑就不重复起。不会 throw,连不上在后台退避重连 */
382
+ start() {
383
+ if (this.run !== undefined)
384
+ return;
385
+ const run = { stopped: false, controller: new AbortController() };
386
+ this.run = run;
387
+ void this.loop(run);
388
+ }
389
+ /** 断开当前连接、取消等待中的重连,之后不再连。再调 start() 会重新起一轮 */
390
+ stop() {
391
+ const run = this.run;
392
+ if (run === undefined)
393
+ return;
394
+ this.run = undefined;
395
+ run.stopped = true;
396
+ run.controller.abort();
397
+ }
398
+ /**
399
+ * 连接循环:连上就一直读,读到服务端关流或出错就按退避等一会再连。
400
+ * 退避只针对「连不上」:这次连上过(流打开了)的,不论后来怎么断,下次都从 1 秒重新算——
401
+ * 健康连接被服务端掐掉(网关重启、顶号)不该被当成连不上而越等越久。
402
+ */
403
+ async loop(run) {
404
+ let delay = RETRY_MIN_MS;
405
+ while (!run.stopped) {
406
+ const attempt = { opened: false };
407
+ try {
408
+ await this.connectOnce(run, attempt);
409
+ if (run.stopped)
410
+ return;
411
+ this.log.warn("事件流被服务端关闭,准备重连", { delayMs: attempt.opened ? RETRY_MIN_MS : delay });
412
+ }
413
+ catch (e) {
414
+ if (run.stopped)
415
+ return;
416
+ this.log.warn("事件流断开,准备重连", { delayMs: attempt.opened ? RETRY_MIN_MS : delay, error: errorText(e) });
417
+ }
418
+ if (attempt.opened)
419
+ delay = RETRY_MIN_MS;
420
+ await sleep(delay + Math.floor(Math.random() * RETRY_JITTER_MS), run.controller.signal);
421
+ delay = Math.min(delay * 2, RETRY_MAX_MS);
422
+ }
423
+ }
424
+ /** 连一次并读到流结束。流一打开就把 attempt.opened 置真;非 2xx、网络错误、被 abort 都 throw */
425
+ async connectOnce(run, attempt) {
426
+ const res = await fetch(`${this.base}/events`, {
427
+ headers: { Authorization: `Bearer ${this.token}`, Accept: "text/event-stream" },
428
+ signal: run.controller.signal,
429
+ });
430
+ if (!res.ok || res.body === null) {
431
+ const text = await res.text().catch(() => "");
432
+ throw new Error(`GET /internal/v1/events 回 ${res.status}:${text}`);
433
+ }
434
+ attempt.opened = true;
435
+ this.log.info("事件流已连上");
436
+ const reader = res.body.getReader();
437
+ const decoder = new TextDecoder();
438
+ let buffer = "";
439
+ for (;;) {
440
+ const { value, done } = await reader.read();
441
+ if (done)
442
+ return;
443
+ // 帧之间以空行分隔;把 \r\n 统一成 \n 后按 \n\n 切,切不下来的半截留在 buffer 等下一块
444
+ buffer = (buffer + decoder.decode(value, { stream: true })).replace(/\r\n/g, "\n");
445
+ let cut = buffer.indexOf("\n\n");
446
+ while (cut !== -1) {
447
+ const frame = buffer.slice(0, cut);
448
+ buffer = buffer.slice(cut + 2);
449
+ if (run.stopped)
450
+ return;
451
+ this.handleFrame(frame);
452
+ cut = buffer.indexOf("\n\n");
453
+ }
454
+ }
455
+ }
456
+ /**
457
+ * 解一帧:取 event: 与 data: 行(多行 data 用 \n 拼),其余字段和 : 开头的注释行不管。
458
+ * 没有 data 的帧不算事件;ping / welcome / data-access 丢掉;只把 message / delete 分发出去,且 convoKey 必须合法。
459
+ */
460
+ handleFrame(frame) {
461
+ // SSE 规定没写 event: 行时事件名就是 message
462
+ let name = "message";
463
+ const data = [];
464
+ for (const line of frame.split("\n")) {
465
+ if (line === "" || line.startsWith(":"))
466
+ continue;
467
+ const colon = line.indexOf(":");
468
+ const field = colon === -1 ? line : line.slice(0, colon);
469
+ let value = colon === -1 ? "" : line.slice(colon + 1);
470
+ if (value.startsWith(" "))
471
+ value = value.slice(1);
472
+ if (field === "event")
473
+ name = value;
474
+ else if (field === "data")
475
+ data.push(value);
476
+ }
477
+ if (data.length === 0)
478
+ return;
479
+ if (name === "ping" || (name === "welcome" && !this.includeWelcome) || name === "data-access")
480
+ return;
481
+ if (name !== "message" && name !== "delete" && name !== "welcome" && name !== "proactive") {
482
+ this.log.warn("事件流收到不认识的事件,丢弃", { event: name });
483
+ return;
484
+ }
485
+ let payload;
486
+ try {
487
+ payload = JSON.parse(data.join("\n"));
488
+ }
489
+ catch {
490
+ this.log.warn("事件的 data 不是 JSON,丢弃", { event: name, data: data.join("\n") });
491
+ return;
492
+ }
493
+ if (name === "proactive") {
494
+ const runId = typeof payload === "object" && payload !== null ? payload.runId : undefined;
495
+ if (typeof runId !== "string" || !/^pr_[a-f0-9]{24}$/.test(runId)) {
496
+ this.log.warn("proactive 事件里的 runId 不合法,丢弃");
497
+ return;
498
+ }
499
+ try {
500
+ this.onEvent({ type: "proactive", runId });
501
+ }
502
+ catch (e) {
503
+ this.log.warn("onEvent 抛错", { event: name, runId, error: errorText(e) });
504
+ }
505
+ return;
506
+ }
507
+ const convoKey = typeof payload === "object" && payload !== null ? payload.convoKey : undefined;
508
+ if (typeof convoKey !== "string" || !CONVO_KEY.test(convoKey)) {
509
+ this.log.warn("事件里的 convoKey 不合法,丢弃", { event: name, convoKey });
510
+ return;
511
+ }
512
+ try {
513
+ this.onEvent({ type: name, convoKey });
514
+ }
515
+ catch (e) {
516
+ this.log.warn("onEvent 抛错", { event: name, convoKey, error: errorText(e) });
517
+ }
518
+ }
519
+ }
520
+ /** 等 ms 毫秒;signal 触发就提前返回(不 reject) */
521
+ function sleep(ms, signal) {
522
+ return new Promise((resolve) => {
523
+ if (signal.aborted) {
524
+ resolve();
525
+ return;
526
+ }
527
+ const finish = () => {
528
+ clearTimeout(timer);
529
+ signal.removeEventListener("abort", finish);
530
+ resolve();
531
+ };
532
+ const timer = setTimeout(finish, ms);
533
+ signal.addEventListener("abort", finish, { once: true });
534
+ });
535
+ }
3
536
  //# sourceMappingURL=mlbClient.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mlbClient.js","sourceRoot":"","sources":["../src/mlbClient.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"mlbClient.js","sourceRoot":"","sources":["../src/mlbClient.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAc,iBAAiB,EAAmB,YAAY,EAAE,MAAM,YAAY,CAAC;AAoC/F,qBAAa,WAAW;IACvB,iDAAiD;WACpC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA6HrE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAc,iBAAiB,EAAmB,YAAY,EAAE,MAAM,YAAY,CAAC;AAoC/F,qBAAa,WAAW;IACvB,iDAAiD;WACpC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA+IrE"}
package/dist/server.js CHANGED
@@ -1,12 +1,13 @@
1
1
  // 进程级入口:一只搭子起来后长什么样。
2
2
  // 管:读环境变量(MLB_BUDDY_ID / MLB_BUDDY_TOKEN 必填;网关地址缺省连 ecs-test,开发者不用填,设了 MLB_GATEWAY_URL 才覆盖)、
3
3
  // 建日志 / MLBClient / 模型条目、启动时读一次 resources/ 目录里的资料、小挂件类型目录懒拉一次存 promise、按会话键管一张 ConversationHandle 表、
4
- // 把事件流的 message / delete 分发给对应会话、每 60 秒淘汰不忙且 30 分钟没消息的会话、stop 时把一切收掉。
4
+ // 把事件流的 message / delete 分发给对应会话、每 60 秒淘汰不忙且 30 分钟没消息的会话(淘汰前历史超过触发线的拍快照、回收后在后台压缩写回,见 conversation/compaction.ts)、stop 时把一切收掉。
5
5
  // 不管:会话里的纪律(conversation/ 目录)、协议细节(mlbClient.ts)。没有 HTTP 面、没有主动触达、没有会话列表。
6
6
  import { existsSync } from "node:fs";
7
7
  import { dirname, join, resolve } from "node:path";
8
+ import { compactConversation } from "./conversation/compaction.js";
8
9
  import { ConversationHandle } from "./conversation/index.js";
9
- import { createLogger } from "./log.js";
10
+ import { createLogger, errorText } from "./log.js";
10
11
  import { EventStream, MLBClient } from "./mlbClient.js";
11
12
  import { createModel, streamFn } from "./model.js";
12
13
  import { loadResources } from "./tools/resource.js";
@@ -149,11 +150,30 @@ export class BuddyServer {
149
150
  };
150
151
  const stream = new EventStream({ gatewayUrl, token, log, onEvent, includeWelcome: !!options.welcome });
151
152
  stream.start();
153
+ // 回收后在后台压缩:同一场会话同时只跑一次;stop 时打断
154
+ const compactions = new Map();
155
+ const startCompaction = (key, snapshot) => {
156
+ if (compactions.has(key))
157
+ return;
158
+ const abort = new AbortController();
159
+ compactions.set(key, abort);
160
+ void compactConversation({ client, key, buddyId, model, streamFn, token, log, signal: abort.signal }, snapshot)
161
+ .catch((e) => log.warn("压缩失败,下次回收再试", { convoKey: key, error: errorText(e) }))
162
+ .finally(() => {
163
+ if (compactions.get(key) === abort)
164
+ compactions.delete(key);
165
+ });
166
+ };
152
167
  const sweeper = setInterval(() => {
153
168
  const now = Date.now();
154
169
  for (const [key, conversation] of conversations) {
155
- if (!conversation.busy && now - conversation.lastActivity > IDLE_AFTER_MS)
156
- dropConversation(key, "idle");
170
+ if (conversation.busy || now - conversation.lastActivity <= IDLE_AFTER_MS)
171
+ continue;
172
+ // 回收前看一眼历史超没超触发线:超了拍快照,会话照常回收,不等摘要
173
+ const snapshot = conversation.snapshotForCompaction();
174
+ dropConversation(key, "idle");
175
+ if (snapshot !== undefined)
176
+ startCompaction(key, snapshot);
157
177
  }
158
178
  }, SWEEP_INTERVAL_MS);
159
179
  sweeper.unref();
@@ -163,6 +183,8 @@ export class BuddyServer {
163
183
  stopped = true;
164
184
  stream.stop();
165
185
  clearInterval(sweeper);
186
+ for (const abort of compactions.values())
187
+ abort.abort();
166
188
  const closing = [...conversations.values()].map((conversation) => conversation.close());
167
189
  conversations.clear();
168
190
  await Promise.all(closing);