@warmdrift/kgauto-compiler 2.0.0-alpha.16 → 2.0.0-alpha.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2925,9 +2925,321 @@ function ensureCrossProviderTail(opts) {
2925
2925
  return { chain };
2926
2926
  }
2927
2927
 
2928
+ // src/glassbox/types.ts
2929
+ var GLASSBOX_STREAM_TTL_MS = 6e4;
2930
+
2931
+ // src/glassbox/pubsub-memory.ts
2932
+ var MemoryPubSub = class {
2933
+ subscribers = /* @__PURE__ */ new Map();
2934
+ async publish(traceId, event) {
2935
+ const subs = this.subscribers.get(traceId);
2936
+ if (!subs || subs.size === 0) return;
2937
+ for (const sub of subs) {
2938
+ if (sub.closed) continue;
2939
+ try {
2940
+ sub.controller.enqueue(event);
2941
+ } catch {
2942
+ sub.closed = true;
2943
+ continue;
2944
+ }
2945
+ this.refreshTtl(traceId, sub);
2946
+ }
2947
+ }
2948
+ subscribe(traceId) {
2949
+ const self = this;
2950
+ let sub;
2951
+ return new ReadableStream({
2952
+ start(controller) {
2953
+ sub = {
2954
+ controller,
2955
+ ttlTimer: setTimeout(() => {
2956
+ self.closeSubscriber(traceId, sub);
2957
+ }, GLASSBOX_STREAM_TTL_MS),
2958
+ closed: false
2959
+ };
2960
+ let set = self.subscribers.get(traceId);
2961
+ if (!set) {
2962
+ set = /* @__PURE__ */ new Set();
2963
+ self.subscribers.set(traceId, set);
2964
+ }
2965
+ set.add(sub);
2966
+ },
2967
+ cancel() {
2968
+ if (sub) self.removeSubscriber(traceId, sub);
2969
+ }
2970
+ });
2971
+ }
2972
+ /**
2973
+ * Refresh the rolling TTL for a subscriber after an event lands. Replaces
2974
+ * the existing timer with a fresh 60s one.
2975
+ */
2976
+ refreshTtl(traceId, sub) {
2977
+ clearTimeout(sub.ttlTimer);
2978
+ sub.ttlTimer = setTimeout(() => {
2979
+ this.closeSubscriber(traceId, sub);
2980
+ }, GLASSBOX_STREAM_TTL_MS);
2981
+ }
2982
+ /**
2983
+ * Close the subscriber's stream cleanly and remove from the fan-out set.
2984
+ * Idempotent — safe to call multiple times.
2985
+ */
2986
+ closeSubscriber(traceId, sub) {
2987
+ if (sub.closed) return;
2988
+ sub.closed = true;
2989
+ clearTimeout(sub.ttlTimer);
2990
+ try {
2991
+ sub.controller.close();
2992
+ } catch {
2993
+ }
2994
+ this.removeSubscriber(traceId, sub);
2995
+ }
2996
+ removeSubscriber(traceId, sub) {
2997
+ clearTimeout(sub.ttlTimer);
2998
+ const set = this.subscribers.get(traceId);
2999
+ if (!set) return;
3000
+ set.delete(sub);
3001
+ if (set.size === 0) this.subscribers.delete(traceId);
3002
+ }
3003
+ /**
3004
+ * Test-only reset. Tears down all subscribers, clears all state. Calling
3005
+ * outside of tests is harmless but cancels every active stream.
3006
+ */
3007
+ _reset() {
3008
+ for (const [, set] of this.subscribers) {
3009
+ for (const sub of set) {
3010
+ this.closeSubscriber("", sub);
3011
+ }
3012
+ }
3013
+ this.subscribers.clear();
3014
+ }
3015
+ };
3016
+
3017
+ // src/glassbox/pubsub-upstash.ts
3018
+ var UpstashPubSub = class {
3019
+ url;
3020
+ token;
3021
+ fetchImpl;
3022
+ blockMs;
3023
+ maxLen;
3024
+ constructor(cfg) {
3025
+ this.url = cfg.url.replace(/\/$/, "");
3026
+ this.token = cfg.token;
3027
+ this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch.bind(globalThis);
3028
+ this.blockMs = cfg.blockMs ?? 100;
3029
+ this.maxLen = cfg.maxLen ?? 100;
3030
+ }
3031
+ async publish(traceId, event) {
3032
+ const key = streamKey(traceId);
3033
+ const payload = JSON.stringify(event);
3034
+ await this.cmd([
3035
+ "XADD",
3036
+ key,
3037
+ "MAXLEN",
3038
+ "~",
3039
+ String(this.maxLen),
3040
+ "*",
3041
+ "event",
3042
+ payload
3043
+ ]);
3044
+ await this.cmd(["EXPIRE", key, String(Math.ceil(GLASSBOX_STREAM_TTL_MS / 1e3))]);
3045
+ }
3046
+ subscribe(traceId) {
3047
+ const key = streamKey(traceId);
3048
+ const self = this;
3049
+ let cursor = "$";
3050
+ let cancelled = false;
3051
+ let ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
3052
+ return new ReadableStream({
3053
+ async start(controller) {
3054
+ try {
3055
+ while (!cancelled && Date.now() < ttlDeadline) {
3056
+ const resp = await self.cmd([
3057
+ "XREAD",
3058
+ "BLOCK",
3059
+ String(self.blockMs),
3060
+ "STREAMS",
3061
+ key,
3062
+ cursor
3063
+ ]);
3064
+ if (cancelled) break;
3065
+ const parsed = parseXReadResult(resp.result);
3066
+ if (parsed.entries.length === 0) {
3067
+ continue;
3068
+ }
3069
+ for (const entry of parsed.entries) {
3070
+ const evt = decodeEvent(entry.fields);
3071
+ if (evt) {
3072
+ try {
3073
+ controller.enqueue(evt);
3074
+ } catch {
3075
+ cancelled = true;
3076
+ break;
3077
+ }
3078
+ }
3079
+ cursor = entry.id;
3080
+ }
3081
+ ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
3082
+ }
3083
+ } catch (err) {
3084
+ if (!cancelled) {
3085
+ try {
3086
+ controller.error(err);
3087
+ } catch {
3088
+ }
3089
+ return;
3090
+ }
3091
+ }
3092
+ try {
3093
+ controller.close();
3094
+ } catch {
3095
+ }
3096
+ },
3097
+ cancel() {
3098
+ cancelled = true;
3099
+ }
3100
+ });
3101
+ }
3102
+ async cmd(args) {
3103
+ const res = await this.fetchImpl(this.url, {
3104
+ method: "POST",
3105
+ headers: {
3106
+ Authorization: `Bearer ${this.token}`,
3107
+ "Content-Type": "application/json"
3108
+ },
3109
+ body: JSON.stringify(args)
3110
+ });
3111
+ if (!res.ok) {
3112
+ throw new Error(`Upstash ${args[0]} failed: HTTP ${res.status}`);
3113
+ }
3114
+ const json = await res.json();
3115
+ if (json.error) {
3116
+ throw new Error(`Upstash ${args[0]} failed: ${json.error}`);
3117
+ }
3118
+ return json;
3119
+ }
3120
+ };
3121
+ function streamKey(traceId) {
3122
+ return `glassbox:trace:${traceId}`;
3123
+ }
3124
+ function decodeEvent(fields) {
3125
+ const raw = fields["event"];
3126
+ if (!raw) return void 0;
3127
+ try {
3128
+ const parsed = JSON.parse(raw);
3129
+ if (typeof parsed.kind === "string" && typeof parsed.at === "number") {
3130
+ return parsed;
3131
+ }
3132
+ return void 0;
3133
+ } catch {
3134
+ return void 0;
3135
+ }
3136
+ }
3137
+ function parseXReadResult(raw) {
3138
+ if (!Array.isArray(raw)) return { entries: [] };
3139
+ const entries = [];
3140
+ for (const stream of raw) {
3141
+ if (!Array.isArray(stream) || stream.length < 2) continue;
3142
+ const streamEntries = stream[1];
3143
+ if (!Array.isArray(streamEntries)) continue;
3144
+ for (const entry of streamEntries) {
3145
+ if (!Array.isArray(entry) || entry.length < 2) continue;
3146
+ const id = String(entry[0]);
3147
+ const flat = entry[1];
3148
+ if (!Array.isArray(flat)) continue;
3149
+ const fields = {};
3150
+ for (let i = 0; i < flat.length; i += 2) {
3151
+ const k = flat[i];
3152
+ const v = flat[i + 1];
3153
+ if (typeof k === "string") fields[k] = String(v ?? "");
3154
+ }
3155
+ entries.push({ id, fields });
3156
+ }
3157
+ }
3158
+ return { entries };
3159
+ }
3160
+
3161
+ // src/glassbox/emit.ts
3162
+ var activePubSub;
3163
+ function getPubSub() {
3164
+ if (activePubSub) return activePubSub;
3165
+ const url = readEnv("UPSTASH_REDIS_URL");
3166
+ const token = readEnv("UPSTASH_REDIS_TOKEN");
3167
+ if (url && token) {
3168
+ activePubSub = new UpstashPubSub({ url, token });
3169
+ } else {
3170
+ activePubSub = new MemoryPubSub();
3171
+ }
3172
+ return activePubSub;
3173
+ }
3174
+ function readEnv(key) {
3175
+ try {
3176
+ if (typeof process !== "undefined" && process.env) {
3177
+ const v = process.env[key];
3178
+ return v && v.trim() !== "" ? v : void 0;
3179
+ }
3180
+ } catch {
3181
+ }
3182
+ return void 0;
3183
+ }
3184
+ function emitGlassboxEvent(traceId, kind, data) {
3185
+ if (!traceId) return;
3186
+ const event = { kind, at: Date.now(), data };
3187
+ const ps = getPubSub();
3188
+ try {
3189
+ const p = ps.publish(traceId, event);
3190
+ if (p && typeof p.then === "function") {
3191
+ p.catch(() => {
3192
+ });
3193
+ }
3194
+ } catch {
3195
+ }
3196
+ }
3197
+ function emitCompileStart(traceId, data) {
3198
+ emitGlassboxEvent(traceId, "compile.start", data);
3199
+ }
3200
+ function emitCompileDone(traceId, data) {
3201
+ emitGlassboxEvent(traceId, "compile.done", data);
3202
+ }
3203
+ function emitExecuteAttempt(traceId, data) {
3204
+ emitGlassboxEvent(traceId, "execute.attempt", data);
3205
+ }
3206
+ function emitExecuteSuccess(traceId, data) {
3207
+ emitGlassboxEvent(traceId, "execute.success", data);
3208
+ }
3209
+ function emitAdvisoryFired(traceId, data) {
3210
+ emitGlassboxEvent(traceId, "advisory.fired", data);
3211
+ }
3212
+ function emitFallbackWalked(traceId, data) {
3213
+ emitGlassboxEvent(traceId, "fallback.walked", data);
3214
+ }
3215
+
2928
3216
  // src/call.ts
2929
3217
  async function call(ir, opts = {}) {
3218
+ const traceId = generateTraceId();
3219
+ safeEmit(
3220
+ () => emitCompileStart(traceId, {
3221
+ appId: ir.appId,
3222
+ archetype: ir.intent.archetype,
3223
+ models: ir.models
3224
+ })
3225
+ );
2930
3226
  const initial = compileAndRegister(ir, opts);
3227
+ safeEmit(
3228
+ () => emitCompileDone(traceId, {
3229
+ target: initial.target,
3230
+ provider: initial.provider,
3231
+ fallbackChain: initial.fallbackChain,
3232
+ tokensIn: initial.tokensIn,
3233
+ estimatedCostUsd: initial.estimatedCostUsd,
3234
+ mutationsApplied: initial.mutationsApplied,
3235
+ advisories: initial.advisories
3236
+ })
3237
+ );
3238
+ for (const adv of initial.advisories) {
3239
+ safeEmit(
3240
+ () => emitAdvisoryFired(traceId, { code: adv.code, message: adv.message })
3241
+ );
3242
+ }
2931
3243
  const start = Date.now();
2932
3244
  const attempts = [];
2933
3245
  const rawTargets = [initial.target, ...initial.fallbackChain];
@@ -3058,6 +3370,9 @@ async function call(ir, opts = {}) {
3058
3370
  continue;
3059
3371
  }
3060
3372
  }
3373
+ safeEmit(
3374
+ () => emitExecuteAttempt(traceId, { model: targetModel, attemptIndex: i })
3375
+ );
3061
3376
  const exec = await execute(activeCompile.request, {
3062
3377
  apiKeys: opts.apiKeys,
3063
3378
  fetchImpl: opts.fetchImpl,
@@ -3067,6 +3382,14 @@ async function call(ir, opts = {}) {
3067
3382
  if (validated.ok) {
3068
3383
  attempts.push({ model: targetModel, status: "success" });
3069
3384
  const latencyMs2 = Date.now() - start;
3385
+ safeEmit(
3386
+ () => emitExecuteSuccess(traceId, {
3387
+ model: targetModel,
3388
+ tokensIn: validated.response.tokens.input,
3389
+ tokensOut: validated.response.tokens.output,
3390
+ latencyMs: latencyMs2
3391
+ })
3392
+ );
3070
3393
  await record({
3071
3394
  handle: initial.handle,
3072
3395
  tokensIn: validated.response.tokens.input,
@@ -3083,6 +3406,20 @@ async function call(ir, opts = {}) {
3083
3406
  cacheCreationInputTokens: validated.response.tokens.cacheCreated
3084
3407
  });
3085
3408
  const fellOver = targetModel !== initial.target;
3409
+ const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
3410
+ if (fellOver) {
3411
+ const firstFailed = attempts.find((a) => a.status !== "success");
3412
+ if (firstFailed) {
3413
+ safeEmit(
3414
+ () => emitFallbackWalked(traceId, {
3415
+ from: initial.target,
3416
+ to: targetModel,
3417
+ reason: fallbackReason ?? "unknown",
3418
+ attempt: firstFailed
3419
+ })
3420
+ );
3421
+ }
3422
+ }
3086
3423
  return {
3087
3424
  handle: initial.handle,
3088
3425
  actualModel: targetModel,
@@ -3094,9 +3431,10 @@ async function call(ir, opts = {}) {
3094
3431
  attempts,
3095
3432
  servedBy: targetModel,
3096
3433
  fellOverFrom: fellOver ? initial.target : void 0,
3097
- fallbackReason: fellOver ? normalizeFallbackReason(attempts) : void 0,
3434
+ fallbackReason,
3098
3435
  unreachableFiltered,
3099
- policyBlockedFiltered
3436
+ policyBlockedFiltered,
3437
+ traceId
3100
3438
  };
3101
3439
  }
3102
3440
  attempts.push({
@@ -3193,6 +3531,23 @@ function normalizeFallbackReason(attempts) {
3193
3531
  if (code === "auth" || code === "auth_inferred") return "provider_auth_failed";
3194
3532
  return "provider_error";
3195
3533
  }
3534
+ function generateTraceId() {
3535
+ try {
3536
+ const g = globalThis;
3537
+ if (g.crypto && typeof g.crypto.randomUUID === "function") {
3538
+ return g.crypto.randomUUID();
3539
+ }
3540
+ } catch {
3541
+ }
3542
+ const hex = (n) => Math.floor(Math.random() * Math.pow(16, n)).toString(16).padStart(n, "0");
3543
+ return `${hex(8)}-${hex(4)}-${hex(4)}-${hex(4)}-${hex(12)}`;
3544
+ }
3545
+ function safeEmit(fn) {
3546
+ try {
3547
+ fn();
3548
+ } catch {
3549
+ }
3550
+ }
3196
3551
 
3197
3552
  // src/oracle.ts
3198
3553
  var DEFAULT_DIMENSIONS = ["correctness", "completeness", "conciseness", "format"];
package/dist/index.mjs CHANGED
@@ -18,6 +18,14 @@ import {
18
18
  profilesByProvider,
19
19
  tryGetProfile
20
20
  } from "./chunk-7MTHFSNY.mjs";
21
+ import {
22
+ emitAdvisoryFired,
23
+ emitCompileDone,
24
+ emitCompileStart,
25
+ emitExecuteAttempt,
26
+ emitExecuteSuccess,
27
+ emitFallbackWalked
28
+ } from "./chunk-NUTC7NUC.mjs";
21
29
 
22
30
  // src/tokenizer.ts
23
31
  var tokenizerImpl = defaultCharBasedCounter;
@@ -1723,7 +1731,31 @@ function ensureCrossProviderTail(opts) {
1723
1731
 
1724
1732
  // src/call.ts
1725
1733
  async function call(ir, opts = {}) {
1734
+ const traceId = generateTraceId();
1735
+ safeEmit(
1736
+ () => emitCompileStart(traceId, {
1737
+ appId: ir.appId,
1738
+ archetype: ir.intent.archetype,
1739
+ models: ir.models
1740
+ })
1741
+ );
1726
1742
  const initial = compileAndRegister(ir, opts);
1743
+ safeEmit(
1744
+ () => emitCompileDone(traceId, {
1745
+ target: initial.target,
1746
+ provider: initial.provider,
1747
+ fallbackChain: initial.fallbackChain,
1748
+ tokensIn: initial.tokensIn,
1749
+ estimatedCostUsd: initial.estimatedCostUsd,
1750
+ mutationsApplied: initial.mutationsApplied,
1751
+ advisories: initial.advisories
1752
+ })
1753
+ );
1754
+ for (const adv of initial.advisories) {
1755
+ safeEmit(
1756
+ () => emitAdvisoryFired(traceId, { code: adv.code, message: adv.message })
1757
+ );
1758
+ }
1727
1759
  const start = Date.now();
1728
1760
  const attempts = [];
1729
1761
  const rawTargets = [initial.target, ...initial.fallbackChain];
@@ -1854,6 +1886,9 @@ async function call(ir, opts = {}) {
1854
1886
  continue;
1855
1887
  }
1856
1888
  }
1889
+ safeEmit(
1890
+ () => emitExecuteAttempt(traceId, { model: targetModel, attemptIndex: i })
1891
+ );
1857
1892
  const exec = await execute(activeCompile.request, {
1858
1893
  apiKeys: opts.apiKeys,
1859
1894
  fetchImpl: opts.fetchImpl,
@@ -1863,6 +1898,14 @@ async function call(ir, opts = {}) {
1863
1898
  if (validated.ok) {
1864
1899
  attempts.push({ model: targetModel, status: "success" });
1865
1900
  const latencyMs2 = Date.now() - start;
1901
+ safeEmit(
1902
+ () => emitExecuteSuccess(traceId, {
1903
+ model: targetModel,
1904
+ tokensIn: validated.response.tokens.input,
1905
+ tokensOut: validated.response.tokens.output,
1906
+ latencyMs: latencyMs2
1907
+ })
1908
+ );
1866
1909
  await record({
1867
1910
  handle: initial.handle,
1868
1911
  tokensIn: validated.response.tokens.input,
@@ -1879,6 +1922,20 @@ async function call(ir, opts = {}) {
1879
1922
  cacheCreationInputTokens: validated.response.tokens.cacheCreated
1880
1923
  });
1881
1924
  const fellOver = targetModel !== initial.target;
1925
+ const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
1926
+ if (fellOver) {
1927
+ const firstFailed = attempts.find((a) => a.status !== "success");
1928
+ if (firstFailed) {
1929
+ safeEmit(
1930
+ () => emitFallbackWalked(traceId, {
1931
+ from: initial.target,
1932
+ to: targetModel,
1933
+ reason: fallbackReason ?? "unknown",
1934
+ attempt: firstFailed
1935
+ })
1936
+ );
1937
+ }
1938
+ }
1882
1939
  return {
1883
1940
  handle: initial.handle,
1884
1941
  actualModel: targetModel,
@@ -1890,9 +1947,10 @@ async function call(ir, opts = {}) {
1890
1947
  attempts,
1891
1948
  servedBy: targetModel,
1892
1949
  fellOverFrom: fellOver ? initial.target : void 0,
1893
- fallbackReason: fellOver ? normalizeFallbackReason(attempts) : void 0,
1950
+ fallbackReason,
1894
1951
  unreachableFiltered,
1895
- policyBlockedFiltered
1952
+ policyBlockedFiltered,
1953
+ traceId
1896
1954
  };
1897
1955
  }
1898
1956
  attempts.push({
@@ -1989,6 +2047,23 @@ function normalizeFallbackReason(attempts) {
1989
2047
  if (code === "auth" || code === "auth_inferred") return "provider_auth_failed";
1990
2048
  return "provider_error";
1991
2049
  }
2050
+ function generateTraceId() {
2051
+ try {
2052
+ const g = globalThis;
2053
+ if (g.crypto && typeof g.crypto.randomUUID === "function") {
2054
+ return g.crypto.randomUUID();
2055
+ }
2056
+ } catch {
2057
+ }
2058
+ const hex = (n) => Math.floor(Math.random() * Math.pow(16, n)).toString(16).padStart(n, "0");
2059
+ return `${hex(8)}-${hex(4)}-${hex(4)}-${hex(4)}-${hex(12)}`;
2060
+ }
2061
+ function safeEmit(fn) {
2062
+ try {
2063
+ fn();
2064
+ } catch {
2065
+ }
2066
+ }
1992
2067
 
1993
2068
  // src/oracle.ts
1994
2069
  var DEFAULT_DIMENSIONS = ["correctness", "completeness", "conciseness", "format"];
@@ -538,6 +538,18 @@ interface CallResult {
538
538
  * case.
539
539
  */
540
540
  policyBlockedFiltered?: string[];
541
+ /**
542
+ * alpha.17. Unique identifier for this call() invocation, generated at
543
+ * call() entry via crypto.randomUUID(). Returned on success and emitted
544
+ * as the routing key for Glass-Box observability events
545
+ * (compile.start, compile.done, execute.attempt, execute.success,
546
+ * fallback.walked, advisory.fired). Pass the same id to
547
+ * `subscribe(traceId)` from `@warmdrift/kgauto-compiler/glassbox` to
548
+ * tap the in-flight event stream.
549
+ *
550
+ * Always present on success. Additive, non-breaking.
551
+ */
552
+ traceId: string;
541
553
  }
542
554
  /**
543
555
  * Thrown when call() exhausts the fallback chain without success.
@@ -624,137 +636,4 @@ interface RecordInput {
624
636
  ttftMs?: number;
625
637
  }
626
638
 
627
- /**
628
- * Model profiles — executable knowledge about each provider/model.
629
- *
630
- * Unlike v1 which carried `known_failures` as prose strings, v2 makes them
631
- * executable: cliffs trigger guards, lowering describes the wire format,
632
- * recovery handlers describe what to do after specific failures.
633
- *
634
- * Each profile is the answer to "if I want to call THIS model with THIS
635
- * shape of work, what does it need from me, and what should I do when it
636
- * fails?"
637
- */
638
-
639
- type StructuredOutputCapability = 'native' | 'grammar' | 'none';
640
- type SystemPromptMode = 'inline' | 'separate' | 'as_developer' | 'unsupported';
641
- type CacheStrategy = 'cache_control' | 'cachedContent' | 'unsupported';
642
- interface CliffRule {
643
- /** What metric triggers this cliff. */
644
- metric: 'input_tokens' | 'tool_count' | 'history_turns' | 'thinking_with_short_output';
645
- /** Threshold — meaning depends on metric. */
646
- threshold: number;
647
- /** What action to take when triggered. */
648
- action: 'downgrade_quality_warning' | 'drop_to_top_relevant' | 'force_thinking_budget_zero' | 'force_terse_output' | 'escalate_target' | 'strip_tools';
649
- /**
650
- * Optional: only fire this cliff when the IR's intent.archetype matches.
651
- * Used for archetype-specific failure modes (e.g. Gemini Flash returns
652
- * empty when summarize is offered tools).
653
- */
654
- whenIntent?: IntentArchetypeName;
655
- /** Human-readable reason for digest reporting. */
656
- reason: string;
657
- }
658
- interface RecoveryRule {
659
- /** What signal triggers recovery. */
660
- signal: 'empty_response_after_tool' | 'empty_response' | 'malformed_function_call' | 'rate_limit' | 'model_not_found' | 'context_overflow';
661
- /** Action: retry with adjusted params, or escalate to next fallback. */
662
- action: 'retry_with_params' | 'escalate' | 'log_only';
663
- /** When action=retry_with_params, the param adjustments to apply. */
664
- retryParams?: Record<string, unknown>;
665
- /** Max retries with this rule. */
666
- maxRetries?: number;
667
- /** Human-readable reason for digest reporting. */
668
- reason: string;
669
- }
670
- interface LoweringSpec {
671
- /** Where the system prompt goes. */
672
- system: {
673
- mode: SystemPromptMode;
674
- field?: string;
675
- };
676
- /** Cache strategy + parameters. */
677
- cache: {
678
- strategy: CacheStrategy;
679
- /** Min tokens before caching is worth it (provider rules). */
680
- minTokens?: number;
681
- /** Discount factor on cached input (0.1 = 10% of normal price). */
682
- discount?: number;
683
- /** TTL hint in seconds. */
684
- ttlSeconds?: number;
685
- };
686
- /** Tool format identifier — see lower.ts for supported formats. */
687
- tools?: {
688
- format: 'anthropic' | 'google' | 'openai' | 'deepseek';
689
- };
690
- /** Thinking config — present iff this model has a thinking knob. */
691
- thinking?: {
692
- /** Field path on the request. */
693
- field: string;
694
- /** Default value when caller hasn't specified. */
695
- default?: number | 'auto' | 'off';
696
- };
697
- }
698
- interface ModelProfile {
699
- id: string;
700
- provider: Provider;
701
- status: 'current' | 'preview' | 'legacy';
702
- maxContextTokens: number;
703
- maxOutputTokens: number;
704
- maxTools: number;
705
- parallelToolCalls: boolean;
706
- structuredOutput: StructuredOutputCapability;
707
- systemPromptMode: SystemPromptMode;
708
- streaming: boolean;
709
- cliffs: CliffRule[];
710
- costInputPer1m: number;
711
- costOutputPer1m: number;
712
- lowering: LoweringSpec;
713
- recovery: RecoveryRule[];
714
- strengths: string[];
715
- weaknesses: string[];
716
- notes?: string;
717
- verifiedAgainstDocs?: string;
718
- /**
719
- * Hand-curated per-archetype performance score on a 0-10 scale.
720
- *
721
- * 10 = frontier on this archetype (e.g. Opus 4.7 on critique)
722
- * 8 = strong second tier (Sonnet on plan, Pro on extract)
723
- * 7 = competent (Haiku on classify, Flash on hunt)
724
- * 5 = acceptable for tolerant archetypes (Flash-Lite on classify)
725
- * 3 = degraded (Flash on critique, DeepSeek on hunt)
726
- *
727
- * Missing archetypes default to `5` (no data, neutral). Each non-default
728
- * value should carry a one-line rationale in the profile's note or inline
729
- * comment citing brain evidence, family prior, or "starter hypothesis —
730
- * verify with telemetry."
731
- *
732
- * Source today: hand-curated from master plan §3.3 + §6.2 starter tables.
733
- * Source tomorrow (alpha.10+): brain `archetype_model_evidence` view.
734
- *
735
- * Anti-hallucination guardrail (master plan §2.5): when the watcher's
736
- * `--audit-fields` flag flags a profile stale (>90 days since
737
- * verifiedAgainstDocs), the archetypePerf values get re-audited
738
- * alongside capability fields. AI-trained intuition is NOT a valid
739
- * source — only docs or brain evidence.
740
- *
741
- * alpha.9.
742
- */
743
- archetypePerf?: Partial<Record<IntentArchetypeName, number>>;
744
- }
745
- declare const ALIASES: Record<string, string>;
746
- interface ProfileBrainHook {
747
- getProfile?: (canonicalId: string) => ModelProfile | undefined;
748
- resolveAlias?: (id: string) => string | undefined;
749
- }
750
- /** @internal — called by models-brain.ts at module load. */
751
- declare function _setProfileBrainHook(hook: ProfileBrainHook): void;
752
- declare function getProfile(id: string): ModelProfile;
753
- declare function tryGetProfile(id: string): ModelProfile | undefined;
754
- declare function allProfiles(): readonly ModelProfile[];
755
- /** @internal — bundled-only access for adapters that need a non-brain
756
- * fallback baseline (avoids a brain → profiles → brain re-entry). */
757
- declare function allProfilesRaw(): readonly ModelProfile[];
758
- declare function profilesByProvider(provider: Provider): readonly ModelProfile[];
759
-
760
- export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type FallbackReason as F, type HistoryCachePolicy as H, type IntentDeclaration as I, type LoweringSpec as L, type ModelProfile as M, type NormalizedResponse as N, type OracleScore as O, type ProviderOverrides as P, type RecordInput as R, type StructuredOutputCapability as S, type ToolCall as T, _setProfileBrainHook as _, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type CompileResult as e, type Provider as f, ALIASES as g, type CacheStrategy as h, type CallAttempt as i, CallError as j, type CliffRule as k, type Constraints as l, type Message as m, type MutationApplied as n, type NormalizedTokens as o, type PromptSection as p, type RecoveryRule as q, type SystemPromptMode as r, type ToolDefinition as s, allProfiles as t, getProfile as u, profilesByProvider as v, tryGetProfile as w, allProfilesRaw as x };
639
+ export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type FallbackReason as F, type HistoryCachePolicy as H, type IntentDeclaration as I, type Message as M, type NormalizedResponse as N, type OracleScore as O, type ProviderOverrides as P, type RecordInput as R, type ToolCall as T, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type CompileResult as e, type Provider as f, type CallAttempt as g, CallError as h, type Constraints as i, type MutationApplied as j, type NormalizedTokens as k, type PromptSection as l, type ToolDefinition as m };