modelrig 0.0.1 → 0.1.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/LICENSE +201 -0
- package/README.md +115 -8
- package/dist/adapters/anthropic.d.ts +46 -0
- package/dist/adapters/anthropic.d.ts.map +1 -0
- package/dist/adapters/anthropic.js +202 -0
- package/dist/adapters/deepseek.d.ts +41 -0
- package/dist/adapters/deepseek.d.ts.map +1 -0
- package/dist/adapters/deepseek.js +163 -0
- package/dist/adapters/gemini.d.ts +44 -0
- package/dist/adapters/gemini.d.ts.map +1 -0
- package/dist/adapters/gemini.js +222 -0
- package/dist/adapters/grok.d.ts +44 -0
- package/dist/adapters/grok.d.ts.map +1 -0
- package/dist/adapters/grok.js +168 -0
- package/dist/adapters/openai-compat.d.ts +74 -0
- package/dist/adapters/openai-compat.d.ts.map +1 -0
- package/dist/adapters/openai-compat.js +187 -0
- package/dist/adapters/openai.d.ts +49 -0
- package/dist/adapters/openai.d.ts.map +1 -0
- package/dist/adapters/openai.js +222 -0
- package/dist/bakeoff/engine.d.ts +52 -0
- package/dist/bakeoff/engine.d.ts.map +1 -0
- package/dist/bakeoff/engine.js +163 -0
- package/dist/bakeoff/replay.d.ts +52 -0
- package/dist/bakeoff/replay.d.ts.map +1 -0
- package/dist/bakeoff/replay.js +94 -0
- package/dist/bakeoff/samples.d.ts +62 -0
- package/dist/bakeoff/samples.d.ts.map +1 -0
- package/dist/bakeoff/samples.js +128 -0
- package/dist/bakeoff/stats.d.ts +13 -0
- package/dist/bakeoff/stats.d.ts.map +1 -0
- package/dist/bakeoff/stats.js +48 -0
- package/dist/bakeoff/types.d.ts +37 -0
- package/dist/bakeoff/types.d.ts.map +1 -0
- package/dist/bakeoff/types.js +10 -0
- package/dist/cli.d.ts +27 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +572 -0
- package/dist/config.d.ts +104 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +148 -0
- package/dist/feedback/coverage.d.ts +32 -0
- package/dist/feedback/coverage.d.ts.map +1 -0
- package/dist/feedback/coverage.js +95 -0
- package/dist/feedback/feedback.d.ts +35 -0
- package/dist/feedback/feedback.d.ts.map +1 -0
- package/dist/feedback/feedback.js +39 -0
- package/dist/index.d.ts +155 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +448 -0
- package/dist/init/finder.d.ts +79 -0
- package/dist/init/finder.d.ts.map +1 -0
- package/dist/init/finder.js +297 -0
- package/dist/init/run.d.ts +99 -0
- package/dist/init/run.d.ts.map +1 -0
- package/dist/init/run.js +281 -0
- package/dist/init/signatures.d.ts +39 -0
- package/dist/init/signatures.d.ts.map +1 -0
- package/dist/init/signatures.js +116 -0
- package/dist/matrix/aggregate.d.ts +89 -0
- package/dist/matrix/aggregate.d.ts.map +1 -0
- package/dist/matrix/aggregate.js +186 -0
- package/dist/query/grammar.d.ts +35 -0
- package/dist/query/grammar.d.ts.map +1 -0
- package/dist/query/grammar.js +279 -0
- package/dist/query/run.d.ts +8 -0
- package/dist/query/run.d.ts.map +1 -0
- package/dist/query/run.js +21 -0
- package/dist/registry/build.d.ts +126 -0
- package/dist/registry/build.d.ts.map +1 -0
- package/dist/registry/build.js +192 -0
- package/dist/registry/call-notes.d.ts +11 -0
- package/dist/registry/call-notes.d.ts.map +1 -0
- package/dist/registry/call-notes.js +72 -0
- package/dist/registry/claims.d.ts +63 -0
- package/dist/registry/claims.d.ts.map +1 -0
- package/dist/registry/claims.js +107 -0
- package/dist/registry/facts.d.ts +32 -0
- package/dist/registry/facts.d.ts.map +1 -0
- package/dist/registry/facts.js +120 -0
- package/dist/registry/fingerprint.d.ts +20 -0
- package/dist/registry/fingerprint.d.ts.map +1 -0
- package/dist/registry/fingerprint.js +150 -0
- package/dist/registry/parity.d.ts +26 -0
- package/dist/registry/parity.d.ts.map +1 -0
- package/dist/registry/parity.js +41 -0
- package/dist/registry/pricing.d.ts +19 -0
- package/dist/registry/pricing.d.ts.map +1 -0
- package/dist/registry/pricing.js +69 -0
- package/dist/registry/rows.d.ts +16 -0
- package/dist/registry/rows.d.ts.map +1 -0
- package/dist/registry/rows.js +57 -0
- package/dist/registry/seed.d.ts +43 -0
- package/dist/registry/seed.d.ts.map +1 -0
- package/dist/registry/seed.js +97 -0
- package/dist/registry/select.d.ts +68 -0
- package/dist/registry/select.d.ts.map +1 -0
- package/dist/registry/select.js +141 -0
- package/dist/registry/staleness.d.ts +18 -0
- package/dist/registry/staleness.d.ts.map +1 -0
- package/dist/registry/staleness.js +39 -0
- package/dist/routes/draft.d.ts +83 -0
- package/dist/routes/draft.d.ts.map +1 -0
- package/dist/routes/draft.js +135 -0
- package/dist/routes/loader.d.ts +26 -0
- package/dist/routes/loader.d.ts.map +1 -0
- package/dist/routes/loader.js +436 -0
- package/dist/routes/manifest.d.ts +24 -0
- package/dist/routes/manifest.d.ts.map +1 -0
- package/dist/routes/manifest.js +118 -0
- package/dist/routes/serveability.d.ts +52 -0
- package/dist/routes/serveability.d.ts.map +1 -0
- package/dist/routes/serveability.js +73 -0
- package/dist/routes/template.d.ts +18 -0
- package/dist/routes/template.d.ts.map +1 -0
- package/dist/routes/template.js +94 -0
- package/dist/run/cost.d.ts +26 -0
- package/dist/run/cost.d.ts.map +1 -0
- package/dist/run/cost.js +41 -0
- package/dist/run/envelope.d.ts +21 -0
- package/dist/run/envelope.d.ts.map +1 -0
- package/dist/run/envelope.js +45 -0
- package/dist/run/grounding.d.ts +56 -0
- package/dist/run/grounding.d.ts.map +1 -0
- package/dist/run/grounding.js +89 -0
- package/dist/run/repair.d.ts +36 -0
- package/dist/run/repair.d.ts.map +1 -0
- package/dist/run/repair.js +61 -0
- package/dist/run/resolve.d.ts +26 -0
- package/dist/run/resolve.d.ts.map +1 -0
- package/dist/run/resolve.js +81 -0
- package/dist/run/retry.d.ts +19 -0
- package/dist/run/retry.d.ts.map +1 -0
- package/dist/run/retry.js +50 -0
- package/dist/run/run.d.ts +41 -0
- package/dist/run/run.d.ts.map +1 -0
- package/dist/run/run.js +0 -0
- package/dist/run/validate.d.ts +15 -0
- package/dist/run/validate.d.ts.map +1 -0
- package/dist/run/validate.js +56 -0
- package/dist/savings/emit.d.ts +25 -0
- package/dist/savings/emit.d.ts.map +1 -0
- package/dist/savings/emit.js +75 -0
- package/dist/savings/odometer.d.ts +32 -0
- package/dist/savings/odometer.d.ts.map +1 -0
- package/dist/savings/odometer.js +70 -0
- package/dist/savings/swap-execute.d.ts +44 -0
- package/dist/savings/swap-execute.d.ts.map +1 -0
- package/dist/savings/swap-execute.js +87 -0
- package/dist/savings/swaps-client.d.ts +41 -0
- package/dist/savings/swaps-client.d.ts.map +1 -0
- package/dist/savings/swaps-client.js +81 -0
- package/dist/telemetry/capture.d.ts +28 -0
- package/dist/telemetry/capture.d.ts.map +1 -0
- package/dist/telemetry/capture.js +74 -0
- package/dist/telemetry/exporter.d.ts +62 -0
- package/dist/telemetry/exporter.d.ts.map +1 -0
- package/dist/telemetry/exporter.js +233 -0
- package/dist/telemetry/ingest-protocol.d.ts +161 -0
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -0
- package/dist/telemetry/ingest-protocol.js +163 -0
- package/dist/telemetry/sinks.d.ts +54 -0
- package/dist/telemetry/sinks.d.ts.map +1 -0
- package/dist/telemetry/sinks.js +89 -0
- package/dist/telemetry/store.d.ts +38 -0
- package/dist/telemetry/store.d.ts.map +1 -0
- package/dist/telemetry/store.js +332 -0
- package/dist/telemetry/supabase-exporter.d.ts +64 -0
- package/dist/telemetry/supabase-exporter.d.ts.map +1 -0
- package/dist/telemetry/supabase-exporter.js +211 -0
- package/dist/tenancy/api-key-format.d.ts +67 -0
- package/dist/tenancy/api-key-format.d.ts.map +1 -0
- package/dist/tenancy/api-key-format.js +91 -0
- package/dist/tenancy/constants.d.ts +23 -0
- package/dist/tenancy/constants.d.ts.map +1 -0
- package/dist/tenancy/constants.js +25 -0
- package/dist/tenancy/scrub.d.ts +47 -0
- package/dist/tenancy/scrub.d.ts.map +1 -0
- package/dist/tenancy/scrub.js +85 -0
- package/dist/types/failures-teaching.d.ts +56 -0
- package/dist/types/failures-teaching.d.ts.map +1 -0
- package/dist/types/failures-teaching.js +177 -0
- package/dist/types/failures.d.ts +27 -0
- package/dist/types/failures.d.ts.map +1 -0
- package/dist/types/failures.js +41 -0
- package/dist/types/provider.d.ts +79 -0
- package/dist/types/provider.d.ts.map +1 -0
- package/dist/types/provider.js +20 -0
- package/dist/types/route.d.ts +127 -0
- package/dist/types/route.d.ts.map +1 -0
- package/dist/types/route.js +6 -0
- package/dist/types/telemetry.d.ts +89 -0
- package/dist/types/telemetry.d.ts.map +1 -0
- package/dist/types/telemetry.js +6 -0
- package/dist/watch/budget.d.ts +19 -0
- package/dist/watch/budget.d.ts.map +1 -0
- package/dist/watch/budget.js +35 -0
- package/dist/watch/evaluate.d.ts +66 -0
- package/dist/watch/evaluate.d.ts.map +1 -0
- package/dist/watch/evaluate.js +94 -0
- package/dist/watch/proposals.d.ts +73 -0
- package/dist/watch/proposals.d.ts.map +1 -0
- package/dist/watch/proposals.js +169 -0
- package/dist/watch/run-record.d.ts +64 -0
- package/dist/watch/run-record.d.ts.map +1 -0
- package/dist/watch/run-record.js +86 -0
- package/dist/watch/run-reported.d.ts +20 -0
- package/dist/watch/run-reported.d.ts.map +1 -0
- package/dist/watch/run-reported.js +53 -0
- package/dist/watch/run.d.ts +40 -0
- package/dist/watch/run.d.ts.map +1 -0
- package/dist/watch/run.js +44 -0
- package/dist/watch/state-store.d.ts +48 -0
- package/dist/watch/state-store.d.ts.map +1 -0
- package/dist/watch/state-store.js +86 -0
- package/dist/watch/state.d.ts +21 -0
- package/dist/watch/state.d.ts.map +1 -0
- package/dist/watch/state.js +93 -0
- package/package.json +50 -14
- package/index.js +0 -3
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProviderAdapter contract + the candidate-set invariant's type machinery.
|
|
3
|
+
* Spec §4. The invariant is structural: AdapterRequest carries a CandidateRef,
|
|
4
|
+
* and CandidateRef is a branded type constructible ONLY in run/resolve.ts.
|
|
5
|
+
*/
|
|
6
|
+
import type { RigFailure } from "./failures";
|
|
7
|
+
export type ProviderId = "gemini" | "openai" | "deepseek" | "anthropic" | "grok" | "deepinfra" | "fireworks";
|
|
8
|
+
export type CapabilityFlag = "structured_native" | "json_mode" | "grounded_native" | "context_cache_explicit" | "prompt_cache_key" | "prefix_cache_implicit" | "tier_flex" | "trace_visible";
|
|
9
|
+
/** The canonical flag enumeration — the single list every static capability
|
|
10
|
+
* materialization iterates (index.ts, template validation, tests). */
|
|
11
|
+
export declare const ALL_CAPABILITY_FLAGS: readonly CapabilityFlag[];
|
|
12
|
+
declare const candidateBrand: unique symbol;
|
|
13
|
+
/**
|
|
14
|
+
* A (provider, model) pair validated against a route's candidate list.
|
|
15
|
+
* DO NOT construct outside run/resolve.ts — no `as CandidateRef` anywhere
|
|
16
|
+
* (CI greps for it; see candidate-set-invariant.test.ts).
|
|
17
|
+
*/
|
|
18
|
+
export interface CandidateRef {
|
|
19
|
+
readonly provider: ProviderId;
|
|
20
|
+
readonly model: string;
|
|
21
|
+
readonly [candidateBrand]: true;
|
|
22
|
+
}
|
|
23
|
+
export type ServiceTier = "standard" | "flex" | "priority";
|
|
24
|
+
export interface AdapterRequest {
|
|
25
|
+
readonly candidate: CandidateRef;
|
|
26
|
+
readonly systemPrompt: string;
|
|
27
|
+
readonly userPrompt: string;
|
|
28
|
+
/** JSON Schema for native structured output; null => prompt/json_mode path. */
|
|
29
|
+
readonly outputSchema: object | null;
|
|
30
|
+
readonly requestedTier: ServiceTier;
|
|
31
|
+
readonly timeoutMs: number;
|
|
32
|
+
/** Provider-neutral cache directive; adapters map to native mechanisms. */
|
|
33
|
+
readonly cache?: {
|
|
34
|
+
key: string;
|
|
35
|
+
ttlSeconds?: number;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Provider-native web-grounding directive (set by the run loop when the
|
|
39
|
+
* route requires "grounded"). BUILDER ADDITION pending architect sign-off:
|
|
40
|
+
* the scaffold's gemini adapter notes grounding is "driven by a
|
|
41
|
+
* cache/grounding directive on AdapterRequest", but the scaffolded type
|
|
42
|
+
* carried only `cache` — this optional field fills that gap additively.
|
|
43
|
+
*/
|
|
44
|
+
readonly grounding?: boolean;
|
|
45
|
+
readonly maxOutputTokens?: number;
|
|
46
|
+
}
|
|
47
|
+
export interface AdapterUsage {
|
|
48
|
+
readonly tokensIn: number;
|
|
49
|
+
readonly tokensOut: number;
|
|
50
|
+
readonly tokensCached: number;
|
|
51
|
+
readonly servedTier: ServiceTier;
|
|
52
|
+
/** Time to first body byte, ms (Phase 4 WS3 — headers lie on inference
|
|
53
|
+
* servers; TTFB is the honest slowness signal). Streaming adapters stamp
|
|
54
|
+
* first-chunk arrival; non-streaming calls equal total latency (the first
|
|
55
|
+
* byte genuinely arrives with the body). Optional: absent on failures
|
|
56
|
+
* where nothing arrived. */
|
|
57
|
+
readonly ttfbMs?: number;
|
|
58
|
+
}
|
|
59
|
+
export type AdapterResult = {
|
|
60
|
+
readonly ok: true;
|
|
61
|
+
readonly text: string;
|
|
62
|
+
readonly usage: AdapterUsage;
|
|
63
|
+
}
|
|
64
|
+
/** F1 (C1 finding, closed Phase 3 step 0): failures that still BILLED
|
|
65
|
+
* tokens (refusals, truncations, post-stream rejections) carry `usage` so
|
|
66
|
+
* envelopes, telemetry, and bake-off cost math see the spend. Absent when
|
|
67
|
+
* the provider billed nothing (transport errors, pre-dispatch rejections). */
|
|
68
|
+
| {
|
|
69
|
+
readonly ok: false;
|
|
70
|
+
readonly failure: RigFailure;
|
|
71
|
+
readonly usage?: AdapterUsage;
|
|
72
|
+
};
|
|
73
|
+
export interface ProviderAdapter {
|
|
74
|
+
readonly id: ProviderId;
|
|
75
|
+
supports(feature: CapabilityFlag, model: string): boolean;
|
|
76
|
+
call(req: AdapterRequest): Promise<AdapterResult>;
|
|
77
|
+
}
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/types/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,WAAW,GACX,MAAM,GAGN,WAAW,GACX,WAAW,CAAC;AAEhB,MAAM,MAAM,cAAc,GACtB,mBAAmB,GACnB,WAAW,GACX,iBAAiB,GACjB,wBAAwB,GACxB,kBAAkB,GAClB,uBAAuB,GACvB,WAAW,GACX,eAAe,CAAC;AAEpB;sEACsE;AACtE,eAAO,MAAM,oBAAoB,EAAE,SAAS,cAAc,EASzD,CAAC;AAEF,OAAO,CAAC,MAAM,cAAc,EAAE,OAAO,MAAM,CAAC;AAE5C;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC;CACjC;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC;;;;gCAI4B;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAA;CAAE;AAC5E;;;8EAG8E;GAC5E;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAA;CAAE,CAAC;AAExF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1D,IAAI,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACnD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ProviderAdapter contract + the candidate-set invariant's type machinery.
|
|
4
|
+
* Spec §4. The invariant is structural: AdapterRequest carries a CandidateRef,
|
|
5
|
+
* and CandidateRef is a branded type constructible ONLY in run/resolve.ts.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.ALL_CAPABILITY_FLAGS = void 0;
|
|
9
|
+
/** The canonical flag enumeration — the single list every static capability
|
|
10
|
+
* materialization iterates (index.ts, template validation, tests). */
|
|
11
|
+
exports.ALL_CAPABILITY_FLAGS = [
|
|
12
|
+
"structured_native",
|
|
13
|
+
"json_mode",
|
|
14
|
+
"grounded_native",
|
|
15
|
+
"context_cache_explicit",
|
|
16
|
+
"prompt_cache_key",
|
|
17
|
+
"prefix_cache_implicit",
|
|
18
|
+
"tier_flex",
|
|
19
|
+
"trace_visible",
|
|
20
|
+
];
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route bundle contract — spec §3. Loaded from modelrig/routes/*.yaml by
|
|
3
|
+
* routes/loader.ts; frozen after load.
|
|
4
|
+
*/
|
|
5
|
+
import type { FailureClass } from "./failures";
|
|
6
|
+
import type { ProviderId, ServiceTier } from "./provider";
|
|
7
|
+
export interface CandidateSpec {
|
|
8
|
+
readonly provider: ProviderId;
|
|
9
|
+
readonly model: string;
|
|
10
|
+
}
|
|
11
|
+
export type Requirement = "schema_conformant" | "grounded" | "zero_retention" | "trace_visible";
|
|
12
|
+
export type Preference = "cost" | "latency";
|
|
13
|
+
export interface RoutePolicy {
|
|
14
|
+
/** Per-class retry budgets — non-fungible. Missing class => 0 retries. */
|
|
15
|
+
readonly retries: Partial<Record<FailureClass, number>>;
|
|
16
|
+
readonly timeoutMs: number;
|
|
17
|
+
readonly tier: ServiceTier;
|
|
18
|
+
readonly json: "native" | "json_mode";
|
|
19
|
+
}
|
|
20
|
+
/** Repair rung config (Phase 3 WS2, ladder rung 4). */
|
|
21
|
+
export interface RepairPolicy {
|
|
22
|
+
/** Total repair attempts on a schema-invalid output: attempt 1 re-asks the
|
|
23
|
+
* SAME model with the ajv error summary; attempt 2 (when maxRepairs ≥ 2 and
|
|
24
|
+
* repairModel is set) hands {invalid output, errors, schema} to the
|
|
25
|
+
* designated repair model. */
|
|
26
|
+
readonly maxRepairs: number;
|
|
27
|
+
/** Designated cheap repair model — must be one of the route's declared
|
|
28
|
+
* candidates (candidate-set invariant holds through repair). */
|
|
29
|
+
readonly repairModel?: CandidateSpec;
|
|
30
|
+
}
|
|
31
|
+
/** A named route variant (Phase 3 WS1, bundle format v2 — additive).
|
|
32
|
+
* Every field optional; an absent field inherits the route's base config. */
|
|
33
|
+
export interface RouteVariant {
|
|
34
|
+
readonly name: string;
|
|
35
|
+
/** Candidate narrowing — MUST be a subset of the route's declared
|
|
36
|
+
* candidates (loader-enforced; the candidate-set invariant is unbreachable
|
|
37
|
+
* via variants). */
|
|
38
|
+
readonly candidates?: readonly CandidateSpec[];
|
|
39
|
+
/** Replaces the system template entirely (rendered with the same variables
|
|
40
|
+
* and capability conditionals). Mutually exclusive with promptAppend. */
|
|
41
|
+
readonly promptOverride?: string;
|
|
42
|
+
/** Appended to the rendered system prompt (after capability conditionals,
|
|
43
|
+
* before json coaching). */
|
|
44
|
+
readonly promptAppend?: string;
|
|
45
|
+
/** Reasoning scaffold (thinking directives; manual authoring this phase) —
|
|
46
|
+
* appended after promptAppend, before json coaching. */
|
|
47
|
+
readonly scaffold?: string;
|
|
48
|
+
/** JSON rung override for this variant. */
|
|
49
|
+
readonly json?: "native" | "json_mode";
|
|
50
|
+
readonly repair?: RepairPolicy;
|
|
51
|
+
}
|
|
52
|
+
export interface RouteBundle {
|
|
53
|
+
readonly route: string;
|
|
54
|
+
readonly version: number;
|
|
55
|
+
/** Resolved, parsed JSON Schema (null = unstructured route). */
|
|
56
|
+
readonly outputSchema: object | null;
|
|
57
|
+
readonly candidates: readonly CandidateSpec[];
|
|
58
|
+
readonly require: readonly Requirement[];
|
|
59
|
+
readonly prefer: readonly Preference[];
|
|
60
|
+
/** Raw template text with {{var}} and {{#if capability.X}} blocks. */
|
|
61
|
+
readonly systemTemplate: string;
|
|
62
|
+
readonly variables: readonly string[];
|
|
63
|
+
readonly policy: RoutePolicy;
|
|
64
|
+
/** Base-config repair rung (Phase 3 WS2) — variants may override. */
|
|
65
|
+
readonly repair?: RepairPolicy;
|
|
66
|
+
/** Named variants (Phase 3 WS1, bundle v2) — [] for v1 bundles. */
|
|
67
|
+
readonly variants: readonly RouteVariant[];
|
|
68
|
+
/** Local-only replay capture opt-in (Phase 3 WS4) — default false. */
|
|
69
|
+
readonly capture: boolean;
|
|
70
|
+
/** Grounding-inject search-query template (Phase 3 WS3) — rendered with
|
|
71
|
+
* the same variables as the system template; absent = the capped rendered
|
|
72
|
+
* prompt is used as the query (adequate only for short prompts). */
|
|
73
|
+
readonly groundingQuery?: string;
|
|
74
|
+
/** Schema-fingerprint cell key, computed at load from outputSchema
|
|
75
|
+
* (registry/fingerprint.ts); null for unstructured routes. */
|
|
76
|
+
readonly fingerprintCell: string | null;
|
|
77
|
+
}
|
|
78
|
+
export interface RunTags {
|
|
79
|
+
readonly run_id?: string;
|
|
80
|
+
readonly step?: string;
|
|
81
|
+
readonly [key: string]: string | undefined;
|
|
82
|
+
}
|
|
83
|
+
export interface RunOptions {
|
|
84
|
+
readonly input: Record<string, unknown>;
|
|
85
|
+
readonly tags: RunTags;
|
|
86
|
+
readonly budget?: {
|
|
87
|
+
readonly envelope: string;
|
|
88
|
+
};
|
|
89
|
+
/** Named variant to serve (Phase 3 WS1); omitted = the default variant
|
|
90
|
+
* (the route's base config). Unknown names are config errors. */
|
|
91
|
+
readonly variant?: string;
|
|
92
|
+
}
|
|
93
|
+
export interface RunMeta {
|
|
94
|
+
/** Telemetry row id of the serving attempt — the handle rig.feedback()
|
|
95
|
+
* takes (Phase 4 WS2). */
|
|
96
|
+
readonly inferenceId: string;
|
|
97
|
+
readonly route: string;
|
|
98
|
+
readonly routeVersion: number;
|
|
99
|
+
readonly provider: ProviderId;
|
|
100
|
+
readonly model: string;
|
|
101
|
+
readonly requestedTier: ServiceTier;
|
|
102
|
+
readonly servedTier: ServiceTier;
|
|
103
|
+
readonly tokensIn: number;
|
|
104
|
+
readonly tokensOut: number;
|
|
105
|
+
readonly tokensCached: number;
|
|
106
|
+
readonly costEstimateUsd: number;
|
|
107
|
+
readonly latencyMs: number;
|
|
108
|
+
readonly validated: boolean;
|
|
109
|
+
readonly attemptsByClass: Partial<Record<FailureClass, number>>;
|
|
110
|
+
/** Variant that served this run — null = default variant (Phase 3 WS1). */
|
|
111
|
+
readonly servedVariant: string | null;
|
|
112
|
+
/** "provider/model" that repaired the output — null when unrepaired
|
|
113
|
+
* (Phase 3 WS2). */
|
|
114
|
+
readonly repairedBy: string | null;
|
|
115
|
+
/** Normalized url_citation annotations (Phase 3 WS3) — present when the
|
|
116
|
+
* grounding-inject rung served this run. */
|
|
117
|
+
readonly citations?: ReadonlyArray<{
|
|
118
|
+
readonly type: "url_citation";
|
|
119
|
+
readonly url: string;
|
|
120
|
+
readonly title?: string;
|
|
121
|
+
}>;
|
|
122
|
+
}
|
|
123
|
+
export interface RunResult {
|
|
124
|
+
readonly output: unknown;
|
|
125
|
+
readonly meta: RunMeta;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/types/route.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry contracts — spec §5. SQLite-backed in Phase 1 (telemetry/store.ts);
|
|
3
|
+
* the interface exists so Phase 6 can add a remote control-plane sink.
|
|
4
|
+
*/
|
|
5
|
+
import type { FailureClass } from "./failures";
|
|
6
|
+
import type { RunTags } from "./route";
|
|
7
|
+
export interface TelemetryRow {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly ts: string;
|
|
10
|
+
readonly route: string;
|
|
11
|
+
readonly routeVersion: number;
|
|
12
|
+
readonly provider: string;
|
|
13
|
+
readonly model: string;
|
|
14
|
+
readonly requestedTier: string;
|
|
15
|
+
readonly servedTier: string;
|
|
16
|
+
readonly tokensIn: number;
|
|
17
|
+
readonly tokensOut: number;
|
|
18
|
+
readonly tokensCached: number;
|
|
19
|
+
readonly costEstimateUsd: number;
|
|
20
|
+
readonly latencyMs: number;
|
|
21
|
+
/** Time to first body byte, ms (Phase 4 WS3) — null when nothing arrived
|
|
22
|
+
* or for rows recorded before the v6 migration. */
|
|
23
|
+
readonly ttfbMs: number | null;
|
|
24
|
+
readonly failureClass: FailureClass | null;
|
|
25
|
+
readonly attemptsJson: string;
|
|
26
|
+
readonly tagsJson: string;
|
|
27
|
+
/** Schema-fingerprint cell key (registry/fingerprint.ts) — null for
|
|
28
|
+
* unstructured routes and rows recorded before the v2 migration. */
|
|
29
|
+
readonly fingerprintCell: string | null;
|
|
30
|
+
/** True when this attempt's model had no pricing entry (addendum A1):
|
|
31
|
+
* cost_estimate_usd stays 0 (no invented dollars) and any active envelope
|
|
32
|
+
* was charged the conservative unpriced rate instead. */
|
|
33
|
+
readonly pricingMissing: boolean;
|
|
34
|
+
/** Variant name this attempt served (Phase 3 WS1) — null = default variant
|
|
35
|
+
* and rows recorded before the v3 migration. */
|
|
36
|
+
readonly servedVariant: string | null;
|
|
37
|
+
/** "provider/model" of the repair model that produced this row's output
|
|
38
|
+
* (Phase 3 WS2) — null for unrepaired attempts. */
|
|
39
|
+
readonly repairedBy: string | null;
|
|
40
|
+
}
|
|
41
|
+
export interface EnvelopeRow {
|
|
42
|
+
readonly envelopeKey: string;
|
|
43
|
+
readonly budgetUsd: number;
|
|
44
|
+
readonly spentUsd: number;
|
|
45
|
+
readonly status: "open" | "exhausted";
|
|
46
|
+
}
|
|
47
|
+
/** One rig.feedback() judgment (Phase 4 WS2) — attached to a single
|
|
48
|
+
* inference OR an episode (= run-level key), or both. Local SQLite is the
|
|
49
|
+
* write path; the exporter mirrors (dual-store symmetry with inferences). */
|
|
50
|
+
export interface FeedbackRow {
|
|
51
|
+
readonly id: string;
|
|
52
|
+
readonly ts: string;
|
|
53
|
+
readonly inferenceId: string | null;
|
|
54
|
+
readonly episodeKey: string | null;
|
|
55
|
+
readonly verdict: "up" | "down";
|
|
56
|
+
readonly score: number | null;
|
|
57
|
+
readonly note: string | null;
|
|
58
|
+
readonly source: string;
|
|
59
|
+
/**
|
|
60
|
+
* The org this verdict belongs to — Phase 6 WS2, and the reason this field
|
|
61
|
+
* exists at all.
|
|
62
|
+
*
|
|
63
|
+
* A verdict recorded through OUR hosted server belongs to the org of the
|
|
64
|
+
* person who recorded it, and one SQLite store serves every org that reaches
|
|
65
|
+
* that server. Without a per-row org the exporter stamps its OWN, which
|
|
66
|
+
* files a customer's judgment into somebody else's corpus — unrecomputable
|
|
67
|
+
* evidence, silently wrong. WS1 shipped a 409 refusal rather than misfile;
|
|
68
|
+
* this column is what replaces the refusal with routing (QA-P6-010).
|
|
69
|
+
*
|
|
70
|
+
* NULL is the ordinary case and means "whatever org this exporter is": a
|
|
71
|
+
* self-hosted rig has exactly one, and `rig.feedback()` from application
|
|
72
|
+
* code has no notion of orgs at all.
|
|
73
|
+
*/
|
|
74
|
+
readonly orgId: string | null;
|
|
75
|
+
/** Authenticated user who recorded it (00017's `feedback.created_by`), or
|
|
76
|
+
* null for an SDK-recorded verdict — which is a fact about the row, not
|
|
77
|
+
* missing data, and is never backfilled. */
|
|
78
|
+
readonly createdBy: string | null;
|
|
79
|
+
}
|
|
80
|
+
export interface TelemetryStore {
|
|
81
|
+
record(row: TelemetryRow): void;
|
|
82
|
+
recordFeedback(row: FeedbackRow): void;
|
|
83
|
+
queryByTag(tag: keyof RunTags & string, value: string): TelemetryRow[];
|
|
84
|
+
getEnvelope(key: string): EnvelopeRow | null;
|
|
85
|
+
accrue(key: string, usd: number): EnvelopeRow;
|
|
86
|
+
openEnvelope(key: string, budgetUsd: number): EnvelopeRow;
|
|
87
|
+
close(): void;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/types/telemetry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watch monthly spend cap — Phase 4 WS1 (spec: MODELRIG_WATCH_MONTHLY_USD,
|
|
3
|
+
* default $50). Every paid run the loop triggers (--from-proposal
|
|
4
|
+
* bake-offs, future re-probes) draws from a calendar-month envelope in the
|
|
5
|
+
* SAME envelope machinery that guards everything else — one budget system,
|
|
6
|
+
* not two.
|
|
7
|
+
*/
|
|
8
|
+
import type { TelemetryStore } from "../types/telemetry";
|
|
9
|
+
export declare const DEFAULT_WATCH_MONTHLY_USD = 50;
|
|
10
|
+
export declare function watchEnvelopeKey(now: Date): string;
|
|
11
|
+
export interface WatchBudgetReservation {
|
|
12
|
+
readonly key: string;
|
|
13
|
+
readonly remainingUsd: number;
|
|
14
|
+
}
|
|
15
|
+
/** Open (idempotently) this month's watch envelope and report the headroom.
|
|
16
|
+
* Throws typed budget_exhausted when the month's cap is spent — the caller
|
|
17
|
+
* refuses the paid run; nothing silently overruns. */
|
|
18
|
+
export declare function reserveWatchBudget(store: TelemetryStore, monthlyUsd: number, now: Date): WatchBudgetReservation;
|
|
19
|
+
//# sourceMappingURL=budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../src/watch/budget.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,CAElD;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED;;sDAEsD;AACtD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,cAAc,EACrB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,IAAI,GACR,sBAAsB,CAgBxB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Watch monthly spend cap — Phase 4 WS1 (spec: MODELRIG_WATCH_MONTHLY_USD,
|
|
4
|
+
* default $50). Every paid run the loop triggers (--from-proposal
|
|
5
|
+
* bake-offs, future re-probes) draws from a calendar-month envelope in the
|
|
6
|
+
* SAME envelope machinery that guards everything else — one budget system,
|
|
7
|
+
* not two.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.DEFAULT_WATCH_MONTHLY_USD = void 0;
|
|
11
|
+
exports.watchEnvelopeKey = watchEnvelopeKey;
|
|
12
|
+
exports.reserveWatchBudget = reserveWatchBudget;
|
|
13
|
+
const failures_1 = require("../types/failures");
|
|
14
|
+
exports.DEFAULT_WATCH_MONTHLY_USD = 50;
|
|
15
|
+
function watchEnvelopeKey(now) {
|
|
16
|
+
return `watch-${now.toISOString().slice(0, 7)}`;
|
|
17
|
+
}
|
|
18
|
+
/** Open (idempotently) this month's watch envelope and report the headroom.
|
|
19
|
+
* Throws typed budget_exhausted when the month's cap is spent — the caller
|
|
20
|
+
* refuses the paid run; nothing silently overruns. */
|
|
21
|
+
function reserveWatchBudget(store, monthlyUsd, now) {
|
|
22
|
+
const key = watchEnvelopeKey(now);
|
|
23
|
+
const envelope = store.openEnvelope(key, monthlyUsd);
|
|
24
|
+
const remainingUsd = Math.max(0, envelope.budgetUsd - envelope.spentUsd);
|
|
25
|
+
if (envelope.status === "exhausted" || remainingUsd <= 0) {
|
|
26
|
+
throw new failures_1.RigFailureError({
|
|
27
|
+
class: "budget_exhausted",
|
|
28
|
+
message: `watch monthly budget ${key} exhausted ` +
|
|
29
|
+
`($${envelope.spentUsd.toFixed(2)} of $${envelope.budgetUsd.toFixed(2)} spent)`,
|
|
30
|
+
fixHint: "Raise MODELRIG_WATCH_MONTHLY_USD or wait for the next calendar month — " +
|
|
31
|
+
"the watch loop never overruns its cap.",
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return { key, remainingUsd };
|
|
35
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watch diff-evaluators — Phase 4 WS1 (plan §4). Pure: no store, no
|
|
3
|
+
* network, no clock beyond the expiry stamp. Two event classes:
|
|
4
|
+
*
|
|
5
|
+
* price_change — a candidate's pricing moved; when the blended cost shift
|
|
6
|
+
* clears the threshold (default ±10%), every route declaring that
|
|
7
|
+
* candidate gets a suggested bake-off proposal.
|
|
8
|
+
* new_model — a new pricing-map entry on a provider a route already
|
|
9
|
+
* uses → suggested bake-off (the re-probe/bake-off run IS the evidence
|
|
10
|
+
* step; the proposal never claims conformance it hasn't measured).
|
|
11
|
+
*
|
|
12
|
+
* Proposals NEVER execute anything. Idempotency: the trigger hash is a
|
|
13
|
+
* stable digest of (route, trigger content) — re-running a watch cycle over
|
|
14
|
+
* the same facts produces the same hashes, and the control-plane unique
|
|
15
|
+
* index (route, trigger_hash) makes duplicates a no-op.
|
|
16
|
+
*/
|
|
17
|
+
export interface CandidateEconomics {
|
|
18
|
+
readonly provider: string;
|
|
19
|
+
readonly model: string;
|
|
20
|
+
}
|
|
21
|
+
export interface RouteEconomics {
|
|
22
|
+
readonly route: string;
|
|
23
|
+
readonly candidates: readonly CandidateEconomics[];
|
|
24
|
+
}
|
|
25
|
+
export interface TokenRates {
|
|
26
|
+
readonly inputUsdPerTok: number;
|
|
27
|
+
readonly outputUsdPerTok: number;
|
|
28
|
+
}
|
|
29
|
+
export type WatchEvent = {
|
|
30
|
+
readonly type: "price_change";
|
|
31
|
+
readonly provider: string;
|
|
32
|
+
readonly model: string;
|
|
33
|
+
readonly old: TokenRates;
|
|
34
|
+
readonly new: TokenRates;
|
|
35
|
+
} | {
|
|
36
|
+
readonly type: "new_model";
|
|
37
|
+
readonly provider: string;
|
|
38
|
+
readonly model: string;
|
|
39
|
+
readonly pricing: TokenRates | null;
|
|
40
|
+
};
|
|
41
|
+
export interface WatchConfig {
|
|
42
|
+
/** Material-shift threshold in percent (spec default ±10). */
|
|
43
|
+
readonly thresholdPct: number;
|
|
44
|
+
}
|
|
45
|
+
/** Trigger payload persisted on the proposal row (jsonb). */
|
|
46
|
+
export interface ProposalTrigger {
|
|
47
|
+
readonly type: "price_change" | "new_model";
|
|
48
|
+
readonly provider: string;
|
|
49
|
+
readonly model: string;
|
|
50
|
+
/** Blended-cost percent change (price_change only). */
|
|
51
|
+
readonly deltaPct?: number;
|
|
52
|
+
readonly oldRates?: TokenRates;
|
|
53
|
+
readonly newRates?: TokenRates;
|
|
54
|
+
readonly pricing?: TokenRates | null;
|
|
55
|
+
}
|
|
56
|
+
export interface ProposalDraft {
|
|
57
|
+
readonly route: string;
|
|
58
|
+
readonly kind: "bakeoff";
|
|
59
|
+
readonly trigger: ProposalTrigger;
|
|
60
|
+
readonly triggerHash: string;
|
|
61
|
+
readonly expiresAt: string;
|
|
62
|
+
}
|
|
63
|
+
export declare const PROPOSAL_TTL_DAYS = 30;
|
|
64
|
+
export declare function triggerHash(route: string, trigger: ProposalTrigger): string;
|
|
65
|
+
export declare function evaluateEvents(routes: readonly RouteEconomics[], events: readonly WatchEvent[], config: WatchConfig): ProposalDraft[];
|
|
66
|
+
//# sourceMappingURL=evaluate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/watch/evaluate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACpD;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,MAAM,UAAU,GAClB;IACE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;CAC1B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;CACrC,CAAC;AAEN,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,6DAA6D;AAC7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,WAAW,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAYpC,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAE3E;AAMD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,cAAc,EAAE,EACjC,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,MAAM,EAAE,WAAW,GAClB,aAAa,EAAE,CAoDjB"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Watch diff-evaluators — Phase 4 WS1 (plan §4). Pure: no store, no
|
|
4
|
+
* network, no clock beyond the expiry stamp. Two event classes:
|
|
5
|
+
*
|
|
6
|
+
* price_change — a candidate's pricing moved; when the blended cost shift
|
|
7
|
+
* clears the threshold (default ±10%), every route declaring that
|
|
8
|
+
* candidate gets a suggested bake-off proposal.
|
|
9
|
+
* new_model — a new pricing-map entry on a provider a route already
|
|
10
|
+
* uses → suggested bake-off (the re-probe/bake-off run IS the evidence
|
|
11
|
+
* step; the proposal never claims conformance it hasn't measured).
|
|
12
|
+
*
|
|
13
|
+
* Proposals NEVER execute anything. Idempotency: the trigger hash is a
|
|
14
|
+
* stable digest of (route, trigger content) — re-running a watch cycle over
|
|
15
|
+
* the same facts produces the same hashes, and the control-plane unique
|
|
16
|
+
* index (route, trigger_hash) makes duplicates a no-op.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.PROPOSAL_TTL_DAYS = void 0;
|
|
20
|
+
exports.triggerHash = triggerHash;
|
|
21
|
+
exports.evaluateEvents = evaluateEvents;
|
|
22
|
+
const node_crypto_1 = require("node:crypto");
|
|
23
|
+
exports.PROPOSAL_TTL_DAYS = 30;
|
|
24
|
+
/** Reference token mix for blending input/output rates into one comparable
|
|
25
|
+
* number: 3 input tokens per output token — a conservative, route-agnostic
|
|
26
|
+
* default (schema-bound analysis routes run input-heavy). */
|
|
27
|
+
const BLEND_IN = 3;
|
|
28
|
+
const BLEND_OUT = 1;
|
|
29
|
+
function blended(rates) {
|
|
30
|
+
return rates.inputUsdPerTok * BLEND_IN + rates.outputUsdPerTok * BLEND_OUT;
|
|
31
|
+
}
|
|
32
|
+
function triggerHash(route, trigger) {
|
|
33
|
+
return (0, node_crypto_1.createHash)("sha256").update(`${route}\n${JSON.stringify(trigger)}`).digest("hex").slice(0, 32);
|
|
34
|
+
}
|
|
35
|
+
function expiryStamp() {
|
|
36
|
+
return new Date(Date.now() + exports.PROPOSAL_TTL_DAYS * 24 * 3600 * 1000).toISOString();
|
|
37
|
+
}
|
|
38
|
+
function evaluateEvents(routes, events, config) {
|
|
39
|
+
const drafts = [];
|
|
40
|
+
for (const event of events) {
|
|
41
|
+
if (event.type === "price_change") {
|
|
42
|
+
const before = blended(event.old);
|
|
43
|
+
if (before <= 0)
|
|
44
|
+
continue; // nothing sane to compare against
|
|
45
|
+
const deltaPct = ((blended(event.new) - before) / before) * 100;
|
|
46
|
+
if (Math.abs(deltaPct) < config.thresholdPct)
|
|
47
|
+
continue;
|
|
48
|
+
const trigger = {
|
|
49
|
+
type: "price_change",
|
|
50
|
+
provider: event.provider,
|
|
51
|
+
model: event.model,
|
|
52
|
+
deltaPct,
|
|
53
|
+
oldRates: event.old,
|
|
54
|
+
newRates: event.new,
|
|
55
|
+
};
|
|
56
|
+
for (const route of routes) {
|
|
57
|
+
if (!route.candidates.some((c) => c.provider === event.provider && c.model === event.model)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
drafts.push({
|
|
61
|
+
route: route.route,
|
|
62
|
+
kind: "bakeoff",
|
|
63
|
+
trigger,
|
|
64
|
+
triggerHash: triggerHash(route.route, trigger),
|
|
65
|
+
expiresAt: expiryStamp(),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const trigger = {
|
|
71
|
+
type: "new_model",
|
|
72
|
+
provider: event.provider,
|
|
73
|
+
model: event.model,
|
|
74
|
+
pricing: event.pricing,
|
|
75
|
+
};
|
|
76
|
+
for (const route of routes) {
|
|
77
|
+
if (!route.candidates.some((c) => c.provider === event.provider))
|
|
78
|
+
continue;
|
|
79
|
+
// A model the route already declares is not "new" for it.
|
|
80
|
+
if (route.candidates.some((c) => c.provider === event.provider && c.model === event.model)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
drafts.push({
|
|
84
|
+
route: route.route,
|
|
85
|
+
kind: "bakeoff",
|
|
86
|
+
trigger,
|
|
87
|
+
triggerHash: triggerHash(route.route, trigger),
|
|
88
|
+
expiresAt: expiryStamp(),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return drafts;
|
|
94
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proposal lifecycle + control-plane client — Phase 4 WS1 (plan §4).
|
|
3
|
+
*
|
|
4
|
+
* suggested → evidenced (bake-off attached)
|
|
5
|
+
* → approved (human, recorded) → executed (swap machinery)
|
|
6
|
+
* suggested|evidenced → rejected | expired
|
|
7
|
+
*
|
|
8
|
+
* Proposals NEVER auto-execute: "executed" is only reachable through
|
|
9
|
+
* "approved", and approval is a human CLI action (`swap execute --approve`).
|
|
10
|
+
* Transport is PostgREST with the service-role key — proposals are
|
|
11
|
+
* control-plane-only state (cross-run truth, not per-inference telemetry).
|
|
12
|
+
*/
|
|
13
|
+
import type { ProposalDraft, ProposalTrigger } from "./evaluate";
|
|
14
|
+
export type ProposalStatus = "suggested" | "evidenced" | "approved" | "rejected" | "executed" | "expired";
|
|
15
|
+
export declare function assertTransition(from: ProposalStatus, to: ProposalStatus): void;
|
|
16
|
+
export interface ProposalRecord {
|
|
17
|
+
readonly id: string;
|
|
18
|
+
readonly route: string;
|
|
19
|
+
readonly kind: "bakeoff" | "swap";
|
|
20
|
+
readonly trigger: ProposalTrigger;
|
|
21
|
+
readonly triggerHash: string;
|
|
22
|
+
readonly evidence: Record<string, unknown> | null;
|
|
23
|
+
readonly status: ProposalStatus;
|
|
24
|
+
readonly createdAt: string;
|
|
25
|
+
readonly updatedAt: string;
|
|
26
|
+
readonly expiresAt: string;
|
|
27
|
+
/** Who approved or rejected (A1.2). Null while undecided. */
|
|
28
|
+
readonly approvedBy: string | null;
|
|
29
|
+
/** When the decision was recorded — NOT when a swap executed. */
|
|
30
|
+
readonly decidedAt: string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface ProposalsClientConfig {
|
|
33
|
+
readonly supabaseUrl: string;
|
|
34
|
+
readonly serviceRoleKey: string;
|
|
35
|
+
readonly fetchFn?: typeof fetch;
|
|
36
|
+
}
|
|
37
|
+
export interface ProposalsClient {
|
|
38
|
+
/** Insert drafts; duplicates on (route, trigger_hash) are silent no-ops.
|
|
39
|
+
* Returns how many rows the control plane actually created. */
|
|
40
|
+
submitDrafts(drafts: readonly ProposalDraft[]): Promise<number>;
|
|
41
|
+
/**
|
|
42
|
+
* List proposals for ONE org, or across all of them.
|
|
43
|
+
*
|
|
44
|
+
* `orgId` is required and `null` is the explicit "every org" case, used by
|
|
45
|
+
* the CLI and by self-host deployments where there is exactly one. An
|
|
46
|
+
* OPTIONAL parameter would have been the same code with a worse failure
|
|
47
|
+
* mode: the unscoped read this replaces was unscoped because nobody passed
|
|
48
|
+
* anything, and an omitted argument reads as an oversight while an explicit
|
|
49
|
+
* null reads as a decision (C6 review ruling §7.2).
|
|
50
|
+
*/
|
|
51
|
+
list(orgId: string | null, status?: ProposalStatus): Promise<ProposalRecord[]>;
|
|
52
|
+
get(id: string): Promise<ProposalRecord | null>;
|
|
53
|
+
/** Bake-off evidence + the suggested→evidenced flip, one PATCH. */
|
|
54
|
+
attachEvidence(id: string, evidence: Record<string, unknown>): Promise<void>;
|
|
55
|
+
/** Validated status change (assertTransition is the caller's guard for
|
|
56
|
+
* reads-before-writes; the PATCH is still status-scoped server-side). */
|
|
57
|
+
setStatus(id: string, from: ProposalStatus, to: ProposalStatus): Promise<void>;
|
|
58
|
+
/** A HUMAN decision on a proposal — addendum A1.2. Records who decided and
|
|
59
|
+
* when alongside the status flip, in one status-scoped PATCH.
|
|
60
|
+
*
|
|
61
|
+
* Approving is NOT executing: this writes a decision, never a swap_event.
|
|
62
|
+
* The swap still happens at a CLI (`modelrig swap execute --approve`) and
|
|
63
|
+
* the YAML it emits is still applied by git. Returns false when the row had
|
|
64
|
+
* already moved on (a concurrent decision), so the caller can say so
|
|
65
|
+
* instead of reporting a success that did not happen. */
|
|
66
|
+
/** The org that owns this proposal — the tenant a write must be authorized against. */
|
|
67
|
+
orgOf(id: string): Promise<string | null>;
|
|
68
|
+
decide(id: string, from: ProposalStatus, to: "approved" | "rejected", decidedBy: string, decidedByUserId?: string | null, orgId?: string): Promise<boolean>;
|
|
69
|
+
/** One sweep: overdue suggested/evidenced → expired. */
|
|
70
|
+
expireOverdue(now: Date): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
export declare function createProposalsClient(config: ProposalsClientConfig): ProposalsClient;
|
|
73
|
+
//# sourceMappingURL=proposals.d.ts.map
|