@askalf/dario 5.5.5 → 5.5.7
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 +9 -3
- package/dist/cc-template.js +14 -12
- package/dist/doctor.js +27 -1
- package/dist/live-fingerprint.d.ts +36 -0
- package/dist/live-fingerprint.js +41 -1
- package/dist/proxy.js +14 -3
- package/package.json +1 -1
package/dist/cc-template.d.ts
CHANGED
|
@@ -114,9 +114,15 @@ export declare const CC_SYSTEM_PROMPT_OPUS5: string;
|
|
|
114
114
|
*/
|
|
115
115
|
export declare const CC_SYSTEM_PROMPT_SONNET5: string;
|
|
116
116
|
/**
|
|
117
|
-
* The system prompt CC would send for `model`:
|
|
118
|
-
* variant, every other model gets the shared base. Keeps
|
|
119
|
-
* CC's per-model system prompt (dario#lock-step).
|
|
117
|
+
* The system prompt CC would send for `model`: a family in VARIANT_FAMILIES
|
|
118
|
+
* gets its captured variant, every other model gets the shared base. Keeps
|
|
119
|
+
* dario byte-aligned with CC's per-model system prompt (dario#lock-step).
|
|
120
|
+
*
|
|
121
|
+
* Selection iterates VARIANT_FAMILIES (live-fingerprint.ts) — the same table
|
|
122
|
+
* the bake captures from — so the two sides cannot drift apart. A family
|
|
123
|
+
* whose variant is absent from the loaded template falls back to the base;
|
|
124
|
+
* `dario doctor`'s "Prompt variants" row surfaces that state instead of
|
|
125
|
+
* letting it pass silently.
|
|
120
126
|
*/
|
|
121
127
|
export declare function systemPromptForModel(model?: string): string;
|
|
122
128
|
/** CC's agent identity string. */
|
package/dist/cc-template.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* live cache self-heals when Anthropic ships a new CC version — no user
|
|
8
8
|
* action required. See src/live-fingerprint.ts for the capture pipeline.
|
|
9
9
|
*/
|
|
10
|
-
import { loadTemplate, promptVariantsOf } from './live-fingerprint.js';
|
|
10
|
+
import { loadTemplate, promptVariantsOf, VARIANT_FAMILIES } from './live-fingerprint.js';
|
|
11
11
|
// Load template at module init — prefer live cache, fall back to bundled.
|
|
12
12
|
const TEMPLATE = loadTemplate({ silent: true });
|
|
13
13
|
/** The loaded template itself — source, version, capture age, all fields. Startup banners and drift checks read this directly. */
|
|
@@ -130,20 +130,22 @@ export const CC_SYSTEM_PROMPT_OPUS5 = _variants['opus-5'] ?? CC_SYSTEM_PROMPT;
|
|
|
130
130
|
*/
|
|
131
131
|
export const CC_SYSTEM_PROMPT_SONNET5 = _variants['sonnet-5'] ?? CC_SYSTEM_PROMPT;
|
|
132
132
|
/**
|
|
133
|
-
* The system prompt CC would send for `model`:
|
|
134
|
-
* variant, every other model gets the shared base. Keeps
|
|
135
|
-
* CC's per-model system prompt (dario#lock-step).
|
|
133
|
+
* The system prompt CC would send for `model`: a family in VARIANT_FAMILIES
|
|
134
|
+
* gets its captured variant, every other model gets the shared base. Keeps
|
|
135
|
+
* dario byte-aligned with CC's per-model system prompt (dario#lock-step).
|
|
136
|
+
*
|
|
137
|
+
* Selection iterates VARIANT_FAMILIES (live-fingerprint.ts) — the same table
|
|
138
|
+
* the bake captures from — so the two sides cannot drift apart. A family
|
|
139
|
+
* whose variant is absent from the loaded template falls back to the base;
|
|
140
|
+
* `dario doctor`'s "Prompt variants" row surfaces that state instead of
|
|
141
|
+
* letting it pass silently.
|
|
136
142
|
*/
|
|
137
143
|
export function systemPromptForModel(model) {
|
|
138
144
|
const m = (model ?? '').toLowerCase();
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (/opus-5(?!\d)/.test(m))
|
|
144
|
-
return CC_SYSTEM_PROMPT_OPUS5;
|
|
145
|
-
if (/sonnet-5(?!\d)/.test(m))
|
|
146
|
-
return CC_SYSTEM_PROMPT_SONNET5;
|
|
145
|
+
for (const f of VARIANT_FAMILIES) {
|
|
146
|
+
if (f.matches(m))
|
|
147
|
+
return _variants[f.key] ?? CC_SYSTEM_PROMPT;
|
|
148
|
+
}
|
|
147
149
|
return CC_SYSTEM_PROMPT;
|
|
148
150
|
}
|
|
149
151
|
/** CC's agent identity string. */
|
package/dist/doctor.js
CHANGED
|
@@ -17,7 +17,7 @@ import { homedir, platform, arch, release } from 'node:os';
|
|
|
17
17
|
import { execFileSync } from 'node:child_process';
|
|
18
18
|
import { createServer } from 'node:http';
|
|
19
19
|
import { CC_TEMPLATE, resolveSystemPrompt, } from './cc-template.js';
|
|
20
|
-
import { describeTemplate, detectDrift, checkCCCompat, findInstalledCC, SUPPORTED_CC_RANGE, CURRENT_SCHEMA_VERSION, compareVersions, } from './live-fingerprint.js';
|
|
20
|
+
import { describeTemplate, detectDrift, checkCCCompat, findInstalledCC, missingVariantFamilies, SUPPORTED_CC_RANGE, CURRENT_SCHEMA_VERSION, compareVersions, VARIANT_FAMILIES, } from './live-fingerprint.js';
|
|
21
21
|
import { detectCCOAuthConfig } from './cc-oauth-detect.js';
|
|
22
22
|
import { runAuthorizeProbe } from './cc-authorize-probe.js';
|
|
23
23
|
import { MIGRATED_LOGIN_ALIAS } from './accounts.js';
|
|
@@ -352,6 +352,32 @@ export async function runChecks(opts = {}) {
|
|
|
352
352
|
catch (err) {
|
|
353
353
|
checks.push({ status: 'fail', label: 'Template', detail: `load failed: ${err.message}` });
|
|
354
354
|
}
|
|
355
|
+
// ---- Per-model prompt variants (dario#lock-step)
|
|
356
|
+
// CC ships several model families a different system prompt than the shared
|
|
357
|
+
// base. A template missing a family's variant silently serves that family
|
|
358
|
+
// the base prompt — a wire-fidelity degradation with no other symptom
|
|
359
|
+
// (requests still 200). Known causes: a bundle baked while variant capture
|
|
360
|
+
// failed, or a pre-variants live cache shadowing the bundle.
|
|
361
|
+
try {
|
|
362
|
+
const missing = missingVariantFamilies(CC_TEMPLATE);
|
|
363
|
+
if (missing.length === 0) {
|
|
364
|
+
checks.push({
|
|
365
|
+
status: 'ok',
|
|
366
|
+
label: 'Prompt variants',
|
|
367
|
+
detail: `all ${VARIANT_FAMILIES.length} model families carried (${VARIANT_FAMILIES.map((f) => f.key).join(', ')})`,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
checks.push({
|
|
372
|
+
status: 'warn',
|
|
373
|
+
label: 'Prompt variants',
|
|
374
|
+
detail: `missing: ${missing.join(', ')} — those models get the shared base prompt, not CC's model-specific one. Re-bake the template, or remove a pre-variants live cache (~/.dario/cc-template.live.json) and restart.`,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
catch (err) {
|
|
379
|
+
checks.push({ status: 'warn', label: 'Prompt variants', detail: `check failed: ${err.message}` });
|
|
380
|
+
}
|
|
355
381
|
// ---- Per-request overhead surfacing.
|
|
356
382
|
// The CC system prompt + tool definitions are injected into every
|
|
357
383
|
// non-passthrough request and dominate the input-token cost on small
|
|
@@ -181,6 +181,42 @@ export interface TemplateData {
|
|
|
181
181
|
* paths cannot drift apart.
|
|
182
182
|
*/
|
|
183
183
|
export declare const TEMPLATE_BASE_MODEL = "claude-opus-4-8";
|
|
184
|
+
/**
|
|
185
|
+
* One model family CC ships a distinct system prompt to (dario#lock-step).
|
|
186
|
+
*/
|
|
187
|
+
export interface VariantFamily {
|
|
188
|
+
/** Key into `system_prompt_variants`. */
|
|
189
|
+
key: string;
|
|
190
|
+
/** Model id the bake pins (via ANTHROPIC_MODEL) to capture this family. */
|
|
191
|
+
captureModel: string;
|
|
192
|
+
/** True when a lowercased model id belongs to this family. */
|
|
193
|
+
matches: (model: string) => boolean;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* The model families CC ships a DIFFERENT system prompt than the shared
|
|
197
|
+
* base, in matcher-precedence order (first match wins — fable stays ahead
|
|
198
|
+
* of the `-5` arms so a hypothetical fable-5 never falls into them).
|
|
199
|
+
*
|
|
200
|
+
* This table is the single source of truth for dario#lock-step: the
|
|
201
|
+
* runtime selection (cc-template.ts:systemPromptForModel), the bake's
|
|
202
|
+
* capture loop (scripts/capture-and-bake.mjs), the doctor's coverage row,
|
|
203
|
+
* and the template invariants all derive from it — the same reason
|
|
204
|
+
* TEMPLATE_BASE_MODEL lives here. Before this table, the bake's model
|
|
205
|
+
* list and the selection arms were maintained by hand in two files, the
|
|
206
|
+
* exact divergence class that shipped tool_names ≠ tools twice.
|
|
207
|
+
*
|
|
208
|
+
* Adding a family here is safe even if it turns out to share the base
|
|
209
|
+
* prompt: the bake stores a variant only when the capture differs.
|
|
210
|
+
*/
|
|
211
|
+
export declare const VARIANT_FAMILIES: readonly VariantFamily[];
|
|
212
|
+
/**
|
|
213
|
+
* Families from VARIANT_FAMILIES that `t` carries no variant for — i.e.
|
|
214
|
+
* models that would silently get the shared BASE prompt instead of CC's
|
|
215
|
+
* model-specific one. Non-empty on a healthy current bundle means the
|
|
216
|
+
* lock-step is degraded: a bad bake, an unreadable bundle behind a live
|
|
217
|
+
* capture, or a pre-variants live cache shadowing the bundle.
|
|
218
|
+
*/
|
|
219
|
+
export declare function missingVariantFamilies(t: TemplateData): string[];
|
|
184
220
|
/**
|
|
185
221
|
* A template's prompt variants, with the legacy `system_prompt_fable` slot
|
|
186
222
|
* folded in under the `fable` key. Callers should always go through this
|
package/dist/live-fingerprint.js
CHANGED
|
@@ -109,6 +109,41 @@ export const CURRENT_SCHEMA_VERSION = 3;
|
|
|
109
109
|
* paths cannot drift apart.
|
|
110
110
|
*/
|
|
111
111
|
export const TEMPLATE_BASE_MODEL = 'claude-opus-4-8';
|
|
112
|
+
/**
|
|
113
|
+
* The model families CC ships a DIFFERENT system prompt than the shared
|
|
114
|
+
* base, in matcher-precedence order (first match wins — fable stays ahead
|
|
115
|
+
* of the `-5` arms so a hypothetical fable-5 never falls into them).
|
|
116
|
+
*
|
|
117
|
+
* This table is the single source of truth for dario#lock-step: the
|
|
118
|
+
* runtime selection (cc-template.ts:systemPromptForModel), the bake's
|
|
119
|
+
* capture loop (scripts/capture-and-bake.mjs), the doctor's coverage row,
|
|
120
|
+
* and the template invariants all derive from it — the same reason
|
|
121
|
+
* TEMPLATE_BASE_MODEL lives here. Before this table, the bake's model
|
|
122
|
+
* list and the selection arms were maintained by hand in two files, the
|
|
123
|
+
* exact divergence class that shipped tool_names ≠ tools twice.
|
|
124
|
+
*
|
|
125
|
+
* Adding a family here is safe even if it turns out to share the base
|
|
126
|
+
* prompt: the bake stores a variant only when the capture differs.
|
|
127
|
+
*/
|
|
128
|
+
export const VARIANT_FAMILIES = [
|
|
129
|
+
{ key: 'fable', captureModel: 'claude-fable-5', matches: (m) => m.includes('fable') },
|
|
130
|
+
// `-5` bounded so a future opus-50 doesn't match, and so the `[1m]` tag
|
|
131
|
+
// (which is not a digit) still does.
|
|
132
|
+
{ key: 'opus-5', captureModel: 'claude-opus-5', matches: (m) => /opus-5(?!\d)/.test(m) },
|
|
133
|
+
{ key: 'sonnet-5', captureModel: 'claude-sonnet-5', matches: (m) => /sonnet-5(?!\d)/.test(m) },
|
|
134
|
+
];
|
|
135
|
+
/**
|
|
136
|
+
* Families from VARIANT_FAMILIES that `t` carries no variant for — i.e.
|
|
137
|
+
* models that would silently get the shared BASE prompt instead of CC's
|
|
138
|
+
* model-specific one. Non-empty on a healthy current bundle means the
|
|
139
|
+
* lock-step is degraded: a bad bake, an unreadable bundle behind a live
|
|
140
|
+
* capture, or a pre-variants live cache shadowing the bundle.
|
|
141
|
+
*/
|
|
142
|
+
export function missingVariantFamilies(t) {
|
|
143
|
+
const have = promptVariantsOf(t);
|
|
144
|
+
return VARIANT_FAMILIES.filter((f) => !(typeof have[f.key] === 'string' && have[f.key].length > 0))
|
|
145
|
+
.map((f) => f.key);
|
|
146
|
+
}
|
|
112
147
|
/**
|
|
113
148
|
* A template's prompt variants, with the legacy `system_prompt_fable` slot
|
|
114
149
|
* folded in under the `fable` key. Callers should always go through this
|
|
@@ -913,7 +948,12 @@ export function formatCaptureAge(capturedIso, now = Date.now()) {
|
|
|
913
948
|
export function describeTemplate(t) {
|
|
914
949
|
const source = t._source ?? 'bundled';
|
|
915
950
|
const age = formatCaptureAge(t._captured);
|
|
916
|
-
|
|
951
|
+
// Variant coverage is part of the template's identity: a template that
|
|
952
|
+
// lost its per-model variants serves every family the base prompt, and
|
|
953
|
+
// that degradation is otherwise invisible (dario#lock-step).
|
|
954
|
+
const keys = Object.keys(promptVariantsOf(t)).sort();
|
|
955
|
+
const variants = keys.length > 0 ? keys.join('+') : 'none';
|
|
956
|
+
return `${source} capture, CC v${t._version} (${age} old), variants: ${variants}`;
|
|
917
957
|
}
|
|
918
958
|
/**
|
|
919
959
|
* Compare the loaded template's captured CC version against the version
|
package/dist/proxy.js
CHANGED
|
@@ -615,9 +615,20 @@ const ORCHESTRATION_PATTERNS_DEFAULT = buildOrchestrationPatterns();
|
|
|
615
615
|
/** Strip orchestration wrapper tags from message content. */
|
|
616
616
|
function sanitizeContent(text, patterns) {
|
|
617
617
|
let result = text;
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
618
|
+
// Fast path: every pattern in buildOrchestrationPatterns is anchored on a
|
|
619
|
+
// literal `<`, so a body with no `<` cannot match any of them — skip the
|
|
620
|
+
// ~28 full-string regex passes. sanitizeMessages runs on EVERY request,
|
|
621
|
+
// including byte-faithful CC traffic, and most message blocks (prose user
|
|
622
|
+
// turns, command/tool output) carry no tag; on a realistic mix this drops
|
|
623
|
+
// ~80% of the scrub's CPU while producing byte-identical output (the loop
|
|
624
|
+
// is skipped only when it provably cannot change the string). The trailing
|
|
625
|
+
// whitespace normalization still runs so no-tag blocks are treated exactly
|
|
626
|
+
// as before.
|
|
627
|
+
if (result.indexOf('<') !== -1) {
|
|
628
|
+
for (const pattern of patterns) {
|
|
629
|
+
pattern.lastIndex = 0;
|
|
630
|
+
result = result.replace(pattern, '');
|
|
631
|
+
}
|
|
621
632
|
}
|
|
622
633
|
return result.replace(/\n{3,}/g, '\n\n').trim();
|
|
623
634
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.7",
|
|
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": {
|