@neondatabase/ai-sdk-provider 0.7.2 → 0.8.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.
Files changed (36) hide show
  1. package/{LICENSE.md → LICENSE} +27 -3
  2. package/README.md +131 -13
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +3 -3
  5. package/dist/lib/neon-anthropic-language-model.d.ts +8 -0
  6. package/dist/lib/neon-anthropic-language-model.d.ts.map +1 -1
  7. package/dist/lib/neon-anthropic-language-model.js +39 -13
  8. package/dist/lib/neon-anthropic-language-model.js.map +1 -1
  9. package/dist/lib/neon-capabilities.d.ts.map +1 -1
  10. package/dist/lib/neon-capabilities.js +17 -11
  11. package/dist/lib/neon-capabilities.js.map +1 -1
  12. package/dist/lib/neon-chat-options.d.ts +4 -11
  13. package/dist/lib/neon-chat-options.d.ts.map +1 -1
  14. package/dist/lib/neon-chat-options.js +23 -28
  15. package/dist/lib/neon-chat-options.js.map +1 -1
  16. package/dist/lib/neon-gateway-error.d.ts +56 -0
  17. package/dist/lib/neon-gateway-error.d.ts.map +1 -0
  18. package/dist/lib/neon-gateway-error.js +102 -0
  19. package/dist/lib/neon-gateway-error.js.map +1 -0
  20. package/dist/lib/neon-model-capabilities.d.ts +7 -0
  21. package/dist/lib/neon-model-capabilities.d.ts.map +1 -1
  22. package/dist/lib/neon-model-capabilities.js +47 -10
  23. package/dist/lib/neon-model-capabilities.js.map +1 -1
  24. package/dist/lib/neon-responses-language-model.d.ts +5 -11
  25. package/dist/lib/neon-responses-language-model.d.ts.map +1 -1
  26. package/dist/lib/neon-responses-language-model.js +8 -29
  27. package/dist/lib/neon-responses-language-model.js.map +1 -1
  28. package/dist/lib/neon-responses-options.d.ts +14 -0
  29. package/dist/lib/neon-responses-options.d.ts.map +1 -0
  30. package/dist/lib/neon-responses-options.js +66 -0
  31. package/dist/lib/neon-responses-options.js.map +1 -0
  32. package/dist/lib/provider.d.ts.map +1 -1
  33. package/dist/lib/provider.js +5 -4
  34. package/dist/lib/provider.js.map +1 -1
  35. package/dist/package.js +1 -1
  36. package/package.json +1 -1
@@ -1,6 +1,5 @@
1
- # Apache License 2.0
2
1
 
3
- Apache License
2
+ Apache License
4
3
  Version 2.0, January 2004
5
4
  http://www.apache.org/licenses/
6
5
 
@@ -175,4 +174,29 @@
175
174
  incurred by, or claims asserted against, such Contributor by reason
176
175
  of your accepting any such warranty or additional liability.
177
176
 
178
- END OF TERMS AND CONDITIONS
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  Community [Vercel AI SDK](https://ai-sdk.dev) provider for the [Neon](https://neon.com) AI Gateway. Supports **AI SDK v6 and v7** (`ai@^6` or `ai@^7`).
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('claude-...')` call reaches the whole catalog.
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. Use the same `neon(modelId)` API across the branch's model catalog; the provider selects Anthropic Messages, OpenAI Responses, or Chat Completions for each model.
6
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.
7
+ Use canonical model ids such as `gpt-5-mini`, `llama-4-maverick`, and `gemini-3-flash`, matching the [`neon` provider on models.dev](https://models.dev). The typed catalog includes the known model ids, and arbitrary strings are accepted so newly available models work before the types update.
8
8
 
9
9
  ## Install
10
10
 
@@ -31,7 +31,7 @@ import { generateText } from "ai";
31
31
 
32
32
  // Reads NEON_AI_GATEWAY_BASE_URL + NEON_AI_GATEWAY_TOKEN from the environment.
33
33
  const { text } = await generateText({
34
- model: neon("claude-haiku-4-5"), // or 'gpt-5-3-codex', etc.
34
+ model: neon("gpt-5-mini"), // or "llama-4-maverick", "gemini-3-flash", …
35
35
  prompt: "Summarize Postgres for me.",
36
36
  });
37
37
  ```
@@ -51,17 +51,56 @@ const neon = createNeon({
51
51
 
52
52
  | Model family | Endpoint | Why |
53
53
  | --- | --- | --- |
54
- | Anthropic (`claude-*`) | native Messages API | streaming structured output + native reasoning |
55
- | OpenAI (`gpt-*`, `*-codex`) | native Responses API | Codex (native-only), native reasoning, image-gen tool |
56
- | Everything else (Gemini, Llama, Qwen, gpt-oss, ...) | unified MLflow endpoint | broad coverage; Gemini is here because its native endpoint does not support streaming |
54
+ | Anthropic (`claude-*`) | Messages API | Anthropic tools, structured output, and reasoning |
55
+ | OpenAI (`gpt-*`, `*-codex`) | Responses API | Codex, reasoning, and built-in tools such as image generation |
56
+ | Everything else (Gemini, Llama, Qwen, gpt-oss, ...) | Chat Completions API | one streaming interface across the remaining model families |
57
57
 
58
- Routing matches on the model id, so both the canonical (`gpt-5`) and the legacy `databricks-`-prefixed (`databricks-gpt-5`) forms route identically.
58
+ Routing matches on the model id.
59
59
 
60
60
  ## Capabilities
61
61
 
62
- 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.
62
+ `generateText` and `streamText` work with any model available to your branch. `generateObject`, `streamObject`, and single- or multi-step tool calls work with OpenAI (including Codex), Meta, Alibaba, Zhipu AI, and Thinking Machines models. Gemini currently supports `generateText` and `streamText`; structured output and multi-step tools are not supported. Vision input works on models that accept images.
63
63
 
64
- For MLflow-routed models, the provider detects the model family and drops parameters a backend rejects (e.g. penalties/`seed` for Llama, `reasoningEffort` for Gemini) with an AI SDK warning (`result.warnings`) instead of failing the request.
64
+ Claude models use the Messages API. On both that route and Chat Completions the provider removes call options the gateway rejects and reports each one in `result.warnings` instead of failing the request — see [Dropped call options](#dropped-call-options). Unsupported Responses API storage options throw before a request is sent — see [Errors](#errors).
65
+
66
+ Which ids your branch serves is account-specific during the beta; `GET $NEON_AI_GATEWAY_BASE_URL/v1/models` is the authoritative list. `NeonChatModelId` accepts any string, so an id this package has not caught up with still works — and, equally, an id the gateway has retired still type-checks and fails at the gateway instead.
67
+
68
+ ### Dropped call options
69
+
70
+ Upstream backends behind the gateway accept different subsets of the OpenAI-style parameters the AI SDK emits, and sending one an upstream rejects is a hard `400`. The provider drops those before the request and records a warning in `result.warnings`, so a call succeeds instead of failing on a parameter you passed in good faith.
71
+
72
+ These rules apply on the Anthropic Messages and Chat Completions routes. The Responses route (every `gpt-*` id) relies on the upstream OpenAI model's own stripping instead, so its behaviour is the AI SDK's rather than described here — but `getNeonModelCapabilities` still answers for those ids.
73
+
74
+ | Models | Dropped |
75
+ | --- | --- |
76
+ | Claude 4.7 and newer (`claude-opus-4-7`, `claude-opus-4-8`, `claude-opus-5`, `claude-sonnet-5`, `claude-fable-5`) | `temperature`, `topP` |
77
+ | All Claude | `frequencyPenalty`, `presencePenalty`, `seed`, `reasoningEffort`, and `topP` when you set both `temperature` and `topP` (Anthropic accepts only one) |
78
+ | `gpt-oss` | `frequencyPenalty`, `presencePenalty`, `seed`, `stopSequences` |
79
+ | Qwen, Gemma | `frequencyPenalty`, `presencePenalty`, `seed` |
80
+ | `glm-5-2`, `inkling` | `frequencyPenalty`, `presencePenalty` |
81
+ | Meta Llama | `frequencyPenalty`, `presencePenalty`, `seed` |
82
+ | Gemini | `reasoningEffort` |
83
+
84
+ **`temperature` on a Claude 5 model therefore has no effect.** That is the gateway's behaviour, not a provider choice; sending it returns `does not support the temperature parameter`. Steer those models with Anthropic's own effort control instead — note that this is `effort`, not the OpenAI-style `reasoningEffort`, which every Claude id drops:
85
+
86
+ ```typescript
87
+ await generateText({
88
+ model: neon('claude-opus-5'),
89
+ prompt: 'Plan a schema migration.',
90
+ providerOptions: { anthropic: { effort: 'high' } }, // low | medium | high | xhigh | max
91
+ });
92
+ ```
93
+
94
+ Query the rules directly rather than hardcoding them:
95
+
96
+ ```typescript
97
+ import { getNeonModelCapabilities } from '@neon/ai-sdk-provider';
98
+
99
+ getNeonModelCapabilities('claude-opus-5').supportsTemperature; // false
100
+ getNeonModelCapabilities('glm-5-2').supportsPenalties; // false
101
+ ```
102
+
103
+ Gemini is the only family on the unified endpoint that accepts penalties. A model none of these rules match is left untouched, so a brand-new id gets the gateway's own error rather than a guess.
65
104
 
66
105
  ## Image generation
67
106
 
@@ -85,11 +124,90 @@ for await (const part of result.fullStream) {
85
124
  }
86
125
  ```
87
126
 
127
+ ### Edit a generated image
128
+
129
+ The gateway does not support stored Responses API items (`store: true`, `previousResponseId`, or `conversation`), which the Responses API uses to reuse tool results across turns. For image edits, pass the returned bytes back as image input; otherwise the model does not receive the original image and generates a new one.
130
+
131
+ ```ts
132
+ const first = await generateText({
133
+ model: neon("gpt-5-mini"),
134
+ prompt: "Generate an image of a plain red square.",
135
+ tools: { image_generation: neon.tools.imageGeneration({ outputFormat: "jpeg" }) },
136
+ });
137
+
138
+ const generated = first.steps
139
+ .flatMap((step) => step.toolResults)
140
+ .find((result) => result.toolName === "image_generation");
141
+ const output = generated?.output;
142
+ if (
143
+ !output ||
144
+ typeof output !== "object" ||
145
+ !("result" in output) ||
146
+ typeof output.result !== "string"
147
+ ) {
148
+ throw new Error("Image generation did not return image bytes.");
149
+ }
150
+
151
+ // Pass it back as image content, not as conversation history.
152
+ await generateText({
153
+ model: neon("gpt-5-mini"),
154
+ tools: { image_generation: neon.tools.imageGeneration({ outputFormat: "jpeg" }) },
155
+ messages: [
156
+ {
157
+ role: "user",
158
+ content: [
159
+ { type: "image", image: output.result, mediaType: "image/jpeg" },
160
+ { type: "text", text: "Make that same square blue instead." },
161
+ ],
162
+ },
163
+ ],
164
+ });
165
+ ```
166
+
167
+ The same stateless limitation applies to other built-in Responses tools such as web search and code interpreter.
168
+
169
+ ## Errors
170
+
171
+ A failed call rejects with the AI SDK's `APICallError`, and `error.message` carries the gateway's own reason rather than the bare HTTP status line:
172
+
173
+ ```ts
174
+ import { APICallError, generateText } from "ai";
175
+
176
+ try {
177
+ await generateText({ model: neon("gpt-5-mini"), maxOutputTokens: 1, prompt });
178
+ } catch (error) {
179
+ if (APICallError.isInstance(error)) {
180
+ error.message; // "Invalid 'max_output_tokens': integer below minimum
181
+ // value. Expected a value >= 16, but got 1 instead."
182
+ error.responseBody; // the gateway's original body, including its error_code
183
+ }
184
+ }
185
+ ```
186
+
187
+ The provider normalizes JSON error responses so the gateway's reason lands on `error.message`. Errors delivered inside an open stream and non-JSON responses keep the HTTP status line; inspect `error.responseBody` for their payload.
188
+
189
+ Requests that cannot work are refused before they leave, with `UnsupportedFunctionalityError`:
190
+
191
+ | `providerOptions.openai` | Why |
192
+ | --- | --- |
193
+ | `store: true` or `store: null` | The Responses route is stateless and never persists items. `null` is not "omitted" — the AI SDK reads it as `true`. |
194
+ | `previousResponseId`, `conversation` | Nothing is stored for them to refer to. Send the full message history instead. |
195
+
196
+ Provider options are namespaced per route, which decides where the SDK reads them from:
197
+
198
+ | Route | Models | Namespace |
199
+ | --- | --- | --- |
200
+ | Responses | `gpt-*` (incl. Codex) | `openai` |
201
+ | Chat Completions | Gemini, Llama, Qwen, gpt-oss, … | `neon` |
202
+ | Anthropic Messages | `claude-*` | `anthropic` |
203
+
204
+ So `store` is only refused on the Responses route; the same option is ignored elsewhere.
205
+
88
206
  ## Limitations
89
207
 
90
- - `generateImage()` and embeddings (`embed` / `embedMany`) are not offered by the gateway and throw `NoSuchModelError`.
91
- - `gpt-oss-*` models return a non-standard ("harmony") response shape on the unified endpoint (`message.content` as an array of reasoning/text parts instead of a string). The provider normalizes this to the OpenAI Chat Completions contract (string `content` + `reasoning_content`) so `generateText`/`streamText` work and reasoning is surfaced. See neondatabase/neon-pkgs#308.
92
- - OpenAI Responses multi-turn tool flows (`generateText` + `stepCountIs`) can return 502 from the gateway; tool calling is covered on Anthropic/Google/Meta in e2e.
208
+ - The gateway does not offer image or embedding model endpoints, so `generateImage()`, `embed()`, and `embedMany()` throw `NoSuchModelError`. Image generation is available through the Responses API's built-in `image_generation` tool with `neon.tools.imageGeneration()`.
209
+ - Results from provider-executed tools (`neon.tools.imageGeneration`, and the other Responses built-ins) are not replayed to the gateway on a later step — see [Edit a generated image](#edit-a-generated-image).
210
+ - The Responses route is stateless, so the provider sends `store: false` and refuses `store: true`, `store: null`, `previousResponseId`, or `conversation` — see [Errors](#errors).
93
211
 
94
212
  ## End-to-end tests
95
213
 
@@ -100,4 +218,4 @@ cp .env.example .env # fill NEON_AI_GATEWAY_BASE_URL + NEON_AI_GATEWAY_TOKEN f
100
218
  pnpm test:e2e
101
219
  ```
102
220
 
103
- 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`. It also fetches the live `/v1/models` catalog and calls every currently enabled model with both AI SDK 6 and AI SDK 7. Tests are skipped when gateway env vars are absent.
221
+ The matrix covers one models.dev `neon` model per family (Anthropic, OpenAI, Codex, Gemini, Meta, Alibaba, Zhipu, Thinking Machines) across `generateText`, `streamText`, `generateObject`, tool calling, and `neon.tools.imageGeneration`. `generateObject` and tool calling run on the subset of families where they are verified (see [Capabilities](#capabilities)); a family whose representative id the branch does not serve is skipped rather than failed. It also fetches the live `/v1/models` catalog and calls every currently enabled model with both AI SDK 6 and AI SDK 7. Tests are 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 { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS, NeonChatModelId, NeonKnownModelId } from "./lib/neon-chat-options.js";
3
+ import { 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 { 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 };
7
+ export { 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
- import { NeonAnthropicLanguageModel } from "./lib/neon-anthropic-language-model.js";
2
1
  import { getNeonModelCapabilities, getNeonModelRoute } from "./lib/neon-model-capabilities.js";
2
+ import { NeonAnthropicLanguageModel } from "./lib/neon-anthropic-language-model.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
+ import { NEON_MODELS_DEV_IDS } from "./lib/neon-chat-options.js";
5
5
  import { NeonResponsesLanguageModel } from "./lib/neon-responses-language-model.js";
6
6
  import { createNeon, neon } from "./lib/provider.js";
7
- export { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS, NeonAnthropicLanguageModel, NeonChatLanguageModel, NeonResponsesLanguageModel, createNeon, getNeonModelCapabilities, getNeonModelRoute, neon };
7
+ export { NEON_MODELS_DEV_IDS, NeonAnthropicLanguageModel, NeonChatLanguageModel, NeonResponsesLanguageModel, createNeon, getNeonModelCapabilities, getNeonModelRoute, neon };
@@ -12,6 +12,14 @@ import { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3GenerateRes
12
12
  * (`eager_input_streaming: true`) on streaming tool calls, which the gateway
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
+ *
16
+ * Capability filtering runs here as well as on the unified endpoint. The
17
+ * upstream Anthropic model drops sampling parameters for the Claude versions it
18
+ * knows about, but not for ones released after it, so `claude-opus-5` and
19
+ * `claude-sonnet-5` reached the API and came back
20
+ * `` `temperature` is deprecated for this model ``. Applying our own rules keeps
21
+ * the behaviour tied to what the gateway was measured to accept rather than to
22
+ * the SDK's release date.
15
23
  */
16
24
  declare class NeonAnthropicLanguageModel extends AnthropicMessagesLanguageModel implements LanguageModelV3 {
17
25
  private withGatewayCompat;
@@ -1 +1 @@
1
- {"version":3,"file":"neon-anthropic-language-model.d.ts","names":[],"sources":["../../src/lib/neon-anthropic-language-model.ts"],"mappings":";;;;;;;AAkBA;AACC;AAqBU;AACC;AAAR;AAKO;AACC;AAAR;AA5BK,cADI,0BAAA,SACJ,8BAAA,YACG,eADH,CAAA;EACG,QAAA,iBAAA;EAAe,UAAA,CAAA,OAAA,EAoBhB,0BApBgB,CAAA,EAqBvB,OArBuB,CAqBf,6BArBe,CAAA;oBA0BhB,6BACP,QAAQ"}
1
+ {"version":3,"file":"neon-anthropic-language-model.d.ts","names":[],"sources":["../../src/lib/neon-anthropic-language-model.ts"],"mappings":";;;;;;;AA+BA;AACC;AA6BU;AACC;AAAR;AASO;AACC;AAAR;AAxCK;AACG;AAAe;;;;;;cAFd,0BAAA,SACJ,8BAAA,YACG;;sBA4BD,6BACP,QAAQ;oBASD,6BACP,QAAQ"}
@@ -1,3 +1,4 @@
1
+ import { applyNeonCapabilities, mergeStreamStartWarnings } from "./neon-capabilities.js";
1
2
  import { AnthropicMessagesLanguageModel } from "@ai-sdk/anthropic/internal";
2
3
  //#region src/lib/neon-anthropic-language-model.ts
3
4
  /**
@@ -9,27 +10,52 @@ import { AnthropicMessagesLanguageModel } from "@ai-sdk/anthropic/internal";
9
10
  * (`eager_input_streaming: true`) on streaming tool calls, which the gateway
10
11
  * rejects (`Extra inputs are not permitted`). We disable it via the model's own
11
12
  * `toolStreaming` option so streaming tool calls work. Users can still override.
13
+ *
14
+ * Capability filtering runs here as well as on the unified endpoint. The
15
+ * upstream Anthropic model drops sampling parameters for the Claude versions it
16
+ * knows about, but not for ones released after it, so `claude-opus-5` and
17
+ * `claude-sonnet-5` reached the API and came back
18
+ * `` `temperature` is deprecated for this model ``. Applying our own rules keeps
19
+ * the behaviour tied to what the gateway was measured to accept rather than to
20
+ * the SDK's release date.
12
21
  */
13
22
  var NeonAnthropicLanguageModel = class extends AnthropicMessagesLanguageModel {
14
23
  withGatewayCompat(options) {
15
- const anthropic = options.providerOptions?.anthropic;
16
- if (anthropic != null && "toolStreaming" in anthropic) return options;
24
+ const { options: adjusted, warnings } = applyNeonCapabilities(this.modelId, options);
25
+ const anthropic = adjusted.providerOptions?.anthropic;
26
+ if (anthropic != null && "toolStreaming" in anthropic) return {
27
+ options: adjusted,
28
+ warnings
29
+ };
17
30
  return {
18
- ...options,
19
- providerOptions: {
20
- ...options.providerOptions,
21
- anthropic: {
22
- ...anthropic,
23
- toolStreaming: false
31
+ options: {
32
+ ...adjusted,
33
+ providerOptions: {
34
+ ...adjusted.providerOptions,
35
+ anthropic: {
36
+ ...anthropic,
37
+ toolStreaming: false
38
+ }
24
39
  }
25
- }
40
+ },
41
+ warnings
26
42
  };
27
43
  }
28
- doGenerate(options) {
29
- return super.doGenerate(this.withGatewayCompat(options));
44
+ async doGenerate(options) {
45
+ const { options: adjusted, warnings } = this.withGatewayCompat(options);
46
+ const result = await super.doGenerate(adjusted);
47
+ return warnings.length > 0 ? {
48
+ ...result,
49
+ warnings: [...warnings, ...result.warnings]
50
+ } : result;
30
51
  }
31
- doStream(options) {
32
- return super.doStream(this.withGatewayCompat(options));
52
+ async doStream(options) {
53
+ const { options: adjusted, warnings } = this.withGatewayCompat(options);
54
+ const result = await super.doStream(adjusted);
55
+ return warnings.length > 0 ? {
56
+ ...result,
57
+ stream: result.stream.pipeThrough(mergeStreamStartWarnings(warnings))
58
+ } : result;
33
59
  }
34
60
  };
35
61
  //#endregion
@@ -1 +1 @@
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 (`/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
+ {"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\tSharedV3Warning,\n} from \"@ai-sdk/provider\";\nimport {\n\tapplyNeonCapabilities,\n\tmergeStreamStartWarnings,\n} from \"./neon-capabilities.js\";\n\n/**\n * Language model for Anthropic models served via the Neon AI Gateway's native\n * Messages API (`/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 *\n * Capability filtering runs here as well as on the unified endpoint. The\n * upstream Anthropic model drops sampling parameters for the Claude versions it\n * knows about, but not for ones released after it, so `claude-opus-5` and\n * `claude-sonnet-5` reached the API and came back\n * `` `temperature` is deprecated for this model ``. Applying our own rules keeps\n * the behaviour tied to what the gateway was measured to accept rather than to\n * the SDK's release date.\n */\nexport class NeonAnthropicLanguageModel\n\textends AnthropicMessagesLanguageModel\n\timplements LanguageModelV3\n{\n\tprivate withGatewayCompat(options: LanguageModelV3CallOptions): {\n\t\toptions: LanguageModelV3CallOptions;\n\t\twarnings: SharedV3Warning[];\n\t} {\n\t\tconst { options: adjusted, warnings } = applyNeonCapabilities(\n\t\t\tthis.modelId,\n\t\t\toptions,\n\t\t);\n\t\tconst anthropic = adjusted.providerOptions?.anthropic;\n\t\t// Respect an explicit user setting.\n\t\tif (anthropic != null && \"toolStreaming\" in anthropic) {\n\t\t\treturn { options: adjusted, warnings };\n\t\t}\n\t\treturn {\n\t\t\toptions: {\n\t\t\t\t...adjusted,\n\t\t\t\tproviderOptions: {\n\t\t\t\t\t...adjusted.providerOptions,\n\t\t\t\t\tanthropic: { ...anthropic, toolStreaming: false },\n\t\t\t\t},\n\t\t\t},\n\t\t\twarnings,\n\t\t};\n\t}\n\n\toverride async doGenerate(\n\t\toptions: LanguageModelV3CallOptions,\n\t): Promise<LanguageModelV3GenerateResult> {\n\t\tconst { options: adjusted, warnings } = this.withGatewayCompat(options);\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 } = this.withGatewayCompat(options);\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":";;;;;;;;;;;;;;;;;;;;;AA+BA,IAAa,6BAAb,cACS,+BAET;CACC,kBAA0B,SAGxB;EACD,MAAM,EAAE,SAAS,UAAU,aAAa,sBACvC,KAAK,SACL,OACD;EACA,MAAM,YAAY,SAAS,iBAAiB;EAE5C,IAAI,aAAa,QAAQ,mBAAmB,WAC3C,OAAO;GAAE,SAAS;GAAU;EAAS;EAEtC,OAAO;GACN,SAAS;IACR,GAAG;IACH,iBAAiB;KAChB,GAAG,SAAS;KACZ,WAAW;MAAE,GAAG;MAAW,eAAe;KAAM;IACjD;GACD;GACA;EACD;CACD;CAEA,MAAe,WACd,SACyC;EACzC,MAAM,EAAE,SAAS,UAAU,aAAa,KAAK,kBAAkB,OAAO;EACtE,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,KAAK,kBAAkB,OAAO;EACtE,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 +1 @@
1
- {"version":3,"file":"neon-capabilities.d.ts","names":[],"sources":["../../src/lib/neon-capabilities.ts"],"mappings":";;;;;;AAaA;AAAqC;AAE3B;AACI,iBAHE,qBAAA,CAGF,OAAA,EAAA,MAAA,EAAA,OAAA,EADJ,0BACI,CAAA,EAAA;EAAsC,OAAA,EAAtC,0BAAsC;EAAe,QAAA,EAAf,eAAe,EAAA;AA4FnE,CAAA;AAAwC;AAAQ;AAAiB;AAAA,iBAAjD,wBAAA,CAAiD,KAAA,EAAjB,eAAiB,EAAA,CAAA,EAAA,eAAA,CAAA,yBAAA,EAAA,yBAAA,CAAA"}
1
+ {"version":3,"file":"neon-capabilities.d.ts","names":[],"sources":["../../src/lib/neon-capabilities.ts"],"mappings":";;;;;;AAoBA;AAAqC;AAE3B;AACI,iBAHE,qBAAA,CAGF,OAAA,EAAA,MAAA,EAAA,OAAA,EADJ,0BACI,CAAA,EAAA;EAAsC,OAAA,EAAtC,0BAAsC;EAAe,QAAA,EAAf,eAAe,EAAA;AA8GnE,CAAA;AAAwC;AAAQ;AAAiB;AAAA,iBAAjD,wBAAA,CAAiD,KAAA,EAAjB,eAAiB,EAAA,CAAA,EAAA,eAAA,CAAA,yBAAA,EAAA,yBAAA,CAAA"}
@@ -1,5 +1,8 @@
1
1
  import { getNeonModelCapabilities } from "./neon-model-capabilities.js";
2
2
  //#region src/lib/neon-capabilities.ts
3
+ const PENALTY_DETAILS = "Only Gemini accepts penalties on the gateway's unified endpoint, so it was dropped rather than sent.";
4
+ const GENERIC_DETAILS = "The Neon AI Gateway rejects this parameter for this model, so it was dropped rather than sent.";
5
+ const REASONING_EFFORT_DETAILS = "This model does not take the OpenAI reasoning_effort field, so it was dropped rather than sent.";
3
6
  /**
4
7
  * Drop call options the resolved model's upstream backend does not accept and
5
8
  * collect a warning for each, so callers get a clear signal instead of a hard
@@ -9,20 +12,23 @@ function applyNeonCapabilities(modelId, options) {
9
12
  const caps = getNeonModelCapabilities(modelId);
10
13
  const warnings = [];
11
14
  const patch = {};
12
- const dropUnsupported = (feature) => {
15
+ const drop = (feature, details, type = "unsupported") => {
13
16
  warnings.push({
14
- type: "unsupported",
17
+ type,
15
18
  feature,
16
- details: `${feature} is not supported by the Neon AI Gateway for ${caps.family} model "${modelId}" and was dropped.`
19
+ details
17
20
  });
18
21
  };
22
+ const unrecognizedClaude = caps.claudeSamplingUnrecognized === true;
23
+ const samplingDetails = unrecognizedClaude ? "This Claude version was not recognised. Claude 4.7 and newer reject sampling parameters, so it was dropped as a precaution; set `providerOptions.anthropic.effort` instead." : caps.family === "anthropic" ? "Claude 4.7 and newer reject sampling parameters, so it was dropped rather than sent. Use `providerOptions.anthropic.effort` (low | medium | high | xhigh | max) to steer these models." : "The Neon AI Gateway rejects this parameter for this model, so it was dropped rather than sent.";
24
+ const samplingType = unrecognizedClaude ? "compatibility" : "unsupported";
19
25
  if (options.temperature != null && !caps.supportsTemperature) {
20
26
  patch.temperature = void 0;
21
- dropUnsupported("temperature");
27
+ drop("temperature", samplingDetails, samplingType);
22
28
  }
23
29
  if (options.topP != null && !caps.supportsTopP) {
24
30
  patch.topP = void 0;
25
- dropUnsupported("topP");
31
+ drop("topP", samplingDetails, samplingType);
26
32
  }
27
33
  const effectiveTemperature = "temperature" in patch ? patch.temperature : options.temperature;
28
34
  const effectiveTopP = "topP" in patch ? patch.topP : options.topP;
@@ -31,29 +37,29 @@ function applyNeonCapabilities(modelId, options) {
31
37
  warnings.push({
32
38
  type: "compatibility",
33
39
  feature: "topP",
34
- details: `${caps.family} models accept only one of temperature or topP; topP was dropped.`
40
+ details: "Anthropic models accept only one of temperature or topP; topP was dropped and temperature kept."
35
41
  });
36
42
  }
37
43
  if (options.frequencyPenalty != null && !caps.supportsPenalties) {
38
44
  patch.frequencyPenalty = void 0;
39
- dropUnsupported("frequencyPenalty");
45
+ drop("frequencyPenalty", PENALTY_DETAILS);
40
46
  }
41
47
  if (options.presencePenalty != null && !caps.supportsPenalties) {
42
48
  patch.presencePenalty = void 0;
43
- dropUnsupported("presencePenalty");
49
+ drop("presencePenalty", PENALTY_DETAILS);
44
50
  }
45
51
  if (options.seed != null && !caps.supportsSeed) {
46
52
  patch.seed = void 0;
47
- dropUnsupported("seed");
53
+ drop("seed", GENERIC_DETAILS);
48
54
  }
49
55
  if (options.stopSequences != null && !caps.supportsStopSequences) {
50
56
  patch.stopSequences = void 0;
51
- dropUnsupported("stopSequences");
57
+ drop("stopSequences", GENERIC_DETAILS);
52
58
  }
53
59
  if (!caps.supportsReasoningEffort) {
54
60
  const { providerOptions } = options;
55
61
  if (providerOptions != null && Object.values(providerOptions).some((group) => "reasoningEffort" in group && group.reasoningEffort != null)) {
56
- dropUnsupported("reasoningEffort");
62
+ drop("reasoningEffort", REASONING_EFFORT_DETAILS);
57
63
  if (providerOptions != null) {
58
64
  const cleaned = {};
59
65
  for (const [key, group] of Object.entries(providerOptions)) if ("reasoningEffort" in group) {
@@ -1 +1 @@
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
+ {"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\nconst PENALTY_DETAILS =\n\t\"Only Gemini accepts penalties on the gateway's unified endpoint, so it was dropped rather than sent.\";\nconst GENERIC_DETAILS =\n\t\"The Neon AI Gateway rejects this parameter for this model, so it was dropped rather than sent.\";\nconst REASONING_EFFORT_DETAILS =\n\t\"This model does not take the OpenAI reasoning_effort field, so it was dropped rather than sent.\";\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\t// The AI SDK prints the provider, the model id and the feature name ahead of\n\t// `details`, so each reason says only what those cannot: why the gateway\n\t// refuses it, and what to use instead. Each carries its own \"was dropped\"\n\t// clause rather than a shared suffix — appending one everywhere restated the\n\t// penalty reason and asserted a 400 for the unrecognised case, which is the\n\t// overstatement this wording exists to avoid.\n\tconst drop = (\n\t\tfeature: string,\n\t\tdetails: string,\n\t\ttype: \"unsupported\" | \"compatibility\" = \"unsupported\",\n\t) => {\n\t\twarnings.push({ type, feature, details });\n\t};\n\n\t// Precautionary rather than measured, so it is flagged as a compatibility\n\t// choice: the SDK renders `unsupported` as a flat \"is not supported\", which\n\t// would contradict the hedge in the sentence that follows it.\n\tconst unrecognizedClaude = caps.claudeSamplingUnrecognized === true;\n\tconst samplingDetails = unrecognizedClaude\n\t\t? \"This Claude version was not recognised. Claude 4.7 and newer reject sampling parameters, so it was dropped as a precaution; set `providerOptions.anthropic.effort` instead.\"\n\t\t: caps.family === \"anthropic\"\n\t\t\t? \"Claude 4.7 and newer reject sampling parameters, so it was dropped rather than sent. Use `providerOptions.anthropic.effort` (low | medium | high | xhigh | max) to steer these models.\"\n\t\t\t: \"The Neon AI Gateway rejects this parameter for this model, so it was dropped rather than sent.\";\n\tconst samplingType = unrecognizedClaude ? \"compatibility\" : \"unsupported\";\n\n\tif (options.temperature != null && !caps.supportsTemperature) {\n\t\tpatch.temperature = undefined;\n\t\tdrop(\"temperature\", samplingDetails, samplingType);\n\t}\n\tif (options.topP != null && !caps.supportsTopP) {\n\t\tpatch.topP = undefined;\n\t\tdrop(\"topP\", samplingDetails, samplingType);\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:\n\t\t\t\t\"Anthropic models accept only one of temperature or topP; topP was dropped and temperature kept.\",\n\t\t});\n\t}\n\n\tif (options.frequencyPenalty != null && !caps.supportsPenalties) {\n\t\tpatch.frequencyPenalty = undefined;\n\t\tdrop(\"frequencyPenalty\", PENALTY_DETAILS);\n\t}\n\tif (options.presencePenalty != null && !caps.supportsPenalties) {\n\t\tpatch.presencePenalty = undefined;\n\t\tdrop(\"presencePenalty\", PENALTY_DETAILS);\n\t}\n\tif (options.seed != null && !caps.supportsSeed) {\n\t\tpatch.seed = undefined;\n\t\tdrop(\"seed\", GENERIC_DETAILS);\n\t}\n\n\tif (options.stopSequences != null && !caps.supportsStopSequences) {\n\t\tpatch.stopSequences = undefined;\n\t\tdrop(\"stopSequences\", GENERIC_DETAILS);\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\tdrop(\"reasoningEffort\", REASONING_EFFORT_DETAILS);\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":";;AAQA,MAAM,kBACL;AACD,MAAM,kBACL;AACD,MAAM,2BACL;;;;;;AAOD,SAAgB,sBACf,SACA,SACuE;CACvE,MAAM,OAAO,yBAAyB,OAAO;CAC7C,MAAM,WAA8B,CAAC;CACrC,MAAM,QAA6C,CAAC;CAQpD,MAAM,QACL,SACA,SACA,OAAwC,kBACpC;EACJ,SAAS,KAAK;GAAE;GAAM;GAAS;EAAQ,CAAC;CACzC;CAKA,MAAM,qBAAqB,KAAK,+BAA+B;CAC/D,MAAM,kBAAkB,qBACrB,gLACA,KAAK,WAAW,cACf,2LACA;CACJ,MAAM,eAAe,qBAAqB,kBAAkB;CAE5D,IAAI,QAAQ,eAAe,QAAQ,CAAC,KAAK,qBAAqB;EAC7D,MAAM,cAAc,KAAA;EACpB,KAAK,eAAe,iBAAiB,YAAY;CAClD;CACA,IAAI,QAAQ,QAAQ,QAAQ,CAAC,KAAK,cAAc;EAC/C,MAAM,OAAO,KAAA;EACb,KAAK,QAAQ,iBAAiB,YAAY;CAC3C;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,SACC;EACF,CAAC;CACF;CAEA,IAAI,QAAQ,oBAAoB,QAAQ,CAAC,KAAK,mBAAmB;EAChE,MAAM,mBAAmB,KAAA;EACzB,KAAK,oBAAoB,eAAe;CACzC;CACA,IAAI,QAAQ,mBAAmB,QAAQ,CAAC,KAAK,mBAAmB;EAC/D,MAAM,kBAAkB,KAAA;EACxB,KAAK,mBAAmB,eAAe;CACxC;CACA,IAAI,QAAQ,QAAQ,QAAQ,CAAC,KAAK,cAAc;EAC/C,MAAM,OAAO,KAAA;EACb,KAAK,QAAQ,eAAe;CAC7B;CAEA,IAAI,QAAQ,iBAAiB,QAAQ,CAAC,KAAK,uBAAuB;EACjE,MAAM,gBAAgB,KAAA;EACtB,KAAK,iBAAiB,eAAe;CACtC;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,KAAK,mBAAmB,wBAAwB;GAChD,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,15 +1,8 @@
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];
3
+ declare const NEON_MODELS_DEV_IDS: readonly ["claude-fable-5", "claude-haiku-4-5", "claude-opus-4-1", "claude-opus-4-5", "claude-opus-4-6", "claude-opus-4-7", "claude-opus-4-8", "claude-opus-5", "claude-sonnet-4-5", "claude-sonnet-4-6", "claude-sonnet-5", "gpt-5", "gpt-5-1", "gpt-5-2", "gpt-5-3-codex", "gpt-5-4", "gpt-5-4-mini", "gpt-5-4-nano", "gpt-5-5", "gpt-5-5-pro", "gpt-5-6-luna", "gpt-5-6-sol", "gpt-5-6-terra", "gpt-5-mini", "gpt-5-nano", "gpt-oss-120b", "gpt-oss-20b", "gemini-3-1-flash-lite", "gemini-3-1-pro", "gemini-3-5-flash", "gemini-3-flash", "gemma-3-12b", "llama-4-maverick", "meta-llama-3-1-8b-instruct", "meta-llama-3-3-70b-instruct", "qwen3-next-80b-a3b-instruct", "qwen35-122b-a10b", "glm-5-2", "inkling"];
4
+ /** A known Neon AI Gateway model id. */
5
+ type NeonKnownModelId = (typeof NEON_MODELS_DEV_IDS)[number];
13
6
  /**
14
7
  * A Neon AI Gateway model id. Known ids are listed for autocomplete; any other
15
8
  * id (e.g. a brand-new model, or the legacy `databricks-` prefixed form) is
@@ -17,5 +10,5 @@ type NeonKnownModelId = (typeof NEON_MODELS_DEV_IDS)[number] | (typeof NEON_EXTR
17
10
  */
18
11
  type NeonChatModelId = NeonKnownModelId | (string & {});
19
12
  //#endregion
20
- export { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS, NeonChatModelId, NeonKnownModelId };
13
+ export { NEON_MODELS_DEV_IDS, NeonChatModelId, NeonKnownModelId };
21
14
  //# 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":";;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;AAA4B;AACjB;AACA;AAAoB;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
+ {"version":3,"file":"neon-chat-options.d.ts","names":[],"sources":["../../src/lib/neon-chat-options.ts"],"mappings":";;AAsBa,cAAA,mBAgDH,EAAA,SAAA,CAAA,gBAAA,EAAA,kBAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,mBAAA,EAAA,mBAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,SAAA,EAAA,SAAA,EAAA,eAAA,EAAA,SAAA,EAAA,cAAA,EAAA,cAAA,EAAA,SAAA,EAAA,aAAA,EAAA,cAAA,EAAA,aAAA,EAAA,eAAA,EAAA,YAAA,EAAA,YAAA,EAAA,cAAA,EAAA,aAAA,EAAA,uBAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,gBAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,4BAAA,EAAA,6BAAA,EAAA,6BAAA,EAAA,kBAAA,EAAA,SAAA,EAAA,SAAA,CAAA;AAGV;AAOY,KAPA,gBAAA,GAOe,CAAG,OAPS,mBAOO,CAAA,CAAA,MAAA,CAAA;;;;;;KAAlC,eAAA,GAAkB"}
@@ -1,52 +1,47 @@
1
1
  //#region src/lib/neon-chat-options.ts
2
2
  /** The models.dev `neon` catalog (canonical, unprefixed ids). */
3
3
  const NEON_MODELS_DEV_IDS = [
4
- "claude-opus-4-7",
5
- "claude-opus-4-6",
6
- "claude-opus-4-5",
4
+ "claude-fable-5",
5
+ "claude-haiku-4-5",
7
6
  "claude-opus-4-1",
8
- "claude-sonnet-4-6",
7
+ "claude-opus-4-5",
8
+ "claude-opus-4-6",
9
+ "claude-opus-4-7",
10
+ "claude-opus-4-8",
11
+ "claude-opus-5",
9
12
  "claude-sonnet-4-5",
10
- "claude-sonnet-4",
11
- "claude-haiku-4-5",
13
+ "claude-sonnet-4-6",
14
+ "claude-sonnet-5",
12
15
  "gpt-5",
13
- "gpt-5-mini",
14
- "gpt-5-nano",
15
16
  "gpt-5-1",
16
17
  "gpt-5-2",
18
+ "gpt-5-3-codex",
17
19
  "gpt-5-4",
18
20
  "gpt-5-4-mini",
19
21
  "gpt-5-4-nano",
20
22
  "gpt-5-5",
23
+ "gpt-5-5-pro",
24
+ "gpt-5-6-luna",
25
+ "gpt-5-6-sol",
26
+ "gpt-5-6-terra",
27
+ "gpt-5-mini",
28
+ "gpt-5-nano",
21
29
  "gpt-oss-120b",
22
30
  "gpt-oss-20b",
23
- "gemini-3-pro",
24
- "gemini-3-flash",
25
- "gemini-3-1-pro",
26
31
  "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",
32
+ "gemini-3-1-pro",
41
33
  "gemini-3-5-flash",
34
+ "gemini-3-flash",
42
35
  "gemma-3-12b",
43
36
  "llama-4-maverick",
44
- "meta-llama-3-3-70b-instruct",
45
37
  "meta-llama-3-1-8b-instruct",
38
+ "meta-llama-3-3-70b-instruct",
46
39
  "qwen3-next-80b-a3b-instruct",
47
- "qwen35-122b-a10b"
40
+ "qwen35-122b-a10b",
41
+ "glm-5-2",
42
+ "inkling"
48
43
  ];
49
44
  //#endregion
50
- export { NEON_EXTRA_MODEL_IDS, NEON_MODELS_DEV_IDS };
45
+ export { NEON_MODELS_DEV_IDS };
51
46
 
52
47
  //# sourceMappingURL=neon-chat-options.js.map