@juspay/neurolink 12.5.0 → 12.5.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 (47) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/dist/adapters/providerImageAdapter.js +43 -19
  3. package/dist/browser/neurolink.min.js +414 -414
  4. package/dist/cli/commands/setup.d.ts +12 -7
  5. package/dist/cli/commands/setup.js +17 -16
  6. package/dist/cli/proxy-clients/openCode.js +16 -3
  7. package/dist/constants/contextWindows.js +23 -95
  8. package/dist/constants/enums.d.ts +111 -216
  9. package/dist/constants/enums.js +124 -240
  10. package/dist/factories/providerDescriptors.d.ts +2 -4
  11. package/dist/factories/providerDescriptors.js +83 -127
  12. package/dist/models/manifestRegistry.js +53 -4
  13. package/dist/providers/catalog/cerebras.json +75 -0
  14. package/dist/providers/catalog/cloudflare.json +121 -0
  15. package/dist/providers/catalog/fireworks.json +124 -0
  16. package/dist/providers/catalog/groq.json +127 -0
  17. package/dist/providers/catalog/index.generated.d.ts +3 -0
  18. package/dist/providers/catalog/index.generated.js +33 -0
  19. package/dist/providers/catalog/loader.d.ts +6 -0
  20. package/dist/providers/catalog/loader.js +115 -0
  21. package/dist/providers/catalog/mistral.json +244 -0
  22. package/dist/providers/catalog/perplexity.json +103 -0
  23. package/dist/providers/catalog/provider-catalog.schema.json +351 -0
  24. package/dist/providers/catalog/sambanova.json +129 -0
  25. package/dist/providers/catalog/schema.d.ts +123 -0
  26. package/dist/providers/catalog/schema.js +310 -0
  27. package/dist/providers/catalog/together-ai.json +172 -0
  28. package/dist/providers/catalog/xai.json +108 -0
  29. package/dist/providers/openaiCompatCatalog.d.ts +13 -13
  30. package/dist/providers/openaiCompatCatalog.js +15 -326
  31. package/dist/types/index.d.ts +2 -0
  32. package/dist/types/index.js +2 -0
  33. package/dist/types/providerCatalog.d.ts +149 -0
  34. package/dist/types/providerCatalog.generated.d.ts +2 -0
  35. package/dist/types/providerCatalog.generated.js +1 -0
  36. package/dist/types/providerCatalog.js +7 -0
  37. package/dist/types/providers.d.ts +14 -14
  38. package/dist/utils/modelChoices.d.ts +11 -3
  39. package/dist/utils/modelChoices.js +84 -190
  40. package/dist/utils/pricing.js +92 -127
  41. package/dist/utils/providerConfig.d.ts +1 -1
  42. package/dist/utils/providerConfig.js +24 -108
  43. package/package.json +2 -1
  44. package/dist/models/manifests/cerebras.d.ts +0 -9
  45. package/dist/models/manifests/cerebras.js +0 -19
  46. package/dist/models/manifests/sambanova.d.ts +0 -11
  47. package/dist/models/manifests/sambanova.js +0 -42
@@ -0,0 +1,310 @@
1
+ /**
2
+ * zod validator for the single-JSON provider catalog authoring format.
3
+ * Mirrors src/lib/types/providerCatalog.ts field-for-field with
4
+ * z.strictObject (unknown keys are authoring mistakes) plus the
5
+ * cross-field refinements the plain types cannot express. See
6
+ * docs/superpowers/plans/2026-08-28-provider-json-catalog-spec.md.
7
+ *
8
+ * provider-catalog.schema.json is a hand-kept JSON Schema mirror for
9
+ * editor validation only — this file is the authoritative validator.
10
+ */
11
+ import { z } from "zod";
12
+ const IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
13
+ const KEBAB_ID_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
14
+ const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
15
+ const catalogPricingPerMTokSchema = z.strictObject({
16
+ input: z.number(),
17
+ output: z.number(),
18
+ cachedInput: z.number().optional(),
19
+ });
20
+ const catalogModelStatusSchema = z.enum(["production", "preview", "retired"]);
21
+ const catalogModelSpecSchema = z.strictObject({
22
+ contextWindow: z.number().optional(),
23
+ maxOutputTokens: z.number().optional(),
24
+ pricingPerMTok: catalogPricingPerMTokSchema.optional(),
25
+ vision: z.boolean(),
26
+ status: catalogModelStatusSchema,
27
+ description: z.string(),
28
+ enumMember: z
29
+ .string()
30
+ .regex(IDENTIFIER_PATTERN, "enumMember must be a valid identifier")
31
+ .optional(),
32
+ });
33
+ const catalogWireSchema = z
34
+ .strictObject({
35
+ baseURL: z.string().optional(),
36
+ baseURLTemplate: z.string().optional(),
37
+ extraCredentials: z.array(z.string()).optional(),
38
+ missingCredentialMessage: z.string().optional(),
39
+ envOverrides: z
40
+ .strictObject({
41
+ apiKey: z.string().optional(),
42
+ baseURL: z.string().optional(),
43
+ model: z.string().optional(),
44
+ })
45
+ .optional(),
46
+ })
47
+ .superRefine((wire, ctx) => {
48
+ const hasBaseURL = wire.baseURL !== undefined;
49
+ const hasTemplate = wire.baseURLTemplate !== undefined;
50
+ if (hasBaseURL === hasTemplate) {
51
+ ctx.addIssue({
52
+ code: "custom",
53
+ path: ["baseURL"],
54
+ message: "wire requires exactly one of baseURL or baseURLTemplate",
55
+ });
56
+ }
57
+ if (wire.extraCredentials !== undefined) {
58
+ if (wire.extraCredentials.length !== 1) {
59
+ ctx.addIssue({
60
+ code: "custom",
61
+ path: ["extraCredentials"],
62
+ message: "wire.extraCredentials must have exactly one entry",
63
+ });
64
+ }
65
+ else if (!IDENTIFIER_PATTERN.test(wire.extraCredentials[0])) {
66
+ // Embedded verbatim in generated credential typing — a non-identifier
67
+ // value would emit invalid TypeScript.
68
+ ctx.addIssue({
69
+ code: "custom",
70
+ path: ["extraCredentials", 0],
71
+ message: "wire.extraCredentials entry must be a valid identifier",
72
+ });
73
+ }
74
+ if (!hasTemplate) {
75
+ ctx.addIssue({
76
+ code: "custom",
77
+ path: ["extraCredentials"],
78
+ message: "wire.extraCredentials is only valid with baseURLTemplate",
79
+ });
80
+ }
81
+ }
82
+ if (wire.missingCredentialMessage !== undefined && !hasTemplate) {
83
+ ctx.addIssue({
84
+ code: "custom",
85
+ path: ["missingCredentialMessage"],
86
+ message: "wire.missingCredentialMessage is only valid with baseURLTemplate",
87
+ });
88
+ }
89
+ if (hasTemplate &&
90
+ wire.extraCredentials !== undefined &&
91
+ wire.extraCredentials.length === 1) {
92
+ const placeholder = `{${wire.extraCredentials[0]}}`;
93
+ if (!wire.baseURLTemplate?.includes(placeholder)) {
94
+ ctx.addIssue({
95
+ code: "custom",
96
+ path: ["baseURLTemplate"],
97
+ message: "wire.baseURLTemplate must contain the extraCredentials[0] placeholder",
98
+ });
99
+ }
100
+ }
101
+ });
102
+ const catalogErrorRuleClassSchema = z.enum([
103
+ "authentication",
104
+ "rate-limit",
105
+ "invalid-model",
106
+ "network",
107
+ "provider",
108
+ ]);
109
+ const catalogErrorRuleJsonSchema = z
110
+ .strictObject({
111
+ status: z.number().optional(),
112
+ pattern: z.string().optional(),
113
+ class: catalogErrorRuleClassSchema,
114
+ message: z.string(),
115
+ })
116
+ .superRefine((rule, ctx) => {
117
+ if (rule.status === undefined && rule.pattern === undefined) {
118
+ ctx.addIssue({
119
+ code: "custom",
120
+ path: [],
121
+ message: "errorRules entry requires status or pattern",
122
+ });
123
+ }
124
+ if (rule.pattern !== undefined) {
125
+ try {
126
+ new RegExp(rule.pattern, "i");
127
+ }
128
+ catch {
129
+ ctx.addIssue({
130
+ code: "custom",
131
+ path: ["pattern"],
132
+ message: "errorRules pattern must compile as a regular expression",
133
+ });
134
+ }
135
+ }
136
+ });
137
+ const catalogQuirksSchema = z.strictObject({
138
+ timeoutErrorClass: z.literal("provider").optional(),
139
+ registryDefaultIgnoresModelEnvVar: z.boolean().optional(),
140
+ });
141
+ const catalogBillingPolicySchema = z.enum([
142
+ "free-tier",
143
+ "free-with-card",
144
+ "no-free-tier",
145
+ ]);
146
+ const catalogSetupSchema = z.strictObject({
147
+ url: z.string(),
148
+ apiKeyFormat: z.string().nullable(),
149
+ billingPolicy: catalogBillingPolicySchema,
150
+ instructions: z.array(z.string()),
151
+ description: z.string().optional(),
152
+ });
153
+ const catalogProbeEvidenceSchema = z.strictObject({
154
+ date: z.string().regex(DATE_PATTERN, "date must match YYYY-MM-DD"),
155
+ status: z.number().optional(),
156
+ code: z.string().optional(),
157
+ method: z.string().optional(),
158
+ });
159
+ const catalogEvidenceSchema = z.strictObject({
160
+ rosterVerified: catalogProbeEvidenceSchema,
161
+ authProbe: catalogProbeEvidenceSchema.optional(),
162
+ billingProbe: catalogProbeEvidenceSchema.optional(),
163
+ liveMatrix: z
164
+ .strictObject({
165
+ date: z.string().regex(DATE_PATTERN, "date must match YYYY-MM-DD"),
166
+ result: z.string(),
167
+ })
168
+ .nullable(),
169
+ addedInPR: z.string(),
170
+ });
171
+ const catalogCapabilitiesSchema = z.strictObject({
172
+ text: z.boolean(),
173
+ streaming: z.boolean(),
174
+ tools: z.boolean(),
175
+ toolsWithStreaming: z.boolean(),
176
+ structuredOutput: z.boolean(),
177
+ structuredOutputWithTools: z.boolean(),
178
+ embeddings: z.boolean(),
179
+ thinking: z.boolean(),
180
+ });
181
+ const catalogModelsSchema = z
182
+ .strictObject({
183
+ default: z.string(),
184
+ fallbacks: z.array(z.string()),
185
+ fallbackModelName: z.string().optional(),
186
+ registryDefaultModel: z.string().optional(),
187
+ defaultContextWindow: z.number(),
188
+ defaultMaxOutputTokens: z.number(),
189
+ catalog: z.record(z.string(), catalogModelSpecSchema),
190
+ topModels: z.array(z.string()).min(1).optional(),
191
+ visionModel: z.string().optional(),
192
+ // Deliberately NOT constrained to catalog keys: testModel captures what
193
+ // the testing account can actually reach today, which may be a model
194
+ // the transcribed catalog predates.
195
+ testModel: z.string().min(1).optional(),
196
+ })
197
+ .superRefine((models, ctx) => {
198
+ const catalogKeys = new Set(Object.keys(models.catalog));
199
+ if (models.fallbacks.length === 0) {
200
+ // The loader's fallbackModelName default is fallbacks[1] ?? fallbacks[0],
201
+ // which depends on fallbacks[0] existing.
202
+ ctx.addIssue({
203
+ code: "custom",
204
+ path: ["fallbacks"],
205
+ message: "models.fallbacks must have at least one entry",
206
+ });
207
+ }
208
+ if (!catalogKeys.has(models.default)) {
209
+ ctx.addIssue({
210
+ code: "custom",
211
+ path: ["default"],
212
+ message: "models.default must be a key of models.catalog",
213
+ });
214
+ }
215
+ models.fallbacks.forEach((fallback, index) => {
216
+ if (!catalogKeys.has(fallback)) {
217
+ ctx.addIssue({
218
+ code: "custom",
219
+ path: ["fallbacks", index],
220
+ message: "models.fallbacks entry must be a key of models.catalog",
221
+ });
222
+ }
223
+ });
224
+ if (models.fallbackModelName !== undefined &&
225
+ !catalogKeys.has(models.fallbackModelName)) {
226
+ ctx.addIssue({
227
+ code: "custom",
228
+ path: ["fallbackModelName"],
229
+ message: "models.fallbackModelName must be a key of models.catalog",
230
+ });
231
+ }
232
+ if (models.registryDefaultModel !== undefined &&
233
+ !catalogKeys.has(models.registryDefaultModel)) {
234
+ ctx.addIssue({
235
+ code: "custom",
236
+ path: ["registryDefaultModel"],
237
+ message: "models.registryDefaultModel must be a key of models.catalog",
238
+ });
239
+ }
240
+ if (models.topModels !== undefined) {
241
+ models.topModels.forEach((modelId, index) => {
242
+ if (!catalogKeys.has(modelId)) {
243
+ ctx.addIssue({
244
+ code: "custom",
245
+ path: ["topModels", index],
246
+ message: "models.topModels entry must be a key of models.catalog",
247
+ });
248
+ }
249
+ });
250
+ const seen = new Set();
251
+ models.topModels.forEach((modelId, index) => {
252
+ if (seen.has(modelId)) {
253
+ ctx.addIssue({
254
+ code: "custom",
255
+ path: ["topModels", index],
256
+ message: "models.topModels must not contain duplicate entries",
257
+ });
258
+ }
259
+ seen.add(modelId);
260
+ });
261
+ }
262
+ if (models.visionModel !== undefined) {
263
+ const spec = models.catalog[models.visionModel];
264
+ if (!spec) {
265
+ ctx.addIssue({
266
+ code: "custom",
267
+ path: ["visionModel"],
268
+ message: "models.visionModel must be a key of models.catalog",
269
+ });
270
+ }
271
+ else if (!spec.vision) {
272
+ ctx.addIssue({
273
+ code: "custom",
274
+ path: ["visionModel"],
275
+ message: "models.visionModel entry must have vision: true",
276
+ });
277
+ }
278
+ }
279
+ });
280
+ export const providerCatalogJsonSchema = z.strictObject({
281
+ $schema: z.string().optional(),
282
+ id: z.string().regex(KEBAB_ID_PATTERN, "id must be kebab-case"),
283
+ displayName: z.string(),
284
+ enumTypeName: z
285
+ .string()
286
+ .regex(IDENTIFIER_PATTERN, "enumTypeName must be a valid identifier")
287
+ .optional(),
288
+ credentialsKey: z
289
+ .string()
290
+ .regex(IDENTIFIER_PATTERN, "credentialsKey must be a valid identifier")
291
+ .optional(),
292
+ aliases: z.array(z.string()),
293
+ tier: z.literal(2),
294
+ wire: catalogWireSchema,
295
+ models: catalogModelsSchema,
296
+ capabilities: catalogCapabilitiesSchema,
297
+ errorRules: z.array(catalogErrorRuleJsonSchema),
298
+ quirks: catalogQuirksSchema.optional(),
299
+ setup: catalogSetupSchema,
300
+ evidence: catalogEvidenceSchema,
301
+ });
302
+ export function parseProviderCatalogJson(raw, sourcePath) {
303
+ const result = providerCatalogJsonSchema.safeParse(raw);
304
+ if (!result.success) {
305
+ throw new Error(`Invalid provider catalog file ${sourcePath}: ${result.error.issues
306
+ .map((i) => `${i.path.join(".")}: ${i.message}`)
307
+ .join("; ")}`);
308
+ }
309
+ return result.data;
310
+ }
@@ -0,0 +1,172 @@
1
+ {
2
+ "$schema": "./provider-catalog.schema.json",
3
+ "id": "together-ai",
4
+ "displayName": "Together AI",
5
+ "enumTypeName": "TogetherAIModels",
6
+ "credentialsKey": "together",
7
+ "aliases": ["together"],
8
+ "tier": 2,
9
+ "wire": {
10
+ "baseURL": "https://api.together.xyz/v1",
11
+ "envOverrides": {
12
+ "apiKey": "TOGETHER_API_KEY",
13
+ "baseURL": "TOGETHER_BASE_URL",
14
+ "model": "TOGETHER_MODEL"
15
+ }
16
+ },
17
+ "models": {
18
+ "default": "meta-llama/Llama-3.3-70B-Instruct-Turbo",
19
+ "fallbackModelName": "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
20
+ "fallbacks": [
21
+ "meta-llama/Llama-3.3-70B-Instruct-Turbo",
22
+ "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo",
23
+ "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
24
+ "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
25
+ "mistralai/Mixtral-8x22B-Instruct-v0.1",
26
+ "Qwen/Qwen2.5-72B-Instruct-Turbo",
27
+ "deepseek-ai/DeepSeek-R1",
28
+ "deepseek-ai/DeepSeek-V3"
29
+ ],
30
+ "defaultContextWindow": 128000,
31
+ "defaultMaxOutputTokens": 4096,
32
+ "catalog": {
33
+ "meta-llama/Llama-3.3-70B-Instruct-Turbo": {
34
+ "enumMember": "LLAMA_3_3_70B_INSTRUCT_TURBO",
35
+ "contextWindow": 128000,
36
+ "pricingPerMTok": { "input": 0.88, "output": 0.88 },
37
+ "vision": false,
38
+ "status": "production",
39
+ "description": "Recommended - Llama 3.3 70B Turbo"
40
+ },
41
+ "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo": {
42
+ "enumMember": "LLAMA_3_1_405B_INSTRUCT_TURBO",
43
+ "contextWindow": 128000,
44
+ "pricingPerMTok": { "input": 3.5, "output": 3.5 },
45
+ "vision": false,
46
+ "status": "production",
47
+ "description": "Flagship 405B"
48
+ },
49
+ "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo": {
50
+ "enumMember": "LLAMA_3_1_70B_INSTRUCT_TURBO",
51
+ "contextWindow": 128000,
52
+ "pricingPerMTok": { "input": 0.88, "output": 0.88 },
53
+ "vision": false,
54
+ "status": "production",
55
+ "description": "Llama 3.1 70B Instruct Turbo"
56
+ },
57
+ "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo": {
58
+ "enumMember": "LLAMA_3_1_8B_INSTRUCT_TURBO",
59
+ "contextWindow": 128000,
60
+ "pricingPerMTok": { "input": 0.18, "output": 0.18 },
61
+ "vision": false,
62
+ "status": "production",
63
+ "description": "Llama 3.1 8B Instruct Turbo — fastest"
64
+ },
65
+ "mistralai/Mixtral-8x22B-Instruct-v0.1": {
66
+ "enumMember": "MIXTRAL_8X22B_INSTRUCT",
67
+ "contextWindow": 65536,
68
+ "pricingPerMTok": { "input": 1.2, "output": 1.2 },
69
+ "vision": false,
70
+ "status": "production",
71
+ "description": "Mistral 8x22B MoE"
72
+ },
73
+ "mistralai/Mixtral-8x7B-Instruct-v0.1": {
74
+ "enumMember": "MIXTRAL_8X7B_INSTRUCT",
75
+ "contextWindow": 32768,
76
+ "pricingPerMTok": { "input": 0.6, "output": 0.6 },
77
+ "vision": false,
78
+ "status": "production",
79
+ "description": "Mixtral 8x7B Instruct"
80
+ },
81
+ "Qwen/Qwen2.5-72B-Instruct-Turbo": {
82
+ "enumMember": "QWEN_2_5_72B_INSTRUCT_TURBO",
83
+ "contextWindow": 32768,
84
+ "pricingPerMTok": { "input": 1.2, "output": 1.2 },
85
+ "vision": false,
86
+ "status": "production",
87
+ "description": "Qwen 2.5 72B Turbo"
88
+ },
89
+ "Qwen/Qwen2.5-Coder-32B-Instruct": {
90
+ "enumMember": "QWEN_2_5_CODER_32B",
91
+ "contextWindow": 32768,
92
+ "vision": false,
93
+ "status": "production",
94
+ "description": "Qwen 2.5 Coder 32B Instruct"
95
+ },
96
+ "deepseek-ai/DeepSeek-R1": {
97
+ "enumMember": "DEEPSEEK_R1",
98
+ "contextWindow": 64000,
99
+ "pricingPerMTok": { "input": 7.0, "output": 7.0 },
100
+ "vision": false,
101
+ "status": "production",
102
+ "description": "DeepSeek R1 reasoning"
103
+ },
104
+ "deepseek-ai/DeepSeek-V3": {
105
+ "enumMember": "DEEPSEEK_V3",
106
+ "contextWindow": 64000,
107
+ "pricingPerMTok": { "input": 1.25, "output": 1.25 },
108
+ "vision": false,
109
+ "status": "production",
110
+ "description": "DeepSeek V3"
111
+ },
112
+ "google/gemma-2-27b-it": {
113
+ "enumMember": "GEMMA_2_27B_IT",
114
+ "contextWindow": 8192,
115
+ "vision": false,
116
+ "status": "production",
117
+ "description": "Google Gemma 2 27B IT"
118
+ },
119
+ "microsoft/WizardLM-2-8x22B": {
120
+ "enumMember": "WIZARDLM_2_8X22B",
121
+ "contextWindow": 65536,
122
+ "vision": false,
123
+ "status": "production",
124
+ "description": "WizardLM 2 8x22B"
125
+ }
126
+ },
127
+ "topModels": [
128
+ "meta-llama/Llama-3.3-70B-Instruct-Turbo",
129
+ "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo",
130
+ "Qwen/Qwen2.5-72B-Instruct-Turbo",
131
+ "deepseek-ai/DeepSeek-R1",
132
+ "mistralai/Mixtral-8x22B-Instruct-v0.1"
133
+ ]
134
+ },
135
+ "capabilities": {
136
+ "text": true,
137
+ "streaming": true,
138
+ "tools": true,
139
+ "toolsWithStreaming": true,
140
+ "structuredOutput": true,
141
+ "structuredOutputWithTools": true,
142
+ "embeddings": false,
143
+ "thinking": false
144
+ },
145
+ "errorRules": [
146
+ {
147
+ "status": 401,
148
+ "pattern": "Invalid API key|Authentication",
149
+ "class": "authentication",
150
+ "message": "Invalid Together AI API key. Get one at https://api.together.xyz/settings/api-keys"
151
+ }
152
+ ],
153
+ "setup": {
154
+ "url": "https://api.together.xyz/settings/api-keys",
155
+ "apiKeyFormat": null,
156
+ "billingPolicy": "free-with-card",
157
+ "instructions": [
158
+ "1. Visit: https://api.together.xyz/settings/api-keys",
159
+ "2. Sign in to your Together AI account",
160
+ "3. Create a new API key",
161
+ "4. Set {apiKeyEnvVar} in your .env file"
162
+ ]
163
+ },
164
+ "evidence": {
165
+ "rosterVerified": {
166
+ "date": "2026-08-28",
167
+ "method": "transcribed from pre-migration TS catalog"
168
+ },
169
+ "liveMatrix": null,
170
+ "addedInPR": "https://github.com/juspay/neurolink/pull/1587"
171
+ }
172
+ }
@@ -0,0 +1,108 @@
1
+ {
2
+ "$schema": "./provider-catalog.schema.json",
3
+ "id": "xai",
4
+ "displayName": "xAI",
5
+ "aliases": ["grok"],
6
+ "tier": 2,
7
+ "wire": {
8
+ "baseURL": "https://api.x.ai/v1"
9
+ },
10
+ "models": {
11
+ "default": "grok-3",
12
+ "fallbacks": [
13
+ "grok-3",
14
+ "grok-3-mini",
15
+ "grok-2-latest",
16
+ "grok-2-vision-latest",
17
+ "grok-beta"
18
+ ],
19
+ "defaultContextWindow": 131072,
20
+ "defaultMaxOutputTokens": 4096,
21
+ "catalog": {
22
+ "grok-3": {
23
+ "contextWindow": 131072,
24
+ "pricingPerMTok": { "input": 3.0, "output": 15.0 },
25
+ "vision": false,
26
+ "status": "production",
27
+ "description": "Recommended - Latest flagship Grok"
28
+ },
29
+ "grok-3-mini": {
30
+ "contextWindow": 131072,
31
+ "pricingPerMTok": { "input": 0.3, "output": 0.5 },
32
+ "vision": false,
33
+ "status": "production",
34
+ "description": "Faster + cheaper Grok 3"
35
+ },
36
+ "grok-2-latest": {
37
+ "contextWindow": 131072,
38
+ "pricingPerMTok": { "input": 2.0, "output": 10.0 },
39
+ "vision": false,
40
+ "status": "production",
41
+ "description": "Previous flagship"
42
+ },
43
+ "grok-2-vision-latest": {
44
+ "contextWindow": 32768,
45
+ "pricingPerMTok": { "input": 2.0, "output": 10.0 },
46
+ "vision": true,
47
+ "status": "production",
48
+ "description": "Multimodal (text + images)"
49
+ },
50
+ "grok-beta": {
51
+ "contextWindow": 131072,
52
+ "pricingPerMTok": { "input": 5.0, "output": 15.0 },
53
+ "vision": false,
54
+ "status": "preview",
55
+ "description": "Pre-release / experimental"
56
+ }
57
+ },
58
+ "topModels": [
59
+ "grok-3",
60
+ "grok-3-mini",
61
+ "grok-2-vision-latest",
62
+ "grok-2-latest",
63
+ "grok-beta"
64
+ ]
65
+ },
66
+ "capabilities": {
67
+ "text": true,
68
+ "streaming": true,
69
+ "tools": true,
70
+ "toolsWithStreaming": true,
71
+ "structuredOutput": true,
72
+ "structuredOutputWithTools": true,
73
+ "embeddings": false,
74
+ "thinking": false
75
+ },
76
+ "errorRules": [
77
+ {
78
+ "status": 401,
79
+ "pattern": "Invalid API key|Authentication|invalid_api_key",
80
+ "class": "authentication",
81
+ "message": "Invalid xAI API key. Please check your {apiKeyEnvVar} environment variable. Get one at https://console.x.ai/"
82
+ },
83
+ {
84
+ "pattern": "insufficient_quota|quota exceeded",
85
+ "class": "provider",
86
+ "message": "xAI account has insufficient quota. Top up at https://console.x.ai/"
87
+ }
88
+ ],
89
+ "setup": {
90
+ "url": "https://console.x.ai/",
91
+ "apiKeyFormat": null,
92
+ "billingPolicy": "no-free-tier",
93
+ "instructions": [
94
+ "1. Visit: https://console.x.ai/",
95
+ "2. Sign in with your xAI account",
96
+ "3. Create an API key",
97
+ "4. Set {apiKeyEnvVar} in your .env file"
98
+ ]
99
+ },
100
+ "evidence": {
101
+ "rosterVerified": {
102
+ "date": "2026-08-28",
103
+ "method": "transcribed from pre-migration TS catalog"
104
+ },
105
+ "liveMatrix": null,
106
+ "addedInPR": "https://github.com/juspay/neurolink/pull/1587"
107
+ }
108
+ }
@@ -6,19 +6,19 @@ import type { OpenAICompatCatalogEntry } from "../types/index.js";
6
6
  * for the class that reads these entries, and providerRegistry.ts for the
7
7
  * registration loop that consumes this array.
8
8
  *
9
- * `errorRules` mirrors each provider's LIVE `formatProviderError` rule array
10
- * (post plan-07/wave-2 migration), not the original hand-rolled ladder these
11
- * providers had when plan 05 was first drafted: every provider below now
12
- * keeps only its bespoke rule(s) auth, plus Groq's model_decommissioned and
13
- * xAI's insufficient_quota before spreading the SAME exported
14
- * `DEFAULT_ERROR_RULES` constant that the live subclasses spread (never an
15
- * inlined copy, so this catalog cannot drift from that table independently).
16
- * See plan-05/progress.md Ruling R4 for the full rationale.
9
+ * The entries themselves are derived from the JSON catalog
10
+ * (src/lib/providers/catalog/<id>.json) via buildCatalogEntries() that
11
+ * JSON is now the single source of truth for these 9 providers' identity,
12
+ * models, error rules and wire config. See
13
+ * src/lib/providers/catalog/loader.ts for the derivation logic and
14
+ * docs/superpowers/plans/2026-08-28-provider-json-catalog-spec.md for the
15
+ * authoring format.
17
16
  *
18
- * To add a new zero-quirk OpenAI-compatible provider: add one entry here.
19
- * Do NOT add a provider here if it needs any hook override beyond the 3
20
- * mandatory ones (getProviderName/getDefaultModel/formatProviderError)
21
- * write a dedicated subclass instead (see deepseek.ts, azureOpenai.ts, and
22
- * Task 14's docs task for the deciding criteria).
17
+ * To add a new zero-quirk OpenAI-compatible provider: add one JSON file
18
+ * under src/lib/providers/catalog/ (see provider-catalog.schema.json) and
19
+ * run `pnpm run codegen:catalog`. Do NOT add a provider here if it needs
20
+ * any hook override beyond the 3 mandatory ones
21
+ * (getProviderName/getDefaultModel/formatProviderError) write a
22
+ * dedicated subclass instead (see deepseek.ts, azureOpenai.ts).
23
23
  */
24
24
  export declare const OPENAI_COMPAT_CATALOG: readonly OpenAICompatCatalogEntry[];