easyrouter-config 1.0.7 → 1.0.8

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 (2) hide show
  1. package/dist/index.js +58 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import { parseArgs } from "util";
20
20
  import pc from "picocolors";
21
21
 
22
22
  // src/config/constants.ts
23
- var VERSION = true ? "1.0.7" : "0.0.0-dev";
23
+ var VERSION = true ? "1.0.8" : "0.0.0-dev";
24
24
  var PRIMARY_HOST = "https://easyrouter.io";
25
25
  var FALLBACK_HOSTS = ["https://ezr.sh"];
26
26
  var HOST_PROBE_TIMEOUT_MS = 5e3;
@@ -362,7 +362,46 @@ var claudeClient = {
362
362
  // src/config/models.ts
363
363
  import { log as log2, select, isCancel } from "@clack/prompts";
364
364
  import pc4 from "picocolors";
365
- function toOpenClawCost(m) {
365
+ async function fetchOpenRouterContextMap(verbose) {
366
+ const map = /* @__PURE__ */ new Map();
367
+ try {
368
+ const ctrl = new AbortController();
369
+ const timer = setTimeout(() => ctrl.abort(), FETCH_MODELS_TIMEOUT_MS);
370
+ const res = await fetch("https://openrouter.ai/api/v1/models", {
371
+ signal: ctrl.signal,
372
+ headers: { "User-Agent": "easyrouter-config/1.0" }
373
+ });
374
+ clearTimeout(timer);
375
+ if (!res.ok) return map;
376
+ const json = await res.json();
377
+ const models = Array.isArray(json?.data) ? json.data : [];
378
+ for (const m of models) {
379
+ const short = m.id.split("/").pop() ?? m.id;
380
+ const ctx = m.context_length ?? 0;
381
+ const maxOut = m.max_completion_tokens ?? Math.min(32768, Math.max(4096, Math.floor(ctx / 4)));
382
+ const entry = { contextLength: ctx, maxTokens: maxOut };
383
+ map.set(short.toLowerCase(), entry);
384
+ map.set(normalizeModelId(short), entry);
385
+ }
386
+ if (verbose) log2.info(`\u2713 OpenRouter: \u62C9\u53D6\u5230 ${models.length} \u4E2A\u6A21\u578B\u4E0A\u4E0B\u6587\u4FE1\u606F`);
387
+ } catch (err) {
388
+ if (verbose) log2.warn(`OpenRouter \u62C9\u53D6\u5931\u8D25\uFF1A${err?.message}\uFF08\u5C06\u7528\u515C\u5E95 contextWindow\uFF09`);
389
+ }
390
+ return map;
391
+ }
392
+ function normalizeModelId(s) {
393
+ s = s.replace(/-\d{6}$/, "");
394
+ s = s.replace(/(?<=[a-zA-Z])-(\d+)-(\d+)(?=-|$)/g, "-$1.$2");
395
+ return s.toLowerCase();
396
+ }
397
+ var _orContextMapPromise = null;
398
+ function getOpenRouterContextMap(verbose) {
399
+ if (!_orContextMapPromise) {
400
+ _orContextMapPromise = fetchOpenRouterContextMap(verbose);
401
+ }
402
+ return _orContextMapPromise;
403
+ }
404
+ function toOpenClawCost(m, orContextMap) {
366
405
  const ratio = m.model_ratio ?? 0;
367
406
  const compRatio = m.completion_ratio ?? 1;
368
407
  const cacheRatio = m.cache_ratio ?? 0;
@@ -370,9 +409,16 @@ function toOpenClawCost(m) {
370
409
  const output = round6(ratio * compRatio * 2e-3);
371
410
  const cacheRead = round6(ratio * cacheRatio * 2e-3);
372
411
  const cacheWrite = round6(input * 1.25);
373
- const tiered = m.tiered_pricing;
374
- const contextWindow = tiered?.input?.threshold ?? tiered?.output?.threshold ?? tiered?.cache_read?.threshold ?? 131072;
375
- const maxTokens = Math.min(32768, Math.max(4096, Math.floor(contextWindow / 4)));
412
+ let contextWindow = 131072;
413
+ let maxTokens = 32768;
414
+ if (orContextMap) {
415
+ const name = m.model_name;
416
+ const hit = orContextMap.get(name.toLowerCase()) ?? orContextMap.get(normalizeModelId(name));
417
+ if (hit && hit.contextLength > 0) {
418
+ contextWindow = hit.contextLength;
419
+ maxTokens = hit.maxTokens;
420
+ }
421
+ }
376
422
  return {
377
423
  cost: { input, output, cacheRead, cacheWrite },
378
424
  contextWindow,
@@ -577,7 +623,8 @@ var openClawClient = {
577
623
  await runOpenClawSubprocess(args, ctx);
578
624
  let registered = 0;
579
625
  if (llms.length > 1) {
580
- registered = await patchOpenClawJson(llms, defaultModel, ctx);
626
+ const orContextMap = await getOpenRouterContextMap(ctx.verbose);
627
+ registered = await patchOpenClawJson(llms, defaultModel, ctx, orContextMap);
581
628
  }
582
629
  return {
583
630
  configPaths: ["~/.openclaw/openclaw.json"],
@@ -585,7 +632,7 @@ var openClawClient = {
585
632
  };
586
633
  }
587
634
  };
588
- async function patchOpenClawJson(llms, defaultModel, ctx) {
635
+ async function patchOpenClawJson(llms, defaultModel, ctx, orContextMap) {
589
636
  const configPath = join(homedir(), ".openclaw", "openclaw.json");
590
637
  let json;
591
638
  try {
@@ -623,11 +670,13 @@ async function patchOpenClawJson(llms, defaultModel, ctx) {
623
670
  let updated = 0;
624
671
  const agentsModels = json?.agents?.defaults?.models ?? null;
625
672
  for (const m of llms) {
626
- const { cost, contextWindow, maxTokens } = toOpenClawCost(m);
673
+ const { cost, contextWindow, maxTokens } = toOpenClawCost(m, orContextMap);
627
674
  const idx = existingById.get(m.model_name);
628
675
  if (idx !== void 0) {
629
676
  const existing = provider.models[idx];
630
- if (existing.cost?.input === 0 && existing.cost?.output === 0) {
677
+ const costChanged = existing.cost?.input !== cost.input || existing.cost?.output !== cost.output;
678
+ const ctxChanged = existing.contextWindow !== contextWindow;
679
+ if (costChanged || ctxChanged) {
631
680
  existing.cost = cost;
632
681
  existing.contextWindow = contextWindow;
633
682
  existing.maxTokens = maxTokens;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easyrouter-config",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "🚀 一键把 EasyRouter 接入 Claude Code & Codex —— 粘贴 Key 即用",
5
5
  "type": "module",
6
6
  "bin": {