@migor/agentia 0.10.4 → 0.10.6

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 (162) hide show
  1. package/CHANGELOG.md +281 -1
  2. package/README.en.md +1 -1
  3. package/README.md +2 -2
  4. package/dist/AGENTS.md +93 -11
  5. package/dist/container/container.js +3 -0
  6. package/dist/container/container.js.map +1 -1
  7. package/dist/core/abort.js +6 -1
  8. package/dist/core/abort.js.map +1 -1
  9. package/dist/core/json.js +4 -0
  10. package/dist/core/json.js.map +1 -1
  11. package/dist/core/limits.d.ts +13 -5
  12. package/dist/core/limits.js +14 -5
  13. package/dist/core/limits.js.map +1 -1
  14. package/dist/core/sse.d.ts +0 -13
  15. package/dist/core/sse.js +28 -2
  16. package/dist/core/sse.js.map +1 -1
  17. package/dist/core/timeout.d.ts +8 -0
  18. package/dist/core/timeout.js +19 -1
  19. package/dist/core/timeout.js.map +1 -1
  20. package/dist/core/tool.d.ts +18 -0
  21. package/dist/core/trace.d.ts +9 -0
  22. package/dist/core/trace.js +21 -0
  23. package/dist/core/trace.js.map +1 -1
  24. package/dist/engine/forwarded.d.ts +3 -1
  25. package/dist/engine/forwarded.js +5 -0
  26. package/dist/engine/forwarded.js.map +1 -1
  27. package/dist/engine/loop.d.ts +5 -1
  28. package/dist/engine/loop.js +45 -12
  29. package/dist/engine/loop.js.map +1 -1
  30. package/dist/engine/mcp-server.d.ts +17 -1
  31. package/dist/engine/mcp-server.js +36 -2
  32. package/dist/engine/mcp-server.js.map +1 -1
  33. package/dist/engine/policy.js +5 -1
  34. package/dist/engine/policy.js.map +1 -1
  35. package/dist/engine/replay.js +63 -1
  36. package/dist/engine/replay.js.map +1 -1
  37. package/dist/engine/run-config.d.ts +6 -0
  38. package/dist/engine/run-config.js +18 -6
  39. package/dist/engine/run-config.js.map +1 -1
  40. package/dist/engine/spec.d.ts +11 -1
  41. package/dist/engine/spec.js.map +1 -1
  42. package/dist/engine/stop-reason.js +19 -1
  43. package/dist/engine/stop-reason.js.map +1 -1
  44. package/dist/engine/tool-context.d.ts +3 -1
  45. package/dist/engine/tool-context.js +3 -1
  46. package/dist/engine/tool-context.js.map +1 -1
  47. package/dist/engine/tool-events.d.ts +7 -2
  48. package/dist/engine/tool-events.js +24 -3
  49. package/dist/engine/tool-events.js.map +1 -1
  50. package/dist/engine/tracer.js +10 -3
  51. package/dist/engine/tracer.js.map +1 -1
  52. package/dist/engine/turn.d.ts +9 -13
  53. package/dist/engine/turn.js +96 -10
  54. package/dist/engine/turn.js.map +1 -1
  55. package/dist/engine/types.d.ts +19 -2
  56. package/dist/engine/types.js +1 -0
  57. package/dist/engine/types.js.map +1 -1
  58. package/dist/engine/usage.js +12 -4
  59. package/dist/engine/usage.js.map +1 -1
  60. package/dist/index.d.ts +11 -3
  61. package/dist/index.js +7 -1
  62. package/dist/index.js.map +1 -1
  63. package/dist/integrations/anthropic.d.ts +9 -1
  64. package/dist/integrations/anthropic.js +42 -7
  65. package/dist/integrations/anthropic.js.map +1 -1
  66. package/dist/integrations/file-sink.d.ts +1 -0
  67. package/dist/integrations/file-sink.js +35 -32
  68. package/dist/integrations/file-sink.js.map +1 -1
  69. package/dist/integrations/mcp-http.js +33 -9
  70. package/dist/integrations/mcp-http.js.map +1 -1
  71. package/dist/integrations/mcp-protocol.js +33 -16
  72. package/dist/integrations/mcp-protocol.js.map +1 -1
  73. package/dist/integrations/metrics-otlp.js +4 -0
  74. package/dist/integrations/metrics-otlp.js.map +1 -1
  75. package/dist/integrations/metrics.js +17 -2
  76. package/dist/integrations/metrics.js.map +1 -1
  77. package/dist/integrations/openai.d.ts +6 -1
  78. package/dist/integrations/openai.js +45 -8
  79. package/dist/integrations/openai.js.map +1 -1
  80. package/dist/integrations/otlp.js +6 -0
  81. package/dist/integrations/otlp.js.map +1 -1
  82. package/dist/runtime/memory.d.ts +0 -8
  83. package/dist/runtime/memory.js +24 -2
  84. package/dist/runtime/memory.js.map +1 -1
  85. package/dist/runtime/run.js +34 -9
  86. package/dist/runtime/run.js.map +1 -1
  87. package/dist/store/fsStore.d.ts +2 -0
  88. package/dist/store/fsStore.js +38 -5
  89. package/dist/store/fsStore.js.map +1 -1
  90. package/dist/store/record.d.ts +40 -0
  91. package/dist/store/record.js +72 -0
  92. package/dist/store/record.js.map +1 -1
  93. package/dist/store/redisStore.js +15 -4
  94. package/dist/store/redisStore.js.map +1 -1
  95. package/dist/store/sqliteStore.js +39 -14
  96. package/dist/store/sqliteStore.js.map +1 -1
  97. package/dist/store/store.d.ts +6 -1
  98. package/dist/store/store.js +10 -4
  99. package/dist/store/store.js.map +1 -1
  100. package/dist/toolkit/capability-loop.d.ts +92 -0
  101. package/dist/toolkit/capability-loop.js +81 -0
  102. package/dist/toolkit/capability-loop.js.map +1 -0
  103. package/dist/toolkit/manifest.d.ts +21 -0
  104. package/dist/toolkit/manifest.js +38 -0
  105. package/dist/toolkit/manifest.js.map +1 -0
  106. package/dist/toolkit/module.d.ts +5 -0
  107. package/dist/toolkit/module.js +9 -0
  108. package/dist/toolkit/module.js.map +1 -1
  109. package/dist/toolkit/prompt.d.ts +3 -1
  110. package/dist/toolkit/prompt.js +22 -3
  111. package/dist/toolkit/prompt.js.map +1 -1
  112. package/dist/toolkit/skill.d.ts +3 -1
  113. package/dist/toolkit/skill.js +2 -0
  114. package/dist/toolkit/skill.js.map +1 -1
  115. package/dist/toolkit/subagent.d.ts +3 -1
  116. package/dist/toolkit/subagent.js +2 -0
  117. package/dist/toolkit/subagent.js.map +1 -1
  118. package/dist/toolkit/tool.d.ts +3 -1
  119. package/dist/toolkit/tool.js +2 -0
  120. package/dist/toolkit/tool.js.map +1 -1
  121. package/dist/transport/approval-policy.d.ts +1 -1
  122. package/dist/transport/approval-policy.js +18 -3
  123. package/dist/transport/approval-policy.js.map +1 -1
  124. package/dist/transport/approval-supervisor.d.ts +15 -3
  125. package/dist/transport/approval-supervisor.js +37 -11
  126. package/dist/transport/approval-supervisor.js.map +1 -1
  127. package/dist/transport/async.d.ts +3 -4
  128. package/dist/transport/async.js +157 -30
  129. package/dist/transport/async.js.map +1 -1
  130. package/dist/transport/drain-gate.js +13 -1
  131. package/dist/transport/drain-gate.js.map +1 -1
  132. package/dist/transport/http-endpoints.d.ts +13 -0
  133. package/dist/transport/http-endpoints.js +108 -28
  134. package/dist/transport/http-endpoints.js.map +1 -1
  135. package/dist/transport/http-shapes.d.ts +26 -3
  136. package/dist/transport/http-shapes.js +12 -2
  137. package/dist/transport/http-shapes.js.map +1 -1
  138. package/dist/transport/http.d.ts +46 -2
  139. package/dist/transport/http.js +43 -18
  140. package/dist/transport/http.js.map +1 -1
  141. package/dist/transport/resume-scanner.d.ts +3 -0
  142. package/dist/transport/resume-scanner.js +10 -1
  143. package/dist/transport/resume-scanner.js.map +1 -1
  144. package/dist/transport/run-call-options.js +46 -1
  145. package/dist/transport/run-call-options.js.map +1 -1
  146. package/dist/transport/run-options.d.ts +98 -0
  147. package/dist/transport/run-options.js +121 -0
  148. package/dist/transport/run-options.js.map +1 -0
  149. package/dist/transport/run-outcome.js +21 -1
  150. package/dist/transport/run-outcome.js.map +1 -1
  151. package/dist/transport/serve.js +10 -0
  152. package/dist/transport/serve.js.map +1 -1
  153. package/dist/transport/signal-supervisor.d.ts +3 -0
  154. package/dist/transport/signal-supervisor.js +5 -1
  155. package/dist/transport/signal-supervisor.js.map +1 -1
  156. package/dist/transport/stream-janitor.d.ts +45 -0
  157. package/dist/transport/stream-janitor.js +137 -0
  158. package/dist/transport/stream-janitor.js.map +1 -0
  159. package/dist/transport/task-wake-gate.d.ts +40 -0
  160. package/dist/transport/task-wake-gate.js +69 -0
  161. package/dist/transport/task-wake-gate.js.map +1 -0
  162. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
- import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, truncateSync, writeFileSync, } from 'node:fs';
1
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, truncateSync, writeFileSync, } from 'node:fs';
2
2
  import { dirname } from 'node:path';
3
- import { parseTaskRecord } from './record.js';
3
+ import { parseTaskRecord, serializeTaskRecord } from './record.js';
4
4
  import { cloneTaskRecord } from './store.js';
5
5
  /**
6
6
  * Agentia —— 文件宿主 TaskStore(spec §6.6:异步耐久 = 换宿主不换语义)。
@@ -25,6 +25,8 @@ export class FileTaskStore {
25
25
  // (实测读数见 spec §10 2026-09-28 ref-due-index-measure)。runner 对缺失的 listDue 回退全表,语义不变。
26
26
  byTask = new Map();
27
27
  byKey = new Map(); // idempotencyKey → taskId
28
+ /** 启动读取失败后进入降级态:仍可追加新记录,但**禁止 compact**(否则空内存会重写掉旧文件) */
29
+ degraded = false;
28
30
  constructor(file, onLoadError) {
29
31
  this.file = file;
30
32
  this.onLoadError = onLoadError;
@@ -41,7 +43,10 @@ export class FileTaskStore {
41
43
  raw = readFileSync(this.file, 'utf8');
42
44
  }
43
45
  catch (err) {
44
- // 读失败按空宿主启动:观测不击穿业务,缺省仍吞;宿主要告警就传 onLoadError
46
+ // 读失败按空宿主启动(不击穿业务),但**必须出声**:否则宿主以为续跑扫描跑了,
47
+ // 实际一条旧任务都没读到;再调 compact 会把旧文件永久清空(2026-11-07 深评)。
48
+ this.degraded = true;
49
+ console.warn(`[agentia] FileTaskStore 读取 ${this.file} 失败,按空库启动(续跑将看不到旧任务;已禁用 compact):`, err instanceof Error ? err.message : err);
45
50
  this.onLoadError?.(err);
46
51
  return;
47
52
  }
@@ -94,7 +99,30 @@ export class FileTaskStore {
94
99
  }
95
100
  }
96
101
  append(rec) {
97
- writeFileSync(this.file, `${JSON.stringify(rec)}\n`, { flag: 'a' });
102
+ // 半行自愈(2026-11-07 深评):此前只在启动时 healTail;同进程一次写残(ENOSPC /
103
+ // 中断)后,下一次 append 会粘在残行尾部,重启时整行非法被跳过(丢一条记录)。
104
+ // 记录写前长度,失败时截回去。
105
+ let before = -1;
106
+ try {
107
+ before = existsSync(this.file) ? statSync(this.file).size : 0;
108
+ }
109
+ catch {
110
+ before = -1;
111
+ }
112
+ try {
113
+ writeFileSync(this.file, `${serializeTaskRecord(rec)}\n`, { flag: 'a' });
114
+ }
115
+ catch (e) {
116
+ if (before >= 0) {
117
+ try {
118
+ truncateSync(this.file, before);
119
+ }
120
+ catch {
121
+ /* 截不回去也没别的补救;至少原错误照抛 */
122
+ }
123
+ }
124
+ throw e;
125
+ }
98
126
  }
99
127
  save(rec) {
100
128
  // **先落盘、后更新内存**(2026-09-20):落盘抛错时内存不得先推进 —— 否则内存说
@@ -133,6 +161,11 @@ export class FileTaskStore {
133
161
  * 旧文件也完整),内存态不受影响。
134
162
  */
135
163
  compact() {
164
+ if (this.degraded) {
165
+ // 读失败时内存是空的;compact 会把文件重写成空/只剩新记录 —— 等于永久删除旧历史。
166
+ console.warn(`[agentia] FileTaskStore 处于降级态(启动读取失败),拒绝 compact:${this.file}`);
167
+ return;
168
+ }
136
169
  // 赢家殿后:内存语义是「同幂等键最后 save 的 taskId 赢」(save 覆写 byKey),
137
170
  // 而 load 回放按行序 last-wins。直接按 Map 首次插入序写盘会丢掉「最后 save」
138
171
  // 信息 —— 同键重提的新任务插入在后,旧任务又被 save 赢回时,插入序恰与赢家
@@ -140,7 +173,7 @@ export class FileTaskStore {
140
173
  // 殿后即等价内存语义);Array.prototype.sort 稳定,同组内仍按插入序。
141
174
  const winners = new Set(this.byKey.values());
142
175
  const rows = [...this.byTask.values()].sort((a, b) => Number(winners.has(a.taskId)) - Number(winners.has(b.taskId)));
143
- const body = rows.map((r) => `${JSON.stringify(r)}\n`).join('');
176
+ const body = rows.map((r) => `${serializeTaskRecord(r)}\n`).join('');
144
177
  // 原子重写:先写临时文件再 rename。直接 writeFileSync 截断重写,中途被杀会留下
145
178
  // 半截文件、丢掉全部记录;同目录 rename 是原子的,旧文件在新文件就位前保持完整。
146
179
  // 临时文件名固定(单写者前提,见头注释)—— 上次被杀留下的残临时文件会被本次覆写。
@@ -1 +1 @@
1
- {"version":3,"file":"fsStore.js","sourceRoot":"","sources":["../../src/store/fsStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fsStore.js","sourceRoot":"","sources":["../../src/store/fsStore.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG7C;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,aAAa;IAUL,IAAI;IACJ,WAAW;IAV9B,+DAA+D;IAC/D,8CAA8C;IAC9C,mFAAmF;IAClE,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;IACvC,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC,CAAC,0BAA0B;IAC9E,yDAAyD;IACjD,QAAQ,GAAG,KAAK,CAAC;IAEzB,YACmB,IAAY,EACZ,WAAoC;oBADpC,IAAI;2BACJ,WAAW;QAE5B,6DAA6D;QAC7D,2BAA2B;QAC3B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO;QACnC,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,2CAA2C;YAC3C,mDAAmD;YACnD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,OAAO,CAAC,IAAI,CACV,8BAA8B,IAAI,CAAC,IAAI,mCAAmC,EAC1E,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CACzC,CAAC;YACF,IAAI,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC;YACxB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACnB,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAC3B,IAAI,CAAC;gBACH,2CAA2C;gBAC3C,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;gBAClC,IAAI,CAAC,GAAG;oBAAE,SAAS;gBACnB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBACjC,IAAI,GAAG,CAAC,cAAc;oBAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YACzE,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc;YAChB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,QAAQ,CAAC,GAAW;QAC1B,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO;QACvC,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB;QAC1D,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC;YACH,2CAA2C;YAC3C,iBAAiB;YACjB,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,KAAK,CAAC;QACnB,CAAC;QACD,IAAI,CAAC;YACH,IAAI,QAAQ;gBACV,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,cAAc;;gBAC5C,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7E,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,GAAe;QAC5B,wDAAwD;QACxD,6CAA6C;QAC7C,iBAAiB;QACjB,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,GAAG,CAAC,CAAC,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;gBAChB,IAAI,CAAC;oBACH,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAClC,CAAC;gBAAC,MAAM,CAAC;oBACP,wBAAwB;gBAC1B,CAAC;YACH,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IAED,IAAI,CAAC,GAAe;QAClB,kDAAkD;QAClD,+CAA+C;QAC/C,0CAA0C;QAC1C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjB,yEAAyE;QACzE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;QAClD,IAAI,GAAG,CAAC,cAAc;YAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzE,CAAC;IAED,GAAG,CAAC,MAAc;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC9D,CAAC;IAED,aAAa,CAAC,GAAW;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI;QACF,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACxD,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACpB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;;OAOG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,iDAAiD;YACjD,OAAO,CAAC,IAAI,CACV,oDAAoD,IAAI,CAAC,IAAI,EAAE,CAChE,CAAC;YACF,OAAO;QACT,CAAC;QACD,qDAAqD;QACrD,qDAAqD;QACrD,4CAA4C;QAC5C,+CAA+C;QAC/C,+CAA+C;QAC/C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CACzC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CACxE,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrE,oDAAoD;QACpD,8CAA8C;QAC9C,4CAA4C;QAC5C,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,cAAc,CAAC;QACvC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACzB,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;CACF"}
@@ -32,6 +32,46 @@ import type { TaskRecord } from './store.js';
32
32
  * 返回值留给需要自己决定要不要回写的调用方(`sqliteStore` 的派生列)。
33
33
  */
34
34
  export declare function normalizeLegacyRecord(rec: TaskRecord): boolean;
35
+ /**
36
+ * 「哪些进程内引用在落库时被剥掉了」的键。
37
+ *
38
+ * ⚠️ **内部键,刻意不进 `RunInvocationOptions` 公共类型面**(AGENTS.md「内部工具不进公共面」):
39
+ * 它只在一条记录自「save」到「恢复段读回」之间活着,是给恢复路径的一句提示,不是使用者该
40
+ * 配置的东西。读侧一律走 `droppedRuntimeRefsOf`,别在别处直接摸这个键名。
41
+ */
42
+ export declare const DROPPED_REFS_KEY = "__agentiaDroppedRefs";
43
+ /** 被剥掉的进程内引用(只有 `true` 的那些有意义;键名对应 `RunInvocationOptions` 上的位置) */
44
+ export interface DroppedRuntimeRefs {
45
+ /** 主 `client`:恢复段会退回 runner 级 / 默认 client */
46
+ client: boolean;
47
+ /** `tools` 菜单:恢复段会退回装配菜单(`app.tools`) */
48
+ tools: boolean;
49
+ /** fallback 环里的 `client`:只保留 `model`,client 由 runner/应用级配置兜住 */
50
+ fallbacks: boolean;
51
+ }
52
+ /**
53
+ * 读一条落库记录上的剥离标记(2026-11-09 深评 P1)。
54
+ *
55
+ * 为什么需要标记:`serializeTaskRecord` 会剥掉主 `client` 与 `tools`,而恢复段的
56
+ * `buildRunCallOptions` 无从区分「提交时本来没传」与「传了但落库时被剥掉了」—— 两种情况下
57
+ * `rec.spec.options.client` 都是 `undefined`。没有这个标记,per-task 自定义 client(典型是
58
+ * OpenAI 兼容端点)的任务重启续跑时会**静默**打到 runner 的端点,自定义工具菜单也会静默
59
+ * 换回装配菜单。标记只用来让恢复段**出声**,不改变任何装配结果。
60
+ */
61
+ export declare function droppedRuntimeRefsOf(options: object | undefined): DroppedRuntimeRefs | undefined;
62
+ /**
63
+ * 落库前的**可序列化清洗**(2026-11-07 深评):`JSON.stringify` 会把 `AbortSignal` 变成
64
+ * `{}`、把 `ModelClient` 变成 `{messages:{}}`、把 `tools` 里的 run 函数丢掉。读回后这些
65
+ * 空壳会在恢复段被当成真对象使用(`combineSignals({})` 直接 TypeError / 工具菜单半残)。
66
+ *
67
+ * 因此三条 JSON store 统一走这里:
68
+ * - 去掉 `signal` / `client` / 回调 / `tools`(它们属于提交进程,不能跨重启);
69
+ * - fallback 环只保留 `model`(client 由 runner/应用级配置兜住,与文档口径一致);
70
+ * - 剥掉的「主 client / tools / fallback client」记进 `DROPPED_REFS_KEY`,让恢复段能出声
71
+ * (2026-11-09 深评 P1:此前剥得比文档承诺的多,且恢复路径看不到这件事)。
72
+ * 返回的是**新对象**,不改调用方记录。
73
+ */
74
+ export declare function serializeTaskRecord(rec: TaskRecord): string;
35
75
  /**
36
76
  * bytes → 记录(**唯一入口**):解析 + 形状守卫 + 读时归一。
37
77
  *
@@ -1,3 +1,4 @@
1
+ import { cloneTaskRecord } from './store.js';
1
2
  /**
2
3
  * ① 之前的状态值。它在本版的 `RunStatus` 联合类型里**不存在**,所以下面那处比较只能走字符串
3
4
  * (`rec.status === 'awaiting_approval'` 根本编译不过)—— 这本身就说明问题:类型看不见盘上的数据。
@@ -38,6 +39,77 @@ export function normalizeLegacyRecord(rec) {
38
39
  }
39
40
  return changed;
40
41
  }
42
+ /**
43
+ * 「哪些进程内引用在落库时被剥掉了」的键。
44
+ *
45
+ * ⚠️ **内部键,刻意不进 `RunInvocationOptions` 公共类型面**(AGENTS.md「内部工具不进公共面」):
46
+ * 它只在一条记录自「save」到「恢复段读回」之间活着,是给恢复路径的一句提示,不是使用者该
47
+ * 配置的东西。读侧一律走 `droppedRuntimeRefsOf`,别在别处直接摸这个键名。
48
+ */
49
+ export const DROPPED_REFS_KEY = '__agentiaDroppedRefs';
50
+ /**
51
+ * 读一条落库记录上的剥离标记(2026-11-09 深评 P1)。
52
+ *
53
+ * 为什么需要标记:`serializeTaskRecord` 会剥掉主 `client` 与 `tools`,而恢复段的
54
+ * `buildRunCallOptions` 无从区分「提交时本来没传」与「传了但落库时被剥掉了」—— 两种情况下
55
+ * `rec.spec.options.client` 都是 `undefined`。没有这个标记,per-task 自定义 client(典型是
56
+ * OpenAI 兼容端点)的任务重启续跑时会**静默**打到 runner 的端点,自定义工具菜单也会静默
57
+ * 换回装配菜单。标记只用来让恢复段**出声**,不改变任何装配结果。
58
+ */
59
+ export function droppedRuntimeRefsOf(options) {
60
+ if (options === undefined)
61
+ return undefined;
62
+ const raw = options[DROPPED_REFS_KEY];
63
+ if (!Array.isArray(raw))
64
+ return undefined;
65
+ return {
66
+ client: raw.includes('client'),
67
+ tools: raw.includes('tools'),
68
+ fallbacks: raw.includes('fallbacks[].client'),
69
+ };
70
+ }
71
+ /**
72
+ * 落库前的**可序列化清洗**(2026-11-07 深评):`JSON.stringify` 会把 `AbortSignal` 变成
73
+ * `{}`、把 `ModelClient` 变成 `{messages:{}}`、把 `tools` 里的 run 函数丢掉。读回后这些
74
+ * 空壳会在恢复段被当成真对象使用(`combineSignals({})` 直接 TypeError / 工具菜单半残)。
75
+ *
76
+ * 因此三条 JSON store 统一走这里:
77
+ * - 去掉 `signal` / `client` / 回调 / `tools`(它们属于提交进程,不能跨重启);
78
+ * - fallback 环只保留 `model`(client 由 runner/应用级配置兜住,与文档口径一致);
79
+ * - 剥掉的「主 client / tools / fallback client」记进 `DROPPED_REFS_KEY`,让恢复段能出声
80
+ * (2026-11-09 深评 P1:此前剥得比文档承诺的多,且恢复路径看不到这件事)。
81
+ * 返回的是**新对象**,不改调用方记录。
82
+ */
83
+ export function serializeTaskRecord(rec) {
84
+ const copy = cloneTaskRecord(rec);
85
+ const options = copy.spec.options;
86
+ if (options !== undefined) {
87
+ const rest = { ...options };
88
+ // 剥之前先记:这几样是「提交进程的运行时引用」,恢复段只能退回配置兜底
89
+ const dropped = [];
90
+ if (options.client !== undefined)
91
+ dropped.push('client');
92
+ if (options.tools !== undefined && options.tools.length > 0)
93
+ dropped.push('tools');
94
+ if (options.fallbacks?.some((link) => link.client !== undefined)) {
95
+ dropped.push('fallbacks[].client');
96
+ }
97
+ // 只摘「进程内对象」;纯数据(approvals / events / blackboard / 预算 / labels)保留。
98
+ delete rest.signal;
99
+ delete rest.client;
100
+ delete rest.onText;
101
+ delete rest.onTraceEvent;
102
+ delete rest.tools;
103
+ if (rest.fallbacks !== undefined) {
104
+ rest.fallbacks = rest.fallbacks.map((link) => ({ model: link.model }));
105
+ }
106
+ if (dropped.length > 0) {
107
+ rest[DROPPED_REFS_KEY] = dropped;
108
+ }
109
+ copy.spec = { ...copy.spec, options: rest };
110
+ }
111
+ return JSON.stringify(copy);
112
+ }
41
113
  /**
42
114
  * bytes → 记录(**唯一入口**):解析 + 形状守卫 + 读时归一。
43
115
  *
@@ -1 +1 @@
1
- {"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/store/record.ts"],"names":[],"mappings":"AAyBA;;;GAGG;AACH,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAC1C,iDAAiD;AACjD,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AAEhD;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAe;IACnD,MAAM,GAAG,GAAG,GAAyC,CAAC;IACtD,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,IAAI,GAAG,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;QACjC,GAAG,CAAC,MAAM,GAAG,WAAW,CAAC;QACzB,wEAAwE;QACxE,gDAAgD;QAChD,cAAc;QACd,IAAI,GAAG,CAAC,eAAe,KAAK,SAAS;YAAE,GAAG,CAAC,eAAe,GAAG,UAAU,CAAC;QACxE,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,iDAAiD;IACjD,gDAAgD;IAChD,8DAA8D;IAC9D,UAAU;IACV,IAAI,OAAO,GAAG,CAAC,gBAAgB,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC9C,IAAI,GAAG,CAAC,cAAc,KAAK,SAAS;YAAE,GAAG,CAAC,cAAc,GAAG,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACjF,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC7B,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;IAC1C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC7D,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/store/record.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { isTerminalStatus } from '../core/run.js';
2
- import { parseTaskRecord } from './record.js';
2
+ import { parseTaskRecord, serializeTaskRecord } from './record.js';
3
3
  export class RedisTaskStore {
4
4
  client;
5
5
  prefix;
@@ -41,7 +41,7 @@ export class RedisTaskStore {
41
41
  return `${this.prefix}idem:${key}`;
42
42
  }
43
43
  async save(rec) {
44
- const json = JSON.stringify(rec);
44
+ const json = serializeTaskRecord(rec);
45
45
  // TTL 只加在**终态**记录上(2026-09-28 外部深评 S1)。此前无条件加:一条在等审批的
46
46
  // 任务,TTL 一到记录就没了 —— 那条「批了它」的决定无家可归(`InMemoryTaskStore.evict`
47
47
  // 里那句「suspended 不可淘汰」是同一条道理,两处此前读数相反)。
@@ -86,10 +86,21 @@ export class RedisTaskStore {
86
86
  return taskId ? this.get(taskId) : undefined;
87
87
  }
88
88
  async list() {
89
- const keys = await this.enumerate(this.taskPattern());
89
+ // Redis SCAN 契约允许同一个 key 返回多次(rehash / 过期时真实发生)。不去重会让
90
+ // `resumePending` 把同一条记录认领两次并派发两次(2026-11-07 深评)。
91
+ const keys = [...new Set(await this.enumerate(this.taskPattern()))];
90
92
  const recs = [];
91
93
  for (const k of keys) {
92
- const rec = parseRecord(await this.client.get(k));
94
+ let raw;
95
+ try {
96
+ raw = await this.client.get(k);
97
+ }
98
+ catch (e) {
99
+ // 单 key 读失败不该让整次 resume 扫描 reject(扫描会因此完全停摆)。
100
+ console.warn(`[agentia] RedisTaskStore.list 读取 ${k} 失败,跳过该条:`, e instanceof Error ? e.message : e);
101
+ continue;
102
+ }
103
+ const rec = parseRecord(raw);
93
104
  if (rec)
94
105
  recs.push(rec);
95
106
  }
@@ -1 +1 @@
1
- {"version":3,"file":"redisStore.js","sourceRoot":"","sources":["../../src/store/redisStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redisStore.js","sourceRoot":"","sources":["../../src/store/redisStore.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { createRequire } from 'node:module';
2
- import { parseTaskRecord } from './record.js';
2
+ import { parseTaskRecord, serializeTaskRecord } from './record.js';
3
3
  // node:sqlite 是 Node ≥22.5 才有的内置模块。这里**延迟加载**而非顶层静态 import:
4
4
  // 顶层 import 会让**整个包**在未提供该模块的运行时「加载即崩」——`src/index.ts` 对
5
5
  // SqliteTaskStore 是 eager 再导出,于是连不用 SQLite 的用户也被殃及。延迟到真正构造
@@ -65,19 +65,37 @@ export class SqliteTaskStore {
65
65
  // 读时自愈判据扩到两列(见 healRow)。存量库走下面的**就地迁移**:
66
66
  // CREATE TABLE IF NOT EXISTS 不会给旧表加列,所以查列 → 缺则 ALTER + 从 json 回填。
67
67
  const cols = this.db.prepare('PRAGMA table_info(tasks)').all();
68
+ // 迁移事务化(2026-11-07 深评):ALTER 与回填是两条 DDL/DML,中间被杀会留下
69
+ // 「列在、wake_at 全 NULL」的半迁移;两个 worker 同时首启还会 duplicate column 崩。
70
+ // BEGIN IMMEDIATE 串行化;duplicate column 视为「别的进程刚做完」并继续。
68
71
  if (!cols.some((c) => c.name === 'wake_at')) {
69
- this.db.exec('ALTER TABLE tasks ADD COLUMN wake_at INTEGER');
70
- // 回填:旧行的 wakeAt 只在 json 里(不补的话旧库里的在睡任务从此醒不来 ——
71
- // 那正是本列要服务的那批记录)
72
- this.db.exec("UPDATE tasks SET wake_at = json_extract(json, '$.wakeAt') " +
73
- "WHERE json_extract(json, '$.wakeAt') IS NOT NULL");
72
+ try {
73
+ this.db.exec('BEGIN IMMEDIATE');
74
+ this.db.exec('ALTER TABLE tasks ADD COLUMN wake_at INTEGER');
75
+ this.db.exec("UPDATE tasks SET wake_at = json_extract(json, '$.wakeAt') " +
76
+ "WHERE json_extract(json, '$.wakeAt') IS NOT NULL");
77
+ this.db.exec('COMMIT');
78
+ }
79
+ catch (e) {
80
+ try {
81
+ this.db.exec('ROLLBACK');
82
+ }
83
+ catch {
84
+ /* 已回滚 / 事务未开始 */
85
+ }
86
+ if (!/duplicate column/i.test(e?.message ?? String(e)))
87
+ throw e;
88
+ }
74
89
  }
90
+ // 幂等回填:半迁移窗口留下的 NULL 也在这里补(只扫 wake_at IS NULL 的行)。
91
+ this.db.exec("UPDATE tasks SET wake_at = json_extract(json, '$.wakeAt') " +
92
+ "WHERE wake_at IS NULL AND json_extract(json, '$.wakeAt') IS NOT NULL");
75
93
  this.db.exec('CREATE INDEX IF NOT EXISTS idx_tasks_due ON tasks(status, wake_at)');
76
94
  }
77
95
  save(rec) {
78
96
  this.db
79
97
  .prepare('INSERT OR REPLACE INTO tasks (task_id, idempotency_key, status, wake_at, json) VALUES (?, ?, ?, ?, ?)')
80
- .run(rec.taskId, rec.idempotencyKey ?? null, rec.status, rec.wakeAt ?? null, JSON.stringify(rec));
98
+ .run(rec.taskId, rec.idempotencyKey ?? null, rec.status, rec.wakeAt ?? null, serializeTaskRecord(rec));
81
99
  }
82
100
  /**
83
101
  * 把派生列(`status` / `wake_at`)拉回与 json 一致(**只在不一致时写**,一次代价)。
@@ -91,14 +109,21 @@ export class SqliteTaskStore {
91
109
  * 判据是「列 ≠ json」而不是「刚才归一过没有」:任何原因(手改过、旧版本写的、将来又一次
92
110
  * 改名)造成的漂移都该被顺手修掉,不依赖调用方传一个「我改过」的旗子。
93
111
  */
94
- healRow(storedStatus, storedWakeAt, rec) {
112
+ healRow(storedStatus, storedWakeAt, storedJson, rec) {
95
113
  const wakeAt = rec.wakeAt ?? null;
96
114
  if (storedStatus === rec.status && storedWakeAt === wakeAt)
97
115
  return;
98
116
  try {
117
+ // 派生列先拉正(不碰 json,绝无覆盖并发 save 的风险)。
118
+ this.db
119
+ .prepare('UPDATE tasks SET status = ?, wake_at = ? WHERE task_id = ?')
120
+ .run(rec.status, wakeAt, rec.taskId);
121
+ // json 回写带 CAS(`json = 旧值`):多进程下若并发 save 已经换了新快照,这一条不生效,
122
+ // 留给下一次真实 save 归一。旧形状的归一化会改 json,所以不能把两者合并成一条
123
+ // (合并后 WHERE json=旧值 会因“写的是新 json”而永远不命中)。
99
124
  this.db
100
- .prepare('UPDATE tasks SET status = ?, wake_at = ?, json = ? WHERE task_id = ?')
101
- .run(rec.status, wakeAt, JSON.stringify(rec), rec.taskId);
125
+ .prepare('UPDATE tasks SET json = ? WHERE task_id = ? AND json = ?')
126
+ .run(serializeTaskRecord(rec), rec.taskId, storedJson);
102
127
  }
103
128
  catch (err) {
104
129
  // 只读库 / 他进程占锁超时:读照常返回归一后的记录,只有列这一处没自愈。**响亮一次**,
@@ -117,7 +142,7 @@ export class SqliteTaskStore {
117
142
  return undefined;
118
143
  const rec = parseTaskRecord(row.json);
119
144
  if (rec)
120
- this.healRow(row.status, row.wake_at, rec);
145
+ this.healRow(row.status, row.wake_at, row.json, rec);
121
146
  return rec;
122
147
  }
123
148
  byIdempotency(key) {
@@ -129,7 +154,7 @@ export class SqliteTaskStore {
129
154
  return undefined;
130
155
  const rec = parseTaskRecord(row.json);
131
156
  if (rec)
132
- this.healRow(row.status, row.wake_at, rec);
157
+ this.healRow(row.status, row.wake_at, row.json, rec);
133
158
  return rec;
134
159
  }
135
160
  list() {
@@ -142,7 +167,7 @@ export class SqliteTaskStore {
142
167
  const rec = parseTaskRecord(r.json);
143
168
  if (!rec)
144
169
  continue;
145
- this.healRow(r.status, r.wake_at, rec);
170
+ this.healRow(r.status, r.wake_at, r.json, rec);
146
171
  out.push(rec);
147
172
  }
148
173
  return out;
@@ -162,7 +187,7 @@ export class SqliteTaskStore {
162
187
  const rec = parseTaskRecord(r.json);
163
188
  if (!rec)
164
189
  continue;
165
- this.healRow(r.status, r.wake_at, rec);
190
+ this.healRow(r.status, r.wake_at, r.json, rec);
166
191
  out.push(rec);
167
192
  }
168
193
  return out;
@@ -1 +1 @@
1
- {"version":3,"file":"sqliteStore.js","sourceRoot":"","sources":["../../src/store/sqliteStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sqliteStore.js","sourceRoot":"","sources":["../../src/store/sqliteStore.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGnE,4DAA4D;AAC5D,yDAAyD;AACzD,2DAA2D;AAC3D,2DAA2D;AAC3D,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAEtD,SAAS,gBAAgB;IACvB,IAAI,CAAC;QACH,OAAQ,cAAc,CAAC,aAAa,CAAkC,CAAC,YAAY,CAAC;IACtF,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,eAAe;IACT,EAAE,CAAe;IAClC,gDAAgD;IAC/B,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhD,YAAY,IAAY;QACtB,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC;QACxC,IAAI,CAAC,EAAE,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;QACjC,gDAAgD;QAChD,0DAA0D;QAC1D,uDAAuD;QACvD,sDAAsD;QACtD,mCAAmC;QACnC,kCAAkC;QAClC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC3C,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,gCAAgC;YAChC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC5C,CAAC;QACD,4DAA4D;QAC5D,4EAA4E;QAC5E,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;KAOZ,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;QAC3F,4EAA4E;QAC5E,uCAAuC;QACvC,EAAE;QACF,2DAA2D;QAC3D,mDAAmD;QACnD,kDAAkD;QAClD,yCAAyC;QACzC,kEAAkE;QAClE,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC,GAAG,EAA6B,CAAC;QAC1F,oDAAoD;QACpD,+DAA+D;QAC/D,uDAAuD;QACvD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBAChC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;gBAC7D,IAAI,CAAC,EAAE,CAAC,IAAI,CACV,4DAA4D;oBAC1D,kDAAkD,CACrD,CAAC;gBACF,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC;oBACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC3B,CAAC;gBAAC,MAAM,CAAC;oBACP,iBAAiB;gBACnB,CAAC;gBACD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAE,CAAW,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;oBAAE,MAAM,CAAC,CAAC;YAC7E,CAAC;QACH,CAAC;QACD,mDAAmD;QACnD,IAAI,CAAC,EAAE,CAAC,IAAI,CACV,4DAA4D;YAC1D,sEAAsE,CACzE,CAAC;QACF,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;IACrF,CAAC;IAED,IAAI,CAAC,GAAe;QAClB,IAAI,CAAC,EAAE;aACJ,OAAO,CACN,uGAAuG,CACxG;aACA,GAAG,CACF,GAAG,CAAC,MAAM,EACV,GAAG,CAAC,cAAc,IAAI,IAAI,EAC1B,GAAG,CAAC,MAAM,EACV,GAAG,CAAC,MAAM,IAAI,IAAI,EAClB,mBAAmB,CAAC,GAAG,CAAC,CACzB,CAAC;IACN,CAAC;IAED;;;;;;;;;;;OAWG;IACK,OAAO,CACb,YAA2B,EAC3B,YAA2B,EAC3B,UAAkB,EAClB,GAAe;QAEf,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC;QAClC,IAAI,YAAY,KAAK,GAAG,CAAC,MAAM,IAAI,YAAY,KAAK,MAAM;YAAE,OAAO;QACnE,IAAI,CAAC;YACH,mCAAmC;YACnC,IAAI,CAAC,EAAE;iBACJ,OAAO,CAAC,4DAA4D,CAAC;iBACrE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YACvC,yDAAyD;YACzD,8CAA8C;YAC9C,2CAA2C;YAC3C,IAAI,CAAC,EAAE;iBACJ,OAAO,CAAC,0DAA0D,CAAC;iBACnE,GAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,gDAAgD;YAChD,mDAAmD;YACnD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBACrC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAChC,OAAO,CAAC,IAAI,CACV,gBAAgB,GAAG,CAAC,MAAM,gCAAgC,EAC1D,GAAG,CACJ,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,GAAG,CAAC,MAAc;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,OAAO,CAAC,2DAA2D,CAAC;aACpE,GAAG,CAAC,MAAM,CAAgF,CAAC;QAC9F,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,MAAM,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,GAAG;YAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC9D,OAAO,GAAG,CAAC;IACb,CAAC;IAED,aAAa,CAAC,GAAW;QACvB,0DAA0D;QAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,OAAO,CACN,+FAA+F,CAChG;aACA,GAAG,CAAC,GAAG,CAAgF,CAAC;QAC3F,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,MAAM,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,GAAG;YAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC9D,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAC,wDAAwD,CAAC;aACjE,GAAG,EAIJ,CAAC;QACH,MAAM,GAAG,GAAiB,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,6CAA6C;YAC7C,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC/C,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,MAAc;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CACN,0CAA0C;YACxC,oFAAoF,CACvF;aACA,GAAG,CAAC,MAAM,CAIX,CAAC;QACH,MAAM,GAAG,GAAiB,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC/C,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACpC,CAAC;IAED,yCAAyC;IACzC,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;CACF"}
@@ -1,5 +1,6 @@
1
1
  import type { AgentRunResult } from '../engine/types.js';
2
- import type { SpanError } from '../core/trace.js';
2
+ import type { SpanError, Usage } from '../core/trace.js';
3
+ import type { MessageParam } from '../core/message.js';
3
4
  import type { RunStatus, SuspendedReason, TaskEvent } from '../core/run.js';
4
5
  import type { ApprovalDecision } from '../core/tool.js';
5
6
  import type { RunSpec } from '../engine/spec.js';
@@ -84,6 +85,10 @@ export interface TaskRecord {
84
85
  * 簿记有界,恰好一次的承诺也就有界)。
85
86
  */
86
87
  deliveredEventIds?: string[] | undefined;
88
+ /** 首个挂起段的本轮用户输入;随记录落库,恢复成功后补写会话,终态清除 */
89
+ sessionInput?: MessageParam[] | undefined;
90
+ /** 本任务所有已收尾 run 段的累计用量;恢复段把它作为预算 offset */
91
+ usageTotal?: Usage | undefined;
87
92
  }
88
93
  export interface TaskStore {
89
94
  /**
@@ -18,11 +18,17 @@ export function nextTaskId() {
18
18
  * `RunInvocationOptions.fallbacks` 的序列化边界注释)。
19
19
  */
20
20
  export function cloneTaskRecord(rec) {
21
- return cloneData(rec);
21
+ return cloneData(rec, 0);
22
22
  }
23
- function cloneData(value) {
23
+ /** 记录应是浅层 JSON 数据;超过这个深度按事故级输入响亮拒绝,而不是让 V8 爆栈 */
24
+ const MAX_CLONE_DEPTH = 256;
25
+ function cloneData(value, depth) {
26
+ if (depth > MAX_CLONE_DEPTH) {
27
+ throw new TypeError(`TaskRecord 的嵌套超过 ${MAX_CLONE_DEPTH} 层 —— 记录应是浅层 JSON 数据,` +
28
+ '拒绝深拷以免 RangeError 掩盖真实问题(2026-11-07 深评)');
29
+ }
24
30
  if (Array.isArray(value))
25
- return value.map(cloneData);
31
+ return value.map((v) => cloneData(v, depth + 1));
26
32
  if (value !== null && typeof value === 'object') {
27
33
  const proto = Object.getPrototypeOf(value);
28
34
  // 类实例(AbortSignal 等)按引用保留:克隆它没有意义,也克隆不了
@@ -32,7 +38,7 @@ function cloneData(value) {
32
38
  for (const [k, v] of Object.entries(value)) {
33
39
  // 直接赋值 '__proto__' 会走原型 setter:自有键丢失且副本原型被改。
34
40
  Object.defineProperty(out, k, {
35
- value: cloneData(v),
41
+ value: cloneData(v, depth + 1),
36
42
  writable: true,
37
43
  enumerable: true,
38
44
  configurable: true,
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/store/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/store/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import type { MessageParam } from '../core/message.js';
2
+ import type { AgentTool, JsonSchema, SchemaType, ToolRunContext } from '../core/tool.js';
3
+ import type { SpanError, SpanId } from '../core/trace.js';
4
+ import type { AgentStopReason, ContextPolicy, SystemParam } from '../engine/types.js';
5
+ /**
6
+ * Agentia —— **代码控制顺序的子循环**原语(spec §10 2026-11-04 run-capability-loop)。
7
+ *
8
+ * ## 它补的是哪一格
9
+ *
10
+ * 四类能力里,「谁定流程」有两个极端:`@SubAgent` / `@Skill` 的子循环由**模型**驱动
11
+ * (前者整段交给模型,后者由你的方法体决定何时调 `ctx.llm`),而「这件事会不会活过
12
+ * 这次请求」的判据又把长跑 / 要审批的活儿推给 `AsyncRunner` 的 task。中间那一格是空的:
13
+ *
14
+ * > 顺序由**我的代码**定(不是模型)、生命周期**不超出**这次请求(不进 task 状态机)、
15
+ * > 但要能挂到**同一棵** trace 上、要能裁剪上下文、要能被外层工具的 `approval` 拦住。
16
+ *
17
+ * 从前做这件事只有一条路:手写 `runAgentScoped` + 自己逐个转发 `ToolRunContext` 的旋钮。
18
+ * 那条路在 `engine/forwarded.ts` 的文件头里有完整的事故记录 —— 漏一个 `toolTimeoutMs`
19
+ * 是**静默**的(TS 的可选字段不会报错),后果还是反的(子循环永不超时)。所以本模块
20
+ * **不是**把 `runAgentScoped` 直接搬上公共面,而是把它包成「旋钮不可漏」的形状:
21
+ * `...forwardToolContext(ctx)` 一次取自单源,使用方接触不到那七个键。
22
+ *
23
+ * ## 与另外三行的分工(选型只看两个问题)
24
+ *
25
+ * | 问题 | 是 ⇒ | 否 ⇒ |
26
+ * |---|---|---|
27
+ * | 顺序要不要模型定? | `@SubAgent`(整段)/ `@Skill`(方法体里 `ctx.llm`) | **本模块** |
28
+ * | 会不会活过这次请求? | `AsyncRunner.submit`(task:耐久 / 崩溃续跑 / 审批原生) | **本模块** |
29
+ *
30
+ * 要审批的动作:把调用本模块的那个方法标成 `@Tool({ approval: 'required' })` ——
31
+ * 审批发生在**外层工具调用**上,于是一个「子循环里要改数据」的活儿既能挂起等人批
32
+ * (`POST /tasks/:id/approve`),又不必为它造一条任务。这正是 `@SubAgent` / `@Skill`
33
+ * 做不到的那半(子循环内部的 `approval` 无法挂起整条 run,见 usage-guide §7)。
34
+ *
35
+ * ## 边界(都是刻意留白,不是缺口)
36
+ *
37
+ * - **不做策略**:不替你拆步、不重试、不汇总多个子循环 —— 顺序写在你的方法体里。
38
+ * - **不自开 run 根**:`llm.turn` 挂在 `ctx.parentSpanId` 下的一个 `capability` span 里,
39
+ * 与本条 run 同树;`traceId` 不变,`runId` 也不会多出来一个。
40
+ * - **不给 `client` 缺省之外的聪明**:不传 `model` 就走引擎缺省;子循环**不继承**主 run
41
+ * 的 `fallbacks` 链(同 `runAgentScoped` 的有意边界)。
42
+ * - **挂起不穿透**:子循环里调用了 `deferUntil` / 触发审批挂起时,语义同其它嵌套能力 ——
43
+ * 以 `is_error` 交回,整条 run 不挂起。要挂起请用 task。
44
+ */
45
+ export interface CapabilityLoopOptions<S extends JsonSchema = JsonSchema> {
46
+ /**
47
+ * trace 里那个 `capability` span 的名字。缺省 `'capability-loop'` ——
48
+ * 建议给一个业务名(`'ledger-review'`),否则看板上一排同名 span 分不出是谁。
49
+ */
50
+ name?: string;
51
+ /** 子循环的输入:一段文本或完整 messages(与 `app.run` 同一套规整口径) */
52
+ input: string | MessageParam[];
53
+ /** 子循环的 system(独立上下文:主 agent 的历史**不可见**) */
54
+ system?: SystemParam;
55
+ /** 子循环可见的工具(缺省空 = 纯文本回合) */
56
+ tools?: AgentTool[];
57
+ model?: string;
58
+ maxTokens?: number;
59
+ maxIterations?: number;
60
+ /**
61
+ * 子循环自己的上下文裁剪策略。**这是本原语存在的理由之一** ——
62
+ * 应用级 `contextPolicy` 不进子循环(usage-guide §7),长跑子循环想不撞上限
63
+ * 只能在这里显式给。
64
+ */
65
+ contextPolicy?: ContextPolicy;
66
+ /** 结构化结果 schema:给出后追加隐藏 `submit_result` 工具,校验结果落在 `typed` */
67
+ resultSchema?: S;
68
+ /** 逐字回调(转发给子循环的 `llm.turn`,不写 trace 时也能做流式) */
69
+ onText?: (delta: string) => void;
70
+ }
71
+ /** 子循环的产物(只回「这次子循环发生了什么」,不夹带整棵 trace) */
72
+ export interface CapabilityLoopResult<S extends JsonSchema = JsonSchema> {
73
+ /** 子循环最终文本(隔离报告:中间往返不外传) */
74
+ text: string;
75
+ /** `resultSchema` 校验通过的结构化结果;未给 schema 或模型未提交时为 undefined */
76
+ typed: SchemaType<S> | undefined;
77
+ /** 收尾原因。调用方自己判成败(`isSuccessStopReason`)—— 框架不替它抛 */
78
+ stopReason: AgentStopReason;
79
+ iterations: number;
80
+ /** 本次子循环的 capability span id(要补事件 / 属性时用) */
81
+ spanId: SpanId;
82
+ /** 非正常收尾时的错误(与 `stopReason` 同源,不另造一份口径) */
83
+ error?: SpanError;
84
+ }
85
+ /**
86
+ * 在**当前工具调用**里拉起一条子循环。
87
+ *
88
+ * `ctx` 必须是引擎注入的 `ToolRunContext`(`AgentTool.run` 的第二个参数)——
89
+ * 它带着 recorder / 父 span / 取消信号 / 预算与超时护栏。从别处手搓一个 ctx 只会
90
+ * 得到一个「看起来在跑、实际不进树、护栏全离线」的子循环,所以这里不做任何兜底。
91
+ */
92
+ export declare function runCapabilityLoop<S extends JsonSchema = JsonSchema>(ctx: ToolRunContext, opts: CapabilityLoopOptions<S>): Promise<CapabilityLoopResult<S>>;