@vincemakes/kiso-runtime 0.1.37 → 0.2.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.
@@ -0,0 +1,152 @@
1
+ /**
2
+ * E2 (1.3.0) — Canonical Usage: the reconciled usage schema (proposal §1
3
+ * as ruled 2026-08-13; R1a-R5 all adopted).
4
+ *
5
+ * THE PINNED SENTENCE (R1a): one canonical meaning for `input`, everywhere
6
+ * in kiso, forever: `input` is FRESH-ONLY — the tokens NOT served from
7
+ * cache. `total = input + cacheRead + cacheWrite` is the derived quantity,
8
+ * never a reported one. A cache ratio is always `cacheRead / total` — the
9
+ * numerator can never exceed the denominator. The >100% disease is
10
+ * structurally impossible under the canonical schema.
11
+ *
12
+ * The mapping keys on the ROUTE, not the provider (R2a): DeepSeek serves
13
+ * both routes and reports input fresh-only on one (anthropic-compat) and
14
+ * TOTAL on the other (openai-compat) — the SAME canonical meaning falls
15
+ * out of the route key (the dual-endpoint closure). The route string is
16
+ * the config adapter identity the guard already holds (`"anthropic" |
17
+ * "openai-compat"`).
18
+ *
19
+ * Cost comes from the versioned pricing table — every cost carries the
20
+ * table version it was computed with (R1c). The built-in v1 table prices
21
+ * both routes at DeepSeek's published rates; the caveat sentence from the
22
+ * bench README carries forward verbatim ("an approximation, not a bill").
23
+ * The commercial table is the product's Phase 10 (the table is injectable;
24
+ * the version travels with every cost).
25
+ *
26
+ * The frozen usage union stays provider-raw — this module derives at the
27
+ * accounting boundary (R4 Case B, pure derivation; the union does not
28
+ * move). Raw is provider observation; canonical is the accounting truth.
29
+ */
30
+ /** The route → input-convention table (R2a). `input` semantics differ
31
+ * between the two routes; the convention is a property of the ROUTE, not
32
+ * the provider. Unknown routes fall back to "total" — exactly the
33
+ * incumbent guard behavior (the guard's else-branch: non-anthropic =
34
+ * total), preserved by construction. */
35
+ export const INPUT_CONVENTIONS = {
36
+ anthropic: "fresh", // input_tokens excludes the cached prefix
37
+ "openai-compat": "total", // prompt_tokens includes the cached prefix
38
+ };
39
+ /** Pricing table v1. Freeze date 2026-08-13 (the E2 ruling). Rates:
40
+ * DeepSeek's published rates (https://api-docs.deepseek.com/quick_start/pricing),
41
+ * the 0.1 cache-hit ratio the bench has used since the 0.1.23 round. The
42
+ * caveat sentence carries forward verbatim (bench README): "an
43
+ * approximation, not a bill." */
44
+ export const PRICING_TABLE_V1 = {
45
+ id: "builtin",
46
+ version: 1,
47
+ entries: {
48
+ anthropic: { inputPerM: 0.27, outputPerM: 1.1, cacheReadPerM: 0.027, cacheWritePerM: 0 },
49
+ "openai-compat": { inputPerM: 0.27, outputPerM: 1.1, cacheReadPerM: 0.027, cacheWritePerM: 0 },
50
+ },
51
+ };
52
+ export const PRICING_TABLES = {
53
+ 1: PRICING_TABLE_V1,
54
+ };
55
+ /** The table pinned for a version; throws when none is pinned (a cost
56
+ * recorded against an unpinned version is a ledger corruption). */
57
+ export function pricingTableFor(version) {
58
+ const table = PRICING_TABLES[version];
59
+ if (table === undefined)
60
+ throw new Error(`no pricing table pinned for version ${version}`);
61
+ return table;
62
+ }
63
+ export function priceFor(route, u, table) {
64
+ // The R5b-④c semantics: a REAL route (an INPUT_CONVENTIONS key — the
65
+ // routes the table is expected to price) missing from the table is a
66
+ // HOLE → null, the explicit-absent stamp. The builtin table never
67
+ // backfills an injected table's hole. Unknown routes keep the legacy
68
+ // within-table mirror fallback (the total-convention entry, matching
69
+ // the convention fallback above — one table, one fallback, no drift);
70
+ // a table without even the mirror entry yields null, never a crash.
71
+ const entry = table.entries[route] ??
72
+ (route in INPUT_CONVENTIONS ? undefined : table.entries["openai-compat"]);
73
+ if (entry === undefined)
74
+ return null;
75
+ return ((u.input * entry.inputPerM +
76
+ u.output * entry.outputPerM +
77
+ u.cacheRead * entry.cacheReadPerM +
78
+ (u.cacheWrite ?? 0) * entry.cacheWritePerM) /
79
+ 1e6);
80
+ }
81
+ /** Raw → canonical (the accounting boundary). Behavior-preserving against
82
+ * the guard's incumbent per-provider branch (guard.ts settle): anthropic
83
+ * input is fresh as-is; every other route subtracts cacheRead.
84
+ *
85
+ * The trailing `table` parameter is the injection slot (R5b-④a): the
86
+ * R5a-1-commercial table rides it on day one, defaulting to the pinned
87
+ * builtin v1 table so the export's default behavior is the pinned one
88
+ * and a future injection never widens this frozen signature. */
89
+ export function canonicalizeUsage(route, raw, table = PRICING_TABLE_V1) {
90
+ const convention = INPUT_CONVENTIONS[route] ?? "total";
91
+ const input = raw.inputTokens === null
92
+ ? 0
93
+ : convention === "fresh"
94
+ ? raw.inputTokens
95
+ : Math.max(0, raw.inputTokens - (raw.cacheRead ?? 0));
96
+ const cacheRead = raw.cacheRead ?? 0;
97
+ const cacheWrite = raw.cacheWrite ?? null;
98
+ const output = raw.outputTokens ?? 0;
99
+ return {
100
+ input,
101
+ output,
102
+ cacheRead,
103
+ cacheWrite,
104
+ reasoning: null, // reserved — no provider reports a split today
105
+ costUsd: priceFor(route, { input, output, cacheRead, cacheWrite }, table),
106
+ pricingTableId: table.id,
107
+ pricingTableVersion: table.version,
108
+ };
109
+ }
110
+ // ── The validator ──────────────────────────────────────────────────────────
111
+ // Strict by design: closed keys (a misspelled field can never enter a
112
+ // ledger), non-negative numbers, the pinned sentence machine-checked, and
113
+ // a pinned table version. Cost CONSISTENCY (costUsd recomputed from the
114
+ // components × the version's table) needs the ROUTE — it lives in the
115
+ // trace record; the trace-level validator cross-checks it there (T3).
116
+ const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
117
+ const CANONICAL_FIELDS = ["input", "output", "cacheRead", "cacheWrite", "reasoning", "costUsd", "pricingTableId", "pricingTableVersion"];
118
+ const isNonNegNum = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
119
+ /** The canonical schema's invariants, machine-checked: closed key set;
120
+ * non-negative numbers; cacheWrite/reasoning null-or-number; the pinned
121
+ * sentence — cacheRead can never exceed total (= input + cacheRead +
122
+ * cacheWrite) — structurally true for non-negatives but pinned against
123
+ * future edits; costUsd null-or-number (R5b-④c — null is the injected
124
+ * table's absent stamp); the (pricingTableId, pricingTableVersion)
125
+ * tuple, with the registry pin scoped to the builtin id (R5b-④b) — an
126
+ * injected table's version is the injector's accounting, the ledger
127
+ * cannot know tables it does not carry. */
128
+ export function validateCanonicalUsage(v) {
129
+ if (!isRecord(v))
130
+ return false;
131
+ const keys = Object.keys(v);
132
+ if (keys.length !== CANONICAL_FIELDS.length || keys.some((k) => !CANONICAL_FIELDS.includes(k)))
133
+ return false;
134
+ if (!isNonNegNum(v.input) || !isNonNegNum(v.output) || !isNonNegNum(v.cacheRead))
135
+ return false;
136
+ if (v.cacheWrite !== null && !isNonNegNum(v.cacheWrite))
137
+ return false;
138
+ if (v.reasoning !== null && !isNonNegNum(v.reasoning))
139
+ return false;
140
+ if (v.costUsd !== null && !isNonNegNum(v.costUsd))
141
+ return false;
142
+ if (typeof v.pricingTableId !== "string" || v.pricingTableId.length === 0)
143
+ return false;
144
+ if (typeof v.pricingTableVersion !== "number" || !Number.isInteger(v.pricingTableVersion) || v.pricingTableVersion <= 0)
145
+ return false;
146
+ if (v.pricingTableId === PRICING_TABLE_V1.id && !(v.pricingTableVersion in PRICING_TABLES))
147
+ return false;
148
+ const total = v.input + v.cacheRead + (v.cacheWrite ?? 0);
149
+ if (v.cacheRead > total)
150
+ return false; // the pinned sentence
151
+ return true;
152
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-runtime",
3
- "version": "0.1.37",
3
+ "version": "0.2.0",
4
4
  "description": "kiso runtime — durable multi-turn agent sessions: AgentDefinition, AgentRuntime, AgentSession, Run, append-only JSONL store.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -8,6 +8,10 @@
8
8
  ".": {
9
9
  "types": "./dist/index.d.ts",
10
10
  "default": "./dist/index.js"
11
+ },
12
+ "./internal": {
13
+ "types": "./dist/internal.d.ts",
14
+ "default": "./dist/internal.js"
11
15
  }
12
16
  },
13
17
  "files": [
@@ -21,11 +25,11 @@
21
25
  "test": "vitest run"
22
26
  },
23
27
  "dependencies": {
24
- "@vincemakes/kiso-core": "0.1.35"
28
+ "@vincemakes/kiso-core": "0.2.0"
25
29
  },
26
30
  "peerDependencies": {
27
- "@vincemakes/kiso-provider-anthropic": "0.1.36",
28
- "@vincemakes/kiso-provider-openai": "0.1.36"
31
+ "@vincemakes/kiso-provider-anthropic": "0.2.0",
32
+ "@vincemakes/kiso-provider-openai": "0.2.0"
29
33
  },
30
34
  "peerDependenciesMeta": {
31
35
  "@vincemakes/kiso-provider-anthropic": {
@@ -36,7 +40,7 @@
36
40
  }
37
41
  },
38
42
  "devDependencies": {
39
- "@vincemakes/kiso-evals": "0.1.36",
43
+ "@vincemakes/kiso-evals": "0.2.0",
40
44
  "@types/node": "^26.1.2",
41
45
  "typescript": "^5.7.2",
42
46
  "vitest": "^3.0.0"