@molecule/app-ide-react 1.1.1 → 1.2.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.
@@ -85,6 +85,35 @@ export declare function resolveModeModel(settings: PerModeModelSettings, mode: M
85
85
  * @returns The clamped model id for the mode.
86
86
  */
87
87
  export declare function freeTierModeModelId(models: readonly AppModelDefinition[], mode: ModelMode, fallback: string): string;
88
+ /**
89
+ * The model id that will ACTUALLY serve a conversation mode, for display.
90
+ *
91
+ * Mirrors the server's `selectModelForMode` candidate chain (minus the
92
+ * per-request override, which the UI never has): the project's per-mode model,
93
+ * then the project's SAVED legacy `chatModel`, each skipped when the free-tier
94
+ * clamp would reject it — then the server-sent per-mode default (which already
95
+ * folds in the owner's account-level settings and tier), then the catalog
96
+ * clamp as the last resort.
97
+ *
98
+ * `settings.chatModel` must be the PERSISTED value only — never a UI-seeded
99
+ * default. Seeding the catalog's single free-tier model (the executor) as
100
+ * "current" is exactly the bug this exists to fix: every plan-mode surface
101
+ * then labeled the planner as the executor model while the server planned
102
+ * with its own plan default (observed on prod 2026-08-13 — the UI said
103
+ * "DeepSeek V4 Flash" for a plan turn that DeepSeek V4 Pro served).
104
+ *
105
+ * @param mode - The conversation mode to resolve.
106
+ * @param settings - Persisted per-mode + legacy model settings (saved only).
107
+ * @param serverDefaults - Server-sent per-mode defaults (`GET /ai/models`).
108
+ * @param isFreeTier - Whether the current user is on the free/anon tier.
109
+ * @param models - The available models from the catalog.
110
+ * @param fallback - The free-tier model id to use when no clamp match exists.
111
+ * @returns The model id the mode resolves to.
112
+ */
113
+ export declare function effectiveModeModelId(mode: 'plan' | 'execute', settings: PerModeModelSettings, serverDefaults: {
114
+ plan?: string;
115
+ execute?: string;
116
+ } | undefined, isFreeTier: boolean, models: readonly AppModelDefinition[], fallback: string): string;
88
117
  /**
89
118
  * Why a model is locked for a free-tier user in a given mode — `'paid'` for a
90
119
  * genuinely paid model, `'mode'` for a model the free tier CAN use, just in a
@@ -1 +1 @@
1
- {"version":3,"file":"chat-model-mode-utilities.d.ts","sourceRoot":"","sources":["../../src/components/chat-model-mode-utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,wEAAwE;AACxE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAA;AAEjE,6EAA6E;AAC7E,MAAM,WAAW,oBAAoB;IACnC,yFAAyF;IACzF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAI9F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,GACd,WAAW,GAAG,cAAc,GAAG,aAAa,GAAG,cAAc,CAW/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,oBAAoB,EAC9B,IAAI,EAAE,SAAS,GACd,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,MAAM,GACf,MAAM,CAgBR;AAED;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,CAAA;AAKhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,kBAAkB,GAAG,IAAI,CAe3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,SAAS,GAAG,IAAI,CAKlB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAET"}
1
+ {"version":3,"file":"chat-model-mode-utilities.d.ts","sourceRoot":"","sources":["../../src/components/chat-model-mode-utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,wEAAwE;AACxE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAA;AAEjE,6EAA6E;AAC7E,MAAM,WAAW,oBAAoB;IACnC,yFAAyF;IACzF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAI9F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,GACd,WAAW,GAAG,cAAc,GAAG,aAAa,GAAG,cAAc,CAW/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,oBAAoB,EAC9B,IAAI,EAAE,SAAS,GACd,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,MAAM,GACf,MAAM,CAgBR;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,QAAQ,EAAE,oBAAoB,EAC9B,cAAc,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EAC/D,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,MAAM,CAcR;AAED;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,CAAA;AAKhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,kBAAkB,GAAG,IAAI,CAe3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,SAAS,GAAG,IAAI,CAKlB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAET"}
@@ -113,6 +113,46 @@ export function freeTierModeModelId(models, mode, fallback) {
113
113
  const anyDeepseek = models.find((m) => m.provider === 'deepseek');
114
114
  return anyDeepseek?.id ?? fallback;
115
115
  }
116
+ /**
117
+ * The model id that will ACTUALLY serve a conversation mode, for display.
118
+ *
119
+ * Mirrors the server's `selectModelForMode` candidate chain (minus the
120
+ * per-request override, which the UI never has): the project's per-mode model,
121
+ * then the project's SAVED legacy `chatModel`, each skipped when the free-tier
122
+ * clamp would reject it — then the server-sent per-mode default (which already
123
+ * folds in the owner's account-level settings and tier), then the catalog
124
+ * clamp as the last resort.
125
+ *
126
+ * `settings.chatModel` must be the PERSISTED value only — never a UI-seeded
127
+ * default. Seeding the catalog's single free-tier model (the executor) as
128
+ * "current" is exactly the bug this exists to fix: every plan-mode surface
129
+ * then labeled the planner as the executor model while the server planned
130
+ * with its own plan default (observed on prod 2026-08-13 — the UI said
131
+ * "DeepSeek V4 Flash" for a plan turn that DeepSeek V4 Pro served).
132
+ *
133
+ * @param mode - The conversation mode to resolve.
134
+ * @param settings - Persisted per-mode + legacy model settings (saved only).
135
+ * @param serverDefaults - Server-sent per-mode defaults (`GET /ai/models`).
136
+ * @param isFreeTier - Whether the current user is on the free/anon tier.
137
+ * @param models - The available models from the catalog.
138
+ * @param fallback - The free-tier model id to use when no clamp match exists.
139
+ * @returns The model id the mode resolves to.
140
+ */
141
+ export function effectiveModeModelId(mode, settings, serverDefaults, isFreeTier, models, fallback) {
142
+ const candidates = mode === 'plan'
143
+ ? [settings.planModel, settings.chatModel]
144
+ : [settings.executeModel, settings.chatModel];
145
+ for (const candidate of candidates) {
146
+ if (!candidate)
147
+ continue;
148
+ // Mirror the server: a candidate the free-tier clamp rejects falls
149
+ // through to the next, it does not stick as the label.
150
+ if (freeTierLockReason(candidate, mode, isFreeTier, models, fallback) === null) {
151
+ return candidate;
152
+ }
153
+ }
154
+ return serverDefaults?.[mode] ?? freeTierModeModelId(models, mode, fallback);
155
+ }
116
156
  /** Every mode a per-mode clamp exists for — used to test "free elsewhere". */
117
157
  const MODEL_MODES = ['plan', 'execute', 'commit', 'compact'];
118
158
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"chat-model-mode-utilities.js","sourceRoot":"","sources":["../../src/components/chat-model-mode-utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAqBH;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAA;IACzF,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAe,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAA;AAC9E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAe;IAEf,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM;YACT,OAAO,WAAW,CAAA;QACpB,KAAK,SAAS;YACZ,OAAO,cAAc,CAAA;QACvB,KAAK,QAAQ;YACX,OAAO,aAAa,CAAA;QACtB,KAAK,SAAS;YACZ,OAAO,cAAc,CAAA;IACzB,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAA8B,EAC9B,IAAe;IAEf,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM;YACT,OAAO,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAA;QACjD,KAAK,SAAS;YACZ,OAAO,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,SAAS,CAAA;QACpD,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC,WAAW,CAAA;QAC7B,KAAK,SAAS;YACZ,OAAO,QAAQ,CAAC,YAAY,CAAA;IAChC,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAqC,EACrC,IAAe,EACf,QAAgB;IAEhB,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,iBAAiB,CAAC,CAAA;QAC5D,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC,EAAE,CAAA;QAC1B,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACtF,IAAI,WAAW;YAAE,OAAO,WAAW,CAAC,EAAE,CAAA;QACtC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAA;QACjE,OAAO,WAAW,EAAE,EAAE,IAAI,QAAQ,CAAA;IACpC,CAAC;IACD,yEAAyE;IACzE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,mBAAmB,CAAC,CAAA;IAC9D,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC,EAAE,CAAA;IAC1B,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1F,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC,EAAE,CAAA;IAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAA;IACjE,OAAO,WAAW,EAAE,EAAE,IAAI,QAAQ,CAAA;AACpC,CAAC;AASD,8EAA8E;AAC9E,MAAM,WAAW,GAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAA;AAElF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAe,EACf,IAAe,EACf,UAAmB,EACnB,MAAqC,EACrC,QAAgB;IAEhB,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAA;IAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAA;IACtD,IAAI,SAAS,EAAE,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IACjD,MAAM,WAAW,GACf,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS;QACrC,CAAC,CAAC,SAAS,EAAE,QAAQ,KAAK,IAAI;QAC9B,CAAC,CAAC,OAAO,KAAK,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;IAC7D,IAAI,WAAW;QAAE,OAAO,IAAI,CAAA;IAC5B,MAAM,aAAa,GACjB,SAAS,EAAE,QAAQ,KAAK,IAAI;QAC5B,WAAW,CAAC,IAAI,CACd,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,mBAAmB,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CACtF,CAAA;IACH,OAAO,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;AACxC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAe,EACf,MAAqC,EACrC,QAAgB;IAEhB,IAAI,OAAO,KAAK,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;QAAE,OAAO,MAAM,CAAA;IAC5E,IAAI,OAAO,KAAK,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAA;IAClF,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,QAAQ,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAA;IAC5E,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,IAAe,EACf,UAAmB,EACnB,MAAqC,EACrC,QAAgB;IAEhB,OAAO,kBAAkB,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,IAAI,CAAA;AACjF,CAAC"}
1
+ {"version":3,"file":"chat-model-mode-utilities.js","sourceRoot":"","sources":["../../src/components/chat-model-mode-utilities.ts"],"names":[],"mappings":"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"}
@@ -40,34 +40,94 @@ export type ModelProcessingRegion = string;
40
40
  */
41
41
  export declare function effectiveModelRegion(model: AppModelDefinition, requested?: string): ModelProcessingRegion;
42
42
  /**
43
- * Combined input + output price per million tokens, used as the single
44
- * "cost/1M tokens" figure — at the rates of the model's effective region
45
- * (`regionPricing` override when the region has one, else the base rates).
43
+ * The peak-hour multiplier in force for a model at an instant, in a region.
44
+ *
45
+ * Mirrors the server's `priceMultiplierAt`, including the rule that matters
46
+ * most: peak belongs to the NATIVE provider, so a region with a `regionPricing`
47
+ * override — a different host, billing its own flat card — never takes it.
48
+ * Showing a 2× on a re-host the user is actually routed to would be a lie in
49
+ * the expensive direction.
50
+ *
51
+ * @param model - The model metadata.
52
+ * @param region - The user's per-model region choice, if any.
53
+ * @param at - The instant to evaluate (defaults to now).
54
+ * @returns The multiplier, or `1` when no peak window applies.
55
+ */
56
+ export declare function modelPeakMultiplier(model: AppModelDefinition, region?: string, at?: Date): number;
57
+ /**
58
+ * Whether a model can EVER cost more at some hours than others, in a region.
59
+ *
60
+ * Distinct from {@link modelPeakMultiplier}, which answers "right now". The
61
+ * picker needs both: one to price the current moment, one to decide whether the
62
+ * model deserves a "costs more at some hours" explanation at all — a model in
63
+ * its off-peak hours still surprises the user later if nothing says so.
64
+ *
65
+ * @param model - The model metadata.
66
+ * @param region - The user's per-model region choice, if any.
67
+ * @returns True when the model has peak windows that apply in this region.
68
+ */
69
+ export declare function modelHasPeakPricing(model: AppModelDefinition, region?: string): boolean;
70
+ /**
71
+ * The peak windows as local-time `HH:MM–HH:MM` ranges, for display.
72
+ *
73
+ * Local, not UTC: a user reasons about "is it expensive right now" in their own
74
+ * clock, and the windows are only actionable if they can be compared to it.
75
+ *
76
+ * @param model - The model metadata.
77
+ * @returns Formatted local ranges, empty when the model has no peak windows.
78
+ */
79
+ export declare function modelPeakWindowLabels(model: AppModelDefinition): string[];
80
+ /**
81
+ * What a representative agentic turn costs on a model, in USD — the single
82
+ * "cost" figure, at the rates of the model's effective region (`regionPricing`
83
+ * override when the region has one, else the base rates).
84
+ *
85
+ * This weighted `AGENTIC_TOKEN_MIX` replaced a plain `input + output` sum on
86
+ * 2026-08-14. That sum ignored cache reads, which is the term that actually
87
+ * dominates the bill, and the error was not small: it showed Claude Haiku at
88
+ * ×23 the cheapest model when the real figure is ×10, and gemini-3.7-flash at
89
+ * ×35 against a true ×15 — systematically scaring users off cache-friendly
90
+ * models while making a couple of others look cheaper than they bill. The sum
91
+ * was a fine proxy while every provider's cache read was a fixed fraction of
92
+ * input; it stopped being one once hosts started pricing cache reads
93
+ * independently (DeepSeek's absolute cache-hit rates, DeepInfra's 0.2x).
94
+ *
95
+ * Not currency: callers surface this only as a RELATIVE multiplier
96
+ * ({@link modelUsageRate}), never as a price.
46
97
  *
47
98
  * @param model - The model metadata.
48
99
  * @param region - The user's per-model region choice, if any (omitted → the
49
100
  * model's default region).
50
- * @returns Sum of input and output price per million tokens in USD.
101
+ * @returns The blended cost of one representative turn in USD.
51
102
  */
52
103
  export declare function modelTotalCost(model: AppModelDefinition, region?: string): number;
53
104
  /**
54
105
  * Relative usage rate: how much faster this model consumes the user's AI
55
106
  * allowance than the cheapest available model (a unitless `×N` multiplier,
56
- * `1` for the cheapest). Derived from combined input+output list rates. This
57
- * is the ONLY per-model "cost" figure user-facing surfaces show — AI usage is
58
- * never presented as currency.
107
+ * `1` for the cheapest). Derived from {@link modelTotalCost}, a blended agentic
108
+ * turn. This is the ONLY per-model "cost" figure user-facing surfaces show — AI
109
+ * usage is never presented as currency.
59
110
  *
60
111
  * The base is every model's DEFAULT-region cost (stable regardless of the
61
112
  * user's per-model region choices); the rated model itself is priced at the
62
113
  * given region so the figure tracks what a region switch actually changes.
63
114
  *
115
+ * PEAK PRICING IS INCLUDED, at `at`. A model inside a provider's peak window
116
+ * genuinely drains the allowance at its multiplier, so the figure has to move
117
+ * with it — a single all-day number is wrong twice a day. Only the RATED model
118
+ * takes its multiplier: the base stays each model's off-peak default-region
119
+ * cost, so the anchor does not wobble as unrelated models enter their windows.
120
+ * Pair it with {@link modelHasPeakPricing} / {@link modelPeakWindowLabels} so a
121
+ * changing number reads as explained rather than erratic.
122
+ *
64
123
  * @param model - The model to rate.
65
124
  * @param models - The full available-model list (supplies the cheapest base).
66
125
  * @param region - The rated model's region choice, if any (omitted → its
67
126
  * default region).
127
+ * @param at - The instant to price at (defaults to now).
68
128
  * @returns The multiplier, rounded to 1 decimal below 10 and whole above.
69
129
  */
70
- export declare function modelUsageRate(model: AppModelDefinition, models: readonly AppModelDefinition[], region?: string): number;
130
+ export declare function modelUsageRate(model: AppModelDefinition, models: readonly AppModelDefinition[], region?: string, at?: Date): number;
71
131
  /**
72
132
  * Ascending comparator for two models by the given column. Returns a negative,
73
133
  * zero, or positive number suitable for `Array.prototype.sort`. Ties fall back
@@ -1 +1 @@
1
- {"version":3,"file":"chat-models-utilities.d.ts","sourceRoot":"","sources":["../../src/components/chat-models-utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AAExF,sBAAsB;AACtB,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAA;AAE1C;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAA;AAE1C;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,kBAAkB,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,qBAAqB,CAGvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,kBAAkB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAKjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,kBAAkB,EACzB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAMR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,kBAAkB,EACrB,CAAC,EAAE,kBAAkB,EACrB,MAAM,EAAE,eAAe,EACvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,qBAAqB,GAC9D,MAAM,CAoCR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,aAAa,EACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,qBAAqB,GAC9D,kBAAkB,EAAE,CAQtB"}
1
+ {"version":3,"file":"chat-models-utilities.d.ts","sourceRoot":"","sources":["../../src/components/chat-models-utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AAExF,sBAAsB;AACtB,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAA;AAE1C;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAA;AAE1C;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,kBAAkB,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,qBAAqB,CAGvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,kBAAkB,EACzB,MAAM,CAAC,EAAE,MAAM,EACf,EAAE,GAAE,IAAiB,GACpB,MAAM,CAaR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAGvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAQzE;AAYD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,kBAAkB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAejF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,kBAAkB,EACzB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,MAAM,CAAC,EAAE,MAAM,EACf,EAAE,GAAE,IAAiB,GACpB,MAAM,CAMR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,kBAAkB,EACrB,CAAC,EAAE,kBAAkB,EACrB,MAAM,EAAE,eAAe,EACvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,qBAAqB,GAC9D,MAAM,CAoCR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,aAAa,EACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,qBAAqB,GAC9D,kBAAkB,EAAE,CAQtB"}
@@ -23,44 +23,148 @@ export function effectiveModelRegion(model, requested) {
23
23
  return requested && regions.includes(requested) ? requested : regions[0];
24
24
  }
25
25
  /**
26
- * Combined input + output price per million tokens, used as the single
27
- * "cost/1M tokens" figure — at the rates of the model's effective region
28
- * (`regionPricing` override when the region has one, else the base rates).
26
+ * The peak-hour multiplier in force for a model at an instant, in a region.
27
+ *
28
+ * Mirrors the server's `priceMultiplierAt`, including the rule that matters
29
+ * most: peak belongs to the NATIVE provider, so a region with a `regionPricing`
30
+ * override — a different host, billing its own flat card — never takes it.
31
+ * Showing a 2× on a re-host the user is actually routed to would be a lie in
32
+ * the expensive direction.
33
+ *
34
+ * @param model - The model metadata.
35
+ * @param region - The user's per-model region choice, if any.
36
+ * @param at - The instant to evaluate (defaults to now).
37
+ * @returns The multiplier, or `1` when no peak window applies.
38
+ */
39
+ export function modelPeakMultiplier(model, region, at = new Date()) {
40
+ if (model.regionPricing?.[effectiveModelRegion(model, region)])
41
+ return 1;
42
+ const peak = model.peakPricing;
43
+ if (!peak || peak.windows.length === 0)
44
+ return 1;
45
+ const minute = at.getUTCHours() * 60 + at.getUTCMinutes();
46
+ for (const w of peak.windows) {
47
+ const inWindow = w.startMinuteUtc <= w.endMinuteUtc
48
+ ? minute >= w.startMinuteUtc && minute < w.endMinuteUtc
49
+ : minute >= w.startMinuteUtc || minute < w.endMinuteUtc;
50
+ if (inWindow)
51
+ return peak.multiplier;
52
+ }
53
+ return 1;
54
+ }
55
+ /**
56
+ * Whether a model can EVER cost more at some hours than others, in a region.
57
+ *
58
+ * Distinct from {@link modelPeakMultiplier}, which answers "right now". The
59
+ * picker needs both: one to price the current moment, one to decide whether the
60
+ * model deserves a "costs more at some hours" explanation at all — a model in
61
+ * its off-peak hours still surprises the user later if nothing says so.
62
+ *
63
+ * @param model - The model metadata.
64
+ * @param region - The user's per-model region choice, if any.
65
+ * @returns True when the model has peak windows that apply in this region.
66
+ */
67
+ export function modelHasPeakPricing(model, region) {
68
+ if (model.regionPricing?.[effectiveModelRegion(model, region)])
69
+ return false;
70
+ return (model.peakPricing?.windows.length ?? 0) > 0 && model.peakPricing.multiplier !== 1;
71
+ }
72
+ /**
73
+ * The peak windows as local-time `HH:MM–HH:MM` ranges, for display.
74
+ *
75
+ * Local, not UTC: a user reasons about "is it expensive right now" in their own
76
+ * clock, and the windows are only actionable if they can be compared to it.
77
+ *
78
+ * @param model - The model metadata.
79
+ * @returns Formatted local ranges, empty when the model has no peak windows.
80
+ */
81
+ export function modelPeakWindowLabels(model) {
82
+ const windows = model.peakPricing?.windows ?? [];
83
+ const fmt = (minuteUtc) => {
84
+ const d = new Date();
85
+ d.setUTCHours(Math.floor(minuteUtc / 60), minuteUtc % 60, 0, 0);
86
+ return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
87
+ };
88
+ return windows.map((w) => `${fmt(w.startMinuteUtc)}–${fmt(w.endMinuteUtc)}`);
89
+ }
90
+ /**
91
+ * The token mix a real agentic turn bills at, used to weight the cost figure.
92
+ *
93
+ * Agentic conversations re-send a growing prefix every turn, so prompt-cache
94
+ * HITS dominate: measured traffic runs ~94% cache reads (deepseek, 2026-08-01).
95
+ * Weighting matters more than the exact numbers — what breaks is ignoring cache
96
+ * reads entirely, not being a few points off the ratio.
97
+ */
98
+ const AGENTIC_TOKEN_MIX = { cacheRead: 47_000, input: 3_000, output: 800 };
99
+ /**
100
+ * What a representative agentic turn costs on a model, in USD — the single
101
+ * "cost" figure, at the rates of the model's effective region (`regionPricing`
102
+ * override when the region has one, else the base rates).
103
+ *
104
+ * This weighted `AGENTIC_TOKEN_MIX` replaced a plain `input + output` sum on
105
+ * 2026-08-14. That sum ignored cache reads, which is the term that actually
106
+ * dominates the bill, and the error was not small: it showed Claude Haiku at
107
+ * ×23 the cheapest model when the real figure is ×10, and gemini-3.7-flash at
108
+ * ×35 against a true ×15 — systematically scaring users off cache-friendly
109
+ * models while making a couple of others look cheaper than they bill. The sum
110
+ * was a fine proxy while every provider's cache read was a fixed fraction of
111
+ * input; it stopped being one once hosts started pricing cache reads
112
+ * independently (DeepSeek's absolute cache-hit rates, DeepInfra's 0.2x).
113
+ *
114
+ * Not currency: callers surface this only as a RELATIVE multiplier
115
+ * ({@link modelUsageRate}), never as a price.
29
116
  *
30
117
  * @param model - The model metadata.
31
118
  * @param region - The user's per-model region choice, if any (omitted → the
32
119
  * model's default region).
33
- * @returns Sum of input and output price per million tokens in USD.
120
+ * @returns The blended cost of one representative turn in USD.
34
121
  */
35
122
  export function modelTotalCost(model, region) {
36
123
  const override = model.regionPricing?.[effectiveModelRegion(model, region)];
37
- return override
38
- ? override.inputPricePerMTok + override.outputPricePerMTok
39
- : model.inputPricePerMTok + model.outputPricePerMTok;
124
+ const input = override?.inputPricePerMTok ?? model.inputPricePerMTok;
125
+ const output = override?.outputPricePerMTok ?? model.outputPricePerMTok;
126
+ // An override with no cache fields bills cache reads at its input rate — the
127
+ // same fallback `modelRegionRates` applies server-side for metering.
128
+ const cacheRead = override
129
+ ? (override.cacheReadPricePerMTok ?? override.inputPricePerMTok)
130
+ : model.cacheReadPricePerMTok;
131
+ return ((AGENTIC_TOKEN_MIX.cacheRead * cacheRead +
132
+ AGENTIC_TOKEN_MIX.input * input +
133
+ AGENTIC_TOKEN_MIX.output * output) /
134
+ 1_000_000);
40
135
  }
41
136
  /**
42
137
  * Relative usage rate: how much faster this model consumes the user's AI
43
138
  * allowance than the cheapest available model (a unitless `×N` multiplier,
44
- * `1` for the cheapest). Derived from combined input+output list rates. This
45
- * is the ONLY per-model "cost" figure user-facing surfaces show — AI usage is
46
- * never presented as currency.
139
+ * `1` for the cheapest). Derived from {@link modelTotalCost}, a blended agentic
140
+ * turn. This is the ONLY per-model "cost" figure user-facing surfaces show — AI
141
+ * usage is never presented as currency.
47
142
  *
48
143
  * The base is every model's DEFAULT-region cost (stable regardless of the
49
144
  * user's per-model region choices); the rated model itself is priced at the
50
145
  * given region so the figure tracks what a region switch actually changes.
51
146
  *
147
+ * PEAK PRICING IS INCLUDED, at `at`. A model inside a provider's peak window
148
+ * genuinely drains the allowance at its multiplier, so the figure has to move
149
+ * with it — a single all-day number is wrong twice a day. Only the RATED model
150
+ * takes its multiplier: the base stays each model's off-peak default-region
151
+ * cost, so the anchor does not wobble as unrelated models enter their windows.
152
+ * Pair it with {@link modelHasPeakPricing} / {@link modelPeakWindowLabels} so a
153
+ * changing number reads as explained rather than erratic.
154
+ *
52
155
  * @param model - The model to rate.
53
156
  * @param models - The full available-model list (supplies the cheapest base).
54
157
  * @param region - The rated model's region choice, if any (omitted → its
55
158
  * default region).
159
+ * @param at - The instant to price at (defaults to now).
56
160
  * @returns The multiplier, rounded to 1 decimal below 10 and whole above.
57
161
  */
58
- export function modelUsageRate(model, models, region) {
162
+ export function modelUsageRate(model, models, region, at = new Date()) {
59
163
  const costs = models.map((m) => modelTotalCost(m)).filter((c) => c > 0);
60
164
  const base = costs.length > 0 ? Math.min(...costs) : 0;
61
165
  if (!Number.isFinite(base) || base <= 0)
62
166
  return 1;
63
- const rate = modelTotalCost(model, region) / base;
167
+ const rate = (modelTotalCost(model, region) * modelPeakMultiplier(model, region, at)) / base;
64
168
  return rate >= 10 ? Math.round(rate) : Math.max(1, Math.round(rate * 10) / 10);
65
169
  }
66
170
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"chat-models-utilities.js","sourceRoot":"","sources":["../../src/components/chat-models-utilities.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chat-models-utilities.js","sourceRoot":"","sources":["../../src/components/chat-models-utilities.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/app-ide-react",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "React IDE components for molecule.dev workspace",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -56,13 +56,13 @@
56
56
  "material-file-icons": "2.4.0"
57
57
  },
58
58
  "devDependencies": {
59
- "@molecule/app-ai-models": "1.1.0",
59
+ "@molecule/app-ai-models": "1.2.0",
60
60
  "@molecule/app-ai-voice": "1.0.1",
61
61
  "@molecule/app-country-flags": "1.0.1",
62
62
  "@molecule/app-i18n": "1.0.1",
63
63
  "@molecule/app-icons": "1.0.1",
64
64
  "@molecule/app-live-preview": "1.0.1",
65
- "@molecule/app-locales-ide": "1.0.1",
65
+ "@molecule/app-locales-ide": "1.1.0",
66
66
  "@molecule/app-logger": "1.0.1",
67
67
  "@molecule/app-react": "1.0.1",
68
68
  "@molecule/app-storage": "1.0.1",