claudish 14.16.1 → 14.17.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.
Files changed (2) hide show
  1. package/dist/index.js +385 -83
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -133,6 +133,9 @@ var init_config = __esm(() => {
133
133
  CLAUDISH_PROVIDER_NAME: "CLAUDISH_PROVIDER_NAME",
134
134
  ANTHROPIC_MODEL: "ANTHROPIC_MODEL",
135
135
  ANTHROPIC_SMALL_FAST_MODEL: "ANTHROPIC_SMALL_FAST_MODEL",
136
+ CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST: "CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST",
137
+ CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL: "_CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL",
138
+ CLAUDISH_SET_HOST_ROUTING_VARS: "CLAUDISH_SET_HOST_ROUTING_VARS",
136
139
  CLAUDISH_MODEL_OPUS: "CLAUDISH_MODEL_OPUS",
137
140
  CLAUDISH_MODEL_SONNET: "CLAUDISH_MODEL_SONNET",
138
141
  CLAUDISH_MODEL_HAIKU: "CLAUDISH_MODEL_HAIKU",
@@ -5491,7 +5494,7 @@ var init_onepassword_config = __esm(() => {
5491
5494
  });
5492
5495
 
5493
5496
  // src/version.ts
5494
- var VERSION = "14.16.1";
5497
+ var VERSION = "14.17.0";
5495
5498
 
5496
5499
  // src/redact.ts
5497
5500
  function isPlaceholder(value) {
@@ -12187,6 +12190,8 @@ function stripVendorPrefix(lowerId) {
12187
12190
  return lowerId.includes("/") ? lowerId.substring(lowerId.lastIndexOf("/") + 1) : lowerId;
12188
12191
  }
12189
12192
  function findCacheEntry(modelId, cachePath) {
12193
+ if (modelId.startsWith("@"))
12194
+ return;
12190
12195
  if (modelId.includes("@")) {
12191
12196
  throw new Error(`model-catalog lookup received provider-routed ID "${modelId}" \u2014 callers must strip the "@" prefix before calling`);
12192
12197
  }
@@ -34200,6 +34205,14 @@ function toModelInfo(raw) {
34200
34205
  if (tp && typeof tp.mode === "string" && typeof tp.limit === "number") {
34201
34206
  info.truncationPolicy = { mode: tp.mode, limit: tp.limit };
34202
34207
  }
34208
+ if (Array.isArray(m.service_tiers)) {
34209
+ info.serviceTiers = m.service_tiers.flatMap((tier) => {
34210
+ const t = tier;
34211
+ return t && typeof t.id === "string" && typeof t.name === "string" ? [{ id: t.id, name: t.name }] : [];
34212
+ });
34213
+ }
34214
+ if (typeof m.default_service_tier === "string")
34215
+ info.defaultServiceTier = m.default_service_tier;
34203
34216
  return info;
34204
34217
  }
34205
34218
  function toModelTable(body) {
@@ -34296,7 +34309,7 @@ async function firstAnswer(entry, slug, binding, opts, now) {
34296
34309
  log(`[CodexDiscovery] ${slug}: /models not answered within ${waitMs} ms`);
34297
34310
  }
34298
34311
  }
34299
- return slug ? fromModelsCache(slug, opts.codexHome) : undefined;
34312
+ return slug && !opts.accountOnly ? fromModelsCache(slug, opts.codexHome) : undefined;
34300
34313
  }
34301
34314
  function fromModelsCache(slug, codexHome) {
34302
34315
  const info = toModelTable(readModelsCache(codexHome))?.get(slug.toLowerCase());
@@ -41082,6 +41095,34 @@ function parseModelParams(spec, into = {}) {
41082
41095
  return into;
41083
41096
  }
41084
41097
 
41098
+ // src/providers/codex-service-tier.ts
41099
+ function findCodexServiceTier(speed, tiers) {
41100
+ if (!tiers)
41101
+ return;
41102
+ const matches = (tier) => tier.id === speed || tier.name.toLowerCase() === speed;
41103
+ return tiers.find(matches);
41104
+ }
41105
+ function decideCodexSpeed(speed, modelInfo) {
41106
+ if (speed.value === "standard") {
41107
+ return { note: "speed standard: field omitted (connection default)" };
41108
+ }
41109
+ if (modelInfo === "unsigned") {
41110
+ const message = `speed "${speed.value}" is not available on this connection (no subscription account signed the request)`;
41111
+ return speed.explicit ? { note: message, refusal: message } : { note: message };
41112
+ }
41113
+ const tier = findCodexServiceTier(speed.value, modelInfo?.serviceTiers);
41114
+ if (tier) {
41115
+ return {
41116
+ tier: tier.id,
41117
+ note: `speed ${speed.value}: ${CODEX_SERVICE_TIER_POINTER} set to the account's ${speed.value} tier (from the account's dynamic models catalog)`
41118
+ };
41119
+ }
41120
+ const listed = modelInfo?.serviceTiers?.length ?? 0;
41121
+ const message = modelInfo ? `speed "${speed.value}" is not offered on this connection (the account lists ${listed} service tier${listed === 1 ? "" : "s"})` : `speed "${speed.value}" is not available on this connection (the account's dynamic models catalog did not answer; retry)`;
41122
+ return speed.explicit ? { note: message, refusal: message } : { note: message };
41123
+ }
41124
+ var CODEX_SERVICE_TIER_POINTER = "/service_tier";
41125
+
41085
41126
  // src/handlers/shared/call-context.ts
41086
41127
  function createSigningSecrets() {
41087
41128
  return { values: new Set, lease: acquireSigningLease() };
@@ -48149,6 +48190,34 @@ var init_authority = __esm(() => {
48149
48190
  installBillingProbes();
48150
48191
  });
48151
48192
 
48193
+ // src/providers/catalog-endpoints.ts
48194
+ function catalogUrl() {
48195
+ return process.env.CLAUDISH_CATALOG_URL ?? DEFAULT_CATALOG_URL;
48196
+ }
48197
+ function siblingEndpoint(pathname, fallback) {
48198
+ try {
48199
+ const url = new URL(catalogUrl());
48200
+ url.pathname = url.pathname.replace(/\/queryModels$/, pathname);
48201
+ url.search = "";
48202
+ return url.toString();
48203
+ } catch {
48204
+ return fallback;
48205
+ }
48206
+ }
48207
+ function plansUrl() {
48208
+ return process.env.CLAUDISH_PLANS_URL ?? siblingEndpoint("/queryPlans", `${DEFAULT_HOST}/queryPlans`);
48209
+ }
48210
+ function probeModelsUrl() {
48211
+ return process.env.CLAUDISH_PROBE_MODELS_URL ?? siblingEndpoint("/probeModels", `${DEFAULT_HOST}/probeModels`);
48212
+ }
48213
+ function modelsBaseUrl() {
48214
+ return siblingEndpoint("/queryModels", `${DEFAULT_HOST}/queryModels`);
48215
+ }
48216
+ var DEFAULT_HOST = "https://us-central1-claudish-6da10.cloudfunctions.net", DEFAULT_CATALOG_URL;
48217
+ var init_catalog_endpoints = __esm(() => {
48218
+ DEFAULT_CATALOG_URL = `${DEFAULT_HOST}/queryModels?status=all&catalog=slim&includeRouteVariants=true&limit=1000`;
48219
+ });
48220
+
48152
48221
  // src/providers/catalog-v3.ts
48153
48222
  function parseCatalogV3Envelope(value) {
48154
48223
  if (!value || typeof value !== "object")
@@ -48617,22 +48686,6 @@ var init_probe_discovery = __esm(() => {
48617
48686
  });
48618
48687
 
48619
48688
  // src/providers/catalog-client.ts
48620
- function catalogUrl() {
48621
- return process.env.CLAUDISH_CATALOG_URL ?? DEFAULT_CATALOG_URL;
48622
- }
48623
- function derivePlansUrl(modelsUrl) {
48624
- try {
48625
- const url = new URL(modelsUrl);
48626
- url.pathname = url.pathname.replace(/\/queryModels$/, "/queryPlans");
48627
- url.search = "";
48628
- return url.toString();
48629
- } catch {
48630
- return "https://us-central1-claudish-6da10.cloudfunctions.net/queryPlans";
48631
- }
48632
- }
48633
- function plansUrl() {
48634
- return process.env.CLAUDISH_PLANS_URL ?? derivePlansUrl(catalogUrl());
48635
- }
48636
48689
  function buildRoutesUrl(modelsUrl, generationId) {
48637
48690
  const url = new URL(modelsUrl);
48638
48691
  url.search = "";
@@ -48832,8 +48885,9 @@ async function refreshCatalogOnce(timeoutMs, options) {
48832
48885
  let pages = 0;
48833
48886
  const seenCursors = new Set;
48834
48887
  let expectedTotal;
48888
+ const base = catalogUrl();
48835
48889
  for (;; ) {
48836
- const result = await fetchEnvelope(buildCatalogPageUrl(catalogUrl(), cursor, CATALOG_PAGE_LIMIT, generationId), timeoutMs);
48890
+ const result = await fetchEnvelope(buildCatalogPageUrl(base, cursor, CATALOG_PAGE_LIMIT, generationId), timeoutMs);
48837
48891
  if (!result.ok) {
48838
48892
  if (result.reason === "incompatible") {
48839
48893
  return { kind: "incompatible", serverContractVersion: result.serverContractVersion };
@@ -48882,7 +48936,7 @@ async function refreshCatalogOnce(timeoutMs, options) {
48882
48936
  }
48883
48937
  return { kind: "fetch_failed", reason: planResult.reason };
48884
48938
  }
48885
- const registryResult = await fetchRouteRegistry(timeoutMs, generationId);
48939
+ const registryResult = await fetchRouteRegistry(timeoutMs, generationId, base);
48886
48940
  if (!registryResult.ok) {
48887
48941
  if (registryResult.reason === "incompatible") {
48888
48942
  return { kind: "incompatible", serverContractVersion: registryResult.serverContractVersion };
@@ -48960,8 +49014,8 @@ async function fetchSubscriptionPlans(timeoutMs, generationId) {
48960
49014
  }
48961
49015
  return { ok: true, plans };
48962
49016
  }
48963
- async function fetchRouteRegistry(timeoutMs, generationId) {
48964
- const result = await fetchEnvelope(buildRoutesUrl(catalogUrl(), generationId), timeoutMs);
49017
+ async function fetchRouteRegistry(timeoutMs, generationId, modelsUrl) {
49018
+ const result = await fetchEnvelope(buildRoutesUrl(modelsUrl, generationId), timeoutMs);
48965
49019
  if (!result.ok)
48966
49020
  return result;
48967
49021
  if (result.envelope.generationId !== generationId) {
@@ -49003,7 +49057,7 @@ async function ensureRouteRegistryReady(timeoutMs = 5000) {
49003
49057
  if (cache?.routeRegistry)
49004
49058
  return;
49005
49059
  if (cache && !catalogWarmDisabled()) {
49006
- const result = await fetchRouteRegistry(timeoutMs, cache.catalogGenerationId);
49060
+ const result = await fetchRouteRegistry(timeoutMs, cache.catalogGenerationId, catalogUrl());
49007
49061
  if (result.ok) {
49008
49062
  const routeRegistry = { generationId: cache.catalogGenerationId, registry: result.registry };
49009
49063
  if (wiresMatchRegistry(cache.entries, routeRegistry, cache.catalogGenerationId)) {
@@ -49026,10 +49080,11 @@ async function waitForCatalogWarm(timeoutMs) {
49026
49080
  if (timedOut)
49027
49081
  log(`[catalog] still refreshing after ${timeoutMs} ms; the caller goes on without it`);
49028
49082
  }
49029
- var DEFAULT_CATALOG_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/queryModels?status=all&catalog=slim&includeRouteVariants=true&limit=1000", MAX_CATALOG_PAGES = 40, CATALOG_PAGE_LIMIT = 1000, _memCache = null, _catalogEntriesForTest, _warmPromise = null;
49083
+ var MAX_CATALOG_PAGES = 40, CATALOG_PAGE_LIMIT = 1000, _memCache = null, _catalogEntriesForTest, _warmPromise = null;
49030
49084
  var init_catalog_client = __esm(() => {
49031
49085
  init_logger();
49032
49086
  init_all_models_cache();
49087
+ init_catalog_endpoints();
49033
49088
  init_catalog_route_bindings();
49034
49089
  init_connection_wire();
49035
49090
  init_probe_discovery();
@@ -50252,7 +50307,7 @@ async function discoverEveryServedModel(providerName) {
50252
50307
  detail: oneLine3(e?.message ?? "")
50253
50308
  });
50254
50309
  }
50255
- if (!hasAuthHeader(headers)) {
50310
+ if (!hasAuthHeader(headers) && def.authScheme !== "none") {
50256
50311
  return recordFailure({ kind: "no-credentials", provider: providerName, endpoint });
50257
50312
  }
50258
50313
  }
@@ -50532,6 +50587,15 @@ function setPointer(body, path, value) {
50532
50587
  }
50533
50588
  node[tokens[tokens.length - 1]] = value;
50534
50589
  }
50590
+ function readPointer(body, path) {
50591
+ let node = body;
50592
+ for (const token of pointerTokens(path)) {
50593
+ if (node === null || typeof node !== "object" || Array.isArray(node))
50594
+ return;
50595
+ node = node[token];
50596
+ }
50597
+ return node;
50598
+ }
50535
50599
  function deletePointer(body, path) {
50536
50600
  const tokens = pointerTokens(path);
50537
50601
  const trail = [body];
@@ -50608,6 +50672,18 @@ function applyControl(body, control, requested, label, explicit, result) {
50608
50672
  result.headers.push(...control.headers);
50609
50673
  result.notes.push(`${label} ${requested}: ${control.path} = ${JSON.stringify(native)}${control.access !== "open" ? ` (access: ${control.access})` : ""}`);
50610
50674
  }
50675
+ function wireSpeedOffered(control, speed) {
50676
+ return control.status === "supported" && control.values[speed] !== undefined;
50677
+ }
50678
+ function applyWireSpeed(body, wire, speed) {
50679
+ const result = { headers: [], notes: [], borrowed: [] };
50680
+ if (wire.speed.status === "supported" && readPointer(body, wire.speed.path) !== undefined) {
50681
+ result.notes.push(`speed ${speed.value}: ${wire.speed.path} already set by --model-params`);
50682
+ return result;
50683
+ }
50684
+ applyControl(body, wire.speed, speed.value, "speed", speed.explicit, result);
50685
+ return result;
50686
+ }
50611
50687
  function writeAssignments(put, assignments) {
50612
50688
  for (const assignment of assignments)
50613
50689
  put(assignment.path, assignment.value);
@@ -50693,7 +50769,8 @@ function wireChoicesFromClaudeRequest(claudeRequest, pinnedEffort) {
50693
50769
  effort: effort === "none" ? undefined : effort,
50694
50770
  reasoningOff,
50695
50771
  hasTools: Array.isArray(claudeRequest?.tools) && claudeRequest.tools.length > 0,
50696
- maxTokens: typeof claudeRequest?.max_tokens === "number" ? claudeRequest.max_tokens : undefined
50772
+ maxTokens: typeof claudeRequest?.max_tokens === "number" ? claudeRequest.max_tokens : undefined,
50773
+ ...claudeRequest?.speed === "fast" && { speed: { value: "fast", explicit: false } }
50697
50774
  };
50698
50775
  }
50699
50776
  function outputLimitToSend(wire, choices, result) {
@@ -50760,7 +50837,7 @@ function recoverBorrowedWireFields(payload, borrowed, errorText) {
50760
50837
  deletePointer(next, path);
50761
50838
  return {
50762
50839
  payload: next,
50763
- note: `dropped ${drop.join(", ")} (borrowed from the owner's connection; this connection's value is unknown)`
50840
+ note: `dropped ${drop.join(", ")} (not published by this connection's catalog wire)`
50764
50841
  };
50765
50842
  }
50766
50843
  function mergeWireHeaders(headers, extra) {
@@ -53111,10 +53188,18 @@ function createAnthropicPassthroughStream(c, response, opts) {
53111
53188
  let pendingEventLine = null;
53112
53189
  let inputTokens = 0;
53113
53190
  let outputTokens = 0;
53191
+ let cacheReadTokens = 0;
53192
+ let cacheCreationTokens = 0;
53114
53193
  let stopReason = null;
53115
53194
  let sawMessageStart = false;
53116
53195
  let sawMessageStop = false;
53117
53196
  let openBlockIndex = null;
53197
+ const reportUsage = () => {
53198
+ opts.onTokenUpdate?.(inputTokens + cacheReadTokens + cacheCreationTokens, outputTokens, {
53199
+ cacheReadTokens,
53200
+ cacheCreationTokens
53201
+ });
53202
+ };
53118
53203
  const noteLifecycle = (data, emittedIndex) => {
53119
53204
  switch (data?.type) {
53120
53205
  case "message_start":
@@ -53191,10 +53276,10 @@ data: ${JSON.stringify(data)}
53191
53276
  } catch {}
53192
53277
  };
53193
53278
  const endCancelled = () => {
53194
- const sawUsage = inputTokens > 0 || outputTokens > 0;
53279
+ const sawUsage = inputTokens > 0 || outputTokens > 0 || cacheReadTokens > 0 || cacheCreationTokens > 0;
53195
53280
  log(`[AnthropicSSE] Client cancelled the stream for ${opts.modelName}; usage ${sawUsage ? "reported" : "not received, not recorded"}`);
53196
53281
  if (sawUsage)
53197
- opts.onTokenUpdate?.(inputTokens, outputTokens);
53282
+ reportUsage();
53198
53283
  if (pingInterval) {
53199
53284
  clearInterval(pingInterval);
53200
53285
  pingInterval = null;
@@ -53356,10 +53441,14 @@ data: ${JSON.stringify({
53356
53441
  if (data.message?.usage) {
53357
53442
  inputTokens = data.message.usage.input_tokens || inputTokens;
53358
53443
  outputTokens = data.message.usage.output_tokens || outputTokens;
53444
+ cacheReadTokens = data.message.usage.cache_read_input_tokens || cacheReadTokens;
53445
+ cacheCreationTokens = data.message.usage.cache_creation_input_tokens || cacheCreationTokens;
53359
53446
  }
53360
53447
  if (data.usage) {
53361
53448
  inputTokens = data.usage.input_tokens || inputTokens;
53362
53449
  outputTokens = data.usage.output_tokens || outputTokens;
53450
+ cacheReadTokens = data.usage.cache_read_input_tokens || cacheReadTokens;
53451
+ cacheCreationTokens = data.usage.cache_creation_input_tokens || cacheCreationTokens;
53363
53452
  }
53364
53453
  if (data.type === "content_block_delta" && data.delta?.type === "text_delta") {
53365
53454
  const txt = data.delta.text || "";
@@ -53398,10 +53487,14 @@ data: ${JSON.stringify({
53398
53487
  if (data.message?.usage) {
53399
53488
  inputTokens = data.message.usage.input_tokens || inputTokens;
53400
53489
  outputTokens = data.message.usage.output_tokens || outputTokens;
53490
+ cacheReadTokens = data.message.usage.cache_read_input_tokens || cacheReadTokens;
53491
+ cacheCreationTokens = data.message.usage.cache_creation_input_tokens || cacheCreationTokens;
53401
53492
  }
53402
53493
  if (data.usage) {
53403
53494
  inputTokens = data.usage.input_tokens || inputTokens;
53404
53495
  outputTokens = data.usage.output_tokens || outputTokens;
53496
+ cacheReadTokens = data.usage.cache_read_input_tokens || cacheReadTokens;
53497
+ cacheCreationTokens = data.usage.cache_creation_input_tokens || cacheCreationTokens;
53405
53498
  }
53406
53499
  if (data.type === "content_block_delta" && data.delta?.type === "text_delta") {
53407
53500
  textChunks++;
@@ -53423,9 +53516,7 @@ data: ${JSON.stringify({
53423
53516
  return;
53424
53517
  }
53425
53518
  log(`[AnthropicSSE] Stream complete for ${opts.modelName}: ${totalLines} lines, ${textChunks} text chunks, ${toolUseBlocks} tool_use blocks, stop_reason=${stopReason}${filterThinking ? `, filtered ${thinkingBlocksSuppressed} thinking blocks` : ""}`);
53426
- if (opts.onTokenUpdate) {
53427
- opts.onTokenUpdate(inputTokens, outputTokens);
53428
- }
53519
+ reportUsage();
53429
53520
  if (!isClosed) {
53430
53521
  isClosed = true;
53431
53522
  if (pingInterval) {
@@ -53442,7 +53533,7 @@ data: ${JSON.stringify({
53442
53533
  log(`[AnthropicSSE] Stream error: ${e}`);
53443
53534
  finalizeAbandonedStream(controller);
53444
53535
  try {
53445
- opts.onTokenUpdate?.(inputTokens, outputTokens);
53536
+ reportUsage();
53446
53537
  } catch {}
53447
53538
  if (!isClosed) {
53448
53539
  isClosed = true;
@@ -54617,6 +54708,13 @@ var init_stall_guard = __esm(() => {
54617
54708
  });
54618
54709
 
54619
54710
  // src/handlers/shared/stream-parsers/responses/responses-leg.ts
54711
+ function hasReplayableReasoning(item) {
54712
+ if (item?.type !== "reasoning")
54713
+ return false;
54714
+ if (item.encrypted_content)
54715
+ return true;
54716
+ return Array.isArray(item.content) && item.content.length > 0;
54717
+ }
54620
54718
  function readUsage(raw, prior, keepPrior = false) {
54621
54719
  if (!raw || typeof raw !== "object")
54622
54720
  return;
@@ -54945,7 +55043,7 @@ class ResponsesLeg {
54945
55043
  if (typeof item.phase === "string")
54946
55044
  message.phase = item.phase;
54947
55045
  this.items.push(message);
54948
- } else if (item?.type === "reasoning" && item.encrypted_content) {
55046
+ } else if (hasReplayableReasoning(item)) {
54949
55047
  this.items.push({
54950
55048
  type: "reasoning",
54951
55049
  content: item.content ?? [],
@@ -55040,7 +55138,7 @@ class ResponsesLeg {
55040
55138
  }
55041
55139
  onItemDone(event) {
55042
55140
  const item = event.item;
55043
- if (item?.type === "reasoning" && item.encrypted_content) {
55141
+ if (hasReplayableReasoning(item)) {
55044
55142
  this.pendingReasoning.push({
55045
55143
  type: "reasoning",
55046
55144
  content: item.content ?? [],
@@ -55655,8 +55753,9 @@ var init_token_file = __esm(() => {
55655
55753
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync12 } from "fs";
55656
55754
  import { dirname as dirname13 } from "path";
55657
55755
  function stripProviderPrefix(name) {
55658
- const at = name.indexOf("@");
55659
- return at === -1 ? name : name.slice(at + 1);
55756
+ if (!hasProviderPrefix(name))
55757
+ return name;
55758
+ return name.slice(name.indexOf("@") + 1);
55660
55759
  }
55661
55760
  function computeCacheReadDiscount(pricing, billedInputTokens, detail) {
55662
55761
  const cacheReadTokens = detail?.cacheReadTokens ?? 0;
@@ -55905,6 +56004,7 @@ var init_token_tracker = __esm(() => {
55905
56004
  init_tool_name_utils();
55906
56005
  init_types2();
55907
56006
  init_logger();
56007
+ init_model_parser();
55908
56008
  init_token_file();
55909
56009
  init_remote_provider_types();
55910
56010
  ALLOWANCE_LABEL_STALE_MS = 10 * 60 * 1000;
@@ -55990,8 +56090,8 @@ class ComposedHandler {
55990
56090
  pendingFallbackMeta;
55991
56091
  lastPlanPollAt = 0;
55992
56092
  constructor(provider, targetModel, modelName, port, options = {}) {
55993
- if (modelName.includes("@")) {
55994
- throw new Error(`ComposedHandler: modelName must not contain '@' (got "${modelName}"). Strip the provider routing prefix before passing modelName. If you need the full routed form, pass it as targetModel.`);
56093
+ if (hasProviderPrefix(modelName)) {
56094
+ throw new Error(`ComposedHandler: modelName must not contain a provider prefix (got "${modelName}"). Strip the provider routing prefix before passing modelName. If you need the full routed form, pass it as targetModel.`);
55995
56095
  }
55996
56096
  this.provider = provider;
55997
56097
  this.targetModel = targetModel;
@@ -56115,6 +56215,17 @@ class ComposedHandler {
56115
56215
  subscription: CREDENTIAL_DECIDED_PROVIDERS.has(name) ? binding?.auth?.arm === "oauth" : isSubscriptionProvider(name)
56116
56216
  };
56117
56217
  }
56218
+ wireWhere() {
56219
+ const connection = this.options.connection;
56220
+ return `${connection?.route.routeId}/${connection?.route.routeProfileId} \xB7 ${connection?.externalModelId}`;
56221
+ }
56222
+ noticeFastIgnored(source) {
56223
+ if (fastIgnoredNoticed.has(this.targetModel))
56224
+ return;
56225
+ fastIgnoredNoticed.add(this.targetModel);
56226
+ const advice = source === "catalog" ? "the fast tier is billed at a higher per-token price. Add #fast to the model spec to send it anyway." : "the Codex fast tier is sent only on a request signed by a Codex subscription account.";
56227
+ logStderr(`${this.targetModel}: Claude Code /fast ignored, the request is metered and ${advice}`);
56228
+ }
56118
56229
  respondCallAborted(startTime, fallbackMeta) {
56119
56230
  log(`[${this.provider.displayName}] call stopped: its deadline passed`);
56120
56231
  try {
@@ -56547,7 +56658,7 @@ class ComposedHandler {
56547
56658
  }));
56548
56659
  }
56549
56660
  let requestPayload = adapter.buildPayload(claudeRequest, messages, tools);
56550
- const extraFields = this.provider.getExtraPayloadFields?.();
56661
+ const extraFields = await this.provider.getExtraPayloadFields?.();
56551
56662
  if (extraFields) {
56552
56663
  Object.assign(requestPayload, extraFields);
56553
56664
  }
@@ -56558,6 +56669,8 @@ class ComposedHandler {
56558
56669
  const toolNameMap = adapter.getToolNameMap();
56559
56670
  let wireHeaders = [];
56560
56671
  let wireBorrowed = [];
56672
+ let codexSpeed;
56673
+ let fastSpeed;
56561
56674
  const wire = this.options.connection?.wire;
56562
56675
  if (wire?.status === "known") {
56563
56676
  const choices = {
@@ -56580,6 +56693,13 @@ class ComposedHandler {
56580
56693
  }
56581
56694
  if (wireSpeed)
56582
56695
  choices.speed = { value: wireSpeed, explicit: true };
56696
+ if (choices.speed && this.provider.name === "openai-codex" && wire.speed.status === "unknown") {
56697
+ codexSpeed = choices.speed;
56698
+ choices.speed = undefined;
56699
+ } else if (choices.speed && !choices.speed.explicit) {
56700
+ fastSpeed = choices.speed;
56701
+ choices.speed = undefined;
56702
+ }
56583
56703
  const shaped = shapeRequestFromWire(requestPayload, wire, choices, this.options.connection?.ownerWire);
56584
56704
  wireBorrowed = shaped.borrowed;
56585
56705
  const where = `${this.options.connection?.route.routeId}/${this.options.connection?.route.routeProfileId} \xB7 ${this.options.connection?.externalModelId}`;
@@ -56680,6 +56800,18 @@ class ComposedHandler {
56680
56800
  this.tokenTracker.setContextWindow(providerWindow);
56681
56801
  }
56682
56802
  }
56803
+ if (fastSpeed && wire?.status === "known") {
56804
+ if (!this.signedBilling(binding).subscription) {
56805
+ log(`[Wire] ${this.wireWhere()}: speed ${fastSpeed.value} (Claude Code /fast) not sent: the request is metered`);
56806
+ if (wireSpeedOffered(wire.speed, fastSpeed.value))
56807
+ this.noticeFastIgnored("catalog");
56808
+ } else {
56809
+ const applied = applyWireSpeed(requestPayload, wire, fastSpeed);
56810
+ for (const note of applied.notes)
56811
+ log(`[Wire] ${this.wireWhere()}: ${note}`);
56812
+ wireHeaders = [...wireHeaders, ...applied.headers];
56813
+ }
56814
+ }
56683
56815
  if (this.provider.name === "openai-codex") {
56684
56816
  const resume = (mayRequestModule) => resumeFromToolResults(claudeRequest, binding, peekCodeModeStores(), claudeRequest?.tool_choice, {
56685
56817
  setting: this.options.codeMode ?? DEFAULT_CODE_MODE_SETTING,
@@ -56704,6 +56836,30 @@ class ComposedHandler {
56704
56836
  if (this.provider.transformPayload) {
56705
56837
  requestPayload = this.provider.transformPayload(requestPayload, claudeRequest, binding);
56706
56838
  }
56839
+ if (codexSpeed) {
56840
+ addSigningSecrets(c, credentialValuesFromRequest(binding?.auth?.headers, this.signedEndpoint(binding)));
56841
+ const accountKey = accountKeyFromBinding(binding);
56842
+ const subscription = this.signedBilling(binding).subscription;
56843
+ const modelInfo = !subscription ? "unsigned" : binding && accountKey ? await getCodexModelInfo(String(requestPayload?.model ?? ""), binding, accountKey, {
56844
+ accountOnly: true
56845
+ }) : undefined;
56846
+ const outcome = decideCodexSpeed(codexSpeed, modelInfo);
56847
+ const where = this.wireWhere();
56848
+ log(`[Wire] ${where}: ${outcome.note}`);
56849
+ if (!subscription && !codexSpeed.explicit && codexSpeed.value !== "standard") {
56850
+ this.noticeFastIgnored("codex");
56851
+ }
56852
+ if (outcome.refusal) {
56853
+ return c.json(wrapAnthropicError(400, redactForClient(`claudish: ${outcome.refusal} (${where})`), "invalid_request_error"), 400);
56854
+ }
56855
+ if (outcome.tier && requestPayload.service_tier !== undefined) {
56856
+ log(`[Wire] ${where}: service_tier already set by --model-params; speed tier not written`);
56857
+ } else if (outcome.tier) {
56858
+ requestPayload.service_tier = outcome.tier;
56859
+ if (!codexSpeed.explicit)
56860
+ wireBorrowed = [...wireBorrowed, CODEX_SERVICE_TIER_POINTER];
56861
+ }
56862
+ }
56707
56863
  let codeModeShape;
56708
56864
  let codeModePrePayload;
56709
56865
  let codeModeContext;
@@ -58024,7 +58180,7 @@ function getRecoveryHint(status, errorText, providerName, transportTerminal429,
58024
58180
  }
58025
58181
  return `Unexpected HTTP ${status} from ${providerName}.`;
58026
58182
  }
58027
- var STREAM_RETRY_DELAYS_MS;
58183
+ var STREAM_RETRY_DELAYS_MS, fastIgnoredNoticed;
58028
58184
  var init_composed_handler = __esm(() => {
58029
58185
  init_base_api_format();
58030
58186
  init_minimax_model_dialect();
@@ -58051,6 +58207,8 @@ var init_composed_handler = __esm(() => {
58051
58207
  init_raw();
58052
58208
  init_request_stage();
58053
58209
  init_logger();
58210
+ init_codex_models_discovery();
58211
+ init_model_parser();
58054
58212
  init_provider_definitions();
58055
58213
  init_openai();
58056
58214
  init_wire_markers();
@@ -58088,6 +58246,7 @@ var init_composed_handler = __esm(() => {
58088
58246
  init_transient_retry();
58089
58247
  init_upstream_error_capture();
58090
58248
  STREAM_RETRY_DELAYS_MS = [3000, 15000, 30000];
58249
+ fastIgnoredNoticed = new Set;
58091
58250
  });
58092
58251
 
58093
58252
  // src/providers/api-key-provenance.ts
@@ -58638,7 +58797,7 @@ class LiteLLMProviderTransport {
58638
58797
  exclude
58639
58798
  });
58640
58799
  }
58641
- getExtraPayloadFields() {
58800
+ async getExtraPayloadFields() {
58642
58801
  const fields = {};
58643
58802
  const extraHeaders = this.getExtraHeaders();
58644
58803
  if (extraHeaders) {
@@ -61230,6 +61389,9 @@ var init_provider_definitions = __esm(() => {
61230
61389
  });
61231
61390
 
61232
61391
  // src/providers/model-parser.ts
61392
+ function hasProviderPrefix(spec) {
61393
+ return PROVIDER_PREFIX.test(spec);
61394
+ }
61233
61395
  function parseModelChain(modelSpec) {
61234
61396
  const parts = modelSpec.split(MODEL_CHAIN_SEPARATOR).map((s) => s.trim()).filter(Boolean);
61235
61397
  const merged = [];
@@ -61363,12 +61525,13 @@ function getLegacySyntaxWarning(parsed) {
61363
61525
  return `Deprecation warning: "${parsed.original}" uses legacy prefix syntax.
61364
61526
  ` + ` Consider using: ${newSyntax}`;
61365
61527
  }
61366
- var AUTO_ROUTE_PROVIDER = "auto-route", PROVIDER_SHORTCUTS, LOCAL_PROVIDERS, NATIVE_MODEL_PATTERNS, LEGACY_PREFIX_PATTERNS, MODEL_CHAIN_SEPARATOR = "+", MODE_MARKER_SEGMENT;
61528
+ var AUTO_ROUTE_PROVIDER = "auto-route", PROVIDER_SHORTCUTS, PROVIDER_PREFIX, LOCAL_PROVIDERS, NATIVE_MODEL_PATTERNS, LEGACY_PREFIX_PATTERNS, MODEL_CHAIN_SEPARATOR = "+", MODE_MARKER_SEGMENT;
61367
61529
  var init_model_parser = __esm(() => {
61368
61530
  init_claude_code_aliases();
61369
61531
  init_provider_definitions();
61370
61532
  init_wire_markers();
61371
61533
  PROVIDER_SHORTCUTS = getShortcuts();
61534
+ PROVIDER_PREFIX = /^[^@]+@/;
61372
61535
  LOCAL_PROVIDERS = {
61373
61536
  has(name) {
61374
61537
  return isLocalTransport(name);
@@ -71066,6 +71229,14 @@ function loadCustomEndpoints(config) {
71066
71229
  }
71067
71230
  return result;
71068
71231
  }
71232
+ function openaiModelsDiscovery(wireFormat, apiPath, modelPrefix) {
71233
+ if (modelPrefix)
71234
+ return;
71235
+ const api = ["/chat/completions", "/responses"].find((suffix) => apiPath.endsWith(suffix));
71236
+ if (wireFormat !== "openai" || !api)
71237
+ return;
71238
+ return { path: `${apiPath.slice(0, -api.length)}/models`, format: "openai-models-list" };
71239
+ }
71069
71240
  function buildProviderDefinition(name, ep, ovr) {
71070
71241
  const apiKeyEnvVar = ovr?.apiKeyEnvVar ?? customEndpointKeyEnvVar(name);
71071
71242
  const apiKeyAliases = ovr?.apiKeyAliases;
@@ -71090,9 +71261,11 @@ function buildProviderDefinition(name, ep, ovr) {
71090
71261
  isDirectApi: true,
71091
71262
  shortestPrefix: name,
71092
71263
  description: ovr?.description ?? `Custom endpoint: ${name}`,
71093
- authScheme: ep.authScheme ?? "bearer"
71264
+ authScheme: ep.authScheme ?? "bearer",
71265
+ modelDiscovery: openaiModelsDiscovery(ep.format, "/chat/completions", ep.modelPrefix)
71094
71266
  };
71095
71267
  }
71268
+ const apiPath = ep.apiPath ?? "/v1/chat/completions";
71096
71269
  return {
71097
71270
  createHandler: runtimeHandler(name),
71098
71271
  tier: CUSTOM_ENDPOINT_TIER,
@@ -71101,7 +71274,7 @@ function buildProviderDefinition(name, ep, ovr) {
71101
71274
  transport: ep.transport,
71102
71275
  baseUrl: stripTrailingSlash(ep.baseUrl),
71103
71276
  baseUrlEnvVars,
71104
- apiPath: ep.apiPath ?? "/v1/chat/completions",
71277
+ apiPath,
71105
71278
  apiKeyEnvVar,
71106
71279
  apiKeyAliases,
71107
71280
  apiKeyDescription: ovr?.apiKeyDescription ?? `${ep.displayName} (custom endpoint)`,
@@ -71112,7 +71285,8 @@ function buildProviderDefinition(name, ep, ovr) {
71112
71285
  shortestPrefix: name,
71113
71286
  description: ovr?.description ?? `Custom endpoint: ${ep.displayName}`,
71114
71287
  headers: ep.headers,
71115
- authScheme: ep.authScheme ?? "bearer"
71288
+ authScheme: ep.authScheme ?? "bearer",
71289
+ modelDiscovery: openaiModelsDiscovery(ep.transport, apiPath, ep.modelPrefix)
71116
71290
  };
71117
71291
  }
71118
71292
  function buildProviderProfile(ep, ovr) {
@@ -71970,7 +72144,7 @@ function isCacheFresh(data, ttlMs = CACHE_TTL_MS4) {
71970
72144
  const generatedMs = Date.parse(data.generatedAt);
71971
72145
  return !Number.isNaN(generatedMs) && Date.now() - generatedMs < ttlMs;
71972
72146
  }
71973
- async function fetchProbeModels(url = PROBE_MODELS_URL, timeoutMs = FETCH_TIMEOUT_MS5) {
72147
+ async function fetchProbeModels(url = probeModelsUrl(), timeoutMs = FETCH_TIMEOUT_MS5) {
71974
72148
  let response;
71975
72149
  try {
71976
72150
  response = await fetch(url, {
@@ -72101,8 +72275,9 @@ function isValidResponse(raw) {
72101
72275
  const data = raw;
72102
72276
  return data.version === 3 && typeof data.generationId === "string" && data.generationId.length > 0 && typeof data.generatedAt === "string" && !!data.providers && typeof data.providers === "object" && !!data.unavailable && typeof data.unavailable === "object";
72103
72277
  }
72104
- var PROBE_MODELS_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/probeModels", CACHE_TTL_MS4, FETCH_TIMEOUT_MS5 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null, DISCOVERY_ATTEMPTS = 3, DISCOVERY_TIMEOUT_MS = 8000;
72278
+ var CACHE_TTL_MS4, FETCH_TIMEOUT_MS5 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null, DISCOVERY_ATTEMPTS = 3, DISCOVERY_TIMEOUT_MS = 8000;
72105
72279
  var init_probe_catalog = __esm(() => {
72280
+ init_catalog_endpoints();
72106
72281
  init_catalog_route_bindings();
72107
72282
  CACHE_TTL_MS4 = 60 * 60 * 1000;
72108
72283
  PROBE_MODELS_CACHE_PATH = join33(homedir31(), ".claudish", "probe-models.json");
@@ -72834,6 +73009,8 @@ async function applyCandidateFilters(explanation, candidates) {
72834
73009
  }
72835
73010
  }
72836
73011
  function wireIdOf(route) {
73012
+ if (route.provider === "openrouter")
73013
+ return route.modelSpec;
72837
73014
  const at = route.modelSpec.indexOf("@");
72838
73015
  return at === -1 ? route.modelSpec : route.modelSpec.slice(at + 1);
72839
73016
  }
@@ -73420,7 +73597,7 @@ function normalizePinnedSpec(r) {
73420
73597
  const spec = r.modelSpec?.trim();
73421
73598
  if (!spec)
73422
73599
  return null;
73423
- if (spec.includes("@"))
73600
+ if (hasProviderPrefix(spec))
73424
73601
  return spec;
73425
73602
  if (spec.startsWith("http://") || spec.startsWith("https://"))
73426
73603
  return spec;
@@ -73485,6 +73662,46 @@ function claudeCodeKeychainServiceCandidates(env = process.env) {
73485
73662
  var BASE_KEYCHAIN_SERVICE = "Claude Code", KEYCHAIN_SERVICE_SUFFIX = "-credentials";
73486
73663
  var init_claude_code_facts = () => {};
73487
73664
 
73665
+ // src/fast-mode-gates.ts
73666
+ function applyProxyFastModeGates(env) {
73667
+ scrubInheritedFastModeGates(env);
73668
+ if (env.CLAUDE_CODE_DISABLE_FAST_MODE)
73669
+ return;
73670
+ const opened = [];
73671
+ if (env.CLAUDE_CODE_SKIP_FAST_MODE_ORG_CHECK === undefined) {
73672
+ env.CLAUDE_CODE_SKIP_FAST_MODE_ORG_CHECK = "1";
73673
+ opened.push("skip");
73674
+ }
73675
+ const caps = env.CLAUDE_CODE_MODEL_CAPABILITIES;
73676
+ env.CLAUDE_CODE_MODEL_CAPABILITIES = caps ? `${FAST_MODE_CAPABILITY};${caps}` : FAST_MODE_CAPABILITY;
73677
+ opened.push("caps");
73678
+ env[CLAUDISH_FAST_MODE_GATES_VAR] = opened.join(",");
73679
+ }
73680
+ function scrubInheritedFastModeGates(env) {
73681
+ const marker = env[CLAUDISH_FAST_MODE_GATES_VAR];
73682
+ if (marker === undefined)
73683
+ return { removed: [] };
73684
+ const opened = marker.split(",");
73685
+ const removed = [];
73686
+ if (opened.includes("skip") && env.CLAUDE_CODE_SKIP_FAST_MODE_ORG_CHECK === "1") {
73687
+ delete env.CLAUDE_CODE_SKIP_FAST_MODE_ORG_CHECK;
73688
+ removed.push("CLAUDE_CODE_SKIP_FAST_MODE_ORG_CHECK");
73689
+ }
73690
+ const caps = env.CLAUDE_CODE_MODEL_CAPABILITIES;
73691
+ if (opened.includes("caps") && caps !== undefined) {
73692
+ if (caps === FAST_MODE_CAPABILITY) {
73693
+ delete env.CLAUDE_CODE_MODEL_CAPABILITIES;
73694
+ removed.push("CLAUDE_CODE_MODEL_CAPABILITIES");
73695
+ } else if (caps.startsWith(`${FAST_MODE_CAPABILITY};`)) {
73696
+ env.CLAUDE_CODE_MODEL_CAPABILITIES = caps.slice(FAST_MODE_CAPABILITY.length + 1);
73697
+ removed.push("CLAUDE_CODE_MODEL_CAPABILITIES");
73698
+ }
73699
+ }
73700
+ delete env[CLAUDISH_FAST_MODE_GATES_VAR];
73701
+ return { removed };
73702
+ }
73703
+ var CLAUDISH_FAST_MODE_GATES_VAR = "CLAUDISH_FAST_MODE_GATES", FAST_MODE_CAPABILITY = "fast_mode";
73704
+
73488
73705
  // src/hooks/session/binding.ts
73489
73706
  function sessionHooksNeedBinding(engine) {
73490
73707
  return BINDING_EVENTS.some((e) => engine.select(e).length > 0);
@@ -77277,6 +77494,34 @@ var init_no_surface = __esm(() => {
77277
77494
  init_binding();
77278
77495
  });
77279
77496
 
77497
+ // src/host-routing-env.ts
77498
+ function applyHostRouting(env) {
77499
+ env[ENV.CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST] = "1";
77500
+ env[ENV.CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL] = "";
77501
+ env[ENV.CLAUDISH_SET_HOST_ROUTING_VARS] = "1";
77502
+ }
77503
+ function scrubInheritedHostRouting(env) {
77504
+ if (env[ENV.CLAUDISH_SET_HOST_ROUTING_VARS] !== "1")
77505
+ return { removed: [] };
77506
+ const removed = [];
77507
+ for (const name of HOST_ROUTING_VARS) {
77508
+ if (name in env) {
77509
+ delete env[name];
77510
+ removed.push(name);
77511
+ }
77512
+ }
77513
+ return { removed };
77514
+ }
77515
+ var HOST_ROUTING_VARS;
77516
+ var init_host_routing_env = __esm(() => {
77517
+ init_config();
77518
+ HOST_ROUTING_VARS = [
77519
+ ENV.CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST,
77520
+ ENV.CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL,
77521
+ ENV.CLAUDISH_SET_HOST_ROUTING_VARS
77522
+ ];
77523
+ });
77524
+
77280
77525
  // src/launcher/magmux-binary.ts
77281
77526
  import { execSync } from "child_process";
77282
77527
  import { existsSync as existsSync28 } from "fs";
@@ -78080,7 +78325,8 @@ async function getRecommendedModels(opts = {}) {
78080
78325
  const generationId = readAllModelsCache()?.catalogGenerationId;
78081
78326
  if (!generationId)
78082
78327
  throw new Error("No complete v3 model and plan snapshot");
78083
- const response = await fetchCatalogData(FIREBASE_RECOMMENDED_URL, RECOMMENDED_FETCH_TIMEOUT_MS, generationId);
78328
+ const base = modelsBaseUrl();
78329
+ const response = await fetchCatalogData(`${base}${RECOMMENDED_VIEW}`, RECOMMENDED_FETCH_TIMEOUT_MS, generationId);
78084
78330
  if (response.mode !== "recommended")
78085
78331
  throw new Error("Unexpected recommendation mode");
78086
78332
  if (response.recommendations.generationId !== generationId) {
@@ -78091,7 +78337,7 @@ async function getRecommendedModels(opts = {}) {
78091
78337
  } catch (err) {
78092
78338
  log(`[effort] sidecar write failed for generation ${generationId}: ${err instanceof Error ? err.message : String(err)}`);
78093
78339
  }
78094
- const top100 = await fetchCatalogData(`${FIREBASE_BASE_URL}?catalog=top100`, RECOMMENDED_FETCH_TIMEOUT_MS, generationId);
78340
+ const top100 = await fetchCatalogData(`${base}?catalog=top100`, RECOMMENDED_FETCH_TIMEOUT_MS, generationId);
78095
78341
  const data = recommendationProjection(response.recommendations, top100.models);
78096
78342
  if (data.models.length > 0) {
78097
78343
  _cachedRecommendedModels = data;
@@ -78135,27 +78381,27 @@ function isFreshEnough(doc) {
78135
78381
  return ageHours <= FIREBASE_CACHE_TTL_HOURS;
78136
78382
  }
78137
78383
  async function searchModels(query, limit = 50) {
78138
- const url = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(query)}&limit=${limit}&status=active`;
78384
+ const url = `${modelsBaseUrl()}?search=${encodeURIComponent(query)}&limit=${limit}&status=active`;
78139
78385
  const data = await fetchCatalogData(url, SEARCH_FETCH_TIMEOUT_MS);
78140
78386
  return data.models ?? [];
78141
78387
  }
78142
78388
  async function getModelByIdFromFirebase(modelId) {
78143
- const url = `${FIREBASE_BASE_URL}?modelId=${encodeURIComponent(modelId)}`;
78389
+ const url = `${modelsBaseUrl()}?modelId=${encodeURIComponent(modelId)}`;
78144
78390
  const data = await fetchCatalogData(url, SEARCH_FETCH_TIMEOUT_MS);
78145
78391
  return data.mode === "exact" ? data.model : null;
78146
78392
  }
78147
78393
  async function getTop100Models() {
78148
- const url = `${FIREBASE_BASE_URL}?catalog=top100`;
78394
+ const url = `${modelsBaseUrl()}?catalog=top100`;
78149
78395
  const data = await fetchCatalogData(url, SEARCH_FETCH_TIMEOUT_MS);
78150
78396
  return data;
78151
78397
  }
78152
78398
  async function getProviderList() {
78153
- const url = `${FIREBASE_BASE_URL}?catalog=providers`;
78399
+ const url = `${modelsBaseUrl()}?catalog=providers`;
78154
78400
  const data = await fetchCatalogData(url, SEARCH_FETCH_TIMEOUT_MS);
78155
78401
  return data.providers ?? [];
78156
78402
  }
78157
78403
  async function getModelsByProvider(provider, pageSize = 200) {
78158
- const base = `${FIREBASE_BASE_URL}?provider=${encodeURIComponent(provider)}&status=active&limit=${pageSize}`;
78404
+ const base = `${modelsBaseUrl()}?provider=${encodeURIComponent(provider)}&status=active&limit=${pageSize}`;
78159
78405
  return fetchPinnedModelDocs(base, "provider catalog");
78160
78406
  }
78161
78407
  async function fetchPinnedModelDocs(base, label) {
@@ -78193,7 +78439,7 @@ async function fetchPinnedModelDocs(base, label) {
78193
78439
  throw new Error(`${Label} exceeded the pagination limit`);
78194
78440
  }
78195
78441
  async function getAllModelDocs(pageSize = 200) {
78196
- const base = `${FIREBASE_BASE_URL}?status=active&limit=${pageSize}`;
78442
+ const base = `${modelsBaseUrl()}?status=active&limit=${pageSize}`;
78197
78443
  return fetchPinnedModelDocs(base, "model catalog");
78198
78444
  }
78199
78445
  function loadModelInfo() {
@@ -78229,7 +78475,7 @@ function getAvailableModels() {
78229
78475
  _cachedModelIds = result;
78230
78476
  return result;
78231
78477
  }
78232
- var RECOMMENDATION_SECTIONS, RECOMMENDATION_TIER_INDEX, _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels = null, FIREBASE_BASE_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/queryModels", FIREBASE_RECOMMENDED_URL, RECOMMENDED_PROJECTION_VERSION = 2, RECOMMENDED_MODELS_CACHE_PATH, RECOMMENDED_FETCH_TIMEOUT_MS = 5000, SEARCH_FETCH_TIMEOUT_MS = 1e4, RECOMMENDED_ROUTE_TIER_ORDER;
78478
+ var RECOMMENDATION_SECTIONS, RECOMMENDATION_TIER_INDEX, _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels = null, RECOMMENDED_VIEW = "?catalog=recommended", RECOMMENDED_PROJECTION_VERSION = 2, RECOMMENDED_MODELS_CACHE_PATH, RECOMMENDED_FETCH_TIMEOUT_MS = 5000, SEARCH_FETCH_TIMEOUT_MS = 1e4, RECOMMENDED_ROUTE_TIER_ORDER;
78233
78479
  var init_model_loader = __esm(() => {
78234
78480
  init_fs_atomic();
78235
78481
  init_logger();
@@ -78237,6 +78483,7 @@ var init_model_loader = __esm(() => {
78237
78483
  init_auto_route();
78238
78484
  init_cache_ttl();
78239
78485
  init_catalog_client();
78486
+ init_catalog_endpoints();
78240
78487
  init_catalog_route_bindings();
78241
78488
  init_effort_recommendations();
78242
78489
  init_route_candidates();
@@ -78258,7 +78505,6 @@ var init_model_loader = __esm(() => {
78258
78505
  { recommendationTier: "subscription", title: "Subscription", quickPickEligible: true }
78259
78506
  ];
78260
78507
  RECOMMENDATION_TIER_INDEX = new Map(RECOMMENDATION_SECTIONS.map((section, index) => [section.recommendationTier, index]));
78261
- FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
78262
78508
  RECOMMENDED_MODELS_CACHE_PATH = join41(homedir33(), ".claudish", "recommended-models-cache-v2.json");
78263
78509
  RECOMMENDED_ROUTE_TIER_ORDER = {
78264
78510
  native: 0,
@@ -83299,7 +83545,7 @@ var init_probe_live = __esm(() => {
83299
83545
  function pinProbeModelSpec(link) {
83300
83546
  if (link.provider === "native-anthropic")
83301
83547
  return link.modelSpec;
83302
- return link.modelSpec.includes("@") ? link.modelSpec : `${link.provider}@${link.modelSpec}`;
83548
+ return hasProviderPrefix(link.modelSpec) ? link.modelSpec : `${link.provider}@${link.modelSpec}`;
83303
83549
  }
83304
83550
  function droppedRemedy(credentialHint) {
83305
83551
  if (!credentialHint)
@@ -83324,6 +83570,7 @@ function probeProviderRoute(proxyUrl, link, timeoutMs) {
83324
83570
  }
83325
83571
  var INTERACTIVE_PROBE_TIMEOUT_MS = 60000, DROPPED_LABEL;
83326
83572
  var init_probe_runner = __esm(() => {
83573
+ init_model_parser();
83327
83574
  init_probe_live();
83328
83575
  DROPPED_LABEL = {
83329
83576
  "no-credential": "no credential",
@@ -90951,6 +91198,16 @@ var init_local_queue = __esm(() => {
90951
91198
 
90952
91199
  // src/providers/transport/local.ts
90953
91200
  import { Agent } from "undici";
91201
+ async function hasOllamaTagsShape(response) {
91202
+ if (!response.ok)
91203
+ return false;
91204
+ try {
91205
+ const data = await response.json();
91206
+ return Array.isArray(data?.models);
91207
+ } catch {
91208
+ return false;
91209
+ }
91210
+ }
90954
91211
 
90955
91212
  class LocalTransport {
90956
91213
  name;
@@ -90964,6 +91221,7 @@ class LocalTransport {
90964
91221
  lastProbeError;
90965
91222
  lastProbeUrl;
90966
91223
  _contextWindow = 32768;
91224
+ _isOllamaBackend;
90967
91225
  constructor(config, modelName, options) {
90968
91226
  this.config = config;
90969
91227
  this.modelName = modelName;
@@ -91005,7 +91263,7 @@ class LocalTransport {
91005
91263
  exclude,
91006
91264
  hasApiKey: Boolean(this.config.apiKey)
91007
91265
  };
91008
- if (this.config.name === "ollama") {
91266
+ if (await this.isOllamaBackend()) {
91009
91267
  return discoverViaOllama(this.config.baseUrl, {
91010
91268
  ...cacheKey,
91011
91269
  key: `ollama:${this.config.baseUrl}`
@@ -91022,8 +91280,8 @@ class LocalTransport {
91022
91280
  signal: AbortSignal.timeout(600000)
91023
91281
  };
91024
91282
  }
91025
- getExtraPayloadFields() {
91026
- if (this.config.name === "ollama") {
91283
+ async getExtraPayloadFields() {
91284
+ if (await this.isOllamaBackend()) {
91027
91285
  const numCtx = Math.max(this._contextWindow, 32768);
91028
91286
  log(`[${this.displayName}] Setting num_ctx: ${numCtx} (detected: ${this._contextWindow})`);
91029
91287
  return { options: { num_ctx: numCtx } };
@@ -91052,6 +91310,25 @@ class LocalTransport {
91052
91310
  getConfig() {
91053
91311
  return this.config;
91054
91312
  }
91313
+ async isOllamaBackend() {
91314
+ if (this.config.name === "ollama")
91315
+ return true;
91316
+ if (this.config.name !== "custom" && this.config.name in DISPLAY_NAMES2)
91317
+ return false;
91318
+ if (this._isOllamaBackend !== undefined)
91319
+ return this._isOllamaBackend;
91320
+ try {
91321
+ const response = await fetch(`${this.config.baseUrl}/api/tags`, {
91322
+ method: "GET",
91323
+ signal: AbortSignal.timeout(5000)
91324
+ });
91325
+ this._isOllamaBackend = await hasOllamaTagsShape(response);
91326
+ } catch {
91327
+ this._isOllamaBackend = false;
91328
+ }
91329
+ log(`[${this.displayName}] Ollama backend probe (${this.config.baseUrl}): ${this._isOllamaBackend}`);
91330
+ return this._isOllamaBackend;
91331
+ }
91055
91332
  async checkHealth() {
91056
91333
  if (this.healthChecked)
91057
91334
  return this.isHealthy;
@@ -91064,6 +91341,7 @@ class LocalTransport {
91064
91341
  method: "GET",
91065
91342
  signal: AbortSignal.timeout(5000)
91066
91343
  });
91344
+ this._isOllamaBackend ??= await hasOllamaTagsShape(response);
91067
91345
  if (response.ok) {
91068
91346
  this.isHealthy = true;
91069
91347
  this.healthChecked = true;
@@ -91103,7 +91381,7 @@ class LocalTransport {
91103
91381
  if (process.env.CLAUDISH_CONTEXT_WINDOW)
91104
91382
  return;
91105
91383
  log(`[${this.displayName}] Fetching context window...`);
91106
- if (this.config.name === "ollama") {
91384
+ if (await this.isOllamaBackend()) {
91107
91385
  await this.fetchOllamaContextWindow();
91108
91386
  } else if (this.config.name === "lmstudio") {
91109
91387
  await this.fetchLMStudioContextWindow();
@@ -96110,6 +96388,14 @@ var init_magmux_ui = __esm(() => {
96110
96388
  };
96111
96389
  });
96112
96390
 
96391
+ // src/signal-exit-code.ts
96392
+ import { constants as constants3 } from "os";
96393
+ function signalExitCode(signal) {
96394
+ const signum = constants3.signals[signal];
96395
+ return typeof signum === "number" ? 128 + signum : 128;
96396
+ }
96397
+ var init_signal_exit_code = () => {};
96398
+
96113
96399
  // src/terminal-isolation.ts
96114
96400
  import { format as format2 } from "util";
96115
96401
  function beginTerminalIsolation(onSuppressed) {
@@ -96232,6 +96518,12 @@ function scrubInheritedClaudishPlaceholders(env) {
96232
96518
  }
96233
96519
  return { removed };
96234
96520
  }
96521
+ function removeInheritedHostRouting(env) {
96522
+ const { removed } = scrubInheritedHostRouting(env);
96523
+ if (removed.length > 0) {
96524
+ log(`[claude-runner] Removed inherited host-routing variables: ${removed.join(", ")}`);
96525
+ }
96526
+ }
96235
96527
  function isClaudishPlaceholderCredential(name, value) {
96236
96528
  if (name === "ANTHROPIC_API_KEY")
96237
96529
  return value === CLAUDISH_PLACEHOLDER_API_KEY;
@@ -97000,6 +97292,8 @@ async function runClaudeWithProxy(config, proxyUrl, onCleanup) {
97000
97292
  if (config.monitor || advisorNativeSession) {
97001
97293
  delete env.ANTHROPIC_API_KEY;
97002
97294
  delete env.ANTHROPIC_AUTH_TOKEN;
97295
+ scrubInheritedFastModeGates(env);
97296
+ removeInheritedHostRouting(env);
97003
97297
  if (modelId) {
97004
97298
  env[ENV.ANTHROPIC_MODEL] = modelId;
97005
97299
  env[ENV.ANTHROPIC_SMALL_FAST_MODEL] = modelId;
@@ -97014,15 +97308,22 @@ async function runClaudeWithProxy(config, proxyUrl, onCleanup) {
97014
97308
  if (scrubbed.removed.length > 0) {
97015
97309
  log(`[claude-runner] Removed inherited claudish placeholder credentials: ${scrubbed.removed.join(", ")}`);
97016
97310
  }
97311
+ removeInheritedHostRouting(env);
97017
97312
  if (shouldHideIncidentalAnthropicKey(config, env)) {
97018
97313
  delete env.ANTHROPIC_API_KEY;
97019
97314
  hidAnthropicApiKey = true;
97020
97315
  }
97316
+ const closedGates = scrubInheritedFastModeGates(env);
97317
+ if (closedGates.removed.length > 0) {
97318
+ log(`[claude-runner] Removed inherited claudish fast-mode gates: ${closedGates.removed.join(", ")}`);
97319
+ }
97021
97320
  } else {
97022
97321
  if (classifierPassthroughEnabled(config)) {
97023
97322
  console.error("[claudish] classifier passthrough enabled but no Anthropic credentials detected \u2014 " + "classifier requests will fail to authenticate against api.anthropic.com. " + "Map a role to a native Claude model (e.g. --model-sonnet claude-sonnet-5) or set ANTHROPIC_API_KEY.");
97024
97323
  }
97025
97324
  applyProxyPlaceholderAuth(env);
97325
+ applyProxyFastModeGates(env);
97326
+ applyHostRouting(env);
97026
97327
  const realWindow = await computeMainThreadContextWindow(config);
97027
97328
  const contextEnv = resolveContextWindowEnv(realWindow, process.env);
97028
97329
  Object.assign(env, contextEnv.vars);
@@ -97198,7 +97499,7 @@ Or set CLAUDE_PATH to your custom installation:`);
97198
97499
  setClaudeCodeRunning(false);
97199
97500
  const paneExit = wrap?.paneExitCode() ?? null;
97200
97501
  resolve({
97201
- exitCode: paneExit !== null ? paneExit : signal ? 128 + (SIGNAL_EXIT_NUMBERS[signal] ?? 0) : code ?? 1,
97502
+ exitCode: paneExit !== null ? paneExit : signal ? signalExitCode(signal) : code ?? 1,
97202
97503
  exitSignal: signal
97203
97504
  });
97204
97505
  });
@@ -97226,6 +97527,7 @@ function sessionOutcomeOf(exitCode) {
97226
97527
  }
97227
97528
  function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
97228
97529
  const signals = isWindows2() ? ["SIGINT", "SIGTERM"] : ["SIGINT", "SIGTERM", "SIGHUP"];
97530
+ claimSignalExit();
97229
97531
  for (const signal of signals) {
97230
97532
  process.on(signal, () => {
97231
97533
  releaseTerminalIsolation();
@@ -97242,7 +97544,7 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
97242
97544
  try {
97243
97545
  unlinkSync11(tempSettingsPath);
97244
97546
  } catch {}
97245
- process.exit(128 + (SIGNAL_EXIT_NUMBERS[signal] ?? 0));
97547
+ process.exit(signalExitCode(signal));
97246
97548
  });
97247
97549
  }
97248
97550
  }
@@ -97345,7 +97647,7 @@ var restoreTerminal = null, macosKeychainAnthropicMemo, defaultKeychainAnthropic
97345
97647
  }
97346
97648
  macosKeychainAnthropicMemo.set(memoKey, found);
97347
97649
  return found;
97348
- }, CLAUDISH_PLACEHOLDER_API_KEY = "sk-ant-api03-placeholder-not-used-proxy-handles-auth-with-openrouter-key-xxxxxxxxxxxxxxxxxxxxx", CLAUDISH_PLACEHOLDER_AUTH_TOKEN = "placeholder-token-not-used-proxy-handles-auth", STALE_TOKEN_FILE_MS, MAX_TOKEN_FILES_SCANNED = 4000, CLAUDE_CODE_DEFAULT_MAX_CONTEXT = 200000, USER_STATUS_LINE_TIMEOUT_SECONDS = 3, MIN_AUTO_COMPACT_WINDOW = 200000, MAX_AUTO_COMPACT_WINDOW = 1e6, ADVISOR_TOOL_ENV_VAR = "CLAUDE_CODE_ENABLE_EXPERIMENTAL_ADVISOR_TOOL", CLAUDISH_CHILD_ADVISOR_MODEL = "sonnet", CHILD_STDERR_NOISE, SIGNAL_EXIT_NUMBERS;
97650
+ }, CLAUDISH_PLACEHOLDER_API_KEY = "sk-ant-api03-placeholder-not-used-proxy-handles-auth-with-openrouter-key-xxxxxxxxxxxxxxxxxxxxx", CLAUDISH_PLACEHOLDER_AUTH_TOKEN = "placeholder-token-not-used-proxy-handles-auth", STALE_TOKEN_FILE_MS, MAX_TOKEN_FILES_SCANNED = 4000, CLAUDE_CODE_DEFAULT_MAX_CONTEXT = 200000, USER_STATUS_LINE_TIMEOUT_SECONDS = 3, MIN_AUTO_COMPACT_WINDOW = 200000, MAX_AUTO_COMPACT_WINDOW = 1e6, ADVISOR_TOOL_ENV_VAR = "CLAUDE_CODE_ENABLE_EXPERIMENTAL_ADVISOR_TOOL", CLAUDISH_CHILD_ADVISOR_MODEL = "sonnet", CHILD_STDERR_NOISE;
97349
97651
  var init_claude_runner = __esm(() => {
97350
97652
  init_model_catalog();
97351
97653
  init_claude_code_facts();
@@ -97356,6 +97658,7 @@ var init_claude_runner = __esm(() => {
97356
97658
  init_interactive_driver();
97357
97659
  init_interactive_launch();
97358
97660
  init_no_surface();
97661
+ init_host_routing_env();
97359
97662
  init_magmux_wrapper();
97360
97663
  init_logger();
97361
97664
  init_child_env();
@@ -97369,18 +97672,13 @@ var init_claude_runner = __esm(() => {
97369
97672
  init_settings();
97370
97673
  init_session_discovery();
97371
97674
  init_token_file();
97675
+ init_signal_exit_code();
97372
97676
  init_telemetry();
97373
97677
  init_terminal_isolation();
97374
97678
  init_theme_mode();
97375
97679
  macosKeychainAnthropicMemo = new Map;
97376
97680
  STALE_TOKEN_FILE_MS = 7 * 24 * 60 * 60 * 1000;
97377
97681
  CHILD_STDERR_NOISE = [/^\[claude-code:unrecognized_model\]/];
97378
- SIGNAL_EXIT_NUMBERS = {
97379
- SIGHUP: 1,
97380
- SIGINT: 2,
97381
- SIGQUIT: 3,
97382
- SIGTERM: 15
97383
- };
97384
97682
  });
97385
97683
 
97386
97684
  // src/pane/contract.ts
@@ -97860,7 +98158,7 @@ var init_accounting = __esm(() => {
97860
98158
 
97861
98159
  // src/pane/pane-registry.ts
97862
98160
  import {
97863
- constants as constants3,
98161
+ constants as constants4,
97864
98162
  accessSync as accessSync2,
97865
98163
  existsSync as existsSync38,
97866
98164
  lstatSync as lstatSync7,
@@ -98233,7 +98531,7 @@ function dialErrno(reported, sockPath) {
98233
98531
  if (!isSocket)
98234
98532
  return "ENOTSOCK";
98235
98533
  try {
98236
- accessSync2(sockPath, constants3.W_OK);
98534
+ accessSync2(sockPath, constants4.W_OK);
98237
98535
  } catch {
98238
98536
  return "EACCES";
98239
98537
  }
@@ -102490,7 +102788,7 @@ var init_transcript_redaction = __esm(() => {
102490
102788
 
102491
102789
  // src/pane/transcript-page.ts
102492
102790
  import {
102493
- constants as constants4,
102791
+ constants as constants5,
102494
102792
  closeSync as closeSync14,
102495
102793
  fstatSync as fstatSync5,
102496
102794
  lstatSync as lstatSync8,
@@ -102856,7 +103154,7 @@ var init_transcript_page = __esm(() => {
102856
103154
  maxEntryBytes: 32 * 1024 * 1024
102857
103155
  };
102858
103156
  READ_CHUNK = 1024 * 1024;
102859
- OPEN_FLAGS = constants4.O_RDONLY | (constants4.O_NOFOLLOW ?? 0) | (constants4.O_NONBLOCK ?? 0);
103157
+ OPEN_FLAGS = constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0) | (constants5.O_NONBLOCK ?? 0);
102860
103158
  loggedRejections = new Set;
102861
103159
  HEAD_CWD_MAX_BYTES = 256 * 1024;
102862
103160
  });
@@ -102887,7 +103185,7 @@ var init_pane = __esm(() => {
102887
103185
 
102888
103186
  // src/mcp-session/replay-manager.ts
102889
103187
  import { randomBytes as randomBytes13, randomUUID as randomUUID9 } from "crypto";
102890
- import { constants as constants5, accessSync as accessSync3, closeSync as closeSync15, existsSync as existsSync39, realpathSync as realpathSync9, statSync as statSync21 } from "fs";
103188
+ import { constants as constants6, accessSync as accessSync3, closeSync as closeSync15, existsSync as existsSync39, realpathSync as realpathSync9, statSync as statSync21 } from "fs";
102891
103189
  import { dirname as dirname23, resolve as resolve7 } from "path";
102892
103190
  function unavailable2(reason, message) {
102893
103191
  return new ContractErrorException("replay_unavailable", message, reason);
@@ -102910,7 +103208,7 @@ async function replayClaudeBinary(env) {
102910
103208
  try {
102911
103209
  if (!statSync21(named).isFile())
102912
103210
  throw new Error("not a file");
102913
- accessSync3(named, constants5.X_OK);
103211
+ accessSync3(named, constants6.X_OK);
102914
103212
  } catch {
102915
103213
  throw new Error(`CLAUDE_PATH ${named} is not an executable file`);
102916
103214
  }
@@ -106167,6 +106465,8 @@ function claudeCodePrintEnv(parent) {
106167
106465
  delete env.ANTHROPIC_API_KEY;
106168
106466
  delete env.ANTHROPIC_AUTH_TOKEN;
106169
106467
  delete env.ANTHROPIC_BASE_URL;
106468
+ scrubInheritedFastModeGates(env);
106469
+ scrubInheritedHostRouting(env);
106170
106470
  return env;
106171
106471
  }
106172
106472
  function isFrame(v) {
@@ -106357,6 +106657,7 @@ function startError(command, e) {
106357
106657
  var PRINT_FLAGS, PRINT_CHILD_DROPPED_MARKERS, inFlight4, KILL_GRACE_MS = 5000, STDERR_TAIL_CHARS = 2000;
106358
106658
  var init_run_prompt_claude_code = __esm(() => {
106359
106659
  init_config();
106660
+ init_host_routing_env();
106360
106661
  init_child_env();
106361
106662
  init_pane_launch();
106362
106663
  init_redact();
@@ -120341,6 +120642,9 @@ function shouldWarmCatalog(args) {
120341
120642
  if (m.startsWith(prefix))
120342
120643
  return false;
120343
120644
  }
120645
+ const routesOnlyNative = !args.forceUpdate && !args.advisor && !args.modelChain?.length && !args.modelOpus && !args.modelSonnet && !args.modelHaiku && !args.modelSubagent;
120646
+ if (args.model && routesOnlyNative && nativeRouteFor(args.model))
120647
+ return false;
120344
120648
  return true;
120345
120649
  }
120346
120650
  function classifyCatalogState(cache, ttlHours, now) {
@@ -120396,10 +120700,7 @@ function startSpinner(label, quiet = false) {
120396
120700
  };
120397
120701
  }
120398
120702
  async function warmCatalogIfNeeded(config, opts) {
120399
- if (!shouldWarmCatalog({
120400
- model: config.model,
120401
- skipModelsUpdate: config.skipModelsUpdate
120402
- })) {
120703
+ if (!shouldWarmCatalog(config)) {
120403
120704
  return "skipped";
120404
120705
  }
120405
120706
  if (!config.quiet) {
@@ -120467,6 +120768,7 @@ var HARD_FAIL_MESSAGE, LOCAL_MODEL_PREFIXES;
120467
120768
  var init_catalog_warm = __esm(() => {
120468
120769
  init_all_models_cache();
120469
120770
  init_catalog_client();
120771
+ init_native_route();
120470
120772
  HARD_FAIL_MESSAGE = `Error: cannot reach model catalog and no cached copy found.
120471
120773
  ` + `
120472
120774
  ` + `To proceed:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "14.16.1",
3
+ "version": "14.17.0",
4
4
  "description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -71,10 +71,10 @@
71
71
  "ai"
72
72
  ],
73
73
  "optionalDependencies": {
74
- "@claudish/magmux-darwin-arm64": "14.16.1",
75
- "@claudish/magmux-darwin-x64": "14.16.1",
76
- "@claudish/magmux-linux-arm64": "14.16.1",
77
- "@claudish/magmux-linux-x64": "14.16.1"
74
+ "@claudish/magmux-darwin-arm64": "14.17.0",
75
+ "@claudish/magmux-darwin-x64": "14.17.0",
76
+ "@claudish/magmux-linux-arm64": "14.17.0",
77
+ "@claudish/magmux-linux-x64": "14.17.0"
78
78
  },
79
79
  "author": "Jack Rudenko <i@madappgang.com>",
80
80
  "license": "MIT",