@neondatabase/ai-sdk-provider 0.1.1 → 0.5.0
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/README.md +25 -14
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lib/neon-anthropic-language-model.d.ts +5 -5
- package/dist/lib/neon-anthropic-language-model.d.ts.map +1 -1
- package/dist/lib/neon-anthropic-language-model.js +2 -2
- package/dist/lib/neon-anthropic-language-model.js.map +1 -1
- package/dist/lib/neon-capabilities.d.ts +5 -5
- package/dist/lib/neon-capabilities.d.ts.map +1 -1
- package/dist/lib/neon-capabilities.js +2 -6
- package/dist/lib/neon-capabilities.js.map +1 -1
- package/dist/lib/neon-chat-language-model.d.ts +4 -4
- package/dist/lib/neon-chat-language-model.js.map +1 -1
- package/dist/lib/neon-chat-options.d.ts +18 -2
- package/dist/lib/neon-chat-options.d.ts.map +1 -1
- package/dist/lib/neon-chat-options.js +52 -1
- package/dist/lib/neon-chat-options.js.map +1 -0
- package/dist/lib/neon-model-capabilities.js.map +1 -1
- package/dist/lib/neon-responses-language-model.d.ts +9 -8
- package/dist/lib/neon-responses-language-model.d.ts.map +1 -1
- package/dist/lib/neon-responses-language-model.js +5 -4
- package/dist/lib/neon-responses-language-model.js.map +1 -1
- package/dist/lib/provider.d.ts +9 -5
- package/dist/lib/provider.d.ts.map +1 -1
- package/dist/lib/provider.js +16 -2
- package/dist/lib/provider.js.map +1 -1
- package/dist/package.js +1 -1
- package/package.json +10 -11
- package/dist/v1.d.ts +0 -7
- package/dist/v1.js +0 -6
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# @neondatabase/ai-sdk-provider
|
|
2
2
|
|
|
3
|
-
Community [Vercel AI SDK](https://ai-sdk.dev) provider for the [Neon](https://neon.com) AI Gateway.
|
|
3
|
+
Community [Vercel AI SDK](https://ai-sdk.dev) provider for the [Neon](https://neon.com) AI Gateway. Requires **AI SDK v6** (`ai@^6`).
|
|
4
4
|
|
|
5
|
-
The Neon AI Gateway is **branch-scoped**: each Neon project branch gets its own gateway host, and a platform token authorizes requests for that branch. This provider routes each model to the best gateway endpoint (Anthropic → native Messages, OpenAI → native Responses incl. **Codex**, everything else → unified OpenAI-compatible MLflow endpoint), so a single `neon('
|
|
5
|
+
The Neon AI Gateway is **branch-scoped**: each Neon project branch gets its own gateway host, and a platform token authorizes requests for that branch. This provider routes each model to the best gateway endpoint (Anthropic → native Messages, OpenAI → native Responses incl. **Codex**, everything else → unified OpenAI-compatible MLflow endpoint), so a single `neon('claude-...')` call reaches the whole catalog.
|
|
6
|
+
|
|
7
|
+
Model ids use the canonical Neon (unprefixed) form — `claude-sonnet-4-6`, `gpt-5`, `gemini-2-5-flash` — matching the [`neon` provider on models.dev](https://models.dev). The typed catalog mirrors that provider exactly (kept in sync by a scheduled drift check), plus a few extra gateway-served ids that models.dev doesn't list yet (e.g. Codex, Llama, Qwen). Any other id — including the legacy `databricks-` prefixed form (`databricks-claude-sonnet-4-6`) — is still accepted as a plain string, so existing code keeps working.
|
|
6
8
|
|
|
7
9
|
## Install
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
|
-
npm install @neondatabase/ai-sdk-provider
|
|
12
|
+
npm install @neondatabase/ai-sdk-provider ai@^6
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
## Configuration
|
|
@@ -22,12 +24,12 @@ NEON_AI_GATEWAY_TOKEN="nt_live_..."
|
|
|
22
24
|
## Usage
|
|
23
25
|
|
|
24
26
|
```ts
|
|
25
|
-
import { neon } from "@neondatabase/ai-sdk-provider
|
|
27
|
+
import { neon } from "@neondatabase/ai-sdk-provider";
|
|
26
28
|
import { generateText } from "ai";
|
|
27
29
|
|
|
28
30
|
// Reads NEON_AI_GATEWAY_BASE_URL + NEON_AI_GATEWAY_TOKEN from the environment.
|
|
29
31
|
const { text } = await generateText({
|
|
30
|
-
model: neon("
|
|
32
|
+
model: neon("claude-haiku-4-5"), // or 'gpt-5-3-codex', etc.
|
|
31
33
|
prompt: "Summarize Postgres for me.",
|
|
32
34
|
});
|
|
33
35
|
```
|
|
@@ -35,7 +37,7 @@ const { text } = await generateText({
|
|
|
35
37
|
Or configure explicitly with `createNeon`:
|
|
36
38
|
|
|
37
39
|
```ts
|
|
38
|
-
import { createNeon } from "@neondatabase/ai-sdk-provider
|
|
40
|
+
import { createNeon } from "@neondatabase/ai-sdk-provider";
|
|
39
41
|
|
|
40
42
|
const neon = createNeon({
|
|
41
43
|
baseURL: process.env.NEON_AI_GATEWAY_BASE_URL,
|
|
@@ -47,10 +49,12 @@ const neon = createNeon({
|
|
|
47
49
|
|
|
48
50
|
| Model family | Endpoint | Why |
|
|
49
51
|
| --- | --- | --- |
|
|
50
|
-
| Anthropic (`
|
|
51
|
-
| OpenAI (`
|
|
52
|
+
| Anthropic (`claude-*`) | native Messages API | streaming structured output + native reasoning |
|
|
53
|
+
| OpenAI (`gpt-*`, `*-codex`) | native Responses API | Codex (native-only), native reasoning, image-gen tool |
|
|
52
54
|
| Everything else (Gemini, Llama, Qwen, gpt-oss, ...) | unified MLflow endpoint | broad coverage; Gemini is here because its native endpoint does not support streaming |
|
|
53
55
|
|
|
56
|
+
Routing matches on the model id, so both the canonical (`gpt-5`) and the legacy `databricks-`-prefixed (`databricks-gpt-5`) forms route identically.
|
|
57
|
+
|
|
54
58
|
## Capabilities
|
|
55
59
|
|
|
56
60
|
Verified across Anthropic, OpenAI (incl. Codex), Google, and Meta models: `generateText` / `streamText` (text, system prompts, multi-turn), tool calling (single and multi-step, generate and stream), `generateObject` / `streamObject`, and image (vision) input.
|
|
@@ -63,13 +67,12 @@ Available on OpenAI models via the Responses `image_generation` tool (there is n
|
|
|
63
67
|
|
|
64
68
|
```ts
|
|
65
69
|
import { streamText } from "ai";
|
|
66
|
-
import { neon } from "@neondatabase/ai-sdk-provider
|
|
67
|
-
import { imageGeneration } from "@ai-sdk/openai/internal";
|
|
70
|
+
import { neon } from "@neondatabase/ai-sdk-provider";
|
|
68
71
|
|
|
69
72
|
const result = streamText({
|
|
70
|
-
model: neon("
|
|
73
|
+
model: neon("gpt-5-mini"),
|
|
71
74
|
prompt: "Generate an image of a red apple on a wooden table",
|
|
72
|
-
tools: { image: imageGeneration({ partialImages: 3 }) },
|
|
75
|
+
tools: { image: neon.tools.imageGeneration({ partialImages: 3 }) },
|
|
73
76
|
});
|
|
74
77
|
|
|
75
78
|
for await (const part of result.fullStream) {
|
|
@@ -84,7 +87,15 @@ for await (const part of result.fullStream) {
|
|
|
84
87
|
|
|
85
88
|
- `generateImage()` and embeddings (`embed` / `embedMany`) are not offered by the gateway and throw `NoSuchModelError`.
|
|
86
89
|
- `gpt-oss-*` models return a non-standard ("harmony") response shape on the unified endpoint and are not fully supported.
|
|
90
|
+
- OpenAI Responses multi-turn tool flows (`generateText` + `stepCountIs`) can return 502 from the gateway; tool calling is covered on Anthropic/Google/Meta in e2e.
|
|
91
|
+
|
|
92
|
+
## End-to-end tests
|
|
87
93
|
|
|
88
|
-
|
|
94
|
+
Against a live branch with AI Gateway enabled:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
cp .env.example .env # fill NEON_AI_GATEWAY_BASE_URL + NEON_AI_GATEWAY_TOKEN from `neonctl env pull`
|
|
98
|
+
pnpm test:e2e
|
|
99
|
+
```
|
|
89
100
|
|
|
90
|
-
|
|
101
|
+
The matrix covers one models.dev `neon` model per family (Anthropic, OpenAI, Codex, Gemini, Meta) across `generateText`, `streamText`, `generateObject`, tool calling, and `neon.tools.imageGeneration`. Skipped when gateway env vars are absent.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NeonAnthropicLanguageModel } from "./lib/neon-anthropic-language-model.js";
|
|
2
2
|
import { NeonChatLanguageModel } from "./lib/neon-chat-language-model.js";
|
|
3
|
-
import { NeonChatModelId } from "./lib/neon-chat-options.js";
|
|
3
|
+
import { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS, NeonChatModelId, NeonKnownModelId } from "./lib/neon-chat-options.js";
|
|
4
4
|
import { NeonModelCapabilities, NeonModelFamily, NeonModelRoute, getNeonModelCapabilities, getNeonModelRoute } from "./lib/neon-model-capabilities.js";
|
|
5
5
|
import { NeonResponsesLanguageModel } from "./lib/neon-responses-language-model.js";
|
|
6
6
|
import { NeonErrorData, NeonProvider, NeonProviderSettings, createNeon, neon } from "./lib/provider.js";
|
|
7
|
-
export { NeonAnthropicLanguageModel, NeonChatLanguageModel, NeonChatModelId, NeonErrorData, NeonModelCapabilities, NeonModelFamily, NeonModelRoute, NeonProvider, NeonProviderSettings, NeonResponsesLanguageModel, createNeon, getNeonModelCapabilities, getNeonModelRoute, neon };
|
|
7
|
+
export { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS, NeonAnthropicLanguageModel, NeonChatLanguageModel, type NeonChatModelId, type NeonErrorData, type NeonKnownModelId, type NeonModelCapabilities, type NeonModelFamily, type NeonModelRoute, type NeonProvider, type NeonProviderSettings, NeonResponsesLanguageModel, createNeon, getNeonModelCapabilities, getNeonModelRoute, neon };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NeonAnthropicLanguageModel } from "./lib/neon-anthropic-language-model.js";
|
|
2
2
|
import { getNeonModelCapabilities, getNeonModelRoute } from "./lib/neon-model-capabilities.js";
|
|
3
3
|
import { NeonChatLanguageModel } from "./lib/neon-chat-language-model.js";
|
|
4
|
+
import { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS } from "./lib/neon-chat-options.js";
|
|
4
5
|
import { NeonResponsesLanguageModel } from "./lib/neon-responses-language-model.js";
|
|
5
6
|
import { createNeon, neon } from "./lib/provider.js";
|
|
6
|
-
|
|
7
|
-
export { NeonAnthropicLanguageModel, NeonChatLanguageModel, NeonResponsesLanguageModel, createNeon, getNeonModelCapabilities, getNeonModelRoute, neon };
|
|
7
|
+
export { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS, NeonAnthropicLanguageModel, NeonChatLanguageModel, NeonResponsesLanguageModel, createNeon, getNeonModelCapabilities, getNeonModelRoute, neon };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { AnthropicMessagesLanguageModel } from "@ai-sdk/anthropic/internal";
|
|
2
|
+
import { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3GenerateResult, LanguageModelV3StreamResult } from "@ai-sdk/provider";
|
|
3
3
|
|
|
4
4
|
//#region src/lib/neon-anthropic-language-model.d.ts
|
|
5
5
|
|
|
@@ -13,10 +13,10 @@ import { LanguageModelV4, LanguageModelV4CallOptions, LanguageModelV4GenerateRes
|
|
|
13
13
|
* rejects (`Extra inputs are not permitted`). We disable it via the model's own
|
|
14
14
|
* `toolStreaming` option so streaming tool calls work. Users can still override.
|
|
15
15
|
*/
|
|
16
|
-
declare class NeonAnthropicLanguageModel extends
|
|
16
|
+
declare class NeonAnthropicLanguageModel extends AnthropicMessagesLanguageModel implements LanguageModelV3 {
|
|
17
17
|
private withGatewayCompat;
|
|
18
|
-
doGenerate(options:
|
|
19
|
-
doStream(options:
|
|
18
|
+
doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult>;
|
|
19
|
+
doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult>;
|
|
20
20
|
}
|
|
21
21
|
//#endregion
|
|
22
22
|
export { NeonAnthropicLanguageModel };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-anthropic-language-model.d.ts","names":[],"sources":["../../src/lib/neon-anthropic-language-model.ts"],"mappings":";;;;;;;AAkBA;;;;;;;;AACS,cADI,0BAAA,SACJ,
|
|
1
|
+
{"version":3,"file":"neon-anthropic-language-model.d.ts","names":[],"sources":["../../src/lib/neon-anthropic-language-model.ts"],"mappings":";;;;;;;AAkBA;;;;;;;;AACS,cADI,0BAAA,SACJ,8BAAA,YACG,eADH,CAAA;UACG,iBAAA;EAAe,UAAA,CAAA,OAAA,EAoBhB,0BApBgB,CAAA,EAqBvB,OArBuB,CAqBf,6BArBe,CAAA;oBA0BhB,6BACP,QAAQ"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AnthropicMessagesLanguageModel } from "@ai-sdk/anthropic/internal";
|
|
2
2
|
//#region src/lib/neon-anthropic-language-model.ts
|
|
3
3
|
/**
|
|
4
4
|
* Language model for Anthropic models served via the Neon AI Gateway's native
|
|
@@ -10,7 +10,7 @@ import { AnthropicLanguageModel } from "@ai-sdk/anthropic/internal";
|
|
|
10
10
|
* rejects (`Extra inputs are not permitted`). We disable it via the model's own
|
|
11
11
|
* `toolStreaming` option so streaming tool calls work. Users can still override.
|
|
12
12
|
*/
|
|
13
|
-
var NeonAnthropicLanguageModel = class extends
|
|
13
|
+
var NeonAnthropicLanguageModel = class extends AnthropicMessagesLanguageModel {
|
|
14
14
|
withGatewayCompat(options) {
|
|
15
15
|
const anthropic = options.providerOptions?.anthropic;
|
|
16
16
|
if (anthropic != null && "toolStreaming" in anthropic) return options;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-anthropic-language-model.js","names":[],"sources":["../../src/lib/neon-anthropic-language-model.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"neon-anthropic-language-model.js","names":[],"sources":["../../src/lib/neon-anthropic-language-model.ts"],"sourcesContent":["import { AnthropicMessagesLanguageModel } from \"@ai-sdk/anthropic/internal\";\nimport type {\n\tLanguageModelV3,\n\tLanguageModelV3CallOptions,\n\tLanguageModelV3GenerateResult,\n\tLanguageModelV3StreamResult,\n} from \"@ai-sdk/provider\";\n\n/**\n * Language model for Anthropic models served via the Neon AI Gateway's native\n * Messages API (`/ai-gateway/anthropic/v1/messages`). Unlocks streaming\n * structured output and native reasoning for Claude.\n *\n * The shared Anthropic model defaults to fine-grained tool-input streaming\n * (`eager_input_streaming: true`) on streaming tool calls, which the gateway\n * rejects (`Extra inputs are not permitted`). We disable it via the model's own\n * `toolStreaming` option so streaming tool calls work. Users can still override.\n */\nexport class NeonAnthropicLanguageModel\n\textends AnthropicMessagesLanguageModel\n\timplements LanguageModelV3\n{\n\tprivate withGatewayCompat(\n\t\toptions: LanguageModelV3CallOptions,\n\t): LanguageModelV3CallOptions {\n\t\tconst anthropic = options.providerOptions?.anthropic;\n\t\t// Respect an explicit user setting.\n\t\tif (anthropic != null && \"toolStreaming\" in anthropic) {\n\t\t\treturn options;\n\t\t}\n\t\treturn {\n\t\t\t...options,\n\t\t\tproviderOptions: {\n\t\t\t\t...options.providerOptions,\n\t\t\t\tanthropic: { ...anthropic, toolStreaming: false },\n\t\t\t},\n\t\t};\n\t}\n\n\toverride doGenerate(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3GenerateResult> {\n\t\treturn super.doGenerate(this.withGatewayCompat(options));\n\t}\n\n\toverride doStream(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3StreamResult> {\n\t\treturn super.doStream(this.withGatewayCompat(options));\n\t}\n}\n"],"mappings":";;;;;;;;;;;;AAkBA,IAAa,6BAAb,cACS,+BAET;CACC,kBACC,SAC6B;EAC7B,MAAM,YAAY,QAAQ,iBAAiB;EAE3C,IAAI,aAAa,QAAQ,mBAAmB,WAC3C,OAAO;EAER,OAAO;GACN,GAAG;GACH,iBAAiB;IAChB,GAAG,QAAQ;IACX,WAAW;KAAE,GAAG;KAAW,eAAe;IAAM;GACjD;EACD;CACD;CAEA,WACC,SACyC;EACzC,OAAO,MAAM,WAAW,KAAK,kBAAkB,OAAO,CAAC;CACxD;CAEA,SACC,SACuC;EACvC,OAAO,MAAM,SAAS,KAAK,kBAAkB,OAAO,CAAC;CACtD;AACD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LanguageModelV3CallOptions, LanguageModelV3StreamPart, SharedV3Warning } from "@ai-sdk/provider";
|
|
2
2
|
|
|
3
3
|
//#region src/lib/neon-capabilities.d.ts
|
|
4
4
|
|
|
@@ -7,14 +7,14 @@ import { LanguageModelV4CallOptions, LanguageModelV4StreamPart, SharedV4Warning
|
|
|
7
7
|
* collect a warning for each, so callers get a clear signal instead of a hard
|
|
8
8
|
* `400` from the gateway.
|
|
9
9
|
*/
|
|
10
|
-
declare function applyNeonCapabilities(modelId: string, options:
|
|
11
|
-
options:
|
|
12
|
-
warnings:
|
|
10
|
+
declare function applyNeonCapabilities(modelId: string, options: LanguageModelV3CallOptions): {
|
|
11
|
+
options: LanguageModelV3CallOptions;
|
|
12
|
+
warnings: SharedV3Warning[];
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
15
|
* Merge additional warnings into the `stream-start` part of a model stream.
|
|
16
16
|
*/
|
|
17
|
-
declare function mergeStreamStartWarnings(extra:
|
|
17
|
+
declare function mergeStreamStartWarnings(extra: SharedV3Warning[]): TransformStream<LanguageModelV3StreamPart, LanguageModelV3StreamPart>;
|
|
18
18
|
//#endregion
|
|
19
19
|
export { applyNeonCapabilities, mergeStreamStartWarnings };
|
|
20
20
|
//# sourceMappingURL=neon-capabilities.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-capabilities.d.ts","names":[],"sources":["../../src/lib/neon-capabilities.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"neon-capabilities.d.ts","names":[],"sources":["../../src/lib/neon-capabilities.ts"],"mappings":";;;;;;AAaA;;;AAGc,iBAHE,qBAAA,CAGF,OAAA,EAAA,MAAA,EAAA,OAAA,EADJ,0BACI,CAAA,EAAA;SAAsC,EAAtC,0BAAsC;EAAe,QAAA,EAAf,eAAe,EAAA;AA4FnE,CAAA;;;;AAAiE,iBAAjD,wBAAA,CAAiD,KAAA,EAAjB,eAAiB,EAAA,CAAA,EAAA,eAAA,CAAA,yBAAA,EAAA,yBAAA,CAAA"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getNeonModelCapabilities } from "./neon-model-capabilities.js";
|
|
2
|
-
import { isCustomReasoning } from "@ai-sdk/provider-utils";
|
|
3
2
|
//#region src/lib/neon-capabilities.ts
|
|
4
3
|
/**
|
|
5
4
|
* Drop call options the resolved model's upstream backend does not accept and
|
|
@@ -53,11 +52,9 @@ function applyNeonCapabilities(modelId, options) {
|
|
|
53
52
|
}
|
|
54
53
|
if (!caps.supportsReasoningEffort) {
|
|
55
54
|
const { providerOptions } = options;
|
|
56
|
-
|
|
57
|
-
const hasReasoningOption = isCustomReasoning(options.reasoning) && options.reasoning !== "none";
|
|
58
|
-
if (hasProviderEffort || hasReasoningOption) {
|
|
55
|
+
if (providerOptions != null && Object.values(providerOptions).some((group) => "reasoningEffort" in group && group.reasoningEffort != null)) {
|
|
59
56
|
dropUnsupported("reasoningEffort");
|
|
60
|
-
if (
|
|
57
|
+
if (providerOptions != null) {
|
|
61
58
|
const cleaned = {};
|
|
62
59
|
for (const [key, group] of Object.entries(providerOptions)) if ("reasoningEffort" in group) {
|
|
63
60
|
const { reasoningEffort: _removed, ...rest } = group;
|
|
@@ -65,7 +62,6 @@ function applyNeonCapabilities(modelId, options) {
|
|
|
65
62
|
} else cleaned[key] = group;
|
|
66
63
|
patch.providerOptions = cleaned;
|
|
67
64
|
}
|
|
68
|
-
if (hasReasoningOption) patch.reasoning = void 0;
|
|
69
65
|
}
|
|
70
66
|
}
|
|
71
67
|
if (Object.keys(patch).length === 0) return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-capabilities.js","names":[],"sources":["../../src/lib/neon-capabilities.ts"],"sourcesContent":["import type {\n\
|
|
1
|
+
{"version":3,"file":"neon-capabilities.js","names":[],"sources":["../../src/lib/neon-capabilities.ts"],"sourcesContent":["import type {\n\tLanguageModelV3CallOptions,\n\tLanguageModelV3StreamPart,\n\tSharedV3ProviderOptions,\n\tSharedV3Warning,\n} from \"@ai-sdk/provider\";\nimport { getNeonModelCapabilities } from \"./neon-model-capabilities.js\";\n\n/**\n * Drop call options the resolved model's upstream backend does not accept and\n * collect a warning for each, so callers get a clear signal instead of a hard\n * `400` from the gateway.\n */\nexport function applyNeonCapabilities(\n\tmodelId: string,\n\toptions: LanguageModelV3CallOptions,\n): { options: LanguageModelV3CallOptions; warnings: SharedV3Warning[] } {\n\tconst caps = getNeonModelCapabilities(modelId);\n\tconst warnings: SharedV3Warning[] = [];\n\tconst patch: Partial<LanguageModelV3CallOptions> = {};\n\n\tconst dropUnsupported = (feature: string) => {\n\t\twarnings.push({\n\t\t\ttype: \"unsupported\",\n\t\t\tfeature,\n\t\t\tdetails: `${feature} is not supported by the Neon AI Gateway for ${caps.family} model \"${modelId}\" and was dropped.`,\n\t\t});\n\t};\n\n\tif (options.temperature != null && !caps.supportsTemperature) {\n\t\tpatch.temperature = undefined;\n\t\tdropUnsupported(\"temperature\");\n\t}\n\tif (options.topP != null && !caps.supportsTopP) {\n\t\tpatch.topP = undefined;\n\t\tdropUnsupported(\"topP\");\n\t}\n\n\t// Anthropic-style models accept only one of temperature / topP.\n\tconst effectiveTemperature =\n\t\t\"temperature\" in patch ? patch.temperature : options.temperature;\n\tconst effectiveTopP = \"topP\" in patch ? patch.topP : options.topP;\n\tif (\n\t\tcaps.temperatureTopPMutuallyExclusive &&\n\t\teffectiveTemperature != null &&\n\t\teffectiveTopP != null\n\t) {\n\t\tpatch.topP = undefined;\n\t\twarnings.push({\n\t\t\ttype: \"compatibility\",\n\t\t\tfeature: \"topP\",\n\t\t\tdetails: `${caps.family} models accept only one of temperature or topP; topP was dropped.`,\n\t\t});\n\t}\n\n\tif (options.frequencyPenalty != null && !caps.supportsPenalties) {\n\t\tpatch.frequencyPenalty = undefined;\n\t\tdropUnsupported(\"frequencyPenalty\");\n\t}\n\tif (options.presencePenalty != null && !caps.supportsPenalties) {\n\t\tpatch.presencePenalty = undefined;\n\t\tdropUnsupported(\"presencePenalty\");\n\t}\n\tif (options.seed != null && !caps.supportsSeed) {\n\t\tpatch.seed = undefined;\n\t\tdropUnsupported(\"seed\");\n\t}\n\n\tif (options.stopSequences != null && !caps.supportsStopSequences) {\n\t\tpatch.stopSequences = undefined;\n\t\tdropUnsupported(\"stopSequences\");\n\t}\n\n\tif (!caps.supportsReasoningEffort) {\n\t\tconst { providerOptions } = options;\n\t\tconst hasProviderEffort =\n\t\t\tproviderOptions != null &&\n\t\t\tObject.values(providerOptions).some(\n\t\t\t\t(group) =>\n\t\t\t\t\t\"reasoningEffort\" in group && group.reasoningEffort != null,\n\t\t\t);\n\n\t\tif (hasProviderEffort) {\n\t\t\tdropUnsupported(\"reasoningEffort\");\n\t\t\tif (providerOptions != null) {\n\t\t\t\tconst cleaned: SharedV3ProviderOptions = {};\n\t\t\t\tfor (const [key, group] of Object.entries(providerOptions)) {\n\t\t\t\t\tif (\"reasoningEffort\" in group) {\n\t\t\t\t\t\tconst { reasoningEffort: _removed, ...rest } = group;\n\t\t\t\t\t\tcleaned[key] = rest;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcleaned[key] = group;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpatch.providerOptions = cleaned;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (Object.keys(patch).length === 0) {\n\t\treturn { options, warnings };\n\t}\n\treturn { options: { ...options, ...patch }, warnings };\n}\n\n/**\n * Merge additional warnings into the `stream-start` part of a model stream.\n */\nexport function mergeStreamStartWarnings(extra: SharedV3Warning[]) {\n\tlet merged = false;\n\treturn new TransformStream<\n\t\tLanguageModelV3StreamPart,\n\t\tLanguageModelV3StreamPart\n\t>({\n\t\ttransform(part, controller) {\n\t\t\tif (!merged && part.type === \"stream-start\") {\n\t\t\t\tmerged = true;\n\t\t\t\tcontroller.enqueue({\n\t\t\t\t\t...part,\n\t\t\t\t\twarnings: [...extra, ...part.warnings],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tcontroller.enqueue(part);\n\t\t\t}\n\t\t},\n\t});\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,sBACf,SACA,SACuE;CACvE,MAAM,OAAO,yBAAyB,OAAO;CAC7C,MAAM,WAA8B,CAAC;CACrC,MAAM,QAA6C,CAAC;CAEpD,MAAM,mBAAmB,YAAoB;EAC5C,SAAS,KAAK;GACb,MAAM;GACN;GACA,SAAS,GAAG,QAAQ,+CAA+C,KAAK,OAAO,UAAU,QAAQ;EAClG,CAAC;CACF;CAEA,IAAI,QAAQ,eAAe,QAAQ,CAAC,KAAK,qBAAqB;EAC7D,MAAM,cAAc,KAAA;EACpB,gBAAgB,aAAa;CAC9B;CACA,IAAI,QAAQ,QAAQ,QAAQ,CAAC,KAAK,cAAc;EAC/C,MAAM,OAAO,KAAA;EACb,gBAAgB,MAAM;CACvB;CAGA,MAAM,uBACL,iBAAiB,QAAQ,MAAM,cAAc,QAAQ;CACtD,MAAM,gBAAgB,UAAU,QAAQ,MAAM,OAAO,QAAQ;CAC7D,IACC,KAAK,oCACL,wBAAwB,QACxB,iBAAiB,MAChB;EACD,MAAM,OAAO,KAAA;EACb,SAAS,KAAK;GACb,MAAM;GACN,SAAS;GACT,SAAS,GAAG,KAAK,OAAO;EACzB,CAAC;CACF;CAEA,IAAI,QAAQ,oBAAoB,QAAQ,CAAC,KAAK,mBAAmB;EAChE,MAAM,mBAAmB,KAAA;EACzB,gBAAgB,kBAAkB;CACnC;CACA,IAAI,QAAQ,mBAAmB,QAAQ,CAAC,KAAK,mBAAmB;EAC/D,MAAM,kBAAkB,KAAA;EACxB,gBAAgB,iBAAiB;CAClC;CACA,IAAI,QAAQ,QAAQ,QAAQ,CAAC,KAAK,cAAc;EAC/C,MAAM,OAAO,KAAA;EACb,gBAAgB,MAAM;CACvB;CAEA,IAAI,QAAQ,iBAAiB,QAAQ,CAAC,KAAK,uBAAuB;EACjE,MAAM,gBAAgB,KAAA;EACtB,gBAAgB,eAAe;CAChC;CAEA,IAAI,CAAC,KAAK,yBAAyB;EAClC,MAAM,EAAE,oBAAoB;EAQ5B,IANC,mBAAmB,QACnB,OAAO,OAAO,eAAe,CAAC,CAAC,MAC7B,UACA,qBAAqB,SAAS,MAAM,mBAAmB,IACzD,GAEsB;GACtB,gBAAgB,iBAAiB;GACjC,IAAI,mBAAmB,MAAM;IAC5B,MAAM,UAAmC,CAAC;IAC1C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,eAAe,GACxD,IAAI,qBAAqB,OAAO;KAC/B,MAAM,EAAE,iBAAiB,UAAU,GAAG,SAAS;KAC/C,QAAQ,OAAO;IAChB,OACC,QAAQ,OAAO;IAGjB,MAAM,kBAAkB;GACzB;EACD;CACD;CAEA,IAAI,OAAO,KAAK,KAAK,CAAC,CAAC,WAAW,GACjC,OAAO;EAAE;EAAS;CAAS;CAE5B,OAAO;EAAE,SAAS;GAAE,GAAG;GAAS,GAAG;EAAM;EAAG;CAAS;AACtD;;;;AAKA,SAAgB,yBAAyB,OAA0B;CAClE,IAAI,SAAS;CACb,OAAO,IAAI,gBAGT,EACD,UAAU,MAAM,YAAY;EAC3B,IAAI,CAAC,UAAU,KAAK,SAAS,gBAAgB;GAC5C,SAAS;GACT,WAAW,QAAQ;IAClB,GAAG;IACH,UAAU,CAAC,GAAG,OAAO,GAAG,KAAK,QAAQ;GACtC,CAAC;EACF,OACC,WAAW,QAAQ,IAAI;CAEzB,EACD,CAAC;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OpenAICompatibleChatLanguageModel } from "@ai-sdk/openai-compatible";
|
|
2
|
-
import {
|
|
2
|
+
import { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3GenerateResult, LanguageModelV3StreamResult } from "@ai-sdk/provider";
|
|
3
3
|
|
|
4
4
|
//#region src/lib/neon-chat-language-model.d.ts
|
|
5
5
|
|
|
@@ -12,9 +12,9 @@ import { LanguageModelV4, LanguageModelV4CallOptions, LanguageModelV4GenerateRes
|
|
|
12
12
|
* parameters an upstream backend is known to reject are dropped and reported as
|
|
13
13
|
* warnings instead of failing the request.
|
|
14
14
|
*/
|
|
15
|
-
declare class NeonChatLanguageModel extends OpenAICompatibleChatLanguageModel implements
|
|
16
|
-
doGenerate(options:
|
|
17
|
-
doStream(options:
|
|
15
|
+
declare class NeonChatLanguageModel extends OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
|
|
16
|
+
doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult>;
|
|
17
|
+
doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult>;
|
|
18
18
|
}
|
|
19
19
|
//#endregion
|
|
20
20
|
export { NeonChatLanguageModel };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-chat-language-model.js","names":[],"sources":["../../src/lib/neon-chat-language-model.ts"],"sourcesContent":["import { OpenAICompatibleChatLanguageModel } from \"@ai-sdk/openai-compatible\";\nimport type {\n\
|
|
1
|
+
{"version":3,"file":"neon-chat-language-model.js","names":[],"sources":["../../src/lib/neon-chat-language-model.ts"],"sourcesContent":["import { OpenAICompatibleChatLanguageModel } from \"@ai-sdk/openai-compatible\";\nimport type {\n\tLanguageModelV3,\n\tLanguageModelV3CallOptions,\n\tLanguageModelV3GenerateResult,\n\tLanguageModelV3StreamResult,\n} from \"@ai-sdk/provider\";\nimport {\n\tapplyNeonCapabilities,\n\tmergeStreamStartWarnings,\n} from \"./neon-capabilities.js\";\n\n/**\n * Language model for the Neon AI Gateway unified (MLflow) endpoint.\n *\n * Used for every model that is not routed to a provider-native endpoint\n * (Gemini, Llama, Qwen, gpt-oss, ...). It is a thin specialization of the shared\n * OpenAI-compatible chat model that adds per-model capability handling:\n * parameters an upstream backend is known to reject are dropped and reported as\n * warnings instead of failing the request.\n */\nexport class NeonChatLanguageModel\n\textends OpenAICompatibleChatLanguageModel\n\timplements LanguageModelV3\n{\n\toverride async doGenerate(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3GenerateResult> {\n\t\tconst { options: adjusted, warnings } = applyNeonCapabilities(\n\t\t\tthis.modelId,\n\t\t\toptions,\n\t\t);\n\t\tconst result = await super.doGenerate(adjusted);\n\t\treturn warnings.length > 0\n\t\t\t? { ...result, warnings: [...warnings, ...result.warnings] }\n\t\t\t: result;\n\t}\n\n\toverride async doStream(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3StreamResult> {\n\t\tconst { options: adjusted, warnings } = applyNeonCapabilities(\n\t\t\tthis.modelId,\n\t\t\toptions,\n\t\t);\n\t\tconst result = await super.doStream(adjusted);\n\t\treturn warnings.length > 0\n\t\t\t? {\n\t\t\t\t\t...result,\n\t\t\t\t\tstream: result.stream.pipeThrough(\n\t\t\t\t\t\tmergeStreamStartWarnings(warnings),\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t: result;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;AAqBA,IAAa,wBAAb,cACS,kCAET;CACC,MAAe,WACd,SACyC;EACzC,MAAM,EAAE,SAAS,UAAU,aAAa,sBACvC,KAAK,SACL,OACD;EACA,MAAM,SAAS,MAAM,MAAM,WAAW,QAAQ;EAC9C,OAAO,SAAS,SAAS,IACtB;GAAE,GAAG;GAAQ,UAAU,CAAC,GAAG,UAAU,GAAG,OAAO,QAAQ;EAAE,IACzD;CACJ;CAEA,MAAe,SACd,SACuC;EACvC,MAAM,EAAE,SAAS,UAAU,aAAa,sBACvC,KAAK,SACL,OACD;EACA,MAAM,SAAS,MAAM,MAAM,SAAS,QAAQ;EAC5C,OAAO,SAAS,SAAS,IACtB;GACA,GAAG;GACH,QAAQ,OAAO,OAAO,YACrB,yBAAyB,QAAQ,CAClC;EACD,IACC;CACJ;AACD"}
|
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
//#region src/lib/neon-chat-options.d.ts
|
|
2
|
-
|
|
2
|
+
/** The models.dev `neon` catalog (canonical, unprefixed ids). */
|
|
3
|
+
declare const NEON_MODELS_DEV_IDS: readonly ["claude-opus-4-7", "claude-opus-4-6", "claude-opus-4-5", "claude-opus-4-1", "claude-sonnet-4-6", "claude-sonnet-4-5", "claude-sonnet-4", "claude-haiku-4-5", "gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-5-1", "gpt-5-2", "gpt-5-4", "gpt-5-4-mini", "gpt-5-4-nano", "gpt-5-5", "gpt-oss-120b", "gpt-oss-20b", "gemini-3-pro", "gemini-3-flash", "gemini-3-1-pro", "gemini-3-1-flash-lite", "gemini-2-5-pro", "gemini-2-5-flash"];
|
|
4
|
+
/**
|
|
5
|
+
* Ids the gateway serves that the models.dev `neon` provider does not list.
|
|
6
|
+
* Verified to resolve against the gateway; retained for autocomplete. If
|
|
7
|
+
* models.dev later lists one of these, the drift check flags it for promotion
|
|
8
|
+
* into `NEON_MODELS_DEV_IDS`.
|
|
9
|
+
*/
|
|
10
|
+
declare const NEON_EXTRA_MODEL_IDS: readonly ["claude-opus-4-8", "gpt-5-2-codex", "gpt-5-3-codex", "gpt-5-5-pro", "gemini-3-5-flash", "gemma-3-12b", "llama-4-maverick", "meta-llama-3-3-70b-instruct", "meta-llama-3-1-8b-instruct", "qwen3-next-80b-a3b-instruct", "qwen35-122b-a10b"];
|
|
11
|
+
/** A known Neon AI Gateway model id (models.dev catalog + gateway extras). */
|
|
12
|
+
type NeonKnownModelId = (typeof NEON_MODELS_DEV_IDS)[number] | (typeof NEON_EXTRA_MODEL_IDS)[number];
|
|
13
|
+
/**
|
|
14
|
+
* A Neon AI Gateway model id. Known ids are listed for autocomplete; any other
|
|
15
|
+
* id (e.g. a brand-new model, or the legacy `databricks-` prefixed form) is
|
|
16
|
+
* accepted via the `(string & {})` fallback.
|
|
17
|
+
*/
|
|
18
|
+
type NeonChatModelId = NeonKnownModelId | (string & {});
|
|
3
19
|
//#endregion
|
|
4
|
-
export { NeonChatModelId };
|
|
20
|
+
export { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS, NeonChatModelId, NeonKnownModelId };
|
|
5
21
|
//# sourceMappingURL=neon-chat-options.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-chat-options.d.ts","names":[],"sources":["../../src/lib/neon-chat-options.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"neon-chat-options.d.ts","names":[],"sources":["../../src/lib/neon-chat-options.ts"],"mappings":";;AAiBa,cAAA,mBA8BH,EAAA,SAAA,CAAA,iBAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,mBAAA,EAAA,iBAAA,EAAA,kBAAA,EAAA,OAAA,EAAA,YAAA,EAAA,YAAA,EAAA,SAAA,EAAA,SAAA,EAAA,SAAA,EAAA,cAAA,EAAA,cAAA,EAAA,SAAA,EAAA,cAAA,EAAA,aAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,gBAAA,EAAA,uBAAA,EAAA,gBAAA,EAAA,kBAAA,CAAA;AAQV;AAoBA;;;;AAE+B;AAOnB,cA7BC,oBA6BiB,EAAA,SAAgB,CAAA,iBAAA,EAAA,eAAA,EAAA,eAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,6BAAA,EAAA,4BAAA,EAAA,6BAAA,EAAA,kBAAA,CAAA;;KATlC,gBAAA,WACD,uCACA;;;;;;KAOC,eAAA,GAAkB"}
|
|
@@ -1 +1,52 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/lib/neon-chat-options.ts
|
|
2
|
+
/** The models.dev `neon` catalog (canonical, unprefixed ids). */
|
|
3
|
+
const NEON_MODELS_DEV_IDS = [
|
|
4
|
+
"claude-opus-4-7",
|
|
5
|
+
"claude-opus-4-6",
|
|
6
|
+
"claude-opus-4-5",
|
|
7
|
+
"claude-opus-4-1",
|
|
8
|
+
"claude-sonnet-4-6",
|
|
9
|
+
"claude-sonnet-4-5",
|
|
10
|
+
"claude-sonnet-4",
|
|
11
|
+
"claude-haiku-4-5",
|
|
12
|
+
"gpt-5",
|
|
13
|
+
"gpt-5-mini",
|
|
14
|
+
"gpt-5-nano",
|
|
15
|
+
"gpt-5-1",
|
|
16
|
+
"gpt-5-2",
|
|
17
|
+
"gpt-5-4",
|
|
18
|
+
"gpt-5-4-mini",
|
|
19
|
+
"gpt-5-4-nano",
|
|
20
|
+
"gpt-5-5",
|
|
21
|
+
"gpt-oss-120b",
|
|
22
|
+
"gpt-oss-20b",
|
|
23
|
+
"gemini-3-pro",
|
|
24
|
+
"gemini-3-flash",
|
|
25
|
+
"gemini-3-1-pro",
|
|
26
|
+
"gemini-3-1-flash-lite",
|
|
27
|
+
"gemini-2-5-pro",
|
|
28
|
+
"gemini-2-5-flash"
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* Ids the gateway serves that the models.dev `neon` provider does not list.
|
|
32
|
+
* Verified to resolve against the gateway; retained for autocomplete. If
|
|
33
|
+
* models.dev later lists one of these, the drift check flags it for promotion
|
|
34
|
+
* into `NEON_MODELS_DEV_IDS`.
|
|
35
|
+
*/
|
|
36
|
+
const NEON_EXTRA_MODEL_IDS = [
|
|
37
|
+
"claude-opus-4-8",
|
|
38
|
+
"gpt-5-2-codex",
|
|
39
|
+
"gpt-5-3-codex",
|
|
40
|
+
"gpt-5-5-pro",
|
|
41
|
+
"gemini-3-5-flash",
|
|
42
|
+
"gemma-3-12b",
|
|
43
|
+
"llama-4-maverick",
|
|
44
|
+
"meta-llama-3-3-70b-instruct",
|
|
45
|
+
"meta-llama-3-1-8b-instruct",
|
|
46
|
+
"qwen3-next-80b-a3b-instruct",
|
|
47
|
+
"qwen35-122b-a10b"
|
|
48
|
+
];
|
|
49
|
+
//#endregion
|
|
50
|
+
export { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=neon-chat-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"neon-chat-options.js","names":[],"sources":["../../src/lib/neon-chat-options.ts"],"sourcesContent":["// Models served by the Neon AI Gateway. Anthropic and OpenAI models are routed\n// to their provider-native endpoints; everything else uses the unified MLflow\n// (OpenAI-compatible) endpoint.\n//\n// Ids use the canonical Neon (unprefixed) form, matching the `neon` provider on\n// models.dev. The gateway also accepts the legacy `databricks-` prefixed form\n// (the `databricks` provider on models.dev), which still resolves via the\n// `(string & {})` fallback on `NeonChatModelId`.\n//\n// `NEON_MODELS_DEV_IDS` mirrors the models.dev `neon` catalog exactly — the\n// `neon-catalog-drift.test.ts` maintainer check fails if the two diverge.\n// `NEON_EXTRA_MODEL_IDS` are additional ids the gateway serves that models.dev\n// does not (yet) list; they are kept for autocomplete and verified to resolve\n// against the gateway. The authoritative, always-current catalog is shown in\n// the Neon Console under the branch's \"AI Gateway\" tab.\n\n/** The models.dev `neon` catalog (canonical, unprefixed ids). */\nexport const NEON_MODELS_DEV_IDS = [\n\t// Anthropic (native Messages API)\n\t\"claude-opus-4-7\",\n\t\"claude-opus-4-6\",\n\t\"claude-opus-4-5\",\n\t\"claude-opus-4-1\",\n\t\"claude-sonnet-4-6\",\n\t\"claude-sonnet-4-5\",\n\t\"claude-sonnet-4\",\n\t\"claude-haiku-4-5\",\n\t// OpenAI (native Responses API)\n\t\"gpt-5\",\n\t\"gpt-5-mini\",\n\t\"gpt-5-nano\",\n\t\"gpt-5-1\",\n\t\"gpt-5-2\",\n\t\"gpt-5-4\",\n\t\"gpt-5-4-mini\",\n\t\"gpt-5-4-nano\",\n\t\"gpt-5-5\",\n\t// OpenAI open-weight (unified MLflow endpoint)\n\t\"gpt-oss-120b\",\n\t\"gpt-oss-20b\",\n\t// Google (unified MLflow endpoint)\n\t\"gemini-3-pro\",\n\t\"gemini-3-flash\",\n\t\"gemini-3-1-pro\",\n\t\"gemini-3-1-flash-lite\",\n\t\"gemini-2-5-pro\",\n\t\"gemini-2-5-flash\",\n] as const;\n\n/**\n * Ids the gateway serves that the models.dev `neon` provider does not list.\n * Verified to resolve against the gateway; retained for autocomplete. If\n * models.dev later lists one of these, the drift check flags it for promotion\n * into `NEON_MODELS_DEV_IDS`.\n */\nexport const NEON_EXTRA_MODEL_IDS = [\n\t// Anthropic (native Messages API)\n\t\"claude-opus-4-8\",\n\t// OpenAI (native Responses API) — Codex is served only natively\n\t\"gpt-5-2-codex\",\n\t\"gpt-5-3-codex\",\n\t\"gpt-5-5-pro\",\n\t// Google (unified MLflow endpoint)\n\t\"gemini-3-5-flash\",\n\t\"gemma-3-12b\",\n\t// Meta (unified MLflow endpoint)\n\t\"llama-4-maverick\",\n\t\"meta-llama-3-3-70b-instruct\",\n\t\"meta-llama-3-1-8b-instruct\",\n\t// Alibaba (unified MLflow endpoint)\n\t\"qwen3-next-80b-a3b-instruct\",\n\t\"qwen35-122b-a10b\",\n] as const;\n\n/** A known Neon AI Gateway model id (models.dev catalog + gateway extras). */\nexport type NeonKnownModelId =\n\t| (typeof NEON_MODELS_DEV_IDS)[number]\n\t| (typeof NEON_EXTRA_MODEL_IDS)[number];\n\n/**\n * A Neon AI Gateway model id. Known ids are listed for autocomplete; any other\n * id (e.g. a brand-new model, or the legacy `databricks-` prefixed form) is\n * accepted via the `(string & {})` fallback.\n */\nexport type NeonChatModelId = NeonKnownModelId | (string & {});\n"],"mappings":";;AAiBA,MAAa,sBAAsB;CAElC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;AACD;;;;;;;AAQA,MAAa,uBAAuB;CAEnC;CAEA;CACA;CACA;CAEA;CACA;CAEA;CACA;CACA;CAEA;CACA;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-model-capabilities.js","names":[],"sources":["../../src/lib/neon-model-capabilities.ts"],"sourcesContent":["export type NeonModelFamily =\n\t| \"anthropic\"\n\t| \"google\"\n\t| \"openai\"\n\t| \"meta\"\n\t| \"other\";\n\n/**\n * Which gateway endpoint a model should be routed to.\n *\n * - `anthropic`: native Messages API — streaming structured output + native reasoning.\n * - `openai`: native Responses API — models served only natively (e.g. Codex),\n * native reasoning, and the image-generation tool.\n * - `mlflow`: the unified, OpenAI-compatible endpoint (the fallback). Gemini is\n * routed here because the gateway's native Gemini endpoint does not support\n * streaming (`streamGenerateContent` is rejected).\n */\nexport type NeonModelRoute = \"anthropic\" | \"openai\" | \"mlflow\";\n\nexport function getNeonModelRoute(modelId: string): NeonModelRoute {\n\tconst id = modelId.toLowerCase();\n\tif (id.includes(\"claude\")) {\n\t\treturn \"anthropic\";\n\t}\n\t// OpenAI proprietary models (gpt-4/gpt-5 families, Codex) are served only via\n\t// the native Responses API. `gpt-oss` is open-weight and served on the\n\t// unified chat endpoint, so it is intentionally excluded here.\n\tif (\n\t\t(id.includes(\"gpt-\") && !id.includes(\"gpt-oss\")) ||\n\t\tid.includes(\"codex\")\n\t) {\n\t\treturn \"openai\";\n\t}\n\treturn \"mlflow\";\n}\n\nexport interface NeonModelCapabilities {\n\tfamily: NeonModelFamily;\n\tsupportsTemperature: boolean;\n\tsupportsTopP: boolean;\n\t/**\n\t * Whether `temperature` and `topP` may be sent together. Anthropic models\n\t * accept only one of the two.\n\t */\n\ttemperatureTopPMutuallyExclusive: boolean;\n\tsupportsPenalties: boolean;\n\tsupportsSeed: boolean;\n\tsupportsStopSequences: boolean;\n\tsupportsReasoningEffort: boolean;\n}\n\nconst PERMISSIVE: Omit<NeonModelCapabilities, \"family\"> = {\n\tsupportsTemperature: true,\n\tsupportsTopP: true,\n\ttemperatureTopPMutuallyExclusive: false,\n\tsupportsPenalties: true,\n\tsupportsSeed: true,\n\tsupportsStopSequences: true,\n\tsupportsReasoningEffort: true,\n};\n\n/**\n * Heuristic, prefix-based capability detection for MLflow-routed Neon models.\n *\n * The unified endpoint proxies to heterogeneous upstream providers, each of\n * which accepts a different subset of the OpenAI-style parameters the AI SDK\n * emits. Sending a parameter an upstream rejects results in a hard `400`, so we\n * strip the parameters a family is known to reject and surface a warning\n * instead. Unknown/untested models stay permissive (passed through unchanged).\n */\nexport function getNeonModelCapabilities(\n\tmodelId: string,\n): NeonModelCapabilities {\n\tconst id = modelId.toLowerCase();\n\n\t// Anthropic (Claude): rejects penalties and seed, accepts only one of\n\t// temperature/topP, and rejects the OpenAI `reasoning_effort` field.\n\tif (id.includes(\"claude\")) {\n\t\treturn {\n\t\t\tfamily: \"anthropic\",\n\t\t\tsupportsTemperature: true,\n\t\t\tsupportsTopP: true,\n\t\t\ttemperatureTopPMutuallyExclusive: true,\n\t\t\tsupportsPenalties: false,\n\t\t\tsupportsSeed: false,\n\t\t\tsupportsStopSequences: true,\n\t\t\tsupportsReasoningEffort: false,\n\t\t};\n\t}\n\n\t// Google (Gemini): accepts standard sampling params but rejects the OpenAI\n\t// `reasoning_effort` field (not part of Gemini's generation config).\n\tif (id.includes(\"gemini\")) {\n\t\treturn {\n\t\t\tfamily: \"google\",\n\t\t\t...PERMISSIVE,\n\t\t\tsupportsReasoningEffort: false,\n\t\t};\n\t}\n\n\t// OpenAI GPT-5 reasoning family (routed to the native Responses API). The\n\t// Responses model strips parameters the Responses API doesn't accept\n\t// (penalties, seed, stop), but its reasoning-model detection matches the bare\n\t// model id (`gpt-5`), which the gateway's `databricks-` prefix
|
|
1
|
+
{"version":3,"file":"neon-model-capabilities.js","names":[],"sources":["../../src/lib/neon-model-capabilities.ts"],"sourcesContent":["export type NeonModelFamily =\n\t| \"anthropic\"\n\t| \"google\"\n\t| \"openai\"\n\t| \"meta\"\n\t| \"other\";\n\n/**\n * Which gateway endpoint a model should be routed to.\n *\n * - `anthropic`: native Messages API — streaming structured output + native reasoning.\n * - `openai`: native Responses API — models served only natively (e.g. Codex),\n * native reasoning, and the image-generation tool.\n * - `mlflow`: the unified, OpenAI-compatible endpoint (the fallback). Gemini is\n * routed here because the gateway's native Gemini endpoint does not support\n * streaming (`streamGenerateContent` is rejected).\n */\nexport type NeonModelRoute = \"anthropic\" | \"openai\" | \"mlflow\";\n\nexport function getNeonModelRoute(modelId: string): NeonModelRoute {\n\tconst id = modelId.toLowerCase();\n\tif (id.includes(\"claude\")) {\n\t\treturn \"anthropic\";\n\t}\n\t// OpenAI proprietary models (gpt-4/gpt-5 families, Codex) are served only via\n\t// the native Responses API. `gpt-oss` is open-weight and served on the\n\t// unified chat endpoint, so it is intentionally excluded here.\n\tif (\n\t\t(id.includes(\"gpt-\") && !id.includes(\"gpt-oss\")) ||\n\t\tid.includes(\"codex\")\n\t) {\n\t\treturn \"openai\";\n\t}\n\treturn \"mlflow\";\n}\n\nexport interface NeonModelCapabilities {\n\tfamily: NeonModelFamily;\n\tsupportsTemperature: boolean;\n\tsupportsTopP: boolean;\n\t/**\n\t * Whether `temperature` and `topP` may be sent together. Anthropic models\n\t * accept only one of the two.\n\t */\n\ttemperatureTopPMutuallyExclusive: boolean;\n\tsupportsPenalties: boolean;\n\tsupportsSeed: boolean;\n\tsupportsStopSequences: boolean;\n\tsupportsReasoningEffort: boolean;\n}\n\nconst PERMISSIVE: Omit<NeonModelCapabilities, \"family\"> = {\n\tsupportsTemperature: true,\n\tsupportsTopP: true,\n\ttemperatureTopPMutuallyExclusive: false,\n\tsupportsPenalties: true,\n\tsupportsSeed: true,\n\tsupportsStopSequences: true,\n\tsupportsReasoningEffort: true,\n};\n\n/**\n * Heuristic, prefix-based capability detection for MLflow-routed Neon models.\n *\n * The unified endpoint proxies to heterogeneous upstream providers, each of\n * which accepts a different subset of the OpenAI-style parameters the AI SDK\n * emits. Sending a parameter an upstream rejects results in a hard `400`, so we\n * strip the parameters a family is known to reject and surface a warning\n * instead. Unknown/untested models stay permissive (passed through unchanged).\n */\nexport function getNeonModelCapabilities(\n\tmodelId: string,\n): NeonModelCapabilities {\n\tconst id = modelId.toLowerCase();\n\n\t// Anthropic (Claude): rejects penalties and seed, accepts only one of\n\t// temperature/topP, and rejects the OpenAI `reasoning_effort` field.\n\tif (id.includes(\"claude\")) {\n\t\treturn {\n\t\t\tfamily: \"anthropic\",\n\t\t\tsupportsTemperature: true,\n\t\t\tsupportsTopP: true,\n\t\t\ttemperatureTopPMutuallyExclusive: true,\n\t\t\tsupportsPenalties: false,\n\t\t\tsupportsSeed: false,\n\t\t\tsupportsStopSequences: true,\n\t\t\tsupportsReasoningEffort: false,\n\t\t};\n\t}\n\n\t// Google (Gemini): accepts standard sampling params but rejects the OpenAI\n\t// `reasoning_effort` field (not part of Gemini's generation config).\n\tif (id.includes(\"gemini\")) {\n\t\treturn {\n\t\t\tfamily: \"google\",\n\t\t\t...PERMISSIVE,\n\t\t\tsupportsReasoningEffort: false,\n\t\t};\n\t}\n\n\t// OpenAI GPT-5 reasoning family (routed to the native Responses API). The\n\t// Responses model strips parameters the Responses API doesn't accept\n\t// (penalties, seed, stop), but its reasoning-model detection matches the bare\n\t// model id (`gpt-5`), which the gateway's optional `databricks-` prefix can\n\t// defeat. So we only handle the temperature/topP restriction here: the\n\t// original gpt-5 / gpt-5-mini / gpt-5-nano require the default temperature and\n\t// reject topP, while gpt-5.1+ (a minor version digit follows) accept them\n\t// again. The regex matches both prefixed and unprefixed ids.\n\tif (/gpt-5/.test(id)) {\n\t\tconst hasMinorVersion = /gpt-5[.-]\\d/.test(id);\n\t\treturn {\n\t\t\tfamily: \"openai\",\n\t\t\tsupportsTemperature: hasMinorVersion,\n\t\t\tsupportsTopP: hasMinorVersion,\n\t\t\ttemperatureTopPMutuallyExclusive: false,\n\t\t\tsupportsPenalties: true,\n\t\t\tsupportsSeed: true,\n\t\t\tsupportsStopSequences: true,\n\t\t\tsupportsReasoningEffort: true,\n\t\t};\n\t}\n\n\t// Meta (Llama): rejects penalties and seed; accepts sampling params and stop.\n\tif (id.includes(\"llama\")) {\n\t\treturn {\n\t\t\tfamily: \"meta\",\n\t\t\tsupportsTemperature: true,\n\t\t\tsupportsTopP: true,\n\t\t\ttemperatureTopPMutuallyExclusive: false,\n\t\t\tsupportsPenalties: false,\n\t\t\tsupportsSeed: false,\n\t\t\tsupportsStopSequences: true,\n\t\t\tsupportsReasoningEffort: true,\n\t\t};\n\t}\n\n\treturn { family: \"other\", ...PERMISSIVE };\n}\n"],"mappings":";AAmBA,SAAgB,kBAAkB,SAAiC;CAClE,MAAM,KAAK,QAAQ,YAAY;CAC/B,IAAI,GAAG,SAAS,QAAQ,GACvB,OAAO;CAKR,IACE,GAAG,SAAS,MAAM,KAAK,CAAC,GAAG,SAAS,SAAS,KAC9C,GAAG,SAAS,OAAO,GAEnB,OAAO;CAER,OAAO;AACR;AAiBA,MAAM,aAAoD;CACzD,qBAAqB;CACrB,cAAc;CACd,kCAAkC;CAClC,mBAAmB;CACnB,cAAc;CACd,uBAAuB;CACvB,yBAAyB;AAC1B;;;;;;;;;;AAWA,SAAgB,yBACf,SACwB;CACxB,MAAM,KAAK,QAAQ,YAAY;CAI/B,IAAI,GAAG,SAAS,QAAQ,GACvB,OAAO;EACN,QAAQ;EACR,qBAAqB;EACrB,cAAc;EACd,kCAAkC;EAClC,mBAAmB;EACnB,cAAc;EACd,uBAAuB;EACvB,yBAAyB;CAC1B;CAKD,IAAI,GAAG,SAAS,QAAQ,GACvB,OAAO;EACN,QAAQ;EACR,GAAG;EACH,yBAAyB;CAC1B;CAWD,IAAI,QAAQ,KAAK,EAAE,GAAG;EACrB,MAAM,kBAAkB,cAAc,KAAK,EAAE;EAC7C,OAAO;GACN,QAAQ;GACR,qBAAqB;GACrB,cAAc;GACd,kCAAkC;GAClC,mBAAmB;GACnB,cAAc;GACd,uBAAuB;GACvB,yBAAyB;EAC1B;CACD;CAGA,IAAI,GAAG,SAAS,OAAO,GACtB,OAAO;EACN,QAAQ;EACR,qBAAqB;EACrB,cAAc;EACd,kCAAkC;EAClC,mBAAmB;EACnB,cAAc;EACd,uBAAuB;EACvB,yBAAyB;CAC1B;CAGD,OAAO;EAAE,QAAQ;EAAS,GAAG;CAAW;AACzC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OpenAIResponsesLanguageModel } from "@ai-sdk/openai/internal";
|
|
2
|
-
import {
|
|
2
|
+
import { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3GenerateResult, LanguageModelV3StreamResult } from "@ai-sdk/provider";
|
|
3
3
|
|
|
4
4
|
//#region src/lib/neon-responses-language-model.d.ts
|
|
5
5
|
|
|
@@ -10,16 +10,17 @@ import { LanguageModelV4, LanguageModelV4CallOptions, LanguageModelV4GenerateRes
|
|
|
10
10
|
* reasoning and the image-generation tool.
|
|
11
11
|
*
|
|
12
12
|
* The shared OpenAI Responses model shapes a request based on whether the model
|
|
13
|
-
* is a reasoning model, but
|
|
14
|
-
*
|
|
15
|
-
* reasoning family we set the model's own
|
|
16
|
-
* applies the correct reasoning behavior
|
|
13
|
+
* is a reasoning model, but its detection is brittle here: the gateway also
|
|
14
|
+
* accepts the legacy `databricks-` prefix, which defeats the upstream bare-id
|
|
15
|
+
* (`gpt-5`) match. For the GPT-5 reasoning family we set the model's own
|
|
16
|
+
* `forceReasoning` provider option so it applies the correct reasoning behavior
|
|
17
|
+
* for both id forms. Users can still override it.
|
|
17
18
|
*/
|
|
18
|
-
declare class NeonResponsesLanguageModel extends OpenAIResponsesLanguageModel implements
|
|
19
|
+
declare class NeonResponsesLanguageModel extends OpenAIResponsesLanguageModel implements LanguageModelV3 {
|
|
19
20
|
private get isReasoningFamily();
|
|
20
21
|
private withForcedReasoning;
|
|
21
|
-
doGenerate(options:
|
|
22
|
-
doStream(options:
|
|
22
|
+
doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult>;
|
|
23
|
+
doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult>;
|
|
23
24
|
}
|
|
24
25
|
//#endregion
|
|
25
26
|
export { NeonResponsesLanguageModel };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-responses-language-model.d.ts","names":[],"sources":["../../src/lib/neon-responses-language-model.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"neon-responses-language-model.d.ts","names":[],"sources":["../../src/lib/neon-responses-language-model.ts"],"mappings":";;;;;;;AAqBA;;;;;;;;;;AAE2B;cAFd,0BAAA,SACJ,4BAAA,YACG;;;sBA2BD,6BACP,QAAQ;oBAKD,6BACP,QAAQ"}
|
|
@@ -7,10 +7,11 @@ import { OpenAIResponsesLanguageModel } from "@ai-sdk/openai/internal";
|
|
|
7
7
|
* reasoning and the image-generation tool.
|
|
8
8
|
*
|
|
9
9
|
* The shared OpenAI Responses model shapes a request based on whether the model
|
|
10
|
-
* is a reasoning model, but
|
|
11
|
-
*
|
|
12
|
-
* reasoning family we set the model's own
|
|
13
|
-
* applies the correct reasoning behavior
|
|
10
|
+
* is a reasoning model, but its detection is brittle here: the gateway also
|
|
11
|
+
* accepts the legacy `databricks-` prefix, which defeats the upstream bare-id
|
|
12
|
+
* (`gpt-5`) match. For the GPT-5 reasoning family we set the model's own
|
|
13
|
+
* `forceReasoning` provider option so it applies the correct reasoning behavior
|
|
14
|
+
* for both id forms. Users can still override it.
|
|
14
15
|
*/
|
|
15
16
|
var NeonResponsesLanguageModel = class extends OpenAIResponsesLanguageModel {
|
|
16
17
|
get isReasoningFamily() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-responses-language-model.js","names":[],"sources":["../../src/lib/neon-responses-language-model.ts"],"sourcesContent":["import { OpenAIResponsesLanguageModel } from \"@ai-sdk/openai/internal\";\nimport type {\n\
|
|
1
|
+
{"version":3,"file":"neon-responses-language-model.js","names":[],"sources":["../../src/lib/neon-responses-language-model.ts"],"sourcesContent":["import { OpenAIResponsesLanguageModel } from \"@ai-sdk/openai/internal\";\nimport type {\n\tLanguageModelV3,\n\tLanguageModelV3CallOptions,\n\tLanguageModelV3GenerateResult,\n\tLanguageModelV3StreamResult,\n} from \"@ai-sdk/provider\";\n\n/**\n * Language model for OpenAI models served via the Neon AI Gateway's native\n * Responses API (`/ai-gateway/openai/v1/responses`). This route is required for\n * models that are only served natively (e.g. Codex) and unlocks native\n * reasoning and the image-generation tool.\n *\n * The shared OpenAI Responses model shapes a request based on whether the model\n * is a reasoning model, but its detection is brittle here: the gateway also\n * accepts the legacy `databricks-` prefix, which defeats the upstream bare-id\n * (`gpt-5`) match. For the GPT-5 reasoning family we set the model's own\n * `forceReasoning` provider option so it applies the correct reasoning behavior\n * for both id forms. Users can still override it.\n */\nexport class NeonResponsesLanguageModel\n\textends OpenAIResponsesLanguageModel\n\timplements LanguageModelV3\n{\n\tprivate get isReasoningFamily(): boolean {\n\t\treturn /gpt-5/.test(this.modelId.toLowerCase());\n\t}\n\n\tprivate withForcedReasoning(\n\t\toptions: LanguageModelV3CallOptions,\n\t): LanguageModelV3CallOptions {\n\t\tif (!this.isReasoningFamily) {\n\t\t\treturn options;\n\t\t}\n\t\tconst openai = options.providerOptions?.openai;\n\t\t// Respect an explicit user setting.\n\t\tif (openai != null && \"forceReasoning\" in openai) {\n\t\t\treturn options;\n\t\t}\n\t\treturn {\n\t\t\t...options,\n\t\t\tproviderOptions: {\n\t\t\t\t...options.providerOptions,\n\t\t\t\topenai: { ...openai, forceReasoning: true },\n\t\t\t},\n\t\t};\n\t}\n\n\toverride doGenerate(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3GenerateResult> {\n\t\treturn super.doGenerate(this.withForcedReasoning(options));\n\t}\n\n\toverride doStream(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3StreamResult> {\n\t\treturn super.doStream(this.withForcedReasoning(options));\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,IAAa,6BAAb,cACS,6BAET;CACC,IAAY,oBAA6B;EACxC,OAAO,QAAQ,KAAK,KAAK,QAAQ,YAAY,CAAC;CAC/C;CAEA,oBACC,SAC6B;EAC7B,IAAI,CAAC,KAAK,mBACT,OAAO;EAER,MAAM,SAAS,QAAQ,iBAAiB;EAExC,IAAI,UAAU,QAAQ,oBAAoB,QACzC,OAAO;EAER,OAAO;GACN,GAAG;GACH,iBAAiB;IAChB,GAAG,QAAQ;IACX,QAAQ;KAAE,GAAG;KAAQ,gBAAgB;IAAK;GAC3C;EACD;CACD;CAEA,WACC,SACyC;EACzC,OAAO,MAAM,WAAW,KAAK,oBAAoB,OAAO,CAAC;CAC1D;CAEA,SACC,SACuC;EACvC,OAAO,MAAM,SAAS,KAAK,oBAAoB,OAAO,CAAC;CACxD;AACD"}
|
package/dist/lib/provider.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { NeonChatModelId } from "./neon-chat-options.js";
|
|
2
|
+
import { openai } from "@ai-sdk/openai";
|
|
3
|
+
import { LanguageModelV3, ProviderV3 } from "@ai-sdk/provider";
|
|
2
4
|
import { FetchFunction } from "@ai-sdk/provider-utils";
|
|
3
|
-
import { LanguageModelV4, ProviderV4 } from "@ai-sdk/provider";
|
|
4
5
|
import { z } from "zod/v4";
|
|
5
6
|
|
|
6
7
|
//#region src/lib/provider.d.ts
|
|
8
|
+
|
|
7
9
|
declare const neonErrorSchema: z.ZodObject<{
|
|
8
10
|
error: z.ZodObject<{
|
|
9
11
|
message: z.ZodString;
|
|
@@ -30,13 +32,15 @@ interface NeonProviderSettings {
|
|
|
30
32
|
/** Custom fetch implementation (e.g. for testing or middleware). */
|
|
31
33
|
fetch?: FetchFunction;
|
|
32
34
|
}
|
|
33
|
-
interface NeonProvider extends
|
|
35
|
+
interface NeonProvider extends ProviderV3 {
|
|
34
36
|
/** Creates a Neon AI Gateway model for text generation. */
|
|
35
|
-
(modelId: NeonChatModelId):
|
|
37
|
+
(modelId: NeonChatModelId): LanguageModelV3;
|
|
36
38
|
/** Creates a Neon AI Gateway model for text generation. */
|
|
37
|
-
languageModel(modelId: NeonChatModelId):
|
|
39
|
+
languageModel(modelId: NeonChatModelId): LanguageModelV3;
|
|
38
40
|
/** Creates a Neon AI Gateway chat model for text generation. */
|
|
39
|
-
chat(modelId: NeonChatModelId):
|
|
41
|
+
chat(modelId: NeonChatModelId): LanguageModelV3;
|
|
42
|
+
/** OpenAI Responses tools (e.g. `imageGeneration`) for OpenAI-routed models. */
|
|
43
|
+
tools: typeof openai.tools;
|
|
40
44
|
/** @deprecated Use `embeddingModel` instead. */
|
|
41
45
|
textEmbeddingModel(modelId: string): never;
|
|
42
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","names":[],"sources":["../../src/lib/provider.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"provider.d.ts","names":[],"sources":["../../src/lib/provider.ts"],"mappings":";;;;;;;;cAmCM,iBAAe,CAAA,CAAA;;;;;IAAA,IAAA,eAAA,cAAA,aAAA,CAAA,CAAA;EAAA,CAAA,eAAA,CAAA;AASrB,CAAA,eAAY,CAAA;AAAa,KAAb,aAAA,GAAgB,CAAA,CAAE,KAAL,CAAA,OAAkB,eAAlB,CAAA;AAAkB,UA4C1B,oBAAA,CA5C0B;;AAAR;AA4CnC;;;SAkBS,CAAA,EAAA,MAAA;EAAa;AAGtB;;;QAE6B,CAAA,EAAA,MAAA;;SAGa,CAAA,EAX/B,MAW+B,CAAA,MAAA,EAAA,MAAA,CAAA;;OAGT,CAAA,EAXxB,aAWwB;;AARK,UAArB,YAAA,SAAqB,UAAA,CAAA;EAAU;EAiBhC,CAAA,OAAA,EAfL,eAee,CAAA,EAfG,eAeH;EAAA;eAAU,CAAA,OAAA,EAZZ,eAYY,CAAA,EAZM,eAYN;;EAAwC,IAAA,CAAA,OAAA,EAT7D,eAS6D,CAAA,EAT3C,eAS2C;EA0F/D;gBAhGE,MAAA,CAAe;;;;iBAMd,UAAA,WAAoB,uBAA4B;;cA0FnD,MAAI"}
|
package/dist/lib/provider.js
CHANGED
|
@@ -3,10 +3,23 @@ import { getNeonModelRoute } from "./neon-model-capabilities.js";
|
|
|
3
3
|
import { NeonChatLanguageModel } from "./neon-chat-language-model.js";
|
|
4
4
|
import { NeonResponsesLanguageModel } from "./neon-responses-language-model.js";
|
|
5
5
|
import { VERSION } from "./version.js";
|
|
6
|
-
import {
|
|
6
|
+
import { openai } from "@ai-sdk/openai";
|
|
7
7
|
import { NoSuchModelError } from "@ai-sdk/provider";
|
|
8
|
+
import { generateId, loadApiKey, loadSetting, withUserAgentSuffix, withoutTrailingSlash } from "@ai-sdk/provider-utils";
|
|
8
9
|
import { z } from "zod/v4";
|
|
9
10
|
//#region src/lib/provider.ts
|
|
11
|
+
/**
|
|
12
|
+
* Community Vercel AI SDK provider for the Neon AI Gateway.
|
|
13
|
+
*
|
|
14
|
+
* `createNeon()` returns a provider that routes each model to the best gateway
|
|
15
|
+
* endpoint based on its id (Anthropic → native Messages, OpenAI → native
|
|
16
|
+
* Responses incl. Codex, everything else → unified MLflow), so a single
|
|
17
|
+
* `neon('claude-...')` call (same base URL + token) reaches the whole catalog.
|
|
18
|
+
* Ids use the canonical Neon (unprefixed) form; the legacy `databricks-` prefix
|
|
19
|
+
* is also accepted. Configure with the branch-scoped `NEON_AI_GATEWAY_BASE_URL` +
|
|
20
|
+
* `NEON_AI_GATEWAY_TOKEN` emitted by `neonctl env pull` / `neon dev`, or pass
|
|
21
|
+
* `baseURL` / `apiKey` explicitly.
|
|
22
|
+
*/
|
|
10
23
|
const neonErrorStructure = {
|
|
11
24
|
errorSchema: z.object({ error: z.object({
|
|
12
25
|
message: z.string(),
|
|
@@ -86,9 +99,10 @@ function createNeon(options = {}) {
|
|
|
86
99
|
}
|
|
87
100
|
};
|
|
88
101
|
const provider = (modelId) => createLanguageModel(modelId);
|
|
89
|
-
provider.specificationVersion = "
|
|
102
|
+
provider.specificationVersion = "v3";
|
|
90
103
|
provider.languageModel = createLanguageModel;
|
|
91
104
|
provider.chat = createLanguageModel;
|
|
105
|
+
provider.tools = openai.tools;
|
|
92
106
|
provider.embeddingModel = (modelId) => {
|
|
93
107
|
throw new NoSuchModelError({
|
|
94
108
|
modelId,
|
package/dist/lib/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","names":[],"sources":["../../src/lib/provider.ts"],"sourcesContent":["/**\n * Community Vercel AI SDK provider for the Neon AI Gateway.\n *\n * `createNeon()` returns a provider that routes each model to the best gateway\n * endpoint based on its id (Anthropic → native Messages, OpenAI → native\n * Responses incl. Codex, everything else → unified MLflow), so a single\n * `neon('
|
|
1
|
+
{"version":3,"file":"provider.js","names":["openaiProvider"],"sources":["../../src/lib/provider.ts"],"sourcesContent":["/**\n * Community Vercel AI SDK provider for the Neon AI Gateway.\n *\n * `createNeon()` returns a provider that routes each model to the best gateway\n * endpoint based on its id (Anthropic → native Messages, OpenAI → native\n * Responses incl. Codex, everything else → unified MLflow), so a single\n * `neon('claude-...')` call (same base URL + token) reaches the whole catalog.\n * Ids use the canonical Neon (unprefixed) form; the legacy `databricks-` prefix\n * is also accepted. Configure with the branch-scoped `NEON_AI_GATEWAY_BASE_URL` +\n * `NEON_AI_GATEWAY_TOKEN` emitted by `neonctl env pull` / `neon dev`, or pass\n * `baseURL` / `apiKey` explicitly.\n */\nimport { openai as openaiProvider } from \"@ai-sdk/openai\";\nimport type { ProviderErrorStructure } from \"@ai-sdk/openai-compatible\";\nimport {\n\ttype LanguageModelV3,\n\tNoSuchModelError,\n\ttype ProviderV3,\n} from \"@ai-sdk/provider\";\nimport {\n\ttype FetchFunction,\n\tgenerateId,\n\tloadApiKey,\n\tloadSetting,\n\twithoutTrailingSlash,\n\twithUserAgentSuffix,\n} from \"@ai-sdk/provider-utils\";\nimport { z } from \"zod/v4\";\nimport { NeonAnthropicLanguageModel } from \"./neon-anthropic-language-model.js\";\nimport { NeonChatLanguageModel } from \"./neon-chat-language-model.js\";\nimport type { NeonChatModelId } from \"./neon-chat-options.js\";\nimport { getNeonModelRoute } from \"./neon-model-capabilities.js\";\nimport { NeonResponsesLanguageModel } from \"./neon-responses-language-model.js\";\nimport { VERSION } from \"./version.js\";\n\nconst neonErrorSchema = z.object({\n\terror: z.object({\n\t\tmessage: z.string(),\n\t\ttype: z.string().nullish(),\n\t\tparam: z.unknown().nullish(),\n\t\tcode: z.unknown().nullish(),\n\t}),\n});\n\nexport type NeonErrorData = z.infer<typeof neonErrorSchema>;\n\nconst neonErrorStructure: ProviderErrorStructure<NeonErrorData> = {\n\terrorSchema: neonErrorSchema,\n\terrorToMessage: (data) => data.error.message,\n};\n\n/**\n * Recursively remove the JSON Schema `$schema` marker, which some gateway\n * backends (notably Gemini) reject in tool/structured-output schemas. Other\n * backends ignore its absence, so stripping it everywhere is safe.\n */\nfunction stripJsonSchemaMarker(value: unknown): unknown {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(stripJsonSchemaMarker);\n\t}\n\tif (value !== null && typeof value === \"object\") {\n\t\tconst result: Record<string, unknown> = {};\n\t\tfor (const [key, entry] of Object.entries(value)) {\n\t\t\tif (key === \"$schema\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult[key] = stripJsonSchemaMarker(entry);\n\t\t}\n\t\treturn result;\n\t}\n\treturn value;\n}\n\nfunction transformNeonRequestBody(\n\targs: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst transformed = { ...args };\n\tif (transformed.tools != null) {\n\t\ttransformed.tools = stripJsonSchemaMarker(transformed.tools);\n\t}\n\tif (transformed.response_format != null) {\n\t\ttransformed.response_format = stripJsonSchemaMarker(\n\t\t\ttransformed.response_format,\n\t\t);\n\t}\n\treturn transformed;\n}\n\nexport interface NeonProviderSettings {\n\t/**\n\t * Neon AI Gateway base URL — the branch-scoped host root, e.g.\n\t * `https://<branch-id>-api.ai.<region>.aws.neon.tech`. The gateway paths are\n\t * appended internally. Falls back to the `NEON_AI_GATEWAY_BASE_URL` env var.\n\t */\n\tbaseURL?: string;\n\n\t/**\n\t * Neon AI Gateway platform token (the `nt_live_...` value). Falls back to the\n\t * `NEON_AI_GATEWAY_TOKEN` env var.\n\t */\n\tapiKey?: string;\n\n\t/** Custom headers to include in the requests. */\n\theaders?: Record<string, string>;\n\n\t/** Custom fetch implementation (e.g. for testing or middleware). */\n\tfetch?: FetchFunction;\n}\n\nexport interface NeonProvider extends ProviderV3 {\n\t/** Creates a Neon AI Gateway model for text generation. */\n\t(modelId: NeonChatModelId): LanguageModelV3;\n\n\t/** Creates a Neon AI Gateway model for text generation. */\n\tlanguageModel(modelId: NeonChatModelId): LanguageModelV3;\n\n\t/** Creates a Neon AI Gateway chat model for text generation. */\n\tchat(modelId: NeonChatModelId): LanguageModelV3;\n\n\t/** OpenAI Responses tools (e.g. `imageGeneration`) for OpenAI-routed models. */\n\ttools: typeof openaiProvider.tools;\n\n\t/** @deprecated Use `embeddingModel` instead. */\n\ttextEmbeddingModel(modelId: string): never;\n}\n\nexport function createNeon(options: NeonProviderSettings = {}): NeonProvider {\n\t// Resolved lazily so that `createNeon()` and the default `neon` instance do\n\t// not throw at import time when configuration comes from the environment.\n\tconst getHost = () =>\n\t\twithoutTrailingSlash(\n\t\t\tloadSetting({\n\t\t\t\tsettingValue: options.baseURL,\n\t\t\t\tenvironmentVariableName: \"NEON_AI_GATEWAY_BASE_URL\",\n\t\t\t\tsettingName: \"baseURL\",\n\t\t\t\tdescription: \"Neon AI Gateway base URL\",\n\t\t\t}),\n\t\t);\n\n\tconst getHeaders = (extra?: Record<string, string>) =>\n\t\twithUserAgentSuffix(\n\t\t\t{\n\t\t\t\tAuthorization: `Bearer ${loadApiKey({\n\t\t\t\t\tapiKey: options.apiKey,\n\t\t\t\t\tenvironmentVariableName: \"NEON_AI_GATEWAY_TOKEN\",\n\t\t\t\t\tdescription: \"Neon AI Gateway token\",\n\t\t\t\t})}`,\n\t\t\t\t...extra,\n\t\t\t\t...options.headers,\n\t\t\t},\n\t\t\t`neondatabase/ai-sdk-provider/${VERSION}`,\n\t\t);\n\n\t// Anthropic models -> native Messages API.\n\tconst createAnthropicModel = (modelId: NeonChatModelId) =>\n\t\tnew NeonAnthropicLanguageModel(modelId, {\n\t\t\tprovider: \"neon.anthropic\",\n\t\t\tbaseURL: `${getHost()}/ai-gateway/anthropic/v1`,\n\t\t\theaders: () => getHeaders({ \"anthropic-version\": \"2023-06-01\" }),\n\t\t\tfetch: options.fetch,\n\t\t\tgenerateId,\n\t\t});\n\n\t// OpenAI models (incl. Codex, only served natively) -> Responses API.\n\tconst createOpenAIModel = (modelId: NeonChatModelId) =>\n\t\tnew NeonResponsesLanguageModel(modelId, {\n\t\t\tprovider: \"neon.openai.responses\",\n\t\t\turl: ({ path }) => `${getHost()}/ai-gateway/openai/v1${path}`,\n\t\t\theaders: getHeaders,\n\t\t\tfetch: options.fetch,\n\t\t\tfileIdPrefixes: [\"file-\"],\n\t\t});\n\n\t// Everything else (Gemini, Llama, Qwen, gpt-oss, ...) -> unified MLflow\n\t// endpoint. Gemini is here because its native endpoint can't stream.\n\tconst createChatModel = (modelId: NeonChatModelId) =>\n\t\tnew NeonChatLanguageModel(modelId, {\n\t\t\tprovider: \"neon.chat\",\n\t\t\turl: ({ path }) => `${getHost()}/ai-gateway/mlflow/v1${path}`,\n\t\t\theaders: getHeaders,\n\t\t\tfetch: options.fetch,\n\t\t\terrorStructure: neonErrorStructure,\n\t\t\ttransformRequestBody: transformNeonRequestBody,\n\t\t\tsupportsStructuredOutputs: true,\n\t\t});\n\n\tconst createLanguageModel = (modelId: NeonChatModelId): LanguageModelV3 => {\n\t\tswitch (getNeonModelRoute(modelId)) {\n\t\t\tcase \"anthropic\":\n\t\t\t\treturn createAnthropicModel(modelId);\n\t\t\tcase \"openai\":\n\t\t\t\treturn createOpenAIModel(modelId);\n\t\t\tdefault:\n\t\t\t\treturn createChatModel(modelId);\n\t\t}\n\t};\n\n\tconst provider = (modelId: NeonChatModelId) => createLanguageModel(modelId);\n\n\tprovider.specificationVersion = \"v3\" as const;\n\tprovider.languageModel = createLanguageModel;\n\tprovider.chat = createLanguageModel;\n\tprovider.tools = openaiProvider.tools;\n\n\tprovider.embeddingModel = (modelId: string) => {\n\t\tthrow new NoSuchModelError({ modelId, modelType: \"embeddingModel\" });\n\t};\n\tprovider.textEmbeddingModel = provider.embeddingModel;\n\tprovider.imageModel = (modelId: string) => {\n\t\tthrow new NoSuchModelError({ modelId, modelType: \"imageModel\" });\n\t};\n\n\treturn provider;\n}\n\n/** Default Neon provider instance (reads `NEON_AI_GATEWAY_*` env vars). */\nexport const neon = createNeon();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAM,qBAA4D;CACjE,aAZuB,EAAE,OAAO,EAChC,OAAO,EAAE,OAAO;EACf,SAAS,EAAE,OAAO;EAClB,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ;EACzB,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ;EAC3B,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ;CAC3B,CAAC,EACF,CAK4B;CAC3B,iBAAiB,SAAS,KAAK,MAAM;AACtC;;;;;;AAOA,SAAS,sBAAsB,OAAyB;CACvD,IAAI,MAAM,QAAQ,KAAK,GACtB,OAAO,MAAM,IAAI,qBAAqB;CAEvC,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;EAChD,MAAM,SAAkC,CAAC;EACzC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;GACjD,IAAI,QAAQ,WACX;GAED,OAAO,OAAO,sBAAsB,KAAK;EAC1C;EACA,OAAO;CACR;CACA,OAAO;AACR;AAEA,SAAS,yBACR,MAC0B;CAC1B,MAAM,cAAc,EAAE,GAAG,KAAK;CAC9B,IAAI,YAAY,SAAS,MACxB,YAAY,QAAQ,sBAAsB,YAAY,KAAK;CAE5D,IAAI,YAAY,mBAAmB,MAClC,YAAY,kBAAkB,sBAC7B,YAAY,eACb;CAED,OAAO;AACR;AAwCA,SAAgB,WAAW,UAAgC,CAAC,GAAiB;CAG5E,MAAM,gBACL,qBACC,YAAY;EACX,cAAc,QAAQ;EACtB,yBAAyB;EACzB,aAAa;EACb,aAAa;CACd,CAAC,CACF;CAED,MAAM,cAAc,UACnB,oBACC;EACC,eAAe,UAAU,WAAW;GACnC,QAAQ,QAAQ;GAChB,yBAAyB;GACzB,aAAa;EACd,CAAC;EACD,GAAG;EACH,GAAG,QAAQ;CACZ,GACA,gCAAgC,SACjC;CAGD,MAAM,wBAAwB,YAC7B,IAAI,2BAA2B,SAAS;EACvC,UAAU;EACV,SAAS,GAAG,QAAQ,EAAE;EACtB,eAAe,WAAW,EAAE,qBAAqB,aAAa,CAAC;EAC/D,OAAO,QAAQ;EACf;CACD,CAAC;CAGF,MAAM,qBAAqB,YAC1B,IAAI,2BAA2B,SAAS;EACvC,UAAU;EACV,MAAM,EAAE,WAAW,GAAG,QAAQ,EAAE,uBAAuB;EACvD,SAAS;EACT,OAAO,QAAQ;EACf,gBAAgB,CAAC,OAAO;CACzB,CAAC;CAIF,MAAM,mBAAmB,YACxB,IAAI,sBAAsB,SAAS;EAClC,UAAU;EACV,MAAM,EAAE,WAAW,GAAG,QAAQ,EAAE,uBAAuB;EACvD,SAAS;EACT,OAAO,QAAQ;EACf,gBAAgB;EAChB,sBAAsB;EACtB,2BAA2B;CAC5B,CAAC;CAEF,MAAM,uBAAuB,YAA8C;EAC1E,QAAQ,kBAAkB,OAAO,GAAjC;GACC,KAAK,aACJ,OAAO,qBAAqB,OAAO;GACpC,KAAK,UACJ,OAAO,kBAAkB,OAAO;GACjC,SACC,OAAO,gBAAgB,OAAO;EAChC;CACD;CAEA,MAAM,YAAY,YAA6B,oBAAoB,OAAO;CAE1E,SAAS,uBAAuB;CAChC,SAAS,gBAAgB;CACzB,SAAS,OAAO;CAChB,SAAS,QAAQA,OAAe;CAEhC,SAAS,kBAAkB,YAAoB;EAC9C,MAAM,IAAI,iBAAiB;GAAE;GAAS,WAAW;EAAiB,CAAC;CACpE;CACA,SAAS,qBAAqB,SAAS;CACvC,SAAS,cAAc,YAAoB;EAC1C,MAAM,IAAI,iBAAiB;GAAE;GAAS,WAAW;EAAa,CAAC;CAChE;CAEA,OAAO;AACR;;AAGA,MAAa,OAAO,WAAW"}
|
package/dist/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neondatabase/ai-sdk-provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Community Vercel AI SDK provider for the Neon AI Gateway.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -29,11 +29,6 @@
|
|
|
29
29
|
"types": "./dist/index.d.ts",
|
|
30
30
|
"import": "./dist/index.js",
|
|
31
31
|
"default": "./dist/index.js"
|
|
32
|
-
},
|
|
33
|
-
"./v1": {
|
|
34
|
-
"types": "./dist/v1.d.ts",
|
|
35
|
-
"import": "./dist/v1.js",
|
|
36
|
-
"default": "./dist/v1.js"
|
|
37
32
|
}
|
|
38
33
|
},
|
|
39
34
|
"files": [
|
|
@@ -44,6 +39,7 @@
|
|
|
44
39
|
"devDependencies": {
|
|
45
40
|
"@types/node": "^20.19.0",
|
|
46
41
|
"@vitest/coverage-v8": "3.0.9",
|
|
42
|
+
"ai": "6.0.132",
|
|
47
43
|
"console-fail-test": "0.5.0",
|
|
48
44
|
"tsdown": "^0.14.1",
|
|
49
45
|
"typescript": "^5.8.2",
|
|
@@ -57,19 +53,22 @@
|
|
|
57
53
|
"provenance": false
|
|
58
54
|
},
|
|
59
55
|
"dependencies": {
|
|
60
|
-
"@ai-sdk/anthropic": "
|
|
61
|
-
"@ai-sdk/openai": "
|
|
62
|
-
"@ai-sdk/openai-compatible": "
|
|
63
|
-
"@ai-sdk/provider": "
|
|
64
|
-
"@ai-sdk/provider-utils": "
|
|
56
|
+
"@ai-sdk/anthropic": "^3.0.82",
|
|
57
|
+
"@ai-sdk/openai": "^3.0.69",
|
|
58
|
+
"@ai-sdk/openai-compatible": "^2.0.48",
|
|
59
|
+
"@ai-sdk/provider": "^3.0.10",
|
|
60
|
+
"@ai-sdk/provider-utils": "^4.0.27"
|
|
65
61
|
},
|
|
66
62
|
"peerDependencies": {
|
|
63
|
+
"ai": "^6.0.0",
|
|
67
64
|
"zod": "^3.25.76 || ^4.1.8"
|
|
68
65
|
},
|
|
69
66
|
"scripts": {
|
|
70
67
|
"build": "tsc --noEmit && tsdown",
|
|
71
68
|
"test": "vitest --passWithNoTests",
|
|
72
69
|
"test:ci": "vitest run --passWithNoTests",
|
|
70
|
+
"test:drift": "NEON_DRIFT_CHECK=1 vitest run neon-catalog-drift",
|
|
71
|
+
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
73
72
|
"tsc": "tsc"
|
|
74
73
|
}
|
|
75
74
|
}
|
package/dist/v1.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { NeonAnthropicLanguageModel } from "./lib/neon-anthropic-language-model.js";
|
|
2
|
-
import { NeonChatLanguageModel } from "./lib/neon-chat-language-model.js";
|
|
3
|
-
import { NeonChatModelId } from "./lib/neon-chat-options.js";
|
|
4
|
-
import { NeonModelCapabilities, NeonModelFamily, NeonModelRoute, getNeonModelCapabilities, getNeonModelRoute } from "./lib/neon-model-capabilities.js";
|
|
5
|
-
import { NeonResponsesLanguageModel } from "./lib/neon-responses-language-model.js";
|
|
6
|
-
import { NeonErrorData, NeonProvider, NeonProviderSettings, createNeon, neon } from "./lib/provider.js";
|
|
7
|
-
export { NeonAnthropicLanguageModel, NeonChatLanguageModel, type NeonChatModelId, type NeonErrorData, type NeonModelCapabilities, type NeonModelFamily, type NeonModelRoute, type NeonProvider, type NeonProviderSettings, NeonResponsesLanguageModel, createNeon, getNeonModelCapabilities, getNeonModelRoute, neon };
|
package/dist/v1.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { NeonAnthropicLanguageModel } from "./lib/neon-anthropic-language-model.js";
|
|
2
|
-
import { getNeonModelCapabilities, getNeonModelRoute } from "./lib/neon-model-capabilities.js";
|
|
3
|
-
import { NeonChatLanguageModel } from "./lib/neon-chat-language-model.js";
|
|
4
|
-
import { NeonResponsesLanguageModel } from "./lib/neon-responses-language-model.js";
|
|
5
|
-
import { createNeon, neon } from "./lib/provider.js";
|
|
6
|
-
export { NeonAnthropicLanguageModel, NeonChatLanguageModel, NeonResponsesLanguageModel, createNeon, getNeonModelCapabilities, getNeonModelRoute, neon };
|