@warmdrift/kgauto-compiler 2.0.0-alpha.27 → 2.0.0-alpha.29

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.mjs CHANGED
@@ -9,6 +9,30 @@ import {
9
9
  isArchetype,
10
10
  learningKey
11
11
  } from "./chunk-5TI6PNSK.mjs";
12
+ import {
13
+ ABSOLUTE_FLOOR,
14
+ ARCHETYPE_FLOOR_DEFAULT,
15
+ PROVIDER_ENV_KEYS,
16
+ configureBrainQuery,
17
+ createBrainQueryCache,
18
+ ensureCrossProviderTail,
19
+ getAllStarterChains,
20
+ getAllStarterChainsWithGrounding,
21
+ getDefaultFallbackChain,
22
+ getDefaultFallbackChainWithGrounding,
23
+ getModelCompatibility,
24
+ getPerAxisMetrics,
25
+ getReachabilityDiagnostic,
26
+ getSequentialStarterChain,
27
+ getSequentialStarterChainWithGrounding,
28
+ getStarterChain,
29
+ getStarterChainWithGrounding,
30
+ isBrainQueryActiveFor,
31
+ isModelReachable,
32
+ isProviderReachable,
33
+ loadChainsFromBrain,
34
+ resolveProviderKey
35
+ } from "./chunk-WXCFWUCN.mjs";
12
36
  import {
13
37
  ALIASES,
14
38
  _setProfileBrainHook,
@@ -451,6 +475,7 @@ function lowerAnthropic(ir, profile, hints) {
451
475
  const historyCacheableTokens = markIndex >= 0 ? sumHistoryTokens(history, markIndex) : 0;
452
476
  const totalCacheableTokens = cacheableTokens + historyCacheableTokens;
453
477
  const cacheSavings = totalCacheableTokens / 1e6 * profile.costInputPer1m * (1 - (profile.lowering.cache.discount ?? 0.1));
478
+ const toolChoice = hints.wireOverrides?.parallelToolCalls === false && tools && tools.length > 0 ? { type: "auto", disable_parallel_tool_use: true } : void 0;
454
479
  return {
455
480
  request: {
456
481
  provider: "anthropic",
@@ -462,7 +487,8 @@ function lowerAnthropic(ir, profile, hints) {
462
487
  // floor surprised every consumer once (PB-Cairn contract-gaps brief, Gap 3).
463
488
  // Profile is the single source of truth; consumers wanting a tighter
464
489
  // budget can pass providerOverrides.anthropic.max_tokens explicitly.
465
- max_tokens: hints.forceTerseOutput ? 200 : profile.maxOutputTokens
490
+ max_tokens: hints.forceTerseOutput ? 200 : profile.maxOutputTokens,
491
+ tool_choice: toolChoice
466
492
  },
467
493
  diagnostics: {
468
494
  cacheableTokens,
@@ -656,6 +682,7 @@ function lowerOpenAI(ir, profile, hints) {
656
682
  const history = (ir.history ?? []).filter((m) => m.role !== "system");
657
683
  const histMarkIndex = resolveHistoryMarkIndex(history.length, ir.historyCachePolicy);
658
684
  const historyCacheableTokens = histMarkIndex >= 0 ? sumHistoryTokens(history, histMarkIndex) : 0;
685
+ const openaiParallelToolCalls = hints.wireOverrides?.parallelToolCalls === false && ir.tools && ir.tools.length > 0 ? false : void 0;
659
686
  return {
660
687
  request: {
661
688
  provider: "openai",
@@ -663,7 +690,8 @@ function lowerOpenAI(ir, profile, hints) {
663
690
  messages,
664
691
  tools: ir.tools && ir.tools.length > 0 ? toOpenAITools(ir.tools) : void 0,
665
692
  response_format: ir.constraints?.structuredOutput ? { type: "json_object" } : void 0,
666
- reasoning_effort: hints.forceTerseOutput ? "low" : void 0
693
+ reasoning_effort: hints.forceTerseOutput ? "low" : void 0,
694
+ parallel_tool_calls: openaiParallelToolCalls
667
695
  },
668
696
  diagnostics: {
669
697
  cacheableTokens: 0,
@@ -740,177 +768,6 @@ function setNestedField(obj, path, value) {
740
768
  cursor[parts[parts.length - 1]] = value;
741
769
  }
742
770
 
743
- // src/brain-query.ts
744
- var FRESH_SNAPSHOT = {
745
- data: null,
746
- expiresAt: 0,
747
- refreshing: false,
748
- warned: false
749
- };
750
- var snapshot = { ...FRESH_SNAPSHOT };
751
- var runtime;
752
- function configureBrainQuery(rt) {
753
- runtime = rt;
754
- snapshot = { ...FRESH_SNAPSHOT };
755
- }
756
- function createBrainQueryCache(opts) {
757
- return () => {
758
- const rt = runtime;
759
- if (!rt || !rt.enabledTables.has(opts.table)) {
760
- return opts.bundledFallback();
761
- }
762
- const now = Date.now();
763
- const stale = snapshot.expiresAt <= now;
764
- if (stale && !snapshot.refreshing) {
765
- snapshot.refreshing = true;
766
- void asyncRefresh(rt);
767
- }
768
- if (snapshot.data) {
769
- const rows = snapshot.data[opts.table];
770
- if (Array.isArray(rows) && rows.length > 0) {
771
- try {
772
- return opts.mapRows(rows);
773
- } catch {
774
- return opts.bundledFallback();
775
- }
776
- }
777
- }
778
- return opts.bundledFallback();
779
- };
780
- }
781
- var pendingRefresh;
782
- async function asyncRefresh(rt) {
783
- const promise = doRefresh(rt);
784
- pendingRefresh = promise;
785
- try {
786
- await promise;
787
- } finally {
788
- if (pendingRefresh === promise) pendingRefresh = void 0;
789
- }
790
- }
791
- var DEFAULT_CONFIG_URL = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/config";
792
- async function doRefresh(rt) {
793
- const url = rt.configEndpoint ?? DEFAULT_CONFIG_URL;
794
- try {
795
- const res = await rt.fetchImpl(url, { method: "GET" });
796
- if (!res.ok) {
797
- throw new Error(`brain-query ${res.status}: ${res.statusText}`);
798
- }
799
- const body = await res.json();
800
- if (runtime !== rt) return;
801
- snapshot = {
802
- data: body,
803
- expiresAt: Date.now() + rt.ttlMs,
804
- refreshing: false,
805
- warned: snapshot.warned
806
- };
807
- } catch (err) {
808
- if (runtime !== rt) return;
809
- snapshot.refreshing = false;
810
- snapshot.expiresAt = Date.now() + rt.ttlMs;
811
- if (!snapshot.warned) {
812
- snapshot.warned = true;
813
- (rt.onError ?? defaultOnError)(err);
814
- }
815
- }
816
- }
817
- function defaultOnError(err) {
818
- console.warn("[kgauto] brain-query failed (using bundled fallback):", err);
819
- }
820
- function isBrainQueryActiveFor(table) {
821
- return runtime !== void 0 && runtime.enabledTables.has(table);
822
- }
823
- async function getPerAxisMetrics(opts) {
824
- const fetchFn = opts.fetch ?? fetch;
825
- const endpoint = opts.endpoint ?? runtime?.endpoint;
826
- if (!endpoint) return null;
827
- const windowDays = opts.windowDays ?? 30;
828
- const body = {
829
- p_app_id: opts.appId,
830
- p_archetype: opts.archetype,
831
- p_model: opts.model,
832
- p_window_days: windowDays,
833
- p_quality_floor: opts.qualityFloor ?? null
834
- };
835
- const headers = {
836
- Accept: "application/json",
837
- "Content-Type": "application/json",
838
- ...opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {}
839
- };
840
- try {
841
- const res = await fetchFn(`${endpoint}/rpc/get_per_axis_metrics`, {
842
- method: "POST",
843
- headers,
844
- body: JSON.stringify(body)
845
- });
846
- if (!res.ok) return null;
847
- const raw = await res.json();
848
- return mapPerAxisMetrics(raw, opts.appId, opts.archetype, opts.model, windowDays);
849
- } catch {
850
- return null;
851
- }
852
- }
853
- function mapPerAxisMetrics(raw, fallbackAppId, fallbackArchetype, fallbackModel, fallbackWindowDays) {
854
- if (raw === null || raw === void 0) return null;
855
- if (typeof raw !== "object") return null;
856
- const r = raw;
857
- if (Array.isArray(raw)) {
858
- if (raw.length === 0) return null;
859
- return mapPerAxisMetrics(raw[0], fallbackAppId, fallbackArchetype, fallbackModel, fallbackWindowDays);
860
- }
861
- const num = (v) => {
862
- if (v === null || v === void 0) return null;
863
- if (typeof v === "number") return Number.isFinite(v) ? v : null;
864
- if (typeof v === "string") {
865
- const n = Number(v);
866
- return Number.isFinite(n) ? n : null;
867
- }
868
- return null;
869
- };
870
- const int = (v) => {
871
- const n = num(v);
872
- return n === null ? 0 : Math.trunc(n);
873
- };
874
- const bool = (v) => {
875
- if (v === null || v === void 0) return null;
876
- if (typeof v === "boolean") return v;
877
- return null;
878
- };
879
- const str = (v, fallback) => typeof v === "string" ? v : fallback;
880
- const cost = r.cost_efficiency ?? {};
881
- const time = r.time_efficiency ?? {};
882
- const rel = r.reliability ?? {};
883
- return {
884
- appId: str(r.app_id, fallbackAppId),
885
- archetype: str(r.archetype, fallbackArchetype),
886
- model: str(r.model, fallbackModel),
887
- windowDays: num(r.window_days) ?? fallbackWindowDays,
888
- nRows: int(r.n_rows),
889
- nRowsClean: int(r.n_rows_clean),
890
- nQualityOutcomes: int(r.n_quality_outcomes),
891
- magicRate: num(r.magic_rate),
892
- qualityFloorMet: bool(r.quality_floor_met),
893
- costEfficiency: {
894
- avgCostUsd: num(cost.avg_cost_usd),
895
- avgCostUsdClean: num(cost.avg_cost_usd_clean),
896
- avgInputTokens: num(cost.avg_input_tokens),
897
- avgOutputTokens: num(cost.avg_output_tokens),
898
- inputTokenRatio: num(cost.input_token_ratio)
899
- },
900
- timeEfficiency: {
901
- avgLatencyMs: num(time.avg_latency_ms),
902
- avgTtftMs: num(time.avg_ttft_ms)
903
- },
904
- reliability: {
905
- successRate: num(rel.success_rate),
906
- successRateClean: num(rel.success_rate_clean),
907
- emptyRate: num(rel.empty_rate),
908
- emptyRateClean: num(rel.empty_rate_clean)
909
- },
910
- evidenceFreshnessDays: num(r.evidence_freshness_days)
911
- };
912
- }
913
-
914
771
  // src/archetype-perf-brain.ts
915
772
  function isPerfRow(x) {
916
773
  if (!x || typeof x !== "object") return false;
@@ -984,8 +841,19 @@ function runAdvisor(ir, result, profile, policy, phase2) {
984
841
  out.push(...detectModelStaleEvidence(ir, profile));
985
842
  out.push(...detectTierDown(ir, profile, phase2));
986
843
  }
844
+ if (!translatorClearedToolCallCliff(phase2)) {
845
+ out.push(...detectArchetypePerfFloorBreach(ir, profile));
846
+ }
987
847
  return out;
988
848
  }
849
+ function translatorClearedToolCallCliff(phase2) {
850
+ const rewrites = phase2?.sectionRewritesApplied;
851
+ if (!rewrites || rewrites.length === 0) return false;
852
+ for (const rw of rewrites) {
853
+ if (rw.kind === "tool_call_contract") return true;
854
+ }
855
+ return false;
856
+ }
989
857
  function detectCachingOff(ir, profile) {
990
858
  if (profile.provider !== "anthropic") return [];
991
859
  const totalChars = ir.sections.reduce((s, sec) => s + sec.text.length, 0);
@@ -1154,6 +1022,77 @@ function detectTierDown(ir, profile, phase2) {
1154
1022
  }
1155
1023
  ];
1156
1024
  }
1025
+ function detectArchetypePerfFloorBreach(ir, profile) {
1026
+ const compat = getModelCompatibility(profile.id, {
1027
+ archetype: ir.intent.archetype,
1028
+ toolOrchestration: ir.constraints?.toolOrchestration
1029
+ });
1030
+ if (compat.status === "compatible") return [];
1031
+ if (compat.status === "requires-adapter") {
1032
+ return [
1033
+ {
1034
+ level: "warn",
1035
+ code: "archetype-perf-floor-breach",
1036
+ message: `${profile.id} sits below the archetype floor for ${ir.intent.archetype} (score ${compat.archetypePerf}/10, floor ${6}). A known adapter would lift it: ${compat.adapter.parameter}=${compat.adapter.value}. ${compat.adapter.consequence}`,
1037
+ suggestion: `Pass \`ir.constraints.${compat.adapter.parameter} = '${compat.adapter.value}'\` for this call, OR pick a model whose archetypePerf for ${ir.intent.archetype} already clears the floor (call \`getModelCompatibility(modelId, { archetype: '${ir.intent.archetype}' })\` to check). Estimated post-adapter score: ${compat.archetypePerfWithAdapter}/10.`,
1038
+ recommendationType: "prompt-fix",
1039
+ suggestedAdaptation: compat.adapter,
1040
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
1041
+ }
1042
+ ];
1043
+ }
1044
+ return [
1045
+ {
1046
+ level: "critical",
1047
+ code: "archetype-perf-floor-breach",
1048
+ message: `${profile.id} sits below the archetype floor for ${ir.intent.archetype} (score ${compat.archetypePerf}/10, floor ${6}) and no known adapter would lift it. ${compat.reason}`,
1049
+ suggestion: `Swap to a model whose archetypePerf for ${ir.intent.archetype} clears the floor. Use \`getModelCompatibility(candidateId, { archetype: '${ir.intent.archetype}' })\` to vet candidates, or \`getDefaultFallbackChain({ archetype: '${ir.intent.archetype}', posture: 'open' })\` for a library-picked chain that respects the floor by construction.`,
1050
+ recommendationType: "model-swap",
1051
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
1052
+ }
1053
+ ];
1054
+ }
1055
+
1056
+ // src/translator.ts
1057
+ var TRANSLATOR_FLOOR = ARCHETYPE_FLOOR_DEFAULT;
1058
+ var RULE_SEQUENTIAL_TOOL_CLIFF = "sequential-tool-cliff-below-floor";
1059
+ var SEQUENTIAL_TOOL_PREAMBLE = "IMPORTANT: Use one tool call per response. Wait for the tool result before deciding the next tool. Do NOT batch tool calls in parallel.";
1060
+ function applySectionRewrites(args) {
1061
+ const { ir, profile, archetype } = args;
1062
+ if (!Array.isArray(ir.sections) || ir.sections.length === 0) {
1063
+ return { rewrittenIR: ir, rewrites: [] };
1064
+ }
1065
+ if (!profile.archetypePerf) {
1066
+ return { rewrittenIR: ir, rewrites: [] };
1067
+ }
1068
+ const archetypeScore = profile.archetypePerf[archetype];
1069
+ const cliffFires = typeof archetypeScore === "number" && archetypeScore < TRANSLATOR_FLOOR;
1070
+ if (!cliffFires) {
1071
+ return { rewrittenIR: ir, rewrites: [] };
1072
+ }
1073
+ const rewrites = [];
1074
+ const newSections = ir.sections.map((section) => {
1075
+ if (section.kind !== "tool_call_contract") return section;
1076
+ const originalText = section.text;
1077
+ const transformedText = `${SEQUENTIAL_TOOL_PREAMBLE}
1078
+
1079
+ ${originalText}`;
1080
+ rewrites.push({
1081
+ sectionId: section.id,
1082
+ kind: "tool_call_contract",
1083
+ rule: RULE_SEQUENTIAL_TOOL_CLIFF,
1084
+ originalText,
1085
+ transformedText,
1086
+ wireOverrides: { parallelToolCalls: false }
1087
+ });
1088
+ return { ...section, text: transformedText };
1089
+ });
1090
+ if (rewrites.length === 0) {
1091
+ return { rewrittenIR: ir, rewrites: [] };
1092
+ }
1093
+ const rewrittenIR = { ...ir, sections: newSections };
1094
+ return { rewrittenIR, rewrites };
1095
+ }
1157
1096
 
1158
1097
  // src/compile.ts
1159
1098
  var counter = 0;
@@ -1198,9 +1137,33 @@ function compile(ir, opts = {}) {
1198
1137
  const cliffs = passApplyCliffs(workingIR, profile, inputTokens);
1199
1138
  workingIR = cliffs.value.ir;
1200
1139
  accumulatedMutations.push(...cliffs.mutations);
1140
+ const translated = applySectionRewrites({
1141
+ ir: workingIR,
1142
+ profile,
1143
+ archetype: ir.intent.archetype
1144
+ });
1145
+ workingIR = translated.rewrittenIR;
1146
+ const sectionRewritesApplied = translated.rewrites;
1147
+ let wireOverrides;
1148
+ for (const rw of sectionRewritesApplied) {
1149
+ if (!rw.wireOverrides) continue;
1150
+ if (!wireOverrides) wireOverrides = {};
1151
+ if (rw.wireOverrides.parallelToolCalls !== void 0) {
1152
+ wireOverrides.parallelToolCalls = rw.wireOverrides.parallelToolCalls;
1153
+ }
1154
+ }
1155
+ for (const rw of sectionRewritesApplied) {
1156
+ accumulatedMutations.push({
1157
+ id: `translator:${rw.rule}:${rw.sectionId}`,
1158
+ source: "translator",
1159
+ passName: "translator",
1160
+ description: `Rewrote section "${rw.sectionId}" (kind=${rw.kind}) via rule "${rw.rule}".`
1161
+ });
1162
+ }
1201
1163
  const lowered = lower(workingIR, profile, {
1202
1164
  forceThinkingZero: cliffs.value.loweringHints.forceThinkingZero,
1203
- forceTerseOutput: cliffs.value.loweringHints.forceTerseOutput
1165
+ forceTerseOutput: cliffs.value.loweringHints.forceTerseOutput,
1166
+ wireOverrides
1204
1167
  });
1205
1168
  validateFinalFit(workingIR, profile, inputTokens);
1206
1169
  const handle = makeHandle();
@@ -1248,7 +1211,13 @@ function compile(ir, opts = {}) {
1248
1211
  opts.policy,
1249
1212
  {
1250
1213
  fallbackChain,
1251
- profileResolver: phase2ProfileResolver
1214
+ profileResolver: phase2ProfileResolver,
1215
+ // alpha.29 — feed translator rewrites to the advisor so the
1216
+ // `archetype-perf-floor-breach` rule can suppress when the translator
1217
+ // already cleared the cliff for the same archetype. Without this,
1218
+ // both the rewrite AND the advisory fire — noisy, and the advisory
1219
+ // would mislead consumers into thinking the cliff is unaddressed.
1220
+ sectionRewritesApplied
1252
1221
  }
1253
1222
  );
1254
1223
  return {
@@ -1261,7 +1230,9 @@ function compile(ir, opts = {}) {
1261
1230
  mutationsApplied: accumulatedMutations,
1262
1231
  fallbackChain,
1263
1232
  advisories,
1264
- diagnostics
1233
+ diagnostics,
1234
+ sectionRewritesApplied,
1235
+ wireOverrides
1265
1236
  };
1266
1237
  }
1267
1238
  function validateIR(ir) {
@@ -1414,6 +1385,9 @@ function registerCompile(appId, archetype, ir, result) {
1414
1385
  tokens
1415
1386
  );
1416
1387
  const shapeKey = `${shape.contextBucket}-${shape.toolCountBucket}-${shape.historyDepth}-${shape.outputMode}`;
1388
+ const toolsCount = result.diagnostics.toolsKept;
1389
+ const historyDepth = Array.isArray(ir.history) ? ir.history.length : 0;
1390
+ const systemPromptChars = estimateSystemPromptChars(ir.sections);
1417
1391
  compileRegistry.set(result.handle, {
1418
1392
  appId,
1419
1393
  archetype,
@@ -1427,9 +1401,28 @@ function registerCompile(appId, archetype, ir, result) {
1427
1401
  historyCacheableTokens: result.diagnostics.historyCacheableTokens,
1428
1402
  historyTokensTotal: result.diagnostics.historyTokensTotal,
1429
1403
  // alpha.20 E3: capture consumer's declared mode for the brain payload.
1430
- toolOrchestration: result.diagnostics.toolOrchestration
1404
+ toolOrchestration: result.diagnostics.toolOrchestration,
1405
+ // alpha.28: shape fields for Glass-Box renderer.
1406
+ toolsCount,
1407
+ historyDepth,
1408
+ systemPromptChars,
1409
+ // alpha.29: translator activity — persisted on the brain row so
1410
+ // cross-app aggregates can answer "Sonnet narration rule fired N times,
1411
+ // outcome quality lifted to M."
1412
+ sectionRewritesApplied: result.sectionRewritesApplied
1431
1413
  });
1432
1414
  }
1415
+ function estimateSystemPromptChars(sections) {
1416
+ if (!Array.isArray(sections) || sections.length === 0) return void 0;
1417
+ let total = 0;
1418
+ for (const s of sections) {
1419
+ if (s && typeof s === "object") {
1420
+ const content = s.content;
1421
+ if (typeof content === "string") total += content.length;
1422
+ }
1423
+ }
1424
+ return total > 0 ? total : void 0;
1425
+ }
1433
1426
  async function record(input) {
1434
1427
  const reg = compileRegistry.get(input.handle);
1435
1428
  if (reg) compileRegistry.delete(input.handle);
@@ -1466,7 +1459,7 @@ async function record(input) {
1466
1459
  }
1467
1460
  outcomeId = await tryExtractOutcomeId(res);
1468
1461
  } catch (err) {
1469
- (config.onError ?? defaultOnError2)(err);
1462
+ (config.onError ?? defaultOnError)(err);
1470
1463
  return;
1471
1464
  }
1472
1465
  const advisories = input.advisories;
@@ -1488,7 +1481,7 @@ async function record(input) {
1488
1481
  throw new Error(`brain advisories ${res.status}: ${text}`);
1489
1482
  }
1490
1483
  } catch (err) {
1491
- (config.onError ?? defaultOnError2)(err);
1484
+ (config.onError ?? defaultOnError)(err);
1492
1485
  }
1493
1486
  };
1494
1487
  if (config.sync) {
@@ -1497,7 +1490,7 @@ async function record(input) {
1497
1490
  void send();
1498
1491
  }
1499
1492
  }
1500
- function defaultOnError2(err) {
1493
+ function defaultOnError(err) {
1501
1494
  console.warn("[kgauto] brain record failed:", err);
1502
1495
  }
1503
1496
  function buildPayload(input, reg) {
@@ -1507,6 +1500,8 @@ function buildPayload(input, reg) {
1507
1500
  const mutationsApplied = input.mutationsApplied ?? reg?.mutationsApplied ?? [];
1508
1501
  const costModel = actual;
1509
1502
  const costUsdActual = costModel ? computeCostUsd(costModel, input.tokensIn, input.tokensOut) : void 0;
1503
+ const fellOverFrom = input.fellOverFrom ?? requested;
1504
+ const fallbackReason = fellOverFrom ? input.fallbackReason : void 0;
1510
1505
  return {
1511
1506
  handle: input.handle,
1512
1507
  app_id: reg?.appId,
@@ -1541,7 +1536,20 @@ function buildPayload(input, reg) {
1541
1536
  // the brain can measure per-mode model perf separately (DeepSeek in
1542
1537
  // sequential vs parallel mode is two different stories — L-040).
1543
1538
  // Null when consumer hadn't adopted the constraint yet.
1544
- tool_orchestration: reg?.toolOrchestration ?? null
1539
+ tool_orchestration: reg?.toolOrchestration ?? null,
1540
+ // alpha.28 — Glass-Box renderer substrate (migration 018). All optional;
1541
+ // omitted-undefined PostgREST inserts store NULL → renderer renders "—".
1542
+ finish_reason: input.finishReason,
1543
+ total_ms: input.totalMs ?? input.latencyMs,
1544
+ tools_count: input.toolsCount ?? reg?.toolsCount,
1545
+ history_depth: input.historyDepth ?? reg?.historyDepth,
1546
+ system_prompt_chars: input.systemPromptChars ?? reg?.systemPromptChars,
1547
+ fell_over_from: fellOverFrom,
1548
+ fallback_reason: fallbackReason,
1549
+ // alpha.29 — translator activity (migration 019). Send NULL when no
1550
+ // rewrites fired so the brain's "did the translator do anything?"
1551
+ // queries can use `IS NOT NULL` cleanly.
1552
+ section_rewrites_applied: reg?.sectionRewritesApplied && reg.sectionRewritesApplied.length > 0 ? reg.sectionRewritesApplied : null
1545
1553
  };
1546
1554
  }
1547
1555
  function computeCostUsd(modelId, tokensIn, tokensOut) {
@@ -1614,12 +1622,12 @@ async function recordOutcome(input) {
1614
1622
  if (!res.ok) {
1615
1623
  const text = await res.text().catch(() => "<no body>");
1616
1624
  const err = new Error(`brain ${res.status}: ${text}`);
1617
- (config.onError ?? defaultOnError2)(err);
1625
+ (config.onError ?? defaultOnError)(err);
1618
1626
  return { ok: false, reason: "persistence_failed" };
1619
1627
  }
1620
1628
  return { ok: true };
1621
1629
  } catch (err) {
1622
- (config.onError ?? defaultOnError2)(err);
1630
+ (config.onError ?? defaultOnError)(err);
1623
1631
  return { ok: false, reason: "persistence_failed" };
1624
1632
  }
1625
1633
  };
@@ -1644,67 +1652,6 @@ var CallError = class extends Error {
1644
1652
  }
1645
1653
  };
1646
1654
 
1647
- // src/env.ts
1648
- var SUPPORTED_PROVIDERS = Object.freeze([
1649
- "anthropic",
1650
- "google",
1651
- "openai",
1652
- "deepseek"
1653
- ]);
1654
- function isSupportedProvider(p) {
1655
- return SUPPORTED_PROVIDERS.includes(p);
1656
- }
1657
- var PROVIDER_ENV_KEYS = Object.freeze({
1658
- anthropic: Object.freeze(["ANTHROPIC_API_KEY"]),
1659
- google: Object.freeze([
1660
- "GOOGLE_API_KEY",
1661
- "GEMINI_API_KEY",
1662
- "GOOGLE_GENERATIVE_AI_API_KEY"
1663
- ]),
1664
- openai: Object.freeze(["OPENAI_API_KEY"]),
1665
- deepseek: Object.freeze(["DEEPSEEK_API_KEY"])
1666
- });
1667
- function defaultEnv() {
1668
- return typeof process !== "undefined" && process.env ? process.env : {};
1669
- }
1670
- function readKeyValue(raw) {
1671
- if (raw === void 0) return void 0;
1672
- const trimmed = raw.trim();
1673
- return trimmed.length > 0 ? trimmed : void 0;
1674
- }
1675
- function resolveProviderKey(provider, opts = {}) {
1676
- if (!isSupportedProvider(provider)) return void 0;
1677
- const explicit = readKeyValue(opts.apiKeys?.[provider]);
1678
- if (explicit) return explicit;
1679
- const env = opts.envSource ?? defaultEnv();
1680
- for (const name of PROVIDER_ENV_KEYS[provider]) {
1681
- const v = readKeyValue(env[name]);
1682
- if (v) return v;
1683
- }
1684
- return void 0;
1685
- }
1686
- function isProviderReachable(provider, opts = {}) {
1687
- return resolveProviderKey(provider, opts) !== void 0;
1688
- }
1689
- function isModelReachable(modelId, opts = {}) {
1690
- const profile = tryGetProfile(modelId);
1691
- if (!profile) return false;
1692
- return isProviderReachable(profile.provider, opts);
1693
- }
1694
- function getReachabilityDiagnostic(opts = {}) {
1695
- const env = opts.envSource ?? defaultEnv();
1696
- const out = {};
1697
- for (const provider of SUPPORTED_PROVIDERS) {
1698
- if (readKeyValue(opts.apiKeys?.[provider])) {
1699
- out[provider] = { reachable: true, via: "apiKeys" };
1700
- continue;
1701
- }
1702
- const envKeyFound = PROVIDER_ENV_KEYS[provider].find((name) => readKeyValue(env[name]));
1703
- out[provider] = envKeyFound ? { reachable: true, via: "env", envKeyFound } : { reachable: false, via: null };
1704
- }
1705
- return out;
1706
- }
1707
-
1708
1655
  // src/execute.ts
1709
1656
  var ANTHROPIC_URL = "https://api.anthropic.com/v1/messages";
1710
1657
  var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
@@ -1923,344 +1870,6 @@ function tryParseJson(s) {
1923
1870
  }
1924
1871
  }
1925
1872
 
1926
- // src/chains-brain.ts
1927
- function isChainsRow(x) {
1928
- if (!x || typeof x !== "object") return false;
1929
- const r = x;
1930
- return typeof r.archetype === "string" && typeof r.tier === "number" && typeof r.model_id === "string";
1931
- }
1932
- function mapRowsToChains(rows) {
1933
- const grouped = /* @__PURE__ */ new Map();
1934
- for (const row of rows) {
1935
- if (!isChainsRow(row)) continue;
1936
- const list = grouped.get(row.archetype) ?? [];
1937
- list.push(row);
1938
- grouped.set(row.archetype, list);
1939
- }
1940
- const out = {};
1941
- for (const [archetype, group] of grouped.entries()) {
1942
- group.sort((a, b) => a.tier - b.tier);
1943
- out[archetype] = group.map((r) => r.model_id);
1944
- }
1945
- const bundled = getAllStarterChains();
1946
- for (const archetype of Object.keys(bundled)) {
1947
- if (!out[archetype]) out[archetype] = bundled[archetype];
1948
- }
1949
- return out;
1950
- }
1951
- var loadChainsFromBrain = createBrainQueryCache({
1952
- table: "kgauto_chains",
1953
- mapRows: mapRowsToChains,
1954
- bundledFallback: getAllStarterChains
1955
- });
1956
-
1957
- // src/fallback.ts
1958
- var STARTER_CHAINS_GROUNDED = {
1959
- // Reasoning floor — never degrade. Walk UP on 429 to Opus → cross-provider.
1960
- critique: [
1961
- { id: "claude-opus-4-7", grounding: "judgment", reason: "Highest reasoning bar, no degradation tier \u2014 engineer pick, awaiting measured backing" },
1962
- { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Same-provider walk-down from Opus on 429" },
1963
- { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor in similar quality bracket" },
1964
- { id: "gpt-5.5", grounding: "judgment", reason: "alpha.16: third-provider frontier-tier floor (archetypePerf=9)" }
1965
- ],
1966
- // Reasoning matters — Sonnet primary; walk UP to Opus on 429.
1967
- plan: [
1968
- { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Reasoning + cost balance \u2014 engineer pick" },
1969
- { id: "claude-opus-4-7", grounding: "judgment", reason: 'Same-provider walk-UP on 429 (rare exception to "always cheaper")' },
1970
- { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor" },
1971
- { id: "deepseek-v4-pro", grounding: "judgment", reason: "Tier 3 cost floor \u2014 no brain evidence yet" }
1972
- ],
1973
- // Quality + cost match.
1974
- generate: [
1975
- { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Quality + cost match \u2014 engineer pick" },
1976
- { id: "claude-haiku-4-5", grounding: "judgment", reason: "Same-provider step-down" },
1977
- { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor" },
1978
- { id: "gpt-5.4-mini", grounding: "judgment", reason: "alpha.16: third-provider tail (archetypePerf=7) \u2014 closes mono-Anthropic gap" }
1979
- ],
1980
- // ask::sonnet — STARTER_CHAINS calls this "Quality + cost match" but
1981
- // tt-intel s78 prod data showed 27% empty rate. Labeled 'judgment' until
1982
- // evidence either validates or refutes the placement.
1983
- ask: [
1984
- { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Quality + cost match \u2014 engineer pick. NOTE: tt-intel s78 prod showed 27% empty rate; placement awaits measurement validation" },
1985
- { id: "claude-haiku-4-5", grounding: "judgment", reason: "Same-provider step-down" },
1986
- { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor" },
1987
- { id: "gpt-5.4-mini", grounding: "judgment", reason: "alpha.16: third-provider tail (archetypePerf=7)" }
1988
- ],
1989
- // Structured-output archetype — Flash skipped (alpha.8 MAX_TOKENS cliff,
1990
- // capability-fact); DeepSeek skipped (no brain evidence).
1991
- extract: [
1992
- { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Reliable structured-output anchor \u2014 engineer pick" },
1993
- { id: "claude-haiku-4-5", grounding: "judgment", reason: "Same-provider step-down with native structured output" },
1994
- { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor with structured-output support" },
1995
- { id: "gpt-5.4", grounding: "capability-fact", reason: "alpha.16: third-provider floor \u2014 native structured-output capability (archetypePerf=8)" }
1996
- ],
1997
- // Forgiving archetype — Sonnet primary but Flash safely floors it.
1998
- transform: [
1999
- { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Quality anchor \u2014 engineer pick" },
2000
- { id: "claude-haiku-4-5", grounding: "judgment", reason: "Same-provider step-down" },
2001
- { id: "gemini-2.5-pro", grounding: "judgment", reason: "Cross-provider anchor" },
2002
- { id: "gemini-2.5-flash", grounding: "judgment", reason: "Cost floor \u2014 forgiving archetype tolerates Flash" }
2003
- ],
2004
- // Parallel-tool throughput champion — Flash leads on the L-040 cliff
2005
- // (capability-fact: Flash 15-75 parallel calls/step vs DeepSeek 7-8).
2006
- hunt: [
2007
- { id: "gemini-2.5-flash", grounding: "capability-fact", reason: "L-040 parallel-tool throughput champion (15-75 calls/step)" },
2008
- { id: "gemini-2.5-pro", grounding: "capability-fact", reason: "Cross-provider tier 1 with strong parallel-tool support" },
2009
- { id: "claude-sonnet-4-6", grounding: "judgment", reason: "Quality safety net for blocked-Flash case" },
2010
- { id: "claude-haiku-4-5", grounding: "judgment", reason: "Reduced tool budget \u2014 cliff at 16 fires" }
2011
- ],
2012
- // Cost-sensitive + tolerant. DeepSeek brain-evidence tier 1.
2013
- summarize: [
2014
- { id: "gemini-2.5-flash", grounding: "judgment", reason: "Cost-sensitive primary \u2014 engineer pick" },
2015
- { id: "deepseek-v4-flash", grounding: "measured", reason: "Brain-validated tier 1 for cost-sensitive summarize workloads", n: 169 },
2016
- { id: "claude-haiku-4-5", grounding: "judgment", reason: "Quality safety net" },
2017
- { id: "gemini-2.5-flash-lite", grounding: "judgment", reason: "Emergency floor \u2014 onboarded s22, no brain evidence yet" }
2018
- ],
2019
- // Brain-validated DeepSeek tier 1 (169 rows, 0% empty rate).
2020
- classify: [
2021
- { id: "gemini-2.5-flash", grounding: "judgment", reason: "Cost-sensitive primary \u2014 engineer pick" },
2022
- { id: "deepseek-v4-flash", grounding: "measured", reason: "Brain-validated tier 1 (169 rows, 0% empty rate)", n: 169 },
2023
- { id: "claude-haiku-4-5", grounding: "judgment", reason: "Quality safety net" },
2024
- { id: "gemini-2.5-flash-lite", grounding: "judgment", reason: "Cache-discount 10\xD7 floor for repeat-prompt workloads" }
2025
- ]
2026
- };
2027
- var STARTER_CHAINS = (() => {
2028
- const out = {};
2029
- for (const [archetype, entries] of Object.entries(STARTER_CHAINS_GROUNDED)) {
2030
- out[archetype] = entries.map((e) => e.id);
2031
- }
2032
- return out;
2033
- })();
2034
- var STARTER_CHAINS_BY_MODE_GROUNDED = {
2035
- hunt: {
2036
- sequential: [
2037
- {
2038
- id: "deepseek-v4-pro",
2039
- grounding: "judgment",
2040
- reason: "alpha.20 E3: cheap + good reasoning at single-step granularity; L-040 cliff silenced when sequential \u2014 hypothesis not yet measured"
2041
- },
2042
- {
2043
- id: "deepseek-v4-flash",
2044
- grounding: "judgment",
2045
- reason: "Cheapest viable; sibling-provider fallback"
2046
- },
2047
- {
2048
- id: "claude-sonnet-4-6",
2049
- grounding: "judgment",
2050
- reason: "Cross-provider safety net \u2014 Sonnet handles sequential agentic loops cleanly"
2051
- },
2052
- {
2053
- id: "gemini-2.5-pro",
2054
- grounding: "judgment",
2055
- reason: "Third-provider tail when no DeepSeek key reachable"
2056
- }
2057
- ]
2058
- }
2059
- };
2060
- var STARTER_CHAINS_BY_MODE = (() => {
2061
- const out = {};
2062
- for (const [archetype, modes] of Object.entries(STARTER_CHAINS_BY_MODE_GROUNDED)) {
2063
- if (modes?.sequential) {
2064
- out[archetype] = {
2065
- sequential: modes.sequential.map((e) => e.id)
2066
- };
2067
- }
2068
- }
2069
- return out;
2070
- })();
2071
- function resolveStarterForMode(archetype, toolOrchestration, allChains) {
2072
- if (toolOrchestration === "sequential") {
2073
- const overlay = STARTER_CHAINS_BY_MODE[archetype]?.sequential;
2074
- if (overlay) return [...overlay];
2075
- }
2076
- return allChains[archetype];
2077
- }
2078
- function getDefaultFallbackChain(opts) {
2079
- const { archetype, primary, maxDepth = 3, policy, reachability, toolOrchestration } = opts;
2080
- if (maxDepth < 1) {
2081
- throw new Error(
2082
- `getDefaultFallbackChain: maxDepth must be >= 1, got ${maxDepth}`
2083
- );
2084
- }
2085
- const allChains = loadChainsFromBrain();
2086
- const starter = resolveStarterForMode(archetype, toolOrchestration, allChains);
2087
- if (!starter) {
2088
- throw new Error(
2089
- `getDefaultFallbackChain: unknown archetype "${archetype}". Known: ${Object.keys(allChains).join(", ")}`
2090
- );
2091
- }
2092
- let chain;
2093
- if (primary) {
2094
- chain = [primary, ...starter.filter((id) => id !== primary)];
2095
- } else {
2096
- chain = [...starter];
2097
- }
2098
- if (policy?.blockedModels && policy.blockedModels.length > 0) {
2099
- const blocked = new Set(policy.blockedModels);
2100
- chain = chain.filter((id) => !blocked.has(id));
2101
- }
2102
- const seen = /* @__PURE__ */ new Set();
2103
- const deduped = [];
2104
- for (const id of chain) {
2105
- if (!seen.has(id)) {
2106
- seen.add(id);
2107
- deduped.push(id);
2108
- }
2109
- }
2110
- let filtered = deduped;
2111
- if (reachability) {
2112
- filtered = deduped.filter((id) => isModelReachable(id, reachability));
2113
- }
2114
- return filtered.slice(0, maxDepth);
2115
- }
2116
- function getStarterChain(archetype) {
2117
- const chain = STARTER_CHAINS[archetype];
2118
- if (!chain) {
2119
- throw new Error(
2120
- `getStarterChain: unknown archetype "${archetype}"`
2121
- );
2122
- }
2123
- return [...chain];
2124
- }
2125
- function getAllStarterChains() {
2126
- const out = {};
2127
- for (const [archetype, chain] of Object.entries(STARTER_CHAINS)) {
2128
- out[archetype] = [...chain];
2129
- }
2130
- return out;
2131
- }
2132
- function getSequentialStarterChain(archetype) {
2133
- const overlay = STARTER_CHAINS_BY_MODE[archetype]?.sequential;
2134
- return overlay ? [...overlay] : void 0;
2135
- }
2136
- function copyEntry(e) {
2137
- const out = { id: e.id, grounding: e.grounding };
2138
- if (e.reason !== void 0) out.reason = e.reason;
2139
- if (e.n !== void 0) out.n = e.n;
2140
- return out;
2141
- }
2142
- function lookupStaticEntry(id, archetype) {
2143
- const archetypeEntries = STARTER_CHAINS_GROUNDED[archetype];
2144
- if (archetypeEntries) {
2145
- const hit = archetypeEntries.find((e) => e.id === id);
2146
- if (hit) return hit;
2147
- }
2148
- const seqOverlay = STARTER_CHAINS_BY_MODE_GROUNDED[archetype]?.sequential;
2149
- if (seqOverlay) {
2150
- const hit = seqOverlay.find((e) => e.id === id);
2151
- if (hit) return hit;
2152
- }
2153
- return void 0;
2154
- }
2155
- function resolveGroundedChainForArchetype(archetype, toolOrchestration) {
2156
- if (toolOrchestration === "sequential") {
2157
- const overlay = STARTER_CHAINS_BY_MODE_GROUNDED[archetype]?.sequential;
2158
- if (overlay) return overlay.map(copyEntry);
2159
- }
2160
- const allChains = loadChainsFromBrain();
2161
- const ids = allChains[archetype];
2162
- if (!ids) return void 0;
2163
- return ids.map((id) => {
2164
- const known = lookupStaticEntry(id, archetype);
2165
- if (known) return copyEntry(known);
2166
- return { id, grounding: "judgment" };
2167
- });
2168
- }
2169
- function getDefaultFallbackChainWithGrounding(opts) {
2170
- const {
2171
- archetype,
2172
- primary,
2173
- maxDepth = 3,
2174
- policy,
2175
- reachability,
2176
- toolOrchestration
2177
- } = opts;
2178
- if (maxDepth < 1) {
2179
- throw new Error(
2180
- `getDefaultFallbackChainWithGrounding: maxDepth must be >= 1, got ${maxDepth}`
2181
- );
2182
- }
2183
- const starter = resolveGroundedChainForArchetype(archetype, toolOrchestration);
2184
- if (!starter) {
2185
- throw new Error(
2186
- `getDefaultFallbackChainWithGrounding: unknown archetype "${archetype}". Known: ${Object.keys(STARTER_CHAINS_GROUNDED).join(", ")}`
2187
- );
2188
- }
2189
- let chain;
2190
- if (primary) {
2191
- const primaryEntry = (() => {
2192
- const inStarter = starter.find((e) => e.id === primary);
2193
- if (inStarter) return copyEntry(inStarter);
2194
- const knownAnywhere = lookupStaticEntry(primary, archetype);
2195
- if (knownAnywhere) return { ...copyEntry(knownAnywhere), id: primary };
2196
- return { id: primary, grounding: "judgment" };
2197
- })();
2198
- chain = [primaryEntry, ...starter.filter((e) => e.id !== primary)];
2199
- } else {
2200
- chain = [...starter];
2201
- }
2202
- if (policy?.blockedModels && policy.blockedModels.length > 0) {
2203
- const blocked = new Set(policy.blockedModels);
2204
- chain = chain.filter((e) => !blocked.has(e.id));
2205
- }
2206
- const seen = /* @__PURE__ */ new Set();
2207
- const deduped = [];
2208
- for (const e of chain) {
2209
- if (!seen.has(e.id)) {
2210
- seen.add(e.id);
2211
- deduped.push(e);
2212
- }
2213
- }
2214
- let filtered = deduped;
2215
- if (reachability) {
2216
- filtered = deduped.filter((e) => isModelReachable(e.id, reachability));
2217
- }
2218
- return filtered.slice(0, maxDepth);
2219
- }
2220
- function getStarterChainWithGrounding(archetype) {
2221
- const entries = STARTER_CHAINS_GROUNDED[archetype];
2222
- if (!entries) {
2223
- throw new Error(
2224
- `getStarterChainWithGrounding: unknown archetype "${archetype}"`
2225
- );
2226
- }
2227
- return entries.map(copyEntry);
2228
- }
2229
- function getAllStarterChainsWithGrounding() {
2230
- const out = {};
2231
- for (const [archetype, entries] of Object.entries(STARTER_CHAINS_GROUNDED)) {
2232
- out[archetype] = entries.map(copyEntry);
2233
- }
2234
- return out;
2235
- }
2236
- function getSequentialStarterChainWithGrounding(archetype) {
2237
- const overlay = STARTER_CHAINS_BY_MODE_GROUNDED[archetype]?.sequential;
2238
- return overlay ? overlay.map(copyEntry) : void 0;
2239
- }
2240
- function ensureCrossProviderTail(opts) {
2241
- const { chain, archetype, apiKeys, envSource } = opts;
2242
- if (chain.length < 1) return { chain };
2243
- const providers = /* @__PURE__ */ new Set();
2244
- for (const t of chain) {
2245
- const p = tryGetProfile(t);
2246
- if (p) providers.add(p.provider);
2247
- }
2248
- if (providers.size >= 2) return { chain };
2249
- const existingProvider = providers.values().next().value;
2250
- if (!existingProvider) return { chain };
2251
- const allChains = loadChainsFromBrain();
2252
- const fullChain = allChains[archetype];
2253
- if (!fullChain) return { chain };
2254
- for (const candidate of fullChain) {
2255
- if (chain.includes(candidate)) continue;
2256
- const cp = tryGetProfile(candidate);
2257
- if (!cp || cp.provider === existingProvider) continue;
2258
- if (!isModelReachable(candidate, { apiKeys, envSource })) continue;
2259
- return { chain: [...chain, candidate], appended: candidate };
2260
- }
2261
- return { chain };
2262
- }
2263
-
2264
1873
  // src/call.ts
2265
1874
  async function call(ir, opts = {}) {
2266
1875
  const traceId = generateTraceId();
@@ -2438,6 +2047,8 @@ async function call(ir, opts = {}) {
2438
2047
  latencyMs: latencyMs2
2439
2048
  })
2440
2049
  );
2050
+ const fellOver = targetModel !== initial.target;
2051
+ const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
2441
2052
  await record({
2442
2053
  handle: initial.handle,
2443
2054
  tokensIn: validated.response.tokens.input,
@@ -2451,10 +2062,18 @@ async function call(ir, opts = {}) {
2451
2062
  promptPreview: extractPromptPreview(ir),
2452
2063
  responsePreview: validated.response.text.slice(0, 200),
2453
2064
  cacheReadInputTokens: validated.response.tokens.cached,
2454
- cacheCreationInputTokens: validated.response.tokens.cacheCreated
2065
+ cacheCreationInputTokens: validated.response.tokens.cacheCreated,
2066
+ // alpha.28 — Glass-Box renderer substrate (migration 018). call()
2067
+ // owns the lifecycle so it has direct visibility into finishReason
2068
+ // (from the normalized provider response), totalMs (mirrors latencyMs
2069
+ // for non-streaming; future streaming variant may diverge), and the
2070
+ // fell-over-from / fallback-reason pair (already computed above for
2071
+ // the CallResult return shape).
2072
+ finishReason: validated.response.finishReason,
2073
+ totalMs: latencyMs2,
2074
+ fellOverFrom: fellOver ? initial.target : void 0,
2075
+ fallbackReason
2455
2076
  });
2456
- const fellOver = targetModel !== initial.target;
2457
- const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
2458
2077
  if (fellOver) {
2459
2078
  const firstFailed = attempts.find((a) => a.status !== "success");
2460
2079
  if (firstFailed) {
@@ -2685,6 +2304,278 @@ function clamp(n) {
2685
2304
  return Math.max(0, Math.min(1, n));
2686
2305
  }
2687
2306
 
2307
+ // src/advisories-api.ts
2308
+ var SEVERITY_SET = /* @__PURE__ */ new Set(["info", "warn", "critical"]);
2309
+ var STATUS_SET = /* @__PURE__ */ new Set(["open", "snoozed", "resolved"]);
2310
+ var RESOLUTION_SOURCE_SET = /* @__PURE__ */ new Set([
2311
+ "auto",
2312
+ "consumer-marked",
2313
+ "declined"
2314
+ ]);
2315
+ function asString(v) {
2316
+ return typeof v === "string" && v.length > 0 ? v : void 0;
2317
+ }
2318
+ function asSeverity(v) {
2319
+ if (typeof v === "string" && SEVERITY_SET.has(v)) {
2320
+ return v;
2321
+ }
2322
+ return "info";
2323
+ }
2324
+ function asStatus(v) {
2325
+ if (typeof v === "string" && STATUS_SET.has(v)) {
2326
+ return v;
2327
+ }
2328
+ return "open";
2329
+ }
2330
+ function asResolutionSource(v) {
2331
+ if (typeof v === "string" && RESOLUTION_SOURCE_SET.has(v)) {
2332
+ return v;
2333
+ }
2334
+ return void 0;
2335
+ }
2336
+ function rowToAdvisory(row) {
2337
+ const archetype = asString(row.applies_to_archetype);
2338
+ const model = asString(row.applies_to_model);
2339
+ const docsLink = asString(row.docs_url);
2340
+ const suggestion = asString(row.suggestion);
2341
+ let suggestedFix = null;
2342
+ if (docsLink || suggestion) {
2343
+ suggestedFix = { type: "manual" };
2344
+ if (docsLink) suggestedFix.docsLink = docsLink;
2345
+ if (suggestion) suggestedFix.before = suggestion;
2346
+ }
2347
+ const out = {
2348
+ id: typeof row.id === "string" ? row.id : "",
2349
+ rule: typeof row.rule === "string" ? row.rule : "",
2350
+ severity: asSeverity(row.severity),
2351
+ openedAt: typeof row.opened_at === "string" ? row.opened_at : "",
2352
+ lastObservedAt: typeof row.last_observed_at === "string" ? row.last_observed_at : "",
2353
+ observationCount: typeof row.observation_count === "number" ? row.observation_count : 0,
2354
+ appliesTo: {
2355
+ ...archetype ? { archetype } : {},
2356
+ ...model ? { model } : {}
2357
+ },
2358
+ message: typeof row.message === "string" ? row.message : "",
2359
+ suggestedFix,
2360
+ autoApplicable: false,
2361
+ // reserved — alpha.30+
2362
+ status: asStatus(row.status)
2363
+ };
2364
+ const resolvedAt = asString(row.resolved_at);
2365
+ if (resolvedAt) out.resolvedAt = resolvedAt;
2366
+ const resolutionSource = asResolutionSource(row.resolution_source);
2367
+ if (resolutionSource) out.resolutionSource = resolutionSource;
2368
+ const resolutionNote = asString(row.resolution_note);
2369
+ if (resolutionNote) out.resolutionNote = resolutionNote;
2370
+ return out;
2371
+ }
2372
+ function resolveFetch(injected) {
2373
+ return injected ?? ((...args) => globalThis.fetch(...args));
2374
+ }
2375
+ function normalizeEndpoint(endpoint) {
2376
+ return endpoint.replace(/\/+$/, "");
2377
+ }
2378
+ async function getActionableAdvisories(opts) {
2379
+ const {
2380
+ appId,
2381
+ severity,
2382
+ status,
2383
+ brainEndpoint,
2384
+ brainJwt,
2385
+ brainAnonKey,
2386
+ fetch: injectedFetch
2387
+ } = opts;
2388
+ if (!appId) {
2389
+ throw new Error("getActionableAdvisories: appId is required");
2390
+ }
2391
+ const doFetch = resolveFetch(injectedFetch);
2392
+ const base = normalizeEndpoint(brainEndpoint);
2393
+ const qs = new URLSearchParams();
2394
+ qs.set("app_id", `eq.${appId}`);
2395
+ if (severity) qs.set("severity", `eq.${severity}`);
2396
+ const effectiveStatus = status ?? "open";
2397
+ if (effectiveStatus !== "all") {
2398
+ qs.set("status", `eq.${effectiveStatus}`);
2399
+ }
2400
+ qs.set("order", "last_observed_at.desc");
2401
+ const url = `${base}/rest/v1/actionable_advisories_v?${qs.toString()}`;
2402
+ let res;
2403
+ try {
2404
+ res = await doFetch(url, {
2405
+ method: "GET",
2406
+ headers: {
2407
+ Authorization: `Bearer ${brainJwt}`,
2408
+ apikey: brainAnonKey,
2409
+ Accept: "application/json"
2410
+ }
2411
+ });
2412
+ } catch (err) {
2413
+ const msg = err instanceof Error ? err.message : String(err);
2414
+ throw new Error(`getActionableAdvisories: network error: ${msg}`);
2415
+ }
2416
+ if (res.status === 401 || res.status === 403) {
2417
+ throw new Error("getActionableAdvisories: brain auth misconfig");
2418
+ }
2419
+ if (res.status >= 500) {
2420
+ throw new Error(`getActionableAdvisories: brain unavailable (${res.status})`);
2421
+ }
2422
+ if (!res.ok) {
2423
+ throw new Error(`getActionableAdvisories: bad request (${res.status})`);
2424
+ }
2425
+ let rows;
2426
+ try {
2427
+ rows = await res.json();
2428
+ } catch {
2429
+ throw new Error("getActionableAdvisories: malformed brain response");
2430
+ }
2431
+ if (!Array.isArray(rows)) {
2432
+ throw new Error("getActionableAdvisories: expected array from brain");
2433
+ }
2434
+ const out = [];
2435
+ for (const raw of rows) {
2436
+ if (raw && typeof raw === "object") {
2437
+ out.push(rowToAdvisory(raw));
2438
+ }
2439
+ }
2440
+ return out;
2441
+ }
2442
+ async function markAdvisoryResolved(opts) {
2443
+ const {
2444
+ id,
2445
+ resolutionNote,
2446
+ brainEndpoint,
2447
+ brainJwt,
2448
+ brainAnonKey,
2449
+ fetch: injectedFetch
2450
+ } = opts;
2451
+ if (!id) {
2452
+ return { ok: false, reason: "id_required" };
2453
+ }
2454
+ const doFetch = resolveFetch(injectedFetch);
2455
+ const base = normalizeEndpoint(brainEndpoint);
2456
+ const lookupUrl = `${base}/rest/v1/actionable_advisories_v?id=eq.${encodeURIComponent(id)}&select=app_id,rule`;
2457
+ let lookupRes;
2458
+ try {
2459
+ lookupRes = await doFetch(lookupUrl, {
2460
+ method: "GET",
2461
+ headers: {
2462
+ Authorization: `Bearer ${brainJwt}`,
2463
+ apikey: brainAnonKey,
2464
+ Accept: "application/json"
2465
+ }
2466
+ });
2467
+ } catch (err) {
2468
+ const msg = err instanceof Error ? err.message : String(err);
2469
+ return { ok: false, reason: `network_error:${msg}` };
2470
+ }
2471
+ if (lookupRes.status === 401 || lookupRes.status === 403) {
2472
+ return { ok: false, reason: "brain_auth_misconfig" };
2473
+ }
2474
+ if (lookupRes.status >= 500) {
2475
+ return { ok: false, reason: "brain_unavailable" };
2476
+ }
2477
+ if (!lookupRes.ok) {
2478
+ return { ok: false, reason: `brain_lookup_failed:${lookupRes.status}` };
2479
+ }
2480
+ let lookupRows;
2481
+ try {
2482
+ lookupRows = await lookupRes.json();
2483
+ } catch {
2484
+ return { ok: false, reason: "brain_lookup_malformed" };
2485
+ }
2486
+ if (!Array.isArray(lookupRows) || lookupRows.length === 0) {
2487
+ return { ok: false, reason: "advisory_not_found" };
2488
+ }
2489
+ const tuple = lookupRows[0];
2490
+ const appId = typeof tuple.app_id === "string" ? tuple.app_id : "";
2491
+ const code = typeof tuple.rule === "string" ? tuple.rule : "";
2492
+ if (!appId || !code) {
2493
+ return { ok: false, reason: "advisory_tuple_invalid" };
2494
+ }
2495
+ const outcomesUrl = `${base}/rest/v1/compile_outcomes?app_id=eq.${encodeURIComponent(appId)}&select=id`;
2496
+ let outcomesRes;
2497
+ try {
2498
+ outcomesRes = await doFetch(outcomesUrl, {
2499
+ method: "GET",
2500
+ headers: {
2501
+ Authorization: `Bearer ${brainJwt}`,
2502
+ apikey: brainAnonKey,
2503
+ Accept: "application/json"
2504
+ }
2505
+ });
2506
+ } catch (err) {
2507
+ const msg = err instanceof Error ? err.message : String(err);
2508
+ return { ok: false, reason: `network_error:${msg}` };
2509
+ }
2510
+ if (outcomesRes.status === 401 || outcomesRes.status === 403) {
2511
+ return { ok: false, reason: "brain_auth_misconfig" };
2512
+ }
2513
+ if (outcomesRes.status >= 500) {
2514
+ return { ok: false, reason: "brain_unavailable" };
2515
+ }
2516
+ if (!outcomesRes.ok) {
2517
+ return { ok: false, reason: `brain_lookup_failed:${outcomesRes.status}` };
2518
+ }
2519
+ let outcomeRows;
2520
+ try {
2521
+ outcomeRows = await outcomesRes.json();
2522
+ } catch {
2523
+ return { ok: false, reason: "brain_lookup_malformed" };
2524
+ }
2525
+ if (!Array.isArray(outcomeRows)) {
2526
+ return { ok: false, reason: "brain_lookup_malformed" };
2527
+ }
2528
+ const outcomeIds = [];
2529
+ for (const row of outcomeRows) {
2530
+ if (row && typeof row === "object") {
2531
+ const idVal = row.id;
2532
+ if (typeof idVal === "number" && Number.isFinite(idVal)) {
2533
+ outcomeIds.push(idVal);
2534
+ }
2535
+ }
2536
+ }
2537
+ if (outcomeIds.length === 0) {
2538
+ return { ok: true };
2539
+ }
2540
+ const inList = outcomeIds.join(",");
2541
+ const patchUrl = `${base}/rest/v1/compile_outcome_advisories?outcome_id=in.(${inList})&code=eq.${encodeURIComponent(code)}&resolved_at=is.null`;
2542
+ const patchBody = {
2543
+ resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
2544
+ resolution_source: "consumer-marked"
2545
+ };
2546
+ if (resolutionNote !== void 0) {
2547
+ patchBody.resolution_note = resolutionNote;
2548
+ }
2549
+ let patchRes;
2550
+ try {
2551
+ patchRes = await doFetch(patchUrl, {
2552
+ method: "PATCH",
2553
+ headers: {
2554
+ Authorization: `Bearer ${brainJwt}`,
2555
+ apikey: brainAnonKey,
2556
+ "Content-Type": "application/json",
2557
+ Accept: "application/json",
2558
+ // PostgREST default is no return; we don't need the row back.
2559
+ Prefer: "return=minimal"
2560
+ },
2561
+ body: JSON.stringify(patchBody)
2562
+ });
2563
+ } catch (err) {
2564
+ const msg = err instanceof Error ? err.message : String(err);
2565
+ return { ok: false, reason: `network_error:${msg}` };
2566
+ }
2567
+ if (patchRes.status === 401 || patchRes.status === 403) {
2568
+ return { ok: false, reason: "brain_auth_misconfig" };
2569
+ }
2570
+ if (patchRes.status >= 500) {
2571
+ return { ok: false, reason: "brain_unavailable" };
2572
+ }
2573
+ if (!patchRes.ok) {
2574
+ return { ok: false, reason: `patch_failed:${patchRes.status}` };
2575
+ }
2576
+ return { ok: true };
2577
+ }
2578
+
2688
2579
  // src/models-brain.ts
2689
2580
  function isModelRow(x) {
2690
2581
  if (!x || typeof x !== "object") return false;
@@ -2811,14 +2702,19 @@ function compile2(ir, opts) {
2811
2702
  return result;
2812
2703
  }
2813
2704
  export {
2705
+ ABSOLUTE_FLOOR,
2814
2706
  ALIASES,
2815
2707
  ALL_ARCHETYPES,
2708
+ ARCHETYPE_FLOOR_DEFAULT,
2816
2709
  CallError,
2817
2710
  DIALECT_VERSION,
2818
2711
  INTENT_ARCHETYPES,
2819
2712
  MEASURED_GROUNDING_MIN_N,
2820
2713
  PROVIDER_ENV_KEYS,
2714
+ RULE_SEQUENTIAL_TOOL_CLIFF,
2715
+ TRANSLATOR_FLOOR,
2821
2716
  allProfiles,
2717
+ applySectionRewrites,
2822
2718
  bucketContext,
2823
2719
  bucketHistory,
2824
2720
  bucketToolCount,
@@ -2829,11 +2725,13 @@ export {
2829
2725
  configureBrain,
2830
2726
  countTokens,
2831
2727
  execute,
2728
+ getActionableAdvisories,
2832
2729
  getAllStarterChains,
2833
2730
  getAllStarterChainsWithGrounding,
2834
2731
  getArchetypePerfScore,
2835
2732
  getDefaultFallbackChain,
2836
2733
  getDefaultFallbackChainWithGrounding,
2734
+ getModelCompatibility,
2837
2735
  getPerAxisMetrics,
2838
2736
  getProfile,
2839
2737
  getReachabilityDiagnostic,
@@ -2853,6 +2751,7 @@ export {
2853
2751
  loadChainsFromBrain,
2854
2752
  loadModelsFromBrain,
2855
2753
  loadPricingFromBrain,
2754
+ markAdvisoryResolved,
2856
2755
  profileToRow,
2857
2756
  profilesByProvider,
2858
2757
  record,