@maxceem/agw 0.6.4 → 0.7.1
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 +63 -15
- package/package.json +13 -2
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.7.1", wrangler: "4.96.0", upgradeFrom: ["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.7.1/gateway-0.7.1.tar.gz", sha256: "1b3ac4141c993b30bf1e90404dee7a21785a38b686c3f2562ec7b0c07fd4534d", manifest: "8455d531a2dc7df63af0fcbe1d8a181c3b6c74796e5f5a69cacf7890ca2dc42a" } };
|
|
10
10
|
|
|
11
11
|
// src/main.ts
|
|
12
12
|
import { Writable as Writable2 } from "node:stream";
|
|
@@ -14699,7 +14699,9 @@ var GATEWAY_DESCRIPTORS = {
|
|
|
14699
14699
|
{ key: "accountId", label: "Cloudflare Account ID" },
|
|
14700
14700
|
{ key: "gatewayId", label: "Cloudflare Gateway ID" }
|
|
14701
14701
|
],
|
|
14702
|
-
routes: CF_AIG_ROUTES
|
|
14702
|
+
routes: CF_AIG_ROUTES,
|
|
14703
|
+
// A proxy in front of the provider's own API: the body is the provider's.
|
|
14704
|
+
relaysProviderResponses: true
|
|
14703
14705
|
},
|
|
14704
14706
|
vercel: {
|
|
14705
14707
|
label: "Vercel AI Gateway",
|
|
@@ -14715,7 +14717,11 @@ var GATEWAY_DESCRIPTORS = {
|
|
|
14715
14717
|
description: "Vercel's origin is fixed in adapter code, so it has no configuration of its own."
|
|
14716
14718
|
}),
|
|
14717
14719
|
connectionFields: [],
|
|
14718
|
-
routes: VERCEL_ROUTES
|
|
14720
|
+
routes: VERCEL_ROUTES,
|
|
14721
|
+
// Vercel answers through its own client APIs, translating between them and
|
|
14722
|
+
// the serving provider's protocol, so a provider's own fields are not part
|
|
14723
|
+
// of the contract.
|
|
14724
|
+
relaysProviderResponses: false
|
|
14719
14725
|
}
|
|
14720
14726
|
};
|
|
14721
14727
|
var GATEWAY_TYPES = Object.keys(GATEWAY_DESCRIPTORS);
|
|
@@ -14767,9 +14773,18 @@ function reportedByok(root, usage2) {
|
|
|
14767
14773
|
return upstreamInferenceCost(usage2) !== null;
|
|
14768
14774
|
}
|
|
14769
14775
|
var OPENROUTER_COST_REPORT = {
|
|
14776
|
+
// Only chat completions carry `usage.cost`, which is why it is the only
|
|
14777
|
+
// style the provider type offers at all.
|
|
14778
|
+
styles: ["chat_completions"],
|
|
14770
14779
|
// Which host actually served a request is opt-in per request; without this
|
|
14771
14780
|
// header the response names no serving provider at all.
|
|
14772
14781
|
requestHeaders: { "x-openrouter-metadata": "enabled" },
|
|
14782
|
+
// `credentialSource` is deliberately not required: it is a claim that is
|
|
14783
|
+
// simply absent on a non-BYOK request, so waiting for it would mean walking
|
|
14784
|
+
// every chunk of every stream. The response that carries it carries the cost
|
|
14785
|
+
// too.
|
|
14786
|
+
settled: (report) => report.costUsd !== null && report.servedProvider !== null && report.servedModel !== null,
|
|
14787
|
+
readsCredentialSource: true,
|
|
14773
14788
|
read(root, report) {
|
|
14774
14789
|
let said = false;
|
|
14775
14790
|
const usage2 = asRecord(root.usage);
|
|
@@ -14801,6 +14816,23 @@ var OPENROUTER_COST_REPORT = {
|
|
|
14801
14816
|
return said;
|
|
14802
14817
|
}
|
|
14803
14818
|
};
|
|
14819
|
+
var XAI_TICKS_PER_USD = 1e10;
|
|
14820
|
+
var XAI_COST_REPORT = {
|
|
14821
|
+
// Images and videos are provider-native operations, `other` to this gateway.
|
|
14822
|
+
// Its Anthropic-compatible Messages API and `v1/stt` are not documented to
|
|
14823
|
+
// report a cost, so they keep billing on the catalog.
|
|
14824
|
+
styles: ["chat_completions", "responses", "other"],
|
|
14825
|
+
settled: (report) => report.costUsd !== null,
|
|
14826
|
+
readsCredentialSource: false,
|
|
14827
|
+
read(root, report) {
|
|
14828
|
+
if (report.costUsd !== null) return false;
|
|
14829
|
+
const usage2 = asRecord(root.usage) ?? asRecord(asRecord(root.response)?.usage);
|
|
14830
|
+
const ticks = usage2 ? finiteNumber(usage2.cost_in_usd_ticks) : null;
|
|
14831
|
+
if (ticks === null || ticks < 0) return false;
|
|
14832
|
+
report.costUsd = ticks / XAI_TICKS_PER_USD;
|
|
14833
|
+
return true;
|
|
14834
|
+
}
|
|
14835
|
+
};
|
|
14804
14836
|
|
|
14805
14837
|
// ../src/shared/providers.ts
|
|
14806
14838
|
var PROVIDER_DESCRIPTORS = {
|
|
@@ -14844,6 +14876,11 @@ var PROVIDER_DESCRIPTORS = {
|
|
|
14844
14876
|
// Native provider paths: xAI transcribes at `v1/stt`, where OpenAI serves
|
|
14845
14877
|
// `v1/audio/transcriptions`.
|
|
14846
14878
|
endpointPaths: { responses: "v1/responses", audio_transcription: "v1/stt" },
|
|
14879
|
+
// Every Chat Completions, Responses, image and video answer carries
|
|
14880
|
+
// `usage.cost_in_usd_ticks`, what xAI actually billed for it. An image
|
|
14881
|
+
// reports nothing else, so this is the only way to bill one; on the token
|
|
14882
|
+
// APIs it beats the catalog's estimate, which knows no discounts.
|
|
14883
|
+
costReport: XAI_COST_REPORT,
|
|
14847
14884
|
modelAuthor: "xAI"
|
|
14848
14885
|
},
|
|
14849
14886
|
gemini: {
|
|
@@ -15015,9 +15052,6 @@ var PROVIDER_TYPES = Object.keys(PROVIDER_DESCRIPTORS);
|
|
|
15015
15052
|
function providerDescriptor(type) {
|
|
15016
15053
|
return PROVIDER_DESCRIPTORS[type];
|
|
15017
15054
|
}
|
|
15018
|
-
function isProviderType(value) {
|
|
15019
|
-
return typeof value === "string" && Object.hasOwn(PROVIDER_DESCRIPTORS, value);
|
|
15020
|
-
}
|
|
15021
15055
|
var PROVIDER_CREDENTIAL_HEADERS = [
|
|
15022
15056
|
...new Set(
|
|
15023
15057
|
PROVIDER_TYPES.map((type) => providerDescriptor(type).auth.header.toLowerCase())
|
|
@@ -15033,10 +15067,6 @@ function providerCapability(provider) {
|
|
|
15033
15067
|
var ENDPOINT_PROVIDER_TYPES = PROVIDER_TYPES.filter(
|
|
15034
15068
|
(type) => providerCapability(type).endpointStyles.length > 0
|
|
15035
15069
|
);
|
|
15036
|
-
function reportsCost(type) {
|
|
15037
|
-
return isProviderType(type) && providerDescriptor(type).costReport !== void 0;
|
|
15038
|
-
}
|
|
15039
|
-
var COST_REPORTING_PROVIDER_TYPES = PROVIDER_TYPES.filter(reportsCost);
|
|
15040
15070
|
|
|
15041
15071
|
// ../src/shared/app-status.ts
|
|
15042
15072
|
var APP_STATUSES = ["active", "disabled"];
|
|
@@ -17849,7 +17879,7 @@ var UsageRepriceResponseSchema = external_exports.object({
|
|
|
17849
17879
|
description: "Matched events that carried no readable usage, and so were repriced to the zero their zero counts imply while keeping whatever cost_source they had. A non-zero number means the month contains spend nothing could meter, which repricing cannot fix and must not appear to have fixed."
|
|
17850
17880
|
}),
|
|
17851
17881
|
unpriced_events: external_exports.number().int().meta({
|
|
17852
|
-
description: "Dry-run only: matched events whose serving instance can no longer price them."
|
|
17882
|
+
description: "Dry-run only: matched events whose serving instance can no longer price them, or that predate the modality breakdown their model's price depends on."
|
|
17853
17883
|
}),
|
|
17854
17884
|
unpriced_cost_usd: external_exports.number(),
|
|
17855
17885
|
previous_cost_usd: external_exports.number(),
|
|
@@ -17859,10 +17889,25 @@ var UsageRepriceResponseSchema = external_exports.object({
|
|
|
17859
17889
|
var ModelPriceSchema = external_exports.object({
|
|
17860
17890
|
input: external_exports.number().optional(),
|
|
17861
17891
|
output: external_exports.number().optional(),
|
|
17892
|
+
image_input: external_exports.number().optional().meta({
|
|
17893
|
+
description: "USD per 1M image input tokens, where they are priced apart from text input."
|
|
17894
|
+
}),
|
|
17895
|
+
audio_input: external_exports.number().optional().meta({
|
|
17896
|
+
description: "USD per 1M audio input tokens, where they are priced apart from text input."
|
|
17897
|
+
}),
|
|
17898
|
+
video_input: external_exports.number().optional().meta({
|
|
17899
|
+
description: "USD per 1M video input tokens, where they are priced apart from text input."
|
|
17900
|
+
}),
|
|
17901
|
+
image_output: external_exports.number().optional().meta({
|
|
17902
|
+
description: "USD per 1M generated image tokens, where they cost more than text output."
|
|
17903
|
+
}),
|
|
17862
17904
|
cached_input: external_exports.number().optional(),
|
|
17863
17905
|
cache_write: external_exports.number().optional(),
|
|
17864
17906
|
per_minute: external_exports.number().optional(),
|
|
17865
17907
|
per_hour: external_exports.number().optional(),
|
|
17908
|
+
per_image: external_exports.number().optional().meta({
|
|
17909
|
+
description: "USD per generated image, for a model billed per image rather than per token."
|
|
17910
|
+
}),
|
|
17866
17911
|
long_context_threshold: external_exports.number().optional(),
|
|
17867
17912
|
long_input: external_exports.number().optional(),
|
|
17868
17913
|
long_output: external_exports.number().optional(),
|
|
@@ -19059,7 +19104,7 @@ var CATALOG = {
|
|
|
19059
19104
|
path: "/v1/cli/bootstrap",
|
|
19060
19105
|
tags: ["CLI"],
|
|
19061
19106
|
summary: "Initialize a recoverable CLI account",
|
|
19062
|
-
description: "Persist the random token before sending: its digest is the operation's id, and an identical retry returns the same account and protected credential during its exchange window. Cloud initialization is public and rate limited. Self-hosted initialization
|
|
19107
|
+
description: "Persist the random token before sending: its digest is the operation's id, and an identical retry returns the same account and protected credential during its exchange window. Cloud initialization is public and rate limited. Self-hosted initialization creates the deployment's single unclaimed account, and only for the token whose SHA-256 the deploying CLI stored as the Worker secret `CLI_BOOTSTRAP_TOKEN_DIGEST`; any other token, or a deployment without that secret, is refused with 403. It is not rate limited, because only the deploying CLI can pass it, and a limit would refuse that CLI retrying a deployment whose storage has not come up yet. All responses are no-store.",
|
|
19063
19108
|
security: "public",
|
|
19064
19109
|
request: CliBootstrapRequestSchema,
|
|
19065
19110
|
response: CliOperationSchema,
|
|
@@ -20308,7 +20353,7 @@ async function openBrowser(url2) {
|
|
|
20308
20353
|
}
|
|
20309
20354
|
|
|
20310
20355
|
// src/deployment.ts
|
|
20311
|
-
import { randomUUID } from "node:crypto";
|
|
20356
|
+
import { createHash as createHash4, randomUUID } from "node:crypto";
|
|
20312
20357
|
import { writeFile as writeFile3, unlink as unlink2 } from "node:fs/promises";
|
|
20313
20358
|
import { join as join4 } from "node:path";
|
|
20314
20359
|
|
|
@@ -20850,7 +20895,7 @@ async function configFile(ctx, journal, artifact) {
|
|
|
20850
20895
|
],
|
|
20851
20896
|
vars: {
|
|
20852
20897
|
...artifact.config.vars,
|
|
20853
|
-
|
|
20898
|
+
ALLOWED_REGISTRATION_EMAILS: "",
|
|
20854
20899
|
...journal.vars,
|
|
20855
20900
|
DEPLOYMENT_ID: journal.id
|
|
20856
20901
|
},
|
|
@@ -21201,7 +21246,10 @@ async function install(ctx, cf, journal, artifact, url2, domain2) {
|
|
|
21201
21246
|
});
|
|
21202
21247
|
const secrets = {
|
|
21203
21248
|
...journal.secrets,
|
|
21204
|
-
SECRET_VAULT_LOCAL_KEK_V1: await ctx.store.vaultKey(journal.id)
|
|
21249
|
+
SECRET_VAULT_LOCAL_KEK_V1: await ctx.store.vaultKey(journal.id),
|
|
21250
|
+
// The Worker creates its account only for the token this digest is of, so
|
|
21251
|
+
// the account is this CLI's however soon anyone else finds the address.
|
|
21252
|
+
CLI_BOOTSTRAP_TOKEN_DIGEST: createHash4("sha256").update(journal.bootstrap.token).digest("hex")
|
|
21205
21253
|
};
|
|
21206
21254
|
const secretPath = join4(file2.directory, "secrets.json");
|
|
21207
21255
|
await writeFile3(secretPath, JSON.stringify(secrets), {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maxceem/agw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
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": [
|
|
@@ -25,7 +25,18 @@
|
|
|
25
25
|
"directory": "cli"
|
|
26
26
|
},
|
|
27
27
|
"bugs": "https://github.com/maxceem/app-ai-gateway/issues",
|
|
28
|
-
"upgradeFrom": [
|
|
28
|
+
"upgradeFrom": [
|
|
29
|
+
"0.7.0",
|
|
30
|
+
"0.6.4",
|
|
31
|
+
"0.6.3",
|
|
32
|
+
"0.6.2",
|
|
33
|
+
"0.6.1",
|
|
34
|
+
"0.6.0",
|
|
35
|
+
"0.5.2",
|
|
36
|
+
"0.5.1",
|
|
37
|
+
"0.5.0",
|
|
38
|
+
"0.4.0"
|
|
39
|
+
],
|
|
29
40
|
"license": "Apache-2.0",
|
|
30
41
|
"bin": {
|
|
31
42
|
"agw": "dist/agw.mjs"
|