@vellumai/assistant 0.7.0 → 0.7.1

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 (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -281,7 +281,10 @@ describe("GET /v1/conversation-starters", () => {
281
281
  category: "productivity",
282
282
  createdAt: now - 1,
283
283
  });
284
- setCheckpoint("conversation_starters:last_gen_at:default", String(now));
284
+ setCheckpoint(
285
+ "conversation_starters:last_gen_at:default",
286
+ String(now - 90_000),
287
+ );
285
288
  setCheckpoint("conversation_starters:item_count_at_last_gen:default", "1");
286
289
  insertMemoryItem();
287
290
 
@@ -313,7 +316,10 @@ describe("GET /v1/conversation-starters", () => {
313
316
  category: "communication",
314
317
  createdAt: now - 1,
315
318
  });
316
- setCheckpoint("conversation_starters:last_gen_at:default", String(now));
319
+ setCheckpoint(
320
+ "conversation_starters:last_gen_at:default",
321
+ String(now - 90_000),
322
+ );
317
323
  setCheckpoint("conversation_starters:item_count_at_last_gen:default", "1");
318
324
  insertMemoryItem();
319
325
 
@@ -331,6 +337,77 @@ describe("GET /v1/conversation-starters", () => {
331
337
  expect(countStarterJobs()).toBe(1);
332
338
  });
333
339
 
340
+ test("does not re-enqueue for invalid items when within cooldown period", async () => {
341
+ const now = Date.now();
342
+ // Generation happened 30 seconds ago (within the 60s cooldown)
343
+ const recentGenAt = now - 30_000;
344
+ insertStarter({
345
+ label: "Let me check calendar",
346
+ prompt: "Let me check what Alice has today.",
347
+ category: "productivity",
348
+ createdAt: now,
349
+ });
350
+ insertStarter({
351
+ label: "Plan my morning",
352
+ prompt: "Can you help me plan my morning?",
353
+ category: "productivity",
354
+ createdAt: now - 1,
355
+ });
356
+ setCheckpoint(
357
+ "conversation_starters:last_gen_at:default",
358
+ String(recentGenAt),
359
+ );
360
+ setCheckpoint("conversation_starters:item_count_at_last_gen:default", "1");
361
+ insertMemoryItem();
362
+
363
+ const result = (await dispatch("conversation-starters")) as {
364
+ starters: unknown[];
365
+ total: number;
366
+ status: string;
367
+ };
368
+
369
+ // The invalid "assistant-voice" starter triggers invalidItemCount > 0,
370
+ // but the cooldown prevents re-enqueueing — status should be "ready".
371
+ expect(result.status).toBe("ready");
372
+ expect(result.total).toBe(1);
373
+ expect(countStarterJobs()).toBe(0);
374
+ });
375
+
376
+ test("re-enqueues for invalid items after cooldown expires", async () => {
377
+ const now = Date.now();
378
+ // Generation happened 90 seconds ago (past the 60s cooldown)
379
+ const oldGenAt = now - 90_000;
380
+ insertStarter({
381
+ label: "Let me check calendar",
382
+ prompt: "Let me check what Alice has today.",
383
+ category: "productivity",
384
+ createdAt: now,
385
+ });
386
+ insertStarter({
387
+ label: "Plan my morning",
388
+ prompt: "Can you help me plan my morning?",
389
+ category: "productivity",
390
+ createdAt: now - 1,
391
+ });
392
+ setCheckpoint(
393
+ "conversation_starters:last_gen_at:default",
394
+ String(oldGenAt),
395
+ );
396
+ setCheckpoint("conversation_starters:item_count_at_last_gen:default", "1");
397
+ insertMemoryItem();
398
+
399
+ const result = (await dispatch("conversation-starters")) as {
400
+ starters: unknown[];
401
+ total: number;
402
+ status: string;
403
+ };
404
+
405
+ // Past the cooldown — should re-enqueue and return refreshing.
406
+ expect(result.status).toBe("refreshing");
407
+ expect(result.total).toBe(1);
408
+ expect(countStarterJobs()).toBe(1);
409
+ });
410
+
334
411
  test("returns empty status when no memory items exist", async () => {
335
412
  const result = (await dispatch("conversation-starters")) as {
336
413
  starters: unknown[];
@@ -17,7 +17,14 @@
17
17
  * and dispatches them in ChatActionHandler → ChatViewModel+SurfaceHandling.
18
18
  */
19
19
 
20
- import { describe, expect, test } from "bun:test";
20
+ import { describe, expect, mock, test } from "bun:test";
21
+
22
+ import type { ServerMessage } from "../daemon/message-protocol.js";
23
+
24
+ let broadcastImpl: (msg: ServerMessage) => void = () => {};
25
+ mock.module("../runtime/assistant-event-hub.js", () => ({
26
+ broadcastMessage: (msg: ServerMessage) => broadcastImpl(msg),
27
+ }));
21
28
 
22
29
  import {
23
30
  buildCompletionSummary,
@@ -25,7 +32,6 @@ import {
25
32
  showStandaloneSurface,
26
33
  type SurfaceConversationContext,
27
34
  } from "../daemon/conversation-surfaces.js";
28
- import type { ServerMessage } from "../daemon/message-protocol.js";
29
35
 
30
36
  // ── Helpers ──────────────────────────────────────────────────────────
31
37
 
@@ -40,6 +46,7 @@ function createMockContext(
40
46
  enqueuedMessages: Array<{ content: string; requestId: string }>;
41
47
  } {
42
48
  const sentMessages: ServerMessage[] = [];
49
+ broadcastImpl = (msg: ServerMessage) => sentMessages.push(msg);
43
50
  const enqueuedMessages: Array<{ content: string; requestId: string }> = [];
44
51
 
45
52
  return {
@@ -54,7 +61,6 @@ function createMockContext(
54
61
  : undefined,
55
62
  traceEmitter: { emit: () => {} },
56
63
  sendToClient: (msg: ServerMessage) => sentMessages.push(msg),
57
- broadcastToAllClients: (msg: ServerMessage) => sentMessages.push(msg),
58
64
  pendingSurfaceActions: new Map(),
59
65
  lastSurfaceAction: new Map(),
60
66
  surfaceState: new Map(),
@@ -67,8 +73,9 @@ function createMockContext(
67
73
  hasNoClient: overrides?.hasNoClient ?? false,
68
74
  isProcessing: () => false,
69
75
  enqueueMessage: (content, _attachments, _onEvent, requestId) => {
70
- enqueuedMessages.push({ content, requestId });
71
- return { queued: false, requestId };
76
+ const resolvedId = requestId ?? "mock-request-id";
77
+ enqueuedMessages.push({ content, requestId: resolvedId });
78
+ return { queued: false, requestId: resolvedId };
72
79
  },
73
80
  getQueueDepth: () => 0,
74
81
  processMessage: async () => "msg-id",
@@ -1,4 +1,12 @@
1
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
1
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ import type { ServerMessage } from "../daemon/message-protocol.js";
4
+ import type { InteractiveUiResult } from "../runtime/interactive-ui.js";
5
+
6
+ let broadcastImpl: (msg: ServerMessage) => void = () => {};
7
+ mock.module("../runtime/assistant-event-hub.js", () => ({
8
+ broadcastMessage: (msg: ServerMessage) => broadcastImpl(msg),
9
+ }));
2
10
 
3
11
  import {
4
12
  canShowInteractiveUi,
@@ -7,8 +15,6 @@ import {
7
15
  showStandaloneSurface,
8
16
  type SurfaceConversationContext,
9
17
  } from "../daemon/conversation-surfaces.js";
10
- import type { ServerMessage } from "../daemon/message-protocol.js";
11
- import type { InteractiveUiResult } from "../runtime/interactive-ui.js";
12
18
 
13
19
  // ── Helpers ──────────────────────────────────────────────────────────
14
20
 
@@ -28,6 +34,7 @@ function createMockContext(
28
34
  enqueuedMessages: Array<{ content: string; requestId: string }>;
29
35
  } {
30
36
  const sentMessages: ServerMessage[] = [];
37
+ broadcastImpl = (msg: ServerMessage) => sentMessages.push(msg);
31
38
  const enqueuedMessages: Array<{ content: string; requestId: string }> = [];
32
39
 
33
40
  return {
@@ -44,7 +51,6 @@ function createMockContext(
44
51
  emit: () => {},
45
52
  },
46
53
  sendToClient: (msg: ServerMessage) => sentMessages.push(msg),
47
- broadcastToAllClients: (msg: ServerMessage) => sentMessages.push(msg),
48
54
  pendingSurfaceActions: new Map(),
49
55
  lastSurfaceAction: new Map(),
50
56
  surfaceState: new Map(),
@@ -58,8 +64,9 @@ function createMockContext(
58
64
  hasNoClient: overrides?.hasNoClient ?? false,
59
65
  isProcessing: () => false,
60
66
  enqueueMessage: (content, _attachments, _onEvent, requestId) => {
61
- enqueuedMessages.push({ content, requestId });
62
- return { queued: false, requestId };
67
+ const resolvedId = requestId ?? "mock-request-id";
68
+ enqueuedMessages.push({ content, requestId: resolvedId });
69
+ return { queued: false, requestId: resolvedId };
63
70
  },
64
71
  getQueueDepth: () => 0,
65
72
  processMessage: async () => "msg-id",
@@ -291,9 +298,8 @@ describe("showStandaloneSurface", () => {
291
298
 
292
299
  test("timeout still resolves when emit throws", async () => {
293
300
  const ctx = createMockContext();
294
- // Override broadcastToAllClients to throw on ui_surface_complete
295
301
  let showEmitted = false;
296
- ctx.broadcastToAllClients = (msg: ServerMessage) => {
302
+ broadcastImpl = (msg: ServerMessage) => {
297
303
  const type = (msg as unknown as Record<string, unknown>).type;
298
304
  if (type === "ui_surface_show") {
299
305
  showEmitted = true;
@@ -518,14 +524,13 @@ describe("standalone surface cleanup on conversation dispose", () => {
518
524
 
519
525
  // Simulate conversation dispose — cancel all pending with dismiss
520
526
  // notifications, matching the Conversation.dispose() implementation.
521
- const emit = ctx.broadcastToAllClients ?? ctx.sendToClient.bind(ctx);
522
527
  for (const [surfaceId, entry] of ctx.pendingStandaloneSurfaces!) {
523
528
  clearTimeout(entry.timer);
524
- emit({
529
+ broadcastImpl({
525
530
  type: "ui_surface_dismiss",
526
531
  conversationId: ctx.conversationId,
527
532
  surfaceId,
528
- });
533
+ } as ServerMessage);
529
534
  entry.resolve({ status: "cancelled", surfaceId });
530
535
  }
531
536
  ctx.pendingStandaloneSurfaces!.clear();
@@ -568,14 +573,13 @@ describe("standalone surface cleanup on conversation dispose", () => {
568
573
  ctx.sentMessages.length = 0;
569
574
 
570
575
  // Simulate the dispose path (matching Conversation.dispose())
571
- const emit = ctx.broadcastToAllClients ?? ctx.sendToClient.bind(ctx);
572
576
  for (const [surfaceId, entry] of ctx.pendingStandaloneSurfaces!) {
573
577
  clearTimeout(entry.timer);
574
- emit({
578
+ broadcastImpl({
575
579
  type: "ui_surface_dismiss",
576
580
  conversationId: ctx.conversationId,
577
581
  surfaceId,
578
- });
582
+ } as ServerMessage);
579
583
  entry.resolve({ status: "cancelled", surfaceId });
580
584
  }
581
585
  ctx.pendingStandaloneSurfaces!.clear();
@@ -46,8 +46,9 @@ function makeContext(opts?: {
46
46
  currentTurnSurfaces: [],
47
47
  isProcessing: () => false,
48
48
  enqueueMessage: (content, _attachments, _onEvent, requestId) => {
49
- enqueueCalls.push({ content, requestId });
50
- return { queued: false, requestId };
49
+ const resolvedId = requestId ?? "mock-request-id";
50
+ enqueueCalls.push({ content, requestId: resolvedId });
51
+ return { queued: false, requestId: resolvedId };
51
52
  },
52
53
  getQueueDepth: () => 0,
53
54
  processMessage: async (content, _attachments, _onEvent, requestId) => {
@@ -25,6 +25,11 @@ import type { ToolExecutionResult } from "../tools/types.js";
25
25
 
26
26
  const refreshSpy = mock(() => {});
27
27
  const updatePublishedSpy = mock(() => Promise.resolve());
28
+ const broadcastSpy = mock(() => {});
29
+
30
+ mock.module("../runtime/assistant-event-hub.js", () => ({
31
+ broadcastMessage: broadcastSpy,
32
+ }));
28
33
 
29
34
  // Mock session-surfaces so refreshSurfacesForApp is captured
30
35
  mock.module("../daemon/conversation-surfaces.js", () => ({
@@ -120,6 +125,7 @@ const noopLifecycleHandler = mock(() => {});
120
125
  describe("session-tool-setup app refresh side effects", () => {
121
126
  beforeEach(() => {
122
127
  refreshSpy.mockClear();
128
+ broadcastSpy.mockClear();
123
129
  updatePublishedSpy.mockClear();
124
130
  });
125
131
 
@@ -132,7 +138,6 @@ describe("session-tool-setup app refresh side effects", () => {
132
138
  content: '{"id":"app-1"}',
133
139
  isError: false,
134
140
  });
135
- const broadcastSpy = mock(() => {});
136
141
 
137
142
  const toolFn = createToolExecutor(
138
143
  executor as unknown as ToolExecutor,
@@ -140,7 +145,6 @@ describe("session-tool-setup app refresh side effects", () => {
140
145
  noopSecretPrompter,
141
146
  ctx,
142
147
  noopLifecycleHandler,
143
- broadcastSpy,
144
148
  );
145
149
 
146
150
  await toolFn("app_refresh", { app_id: "app-1" });
@@ -153,7 +157,6 @@ describe("session-tool-setup app refresh side effects", () => {
153
157
  test("broadcasts app_files_changed with correct appId", async () => {
154
158
  const ctx = makeCtx();
155
159
  const executor = makeFakeExecutor({ content: "{}", isError: false });
156
- const broadcastSpy = mock(() => {});
157
160
 
158
161
  const toolFn = createToolExecutor(
159
162
  executor as unknown as ToolExecutor,
@@ -161,7 +164,6 @@ describe("session-tool-setup app refresh side effects", () => {
161
164
  noopSecretPrompter,
162
165
  ctx,
163
166
  noopLifecycleHandler,
164
- broadcastSpy,
165
167
  );
166
168
 
167
169
  await toolFn("app_refresh", { app_id: "app-42" });
@@ -183,7 +185,6 @@ describe("session-tool-setup app refresh side effects", () => {
183
185
  noopSecretPrompter,
184
186
  ctx,
185
187
  noopLifecycleHandler,
186
- mock(() => {}),
187
188
  );
188
189
 
189
190
  await toolFn("app_refresh", { app_id: "app-publish" });
@@ -202,7 +203,6 @@ describe("session-tool-setup app refresh side effects", () => {
202
203
  content: "Error: not found",
203
204
  isError: true,
204
205
  });
205
- const broadcastSpy = mock(() => {});
206
206
 
207
207
  const toolFn = createToolExecutor(
208
208
  executor as unknown as ToolExecutor,
@@ -210,7 +210,6 @@ describe("session-tool-setup app refresh side effects", () => {
210
210
  noopSecretPrompter,
211
211
  ctx,
212
212
  noopLifecycleHandler,
213
- broadcastSpy,
214
213
  );
215
214
 
216
215
  await toolFn("app_refresh", { app_id: "app-err" });
@@ -223,7 +222,6 @@ describe("session-tool-setup app refresh side effects", () => {
223
222
  test("skips side effects when app_id is missing", async () => {
224
223
  const ctx = makeCtx();
225
224
  const executor = makeFakeExecutor({ content: "{}", isError: false });
226
- const broadcastSpy = mock(() => {});
227
225
 
228
226
  const toolFn = createToolExecutor(
229
227
  executor as unknown as ToolExecutor,
@@ -231,7 +229,6 @@ describe("session-tool-setup app refresh side effects", () => {
231
229
  noopSecretPrompter,
232
230
  ctx,
233
231
  noopLifecycleHandler,
234
- broadcastSpy,
235
232
  );
236
233
 
237
234
  await toolFn("app_refresh", {});
@@ -250,7 +247,6 @@ describe("session-tool-setup app refresh side effects", () => {
250
247
  content: JSON.stringify({ id: "new-app-1", name: "My App" }),
251
248
  isError: false,
252
249
  });
253
- const broadcastSpy = mock(() => {});
254
250
 
255
251
  const toolFn = createToolExecutor(
256
252
  executor as unknown as ToolExecutor,
@@ -258,7 +254,6 @@ describe("session-tool-setup app refresh side effects", () => {
258
254
  noopSecretPrompter,
259
255
  ctx,
260
256
  noopLifecycleHandler,
261
- broadcastSpy,
262
257
  );
263
258
 
264
259
  await toolFn("app_create", { name: "My App", html: "<h1>hi</h1>" });
@@ -273,7 +268,6 @@ describe("session-tool-setup app refresh side effects", () => {
273
268
  test("skips side effects when app_create result is an error", async () => {
274
269
  const ctx = makeCtx();
275
270
  const executor = makeFakeExecutor({ content: "Error", isError: true });
276
- const broadcastSpy = mock(() => {});
277
271
 
278
272
  const toolFn = createToolExecutor(
279
273
  executor as unknown as ToolExecutor,
@@ -281,7 +275,6 @@ describe("session-tool-setup app refresh side effects", () => {
281
275
  noopSecretPrompter,
282
276
  ctx,
283
277
  noopLifecycleHandler,
284
- broadcastSpy,
285
278
  );
286
279
 
287
280
  await toolFn("app_create", { name: "Bad", html: "" });
@@ -305,7 +298,6 @@ describe("session-tool-setup app refresh side effects", () => {
305
298
  }),
306
299
  isError: false,
307
300
  });
308
- const broadcastSpy = mock(() => {});
309
301
 
310
302
  const toolFn = createToolExecutor(
311
303
  executor as unknown as ToolExecutor,
@@ -313,7 +305,6 @@ describe("session-tool-setup app refresh side effects", () => {
313
305
  noopSecretPrompter,
314
306
  ctx,
315
307
  noopLifecycleHandler,
316
- broadcastSpy,
317
308
  );
318
309
 
319
310
  await toolFn("app_create", { name: "Busted", html: "" });
@@ -334,7 +325,6 @@ describe("session-tool-setup app refresh side effects", () => {
334
325
  test("broadcasts app_files_changed after app_delete", async () => {
335
326
  const ctx = makeCtx();
336
327
  const executor = makeFakeExecutor({ content: "{}", isError: false });
337
- const broadcastSpy = mock(() => {});
338
328
 
339
329
  const toolFn = createToolExecutor(
340
330
  executor as unknown as ToolExecutor,
@@ -342,7 +332,6 @@ describe("session-tool-setup app refresh side effects", () => {
342
332
  noopSecretPrompter,
343
333
  ctx,
344
334
  noopLifecycleHandler,
345
- broadcastSpy,
346
335
  );
347
336
 
348
337
  await toolFn("app_delete", { app_id: "del-app-1" });
@@ -357,7 +346,6 @@ describe("session-tool-setup app refresh side effects", () => {
357
346
  test("skips side effects when app_delete result is an error", async () => {
358
347
  const ctx = makeCtx();
359
348
  const executor = makeFakeExecutor({ content: "Error", isError: true });
360
- const broadcastSpy = mock(() => {});
361
349
 
362
350
  const toolFn = createToolExecutor(
363
351
  executor as unknown as ToolExecutor,
@@ -365,7 +353,6 @@ describe("session-tool-setup app refresh side effects", () => {
365
353
  noopSecretPrompter,
366
354
  ctx,
367
355
  noopLifecycleHandler,
368
- broadcastSpy,
369
356
  );
370
357
 
371
358
  await toolFn("app_delete", { app_id: "del-err" });
@@ -384,7 +371,6 @@ describe("session-tool-setup app refresh side effects", () => {
384
371
  // hooks as core tools.
385
372
  const ctx = makeCtx();
386
373
  const executor = makeFakeExecutor({ content: "{}", isError: false });
387
- const broadcastSpy = mock(() => {});
388
374
 
389
375
  const toolFn = createToolExecutor(
390
376
  executor as unknown as ToolExecutor,
@@ -392,12 +378,12 @@ describe("session-tool-setup app refresh side effects", () => {
392
378
  noopSecretPrompter,
393
379
  ctx,
394
380
  noopLifecycleHandler,
395
- broadcastSpy,
396
381
  );
397
382
 
398
383
  // Simulate calling app_refresh by name (as the agent loop does)
399
384
  for (const toolName of ["app_refresh"]) {
400
385
  refreshSpy.mockClear();
386
+ broadcastSpy.mockClear();
401
387
  broadcastSpy.mockClear();
402
388
  updatePublishedSpy.mockClear();
403
389
 
@@ -418,7 +404,6 @@ describe("session-tool-setup app refresh side effects", () => {
418
404
  test("other tool names do not trigger app refresh side effects", async () => {
419
405
  const ctx = makeCtx();
420
406
  const executor = makeFakeExecutor({ content: "{}", isError: false });
421
- const broadcastSpy = mock(() => {});
422
407
 
423
408
  const toolFn = createToolExecutor(
424
409
  executor as unknown as ToolExecutor,
@@ -426,7 +411,6 @@ describe("session-tool-setup app refresh side effects", () => {
426
411
  noopSecretPrompter,
427
412
  ctx,
428
413
  noopLifecycleHandler,
429
- broadcastSpy,
430
414
  );
431
415
 
432
416
  for (const toolName of [
@@ -439,6 +423,7 @@ describe("session-tool-setup app refresh side effects", () => {
439
423
  "app_file_write",
440
424
  ]) {
441
425
  refreshSpy.mockClear();
426
+ broadcastSpy.mockClear();
442
427
  broadcastSpy.mockClear();
443
428
  updatePublishedSpy.mockClear();
444
429
 
@@ -451,28 +436,5 @@ describe("session-tool-setup app refresh side effects", () => {
451
436
  });
452
437
  });
453
438
 
454
- // ── broadcastToAllClients optional ──────────────────────────────────
455
-
456
- describe("broadcastToAllClients is optional", () => {
457
- test("side effects work without broadcastToAllClients callback", async () => {
458
- const ctx = makeCtx();
459
- const executor = makeFakeExecutor({ content: "{}", isError: false });
460
-
461
- // No broadcast callback provided
462
- const toolFn = createToolExecutor(
463
- executor as unknown as ToolExecutor,
464
- noopPrompter,
465
- noopSecretPrompter,
466
- ctx,
467
- noopLifecycleHandler,
468
- );
469
-
470
- // Should not throw even though broadcastToAllClients is undefined
471
- const result = await toolFn("app_refresh", { app_id: "app-no-bc" });
472
439
 
473
- expect(result.isError).toBe(false);
474
- expect(refreshSpy).toHaveBeenCalledTimes(1);
475
- expect(updatePublishedSpy).toHaveBeenCalledTimes(1);
476
- });
477
- });
478
440
  });