@ai-sdk/gateway 4.0.17 → 4.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/index.d.ts +30 -9
- package/dist/index.js +255 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/gateway-config.ts +6 -1
- package/src/gateway-fetch-metadata.ts +2 -0
- package/src/gateway-generation-info.ts +1 -0
- package/src/gateway-provider.ts +10 -0
- package/src/gateway-realtime-auth.ts +38 -10
- package/src/gateway-spend-report.ts +1 -0
- package/src/gateway-transcription-model-settings.ts +1 -0
- package/src/gateway-transcription-model.ts +354 -5
- package/src/index.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @ai-sdk/gateway
|
|
2
2
|
|
|
3
|
+
## 4.0.19
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4be62c1: fix(provider-utils): validate provider-response URLs in `getFromApi`
|
|
8
|
+
|
|
9
|
+
`getFromApi` now has a `validateUrl` flag. It is optional so existing callers keep compiling (omitting it behaves like `false`, i.e. no validation), but all AI SDK provider packages set it explicitly at every call site so each one makes a visible trust decision. When `true`, the URL is routed through `fetchWithValidatedRedirects` — the same guard used by `downloadBlob` — which rejects private/loopback/link-local targets, re-validates every redirect hop, strips proxy/metadata/cookie request headers, and drops all caller headers except the user-agent on cross-origin redirects (custom API-key headers must not follow a redirect off-origin any more than `Authorization` may); blocked URLs throw `DownloadError`. It is enabled at the image/video/audio download and polling call sites where the URL comes from a provider response body; URLs built from developer-configured endpoints pass `validateUrl: false` and are unaffected.
|
|
10
|
+
|
|
11
|
+
A new optional `credentialedOrigin` withholds caller headers unless the URL is same-origin with it, so the API key is not sent to a response-supplied host on a different origin.
|
|
12
|
+
|
|
13
|
+
A new optional `trustedOrigin` exempts URLs (and redirect hops) that are same-origin with the developer-configured provider endpoint from target validation, so self-hosted and localhost deployments whose response URLs point back at the configured host keep working; all other hops are still validated.
|
|
14
|
+
|
|
15
|
+
Also closes range gaps in `validateDownloadUrl` (IPv4 `224.0.0.0/4` multicast and the TEST-NET documentation ranges `192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`; IPv6 documentation ranges `2001:db8::/32` and `3fff::/20`), and follows only the fetch-spec redirect status codes (301/302/303/307/308) — a `Location` header on any other status is not followed. This guard performs string/literal checks only and does not resolve DNS; hostnames that resolve to private addresses and DNS rebinding remain out of scope and must be constrained at the network layer (or by injecting a Node `fetch` that pins the resolved IP at connect time) for server deployments handling untrusted URLs. See `contributing/secure-url-handling.md`.
|
|
16
|
+
|
|
17
|
+
- f8e82fd: Add experimental streaming transcription support to the gateway provider (`GatewayTranscriptionModel.doStream`), speaking the shared transcription-stream WebSocket envelope from `@ai-sdk/provider-utils`. `experimental_streamTranscribe` now works with gateway string model IDs, e.g. `experimental_streamTranscribe({ model: 'openai/gpt-realtime-whisper', ... })`.
|
|
18
|
+
- Updated dependencies [4be62c1]
|
|
19
|
+
- Updated dependencies [7805e4a]
|
|
20
|
+
- Updated dependencies [cd12954]
|
|
21
|
+
- @ai-sdk/provider-utils@5.0.9
|
|
22
|
+
|
|
23
|
+
## 4.0.18
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [e193290]
|
|
28
|
+
- @ai-sdk/provider-utils@5.0.8
|
|
29
|
+
|
|
3
30
|
## 4.0.17
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { LanguageModelV4, ProviderV4, EmbeddingModelV4, ImageModelV4, Experimental_VideoModelV4, RerankingModelV4, SpeechModelV4, TranscriptionModelV4, Experimental_RealtimeFactoryV4, TypeValidationError } from '@ai-sdk/provider';
|
|
2
2
|
import * as _ai_sdk_provider_utils from '@ai-sdk/provider-utils';
|
|
3
|
-
import { FetchFunction, InferSchema } from '@ai-sdk/provider-utils';
|
|
3
|
+
import { FetchFunction, WebSocketConstructor, InferSchema } from '@ai-sdk/provider-utils';
|
|
4
4
|
|
|
5
5
|
type GatewayModelId = 'alibaba/qwen-3-14b' | 'alibaba/qwen-3-235b' | 'alibaba/qwen-3-30b' | 'alibaba/qwen-3-32b' | 'alibaba/qwen-3.6-max-preview' | 'alibaba/qwen3-235b-a22b-thinking' | 'alibaba/qwen3-coder' | 'alibaba/qwen3-coder-30b-a3b' | 'alibaba/qwen3-coder-next' | 'alibaba/qwen3-coder-plus' | 'alibaba/qwen3-max' | 'alibaba/qwen3-max-preview' | 'alibaba/qwen3-max-thinking' | 'alibaba/qwen3-next-80b-a3b-instruct' | 'alibaba/qwen3-next-80b-a3b-thinking' | 'alibaba/qwen3-vl-235b-a22b-instruct' | 'alibaba/qwen3-vl-instruct' | 'alibaba/qwen3-vl-thinking' | 'alibaba/qwen3.5-flash' | 'alibaba/qwen3.5-plus' | 'alibaba/qwen3.6-27b' | 'alibaba/qwen3.6-plus' | 'alibaba/qwen3.7-max' | 'alibaba/qwen3.7-plus' | 'amazon/nova-2-lite' | 'amazon/nova-lite' | 'amazon/nova-micro' | 'amazon/nova-pro' | 'anthropic/claude-3-haiku' | 'anthropic/claude-3.5-haiku' | 'anthropic/claude-fable-5' | 'anthropic/claude-haiku-4.5' | 'anthropic/claude-opus-4' | 'anthropic/claude-opus-4.1' | 'anthropic/claude-opus-4.5' | 'anthropic/claude-opus-4.6' | 'anthropic/claude-opus-4.7' | 'anthropic/claude-opus-4.8' | 'anthropic/claude-sonnet-4' | 'anthropic/claude-sonnet-4.5' | 'anthropic/claude-sonnet-4.6' | 'anthropic/claude-sonnet-5' | 'arcee-ai/trinity-large-preview' | 'arcee-ai/trinity-large-thinking' | 'arcee-ai/trinity-mini' | 'bytedance/seed-1.6' | 'bytedance/seed-1.8' | 'cohere/command-a' | 'deepseek/deepseek-r1' | 'deepseek/deepseek-v3' | 'deepseek/deepseek-v3.1' | 'deepseek/deepseek-v3.1-terminus' | 'deepseek/deepseek-v3.2' | 'deepseek/deepseek-v3.2-thinking' | 'deepseek/deepseek-v4-flash' | 'deepseek/deepseek-v4-pro' | 'google/gemini-2.5-flash' | 'google/gemini-2.5-flash-image' | 'google/gemini-2.5-flash-lite' | 'google/gemini-2.5-pro' | 'google/gemini-3-flash' | 'google/gemini-3-pro-image' | 'google/gemini-3-pro-preview' | 'google/gemini-3.1-flash-image' | 'google/gemini-3.1-flash-image-preview' | 'google/gemini-3.1-flash-lite' | 'google/gemini-3.1-flash-lite-image' | 'google/gemini-3.1-flash-lite-preview' | 'google/gemini-3.1-pro-preview' | 'google/gemini-3.5-flash' | 'google/gemini-omni-flash-preview' | 'google/gemma-4-26b-a4b-it' | 'google/gemma-4-31b-it' | 'inception/mercury-2' | 'inception/mercury-coder-small' | 'interfaze/interfaze-beta' | 'kwaipilot/kat-coder-air-v2.5' | 'kwaipilot/kat-coder-pro-v1' | 'kwaipilot/kat-coder-pro-v2' | 'kwaipilot/kat-coder-pro-v2.5' | 'meituan/longcat-flash-chat' | 'meituan/longcat-flash-thinking-2601' | 'meta/llama-3.1-70b' | 'meta/llama-3.1-8b' | 'meta/llama-3.2-11b' | 'meta/llama-3.2-1b' | 'meta/llama-3.2-3b' | 'meta/llama-3.2-90b' | 'meta/llama-3.3-70b' | 'meta/llama-4-maverick' | 'meta/llama-4-scout' | 'meta/muse-spark-1.1' | 'minimax/minimax-m2' | 'minimax/minimax-m2.1' | 'minimax/minimax-m2.1-lightning' | 'minimax/minimax-m2.5' | 'minimax/minimax-m2.5-highspeed' | 'minimax/minimax-m2.7' | 'minimax/minimax-m2.7-highspeed' | 'minimax/minimax-m3' | 'mistral/codestral' | 'mistral/devstral-2' | 'mistral/devstral-small' | 'mistral/devstral-small-2' | 'mistral/magistral-medium' | 'mistral/magistral-small' | 'mistral/ministral-14b' | 'mistral/ministral-3b' | 'mistral/ministral-8b' | 'mistral/mistral-large-3' | 'mistral/mistral-medium' | 'mistral/mistral-medium-3.5' | 'mistral/mistral-nemo' | 'mistral/mistral-small' | 'mistral/pixtral-12b' | 'mistral/pixtral-large' | 'moonshotai/kimi-k2' | 'moonshotai/kimi-k2-thinking' | 'moonshotai/kimi-k2.5' | 'moonshotai/kimi-k2.6' | 'moonshotai/kimi-k2.7-code' | 'moonshotai/kimi-k2.7-code-highspeed' | 'morph/morph-v3-fast' | 'morph/morph-v3-large' | 'nvidia/nemotron-3-nano-30b-a3b' | 'nvidia/nemotron-3-super-120b-a12b' | 'nvidia/nemotron-3-ultra-550b-a55b' | 'nvidia/nemotron-nano-12b-v2-vl' | 'nvidia/nemotron-nano-9b-v2' | 'openai/gpt-3.5-turbo' | 'openai/gpt-3.5-turbo-instruct' | 'openai/gpt-4-turbo' | 'openai/gpt-4.1' | 'openai/gpt-4.1-mini' | 'openai/gpt-4.1-nano' | 'openai/gpt-4o' | 'openai/gpt-4o-mini' | 'openai/gpt-4o-mini-search-preview' | 'openai/gpt-5' | 'openai/gpt-5-chat' | 'openai/gpt-5-codex' | 'openai/gpt-5-mini' | 'openai/gpt-5-nano' | 'openai/gpt-5-pro' | 'openai/gpt-5.1-codex' | 'openai/gpt-5.1-codex-max' | 'openai/gpt-5.1-codex-mini' | 'openai/gpt-5.1-instant' | 'openai/gpt-5.1-thinking' | 'openai/gpt-5.2' | 'openai/gpt-5.2-chat' | 'openai/gpt-5.2-codex' | 'openai/gpt-5.2-pro' | 'openai/gpt-5.3-chat' | 'openai/gpt-5.3-codex' | 'openai/gpt-5.4' | 'openai/gpt-5.4-mini' | 'openai/gpt-5.4-nano' | 'openai/gpt-5.4-pro' | 'openai/gpt-5.5' | 'openai/gpt-5.5-pro' | 'openai/gpt-5.6-luna' | 'openai/gpt-5.6-sol' | 'openai/gpt-5.6-terra' | 'openai/gpt-oss-120b' | 'openai/gpt-oss-20b' | 'openai/gpt-oss-safeguard-20b' | 'openai/o1' | 'openai/o3' | 'openai/o3-deep-research' | 'openai/o3-mini' | 'openai/o3-pro' | 'openai/o4-mini' | 'perplexity/sonar' | 'perplexity/sonar-pro' | 'perplexity/sonar-reasoning-pro' | 'sakana/fugu-ultra' | 'stepfun/step-3.5-flash' | 'stepfun/step-3.7-flash' | 'xai/grok-4.1-fast-non-reasoning' | 'xai/grok-4.1-fast-reasoning' | 'xai/grok-4.20-multi-agent' | 'xai/grok-4.20-multi-agent-beta' | 'xai/grok-4.20-non-reasoning' | 'xai/grok-4.20-non-reasoning-beta' | 'xai/grok-4.20-reasoning' | 'xai/grok-4.20-reasoning-beta' | 'xai/grok-4.3' | 'xai/grok-4.5' | 'xai/grok-build-0.1' | 'xiaomi/mimo-v2-flash' | 'xiaomi/mimo-v2-pro' | 'xiaomi/mimo-v2.5' | 'xiaomi/mimo-v2.5-pro' | 'zai/glm-4.5' | 'zai/glm-4.5-air' | 'zai/glm-4.5v' | 'zai/glm-4.6' | 'zai/glm-4.6v' | 'zai/glm-4.6v-flash' | 'zai/glm-4.7' | 'zai/glm-4.7-flash' | 'zai/glm-4.7-flashx' | 'zai/glm-5' | 'zai/glm-5-turbo' | 'zai/glm-5.1' | 'zai/glm-5.2' | 'zai/glm-5.2-fast' | 'zai/glm-5v-turbo' | (string & {});
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Shared WebSocket subprotocol contract for AI Gateway realtime
|
|
8
|
+
* Shared WebSocket subprotocol contract for AI Gateway realtime and streaming
|
|
9
|
+
* transcription auth.
|
|
9
10
|
*
|
|
10
11
|
* The browser `WebSocket` API cannot set request headers, so the Gateway auth
|
|
11
12
|
* (bearer) token is carried through the `Sec-WebSocket-Protocol` handshake
|
|
@@ -14,8 +15,9 @@ type GatewayModelId = 'alibaba/qwen-3-14b' | 'alibaba/qwen-3-235b' | 'alibaba/qw
|
|
|
14
15
|
*
|
|
15
16
|
* This module is the single source of truth for that contract so the client and
|
|
16
17
|
* the Gateway server can't drift: the client encodes values with
|
|
17
|
-
* `getGatewayRealtimeProtocols`, and the
|
|
18
|
-
* `getGatewayRealtimeAuthToken` /
|
|
18
|
+
* `getGatewayRealtimeProtocols` / `getGatewayTranscriptionProtocols`, and the
|
|
19
|
+
* Gateway server decodes them with `getGatewayRealtimeAuthToken` /
|
|
20
|
+
* `getGatewayRealtimeTeamIdOrSlug`.
|
|
19
21
|
*
|
|
20
22
|
* WebSocket subprotocol values must fit the RFC token grammar. The auth token is
|
|
21
23
|
* sent as-is, so callers must use tokens that are valid subprotocol tokens; the
|
|
@@ -24,11 +26,16 @@ type GatewayModelId = 'alibaba/qwen-3-14b' | 'alibaba/qwen-3-235b' | 'alibaba/qw
|
|
|
24
26
|
* budget) because intermediaries may reject large upgrade headers.
|
|
25
27
|
*/
|
|
26
28
|
/**
|
|
27
|
-
* Marker subprotocol offered on every handshake so the Gateway can
|
|
28
|
-
* negotiated subprotocol on the 101 response (some clients require the
|
|
29
|
-
* select one of the offered subprotocols).
|
|
29
|
+
* Marker subprotocol offered on every realtime handshake so the Gateway can
|
|
30
|
+
* echo a negotiated subprotocol on the 101 response (some clients require the
|
|
31
|
+
* server to select one of the offered subprotocols).
|
|
30
32
|
*/
|
|
31
33
|
declare const GATEWAY_REALTIME_SUBPROTOCOL = "ai-gateway-realtime.v1";
|
|
34
|
+
/**
|
|
35
|
+
* Marker subprotocol for streaming transcription handshakes (same negotiation
|
|
36
|
+
* purpose as `GATEWAY_REALTIME_SUBPROTOCOL`).
|
|
37
|
+
*/
|
|
38
|
+
declare const GATEWAY_TRANSCRIPTION_SUBPROTOCOL = "ai-gateway-transcription.v1";
|
|
32
39
|
/** Subprotocol prefix that carries the Gateway auth (bearer) token. */
|
|
33
40
|
declare const GATEWAY_AUTH_SUBPROTOCOL_PREFIX = "ai-gateway-auth.";
|
|
34
41
|
/** Subprotocol prefix that carries optional Vercel team scoping. */
|
|
@@ -40,6 +47,13 @@ declare const GATEWAY_TEAM_SUBPROTOCOL_PREFIX = "ai-gateway-team.";
|
|
|
40
47
|
declare function getGatewayRealtimeProtocols(token: string, options?: {
|
|
41
48
|
teamIdOrSlug?: string;
|
|
42
49
|
}): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Client-side: `getGatewayRealtimeProtocols`, but with the streaming
|
|
52
|
+
* transcription marker subprotocol.
|
|
53
|
+
*/
|
|
54
|
+
declare function getGatewayTranscriptionProtocols(token: string, options?: {
|
|
55
|
+
teamIdOrSlug?: string;
|
|
56
|
+
}): string[];
|
|
43
57
|
/**
|
|
44
58
|
* Server-side: extract the Gateway auth (bearer) token from a
|
|
45
59
|
* `Sec-WebSocket-Protocol` header value, or `undefined` when it is absent or
|
|
@@ -63,7 +77,7 @@ type GatewayRerankingModelId = 'cohere/rerank-v3.5' | 'cohere/rerank-v4-fast' |
|
|
|
63
77
|
|
|
64
78
|
type GatewaySpeechModelId = 'openai/tts-1' | 'openai/tts-1-hd' | 'xai/grok-tts' | (string & {});
|
|
65
79
|
|
|
66
|
-
type GatewayTranscriptionModelId = 'openai/gpt-4o-mini-transcribe' | 'openai/gpt-4o-transcribe' | 'openai/whisper-1' | 'xai/grok-stt' | (string & {});
|
|
80
|
+
type GatewayTranscriptionModelId = 'openai/gpt-4o-mini-transcribe' | 'openai/gpt-4o-transcribe' | 'openai/gpt-realtime-whisper' | 'openai/whisper-1' | 'xai/grok-stt' | (string & {});
|
|
67
81
|
|
|
68
82
|
type GatewayVideoModelId = 'alibaba/wan-v2.5-t2v-preview' | 'alibaba/wan-v2.6-i2v' | 'alibaba/wan-v2.6-i2v-flash' | 'alibaba/wan-v2.6-r2v' | 'alibaba/wan-v2.6-r2v-flash' | 'alibaba/wan-v2.6-t2v' | 'alibaba/wan-v2.7-r2v' | 'alibaba/wan-v2.7-t2v' | 'bytedance/seedance-2.0' | 'bytedance/seedance-2.0-fast' | 'bytedance/seedance-v1.0-pro' | 'bytedance/seedance-v1.0-pro-fast' | 'bytedance/seedance-v1.5-pro' | 'google/veo-3.0-fast-generate-001' | 'google/veo-3.0-generate-001' | 'google/veo-3.1-fast-generate-001' | 'google/veo-3.1-generate-001' | 'klingai/kling-v2.5-turbo-i2v' | 'klingai/kling-v2.5-turbo-t2v' | 'klingai/kling-v2.6-i2v' | 'klingai/kling-v2.6-motion-control' | 'klingai/kling-v2.6-t2v' | 'klingai/kling-v3.0-i2v' | 'klingai/kling-v3.0-motion-control' | 'klingai/kling-v3.0-t2v' | 'xai/grok-imagine-video' | 'xai/grok-imagine-video-1.5' | 'xai/grok-imagine-video-1.5-preview' | (string & {});
|
|
69
83
|
|
|
@@ -763,6 +777,13 @@ interface GatewayProviderSettings {
|
|
|
763
777
|
* or to provide a custom fetch implementation for e.g. testing.
|
|
764
778
|
*/
|
|
765
779
|
fetch?: FetchFunction;
|
|
780
|
+
/**
|
|
781
|
+
* Custom WebSocket implementation used for streaming transcription. This is
|
|
782
|
+
* useful for testing or for runtimes without a global WebSocket. A
|
|
783
|
+
* header-capable implementation is not required — Gateway WebSocket auth is
|
|
784
|
+
* carried in the subprotocols.
|
|
785
|
+
*/
|
|
786
|
+
webSocket?: WebSocketConstructor;
|
|
766
787
|
/**
|
|
767
788
|
* How frequently to refresh the metadata cache in milliseconds.
|
|
768
789
|
*/
|
|
@@ -1013,4 +1034,4 @@ declare class GatewayResponseError extends GatewayError {
|
|
|
1013
1034
|
|
|
1014
1035
|
declare const VERSION: string;
|
|
1015
1036
|
|
|
1016
|
-
export { GATEWAY_AUTH_SUBPROTOCOL_PREFIX, GATEWAY_REALTIME_SUBPROTOCOL, GATEWAY_TEAM_SUBPROTOCOL_PREFIX, GatewayAuthenticationError, type GatewayCreditsResponse, GatewayError, type GatewayErrorResponse, GatewayFailedDependencyError, GatewayForbiddenError, type GatewayGenerationInfo, type GatewayGenerationInfoParams, GatewayInternalServerError, GatewayInvalidRequestError, type GatewayLanguageModelEntry, type GatewayProviderOptions as GatewayLanguageModelOptions, type GatewayLanguageModelSpecification, type GatewayLanguageModelEntry as GatewayModelEntry, type GatewayModelId, GatewayModelNotFoundError, type GatewayProvider, type GatewayProviderOptions, type GatewayProviderSettings, GatewayRateLimitError, type GatewayRealtimeModelId, type GatewayRerankingModelId, GatewayResponseError, type GatewaySpeechModelId, type GatewaySpendReportParams, type GatewaySpendReportResponse, type GatewaySpendReportRow, type GatewayTranscriptionModelId, type GatewayVideoModelId, VERSION, createGateway, createGateway as createGatewayProvider, gateway, getGatewayRealtimeAuthToken, getGatewayRealtimeProtocols, getGatewayRealtimeTeamIdOrSlug };
|
|
1037
|
+
export { GATEWAY_AUTH_SUBPROTOCOL_PREFIX, GATEWAY_REALTIME_SUBPROTOCOL, GATEWAY_TEAM_SUBPROTOCOL_PREFIX, GATEWAY_TRANSCRIPTION_SUBPROTOCOL, GatewayAuthenticationError, type GatewayCreditsResponse, GatewayError, type GatewayErrorResponse, GatewayFailedDependencyError, GatewayForbiddenError, type GatewayGenerationInfo, type GatewayGenerationInfoParams, GatewayInternalServerError, GatewayInvalidRequestError, type GatewayLanguageModelEntry, type GatewayProviderOptions as GatewayLanguageModelOptions, type GatewayLanguageModelSpecification, type GatewayLanguageModelEntry as GatewayModelEntry, type GatewayModelId, GatewayModelNotFoundError, type GatewayProvider, type GatewayProviderOptions, type GatewayProviderSettings, GatewayRateLimitError, type GatewayRealtimeModelId, type GatewayRerankingModelId, GatewayResponseError, type GatewaySpeechModelId, type GatewaySpendReportParams, type GatewaySpendReportResponse, type GatewaySpendReportRow, type GatewayTranscriptionModelId, type GatewayVideoModelId, VERSION, createGateway, createGateway as createGatewayProvider, gateway, getGatewayRealtimeAuthToken, getGatewayRealtimeProtocols, getGatewayRealtimeTeamIdOrSlug, getGatewayTranscriptionProtocols };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
// src/gateway-realtime-auth.ts
|
|
2
2
|
var GATEWAY_REALTIME_SUBPROTOCOL = "ai-gateway-realtime.v1";
|
|
3
|
+
var GATEWAY_TRANSCRIPTION_SUBPROTOCOL = "ai-gateway-transcription.v1";
|
|
3
4
|
var GATEWAY_AUTH_SUBPROTOCOL_PREFIX = "ai-gateway-auth.";
|
|
4
5
|
var GATEWAY_TEAM_SUBPROTOCOL_PREFIX = "ai-gateway-team.";
|
|
5
6
|
function getGatewayRealtimeProtocols(token, options) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
return buildGatewayProtocols(GATEWAY_REALTIME_SUBPROTOCOL, token, options);
|
|
8
|
+
}
|
|
9
|
+
function getGatewayTranscriptionProtocols(token, options) {
|
|
10
|
+
return buildGatewayProtocols(
|
|
11
|
+
GATEWAY_TRANSCRIPTION_SUBPROTOCOL,
|
|
12
|
+
token,
|
|
13
|
+
options
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
function buildGatewayProtocols(marker11, token, options) {
|
|
17
|
+
const protocols = [marker11, `${GATEWAY_AUTH_SUBPROTOCOL_PREFIX}${token}`];
|
|
10
18
|
if (options == null ? void 0 : options.teamIdOrSlug) {
|
|
11
19
|
protocols.push(
|
|
12
20
|
`${GATEWAY_TEAM_SUBPROTOCOL_PREFIX}${encodeSubprotocolValue(options.teamIdOrSlug)}`
|
|
@@ -641,6 +649,7 @@ var GatewayFetchMetadata = class {
|
|
|
641
649
|
try {
|
|
642
650
|
const { value } = await getFromApi({
|
|
643
651
|
url: `${this.config.baseURL}/config`,
|
|
652
|
+
validateUrl: false,
|
|
644
653
|
headers: this.config.headers ? await resolve(this.config.headers) : void 0,
|
|
645
654
|
successfulResponseHandler: createJsonResponseHandler(
|
|
646
655
|
gatewayAvailableModelsResponseSchema
|
|
@@ -661,6 +670,7 @@ var GatewayFetchMetadata = class {
|
|
|
661
670
|
const baseUrl = new URL(this.config.baseURL);
|
|
662
671
|
const { value } = await getFromApi({
|
|
663
672
|
url: `${baseUrl.origin}/v1/credits`,
|
|
673
|
+
validateUrl: false,
|
|
664
674
|
headers: this.config.headers ? await resolve(this.config.headers) : void 0,
|
|
665
675
|
successfulResponseHandler: createJsonResponseHandler(
|
|
666
676
|
gatewayCreditsResponseSchema
|
|
@@ -768,6 +778,7 @@ var GatewaySpendReport = class {
|
|
|
768
778
|
}
|
|
769
779
|
const { value } = await getFromApi2({
|
|
770
780
|
url: `${baseUrl.origin}/v1/report?${searchParams.toString()}`,
|
|
781
|
+
validateUrl: false,
|
|
771
782
|
headers: this.config.headers ? await resolve2(this.config.headers) : void 0,
|
|
772
783
|
successfulResponseHandler: createJsonResponseHandler2(
|
|
773
784
|
gatewaySpendReportResponseSchema
|
|
@@ -853,6 +864,7 @@ var GatewayGenerationInfoFetcher = class {
|
|
|
853
864
|
const baseUrl = new URL(this.config.baseURL);
|
|
854
865
|
const { value } = await getFromApi3({
|
|
855
866
|
url: `${baseUrl.origin}/v1/generation?id=${encodeURIComponent(params.id)}`,
|
|
867
|
+
validateUrl: false,
|
|
856
868
|
headers: this.config.headers ? await resolve3(this.config.headers) : void 0,
|
|
857
869
|
successfulResponseHandler: createJsonResponseHandler3(
|
|
858
870
|
gatewayGenerationInfoResponseSchema
|
|
@@ -1865,13 +1877,23 @@ var gatewaySpeechResponseSchema = z13.object({
|
|
|
1865
1877
|
});
|
|
1866
1878
|
|
|
1867
1879
|
// src/gateway-transcription-model.ts
|
|
1880
|
+
import {
|
|
1881
|
+
getErrorMessage
|
|
1882
|
+
} from "@ai-sdk/provider";
|
|
1868
1883
|
import {
|
|
1869
1884
|
combineHeaders as combineHeaders7,
|
|
1885
|
+
convertBase64ToUint8Array,
|
|
1870
1886
|
convertUint8ArrayToBase64 as convertUint8ArrayToBase643,
|
|
1871
1887
|
createJsonErrorResponseHandler as createJsonErrorResponseHandler10,
|
|
1872
1888
|
createJsonResponseHandler as createJsonResponseHandler9,
|
|
1889
|
+
connectToWebSocket,
|
|
1890
|
+
normalizeHeaders,
|
|
1891
|
+
experimental_parseTranscriptionStreamPart as parseTranscriptionStreamPart,
|
|
1873
1892
|
postJsonToApi as postJsonToApi7,
|
|
1874
|
-
resolve as resolve10
|
|
1893
|
+
resolve as resolve10,
|
|
1894
|
+
EXPERIMENTAL_TRANSCRIPTION_STREAM_AUDIO_DONE_FRAME_TYPE as TRANSCRIPTION_STREAM_AUDIO_DONE_FRAME_TYPE,
|
|
1895
|
+
waitForWebSocketBufferDrain,
|
|
1896
|
+
EXPERIMENTAL_TRANSCRIPTION_STREAM_START_FRAME_TYPE as TRANSCRIPTION_STREAM_START_FRAME_TYPE
|
|
1875
1897
|
} from "@ai-sdk/provider-utils";
|
|
1876
1898
|
import { z as z14 } from "zod/v4";
|
|
1877
1899
|
var GatewayTranscriptionModel = class {
|
|
@@ -1941,6 +1963,41 @@ var GatewayTranscriptionModel = class {
|
|
|
1941
1963
|
);
|
|
1942
1964
|
}
|
|
1943
1965
|
}
|
|
1966
|
+
async doStream(options) {
|
|
1967
|
+
var _a11, _b11, _c, _d, _e;
|
|
1968
|
+
const currentDate = (_c = (_b11 = (_a11 = this.config._internal) == null ? void 0 : _a11.currentDate) == null ? void 0 : _b11.call(_a11)) != null ? _c : /* @__PURE__ */ new Date();
|
|
1969
|
+
const headers = combineHeaders7(
|
|
1970
|
+
await resolve10((_d = this.config.headers) != null ? _d : {}),
|
|
1971
|
+
(_e = options.headers) != null ? _e : {},
|
|
1972
|
+
this.getModelConfigHeaders(),
|
|
1973
|
+
await resolve10(this.config.o11yHeaders)
|
|
1974
|
+
);
|
|
1975
|
+
const authMethod = await parseAuthMethod(headers);
|
|
1976
|
+
const startFrame = {
|
|
1977
|
+
type: TRANSCRIPTION_STREAM_START_FRAME_TYPE,
|
|
1978
|
+
inputAudioFormat: options.inputAudioFormat,
|
|
1979
|
+
...options.providerOptions != null && {
|
|
1980
|
+
providerOptions: options.providerOptions
|
|
1981
|
+
},
|
|
1982
|
+
...options.includeRawChunks != null && {
|
|
1983
|
+
includeRawChunks: options.includeRawChunks
|
|
1984
|
+
}
|
|
1985
|
+
};
|
|
1986
|
+
return {
|
|
1987
|
+
stream: createGatewayTranscriptionStream({
|
|
1988
|
+
webSocket: this.config.webSocket,
|
|
1989
|
+
url: toGatewayTranscriptionUrl(this.config.baseURL, this.modelId),
|
|
1990
|
+
protocols: getProtocolsFromHeaders(headers),
|
|
1991
|
+
headers,
|
|
1992
|
+
startFrame,
|
|
1993
|
+
audio: options.audio,
|
|
1994
|
+
abortSignal: options.abortSignal,
|
|
1995
|
+
authMethod
|
|
1996
|
+
}),
|
|
1997
|
+
request: { body: startFrame },
|
|
1998
|
+
response: { timestamp: currentDate, modelId: this.modelId }
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
1944
2001
|
getUrl() {
|
|
1945
2002
|
return `${this.config.baseURL}/transcription-model`;
|
|
1946
2003
|
}
|
|
@@ -1951,6 +2008,163 @@ var GatewayTranscriptionModel = class {
|
|
|
1951
2008
|
};
|
|
1952
2009
|
}
|
|
1953
2010
|
};
|
|
2011
|
+
function toGatewayTranscriptionUrl(baseURL, modelId) {
|
|
2012
|
+
const url = new URL(`${baseURL.replace(/^http/, "ws")}/transcription-model`);
|
|
2013
|
+
url.searchParams.set("ai-model-id", modelId);
|
|
2014
|
+
return url.toString();
|
|
2015
|
+
}
|
|
2016
|
+
function getProtocolsFromHeaders(headers) {
|
|
2017
|
+
const normalizedHeaders = normalizeHeaders(headers);
|
|
2018
|
+
const authorization = normalizedHeaders.authorization;
|
|
2019
|
+
const token = (authorization == null ? void 0 : authorization.startsWith("Bearer ")) ? authorization.slice("Bearer ".length) : void 0;
|
|
2020
|
+
return token == null ? [GATEWAY_TRANSCRIPTION_SUBPROTOCOL] : getGatewayTranscriptionProtocols(token, {
|
|
2021
|
+
teamIdOrSlug: normalizedHeaders[VERCEL_AI_GATEWAY_TEAM_HEADER]
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
var MAX_AUDIO_FRAME_BYTES = 64 * 1024;
|
|
2025
|
+
function createGatewayTranscriptionStream({
|
|
2026
|
+
webSocket,
|
|
2027
|
+
url,
|
|
2028
|
+
protocols,
|
|
2029
|
+
headers,
|
|
2030
|
+
startFrame,
|
|
2031
|
+
audio,
|
|
2032
|
+
abortSignal,
|
|
2033
|
+
authMethod
|
|
2034
|
+
}) {
|
|
2035
|
+
let finished = false;
|
|
2036
|
+
let cleanup = () => {
|
|
2037
|
+
};
|
|
2038
|
+
return new ReadableStream({
|
|
2039
|
+
start: (controller) => {
|
|
2040
|
+
let audioReader;
|
|
2041
|
+
let hasServerErrorPart = false;
|
|
2042
|
+
let lastServerError;
|
|
2043
|
+
let audioStopped = false;
|
|
2044
|
+
let connection;
|
|
2045
|
+
cleanup = (closeCode) => {
|
|
2046
|
+
if (audioReader != null) {
|
|
2047
|
+
void audioReader.cancel().catch(() => {
|
|
2048
|
+
});
|
|
2049
|
+
} else {
|
|
2050
|
+
void audio.cancel().catch(() => {
|
|
2051
|
+
});
|
|
2052
|
+
}
|
|
2053
|
+
connection == null ? void 0 : connection.close(closeCode);
|
|
2054
|
+
};
|
|
2055
|
+
const stopAudio = () => {
|
|
2056
|
+
audioStopped = true;
|
|
2057
|
+
if (audioReader != null) {
|
|
2058
|
+
void audioReader.cancel().catch(() => {
|
|
2059
|
+
});
|
|
2060
|
+
audioReader = void 0;
|
|
2061
|
+
} else {
|
|
2062
|
+
void audio.cancel().catch(() => {
|
|
2063
|
+
});
|
|
2064
|
+
}
|
|
2065
|
+
};
|
|
2066
|
+
const finishWithError = (error) => {
|
|
2067
|
+
if (finished) return;
|
|
2068
|
+
finished = true;
|
|
2069
|
+
cleanup();
|
|
2070
|
+
void errorControllerWithGatewayError(controller, error, authMethod);
|
|
2071
|
+
};
|
|
2072
|
+
const sendAudio = async (socket) => {
|
|
2073
|
+
const reader = audio.getReader();
|
|
2074
|
+
audioReader = reader;
|
|
2075
|
+
try {
|
|
2076
|
+
while (true) {
|
|
2077
|
+
const { done, value } = await reader.read();
|
|
2078
|
+
if (done || finished) break;
|
|
2079
|
+
const bytes = typeof value === "string" ? convertBase64ToUint8Array(value) : value;
|
|
2080
|
+
for (let offset = 0; offset < bytes.length; offset += MAX_AUDIO_FRAME_BYTES) {
|
|
2081
|
+
if (finished) break;
|
|
2082
|
+
socket.send(
|
|
2083
|
+
bytes.subarray(offset, offset + MAX_AUDIO_FRAME_BYTES)
|
|
2084
|
+
);
|
|
2085
|
+
await waitForWebSocketBufferDrain(socket);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
} finally {
|
|
2089
|
+
reader.releaseLock();
|
|
2090
|
+
if (audioReader === reader) {
|
|
2091
|
+
audioReader = void 0;
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
if (!finished && !audioStopped) {
|
|
2095
|
+
socket.send(
|
|
2096
|
+
JSON.stringify({
|
|
2097
|
+
type: TRANSCRIPTION_STREAM_AUDIO_DONE_FRAME_TYPE
|
|
2098
|
+
})
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
};
|
|
2102
|
+
connection = connectToWebSocket({
|
|
2103
|
+
url,
|
|
2104
|
+
protocols,
|
|
2105
|
+
headers,
|
|
2106
|
+
webSocket,
|
|
2107
|
+
abortSignal,
|
|
2108
|
+
onAbort: (reason) => {
|
|
2109
|
+
if (finished) return;
|
|
2110
|
+
finished = true;
|
|
2111
|
+
cleanup();
|
|
2112
|
+
controller.error(reason);
|
|
2113
|
+
},
|
|
2114
|
+
onProcessingError: finishWithError,
|
|
2115
|
+
onOpen: (socket) => {
|
|
2116
|
+
socket.send(JSON.stringify(startFrame));
|
|
2117
|
+
void sendAudio(socket).catch(finishWithError);
|
|
2118
|
+
},
|
|
2119
|
+
// Server frames are envelope-serialized stream parts; the codec
|
|
2120
|
+
// handles parsing, unknown-part skipping, and timestamp revival.
|
|
2121
|
+
onMessageText: (text) => {
|
|
2122
|
+
if (finished) return;
|
|
2123
|
+
const part = parseTranscriptionStreamPart(text);
|
|
2124
|
+
if (part == null) return;
|
|
2125
|
+
if (part.type === "finish") {
|
|
2126
|
+
finished = true;
|
|
2127
|
+
controller.enqueue(part);
|
|
2128
|
+
controller.close();
|
|
2129
|
+
cleanup(1e3);
|
|
2130
|
+
return;
|
|
2131
|
+
}
|
|
2132
|
+
if (part.type === "error") {
|
|
2133
|
+
hasServerErrorPart = true;
|
|
2134
|
+
lastServerError = part.error;
|
|
2135
|
+
stopAudio();
|
|
2136
|
+
}
|
|
2137
|
+
controller.enqueue(part);
|
|
2138
|
+
},
|
|
2139
|
+
onSocketError: () => {
|
|
2140
|
+
finishWithError(
|
|
2141
|
+
new Error("Connection error on AI Gateway transcription stream")
|
|
2142
|
+
);
|
|
2143
|
+
},
|
|
2144
|
+
onClose: () => {
|
|
2145
|
+
if (hasServerErrorPart) {
|
|
2146
|
+
if (finished) return;
|
|
2147
|
+
void createErrorFromServerErrorPart(
|
|
2148
|
+
lastServerError,
|
|
2149
|
+
authMethod
|
|
2150
|
+
).then(finishWithError);
|
|
2151
|
+
return;
|
|
2152
|
+
}
|
|
2153
|
+
finishWithError(
|
|
2154
|
+
new Error(
|
|
2155
|
+
"AI Gateway transcription stream closed before a finish part was received"
|
|
2156
|
+
)
|
|
2157
|
+
);
|
|
2158
|
+
}
|
|
2159
|
+
});
|
|
2160
|
+
},
|
|
2161
|
+
cancel: () => {
|
|
2162
|
+
if (finished) return;
|
|
2163
|
+
finished = true;
|
|
2164
|
+
cleanup();
|
|
2165
|
+
}
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
1954
2168
|
var providerMetadataEntrySchema4 = z14.object({}).catchall(z14.unknown());
|
|
1955
2169
|
var gatewayTranscriptionWarningSchema = z14.discriminatedUnion("type", [
|
|
1956
2170
|
z14.object({
|
|
@@ -1987,6 +2201,36 @@ var gatewayTranscriptionResponseSchema = z14.object({
|
|
|
1987
2201
|
warnings: z14.array(gatewayTranscriptionWarningSchema).optional(),
|
|
1988
2202
|
providerMetadata: z14.record(z14.string(), providerMetadataEntrySchema4).optional()
|
|
1989
2203
|
});
|
|
2204
|
+
async function errorControllerWithGatewayError(controller, error, authMethod) {
|
|
2205
|
+
controller.error(await asGatewayError(error, authMethod));
|
|
2206
|
+
}
|
|
2207
|
+
function getServerErrorMessage(error) {
|
|
2208
|
+
if (error != null && typeof error === "object" && "message" in error && typeof error.message === "string") {
|
|
2209
|
+
return error.message;
|
|
2210
|
+
}
|
|
2211
|
+
return getErrorMessage(error);
|
|
2212
|
+
}
|
|
2213
|
+
var SERVER_ERROR_STATUS_CODES = {
|
|
2214
|
+
authentication_error: 401,
|
|
2215
|
+
failed_dependency: 424,
|
|
2216
|
+
forbidden: 403,
|
|
2217
|
+
internal_server_error: 500,
|
|
2218
|
+
invalid_request_error: 400,
|
|
2219
|
+
model_not_found: 404,
|
|
2220
|
+
rate_limit_exceeded: 429
|
|
2221
|
+
};
|
|
2222
|
+
async function createErrorFromServerErrorPart(error, authMethod) {
|
|
2223
|
+
if (typeof error === "object" && error != null && "message" in error && typeof error.message === "string" && "type" in error && typeof error.type === "string" && error.type in SERVER_ERROR_STATUS_CODES) {
|
|
2224
|
+
return createGatewayErrorFromResponse({
|
|
2225
|
+
response: { error: { message: error.message, type: error.type } },
|
|
2226
|
+
statusCode: SERVER_ERROR_STATUS_CODES[error.type],
|
|
2227
|
+
authMethod
|
|
2228
|
+
});
|
|
2229
|
+
}
|
|
2230
|
+
return new Error(
|
|
2231
|
+
`AI Gateway transcription stream failed: ${getServerErrorMessage(error)}`
|
|
2232
|
+
);
|
|
2233
|
+
}
|
|
1990
2234
|
|
|
1991
2235
|
// src/gateway-realtime-model.ts
|
|
1992
2236
|
var GatewayRealtimeModel = class {
|
|
@@ -2387,7 +2631,7 @@ async function getVercelRequestId() {
|
|
|
2387
2631
|
}
|
|
2388
2632
|
|
|
2389
2633
|
// src/version.ts
|
|
2390
|
-
var VERSION = true ? "4.0.
|
|
2634
|
+
var VERSION = true ? "4.0.19" : "0.0.0-test";
|
|
2391
2635
|
|
|
2392
2636
|
// src/gateway-provider.ts
|
|
2393
2637
|
var AI_GATEWAY_PROTOCOL_VERSION = "0.0.1";
|
|
@@ -2633,7 +2877,8 @@ function createGateway(options = {}) {
|
|
|
2633
2877
|
baseURL,
|
|
2634
2878
|
headers: getHeaders,
|
|
2635
2879
|
fetch: options.fetch,
|
|
2636
|
-
o11yHeaders: createO11yHeaders()
|
|
2880
|
+
o11yHeaders: createO11yHeaders(),
|
|
2881
|
+
webSocket: options.webSocket
|
|
2637
2882
|
});
|
|
2638
2883
|
};
|
|
2639
2884
|
provider.transcriptionModel = createTranscriptionModel;
|
|
@@ -2695,6 +2940,7 @@ export {
|
|
|
2695
2940
|
GATEWAY_AUTH_SUBPROTOCOL_PREFIX,
|
|
2696
2941
|
GATEWAY_REALTIME_SUBPROTOCOL,
|
|
2697
2942
|
GATEWAY_TEAM_SUBPROTOCOL_PREFIX,
|
|
2943
|
+
GATEWAY_TRANSCRIPTION_SUBPROTOCOL,
|
|
2698
2944
|
GatewayAuthenticationError,
|
|
2699
2945
|
GatewayError,
|
|
2700
2946
|
GatewayFailedDependencyError,
|
|
@@ -2710,6 +2956,7 @@ export {
|
|
|
2710
2956
|
gateway,
|
|
2711
2957
|
getGatewayRealtimeAuthToken,
|
|
2712
2958
|
getGatewayRealtimeProtocols,
|
|
2713
|
-
getGatewayRealtimeTeamIdOrSlug
|
|
2959
|
+
getGatewayRealtimeTeamIdOrSlug,
|
|
2960
|
+
getGatewayTranscriptionProtocols
|
|
2714
2961
|
};
|
|
2715
2962
|
//# sourceMappingURL=index.js.map
|