@draht/ai 2026.10.20 → 2026.10.23

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 (269) hide show
  1. package/dist/api/anthropic-messages.d.ts.map +1 -1
  2. package/dist/api/anthropic-messages.js +155 -111
  3. package/dist/api/anthropic-messages.js.map +1 -1
  4. package/dist/api/azure-openai-config.d.ts +15 -0
  5. package/dist/api/azure-openai-config.d.ts.map +1 -0
  6. package/dist/api/azure-openai-config.js +76 -0
  7. package/dist/api/azure-openai-config.js.map +1 -0
  8. package/dist/api/azure-openai-responses.d.ts +3 -6
  9. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  10. package/dist/api/azure-openai-responses.js +19 -83
  11. package/dist/api/azure-openai-responses.js.map +1 -1
  12. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  13. package/dist/api/bedrock-converse-stream.js +86 -22
  14. package/dist/api/bedrock-converse-stream.js.map +1 -1
  15. package/dist/api/classifier-shared.d.ts +21 -0
  16. package/dist/api/classifier-shared.d.ts.map +1 -0
  17. package/dist/api/classifier-shared.js +99 -0
  18. package/dist/api/classifier-shared.js.map +1 -0
  19. package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -1
  20. package/dist/api/cloudflare-workers-ai-system-one.js +15 -9
  21. package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -1
  22. package/dist/api/google-generative-ai.js +4 -4
  23. package/dist/api/google-generative-ai.js.map +1 -1
  24. package/dist/api/google-shared.d.ts.map +1 -1
  25. package/dist/api/google-shared.js +3 -1
  26. package/dist/api/google-shared.js.map +1 -1
  27. package/dist/api/google-vertex.d.ts.map +1 -1
  28. package/dist/api/google-vertex.js +9 -9
  29. package/dist/api/google-vertex.js.map +1 -1
  30. package/dist/api/lazy.d.ts +7 -2
  31. package/dist/api/lazy.d.ts.map +1 -1
  32. package/dist/api/lazy.js +28 -8
  33. package/dist/api/lazy.js.map +1 -1
  34. package/dist/api/llama-cpp-classify.d.ts.map +1 -1
  35. package/dist/api/llama-cpp-classify.js +4 -1
  36. package/dist/api/llama-cpp-classify.js.map +1 -1
  37. package/dist/api/mistral-conversations.d.ts.map +1 -1
  38. package/dist/api/mistral-conversations.js +38 -18
  39. package/dist/api/mistral-conversations.js.map +1 -1
  40. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  41. package/dist/api/openai-codex-responses.js +21 -13
  42. package/dist/api/openai-codex-responses.js.map +1 -1
  43. package/dist/api/openai-completions.d.ts.map +1 -1
  44. package/dist/api/openai-completions.js +49 -38
  45. package/dist/api/openai-completions.js.map +1 -1
  46. package/dist/api/openai-decisions.d.ts +4 -0
  47. package/dist/api/openai-decisions.d.ts.map +1 -0
  48. package/dist/api/openai-decisions.js +162 -0
  49. package/dist/api/openai-decisions.js.map +1 -0
  50. package/dist/api/openai-decisions.lazy.d.ts +3 -0
  51. package/dist/api/openai-decisions.lazy.d.ts.map +1 -0
  52. package/dist/api/openai-decisions.lazy.js +4 -0
  53. package/dist/api/openai-decisions.lazy.js.map +1 -0
  54. package/dist/api/openai-responses-shared.d.ts +26 -0
  55. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  56. package/dist/api/openai-responses-shared.js +82 -16
  57. package/dist/api/openai-responses-shared.js.map +1 -1
  58. package/dist/api/openai-responses.d.ts.map +1 -1
  59. package/dist/api/openai-responses.js +47 -18
  60. package/dist/api/openai-responses.js.map +1 -1
  61. package/dist/api/openrouter-images.d.ts.map +1 -1
  62. package/dist/api/openrouter-images.js +4 -3
  63. package/dist/api/openrouter-images.js.map +1 -1
  64. package/dist/api/pi-messages.d.ts.map +1 -1
  65. package/dist/api/pi-messages.js +3 -3
  66. package/dist/api/pi-messages.js.map +1 -1
  67. package/dist/api/simple-options.d.ts +2 -1
  68. package/dist/api/simple-options.d.ts.map +1 -1
  69. package/dist/api/simple-options.js +12 -2
  70. package/dist/api/simple-options.js.map +1 -1
  71. package/dist/api/system-one-shared.d.ts +0 -1
  72. package/dist/api/system-one-shared.d.ts.map +1 -1
  73. package/dist/api/system-one-shared.js +5 -89
  74. package/dist/api/system-one-shared.js.map +1 -1
  75. package/dist/api/transform-messages.d.ts +16 -1
  76. package/dist/api/transform-messages.d.ts.map +1 -1
  77. package/dist/api/transform-messages.js +28 -15
  78. package/dist/api/transform-messages.js.map +1 -1
  79. package/dist/api/typesafe-system-one.d.ts.map +1 -1
  80. package/dist/api/typesafe-system-one.js +2 -1
  81. package/dist/api/typesafe-system-one.js.map +1 -1
  82. package/dist/auth/oauth/anthropic.d.ts.map +1 -1
  83. package/dist/auth/oauth/anthropic.js +65 -7
  84. package/dist/auth/oauth/anthropic.js.map +1 -1
  85. package/dist/auth/oauth/load.d.ts +2 -0
  86. package/dist/auth/oauth/load.d.ts.map +1 -1
  87. package/dist/auth/oauth/load.js +5 -0
  88. package/dist/auth/oauth/load.js.map +1 -1
  89. package/dist/auth/oauth/openai-chatgpt.d.ts.map +1 -1
  90. package/dist/auth/oauth/openai-chatgpt.js +11 -14
  91. package/dist/auth/oauth/openai-chatgpt.js.map +1 -1
  92. package/dist/auth/oauth/openai-codex.d.ts.map +1 -1
  93. package/dist/auth/oauth/openai-codex.js +7 -5
  94. package/dist/auth/oauth/openai-codex.js.map +1 -1
  95. package/dist/auth/oauth/opencode-go.d.ts +3 -12
  96. package/dist/auth/oauth/opencode-go.d.ts.map +1 -1
  97. package/dist/auth/oauth/opencode-go.js +229 -34
  98. package/dist/auth/oauth/opencode-go.js.map +1 -1
  99. package/dist/auth/resolve.d.ts +16 -1
  100. package/dist/auth/resolve.d.ts.map +1 -1
  101. package/dist/auth/resolve.js +51 -27
  102. package/dist/auth/resolve.js.map +1 -1
  103. package/dist/auth/types.d.ts +5 -0
  104. package/dist/auth/types.d.ts.map +1 -1
  105. package/dist/auth/types.js.map +1 -1
  106. package/dist/bun-oauth.d.ts.map +1 -1
  107. package/dist/bun-oauth.js +2 -1
  108. package/dist/bun-oauth.js.map +1 -1
  109. package/dist/env-api-keys.js +1 -1
  110. package/dist/env-api-keys.js.map +1 -1
  111. package/dist/index.d.ts +2 -1
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +2 -1
  114. package/dist/index.js.map +1 -1
  115. package/dist/models.d.ts +9 -0
  116. package/dist/models.d.ts.map +1 -1
  117. package/dist/models.generated.d.ts +4 -4
  118. package/dist/models.generated.d.ts.map +1 -1
  119. package/dist/models.generated.js +4 -4
  120. package/dist/models.generated.js.map +1 -1
  121. package/dist/models.js +26 -14
  122. package/dist/models.js.map +1 -1
  123. package/dist/providers/all.js +2 -2
  124. package/dist/providers/all.js.map +1 -1
  125. package/dist/providers/azure.d.ts +3 -0
  126. package/dist/providers/azure.d.ts.map +1 -0
  127. package/dist/providers/azure.js +46 -0
  128. package/dist/providers/azure.js.map +1 -0
  129. package/dist/providers/azure.models.d.ts +6 -0
  130. package/dist/providers/azure.models.d.ts.map +1 -0
  131. package/dist/providers/azure.models.js +8 -0
  132. package/dist/providers/azure.models.js.map +1 -0
  133. package/dist/providers/compat-schema.d.ts +491 -0
  134. package/dist/providers/compat-schema.d.ts.map +1 -0
  135. package/dist/providers/compat-schema.js +386 -0
  136. package/dist/providers/compat-schema.js.map +1 -0
  137. package/dist/providers/data/.manifest.json +1 -1
  138. package/dist/providers/data/amazon-bedrock.json +1 -1
  139. package/dist/providers/data/anthropic.json +1 -1
  140. package/dist/providers/data/azure.json +1 -0
  141. package/dist/providers/data/baseten.json +1 -1
  142. package/dist/providers/data/cerebras.json +1 -1
  143. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  144. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  145. package/dist/providers/data/fireworks.json +1 -1
  146. package/dist/providers/data/github-copilot.json +1 -1
  147. package/dist/providers/data/google-vertex.json +1 -1
  148. package/dist/providers/data/google.json +1 -1
  149. package/dist/providers/data/groq.json +1 -1
  150. package/dist/providers/data/huggingface.json +1 -1
  151. package/dist/providers/data/kimi-coding.json +1 -1
  152. package/dist/providers/data/meta.json +1 -1
  153. package/dist/providers/data/minimax-cn.json +1 -1
  154. package/dist/providers/data/minimax.json +1 -1
  155. package/dist/providers/data/mistral.json +1 -1
  156. package/dist/providers/data/moonshotai-cn.json +1 -1
  157. package/dist/providers/data/nvidia.json +1 -1
  158. package/dist/providers/data/openai-codex.json +1 -1
  159. package/dist/providers/data/openai.json +1 -1
  160. package/dist/providers/data/opencode-go.json +1 -1
  161. package/dist/providers/data/opencode.json +1 -1
  162. package/dist/providers/data/openrouter.json +1 -1
  163. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  164. package/dist/providers/data/qwen-token-plan.json +1 -1
  165. package/dist/providers/data/radius.json +1 -1
  166. package/dist/providers/data/together.json +1 -1
  167. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  168. package/dist/providers/data/xai.json +1 -1
  169. package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  170. package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  171. package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  172. package/dist/providers/data/xiaomi.json +1 -1
  173. package/dist/providers/data/zai-coding-cn.json +1 -1
  174. package/dist/providers/faux.d.ts.map +1 -1
  175. package/dist/providers/faux.js +25 -8
  176. package/dist/providers/faux.js.map +1 -1
  177. package/dist/providers/kimi-coding.d.ts +1 -1
  178. package/dist/providers/kimi-coding.js +3 -3
  179. package/dist/providers/kimi-coding.js.map +1 -1
  180. package/dist/providers/model-schema.d.ts +91 -0
  181. package/dist/providers/model-schema.d.ts.map +1 -0
  182. package/dist/providers/model-schema.js +57 -0
  183. package/dist/providers/model-schema.js.map +1 -0
  184. package/dist/providers/openai.d.ts.map +1 -1
  185. package/dist/providers/openai.js +12 -3
  186. package/dist/providers/openai.js.map +1 -1
  187. package/dist/providers/opencode-go.d.ts +3 -1
  188. package/dist/providers/opencode-go.d.ts.map +1 -1
  189. package/dist/providers/opencode-go.js +4 -3
  190. package/dist/providers/opencode-go.js.map +1 -1
  191. package/dist/providers/opencode.d.ts.map +1 -1
  192. package/dist/providers/opencode.js +10 -2
  193. package/dist/providers/opencode.js.map +1 -1
  194. package/dist/providers/openrouter-api.d.ts +40 -0
  195. package/dist/providers/openrouter-api.d.ts.map +1 -0
  196. package/dist/providers/openrouter-api.js +41 -0
  197. package/dist/providers/openrouter-api.js.map +1 -0
  198. package/dist/providers/openrouter.d.ts +11 -1
  199. package/dist/providers/openrouter.d.ts.map +1 -1
  200. package/dist/providers/openrouter.js +52 -1
  201. package/dist/providers/openrouter.js.map +1 -1
  202. package/dist/providers/radius.d.ts.map +1 -1
  203. package/dist/providers/radius.js +4 -12
  204. package/dist/providers/radius.js.map +1 -1
  205. package/dist/telemetry.d.ts +288 -0
  206. package/dist/telemetry.d.ts.map +1 -0
  207. package/dist/telemetry.js +191 -0
  208. package/dist/telemetry.js.map +1 -0
  209. package/dist/types.d.ts +42 -310
  210. package/dist/types.d.ts.map +1 -1
  211. package/dist/types.js.map +1 -1
  212. package/dist/utils/estimate.js +1 -1
  213. package/dist/utils/estimate.js.map +1 -1
  214. package/dist/utils/event-stream.d.ts +10 -1
  215. package/dist/utils/event-stream.d.ts.map +1 -1
  216. package/dist/utils/event-stream.js +25 -0
  217. package/dist/utils/event-stream.js.map +1 -1
  218. package/dist/utils/identity.d.ts +65 -0
  219. package/dist/utils/identity.d.ts.map +1 -0
  220. package/dist/utils/identity.js +145 -0
  221. package/dist/utils/identity.js.map +1 -0
  222. package/dist/utils/json-parse.d.ts +10 -0
  223. package/dist/utils/json-parse.d.ts.map +1 -1
  224. package/dist/utils/json-parse.js +26 -1
  225. package/dist/utils/json-parse.js.map +1 -1
  226. package/dist/utils/model-operations.d.ts +3 -1
  227. package/dist/utils/model-operations.d.ts.map +1 -1
  228. package/dist/utils/model-operations.js +6 -0
  229. package/dist/utils/model-operations.js.map +1 -1
  230. package/dist/utils/overflow.d.ts +1 -0
  231. package/dist/utils/overflow.d.ts.map +1 -1
  232. package/dist/utils/overflow.js +6 -1
  233. package/dist/utils/overflow.js.map +1 -1
  234. package/dist/utils/provider-retry.d.ts +2 -0
  235. package/dist/utils/provider-retry.d.ts.map +1 -1
  236. package/dist/utils/provider-retry.js +2 -0
  237. package/dist/utils/provider-retry.js.map +1 -1
  238. package/dist/utils/retry.d.ts.map +1 -1
  239. package/dist/utils/retry.js +30 -10
  240. package/dist/utils/retry.js.map +1 -1
  241. package/dist/utils/transcript.d.ts +27 -10
  242. package/dist/utils/transcript.d.ts.map +1 -1
  243. package/dist/utils/transcript.js +34 -20
  244. package/dist/utils/transcript.js.map +1 -1
  245. package/dist/utils/validation.d.ts.map +1 -1
  246. package/dist/utils/validation.js +3 -0
  247. package/dist/utils/validation.js.map +1 -1
  248. package/dist/utils/version.d.ts +2 -0
  249. package/dist/utils/version.d.ts.map +1 -0
  250. package/dist/utils/version.js +5 -0
  251. package/dist/utils/version.js.map +1 -0
  252. package/package.json +5 -5
  253. package/dist/providers/azure-openai-responses.d.ts +0 -3
  254. package/dist/providers/azure-openai-responses.d.ts.map +0 -1
  255. package/dist/providers/azure-openai-responses.js +0 -14
  256. package/dist/providers/azure-openai-responses.js.map +0 -1
  257. package/dist/providers/azure-openai-responses.models.d.ts +0 -6
  258. package/dist/providers/azure-openai-responses.models.d.ts.map +0 -1
  259. package/dist/providers/azure-openai-responses.models.js +0 -8
  260. package/dist/providers/azure-openai-responses.models.js.map +0 -1
  261. package/dist/providers/data/azure-openai-responses.json +0 -1
  262. package/dist/utils/assistant-message-frame.d.ts +0 -77
  263. package/dist/utils/assistant-message-frame.d.ts.map +0 -1
  264. package/dist/utils/assistant-message-frame.js +0 -425
  265. package/dist/utils/assistant-message-frame.js.map +0 -1
  266. package/dist/utils/draht-user-agent.d.ts +0 -2
  267. package/dist/utils/draht-user-agent.d.ts.map +0 -1
  268. package/dist/utils/draht-user-agent.js +0 -12
  269. package/dist/utils/draht-user-agent.js.map +0 -1
@@ -0,0 +1,57 @@
1
+ import { Type } from "typebox";
2
+ export const THINKING_LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max"];
3
+ export const MODEL_THINKING_LEVELS = ["off", ...THINKING_LEVELS];
4
+ export const MODEL_INPUT_MODALITIES = ["text", "image"];
5
+ export const CACHE_RETENTIONS = ["none", "short", "long"];
6
+ export const MODEL_PROMPT_CACHE_RETENTIONS = ["short", "long"];
7
+ export const ThinkingLevelSchema = Type.Enum(THINKING_LEVELS);
8
+ export const ModelThinkingLevelSchema = Type.Enum(MODEL_THINKING_LEVELS);
9
+ export const ModelInputModalitySchema = Type.Enum(MODEL_INPUT_MODALITIES);
10
+ export const CacheRetentionSchema = Type.Enum(CACHE_RETENTIONS);
11
+ const ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);
12
+ export const ThinkingLevelMapSchema = Type.Partial(Type.Record(ModelThinkingLevelSchema, ThinkingLevelMapValueSchema), {
13
+ description: "Provider value sent for each thinking level. null marks a level unsupported. Levels the model does not map use the provider's default value through high; xhigh and max are unsupported.",
14
+ });
15
+ export const ModelPromptCacheSchema = Type.Partial(Type.Record(Type.Enum(MODEL_PROMPT_CACHE_RETENTIONS), Type.Number({ exclusiveMinimum: 0 })), {
16
+ description: "Best-effort prompt cache lifetime in seconds for the short and long retention tiers. draht warms only tiers with a known lifetime.",
17
+ });
18
+ const ModelCostRatesProperties = {
19
+ input: Type.Number({ description: "Input cost in USD per million tokens." }),
20
+ output: Type.Number({ description: "Output cost in USD per million tokens." }),
21
+ cacheRead: Type.Number({ description: "Cache-read cost in USD per million tokens." }),
22
+ cacheWrite: Type.Number({ description: "Cache-write cost in USD per million tokens." }),
23
+ };
24
+ export const ModelCostRatesSchema = Type.Object(ModelCostRatesProperties);
25
+ export const ModelCostTierSchema = Type.Object({
26
+ inputTokensAbove: Type.Number({
27
+ description: "Use this tier when total request input exceeds this token count.",
28
+ }),
29
+ ...ModelCostRatesProperties,
30
+ });
31
+ export const ModelCostSchema = Type.Object({
32
+ ...ModelCostRatesProperties,
33
+ tiers: Type.Optional(Type.Array(ModelCostTierSchema, {
34
+ description: "Request-wide pricing tiers. The highest matching input threshold applies to the full request.",
35
+ })),
36
+ });
37
+ function modelImageResizeOptions(options) {
38
+ return Type.Object({
39
+ maxWidth: Type.Optional(Type.Integer({ minimum: 1 })),
40
+ maxHeight: Type.Optional(Type.Integer({ minimum: 1 })),
41
+ maxBytes: Type.Optional(Type.Integer({ minimum: 1, description: "Maximum base64-encoded payload size in bytes." })),
42
+ jpegQuality: Type.Optional(Type.Integer({ minimum: 1, maximum: 100 })),
43
+ }, options);
44
+ }
45
+ export const ModelImageResizeOptionsSchema = modelImageResizeOptions();
46
+ export const ModelImageInputLimitsSchema = Type.Object({
47
+ resize: Type.Optional(modelImageResizeOptions({
48
+ description: "Cache-safe resize profile applied before a new image enters conversation history.",
49
+ })),
50
+ maxPerMessage: Type.Optional(Type.Integer({ minimum: 1, description: "Maximum images accepted in one provider message." })),
51
+ maxPerRequest: Type.Optional(Type.Integer({ minimum: 1, description: "Maximum images accepted across one provider request." })),
52
+ });
53
+ export const ModelInputLimitsSchema = Type.Object({
54
+ maxRequestBytes: Type.Optional(Type.Integer({ minimum: 1, description: "Maximum serialized provider request size in bytes." })),
55
+ images: Type.Optional(ModelImageInputLimitsSchema),
56
+ });
57
+ //# sourceMappingURL=model-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-schema.js","sourceRoot":"","sources":["../../src/providers/model-schema.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Static, type TSchemaOptions, Type } from \"typebox\";\n\nexport const THINKING_LEVELS = [\"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\nexport const MODEL_THINKING_LEVELS = [\"off\", ...THINKING_LEVELS] as const;\nexport const MODEL_INPUT_MODALITIES = [\"text\", \"image\"] as const;\nexport const CACHE_RETENTIONS = [\"none\", \"short\", \"long\"] as const;\nexport const MODEL_PROMPT_CACHE_RETENTIONS = [\"short\", \"long\"] as const;\n\nexport const ThinkingLevelSchema = Type.Enum(THINKING_LEVELS);\nexport const ModelThinkingLevelSchema = Type.Enum(MODEL_THINKING_LEVELS);\nexport const ModelInputModalitySchema = Type.Enum(MODEL_INPUT_MODALITIES);\nexport const CacheRetentionSchema = Type.Enum(CACHE_RETENTIONS);\n\nconst ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);\nexport const ThinkingLevelMapSchema = Type.Partial(Type.Record(ModelThinkingLevelSchema, ThinkingLevelMapValueSchema), {\n\tdescription:\n\t\t\"Provider value sent for each thinking level. null marks a level unsupported. Levels the model does not map use the provider's default value through high; xhigh and max are unsupported.\",\n});\n\nexport const ModelPromptCacheSchema = Type.Partial(\n\tType.Record(Type.Enum(MODEL_PROMPT_CACHE_RETENTIONS), Type.Number({ exclusiveMinimum: 0 })),\n\t{\n\t\tdescription:\n\t\t\t\"Best-effort prompt cache lifetime in seconds for the short and long retention tiers. draht warms only tiers with a known lifetime.\",\n\t},\n);\n\nconst ModelCostRatesProperties = {\n\tinput: Type.Number({ description: \"Input cost in USD per million tokens.\" }),\n\toutput: Type.Number({ description: \"Output cost in USD per million tokens.\" }),\n\tcacheRead: Type.Number({ description: \"Cache-read cost in USD per million tokens.\" }),\n\tcacheWrite: Type.Number({ description: \"Cache-write cost in USD per million tokens.\" }),\n};\n\nexport const ModelCostRatesSchema = Type.Object(ModelCostRatesProperties);\nexport const ModelCostTierSchema = Type.Object({\n\tinputTokensAbove: Type.Number({\n\t\tdescription: \"Use this tier when total request input exceeds this token count.\",\n\t}),\n\t...ModelCostRatesProperties,\n});\nexport const ModelCostSchema = Type.Object({\n\t...ModelCostRatesProperties,\n\ttiers: Type.Optional(\n\t\tType.Array(ModelCostTierSchema, {\n\t\t\tdescription: \"Request-wide pricing tiers. The highest matching input threshold applies to the full request.\",\n\t\t}),\n\t),\n});\n\nfunction modelImageResizeOptions(options?: TSchemaOptions) {\n\treturn Type.Object(\n\t\t{\n\t\t\tmaxWidth: Type.Optional(Type.Integer({ minimum: 1 })),\n\t\t\tmaxHeight: Type.Optional(Type.Integer({ minimum: 1 })),\n\t\t\tmaxBytes: Type.Optional(\n\t\t\t\tType.Integer({ minimum: 1, description: \"Maximum base64-encoded payload size in bytes.\" }),\n\t\t\t),\n\t\t\tjpegQuality: Type.Optional(Type.Integer({ minimum: 1, maximum: 100 })),\n\t\t},\n\t\toptions,\n\t);\n}\n\nexport const ModelImageResizeOptionsSchema = modelImageResizeOptions();\n\nexport const ModelImageInputLimitsSchema = Type.Object({\n\tresize: Type.Optional(\n\t\tmodelImageResizeOptions({\n\t\t\tdescription: \"Cache-safe resize profile applied before a new image enters conversation history.\",\n\t\t}),\n\t),\n\tmaxPerMessage: Type.Optional(\n\t\tType.Integer({ minimum: 1, description: \"Maximum images accepted in one provider message.\" }),\n\t),\n\tmaxPerRequest: Type.Optional(\n\t\tType.Integer({ minimum: 1, description: \"Maximum images accepted across one provider request.\" }),\n\t),\n});\n\nexport const ModelInputLimitsSchema = Type.Object({\n\tmaxRequestBytes: Type.Optional(\n\t\tType.Integer({ minimum: 1, description: \"Maximum serialized provider request size in bytes.\" }),\n\t),\n\timages: Type.Optional(ModelImageInputLimitsSchema),\n});\n\nexport type ThinkingLevel = Static<typeof ThinkingLevelSchema>;\nexport type ModelThinkingLevel = Static<typeof ModelThinkingLevelSchema>;\nexport type ThinkingLevelMap = Static<typeof ThinkingLevelMapSchema>;\nexport type ModelInputModality = Static<typeof ModelInputModalitySchema>;\nexport type CacheRetention = Static<typeof CacheRetentionSchema>;\nexport type ModelPromptCache = Static<typeof ModelPromptCacheSchema>;\nexport type ModelCostRates = Static<typeof ModelCostRatesSchema>;\nexport type ModelCostTier = Static<typeof ModelCostTierSchema>;\nexport type ModelCost = Static<typeof ModelCostSchema>;\nexport type ModelImageResizeOptions = Static<typeof ModelImageResizeOptionsSchema>;\nexport type ModelImageInputLimits = Static<typeof ModelImageInputLimitsSchema>;\nexport type ModelInputLimits = Static<typeof ModelInputLimitsSchema>;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7D,wBAAgB,cAAc,IAAI,QAAQ,CAAC,kBAAkB,CAAC,CAiB7D"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAIA,OAAO,EAA+B,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI1E,wBAAgB,cAAc,IAAI,QAAQ,CAAC,kBAAkB,CAAC,CA0B7D"}
@@ -1,8 +1,9 @@
1
+ import { openAIDecisionsApi } from "../api/openai-decisions.lazy.js";
1
2
  import { openAIResponsesApi } from "../api/openai-responses.lazy.js";
2
3
  import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.js";
3
4
  import { loadOpenAIChatGPTOAuth } from "../auth/oauth/load.js";
4
- import { createProvider } from "../models.js";
5
- import { OPENAI_MODELS } from "./openai.models.js";
5
+ import { createProvider, isModelType } from "../models.js";
6
+ import { OPENAI_CLASSIFIER_MODELS, OPENAI_MODELS } from "./openai.models.js";
6
7
  export function openaiProvider() {
7
8
  return createProvider({
8
9
  id: "openai",
@@ -17,8 +18,16 @@ export function openaiProvider() {
17
18
  load: loadOpenAIChatGPTOAuth,
18
19
  }),
19
20
  },
20
- models: Object.values(OPENAI_MODELS),
21
+ models: [
22
+ ...Object.values(OPENAI_MODELS),
23
+ ...Object.values(OPENAI_CLASSIFIER_MODELS),
24
+ ],
25
+ // Sign in with ChatGPT tokens only reach the Responses API; the Decisions API rejects them.
26
+ filterAllModels: (models, credential) => credential?.type === "oauth" ? models.filter((model) => !isModelType(model, "classifier")) : models,
21
27
  api: openAIResponsesApi(),
28
+ classifiers: {
29
+ "openai-decisions": openAIDecisionsApi(),
30
+ },
22
31
  });
23
32
  }
24
33
  //# sourceMappingURL=openai.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,UAAU,cAAc;IAC7B,OAAO,cAAc,CAAC;QACrB,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,2BAA2B;QACpC,IAAI,EAAE;YACL,MAAM,EAAE,aAAa,CAAC,gBAAgB,EAAE,CAAC,gBAAgB,CAAC,CAAC;YAC3D,KAAK,EAAE,SAAS,CAAC;gBAChB,IAAI,EAAE,+BAA+B;gBACrC,cAAc,EAAE,IAAI;gBACpB,UAAU,EAAE,sBAAsB;gBAClC,IAAI,EAAE,sBAAsB;aAC5B,CAAC;SACF;QACD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC;QACpC,GAAG,EAAE,kBAAkB,EAAE;KACzB,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { openAIResponsesApi } from \"../api/openai-responses.lazy.ts\";\nimport { envApiKeyAuth, lazyOAuth } from \"../auth/helpers.ts\";\nimport { loadOpenAIChatGPTOAuth } from \"../auth/oauth/load.ts\";\nimport { createProvider, type Provider } from \"../models.ts\";\nimport { OPENAI_MODELS } from \"./openai.models.ts\";\n\nexport function openaiProvider(): Provider<\"openai-responses\"> {\n\treturn createProvider({\n\t\tid: \"openai\",\n\t\tname: \"OpenAI\",\n\t\tbaseUrl: \"https://api.openai.com/v1\",\n\t\tauth: {\n\t\t\tapiKey: envApiKeyAuth(\"OpenAI API key\", [\"OPENAI_API_KEY\"]),\n\t\t\toauth: lazyOAuth({\n\t\t\t\tname: \"OpenAI (ChatGPT subscription)\",\n\t\t\t\tisSubscription: true,\n\t\t\t\tloginLabel: \"Sign in with ChatGPT\",\n\t\t\t\tload: loadOpenAIChatGPTOAuth,\n\t\t\t}),\n\t\t},\n\t\tmodels: Object.values(OPENAI_MODELS),\n\t\tapi: openAIResponsesApi(),\n\t});\n}\n"]}
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,WAAW,EAAiB,MAAM,cAAc,CAAC;AAE1E,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE7E,MAAM,UAAU,cAAc;IAC7B,OAAO,cAAc,CAAqB;QACzC,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,2BAA2B;QACpC,IAAI,EAAE;YACL,MAAM,EAAE,aAAa,CAAC,gBAAgB,EAAE,CAAC,gBAAgB,CAAC,CAAC;YAC3D,KAAK,EAAE,SAAS,CAAC;gBAChB,IAAI,EAAE,+BAA+B;gBACrC,cAAc,EAAE,IAAI;gBACpB,UAAU,EAAE,sBAAsB;gBAClC,IAAI,EAAE,sBAAsB;aAC5B,CAAC;SACF;QACD,MAAM,EAAE;YACP,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC;YAC/B,GAAG,MAAM,CAAC,MAAM,CAAsC,wBAAwB,CAAC;SAC/E;QACD,4FAA4F;QAC5F,eAAe,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,CACvC,UAAU,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;QACpG,GAAG,EAAE,kBAAkB,EAAE;QACzB,WAAW,EAAE;YACZ,kBAAkB,EAAE,kBAAkB,EAAE;SACxC;KACD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { openAIDecisionsApi } from \"../api/openai-decisions.lazy.ts\";\nimport { openAIResponsesApi } from \"../api/openai-responses.lazy.ts\";\nimport { envApiKeyAuth, lazyOAuth } from \"../auth/helpers.ts\";\nimport { loadOpenAIChatGPTOAuth } from \"../auth/oauth/load.ts\";\nimport { createProvider, isModelType, type Provider } from \"../models.ts\";\nimport type { ClassifierModel } from \"../types.ts\";\nimport { OPENAI_CLASSIFIER_MODELS, OPENAI_MODELS } from \"./openai.models.ts\";\n\nexport function openaiProvider(): Provider<\"openai-responses\"> {\n\treturn createProvider<\"openai-responses\">({\n\t\tid: \"openai\",\n\t\tname: \"OpenAI\",\n\t\tbaseUrl: \"https://api.openai.com/v1\",\n\t\tauth: {\n\t\t\tapiKey: envApiKeyAuth(\"OpenAI API key\", [\"OPENAI_API_KEY\"]),\n\t\t\toauth: lazyOAuth({\n\t\t\t\tname: \"OpenAI (ChatGPT subscription)\",\n\t\t\t\tisSubscription: true,\n\t\t\t\tloginLabel: \"Sign in with ChatGPT\",\n\t\t\t\tload: loadOpenAIChatGPTOAuth,\n\t\t\t}),\n\t\t},\n\t\tmodels: [\n\t\t\t...Object.values(OPENAI_MODELS),\n\t\t\t...Object.values<ClassifierModel<\"openai-decisions\">>(OPENAI_CLASSIFIER_MODELS),\n\t\t],\n\t\t// Sign in with ChatGPT tokens only reach the Responses API; the Decisions API rejects them.\n\t\tfilterAllModels: (models, credential) =>\n\t\t\tcredential?.type === \"oauth\" ? models.filter((model) => !isModelType(model, \"classifier\")) : models,\n\t\tapi: openAIResponsesApi(),\n\t\tclassifiers: {\n\t\t\t\"openai-decisions\": openAIDecisionsApi(),\n\t\t},\n\t});\n}\n"]}
@@ -1,3 +1,5 @@
1
1
  import { type Provider } from "../models.ts";
2
- export declare function opencodeGoProvider(): Provider<"anthropic-messages" | "openai-completions" | "openai-responses">;
2
+ type OpenCodeGoApi = "anthropic-messages" | "google-generative-ai" | "openai-completions" | "openai-responses";
3
+ export declare function opencodeGoProvider(): Provider<OpenCodeGoApi>;
4
+ export {};
3
5
  //# sourceMappingURL=opencode-go.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"opencode-go.d.ts","sourceRoot":"","sources":["../../src/providers/opencode-go.ts"],"names":[],"mappings":"AAKA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7D,wBAAgB,kBAAkB,IAAI,QAAQ,CAAC,oBAAoB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC,CAqB/G"}
1
+ {"version":3,"file":"opencode-go.d.ts","sourceRoot":"","sources":["../../src/providers/opencode-go.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7D,KAAK,aAAa,GAAG,oBAAoB,GAAG,sBAAsB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AAE/G,wBAAgB,kBAAkB,IAAI,QAAQ,CAAC,aAAa,CAAC,CAqB5D"}
@@ -1,4 +1,5 @@
1
1
  import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.js";
2
+ import { googleGenerativeAIApi } from "../api/google-generative-ai.lazy.js";
2
3
  import { openAICompletionsApi } from "../api/openai-completions.lazy.js";
3
4
  import { openAIResponsesApi } from "../api/openai-responses.lazy.js";
4
5
  import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.js";
@@ -12,17 +13,17 @@ export function opencodeGoProvider() {
12
13
  name: "OpenCode Go",
13
14
  auth: {
14
15
  apiKey: envApiKeyAuth("OpenCode API key", ["OPENCODE_API_KEY"]),
15
- // draht-only OAuth flow. Upstream deleted the runtime registry that used to make
16
- // this reachable, so the provider must declare it directly (mirrors xai.ts).
17
16
  oauth: lazyOAuth({
18
17
  name: "OpenCode Go",
19
- loginLabel: "Paste an OpenCode Zen API key",
18
+ isSubscription: true,
19
+ loginLabel: "Sign in with OpenCode Console",
20
20
  load: loadOpenCodeGoOAuth,
21
21
  }),
22
22
  },
23
23
  models: Object.values(OPENCODE_GO_MODELS),
24
24
  api: {
25
25
  "anthropic-messages": withOpenCodeSessionHeader(anthropicMessagesApi()),
26
+ "google-generative-ai": withOpenCodeSessionHeader(googleGenerativeAIApi()),
26
27
  "openai-completions": withOpenCodeSessionHeader(openAICompletionsApi()),
27
28
  "openai-responses": withOpenCodeSessionHeader(openAIResponsesApi()),
28
29
  },
@@ -1 +1 @@
1
- {"version":3,"file":"opencode-go.js","sourceRoot":"","sources":["../../src/providers/opencode-go.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,UAAU,kBAAkB;IACjC,OAAO,cAAc,CAAmE;QACvF,EAAE,EAAE,aAAa;QACjB,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE;YACL,MAAM,EAAE,aAAa,CAAC,kBAAkB,EAAE,CAAC,kBAAkB,CAAC,CAAC;YAC/D,iFAAiF;YACjF,6EAA6E;YAC7E,KAAK,EAAE,SAAS,CAAC;gBAChB,IAAI,EAAE,aAAa;gBACnB,UAAU,EAAE,+BAA+B;gBAC3C,IAAI,EAAE,mBAAmB;aACzB,CAAC;SACF;QACD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC;QACzC,GAAG,EAAE;YACJ,oBAAoB,EAAE,yBAAyB,CAAC,oBAAoB,EAAE,CAAC;YACvE,oBAAoB,EAAE,yBAAyB,CAAC,oBAAoB,EAAE,CAAC;YACvE,kBAAkB,EAAE,yBAAyB,CAAC,kBAAkB,EAAE,CAAC;SACnE;KACD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { anthropicMessagesApi } from \"../api/anthropic-messages.lazy.ts\";\nimport { openAICompletionsApi } from \"../api/openai-completions.lazy.ts\";\nimport { openAIResponsesApi } from \"../api/openai-responses.lazy.ts\";\nimport { envApiKeyAuth, lazyOAuth } from \"../auth/helpers.ts\";\nimport { loadOpenCodeGoOAuth } from \"../auth/oauth/load.ts\";\nimport { createProvider, type Provider } from \"../models.ts\";\nimport { OPENCODE_GO_MODELS } from \"./opencode-go.models.ts\";\nimport { withOpenCodeSessionHeader } from \"./opencode-headers.ts\";\n\nexport function opencodeGoProvider(): Provider<\"anthropic-messages\" | \"openai-completions\" | \"openai-responses\"> {\n\treturn createProvider<\"anthropic-messages\" | \"openai-completions\" | \"openai-responses\">({\n\t\tid: \"opencode-go\",\n\t\tname: \"OpenCode Go\",\n\t\tauth: {\n\t\t\tapiKey: envApiKeyAuth(\"OpenCode API key\", [\"OPENCODE_API_KEY\"]),\n\t\t\t// draht-only OAuth flow. Upstream deleted the runtime registry that used to make\n\t\t\t// this reachable, so the provider must declare it directly (mirrors xai.ts).\n\t\t\toauth: lazyOAuth({\n\t\t\t\tname: \"OpenCode Go\",\n\t\t\t\tloginLabel: \"Paste an OpenCode Zen API key\",\n\t\t\t\tload: loadOpenCodeGoOAuth,\n\t\t\t}),\n\t\t},\n\t\tmodels: Object.values(OPENCODE_GO_MODELS),\n\t\tapi: {\n\t\t\t\"anthropic-messages\": withOpenCodeSessionHeader(anthropicMessagesApi()),\n\t\t\t\"openai-completions\": withOpenCodeSessionHeader(openAICompletionsApi()),\n\t\t\t\"openai-responses\": withOpenCodeSessionHeader(openAIResponsesApi()),\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"opencode-go.js","sourceRoot":"","sources":["../../src/providers/opencode-go.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAIlE,MAAM,UAAU,kBAAkB;IACjC,OAAO,cAAc,CAAgB;QACpC,EAAE,EAAE,aAAa;QACjB,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE;YACL,MAAM,EAAE,aAAa,CAAC,kBAAkB,EAAE,CAAC,kBAAkB,CAAC,CAAC;YAC/D,KAAK,EAAE,SAAS,CAAC;gBAChB,IAAI,EAAE,aAAa;gBACnB,cAAc,EAAE,IAAI;gBACpB,UAAU,EAAE,+BAA+B;gBAC3C,IAAI,EAAE,mBAAmB;aACzB,CAAC;SACF;QACD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC;QACzC,GAAG,EAAE;YACJ,oBAAoB,EAAE,yBAAyB,CAAC,oBAAoB,EAAE,CAAC;YACvE,sBAAsB,EAAE,yBAAyB,CAAC,qBAAqB,EAAE,CAAC;YAC1E,oBAAoB,EAAE,yBAAyB,CAAC,oBAAoB,EAAE,CAAC;YACvE,kBAAkB,EAAE,yBAAyB,CAAC,kBAAkB,EAAE,CAAC;SACnE;KACD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { anthropicMessagesApi } from \"../api/anthropic-messages.lazy.ts\";\nimport { googleGenerativeAIApi } from \"../api/google-generative-ai.lazy.ts\";\nimport { openAICompletionsApi } from \"../api/openai-completions.lazy.ts\";\nimport { openAIResponsesApi } from \"../api/openai-responses.lazy.ts\";\nimport { envApiKeyAuth, lazyOAuth } from \"../auth/helpers.ts\";\nimport { loadOpenCodeGoOAuth } from \"../auth/oauth/load.ts\";\nimport { createProvider, type Provider } from \"../models.ts\";\nimport { OPENCODE_GO_MODELS } from \"./opencode-go.models.ts\";\nimport { withOpenCodeSessionHeader } from \"./opencode-headers.ts\";\n\ntype OpenCodeGoApi = \"anthropic-messages\" | \"google-generative-ai\" | \"openai-completions\" | \"openai-responses\";\n\nexport function opencodeGoProvider(): Provider<OpenCodeGoApi> {\n\treturn createProvider<OpenCodeGoApi>({\n\t\tid: \"opencode-go\",\n\t\tname: \"OpenCode Go\",\n\t\tauth: {\n\t\t\tapiKey: envApiKeyAuth(\"OpenCode API key\", [\"OPENCODE_API_KEY\"]),\n\t\t\toauth: lazyOAuth({\n\t\t\t\tname: \"OpenCode Go\",\n\t\t\t\tisSubscription: true,\n\t\t\t\tloginLabel: \"Sign in with OpenCode Console\",\n\t\t\t\tload: loadOpenCodeGoOAuth,\n\t\t\t}),\n\t\t},\n\t\tmodels: Object.values(OPENCODE_GO_MODELS),\n\t\tapi: {\n\t\t\t\"anthropic-messages\": withOpenCodeSessionHeader(anthropicMessagesApi()),\n\t\t\t\"google-generative-ai\": withOpenCodeSessionHeader(googleGenerativeAIApi()),\n\t\t\t\"openai-completions\": withOpenCodeSessionHeader(openAICompletionsApi()),\n\t\t\t\"openai-responses\": withOpenCodeSessionHeader(openAIResponsesApi()),\n\t\t},\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../src/providers/opencode.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7D,KAAK,WAAW,GAAG,oBAAoB,GAAG,sBAAsB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AAE7G,wBAAgB,gBAAgB,IAAI,QAAQ,CAAC,WAAW,CAAC,CAexD"}
1
+ {"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../src/providers/opencode.ts"],"names":[],"mappings":"AAOA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7D,KAAK,WAAW,GAAG,oBAAoB,GAAG,sBAAsB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AAE7G,wBAAgB,gBAAgB,IAAI,QAAQ,CAAC,WAAW,CAAC,CAsBxD"}
@@ -3,7 +3,8 @@ import { googleGenerativeAIApi } from "../api/google-generative-ai.lazy.js";
3
3
  import { openAICompletionsApi } from "../api/openai-completions.lazy.js";
4
4
  import { openAIResponsesApi } from "../api/openai-responses.lazy.js";
5
5
  import { typesafeSystemOneApi } from "../api/typesafe-system-one.lazy.js";
6
- import { envApiKeyAuth } from "../auth/helpers.js";
6
+ import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.js";
7
+ import { loadOpenCodeOAuth } from "../auth/oauth/load.js";
7
8
  import { createProvider } from "../models.js";
8
9
  import { OPENCODE_CLASSIFIER_MODELS, OPENCODE_MODELS } from "./opencode.models.js";
9
10
  import { withOpenCodeSessionHeader } from "./opencode-headers.js";
@@ -11,7 +12,14 @@ export function opencodeProvider() {
11
12
  return createProvider({
12
13
  id: "opencode",
13
14
  name: "OpenCode Zen",
14
- auth: { apiKey: envApiKeyAuth("OpenCode API key", ["OPENCODE_API_KEY"]) },
15
+ auth: {
16
+ apiKey: envApiKeyAuth("OpenCode API key", ["OPENCODE_API_KEY"]),
17
+ oauth: lazyOAuth({
18
+ name: "OpenCode Zen",
19
+ loginLabel: "Sign in with OpenCode Console",
20
+ load: loadOpenCodeOAuth,
21
+ }),
22
+ },
15
23
  models: [...Object.values(OPENCODE_MODELS), ...Object.values(OPENCODE_CLASSIFIER_MODELS)],
16
24
  api: {
17
25
  "anthropic-messages": withOpenCodeSessionHeader(anthropicMessagesApi()),
@@ -1 +1 @@
1
- {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/providers/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAIlE,MAAM,UAAU,gBAAgB;IAC/B,OAAO,cAAc,CAAc;QAClC,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,EAAE,MAAM,EAAE,aAAa,CAAC,kBAAkB,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE;QACzE,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;QACzF,GAAG,EAAE;YACJ,oBAAoB,EAAE,yBAAyB,CAAC,oBAAoB,EAAE,CAAC;YACvE,sBAAsB,EAAE,yBAAyB,CAAC,qBAAqB,EAAE,CAAC;YAC1E,oBAAoB,EAAE,yBAAyB,CAAC,oBAAoB,EAAE,CAAC;YACvE,kBAAkB,EAAE,yBAAyB,CAAC,kBAAkB,EAAE,CAAC;SACnE;QACD,2EAA2E;QAC3E,WAAW,EAAE,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,EAAE;KAC9D,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { anthropicMessagesApi } from \"../api/anthropic-messages.lazy.ts\";\nimport { googleGenerativeAIApi } from \"../api/google-generative-ai.lazy.ts\";\nimport { openAICompletionsApi } from \"../api/openai-completions.lazy.ts\";\nimport { openAIResponsesApi } from \"../api/openai-responses.lazy.ts\";\nimport { typesafeSystemOneApi } from \"../api/typesafe-system-one.lazy.ts\";\nimport { envApiKeyAuth } from \"../auth/helpers.ts\";\nimport { createProvider, type Provider } from \"../models.ts\";\nimport { OPENCODE_CLASSIFIER_MODELS, OPENCODE_MODELS } from \"./opencode.models.ts\";\nimport { withOpenCodeSessionHeader } from \"./opencode-headers.ts\";\n\ntype OpenCodeApi = \"anthropic-messages\" | \"google-generative-ai\" | \"openai-completions\" | \"openai-responses\";\n\nexport function opencodeProvider(): Provider<OpenCodeApi> {\n\treturn createProvider<OpenCodeApi>({\n\t\tid: \"opencode\",\n\t\tname: \"OpenCode Zen\",\n\t\tauth: { apiKey: envApiKeyAuth(\"OpenCode API key\", [\"OPENCODE_API_KEY\"]) },\n\t\tmodels: [...Object.values(OPENCODE_MODELS), ...Object.values(OPENCODE_CLASSIFIER_MODELS)],\n\t\tapi: {\n\t\t\t\"anthropic-messages\": withOpenCodeSessionHeader(anthropicMessagesApi()),\n\t\t\t\"google-generative-ai\": withOpenCodeSessionHeader(googleGenerativeAIApi()),\n\t\t\t\"openai-completions\": withOpenCodeSessionHeader(openAICompletionsApi()),\n\t\t\t\"openai-responses\": withOpenCodeSessionHeader(openAIResponsesApi()),\n\t\t},\n\t\t// OpenCode Zen serves TypeSafe's System One protocol at /zen/v1/systemone.\n\t\tclassifiers: { \"typesafe-system-one\": typesafeSystemOneApi() },\n\t});\n}\n"]}
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/providers/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAIlE,MAAM,UAAU,gBAAgB;IAC/B,OAAO,cAAc,CAAc;QAClC,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE;YACL,MAAM,EAAE,aAAa,CAAC,kBAAkB,EAAE,CAAC,kBAAkB,CAAC,CAAC;YAC/D,KAAK,EAAE,SAAS,CAAC;gBAChB,IAAI,EAAE,cAAc;gBACpB,UAAU,EAAE,+BAA+B;gBAC3C,IAAI,EAAE,iBAAiB;aACvB,CAAC;SACF;QACD,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;QACzF,GAAG,EAAE;YACJ,oBAAoB,EAAE,yBAAyB,CAAC,oBAAoB,EAAE,CAAC;YACvE,sBAAsB,EAAE,yBAAyB,CAAC,qBAAqB,EAAE,CAAC;YAC1E,oBAAoB,EAAE,yBAAyB,CAAC,oBAAoB,EAAE,CAAC;YACvE,kBAAkB,EAAE,yBAAyB,CAAC,kBAAkB,EAAE,CAAC;SACnE;QACD,2EAA2E;QAC3E,WAAW,EAAE,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,EAAE;KAC9D,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { anthropicMessagesApi } from \"../api/anthropic-messages.lazy.ts\";\nimport { googleGenerativeAIApi } from \"../api/google-generative-ai.lazy.ts\";\nimport { openAICompletionsApi } from \"../api/openai-completions.lazy.ts\";\nimport { openAIResponsesApi } from \"../api/openai-responses.lazy.ts\";\nimport { typesafeSystemOneApi } from \"../api/typesafe-system-one.lazy.ts\";\nimport { envApiKeyAuth, lazyOAuth } from \"../auth/helpers.ts\";\nimport { loadOpenCodeOAuth } from \"../auth/oauth/load.ts\";\nimport { createProvider, type Provider } from \"../models.ts\";\nimport { OPENCODE_CLASSIFIER_MODELS, OPENCODE_MODELS } from \"./opencode.models.ts\";\nimport { withOpenCodeSessionHeader } from \"./opencode-headers.ts\";\n\ntype OpenCodeApi = \"anthropic-messages\" | \"google-generative-ai\" | \"openai-completions\" | \"openai-responses\";\n\nexport function opencodeProvider(): Provider<OpenCodeApi> {\n\treturn createProvider<OpenCodeApi>({\n\t\tid: \"opencode\",\n\t\tname: \"OpenCode Zen\",\n\t\tauth: {\n\t\t\tapiKey: envApiKeyAuth(\"OpenCode API key\", [\"OPENCODE_API_KEY\"]),\n\t\t\toauth: lazyOAuth({\n\t\t\t\tname: \"OpenCode Zen\",\n\t\t\t\tloginLabel: \"Sign in with OpenCode Console\",\n\t\t\t\tload: loadOpenCodeOAuth,\n\t\t\t}),\n\t\t},\n\t\tmodels: [...Object.values(OPENCODE_MODELS), ...Object.values(OPENCODE_CLASSIFIER_MODELS)],\n\t\tapi: {\n\t\t\t\"anthropic-messages\": withOpenCodeSessionHeader(anthropicMessagesApi()),\n\t\t\t\"google-generative-ai\": withOpenCodeSessionHeader(googleGenerativeAIApi()),\n\t\t\t\"openai-completions\": withOpenCodeSessionHeader(openAICompletionsApi()),\n\t\t\t\"openai-responses\": withOpenCodeSessionHeader(openAIResponsesApi()),\n\t\t},\n\t\t// OpenCode Zen serves TypeSafe's System One protocol at /zen/v1/systemone.\n\t\tclassifiers: { \"typesafe-system-one\": typesafeSystemOneApi() },\n\t});\n}\n"]}
@@ -0,0 +1,40 @@
1
+ import type { ModelCost } from "../types.ts";
2
+ /** OpenRouter's per-token prices, as decimal strings. */
3
+ export interface OpenRouterPricing {
4
+ prompt?: string;
5
+ completion?: string;
6
+ input_cache_read?: string;
7
+ input_cache_write?: string;
8
+ overrides?: OpenRouterPricingOverride[];
9
+ }
10
+ /**
11
+ * A conditional price. `min_prompt_tokens` selects prompt-length pricing; `utc_*` fields select
12
+ * time-of-day or weekday pricing. Missing rates keep the base price.
13
+ */
14
+ export interface OpenRouterPricingOverride {
15
+ min_prompt_tokens?: number;
16
+ utc_start?: number;
17
+ utc_end?: number;
18
+ utc_days?: string[];
19
+ prompt?: string;
20
+ completion?: string;
21
+ input_cache_read?: string;
22
+ input_cache_write?: string;
23
+ }
24
+ /** The fields draht reads from a model in OpenRouter's `GET /models` and `GET /models/user`. */
25
+ export interface OpenRouterModel {
26
+ id: string;
27
+ context_length?: number | null;
28
+ top_provider?: {
29
+ context_length?: number | null;
30
+ max_completion_tokens?: number | null;
31
+ };
32
+ pricing?: OpenRouterPricing;
33
+ }
34
+ /**
35
+ * Convert OpenRouter's $/token prices to draht's $/1M tokens. Missing, invalid and negative base
36
+ * prices are 0. Prompt-length overrides become request-wide tiers; a rate a tier does not list
37
+ * keeps the base price. Time-of-day overrides are skipped because ModelCost cannot express them.
38
+ */
39
+ export declare function openRouterCost(pricing: OpenRouterPricing | undefined): ModelCost;
40
+ //# sourceMappingURL=openrouter-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter-api.d.ts","sourceRoot":"","sources":["../../src/providers/openrouter-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,aAAa,CAAC;AAE5D,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,yBAAyB,EAAE,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACzC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,gGAAgG;AAChG,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACzF,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAYD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,GAAG,SAAS,CA2BhF"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Convert one $/token price to $/1M tokens. 0 means free. Missing, invalid and negative prices use
3
+ * the fallback: OpenRouter reports -1 for router models such as `openrouter/auto`, whose price
4
+ * depends on the model they pick.
5
+ */
6
+ function perMillion(value, fallback) {
7
+ const perToken = Number.parseFloat(value ?? "");
8
+ return perToken >= 0 ? Number((perToken * 1_000_000).toFixed(6)) : fallback;
9
+ }
10
+ /**
11
+ * Convert OpenRouter's $/token prices to draht's $/1M tokens. Missing, invalid and negative base
12
+ * prices are 0. Prompt-length overrides become request-wide tiers; a rate a tier does not list
13
+ * keeps the base price. Time-of-day overrides are skipped because ModelCost cannot express them.
14
+ */
15
+ export function openRouterCost(pricing) {
16
+ const base = {
17
+ input: perMillion(pricing?.prompt, 0),
18
+ output: perMillion(pricing?.completion, 0),
19
+ cacheRead: perMillion(pricing?.input_cache_read, 0),
20
+ cacheWrite: perMillion(pricing?.input_cache_write, 0),
21
+ };
22
+ const tiers = (pricing?.overrides ?? []).flatMap((override) => {
23
+ if (override.min_prompt_tokens === undefined ||
24
+ override.utc_start !== undefined ||
25
+ override.utc_end !== undefined ||
26
+ override.utc_days !== undefined) {
27
+ return [];
28
+ }
29
+ return [
30
+ {
31
+ inputTokensAbove: override.min_prompt_tokens,
32
+ input: perMillion(override.prompt, base.input),
33
+ output: perMillion(override.completion, base.output),
34
+ cacheRead: perMillion(override.input_cache_read, base.cacheRead),
35
+ cacheWrite: perMillion(override.input_cache_write, base.cacheWrite),
36
+ },
37
+ ];
38
+ });
39
+ return tiers.length > 0 ? { ...base, tiers } : base;
40
+ }
41
+ //# sourceMappingURL=openrouter-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter-api.js","sourceRoot":"","sources":["../../src/providers/openrouter-api.ts"],"names":[],"mappings":"AAkCA;;;;GAIG;AACH,SAAS,UAAU,CAAC,KAAyB,EAAE,QAAgB;IAC9D,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAChD,OAAO,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAAsC;IACpE,MAAM,IAAI,GAAG;QACZ,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACrC,MAAM,EAAE,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;QAC1C,SAAS,EAAE,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACnD,UAAU,EAAE,UAAU,CAAC,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;KACrD,CAAC;IACF,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAmB,EAAE;QAC9E,IACC,QAAQ,CAAC,iBAAiB,KAAK,SAAS;YACxC,QAAQ,CAAC,SAAS,KAAK,SAAS;YAChC,QAAQ,CAAC,OAAO,KAAK,SAAS;YAC9B,QAAQ,CAAC,QAAQ,KAAK,SAAS,EAC9B,CAAC;YACF,OAAO,EAAE,CAAC;QACX,CAAC;QACD,OAAO;YACN;gBACC,gBAAgB,EAAE,QAAQ,CAAC,iBAAiB;gBAC5C,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC;gBAC9C,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;gBACpD,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC;gBAChE,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,UAAU,CAAC;aACnE;SACD,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,CAAC","sourcesContent":["import type { ModelCost, ModelCostTier } from \"../types.ts\";\n\n/** OpenRouter's per-token prices, as decimal strings. */\nexport interface OpenRouterPricing {\n\tprompt?: string;\n\tcompletion?: string;\n\tinput_cache_read?: string;\n\tinput_cache_write?: string;\n\toverrides?: OpenRouterPricingOverride[];\n}\n\n/**\n * A conditional price. `min_prompt_tokens` selects prompt-length pricing; `utc_*` fields select\n * time-of-day or weekday pricing. Missing rates keep the base price.\n */\nexport interface OpenRouterPricingOverride {\n\tmin_prompt_tokens?: number;\n\tutc_start?: number;\n\tutc_end?: number;\n\tutc_days?: string[];\n\tprompt?: string;\n\tcompletion?: string;\n\tinput_cache_read?: string;\n\tinput_cache_write?: string;\n}\n\n/** The fields draht reads from a model in OpenRouter's `GET /models` and `GET /models/user`. */\nexport interface OpenRouterModel {\n\tid: string;\n\tcontext_length?: number | null;\n\ttop_provider?: { context_length?: number | null; max_completion_tokens?: number | null };\n\tpricing?: OpenRouterPricing;\n}\n\n/**\n * Convert one $/token price to $/1M tokens. 0 means free. Missing, invalid and negative prices use\n * the fallback: OpenRouter reports -1 for router models such as `openrouter/auto`, whose price\n * depends on the model they pick.\n */\nfunction perMillion(value: string | undefined, fallback: number): number {\n\tconst perToken = Number.parseFloat(value ?? \"\");\n\treturn perToken >= 0 ? Number((perToken * 1_000_000).toFixed(6)) : fallback;\n}\n\n/**\n * Convert OpenRouter's $/token prices to draht's $/1M tokens. Missing, invalid and negative base\n * prices are 0. Prompt-length overrides become request-wide tiers; a rate a tier does not list\n * keeps the base price. Time-of-day overrides are skipped because ModelCost cannot express them.\n */\nexport function openRouterCost(pricing: OpenRouterPricing | undefined): ModelCost {\n\tconst base = {\n\t\tinput: perMillion(pricing?.prompt, 0),\n\t\toutput: perMillion(pricing?.completion, 0),\n\t\tcacheRead: perMillion(pricing?.input_cache_read, 0),\n\t\tcacheWrite: perMillion(pricing?.input_cache_write, 0),\n\t};\n\tconst tiers = (pricing?.overrides ?? []).flatMap((override): ModelCostTier[] => {\n\t\tif (\n\t\t\toverride.min_prompt_tokens === undefined ||\n\t\t\toverride.utc_start !== undefined ||\n\t\t\toverride.utc_end !== undefined ||\n\t\t\toverride.utc_days !== undefined\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\treturn [\n\t\t\t{\n\t\t\t\tinputTokensAbove: override.min_prompt_tokens,\n\t\t\t\tinput: perMillion(override.prompt, base.input),\n\t\t\t\toutput: perMillion(override.completion, base.output),\n\t\t\t\tcacheRead: perMillion(override.input_cache_read, base.cacheRead),\n\t\t\t\tcacheWrite: perMillion(override.input_cache_write, base.cacheWrite),\n\t\t\t},\n\t\t];\n\t});\n\treturn tiers.length > 0 ? { ...base, tiers } : base;\n}\n"]}
@@ -1,3 +1,13 @@
1
- import { type Provider } from "../models.ts";
1
+ import { type Provider, type RefreshModelsContext } from "../models.ts";
2
+ import type { AnyModel } from "../types.ts";
3
+ /**
4
+ * Restrict an OpenRouter catalog to the chat models the key may use, with the key's limits and
5
+ * prices from `GET /models/user`. Image and classifier models are returned unchanged. A missing
6
+ * limit keeps the catalog value. The request uses the provider's configured base URL, so regional
7
+ * endpoints such as `https://us.openrouter.ai/api/v1` apply their region's filtering. When the
8
+ * endpoint rejects the key (401/403) or does not exist (404), for example with a proxy configured
9
+ * in models.json, the catalog is returned unchanged.
10
+ */
11
+ export declare function personalizeOpenRouterCatalog(catalog: readonly AnyModel[], context: RefreshModelsContext): Promise<readonly AnyModel[]>;
2
12
  export declare function openrouterProvider(): Provider<"anthropic-messages" | "openai-completions">;
3
13
  //# sourceMappingURL=openrouter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7D,wBAAgB,kBAAkB,IAAI,QAAQ,CAAC,oBAAoB,GAAG,oBAAoB,CAAC,CA0B1F"}
1
+ {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQ5C;;;;;;;GAOG;AACH,wBAAsB,4BAA4B,CACjD,OAAO,EAAE,SAAS,QAAQ,EAAE,EAC5B,OAAO,EAAE,oBAAoB,GAC3B,OAAO,CAAC,SAAS,QAAQ,EAAE,CAAC,CAiC9B;AAED,wBAAgB,kBAAkB,IAAI,QAAQ,CAAC,oBAAoB,GAAG,oBAAoB,CAAC,CA0B1F"}
@@ -5,12 +5,63 @@ import { typesafeSystemOneApi } from "../api/typesafe-system-one.lazy.js";
5
5
  import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.js";
6
6
  import { loadOpenRouterOAuth } from "../auth/oauth/load.js";
7
7
  import { createProvider } from "../models.js";
8
+ import { isModelType } from "../utils/model-operations.js";
8
9
  import { OPENROUTER_CLASSIFIER_MODELS, OPENROUTER_IMAGE_MODELS, OPENROUTER_MODELS } from "./openrouter.models.js";
10
+ import { openRouterCost } from "./openrouter-api.js";
11
+ const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
12
+ const OPENROUTER_USER_MODELS_TIMEOUT_MS = 15_000;
13
+ /**
14
+ * Restrict an OpenRouter catalog to the chat models the key may use, with the key's limits and
15
+ * prices from `GET /models/user`. Image and classifier models are returned unchanged. A missing
16
+ * limit keeps the catalog value. The request uses the provider's configured base URL, so regional
17
+ * endpoints such as `https://us.openrouter.ai/api/v1` apply their region's filtering. When the
18
+ * endpoint rejects the key (401/403) or does not exist (404), for example with a proxy configured
19
+ * in models.json, the catalog is returned unchanged.
20
+ */
21
+ export async function personalizeOpenRouterCatalog(catalog, context) {
22
+ const key = context.credential?.type === "oauth" ? context.credential.access : context.credential?.key;
23
+ if (!key)
24
+ return catalog;
25
+ const response = await fetch(`${(context.baseUrl ?? OPENROUTER_BASE_URL).replace(/\/+$/, "")}/models/user`, {
26
+ headers: { accept: "application/json", authorization: `Bearer ${key}` },
27
+ signal: AbortSignal.any([context.signal, AbortSignal.timeout(OPENROUTER_USER_MODELS_TIMEOUT_MS)]),
28
+ });
29
+ if (response.status === 401 || response.status === 403 || response.status === 404)
30
+ return catalog;
31
+ if (!response.ok)
32
+ throw new Error(`OpenRouter model list request failed: ${response.status}`);
33
+ const body = await response.json();
34
+ if (typeof body !== "object" || body === null || !("data" in body) || !Array.isArray(body.data)) {
35
+ throw new Error("Invalid OpenRouter model list response");
36
+ }
37
+ const allowed = new Map();
38
+ for (const entry of body.data) {
39
+ if (typeof entry === "object" && entry !== null && "id" in entry && typeof entry.id === "string") {
40
+ allowed.set(entry.id, entry);
41
+ }
42
+ }
43
+ return catalog.flatMap((model) => {
44
+ if (!isModelType(model, "chat"))
45
+ return [model];
46
+ const entry = allowed.get(model.id);
47
+ if (!entry)
48
+ return [];
49
+ return [
50
+ {
51
+ ...model,
52
+ // `||`: OpenRouter reports a missing limit as absent, null or 0, like the generator's fallback.
53
+ contextWindow: entry.top_provider?.context_length || entry.context_length || model.contextWindow,
54
+ maxTokens: entry.top_provider?.max_completion_tokens || model.maxTokens,
55
+ cost: entry.pricing ? openRouterCost(entry.pricing) : model.cost,
56
+ },
57
+ ];
58
+ });
59
+ }
9
60
  export function openrouterProvider() {
10
61
  return createProvider({
11
62
  id: "openrouter",
12
63
  name: "OpenRouter",
13
- baseUrl: "https://openrouter.ai/api/v1",
64
+ baseUrl: OPENROUTER_BASE_URL,
14
65
  auth: {
15
66
  apiKey: envApiKeyAuth("OpenRouter API key", ["OPENROUTER_API_KEY"]),
16
67
  oauth: lazyOAuth({
@@ -1 +1 @@
1
- {"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAElH,MAAM,UAAU,kBAAkB;IACjC,OAAO,cAAc,CAA8C;QAClE,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,8BAA8B;QACvC,IAAI,EAAE;YACL,MAAM,EAAE,aAAa,CAAC,oBAAoB,EAAE,CAAC,oBAAoB,CAAC,CAAC;YACnE,KAAK,EAAE,SAAS,CAAC;gBAChB,IAAI,EAAE,kBAAkB;gBACxB,UAAU,EAAE,yBAAyB;gBACrC,IAAI,EAAE,mBAAmB;aACzB,CAAC;SACF;QACD,MAAM,EAAE;YACP,GAAG,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC;YACnC,GAAG,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC;YACzC,GAAG,MAAM,CAAC,MAAM,CAAC,4BAA4B,CAAC;SAC9C;QACD,GAAG,EAAE;YACJ,oBAAoB,EAAE,oBAAoB,EAAE;YAC5C,oBAAoB,EAAE,oBAAoB,EAAE;SAC5C;QACD,MAAM,EAAE,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,EAAE;QACtD,yEAAyE;QACzE,WAAW,EAAE,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,EAAE;KAC9D,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { anthropicMessagesApi } from \"../api/anthropic-messages.lazy.ts\";\nimport { openAICompletionsApi } from \"../api/openai-completions.lazy.ts\";\nimport { openrouterImagesApi } from \"../api/openrouter-images.lazy.ts\";\nimport { typesafeSystemOneApi } from \"../api/typesafe-system-one.lazy.ts\";\nimport { envApiKeyAuth, lazyOAuth } from \"../auth/helpers.ts\";\nimport { loadOpenRouterOAuth } from \"../auth/oauth/load.ts\";\nimport { createProvider, type Provider } from \"../models.ts\";\nimport { OPENROUTER_CLASSIFIER_MODELS, OPENROUTER_IMAGE_MODELS, OPENROUTER_MODELS } from \"./openrouter.models.ts\";\n\nexport function openrouterProvider(): Provider<\"anthropic-messages\" | \"openai-completions\"> {\n\treturn createProvider<\"anthropic-messages\" | \"openai-completions\">({\n\t\tid: \"openrouter\",\n\t\tname: \"OpenRouter\",\n\t\tbaseUrl: \"https://openrouter.ai/api/v1\",\n\t\tauth: {\n\t\t\tapiKey: envApiKeyAuth(\"OpenRouter API key\", [\"OPENROUTER_API_KEY\"]),\n\t\t\toauth: lazyOAuth({\n\t\t\t\tname: \"OpenRouter OAuth\",\n\t\t\t\tloginLabel: \"Sign in with OpenRouter\",\n\t\t\t\tload: loadOpenRouterOAuth,\n\t\t\t}),\n\t\t},\n\t\tmodels: [\n\t\t\t...Object.values(OPENROUTER_MODELS),\n\t\t\t...Object.values(OPENROUTER_IMAGE_MODELS),\n\t\t\t...Object.values(OPENROUTER_CLASSIFIER_MODELS),\n\t\t],\n\t\tapi: {\n\t\t\t\"anthropic-messages\": anthropicMessagesApi(),\n\t\t\t\"openai-completions\": openAICompletionsApi(),\n\t\t},\n\t\timages: { \"openrouter-images\": openrouterImagesApi() },\n\t\t// OpenRouter serves TypeSafe's System One protocol at /api/v1/systemone.\n\t\tclassifiers: { \"typesafe-system-one\": typesafeSystemOneApi() },\n\t});\n}\n"]}
1
+ {"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"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","sourcesContent":["import { anthropicMessagesApi } from \"../api/anthropic-messages.lazy.ts\";\nimport { openAICompletionsApi } from \"../api/openai-completions.lazy.ts\";\nimport { openrouterImagesApi } from \"../api/openrouter-images.lazy.ts\";\nimport { typesafeSystemOneApi } from \"../api/typesafe-system-one.lazy.ts\";\nimport { envApiKeyAuth, lazyOAuth } from \"../auth/helpers.ts\";\nimport { loadOpenRouterOAuth } from \"../auth/oauth/load.ts\";\nimport { createProvider, type Provider, type RefreshModelsContext } from \"../models.ts\";\nimport type { AnyModel } from \"../types.ts\";\nimport { isModelType } from \"../utils/model-operations.ts\";\nimport { OPENROUTER_CLASSIFIER_MODELS, OPENROUTER_IMAGE_MODELS, OPENROUTER_MODELS } from \"./openrouter.models.ts\";\nimport { type OpenRouterModel, openRouterCost } from \"./openrouter-api.ts\";\n\nconst OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\";\nconst OPENROUTER_USER_MODELS_TIMEOUT_MS = 15_000;\n\n/**\n * Restrict an OpenRouter catalog to the chat models the key may use, with the key's limits and\n * prices from `GET /models/user`. Image and classifier models are returned unchanged. A missing\n * limit keeps the catalog value. The request uses the provider's configured base URL, so regional\n * endpoints such as `https://us.openrouter.ai/api/v1` apply their region's filtering. When the\n * endpoint rejects the key (401/403) or does not exist (404), for example with a proxy configured\n * in models.json, the catalog is returned unchanged.\n */\nexport async function personalizeOpenRouterCatalog(\n\tcatalog: readonly AnyModel[],\n\tcontext: RefreshModelsContext,\n): Promise<readonly AnyModel[]> {\n\tconst key = context.credential?.type === \"oauth\" ? context.credential.access : context.credential?.key;\n\tif (!key) return catalog;\n\tconst response = await fetch(`${(context.baseUrl ?? OPENROUTER_BASE_URL).replace(/\\/+$/, \"\")}/models/user`, {\n\t\theaders: { accept: \"application/json\", authorization: `Bearer ${key}` },\n\t\tsignal: AbortSignal.any([context.signal, AbortSignal.timeout(OPENROUTER_USER_MODELS_TIMEOUT_MS)]),\n\t});\n\tif (response.status === 401 || response.status === 403 || response.status === 404) return catalog;\n\tif (!response.ok) throw new Error(`OpenRouter model list request failed: ${response.status}`);\n\tconst body: unknown = await response.json();\n\tif (typeof body !== \"object\" || body === null || !(\"data\" in body) || !Array.isArray(body.data)) {\n\t\tthrow new Error(\"Invalid OpenRouter model list response\");\n\t}\n\tconst allowed = new Map<string, OpenRouterModel>();\n\tfor (const entry of body.data as unknown[]) {\n\t\tif (typeof entry === \"object\" && entry !== null && \"id\" in entry && typeof entry.id === \"string\") {\n\t\t\tallowed.set(entry.id, entry as OpenRouterModel);\n\t\t}\n\t}\n\treturn catalog.flatMap((model): AnyModel[] => {\n\t\tif (!isModelType(model, \"chat\")) return [model];\n\t\tconst entry = allowed.get(model.id);\n\t\tif (!entry) return [];\n\t\treturn [\n\t\t\t{\n\t\t\t\t...model,\n\t\t\t\t// `||`: OpenRouter reports a missing limit as absent, null or 0, like the generator's fallback.\n\t\t\t\tcontextWindow: entry.top_provider?.context_length || entry.context_length || model.contextWindow,\n\t\t\t\tmaxTokens: entry.top_provider?.max_completion_tokens || model.maxTokens,\n\t\t\t\tcost: entry.pricing ? openRouterCost(entry.pricing) : model.cost,\n\t\t\t},\n\t\t];\n\t});\n}\n\nexport function openrouterProvider(): Provider<\"anthropic-messages\" | \"openai-completions\"> {\n\treturn createProvider<\"anthropic-messages\" | \"openai-completions\">({\n\t\tid: \"openrouter\",\n\t\tname: \"OpenRouter\",\n\t\tbaseUrl: OPENROUTER_BASE_URL,\n\t\tauth: {\n\t\t\tapiKey: envApiKeyAuth(\"OpenRouter API key\", [\"OPENROUTER_API_KEY\"]),\n\t\t\toauth: lazyOAuth({\n\t\t\t\tname: \"OpenRouter OAuth\",\n\t\t\t\tloginLabel: \"Sign in with OpenRouter\",\n\t\t\t\tload: loadOpenRouterOAuth,\n\t\t\t}),\n\t\t},\n\t\tmodels: [\n\t\t\t...Object.values(OPENROUTER_MODELS),\n\t\t\t...Object.values(OPENROUTER_IMAGE_MODELS),\n\t\t\t...Object.values(OPENROUTER_CLASSIFIER_MODELS),\n\t\t],\n\t\tapi: {\n\t\t\t\"anthropic-messages\": anthropicMessagesApi(),\n\t\t\t\"openai-completions\": openAICompletionsApi(),\n\t\t},\n\t\timages: { \"openrouter-images\": openrouterImagesApi() },\n\t\t// OpenRouter serves TypeSafe's System One protocol at /api/v1/systemone.\n\t\tclassifiers: { \"typesafe-system-one\": typesafeSystemOneApi() },\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"radius.d.ts","sourceRoot":"","sources":["../../src/providers/radius.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAW7C,MAAM,WAAW,qBAAqB;IACrC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,QAAQ,CAAC,aAAa,CAAC,CA0E3F"}
1
+ {"version":3,"file":"radius.d.ts","sourceRoot":"","sources":["../../src/providers/radius.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAW7C,MAAM,WAAW,qBAAqB;IACrC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,QAAQ,CAAC,aAAa,CAAC,CAoE3F"}
@@ -11,7 +11,9 @@ export function radiusProvider(options = {}) {
11
11
  const baselineModels = gateway === normalizeRadiusGatewayUrl(DEFAULT_RADIUS_GATEWAY)
12
12
  ? Object.values(RADIUS_MODELS).map((model) => ({ ...model, provider: id }))
13
13
  : [];
14
- let dynamicModels = getRadiusModels(id, undefined);
14
+ // Gateway catalog for this account. Radius org owners can disable models, so once known it replaces
15
+ // the shipped baseline instead of overlaying it. The baseline only covers the time before any catalog exists.
16
+ let dynamicModels;
15
17
  const streams = piMessagesApi();
16
18
  return {
17
19
  id,
@@ -20,17 +22,7 @@ export function radiusProvider(options = {}) {
20
22
  apiKey: envApiKeyAuth("Radius API key", ["RADIUS_API_KEY"]),
21
23
  oauth: lazyOAuth({ name, load: () => loadRadiusOAuth({ name, gateway }) }),
22
24
  },
23
- getModels: () => {
24
- const merged = [...baselineModels];
25
- for (const model of dynamicModels) {
26
- const index = merged.findIndex((entry) => entry.id === model.id);
27
- if (index >= 0)
28
- merged[index] = model;
29
- else
30
- merged.push(model);
31
- }
32
- return merged;
33
- },
25
+ getModels: () => dynamicModels ?? baselineModels,
34
26
  refreshModels: async (context) => {
35
27
  const stored = context.stored;
36
28
  if (stored) {
@@ -1 +1 @@
1
- {"version":3,"file":"radius.js","sourceRoot":"","sources":["../../src/providers/radius.ts"],"names":[],"mappings":"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","sourcesContent":["import { piMessagesApi } from \"../api/pi-messages.lazy.ts\";\nimport { envApiKeyAuth, lazyOAuth } from \"../auth/helpers.ts\";\nimport { loadRadiusOAuth } from \"../auth/oauth/load.ts\";\nimport type { Provider } from \"../models.ts\";\nimport type { Model } from \"../types.ts\";\nimport { RADIUS_MODELS } from \"./radius.models.ts\";\nimport {\n\tDEFAULT_RADIUS_GATEWAY,\n\tgetRadiusModels,\n\tgetRadiusModelsFromConfig,\n\tloadRadiusGatewayConfig,\n\tnormalizeRadiusGatewayUrl,\n} from \"./radius-config.ts\";\n\nexport interface RadiusProviderOptions {\n\tid?: string;\n\tname?: string;\n\tgateway?: string;\n}\n\n/** Radius gateway provider with a persisted, dynamically refreshed catalog. */\nexport function radiusProvider(options: RadiusProviderOptions = {}): Provider<\"pi-messages\"> {\n\tconst id = options.id ?? \"radius\";\n\tconst name = options.name ?? \"Radius\";\n\tconst gateway = normalizeRadiusGatewayUrl(options.gateway ?? DEFAULT_RADIUS_GATEWAY);\n\tconst baselineModels: Model<\"pi-messages\">[] =\n\t\tgateway === normalizeRadiusGatewayUrl(DEFAULT_RADIUS_GATEWAY)\n\t\t\t? Object.values(RADIUS_MODELS).map((model) => ({ ...model, provider: id }))\n\t\t\t: [];\n\tlet dynamicModels = getRadiusModels(id, undefined);\n\tconst streams = piMessagesApi();\n\n\treturn {\n\t\tid,\n\t\tname,\n\t\tauth: {\n\t\t\tapiKey: envApiKeyAuth(\"Radius API key\", [\"RADIUS_API_KEY\"]),\n\t\t\toauth: lazyOAuth({ name, load: () => loadRadiusOAuth({ name, gateway }) }),\n\t\t},\n\t\tgetModels: () => {\n\t\t\tconst merged = [...baselineModels];\n\t\t\tfor (const model of dynamicModels) {\n\t\t\t\tconst index = merged.findIndex((entry) => entry.id === model.id);\n\t\t\t\tif (index >= 0) merged[index] = model;\n\t\t\t\telse merged.push(model);\n\t\t\t}\n\t\t\treturn merged;\n\t\t},\n\t\trefreshModels: async (context) => {\n\t\t\tconst stored = context.stored;\n\t\t\tif (stored) {\n\t\t\t\tconst restored = stored.models.filter((model) => model.provider === id) as typeof dynamicModels;\n\t\t\t\tif (\n\t\t\t\t\t!(await context.publish({\n\t\t\t\t\t\tupdate: () => {\n\t\t\t\t\t\t\tdynamicModels = restored;\n\t\t\t\t\t\t},\n\t\t\t\t\t}))\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Import catalogs cached by the pre-ModelsStore Radius implementation.\n\t\t\tif (!stored && context.credential?.type === \"oauth\") {\n\t\t\t\tconst legacy = getRadiusModels(id, context.credential);\n\t\t\t\tif (legacy.length > 0) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!(await context.publish({\n\t\t\t\t\t\t\tpersist: { models: legacy, checkedAt: Date.now() },\n\t\t\t\t\t\t\tupdate: () => {\n\t\t\t\t\t\t\t\tdynamicModels = legacy;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}))\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!context.allowNetwork || context.signal.aborted) return;\n\t\t\tconst apiKey = context.credential?.type === \"oauth\" ? context.credential.access : context.credential?.key;\n\t\t\tconst config = await loadRadiusGatewayConfig(gateway, apiKey, context.signal);\n\t\t\tif (context.signal.aborted) return;\n\t\t\tconst refreshed = getRadiusModelsFromConfig(id, config);\n\t\t\tawait context.publish({\n\t\t\t\tpersist: { models: refreshed, checkedAt: Date.now() },\n\t\t\t\tupdate: () => {\n\t\t\t\t\tdynamicModels = refreshed;\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\tstream: (model, context, streamOptions) => streams.stream(model, context, streamOptions),\n\t\tstreamSimple: (model, context, streamOptions) => streams.streamSimple(model, context, streamOptions),\n\t};\n}\n"]}
1
+ {"version":3,"file":"radius.js","sourceRoot":"","sources":["../../src/providers/radius.ts"],"names":[],"mappings":"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","sourcesContent":["import { piMessagesApi } from \"../api/pi-messages.lazy.ts\";\nimport { envApiKeyAuth, lazyOAuth } from \"../auth/helpers.ts\";\nimport { loadRadiusOAuth } from \"../auth/oauth/load.ts\";\nimport type { Provider } from \"../models.ts\";\nimport type { Model } from \"../types.ts\";\nimport { RADIUS_MODELS } from \"./radius.models.ts\";\nimport {\n\tDEFAULT_RADIUS_GATEWAY,\n\tgetRadiusModels,\n\tgetRadiusModelsFromConfig,\n\tloadRadiusGatewayConfig,\n\tnormalizeRadiusGatewayUrl,\n} from \"./radius-config.ts\";\n\nexport interface RadiusProviderOptions {\n\tid?: string;\n\tname?: string;\n\tgateway?: string;\n}\n\n/** Radius gateway provider with a persisted, dynamically refreshed catalog. */\nexport function radiusProvider(options: RadiusProviderOptions = {}): Provider<\"pi-messages\"> {\n\tconst id = options.id ?? \"radius\";\n\tconst name = options.name ?? \"Radius\";\n\tconst gateway = normalizeRadiusGatewayUrl(options.gateway ?? DEFAULT_RADIUS_GATEWAY);\n\tconst baselineModels: Model<\"pi-messages\">[] =\n\t\tgateway === normalizeRadiusGatewayUrl(DEFAULT_RADIUS_GATEWAY)\n\t\t\t? Object.values(RADIUS_MODELS).map((model) => ({ ...model, provider: id }))\n\t\t\t: [];\n\t// Gateway catalog for this account. Radius org owners can disable models, so once known it replaces\n\t// the shipped baseline instead of overlaying it. The baseline only covers the time before any catalog exists.\n\tlet dynamicModels: Model<\"pi-messages\">[] | undefined;\n\tconst streams = piMessagesApi();\n\n\treturn {\n\t\tid,\n\t\tname,\n\t\tauth: {\n\t\t\tapiKey: envApiKeyAuth(\"Radius API key\", [\"RADIUS_API_KEY\"]),\n\t\t\toauth: lazyOAuth({ name, load: () => loadRadiusOAuth({ name, gateway }) }),\n\t\t},\n\t\tgetModels: () => dynamicModels ?? baselineModels,\n\t\trefreshModels: async (context) => {\n\t\t\tconst stored = context.stored;\n\t\t\tif (stored) {\n\t\t\t\tconst restored = stored.models.filter((model) => model.provider === id) as Model<\"pi-messages\">[];\n\t\t\t\tif (\n\t\t\t\t\t!(await context.publish({\n\t\t\t\t\t\tupdate: () => {\n\t\t\t\t\t\t\tdynamicModels = restored;\n\t\t\t\t\t\t},\n\t\t\t\t\t}))\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Import catalogs cached by the pre-ModelsStore Radius implementation.\n\t\t\tif (!stored && context.credential?.type === \"oauth\") {\n\t\t\t\tconst legacy = getRadiusModels(id, context.credential);\n\t\t\t\tif (legacy.length > 0) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!(await context.publish({\n\t\t\t\t\t\t\tpersist: { models: legacy, checkedAt: Date.now() },\n\t\t\t\t\t\t\tupdate: () => {\n\t\t\t\t\t\t\t\tdynamicModels = legacy;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}))\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!context.allowNetwork || context.signal.aborted) return;\n\t\t\tconst apiKey = context.credential?.type === \"oauth\" ? context.credential.access : context.credential?.key;\n\t\t\tconst config = await loadRadiusGatewayConfig(gateway, apiKey, context.signal);\n\t\t\tif (context.signal.aborted) return;\n\t\t\tconst refreshed = getRadiusModelsFromConfig(id, config);\n\t\t\tawait context.publish({\n\t\t\t\tpersist: { models: refreshed, checkedAt: Date.now() },\n\t\t\t\tupdate: () => {\n\t\t\t\t\tdynamicModels = refreshed;\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\tstream: (model, context, streamOptions) => streams.stream(model, context, streamOptions),\n\t\tstreamSimple: (model, context, streamOptions) => streams.streamSimple(model, context, streamOptions),\n\t};\n}\n"]}