@fractaal/pi-ai 0.86.9 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/README.md +105 -45
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +180 -141
  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 +8 -10
  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 +130 -96
  10. package/dist/api/bedrock-converse-stream.js.map +1 -1
  11. package/dist/api/classifier-shared.d.ts +21 -0
  12. package/dist/api/classifier-shared.d.ts.map +1 -0
  13. package/dist/api/classifier-shared.js +99 -0
  14. package/dist/api/classifier-shared.js.map +1 -0
  15. package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -1
  16. package/dist/api/cloudflare-workers-ai-system-one.js +10 -1
  17. package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -1
  18. package/dist/api/constrained-sampling.d.ts +11 -1
  19. package/dist/api/constrained-sampling.d.ts.map +1 -1
  20. package/dist/api/constrained-sampling.js +33 -18
  21. package/dist/api/constrained-sampling.js.map +1 -1
  22. package/dist/api/google-generative-ai.d.ts.map +1 -1
  23. package/dist/api/google-generative-ai.js +4 -10
  24. package/dist/api/google-generative-ai.js.map +1 -1
  25. package/dist/api/google-shared.d.ts +2 -1
  26. package/dist/api/google-shared.d.ts.map +1 -1
  27. package/dist/api/google-shared.js +60 -3
  28. package/dist/api/google-shared.js.map +1 -1
  29. package/dist/api/google-vertex.d.ts.map +1 -1
  30. package/dist/api/google-vertex.js +9 -15
  31. package/dist/api/google-vertex.js.map +1 -1
  32. package/dist/api/lazy.d.ts +7 -2
  33. package/dist/api/lazy.d.ts.map +1 -1
  34. package/dist/api/lazy.js +28 -8
  35. package/dist/api/lazy.js.map +1 -1
  36. package/dist/api/llama-cpp-classify.d.ts.map +1 -1
  37. package/dist/api/llama-cpp-classify.js +4 -1
  38. package/dist/api/llama-cpp-classify.js.map +1 -1
  39. package/dist/api/mistral-conversations.d.ts.map +1 -1
  40. package/dist/api/mistral-conversations.js +50 -60
  41. package/dist/api/mistral-conversations.js.map +1 -1
  42. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  43. package/dist/api/openai-codex-responses.js +23 -14
  44. package/dist/api/openai-codex-responses.js.map +1 -1
  45. package/dist/api/openai-completions.d.ts.map +1 -1
  46. package/dist/api/openai-completions.js +83 -87
  47. package/dist/api/openai-completions.js.map +1 -1
  48. package/dist/api/openai-decisions.d.ts +4 -0
  49. package/dist/api/openai-decisions.d.ts.map +1 -0
  50. package/dist/api/openai-decisions.js +162 -0
  51. package/dist/api/openai-decisions.js.map +1 -0
  52. package/dist/api/openai-decisions.lazy.d.ts +3 -0
  53. package/dist/api/openai-decisions.lazy.d.ts.map +1 -0
  54. package/dist/api/openai-decisions.lazy.js +4 -0
  55. package/dist/api/openai-decisions.lazy.js.map +1 -0
  56. package/dist/api/openai-responses-shared.d.ts +26 -0
  57. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  58. package/dist/api/openai-responses-shared.js +132 -66
  59. package/dist/api/openai-responses-shared.js.map +1 -1
  60. package/dist/api/openai-responses.d.ts.map +1 -1
  61. package/dist/api/openai-responses.js +38 -19
  62. package/dist/api/openai-responses.js.map +1 -1
  63. package/dist/api/openrouter-images.d.ts.map +1 -1
  64. package/dist/api/openrouter-images.js +5 -3
  65. package/dist/api/openrouter-images.js.map +1 -1
  66. package/dist/api/pi-messages.d.ts +2 -0
  67. package/dist/api/pi-messages.d.ts.map +1 -1
  68. package/dist/api/pi-messages.js +18 -12
  69. package/dist/api/pi-messages.js.map +1 -1
  70. package/dist/api/simple-options.d.ts.map +1 -1
  71. package/dist/api/simple-options.js +2 -1
  72. package/dist/api/simple-options.js.map +1 -1
  73. package/dist/api/system-one-shared.d.ts +29 -3
  74. package/dist/api/system-one-shared.d.ts.map +1 -1
  75. package/dist/api/system-one-shared.js +54 -86
  76. package/dist/api/system-one-shared.js.map +1 -1
  77. package/dist/api/transform-messages.d.ts +16 -1
  78. package/dist/api/transform-messages.d.ts.map +1 -1
  79. package/dist/api/transform-messages.js +28 -15
  80. package/dist/api/transform-messages.js.map +1 -1
  81. package/dist/api/typesafe-system-one.d.ts.map +1 -1
  82. package/dist/api/typesafe-system-one.js +12 -1
  83. package/dist/api/typesafe-system-one.js.map +1 -1
  84. package/dist/auth/oauth/anthropic.d.ts.map +1 -1
  85. package/dist/auth/oauth/anthropic.js +14 -6
  86. package/dist/auth/oauth/anthropic.js.map +1 -1
  87. package/dist/auth/oauth/openai-chatgpt.js +1 -1
  88. package/dist/auth/oauth/openai-chatgpt.js.map +1 -1
  89. package/dist/auth/oauth/openai-codex.d.ts.map +1 -1
  90. package/dist/auth/oauth/openai-codex.js +4 -4
  91. package/dist/auth/oauth/openai-codex.js.map +1 -1
  92. package/dist/auth/types.d.ts +9 -0
  93. package/dist/auth/types.d.ts.map +1 -1
  94. package/dist/auth/types.js.map +1 -1
  95. package/dist/compat/extension-oauth-types.d.ts +4 -0
  96. package/dist/compat/extension-oauth-types.d.ts.map +1 -1
  97. package/dist/compat/extension-oauth-types.js.map +1 -1
  98. package/dist/index.d.ts +3 -1
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +3 -1
  101. package/dist/index.js.map +1 -1
  102. package/dist/models.d.ts +9 -0
  103. package/dist/models.d.ts.map +1 -1
  104. package/dist/models.js +23 -7
  105. package/dist/models.js.map +1 -1
  106. package/dist/providers/compat-schema.d.ts +509 -0
  107. package/dist/providers/compat-schema.d.ts.map +1 -0
  108. package/dist/providers/compat-schema.js +396 -0
  109. package/dist/providers/compat-schema.js.map +1 -0
  110. package/dist/providers/data/.manifest.json +1 -1
  111. package/dist/providers/data/amazon-bedrock.json +1 -1
  112. package/dist/providers/data/anthropic.json +1 -1
  113. package/dist/providers/data/azure.json +1 -1
  114. package/dist/providers/data/baseten.json +1 -1
  115. package/dist/providers/data/cerebras.json +1 -1
  116. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  117. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  118. package/dist/providers/data/fireworks.json +1 -1
  119. package/dist/providers/data/github-copilot.json +1 -1
  120. package/dist/providers/data/google-vertex.json +1 -1
  121. package/dist/providers/data/google.json +1 -1
  122. package/dist/providers/data/groq.json +1 -1
  123. package/dist/providers/data/huggingface.json +1 -1
  124. package/dist/providers/data/kimi-coding.json +1 -1
  125. package/dist/providers/data/meta.json +1 -1
  126. package/dist/providers/data/minimax-cn.json +1 -1
  127. package/dist/providers/data/minimax.json +1 -1
  128. package/dist/providers/data/mistral.json +1 -1
  129. package/dist/providers/data/moonshotai-cn.json +1 -1
  130. package/dist/providers/data/moonshotai.json +1 -1
  131. package/dist/providers/data/nvidia.json +1 -1
  132. package/dist/providers/data/openai-codex.json +1 -1
  133. package/dist/providers/data/openai.json +1 -1
  134. package/dist/providers/data/opencode-go.json +1 -1
  135. package/dist/providers/data/opencode.json +1 -1
  136. package/dist/providers/data/openrouter.json +1 -1
  137. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  138. package/dist/providers/data/qwen-token-plan.json +1 -1
  139. package/dist/providers/data/radius.json +1 -1
  140. package/dist/providers/data/together.json +1 -1
  141. package/dist/providers/data/typesafe.json +1 -1
  142. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  143. package/dist/providers/data/xai.json +1 -1
  144. package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  145. package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  146. package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  147. package/dist/providers/data/xiaomi.json +1 -1
  148. package/dist/providers/data/zai-coding-cn.json +1 -1
  149. package/dist/providers/faux.d.ts.map +1 -1
  150. package/dist/providers/faux.js +31 -9
  151. package/dist/providers/faux.js.map +1 -1
  152. package/dist/providers/kimi-coding.d.ts +1 -1
  153. package/dist/providers/kimi-coding.js +3 -3
  154. package/dist/providers/kimi-coding.js.map +1 -1
  155. package/dist/providers/model-schema.d.ts +91 -0
  156. package/dist/providers/model-schema.d.ts.map +1 -0
  157. package/dist/providers/model-schema.js +57 -0
  158. package/dist/providers/model-schema.js.map +1 -0
  159. package/dist/providers/openai.d.ts.map +1 -1
  160. package/dist/providers/openai.js +12 -3
  161. package/dist/providers/openai.js.map +1 -1
  162. package/dist/providers/opencode-go.d.ts +3 -1
  163. package/dist/providers/opencode-go.d.ts.map +1 -1
  164. package/dist/providers/opencode-go.js +2 -0
  165. package/dist/providers/opencode-go.js.map +1 -1
  166. package/dist/providers/openrouter-api.d.ts +40 -0
  167. package/dist/providers/openrouter-api.d.ts.map +1 -0
  168. package/dist/providers/openrouter-api.js +41 -0
  169. package/dist/providers/openrouter-api.js.map +1 -0
  170. package/dist/providers/openrouter.d.ts +11 -1
  171. package/dist/providers/openrouter.d.ts.map +1 -1
  172. package/dist/providers/openrouter.js +52 -1
  173. package/dist/providers/openrouter.js.map +1 -1
  174. package/dist/providers/radius-config.d.ts.map +1 -1
  175. package/dist/providers/radius-config.js +2 -1
  176. package/dist/providers/radius-config.js.map +1 -1
  177. package/dist/providers/radius.d.ts.map +1 -1
  178. package/dist/providers/radius.js +4 -12
  179. package/dist/providers/radius.js.map +1 -1
  180. package/dist/telemetry.d.ts +288 -0
  181. package/dist/telemetry.d.ts.map +1 -0
  182. package/dist/telemetry.js +192 -0
  183. package/dist/telemetry.js.map +1 -0
  184. package/dist/types.d.ts +44 -307
  185. package/dist/types.d.ts.map +1 -1
  186. package/dist/types.js.map +1 -1
  187. package/dist/utils/error-body.d.ts.map +1 -1
  188. package/dist/utils/error-body.js +2 -1
  189. package/dist/utils/error-body.js.map +1 -1
  190. package/dist/utils/estimate.js +1 -1
  191. package/dist/utils/estimate.js.map +1 -1
  192. package/dist/utils/event-stream.d.ts +10 -1
  193. package/dist/utils/event-stream.d.ts.map +1 -1
  194. package/dist/utils/event-stream.js +25 -0
  195. package/dist/utils/event-stream.js.map +1 -1
  196. package/dist/utils/identity.d.ts +65 -0
  197. package/dist/utils/identity.d.ts.map +1 -0
  198. package/dist/utils/identity.js +141 -0
  199. package/dist/utils/identity.js.map +1 -0
  200. package/dist/utils/json-parse.d.ts +10 -0
  201. package/dist/utils/json-parse.d.ts.map +1 -1
  202. package/dist/utils/json-parse.js +26 -1
  203. package/dist/utils/json-parse.js.map +1 -1
  204. package/dist/utils/model-operations.d.ts +3 -1
  205. package/dist/utils/model-operations.d.ts.map +1 -1
  206. package/dist/utils/model-operations.js +6 -0
  207. package/dist/utils/model-operations.js.map +1 -1
  208. package/dist/utils/openrouter-cost.d.ts +24 -0
  209. package/dist/utils/openrouter-cost.d.ts.map +1 -0
  210. package/dist/utils/openrouter-cost.js +34 -0
  211. package/dist/utils/openrouter-cost.js.map +1 -0
  212. package/dist/utils/overflow.d.ts +1 -0
  213. package/dist/utils/overflow.d.ts.map +1 -1
  214. package/dist/utils/overflow.js +6 -1
  215. package/dist/utils/overflow.js.map +1 -1
  216. package/dist/utils/provider-retry.d.ts +2 -0
  217. package/dist/utils/provider-retry.d.ts.map +1 -1
  218. package/dist/utils/provider-retry.js +2 -0
  219. package/dist/utils/provider-retry.js.map +1 -1
  220. package/dist/utils/retry.d.ts.map +1 -1
  221. package/dist/utils/retry.js +26 -10
  222. package/dist/utils/retry.js.map +1 -1
  223. package/dist/utils/streaming-json.d.ts +84 -0
  224. package/dist/utils/streaming-json.d.ts.map +1 -0
  225. package/dist/utils/streaming-json.js +513 -0
  226. package/dist/utils/streaming-json.js.map +1 -0
  227. package/dist/utils/text.d.ts +7 -0
  228. package/dist/utils/text.d.ts.map +1 -1
  229. package/dist/utils/text.js +9 -0
  230. package/dist/utils/text.js.map +1 -1
  231. package/dist/utils/transcript.d.ts +22 -8
  232. package/dist/utils/transcript.d.ts.map +1 -1
  233. package/dist/utils/transcript.js +29 -18
  234. package/dist/utils/transcript.js.map +1 -1
  235. package/dist/utils/validation.d.ts.map +1 -1
  236. package/dist/utils/validation.js +3 -0
  237. package/dist/utils/validation.js.map +1 -1
  238. package/dist/utils/version.d.ts +2 -0
  239. package/dist/utils/version.d.ts.map +1 -0
  240. package/dist/utils/version.js +3 -0
  241. package/dist/utils/version.js.map +1 -0
  242. package/package.json +3 -3
  243. package/dist/utils/assistant-message-frame.d.ts +0 -77
  244. package/dist/utils/assistant-message-frame.d.ts.map +0 -1
  245. package/dist/utils/assistant-message-frame.js +0 -425
  246. package/dist/utils/assistant-message-frame.js.map +0 -1
  247. package/dist/utils/pi-user-agent.d.ts +0 -2
  248. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  249. package/dist/utils/pi-user-agent.js +0 -12
  250. package/dist/utils/pi-user-agent.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"openai-completions.d.ts","sourceRoot":"","sources":["../../src/api/openai-completions.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAOX,0BAA0B,EAI1B,MAAM,sCAAsC,CAAC;AAE9C,OAAO,KAAK,EAOX,KAAK,EACL,uBAAuB,EAGvB,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAEb,eAAe,EAMf,MAAM,aAAa,CAAC;AAWrB,OAAO,EAIN,KAAK,iBAAiB,EACtB,MAAM,wBAAwB,CAAC;AAqGhC,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,8BAA8B,CAAC;IACpE,eAAe,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;IAC1E,2KAA2K;IAC3K,eAAe,CAAC,EAAE,eAAe,CAAC;CAClC;AAED,MAAM,WAAW,iCAAiC;IACjD,0BAA0B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzD;AAOD,KAAK,+BAA+B,GAAG,IAAI,CAC1C,QAAQ,CAAC,uBAAuB,CAAC,EAC/B,oBAAoB,GACpB,6BAA6B,GAC7B,0BAA0B,GAC1B,gCAAgC,GAChC,+BAA+B,GAC/B,cAAc,CAChB,GAAG;IACH,kBAAkB,CAAC,EAAE,uBAAuB,CAAC,oBAAoB,CAAC,CAAC;IACnE,2BAA2B,CAAC,EAAE,uBAAuB,CAAC,6BAA6B,CAAC,CAAC;IACrF,wBAAwB,CAAC,EAAE,uBAAuB,CAAC,0BAA0B,CAAC,CAAC;IAC/E,8BAA8B,CAAC,EAAE,uBAAuB,CAAC,gCAAgC,CAAC,CAAC;IAC3F,6BAA6B,CAAC,EAAE,uBAAuB,CAAC,+BAA+B,CAAC,CAAC;IACzF,YAAY,CAAC,EAAE,uBAAuB,CAAC,cAAc,CAAC,CAAC;CACvD,CAAC;AAuHF,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,wBAAwB,CA8ajF,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAmBlF,CAAC;AAsbF,wBAAgB,eAAe,CAC9B,KAAK,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAClC,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,+BAA+B,EACvC,OAAO,CAAC,EAAE,iCAAiC,GACzC,0BAA0B,EAAE,CA0R9B"}
1
+ {"version":3,"file":"openai-completions.d.ts","sourceRoot":"","sources":["../../src/api/openai-completions.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAOX,0BAA0B,EAI1B,MAAM,sCAAsC,CAAC;AAE9C,OAAO,KAAK,EAOX,KAAK,EACL,uBAAuB,EAGvB,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAEb,eAAe,EAMf,MAAM,aAAa,CAAC;AAgBrB,OAAO,EAIN,KAAK,iBAAiB,EACtB,MAAM,wBAAwB,CAAC;AAsGhC,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,8BAA8B,CAAC;IACpE,eAAe,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;IAC1E,2KAA2K;IAC3K,eAAe,CAAC,EAAE,eAAe,CAAC;CAClC;AAED,MAAM,WAAW,iCAAiC;IACjD,0BAA0B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzD;AAOD,KAAK,+BAA+B,GAAG,IAAI,CAC1C,QAAQ,CAAC,uBAAuB,CAAC,EAC/B,oBAAoB,GACpB,6BAA6B,GAC7B,0BAA0B,GAC1B,gCAAgC,GAChC,+BAA+B,GAC/B,cAAc,CAChB,GAAG;IACH,kBAAkB,CAAC,EAAE,uBAAuB,CAAC,oBAAoB,CAAC,CAAC;IACnE,2BAA2B,CAAC,EAAE,uBAAuB,CAAC,6BAA6B,CAAC,CAAC;IACrF,wBAAwB,CAAC,EAAE,uBAAuB,CAAC,0BAA0B,CAAC,CAAC;IAC/E,8BAA8B,CAAC,EAAE,uBAAuB,CAAC,gCAAgC,CAAC,CAAC;IAC3F,6BAA6B,CAAC,EAAE,uBAAuB,CAAC,+BAA+B,CAAC,CAAC;IACzF,YAAY,CAAC,EAAE,uBAAuB,CAAC,cAAc,CAAC,CAAC;CACvD,CAAC;AAuHF,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,wBAAwB,CAsZjF,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAmBlF,CAAC;AAybF,wBAAgB,eAAe,CAC9B,KAAK,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAClC,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,+BAA+B,EACvC,OAAO,CAAC,EAAE,iCAAiC,GACzC,0BAA0B,EAAE,CA8R9B"}
@@ -4,14 +4,15 @@ import { formatProviderError, normalizeProviderError } from "../utils/error-body
4
4
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
5
5
  import { shortHash } from "../utils/hash.js";
6
6
  import { headersToRecord } from "../utils/headers.js";
7
- import { parseStreamingJson } from "../utils/json-parse.js";
8
- import { getPiUserAgent } from "../utils/pi-user-agent.js";
7
+ import { getIdentityHeaders } from "../utils/identity.js";
8
+ import { applyOpenRouterReportedCost, isOpenRouterModel, } from "../utils/openrouter-cost.js";
9
9
  import { getProviderEnvValue } from "../utils/provider-env.js";
10
10
  import { retryProviderRequest } from "../utils/provider-retry.js";
11
11
  import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
12
+ import { ToolCallArgumentsStream } from "../utils/streaming-json.js";
12
13
  import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
13
14
  import { getDeclaredTools, resolveTranscript, resolveTranscriptTools, } from "../utils/transcript.js";
14
- import { appendGrammarToolInputJsonDelta, createGrammarToolInputProperties, getGrammarToolInput, getJsonSchemaToolParameters, resolveGrammarConstrainedSampling, resolveJsonSchemaStrictSampling, } from "./constrained-sampling.js";
15
+ import { appendGrammarToolInputJsonDelta, closeGrammarToolInputJson, createGrammarToolInputProperties, getGrammarToolInput, getJsonSchemaToolParameters, resolveGrammarConstrainedSampling, resolveJsonSchemaStrictSampling, } from "./constrained-sampling.js";
15
16
  import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
16
17
  import { clampOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
17
18
  import { buildBaseOptions, clampThinkingBudgetToAnswerRoom, resolveSamplingParams, thinkingBudgetForLevel, } from "./simple-options.js";
@@ -183,7 +184,7 @@ export const stream = (model, context, options) => {
183
184
  const grammarToolInputProperties = createGrammarToolInputProperties(getDeclaredTools(normalizedContext.messages), compat.supportsOpenAIGrammarTools);
184
185
  const cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);
185
186
  const cacheSessionId = cacheRetention === "none" ? undefined : options?.sessionId;
186
- const client = createClient(model, normalizedContext, apiKey, options?.headers, options?.fetch, cacheSessionId, compat);
187
+ const client = createClient(model, normalizedContext, apiKey, options?.headers, options?.identity, options?.fetch, cacheSessionId, compat);
187
188
  let params = buildParams(model, normalizedContext, options, compat, cacheRetention, grammarToolInputProperties);
188
189
  const nextParams = await options?.onPayload?.(params, model);
189
190
  if (nextParams !== undefined) {
@@ -206,23 +207,14 @@ export const stream = (model, context, options) => {
206
207
  let hasFinishReason = false;
207
208
  const toolCallBlocksByIndex = new Map();
208
209
  const toolCallBlocksById = new Map();
210
+ const toolCallStates = new Map();
209
211
  const blocks = output.content;
210
212
  const getContentIndex = (block) => blocks.indexOf(block);
211
- const getCustomToolCallInput = (block) => {
212
- const property = block.customInput?.property;
213
- if (property === undefined)
214
- return "";
215
- const value = block.arguments[property];
216
- return typeof value === "string" ? value : "";
217
- };
218
- const appendCustomToolCallInput = (block, nextInput, close) => {
219
- const customInput = block.customInput;
220
- if (!customInput)
221
- return undefined;
222
- const delta = appendGrammarToolInputJsonDelta(customInput.jsonBuffer, customInput.property, nextInput, close);
223
- block.arguments = { [customInput.property]: nextInput };
224
- return delta;
225
- };
213
+ const customInput = (property) => ({
214
+ kind: "custom",
215
+ property,
216
+ buffer: { input: "", started: false, closed: false },
217
+ });
226
218
  const finishBlock = (block) => {
227
219
  const contentIndex = getContentIndex(block);
228
220
  if (contentIndex === -1) {
@@ -246,8 +238,10 @@ export const stream = (model, context, options) => {
246
238
  });
247
239
  }
248
240
  else if (block.type === "toolCall") {
249
- if (block.customInput) {
250
- const delta = appendCustomToolCallInput(block, getCustomToolCallInput(block), true);
241
+ const input = toolCallStates.get(block).input;
242
+ toolCallStates.delete(block);
243
+ if (input.kind === "custom") {
244
+ const delta = closeGrammarToolInputJson(input.buffer, input.property, undefined);
251
245
  if (delta !== undefined) {
252
246
  stream.push({
253
247
  type: "toolcall_delta",
@@ -258,13 +252,8 @@ export const stream = (model, context, options) => {
258
252
  }
259
253
  }
260
254
  else {
261
- block.arguments = parseStreamingJson(block.partialArgs);
255
+ Object.assign(block, input.arguments.finish());
262
256
  }
263
- // Finalize in-place and strip the scratch buffers so replay only
264
- // carries parsed arguments.
265
- delete block.partialArgs;
266
- delete block.customInput;
267
- delete block.streamIndex;
268
257
  stream.push({
269
258
  type: "toolcall_end",
270
259
  contentIndex,
@@ -304,18 +293,18 @@ export const stream = (model, context, options) => {
304
293
  // Note: the "input" fallback here should/must not be taken. in case the LLM makes up
305
294
  // a tool we don't knwo about, we at least have a place to stash our stuff.
306
295
  const customInputProperty = toolCall.custom && !toolCall.function ? (grammarToolInputProperties.get(name) ?? "input") : undefined;
307
- const hasCustomInput = customInputProperty !== undefined;
308
296
  block = {
309
297
  type: "toolCall",
310
298
  id: toolCall.id || "",
311
299
  name,
312
- arguments: hasCustomInput ? { [customInputProperty]: "" } : {},
313
- partialArgs: hasCustomInput ? undefined : "",
314
- customInput: hasCustomInput
315
- ? { property: customInputProperty, jsonBuffer: { input: "", started: false, closed: false } }
316
- : undefined,
317
- streamIndex,
300
+ arguments: customInputProperty !== undefined ? { [customInputProperty]: "" } : {},
318
301
  };
302
+ toolCallStates.set(block, {
303
+ streamIndex,
304
+ input: customInputProperty !== undefined
305
+ ? customInput(customInputProperty)
306
+ : { kind: "json", arguments: new ToolCallArgumentsStream() },
307
+ });
319
308
  if (streamIndex !== undefined) {
320
309
  toolCallBlocksByIndex.set(streamIndex, block);
321
310
  }
@@ -329,8 +318,9 @@ export const stream = (model, context, options) => {
329
318
  partial: output,
330
319
  });
331
320
  }
332
- if (streamIndex !== undefined && block.streamIndex === undefined) {
333
- block.streamIndex = streamIndex;
321
+ const state = toolCallStates.get(block);
322
+ if (streamIndex !== undefined && state.streamIndex === undefined) {
323
+ state.streamIndex = streamIndex;
334
324
  toolCallBlocksByIndex.set(streamIndex, block);
335
325
  }
336
326
  if (toolCall.id) {
@@ -339,16 +329,12 @@ export const stream = (model, context, options) => {
339
329
  if (!block.name && name) {
340
330
  block.name = name;
341
331
  }
342
- if (toolCall.custom && !toolCall.function && !block.customInput) {
332
+ if (toolCall.custom && !toolCall.function && state.input.kind !== "custom") {
343
333
  const customInputProperty = grammarToolInputProperties.get(block.name) ?? "input";
344
334
  block.arguments = { [customInputProperty]: "" };
345
- block.customInput = {
346
- property: customInputProperty,
347
- jsonBuffer: { input: "", started: false, closed: false },
348
- };
349
- delete block.partialArgs;
335
+ state.input = customInput(customInputProperty);
350
336
  }
351
- return block;
337
+ return { block, state };
352
338
  };
353
339
  for await (const chunk of openaiStream) {
354
340
  await options?.onProviderStreamEvent?.(chunk, model);
@@ -381,18 +367,8 @@ export const stream = (model, context, options) => {
381
367
  hasFinishReason = true;
382
368
  }
383
369
  if (choice.delta) {
384
- if (choice.delta.content !== null &&
385
- choice.delta.content !== undefined &&
386
- choice.delta.content.length > 0) {
387
- const block = ensureTextBlock();
388
- block.text += choice.delta.content;
389
- stream.push({
390
- type: "text_delta",
391
- contentIndex: getContentIndex(block),
392
- delta: choice.delta.content,
393
- partial: output,
394
- });
395
- }
370
+ // Handle reasoning before content: some proxies (e.g. LiteLLM) aggregate reasoning and
371
+ // answer into one delta, and the thinking block must precede the text block.
396
372
  // Some endpoints return reasoning in reasoning_content (llama.cpp),
397
373
  // or reasoning (other openai compatible endpoints)
398
374
  // Use the first non-empty reasoning field to avoid duplication
@@ -423,9 +399,34 @@ export const stream = (model, context, options) => {
423
399
  });
424
400
  }
425
401
  }
402
+ const reasoningDetails = choice.delta.reasoning_details;
403
+ if (Array.isArray(reasoningDetails)) {
404
+ for (const detail of reasoningDetails) {
405
+ if (!isOpenAIReasoningDetail(detail))
406
+ continue;
407
+ ensureThinkingBlock("");
408
+ streamedReasoningDetails ??= [];
409
+ // Keep provider replay data in the existing signature slot. OpenRouter streams
410
+ // reasoning_details as deltas: consecutive text/summary deltas are merged into
411
+ // logical entries, while encrypted entries remain opaque and discrete.
412
+ appendOpenAIReasoningDetail(streamedReasoningDetails, detail);
413
+ }
414
+ }
415
+ if (choice.delta.content !== null &&
416
+ choice.delta.content !== undefined &&
417
+ choice.delta.content.length > 0) {
418
+ const block = ensureTextBlock();
419
+ block.text += choice.delta.content;
420
+ stream.push({
421
+ type: "text_delta",
422
+ contentIndex: getContentIndex(block),
423
+ delta: choice.delta.content,
424
+ partial: output,
425
+ });
426
+ }
426
427
  if (choice?.delta?.tool_calls) {
427
428
  for (const toolCall of choice.delta.tool_calls) {
428
- const block = ensureToolCallBlock(toolCall);
429
+ const { block, state } = ensureToolCallBlock(toolCall);
429
430
  if (!block.id && toolCall.id) {
430
431
  block.id = toolCall.id;
431
432
  toolCallBlocksById.set(toolCall.id, block);
@@ -435,14 +436,15 @@ export const stream = (model, context, options) => {
435
436
  block.name = name;
436
437
  }
437
438
  let delta = "";
438
- if (toolCall.function?.arguments) {
439
+ const input = state.input;
440
+ if (toolCall.function?.arguments && input.kind === "json") {
439
441
  delta = toolCall.function.arguments;
440
- block.partialArgs = (block.partialArgs ?? "") + toolCall.function.arguments;
441
- block.arguments = parseStreamingJson(block.partialArgs);
442
+ block.arguments = input.arguments.append(delta);
442
443
  }
443
- else if (toolCall.custom?.input) {
444
- const nextInput = getCustomToolCallInput(block) + toolCall.custom.input;
445
- delta = appendCustomToolCallInput(block, nextInput, false) ?? "";
444
+ else if (toolCall.custom?.input && input.kind === "custom") {
445
+ delta =
446
+ appendGrammarToolInputJsonDelta(input.buffer, input.property, toolCall.custom.input) ?? "";
447
+ block.arguments = { [input.property]: input.buffer.input };
446
448
  }
447
449
  stream.push({
448
450
  type: "toolcall_delta",
@@ -452,19 +454,6 @@ export const stream = (model, context, options) => {
452
454
  });
453
455
  }
454
456
  }
455
- const reasoningDetails = choice.delta.reasoning_details;
456
- if (Array.isArray(reasoningDetails)) {
457
- for (const detail of reasoningDetails) {
458
- if (!isOpenAIReasoningDetail(detail))
459
- continue;
460
- ensureThinkingBlock("");
461
- streamedReasoningDetails ??= [];
462
- // Keep provider replay data in the existing signature slot. OpenRouter streams
463
- // reasoning_details as deltas: consecutive text/summary deltas are merged into
464
- // logical entries, while encrypted entries remain opaque and discrete.
465
- appendOpenAIReasoningDetail(streamedReasoningDetails, detail);
466
- }
467
- }
468
457
  }
469
458
  }
470
459
  for (const block of blocks) {
@@ -493,11 +482,6 @@ export const stream = (model, context, options) => {
493
482
  if (block.type === "thinking") {
494
483
  applyStreamedReasoningDetails(block);
495
484
  }
496
- delete block.index;
497
- // Streaming scratch buffers are only used during parsing; never persist them.
498
- delete block.partialArgs;
499
- delete block.customInput;
500
- delete block.streamIndex;
501
485
  }
502
486
  output.stopReason = options?.signal?.aborted ? "aborted" : "error";
503
487
  output.errorMessage = formatProviderError(normalizeProviderError(error));
@@ -529,8 +513,8 @@ export const streamSimple = (model, context, options) => {
529
513
  thinkingBudgets: options?.thinkingBudgets,
530
514
  });
531
515
  };
532
- function createClient(model, context, apiKey, optionsHeaders, fetch, sessionId, compat = getCompat(model)) {
533
- const headers = { "User-Agent": getPiUserAgent(), ...model.headers };
516
+ function createClient(model, context, apiKey, optionsHeaders, identity, fetch, sessionId, compat = getCompat(model)) {
517
+ const headers = { ...getIdentityHeaders(model, identity), ...model.headers };
534
518
  if (model.provider === "github-copilot") {
535
519
  const hasImages = hasCopilotVisionInput(context.messages);
536
520
  const copilotHeaders = buildCopilotDynamicHeaders({
@@ -564,7 +548,9 @@ function createClient(model, context, apiKey, optionsHeaders, fetch, sessionId,
564
548
  });
565
549
  }
566
550
  function buildParams(model, context, options, compat = getCompat(model), cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env), grammarToolInputProperties = createGrammarToolInputProperties(getDeclaredTools(context.messages), compat.supportsOpenAIGrammarTools)) {
567
- const transcriptTools = resolveTranscriptTools(context.messages, compat.supportsMidConvoSystemMessages === true && compat.supportsMidConvoToolAdditions === true);
551
+ const transcriptTools = resolveTranscriptTools(context.messages, compat.supportsMidConvoSystemMessages === true && compat.supportsMidConvoToolAdditions === true
552
+ ? "additions"
553
+ : "none");
568
554
  const messages = convertMessages(model, context, compat, {
569
555
  grammarToolInputProperties,
570
556
  });
@@ -895,9 +881,12 @@ export function convertMessages(model, context, compat, options) {
895
881
  return id;
896
882
  };
897
883
  const transformedMessages = transformMessages(normalizedContext.messages, model, (id) => normalizeToolCallId(id));
898
- const transcriptTools = resolveTranscriptTools(normalizedContext.messages, compat.supportsMidConvoSystemMessages === true && compat.supportsMidConvoToolAdditions === true);
884
+ const transcriptTools = resolveTranscriptTools(normalizedContext.messages, compat.supportsMidConvoSystemMessages === true && compat.supportsMidConvoToolAdditions === true
885
+ ? "additions"
886
+ : "none");
899
887
  const instructionRole = model.reasoning && compat.supportsDeveloperRole ? "developer" : "system";
900
888
  let lastRole = null;
889
+ let systemIndex = 0;
901
890
  for (let i = 0; i < transformedMessages.length; i++) {
902
891
  const msg = transformedMessages[i];
903
892
  // Some providers don't allow user messages directly after tool results
@@ -909,7 +898,8 @@ export function convertMessages(model, context, compat, options) {
909
898
  });
910
899
  }
911
900
  if (msg.role === "system") {
912
- const addedTools = i > 0 && transcriptTools.anchorsAdditions ? (msg.toolsAdded ?? []) : [];
901
+ // transformMessages keeps system messages in order, so their position matches the transcript.
902
+ const addedTools = systemIndex++ >= transcriptTools.foldedSystemMessages ? (msg.toolsAdded ?? []) : [];
913
903
  if (addedTools.length > 0) {
914
904
  const kimiToolMessage = {
915
905
  role: "system",
@@ -1074,7 +1064,7 @@ export function convertMessages(model, context, compat, options) {
1074
1064
  .join("\n");
1075
1065
  const hasImages = toolMsg.content.some((c) => c.type === "image");
1076
1066
  // Always send tool result with text (or placeholder if only images)
1077
- const hasText = textResult.length > 0;
1067
+ const hasText = textResult.trim().length > 0;
1078
1068
  const toolResultText = hasText ? textResult : hasImages ? "(see attached image)" : "(no tool output)";
1079
1069
  // Some providers require the 'name' field in tool results
1080
1070
  const toolResultMsg = {
@@ -1160,7 +1150,10 @@ function convertTools(tools, compat) {
1160
1150
  };
1161
1151
  });
1162
1152
  }
1163
- function parseChunkUsage(rawUsage, model) {
1153
+ function parseChunkUsage(
1154
+ // OpenRouter adds billing fields to streamed usage at runtime,
1155
+ // although the OpenAI SDK does not type those fields.
1156
+ rawUsage, model) {
1164
1157
  const promptTokens = rawUsage.prompt_tokens || 0;
1165
1158
  const cacheReadTokens = rawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.prompt_cache_hit_tokens ?? rawUsage.cached_tokens ?? 0;
1166
1159
  const cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;
@@ -1188,6 +1181,9 @@ function parseChunkUsage(rawUsage, model) {
1188
1181
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
1189
1182
  };
1190
1183
  calculateCost(model, usage);
1184
+ if (isOpenRouterModel(model)) {
1185
+ applyOpenRouterReportedCost(usage, rawUsage);
1186
+ }
1191
1187
  return usage;
1192
1188
  }
1193
1189
  function mapStopReason(reason) {