@bastani/pi-ai 0.9.20-alpha.8 → 0.9.20

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 (370) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +172 -24
  3. package/dist/api/anthropic-messages.d.ts.map +1 -1
  4. package/dist/api/anthropic-messages.js +9 -3
  5. package/dist/api/anthropic-messages.js.map +1 -1
  6. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  7. package/dist/api/azure-openai-responses.js +4 -1
  8. package/dist/api/azure-openai-responses.js.map +1 -1
  9. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  10. package/dist/api/bedrock-converse-stream.js +5 -3
  11. package/dist/api/bedrock-converse-stream.js.map +1 -1
  12. package/dist/api/cloudflare-workers-ai-system-one.d.ts +4 -0
  13. package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -0
  14. package/dist/api/cloudflare-workers-ai-system-one.js +43 -0
  15. package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -0
  16. package/dist/api/cloudflare-workers-ai-system-one.lazy.d.ts +3 -0
  17. package/dist/api/cloudflare-workers-ai-system-one.lazy.d.ts.map +1 -0
  18. package/dist/api/cloudflare-workers-ai-system-one.lazy.js +4 -0
  19. package/dist/api/cloudflare-workers-ai-system-one.lazy.js.map +1 -0
  20. package/dist/api/cloudflare.d.ts +2 -0
  21. package/dist/api/cloudflare.d.ts.map +1 -1
  22. package/dist/api/cloudflare.js +2 -0
  23. package/dist/api/cloudflare.js.map +1 -1
  24. package/dist/api/constrained-sampling.d.ts +8 -3
  25. package/dist/api/constrained-sampling.d.ts.map +1 -1
  26. package/dist/api/constrained-sampling.js +29 -11
  27. package/dist/api/constrained-sampling.js.map +1 -1
  28. package/dist/api/google-generative-ai.d.ts.map +1 -1
  29. package/dist/api/google-generative-ai.js +1 -0
  30. package/dist/api/google-generative-ai.js.map +1 -1
  31. package/dist/api/google-vertex.d.ts.map +1 -1
  32. package/dist/api/google-vertex.js +1 -0
  33. package/dist/api/google-vertex.js.map +1 -1
  34. package/dist/api/mistral-conversations.d.ts.map +1 -1
  35. package/dist/api/mistral-conversations.js +3 -2
  36. package/dist/api/mistral-conversations.js.map +1 -1
  37. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  38. package/dist/api/openai-codex-responses.js +20 -4
  39. package/dist/api/openai-codex-responses.js.map +1 -1
  40. package/dist/api/openai-completions.d.ts.map +1 -1
  41. package/dist/api/openai-completions.js +1 -0
  42. package/dist/api/openai-completions.js.map +1 -1
  43. package/dist/api/openai-responses-shared.d.ts +2 -1
  44. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  45. package/dist/api/openai-responses-shared.js +1 -0
  46. package/dist/api/openai-responses-shared.js.map +1 -1
  47. package/dist/api/openai-responses.d.ts.map +1 -1
  48. package/dist/api/openai-responses.js +1 -0
  49. package/dist/api/openai-responses.js.map +1 -1
  50. package/dist/api/openrouter-images.d.ts +2 -1
  51. package/dist/api/openrouter-images.d.ts.map +1 -1
  52. package/dist/api/openrouter-images.js +1 -0
  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/openrouter-images.lazy.js.map +1 -1
  56. package/dist/api/pi-messages.d.ts.map +1 -1
  57. package/dist/api/pi-messages.js +1 -0
  58. package/dist/api/pi-messages.js.map +1 -1
  59. package/dist/api/simple-options.d.ts.map +1 -1
  60. package/dist/api/simple-options.js +1 -0
  61. package/dist/api/simple-options.js.map +1 -1
  62. package/dist/api/system-one-shared.d.ts +23 -0
  63. package/dist/api/system-one-shared.d.ts.map +1 -0
  64. package/dist/api/system-one-shared.js +170 -0
  65. package/dist/api/system-one-shared.js.map +1 -0
  66. package/dist/api/typesafe-system-one.d.ts +4 -0
  67. package/dist/api/typesafe-system-one.d.ts.map +1 -0
  68. package/dist/api/typesafe-system-one.js +19 -0
  69. package/dist/api/typesafe-system-one.js.map +1 -0
  70. package/dist/api/typesafe-system-one.lazy.d.ts +3 -0
  71. package/dist/api/typesafe-system-one.lazy.d.ts.map +1 -0
  72. package/dist/api/typesafe-system-one.lazy.js +4 -0
  73. package/dist/api/typesafe-system-one.lazy.js.map +1 -0
  74. package/dist/auth/resolve.d.ts +2 -8
  75. package/dist/auth/resolve.d.ts.map +1 -1
  76. package/dist/auth/resolve.js +3 -19
  77. package/dist/auth/resolve.js.map +1 -1
  78. package/dist/env-api-keys.d.ts.map +1 -1
  79. package/dist/env-api-keys.js +1 -0
  80. package/dist/env-api-keys.js.map +1 -1
  81. package/dist/image-models.d.ts +19 -8
  82. package/dist/image-models.d.ts.map +1 -1
  83. package/dist/image-models.js +14 -13
  84. package/dist/image-models.js.map +1 -1
  85. package/dist/images-api-registry.d.ts +7 -7
  86. package/dist/images-api-registry.d.ts.map +1 -1
  87. package/dist/images-api-registry.js.map +1 -1
  88. package/dist/images.d.ts +7 -2
  89. package/dist/images.d.ts.map +1 -1
  90. package/dist/images.js +5 -0
  91. package/dist/images.js.map +1 -1
  92. package/dist/index.d.ts +0 -1
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +0 -1
  95. package/dist/index.js.map +1 -1
  96. package/dist/model-catalog.d.ts +25 -9
  97. package/dist/model-catalog.d.ts.map +1 -1
  98. package/dist/model-catalog.js +14 -2
  99. package/dist/model-catalog.js.map +1 -1
  100. package/dist/models-store.d.ts +3 -2
  101. package/dist/models-store.d.ts.map +1 -1
  102. package/dist/models-store.js.map +1 -1
  103. package/dist/models.d.ts +95 -28
  104. package/dist/models.d.ts.map +1 -1
  105. package/dist/models.generated.d.ts +131 -41
  106. package/dist/models.generated.d.ts.map +1 -1
  107. package/dist/models.generated.js +131 -41
  108. package/dist/models.generated.js.map +1 -1
  109. package/dist/models.js +155 -28
  110. package/dist/models.js.map +1 -1
  111. package/dist/providers/all.d.ts +19 -13
  112. package/dist/providers/all.d.ts.map +1 -1
  113. package/dist/providers/all.js +25 -21
  114. package/dist/providers/all.js.map +1 -1
  115. package/dist/providers/amazon-bedrock.models.d.ts +4 -2
  116. package/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
  117. package/dist/providers/amazon-bedrock.models.js +4 -2
  118. package/dist/providers/amazon-bedrock.models.js.map +1 -1
  119. package/dist/providers/ant-ling.models.d.ts +4 -2
  120. package/dist/providers/ant-ling.models.d.ts.map +1 -1
  121. package/dist/providers/ant-ling.models.js +4 -2
  122. package/dist/providers/ant-ling.models.js.map +1 -1
  123. package/dist/providers/anthropic.models.d.ts +4 -2
  124. package/dist/providers/anthropic.models.d.ts.map +1 -1
  125. package/dist/providers/anthropic.models.js +4 -2
  126. package/dist/providers/anthropic.models.js.map +1 -1
  127. package/dist/providers/azure-openai-responses.models.d.ts +4 -2
  128. package/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
  129. package/dist/providers/azure-openai-responses.models.js +4 -2
  130. package/dist/providers/azure-openai-responses.models.js.map +1 -1
  131. package/dist/providers/baseten.models.d.ts +4 -2
  132. package/dist/providers/baseten.models.d.ts.map +1 -1
  133. package/dist/providers/baseten.models.js +4 -2
  134. package/dist/providers/baseten.models.js.map +1 -1
  135. package/dist/providers/cerebras.models.d.ts +4 -2
  136. package/dist/providers/cerebras.models.d.ts.map +1 -1
  137. package/dist/providers/cerebras.models.js +4 -2
  138. package/dist/providers/cerebras.models.js.map +1 -1
  139. package/dist/providers/cloudflare-ai-gateway.models.d.ts +4 -2
  140. package/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
  141. package/dist/providers/cloudflare-ai-gateway.models.js +4 -2
  142. package/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
  143. package/dist/providers/cloudflare-stream.d.ts +6 -2
  144. package/dist/providers/cloudflare-stream.d.ts.map +1 -1
  145. package/dist/providers/cloudflare-stream.js +6 -0
  146. package/dist/providers/cloudflare-stream.js.map +1 -1
  147. package/dist/providers/cloudflare-workers-ai.d.ts.map +1 -1
  148. package/dist/providers/cloudflare-workers-ai.js +10 -3
  149. package/dist/providers/cloudflare-workers-ai.js.map +1 -1
  150. package/dist/providers/cloudflare-workers-ai.models.d.ts +4 -2
  151. package/dist/providers/cloudflare-workers-ai.models.d.ts.map +1 -1
  152. package/dist/providers/cloudflare-workers-ai.models.js +4 -2
  153. package/dist/providers/cloudflare-workers-ai.models.js.map +1 -1
  154. package/dist/providers/data/.manifest.json +1 -1
  155. package/dist/providers/data/amazon-bedrock.json +1 -1
  156. package/dist/providers/data/ant-ling.json +1 -1
  157. package/dist/providers/data/anthropic.json +1 -1
  158. package/dist/providers/data/azure-openai-responses.json +1 -1
  159. package/dist/providers/data/baseten.json +1 -1
  160. package/dist/providers/data/cerebras.json +1 -1
  161. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  162. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  163. package/dist/providers/data/deepseek.json +1 -1
  164. package/dist/providers/data/fireworks.json +1 -1
  165. package/dist/providers/data/github-copilot.json +1 -1
  166. package/dist/providers/data/google-vertex.json +1 -1
  167. package/dist/providers/data/google.json +1 -1
  168. package/dist/providers/data/groq.json +1 -1
  169. package/dist/providers/data/huggingface.json +1 -1
  170. package/dist/providers/data/kimi-coding.json +1 -1
  171. package/dist/providers/data/meta.json +1 -1
  172. package/dist/providers/data/minimax-cn.json +1 -1
  173. package/dist/providers/data/minimax.json +1 -1
  174. package/dist/providers/data/mistral.json +1 -1
  175. package/dist/providers/data/moonshotai-cn.json +1 -1
  176. package/dist/providers/data/moonshotai.json +1 -1
  177. package/dist/providers/data/nvidia.json +1 -1
  178. package/dist/providers/data/openai-codex.json +1 -1
  179. package/dist/providers/data/openai.json +1 -1
  180. package/dist/providers/data/opencode-go.json +1 -1
  181. package/dist/providers/data/opencode.json +1 -1
  182. package/dist/providers/data/openrouter.json +1 -1
  183. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  184. package/dist/providers/data/qwen-token-plan-individual.json +1 -1
  185. package/dist/providers/data/qwen-token-plan.json +1 -1
  186. package/dist/providers/data/radius.json +1 -1
  187. package/dist/providers/data/together.json +1 -1
  188. package/dist/providers/data/typesafe.json +1 -0
  189. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  190. package/dist/providers/data/xai.json +1 -1
  191. package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  192. package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  193. package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  194. package/dist/providers/data/xiaomi.json +1 -1
  195. package/dist/providers/data/zai-coding-cn.json +1 -1
  196. package/dist/providers/data/zai.json +1 -1
  197. package/dist/providers/deepseek.models.d.ts +4 -2
  198. package/dist/providers/deepseek.models.d.ts.map +1 -1
  199. package/dist/providers/deepseek.models.js +4 -2
  200. package/dist/providers/deepseek.models.js.map +1 -1
  201. package/dist/providers/fireworks.models.d.ts +4 -2
  202. package/dist/providers/fireworks.models.d.ts.map +1 -1
  203. package/dist/providers/fireworks.models.js +4 -2
  204. package/dist/providers/fireworks.models.js.map +1 -1
  205. package/dist/providers/github-copilot.models.d.ts +4 -2
  206. package/dist/providers/github-copilot.models.d.ts.map +1 -1
  207. package/dist/providers/github-copilot.models.js +4 -2
  208. package/dist/providers/github-copilot.models.js.map +1 -1
  209. package/dist/providers/google-vertex.models.d.ts +4 -2
  210. package/dist/providers/google-vertex.models.d.ts.map +1 -1
  211. package/dist/providers/google-vertex.models.js +4 -2
  212. package/dist/providers/google-vertex.models.js.map +1 -1
  213. package/dist/providers/google.models.d.ts +4 -2
  214. package/dist/providers/google.models.d.ts.map +1 -1
  215. package/dist/providers/google.models.js +4 -2
  216. package/dist/providers/google.models.js.map +1 -1
  217. package/dist/providers/groq.models.d.ts +4 -2
  218. package/dist/providers/groq.models.d.ts.map +1 -1
  219. package/dist/providers/groq.models.js +4 -2
  220. package/dist/providers/groq.models.js.map +1 -1
  221. package/dist/providers/huggingface.models.d.ts +4 -2
  222. package/dist/providers/huggingface.models.d.ts.map +1 -1
  223. package/dist/providers/huggingface.models.js +4 -2
  224. package/dist/providers/huggingface.models.js.map +1 -1
  225. package/dist/providers/images/register-builtins.d.ts +1 -1
  226. package/dist/providers/images/register-builtins.d.ts.map +1 -1
  227. package/dist/providers/images/register-builtins.js.map +1 -1
  228. package/dist/providers/kimi-coding.models.d.ts +4 -2
  229. package/dist/providers/kimi-coding.models.d.ts.map +1 -1
  230. package/dist/providers/kimi-coding.models.js +4 -2
  231. package/dist/providers/kimi-coding.models.js.map +1 -1
  232. package/dist/providers/meta.models.d.ts +4 -2
  233. package/dist/providers/meta.models.d.ts.map +1 -1
  234. package/dist/providers/meta.models.js +4 -2
  235. package/dist/providers/meta.models.js.map +1 -1
  236. package/dist/providers/minimax-cn.models.d.ts +4 -2
  237. package/dist/providers/minimax-cn.models.d.ts.map +1 -1
  238. package/dist/providers/minimax-cn.models.js +4 -2
  239. package/dist/providers/minimax-cn.models.js.map +1 -1
  240. package/dist/providers/minimax.models.d.ts +4 -2
  241. package/dist/providers/minimax.models.d.ts.map +1 -1
  242. package/dist/providers/minimax.models.js +4 -2
  243. package/dist/providers/minimax.models.js.map +1 -1
  244. package/dist/providers/mistral.models.d.ts +4 -2
  245. package/dist/providers/mistral.models.d.ts.map +1 -1
  246. package/dist/providers/mistral.models.js +4 -2
  247. package/dist/providers/mistral.models.js.map +1 -1
  248. package/dist/providers/moonshotai-cn.models.d.ts +4 -2
  249. package/dist/providers/moonshotai-cn.models.d.ts.map +1 -1
  250. package/dist/providers/moonshotai-cn.models.js +4 -2
  251. package/dist/providers/moonshotai-cn.models.js.map +1 -1
  252. package/dist/providers/moonshotai.models.d.ts +4 -2
  253. package/dist/providers/moonshotai.models.d.ts.map +1 -1
  254. package/dist/providers/moonshotai.models.js +4 -2
  255. package/dist/providers/moonshotai.models.js.map +1 -1
  256. package/dist/providers/nvidia.models.d.ts +4 -2
  257. package/dist/providers/nvidia.models.d.ts.map +1 -1
  258. package/dist/providers/nvidia.models.js +4 -2
  259. package/dist/providers/nvidia.models.js.map +1 -1
  260. package/dist/providers/openai-codex.models.d.ts +4 -2
  261. package/dist/providers/openai-codex.models.d.ts.map +1 -1
  262. package/dist/providers/openai-codex.models.js +4 -2
  263. package/dist/providers/openai-codex.models.js.map +1 -1
  264. package/dist/providers/openai.models.d.ts +4 -2
  265. package/dist/providers/openai.models.d.ts.map +1 -1
  266. package/dist/providers/openai.models.js +4 -2
  267. package/dist/providers/openai.models.js.map +1 -1
  268. package/dist/providers/opencode-go.models.d.ts +4 -2
  269. package/dist/providers/opencode-go.models.d.ts.map +1 -1
  270. package/dist/providers/opencode-go.models.js +4 -2
  271. package/dist/providers/opencode-go.models.js.map +1 -1
  272. package/dist/providers/opencode.models.d.ts +4 -2
  273. package/dist/providers/opencode.models.d.ts.map +1 -1
  274. package/dist/providers/opencode.models.js +4 -2
  275. package/dist/providers/opencode.models.js.map +1 -1
  276. package/dist/providers/openrouter.d.ts.map +1 -1
  277. package/dist/providers/openrouter.js +11 -2
  278. package/dist/providers/openrouter.js.map +1 -1
  279. package/dist/providers/openrouter.models.d.ts +4 -2
  280. package/dist/providers/openrouter.models.d.ts.map +1 -1
  281. package/dist/providers/openrouter.models.js +4 -2
  282. package/dist/providers/openrouter.models.js.map +1 -1
  283. package/dist/providers/qwen-token-plan-cn.models.d.ts +4 -2
  284. package/dist/providers/qwen-token-plan-cn.models.d.ts.map +1 -1
  285. package/dist/providers/qwen-token-plan-cn.models.js +4 -2
  286. package/dist/providers/qwen-token-plan-cn.models.js.map +1 -1
  287. package/dist/providers/qwen-token-plan-individual.models.d.ts +4 -2
  288. package/dist/providers/qwen-token-plan-individual.models.d.ts.map +1 -1
  289. package/dist/providers/qwen-token-plan-individual.models.js +4 -2
  290. package/dist/providers/qwen-token-plan-individual.models.js.map +1 -1
  291. package/dist/providers/qwen-token-plan.models.d.ts +4 -2
  292. package/dist/providers/qwen-token-plan.models.d.ts.map +1 -1
  293. package/dist/providers/qwen-token-plan.models.js +4 -2
  294. package/dist/providers/qwen-token-plan.models.js.map +1 -1
  295. package/dist/providers/radius.models.d.ts +4 -2
  296. package/dist/providers/radius.models.d.ts.map +1 -1
  297. package/dist/providers/radius.models.js +4 -2
  298. package/dist/providers/radius.models.js.map +1 -1
  299. package/dist/providers/together.models.d.ts +4 -2
  300. package/dist/providers/together.models.d.ts.map +1 -1
  301. package/dist/providers/together.models.js +4 -2
  302. package/dist/providers/together.models.js.map +1 -1
  303. package/dist/providers/typesafe.d.ts +3 -0
  304. package/dist/providers/typesafe.d.ts.map +1 -0
  305. package/dist/providers/typesafe.js +18 -0
  306. package/dist/providers/typesafe.js.map +1 -0
  307. package/dist/providers/typesafe.models.d.ts +5 -0
  308. package/dist/providers/typesafe.models.d.ts.map +1 -0
  309. package/dist/providers/typesafe.models.js +8 -0
  310. package/dist/providers/typesafe.models.js.map +1 -0
  311. package/dist/providers/vercel-ai-gateway.models.d.ts +4 -2
  312. package/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  313. package/dist/providers/vercel-ai-gateway.models.js +4 -2
  314. package/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  315. package/dist/providers/xai.models.d.ts +4 -2
  316. package/dist/providers/xai.models.d.ts.map +1 -1
  317. package/dist/providers/xai.models.js +4 -2
  318. package/dist/providers/xai.models.js.map +1 -1
  319. package/dist/providers/xiaomi-token-plan-ams.models.d.ts +4 -2
  320. package/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
  321. package/dist/providers/xiaomi-token-plan-ams.models.js +4 -2
  322. package/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
  323. package/dist/providers/xiaomi-token-plan-cn.models.d.ts +4 -2
  324. package/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
  325. package/dist/providers/xiaomi-token-plan-cn.models.js +4 -2
  326. package/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
  327. package/dist/providers/xiaomi-token-plan-sgp.models.d.ts +4 -2
  328. package/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
  329. package/dist/providers/xiaomi-token-plan-sgp.models.js +4 -2
  330. package/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
  331. package/dist/providers/xiaomi.models.d.ts +4 -2
  332. package/dist/providers/xiaomi.models.d.ts.map +1 -1
  333. package/dist/providers/xiaomi.models.js +4 -2
  334. package/dist/providers/xiaomi.models.js.map +1 -1
  335. package/dist/providers/zai-coding-cn.models.d.ts +4 -2
  336. package/dist/providers/zai-coding-cn.models.d.ts.map +1 -1
  337. package/dist/providers/zai-coding-cn.models.js +4 -2
  338. package/dist/providers/zai-coding-cn.models.js.map +1 -1
  339. package/dist/providers/zai.models.d.ts +4 -2
  340. package/dist/providers/zai.models.d.ts.map +1 -1
  341. package/dist/providers/zai.models.js +4 -2
  342. package/dist/providers/zai.models.js.map +1 -1
  343. package/dist/types.d.ts +109 -26
  344. package/dist/types.d.ts.map +1 -1
  345. package/dist/types.js.map +1 -1
  346. package/dist/utils/headers.d.ts +1 -1
  347. package/dist/utils/headers.d.ts.map +1 -1
  348. package/dist/utils/headers.js +10 -8
  349. package/dist/utils/headers.js.map +1 -1
  350. package/dist/utils/model-operations.d.ts +11 -0
  351. package/dist/utils/model-operations.d.ts.map +1 -0
  352. package/dist/utils/model-operations.js +47 -0
  353. package/dist/utils/model-operations.js.map +1 -0
  354. package/dist/utils/models-error.d.ts +8 -0
  355. package/dist/utils/models-error.d.ts.map +1 -0
  356. package/dist/utils/models-error.js +19 -0
  357. package/dist/utils/models-error.js.map +1 -0
  358. package/package.json +1 -2
  359. package/dist/image-models.generated.d.ts +0 -830
  360. package/dist/image-models.generated.d.ts.map +0 -1
  361. package/dist/image-models.generated.js +0 -832
  362. package/dist/image-models.generated.js.map +0 -1
  363. package/dist/images-models.d.ts +0 -95
  364. package/dist/images-models.d.ts.map +0 -1
  365. package/dist/images-models.js +0 -143
  366. package/dist/images-models.js.map +0 -1
  367. package/dist/providers/openrouter-images.d.ts +0 -3
  368. package/dist/providers/openrouter-images.d.ts.map +0 -1
  369. package/dist/providers/openrouter-images.js +0 -22
  370. package/dist/providers/openrouter-images.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../src/model-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEjE,KAAK,OAAO,CAAC,OAAO,SAAS,WAAW,IAAI;KAC1C,IAAI,IAAI,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;CAC5C,CAAC,MAAM,OAAO,CAAC,GACf,MAAM,CAAC;AAER,KAAK,QAAQ,CAAC,OAAO,SAAS,WAAW,EAAE,QAAQ,SAAS,OAAO,CAAC,OAAO,CAAC,IAAI;KAC9E,IAAI,IAAI,MAAM,OAAO,GAAG,QAAQ,SAAS,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK;CAC5E,CAAC,MAAM,OAAO,CAAC,GACf,GAAG,CAAC;AAEL,MAAM,MAAM,YAAY,CAAC,OAAO,SAAS,WAAW,EAAE,SAAS,SAAS,UAAU,IAAI;KACpF,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,GAAG;QACpE,EAAE,EAAE,QAAQ,CAAC;QACb,QAAQ,EAAE,SAAS,CAAC;KACpB;CACD,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,SAAS,SAAS,UAAU,EAAE,KAAK,CAAC,OAAO,SAAS,WAAW,EACxG,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,OAAO,GACb,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,CAElC","sourcesContent":["import type { Api, Model, ProviderId } from \"./types.ts\";\n\nexport type ModelGroups = Record<string, Record<string, object>>;\n\ntype ModelId<TGroups extends ModelGroups> = {\n\t[TApi in keyof TGroups]: keyof TGroups[TApi];\n}[keyof TGroups] &\n\tstring;\n\ntype ModelApi<TGroups extends ModelGroups, TModelId extends ModelId<TGroups>> = {\n\t[TApi in keyof TGroups]: TModelId extends keyof TGroups[TApi] ? TApi : never;\n}[keyof TGroups] &\n\tApi;\n\nexport type ModelCatalog<TGroups extends ModelGroups, TProvider extends ProviderId> = {\n\t[TModelId in ModelId<TGroups>]: Model<ModelApi<TGroups, TModelId>> & {\n\t\tid: TModelId;\n\t\tprovider: TProvider;\n\t};\n};\n\nexport function flattenModelCatalog<const TProvider extends ProviderId, const TGroups extends ModelGroups>(\n\t_provider: TProvider,\n\tgroups: TGroups,\n): ModelCatalog<TGroups, TProvider> {\n\treturn Object.assign({}, ...Object.values(groups)) as ModelCatalog<TGroups, TProvider>;\n}\n"]}
1
+ {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../src/model-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tApi,\n\tClassifierApi,\n\tClassifierModel,\n\tImageApi,\n\tImageModel,\n\tModel,\n\tModelType,\n\tProviderId,\n} from \"./types.ts\";\n\nexport type ModelGroups = Record<string, Record<string, object>>;\n\ntype ModelKey<TGroups extends ModelGroups> = {\n\t[TApi in keyof TGroups]: keyof TGroups[TApi];\n}[keyof TGroups] &\n\tstring;\n\ntype KeyForType<TGroups extends ModelGroups, TType extends ModelType> = Extract<\n\tModelKey<TGroups>,\n\t`${TType}:${string}`\n>;\n\ntype ModelId<TKey extends string> = TKey extends `${ModelType}:${infer TModelId}` ? TModelId : never;\n\ntype ApiForKey<TGroups extends ModelGroups, TKey extends ModelKey<TGroups>> = {\n\t[TApi in keyof TGroups]: TKey extends keyof TGroups[TApi] ? TApi : never;\n}[keyof TGroups];\n\nexport type ChatModelCatalog<TGroups extends ModelGroups, TProvider extends ProviderId> = {\n\t[TKey in KeyForType<TGroups, \"chat\"> as ModelId<TKey>]: Model<ApiForKey<TGroups, TKey> & Api> & {\n\t\tid: ModelId<TKey>;\n\t\tprovider: TProvider;\n\t};\n};\n\nexport type ImageModelCatalog<TGroups extends ModelGroups, TProvider extends ProviderId> = {\n\t[TKey in KeyForType<TGroups, \"image\"> as ModelId<TKey>]: ImageModel<ApiForKey<TGroups, TKey> & ImageApi> & {\n\t\tid: ModelId<TKey>;\n\t\tprovider: TProvider;\n\t};\n};\n\nexport type ClassifierModelCatalog<TGroups extends ModelGroups, TProvider extends ProviderId> = {\n\t[TKey in KeyForType<TGroups, \"classifier\"> as ModelId<TKey>]: ClassifierModel<\n\t\tApiForKey<TGroups, TKey> & ClassifierApi\n\t> & {\n\t\tid: ModelId<TKey>;\n\t\tprovider: TProvider;\n\t};\n};\n\nfunction flattenModelCatalog(groups: ModelGroups, type: ModelType): Record<string, object> {\n\treturn Object.fromEntries(\n\t\tObject.values(groups)\n\t\t\t.flatMap((models) => Object.values(models))\n\t\t\t.filter((model) => (model as { type?: unknown }).type === type)\n\t\t\t.map((model) => [(model as { id: string }).id, model]),\n\t);\n}\n\nexport function flattenChatModelCatalog<const TProvider extends ProviderId, const TGroups extends ModelGroups>(\n\t_provider: TProvider,\n\tgroups: TGroups,\n): ChatModelCatalog<TGroups, TProvider> {\n\treturn flattenModelCatalog(groups, \"chat\") as ChatModelCatalog<TGroups, TProvider>;\n}\n\nexport function flattenImageModelCatalog<const TProvider extends ProviderId, const TGroups extends ModelGroups>(\n\t_provider: TProvider,\n\tgroups: TGroups,\n): ImageModelCatalog<TGroups, TProvider> {\n\treturn flattenModelCatalog(groups, \"image\") as ImageModelCatalog<TGroups, TProvider>;\n}\n\nexport function flattenClassifierModelCatalog<const TProvider extends ProviderId, const TGroups extends ModelGroups>(\n\t_provider: TProvider,\n\tgroups: TGroups,\n): ClassifierModelCatalog<TGroups, TProvider> {\n\treturn flattenModelCatalog(groups, \"classifier\") as ClassifierModelCatalog<TGroups, TProvider>;\n}\n"]}
@@ -1,4 +1,16 @@
1
- export function flattenModelCatalog(_provider, groups) {
2
- return Object.assign({}, ...Object.values(groups));
1
+ function flattenModelCatalog(groups, type) {
2
+ return Object.fromEntries(Object.values(groups)
3
+ .flatMap((models) => Object.values(models))
4
+ .filter((model) => model.type === type)
5
+ .map((model) => [model.id, model]));
6
+ }
7
+ export function flattenChatModelCatalog(_provider, groups) {
8
+ return flattenModelCatalog(groups, "chat");
9
+ }
10
+ export function flattenImageModelCatalog(_provider, groups) {
11
+ return flattenModelCatalog(groups, "image");
12
+ }
13
+ export function flattenClassifierModelCatalog(_provider, groups) {
14
+ return flattenModelCatalog(groups, "classifier");
3
15
  }
4
16
  //# sourceMappingURL=model-catalog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-catalog.js","sourceRoot":"","sources":["../src/model-catalog.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,mBAAmB,CAClC,SAAoB,EACpB,MAAe,EACoB;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAqC,CAAC;AAAA,CACvF","sourcesContent":["import type { Api, Model, ProviderId } from \"./types.ts\";\n\nexport type ModelGroups = Record<string, Record<string, object>>;\n\ntype ModelId<TGroups extends ModelGroups> = {\n\t[TApi in keyof TGroups]: keyof TGroups[TApi];\n}[keyof TGroups] &\n\tstring;\n\ntype ModelApi<TGroups extends ModelGroups, TModelId extends ModelId<TGroups>> = {\n\t[TApi in keyof TGroups]: TModelId extends keyof TGroups[TApi] ? TApi : never;\n}[keyof TGroups] &\n\tApi;\n\nexport type ModelCatalog<TGroups extends ModelGroups, TProvider extends ProviderId> = {\n\t[TModelId in ModelId<TGroups>]: Model<ModelApi<TGroups, TModelId>> & {\n\t\tid: TModelId;\n\t\tprovider: TProvider;\n\t};\n};\n\nexport function flattenModelCatalog<const TProvider extends ProviderId, const TGroups extends ModelGroups>(\n\t_provider: TProvider,\n\tgroups: TGroups,\n): ModelCatalog<TGroups, TProvider> {\n\treturn Object.assign({}, ...Object.values(groups)) as ModelCatalog<TGroups, TProvider>;\n}\n"]}
1
+ {"version":3,"file":"model-catalog.js","sourceRoot":"","sources":["../src/model-catalog.ts"],"names":[],"mappings":"AAoDA,SAAS,mBAAmB,CAAC,MAAmB,EAAE,IAAe,EAA0B;IAC1F,OAAO,MAAM,CAAC,WAAW,CACxB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;SACnB,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;SAC1C,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAE,KAA4B,CAAC,IAAI,KAAK,IAAI,CAAC;SAC9D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAE,KAAwB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CACvD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,uBAAuB,CACtC,SAAoB,EACpB,MAAe,EACwB;IACvC,OAAO,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAyC,CAAC;AAAA,CACnF;AAED,MAAM,UAAU,wBAAwB,CACvC,SAAoB,EACpB,MAAe,EACyB;IACxC,OAAO,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAA0C,CAAC;AAAA,CACrF;AAED,MAAM,UAAU,6BAA6B,CAC5C,SAAoB,EACpB,MAAe,EAC8B;IAC7C,OAAO,mBAAmB,CAAC,MAAM,EAAE,YAAY,CAA+C,CAAC;AAAA,CAC/F","sourcesContent":["import type {\n\tApi,\n\tClassifierApi,\n\tClassifierModel,\n\tImageApi,\n\tImageModel,\n\tModel,\n\tModelType,\n\tProviderId,\n} from \"./types.ts\";\n\nexport type ModelGroups = Record<string, Record<string, object>>;\n\ntype ModelKey<TGroups extends ModelGroups> = {\n\t[TApi in keyof TGroups]: keyof TGroups[TApi];\n}[keyof TGroups] &\n\tstring;\n\ntype KeyForType<TGroups extends ModelGroups, TType extends ModelType> = Extract<\n\tModelKey<TGroups>,\n\t`${TType}:${string}`\n>;\n\ntype ModelId<TKey extends string> = TKey extends `${ModelType}:${infer TModelId}` ? TModelId : never;\n\ntype ApiForKey<TGroups extends ModelGroups, TKey extends ModelKey<TGroups>> = {\n\t[TApi in keyof TGroups]: TKey extends keyof TGroups[TApi] ? TApi : never;\n}[keyof TGroups];\n\nexport type ChatModelCatalog<TGroups extends ModelGroups, TProvider extends ProviderId> = {\n\t[TKey in KeyForType<TGroups, \"chat\"> as ModelId<TKey>]: Model<ApiForKey<TGroups, TKey> & Api> & {\n\t\tid: ModelId<TKey>;\n\t\tprovider: TProvider;\n\t};\n};\n\nexport type ImageModelCatalog<TGroups extends ModelGroups, TProvider extends ProviderId> = {\n\t[TKey in KeyForType<TGroups, \"image\"> as ModelId<TKey>]: ImageModel<ApiForKey<TGroups, TKey> & ImageApi> & {\n\t\tid: ModelId<TKey>;\n\t\tprovider: TProvider;\n\t};\n};\n\nexport type ClassifierModelCatalog<TGroups extends ModelGroups, TProvider extends ProviderId> = {\n\t[TKey in KeyForType<TGroups, \"classifier\"> as ModelId<TKey>]: ClassifierModel<\n\t\tApiForKey<TGroups, TKey> & ClassifierApi\n\t> & {\n\t\tid: ModelId<TKey>;\n\t\tprovider: TProvider;\n\t};\n};\n\nfunction flattenModelCatalog(groups: ModelGroups, type: ModelType): Record<string, object> {\n\treturn Object.fromEntries(\n\t\tObject.values(groups)\n\t\t\t.flatMap((models) => Object.values(models))\n\t\t\t.filter((model) => (model as { type?: unknown }).type === type)\n\t\t\t.map((model) => [(model as { id: string }).id, model]),\n\t);\n}\n\nexport function flattenChatModelCatalog<const TProvider extends ProviderId, const TGroups extends ModelGroups>(\n\t_provider: TProvider,\n\tgroups: TGroups,\n): ChatModelCatalog<TGroups, TProvider> {\n\treturn flattenModelCatalog(groups, \"chat\") as ChatModelCatalog<TGroups, TProvider>;\n}\n\nexport function flattenImageModelCatalog<const TProvider extends ProviderId, const TGroups extends ModelGroups>(\n\t_provider: TProvider,\n\tgroups: TGroups,\n): ImageModelCatalog<TGroups, TProvider> {\n\treturn flattenModelCatalog(groups, \"image\") as ImageModelCatalog<TGroups, TProvider>;\n}\n\nexport function flattenClassifierModelCatalog<const TProvider extends ProviderId, const TGroups extends ModelGroups>(\n\t_provider: TProvider,\n\tgroups: TGroups,\n): ClassifierModelCatalog<TGroups, TProvider> {\n\treturn flattenModelCatalog(groups, \"classifier\") as ClassifierModelCatalog<TGroups, TProvider>;\n}\n"]}
@@ -1,6 +1,7 @@
1
- import type { Api, Model } from "./types.ts";
1
+ import type { AnyModel } from "./types.ts";
2
2
  export interface ModelsStoreEntry {
3
- models: readonly Model<Api>[];
3
+ /** Persisted models of every type. */
4
+ models: readonly AnyModel[];
4
5
  /** Unix timestamp from the remote catalog's Last-Modified header. */
5
6
  lastModified?: number;
6
7
  /** Unix timestamp of the last completed remote check. */
@@ -1 +1 @@
1
- {"version":3,"file":"models-store.d.ts","sourceRoot":"","sources":["../src/models-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,2BAA2B;IAC3C,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,sDAAsD;AACtD,MAAM,WAAW,WAAW;IAC3B,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IACvG,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzG,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjF;AAED,qBAAa,mBAAoB,YAAW,WAAW;IACtD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAEzD,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAI3G;IAEK,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7G;IAEK,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrF;CACD","sourcesContent":["import type { Api, Model } from \"./types.ts\";\n\nexport interface ModelsStoreEntry {\n\tmodels: readonly Model<Api>[];\n\t/** Unix timestamp from the remote catalog's Last-Modified header. */\n\tlastModified?: number;\n\t/** Unix timestamp of the last completed remote check. */\n\tcheckedAt?: number;\n\t/**\n\t * Opaque validator from the remote catalog's ETag header, stored verbatim\n\t * (quotes included) and echoed back as If-None-Match.\n\t */\n\tetag?: string;\n}\n\nexport interface ModelsStoreOperationOptions {\n\tsignal?: AbortSignal;\n}\n\n/** Persistent model catalogs keyed by provider ID. */\nexport interface ModelsStore {\n\tread(providerId: string, options?: ModelsStoreOperationOptions): Promise<ModelsStoreEntry | undefined>;\n\twrite(providerId: string, entry: ModelsStoreEntry, options?: ModelsStoreOperationOptions): Promise<void>;\n\tdelete(providerId: string, options?: ModelsStoreOperationOptions): Promise<void>;\n}\n\nexport class InMemoryModelsStore implements ModelsStore {\n\tprivate readonly entries = new Map<string, ModelsStoreEntry>();\n\n\tasync read(providerId: string, options?: ModelsStoreOperationOptions): Promise<ModelsStoreEntry | undefined> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tconst entry = this.entries.get(providerId);\n\t\treturn entry ? structuredClone(entry) : undefined;\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry, options?: ModelsStoreOperationOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tthis.entries.set(providerId, structuredClone(entry));\n\t}\n\n\tasync delete(providerId: string, options?: ModelsStoreOperationOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tthis.entries.delete(providerId);\n\t}\n}\n"]}
1
+ {"version":3,"file":"models-store.d.ts","sourceRoot":"","sources":["../src/models-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAChC,sCAAsC;IACtC,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC5B,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,2BAA2B;IAC3C,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,sDAAsD;AACtD,MAAM,WAAW,WAAW;IAC3B,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IACvG,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzG,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjF;AAED,qBAAa,mBAAoB,YAAW,WAAW;IACtD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAEzD,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAI3G;IAEK,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7G;IAEK,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrF;CACD","sourcesContent":["import type { AnyModel } from \"./types.ts\";\n\nexport interface ModelsStoreEntry {\n\t/** Persisted models of every type. */\n\tmodels: readonly AnyModel[];\n\t/** Unix timestamp from the remote catalog's Last-Modified header. */\n\tlastModified?: number;\n\t/** Unix timestamp of the last completed remote check. */\n\tcheckedAt?: number;\n\t/**\n\t * Opaque validator from the remote catalog's ETag header, stored verbatim\n\t * (quotes included) and echoed back as If-None-Match.\n\t */\n\tetag?: string;\n}\n\nexport interface ModelsStoreOperationOptions {\n\tsignal?: AbortSignal;\n}\n\n/** Persistent model catalogs keyed by provider ID. */\nexport interface ModelsStore {\n\tread(providerId: string, options?: ModelsStoreOperationOptions): Promise<ModelsStoreEntry | undefined>;\n\twrite(providerId: string, entry: ModelsStoreEntry, options?: ModelsStoreOperationOptions): Promise<void>;\n\tdelete(providerId: string, options?: ModelsStoreOperationOptions): Promise<void>;\n}\n\nexport class InMemoryModelsStore implements ModelsStore {\n\tprivate readonly entries = new Map<string, ModelsStoreEntry>();\n\n\tasync read(providerId: string, options?: ModelsStoreOperationOptions): Promise<ModelsStoreEntry | undefined> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tconst entry = this.entries.get(providerId);\n\t\treturn entry ? structuredClone(entry) : undefined;\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry, options?: ModelsStoreOperationOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tthis.entries.set(providerId, structuredClone(entry));\n\t}\n\n\tasync delete(providerId: string, options?: ModelsStoreOperationOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tthis.entries.delete(providerId);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"models-store.js","sourceRoot":"","sources":["../src/models-store.ts"],"names":[],"mappings":"AA0BA,MAAM,OAAO,mBAAmB;IACd,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IAE/D,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAE,OAAqC,EAAyC;QAC5G,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3C,OAAO,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAAA,CAClD;IAED,KAAK,CAAC,KAAK,CAAC,UAAkB,EAAE,KAAuB,EAAE,OAAqC,EAAiB;QAC9G,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IAAA,CACrD;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB,EAAE,OAAqC,EAAiB;QACtF,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAAA,CAChC;CACD","sourcesContent":["import type { Api, Model } from \"./types.ts\";\n\nexport interface ModelsStoreEntry {\n\tmodels: readonly Model<Api>[];\n\t/** Unix timestamp from the remote catalog's Last-Modified header. */\n\tlastModified?: number;\n\t/** Unix timestamp of the last completed remote check. */\n\tcheckedAt?: number;\n\t/**\n\t * Opaque validator from the remote catalog's ETag header, stored verbatim\n\t * (quotes included) and echoed back as If-None-Match.\n\t */\n\tetag?: string;\n}\n\nexport interface ModelsStoreOperationOptions {\n\tsignal?: AbortSignal;\n}\n\n/** Persistent model catalogs keyed by provider ID. */\nexport interface ModelsStore {\n\tread(providerId: string, options?: ModelsStoreOperationOptions): Promise<ModelsStoreEntry | undefined>;\n\twrite(providerId: string, entry: ModelsStoreEntry, options?: ModelsStoreOperationOptions): Promise<void>;\n\tdelete(providerId: string, options?: ModelsStoreOperationOptions): Promise<void>;\n}\n\nexport class InMemoryModelsStore implements ModelsStore {\n\tprivate readonly entries = new Map<string, ModelsStoreEntry>();\n\n\tasync read(providerId: string, options?: ModelsStoreOperationOptions): Promise<ModelsStoreEntry | undefined> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tconst entry = this.entries.get(providerId);\n\t\treturn entry ? structuredClone(entry) : undefined;\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry, options?: ModelsStoreOperationOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tthis.entries.set(providerId, structuredClone(entry));\n\t}\n\n\tasync delete(providerId: string, options?: ModelsStoreOperationOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tthis.entries.delete(providerId);\n\t}\n}\n"]}
1
+ {"version":3,"file":"models-store.js","sourceRoot":"","sources":["../src/models-store.ts"],"names":[],"mappings":"AA2BA,MAAM,OAAO,mBAAmB;IACd,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IAE/D,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAE,OAAqC,EAAyC;QAC5G,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3C,OAAO,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAAA,CAClD;IAED,KAAK,CAAC,KAAK,CAAC,UAAkB,EAAE,KAAuB,EAAE,OAAqC,EAAiB;QAC9G,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IAAA,CACrD;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB,EAAE,OAAqC,EAAiB;QACtF,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAAA,CAChC;CACD","sourcesContent":["import type { AnyModel } from \"./types.ts\";\n\nexport interface ModelsStoreEntry {\n\t/** Persisted models of every type. */\n\tmodels: readonly AnyModel[];\n\t/** Unix timestamp from the remote catalog's Last-Modified header. */\n\tlastModified?: number;\n\t/** Unix timestamp of the last completed remote check. */\n\tcheckedAt?: number;\n\t/**\n\t * Opaque validator from the remote catalog's ETag header, stored verbatim\n\t * (quotes included) and echoed back as If-None-Match.\n\t */\n\tetag?: string;\n}\n\nexport interface ModelsStoreOperationOptions {\n\tsignal?: AbortSignal;\n}\n\n/** Persistent model catalogs keyed by provider ID. */\nexport interface ModelsStore {\n\tread(providerId: string, options?: ModelsStoreOperationOptions): Promise<ModelsStoreEntry | undefined>;\n\twrite(providerId: string, entry: ModelsStoreEntry, options?: ModelsStoreOperationOptions): Promise<void>;\n\tdelete(providerId: string, options?: ModelsStoreOperationOptions): Promise<void>;\n}\n\nexport class InMemoryModelsStore implements ModelsStore {\n\tprivate readonly entries = new Map<string, ModelsStoreEntry>();\n\n\tasync read(providerId: string, options?: ModelsStoreOperationOptions): Promise<ModelsStoreEntry | undefined> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tconst entry = this.entries.get(providerId);\n\t\treturn entry ? structuredClone(entry) : undefined;\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry, options?: ModelsStoreOperationOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tthis.entries.set(providerId, structuredClone(entry));\n\t}\n\n\tasync delete(providerId: string, options?: ModelsStoreOperationOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted();\n\t\tthis.entries.delete(providerId);\n\t}\n}\n"]}
package/dist/models.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { type AuthResolutionOverrides } from "./auth/resolve.ts";
2
2
  import type { AuthCheck, AuthContext, AuthInteraction, AuthOperationOptions, AuthResult, AuthType, Credential, CredentialStore, ProviderAuth } from "./auth/types.ts";
3
3
  import { type ModelsStore, type ModelsStoreEntry } from "./models-store.ts";
4
- import type { Api, ApiStreamOptions, AssistantMessage, AssistantMessageEventStream, Context, DeferredCancelOptions, DeferredFetchOptions, DeferredHandle, Model, ModelThinkingLevel, ProviderHeaders, ProviderStreams, SimpleStreamOptions, TranscriptContext, Usage } from "./types.ts";
4
+ import type { AnyModel, Api, ApiStreamOptions, AssistantImages, AssistantMessage, AssistantMessageEventStream, ClassifierApi, ClassifierContext, ClassifierModel, ClassifierOptions, ClassifierResult, Context, DeferredCancelOptions, DeferredFetchOptions, DeferredHandle, ImageApi, ImageModel, ImagesContext, ImagesOptions, Model, ModelThinkingLevel, ModelType, ModelTypeMap, ProviderClassifier, ProviderHeaders, ProviderImages, ProviderStreams, SimpleStreamOptions, TranscriptContext, Usage } from "./types.ts";
5
5
  export { ModelsError, type ModelsErrorCode, REQUEST_AUTH_PREPARATION_TIMEOUT_MS, requestAuthTimeoutMessage, } from "./auth/resolve.ts";
6
+ export { assertChatModel, classifierErrorResult, getModelType, imageErrorResult, isModelType, } from "./utils/model-operations.ts";
6
7
  export interface ModelsPublication {
7
8
  /** Provider-selected persisted catalog. Omit to leave storage unchanged; null deletes it. */
8
9
  persist?: ModelsStoreEntry | null;
@@ -46,14 +47,20 @@ export type ModelsApiStreamOptions<TApi extends Api> = ApiStreamOptions<TApi> &
46
47
  export type ModelsSimpleStreamOptions = SimpleStreamOptions & ModelsRequestTransforms;
47
48
  export type ModelsDeferredFetchOptions = DeferredFetchOptions & ModelsRequestTransforms;
48
49
  export type ModelsDeferredCancelOptions = DeferredCancelOptions & ModelsRequestTransforms;
50
+ export type ModelsImagesOptions = ImagesOptions & ModelsRequestTransforms;
51
+ export type ModelsClassifierOptions = ClassifierOptions & ModelsRequestTransforms;
52
+ /** Any model a provider with chat APIs `TApi` can list. */
53
+ type ProviderModel<TApi extends Api> = Model<TApi> | ImageModel<ImageApi> | ClassifierModel<ClassifierApi>;
49
54
  /**
50
55
  * A provider is the concrete runtime unit. It owns id/name/base metadata,
51
- * auth methods, model listing, and stream behavior.
56
+ * auth methods, model listing, and the operations its models support
57
+ * (streaming, image generation, classification).
52
58
  *
53
- * `TApi` lets concrete provider factories declare which APIs their models
59
+ * `TApi` lets concrete provider factories declare which chat APIs their models
54
60
  * use (e.g. `openaiProvider(): Provider<"openai-responses" | "openai-completions">`),
55
- * giving typed model lists to direct factory users. Inside a `Models`
56
- * collection providers are held as `Provider<Api>`.
61
+ * giving typed chat model lists to direct factory users. Other model types use
62
+ * their operation-specific API unions. Inside a `Models` collection providers
63
+ * are held as `Provider<Api>`.
57
64
  */
58
65
  export interface Provider<TApi extends Api = Api> {
59
66
  readonly id: string;
@@ -69,12 +76,19 @@ export interface Provider<TApi extends Api = Api> {
69
76
  */
70
77
  readonly auth: ProviderAuth;
71
78
  /**
72
- * Current known models, sync. Static providers return their catalog;
73
- * dynamic providers return the list as of the last `refreshModels()`
74
- * (empty before the first). Must not throw; `Models` treats a throwing
79
+ * Current known chat models, sync. Static providers return their catalog;
80
+ * dynamic providers return the list as of the last `refreshModels()` (empty
81
+ * before the first). Must not throw; `Models` treats a throwing
75
82
  * implementation as having no models.
76
83
  */
77
84
  getModels(): readonly Model<TApi>[];
85
+ /**
86
+ * Current known models of every type, sync, with the same contract as
87
+ * `getModels()`. Providers with only chat models may omit it; `Models` then
88
+ * uses `getModels()`. Model ids are unique within each type; one upstream
89
+ * model may have separate entries for different operations.
90
+ */
91
+ getAllModels?(): readonly ProviderModel<TApi>[];
78
92
  /**
79
93
  * Dynamic providers only: restore `context.stored` and optionally fetch a newer list using
80
94
  * the effective credential. Implementations retain their previous list on failure, publish
@@ -84,34 +98,54 @@ export interface Provider<TApi extends Api = Api> {
84
98
  refreshModels?(context: RefreshModelsContext): Promise<void>;
85
99
  /**
86
100
  * Optional provider policy for credential-specific model availability.
87
- * `getModels()` remains the complete synchronous catalog; `Models.getAvailable()`
101
+ * `getModels()` remains the complete synchronous chat catalog; `Models.getAvailable()`
88
102
  * applies this filter after confirming that provider auth is configured.
89
103
  */
90
104
  filterModels?(models: readonly Model<TApi>[], credential: Credential | undefined): readonly Model<TApi>[];
105
+ /**
106
+ * Optional credential-specific availability policy across every model type.
107
+ * Without it, `Models.getAllAvailable()` applies `filterModels` to chat models
108
+ * and keeps every other model.
109
+ */
110
+ filterAllModels?(models: readonly ProviderModel<TApi>[], credential: Credential | undefined): readonly ProviderModel<TApi>[];
91
111
  /** Stream a normalized transcript. `Models` normalizes the caller's `Context` before dispatching here. */
92
112
  stream<T extends TApi>(model: Model<T>, context: TranscriptContext, options?: ApiStreamOptions<T>): AssistantMessageEventStream;
93
113
  streamSimple(model: Model<TApi>, context: TranscriptContext, options?: SimpleStreamOptions): AssistantMessageEventStream;
94
114
  fetchDeferred?(model: Model<TApi>, handle: DeferredHandle, options?: DeferredFetchOptions): AssistantMessageEventStream;
95
115
  cancelDeferred?(model: Model<TApi>, handle: DeferredHandle, options?: DeferredCancelOptions): Promise<void>;
116
+ /** Present when the provider supports dedicated image models. Never rejects. */
117
+ generateImages?(model: ImageModel<ImageApi>, context: ImagesContext, options?: ImagesOptions): Promise<AssistantImages>;
118
+ /** Present when the provider supports structured classifier models. Never rejects. */
119
+ classify?(model: ClassifierModel<ClassifierApi>, context: ClassifierContext, options?: ClassifierOptions): Promise<ClassifierResult>;
96
120
  }
97
121
  /**
98
- * Runtime collection of providers plus auth application and stream
99
- * convenience. Providers own stream behavior; `Models` resolves auth and
122
+ * Runtime collection of providers plus auth application and request
123
+ * convenience. Providers own request behavior; `Models` resolves auth and
100
124
  * delegates each request to the provider that owns the model.
125
+ *
126
+ * Read accessors come in three flavors: the unqualified ones (`getModels`,
127
+ * `getModel`, `getAvailable`) return chat models, the `*OfType` accessors
128
+ * return one model type, and `getAllModels`/`getAllAvailable` return every type.
101
129
  */
102
130
  export interface Models {
103
131
  getProviders(): readonly Provider[];
104
132
  getProvider(id: string): Provider | undefined;
105
133
  /**
106
- * Sync read of last-known models from one provider or all providers.
134
+ * Sync read of last-known chat models from one provider or all providers.
107
135
  * Best-effort: a provider whose `getModels()` throws yields no models.
108
136
  */
109
137
  getModels(provider?: string): readonly Model<Api>[];
110
138
  /**
111
- * Sync runtime model lookup against last-known lists. Dynamic model lists
139
+ * Sync runtime chat model lookup against last-known lists. Dynamic model lists
112
140
  * are typed as `Model<Api>`; narrow with the `hasApi()` type guard.
113
141
  */
114
142
  getModel(provider: string, id: string): Model<Api> | undefined;
143
+ /** Sync read of last-known models of one type from one provider or all providers. */
144
+ getModelsOfType<TType extends ModelType>(type: TType, provider?: string): readonly ModelTypeMap[TType][];
145
+ /** Sync runtime lookup of a model of one type against last-known lists. */
146
+ getModelOfType<TType extends ModelType>(type: TType, provider: string, id: string): ModelTypeMap[TType] | undefined;
147
+ /** Sync read of last-known models of every type from one provider or all providers. */
148
+ getAllModels(provider?: string): readonly AnyModel[];
115
149
  /**
116
150
  * Refresh selected configured dynamic providers concurrently (all when `providers` is omitted).
117
151
  * Provider errors and cancellation are returned without rejecting; static, unknown, and
@@ -120,8 +154,12 @@ export interface Models {
120
154
  refresh(options?: ModelsRefreshOptions): Promise<ModelsRefreshResult>;
121
155
  /** Check whether a provider has complete auth configuration without refreshing OAuth. */
122
156
  checkAuth(providerId: string, options?: AuthOperationOptions): Promise<AuthCheck | undefined>;
123
- /** Return models whose providers have complete auth configuration. */
157
+ /** Return chat models whose providers have complete auth configuration. */
124
158
  getAvailable(providerId?: string, options?: AuthOperationOptions): Promise<readonly Model<Api>[]>;
159
+ /** Return models of one type whose providers have complete auth configuration. */
160
+ getAvailableOfType<TType extends ModelType>(type: TType, providerId?: string, options?: AuthOperationOptions): Promise<readonly ModelTypeMap[TType][]>;
161
+ /** Return models of every type whose providers have complete auth configuration. */
162
+ getAllAvailable(providerId?: string, options?: AuthOperationOptions): Promise<readonly AnyModel[]>;
125
163
  /**
126
164
  * Resolve provider-scoped auth by provider id, or provider auth plus static
127
165
  * model headers when passed a model. Includes a source label for status UI.
@@ -132,7 +170,7 @@ export interface Models {
132
170
  * surface rejections as stream errors.
133
171
  */
134
172
  getAuth(providerId: string, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;
135
- getAuth(model: Model<Api>, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;
173
+ getAuth(model: AnyModel, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;
136
174
  /** Run a provider-owned login flow and persist its returned credential. */
137
175
  login(providerId: string, type: AuthType, interaction: AuthInteraction): Promise<Credential>;
138
176
  /** Remove the stored credential for a provider. */
@@ -143,6 +181,14 @@ export interface Models {
143
181
  completeSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): Promise<AssistantMessage>;
144
182
  fetchDeferred(model: Model<Api>, handle: DeferredHandle, options?: ModelsDeferredFetchOptions): Promise<AssistantMessage>;
145
183
  cancelDeferred(model: Model<Api>, handle: DeferredHandle, options?: ModelsDeferredCancelOptions): Promise<void>;
184
+ /**
185
+ * Generate images through the owning provider with auth resolved like
186
+ * `stream()`. Never rejects: unknown providers, unconfigured auth, and
187
+ * providers without `generateImages` return an error `AssistantImages`.
188
+ */
189
+ generateImages(model: ImageModel<ImageApi>, context: ImagesContext, options?: ModelsImagesOptions): Promise<AssistantImages>;
190
+ /** Classify structured state through the owning provider. Never rejects. */
191
+ classify(model: ClassifierModel<ClassifierApi>, context: ClassifierContext, options?: ModelsClassifierOptions): Promise<ClassifierResult>;
146
192
  }
147
193
  export interface MutableModels extends Models {
148
194
  /** Upsert/replace by provider.id. Provider ids are unique. */
@@ -164,19 +210,38 @@ export interface CreateProviderOptions<TApi extends Api = Api> {
164
210
  headers?: ProviderHeaders;
165
211
  /** Required — every provider has auth semantics, even ambient/keyless ones. */
166
212
  auth: ProviderAuth;
167
- /** Static baseline model list (empty for purely dynamic providers). */
168
- models: readonly Model<TApi>[];
169
- /** Fetch a dynamic model overlay. createProvider restores and publishes it transactionally. */
170
- fetchModels?: (context: RefreshModelsContext) => Promise<readonly Model<TApi>[]>;
213
+ /**
214
+ * Static baseline models of every type (empty for purely dynamic providers).
215
+ * Models without `type` are chat models.
216
+ */
217
+ models: readonly ProviderModel<TApi>[];
218
+ /**
219
+ * Fetch a dynamic model overlay of every type. createProvider restores and
220
+ * publishes it transactionally and drops models of unknown types.
221
+ */
222
+ fetchModels?: (context: RefreshModelsContext) => Promise<readonly ProviderModel<TApi>[]>;
223
+ /** Credential-specific chat model availability. See `Provider.filterModels`. */
171
224
  filterModels?: (models: readonly Model<TApi>[], credential: Credential | undefined) => readonly Model<TApi>[];
172
- /** Single implementation, or map keyed by `model.api` for mixed-API providers. */
173
- api: ProviderStreams | Partial<Record<TApi, ProviderStreams>>;
225
+ /** Credential-specific availability across every model type. See `Provider.filterAllModels`. */
226
+ filterAllModels?: (models: readonly ProviderModel<TApi>[], credential: Credential | undefined) => readonly ProviderModel<TApi>[];
227
+ /**
228
+ * Chat implementation: a single one for all chat models, or a map keyed by
229
+ * `model.api` for mixed-API providers. Optional when `images` or
230
+ * `classifiers` is given.
231
+ */
232
+ api?: ProviderStreams | Partial<Record<TApi, ProviderStreams>>;
233
+ /** Image-generation implementations keyed by `model.api`. */
234
+ images?: Partial<Record<ImageApi, ProviderImages>>;
235
+ /** Classifier implementations keyed by `model.api`. */
236
+ classifiers?: Partial<Record<ClassifierApi, ProviderClassifier>>;
174
237
  }
175
238
  /**
176
239
  * Builds a provider from parts. Built-in provider factories and models.json
177
- * custom providers both go through this. A single `api` streams all models;
178
- * an `api` map dispatches on `model.api`, and a model whose api has no entry
179
- * produces a stream error.
240
+ * custom providers both go through this. A single `api` streams all chat
241
+ * models; an `api` map dispatches on `model.api`, and a model whose api has
242
+ * no entry produces a stream error. One-shot operation maps dispatch on
243
+ * `model.api` the same way. At least one concrete implementation across
244
+ * `api`/`images`/`classifiers` is required; empty maps are rejected.
180
245
  */
181
246
  export declare function createProvider<TApi extends Api = Api>(input: CreateProviderOptions<TApi>): Provider<TApi>;
182
247
  /**
@@ -188,14 +253,16 @@ export declare function createProvider<TApi extends Api = Api>(input: CreateProv
188
253
  * // model: Model<"anthropic-messages">, stream options fully typed
189
254
  * }
190
255
  * ```
256
+ *
257
+ * Non-chat models never match, even when their api id equals `api`.
191
258
  */
192
- export declare function hasApi<TApi extends Api>(model: Model<Api>, api: TApi): model is Model<TApi>;
193
- export declare function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): Usage["cost"];
259
+ export declare function hasApi<TApi extends Api>(model: AnyModel, api: TApi): model is Model<TApi>;
260
+ export declare function calculateCost(model: AnyModel, usage: Usage): Usage["cost"];
194
261
  export declare function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[];
195
262
  export declare function clampThinkingLevel<TApi extends Api>(model: Model<TApi>, level: ModelThinkingLevel): ModelThinkingLevel;
196
263
  /**
197
- * Check if two models are equal by comparing both their id and provider.
264
+ * Check if two models are equal by comparing their type, id, and provider.
198
265
  * Returns false if either model is null or undefined.
199
266
  */
200
- export declare function modelsAreEqual<TApi extends Api>(a: Model<TApi> | null | undefined, b: Model<TApi> | null | undefined): boolean;
267
+ export declare function modelsAreEqual(a: AnyModel | null | undefined, b: AnyModel | null | undefined): boolean;
201
268
  //# sourceMappingURL=models.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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","sourcesContent":["import { lazyStream } from \"./api/lazy.ts\";\nimport { defaultProviderAuthContext as defaultAuthContext } from \"./auth/context.ts\";\nimport { InMemoryCredentialStore } from \"./auth/credential-store.ts\";\nimport { type AuthResolutionOverrides, ModelsError, resolveProviderAuth } from \"./auth/resolve.ts\";\nimport type {\n\tAuthCheck,\n\tAuthContext,\n\tAuthInteraction,\n\tAuthOperationOptions,\n\tAuthResult,\n\tAuthType,\n\tCredential,\n\tCredentialStore,\n\tProviderAuth,\n} from \"./auth/types.ts\";\nimport { InMemoryModelsStore, type ModelsStore, type ModelsStoreEntry } from \"./models-store.ts\";\nimport type {\n\tApi,\n\tApiStreamOptions,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tContext,\n\tDeferredCancelOptions,\n\tDeferredFetchOptions,\n\tDeferredHandle,\n\tModel,\n\tModelCostRates,\n\tModelThinkingLevel,\n\tProviderHeaders,\n\tProviderRequestOptions,\n\tProviderStreams,\n\tSimpleStreamOptions,\n\tTranscriptContext,\n\tUsage,\n} from \"./types.ts\";\nimport { operationSignal, raceWithAbortSignal } from \"./utils/abort.ts\";\nimport { normalizeContext } from \"./utils/transcript.ts\";\n\nexport {\n\tModelsError,\n\ttype ModelsErrorCode,\n\tREQUEST_AUTH_PREPARATION_TIMEOUT_MS,\n\trequestAuthTimeoutMessage,\n} from \"./auth/resolve.ts\";\n\nexport interface ModelsPublication {\n\t/** Provider-selected persisted catalog. Omit to leave storage unchanged; null deletes it. */\n\tpersist?: ModelsStoreEntry | null;\n\t/** Optional synchronous update of provider-private in-memory catalog state. */\n\tupdate?: () => void;\n}\n\nexport interface RefreshModelsContext {\n\t/** Effective configured credential. OAuth credentials are refreshed before network access. */\n\tcredential?: Credential;\n\t/** Immutable provider-scoped catalog snapshot captured before this refresh phase. */\n\tstored?: Readonly<ModelsStoreEntry>;\n\t/**\n\t * Generation-checked publication. Persistence policy remains provider-owned;\n\t * the update runs synchronously only after the selected persistence mutation.\n\t */\n\tpublish(publication: ModelsPublication): Promise<boolean>;\n\t/** False during offline/cache-only initialization. */\n\tallowNetwork: boolean;\n\t/** Bypass provider freshness checks and fetch immediately when network access is allowed. */\n\tforce?: boolean;\n\t/** Always present, including when the public refresh caller omits its optional signal. */\n\tsignal: AbortSignal;\n}\n\nexport interface ModelsRefreshOptions {\n\tallowNetwork?: boolean;\n\t/** Restrict refresh to these provider IDs. Unknown and static providers are ignored. */\n\tproviders?: readonly string[];\n\t/** Bypass provider freshness checks and fetch immediately when network access is allowed. */\n\tforce?: boolean;\n\tsignal?: AbortSignal;\n}\n\nexport interface ModelsRefreshResult {\n\taborted: boolean;\n\terrors: ReadonlyMap<string, Error>;\n}\n\nexport interface ModelsRequestTransforms {\n\t/** Transform fully assembled model/auth/request headers before provider dispatch. */\n\ttransformHeaders?: (headers: ProviderHeaders) => ProviderHeaders | Promise<ProviderHeaders>;\n}\n\nexport type ModelsApiStreamOptions<TApi extends Api> = ApiStreamOptions<TApi> & ModelsRequestTransforms;\nexport type ModelsSimpleStreamOptions = SimpleStreamOptions & ModelsRequestTransforms;\nexport type ModelsDeferredFetchOptions = DeferredFetchOptions & ModelsRequestTransforms;\nexport type ModelsDeferredCancelOptions = DeferredCancelOptions & ModelsRequestTransforms;\n\n/**\n * A provider is the concrete runtime unit. It owns id/name/base metadata,\n * auth methods, model listing, and stream behavior.\n *\n * `TApi` lets concrete provider factories declare which APIs their models\n * use (e.g. `openaiProvider(): Provider<\"openai-responses\" | \"openai-completions\">`),\n * giving typed model lists to direct factory users. Inside a `Models`\n * collection providers are held as `Provider<Api>`.\n */\nexport interface Provider<TApi extends Api = Api> {\n\treadonly id: string;\n\treadonly name: string;\n\n\treadonly baseUrl?: string;\n\treadonly headers?: ProviderHeaders;\n\n\t/**\n\t * Required: at least one of `apiKey`/`oauth`. Every provider has auth\n\t * semantics — even providers with only ambient credentials (env vars, AWS\n\t * profiles, ADC files) and keyless local servers provide `apiKey` auth\n\t * whose `resolve()` reports whether the provider is configured.\n\t * `Models.getAuth()` returns undefined when the provider is unconfigured.\n\t */\n\treadonly auth: ProviderAuth;\n\n\t/**\n\t * Current known models, sync. Static providers return their catalog;\n\t * dynamic providers return the list as of the last `refreshModels()`\n\t * (empty before the first). Must not throw; `Models` treats a throwing\n\t * implementation as having no models.\n\t */\n\tgetModels(): readonly Model<TApi>[];\n\n\t/**\n\t * Dynamic providers only: restore `context.stored` and optionally fetch a newer list using\n\t * the effective credential. Implementations retain their previous list on failure, publish\n\t * persistence and synchronous state changes through `context.publish()`, and honor the\n\t * shared abort signal for blocking work.\n\t */\n\trefreshModels?(context: RefreshModelsContext): Promise<void>;\n\n\t/**\n\t * Optional provider policy for credential-specific model availability.\n\t * `getModels()` remains the complete synchronous catalog; `Models.getAvailable()`\n\t * applies this filter after confirming that provider auth is configured.\n\t */\n\tfilterModels?(models: readonly Model<TApi>[], credential: Credential | undefined): readonly Model<TApi>[];\n\n\t/** Stream a normalized transcript. `Models` normalizes the caller's `Context` before dispatching here. */\n\tstream<T extends TApi>(\n\t\tmodel: Model<T>,\n\t\tcontext: TranscriptContext,\n\t\toptions?: ApiStreamOptions<T>,\n\t): AssistantMessageEventStream;\n\n\tstreamSimple(\n\t\tmodel: Model<TApi>,\n\t\tcontext: TranscriptContext,\n\t\toptions?: SimpleStreamOptions,\n\t): AssistantMessageEventStream;\n\tfetchDeferred?(\n\t\tmodel: Model<TApi>,\n\t\thandle: DeferredHandle,\n\t\toptions?: DeferredFetchOptions,\n\t): AssistantMessageEventStream;\n\tcancelDeferred?(model: Model<TApi>, handle: DeferredHandle, options?: DeferredCancelOptions): Promise<void>;\n}\n\n/**\n * Runtime collection of providers plus auth application and stream\n * convenience. Providers own stream behavior; `Models` resolves auth and\n * delegates each request to the provider that owns the model.\n */\nexport interface Models {\n\tgetProviders(): readonly Provider[];\n\tgetProvider(id: string): Provider | undefined;\n\n\t/**\n\t * Sync read of last-known models from one provider or all providers.\n\t * Best-effort: a provider whose `getModels()` throws yields no models.\n\t */\n\tgetModels(provider?: string): readonly Model<Api>[];\n\n\t/**\n\t * Sync runtime model lookup against last-known lists. Dynamic model lists\n\t * are typed as `Model<Api>`; narrow with the `hasApi()` type guard.\n\t */\n\tgetModel(provider: string, id: string): Model<Api> | undefined;\n\n\t/**\n\t * Refresh selected configured dynamic providers concurrently (all when `providers` is omitted).\n\t * Provider errors and cancellation are returned without rejecting; static, unknown, and\n\t * unconfigured providers are skipped.\n\t */\n\trefresh(options?: ModelsRefreshOptions): Promise<ModelsRefreshResult>;\n\n\t/** Check whether a provider has complete auth configuration without refreshing OAuth. */\n\tcheckAuth(providerId: string, options?: AuthOperationOptions): Promise<AuthCheck | undefined>;\n\n\t/** Return models whose providers have complete auth configuration. */\n\tgetAvailable(providerId?: string, options?: AuthOperationOptions): Promise<readonly Model<Api>[]>;\n\n\t/**\n\t * Resolve provider-scoped auth by provider id, or provider auth plus static\n\t * model headers when passed a model. Includes a source label for status UI.\n\t * Resolves `undefined` when the provider is unknown or unconfigured.\n\t * Rejects with `ModelsError`: code \"oauth\" when a token refresh fails (the\n\t * stored credential is preserved for retry; re-login fixes it), code \"auth\"\n\t * when api-key resolution or the credential store fails. Request paths\n\t * surface rejections as stream errors.\n\t */\n\tgetAuth(providerId: string, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;\n\tgetAuth(model: Model<Api>, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;\n\n\t/** Run a provider-owned login flow and persist its returned credential. */\n\tlogin(providerId: string, type: AuthType, interaction: AuthInteraction): Promise<Credential>;\n\n\t/** Remove the stored credential for a provider. */\n\tlogout(providerId: string, options?: AuthOperationOptions): Promise<void>;\n\n\tstream<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): AssistantMessageEventStream;\n\n\tcomplete<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): Promise<AssistantMessage>;\n\n\tstreamSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): AssistantMessageEventStream;\n\tcompleteSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): Promise<AssistantMessage>;\n\tfetchDeferred(\n\t\tmodel: Model<Api>,\n\t\thandle: DeferredHandle,\n\t\toptions?: ModelsDeferredFetchOptions,\n\t): Promise<AssistantMessage>;\n\tcancelDeferred(model: Model<Api>, handle: DeferredHandle, options?: ModelsDeferredCancelOptions): Promise<void>;\n}\n\nexport interface MutableModels extends Models {\n\t/** Upsert/replace by provider.id. Provider ids are unique. */\n\tsetProvider(provider: Provider): void;\n\tdeleteProvider(id: string): void;\n\tclearProviders(): void;\n}\n\nexport interface CreateModelsOptions {\n\tcredentials?: CredentialStore;\n\tmodelsStore?: ModelsStore;\n\tauthContext?: AuthContext;\n}\n\nfunction mergeHeaders(\n\tbase: ProviderHeaders | undefined,\n\toverride: ProviderHeaders | undefined,\n): ProviderHeaders | undefined {\n\tif (!base && !override) return undefined;\n\tconst merged = { ...base };\n\tfor (const [name, value] of Object.entries(override ?? {})) {\n\t\tconst lowerName = name.toLowerCase();\n\t\tfor (const existingName of Object.keys(merged)) {\n\t\t\tif (existingName.toLowerCase() === lowerName) delete merged[existingName];\n\t\t}\n\t\tmerged[name] = value;\n\t}\n\treturn merged;\n}\n\nclass ModelsImpl implements MutableModels {\n\tprivate providers = new Map<string, Provider>();\n\tprivate credentials: CredentialStore;\n\tprivate modelsStore: ModelsStore;\n\tprivate authContext: AuthContext;\n\tprivate refreshGenerations = new Map<string, number>();\n\tprivate refreshControllers = new Map<string, AbortController>();\n\tprivate publicationChains = new Map<string, Promise<unknown>>();\n\n\tconstructor(options?: CreateModelsOptions) {\n\t\tthis.credentials = options?.credentials ?? new InMemoryCredentialStore();\n\t\tthis.modelsStore = options?.modelsStore ?? new InMemoryModelsStore();\n\t\tthis.authContext = options?.authContext ?? defaultAuthContext();\n\t}\n\n\tsetProvider(provider: Provider): void {\n\t\tthis.supersedeProviderRefresh(provider.id);\n\t\tthis.providers.set(provider.id, provider);\n\t}\n\n\tdeleteProvider(id: string): void {\n\t\tthis.supersedeProviderRefresh(id);\n\t\tthis.providers.delete(id);\n\t}\n\n\tclearProviders(): void {\n\t\tfor (const id of new Set([...this.providers.keys(), ...this.refreshControllers.keys()])) {\n\t\t\tthis.supersedeProviderRefresh(id);\n\t\t}\n\t\tthis.providers.clear();\n\t}\n\n\tgetProviders(): readonly Provider[] {\n\t\treturn Array.from(this.providers.values());\n\t}\n\n\tgetProvider(id: string): Provider | undefined {\n\t\treturn this.providers.get(id);\n\t}\n\n\tgetModels(provider?: string): readonly Model<Api>[] {\n\t\tif (provider !== undefined) {\n\t\t\tconst entry = this.providers.get(provider);\n\t\t\tif (!entry) return [];\n\t\t\ttry {\n\t\t\t\treturn entry.getModels();\n\t\t\t} catch {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}\n\n\t\tconst models: Model<Api>[] = [];\n\t\tfor (const entry of this.providers.values()) {\n\t\t\ttry {\n\t\t\t\tmodels.push(...entry.getModels());\n\t\t\t} catch {\n\t\t\t\t// Best-effort: ill-behaved providers yield no models.\n\t\t\t}\n\t\t}\n\t\treturn models;\n\t}\n\n\tgetModel(provider: string, id: string): Model<Api> | undefined {\n\t\treturn this.getModels(provider).find((model) => model.id === id);\n\t}\n\n\tprivate supersedeProviderRefresh(providerId: string): number {\n\t\tconst generation = (this.refreshGenerations.get(providerId) ?? 0) + 1;\n\t\tthis.refreshGenerations.set(providerId, generation);\n\t\tconst previous = this.refreshControllers.get(providerId);\n\t\tif (previous) {\n\t\t\tthis.refreshControllers.delete(providerId);\n\t\t\tprevious.abort();\n\t\t}\n\t\treturn generation;\n\t}\n\n\tprivate beginProviderRefresh(providerId: string): { generation: number; controller: AbortController } {\n\t\tconst generation = this.supersedeProviderRefresh(providerId);\n\t\tconst controller = new AbortController();\n\t\tthis.refreshControllers.set(providerId, controller);\n\t\treturn { generation, controller };\n\t}\n\n\tprivate publishProviderModels(\n\t\tproviderId: string,\n\t\tgeneration: number,\n\t\tsignal: AbortSignal,\n\t\tpublication: ModelsPublication,\n\t): Promise<boolean> {\n\t\tconst previous = this.publicationChains.get(providerId) ?? Promise.resolve();\n\t\tconst queued = (async () => {\n\t\t\tawait previous.catch(() => {});\n\t\t\tif (signal.aborted || this.refreshGenerations.get(providerId) !== generation) return false;\n\n\t\t\tif (publication.persist === null) {\n\t\t\t\tawait this.modelsStore.delete(providerId, { signal });\n\t\t\t} else if (publication.persist !== undefined) {\n\t\t\t\tawait this.modelsStore.write(providerId, structuredClone(publication.persist), { signal });\n\t\t\t}\n\n\t\t\tif (signal.aborted || this.refreshGenerations.get(providerId) !== generation) return false;\n\t\t\tpublication.update?.();\n\t\t\treturn true;\n\t\t})();\n\t\tconst tail = queued.catch(() => {});\n\t\tthis.publicationChains.set(providerId, tail);\n\t\tvoid tail.then(() => {\n\t\t\tif (this.publicationChains.get(providerId) === tail) this.publicationChains.delete(providerId);\n\t\t});\n\t\treturn raceWithAbortSignal(queued, signal);\n\t}\n\n\tprivate async runProviderRefreshPhase(\n\t\tprovider: Provider & Required<Pick<Provider, \"refreshModels\">>,\n\t\tcredential: Credential | undefined,\n\t\tallowNetwork: boolean,\n\t\tforce: boolean | undefined,\n\t\tgeneration: number,\n\t\tsignal: AbortSignal,\n\t): Promise<void> {\n\t\tconst stored = await this.modelsStore.read(provider.id, { signal });\n\t\tawait provider.refreshModels({\n\t\t\tcredential,\n\t\t\tstored: stored ? structuredClone(stored) : undefined,\n\t\t\tpublish: (publication) => this.publishProviderModels(provider.id, generation, signal, publication),\n\t\t\tallowNetwork,\n\t\t\tforce: allowNetwork ? force : undefined,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync refresh(options: ModelsRefreshOptions = {}): Promise<ModelsRefreshResult> {\n\t\tconst allowNetwork = options.allowNetwork ?? true;\n\t\tconst callerSignal = operationSignal(options.signal);\n\t\tconst errors = new Map<string, Error>();\n\t\tif (callerSignal.aborted) return { aborted: true, errors };\n\t\tconst selected = options.providers ? new Set(options.providers) : undefined;\n\t\tconst refreshable = Array.from(this.providers.values()).filter(\n\t\t\t(provider): provider is Provider & Required<Pick<Provider, \"refreshModels\">> =>\n\t\t\t\tprovider.refreshModels !== undefined && (!selected || selected.has(provider.id)),\n\t\t);\n\n\t\tconst refresh = Promise.all(\n\t\t\trefreshable.map(async (provider) => {\n\t\t\t\tconst { generation, controller } = this.beginProviderRefresh(provider.id);\n\t\t\t\tconst signal = AbortSignal.any([callerSignal, controller.signal]);\n\t\t\t\tconst operation = (async () => {\n\t\t\t\t\tlet storedCredential: Credential | undefined;\n\t\t\t\t\tlet credentialError: unknown;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tstoredCredential = await this.readCredential(provider.id, signal);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tcredentialError = error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Restore cached provider state before auth resolution or network access.\n\t\t\t\t\tawait this.runProviderRefreshPhase(provider, storedCredential, false, undefined, generation, signal);\n\t\t\t\t\tif (credentialError !== undefined) throw credentialError;\n\t\t\t\t\tif (!allowNetwork || signal.aborted) return;\n\n\t\t\t\t\tconst credential = await this.resolveRefreshCredential(provider, storedCredential, signal);\n\t\t\t\t\tif (!credential) return;\n\t\t\t\t\tawait this.runProviderRefreshPhase(provider, credential, true, options.force, generation, signal);\n\t\t\t\t})();\n\n\t\t\t\ttry {\n\t\t\t\t\tawait raceWithAbortSignal(operation, signal);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!signal.aborted) {\n\t\t\t\t\t\terrors.set(\n\t\t\t\t\t\t\tprovider.id,\n\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t? error\n\t\t\t\t\t\t\t\t: new ModelsError(\"model_source\", `Model refresh failed for ${provider.id}`, { cause: error }),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tif (this.refreshControllers.get(provider.id) === controller) {\n\t\t\t\t\t\tthis.refreshControllers.delete(provider.id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\ttry {\n\t\t\tawait raceWithAbortSignal(refresh, callerSignal);\n\t\t} catch (error) {\n\t\t\tif (!callerSignal.aborted) throw error;\n\t\t}\n\n\t\treturn { aborted: callerSignal.aborted, errors: new Map(errors) };\n\t}\n\n\tprivate async resolveRefreshCredential(\n\t\tprovider: Provider,\n\t\tstored: Credential | undefined,\n\t\tsignal: AbortSignal,\n\t): Promise<Credential | undefined> {\n\t\tif (stored?.type === \"oauth\") {\n\t\t\tconst oauth = provider.auth.oauth;\n\t\t\tif (!oauth) return undefined;\n\t\t\tif (Date.now() < stored.expires) return stored;\n\t\t\tif (signal.aborted) return undefined;\n\t\t\tconst post = await this.credentials.modify(\n\t\t\t\tprovider.id,\n\t\t\t\tasync (current) => {\n\t\t\t\t\tif (current?.type !== \"oauth\" || Date.now() < current.expires) return undefined;\n\t\t\t\t\treturn oauth.refresh(current, signal);\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t\treturn post?.type === \"oauth\" ? post : undefined;\n\t\t}\n\n\t\tconst apiKey = provider.auth.apiKey;\n\t\tif (!apiKey) return undefined;\n\t\tconst credential = stored?.type === \"api_key\" ? stored : undefined;\n\t\tconst result = await apiKey.resolve({ ctx: this.authContext, credential, signal });\n\t\tif (!result) return undefined;\n\t\treturn { type: \"api_key\", key: result.auth.apiKey, env: result.env };\n\t}\n\n\tprivate async readCredential(providerId: string, signal: AbortSignal): Promise<Credential | undefined> {\n\t\ttry {\n\t\t\treturn await this.credentials.read(providerId, { signal });\n\t\t} catch (error) {\n\t\t\tthrow new ModelsError(\"auth\", `Credential store read failed for ${providerId}`, { cause: error });\n\t\t}\n\t}\n\n\tprivate async checkProviderAuth(\n\t\tprovider: Provider,\n\t\tcredential: Credential | undefined,\n\t\tsignal: AbortSignal,\n\t): Promise<AuthCheck | undefined> {\n\t\tif (credential?.type === \"oauth\") {\n\t\t\treturn provider.auth.oauth ? { source: \"OAuth\", type: \"oauth\" } : undefined;\n\t\t}\n\t\tconst apiKey = provider.auth.apiKey;\n\t\tif (!apiKey) return undefined;\n\t\tif (apiKey.check) {\n\t\t\ttry {\n\t\t\t\treturn await apiKey.check({\n\t\t\t\t\tctx: this.authContext,\n\t\t\t\t\tcredential: credential?.type === \"api_key\" ? credential : undefined,\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthrow new ModelsError(\"auth\", `API key auth check failed for provider ${provider.id}`, { cause: error });\n\t\t\t}\n\t\t}\n\n\t\tconst resolution = await resolveProviderAuth(provider, this.credentials, this.authContext, { signal });\n\t\treturn resolution ? { source: resolution.source, type: \"api_key\" } : undefined;\n\t}\n\n\tcheckAuth(providerId: string, options?: AuthOperationOptions): Promise<AuthCheck | undefined> {\n\t\tconst signal = operationSignal(options?.signal);\n\t\tconst check = (async () => {\n\t\t\tsignal.throwIfAborted();\n\t\t\tconst provider = this.providers.get(providerId);\n\t\t\tif (!provider) return undefined;\n\t\t\treturn this.checkProviderAuth(provider, await this.readCredential(providerId, signal), signal);\n\t\t})();\n\t\treturn raceWithAbortSignal(check, signal);\n\t}\n\n\tgetAvailable(providerId?: string, options?: AuthOperationOptions): Promise<readonly Model<Api>[]> {\n\t\tconst signal = operationSignal(options?.signal);\n\t\tconst available = (async () => {\n\t\t\tsignal.throwIfAborted();\n\t\t\tconst providers = providerId\n\t\t\t\t? [this.providers.get(providerId)].filter((entry) => entry !== undefined)\n\t\t\t\t: this.getProviders();\n\t\t\tconst checks = await Promise.all(\n\t\t\t\tproviders.map(async (provider) => {\n\t\t\t\t\tconst credential = await this.readCredential(provider.id, signal);\n\t\t\t\t\treturn { provider, credential, auth: await this.checkProviderAuth(provider, credential, signal) };\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn checks.flatMap(({ provider, credential, auth }) => {\n\t\t\t\tif (!auth) return [];\n\t\t\t\tconst models = provider.getModels();\n\t\t\t\treturn provider.filterModels?.(models, credential) ?? models;\n\t\t\t});\n\t\t})();\n\t\treturn raceWithAbortSignal(available, signal);\n\t}\n\n\tgetAuth(providerId: string, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;\n\tgetAuth(model: Model<Api>, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;\n\tasync getAuth(\n\t\tproviderOrModel: string | Model<Api>,\n\t\toverrides?: AuthResolutionOverrides,\n\t): Promise<AuthResult | undefined> {\n\t\tconst signal = operationSignal(overrides?.signal);\n\t\tconst providerId = typeof providerOrModel === \"string\" ? providerOrModel : providerOrModel.provider;\n\t\tconst provider = this.providers.get(providerId);\n\t\tif (!provider) return undefined;\n\t\tconst result = await resolveProviderAuth(provider, this.credentials, this.authContext, { ...overrides, signal });\n\t\tif (!result || typeof providerOrModel === \"string\" || !providerOrModel.headers) return result;\n\t\treturn {\n\t\t\t...result,\n\t\t\tauth: {\n\t\t\t\t...result.auth,\n\t\t\t\theaders: mergeHeaders(result.auth.headers, providerOrModel.headers),\n\t\t\t},\n\t\t};\n\t}\n\n\tasync login(providerId: string, type: AuthType, interaction: AuthInteraction): Promise<Credential> {\n\t\tconst signal = operationSignal(interaction.signal);\n\t\tsignal.throwIfAborted();\n\t\tconst provider = this.providers.get(providerId);\n\t\tif (!provider) throw new ModelsError(\"provider\", `Unknown provider: ${providerId}`);\n\t\tconst method = type === \"oauth\" ? provider.auth.oauth : provider.auth.apiKey;\n\t\tif (!method?.login) {\n\t\t\tthrow new ModelsError(\"auth\", `${provider.name} does not support ${type} login`);\n\t\t}\n\t\tconst loginOperation: Promise<Credential> = method.login({ ...interaction, signal });\n\t\tconst credential = await raceWithAbortSignal(loginOperation, signal);\n\t\tlet mutationStarted = false;\n\t\tlet markMutationStarted: (() => void) | undefined;\n\t\tconst started = new Promise<void>((resolve) => {\n\t\t\tmarkMutationStarted = resolve;\n\t\t});\n\t\tconst mutation = this.credentials.modify(\n\t\t\tproviderId,\n\t\t\tasync () => {\n\t\t\t\tmutationStarted = true;\n\t\t\t\tmarkMutationStarted?.();\n\t\t\t\treturn credential;\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tvoid mutation.catch(() => {});\n\t\ttry {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tif (!mutationStarted) reject(signal.reason);\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tvoid Promise.race([started, mutation]).then(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t},\n\t\t\t\t\t(error: unknown) => {\n\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(error);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t});\n\t\t\tawait mutation;\n\t\t} catch (error) {\n\t\t\tsignal.throwIfAborted();\n\t\t\tthrow new ModelsError(\"auth\", `Credential store modify failed for ${providerId}`, { cause: error });\n\t\t}\n\t\treturn credential;\n\t}\n\n\tasync logout(providerId: string, options?: AuthOperationOptions): Promise<void> {\n\t\tconst signal = operationSignal(options?.signal);\n\t\tsignal.throwIfAborted();\n\t\ttry {\n\t\t\tawait this.credentials.delete(providerId, { signal });\n\t\t} catch (error) {\n\t\t\tsignal.throwIfAborted();\n\t\t\tthrow new ModelsError(\"auth\", `Credential store delete failed for ${providerId}`, { cause: error });\n\t\t}\n\t}\n\n\tprivate requireProvider(model: Model<Api>): Provider {\n\t\tconst provider = this.providers.get(model.provider);\n\t\tif (!provider) {\n\t\t\tthrow new ModelsError(\"provider\", `Unknown provider: ${model.provider}`);\n\t\t}\n\t\treturn provider;\n\t}\n\n\tprivate async applyAuth<TOptions extends ProviderRequestOptions & ModelsRequestTransforms>(\n\t\tmodel: Model<Api>,\n\t\toptions: TOptions | undefined,\n\t): Promise<{\n\t\trequestModel: Model<Api>;\n\t\trequestOptions: Omit<TOptions, \"transformHeaders\"> & ProviderRequestOptions;\n\t}> {\n\t\tthis.requireProvider(model);\n\t\tconst resolution = await this.getAuth(model, {\n\t\t\tapiKey: options?.apiKey,\n\t\t\tenv: options?.env,\n\t\t\tsignal: options?.signal,\n\t\t});\n\t\tif (!resolution) {\n\t\t\tthrow new ModelsError(\"auth\", `Provider is not configured: ${model.provider}`);\n\t\t}\n\t\tconst auth = resolution.auth;\n\n\t\t// Explicit request options win per-field; the Models-only transform runs last.\n\t\tconst apiKey = options?.apiKey ?? auth.apiKey;\n\t\tlet headers = mergeHeaders(auth.headers, options?.headers);\n\t\tif (options?.transformHeaders) headers = await options.transformHeaders(headers ?? {});\n\t\tconst env = resolution.env || options?.env ? { ...(resolution.env ?? {}), ...(options?.env ?? {}) } : undefined;\n\t\tconst requestModel = auth.baseUrl ? { ...model, baseUrl: auth.baseUrl } : model;\n\t\tconst { transformHeaders: _transformHeaders, ...providerOptions } = options ?? {};\n\t\tconst requestOptions = { ...providerOptions, apiKey, headers, env } as Omit<TOptions, \"transformHeaders\"> &\n\t\t\tProviderRequestOptions;\n\n\t\treturn { requestModel, requestOptions };\n\t}\n\n\tstream<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): AssistantMessageEventStream {\n\t\tconst transcript = normalizeContext(context);\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst provider = this.requireProvider(model);\n\t\t\tconst { requestModel, requestOptions } = await this.applyAuth(\n\t\t\t\tmodel,\n\t\t\t\toptions as ModelsApiStreamOptions<Api> | undefined,\n\t\t\t);\n\t\t\treturn provider.stream(requestModel as Model<TApi>, transcript, requestOptions as ApiStreamOptions<TApi>);\n\t\t});\n\t}\n\n\tasync complete<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): Promise<AssistantMessage> {\n\t\treturn this.stream(model, context, options).result();\n\t}\n\n\tstreamSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): AssistantMessageEventStream {\n\t\tconst transcript = normalizeContext(context);\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst provider = this.requireProvider(model);\n\t\t\tconst { requestModel, requestOptions } = await this.applyAuth(model, options);\n\t\t\treturn provider.streamSimple(requestModel, transcript, requestOptions as SimpleStreamOptions);\n\t\t});\n\t}\n\n\tasync completeSimple(\n\t\tmodel: Model<Api>,\n\t\tcontext: Context,\n\t\toptions?: ModelsSimpleStreamOptions,\n\t): Promise<AssistantMessage> {\n\t\treturn this.streamSimple(model, context, options).result();\n\t}\n\n\tasync fetchDeferred(\n\t\tmodel: Model<Api>,\n\t\thandle: DeferredHandle,\n\t\toptions?: ModelsDeferredFetchOptions,\n\t): Promise<AssistantMessage> {\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst provider = this.requireProvider(model);\n\t\t\tif (!provider.fetchDeferred) {\n\t\t\t\tthrow new ModelsError(\"provider\", `Provider ${model.provider} does not support deferred responses`);\n\t\t\t}\n\t\t\tconst { requestModel, requestOptions } = await this.applyAuth(model, options);\n\t\t\treturn provider.fetchDeferred(requestModel, handle, requestOptions as DeferredFetchOptions);\n\t\t}).result();\n\t}\n\n\tasync cancelDeferred(\n\t\tmodel: Model<Api>,\n\t\thandle: DeferredHandle,\n\t\toptions?: ModelsDeferredCancelOptions,\n\t): Promise<void> {\n\t\tconst provider = this.requireProvider(model);\n\t\tif (!provider.cancelDeferred) {\n\t\t\tthrow new ModelsError(\"provider\", `Provider ${model.provider} does not support deferred responses`);\n\t\t}\n\t\tconst { requestModel, requestOptions } = await this.applyAuth(model, options);\n\t\tawait provider.cancelDeferred(requestModel, handle, requestOptions);\n\t}\n}\n\nexport function createModels(options?: CreateModelsOptions): MutableModels {\n\treturn new ModelsImpl(options);\n}\n\nexport interface CreateProviderOptions<TApi extends Api = Api> {\n\tid: string;\n\t/** Display name. Default: `id`. */\n\tname?: string;\n\tbaseUrl?: string;\n\theaders?: ProviderHeaders;\n\t/** Required — every provider has auth semantics, even ambient/keyless ones. */\n\tauth: ProviderAuth;\n\t/** Static baseline model list (empty for purely dynamic providers). */\n\tmodels: readonly Model<TApi>[];\n\t/** Fetch a dynamic model overlay. createProvider restores and publishes it transactionally. */\n\tfetchModels?: (context: RefreshModelsContext) => Promise<readonly Model<TApi>[]>;\n\tfilterModels?: (models: readonly Model<TApi>[], credential: Credential | undefined) => readonly Model<TApi>[];\n\t/** Single implementation, or map keyed by `model.api` for mixed-API providers. */\n\tapi: ProviderStreams | Partial<Record<TApi, ProviderStreams>>;\n}\n\n/**\n * Builds a provider from parts. Built-in provider factories and models.json\n * custom providers both go through this. A single `api` streams all models;\n * an `api` map dispatches on `model.api`, and a model whose api has no entry\n * produces a stream error.\n */\nexport function createProvider<TApi extends Api = Api>(input: CreateProviderOptions<TApi>): Provider<TApi> {\n\tconst baselineModels = input.models;\n\tlet dynamicModels: readonly Model<TApi>[] = [];\n\tconst fetchModels = input.fetchModels;\n\tconst currentModels = (): readonly Model<TApi>[] => {\n\t\tconst merged = [...baselineModels];\n\t\tfor (const model of dynamicModels) {\n\t\t\tconst index = merged.findIndex((entry) => entry.id === model.id);\n\t\t\tif (index >= 0) merged[index] = model;\n\t\t\telse merged.push(model);\n\t\t}\n\t\treturn merged;\n\t};\n\tconst single =\n\t\ttypeof (input.api as ProviderStreams).stream === \"function\" ? (input.api as ProviderStreams) : undefined;\n\tconst byApi = single ? undefined : (input.api as Partial<Record<string, ProviderStreams>>);\n\n\tconst apiFor = (model: Model<Api>): ProviderStreams | undefined => single ?? byApi?.[model.api];\n\n\tconst dispatch = (\n\t\tmodel: Model<Api>,\n\t\trun: (streams: ProviderStreams) => AssistantMessageEventStream,\n\t): AssistantMessageEventStream => {\n\t\tconst streams = apiFor(model);\n\t\tif (!streams) {\n\t\t\treturn lazyStream(model, async () => {\n\t\t\t\tthrow new ModelsError(\"stream\", `Provider ${input.id} has no API implementation for \"${model.api}\"`);\n\t\t\t});\n\t\t}\n\t\treturn run(streams);\n\t};\n\n\tconst provider: Provider<TApi> = {\n\t\tid: input.id,\n\t\tname: input.name ?? input.id,\n\t\tbaseUrl: input.baseUrl,\n\t\theaders: input.headers,\n\t\tauth: input.auth,\n\t\tgetModels: currentModels,\n\t\trefreshModels: fetchModels\n\t\t\t? async (context) => {\n\t\t\t\t\tif (context.stored) {\n\t\t\t\t\t\tconst restored = context.stored.models\n\t\t\t\t\t\t\t.filter((model) => model.provider === input.id)\n\t\t\t\t\t\t\t.map((model) => model as Model<TApi>);\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!(await context.publish({\n\t\t\t\t\t\t\t\tupdate: () => {\n\t\t\t\t\t\t\t\t\tdynamicModels = restored;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!context.allowNetwork || context.signal.aborted) return;\n\t\t\t\t\tconst refreshed = await fetchModels(context);\n\t\t\t\t\tif (context.signal.aborted) return;\n\t\t\t\t\tawait context.publish({\n\t\t\t\t\t\tpersist: { models: refreshed, checkedAt: Date.now() },\n\t\t\t\t\t\tupdate: () => {\n\t\t\t\t\t\t\tdynamicModels = refreshed;\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfilterModels: input.filterModels,\n\t\tstream: (model, context, options) => dispatch(model, (streams) => streams.stream(model, context, options)),\n\t\tstreamSimple: (model, context, options) =>\n\t\t\tdispatch(model, (streams) => streams.streamSimple(model, context, options)),\n\t};\n\n\tconst streams = single ? [single] : Object.values(byApi ?? {}).filter((entry) => entry !== undefined);\n\tif (streams.some((entry) => entry.fetchDeferred !== undefined)) {\n\t\tprovider.fetchDeferred = (model, handle, options) =>\n\t\t\tlazyStream(model, async () => {\n\t\t\t\tconst implementation = apiFor(model);\n\t\t\t\tif (!implementation?.fetchDeferred) {\n\t\t\t\t\tthrow new ModelsError(\n\t\t\t\t\t\t\"provider\",\n\t\t\t\t\t\t`Provider ${input.id} does not support deferred responses for \"${model.api}\"`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn implementation.fetchDeferred(model, handle, options);\n\t\t\t});\n\t}\n\tif (streams.some((entry) => entry.cancelDeferred !== undefined)) {\n\t\tprovider.cancelDeferred = async (model, handle, options) => {\n\t\t\tconst implementation = apiFor(model);\n\t\t\tif (!implementation?.cancelDeferred) {\n\t\t\t\tthrow new ModelsError(\n\t\t\t\t\t\"provider\",\n\t\t\t\t\t`Provider ${input.id} cannot cancel deferred responses for \"${model.api}\"`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait implementation.cancelDeferred(model, handle, options);\n\t\t};\n\t}\n\n\treturn provider;\n}\n\n/**\n * Runtime-checked narrowing for dynamically looked-up models:\n *\n * ```ts\n * const model = models.getModel(\"anthropic\", \"claude-opus-4-7\");\n * if (model && hasApi(model, \"anthropic-messages\")) {\n * // model: Model<\"anthropic-messages\">, stream options fully typed\n * }\n * ```\n */\nexport function hasApi<TApi extends Api>(model: Model<Api>, api: TApi): model is Model<TApi> {\n\treturn model.api === api;\n}\n\nexport function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): Usage[\"cost\"] {\n\tconst inputTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\tlet rates: ModelCostRates = model.cost;\n\tlet matchedThreshold = -1;\n\tfor (const tier of model.cost.tiers ?? []) {\n\t\tif (inputTokens > tier.inputTokensAbove && tier.inputTokensAbove > matchedThreshold) {\n\t\t\trates = tier;\n\t\t\tmatchedThreshold = tier.inputTokensAbove;\n\t\t}\n\t}\n\n\t// Anthropic charges 2x base input for 1h cache writes.\n\tconst longWrite = usage.cacheWrite1h ?? 0;\n\tconst shortWrite = usage.cacheWrite - longWrite;\n\tusage.cost.input = (rates.input / 1000000) * usage.input;\n\tusage.cost.output = (rates.output / 1000000) * usage.output;\n\tusage.cost.cacheRead = (rates.cacheRead / 1000000) * usage.cacheRead;\n\tusage.cost.cacheWrite = (rates.cacheWrite * shortWrite + rates.input * 2 * longWrite) / 1000000;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n\treturn usage.cost;\n}\n\nconst EXTENDED_THINKING_LEVELS: ModelThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n\nexport function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[] {\n\tif (!model.reasoning) return [\"off\"];\n\n\treturn EXTENDED_THINKING_LEVELS.filter((level) => {\n\t\tconst mapped = model.thinkingLevelMap?.[level];\n\t\tif (mapped === null) return false;\n\t\tif (level === \"xhigh\" || level === \"max\") return mapped !== undefined;\n\t\treturn true;\n\t});\n}\n\nexport function clampThinkingLevel<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tlevel: ModelThinkingLevel,\n): ModelThinkingLevel {\n\tconst availableLevels = getSupportedThinkingLevels(model);\n\tif (availableLevels.includes(level)) return level;\n\n\tconst requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);\n\tif (requestedIndex === -1) return availableLevels[0] ?? \"off\";\n\n\tfor (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\tfor (let i = requestedIndex - 1; i >= 0; i--) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\treturn availableLevels[0] ?? \"off\";\n}\n\n/**\n * Check if two models are equal by comparing both their id and provider.\n * Returns false if either model is null or undefined.\n */\nexport function modelsAreEqual<TApi extends Api>(\n\ta: Model<TApi> | null | undefined,\n\tb: Model<TApi> | null | undefined,\n): boolean {\n\tif (!a || !b) return false;\n\treturn a.id === b.id && a.provider === b.provider;\n}\n"]}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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","sourcesContent":["import { lazyStream } from \"./api/lazy.ts\";\nimport { defaultProviderAuthContext as defaultAuthContext } from \"./auth/context.ts\";\nimport { InMemoryCredentialStore } from \"./auth/credential-store.ts\";\nimport { type AuthResolutionOverrides, ModelsError, resolveProviderAuth } from \"./auth/resolve.ts\";\nimport type {\n\tAuthCheck,\n\tAuthContext,\n\tAuthInteraction,\n\tAuthOperationOptions,\n\tAuthResult,\n\tAuthType,\n\tCredential,\n\tCredentialStore,\n\tProviderAuth,\n} from \"./auth/types.ts\";\nimport { InMemoryModelsStore, type ModelsStore, type ModelsStoreEntry } from \"./models-store.ts\";\nimport type {\n\tAnyModel,\n\tApi,\n\tApiStreamOptions,\n\tAssistantImages,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tClassifierApi,\n\tClassifierContext,\n\tClassifierModel,\n\tClassifierOptions,\n\tClassifierResult,\n\tContext,\n\tDeferredCancelOptions,\n\tDeferredFetchOptions,\n\tDeferredHandle,\n\tImageApi,\n\tImageModel,\n\tImagesContext,\n\tImagesOptions,\n\tModel,\n\tModelCostRates,\n\tModelThinkingLevel,\n\tModelType,\n\tModelTypeMap,\n\tProviderClassifier,\n\tProviderHeaders,\n\tProviderImages,\n\tProviderRequestOptions,\n\tProviderStreams,\n\tSimpleStreamOptions,\n\tTranscriptContext,\n\tUsage,\n} from \"./types.ts\";\nimport { operationSignal, raceWithAbortSignal } from \"./utils/abort.ts\";\nimport {\n\tassertChatModel,\n\tassertClassifierModel,\n\tassertImageModel,\n\tclassifierErrorResult,\n\tgetModelType,\n\timageErrorResult,\n\tisModelType,\n} from \"./utils/model-operations.ts\";\nimport { normalizeContext } from \"./utils/transcript.ts\";\n\nexport {\n\tModelsError,\n\ttype ModelsErrorCode,\n\tREQUEST_AUTH_PREPARATION_TIMEOUT_MS,\n\trequestAuthTimeoutMessage,\n} from \"./auth/resolve.ts\";\nexport {\n\tassertChatModel,\n\tclassifierErrorResult,\n\tgetModelType,\n\timageErrorResult,\n\tisModelType,\n} from \"./utils/model-operations.ts\";\n\nexport interface ModelsPublication {\n\t/** Provider-selected persisted catalog. Omit to leave storage unchanged; null deletes it. */\n\tpersist?: ModelsStoreEntry | null;\n\t/** Optional synchronous update of provider-private in-memory catalog state. */\n\tupdate?: () => void;\n}\n\nexport interface RefreshModelsContext {\n\t/** Effective configured credential. OAuth credentials are refreshed before network access. */\n\tcredential?: Credential;\n\t/** Immutable provider-scoped catalog snapshot captured before this refresh phase. */\n\tstored?: Readonly<ModelsStoreEntry>;\n\t/**\n\t * Generation-checked publication. Persistence policy remains provider-owned;\n\t * the update runs synchronously only after the selected persistence mutation.\n\t */\n\tpublish(publication: ModelsPublication): Promise<boolean>;\n\t/** False during offline/cache-only initialization. */\n\tallowNetwork: boolean;\n\t/** Bypass provider freshness checks and fetch immediately when network access is allowed. */\n\tforce?: boolean;\n\t/** Always present, including when the public refresh caller omits its optional signal. */\n\tsignal: AbortSignal;\n}\n\nexport interface ModelsRefreshOptions {\n\tallowNetwork?: boolean;\n\t/** Restrict refresh to these provider IDs. Unknown and static providers are ignored. */\n\tproviders?: readonly string[];\n\t/** Bypass provider freshness checks and fetch immediately when network access is allowed. */\n\tforce?: boolean;\n\tsignal?: AbortSignal;\n}\n\nexport interface ModelsRefreshResult {\n\taborted: boolean;\n\terrors: ReadonlyMap<string, Error>;\n}\n\nexport interface ModelsRequestTransforms {\n\t/** Transform fully assembled model/auth/request headers before provider dispatch. */\n\ttransformHeaders?: (headers: ProviderHeaders) => ProviderHeaders | Promise<ProviderHeaders>;\n}\n\nexport type ModelsApiStreamOptions<TApi extends Api> = ApiStreamOptions<TApi> & ModelsRequestTransforms;\nexport type ModelsSimpleStreamOptions = SimpleStreamOptions & ModelsRequestTransforms;\nexport type ModelsDeferredFetchOptions = DeferredFetchOptions & ModelsRequestTransforms;\nexport type ModelsDeferredCancelOptions = DeferredCancelOptions & ModelsRequestTransforms;\nexport type ModelsImagesOptions = ImagesOptions & ModelsRequestTransforms;\nexport type ModelsClassifierOptions = ClassifierOptions & ModelsRequestTransforms;\n\nconst KNOWN_MODEL_TYPES: Record<ModelType, true> = { chat: true, image: true, classifier: true };\n\n/** Models from stores and remote sources may have types that only newer versions know. */\nfunction hasKnownModelType(model: AnyModel): boolean {\n\treturn Object.hasOwn(KNOWN_MODEL_TYPES, getModelType(model));\n}\n\n/** Drops stored models whose type this version does not know. */\nfunction withKnownModelTypes(entry: ModelsStoreEntry): ModelsStoreEntry {\n\treturn { ...entry, models: entry.models.filter(hasKnownModelType) };\n}\n\n/** Any model a provider with chat APIs `TApi` can list. */\ntype ProviderModel<TApi extends Api> = Model<TApi> | ImageModel<ImageApi> | ClassifierModel<ClassifierApi>;\n\n/**\n * A provider is the concrete runtime unit. It owns id/name/base metadata,\n * auth methods, model listing, and the operations its models support\n * (streaming, image generation, classification).\n *\n * `TApi` lets concrete provider factories declare which chat APIs their models\n * use (e.g. `openaiProvider(): Provider<\"openai-responses\" | \"openai-completions\">`),\n * giving typed chat model lists to direct factory users. Other model types use\n * their operation-specific API unions. Inside a `Models` collection providers\n * are held as `Provider<Api>`.\n */\nexport interface Provider<TApi extends Api = Api> {\n\treadonly id: string;\n\treadonly name: string;\n\n\treadonly baseUrl?: string;\n\treadonly headers?: ProviderHeaders;\n\n\t/**\n\t * Required: at least one of `apiKey`/`oauth`. Every provider has auth\n\t * semantics — even providers with only ambient credentials (env vars, AWS\n\t * profiles, ADC files) and keyless local servers provide `apiKey` auth\n\t * whose `resolve()` reports whether the provider is configured.\n\t * `Models.getAuth()` returns undefined when the provider is unconfigured.\n\t */\n\treadonly auth: ProviderAuth;\n\n\t/**\n\t * Current known chat models, sync. Static providers return their catalog;\n\t * dynamic providers return the list as of the last `refreshModels()` (empty\n\t * before the first). Must not throw; `Models` treats a throwing\n\t * implementation as having no models.\n\t */\n\tgetModels(): readonly Model<TApi>[];\n\n\t/**\n\t * Current known models of every type, sync, with the same contract as\n\t * `getModels()`. Providers with only chat models may omit it; `Models` then\n\t * uses `getModels()`. Model ids are unique within each type; one upstream\n\t * model may have separate entries for different operations.\n\t */\n\tgetAllModels?(): readonly ProviderModel<TApi>[];\n\n\t/**\n\t * Dynamic providers only: restore `context.stored` and optionally fetch a newer list using\n\t * the effective credential. Implementations retain their previous list on failure, publish\n\t * persistence and synchronous state changes through `context.publish()`, and honor the\n\t * shared abort signal for blocking work.\n\t */\n\trefreshModels?(context: RefreshModelsContext): Promise<void>;\n\n\t/**\n\t * Optional provider policy for credential-specific model availability.\n\t * `getModels()` remains the complete synchronous chat catalog; `Models.getAvailable()`\n\t * applies this filter after confirming that provider auth is configured.\n\t */\n\tfilterModels?(models: readonly Model<TApi>[], credential: Credential | undefined): readonly Model<TApi>[];\n\n\t/**\n\t * Optional credential-specific availability policy across every model type.\n\t * Without it, `Models.getAllAvailable()` applies `filterModels` to chat models\n\t * and keeps every other model.\n\t */\n\tfilterAllModels?(\n\t\tmodels: readonly ProviderModel<TApi>[],\n\t\tcredential: Credential | undefined,\n\t): readonly ProviderModel<TApi>[];\n\n\t/** Stream a normalized transcript. `Models` normalizes the caller's `Context` before dispatching here. */\n\tstream<T extends TApi>(\n\t\tmodel: Model<T>,\n\t\tcontext: TranscriptContext,\n\t\toptions?: ApiStreamOptions<T>,\n\t): AssistantMessageEventStream;\n\n\tstreamSimple(\n\t\tmodel: Model<TApi>,\n\t\tcontext: TranscriptContext,\n\t\toptions?: SimpleStreamOptions,\n\t): AssistantMessageEventStream;\n\tfetchDeferred?(\n\t\tmodel: Model<TApi>,\n\t\thandle: DeferredHandle,\n\t\toptions?: DeferredFetchOptions,\n\t): AssistantMessageEventStream;\n\tcancelDeferred?(model: Model<TApi>, handle: DeferredHandle, options?: DeferredCancelOptions): Promise<void>;\n\n\t/** Present when the provider supports dedicated image models. Never rejects. */\n\tgenerateImages?(\n\t\tmodel: ImageModel<ImageApi>,\n\t\tcontext: ImagesContext,\n\t\toptions?: ImagesOptions,\n\t): Promise<AssistantImages>;\n\n\t/** Present when the provider supports structured classifier models. Never rejects. */\n\tclassify?(\n\t\tmodel: ClassifierModel<ClassifierApi>,\n\t\tcontext: ClassifierContext,\n\t\toptions?: ClassifierOptions,\n\t): Promise<ClassifierResult>;\n}\n\n/**\n * Runtime collection of providers plus auth application and request\n * convenience. Providers own request behavior; `Models` resolves auth and\n * delegates each request to the provider that owns the model.\n *\n * Read accessors come in three flavors: the unqualified ones (`getModels`,\n * `getModel`, `getAvailable`) return chat models, the `*OfType` accessors\n * return one model type, and `getAllModels`/`getAllAvailable` return every type.\n */\nexport interface Models {\n\tgetProviders(): readonly Provider[];\n\tgetProvider(id: string): Provider | undefined;\n\n\t/**\n\t * Sync read of last-known chat models from one provider or all providers.\n\t * Best-effort: a provider whose `getModels()` throws yields no models.\n\t */\n\tgetModels(provider?: string): readonly Model<Api>[];\n\n\t/**\n\t * Sync runtime chat model lookup against last-known lists. Dynamic model lists\n\t * are typed as `Model<Api>`; narrow with the `hasApi()` type guard.\n\t */\n\tgetModel(provider: string, id: string): Model<Api> | undefined;\n\n\t/** Sync read of last-known models of one type from one provider or all providers. */\n\tgetModelsOfType<TType extends ModelType>(type: TType, provider?: string): readonly ModelTypeMap[TType][];\n\n\t/** Sync runtime lookup of a model of one type against last-known lists. */\n\tgetModelOfType<TType extends ModelType>(type: TType, provider: string, id: string): ModelTypeMap[TType] | undefined;\n\n\t/** Sync read of last-known models of every type from one provider or all providers. */\n\tgetAllModels(provider?: string): readonly AnyModel[];\n\n\t/**\n\t * Refresh selected configured dynamic providers concurrently (all when `providers` is omitted).\n\t * Provider errors and cancellation are returned without rejecting; static, unknown, and\n\t * unconfigured providers are skipped.\n\t */\n\trefresh(options?: ModelsRefreshOptions): Promise<ModelsRefreshResult>;\n\n\t/** Check whether a provider has complete auth configuration without refreshing OAuth. */\n\tcheckAuth(providerId: string, options?: AuthOperationOptions): Promise<AuthCheck | undefined>;\n\n\t/** Return chat models whose providers have complete auth configuration. */\n\tgetAvailable(providerId?: string, options?: AuthOperationOptions): Promise<readonly Model<Api>[]>;\n\n\t/** Return models of one type whose providers have complete auth configuration. */\n\tgetAvailableOfType<TType extends ModelType>(\n\t\ttype: TType,\n\t\tproviderId?: string,\n\t\toptions?: AuthOperationOptions,\n\t): Promise<readonly ModelTypeMap[TType][]>;\n\n\t/** Return models of every type whose providers have complete auth configuration. */\n\tgetAllAvailable(providerId?: string, options?: AuthOperationOptions): Promise<readonly AnyModel[]>;\n\n\t/**\n\t * Resolve provider-scoped auth by provider id, or provider auth plus static\n\t * model headers when passed a model. Includes a source label for status UI.\n\t * Resolves `undefined` when the provider is unknown or unconfigured.\n\t * Rejects with `ModelsError`: code \"oauth\" when a token refresh fails (the\n\t * stored credential is preserved for retry; re-login fixes it), code \"auth\"\n\t * when api-key resolution or the credential store fails. Request paths\n\t * surface rejections as stream errors.\n\t */\n\tgetAuth(providerId: string, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;\n\tgetAuth(model: AnyModel, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;\n\n\t/** Run a provider-owned login flow and persist its returned credential. */\n\tlogin(providerId: string, type: AuthType, interaction: AuthInteraction): Promise<Credential>;\n\n\t/** Remove the stored credential for a provider. */\n\tlogout(providerId: string, options?: AuthOperationOptions): Promise<void>;\n\n\tstream<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): AssistantMessageEventStream;\n\n\tcomplete<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): Promise<AssistantMessage>;\n\n\tstreamSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): AssistantMessageEventStream;\n\tcompleteSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): Promise<AssistantMessage>;\n\tfetchDeferred(\n\t\tmodel: Model<Api>,\n\t\thandle: DeferredHandle,\n\t\toptions?: ModelsDeferredFetchOptions,\n\t): Promise<AssistantMessage>;\n\tcancelDeferred(model: Model<Api>, handle: DeferredHandle, options?: ModelsDeferredCancelOptions): Promise<void>;\n\n\t/**\n\t * Generate images through the owning provider with auth resolved like\n\t * `stream()`. Never rejects: unknown providers, unconfigured auth, and\n\t * providers without `generateImages` return an error `AssistantImages`.\n\t */\n\tgenerateImages(\n\t\tmodel: ImageModel<ImageApi>,\n\t\tcontext: ImagesContext,\n\t\toptions?: ModelsImagesOptions,\n\t): Promise<AssistantImages>;\n\n\t/** Classify structured state through the owning provider. Never rejects. */\n\tclassify(\n\t\tmodel: ClassifierModel<ClassifierApi>,\n\t\tcontext: ClassifierContext,\n\t\toptions?: ModelsClassifierOptions,\n\t): Promise<ClassifierResult>;\n}\n\nexport interface MutableModels extends Models {\n\t/** Upsert/replace by provider.id. Provider ids are unique. */\n\tsetProvider(provider: Provider): void;\n\tdeleteProvider(id: string): void;\n\tclearProviders(): void;\n}\n\nexport interface CreateModelsOptions {\n\tcredentials?: CredentialStore;\n\tmodelsStore?: ModelsStore;\n\tauthContext?: AuthContext;\n}\n\nfunction mergeHeaders(\n\tbase: ProviderHeaders | undefined,\n\toverride: ProviderHeaders | undefined,\n): ProviderHeaders | undefined {\n\tif (!base && !override) return undefined;\n\tconst merged = { ...base };\n\tfor (const [name, value] of Object.entries(override ?? {})) {\n\t\tconst lowerName = name.toLowerCase();\n\t\tfor (const existingName of Object.keys(merged)) {\n\t\t\tif (existingName.toLowerCase() === lowerName) delete merged[existingName];\n\t\t}\n\t\tmerged[name] = value;\n\t}\n\treturn merged;\n}\n\nclass ModelsImpl implements MutableModels {\n\tprivate providers = new Map<string, Provider>();\n\tprivate credentials: CredentialStore;\n\tprivate modelsStore: ModelsStore;\n\tprivate authContext: AuthContext;\n\tprivate refreshGenerations = new Map<string, number>();\n\tprivate refreshControllers = new Map<string, AbortController>();\n\tprivate publicationChains = new Map<string, Promise<unknown>>();\n\n\tconstructor(options?: CreateModelsOptions) {\n\t\tthis.credentials = options?.credentials ?? new InMemoryCredentialStore();\n\t\tthis.modelsStore = options?.modelsStore ?? new InMemoryModelsStore();\n\t\tthis.authContext = options?.authContext ?? defaultAuthContext();\n\t}\n\n\tsetProvider(provider: Provider): void {\n\t\tthis.supersedeProviderRefresh(provider.id);\n\t\tthis.providers.set(provider.id, provider);\n\t}\n\n\tdeleteProvider(id: string): void {\n\t\tthis.supersedeProviderRefresh(id);\n\t\tthis.providers.delete(id);\n\t}\n\n\tclearProviders(): void {\n\t\tfor (const id of new Set([...this.providers.keys(), ...this.refreshControllers.keys()])) {\n\t\t\tthis.supersedeProviderRefresh(id);\n\t\t}\n\t\tthis.providers.clear();\n\t}\n\n\tgetProviders(): readonly Provider[] {\n\t\treturn Array.from(this.providers.values());\n\t}\n\n\tgetProvider(id: string): Provider | undefined {\n\t\treturn this.providers.get(id);\n\t}\n\n\tgetModels(provider?: string): readonly Model<Api>[] {\n\t\tif (provider !== undefined) {\n\t\t\tconst entry = this.providers.get(provider);\n\t\t\tif (!entry) return [];\n\t\t\ttry {\n\t\t\t\treturn entry.getModels();\n\t\t\t} catch {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}\n\n\t\tconst models: Model<Api>[] = [];\n\t\tfor (const entry of this.providers.values()) {\n\t\t\ttry {\n\t\t\t\tmodels.push(...entry.getModels());\n\t\t\t} catch {\n\t\t\t\t// Best-effort: ill-behaved providers yield no models.\n\t\t\t}\n\t\t}\n\t\treturn models;\n\t}\n\n\tgetAllModels(provider?: string): readonly AnyModel[] {\n\t\tif (provider !== undefined) {\n\t\t\tconst entry = this.providers.get(provider);\n\t\t\tif (!entry) return [];\n\t\t\ttry {\n\t\t\t\treturn entry.getAllModels?.() ?? entry.getModels();\n\t\t\t} catch {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}\n\n\t\tconst models: AnyModel[] = [];\n\t\tfor (const entry of this.providers.values()) {\n\t\t\ttry {\n\t\t\t\tmodels.push(...(entry.getAllModels?.() ?? entry.getModels()));\n\t\t\t} catch {\n\t\t\t\t// Best-effort: ill-behaved providers yield no models.\n\t\t\t}\n\t\t}\n\t\treturn models;\n\t}\n\n\tgetModelsOfType<TType extends ModelType>(type: TType, provider?: string): readonly ModelTypeMap[TType][] {\n\t\treturn this.getAllModels(provider).filter((model): model is ModelTypeMap[TType] => isModelType(model, type));\n\t}\n\n\tgetModel(provider: string, id: string): Model<Api> | undefined {\n\t\treturn this.getModels(provider).find((model) => model.id === id);\n\t}\n\n\tgetModelOfType<TType extends ModelType>(type: TType, provider: string, id: string): ModelTypeMap[TType] | undefined {\n\t\treturn this.getModelsOfType(type, provider).find((model) => model.id === id);\n\t}\n\n\tprivate supersedeProviderRefresh(providerId: string): number {\n\t\tconst generation = (this.refreshGenerations.get(providerId) ?? 0) + 1;\n\t\tthis.refreshGenerations.set(providerId, generation);\n\t\tconst previous = this.refreshControllers.get(providerId);\n\t\tif (previous) {\n\t\t\tthis.refreshControllers.delete(providerId);\n\t\t\tprevious.abort();\n\t\t}\n\t\treturn generation;\n\t}\n\n\tprivate beginProviderRefresh(providerId: string): { generation: number; controller: AbortController } {\n\t\tconst generation = this.supersedeProviderRefresh(providerId);\n\t\tconst controller = new AbortController();\n\t\tthis.refreshControllers.set(providerId, controller);\n\t\treturn { generation, controller };\n\t}\n\n\tprivate publishProviderModels(\n\t\tproviderId: string,\n\t\tgeneration: number,\n\t\tsignal: AbortSignal,\n\t\tpublication: ModelsPublication,\n\t): Promise<boolean> {\n\t\tconst previous = this.publicationChains.get(providerId) ?? Promise.resolve();\n\t\tconst queued = (async () => {\n\t\t\tawait previous.catch(() => {});\n\t\t\tif (signal.aborted || this.refreshGenerations.get(providerId) !== generation) return false;\n\n\t\t\tif (publication.persist === null) {\n\t\t\t\tawait this.modelsStore.delete(providerId, { signal });\n\t\t\t} else if (publication.persist !== undefined) {\n\t\t\t\tawait this.modelsStore.write(providerId, structuredClone(publication.persist), { signal });\n\t\t\t}\n\n\t\t\tif (signal.aborted || this.refreshGenerations.get(providerId) !== generation) return false;\n\t\t\tpublication.update?.();\n\t\t\treturn true;\n\t\t})();\n\t\tconst tail = queued.catch(() => {});\n\t\tthis.publicationChains.set(providerId, tail);\n\t\tvoid tail.then(() => {\n\t\t\tif (this.publicationChains.get(providerId) === tail) this.publicationChains.delete(providerId);\n\t\t});\n\t\treturn raceWithAbortSignal(queued, signal);\n\t}\n\n\tprivate async runProviderRefreshPhase(\n\t\tprovider: Provider & Required<Pick<Provider, \"refreshModels\">>,\n\t\tcredential: Credential | undefined,\n\t\tallowNetwork: boolean,\n\t\tforce: boolean | undefined,\n\t\tgeneration: number,\n\t\tsignal: AbortSignal,\n\t): Promise<void> {\n\t\tconst stored = await this.modelsStore.read(provider.id, { signal });\n\t\tawait provider.refreshModels({\n\t\t\tcredential,\n\t\t\tstored: stored ? withKnownModelTypes(structuredClone(stored)) : undefined,\n\t\t\tpublish: (publication) => this.publishProviderModels(provider.id, generation, signal, publication),\n\t\t\tallowNetwork,\n\t\t\tforce: allowNetwork ? force : undefined,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync refresh(options: ModelsRefreshOptions = {}): Promise<ModelsRefreshResult> {\n\t\tconst allowNetwork = options.allowNetwork ?? true;\n\t\tconst callerSignal = operationSignal(options.signal);\n\t\tconst errors = new Map<string, Error>();\n\t\tif (callerSignal.aborted) return { aborted: true, errors };\n\t\tconst selected = options.providers ? new Set(options.providers) : undefined;\n\t\tconst refreshable = Array.from(this.providers.values()).filter(\n\t\t\t(provider): provider is Provider & Required<Pick<Provider, \"refreshModels\">> =>\n\t\t\t\tprovider.refreshModels !== undefined && (!selected || selected.has(provider.id)),\n\t\t);\n\n\t\tconst refresh = Promise.all(\n\t\t\trefreshable.map(async (provider) => {\n\t\t\t\tconst { generation, controller } = this.beginProviderRefresh(provider.id);\n\t\t\t\tconst signal = AbortSignal.any([callerSignal, controller.signal]);\n\t\t\t\tconst operation = (async () => {\n\t\t\t\t\tlet storedCredential: Credential | undefined;\n\t\t\t\t\tlet credentialError: unknown;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tstoredCredential = await this.readCredential(provider.id, signal);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tcredentialError = error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Restore cached provider state before auth resolution or network access.\n\t\t\t\t\tawait this.runProviderRefreshPhase(provider, storedCredential, false, undefined, generation, signal);\n\t\t\t\t\tif (credentialError !== undefined) throw credentialError;\n\t\t\t\t\tif (!allowNetwork || signal.aborted) return;\n\n\t\t\t\t\tconst credential = await this.resolveRefreshCredential(provider, storedCredential, signal);\n\t\t\t\t\tif (!credential) return;\n\t\t\t\t\tawait this.runProviderRefreshPhase(provider, credential, true, options.force, generation, signal);\n\t\t\t\t})();\n\n\t\t\t\ttry {\n\t\t\t\t\tawait raceWithAbortSignal(operation, signal);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!signal.aborted) {\n\t\t\t\t\t\terrors.set(\n\t\t\t\t\t\t\tprovider.id,\n\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t? error\n\t\t\t\t\t\t\t\t: new ModelsError(\"model_source\", `Model refresh failed for ${provider.id}`, { cause: error }),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tif (this.refreshControllers.get(provider.id) === controller) {\n\t\t\t\t\t\tthis.refreshControllers.delete(provider.id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\ttry {\n\t\t\tawait raceWithAbortSignal(refresh, callerSignal);\n\t\t} catch (error) {\n\t\t\tif (!callerSignal.aborted) throw error;\n\t\t}\n\n\t\treturn { aborted: callerSignal.aborted, errors: new Map(errors) };\n\t}\n\n\tprivate async resolveRefreshCredential(\n\t\tprovider: Provider,\n\t\tstored: Credential | undefined,\n\t\tsignal: AbortSignal,\n\t): Promise<Credential | undefined> {\n\t\tif (stored?.type === \"oauth\") {\n\t\t\tconst oauth = provider.auth.oauth;\n\t\t\tif (!oauth) return undefined;\n\t\t\tif (Date.now() < stored.expires) return stored;\n\t\t\tif (signal.aborted) return undefined;\n\t\t\tconst post = await this.credentials.modify(\n\t\t\t\tprovider.id,\n\t\t\t\tasync (current) => {\n\t\t\t\t\tif (current?.type !== \"oauth\" || Date.now() < current.expires) return undefined;\n\t\t\t\t\treturn oauth.refresh(current, signal);\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t\treturn post?.type === \"oauth\" ? post : undefined;\n\t\t}\n\n\t\tconst apiKey = provider.auth.apiKey;\n\t\tif (!apiKey) return undefined;\n\t\tconst credential = stored?.type === \"api_key\" ? stored : undefined;\n\t\tconst result = await apiKey.resolve({ ctx: this.authContext, credential, signal });\n\t\tif (!result) return undefined;\n\t\treturn { type: \"api_key\", key: result.auth.apiKey, env: result.env };\n\t}\n\n\tprivate async readCredential(providerId: string, signal: AbortSignal): Promise<Credential | undefined> {\n\t\ttry {\n\t\t\treturn await this.credentials.read(providerId, { signal });\n\t\t} catch (error) {\n\t\t\tthrow new ModelsError(\"auth\", `Credential store read failed for ${providerId}`, { cause: error });\n\t\t}\n\t}\n\n\tprivate async checkProviderAuth(\n\t\tprovider: Provider,\n\t\tcredential: Credential | undefined,\n\t\tsignal: AbortSignal,\n\t): Promise<AuthCheck | undefined> {\n\t\tif (credential?.type === \"oauth\") {\n\t\t\treturn provider.auth.oauth ? { source: \"OAuth\", type: \"oauth\" } : undefined;\n\t\t}\n\t\tconst apiKey = provider.auth.apiKey;\n\t\tif (!apiKey) return undefined;\n\t\tif (apiKey.check) {\n\t\t\ttry {\n\t\t\t\treturn await apiKey.check({\n\t\t\t\t\tctx: this.authContext,\n\t\t\t\t\tcredential: credential?.type === \"api_key\" ? credential : undefined,\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthrow new ModelsError(\"auth\", `API key auth check failed for provider ${provider.id}`, { cause: error });\n\t\t\t}\n\t\t}\n\n\t\tconst resolution = await resolveProviderAuth(provider, this.credentials, this.authContext, { signal });\n\t\treturn resolution ? { source: resolution.source, type: \"api_key\" } : undefined;\n\t}\n\n\tcheckAuth(providerId: string, options?: AuthOperationOptions): Promise<AuthCheck | undefined> {\n\t\tconst signal = operationSignal(options?.signal);\n\t\tconst check = (async () => {\n\t\t\tsignal.throwIfAborted();\n\t\t\tconst provider = this.providers.get(providerId);\n\t\t\tif (!provider) return undefined;\n\t\t\treturn this.checkProviderAuth(provider, await this.readCredential(providerId, signal), signal);\n\t\t})();\n\t\treturn raceWithAbortSignal(check, signal);\n\t}\n\n\tprivate async getAuthenticatedProviders(providerId: string | undefined, signal: AbortSignal) {\n\t\tsignal.throwIfAborted();\n\t\tconst providers = providerId\n\t\t\t? [this.providers.get(providerId)].filter((entry) => entry !== undefined)\n\t\t\t: this.getProviders();\n\t\tconst checks = await Promise.all(\n\t\t\tproviders.map(async (provider) => {\n\t\t\t\tconst credential = await this.readCredential(provider.id, signal);\n\t\t\t\treturn { provider, credential, auth: await this.checkProviderAuth(provider, credential, signal) };\n\t\t\t}),\n\t\t);\n\t\treturn checks.filter((entry) => entry.auth !== undefined);\n\t}\n\n\tgetAvailable(providerId?: string, options?: AuthOperationOptions): Promise<readonly Model<Api>[]> {\n\t\tconst signal = operationSignal(options?.signal);\n\t\tconst available = (async () => {\n\t\t\tconst providers = await this.getAuthenticatedProviders(providerId, signal);\n\t\t\treturn providers.flatMap(({ provider, credential }) => {\n\t\t\t\tconst models = provider.getModels();\n\t\t\t\treturn provider.filterModels?.(models, credential) ?? models;\n\t\t\t});\n\t\t})();\n\t\treturn raceWithAbortSignal(available, signal);\n\t}\n\n\tasync getAvailableOfType<TType extends ModelType>(\n\t\ttype: TType,\n\t\tproviderId?: string,\n\t\toptions?: AuthOperationOptions,\n\t): Promise<readonly ModelTypeMap[TType][]> {\n\t\treturn (await this.getAllAvailable(providerId, options)).filter((model): model is ModelTypeMap[TType] =>\n\t\t\tisModelType(model, type),\n\t\t);\n\t}\n\n\tgetAllAvailable(providerId?: string, options?: AuthOperationOptions): Promise<readonly AnyModel[]> {\n\t\tconst signal = operationSignal(options?.signal);\n\t\tconst available = (async () => {\n\t\t\tconst providers = await this.getAuthenticatedProviders(providerId, signal);\n\t\t\treturn providers.flatMap(({ provider, credential }) => {\n\t\t\t\tconst models = provider.getAllModels?.() ?? provider.getModels();\n\t\t\t\tif (provider.filterAllModels) return provider.filterAllModels(models, credential);\n\t\t\t\tif (!provider.filterModels) return models;\n\t\t\t\tconst availableChatIds = new Set(\n\t\t\t\t\tprovider.filterModels(provider.getModels(), credential).map((model) => model.id),\n\t\t\t\t);\n\t\t\t\treturn models.filter((model) => !isModelType(model, \"chat\") || availableChatIds.has(model.id));\n\t\t\t});\n\t\t})();\n\t\treturn raceWithAbortSignal(available, signal);\n\t}\n\n\tgetAuth(providerId: string, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;\n\tgetAuth(model: AnyModel, overrides?: AuthResolutionOverrides): Promise<AuthResult | undefined>;\n\tasync getAuth(\n\t\tproviderOrModel: string | AnyModel,\n\t\toverrides?: AuthResolutionOverrides,\n\t): Promise<AuthResult | undefined> {\n\t\tconst signal = operationSignal(overrides?.signal);\n\t\tconst providerId = typeof providerOrModel === \"string\" ? providerOrModel : providerOrModel.provider;\n\t\tconst provider = this.providers.get(providerId);\n\t\tif (!provider) return undefined;\n\t\tconst result = await resolveProviderAuth(provider, this.credentials, this.authContext, { ...overrides, signal });\n\t\tif (!result || typeof providerOrModel === \"string\" || !providerOrModel.headers) return result;\n\t\treturn {\n\t\t\t...result,\n\t\t\tauth: {\n\t\t\t\t...result.auth,\n\t\t\t\theaders: mergeHeaders(result.auth.headers, providerOrModel.headers),\n\t\t\t},\n\t\t};\n\t}\n\n\tasync login(providerId: string, type: AuthType, interaction: AuthInteraction): Promise<Credential> {\n\t\tconst signal = operationSignal(interaction.signal);\n\t\tsignal.throwIfAborted();\n\t\tconst provider = this.providers.get(providerId);\n\t\tif (!provider) throw new ModelsError(\"provider\", `Unknown provider: ${providerId}`);\n\t\tconst method = type === \"oauth\" ? provider.auth.oauth : provider.auth.apiKey;\n\t\tif (!method?.login) {\n\t\t\tthrow new ModelsError(\"auth\", `${provider.name} does not support ${type} login`);\n\t\t}\n\t\tconst loginOperation: Promise<Credential> = method.login({ ...interaction, signal });\n\t\tconst credential = await raceWithAbortSignal(loginOperation, signal);\n\t\tlet mutationStarted = false;\n\t\tlet markMutationStarted: (() => void) | undefined;\n\t\tconst started = new Promise<void>((resolve) => {\n\t\t\tmarkMutationStarted = resolve;\n\t\t});\n\t\tconst mutation = this.credentials.modify(\n\t\t\tproviderId,\n\t\t\tasync () => {\n\t\t\t\tmutationStarted = true;\n\t\t\t\tmarkMutationStarted?.();\n\t\t\t\treturn credential;\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tvoid mutation.catch(() => {});\n\t\ttry {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tif (!mutationStarted) reject(signal.reason);\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tvoid Promise.race([started, mutation]).then(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t},\n\t\t\t\t\t(error: unknown) => {\n\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(error);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t});\n\t\t\tawait mutation;\n\t\t} catch (error) {\n\t\t\tsignal.throwIfAborted();\n\t\t\tthrow new ModelsError(\"auth\", `Credential store modify failed for ${providerId}`, { cause: error });\n\t\t}\n\t\treturn credential;\n\t}\n\n\tasync logout(providerId: string, options?: AuthOperationOptions): Promise<void> {\n\t\tconst signal = operationSignal(options?.signal);\n\t\tsignal.throwIfAborted();\n\t\ttry {\n\t\t\tawait this.credentials.delete(providerId, { signal });\n\t\t} catch (error) {\n\t\t\tsignal.throwIfAborted();\n\t\t\tthrow new ModelsError(\"auth\", `Credential store delete failed for ${providerId}`, { cause: error });\n\t\t}\n\t}\n\n\tprivate requireProvider(model: AnyModel): Provider {\n\t\tconst provider = this.providers.get(model.provider);\n\t\tif (!provider) {\n\t\t\tthrow new ModelsError(\"provider\", `Unknown provider: ${model.provider}`);\n\t\t}\n\t\treturn provider;\n\t}\n\n\tprivate requireChatProvider(model: Model<Api>): Provider {\n\t\tassertChatModel(model);\n\t\treturn this.requireProvider(model);\n\t}\n\n\tprivate async applyAuth<\n\t\tTModel extends AnyModel,\n\t\tTOptions extends ProviderRequestOptions<TModel> & ModelsRequestTransforms,\n\t>(\n\t\tmodel: TModel,\n\t\toptions: TOptions | undefined,\n\t): Promise<{\n\t\trequestModel: TModel;\n\t\trequestOptions: Omit<TOptions, \"transformHeaders\"> & ProviderRequestOptions<TModel>;\n\t}> {\n\t\tthis.requireProvider(model);\n\t\tconst resolution = await this.getAuth(model, {\n\t\t\tapiKey: options?.apiKey,\n\t\t\tenv: options?.env,\n\t\t\tsignal: options?.signal,\n\t\t});\n\t\tif (!resolution) {\n\t\t\tthrow new ModelsError(\"auth\", `Provider is not configured: ${model.provider}`);\n\t\t}\n\t\tconst auth = resolution.auth;\n\n\t\t// Explicit request options win per-field; the Models-only transform runs last.\n\t\tconst apiKey = options?.apiKey ?? auth.apiKey;\n\t\tlet headers = mergeHeaders(auth.headers, options?.headers);\n\t\tif (options?.transformHeaders) headers = await options.transformHeaders(headers ?? {});\n\t\tconst env = resolution.env || options?.env ? { ...(resolution.env ?? {}), ...(options?.env ?? {}) } : undefined;\n\t\tconst requestModel: TModel = auth.baseUrl ? { ...model, baseUrl: auth.baseUrl } : model;\n\t\tconst { transformHeaders: _transformHeaders, ...providerOptions } = options ?? {};\n\t\tconst requestOptions = { ...providerOptions, apiKey, headers, env } as Omit<TOptions, \"transformHeaders\"> &\n\t\t\tProviderRequestOptions<TModel>;\n\n\t\treturn { requestModel, requestOptions };\n\t}\n\n\tstream<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): AssistantMessageEventStream {\n\t\tconst transcript = normalizeContext(context);\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst provider = this.requireChatProvider(model);\n\t\t\tconst { requestModel, requestOptions } = await this.applyAuth(\n\t\t\t\tmodel,\n\t\t\t\toptions as ModelsApiStreamOptions<Api> | undefined,\n\t\t\t);\n\t\t\treturn provider.stream(requestModel, transcript, requestOptions as ApiStreamOptions<TApi>);\n\t\t});\n\t}\n\n\tasync complete<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): Promise<AssistantMessage> {\n\t\treturn this.stream(model, context, options).result();\n\t}\n\n\tstreamSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): AssistantMessageEventStream {\n\t\tconst transcript = normalizeContext(context);\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst provider = this.requireChatProvider(model);\n\t\t\tconst { requestModel, requestOptions } = await this.applyAuth(model, options);\n\t\t\treturn provider.streamSimple(requestModel, transcript, requestOptions as SimpleStreamOptions);\n\t\t});\n\t}\n\n\tasync completeSimple(\n\t\tmodel: Model<Api>,\n\t\tcontext: Context,\n\t\toptions?: ModelsSimpleStreamOptions,\n\t): Promise<AssistantMessage> {\n\t\treturn this.streamSimple(model, context, options).result();\n\t}\n\n\tasync fetchDeferred(\n\t\tmodel: Model<Api>,\n\t\thandle: DeferredHandle,\n\t\toptions?: ModelsDeferredFetchOptions,\n\t): Promise<AssistantMessage> {\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst provider = this.requireChatProvider(model);\n\t\t\tif (!provider.fetchDeferred) {\n\t\t\t\tthrow new ModelsError(\"provider\", `Provider ${model.provider} does not support deferred responses`);\n\t\t\t}\n\t\t\tconst { requestModel, requestOptions } = await this.applyAuth(model, options);\n\t\t\treturn provider.fetchDeferred(requestModel, handle, requestOptions as DeferredFetchOptions);\n\t\t}).result();\n\t}\n\n\tasync cancelDeferred(\n\t\tmodel: Model<Api>,\n\t\thandle: DeferredHandle,\n\t\toptions?: ModelsDeferredCancelOptions,\n\t): Promise<void> {\n\t\tconst provider = this.requireChatProvider(model);\n\t\tif (!provider.cancelDeferred) {\n\t\t\tthrow new ModelsError(\"provider\", `Provider ${model.provider} does not support deferred responses`);\n\t\t}\n\t\tconst { requestModel, requestOptions } = await this.applyAuth(model, options);\n\t\tawait provider.cancelDeferred(requestModel, handle, requestOptions);\n\t}\n\n\tasync generateImages(\n\t\tmodel: ImageModel<ImageApi>,\n\t\tcontext: ImagesContext,\n\t\toptions?: ModelsImagesOptions,\n\t): Promise<AssistantImages> {\n\t\ttry {\n\t\t\tassertImageModel(model);\n\t\t\tconst provider = this.requireProvider(model);\n\t\t\tif (!provider.generateImages) {\n\t\t\t\tthrow new ModelsError(\"provider\", `Provider ${model.provider} does not support image generation`);\n\t\t\t}\n\t\t\tconst { requestModel, requestOptions } = await this.applyAuth(model, options);\n\t\t\treturn await provider.generateImages(requestModel, context, requestOptions);\n\t\t} catch (error) {\n\t\t\treturn imageErrorResult(model, error, options?.signal?.aborted);\n\t\t}\n\t}\n\n\tasync classify(\n\t\tmodel: ClassifierModel<ClassifierApi>,\n\t\tcontext: ClassifierContext,\n\t\toptions?: ModelsClassifierOptions,\n\t): Promise<ClassifierResult> {\n\t\ttry {\n\t\t\tassertClassifierModel(model);\n\t\t\tconst provider = this.requireProvider(model);\n\t\t\tif (!provider.classify) {\n\t\t\t\tthrow new ModelsError(\"provider\", `Provider ${model.provider} does not support classification`);\n\t\t\t}\n\t\t\tconst { requestModel, requestOptions } = await this.applyAuth(model, options);\n\t\t\treturn await provider.classify(requestModel, context, requestOptions);\n\t\t} catch (error) {\n\t\t\treturn classifierErrorResult(model, error, options?.signal?.aborted);\n\t\t}\n\t}\n}\n\nexport function createModels(options?: CreateModelsOptions): MutableModels {\n\treturn new ModelsImpl(options);\n}\n\nexport interface CreateProviderOptions<TApi extends Api = Api> {\n\tid: string;\n\t/** Display name. Default: `id`. */\n\tname?: string;\n\tbaseUrl?: string;\n\theaders?: ProviderHeaders;\n\t/** Required — every provider has auth semantics, even ambient/keyless ones. */\n\tauth: ProviderAuth;\n\t/**\n\t * Static baseline models of every type (empty for purely dynamic providers).\n\t * Models without `type` are chat models.\n\t */\n\tmodels: readonly ProviderModel<TApi>[];\n\t/**\n\t * Fetch a dynamic model overlay of every type. createProvider restores and\n\t * publishes it transactionally and drops models of unknown types.\n\t */\n\tfetchModels?: (context: RefreshModelsContext) => Promise<readonly ProviderModel<TApi>[]>;\n\t/** Credential-specific chat model availability. See `Provider.filterModels`. */\n\tfilterModels?: (models: readonly Model<TApi>[], credential: Credential | undefined) => readonly Model<TApi>[];\n\t/** Credential-specific availability across every model type. See `Provider.filterAllModels`. */\n\tfilterAllModels?: (\n\t\tmodels: readonly ProviderModel<TApi>[],\n\t\tcredential: Credential | undefined,\n\t) => readonly ProviderModel<TApi>[];\n\t/**\n\t * Chat implementation: a single one for all chat models, or a map keyed by\n\t * `model.api` for mixed-API providers. Optional when `images` or\n\t * `classifiers` is given.\n\t */\n\tapi?: ProviderStreams | Partial<Record<TApi, ProviderStreams>>;\n\t/** Image-generation implementations keyed by `model.api`. */\n\timages?: Partial<Record<ImageApi, ProviderImages>>;\n\t/** Classifier implementations keyed by `model.api`. */\n\tclassifiers?: Partial<Record<ClassifierApi, ProviderClassifier>>;\n}\n\n/**\n * Builds a provider from parts. Built-in provider factories and models.json\n * custom providers both go through this. A single `api` streams all chat\n * models; an `api` map dispatches on `model.api`, and a model whose api has\n * no entry produces a stream error. One-shot operation maps dispatch on\n * `model.api` the same way. At least one concrete implementation across\n * `api`/`images`/`classifiers` is required; empty maps are rejected.\n */\nexport function createProvider<TApi extends Api = Api>(input: CreateProviderOptions<TApi>): Provider<TApi> {\n\tconst single =\n\t\tinput.api && typeof (input.api as ProviderStreams).stream === \"function\"\n\t\t\t? (input.api as ProviderStreams)\n\t\t\t: undefined;\n\tconst byApi = single || !input.api ? undefined : (input.api as Partial<Record<string, ProviderStreams>>);\n\tconst images = input.images as Partial<Record<string, ProviderImages>> | undefined;\n\tconst classifiers = input.classifiers as Partial<Record<string, ProviderClassifier>> | undefined;\n\tconst streams = single ? [single] : Object.values(byApi ?? {}).filter((entry) => entry !== undefined);\n\tconst imageImplementations = Object.values(images ?? {}).filter((entry) => entry !== undefined);\n\tconst classifierImplementations = Object.values(classifiers ?? {}).filter((entry) => entry !== undefined);\n\tif (streams.length === 0 && imageImplementations.length === 0 && classifierImplementations.length === 0) {\n\t\tthrow new Error(`Provider ${input.id}: at least one of \"api\", \"images\", or \"classifiers\" is required.`);\n\t}\n\n\tconst baselineModels = input.models;\n\tlet dynamicModels: readonly ProviderModel<TApi>[] = [];\n\tconst fetchModels = input.fetchModels;\n\tconst currentModels = (): readonly ProviderModel<TApi>[] => {\n\t\tconst merged = [...baselineModels];\n\t\tfor (const model of dynamicModels) {\n\t\t\tconst index = merged.findIndex(\n\t\t\t\t(entry) => getModelType(entry) === getModelType(model) && entry.id === model.id,\n\t\t\t);\n\t\t\tif (index >= 0) merged[index] = model;\n\t\t\telse merged.push(model);\n\t\t}\n\t\treturn merged;\n\t};\n\tconst apiFor = (model: Model<Api>): ProviderStreams | undefined => single ?? byApi?.[model.api];\n\n\tconst dispatch = (\n\t\tmodel: Model<Api>,\n\t\trun: (streams: ProviderStreams) => AssistantMessageEventStream,\n\t): AssistantMessageEventStream => {\n\t\tconst streams = apiFor(model);\n\t\tif (!streams) {\n\t\t\treturn lazyStream(model, async () => {\n\t\t\t\tthrow new ModelsError(\"stream\", `Provider ${input.id} has no API implementation for \"${model.api}\"`);\n\t\t\t});\n\t\t}\n\t\treturn run(streams);\n\t};\n\n\tconst provider: Provider<TApi> = {\n\t\tid: input.id,\n\t\tname: input.name ?? input.id,\n\t\tbaseUrl: input.baseUrl,\n\t\theaders: input.headers,\n\t\tauth: input.auth,\n\t\tgetModels: () => currentModels().filter((model): model is Model<TApi> => isModelType(model, \"chat\")),\n\t\tgetAllModels: currentModels,\n\t\trefreshModels: fetchModels\n\t\t\t? async (context) => {\n\t\t\t\t\tif (context.stored) {\n\t\t\t\t\t\tconst restored = context.stored.models\n\t\t\t\t\t\t\t.filter((model) => model.provider === input.id)\n\t\t\t\t\t\t\t.map((model) => model as ProviderModel<TApi>);\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!(await context.publish({\n\t\t\t\t\t\t\t\tupdate: () => {\n\t\t\t\t\t\t\t\t\tdynamicModels = restored;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!context.allowNetwork || context.signal.aborted) return;\n\t\t\t\t\tconst fetched = await fetchModels(context);\n\t\t\t\t\tif (context.signal.aborted) return;\n\t\t\t\t\tconst refreshed = fetched.filter(hasKnownModelType);\n\t\t\t\t\tawait context.publish({\n\t\t\t\t\t\tpersist: { models: refreshed, checkedAt: Date.now() },\n\t\t\t\t\t\tupdate: () => {\n\t\t\t\t\t\t\tdynamicModels = refreshed;\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfilterModels: input.filterModels,\n\t\tfilterAllModels: input.filterAllModels,\n\t\tstream: (model, context, options) => dispatch(model, (streams) => streams.stream(model, context, options)),\n\t\tstreamSimple: (model, context, options) =>\n\t\t\tdispatch(model, (streams) => streams.streamSimple(model, context, options)),\n\t};\n\n\tif (streams.some((entry) => entry.fetchDeferred !== undefined)) {\n\t\tprovider.fetchDeferred = (model, handle, options) =>\n\t\t\tlazyStream(model, async () => {\n\t\t\t\tconst implementation = apiFor(model);\n\t\t\t\tif (!implementation?.fetchDeferred) {\n\t\t\t\t\tthrow new ModelsError(\n\t\t\t\t\t\t\"provider\",\n\t\t\t\t\t\t`Provider ${input.id} does not support deferred responses for \"${model.api}\"`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn implementation.fetchDeferred(model, handle, options);\n\t\t\t});\n\t}\n\tif (streams.some((entry) => entry.cancelDeferred !== undefined)) {\n\t\tprovider.cancelDeferred = async (model, handle, options) => {\n\t\t\tconst implementation = apiFor(model);\n\t\t\tif (!implementation?.cancelDeferred) {\n\t\t\t\tthrow new ModelsError(\n\t\t\t\t\t\"provider\",\n\t\t\t\t\t`Provider ${input.id} cannot cancel deferred responses for \"${model.api}\"`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait implementation.cancelDeferred(model, handle, options);\n\t\t};\n\t}\n\tif (images && imageImplementations.length > 0) {\n\t\tprovider.generateImages = async (model, context, options) => {\n\t\t\tconst implementation = images[model.api];\n\t\t\tif (!implementation) {\n\t\t\t\treturn imageErrorResult(\n\t\t\t\t\tmodel,\n\t\t\t\t\tnew ModelsError(\n\t\t\t\t\t\t\"provider\",\n\t\t\t\t\t\t`Provider ${input.id} has no image generation implementation for \"${model.api}\"`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn implementation.generateImages(model, context, options);\n\t\t};\n\t}\n\tif (classifiers && classifierImplementations.length > 0) {\n\t\tprovider.classify = async (model, context, options) => {\n\t\t\tconst implementation = classifiers[model.api];\n\t\t\tif (!implementation) {\n\t\t\t\treturn classifierErrorResult(\n\t\t\t\t\tmodel,\n\t\t\t\t\tnew ModelsError(\"provider\", `Provider ${input.id} has no classifier implementation for \"${model.api}\"`),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn implementation.classify(model, context, options);\n\t\t};\n\t}\n\n\treturn provider;\n}\n\n/**\n * Runtime-checked narrowing for dynamically looked-up models:\n *\n * ```ts\n * const model = models.getModel(\"anthropic\", \"claude-opus-4-7\");\n * if (model && hasApi(model, \"anthropic-messages\")) {\n * // model: Model<\"anthropic-messages\">, stream options fully typed\n * }\n * ```\n *\n * Non-chat models never match, even when their api id equals `api`.\n */\nexport function hasApi<TApi extends Api>(model: AnyModel, api: TApi): model is Model<TApi> {\n\treturn isModelType(model, \"chat\") && model.api === api;\n}\n\nexport function calculateCost(model: AnyModel, usage: Usage): Usage[\"cost\"] {\n\tconst inputTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\tlet rates: ModelCostRates = model.cost;\n\tlet matchedThreshold = -1;\n\tfor (const tier of model.cost.tiers ?? []) {\n\t\tif (inputTokens > tier.inputTokensAbove && tier.inputTokensAbove > matchedThreshold) {\n\t\t\trates = tier;\n\t\t\tmatchedThreshold = tier.inputTokensAbove;\n\t\t}\n\t}\n\n\t// Anthropic charges 2x base input for 1h cache writes.\n\tconst longWrite = usage.cacheWrite1h ?? 0;\n\tconst shortWrite = usage.cacheWrite - longWrite;\n\tusage.cost.input = (rates.input / 1000000) * usage.input;\n\tusage.cost.output = (rates.output / 1000000) * usage.output;\n\tusage.cost.cacheRead = (rates.cacheRead / 1000000) * usage.cacheRead;\n\tusage.cost.cacheWrite = (rates.cacheWrite * shortWrite + rates.input * 2 * longWrite) / 1000000;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n\treturn usage.cost;\n}\n\nconst EXTENDED_THINKING_LEVELS: ModelThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n\nexport function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[] {\n\tif (!model.reasoning) return [\"off\"];\n\n\treturn EXTENDED_THINKING_LEVELS.filter((level) => {\n\t\tconst mapped = model.thinkingLevelMap?.[level];\n\t\tif (mapped === null) return false;\n\t\tif (level === \"xhigh\" || level === \"max\") return mapped !== undefined;\n\t\treturn true;\n\t});\n}\n\nexport function clampThinkingLevel<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tlevel: ModelThinkingLevel,\n): ModelThinkingLevel {\n\tconst availableLevels = getSupportedThinkingLevels(model);\n\tif (availableLevels.includes(level)) return level;\n\n\tconst requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);\n\tif (requestedIndex === -1) return availableLevels[0] ?? \"off\";\n\n\tfor (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\tfor (let i = requestedIndex - 1; i >= 0; i--) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\treturn availableLevels[0] ?? \"off\";\n}\n\n/**\n * Check if two models are equal by comparing their type, id, and provider.\n * Returns false if either model is null or undefined.\n */\nexport function modelsAreEqual(a: AnyModel | null | undefined, b: AnyModel | null | undefined): boolean {\n\tif (!a || !b) return false;\n\treturn getModelType(a) === getModelType(b) && a.id === b.id && a.provider === b.provider;\n}\n"]}