@vellumai/assistant 0.4.48 → 0.4.50

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 (423) hide show
  1. package/ARCHITECTURE.md +26 -35
  2. package/README.md +5 -26
  3. package/docs/architecture/integrations.md +45 -41
  4. package/docs/architecture/keychain-broker.md +3 -3
  5. package/docs/architecture/memory.md +180 -119
  6. package/docs/runbook-trusted-contacts.md +3 -8
  7. package/hook-templates/debug-prompt-logger/hook.json +1 -1
  8. package/hook-templates/debug-prompt-logger/run.sh +1 -3
  9. package/package.json +2 -2
  10. package/src/__tests__/actor-token-service.test.ts +0 -1
  11. package/src/__tests__/agent-loop.test.ts +3 -1
  12. package/src/__tests__/anthropic-provider.test.ts +249 -2
  13. package/src/__tests__/approval-cascade.test.ts +796 -0
  14. package/src/__tests__/approval-primitive.test.ts +0 -1
  15. package/src/__tests__/approval-routes-http.test.ts +4 -0
  16. package/src/__tests__/assistant-attachments.test.ts +12 -34
  17. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  18. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
  19. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
  20. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  21. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  22. package/src/__tests__/channel-guardian.test.ts +0 -2
  23. package/src/__tests__/channel-readiness-routes.test.ts +15 -6
  24. package/src/__tests__/channel-readiness-service.test.ts +10 -9
  25. package/src/__tests__/checker.test.ts +13 -20
  26. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
  27. package/src/__tests__/computer-use-tools.test.ts +2 -19
  28. package/src/__tests__/config-schema.test.ts +1 -68
  29. package/src/__tests__/config-watcher.test.ts +0 -1
  30. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  31. package/src/__tests__/context-image-dimensions.test.ts +332 -0
  32. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  33. package/src/__tests__/context-token-estimator.test.ts +196 -13
  34. package/src/__tests__/conversation-attention-store.test.ts +0 -1
  35. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  36. package/src/__tests__/conversation-routes-guardian-reply.test.ts +152 -0
  37. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  38. package/src/__tests__/credential-metadata-store.test.ts +64 -73
  39. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  40. package/src/__tests__/credential-security-invariants.test.ts +13 -7
  41. package/src/__tests__/credential-vault-unit.test.ts +284 -49
  42. package/src/__tests__/credential-vault.test.ts +150 -16
  43. package/src/__tests__/credentials-cli.test.ts +71 -0
  44. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  45. package/src/__tests__/date-context.test.ts +93 -77
  46. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  47. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  48. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  49. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  50. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
  51. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
  52. package/src/__tests__/guardian-routing-invariants.test.ts +93 -1
  53. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  54. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
  55. package/src/__tests__/heartbeat-service.test.ts +0 -1
  56. package/src/__tests__/history-repair.test.ts +245 -0
  57. package/src/__tests__/host-cu-proxy.test.ts +791 -0
  58. package/src/__tests__/host-shell-tool.test.ts +27 -15
  59. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  60. package/src/__tests__/ingress-url-consistency.test.ts +14 -21
  61. package/src/__tests__/integration-status.test.ts +32 -51
  62. package/src/__tests__/intent-routing.test.ts +0 -1
  63. package/src/__tests__/invite-redemption-service.test.ts +65 -1
  64. package/src/__tests__/invite-routes-http.test.ts +10 -9
  65. package/src/__tests__/keychain-broker-client.test.ts +14 -46
  66. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  67. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  68. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  69. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  70. package/src/__tests__/memory-regressions.test.ts +477 -2841
  71. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  72. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  73. package/src/__tests__/mime-builder.test.ts +28 -0
  74. package/src/__tests__/native-web-search.test.ts +1 -0
  75. package/src/__tests__/notification-routing-intent.test.ts +0 -1
  76. package/src/__tests__/oauth-cli.test.ts +941 -15
  77. package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
  78. package/src/__tests__/oauth-scope-policy.test.ts +4 -6
  79. package/src/__tests__/oauth-store.test.ts +870 -0
  80. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
  81. package/src/__tests__/provider-error-scenarios.test.ts +0 -1
  82. package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
  83. package/src/__tests__/public-ingress-urls.test.ts +15 -21
  84. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  85. package/src/__tests__/recording-handler.test.ts +3 -4
  86. package/src/__tests__/registry.test.ts +2 -3
  87. package/src/__tests__/relay-server.test.ts +46 -1
  88. package/src/__tests__/runtime-events-sse.test.ts +55 -7
  89. package/src/__tests__/schedule-store.test.ts +0 -1
  90. package/src/__tests__/schedule-tools.test.ts +32 -0
  91. package/src/__tests__/scheduler-recurrence.test.ts +0 -1
  92. package/src/__tests__/scoped-approval-grants.test.ts +0 -1
  93. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
  94. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  95. package/src/__tests__/secret-ingress-handler.test.ts +0 -1
  96. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  97. package/src/__tests__/secure-keys.test.ts +7 -2
  98. package/src/__tests__/send-endpoint-busy.test.ts +24 -6
  99. package/src/__tests__/sequence-store.test.ts +0 -1
  100. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  101. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  102. package/src/__tests__/session-agent-loop.test.ts +19 -15
  103. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  104. package/src/__tests__/session-error.test.ts +124 -2
  105. package/src/__tests__/session-history-web-search.test.ts +918 -0
  106. package/src/__tests__/session-init.benchmark.test.ts +4 -5
  107. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  108. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  109. package/src/__tests__/session-queue.test.ts +37 -27
  110. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  111. package/src/__tests__/session-slash-known.test.ts +1 -15
  112. package/src/__tests__/session-slash-queue.test.ts +1 -15
  113. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  114. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  115. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  116. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  117. package/src/__tests__/skill-include-graph.test.ts +66 -0
  118. package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
  119. package/src/__tests__/skill-load-tool.test.ts +149 -1
  120. package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
  121. package/src/__tests__/skills-install-extract.test.ts +93 -0
  122. package/src/__tests__/skills-uninstall.test.ts +1 -1
  123. package/src/__tests__/skills.test.ts +3 -3
  124. package/src/__tests__/skillssh-registry.test.ts +451 -0
  125. package/src/__tests__/slack-channel-config.test.ts +67 -3
  126. package/src/__tests__/slack-share-routes.test.ts +17 -19
  127. package/src/__tests__/system-prompt.test.ts +0 -1
  128. package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
  129. package/src/__tests__/terminal-tools.test.ts +4 -3
  130. package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
  131. package/src/__tests__/tool-approval-handler.test.ts +0 -1
  132. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
  133. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  134. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
  135. package/src/__tests__/tool-executor.test.ts +0 -1
  136. package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
  137. package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
  138. package/src/__tests__/trust-store.test.ts +7 -13
  139. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  140. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  141. package/src/__tests__/twilio-routes.test.ts +0 -16
  142. package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
  143. package/src/__tests__/voice-invite-redemption.test.ts +32 -1
  144. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
  145. package/src/agent/ax-tree-compaction.test.ts +286 -0
  146. package/src/agent/loop.ts +104 -131
  147. package/src/approvals/AGENTS.md +1 -1
  148. package/src/approvals/guardian-request-resolvers.ts +14 -2
  149. package/src/bundler/compiler-tools.ts +66 -2
  150. package/src/calls/call-domain.ts +133 -6
  151. package/src/calls/call-store.ts +6 -0
  152. package/src/calls/relay-server.ts +52 -18
  153. package/src/calls/relay-setup-router.ts +17 -1
  154. package/src/calls/twilio-config.ts +3 -8
  155. package/src/calls/twilio-routes.ts +1 -2
  156. package/src/calls/types.ts +3 -1
  157. package/src/calls/voice-ingress-preflight.ts +1 -1
  158. package/src/cli/commands/browser-relay.ts +18 -12
  159. package/src/cli/commands/completions.ts +0 -3
  160. package/src/cli/commands/credentials.ts +101 -15
  161. package/src/cli/commands/doctor.ts +4 -3
  162. package/src/cli/commands/mcp.ts +46 -59
  163. package/src/cli/commands/memory.ts +16 -165
  164. package/src/cli/commands/oauth/apps.ts +284 -0
  165. package/src/cli/commands/oauth/connections.ts +633 -0
  166. package/src/cli/commands/oauth/index.ts +52 -0
  167. package/src/cli/commands/oauth/providers.ts +256 -0
  168. package/src/cli/commands/sessions.ts +5 -2
  169. package/src/cli/commands/skills.ts +177 -339
  170. package/src/cli/http-client.ts +0 -20
  171. package/src/cli/main-screen.tsx +2 -2
  172. package/src/cli/program.ts +6 -11
  173. package/src/cli/reference.ts +1 -3
  174. package/src/cli.ts +4 -10
  175. package/src/config/assistant-feature-flags.ts +0 -3
  176. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
  177. package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
  178. package/src/config/bundled-skills/computer-use/TOOLS.json +23 -5
  179. package/src/config/bundled-skills/computer-use/tools/{computer-use-request-control.ts → computer-use-observe.ts} +1 -5
  180. package/src/config/bundled-skills/google-calendar/calendar-client.ts +21 -16
  181. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -4
  182. package/src/config/bundled-skills/settings/SKILL.md +1 -1
  183. package/src/config/bundled-skills/settings/TOOLS.json +2 -8
  184. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
  185. package/src/config/bundled-tool-registry.ts +2 -5
  186. package/src/config/env-registry.ts +14 -83
  187. package/src/config/env.ts +11 -50
  188. package/src/config/feature-flag-registry.json +16 -16
  189. package/src/config/loader.ts +0 -6
  190. package/src/config/schema.ts +4 -13
  191. package/src/config/schemas/memory-lifecycle.ts +0 -9
  192. package/src/config/schemas/memory-processing.ts +0 -180
  193. package/src/config/schemas/memory-retrieval.ts +32 -104
  194. package/src/config/schemas/memory.ts +0 -10
  195. package/src/config/skills.ts +21 -2
  196. package/src/config/types.ts +0 -4
  197. package/src/context/image-dimensions.ts +229 -0
  198. package/src/context/token-estimator.ts +75 -12
  199. package/src/context/window-manager.ts +53 -11
  200. package/src/daemon/assistant-attachments.ts +1 -13
  201. package/src/daemon/config-watcher.ts +61 -3
  202. package/src/daemon/daemon-control.ts +1 -1
  203. package/src/daemon/date-context.ts +114 -31
  204. package/src/daemon/handlers/config-ingress.ts +8 -33
  205. package/src/daemon/handlers/config-slack-channel.ts +49 -46
  206. package/src/daemon/handlers/config-telegram.ts +32 -16
  207. package/src/daemon/handlers/sessions.ts +27 -36
  208. package/src/daemon/handlers/shared.ts +0 -130
  209. package/src/daemon/handlers/skills.ts +20 -1
  210. package/src/daemon/history-repair.ts +72 -8
  211. package/src/daemon/host-cu-proxy.ts +430 -0
  212. package/src/daemon/lifecycle.ts +67 -71
  213. package/src/daemon/mcp-reload-service.ts +2 -2
  214. package/src/daemon/message-protocol.ts +3 -0
  215. package/src/daemon/message-types/computer-use.ts +1 -129
  216. package/src/daemon/message-types/host-cu.ts +19 -0
  217. package/src/daemon/message-types/memory.ts +4 -16
  218. package/src/daemon/message-types/messages.ts +4 -0
  219. package/src/daemon/message-types/sessions.ts +4 -0
  220. package/src/daemon/server.ts +25 -21
  221. package/src/daemon/session-agent-loop-handlers.ts +40 -0
  222. package/src/daemon/session-agent-loop.ts +334 -48
  223. package/src/daemon/session-attachments.ts +1 -2
  224. package/src/daemon/session-error.ts +89 -6
  225. package/src/daemon/session-history.ts +17 -7
  226. package/src/daemon/session-media-retry.ts +6 -2
  227. package/src/daemon/session-memory.ts +69 -149
  228. package/src/daemon/session-process.ts +10 -1
  229. package/src/daemon/session-runtime-assembly.ts +49 -19
  230. package/src/daemon/session-slash.ts +1 -1
  231. package/src/daemon/session-surfaces.ts +43 -28
  232. package/src/daemon/session-tool-setup.ts +9 -10
  233. package/src/daemon/session.ts +150 -17
  234. package/src/daemon/tool-side-effects.ts +2 -8
  235. package/src/daemon/watch-handler.ts +2 -2
  236. package/src/events/tool-metrics-listener.ts +2 -2
  237. package/src/hooks/manager.ts +1 -4
  238. package/src/inbound/public-ingress-urls.ts +7 -7
  239. package/src/instrument.ts +61 -1
  240. package/src/logfire.ts +16 -5
  241. package/src/memory/admin.ts +2 -191
  242. package/src/memory/canonical-guardian-store.ts +38 -2
  243. package/src/memory/conversation-crud.ts +0 -33
  244. package/src/memory/conversation-key-store.ts +21 -0
  245. package/src/memory/conversation-queries.ts +22 -3
  246. package/src/memory/db-init.ts +32 -0
  247. package/src/memory/embedding-backend.ts +84 -8
  248. package/src/memory/embedding-types.ts +9 -1
  249. package/src/memory/indexer.ts +7 -46
  250. package/src/memory/items-extractor.ts +274 -76
  251. package/src/memory/job-handlers/backfill.ts +2 -127
  252. package/src/memory/job-handlers/cleanup.ts +2 -16
  253. package/src/memory/job-handlers/extraction.ts +2 -138
  254. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  255. package/src/memory/job-handlers/summarization.ts +3 -148
  256. package/src/memory/job-utils.ts +21 -59
  257. package/src/memory/jobs-store.ts +1 -159
  258. package/src/memory/jobs-worker.ts +9 -52
  259. package/src/memory/migrations/104-core-indexes.ts +3 -3
  260. package/src/memory/migrations/149-oauth-tables.ts +62 -0
  261. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  262. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  263. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  264. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  265. package/src/memory/migrations/154-drop-fts.ts +20 -0
  266. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  267. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  268. package/src/memory/migrations/index.ts +8 -0
  269. package/src/memory/qdrant-client.ts +148 -51
  270. package/src/memory/raw-query.ts +1 -1
  271. package/src/memory/retriever.test.ts +294 -273
  272. package/src/memory/retriever.ts +421 -645
  273. package/src/memory/schema/calls.ts +2 -0
  274. package/src/memory/schema/index.ts +1 -0
  275. package/src/memory/schema/memory-core.ts +3 -48
  276. package/src/memory/schema/oauth.ts +67 -0
  277. package/src/memory/search/formatting.ts +263 -176
  278. package/src/memory/search/lexical.ts +1 -254
  279. package/src/memory/search/ranking.ts +0 -455
  280. package/src/memory/search/semantic.ts +100 -14
  281. package/src/memory/search/staleness.ts +47 -0
  282. package/src/memory/search/tier-classifier.ts +21 -0
  283. package/src/memory/search/types.ts +15 -77
  284. package/src/memory/task-memory-cleanup.ts +4 -6
  285. package/src/messaging/provider.ts +4 -4
  286. package/src/messaging/providers/gmail/client.ts +82 -2
  287. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  288. package/src/messaging/providers/gmail/people-client.ts +10 -10
  289. package/src/messaging/providers/telegram-bot/adapter.ts +17 -17
  290. package/src/messaging/providers/whatsapp/adapter.ts +11 -8
  291. package/src/messaging/registry.ts +2 -32
  292. package/src/notifications/copy-composer.ts +0 -5
  293. package/src/notifications/signal.ts +4 -5
  294. package/src/oauth/byo-connection.test.ts +133 -25
  295. package/src/oauth/byo-connection.ts +22 -6
  296. package/src/oauth/connect-orchestrator.ts +113 -57
  297. package/src/oauth/connect-types.ts +17 -23
  298. package/src/oauth/connection-resolver.ts +35 -11
  299. package/src/oauth/connection.ts +1 -1
  300. package/src/oauth/manual-token-connection.ts +104 -0
  301. package/src/oauth/oauth-store.ts +582 -0
  302. package/src/oauth/platform-connection.test.ts +29 -0
  303. package/src/oauth/platform-connection.ts +6 -5
  304. package/src/oauth/provider-behaviors.ts +124 -0
  305. package/src/oauth/scope-policy.ts +9 -2
  306. package/src/oauth/seed-providers.ts +167 -0
  307. package/src/oauth/token-persistence.ts +81 -77
  308. package/src/permissions/checker.ts +3 -3
  309. package/src/permissions/defaults.ts +1 -1
  310. package/src/permissions/prompter.ts +10 -1
  311. package/src/permissions/trust-store.ts +36 -1
  312. package/src/playbooks/playbook-compiler.ts +1 -1
  313. package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
  314. package/src/prompts/system-prompt.ts +46 -42
  315. package/src/providers/anthropic/client.ts +59 -20
  316. package/src/providers/retry.ts +1 -27
  317. package/src/providers/types.ts +7 -1
  318. package/src/runtime/AGENTS.md +9 -0
  319. package/src/runtime/auth/route-policy.ts +6 -6
  320. package/src/runtime/channel-reply-delivery.ts +0 -40
  321. package/src/runtime/gateway-client.ts +0 -7
  322. package/src/runtime/guardian-reply-router.ts +24 -22
  323. package/src/runtime/http-server.ts +10 -8
  324. package/src/runtime/http-types.ts +2 -2
  325. package/src/runtime/invite-redemption-service.ts +19 -1
  326. package/src/runtime/invite-service.ts +25 -0
  327. package/src/runtime/middleware/twilio-validation.ts +1 -11
  328. package/src/runtime/pending-interactions.ts +14 -12
  329. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  330. package/src/runtime/routes/channel-delivery-routes.ts +0 -1
  331. package/src/runtime/routes/conversation-routes.ts +81 -19
  332. package/src/runtime/routes/events-routes.ts +21 -11
  333. package/src/runtime/routes/host-cu-routes.ts +97 -0
  334. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  335. package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
  336. package/src/runtime/routes/integrations/slack/share.ts +6 -7
  337. package/src/runtime/routes/log-export-routes.ts +126 -8
  338. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  339. package/src/runtime/routes/memory-item-routes.ts +503 -0
  340. package/src/runtime/routes/session-management-routes.ts +3 -3
  341. package/src/runtime/routes/settings-routes.ts +55 -48
  342. package/src/runtime/routes/surface-action-routes.ts +1 -1
  343. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  344. package/src/runtime/routes/watch-routes.ts +128 -0
  345. package/src/runtime/routes/workspace-routes.ts +2 -1
  346. package/src/schedule/integration-status.ts +10 -9
  347. package/src/security/credential-key.ts +0 -156
  348. package/src/security/keychain-broker-client.ts +22 -10
  349. package/src/security/oauth2.ts +1 -1
  350. package/src/security/secure-keys.ts +25 -3
  351. package/src/security/token-manager.ts +137 -64
  352. package/src/skills/catalog-install.ts +414 -0
  353. package/src/skills/include-graph.ts +32 -0
  354. package/src/skills/skillssh-registry.ts +503 -0
  355. package/src/telegram/bot-username.ts +2 -3
  356. package/src/tools/assets/search.ts +5 -1
  357. package/src/tools/browser/network-recorder.ts +1 -1
  358. package/src/tools/browser/network-recording-types.ts +1 -1
  359. package/src/tools/computer-use/definitions.ts +36 -11
  360. package/src/tools/computer-use/registry.ts +5 -6
  361. package/src/tools/credentials/broker.ts +1 -2
  362. package/src/tools/credentials/metadata-store.ts +17 -121
  363. package/src/tools/credentials/vault.ts +92 -167
  364. package/src/tools/memory/definitions.ts +4 -13
  365. package/src/tools/memory/handlers.test.ts +83 -103
  366. package/src/tools/memory/handlers.ts +50 -85
  367. package/src/tools/registry.ts +2 -7
  368. package/src/tools/schedule/create.ts +8 -1
  369. package/src/tools/schedule/update.ts +8 -1
  370. package/src/tools/skills/load.ts +85 -3
  371. package/src/tools/watch/watch-state.ts +0 -12
  372. package/src/util/logger.ts +7 -41
  373. package/src/util/platform.ts +9 -28
  374. package/src/watcher/providers/google-calendar.ts +2 -1
  375. package/src/__tests__/clarification-resolver.test.ts +0 -193
  376. package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
  377. package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
  378. package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
  379. package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
  380. package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
  381. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
  382. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  383. package/src/__tests__/conflict-policy.test.ts +0 -269
  384. package/src/__tests__/conflict-store.test.ts +0 -372
  385. package/src/__tests__/contradiction-checker.test.ts +0 -361
  386. package/src/__tests__/entity-extractor.test.ts +0 -211
  387. package/src/__tests__/entity-search.test.ts +0 -1117
  388. package/src/__tests__/profile-compiler.test.ts +0 -392
  389. package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
  390. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  391. package/src/__tests__/session-profile-injection.test.ts +0 -557
  392. package/src/cli/commands/dev.ts +0 -129
  393. package/src/cli/commands/map.ts +0 -391
  394. package/src/cli/commands/oauth.ts +0 -77
  395. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  396. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  397. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  398. package/src/daemon/computer-use-session.ts +0 -1026
  399. package/src/daemon/ride-shotgun-handler.ts +0 -569
  400. package/src/daemon/session-conflict-gate.ts +0 -167
  401. package/src/daemon/session-dynamic-profile.ts +0 -77
  402. package/src/memory/clarification-resolver.ts +0 -417
  403. package/src/memory/conflict-intent.ts +0 -205
  404. package/src/memory/conflict-policy.ts +0 -127
  405. package/src/memory/conflict-store.ts +0 -410
  406. package/src/memory/contradiction-checker.ts +0 -508
  407. package/src/memory/entity-extractor.ts +0 -535
  408. package/src/memory/format-recall.ts +0 -47
  409. package/src/memory/fts-reconciler.ts +0 -165
  410. package/src/memory/job-handlers/conflict.ts +0 -200
  411. package/src/memory/profile-compiler.ts +0 -195
  412. package/src/memory/recall-cache.ts +0 -117
  413. package/src/memory/search/entity.ts +0 -535
  414. package/src/memory/search/query-expansion.test.ts +0 -70
  415. package/src/memory/search/query-expansion.ts +0 -118
  416. package/src/oauth/provider-base-urls.ts +0 -21
  417. package/src/oauth/provider-profiles.ts +0 -192
  418. package/src/prompts/computer-use-prompt.ts +0 -98
  419. package/src/runtime/routes/computer-use-routes.ts +0 -641
  420. package/src/runtime/routes/mcp-routes.ts +0 -20
  421. package/src/runtime/telegram-streaming-delivery.test.ts +0 -729
  422. package/src/runtime/telegram-streaming-delivery.ts +0 -393
  423. package/src/tools/computer-use/request-computer-control.ts +0 -56
package/src/instrument.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { arch, platform, release } from "node:os";
1
+ import { arch, hostname, platform, release } from "node:os";
2
2
 
3
3
  import * as Sentry from "@sentry/node";
4
4
 
@@ -47,12 +47,14 @@ export function initSentry(): void {
47
47
  dist: COMMIT_SHA,
48
48
  environment: APP_VERSION === "0.0.0-dev" ? "development" : "production",
49
49
  sendDefaultPii: false,
50
+ serverName: hostname(),
50
51
  initialScope: {
51
52
  tags: {
52
53
  commit: COMMIT_SHA,
53
54
  os_platform: platform(),
54
55
  os_release: release(),
55
56
  os_arch: arch(),
57
+ server_name: hostname(),
56
58
  runtime: "bun",
57
59
  runtime_version:
58
60
  typeof Bun !== "undefined" ? Bun.version : process.version,
@@ -90,3 +92,61 @@ export function initSentry(): void {
90
92
  export async function closeSentry(): Promise<void> {
91
93
  await Sentry.close();
92
94
  }
95
+
96
+ // ── Dynamic session-scoped Sentry tags ──────────────────────────────
97
+ //
98
+ // These tags change per conversation turn and are set on the current
99
+ // Sentry scope before the agent loop runs. Any `Sentry.captureException`
100
+ // call within that async execution chain (e.g. inside agent/loop.ts)
101
+ // will inherit these tags, enabling filtering by conversation, session,
102
+ // user, or assistant in the Sentry dashboard.
103
+
104
+ /** Tag keys set by {@link setSentrySessionContext}. */
105
+ const SESSION_TAG_KEYS = [
106
+ "assistant_id",
107
+ "conversation_id",
108
+ "session_id",
109
+ "message_count",
110
+ "user_identifier",
111
+ ] as const;
112
+
113
+ export interface SentrySessionContext {
114
+ /** Internal assistant ID (daemon uses 'self'). */
115
+ assistantId: string;
116
+ /** Conversation/session identifier. */
117
+ conversationId: string;
118
+ /** Number of messages in the conversation at time of the turn. */
119
+ messageCount: number;
120
+ /** Stable per-user identifier (guardian principal ID or similar). */
121
+ userIdentifier?: string;
122
+ }
123
+
124
+ /**
125
+ * Set session-scoped tags on the current Sentry scope.
126
+ *
127
+ * Call at the start of each agent loop turn so that any exceptions
128
+ * captured within the turn include conversation/session context.
129
+ */
130
+ export function setSentrySessionContext(ctx: SentrySessionContext): void {
131
+ Sentry.setTag("assistant_id", ctx.assistantId);
132
+ Sentry.setTag("conversation_id", ctx.conversationId);
133
+ // session_id mirrors conversation_id — in this codebase they are the
134
+ // same value, but downstream Sentry users may search by either name.
135
+ Sentry.setTag("session_id", ctx.conversationId);
136
+ Sentry.setTag("message_count", String(ctx.messageCount));
137
+ if (ctx.userIdentifier) {
138
+ Sentry.setTag("user_identifier", ctx.userIdentifier);
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Clear session-scoped tags from the current Sentry scope.
144
+ *
145
+ * Call in the finally block after the agent loop completes so tags
146
+ * from one conversation do not leak into unrelated error captures.
147
+ */
148
+ export function clearSentrySessionContext(): void {
149
+ for (const key of SESSION_TAG_KEYS) {
150
+ Sentry.setTag(key, undefined);
151
+ }
152
+ }
package/src/logfire.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { getLogfireToken, isMonitoringEnabled } from "./config/env.js";
1
+ import { getLogfireToken } from "./config/env.js";
2
2
  import type {
3
3
  Message,
4
4
  Provider,
@@ -13,7 +13,7 @@ const log = getLogger("logfire");
13
13
 
14
14
  type LogfireModule = typeof import("@pydantic/logfire-node");
15
15
 
16
- const LOGFIRE_ENABLED: boolean = !!getLogfireToken() && isMonitoringEnabled();
16
+ let logfireEnabled: boolean = !!getLogfireToken();
17
17
 
18
18
  let logfireInstance: LogfireModule | null = null;
19
19
 
@@ -23,7 +23,7 @@ let logfireInstance: LogfireModule | null = null;
23
23
  * Non-fatal on failure (logs warning and continues).
24
24
  */
25
25
  export async function initLogfire(): Promise<void> {
26
- if (!LOGFIRE_ENABLED) return;
26
+ if (!logfireEnabled) return;
27
27
 
28
28
  try {
29
29
  const logfire = await import("@pydantic/logfire-node");
@@ -42,12 +42,23 @@ export async function initLogfire(): Promise<void> {
42
42
  }
43
43
  }
44
44
 
45
+ /**
46
+ * Disable Logfire after early initialization. Called when the user has opted
47
+ * out via the feature flag. Nulls out the instance so future wrapWithLogfire
48
+ * calls become no-ops.
49
+ */
50
+ export function disableLogfire(): void {
51
+ logfireEnabled = false;
52
+ logfireInstance = null;
53
+ log.info("Logfire disabled by feature flag");
54
+ }
55
+
45
56
  /**
46
57
  * Wraps a provider with Logfire tracing spans.
47
- * When LOGFIRE_ENABLED is false, returns the provider as-is (no wrapper allocated).
58
+ * When logfireEnabled is false, returns the provider as-is (no wrapper allocated).
48
59
  */
49
60
  export function wrapWithLogfire(provider: Provider): Provider {
50
- if (!LOGFIRE_ENABLED) return provider;
61
+ if (!logfireEnabled) return provider;
51
62
  return new LogfireProvider(provider);
52
63
  }
53
64
 
@@ -1,14 +1,9 @@
1
1
  import { getConfig } from "../config/loader.js";
2
2
  import { getLogger } from "../util/logger.js";
3
- import {
4
- listPendingConflictDetails,
5
- resolveConflict,
6
- } from "./conflict-store.js";
7
3
  import { rawGet } from "./db.js";
8
4
  import { getMemoryBackendStatus } from "./embedding-backend.js";
9
5
  import { enqueueBackfillJob, enqueueRebuildIndexJob } from "./indexer.js";
10
6
  import {
11
- enqueueCleanupResolvedConflictsJob,
12
7
  enqueueCleanupStaleSupersededItemsJob,
13
8
  getMemoryJobCounts,
14
9
  } from "./jobs-store.js";
@@ -28,94 +23,18 @@ export interface MemorySystemStatus {
28
23
  summaries: number;
29
24
  embeddings: number;
30
25
  };
31
- conflicts: {
32
- pending: number;
33
- resolved: number;
34
- oldestPendingAgeMs: number | null;
35
- };
36
26
  cleanup: {
37
- resolvedBacklog: number;
38
27
  supersededBacklog: number;
39
- resolvedCompleted24h: number;
40
28
  supersededCompleted24h: number;
41
29
  };
42
30
  jobs: Record<string, number>;
43
31
  }
44
32
 
45
- export interface MemoryConflictAndCleanupStats {
46
- conflicts: MemorySystemStatus["conflicts"];
47
- cleanup: MemorySystemStatus["cleanup"];
48
- }
49
-
50
- interface ConflictStatsRow {
51
- pending_count: number | null;
52
- resolved_count: number | null;
53
- oldest_pending_created_at: number | null;
54
- }
55
-
56
33
  interface CleanupStatsRow {
57
- resolved_backlog: number | null;
58
34
  superseded_backlog: number | null;
59
- resolved_completed_24h: number | null;
60
35
  superseded_completed_24h: number | null;
61
36
  }
62
37
 
63
- /** Lightweight query for conflict/cleanup metrics only — no table counts or job totals. */
64
- export function getMemoryConflictAndCleanupStats(): MemoryConflictAndCleanupStats {
65
- const conflictStats = rawGet<ConflictStatsRow>(`
66
- SELECT
67
- SUM(CASE WHEN status = 'pending_clarification' THEN 1 ELSE 0 END) AS pending_count,
68
- SUM(CASE WHEN status != 'pending_clarification' THEN 1 ELSE 0 END) AS resolved_count,
69
- MIN(CASE WHEN status = 'pending_clarification' THEN created_at END) AS oldest_pending_created_at
70
- FROM memory_item_conflicts
71
- `);
72
- const pending = conflictStats?.pending_count ?? 0;
73
- const oldestPendingCreatedAt =
74
- conflictStats?.oldest_pending_created_at ?? null;
75
- const oldestPendingAgeMs =
76
- oldestPendingCreatedAt == null
77
- ? null
78
- : Math.max(0, Date.now() - oldestPendingCreatedAt);
79
- const throughputWindowStartMs = Date.now() - 24 * 60 * 60 * 1000;
80
- const cleanupStats = rawGet<CleanupStatsRow>(
81
- `
82
- SELECT
83
- SUM(CASE
84
- WHEN type = 'cleanup_resolved_conflicts' AND status IN ('pending', 'running')
85
- THEN 1 ELSE 0 END
86
- ) AS resolved_backlog,
87
- SUM(CASE
88
- WHEN type = 'cleanup_stale_superseded_items' AND status IN ('pending', 'running')
89
- THEN 1 ELSE 0 END
90
- ) AS superseded_backlog,
91
- SUM(CASE
92
- WHEN type = 'cleanup_resolved_conflicts' AND status = 'completed' AND updated_at >= ?
93
- THEN 1 ELSE 0 END
94
- ) AS resolved_completed_24h,
95
- SUM(CASE
96
- WHEN type = 'cleanup_stale_superseded_items' AND status = 'completed' AND updated_at >= ?
97
- THEN 1 ELSE 0 END
98
- ) AS superseded_completed_24h
99
- FROM memory_jobs
100
- `,
101
- throughputWindowStartMs,
102
- throughputWindowStartMs,
103
- );
104
- return {
105
- conflicts: {
106
- pending,
107
- resolved: conflictStats?.resolved_count ?? 0,
108
- oldestPendingAgeMs,
109
- },
110
- cleanup: {
111
- resolvedBacklog: cleanupStats?.resolved_backlog ?? 0,
112
- supersededBacklog: cleanupStats?.superseded_backlog ?? 0,
113
- resolvedCompleted24h: cleanupStats?.resolved_completed_24h ?? 0,
114
- supersededCompleted24h: cleanupStats?.superseded_completed_24h ?? 0,
115
- },
116
- };
117
- }
118
-
119
38
  export function getMemorySystemStatus(): MemorySystemStatus {
120
39
  const config = getConfig();
121
40
  const backend = getMemoryBackendStatus(config);
@@ -125,36 +44,14 @@ export function getMemorySystemStatus(): MemorySystemStatus {
125
44
  summaries: countTable("memory_summaries"),
126
45
  embeddings: countTable("memory_embeddings"),
127
46
  };
128
- const conflictStats = rawGet<ConflictStatsRow>(`
129
- SELECT
130
- SUM(CASE WHEN status = 'pending_clarification' THEN 1 ELSE 0 END) AS pending_count,
131
- SUM(CASE WHEN status != 'pending_clarification' THEN 1 ELSE 0 END) AS resolved_count,
132
- MIN(CASE WHEN status = 'pending_clarification' THEN created_at END) AS oldest_pending_created_at
133
- FROM memory_item_conflicts
134
- `);
135
- const pending = conflictStats?.pending_count ?? 0;
136
- const oldestPendingCreatedAt =
137
- conflictStats?.oldest_pending_created_at ?? null;
138
- const oldestPendingAgeMs =
139
- oldestPendingCreatedAt == null
140
- ? null
141
- : Math.max(0, Date.now() - oldestPendingCreatedAt);
142
47
  const throughputWindowStartMs = Date.now() - 24 * 60 * 60 * 1000;
143
48
  const cleanupStats = rawGet<CleanupStatsRow>(
144
49
  `
145
50
  SELECT
146
- SUM(CASE
147
- WHEN type = 'cleanup_resolved_conflicts' AND status IN ('pending', 'running')
148
- THEN 1 ELSE 0 END
149
- ) AS resolved_backlog,
150
51
  SUM(CASE
151
52
  WHEN type = 'cleanup_stale_superseded_items' AND status IN ('pending', 'running')
152
53
  THEN 1 ELSE 0 END
153
54
  ) AS superseded_backlog,
154
- SUM(CASE
155
- WHEN type = 'cleanup_resolved_conflicts' AND status = 'completed' AND updated_at >= ?
156
- THEN 1 ELSE 0 END
157
- ) AS resolved_completed_24h,
158
55
  SUM(CASE
159
56
  WHEN type = 'cleanup_stale_superseded_items' AND status = 'completed' AND updated_at >= ?
160
57
  THEN 1 ELSE 0 END
@@ -162,7 +59,6 @@ export function getMemorySystemStatus(): MemorySystemStatus {
162
59
  FROM memory_jobs
163
60
  `,
164
61
  throughputWindowStartMs,
165
- throughputWindowStartMs,
166
62
  );
167
63
  return {
168
64
  enabled: backend.enabled,
@@ -171,15 +67,8 @@ export function getMemorySystemStatus(): MemorySystemStatus {
171
67
  provider: backend.provider,
172
68
  model: backend.model,
173
69
  counts,
174
- conflicts: {
175
- pending,
176
- resolved: conflictStats?.resolved_count ?? 0,
177
- oldestPendingAgeMs,
178
- },
179
70
  cleanup: {
180
- resolvedBacklog: cleanupStats?.resolved_backlog ?? 0,
181
71
  supersededBacklog: cleanupStats?.superseded_backlog ?? 0,
182
- resolvedCompleted24h: cleanupStats?.resolved_completed_24h ?? 0,
183
72
  supersededCompleted24h: cleanupStats?.superseded_completed_24h ?? 0,
184
73
  },
185
74
  jobs: getMemoryJobCounts(),
@@ -203,95 +92,17 @@ export function requestMemoryRebuildIndex(): string {
203
92
  }
204
93
 
205
94
  export function requestMemoryCleanup(retentionMs?: number): {
206
- resolvedConflictsJobId: string;
207
95
  staleSupersededItemsJobId: string;
208
96
  } {
209
- const resolvedConflictsJobId =
210
- enqueueCleanupResolvedConflictsJob(retentionMs);
211
97
  const staleSupersededItemsJobId =
212
98
  enqueueCleanupStaleSupersededItemsJob(retentionMs);
213
99
  log.info(
214
- { resolvedConflictsJobId, staleSupersededItemsJobId, retentionMs },
100
+ { staleSupersededItemsJobId, retentionMs },
215
101
  "Queued memory cleanup jobs",
216
102
  );
217
- return { resolvedConflictsJobId, staleSupersededItemsJobId };
103
+ return { staleSupersededItemsJobId };
218
104
  }
219
105
 
220
106
  export async function queryMemory(query: string, conversationId: string) {
221
107
  return queryMemoryForCli(query, conversationId, getConfig());
222
108
  }
223
-
224
- export interface DismissConflictsResult {
225
- dismissed: number;
226
- remaining: number;
227
- details: Array<{
228
- id: string;
229
- existingStatement: string;
230
- candidateStatement: string;
231
- }>;
232
- }
233
-
234
- /**
235
- * Dismiss pending memory conflicts. With `all: true`, dismisses every
236
- * pending conflict. Otherwise, dismisses only conflicts matching the
237
- * given `pattern` regex against either statement.
238
- */
239
- export function dismissPendingConflicts(options: {
240
- all?: boolean;
241
- pattern?: RegExp;
242
- scopeId?: string;
243
- }): DismissConflictsResult {
244
- const scopeId = options.scopeId ?? "default";
245
- const dismissed: DismissConflictsResult["details"] = [];
246
- const BATCH_SIZE = 1000;
247
-
248
- // Cursor-based pagination: track last seen (createdAt, id) to advance past
249
- // previously inspected rows. This ensures pattern mode scans all pending
250
- // conflicts even when non-matching rows outnumber the batch size.
251
- let cursor: { createdAt: number; id: string } | undefined;
252
- let batch = listPendingConflictDetails(scopeId, BATCH_SIZE);
253
- while (batch.length > 0) {
254
- for (const conflict of batch) {
255
- const matches =
256
- options.all ||
257
- (options.pattern &&
258
- (options.pattern.test(conflict.existingStatement) ||
259
- options.pattern.test(conflict.candidateStatement)));
260
- if (!matches) continue;
261
-
262
- resolveConflict(conflict.id, {
263
- status: "dismissed",
264
- resolutionNote: options.all
265
- ? "Bulk dismissed via CLI (dismiss-conflicts --all)."
266
- : `Dismissed via CLI (pattern: ${options.pattern?.source}).`,
267
- });
268
- dismissed.push({
269
- id: conflict.id,
270
- existingStatement: conflict.existingStatement,
271
- candidateStatement: conflict.candidateStatement,
272
- });
273
- }
274
- // No more rows to inspect
275
- if (batch.length < BATCH_SIZE) break;
276
- const lastRow = batch[batch.length - 1];
277
- cursor = { createdAt: lastRow.createdAt, id: lastRow.id };
278
- batch = listPendingConflictDetails(scopeId, BATCH_SIZE, cursor);
279
- }
280
-
281
- // Get true remaining count via SQL to avoid batch-size truncation
282
- const remaining =
283
- rawGet<{ c: number }>(
284
- `SELECT COUNT(*) AS c FROM memory_item_conflicts WHERE scope_id = ? AND status = 'pending_clarification'`,
285
- scopeId,
286
- )?.c ?? 0;
287
-
288
- log.info(
289
- { dismissed: dismissed.length, remaining, scopeId },
290
- "Dismissed pending conflicts",
291
- );
292
- return {
293
- dismissed: dismissed.length,
294
- remaining,
295
- details: dismissed,
296
- };
297
- }
@@ -17,6 +17,21 @@ import {
17
17
  canonicalGuardianRequests,
18
18
  } from "./schema.js";
19
19
 
20
+ // ---------------------------------------------------------------------------
21
+ // Expiry helpers
22
+ // ---------------------------------------------------------------------------
23
+
24
+ /**
25
+ * Returns true when a canonical request has passed its `expiresAt` deadline.
26
+ * Requests without an `expiresAt` are never considered expired by this check.
27
+ */
28
+ export function isRequestExpired(
29
+ request: Pick<CanonicalGuardianRequest, "expiresAt">,
30
+ ): boolean {
31
+ if (!request.expiresAt) return false;
32
+ return new Date(request.expiresAt).getTime() < Date.now();
33
+ }
34
+
20
35
  // ---------------------------------------------------------------------------
21
36
  // Types
22
37
  // ---------------------------------------------------------------------------
@@ -444,6 +459,27 @@ export function resolveCanonicalGuardianRequest(
444
459
  return getCanonicalGuardianRequest(id);
445
460
  }
446
461
 
462
+ /**
463
+ * Expire all pending canonical guardian requests in a single bulk update.
464
+ *
465
+ * Called at daemon startup to clean up requests that can never be completed
466
+ * because the in-memory pending-interactions Map (which holds session
467
+ * references needed by resolvers) was wiped on restart.
468
+ *
469
+ * Returns the number of requests transitioned from pending → expired.
470
+ */
471
+ export function expireAllPendingCanonicalRequests(): number {
472
+ const db = getDb();
473
+ const now = new Date().toISOString();
474
+
475
+ db.update(canonicalGuardianRequests)
476
+ .set({ status: "expired", updatedAt: now })
477
+ .where(eq(canonicalGuardianRequests.status, "pending"))
478
+ .run();
479
+
480
+ return rawChanges();
481
+ }
482
+
447
483
  // ---------------------------------------------------------------------------
448
484
  // Canonical Guardian Deliveries
449
485
  // ---------------------------------------------------------------------------
@@ -624,14 +660,14 @@ export function listPendingRequestsByConversationScope(
624
660
  const result: CanonicalGuardianRequest[] = [];
625
661
 
626
662
  for (const req of bySource) {
627
- if (!seen.has(req.id)) {
663
+ if (!seen.has(req.id) && !isRequestExpired(req)) {
628
664
  seen.add(req.id);
629
665
  result.push(req);
630
666
  }
631
667
  }
632
668
 
633
669
  for (const req of byDestination) {
634
- if (!seen.has(req.id)) {
670
+ if (!seen.has(req.id) && !isRequestExpired(req)) {
635
671
  seen.add(req.id);
636
672
  result.push(req);
637
673
  }
@@ -19,7 +19,6 @@ import {
19
19
  conversations,
20
20
  llmRequestLogs,
21
21
  memoryEmbeddings,
22
- memoryItemEntities,
23
22
  memoryItems,
24
23
  memoryItemSources,
25
24
  memorySegments,
@@ -503,19 +502,6 @@ export function clearAll(): { conversations: number; messages: number } {
503
502
  // triggers so that the subsequent base-table DELETEs don't also fail
504
503
  // (SQLite triggers are atomic with the triggering statement, so a
505
504
  // corrupted FTS table would roll back every base-table DELETE).
506
- let segmentFtsCorrupted = false;
507
- try {
508
- rawExec("DELETE FROM memory_segment_fts");
509
- } catch (err) {
510
- log.warn(
511
- { err },
512
- "clearAll: failed to clear memory_segment_fts — dropping triggers so base-table cleanup can proceed",
513
- );
514
- rawExec("DROP TRIGGER IF EXISTS memory_segments_ai");
515
- rawExec("DROP TRIGGER IF EXISTS memory_segments_ad");
516
- rawExec("DROP TRIGGER IF EXISTS memory_segments_au");
517
- segmentFtsCorrupted = true;
518
- }
519
505
  rawExec("DELETE FROM memory_item_sources");
520
506
  rawExec("DELETE FROM memory_segments");
521
507
  rawExec("DELETE FROM memory_items");
@@ -548,21 +534,6 @@ export function clearAll(): { conversations: number; messages: number } {
548
534
  // DELETEs have completed. Dropping the virtual table clears the corruption,
549
535
  // and recreating it + triggers means subsequent writes maintain FTS
550
536
  // consistency without requiring a daemon restart.
551
- if (segmentFtsCorrupted) {
552
- rawExec("DROP TABLE IF EXISTS memory_segment_fts");
553
- rawExec(
554
- `CREATE VIRTUAL TABLE IF NOT EXISTS memory_segment_fts USING fts5(segment_id UNINDEXED, text)`,
555
- );
556
- rawExec(
557
- `CREATE TRIGGER IF NOT EXISTS memory_segments_ai AFTER INSERT ON memory_segments BEGIN INSERT INTO memory_segment_fts(segment_id, text) VALUES (new.id, new.text); END`,
558
- );
559
- rawExec(
560
- `CREATE TRIGGER IF NOT EXISTS memory_segments_ad AFTER DELETE ON memory_segments BEGIN DELETE FROM memory_segment_fts WHERE segment_id = old.id; END`,
561
- );
562
- rawExec(
563
- `CREATE TRIGGER IF NOT EXISTS memory_segments_au AFTER UPDATE ON memory_segments BEGIN DELETE FROM memory_segment_fts WHERE segment_id = old.id; INSERT INTO memory_segment_fts(segment_id, text) VALUES (new.id, new.text); END`,
564
- );
565
- }
566
537
  if (messagesFtsCorrupted) {
567
538
  rawExec("DROP TABLE IF EXISTS messages_fts");
568
539
  rawExec(
@@ -787,10 +758,6 @@ export function deleteMessageById(messageId: string): DeletedMemoryIds {
787
758
  result.orphanedItemIds = orphanedIds;
788
759
 
789
760
  if (orphanedIds.length > 0) {
790
- // Delete memory_item_entities (no FK cascade on this table).
791
- tx.delete(memoryItemEntities)
792
- .where(inArray(memoryItemEntities.memoryItemId, orphanedIds))
793
- .run();
794
761
  // Delete embeddings referencing these items.
795
762
  tx.delete(memoryEmbeddings)
796
763
  .where(
@@ -117,6 +117,27 @@ export function getOrCreateConversation(conversationKey: string): {
117
117
  return { conversationId: existing.conversationId, created: false };
118
118
  }
119
119
 
120
+ // Check if the conversationKey itself is an existing conversation ID.
121
+ // This happens when the client loads a thread from the conversations list
122
+ // and uses the server's conversationId as its local sessionId / conversationKey.
123
+ const existingConversation = tx
124
+ .select({ id: conversations.id })
125
+ .from(conversations)
126
+ .where(eq(conversations.id, conversationKey))
127
+ .get();
128
+
129
+ if (existingConversation) {
130
+ tx.insert(conversationKeys)
131
+ .values({
132
+ id: uuid(),
133
+ conversationKey,
134
+ conversationId: existingConversation.id,
135
+ createdAt: Date.now(),
136
+ })
137
+ .run();
138
+ return { conversationId: existingConversation.id, created: false };
139
+ }
140
+
120
141
  const now = Date.now();
121
142
  const conversationId = uuid();
122
143
 
@@ -6,10 +6,24 @@ import { parseConversation, parseMessage } from "./conversation-crud.js";
6
6
  import { ensureDisplayOrderMigration } from "./conversation-display-order-migration.js";
7
7
  import { getDb, rawAll } from "./db.js";
8
8
  import { conversations, messages } from "./schema.js";
9
- import { buildFtsMatchQuery } from "./search/lexical.js";
10
9
 
11
10
  const log = getLogger("conversation-store");
12
11
 
12
+ /**
13
+ * Build an FTS5 MATCH query string from natural text by extracting tokens.
14
+ * Used for messages_fts full-text search over conversation content.
15
+ */
16
+ function buildFtsMatchQuery(text: string): string | null {
17
+ const tokens = text
18
+ .toLowerCase()
19
+ .split(/[^a-z0-9_]+/g)
20
+ .map((token) => token.trim())
21
+ .filter((token) => token.length >= 2);
22
+ if (tokens.length === 0) return null;
23
+ const unique = [...new Set(tokens)].slice(0, 24);
24
+ return unique.map((token) => `"${token.replace(/"/g, '""')}"`).join(" OR ");
25
+ }
26
+
13
27
  export function listConversations(
14
28
  limit?: number,
15
29
  includeBackground = false,
@@ -160,7 +174,9 @@ export function isLastUserMessageToolResult(conversationId: string): boolean {
160
174
  Array.isArray(parsed) &&
161
175
  parsed.length > 0 &&
162
176
  parsed.every(
163
- (block: Record<string, unknown>) => block.type === "tool_result",
177
+ (block: Record<string, unknown>) =>
178
+ block.type === "tool_result" ||
179
+ block.type === "web_search_tool_result",
164
180
  )
165
181
  ) {
166
182
  return true;
@@ -375,7 +391,10 @@ function buildExcerpt(rawContent: string, query: string): string {
375
391
  if (typeof block === "object" && block != null) {
376
392
  if (block.type === "text" && typeof block.text === "string") {
377
393
  parts.push(block.text);
378
- } else if (block.type === "tool_result") {
394
+ } else if (
395
+ block.type === "tool_result" ||
396
+ block.type === "web_search_tool_result"
397
+ ) {
379
398
  const inner = Array.isArray(block.content) ? block.content : [];
380
399
  for (const ib of inner) {
381
400
  if (ib?.type === "text" && typeof ib.text === "string")
@@ -28,6 +28,7 @@ import {
28
28
  createMediaAssetsTables,
29
29
  createMessagesFts,
30
30
  createNotificationTables,
31
+ createOAuthTables,
31
32
  createScopedApprovalGrantsTable,
32
33
  createSequenceTables,
33
34
  createTasksAndWorkItemsTables,
@@ -36,6 +37,7 @@ import {
36
37
  migrateBackfillContactInteractionStats,
37
38
  migrateBackfillGuardianPrincipalId,
38
39
  migrateBackfillUsageCacheAccounting,
40
+ migrateCallSessionInviteMetadata,
39
41
  migrateCallSessionMode,
40
42
  migrateCanonicalGuardianDeliveriesDestinationIndex,
41
43
  migrateCanonicalGuardianRequesterChatId,
@@ -48,7 +50,10 @@ import {
48
50
  migrateConversationsThreadTypeIndex,
49
51
  migrateDropAccountsTable,
50
52
  migrateDropAssistantIdColumns,
53
+ migrateDropConflicts,
54
+ migrateDropEntityTables,
51
55
  migrateDropLegacyMemberGuardianTables,
56
+ migrateDropMemorySegmentFts,
52
57
  migrateDropRemindersTable,
53
58
  migrateDropUsageCompositeIndexes,
54
59
  migrateFkCascadeRebuilds,
@@ -62,9 +67,12 @@ import {
62
67
  migrateGuardianVerificationPurpose,
63
68
  migrateGuardianVerificationSessions,
64
69
  migrateInviteCodeHashColumn,
70
+ migrateMemoryItemSupersession,
65
71
  migrateMessagesFtsBackfill,
66
72
  migrateNormalizePhoneIdentities,
67
73
  migrateNotificationDeliveryThreadDecision,
74
+ migrateOAuthAppsClientSecretPath,
75
+ migrateOAuthProvidersPingUrl,
68
76
  migrateReminderRoutingIntent,
69
77
  migrateRemindersToSchedules,
70
78
  migrateRenameGuardianVerificationValues,
@@ -340,6 +348,30 @@ export function initializeDb(): void {
340
348
  // 52. Drop the legacy reminders table after data migration
341
349
  migrateDropRemindersTable(database);
342
350
 
351
+ // 53. OAuth provider/app/connection tables
352
+ createOAuthTables(database);
353
+
354
+ // 54. Add explicit client_secret_credential_path to oauth_apps
355
+ migrateOAuthAppsClientSecretPath(database);
356
+
357
+ // 55. Add ping_url column to oauth_providers
358
+ migrateOAuthProvidersPingUrl(database);
359
+
360
+ // 56. Add supersession tracking columns and override confidence to memory_items
361
+ migrateMemoryItemSupersession(database);
362
+
363
+ // 56b. Drop unused entity tables (entity search replaced by hybrid search on item statements)
364
+ migrateDropEntityTables(database);
365
+
366
+ // 57. Drop memory_segment_fts virtual table and triggers (replaced by Qdrant hybrid search)
367
+ migrateDropMemorySegmentFts(database);
368
+
369
+ // 58. Drop memory_item_conflicts table (conflict resolution system removed)
370
+ migrateDropConflicts(database);
371
+
372
+ // 59. Add invite metadata columns to call_sessions for outbound invite call routing
373
+ migrateCallSessionInviteMetadata(database);
374
+
343
375
  validateMigrationState(database);
344
376
 
345
377
  if (process.env.BUN_TEST === "1") {