anygate 0.5.5 → 0.5.7

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getTemplateById
4
- } from "./chunk-YYSUTRMV.js";
4
+ } from "./chunk-VKROC37K.js";
5
5
 
6
6
  // src/core/constants.ts
7
7
  import { homedir } from "os";
@@ -10,7 +10,7 @@ import { join } from "path";
10
10
  // package.json
11
11
  var package_default = {
12
12
  name: "anygate",
13
- version: "0.5.5",
13
+ version: "0.5.7",
14
14
  publishConfig: {
15
15
  access: "public"
16
16
  },
@@ -3780,6 +3780,41 @@ function findModelsDevModel(providerId, modelId, cache = loadModelsDevCache()) {
3780
3780
  }
3781
3781
  return null;
3782
3782
  }
3783
+ var MULTIMODAL_FAMILIES = [
3784
+ /nvidia.*nemotron/i,
3785
+ /^gpt-/i,
3786
+ /^o[0-9]/i,
3787
+ // o1, o3, o4, o-series
3788
+ /gpt-5/i,
3789
+ /gemini/i,
3790
+ /claude/i,
3791
+ /sonnet/i,
3792
+ /opus/i,
3793
+ /haiku/i,
3794
+ /llama.*vision/i,
3795
+ /(vision|multimodal)/i,
3796
+ /qwen.*vl/i,
3797
+ /qwen2?-vl/i,
3798
+ /deepseek.*vl/i,
3799
+ /mistral.*(vision|pixtral)/i,
3800
+ /pixtral/i,
3801
+ /grok.*vision/i,
3802
+ /(command|cohere).*vision/i
3803
+ ];
3804
+ function familyMatchesMultimodal(family, modelId) {
3805
+ const hay = `${family} ${modelId}`;
3806
+ return MULTIMODAL_FAMILIES.some((re) => re.test(hay));
3807
+ }
3808
+ function resolveInputTypes(family, providerId, modelId, cache = loadModelsDevCache()) {
3809
+ const entry = findModelsDevModel(providerId, modelId, cache);
3810
+ const baseInput = entry?.modalities?.input && entry.modalities.input.length > 0 ? [...entry.modalities.input] : null;
3811
+ if (baseInput && baseInput.every((t) => t === "text") && !familyMatchesMultimodal(family, modelId)) {
3812
+ return ["text"];
3813
+ }
3814
+ const result = new Set(baseInput ?? ["text"]);
3815
+ if (familyMatchesMultimodal(family, modelId)) result.add("image");
3816
+ return [...result];
3817
+ }
3783
3818
  function shouldHideByModelsDevCapabilities(entry) {
3784
3819
  const output = entry.modalities?.output;
3785
3820
  if (output && output.length > 0 && !output.includes("text")) return true;
@@ -3981,7 +4016,7 @@ function maskGatewayModelId(aliasId) {
3981
4016
  // src/gateway/models.ts
3982
4017
  var CREATED_AT_ISO = "2025-01-01T00:00:00Z";
3983
4018
  var CREATED_AT_UNIX = 1735689600;
3984
- function formatAnthropicModelEntry(id, displayName, contextWindow) {
4019
+ function formatAnthropicModelEntry(id, displayName, contextWindow, inputTypes) {
3985
4020
  const maxInput = resolveContextWindow(id, contextWindow);
3986
4021
  return {
3987
4022
  id,
@@ -3989,12 +4024,13 @@ function formatAnthropicModelEntry(id, displayName, contextWindow) {
3989
4024
  display_name: displayName,
3990
4025
  created_at: CREATED_AT_ISO,
3991
4026
  context_window: maxInput,
3992
- max_input_tokens: maxInput
4027
+ max_input_tokens: maxInput,
4028
+ input_types: inputTypes ?? ["text"]
3993
4029
  };
3994
4030
  }
3995
4031
  function formatAnthropicModelList(entries) {
3996
4032
  return {
3997
- data: entries.map((entry) => formatAnthropicModelEntry(entry.id, entry.name, entry.contextWindow)),
4033
+ data: entries.map((entry) => formatAnthropicModelEntry(entry.id, entry.name, entry.contextWindow, entry.inputTypes)),
3998
4034
  has_more: false,
3999
4035
  first_id: entries[0]?.id ?? null,
4000
4036
  last_id: entries.at(-1)?.id ?? null
@@ -4022,7 +4058,8 @@ function formatGatewayAnthropicModels(models, opts) {
4022
4058
  models.map((model) => ({
4023
4059
  id: exposedGatewayAliasId(model, opts),
4024
4060
  name: gatewayDisplayName(model, opts),
4025
- contextWindow: model.contextWindow
4061
+ contextWindow: model.contextWindow,
4062
+ inputTypes: model.supportedParameters?.includes("image") ? ["text", "image"] : ["text"]
4026
4063
  }))
4027
4064
  );
4028
4065
  }
@@ -5103,6 +5140,94 @@ function resolveUpstreamTools(tools, messages) {
5103
5140
  return upstream;
5104
5141
  }
5105
5142
 
5143
+ // src/gateway/context-fit.ts
5144
+ var CHARS_PER_TOKEN = 4;
5145
+ var RESERVE_TOKENS = 256;
5146
+ function estimateTokens(text4) {
5147
+ return Math.ceil(text4.length / CHARS_PER_TOKEN);
5148
+ }
5149
+ function messageTokens(msg) {
5150
+ if (typeof msg.content === "string") return estimateTokens(msg.content);
5151
+ let total = 0;
5152
+ for (const block of msg.content) {
5153
+ if (typeof block.text === "string") {
5154
+ total += estimateTokens(block.text);
5155
+ }
5156
+ if (block.source?.data) {
5157
+ total += Math.max(512, estimateTokens(block.source.data));
5158
+ }
5159
+ if (typeof block.input === "object" && block.input !== null) {
5160
+ try {
5161
+ total += estimateTokens(JSON.stringify(block.input));
5162
+ } catch {
5163
+ }
5164
+ }
5165
+ }
5166
+ return total;
5167
+ }
5168
+ function estimateContextTokens(system, messages) {
5169
+ let total = estimateTokens(system ?? "");
5170
+ for (const msg of messages) total += messageTokens(msg);
5171
+ return total;
5172
+ }
5173
+ function fitContextWindow(messages, system, contextWindow, maxOutputTokens) {
5174
+ const systemTokens = estimateTokens(system ?? "");
5175
+ const budget = contextWindow - maxOutputTokens - RESERVE_TOKENS;
5176
+ if (budget <= 0) {
5177
+ return { system, messages, trimmed: false, dropped: 0 };
5178
+ }
5179
+ const usable = budget - systemTokens;
5180
+ if (usable <= 0) {
5181
+ return { system, messages, trimmed: false, dropped: 0 };
5182
+ }
5183
+ const kept = [];
5184
+ let used = 0;
5185
+ for (let i = messages.length - 1; i >= 0; i--) {
5186
+ const msg = messages[i];
5187
+ const cost = messageTokens(msg);
5188
+ if (used + cost > usable && kept.length > 0) break;
5189
+ kept.unshift(msg);
5190
+ used += cost;
5191
+ }
5192
+ const toolUseIds = /* @__PURE__ */ new Set();
5193
+ const toolResultIds = /* @__PURE__ */ new Set();
5194
+ for (const msg of kept) {
5195
+ if (!Array.isArray(msg.content)) continue;
5196
+ for (const b of msg.content) {
5197
+ if (b.type === "tool_use" && b.id) toolUseIds.add(b.id);
5198
+ if (b.type === "tool_result" && b.tool_use_id) toolResultIds.add(b.tool_use_id);
5199
+ }
5200
+ }
5201
+ const orphanResult = kept.filter((msg) => {
5202
+ if (!Array.isArray(msg.content)) return false;
5203
+ return msg.content.some((b) => b.type === "tool_result" && b.tool_use_id && !toolUseIds.has(b.tool_use_id));
5204
+ });
5205
+ const orphanUse = kept.filter((msg) => {
5206
+ if (!Array.isArray(msg.content)) return false;
5207
+ return msg.content.some((b) => b.type === "tool_use" && b.id && !toolResultIds.has(b.id));
5208
+ });
5209
+ let trimmedMessages = kept;
5210
+ if (orphanResult.length || orphanUse.length) {
5211
+ const dropIds = /* @__PURE__ */ new Set();
5212
+ for (const msg of [...orphanResult, ...orphanUse]) {
5213
+ for (const b of msg.content) {
5214
+ if (b.id) dropIds.add(b.id);
5215
+ if (b.tool_use_id) dropIds.add(b.tool_use_id);
5216
+ }
5217
+ }
5218
+ trimmedMessages = trimmedMessages.filter(
5219
+ (msg) => !msg.content || !Array.isArray(msg.content) || !msg.content.some((b) => b.id && dropIds.has(b.id) || b.tool_use_id && dropIds.has(b.tool_use_id))
5220
+ );
5221
+ }
5222
+ const dropped = messages.length - trimmedMessages.length;
5223
+ return {
5224
+ system,
5225
+ messages: trimmedMessages,
5226
+ trimmed: dropped > 0,
5227
+ dropped
5228
+ };
5229
+ }
5230
+
5106
5231
  // src/gateway/sdk-adapter.ts
5107
5232
  function anthropicEffortFromRequest(body) {
5108
5233
  const effort = body.output_config?.effort;
@@ -5240,11 +5365,32 @@ function translateToolChoice(tc) {
5240
5365
  return void 0;
5241
5366
  }
5242
5367
  function translateRequest2(body, npm, options) {
5243
- const messages = body.messages ?? [];
5368
+ let messages = body.messages ?? [];
5244
5369
  annotateToolNames(messages);
5245
5370
  const baseSystem = systemToString(body.system);
5246
5371
  const inlineParts = inlineSystemText(messages);
5247
5372
  const systemText = [baseSystem, ...inlineParts].filter((s) => s && s.trim()).join("\n\n") || (options?.openAiOAuth ? "You are a coding assistant." : void 0);
5373
+ let trimmedSystem = systemText;
5374
+ let maxOutput = options?.openAiOAuth ? void 0 : body.max_tokens;
5375
+ if (options?.contextWindow && options.contextWindow > 0) {
5376
+ const { system: fittedSystem, messages: fittedMessages, trimmed } = fitContextWindow(
5377
+ messages,
5378
+ systemText,
5379
+ options.contextWindow,
5380
+ typeof maxOutput === "number" ? maxOutput : 0
5381
+ );
5382
+ if (trimmed) {
5383
+ messages = fittedMessages;
5384
+ annotateToolNames(messages);
5385
+ const fittedInline = inlineSystemText(messages);
5386
+ trimmedSystem = [fittedSystem, ...fittedInline].filter((s) => s && s.trim()).join("\n\n") || (options?.openAiOAuth ? "You are a coding assistant." : void 0);
5387
+ if (typeof maxOutput === "number") {
5388
+ const fittedInputTokens = estimateContextTokens(fittedSystem ?? "", fittedMessages);
5389
+ const headroom = options.contextWindow - fittedInputTokens - 256;
5390
+ if (headroom > 0 && maxOutput > headroom) maxOutput = headroom;
5391
+ }
5392
+ }
5393
+ }
5248
5394
  let upstreamTools = resolveUpstreamTools(
5249
5395
  body.tools,
5250
5396
  messages
@@ -5263,11 +5409,11 @@ function translateRequest2(body, npm, options) {
5263
5409
  });
5264
5410
  }
5265
5411
  return {
5266
- system: options?.openAiOAuth ? void 0 : systemText,
5412
+ system: options?.openAiOAuth ? void 0 : trimmedSystem,
5267
5413
  messages: translateMessages(messages, npm),
5268
5414
  tools: translateTools3(upstreamTools.length ? upstreamTools : void 0),
5269
5415
  toolChoice: translateToolChoice(body.tool_choice),
5270
- maxOutputTokens: options?.openAiOAuth ? void 0 : body.max_tokens,
5416
+ maxOutputTokens: options?.openAiOAuth ? void 0 : maxOutput,
5271
5417
  temperature: body.temperature,
5272
5418
  providerOptions
5273
5419
  };
@@ -5698,6 +5844,10 @@ function makeProxyLog(debug, logPath) {
5698
5844
  appendSecureLog(path, line);
5699
5845
  };
5700
5846
  }
5847
+ var quietErrorLogPath = getProxyDebugLogPath();
5848
+ function quietErrorLog(line) {
5849
+ appendSecureLog(quietErrorLogPath, `[quiet-error] ${line}`);
5850
+ }
5701
5851
  function anthropicError(res, status, message) {
5702
5852
  sendJson(res, status, {
5703
5853
  type: "error",
@@ -5707,7 +5857,8 @@ function anthropicError(res, status, message) {
5707
5857
  function aliasModelId(realId, providerId) {
5708
5858
  if (realId.startsWith("claude-")) return realId;
5709
5859
  const sanitized = providerId.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
5710
- return `anthropic-${sanitized}__${realId}`;
5860
+ const safeRealId = realId.replace(/[\/\s:()]+/g, "-");
5861
+ return `anthropic-${sanitized}__${safeRealId}`;
5711
5862
  }
5712
5863
  function lookupRoute(byAlias, id) {
5713
5864
  for (const key of routeLookupIds(id)) {
@@ -5735,7 +5886,7 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
5735
5886
  process.on("uncaughtException", onException);
5736
5887
  const modelsPayload = JSON.stringify(
5737
5888
  formatAnthropicModelList(
5738
- routes.map((r) => ({ id: r.aliasId, name: r.displayName, contextWindow: r.contextWindow }))
5889
+ routes.map((r) => ({ id: r.aliasId, name: r.displayName, contextWindow: r.contextWindow, inputTypes: r.inputTypes }))
5739
5890
  )
5740
5891
  );
5741
5892
  const server = createServer(async (req, res) => {
@@ -5752,8 +5903,9 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
5752
5903
  const route = lookupRoute(byAlias, id);
5753
5904
  if (route) {
5754
5905
  res.writeHead(200, { "Content-Type": "application/json" });
5755
- res.end(JSON.stringify(formatAnthropicModelEntry(route.aliasId, route.displayName, route.contextWindow)));
5906
+ res.end(JSON.stringify(formatAnthropicModelEntry(route.aliasId, route.displayName, route.contextWindow, route.inputTypes)));
5756
5907
  } else {
5908
+ quietErrorLog(`GET /v1/models/${id} - model not found`);
5757
5909
  res.writeHead(404, { "Content-Type": "application/json" });
5758
5910
  res.end(JSON.stringify({ error: { type: "not_found_error", message: `Model '${id}' not found` } }));
5759
5911
  }
@@ -5780,6 +5932,9 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
5780
5932
  const originalModel = anthropicBody.model;
5781
5933
  const clientWantsStream = Boolean(anthropicBody.stream);
5782
5934
  const route = lookupRoute(byAlias, originalModel) ?? defaultRoute;
5935
+ if (route === defaultRoute && originalModel !== defaultRoute.aliasId) {
5936
+ quietErrorLog(`POST /v1/messages - model alias '${originalModel}' not found, falling back to default route '${defaultRoute.aliasId}'`);
5937
+ }
5783
5938
  const apiKey = route.apiKey;
5784
5939
  const upstreamUrl = route.upstreamUrl;
5785
5940
  plog(
@@ -5845,7 +6000,8 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
5845
6000
  reasoning: route.reasoning,
5846
6001
  interleavedReasoningField: route.interleavedReasoningField,
5847
6002
  upstreamModelId: route.realModelId
5848
- }
6003
+ },
6004
+ contextWindow: route.contextWindow
5849
6005
  });
5850
6006
  plog(
5851
6007
  () => `sdk: npm=${route.npm} model=${route.realModelId}, stream=${clientWantsStream}, tools=${anthropicBody.tools?.length ?? 0}, msgs=${params.messages.length}`
@@ -6865,7 +7021,8 @@ function localModelToRoute(lp, model) {
6865
7021
  reasoning: model.reasoning,
6866
7022
  interleavedReasoningField: model.interleavedReasoningField,
6867
7023
  useResponsesLite: model.useResponsesLite,
6868
- preferWebSockets: model.preferWebSockets
7024
+ preferWebSockets: model.preferWebSockets,
7025
+ inputTypes: resolveInputTypes(model.family, lp.id, model.id)
6869
7026
  };
6870
7027
  }
6871
7028
  function makeRouteResolver(localProviders) {
@@ -7541,7 +7698,8 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
7541
7698
  interleavedReasoningField: model.interleavedReasoningField,
7542
7699
  upstreamModelId: upstreamModelId(model)
7543
7700
  },
7544
- maxTools: npmMaxTools
7701
+ maxTools: npmMaxTools,
7702
+ contextWindow: model.contextWindow ?? resolveContextWindow(model.id)
7545
7703
  });
7546
7704
  const clientWantsStream = Boolean(body.stream);
7547
7705
  const responseModelId = getResponseModelId(body.model, model, options);
@@ -7583,7 +7741,14 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
7583
7741
  if (!res.headersSent) {
7584
7742
  const status = upstreamHttpStatus(err);
7585
7743
  sendJson(res, status === 500 ? 502 : status, { error: { message } });
7586
- } else res.end();
7744
+ } else {
7745
+ const errorType = anthropicErrorType(upstreamHttpStatus(err));
7746
+ res.write(`event: error
7747
+ data: ${JSON.stringify({ type: "error", error: { type: errorType, message } })}
7748
+
7749
+ `);
7750
+ res.end();
7751
+ }
7587
7752
  }
7588
7753
  return;
7589
7754
  }
@@ -7656,7 +7821,14 @@ async function handleOpenAIChatCompletions(req, res, options, modelCache, plog)
7656
7821
  if (!res.headersSent) {
7657
7822
  const status = upstreamHttpStatus(err);
7658
7823
  sendJson(res, status === 500 ? 502 : status, { error: { message } });
7659
- } else res.end();
7824
+ } else {
7825
+ const errorType = anthropicErrorType(upstreamHttpStatus(err));
7826
+ res.write(`event: error
7827
+ data: ${JSON.stringify({ type: "error", error: { type: errorType, message } })}
7828
+
7829
+ `);
7830
+ res.end();
7831
+ }
7660
7832
  }
7661
7833
  }
7662
7834
  function lookupModel(res, catalog, modelId) {
@@ -10745,6 +10917,7 @@ export {
10745
10917
  isFreeStatus,
10746
10918
  freeStatusLabel,
10747
10919
  refreshModelsDevCacheAsync,
10920
+ resolveInputTypes,
10748
10921
  shouldHideModel,
10749
10922
  cachedModelToLocal,
10750
10923
  readBody,
@@ -10782,6 +10955,7 @@ export {
10782
10955
  providersForPicker,
10783
10956
  formatRegistryAuthLabel,
10784
10957
  resolveProvidersForDisplay,
10958
+ localProvidersToServerModels,
10785
10959
  makeRouteResolver,
10786
10960
  buildCatalogRoutes,
10787
10961
  findOpencodeBinary,
@@ -10842,4 +11016,4 @@ export {
10842
11016
  quitClaudeAppGracefully,
10843
11017
  launchOrRestartClaudeApp
10844
11018
  };
10845
- //# sourceMappingURL=chunk-CH5IEXJN.js.map
11019
+ //# sourceMappingURL=chunk-BCPX3QLK.js.map