@warmdrift/kgauto-compiler 2.0.0-alpha.28 → 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/README.md +42 -0
- package/dist/glassbox/index.d.mts +3 -3
- package/dist/glassbox/index.d.ts +3 -3
- package/dist/glassbox-routes/index.d.mts +31 -2
- package/dist/glassbox-routes/index.d.ts +31 -2
- package/dist/glassbox-routes/index.js +39 -0
- package/dist/glassbox-routes/index.mjs +39 -0
- package/dist/index.d.mts +292 -13
- package/dist/index.d.ts +292 -13
- package/dist/index.js +385 -8
- package/dist/index.mjs +380 -8
- package/dist/{ir-5W0efxt9.d.ts → ir-BIAT9gJk.d.ts} +110 -1
- package/dist/{ir-MXCJA8L7.d.mts → ir-De2AQtlr.d.mts} +110 -1
- package/dist/profiles.d.mts +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/{types-sDZQzPM6.d.mts → types-BjrIFPGe.d.mts} +1 -1
- package/dist/{types-CiZ9HLIU.d.ts → types-D_JAhCv4.d.ts} +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -475,6 +475,7 @@ function lowerAnthropic(ir, profile, hints) {
|
|
|
475
475
|
const historyCacheableTokens = markIndex >= 0 ? sumHistoryTokens(history, markIndex) : 0;
|
|
476
476
|
const totalCacheableTokens = cacheableTokens + historyCacheableTokens;
|
|
477
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;
|
|
478
479
|
return {
|
|
479
480
|
request: {
|
|
480
481
|
provider: "anthropic",
|
|
@@ -486,7 +487,8 @@ function lowerAnthropic(ir, profile, hints) {
|
|
|
486
487
|
// floor surprised every consumer once (PB-Cairn contract-gaps brief, Gap 3).
|
|
487
488
|
// Profile is the single source of truth; consumers wanting a tighter
|
|
488
489
|
// budget can pass providerOverrides.anthropic.max_tokens explicitly.
|
|
489
|
-
max_tokens: hints.forceTerseOutput ? 200 : profile.maxOutputTokens
|
|
490
|
+
max_tokens: hints.forceTerseOutput ? 200 : profile.maxOutputTokens,
|
|
491
|
+
tool_choice: toolChoice
|
|
490
492
|
},
|
|
491
493
|
diagnostics: {
|
|
492
494
|
cacheableTokens,
|
|
@@ -680,6 +682,7 @@ function lowerOpenAI(ir, profile, hints) {
|
|
|
680
682
|
const history = (ir.history ?? []).filter((m) => m.role !== "system");
|
|
681
683
|
const histMarkIndex = resolveHistoryMarkIndex(history.length, ir.historyCachePolicy);
|
|
682
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;
|
|
683
686
|
return {
|
|
684
687
|
request: {
|
|
685
688
|
provider: "openai",
|
|
@@ -687,7 +690,8 @@ function lowerOpenAI(ir, profile, hints) {
|
|
|
687
690
|
messages,
|
|
688
691
|
tools: ir.tools && ir.tools.length > 0 ? toOpenAITools(ir.tools) : void 0,
|
|
689
692
|
response_format: ir.constraints?.structuredOutput ? { type: "json_object" } : void 0,
|
|
690
|
-
reasoning_effort: hints.forceTerseOutput ? "low" : void 0
|
|
693
|
+
reasoning_effort: hints.forceTerseOutput ? "low" : void 0,
|
|
694
|
+
parallel_tool_calls: openaiParallelToolCalls
|
|
691
695
|
},
|
|
692
696
|
diagnostics: {
|
|
693
697
|
cacheableTokens: 0,
|
|
@@ -837,9 +841,19 @@ function runAdvisor(ir, result, profile, policy, phase2) {
|
|
|
837
841
|
out.push(...detectModelStaleEvidence(ir, profile));
|
|
838
842
|
out.push(...detectTierDown(ir, profile, phase2));
|
|
839
843
|
}
|
|
840
|
-
|
|
844
|
+
if (!translatorClearedToolCallCliff(phase2)) {
|
|
845
|
+
out.push(...detectArchetypePerfFloorBreach(ir, profile));
|
|
846
|
+
}
|
|
841
847
|
return out;
|
|
842
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
|
+
}
|
|
843
857
|
function detectCachingOff(ir, profile) {
|
|
844
858
|
if (profile.provider !== "anthropic") return [];
|
|
845
859
|
const totalChars = ir.sections.reduce((s, sec) => s + sec.text.length, 0);
|
|
@@ -1039,6 +1053,47 @@ function detectArchetypePerfFloorBreach(ir, profile) {
|
|
|
1039
1053
|
];
|
|
1040
1054
|
}
|
|
1041
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
|
+
}
|
|
1096
|
+
|
|
1042
1097
|
// src/compile.ts
|
|
1043
1098
|
var counter = 0;
|
|
1044
1099
|
function makeHandle() {
|
|
@@ -1082,9 +1137,33 @@ function compile(ir, opts = {}) {
|
|
|
1082
1137
|
const cliffs = passApplyCliffs(workingIR, profile, inputTokens);
|
|
1083
1138
|
workingIR = cliffs.value.ir;
|
|
1084
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
|
+
}
|
|
1085
1163
|
const lowered = lower(workingIR, profile, {
|
|
1086
1164
|
forceThinkingZero: cliffs.value.loweringHints.forceThinkingZero,
|
|
1087
|
-
forceTerseOutput: cliffs.value.loweringHints.forceTerseOutput
|
|
1165
|
+
forceTerseOutput: cliffs.value.loweringHints.forceTerseOutput,
|
|
1166
|
+
wireOverrides
|
|
1088
1167
|
});
|
|
1089
1168
|
validateFinalFit(workingIR, profile, inputTokens);
|
|
1090
1169
|
const handle = makeHandle();
|
|
@@ -1132,7 +1211,13 @@ function compile(ir, opts = {}) {
|
|
|
1132
1211
|
opts.policy,
|
|
1133
1212
|
{
|
|
1134
1213
|
fallbackChain,
|
|
1135
|
-
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
|
|
1136
1221
|
}
|
|
1137
1222
|
);
|
|
1138
1223
|
return {
|
|
@@ -1145,7 +1230,9 @@ function compile(ir, opts = {}) {
|
|
|
1145
1230
|
mutationsApplied: accumulatedMutations,
|
|
1146
1231
|
fallbackChain,
|
|
1147
1232
|
advisories,
|
|
1148
|
-
diagnostics
|
|
1233
|
+
diagnostics,
|
|
1234
|
+
sectionRewritesApplied,
|
|
1235
|
+
wireOverrides
|
|
1149
1236
|
};
|
|
1150
1237
|
}
|
|
1151
1238
|
function validateIR(ir) {
|
|
@@ -1318,7 +1405,11 @@ function registerCompile(appId, archetype, ir, result) {
|
|
|
1318
1405
|
// alpha.28: shape fields for Glass-Box renderer.
|
|
1319
1406
|
toolsCount,
|
|
1320
1407
|
historyDepth,
|
|
1321
|
-
systemPromptChars
|
|
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
|
|
1322
1413
|
});
|
|
1323
1414
|
}
|
|
1324
1415
|
function estimateSystemPromptChars(sections) {
|
|
@@ -1454,7 +1545,11 @@ function buildPayload(input, reg) {
|
|
|
1454
1545
|
history_depth: input.historyDepth ?? reg?.historyDepth,
|
|
1455
1546
|
system_prompt_chars: input.systemPromptChars ?? reg?.systemPromptChars,
|
|
1456
1547
|
fell_over_from: fellOverFrom,
|
|
1457
|
-
fallback_reason: fallbackReason
|
|
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
|
|
1458
1553
|
};
|
|
1459
1554
|
}
|
|
1460
1555
|
function computeCostUsd(modelId, tokensIn, tokensOut) {
|
|
@@ -2209,6 +2304,278 @@ function clamp(n) {
|
|
|
2209
2304
|
return Math.max(0, Math.min(1, n));
|
|
2210
2305
|
}
|
|
2211
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
|
+
|
|
2212
2579
|
// src/models-brain.ts
|
|
2213
2580
|
function isModelRow(x) {
|
|
2214
2581
|
if (!x || typeof x !== "object") return false;
|
|
@@ -2344,7 +2711,10 @@ export {
|
|
|
2344
2711
|
INTENT_ARCHETYPES,
|
|
2345
2712
|
MEASURED_GROUNDING_MIN_N,
|
|
2346
2713
|
PROVIDER_ENV_KEYS,
|
|
2714
|
+
RULE_SEQUENTIAL_TOOL_CLIFF,
|
|
2715
|
+
TRANSLATOR_FLOOR,
|
|
2347
2716
|
allProfiles,
|
|
2717
|
+
applySectionRewrites,
|
|
2348
2718
|
bucketContext,
|
|
2349
2719
|
bucketHistory,
|
|
2350
2720
|
bucketToolCount,
|
|
@@ -2355,6 +2725,7 @@ export {
|
|
|
2355
2725
|
configureBrain,
|
|
2356
2726
|
countTokens,
|
|
2357
2727
|
execute,
|
|
2728
|
+
getActionableAdvisories,
|
|
2358
2729
|
getAllStarterChains,
|
|
2359
2730
|
getAllStarterChainsWithGrounding,
|
|
2360
2731
|
getArchetypePerfScore,
|
|
@@ -2380,6 +2751,7 @@ export {
|
|
|
2380
2751
|
loadChainsFromBrain,
|
|
2381
2752
|
loadModelsFromBrain,
|
|
2382
2753
|
loadPricingFromBrain,
|
|
2754
|
+
markAdvisoryResolved,
|
|
2383
2755
|
profileToRow,
|
|
2384
2756
|
profilesByProvider,
|
|
2385
2757
|
record,
|
|
@@ -40,7 +40,41 @@ interface PromptSection {
|
|
|
40
40
|
* Defaults to insertion order.
|
|
41
41
|
*/
|
|
42
42
|
weight?: number;
|
|
43
|
+
/**
|
|
44
|
+
* alpha.29+ — declares the section's semantic kind so kgauto can apply
|
|
45
|
+
* model-aware rewrites at compile time. Default `'arbitrary'` (when
|
|
46
|
+
* unset) for full back-compat — pre-alpha.29 sections continue working
|
|
47
|
+
* unchanged.
|
|
48
|
+
*
|
|
49
|
+
* alpha.29 ships rewrites for `tool_call_contract` only. Other kinds are
|
|
50
|
+
* type-accepted but pass through. alpha.30+ will add rewrites for
|
|
51
|
+
* `narration_contract`, `role_intro`, etc.
|
|
52
|
+
*
|
|
53
|
+
* See `translator.ts` for the rewrite engine that consumes this field.
|
|
54
|
+
*/
|
|
55
|
+
kind?: SectionKind;
|
|
43
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* alpha.29+ — semantic kind tag for a `PromptSection`. The translator
|
|
59
|
+
* (`v2/src/translator.ts`) consumes this to apply model-aware rewrites at
|
|
60
|
+
* compile time. CLOSED union; future kinds extend it explicitly in named
|
|
61
|
+
* alpha releases.
|
|
62
|
+
*
|
|
63
|
+
* alpha.29 ships rewrites for `tool_call_contract` only. Other kinds are
|
|
64
|
+
* type-accepted but pass through.
|
|
65
|
+
*
|
|
66
|
+
* - `role_intro` — "You are a helpful assistant", persona blocks
|
|
67
|
+
* - `tool_call_contract` — tool-use rules ("call X then Y"); the alpha.29
|
|
68
|
+
* translator rewrites this for models with a
|
|
69
|
+
* sequential-tool cliff on the active archetype
|
|
70
|
+
* - `narration_contract` — output-format rules ("don't narrate your steps");
|
|
71
|
+
* alpha.30+ candidate
|
|
72
|
+
* - `user_turn` — when sections carry user content rather than
|
|
73
|
+
* system context (rare)
|
|
74
|
+
* - `reference` — supporting reference data the model may consult
|
|
75
|
+
* - `arbitrary` — explicit pass-through (default when unset)
|
|
76
|
+
*/
|
|
77
|
+
type SectionKind = 'role_intro' | 'tool_call_contract' | 'narration_contract' | 'user_turn' | 'reference' | 'arbitrary';
|
|
44
78
|
interface ToolDefinition {
|
|
45
79
|
name: string;
|
|
46
80
|
description?: string;
|
|
@@ -262,6 +296,18 @@ type CompiledRequest = {
|
|
|
262
296
|
}>;
|
|
263
297
|
tools?: unknown[];
|
|
264
298
|
max_tokens?: number;
|
|
299
|
+
/**
|
|
300
|
+
* alpha.29 — emitted only when the translator's wire-overrides set
|
|
301
|
+
* `parallelToolCalls = false`. Shape per Anthropic Messages API docs:
|
|
302
|
+
* `{ type: 'auto', disable_parallel_tool_use: true }`. kgauto defaults
|
|
303
|
+
* to omitting `tool_choice` entirely (Anthropic defaults to auto + parallel),
|
|
304
|
+
* so this field's presence signals an explicit override.
|
|
305
|
+
*/
|
|
306
|
+
tool_choice?: {
|
|
307
|
+
type: 'auto' | 'any' | 'tool' | 'none';
|
|
308
|
+
disable_parallel_tool_use?: boolean;
|
|
309
|
+
name?: string;
|
|
310
|
+
};
|
|
265
311
|
} | {
|
|
266
312
|
provider: 'google';
|
|
267
313
|
model: string;
|
|
@@ -288,6 +334,12 @@ type CompiledRequest = {
|
|
|
288
334
|
tools?: unknown[];
|
|
289
335
|
response_format?: unknown;
|
|
290
336
|
reasoning_effort?: string;
|
|
337
|
+
/**
|
|
338
|
+
* alpha.29 — emitted only when the translator's wire-overrides set
|
|
339
|
+
* `parallelToolCalls = false`. OpenAI defaults parallel_tool_calls=true
|
|
340
|
+
* server-side; we explicit-set to false only when overriding.
|
|
341
|
+
*/
|
|
342
|
+
parallel_tool_calls?: boolean;
|
|
291
343
|
} | {
|
|
292
344
|
provider: 'deepseek';
|
|
293
345
|
model: string;
|
|
@@ -397,6 +449,40 @@ type Adapter = {
|
|
|
397
449
|
value: 'sequential';
|
|
398
450
|
consequence: string;
|
|
399
451
|
};
|
|
452
|
+
/**
|
|
453
|
+
* alpha.29+ — record of a single section rewrite fired by the translator at
|
|
454
|
+
* compile time. Surfaces on `CompileResult.sectionRewritesApplied` and (in
|
|
455
|
+
* scrubbed wire form, without original/transformed text) on
|
|
456
|
+
* `TraceDetail.sectionRewritesApplied` for Glass-Box Coaching-card rendering.
|
|
457
|
+
*
|
|
458
|
+
* `originalText` / `transformedText` stay package-internal — they may carry
|
|
459
|
+
* consumer PII. The wire-shape variant (`TraceSectionRewrite` in
|
|
460
|
+
* `glassbox-routes/types.ts`) carries only `summary` for renderer use.
|
|
461
|
+
*/
|
|
462
|
+
interface SectionRewrite {
|
|
463
|
+
/** Stable id of the `PromptSection` that was rewritten. */
|
|
464
|
+
sectionId: string;
|
|
465
|
+
/** The `kind` discriminator that matched the rewrite rule. */
|
|
466
|
+
kind: SectionKind;
|
|
467
|
+
/**
|
|
468
|
+
* Stable identifier of the rule that fired (e.g.
|
|
469
|
+
* `'sequential-tool-cliff-below-floor'`). Future rules add named ids; the
|
|
470
|
+
* brain aggregates by this value for cross-app learning.
|
|
471
|
+
*/
|
|
472
|
+
rule: string;
|
|
473
|
+
/** The section's text BEFORE the rewrite fired. */
|
|
474
|
+
originalText: string;
|
|
475
|
+
/** The text the translator emitted into the IR for this section. */
|
|
476
|
+
transformedText: string;
|
|
477
|
+
/**
|
|
478
|
+
* Wire-level overrides emitted alongside the text rewrite. Merged into
|
|
479
|
+
* `CompileResult.wireOverrides` by `applySectionRewrites`. alpha.29 ships
|
|
480
|
+
* `parallelToolCalls`; the union extends as more wire-overrides surface.
|
|
481
|
+
*/
|
|
482
|
+
wireOverrides?: {
|
|
483
|
+
parallelToolCalls?: boolean;
|
|
484
|
+
};
|
|
485
|
+
}
|
|
400
486
|
interface CompileResult {
|
|
401
487
|
/** Unique handle for this call — pass to record() to correlate the outcome. */
|
|
402
488
|
handle: string;
|
|
@@ -419,6 +505,29 @@ interface CompileResult {
|
|
|
419
505
|
* array when no rules fired. alpha.6 Phase 1.
|
|
420
506
|
*/
|
|
421
507
|
advisories: BestPracticeAdvisory[];
|
|
508
|
+
/**
|
|
509
|
+
* alpha.29+ — per-section rewrites applied by the translator at compile
|
|
510
|
+
* time. Empty array means no rewrites fired (or pre-alpha.29 behavior —
|
|
511
|
+
* all sections default `kind: 'arbitrary'`, which is pass-through).
|
|
512
|
+
*
|
|
513
|
+
* Surfaces to:
|
|
514
|
+
* - Glass-Box Coaching card (via `TraceDetail.sectionRewritesApplied`,
|
|
515
|
+
* scrubbed of original/transformed text)
|
|
516
|
+
* - brain `compile_outcomes.section_rewrites_applied` (migration 019)
|
|
517
|
+
* for cross-app learning
|
|
518
|
+
*/
|
|
519
|
+
sectionRewritesApplied: SectionRewrite[];
|
|
520
|
+
/**
|
|
521
|
+
* alpha.29+ — wire-level overrides emitted by translator rewrites. The
|
|
522
|
+
* provider lowering pass threads these through to the wire request before
|
|
523
|
+
* emit. Today only `parallelToolCalls: boolean`; the type extends as more
|
|
524
|
+
* wire-overrides surface.
|
|
525
|
+
*
|
|
526
|
+
* Undefined when no rewrite emitted overrides — the common case.
|
|
527
|
+
*/
|
|
528
|
+
wireOverrides?: {
|
|
529
|
+
parallelToolCalls?: boolean;
|
|
530
|
+
};
|
|
422
531
|
/** Diagnostics for caller-side logging. */
|
|
423
532
|
diagnostics: {
|
|
424
533
|
sectionsKept: number;
|
|
@@ -919,4 +1028,4 @@ interface PerAxisMetrics {
|
|
|
919
1028
|
/** Per-axis metrics keyed by model — used for chain-comparison views. */
|
|
920
1029
|
type PerAxisMetricsByModel = Record<string, PerAxisMetrics>;
|
|
921
1030
|
|
|
922
|
-
export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type FallbackReason as F, type Grounding as G, type HistoryCachePolicy as H, type IntentDeclaration as I, type Message as M, type NormalizedResponse as N, type OutcomeResult as O, type ProviderOverrides as P, type RecordInput as R, type ToolCall as T, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type RecordOutcomeInput as e, type OracleScore as f, type CompileResult as g, type Adapter as h, type PerAxisMetrics as i, type Provider as j, type ChainEntry as k, type CallAttempt as l, CallError as m, type ChainWithGrounding as n, type Constraints as o, type MutationApplied as p, type NormalizedTokens as q, type OutcomeKind as r, type PerAxisMetricsByModel as s, type PromptSection as t, type
|
|
1031
|
+
export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type FallbackReason as F, type Grounding as G, type HistoryCachePolicy as H, type IntentDeclaration as I, type Message as M, type NormalizedResponse as N, type OutcomeResult as O, type ProviderOverrides as P, type RecordInput as R, type SectionRewrite as S, type ToolCall as T, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type RecordOutcomeInput as e, type OracleScore as f, type CompileResult as g, type Adapter as h, type PerAxisMetrics as i, type Provider as j, type ChainEntry as k, type CallAttempt as l, CallError as m, type ChainWithGrounding as n, type Constraints as o, type MutationApplied as p, type NormalizedTokens as q, type OutcomeKind as r, type PerAxisMetricsByModel as s, type PromptSection as t, type SectionKind as u, type ToolDefinition as v };
|