omnigateway 0.12.9 → 0.12.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 (3) hide show
  1. package/bin/omni.js +239 -15
  2. package/gateway.js +328 -27
  3. package/package.json +1 -1
package/bin/omni.js CHANGED
@@ -20257,7 +20257,7 @@ function blockTokens(block) {
20257
20257
  case "toolUse":
20258
20258
  return BLOCK_OVERHEAD + fromText(block.name) + fromText(safeJson(block.input));
20259
20259
  case "toolResult":
20260
- return BLOCK_OVERHEAD + fromText(block.toolUseId) + fromText(block.content);
20260
+ return BLOCK_OVERHEAD + fromText(block.toolUseId) + fromText(block.content) + (block.images?.length ?? 0) * IMAGE_TOKENS + (block.files ?? []).reduce((sum, f) => sum + fromText(f.data), 0) + (block.native ?? []).reduce((sum, n) => sum + blockTokens(n), 0);
20261
20261
  case "providerNative":
20262
20262
  return BLOCK_OVERHEAD + fromText(block.blockType) + fromText(safeJson(block.data));
20263
20263
  }
@@ -20322,6 +20322,9 @@ function estimateCachedInputTokens(request) {
20322
20322
  running += blockTokens(block);
20323
20323
  if (cacheControlOf(block) !== undefined)
20324
20324
  cached2 = running;
20325
+ if (block.type === "toolResult" && [...block.images ?? [], ...block.native ?? []].some((p) => p.cacheControl !== undefined)) {
20326
+ cached2 = running;
20327
+ }
20325
20328
  }
20326
20329
  }
20327
20330
  return cached2;
@@ -25761,7 +25764,7 @@ function mergeHeaders(base, overrides) {
25761
25764
 
25762
25765
  // packages/providers/src/anthropic/profile.ts
25763
25766
  var host = stainlessHost(process.platform, process.arch);
25764
- var ANTHROPIC_CLI_VERSION = env("OMNI_ANTHROPIC_CLI_VERSION", "2.1.278");
25767
+ var ANTHROPIC_CLI_VERSION = env("OMNI_ANTHROPIC_CLI_VERSION", "2.1.280");
25765
25768
  var anthropicProfile = {
25766
25769
  headers: [
25767
25770
  ["User-Agent", env("OMNI_UA_ANTHROPIC", `claude-cli/${ANTHROPIC_CLI_VERSION} (external, cli)`)],
@@ -26006,7 +26009,7 @@ var museBodyOrder = [
26006
26009
  ];
26007
26010
 
26008
26011
  // packages/providers/src/openai/profile.ts
26009
- var OPENAI_CLI_VERSION = env("OMNI_OPENAI_CLI_VERSION", "0.155.1");
26012
+ var OPENAI_CLI_VERSION = env("OMNI_OPENAI_CLI_VERSION", "0.156.0");
26010
26013
  var OPENAI_UA_PLATFORM = env("OMNI_OPENAI_UA_PLATFORM", "Windows 10.0.26200");
26011
26014
  var OPENAI_UA_ARCH = env("OMNI_OPENAI_UA_ARCH", "x64");
26012
26015
  var openaiProfile = {
@@ -27106,14 +27109,36 @@ function encodeBlock(b, cloak) {
27106
27109
  input: b.input,
27107
27110
  ...cache
27108
27111
  };
27109
- case "toolResult":
27112
+ case "toolResult": {
27113
+ const documents = (b.files ?? []).flatMap((file2) => {
27114
+ const source = file2.mediaType === "application/pdf" ? { type: "base64", media_type: file2.mediaType, data: file2.data } : file2.mediaType === "text/plain" ? {
27115
+ type: "text",
27116
+ media_type: file2.mediaType,
27117
+ data: Buffer.from(file2.data, "base64").toString("utf8")
27118
+ } : undefined;
27119
+ if (source === undefined)
27120
+ return [];
27121
+ return [
27122
+ {
27123
+ type: "document",
27124
+ source,
27125
+ ...file2.filename !== undefined && { title: file2.filename }
27126
+ }
27127
+ ];
27128
+ });
27129
+ const parts = [
27130
+ ...(b.images ?? []).map((image) => encodeBlock(image, cloak)),
27131
+ ...documents,
27132
+ ...(b.native ?? []).map((part) => encodeBlock(part, cloak))
27133
+ ];
27110
27134
  return {
27111
27135
  type: "tool_result",
27112
27136
  tool_use_id: b.toolUseId,
27113
- content: b.content,
27137
+ content: parts.length === 0 ? b.content : [...b.content.length > 0 ? [{ type: "text", text: b.content }] : [], ...parts],
27114
27138
  is_error: b.isError,
27115
27139
  ...cache
27116
27140
  };
27141
+ }
27117
27142
  case "providerNative":
27118
27143
  if (b.provider !== "anthropic") {
27119
27144
  throw new GatewayError("INTERNAL", `anthropic adapter received a ${b.provider} provider-native block`);
@@ -27283,6 +27308,13 @@ function toWire(req, model, opts) {
27283
27308
  const systemCache = systemCacheControl(req);
27284
27309
  if (systemCache.lost)
27285
27310
  note2("anthropic:system-turn-cache-control-dropped");
27311
+ for (const m of req.messages) {
27312
+ for (const b of m.content) {
27313
+ if (b.type === "toolResult" && b.files?.some((f) => f.mediaType !== "application/pdf" && f.mediaType !== "text/plain")) {
27314
+ note2("anthropic:files-dropped");
27315
+ }
27316
+ }
27317
+ }
27286
27318
  const body = {
27287
27319
  model,
27288
27320
  messages: req.messages.flatMap((m) => {
@@ -28367,6 +28399,8 @@ function toAntigravityWire(req, model, identity) {
28367
28399
  });
28368
28400
  break;
28369
28401
  case "toolResult": {
28402
+ if (block.native !== undefined)
28403
+ note2("antigravity:provider-native-block-dropped");
28370
28404
  const name = names.get(block.toolUseId);
28371
28405
  if (name === undefined)
28372
28406
  note2("antigravity:tool-result-unmatched");
@@ -28378,6 +28412,12 @@ function toAntigravityWire(req, model, identity) {
28378
28412
  response: { output: block.content }
28379
28413
  }
28380
28414
  });
28415
+ for (const image of block.images ?? []) {
28416
+ parts.push({ inlineData: { mimeType: image.mediaType, data: image.data } });
28417
+ }
28418
+ for (const file2 of block.files ?? []) {
28419
+ parts.push({ inlineData: { mimeType: file2.mediaType, data: file2.data } });
28420
+ }
28381
28421
  role = "user";
28382
28422
  break;
28383
28423
  }
@@ -30118,6 +30158,61 @@ async function* decodeCustomResponses(messages) {
30118
30158
  }
30119
30159
  }
30120
30160
 
30161
+ // packages/providers/src/responsesFile.ts
30162
+ var ACCEPTED = new Set([
30163
+ "application/pdf",
30164
+ "text/plain",
30165
+ "text/csv",
30166
+ "text/markdown",
30167
+ "text/html",
30168
+ "text/css",
30169
+ "text/xml",
30170
+ "text/calendar",
30171
+ "text/tab-separated-values",
30172
+ "text/javascript",
30173
+ "text/x-python",
30174
+ "text/x-c",
30175
+ "text/x-java",
30176
+ "text/x-sh",
30177
+ "text/x-sql",
30178
+ "text/x-typescript",
30179
+ "text/x-yaml",
30180
+ "application/json",
30181
+ "application/javascript",
30182
+ "application/typescript",
30183
+ "application/toml",
30184
+ "application/yaml",
30185
+ "application/x-yaml",
30186
+ "message/rfc822",
30187
+ "application/rtf",
30188
+ "application/msword",
30189
+ "application/vnd.ms-excel",
30190
+ "application/vnd.ms-powerpoint",
30191
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
30192
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
30193
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation"
30194
+ ]);
30195
+ var TEXTUAL = new Set(["application/xml", "application/sql", "application/x-sh"]);
30196
+ function responsesFiles(files) {
30197
+ const parts = [];
30198
+ const text = [];
30199
+ let dropped = false;
30200
+ for (const file2 of files) {
30201
+ if (ACCEPTED.has(file2.mediaType)) {
30202
+ parts.push({
30203
+ type: "input_file",
30204
+ ...file2.filename !== undefined && { filename: file2.filename },
30205
+ file_data: `data:${file2.mediaType};base64,${file2.data}`
30206
+ });
30207
+ } else if (file2.mediaType.startsWith("text/") || TEXTUAL.has(file2.mediaType)) {
30208
+ text.push(Buffer.from(file2.data, "base64").toString("utf8"));
30209
+ } else {
30210
+ dropped = true;
30211
+ }
30212
+ }
30213
+ return { parts, text, dropped };
30214
+ }
30215
+
30121
30216
  // packages/providers/src/custom/wire.ts
30122
30217
  function encodeChatToolChoice(c) {
30123
30218
  switch (c.type) {
@@ -30182,11 +30277,17 @@ function toCustomChatWire(req, model) {
30182
30277
  });
30183
30278
  break;
30184
30279
  case "toolResult":
30280
+ if (block.native !== undefined)
30281
+ note2("custom:anthropic-native-block-dropped");
30185
30282
  messages.push({
30186
30283
  role: "tool",
30187
30284
  tool_call_id: block.toolUseId,
30188
30285
  content: block.content
30189
30286
  });
30287
+ if (block.images !== undefined)
30288
+ note2("custom:images-dropped");
30289
+ if (block.files !== undefined)
30290
+ note2("custom:files-dropped");
30190
30291
  break;
30191
30292
  case "providerNative":
30192
30293
  note2("custom:anthropic-native-block-dropped");
@@ -30301,14 +30402,37 @@ function toCustomResponsesWire(req, model) {
30301
30402
  arguments: JSON.stringify(block.input)
30302
30403
  });
30303
30404
  break;
30304
- case "toolResult":
30405
+ case "toolResult": {
30406
+ if (block.native !== undefined)
30407
+ note2("custom:anthropic-native-block-dropped");
30305
30408
  flush();
30409
+ const files = responsesFiles(block.files ?? []);
30306
30410
  input2.push({
30307
30411
  type: "function_call_output",
30308
30412
  call_id: block.toolUseId,
30309
- output: block.content
30413
+ output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
30414
+
30415
+ `)
30310
30416
  });
30417
+ if (block.images !== undefined) {
30418
+ note2("custom:tool-result-images-moved");
30419
+ for (const image of block.images) {
30420
+ parts.push({
30421
+ type: "input_image",
30422
+ image_url: `data:${image.mediaType};base64,${image.data}`
30423
+ });
30424
+ }
30425
+ }
30426
+ if (files.parts.length > 0) {
30427
+ note2("custom:tool-result-files-moved");
30428
+ parts.push(...files.parts);
30429
+ }
30430
+ if (files.text.length > 0)
30431
+ note2("custom:tool-result-files-inlined");
30432
+ if (files.dropped)
30433
+ note2("custom:files-dropped");
30311
30434
  break;
30435
+ }
30312
30436
  case "providerNative":
30313
30437
  note2("custom:anthropic-native-block-dropped");
30314
30438
  break;
@@ -30666,14 +30790,37 @@ function toGrokWire(req, model) {
30666
30790
  arguments: JSON.stringify(block.input)
30667
30791
  });
30668
30792
  break;
30669
- case "toolResult":
30793
+ case "toolResult": {
30794
+ if (block.native !== undefined)
30795
+ note2("grok:anthropic-native-block-dropped");
30670
30796
  flush();
30797
+ const files = responsesFiles(block.files ?? []);
30671
30798
  input2.push({
30672
30799
  type: "function_call_output",
30673
30800
  call_id: block.toolUseId,
30674
- output: block.content
30801
+ output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
30802
+
30803
+ `)
30675
30804
  });
30805
+ if (block.images !== undefined) {
30806
+ note2("grok:tool-result-images-moved");
30807
+ for (const image of block.images) {
30808
+ parts.push({
30809
+ type: "input_image",
30810
+ image_url: `data:${image.mediaType};base64,${image.data}`
30811
+ });
30812
+ }
30813
+ }
30814
+ if (files.parts.length > 0) {
30815
+ note2("grok:tool-result-files-moved");
30816
+ parts.push(...files.parts);
30817
+ }
30818
+ if (files.text.length > 0)
30819
+ note2("grok:tool-result-files-inlined");
30820
+ if (files.dropped)
30821
+ note2("grok:files-dropped");
30676
30822
  break;
30823
+ }
30677
30824
  case "providerNative":
30678
30825
  note2("grok:anthropic-native-block-dropped");
30679
30826
  break;
@@ -31080,6 +31227,7 @@ function toKiloWire(req, model) {
31080
31227
  for (const message of req.messages) {
31081
31228
  let parts = [];
31082
31229
  const toolCalls = [];
31230
+ const toolImages = [];
31083
31231
  const flush = () => {
31084
31232
  if (toolCalls.length > 0) {
31085
31233
  messages.push({ role: message.role, content: collapse(parts), tool_calls: [...toolCalls] });
@@ -31111,12 +31259,31 @@ function toKiloWire(req, model) {
31111
31259
  });
31112
31260
  break;
31113
31261
  case "toolResult":
31262
+ if (block.native !== undefined)
31263
+ note2("kilo:anthropic-native-block-dropped");
31114
31264
  flush();
31115
31265
  messages.push({
31116
31266
  role: "tool",
31117
31267
  tool_call_id: block.toolUseId,
31118
31268
  content: block.content
31119
31269
  });
31270
+ for (const image of block.images ?? []) {
31271
+ note2("kilo:tool-result-images-moved");
31272
+ toolImages.push({
31273
+ type: "image_url",
31274
+ image_url: { url: `data:${image.mediaType};base64,${image.data}` }
31275
+ });
31276
+ }
31277
+ for (const file2 of block.files ?? []) {
31278
+ note2("kilo:tool-result-files-moved");
31279
+ toolImages.push({
31280
+ type: "file",
31281
+ file: {
31282
+ ...file2.filename !== undefined && { filename: file2.filename },
31283
+ file_data: `data:${file2.mediaType};base64,${file2.data}`
31284
+ }
31285
+ });
31286
+ }
31120
31287
  break;
31121
31288
  case "providerNative":
31122
31289
  note2("kilo:anthropic-native-block-dropped");
@@ -31124,6 +31291,8 @@ function toKiloWire(req, model) {
31124
31291
  }
31125
31292
  }
31126
31293
  flush();
31294
+ if (toolImages.length > 0)
31295
+ messages.push({ role: "user", content: toolImages });
31127
31296
  }
31128
31297
  const body = {
31129
31298
  model,
@@ -31370,11 +31539,17 @@ function toChatWire(req, model, vendor = "kimi") {
31370
31539
  });
31371
31540
  break;
31372
31541
  case "toolResult":
31542
+ if (block.native !== undefined)
31543
+ note2("kimi:anthropic-native-block-dropped");
31373
31544
  messages.push({
31374
31545
  role: "tool",
31375
31546
  tool_call_id: block.toolUseId,
31376
31547
  content: block.content
31377
31548
  });
31549
+ if (block.images !== undefined)
31550
+ note2("kimi:images-dropped");
31551
+ if (block.files !== undefined)
31552
+ note2("kimi:files-dropped");
31378
31553
  break;
31379
31554
  case "providerNative":
31380
31555
  note2("kimi:anthropic-native-block-dropped");
@@ -31774,14 +31949,37 @@ function toMuseWire(req, model) {
31774
31949
  arguments: JSON.stringify(block.input)
31775
31950
  });
31776
31951
  break;
31777
- case "toolResult":
31952
+ case "toolResult": {
31953
+ if (block.native !== undefined)
31954
+ note2("muse:foreign-native-block-dropped");
31778
31955
  flush();
31956
+ const files = responsesFiles(block.files ?? []);
31779
31957
  input2.push({
31780
31958
  type: "function_call_output",
31781
31959
  call_id: block.toolUseId,
31782
- output: block.content
31960
+ output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
31961
+
31962
+ `)
31783
31963
  });
31964
+ if (block.images !== undefined) {
31965
+ note2("muse:tool-result-images-moved");
31966
+ for (const image of block.images) {
31967
+ parts.push({
31968
+ type: "input_image",
31969
+ image_url: `data:${image.mediaType};base64,${image.data}`
31970
+ });
31971
+ }
31972
+ }
31973
+ if (files.parts.length > 0) {
31974
+ note2("muse:tool-result-files-moved");
31975
+ parts.push(...files.parts);
31976
+ }
31977
+ if (files.text.length > 0)
31978
+ note2("muse:tool-result-files-inlined");
31979
+ if (files.dropped)
31980
+ note2("muse:files-dropped");
31784
31981
  break;
31982
+ }
31785
31983
  case "providerNative":
31786
31984
  if (block.provider === "muse") {
31787
31985
  flush();
@@ -32179,14 +32377,37 @@ function toResponsesWire(req, model, opts = { oauth: false }) {
32179
32377
  arguments: JSON.stringify(block.input)
32180
32378
  });
32181
32379
  break;
32182
- case "toolResult":
32380
+ case "toolResult": {
32381
+ if (block.native !== undefined)
32382
+ note2("openai:anthropic-native-block-dropped");
32183
32383
  flush();
32384
+ const files = responsesFiles(block.files ?? []);
32184
32385
  input2.push({
32185
32386
  type: "function_call_output",
32186
32387
  call_id: block.toolUseId,
32187
- output: block.content
32388
+ output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
32389
+
32390
+ `)
32188
32391
  });
32392
+ if (block.images !== undefined) {
32393
+ note2("openai:tool-result-images-moved");
32394
+ for (const image of block.images) {
32395
+ parts.push({
32396
+ type: "input_image",
32397
+ image_url: `data:${image.mediaType};base64,${image.data}`
32398
+ });
32399
+ }
32400
+ }
32401
+ if (files.parts.length > 0) {
32402
+ note2("openai:tool-result-files-moved");
32403
+ parts.push(...files.parts);
32404
+ }
32405
+ if (files.text.length > 0)
32406
+ note2("openai:tool-result-files-inlined");
32407
+ if (files.dropped)
32408
+ note2("openai:files-dropped");
32189
32409
  break;
32410
+ }
32190
32411
  case "providerNative":
32191
32412
  if (block.provider === "openai") {
32192
32413
  flush();
@@ -32779,12 +33000,15 @@ function requiredProviders(request2) {
32779
33000
  for (const block of message.content) {
32780
33001
  if (block.type === "providerNative")
32781
33002
  owners.add(block.provider);
33003
+ if (block.type === "toolResult")
33004
+ for (const n of block.native ?? [])
33005
+ owners.add(n.provider);
32782
33006
  }
32783
33007
  }
32784
33008
  return owners;
32785
33009
  }
32786
33010
  function requiredCapabilities(request2) {
32787
- const hasImage = (blocks) => blocks.some((b) => b.type === "image");
33011
+ const hasImage = (blocks) => blocks.some((b) => b.type === "image" || b.type === "toolResult" && (b.images !== undefined || b.files !== undefined));
32788
33012
  const images = hasImage(request2.system ?? []) || request2.messages.some((m) => hasImage(m.content));
32789
33013
  return {
32790
33014
  tools: (request2.tools?.length ?? 0) > 0,
@@ -37919,7 +38143,7 @@ function createServiceDeps(input2) {
37919
38143
  }
37920
38144
 
37921
38145
  // apps/cli/src/version.ts
37922
- var VERSION = "0.12.9";
38146
+ var VERSION = "0.12.11";
37923
38147
 
37924
38148
  // apps/cli/src/commands/service.ts
37925
38149
  function gatewayArgv(root) {
package/gateway.js CHANGED
@@ -25673,7 +25673,7 @@ function blockTokens(block) {
25673
25673
  case "toolUse":
25674
25674
  return BLOCK_OVERHEAD + fromText(block.name) + fromText(safeJson(block.input));
25675
25675
  case "toolResult":
25676
- return BLOCK_OVERHEAD + fromText(block.toolUseId) + fromText(block.content);
25676
+ return BLOCK_OVERHEAD + fromText(block.toolUseId) + fromText(block.content) + (block.images?.length ?? 0) * IMAGE_TOKENS + (block.files ?? []).reduce((sum, f) => sum + fromText(f.data), 0) + (block.native ?? []).reduce((sum, n) => sum + blockTokens(n), 0);
25677
25677
  case "providerNative":
25678
25678
  return BLOCK_OVERHEAD + fromText(block.blockType) + fromText(safeJson(block.data));
25679
25679
  }
@@ -25738,6 +25738,9 @@ function estimateCachedInputTokens(request) {
25738
25738
  running += blockTokens(block);
25739
25739
  if (cacheControlOf(block) !== undefined)
25740
25740
  cached2 = running;
25741
+ if (block.type === "toolResult" && [...block.images ?? [], ...block.native ?? []].some((p) => p.cacheControl !== undefined)) {
25742
+ cached2 = running;
25743
+ }
25741
25744
  }
25742
25745
  }
25743
25746
  return cached2;
@@ -31307,7 +31310,7 @@ function mergeHeaders(base, overrides) {
31307
31310
 
31308
31311
  // packages/providers/src/anthropic/profile.ts
31309
31312
  var host = stainlessHost(process.platform, process.arch);
31310
- var ANTHROPIC_CLI_VERSION = env("OMNI_ANTHROPIC_CLI_VERSION", "2.1.278");
31313
+ var ANTHROPIC_CLI_VERSION = env("OMNI_ANTHROPIC_CLI_VERSION", "2.1.280");
31311
31314
  var anthropicProfile = {
31312
31315
  headers: [
31313
31316
  ["User-Agent", env("OMNI_UA_ANTHROPIC", `claude-cli/${ANTHROPIC_CLI_VERSION} (external, cli)`)],
@@ -31552,7 +31555,7 @@ var museBodyOrder = [
31552
31555
  ];
31553
31556
 
31554
31557
  // packages/providers/src/openai/profile.ts
31555
- var OPENAI_CLI_VERSION = env("OMNI_OPENAI_CLI_VERSION", "0.155.1");
31558
+ var OPENAI_CLI_VERSION = env("OMNI_OPENAI_CLI_VERSION", "0.156.0");
31556
31559
  var OPENAI_UA_PLATFORM = env("OMNI_OPENAI_UA_PLATFORM", "Windows 10.0.26200");
31557
31560
  var OPENAI_UA_ARCH = env("OMNI_OPENAI_UA_ARCH", "x64");
31558
31561
  var openaiProfile = {
@@ -32668,14 +32671,36 @@ function encodeBlock(b, cloak) {
32668
32671
  input: b.input,
32669
32672
  ...cache
32670
32673
  };
32671
- case "toolResult":
32674
+ case "toolResult": {
32675
+ const documents = (b.files ?? []).flatMap((file2) => {
32676
+ const source = file2.mediaType === "application/pdf" ? { type: "base64", media_type: file2.mediaType, data: file2.data } : file2.mediaType === "text/plain" ? {
32677
+ type: "text",
32678
+ media_type: file2.mediaType,
32679
+ data: Buffer.from(file2.data, "base64").toString("utf8")
32680
+ } : undefined;
32681
+ if (source === undefined)
32682
+ return [];
32683
+ return [
32684
+ {
32685
+ type: "document",
32686
+ source,
32687
+ ...file2.filename !== undefined && { title: file2.filename }
32688
+ }
32689
+ ];
32690
+ });
32691
+ const parts = [
32692
+ ...(b.images ?? []).map((image) => encodeBlock(image, cloak)),
32693
+ ...documents,
32694
+ ...(b.native ?? []).map((part) => encodeBlock(part, cloak))
32695
+ ];
32672
32696
  return {
32673
32697
  type: "tool_result",
32674
32698
  tool_use_id: b.toolUseId,
32675
- content: b.content,
32699
+ content: parts.length === 0 ? b.content : [...b.content.length > 0 ? [{ type: "text", text: b.content }] : [], ...parts],
32676
32700
  is_error: b.isError,
32677
32701
  ...cache
32678
32702
  };
32703
+ }
32679
32704
  case "providerNative":
32680
32705
  if (b.provider !== "anthropic") {
32681
32706
  throw new GatewayError("INTERNAL", `anthropic adapter received a ${b.provider} provider-native block`);
@@ -32845,6 +32870,13 @@ function toWire(req, model, opts) {
32845
32870
  const systemCache = systemCacheControl(req);
32846
32871
  if (systemCache.lost)
32847
32872
  note("anthropic:system-turn-cache-control-dropped");
32873
+ for (const m of req.messages) {
32874
+ for (const b of m.content) {
32875
+ if (b.type === "toolResult" && b.files?.some((f) => f.mediaType !== "application/pdf" && f.mediaType !== "text/plain")) {
32876
+ note("anthropic:files-dropped");
32877
+ }
32878
+ }
32879
+ }
32848
32880
  const body = {
32849
32881
  model,
32850
32882
  messages: req.messages.flatMap((m) => {
@@ -33929,6 +33961,8 @@ function toAntigravityWire(req, model, identity) {
33929
33961
  });
33930
33962
  break;
33931
33963
  case "toolResult": {
33964
+ if (block.native !== undefined)
33965
+ note("antigravity:provider-native-block-dropped");
33932
33966
  const name = names.get(block.toolUseId);
33933
33967
  if (name === undefined)
33934
33968
  note("antigravity:tool-result-unmatched");
@@ -33940,6 +33974,12 @@ function toAntigravityWire(req, model, identity) {
33940
33974
  response: { output: block.content }
33941
33975
  }
33942
33976
  });
33977
+ for (const image of block.images ?? []) {
33978
+ parts.push({ inlineData: { mimeType: image.mediaType, data: image.data } });
33979
+ }
33980
+ for (const file2 of block.files ?? []) {
33981
+ parts.push({ inlineData: { mimeType: file2.mediaType, data: file2.data } });
33982
+ }
33943
33983
  role = "user";
33944
33984
  break;
33945
33985
  }
@@ -35680,6 +35720,61 @@ async function* decodeCustomResponses(messages) {
35680
35720
  }
35681
35721
  }
35682
35722
 
35723
+ // packages/providers/src/responsesFile.ts
35724
+ var ACCEPTED = new Set([
35725
+ "application/pdf",
35726
+ "text/plain",
35727
+ "text/csv",
35728
+ "text/markdown",
35729
+ "text/html",
35730
+ "text/css",
35731
+ "text/xml",
35732
+ "text/calendar",
35733
+ "text/tab-separated-values",
35734
+ "text/javascript",
35735
+ "text/x-python",
35736
+ "text/x-c",
35737
+ "text/x-java",
35738
+ "text/x-sh",
35739
+ "text/x-sql",
35740
+ "text/x-typescript",
35741
+ "text/x-yaml",
35742
+ "application/json",
35743
+ "application/javascript",
35744
+ "application/typescript",
35745
+ "application/toml",
35746
+ "application/yaml",
35747
+ "application/x-yaml",
35748
+ "message/rfc822",
35749
+ "application/rtf",
35750
+ "application/msword",
35751
+ "application/vnd.ms-excel",
35752
+ "application/vnd.ms-powerpoint",
35753
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
35754
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
35755
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation"
35756
+ ]);
35757
+ var TEXTUAL = new Set(["application/xml", "application/sql", "application/x-sh"]);
35758
+ function responsesFiles(files) {
35759
+ const parts = [];
35760
+ const text = [];
35761
+ let dropped = false;
35762
+ for (const file2 of files) {
35763
+ if (ACCEPTED.has(file2.mediaType)) {
35764
+ parts.push({
35765
+ type: "input_file",
35766
+ ...file2.filename !== undefined && { filename: file2.filename },
35767
+ file_data: `data:${file2.mediaType};base64,${file2.data}`
35768
+ });
35769
+ } else if (file2.mediaType.startsWith("text/") || TEXTUAL.has(file2.mediaType)) {
35770
+ text.push(Buffer.from(file2.data, "base64").toString("utf8"));
35771
+ } else {
35772
+ dropped = true;
35773
+ }
35774
+ }
35775
+ return { parts, text, dropped };
35776
+ }
35777
+
35683
35778
  // packages/providers/src/custom/wire.ts
35684
35779
  function encodeChatToolChoice(c) {
35685
35780
  switch (c.type) {
@@ -35744,11 +35839,17 @@ function toCustomChatWire(req, model) {
35744
35839
  });
35745
35840
  break;
35746
35841
  case "toolResult":
35842
+ if (block.native !== undefined)
35843
+ note("custom:anthropic-native-block-dropped");
35747
35844
  messages.push({
35748
35845
  role: "tool",
35749
35846
  tool_call_id: block.toolUseId,
35750
35847
  content: block.content
35751
35848
  });
35849
+ if (block.images !== undefined)
35850
+ note("custom:images-dropped");
35851
+ if (block.files !== undefined)
35852
+ note("custom:files-dropped");
35752
35853
  break;
35753
35854
  case "providerNative":
35754
35855
  note("custom:anthropic-native-block-dropped");
@@ -35863,14 +35964,37 @@ function toCustomResponsesWire(req, model) {
35863
35964
  arguments: JSON.stringify(block.input)
35864
35965
  });
35865
35966
  break;
35866
- case "toolResult":
35967
+ case "toolResult": {
35968
+ if (block.native !== undefined)
35969
+ note("custom:anthropic-native-block-dropped");
35867
35970
  flush();
35971
+ const files = responsesFiles(block.files ?? []);
35868
35972
  input2.push({
35869
35973
  type: "function_call_output",
35870
35974
  call_id: block.toolUseId,
35871
- output: block.content
35975
+ output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
35976
+
35977
+ `)
35872
35978
  });
35979
+ if (block.images !== undefined) {
35980
+ note("custom:tool-result-images-moved");
35981
+ for (const image of block.images) {
35982
+ parts.push({
35983
+ type: "input_image",
35984
+ image_url: `data:${image.mediaType};base64,${image.data}`
35985
+ });
35986
+ }
35987
+ }
35988
+ if (files.parts.length > 0) {
35989
+ note("custom:tool-result-files-moved");
35990
+ parts.push(...files.parts);
35991
+ }
35992
+ if (files.text.length > 0)
35993
+ note("custom:tool-result-files-inlined");
35994
+ if (files.dropped)
35995
+ note("custom:files-dropped");
35873
35996
  break;
35997
+ }
35874
35998
  case "providerNative":
35875
35999
  note("custom:anthropic-native-block-dropped");
35876
36000
  break;
@@ -36228,14 +36352,37 @@ function toGrokWire(req, model) {
36228
36352
  arguments: JSON.stringify(block.input)
36229
36353
  });
36230
36354
  break;
36231
- case "toolResult":
36355
+ case "toolResult": {
36356
+ if (block.native !== undefined)
36357
+ note("grok:anthropic-native-block-dropped");
36232
36358
  flush();
36359
+ const files = responsesFiles(block.files ?? []);
36233
36360
  input2.push({
36234
36361
  type: "function_call_output",
36235
36362
  call_id: block.toolUseId,
36236
- output: block.content
36363
+ output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
36364
+
36365
+ `)
36237
36366
  });
36367
+ if (block.images !== undefined) {
36368
+ note("grok:tool-result-images-moved");
36369
+ for (const image of block.images) {
36370
+ parts.push({
36371
+ type: "input_image",
36372
+ image_url: `data:${image.mediaType};base64,${image.data}`
36373
+ });
36374
+ }
36375
+ }
36376
+ if (files.parts.length > 0) {
36377
+ note("grok:tool-result-files-moved");
36378
+ parts.push(...files.parts);
36379
+ }
36380
+ if (files.text.length > 0)
36381
+ note("grok:tool-result-files-inlined");
36382
+ if (files.dropped)
36383
+ note("grok:files-dropped");
36238
36384
  break;
36385
+ }
36239
36386
  case "providerNative":
36240
36387
  note("grok:anthropic-native-block-dropped");
36241
36388
  break;
@@ -36642,6 +36789,7 @@ function toKiloWire(req, model) {
36642
36789
  for (const message of req.messages) {
36643
36790
  let parts = [];
36644
36791
  const toolCalls = [];
36792
+ const toolImages = [];
36645
36793
  const flush = () => {
36646
36794
  if (toolCalls.length > 0) {
36647
36795
  messages.push({ role: message.role, content: collapse(parts), tool_calls: [...toolCalls] });
@@ -36673,12 +36821,31 @@ function toKiloWire(req, model) {
36673
36821
  });
36674
36822
  break;
36675
36823
  case "toolResult":
36824
+ if (block.native !== undefined)
36825
+ note("kilo:anthropic-native-block-dropped");
36676
36826
  flush();
36677
36827
  messages.push({
36678
36828
  role: "tool",
36679
36829
  tool_call_id: block.toolUseId,
36680
36830
  content: block.content
36681
36831
  });
36832
+ for (const image of block.images ?? []) {
36833
+ note("kilo:tool-result-images-moved");
36834
+ toolImages.push({
36835
+ type: "image_url",
36836
+ image_url: { url: `data:${image.mediaType};base64,${image.data}` }
36837
+ });
36838
+ }
36839
+ for (const file2 of block.files ?? []) {
36840
+ note("kilo:tool-result-files-moved");
36841
+ toolImages.push({
36842
+ type: "file",
36843
+ file: {
36844
+ ...file2.filename !== undefined && { filename: file2.filename },
36845
+ file_data: `data:${file2.mediaType};base64,${file2.data}`
36846
+ }
36847
+ });
36848
+ }
36682
36849
  break;
36683
36850
  case "providerNative":
36684
36851
  note("kilo:anthropic-native-block-dropped");
@@ -36686,6 +36853,8 @@ function toKiloWire(req, model) {
36686
36853
  }
36687
36854
  }
36688
36855
  flush();
36856
+ if (toolImages.length > 0)
36857
+ messages.push({ role: "user", content: toolImages });
36689
36858
  }
36690
36859
  const body = {
36691
36860
  model,
@@ -36932,11 +37101,17 @@ function toChatWire(req, model, vendor = "kimi") {
36932
37101
  });
36933
37102
  break;
36934
37103
  case "toolResult":
37104
+ if (block.native !== undefined)
37105
+ note("kimi:anthropic-native-block-dropped");
36935
37106
  messages.push({
36936
37107
  role: "tool",
36937
37108
  tool_call_id: block.toolUseId,
36938
37109
  content: block.content
36939
37110
  });
37111
+ if (block.images !== undefined)
37112
+ note("kimi:images-dropped");
37113
+ if (block.files !== undefined)
37114
+ note("kimi:files-dropped");
36940
37115
  break;
36941
37116
  case "providerNative":
36942
37117
  note("kimi:anthropic-native-block-dropped");
@@ -37336,14 +37511,37 @@ function toMuseWire(req, model) {
37336
37511
  arguments: JSON.stringify(block.input)
37337
37512
  });
37338
37513
  break;
37339
- case "toolResult":
37514
+ case "toolResult": {
37515
+ if (block.native !== undefined)
37516
+ note("muse:foreign-native-block-dropped");
37340
37517
  flush();
37518
+ const files = responsesFiles(block.files ?? []);
37341
37519
  input2.push({
37342
37520
  type: "function_call_output",
37343
37521
  call_id: block.toolUseId,
37344
- output: block.content
37522
+ output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
37523
+
37524
+ `)
37345
37525
  });
37526
+ if (block.images !== undefined) {
37527
+ note("muse:tool-result-images-moved");
37528
+ for (const image of block.images) {
37529
+ parts.push({
37530
+ type: "input_image",
37531
+ image_url: `data:${image.mediaType};base64,${image.data}`
37532
+ });
37533
+ }
37534
+ }
37535
+ if (files.parts.length > 0) {
37536
+ note("muse:tool-result-files-moved");
37537
+ parts.push(...files.parts);
37538
+ }
37539
+ if (files.text.length > 0)
37540
+ note("muse:tool-result-files-inlined");
37541
+ if (files.dropped)
37542
+ note("muse:files-dropped");
37346
37543
  break;
37544
+ }
37347
37545
  case "providerNative":
37348
37546
  if (block.provider === "muse") {
37349
37547
  flush();
@@ -37741,14 +37939,37 @@ function toResponsesWire(req, model, opts = { oauth: false }) {
37741
37939
  arguments: JSON.stringify(block.input)
37742
37940
  });
37743
37941
  break;
37744
- case "toolResult":
37942
+ case "toolResult": {
37943
+ if (block.native !== undefined)
37944
+ note("openai:anthropic-native-block-dropped");
37745
37945
  flush();
37946
+ const files = responsesFiles(block.files ?? []);
37746
37947
  input2.push({
37747
37948
  type: "function_call_output",
37748
37949
  call_id: block.toolUseId,
37749
- output: block.content
37950
+ output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
37951
+
37952
+ `)
37750
37953
  });
37954
+ if (block.images !== undefined) {
37955
+ note("openai:tool-result-images-moved");
37956
+ for (const image of block.images) {
37957
+ parts.push({
37958
+ type: "input_image",
37959
+ image_url: `data:${image.mediaType};base64,${image.data}`
37960
+ });
37961
+ }
37962
+ }
37963
+ if (files.parts.length > 0) {
37964
+ note("openai:tool-result-files-moved");
37965
+ parts.push(...files.parts);
37966
+ }
37967
+ if (files.text.length > 0)
37968
+ note("openai:tool-result-files-inlined");
37969
+ if (files.dropped)
37970
+ note("openai:files-dropped");
37751
37971
  break;
37972
+ }
37752
37973
  case "providerNative":
37753
37974
  if (block.provider === "openai") {
37754
37975
  flush();
@@ -38265,12 +38486,15 @@ function requiredProviders(request2) {
38265
38486
  for (const block of message.content) {
38266
38487
  if (block.type === "providerNative")
38267
38488
  owners.add(block.provider);
38489
+ if (block.type === "toolResult")
38490
+ for (const n of block.native ?? [])
38491
+ owners.add(n.provider);
38268
38492
  }
38269
38493
  }
38270
38494
  return owners;
38271
38495
  }
38272
38496
  function requiredCapabilities(request2) {
38273
- const hasImage = (blocks) => blocks.some((b) => b.type === "image");
38497
+ const hasImage = (blocks) => blocks.some((b) => b.type === "image" || b.type === "toolResult" && (b.images !== undefined || b.files !== undefined));
38274
38498
  const images = hasImage(request2.system ?? []) || request2.messages.some((m) => hasImage(m.content));
38275
38499
  return {
38276
38500
  tools: (request2.tools?.length ?? 0) > 0,
@@ -60822,18 +61046,52 @@ var KNOWN = [
60822
61046
  "thinking",
60823
61047
  "metadata"
60824
61048
  ];
60825
- function flattenToolResult(content) {
61049
+ var TOOL_RESULT_NATIVE = new Set(["document", "search_result"]);
61050
+ function readToolResult(content) {
60826
61051
  if (typeof content === "string")
60827
- return content;
61052
+ return { content };
60828
61053
  if (!Array.isArray(content))
60829
- return "";
60830
- return content.map((part) => {
60831
- if (typeof part === "string")
60832
- return part;
61054
+ return { content: "" };
61055
+ const text = [];
61056
+ const images = [];
61057
+ const native = [];
61058
+ for (const part of content) {
61059
+ if (typeof part === "string") {
61060
+ text.push(part);
61061
+ continue;
61062
+ }
61063
+ const image = imageBlock.safeParse(part);
61064
+ if (image.success) {
61065
+ images.push({
61066
+ type: "image",
61067
+ mediaType: image.data.source.media_type,
61068
+ data: image.data.source.data,
61069
+ ...irCacheControl(image.data.cache_control)
61070
+ });
61071
+ continue;
61072
+ }
60833
61073
  const p = part !== null && typeof part === "object" ? part : undefined;
60834
- return p?.type === "text" && typeof p.text === "string" ? p.text : JSON.stringify(part);
60835
- }).join(`
60836
- `);
61074
+ const nativeSchema = p?.type !== undefined && TOOL_RESULT_NATIVE.has(p.type) ? nativeSchemas[p.type] : undefined;
61075
+ const parsed2 = nativeSchema?.safeParse(part);
61076
+ if (p?.type !== undefined && parsed2?.success === true) {
61077
+ const { type: _type, cache_control, ...data } = parsed2.data;
61078
+ native.push({
61079
+ type: "providerNative",
61080
+ provider: "anthropic",
61081
+ blockType: p.type,
61082
+ data,
61083
+ ...cache_control === undefined || cache_control === null ? {} : irCacheControl(cache_control)
61084
+ });
61085
+ continue;
61086
+ }
61087
+ text.push(p?.type === "text" && typeof p.text === "string" ? p.text : JSON.stringify(part));
61088
+ }
61089
+ return {
61090
+ content: text.join(`
61091
+ `),
61092
+ ...images.length > 0 && { images },
61093
+ ...native.length > 0 && { native }
61094
+ };
60837
61095
  }
60838
61096
  function toIrBlock(b) {
60839
61097
  switch (b.type) {
@@ -60869,7 +61127,7 @@ function toIrBlock(b) {
60869
61127
  return {
60870
61128
  type: "toolResult",
60871
61129
  toolUseId: b.tool_use_id,
60872
- content: flattenToolResult(b.content),
61130
+ ...readToolResult(b.content),
60873
61131
  isError: b.is_error ?? false,
60874
61132
  ...irCacheControl(b.cache_control)
60875
61133
  };
@@ -61174,13 +61432,17 @@ function parseOpenAIRequest(body2, headers) {
61174
61432
  if (m.tool_call_id === undefined) {
61175
61433
  throw new GatewayError("BAD_REQUEST", "messages: tool message requires tool_call_id");
61176
61434
  }
61435
+ const parts = contentBlocks(Array.isArray(m.content) ? m.content.filter((p) => p.type !== "image_url" || p.image_url.url.startsWith("data:")) : m.content);
61436
+ const images = parts.filter((b) => b.type === "image");
61177
61437
  messages.push({
61178
61438
  role: "user",
61179
61439
  content: [
61180
61440
  {
61181
61441
  type: "toolResult",
61182
61442
  toolUseId: m.tool_call_id,
61183
- content: typeof m.content === "string" ? m.content : "",
61443
+ content: typeof m.content === "string" ? m.content : parts.flatMap((b) => b.type === "text" ? [b.text] : []).join(`
61444
+ `),
61445
+ ...images.length > 0 && { images },
61184
61446
  isError: false,
61185
61447
  ...looseCacheControl(m.cache_control)
61186
61448
  }
@@ -61334,6 +61596,45 @@ function contentPart(part2) {
61334
61596
  }
61335
61597
  throw new GatewayError("BAD_REQUEST", `input: unsupported content part type "${safeToken(type)}"`);
61336
61598
  }
61599
+ function readToolOutput(output2) {
61600
+ if (typeof output2 === "string")
61601
+ return { content: output2 };
61602
+ if (!Array.isArray(output2))
61603
+ return { content: JSON.stringify(output2 ?? "") };
61604
+ const text = [];
61605
+ const images = [];
61606
+ const files = [];
61607
+ for (const part2 of output2) {
61608
+ if (isRecord9(part2) && (part2.type === "input_text" || part2.type === "output_text")) {
61609
+ text.push(String(part2.text ?? ""));
61610
+ } else if (isRecord9(part2) && part2.type === "input_image" && typeof part2.image_url === "string" && part2.image_url.startsWith("data:")) {
61611
+ images.push({ type: "image", ...parseDataUrl(part2.image_url) });
61612
+ } else if (isRecord9(part2) && part2.type === "input_file" && typeof part2.file_data === "string") {
61613
+ files.push({
61614
+ type: "file",
61615
+ ...fileData(part2.file_data),
61616
+ ...typeof part2.filename === "string" && { filename: part2.filename }
61617
+ });
61618
+ } else {
61619
+ text.push(JSON.stringify(part2));
61620
+ }
61621
+ }
61622
+ return {
61623
+ content: text.join(`
61624
+ `),
61625
+ ...images.length > 0 && { images },
61626
+ ...files.length > 0 && { files }
61627
+ };
61628
+ }
61629
+ function fileData(raw) {
61630
+ const url2 = /^data:([^;,]+);base64,(.*)$/s.exec(raw);
61631
+ if (url2 !== null)
61632
+ return { mediaType: url2[1], data: url2[2] };
61633
+ return {
61634
+ mediaType: raw.startsWith("JVBERi") ? "application/pdf" : "application/octet-stream",
61635
+ data: raw
61636
+ };
61637
+ }
61337
61638
  function messageBlocks(content) {
61338
61639
  if (typeof content === "string")
61339
61640
  return [{ type: "text", text: content }];
@@ -61390,7 +61691,7 @@ function readInputItems(items) {
61390
61691
  {
61391
61692
  type: "toolResult",
61392
61693
  toolUseId: clampCallId(callId),
61393
- content: typeof raw.output === "string" ? raw.output : JSON.stringify(raw.output ?? ""),
61694
+ ...readToolOutput(raw.output),
61394
61695
  isError: false
61395
61696
  }
61396
61697
  ]);
@@ -62779,7 +63080,7 @@ function createRing(limits = DEFAULT_RING_LIMITS) {
62779
63080
  }
62780
63081
 
62781
63082
  // apps/gateway/src/version.ts
62782
- var VERSION = "0.12.9";
63083
+ var VERSION = "0.12.11";
62783
63084
 
62784
63085
  // apps/gateway/src/app.ts
62785
63086
  var ADMIN_SESSION_TTL_MS = 12 * 60 * 60 * 1000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnigateway",
3
- "version": "0.12.9",
3
+ "version": "0.12.11",
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>",