@warmdrift/kgauto-compiler 2.0.0-alpha.7 → 2.0.0-alpha.70
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 +176 -46
- package/dist/brain-proxy.d.mts +113 -0
- package/dist/brain-proxy.d.ts +113 -0
- package/dist/brain-proxy.js +193 -0
- package/dist/brain-proxy.mjs +6 -0
- package/dist/chunk-4UO4CCSP.mjs +1620 -0
- package/dist/chunk-65ZMX5OT.mjs +169 -0
- package/dist/{chunk-5TI6PNSK.mjs → chunk-BVEXV5KC.mjs} +11 -0
- package/dist/chunk-FR4DNGLW.mjs +203 -0
- package/dist/chunk-NBO4R5PC.mjs +313 -0
- package/dist/chunk-P3TOAEG4.mjs +56 -0
- package/dist/chunk-RO22VFIF.mjs +29 -0
- package/dist/chunk-SBFSYCQG.mjs +719 -0
- package/dist/dialect.d.mts +41 -3
- package/dist/dialect.d.ts +41 -3
- package/dist/dialect.js +14 -2
- package/dist/dialect.mjs +5 -3
- package/dist/glassbox/index.d.mts +59 -0
- package/dist/glassbox/index.d.ts +59 -0
- package/dist/glassbox/index.js +312 -0
- package/dist/glassbox/index.mjs +12 -0
- package/dist/glassbox-routes/format.d.mts +24 -0
- package/dist/glassbox-routes/format.d.ts +24 -0
- package/dist/glassbox-routes/format.js +86 -0
- package/dist/glassbox-routes/format.mjs +18 -0
- package/dist/glassbox-routes/index.d.mts +191 -0
- package/dist/glassbox-routes/index.d.ts +191 -0
- package/dist/glassbox-routes/index.js +2888 -0
- package/dist/glassbox-routes/index.mjs +667 -0
- package/dist/glassbox-routes/react/index.d.mts +74 -0
- package/dist/glassbox-routes/react/index.d.ts +74 -0
- package/dist/glassbox-routes/react/index.js +819 -0
- package/dist/glassbox-routes/react/index.mjs +754 -0
- package/dist/index.d.mts +2739 -17
- package/dist/index.d.ts +2739 -17
- package/dist/index.js +8989 -1659
- package/dist/index.mjs +5078 -367
- package/dist/ir-Bqn1RVdV.d.mts +1583 -0
- package/dist/ir-Bvlkw5ja.d.ts +1583 -0
- package/dist/key-health.d.mts +131 -0
- package/dist/key-health.d.ts +131 -0
- package/dist/key-health.js +228 -0
- package/dist/key-health.mjs +6 -0
- package/dist/profiles.d.mts +292 -2
- package/dist/profiles.d.ts +292 -2
- package/dist/profiles.js +1231 -16
- package/dist/profiles.mjs +9 -1
- package/dist/types-Bon96eyc.d.ts +131 -0
- package/dist/types-CwGhacGT.d.mts +149 -0
- package/dist/types-DIxRZ3Dj.d.ts +149 -0
- package/dist/types-DsEq35WY.d.mts +131 -0
- package/package.json +54 -8
- package/dist/chunk-MBEI5UOM.mjs +0 -409
- package/dist/profiles-B3eNQ2py.d.ts +0 -619
- package/dist/profiles-Py8c7zjJ.d.mts +0 -619
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
|
|
1
|
+
import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, B as BestPracticeAdvisory, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-Bvlkw5ja.js';
|
|
2
|
+
export { m as CallAttempt, n as CallError, o as ChainModelEntry, p as ChainWithGrounding, q as Constraints, E as EffortLevel, F as FallbackReason, r as GoldenCaptureOptions, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, s as MutationApplied, t as NormalizedTokens, u as OutcomeKind, v as PerAxisMetricsByModel, w as PromptSection, x as SectionKind, y as ShadowProbeConfig, T as ToolCall, z as ToolDefinition, D as captureGoldenIr, J as parseGoldenCaptureRate, K as resolveGoldenCaptureRate, L as shouldCaptureGolden } from './ir-Bvlkw5ja.js';
|
|
3
|
+
import { ModelProfile, ArchetypeConvention } from './profiles.js';
|
|
4
|
+
export { ALIASES, CacheStrategy, CliffRule, LATENCY_TIER_MS, LatencyTier, LoweringSpec, RecoveryRule, StructuredOutputCapability, SystemPromptMode, allProfiles, getProfile, latencyTierOf, profilesByProvider, tryGetProfile } from './profiles.js';
|
|
5
|
+
export { BrainForwardConfig, BrainForwardRoutes, createBrainForwardRoutes } from './brain-proxy.js';
|
|
6
|
+
export { KeyHealthConfig, KeyHealthProvider, KeyHealthResponseBody, KeyHealthResult, KeyHealthRoute, createKeyHealthRoute } from './key-health.js';
|
|
7
|
+
import { IntentArchetypeName, OutputMode } from './dialect.js';
|
|
8
|
+
export { ALL_ARCHETYPES, ContextBucket, DIALECT_VERSION, HistoryDepth, INTENT_ARCHETYPES, ShapeSignature, ToolCountBucket, bucketContext, bucketHistory, bucketToolCount, hashShape, isArchetype, learningKey } from './dialect.js';
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* compile() — the main orchestrator.
|
|
@@ -33,6 +38,15 @@ interface CompileOptions {
|
|
|
33
38
|
* ceiling, boosts preferred. See CompilePolicy in ir.ts.
|
|
34
39
|
*/
|
|
35
40
|
policy?: CompilePolicy;
|
|
41
|
+
/**
|
|
42
|
+
* alpha.68 / Release A (delegation-fanout-accelerator §5.0, R0 linkage) —
|
|
43
|
+
* transport for the fan-out parent handle. Threaded from
|
|
44
|
+
* `CallOptions.parentHandle` on the call() path (and settable directly on the
|
|
45
|
+
* public compile() path). Release A does NOT route on it — it only labels the
|
|
46
|
+
* outcome row (fanout_role / trace_id / parent_handle) at record-registration
|
|
47
|
+
* time. `registerCompile` reads it to derive the linkage. Absent ⇒ root call.
|
|
48
|
+
*/
|
|
49
|
+
parentHandle?: string;
|
|
36
50
|
}
|
|
37
51
|
|
|
38
52
|
/**
|
|
@@ -51,6 +65,15 @@ interface ExecuteOptions {
|
|
|
51
65
|
apiKeys?: ApiKeys;
|
|
52
66
|
fetchImpl?: typeof fetch;
|
|
53
67
|
providerOverrides?: ProviderOverrides;
|
|
68
|
+
/**
|
|
69
|
+
* alpha.34. When supplied AND the chosen provider supports streaming, the
|
|
70
|
+
* execute() per-provider branch switches to SSE wire format and invokes
|
|
71
|
+
* `onChunk(delta)` once per text-delta event. Single-shot behavior
|
|
72
|
+
* preserved when omitted (current consumers unaffected). Wired from
|
|
73
|
+
* `CallOptions.onChunk` by `call()` after gating on `profile.streaming`
|
|
74
|
+
* and `!opts.noStream`.
|
|
75
|
+
*/
|
|
76
|
+
onChunk?: (chunk: string) => void;
|
|
54
77
|
}
|
|
55
78
|
interface ExecuteOk {
|
|
56
79
|
ok: true;
|
|
@@ -64,6 +87,19 @@ interface ExecuteErr {
|
|
|
64
87
|
errorCode: string;
|
|
65
88
|
message: string;
|
|
66
89
|
raw: unknown;
|
|
90
|
+
/**
|
|
91
|
+
* alpha.66 — real token usage when the failure is a SYNTHESIZED
|
|
92
|
+
* structured-output contract violation (the provider returned 200 with
|
|
93
|
+
* usage; the response just violated the contract). Absent on transport-
|
|
94
|
+
* level failures (4xx/5xx/network) where no usage exists. Lets the
|
|
95
|
+
* brain's failure rows carry true `tokens_in` for the cliff class —
|
|
96
|
+
* PB's 2026-05-18 `chain-walk-on-structured-output-parse-failed` ask 4
|
|
97
|
+
* (tokens_in=0 on a 72s parse-fail made diagnosis ambiguous).
|
|
98
|
+
*/
|
|
99
|
+
tokens?: {
|
|
100
|
+
input: number;
|
|
101
|
+
output: number;
|
|
102
|
+
};
|
|
67
103
|
}
|
|
68
104
|
type ExecuteResult = ExecuteOk | ExecuteErr;
|
|
69
105
|
declare function execute(request: CompiledRequest, opts?: ExecuteOptions): Promise<ExecuteResult>;
|
|
@@ -90,17 +126,317 @@ declare function execute(request: CompiledRequest, opts?: ExecuteOptions): Promi
|
|
|
90
126
|
* exhausted without success.
|
|
91
127
|
*/
|
|
92
128
|
declare function call(ir: PromptIR, opts?: CallOptions): Promise<CallResult>;
|
|
129
|
+
/** Served-side result the AI-SDK consumer already holds from streamText. */
|
|
130
|
+
interface ProbeShadowServed {
|
|
131
|
+
/** Model id that actually served the user (becomes `current_model` on the row). */
|
|
132
|
+
model: string;
|
|
133
|
+
/** The served response text (stored as a preview; never the prompt). */
|
|
134
|
+
responseText: string;
|
|
135
|
+
/** Served prompt tokens (AI SDK `usage.promptTokens`). */
|
|
136
|
+
tokensIn: number;
|
|
137
|
+
/** Served completion tokens (AI SDK `usage.completionTokens`). */
|
|
138
|
+
tokensOut: number;
|
|
139
|
+
/** The user's actual wait in ms (alpha.46 served-latency axis). */
|
|
140
|
+
latencyMs: number;
|
|
141
|
+
}
|
|
142
|
+
/** Options for the standalone {@link probeShadow} export. */
|
|
143
|
+
interface ProbeShadowOptions {
|
|
144
|
+
/** The served leg the consumer supplies; kgauto runs the candidate leg. */
|
|
145
|
+
served: ProbeShadowServed;
|
|
146
|
+
/** Model id(s)/family alias(es) to shadow-test against the served model. */
|
|
147
|
+
candidates: string | string[];
|
|
148
|
+
/** Probability [0,1] a given call fires a probe. Default 0.05; pin 1 for dogfood. */
|
|
149
|
+
sampleRate?: number;
|
|
150
|
+
/** Phase 1 = 'off' (offline rollup). 'opus' inline judge is Phase 2. Default 'off'. */
|
|
151
|
+
judge?: 'off' | 'opus';
|
|
152
|
+
/** Override API keys (defaults: process.env). Gates candidate reachability. */
|
|
153
|
+
apiKeys?: ApiKeys;
|
|
154
|
+
/** Override fetch (for tests / custom transport). */
|
|
155
|
+
fetchImpl?: typeof fetch;
|
|
156
|
+
/** Provider-specific request fields shallow-merged into the candidate request. */
|
|
157
|
+
providerOverrides?: ProviderOverrides;
|
|
158
|
+
/** Forwarded to compile() for the candidate run (match the served-side compile). */
|
|
159
|
+
policy?: CompilePolicy;
|
|
160
|
+
toolRelevanceThreshold?: number;
|
|
161
|
+
compressHistoryAfter?: number;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* s54 — standalone full-IR shadow probe for AI-SDK consumers (tt-intel hunt, IC
|
|
165
|
+
* chat) that own their own streamText round-trip and never call call(). Fire it
|
|
166
|
+
* from the streamText `onFinish` callback, wrapped in the platform's
|
|
167
|
+
* `waitUntil()` / `after()`, so it runs after the response is flushed — no
|
|
168
|
+
* blocking, no `sync:true`, no teardown race (cleaner than call()'s in-process
|
|
169
|
+
* fire-and-forget for Edge runtimes; L-086).
|
|
170
|
+
*
|
|
171
|
+
* Runs the SAME candidate loop as the call()-inline probe ({@link
|
|
172
|
+
* runProbeCandidates}): same gates (sample, self-skip, G4 judge-self,
|
|
173
|
+
* reachability, G6), same fidelity=1.0 full-IR rows, same alpha.46 latency
|
|
174
|
+
* capture. The consumer supplies the served leg it already has; kgauto runs the
|
|
175
|
+
* candidate(s) and writes the `probe_outcomes` row.
|
|
176
|
+
*
|
|
177
|
+
* Requires `configureBrain()` to have been called (same as call()).
|
|
178
|
+
* Fire-and-forget: never throws into the caller.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* const result = streamText({ model, system, messages,
|
|
182
|
+
* onFinish: ({ text, usage }) => {
|
|
183
|
+
* after(() => probeShadow(ir, {
|
|
184
|
+
* served: { model: servedModelId, responseText: text,
|
|
185
|
+
* tokensIn: usage.promptTokens, tokensOut: usage.completionTokens,
|
|
186
|
+
* latencyMs: Date.now() - t0 },
|
|
187
|
+
* candidates: ['deepseek-v4-pro'], sampleRate: 0.05,
|
|
188
|
+
* }));
|
|
189
|
+
* },
|
|
190
|
+
* });
|
|
191
|
+
*/
|
|
192
|
+
declare function probeShadow(ir: PromptIR, opts: ProbeShadowOptions): Promise<void>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* alpha.33 — AI-SDK streamText helpers.
|
|
196
|
+
*
|
|
197
|
+
* The cross-consumer pattern surfaced 2026-05-20 (`streamText-cache-marker-
|
|
198
|
+
* propagation-gap` on `command-center/interfaces/kgauto.md ## Requested`):
|
|
199
|
+
* AI-SDK consumers using `streamText({ system: <string>, messages:
|
|
200
|
+
* convertToModelMessages(messages), model })` silently drop the Anthropic
|
|
201
|
+
* `cache_control` markers the compiler emits on `result.request.messages`.
|
|
202
|
+
* Two losses on that line:
|
|
203
|
+
* (a) `convertToModelMessages()` reads raw inputs not the lowered output,
|
|
204
|
+
* dropping per-message providerOptions; and
|
|
205
|
+
* (b) `streamText({ system: '<string>' })` strips any providerOptions
|
|
206
|
+
* on the system prefix.
|
|
207
|
+
*
|
|
208
|
+
* Net effect prior to this surface: `cache_read_input_tokens = 0` across
|
|
209
|
+
* every measured production call by IC + tt-intel even though both
|
|
210
|
+
* consumers had `historyCachePolicy: { strategy: 'all-but-latest' }` wired
|
|
211
|
+
* since alpha.5. The compiler did the right thing; the consumer integration
|
|
212
|
+
* pattern lost the markers at the wire boundary.
|
|
213
|
+
*
|
|
214
|
+
* This helper closes the gap. Pass the consumer's already-converted messages
|
|
215
|
+
* + the kgauto CompileResult and get back a `{ system, messages }` pair
|
|
216
|
+
* with cacheControl re-attached at the deterministic indices the compiler
|
|
217
|
+
* computed (`diagnostics.historyCacheMarkIndex` + `systemMessages` with
|
|
218
|
+
* its own cacheControl markers).
|
|
219
|
+
*
|
|
220
|
+
* No I/O. Pure transform. Idempotent — calling twice with the same inputs
|
|
221
|
+
* produces structurally-identical output.
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* AI-SDK-shaped converted-message structure. Matches what
|
|
226
|
+
* `convertToModelMessages()` returns at the wire layer. We don't import
|
|
227
|
+
* the AI-SDK type to avoid pulling that dep into the kgauto-compiler
|
|
228
|
+
* package — consumers pass their own already-converted messages.
|
|
229
|
+
*/
|
|
230
|
+
interface AISDKConvertedMessage {
|
|
231
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
232
|
+
content: unknown;
|
|
233
|
+
providerOptions?: {
|
|
234
|
+
anthropic?: {
|
|
235
|
+
cacheControl?: {
|
|
236
|
+
type: 'ephemeral';
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Result of `attachCacheControlToStreamTextInput()` — ready to spread into
|
|
243
|
+
* `streamText(...)` directly.
|
|
244
|
+
*
|
|
245
|
+
* The `system` field is either the structured `SystemModelMessage[]` form
|
|
246
|
+
* (when the compiler computed at least one cacheable section + chose
|
|
247
|
+
* Anthropic) or the flat-string concatenation (when no cacheable sections
|
|
248
|
+
* exist OR the provider isn't Anthropic). Consumers can pass either form
|
|
249
|
+
* to `streamText({ system })` — the AI-SDK accepts both.
|
|
250
|
+
*/
|
|
251
|
+
interface AttachCacheControlResult {
|
|
252
|
+
system: string | SystemModelMessage[];
|
|
253
|
+
messages: AISDKConvertedMessage[];
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Attach Anthropic cache_control markers to a streamText input that the
|
|
257
|
+
* consumer has already prepared via `convertToModelMessages()`. Reads
|
|
258
|
+
* `result.diagnostics.historyCacheMarkIndex` for the position-on-history
|
|
259
|
+
* marker and `result.systemMessages` for the per-section system markers.
|
|
260
|
+
*
|
|
261
|
+
* The flat-string `system` form is returned when:
|
|
262
|
+
* - the compiler produced no `systemMessages` (e.g., zero sections kept), or
|
|
263
|
+
* - the chosen provider is not Anthropic, so cacheControl wouldn't
|
|
264
|
+
* achieve anything at the wire layer (other providers cache implicitly
|
|
265
|
+
* based on prefix shape, no marker needed).
|
|
266
|
+
*
|
|
267
|
+
* Otherwise the structured `SystemModelMessage[]` form is returned —
|
|
268
|
+
* preserves the per-section cacheControl markers across `streamText`.
|
|
269
|
+
*
|
|
270
|
+
* @param result - kgauto CompileResult from `compile(ir, opts)`
|
|
271
|
+
* @param convertedMessages - the consumer's already-converted messages
|
|
272
|
+
* (from `convertToModelMessages(rawMessages)` in their AI-SDK call site)
|
|
273
|
+
* @returns `{ system, messages }` ready to spread into `streamText(...)`
|
|
274
|
+
*/
|
|
275
|
+
declare function attachCacheControlToStreamTextInput(result: CompileResult, convertedMessages: AISDKConvertedMessage[]): AttachCacheControlResult;
|
|
93
276
|
|
|
94
277
|
/**
|
|
95
|
-
*
|
|
278
|
+
* alpha.52 — official AI-SDK-v6 compile adapter + compile-then-discard guard.
|
|
279
|
+
*
|
|
280
|
+
* Until now each AI-SDK consumer (tt-intel, IC) hand-rolled this adapter in
|
|
281
|
+
* its own `lib/kgauto-v2/index.ts`: `compile()` → reassemble the system param
|
|
282
|
+
* per provider → extract kept tool names per provider → re-derive the history
|
|
283
|
+
* cache-mark index (a copy of the compiler's own `historyCacheMarkIndex`
|
|
284
|
+
* logic — drift-prone). This centralizes that boilerplate and DRYs the two
|
|
285
|
+
* near-identical wrappers.
|
|
96
286
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
287
|
+
* It also closes the compile-then-discard hole. The discard pattern is:
|
|
288
|
+
*
|
|
289
|
+
* const c = compileForAISDKv6(ir); // compile runs
|
|
290
|
+
* const out = await generateText({ // …but a hand-built prompt
|
|
291
|
+
* model: getModel(otherId), prompt }); // + a DIFFERENT model run
|
|
292
|
+
* await record({ handle: c.handle, … }); // brain row attributed to `c`
|
|
293
|
+
*
|
|
294
|
+
* The recorded row's `mutations_applied` / `estimated_tokens_in` /
|
|
295
|
+
* `system_prompt_chars` then describe a compile that never reached the wire.
|
|
296
|
+
* A library-level runtime guard could NOT catch this while the adapter lived
|
|
297
|
+
* in consumer code (the consumer wrapper always reads `compile()`'s result to
|
|
298
|
+
* build its own object, so any getter there is "consumed" every time,
|
|
299
|
+
* regardless of whether the final caller used the wrapper output). With the
|
|
300
|
+
* adapter IN the library, the object the FINAL caller reads is library-owned,
|
|
301
|
+
* so consume-tracking getters on `.system` / `.model` / `.raw` detect non-use
|
|
302
|
+
* and `record()` warns. See `interfaces/kgauto.md` (## Requested:
|
|
303
|
+
* `compiled-output-discarded-guard`).
|
|
304
|
+
*
|
|
305
|
+
* The guard is OPT-IN-BY-USE: only `compileForAISDKv6` arms tracking, so
|
|
306
|
+
* `call()` paths and raw `compile()` users never see a false warning.
|
|
307
|
+
*/
|
|
308
|
+
|
|
309
|
+
interface CompileForAISDKv6Result {
|
|
310
|
+
/**
|
|
311
|
+
* Pass to `streamText`/`generateText({ model })` — the caller maps this id
|
|
312
|
+
* to an AI-SDK `LanguageModel`. Reading this marks the compile "consumed"
|
|
313
|
+
* (silences the compile-then-discard guard).
|
|
314
|
+
*/
|
|
315
|
+
readonly model: string;
|
|
316
|
+
/**
|
|
317
|
+
* System parameter for `streamText`/`generateText({ system })`. Returns the
|
|
318
|
+
* structured `SystemModelMessage[]` form when the target is Anthropic AND a
|
|
319
|
+
* cacheable section exists (preserves the cache_control marker across the
|
|
320
|
+
* wire); a flat concatenated string otherwise. Reading this marks
|
|
321
|
+
* "consumed". (Same rule as `attachCacheControlToStreamTextInput`.)
|
|
322
|
+
*/
|
|
323
|
+
readonly system: string | SystemModelMessage[];
|
|
324
|
+
/**
|
|
325
|
+
* The raw kgauto `CompileResult` — for `attachCacheControlToStreamTextInput(raw, msgs)`
|
|
326
|
+
* and `probeShadow(raw.ir-equivalent, …)` paths. Reading this marks
|
|
327
|
+
* "consumed" (it means you're using the compile output via the raw result).
|
|
328
|
+
*/
|
|
329
|
+
readonly raw: CompileResult;
|
|
330
|
+
/** Tool names that survived budget + relevance — filter your SDK tool map to these. */
|
|
331
|
+
keptToolNames: Set<string>;
|
|
332
|
+
/** providerOptions for `streamText` — Anthropic cache_control on the cacheable prefix. Undefined otherwise. */
|
|
333
|
+
providerOptions?: {
|
|
334
|
+
anthropic?: {
|
|
335
|
+
cacheControl?: {
|
|
336
|
+
type: 'ephemeral';
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
/**
|
|
341
|
+
* Index (into post-strip history) for the Anthropic history cache marker
|
|
342
|
+
* (alpha.33). Mirror of `result.diagnostics.historyCacheMarkIndex` — no
|
|
343
|
+
* consumer re-derivation needed. Undefined when no marker fires, and (since
|
|
344
|
+
* alpha.55) always undefined for non-Anthropic targets: the marker is an
|
|
345
|
+
* Anthropic wire concept, other providers cache prefixes implicitly. The
|
|
346
|
+
* ungated value remains on `diagnostics.historyCacheMarkIndex`.
|
|
347
|
+
*/
|
|
348
|
+
historyCacheMarkIndex?: number;
|
|
349
|
+
/** Compile handle — pass to `record()` after the call. */
|
|
350
|
+
handle: string;
|
|
351
|
+
/** Mutation ids the compiler fired (informational). */
|
|
352
|
+
mutationsApplied: string[];
|
|
353
|
+
/** Best-practice advisories (alpha.6). Empty when none fired. */
|
|
354
|
+
advisories: BestPracticeAdvisory[];
|
|
355
|
+
/** Compiler diagnostics + the three commonly-logged top-level fields. */
|
|
356
|
+
diagnostics: CompileResult['diagnostics'] & {
|
|
357
|
+
targetProvider: string;
|
|
358
|
+
estimatedCostUsd: number;
|
|
359
|
+
fallbackChain: string[];
|
|
360
|
+
};
|
|
361
|
+
/** The compiled IR — pass to `probeShadow(ir, …)` in `onFinish` (alpha.48). */
|
|
362
|
+
ir: PromptIR;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Compile a `PromptIR` and lower it to an AI-SDK-v6 `streamText`/`generateText`
|
|
366
|
+
* bundle. Replaces the hand-rolled per-consumer adapter.
|
|
99
367
|
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
368
|
+
* Arms the compile-then-discard guard: read `.system` / `.model` / `.raw` to
|
|
369
|
+
* serve the call. If you `record()` the handle without reading any of them,
|
|
370
|
+
* `record()` emits a dev-mode warning that the compile was discarded.
|
|
102
371
|
*/
|
|
372
|
+
declare function compileForAISDKv6(ir: PromptIR, opts?: CompileOptions): CompileForAISDKv6Result;
|
|
103
373
|
|
|
374
|
+
/**
|
|
375
|
+
* alpha.11 — opt-in nested config for brain-query mode (chains / archetype
|
|
376
|
+
* perf / pricing / models registry). Enabled by default when endpoint is
|
|
377
|
+
* set; per-table opt-out via explicit `false`.
|
|
378
|
+
*
|
|
379
|
+
* Locked via /plan-eng-review 2026-05-15 (decision D3). Structured group
|
|
380
|
+
* keeps the BrainConfig surface clean as more brain-driven tables ship.
|
|
381
|
+
*/
|
|
382
|
+
interface BrainQueryConfig {
|
|
383
|
+
/** Default true when endpoint set. Brain-driven fallback chains. */
|
|
384
|
+
chains?: boolean;
|
|
385
|
+
/** Default true when endpoint set. Brain-driven archetype perf scores. */
|
|
386
|
+
perf?: boolean;
|
|
387
|
+
/** Default true when endpoint set. Brain-driven pricing with at-time resolution. */
|
|
388
|
+
pricing?: boolean;
|
|
389
|
+
/** Default true when endpoint set. Brain-driven model registry + aliases. */
|
|
390
|
+
models?: boolean;
|
|
391
|
+
/**
|
|
392
|
+
* alpha.38 — opt-in compile-time advisor for stale exclusions. Default
|
|
393
|
+
* `true` when endpoint is set. When enabled, the library reads
|
|
394
|
+
* `exclusion_findings` from the central kgauto-dashboard for the consumer's
|
|
395
|
+
* `app_id` (no consumer-side proxy work required) and surfaces a
|
|
396
|
+
* `stale-exclusion-candidate` advisory when compile()'s archetype has a
|
|
397
|
+
* recommend-probe finding open. Set `false` to silence (no fetch, no
|
|
398
|
+
* advisory).
|
|
399
|
+
*/
|
|
400
|
+
findingsExclusions?: boolean;
|
|
401
|
+
/**
|
|
402
|
+
* alpha.64 — hard opt-out of the surface-promotions fetch layer (Stage 2).
|
|
403
|
+
* Default true; only matters when consent (`BrainConfig.autoPromote` /
|
|
404
|
+
* `KGAUTO_AUTO_PROMOTE`) is present — without consent the layer is off
|
|
405
|
+
* regardless. Set `false` to disable the fetch even while consented
|
|
406
|
+
* (debug/emergency lever).
|
|
407
|
+
*/
|
|
408
|
+
promotions?: boolean;
|
|
409
|
+
/** SWR window in ms. Default 300_000 (5 min). */
|
|
410
|
+
cacheTtlMs?: number;
|
|
411
|
+
/** Override the GET URL when the read endpoint differs from the write one.
|
|
412
|
+
* Defaults to `${endpoint}/v2/config` when omitted. */
|
|
413
|
+
configEndpoint?: string;
|
|
414
|
+
/**
|
|
415
|
+
* alpha.38 — override the findings endpoint when the consumer wants to
|
|
416
|
+
* proxy `exclusion_findings` reads through their own service rather than
|
|
417
|
+
* reading directly from the kgauto-dashboard. Library appends `?app_id=X`.
|
|
418
|
+
* Defaults to `https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions`.
|
|
419
|
+
*/
|
|
420
|
+
findingsEndpoint?: string;
|
|
421
|
+
/**
|
|
422
|
+
* alpha.64 — override the surface-promotions endpoint (Stage 2). Only
|
|
423
|
+
* consulted when the consumer opted in via `BrainConfig.autoPromote` /
|
|
424
|
+
* `KGAUTO_AUTO_PROMOTE`. Library appends `?app_id=X`. Defaults to
|
|
425
|
+
* `https://kgauto-dashboard.vercel.app/api/kgauto-v2/promotions`.
|
|
426
|
+
*/
|
|
427
|
+
promotionsEndpoint?: string;
|
|
428
|
+
/**
|
|
429
|
+
* alpha.70 — hard opt-out of the measured-failure gate fetch layer.
|
|
430
|
+
* Default true (the gate is opt-OUT, see `BrainConfig.measuredFailureGate`).
|
|
431
|
+
*/
|
|
432
|
+
measuredFailure?: boolean;
|
|
433
|
+
/**
|
|
434
|
+
* alpha.70 — override the measured-failure endpoint. Library appends
|
|
435
|
+
* `?app_id=X`. Defaults to
|
|
436
|
+
* `https://kgauto-dashboard.vercel.app/api/kgauto-v2/measured-failure`.
|
|
437
|
+
*/
|
|
438
|
+
measuredFailureEndpoint?: string;
|
|
439
|
+
}
|
|
104
440
|
interface BrainConfig {
|
|
105
441
|
/** Brain HTTP endpoint base URL (e.g., https://kgauto-brain.vercel.app/api). */
|
|
106
442
|
endpoint: string;
|
|
@@ -112,16 +448,145 @@ interface BrainConfig {
|
|
|
112
448
|
sync?: boolean;
|
|
113
449
|
/** Optional fetch override (for tests). */
|
|
114
450
|
fetchImpl?: typeof fetch;
|
|
451
|
+
/** alpha.11 — brain-query mode for config tables. Default-on per table
|
|
452
|
+
* when endpoint is set; opt-out via `false`. See BrainQueryConfig. */
|
|
453
|
+
brainQuery?: BrainQueryConfig;
|
|
454
|
+
/**
|
|
455
|
+
* alpha.52 — emit a dev-mode `console.warn` when a `compileForAISDKv6()`
|
|
456
|
+
* result is passed to record() but its `.system` / `.model` / `.raw` were
|
|
457
|
+
* never read (the compile-then-discard pattern: the recorded brain row's
|
|
458
|
+
* `mutations_applied` / `estimated_tokens_in` / `system_prompt_chars`
|
|
459
|
+
* describe a compile that did NOT shape the served call). Default: warn
|
|
460
|
+
* when `NODE_ENV !== 'production'`, silent in production. Set `true` to
|
|
461
|
+
* force-on (e.g. a prod audit window) or `false` to silence. No-op for
|
|
462
|
+
* `call()` paths and raw `compile()` users — only `compileForAISDKv6`
|
|
463
|
+
* arms the tracking, so good actors never see a false warning.
|
|
464
|
+
*/
|
|
465
|
+
warnOnDiscardedCompile?: boolean;
|
|
466
|
+
/**
|
|
467
|
+
* alpha.59 — per-leg timeout (ms) applied to every brain WRITE POST
|
|
468
|
+
* (record() primary + advisory secondary, recordOutcome(),
|
|
469
|
+
* recordShadowProbe()) via `AbortSignal.timeout`. Default 10000.
|
|
470
|
+
*
|
|
471
|
+
* Why: `sync: true` puts these fetches on the USER path (Edge consumers
|
|
472
|
+
* await record() before responding), and alpha.56's representation
|
|
473
|
+
* passthrough added a second sequential POST (advisory secondary) to that
|
|
474
|
+
* same path — an unbounded hang on either leg holds the user to the Edge
|
|
475
|
+
* limit (GE's `brainconfig-first-class-timeout` filing; GE bounded it at
|
|
476
|
+
* 3s via a hand-rolled fetchImpl wrapper every sync consumer had to
|
|
477
|
+
* rediscover).
|
|
478
|
+
*
|
|
479
|
+
* A fired timeout follows each leg's existing degraded-brain path
|
|
480
|
+
* (fire-and-forget: swallowed via onError; sync: `persistence_failed`
|
|
481
|
+
* result — never a throw into the user path). Wraps the configured
|
|
482
|
+
* `fetchImpl` rather than replacing it, so it composes with
|
|
483
|
+
* consumer-supplied impls. Set `0` to disable (pre-alpha.59 unbounded
|
|
484
|
+
* behavior). Brain-query reads (config tables) are cached + SWR and are
|
|
485
|
+
* not affected.
|
|
486
|
+
*/
|
|
487
|
+
timeoutMs?: number;
|
|
488
|
+
/**
|
|
489
|
+
* alpha.64 (Stage 2 of the eval trust ladder) — consent switch for the
|
|
490
|
+
* surface-promotion routing effect. Default OFF.
|
|
491
|
+
*
|
|
492
|
+
* When true (or when the `KGAUTO_AUTO_PROMOTE` env var is '1'/'true' and
|
|
493
|
+
* this field is left undefined — env-as-consent, the KGAUTO_GOLDEN_CAPTURE
|
|
494
|
+
* precedent; an explicit `false` here overrides the env), compile()
|
|
495
|
+
* consults the brain's active `kgauto_promotions` rows for this app and
|
|
496
|
+
* boosts the promoted model at scoring time. Promotions are written only
|
|
497
|
+
* by the automated golden-eval trigger after a promote-ready verdict on a
|
|
498
|
+
* price-dominant (cheaper) candidate, and every promotion sits behind the
|
|
499
|
+
* 7-day rollback guard (daily watcher auto-reverts on regression vs the
|
|
500
|
+
* frozen baseline).
|
|
501
|
+
*
|
|
502
|
+
* Not opted in ⇒ promotions have ZERO routing effect (they remain visible
|
|
503
|
+
* as advisories + dashboard rows). Consumer sovereignty is preserved even
|
|
504
|
+
* when opted in: `forceModel`, `policy.blockedModels`, and cost ceilings
|
|
505
|
+
* always win, and a non-empty `policy.preferredModels` defers the
|
|
506
|
+
* promotion entirely.
|
|
507
|
+
*/
|
|
508
|
+
autoPromote?: boolean;
|
|
509
|
+
/**
|
|
510
|
+
* alpha.70 — the measured-failure quality gate. **Default ON** wherever
|
|
511
|
+
* the brain is configured; set `false` (or `KGAUTO_MEASURED_FAILURE_GATE=0`)
|
|
512
|
+
* to disable. An explicit value here wins over the env var.
|
|
513
|
+
*
|
|
514
|
+
* Why this is opt-OUT while `autoPromote` is opt-IN: a promotion silently
|
|
515
|
+
* changes WHICH model serves you on kgauto's evidence, so it needs
|
|
516
|
+
* consent. This gate only ever DE-RANKS a model that the consumer's own
|
|
517
|
+
* outcome rows show failing them — the failures are already being paid
|
|
518
|
+
* for on their bill and their users' latency, and the model stays
|
|
519
|
+
* available as a graceful fallback. Requiring an opt-in to stop paying
|
|
520
|
+
* would be the wrong default.
|
|
521
|
+
*
|
|
522
|
+
* Consumer sovereignty is unchanged: `forceModel` still wins. Unlike a
|
|
523
|
+
* promotion, `policy.preferredModels` does NOT defer the gate — a
|
|
524
|
+
* preference says which model you would like to lead, not that a
|
|
525
|
+
* measurably-failing one works.
|
|
526
|
+
*/
|
|
527
|
+
measuredFailureGate?: boolean;
|
|
115
528
|
}
|
|
116
529
|
declare function configureBrain(config: BrainConfig): void;
|
|
117
530
|
declare function clearBrain(): void;
|
|
531
|
+
interface BrainHealthSnapshot {
|
|
532
|
+
configState: 'configured' | 'not_configured';
|
|
533
|
+
/** Host of the configured endpoint (never the full URL — no secrets/paths). */
|
|
534
|
+
endpointHost?: string;
|
|
535
|
+
/** True when writes are awaited (BrainConfig.sync). */
|
|
536
|
+
sync: boolean;
|
|
537
|
+
/** Write POSTs attempted (all routes, primary + secondary). */
|
|
538
|
+
sent: number;
|
|
539
|
+
/** Write POSTs acknowledged 2xx without redirect. */
|
|
540
|
+
acked: number;
|
|
541
|
+
/** Write POSTs that failed (non-2xx, redirect, timeout, network throw). */
|
|
542
|
+
failed: number;
|
|
543
|
+
/** Subset of `failed` that failed the redirect check (middleware-drift class). */
|
|
544
|
+
redirected: number;
|
|
545
|
+
lastAckAt?: string;
|
|
546
|
+
lastFailureAt?: string;
|
|
547
|
+
/** Most recent failure message, truncated. */
|
|
548
|
+
lastFailure?: string;
|
|
549
|
+
deadLetterCount: number;
|
|
550
|
+
}
|
|
551
|
+
interface BrainDeadLetterEntry {
|
|
552
|
+
/** Brain route segment the payload was bound for. */
|
|
553
|
+
route: 'outcomes' | 'compile_outcome_quality' | 'probe_outcomes' | 'compile_outcome_advisories' | 'golden_irs';
|
|
554
|
+
/**
|
|
555
|
+
* Endpoint the payload was originally bound for. Flush replays ONLY entries
|
|
556
|
+
* matching the currently-configured endpoint — a reconfigure must never
|
|
557
|
+
* replay another brain's payloads into the new target (caught live by
|
|
558
|
+
* smoke-brain-timeout: a hung-socket test payload auto-flushed into the
|
|
559
|
+
* real brain after the smoke re-pointed configureBrain).
|
|
560
|
+
*/
|
|
561
|
+
endpoint: string;
|
|
562
|
+
/** The exact JSON body that failed to land. */
|
|
563
|
+
payload: unknown;
|
|
564
|
+
failedAt: string;
|
|
565
|
+
/** Delivery attempts so far (1 = the original failed POST). */
|
|
566
|
+
attempts: number;
|
|
567
|
+
lastError: string;
|
|
568
|
+
}
|
|
118
569
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
|
|
570
|
+
* Process-local brain write delivery ledger. `acked` is the only number that
|
|
571
|
+
* means "a row landed" — fire-and-forget callers that need delivery evidence
|
|
572
|
+
* read this (or set `BrainConfig.sync`). Cheap enough to attach to any debug
|
|
573
|
+
* or health surface the consumer already exposes.
|
|
574
|
+
*/
|
|
575
|
+
declare function brainHealth(): BrainHealthSnapshot;
|
|
576
|
+
/** Read-only view of the pending dead-letter (for consumer-side persistence). */
|
|
577
|
+
declare function peekBrainDeadLetter(): readonly BrainDeadLetterEntry[];
|
|
578
|
+
/**
|
|
579
|
+
* Replay pending dead-letter payloads against the configured brain. Delivered
|
|
580
|
+
* entries are removed; failures increment `attempts` and entries are dropped
|
|
581
|
+
* after 3 total attempts (bounded — never an infinite retry, per the Redis
|
|
582
|
+
* DLQ rule). Safe to call any time; no-ops when unconfigured or already
|
|
583
|
+
* flushing. Also runs opportunistically after any successful write.
|
|
124
584
|
*/
|
|
585
|
+
declare function flushBrainDeadLetter(): Promise<{
|
|
586
|
+
attempted: number;
|
|
587
|
+
delivered: number;
|
|
588
|
+
remaining: number;
|
|
589
|
+
}>;
|
|
125
590
|
declare function record(input: RecordInput): Promise<void>;
|
|
126
591
|
/**
|
|
127
592
|
* Wire shape POSTed by `record()` to the brain proxy's `/outcomes` endpoint.
|
|
@@ -168,8 +633,377 @@ interface OutcomePayload {
|
|
|
168
633
|
cost_usd_actual?: number;
|
|
169
634
|
ttft_ms?: number;
|
|
170
635
|
history_cacheable_tokens?: number;
|
|
636
|
+
effort?: string;
|
|
171
637
|
history_tokens_at_compile?: number;
|
|
638
|
+
/**
|
|
639
|
+
* Mirrors `ir.constraints.toolOrchestration` from compile time. NULL when
|
|
640
|
+
* the consumer hadn't adopted the constraint (pre-alpha.20). Powers
|
|
641
|
+
* per-mode model-perf queries on the brain (the L-040 parallel-tool
|
|
642
|
+
* cliff lumps DeepSeek sequential perf with parallel without this).
|
|
643
|
+
*/
|
|
644
|
+
tool_orchestration?: 'parallel' | 'sequential' | 'either' | null;
|
|
645
|
+
finish_reason?: string;
|
|
646
|
+
total_ms?: number;
|
|
647
|
+
tools_count?: number;
|
|
648
|
+
history_depth?: number;
|
|
649
|
+
system_prompt_chars?: number;
|
|
650
|
+
fell_over_from?: string;
|
|
651
|
+
fallback_reason?: 'rate_limit' | 'provider_auth_failed' | 'provider_error' | 'cliff' | 'cost_cap' | 'contract_violation';
|
|
652
|
+
/**
|
|
653
|
+
* True when the same-model retry (CallOptions.sameModelRetry) fired
|
|
654
|
+
* during this call. Key OMITTED (not false) when no retry fired — safe
|
|
655
|
+
* against brains that haven't applied migration 039 yet.
|
|
656
|
+
*/
|
|
657
|
+
retried_same_model?: boolean;
|
|
658
|
+
/**
|
|
659
|
+
* Per-call SectionRewrite[] captured at compile time. Omitted (sent as
|
|
660
|
+
* undefined → stored NULL) when no rewrites fired. Powers cross-app
|
|
661
|
+
* learning aggregates ("rule X fired N times on (app, model, archetype),
|
|
662
|
+
* downstream outcome quality lifted by M points").
|
|
663
|
+
*/
|
|
664
|
+
section_rewrites_applied?: SectionRewrite[] | null;
|
|
665
|
+
/**
|
|
666
|
+
* R0 linkage (§5.0). Parent call's handle when this row is a fan-out branch;
|
|
667
|
+
* key OMITTED (undefined → dropped by JSON.stringify → stored NULL) for a
|
|
668
|
+
* root, safe against pre-042 brains.
|
|
669
|
+
*/
|
|
670
|
+
parent_handle?: string;
|
|
671
|
+
/**
|
|
672
|
+
* R0 linkage (§5.0). Root handle of the fan-out trace (= parent_handle when a
|
|
673
|
+
* branch, else this row's own handle). Emitted for every registered compile.
|
|
674
|
+
*/
|
|
675
|
+
trace_id?: string;
|
|
676
|
+
/**
|
|
677
|
+
* R0 linkage (§5.0). root | branch | composer. Emitted for every registered
|
|
678
|
+
* compile; surface baselines filter to root/NULL so branch traffic never
|
|
679
|
+
* contaminates a promotion/eval baseline. Release A emits only root/branch.
|
|
680
|
+
*/
|
|
681
|
+
fanout_role?: 'root' | 'branch' | 'composer';
|
|
682
|
+
/**
|
|
683
|
+
* RD discipline gate-token accounting (§5.D). Measured token tax of the
|
|
684
|
+
* discipline_contract gate block; 0 when the gate didn't fire.
|
|
685
|
+
*/
|
|
686
|
+
discipline_gate_tokens?: number;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* alpha.20 Entry 4: record a quality outcome for a previously-compiled call.
|
|
690
|
+
*
|
|
691
|
+
* Fires after the consumer's UX surfaces an approve/reject event (e.g., user
|
|
692
|
+
* clicks Approve on a hunt result). Joins to the original `compile_outcomes`
|
|
693
|
+
* row via outcomeId — enables per-(model, archetype) approve-rate measurement
|
|
694
|
+
* once N ≥ 10 outcomes accumulate.
|
|
695
|
+
*
|
|
696
|
+
* Fire-and-forget by default (matches record() semantics). Set BrainConfig.sync
|
|
697
|
+
* = true for runtime contexts that can't tolerate fire-and-forget teardown
|
|
698
|
+
* (Vercel Edge, Cloudflare Workers, AWS Lambda) — see L-086.
|
|
699
|
+
*
|
|
700
|
+
* Returns (alpha.61): `{ok: true}` only when the POST was acknowledged 2xx
|
|
701
|
+
* (sync mode); `{ok: 'queued'}` in fire-and-forget mode (handed to the
|
|
702
|
+
* runtime, NOT acked — read `brainHealth()` for delivery evidence);
|
|
703
|
+
* `{ok: false, reason}` on known failure. Never throws.
|
|
704
|
+
*/
|
|
705
|
+
declare function recordOutcome(input: RecordOutcomeInput): Promise<OutcomeResult>;
|
|
706
|
+
/**
|
|
707
|
+
* True when the active brain config requests synchronous (awaited) writes.
|
|
708
|
+
* call()'s shadow-probe path reads this to decide whether to await the probe
|
|
709
|
+
* (Edge/Worker/Lambda — L-086) or fire-and-forget (Node). False when no brain
|
|
710
|
+
* is configured.
|
|
711
|
+
*/
|
|
712
|
+
declare function isBrainSync(): boolean;
|
|
713
|
+
/**
|
|
714
|
+
* Full-IR inline shadow-probe record input (Shape B, Phase 1 — s51). Carries
|
|
715
|
+
* ONLY response previews + metadata; the prompt (system/context/payload) is
|
|
716
|
+
* never included — `promptHash` is an irreversible grouping key, not content.
|
|
717
|
+
*/
|
|
718
|
+
interface ShadowProbeRecordInput {
|
|
719
|
+
appId: string;
|
|
720
|
+
archetype: string;
|
|
721
|
+
family: string;
|
|
722
|
+
candidateModel: string;
|
|
723
|
+
currentModel: string;
|
|
724
|
+
/** Irreversible grouping hash (NOT the prompt). */
|
|
725
|
+
promptHash: string;
|
|
726
|
+
/** Served model's response, truncated (RESPONSE text only — never the prompt). */
|
|
727
|
+
currentResponsePreview?: string;
|
|
728
|
+
/** Candidate model's response, truncated. */
|
|
729
|
+
candidateResponsePreview?: string;
|
|
730
|
+
tokensCurrentIn?: number;
|
|
731
|
+
tokensCurrentOut?: number;
|
|
732
|
+
tokensCandidateIn?: number;
|
|
733
|
+
tokensCandidateOut?: number;
|
|
734
|
+
/**
|
|
735
|
+
* Wall-clock latency of the served call, ms (alpha.46). The third swap-decision
|
|
736
|
+
* axis alongside quality + cost — a verdict needs to know the candidate is
|
|
737
|
+
* slower, not just better/cheaper. Served latency mirrors
|
|
738
|
+
* `compile_outcomes.latency_ms`; carried here so a probe row is self-contained.
|
|
739
|
+
*/
|
|
740
|
+
latencyCurrentMs?: number;
|
|
741
|
+
/** Wall-clock latency of the candidate replay call, ms (alpha.46). */
|
|
742
|
+
latencyCandidateMs?: number;
|
|
743
|
+
/**
|
|
744
|
+
* alpha — probe-row class (migration 029; `candidate_error` added by 032).
|
|
745
|
+
* Defaults to `'completed'` (the pre-029 row shape: candidate ran, columns
|
|
746
|
+
* populated). `'aborted_latency_budget'` and `'skipped_slow_tier_sync'` are
|
|
747
|
+
* DIAGNOSTIC rows from sync-mode latency protection; `'candidate_error'`
|
|
748
|
+
* (alpha.53) is the failed-candidate diagnostic — the candidate call
|
|
749
|
+
* errored, with the error class + latency-at-death recorded instead of
|
|
750
|
+
* silence (the IC demo-night probe deaths were invisible for ~90 min under
|
|
751
|
+
* the old record-no-row rule). Diagnostic rows carry no candidate response
|
|
752
|
+
* and no verdict — no false quality signal. A verdict rollup MUST filter to
|
|
753
|
+
* `outcome='completed'`.
|
|
754
|
+
*/
|
|
755
|
+
outcome?: 'completed' | 'aborted_latency_budget' | 'skipped_slow_tier_sync' | 'candidate_error';
|
|
756
|
+
/**
|
|
757
|
+
* alpha.53 (migration 032) — error class for `outcome='candidate_error'`
|
|
758
|
+
* rows. Values follow execute()'s taxonomy (`rate_limit`, `timeout`,
|
|
759
|
+
* `server_error`, `model_not_found`, `auth`, `invalid_request`, `unknown`)
|
|
760
|
+
* plus `execute_rejected` (the execute promise rejected outright). NULL /
|
|
761
|
+
* omitted on all other row classes.
|
|
762
|
+
*/
|
|
763
|
+
errorClass?: string;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Pure builder for the `probe_outcomes` row written by the inline shadow-probe.
|
|
767
|
+
* Exported so a test can assert the G3 privacy invariant: the row carries NO
|
|
768
|
+
* prompt/system/context text — only response previews + metadata + a hash.
|
|
769
|
+
*
|
|
770
|
+
* Phase 1 (judge: 'off'): `judge_verdict` / `judge_score` are null — the row
|
|
771
|
+
* is an unjudged sample for the Phase-2 offline batch judge. `prompt_fidelity`
|
|
772
|
+
* is 1.0 by construction (the candidate ran the full IR, not a truncated
|
|
773
|
+
* preview), and `replay_source='inline-full-ir'` marks it as a trustworthy row
|
|
774
|
+
* (vs the watchers' lossy `replay-preview`).
|
|
775
|
+
*/
|
|
776
|
+
declare function buildShadowProbeRow(input: ShadowProbeRecordInput): {
|
|
777
|
+
app_id: string;
|
|
778
|
+
intent_archetype: string;
|
|
779
|
+
family: string;
|
|
780
|
+
candidate_model: string;
|
|
781
|
+
current_model: string;
|
|
782
|
+
prompt_hash: string;
|
|
783
|
+
current_response: string | null;
|
|
784
|
+
candidate_response: string | null;
|
|
785
|
+
judge_verdict: null;
|
|
786
|
+
judge_score: null;
|
|
787
|
+
tokens_current_in: number | null;
|
|
788
|
+
tokens_current_out: number | null;
|
|
789
|
+
tokens_candidate_in: number | null;
|
|
790
|
+
tokens_candidate_out: number | null;
|
|
791
|
+
latency_current_ms: number | null;
|
|
792
|
+
latency_candidate_ms: number | null;
|
|
793
|
+
prompt_fidelity: number;
|
|
794
|
+
replay_source: 'inline-full-ir';
|
|
795
|
+
outcome: 'completed' | 'aborted_latency_budget' | 'skipped_slow_tier_sync' | 'candidate_error';
|
|
796
|
+
error_class: string | null;
|
|
797
|
+
};
|
|
798
|
+
/**
|
|
799
|
+
* Persist one inline shadow-probe row to `probe_outcomes`. Fire-and-forget by
|
|
800
|
+
* default; honors `BrainConfig.sync` (L-086). Never throws — failures route to
|
|
801
|
+
* onError. Mirrors record()'s POST shape; consumer proxies forward
|
|
802
|
+
* `/probe_outcomes` the same way they forward `/outcomes`.
|
|
803
|
+
*/
|
|
804
|
+
declare function recordShadowProbe(input: ShadowProbeRecordInput): Promise<void>;
|
|
805
|
+
/**
|
|
806
|
+
* Golden-IR capture input. UNLIKE every other brain write, this row carries the
|
|
807
|
+
* RAW full PromptIR — an explicit, documented posture change from the s51
|
|
808
|
+
* "brain holds no raw consumer prompts" rule, gated on consumer opt-in
|
|
809
|
+
* (`KGAUTO_GOLDEN_CAPTURE` env / `CallOptions.goldenCapture`). The `consent`
|
|
810
|
+
* field records the provenance of that opt-in at capture time.
|
|
811
|
+
*/
|
|
812
|
+
interface GoldenIrRecordInput {
|
|
813
|
+
appId: string;
|
|
814
|
+
archetype: string;
|
|
815
|
+
/** hashShape() of the call at compile time (peek before record() pops). */
|
|
816
|
+
shapeKey?: string;
|
|
817
|
+
/** The full PromptIR, verbatim. Plain JSON by construction (ir.ts). */
|
|
818
|
+
ir: unknown;
|
|
819
|
+
incumbentModel: string;
|
|
820
|
+
incumbentOutput?: string;
|
|
821
|
+
incumbentLatencyMs?: number;
|
|
822
|
+
incumbentTokensIn?: number;
|
|
823
|
+
incumbentTokensOut?: number;
|
|
824
|
+
/** 'sampled' (capture flag fired on live traffic) | 'curated' (operator). */
|
|
825
|
+
source: 'sampled' | 'curated';
|
|
826
|
+
/** Consent provenance, e.g. 'KGAUTO_GOLDEN_CAPTURE=0.1 (consumer env opt-in)'. */
|
|
827
|
+
consent: string;
|
|
828
|
+
/** Optional link back to the compile handle of the captured call. */
|
|
829
|
+
outcomeHandle?: string;
|
|
830
|
+
}
|
|
831
|
+
/** Pure builder for the `kgauto_golden_irs` row (snake_case wire shape). */
|
|
832
|
+
declare function buildGoldenIrRow(input: GoldenIrRecordInput): {
|
|
833
|
+
app_id: string;
|
|
834
|
+
intent_archetype: string;
|
|
835
|
+
shape_key: string | null;
|
|
836
|
+
ir: unknown;
|
|
837
|
+
incumbent_model: string;
|
|
838
|
+
incumbent_output: string | null;
|
|
839
|
+
incumbent_latency_ms: number | null;
|
|
840
|
+
incumbent_tokens_in: number | null;
|
|
841
|
+
incumbent_tokens_out: number | null;
|
|
842
|
+
source: 'sampled' | 'curated';
|
|
843
|
+
consent: string;
|
|
844
|
+
outcome_handle: string | null;
|
|
845
|
+
};
|
|
846
|
+
/**
|
|
847
|
+
* Persist one golden IR to `kgauto_golden_irs`. Same G1 write-leg discipline as
|
|
848
|
+
* every other brain route (redirect check, ledger, dead-letter); fire-and-forget
|
|
849
|
+
* by default, honors `BrainConfig.sync`. Never throws.
|
|
850
|
+
*/
|
|
851
|
+
declare function recordGoldenIr(input: GoldenIrRecordInput): Promise<void>;
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Golden-set eval engine (alpha.62, eval spine — design brief 2026-07-17).
|
|
855
|
+
*
|
|
856
|
+
* Implements the quality-floor-guarded model-swap contract:
|
|
857
|
+
*
|
|
858
|
+
* > A model replaces another on a surface only by demonstrating
|
|
859
|
+
* > same-or-better quality on that surface's real workload — never by
|
|
860
|
+
* > price, recency, or judgment alone.
|
|
861
|
+
*
|
|
862
|
+
* One eval run: load the active golden set for (app, archetype), replay every
|
|
863
|
+
* IR on BOTH the incumbent and the candidate (fresh outputs on both sides —
|
|
864
|
+
* fair comparison, no stale stored output), apply mechanical hard floors,
|
|
865
|
+
* then a pairwise LLM judge (order-swapped to cancel position bias), and
|
|
866
|
+
* aggregate under the non-inferiority rule:
|
|
867
|
+
*
|
|
868
|
+
* promote-ready ⇔ wins-or-ties ≥ threshold (default 80%)
|
|
869
|
+
* AND zero hard-floor violations
|
|
870
|
+
* AND candidate p50 latency ≤ ratio × incumbent p50
|
|
871
|
+
*
|
|
872
|
+
* Evidence lands as brain rows: one `kgauto_golden_eval_runs` aggregate + one
|
|
873
|
+
* `probe_outcomes` row per case (`replay_source='golden-replay'`, full
|
|
874
|
+
* fidelity by construction) + an evidence-attached advisory on the consumer's
|
|
875
|
+
* advisory surface (trust-ladder Stage 1: eval runs, human clicks promote).
|
|
876
|
+
*
|
|
877
|
+
* Judging is PAIRWISE, not absolute — it operationalizes the quality-floor
|
|
878
|
+
* Common Pattern directly ("same or better, never less"). Each pair is judged
|
|
879
|
+
* twice with A/B order swapped; disagreement between the two orders is scored
|
|
880
|
+
* a tie (the honest reading of positional noise).
|
|
881
|
+
*
|
|
882
|
+
* This module is operator-grade: it talks to the brain via direct PostgREST
|
|
883
|
+
* with a service key (the watchers' convention), never through consumer
|
|
884
|
+
* proxies, and it deliberately does NOT call record() — eval traffic must not
|
|
885
|
+
* pollute compile_outcomes.
|
|
886
|
+
*/
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* What "better" means per archetype. Fed verbatim into the pairwise judge
|
|
890
|
+
* prompt. Kept deliberately short — the judge sees the full request, so the
|
|
891
|
+
* rubric only needs to name the failure modes that matter for the archetype.
|
|
892
|
+
*/
|
|
893
|
+
declare const JUDGE_RUBRICS: Record<string, string>;
|
|
894
|
+
declare function rubricFor(archetype: string): string;
|
|
895
|
+
/** Render the golden IR's request for the judge (system sections + user turn). */
|
|
896
|
+
declare function renderIrForJudge(ir: PromptIR): string;
|
|
897
|
+
declare function buildPairwiseJudgePrompt(args: {
|
|
898
|
+
archetype: string;
|
|
899
|
+
renderedInput: string;
|
|
900
|
+
outputA: string;
|
|
901
|
+
outputB: string;
|
|
902
|
+
}): string;
|
|
903
|
+
type PairwiseWinner = 'A' | 'B' | 'tie';
|
|
904
|
+
/** Parse the judge's JSON verdict. Returns undefined when unparseable. */
|
|
905
|
+
declare function parseJudgeVerdict(raw: string): {
|
|
906
|
+
winner: PairwiseWinner;
|
|
907
|
+
rationale?: string;
|
|
908
|
+
} | undefined;
|
|
909
|
+
/**
|
|
910
|
+
* Combine the two order-swapped verdicts into a case verdict. Both verdicts
|
|
911
|
+
* are expressed in incumbent/candidate terms BEFORE this call (the caller
|
|
912
|
+
* un-swaps run 2). Agreement → that verdict; disagreement → 'tied' (positional
|
|
913
|
+
* noise reads as a tie, never as a win).
|
|
914
|
+
*/
|
|
915
|
+
declare function combineOrderSwappedVerdicts(run1: 'candidate-better' | 'current-better' | 'tied', run2: 'candidate-better' | 'current-better' | 'tied'): 'candidate-better' | 'current-better' | 'tied';
|
|
916
|
+
interface GoldenEvalOptions {
|
|
917
|
+
appId: string;
|
|
918
|
+
archetype: string;
|
|
919
|
+
candidateModel: string;
|
|
920
|
+
/**
|
|
921
|
+
* Incumbent to compare against. Default: the most frequent incumbent_model
|
|
922
|
+
* across the loaded golden set (the surface's de-facto leader).
|
|
923
|
+
*/
|
|
924
|
+
incumbentModel?: string;
|
|
925
|
+
/** Judge model id. Default 'claude-opus-4-8' (judge chain tier 0). */
|
|
926
|
+
judgeModel?: string;
|
|
927
|
+
/** Max golden cases to load (newest first). Default 50. */
|
|
928
|
+
limit?: number;
|
|
929
|
+
/** Non-inferiority threshold on wins-or-ties. Default 0.8. */
|
|
930
|
+
winOrTieThreshold?: number;
|
|
931
|
+
/** Latency hard floor: candidate p50 ≤ ratio × incumbent p50. Default 3. */
|
|
932
|
+
latencyFloorRatio?: number;
|
|
933
|
+
/** Minimum judged cases for a non-inconclusive verdict. Default 5. */
|
|
934
|
+
minJudgeableCases?: number;
|
|
935
|
+
/** What fired the eval. Default 'manual' (Stage 1). */
|
|
936
|
+
triggerSource?: 'manual' | 'supply' | 'price' | 'demand';
|
|
937
|
+
/** Brain access — direct PostgREST (operator convention). */
|
|
938
|
+
supabaseUrl: string;
|
|
939
|
+
serviceKey: string;
|
|
940
|
+
/** Provider keys for the replay + judge calls. Default: process.env. */
|
|
941
|
+
apiKeys?: ApiKeys;
|
|
942
|
+
fetchImpl?: typeof fetch;
|
|
943
|
+
/** Replay + judge but write NOTHING to the brain. */
|
|
944
|
+
dryRun?: boolean;
|
|
945
|
+
onProgress?: (message: string) => void;
|
|
946
|
+
}
|
|
947
|
+
interface GoldenEvalCase {
|
|
948
|
+
goldenIrId: number;
|
|
949
|
+
verdict: 'candidate-better' | 'tied' | 'current-better' | 'inconclusive';
|
|
950
|
+
judgeRationale?: string;
|
|
951
|
+
/** Hard-floor violations on the candidate side for this case. */
|
|
952
|
+
floorViolations: Array<'empty' | 'schema' | 'candidate_error'>;
|
|
953
|
+
errorClass?: string;
|
|
954
|
+
incumbent?: {
|
|
955
|
+
latencyMs: number;
|
|
956
|
+
tokensIn: number;
|
|
957
|
+
tokensOut: number;
|
|
958
|
+
text: string;
|
|
959
|
+
};
|
|
960
|
+
candidate?: {
|
|
961
|
+
latencyMs: number;
|
|
962
|
+
tokensIn: number;
|
|
963
|
+
tokensOut: number;
|
|
964
|
+
text: string;
|
|
965
|
+
};
|
|
966
|
+
/** Case excluded from the denominator (incumbent replay/judge failed). */
|
|
967
|
+
excludedReason?: string;
|
|
172
968
|
}
|
|
969
|
+
interface GoldenEvalRunResult {
|
|
970
|
+
verdict: 'promote-ready' | 'not-inferior' | 'inconclusive';
|
|
971
|
+
runId?: number;
|
|
972
|
+
appId: string;
|
|
973
|
+
archetype: string;
|
|
974
|
+
incumbentModel: string;
|
|
975
|
+
candidateModel: string;
|
|
976
|
+
judgeModel: string;
|
|
977
|
+
nCases: number;
|
|
978
|
+
wins: number;
|
|
979
|
+
ties: number;
|
|
980
|
+
losses: number;
|
|
981
|
+
floorViolations: number;
|
|
982
|
+
floorDetail: Record<string, number>;
|
|
983
|
+
winOrTieRatio: number | null;
|
|
984
|
+
latencyRatio: number | null;
|
|
985
|
+
costIncumbentUsd: number | null;
|
|
986
|
+
costCandidateUsd: number | null;
|
|
987
|
+
advisoryOutcomeId?: number;
|
|
988
|
+
cases: GoldenEvalCase[];
|
|
989
|
+
notes: string[];
|
|
990
|
+
}
|
|
991
|
+
declare function runGoldenEval(opts: GoldenEvalOptions): Promise<GoldenEvalRunResult>;
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* alpha.60 — the library's own version, baked as a constant so Edge/Worker
|
|
995
|
+
* runtimes (no fs, no require) can report it on wire surfaces. First
|
|
996
|
+
* consumer: `createKeyHealthRoute` carries it as `library_version`, which is
|
|
997
|
+
* how the operator dashboard's Fleet panel sees per-consumer vendor drift
|
|
998
|
+
* LIVE instead of via wrap-time package.json probes (the L-093 family
|
|
999
|
+
* "declared state lags actual" fix at the vendor-version axis — s47 found
|
|
1000
|
+
* IC 13 alphas stale that way).
|
|
1001
|
+
*
|
|
1002
|
+
* Kept in sync with package.json by hand at each version bump; the drift
|
|
1003
|
+
* guard in `tests/version.test.ts` fails the suite (and therefore
|
|
1004
|
+
* `prepublishOnly`) when they diverge — a stale constant cannot reach npm.
|
|
1005
|
+
*/
|
|
1006
|
+
declare const LIBRARY_VERSION = "2.0.0-alpha.70";
|
|
173
1007
|
|
|
174
1008
|
/**
|
|
175
1009
|
* Oracle contract — how an app tells the brain whether a response was good.
|
|
@@ -222,6 +1056,34 @@ interface LLMJudgeOptions {
|
|
|
222
1056
|
*/
|
|
223
1057
|
declare function buildLLMJudge(opts: LLMJudgeOptions): AppOracle;
|
|
224
1058
|
|
|
1059
|
+
/**
|
|
1060
|
+
* Resolve the effective ArchetypeConvention[] for a given selected profile,
|
|
1061
|
+
* walking family inheritance once. Model-specific entries on the selected
|
|
1062
|
+
* profile take precedence over family-level entries for the same archetype.
|
|
1063
|
+
*
|
|
1064
|
+
* Pure; safe to call from any context (probe-watcher uses the same logic
|
|
1065
|
+
* via `applyArchetypeConvention`).
|
|
1066
|
+
*/
|
|
1067
|
+
declare function resolveConventionsForProfile(profile: ModelProfile): ArchetypeConvention[];
|
|
1068
|
+
/**
|
|
1069
|
+
* Pure helper: apply the matching ArchetypeConvention's suffix (and
|
|
1070
|
+
* prefix, when meaningful) to a plain prompt-text string. Used by the
|
|
1071
|
+
* exclusion-probe-watcher (`probeOne`) so probe calls carry the same
|
|
1072
|
+
* forcing-function shape consumers see at compile time. Without this,
|
|
1073
|
+
* every reasoner probe on a decisive archetype gets unfairly stay-excluded
|
|
1074
|
+
* for hedging — as ID 20 demonstrated on 2026-05-28.
|
|
1075
|
+
*
|
|
1076
|
+
* Resolution: looks up the family-rep profile for `family` and reads its
|
|
1077
|
+
* `archetypeConventions`. Returns the original text unchanged when no
|
|
1078
|
+
* convention matches or when the suffix is already present.
|
|
1079
|
+
*
|
|
1080
|
+
* @param promptText raw user-prompt text (or prompt_preview from outcome)
|
|
1081
|
+
* @param archetype intent_archetype from the finding row
|
|
1082
|
+
* @param family family tag from deriveFamilyFromModelId / brain row
|
|
1083
|
+
* @returns text with prefix/suffix applied (idempotent)
|
|
1084
|
+
*/
|
|
1085
|
+
declare function applyArchetypeConvention(promptText: string, archetype: string, family: string): string;
|
|
1086
|
+
|
|
225
1087
|
/**
|
|
226
1088
|
* Tokenizer abstraction.
|
|
227
1089
|
*
|
|
@@ -245,6 +1107,75 @@ declare function resetTokenizer(): void;
|
|
|
245
1107
|
*/
|
|
246
1108
|
declare function countTokens(text: string): number;
|
|
247
1109
|
|
|
1110
|
+
/**
|
|
1111
|
+
* archetype-fits — alpha.43.
|
|
1112
|
+
*
|
|
1113
|
+
* Static table of "this archetype tends to be a better fit for this family"
|
|
1114
|
+
* recommendations. Powers the `cross-family-fit-candidate` compile-time
|
|
1115
|
+
* advisor (see `advisor-rules/cross-family-fit.ts`).
|
|
1116
|
+
*
|
|
1117
|
+
* Strategic framing (Sacha, 2026-05-28): "If we get better results and
|
|
1118
|
+
* better price then we do. Even if volume is currently low, that's not an
|
|
1119
|
+
* argument to not do it. Volume can increase quickly if tools is great to
|
|
1120
|
+
* use, let's not create future bottlenecks because we could have wired in
|
|
1121
|
+
* better solution at moment of knowing."
|
|
1122
|
+
*
|
|
1123
|
+
* The convention substrate (passApplyConventions) is the NEGATIVE side:
|
|
1124
|
+
* make a family usable on archetypes it currently fails. This table is the
|
|
1125
|
+
* POSITIVE side: actively surface that a different family is the better
|
|
1126
|
+
* fit for the archetype's shape — even when current volume is low.
|
|
1127
|
+
*
|
|
1128
|
+
* Entries are added only when:
|
|
1129
|
+
* - the archetype's shape and the family's behavior have a clear
|
|
1130
|
+
* architectural fit (not vibes)
|
|
1131
|
+
* - real-world evidence (brain rows, probe outcomes, or published
|
|
1132
|
+
* benchmark) backs the claim, OR the reasoning is structurally so clear
|
|
1133
|
+
* that "wait for volume" would create a future bottleneck
|
|
1134
|
+
*
|
|
1135
|
+
* Alpha.43 ships two entries — `plan` and `critique`. Both fit the
|
|
1136
|
+
* reasoner-family architectural read: plan is multi-step reasoning;
|
|
1137
|
+
* critique rewards epistemic humility and explicit reasoning. Other
|
|
1138
|
+
* archetype-family-fits ride later alphas as evidence accumulates.
|
|
1139
|
+
*
|
|
1140
|
+
* Anti-pattern: do NOT add archetype-family-fits for archetypes where the
|
|
1141
|
+
* fit is unclear (summarize, classify, extract, hunt with parallel tools).
|
|
1142
|
+
* The advisor only earns trust when its recommendations land.
|
|
1143
|
+
*/
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* One archetype-family-fit recommendation. Read by the compile-time
|
|
1147
|
+
* `cross-family-fit-candidate` advisor to decide when to surface a positive
|
|
1148
|
+
* recommendation. The advisor pulls `costGuidance` verbatim into the
|
|
1149
|
+
* advisory message.
|
|
1150
|
+
*/
|
|
1151
|
+
interface ArchetypeFamilyFit {
|
|
1152
|
+
/** Intent archetype this fit applies to. */
|
|
1153
|
+
archetype: IntentArchetypeName;
|
|
1154
|
+
/** Family tag that fits the archetype better than alternatives. Matches the
|
|
1155
|
+
* same family taxonomy used by `family-resolution.deriveFamilyFromModelId`
|
|
1156
|
+
* (e.g. `'deepseek-reasoner'`, `'gemini-flash'`, `'claude-opus'`). */
|
|
1157
|
+
betterFitFamily: string;
|
|
1158
|
+
/** Architectural / evidentiary justification. Appears in the advisor's
|
|
1159
|
+
* internal logs and the advisory `evidence` payload, NOT verbatim in the
|
|
1160
|
+
* consumer-facing message. */
|
|
1161
|
+
reason: string;
|
|
1162
|
+
/** Cost-context clause surfaced VERBATIM in the consumer-facing advisory
|
|
1163
|
+
* message (e.g. "substantially cheaper at current pricing"). Keep
|
|
1164
|
+
* declarative; the advisor wraps this into the larger sentence. */
|
|
1165
|
+
costGuidance: string;
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Frozen registry. Add entries by extending the array. Order is irrelevant
|
|
1169
|
+
* — the advisor filters by `(archetype, currentFamily)` independently.
|
|
1170
|
+
*/
|
|
1171
|
+
declare const ARCHETYPE_FAMILY_FITS: readonly ArchetypeFamilyFit[];
|
|
1172
|
+
/**
|
|
1173
|
+
* Pure lookup: does `(archetype, currentFamily)` have a better-fit family?
|
|
1174
|
+
* Returns the fit entry when the current family is NOT the better fit; null
|
|
1175
|
+
* otherwise. Used by the advisor to decide whether to fire.
|
|
1176
|
+
*/
|
|
1177
|
+
declare function findBetterFit(archetype: string, currentFamily: string): ArchetypeFamilyFit | null;
|
|
1178
|
+
|
|
248
1179
|
/**
|
|
249
1180
|
* Best-practice advisor — alpha.6 Phase 1.
|
|
250
1181
|
*
|
|
@@ -275,10 +1206,1801 @@ declare function countTokens(text: string): number;
|
|
|
275
1206
|
/** Subset of CompileResult fields the advisor needs. */
|
|
276
1207
|
type AdvisorContext = Pick<CompileResult, 'target' | 'provider' | 'tokensIn' | 'diagnostics'>;
|
|
277
1208
|
/**
|
|
278
|
-
*
|
|
279
|
-
*
|
|
1209
|
+
* Optional Phase 2 (alpha.22) context — fallback chain + a profile resolver
|
|
1210
|
+
* for cross-model comparison. Three new rules
|
|
1211
|
+
* (`cost-mismatched-archetype`, `model-stale-evidence`, `tier-down`) consume
|
|
1212
|
+
* this to surface measurement-substrate signals (alpha.20 clean-attribution +
|
|
1213
|
+
* alpha.21 grounding labels) as actionable consumer guidance.
|
|
1214
|
+
*
|
|
1215
|
+
* When `fallbackChain` is empty, rules 1 + 3 stay silent (nothing to
|
|
1216
|
+
* compare against). When `profileResolver` is omitted, the rules degrade
|
|
1217
|
+
* gracefully — they can still inspect the chosen profile but not chain
|
|
1218
|
+
* alternatives. Rule 2 (`model-stale-evidence`) is independent of chain
|
|
1219
|
+
* shape and works on the chosen model alone.
|
|
1220
|
+
*/
|
|
1221
|
+
interface RunAdvisorPhase2Context {
|
|
1222
|
+
fallbackChain: string[];
|
|
1223
|
+
profileResolver?: (id: string) => ModelProfile | undefined;
|
|
1224
|
+
/**
|
|
1225
|
+
* alpha.29 — translator rewrites that fired this compile. When a rewrite
|
|
1226
|
+
* cleared the cliff (e.g. `tool_call_contract` → sequential-tool preamble
|
|
1227
|
+
* + `parallelToolCalls: false`), the matching cliff advisor
|
|
1228
|
+
* (`archetype-perf-floor-breach`) MUST suppress for the same call. Without
|
|
1229
|
+
* suppression both fire — the advisory contradicts the rewrite ("cliff is
|
|
1230
|
+
* unaddressed" vs "we just addressed it").
|
|
1231
|
+
*
|
|
1232
|
+
* Empty array / undefined → no suppression (alpha.28 behavior preserved).
|
|
1233
|
+
*/
|
|
1234
|
+
sectionRewritesApplied?: SectionRewrite[];
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* alpha.42 — rule codes whose advisories are positioned for kgauto (not
|
|
1238
|
+
* the consumer) to act on. Used by `compile()` to default the `ownership`
|
|
1239
|
+
* stamp on each advisory when the rule didn't self-declare. Consumer-side
|
|
1240
|
+
* rules don't need to be listed — they default to `'consumer-actionable'`
|
|
1241
|
+
* via fall-through.
|
|
1242
|
+
*
|
|
1243
|
+
* - `model-stale-evidence`: kgauto's profile data is out of date; the
|
|
1244
|
+
* consumer can't fix that, kgauto needs to update profiles or refresh
|
|
1245
|
+
* archetypePerf scores.
|
|
1246
|
+
* - `promote-ready`: kgauto's promotion-probe-watcher detected a
|
|
1247
|
+
* candidate model worth promoting; consumer-side adoption is downstream
|
|
1248
|
+
* of kgauto adding it to the chain / family taxonomy.
|
|
1249
|
+
*
|
|
1250
|
+
* Frozen so consumers and tests can't mutate the global ownership map.
|
|
1251
|
+
*/
|
|
1252
|
+
declare const PRODUCER_OWNED_RULE_CODES: ReadonlySet<string>;
|
|
1253
|
+
/**
|
|
1254
|
+
* alpha.42 — pure function used by `compile()` to decide ownership for an
|
|
1255
|
+
* advisory. Rule-self-declared wins; falls back to the static map; defaults
|
|
1256
|
+
* `consumer-actionable`. Exported so consumer-side code (or a Glass-Box
|
|
1257
|
+
* renderer) can derive the same classification from a rule code alone
|
|
1258
|
+
* without needing the advisory object.
|
|
1259
|
+
*/
|
|
1260
|
+
declare function deriveOwnership(code: string, selfDeclared?: 'consumer-actionable' | 'producer-owned'): 'consumer-actionable' | 'producer-owned';
|
|
1261
|
+
/**
|
|
1262
|
+
* Run all phased rules and return collected advisories. Order is fixed so
|
|
1263
|
+
* output is stable across runs. The `policy` argument is alpha.9 — the
|
|
1264
|
+
* `single-model-array` rule needs to know whether the consumer explicitly
|
|
1265
|
+
* declared `posture: 'locked'` (in which case single-model is intentional
|
|
1266
|
+
* and shouldn't warn).
|
|
1267
|
+
*
|
|
1268
|
+
* `phase2` is alpha.22 — gives the advisor access to the fallback chain +
|
|
1269
|
+
* a profile resolver so the three new compile-time recommendation rules
|
|
1270
|
+
* (`cost-mismatched-archetype`, `model-stale-evidence`, `tier-down`) can
|
|
1271
|
+
* compare the chosen model against in-chain alternatives. Optional for
|
|
1272
|
+
* backward compatibility with consumers calling `runAdvisor()` directly.
|
|
1273
|
+
*/
|
|
1274
|
+
declare function runAdvisor(ir: PromptIR, result: AdvisorContext, profile: ModelProfile, policy?: CompilePolicy, phase2?: RunAdvisorPhase2Context): BestPracticeAdvisory[];
|
|
1275
|
+
|
|
1276
|
+
/**
|
|
1277
|
+
* Translator primitive — alpha.31.
|
|
1278
|
+
*
|
|
1279
|
+
* Pure function. Walks `IR.sections`, matches each section's `kind` against
|
|
1280
|
+
* a per-rule dispatch table keyed on (kind, profile, archetype), and applies
|
|
1281
|
+
* a model-aware rewrite when a rule fires. Returns the rewritten IR + the
|
|
1282
|
+
* list of rewrites for `CompileResult.sectionRewritesApplied` and brain
|
|
1283
|
+
* persistence.
|
|
1284
|
+
*
|
|
1285
|
+
* This is the s37 translator-framing eureka in code: kgauto graduates from
|
|
1286
|
+
* "gate" (alpha.28's cliff advisor: "consumer must accept adapter") to
|
|
1287
|
+
* "translator" (alpha.29: "consumer declared the section kind, kgauto
|
|
1288
|
+
* applies the adapter at compile time without consumer-side branching").
|
|
1289
|
+
*
|
|
1290
|
+
* Rules shipped:
|
|
1291
|
+
*
|
|
1292
|
+
* alpha.29 — tool_call_contract + archetypePerf[archetype] < TRANSLATOR_FLOOR
|
|
1293
|
+
* → prepend sequential-tool-pattern guidance
|
|
1294
|
+
* → emit wireOverrides: { parallelToolCalls: false }
|
|
1295
|
+
* → rule_id: 'sequential-tool-cliff-below-floor'
|
|
1296
|
+
*
|
|
1297
|
+
* alpha.31 — narration_contract + profile.provider === 'anthropic'
|
|
1298
|
+
* → prepend terse-log narration guidance
|
|
1299
|
+
* → no wireOverrides
|
|
1300
|
+
* → rule_id: 'narration-drift-anthropic'
|
|
1301
|
+
*
|
|
1302
|
+
* alpha.31 — narration_contract + profile.provider === 'deepseek'
|
|
1303
|
+
* → prepend <thinking>-suppression guidance
|
|
1304
|
+
* → no wireOverrides
|
|
1305
|
+
* → rule_id: 'narration-thinking-leak-deepseek'
|
|
1306
|
+
*
|
|
1307
|
+
* Per-rule walk (alpha.31 refactor): the alpha.30 short-circuit
|
|
1308
|
+
* `if (!cliffFires) return passthrough` was correct when only the
|
|
1309
|
+
* cliff-gated tool_call_contract rule existed; alpha.31's narration rules
|
|
1310
|
+
* fire on every call regardless of cliff (narration drift is steady-state,
|
|
1311
|
+
* not a cliff condition). Each section now consults the dispatch table
|
|
1312
|
+
* independently — first-match wins per (section.kind, profile, archetype).
|
|
1313
|
+
*
|
|
1314
|
+
* **Interaction with the cliff advisor (alpha.28):** when this translator
|
|
1315
|
+
* fires for a `tool_call_contract` section, the advisor's
|
|
1316
|
+
* `archetype-perf-floor-breach` rule MUST suppress for the same call — the
|
|
1317
|
+
* cliff was structurally cleared by the rewrite, not unaddressed. The
|
|
1318
|
+
* suppression check lives in `advisor.ts` and consults the
|
|
1319
|
+
* `CompileResult.sectionRewritesApplied` list.
|
|
1320
|
+
*
|
|
1321
|
+
* Design contracts:
|
|
1322
|
+
* command-center/advisory/kgauto/2026-05-21_alpha-29-translator-and-advisories-api.md
|
|
1323
|
+
* command-center/advisory/kgauto/2026-05-22_alpha-31-narration-contract.md
|
|
1324
|
+
*/
|
|
1325
|
+
|
|
1326
|
+
/**
|
|
1327
|
+
* Re-export of `ARCHETYPE_FLOOR_DEFAULT` as the canonical "translator fires
|
|
1328
|
+
* below this score" threshold. Same constant as the cliff advisor — the
|
|
1329
|
+
* single threshold is shared (alpha.28's "below this, advisor warns"; alpha.29's
|
|
1330
|
+
* "below this, translator AUTO-APPLIES the adapter").
|
|
1331
|
+
*/
|
|
1332
|
+
declare const TRANSLATOR_FLOOR = 6;
|
|
1333
|
+
/**
|
|
1334
|
+
* Stable identifier of the alpha.29 sequential-tool rule. Surfaces on
|
|
1335
|
+
* `SectionRewrite.rule` and in brain aggregates. The brain treats this
|
|
1336
|
+
* identifier together with the preamble string as the rule's wire
|
|
1337
|
+
* fingerprint — both stay byte-stable across releases.
|
|
1338
|
+
*/
|
|
1339
|
+
declare const RULE_SEQUENTIAL_TOOL_CLIFF = "sequential-tool-cliff-below-floor";
|
|
1340
|
+
interface ApplySectionRewritesArgs {
|
|
1341
|
+
ir: PromptIR;
|
|
1342
|
+
profile: ModelProfile;
|
|
1343
|
+
archetype: IntentArchetypeName;
|
|
1344
|
+
/**
|
|
1345
|
+
* alpha.68 / Release A — resolved output shape for Factor C (§5.D). `'json'`
|
|
1346
|
+
* ⇒ structured surface (the discipline gate MUST NOT fire — gates 5+6 are
|
|
1347
|
+
* shape-altering and would break the consumer's parser). `'text'` ⇒ free-form
|
|
1348
|
+
* surface (the gate may fire). Optional: when omitted, derived from
|
|
1349
|
+
* `ir.constraints?.structuredOutput` (true ⇒ 'json', else 'text') so callers
|
|
1350
|
+
* / tests need not pass it. compile() passes it explicitly.
|
|
1351
|
+
*/
|
|
1352
|
+
outputMode?: OutputMode;
|
|
1353
|
+
}
|
|
1354
|
+
interface ApplySectionRewritesResult {
|
|
1355
|
+
/**
|
|
1356
|
+
* IR with section.text fields possibly rewritten. When no rewrites fired,
|
|
1357
|
+
* this is identical to the input IR (referentially distinct array but
|
|
1358
|
+
* same section payloads).
|
|
1359
|
+
*/
|
|
1360
|
+
rewrittenIR: PromptIR;
|
|
1361
|
+
/**
|
|
1362
|
+
* One entry per section the translator rewrote. Empty array when no
|
|
1363
|
+
* rules fired. Order matches the corresponding section in
|
|
1364
|
+
* `rewrittenIR.sections`.
|
|
1365
|
+
*/
|
|
1366
|
+
rewrites: SectionRewrite[];
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Pure function. Apply model-aware section rewrites to the IR at compile time.
|
|
1370
|
+
*
|
|
1371
|
+
* Discipline:
|
|
1372
|
+
* - Never mutates the input IR; returns a new IR with new sections array
|
|
1373
|
+
* when at least one rewrite fired; otherwise returns the input IR by
|
|
1374
|
+
* reference (referential identity preserved on no-op).
|
|
1375
|
+
* - Sections without a `kind` (or `kind === 'arbitrary'`) pass through
|
|
1376
|
+
* unchanged.
|
|
1377
|
+
* - Empty `sections` array → returns `{ rewrittenIR: ir, rewrites: [] }`.
|
|
1378
|
+
* - Sections of the same `kind` are processed in array order; first-match
|
|
1379
|
+
* wins per section. (Today every rule is a single-match rule.)
|
|
1380
|
+
*
|
|
1381
|
+
* @example
|
|
1382
|
+
* ```ts
|
|
1383
|
+
* import { applySectionRewrites } from '@warmdrift/kgauto-compiler';
|
|
1384
|
+
* import { getProfile } from '@warmdrift/kgauto-compiler';
|
|
1385
|
+
*
|
|
1386
|
+
* const { rewrittenIR, rewrites } = applySectionRewrites({
|
|
1387
|
+
* ir,
|
|
1388
|
+
* profile: getProfile('deepseek-v4-pro'),
|
|
1389
|
+
* archetype: 'hunt',
|
|
1390
|
+
* });
|
|
1391
|
+
* if (rewrites.length > 0) console.log('translator fired:', rewrites);
|
|
1392
|
+
* ```
|
|
1393
|
+
*/
|
|
1394
|
+
declare function applySectionRewrites(args: ApplySectionRewritesArgs): ApplySectionRewritesResult;
|
|
1395
|
+
|
|
1396
|
+
/**
|
|
1397
|
+
* advisories-api — structured advisories API (alpha.29 Workstream B).
|
|
1398
|
+
*
|
|
1399
|
+
* Closes the L-117 family bottleneck: kgauto's `result.advisories[]` (the
|
|
1400
|
+
* compile-time warnings about caching-off, tool-bloat, archetype-perf-floor
|
|
1401
|
+
* breaches, etc.) used to disappear after the consumer read the compile
|
|
1402
|
+
* result. The s34 caching-off advisory pattern is the canonical failure: an
|
|
1403
|
+
* advisory fired 100+ times in 24h on `generate::sonnet` at 99.4% empty
|
|
1404
|
+
* rate, and nobody knew because there was no structured channel to surface
|
|
1405
|
+
* "what's open right now?"
|
|
1406
|
+
*
|
|
1407
|
+
* Migration 020 ships the substrate: `compile_outcome_advisories` gains
|
|
1408
|
+
* lifecycle columns (`resolved_at`, `resolution_source`, `resolution_note`)
|
|
1409
|
+
* and the `actionable_advisories_v` view rolls per-firing rows into
|
|
1410
|
+
* per-(app_id, code) tuples with deterministic stable ids + server-side
|
|
1411
|
+
* auto-resolution.
|
|
1412
|
+
*
|
|
1413
|
+
* Public surface:
|
|
1414
|
+
* getActionableAdvisories({ appId, severity?, status?, brainEndpoint, brainJwt, brainAnonKey, fetch? })
|
|
1415
|
+
* → Promise<ActionableAdvisory[]>
|
|
1416
|
+
*
|
|
1417
|
+
* markAdvisoryResolved({ id, resolutionNote?, brainEndpoint, brainJwt, brainAnonKey, fetch? })
|
|
1418
|
+
* → Promise<{ ok: true } | { ok: false; reason: string }>
|
|
1419
|
+
*
|
|
1420
|
+
* Both functions are pure I/O — no module-level state. The fetch wiring
|
|
1421
|
+
* mirrors `createProxyHandler` in `glassbox-routes/proxy.ts`: scoped JWT in
|
|
1422
|
+
* `Authorization: Bearer`, `apikey` header carries the anon key.
|
|
1423
|
+
*
|
|
1424
|
+
* The auto-resolution rule is enforced server-side in `actionable_advisories_v`:
|
|
1425
|
+
* • Latest firing > 14 days ago → status='resolved' (auto-pruned)
|
|
1426
|
+
* • All firings have resolved_at set → status='resolved' (consumer-marked)
|
|
1427
|
+
* • Otherwise → status='open'
|
|
1428
|
+
*
|
|
1429
|
+
* `markAdvisoryResolved` is the consumer override: "I fixed it; the next
|
|
1430
|
+
* firing will reopen the rule, but until then it stays resolved."
|
|
1431
|
+
*/
|
|
1432
|
+
|
|
1433
|
+
/**
|
|
1434
|
+
* Severity of an advisory. Maps to the `level` column on
|
|
1435
|
+
* `compile_outcome_advisories` (info | warn | critical).
|
|
1436
|
+
*/
|
|
1437
|
+
type AdvisorySeverity = 'info' | 'warn' | 'critical';
|
|
1438
|
+
/**
|
|
1439
|
+
* Status of an advisory rollup.
|
|
1440
|
+
*
|
|
1441
|
+
* - `open` — at least one unresolved firing in the last 14 days
|
|
1442
|
+
* - `resolved` — either auto-pruned (no firings >14d) or consumer-marked
|
|
1443
|
+
* - `snoozed` — reserved for alpha.30+ (snooze-until-date); type-accepted
|
|
1444
|
+
* today but the view will never emit this value
|
|
1445
|
+
*/
|
|
1446
|
+
type AdvisoryStatus = 'open' | 'snoozed' | 'resolved';
|
|
1447
|
+
/**
|
|
1448
|
+
* Source of resolution when status='resolved'.
|
|
1449
|
+
*
|
|
1450
|
+
* - `auto` — server-side rule auto-pruned (>14d since last firing)
|
|
1451
|
+
* - `consumer-marked` — consumer called `markAdvisoryResolved`
|
|
1452
|
+
* - `declined` — reserved (alpha.30+: consumer marked the suggestion
|
|
1453
|
+
* inapplicable; the advisor will still fire but UIs can hide it)
|
|
1454
|
+
*/
|
|
1455
|
+
type AdvisoryResolutionSource = 'auto' | 'consumer-marked' | 'declined';
|
|
1456
|
+
/**
|
|
1457
|
+
* Suggested-fix metadata. `null` when the advisor has no actionable fix
|
|
1458
|
+
* (info-level rules can be observational). When set, the consumer's
|
|
1459
|
+
* Admin UI can render a one-click apply (alpha.30+) or surface the
|
|
1460
|
+
* before/after diff inline.
|
|
1461
|
+
*/
|
|
1462
|
+
interface AdvisorySuggestedFix {
|
|
1463
|
+
type: 'config-change' | 'one-liner' | 'env-var' | 'manual';
|
|
1464
|
+
/** File:line hint if kgauto can infer (reserved — alpha.30+). */
|
|
1465
|
+
siteHint?: string;
|
|
1466
|
+
before?: string;
|
|
1467
|
+
after?: string;
|
|
1468
|
+
docsLink?: string;
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Per-(app_id, code) advisory rollup. The `id` is stable across polls
|
|
1472
|
+
* until the rule auto-resolves and re-opens (a new firing after the 14d
|
|
1473
|
+
* boundary advances `opened_at` → new id). Treat id-changes as
|
|
1474
|
+
* intentional "fresh re-open" signals.
|
|
1475
|
+
*
|
|
1476
|
+
* Wire-shape from `actionable_advisories_v`. The transformer maps the
|
|
1477
|
+
* view's snake_case columns to camelCase. See `feedback_typed_boundary_transformers.md`
|
|
1478
|
+
* (L-118) for the rationale.
|
|
1479
|
+
*/
|
|
1480
|
+
interface ActionableAdvisory {
|
|
1481
|
+
id: string;
|
|
1482
|
+
rule: string;
|
|
1483
|
+
severity: AdvisorySeverity;
|
|
1484
|
+
openedAt: string;
|
|
1485
|
+
lastObservedAt: string;
|
|
1486
|
+
observationCount: number;
|
|
1487
|
+
appliesTo: {
|
|
1488
|
+
archetype?: IntentArchetypeName;
|
|
1489
|
+
model?: string;
|
|
1490
|
+
callSiteHint?: string;
|
|
1491
|
+
};
|
|
1492
|
+
message: string;
|
|
1493
|
+
suggestedFix: AdvisorySuggestedFix | null;
|
|
1494
|
+
/** Reserved — always `false` in alpha.29. alpha.30+ ships actual auto-apply. */
|
|
1495
|
+
autoApplicable: boolean;
|
|
1496
|
+
status: AdvisoryStatus;
|
|
1497
|
+
resolvedAt?: string;
|
|
1498
|
+
resolutionSource?: AdvisoryResolutionSource;
|
|
1499
|
+
resolutionNote?: string;
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Filter + transport for `getActionableAdvisories`. The brain JWT must
|
|
1503
|
+
* carry an `app_id` claim matching `opts.appId` — RLS enforces tenant
|
|
1504
|
+
* isolation on the underlying table, so a mismatch silently returns [].
|
|
1505
|
+
*/
|
|
1506
|
+
interface GetActionableAdvisoriesOptions {
|
|
1507
|
+
appId: string;
|
|
1508
|
+
/** Severity filter; if omitted, all severities are returned. */
|
|
1509
|
+
severity?: AdvisorySeverity;
|
|
1510
|
+
/** Status filter; defaults to 'open'. Pass 'all' for the full set. */
|
|
1511
|
+
status?: 'open' | 'snoozed' | 'resolved' | 'all';
|
|
1512
|
+
brainEndpoint: string;
|
|
1513
|
+
brainJwt: string;
|
|
1514
|
+
brainAnonKey: string;
|
|
1515
|
+
fetch?: typeof fetch;
|
|
1516
|
+
}
|
|
1517
|
+
interface MarkAdvisoryResolvedOptions {
|
|
1518
|
+
/** Stable id from a prior `getActionableAdvisories` call. */
|
|
1519
|
+
id: string;
|
|
1520
|
+
resolutionNote?: string;
|
|
1521
|
+
brainEndpoint: string;
|
|
1522
|
+
brainJwt: string;
|
|
1523
|
+
brainAnonKey: string;
|
|
1524
|
+
fetch?: typeof fetch;
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Query the open advisory set for an app. Pulls from
|
|
1528
|
+
* `actionable_advisories_v` (per-(app_id, code) rollup with stable ids
|
|
1529
|
+
* + server-side auto-resolution).
|
|
1530
|
+
*
|
|
1531
|
+
* Default behavior (no status filter): returns only `status='open'`.
|
|
1532
|
+
* Pass `status: 'all'` to see resolved + open together — useful for
|
|
1533
|
+
* Admin UIs that show "recently fixed" badges.
|
|
1534
|
+
*
|
|
1535
|
+
* Fetch failures bubble out as thrown Errors. (`markAdvisoryResolved`
|
|
1536
|
+
* uses the ok/reason envelope; this read path throws to match
|
|
1537
|
+
* existing kgauto query semantics where the consumer can decide to
|
|
1538
|
+
* retry or render an error state.)
|
|
1539
|
+
*/
|
|
1540
|
+
declare function getActionableAdvisories(opts: GetActionableAdvisoriesOptions): Promise<ActionableAdvisory[]>;
|
|
1541
|
+
/**
|
|
1542
|
+
* Mark an advisory as consumer-resolved.
|
|
1543
|
+
*
|
|
1544
|
+
* Lookup strategy:
|
|
1545
|
+
* 1. Query `actionable_advisories_v?id=eq.<id>` to find the (app_id, code)
|
|
1546
|
+
* tuple for this advisory.
|
|
1547
|
+
* 2. PATCH the latest unresolved firing in `compile_outcome_advisories`
|
|
1548
|
+
* matching that tuple via the underlying outcome's app_id.
|
|
1549
|
+
*
|
|
1550
|
+
* The (app_id, code) lookup is necessary because `compile_outcome_advisories`
|
|
1551
|
+
* has no `app_id` column — it inherits scope via the FK to compile_outcomes.
|
|
1552
|
+
* PostgREST cannot PATCH with a JOIN predicate, so the markAdvisoryResolved
|
|
1553
|
+
* path is a two-step round-trip. The cost is one extra GET per resolve call;
|
|
1554
|
+
* acceptable because marks are low-frequency operator actions, not per-call
|
|
1555
|
+
* hot path.
|
|
1556
|
+
*
|
|
1557
|
+
* Idempotent re-marks: if the advisory is already resolved (no unresolved
|
|
1558
|
+
* firings match), the PATCH affects zero rows and the call still returns
|
|
1559
|
+
* `ok: true`. The function returns `ok: false` only on transport / auth /
|
|
1560
|
+
* lookup failures.
|
|
1561
|
+
*
|
|
1562
|
+
* Returns ok/reason envelope (vs throwing) because consumer Admin UIs
|
|
1563
|
+
* typically want to render the failure inline rather than crash.
|
|
1564
|
+
*/
|
|
1565
|
+
declare function markAdvisoryResolved(opts: MarkAdvisoryResolvedOptions): Promise<{
|
|
1566
|
+
ok: true;
|
|
1567
|
+
} | {
|
|
1568
|
+
ok: false;
|
|
1569
|
+
reason: string;
|
|
1570
|
+
}>;
|
|
1571
|
+
/**
|
|
1572
|
+
* Resolution sources supported by the alpha.39 `markExclusionFindingHandled`
|
|
1573
|
+
* API. Mirrors the subset of `exclusion_findings.resolution_source` CHECK
|
|
1574
|
+
* constraint values that consumers can self-set:
|
|
1575
|
+
*
|
|
1576
|
+
* - `'consumer-marked'` — generic "we've handled this; stop reminding."
|
|
1577
|
+
* Use this for "we evaluated and chose not to act" or "we'll act when
|
|
1578
|
+
* ready but acknowledge the finding now."
|
|
1579
|
+
* - `'declined'` — explicit "this exclusion is intentional; do not surface
|
|
1580
|
+
* again." Stronger signal than consumer-marked; useful for compliance
|
|
1581
|
+
* exclusions, brand-promise exclusions, etc.
|
|
1582
|
+
* - `'probed-unblock'` — alpha.40+ probe-path verdict: consumer ran a live
|
|
1583
|
+
* probe and decided to unblock the excluded model. Library accepts the
|
|
1584
|
+
* value today so the probe path doesn't need a follow-up API release.
|
|
1585
|
+
* - `'probed-stay-excluded'` — alpha.40+ probe-path verdict: consumer
|
|
1586
|
+
* probed and confirmed the exclusion. Same forward-compat shape as
|
|
1587
|
+
* `'probed-unblock'`.
|
|
1588
|
+
*
|
|
1589
|
+
* The `'auto'` resolution_source is NOT exposed here — that's reserved
|
|
1590
|
+
* for the brain's own automatic resolution (e.g. when the detection
|
|
1591
|
+
* conditions no longer hold). Consumer code sets only the four values
|
|
1592
|
+
* above.
|
|
1593
|
+
*/
|
|
1594
|
+
type ExclusionResolutionSource = 'consumer-marked' | 'declined' | 'probed-unblock' | 'probed-stay-excluded';
|
|
1595
|
+
interface MarkExclusionFindingHandledOptions {
|
|
1596
|
+
/** App id the finding belongs to. Required (RLS scopes writes by this). */
|
|
1597
|
+
appId: string;
|
|
1598
|
+
/** Archetype the finding applies to (e.g. 'hunt', 'classify'). */
|
|
1599
|
+
archetype: string;
|
|
1600
|
+
/** Canonical model id that the consumer had excluded. */
|
|
1601
|
+
excludedModel: string;
|
|
1602
|
+
/** Resolution semantics — see `ExclusionResolutionSource` for the four
|
|
1603
|
+
* values consumers can set. */
|
|
1604
|
+
resolution: ExclusionResolutionSource;
|
|
1605
|
+
/** Optional free-form note explaining the decision. Surfaces in operator
|
|
1606
|
+
* digests + dashboards alongside the resolution_source. */
|
|
1607
|
+
resolutionNote?: string;
|
|
1608
|
+
/** Brain Supabase URL base (e.g. `https://<project>.supabase.co`). The
|
|
1609
|
+
* function appends `/rest/v1/exclusion_findings?...`. */
|
|
1610
|
+
brainEndpoint: string;
|
|
1611
|
+
/** Consumer-scoped JWT carrying the `app_id` claim. The brain's RLS
|
|
1612
|
+
* policy enforces that the JWT's app_id matches the finding's app_id;
|
|
1613
|
+
* cross-tenant writes fail at the database layer regardless of input. */
|
|
1614
|
+
brainJwt: string;
|
|
1615
|
+
/** Supabase anon key for the `apikey` header (PostgREST requires it). */
|
|
1616
|
+
brainAnonKey: string;
|
|
1617
|
+
/** Injected fetch for tests. Defaults to global fetch. */
|
|
1618
|
+
fetch?: typeof fetch;
|
|
1619
|
+
}
|
|
1620
|
+
/**
|
|
1621
|
+
* Mark a stale-exclusion finding as handled. Returns an `ok/reason` envelope
|
|
1622
|
+
* matching `markAdvisoryResolved` — consumer Admin UIs typically render the
|
|
1623
|
+
* failure inline rather than crash.
|
|
1624
|
+
*
|
|
1625
|
+
* Idempotent: if no row matches the (app_id, archetype, excludedModel)
|
|
1626
|
+
* tuple (already resolved, never existed, cron not yet UPSERTed), PostgREST
|
|
1627
|
+
* returns 200 with zero affected rows and we return `{ ok: true }`. The
|
|
1628
|
+
* caller's "I marked it as handled" intent is satisfied regardless of
|
|
1629
|
+
* whether the row was already in that state.
|
|
1630
|
+
*
|
|
1631
|
+
* Reasons surfaced on failure:
|
|
1632
|
+
* - `app_id_required` / `archetype_required` / `excluded_model_required`
|
|
1633
|
+
* - `resolution_invalid` — `resolution` not one of the four documented values
|
|
1634
|
+
* - `brain_auth_misconfig` — 401/403 (JWT / anon key wrong)
|
|
1635
|
+
* - `brain_unavailable` — 5xx
|
|
1636
|
+
* - `network_error:<message>` — fetch threw
|
|
1637
|
+
* - `patch_failed:<status>` — anything else non-2xx
|
|
1638
|
+
*/
|
|
1639
|
+
declare function markExclusionFindingHandled(opts: MarkExclusionFindingHandledOptions): Promise<{
|
|
1640
|
+
ok: true;
|
|
1641
|
+
} | {
|
|
1642
|
+
ok: false;
|
|
1643
|
+
reason: string;
|
|
1644
|
+
}>;
|
|
1645
|
+
|
|
1646
|
+
/**
|
|
1647
|
+
* Archetype-cliff compatibility — alpha.28 (tt-intel-Cairn ratified).
|
|
1648
|
+
*
|
|
1649
|
+
* One question, one answer: *given this model and this intent, can it work
|
|
1650
|
+
* — and if not, what adapter (if any) would make it work?*
|
|
1651
|
+
*
|
|
1652
|
+
* Replaces the silent-archetype-cliff failure mode where a consumer picks a
|
|
1653
|
+
* model that's structurally wrong for the intent and kgauto compiles cleanly
|
|
1654
|
+
* without surfacing the gap. The triggering incident: tt-intel shipped
|
|
1655
|
+
* `deepseek-v4-pro` as the hunt default per a local spec; the kgauto coord
|
|
1656
|
+
* doc said L-040 — V4 is structurally wrong for hunt (sequential tools).
|
|
1657
|
+
* `archetypePerf.hunt = 4` was already in the profile data. The compiler
|
|
1658
|
+
* stayed silent. This API + the matching advisor rule surfaces it.
|
|
1659
|
+
*
|
|
1660
|
+
* Pure function. No network. No brain query. No side effects. ~1ms.
|
|
1661
|
+
*
|
|
1662
|
+
* Consultation doc:
|
|
1663
|
+
* command-center/advisory/kgauto/2026-05-21_archetype-cliff-advisor.md
|
|
1664
|
+
*
|
|
1665
|
+
* Refinements applied per tt-intel-Cairn ratification (2026-05-21):
|
|
1666
|
+
* R1: every variant carries `archetypePerf: number` (raw score) — and
|
|
1667
|
+
* `requires-adapter` adds `archetypePerfWithAdapter: number` so
|
|
1668
|
+
* consumer policy can be expressed as "accept adapter only when score
|
|
1669
|
+
* crosses some threshold WITH the adapter on."
|
|
1670
|
+
* R2: every variant carries a plain-English `reason: string`. No internal
|
|
1671
|
+
* jargon ("L-040", "archetypePerf=4") — the consumer chooses whether
|
|
1672
|
+
* to render it as UI hint or operator-tooling tooltip.
|
|
1673
|
+
* R3: `Adapter` is a CLOSED discriminated union, not `| string`. alpha.28
|
|
1674
|
+
* ships ONE variant (`toolOrchestration: 'sequential'`). Future
|
|
1675
|
+
* adapter parameters extend the union explicitly in named releases.
|
|
1676
|
+
* NO escape hatch — the whole point is catching "I added a new
|
|
1677
|
+
* adapter and forgot to update consumer policy" at compile time.
|
|
1678
|
+
*/
|
|
1679
|
+
|
|
1680
|
+
/**
|
|
1681
|
+
* Minimum `archetypePerf[archetype]` score to count as `compatible` under
|
|
1682
|
+
* Option A (default policy). Below this, a documented adapter is needed
|
|
1683
|
+
* to lift the model above the floor; if no adapter exists, the model is
|
|
1684
|
+
* rejected.
|
|
1685
|
+
*
|
|
1686
|
+
* Matches `QUALITY_FLOOR_FOR_RECOMMENDATION` in `advisor.ts` — kgauto's
|
|
1687
|
+
* library-wide convention for "below this score, swap recommendations stop."
|
|
1688
|
+
*/
|
|
1689
|
+
declare const ARCHETYPE_FLOOR_DEFAULT = 6;
|
|
1690
|
+
/**
|
|
1691
|
+
* Absolute floor — below this, the cliff is too steep for ANY adapter to
|
|
1692
|
+
* lift cleanly. Reserved under Option A (unused today; every below-floor
|
|
1693
|
+
* case is gated by adapter availability). Would gate `reject` vs
|
|
1694
|
+
* `requires-adapter` under a future Option B per consultation doc Q1.
|
|
1695
|
+
*
|
|
1696
|
+
* Exported so consumer-side policy can read it (e.g. "accept adapter only
|
|
1697
|
+
* when archetypePerf >= ABSOLUTE_FLOOR + 1"). Not used internally by
|
|
1698
|
+
* `getModelCompatibility` today — the gate is "does an adapter exist for
|
|
1699
|
+
* this cliff?", not score-based.
|
|
1700
|
+
*/
|
|
1701
|
+
declare const ABSOLUTE_FLOOR = 4;
|
|
1702
|
+
/**
|
|
1703
|
+
* The intent the call is expressing — archetype + optional orchestration
|
|
1704
|
+
* mode. Same shape as `ir.intent.archetype` + `ir.constraints.toolOrchestration`
|
|
1705
|
+
* so a consumer can pass `{ archetype: ir.intent.archetype,
|
|
1706
|
+
* toolOrchestration: ir.constraints?.toolOrchestration }` directly.
|
|
1707
|
+
*/
|
|
1708
|
+
interface CompatibilityIntent {
|
|
1709
|
+
archetype: IntentArchetypeName;
|
|
1710
|
+
toolOrchestration?: 'parallel' | 'sequential' | 'either';
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* `Adapter` — re-exported above. Canonical definition lives in `ir.ts` to
|
|
1714
|
+
* avoid an import cycle (compatibility.ts → profiles.ts → ir.ts).
|
|
1715
|
+
*
|
|
1716
|
+
* **CLOSED discriminated union per R3.** Future adapter parameters extend
|
|
1717
|
+
* the union explicitly in named alpha releases. No `| string` escape hatch
|
|
1718
|
+
* — consumer policy code SHOULD write exhaustive `switch (adapter.parameter)`
|
|
1719
|
+
* and rely on the compiler to flag "I added a new adapter parameter and
|
|
1720
|
+
* forgot to update the consumer's policy."
|
|
1721
|
+
*
|
|
1722
|
+
* alpha.28 variants:
|
|
1723
|
+
* - `{ parameter: 'toolOrchestration'; value: 'sequential'; consequence }`
|
|
1724
|
+
* Lifts DeepSeek V4-family on `hunt` from sequential-tool cliff (L-040).
|
|
1725
|
+
* The "consequence" plain-English-ifies the trade-off:
|
|
1726
|
+
* "Tool calls run one at a time — slower but reliable."
|
|
1727
|
+
*
|
|
1728
|
+
* alpha.29+ likely additions (per tt-intel-Cairn priority list):
|
|
1729
|
+
* - `{ parameter: 'parallelToolCalls'; value: false; consequence }`
|
|
1730
|
+
* - `{ parameter: 'maxTools'; value: number; consequence }`
|
|
1731
|
+
* - `{ parameter: 'thinkingBudget'; value: 0; consequence }`
|
|
1732
|
+
*
|
|
1733
|
+
* Each new variant lands in its own named release with the union extended
|
|
1734
|
+
* in `ir.ts`. Consumers see the change at compile time.
|
|
1735
|
+
*/
|
|
1736
|
+
/**
|
|
1737
|
+
* The compatibility verdict for a (model, intent) pair. Discriminated union
|
|
1738
|
+
* on `status` — `compatible` | `requires-adapter` | `reject`.
|
|
1739
|
+
*
|
|
1740
|
+
* **Every variant carries `archetypePerf` (R1) + `reason` (R2):**
|
|
1741
|
+
* - `archetypePerf` — the raw 0-10 score for (model, archetype). Lets
|
|
1742
|
+
* consumers build their own thresholds without re-importing the profile
|
|
1743
|
+
* registry.
|
|
1744
|
+
* - `reason` — plain-English, consumer-renderable. NOT internal jargon
|
|
1745
|
+
* like "L-040 cliff" or "archetypePerf=4". Examples in R2 ratification:
|
|
1746
|
+
* - compatible: "Suited for hunt-style parallel discovery."
|
|
1747
|
+
* - requires-adapter: "Best with sequential tool calls for hunt — slower but works."
|
|
1748
|
+
* - reject: "Not suited for hunt — would underperform significantly."
|
|
1749
|
+
*
|
|
1750
|
+
* `requires-adapter` additionally carries:
|
|
1751
|
+
* - `archetypePerfWithAdapter` — estimated post-adapter score. May be an
|
|
1752
|
+
* estimate (we don't measure post-adapter scores yet); kgauto's prior is
|
|
1753
|
+
* "adapter lifts to ARCHETYPE_FLOOR_DEFAULT + 1" unless brain-evidenced.
|
|
1754
|
+
* - `adapter` — the closed-union variant describing the structural change.
|
|
1755
|
+
*
|
|
1756
|
+
* Backward-compat: an unknown model returns `reject` with a "model not
|
|
1757
|
+
* registered" reason; callers never throw. Unknown archetype is impossible
|
|
1758
|
+
* at the type level (`IntentArchetypeName` is a closed union).
|
|
1759
|
+
*/
|
|
1760
|
+
type ModelCompatibility = {
|
|
1761
|
+
status: 'compatible';
|
|
1762
|
+
reason: string;
|
|
1763
|
+
archetypePerf: number;
|
|
1764
|
+
} | {
|
|
1765
|
+
status: 'requires-adapter';
|
|
1766
|
+
reason: string;
|
|
1767
|
+
archetypePerf: number;
|
|
1768
|
+
archetypePerfWithAdapter: number;
|
|
1769
|
+
adapter: Adapter;
|
|
1770
|
+
} | {
|
|
1771
|
+
status: 'reject';
|
|
1772
|
+
reason: string;
|
|
1773
|
+
archetypePerf: number;
|
|
1774
|
+
};
|
|
1775
|
+
/**
|
|
1776
|
+
* Compatibility query — *does this model fit this intent, and if not,
|
|
1777
|
+
* what would?*
|
|
1778
|
+
*
|
|
1779
|
+
* **Rules (Option A from consultation doc Q1):**
|
|
1780
|
+
* 1. If model is unregistered → `reject` with "model not registered" reason.
|
|
1781
|
+
* 2. If intent provides `toolOrchestration: 'sequential'` AND that adapter
|
|
1782
|
+
* silences the cliff (because the cliff IS the sequential-tool one)
|
|
1783
|
+
* → return `compatible` with raw score (NOT the post-adapter estimate
|
|
1784
|
+
* — caller already paid the adapter, score reflects reality).
|
|
1785
|
+
* 3. If raw `archetypePerf[archetype] >= ARCHETYPE_FLOOR_DEFAULT`
|
|
1786
|
+
* → `compatible`.
|
|
1787
|
+
* 4. If below floor BUT a documented adapter exists that lifts to floor
|
|
1788
|
+
* → `requires-adapter` with adapter + estimated post-adapter score.
|
|
1789
|
+
* 5. If below floor AND no adapter exists → `reject`.
|
|
1790
|
+
*
|
|
1791
|
+
* **Pure function.** Deterministic for `(modelId, intent)`. No I/O.
|
|
1792
|
+
*
|
|
1793
|
+
* @example
|
|
1794
|
+
* ```ts
|
|
1795
|
+
* import { getModelCompatibility } from '@warmdrift/kgauto-compiler';
|
|
1796
|
+
*
|
|
1797
|
+
* const c = getModelCompatibility('deepseek-v4-pro', { archetype: 'hunt' });
|
|
1798
|
+
* // → { status: 'requires-adapter',
|
|
1799
|
+
* // reason: 'Best with sequential tool calls for hunt — slower but works.',
|
|
1800
|
+
* // archetypePerf: 4,
|
|
1801
|
+
* // archetypePerfWithAdapter: 7,
|
|
1802
|
+
* // adapter: {
|
|
1803
|
+
* // parameter: 'toolOrchestration',
|
|
1804
|
+
* // value: 'sequential',
|
|
1805
|
+
* // consequence: 'Tool calls run one at a time...'
|
|
1806
|
+
* // } }
|
|
1807
|
+
*
|
|
1808
|
+
* // With the adapter already declared:
|
|
1809
|
+
* const c2 = getModelCompatibility('deepseek-v4-pro', {
|
|
1810
|
+
* archetype: 'hunt',
|
|
1811
|
+
* toolOrchestration: 'sequential',
|
|
1812
|
+
* });
|
|
1813
|
+
* // → { status: 'compatible',
|
|
1814
|
+
* // reason: 'Suited for hunt with sequential tool calls.',
|
|
1815
|
+
* // archetypePerf: 4 }
|
|
1816
|
+
* ```
|
|
1817
|
+
*/
|
|
1818
|
+
declare function getModelCompatibility(modelId: string, intent: CompatibilityIntent): ModelCompatibility;
|
|
1819
|
+
|
|
1820
|
+
/**
|
|
1821
|
+
* alpha.22 — sync introspection: is brain-query mode active for a given
|
|
1822
|
+
* table? Used by the advisor (`model-stale-evidence` rule) to decide
|
|
1823
|
+
* whether a `judgment`-grounded chosen model is a measurement gap worth
|
|
1824
|
+
* surfacing. Returns false on cold start, when configureBrain() was never
|
|
1825
|
+
* called, or when the consumer explicitly opted the table out via
|
|
1826
|
+
* `BrainConfig.brainQuery.<table> = false`.
|
|
1827
|
+
*/
|
|
1828
|
+
declare function isBrainQueryActiveFor(table: string): boolean;
|
|
1829
|
+
interface GetPerAxisMetricsOpts {
|
|
1830
|
+
/** App id to filter on. Required. */
|
|
1831
|
+
appId: string;
|
|
1832
|
+
/** Intent archetype to filter on. Required. */
|
|
1833
|
+
archetype: string;
|
|
1834
|
+
/** Canonical model id to filter on. Required. */
|
|
1835
|
+
model: string;
|
|
1836
|
+
/**
|
|
1837
|
+
* Window in days. Default 30. Only rows with
|
|
1838
|
+
* `created_at > now() - windowDays` are counted.
|
|
1839
|
+
*/
|
|
1840
|
+
windowDays?: number;
|
|
1841
|
+
/**
|
|
1842
|
+
* Consumer-declared quality floor (0..1 oracle/approve-rate scale).
|
|
1843
|
+
* When set, the response's `qualityFloorMet` is true/false; when omitted,
|
|
1844
|
+
* `qualityFloorMet` is null (no floor declared, no judgment).
|
|
1845
|
+
*/
|
|
1846
|
+
qualityFloor?: number;
|
|
1847
|
+
/** Pluggable fetch (tests inject mock). Defaults to global fetch. */
|
|
1848
|
+
fetch?: typeof fetch;
|
|
1849
|
+
/**
|
|
1850
|
+
* PostgREST base endpoint (e.g. `https://kgauto-brain.vercel.app/api`).
|
|
1851
|
+
* When omitted, falls back to the active configureBrainQuery runtime's
|
|
1852
|
+
* endpoint. Returns null when neither is set.
|
|
1853
|
+
*/
|
|
1854
|
+
endpoint?: string;
|
|
1855
|
+
/** Bearer token. Forwarded as `Authorization: Bearer ${apiKey}`. */
|
|
1856
|
+
apiKey?: string;
|
|
1857
|
+
}
|
|
1858
|
+
/**
|
|
1859
|
+
* Call the `get_per_axis_metrics` RPC and return the typed result.
|
|
1860
|
+
*
|
|
1861
|
+
* Returns null when:
|
|
1862
|
+
* - no endpoint provided AND no configureBrainQuery runtime active
|
|
1863
|
+
* - RPC returns empty / null / unexpected shape
|
|
1864
|
+
* - brain unreachable / fetch throws / HTTP error
|
|
1865
|
+
*
|
|
1866
|
+
* Never throws — operator-facing query, must not blow up the caller.
|
|
1867
|
+
*/
|
|
1868
|
+
declare function getPerAxisMetrics(opts: GetPerAxisMetricsOpts): Promise<PerAxisMetrics | null>;
|
|
1869
|
+
|
|
1870
|
+
/**
|
|
1871
|
+
* env.ts — provider env-key resolution + reachability predicates.
|
|
1872
|
+
*
|
|
1873
|
+
* Centralizes the per-provider env var names that kgauto checks for
|
|
1874
|
+
* reachability. Used by:
|
|
1875
|
+
*
|
|
1876
|
+
* - execute.ts — to find an API key when one isn't passed via apiKeys
|
|
1877
|
+
* - call.ts — to auto-filter unreachable models from the fallback walk
|
|
1878
|
+
* - getDefaultFallbackChain — opt-in chain filter when consumer passes `reachability`
|
|
1879
|
+
* - operator scripts — getReachabilityDiagnostic() prints what's wired up
|
|
1880
|
+
*
|
|
1881
|
+
* Keeping the map in ONE place means execute() and the reachability check
|
|
1882
|
+
* always agree. Without this, kgauto could declare a model "reachable" because
|
|
1883
|
+
* env.ts found GOOGLE_GENERATIVE_AI_API_KEY, while execute() looks at
|
|
1884
|
+
* GOOGLE_API_KEY only and 401s — shipping the bug we're trying to fix.
|
|
1885
|
+
*
|
|
1886
|
+
* Resolution order (apiKeys takes precedence):
|
|
1887
|
+
* 1. opts.apiKeys?.[provider]
|
|
1888
|
+
* 2. process.env[name] for each name in PROVIDER_ENV_KEYS[provider] (first-present wins)
|
|
1889
|
+
*
|
|
1890
|
+
* alpha.10 (2026-05-14). Resolves the auto-filter-unreachable-models-silently
|
|
1891
|
+
* request from PB after first-deploy 401 on the alpha.9 summarize chain.
|
|
1892
|
+
*/
|
|
1893
|
+
|
|
1894
|
+
/**
|
|
1895
|
+
* Providers kgauto can resolve keys for today. Subset of `Provider` — `mistral`
|
|
1896
|
+
* and `xai` are declared in the type union but not yet executable (no profiles,
|
|
1897
|
+
* no execute() handler, no env-var convention). Narrowing here keeps the
|
|
1898
|
+
* reachability check structurally honest.
|
|
1899
|
+
*/
|
|
1900
|
+
type SupportedProvider = 'anthropic' | 'google' | 'openai' | 'deepseek' | 'zai' | 'moonshot';
|
|
1901
|
+
/**
|
|
1902
|
+
* Per-provider env var names kgauto recognizes. Order doesn't matter —
|
|
1903
|
+
* first-present wins. Multiple names per provider supported because Google
|
|
1904
|
+
* has historical drift (`GOOGLE_API_KEY` from older Google Cloud SDKs,
|
|
1905
|
+
* `GEMINI_API_KEY` in many examples, `GOOGLE_GENERATIVE_AI_API_KEY` is the
|
|
1906
|
+
* Vercel AI SDK convention used by IC + tt-intel adapters).
|
|
1907
|
+
*
|
|
1908
|
+
* Frozen so consumers/tests can't mutate (would break the cache invariant
|
|
1909
|
+
* that execute() and reachability checks agree).
|
|
1910
|
+
*/
|
|
1911
|
+
declare const PROVIDER_ENV_KEYS: Readonly<Record<SupportedProvider, readonly string[]>>;
|
|
1912
|
+
interface ReachabilityOpts {
|
|
1913
|
+
/** Explicit keys (alpha.3 ApiKeys). Checked first; takes precedence over env. */
|
|
1914
|
+
apiKeys?: ApiKeys;
|
|
1915
|
+
/**
|
|
1916
|
+
* Override env source. Defaults to `process.env` in Node-shaped runtimes,
|
|
1917
|
+
* `{}` everywhere else. Pass `{}` explicitly in tests for hermetic runs.
|
|
1918
|
+
*/
|
|
1919
|
+
envSource?: Record<string, string | undefined>;
|
|
1920
|
+
}
|
|
1921
|
+
/**
|
|
1922
|
+
* Resolve a usable API key for the provider. Returns the key string, or
|
|
1923
|
+
* undefined if neither apiKeys nor any of the env names are set.
|
|
1924
|
+
*
|
|
1925
|
+
* Used internally by execute.ts so the reachability check and the actual
|
|
1926
|
+
* call check stay in sync.
|
|
1927
|
+
*/
|
|
1928
|
+
declare function resolveProviderKey(provider: Provider, opts?: ReachabilityOpts): string | undefined;
|
|
1929
|
+
/**
|
|
1930
|
+
* True iff the provider has a usable key — either via explicit `apiKeys`
|
|
1931
|
+
* or one of the `PROVIDER_ENV_KEYS[provider]` names is set in envSource.
|
|
1932
|
+
*/
|
|
1933
|
+
declare function isProviderReachable(provider: Provider, opts?: ReachabilityOpts): boolean;
|
|
1934
|
+
/**
|
|
1935
|
+
* True iff the model's profile exists AND its provider is reachable.
|
|
1936
|
+
* Unknown model id returns false (treat as unreachable; the chain walker
|
|
1937
|
+
* will surface "no reachable models" if everything filters out).
|
|
1938
|
+
*/
|
|
1939
|
+
declare function isModelReachable(modelId: string, opts?: ReachabilityOpts): boolean;
|
|
1940
|
+
interface ProviderReachability {
|
|
1941
|
+
reachable: boolean;
|
|
1942
|
+
/** How the key was found. `null` when unreachable. */
|
|
1943
|
+
via: 'apiKeys' | 'env' | null;
|
|
1944
|
+
/** Which env var name supplied the key (only when via === 'env'). */
|
|
1945
|
+
envKeyFound?: string;
|
|
1946
|
+
}
|
|
1947
|
+
/**
|
|
1948
|
+
* Snapshot of which providers are reachable from the current env / apiKeys.
|
|
1949
|
+
* Useful for operator scripts ("kgauto diagnose"), startup-time logging,
|
|
1950
|
+
* and the cost-watcher's "which consumer is missing what" report.
|
|
1951
|
+
*
|
|
1952
|
+
* Does NOT log the key value itself — only the env var name that supplied it.
|
|
1953
|
+
*/
|
|
1954
|
+
declare function getReachabilityDiagnostic(opts?: ReachabilityOpts): Record<SupportedProvider, ProviderReachability>;
|
|
1955
|
+
/**
|
|
1956
|
+
* Brain-read env contract — canonical names + accepted fallbacks for the
|
|
1957
|
+
* env vars kgauto's brain-read APIs need.
|
|
1958
|
+
*
|
|
1959
|
+
* Affected APIs: `getActionableAdvisories`, `markAdvisoryResolved`,
|
|
1960
|
+
* `markExclusionFindingHandled`, `markPromoteReadyHandled`,
|
|
1961
|
+
* `getStaleExclusionFindings`, and future brain-read surfaces. Each accepts
|
|
1962
|
+
* `brainEndpoint`/`brainJwt`/`brainAnonKey` as call-site arguments; this
|
|
1963
|
+
* helper centralizes resolution from the consumer's environment.
|
|
1964
|
+
*
|
|
1965
|
+
* Resolution order (first-truthy-trimmed wins):
|
|
1966
|
+
* endpoint = KGAUTO_V2_BRAIN_SUPABASE_URL ?? KGAUTO_V2_BRAIN_URL
|
|
1967
|
+
* jwt = KGAUTO_V2_BRAIN_JWT ?? GLASSBOX_BRAIN_JWT
|
|
1968
|
+
* anonKey = KGAUTO_V2_BRAIN_ANON_KEY (no fallback)
|
|
1969
|
+
*
|
|
1970
|
+
* Why fallbacks exist:
|
|
1971
|
+
*
|
|
1972
|
+
* 1. Pre-alpha.42, some consumers set `KGAUTO_V2_BRAIN_URL` pointing at
|
|
1973
|
+
* the kgauto-dashboard URL (write target). The canonical
|
|
1974
|
+
* `KGAUTO_V2_BRAIN_SUPABASE_URL` is the Supabase project URL (read
|
|
1975
|
+
* target — PostgREST against `/rest/v1/`). Until consumers split the
|
|
1976
|
+
* two names, the fallback grabs whichever URL is set. When BOTH are
|
|
1977
|
+
* set, canonical wins (the consumer has explicitly split).
|
|
1978
|
+
*
|
|
1979
|
+
* 2. The s33 Glass-Box ship provisioned `GLASSBOX_BRAIN_JWT` across all
|
|
1980
|
+
* consumers with the same `app_id` claim shape, signed by the same
|
|
1981
|
+
* JWT_SECRET. Reusing it for brain-read avoids re-minting + re-pasting
|
|
1982
|
+
* a second JWT per consumer per surface.
|
|
1983
|
+
*
|
|
1984
|
+
* `missingEnv` lists the CANONICAL names that aren't satisfied by either
|
|
1985
|
+
* canonical OR fallback. Consumer policy: if `missingEnv.length > 0`,
|
|
1986
|
+
* render `not_configured`; otherwise pass `endpoint`/`jwt`/`anonKey` to
|
|
1987
|
+
* `getActionableAdvisories({ ... })` et al.
|
|
1988
|
+
*
|
|
1989
|
+
* Pre-trim semantics carry from `readKeyValue` — paste-newline-trap
|
|
1990
|
+
* (L-060 / L-083 / L-108) closure extends to brain env vars.
|
|
1991
|
+
*
|
|
1992
|
+
* Filed by tt-intel-Cairn (s89, 2026-05-27) after the s89 actionable-
|
|
1993
|
+
* advisories ref template hit `malformed brain response` on prod because
|
|
1994
|
+
* the endpoint env var pointed at the kgauto-dashboard URL instead of the
|
|
1995
|
+
* Supabase URL, AND because IC's ref template used a third env name
|
|
1996
|
+
* (`KGAUTO_V2_BRAIN_ENDPOINT`) that was unset. Three distinct name shapes
|
|
1997
|
+
* across two consumers — the durable closure is one canonical contract.
|
|
1998
|
+
*/
|
|
1999
|
+
interface BrainReadEnv {
|
|
2000
|
+
/** Supabase project URL (PostgREST base). Undefined when neither canonical nor fallback is set. */
|
|
2001
|
+
endpoint?: string;
|
|
2002
|
+
/** JWT carrying `app_id` claim, signed by brain JWT_SECRET. Undefined when neither canonical nor fallback is set. */
|
|
2003
|
+
jwt?: string;
|
|
2004
|
+
/** Supabase anon (publishable) key. Undefined when not set. */
|
|
2005
|
+
anonKey?: string;
|
|
2006
|
+
/**
|
|
2007
|
+
* Canonical names not satisfied by either canonical OR fallback. Subset
|
|
2008
|
+
* (in order) of:
|
|
2009
|
+
* ['KGAUTO_V2_BRAIN_SUPABASE_URL', 'KGAUTO_V2_BRAIN_JWT', 'KGAUTO_V2_BRAIN_ANON_KEY']
|
|
2010
|
+
* Consumer policy: render `not_configured` when length > 0.
|
|
2011
|
+
*/
|
|
2012
|
+
missingEnv: string[];
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* Resolve brain-read env vars. Defaults to `process.env`; pass `envSource`
|
|
2016
|
+
* for hermetic tests. Trims surrounding whitespace and treats
|
|
2017
|
+
* empty-after-trim as unset (same shape as `resolveProviderKey`).
|
|
2018
|
+
*/
|
|
2019
|
+
declare function readBrainReadEnv(envSource?: Record<string, string | undefined>): BrainReadEnv;
|
|
2020
|
+
|
|
2021
|
+
/**
|
|
2022
|
+
* getDefaultFallbackChain — the alpha.9 cascading ship.
|
|
2023
|
+
*
|
|
2024
|
+
* Returns a per-archetype fallback chain that walks the cost/performance
|
|
2025
|
+
* Pareto frontier (master plan §1.3 + §3). Three customer postures:
|
|
2026
|
+
*
|
|
2027
|
+
* locked — caller passes [theOneModel]; never call this function
|
|
2028
|
+
* preferred — caller passes `primary`; chain returned is [primary, ...fallbacks]
|
|
2029
|
+
* open — caller passes no `primary`; chain returned is [best, ...fallbacks]
|
|
2030
|
+
*
|
|
2031
|
+
* The chain at each step:
|
|
2032
|
+
* 1. Costs strictly less than the previous (no expensive sideways moves)
|
|
2033
|
+
* 2. Comes from a different provider than the previous step where possible
|
|
2034
|
+
* (correlated outages don't kill consecutive attempts)
|
|
2035
|
+
* 3. Stays above the archetype's perf floor (skip models scored <baseline
|
|
2036
|
+
* for archetypes where degradation would be unacceptable)
|
|
2037
|
+
*
|
|
2038
|
+
* In alpha.9 the chain is **hand-curated** per archetype (§3.3 starter
|
|
2039
|
+
* table). Brain-query mode lands in alpha.10. Policy.blockedModels filters
|
|
2040
|
+
* the result; policy.maxCostPerCallUsd is NOT applied here because the
|
|
2041
|
+
* function doesn't see the IR's token counts — that filtering happens at
|
|
2042
|
+
* `passScoreTargets()` time inside compile().
|
|
2043
|
+
*
|
|
2044
|
+
* The function is **pure** — no brain query, no I/O, no randomness. Same
|
|
2045
|
+
* inputs always produce the same chain.
|
|
2046
|
+
*/
|
|
2047
|
+
|
|
2048
|
+
/**
|
|
2049
|
+
* Posture passed into `getDefaultFallbackChain`. The chain function only
|
|
2050
|
+
* sees `'open'` and `'preferred'` — callers in `'locked'` posture should
|
|
2051
|
+
* pass `models: [theOneModel]` directly and skip this function entirely.
|
|
2052
|
+
*
|
|
2053
|
+
* Equivalent to `CompilePolicy.posture` minus `'locked'`. Kept distinct so
|
|
2054
|
+
* the type system enforces "don't ask for a chain when you don't want one."
|
|
2055
|
+
*/
|
|
2056
|
+
type FallbackPosture = 'open' | 'preferred';
|
|
2057
|
+
interface GetDefaultFallbackChainOpts {
|
|
2058
|
+
/** The archetype the call is performing. Drives chain shape. */
|
|
2059
|
+
archetype: IntentArchetypeName;
|
|
2060
|
+
/**
|
|
2061
|
+
* The user-selected or caller-anchored primary model. When provided, it
|
|
2062
|
+
* appears at position 0 of the returned chain and fallbacks follow.
|
|
2063
|
+
* When omitted, the function picks the best-perf model for the archetype
|
|
2064
|
+
* as position 0 (open posture).
|
|
2065
|
+
*/
|
|
2066
|
+
primary?: string;
|
|
2067
|
+
/**
|
|
2068
|
+
* Informational. `'preferred'` and `'open'` produce the same chain shape
|
|
2069
|
+
* given the same `primary`/no-primary input — posture is a tag the brain
|
|
2070
|
+
* uses to distinguish "user-anchored" from "library-anchored" telemetry.
|
|
2071
|
+
*/
|
|
2072
|
+
posture?: FallbackPosture;
|
|
2073
|
+
/**
|
|
2074
|
+
* Cap on chain length. Default 3. Min 1. Useful when the consumer wants
|
|
2075
|
+
* to keep the worst-case latency low (each fallback adds a round-trip).
|
|
2076
|
+
*/
|
|
2077
|
+
maxDepth?: number;
|
|
2078
|
+
/**
|
|
2079
|
+
* Consumer-side gating. `blockedModels` are filtered from the chain.
|
|
2080
|
+
* `preferredModels` is informational (no boost applied at this layer —
|
|
2081
|
+
* compile()'s `passScoreTargets` handles preference ranking).
|
|
2082
|
+
* `maxCostPerCallUsd` is NOT applied here — needs IR-level token
|
|
2083
|
+
* estimation. Use compile()'s policy plumbing instead.
|
|
2084
|
+
*/
|
|
2085
|
+
policy?: CompilePolicy;
|
|
2086
|
+
/**
|
|
2087
|
+
* alpha.10. When provided, the chain is filtered to models whose provider
|
|
2088
|
+
* has a reachable API key (via `apiKeys` or one of `PROVIDER_ENV_KEYS[provider]`).
|
|
2089
|
+
* Models whose provider can't be reached are silently dropped. If filtering
|
|
2090
|
+
* leaves the chain empty, returns `[]` — caller decides what to do (call()
|
|
2091
|
+
* throws CallError; this function stays pure).
|
|
2092
|
+
*
|
|
2093
|
+
* Pass `{}` to opt in with `process.env` as the env source. Pass `{ apiKeys, envSource }`
|
|
2094
|
+
* for explicit control (tests, non-Node runtimes). Omit entirely for the
|
|
2095
|
+
* legacy unfiltered behavior — preserves alpha.9 callers byte-for-byte.
|
|
2096
|
+
*/
|
|
2097
|
+
reachability?: ReachabilityOpts;
|
|
2098
|
+
/**
|
|
2099
|
+
* alpha.20 E3: consumer-declared tool-orchestration shape. Currently
|
|
2100
|
+
* only affects `archetype: 'hunt'`, where 'sequential' swaps the
|
|
2101
|
+
* parallel-tool-tier-0 chain (Flash → Pro → Sonnet → Haiku) for a
|
|
2102
|
+
* DeepSeek-tier-0 chain (V4-Pro → Flash → Sonnet) — DeepSeek's L-040
|
|
2103
|
+
* parallel-tool cliff doesn't apply when the consumer commits to
|
|
2104
|
+
* single-step orchestration.
|
|
2105
|
+
*
|
|
2106
|
+
* Other archetypes are NOT mode-aware in this release — they ship the
|
|
2107
|
+
* same chain regardless of toolOrchestration. Future versions may
|
|
2108
|
+
* extend mode-awareness to ask/generate/etc. when brain evidence
|
|
2109
|
+
* supports it.
|
|
2110
|
+
*
|
|
2111
|
+
* Default (omitted or 'either'): parallel chain. Back-compat with all
|
|
2112
|
+
* pre-alpha.20 callers.
|
|
2113
|
+
*/
|
|
2114
|
+
toolOrchestration?: 'parallel' | 'sequential' | 'either';
|
|
2115
|
+
}
|
|
2116
|
+
/**
|
|
2117
|
+
* Returns the fallback chain for an archetype as a plain `string[]` of
|
|
2118
|
+
* model ids.
|
|
2119
|
+
*
|
|
2120
|
+
* @deprecated since alpha.21 — prefer
|
|
2121
|
+
* {@link getDefaultFallbackChainWithGrounding}, which returns the same chain
|
|
2122
|
+
* shape with a `grounding` label on every entry (measured / capability-fact /
|
|
2123
|
+
* judgment). The string[] return is preserved indefinitely for back-compat —
|
|
2124
|
+
* no functional change in alpha.21. Existing callers don't need to migrate
|
|
2125
|
+
* unless they want to surface the grounding gap to users.
|
|
2126
|
+
*/
|
|
2127
|
+
declare function getDefaultFallbackChain(opts: GetDefaultFallbackChainOpts): string[];
|
|
2128
|
+
/**
|
|
2129
|
+
* Returns a shallow copy of the hand-curated starter chain for an archetype.
|
|
2130
|
+
* Useful for tests + the `scripts/digest.mjs` operator readout.
|
|
2131
|
+
*/
|
|
2132
|
+
declare function getStarterChain(archetype: IntentArchetypeName): string[];
|
|
2133
|
+
/**
|
|
2134
|
+
* Returns a shallow copy of all starter chains keyed by archetype.
|
|
2135
|
+
* Useful for the `digest.mjs` readout and consumer audits.
|
|
2136
|
+
*/
|
|
2137
|
+
declare function getAllStarterChains(): Record<IntentArchetypeName, string[]>;
|
|
2138
|
+
/**
|
|
2139
|
+
* alpha.20 E3 introspection — returns the sequential-mode overlay for an
|
|
2140
|
+
* archetype, or `undefined` when no overlay is registered (the archetype
|
|
2141
|
+
* is mode-agnostic and reuses `STARTER_CHAINS[archetype]`).
|
|
2142
|
+
*
|
|
2143
|
+
* Useful for tests + the `scripts/digest.mjs` operator readout to surface
|
|
2144
|
+
* the mode-aware chains.
|
|
2145
|
+
*/
|
|
2146
|
+
declare function getSequentialStarterChain(archetype: IntentArchetypeName): string[] | undefined;
|
|
2147
|
+
/**
|
|
2148
|
+
* alpha.21 (s78 Entry 1) — returns the fallback chain as `ChainEntry[]`,
|
|
2149
|
+
* with a `grounding` label on every position.
|
|
2150
|
+
*
|
|
2151
|
+
* Same selection logic as {@link getDefaultFallbackChain} (primary anchoring,
|
|
2152
|
+
* blockedModels filter, dedupe, reachability filter, maxDepth cap) — the
|
|
2153
|
+
* only difference is the return shape: each position is a `ChainEntry`
|
|
2154
|
+
* carrying `{ id, grounding, reason?, n? }` instead of a bare string.
|
|
2155
|
+
*
|
|
2156
|
+
* Use this when surfacing the chain to consumers who care WHY each entry
|
|
2157
|
+
* sits where it sits — Glass-Box panels, operator dashboards, eval
|
|
2158
|
+
* scaffolding deciding which entries deserve measurement priority.
|
|
2159
|
+
*
|
|
2160
|
+
* Returns `[]` when filtering empties the chain (same semantics as the
|
|
2161
|
+
* string variant) — consumer decides what to do.
|
|
2162
|
+
*/
|
|
2163
|
+
declare function getDefaultFallbackChainWithGrounding(opts: GetDefaultFallbackChainOpts): ChainEntry[];
|
|
2164
|
+
/**
|
|
2165
|
+
* alpha.21 introspection — returns the grounded starter chain for an
|
|
2166
|
+
* archetype (no primary anchoring, no policy filtering, no maxDepth cap).
|
|
2167
|
+
* Use this when you want the raw, hand-curated grounded chain — every
|
|
2168
|
+
* entry carries a `grounding` label and optional reason/n.
|
|
2169
|
+
*/
|
|
2170
|
+
declare function getStarterChainWithGrounding(archetype: IntentArchetypeName): ChainEntry[];
|
|
2171
|
+
/**
|
|
2172
|
+
* alpha.21 introspection — all grounded starter chains keyed by archetype.
|
|
2173
|
+
* Useful for the `digest.mjs` readout and consumer audits that want to
|
|
2174
|
+
* surface the grounding gap across the entire chain table.
|
|
2175
|
+
*/
|
|
2176
|
+
declare function getAllStarterChainsWithGrounding(): Record<IntentArchetypeName, ChainEntry[]>;
|
|
2177
|
+
/**
|
|
2178
|
+
* alpha.21 introspection — sequential-mode overlay with grounding labels,
|
|
2179
|
+
* or `undefined` when no overlay is registered for the archetype.
|
|
2180
|
+
*/
|
|
2181
|
+
declare function getSequentialStarterChainWithGrounding(archetype: IntentArchetypeName): ChainEntry[] | undefined;
|
|
2182
|
+
|
|
2183
|
+
/**
|
|
2184
|
+
* chains-brain — alpha.11 KG-11 adapter.
|
|
2185
|
+
*
|
|
2186
|
+
* Brain-driven STARTER_CHAINS for `getDefaultFallbackChain`. Reads
|
|
2187
|
+
* `kgauto_chains` table via the shared brain-query SWR cache (D6 + D8);
|
|
2188
|
+
* falls back to bundled STARTER_CHAINS on cold-start, brain-down, or
|
|
2189
|
+
* empty/missing table (D2 + D4).
|
|
2190
|
+
*
|
|
2191
|
+
* Behavioral note (locked via D2): the sync API surface returns bundled on
|
|
2192
|
+
* cold-start, with a background refresh fired. Subsequent calls within the
|
|
2193
|
+
* 5-min TTL return brain data. Vercel cold-start consumers see the seed
|
|
2194
|
+
* snapshot (functionally identical to pre-alpha.11); warm-start consumers
|
|
2195
|
+
* see live brain mutations within 5 min.
|
|
2196
|
+
*/
|
|
2197
|
+
/**
|
|
2198
|
+
* Sync reader for the brain-driven chains map. Returns bundled
|
|
2199
|
+
* STARTER_CHAINS when brain-query is disabled, cold, or unreachable.
|
|
2200
|
+
*/
|
|
2201
|
+
declare const loadChainsFromBrain: () => Record<"ask" | "hunt" | "classify" | "summarize" | "generate" | "extract" | "plan" | "critique" | "transform" | "judge", string[]>;
|
|
2202
|
+
|
|
2203
|
+
/**
|
|
2204
|
+
* archetype-perf-brain — alpha.11 KG-12 adapter.
|
|
2205
|
+
*
|
|
2206
|
+
* Brain-driven archetypePerf scores. Substrate for the future closed-loop
|
|
2207
|
+
* tuning engine (KG-12.5): brain telemetry → human or automated bumps →
|
|
2208
|
+
* brain UPDATE → consumers see new scores within 5-min cache TTL with
|
|
2209
|
+
* zero refresh.
|
|
2210
|
+
*
|
|
2211
|
+
* Today: data migrates to brain. No runtime call site reads archetypePerf
|
|
2212
|
+
* (it's metadata for the master plan §2.5 anti-hallucination guardrail +
|
|
2213
|
+
* future auto-tuning). The adapter exists so future readers — auto-tuning
|
|
2214
|
+
* + operator scripts + KG-12.5 — have a shipped substrate to consume.
|
|
2215
|
+
*/
|
|
2216
|
+
|
|
2217
|
+
type ArchetypePerfMap = Map<string, Partial<Record<IntentArchetypeName, number>>>;
|
|
2218
|
+
/**
|
|
2219
|
+
* alpha.21: per-(model, archetype) row count map. Same shape as
|
|
2220
|
+
* ArchetypePerfMap but stores brain row counts when the brain backs a
|
|
2221
|
+
* placement. Undefined entries → no row count seen → score is the
|
|
2222
|
+
* hand-curated cold-start prior (grounding='judgment').
|
|
2223
|
+
*/
|
|
2224
|
+
type ArchetypePerfNMap = Map<string, Partial<Record<IntentArchetypeName, number>>>;
|
|
2225
|
+
/**
|
|
2226
|
+
* Sync reader for the brain-driven archetypePerf map. Returns bundled
|
|
2227
|
+
* profile.archetypePerf data when brain-query is disabled, cold, or
|
|
2228
|
+
* unreachable. Identical shape pre/post-alpha.11 by design (D2).
|
|
2229
|
+
*/
|
|
2230
|
+
declare const loadArchetypePerfFromBrain: () => ArchetypePerfMap;
|
|
2231
|
+
/**
|
|
2232
|
+
* alpha.21 — sync reader for the brain row-count map paired with
|
|
2233
|
+
* archetype-perf. Returns empty map (no measured backing) on cold start /
|
|
2234
|
+
* brain-down / unreachable — all `getArchetypePerfScore` calls then
|
|
2235
|
+
* resolve to `grounding: 'judgment'`. When the brain table includes an
|
|
2236
|
+
* `n` column on each row, this map mirrors those counts so consumers can
|
|
2237
|
+
* see how many measurements back each score.
|
|
2238
|
+
*/
|
|
2239
|
+
declare const loadArchetypePerfNFromBrain: () => ArchetypePerfNMap;
|
|
2240
|
+
/**
|
|
2241
|
+
* Threshold above which a brain row count counts as 'measured' grounding.
|
|
2242
|
+
* Below this, the score is treated as 'judgment' (cold-start prior or
|
|
2243
|
+
* not-yet-enough-evidence). Mirrors the alpha.20 `getCleanPerfScore`
|
|
2244
|
+
* `minRows` default — same rule for consistency.
|
|
2245
|
+
*/
|
|
2246
|
+
declare const MEASURED_GROUNDING_MIN_N = 10;
|
|
2247
|
+
/**
|
|
2248
|
+
* alpha.21 — return shape for the extended {@link getArchetypePerfScore}.
|
|
2249
|
+
* Wraps the existing 0..10 score with:
|
|
2250
|
+
*
|
|
2251
|
+
* - `n`: brain row count backing this score (0 when no measurement).
|
|
2252
|
+
* - `grounding`: derived label — 'measured' when n >= 10, else 'judgment'.
|
|
2253
|
+
*
|
|
2254
|
+
* The score itself is unchanged from pre-alpha.21 (numeric, 5 = neutral
|
|
2255
|
+
* default). 'capability-fact' is NOT a perf-score grounding — capability
|
|
2256
|
+
* decisions live on chain entries, not on perf scores.
|
|
2257
|
+
*/
|
|
2258
|
+
interface ArchetypePerfScoreResult {
|
|
2259
|
+
/** 0..10 perf score. 5 = neutral default when no entry exists. */
|
|
2260
|
+
score: number;
|
|
2261
|
+
/**
|
|
2262
|
+
* Brain row count backing this score. 0 when bundled (cold-start prior)
|
|
2263
|
+
* or when the brain row didn't carry an `n` column.
|
|
2264
|
+
*/
|
|
2265
|
+
n: number;
|
|
2266
|
+
/**
|
|
2267
|
+
* Provenance — 'measured' when `n >= 10`, else 'judgment'.
|
|
2268
|
+
* Never 'capability-fact' (that label is reserved for chain-entry
|
|
2269
|
+
* inclusion/exclusion decisions).
|
|
2270
|
+
*/
|
|
2271
|
+
grounding: Grounding;
|
|
2272
|
+
}
|
|
2273
|
+
/**
|
|
2274
|
+
* Per-model accessor with grounding (alpha.21). Returns 5 (neutral) when no
|
|
2275
|
+
* entry is found — consistent with the master plan §3.3 "missing archetypes
|
|
2276
|
+
* default to 5" convention documented in profiles.ts
|
|
2277
|
+
* ModelProfile.archetypePerf.
|
|
2278
|
+
*
|
|
2279
|
+
* Backwards-compat note: pre-alpha.21 callers expected `number` here. The
|
|
2280
|
+
* new return shape `{ score, n, grounding }` is a breaking shape change at
|
|
2281
|
+
* the type level, but `.score` carries the legacy value. Callers reading
|
|
2282
|
+
* `.score` field-by-field continue working; callers using the bare number
|
|
2283
|
+
* arithmetically need to switch to `.score`. The migration is single-line
|
|
2284
|
+
* (`const x = getArchetypePerfScore(...)` → `const x = getArchetypePerfScore(...).score`).
|
|
2285
|
+
*/
|
|
2286
|
+
declare function getArchetypePerfScore(modelId: string, archetype: IntentArchetypeName): ArchetypePerfScoreResult;
|
|
2287
|
+
|
|
2288
|
+
/**
|
|
2289
|
+
* pricing-brain — alpha.11 KG-13 adapter.
|
|
2290
|
+
*
|
|
2291
|
+
* Brain-driven pricing data with **time-bounded resolution** (`valid_from`
|
|
2292
|
+
* / `valid_until` columns). The V4-Pro 75%-off promo through 2026-05-31
|
|
2293
|
+
* gets modeled as two rows; `at` parameter resolution picks the correct
|
|
2294
|
+
* row per call timestamp. Promo flips happen automatically at the
|
|
2295
|
+
* boundary without alpha cuts.
|
|
2296
|
+
*
|
|
2297
|
+
* SWR cache holds the FULL pricing snapshot (all active rows for all
|
|
2298
|
+
* models). Per-call `at` filtering is in-memory — keeps the SWR semantics
|
|
2299
|
+
* uniform with other adapters (one cache, one snapshot, sync reads).
|
|
2300
|
+
*/
|
|
2301
|
+
interface PricingRow {
|
|
2302
|
+
modelId: string;
|
|
2303
|
+
costInputPer1m: number;
|
|
2304
|
+
costOutputPer1m: number;
|
|
2305
|
+
cacheInputPer1m?: number;
|
|
2306
|
+
cacheCreationPer1m?: number;
|
|
2307
|
+
validFrom: number;
|
|
2308
|
+
validUntil?: number;
|
|
2309
|
+
source?: string;
|
|
2310
|
+
}
|
|
2311
|
+
/**
|
|
2312
|
+
* Sync reader for the brain-driven pricing snapshot. Returns bundled
|
|
2313
|
+
* profile pricing when brain-query is disabled, cold, or unreachable.
|
|
2314
|
+
* Caller filters by `at` via {@link resolvePricingAt}.
|
|
2315
|
+
*/
|
|
2316
|
+
declare const loadPricingFromBrain: () => PricingRow[];
|
|
2317
|
+
/**
|
|
2318
|
+
* Resolve the active pricing row for a model at a given timestamp.
|
|
2319
|
+
* Picks the row with the latest `valid_from <= at` whose
|
|
2320
|
+
* `valid_until > at` (or NULL — open-ended).
|
|
2321
|
+
*
|
|
2322
|
+
* Returns `undefined` when no row matches. Callers should fall back to
|
|
2323
|
+
* profile static pricing in that case.
|
|
2324
|
+
*/
|
|
2325
|
+
declare function resolvePricingAt(modelId: string, at?: Date): PricingRow | undefined;
|
|
2326
|
+
|
|
2327
|
+
/**
|
|
2328
|
+
* models-brain — alpha.11 KG-14 adapter (the largest of the four).
|
|
2329
|
+
*
|
|
2330
|
+
* Brain-driven model registry + aliases. Two adapters share the same
|
|
2331
|
+
* SWR snapshot:
|
|
2332
|
+
*
|
|
2333
|
+
* - `loadModelsFromBrain()` — `Map<modelId, ModelProfile>` from
|
|
2334
|
+
* `kgauto_models` table (cliffs/lowering/recovery as JSONB columns).
|
|
2335
|
+
* - `loadAliasesFromBrain()` — `Record<aliasId, canonicalId>` from
|
|
2336
|
+
* `kgauto_aliases` table.
|
|
2337
|
+
*
|
|
2338
|
+
* After alpha.11, new-model onboarding becomes brain INSERT (vs PR + alpha
|
|
2339
|
+
* cut + 3 consumer refreshes). The auto-onboard pipeline
|
|
2340
|
+
* (`scripts/check-model-releases.mjs`) shifts from emitting profile.ts
|
|
2341
|
+
* edits to writing brain rows directly.
|
|
2342
|
+
*
|
|
2343
|
+
* **D5 — alias resolution stable regardless of canonical's active state.**
|
|
2344
|
+
* `canonicalId('deepseek-chat') → 'deepseek-v4-flash'` even when the
|
|
2345
|
+
* canonical row is `active=false`. Aliases are wire-format contracts;
|
|
2346
|
+
* legacy callers' resolution promise outlives the canonical's active
|
|
2347
|
+
* status. Deprecation (`active=false`) affects chain composition only.
|
|
2348
|
+
*/
|
|
2349
|
+
|
|
2350
|
+
/**
|
|
2351
|
+
* Exported brain-row shape for `kgauto_models`. Mirrors the SQL table
|
|
2352
|
+
* (`v2/brain/migrations/010_kgauto_models_and_aliases.sql`) — column names
|
|
2353
|
+
* are snake_case to match PostgREST. Used by operator scripts that write
|
|
2354
|
+
* to brain (auto-onboard, promote-model) — see `profileToRow()`.
|
|
2355
|
+
*
|
|
2356
|
+
* Read path stays internal via `RawModelRow` to keep `rowToProfile()`'s
|
|
2357
|
+
* tolerance contract from leaking into write callers.
|
|
2358
|
+
*/
|
|
2359
|
+
interface ModelBrainRow {
|
|
2360
|
+
model_id: string;
|
|
2361
|
+
provider: string;
|
|
2362
|
+
status?: string;
|
|
2363
|
+
max_context_tokens?: number;
|
|
2364
|
+
max_output_tokens?: number;
|
|
2365
|
+
max_tools?: number;
|
|
2366
|
+
parallel_tool_calls?: boolean;
|
|
2367
|
+
structured_output?: string;
|
|
2368
|
+
system_prompt_mode?: string;
|
|
2369
|
+
streaming?: boolean;
|
|
2370
|
+
cliffs?: unknown;
|
|
2371
|
+
lowering?: unknown;
|
|
2372
|
+
recovery?: unknown;
|
|
2373
|
+
strengths?: string[] | null;
|
|
2374
|
+
weaknesses?: string[] | null;
|
|
2375
|
+
cost_input_per_1m?: number;
|
|
2376
|
+
cost_output_per_1m?: number;
|
|
2377
|
+
notes?: string | null;
|
|
2378
|
+
verified_against_docs?: string | null;
|
|
2379
|
+
archetype_perf?: Record<string, number> | null;
|
|
2380
|
+
version_added?: string;
|
|
2381
|
+
version_removed?: string | null;
|
|
2382
|
+
active?: boolean;
|
|
2383
|
+
/** alpha.41 — model-family tag (migration 024 column). */
|
|
2384
|
+
family?: string | null;
|
|
2385
|
+
/** alpha.49 — explicit latency bucket (migration 028 column). */
|
|
2386
|
+
latency_tier?: string | null;
|
|
2387
|
+
/** alpha.49 — per-archetype prompt-shape conventions (migration 028 column). */
|
|
2388
|
+
archetype_conventions?: ArchetypeConvention[] | null;
|
|
2389
|
+
}
|
|
2390
|
+
interface ProfileToRowOptions {
|
|
2391
|
+
/** e.g. `'2.0.0-alpha.12'` — leave undefined to omit from row. */
|
|
2392
|
+
versionAdded?: string;
|
|
2393
|
+
/** Pass `null` to clear; omit to leave field unset. */
|
|
2394
|
+
versionRemoved?: string | null;
|
|
2395
|
+
/** Defaults to true if omitted. */
|
|
2396
|
+
active?: boolean;
|
|
2397
|
+
/**
|
|
2398
|
+
* Override verifiedAgainstDocs (e.g. set to `null` for auto-onboard).
|
|
2399
|
+
* When omitted, the profile's own value is used. Pass `null` explicitly
|
|
2400
|
+
* to write a SQL NULL (e.g. unverified auto-onboard rows).
|
|
2401
|
+
*/
|
|
2402
|
+
verifiedAgainstDocs?: string | null;
|
|
2403
|
+
}
|
|
2404
|
+
/**
|
|
2405
|
+
* Inverse of `rowToProfile` — serialize a `ModelProfile` to a `kgauto_models`
|
|
2406
|
+
* row payload for INSERT/UPSERT. Used by operator scripts that write to
|
|
2407
|
+
* brain (auto-onboard pipeline, promote-model verification CLI).
|
|
2408
|
+
*
|
|
2409
|
+
* Row-level fields (`version_added`, `version_removed`, `active`) are
|
|
2410
|
+
* operator-controlled and pass through `opts`. `verifiedAgainstDocs` can
|
|
2411
|
+
* also be overridden via `opts` — auto-onboard explicitly passes `null` to
|
|
2412
|
+
* mark unverified rows (the column is DATE, doesn't accept the
|
|
2413
|
+
* `'UNVERIFIED-AUTO-ONBOARD'` sentinel used in PROFILES_RAW).
|
|
2414
|
+
*/
|
|
2415
|
+
declare function profileToRow(profile: ModelProfile, opts?: ProfileToRowOptions): ModelBrainRow;
|
|
2416
|
+
/**
|
|
2417
|
+
* Sync reader for the brain-driven model registry. Returns bundled
|
|
2418
|
+
* PROFILES_RAW when brain-query is disabled, cold, or unreachable.
|
|
2419
|
+
*/
|
|
2420
|
+
declare const loadModelsFromBrain: () => Map<string, ModelProfile>;
|
|
2421
|
+
/**
|
|
2422
|
+
* Sync reader for the brain-driven aliases map. Returns bundled ALIASES
|
|
2423
|
+
* when brain-query is disabled, cold, or unreachable.
|
|
2424
|
+
*
|
|
2425
|
+
* D5: this map carries both active and inactive canonical mappings —
|
|
2426
|
+
* alias resolution is stable regardless of canonical's `active` state.
|
|
2427
|
+
*/
|
|
2428
|
+
declare const loadAliasesFromBrain: () => Record<string, string>;
|
|
2429
|
+
|
|
2430
|
+
/**
|
|
2431
|
+
* exclusion-findings-brain — alpha.38 KG-19 adapter.
|
|
2432
|
+
*
|
|
2433
|
+
* Per-tenant SWR cache for the `exclusion_findings` table populated by the
|
|
2434
|
+
* `kgauto-exclusion-re-evaluation-watch` cron (alpha.37 substrate). Distinct
|
|
2435
|
+
* from the cross-tenant `brain-query.ts` snapshot because exclusion findings
|
|
2436
|
+
* are scoped per `app_id` — one process = one consumer = one appId, but the
|
|
2437
|
+
* cache key supports multi-app processes by keying snapshots by appId.
|
|
2438
|
+
*
|
|
2439
|
+
* Architecture mirrors `brain-query.ts` but with a per-(appId) snapshot:
|
|
2440
|
+
*
|
|
2441
|
+
* - **Sync API surface.** `getStaleExclusionFindings({ appId, archetype })`
|
|
2442
|
+
* returns `ExclusionFindingRow[]` immediately. First call returns the
|
|
2443
|
+
* bundled fallback (empty array); async refresh fires in background;
|
|
2444
|
+
* subsequent calls within TTL return brain data.
|
|
2445
|
+
*
|
|
2446
|
+
* - **Per-appId snapshot.** Each appId gets its own cache entry. One fetch
|
|
2447
|
+
* per appId per TTL window. Tests can reset between cases.
|
|
2448
|
+
*
|
|
2449
|
+
* - **Tolerant.** Brain down / endpoint misconfigured / unexpected shape →
|
|
2450
|
+
* silent bundled fallback (empty array). Never throws. Warns once per
|
|
2451
|
+
* process per error to avoid log spam.
|
|
2452
|
+
*
|
|
2453
|
+
* - **Opt-in.** Activation gated on `configureExclusionFindingsBrain()`
|
|
2454
|
+
* having been called with a runtime. The public `configureBrain()` in
|
|
2455
|
+
* brain.ts wires this up automatically when `BrainConfig.brainQuery
|
|
2456
|
+
* .findingsExclusions !== false`.
|
|
2457
|
+
*
|
|
2458
|
+
* Default endpoint:
|
|
2459
|
+
* `https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions`
|
|
2460
|
+
* The route accepts `?app_id=X` and returns a JSON array of findings
|
|
2461
|
+
* for that app filtered to `resolved_at IS NULL`. Public read; data
|
|
2462
|
+
* carries no consumer PII (app id, archetype, model id, cost ratio,
|
|
2463
|
+
* savings estimate).
|
|
2464
|
+
*/
|
|
2465
|
+
/**
|
|
2466
|
+
* Shape of one row from the `exclusion_findings` cache table. Mirrors the
|
|
2467
|
+
* snake_case JSONB returned by the brain RPC + the dashboard endpoint.
|
|
2468
|
+
* Camel-case mapping happens at the boundary (rowToFinding) so the in-memory
|
|
2469
|
+
* shape stays consistent with the rest of the library.
|
|
2470
|
+
*/
|
|
2471
|
+
interface ExclusionFindingRow {
|
|
2472
|
+
/** Intent archetype the finding applies to (e.g. 'hunt', 'classify'). */
|
|
2473
|
+
archetype: string;
|
|
2474
|
+
/** Canonical model id that the consumer has excluded (zero traffic in window). */
|
|
2475
|
+
excludedModel: string;
|
|
2476
|
+
/** Provider of the excluded model (e.g. 'deepseek', 'openai'). */
|
|
2477
|
+
excludedProvider: string;
|
|
2478
|
+
/** Detection verdict — alpha.37 ships 'recommend-probe' only. */
|
|
2479
|
+
verdict: 'recommend-probe' | 'unblock' | 'stay-excluded' | 'inconclusive';
|
|
2480
|
+
/**
|
|
2481
|
+
* Estimated 30-day savings in USD if the excluded model becomes primary
|
|
2482
|
+
* on this archetype. Null when pricing is incomplete or excluded model is
|
|
2483
|
+
* more expensive than the leader.
|
|
2484
|
+
*/
|
|
2485
|
+
estimatedSavingsUsd30d: number | null;
|
|
2486
|
+
/** Renderable summary; produced by the detector / RPC. */
|
|
2487
|
+
message: string;
|
|
2488
|
+
/** Actionable recommendation; produced by the detector / RPC. */
|
|
2489
|
+
suggestion: string;
|
|
2490
|
+
/** Detector confidence tier. */
|
|
2491
|
+
confidence: 'high' | 'medium' | 'low';
|
|
2492
|
+
/**
|
|
2493
|
+
* Free-form evidence pack (cost ratio, leader info, promo flags, parallel-
|
|
2494
|
+
* tool hint, etc.). Surfaced verbatim to advisor rules for richer messages.
|
|
2495
|
+
* Optional — older detector runs may not populate every field.
|
|
2496
|
+
*/
|
|
2497
|
+
evidence?: Record<string, unknown>;
|
|
2498
|
+
}
|
|
2499
|
+
/**
|
|
2500
|
+
* Default endpoint hosted on the kgauto-dashboard. Public read — data carries
|
|
2501
|
+
* no PII (app id, archetype, model id, cost ratio, savings estimate). Mirrors
|
|
2502
|
+
* the cross-tenant `/api/kgauto-v2/config` pattern.
|
|
2503
|
+
*/
|
|
2504
|
+
declare const DEFAULT_FINDINGS_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions";
|
|
2505
|
+
/**
|
|
2506
|
+
* Sync introspection — is the findings-brain active? Used by advisor rules
|
|
2507
|
+
* to decide whether to even attempt a read.
|
|
2508
|
+
*/
|
|
2509
|
+
declare function isExclusionFindingsBrainActive(): boolean;
|
|
2510
|
+
interface GetExclusionFindingsOpts {
|
|
2511
|
+
/** App id to read findings for. Required. */
|
|
2512
|
+
appId: string;
|
|
2513
|
+
/**
|
|
2514
|
+
* Optional archetype filter. When set, returns only findings where
|
|
2515
|
+
* `archetype` matches. When omitted, returns all findings for the app.
|
|
2516
|
+
*/
|
|
2517
|
+
archetype?: string;
|
|
2518
|
+
}
|
|
2519
|
+
/**
|
|
2520
|
+
* Sync reader. Returns the cached findings for `appId`, optionally filtered
|
|
2521
|
+
* to a single archetype. First call returns empty array and triggers async
|
|
2522
|
+
* refresh; subsequent calls within TTL return brain data.
|
|
2523
|
+
*
|
|
2524
|
+
* NEVER throws. Brain down / endpoint misconfigured / mapper exception →
|
|
2525
|
+
* empty array.
|
|
2526
|
+
*/
|
|
2527
|
+
declare function getStaleExclusionFindings(opts: GetExclusionFindingsOpts): ExclusionFindingRow[];
|
|
2528
|
+
|
|
2529
|
+
/**
|
|
2530
|
+
* Family resolution — alpha.41.
|
|
2531
|
+
*
|
|
2532
|
+
* "I want the latest Opus" → kgauto picks the current+active model in the
|
|
2533
|
+
* `claude-opus` family. Closes the loop where consumer code carries hardcoded
|
|
2534
|
+
* `claude-opus-4-6` literals long after `claude-opus-4-7` ships and goes
|
|
2535
|
+
* current — the s47 trigger (IC's `generate` chain still routing 43 calls to
|
|
2536
|
+
* legacy 4-6 in production).
|
|
2537
|
+
*
|
|
2538
|
+
* Two surfaces:
|
|
2539
|
+
* - `getRecommendedPrimary({ family, ..., fallback })` — public, sync,
|
|
2540
|
+
* used at IR-construction time when the consumer wants a literal id back
|
|
2541
|
+
* (with a fallback floor for cold-start brain).
|
|
2542
|
+
* - `resolveFamilyEntry({ family, archetype?, appId? })` — internal,
|
|
2543
|
+
* called from compile() when an IR's `models[]` entry is shaped
|
|
2544
|
+
* `{ family: string }`. Throws `FamilyResolutionError` on failure.
|
|
2545
|
+
*
|
|
2546
|
+
* Both routes share the same algorithm (locked in the alpha.41 Phase 0
|
|
2547
|
+
* design contract); they differ only in the fallback ergonomics. The
|
|
2548
|
+
* public route accepts a required `fallback: string`; the IR route throws.
|
|
2549
|
+
*
|
|
2550
|
+
* Pure resolution. No network. No async. Brain-registry reads go through
|
|
2551
|
+
* the existing SWR cache (`loadModelsFromBrain` from `models-brain.ts`) —
|
|
2552
|
+
* cold-start returns bundled profiles, which still resolve via the
|
|
2553
|
+
* `deriveFamilyFromModelId` fallback when the brain row's `family` column
|
|
2554
|
+
* is null (G1 contract: graceful pre-migration behavior).
|
|
2555
|
+
*
|
|
2556
|
+
* @see command-center/advisory/kgauto/2026-05-26_alpha-41-model-family-aliases-and-promotion-probe-watcher.md
|
|
2557
|
+
*/
|
|
2558
|
+
|
|
2559
|
+
interface GetRecommendedPrimaryOptions {
|
|
2560
|
+
/**
|
|
2561
|
+
* Family tag (e.g. `'claude-opus'`, `'gemini-flash'`). See the Phase 0
|
|
2562
|
+
* design contract's family taxonomy table for the locked initial set;
|
|
2563
|
+
* extensible via brain migrations.
|
|
2564
|
+
*/
|
|
2565
|
+
family: string;
|
|
2566
|
+
/**
|
|
2567
|
+
* Optional archetype gate. When provided, candidates must clear
|
|
2568
|
+
* {@link ARCHETYPE_FLOOR_DEFAULT} on `archetypePerf[archetype]`. Also used
|
|
2569
|
+
* as the primary sort key (DESC) when multiple candidates qualify.
|
|
2570
|
+
*/
|
|
2571
|
+
archetype?: IntentArchetypeName;
|
|
2572
|
+
/**
|
|
2573
|
+
* Optional consumer-app id. When provided, candidates matching a
|
|
2574
|
+
* `stay-excluded` finding for `(appId, archetype)` in the
|
|
2575
|
+
* exclusion-findings cache (alpha.38 substrate) are filtered out.
|
|
2576
|
+
*/
|
|
2577
|
+
appId?: string;
|
|
2578
|
+
/**
|
|
2579
|
+
* Consumer-posture tag. `'locked'` short-circuits resolution and returns
|
|
2580
|
+
* the literal `fallback` unconditionally — useful for compliance /
|
|
2581
|
+
* contract / brand-promise flows where the consumer doesn't want kgauto
|
|
2582
|
+
* picking the model on their behalf.
|
|
2583
|
+
*/
|
|
2584
|
+
posture?: 'preferred' | 'open' | 'locked';
|
|
2585
|
+
/**
|
|
2586
|
+
* Last-resort literal model id. REQUIRED. Returned when (a) brain
|
|
2587
|
+
* registry is cold / no candidates exist, (b) `posture === 'locked'`,
|
|
2588
|
+
* (c) every candidate was filtered out by archetype / exclusion gates.
|
|
2589
|
+
*
|
|
2590
|
+
* The fallback is NOT validated against the family — kgauto trusts the
|
|
2591
|
+
* consumer to pass a meaningful floor. The contract intent is "even when
|
|
2592
|
+
* everything below is on fire, you still get a model id back."
|
|
2593
|
+
*/
|
|
2594
|
+
fallback: string;
|
|
2595
|
+
}
|
|
2596
|
+
/**
|
|
2597
|
+
* Thrown by `resolveFamilyEntry` (the internal compile-time twin) when a
|
|
2598
|
+
* `{ family: string }` IR entry can't resolve to any current+active model.
|
|
2599
|
+
* Surfaces with the family string + a one-line cause so consumer error
|
|
2600
|
+
* handling can distinguish "you typo'd the family tag" from "brain is cold
|
|
2601
|
+
* and nothing matches."
|
|
2602
|
+
*
|
|
2603
|
+
* The public `getRecommendedPrimary` does NOT throw — it returns
|
|
2604
|
+
* `fallback` instead.
|
|
2605
|
+
*/
|
|
2606
|
+
declare class FamilyResolutionError extends Error {
|
|
2607
|
+
readonly family: string;
|
|
2608
|
+
readonly cause: string;
|
|
2609
|
+
constructor(family: string, cause: string);
|
|
2610
|
+
}
|
|
2611
|
+
/**
|
|
2612
|
+
* Deterministic model_id → family inference. Pure function; no brain
|
|
2613
|
+
* lookup. Used as the runtime fallback when a brain row's `family` column
|
|
2614
|
+
* is null (pre-migration 024) and as the canonical mapping that migration
|
|
2615
|
+
* 024's CASE statement mirrors.
|
|
2616
|
+
*
|
|
2617
|
+
* Returns null for unrecognized ids — caller must handle (typically by
|
|
2618
|
+
* skipping the row in family resolution).
|
|
2619
|
+
*
|
|
2620
|
+
* Order matters: more specific patterns first (e.g. `flash-lite` before
|
|
2621
|
+
* `flash`; `pro` before `chat`). The brain-side CASE statement uses the
|
|
2622
|
+
* same priority.
|
|
2623
|
+
*/
|
|
2624
|
+
declare function deriveFamilyFromModelId(modelId: string): string | null;
|
|
2625
|
+
/**
|
|
2626
|
+
* Public sync resolver. Pure (modulo brain snapshot read). Returns the
|
|
2627
|
+
* literal model id of the best candidate, or `fallback` when resolution
|
|
2628
|
+
* yields nothing.
|
|
2629
|
+
*/
|
|
2630
|
+
declare function getRecommendedPrimary(opts: GetRecommendedPrimaryOptions): string;
|
|
2631
|
+
|
|
2632
|
+
/**
|
|
2633
|
+
* promote-ready-brain — alpha.41 substrate.
|
|
2634
|
+
*
|
|
2635
|
+
* Per-tenant SWR cache for the `promote_ready_findings` table populated by
|
|
2636
|
+
* the autonomous `promotion-probe-watcher` (Mode 2). Mirrors
|
|
2637
|
+
* `exclusion-findings-brain.ts` shape byte-for-byte where applicable; this
|
|
2638
|
+
* is the read-side substrate for the compile-time `promote-ready` advisor
|
|
2639
|
+
* rule.
|
|
2640
|
+
*
|
|
2641
|
+
* Architecture (mirror of exclusion-findings-brain):
|
|
2642
|
+
*
|
|
2643
|
+
* - **Sync API surface.** `getPromoteReadyFindings({ appId, archetype,
|
|
2644
|
+
* family })` returns `PromoteReadyFindingRow[]` immediately. First call
|
|
2645
|
+
* returns the bundled fallback (empty array); async refresh fires in
|
|
2646
|
+
* background; subsequent calls within TTL return brain data.
|
|
2647
|
+
*
|
|
2648
|
+
* - **Per-appId snapshot.** Each appId gets its own cache entry. One fetch
|
|
2649
|
+
* per appId per TTL window. Tests reset between cases via
|
|
2650
|
+
* `_testResetPromoteReadyFindings()`.
|
|
2651
|
+
*
|
|
2652
|
+
* - **Tolerant.** Brain down / endpoint misconfigured / unexpected shape →
|
|
2653
|
+
* silent bundled fallback (empty array). Never throws. Warns once per
|
|
2654
|
+
* process per error to avoid log spam.
|
|
2655
|
+
*
|
|
2656
|
+
* - **Opt-in.** Activation gated on `configurePromoteReadyBrain()` having
|
|
2657
|
+
* been called with a runtime. The public `configureBrain()` in brain.ts
|
|
2658
|
+
* wires this up automatically when
|
|
2659
|
+
* `BrainConfig.brainQuery.findingsPromoteReady !== false`.
|
|
2660
|
+
*
|
|
2661
|
+
* Plus: `markPromoteReadyHandled` — direct PostgREST PATCH against the
|
|
2662
|
+
* brain (no kgauto proxy). Mirrors `markExclusionFindingHandled` shape
|
|
2663
|
+
* byte-for-byte. Idempotent on `resolved_at=is.null` filter.
|
|
2664
|
+
*
|
|
2665
|
+
* Default endpoint:
|
|
2666
|
+
* `https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/promote-ready`
|
|
2667
|
+
* The route accepts `?app_id=X` and returns a JSON array of findings
|
|
2668
|
+
* for that app filtered to `resolved_at IS NULL`.
|
|
2669
|
+
*/
|
|
2670
|
+
|
|
2671
|
+
/**
|
|
2672
|
+
* Shape of one row from the `promote_ready_findings` cache table. Mirrors
|
|
2673
|
+
* the snake_case JSONB returned by the brain endpoint, mapped to camelCase
|
|
2674
|
+
* at the boundary (rowToFinding) so the in-memory shape stays consistent
|
|
2675
|
+
* with the rest of the library.
|
|
2676
|
+
*/
|
|
2677
|
+
interface PromoteReadyFindingRow {
|
|
2678
|
+
/** Intent archetype the finding applies to. */
|
|
2679
|
+
archetype: string;
|
|
2680
|
+
/** Model family (e.g. 'claude-opus', 'gemini-flash'). */
|
|
2681
|
+
family: string;
|
|
2682
|
+
/** The candidate model that the probe validated. */
|
|
2683
|
+
candidateModel: string;
|
|
2684
|
+
/** The current production model the candidate was compared against. */
|
|
2685
|
+
currentModel: string;
|
|
2686
|
+
/** Sample size of the probe run (typically 10). */
|
|
2687
|
+
sampleN: number;
|
|
2688
|
+
/** Fraction of probes where the judge verdict was 'candidate-better' or
|
|
2689
|
+
* 'tied'. 0.000 to 1.000. */
|
|
2690
|
+
judgePassRate: number;
|
|
2691
|
+
/** Mean judge score across the probe sample. 1.00 to 5.00. */
|
|
2692
|
+
judgeAvgScore: number;
|
|
2693
|
+
/** Signed cost delta as a fraction (negative = candidate is cheaper).
|
|
2694
|
+
* Null when pricing data was incomplete at probe time. */
|
|
2695
|
+
costDeltaPct: number | null;
|
|
2696
|
+
/** ISO timestamp of detection (when the probe wrote the row). */
|
|
2697
|
+
detectedAt: string;
|
|
2698
|
+
}
|
|
2699
|
+
/**
|
|
2700
|
+
* Resolution sources supported by alpha.41 `markPromoteReadyHandled`. The
|
|
2701
|
+
* three values map to the three CHECK-constrained resolution values on
|
|
2702
|
+
* `promote_ready_findings.resolution`:
|
|
2703
|
+
*
|
|
2704
|
+
* - `'promoted'` — consumer migrated to the candidate model. Strong
|
|
2705
|
+
* positive signal; the probe was right.
|
|
2706
|
+
* - `'declined'` — consumer evaluated and chose not to promote.
|
|
2707
|
+
* Strong negative signal; revisit only on new
|
|
2708
|
+
* family entries or material score swings.
|
|
2709
|
+
* - `'still-evaluating'` — consumer acknowledges the finding but defers
|
|
2710
|
+
* the decision. Acknowledges-without-deciding;
|
|
2711
|
+
* finding silences this cycle but next probe may
|
|
2712
|
+
* re-surface.
|
|
2713
|
+
*/
|
|
2714
|
+
type PromoteReadyResolution = 'promoted' | 'declined' | 'still-evaluating';
|
|
2715
|
+
interface MarkPromoteReadyHandledOptions {
|
|
2716
|
+
/** App id the finding belongs to. Required (RLS scopes writes by this). */
|
|
2717
|
+
appId: string;
|
|
2718
|
+
/** Archetype the finding applies to (e.g. 'hunt', 'classify'). */
|
|
2719
|
+
archetype: IntentArchetypeName | string;
|
|
2720
|
+
/** Model family the finding applies to (e.g. 'claude-opus'). */
|
|
2721
|
+
family: string;
|
|
2722
|
+
/** Resolution semantics — see `PromoteReadyResolution`. */
|
|
2723
|
+
resolution: PromoteReadyResolution;
|
|
2724
|
+
/** Optional free-form note explaining the decision. */
|
|
2725
|
+
resolutionNote?: string;
|
|
2726
|
+
/** Brain Supabase URL base (e.g. `https://<project>.supabase.co`). */
|
|
2727
|
+
brainEndpoint: string;
|
|
2728
|
+
/** Consumer-scoped JWT carrying the `app_id` claim. */
|
|
2729
|
+
brainJwt: string;
|
|
2730
|
+
/** Supabase anon key for the `apikey` header. */
|
|
2731
|
+
brainAnonKey: string;
|
|
2732
|
+
/** Injected fetch for tests. Defaults to global fetch. */
|
|
2733
|
+
fetch?: typeof fetch;
|
|
2734
|
+
}
|
|
2735
|
+
/**
|
|
2736
|
+
* Mark a probe-validated promote-ready finding as handled. Returns an
|
|
2737
|
+
* `ok/reason` envelope matching `markExclusionFindingHandled`.
|
|
2738
|
+
*
|
|
2739
|
+
* Idempotent: if no row matches the (app_id, archetype, family) tuple
|
|
2740
|
+
* (already resolved, never existed, watcher not yet UPSERTed), PostgREST
|
|
2741
|
+
* returns 200/204 with zero affected rows and we return `{ ok: true }`.
|
|
2742
|
+
*
|
|
2743
|
+
* Reasons surfaced on failure:
|
|
2744
|
+
* - `app_id_required` / `archetype_required` / `family_required`
|
|
2745
|
+
* - `resolution_invalid` — not one of the three documented values
|
|
2746
|
+
* - `brain_auth_misconfig` — 401/403
|
|
2747
|
+
* - `brain_unavailable` — 5xx
|
|
2748
|
+
* - `network_error:<message>` — fetch threw
|
|
2749
|
+
* - `patch_failed:<status>` — anything else non-2xx
|
|
2750
|
+
*/
|
|
2751
|
+
declare function markPromoteReadyHandled(opts: MarkPromoteReadyHandledOptions): Promise<{
|
|
2752
|
+
ok: true;
|
|
2753
|
+
} | {
|
|
2754
|
+
ok: false;
|
|
2755
|
+
reason: string;
|
|
2756
|
+
}>;
|
|
2757
|
+
|
|
2758
|
+
/**
|
|
2759
|
+
* promotions-brain — alpha.64 Stage-2 substrate.
|
|
2760
|
+
*
|
|
2761
|
+
* Per-tenant SWR cache for the `kgauto_promotions` table populated by the
|
|
2762
|
+
* golden-eval trigger's auto-promote actor (Stage 2 of the eval trust
|
|
2763
|
+
* ladder: auto-promote downswaps behind the 7-day rollback guard). Mirrors
|
|
2764
|
+
* `promote-ready-brain.ts` shape where applicable; this is the read-side
|
|
2765
|
+
* substrate for the compile-time promotion boost in `passScoreTargets`.
|
|
2766
|
+
*
|
|
2767
|
+
* Design contract:
|
|
2768
|
+
* command-center/advisory/kgauto/2026-07-18_stage2-auto-promote-design.md
|
|
2769
|
+
*
|
|
2770
|
+
* Consent posture: the routing effect is OPT-IN, default OFF. The cache is
|
|
2771
|
+
* only activated by `configureBrain()` when the consumer opted in via
|
|
2772
|
+
* `BrainConfig.autoPromote: true` or the `KGAUTO_AUTO_PROMOTE` env var
|
|
2773
|
+
* (config field wins when both are present — mirror of the
|
|
2774
|
+
* `KGAUTO_GOLDEN_CAPTURE` env-as-consent precedent). Not opted in ⇒ this
|
|
2775
|
+
* module never fetches and `getApplicablePromotion` returns undefined ⇒
|
|
2776
|
+
* zero behavior change anywhere in compile().
|
|
2777
|
+
*
|
|
2778
|
+
* Architecture (mirror of promote-ready-brain):
|
|
2779
|
+
* - Sync API surface: `getApplicablePromotion({ appId, archetype })`
|
|
2780
|
+
* returns immediately. First call returns undefined (cold) and fires an
|
|
2781
|
+
* async refresh; subsequent calls within TTL return brain data.
|
|
2782
|
+
* - Per-appId snapshot; one fetch per appId per TTL window.
|
|
2783
|
+
* - Tolerant: brain down / misconfigured / unexpected shape → undefined.
|
|
2784
|
+
* Never throws. Warns once per process.
|
|
2785
|
+
*
|
|
2786
|
+
* A rollback (`status='rolled_back'` PATCHed by the promotion-guard
|
|
2787
|
+
* watcher) drops the row from the endpoint's `status=active` filter, so
|
|
2788
|
+
* routing reverts within one TTL window — the mechanism the 7-day guard's
|
|
2789
|
+
* auto-revert rests on.
|
|
2790
|
+
*/
|
|
2791
|
+
|
|
2792
|
+
/**
|
|
2793
|
+
* One active surface promotion, camelCase-mapped at the boundary from the
|
|
2794
|
+
* snake_case endpoint row (typed-boundary-transformer convention).
|
|
2795
|
+
*/
|
|
2796
|
+
interface PromotionRow {
|
|
2797
|
+
/** Brain row id — cited in the `promotion-applied` mutation for Glass-Box. */
|
|
2798
|
+
id: number;
|
|
2799
|
+
/** Intent archetype the promotion applies to. */
|
|
2800
|
+
archetype: string;
|
|
2801
|
+
/** The model this surface now routes to. */
|
|
2802
|
+
promotedModel: string;
|
|
2803
|
+
/** The model it replaced (the eval's incumbent). */
|
|
2804
|
+
incumbentModel: string;
|
|
2805
|
+
/** The promote-ready kgauto_golden_eval_runs row this rests on. */
|
|
2806
|
+
evalRunId: number | null;
|
|
2807
|
+
/**
|
|
2808
|
+
* Evidence-supersedes-judgment: skip the alpha.49 schema-weak
|
|
2809
|
+
* quality-gate penalty for the promoted model on this surface (the eval
|
|
2810
|
+
* measured the schema floor holding on real workload).
|
|
2811
|
+
*/
|
|
2812
|
+
suppressQualityGate: boolean;
|
|
2813
|
+
/** ISO timestamp the promotion went active. */
|
|
2814
|
+
promotedAt: string;
|
|
2815
|
+
}
|
|
2816
|
+
interface PromotionsRuntime {
|
|
2817
|
+
/** Endpoint base URL. The library appends `?app_id=<id>`. */
|
|
2818
|
+
endpoint: string;
|
|
2819
|
+
/** Stale-while-revalidate window in ms. */
|
|
2820
|
+
ttlMs: number;
|
|
2821
|
+
/** Pluggable fetch. */
|
|
2822
|
+
fetchImpl: typeof fetch;
|
|
2823
|
+
/** Optional warn hook. */
|
|
2824
|
+
onError?: (err: unknown) => void;
|
|
2825
|
+
}
|
|
2826
|
+
/**
|
|
2827
|
+
* Default endpoint hosted on the kgauto-dashboard. Serves `status='active'`
|
|
2828
|
+
* kgauto_promotions rows for one app_id. Mirrors the findings convention.
|
|
2829
|
+
*/
|
|
2830
|
+
declare const DEFAULT_PROMOTIONS_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/promotions";
|
|
2831
|
+
/**
|
|
2832
|
+
* True when the KGAUTO_AUTO_PROMOTE env var opts this process in.
|
|
2833
|
+
* Accepted truthy forms: '1', 'true' (case-insensitive). Everything else —
|
|
2834
|
+
* unset, '', '0', 'false' — is OFF. Read at configureBrain() time, not per
|
|
2835
|
+
* call.
|
|
2836
|
+
*/
|
|
2837
|
+
declare function isAutoPromoteEnabledFromEnv(envSource?: Record<string, string | undefined>): boolean;
|
|
2838
|
+
/**
|
|
2839
|
+
* Wire (or rewire) the runtime. Pass undefined to disable. Resets all
|
|
2840
|
+
* snapshots. Called from `configureBrain()` ONLY when the consumer opted in.
|
|
2841
|
+
*/
|
|
2842
|
+
declare function configurePromotionsBrain(rt: PromotionsRuntime | undefined): void;
|
|
2843
|
+
/** Sync introspection — is the promotions brain active (i.e. opted in)? */
|
|
2844
|
+
declare function isPromotionsBrainActive(): boolean;
|
|
2845
|
+
interface GetApplicablePromotionOpts {
|
|
2846
|
+
/** App id to read promotions for. Required. */
|
|
2847
|
+
appId: string;
|
|
2848
|
+
/** Archetype of the compile in flight. Required. */
|
|
2849
|
+
archetype: IntentArchetypeName | string;
|
|
2850
|
+
}
|
|
2851
|
+
/**
|
|
2852
|
+
* Sync reader. Returns the active promotion for `(appId, archetype)` or
|
|
2853
|
+
* undefined. First call returns undefined and triggers async refresh;
|
|
2854
|
+
* subsequent calls within TTL return brain data. The brain enforces one
|
|
2855
|
+
* active promotion per surface (partial unique index), so at most one row
|
|
2856
|
+
* matches.
|
|
2857
|
+
*
|
|
2858
|
+
* NEVER throws. Not configured / brain down / cold → undefined.
|
|
2859
|
+
*/
|
|
2860
|
+
declare function getApplicablePromotion(opts: GetApplicablePromotionOpts): PromotionRow | undefined;
|
|
2861
|
+
/** Reset module state. Tests must call between cases. */
|
|
2862
|
+
declare function _testResetPromotions(): void;
|
|
2863
|
+
/** Wait for any in-flight refresh to settle. */
|
|
2864
|
+
declare function _testWaitForPromotionsRefresh(): Promise<void>;
|
|
2865
|
+
|
|
2866
|
+
/**
|
|
2867
|
+
* measured-failure-brain — the CREATE-a-gate direction of
|
|
2868
|
+
* measured-supersedes-judgment (alpha.70).
|
|
2869
|
+
*
|
|
2870
|
+
* alpha.49 gives kgauto a quality gate that fires off a model profile's
|
|
2871
|
+
* DECLARED conventions (`archetypeConventions.structuredOutputHint: 'avoid'`).
|
|
2872
|
+
* alpha.64 let a MEASURED eval verdict SUPPRESS that gate
|
|
2873
|
+
* (`kgauto_promotions.suppress_quality_gate`). Nothing could go the other
|
|
2874
|
+
* way — a model whose declarations are wrong could not have a gate CREATED
|
|
2875
|
+
* for it, which is precisely the case where declarations cannot be trusted.
|
|
2876
|
+
*
|
|
2877
|
+
* The originating evidence: `claude-haiku-4-5` on playbacksam/summarize
|
|
2878
|
+
* declares `structuredOutput: 'grammar'` + `archetypePerf.summarize: 8`, so
|
|
2879
|
+
* every quality signal reads green and it wins the surface on price — while
|
|
2880
|
+
* failing **12 of 12 in-window attempts** (2026-07-14..25, seven in one
|
|
2881
|
+
* day). The brain held that evidence and nothing could act on it.
|
|
2882
|
+
*
|
|
2883
|
+
* ── Design notes ───────────────────────────────────────────────────────
|
|
2884
|
+
*
|
|
2885
|
+
* **No stored decision.** The gate is DERIVED from a rolling 28d window
|
|
2886
|
+
* (`kgauto_surface_model_failure_v`), never written down. That kills the
|
|
2887
|
+
* flap problem by construction — there is no state to flap — and it means
|
|
2888
|
+
* a gated model un-gates itself once its failures age out. Combined with
|
|
2889
|
+
* the gate being a DE-RANK (out of leadership, retained as graceful
|
|
2890
|
+
* fallback) rather than a hard block, the model keeps earning evidence, so
|
|
2891
|
+
* this cannot become the exclusion-lock-in trap where a blocked model can
|
|
2892
|
+
* never prove itself again.
|
|
2893
|
+
*
|
|
2894
|
+
* **The threshold is a confidence bound, not a fixed sample floor.** A flat
|
|
2895
|
+
* `minSample: 20` (promotion-guard's rate floor) would NOT have fired on
|
|
2896
|
+
* haiku's n=12 — the consumer would keep paying while we waited for a
|
|
2897
|
+
* rounder number. But distinguishing 100% from 5% needs far fewer trials
|
|
2898
|
+
* than distinguishing 2% from 6%. Gating on the Wilson score lower bound
|
|
2899
|
+
* makes the sample requirement adapt to the effect size automatically,
|
|
2900
|
+
* which is the alpha.67 insight ("the sample floor for a median can be far
|
|
2901
|
+
* lower than for a rate") generalised properly.
|
|
2902
|
+
*
|
|
2903
|
+
* **Direct app-scoped read, not the config-endpoint cache.** Modelled on
|
|
2904
|
+
* `promotions-brain.ts`, deliberately NOT `createBrainQueryCache` — that
|
|
2905
|
+
* routes through the dashboard `/v2/config` projection, which is the third
|
|
2906
|
+
* layer in the L-073 "executable knowledge is dropped at every transport
|
|
2907
|
+
* boundary" chain. One fewer place to forget a field.
|
|
2908
|
+
*/
|
|
2909
|
+
|
|
2910
|
+
/**
|
|
2911
|
+
* One row of the rolling-window evidence view, per (app, archetype, model).
|
|
2912
|
+
* Raw counts only — the brain serves facts, this module decides.
|
|
2913
|
+
*/
|
|
2914
|
+
interface SurfaceFailureRow {
|
|
2915
|
+
archetype: string;
|
|
2916
|
+
model: string;
|
|
2917
|
+
/** Total attempts in-window (served + quality walkaways). */
|
|
2918
|
+
n: number;
|
|
2919
|
+
/** Attempts that failed on the quality axis. */
|
|
2920
|
+
nFail: number;
|
|
2921
|
+
}
|
|
2922
|
+
declare const MEASURED_FAILURE_CFG: {
|
|
2923
|
+
/**
|
|
2924
|
+
* Hard minimum attempts before ANY gate may be created. Guards against
|
|
2925
|
+
* pathological tiny samples that the confidence bound alone would let
|
|
2926
|
+
* through in edge cases. At 5-for-5 the bound clears the threshold; at
|
|
2927
|
+
* 3-for-3 it does not, which is the behaviour we want (three failures is
|
|
2928
|
+
* a bad day, five in a row is a pattern).
|
|
2929
|
+
*/
|
|
2930
|
+
readonly minSample: 5;
|
|
2931
|
+
/**
|
|
2932
|
+
* Gate when we are 95% confident the model fails MORE OFTEN THAN IT
|
|
2933
|
+
* SUCCEEDS on this surface. Deliberately unarguable rather than tuned —
|
|
2934
|
+
* a model that probably fails the majority of the time has no business
|
|
2935
|
+
* leading a surface, whatever its declared scores say.
|
|
2936
|
+
*/
|
|
2937
|
+
readonly lowerBoundThreshold: 0.5;
|
|
2938
|
+
/** 95% one-sided-ish confidence (standard two-sided z at α=0.05). */
|
|
2939
|
+
readonly z: 1.96;
|
|
2940
|
+
/** Must match the view's window. Documented here for the advisory text. */
|
|
2941
|
+
readonly windowDays: 28;
|
|
2942
|
+
};
|
|
2943
|
+
/**
|
|
2944
|
+
* Wilson score interval, lower bound. Preferred over the normal
|
|
2945
|
+
* approximation because it stays sane at the extremes — at p̂ = 1 the
|
|
2946
|
+
* normal approximation gives a zero-width interval (it would gate on a
|
|
2947
|
+
* single failure), while Wilson correctly returns a bound that tightens
|
|
2948
|
+
* with n.
|
|
2949
|
+
*
|
|
2950
|
+
* Returns 0 for n <= 0.
|
|
2951
|
+
*/
|
|
2952
|
+
declare function wilsonLowerBound(failures: number, n: number, z?: number): number;
|
|
2953
|
+
interface MeasuredFailureVerdict {
|
|
2954
|
+
/** Whether the measured-failure quality gate fires for this tuple. */
|
|
2955
|
+
gated: boolean;
|
|
2956
|
+
/** Observed failure rate in-window. */
|
|
2957
|
+
rate: number;
|
|
2958
|
+
/** 95% lower confidence bound on that rate — what the gate tests. */
|
|
2959
|
+
lowerBound: number;
|
|
2960
|
+
/** Attempts backing the verdict. */
|
|
2961
|
+
n: number;
|
|
2962
|
+
nFail: number;
|
|
2963
|
+
}
|
|
2964
|
+
/**
|
|
2965
|
+
* Pure decision, exported for tests and for the advisory text. Separated
|
|
2966
|
+
* from the I/O so the policy can be exercised without a brain.
|
|
2967
|
+
*/
|
|
2968
|
+
declare function judgeMeasuredFailure(row: SurfaceFailureRow | undefined, cfg?: typeof MEASURED_FAILURE_CFG): MeasuredFailureVerdict | undefined;
|
|
2969
|
+
interface MeasuredFailureRuntime {
|
|
2970
|
+
/** Endpoint base URL. The library appends `?app_id=<id>`. */
|
|
2971
|
+
endpoint: string;
|
|
2972
|
+
/** Stale-while-revalidate window in ms. */
|
|
2973
|
+
ttlMs: number;
|
|
2974
|
+
fetchImpl: typeof fetch;
|
|
2975
|
+
onError?: (err: unknown) => void;
|
|
2976
|
+
}
|
|
2977
|
+
/** Default endpoint on the kgauto-dashboard. Mirrors the promotions convention. */
|
|
2978
|
+
declare const DEFAULT_MEASURED_FAILURE_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/measured-failure";
|
|
2979
|
+
/**
|
|
2980
|
+
* Opt-out env switch. UNLIKE auto-promote this defaults ON wherever the
|
|
2981
|
+
* brain is configured, because the gate is protective: it only ever
|
|
2982
|
+
* de-ranks a model the consumer's OWN traffic shows to be failing them, and
|
|
2983
|
+
* the failure is already being paid for. Set `KGAUTO_MEASURED_FAILURE_GATE=0`
|
|
2984
|
+
* (or 'false') to disable.
|
|
2985
|
+
*/
|
|
2986
|
+
declare function isMeasuredFailureGateEnabledFromEnv(envSource?: Record<string, string | undefined>): boolean;
|
|
2987
|
+
declare function configureMeasuredFailureBrain(rt: MeasuredFailureRuntime | undefined): void;
|
|
2988
|
+
declare function isMeasuredFailureBrainActive(): boolean;
|
|
2989
|
+
interface GetMeasuredFailureOpts {
|
|
2990
|
+
appId: string;
|
|
2991
|
+
archetype: IntentArchetypeName | string;
|
|
2992
|
+
model: string;
|
|
2993
|
+
}
|
|
2994
|
+
/**
|
|
2995
|
+
* Sync reader. Returns the verdict for `(appId, archetype, model)` or
|
|
2996
|
+
* undefined (not configured / cold / below minSample / brain down).
|
|
2997
|
+
*
|
|
2998
|
+
* NEVER throws. Cold start returns undefined and warms in the background —
|
|
2999
|
+
* same posture as every other brain-driven lever in compile().
|
|
280
3000
|
*/
|
|
281
|
-
declare function
|
|
3001
|
+
declare function getMeasuredFailureVerdict(opts: GetMeasuredFailureOpts): MeasuredFailureVerdict | undefined;
|
|
3002
|
+
declare function _testResetMeasuredFailure(): void;
|
|
3003
|
+
declare function _testWaitForMeasuredFailureRefresh(): Promise<void>;
|
|
282
3004
|
|
|
283
3005
|
/**
|
|
284
3006
|
* @warmdrift/kgauto v2 — prompt compiler + central learning brain.
|
|
@@ -326,4 +3048,4 @@ declare function runAdvisor(ir: PromptIR, result: AdvisorContext, profile: Model
|
|
|
326
3048
|
*/
|
|
327
3049
|
declare function compile(ir: PromptIR, opts?: CompileOptions): CompileResult;
|
|
328
3050
|
|
|
329
|
-
export { ApiKeys, type AppOracle, BestPracticeAdvisory, type BrainConfig, CallOptions, CallResult, type CompileOptions, CompilePolicy, CompileResult, CompiledRequest, type ExecuteErr, type ExecuteOk, type ExecuteOptions, type ExecuteResult, type LLMJudgeOptions, ModelProfile, NormalizedResponse, type OracleContext, OracleScore, type OutcomePayload, PromptIR, ProviderOverrides, RecordInput, buildLLMJudge, call, clearBrain, compile, configureBrain, countTokens, execute, record, resetTokenizer, runAdvisor, setTokenizer };
|
|
3051
|
+
export { ABSOLUTE_FLOOR, type AISDKConvertedMessage, ARCHETYPE_FAMILY_FITS, ARCHETYPE_FLOOR_DEFAULT, type ActionableAdvisory, Adapter, type AdvisoryResolutionSource, type AdvisorySeverity, type AdvisoryStatus, type AdvisorySuggestedFix, ApiKeys, type AppOracle, type ApplySectionRewritesArgs, type ApplySectionRewritesResult, ArchetypeConvention, type ArchetypeFamilyFit, type ArchetypePerfMap, type ArchetypePerfNMap, type ArchetypePerfScoreResult, type AttachCacheControlResult, BestPracticeAdvisory, type BrainConfig, type BrainDeadLetterEntry, type BrainHealthSnapshot, type BrainQueryConfig, type BrainReadEnv, CallOptions, CallResult, ChainEntry, type CompatibilityIntent, type CompileForAISDKv6Result, type CompileOptions, CompilePolicy, CompileResult, CompiledRequest, DEFAULT_FINDINGS_ENDPOINT, DEFAULT_MEASURED_FAILURE_ENDPOINT, DEFAULT_PROMOTIONS_ENDPOINT, type ExclusionFindingRow, type ExclusionResolutionSource, type ExecuteErr, type ExecuteOk, type ExecuteOptions, type ExecuteResult, type FallbackPosture, FamilyResolutionError, type GetActionableAdvisoriesOptions, type GetApplicablePromotionOpts, type GetDefaultFallbackChainOpts, type GetMeasuredFailureOpts, type GetPerAxisMetricsOpts, type GetRecommendedPrimaryOptions, type GoldenEvalCase, type GoldenEvalOptions, type GoldenEvalRunResult, type GoldenIrRecordInput, Grounding, IntentArchetypeName, JUDGE_RUBRICS, LIBRARY_VERSION, type LLMJudgeOptions, MEASURED_FAILURE_CFG, MEASURED_GROUNDING_MIN_N, type MarkAdvisoryResolvedOptions, type MarkExclusionFindingHandledOptions, type MarkPromoteReadyHandledOptions, type MeasuredFailureRuntime, type MeasuredFailureVerdict, type ModelBrainRow, type ModelCompatibility, ModelProfile, NormalizedResponse, type OracleContext, OracleScore, type OutcomePayload, OutcomeResult, OutputMode, PRODUCER_OWNED_RULE_CODES, PROVIDER_ENV_KEYS, PerAxisMetrics, type PricingRow, type ProbeShadowOptions, type ProbeShadowServed, type ProfileToRowOptions, type PromoteReadyFindingRow, type PromoteReadyResolution, type PromotionRow, type PromotionsRuntime, PromptIR, Provider, ProviderOverrides, type ProviderReachability, RULE_SEQUENTIAL_TOOL_CLIFF, type ReachabilityOpts, RecordInput, RecordOutcomeInput, type RunAdvisorPhase2Context, SectionRewrite, type ShadowProbeRecordInput, type SupportedProvider, type SurfaceFailureRow, SystemModelMessage, TRANSLATOR_FLOOR, _testResetMeasuredFailure, _testResetPromotions, _testWaitForMeasuredFailureRefresh, _testWaitForPromotionsRefresh, applyArchetypeConvention, applySectionRewrites, attachCacheControlToStreamTextInput, brainHealth, buildGoldenIrRow, buildLLMJudge, buildPairwiseJudgePrompt, buildShadowProbeRow, call, clearBrain, combineOrderSwappedVerdicts, compile, compileForAISDKv6, configureBrain, configureMeasuredFailureBrain, configurePromotionsBrain, countTokens, deriveFamilyFromModelId, deriveOwnership, execute, findBetterFit, flushBrainDeadLetter, getActionableAdvisories, getAllStarterChains, getAllStarterChainsWithGrounding, getApplicablePromotion, getArchetypePerfScore, getDefaultFallbackChain, getDefaultFallbackChainWithGrounding, getMeasuredFailureVerdict, getModelCompatibility, getPerAxisMetrics, getReachabilityDiagnostic, getRecommendedPrimary, getSequentialStarterChain, getSequentialStarterChainWithGrounding, getStaleExclusionFindings, getStarterChain, getStarterChainWithGrounding, isAutoPromoteEnabledFromEnv, isBrainQueryActiveFor, isBrainSync, isExclusionFindingsBrainActive, isMeasuredFailureBrainActive, isMeasuredFailureGateEnabledFromEnv, isModelReachable, isPromotionsBrainActive, isProviderReachable, judgeMeasuredFailure, loadAliasesFromBrain, loadArchetypePerfFromBrain, loadArchetypePerfNFromBrain, loadChainsFromBrain, loadModelsFromBrain, loadPricingFromBrain, markAdvisoryResolved, markExclusionFindingHandled, markPromoteReadyHandled, parseJudgeVerdict, peekBrainDeadLetter, probeShadow, profileToRow, readBrainReadEnv, record, recordGoldenIr, recordOutcome, recordShadowProbe, renderIrForJudge, resetTokenizer, resolveConventionsForProfile, resolvePricingAt, resolveProviderKey, rubricFor, runAdvisor, runGoldenEval, setTokenizer, wilsonLowerBound };
|