omnigateway 0.7.2 → 0.7.3

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 (3) hide show
  1. package/bin/omni.js +44 -27
  2. package/gateway.js +52 -31
  3. package/package.json +1 -1
package/bin/omni.js CHANGED
@@ -17877,6 +17877,9 @@ function codecAdapter(id, capabilities2, codec2, origins) {
17877
17877
  };
17878
17878
  }
17879
17879
 
17880
+ // packages/providers/src/body.ts
17881
+ import { createHash } from "crypto";
17882
+
17880
17883
  // packages/providers/src/headers.ts
17881
17884
  var SAFE = /^[\x20-\x7E]{1,200}$/;
17882
17885
  function env(name, fallback) {
@@ -17932,14 +17935,14 @@ function mergeHeaders(base, overrides) {
17932
17935
 
17933
17936
  // packages/providers/src/anthropic/profile.ts
17934
17937
  var host = stainlessHost(process.platform, process.arch);
17935
- var ANTHROPIC_CLI_VERSION = env("OMNI_ANTHROPIC_CLI_VERSION", "2.1.219");
17938
+ var ANTHROPIC_CLI_VERSION = env("OMNI_ANTHROPIC_CLI_VERSION", "2.1.258");
17936
17939
  var anthropicProfile = {
17937
17940
  headers: [
17938
17941
  ["User-Agent", env("OMNI_UA_ANTHROPIC", `claude-cli/${ANTHROPIC_CLI_VERSION} (external, cli)`)],
17939
17942
  ["x-app", "cli"],
17940
17943
  ["anthropic-dangerous-direct-browser-access", "true"],
17941
17944
  ["X-Stainless-Lang", "js"],
17942
- ["X-Stainless-Package-Version", env("OMNI_ANTHROPIC_STAINLESS_PACKAGE_VERSION", "0.94.0")],
17945
+ ["X-Stainless-Package-Version", env("OMNI_ANTHROPIC_STAINLESS_PACKAGE_VERSION", "0.112.1")],
17943
17946
  ["X-Stainless-OS", envOrNull("OMNI_ANTHROPIC_STAINLESS_OS") ?? host.os],
17944
17947
  ["X-Stainless-Arch", envOrNull("OMNI_ANTHROPIC_STAINLESS_ARCH") ?? host.arch],
17945
17948
  ["X-Stainless-Runtime", "node"],
@@ -18181,19 +18184,18 @@ function orderFields(obj, order) {
18181
18184
  }
18182
18185
  return out;
18183
18186
  }
18184
- var BUILD_REVISION = envOr("OMNI_ANTHROPIC_BUILD_REVISION", "250");
18185
- var CLI_VERSION = envOr("OMNI_ANTHROPIC_CLI_VERSION", "2.1.219");
18186
18187
  var CCH_PLACEHOLDER = "00000";
18187
18188
  var CCH_SEED = 0x6e52736ac806831en;
18188
18189
  var CCH_MASK = 0xfffffn;
18190
+ var CCV_SALT = "59cf53e54c78";
18189
18191
  var BILLING_PREFIX = "x-anthropic-billing-header:";
18190
18192
  var AGENT_PREAMBLE = "You are a Claude agent, built on Anthropic's Claude Agent SDK.";
18191
- function envOr(name, fallback) {
18192
- const raw = Bun.env[name];
18193
- return typeof raw === "string" && /^[\x20-\x7E]{1,200}$/.test(raw) ? raw : fallback;
18193
+ function ccVersionSuffix(firstUserText) {
18194
+ const picked = [4, 7, 20].map((i) => firstUserText[i] ?? "0").join("");
18195
+ return createHash("sha256").update(`${CCV_SALT}${picked}${ANTHROPIC_CLI_VERSION}`).digest("hex").slice(0, 3);
18194
18196
  }
18195
- function billingBlock() {
18196
- return `${BILLING_PREFIX} cc_version=${CLI_VERSION}.${BUILD_REVISION}; ` + `cc_entrypoint=cli; cch=${CCH_PLACEHOLDER};`;
18197
+ function billingBlock(firstUserText) {
18198
+ return `${BILLING_PREFIX} cc_version=${ANTHROPIC_CLI_VERSION}.${ccVersionSuffix(firstUserText)}; ` + `cc_entrypoint=cli; cch=${CCH_PLACEHOLDER};`;
18197
18199
  }
18198
18200
  var BANNED_SUBSTRINGS = [
18199
18201
  "github.com/anomalyco/opencode",
@@ -18211,7 +18213,7 @@ var REWRITES = [
18211
18213
  "Environment context you are running in:"
18212
18214
  ]
18213
18215
  ];
18214
- function applyAnthropicSystem(system) {
18216
+ function applyAnthropicSystem(system, firstUserText) {
18215
18217
  const kept = [];
18216
18218
  for (const block of system) {
18217
18219
  const text = block.text.split(/\n{2,}/).filter((p) => !BANNED_SUBSTRINGS.some((b) => p.includes(b))).filter((p) => !IDENTITY_PREFIXES.some((i) => p.trimStart().startsWith(i))).filter((p) => !p.includes(BILLING_PREFIX)).filter((p) => p.trim() !== AGENT_PREAMBLE).join(`
@@ -18228,17 +18230,26 @@ function applyAnthropicSystem(system) {
18228
18230
  });
18229
18231
  }
18230
18232
  }
18231
- return [{ type: "text", text: billingBlock() }, { type: "text", text: AGENT_PREAMBLE }, ...kept];
18233
+ return [
18234
+ { type: "text", text: billingBlock(firstUserText) },
18235
+ { type: "text", text: AGENT_PREAMBLE },
18236
+ ...kept
18237
+ ];
18232
18238
  }
18233
18239
  function computeCch(body) {
18234
18240
  const digest = Bun.hash.xxHash64(Buffer.from(body, "utf8"), CCH_SEED);
18235
18241
  return (digest & CCH_MASK).toString(16).padStart(5, "0");
18236
18242
  }
18243
+ var BILLING_ANCHOR = `"system":[{"type":"text","text":"${BILLING_PREFIX}`;
18237
18244
  function signAnthropicBody(json2) {
18238
18245
  const needle = `cch=${CCH_PLACEHOLDER};`;
18239
- if (!json2.includes(needle))
18246
+ const anchor = json2.indexOf(BILLING_ANCHOR);
18247
+ if (anchor < 0)
18248
+ return json2;
18249
+ const at = json2.indexOf(needle, anchor);
18250
+ if (at < 0)
18240
18251
  return json2;
18241
- return json2.replace(needle, `cch=${computeCch(json2)};`);
18252
+ return `${json2.slice(0, at)}cch=${computeCch(json2)};${json2.slice(at + needle.length)}`;
18242
18253
  }
18243
18254
 
18244
18255
  // packages/providers/src/catalog.ts
@@ -19201,9 +19212,11 @@ var anthropicCodec = {
19201
19212
  cloak,
19202
19213
  autoCache: input.autoCacheEnabled === true
19203
19214
  });
19215
+ const firstUser = input.request.messages.find((m) => m.role === "user");
19216
+ const firstText = firstUser?.content.find((b) => b.type === "text");
19204
19217
  const withSystem = {
19205
19218
  ...body,
19206
- system: applyAnthropicSystem(body.system ?? []),
19219
+ system: applyAnthropicSystem(body.system ?? [], firstText?.text ?? ""),
19207
19220
  stream: true
19208
19221
  };
19209
19222
  const protocol = [
@@ -20780,7 +20793,7 @@ var customCodec = {
20780
20793
  // packages/providers/src/custom/index.ts
20781
20794
  var customAdapter = codecAdapter("custom", customDescriptor.capabilities, customCodec);
20782
20795
  // packages/providers/src/grok/codec.ts
20783
- import { createHash as createHash2 } from "crypto";
20796
+ import { createHash as createHash3 } from "crypto";
20784
20797
 
20785
20798
  // packages/providers/src/grok/decode.ts
20786
20799
  var ERROR_CODE = {
@@ -20979,7 +20992,7 @@ async function* decodeGrokResponses(messages) {
20979
20992
  }
20980
20993
 
20981
20994
  // packages/providers/src/grok/wire.ts
20982
- import { createHash } from "crypto";
20995
+ import { createHash as createHash2 } from "crypto";
20983
20996
  var MAX_TOOLS = 200;
20984
20997
  function encodeToolChoice2(c) {
20985
20998
  switch (c.type) {
@@ -20995,7 +21008,7 @@ function encodeToolChoice2(c) {
20995
21008
  }
20996
21009
  function promptCacheKey(instructions, firstInput) {
20997
21010
  const stable = JSON.stringify({ instructions, firstInput });
20998
- return createHash("sha256").update(stable).digest("hex").slice(0, 32);
21011
+ return createHash2("sha256").update(stable).digest("hex").slice(0, 32);
20999
21012
  }
21000
21013
  function toGrokWire(req, model) {
21001
21014
  const degradations = [];
@@ -21106,7 +21119,7 @@ var PROXY_URL = "https://cli-chat-proxy.grok.com/v1/responses";
21106
21119
  var API_URL = "https://api.x.ai/v1/responses";
21107
21120
  var CONV_NAMESPACE = "omni-grok-conv";
21108
21121
  function derivedUuid(value) {
21109
- const h = createHash2("sha256").update(`${CONV_NAMESPACE}:${value}`).digest("hex");
21122
+ const h = createHash3("sha256").update(`${CONV_NAMESPACE}:${value}`).digest("hex");
21110
21123
  const variant = (Number.parseInt(h[16], 16) & 3 | 8).toString(16);
21111
21124
  return [
21112
21125
  h.slice(0, 8),
@@ -22022,7 +22035,7 @@ async function* decodeResponses(messages, options = {}) {
22022
22035
  }
22023
22036
 
22024
22037
  // packages/providers/src/openai/wire.ts
22025
- import { createHash as createHash3 } from "crypto";
22038
+ import { createHash as createHash4 } from "crypto";
22026
22039
  function suppliedKey(req) {
22027
22040
  const vendor = req.vendor?.openai;
22028
22041
  for (const name of ["prompt_cache_key", "session_id"]) {
@@ -22034,7 +22047,7 @@ function suppliedKey(req) {
22034
22047
  }
22035
22048
  function cacheKey(req, instructions, firstInput) {
22036
22049
  const stable = req.conversationId !== undefined && req.conversationId.length > 0 ? JSON.stringify({ conversation: req.conversationId }) : JSON.stringify({ instructions, firstInput: firstInput ?? null });
22037
- return createHash3("sha256").update(stable).digest("hex").slice(0, 32);
22050
+ return createHash4("sha256").update(stable).digest("hex").slice(0, 32);
22038
22051
  }
22039
22052
  function repairOrphanedCalls(input) {
22040
22053
  const answered = new Set;
@@ -22754,10 +22767,13 @@ function bestPositive(values2) {
22754
22767
  return positive.length > 0 ? Math.min(...positive) : null;
22755
22768
  }
22756
22769
  var EXPECTED_OUTPUT_TOKENS = 1000;
22757
- function requestCost(target, request2) {
22770
+ function estimateTokens(request2) {
22758
22771
  const cachedTok = estimateCachedInputTokens(request2);
22759
22772
  const freshTok = Math.max(0, estimateInputTokens(request2) - cachedTok);
22760
22773
  const outTok = Math.min(request2.maxTokens ?? EXPECTED_OUTPUT_TOKENS, EXPECTED_OUTPUT_TOKENS);
22774
+ return { cachedTok, freshTok, outTok };
22775
+ }
22776
+ function requestCost(target, { cachedTok, freshTok, outTok }) {
22761
22777
  return freshTok * target.costPerMTok.input + cachedTok * cacheReadRate(target.costPerMTok) + outTok * target.costPerMTok.output;
22762
22778
  }
22763
22779
  function healthScore(h) {
@@ -22770,7 +22786,8 @@ function score(pairs, input) {
22770
22786
  const tiers = pairs.map((p) => p.target.tier);
22771
22787
  const minTier = Math.min(...tiers);
22772
22788
  const maxTier = Math.max(...tiers);
22773
- const costs = pairs.map((p) => requestCost(p.target, input.request));
22789
+ const tokens2 = estimateTokens(input.request);
22790
+ const costs = pairs.map((p) => requestCost(p.target, tokens2));
22774
22791
  const bestCost = bestPositive(costs);
22775
22792
  const bestLatency = bestPositive(pairs.flatMap((p) => {
22776
22793
  const h = snapshot.health.get(healthKey(p.credential.id, p.target.model));
@@ -23452,16 +23469,16 @@ async function createKey(store, input) {
23452
23469
  }
23453
23470
  async function setKeyLimits(store, id, input, now = Date.now()) {
23454
23471
  const body2 = parseOrThrow(keyLimitsSchema, input);
23455
- const key = (await store.keys.list()).find((entry) => entry.id === id);
23456
- if (key === undefined)
23472
+ const key = await store.keys.get(id);
23473
+ if (key === null)
23457
23474
  throw new GatewayError("BAD_REQUEST", "no such api key");
23458
23475
  await store.keys.setLimits(id, body2.limits);
23459
23476
  return toSummary(store, { ...key, limits: body2.limits }, now);
23460
23477
  }
23461
23478
  async function setKeyModels(store, id, input, now = Date.now()) {
23462
23479
  const body2 = parseOrThrow(keyModelsSchema, input);
23463
- const key = (await store.keys.list()).find((entry) => entry.id === id);
23464
- if (key === undefined)
23480
+ const key = await store.keys.get(id);
23481
+ if (key === null)
23465
23482
  throw new GatewayError("BAD_REQUEST", "no such api key");
23466
23483
  await store.keys.setModelAllowlist(id, body2.modelAllowlist);
23467
23484
  return toSummary(store, { ...key, modelAllowlist: body2.modelAllowlist }, now);
@@ -27111,7 +27128,7 @@ function createServiceDeps(input) {
27111
27128
  }
27112
27129
 
27113
27130
  // apps/cli/src/version.ts
27114
- var VERSION = "0.7.2";
27131
+ var VERSION = "0.7.3";
27115
27132
 
27116
27133
  // apps/cli/src/commands/service.ts
27117
27134
  function gatewayArgv(root) {
package/gateway.js CHANGED
@@ -23336,6 +23336,9 @@ function codecAdapter(id, capabilities2, codec2, origins) {
23336
23336
  };
23337
23337
  }
23338
23338
 
23339
+ // packages/providers/src/body.ts
23340
+ import { createHash } from "crypto";
23341
+
23339
23342
  // packages/providers/src/headers.ts
23340
23343
  var SAFE = /^[\x20-\x7E]{1,200}$/;
23341
23344
  function env(name, fallback) {
@@ -23391,14 +23394,14 @@ function mergeHeaders(base, overrides) {
23391
23394
 
23392
23395
  // packages/providers/src/anthropic/profile.ts
23393
23396
  var host = stainlessHost(process.platform, process.arch);
23394
- var ANTHROPIC_CLI_VERSION = env("OMNI_ANTHROPIC_CLI_VERSION", "2.1.219");
23397
+ var ANTHROPIC_CLI_VERSION = env("OMNI_ANTHROPIC_CLI_VERSION", "2.1.258");
23395
23398
  var anthropicProfile = {
23396
23399
  headers: [
23397
23400
  ["User-Agent", env("OMNI_UA_ANTHROPIC", `claude-cli/${ANTHROPIC_CLI_VERSION} (external, cli)`)],
23398
23401
  ["x-app", "cli"],
23399
23402
  ["anthropic-dangerous-direct-browser-access", "true"],
23400
23403
  ["X-Stainless-Lang", "js"],
23401
- ["X-Stainless-Package-Version", env("OMNI_ANTHROPIC_STAINLESS_PACKAGE_VERSION", "0.94.0")],
23404
+ ["X-Stainless-Package-Version", env("OMNI_ANTHROPIC_STAINLESS_PACKAGE_VERSION", "0.112.1")],
23402
23405
  ["X-Stainless-OS", envOrNull("OMNI_ANTHROPIC_STAINLESS_OS") ?? host.os],
23403
23406
  ["X-Stainless-Arch", envOrNull("OMNI_ANTHROPIC_STAINLESS_ARCH") ?? host.arch],
23404
23407
  ["X-Stainless-Runtime", "node"],
@@ -23640,19 +23643,18 @@ function orderFields(obj, order) {
23640
23643
  }
23641
23644
  return out;
23642
23645
  }
23643
- var BUILD_REVISION = envOr("OMNI_ANTHROPIC_BUILD_REVISION", "250");
23644
- var CLI_VERSION = envOr("OMNI_ANTHROPIC_CLI_VERSION", "2.1.219");
23645
23646
  var CCH_PLACEHOLDER = "00000";
23646
23647
  var CCH_SEED = 0x6e52736ac806831en;
23647
23648
  var CCH_MASK = 0xfffffn;
23649
+ var CCV_SALT = "59cf53e54c78";
23648
23650
  var BILLING_PREFIX = "x-anthropic-billing-header:";
23649
23651
  var AGENT_PREAMBLE = "You are a Claude agent, built on Anthropic's Claude Agent SDK.";
23650
- function envOr(name, fallback) {
23651
- const raw = Bun.env[name];
23652
- return typeof raw === "string" && /^[\x20-\x7E]{1,200}$/.test(raw) ? raw : fallback;
23652
+ function ccVersionSuffix(firstUserText) {
23653
+ const picked = [4, 7, 20].map((i) => firstUserText[i] ?? "0").join("");
23654
+ return createHash("sha256").update(`${CCV_SALT}${picked}${ANTHROPIC_CLI_VERSION}`).digest("hex").slice(0, 3);
23653
23655
  }
23654
- function billingBlock() {
23655
- return `${BILLING_PREFIX} cc_version=${CLI_VERSION}.${BUILD_REVISION}; ` + `cc_entrypoint=cli; cch=${CCH_PLACEHOLDER};`;
23656
+ function billingBlock(firstUserText) {
23657
+ return `${BILLING_PREFIX} cc_version=${ANTHROPIC_CLI_VERSION}.${ccVersionSuffix(firstUserText)}; ` + `cc_entrypoint=cli; cch=${CCH_PLACEHOLDER};`;
23656
23658
  }
23657
23659
  var BANNED_SUBSTRINGS = [
23658
23660
  "github.com/anomalyco/opencode",
@@ -23670,7 +23672,7 @@ var REWRITES = [
23670
23672
  "Environment context you are running in:"
23671
23673
  ]
23672
23674
  ];
23673
- function applyAnthropicSystem(system) {
23675
+ function applyAnthropicSystem(system, firstUserText) {
23674
23676
  const kept = [];
23675
23677
  for (const block of system) {
23676
23678
  const text = block.text.split(/\n{2,}/).filter((p) => !BANNED_SUBSTRINGS.some((b) => p.includes(b))).filter((p) => !IDENTITY_PREFIXES.some((i) => p.trimStart().startsWith(i))).filter((p) => !p.includes(BILLING_PREFIX)).filter((p) => p.trim() !== AGENT_PREAMBLE).join(`
@@ -23687,17 +23689,26 @@ function applyAnthropicSystem(system) {
23687
23689
  });
23688
23690
  }
23689
23691
  }
23690
- return [{ type: "text", text: billingBlock() }, { type: "text", text: AGENT_PREAMBLE }, ...kept];
23692
+ return [
23693
+ { type: "text", text: billingBlock(firstUserText) },
23694
+ { type: "text", text: AGENT_PREAMBLE },
23695
+ ...kept
23696
+ ];
23691
23697
  }
23692
23698
  function computeCch(body) {
23693
23699
  const digest = Bun.hash.xxHash64(Buffer.from(body, "utf8"), CCH_SEED);
23694
23700
  return (digest & CCH_MASK).toString(16).padStart(5, "0");
23695
23701
  }
23702
+ var BILLING_ANCHOR = `"system":[{"type":"text","text":"${BILLING_PREFIX}`;
23696
23703
  function signAnthropicBody(json2) {
23697
23704
  const needle = `cch=${CCH_PLACEHOLDER};`;
23698
- if (!json2.includes(needle))
23705
+ const anchor = json2.indexOf(BILLING_ANCHOR);
23706
+ if (anchor < 0)
23699
23707
  return json2;
23700
- return json2.replace(needle, `cch=${computeCch(json2)};`);
23708
+ const at = json2.indexOf(needle, anchor);
23709
+ if (at < 0)
23710
+ return json2;
23711
+ return `${json2.slice(0, at)}cch=${computeCch(json2)};${json2.slice(at + needle.length)}`;
23701
23712
  }
23702
23713
 
23703
23714
  // packages/providers/src/catalog.ts
@@ -24676,9 +24687,11 @@ var anthropicCodec = {
24676
24687
  cloak,
24677
24688
  autoCache: input.autoCacheEnabled === true
24678
24689
  });
24690
+ const firstUser = input.request.messages.find((m) => m.role === "user");
24691
+ const firstText = firstUser?.content.find((b) => b.type === "text");
24679
24692
  const withSystem = {
24680
24693
  ...body,
24681
- system: applyAnthropicSystem(body.system ?? []),
24694
+ system: applyAnthropicSystem(body.system ?? [], firstText?.text ?? ""),
24682
24695
  stream: true
24683
24696
  };
24684
24697
  const protocol = [
@@ -26255,7 +26268,7 @@ var customCodec = {
26255
26268
  // packages/providers/src/custom/index.ts
26256
26269
  var customAdapter = codecAdapter("custom", customDescriptor.capabilities, customCodec);
26257
26270
  // packages/providers/src/grok/codec.ts
26258
- import { createHash as createHash2 } from "crypto";
26271
+ import { createHash as createHash3 } from "crypto";
26259
26272
 
26260
26273
  // packages/providers/src/grok/decode.ts
26261
26274
  var ERROR_CODE = {
@@ -26454,7 +26467,7 @@ async function* decodeGrokResponses(messages) {
26454
26467
  }
26455
26468
 
26456
26469
  // packages/providers/src/grok/wire.ts
26457
- import { createHash } from "crypto";
26470
+ import { createHash as createHash2 } from "crypto";
26458
26471
  var MAX_TOOLS = 200;
26459
26472
  function encodeToolChoice2(c) {
26460
26473
  switch (c.type) {
@@ -26470,7 +26483,7 @@ function encodeToolChoice2(c) {
26470
26483
  }
26471
26484
  function promptCacheKey(instructions, firstInput) {
26472
26485
  const stable = JSON.stringify({ instructions, firstInput });
26473
- return createHash("sha256").update(stable).digest("hex").slice(0, 32);
26486
+ return createHash2("sha256").update(stable).digest("hex").slice(0, 32);
26474
26487
  }
26475
26488
  function toGrokWire(req, model) {
26476
26489
  const degradations = [];
@@ -26581,7 +26594,7 @@ var PROXY_URL = "https://cli-chat-proxy.grok.com/v1/responses";
26581
26594
  var API_URL = "https://api.x.ai/v1/responses";
26582
26595
  var CONV_NAMESPACE = "omni-grok-conv";
26583
26596
  function derivedUuid(value) {
26584
- const h = createHash2("sha256").update(`${CONV_NAMESPACE}:${value}`).digest("hex");
26597
+ const h = createHash3("sha256").update(`${CONV_NAMESPACE}:${value}`).digest("hex");
26585
26598
  const variant = (Number.parseInt(h[16], 16) & 3 | 8).toString(16);
26586
26599
  return [
26587
26600
  h.slice(0, 8),
@@ -27497,7 +27510,7 @@ async function* decodeResponses(messages, options = {}) {
27497
27510
  }
27498
27511
 
27499
27512
  // packages/providers/src/openai/wire.ts
27500
- import { createHash as createHash3 } from "crypto";
27513
+ import { createHash as createHash4 } from "crypto";
27501
27514
  function suppliedKey(req) {
27502
27515
  const vendor = req.vendor?.openai;
27503
27516
  for (const name of ["prompt_cache_key", "session_id"]) {
@@ -27509,7 +27522,7 @@ function suppliedKey(req) {
27509
27522
  }
27510
27523
  function cacheKey(req, instructions, firstInput) {
27511
27524
  const stable = req.conversationId !== undefined && req.conversationId.length > 0 ? JSON.stringify({ conversation: req.conversationId }) : JSON.stringify({ instructions, firstInput: firstInput ?? null });
27512
- return createHash3("sha256").update(stable).digest("hex").slice(0, 32);
27525
+ return createHash4("sha256").update(stable).digest("hex").slice(0, 32);
27513
27526
  }
27514
27527
  function repairOrphanedCalls(input) {
27515
27528
  const answered = new Set;
@@ -28236,10 +28249,13 @@ function bestPositive(values2) {
28236
28249
  return positive.length > 0 ? Math.min(...positive) : null;
28237
28250
  }
28238
28251
  var EXPECTED_OUTPUT_TOKENS = 1000;
28239
- function requestCost(target, request2) {
28252
+ function estimateTokens(request2) {
28240
28253
  const cachedTok = estimateCachedInputTokens(request2);
28241
28254
  const freshTok = Math.max(0, estimateInputTokens(request2) - cachedTok);
28242
28255
  const outTok = Math.min(request2.maxTokens ?? EXPECTED_OUTPUT_TOKENS, EXPECTED_OUTPUT_TOKENS);
28256
+ return { cachedTok, freshTok, outTok };
28257
+ }
28258
+ function requestCost(target, { cachedTok, freshTok, outTok }) {
28243
28259
  return freshTok * target.costPerMTok.input + cachedTok * cacheReadRate(target.costPerMTok) + outTok * target.costPerMTok.output;
28244
28260
  }
28245
28261
  function healthScore(h) {
@@ -28252,7 +28268,8 @@ function score(pairs, input) {
28252
28268
  const tiers = pairs.map((p) => p.target.tier);
28253
28269
  const minTier = Math.min(...tiers);
28254
28270
  const maxTier = Math.max(...tiers);
28255
- const costs = pairs.map((p) => requestCost(p.target, input.request));
28271
+ const tokens2 = estimateTokens(input.request);
28272
+ const costs = pairs.map((p) => requestCost(p.target, tokens2));
28256
28273
  const bestCost = bestPositive(costs);
28257
28274
  const bestLatency = bestPositive(pairs.flatMap((p) => {
28258
28275
  const h = snapshot.health.get(healthKey(p.credential.id, p.target.model));
@@ -29077,16 +29094,16 @@ async function createKey(store, input) {
29077
29094
  }
29078
29095
  async function setKeyLimits(store, id, input, now = Date.now()) {
29079
29096
  const body2 = parseOrThrow(keyLimitsSchema, input);
29080
- const key = (await store.keys.list()).find((entry) => entry.id === id);
29081
- if (key === undefined)
29097
+ const key = await store.keys.get(id);
29098
+ if (key === null)
29082
29099
  throw new GatewayError("BAD_REQUEST", "no such api key");
29083
29100
  await store.keys.setLimits(id, body2.limits);
29084
29101
  return toSummary(store, { ...key, limits: body2.limits }, now);
29085
29102
  }
29086
29103
  async function setKeyModels(store, id, input, now = Date.now()) {
29087
29104
  const body2 = parseOrThrow(keyModelsSchema, input);
29088
- const key = (await store.keys.list()).find((entry) => entry.id === id);
29089
- if (key === undefined)
29105
+ const key = await store.keys.get(id);
29106
+ if (key === null)
29090
29107
  throw new GatewayError("BAD_REQUEST", "no such api key");
29091
29108
  await store.keys.setModelAllowlist(id, body2.modelAllowlist);
29092
29109
  return toSummary(store, { ...key, modelAllowlist: body2.modelAllowlist }, now);
@@ -50466,7 +50483,7 @@ function parseOpenAIRequest(body2, headers) {
50466
50483
  }
50467
50484
 
50468
50485
  // apps/gateway/src/ingress/responses.ts
50469
- import { createHash as createHash4 } from "crypto";
50486
+ import { createHash as createHash5 } from "crypto";
50470
50487
  var reasoning = exports_external.object({
50471
50488
  effort: exports_external.enum(REASONING_EFFORTS).optional(),
50472
50489
  summary: exports_external.string().optional()
@@ -50532,7 +50549,7 @@ function toIrReasoning2(r) {
50532
50549
  };
50533
50550
  }
50534
50551
  function clampCallId(raw) {
50535
- return raw.length <= 64 ? raw : createHash4("sha256").update(raw).digest("hex");
50552
+ return raw.length <= 64 ? raw : createHash5("sha256").update(raw).digest("hex");
50536
50553
  }
50537
50554
  function roleOf(raw) {
50538
50555
  if (raw === "assistant")
@@ -51305,7 +51322,10 @@ function streamRoutes(deps) {
51305
51322
  send(ws, { ...head, type: "error", topic: frame2.topic, message: "no source" });
51306
51323
  return;
51307
51324
  }
51308
- deps.registry.subscribe(id, frame2.topic);
51325
+ if (!deps.registry.subscribe(id, frame2.topic)) {
51326
+ send(ws, { ...head, type: "error", topic: frame2.topic, message: "too many topics" });
51327
+ return;
51328
+ }
51309
51329
  send(ws, { ...head, type: "ack", topic: frame2.topic });
51310
51330
  if (frame2.sinceSeq !== undefined) {
51311
51331
  const slice = deps.ring.since(frame2.topic, frame2.sinceSeq);
@@ -51671,14 +51691,15 @@ function createSocketRegistry(deps = {}) {
51671
51691
  subscribe(id, topic) {
51672
51692
  const connection = connections.get(id);
51673
51693
  if (connection === undefined)
51674
- return;
51694
+ return false;
51675
51695
  if (connection.topics.size >= MAX_TOPICS_PER_CONNECTION && !connection.topics.has(topic)) {
51676
- return;
51696
+ return false;
51677
51697
  }
51678
51698
  connection.topics.add(topic);
51679
51699
  const subscribers = index.get(topic) ?? new Set;
51680
51700
  subscribers.add(id);
51681
51701
  index.set(topic, subscribers);
51702
+ return true;
51682
51703
  },
51683
51704
  unsubscribe(id, topic) {
51684
51705
  const connection = connections.get(id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnigateway",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "Self-hosted AI gateway with Anthropic- and OpenAI-compatible APIs, an admin console, and a CLI",
5
5
  "license": "MIT",
6
6
  "author": "Harismawan <mail@harismawan.com>",