@vellumai/assistant 0.4.49 → 0.4.51

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 (353) hide show
  1. package/ARCHITECTURE.md +24 -33
  2. package/README.md +3 -3
  3. package/docs/architecture/integrations.md +2 -2
  4. package/docs/architecture/keychain-broker.md +6 -6
  5. package/docs/architecture/memory.md +180 -119
  6. package/knip.json +32 -0
  7. package/package.json +3 -2
  8. package/src/__tests__/agent-loop.test.ts +3 -1
  9. package/src/__tests__/anthropic-provider.test.ts +114 -23
  10. package/src/__tests__/approval-cascade.test.ts +1 -15
  11. package/src/__tests__/approval-routes-http.test.ts +2 -0
  12. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  13. package/src/__tests__/btw-routes.test.ts +61 -5
  14. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  15. package/src/__tests__/checker.test.ts +13 -0
  16. package/src/__tests__/config-schema.test.ts +1 -68
  17. package/src/__tests__/config-watcher.test.ts +8 -0
  18. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  19. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  20. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  21. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  22. package/src/__tests__/credential-security-invariants.test.ts +8 -7
  23. package/src/__tests__/credential-vault-unit.test.ts +23 -18
  24. package/src/__tests__/credential-vault.test.ts +30 -18
  25. package/src/__tests__/credentials-cli.test.ts +257 -82
  26. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  27. package/src/__tests__/date-context.test.ts +93 -77
  28. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  29. package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
  30. package/src/__tests__/history-repair.test.ts +245 -0
  31. package/src/__tests__/host-cu-proxy.test.ts +165 -3
  32. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  33. package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
  34. package/src/__tests__/integration-status.test.ts +31 -30
  35. package/src/__tests__/invite-redemption-service.test.ts +166 -13
  36. package/src/__tests__/invite-routes-http.test.ts +166 -5
  37. package/src/__tests__/keychain-broker-client.test.ts +4 -4
  38. package/src/__tests__/list-messages-attachments.test.ts +193 -0
  39. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  40. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  41. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  42. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  43. package/src/__tests__/memory-regressions.test.ts +477 -2841
  44. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  45. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  46. package/src/__tests__/mime-builder.test.ts +28 -0
  47. package/src/__tests__/native-web-search.test.ts +1 -0
  48. package/src/__tests__/oauth-cli.test.ts +824 -31
  49. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  50. package/src/__tests__/oauth-store.test.ts +363 -17
  51. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  52. package/src/__tests__/registry.test.ts +0 -1
  53. package/src/__tests__/relay-server.test.ts +55 -1
  54. package/src/__tests__/schedule-tools.test.ts +32 -0
  55. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  56. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  57. package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
  58. package/src/__tests__/secure-keys.test.ts +78 -18
  59. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  60. package/src/__tests__/server-history-render.test.ts +2 -2
  61. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  62. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  63. package/src/__tests__/session-agent-loop.test.ts +19 -15
  64. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  65. package/src/__tests__/session-error.test.ts +124 -2
  66. package/src/__tests__/session-history-web-search.test.ts +918 -0
  67. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  68. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  69. package/src/__tests__/session-queue.test.ts +37 -27
  70. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  71. package/src/__tests__/session-slash-known.test.ts +1 -15
  72. package/src/__tests__/session-slash-queue.test.ts +1 -15
  73. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  74. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  75. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  76. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  77. package/src/__tests__/skills-install-extract.test.ts +93 -0
  78. package/src/__tests__/skills.test.ts +2 -2
  79. package/src/__tests__/skillssh-registry.test.ts +451 -0
  80. package/src/__tests__/slack-channel-config.test.ts +10 -8
  81. package/src/__tests__/trust-store.test.ts +15 -0
  82. package/src/__tests__/twilio-config.test.ts +11 -10
  83. package/src/__tests__/twilio-provider.test.ts +9 -4
  84. package/src/__tests__/voice-invite-redemption.test.ts +85 -5
  85. package/src/agent/ax-tree-compaction.test.ts +51 -0
  86. package/src/agent/loop.ts +39 -12
  87. package/src/approvals/AGENTS.md +1 -1
  88. package/src/approvals/guardian-request-resolvers.ts +14 -2
  89. package/src/bundler/compiler-tools.ts +66 -2
  90. package/src/calls/call-domain.ts +134 -3
  91. package/src/calls/call-store.ts +6 -0
  92. package/src/calls/relay-server.ts +44 -6
  93. package/src/calls/relay-setup-router.ts +17 -1
  94. package/src/calls/twilio-config.ts +5 -4
  95. package/src/calls/twilio-provider.ts +14 -9
  96. package/src/calls/twilio-rest.ts +10 -7
  97. package/src/calls/types.ts +3 -1
  98. package/src/cli/commands/config.ts +14 -9
  99. package/src/cli/commands/contacts.ts +3 -0
  100. package/src/cli/commands/credentials.ts +170 -174
  101. package/src/cli/commands/doctor.ts +11 -8
  102. package/src/cli/commands/keys.ts +9 -9
  103. package/src/cli/commands/mcp.ts +46 -59
  104. package/src/cli/commands/memory.ts +16 -165
  105. package/src/cli/commands/oauth/apps.ts +68 -10
  106. package/src/cli/commands/oauth/connections.ts +475 -105
  107. package/src/cli/commands/oauth/index.ts +3 -3
  108. package/src/cli/commands/oauth/providers.ts +18 -4
  109. package/src/cli/commands/sessions.ts +5 -2
  110. package/src/cli/commands/skills.ts +173 -1
  111. package/src/cli/http-client.ts +0 -20
  112. package/src/cli/main-screen.tsx +2 -2
  113. package/src/cli/program.ts +5 -6
  114. package/src/cli.ts +20 -22
  115. package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
  116. package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
  117. package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
  118. package/src/config/bundled-skills/contacts/SKILL.md +35 -11
  119. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  120. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  121. package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
  122. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
  123. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
  124. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
  125. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
  126. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
  127. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
  128. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
  129. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
  130. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
  131. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
  132. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
  133. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
  134. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
  135. package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
  136. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
  137. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
  138. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
  139. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
  140. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
  141. package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
  142. package/src/config/bundled-skills/messaging/SKILL.md +1 -1
  143. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  144. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  145. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
  146. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
  147. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
  148. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
  149. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
  150. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
  151. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
  152. package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
  153. package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
  154. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
  155. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
  156. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
  157. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
  158. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
  159. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
  160. package/src/config/bundled-tool-registry.ts +2 -5
  161. package/src/config/loader.ts +6 -42
  162. package/src/config/schema.ts +1 -12
  163. package/src/config/schemas/memory-lifecycle.ts +0 -9
  164. package/src/config/schemas/memory-processing.ts +0 -180
  165. package/src/config/schemas/memory-retrieval.ts +32 -104
  166. package/src/config/schemas/memory.ts +0 -10
  167. package/src/config/types.ts +0 -4
  168. package/src/contacts/contact-store.ts +39 -2
  169. package/src/contacts/contacts-write.ts +9 -0
  170. package/src/context/window-manager.ts +4 -1
  171. package/src/daemon/config-watcher.ts +55 -2
  172. package/src/daemon/daemon-control.ts +1 -1
  173. package/src/daemon/date-context.ts +114 -31
  174. package/src/daemon/handlers/config-ingress.ts +2 -2
  175. package/src/daemon/handlers/config-slack-channel.ts +59 -39
  176. package/src/daemon/handlers/config-telegram.ts +23 -14
  177. package/src/daemon/handlers/session-history.ts +1 -358
  178. package/src/daemon/handlers/sessions.ts +18 -13
  179. package/src/daemon/handlers/shared.ts +3 -17
  180. package/src/daemon/handlers/skills.ts +20 -1
  181. package/src/daemon/history-repair.ts +72 -8
  182. package/src/daemon/host-cu-proxy.ts +55 -26
  183. package/src/daemon/lifecycle.ts +39 -4
  184. package/src/daemon/mcp-reload-service.ts +2 -2
  185. package/src/daemon/message-types/computer-use.ts +1 -12
  186. package/src/daemon/message-types/memory.ts +4 -16
  187. package/src/daemon/message-types/messages.ts +1 -0
  188. package/src/daemon/message-types/sessions.ts +4 -42
  189. package/src/daemon/server.ts +6 -1
  190. package/src/daemon/session-agent-loop-handlers.ts +38 -0
  191. package/src/daemon/session-agent-loop.ts +334 -48
  192. package/src/daemon/session-error.ts +89 -6
  193. package/src/daemon/session-history.ts +17 -7
  194. package/src/daemon/session-media-retry.ts +6 -2
  195. package/src/daemon/session-memory.ts +69 -149
  196. package/src/daemon/session-process.ts +10 -1
  197. package/src/daemon/session-runtime-assembly.ts +49 -19
  198. package/src/daemon/session-slash.ts +3 -5
  199. package/src/daemon/session-surfaces.ts +4 -1
  200. package/src/daemon/session-tool-setup.ts +7 -1
  201. package/src/daemon/session.ts +12 -2
  202. package/src/email/providers/index.ts +2 -2
  203. package/src/instrument.ts +61 -1
  204. package/src/media/avatar-router.ts +1 -1
  205. package/src/memory/admin.ts +2 -191
  206. package/src/memory/canonical-guardian-store.ts +38 -2
  207. package/src/memory/conversation-crud.ts +0 -33
  208. package/src/memory/conversation-queries.ts +25 -83
  209. package/src/memory/db-init.ts +32 -0
  210. package/src/memory/embedding-backend.ts +84 -8
  211. package/src/memory/embedding-types.ts +9 -1
  212. package/src/memory/indexer.ts +7 -46
  213. package/src/memory/invite-store.ts +19 -0
  214. package/src/memory/items-extractor.ts +274 -76
  215. package/src/memory/job-handlers/backfill.ts +2 -127
  216. package/src/memory/job-handlers/cleanup.ts +2 -16
  217. package/src/memory/job-handlers/extraction.ts +2 -138
  218. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  219. package/src/memory/job-handlers/summarization.ts +3 -148
  220. package/src/memory/job-utils.ts +21 -59
  221. package/src/memory/jobs-store.ts +1 -159
  222. package/src/memory/jobs-worker.ts +9 -52
  223. package/src/memory/migrations/104-core-indexes.ts +3 -3
  224. package/src/memory/migrations/149-oauth-tables.ts +2 -0
  225. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  226. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  227. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  228. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  229. package/src/memory/migrations/154-drop-fts.ts +20 -0
  230. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  231. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  232. package/src/memory/migrations/157-invite-contact-id.ts +104 -0
  233. package/src/memory/migrations/index.ts +8 -0
  234. package/src/memory/migrations/registry.ts +6 -0
  235. package/src/memory/qdrant-client.ts +148 -51
  236. package/src/memory/raw-query.ts +1 -1
  237. package/src/memory/retriever.test.ts +294 -273
  238. package/src/memory/retriever.ts +421 -645
  239. package/src/memory/schema/calls.ts +2 -0
  240. package/src/memory/schema/contacts.ts +1 -0
  241. package/src/memory/schema/memory-core.ts +3 -48
  242. package/src/memory/schema/oauth.ts +2 -0
  243. package/src/memory/search/formatting.ts +263 -176
  244. package/src/memory/search/lexical.ts +1 -254
  245. package/src/memory/search/ranking.ts +0 -455
  246. package/src/memory/search/semantic.ts +100 -14
  247. package/src/memory/search/staleness.ts +47 -0
  248. package/src/memory/search/tier-classifier.ts +21 -0
  249. package/src/memory/search/types.ts +15 -77
  250. package/src/memory/task-memory-cleanup.ts +4 -6
  251. package/src/messaging/provider.ts +1 -1
  252. package/src/messaging/providers/gmail/adapter.ts +1 -1
  253. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  254. package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
  255. package/src/messaging/providers/whatsapp/adapter.ts +13 -9
  256. package/src/messaging/registry.ts +9 -5
  257. package/src/oauth/byo-connection.test.ts +40 -25
  258. package/src/oauth/connect-orchestrator.ts +4 -10
  259. package/src/oauth/connection-resolver.ts +20 -6
  260. package/src/oauth/manual-token-connection.ts +5 -5
  261. package/src/oauth/oauth-store.ts +183 -31
  262. package/src/oauth/platform-connection.test.ts +1 -1
  263. package/src/oauth/provider-behaviors.ts +503 -4
  264. package/src/oauth/seed-providers.ts +214 -8
  265. package/src/oauth/token-persistence.ts +31 -16
  266. package/src/permissions/defaults.ts +1 -0
  267. package/src/permissions/trust-store.ts +23 -1
  268. package/src/playbooks/playbook-compiler.ts +1 -1
  269. package/src/prompts/system-prompt.ts +18 -2
  270. package/src/providers/anthropic/client.ts +56 -126
  271. package/src/providers/types.ts +7 -1
  272. package/src/runtime/AGENTS.md +9 -0
  273. package/src/runtime/auth/route-policy.ts +6 -3
  274. package/src/runtime/channel-readiness-service.ts +48 -40
  275. package/src/runtime/guardian-reply-router.ts +24 -22
  276. package/src/runtime/http-server.ts +2 -2
  277. package/src/runtime/http-types.ts +2 -0
  278. package/src/runtime/invite-redemption-service.ts +72 -12
  279. package/src/runtime/invite-service.ts +43 -0
  280. package/src/runtime/middleware/twilio-validation.ts +1 -1
  281. package/src/runtime/pending-interactions.ts +2 -2
  282. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  283. package/src/runtime/routes/btw-routes.ts +10 -5
  284. package/src/runtime/routes/conversation-routes.ts +56 -11
  285. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  286. package/src/runtime/routes/integrations/slack/channel.ts +2 -2
  287. package/src/runtime/routes/integrations/telegram.ts +2 -2
  288. package/src/runtime/routes/integrations/twilio.ts +17 -17
  289. package/src/runtime/routes/invite-routes.ts +29 -4
  290. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  291. package/src/runtime/routes/memory-item-routes.ts +503 -0
  292. package/src/runtime/routes/secret-routes.ts +17 -0
  293. package/src/runtime/routes/session-management-routes.ts +3 -3
  294. package/src/runtime/routes/settings-routes.ts +3 -3
  295. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  296. package/src/runtime/routes/workspace-routes.ts +9 -4
  297. package/src/runtime/routes/workspace-utils.ts +8 -2
  298. package/src/schedule/integration-status.ts +26 -19
  299. package/src/security/keychain-broker-client.ts +17 -4
  300. package/src/security/oauth2.ts +6 -7
  301. package/src/security/secure-keys.ts +44 -19
  302. package/src/security/token-manager.ts +46 -39
  303. package/src/services/vercel-deploy.ts +0 -24
  304. package/src/signals/confirm.ts +78 -0
  305. package/src/signals/mcp-reload.ts +18 -0
  306. package/src/skills/catalog-install.ts +74 -18
  307. package/src/skills/skillssh-registry.ts +503 -0
  308. package/src/tools/assets/search.ts +5 -1
  309. package/src/tools/computer-use/definitions.ts +0 -10
  310. package/src/tools/computer-use/registry.ts +1 -1
  311. package/src/tools/credentials/vault.ts +22 -7
  312. package/src/tools/memory/definitions.ts +4 -13
  313. package/src/tools/memory/handlers.test.ts +83 -103
  314. package/src/tools/memory/handlers.ts +50 -85
  315. package/src/tools/network/script-proxy/session-manager.ts +8 -8
  316. package/src/tools/schedule/create.ts +10 -3
  317. package/src/tools/schedule/update.ts +8 -1
  318. package/src/tools/skills/load.ts +25 -2
  319. package/src/watcher/provider-types.ts +1 -1
  320. package/src/watcher/providers/github.ts +1 -1
  321. package/src/watcher/providers/gmail.ts +3 -3
  322. package/src/watcher/providers/google-calendar.ts +3 -3
  323. package/src/watcher/providers/linear.ts +1 -1
  324. package/src/__tests__/clarification-resolver.test.ts +0 -193
  325. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  326. package/src/__tests__/conflict-policy.test.ts +0 -269
  327. package/src/__tests__/conflict-store.test.ts +0 -372
  328. package/src/__tests__/contradiction-checker.test.ts +0 -361
  329. package/src/__tests__/entity-extractor.test.ts +0 -211
  330. package/src/__tests__/entity-search.test.ts +0 -1117
  331. package/src/__tests__/profile-compiler.test.ts +0 -392
  332. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  333. package/src/__tests__/session-profile-injection.test.ts +0 -557
  334. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  335. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  336. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  337. package/src/daemon/session-conflict-gate.ts +0 -167
  338. package/src/daemon/session-dynamic-profile.ts +0 -77
  339. package/src/memory/clarification-resolver.ts +0 -417
  340. package/src/memory/conflict-intent.ts +0 -205
  341. package/src/memory/conflict-policy.ts +0 -127
  342. package/src/memory/conflict-store.ts +0 -410
  343. package/src/memory/contradiction-checker.ts +0 -508
  344. package/src/memory/entity-extractor.ts +0 -535
  345. package/src/memory/format-recall.ts +0 -47
  346. package/src/memory/fts-reconciler.ts +0 -165
  347. package/src/memory/job-handlers/conflict.ts +0 -200
  348. package/src/memory/profile-compiler.ts +0 -195
  349. package/src/memory/recall-cache.ts +0 -117
  350. package/src/memory/search/entity.ts +0 -535
  351. package/src/memory/search/query-expansion.test.ts +0 -70
  352. package/src/memory/search/query-expansion.ts +0 -118
  353. package/src/runtime/routes/mcp-routes.ts +0 -20
@@ -9,6 +9,7 @@
9
9
 
10
10
  import { v4 as uuid } from "uuid";
11
11
 
12
+ import { escapeAxTreeContent } from "../agent/loop.js";
12
13
  import type { ContentBlock } from "../providers/types.js";
13
14
  import type { ToolExecutionResult } from "../tools/types.js";
14
15
  import { AssistantError, ErrorCode } from "../util/errors.js";
@@ -65,6 +66,7 @@ interface PendingRequest {
65
66
  export class HostCuProxy {
66
67
  private pending = new Map<string, PendingRequest>();
67
68
  private sendToClient: (msg: ServerMessage) => void;
69
+ private onInternalResolve?: (requestId: string) => void;
68
70
  private clientConnected = false;
69
71
 
70
72
  // CU state tracking (per-conversation)
@@ -76,9 +78,11 @@ export class HostCuProxy {
76
78
 
77
79
  constructor(
78
80
  sendToClient: (msg: ServerMessage) => void,
81
+ onInternalResolve?: (requestId: string) => void,
79
82
  maxSteps = MAX_STEPS,
80
83
  ) {
81
84
  this.sendToClient = sendToClient;
85
+ this.onInternalResolve = onInternalResolve;
82
86
  this._maxSteps = maxSteps;
83
87
  }
84
88
 
@@ -150,6 +154,7 @@ export class HostCuProxy {
150
154
  return new Promise<ToolExecutionResult>((resolve, reject) => {
151
155
  const timer = setTimeout(() => {
152
156
  this.pending.delete(requestId);
157
+ this.onInternalResolve?.(requestId);
153
158
  log.warn({ requestId, toolName }, "Host CU proxy request timed out");
154
159
  resolve({
155
160
  content: "Host CU proxy timed out waiting for client response",
@@ -164,6 +169,7 @@ export class HostCuProxy {
164
169
  if (this.pending.has(requestId)) {
165
170
  clearTimeout(timer);
166
171
  this.pending.delete(requestId);
172
+ this.onInternalResolve?.(requestId);
167
173
  resolve({ content: "Aborted", isError: true });
168
174
  }
169
175
  };
@@ -191,10 +197,13 @@ export class HostCuProxy {
191
197
  clearTimeout(entry.timer);
192
198
  this.pending.delete(requestId);
193
199
 
200
+ // Capture pre-update state so formatObservation sees the correct previous AX tree
201
+ const prevAXTree = this._previousAXTree;
202
+
194
203
  // Update CU state from observation
195
204
  this.updateStateFromObservation(observation);
196
205
 
197
- const result = this.formatObservation(observation);
206
+ const result = this.formatObservation(observation, prevAXTree);
198
207
  entry.resolve(result);
199
208
  }
200
209
 
@@ -202,6 +211,10 @@ export class HostCuProxy {
202
211
  return this.pending.has(requestId);
203
212
  }
204
213
 
214
+ isAvailable(): boolean {
215
+ return this.clientConnected;
216
+ }
217
+
205
218
  // ---------------------------------------------------------------------------
206
219
  // CU state management
207
220
  // ---------------------------------------------------------------------------
@@ -245,7 +258,11 @@ export class HostCuProxy {
245
258
  * (AX tree wrapped in markers, diff, warnings) and optional screenshot
246
259
  * as an image content block.
247
260
  */
248
- formatObservation(obs: CuObservationResult): ToolExecutionResult {
261
+ formatObservation(
262
+ obs: CuObservationResult,
263
+ previousAXTree?: string,
264
+ ): ToolExecutionResult {
265
+ const prevTree = previousAXTree;
249
266
  const parts: string[] = [];
250
267
 
251
268
  // Surface user guidance prominently so the model sees it first
@@ -263,21 +280,30 @@ export class HostCuProxy {
263
280
  if (obs.axDiff) {
264
281
  parts.push(obs.axDiff);
265
282
  parts.push("");
266
- } else if (this._previousAXTree != null && obs.axTree != null) {
267
- // No diff means the screen didn't change
268
- if (
269
- this._consecutiveUnchangedSteps >=
270
- CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD
271
- ) {
272
- parts.push(
273
- `WARNING: ${this._consecutiveUnchangedSteps} consecutive actions had NO VISIBLE EFFECT on the UI. You MUST try a completely different approach.`,
274
- );
275
- } else {
276
- parts.push(
277
- "Your last action had NO VISIBLE EFFECT on the UI. Try something different.",
278
- );
283
+ } else if (prevTree != null && obs.axTree != null) {
284
+ // Skip unchanged warning after wait actions — they intentionally yield no immediate change
285
+ const lastAction =
286
+ this._actionHistory.length > 0
287
+ ? this._actionHistory[this._actionHistory.length - 1]
288
+ : undefined;
289
+ const isWaitAction = lastAction?.toolName === "computer_use_wait";
290
+
291
+ if (!isWaitAction) {
292
+ // No diff means the screen didn't change
293
+ if (
294
+ this._consecutiveUnchangedSteps >=
295
+ CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD
296
+ ) {
297
+ parts.push(
298
+ `WARNING: ${this._consecutiveUnchangedSteps} consecutive actions had NO VISIBLE EFFECT on the UI. You MUST try a completely different approach.`,
299
+ );
300
+ } else {
301
+ parts.push(
302
+ "Your last action had NO VISIBLE EFFECT on the UI. Try something different.",
303
+ );
304
+ }
305
+ parts.push("");
279
306
  }
280
- parts.push("");
281
307
  }
282
308
 
283
309
  // Loop detection: identical actions repeated
@@ -300,10 +326,20 @@ export class HostCuProxy {
300
326
  if (obs.axTree) {
301
327
  parts.push("<ax-tree>");
302
328
  parts.push("CURRENT SCREEN STATE:");
303
- parts.push(HostCuProxy.escapeAxTreeContent(obs.axTree));
329
+ parts.push(escapeAxTreeContent(obs.axTree));
304
330
  parts.push("</ax-tree>");
305
331
  }
306
332
 
333
+ // Secondary windows for cross-app awareness
334
+ if (obs.secondaryWindows) {
335
+ parts.push("");
336
+ parts.push(obs.secondaryWindows);
337
+ parts.push("");
338
+ parts.push(
339
+ "Note: The element [ID]s above are from other windows — you can reference them for context but can only interact with the focused window's elements.",
340
+ );
341
+ }
342
+
307
343
  // Screenshot metadata
308
344
  const screenshotMeta = this.formatScreenshotMetadata(obs);
309
345
  if (screenshotMeta.length > 0) {
@@ -342,8 +378,9 @@ export class HostCuProxy {
342
378
  // ---------------------------------------------------------------------------
343
379
 
344
380
  dispose(): void {
345
- for (const [_requestId, entry] of this.pending) {
381
+ for (const [requestId, entry] of this.pending) {
346
382
  clearTimeout(entry.timer);
383
+ this.onInternalResolve?.(requestId);
347
384
  entry.reject(
348
385
  new AssistantError("Host CU proxy disposed", ErrorCode.INTERNAL_ERROR),
349
386
  );
@@ -390,12 +427,4 @@ export class HostCuProxy {
390
427
  }
391
428
  return lines;
392
429
  }
393
-
394
- /**
395
- * Escapes literal `</ax-tree>` inside AX tree content so compaction
396
- * regex does not stop prematurely.
397
- */
398
- static escapeAxTreeContent(content: string): string {
399
- return content.replace(/<\/ax-tree>/gi, "&lt;/ax-tree&gt;");
400
- }
401
430
  }
@@ -26,13 +26,18 @@ import { closeSentry, initSentry } from "../instrument.js";
26
26
  import { disableLogfire, initLogfire } from "../logfire.js";
27
27
  import { getMcpServerManager } from "../mcp/manager.js";
28
28
  import * as attachmentsStore from "../memory/attachments-store.js";
29
+ import { expireAllPendingCanonicalRequests } from "../memory/canonical-guardian-store.js";
29
30
  import {
30
31
  deleteMessageById,
31
32
  getConversationThreadType,
32
33
  getMessages,
33
34
  } from "../memory/conversation-crud.js";
34
35
  import { initializeDb } from "../memory/db.js";
35
- import { selectEmbeddingBackend } from "../memory/embedding-backend.js";
36
+ import {
37
+ selectEmbeddingBackend,
38
+ SPARSE_EMBEDDING_VERSION,
39
+ } from "../memory/embedding-backend.js";
40
+ import { enqueueMemoryJob } from "../memory/jobs-store.js";
36
41
  import { startMemoryJobsWorker } from "../memory/jobs-worker.js";
37
42
  import { initQdrantClient } from "../memory/qdrant-client.js";
38
43
  import { QdrantManager } from "../memory/qdrant-manager.js";
@@ -162,9 +167,28 @@ export async function runDaemon(): Promise<void> {
162
167
  // Backfill oauth_connection rows for manual-token providers (Telegram,
163
168
  // Slack channel) that already have keychain credentials from before the
164
169
  // oauth_connection migration. Safe to call on every startup.
165
- await backfillManualTokenConnections();
170
+ try {
171
+ await backfillManualTokenConnections();
172
+ } catch (err) {
173
+ log.warn(
174
+ { err },
175
+ "Manual-token connection backfill failed — continuing startup",
176
+ );
177
+ }
166
178
  log.info("Daemon startup: DB initialized");
167
179
 
180
+ // Expire any pending canonical guardian requests left over from before
181
+ // this process started. Their in-memory pending-interaction session
182
+ // references are gone, so they can never be completed. The agent loop
183
+ // will re-request tool approvals on the next turn.
184
+ const expiredCount = expireAllPendingCanonicalRequests();
185
+ if (expiredCount > 0) {
186
+ log.info(
187
+ { event: "startup_expired_stale_requests", expiredCount },
188
+ `Expired ${expiredCount} stale pending canonical request(s) from previous process`,
189
+ );
190
+ }
191
+
168
192
  // Ensure a vellum guardian binding exists and mint the CLI edge token
169
193
  // as an actor token bound to the guardian principal.
170
194
  let guardianPrincipalId: string | undefined;
@@ -305,9 +329,9 @@ export async function runDaemon(): Promise<void> {
305
329
  await qdrantManager.start();
306
330
  const embeddingSelection = selectEmbeddingBackend(config);
307
331
  const embeddingModel = embeddingSelection.backend
308
- ? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}`
332
+ ? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}:sparse-v${SPARSE_EMBEDDING_VERSION}`
309
333
  : undefined;
310
- initQdrantClient({
334
+ const qdrantClient = initQdrantClient({
311
335
  url: qdrantUrl,
312
336
  collection: config.memory.qdrant.collection,
313
337
  vectorSize: config.memory.qdrant.vectorSize,
@@ -315,6 +339,17 @@ export async function runDaemon(): Promise<void> {
315
339
  quantization: config.memory.qdrant.quantization,
316
340
  embeddingModel,
317
341
  });
342
+
343
+ // Eagerly ensure the collection exists so we detect migrations
344
+ // (unnamed→named vectors, dimension/model changes) at startup.
345
+ // If a destructive migration occurred, enqueue a rebuild_index job
346
+ // to re-embed all memory items from the SQLite cache.
347
+ const { migrated } = await qdrantClient.ensureCollection();
348
+ if (migrated) {
349
+ enqueueMemoryJob("rebuild_index", {});
350
+ log.info("Qdrant collection was migrated — enqueued rebuild_index job");
351
+ }
352
+
318
353
  log.info("Qdrant vector store initialized");
319
354
  } catch (err) {
320
355
  log.warn(
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Shared MCP reload business logic.
3
3
  *
4
- * Used by the HTTP route (`runtime/routes/mcp-routes.ts`) so the reload
5
- * behaviour is defined in exactly one place.
4
+ * Called by the ConfigWatcher when config.json changes or a reload signal
5
+ * file is detected, so the daemon automatically reconnects MCP servers.
6
6
  */
7
7
 
8
8
  import { getConfig, invalidateConfigCache } from "../config/loader.js";
@@ -1,4 +1,4 @@
1
- // Computer use, task routing, and watch observation types.
1
+ // Computer use and watch observation types.
2
2
 
3
3
  import type { CommandIntent, UserMessageAttachment } from "./shared.js";
4
4
 
@@ -89,16 +89,6 @@ export interface RecordingResume {
89
89
  recordingId: string;
90
90
  }
91
91
 
92
- export interface TaskRouted {
93
- type: "task_routed";
94
- sessionId: string;
95
- interactionType: "computer_use" | "text_qa";
96
- /** The task text passed to the escalated session. */
97
- task?: string;
98
- /** Set when a text_qa session escalates to computer_use. */
99
- escalatedFrom?: string;
100
- }
101
-
102
92
  export interface WatchStarted {
103
93
  type: "watch_started";
104
94
  sessionId: string;
@@ -121,7 +111,6 @@ export type _ComputerUseClientMessages =
121
111
  | RecordingStatus;
122
112
 
123
113
  export type _ComputerUseServerMessages =
124
- | TaskRouted
125
114
  | WatchStarted
126
115
  | WatchCompleteRequest
127
116
  | RecordingStart
@@ -11,7 +11,6 @@ export interface MemoryRecalledCandidateDebug {
11
11
  type: string;
12
12
  kind: string;
13
13
  finalScore: number;
14
- lexical: number;
15
14
  semantic: number;
16
15
  recency: number;
17
16
  }
@@ -21,18 +20,14 @@ export interface MemoryRecalled {
21
20
  provider: string;
22
21
  model: string;
23
22
  degradation?: MemoryRecalledDegradation;
24
- lexicalHits: number;
25
23
  semanticHits: number;
26
24
  recencyHits: number;
27
- entityHits: number;
28
- relationSeedEntityCount?: number;
29
- relationTraversedEdgeCount?: number;
30
- relationNeighborEntityCount?: number;
31
- relationExpandedItemCount?: number;
32
- earlyTerminated?: boolean;
25
+ tier1Count: number;
26
+ tier2Count: number;
27
+ hybridSearchLatencyMs: number;
28
+ sparseVectorUsed: boolean;
33
29
  mergedCount: number;
34
30
  selectedCount: number;
35
- rerankApplied: boolean;
36
31
  injectedTokens: number;
37
32
  latencyMs: number;
38
33
  topCandidates: MemoryRecalledCandidateDebug[];
@@ -46,13 +41,6 @@ export interface MemoryStatus {
46
41
  reason?: string;
47
42
  provider?: string;
48
43
  model?: string;
49
- conflictsPending: number;
50
- conflictsResolved: number;
51
- oldestPendingConflictAgeMs: number | null;
52
- cleanupResolvedJobsPending: number;
53
- cleanupSupersededJobsPending: number;
54
- cleanupResolvedJobsCompleted24h: number;
55
- cleanupSupersededJobsCompleted24h: number;
56
44
  }
57
45
 
58
46
  // --- Domain-level union aliases (consumed by the barrel file) ---
@@ -290,6 +290,7 @@ export interface AssistantActivityState {
290
290
  | "tool_result_received"
291
291
  | "confirmation_requested"
292
292
  | "confirmation_resolved"
293
+ | "context_compacting"
293
294
  | "message_complete"
294
295
  | "generation_cancelled"
295
296
  | "error_terminal";
@@ -85,35 +85,6 @@ export interface ImageGenModelSetRequest {
85
85
  model: string;
86
86
  }
87
87
 
88
- export interface HistoryRequest {
89
- type: "history_request";
90
- sessionId: string;
91
- /** Max messages to return. When omitted, all messages are returned (unlimited). */
92
- limit?: number;
93
- /** Pagination cursor: return messages with timestamp before this value. */
94
- beforeTimestamp?: number;
95
- /** Pagination cursor tie-breaker: exclude this message ID when beforeTimestamp matches. */
96
- beforeMessageId?: string;
97
- /** Include attachment base64 data. Defaults to false in light mode. */
98
- includeAttachments?: boolean;
99
- /** Include tool screenshot base64 data. Defaults to false in light mode. */
100
- includeToolImages?: boolean;
101
- /** Include surface HTML payloads. Defaults to false in light mode. */
102
- includeSurfaceData?: boolean;
103
- /** Shorthand: 'light' = all include flags false (default), 'full' = all include flags true. */
104
- mode?: "light" | "full";
105
- /** Truncate message text fields beyond this character limit. When omitted, full text is returned. */
106
- maxTextChars?: number;
107
- /** Truncate tool result strings beyond this character limit. When omitted, full results are returned. */
108
- maxToolResultChars?: number;
109
- }
110
-
111
- export interface MessageContentRequest {
112
- type: "message_content_request";
113
- sessionId: string;
114
- messageId: string;
115
- }
116
-
117
88
  export interface MessageContentResponse {
118
89
  type: "message_content_response";
119
90
  sessionId: string;
@@ -145,16 +116,6 @@ export interface SessionsClearRequest {
145
116
  type: "sessions_clear";
146
117
  }
147
118
 
148
- export interface ConversationSearchRequest {
149
- type: "conversation_search";
150
- /** The search query string. */
151
- query: string;
152
- /** Maximum number of conversations to return. Defaults to 20. */
153
- limit?: number;
154
- /** Maximum number of matching messages to return per conversation. Defaults to 3. */
155
- maxMessagesPerConversation?: number;
156
- }
157
-
158
119
  export interface ReorderThreadsRequest {
159
120
  type: "reorder_threads";
160
121
  updates: Array<{
@@ -394,6 +355,8 @@ export type SessionErrorCode =
394
355
  | "PROVIDER_RATE_LIMIT"
395
356
  | "PROVIDER_API"
396
357
  | "PROVIDER_BILLING"
358
+ | "PROVIDER_ORDERING"
359
+ | "PROVIDER_WEB_SEARCH"
397
360
  | "CONTEXT_TOO_LARGE"
398
361
  | "SESSION_ABORTED"
399
362
  | "SESSION_PROCESSING_FAILED"
@@ -407,6 +370,8 @@ export interface SessionErrorMessage {
407
370
  userMessage: string;
408
371
  retryable: boolean;
409
372
  debugDetails?: string;
373
+ /** Machine-readable error category for log report metadata and triage. */
374
+ errorCategory?: string;
410
375
  }
411
376
 
412
377
  /** Server push — broadcast when a schedule creates a conversation, so the client can show it as a chat thread. */
@@ -427,7 +392,6 @@ export type _SessionsClientMessages =
427
392
  | ModelGetRequest
428
393
  | ModelSetRequest
429
394
  | ImageGenModelSetRequest
430
- | HistoryRequest
431
395
  | UndoRequest
432
396
  | RegenerateRequest
433
397
  | UsageRequest
@@ -436,8 +400,6 @@ export type _SessionsClientMessages =
436
400
  | SessionSwitchRequest
437
401
  | SessionRenameRequest
438
402
  | SessionsClearRequest
439
- | ConversationSearchRequest
440
- | MessageContentRequest
441
403
  | ReorderThreadsRequest;
442
404
 
443
405
  export type _SessionsServerMessages =
@@ -663,8 +663,13 @@ export class DaemonServer {
663
663
  );
664
664
  }
665
665
  if (!session.isProcessing() || !session.hostCuProxy) {
666
- session.setHostCuProxy(new HostCuProxy(session.getCurrentSender()));
666
+ session.setHostCuProxy(
667
+ new HostCuProxy(session.getCurrentSender(), (requestId) => {
668
+ pendingInteractions.resolve(requestId);
669
+ }),
670
+ );
667
671
  }
672
+ session.addPreactivatedSkillId("computer-use");
668
673
  } else if (!session.isProcessing()) {
669
674
  session.setHostBashProxy(undefined);
670
675
  session.setHostFileProxy(undefined);
@@ -57,6 +57,8 @@ export interface EventHandlerState {
57
57
  orderingErrorDetected: boolean;
58
58
  deferredOrderingError: string | null;
59
59
  contextTooLargeDetected: boolean;
60
+ /** The raw error message from the provider when context_too_large is detected. */
61
+ contextTooLargeErrorMessage: string | null;
60
62
  providerErrorUserMessage: string | null;
61
63
  lastAssistantMessageId: string | undefined;
62
64
  readonly pendingToolResults: Map<string, PendingToolResult>;
@@ -121,6 +123,7 @@ export function createEventHandlerState(): EventHandlerState {
121
123
  orderingErrorDetected: false,
122
124
  deferredOrderingError: null,
123
125
  contextTooLargeDetected: false,
126
+ contextTooLargeErrorMessage: null,
124
127
  providerErrorUserMessage: null,
125
128
  lastAssistantMessageId: undefined,
126
129
  pendingToolResults: new Map(),
@@ -595,12 +598,22 @@ export function handleError(
595
598
  state.deferredOrderingError = event.error.message;
596
599
  } else if (isContextTooLarge(event.error.message)) {
597
600
  state.contextTooLargeDetected = true;
601
+ state.contextTooLargeErrorMessage = event.error.message;
598
602
  } else {
599
603
  const classified = classifySessionError(event.error, {
600
604
  phase: "agent_loop",
601
605
  });
602
606
  if (classified.code === "CONTEXT_TOO_LARGE") {
603
607
  state.contextTooLargeDetected = true;
608
+ state.contextTooLargeErrorMessage = event.error.message;
609
+ } else if (
610
+ classified.code === "PROVIDER_ORDERING" ||
611
+ classified.code === "PROVIDER_WEB_SEARCH"
612
+ ) {
613
+ // Ordering errors detected via classifySessionError (e.g. from ProviderError
614
+ // with statusCode 400 and ordering message) — trigger the retry path.
615
+ state.orderingErrorDetected = true;
616
+ state.deferredOrderingError = event.error.message;
604
617
  } else {
605
618
  deps.onEvent(
606
619
  buildSessionErrorMessage(deps.ctx.conversationId, classified),
@@ -831,6 +844,31 @@ export async function dispatchAgentEvent(
831
844
  deps.reqId,
832
845
  statusText,
833
846
  );
847
+ // Emit tool_use_start so the client renders a tool chip (like other tools)
848
+ deps.onEvent({
849
+ type: "tool_use_start",
850
+ toolName: event.name,
851
+ input: event.input,
852
+ sessionId: deps.ctx.conversationId,
853
+ toolUseId: event.toolUseId,
854
+ });
855
+ break;
856
+ }
857
+ case "server_tool_complete": {
858
+ deps.ctx.emitActivityState(
859
+ "streaming",
860
+ "tool_result_received",
861
+ "assistant_turn",
862
+ deps.reqId,
863
+ );
864
+ deps.onEvent({
865
+ type: "tool_result",
866
+ toolName: "",
867
+ result: "",
868
+ isError: false,
869
+ sessionId: deps.ctx.conversationId,
870
+ toolUseId: event.toolUseId,
871
+ });
834
872
  break;
835
873
  }
836
874
  case "error":