comisai 1.0.34 → 1.0.36

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 (284) hide show
  1. package/node_modules/@comis/agent/dist/background/auto-background-middleware.d.ts +11 -1
  2. package/node_modules/@comis/agent/dist/background/auto-background-middleware.js +21 -4
  3. package/node_modules/@comis/agent/dist/background/background-task-manager.d.ts +2 -2
  4. package/node_modules/@comis/agent/dist/background/background-task-manager.js +61 -20
  5. package/node_modules/@comis/agent/dist/background/background-task-persistence.js +10 -3
  6. package/node_modules/@comis/agent/dist/background/background-task-types.d.ts +10 -3
  7. package/node_modules/@comis/agent/dist/background/background-task-types.js +1 -1
  8. package/node_modules/@comis/agent/dist/background/completion-formatter.d.ts +39 -0
  9. package/node_modules/@comis/agent/dist/background/completion-formatter.js +77 -0
  10. package/node_modules/@comis/agent/dist/background/completion-runner.d.ts +53 -0
  11. package/node_modules/@comis/agent/dist/background/completion-runner.js +151 -0
  12. package/node_modules/@comis/agent/dist/background/index.d.ts +4 -0
  13. package/node_modules/@comis/agent/dist/background/index.js +2 -0
  14. package/node_modules/@comis/agent/dist/bridge/bridge-metrics.d.ts +17 -2
  15. package/node_modules/@comis/agent/dist/bridge/bridge-metrics.js +14 -2
  16. package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +23 -23
  17. package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +72 -60
  18. package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.d.ts +6 -7
  19. package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.js +24 -25
  20. package/node_modules/@comis/agent/dist/budget/cost-tracker.d.ts +1 -1
  21. package/node_modules/@comis/agent/dist/context-engine/constants.d.ts +5 -5
  22. package/node_modules/@comis/agent/dist/context-engine/constants.js +12 -12
  23. package/node_modules/@comis/agent/dist/context-engine/context-engine.js +13 -4
  24. package/node_modules/@comis/agent/dist/context-engine/dag-annotator.d.ts +1 -2
  25. package/node_modules/@comis/agent/dist/context-engine/dag-annotator.js +1 -2
  26. package/node_modules/@comis/agent/dist/context-engine/llm-compaction.js +20 -16
  27. package/node_modules/@comis/agent/dist/context-engine/rehydration.js +6 -6
  28. package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.d.ts +12 -12
  29. package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.js +36 -22
  30. package/node_modules/@comis/agent/dist/context-engine/types-core.d.ts +15 -0
  31. package/node_modules/@comis/agent/dist/executor/cache-break-detection.d.ts +6 -6
  32. package/node_modules/@comis/agent/dist/executor/cache-break-detection.js +8 -8
  33. package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.d.ts +16 -0
  34. package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.js +46 -5
  35. package/node_modules/@comis/agent/dist/executor/executor-post-execution.d.ts +30 -0
  36. package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +17 -1
  37. package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +1 -1
  38. package/node_modules/@comis/agent/dist/executor/executor-response-filter.d.ts +7 -6
  39. package/node_modules/@comis/agent/dist/executor/executor-response-filter.js +9 -42
  40. package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +2 -3
  41. package/node_modules/@comis/agent/dist/executor/gemini-cache-injector.d.ts +2 -2
  42. package/node_modules/@comis/agent/dist/executor/gemini-cache-injector.js +4 -4
  43. package/node_modules/@comis/agent/dist/executor/phase-filter.d.ts +2 -2
  44. package/node_modules/@comis/agent/dist/executor/phase-filter.js +5 -7
  45. package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +13 -0
  46. package/node_modules/@comis/agent/dist/executor/pi-executor.js +71 -6
  47. package/node_modules/@comis/agent/dist/executor/post-batch-continuation.js +7 -7
  48. package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.d.ts +1 -1
  49. package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.js +1 -1
  50. package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +2 -2
  51. package/node_modules/@comis/agent/dist/executor/tool-deferral.js +7 -7
  52. package/node_modules/@comis/agent/dist/index.d.ts +17 -0
  53. package/node_modules/@comis/agent/dist/index.js +32 -11
  54. package/node_modules/@comis/agent/dist/model/auth-provider.d.ts +25 -2
  55. package/node_modules/@comis/agent/dist/model/auth-provider.js +6 -0
  56. package/node_modules/@comis/agent/dist/model/compaction-model-resolver.d.ts +3 -3
  57. package/node_modules/@comis/agent/dist/model/compaction-model-resolver.js +3 -3
  58. package/node_modules/@comis/agent/dist/model/oauth-credential-store-file.d.ts +37 -0
  59. package/node_modules/@comis/agent/dist/model/oauth-credential-store-file.js +279 -0
  60. package/node_modules/@comis/agent/dist/model/oauth-credential-store-selector.d.ts +49 -0
  61. package/node_modules/@comis/agent/dist/model/oauth-credential-store-selector.js +50 -0
  62. package/node_modules/@comis/agent/dist/model/oauth-device-code.d.ts +57 -0
  63. package/node_modules/@comis/agent/dist/model/oauth-device-code.js +302 -0
  64. package/node_modules/@comis/agent/dist/model/oauth-env.d.ts +33 -0
  65. package/node_modules/@comis/agent/dist/model/oauth-env.js +38 -0
  66. package/node_modules/@comis/agent/dist/model/oauth-errors.d.ts +41 -0
  67. package/node_modules/@comis/agent/dist/model/oauth-errors.js +88 -0
  68. package/node_modules/@comis/agent/dist/model/oauth-identity.d.ts +53 -0
  69. package/node_modules/@comis/agent/dist/model/oauth-identity.js +141 -0
  70. package/node_modules/@comis/agent/dist/model/oauth-login-runner.d.ts +99 -0
  71. package/node_modules/@comis/agent/dist/model/oauth-login-runner.js +374 -0
  72. package/node_modules/@comis/agent/dist/model/oauth-tls-preflight.d.ts +58 -0
  73. package/node_modules/@comis/agent/dist/model/oauth-tls-preflight.js +82 -0
  74. package/node_modules/@comis/agent/dist/model/oauth-token-manager.d.ts +86 -16
  75. package/node_modules/@comis/agent/dist/model/oauth-token-manager.js +961 -66
  76. package/node_modules/@comis/agent/dist/model/operation-model-defaults.d.ts +9 -4
  77. package/node_modules/@comis/agent/dist/model/operation-model-defaults.js +36 -9
  78. package/node_modules/@comis/agent/dist/model/resolve-provider-api-key.d.ts +48 -0
  79. package/node_modules/@comis/agent/dist/model/resolve-provider-api-key.js +66 -0
  80. package/node_modules/@comis/agent/dist/provider/capabilities.d.ts +5 -5
  81. package/node_modules/@comis/agent/dist/provider/capabilities.js +10 -23
  82. package/node_modules/@comis/agent/dist/safety/tool-output-safety.js +3 -3
  83. package/node_modules/@comis/agent/dist/session/comis-session-manager.d.ts +1 -1
  84. package/node_modules/@comis/agent/dist/session/comis-session-manager.js +1 -1
  85. package/node_modules/@comis/agent/dist/spawn/narrative-caster.d.ts +10 -0
  86. package/node_modules/@comis/agent/dist/spawn/narrative-caster.js +5 -1
  87. package/node_modules/@comis/agent/package.json +1 -1
  88. package/node_modules/@comis/channels/dist/email/email-adapter.js +6 -6
  89. package/node_modules/@comis/channels/dist/email/imap-lifecycle.js +7 -7
  90. package/node_modules/@comis/channels/dist/shared/deliver-to-channel.js +12 -10
  91. package/node_modules/@comis/channels/dist/telegram/telegram-adapter.js +1 -1
  92. package/node_modules/@comis/channels/package.json +1 -1
  93. package/node_modules/@comis/cli/dist/cli.js +2 -0
  94. package/node_modules/@comis/cli/dist/commands/agent.d.ts +3 -3
  95. package/node_modules/@comis/cli/dist/commands/agent.js +46 -3
  96. package/node_modules/@comis/cli/dist/commands/auth.d.ts +37 -0
  97. package/node_modules/@comis/cli/dist/commands/auth.js +433 -0
  98. package/node_modules/@comis/cli/dist/commands/doctor.d.ts +4 -1
  99. package/node_modules/@comis/cli/dist/commands/doctor.js +20 -5
  100. package/node_modules/@comis/cli/dist/doctor/checks/oauth-health.d.ts +39 -0
  101. package/node_modules/@comis/cli/dist/doctor/checks/oauth-health.js +399 -0
  102. package/node_modules/@comis/cli/dist/doctor/types.d.ts +19 -0
  103. package/node_modules/@comis/cli/dist/index.d.ts +1 -0
  104. package/node_modules/@comis/cli/dist/index.js +10 -4
  105. package/node_modules/@comis/cli/dist/output/relative-time.d.ts +23 -0
  106. package/node_modules/@comis/cli/dist/output/relative-time.js +36 -0
  107. package/node_modules/@comis/cli/dist/wizard/non-interactive.js +17 -8
  108. package/node_modules/@comis/cli/dist/wizard/steps/03-provider.js +2 -1
  109. package/node_modules/@comis/cli/dist/wizard/steps/04-credentials.js +223 -34
  110. package/node_modules/@comis/cli/dist/wizard/steps/10-write-config.js +14 -0
  111. package/node_modules/@comis/cli/dist/wizard/steps/11-daemon-start.js +3 -3
  112. package/node_modules/@comis/cli/dist/wizard/types.d.ts +7 -0
  113. package/node_modules/@comis/cli/package.json +1 -1
  114. package/node_modules/@comis/core/dist/bootstrap.d.ts +1 -1
  115. package/node_modules/@comis/core/dist/config/env-substitution.d.ts +66 -0
  116. package/node_modules/@comis/core/dist/config/env-substitution.js +115 -0
  117. package/node_modules/@comis/core/dist/config/index.d.ts +3 -1
  118. package/node_modules/@comis/core/dist/config/index.js +2 -1
  119. package/node_modules/@comis/core/dist/config/loader.js +61 -0
  120. package/node_modules/@comis/core/dist/config/managed-sections.d.ts +3 -3
  121. package/node_modules/@comis/core/dist/config/managed-sections.js +10 -5
  122. package/node_modules/@comis/core/dist/config/schema-agent.d.ts +4 -0
  123. package/node_modules/@comis/core/dist/config/schema-agent.js +16 -1
  124. package/node_modules/@comis/core/dist/config/schema-background-tasks.d.ts +7 -0
  125. package/node_modules/@comis/core/dist/config/schema-background-tasks.js +7 -0
  126. package/node_modules/@comis/core/dist/config/schema-delivery.d.ts +2 -0
  127. package/node_modules/@comis/core/dist/config/schema-delivery.js +2 -0
  128. package/node_modules/@comis/core/dist/config/schema-gemini-cache.d.ts +0 -2
  129. package/node_modules/@comis/core/dist/config/schema-gemini-cache.js +0 -2
  130. package/node_modules/@comis/core/dist/config/schema-oauth.d.ts +23 -0
  131. package/node_modules/@comis/core/dist/config/schema-oauth.js +19 -0
  132. package/node_modules/@comis/core/dist/config/schema-skills.d.ts +6 -8
  133. package/node_modules/@comis/core/dist/config/schema-skills.js +3 -4
  134. package/node_modules/@comis/core/dist/config/schema.d.ts +10 -0
  135. package/node_modules/@comis/core/dist/config/schema.js +3 -0
  136. package/node_modules/@comis/core/dist/domain/background-task-origin.d.ts +39 -0
  137. package/node_modules/@comis/core/dist/domain/background-task-origin.js +39 -0
  138. package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +71 -2
  139. package/node_modules/@comis/core/dist/exports/config.d.ts +2 -2
  140. package/node_modules/@comis/core/dist/exports/config.js +1 -1
  141. package/node_modules/@comis/core/dist/exports/domain.d.ts +2 -0
  142. package/node_modules/@comis/core/dist/exports/domain.js +1 -0
  143. package/node_modules/@comis/core/dist/exports/ports.d.ts +2 -2
  144. package/node_modules/@comis/core/dist/exports/ports.js +1 -1
  145. package/node_modules/@comis/core/dist/ports/delivery-queue.d.ts +23 -0
  146. package/node_modules/@comis/core/dist/ports/delivery-queue.js +2 -0
  147. package/node_modules/@comis/core/dist/ports/index.d.ts +2 -0
  148. package/node_modules/@comis/core/dist/ports/index.js +1 -0
  149. package/node_modules/@comis/core/dist/ports/oauth-credential-store.d.ts +64 -0
  150. package/node_modules/@comis/core/dist/ports/oauth-credential-store.js +37 -0
  151. package/node_modules/@comis/core/dist/tool-metadata.d.ts +20 -0
  152. package/node_modules/@comis/core/package.json +1 -1
  153. package/node_modules/@comis/daemon/dist/daemon-types.d.ts +23 -3
  154. package/node_modules/@comis/daemon/dist/daemon.js +82 -19
  155. package/node_modules/@comis/daemon/dist/index.d.ts +2 -0
  156. package/node_modules/@comis/daemon/dist/index.js +5 -0
  157. package/node_modules/@comis/daemon/dist/observability/channel-health-logger.js +3 -3
  158. package/node_modules/@comis/daemon/dist/observability/delivery-queue-logger.js +1 -1
  159. package/node_modules/@comis/daemon/dist/rpc/agent-handlers.d.ts +22 -1
  160. package/node_modules/@comis/daemon/dist/rpc/agent-handlers.js +84 -21
  161. package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.js +2 -2
  162. package/node_modules/@comis/daemon/dist/rpc/config-handlers.d.ts +9 -1
  163. package/node_modules/@comis/daemon/dist/rpc/config-handlers.js +104 -23
  164. package/node_modules/@comis/daemon/dist/rpc/credential-resolver.d.ts +30 -1
  165. package/node_modules/@comis/daemon/dist/rpc/credential-resolver.js +74 -11
  166. package/node_modules/@comis/daemon/dist/rpc/mcp-handlers.d.ts +8 -0
  167. package/node_modules/@comis/daemon/dist/rpc/mcp-handlers.js +22 -8
  168. package/node_modules/@comis/daemon/dist/rpc/provider-handlers.js +9 -12
  169. package/node_modules/@comis/daemon/dist/rpc/rpc-dispatch.d.ts +1 -0
  170. package/node_modules/@comis/daemon/dist/rpc/rpc-dispatch.js +27 -2
  171. package/node_modules/@comis/daemon/dist/setup-docker-restart-warn.js +0 -1
  172. package/node_modules/@comis/daemon/dist/wiring/index.d.ts +2 -0
  173. package/node_modules/@comis/daemon/dist/wiring/index.js +1 -0
  174. package/node_modules/@comis/daemon/dist/wiring/oauth-preflight.d.ts +21 -0
  175. package/node_modules/@comis/daemon/dist/wiring/oauth-preflight.js +134 -0
  176. package/node_modules/@comis/daemon/dist/wiring/setup-agents.d.ts +46 -1
  177. package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +127 -3
  178. package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.d.ts +39 -0
  179. package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.js +32 -0
  180. package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.d.ts +10 -3
  181. package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.js +11 -5
  182. package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +20 -1
  183. package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.js +1 -1
  184. package/node_modules/@comis/daemon/dist/wiring/setup-delivery.d.ts +14 -5
  185. package/node_modules/@comis/daemon/dist/wiring/setup-delivery.js +52 -19
  186. package/node_modules/@comis/daemon/dist/wiring/setup-schedulers.js +4 -0
  187. package/node_modules/@comis/daemon/package.json +1 -1
  188. package/node_modules/@comis/gateway/dist/index.d.ts +2 -0
  189. package/node_modules/@comis/gateway/dist/index.js +2 -0
  190. package/node_modules/@comis/gateway/dist/oauth/oauth-callback-route.d.ts +66 -0
  191. package/node_modules/@comis/gateway/dist/oauth/oauth-callback-route.js +212 -0
  192. package/node_modules/@comis/gateway/dist/server/hono-server.d.ts +14 -0
  193. package/node_modules/@comis/gateway/dist/server/hono-server.js +10 -0
  194. package/node_modules/@comis/gateway/package.json +1 -1
  195. package/node_modules/@comis/infra/dist/logging/log-fields.d.ts +23 -0
  196. package/node_modules/@comis/infra/package.json +1 -1
  197. package/node_modules/@comis/memory/dist/compaction.d.ts +3 -5
  198. package/node_modules/@comis/memory/dist/compaction.js +2 -3
  199. package/node_modules/@comis/memory/dist/delivery-queue-adapter.d.ts +2 -2
  200. package/node_modules/@comis/memory/dist/delivery-queue-adapter.js +49 -1
  201. package/node_modules/@comis/memory/dist/index.d.ts +2 -0
  202. package/node_modules/@comis/memory/dist/index.js +3 -0
  203. package/node_modules/@comis/memory/dist/memory-api.d.ts +1 -1
  204. package/node_modules/@comis/memory/dist/memory-api.js +1 -1
  205. package/node_modules/@comis/memory/dist/oauth-profile-schema.d.ts +17 -0
  206. package/node_modules/@comis/memory/dist/oauth-profile-schema.js +33 -0
  207. package/node_modules/@comis/memory/dist/oauth-profile-store-encrypted.d.ts +27 -0
  208. package/node_modules/@comis/memory/dist/oauth-profile-store-encrypted.js +144 -0
  209. package/node_modules/@comis/memory/dist/session-store.d.ts +1 -1
  210. package/node_modules/@comis/memory/dist/session-store.js +1 -1
  211. package/node_modules/@comis/memory/dist/sqlite-secret-store.d.ts +29 -3
  212. package/node_modules/@comis/memory/dist/sqlite-secret-store.js +11 -3
  213. package/node_modules/@comis/memory/package.json +1 -1
  214. package/node_modules/@comis/scheduler/dist/execution/execution-lock.d.ts +13 -0
  215. package/node_modules/@comis/scheduler/dist/execution/execution-lock.js +1 -1
  216. package/node_modules/@comis/scheduler/dist/execution/index.d.ts +2 -0
  217. package/node_modules/@comis/scheduler/dist/execution/index.js +2 -0
  218. package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.js +1 -1
  219. package/node_modules/@comis/scheduler/dist/index.d.ts +2 -0
  220. package/node_modules/@comis/scheduler/dist/index.js +2 -0
  221. package/node_modules/@comis/scheduler/package.json +1 -1
  222. package/node_modules/@comis/shared/package.json +1 -1
  223. package/node_modules/@comis/skills/dist/bridge/schema-validator.d.ts +38 -0
  224. package/node_modules/@comis/skills/dist/bridge/schema-validator.js +169 -0
  225. package/node_modules/@comis/skills/dist/bridge/tool-metadata-enforcement.js +12 -0
  226. package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +130 -0
  227. package/node_modules/@comis/skills/dist/builtin/exec-diagnostics.d.ts +32 -0
  228. package/node_modules/@comis/skills/dist/builtin/exec-diagnostics.js +127 -0
  229. package/node_modules/@comis/skills/dist/builtin/exec-security.js +38 -0
  230. package/node_modules/@comis/skills/dist/builtin/exec-tool.js +9 -0
  231. package/node_modules/@comis/skills/dist/builtin/file-tools/grep-tool.js +6 -6
  232. package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +5 -4
  233. package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +38 -27
  234. package/node_modules/@comis/skills/dist/builtin/platform/background-tasks-tool.d.ts +4 -1
  235. package/node_modules/@comis/skills/dist/builtin/platform/background-tasks-tool.js +3 -3
  236. package/node_modules/@comis/skills/dist/builtin/platform/cron-tool.js +1 -1
  237. package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.js +6 -6
  238. package/node_modules/@comis/skills/dist/builtin/platform/mcp-manage-tool.d.ts +1 -1
  239. package/node_modules/@comis/skills/dist/builtin/platform/mcp-manage-tool.js +9 -9
  240. package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.d.ts +11 -0
  241. package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.js +114 -1
  242. package/node_modules/@comis/skills/dist/builtin/sandbox/detect-provider.js +40 -15
  243. package/node_modules/@comis/skills/dist/media/ssrf-fetcher.d.ts +7 -0
  244. package/node_modules/@comis/skills/dist/media/ssrf-fetcher.js +9 -2
  245. package/node_modules/@comis/skills/package.json +1 -1
  246. package/node_modules/@comis/web/dist/assets/{agent-detail-71BSbSfD.js → agent-detail-q8t1NB7w.js} +1 -1
  247. package/node_modules/@comis/web/dist/assets/{agent-editor-CTSDZhwT.js → agent-editor-B46io5gv.js} +1 -1
  248. package/node_modules/@comis/web/dist/assets/{agent-list-BEhni2ea.js → agent-list-DQ6g2Rcx.js} +1 -1
  249. package/node_modules/@comis/web/dist/assets/{billing-view-DVP1IvVs.js → billing-view-IWPR8LgF.js} +1 -1
  250. package/node_modules/@comis/web/dist/assets/{channel-detail-N_YK74xC.js → channel-detail-DlNNZuuC.js} +1 -1
  251. package/node_modules/@comis/web/dist/assets/{channel-list-DRk6ZJaF.js → channel-list-DhGwxiMc.js} +1 -1
  252. package/node_modules/@comis/web/dist/assets/{chat-console-Dm-GtSf9.js → chat-console-Nv6fM3Rc.js} +1 -1
  253. package/node_modules/@comis/web/dist/assets/{config-editor-CIferYX6.js → config-editor-BYKuJF76.js} +1 -1
  254. package/node_modules/@comis/web/dist/assets/{context-dag-browser-CL84rXXM.js → context-dag-browser-ClNEtzYE.js} +1 -1
  255. package/node_modules/@comis/web/dist/assets/{context-engine-B1HOTEZv.js → context-engine-BZJ6HChd.js} +1 -1
  256. package/node_modules/@comis/web/dist/assets/{delivery-view-Y6JKYVFw.js → delivery-view-Cb7I3vGu.js} +1 -1
  257. package/node_modules/@comis/web/dist/assets/{diagnostics-view-DWV1UQjz.js → diagnostics-view-9u9Lyu5a.js} +1 -1
  258. package/node_modules/@comis/web/dist/assets/{ic-chat-message-DfSERzzg.js → ic-chat-message-BFt3cVpx.js} +1 -1
  259. package/node_modules/@comis/web/dist/assets/{ic-connection-dot-CXyhlJup.js → ic-connection-dot-y77LZ3Gu.js} +1 -1
  260. package/node_modules/@comis/web/dist/assets/{ic-tool-call-DNmwTjek.js → ic-tool-call-qt6w1NQl.js} +1 -1
  261. package/node_modules/@comis/web/dist/assets/{index-CBr0Tm9_.js → index-8Tg9oc-C.js} +2 -2
  262. package/node_modules/@comis/web/dist/assets/{mcp-management-BaH2-vox.js → mcp-management-69dtH_kY.js} +2 -2
  263. package/node_modules/@comis/web/dist/assets/{media-config-CZLshJoN.js → media-config-BdjLj5c1.js} +1 -1
  264. package/node_modules/@comis/web/dist/assets/{media-test-C9NUWgo_.js → media-test-DuPqrixi.js} +1 -1
  265. package/node_modules/@comis/web/dist/assets/{memory-inspector-D_fmTcRN.js → memory-inspector-B-Pepbq-.js} +1 -1
  266. package/node_modules/@comis/web/dist/assets/{message-center-BBFlNCZn.js → message-center-B7l0yNYY.js} +1 -1
  267. package/node_modules/@comis/web/dist/assets/{models-BytGLm99.js → models-JHFHuv5S.js} +1 -1
  268. package/node_modules/@comis/web/dist/assets/{observe-view-VXtHqaqq.js → observe-view-r8mqhy4O.js} +1 -1
  269. package/node_modules/@comis/web/dist/assets/{pipeline-builder-CfXczlfJ.js → pipeline-builder-XjkiZRcR.js} +1 -1
  270. package/node_modules/@comis/web/dist/assets/{pipeline-history-CPmXFnbe.js → pipeline-history-CZqJv_Hj.js} +1 -1
  271. package/node_modules/@comis/web/dist/assets/{pipeline-history-detail-DcueTMs9.js → pipeline-history-detail-BEFGMoDy.js} +1 -1
  272. package/node_modules/@comis/web/dist/assets/{pipeline-list-B-xG5WZh.js → pipeline-list-B6q5LvO1.js} +1 -1
  273. package/node_modules/@comis/web/dist/assets/{pipeline-monitor-pnIOYaSY.js → pipeline-monitor-BNomXjVL.js} +1 -1
  274. package/node_modules/@comis/web/dist/assets/{scheduler-BtUIFHhA.js → scheduler-BJEjcGKA.js} +1 -1
  275. package/node_modules/@comis/web/dist/assets/{security-C8mWRq2y.js → security-2G1jhBfV.js} +1 -1
  276. package/node_modules/@comis/web/dist/assets/{session-detail-DgdkO5ka.js → session-detail-DmVPzFBR.js} +1 -1
  277. package/node_modules/@comis/web/dist/assets/{session-list-DcylcfTn.js → session-list-CsqMQoHs.js} +1 -1
  278. package/node_modules/@comis/web/dist/assets/{setup-wizard-BP5yjsuL.js → setup-wizard-CAdM-gSP.js} +1 -1
  279. package/node_modules/@comis/web/dist/assets/{skills-DXt1bX8Z.js → skills-2ODqKaWr.js} +1 -1
  280. package/node_modules/@comis/web/dist/assets/{subagents-C7YbUHXY.js → subagents-BFlwfTbD.js} +1 -1
  281. package/node_modules/@comis/web/dist/assets/{workspace-manager-DP6pW4wa.js → workspace-manager--CbOx_dI.js} +1 -1
  282. package/node_modules/@comis/web/dist/index.html +1 -1
  283. package/node_modules/@comis/web/package.json +1 -1
  284. package/package.json +17 -16
@@ -0,0 +1,151 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Background completion runner: subscribes to background_task:completed and
4
+ * background_task:failed events from the TypedEventBus and re-enters the
5
+ * originating agent session with a formatted completion announcement.
6
+ *
7
+ * Per-session lock serialization is delegated to the existing session
8
+ * manager (ComisSessionManager.withSession in packages/agent/src/session/).
9
+ * The runner does NOT introduce its own queueing -- one turn per completion
10
+ * event, ordering follows the existing per-session lock.
11
+ *
12
+ * Recursion bound: per-task incoming hop count + 1 must stay below
13
+ * `maxBackgroundHops` (default 3). When the cap is hit, the runner emits
14
+ * the fallback notification instead of triggering executor.execute().
15
+ * The hop count is read from `task.origin.backgroundHopCount`
16
+ * (populated by the originResolver).
17
+ *
18
+ * Latency-instrumentation hook: emits `background_task:reentered`
19
+ * immediately before executor.execute(). Integration tests compute the delta
20
+ * from `background_task:completed.timestamp` to this event for SLO tracking.
21
+ *
22
+ * Failure isolation: each handler is wrapped in suppressError so a single
23
+ * completion's failure does not tear down the subscription (AGENTS §2.1).
24
+ *
25
+ * @module
26
+ */
27
+ import { randomUUID } from "node:crypto";
28
+ import { suppressError } from "@comis/shared";
29
+ import { parseFormattedSessionKey } from "@comis/core";
30
+ import { formatCompletionAnnouncement } from "./completion-formatter.js";
31
+ /**
32
+ * Wire the completion runner against an event bus + executor + session store.
33
+ * Subscriptions are installed synchronously; call shutdown() to remove them.
34
+ */
35
+ export function createBackgroundCompletionRunner(deps) {
36
+ const log = deps.logger.child({ submodule: "background-completion-runner" });
37
+ let stopped = false;
38
+ let inflight = Promise.resolve();
39
+ const onCompleted = (data) => {
40
+ if (stopped)
41
+ return;
42
+ const promise = handleEvent(data.taskId, "completed");
43
+ inflight = inflight.then(() => promise).catch(() => undefined);
44
+ suppressError(promise, "background completion handler (completed)");
45
+ };
46
+ const onFailed = (data) => {
47
+ if (stopped)
48
+ return;
49
+ const promise = handleEvent(data.taskId, "failed");
50
+ inflight = inflight.then(() => promise).catch(() => undefined);
51
+ suppressError(promise, "background completion handler (failed)");
52
+ };
53
+ deps.eventBus.on("background_task:completed", onCompleted);
54
+ deps.eventBus.on("background_task:failed", onFailed);
55
+ async function handleEvent(taskId, kind) {
56
+ const task = deps.taskManager.getTask(taskId);
57
+ if (!task) {
58
+ log.warn({ taskId, kind, hint: "Task disappeared from manager before runner could resolve it; no announcement injected", errorKind: "internal" }, "Background completion: task not in manager");
59
+ return;
60
+ }
61
+ // Legacy task without origin -- emit fallback, keep file for audit.
62
+ const origin = task.origin;
63
+ if (!origin || !origin.sessionKey || !origin.agentId) {
64
+ await fallbackForTask(task.toolName, task.origin?.agentId ?? "default", `Background task "${task.toolName}" completed.`);
65
+ return;
66
+ }
67
+ // Hop cap. Read incoming hop count from origin (schema field populated
68
+ // by the originResolver).
69
+ const nextHopCount = (origin.backgroundHopCount ?? 0) + 1;
70
+ if (nextHopCount >= deps.maxBackgroundHops) {
71
+ log.info({ taskId, toolName: task.toolName, agentId: origin.agentId, hopCount: nextHopCount, max: deps.maxBackgroundHops }, "Background completion: hop cap reached, falling back to user notification");
72
+ await fallbackForTask(task.toolName, origin.agentId, `Background task "${task.toolName}" completed but follow-up was skipped — recursion limit reached. Run again or check the result manually.`);
73
+ return;
74
+ }
75
+ // Missing session -- session expired while the task ran. No channel to deliver
76
+ // to, so skip fallback (which would only produce a WARN from notification-service).
77
+ const sessionExists = deps.sessionStore.loadByFormattedKey(origin.sessionKey) !== undefined;
78
+ if (!sessionExists) {
79
+ log.info({ taskId, sessionKey: origin.sessionKey }, "Background completion: session expired, skipping re-entry");
80
+ return;
81
+ }
82
+ // Reconstruct the SessionKey object for executor.execute().
83
+ const parsedKey = parseFormattedSessionKey(origin.sessionKey);
84
+ if (!parsedKey) {
85
+ log.warn({ taskId, sessionKey: origin.sessionKey, hint: "Persisted sessionKey is malformed; cannot route announcement", errorKind: "internal" }, "Background completion: invalid sessionKey");
86
+ await fallbackForTask(task.toolName, origin.agentId, `Background task "${task.toolName}" completed (routing failed).`);
87
+ return;
88
+ }
89
+ // Format the announcement (byte-identical trailing instruction).
90
+ const announcement = formatCompletionAnnouncement(task);
91
+ // Construct the synthetic NormalizedMessage (hop counter in metadata).
92
+ const syntheticMsg = {
93
+ id: randomUUID(),
94
+ channelId: origin.channelId,
95
+ channelType: "background_task",
96
+ senderId: "background-task-runner",
97
+ text: announcement,
98
+ timestamp: Date.now(),
99
+ attachments: [],
100
+ metadata: {
101
+ backgroundHopCount: nextHopCount,
102
+ backgroundTaskId: task.id,
103
+ toolName: task.toolName,
104
+ agentId: origin.agentId,
105
+ traceId: origin.traceId ?? undefined,
106
+ },
107
+ };
108
+ log.debug({ taskId, sessionKey: origin.sessionKey, agentId: origin.agentId, toolName: task.toolName, hopCount: nextHopCount }, "Background completion runner: invoking executor");
109
+ // Emit background_task:reentered immediately before executor.execute().
110
+ // Integration tests compute p95 latency from
111
+ // background_task:completed.timestamp to this event's timestamp.
112
+ deps.eventBus.emit("background_task:reentered", {
113
+ taskId: task.id,
114
+ agentId: origin.agentId,
115
+ sessionKey: origin.sessionKey,
116
+ hopCount: nextHopCount,
117
+ timestamp: Date.now(),
118
+ });
119
+ // One turn per event. Existing session lock orders concurrent calls.
120
+ try {
121
+ await deps.getExecutor(origin.agentId).execute(syntheticMsg, parsedKey, undefined, undefined, origin.agentId);
122
+ }
123
+ catch (err) {
124
+ log.warn({ taskId, err, hint: "Executor failed mid-completion turn; subscription remains active", errorKind: "internal" }, "Background completion: executor.execute() rejected");
125
+ }
126
+ }
127
+ async function fallbackForTask(toolName, agentId, message) {
128
+ try {
129
+ await deps.fallbackNotifyFn({
130
+ agentId,
131
+ message,
132
+ priority: "normal",
133
+ origin: "background_task",
134
+ });
135
+ }
136
+ catch (err) {
137
+ log.warn({ toolName, agentId, err, hint: "fallbackNotifyFn rejected; user will not see the completion notification for this task", errorKind: "internal" }, "Background completion: fallbackNotifyFn rejected");
138
+ }
139
+ }
140
+ return {
141
+ async shutdown() {
142
+ if (stopped)
143
+ return;
144
+ stopped = true;
145
+ deps.eventBus.off("background_task:completed", onCompleted);
146
+ deps.eventBus.off("background_task:failed", onFailed);
147
+ // Wait for any in-flight handler to settle before returning.
148
+ await inflight;
149
+ },
150
+ };
151
+ }
@@ -4,8 +4,12 @@
4
4
  * @module
5
5
  */
6
6
  export type { BackgroundTask, BackgroundTaskStatus, PersistedTaskState } from "./background-task-types.js";
7
+ export type { BackgroundTaskOrigin } from "@comis/core";
7
8
  export { persistTaskSync, loadTask, recoverTasks, removeTaskFile, TASK_DIR_NAME, } from "./background-task-persistence.js";
8
9
  export { createBackgroundTaskManager, } from "./background-task-manager.js";
9
10
  export type { BackgroundTaskManager, BackgroundTaskManagerOpts, NotifyFn, } from "./background-task-manager.js";
10
11
  export { wrapToolForAutoBackground, } from "./auto-background-middleware.js";
11
12
  export type { ToolDefinition, } from "./auto-background-middleware.js";
13
+ export { formatCompletionAnnouncement, TRAILING_INSTRUCTION } from "./completion-formatter.js";
14
+ export { createBackgroundCompletionRunner } from "./completion-runner.js";
15
+ export type { BackgroundCompletionRunner, BackgroundCompletionRunnerDeps, RunnerSessionStore, } from "./completion-runner.js";
@@ -7,3 +7,5 @@
7
7
  export { persistTaskSync, loadTask, recoverTasks, removeTaskFile, TASK_DIR_NAME, } from "./background-task-persistence.js";
8
8
  export { createBackgroundTaskManager, } from "./background-task-manager.js";
9
9
  export { wrapToolForAutoBackground, } from "./auto-background-middleware.js";
10
+ export { formatCompletionAnnouncement, TRAILING_INSTRUCTION } from "./completion-formatter.js";
11
+ export { createBackgroundCompletionRunner } from "./completion-runner.js";
@@ -58,12 +58,23 @@ export interface BridgeMetricsState {
58
58
  totalThinkingTokens: number;
59
59
  budgetWarningEmitted: boolean;
60
60
  thinkingBlockHashes: Map<string, ThinkingBlockHash[]>;
61
- /** 260428-hoy: Canonical (pre-mutation) snapshot of each assistant message's
62
- * full content array, captured at stream close in lockstep with thinkingBlockHashes.
61
+ /** Canonical (pre-mutation) snapshot of each assistant message's full
62
+ * content array, captured at stream close in lockstep with thinkingBlockHashes.
63
63
  * Keyed by responseId; capped at 32 with FIFO eviction in lockstep with the
64
64
  * hash store. Used by the pre-LLM-call restoration pass to heal cross-turn
65
65
  * mutation of signed thinking blocks before pi-ai serializes the next request. */
66
66
  thinkingBlockCanonical: Map<string, ReadonlyArray<unknown>>;
67
+ /** Number of pre-LLM-call hash-assertion walks performed (one per turn_start). */
68
+ hashAssertionsRan: number;
69
+ /** Total cross-turn thinking-block hash mismatches surfaced across all walks. */
70
+ hashAssertionMismatches: number;
71
+ /** Number of signature-replay scrubber invocations that scrubbed at least one
72
+ * assistant message in this execute(). Populated via ceSetup.getSignatureScrubCounters
73
+ * in executor-post-execution; surfaced here for symmetry / future bridge-side use. */
74
+ signatureScrubs: number;
75
+ /** Total tool calls across all signature-replay scrubs whose thoughtSignature
76
+ * was stripped (post-incident-visibility metric). */
77
+ signatureScrubsToolCallsAffected: number;
67
78
  }
68
79
  /**
69
80
  * Create a fresh metrics state with all counters zeroed.
@@ -100,4 +111,8 @@ export declare function buildBridgeResult(metrics: BridgeMetricsState, stepCount
100
111
  sessionCacheSavedUsd?: number;
101
112
  thinkingTokens?: number;
102
113
  budgetWarningEmitted?: boolean;
114
+ hashAssertionsRan?: number;
115
+ hashAssertionMismatches?: number;
116
+ signatureScrubs?: number;
117
+ signatureScrubsToolCallsAffected?: number;
103
118
  };
@@ -53,6 +53,11 @@ export function createBridgeMetrics() {
53
53
  budgetWarningEmitted: false,
54
54
  thinkingBlockHashes: new Map(),
55
55
  thinkingBlockCanonical: new Map(),
56
+ // per-execute diagnostic counters
57
+ hashAssertionsRan: 0,
58
+ hashAssertionMismatches: 0,
59
+ signatureScrubs: 0,
60
+ signatureScrubsToolCallsAffected: 0,
56
61
  };
57
62
  }
58
63
  /**
@@ -95,12 +100,19 @@ export function buildBridgeResult(metrics, stepCount) {
95
100
  lastStopReason: metrics.lastStopReason,
96
101
  cacheWrite5mTokens: metrics.totalCacheWrite5mTokens,
97
102
  cacheWrite1hTokens: metrics.totalCacheWrite1hTokens,
98
- // 1.3: Session-cumulative cost fields
103
+ // Session-cumulative cost fields
99
104
  sessionCostUsd: metrics.sessionCumulativeCostUsd,
100
105
  sessionCacheSavedUsd: metrics.sessionCumulativeCacheSavedUsd,
101
- // 1.5: Thinking tokens (omitted when 0 to avoid log noise)
106
+ // Thinking tokens (omitted when 0 to avoid log noise)
102
107
  thinkingTokens: metrics.totalThinkingTokens > 0 ? metrics.totalThinkingTokens : undefined,
103
108
  // Budget trajectory warning flag
104
109
  budgetWarningEmitted: metrics.budgetWarningEmitted || undefined,
110
+ // Per-execute diagnostic counters. Always populated (no `> 0` gate) — a
111
+ // `0` in the bookend log is itself meaningful ("no scrubs/assertions
112
+ // this execute") and gating would lose that signal.
113
+ hashAssertionsRan: metrics.hashAssertionsRan,
114
+ hashAssertionMismatches: metrics.hashAssertionMismatches,
115
+ signatureScrubs: metrics.signatureScrubs,
116
+ signatureScrubsToolCallsAffected: metrics.signatureScrubsToolCallsAffected,
105
117
  };
106
118
  }
@@ -54,7 +54,7 @@ export interface PiEventBridgeDeps {
54
54
  * internal retry. Rate-limit windows are per-minute (longer than the SDK's
55
55
  * ~30s retry budget), so retrying within the window cannot succeed.
56
56
  * Non-`rate_limited` retryable errors (overloaded, network, 5xx) bypass this
57
- * hook -- the SDK's normal retry-with-backoff proceeds. (260501-dkl) */
57
+ * hook -- the SDK's normal retry-with-backoff proceeds. */
58
58
  onAbortRetry?: () => void;
59
59
  /** SDK context usage accessor -- returns live context metrics from AgentSession. */
60
60
  getContextUsage?: () => ContextUsageData | undefined;
@@ -106,7 +106,7 @@ export interface PiEventBridgeDeps {
106
106
  sepMessageText?: string;
107
107
  /** Execution start timestamp for SEP timing metrics. */
108
108
  sepExecutionStartMs?: number;
109
- /** Cache break detection Phase 2 callback. Returns CacheBreakEvent if break detected. */
109
+ /** Cache break detection callback. Returns CacheBreakEvent if break detected. */
110
110
  checkCacheBreak?: (input: {
111
111
  sessionKey: string;
112
112
  provider: string;
@@ -130,27 +130,27 @@ export interface PiEventBridgeDeps {
130
130
  graphId?: string;
131
131
  /** Graph node ID for cache write signal emission. Set only for graph subagents. */
132
132
  nodeId?: string;
133
- /** + 49-01: Shared mutable TTL split estimate. Populated by request-body-injector
133
+ /** Shared mutable TTL split estimate. Populated by request-body-injector
134
134
  * on each API call, read by the bridge on turn_end for per-TTL cost calculation.
135
135
  * The bridge normalizes these estimates against the actual SDK-reported cacheWriteTokens. */
136
136
  ttlSplit?: TtlSplitEstimate;
137
- /** 260428-hoy pre-call hook: invoked once per `turn_start` event, BEFORE
138
- * pi-ai serializes the next request. The closure (defined in pi-executor)
139
- * walks `session.agent.state.messages`, asserts the cross-turn
140
- * hash-invariant per assistant message with a stored hash entry (logs
141
- * ERROR on mutation), then runs the canonical-restore helper against the
142
- * canonical store (heals any mutation in-place by writing the result
143
- * back to `session.agent.state.messages`). The return value is unused by
144
- * the bridge -- the side effect is the heal write-back. Optional: when
137
+ /** Pre-call hook: invoked once per `turn_start` event, BEFORE pi-ai
138
+ * serializes the next request. The closure (defined in pi-executor) walks
139
+ * `session.agent.state.messages`, asserts the cross-turn hash-invariant
140
+ * per assistant message with a stored hash entry (logs ERROR on mutation),
141
+ * then runs the canonical-restore helper against the canonical store
142
+ * (heals any mutation in-place by writing the result back to
143
+ * `session.agent.state.messages`). The return value is unused by the
144
+ * bridge -- the side effect is the heal write-back. Optional: when
145
145
  * omitted, both the diagnostic and the heal are silently disabled
146
146
  * (e.g., unit tests that don't drive a full agent session). */
147
147
  getSessionMessages?: () => ReadonlyArray<unknown> | undefined;
148
- /** 260428-iag wire-edge diagnostic: returns the absolute path to the
149
- * per-session JSONL on disk. The bridge invokes this only when the LLM
150
- * error path detects the signed-replay rejection signature, then
151
- * diff'd against the persisted canonical to surface mutation that
152
- * occurred AFTER the bridge's restoration hook. Optional — when
153
- * omitted, the wire-edge diagnostic is a silent no-op. */
148
+ /** Wire-edge diagnostic: returns the absolute path to the per-session JSONL
149
+ * on disk. The bridge invokes this only when the LLM error path detects
150
+ * the signed-replay rejection signature, then diff'd against the persisted
151
+ * canonical to surface mutation that occurred AFTER the bridge's
152
+ * restoration hook. Optional — when omitted, the wire-edge diagnostic is
153
+ * a silent no-op. */
154
154
  getSessionJsonlPath?: () => string | null;
155
155
  }
156
156
  /** Estimated cost payload for a timed-out API request. */
@@ -193,12 +193,12 @@ export interface PiEventBridgeResult {
193
193
  };
194
194
  /** Accumulate estimated cost from a timed-out API request. */
195
195
  addGhostCost: (estimated: GhostCostEstimate) => void;
196
- /** 260428-hoy: ReadonlyMap views of the per-responseId hash store and
197
- * canonical-snapshot store, both populated at stream-close in lockstep.
198
- * The executor's pre-LLM-call closure reads both stores to drive the
199
- * hash-invariant assertion plus the canonical restore helper. Returns
200
- * ReadonlyMap views to preserve internal-state encapsulation -- the
201
- * underlying `m` object is never exported. */
196
+ /** ReadonlyMap views of the per-responseId hash store and canonical-snapshot
197
+ * store, both populated at stream-close in lockstep. The executor's
198
+ * pre-LLM-call closure reads both stores to drive the hash-invariant
199
+ * assertion plus the canonical restore helper. Returns ReadonlyMap views
200
+ * to preserve internal-state encapsulation -- the underlying `m` object is
201
+ * never exported. */
202
202
  getThinkingBlockStores: () => {
203
203
  hashes: ReadonlyMap<string, ReadonlyArray<ThinkingBlockHash>>;
204
204
  canonical: ReadonlyMap<string, ReadonlyArray<unknown>>;
@@ -186,7 +186,7 @@ export function createPiEventBridge(deps) {
186
186
  ...(truncMeta && { truncated: truncMeta.truncated, fullChars: truncMeta.fullChars, returnedChars: truncMeta.returnedChars }),
187
187
  });
188
188
  // Reset prompt timeout after each tool completion so slow tools
189
- // do not starve subsequent LLM turns (Quick 215).
189
+ // do not starve subsequent LLM turns.
190
190
  deps.onToolExecutionEnd?.();
191
191
  // Safety: check step limit (delegated to bridge-safety-controls)
192
192
  {
@@ -222,20 +222,20 @@ export function createPiEventBridge(deps) {
222
222
  // LLM turn about to start (pre-serialize hook for assert+restore)
223
223
  // -----------------------------------------------------------------
224
224
  case "turn_start": {
225
- // 260428-hoy: Run the executor-supplied pre-call closure once per
226
- // turn, before pi-ai reads `session.agent.state.messages` to
227
- // serialize the next API request. The closure performs the
228
- // assert-then-restore pass over the live transcript and writes the
229
- // healed array back into session state when at least one swap
230
- // happens, so the bytes Anthropic sees match the canonical
231
- // stream-close snapshot. The closure swallows its own throws; the
232
- // wrapper here is belt-and-braces.
225
+ // Run the executor-supplied pre-call closure once per turn, before
226
+ // pi-ai reads `session.agent.state.messages` to serialize the next
227
+ // API request. The closure performs the assert-then-restore pass
228
+ // over the live transcript and writes the healed array back into
229
+ // session state when at least one swap happens, so the bytes
230
+ // Anthropic sees match the canonical stream-close snapshot. The
231
+ // closure swallows its own throws; the wrapper here is
232
+ // belt-and-braces.
233
233
  //
234
- // 260428-j0v: ALWAYS emit ONE INFO log carrying the counters the
235
- // bridge can derive — even when the closure is unwired or returns
236
- // undefined / no candidates. This closes the silent-success
237
- // ambiguity observed on trace c5680133 where ZERO agent.bridge.*
238
- // events appeared despite the helpers having shipped.
234
+ // ALWAYS emit ONE INFO log carrying the counters the bridge can
235
+ // derive — even when the closure is unwired or returns undefined /
236
+ // no candidates. This closes the silent-success ambiguity where
237
+ // ZERO agent.bridge.* events appeared despite the helpers having
238
+ // shipped.
239
239
  //
240
240
  // Counters are computed by the bridge's own walk of the messages
241
241
  // returned by the closure (or empty when unwired) so the executor
@@ -289,15 +289,27 @@ export function createPiEventBridge(deps) {
289
289
  // implementation; surfaced as a separate field so future asymmetric
290
290
  // assert/restore semantics are observable.
291
291
  const restoredCount = mismatchesLogged;
292
- deps.logger.info({
293
- module: "agent.bridge.hash-invariant",
292
+ m.hashAssertionsRan++;
293
+ m.hashAssertionMismatches += mismatchesLogged;
294
+ const hashAssertionPayload = {
295
+ submodule: "bridge.hash-invariant",
294
296
  candidatesChecked,
295
297
  mismatchesLogged,
296
298
  restoredCount,
297
299
  anyResponseIdMatched,
298
300
  hashStoreSize,
299
301
  canonicalStoreSize,
300
- }, "Pre-call assertion ran");
302
+ };
303
+ if (mismatchesLogged > 0) {
304
+ deps.logger.warn({
305
+ ...hashAssertionPayload,
306
+ hint: "Cross-turn thinking-block mutation detected; pre-call restore pass will heal before next API serialize. Investigate if this fires repeatedly without the heal succeeding (canonicalStoreSize === 0).",
307
+ errorKind: "internal",
308
+ }, "Pre-call assertion ran");
309
+ }
310
+ else {
311
+ deps.logger.debug(hashAssertionPayload, "Pre-call assertion ran");
312
+ }
301
313
  break;
302
314
  }
303
315
  // -----------------------------------------------------------------
@@ -337,14 +349,14 @@ export function createPiEventBridge(deps) {
337
349
  thinkingLen: typeof b.thinking === "string" ? b.thinking.length : 0,
338
350
  })),
339
351
  }, "Assistant message block accounting at stream close");
340
- // Bug A diagnostic + 260428-hoy heal: capture hashes AND a
341
- // canonical (pre-mutation) snapshot of the full content array,
342
- // keyed by responseId, in lockstep across both stores. The
343
- // hash store powers the assertion ERROR log (mutation
344
- // diagnostic); the canonical store powers the pre-call
345
- // restore pass that heals cross-turn mutation before the next
346
- // API serialize. Both stores are FIFO-evicted at 32 entries
347
- // in lockstep so they always share the same keyset.
352
+ // Diagnostic + heal: capture hashes AND a canonical (pre-mutation)
353
+ // snapshot of the full content array, keyed by responseId, in
354
+ // lockstep across both stores. The hash store powers the
355
+ // assertion ERROR log (mutation diagnostic); the canonical
356
+ // store powers the pre-call restore pass that heals cross-turn
357
+ // mutation before the next API serialize. Both stores are
358
+ // FIFO-evicted at 32 entries in lockstep so they always share
359
+ // the same keyset.
348
360
  if (typeof responseIdForLog === "string") {
349
361
  const hashes = computeThinkingBlockHashes(blocks);
350
362
  if (hashes.length > 0) {
@@ -356,11 +368,11 @@ export function createPiEventBridge(deps) {
356
368
  m.thinkingBlockCanonical.delete(oldestKey);
357
369
  }
358
370
  m.thinkingBlockHashes.set(responseIdForLog, hashes);
359
- // 260428-hoy: capture canonical (pre-mutation) full
360
- // content array so the pre-LLM-call restore pass can heal
361
- // any cross-turn mutation before pi-ai serializes the
362
- // next request. structuredClone is a Node 22 global; the
363
- // try/catch is defensive against rare exotic input shapes.
371
+ // Capture canonical (pre-mutation) full content array so
372
+ // the pre-LLM-call restore pass can heal any cross-turn
373
+ // mutation before pi-ai serializes the next request.
374
+ // structuredClone is a Node 22 global; the try/catch is
375
+ // defensive against rare exotic input shapes.
364
376
  try {
365
377
  const canonical = Object.freeze(structuredClone(blocks));
366
378
  m.thinkingBlockCanonical.set(responseIdForLog, canonical);
@@ -382,7 +394,7 @@ export function createPiEventBridge(deps) {
382
394
  const llmLatencyMs = turnWallclockMs - effectiveTurnToolMs;
383
395
  m.cumulativeLlmDurationMs += llmLatencyMs;
384
396
  m.turnToolDurationMs = 0;
385
- // R-04: Extract responseId from assistant message (optional -- not all providers supply it)
397
+ // Extract responseId from assistant message (optional -- not all providers supply it)
386
398
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- SDK interop boundary
387
399
  const responseId = assistantMsg?.responseId;
388
400
  if (assistantMsg && "usage" in assistantMsg && assistantMsg.usage) {
@@ -421,7 +433,7 @@ export function createPiEventBridge(deps) {
421
433
  if (deps.onTurnWithCacheWrite) {
422
434
  deps.onTurnWithCacheWrite(cacheWriteTokens);
423
435
  }
424
- // Cache break detection Phase 2 (all providers, unconditional)
436
+ // Cache break detection (all providers, unconditional)
425
437
  // MUST NOT guard with cacheReadTokens > 0 -- complete cache misses (drop to 0) must be detected
426
438
  if (deps.checkCacheBreak) {
427
439
  // Detect API errors -- zero usage with error stop reason
@@ -451,7 +463,7 @@ export function createPiEventBridge(deps) {
451
463
  }
452
464
  }
453
465
  }
454
- // R-08: Extract cacheCreation breakdown (future upstream -- runtime check)
466
+ // Extract cacheCreation breakdown (future upstream -- runtime check)
455
467
  const rawUsage = usage;
456
468
  const cacheCreation = rawUsage.cacheCreation && typeof rawUsage.cacheCreation === "object"
457
469
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- SDK interop boundary
@@ -472,7 +484,7 @@ export function createPiEventBridge(deps) {
472
484
  }
473
485
  // Record usage in budget guard (token-based, not cost-based -- stays before correction)
474
486
  deps.budgetGuard.recordUsage(usage.totalTokens);
475
- // 49-01 + COST-FIX ordering: Normalize TTL split estimates BEFORE cost correction.
487
+ // COST-FIX ordering: Normalize TTL split estimates BEFORE cost correction.
476
488
  // The injector provides raw per-TTL estimates; normalize so they sum to the
477
489
  // SDK-reported total (eliminates the 28% estimation error).
478
490
  // Mutate in-place so per-TTL cost and accumulation use normalized values.
@@ -551,10 +563,10 @@ export function createPiEventBridge(deps) {
551
563
  if (deps.onTurnCacheSavings) {
552
564
  deps.onTurnCacheSavings(savedVsUncached);
553
565
  }
554
- // 1.3: Accumulate session-cumulative costs alongside per-turn values
566
+ // Accumulate session-cumulative costs alongside per-turn values
555
567
  m.sessionCumulativeCostUsd += cost.total;
556
568
  m.sessionCumulativeCacheSavedUsd += savedVsUncached;
557
- // 1.5: Track thinking tokens from SDK usage object.
569
+ // Track thinking tokens from SDK usage object.
558
570
  // The pi-ai SDK Usage type does not have a dedicated thinking/reasoning field,
559
571
  // but future versions or raw API responses may include `reasoningTokens`.
560
572
  // Runtime-check the raw usage object for this field.
@@ -567,9 +579,9 @@ export function createPiEventBridge(deps) {
567
579
  m.totalThinkingTokens += sdkThinkingTokens;
568
580
  }
569
581
  }
570
- // 49-01: Populate cacheCreation from bridge metrics TTL split when SDK doesn't provide it.
571
- // SDK-sourced cacheCreation (from R-08 extraction) takes priority; bridge metrics
572
- // provide the fallback when pi-ai doesn't surface per-TTL breakdown.
582
+ // Populate cacheCreation from bridge metrics TTL split when SDK doesn't provide it.
583
+ // SDK-sourced cacheCreation takes priority; bridge metrics provide the fallback
584
+ // when pi-ai doesn't surface per-TTL breakdown.
573
585
  const effectiveCacheCreation = cacheCreation ?? ((m.totalCacheWrite5mTokens > 0 || m.totalCacheWrite1hTokens > 0)
574
586
  ? { shortTtl: m.totalCacheWrite5mTokens, longTtl: m.totalCacheWrite1hTokens }
575
587
  : undefined);
@@ -844,7 +856,7 @@ export function createPiEventBridge(deps) {
844
856
  break;
845
857
  }
846
858
  // -----------------------------------------------------------------
847
- // SDK auto-retry loop: abort on rate_limited (260501-dkl)
859
+ // SDK auto-retry loop: abort on rate_limited
848
860
  // -----------------------------------------------------------------
849
861
  case "auto_retry_start": {
850
862
  const errorMessage = event.errorMessage ?? "";
@@ -854,7 +866,7 @@ export function createPiEventBridge(deps) {
854
866
  const classification = classifyError(new Error(errorMessage));
855
867
  if (classification.category === "rate_limited") {
856
868
  deps.logger.info({
857
- module: "agent.bridge.auto-retry-abort",
869
+ submodule: "bridge.auto-retry-abort",
858
870
  attempt,
859
871
  maxAttempts,
860
872
  delayMs,
@@ -884,20 +896,20 @@ export function createPiEventBridge(deps) {
884
896
  hint: "Check LLM provider status",
885
897
  errorKind: "dependency",
886
898
  }, "LLM call returned error");
887
- // 260428-iag wire-edge diagnostic: when the LLM error matches the
888
- // Anthropic signed-replay rejection signature ("thinking blocks ...
889
- // cannot be modified"), diff the in-memory content against the
890
- // persisted JSONL canonical and emit one ERROR per divergent block.
891
- // Fully async / fire-and-forget — never blocks the existing error
892
- // path. Silent no-op when the signature doesn't match or when
893
- // either getSessionMessages / getSessionJsonlPath is unwired.
899
+ // Wire-edge diagnostic: when the LLM error matches the Anthropic
900
+ // signed-replay rejection signature ("thinking blocks ... cannot
901
+ // be modified"), diff the in-memory content against the persisted
902
+ // JSONL canonical and emit one ERROR per divergent block. Fully
903
+ // async / fire-and-forget — never blocks the existing error path.
904
+ // Silent no-op when the signature doesn't match or when either
905
+ // getSessionMessages / getSessionJsonlPath is unwired.
894
906
  //
895
- // 260428-j0v: ALWAYS emit ONE dispatch-decision INFO log carrying
896
- // boolean flags that explain WHY the wire-diff dispatch was or was
897
- // not entered (regex match, candidate count, callback presence) —
898
- // even when regexMatched is false or callbacks are unwired. When
899
- // the dispatch IS entered, emit a second dispatch-completion INFO
900
- // after the async candidates loop completes.
907
+ // ALWAYS emit ONE dispatch-decision INFO log carrying boolean flags
908
+ // that explain WHY the wire-diff dispatch was or was not entered
909
+ // (regex match, candidate count, callback presence) — even when
910
+ // regexMatched is false or callbacks are unwired. When the dispatch
911
+ // IS entered, emit a second dispatch-completion INFO after the
912
+ // async candidates loop completes.
901
913
  //
902
914
  // The signature regex matches Anthropic's actual 400 message:
903
915
  // "messages.N.content.M: thinking blocks cannot be modified"
@@ -936,7 +948,7 @@ export function createPiEventBridge(deps) {
936
948
  }
937
949
  const jsonlPathPresent = typeof jsonlPathForDecision === "string" && jsonlPathForDecision.length > 0;
938
950
  deps.logger.info({
939
- module: "agent.bridge.wire-diff",
951
+ submodule: "bridge.wire-diff",
940
952
  regexMatched,
941
953
  candidatesFound: candidates.length,
942
954
  jsonlPathPresent,
@@ -969,7 +981,7 @@ export function createPiEventBridge(deps) {
969
981
  totalDivergences += entries.length;
970
982
  for (const entry of entries) {
971
983
  deps.logger.error({
972
- module: "agent.bridge.wire-diff",
984
+ submodule: "bridge.wire-diff",
973
985
  responseId: c.responseId,
974
986
  blockIndex: entry.blockIndex,
975
987
  persistedHash: entry.persistedHash,
@@ -991,7 +1003,7 @@ export function createPiEventBridge(deps) {
991
1003
  // ALWAYS emit the completion INFO, even on totalDivergences=0
992
1004
  // or when every helper call hit a read error.
993
1005
  deps.logger.info({
994
- module: "agent.bridge.wire-diff",
1006
+ submodule: "bridge.wire-diff",
995
1007
  candidatesProcessed,
996
1008
  totalDivergences,
997
1009
  persistedNotFound,
@@ -1031,9 +1043,9 @@ export function createPiEventBridge(deps) {
1031
1043
  m.ghostCostUsd += estimated.costUsd;
1032
1044
  m.timedOutRequests += 1;
1033
1045
  };
1034
- // 260428-hoy: typed ReadonlyMap accessor for the executor's pre-call
1035
- // closure. Returns views over the live maps -- the executor never receives
1036
- // the mutable `m` object itself.
1046
+ // Typed ReadonlyMap accessor for the executor's pre-call closure.
1047
+ // Returns views over the live maps -- the executor never receives the
1048
+ // mutable `m` object itself.
1037
1049
  const getThinkingBlockStores = () => ({
1038
1050
  hashes: m.thinkingBlockHashes,
1039
1051
  canonical: m.thinkingBlockCanonical,
@@ -3,9 +3,8 @@
3
3
  *
4
4
  * Observed problem: Anthropic 400 `messages.N.content.M: thinking/redacted_thinking
5
5
  * blocks cannot be modified` errors keep firing in production even after the
6
- * surrogate-guard, drift-scrubber, and signed-replay-detector layers shipped
7
- * (260425-rvm), and even after the immutable-section redirect (260425-t40).
8
- * Trace `c7b91328-9dc5-4618-9ae8-ca207b4b93df` on 2026-04-28 hit a 400 ~2.2s
6
+ * surrogate-guard, drift-scrubber, and signed-replay-detector layers shipped,
7
+ * and even after the immutable-section redirect. A trace hit a 400 ~2.2s
9
8
  * after `turn_end` -- meaning *some other layer* mutates a signed thinking
10
9
  * block between the assistant turn and the next replay. We don't know which.
11
10
  *
@@ -23,12 +22,12 @@
23
22
  * - NEVER mutates inputs. Pure read; only output is the structured log.
24
23
  * - NEVER alters request flow. The mismatch is observable signal only --
25
24
  * Anthropic's 400 still surfaces through the existing error path
26
- * (signed-replay-detector -> executor-prompt-runner). Bug A behavior fix
27
- * is a separate quick task gated on what this diagnostic reveals.
25
+ * (signed-replay-detector -> executor-prompt-runner). The behavior fix
26
+ * for the underlying bug is gated on what this diagnostic reveals.
28
27
  *
29
28
  * Logging surface follows CLAUDE.md canonical Pino fields:
30
29
  * - object-first signature: `error({...fields}, "msg")`
31
- * - `module: "agent.bridge.hash-invariant"`
30
+ * - `submodule: "bridge.hash-invariant"` (parent logger binds `module: "agent"`)
32
31
  * - `errorKind: "internal"` (classification per AGENTS.md §2.1)
33
32
  * - `hint`: actionable next step for the on-call diagnoser
34
33
  * - `responseId`, `blockIndex`, `oldHash`, `newHash`,
@@ -137,7 +136,7 @@ export interface RestoreResult {
137
136
  * Never throws. On any unexpected error during the walk (e.g. malformed
138
137
  * canonical entry whose getter throws), the entire result is `{ messages:
139
138
  * <input ref>, restoredCount: 0, affectedResponseIds: [] }` and ONE WARN log
140
- * fires with `module: RESTORE_MODULE_FIELD, errorKind: "internal"`.
139
+ * fires with `submodule: RESTORE_SUBMODULE_FIELD, errorKind: "internal"`.
141
140
  */
142
141
  export declare function restoreCanonicalThinkingBlocks(messages: ReadonlyArray<unknown> | undefined | null, canonicalStore: ReadonlyMap<string, ReadonlyArray<unknown>>, deps?: RestoreDeps): RestoreResult;
143
142
  export declare const WIRE_DIFF_HINT_FILE_MISSING: string;