@warmdrift/kgauto-compiler 2.0.0-alpha.26 → 2.0.0-alpha.28

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,
@@ -17,7 +41,7 @@ import {
17
41
  getProfile,
18
42
  profilesByProvider,
19
43
  tryGetProfile
20
- } from "./chunk-7MTHFSNY.mjs";
44
+ } from "./chunk-JQGRWJZO.mjs";
21
45
  import {
22
46
  emitAdvisoryFired,
23
47
  emitCompileDone,
@@ -740,177 +764,6 @@ function setNestedField(obj, path, value) {
740
764
  cursor[parts[parts.length - 1]] = value;
741
765
  }
742
766
 
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
767
  // src/archetype-perf-brain.ts
915
768
  function isPerfRow(x) {
916
769
  if (!x || typeof x !== "object") return false;
@@ -984,6 +837,7 @@ function runAdvisor(ir, result, profile, policy, phase2) {
984
837
  out.push(...detectModelStaleEvidence(ir, profile));
985
838
  out.push(...detectTierDown(ir, profile, phase2));
986
839
  }
840
+ out.push(...detectArchetypePerfFloorBreach(ir, profile));
987
841
  return out;
988
842
  }
989
843
  function detectCachingOff(ir, profile) {
@@ -1154,6 +1008,36 @@ function detectTierDown(ir, profile, phase2) {
1154
1008
  }
1155
1009
  ];
1156
1010
  }
1011
+ function detectArchetypePerfFloorBreach(ir, profile) {
1012
+ const compat = getModelCompatibility(profile.id, {
1013
+ archetype: ir.intent.archetype,
1014
+ toolOrchestration: ir.constraints?.toolOrchestration
1015
+ });
1016
+ if (compat.status === "compatible") return [];
1017
+ if (compat.status === "requires-adapter") {
1018
+ return [
1019
+ {
1020
+ level: "warn",
1021
+ code: "archetype-perf-floor-breach",
1022
+ 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}`,
1023
+ 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.`,
1024
+ recommendationType: "prompt-fix",
1025
+ suggestedAdaptation: compat.adapter,
1026
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
1027
+ }
1028
+ ];
1029
+ }
1030
+ return [
1031
+ {
1032
+ level: "critical",
1033
+ code: "archetype-perf-floor-breach",
1034
+ 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}`,
1035
+ 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.`,
1036
+ recommendationType: "model-swap",
1037
+ docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
1038
+ }
1039
+ ];
1040
+ }
1157
1041
 
1158
1042
  // src/compile.ts
1159
1043
  var counter = 0;
@@ -1414,6 +1298,9 @@ function registerCompile(appId, archetype, ir, result) {
1414
1298
  tokens
1415
1299
  );
1416
1300
  const shapeKey = `${shape.contextBucket}-${shape.toolCountBucket}-${shape.historyDepth}-${shape.outputMode}`;
1301
+ const toolsCount = result.diagnostics.toolsKept;
1302
+ const historyDepth = Array.isArray(ir.history) ? ir.history.length : 0;
1303
+ const systemPromptChars = estimateSystemPromptChars(ir.sections);
1417
1304
  compileRegistry.set(result.handle, {
1418
1305
  appId,
1419
1306
  archetype,
@@ -1427,9 +1314,24 @@ function registerCompile(appId, archetype, ir, result) {
1427
1314
  historyCacheableTokens: result.diagnostics.historyCacheableTokens,
1428
1315
  historyTokensTotal: result.diagnostics.historyTokensTotal,
1429
1316
  // alpha.20 E3: capture consumer's declared mode for the brain payload.
1430
- toolOrchestration: result.diagnostics.toolOrchestration
1317
+ toolOrchestration: result.diagnostics.toolOrchestration,
1318
+ // alpha.28: shape fields for Glass-Box renderer.
1319
+ toolsCount,
1320
+ historyDepth,
1321
+ systemPromptChars
1431
1322
  });
1432
1323
  }
1324
+ function estimateSystemPromptChars(sections) {
1325
+ if (!Array.isArray(sections) || sections.length === 0) return void 0;
1326
+ let total = 0;
1327
+ for (const s of sections) {
1328
+ if (s && typeof s === "object") {
1329
+ const content = s.content;
1330
+ if (typeof content === "string") total += content.length;
1331
+ }
1332
+ }
1333
+ return total > 0 ? total : void 0;
1334
+ }
1433
1335
  async function record(input) {
1434
1336
  const reg = compileRegistry.get(input.handle);
1435
1337
  if (reg) compileRegistry.delete(input.handle);
@@ -1466,7 +1368,7 @@ async function record(input) {
1466
1368
  }
1467
1369
  outcomeId = await tryExtractOutcomeId(res);
1468
1370
  } catch (err) {
1469
- (config.onError ?? defaultOnError2)(err);
1371
+ (config.onError ?? defaultOnError)(err);
1470
1372
  return;
1471
1373
  }
1472
1374
  const advisories = input.advisories;
@@ -1488,7 +1390,7 @@ async function record(input) {
1488
1390
  throw new Error(`brain advisories ${res.status}: ${text}`);
1489
1391
  }
1490
1392
  } catch (err) {
1491
- (config.onError ?? defaultOnError2)(err);
1393
+ (config.onError ?? defaultOnError)(err);
1492
1394
  }
1493
1395
  };
1494
1396
  if (config.sync) {
@@ -1497,7 +1399,7 @@ async function record(input) {
1497
1399
  void send();
1498
1400
  }
1499
1401
  }
1500
- function defaultOnError2(err) {
1402
+ function defaultOnError(err) {
1501
1403
  console.warn("[kgauto] brain record failed:", err);
1502
1404
  }
1503
1405
  function buildPayload(input, reg) {
@@ -1507,6 +1409,8 @@ function buildPayload(input, reg) {
1507
1409
  const mutationsApplied = input.mutationsApplied ?? reg?.mutationsApplied ?? [];
1508
1410
  const costModel = actual;
1509
1411
  const costUsdActual = costModel ? computeCostUsd(costModel, input.tokensIn, input.tokensOut) : void 0;
1412
+ const fellOverFrom = input.fellOverFrom ?? requested;
1413
+ const fallbackReason = fellOverFrom ? input.fallbackReason : void 0;
1510
1414
  return {
1511
1415
  handle: input.handle,
1512
1416
  app_id: reg?.appId,
@@ -1541,7 +1445,16 @@ function buildPayload(input, reg) {
1541
1445
  // the brain can measure per-mode model perf separately (DeepSeek in
1542
1446
  // sequential vs parallel mode is two different stories — L-040).
1543
1447
  // Null when consumer hadn't adopted the constraint yet.
1544
- tool_orchestration: reg?.toolOrchestration ?? null
1448
+ tool_orchestration: reg?.toolOrchestration ?? null,
1449
+ // alpha.28 — Glass-Box renderer substrate (migration 018). All optional;
1450
+ // omitted-undefined PostgREST inserts store NULL → renderer renders "—".
1451
+ finish_reason: input.finishReason,
1452
+ total_ms: input.totalMs ?? input.latencyMs,
1453
+ tools_count: input.toolsCount ?? reg?.toolsCount,
1454
+ history_depth: input.historyDepth ?? reg?.historyDepth,
1455
+ system_prompt_chars: input.systemPromptChars ?? reg?.systemPromptChars,
1456
+ fell_over_from: fellOverFrom,
1457
+ fallback_reason: fallbackReason
1545
1458
  };
1546
1459
  }
1547
1460
  function computeCostUsd(modelId, tokensIn, tokensOut) {
@@ -1614,12 +1527,12 @@ async function recordOutcome(input) {
1614
1527
  if (!res.ok) {
1615
1528
  const text = await res.text().catch(() => "<no body>");
1616
1529
  const err = new Error(`brain ${res.status}: ${text}`);
1617
- (config.onError ?? defaultOnError2)(err);
1530
+ (config.onError ?? defaultOnError)(err);
1618
1531
  return { ok: false, reason: "persistence_failed" };
1619
1532
  }
1620
1533
  return { ok: true };
1621
1534
  } catch (err) {
1622
- (config.onError ?? defaultOnError2)(err);
1535
+ (config.onError ?? defaultOnError)(err);
1623
1536
  return { ok: false, reason: "persistence_failed" };
1624
1537
  }
1625
1538
  };
@@ -1644,67 +1557,6 @@ var CallError = class extends Error {
1644
1557
  }
1645
1558
  };
1646
1559
 
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
1560
  // src/execute.ts
1709
1561
  var ANTHROPIC_URL = "https://api.anthropic.com/v1/messages";
1710
1562
  var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
@@ -1923,344 +1775,6 @@ function tryParseJson(s) {
1923
1775
  }
1924
1776
  }
1925
1777
 
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
1778
  // src/call.ts
2265
1779
  async function call(ir, opts = {}) {
2266
1780
  const traceId = generateTraceId();
@@ -2438,6 +1952,8 @@ async function call(ir, opts = {}) {
2438
1952
  latencyMs: latencyMs2
2439
1953
  })
2440
1954
  );
1955
+ const fellOver = targetModel !== initial.target;
1956
+ const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
2441
1957
  await record({
2442
1958
  handle: initial.handle,
2443
1959
  tokensIn: validated.response.tokens.input,
@@ -2451,10 +1967,18 @@ async function call(ir, opts = {}) {
2451
1967
  promptPreview: extractPromptPreview(ir),
2452
1968
  responsePreview: validated.response.text.slice(0, 200),
2453
1969
  cacheReadInputTokens: validated.response.tokens.cached,
2454
- cacheCreationInputTokens: validated.response.tokens.cacheCreated
1970
+ cacheCreationInputTokens: validated.response.tokens.cacheCreated,
1971
+ // alpha.28 — Glass-Box renderer substrate (migration 018). call()
1972
+ // owns the lifecycle so it has direct visibility into finishReason
1973
+ // (from the normalized provider response), totalMs (mirrors latencyMs
1974
+ // for non-streaming; future streaming variant may diverge), and the
1975
+ // fell-over-from / fallback-reason pair (already computed above for
1976
+ // the CallResult return shape).
1977
+ finishReason: validated.response.finishReason,
1978
+ totalMs: latencyMs2,
1979
+ fellOverFrom: fellOver ? initial.target : void 0,
1980
+ fallbackReason
2455
1981
  });
2456
- const fellOver = targetModel !== initial.target;
2457
- const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
2458
1982
  if (fellOver) {
2459
1983
  const firstFailed = attempts.find((a) => a.status !== "success");
2460
1984
  if (firstFailed) {
@@ -2811,8 +2335,10 @@ function compile2(ir, opts) {
2811
2335
  return result;
2812
2336
  }
2813
2337
  export {
2338
+ ABSOLUTE_FLOOR,
2814
2339
  ALIASES,
2815
2340
  ALL_ARCHETYPES,
2341
+ ARCHETYPE_FLOOR_DEFAULT,
2816
2342
  CallError,
2817
2343
  DIALECT_VERSION,
2818
2344
  INTENT_ARCHETYPES,
@@ -2834,6 +2360,7 @@ export {
2834
2360
  getArchetypePerfScore,
2835
2361
  getDefaultFallbackChain,
2836
2362
  getDefaultFallbackChainWithGrounding,
2363
+ getModelCompatibility,
2837
2364
  getPerAxisMetrics,
2838
2365
  getProfile,
2839
2366
  getReachabilityDiagnostic,