agent-shim 8.35.0 → 8.37.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,19 @@ 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.request?.toolsPresent === void 0 ? {} : { "request.toolsPresent": context.request.toolsPresent },
60947
+ ...context.request?.thinking === void 0 ? {} : { "request.thinking": context.request.thinking },
60948
+ ...context.request?.maxTokens === void 0 ? {} : { "request.maxTokens": context.request.maxTokens },
60949
+ ...context.request?.isCountTokens === void 0 ? {} : { "request.isCountTokens": context.request.isCountTokens },
60950
+ ...context.providerQuota === void 0 ? {} : Object.fromEntries(
60951
+ Object.entries(context.providerQuota).flatMap(
60952
+ ([name, windows]) => [
60953
+ ...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]],
60954
+ ...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]]
60955
+ ]
60956
+ )
60957
+ )
60944
60958
  };
60945
60959
  return {
60946
60960
  resolveValue: (key) => {
@@ -61006,6 +61020,24 @@ function evaluateWhen(when, context) {
61006
61020
  }
61007
61021
  return { status: "definite", passed: failed.length === 0, checked, failed };
61008
61022
  }
61023
+ function referencesFact(when, key) {
61024
+ if (when === void 0 || !("kind" in when)) {
61025
+ return false;
61026
+ }
61027
+ const walk = (node2) => {
61028
+ if (Array.isArray(node2)) {
61029
+ return node2.some(walk);
61030
+ }
61031
+ if (typeof node2 !== "object" || node2 === null) {
61032
+ return false;
61033
+ }
61034
+ if ("kind" in node2 && node2.kind === "reference" && "key" in node2 && node2.key === key) {
61035
+ return true;
61036
+ }
61037
+ return Object.values(node2).some(walk);
61038
+ };
61039
+ return walk(when);
61040
+ }
61009
61041
  function isVacuousWhen(when) {
61010
61042
  return when !== void 0 && !("kind" in when) && Object.keys(when).length === 0;
61011
61043
  }
@@ -63675,7 +63707,7 @@ function registerIdentityCommand(program2, deps) {
63675
63707
  // package.json
63676
63708
  var package_default = {
63677
63709
  name: "agent-shim",
63678
- version: "8.35.0",
63710
+ version: "8.37.0",
63679
63711
  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
63712
  license: "MIT",
63681
63713
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -77392,12 +77424,15 @@ function createPassthroughRoute(name, target) {
77392
77424
  };
77393
77425
  }
77394
77426
 
77427
+ // src/frontdoor/providerRoute.ts
77428
+ var import_node_stream3 = require("node:stream");
77429
+
77395
77430
  // src/frontdoor/requestScan.ts
77396
77431
  var import_node_stream2 = require("node:stream");
77397
77432
  var BYTES_PER_KIB = 1024;
77398
77433
  var SCAN_KIB = 64;
77399
77434
  var REQUEST_SCAN_CAP_BYTES = SCAN_KIB * BYTES_PER_KIB;
77400
- async function scanRequestHead(request7) {
77435
+ async function scanRequestHead(request7, wholeBody = false) {
77401
77436
  const body = request7.body;
77402
77437
  const head = [];
77403
77438
  let seen = 0;
@@ -77414,7 +77449,17 @@ async function scanRequestHead(request7) {
77414
77449
  for (const chunk of head) {
77415
77450
  replay.write(chunk);
77416
77451
  }
77417
- resolve({ ...model === void 0 ? {} : { model }, hasImage, replayed: { ...request7, body: replay } });
77452
+ const maxTokens = /"max_tokens"\s*:\s*([0-9]+)/.exec(text2)?.[1];
77453
+ resolve({
77454
+ ...model === void 0 ? {} : { model },
77455
+ hasImage,
77456
+ toolsPresent: /"tools"\s*:\s*\[\s*\{/.test(text2),
77457
+ thinking: /"thinking"\s*:\s*\{\s*"type"\s*:\s*"enabled"/.test(text2),
77458
+ ...maxTokens === void 0 ? {} : { maxTokens: Number(maxTokens) },
77459
+ isCountTokens: request7.url.includes("/v1/messages/count_tokens"),
77460
+ ...wholeBody ? { whole: true, text: text2 } : {},
77461
+ replayed: { ...request7, body: replay }
77462
+ });
77418
77463
  };
77419
77464
  body.on("data", (chunk) => {
77420
77465
  if (decided) {
@@ -77429,7 +77474,7 @@ async function scanRequestHead(request7) {
77429
77474
  head.push(chunk);
77430
77475
  seen += chunk.length;
77431
77476
  text2 += chunk.toString("utf8");
77432
- if (modelIn() !== void 0 || seen >= REQUEST_SCAN_CAP_BYTES) {
77477
+ if (!wholeBody && (modelIn() !== void 0 || seen >= REQUEST_SCAN_CAP_BYTES)) {
77433
77478
  decided = true;
77434
77479
  body.pause();
77435
77480
  replay.once("resume", () => {
@@ -77461,6 +77506,7 @@ async function scanRequestHead(request7) {
77461
77506
  }
77462
77507
 
77463
77508
  // src/frontdoor/providerRoute.ts
77509
+ var MS_PER_HOUR3 = 36e5;
77464
77510
  function createProviderRouteResolver(deps) {
77465
77511
  const isRcSelfHostPath = (path46) => path46 === "/v1/code/sessions" || path46.startsWith("/v1/code/sessions/") || path46 === "/v1/sessions" || path46.startsWith("/v1/sessions/");
77466
77512
  const oauthRoute = createPassthroughRoute("anthropic", { baseUrl: `https://${CONNECT_INTERCEPT_HOST}:${String(HTTPS_PORT)}`, stripPrefix: void 0, headroomUpstream: void 0 });
@@ -77524,13 +77570,13 @@ function createProviderRouteResolver(deps) {
77524
77570
  )
77525
77571
  };
77526
77572
  };
77527
- const servingRewritten = (route, url2, body) => ({
77573
+ const servingRewritten = (route, rewritten) => ({
77528
77574
  name: route.name,
77529
77575
  headroomEligible: route.headroomEligible,
77530
77576
  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.
77577
+ // 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
77578
  serve: async (request7, response) => {
77533
- await route.serve({ ...request7, url: url2, body }, response);
77579
+ await route.serve({ ...request7, url: rewritten.url, headers: rewritten.headers, body: rewritten.body }, response);
77534
77580
  }
77535
77581
  });
77536
77582
  return async (request7) => {
@@ -77556,30 +77602,57 @@ function createProviderRouteResolver(deps) {
77556
77602
  }
77557
77603
  if (routes === void 0 || routes.length === 0) {
77558
77604
  const resolution = resolve(current);
77559
- return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, current.url, replay.body) } : resolution;
77605
+ return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }) } : resolution;
77560
77606
  }
77561
- const scan = await scanRequestHead(current);
77607
+ const whole = routes.some((entry) => entry.model !== void 0 || referencesFact(entry.when, "request.hasImage"));
77608
+ const snapshot = deps.usageSnapshotOf?.(current.session.identity);
77609
+ const windowFacts = (raw) => {
77610
+ if (raw?.utilization === void 0 || raw.resetsAt === void 0) {
77611
+ return void 0;
77612
+ }
77613
+ return { remaining: Math.max(0, 1 - raw.utilization), utilization: raw.utilization, hoursUntilReset: Math.max(0, (Date.parse(raw.resetsAt) - Date.now()) / MS_PER_HOUR3) };
77614
+ };
77615
+ const providerQuota = Object.fromEntries(
77616
+ routes.flatMap((entry) => {
77617
+ const unified = snapshot?.providers[entry.provider]?.rateLimit?.unified;
77618
+ return [[entry.provider, { fiveHour: windowFacts(unified?.fiveHour), sevenDay: windowFacts(unified?.sevenDay) }]];
77619
+ })
77620
+ );
77621
+ const scan = await scanRequestHead(current, whole);
77562
77622
  if (scan.replayed === void 0) {
77563
77623
  const resolution = resolve(current);
77564
- return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, current.url, replay.body) } : resolution;
77624
+ return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }) } : resolution;
77565
77625
  }
77566
77626
  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 } } };
77627
+ const requestFacts = {
77628
+ ...scan.model === void 0 ? {} : { model: scan.model },
77629
+ ...scan.hasImage === void 0 ? {} : { hasImage: scan.hasImage },
77630
+ ...scan.toolsPresent === void 0 ? {} : { toolsPresent: scan.toolsPresent },
77631
+ ...scan.thinking === void 0 ? {} : { thinking: scan.thinking },
77632
+ ...scan.maxTokens === void 0 ? {} : { maxTokens: scan.maxTokens },
77633
+ ...scan.isCountTokens === void 0 ? {} : { isCountTokens: scan.isCountTokens }
77634
+ };
77635
+ const context = { nowMs: Date.now(), env: deps.env, providerQuota, ...Object.keys(requestFacts).length === 0 ? {} : { request: requestFacts } };
77568
77636
  let matched;
77569
77637
  for (const entry of routes) {
77570
77638
  const verdict = evaluateWhen(entry.when, context);
77571
77639
  if (verdict.status === "definite" && verdict.passed) {
77572
- matched = entry.provider;
77640
+ matched = { provider: entry.provider, model: entry.model };
77573
77641
  break;
77574
77642
  }
77575
77643
  }
77576
77644
  if (matched === void 0) {
77577
77645
  const resolution = resolve(current);
77578
- return resolution.ok ? { ok: true, route: servingRewritten(resolution.route, current.url, replay.body) } : resolution;
77646
+ return resolution.ok ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }) } : resolution;
77647
+ }
77648
+ if (matched.model !== void 0 && scan.text !== void 0 && scan.model !== void 0) {
77649
+ const rewritten = scan.text.replace(new RegExp('"model":\\s*"' + scan.model.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + '"'), '"model":"' + matched.model + '"');
77650
+ const headers = Object.fromEntries(Object.entries(replay.headers).filter(([name]) => name.toLowerCase() !== "content-length"));
77651
+ replay = { ...replay, headers, body: import_node_stream3.Readable.from([Buffer.from(rewritten, "utf8")]) };
77579
77652
  }
77580
77653
  const rest = scoped === void 0 ? path46 : path46.slice(`${PROVIDER_PATH_PREFIX}${encodeURIComponent(scoped.provider)}`.length);
77581
77654
  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 };
77655
+ current = { ...current, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(matched.provider)}${rest}${query}`, body: replay.body, headers: replay.headers };
77583
77656
  }
77584
77657
  };
77585
77658
  }
@@ -80710,6 +80783,7 @@ function realFrontDoorSupervisorPorts(paths) {
80710
80783
  appendLog(paths, `frontdoor ${String(process.pid)}: ${line}`);
80711
80784
  }
80712
80785
  });
80786
+ const routingSnapshots = /* @__PURE__ */ new Map();
80713
80787
  const rcControlToken = (0, import_node_crypto15.randomUUID)();
80714
80788
  const resolveRoute = rcObservingResolver(
80715
80789
  createProviderRouteResolver({
@@ -80720,6 +80794,7 @@ function realFrontDoorSupervisorPorts(paths) {
80720
80794
  // 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
80795
  env: process.env,
80722
80796
  credentials: { ...realCredentialPort, cache: realCredentialCacheEnv(paths) },
80797
+ usageSnapshotOf: (identity) => identity === void 0 ? void 0 : routingSnapshots.get(identity) ?? readUsageSnapshot(realFarmFs, paths.usageSnapshotsDir, identity),
80723
80798
  ...rcSelfHostSurface === void 0 ? {} : { rcSelfHostRoute: rcSelfHostSurface.route }
80724
80799
  }),
80725
80800
  rcTracker,
@@ -80734,6 +80809,7 @@ function realFrontDoorSupervisorPorts(paths) {
80734
80809
  readAccount: createAccountReader(realFarmFs, paths.identitiesDir),
80735
80810
  log,
80736
80811
  publish: (snapshot) => {
80812
+ routingSnapshots.set(snapshot.identity, snapshot);
80737
80813
  usagePublisher.publish(snapshot);
80738
80814
  }
80739
80815
  });
@@ -82754,13 +82830,13 @@ function formatLimit(limit) {
82754
82830
  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
82831
  }
82756
82832
  var MONEY_DECIMALS = 2;
82757
- var MS_PER_HOUR3 = 36e5;
82833
+ var MS_PER_HOUR4 = 36e5;
82758
82834
  var HOURS_PER_DAY4 = 24;
82759
82835
  function formatPeriod(window) {
82760
82836
  if (window.periodMs === void 0) {
82761
82837
  return window.period ?? "unknown period";
82762
82838
  }
82763
- const hours = window.periodMs / MS_PER_HOUR3;
82839
+ const hours = window.periodMs / MS_PER_HOUR4;
82764
82840
  return hours >= HOURS_PER_DAY4 && Number.isInteger(hours / HOURS_PER_DAY4) ? `${String(hours / HOURS_PER_DAY4)}d` : `${String(hours)}h`;
82765
82841
  }
82766
82842
  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,19 @@ 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.request?.toolsPresent === void 0 ? {} : { "request.toolsPresent": context.request.toolsPresent },
1035
+ ...context.request?.thinking === void 0 ? {} : { "request.thinking": context.request.thinking },
1036
+ ...context.request?.maxTokens === void 0 ? {} : { "request.maxTokens": context.request.maxTokens },
1037
+ ...context.request?.isCountTokens === void 0 ? {} : { "request.isCountTokens": context.request.isCountTokens },
1038
+ ...context.providerQuota === void 0 ? {} : Object.fromEntries(
1039
+ Object.entries(context.providerQuota).flatMap(
1040
+ ([name, windows]) => [
1041
+ ...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]],
1042
+ ...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]]
1043
+ ]
1044
+ )
1045
+ )
1032
1046
  };
1033
1047
  return {
1034
1048
  resolveValue: (key) => {
@@ -5409,7 +5423,7 @@ var import_undici = require("undici");
5409
5423
  // package.json
5410
5424
  var package_default = {
5411
5425
  name: "agent-shim",
5412
- version: "8.35.0",
5426
+ version: "8.37.0",
5413
5427
  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
5428
  license: "MIT",
5415
5429
  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,19 @@ 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.request?.toolsPresent === void 0 ? {} : { "request.toolsPresent": context.request.toolsPresent },
723
+ ...context.request?.thinking === void 0 ? {} : { "request.thinking": context.request.thinking },
724
+ ...context.request?.maxTokens === void 0 ? {} : { "request.maxTokens": context.request.maxTokens },
725
+ ...context.request?.isCountTokens === void 0 ? {} : { "request.isCountTokens": context.request.isCountTokens },
726
+ ...context.providerQuota === void 0 ? {} : Object.fromEntries(
727
+ Object.entries(context.providerQuota).flatMap(
728
+ ([name, windows]) => [
729
+ ...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]],
730
+ ...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]]
731
+ ]
732
+ )
733
+ )
720
734
  };
721
735
  return {
722
736
  resolveValue: (key) => {
@@ -5097,7 +5111,7 @@ import { Agent as Agent3, fetch as undiciFetch } from "undici";
5097
5111
  // package.json
5098
5112
  var package_default = {
5099
5113
  name: "agent-shim",
5100
- version: "8.35.0",
5114
+ version: "8.37.0",
5101
5115
  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
5116
  license: "MIT",
5103
5117
  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>;
@@ -7114,7 +7115,16 @@ interface ConditionContext {
7114
7115
  readonly request?: {
7115
7116
  readonly model?: string;
7116
7117
  readonly hasImage?: boolean;
7118
+ readonly toolsPresent?: boolean;
7119
+ readonly thinking?: boolean;
7120
+ readonly maxTokens?: number;
7121
+ readonly isCountTokens?: boolean;
7117
7122
  };
7123
+ /** 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. */
7124
+ readonly providerQuota?: Readonly<Record<string, {
7125
+ readonly fiveHour?: PoolWindowFacts;
7126
+ readonly sevenDay?: PoolWindowFacts;
7127
+ }>>;
7118
7128
  }
7119
7129
  /**
7120
7130
  * 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.37.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>",