@askalf/dario 4.8.140 → 4.8.142
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/dist/cc-template.d.ts +63 -39
- package/dist/cc-template.js +91 -71
- package/dist/cli.js +23 -19
- package/dist/doctor.js +2 -2
- package/dist/live-fingerprint.d.ts +1 -1
- package/dist/live-fingerprint.js +3 -3
- package/dist/proxy.js +1 -1
- package/dist/tui/proxy-client.d.ts +8 -0
- package/dist/tui/proxy-client.js +18 -0
- package/dist/tui/tabs/status.d.ts +20 -0
- package/dist/tui/tabs/status.js +57 -2
- package/package.json +1 -1
package/dist/cc-template.d.ts
CHANGED
|
@@ -372,21 +372,28 @@ export declare function parseEffortSuffix(model: string): {
|
|
|
372
372
|
/**
|
|
373
373
|
* Resolve the outbound `output_config.effort` value.
|
|
374
374
|
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
375
|
+
* Effort is a USER KNOB, not a wire constant: real CC sends whatever the
|
|
376
|
+
* user's effort setting is tuned to, and "what CC sends" in a capture is just
|
|
377
|
+
* that install's knob position. dario chased captured values for months
|
|
378
|
+
* ('medium' → 'high' → 'xhigh' across CC releases — each one somebody's
|
|
379
|
+
* setting, not a version default) and pinned the outbound effort to a fixed
|
|
380
|
+
* value, silently clamping every client's explicit choice. Since 4.8.142 the
|
|
381
|
+
* default is client-first, matching how real CC actually behaves:
|
|
382
|
+
*
|
|
383
|
+
* undefined / 'client' → the client's `clientBody.output_config.effort`
|
|
384
|
+
* (normalized for the wire) — forward the knob untouched.
|
|
385
|
+
* Falls back to 'high' only when the client sent none
|
|
386
|
+
* (OpenAI-compat clients that can't set effort).
|
|
387
|
+
* 'low' / 'medium' / 'high' / 'xhigh' / 'max' → operator pin via
|
|
388
|
+
* --effort / DARIO_EFFORT (explicit override, wins over client)
|
|
387
389
|
* 'ultracode' → 'xhigh' (CC's ultracode mode; xhigh on the wire)
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
+
*
|
|
391
|
+
* The 'high' fallback (not 'max') is dario#658 scar tissue: 'max' plus
|
|
392
|
+
* unbounded adaptive thinking exhausts max_tokens on long prompts — the
|
|
393
|
+
* stream ends `stop_reason: max_tokens` with ZERO text blocks. 'high' thinks
|
|
394
|
+
* proportionally and leaves room for the answer. A client that explicitly
|
|
395
|
+
* asks for 'max' gets 'max' — same outcome it would get talking to Anthropic
|
|
396
|
+
* directly.
|
|
390
397
|
*
|
|
391
398
|
* FABLE CLAMP — REMOVED 2026-07-01. Fable 5 was SUSPENDED 2026-06-12 (US-gov
|
|
392
399
|
* directive) and REDEPLOYED 2026-07-01. The pre-suspension model (2026-06-09
|
|
@@ -395,12 +402,9 @@ export declare function parseEffortSuffix(model: string): {
|
|
|
395
402
|
* through the deployed proxy (CC 2.1.198's verbatim fable body, only
|
|
396
403
|
* output_config.effort mutated) shows the redeployed fable now ANSWERS all three
|
|
397
404
|
* — high/xhigh/max → end_turn, zero refusals. So the clamp + the fable-only
|
|
398
|
-
* default are gone: fable
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
* single value is "the" value; `high` is the safe unconfigured baseline.
|
|
402
|
-
* `model` is retained in the signature in case a future model needs per-family
|
|
403
|
-
* effort handling again.
|
|
405
|
+
* default are gone: fable takes the general path, matching how dario treats
|
|
406
|
+
* opus. `model` is retained in the signature in case a future model needs
|
|
407
|
+
* per-family effort handling again.
|
|
404
408
|
*
|
|
405
409
|
* Exported for tests.
|
|
406
410
|
*/
|
|
@@ -442,28 +446,48 @@ export type CacheControl = {
|
|
|
442
446
|
ttl?: '5m' | '1h';
|
|
443
447
|
};
|
|
444
448
|
/**
|
|
445
|
-
* The cache-control dario stamps on every breakpoint (2 system +
|
|
446
|
-
* conversation). `
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
449
|
+
* The cache-control dario stamps on every breakpoint (2 system + 2
|
|
450
|
+
* conversation). Plain `{type:'ephemeral'}` (the 5-minute default) mirrors
|
|
451
|
+
* real CC: a loopback MITM capture of CC v2.1.203 shows no `ttl` field on any
|
|
452
|
+
* breakpoint. v4.8.140 stamped `ttl:'1h'` here on the theory that real CC
|
|
453
|
+
* used 1h — it doesn't, and 1h cache WRITES bill at 2x base input vs 1.25x
|
|
454
|
+
* for 5m, so every write in a write-heavy agentic session cost 60% more than
|
|
455
|
+
* direct CC. The dario#678 re-test caught it: the reporter's cold-start burn
|
|
456
|
+
* went +8% -> +19% on the "fixed" build. Single source of truth so the
|
|
457
|
+
* emitted shape can't drift from CC again.
|
|
452
458
|
*/
|
|
453
459
|
export declare const CC_CACHE_CONTROL: CacheControl;
|
|
454
460
|
/**
|
|
455
|
-
* Place CC-style prompt-cache breakpoints on the
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
*
|
|
461
|
+
* Place CC-style prompt-cache breakpoints on the conversation. The system
|
|
462
|
+
* prompt is already cached at build time (2 system breakpoints); this adds a
|
|
463
|
+
* rolling breakpoint on the last user message plus an anchor on the previous
|
|
464
|
+
* one — total 4, the Anthropic max.
|
|
465
|
+
*
|
|
466
|
+
* Placement mirrors a live capture of CC v2.1.203 (dario#678):
|
|
467
|
+
*
|
|
468
|
+
* - Tools carry NO breakpoint. Real CC sends its tool array unstamped —
|
|
469
|
+
* Anthropic renders tools -> system -> messages, so the system breakpoints
|
|
470
|
+
* already cache the tools prefix. Stamping the last tool (pre-4.8.142) both
|
|
471
|
+
* diverged from CC's wire shape and spent the fourth slot the conversation
|
|
472
|
+
* anchor below needs.
|
|
473
|
+
*
|
|
474
|
+
* - The rolling breakpoint goes on the last USER message, not the last
|
|
475
|
+
* message. CC skips trailing role:"system" injections (agent-type updates
|
|
476
|
+
* etc.); stamping "the last message" meant any turn ending in one wrote no
|
|
477
|
+
* conversation entry at all, and the next request re-paid the entire
|
|
478
|
+
* history as fresh input.
|
|
479
|
+
*
|
|
480
|
+
* - The previous user message is anchored too. Anthropic's cache lookup
|
|
481
|
+
* walks back at most ~20 content blocks from a breakpoint; one parallel-
|
|
482
|
+
* tool turn (N tool_use + N tool_result blocks) can exceed that alone, and
|
|
483
|
+
* the rolling breakpoint then can't reach the prior turn's entry — the
|
|
484
|
+
* whole conversation re-bills at cache-WRITE cost every fan-out turn,
|
|
485
|
+
* which is the dario#678 burn ("read every file" sessions draining the
|
|
486
|
+
* Max window ~10x faster than direct CC). The anchor sits exactly where
|
|
487
|
+
* the previous request's rolling breakpoint was, so the lookup hits it
|
|
488
|
+
* positionally with no walk-back.
|
|
489
|
+
*
|
|
490
|
+
* Exported for unit testing.
|
|
467
491
|
*/
|
|
468
492
|
export declare function applyCcPromptCaching(ccRequest: Record<string, unknown>, cacheControl: CacheControl): void;
|
|
469
493
|
export declare function buildCCRequest(clientBody: Record<string, unknown>, billingTag: string, cacheControl: CacheControl, identity: {
|
package/dist/cc-template.js
CHANGED
|
@@ -1126,21 +1126,28 @@ function normalizeEffortForWire(effort) {
|
|
|
1126
1126
|
/**
|
|
1127
1127
|
* Resolve the outbound `output_config.effort` value.
|
|
1128
1128
|
*
|
|
1129
|
-
*
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1129
|
+
* Effort is a USER KNOB, not a wire constant: real CC sends whatever the
|
|
1130
|
+
* user's effort setting is tuned to, and "what CC sends" in a capture is just
|
|
1131
|
+
* that install's knob position. dario chased captured values for months
|
|
1132
|
+
* ('medium' → 'high' → 'xhigh' across CC releases — each one somebody's
|
|
1133
|
+
* setting, not a version default) and pinned the outbound effort to a fixed
|
|
1134
|
+
* value, silently clamping every client's explicit choice. Since 4.8.142 the
|
|
1135
|
+
* default is client-first, matching how real CC actually behaves:
|
|
1133
1136
|
*
|
|
1134
|
-
* undefined
|
|
1135
|
-
*
|
|
1136
|
-
*
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1140
|
-
* 'low' / 'medium' / 'high' / 'xhigh' / 'max' → pin to that value
|
|
1137
|
+
* undefined / 'client' → the client's `clientBody.output_config.effort`
|
|
1138
|
+
* (normalized for the wire) — forward the knob untouched.
|
|
1139
|
+
* Falls back to 'high' only when the client sent none
|
|
1140
|
+
* (OpenAI-compat clients that can't set effort).
|
|
1141
|
+
* 'low' / 'medium' / 'high' / 'xhigh' / 'max' → operator pin via
|
|
1142
|
+
* --effort / DARIO_EFFORT (explicit override, wins over client)
|
|
1141
1143
|
* 'ultracode' → 'xhigh' (CC's ultracode mode; xhigh on the wire)
|
|
1142
|
-
*
|
|
1143
|
-
*
|
|
1144
|
+
*
|
|
1145
|
+
* The 'high' fallback (not 'max') is dario#658 scar tissue: 'max' plus
|
|
1146
|
+
* unbounded adaptive thinking exhausts max_tokens on long prompts — the
|
|
1147
|
+
* stream ends `stop_reason: max_tokens` with ZERO text blocks. 'high' thinks
|
|
1148
|
+
* proportionally and leaves room for the answer. A client that explicitly
|
|
1149
|
+
* asks for 'max' gets 'max' — same outcome it would get talking to Anthropic
|
|
1150
|
+
* directly.
|
|
1144
1151
|
*
|
|
1145
1152
|
* FABLE CLAMP — REMOVED 2026-07-01. Fable 5 was SUSPENDED 2026-06-12 (US-gov
|
|
1146
1153
|
* directive) and REDEPLOYED 2026-07-01. The pre-suspension model (2026-06-09
|
|
@@ -1149,33 +1156,21 @@ function normalizeEffortForWire(effort) {
|
|
|
1149
1156
|
* through the deployed proxy (CC 2.1.198's verbatim fable body, only
|
|
1150
1157
|
* output_config.effort mutated) shows the redeployed fable now ANSWERS all three
|
|
1151
1158
|
* — high/xhigh/max → end_turn, zero refusals. So the clamp + the fable-only
|
|
1152
|
-
* default are gone: fable
|
|
1153
|
-
*
|
|
1154
|
-
*
|
|
1155
|
-
* single value is "the" value; `high` is the safe unconfigured baseline.
|
|
1156
|
-
* `model` is retained in the signature in case a future model needs per-family
|
|
1157
|
-
* effort handling again.
|
|
1159
|
+
* default are gone: fable takes the general path, matching how dario treats
|
|
1160
|
+
* opus. `model` is retained in the signature in case a future model needs
|
|
1161
|
+
* per-family effort handling again.
|
|
1158
1162
|
*
|
|
1159
1163
|
* Exported for tests.
|
|
1160
1164
|
*/
|
|
1161
1165
|
export function resolveEffort(flag, clientBody, model) {
|
|
1162
1166
|
void model; // no per-family effort handling at present (see FABLE CLAMP note above)
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
// the model reason until it exhausts `max_tokens` — on prompts over ~5K input
|
|
1166
|
-
// tokens the thinking phase consumes the entire budget, so the stream ends
|
|
1167
|
-
// `stop_reason: max_tokens` with ZERO text blocks (dario#658). `high` thinks
|
|
1168
|
-
// proportionally and leaves room for the answer. Effort is a user-adjustable
|
|
1169
|
-
// knob; operators who want a higher tier pin it via `--effort` / DARIO_EFFORT.
|
|
1170
|
-
const familyDefault = 'high';
|
|
1171
|
-
if (flag === undefined)
|
|
1172
|
-
return familyDefault;
|
|
1173
|
-
if (flag === 'client') {
|
|
1167
|
+
const fallback = 'high';
|
|
1168
|
+
if (flag === undefined || flag === 'client') {
|
|
1174
1169
|
const clientOC = clientBody.output_config;
|
|
1175
1170
|
const clientEffort = clientOC?.effort;
|
|
1176
1171
|
if (typeof clientEffort === 'string' && clientEffort.length > 0)
|
|
1177
1172
|
return normalizeEffortForWire(clientEffort);
|
|
1178
|
-
return
|
|
1173
|
+
return fallback;
|
|
1179
1174
|
}
|
|
1180
1175
|
return normalizeEffortForWire(flag);
|
|
1181
1176
|
}
|
|
@@ -1236,55 +1231,80 @@ export function supportsAdaptiveThinking(modelId) {
|
|
|
1236
1231
|
return false;
|
|
1237
1232
|
}
|
|
1238
1233
|
/**
|
|
1239
|
-
* The cache-control dario stamps on every breakpoint (2 system +
|
|
1240
|
-
* conversation). `
|
|
1241
|
-
*
|
|
1242
|
-
*
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
1234
|
+
* The cache-control dario stamps on every breakpoint (2 system + 2
|
|
1235
|
+
* conversation). Plain `{type:'ephemeral'}` (the 5-minute default) mirrors
|
|
1236
|
+
* real CC: a loopback MITM capture of CC v2.1.203 shows no `ttl` field on any
|
|
1237
|
+
* breakpoint. v4.8.140 stamped `ttl:'1h'` here on the theory that real CC
|
|
1238
|
+
* used 1h — it doesn't, and 1h cache WRITES bill at 2x base input vs 1.25x
|
|
1239
|
+
* for 5m, so every write in a write-heavy agentic session cost 60% more than
|
|
1240
|
+
* direct CC. The dario#678 re-test caught it: the reporter's cold-start burn
|
|
1241
|
+
* went +8% -> +19% on the "fixed" build. Single source of truth so the
|
|
1242
|
+
* emitted shape can't drift from CC again.
|
|
1246
1243
|
*/
|
|
1247
|
-
export const CC_CACHE_CONTROL = { type: 'ephemeral'
|
|
1244
|
+
export const CC_CACHE_CONTROL = { type: 'ephemeral' };
|
|
1248
1245
|
/**
|
|
1249
|
-
* Place CC-style prompt-cache breakpoints on the
|
|
1250
|
-
*
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1246
|
+
* Place CC-style prompt-cache breakpoints on the conversation. The system
|
|
1247
|
+
* prompt is already cached at build time (2 system breakpoints); this adds a
|
|
1248
|
+
* rolling breakpoint on the last user message plus an anchor on the previous
|
|
1249
|
+
* one — total 4, the Anthropic max.
|
|
1250
|
+
*
|
|
1251
|
+
* Placement mirrors a live capture of CC v2.1.203 (dario#678):
|
|
1252
|
+
*
|
|
1253
|
+
* - Tools carry NO breakpoint. Real CC sends its tool array unstamped —
|
|
1254
|
+
* Anthropic renders tools -> system -> messages, so the system breakpoints
|
|
1255
|
+
* already cache the tools prefix. Stamping the last tool (pre-4.8.142) both
|
|
1256
|
+
* diverged from CC's wire shape and spent the fourth slot the conversation
|
|
1257
|
+
* anchor below needs.
|
|
1253
1258
|
*
|
|
1254
|
-
*
|
|
1255
|
-
*
|
|
1256
|
-
*
|
|
1257
|
-
*
|
|
1258
|
-
*
|
|
1259
|
-
*
|
|
1260
|
-
*
|
|
1259
|
+
* - The rolling breakpoint goes on the last USER message, not the last
|
|
1260
|
+
* message. CC skips trailing role:"system" injections (agent-type updates
|
|
1261
|
+
* etc.); stamping "the last message" meant any turn ending in one wrote no
|
|
1262
|
+
* conversation entry at all, and the next request re-paid the entire
|
|
1263
|
+
* history as fresh input.
|
|
1264
|
+
*
|
|
1265
|
+
* - The previous user message is anchored too. Anthropic's cache lookup
|
|
1266
|
+
* walks back at most ~20 content blocks from a breakpoint; one parallel-
|
|
1267
|
+
* tool turn (N tool_use + N tool_result blocks) can exceed that alone, and
|
|
1268
|
+
* the rolling breakpoint then can't reach the prior turn's entry — the
|
|
1269
|
+
* whole conversation re-bills at cache-WRITE cost every fan-out turn,
|
|
1270
|
+
* which is the dario#678 burn ("read every file" sessions draining the
|
|
1271
|
+
* Max window ~10x faster than direct CC). The anchor sits exactly where
|
|
1272
|
+
* the previous request's rolling breakpoint was, so the lookup hits it
|
|
1273
|
+
* positionally with no walk-back.
|
|
1274
|
+
*
|
|
1275
|
+
* Exported for unit testing.
|
|
1261
1276
|
*/
|
|
1262
1277
|
export function applyCcPromptCaching(ccRequest, cacheControl) {
|
|
1263
|
-
// Tools —
|
|
1264
|
-
//
|
|
1278
|
+
// Tools — strip any stray client breakpoints (they'd count against the
|
|
1279
|
+
// 4-breakpoint budget) without mutating shared element objects
|
|
1280
|
+
// (CC_TOOL_DEFINITIONS is a module constant).
|
|
1265
1281
|
const tools = ccRequest.tools;
|
|
1266
1282
|
if (Array.isArray(tools) && tools.length > 0) {
|
|
1267
|
-
|
|
1283
|
+
ccRequest.tools = tools.map((t) => {
|
|
1284
|
+
if (!('cache_control' in t))
|
|
1285
|
+
return t;
|
|
1268
1286
|
const copy = { ...t };
|
|
1269
1287
|
delete copy.cache_control;
|
|
1270
1288
|
return copy;
|
|
1271
1289
|
});
|
|
1272
|
-
cloned[cloned.length - 1] = { ...cloned[cloned.length - 1], cache_control: cacheControl };
|
|
1273
|
-
ccRequest.tools = cloned;
|
|
1274
1290
|
}
|
|
1275
|
-
// Conversation —
|
|
1276
|
-
//
|
|
1277
|
-
//
|
|
1291
|
+
// Conversation — last two user messages, walking backward. Client
|
|
1292
|
+
// breakpoints were already stripped upstream. Only block-array content gets
|
|
1293
|
+
// a breakpoint: string content (some SDK clients) is left untouched —
|
|
1294
|
+
// wrapping it would change the wire shape, and a bare string user turn is
|
|
1295
|
+
// tiny anyway. Real CC / agentic sessions use block arrays, which DO cache.
|
|
1278
1296
|
const msgs = ccRequest.messages;
|
|
1279
1297
|
if (Array.isArray(msgs) && msgs.length > 0) {
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1298
|
+
let stamped = 0;
|
|
1299
|
+
for (let i = msgs.length - 1; i >= 0 && stamped < 2; i--) {
|
|
1300
|
+
const msg = msgs[i];
|
|
1301
|
+
if (msg.role !== 'user')
|
|
1302
|
+
continue;
|
|
1303
|
+
if (!Array.isArray(msg.content) || msg.content.length === 0)
|
|
1304
|
+
continue;
|
|
1305
|
+
const blocks = msg.content;
|
|
1287
1306
|
blocks[blocks.length - 1] = { ...blocks[blocks.length - 1], cache_control: cacheControl };
|
|
1307
|
+
stamped++;
|
|
1288
1308
|
}
|
|
1289
1309
|
}
|
|
1290
1310
|
}
|
|
@@ -1557,8 +1577,8 @@ export function buildCCRequest(clientBody, billingTag, cacheControl, identity, o
|
|
|
1557
1577
|
//
|
|
1558
1578
|
// System prompt structure (3 blocks, matching real CC):
|
|
1559
1579
|
// [0] billing tag (no cache)
|
|
1560
|
-
// [1] agent identity (
|
|
1561
|
-
// [2] CC's full 25KB system prompt + client's custom prompt appended (
|
|
1580
|
+
// [1] agent identity (ephemeral cache)
|
|
1581
|
+
// [2] CC's full 25KB system prompt + client's custom prompt appended (ephemeral cache)
|
|
1562
1582
|
// resolveSystemPrompt is the seam for --system-prompt=verbatim|partial|
|
|
1563
1583
|
// aggressive|<file>. Default (undefined) returns CC_SYSTEM_PROMPT
|
|
1564
1584
|
// unchanged. See docs/research/system-prompt-classifier-study.md for the empirical
|
|
@@ -1690,10 +1710,10 @@ export function buildCCRequest(clientBody, billingTag, cacheControl, identity, o
|
|
|
1690
1710
|
// — Max billing pool routing is unchanged.
|
|
1691
1711
|
//
|
|
1692
1712
|
// `output_config.effort` is independent of thinking and ships for all
|
|
1693
|
-
// non-Haiku models that aren't opted out via skipFields. Default
|
|
1694
|
-
//
|
|
1695
|
-
//
|
|
1696
|
-
//
|
|
1713
|
+
// non-Haiku models that aren't opted out via skipFields. Default: forward
|
|
1714
|
+
// the client's own effort (it's a user knob — real CC wires whatever the
|
|
1715
|
+
// user tuned), falling back to 'high' when the client sent none; `--effort`
|
|
1716
|
+
// flag pins an operator override. See resolveEffort / dario#87.
|
|
1697
1717
|
if (!isHaiku) {
|
|
1698
1718
|
const skip = opts.skipFields;
|
|
1699
1719
|
// Client-supplied thinking shape takes precedence when honorClientThinking
|
package/dist/cli.js
CHANGED
|
@@ -400,15 +400,17 @@ async function proxy() {
|
|
|
400
400
|
?? parsePositiveIntEnv(process.env['DARIO_MAX_QUEUED']);
|
|
401
401
|
const queueTimeoutMs = parsePositiveIntFlag('--queue-timeout=')
|
|
402
402
|
?? parsePositiveIntEnv(process.env['DARIO_QUEUE_TIMEOUT_MS']);
|
|
403
|
-
// --effort=low|medium|high|xhigh|ultracode|max|client —
|
|
404
|
-
// output_config.effort (dario#87). Default (unset)
|
|
405
|
-
//
|
|
406
|
-
//
|
|
403
|
+
// --effort=low|medium|high|xhigh|ultracode|max|client — pin the outbound
|
|
404
|
+
// output_config.effort (dario#87). Default (unset) forwards the client's
|
|
405
|
+
// own effort — it's a user knob, real CC wires whatever the user tuned —
|
|
406
|
+
// falling back to 'high' when the client sent none. 'client' is a
|
|
407
|
+
// compatibility alias for the default.
|
|
407
408
|
//
|
|
408
|
-
// Risk:
|
|
409
|
-
//
|
|
410
|
-
//
|
|
411
|
-
// and revert to default
|
|
409
|
+
// Risk: pinning effort overrides every client's explicit choice, and a
|
|
410
|
+
// non-CC-plausible value may cause Anthropic's classifier to flip requests
|
|
411
|
+
// to 'overage' billing. Users opting in should watch the
|
|
412
|
+
// `representative-claim` response header via -v logs and revert to default
|
|
413
|
+
// if subscription billing breaks.
|
|
412
414
|
const effort = resolveEffortFlag(args, process.env['DARIO_EFFORT']);
|
|
413
415
|
// --max-tokens=<N|client> — override outbound max_tokens (dario#88,
|
|
414
416
|
// Hermes compat). Default unset pins 32000 (CC 2.1.116's wire default).
|
|
@@ -1321,17 +1323,19 @@ async function help() {
|
|
|
1321
1323
|
(default: 60000).
|
|
1322
1324
|
Env: DARIO_QUEUE_TIMEOUT_MS. (dario#80)
|
|
1323
1325
|
--effort=<low|medium|high|xhigh|ultracode|max|client>
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1326
|
+
Pin the outbound output_config.effort on
|
|
1327
|
+
non-haiku requests, overriding the
|
|
1328
|
+
client's choice. Default (unset) forwards
|
|
1329
|
+
the client's own effort — it's a user
|
|
1330
|
+
knob; real CC wires whatever the user
|
|
1331
|
+
tuned — falling back to 'high' when the
|
|
1332
|
+
client sent none. 'client' is a compat
|
|
1333
|
+
alias for the default. 'ultracode' rides
|
|
1334
|
+
the wire as 'xhigh'.
|
|
1335
|
+
WARNING: pinned values override every
|
|
1336
|
+
client and may cause Anthropic's
|
|
1337
|
+
classifier to flip requests to 'overage'
|
|
1338
|
+
billing; watch -v logs for
|
|
1335
1339
|
representative-claim changes.
|
|
1336
1340
|
Env: DARIO_EFFORT. (dario#87)
|
|
1337
1341
|
--max-tokens=<N|client> Override outbound max_tokens. Default
|
package/dist/doctor.js
CHANGED
|
@@ -334,7 +334,7 @@ export async function runChecks(opts = {}) {
|
|
|
334
334
|
// non-passthrough request and dominate the input-token cost on small
|
|
335
335
|
// turns. Anthropic caches them after the first hit (cache_creation
|
|
336
336
|
// tokens on call 1, then cache_read on subsequent calls within the
|
|
337
|
-
//
|
|
337
|
+
// 5-minute TTL), but non-CC users routing heavy tooling get
|
|
338
338
|
// surprised by the first-request charge. Surface the size up front
|
|
339
339
|
// so they can plan.
|
|
340
340
|
//
|
|
@@ -355,7 +355,7 @@ export async function runChecks(opts = {}) {
|
|
|
355
355
|
detail: `${promptChars.toLocaleString()} chars system prompt + ${toolCount} tool defs ` +
|
|
356
356
|
`(${toolChars.toLocaleString()} chars JSON-serialized) injected per non-passthrough ` +
|
|
357
357
|
`request. Cached after first hit; read-cost only on subsequent calls within ` +
|
|
358
|
-
`the
|
|
358
|
+
`the 5-minute TTL. Exact token count surfaces as cache_creation_input_tokens ` +
|
|
359
359
|
`on the first response (or run \`dario doctor --usage\`).`,
|
|
360
360
|
});
|
|
361
361
|
}
|
|
@@ -282,7 +282,7 @@ export declare function _resetInstalledVersionProbeForTest(): void;
|
|
|
282
282
|
*/
|
|
283
283
|
export declare const SUPPORTED_CC_RANGE: {
|
|
284
284
|
readonly min: "1.0.0";
|
|
285
|
-
readonly maxTested: "2.1.
|
|
285
|
+
readonly maxTested: "2.1.203";
|
|
286
286
|
};
|
|
287
287
|
/**
|
|
288
288
|
* Compare two dotted-numeric version strings. Returns negative if `a<b`,
|
package/dist/live-fingerprint.js
CHANGED
|
@@ -542,8 +542,8 @@ export function extractTemplate(captured) {
|
|
|
542
542
|
return null;
|
|
543
543
|
// CC's system is a 3-block structure:
|
|
544
544
|
// [0] billing tag (no cache_control, tiny)
|
|
545
|
-
// [1] agent identity ("You are Claude Code..."), cache_control
|
|
546
|
-
// [2] system prompt (~25KB), cache_control
|
|
545
|
+
// [1] agent identity ("You are Claude Code..."), cache_control ephemeral (5m — no ttl field, verified CC v2.1.203)
|
|
546
|
+
// [2] system prompt (~25KB), cache_control ephemeral (5m)
|
|
547
547
|
// Billing tag is per-request — we never cache it. Identity + prompt are
|
|
548
548
|
// what we want.
|
|
549
549
|
const agentIdentity = pickTextBlock(systemBlocks[1]);
|
|
@@ -786,7 +786,7 @@ export function _resetInstalledVersionProbeForTest() {
|
|
|
786
786
|
*/
|
|
787
787
|
export const SUPPORTED_CC_RANGE = {
|
|
788
788
|
min: '1.0.0',
|
|
789
|
-
maxTested: '2.1.
|
|
789
|
+
maxTested: '2.1.203',
|
|
790
790
|
};
|
|
791
791
|
/**
|
|
792
792
|
* Compare two dotted-numeric version strings. Returns negative if `a<b`,
|
package/dist/proxy.js
CHANGED
|
@@ -2049,7 +2049,7 @@ export async function startProxy(opts = {}) {
|
|
|
2049
2049
|
// current Claude Code, which sends none. dario#528.
|
|
2050
2050
|
const cch = hasCchSeed(cliVersion) ? computeCch() : null;
|
|
2051
2051
|
const billingTag = buildBillingTag(cliVersion, cch);
|
|
2052
|
-
//
|
|
2052
|
+
// Plain 5m ephemeral, matching real CC (see CC_CACHE_CONTROL / dario#678).
|
|
2053
2053
|
const CACHE_EPHEMERAL = CC_CACHE_CONTROL;
|
|
2054
2054
|
// Session stickiness: rebind the pre-selected pool account to
|
|
2055
2055
|
// whatever the sticky-key resolver picks. If this is a new
|
|
@@ -70,6 +70,14 @@ export declare class ProxyClient {
|
|
|
70
70
|
* tab can render "unknown" without crashing.
|
|
71
71
|
*/
|
|
72
72
|
getOverageGuard(): Promise<OverageGuardStatus | null>;
|
|
73
|
+
/**
|
|
74
|
+
* Advertised model ids — GET /v1/models (the upstream-autodetected
|
|
75
|
+
* catalog with the baked fallback, so a running proxy always answers).
|
|
76
|
+
* Returns the raw id list (base ids + generated `[1m]` variants) or
|
|
77
|
+
* null on any error so the Status tab renders without a Models panel
|
|
78
|
+
* instead of crashing.
|
|
79
|
+
*/
|
|
80
|
+
listModels(): Promise<string[] | null>;
|
|
73
81
|
/**
|
|
74
82
|
* Clear the overage-guard halt state. POSTs /admin/resume. Returns the
|
|
75
83
|
* server's response (`wasHalted` indicates whether the call actually
|
package/dist/tui/proxy-client.js
CHANGED
|
@@ -186,6 +186,24 @@ export class ProxyClient {
|
|
|
186
186
|
return null;
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Advertised model ids — GET /v1/models (the upstream-autodetected
|
|
191
|
+
* catalog with the baked fallback, so a running proxy always answers).
|
|
192
|
+
* Returns the raw id list (base ids + generated `[1m]` variants) or
|
|
193
|
+
* null on any error so the Status tab renders without a Models panel
|
|
194
|
+
* instead of crashing.
|
|
195
|
+
*/
|
|
196
|
+
async listModels() {
|
|
197
|
+
try {
|
|
198
|
+
const r = await this.getJson('/v1/models');
|
|
199
|
+
if (!Array.isArray(r.data))
|
|
200
|
+
return null;
|
|
201
|
+
return r.data.map((m) => String(m.id ?? '')).filter((id) => id.length > 0);
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
189
207
|
/**
|
|
190
208
|
* Clear the overage-guard halt state. POSTs /admin/resume. Returns the
|
|
191
209
|
* server's response (`wasHalted` indicates whether the call actually
|
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
* │ schema: v1 │
|
|
19
19
|
* │ …per-knob effective values (read-only) │
|
|
20
20
|
* └─────────────────────────────────────────────────┘
|
|
21
|
+
* ┌─ Models ────────────────────────────────────────┐
|
|
22
|
+
* │ claude-fable-5 +[1m] │
|
|
23
|
+
* │ claude-opus-4-8 +[1m] │
|
|
24
|
+
* │ claude-sonnet-5 +[1m] │
|
|
25
|
+
* │ …the advertised catalog, live from /v1/models │
|
|
26
|
+
* └─────────────────────────────────────────────────┘
|
|
21
27
|
*/
|
|
22
28
|
import type { Tab, TabContext } from '../tab.js';
|
|
23
29
|
import type { OverageGuardStatus } from '../proxy-client.js';
|
|
@@ -32,6 +38,8 @@ export interface StatusState {
|
|
|
32
38
|
} | null;
|
|
33
39
|
/** Config-file load source: file | missing | invalid. */
|
|
34
40
|
configSource: 'file' | 'missing' | 'invalid' | null;
|
|
41
|
+
/** Advertised model ids from /v1/models — null if unreachable. */
|
|
42
|
+
models: string[] | null;
|
|
35
43
|
/** Overage-guard state from /admin/resume — null if unreachable. */
|
|
36
44
|
overageGuard: OverageGuardStatus | null;
|
|
37
45
|
/** Transient: did we just attempt a manual resume? */
|
|
@@ -44,6 +52,18 @@ export interface StatusState {
|
|
|
44
52
|
error: string | null;
|
|
45
53
|
}
|
|
46
54
|
export declare const StatusTab: Tab<StatusState>;
|
|
55
|
+
/**
|
|
56
|
+
* Fold `<base>[1m]` variants onto their base id: the /v1/models listing
|
|
57
|
+
* advertises both forms for every long-context-capable family, and showing
|
|
58
|
+
* fourteen rows for seven models is noise. Preserves the catalog's order
|
|
59
|
+
* (family rank, version desc). A `[1m]`-only id with no base row (shouldn't
|
|
60
|
+
* happen — the generator always emits the pair) still gets its own row so
|
|
61
|
+
* nothing silently disappears. Exported for unit testing.
|
|
62
|
+
*/
|
|
63
|
+
export declare function foldLongContextVariants(ids: readonly string[]): Array<{
|
|
64
|
+
base: string;
|
|
65
|
+
has1m: boolean;
|
|
66
|
+
}>;
|
|
47
67
|
/**
|
|
48
68
|
* Refresh the Status tab's data — probe /health, load config file
|
|
49
69
|
* metadata. Exported separately so the parent can re-invoke on key
|
package/dist/tui/tabs/status.js
CHANGED
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
* │ schema: v1 │
|
|
19
19
|
* │ …per-knob effective values (read-only) │
|
|
20
20
|
* └─────────────────────────────────────────────────┘
|
|
21
|
+
* ┌─ Models ────────────────────────────────────────┐
|
|
22
|
+
* │ claude-fable-5 +[1m] │
|
|
23
|
+
* │ claude-opus-4-8 +[1m] │
|
|
24
|
+
* │ claude-sonnet-5 +[1m] │
|
|
25
|
+
* │ …the advertised catalog, live from /v1/models │
|
|
26
|
+
* └─────────────────────────────────────────────────┘
|
|
21
27
|
*/
|
|
22
28
|
import { fg, dim, brand } from '../render.js';
|
|
23
29
|
import { renderKvRow } from '../layout.js';
|
|
@@ -30,6 +36,7 @@ export const StatusTab = {
|
|
|
30
36
|
loading: true,
|
|
31
37
|
health: null,
|
|
32
38
|
configSource: null,
|
|
39
|
+
models: null,
|
|
33
40
|
overageGuard: null,
|
|
34
41
|
resumePending: false,
|
|
35
42
|
resumeMessage: null,
|
|
@@ -112,6 +119,18 @@ export const StatusTab = {
|
|
|
112
119
|
: dim('not loaded');
|
|
113
120
|
lines.push(' ' + renderKvRow('Source', sourceLabel, w - 4));
|
|
114
121
|
lines.push('');
|
|
122
|
+
// ── Models section ─────────────────────────────────────────
|
|
123
|
+
// Live from the proxy's /v1/models (upstream-autodetected catalog,
|
|
124
|
+
// baked fallback) so newly-shipped families — Sonnet 5, Fable 5 —
|
|
125
|
+
// show up here without a TUI change. `[1m]` variants are folded
|
|
126
|
+
// onto their base id as a +[1m] marker instead of doubling the list.
|
|
127
|
+
if (state.models && state.models.length > 0) {
|
|
128
|
+
lines.push(' ' + brand('Models'));
|
|
129
|
+
for (const row of foldLongContextVariants(state.models)) {
|
|
130
|
+
lines.push(' ' + renderKvRow(row.base, row.has1m ? dim('+[1m]') : '', w - 4));
|
|
131
|
+
}
|
|
132
|
+
lines.push('');
|
|
133
|
+
}
|
|
115
134
|
// ── Overage-guard section (v4.1, dario#288) ────────────────
|
|
116
135
|
if (state.overageGuard) {
|
|
117
136
|
lines.push(' ' + brand('Overage-guard'));
|
|
@@ -144,6 +163,40 @@ export const StatusTab = {
|
|
|
144
163
|
return lines.join('\n');
|
|
145
164
|
},
|
|
146
165
|
};
|
|
166
|
+
/**
|
|
167
|
+
* Fold `<base>[1m]` variants onto their base id: the /v1/models listing
|
|
168
|
+
* advertises both forms for every long-context-capable family, and showing
|
|
169
|
+
* fourteen rows for seven models is noise. Preserves the catalog's order
|
|
170
|
+
* (family rank, version desc). A `[1m]`-only id with no base row (shouldn't
|
|
171
|
+
* happen — the generator always emits the pair) still gets its own row so
|
|
172
|
+
* nothing silently disappears. Exported for unit testing.
|
|
173
|
+
*/
|
|
174
|
+
export function foldLongContextVariants(ids) {
|
|
175
|
+
const bases = [];
|
|
176
|
+
const seen = new Map();
|
|
177
|
+
for (const id of ids) {
|
|
178
|
+
const m = id.match(/^(.*)\[1m\]$/);
|
|
179
|
+
if (m) {
|
|
180
|
+
const existing = seen.get(m[1]);
|
|
181
|
+
if (existing) {
|
|
182
|
+
existing.has1m = true;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
// [1m] before (or without) its base — record under the base id.
|
|
186
|
+
const row = { base: m[1], has1m: true };
|
|
187
|
+
seen.set(m[1], row);
|
|
188
|
+
bases.push(row);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const existing = seen.get(id);
|
|
192
|
+
if (existing)
|
|
193
|
+
continue;
|
|
194
|
+
const row = { base: id, has1m: false };
|
|
195
|
+
seen.set(id, row);
|
|
196
|
+
bases.push(row);
|
|
197
|
+
}
|
|
198
|
+
return bases;
|
|
199
|
+
}
|
|
147
200
|
function formatDuration(ms) {
|
|
148
201
|
if (ms <= 0)
|
|
149
202
|
return '0s';
|
|
@@ -175,13 +228,15 @@ export async function refreshStatus(ctx) {
|
|
|
175
228
|
catch (e) {
|
|
176
229
|
error = e.message;
|
|
177
230
|
}
|
|
178
|
-
// Overage-guard state — best-effort; never
|
|
179
|
-
//
|
|
231
|
+
// Overage-guard state + model catalog — best-effort; never throw
|
|
232
|
+
// (proxy-client wraps both GETs in try/catch and returns null).
|
|
180
233
|
const overageGuard = await ctx.client.getOverageGuard();
|
|
234
|
+
const models = await ctx.client.listModels();
|
|
181
235
|
return {
|
|
182
236
|
loading: false,
|
|
183
237
|
health,
|
|
184
238
|
configSource: fileResult.source,
|
|
239
|
+
models,
|
|
185
240
|
overageGuard,
|
|
186
241
|
resumePending: false,
|
|
187
242
|
resumeMessage: null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.142",
|
|
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": {
|