@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/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 both readers (the ledger window and `pass_order`), because
100
- * two of them already drifted apart once: `??` only falls through on null, so it
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 rowTs(row) {
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(rowTs(row));
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, rowTs(row));
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
- const TOKEN_CLASSES = ['input', 'cache_read', 'cache_write_5m', 'cache_write_1h', 'output'];
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
  }