agent-shim 8.35.0 → 8.36.0

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.
package/dist/cli.cjs CHANGED
@@ -17252,7 +17252,7 @@ var require_readable = __commonJS({
17252
17252
  "node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/api/readable.js"(exports2, module2) {
17253
17253
  "use strict";
17254
17254
  var assert2 = require("node:assert");
17255
- var { Readable: Readable2 } = require("node:stream");
17255
+ var { Readable: Readable3 } = require("node:stream");
17256
17256
  var { RequestAbortedError, NotSupportedError, InvalidArgumentError: InvalidArgumentError2, AbortError: AbortError2 } = require_errors();
17257
17257
  var util = require_util2();
17258
17258
  var { ReadableStreamFrom } = require_util2();
@@ -17266,7 +17266,7 @@ var require_readable = __commonJS({
17266
17266
  var kBytesRead = /* @__PURE__ */ Symbol("kBytesRead");
17267
17267
  var noop = () => {
17268
17268
  };
17269
- var BodyReadable = class extends Readable2 {
17269
+ var BodyReadable = class extends Readable3 {
17270
17270
  /**
17271
17271
  * @param {object} opts
17272
17272
  * @param {(this: Readable, size: number) => void} opts.resume
@@ -17655,7 +17655,7 @@ var require_api_request = __commonJS({
17655
17655
  "use strict";
17656
17656
  var assert2 = require("node:assert");
17657
17657
  var { AsyncResource } = require("node:async_hooks");
17658
- var { Readable: Readable2 } = require_readable();
17658
+ var { Readable: Readable3 } = require_readable();
17659
17659
  var { InvalidArgumentError: InvalidArgumentError2, RequestAbortedError } = require_errors();
17660
17660
  var util = require_util2();
17661
17661
  function noop() {
@@ -17736,7 +17736,7 @@ var require_api_request = __commonJS({
17736
17736
  const parsedHeaders = responseHeaders3 === "raw" ? util.parseHeaders(rawHeaders) : headers;
17737
17737
  const contentType = parsedHeaders["content-type"];
17738
17738
  const contentLength = parsedHeaders["content-length"];
17739
- const res = new Readable2({
17739
+ const res = new Readable3({
17740
17740
  resume,
17741
17741
  abort,
17742
17742
  contentType,
@@ -18045,7 +18045,7 @@ var require_api_pipeline = __commonJS({
18045
18045
  "node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/api/api-pipeline.js"(exports2, module2) {
18046
18046
  "use strict";
18047
18047
  var {
18048
- Readable: Readable2,
18048
+ Readable: Readable3,
18049
18049
  Duplex,
18050
18050
  PassThrough: PassThrough2
18051
18051
  } = require("node:stream");
@@ -18061,7 +18061,7 @@ var require_api_pipeline = __commonJS({
18061
18061
  function noop() {
18062
18062
  }
18063
18063
  var kResume = /* @__PURE__ */ Symbol("resume");
18064
- var PipelineRequest = class extends Readable2 {
18064
+ var PipelineRequest = class extends Readable3 {
18065
18065
  constructor() {
18066
18066
  super({ autoDestroy: true });
18067
18067
  this[kResume] = null;
@@ -18078,7 +18078,7 @@ var require_api_pipeline = __commonJS({
18078
18078
  callback(err);
18079
18079
  }
18080
18080
  };
18081
- var PipelineResponse = class extends Readable2 {
18081
+ var PipelineResponse = class extends Readable3 {
18082
18082
  constructor(resume) {
18083
18083
  super({ autoDestroy: true });
18084
18084
  this[kResume] = resume;
@@ -23060,7 +23060,7 @@ var require_cache2 = __commonJS({
23060
23060
  "node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/interceptor/cache.js"(exports2, module2) {
23061
23061
  "use strict";
23062
23062
  var assert2 = require("node:assert");
23063
- var { Readable: Readable2 } = require("node:stream");
23063
+ var { Readable: Readable3 } = require("node:stream");
23064
23064
  var util = require_util2();
23065
23065
  var CacheHandler = require_cache_handler();
23066
23066
  var MemoryCacheStore = require_memory_cache_store();
@@ -23229,7 +23229,7 @@ var require_cache2 = __commonJS({
23229
23229
  return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler));
23230
23230
  }
23231
23231
  function sendCachedValue(handler, opts, result, age, context, isStale2) {
23232
- const stream = util.isStream(result.body) ? result.body : Readable2.from(result.body ?? []);
23232
+ const stream = util.isStream(result.body) ? result.body : Readable3.from(result.body ?? []);
23233
23233
  assert2(!stream.destroyed, "stream should not be destroyed");
23234
23234
  assert2(!stream.readableDidRead, "stream should not be readableDidRead");
23235
23235
  const controller = {
@@ -26437,7 +26437,7 @@ var require_fetch = __commonJS({
26437
26437
  subresourceSet
26438
26438
  } = require_constants4();
26439
26439
  var EE = require("node:events");
26440
- var { Readable: Readable2, pipeline, finished, isErrored, isReadable } = require("node:stream");
26440
+ var { Readable: Readable3, pipeline, finished, isErrored, isReadable } = require("node:stream");
26441
26441
  var { addAbortListener, bufferToLowerCasedHeaderName } = require_util2();
26442
26442
  var { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require_data_url();
26443
26443
  var { getGlobalDispatcher } = require_global2();
@@ -27380,7 +27380,7 @@ var require_fetch = __commonJS({
27380
27380
  }
27381
27381
  }
27382
27382
  const location = headersList.get("location", true);
27383
- this.body = new Readable2({ read: resume });
27383
+ this.body = new Readable3({ read: resume });
27384
27384
  const willFollow = location && request7.redirect === "follow" && redirectStatusSet.has(status);
27385
27385
  const decoders = [];
27386
27386
  if (request7.method !== "HEAD" && request7.method !== "CONNECT" && !nullBodyStatus.includes(status) && !willFollow) {
@@ -57105,7 +57105,9 @@ var ProviderRouteSchema = external_exports.strictObject({
57105
57105
  /** The condition, the same `when` union a configuration cascade entry takes: the object form or a trilean predicate tree over the request facts the door resolves (`request.model` and kin). */
57106
57106
  when: WhenSchema,
57107
57107
  /** The provider a matching request is sent to, by the name a provider file carries. */
57108
- provider: external_exports.string().min(1)
57108
+ provider: external_exports.string().min(1),
57109
+ /** The model name to rewrite the request to before it reaches the target, for a provider that expects another form (OpenRouter's `anthropic/claude-...` for instance). A route that rewrites reads the whole body, the one copy the rewrite needs. */
57110
+ model: external_exports.string().min(1).optional()
57109
57111
  });
57110
57112
  var HttpProviderSchema = external_exports.strictObject({
57111
57113
  $schema: external_exports.string().optional(),
@@ -60940,7 +60942,15 @@ function resolversOf(context) {
60940
60942
  ...pool?.resuming === void 0 ? {} : { "session.resuming": pool.resuming },
60941
60943
  ...pool?.lastPickHoursAgo === void 0 ? {} : { "session.lastPickHoursAgo": pool.lastPickHoursAgo },
60942
60944
  ...context.request?.model === void 0 ? {} : { "request.model": context.request.model },
60943
- ...context.request?.hasImage === void 0 ? {} : { "request.hasImage": context.request.hasImage }
60945
+ ...context.request?.hasImage === void 0 ? {} : { "request.hasImage": context.request.hasImage },
60946
+ ...context.providerQuota === void 0 ? {} : Object.fromEntries(
60947
+ Object.entries(context.providerQuota).flatMap(
60948
+ ([name, windows]) => [
60949
+ ...windows.fiveHour === void 0 ? [] : [["provider." + name + ".fiveHour.remaining", windows.fiveHour.remaining], ["provider." + name + ".fiveHour.utilization", windows.fiveHour.utilization], ["provider." + name + ".fiveHour.hoursUntilReset", windows.fiveHour.hoursUntilReset]],
60950
+ ...windows.sevenDay === void 0 ? [] : [["provider." + name + ".sevenDay.remaining", windows.sevenDay.remaining], ["provider." + name + ".sevenDay.utilization", windows.sevenDay.utilization], ["provider." + name + ".sevenDay.hoursUntilReset", windows.sevenDay.hoursUntilReset]]
60951
+ ]
60952
+ )
60953
+ )
60944
60954
  };
60945
60955
  return {
60946
60956
  resolveValue: (key) => {
@@ -61006,6 +61016,24 @@ function evaluateWhen(when, context) {
61006
61016
  }
61007
61017
  return { status: "definite", passed: failed.length === 0, checked, failed };
61008
61018
  }
61019
+ function referencesFact(when, key) {
61020
+ if (when === void 0 || !("kind" in when)) {
61021
+ return false;
61022
+ }
61023
+ const walk = (node2) => {
61024
+ if (Array.isArray(node2)) {
61025
+ return node2.some(walk);
61026
+ }
61027
+ if (typeof node2 !== "object" || node2 === null) {
61028
+ return false;
61029
+ }
61030
+ if ("kind" in node2 && node2.kind === "reference" && "key" in node2 && node2.key === key) {
61031
+ return true;
61032
+ }
61033
+ return Object.values(node2).some(walk);
61034
+ };
61035
+ return walk(when);
61036
+ }
61009
61037
  function isVacuousWhen(when) {
61010
61038
  return when !== void 0 && !("kind" in when) && Object.keys(when).length === 0;
61011
61039
  }
@@ -63675,7 +63703,7 @@ function registerIdentityCommand(program2, deps) {
63675
63703
  // package.json
63676
63704
  var package_default = {
63677
63705
  name: "agent-shim",
63678
- version: "8.35.0",
63706
+ version: "8.36.0",
63679
63707
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
63680
63708
  license: "MIT",
63681
63709
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -77392,12 +77420,15 @@ function createPassthroughRoute(name, target) {
77392
77420
  };
77393
77421
  }
77394
77422
 
77423
+ // src/frontdoor/providerRoute.ts
77424
+ var import_node_stream3 = require("node:stream");
77425
+
77395
77426
  // src/frontdoor/requestScan.ts
77396
77427
  var import_node_stream2 = require("node:stream");
77397
77428
  var BYTES_PER_KIB = 1024;
77398
77429
  var SCAN_KIB = 64;
77399
77430
  var REQUEST_SCAN_CAP_BYTES = SCAN_KIB * BYTES_PER_KIB;
77400
- async function scanRequestHead(request7) {
77431
+ async function scanRequestHead(request7, wholeBody = false) {
77401
77432
  const body = request7.body;
77402
77433
  const head = [];
77403
77434
  let seen = 0;
@@ -77414,7 +77445,7 @@ async function scanRequestHead(request7) {
77414
77445
  for (const chunk of head) {
77415
77446
  replay.write(chunk);
77416
77447
  }
77417
- resolve({ ...model === void 0 ? {} : { model }, hasImage, replayed: { ...request7, body: replay } });
77448
+ resolve({ ...model === void 0 ? {} : { model }, hasImage, ...wholeBody ? { whole: true, text: text2 } : {}, replayed: { ...request7, body: replay } });
77418
77449
  };
77419
77450
  body.on("data", (chunk) => {
77420
77451
  if (decided) {
@@ -77429,7 +77460,7 @@ async function scanRequestHead(request7) {
77429
77460
  head.push(chunk);
77430
77461
  seen += chunk.length;
77431
77462
  text2 += chunk.toString("utf8");
77432
- if (modelIn() !== void 0 || seen >= REQUEST_SCAN_CAP_BYTES) {
77463
+ if (!wholeBody && (modelIn() !== void 0 || seen >= REQUEST_SCAN_CAP_BYTES)) {
77433
77464
  decided = true;
77434
77465
  body.pause();
77435
77466
  replay.once("resume", () => {
@@ -77461,6 +77492,7 @@ async function scanRequestHead(request7) {
77461
77492
  }
77462
77493
 
77463
77494
  // src/frontdoor/providerRoute.ts
77495
+ var MS_PER_HOUR3 = 36e5;
77464
77496
  function createProviderRouteResolver(deps) {
77465
77497
  const isRcSelfHostPath = (path46) => path46 === "/v1/code/sessions" || path46.startsWith("/v1/code/sessions/") || path46 === "/v1/sessions" || path46.startsWith("/v1/sessions/");
77466
77498
  const oauthRoute = createPassthroughRoute("anthropic", { baseUrl: `https://${CONNECT_INTERCEPT_HOST}:${String(HTTPS_PORT)}`, stripPrefix: void 0, headroomUpstream: void 0 });
@@ -77524,13 +77556,13 @@ function createProviderRouteResolver(deps) {
77524
77556
  )
77525
77557
  };
77526
77558
  };
77527
- const servingRewritten = (route, url2, body) => ({
77559
+ const servingRewritten = (route, rewritten) => ({
77528
77560
  name: route.name,
77529
77561
  headroomEligible: route.headroomEligible,
77530
77562
  headroomUpstream: route.headroomUpstream,
77531
- // The pipeline serves the route with the request it received; the routing layer's decisions (the rewritten target path, the replayed body) are substituted here, so the route sees exactly the request the resolution acted on.
77563
+ // The pipeline serves the route with the request it received; the routing layer's decisions (the rewritten target path, the replayed body and, when the model name was rewritten, the re-framed headers) are substituted here, so the route sees exactly the request the resolution acted on.
77532
77564
  serve: async (request7, response) => {
77533
- await route.serve({ ...request7, url: url2, body }, response);
77565
+ await route.serve({ ...request7, url: rewritten.url, headers: rewritten.headers, body: rewritten.body }, response);
77534
77566
  }
77535
77567
  });
77536
77568
  return async (request7) => {
@@ -77556,30 +77588,49 @@ function createProviderRouteResolver(deps) {
77556
77588
  }
77557
77589
  if (routes === void 0 || routes.length === 0) {
77558
77590
  const resolution = resolve(current);
77559
- return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, current.url, replay.body) } : resolution;
77591
+ return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }) } : resolution;
77560
77592
  }
77561
- const scan = await scanRequestHead(current);
77593
+ const whole = routes.some((entry) => entry.model !== void 0 || referencesFact(entry.when, "request.hasImage"));
77594
+ const snapshot = deps.usageSnapshotOf?.(current.session.identity);
77595
+ const windowFacts = (raw) => {
77596
+ if (raw?.utilization === void 0 || raw.resetsAt === void 0) {
77597
+ return void 0;
77598
+ }
77599
+ return { remaining: Math.max(0, 1 - raw.utilization), utilization: raw.utilization, hoursUntilReset: Math.max(0, (Date.parse(raw.resetsAt) - Date.now()) / MS_PER_HOUR3) };
77600
+ };
77601
+ const providerQuota = Object.fromEntries(
77602
+ routes.flatMap((entry) => {
77603
+ const unified = snapshot?.providers[entry.provider]?.rateLimit?.unified;
77604
+ return [[entry.provider, { fiveHour: windowFacts(unified?.fiveHour), sevenDay: windowFacts(unified?.sevenDay) }]];
77605
+ })
77606
+ );
77607
+ const scan = await scanRequestHead(current, whole);
77562
77608
  if (scan.replayed === void 0) {
77563
77609
  const resolution = resolve(current);
77564
- return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, current.url, replay.body) } : resolution;
77610
+ return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }) } : resolution;
77565
77611
  }
77566
77612
  replay = scan.replayed;
77567
- const context = { nowMs: Date.now(), env: deps.env, ...scan.model === void 0 && scan.hasImage === void 0 ? {} : { request: { ...scan.model === void 0 ? {} : { model: scan.model }, hasImage: scan.hasImage } } };
77613
+ const context = { nowMs: Date.now(), env: deps.env, providerQuota, ...scan.model === void 0 && scan.hasImage === void 0 ? {} : { request: { ...scan.model === void 0 ? {} : { model: scan.model }, hasImage: scan.hasImage } } };
77568
77614
  let matched;
77569
77615
  for (const entry of routes) {
77570
77616
  const verdict = evaluateWhen(entry.when, context);
77571
77617
  if (verdict.status === "definite" && verdict.passed) {
77572
- matched = entry.provider;
77618
+ matched = { provider: entry.provider, model: entry.model };
77573
77619
  break;
77574
77620
  }
77575
77621
  }
77576
77622
  if (matched === void 0) {
77577
77623
  const resolution = resolve(current);
77578
- return resolution.ok ? { ok: true, route: servingRewritten(resolution.route, current.url, replay.body) } : resolution;
77624
+ return resolution.ok ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }) } : resolution;
77625
+ }
77626
+ if (matched.model !== void 0 && scan.text !== void 0 && scan.model !== void 0) {
77627
+ const rewritten = scan.text.replace(new RegExp('"model":\\s*"' + scan.model.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + '"'), '"model":"' + matched.model + '"');
77628
+ const headers = Object.fromEntries(Object.entries(replay.headers).filter(([name]) => name.toLowerCase() !== "content-length"));
77629
+ replay = { ...replay, headers, body: import_node_stream3.Readable.from([Buffer.from(rewritten, "utf8")]) };
77579
77630
  }
77580
77631
  const rest = scoped === void 0 ? path46 : path46.slice(`${PROVIDER_PATH_PREFIX}${encodeURIComponent(scoped.provider)}`.length);
77581
77632
  const query = current.url.includes("?") ? current.url.slice(current.url.indexOf("?")) : "";
77582
- current = { ...current, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(matched)}${rest}${query}`, body: replay.body };
77633
+ current = { ...current, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(matched.provider)}${rest}${query}`, body: replay.body, headers: replay.headers };
77583
77634
  }
77584
77635
  };
77585
77636
  }
@@ -80710,6 +80761,7 @@ function realFrontDoorSupervisorPorts(paths) {
80710
80761
  appendLog(paths, `frontdoor ${String(process.pid)}: ${line}`);
80711
80762
  }
80712
80763
  });
80764
+ const routingSnapshots = /* @__PURE__ */ new Map();
80713
80765
  const rcControlToken = (0, import_node_crypto15.randomUUID)();
80714
80766
  const resolveRoute = rcObservingResolver(
80715
80767
  createProviderRouteResolver({
@@ -80720,6 +80772,7 @@ function realFrontDoorSupervisorPorts(paths) {
80720
80772
  // The same port (cache included) the launcher resolves a launch's provider with, so the credential the door attaches at the route and the one the launcher handed the child are the same resolution of the same block.
80721
80773
  env: process.env,
80722
80774
  credentials: { ...realCredentialPort, cache: realCredentialCacheEnv(paths) },
80775
+ usageSnapshotOf: (identity) => identity === void 0 ? void 0 : routingSnapshots.get(identity) ?? readUsageSnapshot(realFarmFs, paths.usageSnapshotsDir, identity),
80723
80776
  ...rcSelfHostSurface === void 0 ? {} : { rcSelfHostRoute: rcSelfHostSurface.route }
80724
80777
  }),
80725
80778
  rcTracker,
@@ -80734,6 +80787,7 @@ function realFrontDoorSupervisorPorts(paths) {
80734
80787
  readAccount: createAccountReader(realFarmFs, paths.identitiesDir),
80735
80788
  log,
80736
80789
  publish: (snapshot) => {
80790
+ routingSnapshots.set(snapshot.identity, snapshot);
80737
80791
  usagePublisher.publish(snapshot);
80738
80792
  }
80739
80793
  });
@@ -82754,13 +82808,13 @@ function formatLimit(limit) {
82754
82808
  return `last limit: ${limit.kind} (${String(limit.status)}) at ${limit.observedAt}${limit.window === void 0 ? "" : ` on the ${limit.window} window`}${wait2.length === 0 ? "" : `, ${wait2.join(", ")}`}`;
82755
82809
  }
82756
82810
  var MONEY_DECIMALS = 2;
82757
- var MS_PER_HOUR3 = 36e5;
82811
+ var MS_PER_HOUR4 = 36e5;
82758
82812
  var HOURS_PER_DAY4 = 24;
82759
82813
  function formatPeriod(window) {
82760
82814
  if (window.periodMs === void 0) {
82761
82815
  return window.period ?? "unknown period";
82762
82816
  }
82763
- const hours = window.periodMs / MS_PER_HOUR3;
82817
+ const hours = window.periodMs / MS_PER_HOUR4;
82764
82818
  return hours >= HOURS_PER_DAY4 && Number.isInteger(hours / HOURS_PER_DAY4) ? `${String(hours / HOURS_PER_DAY4)}d` : `${String(hours)}h`;
82765
82819
  }
82766
82820
  function formatCount(value2) {
package/dist/index.cjs CHANGED
@@ -593,7 +593,9 @@ var ProviderRouteSchema = import_zod.z.strictObject({
593
593
  /** The condition, the same `when` union a configuration cascade entry takes: the object form or a trilean predicate tree over the request facts the door resolves (`request.model` and kin). */
594
594
  when: WhenSchema,
595
595
  /** The provider a matching request is sent to, by the name a provider file carries. */
596
- provider: import_zod.z.string().min(1)
596
+ provider: import_zod.z.string().min(1),
597
+ /** The model name to rewrite the request to before it reaches the target, for a provider that expects another form (OpenRouter's `anthropic/claude-...` for instance). A route that rewrites reads the whole body, the one copy the rewrite needs. */
598
+ model: import_zod.z.string().min(1).optional()
597
599
  });
598
600
  var HttpProviderSchema = import_zod.z.strictObject({
599
601
  $schema: import_zod.z.string().optional(),
@@ -1028,7 +1030,15 @@ function resolversOf(context) {
1028
1030
  ...pool?.resuming === void 0 ? {} : { "session.resuming": pool.resuming },
1029
1031
  ...pool?.lastPickHoursAgo === void 0 ? {} : { "session.lastPickHoursAgo": pool.lastPickHoursAgo },
1030
1032
  ...context.request?.model === void 0 ? {} : { "request.model": context.request.model },
1031
- ...context.request?.hasImage === void 0 ? {} : { "request.hasImage": context.request.hasImage }
1033
+ ...context.request?.hasImage === void 0 ? {} : { "request.hasImage": context.request.hasImage },
1034
+ ...context.providerQuota === void 0 ? {} : Object.fromEntries(
1035
+ Object.entries(context.providerQuota).flatMap(
1036
+ ([name, windows]) => [
1037
+ ...windows.fiveHour === void 0 ? [] : [["provider." + name + ".fiveHour.remaining", windows.fiveHour.remaining], ["provider." + name + ".fiveHour.utilization", windows.fiveHour.utilization], ["provider." + name + ".fiveHour.hoursUntilReset", windows.fiveHour.hoursUntilReset]],
1038
+ ...windows.sevenDay === void 0 ? [] : [["provider." + name + ".sevenDay.remaining", windows.sevenDay.remaining], ["provider." + name + ".sevenDay.utilization", windows.sevenDay.utilization], ["provider." + name + ".sevenDay.hoursUntilReset", windows.sevenDay.hoursUntilReset]]
1039
+ ]
1040
+ )
1041
+ )
1032
1042
  };
1033
1043
  return {
1034
1044
  resolveValue: (key) => {
@@ -5409,7 +5419,7 @@ var import_undici = require("undici");
5409
5419
  // package.json
5410
5420
  var package_default = {
5411
5421
  name: "agent-shim",
5412
- version: "8.35.0",
5422
+ version: "8.36.0",
5413
5423
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5414
5424
  license: "MIT",
5415
5425
  author: "Joseph Mearman <joseph@mearman.co.uk>",
package/dist/index.mjs CHANGED
@@ -281,7 +281,9 @@ var ProviderRouteSchema = z.strictObject({
281
281
  /** The condition, the same `when` union a configuration cascade entry takes: the object form or a trilean predicate tree over the request facts the door resolves (`request.model` and kin). */
282
282
  when: WhenSchema,
283
283
  /** The provider a matching request is sent to, by the name a provider file carries. */
284
- provider: z.string().min(1)
284
+ provider: z.string().min(1),
285
+ /** The model name to rewrite the request to before it reaches the target, for a provider that expects another form (OpenRouter's `anthropic/claude-...` for instance). A route that rewrites reads the whole body, the one copy the rewrite needs. */
286
+ model: z.string().min(1).optional()
285
287
  });
286
288
  var HttpProviderSchema = z.strictObject({
287
289
  $schema: z.string().optional(),
@@ -716,7 +718,15 @@ function resolversOf(context) {
716
718
  ...pool?.resuming === void 0 ? {} : { "session.resuming": pool.resuming },
717
719
  ...pool?.lastPickHoursAgo === void 0 ? {} : { "session.lastPickHoursAgo": pool.lastPickHoursAgo },
718
720
  ...context.request?.model === void 0 ? {} : { "request.model": context.request.model },
719
- ...context.request?.hasImage === void 0 ? {} : { "request.hasImage": context.request.hasImage }
721
+ ...context.request?.hasImage === void 0 ? {} : { "request.hasImage": context.request.hasImage },
722
+ ...context.providerQuota === void 0 ? {} : Object.fromEntries(
723
+ Object.entries(context.providerQuota).flatMap(
724
+ ([name, windows]) => [
725
+ ...windows.fiveHour === void 0 ? [] : [["provider." + name + ".fiveHour.remaining", windows.fiveHour.remaining], ["provider." + name + ".fiveHour.utilization", windows.fiveHour.utilization], ["provider." + name + ".fiveHour.hoursUntilReset", windows.fiveHour.hoursUntilReset]],
726
+ ...windows.sevenDay === void 0 ? [] : [["provider." + name + ".sevenDay.remaining", windows.sevenDay.remaining], ["provider." + name + ".sevenDay.utilization", windows.sevenDay.utilization], ["provider." + name + ".sevenDay.hoursUntilReset", windows.sevenDay.hoursUntilReset]]
727
+ ]
728
+ )
729
+ )
720
730
  };
721
731
  return {
722
732
  resolveValue: (key) => {
@@ -5097,7 +5107,7 @@ import { Agent as Agent3, fetch as undiciFetch } from "undici";
5097
5107
  // package.json
5098
5108
  var package_default = {
5099
5109
  name: "agent-shim",
5100
- version: "8.35.0",
5110
+ version: "8.36.0",
5101
5111
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5102
5112
  license: "MIT",
5103
5113
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -520,6 +520,7 @@ declare const ProviderSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
520
520
  key: z.ZodType<trilean.JsonValue, unknown, z.core.$ZodTypeInternals<trilean.JsonValue, unknown>>;
521
521
  }, z.core.$strip>], "kind">]>;
522
522
  provider: z.ZodString;
523
+ model: z.ZodOptional<z.ZodString>;
523
524
  }, z.core.$strict>>>;
524
525
  }, z.core.$strict>, z.ZodObject<{
525
526
  $schema: z.ZodOptional<z.ZodString>;
@@ -7115,6 +7116,11 @@ interface ConditionContext {
7115
7116
  readonly model?: string;
7116
7117
  readonly hasImage?: boolean;
7117
7118
  };
7119
+ /** Per-provider quota facts for request routing, keyed by provider name, from the session identity's usage snapshot: a route condition names a target's windows (`provider.<name>.fiveHour.utilization` and kin) to skip one that is exhausted or nearly spent. The windows are the same shape the pool facts read. */
7120
+ readonly providerQuota?: Readonly<Record<string, {
7121
+ readonly fiveHour?: PoolWindowFacts;
7122
+ readonly sevenDay?: PoolWindowFacts;
7123
+ }>>;
7118
7124
  }
7119
7125
  /**
7120
7126
  * The result of evaluating one `when`: definite, with which condition fields were present and which of those did not hold, or indeterminate, when a datum the condition needed is missing. Indeterminate is not false: a missing fact has not failed the condition, it has left it undecided, and the consumer decides what an undecided entry does (the resolver keeps today's behaviour of not passing it, so nothing changes for existing configurations; the pool ranking of #258 instead keeps such a member but ranks it last, naming the missing fact).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-shim",
3
- "version": "8.35.0",
3
+ "version": "8.36.0",
4
4
  "description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5
5
  "license": "MIT",
6
6
  "author": "Joseph Mearman <joseph@mearman.co.uk>",