@vellumai/assistant 0.12.0 → 0.12.1-dev.202609141913.5e16607

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 (441) hide show
  1. package/AGENTS.md +5 -1
  2. package/ARCHITECTURE.md +11 -12
  3. package/docs/architecture/turn-actor.md +15 -8
  4. package/docs/guardian-request-flow.md +16 -0
  5. package/openapi.yaml +292 -50
  6. package/package.json +1 -1
  7. package/scripts/smoke-desktop-window-theme.ts +186 -0
  8. package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
  9. package/src/__tests__/app-compiler.test.ts +6 -0
  10. package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
  11. package/src/__tests__/app-dir-path-guard.test.ts +1 -3
  12. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
  13. package/src/__tests__/computer-use-tools.test.ts +17 -5
  14. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  15. package/src/__tests__/config-schema.test.ts +28 -29
  16. package/src/__tests__/config-watcher.test.ts +23 -8
  17. package/src/__tests__/connection-model-compat.test.ts +2 -2
  18. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  19. package/src/__tests__/conversation-pairing.test.ts +26 -0
  20. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
  21. package/src/__tests__/conversation-queue.test.ts +48 -207
  22. package/src/__tests__/conversation-retry-discard.test.ts +54 -1
  23. package/src/__tests__/conversation-skill-tools.test.ts +27 -0
  24. package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
  25. package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
  26. package/src/__tests__/conversation-title-service.test.ts +14 -10
  27. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
  28. package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
  29. package/src/__tests__/credential-record-retire.test.ts +171 -1
  30. package/src/__tests__/credential-routes.test.ts +212 -3
  31. package/src/__tests__/credential-security-invariants.test.ts +4 -2
  32. package/src/__tests__/cu-unified-flow.test.ts +8 -2
  33. package/src/__tests__/document-sync-tags.test.ts +25 -0
  34. package/src/__tests__/drain-kick-guard.test.ts +0 -2
  35. package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
  36. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  37. package/src/__tests__/git-porcelain.test.ts +47 -0
  38. package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
  39. package/src/__tests__/host-bash-proxy.test.ts +26 -45
  40. package/src/__tests__/host-browser-proxy.test.ts +6 -17
  41. package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
  42. package/src/__tests__/host-file-proxy.test.ts +11 -23
  43. package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
  44. package/src/__tests__/llm-catalog-parity.test.ts +25 -0
  45. package/src/__tests__/mcp-auth-routes.test.ts +6 -9
  46. package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
  47. package/src/__tests__/mcp-health-check.test.ts +8 -11
  48. package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
  49. package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
  50. package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
  51. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  52. package/src/__tests__/messaging-send-tool.test.ts +355 -548
  53. package/src/__tests__/model-intents.test.ts +3 -0
  54. package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
  55. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  56. package/src/__tests__/platform-callback-registration.test.ts +8 -16
  57. package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
  58. package/src/__tests__/plugin-import-boundary-guard.test.ts +13 -0
  59. package/src/__tests__/resolve-app.test.ts +135 -0
  60. package/src/__tests__/script-proxy-certs.test.ts +35 -0
  61. package/src/__tests__/service-account-token.test.ts +247 -0
  62. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  63. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  64. package/src/__tests__/source-fingerprint.test.ts +184 -0
  65. package/src/__tests__/subagent-tool-gate-mode.test.ts +19 -3
  66. package/src/__tests__/subagent-tools.test.ts +3 -2
  67. package/src/__tests__/telephony-tts-guard.test.ts +38 -3
  68. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
  69. package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
  70. package/src/__tests__/workspace-git-service.test.ts +26 -0
  71. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
  72. package/src/acp/__tests__/agent-process.test.ts +258 -4
  73. package/src/acp/__tests__/auth-required.test.ts +96 -0
  74. package/src/acp/__tests__/client-handler.test.ts +90 -2
  75. package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
  76. package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
  77. package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
  78. package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
  79. package/src/acp/__tests__/session-manager.test.ts +895 -4
  80. package/src/acp/agent-process.test.ts +4 -1
  81. package/src/acp/agent-process.ts +94 -9
  82. package/src/acp/auth-required.ts +50 -1
  83. package/src/acp/auto-install.test.ts +9 -7
  84. package/src/acp/client-handler.ts +16 -3
  85. package/src/acp/model-config.test.ts +166 -0
  86. package/src/acp/model-config.ts +138 -0
  87. package/src/acp/resolve-agent.test.ts +220 -6
  88. package/src/acp/resolve-agent.ts +88 -23
  89. package/src/acp/session-manager.test.ts +196 -3
  90. package/src/acp/session-manager.ts +441 -18
  91. package/src/acp/types.ts +50 -5
  92. package/src/api/events/acp-session-model-update.test.ts +88 -0
  93. package/src/api/events/acp-session-model-update.ts +46 -0
  94. package/src/api/events/app-files-changed.ts +4 -3
  95. package/src/api/events/notification-intent.ts +2 -0
  96. package/src/api/index.ts +6 -0
  97. package/src/apps/app-store.ts +1 -1
  98. package/src/apps/resolve-app.ts +81 -0
  99. package/src/apps/source-fingerprint.ts +266 -0
  100. package/src/bundler/app-compiler.ts +15 -0
  101. package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
  102. package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
  103. package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
  104. package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
  105. package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
  106. package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
  107. package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
  108. package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
  109. package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
  110. package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
  111. package/src/calls/__tests__/voice-control-protocol.test.ts +58 -25
  112. package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
  113. package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
  114. package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
  115. package/src/calls/__tests__/voice-session-bridge.test.ts +37 -1
  116. package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
  117. package/src/calls/barge-in-guard.ts +118 -0
  118. package/src/calls/call-constants.ts +24 -4
  119. package/src/calls/call-controller.ts +499 -199
  120. package/src/calls/call-transport.ts +16 -0
  121. package/src/calls/media-stream-output.ts +32 -0
  122. package/src/calls/media-stream-server.ts +82 -30
  123. package/src/calls/media-stream-stt-session.ts +15 -0
  124. package/src/{live-voice → calls}/progress-narration.ts +2 -2
  125. package/src/calls/resolve-call-tts-provider.ts +33 -2
  126. package/src/calls/tts-call-strategy.ts +9 -5
  127. package/src/calls/types.ts +2 -0
  128. package/src/calls/voice-control-protocol.ts +53 -21
  129. package/src/calls/voice-leg-coordinator.ts +189 -0
  130. package/src/calls/voice-progress-cadence.ts +423 -0
  131. package/src/calls/voice-session-bridge.ts +59 -46
  132. package/src/calls/voice-triage-escalate.ts +175 -56
  133. package/src/cli/commands/__tests__/apps.test.ts +245 -0
  134. package/src/cli/commands/__tests__/bash.test.ts +53 -0
  135. package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
  136. package/src/cli/commands/apps.help.ts +67 -13
  137. package/src/cli/commands/apps.ts +183 -0
  138. package/src/cli/commands/bash.help.ts +8 -13
  139. package/src/cli/commands/bash.ts +7 -25
  140. package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
  141. package/src/cli/commands/channels/index.help.ts +70 -2
  142. package/src/cli/commands/channels/index.ts +16 -3
  143. package/src/cli/commands/channels/send.ts +128 -0
  144. package/src/cli/commands/credentials.help.ts +6 -2
  145. package/src/cli/commands/credentials.ts +2 -2
  146. package/src/cli/commands/mcp.help.ts +8 -8
  147. package/src/cli/commands/mcp.ts +1 -1
  148. package/src/cli/commands/roadmap.help.ts +5 -1
  149. package/src/cli/commands/roadmap.ts +1 -1
  150. package/src/cli/lib/bundled-marketplace.json +103 -90
  151. package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
  152. package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
  153. package/src/config/__tests__/platform-identity.test.ts +255 -0
  154. package/src/config/__tests__/platform-rehydration.test.ts +99 -9
  155. package/src/config/acp-agent-write.ts +43 -0
  156. package/src/config/acp-defaults.test.ts +13 -3
  157. package/src/config/acp-defaults.ts +23 -6
  158. package/src/config/acp-schema.test.ts +81 -0
  159. package/src/config/acp-schema.ts +30 -2
  160. package/src/config/bundled-skills/acp/SKILL.md +22 -14
  161. package/src/config/bundled-skills/acp/TOOLS.json +5 -1
  162. package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
  163. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  164. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  165. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  166. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
  167. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  168. package/src/config/bundled-skills/schedule/SKILL.md +3 -4
  169. package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
  170. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
  171. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  172. package/src/config/default-profile-catalog.ts +1 -1
  173. package/src/config/env.ts +2 -2
  174. package/src/config/feature-flag-registry.json +24 -12
  175. package/src/config/loader.ts +1 -0
  176. package/src/config/memory-v3-gate.test.ts +31 -0
  177. package/src/config/memory-v3-gate.ts +20 -16
  178. package/src/config/platform-identity.ts +201 -0
  179. package/src/config/platform-rehydration.ts +11 -27
  180. package/src/config/schema.ts +2 -2
  181. package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
  182. package/src/config/schemas/__tests__/voice.test.ts +148 -0
  183. package/src/config/schemas/calls.ts +1 -28
  184. package/src/config/schemas/live-voice.ts +1 -173
  185. package/src/config/schemas/mcp.ts +1 -1
  186. package/src/config/schemas/memory-retrospective.ts +10 -0
  187. package/src/config/schemas/services.ts +8 -0
  188. package/src/config/schemas/skills.ts +0 -14
  189. package/src/config/schemas/voice.ts +150 -0
  190. package/src/credential-execution/process-manager.test.ts +18 -19
  191. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
  192. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
  193. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
  194. package/src/daemon/app-change-notify.ts +45 -0
  195. package/src/daemon/config-watcher.ts +13 -194
  196. package/src/daemon/conversation-process.ts +35 -64
  197. package/src/daemon/conversation-skill-tools.ts +13 -31
  198. package/src/daemon/conversation-store.ts +1 -1
  199. package/src/daemon/conversation-surfaces.ts +10 -8
  200. package/src/daemon/conversation-tool-setup.ts +37 -43
  201. package/src/daemon/conversation.ts +0 -3
  202. package/src/daemon/host-bash-proxy.ts +8 -12
  203. package/src/daemon/host-browser-proxy.ts +15 -1
  204. package/src/daemon/host-file-proxy.ts +8 -10
  205. package/src/daemon/host-transfer-proxy.ts +14 -18
  206. package/src/daemon/lifecycle.ts +0 -5
  207. package/src/daemon/mcp-reload-service.ts +5 -5
  208. package/src/daemon/message-types/sync.ts +1 -0
  209. package/src/daemon/orphan-reaper.ts +1 -1
  210. package/src/daemon/providers-setup.ts +1 -1
  211. package/src/daemon/shutdown-handlers.ts +1 -9
  212. package/src/daemon/skill-memory-refresh.ts +64 -0
  213. package/src/daemon/tool-side-effects.ts +7 -18
  214. package/src/desktop/__tests__/fake-desktop.ts +119 -0
  215. package/src/desktop/desktop-chrome-policy.test.ts +71 -0
  216. package/src/desktop/desktop-chrome-policy.ts +42 -0
  217. package/src/desktop/desktop-dependencies.test.ts +102 -0
  218. package/src/desktop/desktop-dependencies.ts +306 -0
  219. package/src/desktop/desktop-feature.test.ts +18 -0
  220. package/src/desktop/desktop-feature.ts +19 -0
  221. package/src/desktop/desktop-panel-config.test.ts +135 -0
  222. package/src/desktop/desktop-panel-config.ts +149 -0
  223. package/src/desktop/desktop-session-manager.test.ts +627 -0
  224. package/src/desktop/desktop-session-manager.ts +814 -0
  225. package/src/desktop/desktop-stream-bridge.test.ts +395 -0
  226. package/src/desktop/desktop-stream-bridge.ts +214 -0
  227. package/src/desktop/desktop-wallpaper.test.ts +191 -0
  228. package/src/desktop/desktop-wallpaper.ts +113 -0
  229. package/src/desktop/desktop-window-theme.ts +170 -0
  230. package/src/home/__tests__/feed-writer.test.ts +22 -0
  231. package/src/home/feed-writer.ts +11 -2
  232. package/src/hooks/types.ts +33 -0
  233. package/src/i18n/AGENTS.md +22 -0
  234. package/src/i18n/__tests__/i18n.test.ts +108 -0
  235. package/src/i18n/index.ts +16 -0
  236. package/src/i18n/locales.ts +93 -0
  237. package/src/i18n/messages.ts +61 -0
  238. package/src/i18n/title.ts +25 -0
  239. package/src/inbound/platform-callback-registration.ts +4 -5
  240. package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
  241. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  242. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  243. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
  244. package/src/live-voice/live-voice-session.ts +213 -693
  245. package/src/live-voice/protocol.ts +0 -2
  246. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  247. package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
  248. package/src/mcp/effective-config.ts +3 -3
  249. package/src/mcp/mcp-header-store.ts +29 -45
  250. package/src/mcp/spec-schema.ts +111 -0
  251. package/src/mcp/startup.ts +8 -4
  252. package/src/mcp/workspace-mcp-config.ts +188 -0
  253. package/src/messaging/provider.ts +10 -3
  254. package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
  255. package/src/messaging/providers/callback-routing.ts +18 -0
  256. package/src/messaging/providers/channel-transport.ts +56 -0
  257. package/src/messaging/providers/discord/transport.ts +17 -0
  258. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
  259. package/src/messaging/providers/slack/adapter.ts +7 -44
  260. package/src/messaging/providers/slack/transport.ts +16 -0
  261. package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
  262. package/src/messaging/providers/telegram-bot/client.ts +0 -26
  263. package/src/messaging/providers/telegram-bot/transport.ts +20 -0
  264. package/src/messaging/providers/whatsapp/adapter.ts +1 -48
  265. package/src/messaging/providers/whatsapp/transport.ts +18 -0
  266. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
  267. package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
  268. package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
  269. package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
  270. package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
  271. package/src/notifications/adapters/macos.ts +3 -0
  272. package/src/notifications/assistant-reply-producer.ts +8 -3
  273. package/src/notifications/conversation-pairing.ts +36 -16
  274. package/src/notifications/delivered-post-record.ts +11 -1
  275. package/src/notifications/guardian-feed-projection.ts +125 -5
  276. package/src/notifications/home-feed-side-effect.ts +55 -7
  277. package/src/notifications/schedule-result-producer.ts +66 -22
  278. package/src/oauth/__tests__/seed-providers-managed.test.ts +54 -0
  279. package/src/oauth/byo-connection.test.ts +45 -0
  280. package/src/oauth/byo-connection.ts +36 -6
  281. package/src/oauth/connection-resolver.test.ts +73 -0
  282. package/src/oauth/connection-resolver.ts +95 -2
  283. package/src/oauth/seed-providers.ts +165 -0
  284. package/src/outbound-proxy/certs.ts +3 -5
  285. package/src/permissions/checker.test.ts +11 -6
  286. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  287. package/src/persistence/conversation-crud.ts +71 -63
  288. package/src/persistence/conversation-lineage.ts +12 -4
  289. package/src/persistence/conversation-title-placeholders.ts +23 -0
  290. package/src/persistence/conversation-title-service.ts +9 -26
  291. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  292. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  293. package/src/persistence/message-cursor.ts +78 -0
  294. package/src/persistence/message-reads.ts +30 -0
  295. package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
  296. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
  297. package/src/persistence/schema/memory-core.ts +5 -0
  298. package/src/platform/client.test.ts +4 -2
  299. package/src/platform/client.ts +2 -10
  300. package/src/plugin-api/constants.ts +2 -0
  301. package/src/plugin-api/index.ts +1 -0
  302. package/src/plugin-api/types.ts +2 -0
  303. package/src/plugins/defaults/index.ts +2 -0
  304. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
  305. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
  306. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
  307. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
  308. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
  309. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
  310. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
  311. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
  312. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
  313. package/src/plugins/defaults/memory/graph/capability-seed.ts +4 -6
  314. package/src/plugins/defaults/memory/hooks/init.ts +10 -0
  315. package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
  316. package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
  317. package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
  318. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
  319. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
  320. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
  321. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
  322. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
  323. package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
  324. package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
  325. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
  326. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
  327. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
  328. package/src/plugins/defaults/memory/startup.ts +6 -1
  329. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
  330. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  331. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +89 -0
  332. package/src/plugins/defaults/memory/worker.ts +6 -0
  333. package/src/plugins/mcp-servers.ts +15 -75
  334. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  335. package/src/providers/gemini/client.ts +9 -23
  336. package/src/providers/gemini-thought-signature.test.ts +63 -0
  337. package/src/providers/gemini-thought-signature.ts +44 -0
  338. package/src/providers/inference/auth.ts +2 -3
  339. package/src/providers/inference/connection-availability.ts +27 -8
  340. package/src/providers/inference/resolve-auth.ts +22 -4
  341. package/src/providers/inference/service-account-token.ts +248 -0
  342. package/src/providers/model-catalog.ts +34 -0
  343. package/src/providers/model-intents.ts +10 -5
  344. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
  345. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
  346. package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
  347. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
  348. package/src/providers/openai/chat-completions-provider.ts +192 -78
  349. package/src/providers/openai/codex-models.ts +0 -4
  350. package/src/providers/openai/google-thought-signature.ts +320 -0
  351. package/src/runtime/AGENTS.md +2 -0
  352. package/src/runtime/__tests__/channel-send.test.ts +443 -0
  353. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
  354. package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
  355. package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
  356. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
  357. package/src/runtime/auth/same-actor.ts +38 -3
  358. package/src/runtime/channel-send.ts +316 -0
  359. package/src/runtime/http-server.ts +160 -151
  360. package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
  361. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +205 -0
  362. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
  363. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
  364. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  365. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
  366. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
  367. package/src/runtime/routes/acp-routes.test.ts +15 -0
  368. package/src/runtime/routes/acp-routes.ts +72 -9
  369. package/src/runtime/routes/app-management-routes.ts +73 -0
  370. package/src/runtime/routes/app-routes.ts +1 -1
  371. package/src/runtime/routes/channel-send-routes.ts +85 -0
  372. package/src/runtime/routes/conversation-list-routes.ts +14 -3
  373. package/src/runtime/routes/conversation-query-routes.ts +40 -0
  374. package/src/runtime/routes/credential-routes.ts +19 -10
  375. package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
  376. package/src/runtime/routes/desktop-setup-routes.ts +35 -0
  377. package/src/runtime/routes/diagnostics-routes.ts +55 -3
  378. package/src/runtime/routes/index.ts +4 -2
  379. package/src/runtime/routes/log-export-routes.ts +2 -0
  380. package/src/runtime/routes/mcp-auth-routes.ts +39 -47
  381. package/src/runtime/routes/migration-routes.ts +6 -20
  382. package/src/runtime/routes/platform-routes.ts +18 -15
  383. package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
  384. package/src/runtime/services/conversation-serializer.ts +16 -3
  385. package/src/runtime/sync/resource-sync-events.ts +2 -1
  386. package/src/schedule/worker.ts +1 -1
  387. package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
  388. package/src/security/ces-http-record-backend.ts +120 -0
  389. package/src/security/ces-rpc-record-backend.ts +7 -0
  390. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
  391. package/src/skills/workspace-skill-md-signature.ts +50 -0
  392. package/src/subagent/consult-context.ts +12 -25
  393. package/src/tools/acp/list-agents.test.ts +3 -1
  394. package/src/tools/acp/spawn.test.ts +146 -11
  395. package/src/tools/acp/spawn.ts +21 -3
  396. package/src/tools/acp/status.test.ts +94 -0
  397. package/src/tools/acp/status.ts +40 -3
  398. package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
  399. package/src/tools/capability-offer.test.ts +22 -2
  400. package/src/tools/capability-offer.ts +16 -1
  401. package/src/tools/computer-use/definitions.ts +4 -2
  402. package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
  403. package/src/tools/credentials/metadata-store.ts +100 -0
  404. package/src/tools/host-filesystem/edit.test.ts +2 -1
  405. package/src/tools/host-filesystem/edit.ts +2 -2
  406. package/src/tools/host-filesystem/read.test.ts +2 -1
  407. package/src/tools/host-filesystem/read.ts +2 -2
  408. package/src/tools/host-filesystem/transfer.test.ts +2 -1
  409. package/src/tools/host-filesystem/transfer.ts +2 -2
  410. package/src/tools/host-filesystem/write.test.ts +2 -1
  411. package/src/tools/host-filesystem/write.ts +2 -2
  412. package/src/tools/host-terminal/host-shell.test.ts +16 -0
  413. package/src/tools/host-terminal/host-shell.ts +4 -20
  414. package/src/tools/policy-context.ts +6 -7
  415. package/src/tools/subagent/spawn.ts +5 -8
  416. package/src/tools/terminal/__tests__/safe-env.test.ts +6 -6
  417. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
  418. package/src/tools/terminal/safe-env.ts +23 -3
  419. package/src/tools/terminal/sanitized-bash.ts +105 -0
  420. package/src/tools/watch/watch-retro-report.ts +0 -8
  421. package/src/util/__tests__/language-subtag.test.ts +23 -1
  422. package/src/util/ca-bundle.ts +13 -0
  423. package/src/util/language-subtag.ts +16 -0
  424. package/src/util/platform.ts +8 -0
  425. package/src/workspace/git-porcelain.ts +66 -0
  426. package/src/workspace/git-service.ts +5 -54
  427. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
  428. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
  429. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
  430. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
  431. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
  432. package/src/workspace/migrations/registry.ts +6 -0
  433. package/src/__tests__/app-source-watcher.test.ts +0 -218
  434. package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
  435. package/src/__tests__/speaker-identification.test.ts +0 -56
  436. package/src/calls/speaker-identification.ts +0 -233
  437. package/src/daemon/app-source-watcher.ts +0 -218
  438. package/src/messaging/providers/whatsapp/client.ts +0 -29
  439. package/src/runtime/routes/debug-bash-routes.ts +0 -173
  440. package/src/util/fs-watcher-error.ts +0 -36
  441. /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
@@ -21,11 +21,29 @@ const log = getLogger("byo-oauth-connection");
21
21
  /** Default per-request timeout to prevent hung requests from blocking indefinitely. */
22
22
  const REQUEST_TIMEOUT_MS = 30_000;
23
23
 
24
+ /**
25
+ * How the access token is attached to an outbound request. Almost every
26
+ * provider reads `Authorization: Bearer <token>`; a few use their own header
27
+ * (Shopify's Admin API reads `X-Shopify-Access-Token` and ignores
28
+ * Authorization entirely). Derived from the provider's header-type injection
29
+ * template so the seed is the single source of truth.
30
+ */
31
+ export interface BYOTokenHeader {
32
+ name: string;
33
+ /** Text placed before the token, e.g. `"Bearer "`, `"Bot "`, or `""`. */
34
+ valuePrefix: string;
35
+ }
36
+
24
37
  export interface BYOOAuthConnectionOptions {
25
38
  id: string;
26
39
  provider: string;
27
40
  baseUrl: string;
28
41
  accountInfo: string | null;
42
+ /**
43
+ * Token header override. When omitted the connection falls back to
44
+ * `Authorization: Bearer` (or `Bot` for discord_channel).
45
+ */
46
+ tokenHeader?: BYOTokenHeader | null;
29
47
  }
30
48
 
31
49
  export class BYOOAuthConnection implements OAuthConnection {
@@ -34,12 +52,14 @@ export class BYOOAuthConnection implements OAuthConnection {
34
52
  readonly accountInfo: string | null;
35
53
 
36
54
  private readonly baseUrl: string;
55
+ private readonly tokenHeader: BYOTokenHeader | null;
37
56
 
38
57
  constructor(opts: BYOOAuthConnectionOptions) {
39
58
  this.id = opts.id;
40
59
  this.provider = opts.provider;
41
60
  this.baseUrl = opts.baseUrl;
42
61
  this.accountInfo = opts.accountInfo;
62
+ this.tokenHeader = opts.tokenHeader ?? null;
43
63
  }
44
64
 
45
65
  async request(req: OAuthConnectionRequest): Promise<OAuthConnectionResponse> {
@@ -51,8 +71,12 @@ export class BYOOAuthConnection implements OAuthConnection {
51
71
  // Discord bot tokens authenticate with the `Bot ` scheme, not
52
72
  // `Bearer`. Sending Bearer here reaches Discord as an unusable
53
73
  // credential and comes back 401, which reads as a revoked token.
54
- const authScheme =
55
- this.provider === "discord_channel" ? "Bot" : "Bearer";
74
+ // Providers with their own token header (Shopify) override the
75
+ // whole thing via `tokenHeader`.
76
+ const tokenHeader: BYOTokenHeader = this.tokenHeader ?? {
77
+ name: "Authorization",
78
+ valuePrefix: this.provider === "discord_channel" ? "Bot " : "Bearer ",
79
+ };
56
80
  const requestPath = isTelegram
57
81
  ? buildTelegramBotApiPath(req.path, token)
58
82
  : req.path;
@@ -93,16 +117,22 @@ export class BYOOAuthConnection implements OAuthConnection {
93
117
  }
94
118
  }
95
119
  if (!isTelegram) {
96
- headers.set("Authorization", `${authScheme} ${token}`);
120
+ // The credential always wins over a caller-supplied value, and a
121
+ // provider that reads its own header must not also receive a
122
+ // stray Authorization the caller happened to send.
123
+ if (tokenHeader.name.toLowerCase() !== "authorization") {
124
+ headers.delete("Authorization");
125
+ }
126
+ headers.set(tokenHeader.name, `${tokenHeader.valuePrefix}${token}`);
97
127
  }
98
128
 
99
129
  const resp = await fetch(fullUrl, {
100
130
  method: req.method,
101
131
  headers,
102
132
  body: hasBody
103
- ? (binaryBody !== undefined
104
- ? Buffer.from(binaryBody)
105
- : (rawBody ?? JSON.stringify(req.body)))
133
+ ? binaryBody !== undefined
134
+ ? Buffer.from(binaryBody)
135
+ : (rawBody ?? JSON.stringify(req.body))
106
136
  : undefined,
107
137
  // Following a redirect would replay a POST as a GET against a URL
108
138
  // the caller never asked for, and hide the 3xx from them.
@@ -75,6 +75,7 @@ import {
75
75
  resolveEffectiveBaseUrl,
76
76
  resolveOAuthConnection,
77
77
  resolveOAuthConnectionWithMeta,
78
+ resolveTokenHeader,
78
79
  } from "./connection-resolver.js";
79
80
  import { PlatformOAuthConnection } from "./platform-connection.js";
80
81
 
@@ -753,3 +754,75 @@ describe("resolveEffectiveBaseUrl", () => {
753
754
  ).toBe("https://gmail.googleapis.com/gmail/v1/users/me");
754
755
  });
755
756
  });
757
+
758
+ describe("resolveTokenHeader", () => {
759
+ const shopify = JSON.stringify([
760
+ {
761
+ hostPattern: "*.myshopify.com",
762
+ injectionType: "header",
763
+ headerName: "X-Shopify-Access-Token",
764
+ valuePrefix: "",
765
+ },
766
+ ]);
767
+
768
+ test("returns null when the provider declares no templates", () => {
769
+ expect(resolveTokenHeader(undefined, "https://api.example.com")).toBeNull();
770
+ expect(resolveTokenHeader(null, "https://api.example.com")).toBeNull();
771
+ expect(resolveTokenHeader("[]", "https://api.example.com")).toBeNull();
772
+ });
773
+
774
+ test("returns null for malformed JSON", () => {
775
+ expect(
776
+ resolveTokenHeader("{not json", "https://api.example.com"),
777
+ ).toBeNull();
778
+ });
779
+
780
+ test("ignores non-header injection templates", () => {
781
+ const query = JSON.stringify([
782
+ {
783
+ hostPattern: "api.example.com",
784
+ injectionType: "query",
785
+ headerName: "",
786
+ },
787
+ ]);
788
+ expect(resolveTokenHeader(query, "https://api.example.com")).toBeNull();
789
+ });
790
+
791
+ test("picks the template whose wildcard host pattern matches the base URL", () => {
792
+ const templates = JSON.stringify([
793
+ {
794
+ hostPattern: "api.other.com",
795
+ injectionType: "header",
796
+ headerName: "Authorization",
797
+ valuePrefix: "Bearer ",
798
+ },
799
+ ...JSON.parse(shopify),
800
+ ]);
801
+ expect(
802
+ resolveTokenHeader(templates, "https://example-store.myshopify.com"),
803
+ ).toEqual({ name: "X-Shopify-Access-Token", valuePrefix: "" });
804
+ });
805
+
806
+ test("falls back to the first header template when the host cannot be matched", () => {
807
+ // A still-templated base URL is not a parseable URL.
808
+ expect(resolveTokenHeader(shopify, "https://{tenant_host}")).toEqual({
809
+ name: "X-Shopify-Access-Token",
810
+ valuePrefix: "",
811
+ });
812
+ });
813
+
814
+ test("preserves the Bot prefix for discord_channel", () => {
815
+ const discord = JSON.stringify([
816
+ {
817
+ hostPattern: "discord.com",
818
+ injectionType: "header",
819
+ headerName: "Authorization",
820
+ valuePrefix: "Bot ",
821
+ },
822
+ ]);
823
+ expect(resolveTokenHeader(discord, "https://discord.com/api")).toEqual({
824
+ name: "Authorization",
825
+ valuePrefix: "Bot ",
826
+ });
827
+ });
828
+ });
@@ -6,7 +6,7 @@ import {
6
6
  } from "../config/schemas/services.js";
7
7
  import { VellumPlatformClient } from "../platform/client.js";
8
8
  import { getLogger } from "../util/logger.js";
9
- import { BYOOAuthConnection } from "./byo-connection.js";
9
+ import { BYOOAuthConnection, type BYOTokenHeader } from "./byo-connection.js";
10
10
  import type { OAuthConnection } from "./connection.js";
11
11
  import { getConnectionAccessTokenResult } from "./credential-token-resolver.js";
12
12
  import { syncManualTokenConnection } from "./manual-token-connection.js";
@@ -215,15 +215,108 @@ export async function resolveOAuthConnectionWithMeta(
215
215
  );
216
216
  }
217
217
 
218
+ const effectiveBaseUrl = resolveEffectiveBaseUrl(
219
+ conn.provider,
220
+ baseUrl,
221
+ conn.metadata,
222
+ );
218
223
  const connection = new BYOOAuthConnection({
219
224
  id: conn.id,
220
225
  provider: conn.provider,
221
- baseUrl: resolveEffectiveBaseUrl(conn.provider, baseUrl, conn.metadata),
226
+ baseUrl: effectiveBaseUrl,
222
227
  accountInfo: conn.accountInfo,
228
+ tokenHeader: resolveTokenHeader(
229
+ providerRow?.injectionTemplates,
230
+ effectiveBaseUrl,
231
+ ),
223
232
  });
224
233
  return { connection, ambiguous, allAccounts };
225
234
  }
226
235
 
236
+ /**
237
+ * Pick the header a provider expects its access token in from the seed's
238
+ * header-type injection templates.
239
+ *
240
+ * Prefers the template whose `hostPattern` matches the base URL's host
241
+ * (`*.myshopify.com` style globs included), then falls back to the first
242
+ * header template. Returns `null` when the provider declares none, which
243
+ * leaves `BYOOAuthConnection` on its `Authorization: Bearer` default.
244
+ *
245
+ * Shopify is why this exists: its Admin API reads `X-Shopify-Access-Token`
246
+ * and ignores `Authorization`, so a Bearer header reaches the shop as an
247
+ * unauthenticated request and comes back 401.
248
+ */
249
+ export function resolveTokenHeader(
250
+ rawTemplates: string | null | undefined,
251
+ baseUrl: string,
252
+ ): BYOTokenHeader | null {
253
+ if (!rawTemplates) {
254
+ return null;
255
+ }
256
+ let parsed: unknown;
257
+ try {
258
+ parsed = JSON.parse(rawTemplates);
259
+ } catch {
260
+ return null;
261
+ }
262
+ if (!Array.isArray(parsed)) {
263
+ return null;
264
+ }
265
+
266
+ const headerTemplates = parsed.filter(
267
+ (
268
+ t,
269
+ ): t is {
270
+ hostPattern?: unknown;
271
+ headerName: string;
272
+ valuePrefix?: unknown;
273
+ } =>
274
+ typeof t === "object" &&
275
+ t !== null &&
276
+ (t as { injectionType?: unknown }).injectionType === "header" &&
277
+ typeof (t as { headerName?: unknown }).headerName === "string" &&
278
+ (t as { headerName: string }).headerName.trim() !== "",
279
+ );
280
+ if (headerTemplates.length === 0) {
281
+ return null;
282
+ }
283
+
284
+ let host = "";
285
+ try {
286
+ host = new URL(baseUrl).hostname.toLowerCase();
287
+ } catch {
288
+ // Templated or malformed base URLs (e.g. a still-unfilled
289
+ // `https://{tenant_host}`) cannot be matched by host; fall through to
290
+ // the first header template.
291
+ }
292
+ const matching =
293
+ host === ""
294
+ ? undefined
295
+ : headerTemplates.find(
296
+ (t) =>
297
+ typeof t.hostPattern === "string" &&
298
+ hostMatchesPattern(host, t.hostPattern),
299
+ );
300
+ const chosen = matching ?? headerTemplates[0];
301
+ return {
302
+ name: chosen.headerName.trim(),
303
+ valuePrefix:
304
+ typeof chosen.valuePrefix === "string" ? chosen.valuePrefix : "",
305
+ };
306
+ }
307
+
308
+ function hostMatchesPattern(host: string, pattern: string): boolean {
309
+ const p = pattern.trim().toLowerCase();
310
+ if (p === "") {
311
+ return false;
312
+ }
313
+ if (p.startsWith("*.")) {
314
+ const suffix = p.slice(1); // ".myshopify.com"
315
+ return host.endsWith(suffix) && host.length > suffix.length;
316
+ }
317
+ return host === p;
318
+ }
319
+
227
320
  /**
228
321
  * Resolve the effective API base URL for a connection, preferring per-tenant
229
322
  * values stored on the connection's `metadata` over the provider's static
@@ -1329,6 +1329,171 @@ export const PROVIDER_SEED_DATA: Record<
1329
1329
  identityUrl: "https://api.link.com/userinfo",
1330
1330
  identityResponsePaths: ["email", "phone"],
1331
1331
  },
1332
+ shopify: {
1333
+ provider: "shopify",
1334
+ // Shopify is per-tenant: every OAuth endpoint lives on the merchant's own
1335
+ // myshopify.com domain, so these carry a {tenant_host} placeholder the
1336
+ // platform fills in from the shop domain the user supplies at connect
1337
+ // time. There is no global Shopify authorization host to point at.
1338
+ authorizeUrl: "https://{tenant_host}/admin/oauth/authorize",
1339
+ tokenExchangeUrl: "https://{tenant_host}/admin/oauth/access_token",
1340
+ // Requesting `expiring=1` at token exchange yields a short-lived access
1341
+ // token plus a refresh token, which is refreshed against the same
1342
+ // per-shop endpoint.
1343
+ refreshUrl: "https://{tenant_host}/admin/oauth/access_token",
1344
+ pingUrl: "https://{tenant_host}/admin/api/2026-07/shop.json",
1345
+ baseUrl: "https://{tenant_host}",
1346
+ displayLabel: "Shopify",
1347
+ description: "Products, orders, customers, and inventory",
1348
+ dashboardUrl: "https://shopify.dev/dashboard",
1349
+ clientIdPlaceholder: null,
1350
+ logoUrl: "https://cdn.simpleicons.org/shopify",
1351
+ // Shopify parses `scope` as a comma-separated list. A space-separated
1352
+ // list is read as one malformed scope and the request is rejected.
1353
+ scopeSeparator: ",",
1354
+ // Admin API scopes only: Storefront, Customer Account and Shop APIs are
1355
+ // buyer-facing surfaces an assistant has no use for. Every scope here is
1356
+ // grantable without Shopify approval -- the approval-gated ones
1357
+ // (read_all_orders, customer payment methods, subscription contracts,
1358
+ // dispute evidence) are deliberately absent, because Shopify rejects the
1359
+ // whole authorization request if the app cannot grant a requested scope.
1360
+ // A write_* grant implies its read_* counterpart, so the response may
1361
+ // name only the write scope.
1362
+ defaultScopes: [
1363
+ "read_products",
1364
+ "write_products",
1365
+ "read_orders",
1366
+ "write_orders",
1367
+ "read_draft_orders",
1368
+ "write_draft_orders",
1369
+ "read_customers",
1370
+ "write_customers",
1371
+ "read_inventory",
1372
+ "read_locations",
1373
+ "read_fulfillments",
1374
+ "read_discounts",
1375
+ "write_discounts",
1376
+ "read_price_rules",
1377
+ ],
1378
+ availableScopes: [
1379
+ {
1380
+ scope: "read_products",
1381
+ description: "Read products, variants, and collections",
1382
+ },
1383
+ {
1384
+ scope: "write_products",
1385
+ description: "Create and update products, variants, and collections",
1386
+ },
1387
+ {
1388
+ scope: "read_orders",
1389
+ description: "Read orders, transactions, and abandoned checkouts",
1390
+ },
1391
+ {
1392
+ scope: "write_orders",
1393
+ description: "Create and update orders and fulfillments",
1394
+ },
1395
+ { scope: "read_draft_orders", description: "Read draft orders" },
1396
+ {
1397
+ scope: "write_draft_orders",
1398
+ description: "Create and update draft orders",
1399
+ },
1400
+ {
1401
+ scope: "read_customers",
1402
+ description: "Read customers, segments, and companies",
1403
+ },
1404
+ {
1405
+ scope: "write_customers",
1406
+ description: "Create and update customers and segments",
1407
+ },
1408
+ {
1409
+ scope: "read_inventory",
1410
+ description: "Read inventory levels and items",
1411
+ },
1412
+ {
1413
+ scope: "write_inventory",
1414
+ description: "Adjust inventory levels and items",
1415
+ },
1416
+ { scope: "read_locations", description: "Read store locations" },
1417
+ { scope: "read_fulfillments", description: "Read fulfillment services" },
1418
+ {
1419
+ scope: "write_fulfillments",
1420
+ description: "Create and update fulfillment services",
1421
+ },
1422
+ { scope: "read_discounts", description: "Read discounts" },
1423
+ { scope: "write_discounts", description: "Create and update discounts" },
1424
+ { scope: "read_price_rules", description: "Read price rules" },
1425
+ {
1426
+ scope: "write_price_rules",
1427
+ description: "Create and update price rules",
1428
+ },
1429
+ { scope: "read_files", description: "Read files uploaded to the store" },
1430
+ { scope: "write_files", description: "Upload and update files" },
1431
+ { scope: "read_gift_cards", description: "Read gift cards" },
1432
+ {
1433
+ scope: "write_gift_cards",
1434
+ description: "Create and update gift cards",
1435
+ },
1436
+ { scope: "read_returns", description: "Read returns" },
1437
+ { scope: "write_returns", description: "Create and update returns" },
1438
+ { scope: "read_markets", description: "Read markets" },
1439
+ { scope: "read_locales", description: "Read shop locales" },
1440
+ {
1441
+ scope: "read_shipping",
1442
+ description: "Read shipping and delivery carrier services",
1443
+ },
1444
+ { scope: "read_analytics", description: "Read analytics and reports" },
1445
+ {
1446
+ scope: "read_marketing_events",
1447
+ description: "Read marketing events and activities",
1448
+ },
1449
+ { scope: "read_order_edits", description: "Read order edits" },
1450
+ {
1451
+ scope: "write_order_edits",
1452
+ description: "Create and apply order edits",
1453
+ },
1454
+ {
1455
+ scope: "read_metaobjects",
1456
+ description: "Read metaobjects and their definitions",
1457
+ },
1458
+ {
1459
+ scope: "write_metaobjects",
1460
+ description: "Create and update metaobjects",
1461
+ },
1462
+ { scope: "read_translations", description: "Read translated content" },
1463
+ {
1464
+ scope: "read_shopify_payments_payouts",
1465
+ description: "Read Shopify Payments payouts and balance",
1466
+ },
1467
+ {
1468
+ scope: "read_shopify_payments_disputes",
1469
+ description: "Read Shopify Payments disputes",
1470
+ },
1471
+ ],
1472
+ loopbackPort: 17341,
1473
+ managedServiceConfigKey: "shopify-oauth",
1474
+ injectionTemplates: [
1475
+ {
1476
+ hostPattern: "*.myshopify.com",
1477
+ injectionType: "header",
1478
+ headerName: "X-Shopify-Access-Token",
1479
+ valuePrefix: "",
1480
+ },
1481
+ ],
1482
+ appType: "App",
1483
+ setupNotes: [
1484
+ "Shopify OAuth is per-shop: the authorize, token and API endpoints all live on the merchant's own myshopify.com domain, so connecting requires the shop domain (for example your-store.myshopify.com) alongside the usual credentials.",
1485
+ "The Admin API authenticates with the X-Shopify-Access-Token header rather than an Authorization Bearer header.",
1486
+ ],
1487
+ // The Admin API's shop endpoint nests its payload under "shop"; the
1488
+ // myshopify domain is the stable, human-recognisable handle.
1489
+ identityUrl: "https://{tenant_host}/admin/api/2026-07/shop.json",
1490
+ identityResponsePaths: ["shop.myshopify_domain", "shop.name"],
1491
+ // Gated like monday/figma/stripe-link: the platform side and the
1492
+ // shop-domain input in the clients land separately, and until both are
1493
+ // in place a visible Shopify tile would offer a connect flow that
1494
+ // cannot complete.
1495
+ featureFlag: "shopify-oauth",
1496
+ },
1332
1497
  };
1333
1498
 
1334
1499
  export const SEEDED_PROVIDER_KEYS = new Set(Object.keys(PROVIDER_SEED_DATA));
@@ -2,6 +2,8 @@ import { X509Certificate } from "node:crypto";
2
2
  import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
 
5
+ import { writeCombinedCABundle } from "../util/ca-bundle.js";
6
+
5
7
  const CA_CERT_FILENAME = "ca.pem";
6
8
  const CA_KEY_FILENAME = "ca-key.pem";
7
9
  const COMBINED_CA_FILENAME = "combined-ca-bundle.pem";
@@ -263,11 +265,7 @@ export async function ensureCombinedCABundle(
263
265
  }
264
266
 
265
267
  try {
266
- const [systemCAs, proxyCACert] = await Promise.all([
267
- readFile(systemBundlePath, "utf-8"),
268
- readFile(caCertPath, "utf-8"),
269
- ]);
270
- await writeFile(combinedPath, systemCAs + "\n" + proxyCACert);
268
+ await writeCombinedCABundle(systemBundlePath, caCertPath, combinedPath);
271
269
  return combinedPath;
272
270
  } catch {
273
271
  return null;
@@ -15,13 +15,16 @@ mock.module("../config/assistant-feature-flags.js", () => ({
15
15
  }));
16
16
 
17
17
  // `buildPolicyContext` (used by the integration tests below) precomputes the
18
- // proc-to-skills gate via `isV3TierActive`. Drive it through this slot so a
19
- // test can put the production threading path in the active / inactive state.
18
+ // retrospective skill-improvement gate. Keep the v3 tier active while the
19
+ // dedicated gate changes so the production threading test covers the new
20
+ // opt-out rather than the old v3 condition.
20
21
  let mockV3TierActive = true;
22
+ let mockSkillImprovementActive = true;
21
23
  mock.module("../config/memory-v3-gate.js", () => ({
22
24
  isMemoryEnabled: (config?: { memory?: { enabled?: boolean } }) =>
23
25
  config?.memory?.enabled !== false,
24
26
  isV3TierActive: () => mockV3TierActive,
27
+ isSkillImprovementActive: () => mockSkillImprovementActive,
25
28
  isMemoryV3Live: () => mockV3TierActive,
26
29
  usesConceptPageMemory: (memory?: {
27
30
  enabled?: boolean;
@@ -219,6 +222,7 @@ describe("Permission Checker (gateway IPC)", () => {
219
222
  mockCachedThreshold = "low";
220
223
  mockRefreshedThreshold = null;
221
224
  mockV3TierActive = true;
225
+ mockSkillImprovementActive = true;
222
226
  thresholdCallLog.length = 0;
223
227
  mockSkillCatalog = [];
224
228
  mockResolvedSkill = null;
@@ -1173,10 +1177,11 @@ describe("Permission Checker (gateway IPC)", () => {
1173
1177
  });
1174
1178
 
1175
1179
  test("grant does NOT fire when proc-to-skills is inactive, even for the retrospective turn", async () => {
1176
- // Same retrospective ToolContext, but the feature is inactive (flag off
1177
- // or v3 not live). buildPolicyContext stamps `procToSkillsActive: false`,
1178
- // so the grant is dead and the high-risk scaffold prompts.
1179
- mockV3TierActive = false;
1180
+ // The retrospective keeps its live v3 tier, but this independent flag is
1181
+ // off. buildPolicyContext stamps `procToSkillsActive: false`, so the
1182
+ // grant is dead and the high-risk scaffold prompts.
1183
+ mockV3TierActive = true;
1184
+ mockSkillImprovementActive = false;
1180
1185
  mockIpcClassifyRiskResult = {
1181
1186
  risk: "high",
1182
1187
  reason: "Skill scaffold",
@@ -26,6 +26,7 @@
26
26
  */
27
27
  import type { AgentEvent } from "../agent/loop.js";
28
28
  import { getConfig } from "../config/loader.js";
29
+ import { resolvePlatformAssistantIdOrNull } from "../config/platform-identity.js";
29
30
  import type { CompactionLogsClickHouseConfig } from "../config/schemas/compaction-logs.js";
30
31
  import { credentialKey } from "../security/credential-key.js";
31
32
  import { getSecureKeyAsync } from "../security/secure-keys.js";
@@ -136,7 +137,7 @@ export interface ClickHouseCompactionLogStoreDeps {
136
137
  resolveUrl?: () => Promise<string | null>;
137
138
  /** Override the credential read for `clickhouse:password`. */
138
139
  resolvePassword?: () => Promise<string | null>;
139
- /** Override the credential read for `vellum:platform_assistant_id`. */
140
+ /** Override the in-memory platform assistant id. */
140
141
  resolveAssistantId?: () => Promise<string | null>;
141
142
  /** Override fetch for testing. */
142
143
  fetchImpl?: CompactionLogFetch;
@@ -163,8 +164,7 @@ export class ClickHouseCompactionLogStore {
163
164
  deps.resolvePassword ??
164
165
  (() => readCredentialOrNull("clickhouse", "password"));
165
166
  this.resolveAssistantId =
166
- deps.resolveAssistantId ??
167
- (() => readCredentialOrNull("vellum", "platform_assistant_id"));
167
+ deps.resolveAssistantId ?? resolvePlatformAssistantIdOrNull;
168
168
  this.fetchImpl = deps.fetchImpl ?? globalThis.fetch.bind(globalThis);
169
169
  }
170
170