@fractaal/pi-ai 0.86.9 → 1.6.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 (411) hide show
  1. package/README.md +154 -78
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +380 -144
  4. package/dist/api/anthropic-messages.js.map +1 -1
  5. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  6. package/dist/api/azure-openai-responses.js +9 -11
  7. package/dist/api/azure-openai-responses.js.map +1 -1
  8. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  9. package/dist/api/bedrock-converse-stream.js +184 -121
  10. package/dist/api/bedrock-converse-stream.js.map +1 -1
  11. package/dist/api/bedrock-converse-stream.lazy.d.ts +7 -0
  12. package/dist/api/bedrock-converse-stream.lazy.d.ts.map +1 -1
  13. package/dist/api/bedrock-converse-stream.lazy.js +18 -5
  14. package/dist/api/bedrock-converse-stream.lazy.js.map +1 -1
  15. package/dist/api/classifier-shared.d.ts +21 -0
  16. package/dist/api/classifier-shared.d.ts.map +1 -0
  17. package/dist/api/classifier-shared.js +99 -0
  18. package/dist/api/classifier-shared.js.map +1 -0
  19. package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -1
  20. package/dist/api/cloudflare-workers-ai-system-one.js +10 -1
  21. package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -1
  22. package/dist/api/constrained-sampling.d.ts +15 -1
  23. package/dist/api/constrained-sampling.d.ts.map +1 -1
  24. package/dist/api/constrained-sampling.js +51 -18
  25. package/dist/api/constrained-sampling.js.map +1 -1
  26. package/dist/api/google-generative-ai.d.ts.map +1 -1
  27. package/dist/api/google-generative-ai.js +4 -10
  28. package/dist/api/google-generative-ai.js.map +1 -1
  29. package/dist/api/google-shared.d.ts +2 -1
  30. package/dist/api/google-shared.d.ts.map +1 -1
  31. package/dist/api/google-shared.js +60 -3
  32. package/dist/api/google-shared.js.map +1 -1
  33. package/dist/api/google-vertex.d.ts.map +1 -1
  34. package/dist/api/google-vertex.js +9 -15
  35. package/dist/api/google-vertex.js.map +1 -1
  36. package/dist/api/lazy.d.ts +7 -2
  37. package/dist/api/lazy.d.ts.map +1 -1
  38. package/dist/api/lazy.js +33 -12
  39. package/dist/api/lazy.js.map +1 -1
  40. package/dist/api/llama-cpp-classify.d.ts.map +1 -1
  41. package/dist/api/llama-cpp-classify.js +4 -1
  42. package/dist/api/llama-cpp-classify.js.map +1 -1
  43. package/dist/api/mistral-conversations.d.ts.map +1 -1
  44. package/dist/api/mistral-conversations.js +50 -60
  45. package/dist/api/mistral-conversations.js.map +1 -1
  46. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  47. package/dist/api/openai-codex-responses.js +30 -17
  48. package/dist/api/openai-codex-responses.js.map +1 -1
  49. package/dist/api/openai-completions.d.ts +2 -1
  50. package/dist/api/openai-completions.d.ts.map +1 -1
  51. package/dist/api/openai-completions.js +93 -90
  52. package/dist/api/openai-completions.js.map +1 -1
  53. package/dist/api/openai-decisions.d.ts +4 -0
  54. package/dist/api/openai-decisions.d.ts.map +1 -0
  55. package/dist/api/openai-decisions.js +162 -0
  56. package/dist/api/openai-decisions.js.map +1 -0
  57. package/dist/api/openai-decisions.lazy.d.ts +3 -0
  58. package/dist/api/openai-decisions.lazy.d.ts.map +1 -0
  59. package/dist/api/openai-decisions.lazy.js +4 -0
  60. package/dist/api/openai-decisions.lazy.js.map +1 -0
  61. package/dist/api/openai-responses-shared.d.ts +26 -0
  62. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  63. package/dist/api/openai-responses-shared.js +132 -66
  64. package/dist/api/openai-responses-shared.js.map +1 -1
  65. package/dist/api/openai-responses.d.ts.map +1 -1
  66. package/dist/api/openai-responses.js +42 -21
  67. package/dist/api/openai-responses.js.map +1 -1
  68. package/dist/api/openrouter-images.d.ts.map +1 -1
  69. package/dist/api/openrouter-images.js +5 -3
  70. package/dist/api/openrouter-images.js.map +1 -1
  71. package/dist/api/pi-messages.d.ts +2 -0
  72. package/dist/api/pi-messages.d.ts.map +1 -1
  73. package/dist/api/pi-messages.js +27 -12
  74. package/dist/api/pi-messages.js.map +1 -1
  75. package/dist/api/simple-options.d.ts +1 -0
  76. package/dist/api/simple-options.d.ts.map +1 -1
  77. package/dist/api/simple-options.js +18 -3
  78. package/dist/api/simple-options.js.map +1 -1
  79. package/dist/api/system-one-shared.d.ts +29 -3
  80. package/dist/api/system-one-shared.d.ts.map +1 -1
  81. package/dist/api/system-one-shared.js +54 -86
  82. package/dist/api/system-one-shared.js.map +1 -1
  83. package/dist/api/transform-messages.d.ts +16 -1
  84. package/dist/api/transform-messages.d.ts.map +1 -1
  85. package/dist/api/transform-messages.js +28 -15
  86. package/dist/api/transform-messages.js.map +1 -1
  87. package/dist/api/typesafe-system-one.d.ts.map +1 -1
  88. package/dist/api/typesafe-system-one.js +12 -1
  89. package/dist/api/typesafe-system-one.js.map +1 -1
  90. package/dist/auth/oauth/anthropic.d.ts.map +1 -1
  91. package/dist/auth/oauth/anthropic.js +14 -6
  92. package/dist/auth/oauth/anthropic.js.map +1 -1
  93. package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
  94. package/dist/auth/oauth/github-copilot.js +4 -11
  95. package/dist/auth/oauth/github-copilot.js.map +1 -1
  96. package/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
  97. package/dist/auth/oauth/kimi-coding.js +4 -22
  98. package/dist/auth/oauth/kimi-coding.js.map +1 -1
  99. package/dist/auth/oauth/load.d.ts.map +1 -1
  100. package/dist/auth/oauth/load.js +5 -2
  101. package/dist/auth/oauth/load.js.map +1 -1
  102. package/dist/auth/oauth/meta.d.ts.map +1 -1
  103. package/dist/auth/oauth/meta.js +1 -14
  104. package/dist/auth/oauth/meta.js.map +1 -1
  105. package/dist/auth/oauth/openai-chatgpt.js +1 -1
  106. package/dist/auth/oauth/openai-chatgpt.js.map +1 -1
  107. package/dist/auth/oauth/openai-codex.d.ts.map +1 -1
  108. package/dist/auth/oauth/openai-codex.js +4 -4
  109. package/dist/auth/oauth/openai-codex.js.map +1 -1
  110. package/dist/auth/oauth/radius.d.ts.map +1 -1
  111. package/dist/auth/oauth/radius.js +9 -3
  112. package/dist/auth/oauth/radius.js.map +1 -1
  113. package/dist/auth/oauth/trusted-url.d.ts +7 -0
  114. package/dist/auth/oauth/trusted-url.d.ts.map +1 -0
  115. package/dist/auth/oauth/trusted-url.js +12 -0
  116. package/dist/auth/oauth/trusted-url.js.map +1 -0
  117. package/dist/auth/types.d.ts +9 -0
  118. package/dist/auth/types.d.ts.map +1 -1
  119. package/dist/auth/types.js.map +1 -1
  120. package/dist/cli.js +6 -2
  121. package/dist/cli.js.map +1 -1
  122. package/dist/compat/extension-oauth-types.d.ts +4 -0
  123. package/dist/compat/extension-oauth-types.d.ts.map +1 -1
  124. package/dist/compat/extension-oauth-types.js.map +1 -1
  125. package/dist/env-api-keys.d.ts.map +1 -1
  126. package/dist/env-api-keys.js +1 -0
  127. package/dist/env-api-keys.js.map +1 -1
  128. package/dist/index.d.ts +4 -4
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +4 -3
  131. package/dist/index.js.map +1 -1
  132. package/dist/lazy-bedrock-provider.d.ts +10 -0
  133. package/dist/lazy-bedrock-provider.d.ts.map +1 -0
  134. package/dist/lazy-bedrock-provider.js +13 -0
  135. package/dist/lazy-bedrock-provider.js.map +1 -0
  136. package/dist/lazy-oauth.d.ts +10 -0
  137. package/dist/lazy-oauth.d.ts.map +1 -0
  138. package/dist/lazy-oauth.js +23 -0
  139. package/dist/lazy-oauth.js.map +1 -0
  140. package/dist/models.d.ts +9 -0
  141. package/dist/models.d.ts.map +1 -1
  142. package/dist/models.generated.d.ts +4 -0
  143. package/dist/models.generated.d.ts.map +1 -1
  144. package/dist/models.generated.js +5 -1
  145. package/dist/models.generated.js.map +1 -1
  146. package/dist/models.js +28 -12
  147. package/dist/models.js.map +1 -1
  148. package/dist/providers/all.d.ts.map +1 -1
  149. package/dist/providers/all.js +2 -0
  150. package/dist/providers/all.js.map +1 -1
  151. package/dist/providers/amazon-bedrock.models.js +1 -1
  152. package/dist/providers/amazon-bedrock.models.js.map +1 -1
  153. package/dist/providers/ant-ling.models.js +1 -1
  154. package/dist/providers/ant-ling.models.js.map +1 -1
  155. package/dist/providers/anthropic.models.js +1 -1
  156. package/dist/providers/anthropic.models.js.map +1 -1
  157. package/dist/providers/azure.models.js +1 -1
  158. package/dist/providers/azure.models.js.map +1 -1
  159. package/dist/providers/baseten.models.js +1 -1
  160. package/dist/providers/baseten.models.js.map +1 -1
  161. package/dist/providers/cerebras.models.js +1 -1
  162. package/dist/providers/cerebras.models.js.map +1 -1
  163. package/dist/providers/cloudflare-ai-gateway.models.js +1 -1
  164. package/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
  165. package/dist/providers/cloudflare-workers-ai.models.js +1 -1
  166. package/dist/providers/cloudflare-workers-ai.models.js.map +1 -1
  167. package/dist/providers/compat-schema.d.ts +494 -0
  168. package/dist/providers/compat-schema.d.ts.map +1 -0
  169. package/dist/providers/compat-schema.js +447 -0
  170. package/dist/providers/compat-schema.js.map +1 -0
  171. package/dist/providers/data/.manifest.json +1 -1
  172. package/dist/providers/data/amazon-bedrock.json +1 -1
  173. package/dist/providers/data/anthropic.json +1 -1
  174. package/dist/providers/data/azure.json +1 -1
  175. package/dist/providers/data/baseten.json +1 -1
  176. package/dist/providers/data/cerebras.json +1 -1
  177. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  178. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  179. package/dist/providers/data/fireworks.json +1 -1
  180. package/dist/providers/data/github-copilot.json +1 -1
  181. package/dist/providers/data/google-vertex.json +1 -1
  182. package/dist/providers/data/google.json +1 -1
  183. package/dist/providers/data/groq.json +1 -1
  184. package/dist/providers/data/huggingface.json +1 -1
  185. package/dist/providers/data/kimi-coding.json +1 -1
  186. package/dist/providers/data/meta.json +1 -1
  187. package/dist/providers/data/minimax-cn.json +1 -1
  188. package/dist/providers/data/minimax.json +1 -1
  189. package/dist/providers/data/mistral.json +1 -1
  190. package/dist/providers/data/moonshotai-cn.json +1 -1
  191. package/dist/providers/data/moonshotai.json +1 -1
  192. package/dist/providers/data/nvidia.json +1 -1
  193. package/dist/providers/data/openai-codex.json +1 -1
  194. package/dist/providers/data/openai.json +1 -1
  195. package/dist/providers/data/opencode-go.json +1 -1
  196. package/dist/providers/data/opencode.json +1 -1
  197. package/dist/providers/data/openrouter.json +1 -1
  198. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  199. package/dist/providers/data/qwen-token-plan-individual-cn.json +1 -0
  200. package/dist/providers/data/qwen-token-plan-individual.json +1 -1
  201. package/dist/providers/data/qwen-token-plan.json +1 -1
  202. package/dist/providers/data/radius.json +1 -1
  203. package/dist/providers/data/together.json +1 -1
  204. package/dist/providers/data/typesafe.json +1 -1
  205. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  206. package/dist/providers/data/xai.json +1 -1
  207. package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  208. package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  209. package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  210. package/dist/providers/data/xiaomi.json +1 -1
  211. package/dist/providers/data/zai-coding-cn.json +1 -1
  212. package/dist/providers/data/zai.json +1 -1
  213. package/dist/providers/deepseek.models.js +1 -1
  214. package/dist/providers/deepseek.models.js.map +1 -1
  215. package/dist/providers/faux.d.ts.map +1 -1
  216. package/dist/providers/faux.js +31 -9
  217. package/dist/providers/faux.js.map +1 -1
  218. package/dist/providers/fireworks.models.js +1 -1
  219. package/dist/providers/fireworks.models.js.map +1 -1
  220. package/dist/providers/github-copilot.d.ts +3 -1
  221. package/dist/providers/github-copilot.d.ts.map +1 -1
  222. package/dist/providers/github-copilot.js +13 -2
  223. package/dist/providers/github-copilot.js.map +1 -1
  224. package/dist/providers/github-copilot.models.js +1 -1
  225. package/dist/providers/github-copilot.models.js.map +1 -1
  226. package/dist/providers/google-vertex.models.js +1 -1
  227. package/dist/providers/google-vertex.models.js.map +1 -1
  228. package/dist/providers/google.models.js +1 -1
  229. package/dist/providers/google.models.js.map +1 -1
  230. package/dist/providers/groq.models.js +1 -1
  231. package/dist/providers/groq.models.js.map +1 -1
  232. package/dist/providers/huggingface.models.js +1 -1
  233. package/dist/providers/huggingface.models.js.map +1 -1
  234. package/dist/providers/kimi-coding.d.ts +1 -1
  235. package/dist/providers/kimi-coding.js +3 -3
  236. package/dist/providers/kimi-coding.js.map +1 -1
  237. package/dist/providers/kimi-coding.models.js +1 -1
  238. package/dist/providers/kimi-coding.models.js.map +1 -1
  239. package/dist/providers/meta.models.js +1 -1
  240. package/dist/providers/meta.models.js.map +1 -1
  241. package/dist/providers/minimax-cn.models.js +1 -1
  242. package/dist/providers/minimax-cn.models.js.map +1 -1
  243. package/dist/providers/minimax.models.js +1 -1
  244. package/dist/providers/minimax.models.js.map +1 -1
  245. package/dist/providers/mistral.models.js +1 -1
  246. package/dist/providers/mistral.models.js.map +1 -1
  247. package/dist/providers/model-schema.d.ts +91 -0
  248. package/dist/providers/model-schema.d.ts.map +1 -0
  249. package/dist/providers/model-schema.js +68 -0
  250. package/dist/providers/model-schema.js.map +1 -0
  251. package/dist/providers/moonshotai-cn.models.js +1 -1
  252. package/dist/providers/moonshotai-cn.models.js.map +1 -1
  253. package/dist/providers/moonshotai.models.js +1 -1
  254. package/dist/providers/moonshotai.models.js.map +1 -1
  255. package/dist/providers/nvidia.models.js +1 -1
  256. package/dist/providers/nvidia.models.js.map +1 -1
  257. package/dist/providers/openai-codex-catalog.d.ts.map +1 -1
  258. package/dist/providers/openai-codex-catalog.js +44 -44
  259. package/dist/providers/openai-codex-catalog.js.map +1 -1
  260. package/dist/providers/openai-codex.models.js +1 -1
  261. package/dist/providers/openai-codex.models.js.map +1 -1
  262. package/dist/providers/openai.d.ts.map +1 -1
  263. package/dist/providers/openai.js +12 -3
  264. package/dist/providers/openai.js.map +1 -1
  265. package/dist/providers/openai.models.js +1 -1
  266. package/dist/providers/openai.models.js.map +1 -1
  267. package/dist/providers/opencode-go.d.ts +3 -1
  268. package/dist/providers/opencode-go.d.ts.map +1 -1
  269. package/dist/providers/opencode-go.js +2 -0
  270. package/dist/providers/opencode-go.js.map +1 -1
  271. package/dist/providers/opencode-go.models.js +1 -1
  272. package/dist/providers/opencode-go.models.js.map +1 -1
  273. package/dist/providers/opencode.js +1 -1
  274. package/dist/providers/opencode.js.map +1 -1
  275. package/dist/providers/opencode.models.js +1 -1
  276. package/dist/providers/opencode.models.js.map +1 -1
  277. package/dist/providers/openrouter-api.d.ts +40 -0
  278. package/dist/providers/openrouter-api.d.ts.map +1 -0
  279. package/dist/providers/openrouter-api.js +41 -0
  280. package/dist/providers/openrouter-api.js.map +1 -0
  281. package/dist/providers/openrouter.d.ts +11 -1
  282. package/dist/providers/openrouter.d.ts.map +1 -1
  283. package/dist/providers/openrouter.js +52 -1
  284. package/dist/providers/openrouter.js.map +1 -1
  285. package/dist/providers/openrouter.models.js +1 -1
  286. package/dist/providers/openrouter.models.js.map +1 -1
  287. package/dist/providers/qwen-token-plan-cn.models.js +1 -1
  288. package/dist/providers/qwen-token-plan-cn.models.js.map +1 -1
  289. package/dist/providers/qwen-token-plan-individual-cn.d.ts +3 -0
  290. package/dist/providers/qwen-token-plan-individual-cn.d.ts.map +1 -0
  291. package/dist/providers/qwen-token-plan-individual-cn.js +15 -0
  292. package/dist/providers/qwen-token-plan-individual-cn.js.map +1 -0
  293. package/dist/providers/qwen-token-plan-individual-cn.models.d.ts +6 -0
  294. package/dist/providers/qwen-token-plan-individual-cn.models.d.ts.map +1 -0
  295. package/dist/providers/qwen-token-plan-individual-cn.models.js +8 -0
  296. package/dist/providers/qwen-token-plan-individual-cn.models.js.map +1 -0
  297. package/dist/providers/qwen-token-plan-individual.models.js +1 -1
  298. package/dist/providers/qwen-token-plan-individual.models.js.map +1 -1
  299. package/dist/providers/qwen-token-plan.models.js +1 -1
  300. package/dist/providers/qwen-token-plan.models.js.map +1 -1
  301. package/dist/providers/radius-config.d.ts.map +1 -1
  302. package/dist/providers/radius-config.js +2 -1
  303. package/dist/providers/radius-config.js.map +1 -1
  304. package/dist/providers/radius.d.ts.map +1 -1
  305. package/dist/providers/radius.js +4 -12
  306. package/dist/providers/radius.js.map +1 -1
  307. package/dist/providers/radius.models.js +1 -1
  308. package/dist/providers/radius.models.js.map +1 -1
  309. package/dist/providers/schema-builders.d.ts +10 -0
  310. package/dist/providers/schema-builders.d.ts.map +1 -0
  311. package/dist/providers/schema-builders.js +18 -0
  312. package/dist/providers/schema-builders.js.map +1 -0
  313. package/dist/providers/together.models.js +1 -1
  314. package/dist/providers/together.models.js.map +1 -1
  315. package/dist/providers/typesafe.models.js +1 -1
  316. package/dist/providers/typesafe.models.js.map +1 -1
  317. package/dist/providers/vercel-ai-gateway.models.js +1 -1
  318. package/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  319. package/dist/providers/xai.models.js +1 -1
  320. package/dist/providers/xai.models.js.map +1 -1
  321. package/dist/providers/xiaomi-token-plan-ams.models.js +1 -1
  322. package/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
  323. package/dist/providers/xiaomi-token-plan-cn.models.js +1 -1
  324. package/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
  325. package/dist/providers/xiaomi-token-plan-sgp.models.js +1 -1
  326. package/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
  327. package/dist/providers/xiaomi.models.js +1 -1
  328. package/dist/providers/xiaomi.models.js.map +1 -1
  329. package/dist/providers/zai-coding-cn.models.js +1 -1
  330. package/dist/providers/zai-coding-cn.models.js.map +1 -1
  331. package/dist/providers/zai.models.js +1 -1
  332. package/dist/providers/zai.models.js.map +1 -1
  333. package/dist/telemetry.d.ts +288 -0
  334. package/dist/telemetry.d.ts.map +1 -0
  335. package/dist/telemetry.js +192 -0
  336. package/dist/telemetry.js.map +1 -0
  337. package/dist/types.d.ts +57 -310
  338. package/dist/types.d.ts.map +1 -1
  339. package/dist/types.js.map +1 -1
  340. package/dist/utils/error-body.d.ts +8 -0
  341. package/dist/utils/error-body.d.ts.map +1 -1
  342. package/dist/utils/error-body.js +30 -2
  343. package/dist/utils/error-body.js.map +1 -1
  344. package/dist/utils/estimate.js +1 -1
  345. package/dist/utils/estimate.js.map +1 -1
  346. package/dist/utils/event-stream.d.ts +10 -1
  347. package/dist/utils/event-stream.d.ts.map +1 -1
  348. package/dist/utils/event-stream.js +25 -0
  349. package/dist/utils/event-stream.js.map +1 -1
  350. package/dist/utils/identity.d.ts +65 -0
  351. package/dist/utils/identity.d.ts.map +1 -0
  352. package/dist/utils/identity.js +141 -0
  353. package/dist/utils/identity.js.map +1 -0
  354. package/dist/utils/json-parse.d.ts +10 -0
  355. package/dist/utils/json-parse.d.ts.map +1 -1
  356. package/dist/utils/json-parse.js +26 -1
  357. package/dist/utils/json-parse.js.map +1 -1
  358. package/dist/utils/model-operations.d.ts +3 -1
  359. package/dist/utils/model-operations.d.ts.map +1 -1
  360. package/dist/utils/model-operations.js +6 -0
  361. package/dist/utils/model-operations.js.map +1 -1
  362. package/dist/utils/openrouter-cost.d.ts +24 -0
  363. package/dist/utils/openrouter-cost.d.ts.map +1 -0
  364. package/dist/utils/openrouter-cost.js +34 -0
  365. package/dist/utils/openrouter-cost.js.map +1 -0
  366. package/dist/utils/overflow.d.ts +1 -0
  367. package/dist/utils/overflow.d.ts.map +1 -1
  368. package/dist/utils/overflow.js +8 -1
  369. package/dist/utils/overflow.js.map +1 -1
  370. package/dist/utils/provider-retry.d.ts +2 -0
  371. package/dist/utils/provider-retry.d.ts.map +1 -1
  372. package/dist/utils/provider-retry.js +2 -0
  373. package/dist/utils/provider-retry.js.map +1 -1
  374. package/dist/utils/retry.d.ts.map +1 -1
  375. package/dist/utils/retry.js +29 -10
  376. package/dist/utils/retry.js.map +1 -1
  377. package/dist/utils/streaming-json.d.ts +84 -0
  378. package/dist/utils/streaming-json.d.ts.map +1 -0
  379. package/dist/utils/streaming-json.js +513 -0
  380. package/dist/utils/streaming-json.js.map +1 -0
  381. package/dist/utils/{typebox-helpers.d.ts → string-enum.d.ts} +5 -5
  382. package/dist/utils/string-enum.d.ts.map +1 -0
  383. package/dist/utils/{typebox-helpers.js → string-enum.js} +5 -6
  384. package/dist/utils/string-enum.js.map +1 -0
  385. package/dist/utils/text.d.ts +7 -0
  386. package/dist/utils/text.d.ts.map +1 -1
  387. package/dist/utils/text.js +9 -0
  388. package/dist/utils/text.js.map +1 -1
  389. package/dist/utils/transcript.d.ts +23 -9
  390. package/dist/utils/transcript.d.ts.map +1 -1
  391. package/dist/utils/transcript.js +30 -19
  392. package/dist/utils/transcript.js.map +1 -1
  393. package/dist/utils/validation.d.ts +5 -3
  394. package/dist/utils/validation.d.ts.map +1 -1
  395. package/dist/utils/validation.js +27 -445
  396. package/dist/utils/validation.js.map +1 -1
  397. package/dist/utils/version.d.ts +2 -0
  398. package/dist/utils/version.d.ts.map +1 -0
  399. package/dist/utils/version.js +3 -0
  400. package/dist/utils/version.js.map +1 -0
  401. package/package.json +19 -10
  402. package/dist/utils/assistant-message-frame.d.ts +0 -77
  403. package/dist/utils/assistant-message-frame.d.ts.map +0 -1
  404. package/dist/utils/assistant-message-frame.js +0 -425
  405. package/dist/utils/assistant-message-frame.js.map +0 -1
  406. package/dist/utils/pi-user-agent.d.ts +0 -2
  407. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  408. package/dist/utils/pi-user-agent.js +0 -12
  409. package/dist/utils/pi-user-agent.js.map +0 -1
  410. package/dist/utils/typebox-helpers.d.ts.map +0 -1
  411. package/dist/utils/typebox-helpers.js.map +0 -1
@@ -7,15 +7,16 @@ import { appendAssistantMessageDiagnostic } from "../utils/diagnostics.js";
7
7
  import { normalizeProviderError } from "../utils/error-body.js";
8
8
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
9
9
  import { providerHeadersToRecord } from "../utils/headers.js";
10
- import { parseStreamingJson } from "../utils/json-parse.js";
10
+ import { getClientVersion } from "../utils/identity.js";
11
11
  import { resolveHttpProxyUrlForTarget } from "../utils/node-http-proxy.js";
12
12
  import { getProviderEnvValue } from "../utils/provider-env.js";
13
13
  import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
14
+ import { ToolCallArgumentsStream } from "../utils/streaming-json.js";
14
15
  import { getSystemMessageText } from "../utils/text.js";
15
16
  import { collapseSystemMessages, getCurrentTools, getInitialSystemMessage, withoutInitialSystemMessage, } from "../utils/transcript.js";
16
- import { getJsonSchemaToolParameters, resolveJsonSchemaStrictSampling } from "./constrained-sampling.js";
17
+ import { getJsonSchemaToolParameters, isStrictToolLimitErrorMessage, prefersJsonSchemaStrictSampling, resolveJsonSchemaStrictSampling, } from "./constrained-sampling.js";
17
18
  import { adjustMaxTokensForThinking, buildBaseOptions, clampMaxTokensToContext, clampReasoning, } from "./simple-options.js";
18
- import { transformMessages } from "./transform-messages.js";
19
+ import { splitErrorToolResultImages, transformMessages } from "./transform-messages.js";
19
20
  const EMPTY_TEXT_PLACEHOLDER = "<empty>";
20
21
  const THINKING_BINDING_CONTROLS_BETA = "thinking-binding-controls-2026-08-01";
21
22
  /** Matches the placeholder the Anthropic API path uses for redacted thinking. */
@@ -42,7 +43,7 @@ export const stream = (model, context, options = {}) => {
42
43
  stopReason: "pending",
43
44
  timestamp: Date.now(),
44
45
  };
45
- const blocks = output.content;
46
+ const openBlocks = new Map();
46
47
  // A profile explicitly configured through pi's auth flow (the `profile`
47
48
  // option or scoped `AWS_PROFILE` on the stored credential's env) must win
48
49
  // over ambient AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY. The SDK default
@@ -51,6 +52,7 @@ export const stream = (model, context, options = {}) => {
51
52
  const optionsProfile = options.profile || options.env?.AWS_PROFILE;
52
53
  const config = {
53
54
  profile: optionsProfile || getProviderEnvValue("AWS_PROFILE", options.env),
55
+ customUserAgent: bedrockUserAgent(options.identity),
54
56
  };
55
57
  const configuredRegion = getConfiguredBedrockRegion(options);
56
58
  const hasAmbientConfiguredProfile = Boolean(getProviderEnvValue("AWS_PROFILE"));
@@ -143,24 +145,49 @@ export const stream = (model, context, options = {}) => {
143
145
  const inferenceMaxTokens = options.maxTokens ?? (isAnthropicClaudeModel(model) ? model.maxTokens : undefined);
144
146
  const initialSystemMessage = getInitialSystemMessage(normalizedContext.messages);
145
147
  const initialSystemPrompt = initialSystemMessage ? getSystemMessageText(initialSystemMessage) : undefined;
146
- let commandInput = {
147
- modelId: model.id,
148
- messages: convertMessages(normalizedContext, model, cacheRetention, options.env),
149
- system: buildSystemPrompt(initialSystemPrompt, model, cacheRetention, options.env),
150
- inferenceConfig: {
151
- ...(inferenceMaxTokens !== undefined && { maxTokens: inferenceMaxTokens }),
152
- ...(options.temperature !== undefined && { temperature: options.temperature }),
153
- },
154
- toolConfig: convertToolConfig(getCurrentTools(normalizedContext.messages), options.toolChoice, supportsStrictMode),
155
- additionalModelRequestFields: buildAdditionalModelRequestFields(model, options),
156
- ...(options.requestMetadata !== undefined && { requestMetadata: options.requestMetadata }),
157
- };
158
- const nextCommandInput = await options?.onPayload?.(commandInput, model);
159
- if (nextCommandInput !== undefined) {
160
- commandInput = nextCommandInput;
148
+ let disablePreferredStrictTools = false;
149
+ let response;
150
+ for (;;) {
151
+ const tools = convertToolConfig(getCurrentTools(normalizedContext.messages), options.toolChoice, supportsStrictMode, disablePreferredStrictTools);
152
+ let commandInput = {
153
+ modelId: model.id,
154
+ messages: convertMessages(normalizedContext, model, cacheRetention, options.env),
155
+ system: buildSystemPrompt(initialSystemPrompt, model, cacheRetention, options.env),
156
+ inferenceConfig: {
157
+ ...(inferenceMaxTokens !== undefined && { maxTokens: inferenceMaxTokens }),
158
+ ...(options.temperature !== undefined && { temperature: options.temperature }),
159
+ },
160
+ toolConfig: tools.toolConfig,
161
+ additionalModelRequestFields: buildAdditionalModelRequestFields(model, options),
162
+ ...(options.requestMetadata !== undefined && { requestMetadata: options.requestMetadata }),
163
+ };
164
+ const nextCommandInput = await options?.onPayload?.(commandInput, model);
165
+ if (nextCommandInput !== undefined) {
166
+ commandInput = nextCommandInput;
167
+ }
168
+ try {
169
+ response = await client.send(new ConverseStreamCommand(commandInput), { abortSignal: options.signal });
170
+ break;
171
+ }
172
+ catch (error) {
173
+ // Bedrock checks the tool schemas before it starts the stream, so a retry never repeats streamed output.
174
+ if (options.signal?.aborted ||
175
+ disablePreferredStrictTools ||
176
+ !tools.hasPreferredStrictTools ||
177
+ !(error instanceof BedrockRuntimeServiceException) ||
178
+ error.name !== "ValidationException" ||
179
+ !isStrictToolLimitErrorMessage(error.message)) {
180
+ throw error;
181
+ }
182
+ disablePreferredStrictTools = true;
183
+ appendAssistantMessageDiagnostic(output, {
184
+ type: "bedrock_strict_tools_fallback",
185
+ timestamp: Date.now(),
186
+ error: { message: error.message },
187
+ details: { reason: "strict_tool_limits_exceeded" },
188
+ });
189
+ }
161
190
  }
162
- const command = new ConverseStreamCommand(commandInput);
163
- const response = await client.send(command, { abortSignal: options.signal });
164
191
  responseRequestId = normalizeDiagnosticValue(response.$metadata.requestId);
165
192
  if (!observedRawResponse && response.$metadata.httpStatusCode !== undefined) {
166
193
  const responseHeaders = {};
@@ -178,13 +205,13 @@ export const stream = (model, context, options = {}) => {
178
205
  stream.push({ type: "start", partial: output });
179
206
  }
180
207
  else if (item.contentBlockStart) {
181
- handleContentBlockStart(item.contentBlockStart, blocks, output, stream);
208
+ handleContentBlockStart(item.contentBlockStart, openBlocks, output, stream);
182
209
  }
183
210
  else if (item.contentBlockDelta) {
184
- handleContentBlockDelta(item.contentBlockDelta, blocks, output, stream);
211
+ handleContentBlockDelta(item.contentBlockDelta, openBlocks, output, stream);
185
212
  }
186
213
  else if (item.contentBlockStop) {
187
- handleContentBlockStop(item.contentBlockStop, blocks, output, stream);
214
+ handleContentBlockStop(item.contentBlockStop, openBlocks, output, stream);
188
215
  }
189
216
  else if (item.messageStop) {
190
217
  output.rawStopReason = item.messageStop.stopReason;
@@ -223,15 +250,12 @@ export const stream = (model, context, options = {}) => {
223
250
  throw new Error(output.errorMessage || "An unknown error occurred");
224
251
  }
225
252
  // A stream can settle without stopping every block, so finalize here too.
226
- for (const block of output.content)
227
- finalizeStreamingBlock(block);
253
+ flushOpenBlocks(openBlocks, output);
228
254
  stream.push({ type: "done", reason: output.stopReason, message: output });
229
255
  stream.end();
230
256
  }
231
257
  catch (error) {
232
- for (const block of output.content) {
233
- finalizeStreamingBlock(block);
234
- }
258
+ flushOpenBlocks(openBlocks, output);
235
259
  output.stopReason = options.signal?.aborted ? "aborted" : "error";
236
260
  output.errorMessage = formatBedrockError(error);
237
261
  if (output.stopReason === "error") {
@@ -337,6 +361,16 @@ function isReservedHeader(key) {
337
361
  const lower = key.toLowerCase();
338
362
  return lower.startsWith("x-amz-") || RESERVED_HEADER_EXACT.has(lower);
339
363
  }
364
+ /**
365
+ * The client identity as AWS SDK user agent pairs. The SDK appends them to its own `User-Agent` and escapes characters
366
+ * that are not valid in a user agent token, so the detailed form is reduced to name and version.
367
+ */
368
+ function bedrockUserAgent(identity) {
369
+ const mode = identity?.userAgent ?? "detailed";
370
+ if (typeof mode === "object")
371
+ return mode.custom;
372
+ return mode === "short" ? [["pi"]] : [["pi", getClientVersion(identity)]];
373
+ }
340
374
  /**
341
375
  * Attach caller-supplied headers to the outgoing Bedrock request via a Smithy
342
376
  * `build`-step middleware. The `build` step runs after request serialisation but
@@ -424,59 +458,60 @@ export const streamSimple = (model, context, options) => {
424
458
  thinkingBudgets: options.thinkingBudgets,
425
459
  });
426
460
  };
427
- function handleContentBlockStart(event, blocks, output, stream) {
428
- const index = event.contentBlockIndex;
461
+ function handleContentBlockStart(event, openBlocks, output, stream) {
429
462
  const start = event.start;
430
463
  if (start?.toolUse) {
431
- const block = {
464
+ output.content.push({
432
465
  type: "toolCall",
433
466
  id: start.toolUse.toolUseId || "",
434
467
  name: start.toolUse.name || "",
435
468
  arguments: {},
436
- partialJson: "",
437
- index,
438
- };
439
- output.content.push(block);
440
- stream.push({ type: "toolcall_start", contentIndex: blocks.length - 1, partial: output });
469
+ });
470
+ const contentIndex = output.content.length - 1;
471
+ openBlocks.set(event.contentBlockIndex, { contentIndex, arguments: new ToolCallArgumentsStream() });
472
+ stream.push({ type: "toolcall_start", contentIndex, partial: output });
441
473
  }
442
474
  }
443
- function handleContentBlockDelta(event, blocks, output, stream) {
475
+ function handleContentBlockDelta(event, openBlocks, output, stream) {
444
476
  const contentBlockIndex = event.contentBlockIndex;
445
477
  const delta = event.delta;
446
- let index = blocks.findIndex((b) => b.index === contentBlockIndex);
447
- let block = blocks[index];
478
+ let open = openBlocks.get(contentBlockIndex);
479
+ let block = open === undefined ? undefined : output.content[open.contentIndex];
448
480
  if (delta?.text !== undefined) {
449
481
  // If no text block exists yet, create one, as `handleContentBlockStart` is not sent for text blocks
450
- if (!block) {
451
- const newBlock = { type: "text", text: "", index: contentBlockIndex };
452
- output.content.push(newBlock);
453
- index = blocks.length - 1;
454
- block = blocks[index];
455
- stream.push({ type: "text_start", contentIndex: index, partial: output });
482
+ if (!open) {
483
+ output.content.push({ type: "text", text: "" });
484
+ open = { contentIndex: output.content.length - 1 };
485
+ openBlocks.set(contentBlockIndex, open);
486
+ block = output.content[open.contentIndex];
487
+ stream.push({ type: "text_start", contentIndex: open.contentIndex, partial: output });
456
488
  }
457
- if (block.type === "text") {
489
+ if (block?.type === "text") {
458
490
  block.text += delta.text;
459
- stream.push({ type: "text_delta", contentIndex: index, delta: delta.text, partial: output });
491
+ stream.push({ type: "text_delta", contentIndex: open.contentIndex, delta: delta.text, partial: output });
460
492
  }
461
493
  }
462
- else if (delta?.toolUse && block?.type === "toolCall") {
463
- block.partialJson = (block.partialJson || "") + (delta.toolUse.input || "");
464
- block.arguments = parseStreamingJson(block.partialJson);
465
- stream.push({ type: "toolcall_delta", contentIndex: index, delta: delta.toolUse.input || "", partial: output });
494
+ else if (delta?.toolUse && block?.type === "toolCall" && open?.arguments !== undefined) {
495
+ block.arguments = open.arguments.append(delta.toolUse.input || "");
496
+ stream.push({
497
+ type: "toolcall_delta",
498
+ contentIndex: open.contentIndex,
499
+ delta: delta.toolUse.input || "",
500
+ partial: output,
501
+ });
466
502
  }
467
503
  else if (delta?.reasoningContent) {
468
- let thinkingBlock = block;
469
- let thinkingIndex = index;
470
- if (!thinkingBlock) {
471
- const newBlock = { type: "thinking", thinking: "", thinkingSignature: "", index: contentBlockIndex };
472
- output.content.push(newBlock);
473
- thinkingIndex = blocks.length - 1;
474
- thinkingBlock = blocks[thinkingIndex];
475
- stream.push({ type: "thinking_start", contentIndex: thinkingIndex, partial: output });
504
+ if (!open) {
505
+ output.content.push({ type: "thinking", thinking: "", thinkingSignature: "" });
506
+ open = { contentIndex: output.content.length - 1 };
507
+ openBlocks.set(contentBlockIndex, open);
508
+ block = output.content[open.contentIndex];
509
+ stream.push({ type: "thinking_start", contentIndex: open.contentIndex, partial: output });
476
510
  }
477
- if (thinkingBlock?.type === "thinking") {
511
+ if (block?.type === "thinking") {
512
+ const thinkingIndex = open.contentIndex;
478
513
  if (delta.reasoningContent.text) {
479
- thinkingBlock.thinking += delta.reasoningContent.text;
514
+ block.thinking += delta.reasoningContent.text;
480
515
  stream.push({
481
516
  type: "thinking_delta",
482
517
  contentIndex: thinkingIndex,
@@ -486,18 +521,17 @@ function handleContentBlockDelta(event, blocks, output, stream) {
486
521
  }
487
522
  // `thinkingSignature` holds either an Anthropic signature or an opaque redacted
488
523
  // payload, never both: mixing them would corrupt whichever arrived first.
489
- if (delta.reasoningContent.signature && !thinkingBlock.redacted) {
490
- thinkingBlock.thinkingSignature =
491
- (thinkingBlock.thinkingSignature || "") + delta.reasoningContent.signature;
524
+ if (delta.reasoningContent.signature && !block.redacted) {
525
+ block.thinkingSignature = (block.thinkingSignature || "") + delta.reasoningContent.signature;
492
526
  }
493
527
  if (delta.reasoningContent.redactedContent?.length) {
494
528
  // Encrypted reasoning from non-Anthropic models on Bedrock (e.g. OpenAI GPT-5.6).
495
529
  // The payload is opaque, so keep it verbatim in `thinkingSignature` the way the
496
530
  // Anthropic path stores redacted thinking, and replay it on the next turn.
497
- if (!thinkingBlock.redacted) {
498
- thinkingBlock.redacted = true;
499
- thinkingBlock.thinkingSignature = "";
500
- thinkingBlock.thinking += REDACTED_THINKING_PLACEHOLDER;
531
+ if (!block.redacted) {
532
+ block.redacted = true;
533
+ block.thinkingSignature = "";
534
+ block.thinking += REDACTED_THINKING_PLACEHOLDER;
501
535
  stream.push({
502
536
  type: "thinking_delta",
503
537
  contentIndex: thinkingIndex,
@@ -505,32 +539,29 @@ function handleContentBlockDelta(event, blocks, output, stream) {
505
539
  partial: output,
506
540
  });
507
541
  }
508
- thinkingBlock.redactedChunks ??= [];
509
- thinkingBlock.redactedChunks.push(delta.reasoningContent.redactedContent);
542
+ open.redactedChunks ??= [];
543
+ open.redactedChunks.push(delta.reasoningContent.redactedContent);
510
544
  }
511
545
  }
512
546
  }
513
547
  }
514
548
  /**
515
- * Encodes buffered encrypted reasoning into `thinkingSignature` and drops the scratch
516
- * buffer, which must never reach a persisted message: `Uint8Array` serializes to an
517
- * index-keyed object roughly ten times the size of the base64 payload.
549
+ * Encodes buffered encrypted reasoning into `thinkingSignature`. The chunks stay in the stream state, never on the
550
+ * block: `Uint8Array` is not JSON and serializes to an index-keyed object roughly ten times the size of the base64
551
+ * payload.
518
552
  */
519
- function flushRedactedContent(block) {
520
- if (block.type !== "thinking" || !block.redactedChunks)
553
+ function flushRedactedContent(open, output) {
554
+ const block = output.content[open.contentIndex];
555
+ if (block?.type !== "thinking" || !open.redactedChunks)
521
556
  return;
522
- block.thinkingSignature = bytesToBase64(block.redactedChunks);
523
- delete block.redactedChunks;
557
+ block.thinkingSignature = bytesToBase64(open.redactedChunks);
558
+ open.redactedChunks = undefined;
524
559
  }
525
- /**
526
- * Strips every streaming scratch field. Runs from the terminal paths as well as
527
- * `contentBlockStop`, because a stream can settle without stopping each block.
528
- */
529
- function finalizeStreamingBlock(block) {
530
- delete block.index;
531
- // partialJson is only a streaming scratch buffer; never persist it.
532
- delete block.partialJson;
533
- flushRedactedContent(block);
560
+ /** Ends the stream state of blocks a stream settled without stopping. */
561
+ function flushOpenBlocks(openBlocks, output) {
562
+ for (const open of openBlocks.values())
563
+ flushRedactedContent(open, output);
564
+ openBlocks.clear();
534
565
  }
535
566
  function handleMetadata(event, model, output) {
536
567
  if (event.usage) {
@@ -543,25 +574,24 @@ function handleMetadata(event, model, output) {
543
574
  calculateCost(model, output.usage);
544
575
  }
545
576
  }
546
- function handleContentBlockStop(event, blocks, output, stream) {
547
- const index = blocks.findIndex((b) => b.index === event.contentBlockIndex);
548
- const block = blocks[index];
549
- if (!block)
577
+ function handleContentBlockStop(event, openBlocks, output, stream) {
578
+ const open = openBlocks.get(event.contentBlockIndex);
579
+ if (!open)
550
580
  return;
551
- delete block.index;
581
+ openBlocks.delete(event.contentBlockIndex);
582
+ const index = open.contentIndex;
583
+ const block = output.content[index];
552
584
  switch (block.type) {
553
585
  case "text":
554
586
  stream.push({ type: "text_end", contentIndex: index, content: block.text, partial: output });
555
587
  break;
556
588
  case "thinking":
557
- flushRedactedContent(block);
589
+ flushRedactedContent(open, output);
558
590
  stream.push({ type: "thinking_end", contentIndex: index, content: block.thinking, partial: output });
559
591
  break;
560
592
  case "toolCall":
561
- block.arguments = parseStreamingJson(block.partialJson);
562
- // Finalize in-place and strip the scratch buffer so replay only
563
- // carries parsed arguments.
564
- delete block.partialJson;
593
+ if (open.arguments !== undefined)
594
+ Object.assign(block, open.arguments.finish());
565
595
  stream.push({ type: "toolcall_end", contentIndex: index, toolCall: block, partial: output });
566
596
  break;
567
597
  }
@@ -586,6 +616,7 @@ function supportsAdaptiveThinking(modelId, modelName) {
586
616
  s.includes("opus-5") ||
587
617
  s.includes("sonnet-4-6") ||
588
618
  s.includes("sonnet-5") ||
619
+ s.includes("haiku-5") ||
589
620
  s.includes("fable-5"));
590
621
  }
591
622
  function supportsNativeXhighEffort(model) {
@@ -594,6 +625,7 @@ function supportsNativeXhighEffort(model) {
594
625
  s.includes("opus-4-8") ||
595
626
  s.includes("opus-5") ||
596
627
  s.includes("sonnet-5") ||
628
+ s.includes("haiku-5") ||
597
629
  s.includes("fable-5"));
598
630
  }
599
631
  /**
@@ -606,6 +638,7 @@ function supportsThinkingBlockBinding(model) {
606
638
  s.includes("opus-4-8") ||
607
639
  s.includes("opus-5") ||
608
640
  s.includes("sonnet-5") ||
641
+ s.includes("haiku-5") ||
609
642
  s.includes("fable-5"));
610
643
  }
611
644
  function mapThinkingLevelToEffort(model, level) {
@@ -675,8 +708,8 @@ function supportsPromptCaching(model, env) {
675
708
  return true;
676
709
  return false;
677
710
  }
678
- // Claude 5 models (fable-5, opus-5, sonnet-5)
679
- if (candidates.some((s) => s.includes("fable-5") || s.includes("opus-5") || s.includes("sonnet-5")))
711
+ // Claude 5 models (fable-5, opus-5, sonnet-5, haiku-5)
712
+ if (candidates.some((s) => s.includes("fable-5") || s.includes("opus-5") || s.includes("sonnet-5") || s.includes("haiku-5")))
680
713
  return true;
681
714
  // Claude 4.x models (opus-4, sonnet-4, haiku-4)
682
715
  if (candidates.some((s) => s.includes("-4-")))
@@ -867,30 +900,28 @@ function convertMessages(context, model, cacheRetention, env) {
867
900
  // Collect all consecutive toolResult messages into a single user message
868
901
  // Bedrock requires all tool results to be in one message
869
902
  const toolResults = [];
870
- // Add current tool result with all content blocks combined
871
- toolResults.push({
872
- toolResult: {
873
- toolUseId: m.toolCallId,
874
- content: convertToolResultContent(m.content),
875
- status: m.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,
876
- },
877
- });
878
- // Look ahead for consecutive toolResult messages
879
- let j = i + 1;
903
+ // Claude rejects error tool results that contain anything but text, so for Claude their
904
+ // images follow all tool results of the turn (#10794). Other models keep them in place.
905
+ const errorImages = [];
906
+ let j = i;
880
907
  while (j < transformedMessages.length && transformedMessages[j].role === "toolResult") {
881
- const nextMsg = transformedMessages[j];
908
+ const toolMsg = transformedMessages[j];
909
+ const split = isAnthropicClaudeModel(model) ? splitErrorToolResultImages(toolMsg) : undefined;
882
910
  toolResults.push({
883
911
  toolResult: {
884
- toolUseId: nextMsg.toolCallId,
885
- content: convertToolResultContent(nextMsg.content),
886
- status: nextMsg.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,
912
+ toolUseId: toolMsg.toolCallId,
913
+ content: convertToolResultContent(split?.content ?? toolMsg.content),
914
+ status: toolMsg.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,
887
915
  },
888
916
  });
917
+ if (split) {
918
+ errorImages.push({ text: split.caption }, ...split.images.map((image) => ({ image: createImageBlock(image.mimeType, image.data) })));
919
+ }
889
920
  j++;
890
921
  }
891
922
  // Skip the messages we've already processed
892
923
  i = j - 1;
893
- result.push({ role: ConversationRole.USER, content: toolResults });
924
+ result.push({ role: ConversationRole.USER, content: [...toolResults, ...errorImages] });
894
925
  break;
895
926
  }
896
927
  default:
@@ -911,13 +942,17 @@ function convertMessages(context, model, cacheRetention, env) {
911
942
  }
912
943
  return result;
913
944
  }
914
- function convertToolConfig(tools, toolChoice, supportsStrictMode) {
915
- if (!tools?.length)
916
- return undefined;
917
- if (toolChoice === "none")
918
- return undefined;
945
+ function convertToolConfig(tools, toolChoice, supportsStrictMode, disablePreferredStrictTools) {
946
+ if (!tools?.length || toolChoice === "none")
947
+ return { toolConfig: undefined, hasPreferredStrictTools: false };
948
+ let hasPreferredStrictTools = false;
919
949
  const bedrockTools = tools.map((tool) => {
920
- const strict = resolveJsonSchemaStrictSampling(tool, supportsStrictMode);
950
+ const preferred = prefersJsonSchemaStrictSampling(tool);
951
+ const strict = disablePreferredStrictTools && preferred
952
+ ? undefined
953
+ : resolveJsonSchemaStrictSampling(tool, supportsStrictMode);
954
+ if (strict === true && preferred)
955
+ hasPreferredStrictTools = true;
921
956
  return {
922
957
  toolSpec: {
923
958
  name: tool.name,
@@ -940,7 +975,7 @@ function convertToolConfig(tools, toolChoice, supportsStrictMode) {
940
975
  bedrockToolChoice = { tool: { name: toolChoice.name } };
941
976
  }
942
977
  }
943
- return { tools: bedrockTools, toolChoice: bedrockToolChoice };
978
+ return { toolConfig: { tools: bedrockTools, toolChoice: bedrockToolChoice }, hasPreferredStrictTools };
944
979
  }
945
980
  function mapStopReason(reason) {
946
981
  switch (reason) {
@@ -1053,8 +1088,36 @@ function buildAdditionalModelRequestFields(model, options) {
1053
1088
  }
1054
1089
  return result;
1055
1090
  }
1091
+ const candidates = getModelMatchCandidates(model.id, model.name);
1092
+ if (candidates.some((s) => s.includes("gpt-oss"))) {
1093
+ return { reasoning_effort: OPENAI_GPT_OSS_EFFORT[options.reasoning] };
1094
+ }
1095
+ if (candidates.some((s) => s.includes("gpt-"))) {
1096
+ const mapped = model.thinkingLevelMap?.[options.reasoning];
1097
+ return {
1098
+ reasoning: { effort: typeof mapped === "string" ? mapped : OPENAI_GPT_EFFORT[options.reasoning] },
1099
+ };
1100
+ }
1056
1101
  return undefined;
1057
1102
  }
1103
+ /** OpenAI GPT models (GPT-5.x, GPT-6) take a nested `reasoning.effort` and reject `minimal`. */
1104
+ const OPENAI_GPT_EFFORT = {
1105
+ minimal: "low",
1106
+ low: "low",
1107
+ medium: "medium",
1108
+ high: "high",
1109
+ xhigh: "xhigh",
1110
+ max: "max",
1111
+ };
1112
+ /** gpt-oss takes a flat `reasoning_effort` and only accepts low, medium and high. */
1113
+ const OPENAI_GPT_OSS_EFFORT = {
1114
+ minimal: "low",
1115
+ low: "low",
1116
+ medium: "medium",
1117
+ high: "high",
1118
+ xhigh: "high",
1119
+ max: "high",
1120
+ };
1058
1121
  function createImageBlock(mimeType, data) {
1059
1122
  let format;
1060
1123
  switch (mimeType) {