@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
@@ -11,6 +11,7 @@ import {
11
11
  clearFeatureFlagOverridesCache,
12
12
  initFeatureFlagOverrides,
13
13
  isAssistantFeatureFlagEnabled,
14
+ refreshOverridesFromGateway,
14
15
  } from "../config/assistant-feature-flags.js";
15
16
  import { mockGatewayIpc, resetMockGatewayIpc } from "./mock-gateway-ipc.js";
16
17
 
@@ -110,3 +111,51 @@ describe("initFeatureFlagOverrides", () => {
110
111
  expect(isAssistantFeatureFlagEnabled("second-call", config)).toBe(false);
111
112
  });
112
113
  });
114
+
115
+ describe("refreshOverridesFromGateway", () => {
116
+ it("replaces the cache with the new gateway values", async () => {
117
+ mockGatewayIpc({ "moving-flag": true });
118
+ await initFeatureFlagOverrides();
119
+
120
+ resetMockGatewayIpc();
121
+ mockGatewayIpc({ "moving-flag": false });
122
+
123
+ expect(await refreshOverridesFromGateway()).toBe(true);
124
+
125
+ const config = {} as any;
126
+ expect(isAssistantFeatureFlagEnabled("moving-flag", config)).toBe(false);
127
+ });
128
+
129
+ it("keeps the last known values when the refresh fails", async () => {
130
+ mockGatewayIpc({ "moving-flag": true });
131
+ await initFeatureFlagOverrides();
132
+
133
+ resetMockGatewayIpc();
134
+ mockGatewayIpc(null, { error: true });
135
+
136
+ expect(await refreshOverridesFromGateway()).toBe(false);
137
+
138
+ // A failed refresh must not drop the flag to its registry default: a
139
+ // value the assistant selects behavior from (an experiment arm, a kill
140
+ // switch) would otherwise flip on one timed-out IPC call.
141
+ const config = {} as any;
142
+ expect(isAssistantFeatureFlagEnabled("moving-flag", config)).toBe(true);
143
+ });
144
+
145
+ it("keeps the cache readable for the whole call", async () => {
146
+ mockGatewayIpc({ "moving-flag": true });
147
+ await initFeatureFlagOverrides();
148
+
149
+ resetMockGatewayIpc();
150
+ mockGatewayIpc({ "moving-flag": false });
151
+
152
+ const config = {} as any;
153
+ const inFlight = refreshOverridesFromGateway();
154
+ // A sync read landing mid-refresh sees the previous values, never an
155
+ // empty cache.
156
+ expect(isAssistantFeatureFlagEnabled("moving-flag", config)).toBe(true);
157
+
158
+ await inFlight;
159
+ expect(isAssistantFeatureFlagEnabled("moving-flag", config)).toBe(false);
160
+ });
161
+ });
@@ -67,6 +67,7 @@ const { registerDefaultPluginInjectors } =
67
67
  await import("../plugins/defaults/index.js");
68
68
  import { eq } from "drizzle-orm";
69
69
 
70
+ import type { InterfaceId } from "../channels/types.js";
70
71
  import {
71
72
  clearConversations,
72
73
  setConversation,
@@ -86,6 +87,7 @@ import type { Message } from "../providers/types.js";
86
87
  import { getSubagentManager } from "../subagent/index.js";
87
88
  import type { SubagentState } from "../subagent/types.js";
88
89
  import { getWorkspacePromptPath } from "../util/platform.js";
90
+ import { asConversation } from "./helpers/mock-conversation.js";
89
91
 
90
92
  // `applyRuntimeInjections` self-resolves the Slack active-thread focus block
91
93
  // from the persisted message rows, so the schema must exist for Slack-channel
@@ -153,26 +155,30 @@ function seedWorkspaceContext(
153
155
  text: string,
154
156
  currentTurnTemporalSnapshot?: {
155
157
  clientTimezone: string | null;
158
+ timeSinceLastMessage: string | null;
156
159
  },
157
- interfaceName?: string,
160
+ interfaceName?: InterfaceId,
158
161
  ): void {
159
- setConversation(TEST_CONVERSATION_ID, {
160
- conversationId: TEST_CONVERSATION_ID,
161
- workingDir: "/sandbox",
162
- workspaceTopLevelContext: text,
163
- workspaceTopLevelDirty: false,
164
- currentTurnTemporalSnapshot,
165
- currentTurnInterfaceContext: interfaceName
166
- ? {
167
- userMessageInterface: interfaceName,
168
- assistantMessageInterface: interfaceName,
169
- }
170
- : undefined,
171
- // Mirrors Conversation.getSubagentChildren: the `<active_subagents>` block
172
- // is sourced from the live conversation, which delegates to the manager.
173
- getSubagentChildren: () =>
174
- getSubagentManager().getChildrenOf(TEST_CONVERSATION_ID),
175
- } as never);
162
+ setConversation(
163
+ TEST_CONVERSATION_ID,
164
+ asConversation({
165
+ conversationId: TEST_CONVERSATION_ID,
166
+ workingDir: "/sandbox",
167
+ workspaceTopLevelContext: text,
168
+ workspaceTopLevelDirty: false,
169
+ currentTurnTemporalSnapshot,
170
+ currentTurnInterfaceContext: interfaceName
171
+ ? {
172
+ userMessageInterface: interfaceName,
173
+ assistantMessageInterface: interfaceName,
174
+ }
175
+ : undefined,
176
+ // Mirrors Conversation.getSubagentChildren: the `<active_subagents>` block
177
+ // is sourced from the live conversation, which delegates to the manager.
178
+ getSubagentChildren: () =>
179
+ getSubagentManager().getChildrenOf(TEST_CONVERSATION_ID),
180
+ }),
181
+ );
176
182
  }
177
183
 
178
184
  // `applyRuntimeInjections` gates the `<turn_context>` block on the live
@@ -181,13 +187,19 @@ function seedWorkspaceContext(
181
187
  // fall back to the runtime-assembly fallback conversation, so seed the snapshot
182
188
  // there.
183
189
  function seedFallbackTemporalSnapshot(): void {
184
- setConversation("runtime-assembly-fallback", {
185
- conversationId: "runtime-assembly-fallback",
186
- workingDir: "/sandbox",
187
- workspaceTopLevelContext: "",
188
- workspaceTopLevelDirty: false,
189
- currentTurnTemporalSnapshot: { clientTimezone: null },
190
- } as never);
190
+ setConversation(
191
+ "runtime-assembly-fallback",
192
+ asConversation({
193
+ conversationId: "runtime-assembly-fallback",
194
+ workingDir: "/sandbox",
195
+ workspaceTopLevelContext: "",
196
+ workspaceTopLevelDirty: false,
197
+ currentTurnTemporalSnapshot: {
198
+ clientTimezone: null,
199
+ timeSinceLastMessage: null,
200
+ },
201
+ }),
202
+ );
191
203
  }
192
204
 
193
205
  // Persist Slack-channel rows for the turn conversation so
@@ -484,7 +496,11 @@ describe("injector chain", () => {
484
496
  seedSubagentChild(TEST_CONVERSATION_ID, subagentChild);
485
497
  const subagentBlock = buildSubagentStatusBlock([subagentChild])!;
486
498
 
487
- seedWorkspaceContext(workspaceText, { clientTimezone: null }, "macos");
499
+ seedWorkspaceContext(
500
+ workspaceText,
501
+ { clientTimezone: null, timeSinceLastMessage: null },
502
+ "macos",
503
+ );
488
504
  const result = await applyRuntimeInjections(runMessages, {
489
505
  ...makeTurnContext(),
490
506
  });
@@ -562,20 +578,23 @@ describe("injector chain", () => {
562
578
  createdAt: 1700000005_000,
563
579
  },
564
580
  ]);
565
- setConversation(TEST_CONVERSATION_ID, {
566
- conversationId: TEST_CONVERSATION_ID,
567
- workingDir: "/sandbox",
568
- workspaceTopLevelContext: "",
569
- workspaceTopLevelDirty: false,
570
- trustContext: { trustClass: "guardian" },
571
- channelCapabilities: {
572
- channel: "slack",
573
- dashboardCapable: false,
574
- supportsDynamicUi: false,
575
- supportsVoiceInput: false,
576
- chatType: "channel",
577
- },
578
- } as never);
581
+ setConversation(
582
+ TEST_CONVERSATION_ID,
583
+ asConversation({
584
+ conversationId: TEST_CONVERSATION_ID,
585
+ workingDir: "/sandbox",
586
+ workspaceTopLevelContext: "",
587
+ workspaceTopLevelDirty: false,
588
+ trustContext: { trustClass: "guardian", sourceChannel: "vellum" },
589
+ channelCapabilities: {
590
+ channel: "slack",
591
+ dashboardCapable: false,
592
+ supportsDynamicUi: false,
593
+ supportsVoiceInput: false,
594
+ chatType: "channel",
595
+ },
596
+ }),
597
+ );
579
598
  const result = await applyRuntimeInjections(originalRun, {
580
599
  ...makeTurnContext(),
581
600
  });
@@ -614,7 +633,10 @@ describe("injector chain", () => {
614
633
  timestamp: FIXED_TURN_TIMESTAMP,
615
634
  interfaceName: "web",
616
635
  });
617
- seedWorkspaceContext("", { clientTimezone: null });
636
+ seedWorkspaceContext("", {
637
+ clientTimezone: null,
638
+ timeSinceLastMessage: null,
639
+ });
618
640
  seedSubagentChild(
619
641
  TEST_CONVERSATION_ID,
620
642
  makeSubagentState("sub-1", "worker", "running"),
@@ -14,6 +14,7 @@ mock.module("../daemon/date-context.js", () => ({
14
14
  formatTurnTimestamp: () => FIXED_TURN_TIMESTAMP,
15
15
  }));
16
16
 
17
+ import type { Conversation } from "../daemon/conversation.js";
17
18
  import {
18
19
  clearConversations,
19
20
  setConversation,
@@ -39,6 +40,7 @@ import {
39
40
  } from "../plugins/defaults/workspace/injectors.js";
40
41
  import type { Injector, TurnContext } from "../plugins/types.js";
41
42
  import type { Message } from "../providers/types.js";
43
+ import { asConversation } from "./helpers/mock-conversation.js";
42
44
 
43
45
  // `applyRuntimeInjections` self-resolves the Slack active-thread focus block
44
46
  // from the persisted message rows, so the schema must exist for Slack-channel
@@ -90,38 +92,23 @@ const diskPressureInjector = findInjector("disk-pressure-warning");
90
92
  // turn can exercise both; the seed helpers mutate and re-register the same
91
93
  // instance. An empty (non-dirty) workspace cache resolves to no block, so
92
94
  // disk-pressure-only tests don't trigger a directory scan.
93
- let liveConversation: {
94
- conversationId: string;
95
- workingDir: string;
96
- workspaceTopLevelContext: string | null;
97
- workspaceTopLevelDirty: boolean;
98
- diskPressureCleanupModeActive: boolean;
99
- channelCapabilities?: ChannelCapabilities;
100
- trustContext?: { trustClass: string };
101
- currentTurnTemporalSnapshot?: {
102
- clientTimezone: string | null;
103
- };
104
- currentTurnInterfaceContext?: {
105
- userMessageInterface: string;
106
- assistantMessageInterface: string;
107
- };
108
- };
95
+ let liveConversation: Conversation;
109
96
 
110
97
  function resetLiveConversation(): void {
111
- liveConversation = {
98
+ liveConversation = asConversation({
112
99
  conversationId: TEST_CONVERSATION_ID,
113
100
  workingDir: "/workspace",
114
101
  workspaceTopLevelContext: "",
115
102
  workspaceTopLevelDirty: false,
116
103
  diskPressureCleanupModeActive: false,
117
- trustContext: { trustClass: "guardian" },
104
+ trustContext: { trustClass: "guardian", sourceChannel: "vellum" },
118
105
  // The unified-turn-context injector sources the interface label from the
119
106
  // live conversation's turn interface context; match the expected blocks.
120
107
  currentTurnInterfaceContext: {
121
108
  userMessageInterface: "macos",
122
109
  assistantMessageInterface: "macos",
123
110
  },
124
- };
111
+ });
125
112
  }
126
113
 
127
114
  // `applyRuntimeInjections` gates the `<turn_context>` block on the live
@@ -130,24 +117,25 @@ function resetLiveConversation(): void {
130
117
  function seedTemporalSnapshot(): void {
131
118
  liveConversation.currentTurnTemporalSnapshot = {
132
119
  clientTimezone: null,
120
+ timeSinceLastMessage: null,
133
121
  };
134
- setConversation(TEST_CONVERSATION_ID, liveConversation as never);
122
+ setConversation(TEST_CONVERSATION_ID, liveConversation);
135
123
  }
136
124
 
137
125
  function seedChannelCapabilities(caps: ChannelCapabilities): void {
138
126
  liveConversation.channelCapabilities = caps;
139
- setConversation(TEST_CONVERSATION_ID, liveConversation as never);
127
+ setConversation(TEST_CONVERSATION_ID, liveConversation);
140
128
  }
141
129
 
142
130
  function seedDiskPressure(cleanupModeActive: boolean): void {
143
131
  liveConversation.diskPressureCleanupModeActive = cleanupModeActive;
144
- setConversation(TEST_CONVERSATION_ID, liveConversation as never);
132
+ setConversation(TEST_CONVERSATION_ID, liveConversation);
145
133
  }
146
134
 
147
135
  function seedWorkspaceContext(text: string): void {
148
136
  liveConversation.workspaceTopLevelContext = text;
149
137
  liveConversation.workspaceTopLevelDirty = false;
150
- setConversation(TEST_CONVERSATION_ID, liveConversation as never);
138
+ setConversation(TEST_CONVERSATION_ID, liveConversation);
151
139
  }
152
140
 
153
141
  // Persist Slack-channel rows for the turn conversation so
@@ -26,6 +26,7 @@ process.env.GATEWAY_SECURITY_DIR = join(testDir, "protected");
26
26
 
27
27
  import {
28
28
  installIpcMock,
29
+ lastIpcParams,
29
30
  mockIpcResponse,
30
31
  } from "./helpers/gateway-classify-mock.js";
31
32
  installIpcMock();
@@ -33,6 +34,7 @@ mockIpcResponse("classify_risk", {
33
34
  risk: "low",
34
35
  reason: "skill_load",
35
36
  matchType: "unknown",
37
+ scopeOptions: [],
36
38
  });
37
39
  mockIpcResponse("get_global_thresholds", {
38
40
  interactive: "low",
@@ -42,8 +44,7 @@ mockIpcResponse("get_global_thresholds", {
42
44
 
43
45
  // ── Imports (after mocks) ─────────────────────────────────────────────────
44
46
 
45
- import { check, generateAllowlistOptions } from "../permissions/checker.js";
46
- import { clearRiskCache } from "../permissions/checker.js";
47
+ import { check, classifyRisk } from "../permissions/checker.js";
47
48
  import { _clearGlobalCacheForTesting } from "../permissions/gateway-threshold-reader.js";
48
49
  import { setOverridesForTesting } from "./feature-flag-test-helpers.js";
49
50
 
@@ -82,13 +83,34 @@ function writeDynamicSkill(
82
83
  );
83
84
  }
84
85
 
86
+ /**
87
+ * What the gateway skill classifier answers for a load whose params carry
88
+ * `hasInlineExpansions` (gateway/src/risk/skill-risk-classifier.ts): High,
89
+ * registry-matched. The daemon does not elevate locally; the gateway is the
90
+ * one place a dynamic load becomes High.
91
+ */
92
+ function mockDynamicSkillClassification(): void {
93
+ mockIpcResponse("classify_risk", {
94
+ risk: "high",
95
+ reason:
96
+ "Skill load with inline command expansions (executes shell commands at load time)",
97
+ matchType: "registry",
98
+ scopeOptions: [],
99
+ });
100
+ }
101
+
85
102
  // ── Tests ─────────────────────────────────────────────────────────────────
86
103
 
87
104
  describe("inline-command skill_load permissions", () => {
88
105
  beforeEach(() => {
89
- clearRiskCache();
90
106
  _clearGlobalCacheForTesting();
91
107
  setOverridesForTesting({});
108
+ mockIpcResponse("classify_risk", {
109
+ risk: "low",
110
+ reason: "skill_load",
111
+ matchType: "unknown",
112
+ scopeOptions: [],
113
+ });
92
114
  mockIpcResponse("get_global_thresholds", {
93
115
  interactive: "low",
94
116
  autonomous: "medium",
@@ -116,6 +138,7 @@ describe("inline-command skill_load permissions", () => {
116
138
  test("an uncovered dynamic skill prompts below Full access", async () => {
117
139
  ensureSkillsDir();
118
140
  writeDynamicSkill("dynamic-prompt", "Dynamic Prompt Skill");
141
+ mockDynamicSkillClassification();
119
142
 
120
143
  // interactive threshold "low" (beforeEach) is below the High risk of an
121
144
  // inline-command load, so it prompts.
@@ -131,6 +154,7 @@ describe("inline-command skill_load permissions", () => {
131
154
  test("an uncovered dynamic skill runs at Full access (high threshold)", async () => {
132
155
  ensureSkillsDir();
133
156
  writeDynamicSkill("dynamic-full", "Dynamic Full Access Skill");
157
+ mockDynamicSkillClassification();
134
158
  mockIpcResponse("get_global_thresholds", {
135
159
  interactive: "high",
136
160
  autonomous: "high",
@@ -155,6 +179,7 @@ describe("inline-command skill_load permissions", () => {
155
179
  risk: "low",
156
180
  reason: "user rule: skill_load_dynamic:dynamic-covered",
157
181
  matchType: "user_rule",
182
+ scopeOptions: [],
158
183
  });
159
184
 
160
185
  const result = await check(
@@ -163,17 +188,12 @@ describe("inline-command skill_load permissions", () => {
163
188
  "/tmp",
164
189
  );
165
190
  expect(result.decision).toBe("allow");
166
-
167
- mockIpcResponse("classify_risk", {
168
- risk: "low",
169
- reason: "skill_load",
170
- matchType: "unknown",
171
- });
172
191
  });
173
192
 
174
193
  test("dynamic skill prompts in strict mode (no matching rule)", async () => {
175
194
  ensureSkillsDir();
176
195
  writeDynamicSkill("dynamic-strict", "Dynamic Strict Skill");
196
+ mockDynamicSkillClassification();
177
197
  mockIpcResponse("get_global_thresholds", {
178
198
  interactive: "none",
179
199
  autonomous: "none",
@@ -211,43 +231,34 @@ describe("inline-command skill_load permissions", () => {
211
231
 
212
232
  // ── Allowlist options ────────────────────────────────────────────────
213
233
 
214
- describe("allowlist options", () => {
215
- test("dynamic skill allowlist options use skill_load_dynamic: namespace", async () => {
234
+ describe("skill metadata sent to the gateway", () => {
235
+ // The gateway picks the `skill_load_dynamic:` namespace off these flags,
236
+ // so what the daemon reads from disk decides which rule namespace a user
237
+ // can save into.
238
+ test("a skill with inline expansions is sent as dynamic", async () => {
216
239
  ensureSkillsDir();
217
240
  writeDynamicSkill("dynamic-opts", "Dynamic Opts Skill");
218
241
 
219
- const options = await generateAllowlistOptions("skill_load", {
220
- skill: "dynamic-opts",
221
- });
242
+ await classifyRisk("skill_load", { skill: "dynamic-opts" });
222
243
 
223
- expect(options.length).toBeGreaterThanOrEqual(1);
224
- // All options should use skill_load_dynamic: prefix
225
- for (const option of options) {
226
- expect(option.pattern).toMatch(/^skill_load_dynamic:/);
227
- }
228
-
229
- // Should have an any-version option
230
- const anyVersionOption = options.find(
231
- (o) => o.pattern === "skill_load_dynamic:dynamic-opts",
232
- );
233
- expect(anyVersionOption).toBeDefined();
234
- expect(anyVersionOption!.description).toBe("This skill (any version)");
244
+ const metadata = lastIpcParams("classify_risk")?.skillMetadata as
245
+ | { hasInlineExpansions: boolean; isDynamic: boolean }
246
+ | undefined;
247
+ expect(metadata?.hasInlineExpansions).toBe(true);
248
+ expect(metadata?.isDynamic).toBe(true);
235
249
  });
236
250
 
237
- test("plain skill allowlist options use skill_load: namespace", async () => {
251
+ test("a plain skill is not sent as dynamic", async () => {
238
252
  ensureSkillsDir();
239
253
  writePlainSkill("plain-opts", "Plain Opts Skill");
240
254
 
241
- const options = await generateAllowlistOptions("skill_load", {
242
- skill: "plain-opts",
243
- });
255
+ await classifyRisk("skill_load", { skill: "plain-opts" });
244
256
 
245
- expect(options.length).toBeGreaterThanOrEqual(1);
246
- // Should use skill_load: prefix, not skill_load_dynamic:
247
- for (const option of options) {
248
- expect(option.pattern).toMatch(/^skill_load:/);
249
- expect(option.pattern).not.toMatch(/^skill_load_dynamic:/);
250
- }
257
+ const metadata = lastIpcParams("classify_risk")?.skillMetadata as
258
+ | { hasInlineExpansions: boolean; isDynamic: boolean }
259
+ | undefined;
260
+ expect(metadata?.hasInlineExpansions).toBe(false);
261
+ expect(metadata?.isDynamic).toBe(false);
251
262
  });
252
263
  });
253
264
  });
@@ -1,4 +1,21 @@
1
- import { describe, expect, test } from "bun:test";
1
+ import { describe, expect, mock, test } from "bun:test";
2
+
3
+ // Entry-name providers resolve context limits through their row's kind, so
4
+ // the tests control the row store directly. A dangling label (no row) falls
5
+ // back to the model's catalog owner.
6
+ const connectionRows = new Map<string, { name: string; provider: string }>([
7
+ ["openai-work", { name: "openai-work", provider: "openai" }],
8
+ ["my-endpoint", { name: "my-endpoint", provider: "openai-compatible" }],
9
+ ]);
10
+ mock.module("../persistence/db-connection.js", () => ({
11
+ getDb: () => ({}),
12
+ }));
13
+ mock.module("../providers/inference/connections.js", () => ({
14
+ getConnection: (_db: unknown, name: string) =>
15
+ connectionRows.get(name) ?? null,
16
+ listConnections: () => [],
17
+ canonicalVellumConnection: () => null,
18
+ }));
2
19
 
3
20
  import { resolveEffectiveContextWindow } from "../config/llm-context-resolution.js";
4
21
  import { LLMSchema } from "../config/schemas/llm.js";
@@ -131,6 +148,61 @@ describe("resolveEffectiveContextWindow", () => {
131
148
  expect(resolved.modelMaxInputTokens).toBe(1050000);
132
149
  });
133
150
 
151
+ test("an entry of a catalog kind resolves the model's own context limits", () => {
152
+ // The entries collapse stores connection names in the provider field;
153
+ // the row's kind carries the model's limits, so an entry label must not
154
+ // fall back to the 200k default when its kind serves the model.
155
+ const llm = LLMSchema.parse({
156
+ profiles: {
157
+ work: { provider: "openai-work", model: "gpt-5.5" },
158
+ },
159
+ activeProfile: "work",
160
+ });
161
+
162
+ const resolved = resolveEffectiveContextWindow({
163
+ llm,
164
+ callSite: "mainAgent",
165
+ });
166
+
167
+ expect(resolved.modelMaxInputTokens).toBe(1050000);
168
+ expect(resolved.maxOutputTokens).toBeDefined();
169
+ });
170
+
171
+ test("a custom-endpoint entry keeps the conservative default for a catalog-colliding model id", () => {
172
+ // An openai-compatible endpoint's "gpt-5.5" is not OpenAI's; inheriting
173
+ // the built-in 1.05M limit would let oversized requests through.
174
+ const llm = LLMSchema.parse({
175
+ profiles: {
176
+ custom: { provider: "my-endpoint", model: "gpt-5.5" },
177
+ },
178
+ activeProfile: "custom",
179
+ });
180
+
181
+ const resolved = resolveEffectiveContextWindow({
182
+ llm,
183
+ callSite: "mainAgent",
184
+ });
185
+
186
+ expect(resolved.modelMaxInputTokens).toBe(200000);
187
+ expect(resolved.maxOutputTokens).toBeUndefined();
188
+ });
189
+
190
+ test("a label with no row falls back to the model's catalog owner", () => {
191
+ const llm = LLMSchema.parse({
192
+ profiles: {
193
+ gone: { provider: "deleted-entry", model: "gpt-5.5" },
194
+ },
195
+ activeProfile: "gone",
196
+ });
197
+
198
+ const resolved = resolveEffectiveContextWindow({
199
+ llm,
200
+ callSite: "mainAgent",
201
+ });
202
+
203
+ expect(resolved.modelMaxInputTokens).toBe(1050000);
204
+ });
205
+
134
206
  test("unknown catalog model falls back safely to the default 200k cap", () => {
135
207
  const llm = LLMSchema.parse({
136
208
  callSites: {
@@ -123,11 +123,14 @@ describe("LLMSchema", () => {
123
123
  expect(parsed.profileOrder).toEqual(["fast", "stale"]);
124
124
  });
125
125
 
126
- test("invalid provider rejected", () => {
126
+ test("an unknown provider parses (read tolerance for entry names)", () => {
127
+ // The open provider schema keeps the profile; write-time membership is
128
+ // enforced at the profiles route and the config-write choke point, and
129
+ // dispatch resolves the value as a connection entry name.
127
130
  const result = LLMSchema.safeParse({
128
131
  profiles: { mine: { provider: "bogus-provider" } },
129
132
  });
130
- expect(result.success).toBe(false);
133
+ expect(result.success).toBe(true);
131
134
  });
132
135
 
133
136
  test("invalid temperature (negative) rejected", () => {
@@ -47,6 +47,9 @@ import { skillLoadTool } from "../tools/skills/load.js";
47
47
  import { executeScaffoldManagedSkill } from "../tools/skills/scaffold-managed.js";
48
48
  import type { ToolContext } from "../tools/types.js";
49
49
 
50
+ /** scaffold_managed_skill requires activation hints; a fixed set for tests. */
51
+ const HINTS = ["user asks to run the lifecycle test procedure"];
52
+
50
53
  function makeContext(): ToolContext {
51
54
  return {
52
55
  workingDir: "/tmp",
@@ -126,6 +129,7 @@ Run the custom lifecycle verification procedure.
126
129
  name: "Lifecycle Test",
127
130
  description: "Integration test skill.",
128
131
  body_markdown: "Run the lifecycle test procedure.",
132
+ activation_hints: HINTS,
129
133
  emoji: "🧪",
130
134
  },
131
135
  makeContext(),
@@ -185,6 +189,7 @@ Run the custom lifecycle verification procedure.
185
189
  name: "V1",
186
190
  description: "Version 1.",
187
191
  body_markdown: "Original body.",
192
+ activation_hints: HINTS,
188
193
  },
189
194
  ctx,
190
195
  );
@@ -196,6 +201,7 @@ Run the custom lifecycle verification procedure.
196
201
  name: "V2",
197
202
  description: "Version 2.",
198
203
  body_markdown: "Updated body.",
204
+ activation_hints: HINTS,
199
205
  overwrite: true,
200
206
  },
201
207
  ctx,
@@ -241,6 +247,7 @@ Run the custom lifecycle verification procedure.
241
247
  description: "Created from scaffold.",
242
248
  body_markdown:
243
249
  "This skill was dynamically created.\n\nRun: `echo chain-test-ok`",
250
+ activation_hints: HINTS,
244
251
  },
245
252
  ctx,
246
253
  );