github-router 0.3.311 → 0.3.312

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 (29) hide show
  1. package/dist/{attribution-settings-jLxSnmZT.js → attribution-settings-os6aa-ck.js} +125 -14
  2. package/dist/attribution-settings-os6aa-ck.js.map +1 -0
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/{claude-DhvQETaa.js → claude-CHObdsb5.js} +111 -42
  5. package/dist/claude-CHObdsb5.js.map +1 -0
  6. package/dist/{codex-RJQPJ--K.js → codex-CUQklRRv.js} +4 -4
  7. package/dist/{codex-RJQPJ--K.js.map → codex-CUQklRRv.js.map} +1 -1
  8. package/dist/engine-DyzGsCUb.js +2 -0
  9. package/dist/{gate-discovery-DDkRvyYL.js → gate-discovery-_flEdhYo.js} +2 -2
  10. package/dist/{gate-discovery-DDkRvyYL.js.map → gate-discovery-_flEdhYo.js.map} +1 -1
  11. package/dist/{internal-stop-hook-YyYVQbbN.js → internal-stop-hook-BJ3o61-L.js} +2 -2
  12. package/dist/{internal-stop-hook-YyYVQbbN.js.map → internal-stop-hook-BJ3o61-L.js.map} +1 -1
  13. package/dist/main.js +5 -5
  14. package/dist/{peer-mcp-personas-O35uSWsX.js → peer-mcp-personas-DklYru_1.js} +236 -58
  15. package/dist/peer-mcp-personas-DklYru_1.js.map +1 -0
  16. package/dist/{provision-Ho5v-tt-.js → provision-BYdIsKcp.js} +2 -2
  17. package/dist/{provision-Ho5v-tt-.js.map → provision-BYdIsKcp.js.map} +1 -1
  18. package/dist/{serve-Cb-sUTL8.js → serve-B70Kczq6.js} +5 -5
  19. package/dist/{serve-Cb-sUTL8.js.map → serve-B70Kczq6.js.map} +1 -1
  20. package/dist/{server-setup-OTy-qHfv.js → server-setup-DX27fdcf.js} +244 -18
  21. package/dist/server-setup-DX27fdcf.js.map +1 -0
  22. package/dist/{start-Ch_iOkQE.js → start-JbcSzClY.js} +3 -3
  23. package/dist/{start-Ch_iOkQE.js.map → start-JbcSzClY.js.map} +1 -1
  24. package/package.json +1 -1
  25. package/dist/attribution-settings-jLxSnmZT.js.map +0 -1
  26. package/dist/claude-DhvQETaa.js.map +0 -1
  27. package/dist/engine-DuiPBB4G.js +0 -2
  28. package/dist/peer-mcp-personas-O35uSWsX.js.map +0 -1
  29. package/dist/server-setup-OTy-qHfv.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { $ as UNKNOWN_EFFORT_ANCHOR, At as shimDefaultsToXhigh, B as resolveAdvisorEffort, Bt as warnOnTokenPriceDrift, Cn as oneMContextDisabled, D as toolbeltEnabled, En as withInstallLock, F as ADVISOR_TOOL_INSTRUCTIONS, Ft as getTokenizerFromModel, G as repairRejectedThinkingHistory, Gt as readResponseBodyCapped, H as formatThinkingRepairDecline, Ht as createResponses, I as FAST_ADVISOR_TOOL_INSTRUCTIONS, It as findLaunchBySecret, J as isControllerClosedError, K as buildAnthropicErrorEvent, Kt as parseJsonOrDiagnose, L as buildAdvisorStream, Mt as createMessages, N as searchWeb, Nt as getTextTokenCount, P as ADVISOR_INTERNAL_TOOL_NAME, Pt as getTokenCount, Q as EFFORT_ORDER, R as injectAdvisorTool, Sn as catalogAdvertises1M, Tn as withOneMSuffixForLead, U as rememberThinkingHistoryRepair, Ut as createChatCompletions, V as resolveAdvisorModel, Vt as resolveMcpToolTimeoutMs, W as repairKnownThinkingHistory, Wt as MAX_RESPONSE_BODY_BYTES, X as readIteratorWithTimeout, Y as logStreamError, Z as relayAnthropicStream, bn as upstreamMaxConnections, cn as BUDGET_SMALL_FAST_SLUG, et as bucketEffort, gn as isBudgetClaudeLead, hn as generateRandomPort, i as assertMcpToolSurfaceConsistent, it as agentToolsEnabled, jt as countTokens, mn as UPSTREAM_INACTIVITY_TIMEOUT_MS, nt as handleMcpDelete, on as toolbeltPathOverride, pn as UPSTREAM_FETCH_TIMEOUT_MS, q as buildOpenAIErrorEvent, qt as normalizeOpenAIUsage, rt as handleMcpPost, tn as provisionTreeSitterAssets, tt as clampEffort, wn as withOneMSuffix, xn as classifyMessagesRoute, yn as upstreamAllowH2, z as isAdvisorRequested, zt as assembleResponsesPayload } from "./peer-mcp-personas-O35uSWsX.js";
1
+ import { $ as UNKNOWN_EFFORT_ANCHOR, An as CHEAP_PROFILE_MODELS, B as resolveAdvisorEffort, Cn as upstreamMaxConnections, D as toolbeltEnabled, Dn as withOneMSuffix, En as oneMContextDisabled, F as ADVISOR_TOOL_INSTRUCTIONS, Fn as withInstallLock, Ft as createMessages, G as repairRejectedThinkingHistory, Gt as createResponses, H as formatThinkingRepairDecline, Ht as assembleResponsesPayload, I as FAST_ADVISOR_TOOL_INSTRUCTIONS, It as getTextTokenCount, J as isControllerClosedError, Jt as readResponseBodyCapped, K as buildAnthropicErrorEvent, Kt as createChatCompletions, L as buildAdvisorStream, Lt as getTokenCount, N as searchWeb, Nt as shimDefaultsToXhigh, On as withOneMSuffixForLead, P as ADVISOR_INTERNAL_TOOL_NAME, Pn as CHEAP_PROFILE_SUBAGENT_CONTEXT_TOKENS, Pt as countTokens, Q as EFFORT_ORDER, R as injectAdvisorTool, Rt as getTokenizerFromModel, Sn as upstreamAllowH2, Tn as catalogAdvertises1M, U as rememberThinkingHistoryRepair, Ut as warnOnTokenPriceDrift, V as resolveAdvisorModel, W as repairKnownThinkingHistory, Wt as resolveMcpToolTimeoutMs, X as readIteratorWithTimeout, Xt as normalizeOpenAIUsage, Y as logStreamError, Yt as parseJsonOrDiagnose, Z as relayAnthropicStream, _n as UPSTREAM_INACTIVITY_TIMEOUT_MS, dn as BUDGET_SMALL_FAST_SLUG, et as bucketEffort, gn as UPSTREAM_FETCH_TIMEOUT_MS, i as assertMcpToolSurfaceConsistent, in as provisionTreeSitterAssets, it as agentToolsEnabled, jn as CHEAP_PROFILE_NATIVE_AGENT_NAMES, kn as CHEAP_PROFILE_ADVISOR_CLIENT_MODEL, ln as toolbeltPathOverride, nt as handleMcpDelete, q as buildOpenAIErrorEvent, qt as MAX_RESPONSE_BODY_BYTES, rt as handleMcpPost, tt as clampEffort, vn as generateRandomPort, wn as classifyMessagesRoute, yn as isBudgetClaudeLead, z as isAdvisorRequested, zt as findLaunchBySecret } from "./peer-mcp-personas-DklYru_1.js";
2
2
  import { t as getPackageVersion } from "./version-C8x2hQrZ.js";
3
3
  import { i as ensurePaths, t as PATHS } from "./paths-De1Qh9Q9.js";
4
4
  import { t as state } from "./state-B8adscCv.js";
@@ -380,6 +380,46 @@ const FAST_PROFILE = Object.freeze({
380
380
  hasCoordinator: false
381
381
  });
382
382
  /**
383
+ * The `-m cheap1m` roster: the named successor of the original cheap launch.
384
+ * Identical to `cheap` except the Gemini leader keeps its full 1M window
385
+ * (the `-m cheap1m` lead slug is `[1m]`-decorated) and the `astra` peer
386
+ * remains in the persona allowlist next to Oracle. Oracle and Astra run at
387
+ * the 200K default window like every cheap-family role. Hard-denies match
388
+ * fast's: core workers, `orchestrate`, `decide`, `fleet`, and `first-mate`.
389
+ */
390
+ const CHEAP1M_PROFILE = Object.freeze({
391
+ id: "cheap1m",
392
+ nativeRoster: new Set(CHEAP_PROFILE_NATIVE_AGENT_NAMES),
393
+ personaAllowlist: /* @__PURE__ */ new Set(["oracle", "astra"]),
394
+ allowedGroups: /* @__PURE__ */ new Set([
395
+ "peers",
396
+ "search",
397
+ "workers",
398
+ "browser"
399
+ ]),
400
+ hasCoordinator: false
401
+ });
402
+ /**
403
+ * The `-m cheap` roster: the exact `fast` surface and groups, minus the 1M
404
+ * accounting decoration on the LEAD as well (`-m cheap` selects the BARE
405
+ * `gemini-3.8-flash` slug, so the leader runs at the 200K default window
406
+ * too), plus a cheaper `grok-4.6`/medium Oracle and NO `astra` peer.
407
+ * Hard-denies match fast's: core workers, `orchestrate`, `decide`, `fleet`,
408
+ * and `first-mate`.
409
+ */
410
+ const CHEAP_PROFILE = Object.freeze({
411
+ id: "cheap",
412
+ nativeRoster: new Set(CHEAP_PROFILE_NATIVE_AGENT_NAMES),
413
+ personaAllowlist: /* @__PURE__ */ new Set(["oracle"]),
414
+ allowedGroups: /* @__PURE__ */ new Set([
415
+ "peers",
416
+ "search",
417
+ "workers",
418
+ "browser"
419
+ ]),
420
+ hasCoordinator: false
421
+ });
422
+ /**
383
423
  * The `-m max` profile: Sol/Luna-led, browse-only workers, and explicit
384
424
  * cross-lab peer names. The descriptor is a hard projection for bound launch
385
425
  * requests; unbound/BYO traffic remains standard because it has no registry
@@ -412,6 +452,8 @@ const MAX_PROFILE = Object.freeze({
412
452
  function profileDescriptor(id) {
413
453
  if (id === "fast") return FAST_PROFILE;
414
454
  if (id === "max") return MAX_PROFILE;
455
+ if (id === "cheap1m") return CHEAP1M_PROFILE;
456
+ if (id === "cheap") return CHEAP_PROFILE;
415
457
  return STANDARD_PROFILE;
416
458
  }
417
459
  /**
@@ -429,6 +471,8 @@ function resolveLaunchProfile(modelArg) {
429
471
  const arg = modelArg?.trim().toLowerCase();
430
472
  if (arg === "fast") return "fast";
431
473
  if (arg === "max") return "max";
474
+ if (arg === "cheap1m") return "cheap1m";
475
+ if (arg === "cheap") return "cheap";
432
476
  return "standard";
433
477
  }
434
478
  function validateMaxProfileLaunch(catalog) {
@@ -643,6 +687,104 @@ function validateFastProfilePrerequisites(catalog) {
643
687
  function formatFastPrerequisiteFailure(missing) {
644
688
  return "github-router claude -m fast requires the following live-catalog capabilities, which this account's catalog does not fully provide:\n" + missing.map((m) => ` - ${m}`).join("\n") + "\n\nFalling back or silently dropping an agent is not supported for the fast profile's exact roster. Run plain `github-router claude` instead.";
645
689
  }
690
+ /** The subagent window floor: every cheap subagent must at least EXCEED the
691
+ * Claude Code default budget it runs at. Unlike fast, the catalog's real
692
+ * window is irrelevant to what the client sends (bare slug = 200K either
693
+ * way); this floor only guarantees the billed model isn't tiny. */
694
+ const CHEAP_SUBAGENT_MIN_CONTEXT_TOKENS = CHEAP_PROFILE_SUBAGENT_CONTEXT_TOKENS;
695
+ /**
696
+ * Shared cheap-family roster prerequisite check, parameterized only by the
697
+ * LEAD's context gate. Both `-m cheap` (200K lead floor) and `-m cheap1m`
698
+ * (1M lead window) validate the EXACT same five-agent roster: the lead gate
699
+ * is the only requirement that differs between the two cheap siblings, and
700
+ * every subagent runs at the 200K default window either way. A non-1M
701
+ * luna/sol/sonnet/grok is acceptable as long as the roster models advertise
702
+ * tool calls, the fixed effort, and a supported endpoint.
703
+ */
704
+ function collectCheapPrerequisiteMissing(catalog, leadGateTokens, leadGateMessage) {
705
+ const missing = [];
706
+ const gemini = findModel(catalog, CHEAP_PROFILE_MODELS.lead);
707
+ if (!gemini) missing.push(`${CHEAP_PROFILE_MODELS.lead}: absent from the live catalog`);
708
+ else {
709
+ if (!hasToolCalls(gemini)) missing.push(`${CHEAP_PROFILE_MODELS.lead}: does not advertise tool_calls`);
710
+ if (!hasContextAtLeast(gemini, leadGateTokens)) missing.push(leadGateMessage(CHEAP_PROFILE_MODELS.lead));
711
+ if (!supportsEffort(gemini, "high")) missing.push(`${CHEAP_PROFILE_MODELS.lead}: does not advertise a "high" reasoning effort`);
712
+ if (!supportsEndpoint(gemini, "chat")) missing.push(`${CHEAP_PROFILE_MODELS.lead}: does not advertise a supported chat-completions endpoint`);
713
+ }
714
+ const luna = findModel(catalog, CHEAP_PROFILE_MODELS.explore);
715
+ if (!luna) missing.push(`${CHEAP_PROFILE_MODELS.explore}: absent from the live catalog`);
716
+ else {
717
+ if (!hasToolCalls(luna)) missing.push(`${CHEAP_PROFILE_MODELS.explore}: does not advertise tool_calls`);
718
+ if (!hasContextAtLeast(luna, CHEAP_SUBAGENT_MIN_CONTEXT_TOKENS)) missing.push(`${CHEAP_PROFILE_MODELS.explore}: advertised context window is below the 200K subagent floor`);
719
+ if (!supportsEffort(luna, "high") || !supportsEffort(luna, "max")) missing.push(`${CHEAP_PROFILE_MODELS.explore}: does not advertise both "high" and "max" reasoning effort`);
720
+ if (!supportsEndpoint(luna, "responses")) missing.push(`${CHEAP_PROFILE_MODELS.explore}: does not advertise a supported Responses endpoint`);
721
+ }
722
+ const sol = findModel(catalog, CHEAP_PROFILE_MODELS.plan);
723
+ if (!sol) missing.push(`${CHEAP_PROFILE_MODELS.plan}: absent from the live catalog`);
724
+ else {
725
+ if (!hasToolCalls(sol)) missing.push(`${CHEAP_PROFILE_MODELS.plan}: does not advertise tool_calls`);
726
+ if (!hasContextAtLeast(sol, CHEAP_SUBAGENT_MIN_CONTEXT_TOKENS)) missing.push(`${CHEAP_PROFILE_MODELS.plan}: advertised context window is below the 200K subagent floor`);
727
+ if (!supportsEffort(sol, "high")) missing.push(`${CHEAP_PROFILE_MODELS.plan}: does not advertise a "high" reasoning effort`);
728
+ if (!supportsEndpoint(sol, "responses")) missing.push(`${CHEAP_PROFILE_MODELS.plan}: does not advertise a supported Responses endpoint`);
729
+ }
730
+ const reviewer = findModel(catalog, CHEAP_PROFILE_MODELS.reviewer);
731
+ if (!reviewer) missing.push(`${CHEAP_PROFILE_MODELS.reviewer}: absent from the live catalog`);
732
+ else {
733
+ if (!hasToolCalls(reviewer)) missing.push(`${CHEAP_PROFILE_MODELS.reviewer}: does not advertise tool_calls`);
734
+ if (!hasContextAtLeast(reviewer, CHEAP_SUBAGENT_MIN_CONTEXT_TOKENS)) missing.push(`${CHEAP_PROFILE_MODELS.reviewer}: advertised context window is below the 200K subagent floor`);
735
+ if (!supportsEffort(reviewer, "max")) missing.push(`${CHEAP_PROFILE_MODELS.reviewer}: does not advertise a "max" reasoning effort`);
736
+ if (!supportsEndpoint(reviewer, "responses")) missing.push(`${CHEAP_PROFILE_MODELS.reviewer}: does not advertise a supported Responses endpoint`);
737
+ }
738
+ const grok = findModel(catalog, CHEAP_PROFILE_MODELS.oracle);
739
+ if (!grok) missing.push(`${CHEAP_PROFILE_MODELS.oracle}: absent from the live catalog`);
740
+ else {
741
+ if (!hasContextAtLeast(grok, CHEAP_SUBAGENT_MIN_CONTEXT_TOKENS)) missing.push(`${CHEAP_PROFILE_MODELS.oracle}: advertised context window is below the 200K subagent floor`);
742
+ if (!supportsEffort(grok, "medium")) missing.push(`${CHEAP_PROFILE_MODELS.oracle}: does not advertise a "medium" reasoning effort`);
743
+ if (!hasUsablePromptMetadata(grok)) missing.push(`${CHEAP_PROFILE_MODELS.oracle}: no usable max_prompt_tokens metadata`);
744
+ if (!supportsEndpoint(grok, "responses")) missing.push(`${CHEAP_PROFILE_MODELS.oracle}: does not advertise a supported Responses endpoint`);
745
+ }
746
+ return missing;
747
+ }
748
+ /**
749
+ * Validate the live Copilot catalog for `-m cheap1m` (the named successor of
750
+ * the original cheap launch): the Gemini leader must still advertise 1M, so
751
+ * the lead keeps its full window while every subagent runs at the 200K
752
+ * default. Roster and capability checks are otherwise identical to `cheap`.
753
+ */
754
+ function validateCheap1mProfilePrerequisites(catalog) {
755
+ const missing = collectCheapPrerequisiteMissing(catalog, FAST_REQUIRED_CONTEXT_TOKENS, (id) => `${id}: advertised context window is below 1M (leader window)`);
756
+ return {
757
+ ok: missing.length === 0,
758
+ missing
759
+ };
760
+ }
761
+ /**
762
+ * Validate the live Copilot catalog for `-m cheap`: the Gemini leader runs
763
+ * at the 200K DEFAULT window (bare slug), so the lead only needs to clear
764
+ * the same 200K floor as every subagent — unlike `cheap1m`, which keeps the
765
+ * 1M leader window. Roster and capability checks are otherwise identical.
766
+ */
767
+ function validateCheapProfilePrerequisites(catalog) {
768
+ const missing = collectCheapPrerequisiteMissing(catalog, CHEAP_SUBAGENT_MIN_CONTEXT_TOKENS, (id) => `${id}: advertised context window is below the 200K lead floor`);
769
+ return {
770
+ ok: missing.length === 0,
771
+ missing
772
+ };
773
+ }
774
+ /**
775
+ * Format `validateCheap1mProfilePrerequisites`'s failure list into the launch
776
+ * error message: every missing/invalid model, plus the rollback command.
777
+ */
778
+ function formatCheap1mPrerequisiteFailure(missing) {
779
+ return "github-router claude -m cheap1m requires the following live-catalog capabilities, which this account's catalog does not fully provide:\n" + missing.map((m) => ` - ${m}`).join("\n") + "\n\nFalling back or silently dropping an agent is not supported for the cheap1m profile's exact roster. Run plain `github-router claude` instead.";
780
+ }
781
+ /**
782
+ * Format `validateCheapProfilePrerequisites`'s failure list into the launch
783
+ * error message: every missing/invalid model, plus the rollback command.
784
+ */
785
+ function formatCheapPrerequisiteFailure(missing) {
786
+ return "github-router claude -m cheap requires the following live-catalog capabilities, which this account's catalog does not fully provide:\n" + missing.map((m) => ` - ${m}`).join("\n") + "\n\nFalling back or silently dropping an agent is not supported for the cheap profile's exact roster. Run plain `github-router claude` instead.";
787
+ }
646
788
  //#endregion
647
789
  //#region src/lib/file-log-reporter.ts
648
790
  const MAX_LOG_BYTES = 1048576;
@@ -981,6 +1123,32 @@ const MAX_PICKER_MODELS = Object.freeze([
981
1123
  behavesAs: "claude-opus-5"
982
1124
  }
983
1125
  ]);
1126
+ const CHEAP_PICKER_MODELS = Object.freeze([
1127
+ {
1128
+ id: "gpt-5.6-sol",
1129
+ label: "GPT-5.6 Sol",
1130
+ behavesAs: "claude-opus-5",
1131
+ neverOneM: true
1132
+ },
1133
+ {
1134
+ id: "gpt-5.6-luna",
1135
+ label: "GPT-5.6 Luna",
1136
+ behavesAs: "claude-opus-5",
1137
+ neverOneM: true
1138
+ },
1139
+ {
1140
+ id: "gemini-3.8-flash",
1141
+ label: "Gemini 3.8 Flash",
1142
+ behavesAs: "claude-sonnet-5",
1143
+ neverOneM: true
1144
+ },
1145
+ {
1146
+ id: "grok-4.6",
1147
+ label: "Grok 4.6",
1148
+ behavesAs: "claude-sonnet-5",
1149
+ neverOneM: true
1150
+ }
1151
+ ]);
984
1152
  /**
985
1153
  * Return the ordered, profile-specific `/model` rows supported by the live
986
1154
  * Copilot catalog. Fast intentionally shares Standard's four-row inventory;
@@ -998,7 +1166,7 @@ function selectableModelsInCatalog(profile) {
998
1166
  const catalog = state.models?.data;
999
1167
  if (!catalog || catalog.length === 0) return [];
1000
1168
  const present = new Set(catalog.map((entry) => entry.id));
1001
- return (profile === "max" ? MAX_PICKER_MODELS : STANDARD_PICKER_MODELS).filter((entry) => present.has(entry.id)).map((entry) => ({
1169
+ return (profile === "max" ? MAX_PICKER_MODELS : profile === "cheap" || profile === "cheap1m" ? CHEAP_PICKER_MODELS : STANDARD_PICKER_MODELS).filter((entry) => present.has(entry.id)).map((entry) => ({
1002
1170
  model: entry.neverOneM ? entry.id : withOneMSuffix(entry.id),
1003
1171
  label: entry.label,
1004
1172
  behavesAs: entry.behavesAs
@@ -1938,7 +2106,7 @@ function collectToolFieldKeys(body) {
1938
2106
  //#endregion
1939
2107
  //#region package.json
1940
2108
  var name = "github-router";
1941
- var version = "0.3.311";
2109
+ var version = "0.3.312";
1942
2110
  //#endregion
1943
2111
  //#region src/lib/approval.ts
1944
2112
  const awaitApproval = async () => {
@@ -4910,10 +5078,16 @@ function preprocessMaxRequest(rawBody, launch, subagentRequest = false) {
4910
5078
  Object.freeze([MAX_LUNA_HIGH_ALIAS_ID, MAX_LUNA_MAX_ALIAS_ID]);
4911
5079
  //#endregion
4912
5080
  //#region src/lib/fast-request-preprocess.ts
5081
+ const cheapFamily = (profileId) => profileId === "cheap" || profileId === "cheap1m";
4913
5082
  /**
4914
- * Apply authenticated fast-profile model and effort policy before ordinary model
4915
- * resolution. Synthetic aliases are refused outside an authenticated fast
4916
- * launch, so raw/BYO traffic cannot opt itself into private profile semantics.
5083
+ * Apply authenticated fast/cheap-profile model and effort policy before
5084
+ * ordinary model resolution. Synthetic aliases are refused outside an
5085
+ * authenticated fast or cheap launch, so raw/BYO traffic cannot opt itself
5086
+ * into private profile semantics. The cheap family shares fast's effort
5087
+ * mapping (same model-to-effort rows, just bare subagent slugs at the
5088
+ * wiring layer), so this preprocess is shared. Note the reviewer differs:
5089
+ * fast reviews on Sonnet 5/xhigh while cheap reviews on Luna/max — both
5090
+ * rows exist here, so each profile's reviewer resolves to its fixed effort.
4917
5091
  */
4918
5092
  function preprocessFastRequest(rawBody, launch, subagentRequest = false) {
4919
5093
  if (launch?.profileId === "max") return preprocessMaxRequest(rawBody, launch, subagentRequest);
@@ -4938,13 +5112,13 @@ function preprocessFastRequest(rawBody, launch, subagentRequest = false) {
4938
5112
  retiredAlias: originalModel
4939
5113
  };
4940
5114
  const alias = resolveModelAlias(originalModel);
4941
- if (alias && (launch?.profileId !== "fast" || isMaxModelAlias(originalModel))) return {
5115
+ if (alias && (launch?.profileId !== "fast" && !cheapFamily(launch?.profileId) || isMaxModelAlias(originalModel))) return {
4942
5116
  body: rawBody,
4943
5117
  originalModel,
4944
5118
  modified: false,
4945
5119
  rejectedAlias: originalModel
4946
5120
  };
4947
- if (launch?.profileId !== "fast") return {
5121
+ if (launch?.profileId !== "fast" && !cheapFamily(launch?.profileId)) return {
4948
5122
  body: rawBody,
4949
5123
  originalModel,
4950
5124
  modified: false
@@ -5418,15 +5592,19 @@ async function handleCompletion(c) {
5418
5592
  const advisorRequested = isAdvisorRequested(incomingBeta);
5419
5593
  const fastProfileRequest = identity.launch?.profileId === "fast";
5420
5594
  const maxProfileRequest = identity.launch?.profileId === "max";
5595
+ const cheapProfileRequest = identity.launch?.profileId === "cheap" || identity.launch?.profileId === "cheap1m";
5421
5596
  const subagentRequest = Boolean(c.req.header("x-claude-code-agent-id"));
5422
5597
  const fastSubagentRequest = fastProfileRequest && subagentRequest;
5423
5598
  const maxSubagentRequest = maxProfileRequest && subagentRequest;
5599
+ const cheapSubagentRequest = cheapProfileRequest && subagentRequest;
5424
5600
  const fastLeadAdvisor = fastProfileRequest && !fastSubagentRequest;
5425
5601
  const maxLeadAdvisor = maxProfileRequest && !maxSubagentRequest;
5426
- const advisorEnabled = advisorRequested && !fastSubagentRequest && !maxSubagentRequest;
5602
+ const cheapLeadAdvisor = cheapProfileRequest && !cheapSubagentRequest;
5603
+ const advisorEnabled = advisorRequested && !fastSubagentRequest && !maxSubagentRequest && !cheapSubagentRequest;
5427
5604
  const fastAdvisorEnabled = fastLeadAdvisor && advisorRequested && hasNonEmptyTools(rawBody);
5428
5605
  const maxAdvisorEnabled = maxLeadAdvisor && advisorRequested && hasNonEmptyTools(rawBody);
5429
- const advisorBehaviorEnabled = fastLeadAdvisor ? fastAdvisorEnabled : maxLeadAdvisor ? maxAdvisorEnabled : advisorEnabled;
5606
+ const cheapAdvisorEnabled = cheapLeadAdvisor && advisorRequested && hasNonEmptyTools(rawBody);
5607
+ const advisorBehaviorEnabled = fastLeadAdvisor ? fastAdvisorEnabled : cheapLeadAdvisor ? cheapAdvisorEnabled : maxLeadAdvisor ? maxAdvisorEnabled : advisorEnabled;
5430
5608
  let fastAdvisorChoice;
5431
5609
  let maxAdvisorChoice;
5432
5610
  if (maxAdvisorEnabled) {
@@ -5465,9 +5643,33 @@ async function handleCompletion(c) {
5465
5643
  }, 503);
5466
5644
  }
5467
5645
  }
5646
+ if (cheapAdvisorEnabled) {
5647
+ const mismatch = fastAdvisorMetadataMismatch(rawBody);
5648
+ const relaunchProfile = identity.launch?.profileId === "cheap1m" ? "cheap1m" : "cheap";
5649
+ if (mismatch) return c.json({
5650
+ type: "error",
5651
+ error: {
5652
+ type: "invalid_request_error",
5653
+ message: `Cheap Advisor model mismatch: ${mismatch}. Run \`/advisor ${CHEAP_PROFILE_ADVISOR_CLIENT_MODEL}\` to restore the fixed cheap profile, or relaunch with \`github-router claude -m ${relaunchProfile}\`.`
5654
+ }
5655
+ }, 400, { "x-should-retry": "false" });
5656
+ try {
5657
+ fastAdvisorChoice = resolveAdvisorModel(void 0, true);
5658
+ } catch (error) {
5659
+ return c.json({
5660
+ type: "error",
5661
+ error: {
5662
+ type: "api_error",
5663
+ message: error instanceof Error ? error.message : String(error)
5664
+ }
5665
+ }, 503);
5666
+ }
5667
+ }
5468
5668
  const fastPreprocess = preprocessFastRequest(rawBody, identity.launch, subagentRequest);
5469
5669
  if (fastPreprocess.retiredAlias || fastPreprocess.rejectedAlias || fastPreprocess.rejectedModel) {
5470
- const message = fastPreprocess.retiredAlias ? `Router-owned model alias ${JSON.stringify(fastPreprocess.retiredAlias)} belongs to a retired Fast role and is no longer valid. Relaunch or select a current Fast role.` : identity.launch?.profileId === "max" ? maxRequestError(fastPreprocess) ?? "Invalid max request" : fastPreprocess.rejectedAlias ? `Router-owned model alias ${JSON.stringify(fastPreprocess.rejectedAlias)} is valid only for an authenticated -m fast launch.` : `Model ${JSON.stringify(fastPreprocess.rejectedModel)} is outside the fixed -m fast model set.`;
5670
+ const profileId = identity.launch?.profileId;
5671
+ const profileLabel = profileId === "cheap" || profileId === "cheap1m" ? "cheap" : "fast";
5672
+ const message = fastPreprocess.retiredAlias ? `Router-owned model alias ${JSON.stringify(fastPreprocess.retiredAlias)} belongs to a retired Fast role and is no longer valid. Relaunch or select a current Fast role.` : profileId === "max" ? maxRequestError(fastPreprocess) ?? "Invalid max request" : fastPreprocess.rejectedAlias ? `Router-owned model alias ${JSON.stringify(fastPreprocess.rejectedAlias)} is valid only for an authenticated -m ${profileLabel} launch.` : `Model ${JSON.stringify(fastPreprocess.rejectedModel)} is outside the fixed -m ${profileLabel} model set.`;
5471
5673
  return c.json({
5472
5674
  type: "error",
5473
5675
  error: {
@@ -5513,7 +5715,7 @@ async function handleCompletion(c) {
5513
5715
  parsedBase = JSON.parse(promptWindowBody);
5514
5716
  } catch {}
5515
5717
  const wantsStream = parsedBase?.stream === true;
5516
- if ((fastAdvisorEnabled || maxAdvisorEnabled) && wantsStream) {
5718
+ if ((fastAdvisorEnabled || cheapAdvisorEnabled || maxAdvisorEnabled) && wantsStream) {
5517
5719
  const initialConversation = Array.isArray(parsedBase.messages) ? parsedBase.messages : [];
5518
5720
  const parsedInitial = parseAnthropicRequest(parsedBase, modelId, selectedModel);
5519
5721
  const translatedAdvisorAborter = new AbortController();
@@ -5536,6 +5738,11 @@ async function handleCompletion(c) {
5536
5738
  effort: maxAdvisorChoice.effort,
5537
5739
  escalated: false,
5538
5740
  fastProfile: false
5741
+ } : cheapAdvisorEnabled ? {
5742
+ model: fastAdvisorChoice.model,
5743
+ effort: resolveAdvisorEffort(rawBody, fastAdvisorChoice.model, true),
5744
+ escalated: fastAdvisorChoice.escalated,
5745
+ fastProfile: true
5539
5746
  } : {
5540
5747
  model: fastAdvisorChoice.model,
5541
5748
  effort: resolveAdvisorEffort(rawBody, fastAdvisorChoice.model, true),
@@ -5551,6 +5758,7 @@ async function handleCompletion(c) {
5551
5758
  advisorEscalated: advisorChoice.escalated,
5552
5759
  advisorFastProfile: advisorChoice.fastProfile,
5553
5760
  advisorMaxProfile: maxAdvisorEnabled,
5761
+ advisorCheapProfile: cheapAdvisorEnabled,
5554
5762
  advisorEffort: advisorChoice.effort,
5555
5763
  externalAborter: translatedAdvisorAborter,
5556
5764
  continueTurn: makeShimContinueTurn(endpoint, {
@@ -5673,9 +5881,10 @@ async function handleCompletion(c) {
5673
5881
  requestHeaders,
5674
5882
  advisorModel: advisorChoice.model,
5675
5883
  advisorEscalated: advisorChoice.escalated,
5676
- advisorFastProfile: fastLeadAdvisor,
5884
+ advisorFastProfile: fastLeadAdvisor || cheapLeadAdvisor,
5677
5885
  advisorMaxProfile: maxAdvisorEnabled,
5678
- advisorEffort: maxAdvisorChoice ? maxAdvisorChoice.effort : resolveAdvisorEffort(rawBody, advisorChoice.model, fastLeadAdvisor),
5886
+ advisorCheapProfile: cheapLeadAdvisor,
5887
+ advisorEffort: maxAdvisorChoice ? maxAdvisorChoice.effort : resolveAdvisorEffort(rawBody, advisorChoice.model, fastLeadAdvisor || cheapLeadAdvisor),
5679
5888
  externalAborter: advisorAborter
5680
5889
  }), {
5681
5890
  status: response.status,
@@ -7066,8 +7275,9 @@ function getClaudeCodeEnvVars(serverUrl, model, launchProfileId = "standard", pi
7066
7275
  if (process.env.MCP_TOOL_TIMEOUT === void 0) vars.MCP_TOOL_TIMEOUT = mcpToolTimeoutMs;
7067
7276
  const isFastProfile = launchProfileId === "fast";
7068
7277
  const isMaxProfile = launchProfileId === "max";
7069
- const smallFastModel = isMaxProfile ? MAX_LUNA_HIGH_ALIAS_ID : isFastProfile ? LUNA_HAIKU_ALIAS_ID : isBudgetClaudeLead(model) && (state.models?.data?.some((m) => m.id === "claude-haiku-4.5") ?? false) ? BUDGET_SMALL_FAST_SLUG : "claude-sonnet-5";
7070
- if (process.env.ANTHROPIC_SMALL_FAST_MODEL === void 0) vars.ANTHROPIC_SMALL_FAST_MODEL = isFastProfile || isMaxProfile ? oneMSuffixForAlias(smallFastModel) : smallFastModel;
7278
+ const isCheapProfile = launchProfileId === "cheap" || launchProfileId === "cheap1m";
7279
+ const smallFastModel = isMaxProfile ? MAX_LUNA_HIGH_ALIAS_ID : isFastProfile ? LUNA_HAIKU_ALIAS_ID : isCheapProfile ? LUNA_HAIKU_ALIAS_ID : isBudgetClaudeLead(model) && (state.models?.data?.some((m) => m.id === "claude-haiku-4.5") ?? false) ? BUDGET_SMALL_FAST_SLUG : "claude-sonnet-5";
7280
+ if (process.env.ANTHROPIC_SMALL_FAST_MODEL === void 0) vars.ANTHROPIC_SMALL_FAST_MODEL = (isFastProfile || isMaxProfile) && !isCheapProfile ? oneMSuffixForAlias(smallFastModel) : smallFastModel;
7071
7281
  const seedTierRow = (modelKey, nameKey, bareSlug) => {
7072
7282
  if (process.env[modelKey] !== void 0) return;
7073
7283
  vars[modelKey] = withOneMSuffixForLead(bareSlug);
@@ -7078,6 +7288,11 @@ function getClaudeCodeEnvVars(serverUrl, model, launchProfileId = "standard", pi
7078
7288
  vars[modelKey] = oneMSuffixForAlias(aliasId);
7079
7289
  if (process.env[nameKey] === void 0) vars[nameKey] = displayName;
7080
7290
  };
7291
+ const seedCheapAliasTierRow = (modelKey, nameKey, aliasId, displayName) => {
7292
+ if (process.env[modelKey] !== void 0) return;
7293
+ vars[modelKey] = aliasId;
7294
+ if (process.env[nameKey] === void 0) vars[nameKey] = displayName;
7295
+ };
7081
7296
  if (isMaxProfile) {
7082
7297
  const seedMaxRow = (modelKey, nameKey, id) => {
7083
7298
  if (process.env[modelKey] !== void 0) return;
@@ -7091,6 +7306,17 @@ function getClaudeCodeEnvVars(serverUrl, model, launchProfileId = "standard", pi
7091
7306
  vars.ANTHROPIC_CUSTOM_MODEL_OPTION = oneMSuffixForMaxModel(MAX_PROFILE_MODELS.sol);
7092
7307
  if (process.env.ANTHROPIC_CUSTOM_MODEL_OPTION_NAME === void 0) vars.ANTHROPIC_CUSTOM_MODEL_OPTION_NAME = "GPT-5.6 Sol";
7093
7308
  }
7309
+ } else if (isCheapProfile) {
7310
+ seedCheapAliasTierRow("ANTHROPIC_DEFAULT_SONNET_MODEL", "ANTHROPIC_DEFAULT_SONNET_MODEL_NAME", LUNA_SONNET_ALIAS_ID, "GPT-5.6 Luna (xhigh)");
7311
+ seedCheapAliasTierRow("ANTHROPIC_DEFAULT_HAIKU_MODEL", "ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME", LUNA_HAIKU_ALIAS_ID, "GPT-5.6 Luna (high)");
7312
+ const cheapAliasCapabilities = "effort,xhigh_effort,max_effort,thinking,adaptive_thinking,interleaved_thinking";
7313
+ if (process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES === void 0) vars.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES = cheapAliasCapabilities;
7314
+ if (process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES === void 0) vars.ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES = cheapAliasCapabilities;
7315
+ if (process.env.ANTHROPIC_CUSTOM_MODEL_OPTION === void 0) {
7316
+ vars.ANTHROPIC_CUSTOM_MODEL_OPTION = LUNA_DRIVER_ALIAS_ID;
7317
+ if (process.env.ANTHROPIC_CUSTOM_MODEL_OPTION_NAME === void 0) vars.ANTHROPIC_CUSTOM_MODEL_OPTION_NAME = "GPT-5.6 Luna (max)";
7318
+ if (process.env.ANTHROPIC_CUSTOM_MODEL_OPTION_SUPPORTED_CAPABILITIES === void 0) vars.ANTHROPIC_CUSTOM_MODEL_OPTION_SUPPORTED_CAPABILITIES = cheapAliasCapabilities;
7319
+ }
7094
7320
  } else if (isFastProfile) {
7095
7321
  seedFastAliasTierRow("ANTHROPIC_DEFAULT_SONNET_MODEL", "ANTHROPIC_DEFAULT_SONNET_MODEL_NAME", LUNA_SONNET_ALIAS_ID, "GPT-5.6 Luna (xhigh)");
7096
7322
  seedFastAliasTierRow("ANTHROPIC_DEFAULT_HAIKU_MODEL", "ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME", LUNA_HAIKU_ALIAS_ID, "GPT-5.6 Luna (high)");
@@ -7197,6 +7423,6 @@ function getCodexEnvVars(serverUrl) {
7197
7423
  return vars;
7198
7424
  }
7199
7425
  //#endregion
7200
- export { validateMaxProfileLaunch as _, sharedServerArgs as a, updateClaude as b, stopKeepAwake as c, enableFileLogging as d, LUNA_SCOUT_ALIAS_ID as f, validateFastProfilePrerequisites as g, resolveLaunchProfile as h, setupAndServe as i, injectModelPickerSettingsFile as l, profileDescriptor as m, getCodexEnvVars as n, LAUNCH_SECRET_HEADER as o, formatFastPrerequisiteFailure as p, parseSharedArgs as r, startKeepAwake as s, getClaudeCodeEnvVars as t, listModelsForEndpoint as u, runSelfUpdate as v, checkClaudeVersion as y };
7426
+ export { checkClaudeVersion as C, runSelfUpdate as S, resolveLaunchProfile as _, sharedServerArgs as a, validateFastProfilePrerequisites as b, stopKeepAwake as c, enableFileLogging as d, LUNA_SCOUT_ALIAS_ID as f, profileDescriptor as g, formatFastPrerequisiteFailure as h, setupAndServe as i, injectModelPickerSettingsFile as l, formatCheapPrerequisiteFailure as m, getCodexEnvVars as n, LAUNCH_SECRET_HEADER as o, formatCheap1mPrerequisiteFailure as p, parseSharedArgs as r, startKeepAwake as s, getClaudeCodeEnvVars as t, listModelsForEndpoint as u, validateCheap1mProfilePrerequisites as v, updateClaude as w, validateMaxProfileLaunch as x, validateCheapProfilePrerequisites as y };
7201
7427
 
7202
- //# sourceMappingURL=server-setup-OTy-qHfv.js.map
7428
+ //# sourceMappingURL=server-setup-DX27fdcf.js.map