@oh-my-pi/pi-catalog 18.1.12 → 18.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.1.14] - 2026-09-07
6
+
7
+ ### Fixed
8
+
9
+ - Bills Astra API requests above 272K input at the documented 2x input / 1.5x output long-context tier; the Codex subscription route stays exempt with free cache writes ([#11157](https://github.com/can1357/oh-my-pi/pull/11157) by [@H4vC](https://github.com/H4vC)).
10
+ - Fixed Astra's extended window over-advertising input by 128K; it now uses the documented 922K input cap inside the 1.05M total context ([#11157](https://github.com/can1357/oh-my-pi/pull/11157) by [@H4vC](https://github.com/H4vC)).
11
+ - Fixed explicit Codex context-window overrides widening past the server-honored maximum; they now clamp to the documented ceiling like upstream Codex ([#11157](https://github.com/can1357/oh-my-pi/pull/11157) by [@H4vC](https://github.com/H4vC)).
12
+ - Fixed Codex Astra using its larger window without opt-in; its default is 272K and Extended Context enables at least the documented 1.05M window ([#11126](https://github.com/can1357/oh-my-pi/pull/11126) by [@H4vC](https://github.com/H4vC)).
13
+ - Fixed GitHub Copilot enterprise-only model ids inheriting another provider's wire routing (e.g. `gpt-5.6-sol-fast` pinning every request to the `-none` sibling id regardless of thinking level) ([#11128](https://github.com/can1357/oh-my-pi/pull/11128) by [@H4vC](https://github.com/H4vC)).
14
+
15
+ ## [18.1.13] - 2026-09-07
16
+
17
+ ### Fixed
18
+
19
+ - Fixed GPT-6 Astra compacting early at a 272K-token window with its full window gated behind `/extended-context`: it now defaults to the documented 1.05M-token window.
20
+
5
21
  ## [18.1.12] - 2026-09-06
6
22
 
7
23
  ### Added
@@ -1,7 +1,32 @@
1
1
  import type { Model } from "../types.js";
2
2
  /**
3
- * Maximum prompt window for extended context. Live discovery takes precedence
4
- * over rule-owned fallbacks for older bundled or cached model metadata. Resolve
5
- * at catalog composition time so frozen bundled rows need no runtime mutation.
3
+ * Extended-context capacity. Curated maxima correct stale lower discovery
4
+ * values; a higher live maximum still wins. The registry applies this capacity
5
+ * only when extended context is enabled, before explicit user overrides.
6
6
  */
7
7
  export declare function resolveMaxContextWindow(model: Model): number | undefined;
8
+ /**
9
+ * Override ceiling for Codex models. Upstream clamps `model_context_window`
10
+ * to `min(override, max_context_window)` (`with_config_overrides` in
11
+ * `models-manager/src/model_info.rs`); the ceiling here is stale-aware — the
12
+ * curated maximum corrects a lower server value (Astra reports a stale 872K
13
+ * maximum; OpenAI documents at most 922K input) while a higher live maximum
14
+ * still wins. No curated or live maximum means no ceiling: overrides pass
15
+ * through, matching upstream's unclamped branch.
16
+ */
17
+ export declare function codexOverrideCeiling(model: Model): number | undefined;
18
+ /**
19
+ * Whether explicit context-window overrides for this model clamp to the
20
+ * server-honored ceiling. KDL-owned (`clamp-context-override`): branching on
21
+ * it here keeps provider deployment contracts out of TypeScript.
22
+ */
23
+ export declare function clampsContextOverride(model: Model): boolean;
24
+ /**
25
+ * Clamp a requested Codex context window to the override ceiling, mirroring
26
+ * upstream. `model` is the pre-override model: the ceiling never shrinks the
27
+ * request below the window that already works, so a stale-low live maximum
28
+ * (e.g. 128K base with a 64K advertised maximum) cannot punish an explicit
29
+ * override. Returns the request unchanged when no ceiling applies or it
30
+ * already fits.
31
+ */
32
+ export declare function clampCodexContextWindow(model: Model, requested: number): number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-catalog",
4
- "version": "18.1.12",
4
+ "version": "18.1.14",
5
5
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Stencil Labs, Inc.",
@@ -35,12 +35,12 @@
35
35
  "gen:proto": "bun scripts/generate-protocols.ts"
36
36
  },
37
37
  "dependencies": {
38
- "@oh-my-pi/omptype": "18.1.12",
39
- "@oh-my-pi/pi-utils": "18.1.12"
38
+ "@oh-my-pi/omptype": "18.1.14",
39
+ "@oh-my-pi/pi-utils": "18.1.14"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@bgotink/kdl": "0.4.0",
43
- "@oh-my-pi/pi-ai": "18.1.12",
43
+ "@oh-my-pi/pi-ai": "18.1.14",
44
44
  "@types/bun": "^1.3.14"
45
45
  },
46
46
  "engines": {
@@ -267,6 +267,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
267
267
  shape: "scalar",
268
268
  values: ["freeform", "function"],
269
269
  },
270
+ "clamp-context-override": { key: "clampContextOverride", set: "catalog", shape: "scalar" },
270
271
  "context-promotion-target": { key: "contextPromotionTarget", set: "catalog", shape: "scalar" },
271
272
  "context-window-floor": { key: "contextWindowFloor", set: "catalog", shape: "scalar" },
272
273
  "cost-patch": { key: "costPatch", set: "catalog", shape: "object" },
@@ -3,29 +3,72 @@ import type { Model } from "../types";
3
3
  import { resolveModelPolicy } from "./resolve";
4
4
 
5
5
  /**
6
- * Rule-owned fallback maxima by `provider/id/api`. The rule table is static
7
- * per process (compiled into rules.json), so one resolution per model key is
8
- * enough — composition calls this per model on every rebuild while extended
9
- * context is enabled, and the full policy resolve (identity classification
10
- * plus cascade walk) is wasted work per call.
6
+ * Rule-owned maxima by provider/id/api. Resolve once per process rather than
7
+ * walking the static policy cascade on every catalog rebuild. Null caches the
8
+ * absence of a curated maximum; undefined means the key has not been resolved.
11
9
  */
12
- const ruleFallbackCache = new Map<string, number | undefined>();
10
+ const ruleMaximumCache = new Map<string, number | null>();
13
11
 
14
12
  /**
15
- * Maximum prompt window for extended context. Live discovery takes precedence
16
- * over rule-owned fallbacks for older bundled or cached model metadata. Resolve
17
- * at catalog composition time so frozen bundled rows need no runtime mutation.
13
+ * Extended-context capacity. Curated maxima correct stale lower discovery
14
+ * values; a higher live maximum still wins. The registry applies this capacity
15
+ * only when extended context is enabled, before explicit user overrides.
18
16
  */
19
17
  export function resolveMaxContextWindow(model: Model): number | undefined {
18
+ const key = `${model.provider} ${model.id} ${model.api}`;
19
+ let curated = ruleMaximumCache.get(key);
20
+ if (curated === undefined) {
21
+ const maximum = resolveModelPolicy(toModelSpec(model)).catalog.maxContextWindow;
22
+ curated = typeof maximum === "number" && Number.isFinite(maximum) && maximum > 0 ? maximum : null;
23
+ ruleMaximumCache.set(key, curated);
24
+ }
25
+
20
26
  const maximum = model.maxContextWindow;
21
27
  if (typeof maximum === "number" && Number.isFinite(maximum) && maximum > 0) {
22
- return maximum;
28
+ return Math.max(maximum, curated ?? 0);
23
29
  }
30
+ return curated ?? undefined;
31
+ }
24
32
 
25
- const key = `${model.provider} ${model.id} ${model.api}`;
26
- if (ruleFallbackCache.has(key)) return ruleFallbackCache.get(key);
27
- const fallback = resolveModelPolicy(toModelSpec(model)).catalog.maxContextWindow;
28
- const resolved = typeof fallback === "number" && Number.isFinite(fallback) && fallback > 0 ? fallback : undefined;
29
- ruleFallbackCache.set(key, resolved);
30
- return resolved;
33
+ /**
34
+ * Override ceiling for Codex models. Upstream clamps `model_context_window`
35
+ * to `min(override, max_context_window)` (`with_config_overrides` in
36
+ * `models-manager/src/model_info.rs`); the ceiling here is stale-aware — the
37
+ * curated maximum corrects a lower server value (Astra reports a stale 872K
38
+ * maximum; OpenAI documents at most 922K input) while a higher live maximum
39
+ * still wins. No curated or live maximum means no ceiling: overrides pass
40
+ * through, matching upstream's unclamped branch.
41
+ */
42
+ export function codexOverrideCeiling(model: Model): number | undefined {
43
+ return resolveMaxContextWindow(model);
44
+ }
45
+
46
+ /**
47
+ * Whether explicit context-window overrides for this model clamp to the
48
+ * server-honored ceiling. KDL-owned (`clamp-context-override`): branching on
49
+ * it here keeps provider deployment contracts out of TypeScript.
50
+ */
51
+ export function clampsContextOverride(model: Model): boolean {
52
+ return resolveModelPolicy(toModelSpec(model)).catalog.clampContextOverride === true;
53
+ }
54
+
55
+ /**
56
+ * Clamp a requested Codex context window to the override ceiling, mirroring
57
+ * upstream. `model` is the pre-override model: the ceiling never shrinks the
58
+ * request below the window that already works, so a stale-low live maximum
59
+ * (e.g. 128K base with a 64K advertised maximum) cannot punish an explicit
60
+ * override. Returns the request unchanged when no ceiling applies or it
61
+ * already fits.
62
+ */
63
+ export function clampCodexContextWindow(model: Model, requested: number): number {
64
+ if (!Number.isFinite(requested) || requested <= 0) {
65
+ return requested;
66
+ }
67
+ const ceiling = codexOverrideCeiling(model);
68
+ if (ceiling === undefined || requested <= ceiling) {
69
+ return requested;
70
+ }
71
+ const current = model.contextWindow;
72
+ const floor = typeof current === "number" && Number.isFinite(current) && current > 0 ? current : 0;
73
+ return Math.min(requested, Math.max(ceiling, floor));
31
74
  }
@@ -9,6 +9,11 @@ provider "openai-codex" {
9
9
  // Harmony-protocol leak detection/mitigation applies to every Codex model,
10
10
  // current and future; replaces the provider check in harmony-leak.ts.
11
11
  harmony-leak-mitigation #true
12
+ // Every Codex SKU clamps explicit context-window overrides to the
13
+ // server-honored ceiling (`min(override, max)`, mirroring upstream
14
+ // `with_config_overrides`); models without a curated or live maximum
15
+ // pass through. Replaces the provider check in model-registry.ts.
16
+ clamp-context-override #true
12
17
  // Subscription (Codex) discovery reports no pricing; the curated Daybreak
13
18
  // aliases carry the standard GPT-5.6 Sol/Cyber API list price so cost
14
19
  // display reads as API-equivalent spend. The `-wm` worker sibling bills
@@ -29,12 +34,15 @@ provider "openai-codex" {
29
34
  cache-write 15.625
30
35
  }
31
36
  }
32
- // Codex discovery currently reports Astra's legacy 272K window and no
33
- // pricing. Attribute subscription usage at the documented credit-equivalent
34
- // rates, with free cache writes and without the API's >272K multiplier.
35
- // The wire's 872K `max_context_window` (client 0.153.1, 2026-09-04) is the
36
- // `/extended-context` maximum (see the `max-context-window` fallback
37
- // below); the default stays at 272K so compaction fires first.
37
+ // Codex reports a 272K default and a stale 872K maximum for Astra. Keep
38
+ // the default explicit so cached 1.05M rows from #11089 cannot bypass the
39
+ // opt-in; the curated maximum is applied only with extended context on.
40
+ // OpenAI documents 1.05M total context with at most 922K input and 128K
41
+ // output, so the input ceiling is 922K — not the total. A higher live
42
+ // maximum still wins as the ceiling.
43
+ // Subscription credit-equivalent pricing: no per-token billing, free cache
44
+ // writes, exempt from the API long-context multiplier. The first-party API
45
+ // route bills the documented >272K tier instead — see providers/openai.kdl.
38
46
  models "gpt-6-astra" "gpt-6-astra-wm" {
39
47
  cost-patch {
40
48
  input 10.0
@@ -46,6 +54,10 @@ provider "openai-codex" {
46
54
  flex 0.5
47
55
  priority 2.5
48
56
  }
57
+ limits-patch {
58
+ context-window 272000
59
+ }
60
+ max-context-window 922000
49
61
  }
50
62
  class "openai" {
51
63
  revision ">=5.3 <5.7" {
@@ -136,13 +148,4 @@ provider "openai-codex" {
136
148
  models "gpt-5.6-luna" "gpt-5.6-sol" "gpt-5.6-terra" {
137
149
  context-window-floor 1000000
138
150
  }
139
- // Residue: the Codex registry advertises Astra's 272000 default prompt
140
- // window with max_context_window=872000 (client 0.153.1, 2026-09-04).
141
- // Older bundled and cached catalogs omit the maximum; live discovery
142
- // takes precedence. The fallback stays at the deployment-advertised
143
- // maximum so offline extended context never advertises a window the
144
- // deployment rejects.
145
- models "gpt-6-astra" "gpt-6-astra-wm" {
146
- max-context-window 872000
147
- }
148
151
  }
@@ -72,6 +72,19 @@ provider "openai" {
72
72
  cache-write 5.0
73
73
  }
74
74
  }
75
+ // Astra API route bills the documented long-context tier above 272K input:
76
+ // 2x input and cache rates, 1.5x output for the full request; cache writes
77
+ // stay 1.25x the long input rate (25.0). The Codex subscription route stays
78
+ // exempt (credit-equivalent, free cache writes) — see openai-codex.kdl.
79
+ models "gpt-6-astra*" {
80
+ long-context-cost {
81
+ input-threshold 272000
82
+ input 20.0
83
+ output 75.0
84
+ cache-read 2.0
85
+ cache-write 25.0
86
+ }
87
+ }
75
88
  // residue: the bare Daybreak rolling aliases pin the documented 5.6-gen
76
89
  // wire restrictions without carrying the gpt- prefix identity.
77
90
  models "daybreak-blue-latest" "daybreak-red-latest" {
@@ -10544,7 +10544,7 @@
10544
10544
  }
10545
10545
  },
10546
10546
  {
10547
- "source": "providers/openai-codex.kdl:16",
10547
+ "source": "providers/openai-codex.kdl:21",
10548
10548
  "providers": [
10549
10549
  "openai-codex"
10550
10550
  ],
@@ -10568,7 +10568,7 @@
10568
10568
  }
10569
10569
  },
10570
10570
  {
10571
- "source": "providers/openai-codex.kdl:24",
10571
+ "source": "providers/openai-codex.kdl:29",
10572
10572
  "providers": [
10573
10573
  "openai-codex"
10574
10574
  ],
@@ -10592,7 +10592,7 @@
10592
10592
  }
10593
10593
  },
10594
10594
  {
10595
- "source": "providers/openai-codex.kdl:38",
10595
+ "source": "providers/openai-codex.kdl:46",
10596
10596
  "providers": [
10597
10597
  "openai-codex"
10598
10598
  ],
@@ -10616,11 +10616,15 @@
10616
10616
  "serviceTierCost": {
10617
10617
  "flex": 0.5,
10618
10618
  "priority": 2.5
10619
- }
10619
+ },
10620
+ "limitsPatch": {
10621
+ "contextWindow": 272000
10622
+ },
10623
+ "maxContextWindow": 922000
10620
10624
  }
10621
10625
  },
10622
10626
  {
10623
- "source": "providers/openai-codex.kdl:51",
10627
+ "source": "providers/openai-codex.kdl:63",
10624
10628
  "class": "openai",
10625
10629
  "providers": [
10626
10630
  "openai-codex"
@@ -10640,7 +10644,7 @@
10640
10644
  }
10641
10645
  },
10642
10646
  {
10643
- "source": "providers/openai-codex.kdl:56",
10647
+ "source": "providers/openai-codex.kdl:68",
10644
10648
  "class": "openai",
10645
10649
  "providers": [
10646
10650
  "openai-codex"
@@ -10656,7 +10660,7 @@
10656
10660
  }
10657
10661
  },
10658
10662
  {
10659
- "source": "providers/openai-codex.kdl:59",
10663
+ "source": "providers/openai-codex.kdl:71",
10660
10664
  "class": "openai",
10661
10665
  "providers": [
10662
10666
  "openai-codex"
@@ -10672,7 +10676,7 @@
10672
10676
  }
10673
10677
  },
10674
10678
  {
10675
- "source": "providers/openai-codex.kdl:64",
10679
+ "source": "providers/openai-codex.kdl:76",
10676
10680
  "class": "openai",
10677
10681
  "providers": [
10678
10682
  "openai-codex"
@@ -10691,7 +10695,7 @@
10691
10695
  }
10692
10696
  },
10693
10697
  {
10694
- "source": "providers/openai-codex.kdl:76",
10698
+ "source": "providers/openai-codex.kdl:88",
10695
10699
  "class": "openai",
10696
10700
  "providers": [
10697
10701
  "openai-codex"
@@ -10717,7 +10721,7 @@
10717
10721
  }
10718
10722
  },
10719
10723
  {
10720
- "source": "providers/openai-codex.kdl:82",
10724
+ "source": "providers/openai-codex.kdl:94",
10721
10725
  "class": "openai",
10722
10726
  "providers": [
10723
10727
  "openai-codex"
@@ -10743,7 +10747,7 @@
10743
10747
  }
10744
10748
  },
10745
10749
  {
10746
- "source": "providers/openai-codex.kdl:74",
10750
+ "source": "providers/openai-codex.kdl:86",
10747
10751
  "class": "openai",
10748
10752
  "providers": [
10749
10753
  "openai-codex"
@@ -10760,7 +10764,7 @@
10760
10764
  }
10761
10765
  },
10762
10766
  {
10763
- "source": "providers/openai-codex.kdl:92",
10767
+ "source": "providers/openai-codex.kdl:104",
10764
10768
  "class": "openai",
10765
10769
  "providers": [
10766
10770
  "openai-codex"
@@ -10780,7 +10784,7 @@
10780
10784
  }
10781
10785
  },
10782
10786
  {
10783
- "source": "providers/openai-codex.kdl:98",
10787
+ "source": "providers/openai-codex.kdl:110",
10784
10788
  "class": "unknown",
10785
10789
  "providers": [
10786
10790
  "openai-codex"
@@ -10796,7 +10800,7 @@
10796
10800
  }
10797
10801
  },
10798
10802
  {
10799
- "source": "providers/openai-codex.kdl:101",
10803
+ "source": "providers/openai-codex.kdl:113",
10800
10804
  "class": "unknown",
10801
10805
  "providers": [
10802
10806
  "openai-codex"
@@ -10812,7 +10816,7 @@
10812
10816
  }
10813
10817
  },
10814
10818
  {
10815
- "source": "providers/openai-codex.kdl:107",
10819
+ "source": "providers/openai-codex.kdl:119",
10816
10820
  "providers": [
10817
10821
  "openai-codex"
10818
10822
  ],
@@ -10833,7 +10837,7 @@
10833
10837
  }
10834
10838
  },
10835
10839
  {
10836
- "source": "providers/openai-codex.kdl:116",
10840
+ "source": "providers/openai-codex.kdl:128",
10837
10841
  "providers": [
10838
10842
  "openai-codex"
10839
10843
  ],
@@ -10858,7 +10862,7 @@
10858
10862
  }
10859
10863
  },
10860
10864
  {
10861
- "source": "providers/openai-codex.kdl:125",
10865
+ "source": "providers/openai-codex.kdl:137",
10862
10866
  "providers": [
10863
10867
  "openai-codex"
10864
10868
  ],
@@ -10879,7 +10883,7 @@
10879
10883
  }
10880
10884
  },
10881
10885
  {
10882
- "source": "providers/openai-codex.kdl:136",
10886
+ "source": "providers/openai-codex.kdl:148",
10883
10887
  "providers": [
10884
10888
  "openai-codex"
10885
10889
  ],
@@ -10901,25 +10905,6 @@
10901
10905
  "contextWindowFloor": 1000000
10902
10906
  }
10903
10907
  },
10904
- {
10905
- "source": "providers/openai-codex.kdl:145",
10906
- "providers": [
10907
- "openai-codex"
10908
- ],
10909
- "models": [
10910
- {
10911
- "kind": "exact",
10912
- "value": "gpt-6-astra"
10913
- },
10914
- {
10915
- "kind": "exact",
10916
- "value": "gpt-6-astra-wm"
10917
- }
10918
- ],
10919
- "catalog": {
10920
- "maxContextWindow": 872000
10921
- }
10922
- },
10923
10908
  {
10924
10909
  "source": "providers/openai-codex.kdl:3",
10925
10910
  "providers": [
@@ -10932,7 +10917,8 @@
10932
10917
  "serviceTierCost": {
10933
10918
  "flex": 0.5,
10934
10919
  "priority": 2
10935
- }
10920
+ },
10921
+ "clampContextOverride": true
10936
10922
  }
10937
10923
  },
10938
10924
  {
@@ -11175,7 +11161,28 @@
11175
11161
  }
11176
11162
  },
11177
11163
  {
11178
- "source": "providers/openai.kdl:77",
11164
+ "source": "providers/openai.kdl:79",
11165
+ "providers": [
11166
+ "openai"
11167
+ ],
11168
+ "models": [
11169
+ {
11170
+ "kind": "glob",
11171
+ "value": "gpt-6-astra*"
11172
+ }
11173
+ ],
11174
+ "catalog": {
11175
+ "longContext": {
11176
+ "inputThreshold": 272000,
11177
+ "input": 20,
11178
+ "output": 75,
11179
+ "cacheRead": 2,
11180
+ "cacheWrite": 25
11181
+ }
11182
+ }
11183
+ },
11184
+ {
11185
+ "source": "providers/openai.kdl:90",
11179
11186
  "providers": [
11180
11187
  "openai"
11181
11188
  ],
@@ -92,9 +92,15 @@ export function resolveModelCacheProviderId(providerId: string, options: ModelCa
92
92
  // switching `COPILOT_GITHUB_TOKEN` to a different account misses the
93
93
  // prior endpoint's cache and re-runs discovery instead of hitting the
94
94
  // stale host and 403ing (PR #8510 review).
95
+ // v2: rows cached before the cross-provider routing strip inherit
96
+ // Cursor collapsed-family wire ids (e.g. enterprise-only
97
+ // `gpt-5.6-sol-fast` pinned to `-none-fast`); use a fresh namespace
98
+ // so they refetch instead of serving the poisoned rows. Listing ids
99
+ // cannot cover this class — any enterprise-only sibling can carry
100
+ // another provider's routing — so version the namespace instead.
95
101
  const baseUrl = options.baseUrl ?? PERSONAL_GITHUB_COPILOT_BASE_URL;
96
102
  const scope = `${options.apiKey ?? ""}\u0000${baseUrl}`;
97
- return `github-copilot:models-v1:${Bun.hash(scope).toString(36)}`;
103
+ return `github-copilot:models-v2:${Bun.hash(scope).toString(36)}`;
98
104
  }
99
105
  case "openrouter":
100
106
  return "openrouter:pseudo-api";
@@ -6380,6 +6380,22 @@ export function githubCopilotModelManagerOptions(config?: GithubCopilotModelMana
6380
6380
  }
6381
6381
  : {}),
6382
6382
  };
6383
+ // Cross-provider fallback references (e.g. a Cursor
6384
+ // collapsed family for an enterprise-only sibling id)
6385
+ // carry provider-specific wire routing that must not
6386
+ // transfer: the off-tier `requestModelId` pin would send
6387
+ // every Copilot request under the `-none` sibling id
6388
+ // regardless of thinking level.
6389
+ if (reference && reference.provider !== "github-copilot") {
6390
+ delete base.requestModelId;
6391
+ if (base.thinking) {
6392
+ // `base` is a shallow copy of the shared global
6393
+ // reference: clone before deleting or the bundled
6394
+ // entry loses its routing process-wide.
6395
+ base.thinking = { ...base.thinking };
6396
+ delete base.thinking.effortRouting;
6397
+ }
6398
+ }
6383
6399
  const defaultCost = copilotTierCost(tokenPrices.defaultTier);
6384
6400
  if (defaultCost) {
6385
6401
  // Cache writes are not reported per tier; retain the bundled provider rate.