@migor/agentia 0.8.2 → 0.9.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 (57) hide show
  1. package/CHANGELOG.md +283 -2
  2. package/README.en.md +2 -2
  3. package/README.md +7 -5
  4. package/dist/AGENTS.md +132 -8
  5. package/dist/core/limits.d.ts +226 -0
  6. package/dist/core/limits.js +216 -0
  7. package/dist/core/limits.js.map +1 -0
  8. package/dist/core/trace.d.ts +66 -2
  9. package/dist/core/trace.js +37 -2
  10. package/dist/core/trace.js.map +1 -1
  11. package/dist/engine/forwarded.d.ts +84 -0
  12. package/dist/engine/forwarded.js +39 -0
  13. package/dist/engine/forwarded.js.map +1 -0
  14. package/dist/engine/run-config.d.ts +4 -1
  15. package/dist/engine/run-config.js +14 -1
  16. package/dist/engine/run-config.js.map +1 -1
  17. package/dist/engine/spec.d.ts +26 -1
  18. package/dist/engine/spec.js.map +1 -1
  19. package/dist/engine/tracer.d.ts +68 -1
  20. package/dist/engine/tracer.js +136 -14
  21. package/dist/engine/tracer.js.map +1 -1
  22. package/dist/index.d.ts +4 -3
  23. package/dist/index.js +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/integrations/adapter-options.d.ts +0 -7
  26. package/dist/integrations/adapter-options.js +2 -1
  27. package/dist/integrations/adapter-options.js.map +1 -1
  28. package/dist/integrations/mcp-stdio.js +9 -1
  29. package/dist/integrations/mcp-stdio.js.map +1 -1
  30. package/dist/integrations/metrics-state.d.ts +2 -1
  31. package/dist/integrations/metrics-state.js +6 -2
  32. package/dist/integrations/metrics-state.js.map +1 -1
  33. package/dist/runtime/run.d.ts +13 -1
  34. package/dist/runtime/run.js +14 -3
  35. package/dist/runtime/run.js.map +1 -1
  36. package/dist/toolkit/module.d.ts +29 -1
  37. package/dist/toolkit/module.js +16 -0
  38. package/dist/toolkit/module.js.map +1 -1
  39. package/dist/toolkit/skill.js +4 -13
  40. package/dist/toolkit/skill.js.map +1 -1
  41. package/dist/toolkit/subagent.js +6 -17
  42. package/dist/toolkit/subagent.js.map +1 -1
  43. package/dist/transport/async.d.ts +119 -0
  44. package/dist/transport/async.js +125 -9
  45. package/dist/transport/async.js.map +1 -1
  46. package/dist/transport/http-route.d.ts +6 -1
  47. package/dist/transport/http-route.js +9 -1
  48. package/dist/transport/http-route.js.map +1 -1
  49. package/dist/transport/http.js +99 -1
  50. package/dist/transport/http.js.map +1 -1
  51. package/dist/transport/sse.d.ts +6 -2
  52. package/dist/transport/sse.js +3 -2
  53. package/dist/transport/sse.js.map +1 -1
  54. package/dist/transport/task-events.d.ts +90 -0
  55. package/dist/transport/task-events.js +159 -0
  56. package/dist/transport/task-events.js.map +1 -0
  57. package/package.json +5 -3
@@ -34,8 +34,9 @@ export function sseWriter(res, opts = {}) {
34
34
  get closed() {
35
35
  return closed;
36
36
  },
37
- event(name, data) {
38
- emit(`event: ${name}\ndata: ${JSON.stringify(data)}\n\n`);
37
+ event(name, data, id) {
38
+ // id 行必须在 event 行之前(SSE 规范:一个事件的字段按 id / event / data 顺序)
39
+ emit(`${id === undefined ? '' : `id: ${id}\n`}event: ${name}\ndata: ${JSON.stringify(data)}\n\n`);
39
40
  },
40
41
  comment(text) {
41
42
  emit(`: ${text}\n\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/transport/sse.ts"],"names":[],"mappings":"AAwCA,qDAAqD;AACrD,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAE9D,MAAM,UAAU,SAAS,CAAC,GAAmB,EAAE,IAAI,GAAqB,EAAE;IACxE,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,IAAI,8BAA8B,CAAC;IAC3E,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,cAAc,EAAE,kCAAkC;QAClD,eAAe,EAAE,wBAAwB;QACzC,UAAU,EAAE,YAAY;QACxB,yCAAyC;QACzC,mBAAmB,EAAE,IAAI;KAC1B,CAAC,CAAC;IAEH,qCAAqC;IACrC,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjG,MAAM,IAAI,GAAG,CAAC,KAAa,EAAQ,EAAE;QACnC,IAAI,MAAM;YAAE,OAAO;QACnB,MAAM,OAAO,GAAG,QAAQ,EAAE,CAAC;QAC3B,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;YACzB,oCAAoC;YACpC,MAAM,GAAG,IAAI,CAAC;YACd,IAAI,CAAC;gBACH,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;YAChE,CAAC;YAAC,MAAM,CAAC;gBACP,qBAAqB;YACvB,CAAC;YACD,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,MAAM;YACR,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,KAAK,CAAC,IAAY,EAAE,IAAa;YAC/B,IAAI,CAAC,UAAU,IAAI,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,CAAC,IAAY;YAClB,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC;QACxB,CAAC;QACD,KAAK;YACH,IAAI,MAAM;gBAAE,OAAO;YACnB,MAAM,GAAG,IAAI,CAAC;YACd,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/transport/sse.ts"],"names":[],"mappings":"AA4CA,qDAAqD;AACrD,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAE9D,MAAM,UAAU,SAAS,CAAC,GAAmB,EAAE,IAAI,GAAqB,EAAE;IACxE,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,IAAI,8BAA8B,CAAC;IAC3E,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,cAAc,EAAE,kCAAkC;QAClD,eAAe,EAAE,wBAAwB;QACzC,UAAU,EAAE,YAAY;QACxB,yCAAyC;QACzC,mBAAmB,EAAE,IAAI;KAC1B,CAAC,CAAC;IAEH,qCAAqC;IACrC,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjG,MAAM,IAAI,GAAG,CAAC,KAAa,EAAQ,EAAE;QACnC,IAAI,MAAM;YAAE,OAAO;QACnB,MAAM,OAAO,GAAG,QAAQ,EAAE,CAAC;QAC3B,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;YACzB,oCAAoC;YACpC,MAAM,GAAG,IAAI,CAAC;YACd,IAAI,CAAC;gBACH,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;YAChE,CAAC;YAAC,MAAM,CAAC;gBACP,qBAAqB;YACvB,CAAC;YACD,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,MAAM;YACR,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,KAAK,CAAC,IAAY,EAAE,IAAa,EAAE,EAAW;YAC5C,0DAA0D;YAC1D,IAAI,CACF,GAAG,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,UAAU,IAAI,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAC5F,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,IAAY;YAClB,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC;QACxB,CAAC;QACD,KAAK;YACH,IAAI,MAAM;gBAAE,OAAO;YACnB,MAAM,GAAG,IAAI,CAAC;YACd,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,90 @@
1
+ import type { TraceRecordEvent } from '../core/trace.js';
2
+ /**
3
+ * 任务记账事件流 —— **每任务的事件缓冲 + 订阅表**(`AsyncRunner` 拆分的又一块纯件)。
4
+ *
5
+ * 为什么单独一件:`GET /tasks/:id/stream` 要「连上就能重放 + 之后转实时 + 终态收口」,
6
+ * 这三件事全是**纯记账**,与 store / 引擎 / 槽位无关;留在 855 行的 `AsyncRunner` 里
7
+ * 只会让它再长一截,而这块恰好是最容易用单测钉住的(内存边界、丢最旧、序号连续性)。
8
+ *
9
+ * ## 三条设计约束(都有理由,别按直觉改)
10
+ *
11
+ * 1. **序号是流自己的,不是 recorder 的 `seq`。** 一个异步任务可能跨**多个 run 段**
12
+ * (HITL 挂起→恢复、崩溃恢复重投):每段是**独立的一次 run**(新 recorder,`seq` 从 1 重来),
13
+ * 而流的读者要的是一条**连续的**流。所以本类给每条流维护自己的单调序号(从 1 起),
14
+ * SSE 的 `Last-Event-ID` 与 `?from=` 都指它。事件体里那个 `seq` 原样保留(属于那一段 run)。
15
+ * 2. **有界 + 丢最旧 + 明示。** 内存不能被「跑了就不管的任务」拖垮:每条流最多存
16
+ * `maxEvents` 条,超了丢**最旧**的,并把「小于 `droppedBefore` 的序号已不在缓冲里」
17
+ * 告诉订阅者(`replay()` 的返回值 / `stream.truncated` 帧)—— **不静默**。
18
+ * 3. **终态缓冲区只保留最近 `retainTerminal` 条。** 留下的意义是「刚跑完就连上来也能重放」;
19
+ * 更早的任务连接上来只能拿到终态(不假装还能重放)。留多了等于把内存换成没人看的历史。
20
+ *
21
+ * ⚠️ 内存量级(文档里要给使用者一个数):单条事件正文受 `maxEventChars` 约束(入参/成功出参
22
+ * 缺省 2000 字符),所以 500 条 × 2 KB ≈ 1 MB/任务,16 条终态 ≈ 16 MB 上限 —— 量级可控。
23
+ */
24
+ export interface TaskEventStreamsOptions {
25
+ /**
26
+ * 每条流最多保留多少条事件(超出丢最旧);缺省 500。
27
+ * 必须是**正**安全整数:坏值(NaN/Infinity/负数/小数/0)构造期抛 TypeError ——
28
+ * `NaN` 会让 `length > maxEvents` 恒假(内存闸静默失效,使用者以为设了上限),
29
+ * `0` 没有「缓冲几条」的读法(既不是「关掉流」—— live 推送仍在,也不是「不限」),
30
+ * 静默抬成 1 是替使用者改配置。0 语义归类见 `core/limits.ts` 的
31
+ * `AsyncRunner.streamBufferEvents` 行。
32
+ */
33
+ maxEvents?: number;
34
+ /** 终态流的保留条数(LRU,超出即丢最旧的终态流);缺省 16 */
35
+ retainTerminal?: number;
36
+ }
37
+ /** 一条事件在**流**里的位置(`index` 是流自己的序号,不是 recorder 的 seq) */
38
+ export interface TaskStreamEvent {
39
+ index: number;
40
+ event: TraceRecordEvent;
41
+ }
42
+ export interface TaskReplay {
43
+ /** 待补发的事件(`from` 之后,或全部可用的) */
44
+ events: TaskStreamEvent[];
45
+ /** 小于它的序号已不在缓冲里(缺席 = 没有任何丢弃);订阅者应据此发 `stream.truncated` */
46
+ droppedBefore?: number;
47
+ /** 该任务是否已到终态(调用方据此发 `task.end` 并关闭) */
48
+ done: boolean;
49
+ }
50
+ /** 缺省上限 —— 与文档里写的数字必须一致(`usage-guide` §7) */
51
+ export declare const TASK_STREAM_DEFAULT_MAX_EVENTS = 500;
52
+ export declare const TASK_STREAM_DEFAULT_RETAIN_TERMINAL = 16;
53
+ export declare class TaskEventStreams {
54
+ #private;
55
+ private readonly streams;
56
+ private readonly maxEvents;
57
+ private readonly retainTerminal;
58
+ constructor(opts?: TaskEventStreamsOptions);
59
+ /** 这条流在场吗(在场 = 本进程见过它的记账) */
60
+ has(taskId: string): boolean;
61
+ /** 开一条流(已存在则**复用**:HITL 恢复 / 崩溃重投都是同一个任务,序号必须接着走) */
62
+ open(taskId: string): void;
63
+ /**
64
+ * 记一条事件:入缓冲 + 广播给订阅者。
65
+ * 超上限时丢**最旧**的一条(`firstAvailable` 前移)—— 读者据此知道前面被截了。
66
+ *
67
+ * ⚠️ **终态之后到达的事件直接忽略**:流已经以 `task.end` 收口,再往里塞会让下游看到
68
+ * 「结束后还有事件」这种自相矛盾的流。丢掉的只有收尾残尾(超时工具的后台事件那一类);
69
+ * 权威的完整 trace 仍由 sink 出口交付(那条路不受本类影响)。
70
+ */
71
+ push(taskId: string, event: TraceRecordEvent): void;
72
+ /**
73
+ * 订阅实时事件 + 终态通知;返回退订函数。**不含**重放(重放走 `replay()`,调用方先补后订)。
74
+ *
75
+ * 为什么要 `onDone`:**终态是流的一部分**,不是「没有更多事件」了事 —— 没有它,
76
+ * 实时订阅者永远等不到收口(HTTP 那条流就永远挂着,客户端以为任务还在跑)。
77
+ */
78
+ subscribe(taskId: string, listener: (e: TaskStreamEvent) => void, onDone?: () => void): () => void;
79
+ /** 该任务的订阅者数(用例要断言「流关掉后没人还挂在表里」) */
80
+ subscriberCount(taskId: string): number;
81
+ /**
82
+ * 取待补发的事件。`from` 语义 = 「我手上已有到 `from` 为止,给我之后的」
83
+ *(SSE 的 `Last-Event-ID` 就是它,`?from=` 也是)。
84
+ */
85
+ replay(taskId: string, from?: number): TaskReplay;
86
+ /** 标记终态:此后不再有事件(`task.end` 由调用方发),并按 LRU 丢掉最旧的终态流 */
87
+ markDone(taskId: string): void;
88
+ /** 丢弃某条流(终态 LRU 用) */
89
+ forget(taskId: string): void;
90
+ }
@@ -0,0 +1,159 @@
1
+ import { zeroClauseOf } from '../core/limits.js';
2
+ /** 缺省上限 —— 与文档里写的数字必须一致(`usage-guide` §7) */
3
+ export const TASK_STREAM_DEFAULT_MAX_EVENTS = 500;
4
+ export const TASK_STREAM_DEFAULT_RETAIN_TERMINAL = 16;
5
+ export class TaskEventStreams {
6
+ streams = new Map();
7
+ maxEvents;
8
+ retainTerminal;
9
+ constructor(opts = {}) {
10
+ // 坏值响亮失败(口径与 resolveTraceLimits / resolveMaxRetries 同款):
11
+ // 判定是 `length > maxEvents` ⇒ NaN 恒假(上限根本不生效)、Infinity 永不触发、
12
+ // 负数/小数与「缓冲几条」对不上;0 的读法见 limits 表(invalid —— 构造期抛)。
13
+ const maxEvents = opts.maxEvents ?? TASK_STREAM_DEFAULT_MAX_EVENTS;
14
+ if (typeof maxEvents !== 'number' || !Number.isSafeInteger(maxEvents) || maxEvents <= 0) {
15
+ throw new TypeError(`streamBufferEvents 必须是正安全整数(${zeroClauseOf('AsyncRunner.streamBufferEvents')}),收到 ${String(opts.maxEvents)} —— ` +
16
+ 'NaN 会让「超出条数上限」的判定恒假(每任务内存闸静默失效),0 / 负数 / 小数没有「缓冲几条」的读法');
17
+ }
18
+ this.maxEvents = maxEvents;
19
+ // retainTerminal 同款校验:判定是 `excess <= 0 提前返回` ⇒ NaN 恒假、终态流被**全部清空**
20
+ // (保留机制静默失效,方向与 maxEvents 相反、同族)。0 有读法:不留终态流(disabled)。
21
+ const retainTerminal = opts.retainTerminal ?? TASK_STREAM_DEFAULT_RETAIN_TERMINAL;
22
+ if (typeof retainTerminal !== 'number' ||
23
+ !Number.isSafeInteger(retainTerminal) ||
24
+ retainTerminal < 0) {
25
+ throw new TypeError(`retainTerminal 必须是非负安全整数(${zeroClauseOf('TaskEventStreams.retainTerminal')}),收到 ${String(opts.retainTerminal)} —— ` +
26
+ 'NaN 会让「超出保留条数」的判定恒假(终态流被静默清空),负数 / 小数没有「留几条」的读法');
27
+ }
28
+ this.retainTerminal = retainTerminal;
29
+ }
30
+ /** 这条流在场吗(在场 = 本进程见过它的记账) */
31
+ has(taskId) {
32
+ return this.streams.has(taskId);
33
+ }
34
+ /** 开一条流(已存在则**复用**:HITL 恢复 / 崩溃重投都是同一个任务,序号必须接着走) */
35
+ open(taskId) {
36
+ const existing = this.streams.get(taskId);
37
+ if (!existing) {
38
+ this.streams.set(taskId, {
39
+ events: [],
40
+ nextIndex: 1,
41
+ firstAvailable: 0,
42
+ done: false,
43
+ subscribers: new Set(),
44
+ doneListeners: new Set(),
45
+ });
46
+ return;
47
+ }
48
+ // 复用:只把「已完成」摘掉 —— 恢复段是同一个任务的续篇,缓冲与序号都接着用
49
+ existing.done = false;
50
+ }
51
+ /**
52
+ * 记一条事件:入缓冲 + 广播给订阅者。
53
+ * 超上限时丢**最旧**的一条(`firstAvailable` 前移)—— 读者据此知道前面被截了。
54
+ *
55
+ * ⚠️ **终态之后到达的事件直接忽略**:流已经以 `task.end` 收口,再往里塞会让下游看到
56
+ * 「结束后还有事件」这种自相矛盾的流。丢掉的只有收尾残尾(超时工具的后台事件那一类);
57
+ * 权威的完整 trace 仍由 sink 出口交付(那条路不受本类影响)。
58
+ */
59
+ push(taskId, event) {
60
+ const s = this.streams.get(taskId);
61
+ if (!s || s.done)
62
+ return;
63
+ const item = { index: s.nextIndex++, event };
64
+ s.events.push(item);
65
+ if (s.events.length > this.maxEvents) {
66
+ const dropped = s.events.shift();
67
+ s.firstAvailable = dropped.index + 1;
68
+ }
69
+ // 广播:先拷订阅者集合(回调里可能退订),单个抛错不影响其它订阅者
70
+ for (const l of [...s.subscribers]) {
71
+ try {
72
+ l(item);
73
+ }
74
+ catch {
75
+ /* 观测不击穿业务(与 flushSinks 同款) */
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * 订阅实时事件 + 终态通知;返回退订函数。**不含**重放(重放走 `replay()`,调用方先补后订)。
81
+ *
82
+ * 为什么要 `onDone`:**终态是流的一部分**,不是「没有更多事件」了事 —— 没有它,
83
+ * 实时订阅者永远等不到收口(HTTP 那条流就永远挂着,客户端以为任务还在跑)。
84
+ */
85
+ subscribe(taskId, listener, onDone) {
86
+ const s = this.streams.get(taskId);
87
+ if (!s)
88
+ return () => { };
89
+ s.subscribers.add(listener);
90
+ if (onDone)
91
+ s.doneListeners.add(onDone);
92
+ return () => {
93
+ s.subscribers.delete(listener);
94
+ if (onDone)
95
+ s.doneListeners.delete(onDone);
96
+ };
97
+ }
98
+ /** 该任务的订阅者数(用例要断言「流关掉后没人还挂在表里」) */
99
+ subscriberCount(taskId) {
100
+ const s = this.streams.get(taskId);
101
+ return s ? s.subscribers.size + s.doneListeners.size : 0;
102
+ }
103
+ /**
104
+ * 取待补发的事件。`from` 语义 = 「我手上已有到 `from` 为止,给我之后的」
105
+ *(SSE 的 `Last-Event-ID` 就是它,`?from=` 也是)。
106
+ */
107
+ replay(taskId, from) {
108
+ const s = this.streams.get(taskId);
109
+ if (!s)
110
+ return { events: [], done: false };
111
+ const lower = Number.isFinite(from) ? from : 0;
112
+ return {
113
+ events: s.events.filter((e) => e.index > lower),
114
+ ...(s.firstAvailable > 0 ? { droppedBefore: s.firstAvailable } : {}),
115
+ done: s.done,
116
+ };
117
+ }
118
+ /** 标记终态:此后不再有事件(`task.end` 由调用方发),并按 LRU 丢掉最旧的终态流 */
119
+ markDone(taskId) {
120
+ const s = this.streams.get(taskId);
121
+ if (!s)
122
+ return;
123
+ s.done = true;
124
+ // 先广播终态再考虑淘汰:订阅者要能收口(单个抛错不影响其它订阅者)
125
+ for (const l of [...s.doneListeners]) {
126
+ try {
127
+ l();
128
+ }
129
+ catch {
130
+ /* 观测不击穿业务(与 push 同款) */
131
+ }
132
+ }
133
+ this.#evictTerminal();
134
+ }
135
+ /** 丢弃某条流(终态 LRU 用) */
136
+ forget(taskId) {
137
+ this.streams.delete(taskId);
138
+ }
139
+ /** 终态流超过保留条数 ⇒ 从最旧的开始丢(Map 的插入序即 LRU 序;恢复段 `open()` 会把它当新流) */
140
+ #evictTerminal() {
141
+ const doneIds = [];
142
+ for (const [taskId, s] of this.streams) {
143
+ if (s.done)
144
+ doneIds.push(taskId);
145
+ }
146
+ let excess = doneIds.length - this.retainTerminal;
147
+ for (const taskId of doneIds) {
148
+ if (excess <= 0)
149
+ return;
150
+ // 还有订阅者的终态流**不丢**:那是一条还没被读完的流(丢了下游会莫名断在半路)。
151
+ // 跳过它但不算「减掉一个」,于是继续往后找真正能丢的。
152
+ if (this.streams.get(taskId).subscribers.size > 0)
153
+ continue;
154
+ this.streams.delete(taskId);
155
+ excess -= 1;
156
+ }
157
+ }
158
+ }
159
+ //# sourceMappingURL=task-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-events.js","sourceRoot":"","sources":["../../src/transport/task-events.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@migor/agentia",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "description": "面向应用开发的声明式 agent 服务开发框架:装饰器 + DI 声明四类能力,主 agent 编排执行;每次 run 产出结构化结果与可观测调用树(trace、成本、指标),交付可直接上线的服务。",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -47,13 +47,15 @@
47
47
  "lint:fix": "biome check --write .",
48
48
  "format": "biome format --write .",
49
49
  "test": "node scripts/test-all.mjs",
50
- "e2e": "npm run build && npm run build:cli && tsx scripts/e2e-cli.ts && tsx scripts/e2e-examples.ts && tsx scripts/e2e-deploy.ts && tsx scripts/e2e-grpc.ts",
50
+ "e2e": "npm run build && npm run build:cli && tsx scripts/e2e-cli.ts && tsx scripts/e2e-dev.ts && tsx scripts/e2e-examples.ts && tsx scripts/e2e-deploy.ts && tsx scripts/e2e-grpc.ts",
51
51
  "e2e:examples": "npm run build && tsx scripts/e2e-examples.ts",
52
52
  "e2e:deploy": "npm run build && tsx scripts/e2e-deploy.ts",
53
53
  "e2e:grpc": "npm run build && tsx scripts/e2e-grpc.ts",
54
54
  "e2e:live": "tsx scripts/e2e-live.ts",
55
55
  "e2e:mcp": "npm run build:cli && tsx scripts/e2e-mcp.ts",
56
- "e2e:soak": "tsx scripts/e2e-soak.ts"
56
+ "e2e:soak": "tsx scripts/e2e-soak.ts",
57
+ "bench:trace": "tsx scripts/bench-trace-cost.ts",
58
+ "bench:assembly": "tsx scripts/bench-app-assembly.ts"
57
59
  },
58
60
  "devDependencies": {
59
61
  "@anthropic-ai/sdk": "^0.126.0",