anygate 0.5.4 → 0.5.6

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.
@@ -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.4",
13
+ version: "0.5.6",
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
  }
@@ -4782,8 +4819,8 @@ function getUsage(chunk) {
4782
4819
  const u = resp?.usageMetadata;
4783
4820
  if (!u) return null;
4784
4821
  return {
4785
- input: u.promptTokenCount ?? 0,
4786
- output: u.candidatesTokenCount ?? 0
4822
+ inputTokens: u.promptTokenCount ?? 0,
4823
+ outputTokens: u.candidatesTokenCount ?? 0
4787
4824
  };
4788
4825
  }
4789
4826
  function partThoughtSignature(part) {
@@ -4842,7 +4879,7 @@ async function streamCloudCodeToAnthropic(res, upstreamRes, model, log7) {
4842
4879
  textBlockOpen: false,
4843
4880
  pendingThoughtSignature: void 0,
4844
4881
  toolCalls: [],
4845
- usage: { input: 0, output: 0 },
4882
+ usage: { inputTokens: 0, outputTokens: 0 },
4846
4883
  emittedTextChars: 0,
4847
4884
  suppressedThoughtChars: 0
4848
4885
  };
@@ -4869,7 +4906,7 @@ async function streamCloudCodeToAnthropic(res, upstreamRes, model, log7) {
4869
4906
  writeEvent(res, "message_delta", { type: "message_delta", delta: { stop_reason: "end_turn", stop_sequence: null }, usage: { output_tokens: 0 } });
4870
4907
  writeEvent(res, "message_stop", { type: "message_stop" });
4871
4908
  res.end();
4872
- return;
4909
+ return state.usage;
4873
4910
  }
4874
4911
  const reader = upstreamRes.body.getReader();
4875
4912
  const decoder = new TextDecoder();
@@ -4919,7 +4956,7 @@ async function streamCloudCodeToAnthropic(res, upstreamRes, model, log7) {
4919
4956
  finalStopReason = mapStopReason(finishReason);
4920
4957
  log7?.(() => {
4921
4958
  const toolNames = state.toolCalls.map((tc) => tc.name).filter(Boolean).join(",");
4922
- return `cloud-code stream finish=${finishReason} mapped=${finalStopReason} ${summarizeParts(parts)} emittedTextChars=${state.emittedTextChars} suppressedThoughtChars=${state.suppressedThoughtChars} queuedToolCalls=${state.toolCalls.length} queuedToolNames=${toolNames || "-"} outputTokens=${state.usage.output}`;
4959
+ return `cloud-code stream finish=${finishReason} mapped=${finalStopReason} ${summarizeParts(parts)} emittedTextChars=${state.emittedTextChars} suppressedThoughtChars=${state.suppressedThoughtChars} queuedToolCalls=${state.toolCalls.length} queuedToolNames=${toolNames || "-"} outputTokens=${state.usage.outputTokens}`;
4923
4960
  });
4924
4961
  if (state.textBlockOpen) {
4925
4962
  closeBlock(res, state);
@@ -4951,11 +4988,11 @@ async function streamCloudCodeToAnthropic(res, upstreamRes, model, log7) {
4951
4988
  writeEvent(res, "message_delta", {
4952
4989
  type: "message_delta",
4953
4990
  delta: { stop_reason: anthropicStopReason, stop_sequence: null },
4954
- usage: { output_tokens: state.usage.output }
4991
+ usage: { output_tokens: state.usage.outputTokens }
4955
4992
  });
4956
4993
  writeEvent(res, "message_stop", { type: "message_stop" });
4957
4994
  res.end();
4958
- return;
4995
+ return state.usage;
4959
4996
  }
4960
4997
  }
4961
4998
  }
@@ -4969,10 +5006,11 @@ async function streamCloudCodeToAnthropic(res, upstreamRes, model, log7) {
4969
5006
  writeEvent(res, "message_delta", {
4970
5007
  type: "message_delta",
4971
5008
  delta: { stop_reason: finalStopReason, stop_sequence: null },
4972
- usage: { output_tokens: state.usage.output }
5009
+ usage: { output_tokens: state.usage.outputTokens }
4973
5010
  });
4974
5011
  writeEvent(res, "message_stop", { type: "message_stop" });
4975
5012
  res.end();
5013
+ return state.usage;
4976
5014
  }
4977
5015
  async function collectCloudCodeToAnthropic(upstreamRes, model, log7) {
4978
5016
  const text4 = await upstreamRes.text();
@@ -4988,8 +5026,8 @@ async function collectCloudCodeToAnthropic(upstreamRes, model, log7) {
4988
5026
  if (!chunk) continue;
4989
5027
  const usage = getUsage(chunk);
4990
5028
  if (usage) {
4991
- inputTokens = usage.input;
4992
- outputTokens = usage.output;
5029
+ inputTokens = usage.inputTokens;
5030
+ outputTokens = usage.outputTokens;
4993
5031
  }
4994
5032
  const candidate = getCandidate(chunk);
4995
5033
  if (!candidate) continue;
@@ -5033,7 +5071,9 @@ async function collectCloudCodeToAnthropic(upstreamRes, model, log7) {
5033
5071
  model,
5034
5072
  stop_reason: stopReason,
5035
5073
  stop_sequence: null,
5036
- usage: { input_tokens: inputTokens, output_tokens: outputTokens }
5074
+ usage: { input_tokens: inputTokens, output_tokens: outputTokens },
5075
+ inputTokens,
5076
+ outputTokens
5037
5077
  };
5038
5078
  }
5039
5079
 
@@ -5100,6 +5140,94 @@ function resolveUpstreamTools(tools, messages) {
5100
5140
  return upstream;
5101
5141
  }
5102
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
+
5103
5231
  // src/gateway/sdk-adapter.ts
5104
5232
  function anthropicEffortFromRequest(body) {
5105
5233
  const effort = body.output_config?.effort;
@@ -5237,11 +5365,32 @@ function translateToolChoice(tc) {
5237
5365
  return void 0;
5238
5366
  }
5239
5367
  function translateRequest2(body, npm, options) {
5240
- const messages = body.messages ?? [];
5368
+ let messages = body.messages ?? [];
5241
5369
  annotateToolNames(messages);
5242
5370
  const baseSystem = systemToString(body.system);
5243
5371
  const inlineParts = inlineSystemText(messages);
5244
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
+ }
5245
5394
  let upstreamTools = resolveUpstreamTools(
5246
5395
  body.tools,
5247
5396
  messages
@@ -5260,11 +5409,11 @@ function translateRequest2(body, npm, options) {
5260
5409
  });
5261
5410
  }
5262
5411
  return {
5263
- system: options?.openAiOAuth ? void 0 : systemText,
5412
+ system: options?.openAiOAuth ? void 0 : trimmedSystem,
5264
5413
  messages: translateMessages(messages, npm),
5265
5414
  tools: translateTools3(upstreamTools.length ? upstreamTools : void 0),
5266
5415
  toolChoice: translateToolChoice(body.tool_choice),
5267
- maxOutputTokens: options?.openAiOAuth ? void 0 : body.max_tokens,
5416
+ maxOutputTokens: options?.openAiOAuth ? void 0 : maxOutput,
5268
5417
  temperature: body.temperature,
5269
5418
  providerOptions
5270
5419
  };
@@ -5472,6 +5621,9 @@ async function generateAnthropicResponse(model, params, modelId, options) {
5472
5621
  import { appendFileSync as appendFileSync2, openSync as openSync2, writeSync as writeSync2, closeSync as closeSync2, readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
5473
5622
  import { join as join9 } from "path";
5474
5623
  var ANALYTICS_FILE = "analytics.jsonl";
5624
+ function normalizeModelKey(modelId) {
5625
+ return modelId.toLowerCase().replace(/\//g, ":").replace(/\s*\([^)]*\)\s*$/g, "").replace(/\s+/g, " ").trim();
5626
+ }
5475
5627
  function analyticsPath() {
5476
5628
  return join9(getAppHome(), ANALYTICS_FILE);
5477
5629
  }
@@ -5576,21 +5728,27 @@ function aggregateAnalytics(range) {
5576
5728
  const hour = Number(e.ts.slice(11, 13));
5577
5729
  if (Number.isFinite(hour) && hour >= 0 && hour < 24) hourCounts[hour] += 1;
5578
5730
  const provider = e.providerId ?? e.npm?.replace(/^@/, "").replace(/\//g, "-") ?? "unknown";
5579
- const key = `${provider}|${e.modelId}`;
5580
- const m = modelMap.get(key) ?? { provider, model: e.modelId, app: e.app, inputTokens: 0, outputTokens: 0 };
5731
+ const key = `${provider}|${normalizeModelKey(e.modelId)}`;
5732
+ const m = modelMap.get(key) ?? { provider, model: e.modelId, app: e.app, apps: /* @__PURE__ */ new Set(), inputTokens: 0, outputTokens: 0 };
5733
+ if (!/\s/.test(m.model) && /\s/.test(e.modelId)) m.model = e.modelId;
5581
5734
  m.inputTokens += e.inputTokens;
5582
5735
  m.outputTokens += e.outputTokens;
5736
+ m.apps.add(e.app);
5583
5737
  modelMap.set(key, m);
5584
5738
  }
5585
- const busiestDay = Math.max(1, ...[...eventsByDay.values()]);
5739
+ const busiestDay = Math.max(1, ...[...tokensByDay.values()]);
5586
5740
  const heatmap = [];
5587
5741
  for (let i = rangeDays(range) - 1; i >= 0; i--) {
5588
5742
  const d = new Date(today);
5589
5743
  d.setUTCDate(today.getUTCDate() - i);
5590
5744
  const date = d.toISOString().slice(0, 10);
5591
- const count = eventsByDay.get(date) ?? 0;
5592
- const intensity = Math.min(4, Math.round(count / busiestDay * 4)) || 0;
5593
- heatmap.push({ date, count, intensity });
5745
+ const tokens = tokensByDay.get(date) ?? 0;
5746
+ let intensity = 0;
5747
+ if (tokens > 0) {
5748
+ const pct = tokens / busiestDay;
5749
+ intensity = Math.max(1, Math.min(4, Math.round(1 + pct * 3)));
5750
+ }
5751
+ heatmap.push({ date, count: tokens, intensity });
5594
5752
  }
5595
5753
  const dailyTokens = [];
5596
5754
  for (let i = rangeDays(range) - 1; i >= 0; i--) {
@@ -5625,12 +5783,14 @@ function aggregateAnalytics(range) {
5625
5783
  }
5626
5784
  const models = [...modelMap.entries()].map(([, m], idx) => {
5627
5785
  const share = totalTokens > 0 ? (m.inputTokens + m.outputTokens) / totalTokens : 0;
5786
+ const apps = [...m.apps];
5628
5787
  return {
5629
5788
  provider: m.provider,
5630
5789
  model: m.model,
5631
5790
  tier: "",
5632
5791
  // source tier isn't tracked in the log; UI shows it from catalog elsewhere
5633
- app: m.app,
5792
+ app: apps[0] ?? m.app,
5793
+ apps,
5634
5794
  inputTokens: m.inputTokens,
5635
5795
  outputTokens: m.outputTokens,
5636
5796
  share,
@@ -5684,6 +5844,10 @@ function makeProxyLog(debug, logPath) {
5684
5844
  appendSecureLog(path, line);
5685
5845
  };
5686
5846
  }
5847
+ var quietErrorLogPath = getProxyDebugLogPath();
5848
+ function quietErrorLog(line) {
5849
+ appendSecureLog(quietErrorLogPath, `[quiet-error] ${line}`);
5850
+ }
5687
5851
  function anthropicError(res, status, message) {
5688
5852
  sendJson(res, status, {
5689
5853
  type: "error",
@@ -5693,7 +5857,8 @@ function anthropicError(res, status, message) {
5693
5857
  function aliasModelId(realId, providerId) {
5694
5858
  if (realId.startsWith("claude-")) return realId;
5695
5859
  const sanitized = providerId.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
5696
- return `anthropic-${sanitized}__${realId}`;
5860
+ const safeRealId = realId.replace(/[\/\s:()]+/g, "-");
5861
+ return `anthropic-${sanitized}__${safeRealId}`;
5697
5862
  }
5698
5863
  function lookupRoute(byAlias, id) {
5699
5864
  for (const key of routeLookupIds(id)) {
@@ -5721,7 +5886,7 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
5721
5886
  process.on("uncaughtException", onException);
5722
5887
  const modelsPayload = JSON.stringify(
5723
5888
  formatAnthropicModelList(
5724
- 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 }))
5725
5890
  )
5726
5891
  );
5727
5892
  const server = createServer(async (req, res) => {
@@ -5738,8 +5903,9 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
5738
5903
  const route = lookupRoute(byAlias, id);
5739
5904
  if (route) {
5740
5905
  res.writeHead(200, { "Content-Type": "application/json" });
5741
- 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)));
5742
5907
  } else {
5908
+ quietErrorLog(`GET /v1/models/${id} - model not found`);
5743
5909
  res.writeHead(404, { "Content-Type": "application/json" });
5744
5910
  res.end(JSON.stringify({ error: { type: "not_found_error", message: `Model '${id}' not found` } }));
5745
5911
  }
@@ -5766,6 +5932,9 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
5766
5932
  const originalModel = anthropicBody.model;
5767
5933
  const clientWantsStream = Boolean(anthropicBody.stream);
5768
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
+ }
5769
5938
  const apiKey = route.apiKey;
5770
5939
  const upstreamUrl = route.upstreamUrl;
5771
5940
  plog(
@@ -5831,7 +6000,8 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
5831
6000
  reasoning: route.reasoning,
5832
6001
  interleavedReasoningField: route.interleavedReasoningField,
5833
6002
  upstreamModelId: route.realModelId
5834
- }
6003
+ },
6004
+ contextWindow: route.contextWindow
5835
6005
  });
5836
6006
  plog(
5837
6007
  () => `sdk: npm=${route.npm} model=${route.realModelId}, stream=${clientWantsStream}, tools=${anthropicBody.tools?.length ?? 0}, msgs=${params.messages.length}`
@@ -5939,12 +6109,22 @@ data: ${JSON.stringify({ type: "error", error: { type: errorType, message } })}
5939
6109
  anthropicError(res, upstream.status >= 500 ? 502 : upstream.status, errBody);
5940
6110
  return;
5941
6111
  }
6112
+ let usage = { inputTokens: 0, outputTokens: 0 };
5942
6113
  if (clientWantsStream) {
5943
- await streamCloudCodeToAnthropic(res, upstream, route.realModelId, plog);
6114
+ usage = await streamCloudCodeToAnthropic(res, upstream, route.realModelId, plog);
5944
6115
  } else {
5945
6116
  const response = await collectCloudCodeToAnthropic(upstream, route.realModelId, plog);
6117
+ usage = { inputTokens: response.inputTokens ?? 0, outputTokens: response.outputTokens ?? 0 };
5946
6118
  sendJson(res, 200, response);
5947
6119
  }
6120
+ recordUsage({
6121
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
6122
+ modelId: route.realModelId,
6123
+ providerId: route.providerId,
6124
+ app: route.app ?? "Antigravity",
6125
+ inputTokens: usage.inputTokens,
6126
+ outputTokens: usage.outputTokens
6127
+ });
5948
6128
  } catch (err) {
5949
6129
  const message = err instanceof Error ? err.message : String(err);
5950
6130
  plog(() => `cloud-code fetch error: ${message}`);
@@ -6841,7 +7021,8 @@ function localModelToRoute(lp, model) {
6841
7021
  reasoning: model.reasoning,
6842
7022
  interleavedReasoningField: model.interleavedReasoningField,
6843
7023
  useResponsesLite: model.useResponsesLite,
6844
- preferWebSockets: model.preferWebSockets
7024
+ preferWebSockets: model.preferWebSockets,
7025
+ inputTypes: resolveInputTypes(model.family, lp.id, model.id)
6845
7026
  };
6846
7027
  }
6847
7028
  function makeRouteResolver(localProviders) {
@@ -7517,7 +7698,8 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
7517
7698
  interleavedReasoningField: model.interleavedReasoningField,
7518
7699
  upstreamModelId: upstreamModelId(model)
7519
7700
  },
7520
- maxTools: npmMaxTools
7701
+ maxTools: npmMaxTools,
7702
+ contextWindow: model.contextWindow ?? resolveContextWindow(model.id)
7521
7703
  });
7522
7704
  const clientWantsStream = Boolean(body.stream);
7523
7705
  const responseModelId = getResponseModelId(body.model, model, options);
@@ -7559,7 +7741,14 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
7559
7741
  if (!res.headersSent) {
7560
7742
  const status = upstreamHttpStatus(err);
7561
7743
  sendJson(res, status === 500 ? 502 : status, { error: { message } });
7562
- } 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
+ }
7563
7752
  }
7564
7753
  return;
7565
7754
  }
@@ -7632,7 +7821,14 @@ async function handleOpenAIChatCompletions(req, res, options, modelCache, plog)
7632
7821
  if (!res.headersSent) {
7633
7822
  const status = upstreamHttpStatus(err);
7634
7823
  sendJson(res, status === 500 ? 502 : status, { error: { message } });
7635
- } 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
+ }
7636
7832
  }
7637
7833
  }
7638
7834
  function lookupModel(res, catalog, modelId) {
@@ -10721,6 +10917,7 @@ export {
10721
10917
  isFreeStatus,
10722
10918
  freeStatusLabel,
10723
10919
  refreshModelsDevCacheAsync,
10920
+ resolveInputTypes,
10724
10921
  shouldHideModel,
10725
10922
  cachedModelToLocal,
10726
10923
  readBody,
@@ -10749,6 +10946,7 @@ export {
10749
10946
  encodeToolUseId,
10750
10947
  serializeToolResultContent,
10751
10948
  translateRequest,
10949
+ recordUsage,
10752
10950
  aggregateAnalytics,
10753
10951
  aliasModelId,
10754
10952
  startProxyCatalog,
@@ -10817,4 +11015,4 @@ export {
10817
11015
  quitClaudeAppGracefully,
10818
11016
  launchOrRestartClaudeApp
10819
11017
  };
10820
- //# sourceMappingURL=chunk-E2MV3GDX.js.map
11018
+ //# sourceMappingURL=chunk-ZEO4BR64.js.map