@juspay/neurolink 12.49.10 → 12.49.11

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.
@@ -113,6 +113,9 @@ export function getCatalogJsonEntries() {
113
113
  }
114
114
  export function buildCatalogEntries() {
115
115
  return CATALOG_JSON_ENTRIES.map((entry) => {
116
+ // Only models whose entry sets `tools` explicitly contribute a row —
117
+ // see CatalogModelSpec.tools and OpenAICompatCatalogEntry.modelToolOverrides.
118
+ const modelToolOverrides = Object.fromEntries(Object.entries(entry.models.catalog).flatMap(([modelId, spec]) => spec.tools !== undefined ? [[modelId, spec.tools]] : []));
116
119
  const base = {
117
120
  providerName: entry.id,
118
121
  aliases: [entry.id, ...entry.aliases],
@@ -135,6 +138,9 @@ export function buildCatalogEntries() {
135
138
  ...(typeof entry.capabilities.tools === "boolean"
136
139
  ? { supportsTools: entry.capabilities.tools }
137
140
  : {}),
141
+ ...(Object.keys(modelToolOverrides).length > 0
142
+ ? { modelToolOverrides }
143
+ : {}),
138
144
  // Unlike `tools`, `capabilities.structuredOutputWithTools` is a plain
139
145
  // required boolean in the schema (no "model-dependent" member), so this
140
146
  // is a direct passthrough — `false` and `true` both carry meaning to
@@ -158,6 +158,9 @@
158
158
  "vision": {
159
159
  "type": "boolean"
160
160
  },
161
+ "tools": {
162
+ "type": "boolean"
163
+ },
161
164
  "status": {
162
165
  "type": "string",
163
166
  "enum": ["production", "preview", "retired"]
@@ -19,6 +19,7 @@
19
19
  "output": 2
20
20
  },
21
21
  "vision": true,
22
+ "tools": true,
22
23
  "status": "production",
23
24
  "description": "NeuroLink default. Listed as reka-flash in the baseline model table on https://docs.reka.ai/chat/models.md (intro: \"Our baseline models always available for public access are:\") and named as the model in the code examples on https://docs.reka.ai/chat/overview.md, https://docs.reka.ai/chat/function-calling.md and https://docs.reka.ai/chat/api-reference/create.md (retrieved 2026-09-29). https://docs.reka.ai/pricing.md has a row named \"Reka Flash\" described as \"Fast and cost-efficient model for most tasks\" with $0.80 under \"Input Tokens (per 1M)\" and $2.00 under \"Output Tokens (per 1M)\"; https://docs.reka.ai/chat/models.md ends with \"For full listing of models and pricing, see the Reka API Pricing page\". https://docs.reka.ai/chat/function-calling.md says \"Currently, only Reka Flash supports function calling.\" Vision is true: the first curl example on https://docs.reka.ai/overview.md sends an image_url content part to model \"reka-flash\", and the Quickstart's \"First request\" example (https://docs.reka.ai/quickstart.md) carries the comment '# or \"reka-flash\"' beside an image_url request. No context window or maximum output figure is set for this model; models.defaultContextWindow and models.defaultMaxOutputTokens apply."
24
25
  },
@@ -28,6 +29,7 @@
28
29
  "output": 0.1
29
30
  },
30
31
  "vision": true,
32
+ "tools": false,
31
33
  "status": "production",
32
34
  "description": "Listed as \"reka-edge (or reka-edge-2603)\" in the baseline model table on https://docs.reka.ai/chat/models.md and on https://docs.reka.ai/quickstart.md (retrieved 2026-09-29). The Quickstart's \"First request\" example sends an image_url content part to model \"reka-edge\", and the example response on https://docs.reka.ai/chat/api-reference/get.md lists the id \"reka-edge\". https://docs.reka.ai/pricing.md has a row named \"Reka Edge\" described as \"Compact model ideal for on-device execution\" with $0.10 under \"Input Tokens (per 1M)\" and $0.10 under \"Output Tokens (per 1M)\". https://docs.reka.ai/chat/function-calling.md says \"Currently, only Reka Flash supports function calling.\" No context window or maximum output figure is set for this model; models.defaultContextWindow and models.defaultMaxOutputTokens apply."
33
35
  },
@@ -37,6 +39,7 @@
37
39
  "output": 0.1
38
40
  },
39
41
  "vision": true,
42
+ "tools": false,
40
43
  "status": "production",
41
44
  "description": "Named in the same table row as reka-edge, \"reka-edge (or reka-edge-2603)\", on https://docs.reka.ai/chat/models.md and https://docs.reka.ai/quickstart.md, and shown as {\"id\": \"reka-edge-2603\"} in the example output of GET https://api.reka.ai/v1/models on https://docs.reka.ai/chat/models.md, which says \"All of these model IDs can be used as values for the Chat API's model parameter\" (retrieved 2026-09-29). Vision and prices are those of the row's reka-edge example and its \"Reka Edge\" pricing row (https://docs.reka.ai/quickstart.md, https://docs.reka.ai/pricing.md). No context window or maximum output figure is set for this model; models.defaultContextWindow and models.defaultMaxOutputTokens apply."
42
45
  }
@@ -88,7 +91,7 @@
88
91
  "3. Authentication: the vendor's REST examples send the header X-Api-Key (https://docs.reka.ai/chat/overview.md) and the OpenAPI file https://docs.reka.ai/openapi/api-reference.yaml declares one security scheme, an apiKey in the header X-Api-Key; the OpenAI Python SDK examples pass api_key=\"YOUR_API_KEY\" to the client (https://docs.reka.ai/quickstart.md)",
89
92
  "4. Set {apiKeyEnvVar} in your .env file"
90
93
  ],
91
- "description": "Docs-verified only: the vendor's GET https://api.reka.ai/v1/models needs a key (it answers HTTP 401 without one), so the three model ids come from https://docs.reka.ai/chat/models.md and the roster has not been checked; the entry is not yet live-verified. Endpoint https://api.reka.ai/v1: the Quickstart (https://docs.reka.ai/quickstart.md) says \"our API is fully OpenAI-compatible\" and shows the OpenAI Python SDK with base_url \"https://api.reka.ai/v1\"; https://docs.reka.ai/chat/overview.md shows POST https://api.reka.ai/v1/chat/completions with a messages array and reads the reply from response.choices[0].message.content. Unauthenticated GETs made 2026-09-29: /models answered HTTP 401 with the JSON body {\"error\":{\"message\":\"Unauthorized\",\"type\":\"authentication_error\",\"code\":null,\"param\":null}}; /chat/completions answered HTTP 405 with header allow: POST and the body {\"detail\":\"Method Not Allowed\"}. No POST request was sent. errorRules carry the statuses https://docs.reka.ai/errors.md lists (401 authentication_error, 429 rate_limit_error, 500 server_error) plus a pattern rule on the FAQ's \"P001: Insufficient Balance\" text. capabilities.streaming is true because https://docs.reka.ai/chat/overview.md says \"The Chat API supports streaming\". capabilities.tools is model-dependent because https://docs.reka.ai/chat/function-calling.md documents the tools parameter and tool_calls and says \"Currently, only Reka Flash supports function calling.\" capabilities.structuredOutput is false: the ChatRequest on https://docs.reka.ai/chat/api-reference/create.md lists messages, model, frequency_penalty, max_tokens, presence_penalty, seed, stop, stream, temperature, tool_choice, tools, top_k and top_p. capabilities.toolsWithStreaming and capabilities.structuredOutputWithTools are false because no request combining them was sent. capabilities.embeddings and capabilities.thinking are false. models.defaultContextWindow (16384) and models.defaultMaxOutputTokens (4096) are placeholders the vendor does not publish; the Chat API reference describes max_tokens as \"limited by the model's context length. Defaults to 1024.\" Each model's status field holds production, a placeholder for a value the catalog schema requires; it is not a vendor statement. billingPolicy holds free-tier, one of the three values the catalog schema allows (free-tier, free-with-card, no-free-tier). The vendor wording behind it: on https://platform.reka.ai/pricing the Pay as you go tile has a \"Start for free\" link to /sign-up and the page carries the text \"Free credits used\"; https://docs.reka.ai/pricing.md says \"Get started with no upfront costs.\"; https://docs.reka.ai/resources/faqs.md answers \"Do I need to pre-pay?\" with \"Yes. Add credits to your account before making requests.\" apiKeyFormat is null, so NeuroLink's key-format check is not applied."
94
+ "description": "Docs-verified only: the vendor's GET https://api.reka.ai/v1/models needs a key (it answers HTTP 401 without one), so the three model ids come from https://docs.reka.ai/chat/models.md and the roster has not been checked; the entry is not yet live-verified. Endpoint https://api.reka.ai/v1: the Quickstart (https://docs.reka.ai/quickstart.md) says \"our API is fully OpenAI-compatible\" and shows the OpenAI Python SDK with base_url \"https://api.reka.ai/v1\"; https://docs.reka.ai/chat/overview.md shows POST https://api.reka.ai/v1/chat/completions with a messages array and reads the reply from response.choices[0].message.content. Unauthenticated GETs made 2026-09-29: /models answered HTTP 401 with the JSON body {\"error\":{\"message\":\"Unauthorized\",\"type\":\"authentication_error\",\"code\":null,\"param\":null}}; /chat/completions answered HTTP 405 with header allow: POST and the body {\"detail\":\"Method Not Allowed\"}. No POST request was sent. errorRules carry the statuses https://docs.reka.ai/errors.md lists (401 authentication_error, 429 rate_limit_error, 500 server_error) plus a pattern rule on the FAQ's \"P001: Insufficient Balance\" text. capabilities.streaming is true because https://docs.reka.ai/chat/overview.md says \"The Chat API supports streaming\". capabilities.tools is model-dependent because https://docs.reka.ai/chat/function-calling.md documents the tools parameter and tool_calls and says \"Currently, only Reka Flash supports function calling.\" That sentence is why reka-flash's models.catalog entry sets tools: true and reka-edge/reka-edge-2603 set tools: false (see CatalogModelSpec.tools) instead of leaving every model to the provider-level model-dependent default. capabilities.structuredOutput is false: the ChatRequest on https://docs.reka.ai/chat/api-reference/create.md lists messages, model, frequency_penalty, max_tokens, presence_penalty, seed, stop, stream, temperature, tool_choice, tools, top_k and top_p. capabilities.toolsWithStreaming and capabilities.structuredOutputWithTools are false because no request combining them was sent. capabilities.embeddings and capabilities.thinking are false. models.defaultContextWindow (16384) and models.defaultMaxOutputTokens (4096) are placeholders the vendor does not publish; the Chat API reference describes max_tokens as \"limited by the model's context length. Defaults to 1024.\" Each model's status field holds production, a placeholder for a value the catalog schema requires; it is not a vendor statement. billingPolicy holds free-tier, one of the three values the catalog schema allows (free-tier, free-with-card, no-free-tier). The vendor wording behind it: on https://platform.reka.ai/pricing the Pay as you go tile has a \"Start for free\" link to /sign-up and the page carries the text \"Free credits used\"; https://docs.reka.ai/pricing.md says \"Get started with no upfront costs.\"; https://docs.reka.ai/resources/faqs.md answers \"Do I need to pre-pay?\" with \"Yes. Add credits to your account before making requests.\" apiKeyFormat is null, so NeuroLink's key-format check is not applied."
92
95
  },
93
96
  "evidence": {
94
97
  "rosterVerified": {
@@ -46,6 +46,7 @@ export declare const providerCatalogJsonSchema: z.ZodObject<{
46
46
  cachedInput: z.ZodOptional<z.ZodNumber>;
47
47
  }, z.core.$strict>>;
48
48
  vision: z.ZodBoolean;
49
+ tools: z.ZodOptional<z.ZodBoolean>;
49
50
  status: z.ZodEnum<{
50
51
  production: "production";
51
52
  preview: "preview";
@@ -23,6 +23,7 @@ const catalogModelSpecSchema = z.strictObject({
23
23
  maxOutputTokens: z.number().optional(),
24
24
  pricingPerMTok: catalogPricingPerMTokSchema.optional(),
25
25
  vision: z.boolean(),
26
+ tools: z.boolean().optional(),
26
27
  status: catalogModelStatusSchema,
27
28
  description: z.string(),
28
29
  enumMember: z
@@ -62,6 +62,13 @@ export declare class ConfiguredOpenAICompatProvider extends OpenAIChatCompletion
62
62
  * every unknown id. A vendor that declares tools: false must never receive
63
63
  * a `tools` array — Mancer's free model rejects one with 400 — so the
64
64
  * declaration wins here and the registry is only consulted otherwise.
65
+ * A per-model entry in `modelToolOverrides` (from a "model-dependent"
66
+ * provider whose catalog names which specific models accept tools — see
67
+ * CatalogModelSpec.tools) wins over all of this: it is the same kind of
68
+ * wire-probed fact as `supportsTools`, just scoped to one model instead of
69
+ * the whole provider, so it is checked first and can both grant and
70
+ * withhold tools regardless of what the provider-level flag says.
71
+ *
65
72
  * Like the other entry-reading overrides above, this runs only after
66
73
  * construction: BaseProvider merely closes over it.
67
74
  */
@@ -125,10 +125,21 @@ export class ConfiguredOpenAICompatProvider extends OpenAIChatCompletionsProvide
125
125
  * every unknown id. A vendor that declares tools: false must never receive
126
126
  * a `tools` array — Mancer's free model rejects one with 400 — so the
127
127
  * declaration wins here and the registry is only consulted otherwise.
128
+ * A per-model entry in `modelToolOverrides` (from a "model-dependent"
129
+ * provider whose catalog names which specific models accept tools — see
130
+ * CatalogModelSpec.tools) wins over all of this: it is the same kind of
131
+ * wire-probed fact as `supportsTools`, just scoped to one model instead of
132
+ * the whole provider, so it is checked first and can both grant and
133
+ * withhold tools regardless of what the provider-level flag says.
134
+ *
128
135
  * Like the other entry-reading overrides above, this runs only after
129
136
  * construction: BaseProvider merely closes over it.
130
137
  */
131
138
  supportsTools() {
139
+ const override = this.entry.modelToolOverrides?.[this.modelName];
140
+ if (override !== undefined) {
141
+ return override;
142
+ }
132
143
  if (this.entry.supportsTools === false) {
133
144
  return false;
134
145
  }
@@ -27,6 +27,17 @@ export type CatalogModelSpec = {
27
27
  maxOutputTokens?: number;
28
28
  pricingPerMTok?: CatalogPricingPerMTok;
29
29
  vision: boolean;
30
+ /**
31
+ * Per-model override of the provider-level `capabilities.tools`, for a
32
+ * "model-dependent" provider whose vendor docs name which specific models
33
+ * accept tool definitions (e.g. Reka: "Currently, only Reka Flash
34
+ * supports function calling"). Absent means "inherit the provider-level
35
+ * answer", same as every model before this field existed. Only meaningful
36
+ * when `capabilities.tools` is `"model-dependent"` — a provider that
37
+ * already declares a plain `true`/`false` has no need for it, since that
38
+ * single value already applies to every model it serves.
39
+ */
40
+ tools?: boolean;
30
41
  status: CatalogModelStatus;
31
42
  description: string;
32
43
  /**
@@ -123,13 +134,18 @@ export type CatalogEvidence = {
123
134
  export type CatalogCapabilities = {
124
135
  text: boolean;
125
136
  streaming: boolean;
126
- /** "model-dependent" when tool support varies per served model and the
127
- * vendor doesn't reject `tools` for unsupported ones (the model just
128
- * never emits tool_calls) — e.g. HuggingFace's router. Maps to
137
+ /** "model-dependent" when tool support varies per served model. Maps to
129
138
  * ProviderDescriptor.toolSupport's own "model-dependent" member and
130
- * leaves OpenAICompatCatalogEntry.supportsTools unset so
131
- * ConfiguredOpenAICompatProvider falls through to the model-registry
132
- * default, exactly like an entry that never set supportsTools at all. */
139
+ * leaves OpenAICompatCatalogEntry.supportsTools unset, so
140
+ * ConfiguredOpenAICompatProvider.supportsTools() falls back to whichever
141
+ * of its two remaining sources applies: a model whose own
142
+ * models.catalog[id].tools is set (see CatalogModelSpec.tools) answers
143
+ * from that; any other model falls through further, to the
144
+ * model-registry default (true for an unregistered id) — the same
145
+ * behavior every model had before CatalogModelSpec.tools existed, and
146
+ * still correct for a vendor that doesn't reject `tools` for an
147
+ * unsupported model (the model just never emits tool_calls), e.g.
148
+ * HuggingFace's router. */
133
149
  tools: boolean | "model-dependent";
134
150
  toolsWithStreaming: boolean;
135
151
  structuredOutput: boolean;
@@ -1043,6 +1043,17 @@ export type OpenAICompatCatalogEntry = {
1043
1043
  * same default every hand-written provider uses.
1044
1044
  */
1045
1045
  supportsTools?: boolean;
1046
+ /**
1047
+ * Per-model override of `supportsTools`, from catalog models whose entry
1048
+ * sets `tools` explicitly (CatalogModelSpec.tools) — keyed by the model id
1049
+ * exactly as it appears in `models.catalog`. Checked first by
1050
+ * ConfiguredOpenAICompatProvider.supportsTools(), so it can both grant and
1051
+ * withhold tools regardless of what `supportsTools` says; a model id
1052
+ * absent from this map falls through to `supportsTools` unchanged. Built
1053
+ * only from models that declare `tools`, so a provider with no per-model
1054
+ * overrides gets no field here at all (not an empty object).
1055
+ */
1056
+ modelToolOverrides?: Record<string, boolean>;
1046
1057
  /**
1047
1058
  * Whether the vendor accepts native tool definitions and `response_format`
1048
1059
  * in the SAME request, from the catalog's
@@ -9771,11 +9771,11 @@
9771
9771
  {"objectID":"205e4e44d27692634aa5454565d9f060ceb88cdac97e7d37622bc5b9a1eefeb6","title":"Verification commands","url":"/docs/provider-integration/tiers/tier-1-aggregator-passthrough#verification-commands","content":"`bash","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 1 — Aggregator Passthrough","lvl2":"Verification commands","lvl3":""}},
9772
9772
  {"objectID":"09ead22698863d776e82e2f0f3dfdd9a596f39cc106302a02c51a6ef37b436de","title":"LiteLLM example","url":"/docs/provider-integration/tiers/tier-1-aggregator-passthrough#litellm-example","content":"pnpm run cli generate \"hello\" --provider litellm --model","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 1 — Aggregator Passthrough","lvl2":"LiteLLM example","lvl3":""}},
9773
9773
  {"objectID":"f46ff1668fbf30431a2b6578654212feb2043845eb7a28281e47075703948472","title":"OpenRouter example","url":"/docs/provider-integration/tiers/tier-1-aggregator-passthrough#openrouter-example","content":"pnpm run cli generate \"hello\" --provider openrouter --model /\n\n\nBoth should return a normal GenerateResult with non-empty content`. If\neither 400s with an \"unknown model\" style error, the aggregator doesn't\nactually serve that model yet — fix the aggregator-side config, not\nNeuroLink.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 1 — Aggregator Passthrough","lvl2":"OpenRouter example","lvl3":""}},
9774
- {"objectID":"0c443abf0cfa1b31edc3337559bddbf37453d87732cfd17b08d461f55c77b195","title":"Tier 2 — Catalog Entry","url":"/docs/provider-integration/tiers/tier-2-catalog-entry","content":"Tier 2 — Catalog Entry\n\nWhen this applies: the vendor speaks the OpenAI /v1/chat/completions\nwire format (Bearer auth, standard SSE, standard JSON body) and needs\nzero behavioral overrides — no custom adjustRequestBody, no\nadjustResponseFormat, no nonstandard auth header, no adjustBodyAfter400.\nThis is the Groq/xAI/Together AI/Fireworks/Perplexity/Cloudflare/Mistral\nshape from before the redesign — now expressed as one JSON file instead of\na hand-written subclass (see ../adr/0002-catalog-over-subclass-default.md\nand the single-JSON spec at\ndocs/superpowers/plans/2026-08-28-provider-json-catalog-spec.md).\n\nIf you're not sure whether your provider is quirk-free, start writing the\nJSON anyway — if it turns out you need a hook, migrate to Tier 3 instead of\nforcing the quirk into the catalog shape.\n\nFiles touched (end state)\n\n| # | File | Change |\n| --- | ------------------------------------- | ------------------------------- |\n| 1 | src/lib/providers/catalog/<id>.json | The entire integration, as data |\n\nThat is the whole list. Everything else is generated or derived:\npnpm run codegen:catalog writes the AIProviderName member, the\n <Name>Models enum and the NeurolinkCredentials key into marked\n regions, plus the generated catalog index. Pre-commit and CI fail on\n stale output, so it can't drift.\nThe runtime loader builds the registry entry, descriptor, config options,\n context windows, pricing, vision map and model choices from the JSON.\nThe test suites derive their spec rows, matrix rows and counts from the\n built catalog.\n\nScaffold it with:\n\nTier 2 emits exactly two files: a pre-filled <id>.json (with TODO markers\nwhere only a live probe can supply the truth) and a short checklist. The\nJSON deliberately fails schema validation until every TODO is replaced.\n\nCount pins — nothing to bump\n\nThere are none left. The wiring and descriptor suites compute their\nexpected totals from CATALOG_PROVIDER_IDS, and the matrix rows spread\nfrom the catalog with a completeness guard that throws if any catalog\nprovider is missing. Adding a provider changes no test file.\n\nsrc/lib/factories/providerRegistry.ts isn't in the table either:\n_doRegister() loops over the catalog and registers every entry\ngenerically.\n\nOne historical exception worth re-checking: commandFactory.ts's separate\nsetup [provider] subcommand hand-hardcoded its own provider-choices array.\nThat was migrated to derive from the enum (PR #1583) — confirm it still\ndoes before assuming you need a manual edit.\n\nThe JSON, field by field\n\nid, displayName, aliases, tier, then:\n\nwire — baseURL for the normal case. Env var names derive by\nconvention (<CONSTANT_CASE(id)>_API_KEY / _BASE_URL / _MODEL); set\nenvOverrides only for a vendor that breaks it. For a URL computed from\nanother credential (Cloudflare's account id) use baseURLTemplate plus\nexactly one extraCredentials entry.\n\nmodels — default, fallbacks, defaultContextWindow,\ndefaultMaxOutputTokens, and a catalog map of model id → {contextWindow?,\nmaxOutputTokens?, pricingPerMTok?, vision, status, description, enumMember?}.\nOmit a number rather than invent one. Optional refinements:\n\n| Field | Use it when |\n| ---------------------- | --------------------------------------------------------------- |\n| enumMember | The derived constant-case name would break an existing export |\n| enumTypeName | The <Name>Models enum name must differ from the derived one |\n| fallbackModelName | The legacy fallback differs from fallbacks[1] ?? fallbacks[0] |\n| registryDefaultModel | The registry default differs from default |\n| topModels | The CLI picker should show a curated ordered subset |\n| visionModel | Vision tests need a specific model (the default is text-only) |\n| testModel | The catalog default is retired/gated on the testing account |\n\ntestModel is matrix-only — it never changes the runtime default. Reach\nfor it when a vendor retires the model your catalog documents (Groq purged\nits llama lineup; Fireworks gates deployment per account).\n\ncapabilities — the matrix row. vision is derived from the models,\nnot declared here.\n\nerrorRules — status code and/or case-insensitive pattern → error\nclass + message. Templates: {model}, {apiKeyEnvVar}, {setupUrl}.\nRules are appended before the defaults and matched first-wins.\npatternStatuses (optional, with pattern) limits the pattern to responses\nwith one of those HTTP statuses, so the same words on another status fall\nthrough to the defaults.\n\nquirks — five named, closed escape hatches, all rare. Each one is\nconsumed generically by ConfiguredOpenAICompatProvider/the catalog loader —\nnone of them run arbitrary code. A provider that needs more than these\nbecomes a Tier 3 subclass instead of a sixth quirk.\ntimeoutErrorClass: \"provider\" — What it does: classifyProviderErro","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 2 — Catalog Entry","lvl2":"","lvl3":""}},
9774
+ {"objectID":"0c443abf0cfa1b31edc3337559bddbf37453d87732cfd17b08d461f55c77b195","title":"Tier 2 — Catalog Entry","url":"/docs/provider-integration/tiers/tier-2-catalog-entry","content":"Tier 2 — Catalog Entry\n\nWhen this applies: the vendor speaks the OpenAI /v1/chat/completions\nwire format (Bearer auth, standard SSE, standard JSON body) and needs\nzero behavioral overrides — no custom adjustRequestBody, no\nadjustResponseFormat, no nonstandard auth header, no adjustBodyAfter400.\nThis is the Groq/xAI/Together AI/Fireworks/Perplexity/Cloudflare/Mistral\nshape from before the redesign — now expressed as one JSON file instead of\na hand-written subclass (see ../adr/0002-catalog-over-subclass-default.md\nand the single-JSON spec at\ndocs/superpowers/plans/2026-08-28-provider-json-catalog-spec.md).\n\nIf you're not sure whether your provider is quirk-free, start writing the\nJSON anyway — if it turns out you need a hook, migrate to Tier 3 instead of\nforcing the quirk into the catalog shape.\n\nFiles touched (end state)\n\n| # | File | Change |\n| --- | ------------------------------------- | ------------------------------- |\n| 1 | src/lib/providers/catalog/<id>.json | The entire integration, as data |\n\nThat is the whole list. Everything else is generated or derived:\npnpm run codegen:catalog writes the AIProviderName member, the\n <Name>Models enum and the NeurolinkCredentials key into marked\n regions, plus the generated catalog index. Pre-commit and CI fail on\n stale output, so it can't drift.\nThe runtime loader builds the registry entry, descriptor, config options,\n context windows, pricing, vision map and model choices from the JSON.\nThe test suites derive their spec rows, matrix rows and counts from the\n built catalog.\n\nScaffold it with:\n\nTier 2 emits exactly two files: a pre-filled <id>.json (with TODO markers\nwhere only a live probe can supply the truth) and a short checklist. The\nJSON deliberately fails schema validation until every TODO is replaced.\n\nCount pins — nothing to bump\n\nThere are none left. The wiring and descriptor suites compute their\nexpected totals from CATALOG_PROVIDER_IDS, and the matrix rows spread\nfrom the catalog with a completeness guard that throws if any catalog\nprovider is missing. Adding a provider changes no test file.\n\nsrc/lib/factories/providerRegistry.ts isn't in the table either:\n_doRegister() loops over the catalog and registers every entry\ngenerically.\n\nOne historical exception worth re-checking: commandFactory.ts's separate\nsetup [provider] subcommand hand-hardcoded its own provider-choices array.\nThat was migrated to derive from the enum (PR #1583) — confirm it still\ndoes before assuming you need a manual edit.\n\nThe JSON, field by field\n\nid, displayName, aliases, tier, then:\n\nwire — baseURL for the normal case. Env var names derive by\nconvention (<CONSTANT_CASE(id)>_API_KEY / _BASE_URL / _MODEL); set\nenvOverrides only for a vendor that breaks it. For a URL computed from\nanother credential (Cloudflare's account id) use baseURLTemplate plus\nexactly one extraCredentials entry.\n\nmodels — default, fallbacks, defaultContextWindow,\ndefaultMaxOutputTokens, and a catalog map of model id → {contextWindow?,\nmaxOutputTokens?, pricingPerMTok?, vision, tools?, status, description, enumMember?}.\nOmit a number rather than invent one. Optional refinements:\n\n| Field | Use it when |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| enumMember | The derived constant-case name would break an existing export |\n| enumTypeName | The <Name>Models enum name must differ from the derived one |\n| fallbackModelName | The legacy fallback differs from fallbacks[1] ?? fallbacks[0] |\n| registryDefaultModel | The registry default differs from default |\n| topModels | The CLI picker should show a curated ordered subset |\n| visionModel | Vision tests need a specific model (the default is text-only) |\n| testModel | The catalog default is retired/gated on the testing account |\n| tools (per model) | capabilities.tools is \"model-dependent\" and the vendor's own docs say which served models actually accept tool definitions (Reka: only reka-flash) |\n\ntestModel is matrix-only","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 2 — Catalog Entry","lvl2":"","lvl3":""}},
9775
9775
  {"objectID":"4b278bfa53040dfc60deaffd7c0042488d914cc4eff89ded532f5582eceadce6","title":"Tier 2 — Catalog Entry","url":"/docs/provider-integration/tiers/tier-2-catalog-entry#tier-2-catalog-entry","content":"When this applies: the vendor speaks the OpenAI /v1/chat/completions\nwire format (Bearer auth, standard SSE, standard JSON body) and needs\nzero behavioral overrides — no custom adjustRequestBody, no\nadjustResponseFormat, no nonstandard auth header, no adjustBodyAfter400.\nThis is the Groq/xAI/Together AI/Fireworks/Perplexity/Cloudflare/Mistral\nshape from before the redesign — now expressed as one JSON file instead of\na hand-written subclass (see ../adr/0002-catalog-over-subclass-default.md\nand the single-JSON spec at\ndocs/superpowers/plans/2026-08-28-provider-json-catalog-spec.md).\n\nIf you're not sure whether your provider is quirk-free, start writing the\nJSON anyway — if it turns out you need a hook, migrate to Tier 3 instead of\nforcing the quirk into the catalog shape.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 2 — Catalog Entry","lvl2":"Tier 2 — Catalog Entry","lvl3":""}},
9776
9776
  {"objectID":"1bb614eb5848cace52afb691aa99aeab78366a84a216f758ef9df6c86e49c0cc","title":"Files touched (end state)","url":"/docs/provider-integration/tiers/tier-2-catalog-entry#files-touched-end-state","content":"| # | File | Change |\n| --- | ------------------------------------- | ------------------------------- |\n| 1 | src/lib/providers/catalog/<id>.json | The entire integration, as data |\n\nThat is the whole list. Everything else is generated or derived:\npnpm run codegen:catalog writes the AIProviderName member, the\n <Name>Models enum and the NeurolinkCredentials key into marked\n regions, plus the generated catalog index. Pre-commit and CI fail on\n stale output, so it can't drift.\nThe runtime loader builds the registry entry, descriptor, config options,\n context windows, pricing, vision map and model choices from the JSON.\nThe test suites derive their spec rows, matrix rows and counts from the\n built catalog.\n\nScaffold it with:\n\nTier 2 emits exactly two files: a pre-filled <id>.json (with TODO markers\nwhere only a live probe can supply the truth) and a short checklist. The\nJSON deliberately fails schema validation until every TODO is replaced.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 2 — Catalog Entry","lvl2":"Files touched (end state)","lvl3":""}},
9777
9777
  {"objectID":"9627a6b63ab505017fbc3edd7f9ec312f548b35aef74edd6e2be5eac8e1ade0f","title":"Count pins — nothing to bump","url":"/docs/provider-integration/tiers/tier-2-catalog-entry#count-pins-nothing-to-bump","content":"There are none left. The wiring and descriptor suites compute their\nexpected totals from CATALOG_PROVIDER_IDS, and the matrix rows spread\nfrom the catalog with a completeness guard that throws if any catalog\nprovider is missing. Adding a provider changes no test file.\n\nsrc/lib/factories/providerRegistry.ts isn't in the table either:\n_doRegister() loops over the catalog and registers every entry\ngenerically.\n\nOne historical exception worth re-checking: commandFactory.ts's separate\nsetup [provider] subcommand hand-hardcoded its own provider-choices array.\nThat was migrated to derive from the enum (PR #1583) — confirm it still\ndoes before assuming you need a manual edit.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 2 — Catalog Entry","lvl2":"Count pins — nothing to bump","lvl3":""}},
9778
- {"objectID":"672b4a181677219d0db0d64d290a3f1a268691c336f02fe776a01d94d0684ae5","title":"The JSON, field by field","url":"/docs/provider-integration/tiers/tier-2-catalog-entry#the-json-field-by-field","content":"id, displayName, aliases, tier, then:\n\nwire — baseURL for the normal case. Env var names derive by\nconvention (<CONSTANT_CASE(id)>_API_KEY / _BASE_URL / _MODEL); set\nenvOverrides only for a vendor that breaks it. For a URL computed from\nanother credential (Cloudflare's account id) use baseURLTemplate plus\nexactly one extraCredentials entry.\n\nmodels — default, fallbacks, defaultContextWindow,\ndefaultMaxOutputTokens, and a catalog map of model id → {contextWindow?,\nmaxOutputTokens?, pricingPerMTok?, vision, status, description, enumMember?}.\nOmit a number rather than invent one. Optional refinements:\n\n| Field | Use it when |\n| ---------------------- | --------------------------------------------------------------- |\n| enumMember | The derived constant-case name would break an existing export |\n| enumTypeName | The <Name>Models enum name must differ from the derived one |\n| fallbackModelName | The legacy fallback differs from fallbacks[1] ?? fallbacks[0] |\n| registryDefaultModel | The registry default differs from default |\n| topModels | The CLI picker should show a curated ordered subset |\n| visionModel | Vision tests need a specific model (the default is text-only) |\n| testModel | The catalog default is retired/gated on the testing account |\n\ntestModel is matrix-only — it never changes the runtime default. Reach\nfor it when a vendor retires the model your catalog documents (Groq purged\nits llama lineup; Fireworks gates deployment per account).\n\ncapabilities — the matrix row. vision is derived from the models,\nnot declared here.\n\nerrorRules — status code and/or case-insensitive pattern → error\nclass + message. Templates: {model}, {apiKeyEnvVar}, {setupUrl}.\nRules are appended before the defaults and matched first-wins.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 2 — Catalog Entry","lvl2":"The JSON, field by field","lvl3":""}},
9778
+ {"objectID":"672b4a181677219d0db0d64d290a3f1a268691c336f02fe776a01d94d0684ae5","title":"The JSON, field by field","url":"/docs/provider-integration/tiers/tier-2-catalog-entry#the-json-field-by-field","content":"id, displayName, aliases, tier, then:\n\nwire — baseURL for the normal case. Env var names derive by\nconvention (<CONSTANT_CASE(id)>_API_KEY / _BASE_URL / _MODEL); set\nenvOverrides only for a vendor that breaks it. For a URL computed from\nanother credential (Cloudflare's account id) use baseURLTemplate plus\nexactly one extraCredentials entry.\n\nmodels — default, fallbacks, defaultContextWindow,\ndefaultMaxOutputTokens, and a catalog map of model id → {contextWindow?,\nmaxOutputTokens?, pricingPerMTok?, vision, tools?, status, description, enumMember?}.\nOmit a number rather than invent one. Optional refinements:\n\n| Field | Use it when |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| enumMember | The derived constant-case name would break an existing export |\n| enumTypeName | The <Name>Models enum name must differ from the derived one |\n| fallbackModelName | The legacy fallback differs from fallbacks[1] ??","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 2 — Catalog Entry","lvl2":"The JSON, field by field","lvl3":""}},
9779
9779
  {"objectID":"5f38f36d8546533723645d1643ea69418d7e5cbe47cde5d18b5ad998d053e476","title":"Live verification","url":"/docs/provider-integration/tiers/tier-2-catalog-entry#live-verification","content":"The mocked gates prove the wire contract, not the commercial reality.\nEach of these caught a real defect on the cerebras pilot:\nRoster probe first — authenticated GET <baseURL>/models. Pick\n default, fallbacks and catalog keys from what the API serves TODAY.\n Vendor docs listed four cerebras models; the live roster had two, and\n the documented default 404'd (finding #7). This ages: both Groq's and\n Fireworks' catalog defaults went dead within weeks.\nBilling policy — confirm how a working key is obtained. Cerebras has\n no keyless free tier: even the \"$5 free credits\" require saving a payment\n card (finding #8); SambaNova requires payment outright (finding #11).\nCapability probes — probe tools + response_format in one request\n before setting structuredOutputWithTools; strict backends 400. Don't\n copy another provider's flags on vibes.\nLive matrix — with a working key:\n npx tsx test/continuous-test-suite-provider-matrix.ts --provider=<id>\n must pass generate, stream, tool calling and structured output, and a\n bare node dist/cli/index.js generate \"...\" --provider <id> must resolve\n the default model. The pilot's first live run was 2/4 and surfaced an\n SDK-wide bug (tool_choice emitted on tools-less requests — fixed in\n #1564, now pinned by the mocked suite), which is why this step exists.\n\nRecord the outcome in evidence.liveMatrix.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 2 — Catalog Entry","lvl2":"Live verification","lvl3":""}},
9780
9780
  {"objectID":"bea00545b1053aa393e34f487097636d2ee23cfdc652c6724dc6029192017ffd","title":"Verification commands","url":"/docs/provider-integration/tiers/tier-2-catalog-entry#verification-commands","content":"All must exit 0 before opening the PR. The first three test commands run in\nthe provider-safety-net CI job (.github/workflows/ci.yml) — zero-API,\nzero-credential checks, so there's no reason to skip them locally. Add a\ncase to test:error-classifier-contract first if your entry sets\ntimeoutErrorClass or vendor-specific errorRules.\n\nBecause the suites derive from data, a new provider needs no new assertions\n— but if you ever do add one, run the break-one-assertion ritual: flip it,\nconfirm the suite reports ✗ and exits non-zero (not ⊘ skip — see the\nassertion-message hazard in CLAUDE.md), then restore it.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 2 — Catalog Entry","lvl2":"Verification commands","lvl3":""}},
9781
9781
  {"objectID":"3f8e5102409b953258a82548fec14a7726774f6e1e5c3c7d826400ef24ebf105","title":"Tier 3 — Adapter-Based Native","url":"/docs/provider-integration/tiers/tier-3-adapter-native","content":"Tier 3 — Adapter-Based Native\n\nWhen this applies: the vendor has its own SDK or wire format that\nisn't OpenAI-compatible, but it's still a normal request/response (or\nrequest/SSE-stream) HTTP+JSON lifecycle you can drive from a provider\nclass. This is the Anthropic/Google AI Studio shape — a dedicated\nsrc/lib/providers/<name>.ts extending BaseProvider directly, not the\nOpenAIChatCompletionsProvider family.\n\nCorrected from the original plan text (2026-08-18): the plan's\ndraft cited \"the Mistral/Cohere/Ollama shape\" as the Tier 3 example.\nThat's stale — mistral.ts, cohere.ts, and ollama/client.ts all\nextend OpenAIChatCompletionsProvider, the Tier 2 family, not\nBaseProvider directly. (Mistral is separately already named in\n../adr/0002-catalog-over-subclass-default.md as a Tier 2\ncatalog-migration candidate — the original draft was internally\ninconsistent about which tier Mistral belongs to.) The verified,\ncurrently-shipping examples of a chat/text provider extending\nBaseProvider directly are Anthropic\n(src/lib/providers/anthropic/client.ts) and Google AI Studio\n(src/lib/providers/googleAiStudio/client.ts) — used below.\nWhy these two, specifically: they implement the request/response and\nstreaming lifecycle against their vendor's own wire format directly,\ninside the provider class itself — they don't inherit that lifecycle\nfrom OpenAIChatCompletionsProvider's shared chat-completions\nimplementation the way Mistral/Cohere/Ollama do. That's the actual line\nbetween Tier 2 and Tier 3: not \"does the vendor have a custom SDK\" but\n\"does this class implement the provider surface itself, or inherit it.\"\nWhen you compare your new provider's shape against Anthropic/Google AI\nStudio, that's the property you're matching — not their specific\nrequest/response format, which is vendor-idiosyncratic and won't look\nlike yours.\n\nAs of 2026-08-18 there is no shared streaming-loop adapter beyond\nBaseProvider and OpenAIChatCompletionsProvider (checked\nsrc/lib/providers/ for a nativeAdapter*.ts or similar — none exists).\nIf one lands later, extend it instead of hand-rolling the SSE parser and\nmulti-step tool loop; the steps below describe the always-true minimum\nregardless of whether that shared adapter exists yet.\n\nFiles touched (end state)\n\n| # | File | Change |\n| --- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| 1 | src/lib/constants/enums.ts | New AIProviderName member + a <Name>Models enum (default + fallback model ids — Tier 3 providers keep an explicit model catalog since there's no OPENAI_COMPAT_CATALOG row to hold defaultModel/fallbackModels) |\n| 2 | src/lib/providers/<name>.ts | NEW provider class extending BaseProvider (or a shared adapter, if one has landed by the time you read this) |\n| 3 | src/lib/factories/providerDescriptors.ts | One ProviderDescriptor entry |\n| 4 | src/lib/factories/providerRegistry.ts | One ProviderFactory.registerProvider() block, dynamic import, 5-argument call including the descriptor argument from PROVIDER_DESCRIPTORS_BY_NAME |\n| 5 | src/lib/types/providers.ts | New NeurolinkCredentials[\"<key>\"] slice |\n| 6 | src/lib/adapters/providerImageAdapter.ts | VISION_CAPABILITIES entry — only if the provider/model is multimodal |\n| 7 | test/continuous-test-suite-providers-mocked.ts | Mocked-contract section ","hierarchy":{"lvl0":"Provider Integration","lvl1":"Tier 3 — Adapter-Based Native","lvl2":"","lvl3":""}},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "12.49.10",
3
+ "version": "12.49.11",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
6
6
  "author": {