@my-life-buddies/buddy-runtime 0.0.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.
Files changed (58) hide show
  1. package/README.md +175 -0
  2. package/dist/conversation/agent.d.ts +24 -0
  3. package/dist/conversation/agent.d.ts.map +1 -0
  4. package/dist/conversation/agent.js +94 -0
  5. package/dist/conversation/agent.js.map +1 -0
  6. package/dist/conversation/convert.d.ts +46 -0
  7. package/dist/conversation/convert.d.ts.map +1 -0
  8. package/dist/conversation/convert.js +275 -0
  9. package/dist/conversation/convert.js.map +1 -0
  10. package/dist/conversation/history.d.ts +18 -0
  11. package/dist/conversation/history.d.ts.map +1 -0
  12. package/dist/conversation/history.js +28 -0
  13. package/dist/conversation/history.js.map +1 -0
  14. package/dist/conversation/index.d.ts +92 -0
  15. package/dist/conversation/index.d.ts.map +1 -0
  16. package/dist/conversation/index.js +322 -0
  17. package/dist/conversation/index.js.map +1 -0
  18. package/dist/conversation/presence.d.ts +24 -0
  19. package/dist/conversation/presence.d.ts.map +1 -0
  20. package/dist/conversation/presence.js +56 -0
  21. package/dist/conversation/presence.js.map +1 -0
  22. package/dist/conversation/writeBack.d.ts +36 -0
  23. package/dist/conversation/writeBack.d.ts.map +1 -0
  24. package/dist/conversation/writeBack.js +114 -0
  25. package/dist/conversation/writeBack.js.map +1 -0
  26. package/dist/index.d.ts +5 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +4 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/log.d.ts +5 -0
  31. package/dist/log.d.ts.map +1 -0
  32. package/dist/log.js +17 -0
  33. package/dist/log.js.map +1 -0
  34. package/dist/mlbClient.d.ts +118 -0
  35. package/dist/mlbClient.d.ts.map +1 -0
  36. package/dist/mlbClient.js +322 -0
  37. package/dist/mlbClient.js.map +1 -0
  38. package/dist/model.d.ts +24 -0
  39. package/dist/model.d.ts.map +1 -0
  40. package/dist/model.js +45 -0
  41. package/dist/model.js.map +1 -0
  42. package/dist/server.d.ts +6 -0
  43. package/dist/server.d.ts.map +1 -0
  44. package/dist/server.js +99 -0
  45. package/dist/server.js.map +1 -0
  46. package/dist/tools/resource.d.ts +18 -0
  47. package/dist/tools/resource.d.ts.map +1 -0
  48. package/dist/tools/resource.js +57 -0
  49. package/dist/tools/resource.js.map +1 -0
  50. package/dist/tools/widgets.d.ts +16 -0
  51. package/dist/tools/widgets.d.ts.map +1 -0
  52. package/dist/tools/widgets.js +205 -0
  53. package/dist/tools/widgets.js.map +1 -0
  54. package/dist/types.d.ts +137 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +8 -0
  57. package/dist/types.js.map +1 -0
  58. package/package.json +37 -0
@@ -0,0 +1,114 @@
1
+ // 一场会话的写回:模型说的话怎么写回平台。
2
+ // 管:入队那一刻分配幂等键(之后重发一字不变);串行 POST /internal/v1/messages;4xx 丢弃并 warn(平台明确拒绝,重发没用);
3
+ // 网络错误 / 5xx 留队退避重发(1 秒起步、翻倍、封顶 10 秒);等队列清空;退役时清空并打断等待。
4
+ // 不管:记录长什么样(convert.ts 产出、index.ts 交进来)、写之前要先把 delta 发完(调用方通过 beforeSend 挂进来)。
5
+ import { errorText } from "../log.js";
6
+ /** 写平台遇到网络错误 / 5xx 的重发间隔 */
7
+ const WRITE_RETRY_MIN_MS = 1_000;
8
+ const WRITE_RETRY_MAX_MS = 10_000;
9
+ export class WriteBack {
10
+ deps;
11
+ queue = [];
12
+ /** 串行链正在跑 */
13
+ sending = false;
14
+ /** 幂等键里的自增号 */
15
+ sent = 0;
16
+ retryDelay = WRITE_RETRY_MIN_MS;
17
+ /** close 时打断重发等待 */
18
+ abort = new AbortController();
19
+ /** 等队列清空的人 */
20
+ waiters = [];
21
+ closed = false;
22
+ constructor(deps) {
23
+ this.deps = deps;
24
+ }
25
+ /** 入队即分配幂等键;退役后不收 */
26
+ enqueue(message) {
27
+ if (this.closed)
28
+ return;
29
+ this.sent += 1;
30
+ this.queue.push({ ...message, idempotencyKey: `buddy:${this.deps.buddyId}:${this.deps.key}:${this.deps.runId}:${this.sent}` });
31
+ void this.drain();
32
+ }
33
+ /** 等队列清空(或退役) */
34
+ flush() {
35
+ if (!this.sending && this.queue.length === 0)
36
+ return Promise.resolve();
37
+ return new Promise((resolve) => {
38
+ this.waiters.push(resolve);
39
+ });
40
+ }
41
+ /** 退役:正在退避等重发的立刻醒来并退出,队列清空 */
42
+ close() {
43
+ this.closed = true;
44
+ this.abort.abort();
45
+ this.queue = [];
46
+ }
47
+ /** 一次发队头一条:delivered → 出队;rejected(4xx)→ warn 出队;throw(网络 / 5xx)→ 留队退避后带同一个键重发 */
48
+ async drain() {
49
+ if (this.sending)
50
+ return;
51
+ this.sending = true;
52
+ try {
53
+ while (!this.closed && this.queue.length > 0) {
54
+ const head = this.queue[0];
55
+ this.deps.beforeSend();
56
+ let result;
57
+ try {
58
+ result = await this.deps.client.writeMessages(this.deps.key, [head]);
59
+ }
60
+ catch (e) {
61
+ this.deps.log.warn("写消息失败,稍后重发", {
62
+ convoKey: this.deps.key,
63
+ idempotencyKey: head.idempotencyKey,
64
+ delayMs: this.retryDelay,
65
+ error: errorText(e),
66
+ });
67
+ await waitMs(this.retryDelay, this.abort.signal);
68
+ this.retryDelay = Math.min(this.retryDelay * 2, WRITE_RETRY_MAX_MS);
69
+ continue;
70
+ }
71
+ this.retryDelay = WRITE_RETRY_MIN_MS;
72
+ if (result.kind === "delivered") {
73
+ this.deps.log.info("写回一条", { convoKey: this.deps.key, type: head.type, chars: head.text?.length ?? 0, idempotencyKey: head.idempotencyKey });
74
+ }
75
+ else {
76
+ this.deps.log.warn("写消息被平台拒绝,丢弃", {
77
+ convoKey: this.deps.key,
78
+ idempotencyKey: head.idempotencyKey,
79
+ type: head.type,
80
+ status: result.status,
81
+ body: result.body,
82
+ });
83
+ }
84
+ this.queue.shift();
85
+ }
86
+ if (this.closed)
87
+ this.queue = [];
88
+ }
89
+ finally {
90
+ this.sending = false;
91
+ const waiters = this.waiters;
92
+ this.waiters = [];
93
+ for (const resolve of waiters)
94
+ resolve();
95
+ }
96
+ }
97
+ }
98
+ /** 等 ms 毫秒;signal 触发就提前返回(不 reject) */
99
+ function waitMs(ms, signal) {
100
+ return new Promise((resolve) => {
101
+ if (signal.aborted) {
102
+ resolve();
103
+ return;
104
+ }
105
+ const finish = () => {
106
+ clearTimeout(timer);
107
+ signal.removeEventListener("abort", finish);
108
+ resolve();
109
+ };
110
+ const timer = setTimeout(finish, ms);
111
+ signal.addEventListener("abort", finish, { once: true });
112
+ });
113
+ }
114
+ //# sourceMappingURL=writeBack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeBack.js","sourceRoot":"","sources":["../../src/conversation/writeBack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { BuddyServer } from "./server.ts";
2
+ export { loadResources, readResourceTool, resourceCatalog } from "./tools/resource.ts";
3
+ export type { Resource } from "./tools/resource.ts";
4
+ export type { BuddyFactory, BuddyLogger, BuddyOptions, BuddyServerHandle, Conversation, MemoryEntry, StartOptions } from "./types.ts";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACvF,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // 包出口:搭子开发者只从这里 import。
2
+ export { BuddyServer } from "./server.js";
3
+ export { loadResources, readResourceTool, resourceCatalog } from "./tools/resource.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/log.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { BuddyLogger } from "./types.ts";
2
+ export declare function createLogger(id: string): BuddyLogger;
3
+ /** 抓到的异常转成一行文案,放进日志字段 */
4
+ export declare function errorText(e: unknown): string;
5
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAUpD;AAED,yBAAyB;AACzB,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAE5C"}
package/dist/log.js ADDED
@@ -0,0 +1,17 @@
1
+ // 最朴素的日志:一行一条,行首带搭子 id,一台机器上跑好几只时分得开。
2
+ export function createLogger(id) {
3
+ const line = (level, message, data) => {
4
+ const tail = data === undefined ? "" : ` ${JSON.stringify(data)}`;
5
+ console.log(`[${new Date().toISOString()}] [${id}] ${level} ${message}${tail}`);
6
+ };
7
+ return {
8
+ info: (m, d) => line("INFO", m, d),
9
+ warn: (m, d) => line("WARN", m, d),
10
+ error: (m, d) => line("ERROR", m, d),
11
+ };
12
+ }
13
+ /** 抓到的异常转成一行文案,放进日志字段 */
14
+ export function errorText(e) {
15
+ return e instanceof Error ? e.message : String(e);
16
+ }
17
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAItC,MAAM,UAAU,YAAY,CAAC,EAAU;IACtC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,OAAe,EAAE,IAA8B,EAAQ,EAAE;QACrF,MAAM,IAAI,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,KAAK,IAAI,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC;IACF,OAAO;QACN,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAClC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;KACpC,CAAC;AACH,CAAC;AAED,yBAAyB;AACzB,MAAM,UAAU,SAAS,CAAC,CAAU;IACnC,OAAO,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,118 @@
1
+ import type { BuddyEvent, BuddyLogger, MemoryEntry, OutgoingMessage, PullResponse } from "./types.ts";
2
+ export interface MLBClientOptions {
3
+ /** 网关地址,如 http://localhost:8788;末尾带不带斜杠都行 */
4
+ gatewayUrl: string;
5
+ /** 搭子令牌,放进每个请求的 Authorization: Bearer */
6
+ token: string;
7
+ log: BuddyLogger;
8
+ }
9
+ /** 写消息的结果:4xx 是平台明确拒绝(调用方丢弃不重发);网络错误 / 5xx 直接 throw(调用方重发) */
10
+ export type WriteResult = {
11
+ kind: "delivered";
12
+ } | {
13
+ kind: "rejected";
14
+ status: number;
15
+ body: string;
16
+ };
17
+ /** widget 类型目录里一个模块的声明 */
18
+ export interface WidgetModuleDecl {
19
+ description?: string;
20
+ record?: {
21
+ properties?: Record<string, {
22
+ type?: string;
23
+ description?: string;
24
+ }>;
25
+ required?: string[];
26
+ };
27
+ }
28
+ /** GET /internal/v1/widget-types 回的一个类型 */
29
+ export interface WidgetType {
30
+ id: string;
31
+ description?: string;
32
+ modules?: Record<string, WidgetModuleDecl>;
33
+ }
34
+ /** widget 各接口的结果:ok 时 body 是响应体 JSON;不 ok 时 error 是平台错误体里的 error 字段或网络错误文案 */
35
+ export type WidgetReply = {
36
+ ok: true;
37
+ body: any;
38
+ } | {
39
+ ok: false;
40
+ error: string;
41
+ };
42
+ export declare class MLBClient {
43
+ private readonly base;
44
+ private readonly token;
45
+ private readonly log;
46
+ constructor(options: MLBClientOptions);
47
+ /**
48
+ * GET /internal/v1/messages?convoKey=&after=&limit=。
49
+ * 网络错误与非 2xx 都 throw,交给调用方等下次通知再拉;2xx 原样回响应体(没有 context 字段 = 键已作废,由调用方判)。
50
+ */
51
+ pullMessages(convoKey: string, after: number, limit?: number): Promise<PullResponse>;
52
+ /**
53
+ * POST /internal/v1/messages { convoKey, messages }。
54
+ * 2xx → delivered;4xx → rejected(带 status 与响应体,调用方丢弃);网络错误 / 5xx → throw(调用方带同一幂等键重发)。
55
+ */
56
+ writeMessages(convoKey: string, messages: OutgoingMessage[]): Promise<WriteResult>;
57
+ /** POST /internal/v1/push。只管发,失败(网络错误或非 2xx)只记 warn,不 throw */
58
+ push(convoKey: string, event: "replying", data: {
59
+ on: boolean;
60
+ status?: string;
61
+ }): Promise<void>;
62
+ push(convoKey: string, event: "delta", data: {
63
+ text: string;
64
+ }): Promise<void>;
65
+ /** GET /internal/v1/widget-types → types 数组。非 2xx、网络错误、响应体解析不了都回 [] 并记 warn */
66
+ widgetTypes(): Promise<WidgetType[]>;
67
+ /** POST /internal/v1/widgets { convoKey, type, title } → { id } */
68
+ widgetCreate(convoKey: string, type: string, title: string): Promise<WidgetReply>;
69
+ /** PUT /internal/v1/widgets/:widgetId/:module/:recordId { convoKey, data } → { ok, revision } */
70
+ widgetWrite(convoKey: string, widgetId: string, module: string, recordId: string, data: unknown): Promise<WidgetReply>;
71
+ /**
72
+ * 不带 module:GET /internal/v1/widgets/:widgetId?convoKey= → 整个 widget(含各模块记录);
73
+ * 带 module:GET /internal/v1/widgets/:widgetId/:module?convoKey= → { records }
74
+ */
75
+ widgetRead(convoKey: string, widgetId: string, module?: string): Promise<WidgetReply>;
76
+ /** DELETE /internal/v1/widgets/:widgetId/:module/:recordId?convoKey= → { ok } */
77
+ widgetDelete(convoKey: string, widgetId: string, module: string, recordId: string): Promise<WidgetReply>;
78
+ /** widget 接口共用:2xx 回解析后的响应体;非 2xx 取错误体的 error 字段;网络错误取异常文案。都不 throw,让模型看到原因后改参数重试 */
79
+ private widgetCall;
80
+ /** GET /internal/v1/memory?convoKey= → entries(全量,按 key 字典序)。会话键作废时平台回空表 */
81
+ memoryList(convoKey: string): Promise<MemoryEntry[]>;
82
+ /** PUT /internal/v1/memory/:key { convoKey, text }:覆盖写一条(后写赢) */
83
+ memoryWrite(convoKey: string, key: string, text: string): Promise<void>;
84
+ /** DELETE /internal/v1/memory/:key?convoKey=:删一条,删不存在的也回 ok */
85
+ memoryDelete(convoKey: string, key: string): Promise<void>;
86
+ /** memory 接口共用:2xx 回解析后的响应体;非 2xx throw 平台错误体的 error 字段(超配额、key 不合法都在这);网络错误、超时原样 throw */
87
+ private memoryCall;
88
+ /** 发一个请求并把响应体读完。网络错误、超时直接 throw;HTTP 状态不在这里判 */
89
+ private call;
90
+ }
91
+ export declare class EventStream {
92
+ private readonly base;
93
+ private readonly token;
94
+ private readonly log;
95
+ private readonly onEvent;
96
+ private run;
97
+ constructor(options: MLBClientOptions & {
98
+ onEvent: (event: BuddyEvent) => void;
99
+ });
100
+ /** 连上 GET /internal/v1/events 并一直保持;已经在跑就不重复起。不会 throw,连不上在后台退避重连 */
101
+ start(): void;
102
+ /** 断开当前连接、取消等待中的重连,之后不再连。再调 start() 会重新起一轮 */
103
+ stop(): void;
104
+ /**
105
+ * 连接循环:连上就一直读,读到服务端关流或出错就按退避等一会再连。
106
+ * 退避只针对「连不上」:这次连上过(流打开了)的,不论后来怎么断,下次都从 1 秒重新算——
107
+ * 健康连接被服务端掐掉(网关重启、顶号)不该被当成连不上而越等越久。
108
+ */
109
+ private loop;
110
+ /** 连一次并读到流结束。流一打开就把 attempt.opened 置真;非 2xx、网络错误、被 abort 都 throw */
111
+ private connectOnce;
112
+ /**
113
+ * 解一帧:取 event: 与 data: 行(多行 data 用 \n 拼),其余字段和 : 开头的注释行不管。
114
+ * 没有 data 的帧不算事件;ping / welcome / data-access 丢掉;只把 message / delete 分发出去,且 convoKey 必须合法。
115
+ */
116
+ private handleFrame;
117
+ }
118
+ //# sourceMappingURL=mlbClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mlbClient.d.ts","sourceRoot":"","sources":["../src/mlbClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,322 @@
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
+ /** 会话键:p_ 私聊、g_ 群,后面 24 位十六进制 */
9
+ const CONVO_KEY = /^[gp]_[0-9a-f]{24}$/;
10
+ /** 事件流重连退避:1 秒起步,每次翻倍,封顶 30 秒,再加 0–500 毫秒抖动 */
11
+ const RETRY_MIN_MS = 1_000;
12
+ const RETRY_MAX_MS = 30_000;
13
+ const RETRY_JITTER_MS = 500;
14
+ function baseUrlOf(gatewayUrl) {
15
+ return `${gatewayUrl.replace(/\/+$/, "")}/internal/v1`;
16
+ }
17
+ export class MLBClient {
18
+ base;
19
+ token;
20
+ log;
21
+ constructor(options) {
22
+ this.base = baseUrlOf(options.gatewayUrl);
23
+ this.token = options.token;
24
+ this.log = options.log;
25
+ }
26
+ /**
27
+ * GET /internal/v1/messages?convoKey=&after=&limit=。
28
+ * 网络错误与非 2xx 都 throw,交给调用方等下次通知再拉;2xx 原样回响应体(没有 context 字段 = 键已作废,由调用方判)。
29
+ */
30
+ async pullMessages(convoKey, after, limit = 200) {
31
+ const query = new URLSearchParams({ convoKey, after: String(after), limit: String(limit) });
32
+ const reply = await this.call("GET", `/messages?${query}`);
33
+ if (!reply.ok)
34
+ throw new Error(`GET /internal/v1/messages 回 ${reply.status}:${reply.text}`);
35
+ return JSON.parse(reply.text);
36
+ }
37
+ /**
38
+ * POST /internal/v1/messages { convoKey, messages }。
39
+ * 2xx → delivered;4xx → rejected(带 status 与响应体,调用方丢弃);网络错误 / 5xx → throw(调用方带同一幂等键重发)。
40
+ */
41
+ async writeMessages(convoKey, messages) {
42
+ const reply = await this.call("POST", "/messages", { convoKey, messages });
43
+ if (reply.ok)
44
+ return { kind: "delivered" };
45
+ if (reply.status >= 400 && reply.status < 500)
46
+ return { kind: "rejected", status: reply.status, body: reply.text };
47
+ throw new Error(`POST /internal/v1/messages 回 ${reply.status}:${reply.text}`);
48
+ }
49
+ async push(convoKey, event, data) {
50
+ try {
51
+ const reply = await this.call("POST", "/push", { convoKey, event, data });
52
+ if (!reply.ok)
53
+ this.log.warn("POST /internal/v1/push 非 2xx", { convoKey, event, status: reply.status, body: reply.text });
54
+ }
55
+ catch (e) {
56
+ this.log.warn("POST /internal/v1/push 失败", { convoKey, event, error: errorText(e) });
57
+ }
58
+ }
59
+ /** GET /internal/v1/widget-types → types 数组。非 2xx、网络错误、响应体解析不了都回 [] 并记 warn */
60
+ async widgetTypes() {
61
+ try {
62
+ const reply = await this.call("GET", "/widget-types");
63
+ if (!reply.ok) {
64
+ this.log.warn("GET /internal/v1/widget-types 非 2xx", { status: reply.status, body: reply.text });
65
+ return [];
66
+ }
67
+ const body = JSON.parse(reply.text);
68
+ if (!Array.isArray(body.types)) {
69
+ this.log.warn("GET /internal/v1/widget-types 响应体里没有 types 数组", { body: reply.text });
70
+ return [];
71
+ }
72
+ return body.types;
73
+ }
74
+ catch (e) {
75
+ this.log.warn("GET /internal/v1/widget-types 失败", { error: errorText(e) });
76
+ return [];
77
+ }
78
+ }
79
+ /** POST /internal/v1/widgets { convoKey, type, title } → { id } */
80
+ widgetCreate(convoKey, type, title) {
81
+ return this.widgetCall("POST", "/widgets", { convoKey, type, title });
82
+ }
83
+ /** PUT /internal/v1/widgets/:widgetId/:module/:recordId { convoKey, data } → { ok, revision } */
84
+ widgetWrite(convoKey, widgetId, module, recordId, data) {
85
+ return this.widgetCall("PUT", `/widgets/${seg(widgetId)}/${seg(module)}/${seg(recordId)}`, { convoKey, data });
86
+ }
87
+ /**
88
+ * 不带 module:GET /internal/v1/widgets/:widgetId?convoKey= → 整个 widget(含各模块记录);
89
+ * 带 module:GET /internal/v1/widgets/:widgetId/:module?convoKey= → { records }
90
+ */
91
+ widgetRead(convoKey, widgetId, module) {
92
+ const path = module === undefined ? `/widgets/${seg(widgetId)}` : `/widgets/${seg(widgetId)}/${seg(module)}`;
93
+ return this.widgetCall("GET", `${path}?${new URLSearchParams({ convoKey })}`);
94
+ }
95
+ /** DELETE /internal/v1/widgets/:widgetId/:module/:recordId?convoKey= → { ok } */
96
+ widgetDelete(convoKey, widgetId, module, recordId) {
97
+ const path = `/widgets/${seg(widgetId)}/${seg(module)}/${seg(recordId)}`;
98
+ return this.widgetCall("DELETE", `${path}?${new URLSearchParams({ convoKey })}`);
99
+ }
100
+ /** widget 接口共用:2xx 回解析后的响应体;非 2xx 取错误体的 error 字段;网络错误取异常文案。都不 throw,让模型看到原因后改参数重试 */
101
+ async widgetCall(method, path, body) {
102
+ let reply;
103
+ try {
104
+ reply = await this.call(method, path, body);
105
+ }
106
+ catch (e) {
107
+ return { ok: false, error: errorText(e) };
108
+ }
109
+ if (reply.ok) {
110
+ try {
111
+ return { ok: true, body: reply.text === "" ? undefined : JSON.parse(reply.text) };
112
+ }
113
+ catch {
114
+ return { ok: false, error: `${method} /internal/v1${path} 响应体不是 JSON:${reply.text}` };
115
+ }
116
+ }
117
+ return { ok: false, error: errorOf(reply) };
118
+ }
119
+ /** GET /internal/v1/memory?convoKey= → entries(全量,按 key 字典序)。会话键作废时平台回空表 */
120
+ async memoryList(convoKey) {
121
+ const body = (await this.memoryCall("GET", `/memory?${new URLSearchParams({ convoKey })}`));
122
+ return body.entries;
123
+ }
124
+ /** PUT /internal/v1/memory/:key { convoKey, text }:覆盖写一条(后写赢) */
125
+ async memoryWrite(convoKey, key, text) {
126
+ await this.memoryCall("PUT", `/memory/${seg(key)}`, { convoKey, text });
127
+ }
128
+ /** DELETE /internal/v1/memory/:key?convoKey=:删一条,删不存在的也回 ok */
129
+ async memoryDelete(convoKey, key) {
130
+ await this.memoryCall("DELETE", `/memory/${seg(key)}?${new URLSearchParams({ convoKey })}`);
131
+ }
132
+ /** memory 接口共用:2xx 回解析后的响应体;非 2xx throw 平台错误体的 error 字段(超配额、key 不合法都在这);网络错误、超时原样 throw */
133
+ async memoryCall(method, path, body) {
134
+ const reply = await this.call(method, path, body);
135
+ if (!reply.ok)
136
+ throw new Error(errorOf(reply));
137
+ return JSON.parse(reply.text);
138
+ }
139
+ /** 发一个请求并把响应体读完。网络错误、超时直接 throw;HTTP 状态不在这里判 */
140
+ async call(method, path, body) {
141
+ const headers = { Authorization: `Bearer ${this.token}` };
142
+ if (body !== undefined)
143
+ headers["Content-Type"] = "application/json";
144
+ const res = await fetch(`${this.base}${path}`, {
145
+ method,
146
+ headers,
147
+ body: body === undefined ? undefined : JSON.stringify(body),
148
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
149
+ });
150
+ const text = await res.text();
151
+ return { status: res.status, ok: res.ok, text };
152
+ }
153
+ }
154
+ function seg(value) {
155
+ return encodeURIComponent(value);
156
+ }
157
+ /** 非 2xx 的错误文案:取平台错误体的 error 字段;错误体不是 JSON 或没有这个字段,退回状态码加原文 */
158
+ function errorOf(reply) {
159
+ try {
160
+ const parsed = JSON.parse(reply.text);
161
+ if (typeof parsed.error === "string")
162
+ return parsed.error;
163
+ }
164
+ catch {
165
+ // 错误体不是 JSON,下面退回用原文
166
+ }
167
+ return `HTTP ${reply.status}${reply.text === "" ? "" : `:${reply.text}`}`;
168
+ }
169
+ export class EventStream {
170
+ base;
171
+ token;
172
+ log;
173
+ onEvent;
174
+ run;
175
+ constructor(options) {
176
+ this.base = baseUrlOf(options.gatewayUrl);
177
+ this.token = options.token;
178
+ this.log = options.log;
179
+ this.onEvent = options.onEvent;
180
+ }
181
+ /** 连上 GET /internal/v1/events 并一直保持;已经在跑就不重复起。不会 throw,连不上在后台退避重连 */
182
+ start() {
183
+ if (this.run !== undefined)
184
+ return;
185
+ const run = { stopped: false, controller: new AbortController() };
186
+ this.run = run;
187
+ void this.loop(run);
188
+ }
189
+ /** 断开当前连接、取消等待中的重连,之后不再连。再调 start() 会重新起一轮 */
190
+ stop() {
191
+ const run = this.run;
192
+ if (run === undefined)
193
+ return;
194
+ this.run = undefined;
195
+ run.stopped = true;
196
+ run.controller.abort();
197
+ }
198
+ /**
199
+ * 连接循环:连上就一直读,读到服务端关流或出错就按退避等一会再连。
200
+ * 退避只针对「连不上」:这次连上过(流打开了)的,不论后来怎么断,下次都从 1 秒重新算——
201
+ * 健康连接被服务端掐掉(网关重启、顶号)不该被当成连不上而越等越久。
202
+ */
203
+ async loop(run) {
204
+ let delay = RETRY_MIN_MS;
205
+ while (!run.stopped) {
206
+ const attempt = { opened: false };
207
+ try {
208
+ await this.connectOnce(run, attempt);
209
+ if (run.stopped)
210
+ return;
211
+ this.log.warn("事件流被服务端关闭,准备重连", { delayMs: attempt.opened ? RETRY_MIN_MS : delay });
212
+ }
213
+ catch (e) {
214
+ if (run.stopped)
215
+ return;
216
+ this.log.warn("事件流断开,准备重连", { delayMs: attempt.opened ? RETRY_MIN_MS : delay, error: errorText(e) });
217
+ }
218
+ if (attempt.opened)
219
+ delay = RETRY_MIN_MS;
220
+ await sleep(delay + Math.floor(Math.random() * RETRY_JITTER_MS), run.controller.signal);
221
+ delay = Math.min(delay * 2, RETRY_MAX_MS);
222
+ }
223
+ }
224
+ /** 连一次并读到流结束。流一打开就把 attempt.opened 置真;非 2xx、网络错误、被 abort 都 throw */
225
+ async connectOnce(run, attempt) {
226
+ const res = await fetch(`${this.base}/events`, {
227
+ headers: { Authorization: `Bearer ${this.token}`, Accept: "text/event-stream" },
228
+ signal: run.controller.signal,
229
+ });
230
+ if (!res.ok || res.body === null) {
231
+ const text = await res.text().catch(() => "");
232
+ throw new Error(`GET /internal/v1/events 回 ${res.status}:${text}`);
233
+ }
234
+ attempt.opened = true;
235
+ this.log.info("事件流已连上");
236
+ const reader = res.body.getReader();
237
+ const decoder = new TextDecoder();
238
+ let buffer = "";
239
+ for (;;) {
240
+ const { value, done } = await reader.read();
241
+ if (done)
242
+ return;
243
+ // 帧之间以空行分隔;把 \r\n 统一成 \n 后按 \n\n 切,切不下来的半截留在 buffer 等下一块
244
+ buffer = (buffer + decoder.decode(value, { stream: true })).replace(/\r\n/g, "\n");
245
+ let cut = buffer.indexOf("\n\n");
246
+ while (cut !== -1) {
247
+ const frame = buffer.slice(0, cut);
248
+ buffer = buffer.slice(cut + 2);
249
+ if (run.stopped)
250
+ return;
251
+ this.handleFrame(frame);
252
+ cut = buffer.indexOf("\n\n");
253
+ }
254
+ }
255
+ }
256
+ /**
257
+ * 解一帧:取 event: 与 data: 行(多行 data 用 \n 拼),其余字段和 : 开头的注释行不管。
258
+ * 没有 data 的帧不算事件;ping / welcome / data-access 丢掉;只把 message / delete 分发出去,且 convoKey 必须合法。
259
+ */
260
+ handleFrame(frame) {
261
+ // SSE 规定没写 event: 行时事件名就是 message
262
+ let name = "message";
263
+ const data = [];
264
+ for (const line of frame.split("\n")) {
265
+ if (line === "" || line.startsWith(":"))
266
+ continue;
267
+ const colon = line.indexOf(":");
268
+ const field = colon === -1 ? line : line.slice(0, colon);
269
+ let value = colon === -1 ? "" : line.slice(colon + 1);
270
+ if (value.startsWith(" "))
271
+ value = value.slice(1);
272
+ if (field === "event")
273
+ name = value;
274
+ else if (field === "data")
275
+ data.push(value);
276
+ }
277
+ if (data.length === 0)
278
+ return;
279
+ if (name === "ping" || name === "welcome" || name === "data-access")
280
+ return;
281
+ if (name !== "message" && name !== "delete") {
282
+ this.log.warn("事件流收到不认识的事件,丢弃", { event: name });
283
+ return;
284
+ }
285
+ let payload;
286
+ try {
287
+ payload = JSON.parse(data.join("\n"));
288
+ }
289
+ catch {
290
+ this.log.warn("事件的 data 不是 JSON,丢弃", { event: name, data: data.join("\n") });
291
+ return;
292
+ }
293
+ const convoKey = typeof payload === "object" && payload !== null ? payload.convoKey : undefined;
294
+ if (typeof convoKey !== "string" || !CONVO_KEY.test(convoKey)) {
295
+ this.log.warn("事件里的 convoKey 不合法,丢弃", { event: name, convoKey });
296
+ return;
297
+ }
298
+ try {
299
+ this.onEvent({ type: name, convoKey });
300
+ }
301
+ catch (e) {
302
+ this.log.warn("onEvent 抛错", { event: name, convoKey, error: errorText(e) });
303
+ }
304
+ }
305
+ }
306
+ /** 等 ms 毫秒;signal 触发就提前返回(不 reject) */
307
+ function sleep(ms, signal) {
308
+ return new Promise((resolve) => {
309
+ if (signal.aborted) {
310
+ resolve();
311
+ return;
312
+ }
313
+ const finish = () => {
314
+ clearTimeout(timer);
315
+ signal.removeEventListener("abort", finish);
316
+ resolve();
317
+ };
318
+ const timer = setTimeout(finish, ms);
319
+ signal.addEventListener("abort", finish, { once: true });
320
+ });
321
+ }
322
+ //# sourceMappingURL=mlbClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mlbClient.js","sourceRoot":"","sources":["../src/mlbClient.ts"],"names":[],"mappings":"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"}