@vellumai/assistant 0.11.8 → 0.11.9-staging.1

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 (318) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/Dockerfile +8 -48
  3. package/docker-entrypoint.sh +5 -1
  4. package/docker-kata-apt-env.sh +3 -0
  5. package/docker-kata-apt-shims.sh +127 -0
  6. package/docker-kata-apt-wrapper.sh +45 -0
  7. package/docker-kata-chroot-exec.sh +35 -0
  8. package/docker-kata-pip.sh +8 -2
  9. package/docs/architecture/memory.md +8 -4
  10. package/docs/guardian-request-flow.md +18 -14
  11. package/docs/trusted-contact-access.md +1 -7
  12. package/node_modules/@vellumai/avatar-catalog/src/catalog.ts +7 -1
  13. package/node_modules/@vellumai/avatar-catalog/src/index.ts +1 -1
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +4 -1
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  17. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
  18. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
  19. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +4 -1
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
  24. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-request-contract.test.ts +0 -18
  25. package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +110 -5
  26. package/node_modules/@vellumai/gateway-client/src/guardian-request-contract.ts +5 -33
  27. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +3 -0
  28. package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +100 -9
  29. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -2
  30. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +9 -0
  31. package/node_modules/@vellumai/service-contracts/package.json +4 -1
  32. package/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
  33. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  34. package/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
  35. package/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
  36. package/openapi.yaml +193 -4
  37. package/package.json +2 -2
  38. package/src/__tests__/access-request-card-view.test.ts +6 -5
  39. package/src/__tests__/access-request-seed-content-blocks.test.ts +5 -2
  40. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +43 -82
  41. package/src/__tests__/always-loaded-tools-guard.test.ts +8 -2
  42. package/src/__tests__/attachment-stored-path-annotation.test.ts +80 -0
  43. package/src/__tests__/attachments-store.test.ts +27 -0
  44. package/src/__tests__/attachments.test.ts +43 -0
  45. package/src/__tests__/canned-reply-release.test.ts +48 -5
  46. package/src/__tests__/channel-delivery-store.test.ts +129 -18
  47. package/src/__tests__/channel-reply-delivery.test.ts +553 -93
  48. package/src/__tests__/channel-retry-sweep.test.ts +199 -0
  49. package/src/__tests__/client-os-metadata-persistence.test.ts +32 -3
  50. package/src/__tests__/conversation-error.test.ts +15 -0
  51. package/src/__tests__/conversation-load-history-repair.test.ts +118 -0
  52. package/src/__tests__/conversation-pairing.test.ts +141 -1
  53. package/src/__tests__/conversation-routes-disk-view.test.ts +28 -1
  54. package/src/__tests__/conversation-routes-slash-commands.test.ts +125 -0
  55. package/src/__tests__/conversation-runtime-assembly.test.ts +79 -0
  56. package/src/__tests__/conversation-store-ephemeral.test.ts +323 -10
  57. package/src/__tests__/conversation-sync-tags.test.ts +2 -37
  58. package/src/__tests__/credential-health-service.test.ts +98 -10
  59. package/src/__tests__/delete-propagation.test.ts +469 -0
  60. package/src/__tests__/dm-persistence.test.ts +16 -0
  61. package/src/__tests__/docker-kata-apt-shims.test.ts +135 -0
  62. package/src/__tests__/forbidden-legacy-symbols.test.ts +12 -0
  63. package/src/__tests__/guardian-card-withdrawal.test.ts +0 -22
  64. package/src/__tests__/guardian-gateway-sim.ts +0 -23
  65. package/src/__tests__/guardian-question-mode.test.ts +108 -0
  66. package/src/__tests__/guardian-reply-router-answer-mode.test.ts +0 -2
  67. package/src/__tests__/guardian-routing-invariants.test.ts +26 -12
  68. package/src/__tests__/host-proxy-interface.test.ts +10 -0
  69. package/src/__tests__/inbound-slack-persistence.test.ts +16 -0
  70. package/src/__tests__/injector-v3-suppression.test.ts +43 -9
  71. package/src/__tests__/list-messages-page-latest.test.ts +127 -0
  72. package/src/__tests__/list-messages-system-card.test.ts +103 -0
  73. package/src/__tests__/media-resolve-image-validation.test.ts +77 -0
  74. package/src/__tests__/notification-decision-fallback.test.ts +199 -77
  75. package/src/__tests__/notification-decision-strategy.test.ts +198 -213
  76. package/src/__tests__/notification-discord-adapter.test.ts +25 -0
  77. package/src/__tests__/notification-slack-adapter.test.ts +133 -0
  78. package/src/__tests__/notification-telegram-adapter.test.ts +36 -0
  79. package/src/__tests__/openai-provider.test.ts +5 -5
  80. package/src/__tests__/outbound-slack-persistence.test.ts +85 -72
  81. package/src/__tests__/persist-user-message-set-processing-failure.test.ts +83 -65
  82. package/src/__tests__/platform-client-verify-credential.test.ts +100 -0
  83. package/src/__tests__/plugin-import-boundary-guard.test.ts +1 -1
  84. package/src/__tests__/process-message-display-content.test.ts +20 -9
  85. package/src/__tests__/processing-acquire-fenced-guard.test.ts +56 -0
  86. package/src/__tests__/provider-meta-persistence.test.ts +67 -0
  87. package/src/__tests__/reaction-persistence.test.ts +22 -198
  88. package/src/__tests__/run-conversation-turn-persistence.test.ts +5 -2
  89. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +16 -0
  90. package/src/__tests__/skill-load-tool.test.ts +27 -0
  91. package/src/__tests__/skills.test.ts +34 -1
  92. package/src/__tests__/strip-memory-injections.test.ts +3 -4
  93. package/src/__tests__/terminal-tools.test.ts +9 -0
  94. package/src/__tests__/thread-backfill.test.ts +5 -3
  95. package/src/__tests__/unified-turn-context-location.test.ts +76 -0
  96. package/src/__tests__/voice-session-bridge.test.ts +18 -0
  97. package/src/__tests__/watch-retro-report-payload.test.ts +185 -0
  98. package/src/__tests__/watch-retro-tool-availability.test.ts +82 -0
  99. package/src/__tests__/workspace-migration-151-repair-renamed-fireworks-deepseek-pro-model-id.test.ts +235 -0
  100. package/src/__tests__/workspace-migration-152-repair-retired-fireworks-minimax-m2p7-model-id.test.ts +233 -0
  101. package/src/agent/attachments.ts +13 -2
  102. package/src/agent/loop.ts +3 -19
  103. package/src/api/README.md +9 -5
  104. package/src/api/index.ts +9 -8
  105. package/src/api/package.json +1 -0
  106. package/src/api/responses/conversation-message.ts +8 -0
  107. package/src/api/responses/home.ts +7 -18
  108. package/src/api/surfaces.ts +114 -7
  109. package/src/approvals/AGENTS.md +1 -1
  110. package/src/channels/__tests__/gateway-guardian-requests.test.ts +1 -23
  111. package/src/channels/__tests__/types.test.ts +22 -1
  112. package/src/channels/gateway-guardian-requests.ts +0 -22
  113. package/src/channels/types.ts +8 -6
  114. package/src/cli/__tests__/catalog-search-help.test.ts +12 -0
  115. package/src/cli/commands/channels/__tests__/channels.test.ts +26 -0
  116. package/src/cli/commands/channels/index.help.ts +15 -1
  117. package/src/cli/commands/channels/index.ts +6 -2
  118. package/src/cli/commands/db/__tests__/status.test.ts +22 -0
  119. package/src/cli/commands/db/index.help.ts +1 -1
  120. package/src/cli/commands/db/status.ts +172 -1
  121. package/src/cli/commands/platform/__tests__/connect.test.ts +29 -0
  122. package/src/cli/commands/platform/connect.ts +14 -5
  123. package/src/cli/commands/plugins.help.ts +6 -5
  124. package/src/cli/lib/__tests__/install-from-github.test.ts +0 -8
  125. package/src/cli/lib/__tests__/install-from-platform.test.ts +72 -0
  126. package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +33 -0
  127. package/src/cli/lib/bundled-marketplace.json +14 -0
  128. package/src/cli/lib/install-from-github.ts +9 -5
  129. package/src/cli/lib/install-from-platform.ts +12 -1
  130. package/src/config/__tests__/assistant-initiated-threads-gate.test.ts +61 -0
  131. package/src/config/assistant-initiated-threads-gate.ts +50 -0
  132. package/src/config/bundled-skills/acp/SKILL.md +10 -3
  133. package/src/config/bundled-skills/schedule/SKILL.md +25 -11
  134. package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +3 -1
  135. package/src/config/call-site-defaults.ts +4 -1
  136. package/src/config/feature-flag-registry.json +21 -4
  137. package/src/config/schemas/memory-v3.ts +4 -3
  138. package/src/context/strip-injections.ts +17 -56
  139. package/src/conversations/__tests__/message-consolidation.test.ts +39 -0
  140. package/src/conversations/message-consolidation.ts +4 -3
  141. package/src/credential-health/credential-health-service.ts +130 -0
  142. package/src/daemon/__tests__/conversation-tool-setup.test.ts +31 -0
  143. package/src/daemon/conversation-agent-loop-handlers.ts +55 -59
  144. package/src/daemon/conversation-error.ts +2 -0
  145. package/src/daemon/conversation-messaging.ts +195 -47
  146. package/src/daemon/conversation-process.ts +20 -5
  147. package/src/daemon/conversation-runtime-assembly.ts +48 -39
  148. package/src/daemon/conversation-store.ts +159 -11
  149. package/src/daemon/conversation-tool-setup.ts +9 -2
  150. package/src/daemon/conversation.ts +290 -19
  151. package/src/daemon/dictation-text-processing.ts +2 -7
  152. package/src/daemon/handlers/config-channels.ts +33 -3
  153. package/src/daemon/handlers/shared.ts +9 -0
  154. package/src/daemon/port-oversized-content.test.ts +117 -0
  155. package/src/daemon/port-oversized-content.ts +110 -0
  156. package/src/daemon/process-message.ts +87 -16
  157. package/src/daemon/reaction-record.test.ts +23 -11
  158. package/src/daemon/reaction-record.ts +6 -9
  159. package/src/documents/document-store.ts +1 -5
  160. package/src/home/conversation-starter-validation.ts +1 -5
  161. package/src/live-voice/__tests__/live-voice-photo.test.ts +910 -50
  162. package/src/live-voice/__tests__/live-voice-sight-frame-inline.test.ts +31 -25
  163. package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +70 -1
  164. package/src/live-voice/live-voice-photo.ts +544 -61
  165. package/src/live-voice/live-voice-session.ts +6 -2
  166. package/src/live-voice/protocol.ts +20 -1
  167. package/src/messaging/provider-message-metadata.ts +40 -1
  168. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +10 -2
  169. package/src/messaging/providers/channel-transport.ts +28 -0
  170. package/src/messaging/providers/discord/send.ts +3 -2
  171. package/src/messaging/providers/slack/api.ts +11 -1
  172. package/src/messaging/providers/slack/message-metadata.test.ts +133 -0
  173. package/src/messaging/providers/slack/message-metadata.ts +141 -1
  174. package/src/messaging/providers/slack/send.test.ts +58 -0
  175. package/src/messaging/providers/slack/send.ts +4 -4
  176. package/src/messaging/providers/slack/transport.ts +28 -2
  177. package/src/messaging/providers/telegram-bot/send.test.ts +159 -0
  178. package/src/messaging/providers/telegram-bot/send.ts +93 -0
  179. package/src/messaging/providers/telegram-bot/transport.ts +71 -0
  180. package/src/messaging/reaction-envelopes.test.ts +73 -0
  181. package/src/messaging/reaction-envelopes.ts +33 -5
  182. package/src/messaging/read-provider-metadata.ts +4 -3
  183. package/src/monitoring/recovery/__tests__/stranded-delivery-events.test.ts +208 -0
  184. package/src/monitoring/recovery/db.ts +35 -0
  185. package/src/monitoring/recovery/orphaned-channel-events.ts +3 -22
  186. package/src/monitoring/recovery/run-recovery.ts +6 -2
  187. package/src/monitoring/recovery/stale-processing.ts +3 -20
  188. package/src/monitoring/recovery/stranded-delivery-events.ts +68 -0
  189. package/src/notifications/AGENTS.md +2 -2
  190. package/src/notifications/README.md +2 -2
  191. package/src/notifications/__tests__/assistant-reply-producer.test.ts +11 -9
  192. package/src/notifications/__tests__/broadcaster.test.ts +35 -4
  193. package/src/notifications/__tests__/notification-utils.test.ts +31 -0
  194. package/src/notifications/access-request-copy.ts +126 -114
  195. package/src/notifications/adapters/discord.ts +9 -5
  196. package/src/notifications/adapters/shared.ts +17 -4
  197. package/src/notifications/adapters/slack.ts +14 -4
  198. package/src/notifications/adapters/telegram.ts +8 -4
  199. package/src/notifications/approval-card-data.ts +5 -2
  200. package/src/notifications/assistant-reply-producer.ts +7 -7
  201. package/src/notifications/broadcaster.ts +57 -25
  202. package/src/notifications/conversation-pairing.ts +68 -2
  203. package/src/notifications/copy-composer.ts +13 -32
  204. package/src/notifications/decision-engine.ts +56 -237
  205. package/src/notifications/guardian-delivery-recorder.ts +5 -9
  206. package/src/notifications/guardian-feed-projection.ts +0 -15
  207. package/src/notifications/guardian-question-mode.ts +147 -6
  208. package/src/notifications/notification-utils.ts +117 -1
  209. package/src/permissions/confirmation-guardian-request.ts +2 -2
  210. package/src/permissions/prompter.ts +1 -1
  211. package/src/persistence/conversation-crud.ts +93 -14
  212. package/src/persistence/conversation-queries.ts +144 -17
  213. package/src/persistence/conversation-types.ts +39 -5
  214. package/src/persistence/delivery-crud.ts +224 -28
  215. package/src/persistence/delivery-status.ts +21 -2
  216. package/src/persistence/migrations/374-channel-inbound-message-id-index.ts +26 -0
  217. package/src/persistence/migrations/375-create-channel-outbound-posts.ts +52 -0
  218. package/src/persistence/migrations/__tests__/375-create-channel-outbound-posts.test.ts +84 -0
  219. package/src/persistence/schema/conversations.ts +71 -2
  220. package/src/persistence/schema-contract.test.ts +78 -0
  221. package/src/persistence/schema-contract.ts +96 -0
  222. package/src/persistence/steps.ts +4 -0
  223. package/src/platform/client.ts +55 -0
  224. package/src/plugins/__tests__/mcp-servers.test.ts +46 -0
  225. package/src/plugins/defaults/injector-order.ts +2 -1
  226. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +2 -2
  227. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +13 -15
  228. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +10 -0
  229. package/src/plugins/defaults/memory/injectors.ts +1 -1
  230. package/src/plugins/defaults/memory/memory-marker.ts +17 -7
  231. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +1 -5
  232. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +54 -41
  233. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +3 -3
  234. package/src/plugins/defaults/memory/v3/injector.ts +14 -15
  235. package/src/plugins/defaults/memory/v3/types.ts +15 -4
  236. package/src/plugins/defaults/turn-context/injectors.ts +3 -0
  237. package/src/plugins/defaults/turn-context/unified-turn-context.ts +24 -0
  238. package/src/plugins/mcp-servers.ts +14 -2
  239. package/src/providers/__tests__/dispatch-connection-routing.test.ts +50 -0
  240. package/src/providers/__tests__/registry-native-web-search.test.ts +49 -2
  241. package/src/providers/anthropic/client.ts +21 -24
  242. package/src/providers/call-site-routing.ts +5 -4
  243. package/src/providers/connection-resolution.ts +29 -1
  244. package/src/providers/content-block-size.test.ts +82 -0
  245. package/src/providers/content-block-size.ts +99 -0
  246. package/src/providers/file-block-text.test.ts +64 -0
  247. package/src/providers/file-block-text.ts +28 -0
  248. package/src/providers/gemini/client.ts +12 -7
  249. package/src/providers/inference/auth.ts +6 -6
  250. package/src/providers/media-resolve.ts +14 -0
  251. package/src/providers/model-catalog.ts +31 -34
  252. package/src/providers/openai/chat-completions-provider.ts +9 -25
  253. package/src/providers/openai/responses-provider.ts +11 -18
  254. package/src/providers/registry.ts +10 -7
  255. package/src/providers/routing-identity.ts +2 -1
  256. package/src/providers/types.ts +1 -4
  257. package/src/providers/vellum-model-routing.ts +3 -2
  258. package/src/runtime/AGENTS.md +40 -15
  259. package/src/runtime/approval-message-composer.ts +1 -6
  260. package/src/runtime/assistant-event-hub.ts +2 -39
  261. package/src/runtime/channel-approval-types.ts +1 -5
  262. package/src/runtime/channel-reply-delivery.ts +182 -115
  263. package/src/runtime/{slack-reply-session.test.ts → channel-reply-session.test.ts} +294 -156
  264. package/src/runtime/{slack-reply-session.ts → channel-reply-session.ts} +107 -86
  265. package/src/runtime/channel-retry-sweep.ts +102 -1
  266. package/src/runtime/finalize-event-delivery.ts +4 -4
  267. package/src/runtime/guardian-action-message-composer.ts +1 -4
  268. package/src/runtime/guardian-reply-router.ts +4 -75
  269. package/src/runtime/http-router.ts +1 -5
  270. package/src/runtime/question-request-guardian-bridge.ts +2 -3
  271. package/src/runtime/routes/__tests__/conversation-list-assistant-section.test.ts +359 -0
  272. package/src/runtime/routes/__tests__/dictation-command-mode.test.ts +120 -0
  273. package/src/runtime/routes/__tests__/sight-frame-routes.test.ts +487 -0
  274. package/src/runtime/routes/acp-routes.ts +1 -1
  275. package/src/runtime/routes/canned-reply-release.ts +19 -9
  276. package/src/runtime/routes/channel-route-shared.ts +0 -39
  277. package/src/runtime/routes/channel-verification-routes.ts +4 -1
  278. package/src/runtime/routes/conversation-list-routes.ts +44 -3
  279. package/src/runtime/routes/conversation-management-routes.ts +2 -1
  280. package/src/runtime/routes/conversation-routes.ts +138 -59
  281. package/src/runtime/routes/diagnostics-routes.ts +111 -60
  282. package/src/runtime/routes/guardian-action-routes.ts +10 -14
  283. package/src/runtime/routes/guardian-approval-interception.ts +0 -5
  284. package/src/runtime/routes/inbound-message-handler.ts +170 -48
  285. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +4 -3
  286. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +169 -8
  287. package/src/runtime/routes/inbound-stages/background-dispatch.ts +82 -14
  288. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +23 -48
  289. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +454 -94
  290. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +309 -102
  291. package/src/runtime/routes/index.ts +2 -0
  292. package/src/runtime/routes/platform-routes.ts +99 -10
  293. package/src/runtime/routes/sight-frame-routes.ts +136 -0
  294. package/src/runtime/sync/resource-sync-events.ts +14 -37
  295. package/src/runtime/sync/sync-publisher.test.ts +5 -4
  296. package/src/tools/__tests__/tool-input-schemas.test.ts +2 -0
  297. package/src/tools/client-os.ts +11 -1
  298. package/src/tools/host-filesystem/edit.ts +2 -2
  299. package/src/tools/host-filesystem/read.ts +2 -2
  300. package/src/tools/host-filesystem/transfer.ts +2 -2
  301. package/src/tools/host-filesystem/write.ts +2 -2
  302. package/src/tools/host-terminal/host-shell.ts +2 -2
  303. package/src/tools/skills/load.ts +1 -1
  304. package/src/tools/terminal/safe-env.ts +4 -0
  305. package/src/tools/tool-input-schemas.ts +2 -0
  306. package/src/tools/tool-manifest.ts +2 -0
  307. package/src/tools/ui-surface/definitions.ts +4 -3
  308. package/src/tools/watch/watch-retro-report.ts +205 -0
  309. package/src/watch/__tests__/watch-retro.test.ts +268 -40
  310. package/src/watch/watch-retro.ts +190 -77
  311. package/src/workspace/migrations/151-repair-renamed-fireworks-deepseek-pro-model-id.ts +195 -0
  312. package/src/workspace/migrations/152-repair-retired-fireworks-minimax-m2p7-model-id.ts +198 -0
  313. package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +0 -10
  314. package/src/workspace/migrations/registry.ts +4 -0
  315. package/docker-kata-pip-chroot.sh +0 -22
  316. package/src/__tests__/slack-reaction-approvals.test.ts +0 -97
  317. package/src/__tests__/slack-reaction-guardian-approval.test.ts +0 -307
  318. package/src/api/events/conversation-list-invalidated.ts +0 -38
@@ -10,6 +10,12 @@ import {
10
10
  } from "../../util/provider-error-patterns.js";
11
11
  import { extractRetryAfterMs } from "../../util/retry.js";
12
12
  import { stripOrphanedSurrogatesDeep } from "../../util/unicode.js";
13
+ import {
14
+ clampProviderString,
15
+ isDecodableTextMimeType,
16
+ keepFileAsWorkspaceRef,
17
+ } from "../content-block-size.js";
18
+ import { fileBlockToProviderText } from "../file-block-text.js";
13
19
  import { base64Source, resolveMediaReferences } from "../media-resolve.js";
14
20
  import {
15
21
  couldBePlaceholderSentinelPrefix,
@@ -106,8 +112,7 @@ function readAnthropicErrorType(
106
112
  error: InstanceType<typeof Anthropic.APIError>,
107
113
  ): string | undefined {
108
114
  const body = error.error as
109
- | { type?: string; error?: { type?: string; code?: string } }
110
- | undefined;
115
+ { type?: string; error?: { type?: string; code?: string } } | undefined;
111
116
  return body?.error?.type ?? body?.type;
112
117
  }
113
118
 
@@ -127,8 +132,7 @@ function readAnthropicMessage(
127
132
  error: InstanceType<typeof Anthropic.APIError>,
128
133
  ): string | undefined {
129
134
  const body = error.error as
130
- | { message?: string; error?: { message?: string } }
131
- | undefined;
135
+ { message?: string; error?: { message?: string } } | undefined;
132
136
  const inner = body?.error?.message ?? body?.message;
133
137
  return typeof inner === "string" && inner.length > 0 ? inner : undefined;
134
138
  }
@@ -283,15 +287,6 @@ const ANTHROPIC_SUPPORTED_IMAGE_TYPES = new Set([
283
287
  "image/webp",
284
288
  ]);
285
289
 
286
- function isTextBasedMimeType(mediaType: string): boolean {
287
- return (
288
- mediaType.startsWith("text/") ||
289
- mediaType === "application/json" ||
290
- mediaType === "application/xml" ||
291
- mediaType === "application/javascript"
292
- );
293
- }
294
-
295
290
  /** Anthropic requires tool_use IDs to match ^[a-zA-Z0-9_-]+$ */
296
291
  function sanitizeToolId(id: string): string {
297
292
  if (!id) {
@@ -968,8 +963,7 @@ export class AnthropicProvider implements Provider {
968
963
  const { tools, systemPrompt, config, onEvent, signal } = options ?? {};
969
964
  const cacheTtl: "5m" | "1h" =
970
965
  ((config as Record<string, unknown> | undefined)?.cacheTtl as
971
- | "5m"
972
- | "1h") ?? "1h";
966
+ "5m" | "1h") ?? "1h";
973
967
  // Opt-out for callers (e.g. the memory router) that send a single
974
968
  // user message per call with content that changes every time. The
975
969
  // turn-start cache breakpoint below is only useful when the same
@@ -2148,9 +2142,10 @@ export class AnthropicProvider implements Provider {
2148
2142
  const cacheControl = (
2149
2143
  block as { cache_control?: Anthropic.CacheControlEphemeral }
2150
2144
  ).cache_control;
2145
+ const text = clampProviderString(block.text);
2151
2146
  return cacheControl
2152
- ? { type: "text", text: block.text, cache_control: cacheControl }
2153
- : { type: "text", text: block.text };
2147
+ ? { type: "text", text, cache_control: cacheControl }
2148
+ : { type: "text", text };
2154
2149
  }
2155
2150
  case "thinking":
2156
2151
  if (!block.signature) {
@@ -2183,6 +2178,9 @@ export class AnthropicProvider implements Provider {
2183
2178
  },
2184
2179
  };
2185
2180
  case "file": {
2181
+ if (keepFileAsWorkspaceRef(block.source)) {
2182
+ return { type: "text", text: fileBlockToProviderText(block) };
2183
+ }
2186
2184
  const { media_type, data, filename } = base64Source(block.source);
2187
2185
  if (media_type === "application/pdf") {
2188
2186
  // Only valid base64 document source for Anthropic
@@ -2192,9 +2190,11 @@ export class AnthropicProvider implements Provider {
2192
2190
  ...(filename ? { title: filename } : {}),
2193
2191
  } as unknown as Anthropic.ContentBlockParam;
2194
2192
  }
2195
- if (isTextBasedMimeType(media_type)) {
2193
+ if (isDecodableTextMimeType(media_type)) {
2196
2194
  // Decode base64 to UTF-8 text and send as PlainTextSource
2197
- const decodedText = Buffer.from(data, "base64").toString("utf-8");
2195
+ const decodedText = clampProviderString(
2196
+ Buffer.from(data, "base64").toString("utf-8"),
2197
+ );
2198
2198
  return {
2199
2199
  type: "document",
2200
2200
  source: {
@@ -2205,14 +2205,11 @@ export class AnthropicProvider implements Provider {
2205
2205
  ...(filename ? { title: filename } : {}),
2206
2206
  } as unknown as Anthropic.ContentBlockParam;
2207
2207
  }
2208
- // Binary non-text file: use extracted_text if available, otherwise a placeholder
2208
+ // Binary non-text file: name the workspace file, never dump bytes.
2209
2209
  log.warn(
2210
2210
  `Binary file type not natively supported by Anthropic: ${media_type}; falling back to text`,
2211
2211
  );
2212
- const fallbackText = block.extracted_text?.trim()
2213
- ? block.extracted_text
2214
- : `[File: ${filename ?? "unknown"} (${media_type}) — binary file]`;
2215
- return { type: "text", text: fallbackText };
2212
+ return { type: "text", text: fileBlockToProviderText(block) };
2216
2213
  }
2217
2214
  case "tool_use":
2218
2215
  return {
@@ -358,17 +358,18 @@ export class CallSiteRoutingProvider implements Provider {
358
358
  }
359
359
  // Soft credential failure: the routed connection yielded no usable
360
360
  // adapter and dispatch is landing on the default transport, which may
361
- // be the platform-billed route — keep every such degradation
362
- // observable.
361
+ // be the platform-billed route. Keep every such degradation
362
+ // observable. The reason is "no adapter", not a proven credential miss:
363
+ // adapter construction can also fail for dispatch bugs.
363
364
  log.warn(
364
365
  {
365
366
  callSite,
366
367
  connectionName,
367
368
  provider: resolved.provider,
368
369
  model: resolved.model,
369
- reason: "credential_unavailable",
370
+ reason: "adapter_unavailable",
370
371
  },
371
- "Routed connection yielded no adapter — falling back to the default transport",
372
+ "Routed connection yielded no adapter: falling back to the default transport",
372
373
  );
373
374
  return this.defaultRoute(profileName);
374
375
  }
@@ -387,9 +387,23 @@ export async function tryResolveProviderForConnectionName(
387
387
  });
388
388
  return attachProviderRoute(provider, connection);
389
389
  } catch (err) {
390
+ if (err instanceof ConnectionResolutionError) {
391
+ throw err;
392
+ }
393
+ if (
394
+ err instanceof Error &&
395
+ /unresolved routing identity/.test(err.message)
396
+ ) {
397
+ throw new ConnectionResolutionError(
398
+ connectionName,
399
+ "adapter_unavailable",
400
+ err.message,
401
+ { cause: err, model },
402
+ );
403
+ }
390
404
  log.warn(
391
405
  { err, connectionName },
392
- "provider_connection auth resolution failed transiently — returning null",
406
+ "provider_connection auth resolution failed transiently: returning null",
393
407
  );
394
408
  return null;
395
409
  }
@@ -457,6 +471,20 @@ async function resolveThroughPlatform(
457
471
  { model, providerOverride: upstream },
458
472
  );
459
473
  } catch (err) {
474
+ if (err instanceof ConnectionResolutionError) {
475
+ throw err;
476
+ }
477
+ if (
478
+ err instanceof Error &&
479
+ /unresolved routing identity/.test(err.message)
480
+ ) {
481
+ throw new ConnectionResolutionError(
482
+ VELLUM_MANAGED_CONNECTION_NAME,
483
+ "adapter_unavailable",
484
+ err.message,
485
+ { cause: err, model },
486
+ );
487
+ }
460
488
  log.warn({ err }, "Platform fallback auth resolution failed transiently");
461
489
  return null;
462
490
  }
@@ -0,0 +1,82 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import {
4
+ clampProviderString,
5
+ exceedsProviderStringCap,
6
+ extractedTextForFileBlock,
7
+ isDecodableTextMimeType,
8
+ isVideoMimeType,
9
+ keepFileAsWorkspaceRef,
10
+ MAX_PROVIDER_STRING_BYTES,
11
+ PROVIDER_STRING_OMITTED_NOTE,
12
+ utf8ByteLength,
13
+ } from "./content-block-size.js";
14
+
15
+ describe("content-block-size", () => {
16
+ test("counts UTF-8 bytes, not JS string length", () => {
17
+ expect(utf8ByteLength("é")).toBe(2);
18
+ expect(exceedsProviderStringCap("é".repeat(4), 7)).toBe(true);
19
+ expect(exceedsProviderStringCap("é".repeat(3), 7)).toBe(false);
20
+ });
21
+
22
+ test("default cap is under OpenAI's 10 MiB per-part limit", () => {
23
+ expect(MAX_PROVIDER_STRING_BYTES).toBe(8_000_000);
24
+ expect(MAX_PROVIDER_STRING_BYTES).toBeLessThan(10_485_760);
25
+ });
26
+
27
+ test("treats video MIME types, including parameters, as video", () => {
28
+ expect(isVideoMimeType("video/mp4")).toBe(true);
29
+ expect(isVideoMimeType("VIDEO/WEBM; codecs=vp9")).toBe(true);
30
+ expect(isVideoMimeType("application/pdf")).toBe(false);
31
+ });
32
+
33
+ test("drops extracted_text for video and for over-cap extracts", () => {
34
+ expect(
35
+ extractedTextForFileBlock("video/mp4", "anything at all"),
36
+ ).toBeUndefined();
37
+ expect(extractedTextForFileBlock("application/pdf", "hello")).toBe("hello");
38
+ expect(
39
+ extractedTextForFileBlock("text/plain", "abcdef", 4),
40
+ ).toBeUndefined();
41
+ });
42
+
43
+ test("clampProviderString replaces an over-cap string", () => {
44
+ expect(clampProviderString("ok")).toBe("ok");
45
+ expect(clampProviderString("abcdef", 4)).toBe(PROVIDER_STRING_OMITTED_NOTE);
46
+ });
47
+
48
+ test("keepFileAsWorkspaceRef covers video and over-cap text refs", () => {
49
+ expect(isDecodableTextMimeType("text/plain")).toBe(true);
50
+ expect(isDecodableTextMimeType("application/json")).toBe(true);
51
+ expect(isDecodableTextMimeType("application/pdf")).toBe(false);
52
+
53
+ expect(
54
+ keepFileAsWorkspaceRef({
55
+ type: "workspace_ref",
56
+ media_type: "video/mp4",
57
+ sizeBytes: 12,
58
+ }),
59
+ ).toBe(true);
60
+ expect(
61
+ keepFileAsWorkspaceRef({
62
+ type: "workspace_ref",
63
+ media_type: "text/plain",
64
+ sizeBytes: MAX_PROVIDER_STRING_BYTES + 1,
65
+ }),
66
+ ).toBe(true);
67
+ expect(
68
+ keepFileAsWorkspaceRef({
69
+ type: "workspace_ref",
70
+ media_type: "text/plain",
71
+ sizeBytes: 20,
72
+ }),
73
+ ).toBe(false);
74
+ expect(
75
+ keepFileAsWorkspaceRef({
76
+ type: "workspace_ref",
77
+ media_type: "application/pdf",
78
+ sizeBytes: MAX_PROVIDER_STRING_BYTES + 1,
79
+ }),
80
+ ).toBe(false);
81
+ });
82
+ });
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Provider per-string size cap and helpers for content that would be
3
+ * serialized as a single text part.
4
+ *
5
+ * OpenAI rejects a request when any `content[].text` / `input[].content[].text`
6
+ * exceeds 10_485_760 bytes (`string_above_max_length`). Stay under that so a
7
+ * single block cannot brick every later turn. Extra SQLite-only columns and
8
+ * attachment bytes are out of scope: this is the wire-string budget.
9
+ */
10
+
11
+ /** Bytes. Under OpenAI's 10 MiB per-part string limit (10_485_760). */
12
+ export const MAX_PROVIDER_STRING_BYTES = 8_000_000;
13
+
14
+ export function utf8ByteLength(text: string): number {
15
+ return Buffer.byteLength(text, "utf8");
16
+ }
17
+
18
+ export function exceedsProviderStringCap(
19
+ text: string,
20
+ maxBytes: number = MAX_PROVIDER_STRING_BYTES,
21
+ ): boolean {
22
+ return utf8ByteLength(text) > maxBytes;
23
+ }
24
+
25
+ export function isVideoMimeType(mimeType: string): boolean {
26
+ const normalised = mimeType.toLowerCase().trim().split(";")[0]?.trim() ?? "";
27
+ return normalised.startsWith("video/");
28
+ }
29
+
30
+ /**
31
+ * MIME types a serializer would decode into a provider text/document string.
32
+ * Binary types (PDF, images, audio) stay out of this set: they are not the
33
+ * OpenAI `string_above_max_length` failure mode.
34
+ */
35
+ export function isDecodableTextMimeType(mimeType: string): boolean {
36
+ const normalised = mimeType.toLowerCase().trim().split(";")[0]?.trim() ?? "";
37
+ return (
38
+ normalised.startsWith("text/") ||
39
+ normalised === "application/json" ||
40
+ normalised === "application/xml" ||
41
+ normalised === "application/javascript"
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Video and over-cap text files stay on disk. Serializers name the workspace
47
+ * file; they must not load bytes or emit a decoded dump.
48
+ */
49
+ export function keepFileAsWorkspaceRef(source: {
50
+ type: string;
51
+ media_type: string;
52
+ sizeBytes?: number;
53
+ }): boolean {
54
+ if (isVideoMimeType(source.media_type)) {
55
+ return true;
56
+ }
57
+ return (
58
+ source.type === "workspace_ref" &&
59
+ source.sizeBytes !== undefined &&
60
+ source.sizeBytes > MAX_PROVIDER_STRING_BYTES &&
61
+ isDecodableTextMimeType(source.media_type)
62
+ );
63
+ }
64
+
65
+ /**
66
+ * Drop `extracted_text` that must not ride a file block into the provider
67
+ * prompt: video is a workspace file, not a transcript dump, and any extract
68
+ * over the cap belongs in the attachment store rather than the request.
69
+ */
70
+ export function extractedTextForFileBlock(
71
+ mimeType: string,
72
+ extractedText: string | undefined,
73
+ maxBytes: number = MAX_PROVIDER_STRING_BYTES,
74
+ ): string | undefined {
75
+ if (extractedText === undefined || extractedText.length === 0) {
76
+ return undefined;
77
+ }
78
+ if (isVideoMimeType(mimeType)) {
79
+ return undefined;
80
+ }
81
+ if (exceedsProviderStringCap(extractedText, maxBytes)) {
82
+ return undefined;
83
+ }
84
+ return extractedText;
85
+ }
86
+
87
+ /** Fallback copy when a serializer still sees a string over the cap. */
88
+ export const PROVIDER_STRING_OMITTED_NOTE =
89
+ "Content exceeded the provider size limit and was omitted from this prompt.";
90
+
91
+ export function clampProviderString(
92
+ text: string,
93
+ maxBytes: number = MAX_PROVIDER_STRING_BYTES,
94
+ ): string {
95
+ if (!exceedsProviderStringCap(text, maxBytes)) {
96
+ return text;
97
+ }
98
+ return PROVIDER_STRING_OMITTED_NOTE;
99
+ }
@@ -0,0 +1,64 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { PROVIDER_STRING_OMITTED_NOTE } from "./content-block-size.js";
4
+ import { fileBlockToProviderText } from "./file-block-text.js";
5
+ import type { ContentBlock } from "./types.js";
6
+
7
+ function fileBlock(
8
+ mediaType: string,
9
+ extractedText?: string,
10
+ ): Extract<ContentBlock, { type: "file" }> {
11
+ return {
12
+ type: "file",
13
+ source: {
14
+ type: "workspace_ref",
15
+ media_type: mediaType,
16
+ attachmentId: "att-1",
17
+ sizeBytes: 12,
18
+ filename: "clip.mp4",
19
+ },
20
+ ...(extractedText !== undefined ? { extracted_text: extractedText } : {}),
21
+ };
22
+ }
23
+
24
+ describe("fileBlockToProviderText", () => {
25
+ test("names a video without dumping extracted_text", () => {
26
+ const text = fileBlockToProviderText(
27
+ fileBlock("video/mp4", "a".repeat(1000)),
28
+ );
29
+ expect(text).toContain("video/mp4");
30
+ expect(text).toContain("workspace file");
31
+ expect(text).not.toContain("aaa");
32
+ });
33
+
34
+ test("includes extracted_text for a non-video file under the cap", () => {
35
+ const text = fileBlockToProviderText({
36
+ type: "file",
37
+ source: {
38
+ type: "workspace_ref",
39
+ media_type: "application/pdf",
40
+ attachmentId: "att-2",
41
+ sizeBytes: 20,
42
+ filename: "notes.pdf",
43
+ },
44
+ extracted_text: "quarterly summary",
45
+ });
46
+ expect(text).toContain("quarterly summary");
47
+ });
48
+
49
+ test("omits an over-cap extracted_text dump", () => {
50
+ const text = fileBlockToProviderText({
51
+ type: "file",
52
+ source: {
53
+ type: "workspace_ref",
54
+ media_type: "text/plain",
55
+ attachmentId: "att-3",
56
+ sizeBytes: 20,
57
+ filename: "huge.txt",
58
+ },
59
+ extracted_text: "x".repeat(8_000_001),
60
+ });
61
+ expect(text).toBe(PROVIDER_STRING_OMITTED_NOTE);
62
+ expect(text.length).toBeLessThan(200);
63
+ });
64
+ });
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Shared file-block → provider text. OpenAI, Anthropic, and Gemini all fold
3
+ * non-native files into a text part. Video is never inlined: it stays a
4
+ * workspace file and the prompt only names it.
5
+ */
6
+
7
+ import { escapeXmlAttr } from "../util/xml.js";
8
+ import { clampProviderString, isVideoMimeType } from "./content-block-size.js";
9
+ import type { ContentBlock } from "./types.js";
10
+
11
+ const VIDEO_FILE_NOTE =
12
+ "Video is stored as a workspace file. It is not inlined in this prompt.";
13
+
14
+ export function fileBlockToProviderText(
15
+ block: Extract<ContentBlock, { type: "file" }>,
16
+ ): string {
17
+ const header = `<attached_file name="${escapeXmlAttr(
18
+ block.source.filename ?? "",
19
+ )}" type="${escapeXmlAttr(block.source.media_type)}" />`;
20
+ if (isVideoMimeType(block.source.media_type)) {
21
+ return `${header}\n${VIDEO_FILE_NOTE}`;
22
+ }
23
+ const extracted = block.extracted_text?.trim() ?? "";
24
+ if (extracted.length > 0) {
25
+ return clampProviderString(`${header}\n${extracted}`);
26
+ }
27
+ return `${header}\nNo extracted text available.`;
28
+ }
@@ -10,6 +10,11 @@ import { isAbortReason } from "../../util/abort-reasons.js";
10
10
  import { ProviderError, type ProviderErrorReason } from "../../util/errors.js";
11
11
  import { getLogger } from "../../util/logger.js";
12
12
  import { DAILY_LIMIT_PATTERNS } from "../../util/provider-error-patterns.js";
13
+ import {
14
+ clampProviderString,
15
+ keepFileAsWorkspaceRef,
16
+ } from "../content-block-size.js";
17
+ import { fileBlockToProviderText } from "../file-block-text.js";
13
18
  import { base64Source, resolveMediaReferences } from "../media-resolve.js";
14
19
  import { PROVIDER_CATALOG } from "../model-catalog.js";
15
20
  import { recordProviderRequestDiagnostics } from "../request-diagnostics.js";
@@ -429,8 +434,7 @@ export class GeminiProvider implements Provider {
429
434
  const maxTokens = configObj?.max_tokens as number | undefined;
430
435
  const modelOverride = configObj?.model as string | undefined;
431
436
  const usageAttributionHeaders = configObj?.usageAttributionHeaders as
432
- | Record<string, string>
433
- | undefined;
437
+ Record<string, string> | undefined;
434
438
  const activeModel = modelOverride ?? this.model;
435
439
  const thinkingConfig = geminiModelSupportsThinking(activeModel)
436
440
  ? buildThinkingConfig(
@@ -762,7 +766,7 @@ export class GeminiProvider implements Provider {
762
766
  for (const block of blocks) {
763
767
  switch (block.type) {
764
768
  case "text":
765
- parts.push({ text: block.text });
769
+ parts.push({ text: clampProviderString(block.text) });
766
770
  break;
767
771
  case "image": {
768
772
  const imageSrc = base64Source(block.source);
@@ -775,6 +779,10 @@ export class GeminiProvider implements Provider {
775
779
  break;
776
780
  }
777
781
  case "file": {
782
+ if (keepFileAsWorkspaceRef(block.source)) {
783
+ parts.push({ text: fileBlockToProviderText(block) });
784
+ break;
785
+ }
778
786
  const fileSrc = base64Source(block.source);
779
787
  if (this.supportsGeminiInlineFile(fileSrc.media_type)) {
780
788
  // Normalize audio MIME onto Gemini's spelling (e.g. audio/mpeg →
@@ -797,10 +805,7 @@ export class GeminiProvider implements Provider {
797
805
  });
798
806
  }
799
807
  } else {
800
- const fallback = block.extracted_text?.trim()
801
- ? `[Attached file: ${fileSrc.filename} (${fileSrc.media_type})]\n${block.extracted_text}`
802
- : `[Attached file: ${fileSrc.filename} (${fileSrc.media_type})]\nNo extracted text available.`;
803
- parts.push({ text: fallback });
808
+ parts.push({ text: fileBlockToProviderText(block) });
804
809
  }
805
810
  break;
806
811
  }
@@ -144,12 +144,12 @@ export type ConnectionProvider = string;
144
144
  export const CHATGPT_SUBSCRIPTION_CONNECTION_NAME = "chatgpt-subscription";
145
145
 
146
146
  /**
147
- * Provider values that are routing identities rather than adapters: the
148
- * value names HOW a request routes (vellum = the platform-managed route,
149
- * chatgpt = the subscription route), and dispatch translates it to a real
150
- * upstream + connection row per-request (resolveRoutingIdentity). Identity
151
- * profiles carry no provider_connection; backfill and materialization must
152
- * not stamp one.
147
+ * Provider values that name a routing identity. Dispatch translates them
148
+ * to a connection row and an upstream factory id via
149
+ * `resolveRoutingIdentity`. `chatgpt` has no adapter factory (upstream is
150
+ * always openai). `vellum` is also a catalog factory id when the derived
151
+ * upstream is vellum. Identity profiles carry no provider_connection;
152
+ * backfill and materialization must not stamp one.
153
153
  */
154
154
  export const ROUTING_IDENTITY_PROVIDERS: ReadonlySet<string> = new Set([
155
155
  "vellum",
@@ -28,6 +28,7 @@ import {
28
28
  sniffImageMimeType,
29
29
  } from "../util/image-conversion.js";
30
30
  import { getLogger } from "../util/logger.js";
31
+ import { keepFileAsWorkspaceRef } from "./content-block-size.js";
31
32
  import {
32
33
  attachmentIdFragment,
33
34
  type Base64MediaSource,
@@ -265,6 +266,16 @@ async function resolveImageBlock(
265
266
  }
266
267
 
267
268
  function resolveFileBlock(block: FileContent): ContentBlock {
269
+ // Video and over-cap text stay a workspace file. Do not load bytes or
270
+ // carry extracted_text into the provider prompt: serializers name the
271
+ // file and stop there.
272
+ if (keepFileAsWorkspaceRef(block.source)) {
273
+ if (block.extracted_text === undefined) {
274
+ return block;
275
+ }
276
+ const { extracted_text: _extracted, ...rest } = block;
277
+ return rest;
278
+ }
268
279
  if (block.source.type === "base64") {
269
280
  return block;
270
281
  }
@@ -356,6 +367,9 @@ function contentNeedsResolution(
356
367
  : base64ImageNeedsRewrite(block.source, options);
357
368
  }
358
369
  if (block.type === "file") {
370
+ if (keepFileAsWorkspaceRef(block.source)) {
371
+ return block.extracted_text !== undefined;
372
+ }
359
373
  return block.source.type === "workspace_ref";
360
374
  }
361
375
  if (block.type === "tool_result" && block.contentBlocks?.length) {
@@ -928,23 +928,6 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
928
928
  cacheReadPer1mTokens: 0.16,
929
929
  },
930
930
  },
931
- {
932
- id: "accounts/fireworks/models/glm-5p2",
933
- displayName: "GLM 5.2",
934
- // Fireworks serves GLM 5.2 with a 1,040K input window.
935
- contextWindowTokens: 1040000,
936
- maxOutputTokens: 131072,
937
- supportsThinking: true,
938
- supportsCaching: true,
939
- supportsVision: false,
940
- supportsToolUse: true,
941
- maxEffort: "max",
942
- pricing: {
943
- inputPer1mTokens: 1.4,
944
- outputPer1mTokens: 4.4,
945
- cacheReadPer1mTokens: 0.26,
946
- },
947
- },
948
931
  {
949
932
  id: "accounts/fireworks/models/glm-5p3",
950
933
  displayName: "GLM 5.3",
@@ -984,6 +967,23 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
984
967
  cacheReadPer1mTokens: 0.029,
985
968
  },
986
969
  },
970
+ {
971
+ id: "accounts/fireworks/models/glm-5p2",
972
+ displayName: "GLM 5.2",
973
+ // Fireworks serves GLM 5.2 with a 1,040K input window.
974
+ contextWindowTokens: 1040000,
975
+ maxOutputTokens: 131072,
976
+ supportsThinking: true,
977
+ supportsCaching: true,
978
+ supportsVision: false,
979
+ supportsToolUse: true,
980
+ maxEffort: "max",
981
+ pricing: {
982
+ inputPer1mTokens: 1.4,
983
+ outputPer1mTokens: 4.4,
984
+ cacheReadPer1mTokens: 0.26,
985
+ },
986
+ },
987
987
  // Kimi K2.5 (accounts/fireworks/models/kimi-k2p5) is intentionally
988
988
  // absent: Fireworks serves it on-demand/dedicated only, so serverless
989
989
  // chat/completions calls 404 ("not found, inaccessible, and/or not
@@ -1006,28 +1006,25 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
1006
1006
  cacheReadPer1mTokens: 0.06,
1007
1007
  },
1008
1008
  },
1009
+ // MiniMax M2.7 (accounts/fireworks/models/minimax-m2p7) is
1010
+ // intentionally absent: Fireworks has no serverless deployment for
1011
+ // it (the model page claims serverless support, but the serving API
1012
+ // returns 404).
1009
1013
  {
1010
- id: "accounts/fireworks/models/minimax-m2p7",
1011
- displayName: "MiniMax M2.7",
1012
- contextWindowTokens: 196608,
1013
- maxOutputTokens: 25000,
1014
- supportsThinking: false,
1015
- supportsCaching: false,
1016
- supportsVision: false,
1017
- supportsToolUse: true,
1018
- pricing: { inputPer1mTokens: 0.3, outputPer1mTokens: 1.2 },
1019
- },
1020
- {
1021
- id: "accounts/fireworks/models/deepseek-v4-pro",
1014
+ id: "accounts/fireworks/models/deepseek-v4-pro-0813",
1022
1015
  displayName: "DeepSeek V4 Pro",
1023
1016
  contextWindowTokens: 1040000,
1024
1017
  maxOutputTokens: 131072,
1025
1018
  supportsThinking: true,
1026
- supportsCaching: false,
1019
+ supportsCaching: true,
1027
1020
  supportsVision: false,
1028
1021
  supportsToolUse: true,
1029
1022
  maxEffort: "max",
1030
- pricing: { inputPer1mTokens: 1.74, outputPer1mTokens: 3.48 },
1023
+ pricing: {
1024
+ inputPer1mTokens: 1.32,
1025
+ outputPer1mTokens: 3.96,
1026
+ cacheReadPer1mTokens: 0.044,
1027
+ },
1031
1028
  },
1032
1029
  {
1033
1030
  id: "accounts/fireworks/models/deepseek-v4-flash-0731",
@@ -1834,7 +1831,7 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
1834
1831
  // Z.ai
1835
1832
  {
1836
1833
  id: "z-ai/glm-5.3",
1837
- displayName: "GLM-5.3",
1834
+ displayName: "GLM 5.3",
1838
1835
  contextWindowTokens: 1048576,
1839
1836
  maxOutputTokens: 131072,
1840
1837
  supportsThinking: true,
@@ -1849,7 +1846,7 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
1849
1846
  },
1850
1847
  {
1851
1848
  id: "z-ai/glm-5.3-flash",
1852
- displayName: "GLM-5.3 Flash",
1849
+ displayName: "GLM 5.3 Flash",
1853
1850
  contextWindowTokens: 1310720,
1854
1851
  maxOutputTokens: 131072,
1855
1852
  supportsThinking: true,
@@ -1864,7 +1861,7 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
1864
1861
  },
1865
1862
  {
1866
1863
  id: "z-ai/glm-5.2",
1867
- displayName: "GLM-5.2",
1864
+ displayName: "GLM 5.2",
1868
1865
  contextWindowTokens: 1048576,
1869
1866
  maxOutputTokens: 131072,
1870
1867
  supportsThinking: true,