@mastra/core 0.20.0 → 0.20.1-alpha.2

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 (200) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/agent/agent.d.ts +375 -9
  3. package/dist/agent/agent.d.ts.map +1 -1
  4. package/dist/agent/index.cjs +11 -11
  5. package/dist/agent/index.js +2 -2
  6. package/dist/agent/input-processor/index.cjs +6 -6
  7. package/dist/agent/input-processor/index.js +1 -1
  8. package/dist/agent/types.d.ts +66 -0
  9. package/dist/agent/types.d.ts.map +1 -1
  10. package/dist/agent/workflows/prepare-stream/index.d.ts +19 -3
  11. package/dist/agent/workflows/prepare-stream/index.d.ts.map +1 -1
  12. package/dist/agent/workflows/prepare-stream/prepare-memory-step.d.ts +5 -1
  13. package/dist/agent/workflows/prepare-stream/prepare-memory-step.d.ts.map +1 -1
  14. package/dist/agent/workflows/prepare-stream/prepare-tools-step.d.ts +5 -1
  15. package/dist/agent/workflows/prepare-stream/prepare-tools-step.d.ts.map +1 -1
  16. package/dist/agent/workflows/prepare-stream/stream-step.d.ts +5 -1
  17. package/dist/agent/workflows/prepare-stream/stream-step.d.ts.map +1 -1
  18. package/dist/ai-tracing/index.cjs +32 -32
  19. package/dist/ai-tracing/index.js +1 -1
  20. package/dist/{chunk-3NNB72OL.cjs → chunk-33DTPWTJ.cjs} +7 -7
  21. package/dist/{chunk-3NNB72OL.cjs.map → chunk-33DTPWTJ.cjs.map} +1 -1
  22. package/dist/{chunk-CJDOU6WP.js → chunk-3KBXOXG6.js} +3 -3
  23. package/dist/{chunk-CJDOU6WP.js.map → chunk-3KBXOXG6.js.map} +1 -1
  24. package/dist/{chunk-ZNK5RN5D.cjs → chunk-3Z3DP6S2.cjs} +6 -6
  25. package/dist/{chunk-ZNK5RN5D.cjs.map → chunk-3Z3DP6S2.cjs.map} +1 -1
  26. package/dist/{chunk-KGBDRSMX.js → chunk-5I6DXBUR.js} +4 -4
  27. package/dist/{chunk-KGBDRSMX.js.map → chunk-5I6DXBUR.js.map} +1 -1
  28. package/dist/{chunk-7EUC32F3.cjs → chunk-6K7IMZVR.cjs} +617 -24
  29. package/dist/chunk-6K7IMZVR.cjs.map +1 -0
  30. package/dist/{chunk-FV4QVXO4.js → chunk-6OLRLZJ3.js} +37 -2
  31. package/dist/chunk-6OLRLZJ3.js.map +1 -0
  32. package/dist/{chunk-OXLN4CWA.js → chunk-B5GBHE4E.js} +3 -3
  33. package/dist/{chunk-OXLN4CWA.js.map → chunk-B5GBHE4E.js.map} +1 -1
  34. package/dist/{chunk-2SH5WPUA.cjs → chunk-BG5FC6ZZ.cjs} +407 -803
  35. package/dist/chunk-BG5FC6ZZ.cjs.map +1 -0
  36. package/dist/{chunk-COYTVUIL.js → chunk-EKFF7JLS.js} +610 -17
  37. package/dist/chunk-EKFF7JLS.js.map +1 -0
  38. package/dist/{chunk-BOJNXNRV.js → chunk-FJIABZVI.js} +3 -3
  39. package/dist/{chunk-BOJNXNRV.js.map → chunk-FJIABZVI.js.map} +1 -1
  40. package/dist/{chunk-RYFQKXXS.js → chunk-H4KO46HZ.js} +3 -3
  41. package/dist/{chunk-RYFQKXXS.js.map → chunk-H4KO46HZ.js.map} +1 -1
  42. package/dist/{chunk-T4H33PBR.cjs → chunk-IKLSJCMT.cjs} +360 -69
  43. package/dist/chunk-IKLSJCMT.cjs.map +1 -0
  44. package/dist/{chunk-K4AYIXVH.cjs → chunk-L5A4MRCK.cjs} +4 -4
  45. package/dist/{chunk-K4AYIXVH.cjs.map → chunk-L5A4MRCK.cjs.map} +1 -1
  46. package/dist/{chunk-DVHBWEYY.cjs → chunk-LCJHFYJS.cjs} +7 -7
  47. package/dist/{chunk-DVHBWEYY.cjs.map → chunk-LCJHFYJS.cjs.map} +1 -1
  48. package/dist/{chunk-I6TOPBP6.cjs → chunk-MHHMY2K4.cjs} +49 -18
  49. package/dist/chunk-MHHMY2K4.cjs.map +1 -0
  50. package/dist/{chunk-DQISKQDE.js → chunk-OBAFLVGD.js} +342 -51
  51. package/dist/chunk-OBAFLVGD.js.map +1 -0
  52. package/dist/{chunk-6R46VE63.js → chunk-OPHFW56S.js} +39 -8
  53. package/dist/chunk-OPHFW56S.js.map +1 -0
  54. package/dist/{chunk-LCJP7LWN.cjs → chunk-P4ZPZKZY.cjs} +6 -6
  55. package/dist/{chunk-LCJP7LWN.cjs.map → chunk-P4ZPZKZY.cjs.map} +1 -1
  56. package/dist/{chunk-QR5VZWWT.js → chunk-P7WEYMRS.js} +3 -3
  57. package/dist/{chunk-QR5VZWWT.js.map → chunk-P7WEYMRS.js.map} +1 -1
  58. package/dist/{chunk-YEEAHLAK.cjs → chunk-PWPESTZZ.cjs} +4 -4
  59. package/dist/{chunk-YEEAHLAK.cjs.map → chunk-PWPESTZZ.cjs.map} +1 -1
  60. package/dist/{chunk-7HUKQ6SZ.cjs → chunk-Q3S3BXHO.cjs} +4 -4
  61. package/dist/{chunk-7HUKQ6SZ.cjs.map → chunk-Q3S3BXHO.cjs.map} +1 -1
  62. package/dist/{chunk-WP2KQXPV.js → chunk-RMMGYPXG.js} +3 -3
  63. package/dist/{chunk-WP2KQXPV.js.map → chunk-RMMGYPXG.js.map} +1 -1
  64. package/dist/{chunk-A4RAEU6X.cjs → chunk-SE4PA467.cjs} +37 -2
  65. package/dist/chunk-SE4PA467.cjs.map +1 -0
  66. package/dist/{chunk-AND6J5LG.js → chunk-W2WXYTYI.js} +407 -803
  67. package/dist/chunk-W2WXYTYI.js.map +1 -0
  68. package/dist/{chunk-OKIHIKXV.cjs → chunk-WE6ILDQY.cjs} +4 -4
  69. package/dist/{chunk-OKIHIKXV.cjs.map → chunk-WE6ILDQY.cjs.map} +1 -1
  70. package/dist/{chunk-ZJ2UFCTS.js → chunk-Y2TIJVKC.js} +3 -3
  71. package/dist/{chunk-ZJ2UFCTS.js.map → chunk-Y2TIJVKC.js.map} +1 -1
  72. package/dist/index.cjs +52 -52
  73. package/dist/index.cjs.map +1 -1
  74. package/dist/index.js +11 -11
  75. package/dist/index.js.map +1 -1
  76. package/dist/integration/index.cjs +3 -3
  77. package/dist/integration/index.js +1 -1
  78. package/dist/llm/index.cjs +6 -6
  79. package/dist/llm/index.d.ts +1 -1
  80. package/dist/llm/index.d.ts.map +1 -1
  81. package/dist/llm/index.js +1 -1
  82. package/dist/llm/model/gateway-resolver.d.ts +7 -5
  83. package/dist/llm/model/gateway-resolver.d.ts.map +1 -1
  84. package/dist/llm/model/gateways/base.d.ts +8 -6
  85. package/dist/llm/model/gateways/base.d.ts.map +1 -1
  86. package/dist/llm/model/gateways/constants.d.ts +3 -0
  87. package/dist/llm/model/gateways/constants.d.ts.map +1 -0
  88. package/dist/llm/model/gateways/index.d.ts +5 -0
  89. package/dist/llm/model/gateways/index.d.ts.map +1 -1
  90. package/dist/llm/model/gateways/models-dev.d.ts +8 -2
  91. package/dist/llm/model/gateways/models-dev.d.ts.map +1 -1
  92. package/dist/llm/model/gateways/netlify.d.ts +11 -2
  93. package/dist/llm/model/gateways/netlify.d.ts.map +1 -1
  94. package/dist/llm/model/index.d.ts +1 -1
  95. package/dist/llm/model/index.d.ts.map +1 -1
  96. package/dist/llm/model/model.loop.d.ts +1 -1
  97. package/dist/llm/model/model.loop.d.ts.map +1 -1
  98. package/dist/llm/model/provider-registry.generated.d.ts +6 -7
  99. package/dist/llm/model/provider-registry.generated.d.ts.map +1 -1
  100. package/dist/llm/model/router.d.ts +23 -0
  101. package/dist/llm/model/router.d.ts.map +1 -0
  102. package/dist/loop/index.cjs +2 -2
  103. package/dist/loop/index.js +1 -1
  104. package/dist/loop/network/index.d.ts +5 -1
  105. package/dist/loop/network/index.d.ts.map +1 -1
  106. package/dist/loop/workflows/agentic-execution/index.d.ts +5 -1
  107. package/dist/loop/workflows/agentic-execution/index.d.ts.map +1 -1
  108. package/dist/loop/workflows/agentic-execution/llm-execution-step.d.ts +5 -1
  109. package/dist/loop/workflows/agentic-execution/llm-execution-step.d.ts.map +1 -1
  110. package/dist/loop/workflows/agentic-execution/llm-mapping-step.d.ts +5 -1
  111. package/dist/loop/workflows/agentic-execution/llm-mapping-step.d.ts.map +1 -1
  112. package/dist/loop/workflows/agentic-execution/tool-call-step.d.ts +5 -1
  113. package/dist/loop/workflows/agentic-execution/tool-call-step.d.ts.map +1 -1
  114. package/dist/loop/workflows/agentic-loop/index.d.ts +5 -1
  115. package/dist/loop/workflows/agentic-loop/index.d.ts.map +1 -1
  116. package/dist/mastra/index.cjs +2 -2
  117. package/dist/mastra/index.d.ts +695 -12
  118. package/dist/mastra/index.d.ts.map +1 -1
  119. package/dist/mastra/index.js +1 -1
  120. package/dist/memory/index.cjs +4 -4
  121. package/dist/memory/index.js +1 -1
  122. package/dist/processors/index.cjs +11 -11
  123. package/dist/processors/index.js +1 -1
  124. package/dist/relevance/index.cjs +4 -4
  125. package/dist/relevance/index.js +1 -1
  126. package/dist/scores/index.cjs +9 -9
  127. package/dist/scores/index.js +2 -2
  128. package/dist/scores/run-experiment/index.d.ts +2 -2
  129. package/dist/scores/run-experiment/index.d.ts.map +1 -1
  130. package/dist/scores/scoreTraces/index.cjs +8 -8
  131. package/dist/scores/scoreTraces/index.js +3 -3
  132. package/dist/scores/scoreTraces/scoreTracesWorkflow.d.ts +10 -2
  133. package/dist/scores/scoreTraces/scoreTracesWorkflow.d.ts.map +1 -1
  134. package/dist/storage/domains/operations/base.d.ts +6 -0
  135. package/dist/storage/domains/operations/base.d.ts.map +1 -1
  136. package/dist/storage/index.cjs +11 -3
  137. package/dist/storage/index.cjs.map +1 -1
  138. package/dist/storage/index.js +9 -1
  139. package/dist/storage/index.js.map +1 -1
  140. package/dist/stream/MastraAgentNetworkStream.d.ts +5 -1
  141. package/dist/stream/MastraAgentNetworkStream.d.ts.map +1 -1
  142. package/dist/stream/MastraWorkflowStream.d.ts +3 -3
  143. package/dist/stream/MastraWorkflowStream.d.ts.map +1 -1
  144. package/dist/stream/index.cjs +4 -4
  145. package/dist/stream/index.js +1 -1
  146. package/dist/test-utils/llm-mock.cjs +2 -2
  147. package/dist/test-utils/llm-mock.js +1 -1
  148. package/dist/tools/index.cjs +4 -4
  149. package/dist/tools/index.js +1 -1
  150. package/dist/tools/is-vercel-tool.cjs +2 -2
  151. package/dist/tools/is-vercel-tool.js +1 -1
  152. package/dist/tools/tool.d.ts +163 -0
  153. package/dist/tools/tool.d.ts.map +1 -1
  154. package/dist/utils.cjs +17 -17
  155. package/dist/utils.d.ts +1 -1
  156. package/dist/utils.d.ts.map +1 -1
  157. package/dist/utils.js +1 -1
  158. package/dist/workflows/default.d.ts +13 -7
  159. package/dist/workflows/default.d.ts.map +1 -1
  160. package/dist/workflows/evented/index.cjs +10 -10
  161. package/dist/workflows/evented/index.js +1 -1
  162. package/dist/workflows/evented/step-executor.d.ts +7 -3
  163. package/dist/workflows/evented/step-executor.d.ts.map +1 -1
  164. package/dist/workflows/evented/workflow-event-processor/index.d.ts.map +1 -1
  165. package/dist/workflows/evented/workflow-event-processor/loop.d.ts.map +1 -1
  166. package/dist/workflows/evented/workflow-event-processor/parallel.d.ts.map +1 -1
  167. package/dist/workflows/evented/workflow-event-processor/utils.d.ts +1 -1
  168. package/dist/workflows/evented/workflow.d.ts +23 -19
  169. package/dist/workflows/evented/workflow.d.ts.map +1 -1
  170. package/dist/workflows/execution-engine.d.ts +5 -1
  171. package/dist/workflows/execution-engine.d.ts.map +1 -1
  172. package/dist/workflows/index.cjs +12 -12
  173. package/dist/workflows/index.js +1 -1
  174. package/dist/workflows/legacy/index.cjs +22 -22
  175. package/dist/workflows/legacy/index.js +1 -1
  176. package/dist/workflows/step.d.ts +11 -4
  177. package/dist/workflows/step.d.ts.map +1 -1
  178. package/dist/workflows/types.d.ts +33 -9
  179. package/dist/workflows/types.d.ts.map +1 -1
  180. package/dist/workflows/workflow.d.ts +85 -56
  181. package/dist/workflows/workflow.d.ts.map +1 -1
  182. package/dist/workflows/workflow.warning.d.ts +2 -2
  183. package/dist/workflows/workflow.warning.d.ts.map +1 -1
  184. package/package.json +9 -4
  185. package/dist/chunk-2SH5WPUA.cjs.map +0 -1
  186. package/dist/chunk-45CV4JYJ.cjs +0 -4
  187. package/dist/chunk-45CV4JYJ.cjs.map +0 -1
  188. package/dist/chunk-6R46VE63.js.map +0 -1
  189. package/dist/chunk-7EUC32F3.cjs.map +0 -1
  190. package/dist/chunk-A4RAEU6X.cjs.map +0 -1
  191. package/dist/chunk-AND6J5LG.js.map +0 -1
  192. package/dist/chunk-COYTVUIL.js.map +0 -1
  193. package/dist/chunk-DQISKQDE.js.map +0 -1
  194. package/dist/chunk-FV4QVXO4.js.map +0 -1
  195. package/dist/chunk-I6TOPBP6.cjs.map +0 -1
  196. package/dist/chunk-RFGQ3EQV.js +0 -3
  197. package/dist/chunk-RFGQ3EQV.js.map +0 -1
  198. package/dist/chunk-T4H33PBR.cjs.map +0 -1
  199. package/dist/llm/model/openai-compatible.d.ts +0 -37
  200. package/dist/llm/model/openai-compatible.d.ts.map +0 -1
@@ -1,5 +1,351 @@
1
1
  import { InMemoryServerCache } from './chunk-EQV2PPN2.js';
2
2
  import { MastraError } from './chunk-T3JFFQH2.js';
3
+ import { createHash } from 'crypto';
4
+ import { createAnthropic } from '@ai-sdk/anthropic-v5';
5
+ import { createGoogleGenerativeAI } from '@ai-sdk/google-v5';
6
+ import { createOpenAICompatible } from '@ai-sdk/openai-compatible-v5';
7
+ import { createOpenAI } from '@ai-sdk/openai-v5';
8
+ import { createXai } from '@ai-sdk/xai-v5';
9
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider-v5';
10
+
11
+ // src/llm/model/gateway-resolver.ts
12
+ function parseModelRouterId(routerId, gatewayPrefix) {
13
+ if (gatewayPrefix && !routerId.startsWith(`${gatewayPrefix}/`)) {
14
+ throw new Error(`Expected ${gatewayPrefix}/ in model router ID ${routerId}`);
15
+ }
16
+ const idParts = routerId.split("/");
17
+ if (gatewayPrefix && idParts.length < 3) {
18
+ throw new Error(
19
+ `Expected atleast 3 id parts ${gatewayPrefix}/provider/model, but only saw ${idParts.length} in ${routerId}`
20
+ );
21
+ }
22
+ const providerId = idParts.at(gatewayPrefix ? 1 : 0);
23
+ const modelId = idParts.slice(gatewayPrefix ? 2 : 1).join(`/`);
24
+ if (!routerId.includes(`/`) || !providerId || !modelId) {
25
+ throw new Error(
26
+ `Attempted to parse provider/model from ${routerId} but this ID doesn't appear to contain a provider`
27
+ );
28
+ }
29
+ return {
30
+ providerId,
31
+ modelId
32
+ };
33
+ }
34
+
35
+ // src/llm/model/gateways/base.ts
36
+ var MastraModelGateway = class {
37
+ };
38
+
39
+ // src/llm/model/gateways/constants.ts
40
+ var PROVIDERS_WITH_INSTALLED_PACKAGES = ["anthropic", "google", "openai", "openrouter", "xai"];
41
+ var EXCLUDED_PROVIDERS = ["github-copilot"];
42
+
43
+ // src/llm/model/gateways/models-dev.ts
44
+ var OPENAI_COMPATIBLE_OVERRIDES = {
45
+ cerebras: {
46
+ url: "https://api.cerebras.ai/v1/chat/completions"
47
+ },
48
+ xai: {
49
+ url: "https://api.x.ai/v1/chat/completions"
50
+ },
51
+ mistral: {
52
+ url: "https://api.mistral.ai/v1/chat/completions"
53
+ },
54
+ groq: {
55
+ url: "https://api.groq.com/openai/v1/chat/completions"
56
+ },
57
+ togetherai: {
58
+ url: "https://api.together.xyz/v1/chat/completions"
59
+ },
60
+ deepinfra: {
61
+ url: "https://api.deepinfra.com/v1/openai/chat/completions"
62
+ },
63
+ perplexity: {
64
+ url: "https://api.perplexity.ai/chat/completions"
65
+ },
66
+ vercel: {
67
+ url: "https://ai-gateway.vercel.sh/v1/chat/completions",
68
+ apiKeyEnvVar: "AI_GATEWAY_API_KEY"
69
+ }
70
+ };
71
+ var ModelsDevGateway = class extends MastraModelGateway {
72
+ name = "models.dev";
73
+ prefix = void 0;
74
+ // No prefix for registry gateway
75
+ providerConfigs = {};
76
+ constructor(providerConfigs) {
77
+ super();
78
+ if (providerConfigs) this.providerConfigs = providerConfigs;
79
+ }
80
+ async fetchProviders() {
81
+ console.info("Fetching providers from models.dev API...");
82
+ const response = await fetch("https://models.dev/api.json");
83
+ if (!response.ok) {
84
+ throw new Error(`Failed to fetch from models.dev: ${response.statusText}`);
85
+ }
86
+ const data = await response.json();
87
+ const providerConfigs = {};
88
+ for (const [providerId, providerInfo] of Object.entries(data)) {
89
+ if (EXCLUDED_PROVIDERS.includes(providerId)) continue;
90
+ if (!providerInfo || typeof providerInfo !== "object" || !providerInfo.models) continue;
91
+ const normalizedId = providerId;
92
+ const isOpenAICompatible = providerInfo.npm === "@ai-sdk/openai-compatible" || providerInfo.npm === "@ai-sdk/gateway" || // Vercel AI Gateway is OpenAI-compatible
93
+ normalizedId in OPENAI_COMPATIBLE_OVERRIDES;
94
+ const hasInstalledPackage = PROVIDERS_WITH_INSTALLED_PACKAGES.includes(providerId);
95
+ const hasApiAndEnv = providerInfo.api && providerInfo.env && providerInfo.env.length > 0;
96
+ if (isOpenAICompatible || hasInstalledPackage || hasApiAndEnv) {
97
+ const modelIds = Object.keys(providerInfo.models).sort();
98
+ let url = providerInfo.api || OPENAI_COMPATIBLE_OVERRIDES[normalizedId]?.url;
99
+ if (!hasInstalledPackage && url && !url.includes("/chat/completions") && !url.includes("/messages")) {
100
+ url = url.replace(/\/$/, "") + "/chat/completions";
101
+ }
102
+ if (!hasInstalledPackage && !url) {
103
+ console.info(`Skipping ${normalizedId}: No API URL available`);
104
+ continue;
105
+ }
106
+ const apiKeyEnvVar = providerInfo.env?.[0] || `${normalizedId.toUpperCase().replace(/-/g, "_")}_API_KEY`;
107
+ const apiKeyHeader = !hasInstalledPackage ? OPENAI_COMPATIBLE_OVERRIDES[normalizedId]?.apiKeyHeader || "Authorization" : void 0;
108
+ providerConfigs[normalizedId] = {
109
+ url,
110
+ apiKeyEnvVar,
111
+ apiKeyHeader,
112
+ name: providerInfo.name || providerId.charAt(0).toUpperCase() + providerId.slice(1),
113
+ models: modelIds,
114
+ docUrl: providerInfo.doc,
115
+ // Include documentation URL if available
116
+ gateway: `models.dev`
117
+ };
118
+ } else {
119
+ console.info(`Skipped provider ${providerInfo.name}`);
120
+ }
121
+ }
122
+ this.providerConfigs = providerConfigs;
123
+ console.info(`Found ${Object.keys(providerConfigs).length} OpenAI-compatible providers`);
124
+ console.info("Providers:", Object.keys(providerConfigs).sort());
125
+ return providerConfigs;
126
+ }
127
+ buildUrl(routerId, envVars) {
128
+ const { providerId } = parseModelRouterId(routerId);
129
+ const config = this.providerConfigs[providerId];
130
+ if (!config?.url) {
131
+ return;
132
+ }
133
+ const baseUrlEnvVar = `${providerId.toUpperCase().replace(/-/g, "_")}_BASE_URL`;
134
+ const customBaseUrl = envVars?.[baseUrlEnvVar] || process.env[baseUrlEnvVar];
135
+ return customBaseUrl || config.url;
136
+ }
137
+ getApiKey(modelId) {
138
+ const [provider, model] = modelId.split("/");
139
+ if (!provider || !model) {
140
+ throw new Error(`Could not identify provider from model id ${modelId}`);
141
+ }
142
+ const config = this.providerConfigs[provider];
143
+ if (!config) {
144
+ throw new Error(`Could not find config for provider ${provider} with model id ${modelId}`);
145
+ }
146
+ const apiKey = typeof config.apiKeyEnvVar === `string` ? process.env[config.apiKeyEnvVar] : void 0;
147
+ if (!apiKey) {
148
+ throw new Error(`Could not find API key process.env.${config.apiKeyEnvVar} for model id ${modelId}`);
149
+ }
150
+ return Promise.resolve(apiKey);
151
+ }
152
+ async resolveLanguageModel({
153
+ modelId,
154
+ providerId,
155
+ apiKey
156
+ }) {
157
+ const baseURL = this.buildUrl(`${providerId}/${modelId}`);
158
+ switch (providerId) {
159
+ case "openai":
160
+ return createOpenAI({ apiKey }).responses(modelId);
161
+ case "gemini":
162
+ case "google":
163
+ return createGoogleGenerativeAI({
164
+ apiKey
165
+ }).chat(modelId);
166
+ case "anthropic":
167
+ return createAnthropic({ apiKey })(modelId);
168
+ case "openrouter":
169
+ return createOpenRouter({ apiKey })(modelId);
170
+ case "xai":
171
+ return createXai({
172
+ apiKey
173
+ })(modelId);
174
+ default:
175
+ if (!baseURL) throw new Error(`No API URL found for ${providerId}/${modelId}`);
176
+ return createOpenAICompatible({ name: providerId, apiKey, baseURL }).chatModel(modelId);
177
+ }
178
+ }
179
+ };
180
+ var NetlifyGateway = class extends MastraModelGateway {
181
+ name = "netlify";
182
+ prefix = "netlify";
183
+ // All providers will be prefixed with "netlify/"
184
+ tokenCache = new InMemoryServerCache();
185
+ async fetchProviders() {
186
+ console.info("Fetching providers from Netlify AI Gateway...");
187
+ const response = await fetch("https://api.netlify.com/api/v1/ai-gateway/providers");
188
+ if (!response.ok) {
189
+ throw new Error(`Failed to fetch from Netlify: ${response.statusText}`);
190
+ }
191
+ const data = await response.json();
192
+ const netlify = {
193
+ apiKeyEnvVar: ["NETLIFY_TOKEN", "NETLIFY_SITE_ID"],
194
+ apiKeyHeader: "Authorization",
195
+ // Netlify uses standard Bearer auth
196
+ name: `Netlify`,
197
+ gateway: `netlify`,
198
+ models: [],
199
+ docUrl: "https://docs.netlify.com/build/ai-gateway/overview/"
200
+ };
201
+ for (const [providerId, provider] of Object.entries(data.providers)) {
202
+ for (const model of provider.models) {
203
+ netlify.models.push(`${providerId}/${model}`);
204
+ }
205
+ }
206
+ console.info(`Found ${Object.keys(data.providers).length} models via Netlify Gateway`);
207
+ return { netlify };
208
+ }
209
+ async buildUrl(routerId, envVars) {
210
+ const siteId = envVars?.["NETLIFY_SITE_ID"] || process.env["NETLIFY_SITE_ID"];
211
+ const netlifyToken = envVars?.["NETLIFY_TOKEN"] || process.env["NETLIFY_TOKEN"];
212
+ if (!netlifyToken) {
213
+ throw new MastraError({
214
+ id: "NETLIFY_GATEWAY_NO_TOKEN",
215
+ domain: "LLM",
216
+ category: "UNKNOWN",
217
+ text: `Missing NETLIFY_TOKEN environment variable required for model: ${routerId}`
218
+ });
219
+ }
220
+ if (!siteId) {
221
+ throw new MastraError({
222
+ id: "NETLIFY_GATEWAY_NO_SITE_ID",
223
+ domain: "LLM",
224
+ category: "UNKNOWN",
225
+ text: `Missing NETLIFY_SITE_ID environment variable required for model: ${routerId}`
226
+ });
227
+ }
228
+ try {
229
+ const tokenData = await this.getOrFetchToken(siteId, netlifyToken);
230
+ return tokenData.url.endsWith(`/`) ? tokenData.url.substring(0, tokenData.url.length - 1) : tokenData.url;
231
+ } catch (error) {
232
+ throw new MastraError({
233
+ id: "NETLIFY_GATEWAY_TOKEN_ERROR",
234
+ domain: "LLM",
235
+ category: "UNKNOWN",
236
+ text: `Failed to get Netlify AI Gateway token for model ${routerId}: ${error instanceof Error ? error.message : String(error)}`
237
+ });
238
+ }
239
+ }
240
+ /**
241
+ * Get cached token or fetch a new site-specific AI Gateway token from Netlify
242
+ */
243
+ async getOrFetchToken(siteId, netlifyToken) {
244
+ const cacheKey = `netlify-token:${siteId}:${netlifyToken}`;
245
+ const cached = await this.tokenCache.get(cacheKey);
246
+ if (cached && cached.expiresAt > Date.now() / 1e3 + 60) {
247
+ return { token: cached.token, url: cached.url };
248
+ }
249
+ const response = await fetch(`https://api.netlify.com/api/v1/sites/${siteId}/ai-gateway/token`, {
250
+ method: "GET",
251
+ headers: {
252
+ Authorization: `Bearer ${netlifyToken}`
253
+ }
254
+ });
255
+ if (!response.ok) {
256
+ const error = await response.text();
257
+ throw new Error(`Failed to get Netlify AI Gateway token: ${response.status} ${error}`);
258
+ }
259
+ const tokenResponse = await response.json();
260
+ await this.tokenCache.set(cacheKey, {
261
+ token: tokenResponse.token,
262
+ url: tokenResponse.url,
263
+ expiresAt: tokenResponse.expires_at
264
+ });
265
+ return { token: tokenResponse.token, url: tokenResponse.url };
266
+ }
267
+ /**
268
+ * Get cached token or fetch a new site-specific AI Gateway token from Netlify
269
+ */
270
+ async getApiKey(modelId) {
271
+ const siteId = process.env["NETLIFY_SITE_ID"];
272
+ const netlifyToken = process.env["NETLIFY_TOKEN"];
273
+ if (!netlifyToken) {
274
+ throw new MastraError({
275
+ id: "NETLIFY_GATEWAY_NO_TOKEN",
276
+ domain: "LLM",
277
+ category: "UNKNOWN",
278
+ text: `Missing NETLIFY_TOKEN environment variable required for model: ${modelId}`
279
+ });
280
+ }
281
+ if (!siteId) {
282
+ throw new MastraError({
283
+ id: "NETLIFY_GATEWAY_NO_SITE_ID",
284
+ domain: "LLM",
285
+ category: "UNKNOWN",
286
+ text: `Missing NETLIFY_SITE_ID environment variable required for model: ${modelId}`
287
+ });
288
+ }
289
+ try {
290
+ return (await this.getOrFetchToken(siteId, netlifyToken)).token;
291
+ } catch (error) {
292
+ throw new MastraError({
293
+ id: "NETLIFY_GATEWAY_TOKEN_ERROR",
294
+ domain: "LLM",
295
+ category: "UNKNOWN",
296
+ text: `Failed to get Netlify AI Gateway token for model ${modelId}: ${error instanceof Error ? error.message : String(error)}`
297
+ });
298
+ }
299
+ }
300
+ async resolveLanguageModel({
301
+ modelId,
302
+ providerId,
303
+ apiKey
304
+ }) {
305
+ const baseURL = await this.buildUrl(`${providerId}/${modelId}`);
306
+ switch (providerId) {
307
+ case "openai":
308
+ return createOpenAI({ apiKey, baseURL }).responses(modelId);
309
+ case "gemini":
310
+ return createGoogleGenerativeAI({
311
+ baseURL: `${baseURL}/v1beta/`,
312
+ apiKey,
313
+ headers: {
314
+ "user-agent": "google-genai-sdk/"
315
+ }
316
+ }).chat(modelId);
317
+ case "anthropic":
318
+ return createAnthropic({
319
+ apiKey,
320
+ baseURL: `${baseURL}/v1/`,
321
+ headers: {
322
+ "anthropic-version": "2023-06-01",
323
+ "user-agent": "anthropic/"
324
+ }
325
+ })(modelId);
326
+ default:
327
+ return createOpenAICompatible({ name: providerId, apiKey, baseURL }).chatModel(modelId);
328
+ }
329
+ }
330
+ };
331
+
332
+ // src/llm/model/gateways/index.ts
333
+ function findGatewayForModel(gatewayId, gateways2) {
334
+ const prefixedGateway = gateways2.find((g) => g.prefix && gatewayId.startsWith(`${g.prefix}/`));
335
+ if (prefixedGateway) {
336
+ return prefixedGateway;
337
+ }
338
+ const unprefixedGateways = gateways2.filter((g) => !g.prefix);
339
+ for (const gateway of unprefixedGateways) {
340
+ return gateway;
341
+ }
342
+ throw new MastraError({
343
+ id: "MODEL_ROUTER_NO_GATEWAY_FOUND",
344
+ category: "USER",
345
+ domain: "MODEL_ROUTER",
346
+ text: `No Mastra model router gateway found for model id ${gatewayId}`
347
+ });
348
+ }
3
349
 
4
350
  // src/llm/model/provider-registry.generated.ts
5
351
  var PROVIDER_REGISTRY = {
@@ -51,7 +397,6 @@ var PROVIDER_REGISTRY = {
51
397
  xai: {
52
398
  url: "https://api.x.ai/v1/chat/completions",
53
399
  apiKeyEnvVar: "XAI_API_KEY",
54
- apiKeyHeader: "Authorization",
55
400
  name: "xAI",
56
401
  models: [
57
402
  "grok-2",
@@ -137,33 +482,6 @@ var PROVIDER_REGISTRY = {
137
482
  docUrl: "https://console.groq.com/docs/models",
138
483
  gateway: "models.dev"
139
484
  },
140
- "github-copilot": {
141
- url: "https://api.githubcopilot.com/chat/completions",
142
- apiKeyEnvVar: "GITHUB_TOKEN",
143
- apiKeyHeader: "Authorization",
144
- name: "GitHub Copilot",
145
- models: [
146
- "claude-3.5-sonnet",
147
- "claude-3.7-sonnet",
148
- "claude-3.7-sonnet-thought",
149
- "claude-opus-4",
150
- "claude-opus-41",
151
- "claude-sonnet-4",
152
- "claude-sonnet-4.5",
153
- "gemini-2.0-flash-001",
154
- "gemini-2.5-pro",
155
- "gpt-4.1",
156
- "gpt-4o",
157
- "gpt-5",
158
- "gpt-5-mini",
159
- "grok-code-fast-1",
160
- "o3",
161
- "o3-mini",
162
- "o4-mini"
163
- ],
164
- docUrl: "https://docs.github.com/en/copilot",
165
- gateway: "models.dev"
166
- },
167
485
  mistral: {
168
486
  url: "https://api.mistral.ai/v1/chat/completions",
169
487
  apiKeyEnvVar: "MISTRAL_API_KEY",
@@ -241,6 +559,7 @@ var PROVIDER_REGISTRY = {
241
559
  "openai/gpt-4o",
242
560
  "openai/gpt-4o-mini",
243
561
  "openai/gpt-5",
562
+ "openai/gpt-5-codex",
244
563
  "openai/gpt-5-mini",
245
564
  "openai/gpt-5-nano",
246
565
  "openai/gpt-oss-120b",
@@ -482,20 +801,22 @@ var PROVIDER_REGISTRY = {
482
801
  url: "https://opencode.ai/zen/v1/chat/completions",
483
802
  apiKeyEnvVar: "OPENCODE_API_KEY",
484
803
  apiKeyHeader: "Authorization",
485
- name: "opencode zen",
804
+ name: "OpenCode Zen",
486
805
  models: [
487
806
  "claude-3-5-haiku",
488
807
  "claude-opus-4-1",
489
808
  "claude-sonnet-4",
490
809
  "claude-sonnet-4-5",
491
810
  "code-supernova",
811
+ "glm-4.6",
492
812
  "gpt-5",
813
+ "gpt-5-codex",
493
814
  "grok-code",
494
815
  "kimi-k2",
495
816
  "qwen3-coder",
496
817
  "qwen3-max"
497
818
  ],
498
- docUrl: "https://opencode.ai/docs",
819
+ docUrl: "https://opencode.ai/docs/zen",
499
820
  gateway: "models.dev"
500
821
  },
501
822
  fastrouter: {
@@ -523,9 +844,7 @@ var PROVIDER_REGISTRY = {
523
844
  gateway: "models.dev"
524
845
  },
525
846
  google: {
526
- url: "https://generativelanguage.googleapis.com/v1beta/chat/completions",
527
847
  apiKeyEnvVar: "GOOGLE_GENERATIVE_AI_API_KEY",
528
- apiKeyHeader: "Authorization",
529
848
  name: "Google",
530
849
  models: [
531
850
  "gemini-1.5-flash",
@@ -580,11 +899,10 @@ var PROVIDER_REGISTRY = {
580
899
  gateway: "models.dev"
581
900
  },
582
901
  openai: {
583
- url: "https://api.openai.com/v1/chat/completions",
584
902
  apiKeyEnvVar: "OPENAI_API_KEY",
585
- apiKeyHeader: "Authorization",
586
903
  name: "OpenAI",
587
904
  models: [
905
+ "codex-mini-latest",
588
906
  "gpt-3.5-turbo",
589
907
  "gpt-4",
590
908
  "gpt-4-turbo",
@@ -598,6 +916,7 @@ var PROVIDER_REGISTRY = {
598
916
  "gpt-4o-mini",
599
917
  "gpt-5",
600
918
  "gpt-5-chat-latest",
919
+ "gpt-5-codex",
601
920
  "gpt-5-mini",
602
921
  "gpt-5-nano",
603
922
  "o1",
@@ -633,9 +952,8 @@ var PROVIDER_REGISTRY = {
633
952
  gateway: "models.dev"
634
953
  },
635
954
  openrouter: {
636
- url: "https://openrouter.ai/api/v1/chat/completions",
955
+ url: "https://openrouter.ai/api/v1",
637
956
  apiKeyEnvVar: "OPENROUTER_API_KEY",
638
- apiKeyHeader: "Authorization",
639
957
  name: "OpenRouter",
640
958
  models: [
641
959
  "anthropic/claude-3.5-haiku",
@@ -695,6 +1013,7 @@ var PROVIDER_REGISTRY = {
695
1013
  "openai/gpt-4o-mini",
696
1014
  "openai/gpt-5",
697
1015
  "openai/gpt-5-chat",
1016
+ "openai/gpt-5-codex",
698
1017
  "openai/gpt-5-mini",
699
1018
  "openai/gpt-5-nano",
700
1019
  "openai/gpt-oss-120b",
@@ -769,7 +1088,8 @@ var PROVIDER_REGISTRY = {
769
1088
  "hf:moonshotai/Kimi-K2-Instruct",
770
1089
  "hf:moonshotai/Kimi-K2-Instruct-0905",
771
1090
  "hf:openai/gpt-oss-120b",
772
- "hf:zai-org/GLM-4.5"
1091
+ "hf:zai-org/GLM-4.5",
1092
+ "hf:zai-org/GLM-4.6"
773
1093
  ],
774
1094
  docUrl: "https://synthetic.new/pricing",
775
1095
  gateway: "models.dev"
@@ -886,9 +1206,7 @@ var PROVIDER_REGISTRY = {
886
1206
  gateway: "models.dev"
887
1207
  },
888
1208
  anthropic: {
889
- url: "https://api.anthropic.com/v1/chat/completions",
890
1209
  apiKeyEnvVar: "ANTHROPIC_API_KEY",
891
- apiKeyHeader: "x-api-key",
892
1210
  name: "Anthropic",
893
1211
  models: [
894
1212
  "claude-3-5-haiku-20241022",
@@ -975,38 +1293,39 @@ var PROVIDER_REGISTRY = {
975
1293
  name: "Netlify",
976
1294
  gateway: "netlify",
977
1295
  models: [
978
- "anthropic/claude-3-5-haiku-20241022",
979
1296
  "anthropic/claude-opus-4-20250514",
1297
+ "anthropic/claude-sonnet-4-5-20250929",
980
1298
  "anthropic/claude-sonnet-4-20250514",
981
1299
  "anthropic/claude-3-7-sonnet-20250219",
1300
+ "anthropic/claude-3-7-sonnet-latest",
1301
+ "anthropic/claude-3-5-haiku-20241022",
982
1302
  "anthropic/claude-3-5-haiku-latest",
983
1303
  "anthropic/claude-3-haiku-20240307",
984
1304
  "anthropic/claude-opus-4-1-20250805",
985
- "anthropic/claude-sonnet-4-5-20250929",
986
- "anthropic/claude-3-7-sonnet-latest",
987
1305
  "gemini/gemini-2.5-pro",
988
- "gemini/gemini-2.5-flash",
989
- "gemini/gemini-flash-lite-latest",
990
- "gemini/gemini-2.0-flash-lite",
991
- "gemini/gemini-2.5-flash-image-preview",
992
1306
  "gemini/gemini-flash-latest",
993
- "gemini/gemini-2.5-flash-preview-09-2025",
1307
+ "gemini/gemini-2.5-flash",
994
1308
  "gemini/gemini-2.5-flash-lite-preview-09-2025",
995
1309
  "gemini/gemini-2.5-flash-lite",
1310
+ "gemini/gemini-2.5-flash-preview-09-2025",
1311
+ "gemini/gemini-flash-lite-latest",
996
1312
  "gemini/gemini-2.0-flash",
1313
+ "gemini/gemini-2.0-flash-lite",
1314
+ "gemini/gemini-2.5-flash-image-preview",
1315
+ "openai/gpt-4.1-mini",
1316
+ "openai/gpt-4.1-nano",
1317
+ "openai/gpt-4o",
1318
+ "openai/gpt-5-pro",
1319
+ "openai/gpt-4o-mini",
997
1320
  "openai/o4-mini",
998
1321
  "openai/o3",
999
1322
  "openai/o3-mini",
1000
1323
  "openai/codex-mini-latest",
1324
+ "openai/gpt-5",
1001
1325
  "openai/gpt-5-codex",
1002
1326
  "openai/gpt-5-mini",
1003
1327
  "openai/gpt-5-nano",
1004
- "openai/gpt-4.1",
1005
- "openai/gpt-4.1-mini",
1006
- "openai/gpt-4.1-nano",
1007
- "openai/gpt-4o",
1008
- "openai/gpt-4o-mini",
1009
- "openai/gpt-5"
1328
+ "openai/gpt-4.1"
1010
1329
  ],
1011
1330
  docUrl: "https://docs.netlify.com/build/ai-gateway/overview/"
1012
1331
  }
@@ -1032,331 +1351,12 @@ function parseModelString(modelString) {
1032
1351
  };
1033
1352
  }
1034
1353
 
1035
- // src/llm/model/gateways/base.ts
1036
- var MastraModelGateway = class {
1037
- };
1038
-
1039
- // src/llm/model/gateways/models-dev.ts
1040
- var OPENAI_COMPATIBLE_OVERRIDES = {
1041
- openai: {
1042
- url: "https://api.openai.com/v1/chat/completions"
1043
- },
1044
- anthropic: {
1045
- url: "https://api.anthropic.com/v1/chat/completions",
1046
- apiKeyHeader: "x-api-key"
1047
- },
1048
- cerebras: {
1049
- url: "https://api.cerebras.ai/v1/chat/completions"
1050
- },
1051
- xai: {
1052
- url: "https://api.x.ai/v1/chat/completions"
1053
- },
1054
- mistral: {
1055
- url: "https://api.mistral.ai/v1/chat/completions"
1056
- },
1057
- google: {
1058
- url: "https://generativelanguage.googleapis.com/v1beta/chat/completions"
1059
- },
1060
- groq: {
1061
- url: "https://api.groq.com/openai/v1/chat/completions"
1062
- },
1063
- togetherai: {
1064
- url: "https://api.together.xyz/v1/chat/completions"
1065
- },
1066
- deepinfra: {
1067
- url: "https://api.deepinfra.com/v1/openai/chat/completions"
1068
- },
1069
- perplexity: {
1070
- url: "https://api.perplexity.ai/chat/completions"
1071
- },
1072
- vercel: {
1073
- url: "https://ai-gateway.vercel.sh/v1/chat/completions",
1074
- apiKeyEnvVar: "AI_GATEWAY_API_KEY"
1075
- }
1076
- };
1077
- var ModelsDevGateway = class extends MastraModelGateway {
1078
- name = "models.dev";
1079
- prefix = void 0;
1080
- // No prefix for registry gateway
1081
- providerConfigs = {};
1082
- constructor(providerConfigs) {
1083
- super();
1084
- if (providerConfigs) this.providerConfigs = providerConfigs;
1085
- }
1086
- async fetchProviders() {
1087
- console.info("Fetching providers from models.dev API...");
1088
- const response = await fetch("https://models.dev/api.json");
1089
- if (!response.ok) {
1090
- throw new Error(`Failed to fetch from models.dev: ${response.statusText}`);
1091
- }
1092
- const data = await response.json();
1093
- const providerConfigs = {};
1094
- for (const [providerId, providerInfo] of Object.entries(data)) {
1095
- if (!providerInfo || typeof providerInfo !== "object" || !providerInfo.models) continue;
1096
- const normalizedId = providerId;
1097
- const isOpenAICompatible = providerInfo.npm === "@ai-sdk/openai-compatible" || providerInfo.npm === "@ai-sdk/gateway" || // Vercel AI Gateway is OpenAI-compatible
1098
- normalizedId in OPENAI_COMPATIBLE_OVERRIDES;
1099
- const hasApiAndEnv = providerInfo.api && providerInfo.env && providerInfo.env.length > 0;
1100
- if (isOpenAICompatible || hasApiAndEnv) {
1101
- const modelIds = Object.keys(providerInfo.models).sort();
1102
- let url = providerInfo.api || OPENAI_COMPATIBLE_OVERRIDES[normalizedId]?.url;
1103
- if (url && !url.includes("/chat/completions") && !url.includes("/messages")) {
1104
- url = url.replace(/\/$/, "") + "/chat/completions";
1105
- }
1106
- if (!url) {
1107
- console.info(`Skipping ${normalizedId}: No API URL available`);
1108
- continue;
1109
- }
1110
- const apiKeyEnvVar = providerInfo.env?.[0] || `${normalizedId.toUpperCase().replace(/-/g, "_")}_API_KEY`;
1111
- const apiKeyHeader = OPENAI_COMPATIBLE_OVERRIDES[normalizedId]?.apiKeyHeader || "Authorization";
1112
- providerConfigs[normalizedId] = {
1113
- url,
1114
- apiKeyEnvVar,
1115
- apiKeyHeader,
1116
- name: providerInfo.name || providerId.charAt(0).toUpperCase() + providerId.slice(1),
1117
- models: modelIds.filter((id) => !id.includes(`codex`)),
1118
- // codex requires responses api
1119
- docUrl: providerInfo.doc,
1120
- // Include documentation URL if available
1121
- gateway: `models.dev`
1122
- };
1123
- } else {
1124
- console.info(`Skipped provider ${providerInfo.name}`);
1125
- }
1126
- }
1127
- this.providerConfigs = providerConfigs;
1128
- console.info(`Found ${Object.keys(providerConfigs).length} OpenAI-compatible providers`);
1129
- console.info("Providers:", Object.keys(providerConfigs).sort());
1130
- return providerConfigs;
1131
- }
1132
- buildUrl(modelId, envVars) {
1133
- const [provider, ...modelParts] = modelId.split("/");
1134
- if (!provider || !modelParts.length) {
1135
- return false;
1136
- }
1137
- const config = this.providerConfigs[provider];
1138
- if (!config?.url) {
1139
- return false;
1140
- }
1141
- const baseUrlEnvVar = `${provider.toUpperCase().replace(/-/g, "_")}_BASE_URL`;
1142
- const customBaseUrl = envVars[baseUrlEnvVar];
1143
- return customBaseUrl || config.url;
1144
- }
1145
- buildHeaders(modelId, envVars) {
1146
- const [provider] = modelId.split("/");
1147
- if (!provider) {
1148
- return {};
1149
- }
1150
- const config = this.providerConfigs[provider];
1151
- if (!config) {
1152
- return {};
1153
- }
1154
- const apiKey = typeof config.apiKeyEnvVar === `string` ? envVars[config.apiKeyEnvVar] : void 0;
1155
- if (!apiKey) {
1156
- return {};
1157
- }
1158
- const headers = {};
1159
- if (config.apiKeyHeader === "Authorization" || !config.apiKeyHeader) {
1160
- headers["Authorization"] = `Bearer ${apiKey}`;
1161
- } else {
1162
- headers[config.apiKeyHeader] = apiKey;
1163
- }
1164
- if (provider === "anthropic") {
1165
- headers["anthropic-version"] = "2023-06-01";
1166
- }
1167
- return headers;
1168
- }
1169
- };
1170
-
1171
- // src/llm/model/gateways/netlify.ts
1172
- var NetlifyGateway = class extends MastraModelGateway {
1173
- name = "netlify";
1174
- prefix = "netlify";
1175
- // All providers will be prefixed with "netlify/"
1176
- tokenCache = new InMemoryServerCache();
1177
- async fetchProviders() {
1178
- console.info("Fetching providers from Netlify AI Gateway...");
1179
- const response = await fetch("https://api.netlify.com/api/v1/ai-gateway/providers");
1180
- if (!response.ok) {
1181
- throw new Error(`Failed to fetch from Netlify: ${response.statusText}`);
1182
- }
1183
- const data = await response.json();
1184
- const netlify = {
1185
- apiKeyEnvVar: ["NETLIFY_TOKEN", "NETLIFY_SITE_ID"],
1186
- apiKeyHeader: "Authorization",
1187
- // Netlify uses standard Bearer auth
1188
- name: `Netlify`,
1189
- gateway: `netlify`,
1190
- models: [],
1191
- docUrl: "https://docs.netlify.com/build/ai-gateway/overview/"
1192
- };
1193
- for (const [providerId, provider] of Object.entries(data.providers)) {
1194
- for (const model of provider.models) {
1195
- netlify.models.push(`${providerId}/${model}`);
1196
- }
1197
- }
1198
- console.info(`Found ${Object.keys(data.providers).length} models via Netlify Gateway`);
1199
- return { netlify };
1200
- }
1201
- async buildUrl(modelId, envVars) {
1202
- if (!modelId.startsWith(`${this.prefix}/`)) {
1203
- return false;
1204
- }
1205
- const parts = modelId.split("/");
1206
- if (parts.length < 3) {
1207
- return false;
1208
- }
1209
- const provider = parts[1];
1210
- if (!provider) {
1211
- return false;
1212
- }
1213
- const siteId = envVars["NETLIFY_SITE_ID"];
1214
- const netlifyToken = envVars["NETLIFY_TOKEN"];
1215
- if (!netlifyToken) {
1216
- throw new MastraError({
1217
- id: "NETLIFY_GATEWAY_NO_TOKEN",
1218
- domain: "LLM",
1219
- category: "UNKNOWN",
1220
- text: `Missing NETLIFY_TOKEN environment variable required for model: ${modelId}`
1221
- });
1222
- }
1223
- if (!siteId) {
1224
- throw new MastraError({
1225
- id: "NETLIFY_GATEWAY_NO_SITE_ID",
1226
- domain: "LLM",
1227
- category: "UNKNOWN",
1228
- text: `Missing NETLIFY_SITE_ID environment variable required for model: ${modelId}`
1229
- });
1230
- }
1231
- try {
1232
- const tokenData = await this.getOrFetchToken(siteId, netlifyToken);
1233
- return `${tokenData.url}chat/completions`;
1234
- } catch (error) {
1235
- throw new MastraError({
1236
- id: "NETLIFY_GATEWAY_TOKEN_ERROR",
1237
- domain: "LLM",
1238
- category: "UNKNOWN",
1239
- text: `Failed to get Netlify AI Gateway token for model ${modelId}: ${error instanceof Error ? error.message : String(error)}`
1240
- });
1241
- }
1242
- }
1243
- /**
1244
- * Get cached token or fetch a new site-specific AI Gateway token from Netlify
1245
- */
1246
- async getOrFetchToken(siteId, netlifyToken) {
1247
- const cacheKey = `netlify-token:${siteId}:${netlifyToken}`;
1248
- const cached = await this.tokenCache.get(cacheKey);
1249
- if (cached && cached.expiresAt > Date.now() / 1e3 + 60) {
1250
- return { token: cached.token, url: cached.url };
1251
- }
1252
- const response = await fetch(`https://api.netlify.com/api/v1/sites/${siteId}/ai-gateway/token`, {
1253
- method: "GET",
1254
- headers: {
1255
- Authorization: `Bearer ${netlifyToken}`
1256
- }
1257
- });
1258
- if (!response.ok) {
1259
- const error = await response.text();
1260
- throw new Error(`Failed to get Netlify AI Gateway token: ${response.status} ${error}`);
1261
- }
1262
- const tokenResponse = await response.json();
1263
- await this.tokenCache.set(cacheKey, {
1264
- token: tokenResponse.token,
1265
- url: tokenResponse.url,
1266
- expiresAt: tokenResponse.expires_at
1267
- });
1268
- return { token: tokenResponse.token, url: tokenResponse.url };
1269
- }
1270
- async buildHeaders(modelId, envVars) {
1271
- const siteId = envVars["NETLIFY_SITE_ID"];
1272
- const netlifyToken = envVars["NETLIFY_TOKEN"];
1273
- if (!netlifyToken) {
1274
- throw new MastraError({
1275
- id: "NETLIFY_GATEWAY_NO_TOKEN",
1276
- domain: "LLM",
1277
- category: "UNKNOWN",
1278
- text: `Missing NETLIFY_TOKEN environment variable required for model: ${modelId}`
1279
- });
1280
- }
1281
- if (!siteId) {
1282
- throw new MastraError({
1283
- id: "NETLIFY_GATEWAY_NO_SITE_ID",
1284
- domain: "LLM",
1285
- category: "UNKNOWN",
1286
- text: `Missing NETLIFY_SITE_ID environment variable required for model: ${modelId}`
1287
- });
1288
- }
1289
- try {
1290
- const tokenData = await this.getOrFetchToken(siteId, netlifyToken);
1291
- return {
1292
- Authorization: `Bearer ${tokenData.token}`
1293
- };
1294
- } catch (error) {
1295
- throw new MastraError({
1296
- id: "NETLIFY_GATEWAY_TOKEN_ERROR",
1297
- domain: "LLM",
1298
- category: "UNKNOWN",
1299
- text: `Failed to get Netlify AI Gateway token for model ${modelId}: ${error instanceof Error ? error.message : String(error)}`
1300
- });
1301
- }
1302
- }
1303
- };
1304
-
1305
- // src/llm/model/gateway-resolver.ts
1354
+ // src/llm/model/router.ts
1306
1355
  function getStaticProvidersByGateway(name) {
1307
1356
  return Object.fromEntries(Object.entries(PROVIDER_REGISTRY).filter(([_provider, config]) => config.gateway === name));
1308
1357
  }
1309
1358
  var gateways = [new NetlifyGateway(), new ModelsDevGateway(getStaticProvidersByGateway(`models.dev`))];
1310
- function findGatewayForModel(modelId) {
1311
- const prefixedGateway = gateways.find((g) => g.prefix && modelId.startsWith(`${g.prefix}/`));
1312
- if (prefixedGateway) {
1313
- return prefixedGateway;
1314
- }
1315
- const unprefixedGateways = gateways.filter((g) => !g.prefix);
1316
- for (const gateway of unprefixedGateways) {
1317
- return gateway;
1318
- }
1319
- return null;
1320
- }
1321
- async function resolveModelConfig(modelId, envVars = process.env) {
1322
- const gateway = findGatewayForModel(modelId);
1323
- if (!gateway) {
1324
- return { url: false, headers: {}, resolvedModelId: modelId };
1325
- }
1326
- const url = await gateway.buildUrl(modelId, envVars);
1327
- if (url === false) {
1328
- return { url: false, headers: {}, resolvedModelId: modelId };
1329
- }
1330
- const headers = gateway.buildHeaders ? await gateway.buildHeaders(modelId, envVars) : {};
1331
- let resolvedModelId = modelId;
1332
- const prefix = gateway.prefix ? `${gateway.prefix}/` : null;
1333
- if (prefix && resolvedModelId.startsWith(prefix)) {
1334
- resolvedModelId = resolvedModelId.substring(prefix.length);
1335
- }
1336
- const firstSlashIndex = resolvedModelId.indexOf("/");
1337
- if (firstSlashIndex !== -1) {
1338
- resolvedModelId = resolvedModelId.substring(firstSlashIndex + 1);
1339
- }
1340
- return { url, headers, resolvedModelId };
1341
- }
1342
-
1343
- // src/llm/model/openai-compatible.ts
1344
- function resolveApiKey({ provider, apiKey }) {
1345
- if (apiKey) return apiKey;
1346
- if (provider) {
1347
- const config = getProviderConfig(provider);
1348
- if (typeof config?.apiKeyEnvVar === `string`) {
1349
- return process.env[config.apiKeyEnvVar];
1350
- }
1351
- if (Array.isArray(config?.apiKeyEnvVar)) {
1352
- for (const key of config.apiKeyEnvVar) {
1353
- if (process.env[key]) return process.env[key];
1354
- }
1355
- }
1356
- }
1357
- return void 0;
1358
- }
1359
- var OpenAICompatibleModel = class {
1359
+ var ModelRouterLanguageModel = class _ModelRouterLanguageModel {
1360
1360
  specificationVersion = "v2";
1361
1361
  defaultObjectGenerationMode = "json";
1362
1362
  supportsStructuredOutputs = true;
@@ -1365,215 +1365,29 @@ var OpenAICompatibleModel = class {
1365
1365
  modelId;
1366
1366
  provider;
1367
1367
  config;
1368
- fullModelId;
1369
- // Store the full model ID for gateway resolution
1368
+ gateway;
1370
1369
  constructor(config) {
1371
- let parsedConfig;
1372
- if (typeof config === "string") {
1373
- let isUrl = false;
1374
- try {
1375
- new URL(config);
1376
- isUrl = true;
1377
- } catch {
1378
- }
1379
- if (isUrl) {
1380
- parsedConfig = {
1381
- id: "unknown",
1382
- url: config
1383
- };
1384
- this.provider = "openai-compatible";
1385
- this.fullModelId = "unknown";
1386
- this.config = { id: "unknown", url: config };
1387
- } else {
1388
- this.fullModelId = config;
1389
- const firstSlashIndex = config.indexOf("/");
1390
- if (firstSlashIndex !== -1) {
1391
- const provider = config.substring(0, firstSlashIndex);
1392
- const modelId = config.substring(firstSlashIndex + 1);
1393
- parsedConfig = {
1394
- id: modelId,
1395
- apiKey: resolveApiKey({ provider })
1396
- };
1397
- this.provider = provider;
1398
- } else {
1399
- throw new Error(`Invalid model string: "${config}". Use "provider/model" format or a direct URL.`);
1400
- }
1401
- }
1402
- } else {
1403
- parsedConfig = config;
1404
- this.fullModelId = config.id;
1405
- const parsed = parseModelString(config.id);
1406
- this.provider = parsed.provider || "openai-compatible";
1407
- if (parsed.provider && parsed.modelId !== config.id) {
1408
- parsedConfig.id = parsed.modelId;
1409
- }
1410
- if (!parsedConfig.apiKey) {
1411
- parsedConfig.apiKey = resolveApiKey({ provider: parsed.provider || void 0 });
1412
- }
1370
+ if (typeof config === `string`) config = { id: config };
1371
+ const parsedConfig = { ...config, routerId: config.id };
1372
+ this.gateway = findGatewayForModel(config.id, gateways);
1373
+ const parsed = parseModelRouterId(config.id, this.gateway.prefix);
1374
+ this.provider = parsed.providerId || "openai-compatible";
1375
+ if (parsed.providerId && parsed.modelId !== config.id) {
1376
+ parsedConfig.id = parsed.modelId;
1413
1377
  }
1414
1378
  this.modelId = parsedConfig.id;
1415
1379
  this.config = parsedConfig;
1416
- }
1417
- convertMessagesToOpenAI(messages) {
1418
- return messages.map((msg) => {
1419
- if (msg.role === "system") {
1420
- return {
1421
- role: "system",
1422
- content: msg.content
1423
- };
1424
- }
1425
- if (msg.role === "user") {
1426
- const contentParts = msg.content.map((part) => {
1427
- if (part.type === "text") {
1428
- return { type: "text", text: part.text };
1429
- }
1430
- if (part.type === "file") {
1431
- return {
1432
- type: "image_url",
1433
- image_url: { url: part.data }
1434
- };
1435
- }
1436
- return null;
1437
- }).filter(Boolean);
1438
- if (contentParts.every((p) => p?.type === "text")) {
1439
- return {
1440
- role: "user",
1441
- content: contentParts.map((p) => p?.text || "").join("")
1442
- };
1443
- }
1444
- return {
1445
- role: "user",
1446
- content: contentParts
1447
- };
1448
- }
1449
- if (msg.role === "assistant") {
1450
- const textContent = msg.content.filter((part) => part.type === "text").map((part) => part.text).join("");
1451
- const toolCalls = msg.content.filter((part) => part.type === "tool-call").map((part) => ({
1452
- id: part.toolCallId,
1453
- type: "function",
1454
- function: {
1455
- name: part.toolName,
1456
- arguments: JSON.stringify(part.input || {})
1457
- }
1458
- }));
1459
- return {
1460
- role: "assistant",
1461
- content: textContent || null,
1462
- ...toolCalls.length > 0 && { tool_calls: toolCalls }
1463
- };
1464
- }
1465
- if (msg.role === "tool") {
1466
- return msg.content.map((toolResponse) => ({
1467
- role: "tool",
1468
- tool_call_id: toolResponse.toolCallId,
1469
- content: JSON.stringify(toolResponse.output)
1470
- }));
1471
- }
1472
- return msg;
1473
- }).flat();
1474
- }
1475
- convertToolsToOpenAI(tools) {
1476
- if (!tools || Object.keys(tools).length === 0) return void 0;
1477
- return Object.entries(tools).map(([name, tool]) => {
1478
- if (tool.type === "function") {
1479
- return {
1480
- type: "function",
1481
- function: {
1482
- name: tool.name,
1483
- description: tool.description,
1484
- parameters: tool.inputSchema || {}
1485
- }
1486
- };
1487
- }
1488
- return {
1489
- type: "function",
1490
- function: {
1491
- name,
1492
- description: `Provider tool: ${name}`,
1493
- parameters: {}
1494
- }
1495
- };
1496
- });
1497
- }
1498
- mapFinishReason(reason) {
1499
- switch (reason) {
1500
- case "stop":
1501
- return "stop";
1502
- case "length":
1503
- case "max_tokens":
1504
- return "length";
1505
- case "tool_calls":
1506
- case "function_call":
1507
- return "tool-calls";
1508
- case "content_filter":
1509
- return "content-filter";
1510
- default:
1511
- return "unknown";
1512
- }
1513
- }
1514
- /**
1515
- * Resolve URL and headers for the request
1516
- * This is called fresh for each request to ensure we get the latest values
1517
- * (e.g., Netlify tokens can expire and need to be refreshed)
1518
- */
1519
- async resolveRequestConfig() {
1520
- const shouldUseGateway = !this.config.url;
1521
- if (shouldUseGateway) {
1522
- const { url, headers, resolvedModelId } = await resolveModelConfig(this.fullModelId);
1523
- if (url === false) {
1524
- throw new Error(`No gateway can handle model: ${this.fullModelId}`);
1525
- }
1526
- const finalHeaders = {
1527
- "Content-Type": "application/json",
1528
- ...headers,
1529
- ...this.config.headers
1530
- };
1531
- return { url, headers: finalHeaders, modelId: resolvedModelId };
1532
- } else {
1533
- if (!this.config.url) {
1534
- throw new Error("URL is required for OpenAI-compatible model");
1535
- }
1536
- const headers = {
1537
- "Content-Type": "application/json",
1538
- ...this.config.headers
1539
- };
1540
- if (this.config.apiKey) {
1541
- const providerConfig = this.provider !== "openai-compatible" ? getProviderConfig(this.provider) : void 0;
1542
- if (providerConfig?.apiKeyHeader === "x-api-key") {
1543
- headers["x-api-key"] = this.config.apiKey;
1544
- } else {
1545
- headers["Authorization"] = `Bearer ${this.config.apiKey}`;
1546
- }
1547
- }
1548
- return { url: this.config.url, headers, modelId: this.modelId };
1549
- }
1550
- }
1551
- validateApiKey() {
1552
- const willUseGateway = !this.config.url;
1553
- if (willUseGateway) {
1554
- return;
1555
- }
1556
- if (!this.config.apiKey && this.provider !== "openai-compatible") {
1557
- const providerConfig = getProviderConfig(this.provider);
1558
- if (providerConfig?.apiKeyEnvVar) {
1559
- throw new Error(
1560
- `API key not found for provider "${this.provider}". Please set the ${providerConfig.apiKeyEnvVar} environment variable.`
1561
- );
1562
- } else {
1563
- throw new Error(
1564
- `API key not found for provider "${this.provider}". Please provide an API key in the configuration.`
1565
- );
1566
- }
1567
- }
1380
+ this.gateway = findGatewayForModel(parsedConfig.routerId, gateways);
1568
1381
  }
1569
1382
  async doGenerate() {
1570
1383
  throw new Error(
1571
- "doGenerate is not supported by OpenAICompatibleModel. Mastra only uses streaming (doStream) for all LLM calls."
1384
+ "doGenerate is not supported by Mastra model router. Mastra only uses streaming (doStream) for all LLM calls."
1572
1385
  );
1573
1386
  }
1574
1387
  async doStream(options) {
1388
+ let apiKey;
1575
1389
  try {
1576
- this.validateApiKey();
1390
+ apiKey = await this.gateway.getApiKey(this.config.routerId);
1577
1391
  } catch (error) {
1578
1392
  return {
1579
1393
  stream: new ReadableStream({
@@ -1583,239 +1397,29 @@ var OpenAICompatibleModel = class {
1583
1397
  error: error instanceof Error ? error.message : String(error)
1584
1398
  });
1585
1399
  }
1586
- }),
1587
- warnings: []
1588
- };
1589
- }
1590
- try {
1591
- const { url, headers, modelId: resolvedModelId } = await this.resolveRequestConfig();
1592
- const { prompt, tools, toolChoice, providerOptions } = options;
1593
- const body = {
1594
- messages: this.convertMessagesToOpenAI(prompt),
1595
- model: resolvedModelId,
1596
- stream: true,
1597
- ...providerOptions
1598
- };
1599
- const openAITools = this.convertToolsToOpenAI(tools);
1600
- if (openAITools) {
1601
- body.tools = openAITools;
1602
- if (toolChoice) {
1603
- body.tool_choice = toolChoice.type === "none" ? "none" : toolChoice.type === "required" ? "required" : toolChoice.type === "auto" ? "auto" : toolChoice.type === "tool" ? { type: "function", function: { name: toolChoice.toolName } } : "auto";
1604
- }
1605
- }
1606
- if (options.responseFormat?.type === "json") {
1607
- body.response_format = {
1608
- type: "json_schema",
1609
- json_schema: {
1610
- name: "response",
1611
- strict: true,
1612
- schema: options.responseFormat.schema
1613
- }
1614
- };
1615
- }
1616
- const fetchArgs = {
1617
- method: "POST",
1618
- headers,
1619
- body: JSON.stringify(body),
1620
- signal: options.abortSignal
1621
- };
1622
- const response = await fetch(url, fetchArgs);
1623
- if (!response.ok) {
1624
- const error = await response.text();
1625
- if (response.status === 401 || response.status === 403) {
1626
- const providerConfig = getProviderConfig(this.provider);
1627
- if (providerConfig?.apiKeyEnvVar) {
1628
- throw new Error(
1629
- `Authentication failed for provider "${this.provider}". Please ensure the ${providerConfig.apiKeyEnvVar} environment variable is set with a valid API key.`
1630
- );
1631
- }
1632
- }
1633
- throw new Error(`OpenAI-compatible API error: ${response.status} - ${error}`);
1634
- }
1635
- const reader = response.body?.getReader();
1636
- if (!reader) {
1637
- throw new Error("Response body is not readable");
1638
- }
1639
- const decoder = new TextDecoder();
1640
- let buffer = "";
1641
- let sentStart = false;
1642
- const toolCallBuffers = /* @__PURE__ */ new Map();
1643
- const mapFinishReason = this.mapFinishReason.bind(this);
1644
- const modelId = this.modelId;
1645
- let isActiveText = false;
1646
- const stream = new ReadableStream({
1647
- async start(controller) {
1648
- try {
1649
- controller.enqueue({
1650
- type: "stream-start",
1651
- warnings: []
1652
- });
1653
- while (true) {
1654
- const { done, value } = await reader.read();
1655
- if (done) {
1656
- for (const [_, toolCall] of toolCallBuffers) {
1657
- if (!toolCall.sent && toolCall.id && toolCall.name && toolCall.args) {
1658
- controller.enqueue({
1659
- type: "tool-call",
1660
- toolCallId: toolCall.id,
1661
- toolName: toolCall.name,
1662
- input: toolCall.args || "{}"
1663
- });
1664
- }
1665
- }
1666
- controller.close();
1667
- break;
1668
- }
1669
- buffer += decoder.decode(value, { stream: true });
1670
- const lines = buffer.split("\n");
1671
- buffer = lines.pop() || "";
1672
- for (const line of lines) {
1673
- if (line.trim() === "" || line.trim() === "data: [DONE]") {
1674
- continue;
1675
- }
1676
- if (line.startsWith("data: ")) {
1677
- try {
1678
- const data = JSON.parse(line.slice(6));
1679
- if (!sentStart && data.id) {
1680
- controller.enqueue({
1681
- type: "response-metadata",
1682
- id: data.id,
1683
- modelId: data.model || modelId,
1684
- timestamp: new Date(data.created ? data.created * 1e3 : Date.now())
1685
- });
1686
- sentStart = true;
1687
- }
1688
- const choice = data.choices?.[0];
1689
- if (!choice) continue;
1690
- if (choice.delta?.content) {
1691
- if (!isActiveText) {
1692
- controller.enqueue({ type: "text-start", id: "text-1" });
1693
- isActiveText = true;
1694
- }
1695
- controller.enqueue({
1696
- type: "text-delta",
1697
- id: "text-1",
1698
- delta: choice.delta.content
1699
- });
1700
- } else if (isActiveText) {
1701
- controller.enqueue({ type: "text-end", id: "text-1" });
1702
- isActiveText = false;
1703
- }
1704
- if (choice.delta?.tool_calls) {
1705
- for (const toolCall of choice.delta.tool_calls) {
1706
- const index = toolCall.index;
1707
- if (!toolCallBuffers.has(index)) {
1708
- if (toolCall.id && toolCall.function?.name) {
1709
- controller.enqueue({
1710
- type: "tool-input-start",
1711
- id: toolCall.id,
1712
- toolName: toolCall.function.name
1713
- });
1714
- }
1715
- toolCallBuffers.set(index, {
1716
- id: toolCall.id || "",
1717
- name: toolCall.function?.name || "",
1718
- args: ""
1719
- });
1720
- }
1721
- const buffer2 = toolCallBuffers.get(index);
1722
- if (toolCall.id) {
1723
- buffer2.id = toolCall.id;
1724
- }
1725
- if (toolCall.function?.name) {
1726
- buffer2.name = toolCall.function.name;
1727
- }
1728
- if (toolCall.function?.arguments) {
1729
- buffer2.args += toolCall.function.arguments;
1730
- controller.enqueue({
1731
- type: "tool-input-delta",
1732
- id: buffer2.id,
1733
- delta: toolCall.function.arguments
1734
- });
1735
- try {
1736
- JSON.parse(buffer2.args);
1737
- if (buffer2.id && buffer2.name) {
1738
- controller.enqueue({
1739
- type: "tool-input-end",
1740
- id: buffer2.id
1741
- });
1742
- controller.enqueue({
1743
- type: "tool-call",
1744
- toolCallId: buffer2.id,
1745
- toolName: buffer2.name,
1746
- input: buffer2.args
1747
- });
1748
- toolCallBuffers.set(index, {
1749
- id: buffer2.id,
1750
- name: buffer2.name,
1751
- args: buffer2.args,
1752
- sent: true
1753
- });
1754
- }
1755
- } catch {
1756
- }
1757
- }
1758
- }
1759
- }
1760
- if (choice.finish_reason) {
1761
- toolCallBuffers.clear();
1762
- controller.enqueue({
1763
- type: "finish",
1764
- finishReason: mapFinishReason(choice.finish_reason),
1765
- usage: data.usage ? {
1766
- inputTokens: data.usage.prompt_tokens || 0,
1767
- outputTokens: data.usage.completion_tokens || 0,
1768
- totalTokens: data.usage.total_tokens || 0
1769
- } : {
1770
- inputTokens: 0,
1771
- outputTokens: 0,
1772
- totalTokens: 0
1773
- }
1774
- });
1775
- }
1776
- } catch (e) {
1777
- console.error("Error parsing SSE data:", e);
1778
- }
1779
- }
1780
- }
1781
- }
1782
- } catch (error) {
1783
- return {
1784
- stream: new ReadableStream({
1785
- start(controller2) {
1786
- controller2.enqueue({
1787
- type: "error",
1788
- error: error instanceof Error ? error.message : String(error)
1789
- });
1790
- }
1791
- }),
1792
- warnings: []
1793
- };
1794
- }
1795
- }
1796
- });
1797
- return {
1798
- stream,
1799
- request: { body: JSON.stringify(body) },
1800
- response: { headers: Object.fromEntries(response.headers.entries()) },
1801
- warnings: []
1802
- };
1803
- } catch (error) {
1804
- return {
1805
- stream: new ReadableStream({
1806
- start(controller) {
1807
- controller.enqueue({
1808
- type: "error",
1809
- error: error instanceof Error ? error.message : String(error)
1810
- });
1811
- }
1812
- }),
1813
- warnings: []
1400
+ })
1814
1401
  };
1815
1402
  }
1403
+ const model = await this.resolveLanguageModel({
1404
+ apiKey,
1405
+ ...parseModelRouterId(this.config.routerId, this.gateway.prefix)
1406
+ });
1407
+ return model.doStream(options);
1408
+ }
1409
+ async resolveLanguageModel({
1410
+ modelId,
1411
+ providerId,
1412
+ apiKey
1413
+ }) {
1414
+ const key = createHash("sha256").update(this.gateway.name + modelId + providerId + apiKey).digest("hex");
1415
+ if (_ModelRouterLanguageModel.modelInstances.has(key)) return _ModelRouterLanguageModel.modelInstances.get(key);
1416
+ const modelInstance = await this.gateway.resolveLanguageModel({ modelId, providerId, apiKey });
1417
+ _ModelRouterLanguageModel.modelInstances.set(key, modelInstance);
1418
+ return modelInstance;
1816
1419
  }
1420
+ static modelInstances = /* @__PURE__ */ new Map();
1817
1421
  };
1818
1422
 
1819
- export { OpenAICompatibleModel, PROVIDER_REGISTRY, getProviderConfig, parseModelString };
1820
- //# sourceMappingURL=chunk-AND6J5LG.js.map
1821
- //# sourceMappingURL=chunk-AND6J5LG.js.map
1423
+ export { ModelRouterLanguageModel, PROVIDER_REGISTRY, getProviderConfig, parseModelString };
1424
+ //# sourceMappingURL=chunk-W2WXYTYI.js.map
1425
+ //# sourceMappingURL=chunk-W2WXYTYI.js.map