@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2

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 (596) hide show
  1. package/AGENTS.md +9 -3
  2. package/ARCHITECTURE.md +32 -10
  3. package/docs/architecture/memory.md +43 -5
  4. package/docs/architecture/security.md +96 -152
  5. package/docs/architecture/turn-actor.md +70 -0
  6. package/docs/browser-use-architecture-phase2.md +128 -56
  7. package/docs/flux-turn-detection-spike.md +248 -0
  8. package/docs/guardian-request-flow.md +35 -0
  9. package/docs/stt-provider-onboarding.md +3 -1
  10. package/knip.json +3 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  13. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  19. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  23. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
  24. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
  25. package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
  26. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  27. package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  28. package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  29. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  30. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  31. package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  32. package/openapi.yaml +289 -113
  33. package/package.json +1 -1
  34. package/scripts/voice-ttft-spike.ts +3 -3
  35. package/scripts/write-plugin-api-shim.ts +10 -0
  36. package/src/__tests__/app-compiler.test.ts +38 -3
  37. package/src/__tests__/app-control-flow.test.ts +1 -0
  38. package/src/__tests__/approval-routes-http.test.ts +2 -2
  39. package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
  40. package/src/__tests__/attachments-store.test.ts +21 -12
  41. package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
  42. package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
  43. package/src/__tests__/call-site-routing-provider.test.ts +1 -1
  44. package/src/__tests__/channel-availability-routes.test.ts +14 -1
  45. package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
  46. package/src/__tests__/channel-delivery-store.test.ts +14 -14
  47. package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
  48. package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
  49. package/src/__tests__/checker.test.ts +20 -314
  50. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
  51. package/src/__tests__/compaction-events.test.ts +8 -10
  52. package/src/__tests__/config-loader-backfill.test.ts +3 -3
  53. package/src/__tests__/config-schema.test.ts +25 -10
  54. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  55. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
  56. package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
  57. package/src/__tests__/conversation-agent-loop.test.ts +32 -21
  58. package/src/__tests__/conversation-attachments.test.ts +0 -1
  59. package/src/__tests__/conversation-attention-store.test.ts +63 -0
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
  61. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -0
  63. package/src/__tests__/conversation-fork-referential.test.ts +67 -0
  64. package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
  65. package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
  66. package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
  67. package/src/__tests__/conversation-queue.test.ts +154 -4
  68. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
  69. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
  71. package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
  75. package/src/__tests__/conversation-slash-queue.test.ts +3 -0
  76. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  77. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
  78. package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
  79. package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
  80. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
  81. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
  82. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
  83. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
  85. package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
  86. package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
  87. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
  88. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
  89. package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
  90. package/src/__tests__/credential-prompt-route.test.ts +7 -10
  91. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  92. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  93. package/src/__tests__/custom-profile-ensure.test.ts +5 -1
  94. package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
  95. package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
  96. package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
  97. package/src/__tests__/document-append-idempotency.test.ts +233 -0
  98. package/src/__tests__/document-sync-tags.test.ts +0 -75
  99. package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
  100. package/src/__tests__/edit-propagation.test.ts +107 -11
  101. package/src/__tests__/file-ops-service.test.ts +163 -30
  102. package/src/__tests__/filesystem-tools.test.ts +23 -24
  103. package/src/__tests__/gateway-only-guard.test.ts +2 -5
  104. package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
  105. package/src/__tests__/helpers/mock-actor-context.ts +49 -0
  106. package/src/__tests__/helpers/mock-conversation.ts +13 -1
  107. package/src/__tests__/host-file-read-tool.test.ts +16 -19
  108. package/src/__tests__/http-user-message-parity.test.ts +1 -1
  109. package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
  110. package/src/__tests__/injector-chain.test.ts +63 -41
  111. package/src/__tests__/injector-disk-pressure.test.ts +11 -23
  112. package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
  113. package/src/__tests__/llm-context-resolution.test.ts +73 -1
  114. package/src/__tests__/llm-schema.test.ts +5 -2
  115. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
  116. package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
  117. package/src/__tests__/media-generate-image.test.ts +131 -21
  118. package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
  119. package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
  120. package/src/__tests__/mtime-cache.test.ts +3 -1
  121. package/src/__tests__/non-member-access-request.test.ts +0 -20
  122. package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
  123. package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
  124. package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
  125. package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
  126. package/src/__tests__/plugin-disabled-state.test.ts +2 -0
  127. package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
  128. package/src/__tests__/plugin-execution-context.test.ts +73 -0
  129. package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
  130. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
  131. package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
  132. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
  133. package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
  134. package/src/__tests__/proxy-approval-callback.test.ts +1 -0
  135. package/src/__tests__/qdrant-manager.test.ts +14 -1
  136. package/src/__tests__/reaction-persistence.test.ts +200 -7
  137. package/src/__tests__/require-fresh-approval.test.ts +0 -4
  138. package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
  139. package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
  140. package/src/__tests__/run-due-schedules.test.ts +21 -0
  141. package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
  142. package/src/__tests__/schedule-routes.test.ts +23 -0
  143. package/src/__tests__/schedule-store.test.ts +17 -0
  144. package/src/__tests__/scoped-approval-grants.test.ts +11 -6
  145. package/src/__tests__/secret-ingress-channel.test.ts +0 -1
  146. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  147. package/src/__tests__/send-endpoint-busy.test.ts +3 -3
  148. package/src/__tests__/skills.test.ts +32 -0
  149. package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
  150. package/src/__tests__/starter-task-flow.test.ts +5 -4
  151. package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
  152. package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
  153. package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
  154. package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
  155. package/src/__tests__/subagent-tools.test.ts +81 -101
  156. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
  157. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  158. package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
  159. package/src/__tests__/tool-executor.test.ts +68 -39
  160. package/src/__tests__/turn-events-store.test.ts +43 -0
  161. package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
  162. package/src/__tests__/ui-shape-teaching.test.ts +33 -0
  163. package/src/__tests__/ui-visual-surface.test.ts +1 -1
  164. package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
  165. package/src/__tests__/ui-work-result-surface.test.ts +1 -1
  166. package/src/__tests__/user-plugin-loader.test.ts +3 -1
  167. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  168. package/src/__tests__/visible-app-context.test.ts +16 -9
  169. package/src/__tests__/voice-config-update.test.ts +40 -0
  170. package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
  171. package/src/__tests__/voice-session-bridge.test.ts +85 -29
  172. package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
  173. package/src/__tests__/worker-plugin-surface.test.ts +77 -0
  174. package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
  175. package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
  176. package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
  177. package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
  178. package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
  179. package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
  180. package/src/acp/__tests__/auth-required.test.ts +161 -0
  181. package/src/acp/acp-claude-oauth.ts +19 -2
  182. package/src/acp/agent-process.test.ts +100 -0
  183. package/src/acp/agent-process.ts +29 -26
  184. package/src/acp/auth-required.ts +102 -0
  185. package/src/acp/session-manager.test.ts +119 -0
  186. package/src/acp/session-manager.ts +76 -3
  187. package/src/api/events/acp-auth-required.ts +55 -0
  188. package/src/api/events/host-file.ts +2 -2
  189. package/src/api/index.ts +7 -0
  190. package/src/api/surfaces.ts +12 -3
  191. package/src/apps/app-store.ts +3 -0
  192. package/src/bundler/package-resolver.ts +2 -30
  193. package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
  194. package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
  195. package/src/calls/call-controller.ts +19 -3
  196. package/src/calls/call-setup-flow.ts +0 -1
  197. package/src/calls/media-stream-stt-session.ts +15 -0
  198. package/src/calls/voice-session-bridge.ts +115 -41
  199. package/src/calls/voice-triage-escalate.ts +105 -2
  200. package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
  201. package/src/channels/config.ts +13 -0
  202. package/src/channels/plugin-channel-declarations.ts +108 -0
  203. package/src/channels/types.ts +30 -0
  204. package/src/cli/AGENTS.md +5 -2
  205. package/src/cli/bundled-modules.ts +29 -0
  206. package/src/cli/commands/credentials.help.ts +2 -2
  207. package/src/cli/commands/db/repair.ts +4 -8
  208. package/src/cli/commands/domain.ts +6 -3
  209. package/src/cli/commands/email.ts +6 -3
  210. package/src/cli/commands/inference-providers.ts +1 -1
  211. package/src/cli/commands/keys.ts +8 -3
  212. package/src/cli/commands/mcp.help.ts +13 -4
  213. package/src/cli/commands/mcp.ts +9 -0
  214. package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
  215. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
  216. package/src/cli/commands/memory/index.help.ts +84 -28
  217. package/src/cli/commands/memory/index.ts +2 -0
  218. package/src/cli/commands/memory/memory-v2.ts +58 -54
  219. package/src/cli/commands/memory/memory-v3.ts +64 -0
  220. package/src/cli/commands/memory/memory-validate.ts +18 -0
  221. package/src/cli/commands/plugins.ts +85 -36
  222. package/src/cli/commands/schedules.ts +35 -1
  223. package/src/cli/commands/stt.help.ts +27 -2
  224. package/src/cli/commands/trust.ts +3 -14
  225. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
  226. package/src/cli/lib/bundled-marketplace.json +14 -1
  227. package/src/cli/lib/upgrade-plugin.ts +42 -0
  228. package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
  229. package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
  230. package/src/config/__tests__/default-provider.test.ts +6 -1
  231. package/src/config/__tests__/profile-materialization.test.ts +75 -19
  232. package/src/config/assistant-feature-flags.ts +36 -15
  233. package/src/config/balanced-model-experiment.ts +35 -0
  234. package/src/config/bundled-skills/acp/SKILL.md +6 -7
  235. package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
  236. package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
  237. package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
  238. package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
  240. package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
  241. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  242. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
  243. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
  244. package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
  245. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
  246. package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
  247. package/src/config/bundled-skills/subagent/SKILL.md +17 -12
  248. package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
  249. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
  250. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
  251. package/src/config/call-site-defaults.ts +11 -5
  252. package/src/config/default-profile-catalog.ts +179 -16
  253. package/src/config/default-profile-names.ts +4 -1
  254. package/src/config/default-provider-resolution.ts +4 -0
  255. package/src/config/feature-flag-registry.json +12 -12
  256. package/src/config/llm-context-resolution.ts +11 -3
  257. package/src/config/llm-resolver.ts +28 -1
  258. package/src/config/profile-materialization.ts +70 -22
  259. package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
  260. package/src/config/schemas/call-site-catalog.ts +4 -4
  261. package/src/config/schemas/live-voice.ts +57 -23
  262. package/src/config/schemas/llm.ts +59 -32
  263. package/src/config/schemas/mcp.ts +23 -0
  264. package/src/config/schemas/plugin-updates.ts +6 -2
  265. package/src/config/schemas/stt.ts +1 -0
  266. package/src/config/skills.ts +9 -2
  267. package/src/context/outbound-sanitize.ts +96 -1
  268. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
  269. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
  270. package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
  271. package/src/daemon/conversation-agent-loop.ts +31 -19
  272. package/src/daemon/conversation-messaging.ts +5 -1
  273. package/src/daemon/conversation-notifiers.ts +20 -10
  274. package/src/daemon/conversation-process.ts +20 -6
  275. package/src/daemon/conversation-runtime-assembly.ts +12 -6
  276. package/src/daemon/conversation-store.ts +14 -4
  277. package/src/daemon/conversation-surfaces.ts +75 -26
  278. package/src/daemon/conversation-tool-setup.ts +3 -6
  279. package/src/daemon/conversation.ts +154 -51
  280. package/src/daemon/doordash-steps.ts +2 -2
  281. package/src/daemon/lifecycle.ts +14 -1
  282. package/src/daemon/mcp-reload-service.ts +36 -6
  283. package/src/daemon/process-message.ts +13 -26
  284. package/src/daemon/providers-setup.ts +6 -3
  285. package/src/daemon/trust-context-types.ts +29 -0
  286. package/src/daemon/trust-context.ts +12 -7
  287. package/src/daemon/wake-conversation-ops.ts +3 -2
  288. package/src/daemon/windows-compiled-entry.ts +4 -0
  289. package/src/documents/document-store.ts +143 -240
  290. package/src/hooks/hook-loader.ts +3 -3
  291. package/src/hooks/registry.ts +103 -45
  292. package/src/hooks/types.ts +5 -0
  293. package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
  294. package/src/inbound/oauth-callback-url.ts +61 -0
  295. package/src/ipc/gateway-client.test.ts +1 -1
  296. package/src/ipc/gateway-client.ts +14 -21
  297. package/src/ipc/gateway-flag-listener.ts +17 -3
  298. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
  299. package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
  300. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
  301. package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
  302. package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
  303. package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
  304. package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
  305. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
  306. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
  307. package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
  308. package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
  309. package/src/live-voice/live-voice-archive.ts +2 -0
  310. package/src/live-voice/live-voice-manager.ts +16 -3
  311. package/src/live-voice/live-voice-metrics.ts +57 -32
  312. package/src/live-voice/live-voice-photo.ts +1 -2
  313. package/src/live-voice/live-voice-session.ts +598 -323
  314. package/src/live-voice/progress-narration.ts +277 -0
  315. package/src/live-voice/protocol.ts +21 -1
  316. package/src/live-voice/windows-compiled-live-voice.ts +4 -0
  317. package/src/mcp/__tests__/effective-config.test.ts +238 -0
  318. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  319. package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
  320. package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
  321. package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
  322. package/src/mcp/client.ts +16 -11
  323. package/src/mcp/effective-config.ts +113 -0
  324. package/src/mcp/manager.ts +11 -6
  325. package/src/mcp/mcp-auth-orchestrator.ts +13 -22
  326. package/src/mcp/mcp-oauth-provider.ts +205 -240
  327. package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
  328. package/src/monitoring/control.ts +1 -0
  329. package/src/monitoring/db-integrity-sample.ts +4 -5
  330. package/src/monitoring/plugin-auto-update.ts +128 -24
  331. package/src/notifications/AGENTS.md +2 -0
  332. package/src/notifications/approval-card-data.ts +33 -0
  333. package/src/notifications/signal.ts +1 -0
  334. package/src/permissions/AGENTS.md +16 -0
  335. package/src/permissions/checker.test.ts +75 -122
  336. package/src/permissions/checker.ts +44 -560
  337. package/src/permissions/confirmation-guardian-request.test.ts +15 -11
  338. package/src/permissions/confirmation-guardian-request.ts +2 -2
  339. package/src/permissions/prompter.ts +1 -5
  340. package/src/permissions/question-guardian-request.test.ts +14 -6
  341. package/src/permissions/question-guardian-request.ts +1 -2
  342. package/src/persistence/attachments-store.ts +8 -1
  343. package/src/persistence/bookmark-crud.ts +3 -7
  344. package/src/persistence/conversation-attention-store.ts +16 -45
  345. package/src/persistence/conversation-crud.ts +33 -4
  346. package/src/persistence/conversation-lineage.ts +9 -0
  347. package/src/persistence/conversation-queries.ts +182 -52
  348. package/src/persistence/delivery-crud.ts +150 -36
  349. package/src/persistence/embeddings/qdrant-manager.ts +84 -49
  350. package/src/persistence/external-conversation-store.ts +32 -4
  351. package/src/persistence/llm-request-log-store.ts +4 -10
  352. package/src/persistence/llm-usage-store.ts +8 -3
  353. package/src/persistence/message-reads.test.ts +197 -0
  354. package/src/persistence/message-reads.ts +211 -0
  355. package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
  356. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
  357. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
  358. package/src/persistence/real-user-turn-filter.ts +27 -3
  359. package/src/persistence/schema/documents.ts +4 -4
  360. package/src/persistence/steps.ts +9 -0
  361. package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
  362. package/src/plugin-api/constants.ts +8 -0
  363. package/src/plugin-api/conversation-turn.ts +195 -5
  364. package/src/plugin-api/index.ts +38 -6
  365. package/src/plugin-api/resolve-credential.ts +3 -2
  366. package/src/plugin-api/store-credential.ts +146 -0
  367. package/src/plugin-api/vision-support.test.ts +1 -1
  368. package/src/plugin-api/webhook-url.ts +13 -11
  369. package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
  370. package/src/plugins/defaults/main.ts +21 -7
  371. package/src/plugins/defaults/memory/AGENTS.md +15 -3
  372. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
  373. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
  374. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
  375. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
  376. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
  377. package/src/plugins/defaults/memory/buffer-format.ts +165 -0
  378. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
  379. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
  380. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
  381. package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
  382. package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
  383. package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
  384. package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
  385. package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
  386. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
  387. package/src/plugins/defaults/memory/indexer.ts +3 -1
  388. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
  389. package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
  390. package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
  391. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
  392. package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
  393. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
  394. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
  395. package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
  396. package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
  397. package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
  398. package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
  399. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
  400. package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
  401. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
  402. package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
  403. package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
  404. package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
  405. package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
  406. package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
  407. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
  408. package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
  409. package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
  410. package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
  411. package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
  412. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
  413. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
  414. package/src/plugins/defaults/memory/v3/card.ts +9 -9
  415. package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
  416. package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
  417. package/src/plugins/defaults/memory/v3/edge.ts +13 -57
  418. package/src/plugins/defaults/memory/v3/injector.ts +8 -0
  419. package/src/plugins/defaults/memory/v3/prune.ts +2 -0
  420. package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
  421. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
  422. package/src/plugins/defaults/memory/worker-control.ts +1 -0
  423. package/src/plugins/defaults/memory/worker.ts +6 -3
  424. package/src/plugins/defaults/worker-entrypoints.ts +3 -0
  425. package/src/plugins/external-plugin-loader.ts +47 -0
  426. package/src/plugins/mcp-servers.ts +361 -0
  427. package/src/plugins/mtime-cache.ts +37 -46
  428. package/src/plugins/pipeline.ts +14 -7
  429. package/src/plugins/plugin-execution-context.ts +35 -11
  430. package/src/plugins/worker-plugin-surface.ts +33 -0
  431. package/src/prompts/templates/system-sections.ts +0 -7
  432. package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
  433. package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
  434. package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
  435. package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
  436. package/src/providers/__tests__/retry-callsite.test.ts +25 -2
  437. package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
  438. package/src/providers/anthropic/client.ts +332 -241
  439. package/src/providers/call-site-routing.ts +30 -3
  440. package/src/providers/connection-resolution.ts +194 -11
  441. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
  442. package/src/providers/inference/adapter-factory.ts +3 -0
  443. package/src/providers/inference/auth.ts +6 -0
  444. package/src/providers/inference/connection-availability.ts +24 -2
  445. package/src/providers/inference/connections.ts +2 -0
  446. package/src/providers/model-catalog.ts +3 -3
  447. package/src/providers/model-intents.ts +28 -8
  448. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
  449. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
  450. package/src/providers/openai/chat-completions-provider.ts +133 -36
  451. package/src/providers/openai/codex-models.ts +2 -1
  452. package/src/providers/provider-send-message.ts +32 -3
  453. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
  454. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
  455. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
  456. package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
  457. package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
  458. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
  459. package/src/providers/speech-to-text/provider-catalog.ts +99 -8
  460. package/src/providers/speech-to-text/resolve.ts +25 -2
  461. package/src/routes/control.ts +1 -0
  462. package/src/routes/route-host-client.ts +1 -0
  463. package/src/routes/route-host-protocol.ts +7 -0
  464. package/src/routes/worker.ts +48 -15
  465. package/src/runtime/AGENTS.md +16 -17
  466. package/src/runtime/access-request-helper.ts +9 -12
  467. package/src/runtime/agent-wake.ts +18 -15
  468. package/src/runtime/effective-capabilities.test.ts +43 -0
  469. package/src/runtime/effective-capabilities.ts +27 -0
  470. package/src/runtime/guardian-reply-router.ts +6 -2
  471. package/src/runtime/pre-first-message-gate.ts +4 -0
  472. package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
  473. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
  474. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
  475. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
  476. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
  477. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
  478. package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
  479. package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
  480. package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
  481. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
  482. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
  483. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
  484. package/src/runtime/routes/channel-availability-routes.ts +32 -14
  485. package/src/runtime/routes/channel-route-shared.ts +0 -6
  486. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
  487. package/src/runtime/routes/conversation-list-routes.ts +181 -23
  488. package/src/runtime/routes/conversation-management-routes.ts +17 -12
  489. package/src/runtime/routes/conversation-query-routes.ts +40 -27
  490. package/src/runtime/routes/conversation-routes.ts +43 -29
  491. package/src/runtime/routes/credential-prompt-routes.ts +4 -7
  492. package/src/runtime/routes/credential-routes.ts +26 -82
  493. package/src/runtime/routes/default-provider-routes.ts +15 -0
  494. package/src/runtime/routes/documents-routes.ts +3 -222
  495. package/src/runtime/routes/inbound-message-handler.ts +21 -45
  496. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
  497. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
  498. package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
  499. package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
  500. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
  501. package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
  502. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
  503. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
  504. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
  505. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
  506. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
  507. package/src/runtime/routes/inference-profiles-routes.ts +20 -11
  508. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
  509. package/src/runtime/routes/log-export-routes.ts +3 -0
  510. package/src/runtime/routes/mcp-auth-routes.ts +148 -57
  511. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
  512. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
  513. package/src/runtime/routes/playground/inject-failures.ts +2 -2
  514. package/src/runtime/routes/playground/reset-circuit.ts +1 -1
  515. package/src/runtime/routes/plugins-routes.ts +38 -8
  516. package/src/runtime/routes/schedule-routes.ts +94 -7
  517. package/src/runtime/routes/settings-routes.ts +6 -6
  518. package/src/runtime/routes/stt-routes.ts +31 -25
  519. package/src/runtime/routes/surface-action-routes.ts +20 -19
  520. package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
  521. package/src/runtime/routes/user-route-dispatcher.ts +69 -15
  522. package/src/runtime/routes/user-route-import.ts +108 -0
  523. package/src/runtime/routes/user-route-resolution.ts +18 -1
  524. package/src/runtime/routes/workspace-routes.ts +0 -9
  525. package/src/runtime/routes/workspace-utils.ts +3 -13
  526. package/src/runtime/services/conversation-serializer.ts +7 -2
  527. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
  528. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
  529. package/src/schedule/plugin-schedule-availability.ts +58 -0
  530. package/src/schedule/plugin-schedule-declarations.ts +23 -27
  531. package/src/schedule/plugin-schedule-reconciler.ts +12 -3
  532. package/src/schedule/schedule-store.ts +5 -1
  533. package/src/schedule/scheduler.ts +9 -4
  534. package/src/schedule/worker-control.ts +1 -0
  535. package/src/schedule/worker.ts +6 -0
  536. package/src/security/oauth2.ts +6 -22
  537. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
  538. package/src/stt/__tests__/types.test.ts +94 -0
  539. package/src/stt/daemon-batch-transcriber.ts +10 -0
  540. package/src/stt/stt-stream-session.ts +8 -4
  541. package/src/stt/types.ts +103 -0
  542. package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
  543. package/src/subagent/consult-context.ts +11 -11
  544. package/src/subagent/consult-prompt.ts +26 -35
  545. package/src/subagent/manager.ts +21 -40
  546. package/src/subagent/notify.ts +7 -1
  547. package/src/subagent/types.ts +15 -12
  548. package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
  549. package/src/tools/acp/spawn.test.ts +97 -0
  550. package/src/tools/acp/spawn.ts +38 -4
  551. package/src/tools/credentials/ref-parse.ts +35 -0
  552. package/src/tools/credentials/resolve.ts +4 -10
  553. package/src/tools/credentials/store.ts +168 -0
  554. package/src/tools/document/document-tool.ts +12 -3
  555. package/src/tools/executor.ts +53 -15
  556. package/src/tools/filesystem/read.ts +27 -10
  557. package/src/tools/host-filesystem/read.ts +27 -15
  558. package/src/tools/network/url-safety.ts +9 -16
  559. package/src/tools/permission-checker.ts +43 -52
  560. package/src/tools/registry.ts +2 -1
  561. package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
  562. package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
  563. package/src/tools/shared/filesystem/types.ts +5 -5
  564. package/src/tools/skills/scaffold-managed.ts +25 -7
  565. package/src/tools/subagent/spawn.ts +28 -88
  566. package/src/tools/tool-types.ts +26 -13
  567. package/src/tools/types.ts +6 -6
  568. package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
  569. package/src/tools/workflows/run-workflow.ts +1 -2
  570. package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
  571. package/src/tts/reasoning-tag-filter.ts +89 -0
  572. package/src/util/__tests__/worker-process-command.test.ts +37 -0
  573. package/src/util/logger.ts +16 -0
  574. package/src/util/think-tag-stream.ts +95 -0
  575. package/src/util/worker-process.ts +37 -4
  576. package/src/windows-compiled-cli.ts +32 -0
  577. package/src/windows-compiled-entry.ts +4 -0
  578. package/src/windows-compiled-logger.ts +6 -0
  579. package/src/windows-compiled-worker-entry.ts +29 -0
  580. package/src/workspace/byok-default-profile-ensure.ts +76 -24
  581. package/src/workspace/custom-profile-ensure.ts +4 -24
  582. package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
  583. package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
  584. package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
  585. package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
  586. package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
  587. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
  588. package/src/workspace/migrations/registry.ts +10 -0
  589. package/src/workspace/provider-commit-message-generator.ts +7 -5
  590. package/src/__tests__/document-workspace-file.test.ts +0 -467
  591. package/src/live-voice/__tests__/front-decision.test.ts +0 -645
  592. package/src/live-voice/front-decision.ts +0 -476
  593. package/src/permissions/ipc-risk-types.ts +0 -143
  594. package/src/permissions/risk-types.ts +0 -76
  595. package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
  596. package/src/subagent/consult-transcript.ts +0 -90
@@ -39,6 +39,7 @@ mock.module("../util/logger.js", () => ({
39
39
 
40
40
  import {
41
41
  installIpcMock,
42
+ lastIpcParams,
42
43
  mockIpcResponse,
43
44
  } from "./helpers/gateway-classify-mock.js";
44
45
  installIpcMock();
@@ -53,7 +54,8 @@ function mockRisk(
53
54
  mockIpcResponse("classify_risk", {
54
55
  risk,
55
56
  reason: "test fixture",
56
- matchType: "shell",
57
+ matchType: "registry",
58
+ scopeOptions: [],
57
59
  ...extras,
58
60
  });
59
61
  }
@@ -82,8 +84,6 @@ import * as envRegistry from "../config/env-registry.js";
82
84
  import {
83
85
  check,
84
86
  classifyRisk,
85
- clearRiskCache,
86
- generateAllowlistOptions,
87
87
  generateScopeOptions,
88
88
  SCOPE_AWARE_TOOLS,
89
89
  } from "../permissions/checker.js";
@@ -180,8 +180,6 @@ describe("Permission Checker", () => {
180
180
  mockIpcResponse("get_global_thresholds", DEFAULT_GATEWAY_THRESHOLDS);
181
181
  // Clear the gateway threshold cache so each test gets a fresh threshold read
182
182
  _clearGlobalCacheForTesting();
183
- // Reset trust-store state and risk classification cache between tests
184
- clearRiskCache();
185
183
  // Reset guardian persona mock so each test opts in explicitly
186
184
  mockGuardianPersonaPath = null;
187
185
  loggerWarnCalls.length = 0;
@@ -447,268 +445,6 @@ describe("Permission Checker", () => {
447
445
  });
448
446
  });
449
447
 
450
- // ── generateAllowlistOptions ───────────────────────────────────
451
-
452
- describe("generateAllowlistOptions", () => {
453
- test("file_write: generates prefixed file, ancestor directory wildcards, and tool wildcard", async () => {
454
- const options = await generateAllowlistOptions("file_write", {
455
- path: "/home/user/project/file.ts",
456
- });
457
- expect(options).toHaveLength(5);
458
- // Patterns are prefixed with tool name to match check()'s "tool:path" format
459
- expect(options[0].pattern).toBe("file_write:/home/user/project/file.ts");
460
- expect(options[1].pattern).toBe("file_write:/home/user/project/**");
461
- expect(options[2].pattern).toBe("file_write:/home/user/**");
462
- expect(options[3].pattern).toBe("file_write:/home/**");
463
- expect(options[4].pattern).toBe("file_write:*");
464
- // Labels stay user-friendly
465
- expect(options[0].label).toBe("/home/user/project/file.ts");
466
- expect(options[1].label).toBe("/home/user/project/**");
467
- });
468
-
469
- test("file_read: generates prefixed file, directory, and tool wildcard", async () => {
470
- const options = await generateAllowlistOptions("file_read", {
471
- path: "/tmp/data.json",
472
- });
473
- expect(options).toHaveLength(3);
474
- expect(options[0].pattern).toBe("file_read:/tmp/data.json");
475
- expect(options[1].pattern).toBe("file_read:/tmp/**");
476
- expect(options[2].pattern).toBe("file_read:*");
477
- });
478
-
479
- test("host_file_read: generates prefixed file, directory, and tool wildcard", async () => {
480
- const options = await generateAllowlistOptions("host_file_read", {
481
- path: "/etc/hosts",
482
- });
483
- expect(options).toHaveLength(3);
484
- expect(options[0].pattern).toBe("host_file_read:/etc/hosts");
485
- expect(options[1].pattern).toBe("host_file_read:/etc/**");
486
- expect(options[2].pattern).toBe("host_file_read:*");
487
- });
488
-
489
- test("host_file_write with file_path key", async () => {
490
- const options = await generateAllowlistOptions("host_file_write", {
491
- file_path: "/tmp/out.txt",
492
- });
493
- expect(options[0].pattern).toBe("host_file_write:/tmp/out.txt");
494
- expect(options[1].pattern).toBe("host_file_write:/tmp/**");
495
- expect(options[2].pattern).toBe("host_file_write:*");
496
- });
497
-
498
- test("file_write with file_path key", async () => {
499
- const options = await generateAllowlistOptions("file_write", {
500
- file_path: "/tmp/out.txt",
501
- });
502
- expect(options[0].pattern).toBe("file_write:/tmp/out.txt");
503
- });
504
-
505
- test("unknown tool returns wildcard", async () => {
506
- const options = await generateAllowlistOptions("other_tool", {
507
- foo: "bar",
508
- });
509
- expect(options).toHaveLength(1);
510
- expect(options[0].pattern).toBe("*");
511
- });
512
-
513
- test("web_fetch: generates exact url, origin wildcard, and tool wildcard", async () => {
514
- const options = await generateAllowlistOptions("web_fetch", {
515
- url: "https://example.com/docs/page",
516
- });
517
- expect(options).toHaveLength(3);
518
- expect(options[0].pattern).toBe(
519
- "web_fetch:https://example.com/docs/page",
520
- );
521
- expect(options[1].pattern).toBe("web_fetch:https://example.com/*");
522
- expect(options[2].pattern).toBe("**");
523
- });
524
-
525
- test("web_fetch: strips fragments when generating allowlist options", async () => {
526
- const options = await generateAllowlistOptions("web_fetch", {
527
- url: "https://example.com/docs/page#section-1",
528
- });
529
- expect(options).toHaveLength(3);
530
- expect(options[0].pattern).toBe(
531
- "web_fetch:https://example.com/docs/page",
532
- );
533
- expect(options[1].pattern).toBe("web_fetch:https://example.com/*");
534
- expect(options[2].pattern).toBe("**");
535
- });
536
-
537
- test("web_fetch: strips trailing-dot hostnames when generating allowlist options", async () => {
538
- const options = await generateAllowlistOptions("web_fetch", {
539
- url: "https://example.com./docs/page",
540
- });
541
- expect(options).toHaveLength(3);
542
- expect(options[0].pattern).toBe(
543
- "web_fetch:https://example.com/docs/page",
544
- );
545
- expect(options[1].pattern).toBe("web_fetch:https://example.com/*");
546
- expect(options[2].pattern).toBe("**");
547
- });
548
-
549
- test("web_fetch: strips userinfo when generating allowlist options", async () => {
550
- const username = "demo";
551
- const credential = ["c", "r", "e", "d", "1", "2", "3"].join("");
552
- const credentialedUrl = new URL("https://example.com/docs/page");
553
- credentialedUrl.username = username;
554
- credentialedUrl.password = credential;
555
- const options = await generateAllowlistOptions("web_fetch", {
556
- url: credentialedUrl.href,
557
- });
558
- expect(options).toHaveLength(3);
559
- expect(options[0].pattern).toBe(
560
- "web_fetch:https://example.com/docs/page",
561
- );
562
- expect(options[1].pattern).toBe("web_fetch:https://example.com/*");
563
- expect(options[2].pattern).toBe("**");
564
- expect(options[0].pattern).not.toContain("demo:cred123@");
565
- });
566
-
567
- test("web_fetch: normalizes scheme-less host:port for allowlist options", async () => {
568
- const options = await generateAllowlistOptions("web_fetch", {
569
- url: "example.com:8443/docs/page",
570
- });
571
- expect(options).toHaveLength(3);
572
- expect(options[0].pattern).toBe(
573
- "web_fetch:https://example.com:8443/docs/page",
574
- );
575
- expect(options[1].pattern).toBe("web_fetch:https://example.com:8443/*");
576
- expect(options[2].pattern).toBe("**");
577
- });
578
-
579
- test("web_fetch: does not coerce path-only urls to https hostnames in allowlist options", async () => {
580
- const options = await generateAllowlistOptions("web_fetch", {
581
- url: "/docs/getting-started",
582
- });
583
- expect(options).toHaveLength(2);
584
- expect(options[0].pattern).toBe("web_fetch:/docs/getting-started");
585
- expect(options[1].pattern).toBe("**");
586
- });
587
-
588
- test("scaffold_managed_skill: generates per-skill and wildcard options", async () => {
589
- const options = await generateAllowlistOptions("scaffold_managed_skill", {
590
- skill_id: "my-tool",
591
- });
592
- expect(options).toHaveLength(2);
593
- expect(options[0].label).toBe("my-tool");
594
- expect(options[0].pattern).toBe("scaffold_managed_skill:my-tool");
595
- expect(options[0].description).toBe("This skill only");
596
- expect(options[1].label).toBe("scaffold_managed_skill:*");
597
- expect(options[1].pattern).toBe("scaffold_managed_skill:*");
598
- expect(options[1].description).toBe("All managed skill scaffolds");
599
- });
600
-
601
- test("delete_managed_skill: generates per-skill and wildcard options", async () => {
602
- const options = await generateAllowlistOptions("delete_managed_skill", {
603
- skill_id: "doomed",
604
- });
605
- expect(options).toHaveLength(2);
606
- expect(options[0].pattern).toBe("delete_managed_skill:doomed");
607
- expect(options[1].pattern).toBe("delete_managed_skill:*");
608
- expect(options[1].description).toBe("All managed skill deletes");
609
- });
610
-
611
- test("scaffold_managed_skill with empty skill_id: only wildcard option", async () => {
612
- const options = await generateAllowlistOptions("scaffold_managed_skill", {
613
- skill_id: "",
614
- });
615
- expect(options).toHaveLength(1);
616
- expect(options[0].pattern).toBe("scaffold_managed_skill:*");
617
- });
618
-
619
- test("web_fetch: escapes minimatch metacharacters in generated exact and origin patterns", async () => {
620
- const options = await generateAllowlistOptions("web_fetch", {
621
- url: "https://[2001:db8::1]/search?q=test",
622
- });
623
- expect(options).toHaveLength(3);
624
- expect(options[0].label).toBe("https://[2001:db8::1]/search?q=test");
625
- expect(options[0].pattern).toBe(
626
- "web_fetch:https://\\[2001:db8::1\\]/search\\?q=test",
627
- );
628
- expect(options[1].pattern).toBe("web_fetch:https://\\[2001:db8::1\\]/*");
629
- expect(options[2].pattern).toBe("**");
630
- });
631
-
632
- // ── network_request allowlist options ─────────────────────────
633
-
634
- test("network_request: generates exact url, origin wildcard, and tool wildcard", async () => {
635
- const options = await generateAllowlistOptions("network_request", {
636
- url: "https://api.example.com/v1/data",
637
- });
638
- expect(options).toHaveLength(3);
639
- expect(options[0].pattern).toBe(
640
- "network_request:https://api.example.com/v1/data",
641
- );
642
- expect(options[1].pattern).toBe(
643
- "network_request:https://api.example.com/*",
644
- );
645
- expect(options[2].pattern).toBe("**");
646
- expect(options[2].label).toBe("network_request:*");
647
- expect(options[2].description).toBe("All network requests");
648
- });
649
-
650
- test("network_request: origin wildcard uses friendly hostname", async () => {
651
- const options = await generateAllowlistOptions("network_request", {
652
- url: "https://www.example.com/path",
653
- });
654
- expect(options[1].description).toBe("Any page on example.com");
655
- });
656
-
657
- test("network_request: normalizes scheme-less host:port input", async () => {
658
- const options = await generateAllowlistOptions("network_request", {
659
- url: "api.example.com:8443/v1/data",
660
- });
661
- expect(options).toHaveLength(3);
662
- expect(options[0].pattern).toBe(
663
- "network_request:https://api.example.com:8443/v1/data",
664
- );
665
- expect(options[1].pattern).toBe(
666
- "network_request:https://api.example.com:8443/*",
667
- );
668
- expect(options[2].pattern).toBe("**");
669
- });
670
-
671
- test("network_request: strips fragments and userinfo", async () => {
672
- const username = "demo";
673
- const credential = ["c", "r", "e", "d", "1", "2", "3"].join("");
674
- const credentialedUrl = new URL(
675
- "https://api.example.com/v1/data#section",
676
- );
677
- credentialedUrl.username = username;
678
- credentialedUrl.password = credential;
679
- const options = await generateAllowlistOptions("network_request", {
680
- url: credentialedUrl.href,
681
- });
682
- expect(options).toHaveLength(3);
683
- expect(options[0].pattern).toBe(
684
- "network_request:https://api.example.com/v1/data",
685
- );
686
- expect(options[0].pattern).not.toContain("demo:cred123@");
687
- expect(options[0].pattern).not.toContain("#section");
688
- });
689
-
690
- test("network_request: escapes minimatch metacharacters", async () => {
691
- const options = await generateAllowlistOptions("network_request", {
692
- url: "https://[2001:db8::1]/api?key=val",
693
- });
694
- expect(options).toHaveLength(3);
695
- expect(options[0].pattern).toBe(
696
- "network_request:https://\\[2001:db8::1\\]/api\\?key=val",
697
- );
698
- expect(options[1].pattern).toBe(
699
- "network_request:https://\\[2001:db8::1\\]/*",
700
- );
701
- });
702
-
703
- test("network_request: empty url produces only tool wildcard", async () => {
704
- const options = await generateAllowlistOptions("network_request", {
705
- url: "",
706
- });
707
- expect(options).toHaveLength(1);
708
- expect(options[0].pattern).toBe("**");
709
- });
710
- });
711
-
712
448
  // ── generateScopeOptions ───────────────────────────────────────
713
449
 
714
450
  describe("generateScopeOptions", () => {
@@ -1287,65 +1023,39 @@ describe("Permission Checker", () => {
1287
1023
  // pattern (skillId@hash) and an any-version pattern (bare skillId).
1288
1024
  // Input-supplied version_hash is always ignored to prevent spoofing.
1289
1025
 
1290
- describe("hash-aware skill_load permission candidates (PR 33)", () => {
1026
+ describe("skill metadata sent to the gateway", () => {
1291
1027
  function ensureSkillsDir(): void {
1292
1028
  mkdirSync(join(checkerTestDir, "skills"), { recursive: true });
1293
1029
  }
1294
1030
 
1295
- test("allowlist options only include version-specific option when hash is available", async () => {
1296
- ensureSkillsDir();
1297
- writeSkill("test-opts-skill", "Test Options Skill");
1298
-
1299
- const options = await generateAllowlistOptions("skill_load", {
1300
- skill: "test-opts-skill",
1301
- });
1302
-
1303
- // Should have only the version-specific option
1304
- expect(options).toHaveLength(1);
1305
- expect(options[0].pattern).toMatch(/^skill_load:test-opts-skill@v1:/);
1306
- expect(options[0].description).toBe("This exact version");
1307
- });
1308
-
1309
- test("allowlist options ignore input version_hash and use disk-computed hash (regression)", async () => {
1031
+ test("the version hash comes from disk, never from the model's input", async () => {
1032
+ // The gateway builds the version-pinned trust-rule option from the hash
1033
+ // the daemon sends; taking it from the invocation would let a caller pin
1034
+ // a rule to a version that was never on disk.
1310
1035
  ensureSkillsDir();
1311
1036
  writeSkill("test-opts-explicit", "Test Opts Explicit");
1312
1037
 
1313
- // Even when a version_hash is supplied in the input, allowlist
1314
- // options must use the disk-computed hash, not the input value.
1315
- const options = await generateAllowlistOptions("skill_load", {
1038
+ await classifyRisk("skill_load", {
1316
1039
  skill: "test-opts-explicit",
1317
1040
  version_hash: "v1:customhash123",
1318
1041
  });
1319
1042
 
1320
- expect(options).toHaveLength(1);
1321
- // Should be the disk-computed hash, NOT the input hash
1322
- expect(options[0].pattern).toMatch(/^skill_load:test-opts-explicit@v1:/);
1323
- expect(options[0].pattern).not.toBe(
1324
- "skill_load:test-opts-explicit@v1:customhash123",
1325
- );
1326
- expect(options[0].description).toBe("This exact version");
1043
+ const metadata = lastIpcParams("classify_risk")?.skillMetadata as
1044
+ | { skillId: string; versionHash: string }
1045
+ | undefined;
1046
+ expect(metadata?.skillId).toBe("test-opts-explicit");
1047
+ expect(metadata?.versionHash).toMatch(/^v1:/);
1048
+ expect(metadata?.versionHash).not.toBe("v1:customhash123");
1327
1049
  });
1328
1050
 
1329
- test("allowlist options for unresolvable skill fall back to raw selector", async () => {
1051
+ test("an unresolvable selector is sent with no metadata", async () => {
1330
1052
  ensureSkillsDir();
1331
1053
 
1332
- const options = await generateAllowlistOptions("skill_load", {
1333
- skill: "no-such-skill",
1334
- });
1335
-
1336
- // Should have only the raw selector
1337
- expect(options).toHaveLength(1);
1338
- expect(options[0].pattern).toBe("skill_load:no-such-skill");
1339
- expect(options[0].description).toBe("This skill");
1340
- });
1341
-
1342
- test("allowlist options for empty skill selector only has wildcard", async () => {
1343
- const options = await generateAllowlistOptions("skill_load", {
1344
- skill: "",
1345
- });
1054
+ await classifyRisk("skill_load", { skill: "no-such-skill" });
1346
1055
 
1347
- expect(options).toHaveLength(1);
1348
- expect(options[0].pattern).toBe("skill_load:*");
1056
+ const params = lastIpcParams("classify_risk");
1057
+ expect(params?.skill).toBe("no-such-skill");
1058
+ expect(params?.skillMetadata).toBeUndefined();
1349
1059
  });
1350
1060
  });
1351
1061
 
@@ -1514,7 +1224,6 @@ describe("bash network_mode=proxied — risk capped at medium", () => {
1514
1224
  mockRisk("low");
1515
1225
  mockIpcResponse("get_global_thresholds", DEFAULT_GATEWAY_THRESHOLDS);
1516
1226
  _clearGlobalCacheForTesting();
1517
- clearRiskCache();
1518
1227
  });
1519
1228
 
1520
1229
  test("proxied bash follows risk-based policy (medium risk → prompt outside container)", async () => {
@@ -1562,7 +1271,6 @@ describe("credentialed proxied bash — high risk escalation", () => {
1562
1271
  mockRisk("low");
1563
1272
  mockIpcResponse("get_global_thresholds", DEFAULT_GATEWAY_THRESHOLDS);
1564
1273
  _clearGlobalCacheForTesting();
1565
- clearRiskCache();
1566
1274
  });
1567
1275
 
1568
1276
  test("proxied bash with credential_ids sends credentialRefCount in IPC params", async () => {
@@ -1652,7 +1360,6 @@ describe("workspace mode — auto-allow workspace-scoped operations", () => {
1652
1360
  mockRisk("low");
1653
1361
  mockIpcResponse("get_global_thresholds", DEFAULT_GATEWAY_THRESHOLDS);
1654
1362
  _clearGlobalCacheForTesting();
1655
- clearRiskCache();
1656
1363
  try {
1657
1364
  rmSync(join(checkerTestDir, "protected", "trust.json"));
1658
1365
  } catch {
@@ -1796,7 +1503,6 @@ describe("integration regressions (PR 11)", () => {
1796
1503
  mockRisk("low");
1797
1504
  mockIpcResponse("get_global_thresholds", DEFAULT_GATEWAY_THRESHOLDS);
1798
1505
  _clearGlobalCacheForTesting();
1799
- clearRiskCache();
1800
1506
  // Delete the trust file to prevent stale default rules from prior tests
1801
1507
  try {
1802
1508
  rmSync(join(checkerTestDir, "protected", "trust.json"));
@@ -45,6 +45,10 @@ mock.module("../plugins/defaults/memory/substrate/skill-store.js", () => ({
45
45
  seedV2SkillEntries: async () => {
46
46
  seedCallCount += 1;
47
47
  },
48
+ // The validate route builds the page index, which reads the seeded
49
+ // skill catalog; an empty catalog keeps that walk inert here.
50
+ listSkillEntries: () => [],
51
+ SKILL_SLUG_PREFIX: "skills/",
48
52
  }));
49
53
 
50
54
  // ---------------------------------------------------------------------------
@@ -254,7 +258,7 @@ describe("all memory v2 routes — MEMORY_V2_DISABLED gate", () => {
254
258
  const result = (await route!.handler({ body: {} })) as {
255
259
  pageCount: number;
256
260
  edgeCount: number;
257
- missingEdgeEndpoints: unknown[];
261
+ danglingLinks: unknown[];
258
262
  oversizedPages: unknown[];
259
263
  parseFailures: unknown[];
260
264
  };
@@ -263,7 +267,7 @@ describe("all memory v2 routes — MEMORY_V2_DISABLED gate", () => {
263
267
  // returned at all (no MEMORY_V2_DISABLED throw).
264
268
  expect(result.pageCount).toBe(0);
265
269
  expect(result.edgeCount).toBe(0);
266
- expect(result.missingEdgeEndpoints).toEqual([]);
270
+ expect(result.danglingLinks).toEqual([]);
267
271
  expect(result.oversizedPages).toEqual([]);
268
272
  expect(result.parseFailures).toEqual([]);
269
273
  });
@@ -436,12 +436,11 @@ describe("forceCompact context-window usage push", () => {
436
436
  expect(usageEvent.maxTokens).toBe(200_000);
437
437
  });
438
438
 
439
- test("pushes to the caller's sink when the conversation's own sender is dead", async () => {
440
- // A `/compact` draining behind an interactive turn: `process-message.ts`
441
- // resets `sendToClient` to a no-op in its `finally`, while the queued item
442
- // still carries the live sink its result card streams on. The push has to
443
- // follow the card, not the dead sender.
444
- const stranded: AssistantEvent[] = [];
439
+ test("pushes to the caller's sink instead of the conversation sink when one is given", async () => {
440
+ // A `/compact` draining from the queue carries the queued item's own
441
+ // sink, the one its result card streams on. The push has to follow the
442
+ // card so the two can never be delivered to different places.
443
+ const conversationSink: AssistantEvent[] = [];
445
444
  const cardSink: AssistantEvent[] = [];
446
445
  mockCompactResult = {
447
446
  messages: [],
@@ -460,11 +459,10 @@ describe("forceCompact context-window usage push", () => {
460
459
  };
461
460
 
462
461
  const conversation = makeConversation(
463
- stranded,
464
- "conv-compact-dead-sender",
462
+ conversationSink,
463
+ "conv-compact-caller-sink",
465
464
  [56_000, 18_000],
466
465
  );
467
- conversation.updateClient(() => {}, true);
468
466
 
469
467
  const result = await conversation.forceCompact((msg) => cardSink.push(msg));
470
468
 
@@ -475,7 +473,7 @@ describe("forceCompact context-window usage push", () => {
475
473
  .tokens,
476
474
  ).toBe(result.estimatedInputTokens);
477
475
  expect(
478
- stranded.filter((m) => m.type === "context_window_usage").length,
476
+ conversationSink.filter((m) => m.type === "context_window_usage").length,
479
477
  ).toBe(0);
480
478
  });
481
479
 
@@ -877,13 +877,13 @@ describe("loadConfig startup behavior", () => {
877
877
  raw.llm.defaultProvider,
878
878
  );
879
879
  expect(effective.balanced?.provider).toBe("openai");
880
- expect(effective.balanced?.model).toBe("gpt-5.4-mini");
880
+ expect(effective.balanced?.model).toBe("gpt-5.6-luna");
881
881
  expect(effective.balanced?.provider_connection).toBe("openai-personal");
882
882
  expect(effective.balanced?.source).toBe("managed");
883
883
  expect(effective["quality-optimized"]?.provider).toBe("openai");
884
- expect(effective["quality-optimized"]?.model).toBe("gpt-5.4");
884
+ expect(effective["quality-optimized"]?.model).toBe("gpt-5.6-sol");
885
885
  expect(effective["cost-optimized"]?.provider).toBe("openai");
886
- expect(effective["cost-optimized"]?.model).toBe("gpt-5.4-nano");
886
+ expect(effective["cost-optimized"]?.model).toBe("gpt-5.6-luna");
887
887
  });
888
888
 
889
889
  test("off-platform hatch with a provider outside the named matrix columns resolves through the shared BYOK templates", () => {
@@ -398,11 +398,19 @@ describe("AssistantConfigSchema", () => {
398
398
  }
399
399
  });
400
400
 
401
- test("rejects invalid provider", () => {
401
+ test("parses an unknown provider (read tolerance for entry names)", () => {
402
+ // The provider schema is an open string: a stored value outside the
403
+ // known set parses instead of stripping its profile, and dispatch
404
+ // resolves it as a connection entry name (or fails explainably).
405
+ // Write-time membership is enforced at the profiles route and the
406
+ // config-write choke point.
402
407
  const result = AssistantConfigSchema.safeParse({
403
- llm: { profiles: { custom: { provider: "invalid" } } },
408
+ llm: { profiles: { custom: { provider: "anthropic-work" } } },
404
409
  });
405
- expect(result.success).toBe(false);
410
+ expect(result.success).toBe(true);
411
+ if (result.success) {
412
+ expect(result.data.llm.profiles.custom?.provider).toBe("anthropic-work");
413
+ }
406
414
  });
407
415
 
408
416
  test("accepts the vellum and chatgpt routing identities with a routable model", () => {
@@ -940,8 +948,6 @@ describe("AssistantConfigSchema", () => {
940
948
  endpointDecisionTimeoutMs: 1200,
941
949
  endpointExtensionMs: 1500,
942
950
  endpointMaxExtensions: 2,
943
- ackFirstDeltaTimeoutMs: 2500,
944
- ackGenerationTimeoutMs: 600,
945
951
  progress: {
946
952
  enabled: true,
947
953
  opsThreshold: 3,
@@ -952,6 +958,12 @@ describe("AssistantConfigSchema", () => {
952
958
  generationTimeoutMs: 1500,
953
959
  },
954
960
  },
961
+ flux: {
962
+ turnEnd: { enabled: false },
963
+ model: "flux-general-en",
964
+ eotThreshold: 0.7,
965
+ eotTimeoutMs: 5000,
966
+ },
955
967
  maxSessionDurationSeconds: 1800,
956
968
  archiveAudio: false,
957
969
  });
@@ -976,6 +988,8 @@ describe("AssistantConfigSchema", () => {
976
988
  // Unspecified vad fields still get defaults
977
989
  expect(result.liveVoice.vad.maxTurnDurationMs).toBe(30000);
978
990
  expect(result.liveVoice.maxSessionDurationSeconds).toBe(900);
991
+ // A partial liveVoice override leaves Flux turn-end disabled by default.
992
+ expect(result.liveVoice.flux.turnEnd.enabled).toBe(false);
979
993
  });
980
994
 
981
995
  test("accepts a liveVoice.vad.bargeInMinSpeechMs of 0 (guard disabled)", () => {
@@ -2340,16 +2354,17 @@ describe("loadConfig with schema validation", () => {
2340
2354
  expect(config.llm.callSites?.mainAgent?.maxTokens).toBe(4096);
2341
2355
  });
2342
2356
 
2343
- test("falls back to default for invalid provider", () => {
2344
- // Leaf-deletion recovery: the invalid provider leaf is stripped and the
2345
- // rest of the profile survives.
2357
+ test("keeps an unknown provider on load (read tolerance for entry names)", () => {
2358
+ // The open provider schema keeps the whole profile: an unknown value is
2359
+ // resolved as a connection entry name at dispatch (or fails there
2360
+ // explainably) rather than being leaf-stripped on read.
2346
2361
  writeConfig({
2347
2362
  llm: {
2348
- profiles: { custom: { provider: "invalid-provider", model: "gpt-4" } },
2363
+ profiles: { custom: { provider: "unknown-provider", model: "gpt-4" } },
2349
2364
  },
2350
2365
  });
2351
2366
  const config = loadConfig();
2352
- expect(config.llm.profiles.custom?.provider).toBeUndefined();
2367
+ expect(config.llm.profiles.custom?.provider).toBe("unknown-provider");
2353
2368
  expect(config.llm.profiles.custom?.model).toBe("gpt-4");
2354
2369
  });
2355
2370
 
@@ -71,7 +71,6 @@ mock.module("../plugins/defaults/memory/substrate/edge-index.js", () => ({
71
71
  getEdgeIndex: async (): Promise<EdgeIndex> => edgeIndex,
72
72
  invalidateEdgeIndex: () => {},
73
73
  getReachable: () => new Set<string>(),
74
- validateEdgeTargets: () => ({ ok: true, missing: [] }),
75
74
  totalEdgeCount: () => 0,
76
75
  }));
77
76
 
@@ -325,6 +325,8 @@ mock.module("../persistence/llm-request-log-store.js", () => ({
325
325
 
326
326
  import type { Conversation } from "../daemon/conversation.js";
327
327
  import { runAgentLoopImpl } from "../daemon/conversation-agent-loop.js";
328
+ import type { QueueDrainReason } from "../daemon/conversation-queue-manager.js";
329
+ import { asConversation } from "./helpers/mock-conversation.js";
328
330
 
329
331
  // ── Test helpers ─────────────────────────────────────────────────────
330
332
 
@@ -363,7 +365,7 @@ function makeCtx(
363
365
  ];
364
366
  };
365
367
 
366
- return {
368
+ return asConversation({
367
369
  conversationId: "test-conv",
368
370
  messages: [
369
371
  { role: "user", content: [{ type: "text", text: "Hello" }] },
@@ -433,12 +435,7 @@ function makeCtx(
433
435
  skillProjectionCache:
434
436
  new Map() as unknown as Conversation["skillProjectionCache"],
435
437
 
436
- usageStats: {
437
- totalInputTokens: 0,
438
- totalOutputTokens: 0,
439
- totalEstimatedCost: 0,
440
- model: "",
441
- },
438
+ usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
442
439
  turnCount: 0,
443
440
 
444
441
  lastAssistantAttachments: [],
@@ -456,12 +453,12 @@ function makeCtx(
456
453
  getQueueDepth: () => 0,
457
454
  hasQueuedMessages: () => false,
458
455
  canHandoffAtCheckpoint: () => false,
459
- drainQueue: (_reason?: string) => {},
456
+ drainQueue: async (_reason?: QueueDrainReason) => {},
460
457
  // Forwards to drainQueue so tests that spy the drain observe the agent
461
458
  // loop's post-turn kick through the guarded entry point.
462
459
  kickDrainQueue(
463
- this: { drainQueue: (reason?: string) => unknown },
464
- reason: string = "loop_complete",
460
+ this: { drainQueue: (reason?: QueueDrainReason) => Promise<void> },
461
+ reason: QueueDrainReason = "loop_complete",
465
462
  _origin?: string,
466
463
  ) {
467
464
  return this.drainQueue(reason);
@@ -493,7 +490,7 @@ function makeCtx(
493
490
  } as unknown as Conversation["graphMemory"],
494
491
 
495
492
  ...overrides,
496
- } as unknown as Conversation;
493
+ });
497
494
  }
498
495
 
499
496
  // ── Tests ────────────────────────────────────────────────────────────