ai-lcr 0.1.0 → 0.2.1

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/README.md CHANGED
@@ -108,6 +108,48 @@ The same pattern works for any vendor's native SDK provider — `@ai-sdk/anthrop
108
108
  <img src="assets/ai-lcr-routing.svg" alt="routing diagram: cheapest first, fallback on failure, recover after idle" width="820">
109
109
  </p>
110
110
 
111
+ ## See what happened (`onCall`)
112
+
113
+ `onError`/`onCost` fire separately and uncorrelated, so a failover is hard to read after the fact. `onCall` gives you **one record per request** — the full chain, the winner, the reason for each failed hop, latency, and cost — and `formatCallRecord` turns it into a one-liner you can scan:
114
+
115
+ ```ts
116
+ import { createLCR, formatCallRecord } from "ai-lcr";
117
+
118
+ const lcr = createLCR({
119
+ models: { /* … */ },
120
+ onCall: (record) => console.log(formatCallRecord(record)),
121
+ });
122
+ ```
123
+
124
+ ```text
125
+ ✓ text tokenmart 412ms $0.0003
126
+ ⚠ text tokenmart→openrouter 910ms $0.0004 ⤷ tokenmart 502
127
+ ✗ text deepseek→tokenmart→openrouter 1240ms FAILED ⤷ deepseek 401, tokenmart 502, openrouter 429
128
+ ```
129
+
130
+ `✓` served on the first try · `⚠` failed over but recovered · `✗` every provider failed. The `⤷` shows which provider died and why.
131
+
132
+ **Persist it anywhere — zero lock-in.** `record` is a plain `CallRecord` object. Log the JSON and point any log drain at it (Axiom, Datadog, your own DB); ai-lcr never decides where it goes:
133
+
134
+ ```ts
135
+ onCall: (record) => console.log(JSON.stringify(record)),
136
+ ```
137
+
138
+ ```ts
139
+ interface CallRecord {
140
+ id: string; // correlation id, one per request
141
+ model: string; // logical model name
142
+ attempts: { provider: string; ok: boolean; latencyMs: number; errorClass?: string }[];
143
+ winner?: string; // provider that served; undefined if all failed
144
+ ok: boolean;
145
+ failedOver: boolean; // more than one provider was tried
146
+ latencyMs: number;
147
+ inputTokens: number;
148
+ outputTokens: number;
149
+ costUsd: number;
150
+ }
151
+ ```
152
+
111
153
  ## Supported providers
112
154
 
113
155
  Any OpenAI-compatible endpoint works — and so does any AI SDK provider package, including a model vendor's own official API.
@@ -225,6 +267,7 @@ Two OpenAI-compatible providers, same probe, same day. Cells cover both families
225
267
 
226
268
  - [x] Own failover engine — cheapest-first routing + streaming-safe fallback, no external routing dependency
227
269
  - [x] Real per-call cost accounting (`onCost`)
270
+ - [x] One correlated record per request with the full failover chain (`onCall` + `formatCallRecord`)
228
271
  - [x] Auto cheapest-first ordering (`autoSort`) from per-provider `cost`
229
272
  - [x] Offline capability + cost check (`scripts/check-provider.sh`) → per-model trust matrix
230
273
  - [ ] Bundled price table for zero-config pricing (drop the manual `cost` numbers)