@maxceem/agw 0.9.3 → 0.10.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/dist/agw.mjs +205 -80
- package/package.json +2 -1
package/dist/agw.mjs
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// <define:__AGW_MANIFEST__>
|
|
9
|
-
var define_AGW_MANIFEST_default = { version: "0.
|
|
9
|
+
var define_AGW_MANIFEST_default = { version: "0.10.0", wrangler: "4.96.0", upgradeFrom: ["0.10.0", "0.9.3", "0.9.2", "0.9.1", "0.9.0", "0.8.3", "0.8.2", "0.8.1", "0.8.0", "0.7.2", "0.7.1", "0.7.0", "0.6.4", "0.6.3", "0.6.2", "0.6.1", "0.6.0", "0.5.2", "0.5.1", "0.5.0", "0.4.0"], release: { url: "https://github.com/maxceem/app-ai-gateway/releases/download/v0.10.0/gateway-0.10.0.tar.gz", sha256: "07e8f3d3f6c350db35e181062b87041633eae15bfa3cd0c8651c803a065e94e1", manifest: "3f44570ab891b8d386db59a708e43c5e838c7a2af08c8e95befc95cb1931f700" } };
|
|
10
10
|
|
|
11
11
|
// src/main.ts
|
|
12
12
|
import { Writable as Writable2 } from "node:stream";
|
|
@@ -14639,10 +14639,22 @@ var API_STYLES = [
|
|
|
14639
14639
|
"anthropic_messages",
|
|
14640
14640
|
"gemini_native",
|
|
14641
14641
|
"audio_transcription",
|
|
14642
|
+
"image_generation",
|
|
14643
|
+
"embeddings",
|
|
14644
|
+
"gemini_embedding",
|
|
14642
14645
|
/** A provider-native operation with no cross-provider contract of its own. */
|
|
14643
14646
|
"other"
|
|
14644
14647
|
];
|
|
14645
|
-
var ENDPOINT_API_STYLES = [
|
|
14648
|
+
var ENDPOINT_API_STYLES = [
|
|
14649
|
+
"responses",
|
|
14650
|
+
"chat_completions",
|
|
14651
|
+
"anthropic_messages",
|
|
14652
|
+
"gemini_native",
|
|
14653
|
+
"audio_transcription",
|
|
14654
|
+
"image_generation",
|
|
14655
|
+
"embeddings",
|
|
14656
|
+
"gemini_embedding"
|
|
14657
|
+
];
|
|
14646
14658
|
var OUTPUT_CLAMP_STYLES = [
|
|
14647
14659
|
"responses",
|
|
14648
14660
|
"chat_completions",
|
|
@@ -14662,7 +14674,11 @@ var VERCEL_API_STYLES = [
|
|
|
14662
14674
|
"chat_completions",
|
|
14663
14675
|
"anthropic_messages"
|
|
14664
14676
|
];
|
|
14665
|
-
var VERCEL_ENDPOINT_STYLES = [
|
|
14677
|
+
var VERCEL_ENDPOINT_STYLES = [
|
|
14678
|
+
"responses",
|
|
14679
|
+
"chat_completions",
|
|
14680
|
+
"anthropic_messages"
|
|
14681
|
+
];
|
|
14666
14682
|
function vercelRoute(modelPrefix) {
|
|
14667
14683
|
return {
|
|
14668
14684
|
modelPrefix,
|
|
@@ -14684,6 +14700,107 @@ var VERCEL_ROUTES = {
|
|
|
14684
14700
|
moonshot: vercelRoute("moonshotai/")
|
|
14685
14701
|
};
|
|
14686
14702
|
|
|
14703
|
+
// ../src/shared/records.ts
|
|
14704
|
+
function asRecord(value) {
|
|
14705
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
14706
|
+
}
|
|
14707
|
+
|
|
14708
|
+
// ../src/shared/model-kinds.ts
|
|
14709
|
+
var MODEL_KINDS = ["text", "image", "speech", "transcription", "embedding", "realtime"];
|
|
14710
|
+
var ENDPOINT_KINDS = [
|
|
14711
|
+
"text",
|
|
14712
|
+
"image",
|
|
14713
|
+
"speech",
|
|
14714
|
+
"transcription",
|
|
14715
|
+
"embedding"
|
|
14716
|
+
];
|
|
14717
|
+
|
|
14718
|
+
// ../src/shared/protocols.ts
|
|
14719
|
+
var PROTOCOLS = {
|
|
14720
|
+
audio_transcription: {
|
|
14721
|
+
style: "audio_transcription",
|
|
14722
|
+
path: /^(?:(?:v1|openai\/v1)\/audio\/transcriptions|v1\/stt)$/u,
|
|
14723
|
+
clamp: "none",
|
|
14724
|
+
usage: "audio",
|
|
14725
|
+
body: "multipart",
|
|
14726
|
+
kinds: ["transcription"]
|
|
14727
|
+
},
|
|
14728
|
+
chat_completions: {
|
|
14729
|
+
style: "chat_completions",
|
|
14730
|
+
path: /^(?:chat|v1\/chat|openai\/v1\/chat|inference\/v1\/chat|v1beta\/openai\/chat)\/completions$/u,
|
|
14731
|
+
clamp: "chat_completions",
|
|
14732
|
+
usage: "openai",
|
|
14733
|
+
body: "json",
|
|
14734
|
+
kinds: ["text"]
|
|
14735
|
+
},
|
|
14736
|
+
responses: {
|
|
14737
|
+
style: "responses",
|
|
14738
|
+
path: /^(?:v1|openai\/v1)\/responses$/u,
|
|
14739
|
+
clamp: "responses",
|
|
14740
|
+
usage: "openai",
|
|
14741
|
+
body: "json",
|
|
14742
|
+
kinds: ["text"]
|
|
14743
|
+
},
|
|
14744
|
+
gemini_native: {
|
|
14745
|
+
style: "gemini_native",
|
|
14746
|
+
path: /^v1(?:alpha|beta)?\/models\/(?<model>[^/]+):(?:generateContent|streamGenerateContent)$/du,
|
|
14747
|
+
clamp: "gemini_native",
|
|
14748
|
+
usage: "gemini",
|
|
14749
|
+
body: "json",
|
|
14750
|
+
// Image and speech models answer on `generateContent` like text ones.
|
|
14751
|
+
kinds: ["text", "image", "speech"],
|
|
14752
|
+
urlStreaming: { query: "alt=sse", from: ":generateContent", to: ":streamGenerateContent" }
|
|
14753
|
+
},
|
|
14754
|
+
anthropic_messages: {
|
|
14755
|
+
style: "anthropic_messages",
|
|
14756
|
+
path: /^v1\/messages$/u,
|
|
14757
|
+
clamp: "native",
|
|
14758
|
+
usage: "anthropic",
|
|
14759
|
+
body: "json",
|
|
14760
|
+
kinds: ["text"],
|
|
14761
|
+
requiredHeaders: { "anthropic-version": "2023-06-01" }
|
|
14762
|
+
},
|
|
14763
|
+
// Three APIs with no output to cap, each in the exact layouts the descriptors
|
|
14764
|
+
// name: an OpenAI-shaped image or embedding request under `v1/`, ModelArk's
|
|
14765
|
+
// bare `images/generations` and Fireworks' `inference/v1/`, and Gemini's own
|
|
14766
|
+
// embedding method, which like `generateContent` names its model in the URL.
|
|
14767
|
+
image_generation: {
|
|
14768
|
+
style: "image_generation",
|
|
14769
|
+
path: /^(?:v1\/)?images\/generations$/u,
|
|
14770
|
+
clamp: "none",
|
|
14771
|
+
usage: "openai",
|
|
14772
|
+
body: "json",
|
|
14773
|
+
kinds: ["image"]
|
|
14774
|
+
},
|
|
14775
|
+
embeddings: {
|
|
14776
|
+
style: "embeddings",
|
|
14777
|
+
path: /^(?:v1|inference\/v1)\/embeddings$/u,
|
|
14778
|
+
clamp: "none",
|
|
14779
|
+
usage: "openai",
|
|
14780
|
+
body: "json",
|
|
14781
|
+
kinds: ["embedding"]
|
|
14782
|
+
},
|
|
14783
|
+
gemini_embedding: {
|
|
14784
|
+
style: "gemini_embedding",
|
|
14785
|
+
path: /^v1(?:beta)?\/models\/(?<model>[^/]+):embedContent$/du,
|
|
14786
|
+
clamp: "none",
|
|
14787
|
+
usage: "gemini",
|
|
14788
|
+
body: "json",
|
|
14789
|
+
kinds: ["embedding"]
|
|
14790
|
+
},
|
|
14791
|
+
other: {
|
|
14792
|
+
style: "other",
|
|
14793
|
+
path: null,
|
|
14794
|
+
clamp: "native",
|
|
14795
|
+
usage: "unknown",
|
|
14796
|
+
body: "json",
|
|
14797
|
+
kinds: []
|
|
14798
|
+
}
|
|
14799
|
+
};
|
|
14800
|
+
var CLASSIFIED = Object.values(PROTOCOLS).filter(
|
|
14801
|
+
(protocol) => protocol.path !== null
|
|
14802
|
+
);
|
|
14803
|
+
|
|
14687
14804
|
// ../src/shared/gateways.ts
|
|
14688
14805
|
var GatewayIdSchema = external_exports.string().trim().min(1).max(100);
|
|
14689
14806
|
var GATEWAY_DESCRIPTORS = {
|
|
@@ -14738,11 +14855,6 @@ function gatewayTypeForCliName(name) {
|
|
|
14738
14855
|
return GATEWAY_TYPES.find((type) => GATEWAY_DESCRIPTORS[type].cliName === name);
|
|
14739
14856
|
}
|
|
14740
14857
|
|
|
14741
|
-
// ../src/shared/records.ts
|
|
14742
|
-
function asRecord(value) {
|
|
14743
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
14744
|
-
}
|
|
14745
|
-
|
|
14746
14858
|
// ../src/shared/cost-report.ts
|
|
14747
14859
|
function finiteNumber(value) {
|
|
14748
14860
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
@@ -14818,10 +14930,11 @@ var OPENROUTER_COST_REPORT = {
|
|
|
14818
14930
|
};
|
|
14819
14931
|
var XAI_TICKS_PER_USD = 1e10;
|
|
14820
14932
|
var XAI_COST_REPORT = {
|
|
14821
|
-
//
|
|
14822
|
-
//
|
|
14823
|
-
//
|
|
14824
|
-
|
|
14933
|
+
// Videos are provider-native operations, `other` to this gateway. Embeddings
|
|
14934
|
+
// keep the report they were judged by while they were `other` too. Its
|
|
14935
|
+
// Anthropic-compatible Messages API and `v1/stt` are not documented to report
|
|
14936
|
+
// a cost, so they keep billing on the catalog.
|
|
14937
|
+
styles: ["chat_completions", "responses", "image_generation", "embeddings", "other"],
|
|
14825
14938
|
settled: (report) => report.costUsd !== null,
|
|
14826
14939
|
readsCredentialSource: false,
|
|
14827
14940
|
read(root, report) {
|
|
@@ -14854,9 +14967,15 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
14854
14967
|
// `max_completion_tokens`; every other OpenAI-compatible service still
|
|
14855
14968
|
// reads the older field.
|
|
14856
14969
|
chatCompletionsCapField: "max_completion_tokens",
|
|
14857
|
-
//
|
|
14858
|
-
//
|
|
14859
|
-
|
|
14970
|
+
// Text through Responses alone: the `*-pro` and `*-codex` models serve no
|
|
14971
|
+
// other text API, so offering Chat Completions as well would offer them on
|
|
14972
|
+
// a path that refuses them.
|
|
14973
|
+
endpointPaths: {
|
|
14974
|
+
responses: "v1/responses",
|
|
14975
|
+
audio_transcription: "v1/audio/transcriptions",
|
|
14976
|
+
image_generation: "v1/images/generations",
|
|
14977
|
+
embeddings: "v1/embeddings"
|
|
14978
|
+
},
|
|
14860
14979
|
// Every JSON answer reports `usage`: tokens for the GPT transcription
|
|
14861
14980
|
// models, `{ type: "duration", seconds }` for whisper-1.
|
|
14862
14981
|
transcriptionFormats: { metered: ["json", "verbose_json", "diarized_json"], default: "json" },
|
|
@@ -14869,6 +14988,7 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
14869
14988
|
nativeClampStyle: "anthropic",
|
|
14870
14989
|
probePath: "v1/models",
|
|
14871
14990
|
examplePath: "v1/messages",
|
|
14991
|
+
endpointPaths: { anthropic_messages: "v1/messages" },
|
|
14872
14992
|
modelAuthor: "Anthropic",
|
|
14873
14993
|
// Anthropic refuses any request without a version header, probe included —
|
|
14874
14994
|
// and a probe has no client to send one for it. Deliberately not a
|
|
@@ -14892,8 +15012,13 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
14892
15012
|
],
|
|
14893
15013
|
probePath: "v1/models",
|
|
14894
15014
|
// Native provider paths: xAI transcribes at `v1/stt`, where OpenAI serves
|
|
14895
|
-
// `v1/audio/transcriptions`.
|
|
14896
|
-
|
|
15015
|
+
// `v1/audio/transcriptions`. Text through Responses alone, as on OpenAI:
|
|
15016
|
+
// the multi-agent models serve no other text API.
|
|
15017
|
+
endpointPaths: {
|
|
15018
|
+
responses: "v1/responses",
|
|
15019
|
+
audio_transcription: "v1/stt",
|
|
15020
|
+
image_generation: "v1/images/generations"
|
|
15021
|
+
},
|
|
14897
15022
|
// Every Chat Completions, Responses, image and video answer carries
|
|
14898
15023
|
// `usage.cost_in_usd_ticks`, what xAI actually billed for it. An image
|
|
14899
15024
|
// reports nothing else, so this is the only way to bill one; on the token
|
|
@@ -14917,6 +15042,11 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
14917
15042
|
// Native Gemini generation requests carry the model in the URL rather than
|
|
14918
15043
|
// in the JSON body, so there is no example path without a model.
|
|
14919
15044
|
examplePath: "v1beta/models/{model}:generateContent",
|
|
15045
|
+
// Text, image and speech models all answer on `generateContent`.
|
|
15046
|
+
endpointPaths: {
|
|
15047
|
+
gemini_native: "v1beta/models/{model}:generateContent",
|
|
15048
|
+
gemini_embedding: "v1beta/models/{model}:embedContent"
|
|
15049
|
+
},
|
|
14920
15050
|
modelAuthor: "Google"
|
|
14921
15051
|
},
|
|
14922
15052
|
perplexity: {
|
|
@@ -14935,6 +15065,7 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
14935
15065
|
],
|
|
14936
15066
|
// No `probePath`: Perplexity has no unmetered authenticated endpoint.
|
|
14937
15067
|
examplePath: "chat/completions",
|
|
15068
|
+
endpointPaths: { chat_completions: "chat/completions" },
|
|
14938
15069
|
modelAuthor: "Perplexity"
|
|
14939
15070
|
},
|
|
14940
15071
|
// OpenAI-compatible chat-completions services. `modelAuthor` is set only
|
|
@@ -14958,6 +15089,7 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
14958
15089
|
// DeepSeek's OpenAI base URL carries no `v1` segment.
|
|
14959
15090
|
probePath: "models",
|
|
14960
15091
|
examplePath: "chat/completions",
|
|
15092
|
+
endpointPaths: { chat_completions: "chat/completions" },
|
|
14961
15093
|
modelAuthor: "DeepSeek"
|
|
14962
15094
|
},
|
|
14963
15095
|
groq: {
|
|
@@ -14978,7 +15110,11 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
14978
15110
|
inferencePaths: ["openai/v1/audio/speech"],
|
|
14979
15111
|
// Groq's OpenAI-compatible surface is namespaced under `openai/`.
|
|
14980
15112
|
probePath: "openai/v1/models",
|
|
14981
|
-
examplePath: "openai/v1/chat/completions"
|
|
15113
|
+
examplePath: "openai/v1/chat/completions",
|
|
15114
|
+
endpointPaths: {
|
|
15115
|
+
chat_completions: "openai/v1/chat/completions",
|
|
15116
|
+
audio_transcription: "openai/v1/audio/transcriptions"
|
|
15117
|
+
}
|
|
14982
15118
|
},
|
|
14983
15119
|
mistral: {
|
|
14984
15120
|
label: "Mistral",
|
|
@@ -14992,6 +15128,7 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
14992
15128
|
"v1/audio/speech"
|
|
14993
15129
|
],
|
|
14994
15130
|
probePath: "v1/models",
|
|
15131
|
+
endpointPaths: { chat_completions: "v1/chat/completions" },
|
|
14995
15132
|
modelAuthor: "Mistral"
|
|
14996
15133
|
},
|
|
14997
15134
|
together: {
|
|
@@ -15016,7 +15153,8 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
15016
15153
|
"v1/audio/speech",
|
|
15017
15154
|
"v1/embeddings"
|
|
15018
15155
|
],
|
|
15019
|
-
probePath: "v1/models"
|
|
15156
|
+
probePath: "v1/models",
|
|
15157
|
+
endpointPaths: { chat_completions: "v1/chat/completions" }
|
|
15020
15158
|
},
|
|
15021
15159
|
fireworks: {
|
|
15022
15160
|
label: "Fireworks AI",
|
|
@@ -15035,7 +15173,8 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
15035
15173
|
// No `probePath`: its list-models call is `v1/accounts/{account}/models`,
|
|
15036
15174
|
// and the account id cannot be derived from the key. Nothing under
|
|
15037
15175
|
// `inference/v1/` is documented as a GET.
|
|
15038
|
-
examplePath: "inference/v1/chat/completions"
|
|
15176
|
+
examplePath: "inference/v1/chat/completions",
|
|
15177
|
+
endpointPaths: { chat_completions: "inference/v1/chat/completions" }
|
|
15039
15178
|
},
|
|
15040
15179
|
cerebras: {
|
|
15041
15180
|
label: "Cerebras",
|
|
@@ -15044,7 +15183,8 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
15044
15183
|
nativeClampStyle: "chat_completions",
|
|
15045
15184
|
// Legacy completions.
|
|
15046
15185
|
inferencePaths: [{ path: "v1/completions", clamp: "chat_completions" }],
|
|
15047
|
-
probePath: "v1/models"
|
|
15186
|
+
probePath: "v1/models",
|
|
15187
|
+
endpointPaths: { chat_completions: "v1/chat/completions" }
|
|
15048
15188
|
},
|
|
15049
15189
|
moonshot: {
|
|
15050
15190
|
label: "Moonshot AI",
|
|
@@ -15056,6 +15196,7 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
15056
15196
|
// The Anthropic-format API.
|
|
15057
15197
|
inferencePaths: [{ path: "anthropic/v1/messages", clamp: "anthropic" }],
|
|
15058
15198
|
probePath: "v1/models",
|
|
15199
|
+
endpointPaths: { chat_completions: "v1/chat/completions" },
|
|
15059
15200
|
modelAuthor: "Moonshot AI"
|
|
15060
15201
|
},
|
|
15061
15202
|
huggingface: {
|
|
@@ -15067,11 +15208,12 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
15067
15208
|
// catalog section for that reason; see `catalogPrice` in usage.ts.
|
|
15068
15209
|
directBaseUrl: "https://router.huggingface.co/",
|
|
15069
15210
|
auth: { header: "authorization", scheme: "Bearer " },
|
|
15070
|
-
nativeClampStyle: "chat_completions"
|
|
15211
|
+
nativeClampStyle: "chat_completions",
|
|
15071
15212
|
// No `probePath`: `router.huggingface.co/v1/models` is public — it answers
|
|
15072
15213
|
// 200 to a garbage token, so probing it would validate every key. The
|
|
15073
15214
|
// endpoint that does check a token lives on a different origin
|
|
15074
15215
|
// (`huggingface.co`), which a path under this base URL cannot express.
|
|
15216
|
+
endpointPaths: { chat_completions: "v1/chat/completions" }
|
|
15075
15217
|
},
|
|
15076
15218
|
baseten: {
|
|
15077
15219
|
label: "Baseten",
|
|
@@ -15080,7 +15222,8 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
15080
15222
|
directBaseUrl: "https://inference.baseten.co/",
|
|
15081
15223
|
auth: { header: "authorization", scheme: "Bearer " },
|
|
15082
15224
|
nativeClampStyle: "chat_completions",
|
|
15083
|
-
probePath: "v1/models"
|
|
15225
|
+
probePath: "v1/models",
|
|
15226
|
+
endpointPaths: { chat_completions: "v1/chat/completions" }
|
|
15084
15227
|
},
|
|
15085
15228
|
bytedance: {
|
|
15086
15229
|
label: "ByteDance Ark",
|
|
@@ -15102,7 +15245,8 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
15102
15245
|
// No `probePath`: ModelArk publishes no list-models call, and its own SDK
|
|
15103
15246
|
// has no models resource. It also authenticates before it routes, so every
|
|
15104
15247
|
// path answers the same 401 and a probe would prove nothing about the key.
|
|
15105
|
-
examplePath: "chat/completions"
|
|
15248
|
+
examplePath: "chat/completions",
|
|
15249
|
+
endpointPaths: { chat_completions: "chat/completions", image_generation: "images/generations" }
|
|
15106
15250
|
},
|
|
15107
15251
|
openrouter: {
|
|
15108
15252
|
label: "OpenRouter",
|
|
@@ -15132,6 +15276,7 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
15132
15276
|
// every lab. The declaration owns the parsing and the header that asks for
|
|
15133
15277
|
// the routing metadata — see `src/shared/cost-report.ts`.
|
|
15134
15278
|
costReport: OPENROUTER_COST_REPORT,
|
|
15279
|
+
endpointPaths: { chat_completions: "v1/chat/completions" },
|
|
15135
15280
|
// No `modelAuthor`: an aggregator serves everyone's models, and the slug
|
|
15136
15281
|
// namespace answers per model instead.
|
|
15137
15282
|
authorNamespacedModels: true
|
|
@@ -15358,12 +15503,33 @@ var EndpointTargetSchema = external_exports.object({
|
|
|
15358
15503
|
provider: SlugSchema,
|
|
15359
15504
|
model: external_exports.string().min(1)
|
|
15360
15505
|
});
|
|
15506
|
+
function endpointStyleKinds(style2) {
|
|
15507
|
+
return ENDPOINT_KINDS.filter((kind) => PROTOCOLS[style2].kinds.includes(kind));
|
|
15508
|
+
}
|
|
15509
|
+
function endpointKind(endpoint) {
|
|
15510
|
+
return endpoint.kind ?? endpointStyleKinds(endpoint.api_style)[0] ?? "text";
|
|
15511
|
+
}
|
|
15361
15512
|
var EndpointSchema = EndpointTargetSchema.extend({
|
|
15513
|
+
kind: external_exports.enum(ENDPOINT_KINDS).optional().meta({
|
|
15514
|
+
description: "What the endpoint does, which decides the models it may serve: text, image, speech (text to speech), transcription (speech to text) or embedding. Must be a kind its api_style carries; defaults to the first of them (text for gemini_native). Filled in on every parsed configuration."
|
|
15515
|
+
}),
|
|
15362
15516
|
api_style: external_exports.enum(ENDPOINT_API_STYLES),
|
|
15363
15517
|
params: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
15364
15518
|
max_output_tokens: external_exports.number().int().positive().optional(),
|
|
15365
15519
|
fallback: external_exports.array(EndpointTargetSchema).optional()
|
|
15366
|
-
}).strict()
|
|
15520
|
+
}).strict().superRefine((endpoint, context) => {
|
|
15521
|
+
const kinds = endpointStyleKinds(endpoint.api_style);
|
|
15522
|
+
if (endpoint.kind !== void 0 && !kinds.includes(endpoint.kind)) {
|
|
15523
|
+
context.addIssue({
|
|
15524
|
+
code: "custom",
|
|
15525
|
+
path: ["kind"],
|
|
15526
|
+
message: `cannot be ${endpoint.kind}: a ${endpoint.api_style} endpoint serves ${new Intl.ListFormat("en", { type: "disjunction" }).format(kinds)}`
|
|
15527
|
+
});
|
|
15528
|
+
}
|
|
15529
|
+
}).overwrite((endpoint) => {
|
|
15530
|
+
endpoint.kind = endpointKind(endpoint);
|
|
15531
|
+
return endpoint;
|
|
15532
|
+
});
|
|
15367
15533
|
var LimitScopeSchema = external_exports.object({
|
|
15368
15534
|
requests: external_exports.object({
|
|
15369
15535
|
per_minute: NullableRequestLimit,
|
|
@@ -16856,62 +17022,13 @@ var DEFAULT_INFERENCE_PATHS = new Map(
|
|
|
16856
17022
|
])
|
|
16857
17023
|
);
|
|
16858
17024
|
|
|
16859
|
-
// ../src/shared/protocols.ts
|
|
16860
|
-
var PROTOCOLS = {
|
|
16861
|
-
audio_transcription: {
|
|
16862
|
-
style: "audio_transcription",
|
|
16863
|
-
path: /^(?:(?:v1|openai\/v1)\/audio\/transcriptions|v1\/stt)$/u,
|
|
16864
|
-
clamp: "none",
|
|
16865
|
-
usage: "audio",
|
|
16866
|
-
body: "multipart"
|
|
16867
|
-
},
|
|
16868
|
-
chat_completions: {
|
|
16869
|
-
style: "chat_completions",
|
|
16870
|
-
path: /^(?:chat|v1\/chat|openai\/v1\/chat|inference\/v1\/chat|v1beta\/openai\/chat)\/completions$/u,
|
|
16871
|
-
clamp: "chat_completions",
|
|
16872
|
-
usage: "openai",
|
|
16873
|
-
body: "json"
|
|
16874
|
-
},
|
|
16875
|
-
responses: {
|
|
16876
|
-
style: "responses",
|
|
16877
|
-
path: /^(?:v1|openai\/v1)\/responses$/u,
|
|
16878
|
-
clamp: "responses",
|
|
16879
|
-
usage: "openai",
|
|
16880
|
-
body: "json"
|
|
16881
|
-
},
|
|
16882
|
-
gemini_native: {
|
|
16883
|
-
style: "gemini_native",
|
|
16884
|
-
path: /^v1(?:alpha|beta)?\/models\/(?<model>[^/]+):(?:generateContent|streamGenerateContent)$/du,
|
|
16885
|
-
clamp: "gemini_native",
|
|
16886
|
-
usage: "gemini",
|
|
16887
|
-
body: "json"
|
|
16888
|
-
},
|
|
16889
|
-
anthropic_messages: {
|
|
16890
|
-
style: "anthropic_messages",
|
|
16891
|
-
path: /^v1\/messages$/u,
|
|
16892
|
-
clamp: "native",
|
|
16893
|
-
usage: "anthropic",
|
|
16894
|
-
body: "json"
|
|
16895
|
-
},
|
|
16896
|
-
other: {
|
|
16897
|
-
style: "other",
|
|
16898
|
-
path: null,
|
|
16899
|
-
clamp: "native",
|
|
16900
|
-
usage: "unknown",
|
|
16901
|
-
body: "json"
|
|
16902
|
-
}
|
|
16903
|
-
};
|
|
16904
|
-
var CLASSIFIED = Object.values(PROTOCOLS).filter(
|
|
16905
|
-
(protocol) => protocol.path !== null
|
|
16906
|
-
);
|
|
16907
|
-
|
|
16908
17025
|
// ../src/shared/first-request.ts
|
|
16909
17026
|
var PROVIDER_PLACEHOLDER = "PROVIDER_SLUG";
|
|
16910
17027
|
var MODEL_PLACEHOLDER = "MODEL";
|
|
16911
17028
|
var BODY_PLACEHOLDER = "REQUEST_BODY";
|
|
16912
17029
|
var EXAMPLE_GAP_NOTES = {
|
|
16913
17030
|
provider: `No provider is configured yet, so ${PROVIDER_PLACEHOLDER} stands in for one. Add a provider key, then use its slug.`,
|
|
16914
|
-
model: `No priced model was found for this provider, so ${MODEL_PLACEHOLDER} stands in for one. Use a model the provider serves.`,
|
|
17031
|
+
model: `No priced model this request can use was found for this provider, so ${MODEL_PLACEHOLDER} stands in for one. Use a model the provider serves.`,
|
|
16915
17032
|
body: `This app allows no path whose request shape is known here, so ${BODY_PLACEHOLDER} stands in for the body the provider documents.`
|
|
16916
17033
|
};
|
|
16917
17034
|
function shellQuote(value) {
|
|
@@ -17131,7 +17248,7 @@ ${snippet}`;
|
|
|
17131
17248
|
...snippet ? { snippet } : {},
|
|
17132
17249
|
app: app2,
|
|
17133
17250
|
...key ? { applicationKey: key } : {},
|
|
17134
|
-
guidance: doc.config.authentication.type === "apple_app_attest" ? `Add https://github.com/maxceem/app-ai-gateway-swift from 1.
|
|
17251
|
+
guidance: doc.config.authentication.type === "apple_app_attest" ? `Add https://github.com/maxceem/app-ai-gateway-swift from 1.6.0, enable App Attest, and test on a supported physical device. Run agw app snippet ${app2.id} --provider <slug> for integration code. Production releases should use production-only App Attest.` : `Store the generated key on your server; never embed it in a mobile application. Run agw app snippet ${app2.id} for this request again.`
|
|
17135
17252
|
};
|
|
17136
17253
|
}
|
|
17137
17254
|
}
|
|
@@ -18108,6 +18225,9 @@ var UsageRepriceResponseSchema = external_exports.object({
|
|
|
18108
18225
|
delta_usd: external_exports.number()
|
|
18109
18226
|
});
|
|
18110
18227
|
var ModelPriceSchema = external_exports.object({
|
|
18228
|
+
kind: external_exports.enum(MODEL_KINDS).meta({
|
|
18229
|
+
description: "What the model does: text, image (generation), speech (text to speech), transcription (speech to text), embedding, or realtime (served only over a realtime session). A custom endpoint serves models of its own kind only."
|
|
18230
|
+
}),
|
|
18111
18231
|
input: external_exports.number().optional(),
|
|
18112
18232
|
output: external_exports.number().optional(),
|
|
18113
18233
|
image_input: external_exports.number().optional().meta({
|
|
@@ -18485,8 +18605,8 @@ var SignInRequestSchema = external_exports.object({ email: external_exports.emai
|
|
|
18485
18605
|
var ProviderNativeBodySchema = external_exports.record(external_exports.string(), external_exports.unknown()).meta({
|
|
18486
18606
|
description: "Provider-native JSON request. Consult the selected provider's API reference for the exact shape."
|
|
18487
18607
|
});
|
|
18488
|
-
var
|
|
18489
|
-
description: "OpenAI Responses
|
|
18608
|
+
var EndpointJsonBodySchema = external_exports.record(external_exports.string(), external_exports.unknown()).meta({
|
|
18609
|
+
description: "The JSON body the endpoint's api_style takes: an OpenAI Responses, Chat Completions, image generation or embeddings body, an Anthropic Messages body, or a Gemini generateContent or embedContent body. The gateway sets the configured model (in the body, or in the URL for the Gemini styles) and deep-merges the configured params."
|
|
18490
18610
|
});
|
|
18491
18611
|
var TranscriptionStyleBodySchema = external_exports.object({
|
|
18492
18612
|
file: external_exports.string().meta({ format: "binary" }),
|
|
@@ -18674,16 +18794,21 @@ var CATALOG = {
|
|
|
18674
18794
|
path: "/v1/apps/{app}/endpoints/{slug}",
|
|
18675
18795
|
tags: ["Custom endpoints"],
|
|
18676
18796
|
summary: "Call a server-configured custom endpoint",
|
|
18677
|
-
description: "The endpoint's provider, model, fixed parameters, output cap, and fallback chain come from the application configuration, so you can change models without shipping a client release.
|
|
18797
|
+
description: "The endpoint's provider, model, fixed parameters, output cap, and fallback chain come from the application configuration, so you can change models without shipping a client release. The body is the one the endpoint's api_style takes, without a model: JSON for every style but audio_transcription, which takes an OpenAI audio transcription multipart body. A gemini_native endpoint streams when the request URL carries alt=sse, as Gemini's own API does; every other style streams as its body asks. The successful response keeps the serving provider's native format and streaming behaviour.",
|
|
18678
18798
|
security: "gateway",
|
|
18679
18799
|
params: {
|
|
18680
18800
|
app: { example: "my-app" },
|
|
18681
18801
|
slug: { example: "chat", pattern: /^[a-z0-9-]{1,64}$/ }
|
|
18682
18802
|
},
|
|
18803
|
+
query: external_exports.object({
|
|
18804
|
+
alt: external_exports.literal("sse").optional().meta({
|
|
18805
|
+
description: "gemini_native endpoints only: `sse` streams the response as server-sent events, as Gemini's own API does. Never forwarded upstream."
|
|
18806
|
+
})
|
|
18807
|
+
}),
|
|
18683
18808
|
headers: GatewayClientHeadersSchema,
|
|
18684
18809
|
request: {
|
|
18685
18810
|
content: {
|
|
18686
|
-
"application/json":
|
|
18811
|
+
"application/json": EndpointJsonBodySchema,
|
|
18687
18812
|
"multipart/form-data": TranscriptionStyleBodySchema
|
|
18688
18813
|
}
|
|
18689
18814
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maxceem/agw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Manage App AI Gateway from a terminal or coding agent: providers, iOS and server apps, usage, and self-hosted deployment on Cloudflare",
|
|
6
6
|
"keywords": [
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"bugs": "https://github.com/maxceem/app-ai-gateway/issues",
|
|
28
28
|
"upgradeFrom": [
|
|
29
|
+
"0.9.3",
|
|
29
30
|
"0.9.2",
|
|
30
31
|
"0.9.1",
|
|
31
32
|
"0.9.0",
|