evolcore 0.0.25 → 0.0.27

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 (304) hide show
  1. package/CHANGELOG.md +632 -565
  2. package/LICENSE +21 -21
  3. package/README.md +455 -455
  4. package/bin/codex-managed-acl.ps1 +203 -160
  5. package/bin/codex-managed-hook.mjs +208 -208
  6. package/bin/ec-safe-output.js +327 -327
  7. package/bin/ec.js +40 -29
  8. package/bin/install-codex-managed-hooks.mjs +582 -555
  9. package/dist/agents/baseagent-availability.js +68 -0
  10. package/dist/agents/baseagent.js +96 -46
  11. package/dist/agents/claude-runner.js +172 -33
  12. package/dist/agents/codex/app-server-client.js +76 -31
  13. package/dist/agents/codex/catalog.js +1 -1
  14. package/dist/agents/codex/diagnostics.js +34 -1
  15. package/dist/agents/codex-runner.js +434 -446
  16. package/dist/agents/ecagent-runner.js +174 -34
  17. package/dist/agents/gemini-runner.js +8 -7
  18. package/dist/agents/runner-types.js +75 -19
  19. package/dist/aun/aid/agentmd.js +151 -36
  20. package/dist/aun/aid/client.js +1 -1
  21. package/dist/aun/aid/control-aid.js +180 -1
  22. package/dist/aun/aid/identity.js +4 -4
  23. package/dist/aun/aid/index.js +1 -1
  24. package/dist/aun/aid/store.js +17 -13
  25. package/dist/aun/group/history.js +303 -0
  26. package/dist/aun/group/identity.js +43 -0
  27. package/dist/aun/group/index.js +5 -0
  28. package/dist/aun/{msg/group.js → group/operations.js} +162 -39
  29. package/dist/aun/{menu-client.js → menu/client.js} +85 -6
  30. package/dist/aun/menu/index.js +2 -0
  31. package/dist/aun/menu/transport.js +49 -0
  32. package/dist/aun/msg/index.js +2 -1
  33. package/dist/aun/msg/managed-operation.js +85 -19
  34. package/dist/aun/msg/mention-schema.js +51 -0
  35. package/dist/aun/msg/p2p.js +19 -9
  36. package/dist/aun/msg/upload.js +43 -80
  37. package/dist/aun/outbox.js +29 -7
  38. package/dist/aun/rpc/client.js +1 -0
  39. package/dist/aun/storage/client.js +39 -50
  40. package/dist/channels/aun.js +842 -318
  41. package/dist/channels/daemon.js +10 -6
  42. package/dist/cli/agent-command.js +212 -89
  43. package/dist/cli/agent-create.js +626 -11
  44. package/dist/cli/agent.js +125 -13
  45. package/dist/cli/aun-commands.js +487 -337
  46. package/dist/cli/bench.js +20 -20
  47. package/dist/cli/config.js +55 -33
  48. package/dist/cli/contact.js +72 -15
  49. package/dist/cli/ctl-command.js +24 -24
  50. package/dist/cli/daemon-commands.js +140 -63
  51. package/dist/cli/diag.js +31 -0
  52. package/dist/cli/fs-command.js +70 -70
  53. package/dist/cli/handoff-command.js +46 -14
  54. package/dist/cli/index.js +91 -79
  55. package/dist/cli/init.js +34 -1
  56. package/dist/cli/link-rules.js +21 -21
  57. package/dist/cli/managed-command-guard.js +5 -1
  58. package/dist/cli/menu-client.js +51 -32
  59. package/dist/cli/model.js +3 -3
  60. package/dist/cli/net-check.js +22 -22
  61. package/dist/cli/queue-command.js +31 -31
  62. package/dist/cli/response.js +32 -32
  63. package/dist/cli/restart-monitor.js +103 -42
  64. package/dist/cli/stats.js +51 -51
  65. package/dist/cli/task-command.js +59 -0
  66. package/dist/cli/task-context.js +97 -49
  67. package/dist/cli/trigger-command.js +74 -64
  68. package/dist/config/builtin-roles.js +11 -0
  69. package/dist/config/config-field-policy.js +11 -0
  70. package/dist/config/config-manager.js +32 -4
  71. package/dist/config/config-operation-service.js +160 -0
  72. package/dist/config/contact-book-store.js +1 -1
  73. package/dist/config/contact-book.js +1 -1
  74. package/dist/config/contact-operation-service.js +97 -8
  75. package/dist/config/peer-role-resolver.js +1 -1
  76. package/dist/config/resolved-config-op.js +30 -7
  77. package/dist/config-store.js +1 -1
  78. package/dist/core/agent-application-service.js +7 -1
  79. package/dist/core/audit/event-key.js +17 -2
  80. package/dist/core/audit/log-integrity.js +34 -8
  81. package/dist/core/auth/agent-delegation.js +48 -14
  82. package/dist/core/auth/auth-gateway.js +2 -0
  83. package/dist/core/auth/authorization-audit.js +53 -49
  84. package/dist/core/auth/operation-authorizer.js +90 -7
  85. package/dist/core/auth/operation-catalog.js +145 -4
  86. package/dist/core/auth/remote-access-store.js +155 -10
  87. package/dist/core/bootstrap-messages.js +66 -7
  88. package/dist/core/bootstrap-service.js +111 -20
  89. package/dist/core/command/agent-control.js +88 -7
  90. package/dist/core/command/agent-storage-menu.js +443 -0
  91. package/dist/core/command/cli-intent-parser.js +19 -0
  92. package/dist/core/command/command-handler.js +159 -65
  93. package/dist/core/command/data-root-resolver.js +273 -0
  94. package/dist/core/command/diag-service.js +118 -0
  95. package/dist/core/command/group-menu.js +7 -2
  96. package/dist/core/command/menu-catalog.js +46 -7
  97. package/dist/core/command/menu-handler.js +392 -100
  98. package/dist/core/command/menu-protocol.js +45 -6
  99. package/dist/core/command/menu-token-store.js +41 -8
  100. package/dist/core/command/role-menu.js +2 -2
  101. package/dist/core/command/slash-gate.js +34 -4
  102. package/dist/core/command/slash-handler.js +123 -43
  103. package/dist/core/event-catalog.js +4 -0
  104. package/dist/core/evolagent-registry.js +28 -2
  105. package/dist/core/group/invite-service.js +924 -0
  106. package/dist/core/handoff/runtime.js +205 -27
  107. package/dist/core/handoff/store.js +193 -4
  108. package/dist/core/interaction-router.js +22 -8
  109. package/dist/core/message/im-renderer.js +146 -34
  110. package/dist/core/message/message-bridge.js +163 -20
  111. package/dist/core/message/message-log.js +5 -3
  112. package/dist/core/message/message-queue.js +99 -41
  113. package/dist/core/message/message-utils.js +1 -0
  114. package/dist/core/message/response-engine.js +755 -144
  115. package/dist/core/model/catalog-service.js +79 -49
  116. package/dist/core/model/context-window-suffix.js +33 -0
  117. package/dist/core/model/model-catalog.js +1 -1
  118. package/dist/core/model/model-permission.js +12 -3
  119. package/dist/core/permission/approval-gateway.js +36 -3
  120. package/dist/core/permission/ec-command-parser.js +112 -41
  121. package/dist/core/permission/protected-paths.js +134 -16
  122. package/dist/core/permission/sandbox-runtime.js +108 -17
  123. package/dist/core/permission/tool-error-code.js +15 -0
  124. package/dist/core/permission/tool-policy.js +9 -8
  125. package/dist/core/relation/peer-identity.js +57 -6
  126. package/dist/core/relation/shared-data.js +106 -0
  127. package/dist/core/role/runtime-policy.js +64 -0
  128. package/dist/core/runtime-lock.js +10 -26
  129. package/dist/core/session/runner-task-history.js +170 -0
  130. package/dist/core/session/session-manager.js +34 -6
  131. package/dist/core/session/session-mapper.js +41 -0
  132. package/dist/core/session/session-turn-coordinator.js +37 -7
  133. package/dist/core/session/session-turns.js +48 -7
  134. package/dist/core/task/task-recovery-service.js +176 -0
  135. package/dist/core/task/task-resume-operation.js +32 -0
  136. package/dist/eck/group-rules-sync.js +5 -3
  137. package/dist/eck/kit-renderer.js +1 -0
  138. package/dist/index.js +588 -217
  139. package/dist/ipc.js +193 -15
  140. package/dist/paths.js +17 -4
  141. package/dist/product.js +2 -0
  142. package/dist/response-system/engines/v1/proactive-flow.js +59 -2
  143. package/dist/stats/billing.js +41 -15
  144. package/dist/stats/db.js +159 -159
  145. package/dist/stats/eck-vars.js +9 -9
  146. package/dist/stats/price-resolver.js +28 -10
  147. package/dist/stats/query.js +139 -139
  148. package/dist/stats/role-budget.js +6 -6
  149. package/dist/stats/writer.js +51 -51
  150. package/dist/trigger/event-source.js +19 -0
  151. package/dist/trigger/feedback.js +233 -40
  152. package/dist/trigger/parser.js +55 -5
  153. package/dist/trigger/patch.js +9 -0
  154. package/dist/trigger/scheduler.js +30 -4
  155. package/dist/trigger/validation.js +20 -3
  156. package/dist/utils/cross-platform.js +30 -1
  157. package/dist/utils/ecweb-utils.js +1 -0
  158. package/dist/utils/error-dict.json +160 -160
  159. package/dist/utils/error-utils.js +61 -2
  160. package/dist/utils/evolcore-version.js +129 -0
  161. package/dist/utils/logger.js +26 -14
  162. package/dist/utils/macos-autostart.js +22 -22
  163. package/dist/utils/model-prices.jsonl +23 -23
  164. package/dist/utils/npm-ops.js +176 -35
  165. package/dist/utils/tool-summary.js +59 -3
  166. package/dist/utils/welcome.js +196 -23
  167. package/ecagent/LICENSE +21 -21
  168. package/ecagent/NOTICE +11 -11
  169. package/ecagent/README.md +61 -61
  170. package/ecagent/dist/harness/agent-harness.js +3 -0
  171. package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
  172. package/ecagent/dist/harness/compaction/compaction.js +83 -83
  173. package/ecagent/dist/harness/messages.js +7 -7
  174. package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
  175. package/kits/docs/GUIDE.md +20 -20
  176. package/kits/docs/INDEX.md +60 -66
  177. package/kits/docs/aun/CHEATSHEET.md +19 -19
  178. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
  179. package/kits/docs/channels/aun.md +69 -56
  180. package/kits/docs/channels/feishu.md +56 -56
  181. package/kits/docs/context-assembly.md +379 -367
  182. package/kits/docs/eck_templates/GUIDE.template.md +22 -22
  183. package/kits/docs/eck_templates/INDEX.template.md +28 -28
  184. package/kits/docs/eck_templates/path-registry.template.md +33 -33
  185. package/kits/docs/eck_templates/runtime.template.md +19 -19
  186. package/kits/docs/evolcore/INDEX.md +76 -71
  187. package/kits/docs/evolcore/agent-create.md +202 -165
  188. package/kits/docs/evolcore/agent.md +99 -67
  189. package/kits/docs/evolcore/aid.md +68 -60
  190. package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
  191. package/kits/docs/evolcore/config.md +241 -195
  192. package/kits/docs/evolcore/contact.md +75 -68
  193. package/kits/docs/evolcore/ctl.md +46 -46
  194. package/kits/docs/evolcore/event.md +216 -216
  195. package/kits/docs/evolcore/fs-architecture.md +1215 -1215
  196. package/kits/docs/evolcore/fs.md +110 -110
  197. package/kits/docs/evolcore/group-collaboration.md +244 -244
  198. package/kits/docs/evolcore/group-fs.md +17 -17
  199. package/kits/docs/evolcore/group-rules.md +251 -251
  200. package/kits/docs/evolcore/group.md +267 -152
  201. package/kits/docs/evolcore/menu-client.md +58 -34
  202. package/kits/docs/evolcore/model.md +50 -50
  203. package/kits/docs/evolcore/msg.md +169 -165
  204. package/kits/docs/evolcore/response.md +75 -75
  205. package/kits/docs/evolcore/rpc.md +37 -37
  206. package/kits/docs/evolcore/self-summary.md +29 -29
  207. package/kits/docs/evolcore/stats.md +83 -83
  208. package/kits/docs/evolcore/storage.md +53 -50
  209. package/kits/docs/evolcore/task.md +14 -0
  210. package/kits/docs/evolcore/trigger.md +623 -575
  211. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
  212. package/kits/docs/identity/PATH_OPS.md +16 -16
  213. package/kits/docs/identity/ROLE_DETAIL.md +25 -25
  214. package/kits/docs/identity/identity-tools.md +26 -26
  215. package/kits/docs/path-registry.md +62 -62
  216. package/kits/docs/prompt-loading-architecture.md +269 -269
  217. package/kits/docs/venues/aun-group.md +45 -45
  218. package/kits/docs/venues/aun-private.md +10 -10
  219. package/kits/docs/venues/client-desktop.md +10 -10
  220. package/kits/docs/venues/client-mobile.md +10 -10
  221. package/kits/docs/venues/feishu-group.md +13 -13
  222. package/kits/docs/venues/feishu-private.md +9 -9
  223. package/kits/docs/venues/group.md +42 -25
  224. package/kits/docs/venues/private.md +10 -10
  225. package/kits/eck_manifest.auxiliary.json +43 -43
  226. package/kits/eck_manifest.json +217 -190
  227. package/kits/eck_message_manifest.json +74 -74
  228. package/kits/migrations/README-role-config-v4.md +32 -32
  229. package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
  230. package/kits/migrations/migrate-role-config-v4.mjs +614 -614
  231. package/kits/migrations/migrate-role-config-v5.mjs +365 -365
  232. package/kits/migrations/rename-config-file.mjs +99 -99
  233. package/kits/rules/01-overview.md +166 -162
  234. package/kits/rules/02-navigation.md +96 -96
  235. package/kits/rules/03-identity.md +36 -36
  236. package/kits/rules/04-relation.md +76 -75
  237. package/kits/rules/05-venue.md +60 -60
  238. package/kits/rules/06-channel.md +65 -63
  239. package/kits/schemas/_meta.json +53 -53
  240. package/kits/schemas/agent-config.schema.1.json +177 -177
  241. package/kits/schemas/agent-config.schema.10.json +395 -395
  242. package/kits/schemas/agent-config.schema.11.json +421 -421
  243. package/kits/schemas/agent-config.schema.12.json +451 -427
  244. package/kits/schemas/agent-config.schema.2.json +239 -239
  245. package/kits/schemas/agent-config.schema.3.json +119 -119
  246. package/kits/schemas/agent-config.schema.4.json +208 -208
  247. package/kits/schemas/agent-config.schema.5.json +326 -326
  248. package/kits/schemas/agent-config.schema.6.json +322 -322
  249. package/kits/schemas/agent-config.schema.7.json +303 -303
  250. package/kits/schemas/agent-config.schema.8.json +304 -304
  251. package/kits/schemas/agent-config.schema.9.json +364 -364
  252. package/kits/schemas/contact-book.schema.1.json +36 -36
  253. package/kits/schemas/contact-book.schema.2.json +43 -43
  254. package/kits/schemas/contact-book.schema.3.json +67 -67
  255. package/kits/schemas/daemon.schema.1.json +91 -91
  256. package/kits/schemas/daemon.schema.2.json +101 -101
  257. package/kits/schemas/daemon.schema.3.json +123 -123
  258. package/kits/schemas/daemon.schema.4.json +136 -136
  259. package/kits/schemas/daemon.schema.5.json +135 -135
  260. package/kits/schemas/daemon.schema.6.json +131 -131
  261. package/kits/schemas/defaults.schema.1.json +81 -81
  262. package/kits/schemas/defaults.schema.2.json +85 -85
  263. package/kits/schemas/defaults.schema.3.json +73 -73
  264. package/kits/schemas/defaults.schema.4.json +107 -107
  265. package/kits/schemas/defaults.schema.5.json +119 -119
  266. package/kits/schemas/menu-exec-schema-commands.md +208 -208
  267. package/kits/schemas/migrations/README.md +30 -30
  268. package/kits/schemas/relation-config.schema.1.json +158 -158
  269. package/kits/schemas/relation-config.schema.2.json +73 -73
  270. package/kits/schemas/relation-config.schema.3.json +50 -50
  271. package/kits/schemas/relation-config.schema.4.json +47 -47
  272. package/kits/schemas/relation-config.schema.5.json +47 -47
  273. package/kits/schemas/relation-config.schema.6.json +46 -46
  274. package/kits/schemas/relation-config.schema.7.json +59 -59
  275. package/kits/schemas/relation-config.schema.8.json +103 -103
  276. package/kits/schemas/role-config.schema.1.json +215 -201
  277. package/kits/schemas/role-registry.schema.1.json +35 -35
  278. package/kits/schemas/single-session.schema.1.json +31 -31
  279. package/kits/schemas/single-session.schema.2.json +57 -57
  280. package/kits/schemas/single-session.schema.3.json +32 -32
  281. package/kits/templates/bootstrap-welcome.md +17 -17
  282. package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
  283. package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
  284. package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
  285. package/kits/templates/message-fragments/inject-default.md +2 -2
  286. package/kits/templates/message-fragments/item.md +2 -2
  287. package/kits/templates/roles/admin.json +92 -92
  288. package/kits/templates/roles/member.json +101 -96
  289. package/kits/templates/roles/owner.json +9 -9
  290. package/kits/templates/roles/visitor.json +90 -85
  291. package/kits/templates/system-fragments/baseagent.md +14 -14
  292. package/kits/templates/system-fragments/bootstrap.md +53 -34
  293. package/kits/templates/system-fragments/channel.md +28 -64
  294. package/kits/templates/system-fragments/commands.md +36 -28
  295. package/kits/templates/system-fragments/group-unread-history.md +7 -0
  296. package/kits/templates/system-fragments/identity.md +13 -13
  297. package/kits/templates/system-fragments/relation.md +19 -19
  298. package/kits/templates/system-fragments/reply.md +56 -0
  299. package/kits/templates/system-fragments/session.md +59 -59
  300. package/kits/templates/system-fragments/venue.md +31 -31
  301. package/package.json +104 -98
  302. package/dist/aun/group-identity.js +0 -9
  303. /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
  304. /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
@@ -4,6 +4,7 @@ import { logger } from '../../utils/logger.js';
4
4
  import { LogicalQueueBridge } from './logical-queue-bridge.js';
5
5
  import { normalizeCausation } from '../causation/context.js';
6
6
  import { KeyedFairMutex } from '../handoff/mutex.js';
7
+ import { ExecutionTimeoutError, OrphanedTargetSessionError, isExecutionFailure } from '../../utils/error-utils.js';
7
8
  const DEFAULT_AGENT_NAME = '<unknown>';
8
9
  const RESTART_RESUME_CONTENT = 'evolcore 服务已重启,请继续之前未完成的任务。';
9
10
  export class MessageQueue {
@@ -52,7 +53,7 @@ export class MessageQueue {
52
53
  setInterruptCallback(callback) {
53
54
  this.interruptCallback = callback;
54
55
  }
55
- triggerInterrupt(queueKey, sessionKey, baseagent, evolagentName, reason) {
56
+ triggerInterrupt(queueKey, sessionKey, baseagent, evolagentName, reason, timeout) {
56
57
  const existing = this.interruptBarriers.get(queueKey);
57
58
  if (existing)
58
59
  return existing;
@@ -61,7 +62,9 @@ export class MessageQueue {
61
62
  this.activeTerminalReasons.set(queueKey, reason);
62
63
  let interruption;
63
64
  try {
64
- interruption = Promise.resolve(this.interruptCallback(sessionKey, baseagent, evolagentName, reason));
65
+ interruption = Promise.resolve(timeout
66
+ ? this.interruptCallback(sessionKey, baseagent, evolagentName, reason, timeout)
67
+ : this.interruptCallback(sessionKey, baseagent, evolagentName, reason));
65
68
  }
66
69
  catch (error) {
67
70
  interruption = Promise.reject(error);
@@ -980,7 +983,8 @@ export class MessageQueue {
980
983
  this.persistQueuesImmediate();
981
984
  }
982
985
  else if (message.messageId) {
983
- void this.cancelActiveAndWait(message.messageId, message.selfAID).finally(() => {
986
+ const timeout = isExecutionFailure(options?.signal?.reason) ? options.signal.reason : undefined;
987
+ void this.cancelActiveAndWait(message.messageId, message.selfAID, timeout).finally(() => {
984
988
  this.forgetProcessed(sessionKey, message);
985
989
  settleReject(error);
986
990
  });
@@ -1262,7 +1266,9 @@ export class MessageQueue {
1262
1266
  return result;
1263
1267
  }
1264
1268
  isMergeBarrier(message) {
1265
- return !!message.executionPermissionOverride
1269
+ return !!message.taskRecovery
1270
+ || !!message.asyncQuestionAnswer
1271
+ || !!message.executionPermissionOverride
1266
1272
  || !!message.handoffDelivery
1267
1273
  || !!message.triggerMeta
1268
1274
  || !!message.causation?.trigger?.path.length;
@@ -1275,6 +1281,8 @@ export class MessageQueue {
1275
1281
  return false;
1276
1282
  if (first.projectPath !== next.projectPath || first.agentName !== next.agentName)
1277
1283
  return false;
1284
+ // Results from the same parent handoff are still mergeable. Their
1285
+ // resultRefs are retained and consumed individually after one turn.
1278
1286
  const a = first.message.handoffDelivery?.originAuthorization;
1279
1287
  const b = next.message.handoffDelivery?.originAuthorization;
1280
1288
  if (!a || !b)
@@ -1323,6 +1331,10 @@ export class MessageQueue {
1323
1331
  let hasMessagesAfterRestartResume = false;
1324
1332
  const originHandoffIds = [];
1325
1333
  const seenOriginHandoffIds = new Set();
1334
+ const originResultIds = [];
1335
+ const seenOriginResultIds = new Set();
1336
+ const originResultRefs = [];
1337
+ const seenOriginResultRefs = new Set();
1326
1338
  const allOriginHandoffs = items.every(item => this.isOriginHandoff(item.message));
1327
1339
  for (const item of items) {
1328
1340
  const m = item.message;
@@ -1347,6 +1359,24 @@ export class MessageQueue {
1347
1359
  originHandoffIds.push(id);
1348
1360
  }
1349
1361
  }
1362
+ const refs = m.handoffDelivery.resultRefs?.length
1363
+ ? m.handoffDelivery.resultRefs
1364
+ : (m.handoffDelivery.resultIds?.length
1365
+ ? m.handoffDelivery.resultIds.map(resultId => ({ handoffId: m.handoffDelivery.handoffId, resultId }))
1366
+ : (m.handoffDelivery.resultId
1367
+ ? [{ handoffId: m.handoffDelivery.handoffId, resultId: m.handoffDelivery.resultId }]
1368
+ : []));
1369
+ for (const ref of refs) {
1370
+ const refKey = `${ref.handoffId}\u0000${ref.resultId}`;
1371
+ if (!seenOriginResultRefs.has(refKey)) {
1372
+ seenOriginResultRefs.add(refKey);
1373
+ originResultRefs.push(ref);
1374
+ }
1375
+ if (!seenOriginResultIds.has(ref.resultId)) {
1376
+ seenOriginResultIds.add(ref.resultId);
1377
+ originResultIds.push(ref.resultId);
1378
+ }
1379
+ }
1350
1380
  }
1351
1381
  for (const id of [...(m.sourceMessageIds ?? []), ...(m.messageId ? [m.messageId] : [])]) {
1352
1382
  if (!seenSourceMessageIds.has(id)) {
@@ -1418,6 +1448,8 @@ export class MessageQueue {
1418
1448
  ...last.message.handoffDelivery,
1419
1449
  handoffId: originHandoffIds[0],
1420
1450
  handoffIds: originHandoffIds,
1451
+ ...(originResultIds.length > 0 ? { resultIds: originResultIds } : {}),
1452
+ ...(originResultRefs.length > 0 ? { resultRefs: originResultRefs } : {}),
1421
1453
  }
1422
1454
  : last.message.handoffDelivery,
1423
1455
  };
@@ -1499,12 +1531,14 @@ export class MessageQueue {
1499
1531
  return cancellation.found;
1500
1532
  }
1501
1533
  /** Cancel an active message and wait until the runner interrupt barrier settles. */
1502
- async cancelActiveAndWait(messageId, selfAID) {
1503
- const cancellation = this.beginActiveCancellation(messageId, selfAID);
1534
+ async cancelActiveAndWait(messageId, selfAID, cause) {
1535
+ const cancellation = this.beginActiveCancellation(messageId, selfAID, cause);
1504
1536
  await cancellation.barrier;
1505
1537
  return cancellation.found;
1506
1538
  }
1507
- beginActiveCancellation(messageId, selfAID) {
1539
+ beginActiveCancellation(messageId, selfAID, cause) {
1540
+ const reason = cause instanceof ExecutionTimeoutError ? 'timeout'
1541
+ : cause instanceof OrphanedTargetSessionError ? 'execution_error' : cause ?? 'recalled';
1508
1542
  for (const [queueKey, activeState] of this.activeStates.entries()) {
1509
1543
  if (!activeState.messageIds.has(messageId))
1510
1544
  continue;
@@ -1532,18 +1566,20 @@ export class MessageQueue {
1532
1566
  }
1533
1567
  const sessionKey = this.sessionKeyFromQueueKey(queueKey);
1534
1568
  const agentName = this.processingAgent.get(queueKey);
1535
- logger.info(`[Queue] Recalled active message ${messageId}, interrupting session ${sessionKey}`);
1536
- this.eventBus?.publish({
1537
- type: 'task:interrupted',
1538
- sessionId: sessionKey,
1539
- reason: 'recalled',
1540
- agentName,
1541
- taskId: activeState?.taskId,
1542
- generation: activeState?.generation,
1543
- causation: active?.message.causation,
1544
- });
1569
+ logger.info(`[Queue] Cancelled active message ${messageId}, interrupting session ${sessionKey}: ${reason}`);
1570
+ // TimeoutController owns the failure event and outbound timeout terminal.
1571
+ if (reason !== 'timeout' && reason !== 'execution_error')
1572
+ this.eventBus?.publish({
1573
+ type: 'task:interrupted',
1574
+ sessionId: sessionKey,
1575
+ reason,
1576
+ agentName,
1577
+ taskId: activeState?.taskId,
1578
+ generation: activeState?.generation,
1579
+ causation: active?.message.causation,
1580
+ });
1545
1581
  const barrier = this.interruptCallback
1546
- ? this.triggerInterrupt(queueKey, sessionKey, activeState.baseagent, agentName, 'recalled')
1582
+ ? this.triggerInterrupt(queueKey, sessionKey, activeState.baseagent, agentName, reason, isExecutionFailure(cause) ? cause : undefined)
1547
1583
  : Promise.resolve();
1548
1584
  return { found: true, barrier };
1549
1585
  }
@@ -1577,33 +1613,11 @@ export class MessageQueue {
1577
1613
  }
1578
1614
  let releasePromise;
1579
1615
  const promise = new Promise(resolve => { releasePromise = resolve; });
1580
- let queued = 0;
1581
- let active = false;
1582
- let dispatching = false;
1583
- for (const [queueKey, queue] of this.queues.entries()) {
1584
- if (!this.matchesSession(queueKey, sessionKey))
1585
- continue;
1586
- queued += this.queueRawMessageCount(queue);
1587
- if (this.processing.has(queueKey) || this.activeBatches.has(queueKey))
1588
- active = true;
1589
- if (this.processing.has(queueKey) && !this.activeBatches.has(queueKey))
1590
- dispatching = true;
1591
- }
1592
- for (const queueKey of this.activeBatches.keys()) {
1593
- if (this.matchesSession(queueKey, sessionKey))
1594
- active = true;
1595
- }
1596
1616
  const state = {
1597
1617
  promise,
1598
1618
  releasePromise,
1599
1619
  holders: 1,
1600
- snapshot: {
1601
- prequeue: this.prequeueReservations.get(sessionKey) ?? 0,
1602
- active,
1603
- queued,
1604
- dispatching,
1605
- cutoff: this.enqueueSequence,
1606
- },
1620
+ snapshot: this.getSessionSnapshot(sessionKey),
1607
1621
  };
1608
1622
  this.externalLocks.set(sessionKey, state);
1609
1623
  let released = false;
@@ -1622,6 +1636,50 @@ export class MessageQueue {
1622
1636
  },
1623
1637
  };
1624
1638
  }
1639
+ /** Live admission state, including work that arrived after an older gate. */
1640
+ getMessageState(sessionId, messageId, selfAid) {
1641
+ for (const [key, queue] of this.queues) {
1642
+ if (this.matchesSession(key, sessionId) && queue.some(item => this.partsOf(item)
1643
+ .some(part => this.partMatchesMessage(part, messageId, selfAid, key))))
1644
+ return { state: 'queued' };
1645
+ }
1646
+ for (const [key, item] of this.activeBatches) {
1647
+ if (this.matchesSession(key, sessionId) && this.partsOf(item)
1648
+ .some(part => this.partMatchesMessage(part, messageId, selfAid, key))) {
1649
+ return { state: 'active' };
1650
+ }
1651
+ }
1652
+ return { state: 'missing' };
1653
+ }
1654
+ /** Live admission state, including work that arrived after an older gate. */
1655
+ getSessionSnapshot(sessionKey) {
1656
+ let queued = 0;
1657
+ let active = false;
1658
+ let dispatching = false;
1659
+ const activeTaskIds = new Set();
1660
+ for (const [queueKey, queue] of this.queues.entries()) {
1661
+ if (!this.matchesSession(queueKey, sessionKey))
1662
+ continue;
1663
+ queued += this.queueRawMessageCount(queue);
1664
+ if (this.processing.has(queueKey) || this.activeBatches.has(queueKey))
1665
+ active = true;
1666
+ if (this.processing.has(queueKey) && !this.activeBatches.has(queueKey))
1667
+ dispatching = true;
1668
+ }
1669
+ for (const queueKey of this.activeBatches.keys()) {
1670
+ if (!this.matchesSession(queueKey, sessionKey))
1671
+ continue;
1672
+ active = true;
1673
+ const taskId = this.activeStates.get(queueKey)?.taskId;
1674
+ if (taskId)
1675
+ activeTaskIds.add(taskId);
1676
+ }
1677
+ return {
1678
+ prequeue: this.prequeueReservations.get(sessionKey) ?? 0,
1679
+ active, queued, dispatching, cutoff: this.enqueueSequence,
1680
+ activeTaskIds: [...activeTaskIds],
1681
+ };
1682
+ }
1625
1683
  /**
1626
1684
  * Mark an admitted message before it enters debounce or other pre-queue
1627
1685
  * work. The returned release is idempotent so callers can use it both from
@@ -101,6 +101,7 @@ export function deliveryTargetFromSession(session) {
101
101
  export function replyContextFromSession(session, context) {
102
102
  return {
103
103
  ...(session.metadata?.replyContext ?? {}),
104
+ ...(session.threadId ? { threadId: session.threadId } : {}),
104
105
  ...(context ?? {}),
105
106
  // Session chatType/groupId is the persisted routing authority. The nested
106
107
  // reply context can outlive a route correction, so only an explicit