@vellumai/assistant 0.3.4 → 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 (506) hide show
  1. package/Dockerfile +2 -0
  2. package/README.md +88 -2
  3. package/eslint.config.mjs +31 -0
  4. package/package.json +1 -1
  5. package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
  6. package/scripts/ipc/generate-swift.ts +31 -2
  7. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +438 -1
  8. package/src/__tests__/approval-conversation-turn.test.ts +214 -0
  9. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +41 -0
  10. package/src/__tests__/approval-message-composer.test.ts +253 -0
  11. package/src/__tests__/browser-manager.test.ts +1 -0
  12. package/src/__tests__/call-conversation-messages.test.ts +130 -0
  13. package/src/__tests__/call-domain.test.ts +12 -2
  14. package/src/__tests__/call-orchestrator.test.ts +799 -249
  15. package/src/__tests__/call-pointer-messages.test.ts +148 -0
  16. package/src/__tests__/call-recovery.test.ts +3 -0
  17. package/src/__tests__/call-routes-http.test.ts +32 -2
  18. package/src/__tests__/call-store.test.ts +3 -0
  19. package/src/__tests__/channel-approval-routes.test.ts +1277 -98
  20. package/src/__tests__/channel-approval.test.ts +37 -0
  21. package/src/__tests__/channel-approvals.test.ts +36 -50
  22. package/src/__tests__/channel-guardian.test.ts +630 -22
  23. package/src/__tests__/channel-readiness-service.test.ts +324 -0
  24. package/src/__tests__/checker.test.ts +14 -7
  25. package/src/__tests__/clarification-resolver.test.ts +44 -24
  26. package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
  27. package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
  28. package/src/__tests__/config-schema.test.ts +14 -8
  29. package/src/__tests__/context-window-manager.test.ts +30 -2
  30. package/src/__tests__/contradiction-checker.test.ts +20 -5
  31. package/src/__tests__/credential-security-invariants.test.ts +7 -2
  32. package/src/__tests__/daemon-lifecycle.test.ts +13 -12
  33. package/src/__tests__/db-migration-rollback.test.ts +752 -0
  34. package/src/__tests__/dictation-mode-detection.test.ts +63 -0
  35. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
  36. package/src/__tests__/entity-search.test.ts +615 -0
  37. package/src/__tests__/fuzzy-match-property.test.ts +5 -5
  38. package/src/__tests__/guardian-action-store.test.ts +123 -0
  39. package/src/__tests__/guardian-action-sweep.test.ts +277 -0
  40. package/src/__tests__/guardian-dispatch.test.ts +389 -0
  41. package/src/__tests__/guardian-question-copy.test.ts +47 -0
  42. package/src/__tests__/handlers-telegram-config.test.ts +4 -2
  43. package/src/__tests__/handlers-twilio-config.test.ts +533 -0
  44. package/src/__tests__/intent-routing.test.ts +2 -0
  45. package/src/__tests__/ipc-snapshot.test.ts +291 -1
  46. package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
  47. package/src/__tests__/messaging-send-tool.test.ts +65 -0
  48. package/src/__tests__/model-intents.test.ts +96 -0
  49. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
  50. package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
  51. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
  52. package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
  53. package/src/__tests__/provider-error-scenarios.test.ts +621 -0
  54. package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
  55. package/src/__tests__/qdrant-manager.test.ts +27 -20
  56. package/src/__tests__/relay-server.test.ts +779 -40
  57. package/src/__tests__/run-orchestrator-assistant-events.test.ts +6 -0
  58. package/src/__tests__/run-orchestrator.test.ts +42 -4
  59. package/src/__tests__/runtime-runs-http.test.ts +17 -1
  60. package/src/__tests__/runtime-runs.test.ts +16 -0
  61. package/src/__tests__/schedule-store.test.ts +18 -4
  62. package/src/__tests__/scheduler-recurrence.test.ts +13 -4
  63. package/src/__tests__/session-abort-tool-results.test.ts +6 -0
  64. package/src/__tests__/session-agent-loop.test.ts +857 -0
  65. package/src/__tests__/session-conflict-gate.test.ts +6 -0
  66. package/src/__tests__/session-pre-run-repair.test.ts +6 -0
  67. package/src/__tests__/session-profile-injection.test.ts +6 -0
  68. package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
  69. package/src/__tests__/session-queue.test.ts +6 -0
  70. package/src/__tests__/session-runtime-assembly.test.ts +321 -13
  71. package/src/__tests__/session-slash-known.test.ts +6 -0
  72. package/src/__tests__/session-slash-queue.test.ts +6 -0
  73. package/src/__tests__/session-slash-unknown.test.ts +6 -0
  74. package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
  75. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  76. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  77. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  78. package/src/__tests__/session-workspace-injection.test.ts +6 -0
  79. package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
  80. package/src/__tests__/skills.test.ts +2 -0
  81. package/src/__tests__/sms-messaging-provider.test.ts +126 -0
  82. package/src/__tests__/starter-task-flow.test.ts +2 -0
  83. package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
  84. package/src/__tests__/system-prompt.test.ts +2 -0
  85. package/src/__tests__/task-management-tools.test.ts +2 -2
  86. package/src/__tests__/task-runner.test.ts +14 -4
  87. package/src/__tests__/terminal-tools.test.ts +25 -19
  88. package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
  89. package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
  90. package/src/__tests__/tool-executor.test.ts +23 -24
  91. package/src/__tests__/trust-store.test.ts +3 -3
  92. package/src/__tests__/twilio-rest.test.ts +29 -0
  93. package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
  94. package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
  95. package/src/__tests__/twilio-routes.test.ts +167 -11
  96. package/src/__tests__/twitter-cli-error-shaping.test.ts +2 -2
  97. package/src/__tests__/user-reference.test.ts +2 -0
  98. package/src/__tests__/voice-quality.test.ts +222 -0
  99. package/src/__tests__/web-search.test.ts +46 -30
  100. package/src/__tests__/work-item-output.test.ts +110 -0
  101. package/src/agent/loop.ts +1 -1
  102. package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
  103. package/src/amazon/client.ts +1418 -0
  104. package/src/amazon/request-extractor.ts +135 -0
  105. package/src/amazon/session.ts +109 -0
  106. package/src/autonomy/autonomy-store.ts +5 -5
  107. package/src/browser-extension-relay/client.ts +124 -0
  108. package/src/browser-extension-relay/protocol.ts +63 -0
  109. package/src/browser-extension-relay/server.ts +177 -0
  110. package/src/bundler/app-bundler.ts +3 -3
  111. package/src/bundler/bundle-signer.ts +1 -1
  112. package/src/bundler/signature-verifier.ts +1 -1
  113. package/src/calls/call-conversation-messages.ts +33 -0
  114. package/src/calls/call-domain.ts +114 -10
  115. package/src/calls/call-orchestrator.ts +268 -59
  116. package/src/calls/call-pointer-messages.ts +53 -0
  117. package/src/calls/call-recovery.ts +3 -8
  118. package/src/calls/call-store.ts +69 -87
  119. package/src/calls/elevenlabs-config.ts +3 -2
  120. package/src/calls/guardian-action-sweep.ts +105 -0
  121. package/src/calls/guardian-dispatch.ts +203 -0
  122. package/src/calls/guardian-question-copy.ts +133 -0
  123. package/src/calls/relay-server.ts +466 -8
  124. package/src/calls/speaker-identification.ts +1 -1
  125. package/src/calls/twilio-config.ts +22 -14
  126. package/src/calls/twilio-provider.ts +6 -4
  127. package/src/calls/twilio-rest.ts +308 -7
  128. package/src/calls/twilio-routes.ts +65 -12
  129. package/src/calls/types.ts +3 -1
  130. package/src/channels/types.ts +25 -0
  131. package/src/cli/amazon.ts +815 -0
  132. package/src/cli/config-commands.ts +2 -2
  133. package/src/cli/core-commands.ts +4 -3
  134. package/src/cli/influencer.ts +244 -0
  135. package/src/cli/map.ts +89 -6
  136. package/src/cli.ts +1 -1
  137. package/src/config/agent-schema.ts +171 -0
  138. package/src/config/bundled-skills/amazon/SKILL.md +127 -0
  139. package/src/config/bundled-skills/amazon/icon.svg +13 -0
  140. package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
  141. package/src/config/bundled-skills/browser/SKILL.md +1 -0
  142. package/src/config/bundled-skills/browser/TOOLS.json +17 -0
  143. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
  144. package/src/config/bundled-skills/doordash/SKILL.md +51 -51
  145. package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
  146. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
  147. package/src/config/bundled-skills/influencer/SKILL.md +144 -0
  148. package/src/config/bundled-skills/knowledge-graph/SKILL.md +15 -0
  149. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +56 -0
  150. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +185 -0
  151. package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
  152. package/src/config/bundled-skills/media-processing/SKILL.md +176 -0
  153. package/src/config/bundled-skills/media-processing/TOOLS.json +230 -0
  154. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
  155. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
  156. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
  157. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
  158. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
  159. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
  160. package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
  161. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +259 -0
  162. package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
  163. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +136 -0
  164. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +59 -0
  165. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +195 -0
  166. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +197 -0
  167. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +143 -0
  168. package/src/config/bundled-skills/media-processing/tools/media-status.ts +75 -0
  169. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +65 -0
  170. package/src/config/bundled-skills/messaging/SKILL.md +33 -8
  171. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
  172. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
  173. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -1
  174. package/src/config/bundled-skills/phone-calls/SKILL.md +88 -23
  175. package/src/config/bundled-skills/twitter/SKILL.md +19 -3
  176. package/src/config/bundled-skills/twitter/icon.svg +14 -0
  177. package/src/config/bundled-tool-registry.ts +310 -0
  178. package/src/config/calls-schema.ts +181 -0
  179. package/src/config/core-schema.ts +309 -0
  180. package/src/config/defaults.ts +28 -3
  181. package/src/config/env-registry.ts +162 -0
  182. package/src/config/env.ts +175 -0
  183. package/src/config/loader.ts +6 -6
  184. package/src/config/memory-schema.ts +528 -0
  185. package/src/config/sandbox-schema.ts +55 -0
  186. package/src/config/schema.ts +158 -1133
  187. package/src/config/skill-state.ts +1 -1
  188. package/src/config/skills-schema.ts +32 -0
  189. package/src/config/skills.ts +35 -24
  190. package/src/config/system-prompt.ts +131 -56
  191. package/src/config/templates/IDENTITY.md +2 -2
  192. package/src/config/templates/SOUL.md +1 -1
  193. package/src/config/types.ts +1 -0
  194. package/src/config/user-reference.ts +4 -9
  195. package/src/config/vellum-skills/catalog.json +6 -7
  196. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
  197. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +4 -3
  198. package/src/config/vellum-skills/sms-setup/SKILL.md +216 -0
  199. package/src/config/vellum-skills/twilio-setup/SKILL.md +40 -8
  200. package/src/context/window-manager.ts +27 -7
  201. package/src/daemon/approval-generators.ts +186 -0
  202. package/src/daemon/approved-devices-store.ts +140 -0
  203. package/src/daemon/assistant-attachments.ts +1 -1
  204. package/src/daemon/classifier.ts +35 -32
  205. package/src/daemon/config-watcher.ts +1 -1
  206. package/src/daemon/daemon-control.ts +217 -0
  207. package/src/daemon/handlers/apps.ts +2 -3
  208. package/src/daemon/handlers/config-channels.ts +158 -0
  209. package/src/daemon/handlers/config-inbox.ts +540 -0
  210. package/src/daemon/handlers/config-ingress.ts +231 -0
  211. package/src/daemon/handlers/config-integrations.ts +258 -0
  212. package/src/daemon/handlers/config-model.ts +143 -0
  213. package/src/daemon/handlers/config-parental.ts +163 -0
  214. package/src/daemon/handlers/config-scheduling.ts +172 -0
  215. package/src/daemon/handlers/config-slack.ts +92 -0
  216. package/src/daemon/handlers/config-telegram.ts +301 -0
  217. package/src/daemon/handlers/config-tools.ts +177 -0
  218. package/src/daemon/handlers/config-trust.ts +104 -0
  219. package/src/daemon/handlers/config-twilio.ts +1080 -0
  220. package/src/daemon/handlers/config.ts +53 -1689
  221. package/src/daemon/handlers/diagnostics.ts +1 -1
  222. package/src/daemon/handlers/dictation.ts +180 -0
  223. package/src/daemon/handlers/documents.ts +18 -32
  224. package/src/daemon/handlers/identity.ts +14 -23
  225. package/src/daemon/handlers/index.ts +11 -0
  226. package/src/daemon/handlers/misc.ts +3 -5
  227. package/src/daemon/handlers/pairing.ts +98 -0
  228. package/src/daemon/handlers/sessions.ts +56 -5
  229. package/src/daemon/handlers/shared.ts +6 -1
  230. package/src/daemon/handlers/skills.ts +1 -1
  231. package/src/daemon/handlers/twitter-auth.ts +2 -0
  232. package/src/daemon/handlers/work-items.ts +17 -9
  233. package/src/daemon/handlers/workspace-files.ts +4 -3
  234. package/src/daemon/install-cli-launchers.ts +113 -0
  235. package/src/daemon/ipc-contract/apps.ts +356 -0
  236. package/src/daemon/ipc-contract/browser.ts +74 -0
  237. package/src/daemon/ipc-contract/computer-use.ts +151 -0
  238. package/src/daemon/ipc-contract/diagnostics.ts +56 -0
  239. package/src/daemon/ipc-contract/documents.ts +74 -0
  240. package/src/daemon/ipc-contract/inbox.ts +209 -0
  241. package/src/daemon/ipc-contract/integrations.ts +284 -0
  242. package/src/daemon/ipc-contract/memory.ts +48 -0
  243. package/src/daemon/ipc-contract/messages.ts +211 -0
  244. package/src/daemon/ipc-contract/pairing.ts +45 -0
  245. package/src/daemon/ipc-contract/parental-control.ts +95 -0
  246. package/src/daemon/ipc-contract/schedules.ts +97 -0
  247. package/src/daemon/ipc-contract/sessions.ts +315 -0
  248. package/src/daemon/ipc-contract/shared.ts +42 -0
  249. package/src/daemon/ipc-contract/skills.ts +120 -0
  250. package/src/daemon/ipc-contract/subagents.ts +58 -0
  251. package/src/daemon/ipc-contract/surfaces.ts +250 -0
  252. package/src/daemon/ipc-contract/trust.ts +60 -0
  253. package/src/daemon/ipc-contract/work-items.ts +225 -0
  254. package/src/daemon/ipc-contract/workspace.ts +113 -0
  255. package/src/daemon/ipc-contract-inventory.json +70 -0
  256. package/src/daemon/ipc-contract-inventory.ts +55 -29
  257. package/src/daemon/ipc-contract.ts +229 -2426
  258. package/src/daemon/ipc-protocol.ts +1 -1
  259. package/src/daemon/ipc-validate.ts +7 -0
  260. package/src/daemon/lifecycle.ts +97 -377
  261. package/src/daemon/pairing-store.ts +177 -0
  262. package/src/daemon/providers-setup.ts +43 -0
  263. package/src/daemon/ride-shotgun-handler.ts +68 -3
  264. package/src/daemon/server.ts +66 -46
  265. package/src/daemon/session-agent-loop-handlers.ts +421 -0
  266. package/src/daemon/session-agent-loop.ts +117 -275
  267. package/src/daemon/session-dynamic-profile.ts +1 -1
  268. package/src/daemon/session-history.ts +1 -1
  269. package/src/daemon/session-media-retry.ts +1 -1
  270. package/src/daemon/session-messaging.ts +37 -2
  271. package/src/daemon/session-notifiers.ts +5 -25
  272. package/src/daemon/session-process.ts +99 -59
  273. package/src/daemon/session-queue-manager.ts +96 -4
  274. package/src/daemon/session-runtime-assembly.ts +199 -10
  275. package/src/daemon/session-surfaces.ts +19 -4
  276. package/src/daemon/session-tool-setup.ts +30 -30
  277. package/src/daemon/session-workspace.ts +1 -1
  278. package/src/daemon/session.ts +35 -2
  279. package/src/daemon/shutdown-handlers.ts +122 -0
  280. package/src/daemon/trace-emitter.ts +1 -1
  281. package/src/daemon/watch-handler.ts +36 -33
  282. package/src/doordash/cart-queries.ts +787 -0
  283. package/src/doordash/client.ts +144 -127
  284. package/src/doordash/order-queries.ts +85 -0
  285. package/src/doordash/queries.ts +10 -1308
  286. package/src/doordash/search-queries.ts +203 -0
  287. package/src/doordash/session.ts +3 -2
  288. package/src/doordash/store-queries.ts +246 -0
  289. package/src/doordash/types.ts +367 -0
  290. package/src/email/providers/agentmail.ts +2 -1
  291. package/src/email/providers/index.ts +3 -2
  292. package/src/email/service.ts +3 -2
  293. package/src/errors.ts +43 -0
  294. package/src/home-base/prebuilt/seed.ts +1 -1
  295. package/src/hooks/cli.ts +6 -5
  296. package/src/hooks/config.ts +6 -8
  297. package/src/hooks/discovery.ts +6 -5
  298. package/src/hooks/manager.ts +4 -3
  299. package/src/hooks/runner.ts +2 -2
  300. package/src/hooks/templates.ts +5 -5
  301. package/src/inbound/public-ingress-urls.ts +6 -4
  302. package/src/index.ts +4 -2
  303. package/src/influencer/client.ts +1104 -0
  304. package/src/instrument.ts +4 -3
  305. package/src/logfire.ts +4 -3
  306. package/src/memory/admin.ts +25 -35
  307. package/src/memory/attachments-store.ts +4 -7
  308. package/src/memory/channel-delivery-store.ts +30 -1
  309. package/src/memory/channel-guardian-store.ts +202 -2
  310. package/src/memory/clarification-resolver.ts +37 -33
  311. package/src/memory/conflict-store.ts +67 -61
  312. package/src/memory/contradiction-checker.ts +141 -117
  313. package/src/memory/conversation-store.ts +335 -51
  314. package/src/memory/db-connection.ts +27 -4
  315. package/src/memory/db-init.ts +265 -4
  316. package/src/memory/db.ts +14 -1
  317. package/src/memory/embedding-backend.ts +27 -5
  318. package/src/memory/embedding-ollama.ts +2 -1
  319. package/src/memory/entity-extractor.ts +38 -35
  320. package/src/memory/guardian-action-store.ts +430 -0
  321. package/src/memory/inbox-escalation-projection.ts +59 -0
  322. package/src/memory/inbox-thread-store.ts +218 -0
  323. package/src/memory/ingress-invite-store.ts +338 -0
  324. package/src/memory/ingress-member-store.ts +350 -0
  325. package/src/memory/items-extractor.ts +91 -97
  326. package/src/memory/job-handlers/index-maintenance.ts +3 -3
  327. package/src/memory/job-handlers/media-processing.ts +69 -0
  328. package/src/memory/job-handlers/summarization.ts +32 -26
  329. package/src/memory/job-utils.ts +3 -10
  330. package/src/memory/jobs-store.ts +8 -10
  331. package/src/memory/jobs-worker.ts +55 -36
  332. package/src/memory/media-store.ts +759 -0
  333. package/src/memory/migrations/001-job-deferrals.ts +45 -0
  334. package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
  335. package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
  336. package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
  337. package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
  338. package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
  339. package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
  340. package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
  341. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
  342. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
  343. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
  344. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
  345. package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
  346. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
  347. package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
  348. package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
  349. package/src/memory/migrations/017-memory-items-indexes.ts +10 -0
  350. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
  351. package/src/memory/migrations/index.ts +24 -0
  352. package/src/memory/migrations/registry.ts +79 -0
  353. package/src/memory/migrations/validate-migration-state.ts +69 -0
  354. package/src/memory/qdrant-manager.ts +49 -8
  355. package/src/memory/query-builder.ts +1 -1
  356. package/src/memory/raw-query.ts +119 -0
  357. package/src/memory/recall-cache.ts +4 -1
  358. package/src/memory/retriever.ts +165 -47
  359. package/src/memory/schema-migration.ts +25 -984
  360. package/src/memory/schema.ts +228 -7
  361. package/src/memory/search/entity.ts +205 -31
  362. package/src/memory/search/lexical.ts +81 -52
  363. package/src/memory/search/ranking.ts +27 -23
  364. package/src/memory/search/semantic.ts +157 -19
  365. package/src/memory/search/types.ts +24 -0
  366. package/src/memory/shared-app-links-store.ts +4 -5
  367. package/src/memory/validation.ts +19 -0
  368. package/src/messaging/draft-store.ts +5 -6
  369. package/src/messaging/provider-types.ts +2 -0
  370. package/src/messaging/providers/sms/adapter.ts +201 -0
  371. package/src/messaging/providers/sms/client.ts +93 -0
  372. package/src/messaging/providers/sms/types.ts +7 -0
  373. package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
  374. package/src/messaging/providers/whatsapp/adapter.ts +136 -0
  375. package/src/messaging/providers/whatsapp/client.ts +67 -0
  376. package/src/messaging/style-analyzer.ts +5 -4
  377. package/src/messaging/thread-summarizer.ts +61 -69
  378. package/src/messaging/triage-engine.ts +62 -71
  379. package/src/migrations/config-merge.ts +53 -0
  380. package/src/migrations/data-layout.ts +68 -0
  381. package/src/migrations/data-merge.ts +33 -0
  382. package/src/migrations/hooks-merge.ts +90 -0
  383. package/src/migrations/index.ts +6 -0
  384. package/src/migrations/log.ts +23 -0
  385. package/src/migrations/skills-merge.ts +33 -0
  386. package/src/migrations/workspace-layout.ts +79 -0
  387. package/src/permissions/checker.ts +133 -11
  388. package/src/permissions/prompter.ts +14 -0
  389. package/src/permissions/shell-identity.ts +31 -1
  390. package/src/permissions/trust-store.ts +21 -1
  391. package/src/providers/anthropic/client.ts +4 -4
  392. package/src/providers/failover.ts +2 -2
  393. package/src/providers/model-intents.ts +70 -0
  394. package/src/providers/ollama/client.ts +2 -1
  395. package/src/providers/provider-send-message.ts +176 -0
  396. package/src/providers/registry.ts +71 -30
  397. package/src/providers/retry.ts +35 -1
  398. package/src/providers/types.ts +12 -1
  399. package/src/runtime/approval-conversation-turn.ts +97 -0
  400. package/src/runtime/approval-message-composer.ts +253 -0
  401. package/src/runtime/channel-approval-parser.ts +36 -2
  402. package/src/runtime/channel-approvals.ts +11 -24
  403. package/src/runtime/channel-guardian-service.ts +88 -21
  404. package/src/runtime/channel-readiness-service.ts +418 -0
  405. package/src/runtime/channel-readiness-types.ts +35 -0
  406. package/src/runtime/channel-retry-sweep.ts +184 -0
  407. package/src/runtime/guardian-context-resolver.ts +108 -0
  408. package/src/runtime/http-server.ts +275 -717
  409. package/src/runtime/http-types.ts +59 -3
  410. package/src/runtime/middleware/auth.ts +116 -0
  411. package/src/runtime/middleware/error-handler.ts +33 -0
  412. package/src/runtime/middleware/twilio-validation.ts +127 -0
  413. package/src/runtime/routes/app-routes.ts +1 -1
  414. package/src/runtime/routes/call-routes.ts +51 -7
  415. package/src/runtime/routes/channel-delivery-routes.ts +170 -0
  416. package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
  417. package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
  418. package/src/runtime/routes/channel-route-shared.ts +144 -0
  419. package/src/runtime/routes/channel-routes.ts +32 -1588
  420. package/src/runtime/routes/conversation-routes.ts +50 -7
  421. package/src/runtime/routes/events-routes.ts +2 -2
  422. package/src/runtime/routes/identity-routes.ts +126 -0
  423. package/src/runtime/routes/pairing-routes.ts +143 -0
  424. package/src/runtime/routes/run-routes.ts +15 -1
  425. package/src/runtime/run-orchestrator.ts +86 -35
  426. package/src/schedule/schedule-store.ts +36 -32
  427. package/src/schedule/scheduler.ts +3 -3
  428. package/src/security/encrypted-store.ts +5 -7
  429. package/src/security/oauth2.ts +45 -15
  430. package/src/security/parental-control-store.ts +183 -0
  431. package/src/security/secret-allowlist.ts +4 -3
  432. package/src/security/secret-scanner.ts +5 -5
  433. package/src/security/secure-keys.ts +1 -1
  434. package/src/security/token-manager.ts +3 -2
  435. package/src/services/vercel-deploy.ts +6 -2
  436. package/src/skills/tool-manifest.ts +3 -3
  437. package/src/skills/vellum-catalog-remote.ts +75 -16
  438. package/src/slack/slack-webhook.ts +2 -1
  439. package/src/swarm/orchestrator.ts +92 -1
  440. package/src/swarm/router-planner.ts +6 -9
  441. package/src/swarm/worker-prompts.ts +9 -12
  442. package/src/tasks/task-compiler.ts +19 -28
  443. package/src/tasks/task-runner.ts +1 -1
  444. package/src/tools/assets/materialize.ts +2 -2
  445. package/src/tools/assets/search.ts +15 -14
  446. package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
  447. package/src/tools/browser/auto-navigate.ts +1 -0
  448. package/src/tools/browser/browser-execution.ts +10 -1
  449. package/src/tools/browser/browser-manager.ts +119 -4
  450. package/src/tools/browser/network-recorder.ts +5 -0
  451. package/src/tools/calls/call-start.ts +1 -0
  452. package/src/tools/credentials/broker.ts +11 -2
  453. package/src/tools/credentials/metadata-store.ts +18 -14
  454. package/src/tools/credentials/post-connect-hooks.ts +61 -0
  455. package/src/tools/credentials/vault.ts +49 -23
  456. package/src/tools/execution-target.ts +11 -1
  457. package/src/tools/executor.ts +68 -9
  458. package/src/tools/host-terminal/cli-discover.ts +1 -1
  459. package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
  460. package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
  461. package/src/tools/network/script-proxy/server.ts +1 -1
  462. package/src/tools/network/script-proxy/session-manager.ts +6 -5
  463. package/src/tools/network/web-fetch.ts +18 -2
  464. package/src/tools/network/web-search.ts +8 -4
  465. package/src/tools/reminder/reminder-store.ts +14 -15
  466. package/src/tools/schedule/create.ts +1 -0
  467. package/src/tools/schedule/list.ts +2 -1
  468. package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
  469. package/src/tools/skills/skill-script-runner.ts +24 -9
  470. package/src/tools/skills/skill-tool-factory.ts +1 -0
  471. package/src/tools/tasks/work-item-enqueue.ts +2 -2
  472. package/src/tools/terminal/evaluate-typescript.ts +21 -12
  473. package/src/tools/terminal/parser.ts +50 -0
  474. package/src/tools/types.ts +2 -0
  475. package/src/tools/watcher/delete.ts +6 -0
  476. package/src/tools/weather/service.ts +1 -1
  477. package/src/twitter/client.ts +190 -24
  478. package/src/twitter/router.ts +1 -1
  479. package/src/twitter/session.ts +4 -3
  480. package/src/util/clipboard.ts +1 -1
  481. package/src/util/errors.ts +65 -8
  482. package/src/util/fs.ts +40 -0
  483. package/src/util/json.ts +10 -0
  484. package/src/util/log-redact.ts +189 -0
  485. package/src/util/logger.ts +19 -17
  486. package/src/util/object.ts +3 -0
  487. package/src/util/platform.ts +105 -363
  488. package/src/util/pricing.ts +1 -1
  489. package/src/util/promise-guard.ts +1 -1
  490. package/src/util/retry.ts +19 -0
  491. package/src/util/row-mapper.ts +79 -0
  492. package/src/util/silently.ts +21 -0
  493. package/src/watcher/engine.ts +5 -1
  494. package/src/watcher/provider-types.ts +20 -0
  495. package/src/watcher/providers/github.ts +156 -0
  496. package/src/watcher/providers/gmail.ts +1 -0
  497. package/src/watcher/providers/google-calendar.ts +1 -0
  498. package/src/watcher/providers/linear.ts +460 -0
  499. package/src/watcher/providers/slack.ts +1 -0
  500. package/src/work-items/work-item-runner.ts +1 -1
  501. package/src/workspace/git-service.ts +1 -1
  502. package/src/workspace/provider-commit-message-generator.ts +51 -22
  503. package/src/__tests__/call-bridge.test.ts +0 -517
  504. package/src/__tests__/session-process-bridge.test.ts +0 -244
  505. package/src/calls/call-bridge.ts +0 -168
  506. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
@@ -0,0 +1,201 @@
1
+ /**
2
+ * SMS messaging provider adapter.
3
+ *
4
+ * Enables proactive outbound SMS messaging via the gateway's /deliver/sms
5
+ * endpoint. Similar to the Telegram provider, SMS delivery is proxied through
6
+ * the gateway which owns the Twilio credentials and handles the Messages API.
7
+ *
8
+ * Twilio credentials (account_sid, auth_token) and a configured phone number
9
+ * are required for connectivity. The phone number is resolved from the config
10
+ * (sms.phoneNumber), env var (TWILIO_PHONE_NUMBER), or secure key fallback.
11
+ *
12
+ * The `token` parameter in MessagingProvider methods is unused for SMS
13
+ * because delivery is authenticated via the gateway's bearer token, not
14
+ * a per-user OAuth token.
15
+ */
16
+
17
+ import type { MessagingProvider } from '../../provider.js';
18
+ import type {
19
+ Conversation,
20
+ Message,
21
+ SearchResult,
22
+ SendResult,
23
+ ConnectionInfo,
24
+ ListOptions,
25
+ HistoryOptions,
26
+ SearchOptions,
27
+ SendOptions,
28
+ } from '../../provider-types.js';
29
+ import { getSecureKey } from '../../../security/secure-keys.js';
30
+ import { readHttpToken } from '../../../util/platform.js';
31
+ import { loadConfig } from '../../../config/loader.js';
32
+ import { getGatewayInternalBaseUrl, getTwilioPhoneNumberEnv } from '../../../config/env.js';
33
+ import { getOrCreateConversation } from '../../../memory/conversation-key-store.js';
34
+ import * as externalConversationStore from '../../../memory/external-conversation-store.js';
35
+ import * as sms from './client.js';
36
+
37
+ /** Resolve the gateway base URL, preferring GATEWAY_INTERNAL_BASE_URL if set. */
38
+ function getGatewayUrl(): string {
39
+ return getGatewayInternalBaseUrl();
40
+ }
41
+
42
+ /** Read the runtime HTTP bearer token used to authenticate with the gateway. */
43
+ function getBearerToken(): string {
44
+ const token = readHttpToken();
45
+ if (!token) {
46
+ throw new Error('No runtime HTTP bearer token available — is the daemon running?');
47
+ }
48
+ return token;
49
+ }
50
+
51
+ /** Check whether Twilio credentials are stored. */
52
+ function hasTwilioCredentials(): boolean {
53
+ return (
54
+ !!getSecureKey('credential:twilio:account_sid') &&
55
+ !!getSecureKey('credential:twilio:auth_token')
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Resolve the configured SMS phone number.
61
+ * Priority: assistant-scoped phone number > TWILIO_PHONE_NUMBER env > config sms.phoneNumber > secure key fallback.
62
+ */
63
+ function getPhoneNumber(assistantId?: string): string | undefined {
64
+ // Check assistant-scoped phone number first
65
+ if (assistantId) {
66
+ try {
67
+ const config = loadConfig();
68
+ const assistantPhone = config.sms?.assistantPhoneNumbers?.[assistantId];
69
+ if (assistantPhone) return assistantPhone;
70
+ } catch {
71
+ // Config may not be available yet during early startup
72
+ }
73
+ }
74
+
75
+ const fromEnv = getTwilioPhoneNumberEnv();
76
+ if (fromEnv) return fromEnv;
77
+
78
+ try {
79
+ const config = loadConfig();
80
+ if (config.sms?.phoneNumber) return config.sms.phoneNumber;
81
+ } catch {
82
+ // Config may not be available yet during early startup
83
+ }
84
+
85
+ return getSecureKey('credential:twilio:phone_number') || undefined;
86
+ }
87
+
88
+ function hasAnyAssistantPhoneNumber(): boolean {
89
+ try {
90
+ const config = loadConfig();
91
+ return Object.keys(config.sms?.assistantPhoneNumbers ?? {}).length > 0;
92
+ } catch {
93
+ return false;
94
+ }
95
+ }
96
+
97
+ export const smsMessagingProvider: MessagingProvider = {
98
+ id: 'sms',
99
+ displayName: 'SMS',
100
+ credentialService: 'twilio',
101
+ capabilities: new Set(['send']),
102
+
103
+ /**
104
+ * SMS is connected when Twilio credentials are stored AND a phone number
105
+ * is configured. Without a phone number the gateway cannot determine
106
+ * the `from` for outbound messages.
107
+ */
108
+ isConnected(): boolean {
109
+ return hasTwilioCredentials() && (!!getPhoneNumber() || hasAnyAssistantPhoneNumber());
110
+ },
111
+
112
+ async testConnection(_token: string): Promise<ConnectionInfo> {
113
+ if (!hasTwilioCredentials()) {
114
+ return {
115
+ connected: false,
116
+ user: 'unknown',
117
+ platform: 'sms',
118
+ metadata: { error: 'No Twilio credentials found. Run the twilio-setup skill.' },
119
+ };
120
+ }
121
+
122
+ const phoneNumber = getPhoneNumber();
123
+ if (!phoneNumber && !hasAnyAssistantPhoneNumber()) {
124
+ return {
125
+ connected: false,
126
+ user: 'unknown',
127
+ platform: 'sms',
128
+ metadata: { error: 'No phone number configured. Run the twilio-setup skill to assign a number.' },
129
+ };
130
+ }
131
+
132
+ const accountSid = getSecureKey('credential:twilio:account_sid')!;
133
+
134
+ return {
135
+ connected: true,
136
+ user: phoneNumber ?? 'assistant-scoped numbers configured',
137
+ platform: 'sms',
138
+ metadata: {
139
+ accountSid: accountSid.slice(0, 6) + '...',
140
+ ...(phoneNumber ? { phoneNumber } : {}),
141
+ hasAssistantScopedPhoneNumbers: hasAnyAssistantPhoneNumber(),
142
+ },
143
+ };
144
+ },
145
+
146
+ async sendMessage(_token: string, conversationId: string, text: string, options?: SendOptions): Promise<SendResult> {
147
+ const gatewayUrl = getGatewayUrl();
148
+ const bearerToken = getBearerToken();
149
+ const assistantId = options?.assistantId;
150
+
151
+ const sendResult = await sms.sendMessage(gatewayUrl, bearerToken, conversationId, text, assistantId);
152
+
153
+ // Upsert external conversation binding so the conversation key mapping
154
+ // exists for the next inbound SMS from this number.
155
+ try {
156
+ const sourceChannel = 'sms';
157
+ const conversationKey = assistantId && assistantId !== 'self'
158
+ ? `asst:${assistantId}:${sourceChannel}:${conversationId}`
159
+ : `${sourceChannel}:${conversationId}`;
160
+ const { conversationId: internalId } = getOrCreateConversation(conversationKey);
161
+ // external_conversation_bindings is assistant-agnostic (unique by
162
+ // sourceChannel + externalChatId). Restrict proactive writes to self so
163
+ // multi-assistant sends cannot clobber each other's binding metadata.
164
+ if (!assistantId || assistantId === 'self') {
165
+ externalConversationStore.upsertOutboundBinding({
166
+ conversationId: internalId,
167
+ sourceChannel,
168
+ externalChatId: conversationId,
169
+ });
170
+ }
171
+ } catch {
172
+ // Best-effort — don't fail the send if binding upsert fails
173
+ }
174
+
175
+ // Use the Twilio message SID as the send result ID when available,
176
+ // falling back to a timestamp-based ID for older gateway versions.
177
+ const id = sendResult.messageSid || `sms-${Date.now()}`;
178
+
179
+ return {
180
+ id,
181
+ timestamp: Date.now(),
182
+ conversationId,
183
+ };
184
+ },
185
+
186
+ // SMS does not support listing conversations. The assistant can only
187
+ // send to known phone numbers (conversation IDs).
188
+ async listConversations(_token: string, _options?: ListOptions): Promise<Conversation[]> {
189
+ return [];
190
+ },
191
+
192
+ // SMS does not provide message history retrieval via the gateway.
193
+ async getHistory(_token: string, _conversationId: string, _options?: HistoryOptions): Promise<Message[]> {
194
+ return [];
195
+ },
196
+
197
+ // SMS does not support message search.
198
+ async search(_token: string, _query: string, _options?: SearchOptions): Promise<SearchResult> {
199
+ return { total: 0, messages: [], hasMore: false };
200
+ },
201
+ };
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Low-level SMS operations.
3
+ *
4
+ * Outbound message delivery routes through the gateway's /deliver/sms
5
+ * endpoint, which handles Twilio credential management and the Messages API.
6
+ * The gateway resolves the `from` number using the optional assistantId or
7
+ * its default Twilio phone number configuration.
8
+ */
9
+
10
+ const DELIVERY_TIMEOUT_MS = 30_000;
11
+
12
+ export class SmsApiError extends Error {
13
+ constructor(
14
+ public readonly status: number,
15
+ message: string,
16
+ ) {
17
+ super(message);
18
+ this.name = 'SmsApiError';
19
+ }
20
+ }
21
+
22
+ /** Payload accepted by the gateway's /deliver/sms endpoint. */
23
+ interface DeliverPayload {
24
+ to: string;
25
+ text: string;
26
+ assistantId?: string;
27
+ }
28
+
29
+ /** Result returned by sendMessage with Twilio acceptance details. */
30
+ export interface SmsSendResult {
31
+ messageSid?: string;
32
+ status?: string;
33
+ errorCode?: string | null;
34
+ errorMessage?: string | null;
35
+ }
36
+
37
+ /**
38
+ * Send an SMS message via the gateway's /deliver/sms endpoint.
39
+ *
40
+ * Returns Twilio acceptance details propagated from the gateway.
41
+ * "Accepted" means Twilio received it for delivery -- it has NOT yet
42
+ * been confirmed as delivered to the handset.
43
+ */
44
+ export async function sendMessage(
45
+ gatewayUrl: string,
46
+ bearerToken: string,
47
+ to: string,
48
+ text: string,
49
+ assistantId?: string,
50
+ ): Promise<SmsSendResult> {
51
+ const payload: DeliverPayload = { to, text };
52
+ if (assistantId) {
53
+ payload.assistantId = assistantId;
54
+ }
55
+
56
+ const url = `${gatewayUrl}/deliver/sms`;
57
+ const resp = await fetch(url, {
58
+ method: 'POST',
59
+ headers: {
60
+ 'Content-Type': 'application/json',
61
+ Authorization: `Bearer ${bearerToken}`,
62
+ },
63
+ body: JSON.stringify(payload),
64
+ signal: AbortSignal.timeout(DELIVERY_TIMEOUT_MS),
65
+ });
66
+
67
+ if (!resp.ok) {
68
+ const body = await resp.text().catch(() => '<unreadable>');
69
+ throw new SmsApiError(
70
+ resp.status,
71
+ `Gateway /deliver/sms failed (${resp.status}): ${body}`,
72
+ );
73
+ }
74
+
75
+ try {
76
+ const data = (await resp.json()) as {
77
+ ok?: boolean;
78
+ messageSid?: string;
79
+ status?: string;
80
+ errorCode?: string | null;
81
+ errorMessage?: string | null;
82
+ };
83
+ return {
84
+ messageSid: data.messageSid,
85
+ status: data.status,
86
+ errorCode: data.errorCode,
87
+ errorMessage: data.errorMessage,
88
+ };
89
+ } catch {
90
+ // Older gateway versions may not return JSON with Twilio details
91
+ return {};
92
+ }
93
+ }
@@ -0,0 +1,7 @@
1
+ /** Twilio SMS types used by the messaging provider. */
2
+
3
+ export interface TwilioAccountInfo {
4
+ accountSid: string;
5
+ friendlyName: string;
6
+ phoneNumber: string;
7
+ }
@@ -25,17 +25,14 @@ import type {
25
25
  } from '../../provider-types.js';
26
26
  import { getSecureKey } from '../../../security/secure-keys.js';
27
27
  import { readHttpToken } from '../../../util/platform.js';
28
+ import { getGatewayInternalBaseUrl } from '../../../config/env.js';
28
29
  import { getOrCreateConversation } from '../../../memory/conversation-key-store.js';
29
30
  import * as externalConversationStore from '../../../memory/external-conversation-store.js';
30
31
  import * as telegram from './client.js';
31
32
 
32
33
  /** Resolve the gateway base URL, preferring GATEWAY_INTERNAL_BASE_URL if set. */
33
34
  function getGatewayUrl(): string {
34
- if (process.env.GATEWAY_INTERNAL_BASE_URL) {
35
- return process.env.GATEWAY_INTERNAL_BASE_URL.replace(/\/+$/, "");
36
- }
37
- const port = Number(process.env.GATEWAY_PORT) || 7830;
38
- return `http://127.0.0.1:${port}`;
35
+ return getGatewayInternalBaseUrl();
39
36
  }
40
37
 
41
38
  /** Read the runtime HTTP bearer token used to authenticate with the gateway. */
@@ -0,0 +1,136 @@
1
+ /**
2
+ * WhatsApp Business messaging provider adapter.
3
+ *
4
+ * Enables proactive outbound WhatsApp messaging via the gateway's /deliver/whatsapp
5
+ * endpoint. Delivery is proxied through the gateway which owns the Meta Cloud API
6
+ * credentials (phone_number_id + access_token).
7
+ *
8
+ * The `token` parameter in MessagingProvider methods is unused for WhatsApp
9
+ * because delivery is authenticated via the gateway's bearer token, not
10
+ * a per-user OAuth token.
11
+ */
12
+
13
+ import type { MessagingProvider } from '../../provider.js';
14
+ import type {
15
+ Conversation,
16
+ Message,
17
+ SearchResult,
18
+ SendResult,
19
+ ConnectionInfo,
20
+ ListOptions,
21
+ HistoryOptions,
22
+ SearchOptions,
23
+ SendOptions,
24
+ } from '../../provider-types.js';
25
+ import { getSecureKey } from '../../../security/secure-keys.js';
26
+ import { readHttpToken } from '../../../util/platform.js';
27
+ import { getGatewayInternalBaseUrl } from '../../../config/env.js';
28
+ import { getOrCreateConversation } from '../../../memory/conversation-key-store.js';
29
+ import * as externalConversationStore from '../../../memory/external-conversation-store.js';
30
+ import * as whatsapp from './client.js';
31
+
32
+ /** Resolve the gateway base URL. */
33
+ function getGatewayUrl(): string {
34
+ return getGatewayInternalBaseUrl();
35
+ }
36
+
37
+ /** Read the runtime HTTP bearer token used to authenticate with the gateway. */
38
+ function getBearerToken(): string {
39
+ const token = readHttpToken();
40
+ if (!token) {
41
+ throw new Error('No runtime HTTP bearer token available — is the daemon running?');
42
+ }
43
+ return token;
44
+ }
45
+
46
+ /** Check whether WhatsApp credentials are stored. */
47
+ function hasWhatsAppCredentials(): boolean {
48
+ return (
49
+ !!getSecureKey('credential:whatsapp:phone_number_id') &&
50
+ !!getSecureKey('credential:whatsapp:access_token')
51
+ );
52
+ }
53
+
54
+ export const whatsappMessagingProvider: MessagingProvider = {
55
+ id: 'whatsapp',
56
+ displayName: 'WhatsApp',
57
+ credentialService: 'whatsapp',
58
+ capabilities: new Set(['send']),
59
+
60
+ /**
61
+ * WhatsApp is connected when Meta Cloud API credentials are stored.
62
+ */
63
+ isConnected(): boolean {
64
+ return hasWhatsAppCredentials();
65
+ },
66
+
67
+ async testConnection(_token: string): Promise<ConnectionInfo> {
68
+ if (!hasWhatsAppCredentials()) {
69
+ return {
70
+ connected: false,
71
+ user: 'unknown',
72
+ platform: 'whatsapp',
73
+ metadata: { error: 'No WhatsApp credentials found. Configure WHATSAPP_PHONE_NUMBER_ID and WHATSAPP_ACCESS_TOKEN.' },
74
+ };
75
+ }
76
+
77
+ const phoneNumberId = getSecureKey('credential:whatsapp:phone_number_id')!;
78
+
79
+ return {
80
+ connected: true,
81
+ user: phoneNumberId,
82
+ platform: 'whatsapp',
83
+ metadata: {
84
+ phoneNumberId: phoneNumberId.slice(0, 6) + '...',
85
+ },
86
+ };
87
+ },
88
+
89
+ async sendMessage(_token: string, conversationId: string, text: string, options?: SendOptions): Promise<SendResult> {
90
+ const gatewayUrl = getGatewayUrl();
91
+ const bearerToken = getBearerToken();
92
+ const assistantId = options?.assistantId;
93
+
94
+ await whatsapp.sendMessage(gatewayUrl, bearerToken, conversationId, text, assistantId);
95
+
96
+ // Upsert external conversation binding so the conversation key mapping
97
+ // exists for the next inbound WhatsApp message from this number.
98
+ try {
99
+ const sourceChannel = 'whatsapp';
100
+ const conversationKey = assistantId && assistantId !== 'self'
101
+ ? `asst:${assistantId}:${sourceChannel}:${conversationId}`
102
+ : `${sourceChannel}:${conversationId}`;
103
+ const { conversationId: internalId } = getOrCreateConversation(conversationKey);
104
+ if (!assistantId || assistantId === 'self') {
105
+ externalConversationStore.upsertOutboundBinding({
106
+ conversationId: internalId,
107
+ sourceChannel,
108
+ externalChatId: conversationId,
109
+ });
110
+ }
111
+ } catch {
112
+ // Best-effort — don't fail the send if binding upsert fails
113
+ }
114
+
115
+ return {
116
+ id: `whatsapp-${Date.now()}`,
117
+ timestamp: Date.now(),
118
+ conversationId,
119
+ };
120
+ },
121
+
122
+ // WhatsApp does not support listing conversations via this provider.
123
+ async listConversations(_token: string, _options?: ListOptions): Promise<Conversation[]> {
124
+ return [];
125
+ },
126
+
127
+ // WhatsApp does not provide message history retrieval via the gateway.
128
+ async getHistory(_token: string, _conversationId: string, _options?: HistoryOptions): Promise<Message[]> {
129
+ return [];
130
+ },
131
+
132
+ // WhatsApp does not support message search.
133
+ async search(_token: string, _query: string, _options?: SearchOptions): Promise<SearchResult> {
134
+ return { total: 0, messages: [], hasMore: false };
135
+ },
136
+ };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Low-level WhatsApp operations.
3
+ *
4
+ * Outbound message delivery routes through the gateway's /deliver/whatsapp
5
+ * endpoint, which handles WhatsApp credential management and the Meta Cloud API.
6
+ */
7
+
8
+ const DELIVERY_TIMEOUT_MS = 30_000;
9
+
10
+ export class WhatsAppApiError extends Error {
11
+ constructor(
12
+ public readonly status: number,
13
+ message: string,
14
+ ) {
15
+ super(message);
16
+ this.name = 'WhatsAppApiError';
17
+ }
18
+ }
19
+
20
+ /** Payload accepted by the gateway's /deliver/whatsapp endpoint. */
21
+ interface DeliverPayload {
22
+ to: string;
23
+ text: string;
24
+ assistantId?: string;
25
+ }
26
+
27
+ /** Result returned by sendMessage. */
28
+ export interface WhatsAppSendResult {
29
+ ok: boolean;
30
+ }
31
+
32
+ /**
33
+ * Send a WhatsApp message via the gateway's /deliver/whatsapp endpoint.
34
+ */
35
+ export async function sendMessage(
36
+ gatewayUrl: string,
37
+ bearerToken: string,
38
+ to: string,
39
+ text: string,
40
+ assistantId?: string,
41
+ ): Promise<WhatsAppSendResult> {
42
+ const payload: DeliverPayload = { to, text };
43
+ if (assistantId) {
44
+ payload.assistantId = assistantId;
45
+ }
46
+
47
+ const url = `${gatewayUrl}/deliver/whatsapp`;
48
+ const resp = await fetch(url, {
49
+ method: 'POST',
50
+ headers: {
51
+ 'Content-Type': 'application/json',
52
+ Authorization: `Bearer ${bearerToken}`,
53
+ },
54
+ body: JSON.stringify(payload),
55
+ signal: AbortSignal.timeout(DELIVERY_TIMEOUT_MS),
56
+ });
57
+
58
+ if (!resp.ok) {
59
+ const body = await resp.text().catch(() => '<unreadable>');
60
+ throw new WhatsAppApiError(
61
+ resp.status,
62
+ `Gateway /deliver/whatsapp failed (${resp.status}): ${body}`,
63
+ );
64
+ }
65
+
66
+ return { ok: true };
67
+ }
@@ -9,8 +9,7 @@
9
9
  import type { Message as ProviderMessage } from './provider-types.js';
10
10
  import type { Message, ToolDefinition } from '../providers/types.js';
11
11
  import { truncate } from '../util/truncate.js';
12
- import { getProvider } from '../providers/registry.js';
13
- import { getConfig } from '../config/loader.js';
12
+ import { getConfiguredProvider } from '../providers/provider-send-message.js';
14
13
 
15
14
  export interface StylePattern {
16
15
  aspect: string;
@@ -118,8 +117,10 @@ export async function extractStylePatterns(
118
117
 
119
118
  const corpus = corpusEntries.map((e, i) => `--- Message ${i + 1} ---\n${e}`).join('\n\n');
120
119
 
121
- const config = getConfig();
122
- const provider = getProvider(config.provider);
120
+ const provider = getConfiguredProvider();
121
+ if (!provider) {
122
+ return { stylePatterns: [], contactObservations: [] };
123
+ }
123
124
  const promptMessages: Message[] = [{
124
125
  role: 'user',
125
126
  content: [{ type: 'text', text: `Analyze these ${corpusEntries.length} sent messages for writing style patterns:\n\n${corpus}` }],