pi-mega-compact 0.20.70 → 0.20.71
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/dist/extensions/dashboard-server/routes-vector-cortex-crystals.js +45 -30
- package/dist/extensions/dashboard-server/routes-vector-cortex-diagnostics.js +50 -29
- package/dist/extensions/dashboard-server/routes-vector-cortex-economics.js +33 -20
- package/dist/extensions/dashboard-server/routes-vector-cortex-helpers.js +54 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-policy.js +33 -16
- package/dist/src/vector-cortex/cache/store.js +25 -2
- package/dist/src/vector-cortex/encoder/asset.js +34 -2
- package/dist/src/vector-cortex/encoder/router.js +31 -3
- package/dist/src/vector-cortex/livewire/livewire-live.js +163 -0
- package/dist/src/vector-cortex/livewire/livewire-registry.js +73 -0
- package/dist/src/vector-cortex/livewire/livewire-runtime.js +107 -0
- package/dist/src/vector-cortex/livewire/livewire-snapshot.js +101 -0
- package/dist/src/vector-cortex/livewire/livewire-types.js +19 -0
- package/dist/src/vector-cortex/provider/registry.js +44 -12
- package/dist/vector-cortex/cache/store.js +25 -2
- package/dist/vector-cortex/encoder/asset.js +34 -2
- package/dist/vector-cortex/encoder/router.js +31 -3
- package/dist/vector-cortex/provider/registry.js +44 -12
- package/extensions/dashboard-server/routes-vector-cortex-crystals.ts +46 -30
- package/extensions/dashboard-server/routes-vector-cortex-diagnostics.ts +52 -29
- package/extensions/dashboard-server/routes-vector-cortex-economics.ts +35 -20
- package/extensions/dashboard-server/routes-vector-cortex-helpers.ts +84 -0
- package/extensions/dashboard-server/routes-vector-cortex-policy.ts +35 -16
- package/package.json +1 -1
- package/src/vector-cortex/cache/store.ts +26 -2
- package/src/vector-cortex/encoder/asset.ts +46 -3
- package/src/vector-cortex/encoder/router.ts +56 -2
- package/src/vector-cortex/encoder/types.ts +3 -0
- package/src/vector-cortex/livewire/livewire-live.ts +223 -0
- package/src/vector-cortex/livewire/livewire-registry.ts +91 -0
- package/src/vector-cortex/livewire/livewire-runtime.ts +117 -0
- package/src/vector-cortex/livewire/livewire-snapshot.ts +108 -0
- package/src/vector-cortex/livewire/livewire-types.ts +84 -0
- package/src/vector-cortex/provider/economics.ts +9 -31
- package/src/vector-cortex/provider/registry.ts +82 -11
- package/src/vector-cortex/provider/types.ts +37 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/livewire/livewire-snapshot.ts — LIVEWIRE aggregate persistence.
|
|
3
|
+
*
|
|
4
|
+
* The four LV subsytems are in-process live objects, but the dashboard server may
|
|
5
|
+
* run in a SEPARATE process from the runtime that accumulates the counts. To keep
|
|
6
|
+
* the reader-only routes honest when they run in their own process, this module
|
|
7
|
+
* persists a COUNT-ONLY aggregate snapshot (`vector-cortex-livewire.json`) to the
|
|
8
|
+
* per-repo `stateDir`, and `openLivewire` rehydrates a fresh process from it on
|
|
9
|
+
* first access. This is the same DR-snapshot philosophy as the legacy JSON
|
|
10
|
+
* checkpoints, but reduced to counts + codes (SECURITY_PRIVACY — see these types).
|
|
11
|
+
*
|
|
12
|
+
* BEST-EFFORT + NON-FATAL. A failed write is logged as a structured event and
|
|
13
|
+
* never breaks the agent loop; a missing/unreadable snapshot reads as null and
|
|
14
|
+
* the process starts from zero (matches the non-fatal-stores invariant). Every
|
|
15
|
+
* write is atomic-ish: the JSON is fully serialized to a temp name then renamed
|
|
16
|
+
* so a reader never observes a partial snapshot.
|
|
17
|
+
*
|
|
18
|
+
* PREVENT-PI-004: local filesystem read/write only, no network. PREVENT-011: no
|
|
19
|
+
* `any`.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
import type { LivewireSnapshot } from "./livewire-types.js";
|
|
25
|
+
|
|
26
|
+
/** The snapshot filename in the per-repo stateDir (counts + codes only). */
|
|
27
|
+
export const LIVEWIRE_SNAPSHOT_FILE = "vector-cortex-livewire.json";
|
|
28
|
+
|
|
29
|
+
/** Resolve the snapshot path for a stateDir. */
|
|
30
|
+
export function livewireSnapshotPath(stateDir: string): string {
|
|
31
|
+
return join(stateDir, LIVEWIRE_SNAPSHOT_FILE);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Best-effort type guard over a parsed snapshot. Rejects anything that is not
|
|
36
|
+
* the exact aggregate shape so a corrupted or stale file cannot poison the
|
|
37
|
+
* rehydrated counters.
|
|
38
|
+
*/
|
|
39
|
+
function isSnapshot(value: unknown): value is LivewireSnapshot {
|
|
40
|
+
if (typeof value !== "object" || value === null) return false;
|
|
41
|
+
const s = value as Record<string, unknown>;
|
|
42
|
+
return (
|
|
43
|
+
s.schema === "vector-cortex-livewire-v1" &&
|
|
44
|
+
typeof s.crystals === "object" &&
|
|
45
|
+
s.crystals !== null &&
|
|
46
|
+
typeof s.diagnostics === "object" &&
|
|
47
|
+
s.diagnostics !== null &&
|
|
48
|
+
typeof s.economics === "object" &&
|
|
49
|
+
s.economics !== null &&
|
|
50
|
+
typeof s.policy === "object" &&
|
|
51
|
+
s.policy !== null
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Read the persisted aggregate for a stateDir, or null when absent/unreadable/
|
|
57
|
+
* malformed. Best-effort and non-fatal by construction.
|
|
58
|
+
*/
|
|
59
|
+
export function loadLivewireSnapshot(stateDir: string): LivewireSnapshot | null {
|
|
60
|
+
const path = livewireSnapshotPath(stateDir);
|
|
61
|
+
let raw: string;
|
|
62
|
+
try {
|
|
63
|
+
raw = readFileSync(path, "utf-8");
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const parsed: unknown = JSON.parse(raw);
|
|
69
|
+
return isSnapshot(parsed) ? parsed : null;
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Best-effort write of the aggregate snapshot (atomic rename). Never throws to
|
|
77
|
+
* the caller: a persistence failure logs a structured event and is swallowed.
|
|
78
|
+
*
|
|
79
|
+
* @param logger optional structured logger `(line: unknown) => void`; when
|
|
80
|
+
* omitted no event is emitted (tests pass `undefined`).
|
|
81
|
+
*/
|
|
82
|
+
export function saveLivewireSnapshot(
|
|
83
|
+
stateDir: string,
|
|
84
|
+
snapshot: LivewireSnapshot,
|
|
85
|
+
logger?: (line: unknown) => void,
|
|
86
|
+
): void {
|
|
87
|
+
const dir = stateDir;
|
|
88
|
+
try {
|
|
89
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
90
|
+
const path = livewireSnapshotPath(dir);
|
|
91
|
+
const tmp = `${path}.tmp`;
|
|
92
|
+
writeFileSync(tmp, JSON.stringify(snapshot), "utf-8");
|
|
93
|
+
renameSync(tmp, path);
|
|
94
|
+
} catch (err) {
|
|
95
|
+
if (logger !== undefined) {
|
|
96
|
+
try {
|
|
97
|
+
logger({
|
|
98
|
+
ts: new Date().toISOString(),
|
|
99
|
+
event: "vector_cortex_livewire_snapshot_write_failed",
|
|
100
|
+
stateDir,
|
|
101
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
102
|
+
});
|
|
103
|
+
} catch {
|
|
104
|
+
// A failing logger must not recurse into another failure.
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/livewire/livewire-types.ts — LIVEWIRE aggregate snapshot types.
|
|
3
|
+
*
|
|
4
|
+
* LIVEWIRE wires the four complete-but-unwired Vector Cortex subsystems into the
|
|
5
|
+
* runtime so their dashboard routes report LIVE state instead of hardcoded
|
|
6
|
+
* "deferred" zeros. This module is the SINGLE SOURCE OF TRUTH for the persisted
|
|
7
|
+
* aggregate snapshot shape (counts + codes ONLY) and for the per-stateDir
|
|
8
|
+
* live-state records the routes read.
|
|
9
|
+
*
|
|
10
|
+
* SECURITY_PRIVACY: every field here is a count, a code, or a finite triad mode.
|
|
11
|
+
* There is deliberately NO string slot for a session id, a request/crystal
|
|
12
|
+
* digest, a covered range, frozen bytes, a profile id, or ledger content — a
|
|
13
|
+
* crystal IS a frozen rendered prompt, so the card that reports on it must never
|
|
14
|
+
* be able to carry one. The snapshot is the SAME reduced shape, so nothing secret
|
|
15
|
+
* reaches disk either.
|
|
16
|
+
*
|
|
17
|
+
* PREVENT-PI-004: type definitions only, no network code. PREVENT-011: no `any`.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** Triad mode shared by the crystals / diagnostics / economics cards. */
|
|
21
|
+
export type LivewireMode = "A" | "B" | "C";
|
|
22
|
+
|
|
23
|
+
/** VC7A crystal aggregate — mirrors `CrystalStoreStats` one-for-one. */
|
|
24
|
+
export interface LivewireCrystalAggregate {
|
|
25
|
+
readonly mode: LivewireMode;
|
|
26
|
+
readonly crystalCount: number;
|
|
27
|
+
readonly totalBytes: number;
|
|
28
|
+
readonly hits: number;
|
|
29
|
+
readonly misses: number;
|
|
30
|
+
readonly hitBytes: number;
|
|
31
|
+
readonly writes: number;
|
|
32
|
+
readonly duplicateWrites: number;
|
|
33
|
+
readonly collisions: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** VC7C per-miss-class tallies + breaker observable state. */
|
|
37
|
+
export interface LivewireDiagnosticsAggregate {
|
|
38
|
+
readonly profileMisses: number;
|
|
39
|
+
readonly rangeMisses: number;
|
|
40
|
+
readonly dependencyMisses: number;
|
|
41
|
+
readonly requestMisses: number;
|
|
42
|
+
readonly generationMisses: number;
|
|
43
|
+
readonly unknownMisses: number;
|
|
44
|
+
readonly serveBlocked: number;
|
|
45
|
+
/** Breaker observable state name (CLOSED_A / OPEN_B / ... / MANUAL_HALT). */
|
|
46
|
+
readonly breakerState: string;
|
|
47
|
+
/** Last CACHE/M5 code, or null. */
|
|
48
|
+
readonly lastFailure: string | null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** VC7B economics aggregate — static profile tallies + computed bit. */
|
|
52
|
+
export interface LivewireEconomicsAggregate {
|
|
53
|
+
/** Provider profiles that declare cache economics. */
|
|
54
|
+
readonly profileCount: number;
|
|
55
|
+
/** Exclusions that carry a proving fixture id. */
|
|
56
|
+
readonly provenExclusions: number;
|
|
57
|
+
/** Exclusions rejected for lacking a fixture id. */
|
|
58
|
+
readonly unprovenExclusions: number;
|
|
59
|
+
/** True once the runtime has actually run `computeEconomics` at least once. */
|
|
60
|
+
readonly computed: boolean;
|
|
61
|
+
/** Last ECON_* code, or null. */
|
|
62
|
+
readonly lastFailure: string | null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** VC8B shadow-policy aggregate — maps 1:1 to the policy card fields. */
|
|
66
|
+
export interface LivewirePolicyAggregate {
|
|
67
|
+
readonly shadowDecisions: number;
|
|
68
|
+
readonly clampedDecisions: number;
|
|
69
|
+
readonly rejectedInputs: number;
|
|
70
|
+
readonly liveMutations: number;
|
|
71
|
+
/** Active pressure version (1 legacy / 2 migrated). */
|
|
72
|
+
readonly pressureVersion: 1 | 2;
|
|
73
|
+
/** Last POL_ or M7_ code, or null. */
|
|
74
|
+
readonly lastFailure: string | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The persisted, restart-surviving aggregate for one stateDir. */
|
|
78
|
+
export interface LivewireSnapshot {
|
|
79
|
+
readonly schema: "vector-cortex-livewire-v1";
|
|
80
|
+
readonly crystals: LivewireCrystalAggregate;
|
|
81
|
+
readonly diagnostics: LivewireDiagnosticsAggregate;
|
|
82
|
+
readonly economics: LivewireEconomicsAggregate;
|
|
83
|
+
readonly policy: LivewirePolicyAggregate;
|
|
84
|
+
}
|
|
@@ -47,38 +47,16 @@
|
|
|
47
47
|
* gates only the reporter/dashboard seam in `../cache/economics-emit.ts`.
|
|
48
48
|
*/
|
|
49
49
|
|
|
50
|
-
import type {
|
|
50
|
+
import type {
|
|
51
|
+
ProviderEconomicsV1,
|
|
52
|
+
ProviderProfileExclusion,
|
|
53
|
+
ProviderProfileV1,
|
|
54
|
+
} from "./types.js";
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* charging $3.00 per million input tokens has `basePrice: 3`. Integers keep the
|
|
57
|
-
* money path exact; see the file header for why floats are refused.
|
|
58
|
-
*/
|
|
59
|
-
export interface ProviderEconomicsV1 {
|
|
60
|
-
readonly schema: "provider-economics-v1";
|
|
61
|
-
/** The `ProviderProfileV1.id` these economics belong to. */
|
|
62
|
-
readonly profileId: string;
|
|
63
|
-
/** Profile version — economics are versioned WITH the profile they price. */
|
|
64
|
-
readonly profileVersion: string;
|
|
65
|
-
/** Uncached price per token, integer micro-units. The savings baseline. */
|
|
66
|
-
readonly basePrice: number;
|
|
67
|
-
/** Cache-READ price per token, integer micro-units. Normally < basePrice. */
|
|
68
|
-
readonly readPrice: number;
|
|
69
|
-
/** Cache-WRITE price per token, integer micro-units. Normally > basePrice. */
|
|
70
|
-
readonly writePrice: number;
|
|
71
|
-
/** Cache entry lifetime in ms. A prefix older than this cannot be read back. */
|
|
72
|
-
readonly ttlMs: number;
|
|
73
|
-
/** Minimum cacheable prefix in tokens; a shorter prefix is never cached. */
|
|
74
|
-
readonly minPrefix: number;
|
|
75
|
-
/**
|
|
76
|
-
* Conformance fixture ID proving this profile's exclusion set is safe, or
|
|
77
|
-
* `null` when the profile declares NO exclusions (nothing to prove). A profile
|
|
78
|
-
* WITH exclusions and a null/blank id is rejected — see `validateEconomics`.
|
|
79
|
-
*/
|
|
80
|
-
readonly exclusionFixtureId: string | null;
|
|
81
|
-
}
|
|
56
|
+
// `ProviderEconomicsV1` is defined in `./types.js` so it can ride on
|
|
57
|
+
// `ProviderProfileV1` without a type-only module cycle. Re-exported forward here
|
|
58
|
+
// so every existing consumer import path (`from "./economics.js"`) is unchanged.
|
|
59
|
+
export type { ProviderEconomicsV1 } from "./types.js";
|
|
82
60
|
|
|
83
61
|
/** Observed (or shadow) cache traffic for one economics computation. */
|
|
84
62
|
export interface CacheUsageV1 {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import {
|
|
20
20
|
PRO_PROFILE_UNKNOWN,
|
|
21
|
+
type ProviderEconomicsV1,
|
|
21
22
|
type ProviderProfileBundle,
|
|
22
23
|
type ProviderProfileResult,
|
|
23
24
|
type ProviderProfileV1,
|
|
@@ -60,6 +61,7 @@ function profile(
|
|
|
60
61
|
id: string,
|
|
61
62
|
version: string,
|
|
62
63
|
excludedJsonPointers: ProviderProfileV1["excludedJsonPointers"],
|
|
64
|
+
economics: ProviderProfileV1["economics"],
|
|
63
65
|
): ProviderProfileV1 {
|
|
64
66
|
return {
|
|
65
67
|
schema: "provider-profile-v1",
|
|
@@ -67,42 +69,111 @@ function profile(
|
|
|
67
69
|
version,
|
|
68
70
|
hashMode: "entire-canonical-request",
|
|
69
71
|
excludedJsonPointers,
|
|
72
|
+
economics,
|
|
70
73
|
};
|
|
71
74
|
}
|
|
72
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Build integer micro-unit economics for a base profile (VC7B). A cache WRITE
|
|
78
|
+
* costs more than an uncached token, a cache READ costs less — the standard
|
|
79
|
+
* provider-prompt-cache shape. `exclusionFixtureId` mirrors the profile's own
|
|
80
|
+
* exclusion fixture (or null when the profile has none to prove).
|
|
81
|
+
*/
|
|
82
|
+
function econ(
|
|
83
|
+
id: string,
|
|
84
|
+
version: string,
|
|
85
|
+
exclusionFixtureId: string | null,
|
|
86
|
+
values: {
|
|
87
|
+
basePrice: number;
|
|
88
|
+
readPrice: number;
|
|
89
|
+
writePrice: number;
|
|
90
|
+
ttlMs: number;
|
|
91
|
+
minPrefix: number;
|
|
92
|
+
},
|
|
93
|
+
): ProviderEconomicsV1 {
|
|
94
|
+
return {
|
|
95
|
+
schema: "provider-economics-v1",
|
|
96
|
+
profileId: id,
|
|
97
|
+
profileVersion: version,
|
|
98
|
+
basePrice: values.basePrice,
|
|
99
|
+
readPrice: values.readPrice,
|
|
100
|
+
writePrice: values.writePrice,
|
|
101
|
+
ttlMs: values.ttlMs,
|
|
102
|
+
minPrefix: values.minPrefix,
|
|
103
|
+
exclusionFixtureId,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Representative integer micro-unit economics for the Anthropic opus base tier. */
|
|
108
|
+
const OPUS_ECON: ProviderEconomicsV1 = econ(
|
|
109
|
+
"anthropic-claude-opus",
|
|
110
|
+
"v1",
|
|
111
|
+
null,
|
|
112
|
+
{ basePrice: 15, readPrice: 2, writePrice: 19, ttlMs: 300_000, minPrefix: 1024 },
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
/** Representative integer micro-unit economics for the Anthropic sonnet base tier. */
|
|
116
|
+
const SONNET_ECON: ProviderEconomicsV1 = econ(
|
|
117
|
+
"anthropic-claude-sonnet",
|
|
118
|
+
"v1",
|
|
119
|
+
null,
|
|
120
|
+
{ basePrice: 3, readPrice: 0, writePrice: 4, ttlMs: 300_000, minPrefix: 1024 },
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
/** Representative integer micro-unit economics for the OpenAI gpt base tier. */
|
|
124
|
+
const GPT_ECON: ProviderEconomicsV1 = econ(
|
|
125
|
+
"openai-gpt",
|
|
126
|
+
"v1",
|
|
127
|
+
null,
|
|
128
|
+
{ basePrice: 5, readPrice: 1, writePrice: 6, ttlMs: 300_000, minPrefix: 1024 },
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
/** The gemini profile's versioned, fixture-proven exclusion. */
|
|
132
|
+
const GEMINI_EXCLUSIONS: ProviderProfileV1["excludedJsonPointers"] = [
|
|
133
|
+
{
|
|
134
|
+
pointer: "/requestId",
|
|
135
|
+
fixtureId: "PRO-EXCLUDE-010",
|
|
136
|
+
proofDigest: "sha256:excluded-request-id-proof",
|
|
137
|
+
},
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
/** Representative integer micro-unit economics for the gemini base tier. */
|
|
141
|
+
const GEMINI_ECON: ProviderEconomicsV1 = econ(
|
|
142
|
+
"google-gemini",
|
|
143
|
+
"v1",
|
|
144
|
+
"PRO-EXCLUDE-010",
|
|
145
|
+
{ basePrice: 3, readPrice: 1, writePrice: 4, ttlMs: 300_000, minPrefix: 1024 },
|
|
146
|
+
);
|
|
147
|
+
|
|
73
148
|
/**
|
|
74
149
|
* The fixture-backed base profiles. Each entry is the REAL bundle the renderer
|
|
75
150
|
* resolves; the parallel conformance fixtures prove the cache-identity behavior.
|
|
76
151
|
*/
|
|
77
152
|
const BASE_PROFILES: readonly ProviderProfileBundle[] = [
|
|
78
153
|
{
|
|
79
|
-
profile: profile("anthropic-claude-opus", "v1", []),
|
|
154
|
+
profile: profile("anthropic-claude-opus", "v1", [], OPUS_ECON),
|
|
80
155
|
role: BASE_ROLE,
|
|
81
156
|
tool: BASE_TOOL,
|
|
82
157
|
cache: baseCache(["systemPromptPrepend", "tools", "nodes"]),
|
|
83
158
|
},
|
|
84
159
|
{
|
|
85
|
-
profile: profile("anthropic-claude-sonnet", "v1", []),
|
|
160
|
+
profile: profile("anthropic-claude-sonnet", "v1", [], SONNET_ECON),
|
|
86
161
|
role: BASE_ROLE,
|
|
87
162
|
tool: BASE_TOOL,
|
|
88
163
|
cache: baseCache(["systemPromptPrepend", "tools", "nodes"]),
|
|
89
164
|
},
|
|
90
165
|
{
|
|
91
|
-
profile: profile("openai-gpt", "v1", []),
|
|
166
|
+
profile: profile("openai-gpt", "v1", [], GPT_ECON),
|
|
92
167
|
role: BASE_ROLE,
|
|
93
168
|
tool: BASE_TOOL,
|
|
94
169
|
cache: baseCache(["systemPromptPrepend", "tools", "nodes"]),
|
|
95
170
|
},
|
|
96
171
|
{
|
|
97
172
|
// A profile that proves a fixture-excluded pointer: a provider whose
|
|
98
|
-
// request-id header cannot affect cache identity. Excluded + versioned
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
fixtureId: "PRO-EXCLUDE-010",
|
|
103
|
-
proofDigest: "sha256:excluded-request-id-proof",
|
|
104
|
-
},
|
|
105
|
-
]),
|
|
173
|
+
// request-id header cannot affect cache identity. Excluded + versioned, and
|
|
174
|
+
// the exclusion fixture id is carried into economics so the proof is
|
|
175
|
+
// honored (an unproven exclusion would fail economics validation).
|
|
176
|
+
profile: profile("google-gemini", "v1", GEMINI_EXCLUSIONS, GEMINI_ECON),
|
|
106
177
|
role: BASE_ROLE,
|
|
107
178
|
tool: BASE_TOOL,
|
|
108
179
|
cache: baseCache(["systemPromptPrepend", "tools", "nodes"]),
|
|
@@ -35,6 +35,37 @@ export interface ProviderProfileExclusion {
|
|
|
35
35
|
readonly proofDigest: string;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Cache economics attached to a provider profile (VC7B).
|
|
40
|
+
*
|
|
41
|
+
* Prices are integer MICRO-UNITS PER TOKEN (1e-6 currency units), so a provider
|
|
42
|
+
* charging $3.00 per million input tokens has `basePrice: 3`. Integers keep the
|
|
43
|
+
* money path exact (see `economics.ts` for why floats are refused).
|
|
44
|
+
*/
|
|
45
|
+
export interface ProviderEconomicsV1 {
|
|
46
|
+
readonly schema: "provider-economics-v1";
|
|
47
|
+
/** The `ProviderProfileV1.id` these economics belong to. */
|
|
48
|
+
readonly profileId: string;
|
|
49
|
+
/** Profile version — economics are versioned WITH the profile they price. */
|
|
50
|
+
readonly profileVersion: string;
|
|
51
|
+
/** Uncached price per token, integer micro-units. The savings baseline. */
|
|
52
|
+
readonly basePrice: number;
|
|
53
|
+
/** Cache-READ price per token, integer micro-units. Normally < basePrice. */
|
|
54
|
+
readonly readPrice: number;
|
|
55
|
+
/** Cache-WRITE price per token, integer micro-units. Normally > basePrice. */
|
|
56
|
+
readonly writePrice: number;
|
|
57
|
+
/** Cache entry lifetime in ms. A prefix older than this cannot be read back. */
|
|
58
|
+
readonly ttlMs: number;
|
|
59
|
+
/** Minimum cacheable prefix in tokens; a shorter prefix is never cached. */
|
|
60
|
+
readonly minPrefix: number;
|
|
61
|
+
/**
|
|
62
|
+
* Conformance fixture ID proving this profile's exclusion set is safe, or
|
|
63
|
+
* `null` when the profile declares NO exclusions (nothing to prove). A profile
|
|
64
|
+
* WITH exclusions and a null/blank id is rejected — see `validateEconomics`.
|
|
65
|
+
*/
|
|
66
|
+
readonly exclusionFixtureId: string | null;
|
|
67
|
+
}
|
|
68
|
+
|
|
38
69
|
/**
|
|
39
70
|
* The provider-profile contract. A renderer consumes a profile to decide how the
|
|
40
71
|
* rendered prompt is serialized into the canonical outbound request without
|
|
@@ -47,6 +78,12 @@ export interface ProviderProfileV1 {
|
|
|
47
78
|
readonly hashMode: ProviderHashMode;
|
|
48
79
|
/** Versioned, fixture-proven exclusions (empty = hash the whole request). */
|
|
49
80
|
readonly excludedJsonPointers: readonly ProviderProfileExclusion[];
|
|
81
|
+
/**
|
|
82
|
+
* VC7B cache economics pricing this profile's frozen-render reuse. Every base
|
|
83
|
+
* profile carries economics so the cache-economics aggregate is computable
|
|
84
|
+
* without a side table; a profile WITHOUT economics is simply never cached.
|
|
85
|
+
*/
|
|
86
|
+
readonly economics: ProviderEconomicsV1 | null;
|
|
50
87
|
}
|
|
51
88
|
|
|
52
89
|
/**
|