@askalf/dario 4.8.47 → 4.8.49

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.
@@ -295,13 +295,24 @@ export declare function parseEffortSuffix(model: string): {
295
295
  * 'high' (live capture 2026-06-09, CC v2.1.170 — the same
296
296
  * capture got 'xhigh' on opus and 'high' on fable), so the
297
297
  * unset-flag default mirrors that per-family. An explicit
298
- * flag still pins.
298
+ * flag still pins (subject to the fable clamp below).
299
299
  * 'low' / 'medium' / 'high' / 'xhigh' / 'max' → pin to that value
300
300
  * 'ultracode' → 'xhigh' (CC's ultracode mode; xhigh on the wire)
301
301
  * 'client' → extract from `clientBody.output_config.effort` (normalized
302
302
  * for the wire); fall back to the per-family default if
303
303
  * absent/non-string
304
304
  *
305
+ * FABLE CLAMP (2026-06-09, live replay bisect on the deployed proxy):
306
+ * fable-5 SOFT-REFUSES `max` and `xhigh` — 200 with stop_reason "refusal"
307
+ * and empty content on every prompt, not a 400 — while `high` answers
308
+ * normally (byte-identical request bodies, only output_config.effort
309
+ * mutated). Empirical matrix on claude-fable-5:
310
+ * high → answers xhigh → refusal max → refusal
311
+ * So on the fable family any resolved 'max'/'xhigh' (from --effort /
312
+ * DARIO_EFFORT pins, ultracode, or client passthrough) is clamped to
313
+ * 'high', the strongest level fable accepts. Operators who pin
314
+ * --effort=max for Opus's sake keep that on every other family.
315
+ *
305
316
  * Exported for tests.
306
317
  */
307
318
  export declare function resolveEffort(flag: EffortValue | undefined, clientBody: Record<string, unknown>, model?: string): string;
@@ -989,27 +989,40 @@ function normalizeEffortForWire(effort) {
989
989
  * 'high' (live capture 2026-06-09, CC v2.1.170 — the same
990
990
  * capture got 'xhigh' on opus and 'high' on fable), so the
991
991
  * unset-flag default mirrors that per-family. An explicit
992
- * flag still pins.
992
+ * flag still pins (subject to the fable clamp below).
993
993
  * 'low' / 'medium' / 'high' / 'xhigh' / 'max' → pin to that value
994
994
  * 'ultracode' → 'xhigh' (CC's ultracode mode; xhigh on the wire)
995
995
  * 'client' → extract from `clientBody.output_config.effort` (normalized
996
996
  * for the wire); fall back to the per-family default if
997
997
  * absent/non-string
998
998
  *
999
+ * FABLE CLAMP (2026-06-09, live replay bisect on the deployed proxy):
1000
+ * fable-5 SOFT-REFUSES `max` and `xhigh` — 200 with stop_reason "refusal"
1001
+ * and empty content on every prompt, not a 400 — while `high` answers
1002
+ * normally (byte-identical request bodies, only output_config.effort
1003
+ * mutated). Empirical matrix on claude-fable-5:
1004
+ * high → answers xhigh → refusal max → refusal
1005
+ * So on the fable family any resolved 'max'/'xhigh' (from --effort /
1006
+ * DARIO_EFFORT pins, ultracode, or client passthrough) is clamped to
1007
+ * 'high', the strongest level fable accepts. Operators who pin
1008
+ * --effort=max for Opus's sake keep that on every other family.
1009
+ *
999
1010
  * Exported for tests.
1000
1011
  */
1001
1012
  export function resolveEffort(flag, clientBody, model) {
1002
- const familyDefault = (model ?? '').toLowerCase().includes('fable') ? 'high' : 'max';
1013
+ const isFable = (model ?? '').toLowerCase().includes('fable');
1014
+ const familyDefault = isFable ? 'high' : 'max';
1015
+ const clamp = (effort) => isFable && (effort === 'max' || effort === 'xhigh') ? 'high' : effort;
1003
1016
  if (flag === undefined)
1004
1017
  return familyDefault;
1005
1018
  if (flag === 'client') {
1006
1019
  const clientOC = clientBody.output_config;
1007
1020
  const clientEffort = clientOC?.effort;
1008
1021
  if (typeof clientEffort === 'string' && clientEffort.length > 0)
1009
- return normalizeEffortForWire(clientEffort);
1022
+ return clamp(normalizeEffortForWire(clientEffort));
1010
1023
  return familyDefault;
1011
1024
  }
1012
- return normalizeEffortForWire(flag);
1025
+ return clamp(normalizeEffortForWire(flag));
1013
1026
  }
1014
1027
  /**
1015
1028
  * Returns true if the given model accepts `thinking: { type: "adaptive" }`.
package/dist/proxy.d.ts CHANGED
@@ -29,6 +29,14 @@ export declare function parseProviderPrefix(model: string): {
29
29
  */
30
30
  export declare const FABLE_FALLBACK_CREDIT_BETA = "fallback-credit-2026-06-01";
31
31
  export declare function betaForModel(base: string, model: string | null | undefined): string;
32
+ /**
33
+ * Strip a trailing `[1m]` long-context tag from a model id. The tag is a
34
+ * client-side label: real CC sends the BASE id + `context-1m-2025-08-07`
35
+ * beta on the wire (live capture 2026-06-09, CC v2.1.170) — the literal
36
+ * `X[1m]` id 404s upstream on every family. Case-insensitive, only at the
37
+ * very end of the id. Exported for tests.
38
+ */
39
+ export declare function stripContext1mTag(model: string): string;
32
40
  export declare const ORCHESTRATION_TAG_NAMES: string[];
33
41
  /**
34
42
  * Build the regex list that actually strips orchestration tags.
package/dist/proxy.js CHANGED
@@ -208,6 +208,18 @@ export function betaForModel(base, model) {
208
208
  return base;
209
209
  return base ? `${base},${FABLE_FALLBACK_CREDIT_BETA}` : FABLE_FALLBACK_CREDIT_BETA;
210
210
  }
211
+ /**
212
+ * Strip a trailing `[1m]` long-context tag from a model id. The tag is a
213
+ * client-side label: real CC sends the BASE id + `context-1m-2025-08-07`
214
+ * beta on the wire (live capture 2026-06-09, CC v2.1.170) — the literal
215
+ * `X[1m]` id 404s upstream on every family. Case-insensitive, only at the
216
+ * very end of the id. Exported for tests.
217
+ */
218
+ export function stripContext1mTag(model) {
219
+ if (typeof model !== 'string')
220
+ return model;
221
+ return model.replace(/\[1m\]$/i, '');
222
+ }
211
223
  // Orchestration tags injected by agents (Aider, Cursor, OpenCode, etc.)
212
224
  // that confuse Claude when passed through. Strip before forwarding.
213
225
  export const ORCHESTRATION_TAG_NAMES = [
@@ -1539,6 +1551,17 @@ export async function startProxy(opts = {}) {
1539
1551
  for (const key of Object.keys(r))
1540
1552
  delete r[key];
1541
1553
  Object.assign(r, ccBody);
1554
+ // `X[1m]` is a client-side LABEL, never a valid wire id — real CC
1555
+ // sends the BASE model id plus the `context-1m-2025-08-07` beta
1556
+ // (live capture 2026-06-09, CC v2.1.170 with --model
1557
+ // 'claude-fable-5[1m]': wire model was 'claude-fable-5').
1558
+ // Forwarding the literal `[1m]` id upstream 404s ("model: …[1m]"
1559
+ // not_found) on every family. Strip it here; the context-1m beta
1560
+ // is already in the template beta set (and the existing
1561
+ // long-context billing auto-retry still governs accounts that
1562
+ // can't use it). requestModel keeps the [1m] form so model-aware
1563
+ // logic (family buckets, fable beta/effort) sees the user intent.
1564
+ r.model = stripContext1mTag(r.model);
1542
1565
  }
1543
1566
  finalBody = Buffer.from(JSON.stringify(r));
1544
1567
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "4.8.47",
3
+ "version": "4.8.49",
4
4
  "description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
5
5
  "type": "module",
6
6
  "bin": {