@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
@@ -1,557 +0,0 @@
1
- import { beforeEach, describe, expect, mock, test } from "bun:test";
2
-
3
- import type { AgentEvent } from "../agent/loop.js";
4
- import type { ServerMessage } from "../daemon/message-protocol.js";
5
- import type { Message, ProviderResponse } from "../providers/types.js";
6
-
7
- let runCalls: Message[][] = [];
8
- let profileCompilerCalls = 0;
9
- let profileCompilerArgs: Array<Record<string, unknown>> = [];
10
- let recallArgs: Array<Record<string, unknown>> = [];
11
- let profileEnabled = true;
12
- let memoryEnabled = true;
13
- let profileText =
14
- "<dynamic-user-profile>\n- timezone: America/Los_Angeles\n</dynamic-user-profile>";
15
-
16
- const persistedMessages: Array<{
17
- id: string;
18
- role: string;
19
- content: string;
20
- createdAt: number;
21
- }> = [];
22
-
23
- mock.module("../util/logger.js", () => ({
24
- getLogger: () =>
25
- new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
26
- }));
27
-
28
- mock.module("../util/platform.js", () => ({
29
- getDataDir: () => "/tmp",
30
- }));
31
-
32
- mock.module("../memory/guardian-action-store.js", () => ({
33
- getPendingDeliveryByConversation: () => null,
34
- getGuardianActionRequest: () => null,
35
- resolveGuardianActionRequest: () => {},
36
- }));
37
-
38
- mock.module("../providers/registry.js", () => ({
39
- getProvider: () => ({ name: "mock-provider" }),
40
- initializeProviders: () => {},
41
- }));
42
-
43
- mock.module("../config/loader.js", () => ({
44
- getConfig: () => ({
45
- ui: {},
46
-
47
- provider: "mock-provider",
48
- maxTokens: 4096,
49
- thinking: false,
50
- contextWindow: {
51
- enabled: true,
52
- maxInputTokens: 100000,
53
- targetBudgetRatio: 0.30,
54
- compactThreshold: 0.8, summaryBudgetRatio: 0.05,
55
- overflowRecovery: {
56
- enabled: true,
57
- safetyMarginRatio: 0.05,
58
- maxAttempts: 3,
59
- interactiveLatestTurnCompression: "summarize",
60
- nonInteractiveLatestTurnCompression: "truncate",
61
- },
62
- },
63
- rateLimit: { maxRequestsPerMinute: 0, maxTokensPerSession: 0 },
64
- apiKeys: {},
65
- daemon: {
66
- startupSocketWaitMs: 5000,
67
- stopTimeoutMs: 5000,
68
- sigkillGracePeriodMs: 2000,
69
- titleGenerationMaxTokens: 30,
70
- standaloneRecording: true,
71
- },
72
- memory: {
73
- enabled: memoryEnabled,
74
- retrieval: {
75
- injectionStrategy: "prepend_user_block",
76
- dynamicBudget: {
77
- enabled: false,
78
- minInjectTokens: 1200,
79
- maxInjectTokens: 10000,
80
- targetHeadroomTokens: 10000,
81
- },
82
- },
83
- conflicts: {
84
- enabled: false,
85
- gateMode: "soft",
86
- resolverLlmTimeoutMs: 250,
87
- relevanceThreshold: 0.2,
88
- },
89
- profile: {
90
- enabled: profileEnabled,
91
- maxInjectTokens: 300,
92
- },
93
- },
94
- }),
95
- loadRawConfig: () => ({}),
96
- saveRawConfig: () => {},
97
- invalidateConfigCache: () => {},
98
- }));
99
-
100
- mock.module("../prompts/system-prompt.js", () => ({
101
- buildSystemPrompt: () => "system prompt",
102
- }));
103
-
104
- mock.module("../config/skills.js", () => ({
105
- loadSkillCatalog: () => [],
106
- loadSkillBySelector: () => ({ skill: null }),
107
- ensureSkillIcon: async () => null,
108
- }));
109
-
110
- mock.module("../config/skill-state.js", () => ({
111
- resolveSkillStates: () => [],
112
- }));
113
-
114
- mock.module("../skills/slash-commands.js", () => ({
115
- buildInvocableSlashCatalog: () => new Map(),
116
- resolveSlashSkillCommand: () => ({ kind: "not_slash" }),
117
- rewriteKnownSlashCommandPrompt: () => "",
118
- parseSlashCandidate: () => ({ kind: "not_slash" }),
119
- }));
120
-
121
- mock.module("../permissions/trust-store.js", () => ({
122
- addRule: () => {},
123
- findHighestPriorityRule: () => null,
124
- clearCache: () => {},
125
- }));
126
-
127
- mock.module("../security/secret-allowlist.js", () => ({
128
- resetAllowlist: () => {},
129
- }));
130
-
131
- mock.module("../memory/conversation-crud.js", () => ({
132
- getConversationThreadType: () => "default",
133
- setConversationOriginChannelIfUnset: () => {},
134
- provenanceFromTrustContext: () => ({
135
- source: "user",
136
- trustContext: undefined,
137
- }),
138
- getConversationOriginInterface: () => null,
139
- getConversationOriginChannel: () => null,
140
- getMessages: () => persistedMessages,
141
- getConversation: () => ({
142
- id: "conv-1",
143
- contextSummary: null,
144
- contextCompactedMessageCount: 0,
145
- contextCompactedAt: null,
146
- totalInputTokens: 0,
147
- totalOutputTokens: 0,
148
- totalEstimatedCost: 0,
149
- }),
150
- addMessage: (_conversationId: string, role: string, content: string) => {
151
- const row = {
152
- id: `msg-${persistedMessages.length + 1}`,
153
- role,
154
- content,
155
- createdAt: Date.now(),
156
- };
157
- persistedMessages.push(row);
158
- return { id: row.id };
159
- },
160
- updateConversationUsage: () => {},
161
- updateConversationTitle: () => {},
162
- updateConversationContextWindow: () => {},
163
- deleteMessageById: () => ({ segmentIds: [], orphanedItemIds: [] }),
164
- deleteLastExchange: () => 0,
165
- }));
166
-
167
- mock.module("../memory/conversation-queries.js", () => ({
168
- isLastUserMessageToolResult: () => false,
169
- }));
170
-
171
- mock.module("../memory/attachments-store.js", () => ({
172
- uploadAttachment: () => ({ id: "att-1" }),
173
- linkAttachmentToMessage: () => {},
174
- }));
175
-
176
- mock.module("../memory/retriever.js", () => ({
177
- buildMemoryRecall: async (
178
- _query: string,
179
- _convId: string,
180
- _config: unknown,
181
- options?: Record<string, unknown>,
182
- ) => {
183
- if (options) recallArgs.push(options);
184
- return {
185
- enabled: true,
186
- degraded: false,
187
- reason: null,
188
- provider: "mock",
189
- model: "mock",
190
- injectedText: "",
191
- lexicalHits: 0,
192
- semanticHits: 0,
193
- recencyHits: 0,
194
- entityHits: 0,
195
- relationSeedEntityCount: 0,
196
- relationTraversedEdgeCount: 0,
197
- relationNeighborEntityCount: 0,
198
- relationExpandedItemCount: 0,
199
- earlyTerminated: false,
200
- mergedCount: 0,
201
- selectedCount: 0,
202
- rerankApplied: false,
203
- injectedTokens: 0,
204
- latencyMs: 0,
205
- topCandidates: [],
206
- };
207
- },
208
- injectMemoryRecallIntoUserMessage: (msg: Message) => msg,
209
- injectMemoryRecallAsSeparateMessage: (msgs: Message[]) => msgs,
210
- stripMemoryRecallMessages: (msgs: Message[]) => msgs,
211
- }));
212
-
213
- mock.module("../context/window-manager.js", () => ({
214
- ContextWindowManager: class {
215
- constructor() {}
216
- shouldCompact() {
217
- return { needed: false, estimatedTokens: 0 };
218
- }
219
- async maybeCompact() {
220
- return { compacted: false };
221
- }
222
- },
223
- createContextSummaryMessage: () => ({
224
- role: "user",
225
- content: [{ type: "text", text: "summary" }],
226
- }),
227
- getSummaryFromContextMessage: () => null,
228
- }));
229
-
230
- mock.module("../memory/conflict-store.js", () => ({
231
- listPendingConflictDetails: () => [],
232
- applyConflictResolution: () => true,
233
- }));
234
-
235
- mock.module("../memory/clarification-resolver.js", () => ({
236
- resolveConflictClarification: async () => ({
237
- resolution: "still_unclear",
238
- strategy: "heuristic",
239
- resolvedStatement: null,
240
- explanation: "Need user clarification.",
241
- }),
242
- }));
243
-
244
- mock.module("../memory/admin.js", () => ({
245
- getMemoryConflictAndCleanupStats: () => ({
246
- conflicts: { pending: 0, resolved: 0, oldestPendingAgeMs: null },
247
- cleanup: {
248
- resolvedBacklog: 0,
249
- supersededBacklog: 0,
250
- resolvedCompleted24h: 0,
251
- supersededCompleted24h: 0,
252
- },
253
- }),
254
- }));
255
-
256
- mock.module("../memory/profile-compiler.js", () => ({
257
- compileDynamicProfile: (options?: Record<string, unknown>) => {
258
- profileCompilerCalls += 1;
259
- if (options) profileCompilerArgs.push(options);
260
- return {
261
- text: profileText,
262
- sourceCount: 2,
263
- selectedCount: 1,
264
- budgetTokens: 300,
265
- tokenEstimate: 28,
266
- };
267
- },
268
- }));
269
-
270
- mock.module("../memory/llm-usage-store.js", () => ({
271
- recordUsageEvent: () => ({ id: "usage-1", createdAt: Date.now() }),
272
- }));
273
-
274
- mock.module("../agent/loop.js", () => ({
275
- AgentLoop: class {
276
- constructor() {}
277
- async run(
278
- messages: Message[],
279
- onEvent: (event: AgentEvent) => void,
280
- ): Promise<Message[]> {
281
- runCalls.push(messages);
282
- const assistantMessage: Message = {
283
- role: "assistant",
284
- content: [{ type: "text", text: "normal assistant answer" }],
285
- };
286
- onEvent({
287
- type: "usage",
288
- inputTokens: 10,
289
- outputTokens: 5,
290
- model: "mock",
291
- providerDurationMs: 10,
292
- });
293
- onEvent({ type: "message_complete", message: assistantMessage });
294
- return [...messages, assistantMessage];
295
- }
296
- },
297
- }));
298
- mock.module("../memory/canonical-guardian-store.js", () => ({
299
- listPendingCanonicalGuardianRequestsByDestinationConversation: () => [],
300
- listCanonicalGuardianRequests: () => [],
301
- listPendingRequestsByConversationScope: () => [],
302
- createCanonicalGuardianRequest: () => ({
303
- id: "mock-cg-id",
304
- code: "MOCK",
305
- status: "pending",
306
- }),
307
- getCanonicalGuardianRequest: () => null,
308
- getCanonicalGuardianRequestByCode: () => null,
309
- updateCanonicalGuardianRequest: () => {},
310
- resolveCanonicalGuardianRequest: () => {},
311
- createCanonicalGuardianDelivery: () => ({ id: "mock-cgd-id" }),
312
- listCanonicalGuardianDeliveries: () => [],
313
- listPendingCanonicalGuardianRequestsByDestinationChat: () => [],
314
- updateCanonicalGuardianDelivery: () => {},
315
- generateCanonicalRequestCode: () => "MOCK-CODE",
316
- }));
317
-
318
- import type { SessionMemoryPolicy } from "../daemon/session.js";
319
- import { DEFAULT_MEMORY_POLICY, Session } from "../daemon/session.js";
320
- import {
321
- injectDynamicProfileIntoUserMessage,
322
- stripDynamicProfileMessages,
323
- } from "../daemon/session-dynamic-profile.js";
324
-
325
- function makeSession(memoryPolicy?: SessionMemoryPolicy): Session {
326
- const provider = {
327
- name: "mock",
328
- async sendMessage(): Promise<ProviderResponse> {
329
- return {
330
- content: [],
331
- model: "mock",
332
- usage: { inputTokens: 0, outputTokens: 0 },
333
- stopReason: "end_turn",
334
- };
335
- },
336
- };
337
- const session = new Session(
338
- "conv-1",
339
- provider,
340
- "system prompt",
341
- 4096,
342
- () => {},
343
- "/tmp",
344
- undefined,
345
- memoryPolicy,
346
- );
347
- session.setTrustContext({ trustClass: "guardian", sourceChannel: "vellum" });
348
- return session;
349
- }
350
-
351
- function messageText(message: Message): string {
352
- return message.content
353
- .filter((block) => block.type === "text")
354
- .map((block) => (block as { type: "text"; text: string }).text)
355
- .join("\n");
356
- }
357
-
358
- describe("Session dynamic profile injection", () => {
359
- beforeEach(() => {
360
- runCalls = [];
361
- persistedMessages.length = 0;
362
- profileCompilerCalls = 0;
363
- profileCompilerArgs = [];
364
- recallArgs = [];
365
- profileEnabled = true;
366
- memoryEnabled = true;
367
- profileText =
368
- "<dynamic-user-profile>\n- timezone: America/Los_Angeles\n</dynamic-user-profile>";
369
- });
370
-
371
- test("injects profile context for runtime and strips it from persisted history", async () => {
372
- const session = makeSession();
373
- await session.loadFromDb();
374
-
375
- const events: ServerMessage[] = [];
376
- await session.processMessage("What should I do next?", [], (event) =>
377
- events.push(event),
378
- );
379
-
380
- expect(runCalls).toHaveLength(1);
381
- const runtimeUser = runCalls[0][runCalls[0].length - 1];
382
- expect(runtimeUser.role).toBe("user");
383
- const runtimeText = messageText(runtimeUser);
384
- expect(runtimeText).toContain("<dynamic-profile-context>");
385
- expect(runtimeText).toContain("<dynamic-user-profile>");
386
- expect(runtimeText).toContain("</dynamic-profile-context>");
387
-
388
- const persistedUser = session
389
- .getMessages()
390
- .find((message) => message.role === "user");
391
- expect(persistedUser).toBeDefined();
392
- if (persistedUser) {
393
- const persistedText = messageText(persistedUser);
394
- expect(persistedText).not.toContain("<dynamic-profile-context>");
395
- expect(persistedText).not.toContain("<dynamic-user-profile>");
396
- expect(persistedText).not.toContain("</dynamic-profile-context>");
397
- // No empty text blocks should remain after stripping
398
- const emptyBlocks = persistedUser.content.filter(
399
- (b) => b.type === "text" && (b as { text: string }).text === "",
400
- );
401
- expect(emptyBlocks).toHaveLength(0);
402
- }
403
- expect(profileCompilerCalls).toBe(1);
404
- expect(events.some((event) => event.type === "message_complete")).toBe(
405
- true,
406
- );
407
- });
408
-
409
- test("strip removes empty text blocks left by dedicated injection block", () => {
410
- const profile = "timezone: US/Pacific";
411
- const userMsg: Message = {
412
- role: "user",
413
- content: [{ type: "text", text: "hello" }],
414
- };
415
- const injected = injectDynamicProfileIntoUserMessage(userMsg, profile);
416
- // The injected message has 2 content blocks: original + profile
417
- expect(injected.content).toHaveLength(2);
418
- const stripped = stripDynamicProfileMessages([injected], profile);
419
- // After stripping, the dedicated profile block should be removed entirely
420
- expect(stripped[0].content).toHaveLength(1);
421
- expect(
422
- stripped[0].content.every((b) => {
423
- return b.type !== "text" || (b as { text: string }).text.length > 0;
424
- }),
425
- ).toBe(true);
426
- });
427
-
428
- test("strip only targets the last user message, not earlier ones", () => {
429
- const profile = "timezone: US/Pacific";
430
- const profileMarker = "<dynamic-profile-context>";
431
- const earlyUser: Message = {
432
- role: "user",
433
- content: [
434
- {
435
- type: "text",
436
- text: `I pasted: ${profileMarker}\ntimezone: US/Pacific\n</dynamic-profile-context>`,
437
- },
438
- ],
439
- };
440
- const assistant: Message = {
441
- role: "assistant",
442
- content: [{ type: "text", text: "ok" }],
443
- };
444
- const latestUser: Message = {
445
- role: "user",
446
- content: [{ type: "text", text: "follow up" }],
447
- };
448
- const injected = injectDynamicProfileIntoUserMessage(latestUser, profile);
449
- const msgs = [earlyUser, assistant, injected];
450
- const stripped = stripDynamicProfileMessages(msgs, profile);
451
- // Earlier user message should be untouched
452
- expect(messageText(stripped[0])).toContain(profileMarker);
453
- // Latest user message should have profile removed
454
- expect(messageText(stripped[2])).not.toContain(profileMarker);
455
- });
456
-
457
- test("strip finds injected message even when tool_result user messages follow it", () => {
458
- const profile = "timezone: US/Pacific";
459
- const profileMarker = "<dynamic-profile-context>";
460
- const injectedUser = injectDynamicProfileIntoUserMessage(
461
- { role: "user", content: [{ type: "text", text: "hello" }] },
462
- profile,
463
- );
464
- const assistantMsg: Message = {
465
- role: "assistant",
466
- content: [{ type: "text", text: "calling tool" }],
467
- };
468
- // Simulate tool_result user message appended by agent loop
469
- const toolResultUser: Message = {
470
- role: "user",
471
- content: [
472
- { type: "tool_result", tool_use_id: "tu-1", content: "result" },
473
- ],
474
- };
475
- const msgs = [injectedUser, assistantMsg, toolResultUser];
476
- const stripped = stripDynamicProfileMessages(msgs, profile);
477
- // The injected profile should be stripped from the first user message
478
- expect(messageText(stripped[0])).not.toContain(profileMarker);
479
- // tool_result message should be untouched
480
- expect(stripped[2]).toBe(toolResultUser);
481
- });
482
-
483
- test("skips profile compilation/injection when memory.profile.enabled is false", async () => {
484
- profileEnabled = false;
485
- const session = makeSession();
486
- await session.loadFromDb();
487
-
488
- await session.processMessage("Explain rebase strategy", [], () => {});
489
-
490
- expect(runCalls).toHaveLength(1);
491
- const runtimeUser = runCalls[0][runCalls[0].length - 1];
492
- const runtimeText = messageText(runtimeUser);
493
- expect(runtimeText).not.toContain("<dynamic-profile-context>");
494
- expect(profileCompilerCalls).toBe(0);
495
- });
496
-
497
- test("skips profile injection when top-level memory.enabled is false", async () => {
498
- memoryEnabled = false;
499
- const session = makeSession();
500
- await session.loadFromDb();
501
-
502
- await session.processMessage("What is my timezone?", [], () => {});
503
-
504
- expect(runCalls).toHaveLength(1);
505
- const runtimeUser = runCalls[0][runCalls[0].length - 1];
506
- const runtimeText = messageText(runtimeUser);
507
- expect(runtimeText).not.toContain("<dynamic-profile-context>");
508
- expect(profileCompilerCalls).toBe(0);
509
- });
510
-
511
- test("private thread session uses private scope + default fallback in profile compile and recall", async () => {
512
- const privatePolicy: SessionMemoryPolicy = {
513
- scopeId: "private-thread-abc",
514
- includeDefaultFallback: true,
515
- strictSideEffects: false,
516
- };
517
- const session = makeSession(privatePolicy);
518
- await session.loadFromDb();
519
-
520
- await session.processMessage("What do I prefer?", [], () => {});
521
-
522
- // Profile compiler should receive the private scope with fallback enabled
523
- expect(profileCompilerCalls).toBe(1);
524
- expect(profileCompilerArgs).toHaveLength(1);
525
- expect(profileCompilerArgs[0].scopeId).toBe("private-thread-abc");
526
- expect(profileCompilerArgs[0].includeDefaultFallback).toBe(true);
527
-
528
- // Memory recall should receive scopeId and a scopePolicyOverride for the private scope
529
- expect(recallArgs).toHaveLength(1);
530
- expect(recallArgs[0].scopeId).toBe("private-thread-abc");
531
- expect(recallArgs[0].scopePolicyOverride).toEqual({
532
- scopeId: "private-thread-abc",
533
- fallbackToDefault: true,
534
- });
535
- });
536
-
537
- test("standard thread uses default scope without fallback in profile compile and no scope override in recall", async () => {
538
- // Default policy: scopeId='default', includeDefaultFallback=false
539
- const session = makeSession(DEFAULT_MEMORY_POLICY);
540
- await session.loadFromDb();
541
-
542
- await session.processMessage("Tell me about TypeScript", [], () => {});
543
-
544
- // Profile compiler should receive default scope without fallback
545
- expect(profileCompilerCalls).toBe(1);
546
- expect(profileCompilerArgs).toHaveLength(1);
547
- expect(profileCompilerArgs[0].scopeId).toBe("default");
548
- expect(profileCompilerArgs[0].includeDefaultFallback).toBe(false);
549
-
550
- // Memory recall should forward scopeId='default' so buildScopeFilter
551
- // properly filters to the default scope, and should NOT have a
552
- // scopePolicyOverride (default scope relies on the global config policy)
553
- expect(recallArgs).toHaveLength(1);
554
- expect(recallArgs[0].scopeId).toBe("default");
555
- expect(recallArgs[0].scopePolicyOverride).toBeUndefined();
556
- });
557
- });
@@ -1,129 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { join } from "node:path";
3
-
4
- import type { Command } from "commander";
5
-
6
- import { getDaemonStatus, stopDaemon } from "../../daemon/lifecycle.js";
7
- import { log } from "../logger.js";
8
-
9
- export function registerDevCommand(program: Command): void {
10
- program
11
- .command("dev")
12
- .description("Run the assistant in dev mode")
13
- .option(
14
- "--watch",
15
- "Auto-restart on source file changes (disruptive during Claude Code sessions)",
16
- )
17
- .addHelpText(
18
- "after",
19
- `
20
- Starts the assistant in foreground dev mode for local development. If an
21
- existing assistant is running, it is stopped first (waits up to 5 seconds
22
- for an unresponsive assistant before force-killing it).
23
-
24
- Behavioral notes:
25
- - Sets VELLUM_DEBUG=1 for DEBUG-level logging
26
- - Sets VELLUM_LOG_STDERR=1 so logs stream to stderr (visible in terminal)
27
- - Sets BASE_DATA_DIR to the repository root
28
- - The assistant runs in the foreground; press Ctrl+C to stop
29
-
30
- The --watch flag passes bun --watch to the child process, which
31
- auto-restarts the assistant whenever source files change. This is useful
32
- during development but disruptive if a Claude Code session is active,
33
- since the restart kills the running assistant mid-conversation.
34
-
35
- Examples:
36
- $ assistant dev
37
- $ assistant dev --watch`,
38
- )
39
- .action(async (opts: { watch?: boolean }) => {
40
- let status = await getDaemonStatus();
41
- if (status.running) {
42
- log.info("Stopping existing assistant...");
43
- const stopResult = await stopDaemon();
44
- if (!stopResult.stopped && stopResult.reason === "stop_failed") {
45
- log.error(
46
- "Failed to stop existing assistant — process survived SIGKILL",
47
- );
48
- process.exit(1);
49
- }
50
- } else if (status.pid) {
51
- // PID file references a live process but the socket is unresponsive.
52
- // This can happen during the daemon startup window before the socket
53
- // is bound. Wait briefly for it to come up before replacing.
54
- log.info(
55
- "Assistant process alive but socket unresponsive — waiting for startup...",
56
- );
57
- const maxWait = 5000;
58
- const interval = 500;
59
- let waited = 0;
60
- let resolved = false;
61
- while (waited < maxWait) {
62
- await new Promise((r) => setTimeout(r, interval));
63
- waited += interval;
64
- status = await getDaemonStatus();
65
- if (status.running) {
66
- // Socket came up — stop the daemon normally.
67
- log.info("Assistant became responsive, stopping it...");
68
- const stopResult = await stopDaemon();
69
- if (!stopResult.stopped && stopResult.reason === "stop_failed") {
70
- log.error(
71
- "Failed to stop existing assistant — process survived SIGKILL",
72
- );
73
- process.exit(1);
74
- }
75
- resolved = true;
76
- break;
77
- }
78
- if (!status.pid) {
79
- // Process exited on its own — PID file already cleaned up.
80
- resolved = true;
81
- break;
82
- }
83
- }
84
- if (!resolved) {
85
- // Still alive but unresponsive after waiting — stop it via stopDaemon()
86
- // which handles SIGTERM → SIGKILL escalation and PID file cleanup.
87
- log.info("Assistant still unresponsive after wait — stopping it...");
88
- const stopResult = await stopDaemon();
89
- if (!stopResult.stopped && stopResult.reason === "stop_failed") {
90
- log.error(
91
- "Failed to stop existing assistant — process survived SIGKILL",
92
- );
93
- process.exit(1);
94
- }
95
- }
96
- }
97
-
98
- const mainPath = `${import.meta.dirname}/../../daemon/main.ts`;
99
-
100
- const useWatch = opts.watch === true;
101
- log.info(
102
- `Starting assistant in dev mode${
103
- useWatch ? " with file watching" : ""
104
- } (Ctrl+C to stop)`,
105
- );
106
-
107
- const repoRoot = join(import.meta.dirname, "..", "..", "..", "..");
108
- const args = useWatch ? ["--watch", "run", mainPath] : ["run", mainPath];
109
- const child = spawn("bun", args, {
110
- stdio: "inherit",
111
- env: {
112
- ...process.env,
113
- BASE_DATA_DIR: repoRoot,
114
- VELLUM_LOG_STDERR: "1",
115
- VELLUM_DEBUG: "1",
116
- },
117
- });
118
-
119
- const forward = (signal: NodeJS.Signals) => {
120
- child.kill(signal);
121
- };
122
- process.on("SIGINT", () => forward("SIGINT"));
123
- process.on("SIGTERM", () => forward("SIGTERM"));
124
-
125
- child.on("exit", (code) => {
126
- process.exit(code ?? 0);
127
- });
128
- });
129
- }