@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,177 @@
1
+ /**
2
+ * In-memory pairing request store with TTL.
3
+ *
4
+ * Each pairing request lives for at most TTL_MS (5 minutes) before
5
+ * being swept as expired. Status transitions:
6
+ * registered → pending → approved | denied | expired
7
+ */
8
+
9
+ import { createHash, timingSafeEqual } from 'node:crypto';
10
+ import { getLogger } from '../util/logger.js';
11
+
12
+ const log = getLogger('pairing-store');
13
+
14
+ const TTL_MS = 5 * 60 * 1000; // 5 minutes
15
+ const SWEEP_INTERVAL_MS = 30_000; // 30 seconds
16
+
17
+ export type PairingStatus = 'registered' | 'pending' | 'approved' | 'denied' | 'expired';
18
+
19
+ export interface PairingRequest {
20
+ pairingRequestId: string;
21
+ hashedPairingSecret: string;
22
+ hashedDeviceId?: string;
23
+ deviceName?: string;
24
+ status: PairingStatus;
25
+ gatewayUrl: string;
26
+ localLanUrl: string | null;
27
+ bearerToken?: string;
28
+ createdAt: number;
29
+ }
30
+
31
+ function hashValue(value: string): string {
32
+ return createHash('sha256').update(value).digest('hex');
33
+ }
34
+
35
+ function timingSafeCompare(a: string, b: string): boolean {
36
+ const bufA = Buffer.from(a);
37
+ const bufB = Buffer.from(b);
38
+ if (bufA.length !== bufB.length) return false;
39
+ return timingSafeEqual(bufA, bufB);
40
+ }
41
+
42
+ export class PairingStore {
43
+ private requests = new Map<string, PairingRequest>();
44
+ private sweepTimer: ReturnType<typeof setInterval> | null = null;
45
+
46
+ start(): void {
47
+ this.sweepTimer = setInterval(() => this.sweep(), SWEEP_INTERVAL_MS);
48
+ }
49
+
50
+ stop(): void {
51
+ if (this.sweepTimer) {
52
+ clearInterval(this.sweepTimer);
53
+ this.sweepTimer = null;
54
+ }
55
+ this.requests.clear();
56
+ }
57
+
58
+ /**
59
+ * Pre-register a pairing request (called when QR is displayed).
60
+ * Idempotent: if the same ID exists and secret matches, overwrite.
61
+ * Returns false with 'conflict' if ID exists but secret doesn't match.
62
+ */
63
+ register(params: {
64
+ pairingRequestId: string;
65
+ pairingSecret: string;
66
+ gatewayUrl: string;
67
+ localLanUrl?: string | null;
68
+ }): { ok: true } | { ok: false; reason: 'conflict' } {
69
+ const hashedSecret = hashValue(params.pairingSecret);
70
+ const existing = this.requests.get(params.pairingRequestId);
71
+
72
+ if (existing) {
73
+ if (!timingSafeCompare(existing.hashedPairingSecret, hashedSecret)) {
74
+ return { ok: false, reason: 'conflict' };
75
+ }
76
+ }
77
+
78
+ this.requests.set(params.pairingRequestId, {
79
+ pairingRequestId: params.pairingRequestId,
80
+ hashedPairingSecret: hashedSecret,
81
+ status: 'registered',
82
+ gatewayUrl: params.gatewayUrl,
83
+ localLanUrl: params.localLanUrl ?? null,
84
+ createdAt: Date.now(),
85
+ });
86
+
87
+ log.info({ pairingRequestId: params.pairingRequestId }, 'Pairing request registered');
88
+ return { ok: true };
89
+ }
90
+
91
+ /**
92
+ * iOS initiates a pairing request. Validates the secret and transitions
93
+ * the entry to "pending" (or "approved" if auto-approved).
94
+ */
95
+ beginRequest(params: {
96
+ pairingRequestId: string;
97
+ pairingSecret: string;
98
+ deviceId: string;
99
+ deviceName: string;
100
+ }): { ok: true; entry: PairingRequest } | { ok: false; reason: 'not_found' | 'invalid_secret' | 'expired' } {
101
+ const entry = this.requests.get(params.pairingRequestId);
102
+ if (!entry) {
103
+ return { ok: false, reason: 'not_found' };
104
+ }
105
+
106
+ if (entry.status === 'expired' || entry.status === 'denied') {
107
+ return { ok: false, reason: 'expired' };
108
+ }
109
+
110
+ const hashedSecret = hashValue(params.pairingSecret);
111
+ if (!timingSafeCompare(entry.hashedPairingSecret, hashedSecret)) {
112
+ return { ok: false, reason: 'invalid_secret' };
113
+ }
114
+
115
+ entry.hashedDeviceId = hashValue(params.deviceId);
116
+ entry.deviceName = params.deviceName;
117
+ if (entry.status === 'registered') {
118
+ entry.status = 'pending';
119
+ }
120
+
121
+ return { ok: true, entry };
122
+ }
123
+
124
+ /**
125
+ * Approve a pairing request. Sets the bearer token for iOS to retrieve.
126
+ */
127
+ approve(pairingRequestId: string, bearerToken: string): PairingRequest | null {
128
+ const entry = this.requests.get(pairingRequestId);
129
+ if (!entry) return null;
130
+ entry.status = 'approved';
131
+ entry.bearerToken = bearerToken;
132
+ return entry;
133
+ }
134
+
135
+ /**
136
+ * Deny a pairing request.
137
+ */
138
+ deny(pairingRequestId: string): PairingRequest | null {
139
+ const entry = this.requests.get(pairingRequestId);
140
+ if (!entry) return null;
141
+ entry.status = 'denied';
142
+ return entry;
143
+ }
144
+
145
+ /**
146
+ * Get a pairing request by ID.
147
+ */
148
+ get(pairingRequestId: string): PairingRequest | null {
149
+ return this.requests.get(pairingRequestId) ?? null;
150
+ }
151
+
152
+ /**
153
+ * Validate the secret for a status poll request (timing-safe).
154
+ */
155
+ validateSecret(pairingRequestId: string, secret: string): boolean {
156
+ const entry = this.requests.get(pairingRequestId);
157
+ if (!entry) return false;
158
+ const hashedSecret = hashValue(secret);
159
+ return timingSafeCompare(entry.hashedPairingSecret, hashedSecret);
160
+ }
161
+
162
+ private sweep(): void {
163
+ const now = Date.now();
164
+ for (const [id, entry] of this.requests) {
165
+ if (now - entry.createdAt > TTL_MS) {
166
+ if (entry.status !== 'approved') {
167
+ entry.status = 'expired';
168
+ }
169
+ // Remove entries older than 2x TTL regardless of status
170
+ if (now - entry.createdAt > TTL_MS * 2) {
171
+ this.requests.delete(id);
172
+ log.debug({ pairingRequestId: id }, 'Pairing request swept');
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
@@ -0,0 +1,43 @@
1
+ import { initializeProviders } from '../providers/registry.js';
2
+ import { initializeTools } from '../tools/registry.js';
3
+ import { registerWatcherProvider } from '../watcher/provider-registry.js';
4
+ import { gmailProvider } from '../watcher/providers/gmail.js';
5
+ import { googleCalendarProvider } from '../watcher/providers/google-calendar.js';
6
+ import { slackProvider as slackWatcherProvider } from '../watcher/providers/slack.js';
7
+ import { githubProvider } from '../watcher/providers/github.js';
8
+ import { linearProvider } from '../watcher/providers/linear.js';
9
+ import { registerMessagingProvider } from '../messaging/registry.js';
10
+ import { slackProvider as slackMessagingProvider } from '../messaging/providers/slack/adapter.js';
11
+ import { gmailMessagingProvider } from '../messaging/providers/gmail/adapter.js';
12
+ import { telegramBotMessagingProvider } from '../messaging/providers/telegram-bot/adapter.js';
13
+ import { smsMessagingProvider } from '../messaging/providers/sms/adapter.js';
14
+ import { whatsappMessagingProvider } from '../messaging/providers/whatsapp/adapter.js';
15
+ import { initWatcherEngine } from '../watcher/engine.js';
16
+ import type { AssistantConfig } from '../config/types.js';
17
+ import { getLogger } from '../util/logger.js';
18
+
19
+ const log = getLogger('lifecycle');
20
+
21
+ export async function initializeProvidersAndTools(config: AssistantConfig): Promise<void> {
22
+ log.info('Daemon startup: initializing providers and tools');
23
+ initializeProviders(config);
24
+ await initializeTools();
25
+ log.info('Daemon startup: providers and tools initialized');
26
+ }
27
+
28
+ export function registerWatcherProviders(): void {
29
+ registerWatcherProvider(gmailProvider);
30
+ registerWatcherProvider(googleCalendarProvider);
31
+ registerWatcherProvider(slackWatcherProvider);
32
+ registerWatcherProvider(githubProvider);
33
+ registerWatcherProvider(linearProvider);
34
+ initWatcherEngine();
35
+ }
36
+
37
+ export function registerMessagingProviders(): void {
38
+ registerMessagingProvider(slackMessagingProvider);
39
+ registerMessagingProvider(gmailMessagingProvider);
40
+ registerMessagingProvider(telegramBotMessagingProvider);
41
+ registerMessagingProvider(smsMessagingProvider);
42
+ registerMessagingProvider(whatsappMessagingProvider);
43
+ }
@@ -23,6 +23,9 @@ const log = getLogger('ride-shotgun-handler');
23
23
  /** Active network recorders keyed by watchId. */
24
24
  const activeRecorders = new Map<string, NetworkRecorder>();
25
25
 
26
+ /** Active progress interval timers keyed by watchId, cleared on session completion. */
27
+ const activeProgressIntervals = new Map<string, NodeJS.Timeout>();
28
+
26
29
  /** Return domain-specific URL patterns that indicate a successful login. */
27
30
  function getLoginSignals(targetDomain?: string): string[] {
28
31
  if (targetDomain === 'x.com' || targetDomain === 'twitter.com') {
@@ -52,6 +55,13 @@ async function completeSession(session: WatchSession): Promise<void> {
52
55
  session.timeoutHandle = undefined;
53
56
  }
54
57
 
58
+ // Clear progress interval timer if one was registered for this session
59
+ const progressTimer = activeProgressIntervals.get(session.watchId);
60
+ if (progressTimer) {
61
+ clearInterval(progressTimer);
62
+ activeProgressIntervals.delete(session.watchId);
63
+ }
64
+
55
65
  const { watchId, sessionId } = session;
56
66
  log.info(
57
67
  { watchId, sessionId, observationCount: session.observations.length },
@@ -135,9 +145,62 @@ export async function handleRideShotgunStart(
135
145
  activeRecorders.set(watchId, recorder);
136
146
  log.info({ watchId, targetDomain, attempt }, 'Network recording started for learn session');
137
147
 
148
+ // Send periodic progress updates with network entry counts and idle detection
149
+ let lastNetworkEntryCount = 0;
150
+ let lastActivityTimestamp = Date.now();
151
+ let idleHintSent = false;
152
+
153
+ const progressInterval: NodeJS.Timeout = setInterval(() => {
154
+ if (session.status !== 'active') {
155
+ clearInterval(progressInterval);
156
+ return;
157
+ }
158
+
159
+ const currentCount = recorder.entryCount;
160
+
161
+ // Track activity: reset idle timer when count changes
162
+ if (currentCount !== lastNetworkEntryCount) {
163
+ lastNetworkEntryCount = currentCount;
164
+ lastActivityTimestamp = Date.now();
165
+ // If we previously sent an idle hint, clear it now that activity resumed
166
+ if (idleHintSent) {
167
+ idleHintSent = false;
168
+ log.info({ watchId, currentCount }, 'Activity resumed — clearing idleHint');
169
+ ctx.send(socket, {
170
+ type: 'ride_shotgun_progress',
171
+ watchId,
172
+ message: `Recording network traffic...`,
173
+ networkEntryCount: currentCount,
174
+ statusMessage: 'Recording network traffic...',
175
+ idleHint: false,
176
+ });
177
+ return;
178
+ }
179
+ }
180
+
181
+ // Idle detection: if some initial activity happened and no new entries for 15s, hint once
182
+ const idleMs = Date.now() - lastActivityTimestamp;
183
+ let idleHint: boolean | undefined;
184
+ if (!idleHintSent && currentCount > 0 && idleMs >= 15_000) {
185
+ idleHint = true;
186
+ idleHintSent = true;
187
+ log.info({ watchId, currentCount, idleMs }, 'Idle detected — sending idleHint');
188
+ }
189
+
190
+ ctx.send(socket, {
191
+ type: 'ride_shotgun_progress',
192
+ watchId,
193
+ message: `Recording network traffic...`,
194
+ networkEntryCount: currentCount,
195
+ statusMessage: 'Recording network traffic...',
196
+ ...(idleHint !== undefined ? { idleHint } : {}),
197
+ });
198
+ }, 5000);
199
+ activeProgressIntervals.set(watchId, progressInterval);
200
+
138
201
  // For x.com, auto-navigate Chrome through key pages to capture the full API surface.
139
202
  // Skip login detection — auto-navigation will complete the session when done.
140
- if (targetDomain === 'x.com' || targetDomain === 'twitter.com') {
203
+ if ((targetDomain === 'x.com' || targetDomain === 'twitter.com') && msg.autoNavigate !== false) {
141
204
  // Don't set onLoginDetected — it would kill the session after the first
142
205
  // GraphQL call (5s grace), before auto-navigation finishes.
143
206
  const abortSignal = { aborted: false };
@@ -177,7 +240,7 @@ export async function handleRideShotgunStart(
177
240
  type: 'ride_shotgun_progress',
178
241
  watchId,
179
242
  message: `[${progress.pageNumber || '?'}] ${shortUrl}`,
180
- } as any);
243
+ });
181
244
  }
182
245
  }).then(visited => {
183
246
  clearInterval(checkInterval);
@@ -192,8 +255,10 @@ export async function handleRideShotgunStart(
192
255
  completeSession(session);
193
256
  }
194
257
  });
258
+ } else if (msg.autoNavigate === false && targetDomain) {
259
+ // Manual mode: just record network traffic until timeout or early stop — no login detection shortcut.
195
260
  } else {
196
- // No targetDomain: use login detection as before
261
+ // No targetDomain or targetDomain without explicit autoNavigate=false: use login detection
197
262
  recorder.onLoginDetected = () => {
198
263
  log.info({ watchId }, 'Login detected — auto-stopping learn session');
199
264
  completeSession(session);
@@ -15,6 +15,7 @@ import { IngressBlockedError } from '../util/errors.js';
15
15
  import * as conversationStore from '../memory/conversation-store.js';
16
16
  import * as attachmentsStore from '../memory/attachments-store.js';
17
17
  import { Session, DEFAULT_MEMORY_POLICY, type SessionMemoryPolicy } from './session.js';
18
+ import { parseChannelId, type ChannelId } from '../channels/types.js';
18
19
  import { resolveChannelCapabilities } from './session-runtime-assembly.js';
19
20
  import { ComputerUseSession } from './computer-use-session.js';
20
21
  import {
@@ -31,7 +32,6 @@ import { ensureBlobDir, sweepStaleBlobs } from './ipc-blob-store.js';
31
32
  import { bootstrapHomeBaseAppLink } from '../home-base/bootstrap.js';
32
33
  import { SessionEvictor } from './session-evictor.js';
33
34
  import { getSubagentManager } from '../subagent/index.js';
34
- import { tryRouteCallMessage } from '../calls/call-bridge.js';
35
35
  import { resolveSlash } from './session-slash.js';
36
36
  import { createUserMessage, createAssistantMessage } from '../agent/message-types.js';
37
37
  import { registerDaemonCallbacks } from '../work-items/work-item-runner.js';
@@ -53,6 +53,24 @@ function readPackageVersion(): string | undefined {
53
53
 
54
54
  const daemonVersion = readPackageVersion();
55
55
 
56
+ function resolveTurnChannel(sourceChannel?: string, transportChannelId?: string): ChannelId {
57
+ if (sourceChannel != null) {
58
+ const parsed = parseChannelId(sourceChannel);
59
+ if (!parsed) {
60
+ throw new Error(`Invalid sourceChannel: ${sourceChannel}`);
61
+ }
62
+ return parsed;
63
+ }
64
+ if (transportChannelId != null) {
65
+ const parsed = parseChannelId(transportChannelId);
66
+ if (!parsed) {
67
+ throw new Error(`Invalid transport.channelId: ${transportChannelId}`);
68
+ }
69
+ return parsed;
70
+ }
71
+ return 'macos';
72
+ }
73
+
56
74
  export class DaemonServer {
57
75
  private server: net.Server | null = null;
58
76
  private tcpServer: tls.Server | null = null;
@@ -358,7 +376,7 @@ export class DaemonServer {
358
376
  const parseDurationMs = Number(process.hrtime.bigint() - parseStartNs) / 1_000_000;
359
377
  for (const entry of parsed) {
360
378
  const msg = entry.msg;
361
- if (typeof msg === 'object' && msg !== null && (msg as { type?: unknown }).type === 'cu_observation') {
379
+ if (typeof msg === 'object' && msg != null && (msg as { type?: unknown }).type === 'cu_observation') {
362
380
  const maybeSessionId = (msg as { sessionId?: unknown }).sessionId;
363
381
  const sessionId = typeof maybeSessionId === 'string' ? maybeSessionId : 'unknown';
364
382
  const previousSequence = this.cuObservationParseSequence.get(sessionId) ?? 0;
@@ -488,6 +506,20 @@ export class DaemonServer {
488
506
  }
489
507
  }
490
508
 
509
+ get lastConfigFingerprint(): string {
510
+ return this.configWatcher.lastFingerprint;
511
+ }
512
+
513
+ set lastConfigFingerprint(value: string) {
514
+ this.configWatcher.lastFingerprint = value;
515
+ }
516
+
517
+ refreshConfigFromSources(): boolean {
518
+ const changed = this.configWatcher.refreshConfigFromSources();
519
+ if (changed) this.evictSessionsForReload();
520
+ return changed;
521
+ }
522
+
491
523
  private async sendInitialSession(socket: net.Socket): Promise<void> {
492
524
  const conversation = conversationStore.getLatestConversation();
493
525
  if (!conversation) {
@@ -666,7 +698,15 @@ export class DaemonServer {
666
698
  throw new Error('Session is already processing a message');
667
699
  }
668
700
 
701
+ session.setAssistantId(options?.assistantId ?? 'self');
702
+ session.setGuardianContext(options?.guardianContext ?? null);
669
703
  session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
704
+ session.setCommandIntent(options?.commandIntent ?? null);
705
+ const resolvedChannel = resolveTurnChannel(sourceChannel, options?.transport?.channelId);
706
+ session.setTurnChannelContext({
707
+ userMessageChannel: resolvedChannel,
708
+ assistantMessageChannel: resolvedChannel,
709
+ });
670
710
 
671
711
  const attachments = attachmentIds
672
712
  ? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
@@ -680,21 +720,6 @@ export class DaemonServer {
680
720
  const requestId = crypto.randomUUID();
681
721
  const messageId = session.persistUserMessage(content, attachments, requestId);
682
722
 
683
- let bridgeHandled = false;
684
- try {
685
- const bridgeResult = await tryRouteCallMessage(conversationId, content, messageId);
686
- bridgeHandled = bridgeResult.handled;
687
- } catch (err) {
688
- log.warn({ err, conversationId }, 'Call bridge check failed (non-fatal), proceeding with agent loop');
689
- }
690
-
691
- if (bridgeHandled) {
692
- resetSessionProcessingState(session);
693
- session.drainQueue('loop_complete');
694
- log.info({ conversationId, messageId }, 'User message consumed by call bridge, skipping agent loop');
695
- return { messageId };
696
- }
697
-
698
723
  session.runAgentLoop(content, messageId, () => {}).catch((err) => {
699
724
  log.error({ err, conversationId }, 'Background agent loop failed');
700
725
  });
@@ -720,7 +745,15 @@ export class DaemonServer {
720
745
  throw new Error('Session is already processing a message');
721
746
  }
722
747
 
748
+ session.setAssistantId(options?.assistantId ?? 'self');
749
+ session.setGuardianContext(options?.guardianContext ?? null);
723
750
  session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel));
751
+ session.setCommandIntent(options?.commandIntent ?? null);
752
+ const resolvedChannel2 = resolveTurnChannel(sourceChannel, options?.transport?.channelId);
753
+ session.setTurnChannelContext({
754
+ userMessageChannel: resolvedChannel2,
755
+ assistantMessageChannel: resolvedChannel2,
756
+ });
724
757
 
725
758
  const attachments = attachmentIds
726
759
  ? attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
@@ -734,19 +767,33 @@ export class DaemonServer {
734
767
  const slashResult = resolveSlash(content);
735
768
 
736
769
  if (slashResult.kind === 'unknown') {
770
+ const serverTurnCtx = session.getTurnChannelContext();
771
+ const serverChannelMeta = serverTurnCtx
772
+ ? { userMessageChannel: serverTurnCtx.userMessageChannel, assistantMessageChannel: serverTurnCtx.assistantMessageChannel }
773
+ : undefined;
737
774
  const userMsg = createUserMessage(content, attachments);
738
775
  const persisted = conversationStore.addMessage(
739
776
  conversationId,
740
777
  'user',
741
778
  JSON.stringify(userMsg.content),
779
+ serverChannelMeta,
742
780
  );
743
781
  session.getMessages().push(userMsg);
744
782
 
783
+ if (serverTurnCtx) {
784
+ try {
785
+ conversationStore.setConversationOriginChannelIfUnset(conversationId, serverTurnCtx.userMessageChannel);
786
+ } catch (err) {
787
+ log.warn({ err, conversationId }, 'Failed to set origin channel (best-effort)');
788
+ }
789
+ }
790
+
745
791
  const assistantMsg = createAssistantMessage(slashResult.message);
746
792
  conversationStore.addMessage(
747
793
  conversationId,
748
794
  'assistant',
749
795
  JSON.stringify(assistantMsg.content),
796
+ serverChannelMeta,
750
797
  );
751
798
  session.getMessages().push(assistantMsg);
752
799
  return { messageId: persisted.id };
@@ -767,22 +814,6 @@ export class DaemonServer {
767
814
  throw err;
768
815
  }
769
816
 
770
- let bridgeHandled = false;
771
- try {
772
- const bridgeResult = await tryRouteCallMessage(conversationId, resolvedContent, messageId);
773
- bridgeHandled = bridgeResult.handled;
774
- } catch (err) {
775
- log.warn({ err, conversationId }, 'Call bridge check failed (non-fatal), proceeding with agent loop');
776
- }
777
-
778
- if (bridgeHandled) {
779
- (session as unknown as { preactivatedSkillIds?: string[] }).preactivatedSkillIds = undefined;
780
- resetSessionProcessingState(session);
781
- session.drainQueue('loop_complete');
782
- log.info({ conversationId, messageId }, 'User message consumed by call bridge, skipping agent loop');
783
- return { messageId };
784
- }
785
-
786
817
  await session.runAgentLoop(resolvedContent, messageId, () => {});
787
818
 
788
819
  return { messageId };
@@ -790,8 +821,8 @@ export class DaemonServer {
790
821
 
791
822
  createRunOrchestrator(): RunOrchestrator {
792
823
  return new RunOrchestrator({
793
- getOrCreateSession: (conversationId) =>
794
- this.getOrCreateSession(conversationId),
824
+ getOrCreateSession: (conversationId, transport) =>
825
+ this.getOrCreateSession(conversationId, undefined, true, transport ? { transport } : undefined),
795
826
  resolveAttachments: (attachmentIds) =>
796
827
  attachmentsStore.getAttachmentsByIds(attachmentIds).map((a) => ({
797
828
  id: a.id,
@@ -805,14 +836,3 @@ export class DaemonServer {
805
836
  }
806
837
 
807
838
  }
808
-
809
- function resetSessionProcessingState(session: Session): void {
810
- const s = session as unknown as {
811
- processing: boolean;
812
- abortController: AbortController | null;
813
- currentRequestId: string | undefined;
814
- };
815
- s.processing = false;
816
- s.abortController = null;
817
- s.currentRequestId = undefined;
818
- }