@vellumai/assistant 0.10.2 → 0.10.3-dev.202606252046.9075fd5

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 (546) hide show
  1. package/bun.lock +20 -0
  2. package/docs/workspace-tools.md +42 -33
  3. package/eslint-rules/cli-no-daemon-internals.js +6 -0
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
  5. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
  6. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +44 -0
  7. package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
  8. package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
  9. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
  10. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  11. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +28 -0
  12. package/node_modules/@vellumai/service-contracts/src/channels.ts +41 -0
  13. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  14. package/openapi.yaml +196 -56
  15. package/package.json +4 -1
  16. package/scripts/test.sh +36 -15
  17. package/src/__tests__/actor-token-service.test.ts +36 -14
  18. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +83 -31
  19. package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
  20. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
  21. package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
  22. package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
  23. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  24. package/src/__tests__/approval-cascade.test.ts +2 -0
  25. package/src/__tests__/assistant-attachments.test.ts +42 -0
  26. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
  27. package/src/__tests__/btw-routes.test.ts +2 -0
  28. package/src/__tests__/build-persisted-content.test.ts +2 -0
  29. package/src/__tests__/call-controller.test.ts +19 -0
  30. package/src/__tests__/channel-approval-routes.test.ts +21 -26
  31. package/src/__tests__/channel-delivery-store.test.ts +28 -0
  32. package/src/__tests__/channel-guardian.test.ts +164 -78
  33. package/src/__tests__/channel-inbound-disk-pressure.test.ts +11 -19
  34. package/src/__tests__/channel-reply-delivery.test.ts +2 -0
  35. package/src/__tests__/code-search-tool.test.ts +585 -0
  36. package/src/__tests__/compaction-events.test.ts +2 -0
  37. package/src/__tests__/compaction-ledger-store.test.ts +128 -0
  38. package/src/__tests__/compaction.benchmark.test.ts +2 -0
  39. package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
  40. package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
  41. package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
  42. package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
  43. package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
  44. package/src/__tests__/config-loader-backfill.test.ts +123 -10
  45. package/src/__tests__/config-schema.test.ts +1 -0
  46. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
  47. package/src/__tests__/consult-deadline.test.ts +60 -0
  48. package/src/__tests__/contact-store-interaction-info.test.ts +156 -0
  49. package/src/__tests__/contact-store-user-file.test.ts +7 -10
  50. package/src/__tests__/contacts-relay-reads.test.ts +19 -24
  51. package/src/__tests__/contacts-write.test.ts +0 -2
  52. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  53. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
  54. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  55. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  56. package/src/__tests__/conversation-agent-loop.test.ts +134 -0
  57. package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
  58. package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
  59. package/src/__tests__/conversation-attention-telegram.test.ts +9 -11
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
  61. package/src/__tests__/conversation-fork-crud.test.ts +354 -24
  62. package/src/__tests__/conversation-history-web-search.test.ts +2 -0
  63. package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
  64. package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
  65. package/src/__tests__/conversation-pairing.test.ts +2 -0
  66. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  67. package/src/__tests__/conversation-process-callsite.test.ts +2 -0
  68. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  69. package/src/__tests__/conversation-queue.test.ts +91 -0
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
  71. package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
  72. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  73. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  74. package/src/__tests__/conversation-speed-override.test.ts +2 -0
  75. package/src/__tests__/conversation-surfaces-task-progress.test.ts +29 -0
  76. package/src/__tests__/conversation-title-service.test.ts +2 -0
  77. package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
  78. package/src/__tests__/conversation-usage.test.ts +2 -0
  79. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
  80. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  81. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  82. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  83. package/src/__tests__/db-compaction-events-migration.test.ts +129 -0
  84. package/src/__tests__/db-migration-rollback.test.ts +205 -171
  85. package/src/__tests__/db-test-helpers.ts +5 -4
  86. package/src/__tests__/delete-propagation.test.ts +5 -3
  87. package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
  88. package/src/__tests__/disk-pressure-guard.test.ts +41 -0
  89. package/src/__tests__/dm-backfill.test.ts +6 -4
  90. package/src/__tests__/dm-persistence.test.ts +2 -0
  91. package/src/__tests__/emit-signal-routing-intent.test.ts +7 -6
  92. package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
  93. package/src/__tests__/exploration-drift-hook.test.ts +3 -2
  94. package/src/__tests__/filing-service.test.ts +2 -0
  95. package/src/__tests__/guardian-binding-drift-heal.test.ts +104 -19
  96. package/src/__tests__/guardian-dispatch.test.ts +140 -1
  97. package/src/__tests__/guardian-expiry-notifier.test.ts +282 -0
  98. package/src/__tests__/guardian-outbound-http.test.ts +13 -0
  99. package/src/__tests__/guardian-routing-state.test.ts +6 -10
  100. package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
  101. package/src/__tests__/heartbeat-service.test.ts +2 -0
  102. package/src/__tests__/helpers/channel-test-adapter.ts +46 -19
  103. package/src/__tests__/helpers/create-guardian-binding.ts +15 -23
  104. package/src/__tests__/helpers/mock-logger.ts +1 -0
  105. package/src/__tests__/helpers/seed-contact-channel.ts +96 -0
  106. package/src/__tests__/host-app-control-routes.test.ts +24 -30
  107. package/src/__tests__/host-bash-routes.test.ts +31 -41
  108. package/src/__tests__/host-browser-routes.test.ts +26 -32
  109. package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
  110. package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
  111. package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
  112. package/src/__tests__/http-user-message-parity.test.ts +290 -8
  113. package/src/__tests__/inbound-invite-redemption.test.ts +115 -10
  114. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  115. package/src/__tests__/invite-redemption-service.test.ts +471 -53
  116. package/src/__tests__/invite-routes-http.test.ts +34 -0
  117. package/src/__tests__/invite-service-ipc.test.ts +65 -2
  118. package/src/__tests__/llm-context-normalization.test.ts +105 -0
  119. package/src/__tests__/llm-request-log-error-payload.test.ts +71 -9
  120. package/src/__tests__/llm-usage-store.test.ts +25 -0
  121. package/src/__tests__/mcp-config-secret-boundary.test.ts +392 -0
  122. package/src/__tests__/mcp-health-check.test.ts +2 -1
  123. package/src/__tests__/media-stream-server-integration.test.ts +127 -0
  124. package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
  125. package/src/__tests__/messaging-send-tool.test.ts +2 -0
  126. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  127. package/src/__tests__/mtime-cache.test.ts +275 -5
  128. package/src/__tests__/native-web-search.test.ts +2 -0
  129. package/src/__tests__/non-member-access-request.test.ts +191 -17
  130. package/src/__tests__/notification-broadcaster.test.ts +4 -0
  131. package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
  132. package/src/__tests__/notification-deep-link.test.ts +6 -0
  133. package/src/__tests__/notification-guardian-path.test.ts +19 -0
  134. package/src/__tests__/onboarding-persona-write.test.ts +52 -22
  135. package/src/__tests__/openai-provider.test.ts +22 -12
  136. package/src/__tests__/openai-responses-provider.test.ts +12 -2
  137. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  138. package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
  139. package/src/__tests__/persist-onboarding-artifacts.test.ts +1 -0
  140. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  141. package/src/__tests__/persona-resolver.test.ts +75 -45
  142. package/src/__tests__/plugin-bootstrap.test.ts +21 -83
  143. package/src/__tests__/plugin-disabled-state.test.ts +190 -0
  144. package/src/__tests__/plugin-pipeline.test.ts +96 -0
  145. package/src/__tests__/plugin-route-contribution.test.ts +6 -19
  146. package/src/__tests__/plugin-tool-contribution.test.ts +5 -20
  147. package/src/__tests__/plugin-types.test.ts +2 -4
  148. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  149. package/src/__tests__/process-message-display-content.test.ts +2 -0
  150. package/src/__tests__/provider-error-scenarios.test.ts +5 -4
  151. package/src/__tests__/provider-usage-tracking.test.ts +39 -0
  152. package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +135 -0
  153. package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +158 -0
  154. package/src/__tests__/reaction-persistence.test.ts +51 -4
  155. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
  156. package/src/__tests__/registry.test.ts +4 -1
  157. package/src/__tests__/relay-server.test.ts +758 -32
  158. package/src/__tests__/runtime-attachment-metadata.test.ts +9 -12
  159. package/src/__tests__/secret-ingress-http.test.ts +14 -0
  160. package/src/__tests__/send-endpoint-busy.test.ts +30 -8
  161. package/src/__tests__/settings-routes.test.ts +32 -0
  162. package/src/__tests__/skills.test.ts +44 -0
  163. package/src/__tests__/slack-inbound-verification.test.ts +47 -2
  164. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +79 -0
  165. package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
  166. package/src/__tests__/stt-hints.test.ts +49 -15
  167. package/src/__tests__/subagent-detail.test.ts +27 -0
  168. package/src/__tests__/subagent-disposal.test.ts +65 -0
  169. package/src/__tests__/subagent-fork-prompt-role.test.ts +195 -0
  170. package/src/__tests__/subagent-fork-spawn.test.ts +6 -7
  171. package/src/__tests__/subagent-notify-parent.test.ts +2 -0
  172. package/src/__tests__/subagent-role-registry.test.ts +24 -6
  173. package/src/__tests__/subagent-spawn-and-await.test.ts +546 -0
  174. package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
  175. package/src/__tests__/subagent-tools.test.ts +398 -1
  176. package/src/__tests__/suggestion-routes.test.ts +2 -0
  177. package/src/__tests__/thread-backfill.test.ts +3 -3
  178. package/src/__tests__/title-generate-hook.test.ts +2 -0
  179. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
  180. package/src/__tests__/tool-executor.test.ts +16 -11
  181. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  182. package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
  183. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  184. package/src/__tests__/trusted-contact-approval-notifier.test.ts +37 -51
  185. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +12 -12
  186. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -7
  187. package/src/__tests__/trusted-contact-multichannel.test.ts +16 -7
  188. package/src/__tests__/trusted-contact-verification.test.ts +79 -54
  189. package/src/__tests__/twilio-routes.test.ts +96 -0
  190. package/src/__tests__/ui-file-upload-surface.test.ts +86 -0
  191. package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
  192. package/src/__tests__/voice-guardian-cold-cache-warm.test.ts +137 -0
  193. package/src/__tests__/voice-invite-redemption.test.ts +216 -20
  194. package/src/__tests__/web-search-backend-failure.test.ts +2 -0
  195. package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +3 -3
  196. package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +208 -0
  197. package/src/__tests__/workspace-migration-112-remove-advisor-callsite-override.test.ts +170 -0
  198. package/src/__tests__/workspace-migration-drop-user-md.test.ts +196 -238
  199. package/src/__tests__/workspace-migration-remove-hooks.test.ts +14 -35
  200. package/src/__tests__/workspace-tool-loader.test.ts +195 -2
  201. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +35 -47
  202. package/src/agent/loop-exclusive-tool.test.ts +154 -0
  203. package/src/agent/loop-native-web-search.test.ts +200 -0
  204. package/src/agent/loop.ts +164 -1
  205. package/src/api/constants/sse-replay.ts +41 -0
  206. package/src/api/events/conversation-notice.ts +26 -0
  207. package/src/api/index.ts +19 -1
  208. package/src/api/responses/llm-request-log-entry.ts +29 -0
  209. package/src/api/responses/subagent-detail.ts +17 -0
  210. package/src/api/surfaces.ts +39 -3
  211. package/src/approvals/guardian-channel-delivery.ts +30 -0
  212. package/src/approvals/guardian-expiry-notifier.ts +148 -0
  213. package/src/approvals/guardian-request-resolvers.ts +17 -15
  214. package/src/calls/__tests__/relay-setup-router.test.ts +267 -17
  215. package/src/calls/call-domain.ts +3 -3
  216. package/src/calls/guardian-dispatch.ts +14 -9
  217. package/src/calls/inbound-trust-reader.ts +24 -2
  218. package/src/calls/media-stream-server.ts +21 -0
  219. package/src/calls/relay-access-wait.ts +6 -6
  220. package/src/calls/relay-server.ts +188 -51
  221. package/src/calls/relay-setup-router.ts +47 -17
  222. package/src/calls/relay-verification.ts +4 -4
  223. package/src/calls/stt-hints.ts +9 -12
  224. package/src/calls/twilio-routes.ts +14 -4
  225. package/src/channels/types.ts +10 -20
  226. package/src/cli/commands/__tests__/cache.test.ts +8 -1
  227. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
  228. package/src/cli/commands/cache.ts +194 -181
  229. package/src/cli/commands/contacts.ts +10 -7
  230. package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
  231. package/src/cli/commands/db/status.ts +37 -1
  232. package/src/cli/commands/mcp.ts +252 -218
  233. package/src/cli/commands/memory/__tests__/worker.test.ts +432 -0
  234. package/src/cli/commands/memory/index.ts +2 -0
  235. package/src/cli/commands/memory/worker.ts +242 -0
  236. package/src/cli/commands/plugins.ts +125 -13
  237. package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
  238. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
  239. package/src/cli/lib/__tests__/publish-plugin.test.ts +404 -0
  240. package/src/cli/lib/list-installed-plugins.ts +179 -1
  241. package/src/cli/lib/publish-plugin.ts +633 -0
  242. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
  243. package/src/config/__tests__/sync-gated-profiles.test.ts +16 -10
  244. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
  245. package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
  246. package/src/config/bundled-skills/subagent/SKILL.md +17 -2
  247. package/src/config/bundled-skills/subagent/TOOLS.json +5 -4
  248. package/src/config/call-site-defaults.ts +0 -6
  249. package/src/config/feature-flag-registry.json +5 -13
  250. package/src/config/llm-resolver.ts +0 -3
  251. package/src/config/loader.ts +38 -5
  252. package/src/config/prune-seeded-callsite-defaults.ts +110 -0
  253. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  254. package/src/config/schemas/call-site-catalog.ts +0 -7
  255. package/src/config/schemas/heartbeat.ts +2 -5
  256. package/src/config/schemas/llm.ts +3 -12
  257. package/src/config/schemas/memory-lifecycle.ts +12 -0
  258. package/src/config/schemas/memory-v3.ts +7 -0
  259. package/src/config/schemas/memory.ts +4 -0
  260. package/src/config/schemas/timeouts.ts +8 -0
  261. package/src/config/seed-inference-profiles.ts +30 -34
  262. package/src/config/skills.ts +27 -5
  263. package/src/config/sync-gated-profiles.ts +12 -16
  264. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +128 -0
  265. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
  266. package/src/contacts/__tests__/member-write-relay.test.ts +226 -0
  267. package/src/contacts/contact-store.ts +27 -237
  268. package/src/contacts/contacts-write.ts +18 -55
  269. package/src/contacts/gateway-channel-read.ts +51 -0
  270. package/src/contacts/guardian-delivery-reader.ts +223 -0
  271. package/src/contacts/member-write-relay.ts +183 -0
  272. package/src/contacts/types.ts +3 -15
  273. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +35 -0
  274. package/src/daemon/__tests__/conversation-tool-setup.test.ts +0 -44
  275. package/src/daemon/assistant-attachments.ts +27 -4
  276. package/src/daemon/conversation-agent-loop.ts +28 -0
  277. package/src/daemon/conversation-notices.ts +60 -0
  278. package/src/daemon/conversation-process.ts +35 -16
  279. package/src/daemon/conversation-surfaces.ts +111 -38
  280. package/src/daemon/conversation-tool-setup.ts +71 -30
  281. package/src/daemon/conversation.ts +23 -1
  282. package/src/daemon/disk-pressure-guard.ts +12 -2
  283. package/src/daemon/event-loop-watchdog.ts +28 -1
  284. package/src/daemon/external-plugins-bootstrap.ts +17 -41
  285. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +0 -1
  286. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -2
  287. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -2
  288. package/src/daemon/handlers/__tests__/config-channels.test.ts +220 -0
  289. package/src/daemon/handlers/config-a2a.ts +6 -14
  290. package/src/daemon/handlers/config-channels.ts +67 -26
  291. package/src/daemon/handlers/conversations.ts +77 -0
  292. package/src/daemon/lifecycle.ts +16 -0
  293. package/src/daemon/mcp-reload-service.ts +10 -0
  294. package/src/daemon/memory-v2-startup.test.ts +72 -0
  295. package/src/daemon/memory-v2-startup.ts +87 -19
  296. package/src/daemon/message-types/conversations.ts +2 -0
  297. package/src/daemon/message-types/surfaces.ts +12 -12
  298. package/src/daemon/server.ts +0 -4
  299. package/src/daemon/shutdown-handlers.ts +20 -0
  300. package/src/daemon/tool-setup-types.ts +9 -0
  301. package/src/heartbeat/heartbeat-service.ts +5 -0
  302. package/src/home/relationship-state-writer.ts +5 -0
  303. package/src/hooks/hook-loader.ts +341 -0
  304. package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
  305. package/src/ipc/assistant-server.ts +2 -2
  306. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -0
  307. package/src/mcp/client.ts +15 -1
  308. package/src/mcp/mcp-auth-orchestrator.ts +6 -1
  309. package/src/mcp/mcp-header-store.ts +134 -0
  310. package/src/mcp/mcp-oauth-provider.ts +19 -8
  311. package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
  312. package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
  313. package/src/memory/__tests__/prompt-override.test.ts +192 -0
  314. package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
  315. package/src/memory/compaction-ledger-store.ts +107 -0
  316. package/src/memory/conversation-crud.ts +129 -61
  317. package/src/memory/db-connection.ts +22 -3
  318. package/src/memory/db-init.ts +37 -503
  319. package/src/memory/db-singleton.ts +6 -4
  320. package/src/memory/jobs-worker.ts +104 -0
  321. package/src/memory/llm-request-log-store.ts +26 -1
  322. package/src/memory/llm-usage-store.ts +48 -20
  323. package/src/memory/memory-retrospective-job.ts +14 -8
  324. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +152 -56
  325. package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
  326. package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
  327. package/src/memory/migrations/302-create-compaction-events.ts +107 -0
  328. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +297 -0
  329. package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
  330. package/src/memory/migrations/run-migrations.ts +106 -10
  331. package/src/memory/migrations/validate-migration-state.ts +105 -67
  332. package/src/memory/prompt-override.ts +129 -0
  333. package/src/memory/schema/contacts.ts +6 -2
  334. package/src/memory/schema/conversations.ts +37 -0
  335. package/src/memory/schema/infrastructure.ts +20 -0
  336. package/src/memory/steps.ts +1294 -0
  337. package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
  338. package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
  339. package/src/memory/v2/cli-command-store.ts +75 -38
  340. package/src/memory/v2/prompts/consolidation.ts +13 -82
  341. package/src/memory/v2/prompts/router.ts +21 -93
  342. package/src/memory/v2/skill-store.ts +68 -31
  343. package/src/memory/watchdog-events-store.ts +87 -0
  344. package/src/memory/worker-control.ts +204 -0
  345. package/src/memory/worker-process.ts +89 -0
  346. package/src/messaging/channel-binding-metadata.ts +31 -0
  347. package/src/messaging/provider-types.ts +8 -0
  348. package/src/messaging/providers/slack/binding-metadata.ts +60 -0
  349. package/src/notifications/__tests__/broadcaster.test.ts +8 -8
  350. package/src/notifications/__tests__/connected-channels.test.ts +86 -0
  351. package/src/notifications/__tests__/decision-engine.test.ts +78 -9
  352. package/src/notifications/__tests__/destination-resolver.test.ts +151 -0
  353. package/src/notifications/broadcaster.ts +8 -1
  354. package/src/notifications/decision-engine.ts +15 -7
  355. package/src/notifications/destination-resolver.ts +53 -25
  356. package/src/notifications/emit-signal.ts +34 -15
  357. package/src/onboarding/checkin-event.test.ts +222 -0
  358. package/src/onboarding/checkin-event.ts +321 -0
  359. package/src/onboarding/schedule-checkin.ts +190 -0
  360. package/src/permissions/question-prompter.test.ts +1 -1
  361. package/src/permissions/question-prompter.ts +7 -4
  362. package/src/plugin-api/index.ts +12 -12
  363. package/src/plugin-api/types.ts +12 -14
  364. package/src/plugin-api/vision-support.test.ts +28 -4
  365. package/src/plugin-api/vision-support.ts +66 -31
  366. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +2 -2
  367. package/src/plugins/defaults/empty-response/hooks/stop.ts +2 -2
  368. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +4 -3
  369. package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +2 -2
  370. package/src/plugins/defaults/history-repair/hooks/stop.ts +2 -2
  371. package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +2 -2
  372. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
  373. package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +12 -13
  374. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +14 -22
  375. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
  376. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +2 -2
  377. package/src/plugins/defaults/image-recovery/hooks/stop.ts +2 -2
  378. package/src/plugins/defaults/index.ts +0 -35
  379. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +2 -2
  380. package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +2 -2
  381. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +2 -2
  382. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  383. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +33 -3
  384. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +48 -4
  385. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +4 -8
  386. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +2 -2
  387. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +2 -2
  388. package/src/plugins/defaults/memory-v3-shadow/injector.ts +43 -15
  389. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
  390. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
  391. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +77 -13
  392. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +12 -11
  393. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +2 -2
  394. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +2 -2
  395. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +2 -2
  396. package/src/plugins/defaults/title-generate/hooks/stop.ts +2 -2
  397. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +2 -2
  398. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +2 -2
  399. package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +2 -2
  400. package/src/plugins/disabled-state.ts +31 -0
  401. package/src/plugins/external-plugin-loader.ts +2 -2
  402. package/src/plugins/mtime-cache.ts +186 -330
  403. package/src/plugins/pipeline.ts +111 -13
  404. package/src/plugins/registry.ts +59 -16
  405. package/src/plugins/surface-import.ts +121 -0
  406. package/src/plugins/types.ts +7 -9
  407. package/src/prompts/persona-resolver.ts +43 -11
  408. package/src/providers/anthropic/client.ts +5 -0
  409. package/src/providers/call-site-routing.ts +45 -0
  410. package/src/providers/model-catalog.ts +16 -0
  411. package/src/providers/openai/__tests__/api-error-normalization.test.ts +321 -0
  412. package/src/providers/openai/api-error-normalization.ts +270 -0
  413. package/src/providers/openai/chat-completions-provider.ts +37 -83
  414. package/src/providers/openai/responses-provider.ts +50 -46
  415. package/src/providers/openrouter/client.ts +5 -0
  416. package/src/providers/provider-send-message.ts +10 -0
  417. package/src/providers/ratelimit.ts +10 -0
  418. package/src/providers/registry.ts +1 -1
  419. package/src/providers/retry.ts +10 -0
  420. package/src/providers/types.ts +22 -0
  421. package/src/providers/usage-tracking.ts +10 -0
  422. package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
  423. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +184 -0
  424. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
  425. package/src/runtime/__tests__/local-principal-trust.test.ts +162 -0
  426. package/src/runtime/__tests__/member-verdict-cache.test.ts +119 -0
  427. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +402 -123
  428. package/src/runtime/access-request-helper.ts +18 -39
  429. package/src/runtime/actor-trust-resolver.ts +46 -19
  430. package/src/runtime/anchored-guardian.test.ts +109 -0
  431. package/src/runtime/anchored-guardian.ts +86 -0
  432. package/src/runtime/assistant-event-hub.ts +1 -1
  433. package/src/runtime/assistant-stream-state.ts +9 -2
  434. package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
  435. package/src/runtime/auth/require-bound-guardian.ts +21 -11
  436. package/src/runtime/channel-verification-service.ts +56 -31
  437. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
  438. package/src/runtime/guardian-vellum-migration.ts +69 -8
  439. package/src/runtime/invite-redemption-service.ts +213 -187
  440. package/src/runtime/local-actor-identity.test.ts +108 -0
  441. package/src/runtime/local-actor-identity.ts +85 -13
  442. package/src/runtime/local-principal-trust.ts +52 -0
  443. package/src/runtime/member-verdict-cache.ts +0 -0
  444. package/src/runtime/pending-interactions.ts +11 -1
  445. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
  446. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  447. package/src/runtime/routes/__tests__/contact-routes.test.ts +305 -0
  448. package/src/runtime/routes/__tests__/global-search-routes.test.ts +92 -0
  449. package/src/runtime/routes/__tests__/http-adapter-actor-header.test.ts +129 -0
  450. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +188 -0
  451. package/src/runtime/routes/browser-routes.ts +1 -1
  452. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +13 -5
  453. package/src/runtime/routes/channel-verification-routes.ts +3 -3
  454. package/src/runtime/routes/contact-routes.ts +48 -57
  455. package/src/runtime/routes/conversation-cli-routes.ts +4 -5
  456. package/src/runtime/routes/conversation-list-routes.ts +4 -7
  457. package/src/runtime/routes/conversation-query-routes.ts +72 -0
  458. package/src/runtime/routes/conversation-routes.ts +84 -85
  459. package/src/runtime/routes/events-routes.ts +2 -2
  460. package/src/runtime/routes/global-search-routes.ts +3 -1
  461. package/src/runtime/routes/guardian-action-routes.ts +4 -5
  462. package/src/runtime/routes/host-app-control-routes.ts +5 -4
  463. package/src/runtime/routes/host-bash-routes.ts +5 -4
  464. package/src/runtime/routes/host-browser-routes.ts +9 -11
  465. package/src/runtime/routes/host-cu-routes.ts +5 -4
  466. package/src/runtime/routes/host-file-routes.ts +5 -4
  467. package/src/runtime/routes/host-transfer-routes.ts +6 -6
  468. package/src/runtime/routes/http-adapter.ts +16 -1
  469. package/src/runtime/routes/identity-routes.ts +3 -2
  470. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  471. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
  472. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -59
  473. package/src/runtime/routes/inbound-stages/background-dispatch.ts +13 -5
  474. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
  475. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
  476. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
  477. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +19 -0
  478. package/src/runtime/routes/index.ts +2 -0
  479. package/src/runtime/routes/llm-context-normalization.ts +83 -0
  480. package/src/runtime/routes/mcp-auth-routes.ts +171 -19
  481. package/src/runtime/routes/migration-rollback-routes.ts +4 -3
  482. package/src/runtime/routes/migration-routes.ts +4 -1
  483. package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
  484. package/src/runtime/routes/settings-routes.ts +8 -3
  485. package/src/runtime/routes/subagents-routes.ts +5 -0
  486. package/src/runtime/routes/surface-action-routes.ts +42 -56
  487. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  488. package/src/runtime/services/conversation-serializer.ts +13 -58
  489. package/src/runtime/tool-grant-request-helper.ts +3 -3
  490. package/src/runtime/trust-verdict-consumer.ts +111 -40
  491. package/src/runtime/verification-outbound-actions.ts +18 -18
  492. package/src/signals/user-message.ts +16 -0
  493. package/src/subagent/__tests__/consult-prompt.test.ts +35 -0
  494. package/src/{plugins/defaults/advisor/__tests__/transcript.test.ts → subagent/__tests__/consult-transcript.test.ts} +47 -10
  495. package/src/{plugins/defaults/advisor/steering.ts → subagent/consult-prompt.ts} +22 -32
  496. package/src/{plugins/defaults/advisor/transcript.ts → subagent/consult-transcript.ts} +18 -8
  497. package/src/subagent/index.ts +1 -1
  498. package/src/subagent/manager.ts +254 -33
  499. package/src/subagent/types.ts +11 -4
  500. package/src/telemetry/types.ts +34 -1
  501. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
  502. package/src/telemetry/usage-telemetry-reporter.ts +87 -3
  503. package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
  504. package/src/tools/ask-question/ask-question-tool.ts +13 -0
  505. package/src/tools/executor.ts +4 -4
  506. package/src/tools/filesystem/search.ts +543 -0
  507. package/src/tools/registry.ts +38 -0
  508. package/src/tools/shared/filesystem/path-policy.ts +12 -5
  509. package/src/tools/subagent/consult-deadline.ts +49 -0
  510. package/src/tools/subagent/spawn.ts +234 -5
  511. package/src/tools/tool-approval-handler.ts +1 -1
  512. package/src/tools/tool-defaults.ts +9 -2
  513. package/src/tools/tool-manifest.ts +3 -0
  514. package/src/tools/types.ts +131 -25
  515. package/src/tools/workspace-tools/loader.ts +348 -244
  516. package/src/util/errors.ts +26 -1
  517. package/src/util/logger.ts +9 -0
  518. package/src/util/platform.ts +19 -0
  519. package/src/util/telemetry-db-path.ts +24 -0
  520. package/src/workflows/library.test.ts +140 -0
  521. package/src/workflows/library.ts +82 -28
  522. package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
  523. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
  524. package/src/workspace/migrations/031-drop-user-md.ts +232 -148
  525. package/src/workspace/migrations/048-remove-workspace-hooks.ts +14 -66
  526. package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +134 -0
  527. package/src/workspace/migrations/112-remove-advisor-callsite-override.ts +64 -0
  528. package/src/workspace/migrations/registry.ts +4 -0
  529. package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
  530. package/src/daemon/workspace-tools-watcher.ts +0 -328
  531. package/src/memory/migrations/registry.ts +0 -573
  532. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +0 -56
  533. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +0 -43
  534. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +0 -137
  535. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -153
  536. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +0 -138
  537. package/src/plugins/defaults/advisor/advisor-gate.ts +0 -29
  538. package/src/plugins/defaults/advisor/advisor-state-store.ts +0 -94
  539. package/src/plugins/defaults/advisor/config.ts +0 -21
  540. package/src/plugins/defaults/advisor/consult.ts +0 -93
  541. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +0 -34
  542. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +0 -30
  543. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +0 -19
  544. package/src/plugins/defaults/advisor/package.json +0 -14
  545. package/src/plugins/defaults/advisor/tools/advisor.ts +0 -65
  546. package/src/providers/openai/__tests__/api-error-detail.test.ts +0 -120
@@ -22,6 +22,7 @@ describe("MemoryV3ConfigSchema", () => {
22
22
  needleK: 100,
23
23
  denseK: 100,
24
24
  replyQueryK: 12,
25
+ selectorPromptPath: null,
25
26
  edge: { hubDegree: 30, seedCount: 18, perSeed: 6, cap: 45 },
26
27
  });
27
28
  });
@@ -300,13 +300,6 @@ const CATALOG_RECORD: CatalogRecord = {
300
300
  description: "General-purpose LLM inference call site for skill use.",
301
301
  domain: "skills",
302
302
  },
303
- advisor: {
304
- id: "advisor",
305
- displayName: "Advisor",
306
- description:
307
- "Stronger reviewer model consulted mid-task to shape or pressure-test the plan.",
308
- domain: "skills",
309
- },
310
303
  vision: {
311
304
  id: "vision",
312
305
  displayName: "Vision",
@@ -5,10 +5,7 @@ export const HeartbeatConfigSchema = z
5
5
  .object({
6
6
  enabled: z
7
7
  .boolean({ error: "heartbeat.enabled must be a boolean" })
8
- // Heartbeats are opt-in for new workspaces. Workspaces created while
9
- // the default was true keep their behavior via workspace migration
10
- // 102-preserve-heartbeat-enabled-for-existing-workspaces.
11
- .default(false)
8
+ .default(true)
12
9
  .describe("Whether periodic heartbeat checks are enabled"),
13
10
  intervalMs: z
14
11
  .number({ error: "heartbeat.intervalMs must be a number" })
@@ -64,7 +61,7 @@ export const HeartbeatConfigSchema = z
64
61
  .int("heartbeat.maxDailyRuns must be an integer")
65
62
  .positive("heartbeat.maxDailyRuns must be a positive integer")
66
63
  .nullable()
67
- .default(2)
64
+ .default(10)
68
65
  .describe(
69
66
  "Maximum heartbeats that can run per calendar day. Resets at midnight local time. Set to null for unlimited.",
70
67
  ),
@@ -79,7 +79,6 @@ export const LLMCallSiteEnum = z.enum([
79
79
  "meetConsentMonitor",
80
80
  "meetChatOpportunity",
81
81
  "inference",
82
- "advisor",
83
82
  "vision",
84
83
  "trustRuleSuggestion",
85
84
  "homeGreeting",
@@ -442,13 +441,6 @@ export const ProfileEntry = LLMConfigFragment.extend({
442
441
  * #30362 even though the schema didn't accept it until now.
443
442
  */
444
443
  status: ProfileStatusSchema.nullable().optional(),
445
- /**
446
- * Whether the advisor is active while this profile is the chat profile.
447
- * Absent/null means enabled (default on); only an explicit `false` disables
448
- * it. `.nullable()` matches `status`/`label` so the PUT route's "send null
449
- * to clear" sentinel resets it back to the default-on state.
450
- */
451
- advisorEnabled: z.boolean().nullable().optional(),
452
444
  /**
453
445
  * When present, this profile is a "mix": it carries no model config and
454
446
  * instead references a weighted list of standard profiles. The resolver
@@ -492,10 +484,9 @@ export const LLMSchema = z
492
484
  // schema level, so `LLMSchema.parse({})` yields an empty map.
493
485
  callSites: z.partialRecord(LLMCallSiteEnum, LLMCallSiteConfig).default({}),
494
486
  activeProfile: z.string().min(1).optional(),
495
- // The profile the advisor consults (chosen under Models & Services). It is
496
- // excluded from the chat-profile pickers so it can't be selected as the
497
- // assistant's chat model. Absent falls back to the `advisor` call-site
498
- // default (`quality-optimized`).
487
+ // The profile the advisor role consults when spawned as a subagent (chosen
488
+ // under Models & Services). It is excluded from the chat-profile pickers so
489
+ // it can't be selected as the assistant's chat model.
499
490
  advisorProfile: z.string().min(1).optional(),
500
491
  // TTL bounds for inference profile sessions. `defaultTtlSeconds` is read by
501
492
  // the CLI to apply when `--ttl` is omitted; the daemon handler itself only
@@ -78,6 +78,17 @@ export const MemoryJobsConfigSchema = MemoryJobsConfigInputSchema.transform(
78
78
  },
79
79
  ).describe("Memory background job processing configuration");
80
80
 
81
+ export const MemoryWorkerConfigSchema = z
82
+ .object({
83
+ enabled: z
84
+ .boolean({ error: "memory.worker.enabled must be a boolean" })
85
+ .default(false)
86
+ .describe(
87
+ "Whether the memory jobs worker runs as a separate OS process instead of the assistant's synchronous in-process runner. The assistant's worker supervisor re-reads this flag on every poll: while it is set, the in-process runner stands down (the out-of-process worker, spawned at startup when set, owns the queue); while it is unset, the in-process runner drains the queue. `assistant memory worker start`/`stop` flip the flag (and spawn/stop the worker process) to switch modes at runtime without a restart.",
88
+ ),
89
+ })
90
+ .describe("Memory jobs worker process configuration");
91
+
81
92
  export const MemoryRetentionConfigSchema = z
82
93
  .object({
83
94
  keepRawForever: z
@@ -185,6 +196,7 @@ export const MemoryMaintenanceConfigSchema = z
185
196
  );
186
197
 
187
198
  export type MemoryJobsConfig = z.infer<typeof MemoryJobsConfigSchema>;
199
+ export type MemoryWorkerConfig = z.infer<typeof MemoryWorkerConfigSchema>;
188
200
  export type MemoryRetentionConfig = z.infer<typeof MemoryRetentionConfigSchema>;
189
201
  export type MemoryCleanupConfig = z.infer<typeof MemoryCleanupConfigSchema>;
190
202
  export type MemoryMaintenanceConfig = z.infer<
@@ -259,6 +259,13 @@ export const MemoryV3ConfigSchema = z
259
259
  .describe(
260
260
  "Per-lane article budget for the reply-query finder pass: needle and dense each re-run over the assistant's previous message as separate queries (never concatenated with the user's message). 0 disables the pass. Deliberately small next to needleK/denseK — the pass adds the assistant-side retrieval signal, not a second full sweep.",
261
261
  ),
262
+ selectorPromptPath: z
263
+ .string({ error: "memory.v3.selectorPromptPath must be a string" })
264
+ .nullable()
265
+ .default(null)
266
+ .describe(
267
+ "Optional path to a file whose contents replace the bundled per-turn selector system prompt (the instructions that tell the selector which candidate pages to keep). Absolute paths are used as-is, a leading `~/` is expanded to the home directory, otherwise the path is resolved under the workspace root. The selector prompt takes no placeholders — the candidate pool is supplied separately as the user message — so the file is used verbatim. If the file is missing, unreadable, empty, or over 1 MiB, the bundled prompt is used and a warning is logged.",
268
+ ),
262
269
  edge: MemoryV3EdgeSchema.default(MemoryV3EdgeSchema.parse({})),
263
270
  })
264
271
  .describe("Memory v3 — section-grain lane retrieval");
@@ -5,6 +5,7 @@ import {
5
5
  MemoryJobsConfigSchema,
6
6
  MemoryMaintenanceConfigSchema,
7
7
  MemoryRetentionConfigSchema,
8
+ MemoryWorkerConfigSchema,
8
9
  } from "./memory-lifecycle.js";
9
10
  import {
10
11
  MemoryExtractionConfigSchema,
@@ -39,6 +40,9 @@ export const MemoryConfigSchema = z
39
40
  MemorySegmentationConfigSchema.parse({}),
40
41
  ),
41
42
  jobs: MemoryJobsConfigSchema.default(MemoryJobsConfigSchema.parse({})),
43
+ worker: MemoryWorkerConfigSchema.default(
44
+ MemoryWorkerConfigSchema.parse({}),
45
+ ),
42
46
  retention: MemoryRetentionConfigSchema.default(
43
47
  MemoryRetentionConfigSchema.parse({}),
44
48
  ),
@@ -28,6 +28,14 @@ export const TimeoutConfigSchema = z
28
28
  .describe(
29
29
  "How long to wait for user permission approval before timing out (seconds)",
30
30
  ),
31
+ questionResponseTimeoutSec: z
32
+ .number({ error: "timeouts.questionResponseTimeoutSec must be a number" })
33
+ .finite("timeouts.questionResponseTimeoutSec must be finite")
34
+ .positive("timeouts.questionResponseTimeoutSec must be a positive number")
35
+ .default(1800)
36
+ .describe(
37
+ "Backstop timeout for an unanswered ask_question prompt (seconds). The primary way an interactive user dismisses a prompt is by moving on — enqueuing another message supersedes it — so this only bounds a prompt left open with no response and no follow-up message.",
38
+ ),
31
39
  toolExecutionTimeoutSec: z
32
40
  .number({ error: "timeouts.toolExecutionTimeoutSec must be a number" })
33
41
  .finite("timeouts.toolExecutionTimeoutSec must be finite")
@@ -52,7 +52,7 @@ const MANAGED_PROFILE_TEMPLATES: Record<string, ManagedProfileTemplate> = {
52
52
  label: "Balanced",
53
53
  description: "Good balance of quality, cost, and speed",
54
54
  maxTokens: 32000,
55
- effort: "high",
55
+ effort: "medium",
56
56
  thinking: { enabled: true, streamThinking: true },
57
57
  contextWindow: { maxInputTokens: DEFAULT_CONTEXT_WINDOW_MAX_INPUT_TOKENS },
58
58
  topP: 0.95,
@@ -84,19 +84,25 @@ const MANAGED_PROFILE_TEMPLATES: Record<string, ManagedProfileTemplate> = {
84
84
  effort: "high",
85
85
  thinking: { enabled: true, streamThinking: true },
86
86
  contextWindow: { maxInputTokens: DEFAULT_CONTEXT_WINDOW_MAX_INPUT_TOKENS },
87
- // This is the advisor's own (strongest) profile: when it's also the chat
88
- // profile there's nothing stronger to consult, so the advisor defaults off.
89
- advisorEnabled: false,
90
87
  },
88
+ // Served by DeepSeek V4 Flash on Fireworks via managed platform inference: a
89
+ // fast, low-cost open model. `model` is pinned explicitly rather than
90
+ // resolved via the `latency-optimized` intent (which still maps to Kimi K2.5
91
+ // on Fireworks and Anthropic Haiku elsewhere).
92
+ //
93
+ // `effort: "none"` (not "low") because Fireworks is not thinking-aware: the
94
+ // disabled `thinking` config is stripped before the request, so a non-"none"
95
+ // effort would be sent as `reasoning_effort` and make this profile pay for
96
+ // reasoning despite thinking being off. "none" keeps Speed non-reasoning.
91
97
  "cost-optimized": {
92
- intent: "latency-optimized",
93
- provider: "anthropic",
94
- connectionName: "anthropic-managed",
98
+ model: "accounts/fireworks/models/deepseek-v4-flash",
99
+ provider: "fireworks",
100
+ connectionName: "fireworks-managed",
95
101
  source: "managed",
96
102
  label: "Speed",
97
- description: "Fastest responses at lower cost",
103
+ description: "Fastest responses at lower cost (DeepSeek V4 Flash)",
98
104
  maxTokens: 8192,
99
- effort: "low",
105
+ effort: "none",
100
106
  thinking: { enabled: false, streamThinking: false },
101
107
  contextWindow: { maxInputTokens: DEFAULT_CONTEXT_WINDOW_MAX_INPUT_TOKENS },
102
108
  },
@@ -155,19 +161,20 @@ export const OS_BETA_FEATURE_FLAG_KEY = "os-beta";
155
161
  * Flag-gated managed profile. NOT in MANAGED_PROFILE_TEMPLATES, so the
156
162
  * unconditional boot seed never creates it. Reconciled in/out by
157
163
  * the flag-gated profile reconcile based on the `os-beta` feature flag.
158
- * Balanced-parity defaults; GLM 5.2 pinned explicitly via `model`.
164
+ * Balanced defaults, with lower reasoning effort while the profile is in beta.
159
165
  */
160
166
  export const OS_BETA_PROFILE_TEMPLATE: ManagedProfileTemplate = {
161
- model: "accounts/fireworks/models/glm-5p2",
162
- provider: "fireworks",
163
- connectionName: "fireworks-managed",
167
+ intent: "balanced",
168
+ provider: "together",
169
+ connectionName: "together-managed",
164
170
  source: "managed",
165
171
  label: "OS Beta",
166
- description: "Open-source frontier model (GLM 5.2), in beta",
172
+ description: "Good balance of quality, cost, and speed, in beta",
167
173
  maxTokens: 32000,
168
- effort: "high",
174
+ effort: "low",
169
175
  thinking: { enabled: true, streamThinking: true },
170
176
  contextWindow: { maxInputTokens: DEFAULT_CONTEXT_WINDOW_MAX_INPUT_TOKENS },
177
+ topP: 0.95,
171
178
  };
172
179
 
173
180
  // Membership here marks a name as managed. The route layer applies managed
@@ -214,11 +221,9 @@ export type SeedInferenceProfilesOptions = {
214
221
  * `cost-optimized`): reconciled from the code templates on every boot —
215
222
  * on-platform and off-platform alike — so Vellum can push model/config
216
223
  * updates to customers in a release without a workspace migration. The
217
- * templates own all profile content; `label`, `status`, `advisorEnabled`,
218
- * and `topP` are user overrides that survive reseeds. Of those, only
219
- * `label`, `status`, and `topP` are editable through the managed PUT route
220
- * allowlist; `advisorEnabled` is edited via the generic config path but is
221
- * still preserved here so it survives reboots.
224
+ * templates own all profile content; `label`, `status`, and `topP` are user
225
+ * overrides that survive reseeds and are editable through the managed PUT
226
+ * route allowlist.
222
227
  * Platform overlays (`preserveProfileNames`) take precedence for the boot
223
228
  * they are supplied.
224
229
  *
@@ -273,14 +278,11 @@ export function seedInferenceProfiles(
273
278
  // as usual.
274
279
  //
275
280
  // A whitelist of user-editable fields survives the reconcile: `label`
276
- // (display rename), `status` (active/disabled toggle), `advisorEnabled`
277
- // (per-profile advisor toggle), and `topP` (sampling override) — the only
278
- // fields a user may override. The managed PUT route
279
- // `/v1/config/llm/profiles/:name` lets users patch `label`, `status`, and
280
- // `topP` on managed profiles without duplicating (its editable allowlist,
281
- // `MANAGED_PROFILE_EDITABLE_KEYS`, deliberately excludes `advisorEnabled`,
282
- // which is set through the generic config path). We honor every one of
283
- // these overrides across reseeds or they'd silently revert on every boot.
281
+ // (display rename), `status` (active/disabled toggle), and `topP`
282
+ // (sampling override) — the only fields a user may override. The managed
283
+ // PUT route `/v1/config/llm/profiles/:name` lets users patch these on
284
+ // managed profiles without duplicating. We honor every one of these
285
+ // overrides across reseeds or they'd silently revert on every boot.
284
286
  // Carry by key-presence rather than truthiness so an explicit `null` (user
285
287
  // cleared the field) survives too.
286
288
  //
@@ -352,12 +354,6 @@ export function seedInferenceProfiles(
352
354
  : previous.label;
353
355
  }
354
356
  if ("status" in previous) next.status = previous.status;
355
- // The per-profile advisor toggle is a user override — preserve it across
356
- // reseeds so a user's choice survives reboots (the template value only
357
- // seeds the initial default, e.g. off for quality-optimized).
358
- if ("advisorEnabled" in previous) {
359
- next.advisorEnabled = previous.advisorEnabled;
360
- }
361
357
  // `topP` is user-editable on managed profiles (see the managed-profile
362
358
  // editable allowlist on the PUT route) — preserve a user override across
363
359
  // reseeds, including an explicit `null` clear, or it would silently revert
@@ -688,6 +688,9 @@ function discoverSkillDirectories(skillsDir: string): string[] {
688
688
  * parseable `package.json` whose `name` equals the directory name. This
689
689
  * mirrors the external plugin loader's recognition gate, which skips any
690
690
  * directory whose `manifest.name` does not match its directory name.
691
+ *
692
+ * The caller is responsible for the missing-`package.json` case (it emits a
693
+ * diagnostic warning); this function only judges a manifest that is present.
691
694
  */
692
695
  function isRecognizedPluginDir(pluginDir: string, dirName: string): boolean {
693
696
  const manifestPath = join(pluginDir, "package.json");
@@ -735,12 +738,31 @@ function discoverPluginResidentSkills(): SkillSummary[] {
735
738
  for (const entry of entries) {
736
739
  if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
737
740
  const pluginDir = join(pluginsDir, entry.name);
741
+
742
+ // A directory under `plugins/` with no `package.json` is not a plugin the
743
+ // runtime can load, so its skills are never surfaced. This is an easy
744
+ // footgun — a plugin dropped in without its manifest looks installed but
745
+ // silently contributes nothing — so warn loudly with the path rather than
746
+ // skipping in silence, to make the misconfiguration diagnosable.
747
+ if (!existsSync(join(pluginDir, "package.json"))) {
748
+ log.warn(
749
+ { pluginDir },
750
+ "Plugin directory is missing package.json — skipping; its skills will not be available. Add a package.json whose `name` matches the directory.",
751
+ );
752
+ continue;
753
+ }
754
+
755
+ // Honor the `.disabled` sentinel the runtime plugin scan checks
756
+ // (`plugins/mtime-cache.ts`): a disabled plugin contributes no hooks or
757
+ // tools, so its resident skills must not be loadable either.
758
+ if (existsSync(join(pluginDir, ".disabled"))) continue;
759
+
738
760
  // Mirror the plugin loader's recognition gate: a directory is a real
739
- // installed plugin only if it carries a parseable `package.json` whose
740
- // `name` matches the directory. This rejects staging dirs, stray files,
741
- // and malformed/mismatched clones (e.g. an un-adapted `caveman-installer`)
742
- // that the loader itself would skip, so the catalog never surfaces skills
743
- // from a directory the runtime would refuse to load.
761
+ // installed plugin only if its `package.json` `name` matches the directory.
762
+ // This rejects staging dirs and malformed/mismatched clones (e.g. an
763
+ // un-adapted `caveman-installer`) that the loader itself would skip, so the
764
+ // catalog never surfaces skills from a directory the runtime would refuse
765
+ // to load.
744
766
  if (!isRecognizedPluginDir(pluginDir, entry.name)) continue;
745
767
 
746
768
  const skillsDir = join(pluginDir, "skills");
@@ -23,12 +23,12 @@ const log = getLogger("sync-gated-profiles");
23
23
  * Reconcile flag-gated managed profiles against the current feature-flag state.
24
24
  *
25
25
  * `seedInferenceProfiles()` runs synchronously at boot before feature flags are
26
- * available, so the OS Beta profile (GLM 5.2 / fireworks-managed) is materialized
27
- * here once flags have loaded. When the `os-beta` flag is on, the managed profile
28
- * is created (ordered right after `balanced`); when it is off, a previously
29
- * managed entry is removed with `profileOrder` / `activeProfile` / `advisorProfile`
30
- * fallbacks. The reconcile is idempotent and never touches a user-owned profile of
31
- * the same name.
26
+ * available, so the OS Beta profile (MiniMax M3 / together-managed) is
27
+ * materialized here once flags have loaded. When the `os-beta` flag is on, the
28
+ * managed profile is created (ordered right after `balanced`); when it is off, a
29
+ * previously managed entry is removed with `profileOrder` / `activeProfile` /
30
+ * `advisorProfile` fallbacks. The reconcile is idempotent and never touches a
31
+ * user-owned profile of the same name.
32
32
  *
33
33
  * Returns whether the on-disk config changed.
34
34
  */
@@ -105,23 +105,19 @@ function enableProfile(
105
105
  OS_BETA_PROFILE_TEMPLATE.connectionName,
106
106
  ) as Record<string, unknown>;
107
107
 
108
- // BYOK installs seed managed profiles disabled: the platform-auth
109
- // `fireworks-managed` connection backing this profile isn't usable until the
110
- // user enables it, so a fresh OS Beta entry starts disabled to avoid offering
111
- // an unusable route. A user's own status override (preserved below) wins on
112
- // later reconciles.
108
+ // BYOK installs seed managed profiles disabled: the managed inference
109
+ // connection backing this profile isn't usable until the user enables it, so a
110
+ // fresh OS Beta entry starts disabled to avoid offering an unusable route. A
111
+ // user's own status override (preserved below) wins on later reconciles.
113
112
  if (isByokMode && !previous) {
114
113
  next.status = "disabled";
115
114
  }
116
115
 
117
116
  if (previous) {
118
- // The only fields a user may override on a managed profile. Carry `label`
119
- // by key-presence so an explicit null (user cleared it) survives too.
117
+ // Preserve user-owned overrides across reconciles.
120
118
  if ("label" in previous) next.label = previous.label;
121
119
  if ("status" in previous) next.status = previous.status;
122
- if ("advisorEnabled" in previous) {
123
- next.advisorEnabled = previous.advisorEnabled;
124
- }
120
+ if ("topP" in previous) next.topP = previous.topP;
125
121
  }
126
122
 
127
123
  let changed = false;
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Tests for the gateway-first member-revoke relay.
3
+ *
4
+ * revokeMemberChannel downgrades the channel's ACL status through the gateway
5
+ * (source of truth) via `ipcCallPersistent("mark_channel_revoked", ...)` first,
6
+ * then mirrors the downgrade to the assistant DB best-effort. A local mirror
7
+ * failure is swallowed so the gateway-owned outcome stands.
8
+ */
9
+
10
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
11
+
12
+ import type { ContactWriteResult } from "../types.js";
13
+
14
+ type IpcCall = { method: string; params?: Record<string, unknown> };
15
+
16
+ let ipcCalls: IpcCall[] = [];
17
+ let ipcOk = true;
18
+
19
+ const ipcCallPersistentMock = mock(
20
+ async (method: string, params?: Record<string, unknown>) => {
21
+ ipcCalls.push({ method, params });
22
+ return {
23
+ ok: ipcOk,
24
+ didWrite: ipcOk,
25
+ channel: {
26
+ id: (params?.contactChannelId as string) ?? "ch1",
27
+ contactId: "c1",
28
+ type: "telegram",
29
+ address: "addr",
30
+ status: "revoked",
31
+ revokedReason: (params?.reason as string) ?? null,
32
+ },
33
+ };
34
+ },
35
+ );
36
+ const actualGatewayClient = await import("../../ipc/gateway-client.js");
37
+ mock.module("../../ipc/gateway-client.js", () => ({
38
+ ...actualGatewayClient,
39
+ ipcCallPersistent: ipcCallPersistentMock,
40
+ }));
41
+
42
+
43
+ // Local resolver primitive — resolves the native contact/channel by id; the
44
+ // gateway owns the ACL downgrade, so it takes no reason and mutates nothing.
45
+ const revokeMemberResult: ContactWriteResult = {
46
+ contact: { id: "c1" } as ContactWriteResult["contact"],
47
+ channel: { id: "ch1" } as ContactWriteResult["channel"],
48
+ };
49
+ const revokeMemberMock = mock((_memberId: string) => revokeMemberResult);
50
+ const actualContactsWrite = await import("../contacts-write.js");
51
+ mock.module("../contacts-write.js", () => ({
52
+ ...actualContactsWrite,
53
+ revokeMember: revokeMemberMock,
54
+ }));
55
+
56
+ const { revokeMemberChannel } = await import("../member-write-relay.js");
57
+
58
+ describe("revokeMemberChannel gateway-first relay", () => {
59
+ beforeEach(() => {
60
+ ipcCalls = [];
61
+ ipcOk = true;
62
+ ipcCallPersistentMock.mockClear();
63
+ revokeMemberMock.mockClear();
64
+ revokeMemberMock.mockImplementation(() => revokeMemberResult);
65
+ });
66
+
67
+ test("relays the revoke to the gateway before mirroring locally", async () => {
68
+ const result = await revokeMemberChannel("ch1", "removed");
69
+
70
+ expect(ipcCalls).toEqual([
71
+ {
72
+ method: "mark_channel_revoked",
73
+ params: { contactChannelId: "ch1", reason: "removed" },
74
+ },
75
+ ]);
76
+ expect(revokeMemberMock).toHaveBeenCalledTimes(1);
77
+ expect(revokeMemberMock).toHaveBeenCalledWith("ch1");
78
+ expect(result).toBe(revokeMemberResult);
79
+ });
80
+
81
+ test("strips the composite contactId:channelId prefix before the relay", async () => {
82
+ await revokeMemberChannel("c1:ch1");
83
+
84
+ expect(ipcCalls[0]?.params?.contactChannelId).toBe("ch1");
85
+ // The local resolver still receives the original composite id it accepts.
86
+ expect(revokeMemberMock).toHaveBeenCalledWith("c1:ch1");
87
+ });
88
+
89
+ test("always relays — never skips based on local mirror status", async () => {
90
+ // The gateway owns the ACL outcome; the relay must fire even if the local
91
+ // mirror lags (says revoked) while the gateway row is still active.
92
+ await revokeMemberChannel("ch1");
93
+
94
+ expect(ipcCalls).toEqual([
95
+ {
96
+ method: "mark_channel_revoked",
97
+ params: { contactChannelId: "ch1", reason: undefined },
98
+ },
99
+ ]);
100
+ expect(revokeMemberMock).toHaveBeenCalledTimes(1);
101
+ });
102
+
103
+ test("swallows a local-mirror failure without throwing; the gateway revoke stands", async () => {
104
+ revokeMemberMock.mockImplementation(() => {
105
+ throw new Error("local mirror exploded");
106
+ });
107
+
108
+ const result = await revokeMemberChannel("ch1", "removed");
109
+
110
+ expect(ipcCalls).toHaveLength(1);
111
+ expect(result).toBeNull();
112
+ });
113
+
114
+ test("throws when the gateway relay returns ok: false", async () => {
115
+ ipcOk = false;
116
+
117
+ let thrown: Error | undefined;
118
+ try {
119
+ await revokeMemberChannel("ch1");
120
+ } catch (err) {
121
+ thrown = err as Error;
122
+ }
123
+
124
+ expect(thrown).toBeDefined();
125
+ // Local mirror must not run when the gateway refuses the downgrade.
126
+ expect(revokeMemberMock).not.toHaveBeenCalled();
127
+ });
128
+ });