omnigateway 0.4.11 → 0.4.12

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 +42 -7
  2. package/gateway.js +42 -7
  3. package/package.json +1 -1
package/bin/omni.js CHANGED
@@ -1931,16 +1931,51 @@ function hasVendorCacheControl(req) {
1931
1931
  const anthropic2 = req.vendor?.anthropic;
1932
1932
  return typeof anthropic2 === "object" && anthropic2 !== null && "cache_control" in anthropic2;
1933
1933
  }
1934
- function addAutoCacheBreakpoint(body, req, note2) {
1934
+ var CACHEABLE_WIRE_BLOCKS = new Set(["text", "image", "tool_use", "tool_result", "document"]);
1935
+ function lastCacheableHistoryBlock(messages) {
1936
+ for (let m = messages.length - 1;m >= 0; m--) {
1937
+ const message = messages[m];
1938
+ if (!isRecord(message) || !Array.isArray(message.content))
1939
+ continue;
1940
+ for (let b = message.content.length - 1;b >= 0; b--) {
1941
+ const block = message.content[b];
1942
+ if (!isRecord(block))
1943
+ continue;
1944
+ if (typeof block.type === "string" && CACHEABLE_WIRE_BLOCKS.has(block.type))
1945
+ return block;
1946
+ }
1947
+ }
1948
+ return;
1949
+ }
1950
+ function addAutoCacheBreakpoints(body, req, note2) {
1935
1951
  if (estimateCachedInputTokens(req) !== 0 || hasVendorCacheControl(req))
1936
1952
  return;
1937
- if (estimateInputTokens({ ...req, messages: [] }) < AUTO_CACHE_MIN_TOKENS)
1953
+ let markedPrefix = 0;
1954
+ const worthAMarker = (prefix) => prefix - markedPrefix >= AUTO_CACHE_MIN_TOKENS;
1955
+ let stablePrefixMarked = false;
1956
+ const toolsPrefix = estimateInputTokens({ ...req, messages: [], system: [] });
1957
+ const lastTool = body.tools?.at(-1);
1958
+ if (lastTool !== undefined && worthAMarker(toolsPrefix)) {
1959
+ lastTool.cache_control = { type: "ephemeral" };
1960
+ markedPrefix = toolsPrefix;
1961
+ stablePrefixMarked = true;
1962
+ }
1963
+ const systemPrefix = estimateInputTokens({ ...req, messages: [] });
1964
+ const lastSystem = body.system?.at(-1);
1965
+ if (lastSystem !== undefined && worthAMarker(systemPrefix)) {
1966
+ lastSystem.cache_control = { type: "ephemeral" };
1967
+ markedPrefix = systemPrefix;
1968
+ stablePrefixMarked = true;
1969
+ }
1970
+ if (stablePrefixMarked)
1971
+ note2("anthropic:cache-breakpoint-added");
1972
+ if (!worthAMarker(estimateInputTokens(req)))
1938
1973
  return;
1939
- const target = body.system?.at(-1) ?? body.tools?.at(-1);
1940
- if (target === undefined)
1974
+ const lastHistory = lastCacheableHistoryBlock(body.messages);
1975
+ if (lastHistory === undefined)
1941
1976
  return;
1942
- target.cache_control = { type: "ephemeral" };
1943
- note2("anthropic:cache-breakpoint-added");
1977
+ lastHistory.cache_control = { type: "ephemeral" };
1978
+ note2("anthropic:history-cache-breakpoint-added");
1944
1979
  }
1945
1980
  function toWire(req, model, opts) {
1946
1981
  const cloak = opts.cloak ?? null;
@@ -1992,7 +2027,7 @@ function toWire(req, model, opts) {
1992
2027
  if (req.toolChoice !== undefined)
1993
2028
  body.tool_choice = encodeToolChoice(req.toolChoice, cloak);
1994
2029
  if (opts.autoCache === true)
1995
- addAutoCacheBreakpoint(body, req, note2);
2030
+ addAutoCacheBreakpoints(body, req, note2);
1996
2031
  if (req.reasoning !== undefined) {
1997
2032
  switch (req.reasoning.mode) {
1998
2033
  case "adaptive":
package/gateway.js CHANGED
@@ -7293,16 +7293,51 @@ function hasVendorCacheControl(req) {
7293
7293
  const anthropic2 = req.vendor?.anthropic;
7294
7294
  return typeof anthropic2 === "object" && anthropic2 !== null && "cache_control" in anthropic2;
7295
7295
  }
7296
- function addAutoCacheBreakpoint(body, req, note) {
7296
+ var CACHEABLE_WIRE_BLOCKS = new Set(["text", "image", "tool_use", "tool_result", "document"]);
7297
+ function lastCacheableHistoryBlock(messages) {
7298
+ for (let m = messages.length - 1;m >= 0; m--) {
7299
+ const message = messages[m];
7300
+ if (!isRecord(message) || !Array.isArray(message.content))
7301
+ continue;
7302
+ for (let b = message.content.length - 1;b >= 0; b--) {
7303
+ const block = message.content[b];
7304
+ if (!isRecord(block))
7305
+ continue;
7306
+ if (typeof block.type === "string" && CACHEABLE_WIRE_BLOCKS.has(block.type))
7307
+ return block;
7308
+ }
7309
+ }
7310
+ return;
7311
+ }
7312
+ function addAutoCacheBreakpoints(body, req, note) {
7297
7313
  if (estimateCachedInputTokens(req) !== 0 || hasVendorCacheControl(req))
7298
7314
  return;
7299
- if (estimateInputTokens({ ...req, messages: [] }) < AUTO_CACHE_MIN_TOKENS)
7315
+ let markedPrefix = 0;
7316
+ const worthAMarker = (prefix) => prefix - markedPrefix >= AUTO_CACHE_MIN_TOKENS;
7317
+ let stablePrefixMarked = false;
7318
+ const toolsPrefix = estimateInputTokens({ ...req, messages: [], system: [] });
7319
+ const lastTool = body.tools?.at(-1);
7320
+ if (lastTool !== undefined && worthAMarker(toolsPrefix)) {
7321
+ lastTool.cache_control = { type: "ephemeral" };
7322
+ markedPrefix = toolsPrefix;
7323
+ stablePrefixMarked = true;
7324
+ }
7325
+ const systemPrefix = estimateInputTokens({ ...req, messages: [] });
7326
+ const lastSystem = body.system?.at(-1);
7327
+ if (lastSystem !== undefined && worthAMarker(systemPrefix)) {
7328
+ lastSystem.cache_control = { type: "ephemeral" };
7329
+ markedPrefix = systemPrefix;
7330
+ stablePrefixMarked = true;
7331
+ }
7332
+ if (stablePrefixMarked)
7333
+ note("anthropic:cache-breakpoint-added");
7334
+ if (!worthAMarker(estimateInputTokens(req)))
7300
7335
  return;
7301
- const target = body.system?.at(-1) ?? body.tools?.at(-1);
7302
- if (target === undefined)
7336
+ const lastHistory = lastCacheableHistoryBlock(body.messages);
7337
+ if (lastHistory === undefined)
7303
7338
  return;
7304
- target.cache_control = { type: "ephemeral" };
7305
- note("anthropic:cache-breakpoint-added");
7339
+ lastHistory.cache_control = { type: "ephemeral" };
7340
+ note("anthropic:history-cache-breakpoint-added");
7306
7341
  }
7307
7342
  function toWire(req, model, opts) {
7308
7343
  const cloak = opts.cloak ?? null;
@@ -7354,7 +7389,7 @@ function toWire(req, model, opts) {
7354
7389
  if (req.toolChoice !== undefined)
7355
7390
  body.tool_choice = encodeToolChoice(req.toolChoice, cloak);
7356
7391
  if (opts.autoCache === true)
7357
- addAutoCacheBreakpoint(body, req, note);
7392
+ addAutoCacheBreakpoints(body, req, note);
7358
7393
  if (req.reasoning !== undefined) {
7359
7394
  switch (req.reasoning.mode) {
7360
7395
  case "adaptive":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnigateway",
3
- "version": "0.4.11",
3
+ "version": "0.4.12",
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>",