@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
@@ -0,0 +1,430 @@
1
+ /**
2
+ * Host computer-use proxy.
3
+ *
4
+ * Proxies computer-use actions to the desktop client when running as a
5
+ * managed assistant, following the same request/resolve pattern as
6
+ * HostBashProxy. Also owns CU-specific state tracking (step counting,
7
+ * loop detection, observation formatting) for the unified agent loop.
8
+ */
9
+
10
+ import { v4 as uuid } from "uuid";
11
+
12
+ import { escapeAxTreeContent } from "../agent/loop.js";
13
+ import type { ContentBlock } from "../providers/types.js";
14
+ import type { ToolExecutionResult } from "../tools/types.js";
15
+ import { AssistantError, ErrorCode } from "../util/errors.js";
16
+ import { getLogger } from "../util/logger.js";
17
+ import type { ServerMessage } from "./message-protocol.js";
18
+
19
+ const log = getLogger("host-cu-proxy");
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Constants
23
+ // ---------------------------------------------------------------------------
24
+
25
+ const REQUEST_TIMEOUT_SEC = 60;
26
+ const MAX_STEPS = 50;
27
+ const MAX_HISTORY_ENTRIES = 10;
28
+ const LOOP_DETECTION_WINDOW = 3;
29
+ const CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD = 2;
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Types
33
+ // ---------------------------------------------------------------------------
34
+
35
+ export interface CuObservationResult {
36
+ axTree?: string;
37
+ axDiff?: string;
38
+ secondaryWindows?: string;
39
+ screenshot?: string; // base64 JPEG
40
+ screenshotWidthPx?: number;
41
+ screenshotHeightPx?: number;
42
+ screenWidthPt?: number;
43
+ screenHeightPt?: number;
44
+ executionResult?: string;
45
+ executionError?: string;
46
+ userGuidance?: string;
47
+ }
48
+
49
+ export interface ActionRecord {
50
+ step: number;
51
+ toolName: string;
52
+ input: Record<string, unknown>;
53
+ reasoning?: string;
54
+ }
55
+
56
+ interface PendingRequest {
57
+ resolve: (result: ToolExecutionResult) => void;
58
+ reject: (err: Error) => void;
59
+ timer: ReturnType<typeof setTimeout>;
60
+ }
61
+
62
+ // ---------------------------------------------------------------------------
63
+ // HostCuProxy
64
+ // ---------------------------------------------------------------------------
65
+
66
+ export class HostCuProxy {
67
+ private pending = new Map<string, PendingRequest>();
68
+ private sendToClient: (msg: ServerMessage) => void;
69
+ private onInternalResolve?: (requestId: string) => void;
70
+ private clientConnected = false;
71
+
72
+ // CU state tracking (per-conversation)
73
+ private _stepCount = 0;
74
+ private _maxSteps: number;
75
+ private _previousAXTree: string | undefined;
76
+ private _consecutiveUnchangedSteps = 0;
77
+ private _actionHistory: ActionRecord[] = [];
78
+
79
+ constructor(
80
+ sendToClient: (msg: ServerMessage) => void,
81
+ onInternalResolve?: (requestId: string) => void,
82
+ maxSteps = MAX_STEPS,
83
+ ) {
84
+ this.sendToClient = sendToClient;
85
+ this.onInternalResolve = onInternalResolve;
86
+ this._maxSteps = maxSteps;
87
+ }
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // CU state accessors (for testing / external inspection)
91
+ // ---------------------------------------------------------------------------
92
+
93
+ get stepCount(): number {
94
+ return this._stepCount;
95
+ }
96
+
97
+ get maxSteps(): number {
98
+ return this._maxSteps;
99
+ }
100
+
101
+ get previousAXTree(): string | undefined {
102
+ return this._previousAXTree;
103
+ }
104
+
105
+ get consecutiveUnchangedSteps(): number {
106
+ return this._consecutiveUnchangedSteps;
107
+ }
108
+
109
+ get actionHistory(): readonly ActionRecord[] {
110
+ return this._actionHistory;
111
+ }
112
+
113
+ // ---------------------------------------------------------------------------
114
+ // Sender management
115
+ // ---------------------------------------------------------------------------
116
+
117
+ updateSender(
118
+ sendToClient: (msg: ServerMessage) => void,
119
+ clientConnected: boolean,
120
+ ): void {
121
+ this.sendToClient = sendToClient;
122
+ this.clientConnected = clientConnected;
123
+ }
124
+
125
+ // ---------------------------------------------------------------------------
126
+ // Request / resolve lifecycle
127
+ // ---------------------------------------------------------------------------
128
+
129
+ request(
130
+ toolName: string,
131
+ input: Record<string, unknown>,
132
+ sessionId: string,
133
+ stepNumber: number,
134
+ reasoning?: string,
135
+ signal?: AbortSignal,
136
+ ): Promise<ToolExecutionResult> {
137
+ if (signal?.aborted) {
138
+ return Promise.resolve({
139
+ content: "Aborted",
140
+ isError: true,
141
+ });
142
+ }
143
+
144
+ // Enforce step limit before sending to client
145
+ if (this._stepCount > this._maxSteps) {
146
+ return Promise.resolve({
147
+ content: `Step limit (${this._maxSteps}) exceeded. Call computer_use_done to finish.`,
148
+ isError: true,
149
+ });
150
+ }
151
+
152
+ const requestId = uuid();
153
+
154
+ return new Promise<ToolExecutionResult>((resolve, reject) => {
155
+ const timer = setTimeout(() => {
156
+ this.pending.delete(requestId);
157
+ this.onInternalResolve?.(requestId);
158
+ log.warn({ requestId, toolName }, "Host CU proxy request timed out");
159
+ resolve({
160
+ content: "Host CU proxy timed out waiting for client response",
161
+ isError: true,
162
+ });
163
+ }, REQUEST_TIMEOUT_SEC * 1000);
164
+
165
+ this.pending.set(requestId, { resolve, reject, timer });
166
+
167
+ if (signal) {
168
+ const onAbort = () => {
169
+ if (this.pending.has(requestId)) {
170
+ clearTimeout(timer);
171
+ this.pending.delete(requestId);
172
+ this.onInternalResolve?.(requestId);
173
+ resolve({ content: "Aborted", isError: true });
174
+ }
175
+ };
176
+ signal.addEventListener("abort", onAbort, { once: true });
177
+ }
178
+
179
+ this.sendToClient({
180
+ type: "host_cu_request",
181
+ requestId,
182
+ sessionId,
183
+ toolName,
184
+ input,
185
+ stepNumber,
186
+ reasoning,
187
+ } as ServerMessage);
188
+ });
189
+ }
190
+
191
+ resolve(requestId: string, observation: CuObservationResult): void {
192
+ const entry = this.pending.get(requestId);
193
+ if (!entry) {
194
+ log.warn({ requestId }, "No pending host CU request for response");
195
+ return;
196
+ }
197
+ clearTimeout(entry.timer);
198
+ this.pending.delete(requestId);
199
+
200
+ // Capture pre-update state so formatObservation sees the correct previous AX tree
201
+ const prevAXTree = this._previousAXTree;
202
+
203
+ // Update CU state from observation
204
+ this.updateStateFromObservation(observation);
205
+
206
+ const result = this.formatObservation(observation, prevAXTree);
207
+ entry.resolve(result);
208
+ }
209
+
210
+ hasPendingRequest(requestId: string): boolean {
211
+ return this.pending.has(requestId);
212
+ }
213
+
214
+ isAvailable(): boolean {
215
+ return this.clientConnected;
216
+ }
217
+
218
+ // ---------------------------------------------------------------------------
219
+ // CU state management
220
+ // ---------------------------------------------------------------------------
221
+
222
+ /**
223
+ * Increment step count and record an action. Call this before sending
224
+ * each non-terminal tool request.
225
+ */
226
+ recordAction(
227
+ toolName: string,
228
+ input: Record<string, unknown>,
229
+ reasoning?: string,
230
+ ): void {
231
+ this._stepCount++;
232
+ this._actionHistory.push({
233
+ step: this._stepCount,
234
+ toolName,
235
+ input,
236
+ reasoning,
237
+ });
238
+ // Keep history bounded
239
+ if (this._actionHistory.length > MAX_HISTORY_ENTRIES) {
240
+ this._actionHistory = this._actionHistory.slice(-MAX_HISTORY_ENTRIES);
241
+ }
242
+ }
243
+
244
+ /** Reset all CU state. Called on terminal tools (computer_use_done, etc.). */
245
+ reset(): void {
246
+ this._stepCount = 0;
247
+ this._previousAXTree = undefined;
248
+ this._consecutiveUnchangedSteps = 0;
249
+ this._actionHistory = [];
250
+ }
251
+
252
+ // ---------------------------------------------------------------------------
253
+ // Observation formatting
254
+ // ---------------------------------------------------------------------------
255
+
256
+ /**
257
+ * Formats a CU observation into a ToolExecutionResult with text content
258
+ * (AX tree wrapped in markers, diff, warnings) and optional screenshot
259
+ * as an image content block.
260
+ */
261
+ formatObservation(
262
+ obs: CuObservationResult,
263
+ previousAXTree?: string,
264
+ ): ToolExecutionResult {
265
+ const prevTree = previousAXTree;
266
+ const parts: string[] = [];
267
+
268
+ // Surface user guidance prominently so the model sees it first
269
+ if (obs.userGuidance) {
270
+ parts.push(`USER GUIDANCE: ${obs.userGuidance}`);
271
+ parts.push("");
272
+ }
273
+
274
+ if (obs.executionResult) {
275
+ parts.push(obs.executionResult);
276
+ parts.push("");
277
+ }
278
+
279
+ // AX tree diff / unchanged warning
280
+ if (obs.axDiff) {
281
+ parts.push(obs.axDiff);
282
+ parts.push("");
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("");
306
+ }
307
+ }
308
+
309
+ // Loop detection: identical actions repeated
310
+ if (this._actionHistory.length >= LOOP_DETECTION_WINDOW) {
311
+ const recent = this._actionHistory.slice(-LOOP_DETECTION_WINDOW);
312
+ const allIdentical = recent.every(
313
+ (r) =>
314
+ r.toolName === recent[0].toolName &&
315
+ JSON.stringify(r.input) === JSON.stringify(recent[0].input),
316
+ );
317
+ if (allIdentical) {
318
+ parts.push(
319
+ `WARNING: You've repeated the same action (${recent[0].toolName}) ${LOOP_DETECTION_WINDOW} times. Try something different.`,
320
+ );
321
+ parts.push("");
322
+ }
323
+ }
324
+
325
+ // Current screen state wrapped in markers for history compaction
326
+ if (obs.axTree) {
327
+ parts.push("<ax-tree>");
328
+ parts.push("CURRENT SCREEN STATE:");
329
+ parts.push(escapeAxTreeContent(obs.axTree));
330
+ parts.push("</ax-tree>");
331
+ }
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
+
343
+ // Screenshot metadata
344
+ const screenshotMeta = this.formatScreenshotMetadata(obs);
345
+ if (screenshotMeta.length > 0) {
346
+ parts.push("");
347
+ parts.push(...screenshotMeta);
348
+ }
349
+
350
+ const content = parts.join("\n").trim() || "Action executed";
351
+
352
+ // Build content blocks for screenshot
353
+ const contentBlocks: ContentBlock[] = [];
354
+ if (obs.screenshot) {
355
+ contentBlocks.push({
356
+ type: "image",
357
+ source: {
358
+ type: "base64",
359
+ media_type: "image/jpeg",
360
+ data: obs.screenshot,
361
+ },
362
+ });
363
+ }
364
+
365
+ const isError = obs.executionError != null;
366
+
367
+ return {
368
+ content: isError
369
+ ? `Action failed: ${obs.executionError}\n\n${content}`
370
+ : content,
371
+ isError,
372
+ ...(contentBlocks.length > 0 ? { contentBlocks } : {}),
373
+ };
374
+ }
375
+
376
+ // ---------------------------------------------------------------------------
377
+ // Dispose
378
+ // ---------------------------------------------------------------------------
379
+
380
+ dispose(): void {
381
+ for (const [requestId, entry] of this.pending) {
382
+ clearTimeout(entry.timer);
383
+ this.onInternalResolve?.(requestId);
384
+ entry.reject(
385
+ new AssistantError("Host CU proxy disposed", ErrorCode.INTERNAL_ERROR),
386
+ );
387
+ }
388
+ this.pending.clear();
389
+ }
390
+
391
+ // ---------------------------------------------------------------------------
392
+ // Private helpers
393
+ // ---------------------------------------------------------------------------
394
+
395
+ /** Update consecutive-unchanged tracking from an incoming observation. */
396
+ private updateStateFromObservation(obs: CuObservationResult): void {
397
+ if (this._stepCount > 0) {
398
+ if (
399
+ obs.axDiff == null &&
400
+ this._previousAXTree != null &&
401
+ obs.axTree != null
402
+ ) {
403
+ this._consecutiveUnchangedSteps++;
404
+ } else if (obs.axDiff != null) {
405
+ this._consecutiveUnchangedSteps = 0;
406
+ }
407
+ }
408
+
409
+ if (obs.axTree != null) {
410
+ this._previousAXTree = obs.axTree;
411
+ }
412
+ }
413
+
414
+ private formatScreenshotMetadata(obs: CuObservationResult): string[] {
415
+ if (!obs.screenshot) return [];
416
+
417
+ const lines: string[] = [];
418
+ if (obs.screenshotWidthPx != null && obs.screenshotHeightPx != null) {
419
+ lines.push(
420
+ `Screenshot metadata: ${obs.screenshotWidthPx}x${obs.screenshotHeightPx} px`,
421
+ );
422
+ }
423
+ if (obs.screenWidthPt != null && obs.screenHeightPt != null) {
424
+ lines.push(
425
+ `Screen metadata: ${obs.screenWidthPt}x${obs.screenHeightPt} pt`,
426
+ );
427
+ }
428
+ return lines;
429
+ }
430
+ }
@@ -15,6 +15,7 @@ import {
15
15
  getQdrantUrlEnv,
16
16
  getRuntimeHttpHost,
17
17
  getRuntimeHttpPort,
18
+ setIngressPublicBaseUrl,
18
19
  validateEnv,
19
20
  } from "../config/env.js";
20
21
  import { loadConfig } from "../config/loader.js";
@@ -22,16 +23,21 @@ import { HeartbeatService } from "../heartbeat/heartbeat-service.js";
22
23
  import { getHookManager } from "../hooks/manager.js";
23
24
  import { installTemplates } from "../hooks/templates.js";
24
25
  import { closeSentry, initSentry } from "../instrument.js";
25
- import { initLogfire } from "../logfire.js";
26
+ import { disableLogfire, initLogfire } from "../logfire.js";
26
27
  import { getMcpServerManager } from "../mcp/manager.js";
27
28
  import * as attachmentsStore from "../memory/attachments-store.js";
29
+ import { expireAllPendingCanonicalRequests } from "../memory/canonical-guardian-store.js";
28
30
  import {
29
31
  deleteMessageById,
30
32
  getConversationThreadType,
31
33
  getMessages,
32
34
  } from "../memory/conversation-crud.js";
33
35
  import { initializeDb } from "../memory/db.js";
34
- 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";
35
41
  import { startMemoryJobsWorker } from "../memory/jobs-worker.js";
36
42
  import { initQdrantClient } from "../memory/qdrant-client.js";
37
43
  import { QdrantManager } from "../memory/qdrant-manager.js";
@@ -40,6 +46,8 @@ import {
40
46
  emitNotificationSignal,
41
47
  registerBroadcastFn,
42
48
  } from "../notifications/emit-signal.js";
49
+ import { backfillManualTokenConnections } from "../oauth/manual-token-connection.js";
50
+ import { seedOAuthProviders } from "../oauth/seed-providers.js";
43
51
  import { ensurePromptFiles } from "../prompts/system-prompt.js";
44
52
  import { syncUpdateBulletinOnStartup } from "../prompts/update-bulletin.js";
45
53
  import { buildAssistantEvent } from "../runtime/assistant-event.js";
@@ -54,8 +62,6 @@ import {
54
62
  import { ensureVellumGuardianBinding } from "../runtime/guardian-vellum-migration.js";
55
63
  import { RuntimeHttpServer } from "../runtime/http-server.js";
56
64
  import { startScheduler } from "../schedule/scheduler.js";
57
- import { migrateKeys } from "../security/credential-key.js";
58
- import { watchSessions } from "../tools/watch/watch-state.js";
59
65
  import { getLogger, initLogger } from "../util/logger.js";
60
66
  import {
61
67
  ensureDataDir,
@@ -95,10 +101,6 @@ import {
95
101
  registerMessagingProviders,
96
102
  registerWatcherProviders,
97
103
  } from "./providers-setup.js";
98
- import {
99
- handleRideShotgunStart,
100
- handleRideShotgunStop,
101
- } from "./ride-shotgun-handler.js";
102
104
  import { seedInterfaceFiles } from "./seed-files.js";
103
105
  import { DaemonServer } from "./server.js";
104
106
  import { initSlashPairingContext } from "./session-slash.js";
@@ -137,11 +139,6 @@ export async function runDaemon(): Promise<void> {
137
139
 
138
140
  ensureDataDir();
139
141
 
140
- // Migrate legacy colon-delimited credential keys to the new
141
- // slash-delimited format. Must run after ensureDataDir() so the
142
- // secure key store is available, and before any credential reads.
143
- migrateKeys();
144
-
145
142
  // Load (or generate + persist) the auth signing key so tokens survive
146
143
  // daemon restarts. Must happen after ensureDataDir() creates the
147
144
  // protected directory.
@@ -165,8 +162,26 @@ export async function runDaemon(): Promise<void> {
165
162
  );
166
163
  }
167
164
  initializeDb();
165
+ // Seed well-known OAuth provider configurations (insert-if-not-exists)
166
+ seedOAuthProviders();
167
+ // Backfill oauth_connection rows for manual-token providers (Telegram,
168
+ // Slack channel) that already have keychain credentials from before the
169
+ // oauth_connection migration. Safe to call on every startup.
170
+ await backfillManualTokenConnections();
168
171
  log.info("Daemon startup: DB initialized");
169
172
 
173
+ // Expire any pending canonical guardian requests left over from before
174
+ // this process started. Their in-memory pending-interaction session
175
+ // references are gone, so they can never be completed. The agent loop
176
+ // will re-request tool approvals on the next turn.
177
+ const expiredCount = expireAllPendingCanonicalRequests();
178
+ if (expiredCount > 0) {
179
+ log.info(
180
+ { event: "startup_expired_stale_requests", expiredCount },
181
+ `Expired ${expiredCount} stale pending canonical request(s) from previous process`,
182
+ );
183
+ }
184
+
170
185
  // Ensure a vellum guardian binding exists and mint the CLI edge token
171
186
  // as an actor token bound to the guardian principal.
172
187
  let guardianPrincipalId: string | undefined;
@@ -242,6 +257,19 @@ export async function runDaemon(): Promise<void> {
242
257
  log.info("Daemon startup: loading config");
243
258
  const config = loadConfig();
244
259
 
260
+ // Seed module-level ingress state from the workspace config so that
261
+ // getIngressPublicBaseUrl() returns the correct value immediately after
262
+ // startup (before any handleIngressConfig("set") call). Without this,
263
+ // code paths that read the module-level state directly (e.g. session-slash
264
+ // pairing info) would see undefined until an explicit set.
265
+ if (config.ingress.enabled && config.ingress.publicBaseUrl) {
266
+ setIngressPublicBaseUrl(config.ingress.publicBaseUrl);
267
+ log.info(
268
+ { url: config.ingress.publicBaseUrl },
269
+ "Daemon startup: seeded ingress URL from workspace config",
270
+ );
271
+ }
272
+
245
273
  if (config.logFile.dir) {
246
274
  initLogger({
247
275
  dir: config.logFile.dir,
@@ -259,6 +287,18 @@ export async function runDaemon(): Promise<void> {
259
287
  await closeSentry();
260
288
  }
261
289
 
290
+ // If Logfire observability is not explicitly enabled, disable it so
291
+ // wrapWithLogfire() calls during provider setup become no-ops. Logfire
292
+ // is initialized eagerly (before config loads) for the same reason as
293
+ // Sentry — but the feature flag gates whether it actually traces.
294
+ const logfireEnabled = isAssistantFeatureFlagEnabled(
295
+ "feature_flags.logfire.enabled",
296
+ config,
297
+ );
298
+ if (!logfireEnabled) {
299
+ disableLogfire();
300
+ }
301
+
262
302
  await initializeProvidersAndTools(config);
263
303
 
264
304
  // Start the DaemonServer (session manager) before Qdrant so HTTP
@@ -282,9 +322,9 @@ export async function runDaemon(): Promise<void> {
282
322
  await qdrantManager.start();
283
323
  const embeddingSelection = selectEmbeddingBackend(config);
284
324
  const embeddingModel = embeddingSelection.backend
285
- ? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}`
325
+ ? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}:sparse-v${SPARSE_EMBEDDING_VERSION}`
286
326
  : undefined;
287
- initQdrantClient({
327
+ const qdrantClient = initQdrantClient({
288
328
  url: qdrantUrl,
289
329
  collection: config.memory.qdrant.collection,
290
330
  vectorSize: config.memory.qdrant.vectorSize,
@@ -292,6 +332,17 @@ export async function runDaemon(): Promise<void> {
292
332
  quantization: config.memory.qdrant.quantization,
293
333
  embeddingModel,
294
334
  });
335
+
336
+ // Eagerly ensure the collection exists so we detect migrations
337
+ // (unnamed→named vectors, dimension/model changes) at startup.
338
+ // If a destructive migration occurred, enqueue a rebuild_index job
339
+ // to re-embed all memory items from the SQLite cache.
340
+ const { migrated } = await qdrantClient.ensureCollection();
341
+ if (migrated) {
342
+ enqueueMemoryJob("rebuild_index", {});
343
+ log.info("Qdrant collection was migrated — enqueued rebuild_index job");
344
+ }
345
+
295
346
  log.info("Qdrant vector store initialized");
296
347
  } catch (err) {
297
348
  log.warn(
@@ -501,64 +552,9 @@ export async function runDaemon(): Promise<void> {
501
552
  );
502
553
  },
503
554
  },
504
- getComputerUseDeps: () => {
555
+ getWatchDeps: () => {
505
556
  const ctx = server.getHandlerContext();
506
557
  return {
507
- cuSessions: ctx.cuSessions,
508
- sharedRequestTimestamps: ctx.sharedRequestTimestamps,
509
- cuObservationParseSequence: ctx.cuObservationParseSequence,
510
- handleRideShotgunStart: async (params) => {
511
- // The handler generates its own watchId/sessionId and
512
- // sends them via ctx.send as a watch_started message.
513
- // We intercept send to capture the IDs before they broadcast.
514
- let capturedWatchId = "";
515
- let capturedSessionId = "";
516
- const interceptCtx = {
517
- ...ctx,
518
- send: (msg: ServerMessage) => {
519
- if (
520
- "type" in msg &&
521
- msg.type === "watch_started" &&
522
- "watchId" in msg &&
523
- "sessionId" in msg
524
- ) {
525
- capturedWatchId = (msg as { watchId: string }).watchId;
526
- capturedSessionId = (msg as { sessionId: string }).sessionId;
527
- }
528
- ctx.send(msg);
529
- },
530
- };
531
- await handleRideShotgunStart(
532
- {
533
- type: "ride_shotgun_start",
534
- durationSeconds: params.durationSeconds,
535
- intervalSeconds: params.intervalSeconds,
536
- mode: params.mode,
537
- targetDomain: params.targetDomain,
538
- navigateDomain: params.navigateDomain,
539
- autoNavigate: params.autoNavigate,
540
- },
541
- interceptCtx,
542
- );
543
- return { watchId: capturedWatchId, sessionId: capturedSessionId };
544
- },
545
- handleRideShotgunStop: async (watchId) => {
546
- await handleRideShotgunStop(
547
- { type: "ride_shotgun_stop", watchId },
548
- ctx,
549
- );
550
- },
551
- getRideShotgunStatus: (watchId) => {
552
- const session = watchSessions.get(watchId);
553
- if (!session) return undefined;
554
- return {
555
- status: session.status,
556
- sessionId: session.sessionId,
557
- recordingId: session.recordingId,
558
- savedRecordingPath: session.savedRecordingPath,
559
- bootstrapFailureReason: session.bootstrapFailureReason,
560
- };
561
- },
562
558
  handleWatchObservation: async (params) => {
563
559
  await handleWatchObservation(
564
560
  {
@@ -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";
@@ -21,6 +21,7 @@ export * from "./message-types/diagnostics.js";
21
21
  export * from "./message-types/documents.js";
22
22
  export * from "./message-types/guardian-actions.js";
23
23
  export * from "./message-types/host-bash.js";
24
+ export * from "./message-types/host-cu.js";
24
25
  export * from "./message-types/host-file.js";
25
26
  export * from "./message-types/inbox.js";
26
27
  export * from "./message-types/integrations.js";
@@ -69,6 +70,7 @@ import type {
69
70
  _GuardianActionsServerMessages,
70
71
  } from "./message-types/guardian-actions.js";
71
72
  import type { _HostBashServerMessages } from "./message-types/host-bash.js";
73
+ import type { _HostCuServerMessages } from "./message-types/host-cu.js";
72
74
  import type { _HostFileServerMessages } from "./message-types/host-file.js";
73
75
  import type {
74
76
  _InboxClientMessages,
@@ -180,6 +182,7 @@ export type ServerMessage =
180
182
  | _DocumentsServerMessages
181
183
  | _GuardianActionsServerMessages
182
184
  | _HostBashServerMessages
185
+ | _HostCuServerMessages
183
186
  | _HostFileServerMessages
184
187
  | _MemoryServerMessages
185
188
  | _WorkspaceServerMessages