@bglocation/tune-context 2.4.0 → 3.0.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +195 -0
- package/README.md +211 -18
- package/bin/tune-context +1 -1
- package/bin/tune-context.mjs +167 -51
- package/cli/archive.mjs +322 -0
- package/cli/entry-point.mjs +73 -0
- package/cli/experiment.mjs +35 -3
- package/cli/version.mjs +118 -0
- package/eval/adoption-report.mjs +11 -5
- package/eval/analyze.mjs +792 -0
- package/eval/arm.mjs +9 -5
- package/eval/pricing.mjs +32 -1
- package/eval/prompt-metrics.mjs +395 -46
- package/eval/report.mjs +881 -0
- package/eval/verdict.mjs +963 -0
- package/hooks/adoption-log.mjs +1 -1
- package/hooks/context-reminder.mjs +1 -1
- package/hooks/pre-compact-snapshot.mjs +4 -4
- package/hooks/session-start-reinject.mjs +1 -4
- package/package.json +7 -2
- package/skills/token-efficiency/SKILL.md +1 -1
- package/skills/tune-context/SKILL.md +4 -2
package/eval/arm.mjs
CHANGED
|
@@ -96,13 +96,17 @@ export function ledgerArmAt(entries, tsIso) {
|
|
|
96
96
|
* The row's timestamp: when the prompt was submitted, or the first **readable**
|
|
97
97
|
* one of the remaining fields.
|
|
98
98
|
*
|
|
99
|
-
* One definition for
|
|
100
|
-
*
|
|
99
|
+
* One definition for every reader — the ledger window, `pass_order`, and the
|
|
100
|
+
* natural-work attribution in analyze.mjs (TASK-089), which asks the same ledger
|
|
101
|
+
* the same question about a row that is NOT on an `exp/` branch. Exported for
|
|
102
|
+
* that reason: a second "when did this row happen" would be a second answer.
|
|
103
|
+
*
|
|
104
|
+
* Two of these readers already drifted apart once: `??` only falls through on null, so it
|
|
101
105
|
* stopped at a `ts_submit` that was a string but unparseable — and a row the
|
|
102
106
|
* ledger DID cover came out as `conflict:no-ledger-entry`, i.e. a run to be
|
|
103
107
|
* repeated (§7) because of a cosmetic defect in the data.
|
|
104
108
|
*/
|
|
105
|
-
function
|
|
109
|
+
export function rowTimestamp(row) {
|
|
106
110
|
for (const value of [row.ts_submit, row.ts_first_assistant, row.ts_end]) {
|
|
107
111
|
if (msOf(value) !== null) return value;
|
|
108
112
|
}
|
|
@@ -110,7 +114,7 @@ function rowTs(row) {
|
|
|
110
114
|
}
|
|
111
115
|
|
|
112
116
|
function rowMs(row) {
|
|
113
|
-
return msOf(
|
|
117
|
+
return msOf(rowTimestamp(row));
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
function armFields(row, { ledger, ledgerAvailable }) {
|
|
@@ -133,7 +137,7 @@ function armFields(row, { ledger, ledgerAvailable }) {
|
|
|
133
137
|
return { exp_task: parsed.task, exp_arm: parsed.arm, exp_arm_source: 'branch', exp_ledger_arm: '' };
|
|
134
138
|
}
|
|
135
139
|
|
|
136
|
-
const fromLedger = ledgerArmAt(ledger,
|
|
140
|
+
const fromLedger = ledgerArmAt(ledger, rowTimestamp(row));
|
|
137
141
|
if (fromLedger === null) {
|
|
138
142
|
return { exp_task: parsed.task, exp_arm: '', exp_arm_source: 'conflict:no-ledger-entry', exp_ledger_arm: '' };
|
|
139
143
|
}
|
package/eval/pricing.mjs
CHANGED
|
@@ -115,7 +115,29 @@ export const GEO_MULTIPLIERS = { global: 1, not_available: 1, us: 1.1 };
|
|
|
115
115
|
/** $10 per 1,000 searches. Web FETCH is free — only search is billed. */
|
|
116
116
|
export const WEB_SEARCH_USD = 0.01;
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
/**
|
|
119
|
+
* The five priced classes, paired with the field each one is read from on a
|
|
120
|
+
* prompt-metrics row. Two vocabularies for one fact — `input`/`output` are cost
|
|
121
|
+
* classes, `input_tokens`/`output_tokens` are row fields — and this is the one
|
|
122
|
+
* place that knows the translation, because costOfTokens() below is already its
|
|
123
|
+
* other reader. Anything that folds tokens up (eval/analyze.mjs) reads it from
|
|
124
|
+
* here rather than retyping the list: a sixth class added to the collector's
|
|
125
|
+
* emptyTokens() must not be able to fall out of a downstream total by being
|
|
126
|
+
* forgotten in a hand-written array.
|
|
127
|
+
*
|
|
128
|
+
* `cache_write_unsplit` is deliberately NOT here. It is not a priced class — it
|
|
129
|
+
* is the admission that a write's TTL is unknown, and a row carrying it is
|
|
130
|
+
* refused rather than priced.
|
|
131
|
+
*/
|
|
132
|
+
export const TOKEN_CLASS_FIELDS = [
|
|
133
|
+
['input', 'input_tokens'],
|
|
134
|
+
['cache_read', 'cache_read'],
|
|
135
|
+
['cache_write_5m', 'cache_write_5m'],
|
|
136
|
+
['cache_write_1h', 'cache_write_1h'],
|
|
137
|
+
['output', 'output_tokens'],
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
const TOKEN_CLASSES = TOKEN_CLASS_FIELDS.map(([className]) => className);
|
|
119
141
|
|
|
120
142
|
function emptyCost() {
|
|
121
143
|
return Object.fromEntries(TOKEN_CLASSES.map((c) => [c, 0]));
|
|
@@ -371,6 +393,15 @@ function usd(n) {
|
|
|
371
393
|
return `$${n.toFixed(4)}`;
|
|
372
394
|
}
|
|
373
395
|
|
|
396
|
+
/**
|
|
397
|
+
* An amount for human eyes, including the case where there is none. An
|
|
398
|
+
* uncomputable total prints as the word, never as `$0.0000` — the whole file
|
|
399
|
+
* exists to stop an unknown cost reading as a cheap one.
|
|
400
|
+
*/
|
|
401
|
+
export function formatUsd(n) {
|
|
402
|
+
return Number.isFinite(n) ? usd(n) : 'unknown (NOT $0)';
|
|
403
|
+
}
|
|
404
|
+
|
|
374
405
|
function count(n) {
|
|
375
406
|
return n.toLocaleString('en-US');
|
|
376
407
|
}
|