@vellumai/assistant 0.3.5 → 0.3.6

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 (486) hide show
  1. package/README.md +51 -0
  2. package/eslint.config.mjs +31 -0
  3. package/package.json +1 -1
  4. package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
  5. package/scripts/ipc/generate-swift.ts +18 -2
  6. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +338 -1
  7. package/src/__tests__/approval-conversation-turn.test.ts +214 -0
  8. package/src/__tests__/browser-manager.test.ts +1 -0
  9. package/src/__tests__/call-conversation-messages.test.ts +130 -0
  10. package/src/__tests__/call-orchestrator.test.ts +752 -271
  11. package/src/__tests__/call-pointer-messages.test.ts +148 -0
  12. package/src/__tests__/call-recovery.test.ts +3 -0
  13. package/src/__tests__/call-routes-http.test.ts +5 -0
  14. package/src/__tests__/call-store.test.ts +3 -0
  15. package/src/__tests__/channel-approval-routes.test.ts +1260 -85
  16. package/src/__tests__/channel-approval.test.ts +37 -0
  17. package/src/__tests__/channel-approvals.test.ts +4 -65
  18. package/src/__tests__/channel-guardian.test.ts +556 -0
  19. package/src/__tests__/channel-readiness-service.test.ts +74 -7
  20. package/src/__tests__/checker.test.ts +14 -7
  21. package/src/__tests__/clarification-resolver.test.ts +44 -24
  22. package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
  23. package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
  24. package/src/__tests__/config-schema.test.ts +12 -7
  25. package/src/__tests__/context-window-manager.test.ts +30 -2
  26. package/src/__tests__/contradiction-checker.test.ts +20 -5
  27. package/src/__tests__/credential-security-invariants.test.ts +6 -2
  28. package/src/__tests__/db-migration-rollback.test.ts +752 -0
  29. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
  30. package/src/__tests__/fuzzy-match-property.test.ts +5 -5
  31. package/src/__tests__/guardian-action-store.test.ts +123 -0
  32. package/src/__tests__/guardian-action-sweep.test.ts +277 -0
  33. package/src/__tests__/guardian-dispatch.test.ts +389 -0
  34. package/src/__tests__/guardian-question-copy.test.ts +47 -0
  35. package/src/__tests__/handlers-telegram-config.test.ts +4 -2
  36. package/src/__tests__/handlers-twilio-config.test.ts +126 -0
  37. package/src/__tests__/intent-routing.test.ts +2 -0
  38. package/src/__tests__/ipc-snapshot.test.ts +228 -1
  39. package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
  40. package/src/__tests__/model-intents.test.ts +96 -0
  41. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
  42. package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
  43. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
  44. package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
  45. package/src/__tests__/provider-error-scenarios.test.ts +621 -0
  46. package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
  47. package/src/__tests__/qdrant-manager.test.ts +27 -20
  48. package/src/__tests__/relay-server.test.ts +779 -40
  49. package/src/__tests__/run-orchestrator-assistant-events.test.ts +2 -0
  50. package/src/__tests__/run-orchestrator.test.ts +20 -4
  51. package/src/__tests__/runtime-runs-http.test.ts +17 -1
  52. package/src/__tests__/runtime-runs.test.ts +16 -0
  53. package/src/__tests__/schedule-store.test.ts +18 -4
  54. package/src/__tests__/scheduler-recurrence.test.ts +13 -4
  55. package/src/__tests__/session-abort-tool-results.test.ts +6 -0
  56. package/src/__tests__/session-agent-loop.test.ts +857 -0
  57. package/src/__tests__/session-conflict-gate.test.ts +6 -0
  58. package/src/__tests__/session-pre-run-repair.test.ts +6 -0
  59. package/src/__tests__/session-profile-injection.test.ts +6 -0
  60. package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
  61. package/src/__tests__/session-queue.test.ts +6 -0
  62. package/src/__tests__/session-runtime-assembly.test.ts +237 -13
  63. package/src/__tests__/session-slash-known.test.ts +6 -0
  64. package/src/__tests__/session-slash-queue.test.ts +6 -0
  65. package/src/__tests__/session-slash-unknown.test.ts +6 -0
  66. package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
  67. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  68. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  69. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  70. package/src/__tests__/session-workspace-injection.test.ts +6 -0
  71. package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
  72. package/src/__tests__/skills.test.ts +2 -0
  73. package/src/__tests__/sms-messaging-provider.test.ts +2 -1
  74. package/src/__tests__/starter-task-flow.test.ts +2 -0
  75. package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
  76. package/src/__tests__/system-prompt.test.ts +2 -0
  77. package/src/__tests__/task-management-tools.test.ts +2 -2
  78. package/src/__tests__/task-runner.test.ts +14 -4
  79. package/src/__tests__/terminal-tools.test.ts +25 -19
  80. package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
  81. package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
  82. package/src/__tests__/tool-executor.test.ts +23 -24
  83. package/src/__tests__/trust-store.test.ts +3 -3
  84. package/src/__tests__/twilio-rest.test.ts +29 -0
  85. package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
  86. package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
  87. package/src/__tests__/twilio-routes.test.ts +141 -21
  88. package/src/__tests__/user-reference.test.ts +2 -0
  89. package/src/__tests__/voice-quality.test.ts +222 -0
  90. package/src/__tests__/web-search.test.ts +45 -29
  91. package/src/agent/loop.ts +1 -1
  92. package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
  93. package/src/amazon/client.ts +1418 -0
  94. package/src/amazon/request-extractor.ts +135 -0
  95. package/src/amazon/session.ts +109 -0
  96. package/src/autonomy/autonomy-store.ts +5 -5
  97. package/src/browser-extension-relay/client.ts +124 -0
  98. package/src/browser-extension-relay/protocol.ts +63 -0
  99. package/src/browser-extension-relay/server.ts +177 -0
  100. package/src/bundler/app-bundler.ts +3 -3
  101. package/src/bundler/bundle-signer.ts +1 -1
  102. package/src/bundler/signature-verifier.ts +1 -1
  103. package/src/calls/call-conversation-messages.ts +33 -0
  104. package/src/calls/call-domain.ts +106 -5
  105. package/src/calls/call-orchestrator.ts +252 -54
  106. package/src/calls/call-pointer-messages.ts +53 -0
  107. package/src/calls/call-recovery.ts +3 -8
  108. package/src/calls/call-store.ts +69 -87
  109. package/src/calls/elevenlabs-config.ts +3 -2
  110. package/src/calls/guardian-action-sweep.ts +105 -0
  111. package/src/calls/guardian-dispatch.ts +203 -0
  112. package/src/calls/guardian-question-copy.ts +133 -0
  113. package/src/calls/relay-server.ts +466 -8
  114. package/src/calls/speaker-identification.ts +1 -1
  115. package/src/calls/twilio-config.ts +7 -5
  116. package/src/calls/twilio-provider.ts +6 -4
  117. package/src/calls/twilio-rest.ts +40 -15
  118. package/src/calls/twilio-routes.ts +60 -45
  119. package/src/calls/types.ts +3 -1
  120. package/src/channels/types.ts +25 -0
  121. package/src/cli/amazon.ts +815 -0
  122. package/src/cli/config-commands.ts +2 -2
  123. package/src/cli/core-commands.ts +4 -3
  124. package/src/cli/influencer.ts +244 -0
  125. package/src/cli/map.ts +89 -6
  126. package/src/cli.ts +1 -1
  127. package/src/config/agent-schema.ts +171 -0
  128. package/src/config/bundled-skills/amazon/SKILL.md +127 -0
  129. package/src/config/bundled-skills/amazon/icon.svg +13 -0
  130. package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
  131. package/src/config/bundled-skills/browser/SKILL.md +1 -0
  132. package/src/config/bundled-skills/browser/TOOLS.json +17 -0
  133. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
  134. package/src/config/bundled-skills/doordash/SKILL.md +51 -51
  135. package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
  136. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
  137. package/src/config/bundled-skills/influencer/SKILL.md +144 -0
  138. package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
  139. package/src/config/bundled-skills/media-processing/SKILL.md +72 -95
  140. package/src/config/bundled-skills/media-processing/TOOLS.json +57 -147
  141. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
  142. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
  143. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
  144. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
  145. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
  146. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
  147. package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
  148. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +7 -9
  149. package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
  150. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +88 -253
  151. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +22 -153
  152. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  153. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +28 -51
  154. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +35 -270
  155. package/src/config/bundled-skills/messaging/SKILL.md +12 -2
  156. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
  157. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
  158. package/src/config/bundled-skills/phone-calls/SKILL.md +86 -21
  159. package/src/config/bundled-skills/twitter/icon.svg +14 -0
  160. package/src/config/bundled-tool-registry.ts +310 -0
  161. package/src/config/calls-schema.ts +181 -0
  162. package/src/config/core-schema.ts +309 -0
  163. package/src/config/defaults.ts +26 -2
  164. package/src/config/env-registry.ts +162 -0
  165. package/src/config/env.ts +175 -0
  166. package/src/config/loader.ts +6 -6
  167. package/src/config/memory-schema.ts +528 -0
  168. package/src/config/sandbox-schema.ts +55 -0
  169. package/src/config/schema.ts +156 -1137
  170. package/src/config/skill-state.ts +1 -1
  171. package/src/config/skills-schema.ts +32 -0
  172. package/src/config/skills.ts +35 -24
  173. package/src/config/system-prompt.ts +107 -56
  174. package/src/config/templates/SOUL.md +1 -1
  175. package/src/config/types.ts +1 -0
  176. package/src/config/user-reference.ts +4 -9
  177. package/src/config/vellum-skills/catalog.json +0 -7
  178. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
  179. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +1 -0
  180. package/src/config/vellum-skills/sms-setup/SKILL.md +112 -14
  181. package/src/context/window-manager.ts +27 -7
  182. package/src/daemon/approval-generators.ts +186 -0
  183. package/src/daemon/approved-devices-store.ts +140 -0
  184. package/src/daemon/assistant-attachments.ts +1 -1
  185. package/src/daemon/classifier.ts +35 -32
  186. package/src/daemon/config-watcher.ts +1 -1
  187. package/src/daemon/daemon-control.ts +217 -0
  188. package/src/daemon/handlers/apps.ts +2 -3
  189. package/src/daemon/handlers/config-channels.ts +158 -0
  190. package/src/daemon/handlers/config-inbox.ts +540 -0
  191. package/src/daemon/handlers/config-ingress.ts +231 -0
  192. package/src/daemon/handlers/config-integrations.ts +258 -0
  193. package/src/daemon/handlers/config-model.ts +143 -0
  194. package/src/daemon/handlers/config-parental.ts +163 -0
  195. package/src/daemon/handlers/config-scheduling.ts +172 -0
  196. package/src/daemon/handlers/config-slack.ts +92 -0
  197. package/src/daemon/handlers/config-telegram.ts +301 -0
  198. package/src/daemon/handlers/config-tools.ts +177 -0
  199. package/src/daemon/handlers/config-trust.ts +104 -0
  200. package/src/daemon/handlers/config-twilio.ts +1080 -0
  201. package/src/daemon/handlers/config.ts +53 -2463
  202. package/src/daemon/handlers/diagnostics.ts +1 -1
  203. package/src/daemon/handlers/dictation.ts +4 -6
  204. package/src/daemon/handlers/documents.ts +18 -32
  205. package/src/daemon/handlers/index.ts +9 -0
  206. package/src/daemon/handlers/misc.ts +3 -5
  207. package/src/daemon/handlers/pairing.ts +98 -0
  208. package/src/daemon/handlers/sessions.ts +54 -5
  209. package/src/daemon/handlers/shared.ts +3 -1
  210. package/src/daemon/handlers/skills.ts +1 -1
  211. package/src/daemon/handlers/twitter-auth.ts +2 -0
  212. package/src/daemon/handlers/work-items.ts +2 -2
  213. package/src/daemon/handlers/workspace-files.ts +4 -3
  214. package/src/daemon/install-cli-launchers.ts +113 -0
  215. package/src/daemon/ipc-contract/apps.ts +356 -0
  216. package/src/daemon/ipc-contract/browser.ts +74 -0
  217. package/src/daemon/ipc-contract/computer-use.ts +151 -0
  218. package/src/daemon/ipc-contract/diagnostics.ts +56 -0
  219. package/src/daemon/ipc-contract/documents.ts +74 -0
  220. package/src/daemon/ipc-contract/inbox.ts +209 -0
  221. package/src/daemon/ipc-contract/integrations.ts +284 -0
  222. package/src/daemon/ipc-contract/memory.ts +48 -0
  223. package/src/daemon/ipc-contract/messages.ts +211 -0
  224. package/src/daemon/ipc-contract/pairing.ts +45 -0
  225. package/src/daemon/ipc-contract/parental-control.ts +95 -0
  226. package/src/daemon/ipc-contract/schedules.ts +97 -0
  227. package/src/daemon/ipc-contract/sessions.ts +315 -0
  228. package/src/daemon/ipc-contract/shared.ts +42 -0
  229. package/src/daemon/ipc-contract/skills.ts +120 -0
  230. package/src/daemon/ipc-contract/subagents.ts +58 -0
  231. package/src/daemon/ipc-contract/surfaces.ts +250 -0
  232. package/src/daemon/ipc-contract/trust.ts +60 -0
  233. package/src/daemon/ipc-contract/work-items.ts +225 -0
  234. package/src/daemon/ipc-contract/workspace.ts +113 -0
  235. package/src/daemon/ipc-contract-inventory.json +60 -0
  236. package/src/daemon/ipc-contract-inventory.ts +55 -29
  237. package/src/daemon/ipc-contract.ts +226 -2527
  238. package/src/daemon/ipc-protocol.ts +1 -1
  239. package/src/daemon/ipc-validate.ts +7 -0
  240. package/src/daemon/lifecycle.ts +97 -379
  241. package/src/daemon/pairing-store.ts +177 -0
  242. package/src/daemon/providers-setup.ts +43 -0
  243. package/src/daemon/ride-shotgun-handler.ts +67 -2
  244. package/src/daemon/server.ts +60 -44
  245. package/src/daemon/session-agent-loop-handlers.ts +421 -0
  246. package/src/daemon/session-agent-loop.ts +113 -275
  247. package/src/daemon/session-dynamic-profile.ts +1 -1
  248. package/src/daemon/session-history.ts +1 -1
  249. package/src/daemon/session-media-retry.ts +1 -1
  250. package/src/daemon/session-messaging.ts +37 -2
  251. package/src/daemon/session-notifiers.ts +5 -25
  252. package/src/daemon/session-process.ts +99 -59
  253. package/src/daemon/session-queue-manager.ts +96 -4
  254. package/src/daemon/session-runtime-assembly.ts +149 -15
  255. package/src/daemon/session-surfaces.ts +19 -4
  256. package/src/daemon/session-tool-setup.ts +28 -30
  257. package/src/daemon/session-workspace.ts +1 -1
  258. package/src/daemon/session.ts +24 -1
  259. package/src/daemon/shutdown-handlers.ts +122 -0
  260. package/src/daemon/trace-emitter.ts +1 -1
  261. package/src/daemon/watch-handler.ts +36 -33
  262. package/src/doordash/cart-queries.ts +787 -0
  263. package/src/doordash/client.ts +144 -127
  264. package/src/doordash/order-queries.ts +85 -0
  265. package/src/doordash/queries.ts +10 -1308
  266. package/src/doordash/search-queries.ts +203 -0
  267. package/src/doordash/session.ts +3 -2
  268. package/src/doordash/store-queries.ts +246 -0
  269. package/src/doordash/types.ts +367 -0
  270. package/src/email/providers/agentmail.ts +2 -1
  271. package/src/email/providers/index.ts +3 -2
  272. package/src/email/service.ts +3 -2
  273. package/src/errors.ts +43 -0
  274. package/src/home-base/prebuilt/seed.ts +1 -1
  275. package/src/hooks/cli.ts +6 -5
  276. package/src/hooks/config.ts +6 -8
  277. package/src/hooks/discovery.ts +6 -5
  278. package/src/hooks/manager.ts +4 -3
  279. package/src/hooks/runner.ts +2 -2
  280. package/src/hooks/templates.ts +5 -5
  281. package/src/inbound/public-ingress-urls.ts +3 -1
  282. package/src/index.ts +4 -2
  283. package/src/influencer/client.ts +1104 -0
  284. package/src/instrument.ts +4 -3
  285. package/src/logfire.ts +4 -3
  286. package/src/memory/admin.ts +25 -35
  287. package/src/memory/attachments-store.ts +4 -7
  288. package/src/memory/channel-delivery-store.ts +30 -1
  289. package/src/memory/channel-guardian-store.ts +200 -1
  290. package/src/memory/clarification-resolver.ts +37 -33
  291. package/src/memory/conflict-store.ts +67 -61
  292. package/src/memory/contradiction-checker.ts +141 -117
  293. package/src/memory/conversation-store.ts +335 -51
  294. package/src/memory/db-connection.ts +27 -4
  295. package/src/memory/db-init.ts +121 -4
  296. package/src/memory/db.ts +14 -1
  297. package/src/memory/embedding-backend.ts +27 -5
  298. package/src/memory/embedding-ollama.ts +2 -1
  299. package/src/memory/entity-extractor.ts +38 -35
  300. package/src/memory/guardian-action-store.ts +430 -0
  301. package/src/memory/inbox-escalation-projection.ts +59 -0
  302. package/src/memory/inbox-thread-store.ts +218 -0
  303. package/src/memory/ingress-invite-store.ts +338 -0
  304. package/src/memory/ingress-member-store.ts +350 -0
  305. package/src/memory/items-extractor.ts +91 -97
  306. package/src/memory/job-handlers/index-maintenance.ts +3 -3
  307. package/src/memory/job-handlers/media-processing.ts +11 -42
  308. package/src/memory/job-handlers/summarization.ts +32 -26
  309. package/src/memory/job-utils.ts +3 -10
  310. package/src/memory/jobs-store.ts +6 -9
  311. package/src/memory/jobs-worker.ts +51 -36
  312. package/src/memory/migrations/001-job-deferrals.ts +45 -0
  313. package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
  314. package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
  315. package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
  316. package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
  317. package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
  318. package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
  319. package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
  320. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
  321. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
  322. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
  323. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
  324. package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
  325. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
  326. package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
  327. package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
  328. package/src/memory/migrations/017-memory-items-indexes.ts +10 -0
  329. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
  330. package/src/memory/migrations/index.ts +24 -0
  331. package/src/memory/migrations/registry.ts +79 -0
  332. package/src/memory/migrations/validate-migration-state.ts +69 -0
  333. package/src/memory/qdrant-manager.ts +49 -8
  334. package/src/memory/query-builder.ts +1 -1
  335. package/src/memory/raw-query.ts +119 -0
  336. package/src/memory/recall-cache.ts +4 -1
  337. package/src/memory/retriever.ts +160 -47
  338. package/src/memory/schema-migration.ts +25 -984
  339. package/src/memory/schema.ts +130 -7
  340. package/src/memory/search/entity.ts +10 -19
  341. package/src/memory/search/lexical.ts +81 -52
  342. package/src/memory/search/ranking.ts +21 -22
  343. package/src/memory/search/semantic.ts +157 -19
  344. package/src/memory/shared-app-links-store.ts +4 -5
  345. package/src/memory/validation.ts +19 -0
  346. package/src/messaging/draft-store.ts +5 -6
  347. package/src/messaging/providers/sms/adapter.ts +3 -6
  348. package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
  349. package/src/messaging/providers/whatsapp/adapter.ts +136 -0
  350. package/src/messaging/providers/whatsapp/client.ts +67 -0
  351. package/src/messaging/style-analyzer.ts +5 -4
  352. package/src/messaging/thread-summarizer.ts +61 -69
  353. package/src/messaging/triage-engine.ts +62 -71
  354. package/src/migrations/config-merge.ts +53 -0
  355. package/src/migrations/data-layout.ts +68 -0
  356. package/src/migrations/data-merge.ts +33 -0
  357. package/src/migrations/hooks-merge.ts +90 -0
  358. package/src/migrations/index.ts +6 -0
  359. package/src/migrations/log.ts +23 -0
  360. package/src/migrations/skills-merge.ts +33 -0
  361. package/src/migrations/workspace-layout.ts +79 -0
  362. package/src/permissions/checker.ts +119 -11
  363. package/src/permissions/prompter.ts +14 -0
  364. package/src/permissions/shell-identity.ts +31 -1
  365. package/src/permissions/trust-store.ts +21 -1
  366. package/src/providers/anthropic/client.ts +4 -4
  367. package/src/providers/failover.ts +2 -2
  368. package/src/providers/model-intents.ts +70 -0
  369. package/src/providers/ollama/client.ts +2 -1
  370. package/src/providers/provider-send-message.ts +176 -0
  371. package/src/providers/registry.ts +71 -30
  372. package/src/providers/retry.ts +35 -1
  373. package/src/providers/types.ts +12 -1
  374. package/src/runtime/approval-conversation-turn.ts +97 -0
  375. package/src/runtime/approval-message-composer.ts +115 -5
  376. package/src/runtime/channel-approval-parser.ts +36 -2
  377. package/src/runtime/channel-approvals.ts +0 -21
  378. package/src/runtime/channel-guardian-service.ts +48 -7
  379. package/src/runtime/channel-readiness-service.ts +160 -34
  380. package/src/runtime/channel-readiness-types.ts +10 -4
  381. package/src/runtime/channel-retry-sweep.ts +184 -0
  382. package/src/runtime/guardian-context-resolver.ts +108 -0
  383. package/src/runtime/http-server.ts +275 -743
  384. package/src/runtime/http-types.ts +56 -3
  385. package/src/runtime/middleware/auth.ts +116 -0
  386. package/src/runtime/middleware/error-handler.ts +33 -0
  387. package/src/runtime/middleware/twilio-validation.ts +127 -0
  388. package/src/runtime/routes/app-routes.ts +1 -1
  389. package/src/runtime/routes/call-routes.ts +49 -6
  390. package/src/runtime/routes/channel-delivery-routes.ts +170 -0
  391. package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
  392. package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
  393. package/src/runtime/routes/channel-route-shared.ts +144 -0
  394. package/src/runtime/routes/channel-routes.ts +32 -1634
  395. package/src/runtime/routes/conversation-routes.ts +50 -7
  396. package/src/runtime/routes/events-routes.ts +2 -2
  397. package/src/runtime/routes/identity-routes.ts +126 -0
  398. package/src/runtime/routes/pairing-routes.ts +143 -0
  399. package/src/runtime/routes/run-routes.ts +15 -1
  400. package/src/runtime/run-orchestrator.ts +52 -34
  401. package/src/schedule/schedule-store.ts +36 -32
  402. package/src/schedule/scheduler.ts +3 -3
  403. package/src/security/encrypted-store.ts +5 -7
  404. package/src/security/oauth2.ts +45 -15
  405. package/src/security/parental-control-store.ts +183 -0
  406. package/src/security/secret-allowlist.ts +4 -3
  407. package/src/security/secret-scanner.ts +5 -5
  408. package/src/security/secure-keys.ts +1 -1
  409. package/src/security/token-manager.ts +3 -2
  410. package/src/services/vercel-deploy.ts +6 -2
  411. package/src/skills/tool-manifest.ts +3 -3
  412. package/src/skills/vellum-catalog-remote.ts +75 -16
  413. package/src/slack/slack-webhook.ts +2 -1
  414. package/src/swarm/orchestrator.ts +92 -1
  415. package/src/swarm/router-planner.ts +6 -9
  416. package/src/swarm/worker-prompts.ts +9 -12
  417. package/src/tasks/task-compiler.ts +19 -28
  418. package/src/tasks/task-runner.ts +1 -1
  419. package/src/tools/assets/search.ts +15 -14
  420. package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
  421. package/src/tools/browser/auto-navigate.ts +1 -0
  422. package/src/tools/browser/browser-execution.ts +10 -1
  423. package/src/tools/browser/browser-manager.ts +119 -4
  424. package/src/tools/browser/network-recorder.ts +5 -0
  425. package/src/tools/credentials/broker.ts +11 -2
  426. package/src/tools/credentials/metadata-store.ts +18 -14
  427. package/src/tools/credentials/post-connect-hooks.ts +61 -0
  428. package/src/tools/credentials/vault.ts +49 -23
  429. package/src/tools/executor.ts +68 -9
  430. package/src/tools/host-terminal/cli-discover.ts +1 -1
  431. package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
  432. package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
  433. package/src/tools/network/script-proxy/server.ts +1 -1
  434. package/src/tools/network/script-proxy/session-manager.ts +6 -5
  435. package/src/tools/network/web-fetch.ts +18 -2
  436. package/src/tools/network/web-search.ts +7 -3
  437. package/src/tools/reminder/reminder-store.ts +14 -15
  438. package/src/tools/schedule/create.ts +1 -0
  439. package/src/tools/schedule/list.ts +2 -1
  440. package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
  441. package/src/tools/skills/skill-script-runner.ts +24 -9
  442. package/src/tools/skills/skill-tool-factory.ts +1 -0
  443. package/src/tools/tasks/work-item-enqueue.ts +2 -2
  444. package/src/tools/terminal/evaluate-typescript.ts +21 -12
  445. package/src/tools/terminal/parser.ts +50 -0
  446. package/src/tools/watcher/delete.ts +6 -0
  447. package/src/tools/weather/service.ts +1 -1
  448. package/src/twitter/client.ts +190 -24
  449. package/src/twitter/session.ts +4 -3
  450. package/src/util/clipboard.ts +1 -1
  451. package/src/util/errors.ts +65 -8
  452. package/src/util/fs.ts +40 -0
  453. package/src/util/json.ts +10 -0
  454. package/src/util/log-redact.ts +189 -0
  455. package/src/util/logger.ts +19 -17
  456. package/src/util/object.ts +3 -0
  457. package/src/util/platform.ts +72 -365
  458. package/src/util/pricing.ts +1 -1
  459. package/src/util/promise-guard.ts +1 -1
  460. package/src/util/retry.ts +19 -0
  461. package/src/util/row-mapper.ts +79 -0
  462. package/src/util/silently.ts +21 -0
  463. package/src/watcher/engine.ts +5 -1
  464. package/src/watcher/provider-types.ts +20 -0
  465. package/src/watcher/providers/github.ts +156 -0
  466. package/src/watcher/providers/gmail.ts +1 -0
  467. package/src/watcher/providers/google-calendar.ts +1 -0
  468. package/src/watcher/providers/linear.ts +460 -0
  469. package/src/watcher/providers/slack.ts +1 -0
  470. package/src/work-items/work-item-runner.ts +1 -1
  471. package/src/workspace/git-service.ts +1 -1
  472. package/src/workspace/provider-commit-message-generator.ts +51 -22
  473. package/src/__tests__/call-bridge.test.ts +0 -517
  474. package/src/__tests__/session-process-bridge.test.ts +0 -244
  475. package/src/calls/call-bridge.ts +0 -168
  476. package/src/config/bundled-skills/media-processing/services/capability-registry.ts +0 -137
  477. package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +0 -280
  478. package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +0 -144
  479. package/src/config/bundled-skills/media-processing/services/feedback-store.ts +0 -136
  480. package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +0 -95
  481. package/src/config/bundled-skills/media-processing/services/timeline-service.ts +0 -267
  482. package/src/config/bundled-skills/media-processing/tools/detect-events.ts +0 -110
  483. package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +0 -235
  484. package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +0 -142
  485. package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +0 -150
  486. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
@@ -1,5 +1,4 @@
1
- import { Database } from 'bun:sqlite';
2
- import { getDb } from './db-connection.js';
1
+ import { getDb, getSqliteFrom } from './db-connection.js';
3
2
  import { getLogger } from '../util/logger.js';
4
3
  import {
5
4
  migrateJobDeferrals,
@@ -12,7 +11,15 @@ import {
12
11
  migrateLlmUsageEventsDropAssistantId,
13
12
  migrateExtConvBindingsChannelChatUnique,
14
13
  migrateCallSessionsProviderSidDedup,
14
+ migrateCallSessionsAddInitiatedFrom,
15
15
  migrateMemoryFtsBackfill,
16
+ migrateGuardianActionTables,
17
+ migrateBackfillInboxThreadStateFromBindings,
18
+ migrateDropActiveSearchIndex,
19
+ migrateMemorySegmentsIndexes,
20
+ migrateMemoryItemsIndexes,
21
+ migrateRemainingTableIndexes,
22
+ validateMigrationState,
16
23
  } from './schema-migration.js';
17
24
 
18
25
  const log = getLogger('memory-db');
@@ -31,7 +38,8 @@ export function initializeDb(): void {
31
38
  total_estimated_cost REAL NOT NULL DEFAULT 0,
32
39
  context_summary TEXT,
33
40
  context_compacted_message_count INTEGER NOT NULL DEFAULT 0,
34
- context_compacted_at INTEGER
41
+ context_compacted_at INTEGER,
42
+ source TEXT NOT NULL DEFAULT 'user'
35
43
  )
36
44
  `);
37
45
 
@@ -524,7 +532,9 @@ export function initializeDb(): void {
524
532
  try { database.run(/*sql*/ `ALTER TABLE channel_inbound_events ADD COLUMN retry_after INTEGER`); } catch { /* already exists */ }
525
533
  try { database.run(/*sql*/ `ALTER TABLE channel_inbound_events ADD COLUMN raw_payload TEXT`); } catch { /* already exists */ }
526
534
  try { database.run(/*sql*/ `ALTER TABLE conversations ADD COLUMN thread_type TEXT NOT NULL DEFAULT 'standard'`); } catch { /* already exists */ }
535
+ try { database.run(/*sql*/ `ALTER TABLE conversations ADD COLUMN source TEXT NOT NULL DEFAULT 'user'`); } catch { /* already exists */ }
527
536
  try { database.run(/*sql*/ `ALTER TABLE conversations ADD COLUMN memory_scope_id TEXT NOT NULL DEFAULT 'default'`); } catch { /* already exists */ }
537
+ try { database.run(/*sql*/ `ALTER TABLE conversations ADD COLUMN origin_channel TEXT`); } catch { /* already exists */ }
528
538
  try { database.run(/*sql*/ `ALTER TABLE attachments ADD COLUMN thumbnail_base64 TEXT`); } catch { /* already exists */ }
529
539
  try { database.run(/*sql*/ `ALTER TABLE cron_jobs ADD COLUMN schedule_syntax TEXT NOT NULL DEFAULT 'cron'`); } catch { /* already exists */ }
530
540
  try { database.run(/*sql*/ `ALTER TABLE messages ADD COLUMN metadata TEXT`); } catch { /* already exists */ }
@@ -542,6 +552,7 @@ export function initializeDb(): void {
542
552
  // Indexes for query performance on large datasets
543
553
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_llm_request_logs_conv_created ON llm_request_logs(conversation_id, created_at)`);
544
554
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON messages(conversation_id)`);
555
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at)`);
545
556
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_tool_invocations_conversation_id ON tool_invocations(conversation_id)`);
546
557
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_conversations_updated_at ON conversations(updated_at)`);
547
558
  database.run(/*sql*/ `CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_segments_message_segment ON memory_segments(message_id, segment_index)`);
@@ -558,10 +569,21 @@ export function initializeDb(): void {
558
569
  WHERE status = 'pending_clarification'
559
570
  `);
560
571
  database.run(/*sql*/ `CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_items_fingerprint_scope ON memory_items(fingerprint, scope_id)`);
572
+ database.run(/*sql*/ `DROP INDEX IF EXISTS idx_memory_items_fingerprint`);
561
573
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_items_kind_status ON memory_items(kind, status)`);
562
574
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_items_status_invalid_at ON memory_items(status, invalid_at)`);
563
575
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_items_scope_status_kind ON memory_items(scope_id, status, kind)`);
576
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_items_scope_kind_status ON memory_items(scope_id, kind, status)`);
564
577
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_items_last_seen_at ON memory_items(last_seen_at)`);
578
+ // Partial covering index for directItemSearch: the LIKE '%term%' pattern can't
579
+ // seek a B-tree, but this index lets SQLite scan only active non-invalidated rows
580
+ // and evaluate LIKE + return columns without touching the main table.
581
+ migrateDropActiveSearchIndex(database);
582
+ database.run(/*sql*/ `
583
+ CREATE INDEX IF NOT EXISTS idx_memory_items_active_search
584
+ ON memory_items(status, invalid_at, last_seen_at DESC, subject, statement, id, kind, confidence, importance, first_seen_at, scope_id)
585
+ WHERE status = 'active' AND invalid_at IS NULL
586
+ `);
565
587
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_embeddings_target ON memory_embeddings(target_type, target_id)`);
566
588
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_embeddings_provider_model ON memory_embeddings(provider, model)`);
567
589
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_embeddings_content_hash ON memory_embeddings(content_hash, provider, model)`);
@@ -583,7 +605,7 @@ export function initializeDb(): void {
583
605
  // Deduplicate before creating unique index — existing DBs may have duplicate content_hash values.
584
606
  // Re-point message_attachments to the survivor (MIN rowid per content_hash), then delete dupes.
585
607
  {
586
- const raw = (database as unknown as { $client: Database }).$client;
608
+ const raw = getSqliteFrom(database);
587
609
  raw.exec(/*sql*/ `
588
610
  UPDATE message_attachments
589
611
  SET attachment_id = (
@@ -782,6 +804,12 @@ export function initializeDb(): void {
782
804
  try { database.run(/*sql*/ `ALTER TABLE call_sessions ADD COLUMN caller_identity_mode TEXT`); } catch { /* already exists */ }
783
805
  try { database.run(/*sql*/ `ALTER TABLE call_sessions ADD COLUMN caller_identity_source TEXT`); } catch { /* already exists */ }
784
806
 
807
+ // Persist assistantId so the webhook path can resolve assistant-scoped Twilio numbers
808
+ try { database.run(/*sql*/ `ALTER TABLE call_sessions ADD COLUMN assistant_id TEXT`); } catch { /* already exists */ }
809
+
810
+ // Track which conversation initiated the call (the chat where call_start was invoked)
811
+ migrateCallSessionsAddInitiatedFrom(database);
812
+
785
813
  // Unique constraint: at most one non-null provider_call_sid per (provider, provider_call_sid).
786
814
  // On upgraded databases that pre-date this constraint, duplicate rows may exist; deduplicate
787
815
  // them first to avoid a UNIQUE constraint failure that would prevent startup.
@@ -1159,5 +1187,94 @@ export function initializeDb(): void {
1159
1187
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_media_event_feedback_event_id ON media_event_feedback(event_id)`);
1160
1188
  database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_media_event_feedback_type ON media_event_feedback(asset_id, feedback_type)`);
1161
1189
 
1190
+ // ── Assistant Inbox ──────────────────────────────────────────────────
1191
+
1192
+ database.run(/*sql*/ `
1193
+ CREATE TABLE IF NOT EXISTS assistant_ingress_invites (
1194
+ id TEXT PRIMARY KEY,
1195
+ assistant_id TEXT NOT NULL DEFAULT 'self',
1196
+ source_channel TEXT NOT NULL,
1197
+ token_hash TEXT NOT NULL,
1198
+ created_by_session_id TEXT,
1199
+ note TEXT,
1200
+ max_uses INTEGER NOT NULL DEFAULT 1 CHECK (max_uses > 0),
1201
+ use_count INTEGER NOT NULL DEFAULT 0 CHECK (use_count >= 0),
1202
+ expires_at INTEGER NOT NULL,
1203
+ status TEXT NOT NULL DEFAULT 'active',
1204
+ redeemed_by_external_user_id TEXT,
1205
+ redeemed_by_external_chat_id TEXT,
1206
+ redeemed_at INTEGER,
1207
+ created_at INTEGER NOT NULL,
1208
+ updated_at INTEGER NOT NULL
1209
+ )
1210
+ `);
1211
+
1212
+ database.run(/*sql*/ `CREATE UNIQUE INDEX IF NOT EXISTS idx_ingress_invites_token_hash ON assistant_ingress_invites(token_hash)`);
1213
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_ingress_invites_channel_status ON assistant_ingress_invites(assistant_id, source_channel, status, expires_at)`);
1214
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_ingress_invites_channel_created ON assistant_ingress_invites(assistant_id, source_channel, created_at)`);
1215
+
1216
+ database.run(/*sql*/ `
1217
+ CREATE TABLE IF NOT EXISTS assistant_ingress_members (
1218
+ id TEXT PRIMARY KEY,
1219
+ assistant_id TEXT NOT NULL DEFAULT 'self',
1220
+ source_channel TEXT NOT NULL,
1221
+ external_user_id TEXT,
1222
+ external_chat_id TEXT,
1223
+ display_name TEXT,
1224
+ username TEXT,
1225
+ status TEXT NOT NULL DEFAULT 'pending',
1226
+ policy TEXT NOT NULL DEFAULT 'allow',
1227
+ invite_id TEXT REFERENCES assistant_ingress_invites(id),
1228
+ created_by_session_id TEXT,
1229
+ revoked_reason TEXT,
1230
+ blocked_reason TEXT,
1231
+ last_seen_at INTEGER,
1232
+ created_at INTEGER NOT NULL,
1233
+ updated_at INTEGER NOT NULL,
1234
+ CHECK (external_user_id IS NOT NULL OR external_chat_id IS NOT NULL)
1235
+ )
1236
+ `);
1237
+
1238
+ database.run(/*sql*/ `CREATE UNIQUE INDEX IF NOT EXISTS idx_ingress_members_user ON assistant_ingress_members(assistant_id, source_channel, external_user_id) WHERE external_user_id IS NOT NULL`);
1239
+ database.run(/*sql*/ `CREATE UNIQUE INDEX IF NOT EXISTS idx_ingress_members_chat ON assistant_ingress_members(assistant_id, source_channel, external_chat_id) WHERE external_chat_id IS NOT NULL`);
1240
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_ingress_members_status_policy ON assistant_ingress_members(assistant_id, source_channel, status, policy)`);
1241
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_ingress_members_updated ON assistant_ingress_members(assistant_id, source_channel, updated_at)`);
1242
+
1243
+ database.run(/*sql*/ `
1244
+ CREATE TABLE IF NOT EXISTS assistant_inbox_thread_state (
1245
+ conversation_id TEXT PRIMARY KEY REFERENCES conversations(id) ON DELETE CASCADE,
1246
+ assistant_id TEXT NOT NULL DEFAULT 'self',
1247
+ source_channel TEXT NOT NULL,
1248
+ external_chat_id TEXT NOT NULL,
1249
+ external_user_id TEXT,
1250
+ display_name TEXT,
1251
+ username TEXT,
1252
+ last_inbound_at INTEGER,
1253
+ last_outbound_at INTEGER,
1254
+ last_message_at INTEGER,
1255
+ unread_count INTEGER NOT NULL DEFAULT 0,
1256
+ pending_escalation_count INTEGER NOT NULL DEFAULT 0,
1257
+ has_pending_escalation INTEGER NOT NULL DEFAULT 0,
1258
+ created_at INTEGER NOT NULL,
1259
+ updated_at INTEGER NOT NULL
1260
+ )
1261
+ `);
1262
+
1263
+ database.run(/*sql*/ `CREATE UNIQUE INDEX IF NOT EXISTS idx_inbox_thread_state_channel ON assistant_inbox_thread_state(assistant_id, source_channel, external_chat_id)`);
1264
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_inbox_thread_state_last_msg ON assistant_inbox_thread_state(assistant_id, last_message_at)`);
1265
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_inbox_thread_state_escalation ON assistant_inbox_thread_state(assistant_id, has_pending_escalation, last_message_at)`);
1266
+
1267
+ migrateBackfillInboxThreadStateFromBindings(database);
1268
+
1269
+ migrateGuardianActionTables(database);
1270
+
1162
1271
  migrateMemoryFtsBackfill(database);
1272
+
1273
+ migrateMemorySegmentsIndexes(database);
1274
+
1275
+ migrateMemoryItemsIndexes(database);
1276
+
1277
+ migrateRemainingTableIndexes(database);
1278
+
1279
+ validateMigrationState(database);
1163
1280
  }
package/src/memory/db.ts CHANGED
@@ -1,2 +1,15 @@
1
- export { getDb, resetDb } from './db-connection.js';
1
+ export { getDb, resetDb, getSqlite, getSqliteFrom, type DrizzleDb } from './db-connection.js';
2
2
  export { initializeDb } from './db-init.js';
3
+ export {
4
+ rawGet,
5
+ rawAll,
6
+ rawRun,
7
+ rawExec,
8
+ rawChanges,
9
+ rawGetFrom,
10
+ rawAllFrom,
11
+ rawRunFrom,
12
+ rawExecFrom,
13
+ rawPrepare,
14
+ rawPrepareFrom,
15
+ } from './raw-query.js';
@@ -1,6 +1,7 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import type { AssistantConfig } from '../config/types.js';
3
3
  import { getLogger } from '../util/logger.js';
4
+ import { getOllamaBaseUrlEnv } from '../config/env.js';
4
5
  import { GeminiEmbeddingBackend } from './embedding-gemini.js';
5
6
  import { LocalEmbeddingBackend } from './embedding-local.js';
6
7
  import { OllamaEmbeddingBackend } from './embedding-ollama.js';
@@ -14,8 +15,17 @@ const backendCache = new Map<string, EmbeddingBackend>();
14
15
  // ── In-memory embedding vector cache ──────────────────────────────
15
16
  // LRU cache keyed by sha256(provider + model + text) → embedding vector.
16
17
  // Avoids redundant API calls / local compute for identical content.
17
- const VECTOR_CACHE_MAX_ENTRIES = 4096;
18
+ // Eviction is based on estimated byte size (32 MB cap) rather than entry count,
19
+ // since vector dimensions vary across providers/models.
20
+ const VECTOR_CACHE_MAX_BYTES = 33_554_432; // 32 MB
18
21
  const vectorCache = new Map<string, number[]>();
22
+ let vectorCacheBytes = 0;
23
+
24
+ /** Estimate in-memory byte cost of a single cache entry. */
25
+ function estimateEntryBytes(key: string, vector: number[]): number {
26
+ // key: UTF-16 chars (2 bytes each) + vector: 8 bytes per float64
27
+ return key.length * 2 + vector.length * 8;
28
+ }
19
29
 
20
30
  function vectorCacheKey(provider: string, model: string, text: string): string {
21
31
  return createHash('sha256').update(`${provider}\0${model}\0${text}`).digest('hex');
@@ -34,18 +44,30 @@ function getFromVectorCache(provider: string, model: string, text: string): numb
34
44
 
35
45
  function putInVectorCache(provider: string, model: string, text: string, vector: number[]): void {
36
46
  const key = vectorCacheKey(provider, model, text);
37
- vectorCache.delete(key);
38
- if (vectorCache.size >= VECTOR_CACHE_MAX_ENTRIES) {
47
+ // If replacing an existing entry, subtract its old cost first
48
+ const existing = vectorCache.get(key);
49
+ if (existing !== undefined) {
50
+ vectorCacheBytes -= estimateEntryBytes(key, existing);
51
+ vectorCache.delete(key);
52
+ }
53
+ const entryBytes = estimateEntryBytes(key, vector);
54
+ // Evict oldest entries until we have room
55
+ while (vectorCacheBytes + entryBytes > VECTOR_CACHE_MAX_BYTES && vectorCache.size > 0) {
39
56
  const oldest = vectorCache.keys().next().value;
40
- if (oldest !== undefined) vectorCache.delete(oldest);
57
+ if (oldest === undefined) break;
58
+ const oldVec = vectorCache.get(oldest)!;
59
+ vectorCacheBytes -= estimateEntryBytes(oldest, oldVec);
60
+ vectorCache.delete(oldest);
41
61
  }
42
62
  vectorCache.set(key, vector);
63
+ vectorCacheBytes += entryBytes;
43
64
  }
44
65
 
45
66
  /** Clear cached embedding backends and the in-memory vector cache. */
46
67
  export function clearEmbeddingBackendCache(): void {
47
68
  backendCache.clear();
48
69
  vectorCache.clear();
70
+ vectorCacheBytes = 0;
49
71
  }
50
72
 
51
73
  function cacheKey(provider: string, model: string): string {
@@ -293,5 +315,5 @@ function selectFallbackBackends(config: AssistantConfig, exclude: EmbeddingProvi
293
315
  function isOllamaConfigured(config: AssistantConfig): boolean {
294
316
  return config.provider === 'ollama'
295
317
  || Boolean(config.apiKeys.ollama)
296
- || Boolean(process.env.OLLAMA_BASE_URL);
318
+ || Boolean(getOllamaBaseUrlEnv());
297
319
  }
@@ -1,4 +1,5 @@
1
1
  import type { EmbeddingBackend, EmbeddingRequestOptions } from './embedding-backend.js';
2
+ import { getOllamaBaseUrlEnv } from '../config/env.js';
2
3
 
3
4
  interface OllamaEmbeddingsResponse {
4
5
  data?: Array<{ embedding: number[] }>;
@@ -49,7 +50,7 @@ export class OllamaEmbeddingBackend implements EmbeddingBackend {
49
50
  }
50
51
 
51
52
  function resolveBaseUrl(override?: string): string {
52
- const value = (override ?? process.env.OLLAMA_BASE_URL ?? DEFAULT_OLLAMA_BASE_URL).trim();
53
+ const value = (override ?? getOllamaBaseUrlEnv() ?? DEFAULT_OLLAMA_BASE_URL).trim();
53
54
  if (value.endsWith('/')) return value.slice(0, -1);
54
55
  return value;
55
56
  }
@@ -1,9 +1,8 @@
1
- import Anthropic from '@anthropic-ai/sdk';
2
1
  import { eq, sql } from 'drizzle-orm';
3
- import { getConfig } from '../config/loader.js';
4
2
  import type { MemoryEntityConfig } from '../config/types.js';
5
3
  import { getLogger } from '../util/logger.js';
6
4
  import { truncate } from '../util/truncate.js';
5
+ import { getConfiguredProvider, createTimeout, extractToolUse, userMessage } from '../providers/provider-send-message.js';
7
6
  import { getDb } from './db.js';
8
7
  import { memoryEntities, memoryEntityRelations, memoryItemEntities } from './schema.js';
9
8
 
@@ -123,51 +122,55 @@ export async function extractEntitiesWithLLM(
123
122
  text: string,
124
123
  entityConfig: MemoryEntityConfig,
125
124
  ): Promise<ExtractedEntityGraph> {
126
- const config = getConfig();
127
- const apiKey = config.apiKeys.anthropic ?? process.env.ANTHROPIC_API_KEY;
128
- if (!apiKey) {
129
- log.debug('No Anthropic API key available for entity extraction');
125
+ const provider = getConfiguredProvider();
126
+ if (!provider) {
127
+ log.debug('Configured provider unavailable for entity extraction');
130
128
  return { entities: [], relations: [] };
131
129
  }
132
130
 
133
131
  const extractRelations = entityConfig.extractRelations?.enabled ?? false;
134
132
 
135
133
  try {
136
- const client = new Anthropic({ apiKey });
137
- const response = await Promise.race([
138
- client.messages.create({
139
- model: entityConfig.model,
140
- max_tokens: 1024,
141
- system: ENTITY_EXTRACTION_SYSTEM_PROMPT,
142
- tools: [{
134
+ const { signal, cleanup } = createTimeout(ENTITY_EXTRACTION_TIMEOUT_MS);
135
+ try {
136
+ const response = await provider.sendMessage(
137
+ [userMessage(text)],
138
+ [{
143
139
  name: 'store_entities',
144
140
  description: 'Store extracted entities from the text',
145
141
  input_schema: buildToolInputSchema(extractRelations),
146
142
  }],
147
- tool_choice: { type: 'tool' as const, name: 'store_entities' },
148
- messages: [{ role: 'user' as const, content: text }],
149
- }) as Promise<Anthropic.Message>,
150
- new Promise<never>((_, reject) =>
151
- setTimeout(() => reject(new Error('Entity extraction LLM timeout')), ENTITY_EXTRACTION_TIMEOUT_MS),
152
- ),
153
- ]) as Anthropic.Message;
154
-
155
- const toolBlock = response.content.find((block) => block.type === 'tool_use');
156
- if (!toolBlock || toolBlock.type !== 'tool_use') {
157
- log.warn('No tool_use block in entity extraction response');
158
- return { entities: [], relations: [] };
159
- }
143
+ ENTITY_EXTRACTION_SYSTEM_PROMPT,
144
+ {
145
+ config: {
146
+ model: entityConfig.model,
147
+ max_tokens: 1024,
148
+ tool_choice: { type: 'tool' as const, name: 'store_entities' },
149
+ },
150
+ signal,
151
+ },
152
+ );
153
+ cleanup();
160
154
 
161
- const input = toolBlock.input as { entities?: LLMExtractedEntity[]; relations?: LLMExtractedRelation[] };
162
- if (!Array.isArray(input.entities)) {
163
- log.warn('Invalid entities in entity extraction response');
164
- return { entities: [], relations: [] };
165
- }
155
+ const toolBlock = extractToolUse(response);
156
+ if (!toolBlock) {
157
+ log.warn('No tool_use block in entity extraction response');
158
+ return { entities: [], relations: [] };
159
+ }
160
+
161
+ const input = toolBlock.input as { entities?: LLMExtractedEntity[]; relations?: LLMExtractedRelation[] };
162
+ if (!Array.isArray(input.entities)) {
163
+ log.warn('Invalid entities in entity extraction response');
164
+ return { entities: [], relations: [] };
165
+ }
166
166
 
167
- const entities = parseExtractedEntities(input.entities);
168
- const relations = extractRelations ? parseExtractedRelations(input.relations) : [];
167
+ const entities = parseExtractedEntities(input.entities);
168
+ const relations = extractRelations ? parseExtractedRelations(input.relations) : [];
169
169
 
170
- return { entities, relations };
170
+ return { entities, relations };
171
+ } finally {
172
+ cleanup();
173
+ }
171
174
  } catch (err) {
172
175
  const message = err instanceof Error ? err.message : String(err);
173
176
  log.warn({ err: message }, 'Entity extraction LLM call failed');
@@ -284,7 +287,7 @@ export function upsertEntityRelation(input: UpsertEntityRelationInput): void {
284
287
  memoryEntityRelations.targetEntityId,
285
288
  memoryEntityRelations.relation,
286
289
  ],
287
- set: normalizedEvidence === null
290
+ set: normalizedEvidence === undefined
288
291
  ? {
289
292
  firstSeenAt: sql`MIN(${memoryEntityRelations.firstSeenAt}, ${seenAt})`,
290
293
  lastSeenAt: sql`MAX(${memoryEntityRelations.lastSeenAt}, ${seenAt})`,