@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,216 @@
1
+ ---
2
+ name: "SMS Setup"
3
+ description: "Set up and troubleshoot SMS messaging with guided Twilio configuration, compliance, and verification"
4
+ user-invocable: true
5
+ metadata: {"vellum": {"emoji": "\ud83d\udce8"}}
6
+ ---
7
+
8
+ You are helping your user set up SMS messaging. This skill orchestrates Twilio setup, SMS-specific compliance, and end-to-end testing through a conversational flow.
9
+
10
+ ## Step 1: Check Channel Readiness
11
+
12
+ First, check the current SMS channel readiness state by sending the `channel_readiness` IPC message:
13
+
14
+ ```json
15
+ {
16
+ "type": "channel_readiness",
17
+ "action": "get",
18
+ "channel": "sms"
19
+ }
20
+ ```
21
+
22
+ Inspect the `channel_readiness_response`. The response contains `snapshots` with each channel's readiness state.
23
+
24
+ - If the SMS channel shows `ready: true` and all `localChecks` pass, skip to Step 3.
25
+ - If any local checks fail, proceed to Step 2 to fix the baseline.
26
+
27
+ ## Step 2: Establish Baseline (Twilio Setup)
28
+
29
+ If SMS baseline is not ready (missing credentials, phone number, or ingress), load the `twilio-setup` skill to walk the user through the basics:
30
+
31
+ ```
32
+ skill_load skill=twilio-setup
33
+ ```
34
+
35
+ Tell the user: *"SMS needs Twilio configured first. I've loaded the Twilio setup guide — let's walk through it."*
36
+
37
+ After twilio-setup completes, re-check readiness:
38
+
39
+ ```json
40
+ {
41
+ "type": "channel_readiness",
42
+ "action": "refresh",
43
+ "channel": "sms"
44
+ }
45
+ ```
46
+
47
+ If baseline is still not ready, report the specific failures and ask the user to address them before continuing.
48
+
49
+ ## Step 3: Remote Compliance Check
50
+
51
+ Once baseline is ready, run a full readiness check including remote (Twilio API) checks:
52
+
53
+ ```json
54
+ {
55
+ "type": "channel_readiness",
56
+ "action": "refresh",
57
+ "channel": "sms",
58
+ "includeRemote": true
59
+ }
60
+ ```
61
+
62
+ Examine the remote check results:
63
+ - If all remote checks pass, proceed to Step 4.
64
+ - If compliance issues are found (e.g., toll-free verification needed), guide the user through the compliance flow.
65
+
66
+ ### Toll-Free Verification Submission
67
+
68
+ When the remote check returns `toll_free_verification` as a failing check, the assistant must submit verification directly to the Twilio API. The daemon does not yet have an IPC action for this, so use the Twilio REST API directly.
69
+
70
+ **Prerequisites:** The assistant needs the Account SID and Auth Token. These are stored in daemon secure storage and can be accessed by importing `getSecureKey` from the daemon's `security/secure-keys` module:
71
+
72
+ ```typescript
73
+ import { getSecureKey } from "./src/security/secure-keys.js";
74
+ const accountSid = getSecureKey("credential:twilio:account_sid");
75
+ const authToken = getSecureKey("credential:twilio:auth_token");
76
+ ```
77
+
78
+ **Step 3a: Look up the phone number SID.** The toll-free verification API requires the phone number's SID (format `PNxxxx`), not the E.164 number itself:
79
+
80
+ ```
81
+ GET https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers.json?PhoneNumber={E.164 number}
82
+ ```
83
+
84
+ Extract the `sid` field from the matching number in `incoming_phone_numbers`.
85
+
86
+ **Step 3b: Check for existing verifications.** Before submitting, check if a verification already exists:
87
+
88
+ ```
89
+ GET https://messaging.twilio.com/v1/Tollfree/Verifications
90
+ ```
91
+
92
+ If a verification already exists for this number, report its status to the user and skip submission.
93
+
94
+ **Step 3c: Check Trust Hub profile assignments.** Twilio auto-attaches toll-free numbers to their assigned Trust Hub Customer Profile. The verification API rejects submissions when the number is attached to a Primary Customer Profile (PCP). It requires either no profile, a Starter profile, or a Secondary Customer Profile (SCP).
95
+
96
+ Check if the number is assigned to a profile:
97
+
98
+ ```
99
+ GET https://trusthub.twilio.com/v1/CustomerProfiles?PageSize=50
100
+ ```
101
+
102
+ For each profile, check `ChannelEndpointAssignments`:
103
+
104
+ ```
105
+ GET https://trusthub.twilio.com/v1/CustomerProfiles/{ProfileSid}/ChannelEndpointAssignments?PageSize=50
106
+ ```
107
+
108
+ If the number is assigned to a Primary profile:
109
+ 1. **Tell the user** the number is linked to a Primary Customer Profile, which blocks toll-free verification.
110
+ 2. **Offer two options:**
111
+ - **Option A:** Remove the number from the Primary profile (DELETE the ChannelEndpointAssignment), then resubmit. Warn that this may affect other services tied to that profile.
112
+ - **Option B:** Wait for the Starter profile to be approved (if one exists and is `in-review`), then link the number to that profile instead.
113
+ 3. **Do not silently retry.** The same error will recur until the profile assignment is resolved.
114
+
115
+ **Step 3d: Collect user information.** Collect the following from the user (assume individual/sole proprietor by default):
116
+
117
+ | Field | API Parameter | Notes |
118
+ |---|---|---|
119
+ | Name | `BusinessName` | Can be personal name |
120
+ | Business type | `BusinessType` | Use `SOLE_PROPRIETOR` for individuals. Valid values: `PRIVATE_PROFIT`, `PUBLIC_PROFIT`, `SOLE_PROPRIETOR`, `NON_PROFIT`, `GOVERNMENT` |
121
+ | Website | `BusinessWebsite` | LinkedIn or personal site is fine |
122
+ | Street address | `BusinessStreetAddress` | |
123
+ | City | `BusinessCity` | |
124
+ | State | `BusinessStateProvinceRegion` | |
125
+ | Zip | `BusinessPostalCode` | |
126
+ | Country | `BusinessCountry` | Two-letter ISO code, e.g. `US` |
127
+ | Notification email | `NotificationEmail` | Where Twilio sends status updates |
128
+ | Contact phone | `BusinessContactPhone` | E.164 format |
129
+ | Contact first name | `BusinessContactFirstName` | |
130
+ | Contact last name | `BusinessContactLastName` | |
131
+ | Contact email | `BusinessContactEmail` | |
132
+ | Use case category | `UseCaseCategories` | e.g. `ACCOUNT_NOTIFICATIONS` |
133
+ | Use case summary | `UseCaseSummary` | Plain English description |
134
+ | Message volume | `MessageVolume` | Estimated monthly messages, e.g. `100` |
135
+ | Sample message | `ProductionMessageSample` | A realistic example message |
136
+ | Opt-in type | `OptInType` | `VERBAL`, `WEB_FORM`, `PAPER_FORM`, `VIA_TEXT`, `MOBILE_QR_CODE` |
137
+ | Opt-in image URL | `OptInImageUrls` | URL showing opt-in mechanism (can be website URL) |
138
+
139
+ Do NOT ask for EIN, business registration number, or business registration authority. Explain that Twilio labels some fields as "business" fields even for individual submitters.
140
+
141
+ **Step 3e: Submit verification:**
142
+
143
+ ```
144
+ POST https://messaging.twilio.com/v1/Tollfree/Verifications
145
+ Content-Type: application/x-www-form-urlencoded
146
+ ```
147
+
148
+ With all fields as form-encoded parameters, including `TollfreePhoneNumberSid` (the PN SID from Step 3a).
149
+
150
+ **Common errors:**
151
+ - `"BusinessType must be one of [...]"` — Use exact enum values listed above
152
+ - `"Customer profiles submitted with verifications must be either ISV Starters or Secondary Customer Profiles"` — The number is linked to a Primary profile. See Step 3c above.
153
+ - `400` or `20001` errors — Check the `message` field for specifics and report to user
154
+
155
+ **On success:** Tell the user the verification has been submitted and is now `PENDING_REVIEW`. Twilio typically reviews within 1-5 business days. They'll receive status updates at the notification email provided.
156
+
157
+ **On failure:** Report the exact error message and guide the user through resolution.
158
+
159
+ ## Step 4: Test Send
160
+
161
+ Run a test SMS to verify end-to-end delivery:
162
+
163
+ Tell the user: *"Let's send a test SMS to verify everything works. What phone number should I send the test to?"*
164
+
165
+ **Important:** If toll-free verification is pending (not yet approved), inform the user that test messages may be silently dropped by carriers even though Twilio accepts them. Offer to attempt the test anyway, but set expectations.
166
+
167
+ **Trial account limitation:** On Twilio trial accounts, SMS can only be sent to verified phone numbers. If the send fails with a "not verified" error, tell the user to verify the recipient number in the Twilio Console under Verified Caller IDs, or upgrade their account.
168
+
169
+ After the user provides a number, send a test message using the messaging tools:
170
+ - Use `messaging_send` with `platform: "sms"`, `conversation_id: "<phone number>"`, and a test message like "Test SMS from your Vellum assistant."
171
+ - Report the result honestly:
172
+ - If the send succeeds: *"The message was accepted by Twilio. Note: 'accepted' means Twilio received it for delivery, not that it reached the handset yet. Delivery can take a few seconds to a few minutes. If verification is still pending, carriers may silently drop the message."*
173
+ - If the send fails: report the error and suggest troubleshooting steps
174
+
175
+ ## Step 5: Final Status Report
176
+
177
+ After completing (or skipping) the test, present a clear summary:
178
+
179
+ **If everything passed:**
180
+ *"SMS is ready! Here's your setup status:"*
181
+ - Twilio credentials: configured
182
+ - Phone number: {number}
183
+ - Ingress: configured
184
+ - Compliance: {status}
185
+ - Test send: {result}
186
+
187
+ **If there are blockers:**
188
+ *"SMS setup is partially complete. Here's what still needs attention:"*
189
+ - List each blocker with the specific next action
190
+
191
+ ## Troubleshooting
192
+
193
+ If the user returns to this skill after initial setup:
194
+ 1. Always start with Step 1 (readiness check) to assess current state
195
+ 2. Skip steps that are already complete
196
+ 3. Focus on the specific issue the user is experiencing
197
+
198
+ Common issues:
199
+ - **"Messages not delivering"** — Check compliance status (toll-free verification), verify the number isn't flagged
200
+ - **"Twilio error on send"** — Check credentials, phone number assignment, and ingress
201
+ - **"Trial account limitations"** — Explain that trial accounts can only send to verified numbers
202
+ - **"Customer profiles must be ISV Starters or Secondary"** — The toll-free number is linked to a Primary Customer Profile in Trust Hub. Must be unlinked or reassigned before verification can be submitted.
203
+
204
+ ## Accessing the Twilio API
205
+
206
+ The skill references IPC messages (`channel_readiness`, `twilio_config`) that are sent via Unix socket to the daemon. The assistant does not have an HTTP endpoint for IPC. Use the following pattern to send IPC messages:
207
+
208
+ ```bash
209
+ cd "$(git rev-parse --show-toplevel)/assistant" && bun -e '
210
+ import { sendOneMessage } from "./src/cli/ipc-client.js";
211
+ const res = await sendOneMessage({ type: "twilio_config", action: "get" });
212
+ console.log(JSON.stringify(res, null, 2));
213
+ '
214
+ ```
215
+
216
+ For direct Twilio REST API calls (e.g., toll-free verification submission), use the same `bun -e` pattern with `getSecureKey` from `./src/security/secure-keys.js` to retrieve credentials, then use `fetch()`.
@@ -18,6 +18,27 @@ This skill manages the full Twilio lifecycle:
18
18
 
19
19
  All operations go through the `twilio_config` IPC handler on the daemon, which validates inputs, stores credentials securely, and manages phone number state.
20
20
 
21
+ ### Multi-Assistant Setups
22
+
23
+ In a multi-assistant environment (multiple assistants sharing the same daemon), some `twilio_config` actions are **assistant-scoped** while others are **global** (shared across all assistants):
24
+
25
+ **Global actions** (ignore `assistantId` — credentials are shared across all assistants):
26
+ - `set_credentials` — Stores Account SID and Auth Token in global secure storage (`credential:twilio:*` keys). All assistants share the same Twilio account credentials.
27
+ - `clear_credentials` — Removes the globally stored Account SID and Auth Token. This affects all assistants.
28
+
29
+ **Assistant-scoped actions** (use `assistantId` to scope phone number configuration per assistant):
30
+ - `get` — Returns the phone number assigned to the specified assistant (falls back to the legacy global number if no per-assistant mapping exists).
31
+ - `assign_number` — Assigns a phone number to a specific assistant via the per-assistant mapping.
32
+ - `provision_number` — Provisions a new number and assigns it to the specified assistant.
33
+ - `list_numbers` — Lists all phone numbers on the shared Twilio account (uses global credentials).
34
+
35
+ Include `assistantId` in assistant-scoped actions whenever:
36
+ - Multiple assistants share the same Twilio account but use different phone numbers
37
+ - You want to ensure configuration changes only affect a specific assistant
38
+ - The user has explicitly selected or referenced a particular assistant
39
+
40
+ All IPC examples below include the optional `assistantId` field in assistant-scoped actions. Omit it in single-assistant setups. For global actions (`set_credentials`, `clear_credentials`), the `assistantId` field is accepted but ignored.
41
+
21
42
  ## Step 1: Check Current Configuration
22
43
 
23
44
  First, check whether Twilio is already configured by sending the `twilio_config` IPC message with `action: "get"`:
@@ -25,7 +46,8 @@ First, check whether Twilio is already configured by sending the `twilio_config`
25
46
  ```json
26
47
  {
27
48
  "type": "twilio_config",
28
- "action": "get"
49
+ "action": "get",
50
+ "assistantId": "<optional — omit for single-assistant setups>"
29
51
  }
30
52
  ```
31
53
 
@@ -62,6 +84,8 @@ After both credentials are collected, retrieve them from secure storage and pass
62
84
 
63
85
  Both `accountSid` and `authToken` are required — the daemon validates the credentials against the Twilio API before storing them. If credentials are invalid, the daemon returns an error. Tell the user and ask them to re-enter via the secure prompt.
64
86
 
87
+ **Note:** `set_credentials` is a global operation — credentials are stored once and shared across all assistants. The `assistantId` field is accepted but ignored.
88
+
65
89
  ## Step 3: Get a Phone Number
66
90
 
67
91
  The assistant needs a phone number to make calls and send SMS. There are two paths:
@@ -75,7 +99,8 @@ If the user wants to buy a new number through Twilio, send:
75
99
  "type": "twilio_config",
76
100
  "action": "provision_number",
77
101
  "areaCode": "415",
78
- "country": "US"
102
+ "country": "US",
103
+ "assistantId": "<optional — omit for single-assistant setups>"
79
104
  }
80
105
  ```
81
106
 
@@ -100,7 +125,8 @@ If the user already has a Twilio phone number, first list available numbers:
100
125
  ```json
101
126
  {
102
127
  "type": "twilio_config",
103
- "action": "list_numbers"
128
+ "action": "list_numbers",
129
+ "assistantId": "<optional — omit for single-assistant setups>"
104
130
  }
105
131
  ```
106
132
 
@@ -112,7 +138,8 @@ Then assign the chosen number:
112
138
  {
113
139
  "type": "twilio_config",
114
140
  "action": "assign_number",
115
- "phoneNumber": "+14155551234"
141
+ "phoneNumber": "+14155551234",
142
+ "assistantId": "<optional — omit for single-assistant setups>"
116
143
  }
117
144
  ```
118
145
 
@@ -132,7 +159,8 @@ Then assign it through the IPC:
132
159
  {
133
160
  "type": "twilio_config",
134
161
  "action": "assign_number",
135
- "phoneNumber": "+14155551234"
162
+ "phoneNumber": "+14155551234",
163
+ "assistantId": "<optional — omit for single-assistant setups>"
136
164
  }
137
165
  ```
138
166
 
@@ -181,7 +209,8 @@ Now link the user's phone number as the trusted SMS guardian for this assistant.
181
209
  {
182
210
  "type": "guardian_verification",
183
211
  "action": "create_challenge",
184
- "channel": "sms"
212
+ "channel": "sms",
213
+ "assistantId": "<optional — omit for single-assistant setups>"
185
214
  }
186
215
  ```
187
216
 
@@ -195,7 +224,8 @@ Now link the user's phone number as the trusted SMS guardian for this assistant.
195
224
  {
196
225
  "type": "guardian_verification",
197
226
  "action": "status",
198
- "channel": "sms"
227
+ "channel": "sms",
228
+ "assistantId": "<optional — omit for single-assistant setups>"
199
229
  }
200
230
  ```
201
231
 
@@ -232,7 +262,9 @@ If the user wants to disconnect Twilio, send:
232
262
  }
233
263
  ```
234
264
 
235
- This removes the stored Account SID and Auth Token. Your phone number assignment will be preserved. Voice calls and SMS will stop working until credentials are reconfigured.
265
+ This removes the stored Account SID and Auth Token. Phone number assignments are preserved. Voice calls and SMS will stop working until credentials are reconfigured.
266
+
267
+ **Note:** `clear_credentials` is a global operation — it removes credentials for all assistants, not just the current one. The `assistantId` field is accepted but ignored. In multi-assistant setups, warn the user that clearing credentials will affect all assistants sharing this Twilio account.
236
268
 
237
269
  ## Troubleshooting
238
270
 
@@ -112,7 +112,7 @@ export class ContextWindowManager {
112
112
  };
113
113
  }
114
114
 
115
- const summaryOffset = existingSummary !== null ? 1 : 0;
115
+ const summaryOffset = existingSummary != null ? 1 : 0;
116
116
  const userTurnStarts = collectUserTurnStartIndexes(messages);
117
117
  if (userTurnStarts.length === 0) {
118
118
  return {
@@ -186,14 +186,34 @@ export class ContextWindowManager {
186
186
  const projectedGainTokens = Math.max(0, previousEstimatedInputTokens - projectedInputTokens);
187
187
  const severePressure = previousEstimatedInputTokens >= Math.floor(this.config.maxInputTokens * SEVERE_PRESSURE_RATIO);
188
188
  const lastCompactedAt = options?.lastCompactedAt;
189
- const withinCooldown = typeof lastCompactedAt === 'number'
190
- && Date.now() - lastCompactedAt < COMPACTION_COOLDOWN_MS;
191
189
 
190
+ // Adaptive cooldown: conversations growing quickly (high projected gain) compact
191
+ // sooner. Scale the cooldown inversely with the growth-rate multiplier, capped at
192
+ // 1/4 of the base cooldown so we never check more than 4× as frequently.
193
+ const growthRateMultiplier = Math.max(1, projectedGainTokens / MIN_GAIN_TOKENS_DURING_COOLDOWN);
194
+ const adaptiveCooldownMs = Math.max(
195
+ COMPACTION_COOLDOWN_MS / 4,
196
+ COMPACTION_COOLDOWN_MS / growthRateMultiplier,
197
+ );
198
+ const withinCooldown = typeof lastCompactedAt === 'number'
199
+ && Date.now() - lastCompactedAt < adaptiveCooldownMs;
200
+
201
+ // The adaptive cooldown is already tuned to be shorter for fast-growing
202
+ // conversations (high projectedGainTokens → smaller adaptiveCooldownMs).
203
+ // Removing the redundant MIN_GAIN_TOKENS_DURING_COOLDOWN guard here lets
204
+ // that shorter cooldown actually gate compaction: high-growth conversations
205
+ // break out of the cooldown sooner and compact more frequently.
206
+ // force=true bypasses the cooldown so context-too-large recovery can always
207
+ // attempt a compaction even within the cooldown window.
192
208
  if (
193
209
  withinCooldown
194
- && projectedGainTokens < MIN_GAIN_TOKENS_DURING_COOLDOWN
195
210
  && !severePressure
211
+ && !options?.force
196
212
  ) {
213
+ log.debug(
214
+ { projectedGainTokens, adaptiveCooldownMs, growthRateMultiplier, msSinceCompaction: typeof lastCompactedAt === 'number' ? Date.now() - lastCompactedAt : null },
215
+ 'Compaction cooldown active',
216
+ );
197
217
  return {
198
218
  messages,
199
219
  compacted: false,
@@ -208,7 +228,7 @@ export class ContextWindowManager {
208
228
  summaryOutputTokens: 0,
209
229
  summaryModel: '',
210
230
  summaryText: existingSummary ?? '',
211
- reason: 'compaction cooldown active with low projected gain',
231
+ reason: 'compaction cooldown active',
212
232
  };
213
233
  }
214
234
 
@@ -355,7 +375,7 @@ function collectUserTurnStartIndexes(messages: Message[]): number[] {
355
375
  for (let i = 0; i < messages.length; i++) {
356
376
  const message = messages[i];
357
377
  if (message.role !== 'user') continue;
358
- if (getSummaryFromContextMessage(message) !== null) continue;
378
+ if (getSummaryFromContextMessage(message) !== undefined) continue;
359
379
  if (isToolResultOnly(message)) continue;
360
380
  starts.push(i);
361
381
  }
@@ -370,7 +390,7 @@ function collectUserTurnStartIndexes(messages: Message[]): number[] {
370
390
  */
371
391
  function countPersistedMessages(messages: Message[]): number {
372
392
  return messages.filter((message) => {
373
- return getSummaryFromContextMessage(message) === null;
393
+ return getSummaryFromContextMessage(message) === undefined;
374
394
  }).length;
375
395
  }
376
396
 
@@ -0,0 +1,186 @@
1
+ import type { ApprovalCopyGenerator, ApprovalConversationGenerator, ApprovalConversationResult, ApprovalConversationDisposition } from '../runtime/http-types.js';
2
+ import {
3
+ buildGenerationPrompt,
4
+ includesRequiredKeywords,
5
+ getFallbackMessage,
6
+ APPROVAL_COPY_TIMEOUT_MS,
7
+ APPROVAL_COPY_MAX_TOKENS,
8
+ APPROVAL_COPY_SYSTEM_PROMPT,
9
+ } from '../runtime/approval-message-composer.js';
10
+ import { loadConfig } from '../config/loader.js';
11
+ import { getFailoverProvider, listProviders } from '../providers/registry.js';
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Approval conversation generator constants
15
+ // ---------------------------------------------------------------------------
16
+
17
+ const APPROVAL_CONVERSATION_TIMEOUT_MS = 8_000;
18
+ const APPROVAL_CONVERSATION_MAX_TOKENS = 300;
19
+
20
+ const APPROVAL_CONVERSATION_SYSTEM_PROMPT =
21
+ 'You are an assistant helping a user manage a pending tool approval request. '
22
+ + 'Analyze the user\'s message to determine if they are making a decision '
23
+ + '(approve, reject, or cancel) or just asking a question / making conversation. '
24
+ + 'When uncertain, default to keep_pending — never approve or reject without clear intent. '
25
+ + 'For guardians: explain what tool is requesting approval and from whom. '
26
+ + 'Always provide a natural, helpful reply along with your decision.';
27
+
28
+ const APPROVAL_CONVERSATION_TOOL_NAME = 'approval_decision';
29
+
30
+ const APPROVAL_CONVERSATION_TOOL_SCHEMA = {
31
+ name: APPROVAL_CONVERSATION_TOOL_NAME,
32
+ description:
33
+ 'Record the disposition of the approval conversation turn. '
34
+ + 'Call this tool with the determined disposition and a natural reply to the user.',
35
+ input_schema: {
36
+ type: 'object' as const,
37
+ properties: {
38
+ disposition: {
39
+ type: 'string',
40
+ enum: ['keep_pending', 'approve_once', 'approve_always', 'reject'],
41
+ description:
42
+ 'The decision: keep_pending if the user is asking questions or unclear, '
43
+ + 'approve_once to approve this single request, approve_always to approve '
44
+ + 'this tool permanently, reject to deny the request.',
45
+ },
46
+ replyText: {
47
+ type: 'string',
48
+ description: 'A natural language reply to send back to the user.',
49
+ },
50
+ targetRunId: {
51
+ type: 'string',
52
+ description:
53
+ 'The run ID of the specific pending approval being acted on. '
54
+ + 'Required when there are multiple pending approvals and the disposition is decision-bearing.',
55
+ },
56
+ },
57
+ required: ['disposition', 'replyText'],
58
+ },
59
+ };
60
+
61
+ const VALID_DISPOSITIONS: ReadonlySet<string> = new Set([
62
+ 'keep_pending',
63
+ 'approve_once',
64
+ 'approve_always',
65
+ 'reject',
66
+ ]);
67
+
68
+ /**
69
+ * Create the daemon-owned approval copy generator that resolves providers
70
+ * and calls `provider.sendMessage` to generate approval copy text.
71
+ * This keeps all provider awareness in the daemon lifecycle, away from
72
+ * the runtime composer.
73
+ */
74
+ export function createApprovalCopyGenerator(): ApprovalCopyGenerator {
75
+ return async (context, options = {}) => {
76
+ const config = loadConfig();
77
+ let provider;
78
+ try {
79
+ provider = getFailoverProvider(config.provider, config.providerOrder);
80
+ } catch {
81
+ return null;
82
+ }
83
+
84
+ const fallbackText = options.fallbackText?.trim() || getFallbackMessage(context);
85
+ const requiredKeywords = options.requiredKeywords?.map((kw) => kw.trim()).filter((kw) => kw.length > 0);
86
+ const prompt = buildGenerationPrompt(context, fallbackText, requiredKeywords);
87
+
88
+ const response = await provider.sendMessage(
89
+ [{ role: 'user', content: [{ type: 'text', text: prompt }] }],
90
+ [],
91
+ APPROVAL_COPY_SYSTEM_PROMPT,
92
+ {
93
+ config: {
94
+ max_tokens: options.maxTokens ?? APPROVAL_COPY_MAX_TOKENS,
95
+ },
96
+ signal: AbortSignal.timeout(options.timeoutMs ?? APPROVAL_COPY_TIMEOUT_MS),
97
+ },
98
+ );
99
+
100
+ const block = response.content.find((entry) => entry.type === 'text');
101
+ const text = block && 'text' in block ? block.text.trim() : '';
102
+ if (!text) return null;
103
+ const cleaned = text
104
+ .replace(/^["'`]+/, '')
105
+ .replace(/["'`]+$/, '')
106
+ .trim();
107
+ if (!cleaned) return null;
108
+ if (!includesRequiredKeywords(cleaned, requiredKeywords)) return null;
109
+ return cleaned;
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Create the daemon-owned approval conversation generator that resolves
115
+ * providers and uses tool_use / function calling for structured output.
116
+ * Follows the same provider-aware pattern as createApprovalCopyGenerator().
117
+ */
118
+ export function createApprovalConversationGenerator(): ApprovalConversationGenerator {
119
+ return async (context) => {
120
+ const config = loadConfig();
121
+ if (!listProviders().includes(config.provider)) {
122
+ throw new Error('No provider available for approval conversation');
123
+ }
124
+ const provider = getFailoverProvider(config.provider, config.providerOrder);
125
+
126
+ const pendingDescription = context.pendingApprovals
127
+ .map((p) => `- Run ${p.runId}: tool "${p.toolName}"`)
128
+ .join('\n');
129
+
130
+ const userPrompt = [
131
+ `Role: ${context.role}`,
132
+ `Tool requesting approval: "${context.toolName}"`,
133
+ `Allowed actions: ${context.allowedActions.join(', ')}`,
134
+ `Pending approvals:\n${pendingDescription}`,
135
+ `\nUser message: ${context.userMessage}`,
136
+ ].join('\n');
137
+
138
+ const response = await provider.sendMessage(
139
+ [{ role: 'user', content: [{ type: 'text', text: userPrompt }] }],
140
+ [APPROVAL_CONVERSATION_TOOL_SCHEMA],
141
+ APPROVAL_CONVERSATION_SYSTEM_PROMPT,
142
+ {
143
+ config: {
144
+ max_tokens: APPROVAL_CONVERSATION_MAX_TOKENS,
145
+ },
146
+ signal: AbortSignal.timeout(APPROVAL_CONVERSATION_TIMEOUT_MS),
147
+ },
148
+ );
149
+
150
+ // Extract the tool_use block from the response
151
+ const toolUseBlock = response.content.find(
152
+ (block) => block.type === 'tool_use' && block.name === APPROVAL_CONVERSATION_TOOL_NAME,
153
+ );
154
+
155
+ if (!toolUseBlock || toolUseBlock.type !== 'tool_use') {
156
+ throw new Error('Provider did not return a tool_use block for approval decision');
157
+ }
158
+
159
+ const input = toolUseBlock.input as Record<string, unknown>;
160
+
161
+ // Strict validation of the structured output
162
+ const disposition = input.disposition;
163
+ if (typeof disposition !== 'string' || !VALID_DISPOSITIONS.has(disposition)) {
164
+ throw new Error(`Invalid disposition: ${String(disposition)}`);
165
+ }
166
+
167
+ const replyText = input.replyText;
168
+ if (typeof replyText !== 'string' || replyText.trim().length === 0) {
169
+ throw new Error('Missing or empty replyText in tool_use response');
170
+ }
171
+
172
+ const targetRunId = input.targetRunId;
173
+ if (targetRunId !== undefined && typeof targetRunId !== 'string') {
174
+ throw new Error('Invalid targetRunId in tool_use response');
175
+ }
176
+
177
+ const result: ApprovalConversationResult = {
178
+ disposition: disposition as ApprovalConversationDisposition,
179
+ replyText: replyText.trim(),
180
+ };
181
+ if (typeof targetRunId === 'string' && targetRunId.length > 0) {
182
+ result.targetRunId = targetRunId;
183
+ }
184
+ return result;
185
+ };
186
+ }