omnigateway 0.4.10 → 0.4.11

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 (25) hide show
  1. package/bin/omni.js +163 -25
  2. package/gateway.js +190 -29
  3. package/package.json +1 -1
  4. package/public/assets/{CopyValue-CcE2vXiA.js → CopyValue-By5BAgv7.js} +1 -1
  5. package/public/assets/{Rack-Bbk1hAor.js → Rack-fDZClWZL.js} +1 -1
  6. package/public/assets/{Toggle-DGsa7LWV.js → Toggle-ClEeOh0F.js} +1 -1
  7. package/public/assets/{TokenBreakdown-Do_4AmfF.js → TokenBreakdown-D70VeZ2N.js} +1 -1
  8. package/public/assets/{_app-UpbTpRCt.js → _app-CDPKnQ72.js} +1 -1
  9. package/public/assets/{_app.accounts-CPG3iaDT.js → _app.accounts-Dz0ox4Br.js} +1 -1
  10. package/public/assets/{_app.console-BaGTRPEe.js → _app.console-hPUmmYjp.js} +1 -1
  11. package/public/assets/{_app.database-DA2aB-ij.js → _app.database-DGtP4NdG.js} +1 -1
  12. package/public/assets/{_app.index-CDjVA5Ix.js → _app.index-COcCAmbH.js} +1 -1
  13. package/public/assets/{_app.keys-Bf8HiloS.js → _app.keys-yTXTbKTA.js} +1 -1
  14. package/public/assets/{_app.logs-DTF9RDhN.js → _app.logs-BhMvO_Fx.js} +1 -1
  15. package/public/assets/{_app.models-B6_6bC3z.js → _app.models-0S3rurIl.js} +1 -1
  16. package/public/assets/{_app.plugins._pluginId-Dl_jYunC.js → _app.plugins._pluginId-B-ZDQNPU.js} +1 -1
  17. package/public/assets/_app.settings-DTnFwTeA.js +46 -0
  18. package/public/assets/{_app.usage-D4TLCm9J.js → _app.usage-C2-VLiq9.js} +1 -1
  19. package/public/assets/{index-CJZIRJ43.js → index-COwhxKU7.js} +2 -2
  20. package/public/assets/{login-Bu6texfZ.js → login-DjfMomJJ.js} +1 -1
  21. package/public/assets/plus-UDQ_BTEr.js +1 -0
  22. package/public/assets/{trash-2-5CCUKFQ0.js → trash-2-U2ViYZum.js} +1 -1
  23. package/public/index.html +1 -1
  24. package/public/assets/_app.settings-Dh6lrqws.js +0 -46
  25. package/public/assets/plus-Z1kRC6KA.js +0 -1
package/bin/omni.js CHANGED
@@ -233,6 +233,7 @@ var RETRYABLE = {
233
233
  BAD_REQUEST: false,
234
234
  CONFLICT: false,
235
235
  CONTENT_FILTER: false,
236
+ FINGERPRINT_REFUSED: false,
236
237
  NO_CANDIDATES: false,
237
238
  ALL_CANDIDATES_FAILED: false,
238
239
  INTERNAL: false
@@ -249,6 +250,7 @@ class GatewayError extends Error {
249
250
  provider;
250
251
  upstreamStatus;
251
252
  retryAfterMs;
253
+ degradations;
252
254
  constructor(code, message, opts) {
253
255
  super(message, opts?.cause === undefined ? undefined : { cause: opts.cause });
254
256
  this.name = "GatewayError";
@@ -257,6 +259,7 @@ class GatewayError extends Error {
257
259
  this.provider = opts?.provider;
258
260
  this.upstreamStatus = opts?.status;
259
261
  this.retryAfterMs = opts?.retryAfterMs;
262
+ this.degradations = [...opts?.degradations ?? []];
260
263
  }
261
264
  }
262
265
  // packages/ir/src/logger.ts
@@ -1290,6 +1293,82 @@ function parseRecord(record) {
1290
1293
  `) };
1291
1294
  }
1292
1295
 
1296
+ // packages/providers/src/anthropic/cloak.ts
1297
+ var ALREADY_CLOAKED = /^[A-Z][A-Za-z0-9]*$/;
1298
+ var MCP_PREFIX = "mcp__";
1299
+ function isExempt(name) {
1300
+ return ALREADY_CLOAKED.test(name) || name.startsWith(MCP_PREFIX);
1301
+ }
1302
+ var MAX_ALIAS = 128;
1303
+ var SUFFIX_LENGTH = 6;
1304
+ function aliasFor(name) {
1305
+ const joined = name.split(/[^A-Za-z0-9]+/).filter((s) => s.length > 0).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
1306
+ if (joined === "")
1307
+ return { base: "Tool", forced: true };
1308
+ if (joined.length > MAX_ALIAS) {
1309
+ return { base: joined.slice(0, MAX_ALIAS - SUFFIX_LENGTH), forced: true };
1310
+ }
1311
+ return { base: joined, forced: false };
1312
+ }
1313
+ function clientToolNames(request2) {
1314
+ const renamable = new Set;
1315
+ const reserved = new Set;
1316
+ const add = (name) => {
1317
+ (isExempt(name) ? reserved : renamable).add(name);
1318
+ };
1319
+ for (const tool of request2.tools ?? []) {
1320
+ if (tool.provider === "custom")
1321
+ add(tool.name);
1322
+ }
1323
+ for (const message of request2.messages) {
1324
+ for (const block of message.content) {
1325
+ if (block.type === "toolUse")
1326
+ add(block.name);
1327
+ }
1328
+ }
1329
+ if (request2.toolChoice?.type === "tool")
1330
+ add(request2.toolChoice.name);
1331
+ return { renamable: [...renamable], reserved: [...reserved] };
1332
+ }
1333
+ function suffixFor(name) {
1334
+ const digest = Bun.hash.xxHash64(Buffer.from(name, "utf8")) & 0xffffffn;
1335
+ const hex = digest.toString(16).padStart(SUFFIX_LENGTH, "0");
1336
+ return hex.charAt(0).toUpperCase() + hex.slice(1);
1337
+ }
1338
+ function buildToolCloak(request2) {
1339
+ const { renamable, reserved } = clientToolNames(request2);
1340
+ const claims = new Map;
1341
+ const claim = (name) => {
1342
+ claims.set(name, (claims.get(name) ?? 0) + 1);
1343
+ };
1344
+ for (const tool of request2.tools ?? []) {
1345
+ if (tool.provider === "anthropic" && tool.name !== "")
1346
+ claim(tool.name);
1347
+ }
1348
+ for (const name of reserved)
1349
+ claim(name);
1350
+ const bases = new Map;
1351
+ for (const name of renamable) {
1352
+ const derived = aliasFor(name);
1353
+ bases.set(name, derived);
1354
+ claim(derived.base);
1355
+ }
1356
+ const toWire = new Map;
1357
+ const fromWire = new Map;
1358
+ for (const [name, { base, forced }] of bases) {
1359
+ const alias = forced || (claims.get(base) ?? 0) > 1 ? base + suffixFor(name) : base;
1360
+ toWire.set(name, alias);
1361
+ fromWire.set(alias, name);
1362
+ }
1363
+ return toWire.size === 0 ? null : { toWire, fromWire };
1364
+ }
1365
+ function cloakName(cloak, name) {
1366
+ return cloak?.toWire.get(name) ?? name;
1367
+ }
1368
+ function uncloakName(cloak, name) {
1369
+ return cloak?.fromWire.get(name) ?? name;
1370
+ }
1371
+
1293
1372
  // packages/providers/src/anthropic/tools.ts
1294
1373
  var COMMON = ["cache_control", "strict", "defer_loading", "allowed_callers"];
1295
1374
  var COMMON_WITH_EXAMPLES = [...COMMON, "input_examples"];
@@ -1524,6 +1603,14 @@ var ERROR_TYPE = {
1524
1603
  invalid_request_error: "BAD_REQUEST",
1525
1604
  api_error: "UPSTREAM"
1526
1605
  };
1606
+ var FINGERPRINT_PHRASES = ["out of extra usage", "draw from extra usage"];
1607
+ function isFingerprintMessage(message) {
1608
+ const lowered = message.toLowerCase();
1609
+ return FINGERPRINT_PHRASES.some((phrase) => lowered.includes(phrase));
1610
+ }
1611
+ function isFingerprintRefusal(type, message) {
1612
+ return type === "invalid_request_error" && isFingerprintMessage(message);
1613
+ }
1527
1614
  function json(data) {
1528
1615
  try {
1529
1616
  const v = JSON.parse(data);
@@ -1532,7 +1619,8 @@ function json(data) {
1532
1619
  return null;
1533
1620
  }
1534
1621
  }
1535
- async function* decodeAnthropic(messages) {
1622
+ async function* decodeAnthropic(messages, opts = {}) {
1623
+ const cloak = opts.cloak ?? null;
1536
1624
  let inputTokens = 0;
1537
1625
  let cacheReadTokens = 0;
1538
1626
  let cacheWriteTokens = 0;
@@ -1578,7 +1666,11 @@ async function* decodeAnthropic(messages) {
1578
1666
  yield {
1579
1667
  type: "blockStart",
1580
1668
  index,
1581
- block: { type: "toolUse", id: String(cb.id), name: String(cb.name) }
1669
+ block: {
1670
+ type: "toolUse",
1671
+ id: String(cb.id),
1672
+ name: uncloakName(cloak, String(cb.name))
1673
+ }
1582
1674
  };
1583
1675
  else if (cb.type !== undefined && ANTHROPIC_NATIVE_BLOCK_TYPES.has(cb.type)) {
1584
1676
  nativeBlocks.add(index);
@@ -1681,13 +1773,10 @@ async function* decodeAnthropic(messages) {
1681
1773
  break;
1682
1774
  case "error": {
1683
1775
  terminal = true;
1684
- const code = ERROR_TYPE[String(d.error?.type)] ?? "UPSTREAM";
1685
- yield {
1686
- type: "error",
1687
- code,
1688
- message: String(d.error?.message ?? "upstream error"),
1689
- retryable: RETRYABLE[code]
1690
- };
1776
+ const type = String(d.error?.type);
1777
+ const message = String(d.error?.message ?? "upstream error");
1778
+ const code = isFingerprintRefusal(type, message) ? "FINGERPRINT_REFUSED" : ERROR_TYPE[type] ?? "UPSTREAM";
1779
+ yield { type: "error", code, message, retryable: RETRYABLE[code] };
1691
1780
  break;
1692
1781
  }
1693
1782
  default:
@@ -1714,7 +1803,7 @@ function wireCacheControl(c) {
1714
1803
  function isReplayableThinking(b) {
1715
1804
  return b.type !== "thinking" || b.signature !== undefined && b.signature !== "";
1716
1805
  }
1717
- function encodeBlock(b) {
1806
+ function encodeBlock(b, cloak) {
1718
1807
  const cache = wireCacheControl(cacheControlOf(b));
1719
1808
  switch (b.type) {
1720
1809
  case "text":
@@ -1733,7 +1822,13 @@ function encodeBlock(b) {
1733
1822
  case "thinking":
1734
1823
  return { type: "thinking", thinking: b.text, signature: b.signature };
1735
1824
  case "toolUse":
1736
- return { type: "tool_use", id: b.id, name: b.name, input: b.input, ...cache };
1825
+ return {
1826
+ type: "tool_use",
1827
+ id: b.id,
1828
+ name: cloakName(cloak, b.name),
1829
+ input: b.input,
1830
+ ...cache
1831
+ };
1737
1832
  case "toolResult":
1738
1833
  return {
1739
1834
  type: "tool_result",
@@ -1746,12 +1841,12 @@ function encodeBlock(b) {
1746
1841
  return { ...b.data, type: b.blockType, ...cache };
1747
1842
  }
1748
1843
  }
1749
- function encodeSystemTurn(content) {
1844
+ function encodeSystemTurn(content, cloak) {
1750
1845
  if (content.every((block) => block.type === "text")) {
1751
1846
  return content.map((block) => block.text).join(`
1752
1847
  `);
1753
1848
  }
1754
- return content.map(encodeBlock);
1849
+ return content.map((block) => encodeBlock(block, cloak));
1755
1850
  }
1756
1851
  function systemCacheControl(req) {
1757
1852
  const cacheable = req.messages.flatMap((message) => message.content.flatMap((block) => block.type === "thinking" ? [] : [{ role: message.role, block }]));
@@ -1763,7 +1858,7 @@ function systemCacheControl(req) {
1763
1858
  lost: markedSystemBlocks.length > (promoted === undefined ? 0 : 1)
1764
1859
  };
1765
1860
  }
1766
- function encodeTool(t) {
1861
+ function encodeTool(t, cloak) {
1767
1862
  if (t.provider === "anthropic") {
1768
1863
  return {
1769
1864
  type: t.type,
@@ -1773,14 +1868,14 @@ function encodeTool(t) {
1773
1868
  };
1774
1869
  }
1775
1870
  return {
1776
- name: t.name,
1871
+ name: cloakName(cloak, t.name),
1777
1872
  ...t.description === undefined ? {} : { description: t.description },
1778
1873
  input_schema: t.inputSchema,
1779
1874
  ...t.options ?? {},
1780
1875
  ...wireCacheControl(t.cacheControl)
1781
1876
  };
1782
1877
  }
1783
- function encodeToolChoice(c) {
1878
+ function encodeToolChoice(c, cloak) {
1784
1879
  switch (c.type) {
1785
1880
  case "auto":
1786
1881
  return { type: "auto" };
@@ -1789,7 +1884,7 @@ function encodeToolChoice(c) {
1789
1884
  case "none":
1790
1885
  return { type: "none" };
1791
1886
  case "tool":
1792
- return { type: "tool", name: c.name };
1887
+ return { type: "tool", name: cloakName(cloak, c.name) };
1793
1888
  }
1794
1889
  }
1795
1890
  function isRecord(value) {
@@ -1831,7 +1926,24 @@ function stripUnsupportedEdits(body, note2) {
1831
1926
  }
1832
1927
  body.context_management = { ...config, edits: kept };
1833
1928
  }
1929
+ var AUTO_CACHE_MIN_TOKENS = 1024;
1930
+ function hasVendorCacheControl(req) {
1931
+ const anthropic2 = req.vendor?.anthropic;
1932
+ return typeof anthropic2 === "object" && anthropic2 !== null && "cache_control" in anthropic2;
1933
+ }
1934
+ function addAutoCacheBreakpoint(body, req, note2) {
1935
+ if (estimateCachedInputTokens(req) !== 0 || hasVendorCacheControl(req))
1936
+ return;
1937
+ if (estimateInputTokens({ ...req, messages: [] }) < AUTO_CACHE_MIN_TOKENS)
1938
+ return;
1939
+ const target = body.system?.at(-1) ?? body.tools?.at(-1);
1940
+ if (target === undefined)
1941
+ return;
1942
+ target.cache_control = { type: "ephemeral" };
1943
+ note2("anthropic:cache-breakpoint-added");
1944
+ }
1834
1945
  function toWire(req, model, opts) {
1946
+ const cloak = opts.cloak ?? null;
1835
1947
  const degradations = [];
1836
1948
  const note2 = (d) => {
1837
1949
  if (!degradations.includes(d))
@@ -1842,6 +1954,8 @@ function toWire(req, model, opts) {
1842
1954
  system = [{ type: "text", text: OAUTH_IDENTITY }, ...system ?? []];
1843
1955
  note2("anthropic:oauth-system-prefix");
1844
1956
  }
1957
+ if (cloak !== null)
1958
+ note2("anthropic:tool-names-cloaked");
1845
1959
  const systemCache = systemCacheControl(req);
1846
1960
  if (systemCache.lost)
1847
1961
  note2("anthropic:system-turn-cache-control-dropped");
@@ -1854,9 +1968,9 @@ function toWire(req, model, opts) {
1854
1968
  note2("anthropic:unsigned-thinking-dropped");
1855
1969
  if (replayable.length === 0)
1856
1970
  return [];
1857
- return [{ role: m.role, content: replayable.map(encodeBlock) }];
1971
+ return [{ role: m.role, content: replayable.map((b) => encodeBlock(b, cloak)) }];
1858
1972
  }
1859
- return [{ role: m.role, content: encodeSystemTurn(m.content) }];
1973
+ return [{ role: m.role, content: encodeSystemTurn(m.content, cloak) }];
1860
1974
  }),
1861
1975
  max_tokens: req.maxTokens ?? 4096,
1862
1976
  stream: req.stream,
@@ -1874,9 +1988,11 @@ function toWire(req, model, opts) {
1874
1988
  if (req.stopSequences !== undefined)
1875
1989
  body.stop_sequences = req.stopSequences;
1876
1990
  if (req.tools !== undefined)
1877
- body.tools = req.tools.map(encodeTool);
1991
+ body.tools = req.tools.map((t) => encodeTool(t, cloak));
1878
1992
  if (req.toolChoice !== undefined)
1879
- body.tool_choice = encodeToolChoice(req.toolChoice);
1993
+ body.tool_choice = encodeToolChoice(req.toolChoice, cloak);
1994
+ if (opts.autoCache === true)
1995
+ addAutoCacheBreakpoint(body, req, note2);
1880
1996
  if (req.reasoning !== undefined) {
1881
1997
  switch (req.reasoning.mode) {
1882
1998
  case "adaptive":
@@ -1919,7 +2035,12 @@ var anthropicAdapter = {
1919
2035
  capabilities: PROVIDER_CAPABILITIES.anthropic,
1920
2036
  async send(req) {
1921
2037
  const oauth = req.credentials.accessToken !== null;
1922
- const { body, degradations } = toWire(req.request, req.model, { oauth });
2038
+ const cloak = oauth ? buildToolCloak(req.request) : null;
2039
+ const { body, degradations } = toWire(req.request, req.model, {
2040
+ oauth,
2041
+ cloak,
2042
+ autoCache: req.autoCache === true
2043
+ });
1923
2044
  const withSystem = {
1924
2045
  ...body,
1925
2046
  system: applyAnthropicSystem(body.system ?? []),
@@ -1963,11 +2084,25 @@ var anthropicAdapter = {
1963
2084
  body: bodyString,
1964
2085
  signal: req.signal
1965
2086
  });
1966
- if (res.status < 200 || res.status >= 300)
1967
- throw await httpError(res, "anthropic");
2087
+ if (res.status < 200 || res.status >= 300) {
2088
+ const error = await httpError(res, "anthropic");
2089
+ if (res.status === 400 && isFingerprintMessage(error.message)) {
2090
+ throw new GatewayError("FINGERPRINT_REFUSED", error.message, {
2091
+ provider: "anthropic",
2092
+ degradations: notes,
2093
+ ...error.upstreamStatus === undefined ? {} : { status: error.upstreamStatus },
2094
+ ...error.retryAfterMs === undefined ? {} : { retryAfterMs: error.retryAfterMs }
2095
+ });
2096
+ }
2097
+ throw error;
2098
+ }
1968
2099
  if (res.body === null)
1969
2100
  throw new GatewayError("UPSTREAM", "empty response body", { provider: "anthropic" });
1970
- return { events: decodeAnthropic(parseSse(res.body)), degradations: notes };
2101
+ return {
2102
+ events: decodeAnthropic(parseSse(res.body), { cloak }),
2103
+ degradations: notes,
2104
+ ...cloak === null ? {} : { cloakedTools: cloak.toWire.size }
2105
+ };
1971
2106
  }
1972
2107
  };
1973
2108
  // packages/providers/src/kimi/decode.ts
@@ -17998,6 +18133,7 @@ var settingsSchema = exports_external.object({
17998
18133
  logRetentionDays: exports_external.number().int().min(1),
17999
18134
  quotaPollIntervalMs: exports_external.number().int().min(0),
18000
18135
  rtkEnabled: exports_external.boolean(),
18136
+ autoCacheEnabled: exports_external.boolean(),
18001
18137
  bodyLoggingEnabled: exports_external.boolean(),
18002
18138
  bodyLoggingCaptureStreamChunks: exports_external.boolean(),
18003
18139
  snapshotKeepLatest: retentionSchema.shape.keepLatest.optional(),
@@ -18225,6 +18361,7 @@ var DEFAULT_SETTINGS = {
18225
18361
  logRetentionDays: 30,
18226
18362
  quotaPollIntervalMs: 300000,
18227
18363
  rtkEnabled: false,
18364
+ autoCacheEnabled: true,
18228
18365
  bodyLoggingEnabled: false,
18229
18366
  bodyLoggingCaptureStreamChunks: false,
18230
18367
  snapshotKeepLatest: 5,
@@ -18821,6 +18958,7 @@ function createConfigRepo(db, emit2 = () => {}) {
18821
18958
  ...DEFAULT_SETTINGS,
18822
18959
  ...stored,
18823
18960
  rtkEnabled: stored.rtkEnabled === true,
18961
+ autoCacheEnabled: stored.autoCacheEnabled === undefined ? true : stored.autoCacheEnabled === true,
18824
18962
  bodyLoggingEnabled: stored.bodyLoggingEnabled === true,
18825
18963
  bodyLoggingCaptureStreamChunks: stored.bodyLoggingCaptureStreamChunks === true,
18826
18964
  weights: knownWeights(stored.weights)