@draht/ai 2026.7.7 → 2026.7.12-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 (340) hide show
  1. package/dist/api/anthropic-messages.d.ts.map +1 -1
  2. package/dist/api/anthropic-messages.js +7 -4
  3. package/dist/api/anthropic-messages.js.map +1 -1
  4. package/dist/api/anthropic-messages.lazy.d.ts.map +1 -1
  5. package/dist/api/azure-openai-responses.d.ts +1 -1
  6. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  7. package/dist/api/azure-openai-responses.js +2 -3
  8. package/dist/api/azure-openai-responses.js.map +1 -1
  9. package/dist/api/azure-openai-responses.lazy.d.ts.map +1 -1
  10. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  11. package/dist/api/bedrock-converse-stream.js +1 -1
  12. package/dist/api/bedrock-converse-stream.js.map +1 -1
  13. package/dist/api/bedrock-converse-stream.lazy.d.ts.map +1 -1
  14. package/dist/api/bedrock-converse-stream.lazy.js.map +1 -1
  15. package/dist/api/cloudflare.d.ts.map +1 -1
  16. package/dist/api/cloudflare.js.map +1 -1
  17. package/dist/api/github-copilot-headers.d.ts.map +1 -1
  18. package/dist/api/github-copilot-headers.js.map +1 -1
  19. package/dist/api/google-generative-ai.d.ts.map +1 -1
  20. package/dist/api/google-generative-ai.js.map +1 -1
  21. package/dist/api/google-generative-ai.lazy.d.ts.map +1 -1
  22. package/dist/api/google-shared.d.ts.map +1 -1
  23. package/dist/api/google-shared.js.map +1 -1
  24. package/dist/api/google-vertex.d.ts.map +1 -1
  25. package/dist/api/google-vertex.js.map +1 -1
  26. package/dist/api/google-vertex.lazy.d.ts.map +1 -1
  27. package/dist/api/lazy.d.ts.map +1 -1
  28. package/dist/api/lazy.js.map +1 -1
  29. package/dist/api/mistral-conversations.d.ts.map +1 -1
  30. package/dist/api/mistral-conversations.js.map +1 -1
  31. package/dist/api/mistral-conversations.lazy.d.ts.map +1 -1
  32. package/dist/api/openai-codex-responses.d.ts +1 -1
  33. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  34. package/dist/api/openai-codex-responses.js +2 -9
  35. package/dist/api/openai-codex-responses.js.map +1 -1
  36. package/dist/api/openai-codex-responses.lazy.d.ts.map +1 -1
  37. package/dist/api/openai-completions.d.ts +1 -1
  38. package/dist/api/openai-completions.d.ts.map +1 -1
  39. package/dist/api/openai-completions.js +2 -3
  40. package/dist/api/openai-completions.js.map +1 -1
  41. package/dist/api/openai-completions.lazy.d.ts.map +1 -1
  42. package/dist/api/openai-prompt-cache.d.ts.map +1 -1
  43. package/dist/api/openai-prompt-cache.js.map +1 -1
  44. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  45. package/dist/api/openai-responses-shared.js +6 -4
  46. package/dist/api/openai-responses-shared.js.map +1 -1
  47. package/dist/api/openai-responses.d.ts +1 -1
  48. package/dist/api/openai-responses.d.ts.map +1 -1
  49. package/dist/api/openai-responses.js +2 -3
  50. package/dist/api/openai-responses.js.map +1 -1
  51. package/dist/api/openai-responses.lazy.d.ts.map +1 -1
  52. package/dist/api/openrouter-images.d.ts.map +1 -1
  53. package/dist/api/openrouter-images.js.map +1 -1
  54. package/dist/api/openrouter-images.lazy.d.ts.map +1 -1
  55. package/dist/api/simple-options.d.ts +0 -5
  56. package/dist/api/simple-options.d.ts.map +1 -1
  57. package/dist/api/simple-options.js +1 -7
  58. package/dist/api/simple-options.js.map +1 -1
  59. package/dist/api/transform-messages.d.ts.map +1 -1
  60. package/dist/api/transform-messages.js.map +1 -1
  61. package/dist/auth/context.d.ts.map +1 -1
  62. package/dist/auth/context.js.map +1 -1
  63. package/dist/auth/credential-store.d.ts.map +1 -1
  64. package/dist/auth/credential-store.js +4 -2
  65. package/dist/auth/credential-store.js.map +1 -1
  66. package/dist/auth/helpers.d.ts.map +1 -1
  67. package/dist/auth/helpers.js.map +1 -1
  68. package/dist/auth/resolve.d.ts.map +1 -1
  69. package/dist/auth/resolve.js +0 -1
  70. package/dist/auth/resolve.js.map +1 -1
  71. package/dist/auth/types.d.ts.map +1 -1
  72. package/dist/bedrock-provider.d.ts.map +1 -1
  73. package/dist/cli.d.ts.map +1 -1
  74. package/dist/cli.js.map +1 -1
  75. package/dist/compat.d.ts.map +1 -1
  76. package/dist/compat.js.map +1 -1
  77. package/dist/env-api-keys.d.ts.map +1 -1
  78. package/dist/env-api-keys.js.map +1 -1
  79. package/dist/image-models.d.ts.map +1 -1
  80. package/dist/image-models.generated.d.ts.map +1 -1
  81. package/dist/image-models.js.map +1 -1
  82. package/dist/images-api-registry.d.ts.map +1 -1
  83. package/dist/images-api-registry.js.map +1 -1
  84. package/dist/images-models.d.ts.map +1 -1
  85. package/dist/images-models.js +1 -3
  86. package/dist/images-models.js.map +1 -1
  87. package/dist/images.d.ts.map +1 -1
  88. package/dist/images.js.map +1 -1
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/legacy-api-aliases.d.ts.map +1 -1
  91. package/dist/models.d.ts.map +1 -1
  92. package/dist/models.generated.d.ts +1108 -269
  93. package/dist/models.generated.d.ts.map +1 -1
  94. package/dist/models.js +15 -8
  95. package/dist/models.js.map +1 -1
  96. package/dist/oauth.d.ts.map +1 -1
  97. package/dist/providers/all.d.ts.map +1 -1
  98. package/dist/providers/all.js.map +1 -1
  99. package/dist/providers/amazon-bedrock.d.ts.map +1 -1
  100. package/dist/providers/amazon-bedrock.js.map +1 -1
  101. package/dist/providers/amazon-bedrock.models.d.ts +62 -5
  102. package/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
  103. package/dist/providers/amazon-bedrock.models.js +32 -20
  104. package/dist/providers/amazon-bedrock.models.js.map +1 -1
  105. package/dist/providers/ant-ling.d.ts.map +1 -1
  106. package/dist/providers/ant-ling.js.map +1 -1
  107. package/dist/providers/ant-ling.models.d.ts.map +1 -1
  108. package/dist/providers/anthropic.d.ts.map +1 -1
  109. package/dist/providers/anthropic.js.map +1 -1
  110. package/dist/providers/anthropic.models.d.ts +11 -1
  111. package/dist/providers/anthropic.models.d.ts.map +1 -1
  112. package/dist/providers/anthropic.models.js +6 -4
  113. package/dist/providers/anthropic.models.js.map +1 -1
  114. package/dist/providers/azure-openai-responses.d.ts.map +1 -1
  115. package/dist/providers/azure-openai-responses.js.map +1 -1
  116. package/dist/providers/azure-openai-responses.models.d.ts +83 -0
  117. package/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
  118. package/dist/providers/azure-openai-responses.models.js +71 -0
  119. package/dist/providers/azure-openai-responses.models.js.map +1 -1
  120. package/dist/providers/cerebras.d.ts.map +1 -1
  121. package/dist/providers/cerebras.js.map +1 -1
  122. package/dist/providers/cerebras.models.d.ts.map +1 -1
  123. package/dist/providers/cloudflare-ai-gateway.d.ts.map +1 -1
  124. package/dist/providers/cloudflare-ai-gateway.js.map +1 -1
  125. package/dist/providers/cloudflare-ai-gateway.models.d.ts +11 -1
  126. package/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
  127. package/dist/providers/cloudflare-ai-gateway.models.js +6 -4
  128. package/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
  129. package/dist/providers/cloudflare-auth.d.ts.map +1 -1
  130. package/dist/providers/cloudflare-auth.js.map +1 -1
  131. package/dist/providers/cloudflare-workers-ai.d.ts.map +1 -1
  132. package/dist/providers/cloudflare-workers-ai.js.map +1 -1
  133. package/dist/providers/cloudflare-workers-ai.models.d.ts.map +1 -1
  134. package/dist/providers/deepseek.d.ts.map +1 -1
  135. package/dist/providers/deepseek.js.map +1 -1
  136. package/dist/providers/deepseek.models.d.ts +2 -2
  137. package/dist/providers/deepseek.models.d.ts.map +1 -1
  138. package/dist/providers/deepseek.models.js +2 -2
  139. package/dist/providers/deepseek.models.js.map +1 -1
  140. package/dist/providers/faux.d.ts.map +1 -1
  141. package/dist/providers/faux.js.map +1 -1
  142. package/dist/providers/fireworks.d.ts.map +1 -1
  143. package/dist/providers/fireworks.js.map +1 -1
  144. package/dist/providers/fireworks.models.d.ts +2 -2
  145. package/dist/providers/fireworks.models.d.ts.map +1 -1
  146. package/dist/providers/fireworks.models.js +3 -3
  147. package/dist/providers/fireworks.models.js.map +1 -1
  148. package/dist/providers/github-copilot.d.ts.map +1 -1
  149. package/dist/providers/github-copilot.js.map +1 -1
  150. package/dist/providers/github-copilot.models.d.ts +95 -2
  151. package/dist/providers/github-copilot.models.d.ts.map +1 -1
  152. package/dist/providers/github-copilot.models.js +68 -10
  153. package/dist/providers/github-copilot.models.js.map +1 -1
  154. package/dist/providers/google-vertex.d.ts.map +1 -1
  155. package/dist/providers/google-vertex.js.map +1 -1
  156. package/dist/providers/google-vertex.models.d.ts.map +1 -1
  157. package/dist/providers/google.d.ts.map +1 -1
  158. package/dist/providers/google.js.map +1 -1
  159. package/dist/providers/google.models.d.ts.map +1 -1
  160. package/dist/providers/groq.d.ts.map +1 -1
  161. package/dist/providers/groq.js.map +1 -1
  162. package/dist/providers/groq.models.d.ts.map +1 -1
  163. package/dist/providers/huggingface.d.ts.map +1 -1
  164. package/dist/providers/huggingface.js.map +1 -1
  165. package/dist/providers/huggingface.models.d.ts.map +1 -1
  166. package/dist/providers/images/register-builtins.d.ts.map +1 -1
  167. package/dist/providers/images/register-builtins.js.map +1 -1
  168. package/dist/providers/kimi-coding.d.ts.map +1 -1
  169. package/dist/providers/kimi-coding.js.map +1 -1
  170. package/dist/providers/kimi-coding.models.d.ts.map +1 -1
  171. package/dist/providers/minimax-cn.d.ts.map +1 -1
  172. package/dist/providers/minimax-cn.js.map +1 -1
  173. package/dist/providers/minimax-cn.models.d.ts.map +1 -1
  174. package/dist/providers/minimax.d.ts.map +1 -1
  175. package/dist/providers/minimax.js.map +1 -1
  176. package/dist/providers/minimax.models.d.ts.map +1 -1
  177. package/dist/providers/mistral.d.ts.map +1 -1
  178. package/dist/providers/mistral.js.map +1 -1
  179. package/dist/providers/mistral.models.d.ts.map +1 -1
  180. package/dist/providers/moonshotai-cn.d.ts.map +1 -1
  181. package/dist/providers/moonshotai-cn.js.map +1 -1
  182. package/dist/providers/moonshotai-cn.models.d.ts.map +1 -1
  183. package/dist/providers/moonshotai.d.ts.map +1 -1
  184. package/dist/providers/moonshotai.js.map +1 -1
  185. package/dist/providers/moonshotai.models.d.ts.map +1 -1
  186. package/dist/providers/nvidia.d.ts.map +1 -1
  187. package/dist/providers/nvidia.js.map +1 -1
  188. package/dist/providers/nvidia.models.d.ts.map +1 -1
  189. package/dist/providers/openai-codex.d.ts.map +1 -1
  190. package/dist/providers/openai-codex.js.map +1 -1
  191. package/dist/providers/openai-codex.models.d.ts +101 -0
  192. package/dist/providers/openai-codex.models.d.ts.map +1 -1
  193. package/dist/providers/openai-codex.models.js +59 -0
  194. package/dist/providers/openai-codex.models.js.map +1 -1
  195. package/dist/providers/openai.d.ts.map +1 -1
  196. package/dist/providers/openai.js.map +1 -1
  197. package/dist/providers/openai.models.d.ts +132 -0
  198. package/dist/providers/openai.models.d.ts.map +1 -1
  199. package/dist/providers/openai.models.js +78 -0
  200. package/dist/providers/openai.models.js.map +1 -1
  201. package/dist/providers/opencode-go.d.ts.map +1 -1
  202. package/dist/providers/opencode-go.js.map +1 -1
  203. package/dist/providers/opencode-go.models.d.ts +3 -3
  204. package/dist/providers/opencode-go.models.d.ts.map +1 -1
  205. package/dist/providers/opencode-go.models.js +3 -3
  206. package/dist/providers/opencode-go.models.js.map +1 -1
  207. package/dist/providers/opencode.d.ts.map +1 -1
  208. package/dist/providers/opencode.js.map +1 -1
  209. package/dist/providers/opencode.models.d.ts +124 -4
  210. package/dist/providers/opencode.models.d.ts.map +1 -1
  211. package/dist/providers/opencode.models.js +99 -7
  212. package/dist/providers/opencode.models.js.map +1 -1
  213. package/dist/providers/openrouter-images.d.ts.map +1 -1
  214. package/dist/providers/openrouter-images.js.map +1 -1
  215. package/dist/providers/openrouter.d.ts.map +1 -1
  216. package/dist/providers/openrouter.js.map +1 -1
  217. package/dist/providers/openrouter.models.d.ts +284 -85
  218. package/dist/providers/openrouter.models.d.ts.map +1 -1
  219. package/dist/providers/openrouter.models.js +296 -144
  220. package/dist/providers/openrouter.models.js.map +1 -1
  221. package/dist/providers/together.d.ts.map +1 -1
  222. package/dist/providers/together.js.map +1 -1
  223. package/dist/providers/together.models.d.ts.map +1 -1
  224. package/dist/providers/vercel-ai-gateway.d.ts.map +1 -1
  225. package/dist/providers/vercel-ai-gateway.js.map +1 -1
  226. package/dist/providers/vercel-ai-gateway.models.d.ts +139 -1
  227. package/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  228. package/dist/providers/vercel-ai-gateway.models.js +132 -8
  229. package/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  230. package/dist/providers/xai.d.ts.map +1 -1
  231. package/dist/providers/xai.js +6 -2
  232. package/dist/providers/xai.js.map +1 -1
  233. package/dist/providers/xai.models.d.ts +22 -0
  234. package/dist/providers/xai.models.d.ts.map +1 -1
  235. package/dist/providers/xai.models.js +18 -0
  236. package/dist/providers/xai.models.js.map +1 -1
  237. package/dist/providers/xiaomi-token-plan-ams.d.ts.map +1 -1
  238. package/dist/providers/xiaomi-token-plan-ams.js.map +1 -1
  239. package/dist/providers/xiaomi-token-plan-ams.models.d.ts +0 -42
  240. package/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
  241. package/dist/providers/xiaomi-token-plan-ams.models.js +9 -45
  242. package/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
  243. package/dist/providers/xiaomi-token-plan-cn.d.ts.map +1 -1
  244. package/dist/providers/xiaomi-token-plan-cn.js.map +1 -1
  245. package/dist/providers/xiaomi-token-plan-cn.models.d.ts +0 -42
  246. package/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
  247. package/dist/providers/xiaomi-token-plan-cn.models.js +9 -45
  248. package/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
  249. package/dist/providers/xiaomi-token-plan-sgp.d.ts.map +1 -1
  250. package/dist/providers/xiaomi-token-plan-sgp.js.map +1 -1
  251. package/dist/providers/xiaomi-token-plan-sgp.models.d.ts +0 -42
  252. package/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
  253. package/dist/providers/xiaomi-token-plan-sgp.models.js +9 -45
  254. package/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
  255. package/dist/providers/xiaomi.d.ts.map +1 -1
  256. package/dist/providers/xiaomi.js.map +1 -1
  257. package/dist/providers/xiaomi.models.d.ts.map +1 -1
  258. package/dist/providers/zai-coding-cn.d.ts.map +1 -1
  259. package/dist/providers/zai-coding-cn.js.map +1 -1
  260. package/dist/providers/zai-coding-cn.models.d.ts +1 -1
  261. package/dist/providers/zai-coding-cn.models.d.ts.map +1 -1
  262. package/dist/providers/zai-coding-cn.models.js +1 -1
  263. package/dist/providers/zai-coding-cn.models.js.map +1 -1
  264. package/dist/providers/zai.d.ts.map +1 -1
  265. package/dist/providers/zai.js.map +1 -1
  266. package/dist/providers/zai.models.d.ts +1 -1
  267. package/dist/providers/zai.models.d.ts.map +1 -1
  268. package/dist/providers/zai.models.js +1 -1
  269. package/dist/providers/zai.models.js.map +1 -1
  270. package/dist/session-resources.d.ts.map +1 -1
  271. package/dist/session-resources.js.map +1 -1
  272. package/dist/types.d.ts +15 -6
  273. package/dist/types.d.ts.map +1 -1
  274. package/dist/types.js.map +1 -1
  275. package/dist/utils/abort-signals.d.ts.map +1 -1
  276. package/dist/utils/abort-signals.js.map +1 -1
  277. package/dist/utils/diagnostics.d.ts.map +1 -1
  278. package/dist/utils/diagnostics.js.map +1 -1
  279. package/dist/utils/error-body.d.ts.map +1 -1
  280. package/dist/utils/error-body.js.map +1 -1
  281. package/dist/utils/estimate.d.ts +3 -3
  282. package/dist/utils/estimate.d.ts.map +1 -1
  283. package/dist/utils/estimate.js +17 -9
  284. package/dist/utils/estimate.js.map +1 -1
  285. package/dist/utils/event-stream.d.ts.map +1 -1
  286. package/dist/utils/event-stream.js +3 -7
  287. package/dist/utils/event-stream.js.map +1 -1
  288. package/dist/utils/hash.d.ts.map +1 -1
  289. package/dist/utils/hash.js.map +1 -1
  290. package/dist/utils/headers.d.ts.map +1 -1
  291. package/dist/utils/headers.js.map +1 -1
  292. package/dist/utils/json-parse.d.ts.map +1 -1
  293. package/dist/utils/json-parse.js.map +1 -1
  294. package/dist/utils/node-http-proxy.d.ts.map +1 -1
  295. package/dist/utils/node-http-proxy.js.map +1 -1
  296. package/dist/utils/oauth/anthropic.d.ts.map +1 -1
  297. package/dist/utils/oauth/anthropic.js.map +1 -1
  298. package/dist/utils/oauth/device-code.d.ts.map +1 -1
  299. package/dist/utils/oauth/device-code.js.map +1 -1
  300. package/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  301. package/dist/utils/oauth/github-copilot.js.map +1 -1
  302. package/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  303. package/dist/utils/oauth/google-antigravity.js.map +1 -1
  304. package/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  305. package/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  306. package/dist/utils/oauth/index.d.ts +1 -0
  307. package/dist/utils/oauth/index.d.ts.map +1 -1
  308. package/dist/utils/oauth/index.js +4 -0
  309. package/dist/utils/oauth/index.js.map +1 -1
  310. package/dist/utils/oauth/load.d.ts +1 -0
  311. package/dist/utils/oauth/load.d.ts.map +1 -1
  312. package/dist/utils/oauth/load.js +1 -0
  313. package/dist/utils/oauth/load.js.map +1 -1
  314. package/dist/utils/oauth/oauth-page.d.ts.map +1 -1
  315. package/dist/utils/oauth/oauth-page.js.map +1 -1
  316. package/dist/utils/oauth/openai-codex.d.ts.map +1 -1
  317. package/dist/utils/oauth/openai-codex.js.map +1 -1
  318. package/dist/utils/oauth/opencode-go.d.ts.map +1 -1
  319. package/dist/utils/oauth/opencode-go.js.map +1 -1
  320. package/dist/utils/oauth/pkce.d.ts.map +1 -1
  321. package/dist/utils/oauth/pkce.js.map +1 -1
  322. package/dist/utils/oauth/types.d.ts.map +1 -1
  323. package/dist/utils/oauth/xai.d.ts +34 -0
  324. package/dist/utils/oauth/xai.d.ts.map +1 -0
  325. package/dist/utils/oauth/xai.js +339 -0
  326. package/dist/utils/oauth/xai.js.map +1 -0
  327. package/dist/utils/overflow.d.ts.map +1 -1
  328. package/dist/utils/overflow.js.map +1 -1
  329. package/dist/utils/provider-env.d.ts.map +1 -1
  330. package/dist/utils/provider-env.js.map +1 -1
  331. package/dist/utils/retry.d.ts.map +1 -1
  332. package/dist/utils/retry.js +3 -0
  333. package/dist/utils/retry.js.map +1 -1
  334. package/dist/utils/sanitize-unicode.d.ts.map +1 -1
  335. package/dist/utils/sanitize-unicode.js.map +1 -1
  336. package/dist/utils/typebox-helpers.d.ts.map +1 -1
  337. package/dist/utils/typebox-helpers.js.map +1 -1
  338. package/dist/utils/validation.d.ts.map +1 -1
  339. package/dist/utils/validation.js.map +1 -1
  340. package/package.json +4 -4
@@ -0,0 +1,339 @@
1
+ /**
2
+ * xAI (Grok) OAuth flow — SuperGrok / X Premium+ subscription login.
3
+ *
4
+ * Mirrors the flow the official Grok CLI uses: PKCE authorization code
5
+ * against auth.x.ai's OIDC discovery document. Tokens are scoped for the
6
+ * Grok CLI proxy (cli-chat-proxy.grok.com) rather than the pay-per-token
7
+ * api.x.ai endpoint, so `toAuth`/`modifyModels` route requests there.
8
+ *
9
+ * NOTE: This module uses Node.js http.createServer for the OAuth callback
10
+ * server. It is only intended for CLI use, not browser environments.
11
+ */
12
+ import { getProviderEnvValue } from "../provider-env.js";
13
+ import { oauthErrorHtml, oauthSuccessHtml } from "./oauth-page.js";
14
+ import { generatePKCE } from "./pkce.js";
15
+ let nodeApis = null;
16
+ let nodeApisPromise = null;
17
+ const OAUTH_ISSUER = "https://auth.x.ai";
18
+ const DISCOVERY_URL = `${OAUTH_ISSUER}/.well-known/openid-configuration`;
19
+ const CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
20
+ const SCOPE = "openid profile email offline_access grok-cli:access api:access";
21
+ const CALLBACK_HOST = getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
22
+ const CALLBACK_PORT = 56121;
23
+ const CALLBACK_PATH = "/callback";
24
+ const REFRESH_SKEW_MS = 2 * 60 * 1000;
25
+ /** OAuth-authenticated requests are proxied through the Grok CLI endpoint, not api.x.ai directly. */
26
+ export const XAI_OAUTH_BASE_URL = "https://cli-chat-proxy.grok.com/v1";
27
+ async function getNodeApis() {
28
+ if (nodeApis)
29
+ return nodeApis;
30
+ if (!nodeApisPromise) {
31
+ if (typeof process === "undefined" || (!process.versions?.node && !process.versions?.bun)) {
32
+ throw new Error("xAI OAuth is only available in Node.js environments");
33
+ }
34
+ nodeApisPromise = import("node:http").then((httpModule) => ({
35
+ createServer: httpModule.createServer,
36
+ }));
37
+ }
38
+ nodeApis = await nodeApisPromise;
39
+ return nodeApis;
40
+ }
41
+ /** Reject discovery responses that don't point back at x.ai, in case DNS/discovery is ever compromised. */
42
+ function validateXaiEndpoint(url) {
43
+ const parsed = new URL(url);
44
+ const host = parsed.hostname.toLowerCase();
45
+ if (parsed.protocol !== "https:" || (host !== "x.ai" && !host.endsWith(".x.ai"))) {
46
+ throw new Error(`xAI OAuth discovery returned an unexpected endpoint: ${url}`);
47
+ }
48
+ return url;
49
+ }
50
+ async function discoverXaiEndpoints() {
51
+ const response = await fetch(DISCOVERY_URL, { headers: { Accept: "application/json" } });
52
+ if (!response.ok) {
53
+ throw new Error(`xAI OAuth discovery failed: ${response.status} ${await response.text()}`);
54
+ }
55
+ const data = (await response.json());
56
+ if (!data.authorization_endpoint || !data.token_endpoint) {
57
+ throw new Error("xAI OAuth discovery response did not include authorization/token endpoints");
58
+ }
59
+ return {
60
+ authorizationEndpoint: validateXaiEndpoint(data.authorization_endpoint),
61
+ tokenEndpoint: validateXaiEndpoint(data.token_endpoint),
62
+ };
63
+ }
64
+ function parseAuthorizationInput(input) {
65
+ const value = input.trim();
66
+ if (!value)
67
+ return {};
68
+ try {
69
+ const url = new URL(value);
70
+ return {
71
+ code: url.searchParams.get("code") ?? undefined,
72
+ state: url.searchParams.get("state") ?? undefined,
73
+ };
74
+ }
75
+ catch {
76
+ // not a URL
77
+ }
78
+ if (value.includes("code=")) {
79
+ const params = new URLSearchParams(value);
80
+ return {
81
+ code: params.get("code") ?? undefined,
82
+ state: params.get("state") ?? undefined,
83
+ };
84
+ }
85
+ return { code: value };
86
+ }
87
+ async function startCallbackServer(expectedState) {
88
+ const { createServer } = await getNodeApis();
89
+ return new Promise((resolve, reject) => {
90
+ let settleWait;
91
+ const waitForCodePromise = new Promise((resolveWait) => {
92
+ let settled = false;
93
+ settleWait = (value) => {
94
+ if (settled)
95
+ return;
96
+ settled = true;
97
+ resolveWait(value);
98
+ };
99
+ });
100
+ const server = createServer((req, res) => {
101
+ try {
102
+ const url = new URL(req.url || "", `http://${CALLBACK_HOST}`);
103
+ if (url.pathname !== CALLBACK_PATH) {
104
+ res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
105
+ res.end(oauthErrorHtml("Callback route not found."));
106
+ return;
107
+ }
108
+ const code = url.searchParams.get("code");
109
+ const state = url.searchParams.get("state");
110
+ const error = url.searchParams.get("error");
111
+ if (error) {
112
+ res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
113
+ res.end(oauthErrorHtml("xAI authentication did not complete.", `Error: ${error}`));
114
+ return;
115
+ }
116
+ if (!code || !state) {
117
+ res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
118
+ res.end(oauthErrorHtml("Missing code or state parameter."));
119
+ return;
120
+ }
121
+ if (state !== expectedState) {
122
+ res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
123
+ res.end(oauthErrorHtml("State mismatch."));
124
+ return;
125
+ }
126
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
127
+ res.end(oauthSuccessHtml("xAI authentication completed. You can close this window."));
128
+ settleWait?.({ code, state });
129
+ }
130
+ catch {
131
+ res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
132
+ res.end("Internal error");
133
+ }
134
+ });
135
+ server.on("error", (err) => {
136
+ reject(err);
137
+ });
138
+ server.listen(CALLBACK_PORT, CALLBACK_HOST, () => {
139
+ resolve({
140
+ server,
141
+ redirectUri: `http://${CALLBACK_HOST}:${CALLBACK_PORT}${CALLBACK_PATH}`,
142
+ cancelWait: () => {
143
+ settleWait?.(null);
144
+ },
145
+ waitForCode: () => waitForCodePromise,
146
+ });
147
+ });
148
+ });
149
+ }
150
+ async function postForm(url, body) {
151
+ const response = await fetch(url, {
152
+ method: "POST",
153
+ headers: {
154
+ "Content-Type": "application/x-www-form-urlencoded",
155
+ Accept: "application/json",
156
+ },
157
+ body: new URLSearchParams(body).toString(),
158
+ signal: AbortSignal.timeout(30_000),
159
+ });
160
+ const responseBody = await response.text();
161
+ if (!response.ok) {
162
+ throw new Error(`xAI token request failed. status=${response.status}; url=${url}; body=${responseBody}`);
163
+ }
164
+ return responseBody;
165
+ }
166
+ function credentialsFromTokenPayload(data, fallbackRefresh = "") {
167
+ if (!data.access_token) {
168
+ throw new Error("xAI token response did not include an access token");
169
+ }
170
+ const refresh = data.refresh_token || fallbackRefresh;
171
+ if (!refresh) {
172
+ throw new Error("xAI token response did not include a refresh token");
173
+ }
174
+ return {
175
+ access: data.access_token,
176
+ refresh,
177
+ expires: Date.now() + (data.expires_in ?? 3600) * 1000 - REFRESH_SKEW_MS,
178
+ };
179
+ }
180
+ /**
181
+ * Login with xAI OAuth (SuperGrok / X Premium+ subscription, authorization code + PKCE)
182
+ */
183
+ export async function loginXai(options) {
184
+ const discovery = await discoverXaiEndpoints();
185
+ const { verifier, challenge } = await generatePKCE();
186
+ const server = await startCallbackServer(verifier);
187
+ try {
188
+ const authParams = new URLSearchParams({
189
+ response_type: "code",
190
+ client_id: CLIENT_ID,
191
+ redirect_uri: server.redirectUri,
192
+ scope: SCOPE,
193
+ code_challenge: challenge,
194
+ code_challenge_method: "S256",
195
+ state: verifier,
196
+ });
197
+ options.onAuth({
198
+ url: `${discovery.authorizationEndpoint}?${authParams.toString()}`,
199
+ instructions: "Sign in with your SuperGrok or X Premium+ account. If the browser is on another machine, paste the final redirect URL here.",
200
+ });
201
+ let code;
202
+ if (options.onManualCodeInput) {
203
+ let manualInput;
204
+ let manualError;
205
+ const manualPromise = options
206
+ .onManualCodeInput()
207
+ .then((input) => {
208
+ manualInput = input;
209
+ server.cancelWait();
210
+ })
211
+ .catch((err) => {
212
+ manualError = err instanceof Error ? err : new Error(String(err));
213
+ server.cancelWait();
214
+ });
215
+ const result = await server.waitForCode();
216
+ if (manualError) {
217
+ throw manualError;
218
+ }
219
+ if (result?.code) {
220
+ code = result.code;
221
+ }
222
+ else if (manualInput) {
223
+ const parsed = parseAuthorizationInput(manualInput);
224
+ if (parsed.state && parsed.state !== verifier) {
225
+ throw new Error("OAuth state mismatch");
226
+ }
227
+ code = parsed.code;
228
+ }
229
+ if (!code) {
230
+ await manualPromise;
231
+ if (manualError) {
232
+ throw manualError;
233
+ }
234
+ if (manualInput) {
235
+ const parsed = parseAuthorizationInput(manualInput);
236
+ if (parsed.state && parsed.state !== verifier) {
237
+ throw new Error("OAuth state mismatch");
238
+ }
239
+ code = parsed.code;
240
+ }
241
+ }
242
+ }
243
+ else {
244
+ const result = await server.waitForCode();
245
+ if (result?.code) {
246
+ code = result.code;
247
+ }
248
+ }
249
+ if (!code) {
250
+ const input = await options.onPrompt({
251
+ message: "Paste the authorization code or full redirect URL:",
252
+ placeholder: server.redirectUri,
253
+ });
254
+ const parsed = parseAuthorizationInput(input);
255
+ if (parsed.state && parsed.state !== verifier) {
256
+ throw new Error("OAuth state mismatch");
257
+ }
258
+ code = parsed.code;
259
+ }
260
+ if (!code) {
261
+ throw new Error("Missing authorization code");
262
+ }
263
+ options.onProgress?.("Exchanging xAI authorization code...");
264
+ const responseBody = await postForm(discovery.tokenEndpoint, {
265
+ grant_type: "authorization_code",
266
+ client_id: CLIENT_ID,
267
+ code,
268
+ redirect_uri: server.redirectUri,
269
+ code_verifier: verifier,
270
+ });
271
+ return credentialsFromTokenPayload(JSON.parse(responseBody));
272
+ }
273
+ finally {
274
+ server.server.close();
275
+ }
276
+ }
277
+ /**
278
+ * Refresh xAI OAuth token
279
+ */
280
+ export async function refreshXaiToken(refreshToken) {
281
+ const discovery = await discoverXaiEndpoints();
282
+ const responseBody = await postForm(discovery.tokenEndpoint, {
283
+ grant_type: "refresh_token",
284
+ client_id: CLIENT_ID,
285
+ refresh_token: refreshToken,
286
+ });
287
+ return credentialsFromTokenPayload(JSON.parse(responseBody), refreshToken);
288
+ }
289
+ export const xaiOAuth = {
290
+ name: "xAI (Grok)",
291
+ async login(callbacks) {
292
+ // The manual_code prompt races the local callback server; abort it once
293
+ // the flow settles so the UI can dismiss the pending input.
294
+ const manualAbort = new AbortController();
295
+ try {
296
+ const credentials = await loginXai({
297
+ onAuth: (info) => callbacks.notify({ type: "auth_url", url: info.url, instructions: info.instructions }),
298
+ onProgress: (message) => callbacks.notify({ type: "progress", message }),
299
+ onPrompt: (prompt) => callbacks.prompt({ type: "text", message: prompt.message, placeholder: prompt.placeholder }),
300
+ onManualCodeInput: () => callbacks.prompt({
301
+ type: "manual_code",
302
+ message: "Complete login in your browser, or paste the authorization code / redirect URL here:",
303
+ placeholder: `http://${CALLBACK_HOST}:${CALLBACK_PORT}${CALLBACK_PATH}`,
304
+ signal: manualAbort.signal,
305
+ }),
306
+ });
307
+ return { ...credentials, type: "oauth" };
308
+ }
309
+ finally {
310
+ manualAbort.abort();
311
+ }
312
+ },
313
+ async refresh(credential) {
314
+ return { ...(await refreshXaiToken(credential.refresh)), type: "oauth" };
315
+ },
316
+ async toAuth(credential) {
317
+ return { apiKey: credential.access, baseUrl: XAI_OAUTH_BASE_URL };
318
+ },
319
+ };
320
+ export const xaiOAuthProvider = {
321
+ id: "xai",
322
+ name: "xAI (Grok)",
323
+ usesCallbackServer: true,
324
+ async login(callbacks) {
325
+ return loginXai({
326
+ onAuth: callbacks.onAuth,
327
+ onPrompt: callbacks.onPrompt,
328
+ onProgress: callbacks.onProgress,
329
+ onManualCodeInput: callbacks.onManualCodeInput,
330
+ });
331
+ },
332
+ async refreshToken(credentials) {
333
+ return refreshXaiToken(credentials.refresh);
334
+ },
335
+ getApiKey(credentials) {
336
+ return credentials.access;
337
+ },
338
+ };
339
+ //# sourceMappingURL=xai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/utils/oauth/xai.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * xAI (Grok) OAuth flow — SuperGrok / X Premium+ subscription login.\n *\n * Mirrors the flow the official Grok CLI uses: PKCE authorization code\n * against auth.x.ai's OIDC discovery document. Tokens are scoped for the\n * Grok CLI proxy (cli-chat-proxy.grok.com) rather than the pay-per-token\n * api.x.ai endpoint, so `toAuth`/`modifyModels` route requests there.\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback\n * server. It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport type { OAuthAuth } from \"../../auth/types.ts\";\nimport { getProviderEnvValue } from \"../provider-env.ts\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthPrompt, OAuthProviderInterface } from \"./types.ts\";\n\ntype NodeApis = {\n\tcreateServer: typeof import(\"node:http\").createServer;\n};\n\nlet nodeApis: NodeApis | null = null;\nlet nodeApisPromise: Promise<NodeApis> | null = null;\n\nconst OAUTH_ISSUER = \"https://auth.x.ai\";\nconst DISCOVERY_URL = `${OAUTH_ISSUER}/.well-known/openid-configuration`;\nconst CLIENT_ID = \"b1a00492-073a-47ea-816f-4c329264a828\";\nconst SCOPE = \"openid profile email offline_access grok-cli:access api:access\";\nconst CALLBACK_HOST = getProviderEnvValue(\"PI_OAUTH_CALLBACK_HOST\") || \"127.0.0.1\";\nconst CALLBACK_PORT = 56121;\nconst CALLBACK_PATH = \"/callback\";\nconst REFRESH_SKEW_MS = 2 * 60 * 1000;\n\n/** OAuth-authenticated requests are proxied through the Grok CLI endpoint, not api.x.ai directly. */\nexport const XAI_OAUTH_BASE_URL = \"https://cli-chat-proxy.grok.com/v1\";\n\ntype XaiDiscovery = { authorizationEndpoint: string; tokenEndpoint: string };\ntype XaiTokenPayload = { access_token?: string; refresh_token?: string; expires_in?: number };\n\nasync function getNodeApis(): Promise<NodeApis> {\n\tif (nodeApis) return nodeApis;\n\tif (!nodeApisPromise) {\n\t\tif (typeof process === \"undefined\" || (!process.versions?.node && !process.versions?.bun)) {\n\t\t\tthrow new Error(\"xAI OAuth is only available in Node.js environments\");\n\t\t}\n\t\tnodeApisPromise = import(\"node:http\").then((httpModule) => ({\n\t\t\tcreateServer: httpModule.createServer,\n\t\t}));\n\t}\n\tnodeApis = await nodeApisPromise;\n\treturn nodeApis;\n}\n\n/** Reject discovery responses that don't point back at x.ai, in case DNS/discovery is ever compromised. */\nfunction validateXaiEndpoint(url: string): string {\n\tconst parsed = new URL(url);\n\tconst host = parsed.hostname.toLowerCase();\n\tif (parsed.protocol !== \"https:\" || (host !== \"x.ai\" && !host.endsWith(\".x.ai\"))) {\n\t\tthrow new Error(`xAI OAuth discovery returned an unexpected endpoint: ${url}`);\n\t}\n\treturn url;\n}\n\nasync function discoverXaiEndpoints(): Promise<XaiDiscovery> {\n\tconst response = await fetch(DISCOVERY_URL, { headers: { Accept: \"application/json\" } });\n\tif (!response.ok) {\n\t\tthrow new Error(`xAI OAuth discovery failed: ${response.status} ${await response.text()}`);\n\t}\n\n\tconst data = (await response.json()) as { authorization_endpoint?: string; token_endpoint?: string };\n\tif (!data.authorization_endpoint || !data.token_endpoint) {\n\t\tthrow new Error(\"xAI OAuth discovery response did not include authorization/token endpoints\");\n\t}\n\n\treturn {\n\t\tauthorizationEndpoint: validateXaiEndpoint(data.authorization_endpoint),\n\t\ttokenEndpoint: validateXaiEndpoint(data.token_endpoint),\n\t};\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn {\n\t\t\tcode: url.searchParams.get(\"code\") ?? undefined,\n\t\t\tstate: url.searchParams.get(\"state\") ?? undefined,\n\t\t};\n\t} catch {\n\t\t// not a URL\n\t}\n\n\tif (value.includes(\"code=\")) {\n\t\tconst params = new URLSearchParams(value);\n\t\treturn {\n\t\t\tcode: params.get(\"code\") ?? undefined,\n\t\t\tstate: params.get(\"state\") ?? undefined,\n\t\t};\n\t}\n\n\treturn { code: value };\n}\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tredirectUri: string;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\nasync function startCallbackServer(expectedState: string): Promise<CallbackServerInfo> {\n\tconst { createServer } = await getNodeApis();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet settleWait: ((value: { code: string; state: string } | null) => void) | undefined;\n\t\tconst waitForCodePromise = new Promise<{ code: string; state: string } | null>((resolveWait) => {\n\t\t\tlet settled = false;\n\t\t\tsettleWait = (value) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolveWait(value);\n\t\t\t};\n\t\t});\n\n\t\tconst server = createServer((req, res) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(req.url || \"\", `http://${CALLBACK_HOST}`);\n\t\t\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Callback route not found.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"xAI authentication did not complete.\", `Error: ${error}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!code || !state) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Missing code or state parameter.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (state !== expectedState) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"State mismatch.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(oauthSuccessHtml(\"xAI authentication completed. You can close this window.\"));\n\t\t\t\tsettleWait?.({ code, state });\n\t\t\t} catch {\n\t\t\t\tres.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\tres.end(\"Internal error\");\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(CALLBACK_PORT, CALLBACK_HOST, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tredirectUri: `http://${CALLBACK_HOST}:${CALLBACK_PORT}${CALLBACK_PATH}`,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tsettleWait?.(null);\n\t\t\t\t},\n\t\t\t\twaitForCode: () => waitForCodePromise,\n\t\t\t});\n\t\t});\n\t});\n}\n\nasync function postForm(url: string, body: Record<string, string>): Promise<string> {\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: new URLSearchParams(body).toString(),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tconst responseBody = await response.text();\n\tif (!response.ok) {\n\t\tthrow new Error(`xAI token request failed. status=${response.status}; url=${url}; body=${responseBody}`);\n\t}\n\treturn responseBody;\n}\n\nfunction credentialsFromTokenPayload(data: XaiTokenPayload, fallbackRefresh = \"\"): OAuthCredentials {\n\tif (!data.access_token) {\n\t\tthrow new Error(\"xAI token response did not include an access token\");\n\t}\n\n\tconst refresh = data.refresh_token || fallbackRefresh;\n\tif (!refresh) {\n\t\tthrow new Error(\"xAI token response did not include a refresh token\");\n\t}\n\n\treturn {\n\t\taccess: data.access_token,\n\t\trefresh,\n\t\texpires: Date.now() + (data.expires_in ?? 3600) * 1000 - REFRESH_SKEW_MS,\n\t};\n}\n\n/**\n * Login with xAI OAuth (SuperGrok / X Premium+ subscription, authorization code + PKCE)\n */\nexport async function loginXai(options: {\n\tonAuth: (info: { url: string; instructions?: string }) => void;\n\tonPrompt: (prompt: OAuthPrompt) => Promise<string>;\n\tonProgress?: (message: string) => void;\n\tonManualCodeInput?: () => Promise<string>;\n}): Promise<OAuthCredentials> {\n\tconst discovery = await discoverXaiEndpoints();\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst server = await startCallbackServer(verifier);\n\n\ttry {\n\t\tconst authParams = new URLSearchParams({\n\t\t\tresponse_type: \"code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tredirect_uri: server.redirectUri,\n\t\t\tscope: SCOPE,\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t});\n\n\t\toptions.onAuth({\n\t\t\turl: `${discovery.authorizationEndpoint}?${authParams.toString()}`,\n\t\t\tinstructions:\n\t\t\t\t\"Sign in with your SuperGrok or X Premium+ account. If the browser is on another machine, paste the final redirect URL here.\",\n\t\t});\n\n\t\tlet code: string | undefined;\n\n\t\tif (options.onManualCodeInput) {\n\t\t\tlet manualInput: string | undefined;\n\t\t\tlet manualError: Error | undefined;\n\t\t\tconst manualPromise = options\n\t\t\t\t.onManualCodeInput()\n\t\t\t\t.then((input) => {\n\t\t\t\t\tmanualInput = input;\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tmanualError = err instanceof Error ? err : new Error(String(err));\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t});\n\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualInput) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t}\n\n\t\t\tif (!code) {\n\t\t\t\tawait manualPromise;\n\t\t\t\tif (manualError) {\n\t\t\t\t\tthrow manualError;\n\t\t\t\t}\n\t\t\t\tif (manualInput) {\n\t\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t}\n\t\t}\n\n\t\tif (!code) {\n\t\t\tconst input = await options.onPrompt({\n\t\t\t\tmessage: \"Paste the authorization code or full redirect URL:\",\n\t\t\t\tplaceholder: server.redirectUri,\n\t\t\t});\n\t\t\tconst parsed = parseAuthorizationInput(input);\n\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t}\n\t\t\tcode = parsed.code;\n\t\t}\n\n\t\tif (!code) {\n\t\t\tthrow new Error(\"Missing authorization code\");\n\t\t}\n\n\t\toptions.onProgress?.(\"Exchanging xAI authorization code...\");\n\t\tconst responseBody = await postForm(discovery.tokenEndpoint, {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode,\n\t\t\tredirect_uri: server.redirectUri,\n\t\t\tcode_verifier: verifier,\n\t\t});\n\t\treturn credentialsFromTokenPayload(JSON.parse(responseBody) as XaiTokenPayload);\n\t} finally {\n\t\tserver.server.close();\n\t}\n}\n\n/**\n * Refresh xAI OAuth token\n */\nexport async function refreshXaiToken(refreshToken: string): Promise<OAuthCredentials> {\n\tconst discovery = await discoverXaiEndpoints();\n\tconst responseBody = await postForm(discovery.tokenEndpoint, {\n\t\tgrant_type: \"refresh_token\",\n\t\tclient_id: CLIENT_ID,\n\t\trefresh_token: refreshToken,\n\t});\n\treturn credentialsFromTokenPayload(JSON.parse(responseBody) as XaiTokenPayload, refreshToken);\n}\n\nexport const xaiOAuth: OAuthAuth = {\n\tname: \"xAI (Grok)\",\n\n\tasync login(callbacks) {\n\t\t// The manual_code prompt races the local callback server; abort it once\n\t\t// the flow settles so the UI can dismiss the pending input.\n\t\tconst manualAbort = new AbortController();\n\t\ttry {\n\t\t\tconst credentials = await loginXai({\n\t\t\t\tonAuth: (info) => callbacks.notify({ type: \"auth_url\", url: info.url, instructions: info.instructions }),\n\t\t\t\tonProgress: (message) => callbacks.notify({ type: \"progress\", message }),\n\t\t\t\tonPrompt: (prompt) =>\n\t\t\t\t\tcallbacks.prompt({ type: \"text\", message: prompt.message, placeholder: prompt.placeholder }),\n\t\t\t\tonManualCodeInput: () =>\n\t\t\t\t\tcallbacks.prompt({\n\t\t\t\t\t\ttype: \"manual_code\",\n\t\t\t\t\t\tmessage: \"Complete login in your browser, or paste the authorization code / redirect URL here:\",\n\t\t\t\t\t\tplaceholder: `http://${CALLBACK_HOST}:${CALLBACK_PORT}${CALLBACK_PATH}`,\n\t\t\t\t\t\tsignal: manualAbort.signal,\n\t\t\t\t\t}),\n\t\t\t});\n\t\t\treturn { ...credentials, type: \"oauth\" };\n\t\t} finally {\n\t\t\tmanualAbort.abort();\n\t\t}\n\t},\n\n\tasync refresh(credential) {\n\t\treturn { ...(await refreshXaiToken(credential.refresh)), type: \"oauth\" };\n\t},\n\n\tasync toAuth(credential) {\n\t\treturn { apiKey: credential.access, baseUrl: XAI_OAUTH_BASE_URL };\n\t},\n};\n\nexport const xaiOAuthProvider: OAuthProviderInterface = {\n\tid: \"xai\",\n\tname: \"xAI (Grok)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginXai({\n\t\t\tonAuth: callbacks.onAuth,\n\t\t\tonPrompt: callbacks.onPrompt,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tonManualCodeInput: callbacks.onManualCodeInput,\n\t\t});\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshXaiToken(credentials.refresh);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6EpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CA6B5F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\n/**\n * Regex patterns to detect context overflow errors from different providers.\n *\n * These patterns match error messages returned when the input exceeds\n * the model's context window.\n *\n * Provider-specific patterns (with example error messages):\n *\n * - Anthropic: \"prompt is too long: 213462 tokens > 200000 maximum\"\n * - Anthropic: \"413 {\\\"error\\\":{\\\"type\\\":\\\"request_too_large\\\",\\\"message\\\":\\\"Request exceeds the maximum size\\\"}}\"\n * - OpenAI: \"Your input exceeds the context window of this model\"\n * - OpenAI/LiteLLM: \"Requested token count exceeds the model's maximum context length of 131072 tokens\"\n * - OpenAI-compatible: \"Input length (265330) exceeds model's maximum context length (262144).\"\n * - Google: \"The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)\"\n * - xAI: \"This model's maximum prompt length is 131072 but the request contains 537812 tokens\"\n * - Groq: \"Please reduce the length of the messages or completion\"\n * - OpenRouter: \"This endpoint's maximum context length is X tokens. However, you requested about Y tokens\"\n * - OpenRouter/Poolside: \"Input length X exceeds the maximum allowed input length of Y tokens.\"\n * - Together AI: \"The input (X tokens) is longer than the model's context length (Y tokens).\"\n * - llama.cpp: \"the request exceeds the available context size, try increasing it\"\n * - LM Studio: \"tokens to keep from the initial prompt is greater than the context length\"\n * - GitHub Copilot: \"prompt token count of X exceeds the limit of Y\"\n * - MiniMax: \"invalid params, context window exceeds limit\"\n * - Kimi For Coding: \"Your request exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - Cerebras: \"400/413 status code (no body)\"\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - z.ai: Does NOT error, accepts overflow silently - handled via usage.input > contextWindow\n * - Xiaomi MiMo: Truncates input to fill contextWindow exactly, then returns finish_reason \"length\"\n * with output=0 (no room left to generate). Detected via stopReason \"length\" + zero output +\n * input filling the context window.\n * - Ollama: Some deployments truncate silently, others return errors like \"prompt too long; exceeded max context length by X tokens\"\n */\nconst OVERFLOW_PATTERNS = [\n\t/prompt is too long/i, // Anthropic token overflow\n\t/request_too_large/i, // Anthropic request byte-size overflow (HTTP 413)\n\t/input is too long for requested model/i, // Amazon Bedrock\n\t/exceeds the context window/i, // OpenAI (Completions & Responses API)\n\t/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\\d,]+ tokens?|\\s*\\([\\d,]+\\))/i, // OpenAI-compatible proxies (LiteLLM)\n\t/input token count.*exceeds the maximum/i, // Google (Gemini)\n\t/maximum prompt length is \\d+/i, // xAI (Grok)\n\t/reduce the length of the messages/i, // Groq\n\t/maximum context length is \\d+ tokens/i, // OpenRouter (most backends)\n\t/exceeds (?:the )?maximum allowed input length of [\\d,]+ tokens?/i, // OpenRouter/Poolside\n\t/input \\(\\d+ tokens\\) is longer than the model'?s context length \\(\\d+ tokens\\)/i, // Together AI\n\t/exceeds the limit of \\d+/i, // GitHub Copilot\n\t/exceeds the available context size/i, // llama.cpp server\n\t/greater than the context length/i, // LM Studio\n\t/context window exceeds limit/i, // MiniMax\n\t/exceeded model token limit/i, // Kimi For Coding\n\t/too large for model with \\d+ maximum context length/i, // Mistral\n\t/prompt has [\\d,]+ tokens?, but the configured context size is [\\d,]+ tokens?/i, // DS4 server\n\t/model_context_window_exceeded/i, // z.ai non-standard finish_reason surfaced as error text\n\t/prompt too long; exceeded (?:max )?context length/i, // Ollama explicit overflow error\n\t/context[_ ]length[_ ]exceeded/i, // Generic fallback\n\t/too many tokens/i, // Generic fallback\n\t/token limit exceeded/i, // Generic fallback\n\t/^4(?:00|13)\\s*(?:status code)?\\s*\\(no body\\)/i, // Cerebras: 400/413 with no body\n];\n\n/**\n * Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).\n * Error messages matching any of these are excluded from overflow detection\n * even if they also match an OVERFLOW_PATTERN.\n *\n * Example: Bedrock formats throttling errors as \"ThrottlingException: Too many tokens,\n * please wait before trying again.\" which would match the /too many tokens/i overflow\n * pattern without this exclusion.\n */\nconst NON_OVERFLOW_PATTERNS = [\n\t/^(Throttling error|Service unavailable):/i, // AWS Bedrock non-overflow errors (human-readable prefixes from formatBedrockError)\n\t/rate limit/i, // Generic rate limiting\n\t/too many requests/i, // Generic HTTP 429 style\n];\n\n/**\n * Check if an assistant message represents a context overflow error.\n *\n * This handles two cases:\n * 1. Error-based overflow: Most providers return stopReason \"error\" with a\n * specific error message pattern.\n * 2. Silent overflow: Some providers accept overflow requests and return\n * successfully. For these, we check if usage.input exceeds the context window.\n *\n * ## Reliability by Provider\n *\n * **Reliable detection (returns error with detectable message):**\n * - Anthropic: \"prompt is too long: X tokens > Y maximum\" or \"request_too_large\"\n * - OpenAI (Completions & Responses): \"exceeds the context window\", \"exceeds the model's maximum context length of X tokens\", or \"exceeds model's maximum context length (X)\"\n * - Google Gemini: \"input token count exceeds the maximum\"\n * - xAI (Grok): \"maximum prompt length is X but request contains Y\"\n * - Groq: \"reduce the length of the messages\"\n * - Cerebras: 400/413 status code (no body)\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - OpenRouter (most backends): \"maximum context length is X tokens\"\n * - OpenRouter/Poolside: \"Input length X exceeds the maximum allowed input length of Y tokens.\"\n * - Together AI: \"The input (X tokens) is longer than the model's context length (Y tokens).\"\n * - llama.cpp: \"exceeds the available context size\"\n * - LM Studio: \"greater than the context length\"\n * - Kimi For Coding: \"exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n *\n * **Unreliable detection:**\n * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),\n * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.\n * - Xiaomi MiMo: Truncates input to fit contextWindow then returns stopReason \"length\" with\n * output=0. Pass contextWindow param to detect via the \"filled context + zero output\" signal.\n * - Ollama: May truncate input silently for some setups, but may also return explicit\n * overflow errors that match the patterns above. Silent truncation still cannot be\n * detected here because we do not know the expected token count.\n *\n * ## Custom Providers\n *\n * If you've added custom models via settings.json, this function may not detect\n * overflow errors from those providers. To add support:\n *\n * 1. Send a request that exceeds the model's context window\n * 2. Check the errorMessage in the response\n * 3. Create a regex pattern that matches the error\n * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or\n * check the errorMessage yourself before calling this function\n *\n * @param message - The assistant message to check\n * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)\n * @returns true if the message indicates a context overflow\n */\nexport function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean {\n\t// Case 1: Check error message patterns\n\tif (message.stopReason === \"error\" && message.errorMessage) {\n\t\t// Skip messages matching known non-overflow patterns (e.g. throttling / rate-limit)\n\t\tconst isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!));\n\t\tif (!isNonOverflow && OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!))) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 2: Silent overflow (z.ai style) - successful but usage exceeds context\n\tif (contextWindow && message.stopReason === \"stop\") {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens > contextWindow) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 3: Length-stop overflow (Xiaomi MiMo style) - server truncates oversized input\n\t// to fit the context window, leaving no room for output. Returns stopReason \"length\"\n\t// with output=0 and input+cacheRead filling the context window.\n\tif (contextWindow && message.stopReason === \"length\" && message.usage.output === 0) {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens >= contextWindow * 0.99) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Get the overflow patterns for testing purposes.\n */\nexport function getOverflowPatterns(): RegExp[] {\n\treturn [...OVERFLOW_PATTERNS];\n}\n"]}
1
+ {"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6EpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CA6B5F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"overflow.js","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,iBAAiB,GAAG;IACzB,qBAAqB,EAAE,2BAA2B;IAClD,oBAAoB,EAAE,kDAAkD;IACxE,wCAAwC,EAAE,iBAAiB;IAC3D,6BAA6B,EAAE,uCAAuC;IACtE,4FAA4F,EAAE,sCAAsC;IACpI,yCAAyC,EAAE,kBAAkB;IAC7D,+BAA+B,EAAE,aAAa;IAC9C,oCAAoC,EAAE,OAAO;IAC7C,uCAAuC,EAAE,6BAA6B;IACtE,kEAAkE,EAAE,sBAAsB;IAC1F,iFAAiF,EAAE,cAAc;IACjG,2BAA2B,EAAE,iBAAiB;IAC9C,qCAAqC,EAAE,mBAAmB;IAC1D,kCAAkC,EAAE,YAAY;IAChD,+BAA+B,EAAE,UAAU;IAC3C,6BAA6B,EAAE,kBAAkB;IACjD,sDAAsD,EAAE,UAAU;IAClE,+EAA+E,EAAE,aAAa;IAC9F,gCAAgC,EAAE,yDAAyD;IAC3F,oDAAoD,EAAE,iCAAiC;IACvF,gCAAgC,EAAE,mBAAmB;IACrD,kBAAkB,EAAE,mBAAmB;IACvC,uBAAuB,EAAE,mBAAmB;IAC5C,+CAA+C,EAAE,iCAAiC;CAClF,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,qBAAqB,GAAG;IAC7B,2CAA2C,EAAE,oFAAoF;IACjI,aAAa,EAAE,wBAAwB;IACvC,oBAAoB,EAAE,yBAAyB;CAC/C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAyB,EAAE,aAAsB,EAAW;IAC7F,uCAAuC;IACvC,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QAC5D,oFAAoF;QACpF,MAAM,aAAa,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,YAAa,CAAC,CAAC,CAAC;QACvF,IAAI,CAAC,aAAa,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,YAAa,CAAC,CAAC,EAAE,CAAC;YACpF,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,8EAA8E;IAC9E,IAAI,aAAa,IAAI,OAAO,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;QACpD,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;QAClE,IAAI,WAAW,GAAG,aAAa,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,sFAAsF;IACtF,qFAAqF;IACrF,gEAAgE;IAChE,IAAI,aAAa,IAAI,OAAO,CAAC,UAAU,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpF,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;QAClE,IAAI,WAAW,IAAI,aAAa,GAAG,IAAI,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AAAA,CACb;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,GAAa;IAC/C,OAAO,CAAC,GAAG,iBAAiB,CAAC,CAAC;AAAA,CAC9B","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\n/**\n * Regex patterns to detect context overflow errors from different providers.\n *\n * These patterns match error messages returned when the input exceeds\n * the model's context window.\n *\n * Provider-specific patterns (with example error messages):\n *\n * - Anthropic: \"prompt is too long: 213462 tokens > 200000 maximum\"\n * - Anthropic: \"413 {\\\"error\\\":{\\\"type\\\":\\\"request_too_large\\\",\\\"message\\\":\\\"Request exceeds the maximum size\\\"}}\"\n * - OpenAI: \"Your input exceeds the context window of this model\"\n * - OpenAI/LiteLLM: \"Requested token count exceeds the model's maximum context length of 131072 tokens\"\n * - OpenAI-compatible: \"Input length (265330) exceeds model's maximum context length (262144).\"\n * - Google: \"The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)\"\n * - xAI: \"This model's maximum prompt length is 131072 but the request contains 537812 tokens\"\n * - Groq: \"Please reduce the length of the messages or completion\"\n * - OpenRouter: \"This endpoint's maximum context length is X tokens. However, you requested about Y tokens\"\n * - OpenRouter/Poolside: \"Input length X exceeds the maximum allowed input length of Y tokens.\"\n * - Together AI: \"The input (X tokens) is longer than the model's context length (Y tokens).\"\n * - llama.cpp: \"the request exceeds the available context size, try increasing it\"\n * - LM Studio: \"tokens to keep from the initial prompt is greater than the context length\"\n * - GitHub Copilot: \"prompt token count of X exceeds the limit of Y\"\n * - MiniMax: \"invalid params, context window exceeds limit\"\n * - Kimi For Coding: \"Your request exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - Cerebras: \"400/413 status code (no body)\"\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - z.ai: Does NOT error, accepts overflow silently - handled via usage.input > contextWindow\n * - Xiaomi MiMo: Truncates input to fill contextWindow exactly, then returns finish_reason \"length\"\n * with output=0 (no room left to generate). Detected via stopReason \"length\" + zero output +\n * input filling the context window.\n * - Ollama: Some deployments truncate silently, others return errors like \"prompt too long; exceeded max context length by X tokens\"\n */\nconst OVERFLOW_PATTERNS = [\n\t/prompt is too long/i, // Anthropic token overflow\n\t/request_too_large/i, // Anthropic request byte-size overflow (HTTP 413)\n\t/input is too long for requested model/i, // Amazon Bedrock\n\t/exceeds the context window/i, // OpenAI (Completions & Responses API)\n\t/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\\d,]+ tokens?|\\s*\\([\\d,]+\\))/i, // OpenAI-compatible proxies (LiteLLM)\n\t/input token count.*exceeds the maximum/i, // Google (Gemini)\n\t/maximum prompt length is \\d+/i, // xAI (Grok)\n\t/reduce the length of the messages/i, // Groq\n\t/maximum context length is \\d+ tokens/i, // OpenRouter (most backends)\n\t/exceeds (?:the )?maximum allowed input length of [\\d,]+ tokens?/i, // OpenRouter/Poolside\n\t/input \\(\\d+ tokens\\) is longer than the model'?s context length \\(\\d+ tokens\\)/i, // Together AI\n\t/exceeds the limit of \\d+/i, // GitHub Copilot\n\t/exceeds the available context size/i, // llama.cpp server\n\t/greater than the context length/i, // LM Studio\n\t/context window exceeds limit/i, // MiniMax\n\t/exceeded model token limit/i, // Kimi For Coding\n\t/too large for model with \\d+ maximum context length/i, // Mistral\n\t/prompt has [\\d,]+ tokens?, but the configured context size is [\\d,]+ tokens?/i, // DS4 server\n\t/model_context_window_exceeded/i, // z.ai non-standard finish_reason surfaced as error text\n\t/prompt too long; exceeded (?:max )?context length/i, // Ollama explicit overflow error\n\t/context[_ ]length[_ ]exceeded/i, // Generic fallback\n\t/too many tokens/i, // Generic fallback\n\t/token limit exceeded/i, // Generic fallback\n\t/^4(?:00|13)\\s*(?:status code)?\\s*\\(no body\\)/i, // Cerebras: 400/413 with no body\n];\n\n/**\n * Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).\n * Error messages matching any of these are excluded from overflow detection\n * even if they also match an OVERFLOW_PATTERN.\n *\n * Example: Bedrock formats throttling errors as \"ThrottlingException: Too many tokens,\n * please wait before trying again.\" which would match the /too many tokens/i overflow\n * pattern without this exclusion.\n */\nconst NON_OVERFLOW_PATTERNS = [\n\t/^(Throttling error|Service unavailable):/i, // AWS Bedrock non-overflow errors (human-readable prefixes from formatBedrockError)\n\t/rate limit/i, // Generic rate limiting\n\t/too many requests/i, // Generic HTTP 429 style\n];\n\n/**\n * Check if an assistant message represents a context overflow error.\n *\n * This handles two cases:\n * 1. Error-based overflow: Most providers return stopReason \"error\" with a\n * specific error message pattern.\n * 2. Silent overflow: Some providers accept overflow requests and return\n * successfully. For these, we check if usage.input exceeds the context window.\n *\n * ## Reliability by Provider\n *\n * **Reliable detection (returns error with detectable message):**\n * - Anthropic: \"prompt is too long: X tokens > Y maximum\" or \"request_too_large\"\n * - OpenAI (Completions & Responses): \"exceeds the context window\", \"exceeds the model's maximum context length of X tokens\", or \"exceeds model's maximum context length (X)\"\n * - Google Gemini: \"input token count exceeds the maximum\"\n * - xAI (Grok): \"maximum prompt length is X but request contains Y\"\n * - Groq: \"reduce the length of the messages\"\n * - Cerebras: 400/413 status code (no body)\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - OpenRouter (most backends): \"maximum context length is X tokens\"\n * - OpenRouter/Poolside: \"Input length X exceeds the maximum allowed input length of Y tokens.\"\n * - Together AI: \"The input (X tokens) is longer than the model's context length (Y tokens).\"\n * - llama.cpp: \"exceeds the available context size\"\n * - LM Studio: \"greater than the context length\"\n * - Kimi For Coding: \"exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n *\n * **Unreliable detection:**\n * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),\n * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.\n * - Xiaomi MiMo: Truncates input to fit contextWindow then returns stopReason \"length\" with\n * output=0. Pass contextWindow param to detect via the \"filled context + zero output\" signal.\n * - Ollama: May truncate input silently for some setups, but may also return explicit\n * overflow errors that match the patterns above. Silent truncation still cannot be\n * detected here because we do not know the expected token count.\n *\n * ## Custom Providers\n *\n * If you've added custom models via settings.json, this function may not detect\n * overflow errors from those providers. To add support:\n *\n * 1. Send a request that exceeds the model's context window\n * 2. Check the errorMessage in the response\n * 3. Create a regex pattern that matches the error\n * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or\n * check the errorMessage yourself before calling this function\n *\n * @param message - The assistant message to check\n * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)\n * @returns true if the message indicates a context overflow\n */\nexport function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean {\n\t// Case 1: Check error message patterns\n\tif (message.stopReason === \"error\" && message.errorMessage) {\n\t\t// Skip messages matching known non-overflow patterns (e.g. throttling / rate-limit)\n\t\tconst isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!));\n\t\tif (!isNonOverflow && OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!))) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 2: Silent overflow (z.ai style) - successful but usage exceeds context\n\tif (contextWindow && message.stopReason === \"stop\") {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens > contextWindow) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 3: Length-stop overflow (Xiaomi MiMo style) - server truncates oversized input\n\t// to fit the context window, leaving no room for output. Returns stopReason \"length\"\n\t// with output=0 and input+cacheRead filling the context window.\n\tif (contextWindow && message.stopReason === \"length\" && message.usage.output === 0) {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens >= contextWindow * 0.99) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Get the overflow patterns for testing purposes.\n */\nexport function getOverflowPatterns(): RegExp[] {\n\treturn [...OVERFLOW_PATTERNS];\n}\n"]}
1
+ {"version":3,"file":"overflow.js","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,iBAAiB,GAAG;IACzB,qBAAqB,EAAE,2BAA2B;IAClD,oBAAoB,EAAE,kDAAkD;IACxE,wCAAwC,EAAE,iBAAiB;IAC3D,6BAA6B,EAAE,uCAAuC;IACtE,4FAA4F,EAAE,sCAAsC;IACpI,yCAAyC,EAAE,kBAAkB;IAC7D,+BAA+B,EAAE,aAAa;IAC9C,oCAAoC,EAAE,OAAO;IAC7C,uCAAuC,EAAE,6BAA6B;IACtE,kEAAkE,EAAE,sBAAsB;IAC1F,iFAAiF,EAAE,cAAc;IACjG,2BAA2B,EAAE,iBAAiB;IAC9C,qCAAqC,EAAE,mBAAmB;IAC1D,kCAAkC,EAAE,YAAY;IAChD,+BAA+B,EAAE,UAAU;IAC3C,6BAA6B,EAAE,kBAAkB;IACjD,sDAAsD,EAAE,UAAU;IAClE,+EAA+E,EAAE,aAAa;IAC9F,gCAAgC,EAAE,yDAAyD;IAC3F,oDAAoD,EAAE,iCAAiC;IACvF,gCAAgC,EAAE,mBAAmB;IACrD,kBAAkB,EAAE,mBAAmB;IACvC,uBAAuB,EAAE,mBAAmB;IAC5C,+CAA+C,EAAE,iCAAiC;CAClF,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,qBAAqB,GAAG;IAC7B,2CAA2C,EAAE,oFAAoF;IACjI,aAAa,EAAE,wBAAwB;IACvC,oBAAoB,EAAE,yBAAyB;CAC/C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAyB,EAAE,aAAsB;IAClF,uCAAuC;IACvC,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QAC5D,oFAAoF;QACpF,MAAM,aAAa,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,YAAa,CAAC,CAAC,CAAC;QACvF,IAAI,CAAC,aAAa,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,YAAa,CAAC,CAAC,EAAE,CAAC;YACpF,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,8EAA8E;IAC9E,IAAI,aAAa,IAAI,OAAO,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;QACpD,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;QAClE,IAAI,WAAW,GAAG,aAAa,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,sFAAsF;IACtF,qFAAqF;IACrF,gEAAgE;IAChE,IAAI,aAAa,IAAI,OAAO,CAAC,UAAU,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpF,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;QAClE,IAAI,WAAW,IAAI,aAAa,GAAG,IAAI,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IAClC,OAAO,CAAC,GAAG,iBAAiB,CAAC,CAAC;AAC/B,CAAC","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\n/**\n * Regex patterns to detect context overflow errors from different providers.\n *\n * These patterns match error messages returned when the input exceeds\n * the model's context window.\n *\n * Provider-specific patterns (with example error messages):\n *\n * - Anthropic: \"prompt is too long: 213462 tokens > 200000 maximum\"\n * - Anthropic: \"413 {\\\"error\\\":{\\\"type\\\":\\\"request_too_large\\\",\\\"message\\\":\\\"Request exceeds the maximum size\\\"}}\"\n * - OpenAI: \"Your input exceeds the context window of this model\"\n * - OpenAI/LiteLLM: \"Requested token count exceeds the model's maximum context length of 131072 tokens\"\n * - OpenAI-compatible: \"Input length (265330) exceeds model's maximum context length (262144).\"\n * - Google: \"The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)\"\n * - xAI: \"This model's maximum prompt length is 131072 but the request contains 537812 tokens\"\n * - Groq: \"Please reduce the length of the messages or completion\"\n * - OpenRouter: \"This endpoint's maximum context length is X tokens. However, you requested about Y tokens\"\n * - OpenRouter/Poolside: \"Input length X exceeds the maximum allowed input length of Y tokens.\"\n * - Together AI: \"The input (X tokens) is longer than the model's context length (Y tokens).\"\n * - llama.cpp: \"the request exceeds the available context size, try increasing it\"\n * - LM Studio: \"tokens to keep from the initial prompt is greater than the context length\"\n * - GitHub Copilot: \"prompt token count of X exceeds the limit of Y\"\n * - MiniMax: \"invalid params, context window exceeds limit\"\n * - Kimi For Coding: \"Your request exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - Cerebras: \"400/413 status code (no body)\"\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - z.ai: Does NOT error, accepts overflow silently - handled via usage.input > contextWindow\n * - Xiaomi MiMo: Truncates input to fill contextWindow exactly, then returns finish_reason \"length\"\n * with output=0 (no room left to generate). Detected via stopReason \"length\" + zero output +\n * input filling the context window.\n * - Ollama: Some deployments truncate silently, others return errors like \"prompt too long; exceeded max context length by X tokens\"\n */\nconst OVERFLOW_PATTERNS = [\n\t/prompt is too long/i, // Anthropic token overflow\n\t/request_too_large/i, // Anthropic request byte-size overflow (HTTP 413)\n\t/input is too long for requested model/i, // Amazon Bedrock\n\t/exceeds the context window/i, // OpenAI (Completions & Responses API)\n\t/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\\d,]+ tokens?|\\s*\\([\\d,]+\\))/i, // OpenAI-compatible proxies (LiteLLM)\n\t/input token count.*exceeds the maximum/i, // Google (Gemini)\n\t/maximum prompt length is \\d+/i, // xAI (Grok)\n\t/reduce the length of the messages/i, // Groq\n\t/maximum context length is \\d+ tokens/i, // OpenRouter (most backends)\n\t/exceeds (?:the )?maximum allowed input length of [\\d,]+ tokens?/i, // OpenRouter/Poolside\n\t/input \\(\\d+ tokens\\) is longer than the model'?s context length \\(\\d+ tokens\\)/i, // Together AI\n\t/exceeds the limit of \\d+/i, // GitHub Copilot\n\t/exceeds the available context size/i, // llama.cpp server\n\t/greater than the context length/i, // LM Studio\n\t/context window exceeds limit/i, // MiniMax\n\t/exceeded model token limit/i, // Kimi For Coding\n\t/too large for model with \\d+ maximum context length/i, // Mistral\n\t/prompt has [\\d,]+ tokens?, but the configured context size is [\\d,]+ tokens?/i, // DS4 server\n\t/model_context_window_exceeded/i, // z.ai non-standard finish_reason surfaced as error text\n\t/prompt too long; exceeded (?:max )?context length/i, // Ollama explicit overflow error\n\t/context[_ ]length[_ ]exceeded/i, // Generic fallback\n\t/too many tokens/i, // Generic fallback\n\t/token limit exceeded/i, // Generic fallback\n\t/^4(?:00|13)\\s*(?:status code)?\\s*\\(no body\\)/i, // Cerebras: 400/413 with no body\n];\n\n/**\n * Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).\n * Error messages matching any of these are excluded from overflow detection\n * even if they also match an OVERFLOW_PATTERN.\n *\n * Example: Bedrock formats throttling errors as \"ThrottlingException: Too many tokens,\n * please wait before trying again.\" which would match the /too many tokens/i overflow\n * pattern without this exclusion.\n */\nconst NON_OVERFLOW_PATTERNS = [\n\t/^(Throttling error|Service unavailable):/i, // AWS Bedrock non-overflow errors (human-readable prefixes from formatBedrockError)\n\t/rate limit/i, // Generic rate limiting\n\t/too many requests/i, // Generic HTTP 429 style\n];\n\n/**\n * Check if an assistant message represents a context overflow error.\n *\n * This handles two cases:\n * 1. Error-based overflow: Most providers return stopReason \"error\" with a\n * specific error message pattern.\n * 2. Silent overflow: Some providers accept overflow requests and return\n * successfully. For these, we check if usage.input exceeds the context window.\n *\n * ## Reliability by Provider\n *\n * **Reliable detection (returns error with detectable message):**\n * - Anthropic: \"prompt is too long: X tokens > Y maximum\" or \"request_too_large\"\n * - OpenAI (Completions & Responses): \"exceeds the context window\", \"exceeds the model's maximum context length of X tokens\", or \"exceeds model's maximum context length (X)\"\n * - Google Gemini: \"input token count exceeds the maximum\"\n * - xAI (Grok): \"maximum prompt length is X but request contains Y\"\n * - Groq: \"reduce the length of the messages\"\n * - Cerebras: 400/413 status code (no body)\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - OpenRouter (most backends): \"maximum context length is X tokens\"\n * - OpenRouter/Poolside: \"Input length X exceeds the maximum allowed input length of Y tokens.\"\n * - Together AI: \"The input (X tokens) is longer than the model's context length (Y tokens).\"\n * - llama.cpp: \"exceeds the available context size\"\n * - LM Studio: \"greater than the context length\"\n * - Kimi For Coding: \"exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n *\n * **Unreliable detection:**\n * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),\n * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.\n * - Xiaomi MiMo: Truncates input to fit contextWindow then returns stopReason \"length\" with\n * output=0. Pass contextWindow param to detect via the \"filled context + zero output\" signal.\n * - Ollama: May truncate input silently for some setups, but may also return explicit\n * overflow errors that match the patterns above. Silent truncation still cannot be\n * detected here because we do not know the expected token count.\n *\n * ## Custom Providers\n *\n * If you've added custom models via settings.json, this function may not detect\n * overflow errors from those providers. To add support:\n *\n * 1. Send a request that exceeds the model's context window\n * 2. Check the errorMessage in the response\n * 3. Create a regex pattern that matches the error\n * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or\n * check the errorMessage yourself before calling this function\n *\n * @param message - The assistant message to check\n * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)\n * @returns true if the message indicates a context overflow\n */\nexport function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean {\n\t// Case 1: Check error message patterns\n\tif (message.stopReason === \"error\" && message.errorMessage) {\n\t\t// Skip messages matching known non-overflow patterns (e.g. throttling / rate-limit)\n\t\tconst isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!));\n\t\tif (!isNonOverflow && OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!))) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 2: Silent overflow (z.ai style) - successful but usage exceeds context\n\tif (contextWindow && message.stopReason === \"stop\") {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens > contextWindow) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 3: Length-stop overflow (Xiaomi MiMo style) - server truncates oversized input\n\t// to fit the context window, leaving no room for output. Returns stopReason \"length\"\n\t// with output=0 and input+cacheRead filling the context window.\n\tif (contextWindow && message.stopReason === \"length\" && message.usage.output === 0) {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens >= contextWindow * 0.99) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Get the overflow patterns for testing purposes.\n */\nexport function getOverflowPatterns(): RegExp[] {\n\treturn [...OVERFLOW_PATTERNS];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"provider-env.d.ts","sourceRoot":"","sources":["../../src/utils/provider-env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAwC/C;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAOvF","sourcesContent":["import type { ProviderEnv } from \"../types.ts\";\n\nlet procEnvCache: Map<string, string> | null = null;\n\n/**\n * Fallback for https://github.com/oven-sh/bun/issues/27802.\n * Bun compiled binaries can expose an empty process.env inside Linux sandboxes\n * even though /proc/self/environ contains the environment.\n *\n * This intentionally duplicates restoreSandboxEnv() in\n * packages/coding-agent/src/bun/restore-sandbox-env.ts. The ai package can be\n * used directly, without going through that entrypoint, so provider env lookup\n * must not depend on process.env having been patched.\n */\nfunction getBunSandboxEnvValue(name: string): string | undefined {\n\tif (typeof process === \"undefined\" || !process.versions?.bun || Object.keys(process.env).length > 0) {\n\t\treturn undefined;\n\t}\n\n\tif (procEnvCache === null) {\n\t\tprocEnvCache = new Map();\n\t\ttry {\n\t\t\tconst { readFileSync } = require(\"node:fs\") as {\n\t\t\t\treadFileSync(path: string, encoding: BufferEncoding): string;\n\t\t\t};\n\t\t\tconst data = readFileSync(\"/proc/self/environ\", \"utf-8\");\n\t\t\tfor (const entry of data.split(\"\\0\")) {\n\t\t\t\tconst idx = entry.indexOf(\"=\");\n\t\t\t\tif (idx > 0) {\n\t\t\t\t\tprocEnvCache.set(entry.slice(0, idx), entry.slice(idx + 1));\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// /proc/self/environ may not exist or may not be readable.\n\t\t}\n\t}\n\n\treturn procEnvCache.get(name);\n}\n\n/**\n * Resolve a provider env value from scoped overrides, normal process.env, then\n * the duplicated Bun sandbox fallback for direct pi-ai consumers.\n */\nexport function getProviderEnvValue(name: string, env?: ProviderEnv): string | undefined {\n\treturn (\n\t\tenv?.[name] ||\n\t\t(typeof process !== \"undefined\" ? process.env[name] : undefined) ||\n\t\tgetBunSandboxEnvValue(name) ||\n\t\tundefined\n\t);\n}\n"]}
1
+ {"version":3,"file":"provider-env.d.ts","sourceRoot":"","sources":["../../src/utils/provider-env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAwC/C;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAOvF"}
@@ -1 +1 @@
1
- {"version":3,"file":"provider-env.js","sourceRoot":"","sources":["../../src/utils/provider-env.ts"],"names":[],"mappings":"AAEA,IAAI,YAAY,GAA+B,IAAI,CAAC;AAEpD;;;;;;;;;GASG;AACH,SAAS,qBAAqB,CAAC,IAAY,EAAsB;IAChE,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrG,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC3B,YAAY,GAAG,IAAI,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC;YACJ,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,SAAS,CAEzC,CAAC;YACF,MAAM,IAAI,GAAG,YAAY,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;YACzD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtC,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC/B,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;oBACb,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACF,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,2DAA2D;QAC5D,CAAC;IACF,CAAC;IAED,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAAA,CAC9B;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,GAAiB,EAAsB;IACxF,OAAO,CACN,GAAG,EAAE,CAAC,IAAI,CAAC;QACX,CAAC,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,qBAAqB,CAAC,IAAI,CAAC;QAC3B,SAAS,CACT,CAAC;AAAA,CACF","sourcesContent":["import type { ProviderEnv } from \"../types.ts\";\n\nlet procEnvCache: Map<string, string> | null = null;\n\n/**\n * Fallback for https://github.com/oven-sh/bun/issues/27802.\n * Bun compiled binaries can expose an empty process.env inside Linux sandboxes\n * even though /proc/self/environ contains the environment.\n *\n * This intentionally duplicates restoreSandboxEnv() in\n * packages/coding-agent/src/bun/restore-sandbox-env.ts. The ai package can be\n * used directly, without going through that entrypoint, so provider env lookup\n * must not depend on process.env having been patched.\n */\nfunction getBunSandboxEnvValue(name: string): string | undefined {\n\tif (typeof process === \"undefined\" || !process.versions?.bun || Object.keys(process.env).length > 0) {\n\t\treturn undefined;\n\t}\n\n\tif (procEnvCache === null) {\n\t\tprocEnvCache = new Map();\n\t\ttry {\n\t\t\tconst { readFileSync } = require(\"node:fs\") as {\n\t\t\t\treadFileSync(path: string, encoding: BufferEncoding): string;\n\t\t\t};\n\t\t\tconst data = readFileSync(\"/proc/self/environ\", \"utf-8\");\n\t\t\tfor (const entry of data.split(\"\\0\")) {\n\t\t\t\tconst idx = entry.indexOf(\"=\");\n\t\t\t\tif (idx > 0) {\n\t\t\t\t\tprocEnvCache.set(entry.slice(0, idx), entry.slice(idx + 1));\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// /proc/self/environ may not exist or may not be readable.\n\t\t}\n\t}\n\n\treturn procEnvCache.get(name);\n}\n\n/**\n * Resolve a provider env value from scoped overrides, normal process.env, then\n * the duplicated Bun sandbox fallback for direct pi-ai consumers.\n */\nexport function getProviderEnvValue(name: string, env?: ProviderEnv): string | undefined {\n\treturn (\n\t\tenv?.[name] ||\n\t\t(typeof process !== \"undefined\" ? process.env[name] : undefined) ||\n\t\tgetBunSandboxEnvValue(name) ||\n\t\tundefined\n\t);\n}\n"]}
1
+ {"version":3,"file":"provider-env.js","sourceRoot":"","sources":["../../src/utils/provider-env.ts"],"names":[],"mappings":"AAEA,IAAI,YAAY,GAA+B,IAAI,CAAC;AAEpD;;;;;;;;;GASG;AACH,SAAS,qBAAqB,CAAC,IAAY;IAC1C,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrG,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC3B,YAAY,GAAG,IAAI,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC;YACJ,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,SAAS,CAEzC,CAAC;YACF,MAAM,IAAI,GAAG,YAAY,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;YACzD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtC,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC/B,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;oBACb,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACF,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,2DAA2D;QAC5D,CAAC;IACF,CAAC;IAED,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,GAAiB;IAClE,OAAO,CACN,GAAG,EAAE,CAAC,IAAI,CAAC;QACX,CAAC,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,qBAAqB,CAAC,IAAI,CAAC;QAC3B,SAAS,CACT,CAAC;AACH,CAAC","sourcesContent":["import type { ProviderEnv } from \"../types.ts\";\n\nlet procEnvCache: Map<string, string> | null = null;\n\n/**\n * Fallback for https://github.com/oven-sh/bun/issues/27802.\n * Bun compiled binaries can expose an empty process.env inside Linux sandboxes\n * even though /proc/self/environ contains the environment.\n *\n * This intentionally duplicates restoreSandboxEnv() in\n * packages/coding-agent/src/bun/restore-sandbox-env.ts. The ai package can be\n * used directly, without going through that entrypoint, so provider env lookup\n * must not depend on process.env having been patched.\n */\nfunction getBunSandboxEnvValue(name: string): string | undefined {\n\tif (typeof process === \"undefined\" || !process.versions?.bun || Object.keys(process.env).length > 0) {\n\t\treturn undefined;\n\t}\n\n\tif (procEnvCache === null) {\n\t\tprocEnvCache = new Map();\n\t\ttry {\n\t\t\tconst { readFileSync } = require(\"node:fs\") as {\n\t\t\t\treadFileSync(path: string, encoding: BufferEncoding): string;\n\t\t\t};\n\t\t\tconst data = readFileSync(\"/proc/self/environ\", \"utf-8\");\n\t\t\tfor (const entry of data.split(\"\\0\")) {\n\t\t\t\tconst idx = entry.indexOf(\"=\");\n\t\t\t\tif (idx > 0) {\n\t\t\t\t\tprocEnvCache.set(entry.slice(0, idx), entry.slice(idx + 1));\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// /proc/self/environ may not exist or may not be readable.\n\t\t}\n\t}\n\n\treturn procEnvCache.get(name);\n}\n\n/**\n * Resolve a provider env value from scoped overrides, normal process.env, then\n * the duplicated Bun sandbox fallback for direct pi-ai consumers.\n */\nexport function getProviderEnvValue(name: string, env?: ProviderEnv): string | undefined {\n\treturn (\n\t\tenv?.[name] ||\n\t\t(typeof process !== \"undefined\" ? process.env[name] : undefined) ||\n\t\tgetBunSandboxEnvValue(name) ||\n\t\tundefined\n\t);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAkFpD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAK5E","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\nfunction buildProviderErrorPattern(patterns: readonly string[]): RegExp {\n\treturn new RegExp(patterns.join(\"|\"), \"i\");\n}\n\nconst NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([\n\t// OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's\n\t// Zen API. These are subscription/account limits, not transient throttles.\n\t\"GoUsageLimitError\",\n\t\"FreeUsageLimitError\",\n\n\t// OpenCode Go subscription-limit text asks users to enable available-balance\n\t// usage after rolling/weekly/monthly limits are reached.\n\t\"Monthly usage limit reached\",\n\t\"available balance\",\n\n\t// Generic quota/budget/billing exhaustion. `insufficient_quota` is OpenAI's\n\t// quota/billing error code; the other strings cover common gateway wording.\n\t\"insufficient_quota\",\n\t\"out of budget\",\n\t\"quota exceeded\",\n\t\"billing\",\n]);\n\nconst RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([\n\t// Generic provider load, HTTP status, and server-side transient failures.\n\t\"overloaded\",\n\t\"rate.?limit\",\n\t\"too many requests\",\n\t\"429\",\n\t\"500\",\n\t\"502\",\n\t\"503\",\n\t\"504\",\n\t\"524\",\n\t\"service.?unavailable\",\n\t\"server.?error\",\n\t\"internal.?error\",\n\n\t// Wrapper/provider text for transient upstream failures, including OpenRouter\n\t// \"Provider returned error\" responses (#2264).\n\t\"provider.?returned.?error\",\n\n\t// Network, proxy, and fetch transport failures. This includes OpenAI Codex\n\t// raw-fetch failures such as \"upstream connect\", \"connection refused\", and\n\t// \"reset before headers\" (#733), plus OpenRouter connection drops (#3317).\n\t\"network.?error\",\n\t\"connection.?error\",\n\t\"connection.?refused\",\n\t\"connection.?lost\",\n\t\"other side closed\",\n\t\"fetch failed\",\n\t\"upstream.?connect\",\n\t\"reset before headers\",\n\t\"socket hang up\",\n\t\"timed? out\",\n\t\"timeout\",\n\t\"terminated\",\n\n\t// WebSocket transports can report close/error text instead of HTTP/fetch text.\n\t\"websocket.?closed\",\n\t\"websocket.?error\",\n\n\t// Premature stream endings from SDKs and transports. Anthropic can throw\n\t// \"stream ended without ...\" and \"Anthropic stream ended before message_stop\"\n\t// (#4433); Bedrock/Smithy can throw an HTTP/2 no-response error (#3594).\n\t\"ended without\",\n\t\"stream ended before message_stop\",\n\t\"http2 request did not get a response\",\n\n\t// Provider-requested retry delay cap failures should flow through the outer\n\t// retry policy so callers can surface/abort the backoff (#1123).\n\t\"retry delay\",\n\n\t// Explicit retry guidance emitted mid-stream by OpenAI Responses and Bedrock\n\t// stream exceptions (#6019).\n\t\"you can retry your request\",\n\t\"try your request again\",\n\t\"please retry your request\",\n]);\n\n/**\n * Classifies whether a failed assistant message looks like a transient provider\n * or transport error, so callers can decide if the last assistant turn should be\n * restarted.\n *\n * This does not implement retry policy. Callers should first handle context\n * overflow separately, then apply their own retry budget, backoff, and reporting\n * before restarting the assistant turn.\n */\nexport function isRetryableAssistantError(message: AssistantMessage): boolean {\n\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\tconst errorMessage = message.errorMessage;\n\tif (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN.test(errorMessage)) return false;\n\treturn RETRYABLE_PROVIDER_ERROR_PATTERN.test(errorMessage);\n}\n"]}
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAsFpD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAK5E"}
@@ -46,6 +46,7 @@ const RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([
46
46
  "upstream.?connect",
47
47
  "reset before headers",
48
48
  "socket hang up",
49
+ "socket connection was closed",
49
50
  "timed? out",
50
51
  "timeout",
51
52
  "terminated",
@@ -66,6 +67,8 @@ const RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([
66
67
  "you can retry your request",
67
68
  "try your request again",
68
69
  "please retry your request",
70
+ // gRPC based providers (e.g. NVIDIA NIM)
71
+ "ResourceExhausted",
69
72
  ]);
70
73
  /**
71
74
  * Classifies whether a failed assistant message looks like a transient provider
@@ -1 +1 @@
1
- {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAEA,SAAS,yBAAyB,CAAC,QAA2B,EAAU;IACvE,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAAA,CAC3C;AAED,MAAM,0CAA0C,GAAG,yBAAyB,CAAC;IAC5E,8EAA8E;IAC9E,2EAA2E;IAC3E,mBAAmB;IACnB,qBAAqB;IAErB,6EAA6E;IAC7E,yDAAyD;IACzD,6BAA6B;IAC7B,mBAAmB;IAEnB,4EAA4E;IAC5E,4EAA4E;IAC5E,oBAAoB;IACpB,eAAe;IACf,gBAAgB;IAChB,SAAS;CACT,CAAC,CAAC;AAEH,MAAM,gCAAgC,GAAG,yBAAyB,CAAC;IAClE,0EAA0E;IAC1E,YAAY;IACZ,aAAa;IACb,mBAAmB;IACnB,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,sBAAsB;IACtB,eAAe;IACf,iBAAiB;IAEjB,8EAA8E;IAC9E,+CAA+C;IAC/C,2BAA2B;IAE3B,2EAA2E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,gBAAgB;IAChB,mBAAmB;IACnB,qBAAqB;IACrB,kBAAkB;IAClB,mBAAmB;IACnB,cAAc;IACd,mBAAmB;IACnB,sBAAsB;IACtB,gBAAgB;IAChB,YAAY;IACZ,SAAS;IACT,YAAY;IAEZ,+EAA+E;IAC/E,mBAAmB;IACnB,kBAAkB;IAElB,yEAAyE;IACzE,8EAA8E;IAC9E,yEAAyE;IACzE,eAAe;IACf,kCAAkC;IAClC,sCAAsC;IAEtC,4EAA4E;IAC5E,iEAAiE;IACjE,aAAa;IAEb,6EAA6E;IAC7E,6BAA6B;IAC7B,4BAA4B;IAC5B,wBAAwB;IACxB,2BAA2B;CAC3B,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAyB,EAAW;IAC7E,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IAC1E,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC1C,IAAI,0CAA0C,CAAC,IAAI,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IAChF,OAAO,gCAAgC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAAA,CAC3D","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\nfunction buildProviderErrorPattern(patterns: readonly string[]): RegExp {\n\treturn new RegExp(patterns.join(\"|\"), \"i\");\n}\n\nconst NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([\n\t// OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's\n\t// Zen API. These are subscription/account limits, not transient throttles.\n\t\"GoUsageLimitError\",\n\t\"FreeUsageLimitError\",\n\n\t// OpenCode Go subscription-limit text asks users to enable available-balance\n\t// usage after rolling/weekly/monthly limits are reached.\n\t\"Monthly usage limit reached\",\n\t\"available balance\",\n\n\t// Generic quota/budget/billing exhaustion. `insufficient_quota` is OpenAI's\n\t// quota/billing error code; the other strings cover common gateway wording.\n\t\"insufficient_quota\",\n\t\"out of budget\",\n\t\"quota exceeded\",\n\t\"billing\",\n]);\n\nconst RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([\n\t// Generic provider load, HTTP status, and server-side transient failures.\n\t\"overloaded\",\n\t\"rate.?limit\",\n\t\"too many requests\",\n\t\"429\",\n\t\"500\",\n\t\"502\",\n\t\"503\",\n\t\"504\",\n\t\"524\",\n\t\"service.?unavailable\",\n\t\"server.?error\",\n\t\"internal.?error\",\n\n\t// Wrapper/provider text for transient upstream failures, including OpenRouter\n\t// \"Provider returned error\" responses (#2264).\n\t\"provider.?returned.?error\",\n\n\t// Network, proxy, and fetch transport failures. This includes OpenAI Codex\n\t// raw-fetch failures such as \"upstream connect\", \"connection refused\", and\n\t// \"reset before headers\" (#733), plus OpenRouter connection drops (#3317).\n\t\"network.?error\",\n\t\"connection.?error\",\n\t\"connection.?refused\",\n\t\"connection.?lost\",\n\t\"other side closed\",\n\t\"fetch failed\",\n\t\"upstream.?connect\",\n\t\"reset before headers\",\n\t\"socket hang up\",\n\t\"timed? out\",\n\t\"timeout\",\n\t\"terminated\",\n\n\t// WebSocket transports can report close/error text instead of HTTP/fetch text.\n\t\"websocket.?closed\",\n\t\"websocket.?error\",\n\n\t// Premature stream endings from SDKs and transports. Anthropic can throw\n\t// \"stream ended without ...\" and \"Anthropic stream ended before message_stop\"\n\t// (#4433); Bedrock/Smithy can throw an HTTP/2 no-response error (#3594).\n\t\"ended without\",\n\t\"stream ended before message_stop\",\n\t\"http2 request did not get a response\",\n\n\t// Provider-requested retry delay cap failures should flow through the outer\n\t// retry policy so callers can surface/abort the backoff (#1123).\n\t\"retry delay\",\n\n\t// Explicit retry guidance emitted mid-stream by OpenAI Responses and Bedrock\n\t// stream exceptions (#6019).\n\t\"you can retry your request\",\n\t\"try your request again\",\n\t\"please retry your request\",\n]);\n\n/**\n * Classifies whether a failed assistant message looks like a transient provider\n * or transport error, so callers can decide if the last assistant turn should be\n * restarted.\n *\n * This does not implement retry policy. Callers should first handle context\n * overflow separately, then apply their own retry budget, backoff, and reporting\n * before restarting the assistant turn.\n */\nexport function isRetryableAssistantError(message: AssistantMessage): boolean {\n\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\tconst errorMessage = message.errorMessage;\n\tif (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN.test(errorMessage)) return false;\n\treturn RETRYABLE_PROVIDER_ERROR_PATTERN.test(errorMessage);\n}\n"]}
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAEA,SAAS,yBAAyB,CAAC,QAA2B;IAC7D,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,0CAA0C,GAAG,yBAAyB,CAAC;IAC5E,8EAA8E;IAC9E,2EAA2E;IAC3E,mBAAmB;IACnB,qBAAqB;IAErB,6EAA6E;IAC7E,yDAAyD;IACzD,6BAA6B;IAC7B,mBAAmB;IAEnB,4EAA4E;IAC5E,4EAA4E;IAC5E,oBAAoB;IACpB,eAAe;IACf,gBAAgB;IAChB,SAAS;CACT,CAAC,CAAC;AAEH,MAAM,gCAAgC,GAAG,yBAAyB,CAAC;IAClE,0EAA0E;IAC1E,YAAY;IACZ,aAAa;IACb,mBAAmB;IACnB,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,sBAAsB;IACtB,eAAe;IACf,iBAAiB;IAEjB,8EAA8E;IAC9E,+CAA+C;IAC/C,2BAA2B;IAE3B,2EAA2E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,gBAAgB;IAChB,mBAAmB;IACnB,qBAAqB;IACrB,kBAAkB;IAClB,mBAAmB;IACnB,cAAc;IACd,mBAAmB;IACnB,sBAAsB;IACtB,gBAAgB;IAChB,8BAA8B;IAC9B,YAAY;IACZ,SAAS;IACT,YAAY;IAEZ,+EAA+E;IAC/E,mBAAmB;IACnB,kBAAkB;IAElB,yEAAyE;IACzE,8EAA8E;IAC9E,yEAAyE;IACzE,eAAe;IACf,kCAAkC;IAClC,sCAAsC;IAEtC,4EAA4E;IAC5E,iEAAiE;IACjE,aAAa;IAEb,6EAA6E;IAC7E,6BAA6B;IAC7B,4BAA4B;IAC5B,wBAAwB;IACxB,2BAA2B;IAE3B,yCAAyC;IACzC,mBAAmB;CACnB,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAyB;IAClE,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IAC1E,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC1C,IAAI,0CAA0C,CAAC,IAAI,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IAChF,OAAO,gCAAgC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAC5D,CAAC","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\nfunction buildProviderErrorPattern(patterns: readonly string[]): RegExp {\n\treturn new RegExp(patterns.join(\"|\"), \"i\");\n}\n\nconst NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([\n\t// OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's\n\t// Zen API. These are subscription/account limits, not transient throttles.\n\t\"GoUsageLimitError\",\n\t\"FreeUsageLimitError\",\n\n\t// OpenCode Go subscription-limit text asks users to enable available-balance\n\t// usage after rolling/weekly/monthly limits are reached.\n\t\"Monthly usage limit reached\",\n\t\"available balance\",\n\n\t// Generic quota/budget/billing exhaustion. `insufficient_quota` is OpenAI's\n\t// quota/billing error code; the other strings cover common gateway wording.\n\t\"insufficient_quota\",\n\t\"out of budget\",\n\t\"quota exceeded\",\n\t\"billing\",\n]);\n\nconst RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([\n\t// Generic provider load, HTTP status, and server-side transient failures.\n\t\"overloaded\",\n\t\"rate.?limit\",\n\t\"too many requests\",\n\t\"429\",\n\t\"500\",\n\t\"502\",\n\t\"503\",\n\t\"504\",\n\t\"524\",\n\t\"service.?unavailable\",\n\t\"server.?error\",\n\t\"internal.?error\",\n\n\t// Wrapper/provider text for transient upstream failures, including OpenRouter\n\t// \"Provider returned error\" responses (#2264).\n\t\"provider.?returned.?error\",\n\n\t// Network, proxy, and fetch transport failures. This includes OpenAI Codex\n\t// raw-fetch failures such as \"upstream connect\", \"connection refused\", and\n\t// \"reset before headers\" (#733), plus OpenRouter connection drops (#3317).\n\t\"network.?error\",\n\t\"connection.?error\",\n\t\"connection.?refused\",\n\t\"connection.?lost\",\n\t\"other side closed\",\n\t\"fetch failed\",\n\t\"upstream.?connect\",\n\t\"reset before headers\",\n\t\"socket hang up\",\n\t\"socket connection was closed\",\n\t\"timed? out\",\n\t\"timeout\",\n\t\"terminated\",\n\n\t// WebSocket transports can report close/error text instead of HTTP/fetch text.\n\t\"websocket.?closed\",\n\t\"websocket.?error\",\n\n\t// Premature stream endings from SDKs and transports. Anthropic can throw\n\t// \"stream ended without ...\" and \"Anthropic stream ended before message_stop\"\n\t// (#4433); Bedrock/Smithy can throw an HTTP/2 no-response error (#3594).\n\t\"ended without\",\n\t\"stream ended before message_stop\",\n\t\"http2 request did not get a response\",\n\n\t// Provider-requested retry delay cap failures should flow through the outer\n\t// retry policy so callers can surface/abort the backoff (#1123).\n\t\"retry delay\",\n\n\t// Explicit retry guidance emitted mid-stream by OpenAI Responses and Bedrock\n\t// stream exceptions (#6019).\n\t\"you can retry your request\",\n\t\"try your request again\",\n\t\"please retry your request\",\n\n\t// gRPC based providers (e.g. NVIDIA NIM)\n\t\"ResourceExhausted\",\n]);\n\n/**\n * Classifies whether a failed assistant message looks like a transient provider\n * or transport error, so callers can decide if the last assistant turn should be\n * restarted.\n *\n * This does not implement retry policy. Callers should first handle context\n * overflow separately, then apply their own retry budget, backoff, and reporting\n * before restarting the assistant turn.\n */\nexport function isRetryableAssistantError(message: AssistantMessage): boolean {\n\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\tconst errorMessage = message.errorMessage;\n\tif (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN.test(errorMessage)) return false;\n\treturn RETRYABLE_PROVIDER_ERROR_PATTERN.test(errorMessage);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize-unicode.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIvD","sourcesContent":["/**\n * Removes unpaired Unicode surrogate characters from a string.\n *\n * Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,\n * or vice versa) cause JSON serialization errors in many API providers.\n *\n * Valid emoji and other characters outside the Basic Multilingual Plane use properly paired\n * surrogates and will NOT be affected by this function.\n *\n * @param text - The text to sanitize\n * @returns The sanitized text with unpaired surrogates removed\n *\n * @example\n * // Valid emoji (properly paired surrogates) are preserved\n * sanitizeSurrogates(\"Hello 🙈 World\") // => \"Hello 🙈 World\"\n *\n * // Unpaired high surrogate is removed\n * const unpaired = String.fromCharCode(0xD83D); // high surrogate without low\n * sanitizeSurrogates(`Text ${unpaired} here`) // => \"Text here\"\n */\nexport function sanitizeSurrogates(text: string): string {\n\t// Replace unpaired high surrogates (0xD800-0xDBFF not followed by low surrogate)\n\t// Replace unpaired low surrogates (0xDC00-0xDFFF not preceded by high surrogate)\n\treturn text.replace(/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/g, \"\");\n}\n"]}
1
+ {"version":3,"file":"sanitize-unicode.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIvD"}
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize-unicode.js","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAU;IACxD,iFAAiF;IACjF,iFAAiF;IACjF,OAAO,IAAI,CAAC,OAAO,CAAC,yEAAyE,EAAE,EAAE,CAAC,CAAC;AAAA,CACnG","sourcesContent":["/**\n * Removes unpaired Unicode surrogate characters from a string.\n *\n * Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,\n * or vice versa) cause JSON serialization errors in many API providers.\n *\n * Valid emoji and other characters outside the Basic Multilingual Plane use properly paired\n * surrogates and will NOT be affected by this function.\n *\n * @param text - The text to sanitize\n * @returns The sanitized text with unpaired surrogates removed\n *\n * @example\n * // Valid emoji (properly paired surrogates) are preserved\n * sanitizeSurrogates(\"Hello 🙈 World\") // => \"Hello 🙈 World\"\n *\n * // Unpaired high surrogate is removed\n * const unpaired = String.fromCharCode(0xD83D); // high surrogate without low\n * sanitizeSurrogates(`Text ${unpaired} here`) // => \"Text here\"\n */\nexport function sanitizeSurrogates(text: string): string {\n\t// Replace unpaired high surrogates (0xD800-0xDBFF not followed by low surrogate)\n\t// Replace unpaired low surrogates (0xDC00-0xDFFF not preceded by high surrogate)\n\treturn text.replace(/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/g, \"\");\n}\n"]}
1
+ {"version":3,"file":"sanitize-unicode.js","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC9C,iFAAiF;IACjF,iFAAiF;IACjF,OAAO,IAAI,CAAC,OAAO,CAAC,yEAAyE,EAAE,EAAE,CAAC,CAAC;AACpG,CAAC","sourcesContent":["/**\n * Removes unpaired Unicode surrogate characters from a string.\n *\n * Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,\n * or vice versa) cause JSON serialization errors in many API providers.\n *\n * Valid emoji and other characters outside the Basic Multilingual Plane use properly paired\n * surrogates and will NOT be affected by this function.\n *\n * @param text - The text to sanitize\n * @returns The sanitized text with unpaired surrogates removed\n *\n * @example\n * // Valid emoji (properly paired surrogates) are preserved\n * sanitizeSurrogates(\"Hello 🙈 World\") // => \"Hello 🙈 World\"\n *\n * // Unpaired high surrogate is removed\n * const unpaired = String.fromCharCode(0xD83D); // high surrogate without low\n * sanitizeSurrogates(`Text ${unpaired} here`) // => \"Text here\"\n */\nexport function sanitizeSurrogates(text: string): string {\n\t// Replace unpaired high surrogates (0xD800-0xDBFF not followed by low surrogate)\n\t// Replace unpaired low surrogates (0xDC00-0xDFFF not preceded by high surrogate)\n\treturn text.replace(/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/g, \"\");\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"typebox-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACrD,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;CAAE,GACrD,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAOpB","sourcesContent":["import { type TUnsafe, Type } from \"typebox\";\n\n/**\n * Creates a string enum schema compatible with Google's API and other providers\n * that don't support anyOf/const patterns.\n *\n * @example\n * const OperationSchema = StringEnum([\"add\", \"subtract\", \"multiply\", \"divide\"], {\n * description: \"The operation to perform\"\n * });\n *\n * type Operation = Static<typeof OperationSchema>; // \"add\" | \"subtract\" | \"multiply\" | \"divide\"\n */\nexport function StringEnum<T extends readonly string[]>(\n\tvalues: T,\n\toptions?: { description?: string; default?: T[number] },\n): TUnsafe<T[number]> {\n\treturn Type.Unsafe<T[number]>({\n\t\ttype: \"string\",\n\t\tenum: values as any,\n\t\t...(options?.description && { description: options.description }),\n\t\t...(options?.default && { default: options.default }),\n\t});\n}\n"]}
1
+ {"version":3,"file":"typebox-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACrD,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;CAAE,GACrD,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAOpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"typebox-helpers.js","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,IAAI,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CACzB,MAAS,EACT,OAAuD,EAClC;IACrB,OAAO,IAAI,CAAC,MAAM,CAAY;QAC7B,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,MAAa;QACnB,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;QACjE,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;KACrD,CAAC,CAAC;AAAA,CACH","sourcesContent":["import { type TUnsafe, Type } from \"typebox\";\n\n/**\n * Creates a string enum schema compatible with Google's API and other providers\n * that don't support anyOf/const patterns.\n *\n * @example\n * const OperationSchema = StringEnum([\"add\", \"subtract\", \"multiply\", \"divide\"], {\n * description: \"The operation to perform\"\n * });\n *\n * type Operation = Static<typeof OperationSchema>; // \"add\" | \"subtract\" | \"multiply\" | \"divide\"\n */\nexport function StringEnum<T extends readonly string[]>(\n\tvalues: T,\n\toptions?: { description?: string; default?: T[number] },\n): TUnsafe<T[number]> {\n\treturn Type.Unsafe<T[number]>({\n\t\ttype: \"string\",\n\t\tenum: values as any,\n\t\t...(options?.description && { description: options.description }),\n\t\t...(options?.default && { default: options.default }),\n\t});\n}\n"]}
1
+ {"version":3,"file":"typebox-helpers.js","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,IAAI,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CACzB,MAAS,EACT,OAAuD;IAEvD,OAAO,IAAI,CAAC,MAAM,CAAY;QAC7B,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,MAAa;QACnB,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;QACjE,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;KACrD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { type TUnsafe, Type } from \"typebox\";\n\n/**\n * Creates a string enum schema compatible with Google's API and other providers\n * that don't support anyOf/const patterns.\n *\n * @example\n * const OperationSchema = StringEnum([\"add\", \"subtract\", \"multiply\", \"divide\"], {\n * description: \"The operation to perform\"\n * });\n *\n * type Operation = Static<typeof OperationSchema>; // \"add\" | \"subtract\" | \"multiply\" | \"divide\"\n */\nexport function StringEnum<T extends readonly string[]>(\n\tvalues: T,\n\toptions?: { description?: string; default?: T[number] },\n): TUnsafe<T[number]> {\n\treturn Type.Unsafe<T[number]>({\n\t\ttype: \"string\",\n\t\tenum: values as any,\n\t\t...(options?.description && { description: options.description }),\n\t\t...(options?.default && { default: options.default }),\n\t});\n}\n"]}