@vellumai/assistant 0.9.0 → 0.10.0-dev.202606192226.8ed8a6a

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 (624) hide show
  1. package/ARCHITECTURE.md +19 -35
  2. package/bun.lock +7 -8
  3. package/docs/activation-funnel-telemetry.md +28 -22
  4. package/docs/architecture/security.md +29 -28
  5. package/docs/stt-provider-onboarding.md +3 -5
  6. package/docs/workflows-testing.md +13 -44
  7. package/docs/workflows.md +3 -5
  8. package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
  9. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
  10. package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
  11. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
  12. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
  13. package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
  14. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
  15. package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
  16. package/openapi.yaml +1128 -119
  17. package/package.json +2 -1
  18. package/scripts/sync-llm-catalog.ts +6 -15
  19. package/scripts/sync-web-search-catalog.ts +3 -11
  20. package/src/__tests__/access-request-card-view.test.ts +98 -0
  21. package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
  22. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
  23. package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
  24. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
  25. package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
  26. package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
  27. package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
  28. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
  29. package/src/__tests__/app-compiler.test.ts +15 -1
  30. package/src/__tests__/app-dir-path-guard.test.ts +0 -1
  31. package/src/__tests__/approval-cascade.test.ts +6 -0
  32. package/src/__tests__/approval-routes-http.test.ts +128 -0
  33. package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
  34. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
  35. package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
  36. package/src/__tests__/avatar-identity-sync.test.ts +2 -27
  37. package/src/__tests__/btw-routes.test.ts +6 -8
  38. package/src/__tests__/call-pointer-messages.test.ts +28 -0
  39. package/src/__tests__/cancel-clears-processing.test.ts +89 -0
  40. package/src/__tests__/channel-approval-routes.test.ts +0 -4
  41. package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
  42. package/src/__tests__/checker.test.ts +0 -3
  43. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
  44. package/src/__tests__/compaction-events.test.ts +6 -0
  45. package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
  46. package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
  47. package/src/__tests__/config-loader-backfill.test.ts +268 -27
  48. package/src/__tests__/config-schema.test.ts +35 -0
  49. package/src/__tests__/config-watcher.test.ts +0 -18
  50. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
  51. package/src/__tests__/contact-store-user-file.test.ts +0 -6
  52. package/src/__tests__/contacts-tools.test.ts +29 -0
  53. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  54. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
  55. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  56. package/src/__tests__/conversation-agent-loop.test.ts +58 -0
  57. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  58. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
  59. package/src/__tests__/conversation-lifecycle.test.ts +7 -9
  60. package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
  61. package/src/__tests__/conversation-process-callsite.test.ts +6 -0
  62. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  63. package/src/__tests__/conversation-queue.test.ts +6 -0
  64. package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
  65. package/src/__tests__/conversation-slash-queue.test.ts +6 -0
  66. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +6 -0
  68. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
  69. package/src/__tests__/conversation-title-service.test.ts +62 -0
  70. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
  71. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  72. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  73. package/src/__tests__/credential-broker.test.ts +449 -1
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
  75. package/src/__tests__/credential-execution-tools.test.ts +0 -1
  76. package/src/__tests__/credential-prompt-route.test.ts +4 -4
  77. package/src/__tests__/credential-routes.test.ts +360 -0
  78. package/src/__tests__/credential-security-invariants.test.ts +4 -13
  79. package/src/__tests__/disk-pressure-policy.test.ts +12 -0
  80. package/src/__tests__/disk-pressure-tools.test.ts +41 -1
  81. package/src/__tests__/disk-usage.test.ts +65 -0
  82. package/src/__tests__/document-tool-security.test.ts +9 -6
  83. package/src/__tests__/document-update-default-surface.test.ts +202 -0
  84. package/src/__tests__/dynamic-page-surface.test.ts +152 -1
  85. package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
  86. package/src/__tests__/gateway-flag-listener.test.ts +110 -1
  87. package/src/__tests__/gateway-only-guard.test.ts +3 -7
  88. package/src/__tests__/gemini-count-tokens.test.ts +70 -0
  89. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  90. package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
  91. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
  92. package/src/__tests__/guardian-grant-minting.test.ts +3 -35
  93. package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
  94. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  95. package/src/__tests__/headless-browser-mode.test.ts +10 -0
  96. package/src/__tests__/headless-browser-navigate.test.ts +8 -3
  97. package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
  98. package/src/__tests__/host-browser-proxy.test.ts +87 -0
  99. package/src/__tests__/identity-routes.test.ts +0 -189
  100. package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
  101. package/src/__tests__/injector-disk-pressure.test.ts +10 -5
  102. package/src/__tests__/injector-v3-suppression.test.ts +27 -20
  103. package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
  104. package/src/__tests__/invite-redemption-service.test.ts +4 -7
  105. package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
  106. package/src/__tests__/llm-catalog-parity.test.ts +30 -23
  107. package/src/__tests__/llm-resolver.test.ts +70 -24
  108. package/src/__tests__/llm-schema.test.ts +1 -0
  109. package/src/__tests__/managed-profile-guard.test.ts +163 -4
  110. package/src/__tests__/mcp-health-check.test.ts +6 -7
  111. package/src/__tests__/media-stream-server-integration.test.ts +317 -13
  112. package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
  113. package/src/__tests__/onboarding-persona-write.test.ts +1 -1
  114. package/src/__tests__/path-policy.test.ts +34 -0
  115. package/src/__tests__/persona-resolver.test.ts +49 -14
  116. package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
  117. package/src/__tests__/plugin-api-provider.test.ts +24 -0
  118. package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
  119. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
  120. package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
  121. package/src/__tests__/reaction-persistence.test.ts +150 -29
  122. package/src/__tests__/registry.test.ts +2 -7
  123. package/src/__tests__/relay-server.test.ts +285 -0
  124. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  125. package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
  126. package/src/__tests__/schedule-routes.test.ts +0 -30
  127. package/src/__tests__/schedule-tools.test.ts +2 -18
  128. package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
  129. package/src/__tests__/secret-response-routing.test.ts +35 -0
  130. package/src/__tests__/secret-routes-platform-proxy.test.ts +16 -2
  131. package/src/__tests__/skill-execute-input.test.ts +177 -1
  132. package/src/__tests__/skill-load-tool.test.ts +72 -0
  133. package/src/__tests__/skill-runtime-path.test.ts +2 -3
  134. package/src/__tests__/skills.test.ts +51 -0
  135. package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
  136. package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
  137. package/src/__tests__/subagent-tools.test.ts +266 -0
  138. package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
  139. package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
  140. package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
  141. package/src/__tests__/title-generate-hook.test.ts +100 -3
  142. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
  143. package/src/__tests__/token-manager.test.ts +519 -0
  144. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
  145. package/src/__tests__/tool-audit-listener.test.ts +7 -7
  146. package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
  147. package/src/__tests__/tool-executor.test.ts +0 -79
  148. package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
  149. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
  150. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
  151. package/src/__tests__/trusted-contact-verification.test.ts +8 -10
  152. package/src/__tests__/twilio-routes.test.ts +81 -1
  153. package/src/__tests__/voice-invite-redemption.test.ts +2 -3
  154. package/src/__tests__/weak-open-model.test.ts +30 -0
  155. package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
  156. package/src/__tests__/workspace-greetings.test.ts +152 -0
  157. package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
  158. package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
  159. package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
  160. package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
  161. package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
  162. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
  163. package/src/agent/loop.ts +75 -29
  164. package/src/api/README.md +6 -6
  165. package/src/api/events/tool-result.ts +6 -0
  166. package/src/api/events/workflow-completed.ts +53 -0
  167. package/src/api/events/workflow-leaf-finished.ts +38 -0
  168. package/src/api/events/workflow-leaf-started.ts +35 -0
  169. package/src/api/events/workflow-progress.ts +32 -0
  170. package/src/api/events/workflow-started.ts +31 -0
  171. package/src/api/index.ts +40 -0
  172. package/src/api/responses/conversation-message.ts +28 -4
  173. package/src/api/responses/home.ts +26 -4
  174. package/src/api/responses/workflow-journal.ts +53 -0
  175. package/src/approvals/guardian-card-withdrawal.ts +145 -0
  176. package/src/approvals/guardian-decision-primitive.ts +26 -3
  177. package/src/approvals/guardian-request-resolvers.ts +183 -80
  178. package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
  179. package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
  180. package/src/calls/call-pointer-messages.ts +10 -4
  181. package/src/calls/channel-admission-reader.ts +104 -0
  182. package/src/calls/guardian-dispatch.ts +17 -45
  183. package/src/calls/media-stream-server.ts +84 -2
  184. package/src/calls/relay-access-wait.ts +1 -1
  185. package/src/calls/relay-server.ts +66 -0
  186. package/src/calls/relay-setup-router.ts +82 -1
  187. package/src/calls/twilio-routes.ts +17 -8
  188. package/src/calls/voice-session-bridge.ts +2 -2
  189. package/src/cli/commands/clients.ts +3 -0
  190. package/src/cli/commands/db/status.ts +37 -3
  191. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
  192. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
  193. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
  194. package/src/cli/commands/memory/index.ts +30 -0
  195. package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
  196. package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
  197. package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
  198. package/src/cli/commands/oauth/status.test.ts +36 -0
  199. package/src/cli/commands/oauth/status.ts +23 -3
  200. package/src/cli/commands/plugins.ts +400 -14
  201. package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
  202. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  203. package/src/cli/lib/__tests__/install-from-github.test.ts +31 -0
  204. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
  205. package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
  206. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
  207. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
  208. package/src/cli/lib/diff-plugin.ts +346 -0
  209. package/src/cli/lib/inspect-plugin.ts +12 -1
  210. package/src/cli/lib/install-from-github.ts +128 -19
  211. package/src/cli/lib/merge-plugin-tree.ts +328 -0
  212. package/src/cli/lib/plugin-fingerprint.ts +14 -0
  213. package/src/cli/lib/plugin-marketplace.ts +11 -0
  214. package/src/cli/lib/plugin-pin-history.ts +257 -0
  215. package/src/cli/lib/plugin-surfaces.ts +104 -0
  216. package/src/cli/lib/upgrade-plugin.ts +298 -10
  217. package/src/cli/program.ts +2 -6
  218. package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
  219. package/src/config/assistant-feature-flags.ts +22 -7
  220. package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
  221. package/src/config/bundled-skills/document-editor/SKILL.md +3 -3
  222. package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
  223. package/src/config/bundled-skills/messaging/SKILL.md +6 -4
  224. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
  225. package/src/config/bundled-skills/subagent/SKILL.md +4 -0
  226. package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
  227. package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
  228. package/src/config/bundled-skills/workflows/SKILL.md +14 -8
  229. package/src/config/bundled-tool-registry.ts +2 -7
  230. package/src/config/call-site-defaults.ts +15 -2
  231. package/src/config/feature-flag-registry.json +46 -31
  232. package/src/config/inference-profile-validation.ts +26 -0
  233. package/src/config/llm-resolver.ts +3 -0
  234. package/src/config/loader.ts +4 -0
  235. package/src/config/memory-v3-gate.ts +11 -0
  236. package/src/config/profile-order.ts +28 -0
  237. package/src/config/schema.ts +8 -6
  238. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  239. package/src/config/schemas/call-site-catalog.ts +7 -0
  240. package/src/config/schemas/channels.ts +11 -0
  241. package/src/config/schemas/elevenlabs.ts +0 -1
  242. package/src/config/schemas/llm.ts +31 -0
  243. package/src/config/schemas/memory-lifecycle.ts +3 -7
  244. package/src/config/schemas/memory-v3.ts +6 -0
  245. package/src/config/schemas/platform.ts +0 -8
  246. package/src/config/schemas/services.ts +18 -0
  247. package/src/config/seed-inference-profiles.ts +109 -44
  248. package/src/config/skills.ts +21 -0
  249. package/src/config/sync-gated-profiles.ts +220 -0
  250. package/src/contacts/contact-store.ts +89 -106
  251. package/src/contacts/contacts-write.ts +5 -22
  252. package/src/contacts/types.ts +0 -1
  253. package/src/context/compactor.ts +88 -54
  254. package/src/context/strip-injections.ts +58 -10
  255. package/src/context/token-estimator.ts +1 -1
  256. package/src/credential-execution/process-manager.ts +55 -14
  257. package/src/credential-execution/prompted-credential.ts +2 -3
  258. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
  259. package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
  260. package/src/daemon/config-watcher.ts +0 -4
  261. package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
  262. package/src/daemon/conversation-agent-loop.ts +114 -22
  263. package/src/daemon/conversation-history.ts +1 -1
  264. package/src/daemon/conversation-lifecycle.ts +3 -5
  265. package/src/daemon/conversation-process.ts +13 -5
  266. package/src/daemon/conversation-runtime-assembly.ts +13 -15
  267. package/src/daemon/conversation-slash.ts +2 -23
  268. package/src/daemon/conversation-surfaces.ts +26 -0
  269. package/src/daemon/conversation-tool-setup.ts +53 -19
  270. package/src/daemon/conversation.ts +131 -20
  271. package/src/daemon/disk-pressure-policy.ts +5 -3
  272. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
  273. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
  274. package/src/daemon/handlers/config-a2a.ts +0 -2
  275. package/src/daemon/handlers/config-channels.ts +15 -16
  276. package/src/daemon/handlers/config-slack-channel.ts +22 -3
  277. package/src/daemon/handlers/conversations.ts +107 -0
  278. package/src/daemon/host-browser-proxy.ts +41 -0
  279. package/src/daemon/lifecycle.ts +55 -27
  280. package/src/daemon/memory-v2-startup.test.ts +131 -0
  281. package/src/daemon/memory-v2-startup.ts +100 -1
  282. package/src/daemon/message-provenance.ts +2 -0
  283. package/src/daemon/message-types/contacts.ts +0 -1
  284. package/src/daemon/message-types/conversations.ts +3 -3
  285. package/src/daemon/message-types/sync.ts +0 -1
  286. package/src/daemon/message-types/web-activity.ts +7 -1
  287. package/src/daemon/message-types/workflows.ts +83 -1
  288. package/src/daemon/orphan-reaper.test.ts +0 -19
  289. package/src/daemon/orphan-reaper.ts +2 -24
  290. package/src/daemon/server.ts +0 -10
  291. package/src/daemon/tool-setup-types.ts +4 -0
  292. package/src/daemon/trust-context.ts +1 -1
  293. package/src/daemon/wake-conversation-ops.ts +1 -0
  294. package/src/events/tool-audit-listener.ts +2 -2
  295. package/src/home/feed-source-enrichment.test.ts +151 -0
  296. package/src/home/feed-source-enrichment.ts +176 -0
  297. package/src/home/relationship-state.ts +2 -4
  298. package/src/instrument.ts +18 -6
  299. package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
  300. package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
  301. package/src/ipc/assistant-server.ts +37 -4
  302. package/src/ipc/gateway-flag-listener.ts +18 -2
  303. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
  304. package/src/memory/__tests__/db-logs-attach.test.ts +122 -0
  305. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
  306. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
  307. package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
  308. package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
  309. package/src/memory/auth-fallback-events-store.ts +2 -2
  310. package/src/memory/auto-analysis-enqueue.ts +3 -5
  311. package/src/memory/bookmark-crud.ts +1 -2
  312. package/src/memory/canonical-guardian-store.ts +39 -1
  313. package/src/memory/conversation-crud.ts +9 -4
  314. package/src/memory/conversation-key-store.ts +17 -2
  315. package/src/memory/conversation-title-service.ts +64 -7
  316. package/src/memory/db-async-query.ts +20 -2
  317. package/src/memory/db-connection.ts +49 -5
  318. package/src/memory/db-init.ts +17 -17
  319. package/src/memory/embedding-backend.ts +38 -1
  320. package/src/memory/embedding-billing-breaker.ts +96 -0
  321. package/src/memory/jobs-store.ts +25 -13
  322. package/src/memory/jobs-worker.ts +54 -1
  323. package/src/memory/lifecycle-events-store.ts +2 -2
  324. package/src/memory/memory-retrospective-constants.ts +4 -4
  325. package/src/memory/memory-retrospective-enqueue.ts +31 -6
  326. package/src/memory/memory-retrospective-job.ts +28 -227
  327. package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
  328. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
  329. package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
  330. package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
  331. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
  332. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
  333. package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
  334. package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
  335. package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
  336. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
  337. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
  338. package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
  339. package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
  340. package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
  341. package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
  342. package/src/memory/migrations/index.ts +6 -0
  343. package/src/memory/migrations/run-migrations.ts +41 -0
  344. package/src/memory/migrations/validate-migration-state.ts +1 -1
  345. package/src/memory/onboarding-events-store.ts +3 -3
  346. package/src/memory/schema/contacts.ts +0 -5
  347. package/src/memory/skill-loaded-events-store.test.ts +7 -15
  348. package/src/memory/skill-loaded-events-store.ts +2 -2
  349. package/src/memory/tool-executed-events-store.test.ts +7 -7
  350. package/src/memory/turn-trace-store.test.ts +736 -0
  351. package/src/memory/turn-trace-store.ts +364 -0
  352. package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
  353. package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
  354. package/src/memory/v2/consolidation-job.ts +2 -2
  355. package/src/memory/v2/skill-content.ts +25 -7
  356. package/src/memory/v2/skill-store.ts +7 -1
  357. package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
  358. package/src/memory/v3-eval/eval-packets.ts +546 -0
  359. package/src/messaging/providers/slack/adapter.ts +1 -1
  360. package/src/messaging/providers/slack/api.ts +31 -0
  361. package/src/messaging/providers/slack/send.test.ts +114 -2
  362. package/src/messaging/providers/slack/send.ts +30 -7
  363. package/src/messaging/providers/slack/withdraw.test.ts +200 -0
  364. package/src/messaging/providers/slack/withdraw.ts +161 -0
  365. package/src/notifications/AGENTS.md +2 -0
  366. package/src/notifications/access-request-copy.ts +72 -59
  367. package/src/notifications/adapters/shared.ts +29 -0
  368. package/src/notifications/adapters/slack.ts +58 -103
  369. package/src/notifications/adapters/telegram.ts +2 -20
  370. package/src/notifications/approval-card-data.ts +333 -0
  371. package/src/notifications/broadcaster.ts +16 -3
  372. package/src/notifications/canonical-delivery-recorder.ts +139 -0
  373. package/src/notifications/copy-composer.ts +3 -3
  374. package/src/notifications/decision-engine.ts +4 -2
  375. package/src/notifications/destination-resolver.ts +4 -6
  376. package/src/notifications/guardian-question-mode.ts +10 -0
  377. package/src/notifications/home-feed-side-effect.ts +7 -16
  378. package/src/notifications/notification-utils.ts +19 -20
  379. package/src/notifications/signal.ts +79 -43
  380. package/src/notifications/types.ts +98 -121
  381. package/src/oauth/AGENTS.md +5 -24
  382. package/src/permissions/checker.test.ts +51 -0
  383. package/src/permissions/checker.ts +185 -26
  384. package/src/permissions/ipc-risk-types.ts +24 -0
  385. package/src/permissions/question-prompter.test.ts +27 -0
  386. package/src/permissions/question-prompter.ts +4 -0
  387. package/src/permissions/secret-prompter.ts +15 -1
  388. package/src/platform/client.test.ts +119 -0
  389. package/src/platform/client.ts +66 -0
  390. package/src/platform/consent-cache.test.ts +267 -0
  391. package/src/platform/consent-cache.ts +174 -0
  392. package/src/plugin-api/constants.ts +1 -1
  393. package/src/plugin-api/index.ts +33 -1
  394. package/src/plugin-api/model-profiles.ts +33 -0
  395. package/src/plugin-api/types.ts +50 -2
  396. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
  397. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
  398. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
  399. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
  400. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
  401. package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
  402. package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
  403. package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
  404. package/src/plugins/defaults/advisor/config.ts +21 -0
  405. package/src/plugins/defaults/advisor/consult.ts +93 -0
  406. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
  407. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
  408. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
  409. package/src/plugins/defaults/advisor/package.json +14 -0
  410. package/src/plugins/defaults/advisor/steering.ts +67 -0
  411. package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
  412. package/src/plugins/defaults/advisor/transcript.ts +76 -0
  413. package/src/plugins/defaults/compaction/window-manager.ts +18 -0
  414. package/src/plugins/defaults/index.ts +60 -0
  415. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
  416. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  417. package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
  418. package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
  419. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
  420. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
  421. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
  422. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
  423. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
  424. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
  425. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
  426. package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
  427. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
  428. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
  429. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
  430. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
  431. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
  432. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
  433. package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
  434. package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
  435. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
  436. package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
  437. package/src/prompts/persona-resolver.ts +14 -4
  438. package/src/prompts/templates/system-sections.ts +7 -2
  439. package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
  440. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  441. package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
  442. package/src/providers/__tests__/retry-callsite.test.ts +176 -0
  443. package/src/providers/anthropic/client.ts +230 -175
  444. package/src/providers/atlascloud/client.ts +85 -0
  445. package/src/providers/call-site-routing.ts +10 -0
  446. package/src/providers/fetch-provider-catalog.ts +85 -0
  447. package/src/providers/gemini/client.ts +43 -0
  448. package/src/providers/inference/adapter-factory.ts +3 -0
  449. package/src/providers/model-catalog.ts +58 -0
  450. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
  451. package/src/providers/openai/chat-completions-provider.ts +7 -0
  452. package/src/providers/openai/responses-provider.ts +10 -0
  453. package/src/providers/provider-send-message.ts +11 -3
  454. package/src/providers/ratelimit.ts +9 -0
  455. package/src/providers/retry.ts +62 -12
  456. package/src/providers/search-provider-catalog.ts +10 -0
  457. package/src/providers/types.ts +16 -0
  458. package/src/providers/usage-tracking.ts +7 -0
  459. package/src/providers/weak-open-model.ts +22 -0
  460. package/src/runtime/AGENTS.md +0 -1
  461. package/src/runtime/__tests__/agent-wake.test.ts +227 -0
  462. package/src/runtime/__tests__/client-health.test.ts +44 -0
  463. package/src/runtime/access-request-helper.ts +21 -53
  464. package/src/runtime/actor-trust-resolver.ts +59 -63
  465. package/src/runtime/agent-wake.ts +71 -0
  466. package/src/runtime/assistant-event-hub.ts +18 -4
  467. package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
  468. package/src/runtime/auth/require-bound-guardian.ts +1 -4
  469. package/src/runtime/btw-sidechain.ts +3 -6
  470. package/src/runtime/capabilities.test.ts +120 -0
  471. package/src/runtime/capabilities.ts +197 -0
  472. package/src/runtime/channel-approval-types.ts +22 -45
  473. package/src/runtime/channel-invite-transports/telegram.ts +4 -4
  474. package/src/runtime/channel-retry-sweep.ts +1 -0
  475. package/src/runtime/channel-verification-service.ts +3 -3
  476. package/src/runtime/client-health.ts +26 -0
  477. package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
  478. package/src/runtime/effective-capabilities.test.ts +128 -0
  479. package/src/runtime/effective-capabilities.ts +84 -0
  480. package/src/runtime/guardian-reply-router.ts +106 -21
  481. package/src/runtime/invite-redemption-service.ts +9 -25
  482. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +126 -0
  483. package/src/runtime/migrations/vbundle-builder.ts +49 -20
  484. package/src/runtime/pending-interactions.ts +35 -0
  485. package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
  486. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
  487. package/src/runtime/routes/__tests__/plugins-routes.test.ts +383 -1
  488. package/src/runtime/routes/app-routes.ts +1 -1
  489. package/src/runtime/routes/approval-routes.ts +40 -9
  490. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
  491. package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
  492. package/src/runtime/routes/browser-tabs-routes.ts +9 -0
  493. package/src/runtime/routes/btw-routes.ts +1 -27
  494. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
  495. package/src/runtime/routes/client-routes.ts +10 -0
  496. package/src/runtime/routes/contact-routes.ts +31 -8
  497. package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
  498. package/src/runtime/routes/conversation-management-routes.ts +80 -1
  499. package/src/runtime/routes/conversation-query-routes.ts +68 -22
  500. package/src/runtime/routes/conversation-routes.ts +39 -14
  501. package/src/runtime/routes/credential-routes.ts +40 -16
  502. package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
  503. package/src/runtime/routes/events-routes.ts +1 -3
  504. package/src/runtime/routes/guardian-approval-interception.ts +14 -73
  505. package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
  506. package/src/runtime/routes/home-feed-routes.ts +8 -3
  507. package/src/runtime/routes/identity-routes.ts +1 -296
  508. package/src/runtime/routes/inbound-message-handler.ts +214 -228
  509. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
  510. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
  511. package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
  512. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
  513. package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
  514. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
  515. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
  516. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
  517. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
  518. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
  519. package/src/runtime/routes/index.ts +2 -0
  520. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
  521. package/src/runtime/routes/integrations/slack/channel.ts +36 -0
  522. package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
  523. package/src/runtime/routes/mcp-auth-routes.ts +233 -41
  524. package/src/runtime/routes/memory-eval-routes.ts +87 -0
  525. package/src/runtime/routes/notification-routes.ts +122 -133
  526. package/src/runtime/routes/platform-routes.ts +2 -2
  527. package/src/runtime/routes/plugins-routes.ts +366 -11
  528. package/src/runtime/routes/schedule-routes.ts +0 -22
  529. package/src/runtime/routes/secret-routes.ts +15 -0
  530. package/src/runtime/routes/surface-action-routes.ts +2 -1
  531. package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
  532. package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
  533. package/src/runtime/routes/workflow-routes.test.ts +229 -44
  534. package/src/runtime/routes/workflow-routes.ts +131 -29
  535. package/src/runtime/routes/workspace-greetings.ts +55 -0
  536. package/src/runtime/sync/resource-sync-events.ts +1 -11
  537. package/src/runtime/tool-grant-request-helper.ts +18 -16
  538. package/src/runtime/trust-context-resolver.ts +8 -5
  539. package/src/schedule/inference-profile.ts +2 -14
  540. package/src/schedule/schedule-store.ts +1 -1
  541. package/src/schedule/scheduler-types.ts +5 -1
  542. package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
  543. package/src/security/secret-patterns.ts +3 -0
  544. package/src/subagent/manager.ts +17 -4
  545. package/src/subagent/types.ts +6 -0
  546. package/src/telemetry/trace-collection-policy.test.ts +28 -0
  547. package/src/telemetry/trace-collection-policy.ts +30 -0
  548. package/src/telemetry/types.ts +89 -0
  549. package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
  550. package/src/telemetry/usage-telemetry-reporter.ts +148 -41
  551. package/src/tools/AGENTS.md +3 -3
  552. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
  553. package/src/tools/browser/browser-execution.ts +30 -19
  554. package/src/tools/document/document-tool.ts +30 -6
  555. package/src/tools/executor.ts +5 -3
  556. package/src/tools/host-terminal/host-shell.ts +5 -4
  557. package/src/tools/memory/register.ts +2 -2
  558. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
  559. package/src/tools/network/__tests__/web-search.test.ts +143 -0
  560. package/src/tools/network/web-fetch.ts +372 -1
  561. package/src/tools/network/web-search-error.ts +1 -1
  562. package/src/tools/network/web-search.ts +213 -10
  563. package/src/tools/permission-checker.ts +4 -3
  564. package/src/tools/registry.ts +20 -0
  565. package/src/tools/schedule/create.ts +7 -12
  566. package/src/tools/schedule/update.ts +4 -11
  567. package/src/tools/shared/filesystem/path-policy.ts +39 -13
  568. package/src/tools/side-effects.ts +2 -17
  569. package/src/tools/skills/execute.ts +99 -2
  570. package/src/tools/skills/load.ts +43 -2
  571. package/src/tools/subagent/spawn.ts +64 -15
  572. package/src/tools/terminal/shell.ts +10 -4
  573. package/src/tools/tool-approval-handler.ts +18 -13
  574. package/src/tools/tool-manifest.ts +0 -2
  575. package/src/tools/types.ts +10 -0
  576. package/src/tools/ui-surface/definitions.ts +64 -3
  577. package/src/tools/verification-control-plane-policy.ts +3 -1
  578. package/src/tools/workflows/run-workflow.test.ts +8 -18
  579. package/src/tools/workflows/run-workflow.ts +1 -0
  580. package/src/util/disk-usage.ts +78 -23
  581. package/src/util/logs-db-path.ts +22 -0
  582. package/src/util/platform.ts +10 -3
  583. package/src/watcher/telemetry.ts +2 -2
  584. package/src/workflows/capabilities.ts +2 -3
  585. package/src/workflows/engine.test.ts +175 -1
  586. package/src/workflows/engine.ts +82 -0
  587. package/src/workflows/journal-store.test.ts +70 -0
  588. package/src/workflows/journal-store.ts +18 -3
  589. package/src/workflows/run-manager.test.ts +171 -28
  590. package/src/workflows/run-manager.ts +66 -24
  591. package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
  592. package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
  593. package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
  594. package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
  595. package/src/workspace/migrations/registry.ts +8 -0
  596. package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
  597. package/src/__tests__/credential-security-e2e.test.ts +0 -362
  598. package/src/__tests__/credential-vault-unit.test.ts +0 -1528
  599. package/src/__tests__/credential-vault.test.ts +0 -1706
  600. package/src/__tests__/identity-intro-cache.test.ts +0 -315
  601. package/src/__tests__/secret-onetime-send.test.ts +0 -182
  602. package/src/cli/commands/__tests__/task.test.ts +0 -914
  603. package/src/cli/commands/task.ts +0 -771
  604. package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
  605. package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
  606. package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
  607. package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
  608. package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
  609. package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
  610. package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
  611. package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
  612. package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
  613. package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
  614. package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
  615. package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
  616. package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
  617. package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
  618. package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
  619. package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
  620. package/src/memory/preloaded-apps.ts +0 -116
  621. package/src/notifications/tool-approval-copy.ts +0 -142
  622. package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
  623. package/src/runtime/routes/identity-intro-cache.ts +0 -172
  624. package/src/tools/credentials/vault.ts +0 -712
@@ -0,0 +1,367 @@
1
+ /**
2
+ * Tests for the default `surface-completion-nudge` plugin's hooks.
3
+ *
4
+ * Covers:
5
+ * - The `post-model-call` hook nudges (continue + canonical text appended as a
6
+ * `user` message) when a turn ends with a progress surface left open: a
7
+ * `task_progress` card shown and never advanced to a terminal status, and a
8
+ * `work_result` shown `in_progress`.
9
+ * - It does NOT nudge when the surface was completed via `ui_update`, dismissed
10
+ * via `ui_dismiss`, or was never a progress surface (a plain card / a form).
11
+ * - Outcomes it does not own are ignored: a provider rejection, a tool-bearing
12
+ * turn, and a non-main-agent call site.
13
+ * - The signal is scoped to the current response cycle — a surface left open in
14
+ * a prior cycle (before the last genuine user prompt) does not trigger it.
15
+ * - The one-shot bound is split across the two hooks: `post-model-call` marks it
16
+ * (nudging at most once per run) and `stop` clears it so the next run nudges
17
+ * afresh.
18
+ *
19
+ * The loop's actual continuation side-effects live in `agent/loop.ts` and are
20
+ * covered by integration tests. This file isolates the hook.
21
+ */
22
+
23
+ import { beforeEach, describe, expect, test } from "bun:test";
24
+
25
+ import type {
26
+ PluginLogger,
27
+ PostModelCallContext,
28
+ } from "../plugin-api/types.js";
29
+ import postModelCall, {
30
+ SURFACE_COMPLETION_NUDGE_TEXT,
31
+ } from "../plugins/defaults/surface-completion-nudge/hooks/post-model-call.js";
32
+ import stop from "../plugins/defaults/surface-completion-nudge/hooks/stop.js";
33
+ import {
34
+ isSurfaceCompletionNudged,
35
+ resetSurfaceCompletionNudgeStoreForTests,
36
+ } from "../plugins/defaults/surface-completion-nudge/nudge-state-store.js";
37
+ import type { ContentBlock, Message } from "../providers/types.js";
38
+
39
+ // ─── Fixtures ────────────────────────────────────────────────────────────────
40
+
41
+ const noopLogger: PluginLogger = {
42
+ info: () => {},
43
+ warn: () => {},
44
+ error: () => {},
45
+ debug: () => {},
46
+ };
47
+
48
+ const finalText: ContentBlock = { type: "text", text: "All set." };
49
+
50
+ let surfaceCounter = 0;
51
+
52
+ /**
53
+ * An assistant `ui_show` turn paired with its `{ surfaceId }` tool result.
54
+ * Returns both messages plus the assigned surface id.
55
+ */
56
+ function showSurface(input: Record<string, unknown>): {
57
+ messages: Message[];
58
+ surfaceId: string;
59
+ } {
60
+ surfaceCounter += 1;
61
+ const toolUseId = `tu_show_${surfaceCounter}`;
62
+ const surfaceId = `surface-${surfaceCounter}`;
63
+ return {
64
+ surfaceId,
65
+ messages: [
66
+ {
67
+ role: "assistant",
68
+ content: [{ type: "tool_use", id: toolUseId, name: "ui_show", input }],
69
+ },
70
+ {
71
+ role: "user",
72
+ content: [
73
+ {
74
+ type: "tool_result",
75
+ tool_use_id: toolUseId,
76
+ content: JSON.stringify({ surfaceId }),
77
+ },
78
+ ],
79
+ },
80
+ ],
81
+ };
82
+ }
83
+
84
+ function updateSurface(
85
+ surfaceId: string,
86
+ data: Record<string, unknown>,
87
+ ): Message {
88
+ return {
89
+ role: "assistant",
90
+ content: [
91
+ {
92
+ type: "tool_use",
93
+ id: `tu_update_${surfaceId}`,
94
+ name: "ui_update",
95
+ input: { surface_id: surfaceId, data },
96
+ },
97
+ ],
98
+ };
99
+ }
100
+
101
+ function dismissSurface(surfaceId: string): Message {
102
+ return {
103
+ role: "assistant",
104
+ content: [
105
+ {
106
+ type: "tool_use",
107
+ id: `tu_dismiss_${surfaceId}`,
108
+ name: "ui_dismiss",
109
+ input: { surface_id: surfaceId },
110
+ },
111
+ ],
112
+ };
113
+ }
114
+
115
+ function userPrompt(text: string): Message {
116
+ return { role: "user", content: [{ type: "text", text }] };
117
+ }
118
+
119
+ const taskProgressShow = (status?: string): Record<string, unknown> => ({
120
+ surface_type: "card",
121
+ title: "Working on X",
122
+ data: {
123
+ template: "task_progress",
124
+ templateData: {
125
+ title: "Working on X",
126
+ ...(status ? { status } : {}),
127
+ steps: [{ label: "Step 1", status: status ?? "in_progress" }],
128
+ },
129
+ },
130
+ });
131
+
132
+ function makeCtx(
133
+ overrides: Partial<PostModelCallContext> = {},
134
+ ): PostModelCallContext {
135
+ return {
136
+ conversationId: "conv-scn",
137
+ callSite: "mainAgent",
138
+ content: [finalText],
139
+ messages: [],
140
+ stopReason: null,
141
+ decision: "stop",
142
+ logger: noopLogger,
143
+ ...overrides,
144
+ };
145
+ }
146
+
147
+ beforeEach(() => {
148
+ resetSurfaceCompletionNudgeStoreForTests();
149
+ surfaceCounter = 0;
150
+ });
151
+
152
+ // ─── Nudges when a progress surface is left open ──────────────────────────────
153
+
154
+ describe("surface-completion-nudge — nudges on a dangling progress surface", () => {
155
+ test("task_progress card shown and never completed → continue with nudge", async () => {
156
+ const shown = showSurface(taskProgressShow("in_progress"));
157
+ const ctx = makeCtx({
158
+ messages: [userPrompt("do the thing"), ...shown.messages],
159
+ });
160
+
161
+ await postModelCall(ctx);
162
+
163
+ expect(ctx.decision).toBe("continue");
164
+ const last = ctx.messages[ctx.messages.length - 1];
165
+ expect(last.role).toBe("user");
166
+ expect(last.content[0]).toEqual({
167
+ type: "text",
168
+ text: SURFACE_COMPLETION_NUDGE_TEXT,
169
+ });
170
+ expect(isSurfaceCompletionNudged("conv-scn")).toBe(true);
171
+ });
172
+
173
+ test("task_progress card shown with no explicit status → continue with nudge", async () => {
174
+ const shown = showSurface(taskProgressShow());
175
+ const ctx = makeCtx({
176
+ messages: [userPrompt("go"), ...shown.messages],
177
+ });
178
+
179
+ await postModelCall(ctx);
180
+
181
+ expect(ctx.decision).toBe("continue");
182
+ });
183
+
184
+ test("work_result shown in_progress → continue with nudge", async () => {
185
+ const shown = showSurface({
186
+ surface_type: "work_result",
187
+ data: { status: "in_progress", summary: "Crunching" },
188
+ });
189
+ const ctx = makeCtx({
190
+ messages: [userPrompt("go"), ...shown.messages],
191
+ });
192
+
193
+ await postModelCall(ctx);
194
+
195
+ expect(ctx.decision).toBe("continue");
196
+ });
197
+ });
198
+
199
+ // ─── Stays quiet when there is nothing to close ───────────────────────────────
200
+
201
+ describe("surface-completion-nudge — no nudge when surface is closed or absent", () => {
202
+ test("task_progress completed via ui_update → stop", async () => {
203
+ const shown = showSurface(taskProgressShow("in_progress"));
204
+ const ctx = makeCtx({
205
+ messages: [
206
+ userPrompt("go"),
207
+ ...shown.messages,
208
+ updateSurface(shown.surfaceId, {
209
+ templateData: { status: "completed" },
210
+ }),
211
+ ],
212
+ });
213
+
214
+ await postModelCall(ctx);
215
+
216
+ expect(ctx.decision).toBe("stop");
217
+ expect(isSurfaceCompletionNudged("conv-scn")).toBe(false);
218
+ });
219
+
220
+ test("progress surface dismissed via ui_dismiss → stop", async () => {
221
+ const shown = showSurface(taskProgressShow("in_progress"));
222
+ const ctx = makeCtx({
223
+ messages: [
224
+ userPrompt("go"),
225
+ ...shown.messages,
226
+ dismissSurface(shown.surfaceId),
227
+ ],
228
+ });
229
+
230
+ await postModelCall(ctx);
231
+
232
+ expect(ctx.decision).toBe("stop");
233
+ });
234
+
235
+ test("work_result shown completed → stop", async () => {
236
+ const shown = showSurface({
237
+ surface_type: "work_result",
238
+ data: { status: "completed", summary: "Done" },
239
+ });
240
+ const ctx = makeCtx({
241
+ messages: [userPrompt("go"), ...shown.messages],
242
+ });
243
+
244
+ await postModelCall(ctx);
245
+
246
+ expect(ctx.decision).toBe("stop");
247
+ });
248
+
249
+ test("plain card (not a progress surface) → stop", async () => {
250
+ const shown = showSurface({
251
+ surface_type: "card",
252
+ title: "Weather",
253
+ data: { template: "weather_forecast", body: "Sunny" },
254
+ });
255
+ const ctx = makeCtx({
256
+ messages: [userPrompt("go"), ...shown.messages],
257
+ });
258
+
259
+ await postModelCall(ctx);
260
+
261
+ expect(ctx.decision).toBe("stop");
262
+ });
263
+
264
+ test("no surfaces shown at all → stop", async () => {
265
+ const ctx = makeCtx({
266
+ messages: [userPrompt("go")],
267
+ });
268
+
269
+ await postModelCall(ctx);
270
+
271
+ expect(ctx.decision).toBe("stop");
272
+ });
273
+ });
274
+
275
+ // ─── Outcomes the hook does not own ───────────────────────────────────────────
276
+
277
+ describe("surface-completion-nudge — ignores outcomes it does not own", () => {
278
+ test("provider rejection (error present) → stop", async () => {
279
+ const shown = showSurface(taskProgressShow("in_progress"));
280
+ const ctx = makeCtx({
281
+ messages: [userPrompt("go"), ...shown.messages],
282
+ error: new Error("provider exploded"),
283
+ });
284
+
285
+ await postModelCall(ctx);
286
+
287
+ expect(ctx.decision).toBe("stop");
288
+ });
289
+
290
+ test("tool-bearing turn (model still working) → stop", async () => {
291
+ const shown = showSurface(taskProgressShow("in_progress"));
292
+ const ctx = makeCtx({
293
+ messages: [userPrompt("go"), ...shown.messages],
294
+ content: [
295
+ { type: "tool_use", id: "tu_next", name: "read_file", input: {} },
296
+ ],
297
+ });
298
+
299
+ await postModelCall(ctx);
300
+
301
+ expect(ctx.decision).toBe("stop");
302
+ });
303
+
304
+ test("non-main-agent call site → stop", async () => {
305
+ const shown = showSurface(taskProgressShow("in_progress"));
306
+ const ctx = makeCtx({
307
+ messages: [userPrompt("go"), ...shown.messages],
308
+ callSite: "heartbeatAgent",
309
+ });
310
+
311
+ await postModelCall(ctx);
312
+
313
+ expect(ctx.decision).toBe("stop");
314
+ });
315
+ });
316
+
317
+ // ─── Cycle scoping and the one-shot bound ─────────────────────────────────────
318
+
319
+ describe("surface-completion-nudge — cycle scoping and one-shot bound", () => {
320
+ test("a surface left open in a prior cycle does not trigger this cycle", async () => {
321
+ const priorOpen = showSurface(taskProgressShow("in_progress"));
322
+ const ctx = makeCtx({
323
+ messages: [
324
+ userPrompt("first task"),
325
+ ...priorOpen.messages,
326
+ // New genuine user prompt opens a fresh cycle with no open surface.
327
+ userPrompt("second task"),
328
+ ],
329
+ });
330
+
331
+ await postModelCall(ctx);
332
+
333
+ expect(ctx.decision).toBe("stop");
334
+ });
335
+
336
+ test("nudges at most once per run; stop clears the bound", async () => {
337
+ const shown = showSurface(taskProgressShow("in_progress"));
338
+ const firstCtx = makeCtx({
339
+ messages: [userPrompt("go"), ...shown.messages],
340
+ });
341
+
342
+ await postModelCall(firstCtx);
343
+ expect(firstCtx.decision).toBe("continue");
344
+
345
+ // Same run, surface still open: the one-shot bound suppresses a second nudge.
346
+ const secondCtx = makeCtx({
347
+ messages: [userPrompt("go"), ...shown.messages],
348
+ });
349
+ await postModelCall(secondCtx);
350
+ expect(secondCtx.decision).toBe("stop");
351
+
352
+ // Terminal stop clears the bound so the next run nudges afresh.
353
+ await stop({
354
+ conversationId: "conv-scn",
355
+ messages: [],
356
+ exitReason: "no_tool_calls",
357
+ logger: noopLogger,
358
+ });
359
+ expect(isSurfaceCompletionNudged("conv-scn")).toBe(false);
360
+
361
+ const thirdCtx = makeCtx({
362
+ messages: [userPrompt("go"), ...shown.messages],
363
+ });
364
+ await postModelCall(thirdCtx);
365
+ expect(thirdCtx.decision).toBe("continue");
366
+ });
367
+ });
@@ -0,0 +1,56 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { loadSkillBySelector, loadSkillCatalog } from "../config/skills.js";
4
+
5
+ describe("system-storage-cleanup bundled skill", () => {
6
+ test("is bundled without tools or inline command expansions", () => {
7
+ const catalog = loadSkillCatalog();
8
+ const skill = catalog.find(
9
+ (candidate) => candidate.id === "system-storage-cleanup",
10
+ );
11
+
12
+ expect(skill).toBeDefined();
13
+ expect(skill!.source).toBe("bundled");
14
+ expect(skill!.bundled).toBe(true);
15
+ expect(skill!.toolManifest).toBeUndefined();
16
+ expect(skill!.inlineCommandExpansions).toBeUndefined();
17
+ });
18
+
19
+ test("loads by id with the cleanup safety contract", () => {
20
+ const result = loadSkillBySelector("system-storage-cleanup");
21
+
22
+ expect(result.error).toBeUndefined();
23
+ expect(result.skill).toBeDefined();
24
+ expect(result.skill!.id).toBe("system-storage-cleanup");
25
+ expect(result.skill!.source).toBe("bundled");
26
+
27
+ const body = result.skill!.body.toLowerCase();
28
+
29
+ expect(body).toContain("normal work is suspended");
30
+ expect(body).toContain("stay scoped to freeing storage");
31
+ expect(body).toContain("prefer foreground inspection");
32
+ expect(body).toContain("before any mutation");
33
+ expect(body).toContain("ask for explicit approval before deleting");
34
+ expect(body).toContain("target volume");
35
+ expect(body).toContain("workspace path");
36
+ expect(body).toContain("read-only `sqlite3` access");
37
+ expect(body).toContain("never run ad hoc `delete`");
38
+ expect(body).toContain("`vacuum`");
39
+ expect(body).toContain("mutating sqlite command");
40
+
41
+ for (const protectedText of [
42
+ "credentials",
43
+ "security material",
44
+ "workspace database files",
45
+ "config files",
46
+ "backups",
47
+ "backup keys",
48
+ "memory graph nodes or segments",
49
+ "`journal/`",
50
+ "`data/reflections/`",
51
+ "pkb files",
52
+ ]) {
53
+ expect(body).toContain(protectedText);
54
+ }
55
+ });
56
+ });
@@ -104,7 +104,7 @@ function currentResponse(toolUseId: string): ToolResultContent {
104
104
  };
105
105
  }
106
106
 
107
- /** A weak-model id that matches WEAK_MODEL_PATTERN (the gated population). */
107
+ /** A weak-model id that matches WEAK_OPEN_MODEL_PATTERN (the gated population). */
108
108
  const WEAK_MODEL = "minimax/minimax-m3";
109
109
 
110
110
  function makeCtx(
@@ -7,8 +7,8 @@
7
7
  * - `user-prompt-submit` — first-pass generation from the submitted prompt,
8
8
  * scheduled on a later macrotask so the main agent-loop LLM request is
9
9
  * issued first.
10
- * - `stop` — second-pass regeneration once the conversation reaches its third
11
- * user turn (turn count derived from the user prompts in history).
10
+ * - `stop` — fallback retry for replaceable titles and second-pass
11
+ * regeneration once the conversation reaches its third user turn.
12
12
  *
13
13
  * Both let the title service resolve the provider, persist the title, and
14
14
  * broadcast the resulting `conversation_title_updated` / `sync_changed`
@@ -31,13 +31,42 @@ const queueGenerateConversationTitleMock = mock(
31
31
  }): void => undefined,
32
32
  );
33
33
  const queueRegenerateConversationTitleMock = mock(
34
- (_params: { conversationId: string; provider?: unknown }): void => undefined,
34
+ (_params: {
35
+ conversationId: string;
36
+ provider?: unknown;
37
+ onlyIfReplaceable?: boolean;
38
+ }): void => undefined,
35
39
  );
36
40
  mock.module("../memory/conversation-title-service.js", () => ({
41
+ AUTO_TITLE_DETERMINISTIC: 2,
42
+ isReplaceableTitle: (title: string | null) =>
43
+ title == null ||
44
+ title === "" ||
45
+ title === "Generating title..." ||
46
+ title === "New Conversation" ||
47
+ title === "Untitled" ||
48
+ title === "Untitled Conversation" ||
49
+ title.startsWith("Runtime: "),
37
50
  queueGenerateConversationTitle: queueGenerateConversationTitleMock,
38
51
  queueRegenerateConversationTitle: queueRegenerateConversationTitleMock,
39
52
  }));
40
53
 
54
+ const mockGetConversation = mock(
55
+ (_conversationId: string) =>
56
+ ({
57
+ title: "Existing Title",
58
+ isAutoTitle: 1,
59
+ conversationType: "standard",
60
+ }) as {
61
+ title: string;
62
+ isAutoTitle: number;
63
+ conversationType: string;
64
+ },
65
+ );
66
+ mock.module("../memory/conversation-crud.js", () => ({
67
+ getConversation: mockGetConversation,
68
+ }));
69
+
41
70
  // The `stop` hook reads `conversations.skipAutoRetitling`; stub the loader so
42
71
  // the opt-out is controllable per test.
43
72
  let skipAutoRetitling = false;
@@ -192,6 +221,19 @@ describe("title-generate stop hook", () => {
192
221
  resetPluginRegistryForTests();
193
222
  queueRegenerateConversationTitleMock.mockReset();
194
223
  queueRegenerateConversationTitleMock.mockImplementation(() => undefined);
224
+ mockGetConversation.mockReset();
225
+ mockGetConversation.mockImplementation(
226
+ (_conversationId: string) =>
227
+ ({
228
+ title: "Existing Title",
229
+ isAutoTitle: 1,
230
+ conversationType: "standard",
231
+ }) as {
232
+ title: string;
233
+ isAutoTitle: number;
234
+ conversationType: string;
235
+ },
236
+ );
195
237
  skipAutoRetitling = false;
196
238
  });
197
239
 
@@ -210,6 +252,61 @@ describe("title-generate stop hook", () => {
210
252
  expect(call?.conversationId).toBe("conv-1");
211
253
  expect(call).not.toHaveProperty("provider");
212
254
  expect(call).not.toHaveProperty("signal");
255
+ expect(call).not.toHaveProperty("onlyIfReplaceable");
256
+ });
257
+
258
+ test("retries a replaceable fallback title after a successful turn", async () => {
259
+ mockGetConversation.mockReturnValueOnce({
260
+ title: "Untitled Conversation",
261
+ isAutoTitle: 2,
262
+ conversationType: "standard",
263
+ });
264
+ const ctx = makeStopCtx({ messages: historyWithUserTurns(1) });
265
+
266
+ await stop(ctx);
267
+ await flushMacrotasks();
268
+
269
+ expect(queueRegenerateConversationTitleMock).toHaveBeenCalledTimes(1);
270
+ expect(queueRegenerateConversationTitleMock).toHaveBeenCalledWith({
271
+ conversationId: "conv-1",
272
+ onlyIfReplaceable: true,
273
+ });
274
+ });
275
+
276
+ test("preserves the third-turn retitle when the title is still replaceable", async () => {
277
+ mockGetConversation.mockReturnValueOnce({
278
+ title: "Untitled Conversation",
279
+ isAutoTitle: 2,
280
+ conversationType: "standard",
281
+ });
282
+ const ctx = makeStopCtx({ messages: historyWithUserTurns(3) });
283
+
284
+ await stop(ctx);
285
+ await flushMacrotasks();
286
+
287
+ expect(queueRegenerateConversationTitleMock).toHaveBeenCalledTimes(1);
288
+ const call = queueRegenerateConversationTitleMock.mock.calls[0]?.[0];
289
+ expect(call?.conversationId).toBe("conv-1");
290
+ expect(call).not.toHaveProperty("onlyIfReplaceable");
291
+ });
292
+
293
+ test("fallback title retry is not blocked by the retitling opt-out", async () => {
294
+ skipAutoRetitling = true;
295
+ mockGetConversation.mockReturnValueOnce({
296
+ title: "Generating title...",
297
+ isAutoTitle: 1,
298
+ conversationType: "standard",
299
+ });
300
+ const ctx = makeStopCtx({ messages: historyWithUserTurns(1) });
301
+
302
+ await stop(ctx);
303
+ await flushMacrotasks();
304
+
305
+ expect(queueRegenerateConversationTitleMock).toHaveBeenCalledTimes(1);
306
+ expect(queueRegenerateConversationTitleMock).toHaveBeenCalledWith({
307
+ conversationId: "conv-1",
308
+ onlyIfReplaceable: true,
309
+ });
213
310
  });
214
311
 
215
312
  test("defers the regeneration so the completed turn is persisted first", async () => {
@@ -128,7 +128,6 @@ function makeSystemPrompt(size: "small" | "production" = "small"): string {
128
128
  "- `file_write` — Creating or overwriting files",
129
129
  "- `file_edit` — Modifying existing files",
130
130
  "- `file_delete` — Deleting files",
131
- "- `credential_store set` — Storing credentials",
132
131
  "",
133
132
  "### Medium-Risk Tools (require approval on first use per session)",
134
133
  "- `web_fetch` — Fetching external URLs",
@@ -349,7 +348,7 @@ function makeToolDefinitions(): Array<{
349
348
  input_schema: object;
350
349
  }> = [];
351
350
 
352
- // Core tools (11)
351
+ // Core tools (10)
353
352
  tools.push(
354
353
  {
355
354
  name: "bash",
@@ -566,33 +565,6 @@ function makeToolDefinitions(): Array<{
566
565
  required: ["query"],
567
566
  },
568
567
  },
569
- {
570
- name: "credential_store",
571
- description:
572
- "Securely store or retrieve credentials for external services. Credentials are encrypted at rest.",
573
- input_schema: {
574
- type: "object",
575
- properties: {
576
- action: {
577
- type: "string",
578
- enum: ["get", "set", "delete", "list"],
579
- },
580
- service: {
581
- type: "string",
582
- description: "The service name (e.g., 'github', 'slack')",
583
- },
584
- key: {
585
- type: "string",
586
- description: "Credential key within the service",
587
- },
588
- value: {
589
- type: "string",
590
- description: "Credential value (required for 'set')",
591
- },
592
- },
593
- required: ["action", "service"],
594
- },
595
- },
596
568
  );
597
569
 
598
570
  // Computer-use proxy tools (11)