@vellumai/assistant 0.4.56 → 0.5.0

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 (457) hide show
  1. package/ARCHITECTURE.md +10 -10
  2. package/Dockerfile +3 -0
  3. package/README.md +11 -11
  4. package/docs/architecture/integrations.md +2 -2
  5. package/docs/architecture/memory.md +3 -4
  6. package/docs/credential-execution-service.md +13 -20
  7. package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
  8. package/package.json +1 -1
  9. package/src/__tests__/actor-token-service.test.ts +7 -7
  10. package/src/__tests__/anthropic-provider.test.ts +172 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
  12. package/src/__tests__/approval-cascade.test.ts +2 -2
  13. package/src/__tests__/approval-routes-http.test.ts +3 -4
  14. package/src/__tests__/asset-materialize-tool.test.ts +5 -5
  15. package/src/__tests__/asset-search-tool.test.ts +1 -1
  16. package/src/__tests__/assistant-attachments.test.ts +5 -5
  17. package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
  19. package/src/__tests__/attachments-store.test.ts +2 -2
  20. package/src/__tests__/avatar-e2e.test.ts +5 -3
  21. package/src/__tests__/browser-skill-endstate.test.ts +0 -1
  22. package/src/__tests__/call-routes-http.test.ts +2 -2
  23. package/src/__tests__/callback-handoff-copy.test.ts +1 -1
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
  25. package/src/__tests__/channel-readiness-routes.test.ts +0 -1
  26. package/src/__tests__/channel-readiness-service.test.ts +0 -1
  27. package/src/__tests__/checker.test.ts +31 -32
  28. package/src/__tests__/chrome-cdp.test.ts +47 -18
  29. package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
  30. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  31. package/src/__tests__/config-schema.test.ts +9 -18
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
  34. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
  35. package/src/__tests__/conversation-agent-loop.test.ts +11 -4
  36. package/src/__tests__/conversation-attachments.test.ts +1 -1
  37. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
  38. package/src/__tests__/conversation-error.test.ts +33 -0
  39. package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
  40. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  41. package/src/__tests__/conversation-pairing.test.ts +1 -1
  42. package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
  43. package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
  44. package/src/__tests__/conversation-queue.test.ts +23 -14
  45. package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +204 -185
  47. package/src/__tests__/conversation-seed-composer.test.ts +1 -1
  48. package/src/__tests__/conversation-slash-queue.test.ts +4 -4
  49. package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
  50. package/src/__tests__/conversation-starter-routes.test.ts +291 -0
  51. package/src/__tests__/conversation-wipe.test.ts +438 -0
  52. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
  53. package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
  54. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
  55. package/src/__tests__/credential-security-e2e.test.ts +20 -0
  56. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  57. package/src/__tests__/credential-vault-unit.test.ts +227 -0
  58. package/src/__tests__/credentials-cli.test.ts +3 -0
  59. package/src/__tests__/date-context.test.ts +59 -377
  60. package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
  61. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
  62. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
  63. package/src/__tests__/encrypted-store.test.ts +249 -15
  64. package/src/__tests__/ephemeral-permissions.test.ts +4 -5
  65. package/src/__tests__/event-bus.test.ts +3 -3
  66. package/src/__tests__/file-read-tool.test.ts +40 -0
  67. package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
  68. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  69. package/src/__tests__/gemini-image-service.test.ts +4 -4
  70. package/src/__tests__/gemini-provider.test.ts +6 -9
  71. package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
  72. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  73. package/src/__tests__/host-file-read-tool.test.ts +87 -0
  74. package/src/__tests__/host-shell-tool.test.ts +6 -6
  75. package/src/__tests__/http-user-message-parity.test.ts +2 -2
  76. package/src/__tests__/identity-intro-cache.test.ts +209 -0
  77. package/src/__tests__/intent-routing.test.ts +51 -99
  78. package/src/__tests__/invite-routes-http.test.ts +5 -0
  79. package/src/__tests__/list-messages-attachments.test.ts +1 -1
  80. package/src/__tests__/managed-proxy-context.test.ts +2 -5
  81. package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
  82. package/src/__tests__/media-generate-image.test.ts +32 -15
  83. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
  84. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
  85. package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
  86. package/src/__tests__/memory-recall-quality.test.ts +4 -3
  87. package/src/__tests__/memory-regressions.test.ts +86 -90
  88. package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
  89. package/src/__tests__/migration-export-http.test.ts +26 -27
  90. package/src/__tests__/migration-import-commit-http.test.ts +165 -37
  91. package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
  92. package/src/__tests__/migration-validate-http.test.ts +16 -16
  93. package/src/__tests__/model-intents.test.ts +2 -2
  94. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
  95. package/src/__tests__/non-member-access-request.test.ts +3 -3
  96. package/src/__tests__/notification-broadcaster.test.ts +1 -1
  97. package/src/__tests__/notification-decision-fallback.test.ts +2 -2
  98. package/src/__tests__/notification-decision-identity.test.ts +8 -9
  99. package/src/__tests__/notification-decision-strategy.test.ts +1 -1
  100. package/src/__tests__/notification-deep-link.test.ts +1 -1
  101. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  102. package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
  103. package/src/__tests__/oauth-store.test.ts +1 -3
  104. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
  105. package/src/__tests__/onboarding-template-contract.test.ts +23 -59
  106. package/src/__tests__/provider-error-scenarios.test.ts +154 -0
  107. package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
  108. package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
  109. package/src/__tests__/provider-registry-ollama.test.ts +5 -2
  110. package/src/__tests__/qdrant-manager.test.ts +7 -7
  111. package/src/__tests__/ratelimit.test.ts +0 -74
  112. package/src/__tests__/recording-handler.test.ts +0 -1
  113. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  114. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  115. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  116. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  117. package/src/__tests__/scheduler-recurrence.test.ts +46 -2
  118. package/src/__tests__/schema-transforms.test.ts +114 -54
  119. package/src/__tests__/secret-onetime-send.test.ts +20 -0
  120. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
  121. package/src/__tests__/secret-scanner-executor.test.ts +1 -2
  122. package/src/__tests__/send-endpoint-busy.test.ts +63 -4
  123. package/src/__tests__/send-notification-tool.test.ts +2 -2
  124. package/src/__tests__/shell-credential-ref.test.ts +0 -1
  125. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
  126. package/src/__tests__/skill-memory.test.ts +549 -0
  127. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
  128. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
  129. package/src/__tests__/slack-channel-config.test.ts +109 -94
  130. package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
  131. package/src/__tests__/swarm-recursion.test.ts +2 -2
  132. package/src/__tests__/swarm-tool.test.ts +2 -2
  133. package/src/__tests__/system-prompt.test.ts +19 -66
  134. package/src/__tests__/telegram-config.test.ts +121 -0
  135. package/src/__tests__/terminal-tools.test.ts +1 -1
  136. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  138. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
  139. package/src/__tests__/tool-executor.test.ts +1 -1
  140. package/src/__tests__/trace-emitter.test.ts +8 -1
  141. package/src/__tests__/trust-store.test.ts +7 -8
  142. package/src/__tests__/twilio-routes.test.ts +1 -18
  143. package/src/__tests__/user-reference.test.ts +82 -2
  144. package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
  145. package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
  146. package/src/approvals/guardian-request-resolvers.ts +3 -3
  147. package/src/avatar/ascii-renderer.ts +2 -2
  148. package/src/avatar/png-renderer.ts +2 -2
  149. package/src/avatar/resvg-lazy.ts +21 -0
  150. package/src/calls/guardian-dispatch.ts +1 -1
  151. package/src/calls/relay-access-wait.ts +2 -2
  152. package/src/calls/twilio-rest.ts +0 -248
  153. package/src/cli/AGENTS.md +5 -8
  154. package/src/cli/__tests__/notifications.test.ts +5 -5
  155. package/src/cli/commands/avatar.ts +64 -2
  156. package/src/cli/commands/conversations.ts +131 -1
  157. package/src/cli/commands/credentials.ts +2 -0
  158. package/src/cli/commands/notifications.ts +3 -3
  159. package/src/cli.ts +10 -0
  160. package/src/config/bundled-skills/acp/SKILL.md +5 -5
  161. package/src/config/bundled-skills/acp/TOOLS.json +6 -6
  162. package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
  163. package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
  164. package/src/config/bundled-skills/browser/SKILL.md +15 -15
  165. package/src/config/bundled-skills/browser/TOOLS.json +14 -14
  166. package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
  167. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
  168. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  169. package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
  170. package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
  171. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
  172. package/src/config/bundled-skills/contacts/SKILL.md +3 -3
  173. package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
  174. package/src/config/bundled-skills/document/SKILL.md +4 -4
  175. package/src/config/bundled-skills/document/TOOLS.json +2 -2
  176. package/src/config/bundled-skills/followups/TOOLS.json +3 -3
  177. package/src/config/bundled-skills/gmail/SKILL.md +32 -32
  178. package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
  179. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
  180. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
  181. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
  182. package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
  183. package/src/config/bundled-skills/google-calendar/types.ts +1 -1
  184. package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
  185. package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
  186. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
  187. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
  188. package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
  189. package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
  190. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
  191. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
  192. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
  193. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
  194. package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
  195. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
  196. package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
  197. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  198. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
  199. package/src/config/bundled-skills/messaging/SKILL.md +29 -25
  200. package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
  201. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  202. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  203. package/src/config/bundled-skills/notifications/SKILL.md +3 -3
  204. package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
  205. package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
  206. package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
  207. package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
  208. package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
  209. package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
  210. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
  211. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
  212. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
  213. package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
  214. package/src/config/bundled-skills/schedule/SKILL.md +26 -26
  215. package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
  216. package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
  217. package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
  218. package/src/config/bundled-skills/sequences/SKILL.md +2 -2
  219. package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
  220. package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
  221. package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
  222. package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
  223. package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
  224. package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
  225. package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
  226. package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
  227. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  228. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
  229. package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
  230. package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
  231. package/src/config/bundled-skills/slack/SKILL.md +2 -2
  232. package/src/config/bundled-skills/slack/TOOLS.json +8 -8
  233. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
  234. package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
  235. package/src/config/bundled-skills/tasks/SKILL.md +1 -1
  236. package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
  237. package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
  238. package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
  240. package/src/config/bundled-skills/watcher/SKILL.md +4 -4
  241. package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
  242. package/src/config/feature-flag-registry.json +33 -17
  243. package/src/config/schemas/sandbox.ts +1 -1
  244. package/src/config/schemas/services.ts +13 -3
  245. package/src/config/schemas/timeouts.ts +0 -10
  246. package/src/contacts/contact-store.ts +63 -0
  247. package/src/contacts/contacts-write.ts +1 -1
  248. package/src/daemon/assistant-attachments.ts +2 -2
  249. package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
  250. package/src/daemon/conversation-agent-loop.ts +7 -30
  251. package/src/daemon/conversation-error.ts +24 -0
  252. package/src/daemon/conversation-memory.ts +8 -7
  253. package/src/daemon/conversation-runtime-assembly.ts +141 -275
  254. package/src/daemon/conversation-slash.ts +7 -26
  255. package/src/daemon/conversation-surfaces.ts +14 -0
  256. package/src/daemon/conversation-tool-setup.ts +9 -8
  257. package/src/daemon/conversation.ts +2 -0
  258. package/src/daemon/daemon-control.ts +1 -1
  259. package/src/daemon/date-context.ts +10 -83
  260. package/src/daemon/handlers/config-channels.ts +12 -2
  261. package/src/daemon/handlers/config-slack-channel.ts +7 -1
  262. package/src/daemon/handlers/config-telegram.ts +6 -1
  263. package/src/daemon/handlers/conversations.ts +2 -2
  264. package/src/daemon/handlers/skills.ts +4 -0
  265. package/src/daemon/lifecycle.ts +28 -4
  266. package/src/daemon/providers-setup.ts +1 -1
  267. package/src/daemon/server.ts +1 -5
  268. package/src/daemon/shutdown-handlers.ts +9 -3
  269. package/src/daemon/tool-side-effects.ts +40 -0
  270. package/src/daemon/trace-emitter.ts +26 -2
  271. package/src/events/domain-events.ts +1 -1
  272. package/src/events/tool-permission-telemetry-listener.ts +46 -0
  273. package/src/inbound/platform-callback-registration.ts +0 -18
  274. package/src/media/app-icon-generator.ts +15 -8
  275. package/src/media/avatar-router.ts +15 -8
  276. package/src/media/gemini-image-service.ts +125 -21
  277. package/src/memory/attachments-store.ts +3 -3
  278. package/src/memory/channel-verification-sessions.ts +6 -6
  279. package/src/memory/conversation-crud.ts +196 -1
  280. package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
  281. package/src/memory/conversation-title-service.ts +2 -3
  282. package/src/memory/db-init.ts +25 -1
  283. package/src/memory/invite-store.ts +4 -4
  284. package/src/memory/items-extractor.ts +4 -4
  285. package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
  286. package/src/memory/jobs-store.ts +3 -2
  287. package/src/memory/jobs-worker.ts +7 -5
  288. package/src/memory/lifecycle-events-store.ts +63 -0
  289. package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
  290. package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
  291. package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
  292. package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
  293. package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
  294. package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
  295. package/src/memory/migrations/index.ts +6 -0
  296. package/src/memory/migrations/registry.ts +13 -0
  297. package/src/memory/retriever.test.ts +223 -96
  298. package/src/memory/retriever.ts +115 -138
  299. package/src/memory/schema/calls.ts +1 -1
  300. package/src/memory/schema/contacts.ts +1 -1
  301. package/src/memory/schema/infrastructure.ts +29 -0
  302. package/src/memory/schema/memory-core.ts +7 -17
  303. package/src/memory/schema/notifications.ts +1 -1
  304. package/src/memory/search/formatting.ts +23 -6
  305. package/src/memory/search/lexical.ts +2 -0
  306. package/src/memory/search/semantic.ts +2 -0
  307. package/src/memory/search/staleness.ts +5 -1
  308. package/src/memory/search/types.ts +4 -0
  309. package/src/memory/task-memory-cleanup.ts +96 -6
  310. package/src/memory/trace-event-store.ts +148 -0
  311. package/src/notifications/README.md +1 -1
  312. package/src/notifications/decision-engine.ts +45 -4
  313. package/src/notifications/emit-signal.ts +5 -4
  314. package/src/notifications/events-store.ts +4 -4
  315. package/src/notifications/signal.ts +1 -1
  316. package/src/oauth/manual-token-connection.ts +49 -25
  317. package/src/permissions/checker.ts +6 -5
  318. package/src/permissions/defaults.ts +4 -4
  319. package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
  320. package/src/prompts/cache-boundary.ts +8 -0
  321. package/src/prompts/system-prompt.ts +105 -634
  322. package/src/prompts/templates/BOOTSTRAP.md +172 -33
  323. package/src/prompts/templates/IDENTITY.md +8 -24
  324. package/src/prompts/templates/SOUL.md +20 -41
  325. package/src/prompts/templates/USER.md +3 -19
  326. package/src/prompts/user-reference.ts +14 -16
  327. package/src/providers/anthropic/client.ts +51 -19
  328. package/src/providers/gemini/client.ts +6 -9
  329. package/src/providers/managed-proxy/constants.ts +1 -7
  330. package/src/providers/managed-proxy/context.ts +0 -1
  331. package/src/providers/model-intents.ts +5 -5
  332. package/src/providers/openai/client.ts +10 -1
  333. package/src/providers/openrouter/client.ts +1 -0
  334. package/src/providers/ratelimit.ts +0 -35
  335. package/src/providers/registry.ts +3 -5
  336. package/src/providers/retry.ts +18 -1
  337. package/src/runtime/access-request-helper.ts +16 -2
  338. package/src/runtime/auth/route-policy.ts +7 -0
  339. package/src/runtime/channel-verification-service.ts +1 -1
  340. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  341. package/src/runtime/guardian-vellum-migration.ts +61 -1
  342. package/src/runtime/http-server.ts +8 -4
  343. package/src/runtime/migrations/vbundle-builder.ts +212 -32
  344. package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
  345. package/src/runtime/migrations/vbundle-importer.ts +66 -1
  346. package/src/runtime/migrations/vbundle-validator.ts +17 -3
  347. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
  348. package/src/runtime/routes/attachment-routes.ts +2 -2
  349. package/src/runtime/routes/btw-routes.ts +93 -0
  350. package/src/runtime/routes/channel-verification-routes.ts +19 -2
  351. package/src/runtime/routes/conversation-management-routes.ts +55 -1
  352. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  353. package/src/runtime/routes/conversation-routes.ts +49 -5
  354. package/src/runtime/routes/conversation-starter-routes.ts +207 -0
  355. package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
  356. package/src/runtime/routes/identity-intro-cache.ts +105 -0
  357. package/src/runtime/routes/identity-routes.ts +51 -0
  358. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
  359. package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
  360. package/src/runtime/routes/migration-routes.ts +25 -13
  361. package/src/runtime/routes/secret-routes.ts +18 -0
  362. package/src/runtime/routes/settings-routes.ts +9 -9
  363. package/src/runtime/routes/telemetry-routes.ts +53 -0
  364. package/src/runtime/routes/trace-event-routes.ts +62 -0
  365. package/src/runtime/tool-grant-request-helper.ts +1 -1
  366. package/src/runtime/verification-outbound-actions.ts +47 -31
  367. package/src/security/encrypted-store.ts +262 -78
  368. package/src/skills/catalog-install.ts +10 -0
  369. package/src/skills/managed-store.ts +2 -0
  370. package/src/skills/skill-memory.ts +222 -0
  371. package/src/subagent/manager.ts +1 -4
  372. package/src/telemetry/types.ts +10 -1
  373. package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
  374. package/src/telemetry/usage-telemetry-reporter.ts +53 -4
  375. package/src/tools/AGENTS.md +11 -11
  376. package/src/tools/acp/spawn.ts +1 -1
  377. package/src/tools/apps/executors.ts +8 -8
  378. package/src/tools/apps/registry.ts +1 -1
  379. package/src/tools/assets/materialize.ts +6 -6
  380. package/src/tools/assets/search.ts +10 -10
  381. package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
  382. package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
  383. package/src/tools/browser/auth-detector.ts +6 -6
  384. package/src/tools/browser/browser-execution.ts +13 -13
  385. package/src/tools/browser/browser-manager.ts +3 -3
  386. package/src/tools/browser/chrome-cdp.ts +5 -5
  387. package/src/tools/browser/jit-auth.ts +2 -2
  388. package/src/tools/browser/network-recorder.test.ts +2 -2
  389. package/src/tools/browser/network-recorder.ts +3 -3
  390. package/src/tools/browser/runtime-check.ts +3 -3
  391. package/src/tools/claude-code/claude-code.ts +2 -2
  392. package/src/tools/computer-use/definitions.ts +18 -18
  393. package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
  394. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
  395. package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
  396. package/src/tools/credentials/broker-types.ts +5 -5
  397. package/src/tools/credentials/broker.ts +15 -15
  398. package/src/tools/credentials/metadata-store.ts +2 -2
  399. package/src/tools/credentials/resolve.ts +1 -1
  400. package/src/tools/credentials/selection.ts +1 -1
  401. package/src/tools/credentials/tool-policy.ts +1 -1
  402. package/src/tools/credentials/vault.ts +115 -25
  403. package/src/tools/execution-target.ts +2 -2
  404. package/src/tools/executor.ts +7 -7
  405. package/src/tools/filesystem/edit.ts +2 -2
  406. package/src/tools/filesystem/read.ts +15 -4
  407. package/src/tools/filesystem/write.ts +1 -1
  408. package/src/tools/host-filesystem/edit.ts +2 -1
  409. package/src/tools/host-filesystem/read.ts +18 -1
  410. package/src/tools/host-filesystem/write.ts +1 -1
  411. package/src/tools/host-terminal/host-shell.ts +9 -8
  412. package/src/tools/mcp/mcp-tool-factory.ts +7 -6
  413. package/src/tools/memory/definitions.ts +6 -5
  414. package/src/tools/memory/handlers.test.ts +1 -1
  415. package/src/tools/network/__tests__/web-search.test.ts +3 -3
  416. package/src/tools/network/domain-normalize.ts +2 -2
  417. package/src/tools/network/script-proxy/session-manager.ts +10 -10
  418. package/src/tools/network/web-fetch.ts +1 -1
  419. package/src/tools/network/web-search.ts +3 -3
  420. package/src/tools/permission-checker.ts +8 -8
  421. package/src/tools/registry.ts +7 -7
  422. package/src/tools/schedule/list.ts +2 -2
  423. package/src/tools/schema-transforms.ts +31 -21
  424. package/src/tools/secret-detection-handler.ts +1 -1
  425. package/src/tools/sensitive-output-placeholders.ts +1 -1
  426. package/src/tools/shared/filesystem/edit-engine.ts +1 -1
  427. package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
  428. package/src/tools/shared/filesystem/image-read.ts +25 -5
  429. package/src/tools/shared/filesystem/path-policy.ts +2 -2
  430. package/src/tools/shared/shell-output.ts +1 -1
  431. package/src/tools/side-effects.ts +1 -1
  432. package/src/tools/skills/execute.ts +1 -1
  433. package/src/tools/skills/load.ts +3 -3
  434. package/src/tools/skills/sandbox-runner.ts +3 -3
  435. package/src/tools/subagent/read.ts +1 -1
  436. package/src/tools/subagent/spawn.ts +2 -2
  437. package/src/tools/swarm/delegate.ts +3 -3
  438. package/src/tools/system/request-permission.ts +5 -4
  439. package/src/tools/terminal/backends/native.ts +4 -4
  440. package/src/tools/terminal/parser.ts +6 -6
  441. package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
  442. package/src/tools/terminal/shell.ts +16 -16
  443. package/src/tools/tool-approval-handler.ts +21 -12
  444. package/src/tools/tool-manifest.ts +4 -4
  445. package/src/tools/types.ts +3 -3
  446. package/src/tools/ui-surface/definitions.ts +9 -37
  447. package/src/tools/watcher/list.ts +1 -1
  448. package/src/util/logger.ts +7 -2
  449. package/src/util/pricing.ts +4 -0
  450. package/src/util/retry.ts +29 -1
  451. package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
  452. package/src/workspace/migrations/registry.ts +2 -0
  453. package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
  454. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
  455. package/src/cli/reference.ts +0 -38
  456. package/src/memory/job-handlers/capability-cards.ts +0 -420
  457. package/src/runtime/routes/thread-starter-routes.ts +0 -294
@@ -146,7 +146,6 @@ export async function generateAndPersistConversationTitle(
146
146
  signal: combinedSignal,
147
147
  },
148
148
  );
149
-
150
149
  const textBlock = response.content.find((b) => b.type === "text");
151
150
  if (textBlock && textBlock.type === "text") {
152
151
  let title = normalizeTitle(textBlock.text);
@@ -312,7 +311,7 @@ function buildTitlePrompt(
312
311
  assistantResponse?: string,
313
312
  ): string {
314
313
  const parts: string[] = [
315
- "Generate a very short title for this conversation. Rules: at most 5 words, at most 40 characters, no quotes, no markdown formatting.",
314
+ "Generate a very short title summarizing the TOPIC of this conversation. Rules: at most 5 words, at most 40 characters, no quotes, no markdown formatting. IMPORTANT: Summarize what the user is asking about — do NOT respond to the message, do NOT assess feasibility, and do NOT comment on your own capabilities.",
316
315
  ];
317
316
 
318
317
  if (context) {
@@ -369,7 +368,7 @@ function deriveFallbackTitle(context?: TitleContext): string | null {
369
368
 
370
369
  function buildRegenerationPrompt(recentMessages: MessageRow[]): string {
371
370
  const parts: string[] = [
372
- "Generate a very short title for this conversation based on the recent messages below. Rules: at most 5 words, at most 40 characters, no quotes, no markdown formatting.",
371
+ "Generate a very short title summarizing the TOPIC of this conversation based on the recent messages below. Rules: at most 5 words, at most 40 characters, no quotes, no markdown formatting. IMPORTANT: Summarize what the user is asking about — do NOT respond to the messages, do NOT assess feasibility, and do NOT comment on your own capabilities.",
373
372
  "",
374
373
  "Recent messages:",
375
374
  ];
@@ -25,6 +25,7 @@ import {
25
25
  createCoreTables,
26
26
  createExternalConversationBindingsTables,
27
27
  createFollowupsTables,
28
+ createLifecycleEventsTable,
28
29
  createMediaAssetsTables,
29
30
  createMessagesFts,
30
31
  createNotificationTables,
@@ -51,8 +52,10 @@ import {
51
52
  migrateContactsRolePrincipal,
52
53
  migrateConversationsThreadTypeIndex,
53
54
  migrateCreateThreadStartersTable,
55
+ migrateCreateTraceEventsTable,
54
56
  migrateDropAccountsTable,
55
57
  migrateDropAssistantIdColumns,
58
+ migrateDropCapabilityCardState,
56
59
  migrateDropConflicts,
57
60
  migrateDropContactInteractionColumns,
58
61
  migrateDropEntityTables,
@@ -84,6 +87,7 @@ import {
84
87
  migrateReminderRoutingIntent,
85
88
  migrateRemindersToSchedules,
86
89
  migrateRenameConversationTypeColumn,
90
+ migrateRenameCreatedBySessionIdColumns,
87
91
  migrateRenameFollowupsThreadIdColumn,
88
92
  migrateRenameGmailProviderKeyToGoogle,
89
93
  migrateRenameGuardianVerificationValues,
@@ -91,6 +95,8 @@ import {
91
95
  migrateRenameNotificationThreadColumns,
92
96
  migrateRenameSequenceEnrollmentsThreadIdColumn,
93
97
  migrateRenameSequenceStepsReplyKey,
98
+ migrateRenameSourceSessionIdColumn,
99
+ migrateRenameThreadStartersTable,
94
100
  migrateRenameVerificationSessionIdColumn,
95
101
  migrateRenameVerificationTable,
96
102
  migrateRenameVoiceToPhone,
@@ -426,12 +432,30 @@ export function initializeDb(): void {
426
432
  // 72. Rename integration:gmail → integration:google across OAuth tables
427
433
  migrateRenameGmailProviderKeyToGoogle(database);
428
434
 
429
- // 73. Create thread_starters table for personalized empty-thread suggestions
435
+ // 73. Create thread_starters table for personalized empty-thread suggestions (renamed in migration 77)
430
436
  migrateCreateThreadStartersTable(database);
431
437
 
432
438
  // 74. Add capability card columns to thread_starters + category relevance table
433
439
  migrateCapabilityCardColumns(database);
434
440
 
441
+ // 75. Rename created_by_session_id → source_conversation_id in verification sessions and invites
442
+ migrateRenameCreatedBySessionIdColumns(database);
443
+
444
+ // 76. Rename source_session_id → source_context_id in notification_events
445
+ migrateRenameSourceSessionIdColumn(database);
446
+
447
+ // 77. Rename thread_starters → conversation_starters table and indexes
448
+ migrateRenameThreadStartersTable(database);
449
+
450
+ // 78. Lifecycle events table for app_open / hatch telemetry
451
+ createLifecycleEventsTable(database);
452
+
453
+ // 79. Remove deleted capability-card state while keeping conversation starter chips
454
+ migrateDropCapabilityCardState(database);
455
+
456
+ // 80. Trace events table for persistent trace/activity storage across sessions
457
+ migrateCreateTraceEventsTable(database);
458
+
435
459
  validateMigrationState(database);
436
460
 
437
461
  if (process.env.BUN_TEST === "1") {
@@ -23,7 +23,7 @@ export interface IngressInvite {
23
23
  id: string;
24
24
  sourceChannel: string;
25
25
  tokenHash: string;
26
- createdByConversationId: string | null;
26
+ sourceConversationId: string | null;
27
27
  note: string | null;
28
28
  maxUses: number;
29
29
  useCount: number;
@@ -73,7 +73,7 @@ function rowToInvite(
73
73
  id: row.id,
74
74
  sourceChannel: row.sourceChannel,
75
75
  tokenHash: row.tokenHash,
76
- createdByConversationId: row.createdByConversationId,
76
+ sourceConversationId: row.sourceConversationId,
77
77
  note: row.note,
78
78
  maxUses: row.maxUses,
79
79
  useCount: row.useCount,
@@ -101,7 +101,7 @@ function rowToInvite(
101
101
  export function createInvite(params: {
102
102
  sourceChannel: string;
103
103
  contactId: string;
104
- createdByConversationId?: string;
104
+ sourceConversationId?: string;
105
105
  note?: string;
106
106
  maxUses?: number;
107
107
  expiresInMs?: number;
@@ -124,7 +124,7 @@ export function createInvite(params: {
124
124
  id,
125
125
  sourceChannel: params.sourceChannel,
126
126
  tokenHash: tokenH,
127
- createdByConversationId: params.createdByConversationId ?? null,
127
+ sourceConversationId: params.sourceConversationId ?? null,
128
128
  note: params.note ?? null,
129
129
  maxUses: params.maxUses ?? 1,
130
130
  useCount: 0,
@@ -12,6 +12,7 @@ import {
12
12
  } from "../providers/provider-send-message.js";
13
13
  import { getLogger } from "../util/logger.js";
14
14
  import { truncate } from "../util/truncate.js";
15
+ import { maybeEnqueueConversationStartersJob } from "./conversation-starters-cadence.js";
15
16
  import { getDb } from "./db.js";
16
17
  import { computeMemoryFingerprint } from "./fingerprint.js";
17
18
  import { enqueueMemoryJob } from "./jobs-store.js";
@@ -20,7 +21,6 @@ import { withQdrantBreaker } from "./qdrant-circuit-breaker.js";
20
21
  import { getQdrantClient } from "./qdrant-client.js";
21
22
  import { memoryItems, memoryItemSources, messages } from "./schema.js";
22
23
  import { isConversationFailed } from "./task-memory-cleanup.js";
23
- import { maybeEnqueueThreadStartersJob } from "./thread-starters-cadence.js";
24
24
  import { clampUnitInterval } from "./validation.js";
25
25
 
26
26
  const log = getLogger("memory-items-extractor");
@@ -715,14 +715,14 @@ export async function extractAndUpsertMemoryItemsForMessage(
715
715
  "Extracted memory items from message",
716
716
  );
717
717
 
718
- // Trigger thread starters generation when new items are upserted
718
+ // Trigger conversation starters generation when new items are upserted
719
719
  if (upserted > 0) {
720
720
  try {
721
- maybeEnqueueThreadStartersJob(effectiveScopeId);
721
+ maybeEnqueueConversationStartersJob(effectiveScopeId);
722
722
  } catch (err) {
723
723
  log.warn(
724
724
  { err: err instanceof Error ? err.message : String(err) },
725
- "Failed to check thread starters cadence",
725
+ "Failed to check conversation starters cadence",
726
726
  );
727
727
  }
728
728
  }
@@ -1,14 +1,15 @@
1
1
  /**
2
- * Job handler for generating thread starters.
2
+ * Job handler for generating conversation starters.
3
3
  *
4
4
  * Crosses user memory items with the skill catalog to produce personalized
5
- * suggestion chips shown on the empty thread page.
5
+ * suggestion chips shown on the empty conversation page.
6
6
  */
7
7
 
8
8
  import { and, desc, eq } from "drizzle-orm";
9
9
  import { v4 as uuid } from "uuid";
10
10
 
11
11
  import { loadSkillCatalog } from "../../config/skills.js";
12
+ import { buildCoreIdentityContext } from "../../prompts/system-prompt.js";
12
13
  import {
13
14
  createTimeout,
14
15
  extractToolUse,
@@ -21,17 +22,21 @@ import { getDb } from "../db.js";
21
22
  import { asString } from "../job-utils.js";
22
23
  import type { MemoryJob } from "../jobs-store.js";
23
24
  import { rawAll, rawGet } from "../raw-query.js";
24
- import { memoryCheckpoints, memoryItems, threadStarters } from "../schema.js";
25
+ import {
26
+ conversationStarters,
27
+ memoryCheckpoints,
28
+ memoryItems,
29
+ } from "../schema.js";
25
30
 
26
- const log = getLogger("thread-starters-gen");
31
+ const log = getLogger("conversation-starters-gen");
27
32
 
28
33
  function checkpointKey(base: string, scopeId: string): string {
29
34
  return `${base}:${scopeId}`;
30
35
  }
31
36
 
32
- const CK_ITEM_COUNT = "thread_starters:item_count_at_last_gen";
33
- const CK_BATCH = "thread_starters:generation_batch";
34
- const CK_LAST_GEN_AT = "thread_starters:last_gen_at";
37
+ const CK_ITEM_COUNT = "conversation_starters:item_count_at_last_gen";
38
+ const CK_BATCH = "conversation_starters:generation_batch";
39
+ const CK_LAST_GEN_AT = "conversation_starters:last_gen_at";
35
40
 
36
41
  // ── Rollup construction ───────────────────────────────────────────
37
42
 
@@ -126,7 +131,7 @@ export function buildSkillsSummary(): string {
126
131
  // ── LLM generation ────────────────────────────────────────────────
127
132
 
128
133
  /** Capability categories matching the Intelligence page taxonomy. */
129
- export const THREAD_STARTER_CATEGORIES = [
134
+ export const CONVERSATION_STARTER_CATEGORIES = [
130
135
  "communication",
131
136
  "productivity",
132
137
  "development",
@@ -137,7 +142,8 @@ export const THREAD_STARTER_CATEGORIES = [
137
142
  "integration",
138
143
  ] as const;
139
144
 
140
- export type ThreadStarterCategory = (typeof THREAD_STARTER_CATEGORIES)[number];
145
+ export type ConversationStarterCategory =
146
+ (typeof CONVERSATION_STARTER_CATEGORIES)[number];
141
147
 
142
148
  interface GeneratedStarter {
143
149
  label: string;
@@ -148,48 +154,110 @@ interface GeneratedStarter {
148
154
  async function generateStarters(scopeId: string): Promise<GeneratedStarter[]> {
149
155
  const provider = await getConfiguredProvider();
150
156
  if (!provider) {
151
- log.info("No configured provider for thread starters generation");
157
+ log.info("No configured provider for conversation starters generation");
152
158
  return [];
153
159
  }
154
160
 
155
161
  const rollup = buildMemoryRollup(scopeId);
156
162
  if (!rollup) {
157
- log.info("No memory items to generate thread starters from");
163
+ log.info("No memory items to generate conversation starters from");
158
164
  return [];
159
165
  }
160
166
  const diff = buildNewItemsDiff(scopeId);
161
167
  const skills = buildSkillsSummary();
162
168
 
163
- const systemPrompt = `You are generating thread starter suggestions for a personal AI assistant's empty conversation page. These are clickable chips that help the user discover what the assistant can do, personalized to their context.
169
+ const now = new Date();
170
+ const timeContext = `Current time: ${now.toLocaleString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "2-digit", hour12: true })}`;
171
+
172
+ const identityContext = buildCoreIdentityContext();
173
+
174
+ const systemPrompt = `You are generating 4 conversation starters for a personal assistant app. These appear as clickable chips on the empty conversation page — the first thing the user sees when they open the app.
175
+
176
+ ${timeContext}
164
177
 
165
- Given the user's accumulated memories and the assistant's available skills, generate 4-6 thread starters. Each starter has:
166
- - label: Short chip text (max 50 chars). Start with a verb. Be specific and actionable.
167
- - prompt: The full message that will be sent when clicked (1-2 natural sentences).
168
- - category: One of: ${THREAD_STARTER_CATEGORIES.join(", ")}. Pick the best-fit capability category.
178
+ Your goal: look at what's going on in this person's life right now and suggest the 4 most useful things they could ask you to do. Think about what a thoughtful chief of staff would proactively bring up in a 30-second check-in.
169
179
 
170
- Rules:
171
- - Cross user context (who they are, what they work on) with assistant capabilities (skills).
172
- - Be specific to THIS user — generic suggestions like "Tell me a joke" are not useful.
173
- - Vary across different skills and memory categories.
174
- - Labels should be concise and scannable.
175
- - Prompts should be natural, as if the user typed them.
180
+ ${identityContext ? `## Assistant identity & user profile\n\n${identityContext}\n\n` : ""}## What you know
176
181
 
177
182
  ${rollup}
178
183
  ${diff}
179
- ${skills}`;
184
+ ${skills}
185
+
186
+ ## How to think about this
187
+
188
+ Start from the user's situation, not from the skill list. Ask yourself:
189
+ - What is this person likely dealing with right now (given the day/time and their context)?
190
+ - What's active, stuck, or coming up soon?
191
+ - Where could I save them real time or effort right now?
192
+
193
+ The skills list tells you what the assistant CAN do — use it to filter out suggestions the assistant can't actually help with, not as a menu to generate suggestions from.
194
+
195
+ ## Selection
196
+
197
+ Generate exactly 4 starters, ranked #1 (best) to #4.
198
+
199
+ For each, you must be able to clearly answer:
200
+ - Why now? (timing — day of week, recent activity, upcoming deadline)
201
+ - Why this user? (grounded in their specific context, not generic)
202
+ - Why would they be glad I suggested this? (genuine usefulness, not just relevance)
203
+
204
+ If you can't answer all three strongly, replace it with something better.
205
+
206
+ Prioritize:
207
+ - Relief: unblock something stuck, reduce drag
208
+ - Momentum: advance work already in motion
209
+ - Confidence: surface what they need to decide or act on
210
+ - Curiosity: something timely they'd want to know about
211
+
212
+ Favor what is live over what is merely true. Recent changes matter more than old memories. Active work matters more than dormant topics. This week matters more than "someday."
213
+
214
+ ## Output format
215
+
216
+ Return exactly 4 starters in rank order (best first).
217
+
218
+ Each starter has:
219
+ - label: 3-6 words, max 40 chars, starts with a verb. Should sound like a smart offer of help, not a feature name or task description. Must sound natural when read aloud.
220
+ - prompt: 1-2 natural sentences, written as the user would actually say them — not templated.
221
+ - category: one of ${CONVERSATION_STARTER_CATEGORIES.join(", ")}
222
+
223
+ The 4 starters should feel like one coherent set of recommendations for this moment — similar abstraction level, no jarring mix of mundane chores and life strategy. Don't lift raw memory phrases, project names, or jargon into labels unless they already sound natural in conversation.
224
+
225
+ Never include a chip whose primary meaning is configuration, setup, workflow creation, or "set up X for Y" unless it solves an urgent pain the user is actively feeling right now. Prefer the outcome over the mechanism — "Catch the emails that matter" beats "Set up a playbook for inbox."
226
+
227
+ ## Topic diversity
228
+
229
+ Each chip should cover a distinct topic or concern. Never have two chips about the same tool, project, or theme — even if there are multiple related issues. Pick the single most impactful angle and give the other slot to something different. Four chips about three topics is too narrow; four chips about four topics is right.
230
+
231
+ ## User-facingness check
232
+
233
+ If a label sounds like an issue title, project ticket, or implementation task, rewrite it. Prefer the user-visible payoff over the internal object name. The chip should feel inviting and useful, not merely accurate.
234
+
235
+ Prefer natural, flowing language over mechanical or operational phrasing. "Get Slack messages flowing" is better than "Restore outgoing Slack messages." The label should sound like something a helpful person would say, not a support ticket.
236
+
237
+ Before finalizing each label, ask yourself: would this feel good to click? Or does it sound like a backlog item? If it sounds like a backlog item, rewrite it.
238
+
239
+ Examples of bad vs good:
240
+ - BAD: "Fix Slack Socket Mode blocker" → GOOD: "Fix Slack so it just works"
241
+ - BAD: "Rewire messaging for Socket Mode" → GOOD: "Get Socket Mode stable"
242
+ - BAD: "Review this week's calendar" → GOOD: "Protect this week's focus"
243
+ - BAD: "Model the coaching transition" → GOOD: "Plan the coaching transition"
244
+ - BAD: "Restore outgoing Slack messages" → GOOD: "Get Slack messages flowing"
245
+ - BAD: "Set up a playbook for inbox" → GOOD: "Catch the emails that matter"
246
+
247
+ The good versions emphasize the user's payoff, not the internal mechanism.`;
180
248
 
181
249
  const { signal, cleanup } = createTimeout(20000);
182
250
  try {
183
251
  const response = await provider.sendMessage(
184
252
  [
185
253
  userMessage(
186
- "Generate personalized thread starters based on my context.",
254
+ "Generate personalized conversation starters based on my context.",
187
255
  ),
188
256
  ],
189
257
  [
190
258
  {
191
- name: "store_thread_starters",
192
- description: "Store generated thread starter suggestions",
259
+ name: "store_conversation_starters",
260
+ description: "Store generated conversation starter suggestions",
193
261
  input_schema: {
194
262
  type: "object" as const,
195
263
  properties: {
@@ -201,15 +269,16 @@ ${skills}`;
201
269
  label: {
202
270
  type: "string",
203
271
  description:
204
- "Short chip text (max 50 chars, starts with a verb)",
272
+ "Concierge-quality chip text (2-7 words, max 40 chars, starts with a verb)",
205
273
  },
206
274
  prompt: {
207
275
  type: "string",
208
- description: "Full message sent on click (1-2 sentences)",
276
+ description:
277
+ "Full message sent on click (1-2 natural sentences, as the user would say it)",
209
278
  },
210
279
  category: {
211
280
  type: "string",
212
- enum: [...THREAD_STARTER_CATEGORIES],
281
+ enum: [...CONVERSATION_STARTER_CATEGORIES],
213
282
  description: "Capability category for grouping",
214
283
  },
215
284
  },
@@ -226,7 +295,10 @@ ${skills}`;
226
295
  config: {
227
296
  modelIntent: "quality-optimized",
228
297
  max_tokens: 1024,
229
- tool_choice: { type: "tool" as const, name: "store_thread_starters" },
298
+ tool_choice: {
299
+ type: "tool" as const,
300
+ name: "store_conversation_starters",
301
+ },
230
302
  },
231
303
  signal,
232
304
  },
@@ -235,7 +307,9 @@ ${skills}`;
235
307
 
236
308
  const toolBlock = extractToolUse(response);
237
309
  if (!toolBlock) {
238
- log.warn("No tool_use block in thread starters generation response");
310
+ log.warn(
311
+ "No tool_use block in conversation starters generation response",
312
+ );
239
313
  return [];
240
314
  }
241
315
 
@@ -253,12 +327,15 @@ ${skills}`;
253
327
  typeof s.prompt === "string" &&
254
328
  s.prompt.length > 0,
255
329
  )
330
+ .slice(0, 4)
256
331
  .map((s) => ({
257
- label: truncate(s.label, 50, ""),
332
+ label: truncate(s.label, 40, ""),
258
333
  prompt: truncate(s.prompt, 500, ""),
259
334
  category:
260
335
  typeof s.category === "string" &&
261
- (THREAD_STARTER_CATEGORIES as readonly string[]).includes(s.category)
336
+ (CONVERSATION_STARTER_CATEGORIES as readonly string[]).includes(
337
+ s.category,
338
+ )
262
339
  ? s.category
263
340
  : "productivity",
264
341
  }));
@@ -270,12 +347,14 @@ ${skills}`;
270
347
 
271
348
  // ── Job handler ───────────────────────────────────────────────────
272
349
 
273
- export async function generateThreadStartersJob(job: MemoryJob): Promise<void> {
350
+ export async function generateConversationStartersJob(
351
+ job: MemoryJob,
352
+ ): Promise<void> {
274
353
  const scopeId = asString(job.payload.scopeId) ?? "default";
275
354
 
276
355
  const starters = await generateStarters(scopeId);
277
356
  if (starters.length === 0) {
278
- log.info({ scopeId }, "No thread starters generated");
357
+ log.info({ scopeId }, "No conversation starters generated");
279
358
  return;
280
359
  }
281
360
 
@@ -303,14 +382,20 @@ export async function generateThreadStartersJob(job: MemoryJob): Promise<void> {
303
382
  .all();
304
383
  const sourceKinds = kindRows.map((r) => r.kind).join(",");
305
384
 
306
- // Insert starters
385
+ // Remove previous starters for this scope before inserting the new batch
386
+ db.delete(conversationStarters)
387
+ .where(eq(conversationStarters.scopeId, scopeId))
388
+ .run();
389
+
390
+ // Insert starters — all are chips
307
391
  for (const starter of starters) {
308
- db.insert(threadStarters)
392
+ db.insert(conversationStarters)
309
393
  .values({
310
394
  id: uuid(),
311
395
  label: starter.label,
312
396
  prompt: starter.prompt,
313
397
  category: starter.category,
398
+ cardType: "chip",
314
399
  generationBatch: nextBatch,
315
400
  scopeId,
316
401
  sourceMemoryKinds: sourceKinds,
@@ -343,6 +428,6 @@ export async function generateThreadStartersJob(job: MemoryJob): Promise<void> {
343
428
 
344
429
  log.info(
345
430
  { scopeId, batch: nextBatch, count: starters.length },
346
- "Generated thread starters",
431
+ "Generated conversation starters",
347
432
  );
348
433
  }
@@ -26,8 +26,9 @@ export type MemoryJobType =
26
26
  | "media_processing"
27
27
  | "embed_media"
28
28
  | "embed_attachment"
29
- | "generate_thread_starters"
30
- | "generate_capability_cards";
29
+ | "generate_conversation_starters"
30
+ | "generate_capability_cards" // legacy compat — silently dropped by worker (capability cards removed)
31
+ | "generate_thread_starters"; // legacy compat — silently dropped by worker (renamed to generate_conversation_starters)
31
32
 
32
33
  const EMBED_JOB_TYPES: MemoryJobType[] = [
33
34
  "embed_segment",
@@ -3,11 +3,11 @@ import type { AssistantConfig } from "../config/types.js";
3
3
  import { getLogger } from "../util/logger.js";
4
4
  import { rawRun } from "./db.js";
5
5
  import { backfillJob } from "./job-handlers/backfill.js";
6
- import { generateCapabilityCardsJob } from "./job-handlers/capability-cards.js";
7
6
  import {
8
7
  cleanupStaleSupersededItemsJob,
9
8
  pruneOldConversationsJob,
10
9
  } from "./job-handlers/cleanup.js";
10
+ import { generateConversationStartersJob } from "./job-handlers/conversation-starters.js";
11
11
  // ── Per-job-type handlers ──────────────────────────────────────────
12
12
  import {
13
13
  embedAttachmentJob,
@@ -23,7 +23,6 @@ import {
23
23
  } from "./job-handlers/index-maintenance.js";
24
24
  import { mediaProcessingJob } from "./job-handlers/media-processing.js";
25
25
  import { buildConversationSummaryJob } from "./job-handlers/summarization.js";
26
- import { generateThreadStartersJob } from "./job-handlers/thread-starters.js";
27
26
  import {
28
27
  BackendUnavailableError,
29
28
  classifyError,
@@ -308,11 +307,14 @@ async function processJob(
308
307
  case "embed_attachment":
309
308
  await embedAttachmentJob(job, config);
310
309
  return;
311
- case "generate_thread_starters":
312
- await generateThreadStartersJob(job);
310
+ case "generate_conversation_starters":
311
+ await generateConversationStartersJob(job);
313
312
  return;
314
313
  case "generate_capability_cards":
315
- await generateCapabilityCardsJob(job);
314
+ // Capability cards were removed — silently drop legacy jobs.
315
+ return;
316
+ case "generate_thread_starters":
317
+ // Thread starters renamed to conversation starters — silently drop legacy jobs
316
318
  return;
317
319
  default:
318
320
  throw new Error(
@@ -0,0 +1,63 @@
1
+ import { and, asc, eq, gt, or } from "drizzle-orm";
2
+ import { v4 as uuid } from "uuid";
3
+
4
+ import { getDb } from "./db.js";
5
+ import { lifecycleEvents } from "./schema.js";
6
+
7
+ export interface LifecycleEvent {
8
+ id: string;
9
+ eventName: string;
10
+ createdAt: number;
11
+ }
12
+
13
+ /** Record a lifecycle event (e.g. app_open, hatch). */
14
+ export function recordLifecycleEvent(eventName: string): LifecycleEvent {
15
+ const db = getDb();
16
+ const event: LifecycleEvent = {
17
+ id: uuid(),
18
+ eventName,
19
+ createdAt: Date.now(),
20
+ };
21
+ db.insert(lifecycleEvents)
22
+ .values({
23
+ id: event.id,
24
+ eventName: event.eventName,
25
+ createdAt: event.createdAt,
26
+ })
27
+ .run();
28
+ return event;
29
+ }
30
+
31
+ /**
32
+ * Query lifecycle events that haven't been reported to telemetry yet.
33
+ * Uses a compound cursor (createdAt + id) for reliable watermarking.
34
+ */
35
+ export function queryUnreportedLifecycleEvents(
36
+ afterCreatedAt: number,
37
+ afterId: string | undefined,
38
+ limit: number,
39
+ ): LifecycleEvent[] {
40
+ const db = getDb();
41
+ const rows = db
42
+ .select({
43
+ id: lifecycleEvents.id,
44
+ eventName: lifecycleEvents.eventName,
45
+ createdAt: lifecycleEvents.createdAt,
46
+ })
47
+ .from(lifecycleEvents)
48
+ .where(
49
+ afterId
50
+ ? or(
51
+ gt(lifecycleEvents.createdAt, afterCreatedAt),
52
+ and(
53
+ eq(lifecycleEvents.createdAt, afterCreatedAt),
54
+ gt(lifecycleEvents.id, afterId),
55
+ ),
56
+ )
57
+ : gt(lifecycleEvents.createdAt, afterCreatedAt),
58
+ )
59
+ .orderBy(asc(lifecycleEvents.createdAt), asc(lifecycleEvents.id))
60
+ .limit(limit)
61
+ .all();
62
+ return rows;
63
+ }
@@ -0,0 +1,27 @@
1
+ import { type DrizzleDb } from "../db-connection.js";
2
+
3
+ /**
4
+ * Rename `created_by_session_id` to `source_conversation_id` in two tables,
5
+ * aligning with the broader session → conversation terminology unification.
6
+ *
7
+ * Each rename is wrapped in try/catch so re-running the migration is
8
+ * idempotent (SQLite throws if the source column does not exist).
9
+ */
10
+ export function migrateRenameCreatedBySessionIdColumns(
11
+ database: DrizzleDb,
12
+ ): void {
13
+ try {
14
+ database.run(
15
+ `ALTER TABLE channel_verification_sessions RENAME COLUMN created_by_session_id TO source_conversation_id`,
16
+ );
17
+ } catch {
18
+ /* already renamed */
19
+ }
20
+ try {
21
+ database.run(
22
+ `ALTER TABLE assistant_ingress_invites RENAME COLUMN created_by_session_id TO source_conversation_id`,
23
+ );
24
+ } catch {
25
+ /* already renamed */
26
+ }
27
+ }
@@ -0,0 +1,16 @@
1
+ import { type DrizzleDb } from "../db-connection.js";
2
+
3
+ /**
4
+ * Rename `source_session_id` to `source_context_id` in the `notification_events`
5
+ * table, aligning with the field's actual polymorphic usage (it holds conversation
6
+ * IDs, call session IDs, schedule IDs, etc.).
7
+ */
8
+ export function migrateRenameSourceSessionIdColumn(database: DrizzleDb): void {
9
+ try {
10
+ database.run(
11
+ `ALTER TABLE notification_events RENAME COLUMN source_session_id TO source_context_id`,
12
+ );
13
+ } catch {
14
+ /* already renamed */
15
+ }
16
+ }