auto-model-router 0.22.0 → 0.23.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.
@@ -7,14 +7,14 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "auto-model-router: a local cost/complexity-aware model router for Oh My Pi, backed by OpenRouter",
10
- "version": "0.22.0",
10
+ "version": "0.23.0",
11
11
  "pluginRoot": "."
12
12
  },
13
13
  "plugins": [
14
14
  {
15
15
  "name": "auto-model-router",
16
16
  "description": "Local cost/complexity-aware model router for Oh My Pi, backed by OpenRouter. Runs in-process, routes per turn by price and task complexity, with budget caps, mid-stream escalation, and cache-aware hysteresis.",
17
- "version": "0.22.0",
17
+ "version": "0.23.0",
18
18
  "author": {
19
19
  "name": "drewappling",
20
20
  "email": "drewappling@gmail.com"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auto-model-router",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "private": false,
5
5
  "description": "Local cost/complexity-aware model router for Oh My Pi, backed by OpenRouter",
6
6
  "type": "module",
@@ -20,6 +20,7 @@ import { computeBlendedRate } from "./blended.ts";
20
20
  import { computeCost } from "./forecast.ts";
21
21
  import type {
22
22
  BlendedRate,
23
+ CostBreakdown,
23
24
  EscalationCost,
24
25
  Ledger,
25
26
  LedgerEntry,
@@ -283,6 +284,9 @@ export function toEntry(row: LedgerRow): LedgerEntry {
283
284
  // Likewise a row from before v19, or a turn with redaction off: absent,
284
285
  // which is a different fact from 0 (the rules ran and matched nothing).
285
286
  ...(row.redactions === null || row.redactions === undefined ? {} : { redactions: row.redactions }),
287
+ // A row recorded before pricing, or one whose model could not be priced,
288
+ // stores NULL; absent is the front door's cue to fall back to the blend.
289
+ ...(row.cost_breakdown === null || row.cost_breakdown === undefined ? {} : { costBreakdown: JSON.parse(row.cost_breakdown) as CostBreakdown }),
286
290
  };
287
291
  }
288
292
 
package/src/cost/types.ts CHANGED
@@ -167,6 +167,13 @@ export interface LedgerEntry {
167
167
  * provider (Ollama) exists only in memory, so the orchestrator hands it over.
168
168
  */
169
169
  priceModel?: CatalogModel;
170
+ /**
171
+ * The cost component split the router computed when it recorded this row,
172
+ * from its own catalog prices. Absent when the row predates pricing, or
173
+ * when the model could not be priced (NULL in the ledger) — a front door
174
+ * shows input/output/cache costs from this rather than re-deriving them.
175
+ */
176
+ costBreakdown?: CostBreakdown;
170
177
  }
171
178
 
172
179
  /**
@@ -215,4 +215,20 @@ describe("decision entries", () => {
215
215
  expect(bob.find((e) => e.id === "l3")?.error).toBe("boom");
216
216
  expect(bob.find((e) => e.id === "l3")?.feedback[0]?.note).toBe("looped");
217
217
  });
218
+
219
+ test("the recorded cost split rides along; unpriced rows leave it absent", () => {
220
+ const { decisionEntries } = require("../src/cost/views.ts") as typeof import("../src/cost/views.ts");
221
+ // The fixture records before any catalog fetch, so every row stored NULL;
222
+ // one priced row stands in for a turn the router could price at record time.
223
+ db.run("UPDATE ledger SET cost_breakdown = ? WHERE id = 'l1'", [
224
+ JSON.stringify({ freshPrompt: 0.006, cacheRead: 0.004, cacheWrite: 0, completion: 0.002, reasoning: 0, images: 0, request: 0, total: 0.006, tierAtPromptTokens: 0 }),
225
+ ]);
226
+ const entries = decisionEntries(db, { sinceMs: since, harness: null });
227
+ const priced = entries.find((e) => e.id === "l1");
228
+ expect(priced?.costBreakdown?.total).toBeCloseTo(0.006, 6);
229
+ expect(priced?.costBreakdown?.cacheRead).toBeCloseTo(0.004, 6);
230
+ // A row the ledger could not price (all of them here, NULL column) has no
231
+ // breakdown at all — the front door's cue to fall back to the blend.
232
+ expect(entries.find((e) => e.id === "l2")?.costBreakdown).toBeUndefined();
233
+ });
218
234
  });