@vellumai/assistant 0.12.1-dev.202609141913.5e16607 → 0.12.1-staging.2

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 (439) hide show
  1. package/AGENTS.md +0 -4
  2. package/ARCHITECTURE.md +12 -11
  3. package/docs/architecture/turn-actor.md +8 -15
  4. package/docs/guardian-request-flow.md +0 -16
  5. package/openapi.yaml +49 -291
  6. package/package.json +1 -1
  7. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  8. package/src/__tests__/app-compiler.test.ts +0 -6
  9. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  10. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  11. package/src/__tests__/app-source-watcher.test.ts +218 -0
  12. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  13. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  14. package/src/__tests__/computer-use-tools.test.ts +5 -17
  15. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  16. package/src/__tests__/config-schema.test.ts +29 -28
  17. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  18. package/src/__tests__/config-watcher.test.ts +8 -23
  19. package/src/__tests__/connection-model-compat.test.ts +2 -2
  20. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  21. package/src/__tests__/conversation-pairing.test.ts +0 -26
  22. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  23. package/src/__tests__/conversation-queue.test.ts +207 -48
  24. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  25. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  26. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  27. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  28. package/src/__tests__/conversation-title-service.test.ts +10 -14
  29. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  30. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  31. package/src/__tests__/credential-record-retire.test.ts +1 -171
  32. package/src/__tests__/credential-routes.test.ts +3 -212
  33. package/src/__tests__/credential-security-invariants.test.ts +2 -4
  34. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  35. package/src/__tests__/document-sync-tags.test.ts +0 -25
  36. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  37. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  38. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  39. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  40. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  41. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  42. package/src/__tests__/host-file-proxy.test.ts +23 -11
  43. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  44. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  45. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  46. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  47. package/src/__tests__/mcp-health-check.test.ts +11 -8
  48. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  49. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  51. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  52. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  53. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  54. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  55. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  56. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  57. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  58. package/src/__tests__/model-intents.test.ts +0 -3
  59. package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
  60. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  61. package/src/__tests__/platform-callback-registration.test.ts +16 -8
  62. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  63. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  64. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  66. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  67. package/src/__tests__/speaker-identification.test.ts +56 -0
  68. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  69. package/src/__tests__/subagent-tools.test.ts +2 -3
  70. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  71. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  72. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  73. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  74. package/src/__tests__/workspace-git-service.test.ts +0 -26
  75. package/src/acp/__tests__/agent-process.test.ts +4 -258
  76. package/src/acp/__tests__/auth-required.test.ts +0 -96
  77. package/src/acp/__tests__/client-handler.test.ts +2 -90
  78. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  79. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  80. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  81. package/src/acp/__tests__/session-manager.test.ts +4 -895
  82. package/src/acp/agent-process.test.ts +1 -4
  83. package/src/acp/agent-process.ts +9 -94
  84. package/src/acp/auth-required.ts +1 -50
  85. package/src/acp/auto-install.test.ts +7 -9
  86. package/src/acp/client-handler.ts +3 -16
  87. package/src/acp/resolve-agent.test.ts +6 -220
  88. package/src/acp/resolve-agent.ts +23 -88
  89. package/src/acp/session-manager.test.ts +3 -196
  90. package/src/acp/session-manager.ts +18 -441
  91. package/src/acp/types.ts +5 -50
  92. package/src/api/events/app-files-changed.ts +3 -4
  93. package/src/api/events/notification-intent.ts +0 -2
  94. package/src/api/index.ts +0 -6
  95. package/src/apps/app-store.ts +1 -1
  96. package/src/bundler/app-compiler.ts +0 -15
  97. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  98. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  99. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  100. package/src/calls/call-constants.ts +4 -24
  101. package/src/calls/call-controller.ts +199 -499
  102. package/src/calls/call-transport.ts +0 -16
  103. package/src/calls/media-stream-output.ts +0 -32
  104. package/src/calls/media-stream-server.ts +30 -82
  105. package/src/calls/media-stream-stt-session.ts +0 -15
  106. package/src/calls/resolve-call-tts-provider.ts +2 -33
  107. package/src/calls/speaker-identification.ts +233 -0
  108. package/src/calls/tts-call-strategy.ts +5 -9
  109. package/src/calls/types.ts +0 -2
  110. package/src/calls/voice-control-protocol.ts +21 -53
  111. package/src/calls/voice-session-bridge.ts +46 -59
  112. package/src/calls/voice-triage-escalate.ts +56 -175
  113. package/src/cli/commands/apps.help.ts +13 -67
  114. package/src/cli/commands/apps.ts +0 -183
  115. package/src/cli/commands/bash.help.ts +13 -8
  116. package/src/cli/commands/bash.ts +25 -7
  117. package/src/cli/commands/channels/index.help.ts +2 -70
  118. package/src/cli/commands/channels/index.ts +3 -16
  119. package/src/cli/commands/credentials.help.ts +2 -6
  120. package/src/cli/commands/credentials.ts +2 -2
  121. package/src/cli/commands/mcp.help.ts +8 -8
  122. package/src/cli/commands/mcp.ts +1 -1
  123. package/src/cli/commands/roadmap.help.ts +1 -5
  124. package/src/cli/commands/roadmap.ts +1 -1
  125. package/src/cli/lib/bundled-marketplace.json +90 -103
  126. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  127. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  128. package/src/config/__tests__/platform-rehydration.test.ts +9 -99
  129. package/src/config/acp-defaults.test.ts +3 -13
  130. package/src/config/acp-defaults.ts +6 -23
  131. package/src/config/acp-schema.ts +2 -30
  132. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  133. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  134. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  135. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  136. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  137. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  138. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  139. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  140. package/src/config/bundled-skills/schedule/SKILL.md +4 -3
  141. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  142. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  143. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  144. package/src/config/default-profile-catalog.ts +1 -1
  145. package/src/config/env.ts +2 -2
  146. package/src/config/feature-flag-registry.json +12 -24
  147. package/src/config/loader.ts +0 -1
  148. package/src/config/memory-v3-gate.test.ts +0 -31
  149. package/src/config/memory-v3-gate.ts +16 -20
  150. package/src/config/platform-rehydration.ts +27 -11
  151. package/src/config/schema.ts +2 -2
  152. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  153. package/src/config/schemas/calls.ts +28 -1
  154. package/src/config/schemas/live-voice.ts +173 -1
  155. package/src/config/schemas/mcp.ts +1 -1
  156. package/src/config/schemas/memory-retrospective.ts +0 -10
  157. package/src/config/schemas/services.ts +0 -8
  158. package/src/config/schemas/skills.ts +14 -0
  159. package/src/credential-execution/process-manager.test.ts +19 -18
  160. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  161. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  162. package/src/daemon/app-source-watcher.ts +218 -0
  163. package/src/daemon/config-watcher.ts +194 -13
  164. package/src/daemon/conversation-process.ts +64 -35
  165. package/src/daemon/conversation-skill-tools.ts +31 -13
  166. package/src/daemon/conversation-store.ts +1 -1
  167. package/src/daemon/conversation-surfaces.ts +8 -10
  168. package/src/daemon/conversation-tool-setup.ts +43 -37
  169. package/src/daemon/conversation.ts +3 -0
  170. package/src/daemon/host-bash-proxy.ts +12 -8
  171. package/src/daemon/host-browser-proxy.ts +1 -15
  172. package/src/daemon/host-file-proxy.ts +10 -8
  173. package/src/daemon/host-transfer-proxy.ts +18 -14
  174. package/src/daemon/lifecycle.ts +5 -0
  175. package/src/daemon/mcp-reload-service.ts +5 -5
  176. package/src/daemon/message-types/sync.ts +0 -1
  177. package/src/daemon/orphan-reaper.ts +1 -1
  178. package/src/daemon/providers-setup.ts +1 -1
  179. package/src/daemon/shutdown-handlers.ts +9 -1
  180. package/src/daemon/skill-memory-refresh.ts +0 -64
  181. package/src/daemon/tool-side-effects.ts +18 -7
  182. package/src/home/__tests__/feed-writer.test.ts +0 -22
  183. package/src/home/feed-writer.ts +2 -11
  184. package/src/hooks/types.ts +0 -33
  185. package/src/inbound/platform-callback-registration.ts +5 -4
  186. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  187. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  188. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  189. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  190. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  191. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  192. package/src/live-voice/live-voice-session.ts +693 -213
  193. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  194. package/src/live-voice/protocol.ts +2 -0
  195. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  196. package/src/mcp/effective-config.ts +3 -3
  197. package/src/mcp/mcp-header-store.ts +45 -29
  198. package/src/mcp/startup.ts +4 -8
  199. package/src/messaging/provider.ts +3 -10
  200. package/src/messaging/providers/callback-routing.ts +0 -18
  201. package/src/messaging/providers/channel-transport.ts +0 -56
  202. package/src/messaging/providers/discord/transport.ts +0 -17
  203. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  204. package/src/messaging/providers/slack/adapter.ts +44 -7
  205. package/src/messaging/providers/slack/transport.ts +0 -16
  206. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  207. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  208. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  209. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  210. package/src/messaging/providers/whatsapp/client.ts +29 -0
  211. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  212. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  213. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  214. package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
  215. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  216. package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
  217. package/src/notifications/adapters/macos.ts +0 -3
  218. package/src/notifications/assistant-reply-producer.ts +3 -8
  219. package/src/notifications/conversation-pairing.ts +16 -36
  220. package/src/notifications/delivered-post-record.ts +1 -11
  221. package/src/notifications/guardian-feed-projection.ts +5 -125
  222. package/src/notifications/home-feed-side-effect.ts +7 -55
  223. package/src/notifications/schedule-result-producer.ts +22 -66
  224. package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
  225. package/src/oauth/byo-connection.test.ts +0 -45
  226. package/src/oauth/byo-connection.ts +6 -36
  227. package/src/oauth/connection-resolver.test.ts +0 -73
  228. package/src/oauth/connection-resolver.ts +2 -95
  229. package/src/oauth/seed-providers.ts +0 -165
  230. package/src/outbound-proxy/certs.ts +5 -3
  231. package/src/permissions/checker.test.ts +6 -11
  232. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  233. package/src/persistence/conversation-crud.ts +63 -71
  234. package/src/persistence/conversation-lineage.ts +4 -12
  235. package/src/persistence/conversation-title-service.ts +26 -9
  236. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  237. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  238. package/src/persistence/message-reads.ts +0 -30
  239. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  240. package/src/persistence/schema/memory-core.ts +0 -5
  241. package/src/platform/client.test.ts +2 -4
  242. package/src/platform/client.ts +10 -2
  243. package/src/plugin-api/constants.ts +0 -2
  244. package/src/plugin-api/index.ts +0 -1
  245. package/src/plugin-api/types.ts +0 -2
  246. package/src/plugins/defaults/index.ts +0 -2
  247. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  248. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  249. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  250. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  251. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  252. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  253. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  254. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  255. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  256. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  257. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  258. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  259. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  260. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  261. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  262. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  263. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  264. package/src/plugins/defaults/memory/startup.ts +1 -6
  265. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  266. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  267. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  268. package/src/plugins/defaults/memory/worker.ts +0 -6
  269. package/src/plugins/mcp-servers.ts +75 -15
  270. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  271. package/src/providers/gemini/client.ts +23 -9
  272. package/src/providers/inference/auth.ts +3 -2
  273. package/src/providers/inference/connection-availability.ts +8 -27
  274. package/src/providers/inference/resolve-auth.ts +4 -22
  275. package/src/providers/model-catalog.ts +0 -34
  276. package/src/providers/model-intents.ts +5 -10
  277. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  278. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  279. package/src/providers/openai/chat-completions-provider.ts +78 -192
  280. package/src/providers/openai/codex-models.ts +4 -0
  281. package/src/runtime/AGENTS.md +0 -2
  282. package/src/runtime/auth/same-actor.ts +3 -38
  283. package/src/runtime/http-server.ts +151 -160
  284. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  286. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  287. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  288. package/src/runtime/routes/acp-routes.test.ts +0 -15
  289. package/src/runtime/routes/acp-routes.ts +9 -72
  290. package/src/runtime/routes/app-management-routes.ts +0 -73
  291. package/src/runtime/routes/app-routes.ts +1 -1
  292. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  293. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  294. package/src/runtime/routes/credential-routes.ts +10 -19
  295. package/src/runtime/routes/debug-bash-routes.ts +173 -0
  296. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  297. package/src/runtime/routes/index.ts +2 -4
  298. package/src/runtime/routes/log-export-routes.ts +0 -2
  299. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  300. package/src/runtime/routes/migration-routes.ts +20 -6
  301. package/src/runtime/routes/platform-routes.ts +15 -18
  302. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  303. package/src/runtime/services/conversation-serializer.ts +3 -16
  304. package/src/runtime/sync/resource-sync-events.ts +1 -2
  305. package/src/schedule/worker.ts +1 -1
  306. package/src/security/ces-rpc-record-backend.ts +0 -7
  307. package/src/subagent/consult-context.ts +25 -12
  308. package/src/tools/acp/list-agents.test.ts +1 -3
  309. package/src/tools/acp/spawn.test.ts +11 -146
  310. package/src/tools/acp/spawn.ts +3 -21
  311. package/src/tools/acp/status.ts +3 -40
  312. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  313. package/src/tools/capability-offer.test.ts +2 -22
  314. package/src/tools/capability-offer.ts +1 -16
  315. package/src/tools/computer-use/definitions.ts +2 -4
  316. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  317. package/src/tools/credentials/metadata-store.ts +0 -100
  318. package/src/tools/host-filesystem/edit.test.ts +1 -2
  319. package/src/tools/host-filesystem/edit.ts +2 -2
  320. package/src/tools/host-filesystem/read.test.ts +1 -2
  321. package/src/tools/host-filesystem/read.ts +2 -2
  322. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  323. package/src/tools/host-filesystem/transfer.ts +2 -2
  324. package/src/tools/host-filesystem/write.test.ts +1 -2
  325. package/src/tools/host-filesystem/write.ts +2 -2
  326. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  327. package/src/tools/host-terminal/host-shell.ts +20 -4
  328. package/src/tools/policy-context.ts +7 -6
  329. package/src/tools/subagent/spawn.ts +8 -5
  330. package/src/tools/watch/watch-retro-report.ts +8 -0
  331. package/src/util/__tests__/language-subtag.test.ts +1 -23
  332. package/src/util/fs-watcher-error.ts +36 -0
  333. package/src/util/language-subtag.ts +0 -16
  334. package/src/util/platform.ts +0 -8
  335. package/src/workspace/git-service.ts +54 -5
  336. package/src/workspace/migrations/registry.ts +0 -6
  337. package/scripts/smoke-desktop-window-theme.ts +0 -186
  338. package/src/__tests__/git-porcelain.test.ts +0 -47
  339. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  340. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  341. package/src/__tests__/resolve-app.test.ts +0 -135
  342. package/src/__tests__/service-account-token.test.ts +0 -247
  343. package/src/__tests__/source-fingerprint.test.ts +0 -184
  344. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  345. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  346. package/src/acp/model-config.test.ts +0 -166
  347. package/src/acp/model-config.ts +0 -138
  348. package/src/api/events/acp-session-model-update.test.ts +0 -88
  349. package/src/api/events/acp-session-model-update.ts +0 -46
  350. package/src/apps/resolve-app.ts +0 -81
  351. package/src/apps/source-fingerprint.ts +0 -266
  352. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  353. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  354. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  355. package/src/calls/barge-in-guard.ts +0 -118
  356. package/src/calls/voice-leg-coordinator.ts +0 -189
  357. package/src/calls/voice-progress-cadence.ts +0 -423
  358. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  359. package/src/cli/commands/__tests__/bash.test.ts +0 -53
  360. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  361. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  362. package/src/cli/commands/channels/send.ts +0 -128
  363. package/src/config/__tests__/platform-identity.test.ts +0 -255
  364. package/src/config/acp-agent-write.ts +0 -43
  365. package/src/config/acp-schema.test.ts +0 -81
  366. package/src/config/platform-identity.ts +0 -201
  367. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  368. package/src/config/schemas/voice.ts +0 -150
  369. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  370. package/src/daemon/app-change-notify.ts +0 -45
  371. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  372. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  373. package/src/desktop/desktop-chrome-policy.ts +0 -42
  374. package/src/desktop/desktop-dependencies.test.ts +0 -102
  375. package/src/desktop/desktop-dependencies.ts +0 -306
  376. package/src/desktop/desktop-feature.test.ts +0 -18
  377. package/src/desktop/desktop-feature.ts +0 -19
  378. package/src/desktop/desktop-panel-config.test.ts +0 -135
  379. package/src/desktop/desktop-panel-config.ts +0 -149
  380. package/src/desktop/desktop-session-manager.test.ts +0 -627
  381. package/src/desktop/desktop-session-manager.ts +0 -814
  382. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  383. package/src/desktop/desktop-stream-bridge.ts +0 -214
  384. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  385. package/src/desktop/desktop-wallpaper.ts +0 -113
  386. package/src/desktop/desktop-window-theme.ts +0 -170
  387. package/src/i18n/AGENTS.md +0 -22
  388. package/src/i18n/__tests__/i18n.test.ts +0 -108
  389. package/src/i18n/index.ts +0 -16
  390. package/src/i18n/locales.ts +0 -93
  391. package/src/i18n/messages.ts +0 -61
  392. package/src/i18n/title.ts +0 -25
  393. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  394. package/src/mcp/spec-schema.ts +0 -111
  395. package/src/mcp/workspace-mcp-config.ts +0 -188
  396. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  397. package/src/persistence/conversation-title-placeholders.ts +0 -23
  398. package/src/persistence/message-cursor.ts +0 -78
  399. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  400. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  401. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  402. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  403. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  404. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  405. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  406. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  407. package/src/providers/gemini-thought-signature.test.ts +0 -63
  408. package/src/providers/gemini-thought-signature.ts +0 -44
  409. package/src/providers/inference/service-account-token.ts +0 -248
  410. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  411. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  412. package/src/providers/openai/google-thought-signature.ts +0 -320
  413. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  414. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  415. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  416. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  417. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  418. package/src/runtime/channel-send.ts +0 -316
  419. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  420. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  421. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  422. package/src/runtime/routes/channel-send-routes.ts +0 -85
  423. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  424. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  425. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  426. package/src/security/ces-http-record-backend.ts +0 -120
  427. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  428. package/src/skills/workspace-skill-md-signature.ts +0 -50
  429. package/src/tools/acp/status.test.ts +0 -94
  430. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
  431. package/src/tools/terminal/sanitized-bash.ts +0 -105
  432. package/src/util/ca-bundle.ts +0 -13
  433. package/src/workspace/git-porcelain.ts +0 -66
  434. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  435. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  436. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  437. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  438. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  439. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -1,255 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
-
3
- import {
4
- getPlatformBaseUrl,
5
- setPlatformAssistantId,
6
- setPlatformBaseUrl,
7
- setPlatformOrganizationId,
8
- setPlatformUserId,
9
- } from "../env.js";
10
-
11
- const actualSecureKeys = await import("../../security/secure-keys.js");
12
- mock.module("../../security/secure-keys.js", () => ({
13
- ...actualSecureKeys,
14
- getSecureKeyAsync: async () => undefined,
15
- }));
16
-
17
- const {
18
- _resetPlatformIdentityEnsureForTests,
19
- fetchPlatformIdentityIds,
20
- PLATFORM_IDENTITY_VALIDATE_PATH,
21
- resolvePlatformAssistantId,
22
- } = await import("../platform-identity.js");
23
-
24
- const BASE_URL = "https://platform.vellum.ai";
25
- const ASSISTANT_ID = "11111111-2222-4333-8444-555555555555";
26
- const ORG_ID = "22222222-3333-4444-8555-666666666666";
27
- const USER_ID = "33333333-4444-4555-8666-777777777777";
28
-
29
- describe("fetchPlatformIdentityIds", () => {
30
- const originalFetch = globalThis.fetch;
31
- const fetchCalls: Array<{ url: string; init?: RequestInit }> = [];
32
- let fetchImpl: (
33
- input: RequestInfo | URL,
34
- init?: RequestInit,
35
- ) => Promise<Response> = async () =>
36
- new Response("not found", { status: 404 });
37
-
38
- beforeEach(() => {
39
- fetchCalls.length = 0;
40
- fetchImpl = async () => new Response("not found", { status: 404 });
41
- globalThis.fetch = (async (
42
- input: RequestInfo | URL,
43
- init?: RequestInit,
44
- ) => {
45
- const url = typeof input === "string" ? input : input.toString();
46
- fetchCalls.push({ url, init });
47
- return fetchImpl(input, init);
48
- }) as unknown as typeof fetch;
49
- });
50
-
51
- afterEach(() => {
52
- globalThis.fetch = originalFetch;
53
- });
54
-
55
- test("returns the three ids from a successful validate response", async () => {
56
- fetchImpl = async () =>
57
- new Response(
58
- JSON.stringify({
59
- assistant_id: ASSISTANT_ID,
60
- organization_id: ORG_ID,
61
- user_id: USER_ID,
62
- name: "Example Assistant",
63
- }),
64
- { status: 200 },
65
- );
66
-
67
- await expect(
68
- fetchPlatformIdentityIds(BASE_URL, "assistant-key"),
69
- ).resolves.toEqual({
70
- assistantId: ASSISTANT_ID,
71
- organizationId: ORG_ID,
72
- userId: USER_ID,
73
- });
74
- expect(fetchCalls[0]?.url).toBe(
75
- `${BASE_URL}${PLATFORM_IDENTITY_VALIDATE_PATH}`,
76
- );
77
- expect(fetchCalls[0]?.init?.method).toBe("POST");
78
- const headers = new Headers(fetchCalls[0]?.init?.headers);
79
- expect(headers.get("Authorization")).toBe("Api-Key assistant-key");
80
- });
81
-
82
- test("strips a trailing slash from the base URL", async () => {
83
- fetchImpl = async () =>
84
- new Response(
85
- JSON.stringify({
86
- assistant_id: ASSISTANT_ID,
87
- organization_id: ORG_ID,
88
- user_id: USER_ID,
89
- }),
90
- { status: 200 },
91
- );
92
-
93
- await fetchPlatformIdentityIds(`${BASE_URL}/`, "assistant-key");
94
- expect(fetchCalls[0]?.url).toBe(
95
- `${BASE_URL}${PLATFORM_IDENTITY_VALIDATE_PATH}`,
96
- );
97
- });
98
-
99
- test("returns null on 401 without throwing", async () => {
100
- fetchImpl = async () => new Response("no", { status: 401 });
101
- await expect(
102
- fetchPlatformIdentityIds(BASE_URL, "assistant-key"),
103
- ).resolves.toBeNull();
104
- });
105
-
106
- test("returns null on a network error without throwing", async () => {
107
- fetchImpl = async () => {
108
- throw new Error("network down");
109
- };
110
- await expect(
111
- fetchPlatformIdentityIds(BASE_URL, "assistant-key"),
112
- ).resolves.toBeNull();
113
- });
114
- });
115
-
116
- describe("resolvePlatformAssistantId", () => {
117
- const originalFetch = globalThis.fetch;
118
- const originalAssistantApiKeyEnv = process.env.ASSISTANT_API_KEY;
119
- const fetchCalls: Array<{ url: string; init?: RequestInit }> = [];
120
- let fetchImpl: (
121
- input: RequestInfo | URL,
122
- init?: RequestInit,
123
- ) => Promise<Response> = async () =>
124
- new Response("not found", { status: 404 });
125
-
126
- beforeEach(() => {
127
- fetchCalls.length = 0;
128
- fetchImpl = async () => new Response("not found", { status: 404 });
129
- globalThis.fetch = (async (
130
- input: RequestInfo | URL,
131
- init?: RequestInit,
132
- ) => {
133
- const url = typeof input === "string" ? input : input.toString();
134
- fetchCalls.push({ url, init });
135
- return fetchImpl(input, init);
136
- }) as unknown as typeof fetch;
137
- delete process.env.ASSISTANT_API_KEY;
138
- setPlatformBaseUrl(undefined);
139
- setPlatformAssistantId(undefined);
140
- setPlatformOrganizationId(undefined);
141
- setPlatformUserId(undefined);
142
- _resetPlatformIdentityEnsureForTests();
143
- });
144
-
145
- afterEach(() => {
146
- globalThis.fetch = originalFetch;
147
- if (originalAssistantApiKeyEnv === undefined) {
148
- delete process.env.ASSISTANT_API_KEY;
149
- } else {
150
- process.env.ASSISTANT_API_KEY = originalAssistantApiKeyEnv;
151
- }
152
- setPlatformBaseUrl(undefined);
153
- setPlatformAssistantId(undefined);
154
- setPlatformOrganizationId(undefined);
155
- setPlatformUserId(undefined);
156
- _resetPlatformIdentityEnsureForTests();
157
- });
158
-
159
- test("returns the in-memory override without calling validate", async () => {
160
- setPlatformAssistantId(ASSISTANT_ID);
161
- process.env.ASSISTANT_API_KEY = "assistant-key";
162
- await expect(resolvePlatformAssistantId()).resolves.toBe(ASSISTANT_ID);
163
- expect(fetchCalls).toHaveLength(0);
164
- });
165
-
166
- test("returns empty when the in-memory override is unset and there is no API key", async () => {
167
- await expect(resolvePlatformAssistantId()).resolves.toBe("");
168
- expect(fetchCalls).toHaveLength(0);
169
- });
170
-
171
- test("loads ids from validate when the in-memory override is empty", async () => {
172
- process.env.ASSISTANT_API_KEY = "assistant-key";
173
- setPlatformBaseUrl(BASE_URL);
174
- fetchImpl = async () =>
175
- new Response(
176
- JSON.stringify({
177
- assistant_id: ASSISTANT_ID,
178
- organization_id: ORG_ID,
179
- user_id: USER_ID,
180
- }),
181
- { status: 200 },
182
- );
183
-
184
- await expect(resolvePlatformAssistantId()).resolves.toBe(ASSISTANT_ID);
185
- expect(fetchCalls).toHaveLength(1);
186
- expect(fetchCalls[0]?.url).toBe(
187
- `${getPlatformBaseUrl().replace(/\/+$/, "")}${PLATFORM_IDENTITY_VALIDATE_PATH}`,
188
- );
189
- });
190
-
191
- test("does not retry validate during the cooldown after a failure", async () => {
192
- process.env.ASSISTANT_API_KEY = "assistant-key";
193
- setPlatformBaseUrl(BASE_URL);
194
- fetchImpl = async () => new Response("down", { status: 503 });
195
-
196
- await expect(resolvePlatformAssistantId()).resolves.toBe("");
197
- await expect(resolvePlatformAssistantId()).resolves.toBe("");
198
- expect(fetchCalls).toHaveLength(1);
199
- });
200
-
201
- test("retries validate after a failed attempt once the cooldown is cleared", async () => {
202
- process.env.ASSISTANT_API_KEY = "assistant-key";
203
- setPlatformBaseUrl(BASE_URL);
204
- fetchImpl = async () => new Response("down", { status: 503 });
205
-
206
- await expect(resolvePlatformAssistantId()).resolves.toBe("");
207
- _resetPlatformIdentityEnsureForTests();
208
- fetchImpl = async () =>
209
- new Response(
210
- JSON.stringify({
211
- assistant_id: ASSISTANT_ID,
212
- organization_id: ORG_ID,
213
- user_id: USER_ID,
214
- }),
215
- { status: 200 },
216
- );
217
-
218
- await expect(resolvePlatformAssistantId()).resolves.toBe(ASSISTANT_ID);
219
- expect(fetchCalls).toHaveLength(2);
220
- });
221
-
222
- test("concurrent resolves share one in-flight validate", async () => {
223
- process.env.ASSISTANT_API_KEY = "assistant-key";
224
- setPlatformBaseUrl(BASE_URL);
225
- let release!: (value: Response) => void;
226
- let notifyFetchStarted!: () => void;
227
- const fetchStarted = new Promise<void>((resolve) => {
228
- notifyFetchStarted = resolve;
229
- });
230
- fetchImpl = () => {
231
- notifyFetchStarted();
232
- return new Promise<Response>((resolve) => {
233
- release = resolve;
234
- });
235
- };
236
-
237
- const first = resolvePlatformAssistantId();
238
- const second = resolvePlatformAssistantId();
239
- await fetchStarted;
240
- expect(fetchCalls).toHaveLength(1);
241
- release(
242
- new Response(
243
- JSON.stringify({
244
- assistant_id: ASSISTANT_ID,
245
- organization_id: ORG_ID,
246
- user_id: USER_ID,
247
- }),
248
- { status: 200 },
249
- ),
250
- );
251
- await expect(first).resolves.toBe(ASSISTANT_ID);
252
- await expect(second).resolves.toBe(ASSISTANT_ID);
253
- expect(fetchCalls).toHaveLength(1);
254
- });
255
- });
@@ -1,43 +0,0 @@
1
- /**
2
- * Raw-config helper shared by the config PATCH and SET routes, the paths that
3
- * write a coding agent's entry.
4
- */
5
-
6
- import { isPlainObject } from "../util/object.js";
7
-
8
- /**
9
- * Clearing a leaf of a coding agent's entry is a write of `null` - a PATCH of
10
- * `{ acp: { agents: { <id>: { model: null } } } }` or a
11
- * `config set acp.agents.<id>.model null`. The deep-merge assigns that literal
12
- * `null` because the stored value is a scalar, and a SET writes it verbatim by
13
- * design. Both `command` and `model` are optional strings in `AcpConfigSchema`,
14
- * so a persisted `null` makes every later `loadConfig()` warn and take its
15
- * salvage path, dropping the whole `acp` section with the agents defined in it.
16
- * Clearing means removing the key, so drop it here on every write path.
17
- *
18
- * A cleared `command` then reads as an omitted one: a bundled id inherits the
19
- * profile's command, and an id that has no profile fails the agents refinement
20
- * with a message naming the id, which tells the user more than zod's "expected
21
- * string, received null".
22
- */
23
- export function scrubNulledAcpAgentLeaves(raw: Record<string, unknown>): void {
24
- const acp = raw.acp;
25
- if (!isPlainObject(acp)) {
26
- return;
27
- }
28
- const agents = acp.agents;
29
- if (!isPlainObject(agents)) {
30
- return;
31
- }
32
- for (const entry of Object.values(agents)) {
33
- if (!isPlainObject(entry)) {
34
- continue;
35
- }
36
- if (entry.command === null) {
37
- delete entry.command;
38
- }
39
- if (entry.model === null) {
40
- delete entry.model;
41
- }
42
- }
43
- }
@@ -1,81 +0,0 @@
1
- /**
2
- * Covers the ACP config leaf that carries model selection, the per-agent
3
- * `model`. It is optional with no `.default()`, so an absent value must stay
4
- * absent after parsing: the bundled profile supplies the model a session
5
- * starts on, and a key materialized as `undefined` would shadow it.
6
- *
7
- * `command` is optional in the same shape, so an entry for a bundled id can
8
- * carry a model and nothing else; the record's own check keeps a command
9
- * required for every id that has no bundled profile to inherit one from.
10
- */
11
-
12
- import { describe, expect, test } from "bun:test";
13
-
14
- import { AcpAgentConfigSchema, AcpConfigSchema } from "./acp-schema.js";
15
-
16
- describe("AcpConfigSchema", () => {
17
- test("populates defaults for an empty config", () => {
18
- expect(AcpConfigSchema.parse({})).toEqual({
19
- maxConcurrentSessions: 4,
20
- agents: {},
21
- });
22
- });
23
- });
24
-
25
- describe("AcpConfigSchema agents", () => {
26
- test("a bundled id's entry may omit command and name only a model", () => {
27
- const parsed = AcpConfigSchema.parse({
28
- agents: { claude: { model: "sonnet" } },
29
- });
30
-
31
- expect(parsed.agents).toEqual({ claude: { args: [], model: "sonnet" } });
32
- expect("command" in parsed.agents.claude!).toBe(false);
33
- });
34
-
35
- test("an id with no bundled profile needs a command", () => {
36
- const result = AcpConfigSchema.safeParse({
37
- agents: { mine: { model: "sonnet" } },
38
- });
39
-
40
- expect(result.success).toBe(false);
41
- if (result.success) {
42
- return;
43
- }
44
- expect(result.error.issues.map((issue) => issue.path)).toEqual([
45
- ["agents", "mine", "command"],
46
- ]);
47
- expect(result.error.issues[0]?.message).toContain("acp.agents.mine");
48
- });
49
-
50
- test("an id naming an Object.prototype member inherits no command", () => {
51
- expect(
52
- AcpConfigSchema.safeParse({ agents: { constructor: { model: "x" } } })
53
- .success,
54
- ).toBe(false);
55
- });
56
- });
57
-
58
- describe("AcpAgentConfigSchema", () => {
59
- test("round-trips a per-agent model override", () => {
60
- expect(
61
- AcpAgentConfigSchema.parse({
62
- command: "claude-agent-acp",
63
- model: "opus",
64
- }),
65
- ).toEqual({ command: "claude-agent-acp", args: [], model: "opus" });
66
- });
67
-
68
- test("leaves model unset when omitted, so a bundled profile's shows through", () => {
69
- const parsed = AcpAgentConfigSchema.parse({ command: "claude-agent-acp" });
70
-
71
- expect(parsed.model).toBeUndefined();
72
- expect("model" in parsed).toBe(false);
73
- });
74
-
75
- test("rejects a non-string model", () => {
76
- expect(
77
- AcpAgentConfigSchema.safeParse({ command: "claude-agent-acp", model: 3 })
78
- .success,
79
- ).toBe(false);
80
- });
81
- });
@@ -1,201 +0,0 @@
1
- /**
2
- * Bound platform identity (assistant, organization, user).
3
- *
4
- * Django maps an assistant API key to these ids via
5
- * `POST /v1/internal/assistants/validate/`. Process startup rehydrates from
6
- * that endpoint into the in-memory overrides. Resolution reads those
7
- * overrides (and `PLATFORM_ORGANIZATION_ID` / `PLATFORM_USER_ID` when set).
8
- * When the in-memory assistant id is empty, the next resolve retries
9
- * validate (single-flight, with a cooldown after a failed attempt).
10
- */
11
-
12
- import { credentialKey } from "../security/credential-key.js";
13
- import { getSecureKeyAsync } from "../security/secure-keys.js";
14
- import { getLogger } from "../util/logger.js";
15
- import {
16
- getPlatformAssistantId,
17
- getPlatformBaseUrl,
18
- getPlatformOrganizationId,
19
- getPlatformUserId,
20
- setPlatformAssistantId,
21
- setPlatformOrganizationId,
22
- setPlatformUserId,
23
- } from "./env.js";
24
-
25
- const log = getLogger("platform-identity");
26
-
27
- export const PLATFORM_IDENTITY_VALIDATE_PATH =
28
- "/v1/internal/assistants/validate/";
29
-
30
- const VALIDATE_TIMEOUT_MS = 5_000;
31
- const ENSURE_COOLDOWN_MS = 10_000;
32
-
33
- export type PlatformIdentityIds = {
34
- assistantId: string;
35
- organizationId: string;
36
- userId: string;
37
- };
38
-
39
- function asNonEmptyString(value: unknown): string | undefined {
40
- if (typeof value !== "string") {
41
- return undefined;
42
- }
43
- const trimmed = value.trim();
44
- return trimmed.length > 0 ? trimmed : undefined;
45
- }
46
-
47
- export function applyPlatformIdentityIds(ids: PlatformIdentityIds): void {
48
- if (ids.assistantId) {
49
- setPlatformAssistantId(ids.assistantId);
50
- }
51
- if (ids.organizationId) {
52
- setPlatformOrganizationId(ids.organizationId);
53
- }
54
- if (ids.userId) {
55
- setPlatformUserId(ids.userId);
56
- }
57
- }
58
-
59
- /**
60
- * Trade an assistant API key for the bound platform ids.
61
- *
62
- * Returns null when the platform is unreachable, refuses the key, or the
63
- * body has no ids. Never throws.
64
- */
65
- export async function fetchPlatformIdentityIds(
66
- baseUrl: string,
67
- apiKey: string,
68
- ): Promise<PlatformIdentityIds | null> {
69
- const url = `${baseUrl.replace(/\/+$/, "")}${PLATFORM_IDENTITY_VALIDATE_PATH}`;
70
- try {
71
- const res = await fetch(url, {
72
- method: "POST",
73
- headers: {
74
- Authorization: `Api-Key ${apiKey}`,
75
- "Content-Type": "application/json",
76
- },
77
- body: "{}",
78
- signal: AbortSignal.timeout(VALIDATE_TIMEOUT_MS),
79
- });
80
- if (!res.ok) {
81
- log.warn(
82
- { status: res.status },
83
- "platform identity validate returned non-2xx",
84
- );
85
- return null;
86
- }
87
- const body: unknown = await res.json();
88
- if (!body || typeof body !== "object") {
89
- return null;
90
- }
91
- const obj = body as Record<string, unknown>;
92
- const assistantId = asNonEmptyString(obj.assistant_id);
93
- const organizationId = asNonEmptyString(obj.organization_id);
94
- const userId = asNonEmptyString(obj.user_id);
95
- if (!assistantId && !organizationId && !userId) {
96
- return null;
97
- }
98
- return {
99
- assistantId: assistantId ?? "",
100
- organizationId: organizationId ?? "",
101
- userId: userId ?? "",
102
- };
103
- } catch (err) {
104
- log.warn({ err }, "platform identity validate failed");
105
- return null;
106
- }
107
- }
108
-
109
- async function readAssistantApiKey(): Promise<string> {
110
- try {
111
- const stored = (
112
- await getSecureKeyAsync(credentialKey("vellum", "assistant_api_key"))
113
- )?.trim();
114
- if (stored) {
115
- return stored;
116
- }
117
- } catch (err) {
118
- log.warn({ err }, "failed to read assistant API key from credential store");
119
- }
120
- return process.env.ASSISTANT_API_KEY?.trim() ?? "";
121
- }
122
-
123
- let ensureInFlight: Promise<void> | null = null;
124
- let nextEnsureAttemptAt = 0;
125
-
126
- export function _resetPlatformIdentityEnsureForTests(): void {
127
- ensureInFlight = null;
128
- nextEnsureAttemptAt = 0;
129
- }
130
-
131
- /**
132
- * Load in-memory platform ids from validate when they are missing.
133
- *
134
- * No-ops when the assistant id is already set, when auth prerequisites are
135
- * missing, or when a failed attempt is still inside the cooldown window.
136
- * Concurrent callers share one in-flight request.
137
- */
138
- export async function ensurePlatformIdentityIds(): Promise<void> {
139
- if (getPlatformAssistantId().trim()) {
140
- return;
141
- }
142
- if (Date.now() < nextEnsureAttemptAt) {
143
- return;
144
- }
145
- if (!ensureInFlight) {
146
- ensureInFlight = (async () => {
147
- try {
148
- const apiKey = await readAssistantApiKey();
149
- const baseUrl = getPlatformBaseUrl();
150
- if (!apiKey || !baseUrl) {
151
- return;
152
- }
153
- const ids = await fetchPlatformIdentityIds(baseUrl, apiKey);
154
- if (!ids) {
155
- nextEnsureAttemptAt = Date.now() + ENSURE_COOLDOWN_MS;
156
- return;
157
- }
158
- applyPlatformIdentityIds(ids);
159
- nextEnsureAttemptAt = 0;
160
- log.info("Loaded platform identity from platform validate");
161
- } finally {
162
- ensureInFlight = null;
163
- }
164
- })();
165
- }
166
- await ensureInFlight;
167
- }
168
-
169
- export async function resolvePlatformAssistantId(): Promise<string> {
170
- const existing = getPlatformAssistantId().trim();
171
- if (existing) {
172
- return existing;
173
- }
174
- await ensurePlatformIdentityIds();
175
- return getPlatformAssistantId().trim();
176
- }
177
-
178
- export async function resolvePlatformAssistantIdOrNull(): Promise<
179
- string | null
180
- > {
181
- const id = await resolvePlatformAssistantId();
182
- return id || null;
183
- }
184
-
185
- export async function resolvePlatformOrganizationId(): Promise<string> {
186
- const existing = getPlatformOrganizationId().trim();
187
- if (existing) {
188
- return existing;
189
- }
190
- await ensurePlatformIdentityIds();
191
- return getPlatformOrganizationId().trim();
192
- }
193
-
194
- export async function resolvePlatformUserId(): Promise<string> {
195
- const existing = getPlatformUserId().trim();
196
- if (existing) {
197
- return existing;
198
- }
199
- await ensurePlatformIdentityIds();
200
- return getPlatformUserId().trim();
201
- }