comisai 1.0.36 → 1.0.37

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 (239) hide show
  1. package/node_modules/@comis/agent/dist/background/auto-background-middleware.js +9 -0
  2. package/node_modules/@comis/agent/dist/background/background-task-manager.d.ts +22 -2
  3. package/node_modules/@comis/agent/dist/background/background-task-manager.js +48 -41
  4. package/node_modules/@comis/agent/dist/background/background-task-persistence.js +28 -5
  5. package/node_modules/@comis/agent/dist/background/background-task-types.d.ts +49 -0
  6. package/node_modules/@comis/agent/dist/background/completion-dispatcher.d.ts +130 -0
  7. package/node_modules/@comis/agent/dist/background/completion-dispatcher.js +215 -0
  8. package/node_modules/@comis/agent/dist/background/completion-runner.d.ts +10 -1
  9. package/node_modules/@comis/agent/dist/background/completion-runner.js +98 -15
  10. package/node_modules/@comis/agent/dist/background/index.d.ts +6 -1
  11. package/node_modules/@comis/agent/dist/background/index.js +2 -0
  12. package/node_modules/@comis/agent/dist/background/session-resolver.d.ts +85 -0
  13. package/node_modules/@comis/agent/dist/background/session-resolver.js +78 -0
  14. package/node_modules/@comis/agent/dist/bootstrap/sections/messaging-sections.js +1 -0
  15. package/node_modules/@comis/agent/dist/bootstrap/sections/tool-descriptions.js +3 -3
  16. package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.d.ts +30 -2
  17. package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.js +51 -2
  18. package/node_modules/@comis/agent/dist/bootstrap/system-prompt-assembler.d.ts +22 -0
  19. package/node_modules/@comis/agent/dist/bootstrap/system-prompt-assembler.js +2 -2
  20. package/node_modules/@comis/agent/dist/bridge/bridge-event-handlers.d.ts +1 -5
  21. package/node_modules/@comis/agent/dist/bridge/bridge-event-handlers.js +2 -14
  22. package/node_modules/@comis/agent/dist/bridge/bridge-metrics.d.ts +26 -0
  23. package/node_modules/@comis/agent/dist/bridge/bridge-metrics.js +3 -0
  24. package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +9 -0
  25. package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +73 -2
  26. package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.d.ts +10 -10
  27. package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.js +14 -14
  28. package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.d.ts +11 -13
  29. package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.js +14 -15
  30. package/node_modules/@comis/agent/dist/executor/capability-index-context.d.ts +72 -0
  31. package/node_modules/@comis/agent/dist/executor/capability-index-context.js +329 -0
  32. package/node_modules/@comis/agent/dist/executor/drain-helper.d.ts +122 -0
  33. package/node_modules/@comis/agent/dist/executor/drain-helper.js +173 -0
  34. package/node_modules/@comis/agent/dist/executor/error-classifier.js +2 -2
  35. package/node_modules/@comis/agent/dist/executor/executor-post-execution.d.ts +48 -4
  36. package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +134 -31
  37. package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.d.ts +7 -0
  38. package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +25 -4
  39. package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.d.ts +18 -1
  40. package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +19 -16
  41. package/node_modules/@comis/agent/dist/executor/jit-guide-injector.d.ts +11 -2
  42. package/node_modules/@comis/agent/dist/executor/jit-guide-injector.js +16 -2
  43. package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +8 -2
  44. package/node_modules/@comis/agent/dist/executor/pi-executor.js +25 -12
  45. package/node_modules/@comis/agent/dist/executor/prompt-assembly.d.ts +9 -1
  46. package/node_modules/@comis/agent/dist/executor/prompt-assembly.js +15 -1
  47. package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +18 -27
  48. package/node_modules/@comis/agent/dist/executor/tool-deferral.js +29 -38
  49. package/node_modules/@comis/agent/dist/model/model-registry-adapter.js +1 -1
  50. package/node_modules/@comis/agent/dist/model/model-scanner.js +1 -1
  51. package/node_modules/@comis/agent/dist/safety/tool-retry-breaker.d.ts +11 -1
  52. package/node_modules/@comis/agent/dist/safety/tool-retry-breaker.js +19 -22
  53. package/node_modules/@comis/agent/dist/session/comis-session-manager.d.ts +16 -2
  54. package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.d.ts +1 -1
  55. package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.js +5 -5
  56. package/node_modules/@comis/agent/dist/workspace/data-env.d.ts +38 -0
  57. package/node_modules/@comis/agent/dist/workspace/data-env.js +56 -0
  58. package/node_modules/@comis/agent/dist/workspace/index.d.ts +1 -0
  59. package/node_modules/@comis/agent/dist/workspace/index.js +1 -0
  60. package/node_modules/@comis/agent/dist/workspace/templates.js +5 -1
  61. package/node_modules/@comis/agent/package.json +1 -1
  62. package/node_modules/@comis/channels/dist/index.d.ts +1 -1
  63. package/node_modules/@comis/channels/dist/index.js +1 -1
  64. package/node_modules/@comis/channels/dist/shared/channel-manager.d.ts +9 -3
  65. package/node_modules/@comis/channels/dist/shared/inbound-gate.d.ts +1 -1
  66. package/node_modules/@comis/channels/dist/shared/inbound-gate.js +22 -7
  67. package/node_modules/@comis/channels/dist/shared/inbound-pipeline.d.ts +10 -3
  68. package/node_modules/@comis/channels/dist/shared/inbound-route.d.ts +1 -1
  69. package/node_modules/@comis/channels/dist/shared/inbound-route.js +13 -2
  70. package/node_modules/@comis/channels/dist/shared/response-filter.d.ts +11 -24
  71. package/node_modules/@comis/channels/dist/shared/response-filter.js +25 -53
  72. package/node_modules/@comis/channels/package.json +1 -1
  73. package/node_modules/@comis/cli/dist/commands/providers.d.ts +1 -2
  74. package/node_modules/@comis/cli/dist/commands/providers.js +5 -6
  75. package/node_modules/@comis/cli/package.json +1 -1
  76. package/node_modules/@comis/core/dist/config/field-metadata.js +2 -0
  77. package/node_modules/@comis/core/dist/config/immutable-keys.js +4 -1
  78. package/node_modules/@comis/core/dist/config/index.d.ts +4 -0
  79. package/node_modules/@comis/core/dist/config/index.js +2 -0
  80. package/node_modules/@comis/core/dist/config/schema-agent.d.ts +0 -792
  81. package/node_modules/@comis/core/dist/config/schema-approvals.d.ts +0 -14
  82. package/node_modules/@comis/core/dist/config/schema-auto-reply-engine.d.ts +0 -6
  83. package/node_modules/@comis/core/dist/config/schema-background-tasks.d.ts +0 -12
  84. package/node_modules/@comis/core/dist/config/schema-browser.d.ts +0 -18
  85. package/node_modules/@comis/core/dist/config/schema-channel.d.ts +0 -158
  86. package/node_modules/@comis/core/dist/config/schema-coalescer.d.ts +0 -5
  87. package/node_modules/@comis/core/dist/config/schema-daemon.d.ts +0 -32
  88. package/node_modules/@comis/core/dist/config/schema-delivery.d.ts +0 -18
  89. package/node_modules/@comis/core/dist/config/schema-documentation.d.ts +0 -12
  90. package/node_modules/@comis/core/dist/config/schema-embedding.d.ts +0 -20
  91. package/node_modules/@comis/core/dist/config/schema-envelope.d.ts +0 -15
  92. package/node_modules/@comis/core/dist/config/schema-gateway.d.ts +0 -37
  93. package/node_modules/@comis/core/dist/config/schema-gemini-cache.d.ts +0 -2
  94. package/node_modules/@comis/core/dist/config/schema-integrations.d.ts +0 -318
  95. package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.d.ts +0 -18
  96. package/node_modules/@comis/core/dist/config/schema-memory-review.d.ts +0 -7
  97. package/node_modules/@comis/core/dist/config/schema-memory.d.ts +0 -16
  98. package/node_modules/@comis/core/dist/config/schema-messages.d.ts +0 -8
  99. package/node_modules/@comis/core/dist/config/schema-models.d.ts +0 -15
  100. package/node_modules/@comis/core/dist/config/schema-notification.d.ts +0 -5
  101. package/node_modules/@comis/core/dist/config/schema-oauth.d.ts +0 -5
  102. package/node_modules/@comis/core/dist/config/schema-observability.d.ts +0 -38
  103. package/node_modules/@comis/core/dist/config/schema-output-retention.d.ts +34 -0
  104. package/node_modules/@comis/core/dist/config/schema-output-retention.js +48 -0
  105. package/node_modules/@comis/core/dist/config/schema-plugins.d.ts +0 -8
  106. package/node_modules/@comis/core/dist/config/schema-providers.d.ts +0 -64
  107. package/node_modules/@comis/core/dist/config/schema-queue.d.ts +0 -58
  108. package/node_modules/@comis/core/dist/config/schema-response-prefix.d.ts +0 -2
  109. package/node_modules/@comis/core/dist/config/schema-retry.d.ts +0 -6
  110. package/node_modules/@comis/core/dist/config/schema-scheduler.d.ts +0 -39
  111. package/node_modules/@comis/core/dist/config/schema-secrets.d.ts +0 -3
  112. package/node_modules/@comis/core/dist/config/schema-security.d.ts +0 -18
  113. package/node_modules/@comis/core/dist/config/schema-send-policy.d.ts +0 -13
  114. package/node_modules/@comis/core/dist/config/schema-sender-trust-display.d.ts +0 -5
  115. package/node_modules/@comis/core/dist/config/schema-serializer.js +2 -0
  116. package/node_modules/@comis/core/dist/config/schema-skills.d.ts +0 -61
  117. package/node_modules/@comis/core/dist/config/schema-streaming.d.ts +0 -38
  118. package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.d.ts +0 -3
  119. package/node_modules/@comis/core/dist/config/schema-tooling.d.ts +87 -0
  120. package/node_modules/@comis/core/dist/config/schema-tooling.js +152 -0
  121. package/node_modules/@comis/core/dist/config/schema-verbosity.d.ts +0 -12
  122. package/node_modules/@comis/core/dist/config/schema-webhooks.d.ts +0 -40
  123. package/node_modules/@comis/core/dist/config/schema.d.ts +41 -38
  124. package/node_modules/@comis/core/dist/config/schema.js +6 -0
  125. package/node_modules/@comis/core/dist/context/context.d.ts +0 -4
  126. package/node_modules/@comis/core/dist/domain/approval-request.d.ts +0 -17
  127. package/node_modules/@comis/core/dist/domain/background-task-origin.d.ts +0 -10
  128. package/node_modules/@comis/core/dist/domain/delivery-origin.d.ts +0 -5
  129. package/node_modules/@comis/core/dist/domain/execution-graph.d.ts +0 -48
  130. package/node_modules/@comis/core/dist/domain/memory-entry.d.ts +0 -3
  131. package/node_modules/@comis/core/dist/domain/model-compat.d.ts +0 -4
  132. package/node_modules/@comis/core/dist/domain/normalized-message.d.ts +0 -15
  133. package/node_modules/@comis/core/dist/domain/provider-capabilities.d.ts +0 -6
  134. package/node_modules/@comis/core/dist/domain/rich-message.d.ts +0 -14
  135. package/node_modules/@comis/core/dist/domain/subagent-context-config.d.ts +0 -22
  136. package/node_modules/@comis/core/dist/domain/subagent-context-types.d.ts +0 -8
  137. package/node_modules/@comis/core/dist/event-bus/events-agent.d.ts +31 -0
  138. package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +5 -0
  139. package/node_modules/@comis/core/dist/exports/config.d.ts +2 -2
  140. package/node_modules/@comis/core/dist/exports/config.js +3 -1
  141. package/node_modules/@comis/core/dist/exports/hooks.d.ts +1 -1
  142. package/node_modules/@comis/core/dist/exports/ports.d.ts +2 -2
  143. package/node_modules/@comis/core/dist/exports/ports.js +1 -1
  144. package/node_modules/@comis/core/dist/ports/channel-plugin.d.ts +0 -13
  145. package/node_modules/@comis/core/dist/ports/index.d.ts +2 -0
  146. package/node_modules/@comis/core/dist/ports/index.js +4 -0
  147. package/node_modules/@comis/core/dist/ports/no-op-tool-capability.d.ts +30 -0
  148. package/node_modules/@comis/core/dist/ports/no-op-tool-capability.js +47 -0
  149. package/node_modules/@comis/core/dist/ports/tool-capability.d.ts +165 -0
  150. package/node_modules/@comis/core/dist/ports/tool-capability.js +15 -0
  151. package/node_modules/@comis/core/dist/security/audit.d.ts +0 -11
  152. package/node_modules/@comis/core/dist/tool-metadata.d.ts +21 -1
  153. package/node_modules/@comis/core/dist/tool-metadata.js +1 -1
  154. package/node_modules/@comis/core/package.json +1 -1
  155. package/node_modules/@comis/daemon/bundled-skills/skill-creator/scripts/validate-skill.py +1 -1
  156. package/node_modules/@comis/daemon/dist/daemon.js +89 -14
  157. package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.d.ts +1 -1
  158. package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.js +1 -1
  159. package/node_modules/@comis/daemon/dist/rpc/builtin-provider-guard.js +2 -2
  160. package/node_modules/@comis/daemon/dist/rpc/credential-resolver.js +1 -1
  161. package/node_modules/@comis/daemon/dist/rpc/model-handlers.d.ts +1 -1
  162. package/node_modules/@comis/daemon/dist/rpc/model-handlers.js +2 -2
  163. package/node_modules/@comis/daemon/dist/sub-agent-runner.d.ts +18 -0
  164. package/node_modules/@comis/daemon/dist/sub-agent-runner.js +41 -9
  165. package/node_modules/@comis/daemon/dist/wiring/index.d.ts +2 -0
  166. package/node_modules/@comis/daemon/dist/wiring/index.js +1 -0
  167. package/node_modules/@comis/daemon/dist/wiring/setup-agents.d.ts +36 -2
  168. package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +45 -8
  169. package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.d.ts +28 -9
  170. package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.js +36 -9
  171. package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.js +2 -2
  172. package/node_modules/@comis/daemon/dist/wiring/setup-channels.d.ts +9 -2
  173. package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +15 -9
  174. package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.d.ts +20 -5
  175. package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.js +20 -15
  176. package/node_modules/@comis/daemon/dist/wiring/setup-delivery.js +14 -2
  177. package/node_modules/@comis/daemon/dist/wiring/setup-gateway.d.ts +4 -6
  178. package/node_modules/@comis/daemon/dist/wiring/setup-gateway.js +3 -5
  179. package/node_modules/@comis/daemon/dist/wiring/setup-heartbeat.d.ts +20 -5
  180. package/node_modules/@comis/daemon/dist/wiring/setup-heartbeat.js +11 -2
  181. package/node_modules/@comis/daemon/dist/wiring/setup-output-retention.d.ts +89 -0
  182. package/node_modules/@comis/daemon/dist/wiring/setup-output-retention.js +212 -0
  183. package/node_modules/@comis/daemon/dist/wiring/setup-tools.d.ts +18 -4
  184. package/node_modules/@comis/daemon/dist/wiring/setup-tools.js +29 -10
  185. package/node_modules/@comis/daemon/dist/wiring/tool-capability-adapter.d.ts +75 -0
  186. package/node_modules/@comis/daemon/dist/wiring/tool-capability-adapter.js +253 -0
  187. package/node_modules/@comis/daemon/package.json +1 -1
  188. package/node_modules/@comis/gateway/dist/webhook/webhook-endpoint.d.ts +0 -4
  189. package/node_modules/@comis/gateway/package.json +1 -1
  190. package/node_modules/@comis/infra/package.json +1 -1
  191. package/node_modules/@comis/memory/package.json +1 -1
  192. package/node_modules/@comis/scheduler/dist/cron/cron-types.d.ts +0 -42
  193. package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.d.ts +29 -8
  194. package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.js +19 -7
  195. package/node_modules/@comis/scheduler/dist/system-events/system-event-types.d.ts +0 -3
  196. package/node_modules/@comis/scheduler/dist/tasks/task-types.d.ts +0 -17
  197. package/node_modules/@comis/scheduler/package.json +1 -1
  198. package/node_modules/@comis/shared/dist/index.d.ts +3 -0
  199. package/node_modules/@comis/shared/dist/index.js +4 -0
  200. package/node_modules/@comis/shared/dist/mcp-tool-name.d.ts +78 -0
  201. package/node_modules/@comis/shared/dist/mcp-tool-name.js +92 -0
  202. package/node_modules/@comis/shared/dist/silent-tokens.d.ts +38 -0
  203. package/node_modules/@comis/shared/dist/silent-tokens.js +51 -0
  204. package/node_modules/@comis/shared/dist/visible-delivery.d.ts +28 -0
  205. package/node_modules/@comis/shared/dist/visible-delivery.js +16 -0
  206. package/node_modules/@comis/shared/package.json +1 -1
  207. package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.d.ts +2 -13
  208. package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.js +3 -21
  209. package/node_modules/@comis/skills/dist/bridge/tool-metadata-enforcement.js +1 -1
  210. package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +4 -4
  211. package/node_modules/@comis/skills/dist/builtin/exec-tool.d.ts +55 -9
  212. package/node_modules/@comis/skills/dist/builtin/exec-tool.js +383 -19
  213. package/node_modules/@comis/skills/dist/builtin/install-detour.d.ts +67 -0
  214. package/node_modules/@comis/skills/dist/builtin/install-detour.js +342 -0
  215. package/node_modules/@comis/skills/dist/builtin/platform/admin-manage-factory.js +5 -5
  216. package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +2 -2
  217. package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +2 -2
  218. package/node_modules/@comis/skills/dist/builtin/platform/message-tool.js +18 -0
  219. package/node_modules/@comis/skills/dist/builtin/platform/messaging-factory.d.ts +18 -1
  220. package/node_modules/@comis/skills/dist/builtin/platform/messaging-factory.js +18 -2
  221. package/node_modules/@comis/skills/dist/builtin/platform/models-manage-tool.js +3 -3
  222. package/node_modules/@comis/skills/dist/builtin/process-registry.d.ts +14 -0
  223. package/node_modules/@comis/skills/dist/builtin/process-tool.d.ts +24 -4
  224. package/node_modules/@comis/skills/dist/builtin/process-tool.js +25 -7
  225. package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.d.ts +1 -1
  226. package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.js +9 -0
  227. package/node_modules/@comis/skills/dist/index.d.ts +4 -1
  228. package/node_modules/@comis/skills/dist/index.js +3 -1
  229. package/node_modules/@comis/skills/dist/manifest/capability-parser.d.ts +44 -0
  230. package/node_modules/@comis/skills/dist/manifest/capability-parser.js +68 -0
  231. package/node_modules/@comis/skills/dist/manifest/schema.d.ts +44 -37
  232. package/node_modules/@comis/skills/dist/manifest/schema.js +35 -0
  233. package/node_modules/@comis/skills/dist/registry/discovery.d.ts +8 -0
  234. package/node_modules/@comis/skills/dist/registry/discovery.js +10 -3
  235. package/node_modules/@comis/skills/dist/registry/skill-registry.d.ts +45 -1
  236. package/node_modules/@comis/skills/dist/registry/skill-registry.js +70 -7
  237. package/node_modules/@comis/skills/package.json +1 -1
  238. package/node_modules/@comis/web/package.json +1 -1
  239. package/package.json +21 -21
@@ -67,7 +67,7 @@ import { randomUUID } from "node:crypto";
67
67
  /** Number of turns to restrict breakpoints after server eviction. */
68
68
  const EVICTION_COOLDOWN_TURNS = 2;
69
69
  // ---------------------------------------------------------------------------
70
- // R-12: Proactive tool-call safety guard
70
+ // Proactive tool-call safety guard
71
71
  // ---------------------------------------------------------------------------
72
72
  /**
73
73
  * Create a beforeToolCall guard that proactively blocks tool execution when
@@ -124,10 +124,10 @@ export function createBeforeToolCallGuard(stepCounter, budgetGuard, circuitBreak
124
124
  };
125
125
  }
126
126
  // ---------------------------------------------------------------------------
127
- // R-13: Session stats delegation helper
127
+ // Session stats delegation helper
128
128
  // ---------------------------------------------------------------------------
129
129
  /**
130
- * Merge SDK session stats into execution result for token totals (R-13).
130
+ * Merge SDK session stats into execution result for token totals.
131
131
  *
132
132
  * Token counts (input, output, cacheRead, cacheWrite, total) are sourced
133
133
  * from the SDK's cumulative session stats -- single source of truth.
@@ -400,7 +400,7 @@ export function createPiExecutor(config, deps) {
400
400
  provider: resolvedModel.provider,
401
401
  id: resolvedModel.id,
402
402
  }) : undefined;
403
- // f. Execute within session adapter (R-11: use ephemeral adapter if provided)
403
+ // f. Execute within session adapter (use ephemeral adapter if provided)
404
404
  const sessionAdapter = overrides?.ephemeralSessionAdapter ?? deps.sessionAdapter;
405
405
  const lockResult = await sessionAdapter.withSession(sessionKey, async (sm) => {
406
406
  // Repair orphaned messages
@@ -450,6 +450,7 @@ export function createPiExecutor(config, deps) {
450
450
  const stableGetPromptSkillsXml = frozenPromptSkillsXml !== undefined
451
451
  ? () => frozenPromptSkillsXml
452
452
  : deps.getPromptSkillsXml;
453
+ // toolCapabilityPort flows through frozenDeps spread — no explicit re-assignment.
453
454
  const frozenDeps = { ...deps, getPromptSkillsXml: stableGetPromptSkillsXml };
454
455
  // Tool assembly pipeline: merge, settings, prompt, deferral, JIT, pruning, snapshot, normalization, serializer
455
456
  // Extracted to executor-tool-assembly.ts
@@ -459,7 +460,7 @@ export function createPiExecutor(config, deps) {
459
460
  resolvedModel, modelCompat, agentId, safetyReinforcement, _directives,
460
461
  });
461
462
  const { mergedCustomTools, } = toolAssembly;
462
- const { deferralResult, deferredContext, modelTier, discoveryTracker, settingsManager, resourceLoaderOptions, promptResult, cachedSystemTokensEstimate, } = toolAssembly;
463
+ const { deferralResult, deferredContext, capabilityIndexResult, modelTier, discoveryTracker, settingsManager, resourceLoaderOptions, promptResult, cachedSystemTokensEstimate, } = toolAssembly;
463
464
  const currentDiscoveryTracker = toolAssembly.currentDiscoveryTracker;
464
465
  const { systemPrompt, systemPromptBlocks, dynamicPreamble, inlineMemory } = promptResult;
465
466
  // DAG ingestion hook -- install BEFORE microcompaction
@@ -537,8 +538,8 @@ export function createPiExecutor(config, deps) {
537
538
  const messageSendLimiter = createMessageSendLimiter({
538
539
  maxSendsPerExecution: deps.maxSendsPerExecution ?? 3,
539
540
  });
540
- // R-12: Proactive safety -- block tool execution before it starts
541
- // when safety limits are already reached. Existing reactive checks in
541
+ // Proactive safety -- block tool execution before it starts when
542
+ // safety limits are already reached. Existing reactive checks in
542
543
  // pi-event-bridge remain as fallback for limits crossed during execution.
543
544
  // NOTE: beforeToolCall replaces the extension runner's hook. Comis does
544
545
  // not load pi-mono extensions, so this override is safe.
@@ -663,6 +664,18 @@ export function createPiExecutor(config, deps) {
663
664
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
664
665
  session.agent.transformContext = ceSetup.contextEngine.transformContext;
665
666
  }
667
+ // Align register/deregister key shape with
668
+ // BackgroundSessionResolver.formatComposite so production lookups via
669
+ // resolveActiveSession({agentId, channelType, channelId}) find the
670
+ // handle this execute() call registers. session-resolver.test.ts
671
+ // locks the formula — drift on either side breaks that test.
672
+ // NormalizedMessageSchema enforces channelType / channelId are
673
+ // non-empty (z.string().min(1)), so this composition is unconditional.
674
+ const resolverRegisterKey = formatSessionKey({
675
+ tenantId: agentId ?? "default",
676
+ channelId: `${msg.channelType}:${msg.channelId}`,
677
+ userId: msg.channelId,
678
+ });
666
679
  // Register active run for mid-execution steering
667
680
  if (deps.activeRunRegistry) {
668
681
  const handle = {
@@ -672,9 +685,9 @@ export function createPiExecutor(config, deps) {
672
685
  isStreaming: () => session.isStreaming,
673
686
  isCompacting: () => session.isCompacting,
674
687
  };
675
- const registered = deps.activeRunRegistry.register(formattedKey, handle);
688
+ const registered = deps.activeRunRegistry.register(resolverRegisterKey, handle);
676
689
  if (!registered) {
677
- deps.logger.warn({ sessionKey: formattedKey, hint: "Session already has an active run; concurrent execution may cause issues", errorKind: "resource" }, "Active run already registered");
690
+ deps.logger.warn({ sessionKey: resolverRegisterKey, hint: "Session already has an active run; concurrent execution may cause issues", errorKind: "resource" }, "Active run already registered");
678
691
  }
679
692
  }
680
693
  // SDK tool management validation and introspection.
@@ -748,7 +761,7 @@ export function createPiExecutor(config, deps) {
748
761
  deps.logger.debug({ err: sdkSkillError, hint: "SDK skill population failed, Comis discovery still active", errorKind: "dependency" }, "SDK skill population non-fatal error");
749
762
  }
750
763
  // session.sendCustomMessage() is available for operator annotations.
751
- // REQUIREMENTS.md refers to appendCustomEntry() which is the SessionManager-level API;
764
+ // Note: appendCustomEntry() is the SessionManager-level API;
752
765
  // the AgentSession wrapper exposes this as sendCustomMessage({ customType, content, display, details }).
753
766
  // Future commands or hooks can call this to inject custom entries into the JSONL session.
754
767
  // Apply command directives (thinking, compact, model, export, fork, branch)
@@ -1067,7 +1080,7 @@ export function createPiExecutor(config, deps) {
1067
1080
  const promptRunResult = await runPrompt({
1068
1081
  msg, session, config, sessionKey, formattedKey, agentId, result,
1069
1082
  executionOverrides, executionStartMs, effectiveTimeout, executionId,
1070
- bridge, dynamicPreamble, deferredContext, inlineMemory,
1083
+ bridge, dynamicPreamble, deferredContext, capabilityIndexResult, inlineMemory,
1071
1084
  systemPrompt,
1072
1085
  mergedCustomTools,
1073
1086
  cmdResult, sepEnabled, executionPlanRef,
@@ -1144,7 +1157,7 @@ export function createPiExecutor(config, deps) {
1144
1157
  // Post-execution cleanup: stats merge, cache metrics, memory persist, session cleanup
1145
1158
  // Extracted to executor-post-execution.ts
1146
1159
  await postExecution({
1147
- result, session, sm, config, msg, sessionKey, formattedKey, agentId,
1160
+ result, session, sm, config, msg, sessionKey, formattedKey, resolverRegisterKey, agentId,
1148
1161
  executionStartMs, executionId, executionOverrides,
1149
1162
  bridge, unsubscribe,
1150
1163
  contextEngineRef, ceSetup, streamSetup,
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @module
10
10
  */
11
- import type { SessionKey, NormalizedMessage, PerAgentConfig, MemoryPort, HookRunner, SecretManager, EnvelopeConfig, WrapExternalContentOptions, TypedEventBus, SenderTrustDisplayConfig, SpawnPacket, DeliveryMirrorPort, ModelOperationType } from "@comis/core";
11
+ import type { SessionKey, NormalizedMessage, PerAgentConfig, MemoryPort, HookRunner, SecretManager, EnvelopeConfig, WrapExternalContentOptions, TypedEventBus, SenderTrustDisplayConfig, SpawnPacket, DeliveryMirrorPort, ModelOperationType, ToolCapabilityPort } from "@comis/core";
12
12
  import type { ComisLogger } from "@comis/infra";
13
13
  import type { ToolDefinition } from "@mariozechner/pi-coding-agent";
14
14
  import type { BootstrapContextFile } from "../bootstrap/types.js";
@@ -130,6 +130,14 @@ export interface PromptAssemblyParams {
130
130
  }>;
131
131
  /** Platform message character limit for auto verbosity mode. Resolved by caller from channelRegistry. */
132
132
  channelMaxChars?: number;
133
+ /**
134
+ * Tool-capability port for the gate flag.
135
+ * Only `port.isCapabilityIndexEnabled()` is read from this file — live-runtime
136
+ * port accessors (skill catalog, connected MCP servers, deferred-tool state)
137
+ * are FORBIDDEN here per the cache-fence invariant. Architecture-grep tests
138
+ * statically enforce this restriction.
139
+ */
140
+ toolCapabilityPort: ToolCapabilityPort;
133
141
  };
134
142
  msg: NormalizedMessage;
135
143
  sessionKey: SessionKey;
@@ -331,7 +331,7 @@ export async function assembleExecutionPrompt(params) {
331
331
  // Consolidated lightContext flag: heartbeat implies light-context regardless
332
332
  // of the explicit msg.metadata.lightContext flag. Callers that only set the
333
333
  // metadata flag OR only set operationType="heartbeat" produce identical
334
- // prompt output (design-doc §Risks: "Heartbeat lightContext and operationType drift").
334
+ // prompt output.
335
335
  const effectiveLightContext = msg.metadata?.lightContext === true || params.operationType === "heartbeat";
336
336
  // 2. Load workspace bootstrap files (skip for "none" mode)
337
337
  let bootstrapContextFiles = [];
@@ -522,6 +522,13 @@ export async function assembleExecutionPrompt(params) {
522
522
  const isOnboarding = await detectOnboardingState(deps.workspaceDir);
523
523
  // Shared params for both assembleRichSystemPrompt and assembleRichSystemPromptBlocks.
524
524
  // Using a single variable guarantees identity by construction.
525
+ //
526
+ // Hot-flip safety: the capability-index gate value is read once per
527
+ // assembleExecutionPrompt call via
528
+ // `deps.toolCapabilityPort.isCapabilityIndexEnabled()`. The flag is
529
+ // restart-required and stable across the session by config contract, so the
530
+ // cached system-prompt prefix is NOT retroactively rewritten when the
531
+ // underlying YAML changes mid-session.
525
532
  const assemblerParams = {
526
533
  agentName: config.name,
527
534
  promptMode,
@@ -554,6 +561,13 @@ export async function assembleExecutionPrompt(params) {
554
561
  subagentRole: undefined, // relocated to dynamic preamble for sub-agent cache sharing
555
562
  excludeBootstrapFromContext: true, // BOOTSTRAP.md is either elevated (onboarding) or dead weight (post-onboarding); never useful in Project Context
556
563
  workspaceProfile: config.workspace?.profile,
564
+ /**
565
+ * Read once per call. The value is config-derived / restart-required,
566
+ * so it's stable across all turns in this session. Reading it via the
567
+ * port (rather than from config directly) isolates this code from the
568
+ * config-schema shape and matches the live adapter contract.
569
+ */
570
+ capabilityIndexEnabled: deps.toolCapabilityPort.isCapabilityIndexEnabled(),
557
571
  sepEnabled: params.sepEnabled,
558
572
  };
559
573
  let systemPrompt = assembleRichSystemPrompt(assemblerParams);
@@ -101,13 +101,16 @@ export declare function resolveModelTier(contextWindow: number): ModelTier;
101
101
  */
102
102
  export declare function resolveToolCallingTemperature(modelTier: ModelTier): number;
103
103
  /**
104
- * Anthropic models that support server-side tool_search_tool_regex
105
- * (defer_loading). Sonnet 4.x+, Opus 4.x+; NOT Haiku.
104
+ * Anthropic models that support server-side tool-search via defer_loading.
105
+ * Sonnet 4.x+, Opus 4.x+; NOT Haiku.
106
106
  *
107
- * When this returns true, request-body-injector strips client-side
108
- * `discover_tools` from the API payload and appends `tool_search_tool_regex`
109
- * instead -- so any model-facing teaching string about `discover_tools`
110
- * contradicts the actual tool list and must be suppressed.
107
+ * **Surviving caller:** `request-body-injector.ts` (the
108
+ * `if (supportsToolSearch(model.id)) {...}` gate inside the Anthropic
109
+ * `onPayload` handler). Used to gate the API-payload reshape that strips
110
+ * the client-side discovery tool, appends the server-side tool-search
111
+ * regex tool, and marks deferred tools `defer_loading: true`. This is a
112
+ * runtime API-payload concern, distinct from the deferred-tool prompt
113
+ * teaching emitted by `buildDeferredToolsContext`.
111
114
  *
112
115
  * Lowercase-normalize so provider-prefixed model ids
113
116
  * (`anthropic/claude-sonnet-4`, `bedrock/anthropic.claude-opus-4`) resolve
@@ -135,31 +138,19 @@ export declare function resolveToolDescription(tool: ToolDefinition): string;
135
138
  * Lists deferred tool names and descriptions so the LLM knows what's
136
139
  * available behind a discovery mechanism.
137
140
  *
138
- * The third line (the instruction line) is conditional on `useToolSearch`:
139
- *
140
- * - `useToolSearch=false` (default, every non-Anthropic provider + Haiku):
141
- * teaches the model to call the client-side `discover_tools` tool, which
142
- * IS present in those payloads.
143
- *
144
- * - `useToolSearch=true` (Anthropic Sonnet/Opus 4.x): the API payload no
145
- * longer contains a client-side `discover_tools` tool -- the
146
- * request-body-injector replaces it with the server-side
147
- * `tool_search_tool_regex` and marks deferred tools `defer_loading: true`,
148
- * meaning Anthropic auto-loads them on first direct invocation. The
149
- * teaching string therefore points at direct invocation + tool-search by
150
- * regex, never at `discover_tools`. Without this conditional, the model
151
- * reads its own preamble ("call discover_tools") against a tool list that
152
- * doesn't contain that tool and gives up (production repro).
141
+ * The instruction line is mechanism-neutral: it tells the model these
142
+ * tools are available but not loaded, and points it at "the discovery
143
+ * mechanism available in your active toolspace" without naming a specific
144
+ * tool. Provider-specific payload reshaping (stripping the client-side
145
+ * discovery tool and appending the server-side tool-search regex tool for
146
+ * Anthropic Sonnet/Opus 4.x) lives entirely in `request-body-injector.ts`
147
+ * and is gated by `supportsToolSearch(modelId)`. This separation is
148
+ * enforced by architecture-grep tests.
153
149
  *
154
150
  * @param entries - Deferred tool entries (remaining after discovery re-inclusion)
155
- * @param options - Optional flags. `useToolSearch=true` switches the third
156
- * line to the tool-search-aware variant. Defaults to false (backward-
157
- * compatible with the discover_tools teaching).
158
151
  * @returns XML block string, or empty string when no entries
159
152
  */
160
- export declare function buildDeferredToolsContext(entries: DeferredToolEntry[], options?: {
161
- useToolSearch?: boolean;
162
- }): string;
153
+ export declare function buildDeferredToolsContext(entries: DeferredToolEntry[]): string;
163
154
  /**
164
155
  * Apply unified tool deferral: rule-based, budget-based, small-model,
165
156
  * lifecycle merge, and operator overrides.
@@ -15,7 +15,7 @@
15
15
  * @module
16
16
  */
17
17
  import { getToolMetadata } from "@comis/core";
18
- import { extractMcpServerName } from "../bridge/bridge-event-handlers.js";
18
+ import { extractMcpServerName } from "@comis/shared";
19
19
  import { PRIVILEGED_TOOL_NAMES } from "../bootstrap/sections/tooling-sections.js";
20
20
  import { LEAN_TOOL_DESCRIPTIONS } from "../bootstrap/sections/tool-descriptions.js";
21
21
  // ---------------------------------------------------------------------------
@@ -96,13 +96,16 @@ export function resolveToolCallingTemperature(modelTier) {
96
96
  return modelTier === "small" ? 0.0 : 0.1;
97
97
  }
98
98
  /**
99
- * Anthropic models that support server-side tool_search_tool_regex
100
- * (defer_loading). Sonnet 4.x+, Opus 4.x+; NOT Haiku.
99
+ * Anthropic models that support server-side tool-search via defer_loading.
100
+ * Sonnet 4.x+, Opus 4.x+; NOT Haiku.
101
101
  *
102
- * When this returns true, request-body-injector strips client-side
103
- * `discover_tools` from the API payload and appends `tool_search_tool_regex`
104
- * instead -- so any model-facing teaching string about `discover_tools`
105
- * contradicts the actual tool list and must be suppressed.
102
+ * **Surviving caller:** `request-body-injector.ts` (the
103
+ * `if (supportsToolSearch(model.id)) {...}` gate inside the Anthropic
104
+ * `onPayload` handler). Used to gate the API-payload reshape that strips
105
+ * the client-side discovery tool, appends the server-side tool-search
106
+ * regex tool, and marks deferred tools `defer_loading: true`. This is a
107
+ * runtime API-payload concern, distinct from the deferred-tool prompt
108
+ * teaching emitted by `buildDeferredToolsContext`.
106
109
  *
107
110
  * Lowercase-normalize so provider-prefixed model ids
108
111
  * (`anthropic/claude-sonnet-4`, `bedrock/anthropic.claude-opus-4`) resolve
@@ -169,32 +172,21 @@ export function resolveToolDescription(tool) {
169
172
  * Lists deferred tool names and descriptions so the LLM knows what's
170
173
  * available behind a discovery mechanism.
171
174
  *
172
- * The third line (the instruction line) is conditional on `useToolSearch`:
173
- *
174
- * - `useToolSearch=false` (default, every non-Anthropic provider + Haiku):
175
- * teaches the model to call the client-side `discover_tools` tool, which
176
- * IS present in those payloads.
177
- *
178
- * - `useToolSearch=true` (Anthropic Sonnet/Opus 4.x): the API payload no
179
- * longer contains a client-side `discover_tools` tool -- the
180
- * request-body-injector replaces it with the server-side
181
- * `tool_search_tool_regex` and marks deferred tools `defer_loading: true`,
182
- * meaning Anthropic auto-loads them on first direct invocation. The
183
- * teaching string therefore points at direct invocation + tool-search by
184
- * regex, never at `discover_tools`. Without this conditional, the model
185
- * reads its own preamble ("call discover_tools") against a tool list that
186
- * doesn't contain that tool and gives up (production repro).
175
+ * The instruction line is mechanism-neutral: it tells the model these
176
+ * tools are available but not loaded, and points it at "the discovery
177
+ * mechanism available in your active toolspace" without naming a specific
178
+ * tool. Provider-specific payload reshaping (stripping the client-side
179
+ * discovery tool and appending the server-side tool-search regex tool for
180
+ * Anthropic Sonnet/Opus 4.x) lives entirely in `request-body-injector.ts`
181
+ * and is gated by `supportsToolSearch(modelId)`. This separation is
182
+ * enforced by architecture-grep tests.
187
183
  *
188
184
  * @param entries - Deferred tool entries (remaining after discovery re-inclusion)
189
- * @param options - Optional flags. `useToolSearch=true` switches the third
190
- * line to the tool-search-aware variant. Defaults to false (backward-
191
- * compatible with the discover_tools teaching).
192
185
  * @returns XML block string, or empty string when no entries
193
186
  */
194
- export function buildDeferredToolsContext(entries, options) {
187
+ export function buildDeferredToolsContext(entries) {
195
188
  if (entries.length === 0)
196
189
  return "";
197
- const useToolSearch = options?.useToolSearch === true;
198
190
  // Separate MCP tools (group by server) from non-MCP tools (individual listing)
199
191
  const mcpByServer = new Map();
200
192
  const nonMcpEntries = [];
@@ -220,9 +212,9 @@ export function buildDeferredToolsContext(entries, options) {
220
212
  const shortNames = tools.map(t => t.name.startsWith(prefix) ? t.name.slice(prefix.length) : t.name);
221
213
  lines.push(`[${server}] (${tools.length} tools): ${shortNames.join(", ")}`);
222
214
  }
223
- const instruction = useToolSearch
224
- ? "These tools auto-load on first invocation -- call them directly by name with the right arguments. To preview a tool's schema before calling, use tool_search_tool_regex with a regex matching the tool name (e.g., tool_search_tool_regex(pattern: \"agents_manage\"))."
225
- : "Call discover_tools to search by keyword or server name (e.g., discover_tools(\"yfinance\")).";
215
+ const instruction = "These tools are connected but not currently loaded into your active context. " +
216
+ "To use one, invoke the discovery mechanism available in your active toolspace, " +
217
+ "then call the loaded tool with the appropriate arguments.";
226
218
  return [
227
219
  "<deferred-tools>",
228
220
  "The following tools are available but not loaded.",
@@ -428,7 +420,7 @@ function structuredSearch(deferredTools, query, maxResults) {
428
420
  if (prefixMatches.length > 0)
429
421
  return prefixMatches;
430
422
  }
431
- // Mode 4: Server name match (e.g., "yfinance" -> all mcp__yfinance--* tools)
423
+ // Mode 4: Server name match (e.g., bare server token -> all mcp__<server>--* tools)
432
424
  const serverPrefix = `mcp__${q}--`;
433
425
  const serverMatches = deferredTools.filter(t => t.name.toLowerCase().startsWith(serverPrefix));
434
426
  if (serverMatches.length > 0)
@@ -622,7 +614,7 @@ export function createDiscoverTool(deferredEntries, logger, embeddingPort, score
622
614
  return {
623
615
  content: [{
624
616
  type: "text",
625
- text: "No matching tools found. Try an exact tool name, MCP server name (e.g. 'yfinance'), or select:tool1,tool2 syntax.",
617
+ text: "No matching tools found. Try an exact tool name, MCP server name, or select:tool1,tool2 syntax.",
626
618
  }],
627
619
  isError: false,
628
620
  details: undefined,
@@ -648,12 +640,11 @@ export function createDiscoverTool(deferredEntries, logger, embeddingPort, score
648
640
  * Match modes (checked in order, first non-empty wins):
649
641
  * 1. Exact name match (case-insensitive) against the full query.
650
642
  * 2. `mcp__` / `mcp:` prefix match against the full query.
651
- * 3. Bare server-name match on full query (`"yfinance"` -> all `mcp__yfinance--*`).
643
+ * 3. Bare server-name match on full query (e.g., bare server token -> all `mcp__<server>--*`).
652
644
  * 4. Per-token server-name fallback: for multi-word queries like
653
- * `"yfinance get_stock"`, check each whitespace-separated token as a
654
- * potential MCP server name. Catches the srv1593437 08:06:39Z scenario
655
- * where the agent emits `{query: "yfinance get_stock"}` rather than just
656
- * `{query: "yfinance"}`.
645
+ * `"<server> <verb>"`, check each whitespace-separated token as a
646
+ * potential MCP server name. Catches the case where the agent emits
647
+ * `{query: "<server> <verb>"}` rather than just `{query: "<server>"}`.
657
648
  */
658
649
  function findActiveToolMatches(query, activeToolNames) {
659
650
  const q = query.toLowerCase().trim();
@@ -679,7 +670,7 @@ function findActiveToolMatches(query, activeToolNames) {
679
670
  // Mode 4: per-token server fallback for multi-word queries.
680
671
  // Each whitespace-separated token is probed as a server name. The first
681
672
  // token that resolves to >= 1 active tool wins. This handles the common
682
- // "{server} {verb}" pattern like "yfinance get_stock".
673
+ // "<server> <verb>" pattern like "<bare-server-token> <verb>".
683
674
  const tokens = q.split(/\s+/).filter(t => /^[a-z0-9_-]+$/.test(t));
684
675
  for (const token of tokens) {
685
676
  const tokenServerPrefix = `mcp__${token}--`;
@@ -113,7 +113,7 @@ export function registerCustomProviders(registry, entries, secretManager, logger
113
113
  if (isBuiltInType && providerName !== entry.type) {
114
114
  providerAliases.set(providerName, entry.type);
115
115
  }
116
- // Layer 1B (260430-vwt): catalog-aware model enrichment.
116
+ // Catalog-aware model enrichment.
117
117
  //
118
118
  // Before computing customModels, decide whether to inherit the full
119
119
  // pi-ai catalog or to enrich the user's sparse list with catalog
@@ -14,7 +14,7 @@
14
14
  */
15
15
  import { getModels, getProviders } from "@mariozechner/pi-ai";
16
16
  // ---------------------------------------------------------------------------
17
- // Catalog-driven endpoint resolution (Layer 1E -- 260430-vwt)
17
+ // Catalog-driven endpoint resolution
18
18
  // ---------------------------------------------------------------------------
19
19
  /**
20
20
  * Native pi-ai providers from the live catalog. Used to source baseUrls
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Tool retry circuit breaker: per-tool-signature consecutive failure tracking.
3
3
  *
4
- * Prevents infinite retry loops (like the 48-call yfinance incident) by blocking
4
+ * Prevents infinite retry loops (the original repro: 48-call MCP-server retry incident) by blocking
5
5
  * tool calls after repeated failures and providing actionable LLM guidance with
6
6
  * alternative tool suggestions.
7
7
  *
@@ -29,6 +29,16 @@ export interface ToolRetryBreakerConfig {
29
29
  /** Max consecutive same-error-class failures (any args) before blocking.
30
30
  * Stricter than args-based because same error + different args = stronger stuck signal. */
31
31
  maxConsecutiveErrorPatterns?: number;
32
+ /**
33
+ * Operator-supplied tool-alternative map. Keys are tool-name prefixes
34
+ * (e.g., `"mcp__finance-data"`); values are arrays of suggested alternative
35
+ * tool names. Used in block reasons to guide the LLM toward working tools.
36
+ *
37
+ * Defaults to an empty map (no alternatives suggested). The codebase MUST
38
+ * NOT ship hardcoded MCP server names — operators opt in by populating
39
+ * this map in their breaker config.
40
+ */
41
+ toolAlternatives?: Record<string, readonly string[]>;
32
42
  }
33
43
  /** Tool retry breaker interface -- tracks per-tool-signature failures. */
34
44
  export interface ToolRetryBreaker {
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * Tool retry circuit breaker: per-tool-signature consecutive failure tracking.
4
4
  *
5
- * Prevents infinite retry loops (like the 48-call yfinance incident) by blocking
5
+ * Prevents infinite retry loops (the original repro: 48-call MCP-server retry incident) by blocking
6
6
  * tool calls after repeated failures and providing actionable LLM guidance with
7
7
  * alternative tool suggestions.
8
8
  *
@@ -17,16 +17,6 @@
17
17
  * @module
18
18
  */
19
19
  // ---------------------------------------------------------------------------
20
- // Alternative tool mapping (hardcoded v1)
21
- // ---------------------------------------------------------------------------
22
- /**
23
- * Maps tool name prefixes to alternative tools that can serve similar purposes.
24
- * Used in block reasons to guide the LLM toward working alternatives.
25
- */
26
- const TOOL_ALTERNATIVES = {
27
- "mcp__yfinance": ["web_search", "mcp__tavily--tavily-search", "web_fetch"],
28
- };
29
- // ---------------------------------------------------------------------------
30
20
  // Error tag extraction
31
21
  // ---------------------------------------------------------------------------
32
22
  /**
@@ -154,17 +144,6 @@ function fingerprint(toolName, args) {
154
144
  const sortedArgs = JSON.stringify(Object.fromEntries(Object.entries(args).sort()));
155
145
  return `${toolName}::${sortedArgs}`;
156
146
  }
157
- /**
158
- * Find alternative tools for a given tool name by prefix matching.
159
- * @returns Array of alternative tool names, empty if none known.
160
- */
161
- function findAlternatives(toolName) {
162
- for (const [prefix, alts] of Object.entries(TOOL_ALTERNATIVES)) {
163
- if (toolName.startsWith(prefix))
164
- return alts;
165
- }
166
- return [];
167
- }
168
147
  /**
169
148
  * When tool failures are caused by the macOS sandbox-exec profile denying writes
170
149
  * to protected paths (~/.comis/skills/, global node_modules, ~/.gitconfig,
@@ -246,6 +225,7 @@ function buildBlockReason(toolName, count, lastError, alternatives, isToolLevel)
246
225
  export function createToolRetryBreaker(config) {
247
226
  const { maxConsecutiveFailures, maxToolFailures, suggestAlternatives } = config;
248
227
  const maxErrorPatterns = config.maxConsecutiveErrorPatterns ?? 2;
228
+ const toolAlternatives = config.toolAlternatives ?? {};
249
229
  // Per-fingerprint (tool+args) consecutive failure tracking
250
230
  const signatureFailures = new Map();
251
231
  // Per-tool-name total failure count (across all args)
@@ -254,6 +234,23 @@ export function createToolRetryBreaker(config) {
254
234
  const blockedTools = new Set();
255
235
  // Per-error-pattern consecutive failure tracking (keyed by `${toolName}::err::${errorTag}`)
256
236
  const errorPatternFailures = new Map();
237
+ /**
238
+ * Find alternative tools for a given tool name by prefix matching against
239
+ * `config.toolAlternatives`. Closed-over the factory's `toolAlternatives`
240
+ * local; defaults to no alternatives when the config field is omitted.
241
+ * Spread to a fresh mutable array so the readonly-input / mutable-output
242
+ * contract documented in `ToolRetryVerdict.alternatives?: string[]` is
243
+ * preserved.
244
+ *
245
+ * @returns Array of alternative tool names, empty if no prefix match.
246
+ */
247
+ function findAlternatives(toolName) {
248
+ for (const [prefix, alts] of Object.entries(toolAlternatives)) {
249
+ if (toolName.startsWith(prefix))
250
+ return [...alts];
251
+ }
252
+ return [];
253
+ }
257
254
  return {
258
255
  beforeToolCall(toolName, args) {
259
256
  // Check tool-level block first (all args blocked)
@@ -30,11 +30,25 @@ export interface ComisSessionManagerDeps {
30
30
  * Session metadata written as a companion file alongside the JSONL.
31
31
  * The SDK controls the JSONL format, so enrichment data (traceId, runId, session_end)
32
32
  * is stored in `_session-metadata.json` next to the `.jsonl` file.
33
+ *
34
+ * `traceId` and `runId` are deliberately distinct identifiers:
35
+ * - `traceId` is the request-scope AsyncLocalStorage value set by
36
+ * `runWithContext` at the channel boundary (channels/.../execution-execute.ts).
37
+ * The Pino tracing mixin (infra/.../log-fields.ts) injects it into every
38
+ * daemon log line, so an operator can grep daemon.log for this exact value
39
+ * to find every log entry produced while handling this turn.
40
+ * - `runId` is the executor-scope UUID minted per `executor.execute()` call
41
+ * in pi-executor.ts. It keys cost-tracker / token_usage rows in the
42
+ * observability store.
43
+ *
44
+ * They are 1:1 in the steady-state interactive path (one inbound message →
45
+ * one execution), but heartbeat and sub-agent paths can fan out a single
46
+ * trace into multiple executions.
33
47
  */
34
48
  export interface SessionMetadata {
35
- /** Trace ID for cross-correlating with daemon logs */
49
+ /** Request-scope trace ID from runWithContext; matches traceId in daemon.log. */
36
50
  traceId?: string;
37
- /** Execution run ID */
51
+ /** Executor-scope run ID; keys cost-tracker / token_usage rows. */
38
52
  runId?: string;
39
53
  /** Session end marker with completion details */
40
54
  sessionEnd?: {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Pi-mono adapter wrappers for sub-agent ephemeral sessions (R-11).
2
+ * Pi-mono adapter wrappers for sub-agent ephemeral sessions.
3
3
  *
4
4
  * Provides `createEphemeralComisSessionManager()` — a zero-persistence
5
5
  * ComisSessionManager whose `withSession` uses `SessionManager.inMemory()`
@@ -1,6 +1,6 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
- * Pi-mono adapter wrappers for sub-agent ephemeral sessions (R-11).
3
+ * Pi-mono adapter wrappers for sub-agent ephemeral sessions.
4
4
  *
5
5
  * Provides `createEphemeralComisSessionManager()` — a zero-persistence
6
6
  * ComisSessionManager whose `withSession` uses `SessionManager.inMemory()`
@@ -51,10 +51,10 @@ export function createEphemeralComisSessionManager(cwd) {
51
51
  // No-op: no companion file for in-memory sessions
52
52
  },
53
53
  getSessionPath() {
54
- // 260428-iag wire-edge diagnostic: ephemeral sub-agent sessions never
55
- // persist a JSONL file, so there is no path to return. Empty string
56
- // signals "no persisted file"; the bridge's wire-diff hook short-circuits
57
- // when jsonlPath.length === 0.
54
+ // Wire-edge diagnostic: ephemeral sub-agent sessions never persist a
55
+ // JSONL file, so there is no path to return. Empty string signals
56
+ // "no persisted file"; the bridge's wire-diff hook short-circuits when
57
+ // jsonlPath.length === 0.
58
58
  return "";
59
59
  },
60
60
  };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Workspace-internal data env resolver.
3
+ *
4
+ * Returns environment variables for python/matplotlib subprocesses that
5
+ * derive ALL paths from `workspaceDir`. Avoids slow pip installs in the
6
+ * chart hot path and matplotlib Fontconfig errors from a non-writable
7
+ * default cache dir.
8
+ *
9
+ * This file contains no host-env reads. Subprocesses inheriting the
10
+ * daemon's full environment can pick up host paths (e.g.
11
+ * `/root/.cache/matplotlib`) that fail under read-only systemd hardening
12
+ * (`ProtectSystem=strict`) and leak host PATH into the agent's tool
13
+ * execution.
14
+ *
15
+ * matplotlib + python deps install into the agent workspace's `venv/`.
16
+ * The Dockerfile pre-warms the default workspace's venv at image build
17
+ * time so first-chart latency drops; subsequent chart calls reuse the
18
+ * venv. Full Docker image size goes up (acceptable trade-off).
19
+ *
20
+ * Mirrors workspace-resolver.ts's safePath + workspaceDir precedent
21
+ * (no path.join, no host-env reads).
22
+ *
23
+ * @module
24
+ */
25
+ /**
26
+ * Resolve workspace-internal env vars for python/matplotlib subprocesses.
27
+ *
28
+ * The returned record is intended to be MERGED over an existing subprocess
29
+ * env at the call site (e.g. exec-tool's `{ ...baseEnv, ...resolveDataEnv(...) }`),
30
+ * so the workspace-internal values win on collision and the host PATH /
31
+ * cache dirs are not surfaced inside the subprocess.
32
+ *
33
+ * @param opts.workspaceDir - Absolute path to the agent workspace.
34
+ * @returns env-var record suitable for `child_process.spawn(..., { env })`.
35
+ */
36
+ export declare function resolveDataEnv(opts: {
37
+ workspaceDir: string;
38
+ }): Record<string, string>;