@metrxbot/sdk 0.2.0 → 0.2.2

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,96 @@
1
+ /**
2
+ * Policy cache for the SDK cascade router (spec §5.6).
3
+ *
4
+ * - One fetch caches the whole org's policy set (GET /api/v1/routing/policies).
5
+ * - TTL 5 min (matches the server's max-age) with ETag revalidation.
6
+ * - Stale tolerance ≤ 60 min: a kill-switch flip must propagate; past the
7
+ * bound the cache reports "unknown" and every caller falls back to
8
+ * pass-through (seam F2).
9
+ * - Lazy + non-blocking: the first call triggers a background load and
10
+ * returns "unknown" — cold start is pass-through, never a blocked request
11
+ * (seam F1).
12
+ *
13
+ * NEVER throws. All fetch failures degrade to "unknown" → pass-through.
14
+ */
15
+ const DEFAULT_TTL_MS = 5 * 60 * 1000;
16
+ const DEFAULT_STALE_MAX_MS = 60 * 60 * 1000;
17
+ export class PolicyCache {
18
+ byKey = new Map();
19
+ etag = null;
20
+ loaded = false;
21
+ loadedAt = 0;
22
+ loading = null;
23
+ fetcher;
24
+ ttlMs;
25
+ staleMaxMs;
26
+ now;
27
+ constructor(opts) {
28
+ this.fetcher = opts.fetcher;
29
+ this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
30
+ this.staleMaxMs = opts.staleMaxMs ?? DEFAULT_STALE_MAX_MS;
31
+ this.now = opts.now ?? Date.now;
32
+ }
33
+ /**
34
+ * Non-blocking lookup.
35
+ * - `undefined` → policy state UNKNOWN (never loaded, or stale past the
36
+ * bound) — caller must pass through.
37
+ * - `null` → the org's policies ARE loaded and this agent has no row —
38
+ * pass-through by design (no row = not allow-listed).
39
+ * - a policy row otherwise.
40
+ */
41
+ get(agentKey) {
42
+ if (!this.loaded) {
43
+ // Cold: kick off the first load, serve pass-through now (F1).
44
+ this.refresh();
45
+ return undefined;
46
+ }
47
+ const age = this.now() - this.loadedAt;
48
+ if (age > this.staleMaxMs) {
49
+ // Too stale to trust — a kill-switch flip may not have propagated (F2).
50
+ this.refresh();
51
+ return undefined;
52
+ }
53
+ if (age > this.ttlMs) {
54
+ // Stale-but-tolerable: serve, refresh in the background.
55
+ this.refresh();
56
+ }
57
+ return this.byKey.get(normalizeAgentKey(agentKey)) ?? null;
58
+ }
59
+ /** Await any in-flight load — for tests and graceful shutdown. */
60
+ async settle() {
61
+ if (this.loading)
62
+ await this.loading.catch(() => undefined);
63
+ }
64
+ refresh() {
65
+ if (this.loading)
66
+ return; // single-flight
67
+ this.loading = this.fetcher(this.etag)
68
+ .then((result) => {
69
+ if (result.notModified) {
70
+ this.loadedAt = this.now();
71
+ return;
72
+ }
73
+ const next = new Map();
74
+ for (const p of result.policies) {
75
+ if (p && typeof p.agent_key === 'string') {
76
+ next.set(normalizeAgentKey(p.agent_key), p);
77
+ }
78
+ }
79
+ this.byKey = next;
80
+ this.etag = result.etag ?? null;
81
+ this.loaded = true;
82
+ this.loadedAt = this.now();
83
+ })
84
+ .catch(() => {
85
+ // F1: fetch failure never surfaces; state stays as-is (or unknown).
86
+ })
87
+ .finally(() => {
88
+ this.loading = null;
89
+ });
90
+ }
91
+ }
92
+ /** Normalization rule shared with policy writes (spec §5.1 M8). */
93
+ export function normalizeAgentKey(key) {
94
+ return key.trim().toLowerCase();
95
+ }
96
+ //# sourceMappingURL=routing-policy-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing-policy-cache.js","sourceRoot":"","sources":["../src/routing-policy-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * SDK cascade routing module — `runWithPolicy()` (spec
3
+ * docs/roi-engine-cascade-sdk-phase1-spec.md §5, Phase 1 S2).
4
+ *
5
+ * Bring-your-own-caller: the customer supplies the function that calls their
6
+ * provider with THEIR keys; this module supplies policy consultation, the
7
+ * confidence gate, escalation, holdout randomization, and evidence emission.
8
+ *
9
+ * THE INVARIANT (throw-parity, §5.7): no code path in runWithPolicy throws an
10
+ * error that the customer's own `callModel(prodModel)` would not have thrown.
11
+ * Policy fetch, gate, candidate calls, and every emit fail OPEN; only the
12
+ * production-model call's own errors propagate.
13
+ *
14
+ * Streaming is OUT OF SCOPE for v1 (§5.1 H7): this contract handles complete
15
+ * responses only — keep streaming call sites on their original path.
16
+ */
17
+ import type { MetrxbotClient } from './client';
18
+ /** Bump with package.json (atomic-version rule). Server can force pass-through
19
+ * for known-bad versions via routing_policies.min_sdk_version (F10).
20
+ * 0.2.2 = the FIRST published version carrying WS1 (task-keyed holdout draw,
21
+ * #260) — required for `randomization_unit:'task'` policies to draw causal arms.
22
+ * The npm-published 0.2.1 predates WS1; min_sdk_version must be '0.2.2'+ to gate. */
23
+ export declare const SDK_VERSION = "0.2.2";
24
+ /**
25
+ * WS1 (Phase 3): deterministic map of a string to a uniform value in [0, 1).
26
+ * FNV-1a (32-bit) — stable across runs/processes and well-distributed, so the
27
+ * empirical treatment fraction over many task ids matches `holdout_pct`. Used to
28
+ * make the holdout arm a function of the TASK id (whole-task treatment) so
29
+ * multi-request tasks are arm-consistent — the prerequisite for task-level
30
+ * causal value evidence (Phase 3 D10). Mirrors the gateway's deterministicBucket
31
+ * (apps/gateway/src/model-routing.ts) but returns a unit float, not a %-bucket.
32
+ */
33
+ export declare function hashToUnit(input: string): number;
34
+ export interface ModelCallResult {
35
+ output: string;
36
+ costMicrocents?: number;
37
+ /** Server-side cost fallback via model_registry pricing when cost is absent. */
38
+ usage?: {
39
+ inputTokens: number;
40
+ outputTokens: number;
41
+ };
42
+ raw?: unknown;
43
+ }
44
+ /**
45
+ * Call-context handed to the customer's `ModelCaller`/`checkerCaller` on every
46
+ * provider call (v0.2.1, additive). Lets caller-side instrumentation (a) stamp
47
+ * `requestId`/`experimentId`/`arm` on the provider call so cascade cost SUMs
48
+ * join across `llm_events ↔ optimization_decisions ↔ quality`, and (b) detect
49
+ * the background shadow candidate (`phase === 'shadow_candidate'`) and suppress
50
+ * it from a cost dashboard.
51
+ *
52
+ * `phase` marks which leg of routing is making the call:
53
+ * - `primary` served production call (pass-through, shadow served,
54
+ * cascade control arm)
55
+ * - `candidate` cascade treatment candidate (the cheaper model)
56
+ * - `escalation` cascade treatment fell back to the production model
57
+ * - `shadow_candidate` background dual-call in shadow_sample (never served)
58
+ * - `checker` any `checkerCaller` invocation (gate + post-response judging)
59
+ */
60
+ export interface ModelCallContext {
61
+ requestId: string;
62
+ experimentId?: string;
63
+ arm?: 'control' | 'treatment';
64
+ phase: 'primary' | 'candidate' | 'escalation' | 'shadow_candidate' | 'checker';
65
+ }
66
+ export interface ModelCaller {
67
+ /**
68
+ * `model === undefined` ⇒ "call your own default" — the day-0 pass-through
69
+ * contract (§5.1 M2). The input is passed through verbatim and is never
70
+ * serialized to Metrx.
71
+ *
72
+ * `ctx` (v0.2.1) is an OPTIONAL third argument — existing two-arg callers
73
+ * keep working unchanged. It is purely informational: it never changes what
74
+ * the router serves and passing it introduces no new throw path (§5.7).
75
+ */
76
+ (model: string | undefined, input: unknown, ctx?: ModelCallContext): Promise<ModelCallResult>;
77
+ }
78
+ export interface ClientJudge {
79
+ (args: {
80
+ input: unknown;
81
+ output: string;
82
+ model: string;
83
+ }): Promise<{
84
+ score: number;
85
+ judgeModel: string;
86
+ }>;
87
+ }
88
+ export interface RunWithPolicyOptions {
89
+ agentKey: string;
90
+ /** The customer's own provider call — their client, their keys. */
91
+ callModel: ModelCaller;
92
+ /**
93
+ * Caller for the cross-family checker model. REQUIRED for shadow/cascade
94
+ * when the checker family is one the primary caller can't reach (e.g. an
95
+ * all-Anthropic customer with a non-Anthropic checker — §5.3 C3).
96
+ */
97
+ checkerCaller?: ModelCaller;
98
+ input: unknown;
99
+ /** Optional custom scorer; default = the G4 checker via checkerCaller. */
100
+ judge?: ClientJudge;
101
+ requestId?: string;
102
+ }
103
+ export interface RunWithPolicyResult {
104
+ output: string;
105
+ /** undefined on no-policy pass-through (the customer's own default ran). */
106
+ servedModel: string | undefined;
107
+ escalated: boolean;
108
+ arm?: 'control' | 'treatment';
109
+ /** Cascade experiment id — attach to telemetry events (with the arm) so the
110
+ * contamination guard can exclude routed calls from baselines. */
111
+ experimentId?: string;
112
+ requestId: string;
113
+ /** What the policy said: pass_through | shadow_sample | cascade | disabled. */
114
+ mode: string;
115
+ }
116
+ export interface RouterConfig {
117
+ apiKey: string;
118
+ apiUrl: string;
119
+ /** Injectable for tests. */
120
+ fetchImpl?: typeof fetch;
121
+ now?: () => number;
122
+ random?: () => number;
123
+ /** Hard local kill switch (F10); also honors METRX_ROUTING_DISABLED=true. */
124
+ disabled?: boolean;
125
+ policyTtlMs?: number;
126
+ policyStaleMaxMs?: number;
127
+ }
128
+ export declare class MetrxRouter {
129
+ private readonly cfg;
130
+ private readonly cache;
131
+ private readonly now;
132
+ private readonly random;
133
+ private readonly fetchImpl;
134
+ private readonly breakers;
135
+ private readonly background;
136
+ constructor(cfg: RouterConfig);
137
+ /** Await all in-flight background work (emits, shadow calls, judging).
138
+ * For tests and graceful shutdown — never required for correctness. */
139
+ flush(): Promise<void>;
140
+ run(opts: RunWithPolicyOptions): Promise<RunWithPolicyResult>;
141
+ private passThrough;
142
+ private runShadowSample;
143
+ /**
144
+ * WS1 (Phase 3): the holdout-arm uniform draw.
145
+ *
146
+ * DEFAULT (`gate_config.randomization_unit` unset or `'request'`): a per-request
147
+ * Bernoulli via `this.random()` — BYTE-IDENTICAL to pre-Phase-3 behaviour. This
148
+ * is the live cascade path for every policy, so it must not change unless the
149
+ * policy explicitly opts in.
150
+ *
151
+ * TASK unit (`gate_config.randomization_unit === 'task'`): a DETERMINISTIC
152
+ * function of the current task id, so every request inside one `task()` lands on
153
+ * the same arm (whole-task treatment) → multi-request tasks are arm-consistent →
154
+ * task-level value evidence becomes causal (Phase 3 D10). Salted with
155
+ * `experiment_id` so a judge/experiment rotation re-randomizes assignments.
156
+ *
157
+ * Falls back to the per-request draw when there is no task context OR no
158
+ * `experiment_id` (M2 — never silently salt with a literal 'null'): those
159
+ * requests stay the Phase-2 non-actionable stratum, no throw, no regression.
160
+ */
161
+ private holdoutUniform;
162
+ private runCascade;
163
+ private judgeOutput;
164
+ private emitDecision;
165
+ private emitPair;
166
+ private emitQuality;
167
+ private fireAndForget;
168
+ /** F8/F9: background work never throws into the request path. */
169
+ private spawnBackground;
170
+ private breakerFor;
171
+ private breakerOpen;
172
+ private recordCandidateError;
173
+ private recordEscalation;
174
+ private makePolicyFetcher;
175
+ }
176
+ export declare function routerFor(client: MetrxbotClient, overrides?: Partial<RouterConfig>): MetrxRouter;
177
+ /**
178
+ * Run one request under the agent's routing policy. Day 0 (no policy rows):
179
+ * behaves exactly like `opts.callModel(undefined, opts.input)`.
180
+ */
181
+ export declare function runWithPolicy(client: MetrxbotClient, opts: RunWithPolicyOptions): Promise<RunWithPolicyResult>;
182
+ /**
183
+ * Loose semver-ish comparison. Returns true when a < b, false when a >= b,
184
+ * and `undefined` when either side is unparseable — the caller treats
185
+ * "unknown" as pass-through (fail toward doing nothing).
186
+ */
187
+ export declare function semverLt(a: string, b: string): boolean | undefined;
188
+ //# sourceMappingURL=routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"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"}