@vellumai/assistant 0.4.56 → 0.5.0

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 (457) hide show
  1. package/ARCHITECTURE.md +10 -10
  2. package/Dockerfile +3 -0
  3. package/README.md +11 -11
  4. package/docs/architecture/integrations.md +2 -2
  5. package/docs/architecture/memory.md +3 -4
  6. package/docs/credential-execution-service.md +13 -20
  7. package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
  8. package/package.json +1 -1
  9. package/src/__tests__/actor-token-service.test.ts +7 -7
  10. package/src/__tests__/anthropic-provider.test.ts +172 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
  12. package/src/__tests__/approval-cascade.test.ts +2 -2
  13. package/src/__tests__/approval-routes-http.test.ts +3 -4
  14. package/src/__tests__/asset-materialize-tool.test.ts +5 -5
  15. package/src/__tests__/asset-search-tool.test.ts +1 -1
  16. package/src/__tests__/assistant-attachments.test.ts +5 -5
  17. package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
  19. package/src/__tests__/attachments-store.test.ts +2 -2
  20. package/src/__tests__/avatar-e2e.test.ts +5 -3
  21. package/src/__tests__/browser-skill-endstate.test.ts +0 -1
  22. package/src/__tests__/call-routes-http.test.ts +2 -2
  23. package/src/__tests__/callback-handoff-copy.test.ts +1 -1
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
  25. package/src/__tests__/channel-readiness-routes.test.ts +0 -1
  26. package/src/__tests__/channel-readiness-service.test.ts +0 -1
  27. package/src/__tests__/checker.test.ts +31 -32
  28. package/src/__tests__/chrome-cdp.test.ts +47 -18
  29. package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
  30. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  31. package/src/__tests__/config-schema.test.ts +9 -18
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
  34. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
  35. package/src/__tests__/conversation-agent-loop.test.ts +11 -4
  36. package/src/__tests__/conversation-attachments.test.ts +1 -1
  37. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
  38. package/src/__tests__/conversation-error.test.ts +33 -0
  39. package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
  40. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  41. package/src/__tests__/conversation-pairing.test.ts +1 -1
  42. package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
  43. package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
  44. package/src/__tests__/conversation-queue.test.ts +23 -14
  45. package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +204 -185
  47. package/src/__tests__/conversation-seed-composer.test.ts +1 -1
  48. package/src/__tests__/conversation-slash-queue.test.ts +4 -4
  49. package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
  50. package/src/__tests__/conversation-starter-routes.test.ts +291 -0
  51. package/src/__tests__/conversation-wipe.test.ts +438 -0
  52. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
  53. package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
  54. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
  55. package/src/__tests__/credential-security-e2e.test.ts +20 -0
  56. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  57. package/src/__tests__/credential-vault-unit.test.ts +227 -0
  58. package/src/__tests__/credentials-cli.test.ts +3 -0
  59. package/src/__tests__/date-context.test.ts +59 -377
  60. package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
  61. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
  62. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
  63. package/src/__tests__/encrypted-store.test.ts +249 -15
  64. package/src/__tests__/ephemeral-permissions.test.ts +4 -5
  65. package/src/__tests__/event-bus.test.ts +3 -3
  66. package/src/__tests__/file-read-tool.test.ts +40 -0
  67. package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
  68. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  69. package/src/__tests__/gemini-image-service.test.ts +4 -4
  70. package/src/__tests__/gemini-provider.test.ts +6 -9
  71. package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
  72. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  73. package/src/__tests__/host-file-read-tool.test.ts +87 -0
  74. package/src/__tests__/host-shell-tool.test.ts +6 -6
  75. package/src/__tests__/http-user-message-parity.test.ts +2 -2
  76. package/src/__tests__/identity-intro-cache.test.ts +209 -0
  77. package/src/__tests__/intent-routing.test.ts +51 -99
  78. package/src/__tests__/invite-routes-http.test.ts +5 -0
  79. package/src/__tests__/list-messages-attachments.test.ts +1 -1
  80. package/src/__tests__/managed-proxy-context.test.ts +2 -5
  81. package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
  82. package/src/__tests__/media-generate-image.test.ts +32 -15
  83. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
  84. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
  85. package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
  86. package/src/__tests__/memory-recall-quality.test.ts +4 -3
  87. package/src/__tests__/memory-regressions.test.ts +86 -90
  88. package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
  89. package/src/__tests__/migration-export-http.test.ts +26 -27
  90. package/src/__tests__/migration-import-commit-http.test.ts +165 -37
  91. package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
  92. package/src/__tests__/migration-validate-http.test.ts +16 -16
  93. package/src/__tests__/model-intents.test.ts +2 -2
  94. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
  95. package/src/__tests__/non-member-access-request.test.ts +3 -3
  96. package/src/__tests__/notification-broadcaster.test.ts +1 -1
  97. package/src/__tests__/notification-decision-fallback.test.ts +2 -2
  98. package/src/__tests__/notification-decision-identity.test.ts +8 -9
  99. package/src/__tests__/notification-decision-strategy.test.ts +1 -1
  100. package/src/__tests__/notification-deep-link.test.ts +1 -1
  101. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  102. package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
  103. package/src/__tests__/oauth-store.test.ts +1 -3
  104. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
  105. package/src/__tests__/onboarding-template-contract.test.ts +23 -59
  106. package/src/__tests__/provider-error-scenarios.test.ts +154 -0
  107. package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
  108. package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
  109. package/src/__tests__/provider-registry-ollama.test.ts +5 -2
  110. package/src/__tests__/qdrant-manager.test.ts +7 -7
  111. package/src/__tests__/ratelimit.test.ts +0 -74
  112. package/src/__tests__/recording-handler.test.ts +0 -1
  113. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  114. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  115. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  116. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  117. package/src/__tests__/scheduler-recurrence.test.ts +46 -2
  118. package/src/__tests__/schema-transforms.test.ts +114 -54
  119. package/src/__tests__/secret-onetime-send.test.ts +20 -0
  120. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
  121. package/src/__tests__/secret-scanner-executor.test.ts +1 -2
  122. package/src/__tests__/send-endpoint-busy.test.ts +63 -4
  123. package/src/__tests__/send-notification-tool.test.ts +2 -2
  124. package/src/__tests__/shell-credential-ref.test.ts +0 -1
  125. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
  126. package/src/__tests__/skill-memory.test.ts +549 -0
  127. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
  128. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
  129. package/src/__tests__/slack-channel-config.test.ts +109 -94
  130. package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
  131. package/src/__tests__/swarm-recursion.test.ts +2 -2
  132. package/src/__tests__/swarm-tool.test.ts +2 -2
  133. package/src/__tests__/system-prompt.test.ts +19 -66
  134. package/src/__tests__/telegram-config.test.ts +121 -0
  135. package/src/__tests__/terminal-tools.test.ts +1 -1
  136. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  138. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
  139. package/src/__tests__/tool-executor.test.ts +1 -1
  140. package/src/__tests__/trace-emitter.test.ts +8 -1
  141. package/src/__tests__/trust-store.test.ts +7 -8
  142. package/src/__tests__/twilio-routes.test.ts +1 -18
  143. package/src/__tests__/user-reference.test.ts +82 -2
  144. package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
  145. package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
  146. package/src/approvals/guardian-request-resolvers.ts +3 -3
  147. package/src/avatar/ascii-renderer.ts +2 -2
  148. package/src/avatar/png-renderer.ts +2 -2
  149. package/src/avatar/resvg-lazy.ts +21 -0
  150. package/src/calls/guardian-dispatch.ts +1 -1
  151. package/src/calls/relay-access-wait.ts +2 -2
  152. package/src/calls/twilio-rest.ts +0 -248
  153. package/src/cli/AGENTS.md +5 -8
  154. package/src/cli/__tests__/notifications.test.ts +5 -5
  155. package/src/cli/commands/avatar.ts +64 -2
  156. package/src/cli/commands/conversations.ts +131 -1
  157. package/src/cli/commands/credentials.ts +2 -0
  158. package/src/cli/commands/notifications.ts +3 -3
  159. package/src/cli.ts +10 -0
  160. package/src/config/bundled-skills/acp/SKILL.md +5 -5
  161. package/src/config/bundled-skills/acp/TOOLS.json +6 -6
  162. package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
  163. package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
  164. package/src/config/bundled-skills/browser/SKILL.md +15 -15
  165. package/src/config/bundled-skills/browser/TOOLS.json +14 -14
  166. package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
  167. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
  168. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  169. package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
  170. package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
  171. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
  172. package/src/config/bundled-skills/contacts/SKILL.md +3 -3
  173. package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
  174. package/src/config/bundled-skills/document/SKILL.md +4 -4
  175. package/src/config/bundled-skills/document/TOOLS.json +2 -2
  176. package/src/config/bundled-skills/followups/TOOLS.json +3 -3
  177. package/src/config/bundled-skills/gmail/SKILL.md +32 -32
  178. package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
  179. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
  180. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
  181. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
  182. package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
  183. package/src/config/bundled-skills/google-calendar/types.ts +1 -1
  184. package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
  185. package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
  186. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
  187. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
  188. package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
  189. package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
  190. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
  191. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
  192. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
  193. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
  194. package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
  195. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
  196. package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
  197. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  198. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
  199. package/src/config/bundled-skills/messaging/SKILL.md +29 -25
  200. package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
  201. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  202. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  203. package/src/config/bundled-skills/notifications/SKILL.md +3 -3
  204. package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
  205. package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
  206. package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
  207. package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
  208. package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
  209. package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
  210. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
  211. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
  212. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
  213. package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
  214. package/src/config/bundled-skills/schedule/SKILL.md +26 -26
  215. package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
  216. package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
  217. package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
  218. package/src/config/bundled-skills/sequences/SKILL.md +2 -2
  219. package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
  220. package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
  221. package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
  222. package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
  223. package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
  224. package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
  225. package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
  226. package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
  227. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  228. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
  229. package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
  230. package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
  231. package/src/config/bundled-skills/slack/SKILL.md +2 -2
  232. package/src/config/bundled-skills/slack/TOOLS.json +8 -8
  233. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
  234. package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
  235. package/src/config/bundled-skills/tasks/SKILL.md +1 -1
  236. package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
  237. package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
  238. package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
  240. package/src/config/bundled-skills/watcher/SKILL.md +4 -4
  241. package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
  242. package/src/config/feature-flag-registry.json +33 -17
  243. package/src/config/schemas/sandbox.ts +1 -1
  244. package/src/config/schemas/services.ts +13 -3
  245. package/src/config/schemas/timeouts.ts +0 -10
  246. package/src/contacts/contact-store.ts +63 -0
  247. package/src/contacts/contacts-write.ts +1 -1
  248. package/src/daemon/assistant-attachments.ts +2 -2
  249. package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
  250. package/src/daemon/conversation-agent-loop.ts +7 -30
  251. package/src/daemon/conversation-error.ts +24 -0
  252. package/src/daemon/conversation-memory.ts +8 -7
  253. package/src/daemon/conversation-runtime-assembly.ts +141 -275
  254. package/src/daemon/conversation-slash.ts +7 -26
  255. package/src/daemon/conversation-surfaces.ts +14 -0
  256. package/src/daemon/conversation-tool-setup.ts +9 -8
  257. package/src/daemon/conversation.ts +2 -0
  258. package/src/daemon/daemon-control.ts +1 -1
  259. package/src/daemon/date-context.ts +10 -83
  260. package/src/daemon/handlers/config-channels.ts +12 -2
  261. package/src/daemon/handlers/config-slack-channel.ts +7 -1
  262. package/src/daemon/handlers/config-telegram.ts +6 -1
  263. package/src/daemon/handlers/conversations.ts +2 -2
  264. package/src/daemon/handlers/skills.ts +4 -0
  265. package/src/daemon/lifecycle.ts +28 -4
  266. package/src/daemon/providers-setup.ts +1 -1
  267. package/src/daemon/server.ts +1 -5
  268. package/src/daemon/shutdown-handlers.ts +9 -3
  269. package/src/daemon/tool-side-effects.ts +40 -0
  270. package/src/daemon/trace-emitter.ts +26 -2
  271. package/src/events/domain-events.ts +1 -1
  272. package/src/events/tool-permission-telemetry-listener.ts +46 -0
  273. package/src/inbound/platform-callback-registration.ts +0 -18
  274. package/src/media/app-icon-generator.ts +15 -8
  275. package/src/media/avatar-router.ts +15 -8
  276. package/src/media/gemini-image-service.ts +125 -21
  277. package/src/memory/attachments-store.ts +3 -3
  278. package/src/memory/channel-verification-sessions.ts +6 -6
  279. package/src/memory/conversation-crud.ts +196 -1
  280. package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
  281. package/src/memory/conversation-title-service.ts +2 -3
  282. package/src/memory/db-init.ts +25 -1
  283. package/src/memory/invite-store.ts +4 -4
  284. package/src/memory/items-extractor.ts +4 -4
  285. package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
  286. package/src/memory/jobs-store.ts +3 -2
  287. package/src/memory/jobs-worker.ts +7 -5
  288. package/src/memory/lifecycle-events-store.ts +63 -0
  289. package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
  290. package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
  291. package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
  292. package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
  293. package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
  294. package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
  295. package/src/memory/migrations/index.ts +6 -0
  296. package/src/memory/migrations/registry.ts +13 -0
  297. package/src/memory/retriever.test.ts +223 -96
  298. package/src/memory/retriever.ts +115 -138
  299. package/src/memory/schema/calls.ts +1 -1
  300. package/src/memory/schema/contacts.ts +1 -1
  301. package/src/memory/schema/infrastructure.ts +29 -0
  302. package/src/memory/schema/memory-core.ts +7 -17
  303. package/src/memory/schema/notifications.ts +1 -1
  304. package/src/memory/search/formatting.ts +23 -6
  305. package/src/memory/search/lexical.ts +2 -0
  306. package/src/memory/search/semantic.ts +2 -0
  307. package/src/memory/search/staleness.ts +5 -1
  308. package/src/memory/search/types.ts +4 -0
  309. package/src/memory/task-memory-cleanup.ts +96 -6
  310. package/src/memory/trace-event-store.ts +148 -0
  311. package/src/notifications/README.md +1 -1
  312. package/src/notifications/decision-engine.ts +45 -4
  313. package/src/notifications/emit-signal.ts +5 -4
  314. package/src/notifications/events-store.ts +4 -4
  315. package/src/notifications/signal.ts +1 -1
  316. package/src/oauth/manual-token-connection.ts +49 -25
  317. package/src/permissions/checker.ts +6 -5
  318. package/src/permissions/defaults.ts +4 -4
  319. package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
  320. package/src/prompts/cache-boundary.ts +8 -0
  321. package/src/prompts/system-prompt.ts +105 -634
  322. package/src/prompts/templates/BOOTSTRAP.md +172 -33
  323. package/src/prompts/templates/IDENTITY.md +8 -24
  324. package/src/prompts/templates/SOUL.md +20 -41
  325. package/src/prompts/templates/USER.md +3 -19
  326. package/src/prompts/user-reference.ts +14 -16
  327. package/src/providers/anthropic/client.ts +51 -19
  328. package/src/providers/gemini/client.ts +6 -9
  329. package/src/providers/managed-proxy/constants.ts +1 -7
  330. package/src/providers/managed-proxy/context.ts +0 -1
  331. package/src/providers/model-intents.ts +5 -5
  332. package/src/providers/openai/client.ts +10 -1
  333. package/src/providers/openrouter/client.ts +1 -0
  334. package/src/providers/ratelimit.ts +0 -35
  335. package/src/providers/registry.ts +3 -5
  336. package/src/providers/retry.ts +18 -1
  337. package/src/runtime/access-request-helper.ts +16 -2
  338. package/src/runtime/auth/route-policy.ts +7 -0
  339. package/src/runtime/channel-verification-service.ts +1 -1
  340. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  341. package/src/runtime/guardian-vellum-migration.ts +61 -1
  342. package/src/runtime/http-server.ts +8 -4
  343. package/src/runtime/migrations/vbundle-builder.ts +212 -32
  344. package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
  345. package/src/runtime/migrations/vbundle-importer.ts +66 -1
  346. package/src/runtime/migrations/vbundle-validator.ts +17 -3
  347. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
  348. package/src/runtime/routes/attachment-routes.ts +2 -2
  349. package/src/runtime/routes/btw-routes.ts +93 -0
  350. package/src/runtime/routes/channel-verification-routes.ts +19 -2
  351. package/src/runtime/routes/conversation-management-routes.ts +55 -1
  352. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  353. package/src/runtime/routes/conversation-routes.ts +49 -5
  354. package/src/runtime/routes/conversation-starter-routes.ts +207 -0
  355. package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
  356. package/src/runtime/routes/identity-intro-cache.ts +105 -0
  357. package/src/runtime/routes/identity-routes.ts +51 -0
  358. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
  359. package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
  360. package/src/runtime/routes/migration-routes.ts +25 -13
  361. package/src/runtime/routes/secret-routes.ts +18 -0
  362. package/src/runtime/routes/settings-routes.ts +9 -9
  363. package/src/runtime/routes/telemetry-routes.ts +53 -0
  364. package/src/runtime/routes/trace-event-routes.ts +62 -0
  365. package/src/runtime/tool-grant-request-helper.ts +1 -1
  366. package/src/runtime/verification-outbound-actions.ts +47 -31
  367. package/src/security/encrypted-store.ts +262 -78
  368. package/src/skills/catalog-install.ts +10 -0
  369. package/src/skills/managed-store.ts +2 -0
  370. package/src/skills/skill-memory.ts +222 -0
  371. package/src/subagent/manager.ts +1 -4
  372. package/src/telemetry/types.ts +10 -1
  373. package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
  374. package/src/telemetry/usage-telemetry-reporter.ts +53 -4
  375. package/src/tools/AGENTS.md +11 -11
  376. package/src/tools/acp/spawn.ts +1 -1
  377. package/src/tools/apps/executors.ts +8 -8
  378. package/src/tools/apps/registry.ts +1 -1
  379. package/src/tools/assets/materialize.ts +6 -6
  380. package/src/tools/assets/search.ts +10 -10
  381. package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
  382. package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
  383. package/src/tools/browser/auth-detector.ts +6 -6
  384. package/src/tools/browser/browser-execution.ts +13 -13
  385. package/src/tools/browser/browser-manager.ts +3 -3
  386. package/src/tools/browser/chrome-cdp.ts +5 -5
  387. package/src/tools/browser/jit-auth.ts +2 -2
  388. package/src/tools/browser/network-recorder.test.ts +2 -2
  389. package/src/tools/browser/network-recorder.ts +3 -3
  390. package/src/tools/browser/runtime-check.ts +3 -3
  391. package/src/tools/claude-code/claude-code.ts +2 -2
  392. package/src/tools/computer-use/definitions.ts +18 -18
  393. package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
  394. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
  395. package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
  396. package/src/tools/credentials/broker-types.ts +5 -5
  397. package/src/tools/credentials/broker.ts +15 -15
  398. package/src/tools/credentials/metadata-store.ts +2 -2
  399. package/src/tools/credentials/resolve.ts +1 -1
  400. package/src/tools/credentials/selection.ts +1 -1
  401. package/src/tools/credentials/tool-policy.ts +1 -1
  402. package/src/tools/credentials/vault.ts +115 -25
  403. package/src/tools/execution-target.ts +2 -2
  404. package/src/tools/executor.ts +7 -7
  405. package/src/tools/filesystem/edit.ts +2 -2
  406. package/src/tools/filesystem/read.ts +15 -4
  407. package/src/tools/filesystem/write.ts +1 -1
  408. package/src/tools/host-filesystem/edit.ts +2 -1
  409. package/src/tools/host-filesystem/read.ts +18 -1
  410. package/src/tools/host-filesystem/write.ts +1 -1
  411. package/src/tools/host-terminal/host-shell.ts +9 -8
  412. package/src/tools/mcp/mcp-tool-factory.ts +7 -6
  413. package/src/tools/memory/definitions.ts +6 -5
  414. package/src/tools/memory/handlers.test.ts +1 -1
  415. package/src/tools/network/__tests__/web-search.test.ts +3 -3
  416. package/src/tools/network/domain-normalize.ts +2 -2
  417. package/src/tools/network/script-proxy/session-manager.ts +10 -10
  418. package/src/tools/network/web-fetch.ts +1 -1
  419. package/src/tools/network/web-search.ts +3 -3
  420. package/src/tools/permission-checker.ts +8 -8
  421. package/src/tools/registry.ts +7 -7
  422. package/src/tools/schedule/list.ts +2 -2
  423. package/src/tools/schema-transforms.ts +31 -21
  424. package/src/tools/secret-detection-handler.ts +1 -1
  425. package/src/tools/sensitive-output-placeholders.ts +1 -1
  426. package/src/tools/shared/filesystem/edit-engine.ts +1 -1
  427. package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
  428. package/src/tools/shared/filesystem/image-read.ts +25 -5
  429. package/src/tools/shared/filesystem/path-policy.ts +2 -2
  430. package/src/tools/shared/shell-output.ts +1 -1
  431. package/src/tools/side-effects.ts +1 -1
  432. package/src/tools/skills/execute.ts +1 -1
  433. package/src/tools/skills/load.ts +3 -3
  434. package/src/tools/skills/sandbox-runner.ts +3 -3
  435. package/src/tools/subagent/read.ts +1 -1
  436. package/src/tools/subagent/spawn.ts +2 -2
  437. package/src/tools/swarm/delegate.ts +3 -3
  438. package/src/tools/system/request-permission.ts +5 -4
  439. package/src/tools/terminal/backends/native.ts +4 -4
  440. package/src/tools/terminal/parser.ts +6 -6
  441. package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
  442. package/src/tools/terminal/shell.ts +16 -16
  443. package/src/tools/tool-approval-handler.ts +21 -12
  444. package/src/tools/tool-manifest.ts +4 -4
  445. package/src/tools/types.ts +3 -3
  446. package/src/tools/ui-surface/definitions.ts +9 -37
  447. package/src/tools/watcher/list.ts +1 -1
  448. package/src/util/logger.ts +7 -2
  449. package/src/util/pricing.ts +4 -0
  450. package/src/util/retry.ts +29 -1
  451. package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
  452. package/src/workspace/migrations/registry.ts +2 -0
  453. package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
  454. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
  455. package/src/cli/reference.ts +0 -38
  456. package/src/memory/job-handlers/capability-cards.ts +0 -420
  457. package/src/runtime/routes/thread-starter-routes.ts +0 -294
@@ -89,7 +89,7 @@ function makeSignal(
89
89
  signalId: "sig-deeplink-001",
90
90
  createdAt: Date.now(),
91
91
  sourceChannel: "scheduler",
92
- sourceSessionId: "sess-001",
92
+ sourceContextId: "sess-001",
93
93
  sourceEventName: "test.event",
94
94
  contextPayload: {},
95
95
  attentionHints: {
@@ -239,7 +239,6 @@ describe("ASK_GUARDIAN canonical notification path", () => {
239
239
 
240
240
  const signalParams = emitCalls[0] as Record<string, unknown>;
241
241
  expect(typeof signalParams.onConversationCreated).toBe("function");
242
- expect(signalParams.skipVellumThread).toBeUndefined();
243
242
  });
244
243
 
245
244
  test("creates guardian action deliveries from notification pipeline delivery results", async () => {
@@ -72,7 +72,7 @@ function makeSignal(
72
72
  signalId: `sig-${crypto.randomUUID()}`,
73
73
  createdAt: Date.now(),
74
74
  sourceChannel: "scheduler",
75
- sourceSessionId: "schedule-123",
75
+ sourceContextId: "schedule-123",
76
76
  sourceEventName: "schedule.complete",
77
77
  contextPayload: { scheduleId: "schedule-123", name: "Drink water" },
78
78
  attentionHints: {
@@ -118,7 +118,7 @@ describe("recurring schedule notification dedup", () => {
118
118
  id: firstSignal.signalId,
119
119
  sourceEventName: "schedule.complete",
120
120
  sourceChannel: "scheduler",
121
- sourceSessionId: "schedule-123",
121
+ sourceContextId: "schedule-123",
122
122
  attentionHints: firstSignal.attentionHints,
123
123
  payload: firstSignal.contextPayload,
124
124
  // No dedupeKey — this is the bug scenario
@@ -132,7 +132,7 @@ describe("recurring schedule notification dedup", () => {
132
132
  id: secondSignal.signalId,
133
133
  sourceEventName: "schedule.complete",
134
134
  sourceChannel: "scheduler",
135
- sourceSessionId: "schedule-123",
135
+ sourceContextId: "schedule-123",
136
136
  attentionHints: secondSignal.attentionHints,
137
137
  payload: secondSignal.contextPayload,
138
138
  });
@@ -160,7 +160,7 @@ describe("recurring schedule notification dedup", () => {
160
160
  id: firstSignal.signalId,
161
161
  sourceEventName: "schedule.complete",
162
162
  sourceChannel: "scheduler",
163
- sourceSessionId: "schedule-123",
163
+ sourceContextId: "schedule-123",
164
164
  attentionHints: firstSignal.attentionHints,
165
165
  payload: firstSignal.contextPayload,
166
166
  dedupeKey: `schedule:complete:schedule-123:${Date.now() - 60_000}`,
@@ -173,7 +173,7 @@ describe("recurring schedule notification dedup", () => {
173
173
  id: secondSignal.signalId,
174
174
  sourceEventName: "schedule.complete",
175
175
  sourceChannel: "scheduler",
176
- sourceSessionId: "schedule-123",
176
+ sourceContextId: "schedule-123",
177
177
  attentionHints: secondSignal.attentionHints,
178
178
  payload: secondSignal.contextPayload,
179
179
  dedupeKey: `schedule:complete:schedule-123:${Date.now()}`,
@@ -204,7 +204,7 @@ describe("recurring schedule notification dedup", () => {
204
204
  id: firstSignal.signalId,
205
205
  sourceEventName: "schedule.notify",
206
206
  sourceChannel: "scheduler",
207
- sourceSessionId: "schedule-123",
207
+ sourceContextId: "schedule-123",
208
208
  attentionHints: firstSignal.attentionHints,
209
209
  payload: firstSignal.contextPayload,
210
210
  dedupeKey: `schedule:notify:schedule-123:${Date.now() - 60_000}`,
@@ -219,7 +219,7 @@ describe("recurring schedule notification dedup", () => {
219
219
  id: secondSignal.signalId,
220
220
  sourceEventName: "schedule.notify",
221
221
  sourceChannel: "scheduler",
222
- sourceSessionId: "schedule-123",
222
+ sourceContextId: "schedule-123",
223
223
  attentionHints: secondSignal.attentionHints,
224
224
  payload: secondSignal.contextPayload,
225
225
  dedupeKey: `schedule:notify:schedule-123:${Date.now()}`,
@@ -83,9 +83,7 @@ async function createTestApp(providerKey = "github", clientId = "client-1") {
83
83
  }
84
84
 
85
85
  beforeEach(() => {
86
- resetDb();
87
- initializeDb();
88
- // Explicitly clear all OAuth tables to prevent cross-test state pollution.
86
+ // Clear OAuth tables between tests instead of full DB reset + migration.
89
87
  // Delete in FK-dependency order: connections → apps → providers.
90
88
  resetTestTables("oauth_connections", "oauth_apps", "oauth_providers");
91
89
  mockDeleteSecureKeyAsync.mockClear();
@@ -484,17 +484,22 @@ describe("OAuth2 gateway transport", () => {
484
484
  };
485
485
 
486
486
  let capturedAuthUrl = "";
487
+ let urlReady!: () => void;
488
+ const urlReadyPromise = new Promise<void>((r) => {
489
+ urlReady = r;
490
+ });
487
491
  const flowPromise = startOAuth2Flow(
488
492
  BASE_OAUTH_CONFIG,
489
493
  {
490
494
  openUrl: (url) => {
491
495
  capturedAuthUrl = url;
496
+ urlReady();
492
497
  },
493
498
  },
494
499
  { callbackTransport: "loopback" },
495
500
  );
496
501
 
497
- await new Promise((r) => setTimeout(r, 50));
502
+ await urlReadyPromise;
498
503
 
499
504
  const authUrl = new URL(capturedAuthUrl);
500
505
  const redirectUri = authUrl.searchParams.get("redirect_uri")!;
@@ -9,14 +9,19 @@ const user = readFileSync(join(templatesDir, "USER.md"), "utf-8");
9
9
 
10
10
  describe("onboarding template contracts", () => {
11
11
  describe("BOOTSTRAP.md", () => {
12
- test("contains identity question prompts", () => {
12
+ test("preserves comment line format instruction", () => {
13
+ expect(bootstrap).toMatch(/^_ Lines starting with _/);
14
+ });
15
+
16
+ test("contains identity discovery prompts", () => {
13
17
  const lower = bootstrap.toLowerCase();
14
- expect(lower).toContain("who am i");
18
+ expect(lower).toContain("your name");
19
+ expect(lower).toContain("personality");
20
+ expect(lower).toContain("avatar");
15
21
  });
16
22
 
17
23
  test("infers personality organically instead of asking directly", () => {
18
24
  const lower = bootstrap.toLowerCase();
19
- // Personality step must instruct organic discovery via conversation
20
25
  expect(lower).toContain("personality");
21
26
  expect(lower).toContain("emerge");
22
27
  expect(lower).toContain("vibe");
@@ -28,28 +33,17 @@ describe("onboarding template contracts", () => {
28
33
  expect(lower).toContain("change it later");
29
34
  });
30
35
 
31
- test("contains naming intent markers so the first reply includes naming cues", () => {
32
- const lower = bootstrap.toLowerCase();
33
- // The template must prompt the assistant to ask about names.
34
- expect(lower).toContain("name");
35
- // The first step should be about the assistant's name
36
- expect(lower).toContain("your name");
37
- // The conversation sequence must include identity/naming
38
- expect(lower).toContain("who am i");
39
- });
40
-
41
- test("asks user name AFTER assistant identity is established", () => {
42
- // Step 1 is the assistant's name, step 4 is asking the user's name
43
- const assistantNameIdx = bootstrap.indexOf("Your name:");
44
- const userNameIdx = bootstrap.indexOf("who am I talking to?");
45
- expect(assistantNameIdx).toBeGreaterThan(-1);
46
- expect(userNameIdx).toBeGreaterThan(-1);
47
- expect(assistantNameIdx).toBeLessThan(userNameIdx);
36
+ test("asks about user after assistant identity", () => {
37
+ const nameIdx = bootstrap.indexOf("Your name");
38
+ const theirNameIdx = bootstrap.indexOf("Their name");
39
+ expect(nameIdx).toBeGreaterThan(-1);
40
+ expect(theirNameIdx).toBeGreaterThan(-1);
41
+ expect(nameIdx).toBeLessThan(theirNameIdx);
48
42
  });
49
43
 
50
44
  test("gathers user context: work role, hobbies, daily tools", () => {
51
45
  const lower = bootstrap.toLowerCase();
52
- expect(lower).toContain("work");
46
+ expect(lower).toContain("work role");
53
47
  expect(lower).toContain("hobbies");
54
48
  expect(lower).toContain("tools");
55
49
  });
@@ -57,51 +51,32 @@ describe("onboarding template contracts", () => {
57
51
  test("shows exactly 2 suggestions via ui_show card with relay_prompt actions", () => {
58
52
  expect(bootstrap).toContain("ui_show");
59
53
  expect(bootstrap).toContain("exactly 2");
60
- // Must use card surface with relay_prompt action buttons
61
- expect(bootstrap).toContain('surface_type: "card"');
62
54
  expect(bootstrap).toContain("relay_prompt");
63
55
  });
64
56
 
65
- test("contains completion gate with all required conditions", () => {
57
+ test("contains wrapping-up criteria with required conditions", () => {
66
58
  const lower = bootstrap.toLowerCase();
67
- expect(lower).toContain("completion gate");
68
- expect(lower).toContain("do not delete this file");
69
- // Assistant name is hard-required
70
- expect(lower).toContain("you have a name");
71
- expect(lower).toContain("hard-required");
59
+ expect(lower).toContain("wrapping up");
60
+ expect(lower).toContain("done with onboarding");
72
61
  expect(lower).toContain("vibe");
73
- // User detail fields must be resolved (provided, inferred, or declined)
74
- expect(lower).toContain("resolved");
75
- expect(lower).toContain("work role");
76
- expect(lower).toContain("2 suggestions from step 6");
62
+ expect(lower).toContain("two suggestions");
77
63
  });
78
64
 
79
65
  test("contains refusal policy", () => {
80
66
  const lower = bootstrap.toLowerCase();
81
- // Assistant name is hard-required, user details are best-effort
82
67
  expect(lower).toContain("hard-required");
83
68
  expect(lower).toContain("best-effort");
84
- // Refusal is a valid resolution
85
69
  expect(lower).toContain("declined");
86
- expect(lower).toContain("do not push");
70
+ expect(lower).toContain("not interrogation");
87
71
  });
88
72
 
89
73
  test("defines resolved as provided, inferred, or declined", () => {
90
74
  const lower = bootstrap.toLowerCase();
91
- // The template must define what "resolved" means
92
75
  expect(lower).toContain("resolved");
93
76
  expect(lower).toContain("inferred");
94
77
  expect(lower).toContain("declined");
95
78
  });
96
79
 
97
- // em-dash and technical jargon instructions are now hardcoded in the system
98
- // prompt builder (buildSystemPrompt) rather than in the BOOTSTRAP.md template.
99
-
100
- test("preserves comment line format instruction", () => {
101
- // The template must start with the comment format explanation
102
- expect(bootstrap).toMatch(/^_ Lines starting with _/);
103
- });
104
-
105
80
  test("instructs saving to IDENTITY.md, USER.md, and SOUL.md via file_edit", () => {
106
81
  expect(bootstrap).toContain("IDENTITY.md");
107
82
  expect(bootstrap).toContain("USER.md");
@@ -118,18 +93,13 @@ describe("onboarding template contracts", () => {
118
93
  expect(identity).toContain("**Emoji:**");
119
94
  });
120
95
 
121
- test("contains the emoji overwrite instruction", () => {
122
- const lower = identity.toLowerCase();
123
- expect(lower).toContain("change their emoji");
124
- });
125
-
126
- test("contains the style tendency field", () => {
127
- expect(identity).toContain("**Style tendency:**");
96
+ test("contains parsed field format guidance", () => {
97
+ expect(identity).toContain("parsed by the app");
128
98
  });
129
99
  });
130
100
 
131
101
  describe("USER.md", () => {
132
- test("contains onboarding snapshot with all required fields", () => {
102
+ test("contains profile fields", () => {
133
103
  expect(user).toContain("Preferred name/reference:");
134
104
  expect(user).toContain("Goals:");
135
105
  expect(user).toContain("Locale:");
@@ -137,11 +107,5 @@ describe("onboarding template contracts", () => {
137
107
  expect(user).toContain("Hobbies/fun:");
138
108
  expect(user).toContain("Daily tools:");
139
109
  });
140
-
141
- test("documents resolved-field status conventions", () => {
142
- const lower = user.toLowerCase();
143
- expect(lower).toContain("declined_by_user");
144
- expect(lower).toContain("resolved");
145
- });
146
110
  });
147
111
  });
@@ -49,6 +49,11 @@ mock.module("../util/retry.js", () => {
49
49
  return status === 429 || status >= 500;
50
50
  }
51
51
 
52
+ const RETRYABLE_NETWORK_MESSAGE_PATTERNS = [
53
+ /socket.*closed unexpectedly/i,
54
+ /socket hang up/i,
55
+ ];
56
+
52
57
  function isRetryableNetworkError(error: unknown): boolean {
53
58
  if (!(error instanceof Error)) return false;
54
59
  const retryableCodes = new Set([
@@ -63,6 +68,18 @@ mock.module("../util/retry.js", () => {
63
68
  const causeCode = (error.cause as NodeJS.ErrnoException).code;
64
69
  if (causeCode && retryableCodes.has(causeCode)) return true;
65
70
  }
71
+ if (
72
+ RETRYABLE_NETWORK_MESSAGE_PATTERNS.some((p) => p.test(error.message))
73
+ ) {
74
+ return true;
75
+ }
76
+ const cause = error.cause;
77
+ if (
78
+ cause instanceof Error &&
79
+ RETRYABLE_NETWORK_MESSAGE_PATTERNS.some((p) => p.test(cause.message))
80
+ ) {
81
+ return true;
82
+ }
66
83
  return false;
67
84
  }
68
85
 
@@ -396,6 +413,34 @@ describe("RetryProvider — network error retries", () => {
396
413
  expect(result.content[0]).toMatchObject({ type: "text", text: "ok" });
397
414
  });
398
415
 
416
+ test("retries on Bun 'socket connection was closed unexpectedly' (ProviderError wrapping)", async () => {
417
+ const inner = makeFlaky(
418
+ 1,
419
+ new ProviderError(
420
+ "Anthropic request failed: The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()",
421
+ "anthropic",
422
+ ),
423
+ );
424
+ const provider = new RetryProvider(inner);
425
+
426
+ const result = await provider.sendMessage(MESSAGES);
427
+ expect(inner.calls).toBe(2);
428
+ expect(result.stopReason).toBe("end_turn");
429
+ });
430
+
431
+ test("retries on 'socket connection was closed unexpectedly' in error cause", async () => {
432
+ const cause = new Error(
433
+ "The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()",
434
+ );
435
+ const outer = new Error("fetch failed", { cause });
436
+ const inner = makeFlaky(1, outer);
437
+ const provider = new RetryProvider(inner);
438
+
439
+ const result = await provider.sendMessage(MESSAGES);
440
+ expect(inner.calls).toBe(2);
441
+ expect(result.content[0]).toMatchObject({ type: "text", text: "ok" });
442
+ });
443
+
399
444
  test("does not retry on non-retryable errors", async () => {
400
445
  const inner = makeFailing(new Error("unexpected error"));
401
446
  const provider = new RetryProvider(inner);
@@ -419,6 +464,115 @@ describe("RetryProvider — network error retries", () => {
419
464
  });
420
465
  });
421
466
 
467
+ // ---------------------------------------------------------------------------
468
+ // RetryProvider — streaming corruption retries
469
+ // ---------------------------------------------------------------------------
470
+
471
+ describe("RetryProvider — streaming corruption retries", () => {
472
+ test("retries on 'Unexpected event order' (message_start before message_stop)", async () => {
473
+ const inner = makeFlaky(
474
+ 1,
475
+ new ProviderError(
476
+ 'Anthropic request failed: Unexpected event order, got message_start before receiving "message_stop"',
477
+ "anthropic",
478
+ ),
479
+ );
480
+ const provider = new RetryProvider(inner);
481
+
482
+ const result = await provider.sendMessage(MESSAGES);
483
+ expect(result.stopReason).toBe("end_turn");
484
+ expect(inner.calls).toBe(2);
485
+ });
486
+
487
+ test("retries on 'Unexpected event order' (event before message_start)", async () => {
488
+ const inner = makeFlaky(
489
+ 1,
490
+ new ProviderError(
491
+ 'Anthropic request failed: Unexpected event order, got content_block_start before "message_start"',
492
+ "anthropic",
493
+ ),
494
+ );
495
+ const provider = new RetryProvider(inner);
496
+
497
+ const result = await provider.sendMessage(MESSAGES);
498
+ expect(inner.calls).toBe(2);
499
+ expect(result.model).toBe("test-model");
500
+ });
501
+
502
+ test("retries on 'stream ended without producing'", async () => {
503
+ const inner = makeFlaky(
504
+ 1,
505
+ new ProviderError(
506
+ "Anthropic request failed: stream ended without producing a Message with role=assistant",
507
+ "anthropic",
508
+ ),
509
+ );
510
+ const provider = new RetryProvider(inner);
511
+
512
+ const result = await provider.sendMessage(MESSAGES);
513
+ expect(inner.calls).toBe(2);
514
+ expect(result.content).toHaveLength(1);
515
+ });
516
+
517
+ test("retries on 'request ended without sending any chunks'", async () => {
518
+ const inner = makeFlaky(
519
+ 1,
520
+ new ProviderError(
521
+ "Anthropic request failed: request ended without sending any chunks",
522
+ "anthropic",
523
+ ),
524
+ );
525
+ const provider = new RetryProvider(inner);
526
+
527
+ await provider.sendMessage(MESSAGES);
528
+ expect(inner.calls).toBe(2);
529
+ });
530
+
531
+ test("throws after exhausting retries on persistent stream corruption", async () => {
532
+ const inner = makeFailing(
533
+ new ProviderError(
534
+ 'Anthropic request failed: Unexpected event order, got message_start before receiving "message_stop"',
535
+ "anthropic",
536
+ ),
537
+ );
538
+ const provider = new RetryProvider(inner);
539
+
540
+ await expect(provider.sendMessage(MESSAGES)).rejects.toThrow(
541
+ "Unexpected event order",
542
+ );
543
+ expect(inner.calls).toBe(DEFAULT_MAX_RETRIES + 1);
544
+ });
545
+
546
+ test("does not retry non-stream ProviderError without status code", async () => {
547
+ const inner = makeFailing(
548
+ new ProviderError("model not found", "anthropic"),
549
+ );
550
+ const provider = new RetryProvider(inner);
551
+
552
+ await expect(provider.sendMessage(MESSAGES)).rejects.toThrow(
553
+ "model not found",
554
+ );
555
+ expect(inner.calls).toBe(1);
556
+ });
557
+
558
+ test("does not treat stream pattern as retryable when ProviderError has a status code", async () => {
559
+ // A 400 error that happens to contain "Unexpected event order" should NOT be retried
560
+ const inner = makeFailing(
561
+ new ProviderError(
562
+ "Unexpected event order in request payload",
563
+ "anthropic",
564
+ 400,
565
+ ),
566
+ );
567
+ const provider = new RetryProvider(inner);
568
+
569
+ await expect(provider.sendMessage(MESSAGES)).rejects.toThrow(
570
+ "Unexpected event order",
571
+ );
572
+ expect(inner.calls).toBe(1);
573
+ });
574
+ });
575
+
422
576
  // ---------------------------------------------------------------------------
423
577
  // RetryProvider — streaming + options passthrough
424
578
  // ---------------------------------------------------------------------------
@@ -52,9 +52,9 @@ function makeProvidersConfig(provider: string, model: string): ProvidersConfig {
52
52
  "image-generation": {
53
53
  mode: "your-own",
54
54
  provider: "gemini",
55
- model: "gemini-2.5-flash-image",
55
+ model: "gemini-3.1-flash-image-preview",
56
56
  },
57
- "web-search": { mode: "your-own", provider: "anthropic-native" },
57
+ "web-search": { mode: "your-own", provider: "inference-provider-native" },
58
58
  },
59
59
  };
60
60
  }
@@ -69,9 +69,9 @@ function makeProvidersConfig(provider: string, model: string): ProvidersConfig {
69
69
  "image-generation": {
70
70
  mode: "your-own",
71
71
  provider: "gemini",
72
- model: "gemini-2.5-flash-image",
72
+ model: "gemini-3.1-flash-image-preview",
73
73
  },
74
- "web-search": { mode: "your-own", provider: "anthropic-native" },
74
+ "web-search": { mode: "your-own", provider: "inference-provider-native" },
75
75
  },
76
76
  };
77
77
  }
@@ -206,7 +206,7 @@ describe("managed proxy integration — credential precedence", () => {
206
206
  expect(baseURL).toContain("/v1/runtime-proxy/anthropic");
207
207
  });
208
208
 
209
- test("managed gemini uses vertex proxy path", async () => {
209
+ test("managed gemini uses gemini proxy path", async () => {
210
210
  enableManagedProxy();
211
211
  mockProviderKeys = {};
212
212
  await initializeProviders(makeProvidersConfig("anthropic", "test-model"));
@@ -216,8 +216,7 @@ describe("managed proxy integration — credential precedence", () => {
216
216
  | { baseUrl?: string }
217
217
  | undefined;
218
218
  expect(httpOptions).toBeDefined();
219
- expect(httpOptions!.baseUrl).toContain("/v1/runtime-proxy/vertex");
220
- expect(httpOptions!.baseUrl).not.toContain("/v1/runtime-proxy/gemini");
219
+ expect(httpOptions!.baseUrl).toContain("/v1/runtime-proxy/gemini");
221
220
  });
222
221
  });
223
222
 
@@ -309,8 +308,8 @@ describe("managed proxy integration — ollama exclusion", () => {
309
308
  });
310
309
 
311
310
  describe("managed proxy integration — constants integrity", () => {
312
- test("anthropic, gemini, and vertex have metadata with managed=true and a proxyPath", () => {
313
- for (const provider of ["anthropic", "gemini", "vertex"]) {
311
+ test("anthropic and gemini have metadata with managed=true and a proxyPath", () => {
312
+ for (const provider of ["anthropic", "gemini"]) {
314
313
  const meta = MANAGED_PROVIDER_META[provider];
315
314
  expect(meta).toBeDefined();
316
315
  expect(meta.managed).toBe(true);
@@ -325,9 +324,9 @@ describe("managed proxy integration — constants integrity", () => {
325
324
  );
326
325
  });
327
326
 
328
- test("gemini routes through vertex proxy path", () => {
327
+ test("gemini routes through gemini proxy path", () => {
329
328
  expect(MANAGED_PROVIDER_META.gemini.proxyPath).toBe(
330
- "/v1/runtime-proxy/vertex",
329
+ "/v1/runtime-proxy/gemini",
331
330
  );
332
331
  });
333
332
 
@@ -25,9 +25,12 @@ describe("provider registry (ollama)", () => {
25
25
  "image-generation": {
26
26
  mode: "your-own",
27
27
  provider: "gemini",
28
- model: "gemini-2.5-flash-image",
28
+ model: "gemini-3.1-flash-image-preview",
29
+ },
30
+ "web-search": {
31
+ mode: "your-own",
32
+ provider: "inference-provider-native",
29
33
  },
30
- "web-search": { mode: "your-own", provider: "anthropic-native" },
31
34
  },
32
35
  });
33
36
 
@@ -36,9 +36,9 @@ import { QdrantManager } from "../memory/qdrant-manager.js";
36
36
 
37
37
  /** Short timeouts so tests complete fast but with enough headroom for CI. */
38
38
  const FAST_TIMEOUTS = {
39
- readyzPollIntervalMs: 10,
40
- readyzTimeoutMs: 1_000,
41
- shutdownGraceMs: 200,
39
+ readyzPollIntervalMs: 5,
40
+ readyzTimeoutMs: 100,
41
+ shutdownGraceMs: 50,
42
42
  } as const;
43
43
 
44
44
  function placeFakeBinary(script: string): string {
@@ -248,7 +248,7 @@ describe("QdrantManager", () => {
248
248
  const startPromise = mgr.start();
249
249
 
250
250
  // Wait for spawn to happen
251
- await Bun.sleep(300);
251
+ await Bun.sleep(50);
252
252
 
253
253
  // PID file should be written
254
254
  expect(existsSync(pidPath)).toBe(true);
@@ -277,7 +277,7 @@ describe("QdrantManager", () => {
277
277
  });
278
278
 
279
279
  const startPromise = mgr.start();
280
- await Bun.sleep(300);
280
+ await Bun.sleep(50);
281
281
 
282
282
  expect(existsSync(pidPath)).toBe(true);
283
283
 
@@ -285,8 +285,8 @@ describe("QdrantManager", () => {
285
285
  await mgr.stop();
286
286
  const stopElapsed = Date.now() - stopStart;
287
287
 
288
- // Grace period is 200ms with FAST_TIMEOUTS — should wait at least that long
289
- expect(stopElapsed).toBeGreaterThanOrEqual(100);
288
+ // Grace period is 50ms with FAST_TIMEOUTS — should wait at least that long
289
+ expect(stopElapsed).toBeGreaterThanOrEqual(30);
290
290
  expect(existsSync(pidPath)).toBe(false);
291
291
 
292
292
  await expect(startPromise).rejects.toThrow("did not become ready");