@linxiraos/pi-ai 1.0.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 (639) hide show
  1. package/CHANGELOG.md +5066 -0
  2. package/README.md +1195 -0
  3. package/dist/types/api-registry.d.ts +30 -0
  4. package/dist/types/auth/sqlite-credential-store.d.ts +117 -0
  5. package/dist/types/auth-broker/client.d.ts +93 -0
  6. package/dist/types/auth-broker/discover.d.ts +39 -0
  7. package/dist/types/auth-broker/index.d.ts +7 -0
  8. package/dist/types/auth-broker/refresher.d.ts +25 -0
  9. package/dist/types/auth-broker/remote-store.d.ts +136 -0
  10. package/dist/types/auth-broker/server.d.ts +48 -0
  11. package/dist/types/auth-broker/snapshot-cache.d.ts +17 -0
  12. package/dist/types/auth-broker/types.d.ts +152 -0
  13. package/dist/types/auth-broker/wire-schema-resource.d.ts +53 -0
  14. package/dist/types/auth-broker/wire-schemas.d.ts +5 -0
  15. package/dist/types/auth-gateway/http.d.ts +56 -0
  16. package/dist/types/auth-gateway/index.d.ts +3 -0
  17. package/dist/types/auth-gateway/server.d.ts +36 -0
  18. package/dist/types/auth-gateway/types.d.ts +127 -0
  19. package/dist/types/auth-retry.d.ts +150 -0
  20. package/dist/types/auth-storage.d.ts +1258 -0
  21. package/dist/types/dialect/anthropic.d.ts +15 -0
  22. package/dist/types/dialect/catalog.d.ts +3 -0
  23. package/dist/types/dialect/coercion.d.ts +23 -0
  24. package/dist/types/dialect/deepseek.d.ts +14 -0
  25. package/dist/types/dialect/demotion.d.ts +30 -0
  26. package/dist/types/dialect/examples.d.ts +18 -0
  27. package/dist/types/dialect/factory.d.ts +3 -0
  28. package/dist/types/dialect/fenced-thinking.d.ts +53 -0
  29. package/dist/types/dialect/gemini.d.ts +17 -0
  30. package/dist/types/dialect/gemma.d.ts +15 -0
  31. package/dist/types/dialect/glm.d.ts +9 -0
  32. package/dist/types/dialect/harmony.d.ts +8 -0
  33. package/dist/types/dialect/hermes.d.ts +9 -0
  34. package/dist/types/dialect/history.d.ts +3 -0
  35. package/dist/types/dialect/index.d.ts +11 -0
  36. package/dist/types/dialect/inventory.d.ts +9 -0
  37. package/dist/types/dialect/kimi.d.ts +14 -0
  38. package/dist/types/dialect/minimax.d.ts +3 -0
  39. package/dist/types/dialect/owned-stream.d.ts +4 -0
  40. package/dist/types/dialect/qwen3.d.ts +9 -0
  41. package/dist/types/dialect/rendering.d.ts +54 -0
  42. package/dist/types/dialect/thinking.d.ts +6 -0
  43. package/dist/types/dialect/types.d.ts +68 -0
  44. package/dist/types/dialect/xml.d.ts +9 -0
  45. package/dist/types/error/abort.d.ts +14 -0
  46. package/dist/types/error/auth-classify.d.ts +20 -0
  47. package/dist/types/error/auth.d.ts +27 -0
  48. package/dist/types/error/aws.d.ts +27 -0
  49. package/dist/types/error/classes.d.ts +106 -0
  50. package/dist/types/error/finalize.d.ts +39 -0
  51. package/dist/types/error/flags.d.ts +94 -0
  52. package/dist/types/error/format.d.ts +20 -0
  53. package/dist/types/error/gateway.d.ts +20 -0
  54. package/dist/types/error/index.d.ts +14 -0
  55. package/dist/types/error/oauth.d.ts +43 -0
  56. package/dist/types/error/provider.d.ts +42 -0
  57. package/dist/types/error/rate-limit.d.ts +80 -0
  58. package/dist/types/error/retryable.d.ts +27 -0
  59. package/dist/types/error/validation.d.ts +32 -0
  60. package/dist/types/index.d.ts +51 -0
  61. package/dist/types/provider-details.d.ts +24 -0
  62. package/dist/types/providers/amazon-bedrock.d.ts +39 -0
  63. package/dist/types/providers/anthropic-client.d.ts +106 -0
  64. package/dist/types/providers/anthropic-messages-server-schema.d.ts +937 -0
  65. package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
  66. package/dist/types/providers/anthropic-wire.d.ts +345 -0
  67. package/dist/types/providers/anthropic.d.ts +261 -0
  68. package/dist/types/providers/aws-credentials.d.ts +48 -0
  69. package/dist/types/providers/aws-eventstream.d.ts +39 -0
  70. package/dist/types/providers/aws-sigv4.d.ts +55 -0
  71. package/dist/types/providers/azure-openai-responses.d.ts +16 -0
  72. package/dist/types/providers/bedrock-mantle.d.ts +13 -0
  73. package/dist/types/providers/claude-code-fingerprint.d.ts +19 -0
  74. package/dist/types/providers/cowork-fetch.d.ts +3 -0
  75. package/dist/types/providers/cursor/exec-modern.d.ts +98 -0
  76. package/dist/types/providers/cursor-pi-args.d.ts +105 -0
  77. package/dist/types/providers/cursor.d.ts +221 -0
  78. package/dist/types/providers/devin.d.ts +12 -0
  79. package/dist/types/providers/error-message.d.ts +25 -0
  80. package/dist/types/providers/github-copilot-headers.d.ts +40 -0
  81. package/dist/types/providers/gitlab-duo-workflow.d.ts +254 -0
  82. package/dist/types/providers/gitlab-duo.d.ts +27 -0
  83. package/dist/types/providers/google-auth.d.ts +24 -0
  84. package/dist/types/providers/google-gemini-cli.d.ts +120 -0
  85. package/dist/types/providers/google-shared.d.ts +203 -0
  86. package/dist/types/providers/google-types.d.ts +155 -0
  87. package/dist/types/providers/google-vertex.d.ts +7 -0
  88. package/dist/types/providers/google.d.ts +4 -0
  89. package/dist/types/providers/grammar.d.ts +1 -0
  90. package/dist/types/providers/kimi.d.ts +27 -0
  91. package/dist/types/providers/mock.d.ts +179 -0
  92. package/dist/types/providers/ollama.d.ts +8 -0
  93. package/dist/types/providers/openai-anthropic-shim.d.ts +35 -0
  94. package/dist/types/providers/openai-chat-server-schema.d.ts +1311 -0
  95. package/dist/types/providers/openai-chat-server.d.ts +16 -0
  96. package/dist/types/providers/openai-chat-wire.d.ts +669 -0
  97. package/dist/types/providers/openai-codex/request-transformer.d.ts +109 -0
  98. package/dist/types/providers/openai-codex/response-handler.d.ts +26 -0
  99. package/dist/types/providers/openai-codex-responses.d.ts +238 -0
  100. package/dist/types/providers/openai-completions.d.ts +48 -0
  101. package/dist/types/providers/openai-reasoning-fallback.d.ts +25 -0
  102. package/dist/types/providers/openai-responses-server-schema.d.ts +1314 -0
  103. package/dist/types/providers/openai-responses-server.d.ts +17 -0
  104. package/dist/types/providers/openai-responses-wire.d.ts +6099 -0
  105. package/dist/types/providers/openai-responses.d.ts +131 -0
  106. package/dist/types/providers/openai-shared.d.ts +624 -0
  107. package/dist/types/providers/pi-native-client.d.ts +13 -0
  108. package/dist/types/providers/pi-native-server.d.ts +69 -0
  109. package/dist/types/providers/register-builtins.d.ts +37 -0
  110. package/dist/types/providers/synthetic.d.ts +26 -0
  111. package/dist/types/providers/transform-messages.d.ts +32 -0
  112. package/dist/types/providers/vision-guard.d.ts +20 -0
  113. package/dist/types/registry/aiand.d.ts +7 -0
  114. package/dist/types/registry/aimlapi.d.ts +4 -0
  115. package/dist/types/registry/alibaba-coding-plan.d.ts +8 -0
  116. package/dist/types/registry/alibaba-token-plan.d.ts +18 -0
  117. package/dist/types/registry/amazon-bedrock.d.ts +5 -0
  118. package/dist/types/registry/anthropic.d.ts +10 -0
  119. package/dist/types/registry/api-key-login.d.ts +42 -0
  120. package/dist/types/registry/api-key-validation.d.ts +43 -0
  121. package/dist/types/registry/aws.d.ts +13 -0
  122. package/dist/types/registry/azure.d.ts +4 -0
  123. package/dist/types/registry/baseten.d.ts +7 -0
  124. package/dist/types/registry/bedrock-mantle.d.ts +22 -0
  125. package/dist/types/registry/cerebras.d.ts +7 -0
  126. package/dist/types/registry/cloudflare-ai-gateway.d.ts +13 -0
  127. package/dist/types/registry/coreweave.d.ts +7 -0
  128. package/dist/types/registry/cursor.d.ts +7 -0
  129. package/dist/types/registry/deepseek.d.ts +8 -0
  130. package/dist/types/registry/derived.d.ts +5 -0
  131. package/dist/types/registry/devin.d.ts +8 -0
  132. package/dist/types/registry/exa.d.ts +8 -0
  133. package/dist/types/registry/firepass.d.ts +16 -0
  134. package/dist/types/registry/fireworks.d.ts +7 -0
  135. package/dist/types/registry/github-copilot.d.ts +7 -0
  136. package/dist/types/registry/gitlab-duo-workflow.d.ts +10 -0
  137. package/dist/types/registry/gitlab-duo.d.ts +9 -0
  138. package/dist/types/registry/gmi-cloud.d.ts +7 -0
  139. package/dist/types/registry/google-antigravity.d.ts +9 -0
  140. package/dist/types/registry/google-gemini-cli.d.ts +9 -0
  141. package/dist/types/registry/google-vertex.d.ts +5 -0
  142. package/dist/types/registry/google.d.ts +4 -0
  143. package/dist/types/registry/groq.d.ts +4 -0
  144. package/dist/types/registry/huggingface.d.ts +7 -0
  145. package/dist/types/registry/index.d.ts +4 -0
  146. package/dist/types/registry/kagi.d.ts +14 -0
  147. package/dist/types/registry/kilo.d.ts +7 -0
  148. package/dist/types/registry/kimi-code.d.ts +7 -0
  149. package/dist/types/registry/litellm.d.ts +13 -0
  150. package/dist/types/registry/llama-cpp.d.ts +8 -0
  151. package/dist/types/registry/lm-studio.d.ts +8 -0
  152. package/dist/types/registry/meta.d.ts +7 -0
  153. package/dist/types/registry/minimax-code-cn.d.ts +6 -0
  154. package/dist/types/registry/minimax-code.d.ts +6 -0
  155. package/dist/types/registry/minimax.d.ts +4 -0
  156. package/dist/types/registry/mistral.d.ts +4 -0
  157. package/dist/types/registry/moonshot.d.ts +7 -0
  158. package/dist/types/registry/nanogpt.d.ts +7 -0
  159. package/dist/types/registry/novita.d.ts +6 -0
  160. package/dist/types/registry/nvidia.d.ts +7 -0
  161. package/dist/types/registry/oauth/anthropic-constants.d.ts +12 -0
  162. package/dist/types/registry/oauth/anthropic.d.ts +24 -0
  163. package/dist/types/registry/oauth/callback-server.d.ts +74 -0
  164. package/dist/types/registry/oauth/cursor.d.ts +16 -0
  165. package/dist/types/registry/oauth/device-code.d.ts +25 -0
  166. package/dist/types/registry/oauth/devin.d.ts +5 -0
  167. package/dist/types/registry/oauth/github-copilot.d.ts +30 -0
  168. package/dist/types/registry/oauth/gitlab-duo-workflow.d.ts +6 -0
  169. package/dist/types/registry/oauth/gitlab-duo.d.ts +3 -0
  170. package/dist/types/registry/oauth/google-antigravity.d.ts +11 -0
  171. package/dist/types/registry/oauth/google-gemini-cli.d.ts +22 -0
  172. package/dist/types/registry/oauth/google-oauth-shared.d.ts +56 -0
  173. package/dist/types/registry/oauth/index.d.ts +45 -0
  174. package/dist/types/registry/oauth/kimi.d.ts +21 -0
  175. package/dist/types/registry/oauth/minimax-code.d.ts +27 -0
  176. package/dist/types/registry/oauth/openai-codex.d.ts +33 -0
  177. package/dist/types/registry/oauth/opencode.d.ts +18 -0
  178. package/dist/types/registry/oauth/perplexity.d.ts +9 -0
  179. package/dist/types/registry/oauth/pkce.d.ts +8 -0
  180. package/dist/types/registry/oauth/types.d.ts +87 -0
  181. package/dist/types/registry/oauth/wafer.d.ts +1 -0
  182. package/dist/types/registry/oauth/xai-oauth.d.ts +46 -0
  183. package/dist/types/registry/oauth/xiaomi.d.ts +25 -0
  184. package/dist/types/registry/oauth/zai.d.ts +25 -0
  185. package/dist/types/registry/ollama-cloud.d.ts +7 -0
  186. package/dist/types/registry/ollama.d.ts +12 -0
  187. package/dist/types/registry/openai-codex-device.d.ts +8 -0
  188. package/dist/types/registry/openai-codex.d.ts +9 -0
  189. package/dist/types/registry/openai.d.ts +4 -0
  190. package/dist/types/registry/opencode-go.d.ts +6 -0
  191. package/dist/types/registry/opencode-zen.d.ts +6 -0
  192. package/dist/types/registry/openrouter.d.ts +13 -0
  193. package/dist/types/registry/parallel.d.ts +14 -0
  194. package/dist/types/registry/perplexity.d.ts +7 -0
  195. package/dist/types/registry/qianfan.d.ts +7 -0
  196. package/dist/types/registry/qwen-portal.d.ts +7 -0
  197. package/dist/types/registry/registry.d.ts +367 -0
  198. package/dist/types/registry/sakana.d.ts +7 -0
  199. package/dist/types/registry/siliconflow-cn.d.ts +7 -0
  200. package/dist/types/registry/siliconflow.d.ts +7 -0
  201. package/dist/types/registry/synthetic.d.ts +6 -0
  202. package/dist/types/registry/tavily.d.ts +14 -0
  203. package/dist/types/registry/together.d.ts +6 -0
  204. package/dist/types/registry/types.d.ts +75 -0
  205. package/dist/types/registry/umans.d.ts +7 -0
  206. package/dist/types/registry/venice.d.ts +13 -0
  207. package/dist/types/registry/vercel-ai-gateway.d.ts +7 -0
  208. package/dist/types/registry/vllm.d.ts +7 -0
  209. package/dist/types/registry/wafer-serverless.d.ts +6 -0
  210. package/dist/types/registry/xai-oauth.d.ts +7 -0
  211. package/dist/types/registry/xai.d.ts +7 -0
  212. package/dist/types/registry/xiaomi-token-plan-ams.d.ts +6 -0
  213. package/dist/types/registry/xiaomi-token-plan-cn.d.ts +6 -0
  214. package/dist/types/registry/xiaomi-token-plan-sgp.d.ts +6 -0
  215. package/dist/types/registry/xiaomi.d.ts +6 -0
  216. package/dist/types/registry/zai.d.ts +15 -0
  217. package/dist/types/registry/zenmux.d.ts +7 -0
  218. package/dist/types/registry/zhipu-coding-plan.d.ts +7 -0
  219. package/dist/types/stream.d.ts +46 -0
  220. package/dist/types/types.d.ts +1064 -0
  221. package/dist/types/usage/alibaba-token-plan.d.ts +3 -0
  222. package/dist/types/usage/claude.d.ts +4 -0
  223. package/dist/types/usage/cursor.d.ts +4 -0
  224. package/dist/types/usage/gemini.d.ts +2 -0
  225. package/dist/types/usage/github-copilot.d.ts +7 -0
  226. package/dist/types/usage/google-antigravity.d.ts +15 -0
  227. package/dist/types/usage/kimi.d.ts +2 -0
  228. package/dist/types/usage/minimax-code.d.ts +3 -0
  229. package/dist/types/usage/ollama.d.ts +5 -0
  230. package/dist/types/usage/openai-codex-base-url.d.ts +18 -0
  231. package/dist/types/usage/openai-codex-reset.d.ts +88 -0
  232. package/dist/types/usage/openai-codex.d.ts +10 -0
  233. package/dist/types/usage/opencode-go.d.ts +2 -0
  234. package/dist/types/usage/shared.d.ts +1 -0
  235. package/dist/types/usage/synthetic.d.ts +2 -0
  236. package/dist/types/usage/umans.d.ts +2 -0
  237. package/dist/types/usage/xai-oauth.d.ts +12 -0
  238. package/dist/types/usage/zai.d.ts +3 -0
  239. package/dist/types/usage.d.ts +527 -0
  240. package/dist/types/utils/abort.d.ts +25 -0
  241. package/dist/types/utils/anthropic-auth.d.ts +35 -0
  242. package/dist/types/utils/aws-profile.d.ts +17 -0
  243. package/dist/types/utils/block-symbols.d.ts +62 -0
  244. package/dist/types/utils/deterministic-id.d.ts +16 -0
  245. package/dist/types/utils/empty-completion-retry.d.ts +21 -0
  246. package/dist/types/utils/event-stream.d.ts +39 -0
  247. package/dist/types/utils/foundry.d.ts +1 -0
  248. package/dist/types/utils/google-validation.d.ts +2 -0
  249. package/dist/types/utils/harmony-leak.d.ts +135 -0
  250. package/dist/types/utils/http-inspector.d.ts +49 -0
  251. package/dist/types/utils/idle-iterator.d.ts +149 -0
  252. package/dist/types/utils/leaked-thinking-stream.d.ts +33 -0
  253. package/dist/types/utils/openai-http.d.ts +48 -0
  254. package/dist/types/utils/openrouter-headers.d.ts +1 -0
  255. package/dist/types/utils/parse-bind.d.ts +23 -0
  256. package/dist/types/utils/provider-response.d.ts +3 -0
  257. package/dist/types/utils/proxy.d.ts +39 -0
  258. package/dist/types/utils/request-debug.d.ts +29 -0
  259. package/dist/types/utils/retry-after.d.ts +4 -0
  260. package/dist/types/utils/retry.d.ts +14 -0
  261. package/dist/types/utils/schema/adapt.d.ts +24 -0
  262. package/dist/types/utils/schema/compatibility.d.ts +30 -0
  263. package/dist/types/utils/schema/dereference.d.ts +11 -0
  264. package/dist/types/utils/schema/draft.d.ts +10 -0
  265. package/dist/types/utils/schema/equality.d.ts +4 -0
  266. package/dist/types/utils/schema/fields.d.ts +54 -0
  267. package/dist/types/utils/schema/index.d.ts +14 -0
  268. package/dist/types/utils/schema/json-schema-validator.d.ts +20 -0
  269. package/dist/types/utils/schema/meta-validator.d.ts +2 -0
  270. package/dist/types/utils/schema/normalize.d.ts +153 -0
  271. package/dist/types/utils/schema/spill.d.ts +8 -0
  272. package/dist/types/utils/schema/stamps.d.ts +17 -0
  273. package/dist/types/utils/schema/strict-tool-validation.d.ts +16 -0
  274. package/dist/types/utils/schema/types.d.ts +4 -0
  275. package/dist/types/utils/schema/typescript.d.ts +24 -0
  276. package/dist/types/utils/schema/wire.d.ts +52 -0
  277. package/dist/types/utils/sdk-stream-timeout.d.ts +33 -0
  278. package/dist/types/utils/sse-debug.d.ts +5 -0
  279. package/dist/types/utils/stream-markup-healing.d.ts +87 -0
  280. package/dist/types/utils/thinking-loop.d.ts +102 -0
  281. package/dist/types/utils/tool-call-loop-guard.d.ts +26 -0
  282. package/dist/types/utils/tool-choice.d.ts +52 -0
  283. package/dist/types/utils/validation.d.ts +28 -0
  284. package/dist/types/utils.d.ts +57 -0
  285. package/package.json +138 -0
  286. package/src/api-registry.ts +109 -0
  287. package/src/auth/sqlite-credential-store.ts +2066 -0
  288. package/src/auth-broker/client.ts +471 -0
  289. package/src/auth-broker/discover.ts +310 -0
  290. package/src/auth-broker/index.ts +7 -0
  291. package/src/auth-broker/refresher.ts +117 -0
  292. package/src/auth-broker/remote-store.ts +1332 -0
  293. package/src/auth-broker/server.ts +898 -0
  294. package/src/auth-broker/snapshot-cache.ts +200 -0
  295. package/src/auth-broker/types.ts +193 -0
  296. package/src/auth-broker/wire-schema-resource.ts +487 -0
  297. package/src/auth-broker/wire-schemas.ts +43 -0
  298. package/src/auth-gateway/http.ts +227 -0
  299. package/src/auth-gateway/index.ts +3 -0
  300. package/src/auth-gateway/server.ts +836 -0
  301. package/src/auth-gateway/types.ts +153 -0
  302. package/src/auth-retry.ts +401 -0
  303. package/src/auth-storage.ts +6540 -0
  304. package/src/dialect/anthropic.md +31 -0
  305. package/src/dialect/anthropic.ts +608 -0
  306. package/src/dialect/catalog.ts +29 -0
  307. package/src/dialect/coercion.ts +136 -0
  308. package/src/dialect/deepseek.md +24 -0
  309. package/src/dialect/deepseek.ts +609 -0
  310. package/src/dialect/demotion.ts +40 -0
  311. package/src/dialect/examples.ts +71 -0
  312. package/src/dialect/factory.ts +34 -0
  313. package/src/dialect/fenced-thinking.ts +184 -0
  314. package/src/dialect/gemini.md +44 -0
  315. package/src/dialect/gemini.ts +583 -0
  316. package/src/dialect/gemma.md +33 -0
  317. package/src/dialect/gemma.ts +387 -0
  318. package/src/dialect/glm.md +32 -0
  319. package/src/dialect/glm.ts +579 -0
  320. package/src/dialect/harmony.md +31 -0
  321. package/src/dialect/harmony.ts +345 -0
  322. package/src/dialect/hermes.md +25 -0
  323. package/src/dialect/hermes.ts +206 -0
  324. package/src/dialect/history.ts +81 -0
  325. package/src/dialect/index.ts +15 -0
  326. package/src/dialect/inventory.ts +30 -0
  327. package/src/dialect/kimi.md +24 -0
  328. package/src/dialect/kimi.ts +340 -0
  329. package/src/dialect/minimax.md +31 -0
  330. package/src/dialect/minimax.ts +95 -0
  331. package/src/dialect/owned-stream.ts +481 -0
  332. package/src/dialect/prompt-template.md +12 -0
  333. package/src/dialect/qwen3.md +28 -0
  334. package/src/dialect/qwen3.ts +240 -0
  335. package/src/dialect/rendering.ts +304 -0
  336. package/src/dialect/thinking.ts +292 -0
  337. package/src/dialect/types.ts +56 -0
  338. package/src/dialect/xml.md +22 -0
  339. package/src/dialect/xml.ts +90 -0
  340. package/src/error/abort.ts +18 -0
  341. package/src/error/auth-classify.ts +47 -0
  342. package/src/error/auth.ts +48 -0
  343. package/src/error/aws.ts +35 -0
  344. package/src/error/classes.ts +281 -0
  345. package/src/error/finalize.ts +69 -0
  346. package/src/error/flags.ts +602 -0
  347. package/src/error/format.ts +45 -0
  348. package/src/error/gateway.ts +96 -0
  349. package/src/error/index.ts +14 -0
  350. package/src/error/oauth.ts +58 -0
  351. package/src/error/provider.ts +63 -0
  352. package/src/error/rate-limit.ts +303 -0
  353. package/src/error/retryable.ts +70 -0
  354. package/src/error/validation.ts +44 -0
  355. package/src/index.ts +51 -0
  356. package/src/provider-details.ts +90 -0
  357. package/src/providers/amazon-bedrock.ts +1064 -0
  358. package/src/providers/anthropic-client.ts +317 -0
  359. package/src/providers/anthropic-messages-server-schema.ts +252 -0
  360. package/src/providers/anthropic-messages-server.ts +818 -0
  361. package/src/providers/anthropic-wire.ts +359 -0
  362. package/src/providers/anthropic.ts +4539 -0
  363. package/src/providers/aws-credentials.ts +772 -0
  364. package/src/providers/aws-eventstream.ts +181 -0
  365. package/src/providers/aws-sigv4.ts +218 -0
  366. package/src/providers/azure-openai-responses.ts +438 -0
  367. package/src/providers/bedrock-mantle.ts +110 -0
  368. package/src/providers/claude-code-fingerprint.ts +20 -0
  369. package/src/providers/cowork-fetch.ts +201 -0
  370. package/src/providers/cursor/exec-modern.ts +496 -0
  371. package/src/providers/cursor/proto/agent.proto +4533 -0
  372. package/src/providers/cursor/proto/buf.gen.yaml +6 -0
  373. package/src/providers/cursor/proto/buf.yaml +17 -0
  374. package/src/providers/cursor-pi-args.ts +165 -0
  375. package/src/providers/cursor.ts +4689 -0
  376. package/src/providers/devin/proto/buf/validate/validate.proto +468 -0
  377. package/src/providers/devin/proto/buf.gen.yaml +33 -0
  378. package/src/providers/devin/proto/buf.yaml +17 -0
  379. package/src/providers/devin/proto/cel/expr/checked.proto +103 -0
  380. package/src/providers/devin/proto/cel/expr/eval.proto +38 -0
  381. package/src/providers/devin/proto/cel/expr/explain.proto +15 -0
  382. package/src/providers/devin/proto/cel/expr/syntax.proto +113 -0
  383. package/src/providers/devin/proto/cel/expr/value.proto +41 -0
  384. package/src/providers/devin/proto/connectext/grpc/status/v1/status.proto +11 -0
  385. package/src/providers/devin/proto/errorspb/errors.proto +56 -0
  386. package/src/providers/devin/proto/errorspb/hintdetail.proto +7 -0
  387. package/src/providers/devin/proto/errorspb/markers.proto +10 -0
  388. package/src/providers/devin/proto/errorspb/tags.proto +12 -0
  389. package/src/providers/devin/proto/errorspb/testing.proto +6 -0
  390. package/src/providers/devin/proto/exa/analytics_pb/analytics.proto +188 -0
  391. package/src/providers/devin/proto/exa/api_server_pb/api_server.proto +2461 -0
  392. package/src/providers/devin/proto/exa/auth_pb/auth.proto +19 -0
  393. package/src/providers/devin/proto/exa/auto_cascade_common_pb/auto_cascade_common.proto +79 -0
  394. package/src/providers/devin/proto/exa/browser_preview_pb/browser_preview.proto +32 -0
  395. package/src/providers/devin/proto/exa/bug_checker_pb/bug_checker.proto +22 -0
  396. package/src/providers/devin/proto/exa/cascade_plugins_pb/cascade_plugins.proto +262 -0
  397. package/src/providers/devin/proto/exa/chat_client_server_pb/chat_client_server.proto +57 -0
  398. package/src/providers/devin/proto/exa/chat_pb/chat.proto +449 -0
  399. package/src/providers/devin/proto/exa/code_edit/code_edit_pb/code_edit.proto +186 -0
  400. package/src/providers/devin/proto/exa/codeium_common_pb/codeium_common.proto +4157 -0
  401. package/src/providers/devin/proto/exa/context_module_pb/context_module.proto +175 -0
  402. package/src/providers/devin/proto/exa/cortex_pb/cortex.proto +3268 -0
  403. package/src/providers/devin/proto/exa/dev_pb/dev.proto +26 -0
  404. package/src/providers/devin/proto/exa/diff_action_pb/diff_action.proto +75 -0
  405. package/src/providers/devin/proto/exa/eval/pr_eval/datasets_pb/datasets.proto +103 -0
  406. package/src/providers/devin/proto/exa/eval_pb/eval.proto +1315 -0
  407. package/src/providers/devin/proto/exa/extension_server_pb/extension_server.proto +556 -0
  408. package/src/providers/devin/proto/exa/file_system_provider_pb/file_system_provider.proto +75 -0
  409. package/src/providers/devin/proto/exa/index_pb/index.proto +461 -0
  410. package/src/providers/devin/proto/exa/knowledge_base_pb/knowledge_base.proto +144 -0
  411. package/src/providers/devin/proto/exa/language_server_pb/language_server.proto +2385 -0
  412. package/src/providers/devin/proto/exa/model_management_pb/model_management.proto +186 -0
  413. package/src/providers/devin/proto/exa/opensearch_clients_pb/opensearch_clients.proto +503 -0
  414. package/src/providers/devin/proto/exa/product_analytics_pb/product_analytics.proto +37 -0
  415. package/src/providers/devin/proto/exa/prompt_pb/prompt.proto +92 -0
  416. package/src/providers/devin/proto/exa/reactive_component_pb/reactive_component.proto +96 -0
  417. package/src/providers/devin/proto/exa/seat_management_pb/seat_management.proto +2680 -0
  418. package/src/providers/devin/proto/exa/tokenizer_pb/tokenizer.proto +37 -0
  419. package/src/providers/devin/proto/exa/trainer_pb/config.proto +647 -0
  420. package/src/providers/devin/proto/exa/tree_sitter/language_data_pb/language_data.proto +14 -0
  421. package/src/providers/devin/proto/exa/trust_pb/trust.proto +157 -0
  422. package/src/providers/devin/proto/exa/user_analytics_pb/user_analytics.proto +519 -0
  423. package/src/providers/devin/proto/google.golang.org/appengine/internal/base/api_base.proto +28 -0
  424. package/src/providers/devin/proto/google.golang.org/appengine/internal/datastore/datastore_v3.proto +484 -0
  425. package/src/providers/devin/proto/google.golang.org/appengine/internal/log/log_service.proto +136 -0
  426. package/src/providers/devin/proto/google.golang.org/appengine/internal/remote_api/remote_api.proto +42 -0
  427. package/src/providers/devin/proto/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto +61 -0
  428. package/src/providers/devin/proto/grpc/binlog/v1/binarylog.proto +84 -0
  429. package/src/providers/devin/proto/io/prometheus/client/metrics.proto +98 -0
  430. package/src/providers/devin.ts +679 -0
  431. package/src/providers/error-message.ts +23 -0
  432. package/src/providers/github-copilot-headers.ts +141 -0
  433. package/src/providers/gitlab-duo-workflow-chatml-note.md +1 -0
  434. package/src/providers/gitlab-duo-workflow.ts +3135 -0
  435. package/src/providers/gitlab-duo.ts +399 -0
  436. package/src/providers/google-auth.ts +330 -0
  437. package/src/providers/google-gemini-cli.ts +1370 -0
  438. package/src/providers/google-shared.ts +1122 -0
  439. package/src/providers/google-types.ts +180 -0
  440. package/src/providers/google-vertex.ts +135 -0
  441. package/src/providers/google.ts +47 -0
  442. package/src/providers/grammar.ts +70 -0
  443. package/src/providers/kimi.ts +51 -0
  444. package/src/providers/mock.ts +514 -0
  445. package/src/providers/ollama.ts +776 -0
  446. package/src/providers/openai-anthropic-shim.ts +166 -0
  447. package/src/providers/openai-chat-server-schema.ts +243 -0
  448. package/src/providers/openai-chat-server.ts +752 -0
  449. package/src/providers/openai-chat-wire.ts +859 -0
  450. package/src/providers/openai-codex/request-transformer.ts +491 -0
  451. package/src/providers/openai-codex/response-handler.ts +102 -0
  452. package/src/providers/openai-codex-responses.ts +4716 -0
  453. package/src/providers/openai-completions.ts +2389 -0
  454. package/src/providers/openai-reasoning-fallback.ts +269 -0
  455. package/src/providers/openai-responses-server-schema.ts +397 -0
  456. package/src/providers/openai-responses-server.ts +1466 -0
  457. package/src/providers/openai-responses-wire.ts +6416 -0
  458. package/src/providers/openai-responses.ts +1393 -0
  459. package/src/providers/openai-shared.ts +3500 -0
  460. package/src/providers/pi-native-client.ts +275 -0
  461. package/src/providers/pi-native-server.ts +245 -0
  462. package/src/providers/register-builtins.ts +503 -0
  463. package/src/providers/synthetic.ts +50 -0
  464. package/src/providers/transform-messages.ts +1083 -0
  465. package/src/providers/vision-guard.ts +54 -0
  466. package/src/registry/aiand.ts +22 -0
  467. package/src/registry/aimlapi.ts +6 -0
  468. package/src/registry/alibaba-coding-plan.ts +104 -0
  469. package/src/registry/alibaba-token-plan.ts +125 -0
  470. package/src/registry/amazon-bedrock.ts +22 -0
  471. package/src/registry/anthropic.ts +26 -0
  472. package/src/registry/api-key-login.ts +115 -0
  473. package/src/registry/api-key-validation.ts +145 -0
  474. package/src/registry/aws.ts +57 -0
  475. package/src/registry/azure.ts +6 -0
  476. package/src/registry/baseten.ts +22 -0
  477. package/src/registry/bedrock-mantle.ts +34 -0
  478. package/src/registry/cerebras.ts +23 -0
  479. package/src/registry/cloudflare-ai-gateway.ts +45 -0
  480. package/src/registry/coreweave.ts +40 -0
  481. package/src/registry/cursor.ts +20 -0
  482. package/src/registry/deepseek.ts +46 -0
  483. package/src/registry/derived.ts +9 -0
  484. package/src/registry/devin.ts +15 -0
  485. package/src/registry/exa.ts +19 -0
  486. package/src/registry/firepass.ts +32 -0
  487. package/src/registry/fireworks.ts +28 -0
  488. package/src/registry/github-copilot.ts +22 -0
  489. package/src/registry/gitlab-duo-workflow.ts +20 -0
  490. package/src/registry/gitlab-duo.ts +19 -0
  491. package/src/registry/gmi-cloud.ts +22 -0
  492. package/src/registry/google-antigravity.ts +22 -0
  493. package/src/registry/google-gemini-cli.ts +22 -0
  494. package/src/registry/google-vertex.ts +38 -0
  495. package/src/registry/google.ts +6 -0
  496. package/src/registry/groq.ts +6 -0
  497. package/src/registry/huggingface.ts +29 -0
  498. package/src/registry/index.ts +4 -0
  499. package/src/registry/kagi.ts +46 -0
  500. package/src/registry/kilo.ts +114 -0
  501. package/src/registry/kimi-code.ts +17 -0
  502. package/src/registry/litellm.ts +45 -0
  503. package/src/registry/llama-cpp.ts +35 -0
  504. package/src/registry/lm-studio.ts +31 -0
  505. package/src/registry/meta.ts +22 -0
  506. package/src/registry/minimax-code-cn.ts +12 -0
  507. package/src/registry/minimax-code.ts +12 -0
  508. package/src/registry/minimax.ts +6 -0
  509. package/src/registry/mistral.ts +6 -0
  510. package/src/registry/moonshot.ts +28 -0
  511. package/src/registry/nanogpt.ts +22 -0
  512. package/src/registry/novita.ts +25 -0
  513. package/src/registry/nvidia.ts +61 -0
  514. package/src/registry/oauth/anthropic-constants.ts +12 -0
  515. package/src/registry/oauth/anthropic.ts +346 -0
  516. package/src/registry/oauth/callback-server.ts +438 -0
  517. package/src/registry/oauth/cursor.ts +187 -0
  518. package/src/registry/oauth/device-code.ts +92 -0
  519. package/src/registry/oauth/devin.ts +124 -0
  520. package/src/registry/oauth/github-copilot.ts +369 -0
  521. package/src/registry/oauth/gitlab-duo-workflow.ts +146 -0
  522. package/src/registry/oauth/gitlab-duo.ts +222 -0
  523. package/src/registry/oauth/google-antigravity.ts +225 -0
  524. package/src/registry/oauth/google-gemini-cli.ts +297 -0
  525. package/src/registry/oauth/google-oauth-shared.ts +211 -0
  526. package/src/registry/oauth/index.ts +187 -0
  527. package/src/registry/oauth/kimi.ts +297 -0
  528. package/src/registry/oauth/minimax-code.ts +53 -0
  529. package/src/registry/oauth/oauth.html +317 -0
  530. package/src/registry/oauth/openai-codex.ts +384 -0
  531. package/src/registry/oauth/opencode.ts +50 -0
  532. package/src/registry/oauth/perplexity.ts +228 -0
  533. package/src/registry/oauth/pkce.ts +18 -0
  534. package/src/registry/oauth/types.ts +96 -0
  535. package/src/registry/oauth/wafer.ts +24 -0
  536. package/src/registry/oauth/xai-oauth.ts +559 -0
  537. package/src/registry/oauth/xiaomi.ts +211 -0
  538. package/src/registry/oauth/zai.ts +285 -0
  539. package/src/registry/ollama-cloud.ts +36 -0
  540. package/src/registry/ollama.ts +43 -0
  541. package/src/registry/openai-codex-device.ts +18 -0
  542. package/src/registry/openai-codex.ts +19 -0
  543. package/src/registry/openai.ts +6 -0
  544. package/src/registry/opencode-go.ts +12 -0
  545. package/src/registry/opencode-zen.ts +12 -0
  546. package/src/registry/openrouter.ts +28 -0
  547. package/src/registry/parallel.ts +45 -0
  548. package/src/registry/perplexity.ts +13 -0
  549. package/src/registry/qianfan.ts +27 -0
  550. package/src/registry/qwen-portal.ts +50 -0
  551. package/src/registry/registry.ts +182 -0
  552. package/src/registry/sakana.ts +22 -0
  553. package/src/registry/siliconflow-cn.ts +22 -0
  554. package/src/registry/siliconflow.ts +22 -0
  555. package/src/registry/synthetic.ts +21 -0
  556. package/src/registry/tavily.ts +45 -0
  557. package/src/registry/together.ts +22 -0
  558. package/src/registry/types.ts +86 -0
  559. package/src/registry/umans.ts +23 -0
  560. package/src/registry/venice.ts +33 -0
  561. package/src/registry/vercel-ai-gateway.ts +38 -0
  562. package/src/registry/vllm.ts +34 -0
  563. package/src/registry/wafer-serverless.ts +12 -0
  564. package/src/registry/xai-oauth.ts +17 -0
  565. package/src/registry/xai.ts +22 -0
  566. package/src/registry/xiaomi-token-plan-ams.ts +12 -0
  567. package/src/registry/xiaomi-token-plan-cn.ts +12 -0
  568. package/src/registry/xiaomi-token-plan-sgp.ts +12 -0
  569. package/src/registry/xiaomi.ts +12 -0
  570. package/src/registry/zai.ts +41 -0
  571. package/src/registry/zenmux.ts +22 -0
  572. package/src/registry/zhipu-coding-plan.ts +27 -0
  573. package/src/stream.ts +1944 -0
  574. package/src/types.ts +1243 -0
  575. package/src/usage/alibaba-token-plan.ts +230 -0
  576. package/src/usage/claude.ts +830 -0
  577. package/src/usage/cursor.ts +335 -0
  578. package/src/usage/gemini.ts +258 -0
  579. package/src/usage/github-copilot.ts +424 -0
  580. package/src/usage/google-antigravity.ts +497 -0
  581. package/src/usage/kimi.ts +277 -0
  582. package/src/usage/minimax-code.ts +291 -0
  583. package/src/usage/ollama.ts +41 -0
  584. package/src/usage/openai-codex-base-url.ts +35 -0
  585. package/src/usage/openai-codex-reset.ts +205 -0
  586. package/src/usage/openai-codex.ts +627 -0
  587. package/src/usage/opencode-go.ts +89 -0
  588. package/src/usage/shared.ts +10 -0
  589. package/src/usage/synthetic.ts +180 -0
  590. package/src/usage/umans.ts +192 -0
  591. package/src/usage/xai-oauth.ts +414 -0
  592. package/src/usage/zai.ts +370 -0
  593. package/src/usage.ts +411 -0
  594. package/src/utils/abort.ts +67 -0
  595. package/src/utils/anthropic-auth.ts +93 -0
  596. package/src/utils/aws-profile.ts +88 -0
  597. package/src/utils/block-symbols.ts +78 -0
  598. package/src/utils/deterministic-id.ts +20 -0
  599. package/src/utils/empty-completion-retry.ts +161 -0
  600. package/src/utils/event-stream.ts +202 -0
  601. package/src/utils/foundry.ts +8 -0
  602. package/src/utils/google-validation.ts +25 -0
  603. package/src/utils/harmony-leak.ts +500 -0
  604. package/src/utils/http-inspector.ts +196 -0
  605. package/src/utils/idle-iterator.ts +531 -0
  606. package/src/utils/leaked-thinking-stream.ts +483 -0
  607. package/src/utils/openai-http.ts +119 -0
  608. package/src/utils/openrouter-headers.ts +12 -0
  609. package/src/utils/parse-bind.ts +56 -0
  610. package/src/utils/provider-response.ts +30 -0
  611. package/src/utils/proxy.ts +314 -0
  612. package/src/utils/request-debug.ts +351 -0
  613. package/src/utils/retry-after.ts +121 -0
  614. package/src/utils/retry.ts +77 -0
  615. package/src/utils/schema/CONSTRAINTS.md +168 -0
  616. package/src/utils/schema/adapt.ts +36 -0
  617. package/src/utils/schema/compatibility.ts +435 -0
  618. package/src/utils/schema/dereference.ts +98 -0
  619. package/src/utils/schema/draft.ts +341 -0
  620. package/src/utils/schema/equality.ts +97 -0
  621. package/src/utils/schema/fields.ts +210 -0
  622. package/src/utils/schema/index.ts +14 -0
  623. package/src/utils/schema/json-schema-validator.ts +595 -0
  624. package/src/utils/schema/meta-validator.ts +167 -0
  625. package/src/utils/schema/normalize.ts +2314 -0
  626. package/src/utils/schema/spill.ts +43 -0
  627. package/src/utils/schema/stamps.ts +109 -0
  628. package/src/utils/schema/strict-tool-validation.ts +117 -0
  629. package/src/utils/schema/types.ts +10 -0
  630. package/src/utils/schema/typescript.ts +212 -0
  631. package/src/utils/schema/wire.ts +662 -0
  632. package/src/utils/sdk-stream-timeout.ts +43 -0
  633. package/src/utils/sse-debug.ts +18 -0
  634. package/src/utils/stream-markup-healing.ts +247 -0
  635. package/src/utils/thinking-loop.ts +552 -0
  636. package/src/utils/tool-call-loop-guard.ts +107 -0
  637. package/src/utils/tool-choice.ts +101 -0
  638. package/src/utils/validation.ts +1932 -0
  639. package/src/utils.ts +492 -0
@@ -0,0 +1,818 @@
1
+ import { Effort } from "@linxiraos/pi-catalog/effort";
2
+ import { type } from "@linxiraos/pi-omptype";
3
+ import { logger } from "@linxiraos/pi-utils";
4
+ import { captureRequestHeaders, resolvePromptCacheKey } from "../auth-gateway/http";
5
+ import * as AIError from "../error";
6
+ import type {
7
+ AnthropicServerToolContent,
8
+ AssistantMessage,
9
+ AssistantMessageEventStream,
10
+ Message,
11
+ RedactedThinkingContent,
12
+ StopReason,
13
+ TextContent,
14
+ ThinkingContent,
15
+ Tool,
16
+ ToolCall,
17
+ ToolResultMessage,
18
+ UserMessage,
19
+ } from "../types";
20
+ import {
21
+ type AnthropicAssistantContentBlock,
22
+ type AnthropicMessage,
23
+ type AnthropicSystem,
24
+ type AnthropicTool,
25
+ type AnthropicToolChoice,
26
+ type AnthropicToolResultContent,
27
+ type AnthropicUserContentBlock,
28
+ anthropicMessagesRequestSchema,
29
+ } from "./anthropic-messages-server-schema";
30
+ import { isAnthropicWebSearchHistoryBlock } from "./anthropic-wire";
31
+
32
+ /**
33
+ * Anthropic Messages API (https://docs.anthropic.com/en/api/messages) ↔ pi-ai
34
+ * gateway translation. Inbound: foreign HTTP body → omp Context. Outbound:
35
+ * omp AssistantMessage[Stream] → Anthropic-shaped JSON / SSE.
36
+ */
37
+
38
+ import type { AuthGatewayStreamControl, AuthGatewayParsedRequest as ParsedRequest } from "../auth-gateway/types";
39
+
40
+ export type { ParsedRequest };
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Inbound parsing
44
+ // ---------------------------------------------------------------------------
45
+
46
+ type ImageContentPart = { type: "image"; data: string; mimeType: string };
47
+
48
+ // Dedup noise from unknown-block-type warnings. Module-scoped so the warn
49
+ // fires once per (category, type) pair across the lifetime of the process.
50
+ const WARNED_UNKNOWN_BLOCK_TYPES = new Set<string>();
51
+ function warnUnknownBlockType(category: "user" | "assistant", blockType: string): void {
52
+ const key = `${category}:${blockType}`;
53
+ if (WARNED_UNKNOWN_BLOCK_TYPES.has(key)) return;
54
+ WARNED_UNKNOWN_BLOCK_TYPES.add(key);
55
+ logger.warn("anthropic-messages: unknown content block flattened to text placeholder", {
56
+ category,
57
+ blockType,
58
+ });
59
+ }
60
+
61
+ // pi-ai's `ImageContent` only carries base64 + mimeType. When the inbound
62
+ // uses `url` or `file_id` sources we surface a text placeholder so the
63
+ // downstream provider still sees a sane history; warn once per source kind.
64
+ const WARNED_NON_BASE64_IMAGE_SOURCES = new Set<string>();
65
+ function warnNonBase64ImageSource(sourceType: string): void {
66
+ if (WARNED_NON_BASE64_IMAGE_SOURCES.has(sourceType)) return;
67
+ WARNED_NON_BASE64_IMAGE_SOURCES.add(sourceType);
68
+ logger.warn("anthropic-messages: image source surfaced as text placeholder (pi-ai ImageContent lacks URL channel)", {
69
+ sourceType,
70
+ });
71
+ }
72
+
73
+ // Compact, log-safe stringification for unknown content blocks. Keeps the
74
+ // placeholder informative without dumping multi-KB structures into history.
75
+ function describeUnknownBlock(block: { type: string }): string {
76
+ try {
77
+ const json = JSON.stringify(block);
78
+ if (json !== undefined && json.length <= 200) return `[${block.type}: ${json}]`;
79
+ } catch {
80
+ // fall through
81
+ }
82
+ return `[${block.type}]`;
83
+ }
84
+
85
+ function buildSystemPrompt(raw: AnthropicSystem): string[] | undefined {
86
+ if (raw === undefined) return undefined;
87
+ if (typeof raw === "string") return raw.length > 0 ? [raw] : undefined;
88
+ const parts = raw.map(block => block.text).filter(text => text.length > 0);
89
+ return parts.length > 0 ? [parts.join("\n\n")] : undefined;
90
+ }
91
+
92
+ function makeUserMessage(parts: (TextContent | ImageContentPart)[], timestamp: number): UserMessage {
93
+ return {
94
+ role: "user",
95
+ content: parts.length === 1 && parts[0].type === "text" ? parts[0].text : parts,
96
+ timestamp,
97
+ };
98
+ }
99
+
100
+ function toolResultPartsFromBlocks(
101
+ content: AnthropicToolResultContent[] | string | undefined,
102
+ ): (TextContent | ImageContentPart)[] {
103
+ if (content === undefined) return [];
104
+ if (typeof content === "string") return [{ type: "text", text: content }];
105
+ const out: (TextContent | ImageContentPart)[] = [];
106
+ for (const block of content) {
107
+ if (block.type === "text") {
108
+ out.push({ type: "text", text: block.text });
109
+ continue;
110
+ }
111
+ // block.type === "image" — schema only accepts base64 sources.
112
+ if (block.source.type === "base64") {
113
+ out.push({ type: "image", data: block.source.data, mimeType: block.source.media_type });
114
+ }
115
+ }
116
+ return out;
117
+ }
118
+
119
+ function walkUserContent(
120
+ blocks: string | AnthropicUserContentBlock[],
121
+ timestamp: number,
122
+ ): (UserMessage | ToolResultMessage)[] {
123
+ const messages: (UserMessage | ToolResultMessage)[] = [];
124
+ const userParts: (TextContent | ImageContentPart)[] = [];
125
+ const flush = () => {
126
+ if (userParts.length === 0) return;
127
+ messages.push(makeUserMessage(userParts.splice(0), timestamp));
128
+ };
129
+ if (typeof blocks === "string") {
130
+ if (blocks.length > 0) userParts.push({ type: "text", text: blocks });
131
+ flush();
132
+ return messages;
133
+ }
134
+ for (const block of blocks) {
135
+ if (block.type === "text") {
136
+ userParts.push({ type: "text", text: block.text });
137
+ } else if (block.type === "image") {
138
+ // SDK's typed source covers base64+url; our schema also accepts the
139
+ // forward-compat `file` variant. Narrow against a widened shape so
140
+ // every variant is handled at runtime regardless of SDK lag.
141
+ const source = block.source as {
142
+ type: string;
143
+ data?: string;
144
+ media_type?: string;
145
+ url?: string;
146
+ file_id?: string;
147
+ };
148
+ if (source.type === "base64" && source.data && source.media_type) {
149
+ userParts.push({ type: "image", data: source.data, mimeType: source.media_type });
150
+ } else {
151
+ warnNonBase64ImageSource(source.type);
152
+ const ref =
153
+ source.type === "url" ? (source.url ?? "") : source.type === "file" ? (source.file_id ?? "") : "";
154
+ userParts.push({ type: "text", text: `[image: ${ref}]` });
155
+ }
156
+ } else if (block.type === "tool_result") {
157
+ // Anthropic permits tool_result blocks to follow plain text/image
158
+ // siblings in the same user message. pi-ai's history is a flat
159
+ // sequence of typed messages, so flush the accumulated parts as a
160
+ // separate UserMessage before emitting the ToolResultMessage.
161
+ flush();
162
+ messages.push({
163
+ role: "toolResult",
164
+ toolCallId: block.tool_use_id,
165
+ // Anthropic tool_results don't carry the tool name; downstream can rehydrate.
166
+ toolName: "",
167
+ content: toolResultPartsFromBlocks(block.content as AnthropicToolResultContent[] | string | undefined),
168
+ isError: block.is_error === true,
169
+ timestamp,
170
+ });
171
+ } else {
172
+ // Unknown variant (server_tool_use, mcp_*, document, web_search_tool_result,
173
+ // container_upload, code_execution_*, …). Flatten to a text placeholder
174
+ // so the downstream provider still gets a coherent transcript.
175
+ const unknown = block as { type: string };
176
+ warnUnknownBlockType("user", unknown.type);
177
+ userParts.push({ type: "text", text: describeUnknownBlock(unknown) });
178
+ }
179
+ }
180
+ flush();
181
+ return messages;
182
+ }
183
+
184
+ function walkAssistantContent(
185
+ blocks: string | AnthropicAssistantContentBlock[],
186
+ ): (TextContent | ThinkingContent | RedactedThinkingContent | AnthropicServerToolContent | ToolCall)[] {
187
+ const out: (TextContent | ThinkingContent | RedactedThinkingContent | AnthropicServerToolContent | ToolCall)[] = [];
188
+ if (typeof blocks === "string") {
189
+ if (blocks.length > 0) out.push({ type: "text", text: blocks });
190
+ return out;
191
+ }
192
+ for (const block of blocks) {
193
+ switch (block.type) {
194
+ case "text":
195
+ out.push({ type: "text", text: block.text });
196
+ break;
197
+ case "thinking": {
198
+ const tc: ThinkingContent = { type: "thinking", thinking: block.thinking };
199
+ if (block.signature !== undefined) tc.thinkingSignature = block.signature;
200
+ out.push(tc);
201
+ break;
202
+ }
203
+ case "redacted_thinking":
204
+ out.push({ type: "redactedThinking", data: block.data });
205
+ break;
206
+ case "tool_use":
207
+ out.push({
208
+ type: "toolCall",
209
+ id: block.id,
210
+ name: block.name,
211
+ arguments:
212
+ block.input && typeof block.input === "object" && !Array.isArray(block.input)
213
+ ? (block.input as Record<string, unknown>)
214
+ : {},
215
+ });
216
+ break;
217
+ case "server_tool_use":
218
+ case "web_search_tool_result":
219
+ if (isAnthropicWebSearchHistoryBlock(block)) {
220
+ // Native web-search call/result. Anthropic requires these
221
+ // replayed verbatim (encrypted_content included), so retain
222
+ // the block instead of flattening it to text.
223
+ out.push({ type: "anthropicServerTool", block: { ...block } });
224
+ } else {
225
+ // Other server tools use distinct result block types that omp
226
+ // cannot yet replay atomically. Flatten both sides rather than
227
+ // persisting a lone server_tool_use without its matching result.
228
+ const unknown = block as { type: string };
229
+ warnUnknownBlockType("assistant", unknown.type);
230
+ out.push({ type: "text", text: describeUnknownBlock(unknown) });
231
+ }
232
+ break;
233
+ default: {
234
+ // Unknown assistant variant (mcp_tool_use, code_execution_*, …).
235
+ // Flatten to a text placeholder; warn once per unknown type.
236
+ const unknown = block as { type: string };
237
+ warnUnknownBlockType("assistant", unknown.type);
238
+ out.push({ type: "text", text: describeUnknownBlock(unknown) });
239
+ break;
240
+ }
241
+ }
242
+ }
243
+ return out;
244
+ }
245
+
246
+ function walkTools(tools: AnthropicTool[] | undefined): Tool[] | undefined {
247
+ if (!tools) return undefined;
248
+ return tools.map(tool => ({
249
+ name: tool.name,
250
+ description: tool.description ?? "",
251
+ parameters: tool.input_schema as Record<string, unknown>,
252
+ }));
253
+ }
254
+
255
+ function mapToolChoice(choice: AnthropicToolChoice | undefined): ParsedRequest["options"]["toolChoice"] {
256
+ if (!choice) return undefined;
257
+ switch (choice.type) {
258
+ case "auto":
259
+ return "auto";
260
+ case "any":
261
+ return "required";
262
+ case "none":
263
+ return "none";
264
+ case "tool":
265
+ return { name: choice.name };
266
+ }
267
+ }
268
+
269
+ type AnthropicCacheControl = { type: "ephemeral"; ttl?: "1h" | "5m" };
270
+ type HasCacheControl = { cache_control?: AnthropicCacheControl };
271
+
272
+ function readCacheControl(value: unknown): AnthropicCacheControl | undefined {
273
+ if (value === null || typeof value !== "object") return undefined;
274
+ const cc = (value as HasCacheControl).cache_control;
275
+ if (!cc || typeof cc !== "object" || cc.type !== "ephemeral") return undefined;
276
+ return cc;
277
+ }
278
+
279
+ /**
280
+ * Anthropic clients annotate caching breakpoints per block via
281
+ * `cache_control: { type: "ephemeral", ttl?: "1h"|"5m" }`. pi-ai's
282
+ * `cacheRetention` is per-request, not per-block, and its anthropic provider
283
+ * re-applies breakpoints itself on the rebuilt outbound wire. Scan every
284
+ * block once and return the strongest retention requested: any `ttl: "1h"`
285
+ * promotes the request to "long", anything else ephemeral maps to "short".
286
+ */
287
+ function deriveCacheRetention(data: {
288
+ system?: unknown;
289
+ messages: readonly unknown[];
290
+ tools?: readonly unknown[];
291
+ }): "short" | "long" | undefined {
292
+ let strongest: "short" | "long" | undefined;
293
+ const visit = (cc: AnthropicCacheControl | undefined): void => {
294
+ if (!cc) return;
295
+ if (cc.ttl === "1h") strongest = "long";
296
+ else strongest ??= "short";
297
+ };
298
+ if (Array.isArray(data.system)) {
299
+ for (const block of data.system) visit(readCacheControl(block));
300
+ }
301
+ for (const message of data.messages) {
302
+ if (message === null || typeof message !== "object") continue;
303
+ const content = (message as { content?: unknown }).content;
304
+ if (!Array.isArray(content)) continue;
305
+ for (const block of content) visit(readCacheControl(block));
306
+ }
307
+ if (data.tools) {
308
+ for (const tool of data.tools) visit(readCacheControl(tool));
309
+ }
310
+ return strongest;
311
+ }
312
+
313
+ /**
314
+ * Inbound `output_config.effort` wire literal → catalog `Effort` (1:1).
315
+ * Values outside this table (none exist in the schema today) are ignored
316
+ * rather than guessed at.
317
+ */
318
+ const REASONING_EFFORT_BY_WIRE: Partial<Record<string, Effort>> = {
319
+ low: Effort.Low,
320
+ medium: Effort.Medium,
321
+ high: Effort.High,
322
+ xhigh: Effort.XHigh,
323
+ max: Effort.Max,
324
+ };
325
+
326
+ export function parseRequest(body: unknown, headers?: Headers): ParsedRequest {
327
+ const data = anthropicMessagesRequestSchema(body);
328
+ if (data instanceof type.errors) {
329
+ throw new AIError.ValidationError(`anthropic-messages: ${data.summary}`);
330
+ }
331
+
332
+ const now = Date.now();
333
+ const messages: Message[] = [];
334
+ for (const message of data.messages as AnthropicMessage[]) {
335
+ if (message.role === "user") {
336
+ for (const m of walkUserContent(message.content, now)) messages.push(m);
337
+ } else {
338
+ const assistant: AssistantMessage = {
339
+ role: "assistant",
340
+ content: walkAssistantContent(message.content),
341
+ api: "anthropic-messages",
342
+ provider: "anthropic",
343
+ model: data.model,
344
+ usage: emptyUsage(),
345
+ stopReason: "stop",
346
+ timestamp: now,
347
+ };
348
+ messages.push(assistant);
349
+ }
350
+ }
351
+
352
+ const options: ParsedRequest["options"] = {
353
+ maxOutputTokens: data.max_tokens,
354
+ };
355
+ if (data.temperature !== undefined) options.temperature = data.temperature;
356
+ if (data.top_p !== undefined) options.topP = data.top_p;
357
+ if (data.top_k !== undefined) options.topK = data.top_k;
358
+ if (data.stop_sequences) options.stopSequences = data.stop_sequences;
359
+ const toolChoice = mapToolChoice(data.tool_choice as AnthropicToolChoice | undefined);
360
+ if (toolChoice !== undefined) options.toolChoice = toolChoice;
361
+ // `disable_parallel_tool_use === true` means the client wants the model to
362
+ // emit at most one tool call per turn; map to pi-ai's negated boolean.
363
+ // Leave undefined when the field is absent or explicitly `false` so we
364
+ // don't override provider defaults.
365
+ if (data.tool_choice?.disable_parallel_tool_use === true) {
366
+ options.parallelToolCalls = false;
367
+ }
368
+ if (data.thinking) {
369
+ switch (data.thinking.type) {
370
+ case "enabled":
371
+ options.explicitThinkingBudgetTokens = data.thinking.budget_tokens;
372
+ break;
373
+ case "disabled":
374
+ options.disableReasoning = true;
375
+ break;
376
+ case "adaptive":
377
+ if (data.thinking.budget_tokens !== undefined) {
378
+ options.explicitThinkingBudgetTokens = data.thinking.budget_tokens;
379
+ }
380
+ break;
381
+ }
382
+ }
383
+ if (data.output_config?.task_budget) {
384
+ options.taskBudget = data.output_config.task_budget;
385
+ }
386
+ if (data.output_config?.effort) {
387
+ const mapped = REASONING_EFFORT_BY_WIRE[data.output_config.effort];
388
+ if (mapped !== undefined) options.reasoning = mapped;
389
+ }
390
+ const cacheRetention = deriveCacheRetention(data);
391
+ if (cacheRetention !== undefined) options.cacheRetention = cacheRetention;
392
+ // Anthropic clients commonly send `metadata: { user_id }`; forward verbatim
393
+ // so downstream providers (and our anthropic-passthrough fast-path) can
394
+ // preserve abuse-tracking signal.
395
+ if (data.metadata !== undefined) {
396
+ options.metadata = data.metadata as Record<string, unknown>;
397
+ }
398
+ const cacheKey = resolvePromptCacheKey(body, headers);
399
+ if (cacheKey !== undefined) options.promptCacheKey = cacheKey;
400
+ // Allow-listed header capture. The gateway's `handleFormatEndpoint`
401
+ // already merges its own pre-capture under whatever the parser sets, but
402
+ // we populate here too so direct callers of `parseRequest` (tests, custom
403
+ // wrappers) see the same surface. `anthropic-version` is the most
404
+ // load-bearing — some downstream Anthropic-API targets reject requests
405
+ // missing it.
406
+ if (headers) {
407
+ const captured = captureRequestHeaders(headers);
408
+ if (Object.keys(captured).length > 0) options.headers = captured;
409
+ }
410
+
411
+ return {
412
+ modelId: data.model,
413
+ context: {
414
+ systemPrompt: buildSystemPrompt(data.system as AnthropicSystem),
415
+ messages,
416
+ tools: walkTools(data.tools as AnthropicTool[] | undefined),
417
+ },
418
+ stream: data.stream === true,
419
+ options,
420
+ };
421
+ }
422
+
423
+ function emptyUsage(): AssistantMessage["usage"] {
424
+ return {
425
+ input: 0,
426
+ output: 0,
427
+ cacheRead: 0,
428
+ cacheWrite: 0,
429
+ totalTokens: 0,
430
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
431
+ };
432
+ }
433
+
434
+ // ---------------------------------------------------------------------------
435
+ // Outbound encoding
436
+ // ---------------------------------------------------------------------------
437
+
438
+ function newMessageId(): string {
439
+ const hex = (globalThis.crypto?.randomUUID?.() ?? randomFallback()).replace(/-/g, "").slice(0, 24);
440
+ return `msg_${hex}`;
441
+ }
442
+
443
+ function randomFallback(): string {
444
+ // Sufficient for tests / environments without crypto.randomUUID
445
+ const buf = new Uint8Array(16);
446
+ for (let i = 0; i < 16; i++) buf[i] = Math.floor(Math.random() * 256);
447
+ const hex = Array.from(buf, b => b.toString(16).padStart(2, "0")).join("");
448
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
449
+ }
450
+
451
+ function mapStopReasonOut(reason: StopReason): "end_turn" | "max_tokens" | "tool_use" {
452
+ switch (reason) {
453
+ case "length":
454
+ return "max_tokens";
455
+ case "toolUse":
456
+ return "tool_use";
457
+ default:
458
+ return "end_turn";
459
+ }
460
+ }
461
+
462
+ function encodeContentBlocks(message: AssistantMessage): Record<string, unknown>[] {
463
+ const blocks: Record<string, unknown>[] = [];
464
+ for (const c of message.content) {
465
+ switch (c.type) {
466
+ case "text":
467
+ blocks.push({ type: "text", text: c.text });
468
+ break;
469
+ case "thinking": {
470
+ const b: Record<string, unknown> = { type: "thinking", thinking: c.thinking };
471
+ if (c.thinkingSignature) b.signature = c.thinkingSignature;
472
+ blocks.push(b);
473
+ break;
474
+ }
475
+ case "redactedThinking":
476
+ blocks.push({ type: "redacted_thinking", data: c.data });
477
+ break;
478
+ case "anthropicServerTool":
479
+ blocks.push(c.block);
480
+ break;
481
+ case "toolCall":
482
+ blocks.push({ type: "tool_use", id: c.id, name: c.name, input: c.arguments ?? {} });
483
+ break;
484
+ }
485
+ }
486
+ return blocks;
487
+ }
488
+
489
+ function encodeUsage(message: AssistantMessage): Record<string, unknown> {
490
+ return {
491
+ input_tokens: message.usage.input,
492
+ output_tokens: message.usage.output,
493
+ cache_read_input_tokens: message.usage.cacheRead,
494
+ cache_creation_input_tokens: message.usage.cacheWrite,
495
+ };
496
+ }
497
+
498
+ export function encodeResponse(message: AssistantMessage, requestedModelId: string): Record<string, unknown> {
499
+ if (message.stopReason === "error" || message.stopReason === "aborted") {
500
+ throw new AIError.ProviderResponseError(
501
+ message.errorMessage ?? `anthropic-messages: upstream ${message.stopReason}`,
502
+ {
503
+ provider: "anthropic",
504
+ kind: "output",
505
+ },
506
+ );
507
+ }
508
+ return {
509
+ id: message.responseId ?? newMessageId(),
510
+ type: "message",
511
+ role: "assistant",
512
+ model: requestedModelId,
513
+ content: encodeContentBlocks(message),
514
+ stop_reason: mapStopReasonOut(message.stopReason),
515
+ // TODO: surface the matched stop sequence once pi-ai's
516
+ // `AssistantMessage.stopReason` carries the matched string. Intentionally
517
+ // `null` for now (Anthropic schema allows it).
518
+ stop_sequence: null,
519
+ usage: encodeUsage(message),
520
+ };
521
+ }
522
+
523
+ // ---------------------------------------------------------------------------
524
+ // Streaming encoder
525
+ // ---------------------------------------------------------------------------
526
+
527
+ const ENCODER = new TextEncoder();
528
+
529
+ function sseFrame(event: string, data: Record<string, unknown>): Uint8Array {
530
+ return ENCODER.encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
531
+ }
532
+
533
+ type BlockKind = "text" | "thinking" | "tool_use";
534
+
535
+ interface OpenBlock {
536
+ index: number;
537
+ kind: BlockKind;
538
+ }
539
+
540
+ // Keepalive cadence for the SSE encoder. Anthropic's API pings periodically;
541
+ // without frames between message_start and the first content block (slow first
542
+ // token) SDK first-event/idle watchdogs classify the stream as stalled.
543
+ const STREAM_PING_INTERVAL_MS = 15_000;
544
+
545
+ const ZERO_WIRE_USAGE: Record<string, unknown> = {
546
+ input_tokens: 0,
547
+ output_tokens: 0,
548
+ cache_read_input_tokens: 0,
549
+ cache_creation_input_tokens: 0,
550
+ };
551
+
552
+ export function encodeStream(
553
+ events: AssistantMessageEventStream,
554
+ requestedModelId: string,
555
+ _options?: ParsedRequest["options"],
556
+ control?: AuthGatewayStreamControl,
557
+ ): ReadableStream<Uint8Array> {
558
+ let pingTimer: NodeJS.Timeout | undefined;
559
+ let cancelled = control?.signal?.aborted === true;
560
+ const markCancelled = () => {
561
+ cancelled = true;
562
+ };
563
+ control?.signal?.addEventListener("abort", markCancelled, { once: true });
564
+ const stopPings = () => {
565
+ if (pingTimer !== undefined) {
566
+ clearInterval(pingTimer);
567
+ pingTimer = undefined;
568
+ }
569
+ };
570
+ return new ReadableStream<Uint8Array>({
571
+ async start(controller) {
572
+ const messageId = newMessageId();
573
+ let started = false;
574
+ let lastPartial: AssistantMessage | undefined;
575
+ const open = new Map<number, OpenBlock>();
576
+
577
+ const ensureStart = (partial: AssistantMessage | undefined) => {
578
+ if (started) return;
579
+ started = true;
580
+ controller.enqueue(
581
+ sseFrame("message_start", {
582
+ type: "message_start",
583
+ message: {
584
+ id: messageId,
585
+ type: "message",
586
+ role: "assistant",
587
+ model: requestedModelId,
588
+ content: [],
589
+ stop_reason: null,
590
+ // TODO: same as encodeResponse — surface matched stop sequence
591
+ // once pi-ai propagates it.
592
+ stop_sequence: null,
593
+ usage: partial ? encodeUsage(partial) : ZERO_WIRE_USAGE,
594
+ },
595
+ }),
596
+ );
597
+ };
598
+
599
+ let nextContentIndexToInspect = 0;
600
+ const emitServerToolBlocksBefore = (message: AssistantMessage, beforeIndex: number) => {
601
+ const limit = Math.min(beforeIndex, message.content.length);
602
+ while (nextContentIndexToInspect < limit) {
603
+ const index = nextContentIndexToInspect++;
604
+ const content = message.content[index];
605
+ if (content?.type !== "anthropicServerTool") continue;
606
+ ensureStart(message);
607
+ controller.enqueue(
608
+ sseFrame("content_block_start", {
609
+ type: "content_block_start",
610
+ index,
611
+ content_block: content.block,
612
+ }),
613
+ );
614
+ controller.enqueue(sseFrame("content_block_stop", { type: "content_block_stop", index }));
615
+ }
616
+ };
617
+
618
+ const closeBlock = (index: number) => {
619
+ if (!open.has(index)) return;
620
+ controller.enqueue(sseFrame("content_block_stop", { type: "content_block_stop", index }));
621
+ open.delete(index);
622
+ };
623
+
624
+ pingTimer = setInterval(() => {
625
+ try {
626
+ if (cancelled) {
627
+ stopPings();
628
+ return;
629
+ }
630
+ controller.enqueue(sseFrame("ping", { type: "ping" }));
631
+ } catch {
632
+ // Controller already closed/errored (client gone); stop the timer.
633
+ stopPings();
634
+ }
635
+ }, STREAM_PING_INTERVAL_MS);
636
+
637
+ try {
638
+ if (cancelled) {
639
+ controller.close();
640
+ return;
641
+ }
642
+ for await (const ev of events) {
643
+ if (cancelled) return;
644
+ switch (ev.type) {
645
+ case "start":
646
+ ensureStart(ev.partial);
647
+ break;
648
+ case "text_start": {
649
+ emitServerToolBlocksBefore(ev.partial, ev.contentIndex);
650
+ ensureStart(ev.partial);
651
+ open.set(ev.contentIndex, { index: ev.contentIndex, kind: "text" });
652
+ controller.enqueue(
653
+ sseFrame("content_block_start", {
654
+ type: "content_block_start",
655
+ index: ev.contentIndex,
656
+ content_block: { type: "text", text: "" },
657
+ }),
658
+ );
659
+ break;
660
+ }
661
+ case "text_delta":
662
+ controller.enqueue(
663
+ sseFrame("content_block_delta", {
664
+ type: "content_block_delta",
665
+ index: ev.contentIndex,
666
+ delta: { type: "text_delta", text: ev.delta },
667
+ }),
668
+ );
669
+ break;
670
+ case "text_end":
671
+ closeBlock(ev.contentIndex);
672
+ break;
673
+ case "thinking_start": {
674
+ emitServerToolBlocksBefore(ev.partial, ev.contentIndex);
675
+ ensureStart(ev.partial);
676
+ open.set(ev.contentIndex, { index: ev.contentIndex, kind: "thinking" });
677
+ controller.enqueue(
678
+ sseFrame("content_block_start", {
679
+ type: "content_block_start",
680
+ index: ev.contentIndex,
681
+ content_block: { type: "thinking", thinking: "" },
682
+ }),
683
+ );
684
+ break;
685
+ }
686
+ case "thinking_delta":
687
+ controller.enqueue(
688
+ sseFrame("content_block_delta", {
689
+ type: "content_block_delta",
690
+ index: ev.contentIndex,
691
+ delta: { type: "thinking_delta", thinking: ev.delta },
692
+ }),
693
+ );
694
+ break;
695
+ case "thinking_end": {
696
+ const c = ev.partial.content[ev.contentIndex];
697
+ if (c?.type === "thinking" && c.thinkingSignature) {
698
+ controller.enqueue(
699
+ sseFrame("content_block_delta", {
700
+ type: "content_block_delta",
701
+ index: ev.contentIndex,
702
+ delta: { type: "signature_delta", signature: c.thinkingSignature },
703
+ }),
704
+ );
705
+ }
706
+ closeBlock(ev.contentIndex);
707
+ break;
708
+ }
709
+ case "toolcall_start": {
710
+ emitServerToolBlocksBefore(ev.partial, ev.contentIndex);
711
+ ensureStart(ev.partial);
712
+ const tc = ev.partial.content[ev.contentIndex] as ToolCall | undefined;
713
+ open.set(ev.contentIndex, { index: ev.contentIndex, kind: "tool_use" });
714
+ controller.enqueue(
715
+ sseFrame("content_block_start", {
716
+ type: "content_block_start",
717
+ index: ev.contentIndex,
718
+ content_block: {
719
+ type: "tool_use",
720
+ id: tc?.id ?? "",
721
+ name: tc?.name ?? "",
722
+ input: {},
723
+ },
724
+ }),
725
+ );
726
+ break;
727
+ }
728
+ case "toolcall_delta":
729
+ controller.enqueue(
730
+ sseFrame("content_block_delta", {
731
+ type: "content_block_delta",
732
+ index: ev.contentIndex,
733
+ delta: { type: "input_json_delta", partial_json: ev.delta },
734
+ }),
735
+ );
736
+ break;
737
+ case "toolcall_end":
738
+ closeBlock(ev.contentIndex);
739
+ break;
740
+ case "done": {
741
+ for (const idx of [...open.keys()]) closeBlock(idx);
742
+ emitServerToolBlocksBefore(ev.message, ev.message.content.length);
743
+ controller.enqueue(
744
+ sseFrame("message_delta", {
745
+ type: "message_delta",
746
+ // TODO: surface matched stop sequence once pi-ai
747
+ // propagates it on the `done` event.
748
+ delta: { stop_reason: mapStopReasonOut(ev.reason), stop_sequence: null },
749
+ usage: encodeUsage(ev.message),
750
+ }),
751
+ );
752
+ controller.enqueue(sseFrame("message_stop", { type: "message_stop" }));
753
+ controller.close();
754
+ return;
755
+ }
756
+ case "error": {
757
+ const msg = ev.error.errorMessage ?? "stream error";
758
+ controller.enqueue(
759
+ sseFrame("error", { type: "error", error: { type: "api_error", message: msg } }),
760
+ );
761
+ controller.close();
762
+ return;
763
+ }
764
+ }
765
+ }
766
+ // Stream ended without an explicit done: emit a complete envelope
767
+ // (message_start + message_delta carrying a stop_reason) so strict
768
+ // clients don't reject the response as a protocol error.
769
+ ensureStart(lastPartial);
770
+ for (const idx of [...open.keys()]) closeBlock(idx);
771
+ controller.enqueue(
772
+ sseFrame("message_delta", {
773
+ type: "message_delta",
774
+ delta: { stop_reason: "end_turn", stop_sequence: null },
775
+ usage: lastPartial ? encodeUsage(lastPartial) : ZERO_WIRE_USAGE,
776
+ }),
777
+ );
778
+ controller.enqueue(sseFrame("message_stop", { type: "message_stop" }));
779
+ controller.close();
780
+ } catch (err) {
781
+ if (!cancelled) {
782
+ controller.enqueue(
783
+ sseFrame("error", {
784
+ type: "error",
785
+ error: { type: "api_error", message: err instanceof Error ? err.message : String(err) },
786
+ }),
787
+ );
788
+ controller.close();
789
+ }
790
+ } finally {
791
+ control?.signal?.removeEventListener("abort", markCancelled);
792
+ stopPings();
793
+ }
794
+ },
795
+ cancel(reason) {
796
+ cancelled = true;
797
+ control?.signal?.removeEventListener("abort", markCancelled);
798
+ control?.onCancel?.(reason);
799
+ stopPings();
800
+ },
801
+ });
802
+ }
803
+
804
+ // ---------------------------------------------------------------------------
805
+ // Error envelope
806
+ // ---------------------------------------------------------------------------
807
+
808
+ /**
809
+ * Anthropic error envelope: `{ type: "error", error: { type, message } }`.
810
+ * See https://docs.anthropic.com/en/api/errors. Returned as a `Response` so
811
+ * the gateway can hand it straight back to the client without extra wrapping.
812
+ */
813
+ export function formatError(status: number, type: string, message: string): Response {
814
+ return new Response(JSON.stringify({ type: "error", error: { type, message } }), {
815
+ status,
816
+ headers: { "Content-Type": "application/json" },
817
+ });
818
+ }