@warmdrift/kgauto-compiler 2.0.0-alpha.39 → 2.0.0-alpha.41

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
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  CallError: () => CallError,
28
28
  DEFAULT_FINDINGS_ENDPOINT: () => DEFAULT_FINDINGS_ENDPOINT,
29
29
  DIALECT_VERSION: () => DIALECT_VERSION,
30
+ FamilyResolutionError: () => FamilyResolutionError,
30
31
  INTENT_ARCHETYPES: () => INTENT_ARCHETYPES,
31
32
  MEASURED_GROUNDING_MIN_N: () => MEASURED_GROUNDING_MIN_N,
32
33
  PROVIDER_ENV_KEYS: () => PROVIDER_ENV_KEYS,
@@ -44,6 +45,7 @@ __export(index_exports, {
44
45
  compile: () => compile2,
45
46
  configureBrain: () => configureBrain,
46
47
  countTokens: () => countTokens,
48
+ deriveFamilyFromModelId: () => deriveFamilyFromModelId,
47
49
  execute: () => execute,
48
50
  getActionableAdvisories: () => getActionableAdvisories,
49
51
  getAllStarterChains: () => getAllStarterChains,
@@ -55,6 +57,7 @@ __export(index_exports, {
55
57
  getPerAxisMetrics: () => getPerAxisMetrics,
56
58
  getProfile: () => getProfile,
57
59
  getReachabilityDiagnostic: () => getReachabilityDiagnostic,
60
+ getRecommendedPrimary: () => getRecommendedPrimary,
58
61
  getSequentialStarterChain: () => getSequentialStarterChain,
59
62
  getSequentialStarterChainWithGrounding: () => getSequentialStarterChainWithGrounding,
60
63
  getStaleExclusionFindings: () => getStaleExclusionFindings,
@@ -75,6 +78,7 @@ __export(index_exports, {
75
78
  loadPricingFromBrain: () => loadPricingFromBrain,
76
79
  markAdvisoryResolved: () => markAdvisoryResolved,
77
80
  markExclusionFindingHandled: () => markExclusionFindingHandled,
81
+ markPromoteReadyHandled: () => markPromoteReadyHandled,
78
82
  profileToRow: () => profileToRow,
79
83
  profilesByProvider: () => profilesByProvider,
80
84
  record: () => record,
@@ -463,7 +467,8 @@ function passScoreTargets(ir, opts) {
463
467
  const preferredSet = new Set(policy.preferredModels ?? []);
464
468
  const scores = [];
465
469
  const policyMutations = [];
466
- for (const modelId of ir.models) {
470
+ const modelIds = ir.models.filter((m) => typeof m === "string");
471
+ for (const modelId of modelIds) {
467
472
  let profile;
468
473
  try {
469
474
  profile = opts.profilesById(modelId);
@@ -507,7 +512,7 @@ function passScoreTargets(ir, opts) {
507
512
  }
508
513
  const baseQuality = profile.strengths.includes("reasoning") ? 0.85 : profile.strengths.includes("quality") ? 0.8 : 0.6;
509
514
  const qualityScore = Math.max(0, baseQuality - qualityPenalty);
510
- const callerOrderBoost = (ir.models.length - ir.models.indexOf(modelId)) * 0.1;
515
+ const callerOrderBoost = (modelIds.length - modelIds.indexOf(modelId)) * 0.1;
511
516
  const costPenalty = estimatedCostUsd * 5;
512
517
  const preferredBoost = preferredSet.has(modelId) ? 0.5 : 0;
513
518
  const rank = qualityScore + callerOrderBoost - costPenalty - reasons.length * 10 + preferredBoost;
@@ -2523,6 +2528,393 @@ function defaultOnError2(err) {
2523
2528
  );
2524
2529
  }
2525
2530
 
2531
+ // src/promote-ready-brain.ts
2532
+ function isRawPromoteReadyRow(x) {
2533
+ if (!x || typeof x !== "object") return false;
2534
+ const r = x;
2535
+ return typeof r.intent_archetype === "string" && typeof r.family === "string" && typeof r.candidate_model === "string" && typeof r.current_model === "string" && typeof r.detected_at === "string";
2536
+ }
2537
+ function coerceNumber(v) {
2538
+ if (typeof v === "number") return Number.isFinite(v) ? v : null;
2539
+ if (typeof v === "string") {
2540
+ const n = Number(v);
2541
+ return Number.isFinite(n) ? n : null;
2542
+ }
2543
+ return null;
2544
+ }
2545
+ function mapRowsToFindings2(rows) {
2546
+ const out = [];
2547
+ for (const row of rows) {
2548
+ if (!isRawPromoteReadyRow(row)) continue;
2549
+ const sampleN = coerceNumber(row.sample_n);
2550
+ const passRate = coerceNumber(row.judge_pass_rate);
2551
+ const avgScore = coerceNumber(row.judge_avg_score);
2552
+ if (sampleN === null || passRate === null || avgScore === null) continue;
2553
+ out.push({
2554
+ archetype: row.intent_archetype,
2555
+ family: row.family,
2556
+ candidateModel: row.candidate_model,
2557
+ currentModel: row.current_model,
2558
+ sampleN,
2559
+ judgePassRate: passRate,
2560
+ judgeAvgScore: avgScore,
2561
+ costDeltaPct: coerceNumber(row.cost_delta_pct),
2562
+ detectedAt: row.detected_at
2563
+ });
2564
+ }
2565
+ return out;
2566
+ }
2567
+ var snapshots2 = /* @__PURE__ */ new Map();
2568
+ var runtime3;
2569
+ var warnedOnce2 = false;
2570
+ function isPromoteReadyBrainActive() {
2571
+ return runtime3 !== void 0;
2572
+ }
2573
+ function loadPromoteReadyFindings(opts) {
2574
+ const rt = runtime3;
2575
+ if (!rt) return [];
2576
+ const appId = opts.appId;
2577
+ if (!appId) return [];
2578
+ let snap = snapshots2.get(appId);
2579
+ if (!snap) {
2580
+ snap = { data: [], expiresAt: 0, refreshing: false };
2581
+ snapshots2.set(appId, snap);
2582
+ }
2583
+ const now = Date.now();
2584
+ const stale = snap.expiresAt <= now;
2585
+ if (stale && !snap.refreshing) {
2586
+ snap.refreshing = true;
2587
+ void asyncRefresh3(rt, appId);
2588
+ }
2589
+ let rows = snap.data;
2590
+ if (opts.archetype) {
2591
+ rows = rows.filter((f) => f.archetype === opts.archetype);
2592
+ }
2593
+ if (opts.family) {
2594
+ rows = rows.filter((f) => f.family === opts.family);
2595
+ }
2596
+ return rows;
2597
+ }
2598
+ var pendingRefreshes2 = /* @__PURE__ */ new Map();
2599
+ async function asyncRefresh3(rt, appId) {
2600
+ const promise = doRefresh3(rt, appId);
2601
+ pendingRefreshes2.set(appId, promise);
2602
+ try {
2603
+ await promise;
2604
+ } finally {
2605
+ if (pendingRefreshes2.get(appId) === promise) {
2606
+ pendingRefreshes2.delete(appId);
2607
+ }
2608
+ }
2609
+ }
2610
+ async function doRefresh3(rt, appId) {
2611
+ const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}`;
2612
+ let snap = snapshots2.get(appId);
2613
+ if (!snap) {
2614
+ snap = { data: [], expiresAt: 0, refreshing: false };
2615
+ snapshots2.set(appId, snap);
2616
+ }
2617
+ try {
2618
+ const res = await rt.fetchImpl(url, { method: "GET" });
2619
+ if (!res.ok) {
2620
+ throw new Error(`promote-ready ${res.status}: ${res.statusText}`);
2621
+ }
2622
+ const body = await res.json();
2623
+ if (runtime3 !== rt) return;
2624
+ const rows = Array.isArray(body) ? mapRowsToFindings2(body) : [];
2625
+ snap.data = rows;
2626
+ snap.expiresAt = Date.now() + rt.ttlMs;
2627
+ snap.refreshing = false;
2628
+ } catch (err) {
2629
+ if (runtime3 !== rt) return;
2630
+ snap.refreshing = false;
2631
+ snap.expiresAt = Date.now() + rt.ttlMs;
2632
+ if (!warnedOnce2) {
2633
+ warnedOnce2 = true;
2634
+ (rt.onError ?? defaultOnError3)(err);
2635
+ }
2636
+ }
2637
+ }
2638
+ function defaultOnError3(err) {
2639
+ console.warn(
2640
+ "[kgauto] promote-ready fetch failed (using empty fallback):",
2641
+ err
2642
+ );
2643
+ }
2644
+ function resolveFetchImpl(injected) {
2645
+ return injected ?? ((...args) => globalThis.fetch(...args));
2646
+ }
2647
+ function normalizeEndpoint(endpoint) {
2648
+ return endpoint.replace(/\/+$/, "");
2649
+ }
2650
+ async function markPromoteReadyHandled(opts) {
2651
+ const {
2652
+ appId,
2653
+ archetype,
2654
+ family,
2655
+ resolution,
2656
+ resolutionNote,
2657
+ brainEndpoint,
2658
+ brainJwt,
2659
+ brainAnonKey,
2660
+ fetch: injectedFetch
2661
+ } = opts;
2662
+ if (!appId) return { ok: false, reason: "app_id_required" };
2663
+ if (!archetype) return { ok: false, reason: "archetype_required" };
2664
+ if (!family) return { ok: false, reason: "family_required" };
2665
+ if (resolution !== "promoted" && resolution !== "declined" && resolution !== "still-evaluating") {
2666
+ return { ok: false, reason: "resolution_invalid" };
2667
+ }
2668
+ const doFetch = resolveFetchImpl(injectedFetch);
2669
+ const base = normalizeEndpoint(brainEndpoint);
2670
+ const url = `${base}/rest/v1/promote_ready_findings?app_id=eq.${encodeURIComponent(appId)}&intent_archetype=eq.${encodeURIComponent(archetype)}&family=eq.${encodeURIComponent(family)}&resolved_at=is.null`;
2671
+ const patchBody = {
2672
+ resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
2673
+ resolution
2674
+ };
2675
+ if (resolutionNote !== void 0) {
2676
+ patchBody.resolution_note = resolutionNote;
2677
+ }
2678
+ let res;
2679
+ try {
2680
+ res = await doFetch(url, {
2681
+ method: "PATCH",
2682
+ headers: {
2683
+ Authorization: `Bearer ${brainJwt}`,
2684
+ apikey: brainAnonKey,
2685
+ "Content-Type": "application/json",
2686
+ Accept: "application/json",
2687
+ Prefer: "return=minimal"
2688
+ },
2689
+ body: JSON.stringify(patchBody)
2690
+ });
2691
+ } catch (err) {
2692
+ const msg = err instanceof Error ? err.message : String(err);
2693
+ return { ok: false, reason: `network_error:${msg}` };
2694
+ }
2695
+ if (res.status === 401 || res.status === 403) {
2696
+ return { ok: false, reason: "brain_auth_misconfig" };
2697
+ }
2698
+ if (res.status >= 500) {
2699
+ return { ok: false, reason: "brain_unavailable" };
2700
+ }
2701
+ if (!res.ok) {
2702
+ return { ok: false, reason: `patch_failed:${res.status}` };
2703
+ }
2704
+ return { ok: true };
2705
+ }
2706
+
2707
+ // src/advisor-rules/promote-ready.ts
2708
+ var PROMOTE_READY_THRESHOLDS = {
2709
+ minPassRate: 0.8,
2710
+ minAvgScore: 4
2711
+ };
2712
+ function shouldFirePromoteReady(finding, resolvedPrimary) {
2713
+ if (finding.currentModel !== resolvedPrimary) return false;
2714
+ if (finding.judgePassRate < PROMOTE_READY_THRESHOLDS.minPassRate) return false;
2715
+ if (finding.judgeAvgScore < PROMOTE_READY_THRESHOLDS.minAvgScore) return false;
2716
+ return true;
2717
+ }
2718
+ function deriveFamilyLocal(modelId) {
2719
+ if (modelId.startsWith("claude-opus-")) return "claude-opus";
2720
+ if (modelId.startsWith("claude-sonnet-")) return "claude-sonnet";
2721
+ if (modelId.startsWith("claude-haiku-")) return "claude-haiku";
2722
+ if (/^gemini-.*-flash-lite/.test(modelId)) return "gemini-flash-lite";
2723
+ if (/^gemini-.*-flash/.test(modelId)) return "gemini-flash";
2724
+ if (/^gemini-.*-pro/.test(modelId)) return "gemini-pro";
2725
+ if (/^deepseek-.*-pro/.test(modelId)) return "deepseek-reasoner";
2726
+ if (modelId.startsWith("deepseek-")) return "deepseek-chat";
2727
+ if (modelId.startsWith("gpt-")) return "openai-gpt";
2728
+ return null;
2729
+ }
2730
+ function advisorRulePromoteReady(ctx) {
2731
+ if (!isPromoteReadyBrainActive()) return [];
2732
+ if (!ctx.appId) return [];
2733
+ if (!ctx.resolvedPrimary) return [];
2734
+ const family = deriveFamilyLocal(ctx.resolvedPrimary);
2735
+ if (!family) return [];
2736
+ const findings = loadPromoteReadyFindings({
2737
+ appId: ctx.appId,
2738
+ archetype: ctx.archetype,
2739
+ family
2740
+ });
2741
+ if (findings.length === 0) return [];
2742
+ const qualifying = findings.filter(
2743
+ (f) => shouldFirePromoteReady(f, ctx.resolvedPrimary)
2744
+ );
2745
+ if (qualifying.length === 0) return [];
2746
+ qualifying.sort((a, b) => {
2747
+ if (a.judgeAvgScore !== b.judgeAvgScore) {
2748
+ return b.judgeAvgScore - a.judgeAvgScore;
2749
+ }
2750
+ return b.judgePassRate - a.judgePassRate;
2751
+ });
2752
+ const top = qualifying[0];
2753
+ const pctPass = Math.round(top.judgePassRate * 100);
2754
+ const score = top.judgeAvgScore.toFixed(2);
2755
+ let costClause = "";
2756
+ if (top.costDeltaPct !== null) {
2757
+ const sign = top.costDeltaPct < 0 ? "cheaper" : "more expensive";
2758
+ const magnitude = Math.abs(top.costDeltaPct * 100).toFixed(1);
2759
+ costClause = `, cost ${magnitude}% ${sign}`;
2760
+ }
2761
+ const message = `Probe found ${top.candidateModel} produces equivalent-or-better outputs vs ${top.currentModel} on ${top.sampleN} recent ${top.archetype} prompts (pass rate ${pctPass}%, avg score ${score}/5${costClause}). Consider promoting via markPromoteReadyHandled.`;
2762
+ return [
2763
+ {
2764
+ level: "info",
2765
+ code: "promote-ready",
2766
+ message,
2767
+ suggestion: `Migrate ${top.archetype} traffic from ${top.currentModel} to ${top.candidateModel}, then call markPromoteReadyHandled({ appId, archetype: '${top.archetype}', family: '${top.family}', resolution: 'promoted' }) to silence this advisory.`,
2768
+ // alpha.36 architectural field — not a no-ai-needed case.
2769
+ recommendedArchitecture: void 0,
2770
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
2771
+ }
2772
+ ];
2773
+ }
2774
+
2775
+ // src/advisor-rules/consumer-on-stale-model.ts
2776
+ function isStaleStatus(v) {
2777
+ return v === "legacy" || v === "deprecated";
2778
+ }
2779
+ function asString(v) {
2780
+ return typeof v === "string" && v.length > 0 ? v : void 0;
2781
+ }
2782
+ function mapRowsToFindings3(rows) {
2783
+ const out = [];
2784
+ for (const raw of rows) {
2785
+ if (!raw || typeof raw !== "object") continue;
2786
+ const r = raw;
2787
+ const archetype = asString(r.intent_archetype) ?? asString(r.applies_to_archetype);
2788
+ const staleModel = asString(r.stale_model) ?? asString(r.applies_to_model);
2789
+ const staleProvider = asString(r.stale_provider);
2790
+ const recommendedModel = asString(r.recommended_model);
2791
+ const family = asString(r.family);
2792
+ const message = asString(r.message);
2793
+ if (!archetype || !staleModel || !recommendedModel || !family || !message) {
2794
+ continue;
2795
+ }
2796
+ if (!isStaleStatus(r.stale_status)) continue;
2797
+ const row = {
2798
+ archetype,
2799
+ staleModel,
2800
+ staleProvider: staleProvider ?? "unknown",
2801
+ staleStatus: r.stale_status,
2802
+ recommendedModel,
2803
+ family,
2804
+ message
2805
+ };
2806
+ const suggestion = asString(r.suggestion);
2807
+ if (suggestion) row.suggestion = suggestion;
2808
+ if (typeof r.observation_count === "number" && Number.isFinite(r.observation_count)) {
2809
+ row.observationCount = r.observation_count;
2810
+ }
2811
+ out.push(row);
2812
+ }
2813
+ return out;
2814
+ }
2815
+ var snapshots3 = /* @__PURE__ */ new Map();
2816
+ var runtime4;
2817
+ var warnedOnce3 = false;
2818
+ var pendingRefreshes3 = /* @__PURE__ */ new Map();
2819
+ function isStaleModelFindingsBrainActive() {
2820
+ return runtime4 !== void 0;
2821
+ }
2822
+ function getStaleModelFindings(opts) {
2823
+ const rt = runtime4;
2824
+ if (!rt) return [];
2825
+ const appId = opts.appId;
2826
+ if (!appId) return [];
2827
+ let snap = snapshots3.get(appId);
2828
+ if (!snap) {
2829
+ snap = { data: [], expiresAt: 0, refreshing: false };
2830
+ snapshots3.set(appId, snap);
2831
+ }
2832
+ const now = Date.now();
2833
+ const stale = snap.expiresAt <= now;
2834
+ if (stale && !snap.refreshing) {
2835
+ snap.refreshing = true;
2836
+ void asyncRefresh4(rt, appId);
2837
+ }
2838
+ if (opts.archetype) {
2839
+ return snap.data.filter((f) => f.archetype === opts.archetype);
2840
+ }
2841
+ return snap.data;
2842
+ }
2843
+ async function asyncRefresh4(rt, appId) {
2844
+ const promise = doRefresh4(rt, appId);
2845
+ pendingRefreshes3.set(appId, promise);
2846
+ try {
2847
+ await promise;
2848
+ } finally {
2849
+ if (pendingRefreshes3.get(appId) === promise) {
2850
+ pendingRefreshes3.delete(appId);
2851
+ }
2852
+ }
2853
+ }
2854
+ async function doRefresh4(rt, appId) {
2855
+ const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}`;
2856
+ let snap = snapshots3.get(appId);
2857
+ if (!snap) {
2858
+ snap = { data: [], expiresAt: 0, refreshing: false };
2859
+ snapshots3.set(appId, snap);
2860
+ }
2861
+ try {
2862
+ const res = await rt.fetchImpl(url, { method: "GET" });
2863
+ if (!res.ok) {
2864
+ throw new Error(`stale-model findings ${res.status}: ${res.statusText}`);
2865
+ }
2866
+ const body = await res.json();
2867
+ if (runtime4 !== rt) return;
2868
+ const rows = Array.isArray(body) ? mapRowsToFindings3(body) : [];
2869
+ snap.data = rows;
2870
+ snap.expiresAt = Date.now() + rt.ttlMs;
2871
+ snap.refreshing = false;
2872
+ } catch (err) {
2873
+ if (runtime4 !== rt) return;
2874
+ snap.refreshing = false;
2875
+ snap.expiresAt = Date.now() + rt.ttlMs;
2876
+ if (!warnedOnce3) {
2877
+ warnedOnce3 = true;
2878
+ (rt.onError ?? defaultOnError4)(err);
2879
+ }
2880
+ }
2881
+ }
2882
+ function defaultOnError4(err) {
2883
+ console.warn(
2884
+ "[kgauto] stale-model findings fetch failed (using empty fallback):",
2885
+ err
2886
+ );
2887
+ }
2888
+ var CONSUMER_ON_STALE_MODEL_RULE_CODE = "consumer-on-stale-model";
2889
+ function advisorRuleConsumerOnStaleModel(ir) {
2890
+ if (!isStaleModelFindingsBrainActive()) return [];
2891
+ if (!ir.appId) return [];
2892
+ const findings = getStaleModelFindings({
2893
+ appId: ir.appId,
2894
+ archetype: ir.intent.archetype
2895
+ });
2896
+ if (findings.length === 0) return [];
2897
+ const ranked = [...findings].sort((a, b) => {
2898
+ if (a.staleStatus !== b.staleStatus) {
2899
+ return a.staleStatus === "deprecated" ? -1 : 1;
2900
+ }
2901
+ return a.staleModel.localeCompare(b.staleModel);
2902
+ });
2903
+ const top = ranked[0];
2904
+ const extraCount = findings.length - 1;
2905
+ const extraNote = extraCount > 0 ? ` (+ ${extraCount} more stale model${extraCount === 1 ? "" : "s"} for this archetype)` : "";
2906
+ return [
2907
+ {
2908
+ level: "warn",
2909
+ code: CONSUMER_ON_STALE_MODEL_RULE_CODE,
2910
+ message: `${top.message}${extraNote}`,
2911
+ suggestion: top.suggestion ?? `Migrate ${top.staleModel} \u2192 ${top.recommendedModel} for archetype "${top.archetype}". The newer model is the current latest in the "${top.family}" family; the stale one is ${top.staleStatus}.`,
2912
+ recommendationType: "model-swap",
2913
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
2914
+ }
2915
+ ];
2916
+ }
2917
+
2526
2918
  // src/advisor.ts
2527
2919
  var QUALITY_FLOOR_FOR_RECOMMENDATION = 6;
2528
2920
  var TIER_DOWN_COST_RATIO = 0.5;
@@ -2545,6 +2937,16 @@ function runAdvisor(ir, result, profile, policy, phase2) {
2545
2937
  if (policy?.posture !== "locked") {
2546
2938
  out.push(...detectStaleExclusionCandidate(ir));
2547
2939
  }
2940
+ if (policy?.posture !== "locked" && ir.appId) {
2941
+ out.push(
2942
+ ...advisorRulePromoteReady({
2943
+ appId: ir.appId,
2944
+ archetype: ir.intent.archetype,
2945
+ resolvedPrimary: profile.id
2946
+ })
2947
+ );
2948
+ out.push(...advisorRuleConsumerOnStaleModel(ir));
2949
+ }
2548
2950
  return out;
2549
2951
  }
2550
2952
  function translatorClearedToolCallCliff(phase2) {
@@ -2856,6 +3258,261 @@ ${originalText}`;
2856
3258
  return { rewrittenIR, rewrites };
2857
3259
  }
2858
3260
 
3261
+ // src/models-brain.ts
3262
+ function isModelRow(x) {
3263
+ if (!x || typeof x !== "object") return false;
3264
+ const r = x;
3265
+ return typeof r.model_id === "string" && typeof r.provider === "string";
3266
+ }
3267
+ function isAliasRow(x) {
3268
+ if (!x || typeof x !== "object") return false;
3269
+ const r = x;
3270
+ return typeof r.alias_id === "string" && typeof r.canonical_id === "string";
3271
+ }
3272
+ function rowToProfile(row) {
3273
+ try {
3274
+ if (row.cliffs !== void 0 && row.cliffs !== null && !Array.isArray(row.cliffs)) {
3275
+ return null;
3276
+ }
3277
+ if (row.recovery !== void 0 && row.recovery !== null && !Array.isArray(row.recovery)) {
3278
+ return null;
3279
+ }
3280
+ if (row.lowering !== void 0 && row.lowering !== null && (typeof row.lowering !== "object" || Array.isArray(row.lowering))) {
3281
+ return null;
3282
+ }
3283
+ return {
3284
+ id: row.model_id,
3285
+ provider: row.provider,
3286
+ status: row.status ?? "current",
3287
+ maxContextTokens: row.max_context_tokens ?? 0,
3288
+ maxOutputTokens: row.max_output_tokens ?? 0,
3289
+ maxTools: row.max_tools ?? 0,
3290
+ parallelToolCalls: row.parallel_tool_calls ?? false,
3291
+ structuredOutput: row.structured_output ?? "none",
3292
+ systemPromptMode: row.system_prompt_mode ?? "inline",
3293
+ streaming: row.streaming ?? true,
3294
+ cliffs: row.cliffs ?? [],
3295
+ costInputPer1m: row.cost_input_per_1m ?? 0,
3296
+ costOutputPer1m: row.cost_output_per_1m ?? 0,
3297
+ lowering: row.lowering ?? { system: { mode: "inline" }, cache: { strategy: "unsupported" } },
3298
+ recovery: row.recovery ?? [],
3299
+ strengths: row.strengths ?? [],
3300
+ weaknesses: row.weaknesses ?? [],
3301
+ notes: row.notes ?? void 0,
3302
+ verifiedAgainstDocs: row.verified_against_docs ?? void 0,
3303
+ archetypePerf: row.archetype_perf ?? void 0,
3304
+ // alpha.41 — family-resolution fields. `family` may be null pre-
3305
+ // migration 024; runtime falls back to deriveFamilyFromModelId at
3306
+ // resolution time (see family-resolution.ts, G1).
3307
+ family: row.family ?? void 0,
3308
+ versionAdded: row.version_added ?? void 0,
3309
+ active: row.active ?? void 0
3310
+ };
3311
+ } catch {
3312
+ return null;
3313
+ }
3314
+ }
3315
+ function profileToRow(profile, opts = {}) {
3316
+ const row = {
3317
+ model_id: profile.id,
3318
+ provider: profile.provider,
3319
+ status: profile.status,
3320
+ max_context_tokens: profile.maxContextTokens,
3321
+ max_output_tokens: profile.maxOutputTokens,
3322
+ max_tools: profile.maxTools,
3323
+ parallel_tool_calls: profile.parallelToolCalls,
3324
+ structured_output: profile.structuredOutput,
3325
+ system_prompt_mode: profile.systemPromptMode,
3326
+ streaming: profile.streaming,
3327
+ cliffs: profile.cliffs,
3328
+ cost_input_per_1m: profile.costInputPer1m,
3329
+ cost_output_per_1m: profile.costOutputPer1m,
3330
+ lowering: profile.lowering,
3331
+ recovery: profile.recovery,
3332
+ strengths: profile.strengths,
3333
+ weaknesses: profile.weaknesses,
3334
+ notes: profile.notes ?? null,
3335
+ archetype_perf: profile.archetypePerf ?? null,
3336
+ active: opts.active ?? profile.active ?? true,
3337
+ // alpha.41 — round-trip family + version_added when present on profile.
3338
+ // version_added is operator-controlled via opts; profile-side value is
3339
+ // used only when opts didn't override.
3340
+ family: profile.family ?? null
3341
+ };
3342
+ if (opts.verifiedAgainstDocs !== void 0) {
3343
+ row.verified_against_docs = opts.verifiedAgainstDocs;
3344
+ } else if (profile.verifiedAgainstDocs !== void 0) {
3345
+ const v = profile.verifiedAgainstDocs;
3346
+ row.verified_against_docs = /^\d{4}-\d{2}-\d{2}/.test(v) ? v : null;
3347
+ }
3348
+ if (opts.versionAdded !== void 0) row.version_added = opts.versionAdded;
3349
+ else if (profile.versionAdded !== void 0) row.version_added = profile.versionAdded;
3350
+ if (opts.versionRemoved !== void 0) row.version_removed = opts.versionRemoved;
3351
+ return row;
3352
+ }
3353
+ function mapRowsToModels(rows) {
3354
+ const out = /* @__PURE__ */ new Map();
3355
+ for (const row of rows) {
3356
+ if (!isModelRow(row)) continue;
3357
+ const profile = rowToProfile(row);
3358
+ if (profile) out.set(profile.id, profile);
3359
+ }
3360
+ return out;
3361
+ }
3362
+ function mapRowsToAliases(rows) {
3363
+ const out = {};
3364
+ for (const row of rows) {
3365
+ if (!isAliasRow(row)) continue;
3366
+ out[row.alias_id] = row.canonical_id;
3367
+ }
3368
+ return out;
3369
+ }
3370
+ function bundledModels() {
3371
+ return new Map(allProfilesRaw().map((p) => [p.id, p]));
3372
+ }
3373
+ function bundledAliases() {
3374
+ return { ...ALIASES };
3375
+ }
3376
+ var loadModelsFromBrain = createBrainQueryCache({
3377
+ table: "kgauto_models",
3378
+ mapRows: mapRowsToModels,
3379
+ bundledFallback: bundledModels
3380
+ });
3381
+ var loadAliasesFromBrain = createBrainQueryCache({
3382
+ table: "kgauto_aliases",
3383
+ mapRows: mapRowsToAliases,
3384
+ bundledFallback: bundledAliases
3385
+ });
3386
+ _setProfileBrainHook({
3387
+ getProfile: (canonical) => loadModelsFromBrain().get(canonical),
3388
+ resolveAlias: (id) => loadAliasesFromBrain()[id]
3389
+ });
3390
+
3391
+ // src/family-resolution.ts
3392
+ var FamilyResolutionError = class extends Error {
3393
+ family;
3394
+ cause;
3395
+ constructor(family, cause) {
3396
+ super(
3397
+ `Family "${family}" did not resolve to any current+active model. ${cause}. Pass a literal model id in ir.models, or call getRecommendedPrimary({ family, fallback }) at IR-construction time.`
3398
+ );
3399
+ this.name = "FamilyResolutionError";
3400
+ this.family = family;
3401
+ this.cause = cause;
3402
+ }
3403
+ };
3404
+ function deriveFamilyFromModelId(modelId) {
3405
+ if (typeof modelId !== "string" || modelId.length === 0) return null;
3406
+ if (modelId.startsWith("claude-opus-")) return "claude-opus";
3407
+ if (modelId.startsWith("claude-sonnet-")) return "claude-sonnet";
3408
+ if (modelId.startsWith("claude-haiku-")) return "claude-haiku";
3409
+ if (modelId.startsWith("gemini-") && modelId.includes("flash-lite")) {
3410
+ return "gemini-flash-lite";
3411
+ }
3412
+ if (modelId.startsWith("gemini-") && modelId.includes("flash")) {
3413
+ return "gemini-flash";
3414
+ }
3415
+ if (modelId.startsWith("gemini-") && modelId.includes("pro")) {
3416
+ return "gemini-pro";
3417
+ }
3418
+ if (modelId.startsWith("deepseek-") && modelId.includes("pro")) {
3419
+ return "deepseek-reasoner";
3420
+ }
3421
+ if (modelId.startsWith("deepseek-")) return "deepseek-chat";
3422
+ if (modelId.startsWith("gpt-")) return "openai-gpt";
3423
+ return null;
3424
+ }
3425
+ function familyOf(profile) {
3426
+ return profile.family ?? deriveFamilyFromModelId(profile.id);
3427
+ }
3428
+ function archetypePerfFor(profile, archetype) {
3429
+ if (!archetype) return 0;
3430
+ const score = profile.archetypePerf?.[archetype];
3431
+ return typeof score === "number" ? score : 5;
3432
+ }
3433
+ function selectCandidates(registry, family, archetype, appId) {
3434
+ const out = [];
3435
+ const excluded = /* @__PURE__ */ new Set();
3436
+ if (appId && archetype) {
3437
+ const findings = getStaleExclusionFindings({ appId, archetype });
3438
+ for (const f of findings) {
3439
+ if (f.verdict === "stay-excluded") excluded.add(f.excludedModel);
3440
+ }
3441
+ }
3442
+ for (const profile of registry.values()) {
3443
+ if (familyOf(profile) !== family) continue;
3444
+ if (profile.status !== "current") continue;
3445
+ if (profile.active === false) continue;
3446
+ if (archetype) {
3447
+ if (archetypePerfFor(profile, archetype) < ARCHETYPE_FLOOR_DEFAULT) continue;
3448
+ }
3449
+ if (excluded.has(profile.id)) continue;
3450
+ out.push(profile);
3451
+ }
3452
+ return out;
3453
+ }
3454
+ function sortCandidates(candidates, archetype) {
3455
+ const sorted = [...candidates];
3456
+ sorted.sort((a, b) => {
3457
+ const perfA = archetypePerfFor(a, archetype);
3458
+ const perfB = archetypePerfFor(b, archetype);
3459
+ if (perfA !== perfB) return perfB - perfA;
3460
+ const vA = a.versionAdded ?? "";
3461
+ const vB = b.versionAdded ?? "";
3462
+ if (vA !== vB) return vA < vB ? 1 : -1;
3463
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
3464
+ });
3465
+ return sorted;
3466
+ }
3467
+ function getRecommendedPrimary(opts) {
3468
+ if (opts.posture === "locked") return opts.fallback;
3469
+ const registry = loadModelsFromBrain();
3470
+ const candidates = selectCandidates(
3471
+ registry,
3472
+ opts.family,
3473
+ opts.archetype,
3474
+ opts.appId
3475
+ );
3476
+ if (candidates.length === 0) return opts.fallback;
3477
+ const sorted = sortCandidates(candidates, opts.archetype);
3478
+ return sorted[0]?.id ?? opts.fallback;
3479
+ }
3480
+ function resolveFamilyEntry(family, ctx) {
3481
+ if (typeof family !== "string" || family.length === 0) {
3482
+ throw new FamilyResolutionError(
3483
+ String(family),
3484
+ "Family tag must be a non-empty string"
3485
+ );
3486
+ }
3487
+ const registry = loadModelsFromBrain();
3488
+ const candidates = selectCandidates(
3489
+ registry,
3490
+ family,
3491
+ ctx.archetype,
3492
+ ctx.appId
3493
+ );
3494
+ if (candidates.length === 0) {
3495
+ let anyInFamily = false;
3496
+ for (const profile of registry.values()) {
3497
+ if (familyOf(profile) === family) {
3498
+ anyInFamily = true;
3499
+ break;
3500
+ }
3501
+ }
3502
+ const cause = anyInFamily ? `Family has registered models but none are current+active${ctx.archetype ? ` at archetype-perf >= ${ARCHETYPE_FLOOR_DEFAULT} for "${ctx.archetype}"` : ""}${ctx.appId ? ` and not excluded for app "${ctx.appId}"` : ""}` : `No models in brain registry carry family="${family}". Check the taxonomy table in family-resolution.ts or migration 024`;
3503
+ throw new FamilyResolutionError(family, cause);
3504
+ }
3505
+ const sorted = sortCandidates(candidates, ctx.archetype);
3506
+ const winner = sorted[0];
3507
+ if (!winner) {
3508
+ throw new FamilyResolutionError(
3509
+ family,
3510
+ "Candidates non-empty but sort returned undefined \u2014 internal invariant violation"
3511
+ );
3512
+ }
3513
+ return winner.id;
3514
+ }
3515
+
2859
3516
  // src/compile.ts
2860
3517
  var counter = 0;
2861
3518
  function makeHandle() {
@@ -2865,6 +3522,7 @@ function makeHandle() {
2865
3522
  function compile(ir, opts = {}) {
2866
3523
  const resolver = opts.profileResolver ?? getProfile;
2867
3524
  validateIR(ir);
3525
+ ir = resolveModelEntries(ir);
2868
3526
  const sliced = passSlice(ir);
2869
3527
  const deduped = passDedupe(sliced.value);
2870
3528
  const toolFiltered = passToolRelevance(deduped.value, {
@@ -3051,6 +3709,29 @@ function validateIR(ir) {
3051
3709
  throw new Error("compile(): ir.sections must be an array");
3052
3710
  }
3053
3711
  }
3712
+ function resolveModelEntries(ir) {
3713
+ const out = [];
3714
+ const seen = /* @__PURE__ */ new Set();
3715
+ for (const entry of ir.models) {
3716
+ let id;
3717
+ if (typeof entry === "string") {
3718
+ id = entry;
3719
+ } else if (entry && typeof entry === "object" && "family" in entry) {
3720
+ id = resolveFamilyEntry(entry.family, {
3721
+ archetype: ir.intent.archetype,
3722
+ appId: ir.appId
3723
+ });
3724
+ } else {
3725
+ throw new Error(
3726
+ `compile(): ir.models entry must be a string or { family: string }; got ${JSON.stringify(entry)}`
3727
+ );
3728
+ }
3729
+ if (seen.has(id)) continue;
3730
+ seen.add(id);
3731
+ out.push(id);
3732
+ }
3733
+ return { ...ir, models: out };
3734
+ }
3054
3735
  function pickTarget(ir, scores) {
3055
3736
  if (ir.constraints?.forceModel) {
3056
3737
  const forced = scores.find((s) => s.modelId === ir.constraints.forceModel);
@@ -3277,7 +3958,7 @@ async function record(input) {
3277
3958
  }
3278
3959
  outcomeId = await tryExtractOutcomeId(res);
3279
3960
  } catch (err) {
3280
- (config.onError ?? defaultOnError3)(err);
3961
+ (config.onError ?? defaultOnError5)(err);
3281
3962
  return;
3282
3963
  }
3283
3964
  const advisories = input.advisories ?? reg?.advisoriesFromCompile;
@@ -3299,7 +3980,7 @@ async function record(input) {
3299
3980
  throw new Error(`brain advisories ${res.status}: ${text}`);
3300
3981
  }
3301
3982
  } catch (err) {
3302
- (config.onError ?? defaultOnError3)(err);
3983
+ (config.onError ?? defaultOnError5)(err);
3303
3984
  }
3304
3985
  };
3305
3986
  if (config.sync) {
@@ -3308,7 +3989,7 @@ async function record(input) {
3308
3989
  void send();
3309
3990
  }
3310
3991
  }
3311
- function defaultOnError3(err) {
3992
+ function defaultOnError5(err) {
3312
3993
  console.warn("[kgauto] brain record failed:", err);
3313
3994
  }
3314
3995
  function buildPayload(input, reg) {
@@ -3440,12 +4121,12 @@ async function recordOutcome(input) {
3440
4121
  if (!res.ok) {
3441
4122
  const text = await res.text().catch(() => "<no body>");
3442
4123
  const err = new Error(`brain ${res.status}: ${text}`);
3443
- (config.onError ?? defaultOnError3)(err);
4124
+ (config.onError ?? defaultOnError5)(err);
3444
4125
  return { ok: false, reason: "persistence_failed" };
3445
4126
  }
3446
4127
  return { ok: true };
3447
4128
  } catch (err) {
3448
- (config.onError ?? defaultOnError3)(err);
4129
+ (config.onError ?? defaultOnError5)(err);
3449
4130
  return { ok: false, reason: "persistence_failed" };
3450
4131
  }
3451
4132
  };
@@ -4705,7 +5386,13 @@ async function call(ir, opts = {}) {
4705
5386
  () => emitCompileStart(traceId, ir.appId, {
4706
5387
  appId: ir.appId,
4707
5388
  archetype: ir.intent.archetype,
4708
- models: ir.models
5389
+ // alpha.41: ir.models is ChainModelEntry[] (string | { family }).
5390
+ // Glass-Box renderer carries string ids only; surface family entries
5391
+ // as their family tag prefixed so the panel still shows them in the
5392
+ // pre-resolution log.
5393
+ models: ir.models.map(
5394
+ (m) => typeof m === "string" ? m : `family:${m.family}`
5395
+ )
4709
5396
  })
4710
5397
  );
4711
5398
  const initial = compileAndRegister(ir, opts);
@@ -5171,7 +5858,7 @@ var RESOLUTION_SOURCE_SET = /* @__PURE__ */ new Set([
5171
5858
  "consumer-marked",
5172
5859
  "declined"
5173
5860
  ]);
5174
- function asString(v) {
5861
+ function asString2(v) {
5175
5862
  return typeof v === "string" && v.length > 0 ? v : void 0;
5176
5863
  }
5177
5864
  function asSeverity(v) {
@@ -5193,10 +5880,10 @@ function asResolutionSource(v) {
5193
5880
  return void 0;
5194
5881
  }
5195
5882
  function rowToAdvisory(row) {
5196
- const archetype = asString(row.applies_to_archetype);
5197
- const model = asString(row.applies_to_model);
5198
- const docsLink = asString(row.docs_url);
5199
- const suggestion = asString(row.suggestion);
5883
+ const archetype = asString2(row.applies_to_archetype);
5884
+ const model = asString2(row.applies_to_model);
5885
+ const docsLink = asString2(row.docs_url);
5886
+ const suggestion = asString2(row.suggestion);
5200
5887
  let suggestedFix = null;
5201
5888
  if (docsLink || suggestion) {
5202
5889
  suggestedFix = { type: "manual" };
@@ -5220,18 +5907,18 @@ function rowToAdvisory(row) {
5220
5907
  // reserved — alpha.30+
5221
5908
  status: asStatus(row.status)
5222
5909
  };
5223
- const resolvedAt = asString(row.resolved_at);
5910
+ const resolvedAt = asString2(row.resolved_at);
5224
5911
  if (resolvedAt) out.resolvedAt = resolvedAt;
5225
5912
  const resolutionSource = asResolutionSource(row.resolution_source);
5226
5913
  if (resolutionSource) out.resolutionSource = resolutionSource;
5227
- const resolutionNote = asString(row.resolution_note);
5914
+ const resolutionNote = asString2(row.resolution_note);
5228
5915
  if (resolutionNote) out.resolutionNote = resolutionNote;
5229
5916
  return out;
5230
5917
  }
5231
5918
  function resolveFetch(injected) {
5232
5919
  return injected ?? ((...args) => globalThis.fetch(...args));
5233
5920
  }
5234
- function normalizeEndpoint(endpoint) {
5921
+ function normalizeEndpoint2(endpoint) {
5235
5922
  return endpoint.replace(/\/+$/, "");
5236
5923
  }
5237
5924
  async function getActionableAdvisories(opts) {
@@ -5248,7 +5935,7 @@ async function getActionableAdvisories(opts) {
5248
5935
  throw new Error("getActionableAdvisories: appId is required");
5249
5936
  }
5250
5937
  const doFetch = resolveFetch(injectedFetch);
5251
- const base = normalizeEndpoint(brainEndpoint);
5938
+ const base = normalizeEndpoint2(brainEndpoint);
5252
5939
  const qs = new URLSearchParams();
5253
5940
  qs.set("app_id", `eq.${appId}`);
5254
5941
  if (severity) qs.set("severity", `eq.${severity}`);
@@ -5311,7 +5998,7 @@ async function markAdvisoryResolved(opts) {
5311
5998
  return { ok: false, reason: "id_required" };
5312
5999
  }
5313
6000
  const doFetch = resolveFetch(injectedFetch);
5314
- const base = normalizeEndpoint(brainEndpoint);
6001
+ const base = normalizeEndpoint2(brainEndpoint);
5315
6002
  const lookupUrl = `${base}/rest/v1/actionable_advisories_v?id=eq.${encodeURIComponent(id)}&select=app_id,rule`;
5316
6003
  let lookupRes;
5317
6004
  try {
@@ -5455,7 +6142,7 @@ async function markExclusionFindingHandled(opts) {
5455
6142
  return { ok: false, reason: "resolution_invalid" };
5456
6143
  }
5457
6144
  const doFetch = resolveFetch(injectedFetch);
5458
- const base = normalizeEndpoint(brainEndpoint);
6145
+ const base = normalizeEndpoint2(brainEndpoint);
5459
6146
  const url = `${base}/rest/v1/exclusion_findings?app_id=eq.${encodeURIComponent(appId)}&intent_archetype=eq.${encodeURIComponent(archetype)}&excluded_model=eq.${encodeURIComponent(excludedModel)}&resolved_at=is.null`;
5460
6147
  const patchBody = {
5461
6148
  resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -5495,125 +6182,6 @@ async function markExclusionFindingHandled(opts) {
5495
6182
  return { ok: true };
5496
6183
  }
5497
6184
 
5498
- // src/models-brain.ts
5499
- function isModelRow(x) {
5500
- if (!x || typeof x !== "object") return false;
5501
- const r = x;
5502
- return typeof r.model_id === "string" && typeof r.provider === "string";
5503
- }
5504
- function isAliasRow(x) {
5505
- if (!x || typeof x !== "object") return false;
5506
- const r = x;
5507
- return typeof r.alias_id === "string" && typeof r.canonical_id === "string";
5508
- }
5509
- function rowToProfile(row) {
5510
- try {
5511
- if (row.cliffs !== void 0 && row.cliffs !== null && !Array.isArray(row.cliffs)) {
5512
- return null;
5513
- }
5514
- if (row.recovery !== void 0 && row.recovery !== null && !Array.isArray(row.recovery)) {
5515
- return null;
5516
- }
5517
- if (row.lowering !== void 0 && row.lowering !== null && (typeof row.lowering !== "object" || Array.isArray(row.lowering))) {
5518
- return null;
5519
- }
5520
- return {
5521
- id: row.model_id,
5522
- provider: row.provider,
5523
- status: row.status ?? "current",
5524
- maxContextTokens: row.max_context_tokens ?? 0,
5525
- maxOutputTokens: row.max_output_tokens ?? 0,
5526
- maxTools: row.max_tools ?? 0,
5527
- parallelToolCalls: row.parallel_tool_calls ?? false,
5528
- structuredOutput: row.structured_output ?? "none",
5529
- systemPromptMode: row.system_prompt_mode ?? "inline",
5530
- streaming: row.streaming ?? true,
5531
- cliffs: row.cliffs ?? [],
5532
- costInputPer1m: row.cost_input_per_1m ?? 0,
5533
- costOutputPer1m: row.cost_output_per_1m ?? 0,
5534
- lowering: row.lowering ?? { system: { mode: "inline" }, cache: { strategy: "unsupported" } },
5535
- recovery: row.recovery ?? [],
5536
- strengths: row.strengths ?? [],
5537
- weaknesses: row.weaknesses ?? [],
5538
- notes: row.notes ?? void 0,
5539
- verifiedAgainstDocs: row.verified_against_docs ?? void 0,
5540
- archetypePerf: row.archetype_perf ?? void 0
5541
- };
5542
- } catch {
5543
- return null;
5544
- }
5545
- }
5546
- function profileToRow(profile, opts = {}) {
5547
- const row = {
5548
- model_id: profile.id,
5549
- provider: profile.provider,
5550
- status: profile.status,
5551
- max_context_tokens: profile.maxContextTokens,
5552
- max_output_tokens: profile.maxOutputTokens,
5553
- max_tools: profile.maxTools,
5554
- parallel_tool_calls: profile.parallelToolCalls,
5555
- structured_output: profile.structuredOutput,
5556
- system_prompt_mode: profile.systemPromptMode,
5557
- streaming: profile.streaming,
5558
- cliffs: profile.cliffs,
5559
- cost_input_per_1m: profile.costInputPer1m,
5560
- cost_output_per_1m: profile.costOutputPer1m,
5561
- lowering: profile.lowering,
5562
- recovery: profile.recovery,
5563
- strengths: profile.strengths,
5564
- weaknesses: profile.weaknesses,
5565
- notes: profile.notes ?? null,
5566
- archetype_perf: profile.archetypePerf ?? null,
5567
- active: opts.active ?? true
5568
- };
5569
- if (opts.verifiedAgainstDocs !== void 0) {
5570
- row.verified_against_docs = opts.verifiedAgainstDocs;
5571
- } else if (profile.verifiedAgainstDocs !== void 0) {
5572
- const v = profile.verifiedAgainstDocs;
5573
- row.verified_against_docs = /^\d{4}-\d{2}-\d{2}/.test(v) ? v : null;
5574
- }
5575
- if (opts.versionAdded !== void 0) row.version_added = opts.versionAdded;
5576
- if (opts.versionRemoved !== void 0) row.version_removed = opts.versionRemoved;
5577
- return row;
5578
- }
5579
- function mapRowsToModels(rows) {
5580
- const out = /* @__PURE__ */ new Map();
5581
- for (const row of rows) {
5582
- if (!isModelRow(row)) continue;
5583
- const profile = rowToProfile(row);
5584
- if (profile) out.set(profile.id, profile);
5585
- }
5586
- return out;
5587
- }
5588
- function mapRowsToAliases(rows) {
5589
- const out = {};
5590
- for (const row of rows) {
5591
- if (!isAliasRow(row)) continue;
5592
- out[row.alias_id] = row.canonical_id;
5593
- }
5594
- return out;
5595
- }
5596
- function bundledModels() {
5597
- return new Map(allProfilesRaw().map((p) => [p.id, p]));
5598
- }
5599
- function bundledAliases() {
5600
- return { ...ALIASES };
5601
- }
5602
- var loadModelsFromBrain = createBrainQueryCache({
5603
- table: "kgauto_models",
5604
- mapRows: mapRowsToModels,
5605
- bundledFallback: bundledModels
5606
- });
5607
- var loadAliasesFromBrain = createBrainQueryCache({
5608
- table: "kgauto_aliases",
5609
- mapRows: mapRowsToAliases,
5610
- bundledFallback: bundledAliases
5611
- });
5612
- _setProfileBrainHook({
5613
- getProfile: (canonical) => loadModelsFromBrain().get(canonical),
5614
- resolveAlias: (id) => loadAliasesFromBrain()[id]
5615
- });
5616
-
5617
6185
  // src/index.ts
5618
6186
  function compile2(ir, opts) {
5619
6187
  const result = compile(ir, opts);
@@ -5629,6 +6197,7 @@ function compile2(ir, opts) {
5629
6197
  CallError,
5630
6198
  DEFAULT_FINDINGS_ENDPOINT,
5631
6199
  DIALECT_VERSION,
6200
+ FamilyResolutionError,
5632
6201
  INTENT_ARCHETYPES,
5633
6202
  MEASURED_GROUNDING_MIN_N,
5634
6203
  PROVIDER_ENV_KEYS,
@@ -5646,6 +6215,7 @@ function compile2(ir, opts) {
5646
6215
  compile,
5647
6216
  configureBrain,
5648
6217
  countTokens,
6218
+ deriveFamilyFromModelId,
5649
6219
  execute,
5650
6220
  getActionableAdvisories,
5651
6221
  getAllStarterChains,
@@ -5657,6 +6227,7 @@ function compile2(ir, opts) {
5657
6227
  getPerAxisMetrics,
5658
6228
  getProfile,
5659
6229
  getReachabilityDiagnostic,
6230
+ getRecommendedPrimary,
5660
6231
  getSequentialStarterChain,
5661
6232
  getSequentialStarterChainWithGrounding,
5662
6233
  getStaleExclusionFindings,
@@ -5677,6 +6248,7 @@ function compile2(ir, opts) {
5677
6248
  loadPricingFromBrain,
5678
6249
  markAdvisoryResolved,
5679
6250
  markExclusionFindingHandled,
6251
+ markPromoteReadyHandled,
5680
6252
  profileToRow,
5681
6253
  profilesByProvider,
5682
6254
  record,