@juspay/neurolink 12.49.14 → 12.49.16
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.
- package/CHANGELOG.md +2 -2
- package/dist/browser/neurolink.min.js +411 -421
- package/dist/cli/factories/commandFactory.d.ts +12 -0
- package/dist/cli/factories/commandFactory.js +11 -1
- package/dist/constants/bedrockIdentifiers.d.ts +16 -0
- package/dist/constants/bedrockIdentifiers.js +79 -0
- package/dist/constants/contextWindows.d.ts +6 -15
- package/dist/constants/contextWindows.js +18 -52
- package/dist/constants/enums.d.ts +12 -0
- package/dist/constants/enums.js +15 -0
- package/dist/constants/tokens.js +9 -0
- package/dist/core/loopEngine.js +8 -0
- package/dist/hitl/hitlManager.js +15 -2
- package/dist/providers/amazonBedrock/client.js +3 -0
- package/dist/providers/amazonBedrock/inferenceProfile.js +9 -5
- package/dist/providers/catalog/abliteration.json +85 -0
- package/dist/providers/catalog/aihubmix.json +77 -0
- package/dist/providers/catalog/api-route.json +1 -1
- package/dist/providers/catalog/baseten.json +1 -1
- package/dist/providers/catalog/deepseek.json +1 -1
- package/dist/providers/catalog/gmicloud.json +1 -1
- package/dist/providers/catalog/huggingface.json +1 -1
- package/dist/providers/catalog/inception-labs.json +1 -1
- package/dist/providers/catalog/index.generated.d.ts +1 -1
- package/dist/providers/catalog/index.generated.js +9 -0
- package/dist/providers/catalog/io-intelligence.json +1 -1
- package/dist/providers/catalog/loader.js +3 -0
- package/dist/providers/catalog/mancer.json +1 -1
- package/dist/providers/catalog/morph.json +1 -1
- package/dist/providers/catalog/naver-clova-studio.json +68 -0
- package/dist/providers/catalog/novita.json +1 -1
- package/dist/providers/catalog/provider-catalog.schema.json +27 -4
- package/dist/providers/catalog/schema.d.ts +3 -1
- package/dist/providers/catalog/schema.js +15 -2
- package/dist/providers/catalog/upstage.json +1 -1
- package/dist/providers/cohere.js +7 -2
- package/dist/providers/configuredOpenAICompat.js +7 -0
- package/dist/providers/embeddingResponseParsing.d.ts +15 -0
- package/dist/providers/embeddingResponseParsing.js +4 -3
- package/dist/providers/googleAiStudio/client.js +104 -26
- package/dist/rag/chunking/htmlChunker.js +4 -11
- package/dist/rag/document/loaders.js +12 -14
- package/dist/server/openapi/generator.d.ts +0 -6
- package/dist/server/openapi/generator.js +2 -72
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/hitl.d.ts +2 -0
- package/dist/types/loopEngine.d.ts +7 -0
- package/dist/types/providerCatalog.d.ts +15 -1
- package/dist/types/providerCatalog.generated.d.ts +2 -2
- package/dist/types/providers.d.ts +15 -0
- package/dist/types/safeFetch.d.ts +1 -1
- package/dist/utils/htmlEntities.d.ts +8 -0
- package/dist/utils/htmlEntities.js +29 -0
- package/dist/utils/safeFetch.js +11 -3
- package/dist/utils/tokenLimits.js +23 -4
- package/docs-site/static/search-index.json +27 -16
- package/package.json +6 -3
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./provider-catalog.schema.json",
|
|
3
|
+
"id": "abliteration",
|
|
4
|
+
"displayName": "Abliteration AI",
|
|
5
|
+
"aliases": [],
|
|
6
|
+
"tier": 2,
|
|
7
|
+
"wire": {
|
|
8
|
+
"baseURL": "https://api.abliteration.ai/v1"
|
|
9
|
+
},
|
|
10
|
+
"models": {
|
|
11
|
+
"default": "abliterated-model",
|
|
12
|
+
"fallbacks": ["abliterated-model"],
|
|
13
|
+
"defaultContextWindow": 262144,
|
|
14
|
+
"defaultMaxOutputTokens": 262134,
|
|
15
|
+
"catalog": {
|
|
16
|
+
"abliterated-model": {
|
|
17
|
+
"vision": true,
|
|
18
|
+
"tools": true,
|
|
19
|
+
"status": "production",
|
|
20
|
+
"contextWindow": 262144,
|
|
21
|
+
"maxOutputTokens": 262134,
|
|
22
|
+
"pricingPerMTok": {
|
|
23
|
+
"input": 1,
|
|
24
|
+
"output": 3,
|
|
25
|
+
"cachedInput": 0.1
|
|
26
|
+
},
|
|
27
|
+
"description": "Source documentation only (2026-10-09). The vendor Limits table lists 262,144 combined context tokens and 262,134 maximum completion tokens for abliterated-model; maximum output is reachable only with a small prompt. This is the documented general-purpose model with image input. Account-specific availability and live execution are unverified. Other models and protocol families are outside this initial entry."
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"topModels": ["abliterated-model"]
|
|
31
|
+
},
|
|
32
|
+
"capabilities": {
|
|
33
|
+
"text": true,
|
|
34
|
+
"streaming": true,
|
|
35
|
+
"tools": true,
|
|
36
|
+
"toolsWithStreaming": true,
|
|
37
|
+
"structuredOutput": true,
|
|
38
|
+
"structuredOutputWithTools": false,
|
|
39
|
+
"embeddings": false,
|
|
40
|
+
"thinking": false
|
|
41
|
+
},
|
|
42
|
+
"errorRules": [
|
|
43
|
+
{
|
|
44
|
+
"status": 401,
|
|
45
|
+
"class": "authentication",
|
|
46
|
+
"message": "Abliteration requires an API key. https://docs.abliteration.ai/api/errors.md documents HTTP 401 for missing or invalid Bearer credentials."
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"status": 402,
|
|
50
|
+
"class": "provider",
|
|
51
|
+
"message": "Abliteration documents HTTP 402 for insufficient credits. This is a billing block, not a rate limit. See https://docs.abliteration.ai/api/errors.md."
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"status": 429,
|
|
55
|
+
"class": "rate-limit",
|
|
56
|
+
"message": "Abliteration documents HTTP 429 rate limiting and Retry-After at https://docs.abliteration.ai/api/errors.md."
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"setup": {
|
|
60
|
+
"url": "https://abliteration.ai/console",
|
|
61
|
+
"apiKeyFormat": null,
|
|
62
|
+
"billingPolicy": "free-tier",
|
|
63
|
+
"instructions": [
|
|
64
|
+
"Create an API key in https://abliteration.ai/console. The public pricing page, retrieved 2026-10-09, states a one-credit free preview without a card; account eligibility and remaining credit are unverified.",
|
|
65
|
+
"Set {apiKeyEnvVar}. The chat endpoint is https://api.abliteration.ai/v1/chat/completions with Authorization: Bearer authentication.",
|
|
66
|
+
"This entry includes only abliterated-model. Public documentation describes image input, tools, streamed tools and JSON/schema; vendor and account acceptance remain pending.",
|
|
67
|
+
"Reasoning is on by default at the service. SDK effort/toggle controls and native tool-plus-schema combinations are outside this initial declared scope."
|
|
68
|
+
],
|
|
69
|
+
"description": "Source-docs/local-contract pilot, not live or delivered-provider certification. Public documents specify the model-bound integer ceilings and prepaid usage pricing, and the pricing page states a no-card free preview. No authenticated roster, account creation, payment or inference was performed."
|
|
70
|
+
},
|
|
71
|
+
"evidence": {
|
|
72
|
+
"rosterVerified": {
|
|
73
|
+
"date": "2026-10-09",
|
|
74
|
+
"code": "DOCS_ONLY_ROSTER_NOT_OBSERVED",
|
|
75
|
+
"method": "Source documentation recorded in the legacy required field, not an observed roster: https://docs.abliteration.ai/models.md Limits table and quickstart, compatibility, streaming and tool documentation retrieved 2026-10-09. No GET /models, credentials or inference used. Authenticated roster remains pending."
|
|
76
|
+
},
|
|
77
|
+
"billingProbe": {
|
|
78
|
+
"date": "2026-10-09",
|
|
79
|
+
"code": "PUBLIC_DOCS_ONLY_ACCOUNT_NOT_TESTED",
|
|
80
|
+
"method": "Public documentation only: https://abliteration.ai/pricing states a one-credit free preview without a credit card; https://docs.abliteration.ai/pricing.md lists USD prepaid balance and $1.00 input / $0.10 cached input / $3.00 output per million tokens for abliterated-model. Account eligibility, balance and billing execution are untested."
|
|
81
|
+
},
|
|
82
|
+
"liveMatrix": null,
|
|
83
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1966"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./provider-catalog.schema.json",
|
|
3
|
+
"id": "aihubmix",
|
|
4
|
+
"displayName": "AIHubMix",
|
|
5
|
+
"enumTypeName": "AIHubMixModels",
|
|
6
|
+
"aliases": [],
|
|
7
|
+
"tier": 2,
|
|
8
|
+
"wire": {
|
|
9
|
+
"baseURL": "https://aihubmix.com/v1"
|
|
10
|
+
},
|
|
11
|
+
"models": {
|
|
12
|
+
"default": "gpt-4o-mini",
|
|
13
|
+
"fallbacks": ["gpt-4o-mini"],
|
|
14
|
+
"defaultContextWindow": 128000,
|
|
15
|
+
"defaultMaxOutputTokens": 16384,
|
|
16
|
+
"catalog": {
|
|
17
|
+
"gpt-4o-mini": {
|
|
18
|
+
"contextWindow": 128000,
|
|
19
|
+
"maxOutputTokens": 16384,
|
|
20
|
+
"vision": false,
|
|
21
|
+
"status": "production",
|
|
22
|
+
"description": "AIHubMix's paid GPT 4o Mini. Exact context/output limits and active lifecycle are published in its own model-page record on 2026-10-09. This pilot declares text generate/stream; tools, vision, strict schema and effort controls await separate evidence and acceptance. Account/model access is unverified."
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"capabilities": {
|
|
27
|
+
"text": true,
|
|
28
|
+
"streaming": true,
|
|
29
|
+
"tools": false,
|
|
30
|
+
"toolsWithStreaming": false,
|
|
31
|
+
"structuredOutput": false,
|
|
32
|
+
"structuredOutputWithTools": false,
|
|
33
|
+
"embeddings": false,
|
|
34
|
+
"thinking": false
|
|
35
|
+
},
|
|
36
|
+
"errorRules": [
|
|
37
|
+
{
|
|
38
|
+
"status": 401,
|
|
39
|
+
"class": "authentication",
|
|
40
|
+
"message": "Invalid or expired AIHubMix API key. Check {apiKeyEnvVar} and your key permissions."
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"pattern": "insufficient_user_quota|insufficient.*quota",
|
|
44
|
+
"patternStatuses": [403],
|
|
45
|
+
"class": "provider",
|
|
46
|
+
"message": "AIHubMix quota or paid-model access is insufficient. The gpt-4o-mini default is usage-priced; verify account funding and model eligibility."
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"pattern": "model_retired|model.*retired",
|
|
50
|
+
"patternStatuses": [404],
|
|
51
|
+
"class": "invalid-model",
|
|
52
|
+
"message": "The requested AIHubMix model '{model}' is retired. Select a current documented model; gpt-4o-free and gpt-5.5-free are excluded from this pilot."
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"setup": {
|
|
56
|
+
"url": "https://console.aihubmix.com",
|
|
57
|
+
"apiKeyFormat": null,
|
|
58
|
+
"billingPolicy": "free-tier",
|
|
59
|
+
"instructions": [
|
|
60
|
+
"1. Sign in to the AIHubMix console and create an API key.",
|
|
61
|
+
"2. The selected gpt-4o-mini default is paid and usage-priced. Verify your own account funding, model permissions and current rates before using it.",
|
|
62
|
+
"3. The vendor-level free-tier label refers to AIHubMix's separately documented, model-limited free programme. It does not grant free usage of gpt-4o-mini; current model eligibility and allowances are unverified.",
|
|
63
|
+
"4. Current model-specific guides mark gpt-4o-free and gpt-5.5-free retired. Do not use either as a default or fallback based on older free-model marketing.",
|
|
64
|
+
"5. Set {apiKeyEnvVar} for this provider. The documented base URL is https://aihubmix.com/v1."
|
|
65
|
+
],
|
|
66
|
+
"description": "AIHubMix gateway text/stream pilot with a paid gpt-4o-mini default. A separate model-limited free programme is documented; no account entitlement, roster, live inference or delivery is verified."
|
|
67
|
+
},
|
|
68
|
+
"evidence": {
|
|
69
|
+
"rosterVerified": {
|
|
70
|
+
"date": "2026-10-09",
|
|
71
|
+
"code": "PUBLIC_DOCS_ONLY_NOT_ROSTER_VERIFIED",
|
|
72
|
+
"method": "Public documentation GETs of https://aihubmix.com/model/gpt-4o-mini and its /llms.txt guide. Exact own model-page record binds context_window=128000 and max_output=16384. No vendor roster, auth, billing or inference probe ran; this legacy field does not assert roster verification."
|
|
73
|
+
},
|
|
74
|
+
"liveMatrix": null,
|
|
75
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1966"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -125,6 +125,6 @@
|
|
|
125
125
|
"date": "2026-09-17",
|
|
126
126
|
"result": "Verified live against https://global.api-route.com/v1: GET /v1/models returned 70 models. Chat completions, streaming, function calling, streamed function calling, and structured JSON output (json_object and json_schema) verified. Multimodal vision verified on claude-sonnet-4-6, claude-haiku-4-5, and gemini-3.8-flash. Invalid API key returns 401 (无效的令牌) and invalid model returns 503 (model_not_found). Tools and response_format were only probed SEPARATELY, never together in one request, so structuredOutputWithTools is corrected to false here pending a dedicated tools_plus_schema probe — the individual passes do not demonstrate the combined capability."
|
|
127
127
|
},
|
|
128
|
-
"addedInPR": "
|
|
128
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1725"
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -94,6 +94,6 @@
|
|
|
94
94
|
"method": "Live against api.deepseek.com on 2026-09-24. GET /models lists only deepseek-flash and deepseek-v4-pro, with context_window 1048576 and max_output_tokens 393216 (the pricing page's 1M / 384K). deepseek-chat and deepseek-reasoner still answer 200 but report model deepseek-flash — deepseek-chat without reasoning_content, deepseek-reasoner with it — so both stay production as aliases rather than being marked retired. Vision was probed with a solid-blue PNG: deepseek-flash, deepseek-chat and deepseek-reasoner all named the colour; deepseek-v4-pro answered 200 but described a scene that was not in the image, so it keeps vision false, matching the pricing page. An unknown model id returns 400 'The supported API model names are …' with code invalid_request_error — never 'model_not_found' — so the invalid-model rule now matches that text. tools plus response_format json_object in one request returned 200 with tool_calls, confirming structuredOutputWithTools. billingPolicy is not re-verified."
|
|
95
95
|
},
|
|
96
96
|
"liveMatrix": null,
|
|
97
|
-
"addedInPR": "
|
|
97
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1781"
|
|
98
98
|
}
|
|
99
99
|
}
|
|
@@ -59,6 +59,6 @@
|
|
|
59
59
|
"date": "2026-09-03",
|
|
60
60
|
"result": "MiniMax-M3 accepted max_completion_tokens=524288 and rejected 1048576 with an explicit 524288 limit. Structured output: the endpoint ignores response_format (json_schema and json_object both return prose with no prompt hint; raw fetch, 2026-09-03), so the SDK's structured-output fallback re-asks with the schema spelled out in the system prompt and coerces the reply — generate({ schema }) returned a schema-valid structuredData 3/3 in the prompt-fallback experiment and again in the final live proof through dist/index.js. structuredOutput and structuredOutputWithTools are declared true on that basis."
|
|
61
61
|
},
|
|
62
|
-
"addedInPR": "
|
|
62
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1625"
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -401,6 +401,6 @@
|
|
|
401
401
|
"method": "Live against router.huggingface.co on 2026-09-24. GET /v1/models returned 138 models; each of the 53 catalog ids was also sent a real chat call. 39 ids are absent from the roster AND rejected with 400 ('does not exist' / 'not supported by any provider'), so they are marked retired and keep their enumMember; the other 14 are on the roster and answered 402 (the test account's monthly credits are spent), which is a billing block, not a rejection, so they stay production. No id had the two signals disagree. topModels swaps the retired Mistral-Large-3 for zai-org/GLM-5, which is on the roster. billingPolicy is free-tier per https://huggingface.co/docs/inference-providers/pricing (free users get monthly credits, no card). apiKeyFormat accepts the hf_ + 34 characters a real token has; the previous hf_ + 37 pattern rejected it. structuredOutput, toolsWithStreaming and per-model vision are left unchanged: /v1/models reports them per serving provider, and the 402 prevented a live round trip that would prove them."
|
|
402
402
|
},
|
|
403
403
|
"liveMatrix": null,
|
|
404
|
-
"addedInPR": "
|
|
404
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1781"
|
|
405
405
|
}
|
|
406
406
|
}
|
|
@@ -70,6 +70,6 @@
|
|
|
70
70
|
"date": "2026-09-03",
|
|
71
71
|
"result": "Full capability sweep on mercury-2: chat, stream, system_role, content_text_parts, sampling_params, tools, tools_stream, tools_roundtrip_null, tool_choice_without_tools, json_object, json_schema and tools_plus_schema all 200. The smoke-test json_schema probe (max_tokens:60) came back truncated (finish_reason=length, null content) because this diffusion model spends part of the budget on reasoning tokens before content; re-probed live with max_tokens:300 and got a clean schema-conformant reply ({\"name\":\"Lila Whitaker\",\"age\":34}, finish_reason=stop), confirming structuredOutput:true is correct. vision is 400 (text-only; rejects image_url on mercury-2, matching the vendor docs' 'Supported Formats: Text'). bad_key is 401 'Incorrect API key provided'. bad_model is 400 with an array-shaped pydantic error.message; the shared OpenAI-compat wire-error builder coerces a non-string Error message via toString, so that array becomes the literal string \"[object Object]\" and no regex pattern can match the real text \u2014 errorRules is intentionally left empty rather than shipping a rule that can never fire (see notes)."
|
|
72
72
|
},
|
|
73
|
-
"addedInPR": "
|
|
73
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1625"
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ProviderCatalogJson } from "../../types/index.js";
|
|
2
2
|
export declare const CATALOG_JSON_ENTRIES: ProviderCatalogJson[];
|
|
3
|
-
export declare const CATALOG_PROVIDER_IDS: readonly ["a2agent", "above-dev", "ai21", "aiand", "aionlabs", "ambient", "api-route", "arcee", "atlas-cloud", "avian-io", "baidu-qianfan", "baseten", "bee-heossi", "byteplus-modelark", "bytez", "cerebras", "charm-hyper", "chutes", "cloudflare", "crusoe", "dashscope", "deepinfra", "deepseek", "empiriolabs", "featherless-ai", "fireworks", "friendli", "gmicloud", "gradientai", "groq", "hetzner-inference", "huggingface", "inception-labs", "inceptron", "inco", "inference-net", "io-intelligence", "koscompute", "lemonfox-ai", "lilac", "llmtech", "mancer", "meta-model-api", "minimax", "mistral", "moark", "modelscope", "moonshot-ai", "morph", "nebius", "neuralwatt", "novita", "ovhcloud", "parasail", "pareto-inference", "perplexity", "poolside", "prime-intellect", "reka", "sakana-ai", "sambanova", "sarvam", "scaleway", "siliconflow", "stackit", "stepfun", "subconscious", "synthetic", "telnyx", "thinking-machines", "tinfoil", "together-ai", "umans-ai", "upstage", "venice-ai", "vispark", "vultr-inference", "wafer", "wandb-inference", "xai", "z-ai"];
|
|
3
|
+
export declare const CATALOG_PROVIDER_IDS: readonly ["a2agent", "abliteration", "above-dev", "ai21", "aiand", "aihubmix", "aionlabs", "ambient", "api-route", "arcee", "atlas-cloud", "avian-io", "baidu-qianfan", "baseten", "bee-heossi", "byteplus-modelark", "bytez", "cerebras", "charm-hyper", "chutes", "cloudflare", "crusoe", "dashscope", "deepinfra", "deepseek", "empiriolabs", "featherless-ai", "fireworks", "friendli", "gmicloud", "gradientai", "groq", "hetzner-inference", "huggingface", "inception-labs", "inceptron", "inco", "inference-net", "io-intelligence", "koscompute", "lemonfox-ai", "lilac", "llmtech", "mancer", "meta-model-api", "minimax", "mistral", "moark", "modelscope", "moonshot-ai", "morph", "naver-clova-studio", "nebius", "neuralwatt", "novita", "ovhcloud", "parasail", "pareto-inference", "perplexity", "poolside", "prime-intellect", "reka", "sakana-ai", "sambanova", "sarvam", "scaleway", "siliconflow", "stackit", "stepfun", "subconscious", "synthetic", "telnyx", "thinking-machines", "tinfoil", "together-ai", "umans-ai", "upstage", "venice-ai", "vispark", "vultr-inference", "wafer", "wandb-inference", "xai", "z-ai"];
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// GENERATED FILE — do not edit. Regenerate with `pnpm run codegen:catalog`.
|
|
2
2
|
// Source of truth: the per-provider JSON files in this directory.
|
|
3
3
|
import a2agentJson from "./a2agent.json" with { type: "json" };
|
|
4
|
+
import abliterationJson from "./abliteration.json" with { type: "json" };
|
|
4
5
|
import aboveDevJson from "./above-dev.json" with { type: "json" };
|
|
5
6
|
import ai21Json from "./ai21.json" with { type: "json" };
|
|
6
7
|
import aiandJson from "./aiand.json" with { type: "json" };
|
|
8
|
+
import aihubmixJson from "./aihubmix.json" with { type: "json" };
|
|
7
9
|
import aionlabsJson from "./aionlabs.json" with { type: "json" };
|
|
8
10
|
import ambientJson from "./ambient.json" with { type: "json" };
|
|
9
11
|
import apiRouteJson from "./api-route.json" with { type: "json" };
|
|
@@ -49,6 +51,7 @@ import moarkJson from "./moark.json" with { type: "json" };
|
|
|
49
51
|
import modelscopeJson from "./modelscope.json" with { type: "json" };
|
|
50
52
|
import moonshotAiJson from "./moonshot-ai.json" with { type: "json" };
|
|
51
53
|
import morphJson from "./morph.json" with { type: "json" };
|
|
54
|
+
import naverClovaStudioJson from "./naver-clova-studio.json" with { type: "json" };
|
|
52
55
|
import nebiusJson from "./nebius.json" with { type: "json" };
|
|
53
56
|
import neuralwattJson from "./neuralwatt.json" with { type: "json" };
|
|
54
57
|
import novitaJson from "./novita.json" with { type: "json" };
|
|
@@ -83,9 +86,11 @@ import xaiJson from "./xai.json" with { type: "json" };
|
|
|
83
86
|
import zAiJson from "./z-ai.json" with { type: "json" };
|
|
84
87
|
export const CATALOG_JSON_ENTRIES = [
|
|
85
88
|
a2agentJson,
|
|
89
|
+
abliterationJson,
|
|
86
90
|
aboveDevJson,
|
|
87
91
|
ai21Json,
|
|
88
92
|
aiandJson,
|
|
93
|
+
aihubmixJson,
|
|
89
94
|
aionlabsJson,
|
|
90
95
|
ambientJson,
|
|
91
96
|
apiRouteJson,
|
|
@@ -131,6 +136,7 @@ export const CATALOG_JSON_ENTRIES = [
|
|
|
131
136
|
modelscopeJson,
|
|
132
137
|
moonshotAiJson,
|
|
133
138
|
morphJson,
|
|
139
|
+
naverClovaStudioJson,
|
|
134
140
|
nebiusJson,
|
|
135
141
|
neuralwattJson,
|
|
136
142
|
novitaJson,
|
|
@@ -166,9 +172,11 @@ export const CATALOG_JSON_ENTRIES = [
|
|
|
166
172
|
];
|
|
167
173
|
export const CATALOG_PROVIDER_IDS = [
|
|
168
174
|
"a2agent",
|
|
175
|
+
"abliteration",
|
|
169
176
|
"above-dev",
|
|
170
177
|
"ai21",
|
|
171
178
|
"aiand",
|
|
179
|
+
"aihubmix",
|
|
172
180
|
"aionlabs",
|
|
173
181
|
"ambient",
|
|
174
182
|
"api-route",
|
|
@@ -214,6 +222,7 @@ export const CATALOG_PROVIDER_IDS = [
|
|
|
214
222
|
"modelscope",
|
|
215
223
|
"moonshot-ai",
|
|
216
224
|
"morph",
|
|
225
|
+
"naver-clova-studio",
|
|
217
226
|
"nebius",
|
|
218
227
|
"neuralwatt",
|
|
219
228
|
"novita",
|
|
@@ -453,7 +453,7 @@
|
|
|
453
453
|
"date": "2026-09-03",
|
|
454
454
|
"result": "SDK end-to-end via dist: generate, stream, tool call (nonce round-trip) and json_schema structured output all pass. Tools + schema: after a tool result the vendor answers finish_reason=tool_calls with no tool_calls and null content when JSON is requested (4/4 raw replays); the SDK now re-asks that step once with tool_choice none and recovers the JSON — passed 1/1 in the final live proof through dist/index.js, tool nonce present in structuredData. structuredOutputWithTools is declared true on that basis."
|
|
455
455
|
},
|
|
456
|
-
"addedInPR": "
|
|
456
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1625",
|
|
457
457
|
"billingProbe": {
|
|
458
458
|
"date": "2026-09-03",
|
|
459
459
|
"status": 200,
|
|
@@ -176,6 +176,9 @@ export function buildCatalogEntries() {
|
|
|
176
176
|
if (entry.quirks?.replayReasoningContent) {
|
|
177
177
|
base.replayReasoningContent = true;
|
|
178
178
|
}
|
|
179
|
+
if (entry.quirks?.rejectRequiredToolChoice !== undefined) {
|
|
180
|
+
base.rejectRequiredToolChoice = entry.quirks.rejectRequiredToolChoice;
|
|
181
|
+
}
|
|
179
182
|
if (entry.quirks?.authHeaderStyle) {
|
|
180
183
|
base.authHeaderStyle = entry.quirks.authHeaderStyle;
|
|
181
184
|
}
|
|
@@ -187,6 +187,6 @@
|
|
|
187
187
|
"date": "2026-09-03",
|
|
188
188
|
"result": "18-probe harness on the free model mytholite: roster, chat, max_completion_tokens, system role, content parts, sampling params, SSE stream (usage chunk + [DONE]), json_schema (valid JSON matching schema) and json_object all 200; tools and tools+schema 400 BAD_PARAMETERS ('\"auto\" tool choice requires --enable-auto-tool-choice and --tool-call-parser') so tools are declared false; vision 200 but text-only (image ignored); bad key 401 'Bad API key'; unknown model 400 'Unknown Model'. Paid models could not be capability-probed without credits — tools may work there and can be re-declared once probed. Nightly matrix pins testModel mytholite."
|
|
189
189
|
},
|
|
190
|
-
"addedInPR": "
|
|
190
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1631"
|
|
191
191
|
}
|
|
192
192
|
}
|
|
@@ -92,6 +92,6 @@
|
|
|
92
92
|
"date": "2026-09-05",
|
|
93
93
|
"result": "Full wire probe on morph-v3-fast plus a focused tool-calling re-probe on both chat models. Non-tool basics all 200: chat, max_completion_tokens, system role, sampling params, SSE streaming (content deltas, usage chunk, [DONE]), json_schema (valid JSON matching schema) and json_object. Array-shaped message content is REJECTED with HTTP 500 'Request processing failed: text.charCodeAt is not a function' — same class of quirk as Cloudflare (PR #1587); messageContentFormat is set to 'string' and vision is false because the vision probe sends array parts and hits the identical 500. Tool calling does NOT work despite HTTP 200: morph-v3-large echoes the call as literal '<tool_call>{...}</tool_call>' text in message.content, and morph-v3-fast ignores the tools parameter and returns unrelated generated text (Python source) with finish_reason=length. tools and toolsWithStreaming are declared false on that basis; tools_plus_schema returning 200 is not evidence of structuredOutputWithTools since tools do not actually work. structuredOutput is true and strong (schema-conformant JSON, json_object accepted). The GET /v1/models roster lists 22 ids (morph-v3-fast, morph-v3-large, auto, morph-compactor, morph-warp-grep-v2.1, and passthrough ids for GLM/DeepSeek/Kimi/Qwen/MiniMax/Gemma/computer-use), but a deliberately invalid model name on /chat/completions came back 'is not served by this endpoint; accepted models: morph-v0, morph-v2, morph-v3-fast, morph-v3-large' — none of those other 18 roster ids were live-verified against chat/completions, so only the two confirmed working chat models are catalogued; context window (262144) and max output tokens (131072) for both come from Morph's public model metadata (https://www.morphllm.com/api/models/json), which also supplied pricing. Morph is a code-application (Fast Apply) specialist, not a general chat vendor: morph-v3-large is catalogued as the default because it is the general-purpose one of the pair, while morph-v3-fast is purpose-built for edit application rather than open-ended conversation."
|
|
94
94
|
},
|
|
95
|
-
"addedInPR": "
|
|
95
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1647"
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./provider-catalog.schema.json",
|
|
3
|
+
"id": "naver-clova-studio",
|
|
4
|
+
"displayName": "NAVER CLOVA Studio",
|
|
5
|
+
"aliases": [],
|
|
6
|
+
"tier": 2,
|
|
7
|
+
"wire": {
|
|
8
|
+
"baseURL": "https://clovastudio.stream.ntruss.com/v1/openai"
|
|
9
|
+
},
|
|
10
|
+
"models": {
|
|
11
|
+
"default": "HCX-005",
|
|
12
|
+
"fallbacks": ["HCX-005"],
|
|
13
|
+
"defaultContextWindow": 128000,
|
|
14
|
+
"defaultMaxOutputTokens": 4096,
|
|
15
|
+
"catalog": {
|
|
16
|
+
"HCX-005": {
|
|
17
|
+
"contextWindow": 128000,
|
|
18
|
+
"maxOutputTokens": 4096,
|
|
19
|
+
"vision": false,
|
|
20
|
+
"tools": true,
|
|
21
|
+
"status": "production",
|
|
22
|
+
"description": "Own Chat Completions v3 documentation names HCX-005 and states a combined input/output limit of 128,000 tokens and a maximum of 4,096 output tokens. The OpenAI-compatible guide uses the same model ID. This initial entry declares text and tool paths, not endpoint-specific image or native strict-schema acceptance. Account availability is unverified."
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"topModels": ["HCX-005"]
|
|
26
|
+
},
|
|
27
|
+
"capabilities": {
|
|
28
|
+
"text": true,
|
|
29
|
+
"streaming": true,
|
|
30
|
+
"tools": true,
|
|
31
|
+
"toolsWithStreaming": true,
|
|
32
|
+
"structuredOutput": false,
|
|
33
|
+
"structuredOutputWithTools": false,
|
|
34
|
+
"embeddings": false,
|
|
35
|
+
"thinking": false
|
|
36
|
+
},
|
|
37
|
+
"errorRules": [],
|
|
38
|
+
"quirks": {
|
|
39
|
+
"rejectRequiredToolChoice": true
|
|
40
|
+
},
|
|
41
|
+
"setup": {
|
|
42
|
+
"url": "https://console.ncloud.com",
|
|
43
|
+
"apiKeyFormat": null,
|
|
44
|
+
"billingPolicy": "promotional-credit",
|
|
45
|
+
"instructions": [
|
|
46
|
+
"Use an eligible NAVER Cloud account and subscribe to CLOVA Studio in the Korea region on Classic or VPC, following https://guide.ncloud-docs.com/docs/en/clovastudio-start.",
|
|
47
|
+
"The official new-signup program at https://www.ncloud.com/main/creditEvent, retrieved 2026-10-09, offers 100,000 KRW discount credit after payment-method registration and a credit application. Eligibility follows the policy at application time; prior recipients of other discounts cannot apply.",
|
|
48
|
+
"Issued credit is usable for three months against NAVER Cloud service charges. Free/trial products, Marketplace purchases and NAVER WORKS are excluded. This is a conditional promotional program, not a no-card free tier or proof of your current entitlement or balance.",
|
|
49
|
+
"Create a CLOVA Studio test or service API key under the CLOVA Studio API-key menu. Its OpenAI-compatible API accepts those keys with Authorization: Bearer; a general NAVER Cloud access key is not a substitute. Set {apiKeyEnvVar}.",
|
|
50
|
+
"The chat base is https://clovastudio.stream.ntruss.com/v1/openai and default model is HCX-005. Auto, none and named tool choices retain their documented meanings. Required tool choice is unsupported and explicitly rejected, never silently downgraded to auto."
|
|
51
|
+
],
|
|
52
|
+
"description": "Documentation-based source pilot. CLOVA Studio is usage-priced; conditional NAVER Cloud promotional credit requires payment-method registration/application and eligibility. Actual account subscription, models, credit balance and live API execution remain unverified. JSON-schema name/strict controls are ignored by the shim, so native strict-schema and tools-plus-schema support are not declared."
|
|
53
|
+
},
|
|
54
|
+
"evidence": {
|
|
55
|
+
"rosterVerified": {
|
|
56
|
+
"date": "2026-10-09",
|
|
57
|
+
"code": "DOCS_ONLY_ROSTER_NOT_OBSERVED",
|
|
58
|
+
"method": "Public first-party HCX-005 Chat v3 limits, OpenAI compatibility and function-calling documents only. No authenticated model roster, account/key lookup or inference performed. Limits 128,000 / 4,096 are explicit per-model source constraints, not K/M expansion."
|
|
59
|
+
},
|
|
60
|
+
"billingProbe": {
|
|
61
|
+
"date": "2026-10-09",
|
|
62
|
+
"code": "PUBLIC_PROMOTIONAL_POLICY_ONLY",
|
|
63
|
+
"method": "Public https://guide.ncloud-docs.com/docs/en/clovastudio-spec confirms usage fees; https://www.ncloud.com/main/creditEvent publishes conditional 100,000 KRW credit, valid three months, after payment-method registration and application. No card-only requirement or current account entitlement is claimed."
|
|
64
|
+
},
|
|
65
|
+
"liveMatrix": null,
|
|
66
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1966"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -109,6 +109,6 @@
|
|
|
109
109
|
"date": "2026-09-05",
|
|
110
110
|
"result": "18-probe harness against zai-org/glm-5.3-flash (Novita's own served default) via https://api.novita.ai/openai/v1. Wire mechanics: chat, system role, array content parts, sampling params and max_completion_tokens all 200; SSE streaming 200 with a usage chunk and a terminal [DONE]. Reasoning is genuinely heavy on this model \u2014 several 200 responses show finish_reason=length with only 8 completion tokens, entirely spent on an unfinished reasoning_content and an empty visible content \u2014 but `default` and `testModel` are both pinned to the probed model itself (zai-org/glm-5.3-flash, Novita's own served default), which is exactly what the capability matrix below exercises — see the structured-output findings further down for why the reasoning-heavy default is still the right choice over the plain meta-llama/llama-3.3-70b-instruct fallback. Tool calling: a real tool_call (get_time, parsed tz argument) on the first turn, a null-content assistant tool_calls turn accepted on replay, and a tool_call surfacing mid-SSE-stream \u2014 tools and toolsWithStreaming true; tool_choice is tolerated even with no tools declared. response_format json_object returns 200 cleanly \u2014 structuredOutput true. response_format json_schema also returns 200, but at this token budget the content is unfinished reasoning text rather than schema-conformant JSON, same reasoning-budget effect as above \u2014 NeuroLink's coerceJsonToSchema repair layer is the safety net here, as for other reasoning-heavy vendors. Sending tools and a JSON schema together in one request succeeds (200, real tool_call returned) at the wire level. That single-shot result alone does not demonstrate the combined capability \u2014 the follow-up turn where the model must answer the original JSON-schema question from a tool result was untested at raw-probe time. It was proved separately through the SDK's public surface: `generate({ provider: 'novita', schema, ...})` with a registered getTime tool called end-to-end via dist/index.js \u2014 the model invoked getTime(tz='Asia/Tokyo') (toolsUsed=['getTime'], stepsUsed=2), then answered `{\"city\":\"Tokyo\",\"time\":\"09:00\"}`, which parsed against the request schema with no repair needed (jsonRepaired/jsonTruncated both unset) \u2014 passed 1/1 in the final live proof. structuredOutputWithTools is declared true on that basis. Vision: a 64x64 PNG sent to glm-5.3-flash (not a vision-tagged model; Novita has no live-verified vision model) returns 200 with reasoning_content correctly describing 'a solid blue rectangle' but an EMPTY final content \u2014 not a working, schema-usable vision reply, so no catalog entry is marked vision:true and models.visionModel is left unset. bad key -> 401 {\"code\":401,\"reason\":\"FAILED_TO_AUTH\",\"message\":\"failed to authenticate API key\"}; bad model -> 404 {\"code\":404,\"reason\":\"MODEL_NOT_FOUND\",\"message\":\"model not found\"}. Novita funds this account with a $1 Model API voucher, so only this one model was live-probed end-to-end; the other four catalog entries are roster-verified by id only, not capability-probed. Structured output on Novita is per-model, and the catalog schema can only express it per provider. Verified 2026-09-05 at the wire: meta-llama/llama-3.3-70b-instruct returns HTTP 400 for response_format json_schema (\"does not support 'json_schema' response format. Supported formats: json_object\") and also 400 for json_object, while zai-org/glm-5.3-flash returns 200 for json_object, json_schema and tools+json_schema together. The default is therefore zai-org/glm-5.3-flash, which is also Novita's own served default, so the provider-level structuredOutput and structuredOutputWithTools flags are true for the model a default-configuration caller actually gets. meta-llama/llama-3.3-70b-instruct remains a fallback for plain chat. Tool calling was verified separately on both models (finish_reason=tool_calls with a structured call). Note that glm-5.3-flash is a reasoning model: at very small max_tokens (observed at 40) the budget is consumed by reasoning and content comes back empty; the entry's defaultMaxOutputTokens of 4096 is well clear of that."
|
|
111
111
|
},
|
|
112
|
-
"addedInPR": "
|
|
112
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1647"
|
|
113
113
|
}
|
|
114
114
|
}
|
|
@@ -121,10 +121,16 @@
|
|
|
121
121
|
"description": "Default: models.default."
|
|
122
122
|
},
|
|
123
123
|
"defaultContextWindow": {
|
|
124
|
-
"type": "
|
|
124
|
+
"type": "integer",
|
|
125
|
+
"minimum": 1,
|
|
126
|
+
"maximum": 9007199254740991,
|
|
127
|
+
"description": "Source-supported positive safe integer model default ceiling; unknown values are incomplete authoring drafts."
|
|
125
128
|
},
|
|
126
129
|
"defaultMaxOutputTokens": {
|
|
127
|
-
"type": "
|
|
130
|
+
"type": "integer",
|
|
131
|
+
"minimum": 1,
|
|
132
|
+
"maximum": 9007199254740991,
|
|
133
|
+
"description": "Source-supported positive safe integer model default ceiling; unknown values are incomplete authoring drafts."
|
|
128
134
|
},
|
|
129
135
|
"catalog": {
|
|
130
136
|
"type": "object",
|
|
@@ -215,7 +221,14 @@
|
|
|
215
221
|
"type": "boolean"
|
|
216
222
|
},
|
|
217
223
|
"tools": {
|
|
218
|
-
"anyOf": [
|
|
224
|
+
"anyOf": [
|
|
225
|
+
{
|
|
226
|
+
"type": "boolean"
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"const": "model-dependent"
|
|
230
|
+
}
|
|
231
|
+
],
|
|
219
232
|
"description": "\"model-dependent\" when tool support varies per served model and the vendor doesn't reject tools for unsupported ones (e.g. HuggingFace's router)."
|
|
220
233
|
},
|
|
221
234
|
"toolsWithStreaming": {
|
|
@@ -288,6 +301,10 @@
|
|
|
288
301
|
"type": "boolean",
|
|
289
302
|
"description": "Vendor wants each assistant turn's reasoning_content sent back on every later request of the conversation (DeepSeek documents a 400 without it once tools are in play). Off for every other provider, since strict OpenAI-compatible backends reject the unknown field."
|
|
290
303
|
},
|
|
304
|
+
"rejectRequiredToolChoice": {
|
|
305
|
+
"type": "boolean",
|
|
306
|
+
"description": "Reject tool_choice=required with nonempty tools before sending. Preserve auto/none/named choices and do not silently downgrade caller intent. Omitted leaves other providers unchanged."
|
|
307
|
+
},
|
|
291
308
|
"authHeaderStyle": {
|
|
292
309
|
"type": "string",
|
|
293
310
|
"enum": ["x-api-key"],
|
|
@@ -325,7 +342,13 @@
|
|
|
325
342
|
},
|
|
326
343
|
"billingPolicy": {
|
|
327
344
|
"type": "string",
|
|
328
|
-
"enum": [
|
|
345
|
+
"enum": [
|
|
346
|
+
"free-tier",
|
|
347
|
+
"free-with-card",
|
|
348
|
+
"no-free-tier",
|
|
349
|
+
"promotional-credit"
|
|
350
|
+
],
|
|
351
|
+
"description": "Promotional credit is conditional; setup instructions must state activation, eligibility and expiry without asserting current account entitlement."
|
|
329
352
|
},
|
|
330
353
|
"instructions": {
|
|
331
354
|
"type": "array",
|
|
@@ -77,8 +77,8 @@ export declare const providerCatalogJsonSchema: z.ZodObject<{
|
|
|
77
77
|
network: "network";
|
|
78
78
|
provider: "provider";
|
|
79
79
|
authentication: "authentication";
|
|
80
|
-
"invalid-model": "invalid-model";
|
|
81
80
|
"rate-limit": "rate-limit";
|
|
81
|
+
"invalid-model": "invalid-model";
|
|
82
82
|
}>;
|
|
83
83
|
message: z.ZodString;
|
|
84
84
|
}, z.core.$strict>>;
|
|
@@ -88,6 +88,7 @@ export declare const providerCatalogJsonSchema: z.ZodObject<{
|
|
|
88
88
|
registryDefaultIgnoresModelEnvVar: z.ZodOptional<z.ZodBoolean>;
|
|
89
89
|
responseFormatDowngrade: z.ZodOptional<z.ZodLiteral<"json-schema-to-json-object">>;
|
|
90
90
|
replayReasoningContent: z.ZodOptional<z.ZodBoolean>;
|
|
91
|
+
rejectRequiredToolChoice: z.ZodOptional<z.ZodBoolean>;
|
|
91
92
|
authHeaderStyle: z.ZodOptional<z.ZodLiteral<"x-api-key">>;
|
|
92
93
|
}, z.core.$strict>>;
|
|
93
94
|
timeouts: z.ZodOptional<z.ZodObject<{
|
|
@@ -102,6 +103,7 @@ export declare const providerCatalogJsonSchema: z.ZodObject<{
|
|
|
102
103
|
"no-free-tier": "no-free-tier";
|
|
103
104
|
"free-tier": "free-tier";
|
|
104
105
|
"free-with-card": "free-with-card";
|
|
106
|
+
"promotional-credit": "promotional-credit";
|
|
105
107
|
}>;
|
|
106
108
|
instructions: z.ZodArray<z.ZodString>;
|
|
107
109
|
description: z.ZodOptional<z.ZodString>;
|
|
@@ -150,6 +150,7 @@ const catalogQuirksSchema = z.strictObject({
|
|
|
150
150
|
registryDefaultIgnoresModelEnvVar: z.boolean().optional(),
|
|
151
151
|
responseFormatDowngrade: z.literal("json-schema-to-json-object").optional(),
|
|
152
152
|
replayReasoningContent: z.boolean().optional(),
|
|
153
|
+
rejectRequiredToolChoice: z.boolean().optional(),
|
|
153
154
|
authHeaderStyle: z.literal("x-api-key").optional(),
|
|
154
155
|
});
|
|
155
156
|
const catalogTimeoutsSchema = z.strictObject({
|
|
@@ -160,6 +161,7 @@ const catalogBillingPolicySchema = z.enum([
|
|
|
160
161
|
"free-tier",
|
|
161
162
|
"free-with-card",
|
|
162
163
|
"no-free-tier",
|
|
164
|
+
"promotional-credit",
|
|
163
165
|
]);
|
|
164
166
|
const catalogSetupSchema = z.strictObject({
|
|
165
167
|
url: z.string(),
|
|
@@ -202,8 +204,19 @@ const catalogModelsSchema = z
|
|
|
202
204
|
fallbacks: z.array(z.string()),
|
|
203
205
|
fallbackModelName: z.string().optional(),
|
|
204
206
|
registryDefaultModel: z.string().optional(),
|
|
205
|
-
|
|
206
|
-
|
|
207
|
+
// Catalog defaults are real model ceilings, never an unknown/zero
|
|
208
|
+
// placeholder. Caller maxTokens and optional model overrides are separate
|
|
209
|
+
// contracts and deliberately keep their existing validation semantics.
|
|
210
|
+
defaultContextWindow: z
|
|
211
|
+
.number()
|
|
212
|
+
.int()
|
|
213
|
+
.positive()
|
|
214
|
+
.max(Number.MAX_SAFE_INTEGER),
|
|
215
|
+
defaultMaxOutputTokens: z
|
|
216
|
+
.number()
|
|
217
|
+
.int()
|
|
218
|
+
.positive()
|
|
219
|
+
.max(Number.MAX_SAFE_INTEGER),
|
|
207
220
|
catalog: z.record(z.string(), catalogModelSpecSchema),
|
|
208
221
|
topModels: z.array(z.string()).min(1).optional(),
|
|
209
222
|
visionModel: z.string().optional(),
|
package/dist/providers/cohere.js
CHANGED
|
@@ -8,6 +8,7 @@ import { createCohereConfig, getProviderModel, validateApiKey, } from "../utils/
|
|
|
8
8
|
import { createTimeoutController } from "../utils/timeout.js";
|
|
9
9
|
import { stripTrailingSlash } from "./openaiChatCompletionsClient.js";
|
|
10
10
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
11
|
+
import { isFiniteEmbeddingVector } from "./embeddingResponseParsing.js";
|
|
11
12
|
const COHERE_DEFAULT_BASE_URL = "https://api.cohere.com/compatibility/v1";
|
|
12
13
|
const getCohereApiKey = () => validateApiKey(createCohereConfig());
|
|
13
14
|
const getDefaultCohereModel = () => getProviderModel("COHERE_MODEL", CohereModels.COMMAND_R_PLUS);
|
|
@@ -172,8 +173,12 @@ export class CohereProvider extends OpenAIChatCompletionsProvider {
|
|
|
172
173
|
const json = (await response.json());
|
|
173
174
|
const floatVecs = json.embeddings?.float ??
|
|
174
175
|
(Array.isArray(json.embeddings) ? json.embeddings : undefined);
|
|
175
|
-
if (!floatVecs || floatVecs.length !== batch.length) {
|
|
176
|
-
throw new ProviderError(`Cohere /v2/embed returned ${floatVecs
|
|
176
|
+
if (!Array.isArray(floatVecs) || floatVecs.length !== batch.length) {
|
|
177
|
+
throw new ProviderError(`Cohere /v2/embed returned ${Array.isArray(floatVecs) ? floatVecs.length : 0} embeddings for ${batch.length} inputs.`, "cohere");
|
|
178
|
+
}
|
|
179
|
+
if (!floatVecs.every(isFiniteEmbeddingVector)) {
|
|
180
|
+
const index = floatVecs.findIndex((v) => !isFiniteEmbeddingVector(v));
|
|
181
|
+
throw new ProviderError(`Cohere /v2/embed returned an invalid embedding at index ${index}: expected a nonempty array of finite numbers.`, "cohere");
|
|
177
182
|
}
|
|
178
183
|
results.push(...floatVecs);
|
|
179
184
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ProviderError } from "../types/index.js";
|
|
1
2
|
import { logger } from "../utils/logger.js";
|
|
2
3
|
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
3
4
|
import { getProviderModel, resolveOpenAICompatConfig, } from "../utils/providerConfig.js";
|
|
@@ -165,6 +166,12 @@ export class ConfiguredOpenAICompatProvider extends OpenAIChatCompletionsProvide
|
|
|
165
166
|
}
|
|
166
167
|
adjustRequestBody(body, modelId) {
|
|
167
168
|
const adjusted = super.adjustRequestBody(body, modelId);
|
|
169
|
+
if (this.entry.rejectRequiredToolChoice === true &&
|
|
170
|
+
adjusted.tool_choice === "required" &&
|
|
171
|
+
Array.isArray(adjusted.tools) &&
|
|
172
|
+
adjusted.tools.length > 0) {
|
|
173
|
+
throw new ProviderError("tool_choice='required' is not supported by this endpoint; use auto, none or a named tool choice", this.providerName);
|
|
174
|
+
}
|
|
168
175
|
if (this.entry.messageContentFormat !== "string") {
|
|
169
176
|
return adjusted;
|
|
170
177
|
}
|
|
@@ -1 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared embeddings-response validation for Voyage and Jina — both call
|
|
3
|
+
* POST /embeddings with an identical `{input, model}` body and get back an
|
|
4
|
+
* identical `{data: [{embedding, index}]}` shape, and both had byte-identical
|
|
5
|
+
* validation logic (same three message templates, same sort-by-index +
|
|
6
|
+
* 0..n-1 coverage check) before this was factored out.
|
|
7
|
+
*
|
|
8
|
+
* A plain function, not a shared base class: Voyage throws typed
|
|
9
|
+
* `ProviderError` here, Jina throws plain `Error` (a real, pre-existing
|
|
10
|
+
* inconsistency between the two — not something this refactor silently
|
|
11
|
+
* fixes). `makeError` preserves each provider's exact existing behavior;
|
|
12
|
+
* `providerLabel` preserves each provider's exact existing message text
|
|
13
|
+
* ("Voyage ..." / "Jina ...").
|
|
14
|
+
*/
|
|
15
|
+
export declare const isFiniteEmbeddingVector: (value: unknown) => value is number[];
|
|
1
16
|
export declare function parseIndexedEmbeddingsResponse(data: unknown, inputCount: number, providerLabel: string, makeError: (message: string) => Error): number[][];
|