@warmdrift/kgauto-compiler 2.0.0-alpha.5 → 2.0.0-alpha.52
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 +140 -3
- package/dist/chunk-CXH7KC4D.mjs +1413 -0
- package/dist/chunk-HHWBB46W.mjs +694 -0
- package/dist/chunk-NBO4R5PC.mjs +313 -0
- package/dist/chunk-P3TOAEG4.mjs +56 -0
- package/dist/chunk-RO22VFIF.mjs +29 -0
- package/dist/glassbox/index.d.mts +59 -0
- package/dist/glassbox/index.d.ts +59 -0
- package/dist/glassbox/index.js +312 -0
- package/dist/glassbox/index.mjs +12 -0
- package/dist/glassbox-routes/format.d.mts +24 -0
- package/dist/glassbox-routes/format.d.ts +24 -0
- package/dist/glassbox-routes/format.js +86 -0
- package/dist/glassbox-routes/format.mjs +18 -0
- package/dist/glassbox-routes/index.d.mts +191 -0
- package/dist/glassbox-routes/index.d.ts +191 -0
- package/dist/glassbox-routes/index.js +2657 -0
- package/dist/glassbox-routes/index.mjs +663 -0
- package/dist/glassbox-routes/react/index.d.mts +74 -0
- package/dist/glassbox-routes/react/index.d.ts +74 -0
- package/dist/glassbox-routes/react/index.js +819 -0
- package/dist/glassbox-routes/react/index.mjs +754 -0
- package/dist/index.d.mts +2150 -14
- package/dist/index.d.ts +2150 -14
- package/dist/index.js +6367 -1085
- package/dist/index.mjs +3470 -175
- package/dist/ir-dDcG8Pvu.d.mts +1337 -0
- package/dist/ir-rUUojj0s.d.ts +1337 -0
- package/dist/profiles.d.mts +292 -2
- package/dist/profiles.d.ts +292 -2
- package/dist/profiles.js +1024 -16
- package/dist/profiles.mjs +9 -1
- package/dist/types-BTeRoSvM.d.mts +149 -0
- package/dist/types-B_pdPjxm.d.ts +149 -0
- package/dist/types-UXPxWabQ.d.ts +131 -0
- package/dist/types-vGo-h0tZ.d.mts +131 -0
- package/package.json +42 -6
- package/dist/chunk-MBEI5UOM.mjs +0 -409
- package/dist/profiles-DHdCRBVH.d.mts +0 -571
- package/dist/profiles-MGq5Tnjv.d.ts +0 -571
package/dist/index.mjs
CHANGED
|
@@ -9,13 +9,441 @@ 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
|
+
readBrainReadEnv,
|
|
35
|
+
resolveProviderKey
|
|
36
|
+
} from "./chunk-HHWBB46W.mjs";
|
|
12
37
|
import {
|
|
13
38
|
ALIASES,
|
|
39
|
+
LATENCY_TIER_MS,
|
|
40
|
+
_setProfileBrainHook,
|
|
14
41
|
allProfiles,
|
|
42
|
+
allProfilesRaw,
|
|
15
43
|
getProfile,
|
|
44
|
+
latencyTierOf,
|
|
16
45
|
profilesByProvider,
|
|
17
46
|
tryGetProfile
|
|
18
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-CXH7KC4D.mjs";
|
|
48
|
+
import {
|
|
49
|
+
emitAdvisoryFired,
|
|
50
|
+
emitCompileDone,
|
|
51
|
+
emitCompileStart,
|
|
52
|
+
emitExecuteAttempt,
|
|
53
|
+
emitExecuteSuccess,
|
|
54
|
+
emitFallbackWalked
|
|
55
|
+
} from "./chunk-NBO4R5PC.mjs";
|
|
56
|
+
|
|
57
|
+
// src/models-brain.ts
|
|
58
|
+
function isModelRow(x) {
|
|
59
|
+
if (!x || typeof x !== "object") return false;
|
|
60
|
+
const r = x;
|
|
61
|
+
return typeof r.model_id === "string" && typeof r.provider === "string";
|
|
62
|
+
}
|
|
63
|
+
function isAliasRow(x) {
|
|
64
|
+
if (!x || typeof x !== "object") return false;
|
|
65
|
+
const r = x;
|
|
66
|
+
return typeof r.alias_id === "string" && typeof r.canonical_id === "string";
|
|
67
|
+
}
|
|
68
|
+
function rowToProfile(row) {
|
|
69
|
+
try {
|
|
70
|
+
if (row.cliffs !== void 0 && row.cliffs !== null && !Array.isArray(row.cliffs)) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
if (row.recovery !== void 0 && row.recovery !== null && !Array.isArray(row.recovery)) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
if (row.lowering !== void 0 && row.lowering !== null && (typeof row.lowering !== "object" || Array.isArray(row.lowering))) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
if (row.archetype_conventions !== void 0 && row.archetype_conventions !== null && !Array.isArray(row.archetype_conventions)) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
id: row.model_id,
|
|
84
|
+
provider: row.provider,
|
|
85
|
+
status: row.status ?? "current",
|
|
86
|
+
maxContextTokens: row.max_context_tokens ?? 0,
|
|
87
|
+
maxOutputTokens: row.max_output_tokens ?? 0,
|
|
88
|
+
maxTools: row.max_tools ?? 0,
|
|
89
|
+
parallelToolCalls: row.parallel_tool_calls ?? false,
|
|
90
|
+
structuredOutput: row.structured_output ?? "none",
|
|
91
|
+
systemPromptMode: row.system_prompt_mode ?? "inline",
|
|
92
|
+
streaming: row.streaming ?? true,
|
|
93
|
+
cliffs: row.cliffs ?? [],
|
|
94
|
+
costInputPer1m: row.cost_input_per_1m ?? 0,
|
|
95
|
+
costOutputPer1m: row.cost_output_per_1m ?? 0,
|
|
96
|
+
lowering: row.lowering ?? { system: { mode: "inline" }, cache: { strategy: "unsupported" } },
|
|
97
|
+
recovery: row.recovery ?? [],
|
|
98
|
+
strengths: row.strengths ?? [],
|
|
99
|
+
weaknesses: row.weaknesses ?? [],
|
|
100
|
+
notes: row.notes ?? void 0,
|
|
101
|
+
verifiedAgainstDocs: row.verified_against_docs ?? void 0,
|
|
102
|
+
archetypePerf: row.archetype_perf ?? void 0,
|
|
103
|
+
// alpha.41 — family-resolution fields. `family` may be null pre-
|
|
104
|
+
// migration 024; runtime falls back to deriveFamilyFromModelId at
|
|
105
|
+
// resolution time (see family-resolution.ts, G1).
|
|
106
|
+
family: row.family ?? void 0,
|
|
107
|
+
versionAdded: row.version_added ?? void 0,
|
|
108
|
+
active: row.active ?? void 0,
|
|
109
|
+
// alpha.49 — executable-knowledge fields (migration 028). Invalid
|
|
110
|
+
// latency_tier → undefined (latencyTierOf derives from tags; not
|
|
111
|
+
// safety-critical). archetype_conventions already array-validated above.
|
|
112
|
+
latencyTier: normalizeLatencyTier(row.latency_tier),
|
|
113
|
+
archetypeConventions: row.archetype_conventions ?? void 0
|
|
114
|
+
};
|
|
115
|
+
} catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
var VALID_LATENCY_TIERS = /* @__PURE__ */ new Set(["fast", "medium", "slow"]);
|
|
120
|
+
function normalizeLatencyTier(v) {
|
|
121
|
+
return typeof v === "string" && VALID_LATENCY_TIERS.has(v) ? v : void 0;
|
|
122
|
+
}
|
|
123
|
+
function profileToRow(profile, opts = {}) {
|
|
124
|
+
const row = {
|
|
125
|
+
model_id: profile.id,
|
|
126
|
+
provider: profile.provider,
|
|
127
|
+
status: profile.status,
|
|
128
|
+
max_context_tokens: profile.maxContextTokens,
|
|
129
|
+
max_output_tokens: profile.maxOutputTokens,
|
|
130
|
+
max_tools: profile.maxTools,
|
|
131
|
+
parallel_tool_calls: profile.parallelToolCalls,
|
|
132
|
+
structured_output: profile.structuredOutput,
|
|
133
|
+
system_prompt_mode: profile.systemPromptMode,
|
|
134
|
+
streaming: profile.streaming,
|
|
135
|
+
cliffs: profile.cliffs,
|
|
136
|
+
cost_input_per_1m: profile.costInputPer1m,
|
|
137
|
+
cost_output_per_1m: profile.costOutputPer1m,
|
|
138
|
+
lowering: profile.lowering,
|
|
139
|
+
recovery: profile.recovery,
|
|
140
|
+
strengths: profile.strengths,
|
|
141
|
+
weaknesses: profile.weaknesses,
|
|
142
|
+
notes: profile.notes ?? null,
|
|
143
|
+
archetype_perf: profile.archetypePerf ?? null,
|
|
144
|
+
active: opts.active ?? profile.active ?? true,
|
|
145
|
+
// alpha.41 — round-trip family + version_added when present on profile.
|
|
146
|
+
// version_added is operator-controlled via opts; profile-side value is
|
|
147
|
+
// used only when opts didn't override.
|
|
148
|
+
family: profile.family ?? null,
|
|
149
|
+
// alpha.49 — round-trip the executable-knowledge fields (migration 028)
|
|
150
|
+
// so a reseed from bundled profiles makes the latency lever + schema
|
|
151
|
+
// conventions live warm. Closes the silently-dropped-field gap.
|
|
152
|
+
latency_tier: profile.latencyTier ?? null,
|
|
153
|
+
archetype_conventions: profile.archetypeConventions ?? null
|
|
154
|
+
};
|
|
155
|
+
if (opts.verifiedAgainstDocs !== void 0) {
|
|
156
|
+
row.verified_against_docs = opts.verifiedAgainstDocs;
|
|
157
|
+
} else if (profile.verifiedAgainstDocs !== void 0) {
|
|
158
|
+
const v = profile.verifiedAgainstDocs;
|
|
159
|
+
row.verified_against_docs = /^\d{4}-\d{2}-\d{2}/.test(v) ? v : null;
|
|
160
|
+
}
|
|
161
|
+
if (opts.versionAdded !== void 0) row.version_added = opts.versionAdded;
|
|
162
|
+
else if (profile.versionAdded !== void 0) row.version_added = profile.versionAdded;
|
|
163
|
+
if (opts.versionRemoved !== void 0) row.version_removed = opts.versionRemoved;
|
|
164
|
+
return row;
|
|
165
|
+
}
|
|
166
|
+
function mapRowsToModels(rows) {
|
|
167
|
+
const out = /* @__PURE__ */ new Map();
|
|
168
|
+
for (const row of rows) {
|
|
169
|
+
if (!isModelRow(row)) continue;
|
|
170
|
+
const profile = rowToProfile(row);
|
|
171
|
+
if (profile) out.set(profile.id, profile);
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
function mapRowsToAliases(rows) {
|
|
176
|
+
const out = {};
|
|
177
|
+
for (const row of rows) {
|
|
178
|
+
if (!isAliasRow(row)) continue;
|
|
179
|
+
out[row.alias_id] = row.canonical_id;
|
|
180
|
+
}
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
function bundledModels() {
|
|
184
|
+
return new Map(allProfilesRaw().map((p) => [p.id, p]));
|
|
185
|
+
}
|
|
186
|
+
function bundledAliases() {
|
|
187
|
+
return { ...ALIASES };
|
|
188
|
+
}
|
|
189
|
+
var loadModelsFromBrain = createBrainQueryCache({
|
|
190
|
+
table: "kgauto_models",
|
|
191
|
+
mapRows: mapRowsToModels,
|
|
192
|
+
bundledFallback: bundledModels
|
|
193
|
+
});
|
|
194
|
+
var loadAliasesFromBrain = createBrainQueryCache({
|
|
195
|
+
table: "kgauto_aliases",
|
|
196
|
+
mapRows: mapRowsToAliases,
|
|
197
|
+
bundledFallback: bundledAliases
|
|
198
|
+
});
|
|
199
|
+
_setProfileBrainHook({
|
|
200
|
+
getProfile: (canonical) => loadModelsFromBrain().get(canonical),
|
|
201
|
+
resolveAlias: (id) => loadAliasesFromBrain()[id]
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// src/exclusion-findings-brain.ts
|
|
205
|
+
function isValidVerdict(v) {
|
|
206
|
+
return v === "recommend-probe" || v === "unblock" || v === "stay-excluded" || v === "inconclusive";
|
|
207
|
+
}
|
|
208
|
+
function isValidConfidence(v) {
|
|
209
|
+
return v === "high" || v === "medium" || v === "low";
|
|
210
|
+
}
|
|
211
|
+
function isRawFindingRow(x) {
|
|
212
|
+
if (!x || typeof x !== "object") return false;
|
|
213
|
+
const r = x;
|
|
214
|
+
return typeof r.intent_archetype === "string" && typeof r.excluded_model === "string" && typeof r.excluded_provider === "string" && typeof r.verdict === "string" && typeof r.message === "string" && typeof r.suggestion === "string" && typeof r.confidence === "string";
|
|
215
|
+
}
|
|
216
|
+
function mapRowsToFindings(rows) {
|
|
217
|
+
const out = [];
|
|
218
|
+
for (const row of rows) {
|
|
219
|
+
if (!isRawFindingRow(row)) continue;
|
|
220
|
+
if (!isValidVerdict(row.verdict)) continue;
|
|
221
|
+
if (!isValidConfidence(row.confidence)) continue;
|
|
222
|
+
let savings = null;
|
|
223
|
+
if (typeof row.estimated_savings_usd_30d === "number") {
|
|
224
|
+
savings = Number.isFinite(row.estimated_savings_usd_30d) ? row.estimated_savings_usd_30d : null;
|
|
225
|
+
} else if (typeof row.estimated_savings_usd_30d === "string") {
|
|
226
|
+
const n = Number(row.estimated_savings_usd_30d);
|
|
227
|
+
savings = Number.isFinite(n) ? n : null;
|
|
228
|
+
}
|
|
229
|
+
out.push({
|
|
230
|
+
archetype: row.intent_archetype,
|
|
231
|
+
excludedModel: row.excluded_model,
|
|
232
|
+
excludedProvider: row.excluded_provider,
|
|
233
|
+
verdict: row.verdict,
|
|
234
|
+
estimatedSavingsUsd30d: savings,
|
|
235
|
+
message: row.message,
|
|
236
|
+
suggestion: row.suggestion,
|
|
237
|
+
confidence: row.confidence,
|
|
238
|
+
evidence: row.evidence && typeof row.evidence === "object" ? row.evidence : void 0
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
return out;
|
|
242
|
+
}
|
|
243
|
+
var snapshots = /* @__PURE__ */ new Map();
|
|
244
|
+
var runtime;
|
|
245
|
+
var warnedOnce = false;
|
|
246
|
+
var DEFAULT_FINDINGS_ENDPOINT = "https://kgauto-dashboard.vercel.app/api/kgauto-v2/findings/exclusions";
|
|
247
|
+
function configureExclusionFindingsBrain(rt) {
|
|
248
|
+
runtime = rt;
|
|
249
|
+
snapshots.clear();
|
|
250
|
+
warnedOnce = false;
|
|
251
|
+
}
|
|
252
|
+
function isExclusionFindingsBrainActive() {
|
|
253
|
+
return runtime !== void 0;
|
|
254
|
+
}
|
|
255
|
+
function getStaleExclusionFindings(opts) {
|
|
256
|
+
const rt = runtime;
|
|
257
|
+
if (!rt) return [];
|
|
258
|
+
const appId = opts.appId;
|
|
259
|
+
if (!appId) return [];
|
|
260
|
+
let snap = snapshots.get(appId);
|
|
261
|
+
if (!snap) {
|
|
262
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
263
|
+
snapshots.set(appId, snap);
|
|
264
|
+
}
|
|
265
|
+
const now = Date.now();
|
|
266
|
+
const stale = snap.expiresAt <= now;
|
|
267
|
+
if (stale && !snap.refreshing) {
|
|
268
|
+
snap.refreshing = true;
|
|
269
|
+
void asyncRefresh(rt, appId);
|
|
270
|
+
}
|
|
271
|
+
if (opts.archetype) {
|
|
272
|
+
return snap.data.filter((f) => f.archetype === opts.archetype);
|
|
273
|
+
}
|
|
274
|
+
return snap.data;
|
|
275
|
+
}
|
|
276
|
+
var pendingRefreshes = /* @__PURE__ */ new Map();
|
|
277
|
+
async function asyncRefresh(rt, appId) {
|
|
278
|
+
const promise = doRefresh(rt, appId);
|
|
279
|
+
pendingRefreshes.set(appId, promise);
|
|
280
|
+
try {
|
|
281
|
+
await promise;
|
|
282
|
+
} finally {
|
|
283
|
+
if (pendingRefreshes.get(appId) === promise) {
|
|
284
|
+
pendingRefreshes.delete(appId);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
async function doRefresh(rt, appId) {
|
|
289
|
+
const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}`;
|
|
290
|
+
let snap = snapshots.get(appId);
|
|
291
|
+
if (!snap) {
|
|
292
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
293
|
+
snapshots.set(appId, snap);
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
const res = await rt.fetchImpl(url, { method: "GET" });
|
|
297
|
+
if (!res.ok) {
|
|
298
|
+
throw new Error(`findings ${res.status}: ${res.statusText}`);
|
|
299
|
+
}
|
|
300
|
+
const body = await res.json();
|
|
301
|
+
if (runtime !== rt) return;
|
|
302
|
+
const rows = Array.isArray(body) ? mapRowsToFindings(body) : [];
|
|
303
|
+
snap.data = rows;
|
|
304
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
305
|
+
snap.refreshing = false;
|
|
306
|
+
} catch (err) {
|
|
307
|
+
if (runtime !== rt) return;
|
|
308
|
+
snap.refreshing = false;
|
|
309
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
310
|
+
if (!warnedOnce) {
|
|
311
|
+
warnedOnce = true;
|
|
312
|
+
(rt.onError ?? defaultOnError)(err);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function defaultOnError(err) {
|
|
317
|
+
console.warn(
|
|
318
|
+
"[kgauto] exclusion-findings fetch failed (using empty fallback):",
|
|
319
|
+
err
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/family-resolution.ts
|
|
324
|
+
var FamilyResolutionError = class extends Error {
|
|
325
|
+
family;
|
|
326
|
+
cause;
|
|
327
|
+
constructor(family, cause) {
|
|
328
|
+
super(
|
|
329
|
+
`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.`
|
|
330
|
+
);
|
|
331
|
+
this.name = "FamilyResolutionError";
|
|
332
|
+
this.family = family;
|
|
333
|
+
this.cause = cause;
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
function deriveFamilyFromModelId(modelId) {
|
|
337
|
+
if (typeof modelId !== "string" || modelId.length === 0) return null;
|
|
338
|
+
if (modelId.startsWith("claude-opus-")) return "claude-opus";
|
|
339
|
+
if (modelId.startsWith("claude-sonnet-")) return "claude-sonnet";
|
|
340
|
+
if (modelId.startsWith("claude-haiku-")) return "claude-haiku";
|
|
341
|
+
if (modelId.startsWith("gemini-") && modelId.includes("flash-lite")) {
|
|
342
|
+
return "gemini-flash-lite";
|
|
343
|
+
}
|
|
344
|
+
if (modelId.startsWith("gemini-") && modelId.includes("flash")) {
|
|
345
|
+
return "gemini-flash";
|
|
346
|
+
}
|
|
347
|
+
if (modelId.startsWith("gemini-") && modelId.includes("pro")) {
|
|
348
|
+
return "gemini-pro";
|
|
349
|
+
}
|
|
350
|
+
if (modelId.startsWith("deepseek-") && modelId.includes("pro")) {
|
|
351
|
+
return "deepseek-reasoner";
|
|
352
|
+
}
|
|
353
|
+
if (modelId.startsWith("deepseek-")) return "deepseek-chat";
|
|
354
|
+
if (modelId.startsWith("gpt-")) return "openai-gpt";
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
function familyOf(profile) {
|
|
358
|
+
return profile.family ?? deriveFamilyFromModelId(profile.id);
|
|
359
|
+
}
|
|
360
|
+
function archetypePerfFor(profile, archetype) {
|
|
361
|
+
if (!archetype) return 0;
|
|
362
|
+
const score = profile.archetypePerf?.[archetype];
|
|
363
|
+
return typeof score === "number" ? score : 5;
|
|
364
|
+
}
|
|
365
|
+
function selectCandidates(registry, family, archetype, appId) {
|
|
366
|
+
const out = [];
|
|
367
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
368
|
+
if (appId && archetype) {
|
|
369
|
+
const findings = getStaleExclusionFindings({ appId, archetype });
|
|
370
|
+
for (const f of findings) {
|
|
371
|
+
if (f.verdict === "stay-excluded") excluded.add(f.excludedModel);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
for (const profile of registry.values()) {
|
|
375
|
+
if (familyOf(profile) !== family) continue;
|
|
376
|
+
if (profile.status !== "current") continue;
|
|
377
|
+
if (profile.active === false) continue;
|
|
378
|
+
if (archetype) {
|
|
379
|
+
if (archetypePerfFor(profile, archetype) < ARCHETYPE_FLOOR_DEFAULT) continue;
|
|
380
|
+
}
|
|
381
|
+
if (excluded.has(profile.id)) continue;
|
|
382
|
+
out.push(profile);
|
|
383
|
+
}
|
|
384
|
+
return out;
|
|
385
|
+
}
|
|
386
|
+
function sortCandidates(candidates, archetype) {
|
|
387
|
+
const sorted = [...candidates];
|
|
388
|
+
sorted.sort((a, b) => {
|
|
389
|
+
const perfA = archetypePerfFor(a, archetype);
|
|
390
|
+
const perfB = archetypePerfFor(b, archetype);
|
|
391
|
+
if (perfA !== perfB) return perfB - perfA;
|
|
392
|
+
const vA = a.versionAdded ?? "";
|
|
393
|
+
const vB = b.versionAdded ?? "";
|
|
394
|
+
if (vA !== vB) return vA < vB ? 1 : -1;
|
|
395
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
396
|
+
});
|
|
397
|
+
return sorted;
|
|
398
|
+
}
|
|
399
|
+
function getRecommendedPrimary(opts) {
|
|
400
|
+
if (opts.posture === "locked") return opts.fallback;
|
|
401
|
+
const registry = loadModelsFromBrain();
|
|
402
|
+
const candidates = selectCandidates(
|
|
403
|
+
registry,
|
|
404
|
+
opts.family,
|
|
405
|
+
opts.archetype,
|
|
406
|
+
opts.appId
|
|
407
|
+
);
|
|
408
|
+
if (candidates.length === 0) return opts.fallback;
|
|
409
|
+
const sorted = sortCandidates(candidates, opts.archetype);
|
|
410
|
+
return sorted[0]?.id ?? opts.fallback;
|
|
411
|
+
}
|
|
412
|
+
function resolveFamilyEntry(family, ctx) {
|
|
413
|
+
if (typeof family !== "string" || family.length === 0) {
|
|
414
|
+
throw new FamilyResolutionError(
|
|
415
|
+
String(family),
|
|
416
|
+
"Family tag must be a non-empty string"
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
const registry = loadModelsFromBrain();
|
|
420
|
+
const candidates = selectCandidates(
|
|
421
|
+
registry,
|
|
422
|
+
family,
|
|
423
|
+
ctx.archetype,
|
|
424
|
+
ctx.appId
|
|
425
|
+
);
|
|
426
|
+
if (candidates.length === 0) {
|
|
427
|
+
let anyInFamily = false;
|
|
428
|
+
for (const profile of registry.values()) {
|
|
429
|
+
if (familyOf(profile) === family) {
|
|
430
|
+
anyInFamily = true;
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
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`;
|
|
435
|
+
throw new FamilyResolutionError(family, cause);
|
|
436
|
+
}
|
|
437
|
+
const sorted = sortCandidates(candidates, ctx.archetype);
|
|
438
|
+
const winner = sorted[0];
|
|
439
|
+
if (!winner) {
|
|
440
|
+
throw new FamilyResolutionError(
|
|
441
|
+
family,
|
|
442
|
+
"Candidates non-empty but sort returned undefined \u2014 internal invariant violation"
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
return winner.id;
|
|
446
|
+
}
|
|
19
447
|
|
|
20
448
|
// src/tokenizer.ts
|
|
21
449
|
var tokenizerImpl = defaultCharBasedCounter;
|
|
@@ -120,38 +548,96 @@ function passToolRelevance(ir, opts = {}) {
|
|
|
120
548
|
]
|
|
121
549
|
};
|
|
122
550
|
}
|
|
551
|
+
function totalHistoryTokens(history) {
|
|
552
|
+
let total = 0;
|
|
553
|
+
for (const m of history) {
|
|
554
|
+
if (typeof m.content === "string") total += countTokens(m.content);
|
|
555
|
+
}
|
|
556
|
+
return total;
|
|
557
|
+
}
|
|
123
558
|
function passCompressHistory(ir, opts = {}) {
|
|
124
559
|
const history = ir.history;
|
|
125
|
-
if (!history || history.length === 0)
|
|
560
|
+
if (!history || history.length === 0) {
|
|
561
|
+
return { value: ir, mutations: [], historyTokensTotal: 0 };
|
|
562
|
+
}
|
|
126
563
|
const keepRecent = opts.keepRecent ?? 4;
|
|
127
564
|
const summarizeOlderThan = opts.summarizeOlderThan ?? 8;
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
565
|
+
const summarizeAboveTokens = opts.summarizeAboveTokens;
|
|
566
|
+
const historyTokensTotal = totalHistoryTokens(history);
|
|
567
|
+
const countThresholdHit = history.length > summarizeOlderThan;
|
|
568
|
+
const tokenThresholdHit = summarizeAboveTokens !== void 0 && historyTokensTotal > summarizeAboveTokens;
|
|
569
|
+
if (!countThresholdHit && !tokenThresholdHit) {
|
|
570
|
+
return { value: ir, mutations: [], historyTokensTotal };
|
|
571
|
+
}
|
|
572
|
+
if (history.length > keepRecent) {
|
|
573
|
+
const cutIndex = history.length - keepRecent;
|
|
574
|
+
const old = history.slice(0, cutIndex);
|
|
575
|
+
const recent = history.slice(cutIndex);
|
|
576
|
+
const userTurns = old.filter((m) => m.role === "user");
|
|
577
|
+
const firstUserLine = userTurns[0]?.content.split("\n")[0]?.slice(0, 200) ?? "";
|
|
578
|
+
const oldTokens = totalHistoryTokens(old);
|
|
579
|
+
const trigger = tokenThresholdHit && !countThresholdHit ? "tokens" : "count";
|
|
580
|
+
const summary = {
|
|
581
|
+
role: "system",
|
|
582
|
+
content: `[Earlier conversation: ${old.length} turns omitted (~${oldTokens} tokens). First user message: "${firstUserLine}"]`
|
|
583
|
+
};
|
|
584
|
+
return {
|
|
585
|
+
value: { ...ir, history: [summary, ...recent] },
|
|
586
|
+
mutations: [
|
|
587
|
+
{
|
|
588
|
+
id: `compress-history-${old.length}`,
|
|
589
|
+
source: "static_pass",
|
|
590
|
+
passName: "compress_history",
|
|
591
|
+
description: trigger === "tokens" ? `Compressed ${old.length} old turns (~${oldTokens} tokens) into 1 summary \u2014 token threshold ${summarizeAboveTokens} exceeded (kept ${keepRecent} recent)` : `Compressed ${old.length} old turns into 1 summary (kept ${keepRecent} recent)`
|
|
592
|
+
}
|
|
593
|
+
],
|
|
594
|
+
historyTokensTotal
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
if (tokenThresholdHit) {
|
|
598
|
+
let fattestIdx = -1;
|
|
599
|
+
let fattestTokens = 0;
|
|
600
|
+
for (let i = 0; i < history.length; i++) {
|
|
601
|
+
const m = history[i];
|
|
602
|
+
if (!m || typeof m.content !== "string") continue;
|
|
603
|
+
const t = countTokens(m.content);
|
|
604
|
+
if (t > fattestTokens) {
|
|
605
|
+
fattestTokens = t;
|
|
606
|
+
fattestIdx = i;
|
|
146
607
|
}
|
|
147
|
-
|
|
148
|
-
|
|
608
|
+
}
|
|
609
|
+
const FAT_DOMINANCE_FLOOR = 0.3;
|
|
610
|
+
const fattest = fattestIdx >= 0 ? history[fattestIdx] : void 0;
|
|
611
|
+
if (fattest && historyTokensTotal > 0 && fattestTokens / historyTokensTotal >= FAT_DOMINANCE_FLOOR) {
|
|
612
|
+
const firstLine = fattest.content.split("\n")[0]?.slice(0, 200) ?? "";
|
|
613
|
+
const newContent = `[Earlier ${fattest.role} message content omitted: ~${fattestTokens} tokens. Preview: "${firstLine}"]`;
|
|
614
|
+
const newHistory = history.slice();
|
|
615
|
+
newHistory[fattestIdx] = { ...fattest, content: newContent };
|
|
616
|
+
return {
|
|
617
|
+
value: { ...ir, history: newHistory },
|
|
618
|
+
mutations: [
|
|
619
|
+
{
|
|
620
|
+
id: `compress-fat-message-${fattestIdx}`,
|
|
621
|
+
source: "static_pass",
|
|
622
|
+
passName: "compress_history",
|
|
623
|
+
description: `Replaced fat ${fattest.role} message #${fattestIdx} content (~${fattestTokens} of ${historyTokensTotal} tokens, ${Math.round(fattestTokens / historyTokensTotal * 100)}% of history) with summary stub \u2014 token threshold ${summarizeAboveTokens} exceeded (history.length ${history.length} <= keepRecent ${keepRecent}, slice not possible)`
|
|
624
|
+
}
|
|
625
|
+
],
|
|
626
|
+
historyTokensTotal
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return { value: ir, mutations: [], historyTokensTotal };
|
|
149
631
|
}
|
|
150
632
|
function passApplyCliffs(ir, profile, estimatedInputTokens) {
|
|
151
633
|
const mutations = [];
|
|
152
634
|
const hints = { qualityWarning: [] };
|
|
153
635
|
let nextIR = ir;
|
|
636
|
+
const sequentialMode = nextIR.constraints?.toolOrchestration === "sequential";
|
|
154
637
|
for (const cliff of profile.cliffs) {
|
|
638
|
+
if (sequentialMode && cliff.reason.includes("L-040")) {
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
155
641
|
let triggered = false;
|
|
156
642
|
switch (cliff.metric) {
|
|
157
643
|
case "input_tokens":
|
|
@@ -243,6 +729,19 @@ function passApplyCliffs(ir, profile, estimatedInputTokens) {
|
|
|
243
729
|
}
|
|
244
730
|
return { value: { ir: nextIR, loweringHints: hints }, mutations };
|
|
245
731
|
}
|
|
732
|
+
var LATENCY_OVERAGE_WEIGHT = 0.6;
|
|
733
|
+
var LATENCY_PENALTY_CAP = 1;
|
|
734
|
+
var QUALITY_GATE_PENALTY = 4;
|
|
735
|
+
function effectiveConventions(profile) {
|
|
736
|
+
const own = profile.archetypeConventions ?? [];
|
|
737
|
+
if (own.length > 0) return own;
|
|
738
|
+
const family = profile.family ?? deriveFamilyFromModelId(profile.id);
|
|
739
|
+
if (!family) return [];
|
|
740
|
+
const repId = familyRepId(family);
|
|
741
|
+
if (!repId || repId === profile.id) return [];
|
|
742
|
+
const rep = tryGetProfile(repId);
|
|
743
|
+
return rep?.archetypeConventions ?? [];
|
|
744
|
+
}
|
|
246
745
|
function passScoreTargets(ir, opts) {
|
|
247
746
|
const constraints = ir.constraints ?? {};
|
|
248
747
|
const policy = opts.policy ?? {};
|
|
@@ -250,7 +749,8 @@ function passScoreTargets(ir, opts) {
|
|
|
250
749
|
const preferredSet = new Set(policy.preferredModels ?? []);
|
|
251
750
|
const scores = [];
|
|
252
751
|
const policyMutations = [];
|
|
253
|
-
|
|
752
|
+
const modelIds = ir.models.filter((m) => typeof m === "string");
|
|
753
|
+
for (const modelId of modelIds) {
|
|
254
754
|
let profile;
|
|
255
755
|
try {
|
|
256
756
|
profile = opts.profilesById(modelId);
|
|
@@ -294,10 +794,26 @@ function passScoreTargets(ir, opts) {
|
|
|
294
794
|
}
|
|
295
795
|
const baseQuality = profile.strengths.includes("reasoning") ? 0.85 : profile.strengths.includes("quality") ? 0.8 : 0.6;
|
|
296
796
|
const qualityScore = Math.max(0, baseQuality - qualityPenalty);
|
|
297
|
-
const callerOrderBoost = (
|
|
797
|
+
const callerOrderBoost = (modelIds.length - modelIds.indexOf(modelId)) * 0.1;
|
|
298
798
|
const costPenalty = estimatedCostUsd * 5;
|
|
299
799
|
const preferredBoost = preferredSet.has(modelId) ? 0.5 : 0;
|
|
300
|
-
|
|
800
|
+
let latencyPenalty = 0;
|
|
801
|
+
const maxLatencyMs = constraints.maxLatencyMs;
|
|
802
|
+
if (typeof maxLatencyMs === "number" && maxLatencyMs > 0) {
|
|
803
|
+
const tierMs = LATENCY_TIER_MS[latencyTierOf(profile)];
|
|
804
|
+
if (tierMs > maxLatencyMs) {
|
|
805
|
+
const overage = (tierMs - maxLatencyMs) / maxLatencyMs;
|
|
806
|
+
latencyPenalty = Math.min(LATENCY_OVERAGE_WEIGHT * overage, LATENCY_PENALTY_CAP);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
let qualityGatePenalty = 0;
|
|
810
|
+
if (constraints.structuredOutput) {
|
|
811
|
+
const schemaWeak = effectiveConventions(profile).some(
|
|
812
|
+
(c) => c.archetype === ir.intent.archetype && c.structuredOutputHint === "avoid"
|
|
813
|
+
);
|
|
814
|
+
if (schemaWeak) qualityGatePenalty = QUALITY_GATE_PENALTY;
|
|
815
|
+
}
|
|
816
|
+
const rank = qualityScore + callerOrderBoost - costPenalty - reasons.length * 10 + preferredBoost - latencyPenalty - qualityGatePenalty;
|
|
301
817
|
scores.push({
|
|
302
818
|
modelId,
|
|
303
819
|
estimatedCostUsd,
|
|
@@ -330,6 +846,23 @@ function passScoreTargets(ir, opts) {
|
|
|
330
846
|
description: `Model ${modelId} rank boosted by CompilePolicy.preferredModels`
|
|
331
847
|
});
|
|
332
848
|
}
|
|
849
|
+
if (latencyPenalty > 0) {
|
|
850
|
+
const tier = latencyTierOf(profile);
|
|
851
|
+
policyMutations.push({
|
|
852
|
+
id: `latency-downrank-${modelId}`,
|
|
853
|
+
source: "latency_guard",
|
|
854
|
+
passName: "score_targets",
|
|
855
|
+
description: `Model ${modelId} rank down ${latencyPenalty.toFixed(2)} \u2014 latency tier '${tier}' (~${LATENCY_TIER_MS[tier]}ms) exceeds constraints.maxLatencyMs (${maxLatencyMs}ms)`
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
if (qualityGatePenalty > 0) {
|
|
859
|
+
policyMutations.push({
|
|
860
|
+
id: `quality-gate-structured-${modelId}`,
|
|
861
|
+
source: "quality_gate",
|
|
862
|
+
passName: "score_targets",
|
|
863
|
+
description: `Model ${modelId} gated below the quality floor for archetype '${ir.intent.archetype}' \u2014 declared structuredOutput + kgauto convention flags it schema-weak for this contract (structuredOutputHint:'avoid'). Down-ranked out of leadership; retained as graceful fallback only.`
|
|
864
|
+
});
|
|
865
|
+
}
|
|
333
866
|
}
|
|
334
867
|
return { value: scores, mutations: policyMutations };
|
|
335
868
|
}
|
|
@@ -356,6 +889,175 @@ function simpleHash(s) {
|
|
|
356
889
|
}
|
|
357
890
|
return (h >>> 0).toString(36);
|
|
358
891
|
}
|
|
892
|
+
function resolveConventionsForProfile(profile) {
|
|
893
|
+
const own = profile.archetypeConventions ?? [];
|
|
894
|
+
const family = profile.family ?? deriveFamilyFromModelId(profile.id);
|
|
895
|
+
if (!family) return own;
|
|
896
|
+
return own;
|
|
897
|
+
}
|
|
898
|
+
function applyArchetypeConvention(promptText, archetype, family) {
|
|
899
|
+
if (typeof promptText !== "string" || promptText.length === 0) return promptText;
|
|
900
|
+
const repId = familyRepId(family);
|
|
901
|
+
if (!repId) return promptText;
|
|
902
|
+
const profile = tryGetProfile(repId);
|
|
903
|
+
if (!profile || !profile.archetypeConventions) return promptText;
|
|
904
|
+
const conventions = profile.archetypeConventions.filter((c) => c.archetype === archetype);
|
|
905
|
+
if (conventions.length === 0) return promptText;
|
|
906
|
+
let next = promptText;
|
|
907
|
+
for (const c of conventions) {
|
|
908
|
+
if (c.promptPrefix) {
|
|
909
|
+
if (!next.startsWith(c.promptPrefix)) {
|
|
910
|
+
next = c.promptPrefix + next;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
if (c.promptSuffix) {
|
|
914
|
+
if (!next.endsWith(c.promptSuffix)) {
|
|
915
|
+
next = next + c.promptSuffix;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return next;
|
|
920
|
+
}
|
|
921
|
+
function familyRepId(family) {
|
|
922
|
+
switch (family) {
|
|
923
|
+
case "deepseek-reasoner":
|
|
924
|
+
return "deepseek-v4-pro";
|
|
925
|
+
case "deepseek-chat":
|
|
926
|
+
return "deepseek-v4-flash";
|
|
927
|
+
default:
|
|
928
|
+
return void 0;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
function passApplyConventions(ir, profile) {
|
|
932
|
+
const mutations = [];
|
|
933
|
+
const cliffWarnings = [];
|
|
934
|
+
const structuredOutputHints = [];
|
|
935
|
+
const own = profile.archetypeConventions ?? [];
|
|
936
|
+
let effective = own;
|
|
937
|
+
if (effective.length === 0) {
|
|
938
|
+
const family2 = profile.family ?? deriveFamilyFromModelId(profile.id);
|
|
939
|
+
if (family2) {
|
|
940
|
+
const repId = familyRepId(family2);
|
|
941
|
+
if (repId && repId !== profile.id) {
|
|
942
|
+
const repProfile = tryGetProfile(repId);
|
|
943
|
+
if (repProfile && repProfile.archetypeConventions) {
|
|
944
|
+
effective = repProfile.archetypeConventions;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
if (effective.length === 0) {
|
|
950
|
+
return {
|
|
951
|
+
value: { ir, cliffWarnings, structuredOutputHints },
|
|
952
|
+
mutations
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
const archetype = ir.intent.archetype;
|
|
956
|
+
const matching = effective.filter((c) => c.archetype === archetype);
|
|
957
|
+
if (matching.length === 0) {
|
|
958
|
+
return {
|
|
959
|
+
value: { ir, cliffWarnings, structuredOutputHints },
|
|
960
|
+
mutations
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
const family = profile.family ?? deriveFamilyFromModelId(profile.id) ?? "unknown";
|
|
964
|
+
let nextIR = ir;
|
|
965
|
+
for (const convention of matching) {
|
|
966
|
+
let touched = false;
|
|
967
|
+
if (convention.promptPrefix) {
|
|
968
|
+
const sections = nextIR.sections ?? [];
|
|
969
|
+
const alreadyPresent = sections.some(
|
|
970
|
+
(s) => s.text.includes(convention.promptPrefix)
|
|
971
|
+
);
|
|
972
|
+
if (!alreadyPresent) {
|
|
973
|
+
const prefixSection = {
|
|
974
|
+
id: `convention-prefix-${family}-${archetype}`,
|
|
975
|
+
text: convention.promptPrefix
|
|
976
|
+
};
|
|
977
|
+
nextIR = { ...nextIR, sections: [prefixSection, ...sections] };
|
|
978
|
+
touched = true;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
if (convention.promptSuffix) {
|
|
982
|
+
const history = nextIR.history ?? [];
|
|
983
|
+
let lastUserIdx = -1;
|
|
984
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
985
|
+
if (history[i]?.role === "user") {
|
|
986
|
+
lastUserIdx = i;
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (lastUserIdx >= 0) {
|
|
991
|
+
const target = history[lastUserIdx];
|
|
992
|
+
if (!target.content.endsWith(convention.promptSuffix)) {
|
|
993
|
+
const newHistory = history.slice();
|
|
994
|
+
newHistory[lastUserIdx] = {
|
|
995
|
+
...target,
|
|
996
|
+
content: target.content + convention.promptSuffix
|
|
997
|
+
};
|
|
998
|
+
nextIR = { ...nextIR, history: newHistory };
|
|
999
|
+
touched = true;
|
|
1000
|
+
}
|
|
1001
|
+
} else if (nextIR.currentTurn && nextIR.currentTurn.role === "user") {
|
|
1002
|
+
const target = nextIR.currentTurn;
|
|
1003
|
+
if (!target.content.endsWith(convention.promptSuffix)) {
|
|
1004
|
+
nextIR = {
|
|
1005
|
+
...nextIR,
|
|
1006
|
+
currentTurn: {
|
|
1007
|
+
...target,
|
|
1008
|
+
content: target.content + convention.promptSuffix
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
touched = true;
|
|
1012
|
+
}
|
|
1013
|
+
} else {
|
|
1014
|
+
nextIR = {
|
|
1015
|
+
...nextIR,
|
|
1016
|
+
currentTurn: {
|
|
1017
|
+
role: "user",
|
|
1018
|
+
content: convention.promptSuffix.trim()
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
touched = true;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
if (convention.structuredOutputHint) {
|
|
1025
|
+
const wantsStructured = !!nextIR.constraints?.structuredOutput;
|
|
1026
|
+
const shouldSurface = convention.structuredOutputHint === "avoid" && wantsStructured || convention.structuredOutputHint === "enforce" && !wantsStructured;
|
|
1027
|
+
if (shouldSurface) {
|
|
1028
|
+
structuredOutputHints.push({
|
|
1029
|
+
archetype,
|
|
1030
|
+
hint: convention.structuredOutputHint,
|
|
1031
|
+
reason: convention.reason
|
|
1032
|
+
});
|
|
1033
|
+
if (convention.cliffWarning) {
|
|
1034
|
+
cliffWarnings.push(`${profile.id}: ${convention.cliffWarning}`);
|
|
1035
|
+
}
|
|
1036
|
+
touched = true;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
if (convention.cliffWarning && !convention.structuredOutputHint) {
|
|
1040
|
+
const toolCount = nextIR.tools?.length ?? 0;
|
|
1041
|
+
const thresholdOk = convention.whenToolCountAtLeast === void 0 || toolCount >= convention.whenToolCountAtLeast;
|
|
1042
|
+
if (thresholdOk) {
|
|
1043
|
+
cliffWarnings.push(`${profile.id}: ${convention.cliffWarning}`);
|
|
1044
|
+
touched = true;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (touched) {
|
|
1048
|
+
mutations.push({
|
|
1049
|
+
id: `apply-convention-${family}-${archetype}`,
|
|
1050
|
+
source: "archetype_convention",
|
|
1051
|
+
passName: "apply_conventions",
|
|
1052
|
+
description: `${profile.id}: applied ${family}-family convention for archetype=${archetype} \u2014 ${convention.reason}`
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
return {
|
|
1057
|
+
value: { ir: nextIR, cliffWarnings, structuredOutputHints },
|
|
1058
|
+
mutations
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
359
1061
|
|
|
360
1062
|
// src/lower.ts
|
|
361
1063
|
function lower(ir, profile, hints = {}) {
|
|
@@ -374,7 +1076,7 @@ function lower(ir, profile, hints = {}) {
|
|
|
374
1076
|
}
|
|
375
1077
|
function lowerAnthropic(ir, profile, hints) {
|
|
376
1078
|
const systemBlocks = buildAnthropicSystemBlocks(ir.sections, profile);
|
|
377
|
-
const history = ir.history ?? [];
|
|
1079
|
+
const history = (ir.history ?? []).filter((m) => m.role !== "system");
|
|
378
1080
|
const policy = ir.historyCachePolicy;
|
|
379
1081
|
const markIndex = resolveHistoryMarkIndex(history.length, policy);
|
|
380
1082
|
const messages = buildAnthropicMessages(history, ir.currentTurn, markIndex);
|
|
@@ -383,6 +1085,7 @@ function lowerAnthropic(ir, profile, hints) {
|
|
|
383
1085
|
const historyCacheableTokens = markIndex >= 0 ? sumHistoryTokens(history, markIndex) : 0;
|
|
384
1086
|
const totalCacheableTokens = cacheableTokens + historyCacheableTokens;
|
|
385
1087
|
const cacheSavings = totalCacheableTokens / 1e6 * profile.costInputPer1m * (1 - (profile.lowering.cache.discount ?? 0.1));
|
|
1088
|
+
const toolChoice = hints.wireOverrides?.parallelToolCalls === false && tools && tools.length > 0 ? { type: "auto", disable_parallel_tool_use: true } : void 0;
|
|
386
1089
|
return {
|
|
387
1090
|
request: {
|
|
388
1091
|
provider: "anthropic",
|
|
@@ -390,7 +1093,12 @@ function lowerAnthropic(ir, profile, hints) {
|
|
|
390
1093
|
system: systemBlocks,
|
|
391
1094
|
messages,
|
|
392
1095
|
tools,
|
|
393
|
-
|
|
1096
|
+
// alpha.8: trust profile.maxOutputTokens. The historical Math.min(_, 4096)
|
|
1097
|
+
// floor surprised every consumer once (PB-Cairn contract-gaps brief, Gap 3).
|
|
1098
|
+
// Profile is the single source of truth; consumers wanting a tighter
|
|
1099
|
+
// budget can pass providerOverrides.anthropic.max_tokens explicitly.
|
|
1100
|
+
max_tokens: hints.forceTerseOutput ? 200 : profile.maxOutputTokens,
|
|
1101
|
+
tool_choice: toolChoice
|
|
394
1102
|
},
|
|
395
1103
|
diagnostics: {
|
|
396
1104
|
cacheableTokens,
|
|
@@ -519,7 +1227,7 @@ function lowerGoogle(ir, profile, hints) {
|
|
|
519
1227
|
const minTokens = profile.lowering.cache.minTokens ?? 4096;
|
|
520
1228
|
const meetsMin = cacheableTokens >= minTokens;
|
|
521
1229
|
const cacheSavings = meetsMin ? cacheableTokens / 1e6 * profile.costInputPer1m * (1 - (profile.lowering.cache.discount ?? 0.25)) : 0;
|
|
522
|
-
const history = ir.history ?? [];
|
|
1230
|
+
const history = (ir.history ?? []).filter((m) => m.role !== "system");
|
|
523
1231
|
const histMarkIndex = resolveHistoryMarkIndex(history.length, ir.historyCachePolicy);
|
|
524
1232
|
const historyCacheableTokens = histMarkIndex >= 0 ? sumHistoryTokens(history, histMarkIndex) : 0;
|
|
525
1233
|
return {
|
|
@@ -581,9 +1289,10 @@ function lowerOpenAI(ir, profile, hints) {
|
|
|
581
1289
|
content: ir.currentTurn.parts ?? ir.currentTurn.content
|
|
582
1290
|
});
|
|
583
1291
|
}
|
|
584
|
-
const history = ir.history ?? [];
|
|
1292
|
+
const history = (ir.history ?? []).filter((m) => m.role !== "system");
|
|
585
1293
|
const histMarkIndex = resolveHistoryMarkIndex(history.length, ir.historyCachePolicy);
|
|
586
1294
|
const historyCacheableTokens = histMarkIndex >= 0 ? sumHistoryTokens(history, histMarkIndex) : 0;
|
|
1295
|
+
const openaiParallelToolCalls = hints.wireOverrides?.parallelToolCalls === false && ir.tools && ir.tools.length > 0 ? false : void 0;
|
|
587
1296
|
return {
|
|
588
1297
|
request: {
|
|
589
1298
|
provider: "openai",
|
|
@@ -591,7 +1300,8 @@ function lowerOpenAI(ir, profile, hints) {
|
|
|
591
1300
|
messages,
|
|
592
1301
|
tools: ir.tools && ir.tools.length > 0 ? toOpenAITools(ir.tools) : void 0,
|
|
593
1302
|
response_format: ir.constraints?.structuredOutput ? { type: "json_object" } : void 0,
|
|
594
|
-
reasoning_effort: hints.forceTerseOutput ? "low" : void 0
|
|
1303
|
+
reasoning_effort: hints.forceTerseOutput ? "low" : void 0,
|
|
1304
|
+
parallel_tool_calls: openaiParallelToolCalls
|
|
595
1305
|
},
|
|
596
1306
|
diagnostics: {
|
|
597
1307
|
cacheableTokens: 0,
|
|
@@ -624,7 +1334,7 @@ function lowerDeepSeek(ir, profile) {
|
|
|
624
1334
|
content: ir.currentTurn.parts ?? ir.currentTurn.content
|
|
625
1335
|
});
|
|
626
1336
|
}
|
|
627
|
-
const history = ir.history ?? [];
|
|
1337
|
+
const history = (ir.history ?? []).filter((m) => m.role !== "system");
|
|
628
1338
|
const histMarkIndex = resolveHistoryMarkIndex(history.length, ir.historyCachePolicy);
|
|
629
1339
|
const historyCacheableTokens = histMarkIndex >= 0 ? sumHistoryTokens(history, histMarkIndex) : 0;
|
|
630
1340
|
return {
|
|
@@ -668,102 +1378,1126 @@ function setNestedField(obj, path, value) {
|
|
|
668
1378
|
cursor[parts[parts.length - 1]] = value;
|
|
669
1379
|
}
|
|
670
1380
|
|
|
671
|
-
// src/
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
return
|
|
1381
|
+
// src/archetype-perf-brain.ts
|
|
1382
|
+
function isPerfRow(x) {
|
|
1383
|
+
if (!x || typeof x !== "object") return false;
|
|
1384
|
+
const r = x;
|
|
1385
|
+
return typeof r.model_id === "string" && typeof r.archetype === "string" && typeof r.perf_score === "number";
|
|
676
1386
|
}
|
|
677
|
-
function
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
});
|
|
685
|
-
const compressed = passCompressHistory(toolFiltered.value, {
|
|
686
|
-
summarizeOlderThan: opts.compressHistoryAfter
|
|
687
|
-
});
|
|
688
|
-
let workingIR = compressed.value;
|
|
689
|
-
const accumulatedMutations = [
|
|
690
|
-
...sliced.mutations,
|
|
691
|
-
...deduped.mutations,
|
|
692
|
-
...toolFiltered.mutations,
|
|
693
|
-
...compressed.mutations
|
|
694
|
-
];
|
|
695
|
-
const inputTokens = estimateInputTokens(workingIR);
|
|
696
|
-
const scores = passScoreTargets(workingIR, {
|
|
697
|
-
estimatedInputTokens: inputTokens,
|
|
698
|
-
profilesById: resolver,
|
|
699
|
-
policy: opts.policy
|
|
700
|
-
});
|
|
701
|
-
accumulatedMutations.push(...scores.mutations);
|
|
702
|
-
const target = pickTarget(workingIR, scores.value);
|
|
703
|
-
if (!target) {
|
|
704
|
-
throw new Error(
|
|
705
|
-
`compile(): no allowed model fits the request. Scores: ${JSON.stringify(scores.value, null, 2)}`
|
|
706
|
-
);
|
|
1387
|
+
function mapRowsToPerfMap(rows) {
|
|
1388
|
+
const out = /* @__PURE__ */ new Map();
|
|
1389
|
+
for (const row of rows) {
|
|
1390
|
+
if (!isPerfRow(row)) continue;
|
|
1391
|
+
const existing = out.get(row.model_id) ?? {};
|
|
1392
|
+
existing[row.archetype] = row.perf_score;
|
|
1393
|
+
out.set(row.model_id, existing);
|
|
707
1394
|
}
|
|
708
|
-
|
|
709
|
-
const fallbackChain = scores.value.filter((s) => s.modelId !== target.modelId && s.fits).sort((a, b) => b.rank - a.rank).map((s) => s.modelId);
|
|
710
|
-
const cliffs = passApplyCliffs(workingIR, profile, inputTokens);
|
|
711
|
-
workingIR = cliffs.value.ir;
|
|
712
|
-
accumulatedMutations.push(...cliffs.mutations);
|
|
713
|
-
const lowered = lower(workingIR, profile, {
|
|
714
|
-
forceThinkingZero: cliffs.value.loweringHints.forceThinkingZero,
|
|
715
|
-
forceTerseOutput: cliffs.value.loweringHints.forceTerseOutput
|
|
716
|
-
});
|
|
717
|
-
validateFinalFit(workingIR, profile, inputTokens);
|
|
718
|
-
const handle = makeHandle();
|
|
719
|
-
const finalShape = computeShape(workingIR, inputTokens);
|
|
720
|
-
const _learningKey = learningKey(ir.intent.archetype, profile.id, finalShape);
|
|
721
|
-
return {
|
|
722
|
-
handle,
|
|
723
|
-
target: profile.id,
|
|
724
|
-
provider: profile.provider,
|
|
725
|
-
request: lowered.request,
|
|
726
|
-
tokensIn: inputTokens,
|
|
727
|
-
estimatedCostUsd: target.estimatedCostUsd,
|
|
728
|
-
mutationsApplied: accumulatedMutations,
|
|
729
|
-
fallbackChain,
|
|
730
|
-
diagnostics: {
|
|
731
|
-
sectionsKept: workingIR.sections.length,
|
|
732
|
-
sectionsDropped: ir.sections.length - workingIR.sections.length,
|
|
733
|
-
toolsKept: workingIR.tools?.length ?? 0,
|
|
734
|
-
toolsDropped: (ir.tools?.length ?? 0) - (workingIR.tools?.length ?? 0),
|
|
735
|
-
historyKept: workingIR.history?.length ?? 0,
|
|
736
|
-
historyDropped: (ir.history?.length ?? 0) - (workingIR.history?.length ?? 0),
|
|
737
|
-
cacheableTokens: lowered.diagnostics.cacheableTokens,
|
|
738
|
-
estimatedCacheSavingsUsd: lowered.diagnostics.estimatedCacheSavingsUsd,
|
|
739
|
-
historyCacheableTokens: lowered.diagnostics.historyCacheableTokens
|
|
740
|
-
}
|
|
741
|
-
};
|
|
1395
|
+
return out;
|
|
742
1396
|
}
|
|
743
|
-
function
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
if (!Array.isArray(ir.sections)) {
|
|
752
|
-
throw new Error("compile(): ir.sections must be an array");
|
|
1397
|
+
function mapRowsToNMap(rows) {
|
|
1398
|
+
const out = /* @__PURE__ */ new Map();
|
|
1399
|
+
for (const row of rows) {
|
|
1400
|
+
if (!isPerfRow(row)) continue;
|
|
1401
|
+
if (typeof row.n !== "number") continue;
|
|
1402
|
+
const existing = out.get(row.model_id) ?? {};
|
|
1403
|
+
existing[row.archetype] = row.n;
|
|
1404
|
+
out.set(row.model_id, existing);
|
|
753
1405
|
}
|
|
1406
|
+
return out;
|
|
754
1407
|
}
|
|
755
|
-
function
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
if (
|
|
759
|
-
if (forced) {
|
|
760
|
-
throw new Error(
|
|
761
|
-
`compile(): forceModel="${ir.constraints.forceModel}" does not fit: ${forced.rejectReasons.join("; ")}`
|
|
762
|
-
);
|
|
763
|
-
}
|
|
1408
|
+
function bundledArchetypePerf() {
|
|
1409
|
+
const out = /* @__PURE__ */ new Map();
|
|
1410
|
+
for (const profile of allProfiles()) {
|
|
1411
|
+
if (profile.archetypePerf) out.set(profile.id, profile.archetypePerf);
|
|
764
1412
|
}
|
|
765
|
-
|
|
766
|
-
|
|
1413
|
+
return out;
|
|
1414
|
+
}
|
|
1415
|
+
function bundledArchetypePerfN() {
|
|
1416
|
+
return /* @__PURE__ */ new Map();
|
|
1417
|
+
}
|
|
1418
|
+
var loadArchetypePerfFromBrain = createBrainQueryCache({
|
|
1419
|
+
table: "kgauto_archetype_perf",
|
|
1420
|
+
mapRows: mapRowsToPerfMap,
|
|
1421
|
+
bundledFallback: bundledArchetypePerf
|
|
1422
|
+
});
|
|
1423
|
+
var loadArchetypePerfNFromBrain = createBrainQueryCache(
|
|
1424
|
+
{
|
|
1425
|
+
table: "kgauto_archetype_perf",
|
|
1426
|
+
mapRows: mapRowsToNMap,
|
|
1427
|
+
bundledFallback: bundledArchetypePerfN
|
|
1428
|
+
}
|
|
1429
|
+
);
|
|
1430
|
+
var MEASURED_GROUNDING_MIN_N = 10;
|
|
1431
|
+
function getArchetypePerfScore(modelId, archetype) {
|
|
1432
|
+
const score = loadArchetypePerfFromBrain().get(modelId)?.[archetype] ?? 5;
|
|
1433
|
+
const n = loadArchetypePerfNFromBrain().get(modelId)?.[archetype] ?? 0;
|
|
1434
|
+
const grounding = n >= MEASURED_GROUNDING_MIN_N ? "measured" : "judgment";
|
|
1435
|
+
return { score, n, grounding };
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
// src/promote-ready-brain.ts
|
|
1439
|
+
function isRawPromoteReadyRow(x) {
|
|
1440
|
+
if (!x || typeof x !== "object") return false;
|
|
1441
|
+
const r = x;
|
|
1442
|
+
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";
|
|
1443
|
+
}
|
|
1444
|
+
function coerceNumber(v) {
|
|
1445
|
+
if (typeof v === "number") return Number.isFinite(v) ? v : null;
|
|
1446
|
+
if (typeof v === "string") {
|
|
1447
|
+
const n = Number(v);
|
|
1448
|
+
return Number.isFinite(n) ? n : null;
|
|
1449
|
+
}
|
|
1450
|
+
return null;
|
|
1451
|
+
}
|
|
1452
|
+
function mapRowsToFindings2(rows) {
|
|
1453
|
+
const out = [];
|
|
1454
|
+
for (const row of rows) {
|
|
1455
|
+
if (!isRawPromoteReadyRow(row)) continue;
|
|
1456
|
+
const sampleN = coerceNumber(row.sample_n);
|
|
1457
|
+
const passRate = coerceNumber(row.judge_pass_rate);
|
|
1458
|
+
const avgScore = coerceNumber(row.judge_avg_score);
|
|
1459
|
+
if (sampleN === null || passRate === null || avgScore === null) continue;
|
|
1460
|
+
out.push({
|
|
1461
|
+
archetype: row.intent_archetype,
|
|
1462
|
+
family: row.family,
|
|
1463
|
+
candidateModel: row.candidate_model,
|
|
1464
|
+
currentModel: row.current_model,
|
|
1465
|
+
sampleN,
|
|
1466
|
+
judgePassRate: passRate,
|
|
1467
|
+
judgeAvgScore: avgScore,
|
|
1468
|
+
costDeltaPct: coerceNumber(row.cost_delta_pct),
|
|
1469
|
+
detectedAt: row.detected_at
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
return out;
|
|
1473
|
+
}
|
|
1474
|
+
var snapshots2 = /* @__PURE__ */ new Map();
|
|
1475
|
+
var runtime2;
|
|
1476
|
+
var warnedOnce2 = false;
|
|
1477
|
+
function isPromoteReadyBrainActive() {
|
|
1478
|
+
return runtime2 !== void 0;
|
|
1479
|
+
}
|
|
1480
|
+
function loadPromoteReadyFindings(opts) {
|
|
1481
|
+
const rt = runtime2;
|
|
1482
|
+
if (!rt) return [];
|
|
1483
|
+
const appId = opts.appId;
|
|
1484
|
+
if (!appId) return [];
|
|
1485
|
+
let snap = snapshots2.get(appId);
|
|
1486
|
+
if (!snap) {
|
|
1487
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
1488
|
+
snapshots2.set(appId, snap);
|
|
1489
|
+
}
|
|
1490
|
+
const now = Date.now();
|
|
1491
|
+
const stale = snap.expiresAt <= now;
|
|
1492
|
+
if (stale && !snap.refreshing) {
|
|
1493
|
+
snap.refreshing = true;
|
|
1494
|
+
void asyncRefresh2(rt, appId);
|
|
1495
|
+
}
|
|
1496
|
+
let rows = snap.data;
|
|
1497
|
+
if (opts.archetype) {
|
|
1498
|
+
rows = rows.filter((f) => f.archetype === opts.archetype);
|
|
1499
|
+
}
|
|
1500
|
+
if (opts.family) {
|
|
1501
|
+
rows = rows.filter((f) => f.family === opts.family);
|
|
1502
|
+
}
|
|
1503
|
+
return rows;
|
|
1504
|
+
}
|
|
1505
|
+
var pendingRefreshes2 = /* @__PURE__ */ new Map();
|
|
1506
|
+
async function asyncRefresh2(rt, appId) {
|
|
1507
|
+
const promise = doRefresh2(rt, appId);
|
|
1508
|
+
pendingRefreshes2.set(appId, promise);
|
|
1509
|
+
try {
|
|
1510
|
+
await promise;
|
|
1511
|
+
} finally {
|
|
1512
|
+
if (pendingRefreshes2.get(appId) === promise) {
|
|
1513
|
+
pendingRefreshes2.delete(appId);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
async function doRefresh2(rt, appId) {
|
|
1518
|
+
const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}`;
|
|
1519
|
+
let snap = snapshots2.get(appId);
|
|
1520
|
+
if (!snap) {
|
|
1521
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
1522
|
+
snapshots2.set(appId, snap);
|
|
1523
|
+
}
|
|
1524
|
+
try {
|
|
1525
|
+
const res = await rt.fetchImpl(url, { method: "GET" });
|
|
1526
|
+
if (!res.ok) {
|
|
1527
|
+
throw new Error(`promote-ready ${res.status}: ${res.statusText}`);
|
|
1528
|
+
}
|
|
1529
|
+
const body = await res.json();
|
|
1530
|
+
if (runtime2 !== rt) return;
|
|
1531
|
+
const rows = Array.isArray(body) ? mapRowsToFindings2(body) : [];
|
|
1532
|
+
snap.data = rows;
|
|
1533
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
1534
|
+
snap.refreshing = false;
|
|
1535
|
+
} catch (err) {
|
|
1536
|
+
if (runtime2 !== rt) return;
|
|
1537
|
+
snap.refreshing = false;
|
|
1538
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
1539
|
+
if (!warnedOnce2) {
|
|
1540
|
+
warnedOnce2 = true;
|
|
1541
|
+
(rt.onError ?? defaultOnError2)(err);
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
function defaultOnError2(err) {
|
|
1546
|
+
console.warn(
|
|
1547
|
+
"[kgauto] promote-ready fetch failed (using empty fallback):",
|
|
1548
|
+
err
|
|
1549
|
+
);
|
|
1550
|
+
}
|
|
1551
|
+
function resolveFetchImpl(injected) {
|
|
1552
|
+
return injected ?? ((...args) => globalThis.fetch(...args));
|
|
1553
|
+
}
|
|
1554
|
+
function normalizeEndpoint(endpoint) {
|
|
1555
|
+
return endpoint.replace(/\/+$/, "");
|
|
1556
|
+
}
|
|
1557
|
+
async function markPromoteReadyHandled(opts) {
|
|
1558
|
+
const {
|
|
1559
|
+
appId,
|
|
1560
|
+
archetype,
|
|
1561
|
+
family,
|
|
1562
|
+
resolution,
|
|
1563
|
+
resolutionNote,
|
|
1564
|
+
brainEndpoint,
|
|
1565
|
+
brainJwt,
|
|
1566
|
+
brainAnonKey,
|
|
1567
|
+
fetch: injectedFetch
|
|
1568
|
+
} = opts;
|
|
1569
|
+
if (!appId) return { ok: false, reason: "app_id_required" };
|
|
1570
|
+
if (!archetype) return { ok: false, reason: "archetype_required" };
|
|
1571
|
+
if (!family) return { ok: false, reason: "family_required" };
|
|
1572
|
+
if (resolution !== "promoted" && resolution !== "declined" && resolution !== "still-evaluating") {
|
|
1573
|
+
return { ok: false, reason: "resolution_invalid" };
|
|
1574
|
+
}
|
|
1575
|
+
const doFetch = resolveFetchImpl(injectedFetch);
|
|
1576
|
+
const base = normalizeEndpoint(brainEndpoint);
|
|
1577
|
+
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`;
|
|
1578
|
+
const patchBody = {
|
|
1579
|
+
resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1580
|
+
resolution
|
|
1581
|
+
};
|
|
1582
|
+
if (resolutionNote !== void 0) {
|
|
1583
|
+
patchBody.resolution_note = resolutionNote;
|
|
1584
|
+
}
|
|
1585
|
+
let res;
|
|
1586
|
+
try {
|
|
1587
|
+
res = await doFetch(url, {
|
|
1588
|
+
method: "PATCH",
|
|
1589
|
+
headers: {
|
|
1590
|
+
Authorization: `Bearer ${brainJwt}`,
|
|
1591
|
+
apikey: brainAnonKey,
|
|
1592
|
+
"Content-Type": "application/json",
|
|
1593
|
+
Accept: "application/json",
|
|
1594
|
+
Prefer: "return=minimal"
|
|
1595
|
+
},
|
|
1596
|
+
body: JSON.stringify(patchBody)
|
|
1597
|
+
});
|
|
1598
|
+
} catch (err) {
|
|
1599
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1600
|
+
return { ok: false, reason: `network_error:${msg}` };
|
|
1601
|
+
}
|
|
1602
|
+
if (res.status === 401 || res.status === 403) {
|
|
1603
|
+
return { ok: false, reason: "brain_auth_misconfig" };
|
|
1604
|
+
}
|
|
1605
|
+
if (res.status >= 500) {
|
|
1606
|
+
return { ok: false, reason: "brain_unavailable" };
|
|
1607
|
+
}
|
|
1608
|
+
if (!res.ok) {
|
|
1609
|
+
return { ok: false, reason: `patch_failed:${res.status}` };
|
|
1610
|
+
}
|
|
1611
|
+
return { ok: true };
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
// src/advisor-rules/promote-ready.ts
|
|
1615
|
+
var PROMOTE_READY_THRESHOLDS = {
|
|
1616
|
+
minPassRate: 0.8,
|
|
1617
|
+
minAvgScore: 4
|
|
1618
|
+
};
|
|
1619
|
+
function shouldFirePromoteReady(finding, resolvedPrimary) {
|
|
1620
|
+
if (finding.currentModel !== resolvedPrimary) return false;
|
|
1621
|
+
if (finding.judgePassRate < PROMOTE_READY_THRESHOLDS.minPassRate) return false;
|
|
1622
|
+
if (finding.judgeAvgScore < PROMOTE_READY_THRESHOLDS.minAvgScore) return false;
|
|
1623
|
+
return true;
|
|
1624
|
+
}
|
|
1625
|
+
function deriveFamilyLocal(modelId) {
|
|
1626
|
+
if (modelId.startsWith("claude-opus-")) return "claude-opus";
|
|
1627
|
+
if (modelId.startsWith("claude-sonnet-")) return "claude-sonnet";
|
|
1628
|
+
if (modelId.startsWith("claude-haiku-")) return "claude-haiku";
|
|
1629
|
+
if (/^gemini-.*-flash-lite/.test(modelId)) return "gemini-flash-lite";
|
|
1630
|
+
if (/^gemini-.*-flash/.test(modelId)) return "gemini-flash";
|
|
1631
|
+
if (/^gemini-.*-pro/.test(modelId)) return "gemini-pro";
|
|
1632
|
+
if (/^deepseek-.*-pro/.test(modelId)) return "deepseek-reasoner";
|
|
1633
|
+
if (modelId.startsWith("deepseek-")) return "deepseek-chat";
|
|
1634
|
+
if (modelId.startsWith("gpt-")) return "openai-gpt";
|
|
1635
|
+
return null;
|
|
1636
|
+
}
|
|
1637
|
+
function advisorRulePromoteReady(ctx) {
|
|
1638
|
+
if (!isPromoteReadyBrainActive()) return [];
|
|
1639
|
+
if (!ctx.appId) return [];
|
|
1640
|
+
if (!ctx.resolvedPrimary) return [];
|
|
1641
|
+
const family = deriveFamilyLocal(ctx.resolvedPrimary);
|
|
1642
|
+
if (!family) return [];
|
|
1643
|
+
const findings = loadPromoteReadyFindings({
|
|
1644
|
+
appId: ctx.appId,
|
|
1645
|
+
archetype: ctx.archetype,
|
|
1646
|
+
family
|
|
1647
|
+
});
|
|
1648
|
+
if (findings.length === 0) return [];
|
|
1649
|
+
const qualifying = findings.filter(
|
|
1650
|
+
(f) => shouldFirePromoteReady(f, ctx.resolvedPrimary)
|
|
1651
|
+
);
|
|
1652
|
+
if (qualifying.length === 0) return [];
|
|
1653
|
+
qualifying.sort((a, b) => {
|
|
1654
|
+
if (a.judgeAvgScore !== b.judgeAvgScore) {
|
|
1655
|
+
return b.judgeAvgScore - a.judgeAvgScore;
|
|
1656
|
+
}
|
|
1657
|
+
return b.judgePassRate - a.judgePassRate;
|
|
1658
|
+
});
|
|
1659
|
+
const top = qualifying[0];
|
|
1660
|
+
const pctPass = Math.round(top.judgePassRate * 100);
|
|
1661
|
+
const score = top.judgeAvgScore.toFixed(2);
|
|
1662
|
+
let costClause = "";
|
|
1663
|
+
if (top.costDeltaPct !== null) {
|
|
1664
|
+
const sign = top.costDeltaPct < 0 ? "cheaper" : "more expensive";
|
|
1665
|
+
const magnitude = Math.abs(top.costDeltaPct * 100).toFixed(1);
|
|
1666
|
+
costClause = `, cost ${magnitude}% ${sign}`;
|
|
1667
|
+
}
|
|
1668
|
+
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.`;
|
|
1669
|
+
return [
|
|
1670
|
+
{
|
|
1671
|
+
level: "info",
|
|
1672
|
+
code: "promote-ready",
|
|
1673
|
+
message,
|
|
1674
|
+
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.`,
|
|
1675
|
+
// alpha.36 architectural field — not a no-ai-needed case.
|
|
1676
|
+
recommendedArchitecture: void 0,
|
|
1677
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
1678
|
+
}
|
|
1679
|
+
];
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
// src/advisor-rules/consumer-on-stale-model.ts
|
|
1683
|
+
function isStaleStatus(v) {
|
|
1684
|
+
return v === "legacy" || v === "deprecated";
|
|
1685
|
+
}
|
|
1686
|
+
function asString(v) {
|
|
1687
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
1688
|
+
}
|
|
1689
|
+
function mapRowsToFindings3(rows) {
|
|
1690
|
+
const out = [];
|
|
1691
|
+
for (const raw of rows) {
|
|
1692
|
+
if (!raw || typeof raw !== "object") continue;
|
|
1693
|
+
const r = raw;
|
|
1694
|
+
const archetype = asString(r.intent_archetype) ?? asString(r.applies_to_archetype);
|
|
1695
|
+
const staleModel = asString(r.stale_model) ?? asString(r.applies_to_model);
|
|
1696
|
+
const staleProvider = asString(r.stale_provider);
|
|
1697
|
+
const recommendedModel = asString(r.recommended_model);
|
|
1698
|
+
const family = asString(r.family);
|
|
1699
|
+
const message = asString(r.message);
|
|
1700
|
+
if (!archetype || !staleModel || !recommendedModel || !family || !message) {
|
|
1701
|
+
continue;
|
|
1702
|
+
}
|
|
1703
|
+
if (!isStaleStatus(r.stale_status)) continue;
|
|
1704
|
+
const row = {
|
|
1705
|
+
archetype,
|
|
1706
|
+
staleModel,
|
|
1707
|
+
staleProvider: staleProvider ?? "unknown",
|
|
1708
|
+
staleStatus: r.stale_status,
|
|
1709
|
+
recommendedModel,
|
|
1710
|
+
family,
|
|
1711
|
+
message
|
|
1712
|
+
};
|
|
1713
|
+
const suggestion = asString(r.suggestion);
|
|
1714
|
+
if (suggestion) row.suggestion = suggestion;
|
|
1715
|
+
if (typeof r.observation_count === "number" && Number.isFinite(r.observation_count)) {
|
|
1716
|
+
row.observationCount = r.observation_count;
|
|
1717
|
+
}
|
|
1718
|
+
out.push(row);
|
|
1719
|
+
}
|
|
1720
|
+
return out;
|
|
1721
|
+
}
|
|
1722
|
+
var snapshots3 = /* @__PURE__ */ new Map();
|
|
1723
|
+
var runtime3;
|
|
1724
|
+
var warnedOnce3 = false;
|
|
1725
|
+
var pendingRefreshes3 = /* @__PURE__ */ new Map();
|
|
1726
|
+
function isStaleModelFindingsBrainActive() {
|
|
1727
|
+
return runtime3 !== void 0;
|
|
1728
|
+
}
|
|
1729
|
+
function getStaleModelFindings(opts) {
|
|
1730
|
+
const rt = runtime3;
|
|
1731
|
+
if (!rt) return [];
|
|
1732
|
+
const appId = opts.appId;
|
|
1733
|
+
if (!appId) return [];
|
|
1734
|
+
let snap = snapshots3.get(appId);
|
|
1735
|
+
if (!snap) {
|
|
1736
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
1737
|
+
snapshots3.set(appId, snap);
|
|
1738
|
+
}
|
|
1739
|
+
const now = Date.now();
|
|
1740
|
+
const stale = snap.expiresAt <= now;
|
|
1741
|
+
if (stale && !snap.refreshing) {
|
|
1742
|
+
snap.refreshing = true;
|
|
1743
|
+
void asyncRefresh3(rt, appId);
|
|
1744
|
+
}
|
|
1745
|
+
if (opts.archetype) {
|
|
1746
|
+
return snap.data.filter((f) => f.archetype === opts.archetype);
|
|
1747
|
+
}
|
|
1748
|
+
return snap.data;
|
|
1749
|
+
}
|
|
1750
|
+
async function asyncRefresh3(rt, appId) {
|
|
1751
|
+
const promise = doRefresh3(rt, appId);
|
|
1752
|
+
pendingRefreshes3.set(appId, promise);
|
|
1753
|
+
try {
|
|
1754
|
+
await promise;
|
|
1755
|
+
} finally {
|
|
1756
|
+
if (pendingRefreshes3.get(appId) === promise) {
|
|
1757
|
+
pendingRefreshes3.delete(appId);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
async function doRefresh3(rt, appId) {
|
|
1762
|
+
const url = `${rt.endpoint}?app_id=${encodeURIComponent(appId)}`;
|
|
1763
|
+
let snap = snapshots3.get(appId);
|
|
1764
|
+
if (!snap) {
|
|
1765
|
+
snap = { data: [], expiresAt: 0, refreshing: false };
|
|
1766
|
+
snapshots3.set(appId, snap);
|
|
1767
|
+
}
|
|
1768
|
+
try {
|
|
1769
|
+
const res = await rt.fetchImpl(url, { method: "GET" });
|
|
1770
|
+
if (!res.ok) {
|
|
1771
|
+
throw new Error(`stale-model findings ${res.status}: ${res.statusText}`);
|
|
1772
|
+
}
|
|
1773
|
+
const body = await res.json();
|
|
1774
|
+
if (runtime3 !== rt) return;
|
|
1775
|
+
const rows = Array.isArray(body) ? mapRowsToFindings3(body) : [];
|
|
1776
|
+
snap.data = rows;
|
|
1777
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
1778
|
+
snap.refreshing = false;
|
|
1779
|
+
} catch (err) {
|
|
1780
|
+
if (runtime3 !== rt) return;
|
|
1781
|
+
snap.refreshing = false;
|
|
1782
|
+
snap.expiresAt = Date.now() + rt.ttlMs;
|
|
1783
|
+
if (!warnedOnce3) {
|
|
1784
|
+
warnedOnce3 = true;
|
|
1785
|
+
(rt.onError ?? defaultOnError3)(err);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
function defaultOnError3(err) {
|
|
1790
|
+
console.warn(
|
|
1791
|
+
"[kgauto] stale-model findings fetch failed (using empty fallback):",
|
|
1792
|
+
err
|
|
1793
|
+
);
|
|
1794
|
+
}
|
|
1795
|
+
var CONSUMER_ON_STALE_MODEL_RULE_CODE = "consumer-on-stale-model";
|
|
1796
|
+
function advisorRuleConsumerOnStaleModel(ir) {
|
|
1797
|
+
if (!isStaleModelFindingsBrainActive()) return [];
|
|
1798
|
+
if (!ir.appId) return [];
|
|
1799
|
+
const findings = getStaleModelFindings({
|
|
1800
|
+
appId: ir.appId,
|
|
1801
|
+
archetype: ir.intent.archetype
|
|
1802
|
+
});
|
|
1803
|
+
if (findings.length === 0) return [];
|
|
1804
|
+
const ranked = [...findings].sort((a, b) => {
|
|
1805
|
+
if (a.staleStatus !== b.staleStatus) {
|
|
1806
|
+
return a.staleStatus === "deprecated" ? -1 : 1;
|
|
1807
|
+
}
|
|
1808
|
+
return a.staleModel.localeCompare(b.staleModel);
|
|
1809
|
+
});
|
|
1810
|
+
const top = ranked[0];
|
|
1811
|
+
const extraCount = findings.length - 1;
|
|
1812
|
+
const extraNote = extraCount > 0 ? ` (+ ${extraCount} more stale model${extraCount === 1 ? "" : "s"} for this archetype)` : "";
|
|
1813
|
+
return [
|
|
1814
|
+
{
|
|
1815
|
+
level: "warn",
|
|
1816
|
+
code: CONSUMER_ON_STALE_MODEL_RULE_CODE,
|
|
1817
|
+
message: `${top.message}${extraNote}`,
|
|
1818
|
+
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}.`,
|
|
1819
|
+
recommendationType: "model-swap",
|
|
1820
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
1821
|
+
}
|
|
1822
|
+
];
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
// src/archetype-fits.ts
|
|
1826
|
+
var ARCHETYPE_FAMILY_FITS = Object.freeze([
|
|
1827
|
+
{
|
|
1828
|
+
archetype: "plan",
|
|
1829
|
+
betterFitFamily: "deepseek-reasoner",
|
|
1830
|
+
reason: "Plan archetype is reasoning-shaped (multi-step chains, hypothesis-and-check, sub-goal decomposition) \u2014 exactly where reasoner-family models excel. Sonnet/Opus produce plans but at higher cost; reasoners produce equivalent-or-better plans at 7-17x lower cost at current promo pricing (deepseek-v4-pro $0.435/$0.87 per 1M promo through 2026-05-31 vs sonnet $3/$15).",
|
|
1831
|
+
costGuidance: "substantially cheaper at current pricing (deepseek-v4-pro promo: ~7-17x cheaper than sonnet)"
|
|
1832
|
+
},
|
|
1833
|
+
{
|
|
1834
|
+
archetype: "critique",
|
|
1835
|
+
betterFitFamily: "deepseek-reasoner",
|
|
1836
|
+
reason: "Critique archetype rewards epistemic humility and explicit reasoning \u2014 reasoner-family default behavior. Sonnet/Opus over-confident on critique tasks; reasoners surface uncertainty productively.",
|
|
1837
|
+
costGuidance: "comparable or cheaper at current pricing"
|
|
1838
|
+
}
|
|
1839
|
+
]);
|
|
1840
|
+
function findBetterFit(archetype, currentFamily) {
|
|
1841
|
+
for (const fit of ARCHETYPE_FAMILY_FITS) {
|
|
1842
|
+
if (fit.archetype !== archetype) continue;
|
|
1843
|
+
if (fit.betterFitFamily === currentFamily) return null;
|
|
1844
|
+
return fit;
|
|
1845
|
+
}
|
|
1846
|
+
return null;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
// src/advisor-rules/cross-family-fit.ts
|
|
1850
|
+
function familyHasCurrentActiveModel(family) {
|
|
1851
|
+
for (const profile of allProfiles()) {
|
|
1852
|
+
const profileFamily = profile.family ?? deriveFamilyFromModelId(profile.id);
|
|
1853
|
+
if (profileFamily !== family) continue;
|
|
1854
|
+
if (profile.status !== "current") continue;
|
|
1855
|
+
if (profile.active === false) continue;
|
|
1856
|
+
return true;
|
|
1857
|
+
}
|
|
1858
|
+
return false;
|
|
1859
|
+
}
|
|
1860
|
+
function listCandidatesInFamily(family) {
|
|
1861
|
+
const candidates = [];
|
|
1862
|
+
for (const profile of allProfiles()) {
|
|
1863
|
+
const profileFamily = profile.family ?? deriveFamilyFromModelId(profile.id);
|
|
1864
|
+
if (profileFamily !== family) continue;
|
|
1865
|
+
if (profile.status !== "current") continue;
|
|
1866
|
+
if (profile.active === false) continue;
|
|
1867
|
+
candidates.push(profile.id);
|
|
1868
|
+
if (candidates.length >= 3) break;
|
|
1869
|
+
}
|
|
1870
|
+
return candidates;
|
|
1871
|
+
}
|
|
1872
|
+
function advisorRuleCrossFamilyFit(ctx) {
|
|
1873
|
+
if (!ctx.resolvedPrimary) return [];
|
|
1874
|
+
const currentFamily = deriveFamilyFromModelId(ctx.resolvedPrimary);
|
|
1875
|
+
if (!currentFamily) return [];
|
|
1876
|
+
const fit = findBetterFit(ctx.archetype, currentFamily);
|
|
1877
|
+
if (!fit) return [];
|
|
1878
|
+
if (!familyHasCurrentActiveModel(fit.betterFitFamily)) return [];
|
|
1879
|
+
const candidates = listCandidatesInFamily(fit.betterFitFamily);
|
|
1880
|
+
if (candidates.length === 0) return [];
|
|
1881
|
+
const candidateStr = candidates.join(", ");
|
|
1882
|
+
const message = `Your ${currentFamily} call on ${ctx.archetype} could shift to ${fit.betterFitFamily} \u2014 typically better quality + ${fit.costGuidance}. Suggested candidates: ${candidateStr}.`;
|
|
1883
|
+
return [
|
|
1884
|
+
{
|
|
1885
|
+
level: "info",
|
|
1886
|
+
code: "cross-family-fit-candidate",
|
|
1887
|
+
ownership: "consumer-actionable",
|
|
1888
|
+
message,
|
|
1889
|
+
suggestion: `Swap the model literal in \`ir.models\` to one of: ${candidateStr}. Or call \`getRecommendedPrimary({ family: '${fit.betterFitFamily}', archetype: '${ctx.archetype}', fallback: { id: '${candidates[0]}', reason: 'cross-family-fit-recommendation' } })\` to let kgauto resolve to the current+active family member.`,
|
|
1890
|
+
recommendationType: "model-swap",
|
|
1891
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
1892
|
+
}
|
|
1893
|
+
];
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
// src/advisor.ts
|
|
1897
|
+
var QUALITY_FLOOR_FOR_RECOMMENDATION = 6;
|
|
1898
|
+
var TIER_DOWN_COST_RATIO = 0.5;
|
|
1899
|
+
var COST_MISMATCHED_CHOSEN_SCORE_CEILING = 7;
|
|
1900
|
+
var PRODUCER_OWNED_RULE_CODES = Object.freeze(
|
|
1901
|
+
/* @__PURE__ */ new Set(["model-stale-evidence", "promote-ready"])
|
|
1902
|
+
);
|
|
1903
|
+
function deriveOwnership(code, selfDeclared) {
|
|
1904
|
+
if (selfDeclared) return selfDeclared;
|
|
1905
|
+
return PRODUCER_OWNED_RULE_CODES.has(code) ? "producer-owned" : "consumer-actionable";
|
|
1906
|
+
}
|
|
1907
|
+
function runAdvisor(ir, result, profile, policy, phase2) {
|
|
1908
|
+
const out = [];
|
|
1909
|
+
out.push(...detectCachingOff(ir, profile));
|
|
1910
|
+
out.push(...detectSingleChunkSystem(ir, profile));
|
|
1911
|
+
out.push(...detectToolBloat(ir, result));
|
|
1912
|
+
out.push(...detectHistoryUncached(ir, profile));
|
|
1913
|
+
out.push(...detectSingleModelArray(ir, policy));
|
|
1914
|
+
if (policy?.posture !== "locked") {
|
|
1915
|
+
out.push(...detectCostMismatchedArchetype(ir, profile, phase2));
|
|
1916
|
+
out.push(...detectModelStaleEvidence(ir, profile));
|
|
1917
|
+
out.push(...detectTierDown(ir, profile, phase2));
|
|
1918
|
+
}
|
|
1919
|
+
if (!translatorClearedToolCallCliff(phase2)) {
|
|
1920
|
+
out.push(...detectArchetypePerfFloorBreach(ir, profile));
|
|
1921
|
+
}
|
|
1922
|
+
if (policy?.posture !== "locked") {
|
|
1923
|
+
out.push(...detectStaleExclusionCandidate(ir));
|
|
1924
|
+
}
|
|
1925
|
+
if (policy?.posture !== "locked" && ir.appId) {
|
|
1926
|
+
out.push(
|
|
1927
|
+
...advisorRulePromoteReady({
|
|
1928
|
+
appId: ir.appId,
|
|
1929
|
+
archetype: ir.intent.archetype,
|
|
1930
|
+
resolvedPrimary: profile.id
|
|
1931
|
+
})
|
|
1932
|
+
);
|
|
1933
|
+
out.push(...advisorRuleConsumerOnStaleModel(ir));
|
|
1934
|
+
}
|
|
1935
|
+
if (policy?.posture !== "locked") {
|
|
1936
|
+
out.push(
|
|
1937
|
+
...advisorRuleCrossFamilyFit({
|
|
1938
|
+
archetype: ir.intent.archetype,
|
|
1939
|
+
resolvedPrimary: profile.id
|
|
1940
|
+
})
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
return out;
|
|
1944
|
+
}
|
|
1945
|
+
function translatorClearedToolCallCliff(phase2) {
|
|
1946
|
+
const rewrites = phase2?.sectionRewritesApplied;
|
|
1947
|
+
if (!rewrites || rewrites.length === 0) return false;
|
|
1948
|
+
for (const rw of rewrites) {
|
|
1949
|
+
if (rw.kind === "tool_call_contract") return true;
|
|
1950
|
+
}
|
|
1951
|
+
return false;
|
|
1952
|
+
}
|
|
1953
|
+
function detectCachingOff(ir, profile) {
|
|
1954
|
+
if (profile.provider !== "anthropic") return [];
|
|
1955
|
+
const totalChars = ir.sections.reduce((s, sec) => s + sec.text.length, 0);
|
|
1956
|
+
if (totalChars < 2e3) return [];
|
|
1957
|
+
const anyCacheable = ir.sections.some((s) => s.cacheable === true);
|
|
1958
|
+
if (anyCacheable) return [];
|
|
1959
|
+
return [
|
|
1960
|
+
{
|
|
1961
|
+
level: "warn",
|
|
1962
|
+
code: "caching-off-on-claude",
|
|
1963
|
+
message: `System prompt is ${totalChars} chars on Anthropic but no PromptSection has cacheable=true. Anthropic prompt caching cuts cached-prefix input cost by ~90% on subsequent calls; without it, every turn re-pays full price for the static system context.`,
|
|
1964
|
+
suggestion: "Mark stable system sections (role, persona, tool policy) with `cacheable: true`. The lowering pass concatenates cacheable sections into a single cache-controlled block before the dynamic ones.",
|
|
1965
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
1966
|
+
}
|
|
1967
|
+
];
|
|
1968
|
+
}
|
|
1969
|
+
function detectSingleChunkSystem(ir, profile) {
|
|
1970
|
+
if (profile.provider !== "anthropic") return [];
|
|
1971
|
+
if (ir.sections.length !== 1) return [];
|
|
1972
|
+
const only = ir.sections[0];
|
|
1973
|
+
if (!only || only.text.length <= 1e3) return [];
|
|
1974
|
+
return [
|
|
1975
|
+
{
|
|
1976
|
+
level: "info",
|
|
1977
|
+
code: "single-chunk-system",
|
|
1978
|
+
message: `System prompt is a single ${only.text.length}-char chunk. Splitting into NamedChunks (static role/persona vs dynamic context) gives the lowering pass a finer cache-marker boundary \u2014 only the static portion needs to be byte-stable for the cache to hit.`,
|
|
1979
|
+
suggestion: "Refactor the system builder to return an array of `PromptSection` shaped { id, text, cacheable?: boolean }. Static chunks (role, persona, tool policy) get `cacheable: true`; dynamic ones (current context, today's date) don't.",
|
|
1980
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
1981
|
+
}
|
|
1982
|
+
];
|
|
1983
|
+
}
|
|
1984
|
+
function detectToolBloat(ir, result) {
|
|
1985
|
+
const SHORT_OUTPUT = /* @__PURE__ */ new Set([
|
|
1986
|
+
"classify",
|
|
1987
|
+
"extract",
|
|
1988
|
+
"summarize",
|
|
1989
|
+
"transform",
|
|
1990
|
+
"critique"
|
|
1991
|
+
]);
|
|
1992
|
+
if (!ir.tools || ir.tools.length === 0) return [];
|
|
1993
|
+
const toolsKept = result.diagnostics.toolsKept;
|
|
1994
|
+
if (toolsKept <= 10) return [];
|
|
1995
|
+
if (!SHORT_OUTPUT.has(ir.intent.archetype)) return [];
|
|
1996
|
+
return [
|
|
1997
|
+
{
|
|
1998
|
+
level: "warn",
|
|
1999
|
+
code: "tool-bloat",
|
|
2000
|
+
message: `${toolsKept} tools kept after the relevance pass for archetype="${ir.intent.archetype}" (consumer declared ${ir.tools.length}). This archetype is short-output and rarely needs more than 3 tools; each tool definition eats ~350 tokens of context budget.`,
|
|
2001
|
+
suggestion: "Tighten `relevanceByIntent: { [archetype]: 0..1 }` per ToolDefinition. Tools below `toolRelevanceThreshold` (default 0.2) get dropped. Without `relevanceByIntent`, every tool defaults to neutral (0.5) and stays.",
|
|
2002
|
+
docsUrl: "https://github.com/stue/kgauto/blob/main/v2/README.md#tools"
|
|
2003
|
+
}
|
|
2004
|
+
];
|
|
2005
|
+
}
|
|
2006
|
+
function detectHistoryUncached(ir, profile) {
|
|
2007
|
+
if (profile.provider !== "anthropic") return [];
|
|
2008
|
+
if (!ir.history || ir.history.length < 2) return [];
|
|
2009
|
+
if (ir.historyCachePolicy && ir.historyCachePolicy.strategy !== "none") {
|
|
2010
|
+
return [];
|
|
2011
|
+
}
|
|
2012
|
+
return [
|
|
2013
|
+
{
|
|
2014
|
+
level: "warn",
|
|
2015
|
+
code: "history-uncached-on-claude",
|
|
2016
|
+
message: `${ir.history.length} history messages on Anthropic with no historyCachePolicy. Every turn re-pays for the full conversation context; with caching, subsequent turns hit the cache at ~10% the input cost.`,
|
|
2017
|
+
suggestion: "Set `historyCachePolicy: { strategy: 'all-but-latest' }` on this IR. The lowering pass marks the message immediately preceding currentTurn with cache_control; subsequent turns whose history prefix matches byte-for-byte hit the cache.",
|
|
2018
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
2019
|
+
}
|
|
2020
|
+
];
|
|
2021
|
+
}
|
|
2022
|
+
function detectSingleModelArray(ir, policy) {
|
|
2023
|
+
if (ir.models.length !== 1) return [];
|
|
2024
|
+
if (policy?.posture === "locked") return [];
|
|
2025
|
+
const only = ir.models[0];
|
|
2026
|
+
return [
|
|
2027
|
+
{
|
|
2028
|
+
level: "warn",
|
|
2029
|
+
code: "single-model-array",
|
|
2030
|
+
message: `\`ir.models\` has length 1 (only "${only}") and posture is not 'locked'. A single-model chain has no safety net \u2014 the first 429 / 5xx / cliff hits the user as a failure. Master plan \xA71.2 closes the reliability gap with a 2-step minimum.`,
|
|
2031
|
+
suggestion: "Use `getDefaultFallbackChain({ archetype: ir.intent.archetype, primary: '" + only + "', posture: 'preferred' })` for a user-anchored chain, or `getDefaultFallbackChain({ archetype, posture: 'open' })` for library-picked. If single-model is intentional (compliance/brand promise), set `policy.posture = 'locked'` to silence this rule.",
|
|
2032
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#single-model-array"
|
|
2033
|
+
}
|
|
2034
|
+
];
|
|
2035
|
+
}
|
|
2036
|
+
function detectCostMismatchedArchetype(ir, profile, phase2) {
|
|
2037
|
+
if (!phase2 || phase2.fallbackChain.length === 0) return [];
|
|
2038
|
+
if (!phase2.profileResolver) return [];
|
|
2039
|
+
const archetype = ir.intent.archetype;
|
|
2040
|
+
const chosenScore = getArchetypePerfScore(profile.id, archetype);
|
|
2041
|
+
const chosenHasRoomToGrow = chosenScore.grounding === "judgment" || chosenScore.score < COST_MISMATCHED_CHOSEN_SCORE_CEILING;
|
|
2042
|
+
if (!chosenHasRoomToGrow) return [];
|
|
2043
|
+
let bestAlt = null;
|
|
2044
|
+
for (const altId of phase2.fallbackChain) {
|
|
2045
|
+
const altProfile = phase2.profileResolver(altId);
|
|
2046
|
+
if (!altProfile) continue;
|
|
2047
|
+
if (altProfile.id === profile.id) continue;
|
|
2048
|
+
const altScore = getArchetypePerfScore(altProfile.id, archetype);
|
|
2049
|
+
if (altScore.score < QUALITY_FLOOR_FOR_RECOMMENDATION) continue;
|
|
2050
|
+
if (altScore.score < chosenScore.score) continue;
|
|
2051
|
+
if (altProfile.costInputPer1m >= profile.costInputPer1m) continue;
|
|
2052
|
+
if (!bestAlt || altScore.score > bestAlt.score.score || altScore.score === bestAlt.score.score && altProfile.costInputPer1m < bestAlt.profile.costInputPer1m) {
|
|
2053
|
+
bestAlt = { id: altId, profile: altProfile, score: altScore };
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
if (!bestAlt) return [];
|
|
2057
|
+
const tierDownWouldFire = bestAlt.score.grounding === "measured" && bestAlt.profile.costInputPer1m <= profile.costInputPer1m * TIER_DOWN_COST_RATIO;
|
|
2058
|
+
if (tierDownWouldFire) return [];
|
|
2059
|
+
const chosenGrounding = chosenScore.grounding === "judgment" ? `archetypePerf.${archetype}=judgment` : `archetypePerf.${archetype}=${chosenScore.score}`;
|
|
2060
|
+
const altGrounding = bestAlt.score.grounding === "measured" ? `archetypePerf.${archetype}=${bestAlt.score.score}, measured, n=${bestAlt.score.n}` : `archetypePerf.${archetype}=${bestAlt.score.score}, judgment`;
|
|
2061
|
+
return [
|
|
2062
|
+
{
|
|
2063
|
+
level: "warn",
|
|
2064
|
+
code: "cost-mismatched-archetype",
|
|
2065
|
+
message: `Cost-mismatched-archetype: target=${profile.id} (${chosenGrounding}) selected for ${archetype}. Alternative ${bestAlt.id} (${altGrounding}) is cheaper ($${bestAlt.profile.costInputPer1m}/$${bestAlt.profile.costOutputPer1m} vs $${profile.costInputPer1m}/$${profile.costOutputPer1m} per 1M) at equal-or-better quality.`,
|
|
2066
|
+
suggestion: `Consider declaring \`${bestAlt.id}\` as the primary model for this archetype, or relax to posture='open' to let kgauto select among the chain. If the chosen model is required for compliance/brand reasons, set \`policy.posture = 'locked'\` to silence this rule.`,
|
|
2067
|
+
recommendationType: profile.provider === bestAlt.profile.provider ? "tier-down" : "model-swap",
|
|
2068
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
2069
|
+
}
|
|
2070
|
+
];
|
|
2071
|
+
}
|
|
2072
|
+
function detectModelStaleEvidence(ir, profile) {
|
|
2073
|
+
if (!isBrainQueryActiveFor("kgauto_archetype_perf")) return [];
|
|
2074
|
+
const archetype = ir.intent.archetype;
|
|
2075
|
+
const chosen = getArchetypePerfScore(profile.id, archetype);
|
|
2076
|
+
if (chosen.grounding !== "judgment") return [];
|
|
2077
|
+
return [
|
|
2078
|
+
{
|
|
2079
|
+
level: "info",
|
|
2080
|
+
code: "model-stale-evidence",
|
|
2081
|
+
message: `Model-stale-evidence: target=${profile.id} archetype=${archetype} is judgment-grounded (n=${chosen.n}) despite brain-query mode being active. Measurement substrate is wired but the brain hasn't accumulated >=10 outcomes for this (model, archetype) tuple yet \u2014 routing decisions remain pre-measured for this slot.`,
|
|
2082
|
+
suggestion: "Verify that `record()` is being called on every call() outcome with the appropriate `actualModel` and `mutationsApplied` fields. Once the brain accumulates n>=10 rows on this tuple, the score promotes from judgment to measured automatically (5-min SWR cache). No code change required from your side \u2014 this is the substrate signaling the gap.",
|
|
2083
|
+
recommendationType: "prompt-fix",
|
|
2084
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
2085
|
+
}
|
|
2086
|
+
];
|
|
2087
|
+
}
|
|
2088
|
+
function detectTierDown(ir, profile, phase2) {
|
|
2089
|
+
if (!phase2 || phase2.fallbackChain.length === 0) return [];
|
|
2090
|
+
if (!phase2.profileResolver) return [];
|
|
2091
|
+
const archetype = ir.intent.archetype;
|
|
2092
|
+
const chosenScore = getArchetypePerfScore(profile.id, archetype);
|
|
2093
|
+
const chosenCost = profile.costInputPer1m;
|
|
2094
|
+
let bestAlt = null;
|
|
2095
|
+
for (const altId of phase2.fallbackChain) {
|
|
2096
|
+
const altProfile = phase2.profileResolver(altId);
|
|
2097
|
+
if (!altProfile) continue;
|
|
2098
|
+
if (altProfile.id === profile.id) continue;
|
|
2099
|
+
const altScore = getArchetypePerfScore(altProfile.id, archetype);
|
|
2100
|
+
if (altScore.grounding !== "measured") continue;
|
|
2101
|
+
if (altScore.score < QUALITY_FLOOR_FOR_RECOMMENDATION) continue;
|
|
2102
|
+
if (altScore.score < chosenScore.score) continue;
|
|
2103
|
+
if (altProfile.costInputPer1m > chosenCost * TIER_DOWN_COST_RATIO) continue;
|
|
2104
|
+
if (!bestAlt || altProfile.costInputPer1m < bestAlt.profile.costInputPer1m || altProfile.costInputPer1m === bestAlt.profile.costInputPer1m && altScore.score > bestAlt.score.score) {
|
|
2105
|
+
bestAlt = { id: altId, profile: altProfile, score: altScore };
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
if (!bestAlt) return [];
|
|
2109
|
+
const chosenDesc = chosenScore.grounding === "measured" ? `archetypePerf.${archetype}=${chosenScore.score} (measured, n=${chosenScore.n})` : `archetypePerf.${archetype}=${chosenScore.score} (${chosenScore.grounding})`;
|
|
2110
|
+
return [
|
|
2111
|
+
{
|
|
2112
|
+
level: "warn",
|
|
2113
|
+
code: "tier-down",
|
|
2114
|
+
message: `Tier-down: target=${profile.id} (${chosenDesc}) selected for ${archetype}. Brain shows ${bestAlt.id} delivers equal-or-better quality (archetypePerf.${archetype}=${bestAlt.score.score}, measured, n=${bestAlt.score.n}) at $${bestAlt.profile.costInputPer1m}/$${bestAlt.profile.costOutputPer1m} per 1M vs $${profile.costInputPer1m}/$${profile.costOutputPer1m} \u2014 a measured tier-down opportunity.`,
|
|
2115
|
+
suggestion: `Move \`${bestAlt.id}\` to primary for this archetype. The brain has n=${bestAlt.score.n} measured outcomes backing the recommendation; this is data, not opinion. If posture='locked' is required (compliance/brand promise), set it explicitly to silence this rule.`,
|
|
2116
|
+
recommendationType: "tier-down",
|
|
2117
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
2118
|
+
}
|
|
2119
|
+
];
|
|
2120
|
+
}
|
|
2121
|
+
function detectArchetypePerfFloorBreach(ir, profile) {
|
|
2122
|
+
const compat = getModelCompatibility(profile.id, {
|
|
2123
|
+
archetype: ir.intent.archetype,
|
|
2124
|
+
toolOrchestration: ir.constraints?.toolOrchestration
|
|
2125
|
+
});
|
|
2126
|
+
if (compat.status === "compatible") return [];
|
|
2127
|
+
if (compat.status === "requires-adapter") {
|
|
2128
|
+
return [
|
|
2129
|
+
{
|
|
2130
|
+
level: "warn",
|
|
2131
|
+
code: "archetype-perf-floor-breach",
|
|
2132
|
+
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}`,
|
|
2133
|
+
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.`,
|
|
2134
|
+
recommendationType: "prompt-fix",
|
|
2135
|
+
suggestedAdaptation: compat.adapter,
|
|
2136
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
2137
|
+
}
|
|
2138
|
+
];
|
|
2139
|
+
}
|
|
2140
|
+
return [
|
|
2141
|
+
{
|
|
2142
|
+
level: "critical",
|
|
2143
|
+
code: "archetype-perf-floor-breach",
|
|
2144
|
+
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}`,
|
|
2145
|
+
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.`,
|
|
2146
|
+
recommendationType: "model-swap",
|
|
2147
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
2148
|
+
}
|
|
2149
|
+
];
|
|
2150
|
+
}
|
|
2151
|
+
function detectStaleExclusionCandidate(ir) {
|
|
2152
|
+
if (!isExclusionFindingsBrainActive()) return [];
|
|
2153
|
+
if (!ir.appId) return [];
|
|
2154
|
+
const findings = getStaleExclusionFindings({
|
|
2155
|
+
appId: ir.appId,
|
|
2156
|
+
archetype: ir.intent.archetype
|
|
2157
|
+
});
|
|
2158
|
+
if (findings.length === 0) return [];
|
|
2159
|
+
const ranked = [...findings].sort((a, b) => {
|
|
2160
|
+
const sa = a.estimatedSavingsUsd30d ?? -Infinity;
|
|
2161
|
+
const sb = b.estimatedSavingsUsd30d ?? -Infinity;
|
|
2162
|
+
if (sa !== sb) return sb - sa;
|
|
2163
|
+
return confidenceRank(b.confidence) - confidenceRank(a.confidence);
|
|
2164
|
+
});
|
|
2165
|
+
const top = ranked[0];
|
|
2166
|
+
const extraCount = findings.length - 1;
|
|
2167
|
+
const extraNote = extraCount > 0 ? ` (+ ${extraCount} more excluded model${extraCount === 1 ? "" : "s"} for this archetype)` : "";
|
|
2168
|
+
return [
|
|
2169
|
+
{
|
|
2170
|
+
level: "info",
|
|
2171
|
+
code: "stale-exclusion-candidate",
|
|
2172
|
+
message: `${top.message}${extraNote}`,
|
|
2173
|
+
suggestion: top.suggestion,
|
|
2174
|
+
recommendationType: "tier-down",
|
|
2175
|
+
docsUrl: "https://github.com/stue/command-center/blob/main/interfaces/kgauto.md#best-practice-advisories"
|
|
2176
|
+
}
|
|
2177
|
+
];
|
|
2178
|
+
}
|
|
2179
|
+
function confidenceRank(c) {
|
|
2180
|
+
if (c === "high") return 3;
|
|
2181
|
+
if (c === "medium") return 2;
|
|
2182
|
+
return 1;
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
// src/translator.ts
|
|
2186
|
+
var TRANSLATOR_FLOOR = ARCHETYPE_FLOOR_DEFAULT;
|
|
2187
|
+
var RULE_SEQUENTIAL_TOOL_CLIFF = "sequential-tool-cliff-below-floor";
|
|
2188
|
+
var RULE_NARRATION_DRIFT_ANTHROPIC = "narration-drift-anthropic";
|
|
2189
|
+
var RULE_NARRATION_THINKING_LEAK_DEEPSEEK = "narration-thinking-leak-deepseek";
|
|
2190
|
+
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.";
|
|
2191
|
+
var NARRATION_DRIFT_ANTHROPIC_PREAMBLE = "Output ONLY the requested content. Do not narrate your thought process. Each line \u2264 12 words.";
|
|
2192
|
+
var NARRATION_THINKING_LEAK_DEEPSEEK_PREAMBLE = "Reasoning is internal. Output ONLY the requested content; do not emit <thinking> blocks or internal monologue as user-facing text.";
|
|
2193
|
+
function matchRule(kind, profile, archetype) {
|
|
2194
|
+
if (kind === "tool_call_contract") {
|
|
2195
|
+
if (!profile.archetypePerf) return null;
|
|
2196
|
+
const archetypeScore = profile.archetypePerf[archetype];
|
|
2197
|
+
if (typeof archetypeScore !== "number" || archetypeScore >= TRANSLATOR_FLOOR) {
|
|
2198
|
+
return null;
|
|
2199
|
+
}
|
|
2200
|
+
return {
|
|
2201
|
+
id: RULE_SEQUENTIAL_TOOL_CLIFF,
|
|
2202
|
+
preamble: SEQUENTIAL_TOOL_PREAMBLE,
|
|
2203
|
+
wireOverrides: { parallelToolCalls: false }
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
if (kind === "narration_contract") {
|
|
2207
|
+
if (profile.provider === "anthropic") {
|
|
2208
|
+
return {
|
|
2209
|
+
id: RULE_NARRATION_DRIFT_ANTHROPIC,
|
|
2210
|
+
preamble: NARRATION_DRIFT_ANTHROPIC_PREAMBLE
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
if (profile.provider === "deepseek") {
|
|
2214
|
+
return {
|
|
2215
|
+
id: RULE_NARRATION_THINKING_LEAK_DEEPSEEK,
|
|
2216
|
+
preamble: NARRATION_THINKING_LEAK_DEEPSEEK_PREAMBLE
|
|
2217
|
+
};
|
|
2218
|
+
}
|
|
2219
|
+
return null;
|
|
2220
|
+
}
|
|
2221
|
+
return null;
|
|
2222
|
+
}
|
|
2223
|
+
function applySectionRewrites(args) {
|
|
2224
|
+
const { ir, profile, archetype } = args;
|
|
2225
|
+
if (!Array.isArray(ir.sections) || ir.sections.length === 0) {
|
|
2226
|
+
return { rewrittenIR: ir, rewrites: [] };
|
|
2227
|
+
}
|
|
2228
|
+
const rewrites = [];
|
|
2229
|
+
const newSections = ir.sections.map((section) => {
|
|
2230
|
+
if (!section.kind || section.kind === "arbitrary") return section;
|
|
2231
|
+
const rule = matchRule(section.kind, profile, archetype);
|
|
2232
|
+
if (!rule) return section;
|
|
2233
|
+
const originalText = section.text;
|
|
2234
|
+
const transformedText = `${rule.preamble}
|
|
2235
|
+
|
|
2236
|
+
${originalText}`;
|
|
2237
|
+
rewrites.push({
|
|
2238
|
+
sectionId: section.id,
|
|
2239
|
+
kind: section.kind,
|
|
2240
|
+
rule: rule.id,
|
|
2241
|
+
originalText,
|
|
2242
|
+
transformedText,
|
|
2243
|
+
...rule.wireOverrides ? { wireOverrides: rule.wireOverrides } : {}
|
|
2244
|
+
});
|
|
2245
|
+
return { ...section, text: transformedText };
|
|
2246
|
+
});
|
|
2247
|
+
if (rewrites.length === 0) {
|
|
2248
|
+
return { rewrittenIR: ir, rewrites: [] };
|
|
2249
|
+
}
|
|
2250
|
+
const rewrittenIR = { ...ir, sections: newSections };
|
|
2251
|
+
return { rewrittenIR, rewrites };
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
// src/compile.ts
|
|
2255
|
+
var counter = 0;
|
|
2256
|
+
function makeHandle() {
|
|
2257
|
+
counter = (counter + 1) % 1e6;
|
|
2258
|
+
return `c${Date.now().toString(36)}-${counter.toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
2259
|
+
}
|
|
2260
|
+
function compile(ir, opts = {}) {
|
|
2261
|
+
const resolver = opts.profileResolver ?? getProfile;
|
|
2262
|
+
validateIR(ir);
|
|
2263
|
+
ir = resolveModelEntries(ir);
|
|
2264
|
+
const sliced = passSlice(ir);
|
|
2265
|
+
const deduped = passDedupe(sliced.value);
|
|
2266
|
+
const toolFiltered = passToolRelevance(deduped.value, {
|
|
2267
|
+
threshold: opts.toolRelevanceThreshold
|
|
2268
|
+
});
|
|
2269
|
+
const compressed = passCompressHistory(toolFiltered.value, {
|
|
2270
|
+
summarizeOlderThan: opts.compressHistoryAfter,
|
|
2271
|
+
summarizeAboveTokens: opts.compressHistoryAboveTokens
|
|
2272
|
+
});
|
|
2273
|
+
let workingIR = compressed.value;
|
|
2274
|
+
const accumulatedMutations = [
|
|
2275
|
+
...sliced.mutations,
|
|
2276
|
+
...deduped.mutations,
|
|
2277
|
+
...toolFiltered.mutations,
|
|
2278
|
+
...compressed.mutations
|
|
2279
|
+
];
|
|
2280
|
+
const inputTokens = estimateInputTokens(workingIR);
|
|
2281
|
+
const scores = passScoreTargets(workingIR, {
|
|
2282
|
+
estimatedInputTokens: inputTokens,
|
|
2283
|
+
profilesById: resolver,
|
|
2284
|
+
policy: opts.policy
|
|
2285
|
+
});
|
|
2286
|
+
accumulatedMutations.push(...scores.mutations);
|
|
2287
|
+
const target = pickTarget(workingIR, scores.value);
|
|
2288
|
+
if (!target) {
|
|
2289
|
+
throw new Error(
|
|
2290
|
+
`compile(): no allowed model fits the request. Scores: ${JSON.stringify(scores.value, null, 2)}`
|
|
2291
|
+
);
|
|
2292
|
+
}
|
|
2293
|
+
const profile = resolver(target.modelId);
|
|
2294
|
+
const fallbackChain = scores.value.filter((s) => s.modelId !== target.modelId && s.fits).sort((a, b) => b.rank - a.rank).map((s) => s.modelId);
|
|
2295
|
+
const cliffs = passApplyCliffs(workingIR, profile, inputTokens);
|
|
2296
|
+
workingIR = cliffs.value.ir;
|
|
2297
|
+
accumulatedMutations.push(...cliffs.mutations);
|
|
2298
|
+
const conventions = passApplyConventions(workingIR, profile);
|
|
2299
|
+
workingIR = conventions.value.ir;
|
|
2300
|
+
accumulatedMutations.push(...conventions.mutations);
|
|
2301
|
+
const translated = applySectionRewrites({
|
|
2302
|
+
ir: workingIR,
|
|
2303
|
+
profile,
|
|
2304
|
+
archetype: ir.intent.archetype
|
|
2305
|
+
});
|
|
2306
|
+
workingIR = translated.rewrittenIR;
|
|
2307
|
+
const sectionRewritesApplied = translated.rewrites;
|
|
2308
|
+
let wireOverrides;
|
|
2309
|
+
for (const rw of sectionRewritesApplied) {
|
|
2310
|
+
if (!rw.wireOverrides) continue;
|
|
2311
|
+
if (!wireOverrides) wireOverrides = {};
|
|
2312
|
+
if (rw.wireOverrides.parallelToolCalls !== void 0) {
|
|
2313
|
+
wireOverrides.parallelToolCalls = rw.wireOverrides.parallelToolCalls;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
for (const rw of sectionRewritesApplied) {
|
|
2317
|
+
accumulatedMutations.push({
|
|
2318
|
+
id: `translator:${rw.rule}:${rw.sectionId}`,
|
|
2319
|
+
source: "translator",
|
|
2320
|
+
passName: "translator",
|
|
2321
|
+
description: `Rewrote section "${rw.sectionId}" (kind=${rw.kind}) via rule "${rw.rule}".`
|
|
2322
|
+
});
|
|
2323
|
+
}
|
|
2324
|
+
const lowered = lower(workingIR, profile, {
|
|
2325
|
+
forceThinkingZero: cliffs.value.loweringHints.forceThinkingZero,
|
|
2326
|
+
forceTerseOutput: cliffs.value.loweringHints.forceTerseOutput,
|
|
2327
|
+
wireOverrides
|
|
2328
|
+
});
|
|
2329
|
+
validateFinalFit(workingIR, profile, inputTokens);
|
|
2330
|
+
const handle = makeHandle();
|
|
2331
|
+
const finalShape = computeShape(workingIR, inputTokens);
|
|
2332
|
+
const _learningKey = learningKey(ir.intent.archetype, profile.id, finalShape);
|
|
2333
|
+
const historyCacheMarkIndex = computeHistoryCacheMarkIndex(workingIR);
|
|
2334
|
+
const systemMessages = buildSystemMessages(workingIR, profile.provider);
|
|
2335
|
+
const systemCacheMarkIndex = lastCacheableSystemIndex(systemMessages);
|
|
2336
|
+
const diagnostics = {
|
|
2337
|
+
sectionsKept: workingIR.sections.length,
|
|
2338
|
+
sectionsDropped: ir.sections.length - workingIR.sections.length,
|
|
2339
|
+
toolsKept: workingIR.tools?.length ?? 0,
|
|
2340
|
+
toolsDropped: (ir.tools?.length ?? 0) - (workingIR.tools?.length ?? 0),
|
|
2341
|
+
historyKept: workingIR.history?.length ?? 0,
|
|
2342
|
+
historyDropped: (ir.history?.length ?? 0) - (workingIR.history?.length ?? 0),
|
|
2343
|
+
cacheableTokens: lowered.diagnostics.cacheableTokens,
|
|
2344
|
+
estimatedCacheSavingsUsd: lowered.diagnostics.estimatedCacheSavingsUsd,
|
|
2345
|
+
historyCacheableTokens: lowered.diagnostics.historyCacheableTokens,
|
|
2346
|
+
historyTokensTotal: compressed.historyTokensTotal,
|
|
2347
|
+
// alpha.20 E3: mirror the consumer's declared mode for Glass-Box +
|
|
2348
|
+
// brain observability. Undefined when not declared (pre-alpha.20).
|
|
2349
|
+
toolOrchestration: ir.constraints?.toolOrchestration,
|
|
2350
|
+
// alpha.33 — see top-of-block comment.
|
|
2351
|
+
historyCacheMarkIndex,
|
|
2352
|
+
systemCacheMarkIndex,
|
|
2353
|
+
// alpha.43 — cliff-style warnings emitted by passApplyConventions.
|
|
2354
|
+
// Merge convention-pass cliffWarnings with any cliff-guard quality
|
|
2355
|
+
// warnings the cliff pass surfaced (the same shape — informational
|
|
2356
|
+
// text the consumer can route on without changing behavior).
|
|
2357
|
+
cliffWarnings: [
|
|
2358
|
+
...cliffs.value.loweringHints.qualityWarning ?? [],
|
|
2359
|
+
...conventions.value.cliffWarnings
|
|
2360
|
+
]
|
|
2361
|
+
};
|
|
2362
|
+
if (ir.intent.archetype === "hunt" && ir.constraints?.toolOrchestration === "sequential") {
|
|
2363
|
+
accumulatedMutations.push({
|
|
2364
|
+
id: "sequential-mode-chain-selected",
|
|
2365
|
+
source: "tool_orchestration",
|
|
2366
|
+
passName: "compile",
|
|
2367
|
+
description: "ir.constraints.toolOrchestration='sequential' selected the DeepSeek-tier-0 hunt chain overlay (L-040 parallel-tool cliff doesn't apply at single-step granularity)."
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
const phase2ProfileResolver = opts.profileResolver ? (id) => {
|
|
2371
|
+
try {
|
|
2372
|
+
return opts.profileResolver(id);
|
|
2373
|
+
} catch {
|
|
2374
|
+
return void 0;
|
|
2375
|
+
}
|
|
2376
|
+
} : tryGetProfile;
|
|
2377
|
+
const rawAdvisories = runAdvisor(
|
|
2378
|
+
ir,
|
|
2379
|
+
{
|
|
2380
|
+
target: profile.id,
|
|
2381
|
+
provider: profile.provider,
|
|
2382
|
+
tokensIn: inputTokens,
|
|
2383
|
+
diagnostics
|
|
2384
|
+
},
|
|
2385
|
+
profile,
|
|
2386
|
+
opts.policy,
|
|
2387
|
+
{
|
|
2388
|
+
fallbackChain,
|
|
2389
|
+
profileResolver: phase2ProfileResolver,
|
|
2390
|
+
// alpha.29 — feed translator rewrites to the advisor so the
|
|
2391
|
+
// `archetype-perf-floor-breach` rule can suppress when the translator
|
|
2392
|
+
// already cleared the cliff for the same archetype. Without this,
|
|
2393
|
+
// both the rewrite AND the advisory fire — noisy, and the advisory
|
|
2394
|
+
// would mislead consumers into thinking the cliff is unaddressed.
|
|
2395
|
+
sectionRewritesApplied
|
|
2396
|
+
}
|
|
2397
|
+
);
|
|
2398
|
+
const advisories = rawAdvisories.map((a) => ({
|
|
2399
|
+
...a,
|
|
2400
|
+
kgautoRequestId: handle,
|
|
2401
|
+
ownership: deriveOwnership(a.code, a.ownership)
|
|
2402
|
+
}));
|
|
2403
|
+
return {
|
|
2404
|
+
handle,
|
|
2405
|
+
target: profile.id,
|
|
2406
|
+
provider: profile.provider,
|
|
2407
|
+
request: lowered.request,
|
|
2408
|
+
tokensIn: inputTokens,
|
|
2409
|
+
estimatedCostUsd: target.estimatedCostUsd,
|
|
2410
|
+
mutationsApplied: accumulatedMutations,
|
|
2411
|
+
fallbackChain,
|
|
2412
|
+
advisories,
|
|
2413
|
+
diagnostics,
|
|
2414
|
+
sectionRewritesApplied,
|
|
2415
|
+
wireOverrides,
|
|
2416
|
+
systemMessages
|
|
2417
|
+
};
|
|
2418
|
+
}
|
|
2419
|
+
function computeHistoryCacheMarkIndex(ir) {
|
|
2420
|
+
const policy = ir.historyCachePolicy;
|
|
2421
|
+
if (!policy || policy.strategy === "none") return void 0;
|
|
2422
|
+
const historyLen = ir.history?.length ?? 0;
|
|
2423
|
+
if (historyLen === 0) return void 0;
|
|
2424
|
+
if (policy.strategy === "all-but-latest") {
|
|
2425
|
+
return historyLen - 1;
|
|
2426
|
+
}
|
|
2427
|
+
if (policy.strategy === "fixed-suffix") {
|
|
2428
|
+
const idx = historyLen - 1 - policy.suffix;
|
|
2429
|
+
if (idx < 0) return void 0;
|
|
2430
|
+
return idx;
|
|
2431
|
+
}
|
|
2432
|
+
return void 0;
|
|
2433
|
+
}
|
|
2434
|
+
function buildSystemMessages(ir, provider) {
|
|
2435
|
+
const sections = ir.sections;
|
|
2436
|
+
if (!sections || sections.length === 0) return [];
|
|
2437
|
+
return sections.map((s) => {
|
|
2438
|
+
const base = { role: "system", content: s.text };
|
|
2439
|
+
if (provider === "anthropic" && s.cacheable) {
|
|
2440
|
+
base.providerOptions = { anthropic: { cacheControl: { type: "ephemeral" } } };
|
|
2441
|
+
}
|
|
2442
|
+
return base;
|
|
2443
|
+
});
|
|
2444
|
+
}
|
|
2445
|
+
function lastCacheableSystemIndex(systemMessages) {
|
|
2446
|
+
for (let i = systemMessages.length - 1; i >= 0; i--) {
|
|
2447
|
+
const entry = systemMessages[i];
|
|
2448
|
+
if (entry && entry.providerOptions?.anthropic?.cacheControl) {
|
|
2449
|
+
return i;
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
return void 0;
|
|
2453
|
+
}
|
|
2454
|
+
function validateIR(ir) {
|
|
2455
|
+
if (!ir.appId) throw new Error("compile(): ir.appId is required");
|
|
2456
|
+
if (!ir.intent || !ir.intent.archetype) {
|
|
2457
|
+
throw new Error("compile(): ir.intent.archetype is required (use a dialect-v1 archetype)");
|
|
2458
|
+
}
|
|
2459
|
+
if (!Array.isArray(ir.models) || ir.models.length === 0) {
|
|
2460
|
+
throw new Error("compile(): ir.models must be a non-empty array");
|
|
2461
|
+
}
|
|
2462
|
+
if (!Array.isArray(ir.sections)) {
|
|
2463
|
+
throw new Error("compile(): ir.sections must be an array");
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
function resolveModelEntries(ir) {
|
|
2467
|
+
const out = [];
|
|
2468
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2469
|
+
for (const entry of ir.models) {
|
|
2470
|
+
let id;
|
|
2471
|
+
if (typeof entry === "string") {
|
|
2472
|
+
id = entry;
|
|
2473
|
+
} else if (entry && typeof entry === "object" && "family" in entry) {
|
|
2474
|
+
id = resolveFamilyEntry(entry.family, {
|
|
2475
|
+
archetype: ir.intent.archetype,
|
|
2476
|
+
appId: ir.appId
|
|
2477
|
+
});
|
|
2478
|
+
} else {
|
|
2479
|
+
throw new Error(
|
|
2480
|
+
`compile(): ir.models entry must be a string or { family: string }; got ${JSON.stringify(entry)}`
|
|
2481
|
+
);
|
|
2482
|
+
}
|
|
2483
|
+
if (seen.has(id)) continue;
|
|
2484
|
+
seen.add(id);
|
|
2485
|
+
out.push(id);
|
|
2486
|
+
}
|
|
2487
|
+
return { ...ir, models: out };
|
|
2488
|
+
}
|
|
2489
|
+
function pickTarget(ir, scores) {
|
|
2490
|
+
if (ir.constraints?.forceModel) {
|
|
2491
|
+
const forced = scores.find((s) => s.modelId === ir.constraints.forceModel);
|
|
2492
|
+
if (forced && forced.fits) return forced;
|
|
2493
|
+
if (forced) {
|
|
2494
|
+
throw new Error(
|
|
2495
|
+
`compile(): forceModel="${ir.constraints.forceModel}" does not fit: ${forced.rejectReasons.join("; ")}`
|
|
2496
|
+
);
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
const fitting = scores.filter((s) => s.fits).sort((a, b) => b.rank - a.rank);
|
|
2500
|
+
return fitting[0];
|
|
767
2501
|
}
|
|
768
2502
|
function validateFinalFit(ir, profile, tokens) {
|
|
769
2503
|
if (tokens > profile.maxContextTokens) {
|
|
@@ -778,14 +2512,103 @@ function validateFinalFit(ir, profile, tokens) {
|
|
|
778
2512
|
}
|
|
779
2513
|
}
|
|
780
2514
|
|
|
2515
|
+
// src/pricing-brain.ts
|
|
2516
|
+
function isPricingRow(x) {
|
|
2517
|
+
if (!x || typeof x !== "object") return false;
|
|
2518
|
+
const r = x;
|
|
2519
|
+
return typeof r.model_id === "string" && typeof r.cost_input_per_1m === "number" && typeof r.cost_output_per_1m === "number" && typeof r.valid_from === "string";
|
|
2520
|
+
}
|
|
2521
|
+
function mapRowsToPricing(rows) {
|
|
2522
|
+
const out = [];
|
|
2523
|
+
for (const row of rows) {
|
|
2524
|
+
if (!isPricingRow(row)) continue;
|
|
2525
|
+
out.push({
|
|
2526
|
+
modelId: row.model_id,
|
|
2527
|
+
costInputPer1m: row.cost_input_per_1m,
|
|
2528
|
+
costOutputPer1m: row.cost_output_per_1m,
|
|
2529
|
+
cacheInputPer1m: row.cache_input_per_1m ?? void 0,
|
|
2530
|
+
cacheCreationPer1m: row.cache_creation_per_1m ?? void 0,
|
|
2531
|
+
validFrom: Date.parse(row.valid_from),
|
|
2532
|
+
validUntil: row.valid_until == null ? void 0 : Date.parse(row.valid_until),
|
|
2533
|
+
source: row.source ?? void 0
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2536
|
+
return out;
|
|
2537
|
+
}
|
|
2538
|
+
function bundledPricing() {
|
|
2539
|
+
const out = [];
|
|
2540
|
+
for (const profile of allProfiles()) {
|
|
2541
|
+
out.push({
|
|
2542
|
+
modelId: profile.id,
|
|
2543
|
+
costInputPer1m: profile.costInputPer1m,
|
|
2544
|
+
costOutputPer1m: profile.costOutputPer1m,
|
|
2545
|
+
cacheInputPer1m: profile.lowering.cache.discount !== void 0 && profile.lowering.cache.discount > 0 ? profile.costInputPer1m * profile.lowering.cache.discount : void 0,
|
|
2546
|
+
validFrom: 0,
|
|
2547
|
+
validUntil: void 0,
|
|
2548
|
+
source: "profile_seed"
|
|
2549
|
+
});
|
|
2550
|
+
}
|
|
2551
|
+
return out;
|
|
2552
|
+
}
|
|
2553
|
+
var loadPricingFromBrain = createBrainQueryCache({
|
|
2554
|
+
table: "kgauto_pricing",
|
|
2555
|
+
mapRows: mapRowsToPricing,
|
|
2556
|
+
bundledFallback: bundledPricing
|
|
2557
|
+
});
|
|
2558
|
+
function resolvePricingAt(modelId, at = /* @__PURE__ */ new Date()) {
|
|
2559
|
+
const ts = at.getTime();
|
|
2560
|
+
const all = loadPricingFromBrain();
|
|
2561
|
+
let best;
|
|
2562
|
+
for (const row of all) {
|
|
2563
|
+
if (row.modelId !== modelId) continue;
|
|
2564
|
+
if (row.validFrom > ts) continue;
|
|
2565
|
+
if (row.validUntil !== void 0 && row.validUntil <= ts) continue;
|
|
2566
|
+
if (!best || row.validFrom > best.validFrom) best = row;
|
|
2567
|
+
}
|
|
2568
|
+
return best;
|
|
2569
|
+
}
|
|
2570
|
+
|
|
781
2571
|
// src/brain.ts
|
|
782
2572
|
var activeConfig;
|
|
783
2573
|
function configureBrain(config) {
|
|
784
2574
|
const endpoint = config.endpoint.replace(/\/outcomes\/?$/, "");
|
|
785
2575
|
activeConfig = { ...config, endpoint };
|
|
2576
|
+
const bq = config.brainQuery ?? {};
|
|
2577
|
+
const enabledTables = /* @__PURE__ */ new Set();
|
|
2578
|
+
if (bq.chains !== false) enabledTables.add("kgauto_chains");
|
|
2579
|
+
if (bq.perf !== false) enabledTables.add("kgauto_archetype_perf");
|
|
2580
|
+
if (bq.pricing !== false) enabledTables.add("kgauto_pricing");
|
|
2581
|
+
if (bq.models !== false) {
|
|
2582
|
+
enabledTables.add("kgauto_models");
|
|
2583
|
+
enabledTables.add("kgauto_aliases");
|
|
2584
|
+
}
|
|
2585
|
+
if (enabledTables.size === 0) {
|
|
2586
|
+
configureBrainQuery(void 0);
|
|
2587
|
+
} else {
|
|
2588
|
+
configureBrainQuery({
|
|
2589
|
+
endpoint,
|
|
2590
|
+
configEndpoint: bq.configEndpoint,
|
|
2591
|
+
ttlMs: bq.cacheTtlMs ?? 3e5,
|
|
2592
|
+
fetchImpl: config.fetchImpl ?? fetch,
|
|
2593
|
+
enabledTables,
|
|
2594
|
+
onError: config.onError
|
|
2595
|
+
});
|
|
2596
|
+
}
|
|
2597
|
+
if (bq.findingsExclusions !== false) {
|
|
2598
|
+
configureExclusionFindingsBrain({
|
|
2599
|
+
endpoint: bq.findingsEndpoint ?? DEFAULT_FINDINGS_ENDPOINT,
|
|
2600
|
+
ttlMs: bq.cacheTtlMs ?? 3e5,
|
|
2601
|
+
fetchImpl: config.fetchImpl ?? fetch,
|
|
2602
|
+
onError: config.onError
|
|
2603
|
+
});
|
|
2604
|
+
} else {
|
|
2605
|
+
configureExclusionFindingsBrain(void 0);
|
|
2606
|
+
}
|
|
786
2607
|
}
|
|
787
2608
|
function clearBrain() {
|
|
788
2609
|
activeConfig = void 0;
|
|
2610
|
+
configureBrainQuery(void 0);
|
|
2611
|
+
configureExclusionFindingsBrain(void 0);
|
|
789
2612
|
}
|
|
790
2613
|
var compileRegistry = /* @__PURE__ */ new Map();
|
|
791
2614
|
var REGISTRY_MAX_ENTRIES = 1e4;
|
|
@@ -812,6 +2635,9 @@ function registerCompile(appId, archetype, ir, result) {
|
|
|
812
2635
|
tokens
|
|
813
2636
|
);
|
|
814
2637
|
const shapeKey = `${shape.contextBucket}-${shape.toolCountBucket}-${shape.historyDepth}-${shape.outputMode}`;
|
|
2638
|
+
const toolsCount = result.diagnostics.toolsKept;
|
|
2639
|
+
const historyDepth = Array.isArray(ir.history) ? ir.history.length : 0;
|
|
2640
|
+
const systemPromptChars = estimateSystemPromptChars(ir.sections);
|
|
815
2641
|
compileRegistry.set(result.handle, {
|
|
816
2642
|
appId,
|
|
817
2643
|
archetype,
|
|
@@ -821,13 +2647,66 @@ function registerCompile(appId, archetype, ir, result) {
|
|
|
821
2647
|
learningKey: learningKey(archetype, result.target, shape),
|
|
822
2648
|
estimatedTokensIn: tokens,
|
|
823
2649
|
mutationsApplied: result.mutationsApplied.map((m) => m.id),
|
|
2650
|
+
// alpha.30: cache the in-memory advisories so record() can auto-persist
|
|
2651
|
+
// to `compile_outcome_advisories` without consumer-side threading.
|
|
2652
|
+
advisoriesFromCompile: result.advisories ?? [],
|
|
824
2653
|
startedAt: Date.now(),
|
|
825
|
-
historyCacheableTokens: result.diagnostics.historyCacheableTokens
|
|
2654
|
+
historyCacheableTokens: result.diagnostics.historyCacheableTokens,
|
|
2655
|
+
historyTokensTotal: result.diagnostics.historyTokensTotal,
|
|
2656
|
+
// alpha.20 E3: capture consumer's declared mode for the brain payload.
|
|
2657
|
+
toolOrchestration: result.diagnostics.toolOrchestration,
|
|
2658
|
+
// alpha.28: shape fields for Glass-Box renderer.
|
|
2659
|
+
toolsCount,
|
|
2660
|
+
historyDepth,
|
|
2661
|
+
systemPromptChars,
|
|
2662
|
+
// alpha.29: translator activity — persisted on the brain row so
|
|
2663
|
+
// cross-app aggregates can answer "Sonnet narration rule fired N times,
|
|
2664
|
+
// outcome quality lifted to M."
|
|
2665
|
+
sectionRewritesApplied: result.sectionRewritesApplied
|
|
826
2666
|
});
|
|
827
2667
|
}
|
|
2668
|
+
function estimateSystemPromptChars(sections) {
|
|
2669
|
+
if (!Array.isArray(sections) || sections.length === 0) return void 0;
|
|
2670
|
+
let total = 0;
|
|
2671
|
+
for (const s of sections) {
|
|
2672
|
+
if (s && typeof s === "object") {
|
|
2673
|
+
const content = s.content;
|
|
2674
|
+
if (typeof content === "string") total += content.length;
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
return total > 0 ? total : void 0;
|
|
2678
|
+
}
|
|
2679
|
+
function armCompileConsumeTracking(handle) {
|
|
2680
|
+
const reg = compileRegistry.get(handle);
|
|
2681
|
+
if (!reg) return;
|
|
2682
|
+
reg.consumeTracked = true;
|
|
2683
|
+
reg.systemConsumed = false;
|
|
2684
|
+
reg.modelConsumed = false;
|
|
2685
|
+
reg.rawConsumed = false;
|
|
2686
|
+
}
|
|
2687
|
+
function markCompileConsumed(handle, field) {
|
|
2688
|
+
const reg = compileRegistry.get(handle);
|
|
2689
|
+
if (!reg || !reg.consumeTracked) return;
|
|
2690
|
+
if (field === "system") reg.systemConsumed = true;
|
|
2691
|
+
else if (field === "model") reg.modelConsumed = true;
|
|
2692
|
+
else reg.rawConsumed = true;
|
|
2693
|
+
}
|
|
2694
|
+
function maybeWarnDiscardedCompile(reg, handle) {
|
|
2695
|
+
if (!reg.consumeTracked) return;
|
|
2696
|
+
if (reg.systemConsumed || reg.modelConsumed || reg.rawConsumed) return;
|
|
2697
|
+
const isProd = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
2698
|
+
const enabled = activeConfig?.warnOnDiscardedCompile ?? !isProd;
|
|
2699
|
+
if (!enabled) return;
|
|
2700
|
+
console.warn(
|
|
2701
|
+
`[kgauto] compile-then-discard: compileForAISDKv6() output for handle ${handle} (archetype=${reg.archetype}, model=${reg.model}) was recorded but neither .system, .model, nor .raw was read before record(). The brain row's mutations_applied / estimated_tokens_in / system_prompt_chars describe a compile that did NOT shape the served call. Pass compiled.system + compiled.model into your generateText/streamText (or use call()). Silence via configureBrain({ warnOnDiscardedCompile: false }).`
|
|
2702
|
+
);
|
|
2703
|
+
}
|
|
828
2704
|
async function record(input) {
|
|
829
2705
|
const reg = compileRegistry.get(input.handle);
|
|
830
|
-
if (reg)
|
|
2706
|
+
if (reg) {
|
|
2707
|
+
maybeWarnDiscardedCompile(reg, input.handle);
|
|
2708
|
+
compileRegistry.delete(input.handle);
|
|
2709
|
+
}
|
|
831
2710
|
if (!activeConfig) {
|
|
832
2711
|
return;
|
|
833
2712
|
}
|
|
@@ -835,11 +2714,22 @@ async function record(input) {
|
|
|
835
2714
|
const config = activeConfig;
|
|
836
2715
|
const fetchFn = config.fetchImpl ?? fetch;
|
|
837
2716
|
const send = async () => {
|
|
2717
|
+
let outcomeId;
|
|
838
2718
|
try {
|
|
839
2719
|
const res = await fetchFn(`${config.endpoint}/outcomes`, {
|
|
840
2720
|
method: "POST",
|
|
841
2721
|
headers: {
|
|
842
2722
|
"Content-Type": "application/json",
|
|
2723
|
+
// alpha.20: request the inserted row back so we can JOIN advisories
|
|
2724
|
+
// to it via outcome_id. PostgREST returns the row when
|
|
2725
|
+
// `Prefer: return=representation` is set; proxies that pass the
|
|
2726
|
+
// header through (the recommended `const row = { ...body }` shape
|
|
2727
|
+
// from OutcomePayload's forward-compat rule) will surface
|
|
2728
|
+
// the row id. Proxies that don't (legacy / hand-rolled shapes)
|
|
2729
|
+
// simply produce no parseable id → secondary advisory POST is
|
|
2730
|
+
// skipped silently. Best-effort — primary outcome row is the
|
|
2731
|
+
// load-bearing write.
|
|
2732
|
+
Prefer: "return=representation",
|
|
843
2733
|
...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}
|
|
844
2734
|
},
|
|
845
2735
|
body: JSON.stringify(payload)
|
|
@@ -848,8 +2738,31 @@ async function record(input) {
|
|
|
848
2738
|
const text = await res.text().catch(() => "<no body>");
|
|
849
2739
|
throw new Error(`brain ${res.status}: ${text}`);
|
|
850
2740
|
}
|
|
2741
|
+
outcomeId = await tryExtractOutcomeId(res);
|
|
2742
|
+
} catch (err) {
|
|
2743
|
+
(config.onError ?? defaultOnError4)(err);
|
|
2744
|
+
return;
|
|
2745
|
+
}
|
|
2746
|
+
const advisories = input.advisories ?? reg?.advisoriesFromCompile;
|
|
2747
|
+
if (!advisories || advisories.length === 0) return;
|
|
2748
|
+
if (outcomeId === void 0) return;
|
|
2749
|
+
try {
|
|
2750
|
+
const advisoryPayload = advisories.map((a) => buildAdvisoryRow(outcomeId, a));
|
|
2751
|
+
const res = await fetchFn(`${config.endpoint}/compile_outcome_advisories`, {
|
|
2752
|
+
method: "POST",
|
|
2753
|
+
headers: {
|
|
2754
|
+
"Content-Type": "application/json",
|
|
2755
|
+
Prefer: "return=minimal",
|
|
2756
|
+
...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}
|
|
2757
|
+
},
|
|
2758
|
+
body: JSON.stringify(advisoryPayload)
|
|
2759
|
+
});
|
|
2760
|
+
if (!res.ok) {
|
|
2761
|
+
const text = await res.text().catch(() => "<no body>");
|
|
2762
|
+
throw new Error(`brain advisories ${res.status}: ${text}`);
|
|
2763
|
+
}
|
|
851
2764
|
} catch (err) {
|
|
852
|
-
(config.onError ??
|
|
2765
|
+
(config.onError ?? defaultOnError4)(err);
|
|
853
2766
|
}
|
|
854
2767
|
};
|
|
855
2768
|
if (config.sync) {
|
|
@@ -858,7 +2771,7 @@ async function record(input) {
|
|
|
858
2771
|
void send();
|
|
859
2772
|
}
|
|
860
2773
|
}
|
|
861
|
-
function
|
|
2774
|
+
function defaultOnError4(err) {
|
|
862
2775
|
console.warn("[kgauto] brain record failed:", err);
|
|
863
2776
|
}
|
|
864
2777
|
function buildPayload(input, reg) {
|
|
@@ -868,6 +2781,8 @@ function buildPayload(input, reg) {
|
|
|
868
2781
|
const mutationsApplied = input.mutationsApplied ?? reg?.mutationsApplied ?? [];
|
|
869
2782
|
const costModel = actual;
|
|
870
2783
|
const costUsdActual = costModel ? computeCostUsd(costModel, input.tokensIn, input.tokensOut) : void 0;
|
|
2784
|
+
const fellOverFrom = input.fellOverFrom ?? requested;
|
|
2785
|
+
const fallbackReason = fellOverFrom ? input.fallbackReason : void 0;
|
|
871
2786
|
return {
|
|
872
2787
|
handle: input.handle,
|
|
873
2788
|
app_id: reg?.appId,
|
|
@@ -896,17 +2811,173 @@ function buildPayload(input, reg) {
|
|
|
896
2811
|
cache_creation_input_tokens: input.cacheCreationInputTokens,
|
|
897
2812
|
cost_usd_actual: costUsdActual,
|
|
898
2813
|
ttft_ms: input.ttftMs,
|
|
899
|
-
history_cacheable_tokens: reg?.historyCacheableTokens
|
|
2814
|
+
history_cacheable_tokens: reg?.historyCacheableTokens,
|
|
2815
|
+
history_tokens_at_compile: reg?.historyTokensTotal,
|
|
2816
|
+
// alpha.20 E3: mirror consumer's declared tool-orchestration mode so
|
|
2817
|
+
// the brain can measure per-mode model perf separately (DeepSeek in
|
|
2818
|
+
// sequential vs parallel mode is two different stories — L-040).
|
|
2819
|
+
// Null when consumer hadn't adopted the constraint yet.
|
|
2820
|
+
tool_orchestration: reg?.toolOrchestration ?? null,
|
|
2821
|
+
// alpha.28 — Glass-Box renderer substrate (migration 018). All optional;
|
|
2822
|
+
// omitted-undefined PostgREST inserts store NULL → renderer renders "—".
|
|
2823
|
+
finish_reason: input.finishReason,
|
|
2824
|
+
total_ms: input.totalMs ?? input.latencyMs,
|
|
2825
|
+
tools_count: input.toolsCount ?? reg?.toolsCount,
|
|
2826
|
+
history_depth: input.historyDepth ?? reg?.historyDepth,
|
|
2827
|
+
system_prompt_chars: input.systemPromptChars ?? reg?.systemPromptChars,
|
|
2828
|
+
fell_over_from: fellOverFrom,
|
|
2829
|
+
fallback_reason: fallbackReason,
|
|
2830
|
+
// alpha.29 — translator activity (migration 019). Send NULL when no
|
|
2831
|
+
// rewrites fired so the brain's "did the translator do anything?"
|
|
2832
|
+
// queries can use `IS NOT NULL` cleanly.
|
|
2833
|
+
section_rewrites_applied: reg?.sectionRewritesApplied && reg.sectionRewritesApplied.length > 0 ? reg.sectionRewritesApplied : null
|
|
900
2834
|
};
|
|
901
2835
|
}
|
|
902
2836
|
function computeCostUsd(modelId, tokensIn, tokensOut) {
|
|
903
2837
|
if (tokensIn === 0 && tokensOut === 0) return void 0;
|
|
2838
|
+
const brainRow = resolvePricingAt(modelId);
|
|
2839
|
+
if (brainRow && (brainRow.costInputPer1m > 0 || brainRow.costOutputPer1m > 0)) {
|
|
2840
|
+
const inUsd2 = tokensIn / 1e6 * brainRow.costInputPer1m;
|
|
2841
|
+
const outUsd2 = tokensOut / 1e6 * brainRow.costOutputPer1m;
|
|
2842
|
+
return Math.round((inUsd2 + outUsd2) * 1e6) / 1e6;
|
|
2843
|
+
}
|
|
904
2844
|
const profile = tryGetProfile(modelId);
|
|
905
2845
|
if (!profile) return void 0;
|
|
906
2846
|
const inUsd = tokensIn / 1e6 * profile.costInputPer1m;
|
|
907
2847
|
const outUsd = tokensOut / 1e6 * profile.costOutputPer1m;
|
|
908
2848
|
return Math.round((inUsd + outUsd) * 1e6) / 1e6;
|
|
909
2849
|
}
|
|
2850
|
+
async function tryExtractOutcomeId(res) {
|
|
2851
|
+
try {
|
|
2852
|
+
const ct = res.headers?.get?.("content-type") ?? "";
|
|
2853
|
+
if (ct && !ct.includes("application/json")) return void 0;
|
|
2854
|
+
if (typeof res.json !== "function") return void 0;
|
|
2855
|
+
const body = await res.json();
|
|
2856
|
+
if (Array.isArray(body) && body.length > 0) {
|
|
2857
|
+
const first = body[0];
|
|
2858
|
+
const id = first?.id;
|
|
2859
|
+
if (typeof id === "number") return id;
|
|
2860
|
+
} else if (body && typeof body === "object") {
|
|
2861
|
+
const id = body.id;
|
|
2862
|
+
if (typeof id === "number") return id;
|
|
2863
|
+
}
|
|
2864
|
+
return void 0;
|
|
2865
|
+
} catch {
|
|
2866
|
+
return void 0;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
function buildAdvisoryRow(outcomeId, a) {
|
|
2870
|
+
return {
|
|
2871
|
+
outcome_id: outcomeId,
|
|
2872
|
+
code: a.code,
|
|
2873
|
+
level: a.level,
|
|
2874
|
+
message: a.message,
|
|
2875
|
+
...a.recommendationType ? { recommendation_type: a.recommendationType } : {},
|
|
2876
|
+
...a.suggestion ? { suggestion: a.suggestion } : {},
|
|
2877
|
+
...a.docsUrl ? { docs_url: a.docsUrl } : {}
|
|
2878
|
+
};
|
|
2879
|
+
}
|
|
2880
|
+
async function recordOutcome(input) {
|
|
2881
|
+
if (!activeConfig) {
|
|
2882
|
+
return { ok: false, reason: "brain_not_configured" };
|
|
2883
|
+
}
|
|
2884
|
+
const config = activeConfig;
|
|
2885
|
+
const fetchFn = config.fetchImpl ?? fetch;
|
|
2886
|
+
const payload = {
|
|
2887
|
+
outcome_id: input.outcomeId,
|
|
2888
|
+
outcome: input.outcome,
|
|
2889
|
+
rating: input.rating ?? null,
|
|
2890
|
+
reason: input.reason ?? null,
|
|
2891
|
+
observed_confidence: input.observedConfidence ?? null
|
|
2892
|
+
};
|
|
2893
|
+
const send = async () => {
|
|
2894
|
+
try {
|
|
2895
|
+
const res = await fetchFn(`${config.endpoint}/compile_outcome_quality`, {
|
|
2896
|
+
method: "POST",
|
|
2897
|
+
headers: {
|
|
2898
|
+
"Content-Type": "application/json",
|
|
2899
|
+
...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}
|
|
2900
|
+
},
|
|
2901
|
+
body: JSON.stringify(payload)
|
|
2902
|
+
});
|
|
2903
|
+
if (!res.ok) {
|
|
2904
|
+
const text = await res.text().catch(() => "<no body>");
|
|
2905
|
+
const err = new Error(`brain ${res.status}: ${text}`);
|
|
2906
|
+
(config.onError ?? defaultOnError4)(err);
|
|
2907
|
+
return { ok: false, reason: "persistence_failed" };
|
|
2908
|
+
}
|
|
2909
|
+
return { ok: true };
|
|
2910
|
+
} catch (err) {
|
|
2911
|
+
(config.onError ?? defaultOnError4)(err);
|
|
2912
|
+
return { ok: false, reason: "persistence_failed" };
|
|
2913
|
+
}
|
|
2914
|
+
};
|
|
2915
|
+
if (config.sync) {
|
|
2916
|
+
return send();
|
|
2917
|
+
}
|
|
2918
|
+
void send();
|
|
2919
|
+
return { ok: true };
|
|
2920
|
+
}
|
|
2921
|
+
function isBrainSync() {
|
|
2922
|
+
return activeConfig?.sync === true;
|
|
2923
|
+
}
|
|
2924
|
+
function buildShadowProbeRow(input) {
|
|
2925
|
+
return {
|
|
2926
|
+
app_id: input.appId,
|
|
2927
|
+
intent_archetype: input.archetype,
|
|
2928
|
+
family: input.family,
|
|
2929
|
+
candidate_model: input.candidateModel,
|
|
2930
|
+
current_model: input.currentModel,
|
|
2931
|
+
prompt_hash: input.promptHash,
|
|
2932
|
+
current_response: input.currentResponsePreview ?? null,
|
|
2933
|
+
candidate_response: input.candidateResponsePreview ?? null,
|
|
2934
|
+
judge_verdict: null,
|
|
2935
|
+
judge_score: null,
|
|
2936
|
+
tokens_current_in: input.tokensCurrentIn ?? null,
|
|
2937
|
+
tokens_current_out: input.tokensCurrentOut ?? null,
|
|
2938
|
+
tokens_candidate_in: input.tokensCandidateIn ?? null,
|
|
2939
|
+
tokens_candidate_out: input.tokensCandidateOut ?? null,
|
|
2940
|
+
latency_current_ms: input.latencyCurrentMs ?? null,
|
|
2941
|
+
latency_candidate_ms: input.latencyCandidateMs ?? null,
|
|
2942
|
+
// Full IR was replayed (not a truncated preview), so fidelity is 1.0 — the
|
|
2943
|
+
// prompt-fidelity guard never fires on these rows.
|
|
2944
|
+
prompt_fidelity: 1,
|
|
2945
|
+
replay_source: "inline-full-ir",
|
|
2946
|
+
// alpha — migration 029. 'completed' is the default completed-probe shape;
|
|
2947
|
+
// diagnostic rows (aborted/skipped) pass the explicit class.
|
|
2948
|
+
outcome: input.outcome ?? "completed"
|
|
2949
|
+
};
|
|
2950
|
+
}
|
|
2951
|
+
async function recordShadowProbe(input) {
|
|
2952
|
+
if (!activeConfig) return;
|
|
2953
|
+
const config = activeConfig;
|
|
2954
|
+
const fetchFn = config.fetchImpl ?? fetch;
|
|
2955
|
+
const row = buildShadowProbeRow(input);
|
|
2956
|
+
const send = async () => {
|
|
2957
|
+
try {
|
|
2958
|
+
const res = await fetchFn(`${config.endpoint}/probe_outcomes`, {
|
|
2959
|
+
method: "POST",
|
|
2960
|
+
headers: {
|
|
2961
|
+
"Content-Type": "application/json",
|
|
2962
|
+
Prefer: "return=minimal",
|
|
2963
|
+
...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}
|
|
2964
|
+
},
|
|
2965
|
+
body: JSON.stringify(row)
|
|
2966
|
+
});
|
|
2967
|
+
if (!res.ok) {
|
|
2968
|
+
const text = await res.text().catch(() => "<no body>");
|
|
2969
|
+
throw new Error(`brain probe_outcomes ${res.status}: ${text}`);
|
|
2970
|
+
}
|
|
2971
|
+
} catch (err) {
|
|
2972
|
+
(config.onError ?? defaultOnError4)(err);
|
|
2973
|
+
}
|
|
2974
|
+
};
|
|
2975
|
+
if (config.sync) {
|
|
2976
|
+
await send();
|
|
2977
|
+
} else {
|
|
2978
|
+
void send();
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
910
2981
|
|
|
911
2982
|
// src/ir.ts
|
|
912
2983
|
var CallError = class extends Error {
|
|
@@ -920,10 +2991,297 @@ var CallError = class extends Error {
|
|
|
920
2991
|
this.lastStatus = lastStatus;
|
|
921
2992
|
this.lastErrorCode = lastErrorCode;
|
|
922
2993
|
}
|
|
923
|
-
};
|
|
2994
|
+
};
|
|
2995
|
+
|
|
2996
|
+
// src/streaming.ts
|
|
2997
|
+
var ANTHROPIC_URL = "https://api.anthropic.com/v1/messages";
|
|
2998
|
+
async function streamAnthropic(request, apiKey, opts) {
|
|
2999
|
+
const { provider: _provider, ...body } = request;
|
|
3000
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
3001
|
+
let res;
|
|
3002
|
+
try {
|
|
3003
|
+
res = await fetchFn(ANTHROPIC_URL, {
|
|
3004
|
+
method: "POST",
|
|
3005
|
+
headers: {
|
|
3006
|
+
"x-api-key": apiKey,
|
|
3007
|
+
"anthropic-version": "2023-06-01",
|
|
3008
|
+
"content-type": "application/json"
|
|
3009
|
+
},
|
|
3010
|
+
body: JSON.stringify({ ...body, stream: true })
|
|
3011
|
+
});
|
|
3012
|
+
} catch (err) {
|
|
3013
|
+
return retryableError(0, "network_error", String(err), null);
|
|
3014
|
+
}
|
|
3015
|
+
if (!res.ok) {
|
|
3016
|
+
const errBody = await res.json().catch(() => ({}));
|
|
3017
|
+
return classifyHttpError(res.status, errBody);
|
|
3018
|
+
}
|
|
3019
|
+
let text = "";
|
|
3020
|
+
let inputTokens = 0;
|
|
3021
|
+
let outputTokens = 0;
|
|
3022
|
+
let cacheReadTokens;
|
|
3023
|
+
let cacheCreatedTokens;
|
|
3024
|
+
let stopReason;
|
|
3025
|
+
const toolBlocks = /* @__PURE__ */ new Map();
|
|
3026
|
+
try {
|
|
3027
|
+
await parseSSEStream(res, (event) => {
|
|
3028
|
+
if (!event.data) return;
|
|
3029
|
+
let payload;
|
|
3030
|
+
try {
|
|
3031
|
+
payload = JSON.parse(event.data);
|
|
3032
|
+
} catch {
|
|
3033
|
+
return;
|
|
3034
|
+
}
|
|
3035
|
+
const type = payload.type;
|
|
3036
|
+
if (type === "message_start") {
|
|
3037
|
+
const msg = payload.message;
|
|
3038
|
+
const usage = msg?.usage;
|
|
3039
|
+
if (usage) {
|
|
3040
|
+
inputTokens = usage.input_tokens ?? 0;
|
|
3041
|
+
outputTokens = usage.output_tokens ?? 0;
|
|
3042
|
+
if (typeof usage.cache_read_input_tokens === "number")
|
|
3043
|
+
cacheReadTokens = usage.cache_read_input_tokens;
|
|
3044
|
+
if (typeof usage.cache_creation_input_tokens === "number")
|
|
3045
|
+
cacheCreatedTokens = usage.cache_creation_input_tokens;
|
|
3046
|
+
}
|
|
3047
|
+
return;
|
|
3048
|
+
}
|
|
3049
|
+
if (type === "content_block_start") {
|
|
3050
|
+
const p = payload;
|
|
3051
|
+
const idx = p.index ?? 0;
|
|
3052
|
+
const block = p.content_block;
|
|
3053
|
+
if (block?.type === "tool_use" && block.id && block.name) {
|
|
3054
|
+
toolBlocks.set(idx, { id: block.id, name: block.name, argsJson: "" });
|
|
3055
|
+
}
|
|
3056
|
+
return;
|
|
3057
|
+
}
|
|
3058
|
+
if (type === "content_block_delta") {
|
|
3059
|
+
const p = payload;
|
|
3060
|
+
const delta = p.delta;
|
|
3061
|
+
if (!delta) return;
|
|
3062
|
+
if (delta.type === "text_delta" && typeof delta.text === "string") {
|
|
3063
|
+
text += delta.text;
|
|
3064
|
+
opts.onChunk(delta.text);
|
|
3065
|
+
} else if (delta.type === "input_json_delta" && typeof delta.partial_json === "string") {
|
|
3066
|
+
const idx = p.index ?? 0;
|
|
3067
|
+
const tool = toolBlocks.get(idx);
|
|
3068
|
+
if (tool) tool.argsJson += delta.partial_json;
|
|
3069
|
+
}
|
|
3070
|
+
return;
|
|
3071
|
+
}
|
|
3072
|
+
if (type === "message_delta") {
|
|
3073
|
+
const p = payload;
|
|
3074
|
+
if (p.delta?.stop_reason) stopReason = p.delta.stop_reason;
|
|
3075
|
+
if (typeof p.usage?.output_tokens === "number") outputTokens = p.usage.output_tokens;
|
|
3076
|
+
return;
|
|
3077
|
+
}
|
|
3078
|
+
});
|
|
3079
|
+
} catch (err) {
|
|
3080
|
+
return retryableError(0, "stream_interrupted", String(err), null);
|
|
3081
|
+
}
|
|
3082
|
+
const toolCalls = Array.from(toolBlocks.values()).map((b) => ({
|
|
3083
|
+
id: b.id,
|
|
3084
|
+
name: b.name,
|
|
3085
|
+
args: tryParseJson(b.argsJson) ?? {}
|
|
3086
|
+
}));
|
|
3087
|
+
const tokens = {
|
|
3088
|
+
input: inputTokens,
|
|
3089
|
+
output: outputTokens,
|
|
3090
|
+
total: inputTokens + outputTokens,
|
|
3091
|
+
cached: cacheReadTokens,
|
|
3092
|
+
cacheCreated: cacheCreatedTokens
|
|
3093
|
+
};
|
|
3094
|
+
const response = {
|
|
3095
|
+
text,
|
|
3096
|
+
structuredOutput: null,
|
|
3097
|
+
toolCalls,
|
|
3098
|
+
tokens,
|
|
3099
|
+
finishReason: stopReason,
|
|
3100
|
+
raw: { streamed: true, provider: "anthropic" }
|
|
3101
|
+
};
|
|
3102
|
+
return { ok: true, status: res.status, response };
|
|
3103
|
+
}
|
|
3104
|
+
async function streamOpenAILike(url, request, apiKey, providerLabel, opts) {
|
|
3105
|
+
const { provider: _provider, ...body } = request;
|
|
3106
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
3107
|
+
const reqBody = {
|
|
3108
|
+
...body,
|
|
3109
|
+
stream: true,
|
|
3110
|
+
stream_options: {
|
|
3111
|
+
...body.stream_options ?? {},
|
|
3112
|
+
include_usage: true
|
|
3113
|
+
}
|
|
3114
|
+
};
|
|
3115
|
+
let res;
|
|
3116
|
+
try {
|
|
3117
|
+
res = await fetchFn(url, {
|
|
3118
|
+
method: "POST",
|
|
3119
|
+
headers: {
|
|
3120
|
+
authorization: `Bearer ${apiKey}`,
|
|
3121
|
+
"content-type": "application/json"
|
|
3122
|
+
},
|
|
3123
|
+
body: JSON.stringify(reqBody)
|
|
3124
|
+
});
|
|
3125
|
+
} catch (err) {
|
|
3126
|
+
return retryableError(0, "network_error", String(err), null);
|
|
3127
|
+
}
|
|
3128
|
+
if (!res.ok) {
|
|
3129
|
+
const errBody = await res.json().catch(() => ({}));
|
|
3130
|
+
return classifyHttpError(res.status, errBody);
|
|
3131
|
+
}
|
|
3132
|
+
let text = "";
|
|
3133
|
+
let finishReason;
|
|
3134
|
+
let inputTokens = 0;
|
|
3135
|
+
let outputTokens = 0;
|
|
3136
|
+
let totalTokens;
|
|
3137
|
+
let cachedTokens;
|
|
3138
|
+
const toolBuffers = /* @__PURE__ */ new Map();
|
|
3139
|
+
try {
|
|
3140
|
+
await parseSSEStream(res, (event) => {
|
|
3141
|
+
if (!event.data) return;
|
|
3142
|
+
if (event.data === "[DONE]") return;
|
|
3143
|
+
let payload;
|
|
3144
|
+
try {
|
|
3145
|
+
payload = JSON.parse(event.data);
|
|
3146
|
+
} catch {
|
|
3147
|
+
return;
|
|
3148
|
+
}
|
|
3149
|
+
const choices = payload.choices;
|
|
3150
|
+
if (choices && choices.length > 0) {
|
|
3151
|
+
const choice = choices[0];
|
|
3152
|
+
const deltaContent = choice.delta?.content;
|
|
3153
|
+
if (typeof deltaContent === "string" && deltaContent.length > 0) {
|
|
3154
|
+
text += deltaContent;
|
|
3155
|
+
opts.onChunk(deltaContent);
|
|
3156
|
+
}
|
|
3157
|
+
const toolDeltas = choice.delta?.tool_calls;
|
|
3158
|
+
if (toolDeltas) {
|
|
3159
|
+
for (const tcDelta of toolDeltas) {
|
|
3160
|
+
const idx = tcDelta.index ?? 0;
|
|
3161
|
+
let buf = toolBuffers.get(idx);
|
|
3162
|
+
if (!buf) {
|
|
3163
|
+
buf = { id: tcDelta.id ?? `tc-${idx}`, name: "", argsJson: "" };
|
|
3164
|
+
toolBuffers.set(idx, buf);
|
|
3165
|
+
}
|
|
3166
|
+
if (tcDelta.id) buf.id = tcDelta.id;
|
|
3167
|
+
if (tcDelta.function?.name) buf.name += tcDelta.function.name;
|
|
3168
|
+
if (tcDelta.function?.arguments) buf.argsJson += tcDelta.function.arguments;
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
if (choice.finish_reason) finishReason = choice.finish_reason;
|
|
3172
|
+
}
|
|
3173
|
+
const usage = payload.usage;
|
|
3174
|
+
if (usage) {
|
|
3175
|
+
if (typeof usage.prompt_tokens === "number") inputTokens = usage.prompt_tokens;
|
|
3176
|
+
if (typeof usage.completion_tokens === "number") outputTokens = usage.completion_tokens;
|
|
3177
|
+
if (typeof usage.total_tokens === "number") totalTokens = usage.total_tokens;
|
|
3178
|
+
const details = usage.prompt_tokens_details;
|
|
3179
|
+
if (typeof details?.cached_tokens === "number") cachedTokens = details.cached_tokens;
|
|
3180
|
+
}
|
|
3181
|
+
});
|
|
3182
|
+
} catch (err) {
|
|
3183
|
+
return retryableError(0, "stream_interrupted", String(err), null);
|
|
3184
|
+
}
|
|
3185
|
+
const toolCalls = Array.from(toolBuffers.values()).filter((b) => b.name.length > 0).map((b) => ({
|
|
3186
|
+
id: b.id,
|
|
3187
|
+
name: b.name,
|
|
3188
|
+
args: tryParseJson(b.argsJson) ?? {}
|
|
3189
|
+
}));
|
|
3190
|
+
const tokens = {
|
|
3191
|
+
input: inputTokens,
|
|
3192
|
+
output: outputTokens,
|
|
3193
|
+
total: totalTokens ?? inputTokens + outputTokens,
|
|
3194
|
+
cached: cachedTokens
|
|
3195
|
+
};
|
|
3196
|
+
const response = {
|
|
3197
|
+
text,
|
|
3198
|
+
structuredOutput: null,
|
|
3199
|
+
toolCalls,
|
|
3200
|
+
tokens,
|
|
3201
|
+
finishReason,
|
|
3202
|
+
raw: { streamed: true, provider: providerLabel }
|
|
3203
|
+
};
|
|
3204
|
+
return { ok: true, status: res.status, response };
|
|
3205
|
+
}
|
|
3206
|
+
async function parseSSEStream(response, handler) {
|
|
3207
|
+
const body = response.body;
|
|
3208
|
+
if (!body) throw new Error("Response has no body for SSE parse");
|
|
3209
|
+
const reader = body.getReader();
|
|
3210
|
+
const decoder = new TextDecoder("utf-8");
|
|
3211
|
+
let buffer = "";
|
|
3212
|
+
for (; ; ) {
|
|
3213
|
+
const { value, done } = await reader.read();
|
|
3214
|
+
if (done) break;
|
|
3215
|
+
buffer += decoder.decode(value, { stream: true });
|
|
3216
|
+
let sep;
|
|
3217
|
+
while (sep = buffer.indexOf("\n\n"), sep !== -1) {
|
|
3218
|
+
const block = buffer.slice(0, sep);
|
|
3219
|
+
buffer = buffer.slice(sep + 2);
|
|
3220
|
+
const event = parseSSEBlock(block);
|
|
3221
|
+
if (event) handler(event);
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
if (buffer.length > 0) {
|
|
3225
|
+
const event = parseSSEBlock(buffer);
|
|
3226
|
+
if (event) handler(event);
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
function parseSSEBlock(block) {
|
|
3230
|
+
const lines = block.split(/\r?\n/);
|
|
3231
|
+
let eventName;
|
|
3232
|
+
const dataLines = [];
|
|
3233
|
+
for (const line of lines) {
|
|
3234
|
+
if (line.startsWith(":")) continue;
|
|
3235
|
+
if (line.startsWith("event:")) {
|
|
3236
|
+
eventName = line.slice(6).trim();
|
|
3237
|
+
} else if (line.startsWith("data:")) {
|
|
3238
|
+
dataLines.push(line.slice(5).trim());
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
if (dataLines.length === 0) return void 0;
|
|
3242
|
+
return { event: eventName, data: dataLines.join("\n") };
|
|
3243
|
+
}
|
|
3244
|
+
function tryParseJson(s) {
|
|
3245
|
+
if (typeof s !== "string" || s.length === 0) return void 0;
|
|
3246
|
+
try {
|
|
3247
|
+
const parsed = JSON.parse(s);
|
|
3248
|
+
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
3249
|
+
} catch {
|
|
3250
|
+
return void 0;
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
function classifyHttpError(status, body) {
|
|
3254
|
+
const message = extractErrorMessage(body) ?? `HTTP ${status}`;
|
|
3255
|
+
if (status === 429)
|
|
3256
|
+
return { ok: false, status, errorType: "retryable", errorCode: "rate_limit", message, raw: body };
|
|
3257
|
+
if (status === 408)
|
|
3258
|
+
return { ok: false, status, errorType: "retryable", errorCode: "timeout", message, raw: body };
|
|
3259
|
+
if (status >= 500)
|
|
3260
|
+
return { ok: false, status, errorType: "retryable", errorCode: "server_error", message, raw: body };
|
|
3261
|
+
if (status === 404)
|
|
3262
|
+
return { ok: false, status, errorType: "retryable", errorCode: "model_not_found", message, raw: body };
|
|
3263
|
+
if (status === 401 || status === 403)
|
|
3264
|
+
return { ok: false, status, errorType: "terminal", errorCode: "auth", message, raw: body };
|
|
3265
|
+
if (status === 400)
|
|
3266
|
+
return { ok: false, status, errorType: "terminal", errorCode: "invalid_request", message, raw: body };
|
|
3267
|
+
return { ok: false, status, errorType: "terminal", errorCode: "unknown", message, raw: body };
|
|
3268
|
+
}
|
|
3269
|
+
function extractErrorMessage(body) {
|
|
3270
|
+
if (!body || typeof body !== "object") return void 0;
|
|
3271
|
+
const b = body;
|
|
3272
|
+
if (b.error && typeof b.error === "object") {
|
|
3273
|
+
const e = b.error;
|
|
3274
|
+
if (typeof e.message === "string") return e.message;
|
|
3275
|
+
}
|
|
3276
|
+
if (typeof b.message === "string") return b.message;
|
|
3277
|
+
return void 0;
|
|
3278
|
+
}
|
|
3279
|
+
function retryableError(status, code, message, raw) {
|
|
3280
|
+
return { ok: false, status, errorType: "retryable", errorCode: code, message, raw };
|
|
3281
|
+
}
|
|
924
3282
|
|
|
925
3283
|
// src/execute.ts
|
|
926
|
-
var
|
|
3284
|
+
var ANTHROPIC_URL2 = "https://api.anthropic.com/v1/messages";
|
|
927
3285
|
var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
|
|
928
3286
|
var DEEPSEEK_URL = "https://api.deepseek.com/chat/completions";
|
|
929
3287
|
async function execute(request, opts = {}) {
|
|
@@ -944,16 +3302,22 @@ async function execute(request, opts = {}) {
|
|
|
944
3302
|
}
|
|
945
3303
|
}
|
|
946
3304
|
async function executeAnthropic(request, opts) {
|
|
947
|
-
const apiKey = opts.apiKeys
|
|
3305
|
+
const apiKey = resolveProviderKey("anthropic", { apiKeys: opts.apiKeys });
|
|
948
3306
|
if (!apiKey) {
|
|
949
3307
|
return terminalError(401, "auth", "ANTHROPIC_API_KEY missing");
|
|
950
3308
|
}
|
|
3309
|
+
if (opts.onChunk) {
|
|
3310
|
+
return streamAnthropic(request, apiKey, {
|
|
3311
|
+
onChunk: opts.onChunk,
|
|
3312
|
+
fetchImpl: opts.fetchImpl
|
|
3313
|
+
});
|
|
3314
|
+
}
|
|
951
3315
|
const { provider: _provider, ...body } = request;
|
|
952
3316
|
const fetchFn = opts.fetchImpl ?? fetch;
|
|
953
3317
|
let res;
|
|
954
3318
|
let json;
|
|
955
3319
|
try {
|
|
956
|
-
res = await fetchFn(
|
|
3320
|
+
res = await fetchFn(ANTHROPIC_URL2, {
|
|
957
3321
|
method: "POST",
|
|
958
3322
|
headers: {
|
|
959
3323
|
"x-api-key": apiKey,
|
|
@@ -964,9 +3328,9 @@ async function executeAnthropic(request, opts) {
|
|
|
964
3328
|
});
|
|
965
3329
|
json = await res.json().catch(() => ({}));
|
|
966
3330
|
} catch (err) {
|
|
967
|
-
return
|
|
3331
|
+
return retryableError2(0, "network_error", String(err), null);
|
|
968
3332
|
}
|
|
969
|
-
if (!res.ok) return
|
|
3333
|
+
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
970
3334
|
return { ok: true, status: res.status, response: normalizeAnthropic(json) };
|
|
971
3335
|
}
|
|
972
3336
|
function normalizeAnthropic(raw) {
|
|
@@ -983,7 +3347,7 @@ function normalizeAnthropic(raw) {
|
|
|
983
3347
|
return { text, structuredOutput: null, toolCalls, tokens, finishReason: r.stop_reason, raw };
|
|
984
3348
|
}
|
|
985
3349
|
async function executeGoogle(request, opts) {
|
|
986
|
-
const apiKey =
|
|
3350
|
+
const apiKey = resolveProviderKey("google", { apiKeys: opts.apiKeys });
|
|
987
3351
|
if (!apiKey) {
|
|
988
3352
|
return terminalError(401, "auth", "GOOGLE_API_KEY/GEMINI_API_KEY missing");
|
|
989
3353
|
}
|
|
@@ -1000,9 +3364,9 @@ async function executeGoogle(request, opts) {
|
|
|
1000
3364
|
});
|
|
1001
3365
|
json = await res.json().catch(() => ({}));
|
|
1002
3366
|
} catch (err) {
|
|
1003
|
-
return
|
|
3367
|
+
return retryableError2(0, "network_error", String(err), null);
|
|
1004
3368
|
}
|
|
1005
|
-
if (!res.ok) return
|
|
3369
|
+
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
1006
3370
|
return { ok: true, status: res.status, response: normalizeGoogle(json) };
|
|
1007
3371
|
}
|
|
1008
3372
|
function normalizeGoogle(raw) {
|
|
@@ -1025,10 +3389,16 @@ function normalizeGoogle(raw) {
|
|
|
1025
3389
|
return { text, structuredOutput: null, toolCalls, tokens, finishReason: candidate?.finishReason, raw };
|
|
1026
3390
|
}
|
|
1027
3391
|
async function executeOpenAI(request, opts) {
|
|
1028
|
-
const apiKey = opts.apiKeys
|
|
3392
|
+
const apiKey = resolveProviderKey("openai", { apiKeys: opts.apiKeys });
|
|
1029
3393
|
if (!apiKey) {
|
|
1030
3394
|
return terminalError(401, "auth", "OPENAI_API_KEY missing");
|
|
1031
3395
|
}
|
|
3396
|
+
if (opts.onChunk) {
|
|
3397
|
+
return streamOpenAILike(OPENAI_URL, request, apiKey, "openai", {
|
|
3398
|
+
onChunk: opts.onChunk,
|
|
3399
|
+
fetchImpl: opts.fetchImpl
|
|
3400
|
+
});
|
|
3401
|
+
}
|
|
1032
3402
|
const { provider: _provider, ...body } = request;
|
|
1033
3403
|
const fetchFn = opts.fetchImpl ?? fetch;
|
|
1034
3404
|
let res;
|
|
@@ -1041,16 +3411,22 @@ async function executeOpenAI(request, opts) {
|
|
|
1041
3411
|
});
|
|
1042
3412
|
json = await res.json().catch(() => ({}));
|
|
1043
3413
|
} catch (err) {
|
|
1044
|
-
return
|
|
3414
|
+
return retryableError2(0, "network_error", String(err), null);
|
|
1045
3415
|
}
|
|
1046
|
-
if (!res.ok) return
|
|
3416
|
+
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
1047
3417
|
return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
|
|
1048
3418
|
}
|
|
1049
3419
|
async function executeDeepSeek(request, opts) {
|
|
1050
|
-
const apiKey = opts.apiKeys
|
|
3420
|
+
const apiKey = resolveProviderKey("deepseek", { apiKeys: opts.apiKeys });
|
|
1051
3421
|
if (!apiKey) {
|
|
1052
3422
|
return terminalError(401, "auth", "DEEPSEEK_API_KEY missing");
|
|
1053
3423
|
}
|
|
3424
|
+
if (opts.onChunk) {
|
|
3425
|
+
return streamOpenAILike(DEEPSEEK_URL, request, apiKey, "deepseek", {
|
|
3426
|
+
onChunk: opts.onChunk,
|
|
3427
|
+
fetchImpl: opts.fetchImpl
|
|
3428
|
+
});
|
|
3429
|
+
}
|
|
1054
3430
|
const { provider: _provider, ...body } = request;
|
|
1055
3431
|
const fetchFn = opts.fetchImpl ?? fetch;
|
|
1056
3432
|
let res;
|
|
@@ -1063,9 +3439,9 @@ async function executeDeepSeek(request, opts) {
|
|
|
1063
3439
|
});
|
|
1064
3440
|
json = await res.json().catch(() => ({}));
|
|
1065
3441
|
} catch (err) {
|
|
1066
|
-
return
|
|
3442
|
+
return retryableError2(0, "network_error", String(err), null);
|
|
1067
3443
|
}
|
|
1068
|
-
if (!res.ok) return
|
|
3444
|
+
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
1069
3445
|
return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
|
|
1070
3446
|
}
|
|
1071
3447
|
function normalizeOpenAILike(raw) {
|
|
@@ -1075,7 +3451,7 @@ function normalizeOpenAILike(raw) {
|
|
|
1075
3451
|
const toolCalls = (choice?.message?.tool_calls ?? []).filter((tc) => tc.function?.name).map((tc, i) => ({
|
|
1076
3452
|
id: tc.id ?? `tc-${i}`,
|
|
1077
3453
|
name: tc.function.name,
|
|
1078
|
-
args:
|
|
3454
|
+
args: tryParseJson2(tc.function?.arguments) ?? {}
|
|
1079
3455
|
}));
|
|
1080
3456
|
const u = r.usage ?? {};
|
|
1081
3457
|
const tokens = {
|
|
@@ -1092,8 +3468,8 @@ function applyOverrides(request, overrides) {
|
|
|
1092
3468
|
if (!layer) return request;
|
|
1093
3469
|
return { ...request, ...layer };
|
|
1094
3470
|
}
|
|
1095
|
-
function
|
|
1096
|
-
const message =
|
|
3471
|
+
function classifyHttpError2(status, body) {
|
|
3472
|
+
const message = extractErrorMessage2(body) ?? `HTTP ${status}`;
|
|
1097
3473
|
if (status === 429) {
|
|
1098
3474
|
return { ok: false, status, errorType: "retryable", errorCode: "rate_limit", message, raw: body };
|
|
1099
3475
|
}
|
|
@@ -1114,7 +3490,7 @@ function classifyHttpError(status, body) {
|
|
|
1114
3490
|
}
|
|
1115
3491
|
return { ok: false, status, errorType: "terminal", errorCode: "unknown", message, raw: body };
|
|
1116
3492
|
}
|
|
1117
|
-
function
|
|
3493
|
+
function extractErrorMessage2(body) {
|
|
1118
3494
|
if (!body || typeof body !== "object") return void 0;
|
|
1119
3495
|
const b = body;
|
|
1120
3496
|
if (b.error && typeof b.error === "object") {
|
|
@@ -1127,10 +3503,10 @@ function extractErrorMessage(body) {
|
|
|
1127
3503
|
function terminalError(status, code, message) {
|
|
1128
3504
|
return { ok: false, status, errorType: "terminal", errorCode: code, message, raw: null };
|
|
1129
3505
|
}
|
|
1130
|
-
function
|
|
3506
|
+
function retryableError2(status, code, message, raw) {
|
|
1131
3507
|
return { ok: false, status, errorType: "retryable", errorCode: code, message, raw };
|
|
1132
3508
|
}
|
|
1133
|
-
function
|
|
3509
|
+
function tryParseJson2(s) {
|
|
1134
3510
|
if (typeof s !== "string" || s.length === 0) return void 0;
|
|
1135
3511
|
try {
|
|
1136
3512
|
const parsed = JSON.parse(s);
|
|
@@ -1142,15 +3518,148 @@ function tryParseJson(s) {
|
|
|
1142
3518
|
|
|
1143
3519
|
// src/call.ts
|
|
1144
3520
|
async function call(ir, opts = {}) {
|
|
3521
|
+
const traceId = generateTraceId();
|
|
3522
|
+
safeEmit(
|
|
3523
|
+
() => emitCompileStart(traceId, ir.appId, {
|
|
3524
|
+
appId: ir.appId,
|
|
3525
|
+
archetype: ir.intent.archetype,
|
|
3526
|
+
// alpha.41: ir.models is ChainModelEntry[] (string | { family }).
|
|
3527
|
+
// Glass-Box renderer carries string ids only; surface family entries
|
|
3528
|
+
// as their family tag prefixed so the panel still shows them in the
|
|
3529
|
+
// pre-resolution log.
|
|
3530
|
+
models: ir.models.map(
|
|
3531
|
+
(m) => typeof m === "string" ? m : `family:${m.family}`
|
|
3532
|
+
)
|
|
3533
|
+
})
|
|
3534
|
+
);
|
|
1145
3535
|
const initial = compileAndRegister(ir, opts);
|
|
3536
|
+
safeEmit(
|
|
3537
|
+
() => emitCompileDone(traceId, ir.appId, {
|
|
3538
|
+
target: initial.target,
|
|
3539
|
+
provider: initial.provider,
|
|
3540
|
+
fallbackChain: initial.fallbackChain,
|
|
3541
|
+
tokensIn: initial.tokensIn,
|
|
3542
|
+
estimatedCostUsd: initial.estimatedCostUsd,
|
|
3543
|
+
mutationsApplied: initial.mutationsApplied,
|
|
3544
|
+
advisories: initial.advisories
|
|
3545
|
+
})
|
|
3546
|
+
);
|
|
3547
|
+
for (const adv of initial.advisories) {
|
|
3548
|
+
safeEmit(
|
|
3549
|
+
() => emitAdvisoryFired(traceId, ir.appId, { code: adv.code, message: adv.message })
|
|
3550
|
+
);
|
|
3551
|
+
}
|
|
1146
3552
|
const start = Date.now();
|
|
1147
3553
|
const attempts = [];
|
|
1148
|
-
const
|
|
3554
|
+
const rawTargets = [initial.target, ...initial.fallbackChain];
|
|
3555
|
+
let unreachableFiltered;
|
|
3556
|
+
let targetsToTry;
|
|
3557
|
+
if (opts.noAutoFilter) {
|
|
3558
|
+
targetsToTry = rawTargets;
|
|
3559
|
+
} else {
|
|
3560
|
+
const dropped = [];
|
|
3561
|
+
targetsToTry = [];
|
|
3562
|
+
for (const t of rawTargets) {
|
|
3563
|
+
if (isModelReachable(t, { apiKeys: opts.apiKeys })) {
|
|
3564
|
+
targetsToTry.push(t);
|
|
3565
|
+
} else {
|
|
3566
|
+
dropped.push(t);
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
unreachableFiltered = dropped;
|
|
3570
|
+
if (targetsToTry.length === 0) {
|
|
3571
|
+
const latencyMs2 = Date.now() - start;
|
|
3572
|
+
await record({
|
|
3573
|
+
handle: initial.handle,
|
|
3574
|
+
tokensIn: 0,
|
|
3575
|
+
tokensOut: 0,
|
|
3576
|
+
latencyMs: latencyMs2,
|
|
3577
|
+
success: false,
|
|
3578
|
+
errorType: "no_reachable_models",
|
|
3579
|
+
promptPreview: extractPromptPreview(ir)
|
|
3580
|
+
});
|
|
3581
|
+
const noReachableAttempts = dropped.map((m) => ({
|
|
3582
|
+
model: m,
|
|
3583
|
+
status: "terminal",
|
|
3584
|
+
errorCode: "unreachable_provider",
|
|
3585
|
+
message: `No API key for ${m}'s provider \u2014 set one of PROVIDER_ENV_KEYS or pass apiKeys`
|
|
3586
|
+
}));
|
|
3587
|
+
throw new CallError(
|
|
3588
|
+
`call(): no reachable models in chain. Filtered: [${dropped.join(", ")}]. Add a key for one provider, or pass apiKeys.`,
|
|
3589
|
+
noReachableAttempts,
|
|
3590
|
+
void 0,
|
|
3591
|
+
"no_reachable_models"
|
|
3592
|
+
);
|
|
3593
|
+
}
|
|
3594
|
+
const archetypeName = ir.intent?.archetype;
|
|
3595
|
+
if (archetypeName) {
|
|
3596
|
+
const ensured = ensureCrossProviderTail({
|
|
3597
|
+
chain: targetsToTry,
|
|
3598
|
+
archetype: archetypeName,
|
|
3599
|
+
apiKeys: opts.apiKeys
|
|
3600
|
+
});
|
|
3601
|
+
if (ensured.appended) {
|
|
3602
|
+
targetsToTry = ensured.chain;
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
let policyBlockedFiltered;
|
|
3607
|
+
if (opts.policy?.blockedModels && opts.policy.blockedModels.length > 0) {
|
|
3608
|
+
const blocked = new Set(opts.policy.blockedModels);
|
|
3609
|
+
const filtered = [];
|
|
3610
|
+
const dropped = [];
|
|
3611
|
+
for (const t of targetsToTry) {
|
|
3612
|
+
if (blocked.has(t)) {
|
|
3613
|
+
dropped.push(t);
|
|
3614
|
+
} else {
|
|
3615
|
+
filtered.push(t);
|
|
3616
|
+
}
|
|
3617
|
+
}
|
|
3618
|
+
if (dropped.length > 0) {
|
|
3619
|
+
policyBlockedFiltered = dropped;
|
|
3620
|
+
targetsToTry = filtered;
|
|
3621
|
+
}
|
|
3622
|
+
if (targetsToTry.length === 0) {
|
|
3623
|
+
const latencyMs2 = Date.now() - start;
|
|
3624
|
+
await record({
|
|
3625
|
+
handle: initial.handle,
|
|
3626
|
+
tokensIn: 0,
|
|
3627
|
+
tokensOut: 0,
|
|
3628
|
+
latencyMs: latencyMs2,
|
|
3629
|
+
success: false,
|
|
3630
|
+
errorType: "all_blocked_by_policy",
|
|
3631
|
+
promptPreview: extractPromptPreview(ir)
|
|
3632
|
+
});
|
|
3633
|
+
const blockedAttempts = dropped.map((m) => ({
|
|
3634
|
+
model: m,
|
|
3635
|
+
status: "terminal",
|
|
3636
|
+
errorCode: "blocked_by_policy",
|
|
3637
|
+
message: `Skipped \u2014 model ${m} is in CompilePolicy.blockedModels`
|
|
3638
|
+
}));
|
|
3639
|
+
throw new CallError(
|
|
3640
|
+
`call(): all chain targets blocked by CompilePolicy.blockedModels: [${dropped.join(", ")}]`,
|
|
3641
|
+
blockedAttempts,
|
|
3642
|
+
void 0,
|
|
3643
|
+
"all_blocked_by_policy"
|
|
3644
|
+
);
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
1149
3647
|
let activeCompile = initial;
|
|
1150
3648
|
let lastErr;
|
|
3649
|
+
const failedProviders = /* @__PURE__ */ new Set();
|
|
1151
3650
|
for (let i = 0; i < targetsToTry.length; i++) {
|
|
1152
3651
|
const targetModel = targetsToTry[i];
|
|
1153
|
-
|
|
3652
|
+
const targetProfile = tryGetProfile(targetModel);
|
|
3653
|
+
if (targetProfile && failedProviders.has(targetProfile.provider) && !opts.noFallback) {
|
|
3654
|
+
attempts.push({
|
|
3655
|
+
model: targetModel,
|
|
3656
|
+
status: "terminal",
|
|
3657
|
+
errorCode: "auth_inferred",
|
|
3658
|
+
message: `Skipped \u2014 provider ${targetProfile.provider} returned 401/403 earlier in this call; same key inferred to fail`
|
|
3659
|
+
});
|
|
3660
|
+
continue;
|
|
3661
|
+
}
|
|
3662
|
+
if (targetModel !== initial.target) {
|
|
1154
3663
|
try {
|
|
1155
3664
|
activeCompile = compileAndRegister(
|
|
1156
3665
|
{
|
|
@@ -1170,49 +3679,117 @@ async function call(ir, opts = {}) {
|
|
|
1170
3679
|
continue;
|
|
1171
3680
|
}
|
|
1172
3681
|
}
|
|
3682
|
+
safeEmit(
|
|
3683
|
+
() => emitExecuteAttempt(traceId, ir.appId, { model: targetModel, attemptIndex: i })
|
|
3684
|
+
);
|
|
3685
|
+
const targetSupportsStreaming = targetProfile?.streaming === true;
|
|
3686
|
+
const streamingOnChunk = opts.onChunk && !opts.noStream && targetSupportsStreaming ? opts.onChunk : void 0;
|
|
1173
3687
|
const exec = await execute(activeCompile.request, {
|
|
1174
3688
|
apiKeys: opts.apiKeys,
|
|
1175
3689
|
fetchImpl: opts.fetchImpl,
|
|
1176
|
-
providerOverrides: opts.providerOverrides
|
|
3690
|
+
providerOverrides: opts.providerOverrides,
|
|
3691
|
+
onChunk: streamingOnChunk
|
|
1177
3692
|
});
|
|
1178
|
-
|
|
3693
|
+
const validated = exec.ok ? validateStructuredContract(exec, ir) : exec;
|
|
3694
|
+
if (validated.ok) {
|
|
1179
3695
|
attempts.push({ model: targetModel, status: "success" });
|
|
1180
3696
|
const latencyMs2 = Date.now() - start;
|
|
1181
|
-
|
|
3697
|
+
safeEmit(
|
|
3698
|
+
() => emitExecuteSuccess(traceId, ir.appId, {
|
|
3699
|
+
model: targetModel,
|
|
3700
|
+
tokensIn: validated.response.tokens.input,
|
|
3701
|
+
tokensOut: validated.response.tokens.output,
|
|
3702
|
+
latencyMs: latencyMs2
|
|
3703
|
+
})
|
|
3704
|
+
);
|
|
3705
|
+
const fellOver = targetModel !== initial.target;
|
|
3706
|
+
const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
|
|
1182
3707
|
await record({
|
|
1183
3708
|
handle: initial.handle,
|
|
1184
|
-
tokensIn:
|
|
1185
|
-
tokensOut:
|
|
3709
|
+
tokensIn: validated.response.tokens.input,
|
|
3710
|
+
tokensOut: validated.response.tokens.output,
|
|
1186
3711
|
latencyMs: latencyMs2,
|
|
1187
3712
|
success: true,
|
|
1188
|
-
emptyResponse:
|
|
1189
|
-
toolsCalled:
|
|
3713
|
+
emptyResponse: validated.response.tokens.output === 0,
|
|
3714
|
+
toolsCalled: validated.response.toolCalls.map((tc) => tc.name),
|
|
1190
3715
|
actualModel: targetModel !== initial.target ? targetModel : void 0,
|
|
1191
3716
|
mutationsApplied: targetModel !== initial.target ? activeCompile.mutationsApplied.map((m) => m.id) : void 0,
|
|
1192
3717
|
promptPreview: extractPromptPreview(ir),
|
|
1193
|
-
responsePreview:
|
|
1194
|
-
cacheReadInputTokens:
|
|
1195
|
-
cacheCreationInputTokens:
|
|
3718
|
+
responsePreview: validated.response.text.slice(0, 200),
|
|
3719
|
+
cacheReadInputTokens: validated.response.tokens.cached,
|
|
3720
|
+
cacheCreationInputTokens: validated.response.tokens.cacheCreated,
|
|
3721
|
+
// alpha.28 — Glass-Box renderer substrate (migration 018). call()
|
|
3722
|
+
// owns the lifecycle so it has direct visibility into finishReason
|
|
3723
|
+
// (from the normalized provider response), totalMs (mirrors latencyMs
|
|
3724
|
+
// for non-streaming; future streaming variant may diverge), and the
|
|
3725
|
+
// fell-over-from / fallback-reason pair (already computed above for
|
|
3726
|
+
// the CallResult return shape).
|
|
3727
|
+
finishReason: validated.response.finishReason,
|
|
3728
|
+
totalMs: latencyMs2,
|
|
3729
|
+
fellOverFrom: fellOver ? initial.target : void 0,
|
|
3730
|
+
fallbackReason
|
|
1196
3731
|
});
|
|
3732
|
+
if (fellOver) {
|
|
3733
|
+
const firstFailed = attempts.find((a) => a.status !== "success");
|
|
3734
|
+
if (firstFailed) {
|
|
3735
|
+
safeEmit(
|
|
3736
|
+
() => emitFallbackWalked(traceId, ir.appId, {
|
|
3737
|
+
from: initial.target,
|
|
3738
|
+
to: targetModel,
|
|
3739
|
+
reason: fallbackReason ?? "unknown",
|
|
3740
|
+
attempt: firstFailed
|
|
3741
|
+
})
|
|
3742
|
+
);
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
if (opts.shadowProbe) {
|
|
3746
|
+
const probe = runShadowProbe({
|
|
3747
|
+
ir,
|
|
3748
|
+
opts,
|
|
3749
|
+
servedModel: targetModel,
|
|
3750
|
+
servedResponse: validated.response,
|
|
3751
|
+
servedLatencyMs: latencyMs2
|
|
3752
|
+
});
|
|
3753
|
+
if (isBrainSync()) {
|
|
3754
|
+
await probe;
|
|
3755
|
+
} else {
|
|
3756
|
+
void probe;
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
1197
3759
|
return {
|
|
1198
3760
|
handle: initial.handle,
|
|
1199
3761
|
actualModel: targetModel,
|
|
1200
3762
|
requestedModel: initial.target,
|
|
1201
3763
|
provider: activeCompile.provider,
|
|
1202
|
-
response:
|
|
3764
|
+
response: validated.response,
|
|
1203
3765
|
latencyMs: latencyMs2,
|
|
1204
3766
|
mutationsApplied: activeCompile.mutationsApplied,
|
|
1205
|
-
attempts
|
|
3767
|
+
attempts,
|
|
3768
|
+
servedBy: targetModel,
|
|
3769
|
+
fellOverFrom: fellOver ? initial.target : void 0,
|
|
3770
|
+
fallbackReason,
|
|
3771
|
+
unreachableFiltered,
|
|
3772
|
+
policyBlockedFiltered,
|
|
3773
|
+
traceId,
|
|
3774
|
+
// alpha.44: surface the served compile's advisories so call()
|
|
3775
|
+
// consumers (agent paths) can logAdvisories() like compile()
|
|
3776
|
+
// consumers (chat/intake) do. activeCompile, not initial — parity
|
|
3777
|
+
// with mutationsApplied above on fallback. Closes IC's side-finding.
|
|
3778
|
+
advisories: activeCompile.advisories
|
|
1206
3779
|
};
|
|
1207
3780
|
}
|
|
1208
3781
|
attempts.push({
|
|
1209
3782
|
model: targetModel,
|
|
1210
|
-
status:
|
|
1211
|
-
errorCode:
|
|
1212
|
-
message:
|
|
3783
|
+
status: validated.errorType,
|
|
3784
|
+
errorCode: validated.errorCode,
|
|
3785
|
+
message: validated.message
|
|
1213
3786
|
});
|
|
1214
|
-
lastErr =
|
|
1215
|
-
if (
|
|
3787
|
+
lastErr = validated;
|
|
3788
|
+
if (validated.errorType === "terminal" || opts.noFallback) {
|
|
3789
|
+
if (validated.errorCode === "auth" && !opts.noFallback && activeCompile.provider) {
|
|
3790
|
+
failedProviders.add(activeCompile.provider);
|
|
3791
|
+
continue;
|
|
3792
|
+
}
|
|
1216
3793
|
break;
|
|
1217
3794
|
}
|
|
1218
3795
|
}
|
|
@@ -1226,8 +3803,10 @@ async function call(ir, opts = {}) {
|
|
|
1226
3803
|
errorType: lastErr?.errorCode,
|
|
1227
3804
|
promptPreview: extractPromptPreview(ir)
|
|
1228
3805
|
});
|
|
3806
|
+
const filteredNote = unreachableFiltered && unreachableFiltered.length > 0 ? ` (also auto-filtered: [${unreachableFiltered.join(", ")}] \u2014 no API key)` : "";
|
|
3807
|
+
const blockedNote = policyBlockedFiltered && policyBlockedFiltered.length > 0 ? ` (also policy-blocked: [${policyBlockedFiltered.join(", ")}])` : "";
|
|
1229
3808
|
throw new CallError(
|
|
1230
|
-
`call(): all attempts failed${lastErr ? ` \u2014 ${lastErr.errorCode}: ${lastErr.message}` : ""}`,
|
|
3809
|
+
`call(): all attempts failed${lastErr ? ` \u2014 ${lastErr.errorCode}: ${lastErr.message}` : ""}${filteredNote}${blockedNote}`,
|
|
1231
3810
|
attempts,
|
|
1232
3811
|
lastErr?.status,
|
|
1233
3812
|
lastErr?.errorCode
|
|
@@ -1249,20 +3828,346 @@ function extractPromptPreview(ir) {
|
|
|
1249
3828
|
if (lastHist) return lastHist.slice(0, 200);
|
|
1250
3829
|
return void 0;
|
|
1251
3830
|
}
|
|
1252
|
-
function
|
|
1253
|
-
if (!
|
|
1254
|
-
if (
|
|
3831
|
+
function shouldSampleProbe(sampleRate, rng = Math.random) {
|
|
3832
|
+
if (!(sampleRate > 0)) return false;
|
|
3833
|
+
if (sampleRate >= 1) return true;
|
|
3834
|
+
return rng() < sampleRate;
|
|
3835
|
+
}
|
|
3836
|
+
function normalizeProbeCandidates(candidates) {
|
|
3837
|
+
const arr = Array.isArray(candidates) ? candidates : [candidates];
|
|
3838
|
+
return [...new Set(arr.filter((c) => typeof c === "string" && c.length > 0))];
|
|
3839
|
+
}
|
|
3840
|
+
function hashForProbe(s) {
|
|
3841
|
+
let h = 0;
|
|
3842
|
+
for (let i = 0; i < s.length; i++) h = (h << 5) - h + s.charCodeAt(i) | 0;
|
|
3843
|
+
return `h${(h >>> 0).toString(16)}`;
|
|
3844
|
+
}
|
|
3845
|
+
var DEFAULT_PROBE_MAX_LATENCY_MS = 15e3;
|
|
3846
|
+
function isSlowTierCandidate(candidate) {
|
|
3847
|
+
const profile = tryGetProfile(candidate);
|
|
3848
|
+
if (!profile) return false;
|
|
3849
|
+
return latencyTierOf(profile) === "slow";
|
|
3850
|
+
}
|
|
3851
|
+
async function runProbeCandidates(args) {
|
|
3852
|
+
try {
|
|
3853
|
+
if (!shouldSampleProbe(args.cfg.sampleRate ?? 0.05)) return;
|
|
3854
|
+
const candidates = normalizeProbeCandidates(args.cfg.candidates);
|
|
3855
|
+
const promptHash = hashForProbe(args.ir.currentTurn?.content ?? "");
|
|
3856
|
+
const budgetMs = args.cfg.maxLatencyMs ?? DEFAULT_PROBE_MAX_LATENCY_MS;
|
|
3857
|
+
const deadline = args.sync ? Date.now() + budgetMs : Number.POSITIVE_INFINITY;
|
|
3858
|
+
const skipSlow = args.sync && (args.cfg.skipSlowTierInSync ?? true);
|
|
3859
|
+
const recordDiagnostic = async (candidate, outcome) => {
|
|
3860
|
+
await recordShadowProbe({
|
|
3861
|
+
appId: args.ir.appId,
|
|
3862
|
+
archetype: args.ir.intent.archetype,
|
|
3863
|
+
family: deriveFamilyFromModelId(candidate) ?? "unknown",
|
|
3864
|
+
candidateModel: candidate,
|
|
3865
|
+
currentModel: args.servedModel,
|
|
3866
|
+
promptHash,
|
|
3867
|
+
// Served leg only — the candidate never produced a comparable response.
|
|
3868
|
+
currentResponsePreview: args.servedResponse.text.slice(0, 2e3),
|
|
3869
|
+
tokensCurrentIn: args.servedResponse.tokens.input,
|
|
3870
|
+
tokensCurrentOut: args.servedResponse.tokens.output,
|
|
3871
|
+
latencyCurrentMs: args.servedLatencyMs,
|
|
3872
|
+
outcome
|
|
3873
|
+
});
|
|
3874
|
+
};
|
|
3875
|
+
for (const candidate of candidates) {
|
|
3876
|
+
if (candidate === args.servedModel) continue;
|
|
3877
|
+
if (deriveFamilyFromModelId(candidate) === "claude-opus") continue;
|
|
3878
|
+
if (!isModelReachable(candidate, { apiKeys: args.exec.apiKeys })) continue;
|
|
3879
|
+
if (skipSlow && isSlowTierCandidate(candidate)) {
|
|
3880
|
+
try {
|
|
3881
|
+
await recordDiagnostic(candidate, "skipped_slow_tier_sync");
|
|
3882
|
+
} catch {
|
|
3883
|
+
}
|
|
3884
|
+
continue;
|
|
3885
|
+
}
|
|
3886
|
+
if (args.sync && Date.now() >= deadline) {
|
|
3887
|
+
try {
|
|
3888
|
+
await recordDiagnostic(candidate, "aborted_latency_budget");
|
|
3889
|
+
} catch {
|
|
3890
|
+
}
|
|
3891
|
+
break;
|
|
3892
|
+
}
|
|
3893
|
+
try {
|
|
3894
|
+
const candCompile = compileAndRegister(
|
|
3895
|
+
{
|
|
3896
|
+
...args.ir,
|
|
3897
|
+
models: args.ir.models.includes(candidate) ? args.ir.models : [candidate, ...args.ir.models],
|
|
3898
|
+
constraints: { ...args.ir.constraints ?? {}, forceModel: candidate }
|
|
3899
|
+
},
|
|
3900
|
+
args.exec
|
|
3901
|
+
);
|
|
3902
|
+
const candStart = Date.now();
|
|
3903
|
+
let timer;
|
|
3904
|
+
const execPromise = execute(candCompile.request, {
|
|
3905
|
+
apiKeys: args.exec.apiKeys,
|
|
3906
|
+
fetchImpl: args.exec.fetchImpl,
|
|
3907
|
+
providerOverrides: args.exec.providerOverrides
|
|
3908
|
+
}).then((exec2) => ({ kind: "exec", exec: exec2 })).catch(() => ({ kind: "failed" }));
|
|
3909
|
+
let raced;
|
|
3910
|
+
if (args.sync) {
|
|
3911
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
3912
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
3913
|
+
timer = setTimeout(() => resolve({ kind: "timeout" }), remaining);
|
|
3914
|
+
});
|
|
3915
|
+
raced = await Promise.race([execPromise, timeoutPromise]);
|
|
3916
|
+
if (timer) clearTimeout(timer);
|
|
3917
|
+
} else {
|
|
3918
|
+
raced = await execPromise;
|
|
3919
|
+
}
|
|
3920
|
+
if (raced.kind === "timeout") {
|
|
3921
|
+
try {
|
|
3922
|
+
await recordDiagnostic(candidate, "aborted_latency_budget");
|
|
3923
|
+
} catch {
|
|
3924
|
+
}
|
|
3925
|
+
break;
|
|
3926
|
+
}
|
|
3927
|
+
if (raced.kind === "failed") continue;
|
|
3928
|
+
const exec = raced.exec;
|
|
3929
|
+
const candidateLatencyMs = Date.now() - candStart;
|
|
3930
|
+
if (!exec.ok) continue;
|
|
3931
|
+
await recordShadowProbe({
|
|
3932
|
+
appId: args.ir.appId,
|
|
3933
|
+
archetype: args.ir.intent.archetype,
|
|
3934
|
+
family: deriveFamilyFromModelId(candidate) ?? candCompile.provider,
|
|
3935
|
+
candidateModel: candidate,
|
|
3936
|
+
currentModel: args.servedModel,
|
|
3937
|
+
promptHash,
|
|
3938
|
+
currentResponsePreview: args.servedResponse.text.slice(0, 2e3),
|
|
3939
|
+
candidateResponsePreview: exec.response.text.slice(0, 2e3),
|
|
3940
|
+
tokensCurrentIn: args.servedResponse.tokens.input,
|
|
3941
|
+
tokensCurrentOut: args.servedResponse.tokens.output,
|
|
3942
|
+
tokensCandidateIn: exec.response.tokens.input,
|
|
3943
|
+
tokensCandidateOut: exec.response.tokens.output,
|
|
3944
|
+
// alpha.46 — speed is the third swap-decision axis. Served latency
|
|
3945
|
+
// mirrors the user's actual wait; candidate latency is measured only
|
|
3946
|
+
// here and stored nowhere else (irrecoverable if not captured now).
|
|
3947
|
+
latencyCurrentMs: args.servedLatencyMs,
|
|
3948
|
+
latencyCandidateMs: candidateLatencyMs,
|
|
3949
|
+
outcome: "completed"
|
|
3950
|
+
});
|
|
3951
|
+
} catch {
|
|
3952
|
+
}
|
|
3953
|
+
}
|
|
3954
|
+
} catch {
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
async function runShadowProbe(args) {
|
|
3958
|
+
const cfg = args.opts.shadowProbe;
|
|
3959
|
+
if (!cfg) return;
|
|
3960
|
+
await runProbeCandidates({
|
|
3961
|
+
ir: args.ir,
|
|
3962
|
+
cfg,
|
|
3963
|
+
servedModel: args.servedModel,
|
|
3964
|
+
servedResponse: args.servedResponse,
|
|
3965
|
+
servedLatencyMs: args.servedLatencyMs,
|
|
3966
|
+
// CallOptions is a structural superset of ProbeExecOpts.
|
|
3967
|
+
exec: args.opts,
|
|
3968
|
+
// alpha — the call()-inline path is on the user's critical path exactly when
|
|
3969
|
+
// BrainConfig.sync is set (call() awaits the probe before returning). That's
|
|
3970
|
+
// the only case where the latency budget + slow-tier skip must fire.
|
|
3971
|
+
sync: isBrainSync()
|
|
3972
|
+
});
|
|
3973
|
+
}
|
|
3974
|
+
async function probeShadow(ir, opts) {
|
|
3975
|
+
try {
|
|
3976
|
+
const servedResponse = {
|
|
3977
|
+
text: opts.served.responseText,
|
|
3978
|
+
structuredOutput: null,
|
|
3979
|
+
toolCalls: [],
|
|
3980
|
+
tokens: {
|
|
3981
|
+
input: opts.served.tokensIn,
|
|
3982
|
+
output: opts.served.tokensOut,
|
|
3983
|
+
total: opts.served.tokensIn + opts.served.tokensOut
|
|
3984
|
+
},
|
|
3985
|
+
raw: null
|
|
3986
|
+
};
|
|
3987
|
+
await runProbeCandidates({
|
|
3988
|
+
ir,
|
|
3989
|
+
cfg: {
|
|
3990
|
+
candidates: opts.candidates,
|
|
3991
|
+
sampleRate: opts.sampleRate,
|
|
3992
|
+
judge: opts.judge ?? "off"
|
|
3993
|
+
},
|
|
3994
|
+
servedModel: opts.served.model,
|
|
3995
|
+
servedResponse,
|
|
3996
|
+
servedLatencyMs: opts.served.latencyMs,
|
|
3997
|
+
exec: {
|
|
3998
|
+
policy: opts.policy,
|
|
3999
|
+
toolRelevanceThreshold: opts.toolRelevanceThreshold,
|
|
4000
|
+
compressHistoryAfter: opts.compressHistoryAfter,
|
|
4001
|
+
apiKeys: opts.apiKeys,
|
|
4002
|
+
fetchImpl: opts.fetchImpl,
|
|
4003
|
+
providerOverrides: opts.providerOverrides
|
|
4004
|
+
},
|
|
4005
|
+
// alpha — probeShadow() is ALWAYS off the user-facing critical path: the
|
|
4006
|
+
// consumer fires it from `onFinish` wrapped in `after()`/`waitUntil()`,
|
|
4007
|
+
// after the response is flushed. So the sync-mode latency budget +
|
|
4008
|
+
// slow-tier skip are no-ops here — slow candidates run to completion (this
|
|
4009
|
+
// is in fact the right place to evaluate a slow reasoner). The
|
|
4010
|
+
// maxLatencyMs/skipSlowTierInSync knobs aren't even exposed on
|
|
4011
|
+
// ProbeShadowOptions for that reason.
|
|
4012
|
+
sync: false
|
|
4013
|
+
});
|
|
4014
|
+
} catch {
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
function validateStructuredContract(exec, ir) {
|
|
4018
|
+
if (!ir.constraints?.structuredOutput) {
|
|
4019
|
+
return { ok: true, response: exec.response };
|
|
4020
|
+
}
|
|
4021
|
+
const finish = (exec.response.finishReason ?? "").toLowerCase();
|
|
4022
|
+
if (finish === "max_tokens" || finish === "length") {
|
|
4023
|
+
return {
|
|
4024
|
+
ok: false,
|
|
4025
|
+
status: exec.status,
|
|
4026
|
+
errorType: "retryable",
|
|
4027
|
+
errorCode: "max_tokens_on_structured_output",
|
|
4028
|
+
message: `Provider returned finishReason="${exec.response.finishReason}" on a structured-output call \u2014 output truncated mid-token, JSON cannot be valid`,
|
|
4029
|
+
raw: exec.response.raw
|
|
4030
|
+
};
|
|
4031
|
+
}
|
|
4032
|
+
if (!exec.response.text) {
|
|
4033
|
+
return { ok: true, response: exec.response };
|
|
4034
|
+
}
|
|
1255
4035
|
try {
|
|
1256
|
-
const parsed = JSON.parse(response.text);
|
|
1257
|
-
return { ...response, structuredOutput: parsed };
|
|
4036
|
+
const parsed = JSON.parse(exec.response.text);
|
|
4037
|
+
return { ok: true, response: { ...exec.response, structuredOutput: parsed } };
|
|
1258
4038
|
} catch (err) {
|
|
1259
4039
|
return {
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
4040
|
+
ok: false,
|
|
4041
|
+
status: exec.status,
|
|
4042
|
+
errorType: "retryable",
|
|
4043
|
+
errorCode: "structured_output_parse_failed",
|
|
4044
|
+
message: err instanceof Error ? err.message : String(err),
|
|
4045
|
+
raw: exec.response.raw
|
|
1263
4046
|
};
|
|
1264
4047
|
}
|
|
1265
4048
|
}
|
|
4049
|
+
function normalizeFallbackReason(attempts) {
|
|
4050
|
+
const first = attempts.find((a) => a.status !== "success");
|
|
4051
|
+
if (!first) return void 0;
|
|
4052
|
+
const code = first.errorCode ?? "";
|
|
4053
|
+
if (code === "rate_limit_429" || code === "rate_limit") return "rate_limit";
|
|
4054
|
+
if (code === "max_tokens_on_structured_output" || code === "structured_output_parse_failed") {
|
|
4055
|
+
return "cliff";
|
|
4056
|
+
}
|
|
4057
|
+
if (code === "cost_cap_exceeded") return "cost_cap";
|
|
4058
|
+
if (code === "auth" || code === "auth_inferred") return "provider_auth_failed";
|
|
4059
|
+
return "provider_error";
|
|
4060
|
+
}
|
|
4061
|
+
function generateTraceId() {
|
|
4062
|
+
try {
|
|
4063
|
+
const g = globalThis;
|
|
4064
|
+
if (g.crypto && typeof g.crypto.randomUUID === "function") {
|
|
4065
|
+
return g.crypto.randomUUID();
|
|
4066
|
+
}
|
|
4067
|
+
} catch {
|
|
4068
|
+
}
|
|
4069
|
+
const hex = (n) => Math.floor(Math.random() * Math.pow(16, n)).toString(16).padStart(n, "0");
|
|
4070
|
+
return `${hex(8)}-${hex(4)}-${hex(4)}-${hex(4)}-${hex(12)}`;
|
|
4071
|
+
}
|
|
4072
|
+
function safeEmit(fn) {
|
|
4073
|
+
try {
|
|
4074
|
+
fn();
|
|
4075
|
+
} catch {
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
4078
|
+
|
|
4079
|
+
// src/streamtext-helpers.ts
|
|
4080
|
+
function attachCacheControlToStreamTextInput(result, convertedMessages) {
|
|
4081
|
+
const messages = convertedMessages.map((m) => ({ ...m }));
|
|
4082
|
+
const markIdx = result.diagnostics.historyCacheMarkIndex;
|
|
4083
|
+
if (result.provider === "anthropic" && typeof markIdx === "number" && markIdx >= 0 && markIdx < messages.length) {
|
|
4084
|
+
const target = messages[markIdx];
|
|
4085
|
+
if (target) {
|
|
4086
|
+
messages[markIdx] = {
|
|
4087
|
+
role: target.role,
|
|
4088
|
+
content: target.content,
|
|
4089
|
+
providerOptions: {
|
|
4090
|
+
...target.providerOptions ?? {},
|
|
4091
|
+
anthropic: {
|
|
4092
|
+
...target.providerOptions?.anthropic ?? {},
|
|
4093
|
+
cacheControl: { type: "ephemeral" }
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
};
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
const systemMessages = result.systemMessages;
|
|
4100
|
+
const hasStructuredSystemCacheControl = result.provider === "anthropic" && systemMessages.some(
|
|
4101
|
+
(m) => m.providerOptions?.anthropic?.cacheControl !== void 0
|
|
4102
|
+
);
|
|
4103
|
+
const system = hasStructuredSystemCacheControl ? systemMessages : systemMessages.map((m) => m.content).join("\n\n");
|
|
4104
|
+
return { system, messages };
|
|
4105
|
+
}
|
|
4106
|
+
|
|
4107
|
+
// src/compile-aisdk.ts
|
|
4108
|
+
function compileForAISDKv6(ir, opts) {
|
|
4109
|
+
const result = compile(ir, opts);
|
|
4110
|
+
registerCompile(ir.appId, ir.intent.archetype, ir, result);
|
|
4111
|
+
armCompileConsumeTracking(result.handle);
|
|
4112
|
+
const systemMessages = result.systemMessages;
|
|
4113
|
+
const hasStructuredSystemCacheControl = result.provider === "anthropic" && systemMessages.some(
|
|
4114
|
+
(m) => m.providerOptions?.anthropic?.cacheControl !== void 0
|
|
4115
|
+
);
|
|
4116
|
+
const systemValue = hasStructuredSystemCacheControl ? systemMessages : systemMessages.map((m) => m.content).join("\n\n");
|
|
4117
|
+
const keptToolNames = extractKeptToolNames(result);
|
|
4118
|
+
const providerOptions = result.provider === "anthropic" && result.diagnostics.cacheableTokens > 0 ? { anthropic: { cacheControl: { type: "ephemeral" } } } : void 0;
|
|
4119
|
+
const handle = result.handle;
|
|
4120
|
+
const diagnostics = {
|
|
4121
|
+
...result.diagnostics,
|
|
4122
|
+
targetProvider: result.provider,
|
|
4123
|
+
estimatedCostUsd: result.estimatedCostUsd,
|
|
4124
|
+
fallbackChain: result.fallbackChain
|
|
4125
|
+
};
|
|
4126
|
+
return {
|
|
4127
|
+
handle,
|
|
4128
|
+
// Consume-tracking getters: reading any of these flags the compile as
|
|
4129
|
+
// "used", silencing the discard guard at record() time.
|
|
4130
|
+
get model() {
|
|
4131
|
+
markCompileConsumed(handle, "model");
|
|
4132
|
+
return result.target;
|
|
4133
|
+
},
|
|
4134
|
+
get system() {
|
|
4135
|
+
markCompileConsumed(handle, "system");
|
|
4136
|
+
return systemValue;
|
|
4137
|
+
},
|
|
4138
|
+
get raw() {
|
|
4139
|
+
markCompileConsumed(handle, "raw");
|
|
4140
|
+
return result;
|
|
4141
|
+
},
|
|
4142
|
+
keptToolNames,
|
|
4143
|
+
...providerOptions ? { providerOptions } : {},
|
|
4144
|
+
...result.diagnostics.historyCacheMarkIndex !== void 0 ? { historyCacheMarkIndex: result.diagnostics.historyCacheMarkIndex } : {},
|
|
4145
|
+
mutationsApplied: result.mutationsApplied.map((m) => m.id),
|
|
4146
|
+
advisories: result.advisories ?? [],
|
|
4147
|
+
diagnostics,
|
|
4148
|
+
ir
|
|
4149
|
+
};
|
|
4150
|
+
}
|
|
4151
|
+
function extractKeptToolNames(result) {
|
|
4152
|
+
const names = /* @__PURE__ */ new Set();
|
|
4153
|
+
const tools = result.request.tools;
|
|
4154
|
+
if (!Array.isArray(tools)) return names;
|
|
4155
|
+
if (result.provider === "google") {
|
|
4156
|
+
for (const td of tools) {
|
|
4157
|
+
for (const fn of td.functionDeclarations ?? []) if (fn.name) names.add(fn.name);
|
|
4158
|
+
}
|
|
4159
|
+
} else if (result.provider === "openai") {
|
|
4160
|
+
for (const t of tools) {
|
|
4161
|
+
const n = t.function?.name;
|
|
4162
|
+
if (n) names.add(n);
|
|
4163
|
+
}
|
|
4164
|
+
} else {
|
|
4165
|
+
for (const t of tools) {
|
|
4166
|
+
if (t.name) names.add(t.name);
|
|
4167
|
+
}
|
|
4168
|
+
}
|
|
4169
|
+
return names;
|
|
4170
|
+
}
|
|
1266
4171
|
|
|
1267
4172
|
// src/oracle.ts
|
|
1268
4173
|
var DEFAULT_DIMENSIONS = ["correctness", "completeness", "conciseness", "format"];
|
|
@@ -1352,6 +4257,338 @@ function clamp(n) {
|
|
|
1352
4257
|
return Math.max(0, Math.min(1, n));
|
|
1353
4258
|
}
|
|
1354
4259
|
|
|
4260
|
+
// src/advisories-api.ts
|
|
4261
|
+
var SEVERITY_SET = /* @__PURE__ */ new Set(["info", "warn", "critical"]);
|
|
4262
|
+
var STATUS_SET = /* @__PURE__ */ new Set(["open", "snoozed", "resolved"]);
|
|
4263
|
+
var RESOLUTION_SOURCE_SET = /* @__PURE__ */ new Set([
|
|
4264
|
+
"auto",
|
|
4265
|
+
"consumer-marked",
|
|
4266
|
+
"declined"
|
|
4267
|
+
]);
|
|
4268
|
+
function asString2(v) {
|
|
4269
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
4270
|
+
}
|
|
4271
|
+
function asSeverity(v) {
|
|
4272
|
+
if (typeof v === "string" && SEVERITY_SET.has(v)) {
|
|
4273
|
+
return v;
|
|
4274
|
+
}
|
|
4275
|
+
return "info";
|
|
4276
|
+
}
|
|
4277
|
+
function asStatus(v) {
|
|
4278
|
+
if (typeof v === "string" && STATUS_SET.has(v)) {
|
|
4279
|
+
return v;
|
|
4280
|
+
}
|
|
4281
|
+
return "open";
|
|
4282
|
+
}
|
|
4283
|
+
function asResolutionSource(v) {
|
|
4284
|
+
if (typeof v === "string" && RESOLUTION_SOURCE_SET.has(v)) {
|
|
4285
|
+
return v;
|
|
4286
|
+
}
|
|
4287
|
+
return void 0;
|
|
4288
|
+
}
|
|
4289
|
+
function rowToAdvisory(row) {
|
|
4290
|
+
const archetype = asString2(row.applies_to_archetype);
|
|
4291
|
+
const model = asString2(row.applies_to_model);
|
|
4292
|
+
const docsLink = asString2(row.docs_url);
|
|
4293
|
+
const suggestion = asString2(row.suggestion);
|
|
4294
|
+
let suggestedFix = null;
|
|
4295
|
+
if (docsLink || suggestion) {
|
|
4296
|
+
suggestedFix = { type: "manual" };
|
|
4297
|
+
if (docsLink) suggestedFix.docsLink = docsLink;
|
|
4298
|
+
if (suggestion) suggestedFix.before = suggestion;
|
|
4299
|
+
}
|
|
4300
|
+
const out = {
|
|
4301
|
+
id: typeof row.id === "string" ? row.id : "",
|
|
4302
|
+
rule: typeof row.rule === "string" ? row.rule : "",
|
|
4303
|
+
severity: asSeverity(row.severity),
|
|
4304
|
+
openedAt: typeof row.opened_at === "string" ? row.opened_at : "",
|
|
4305
|
+
lastObservedAt: typeof row.last_observed_at === "string" ? row.last_observed_at : "",
|
|
4306
|
+
observationCount: typeof row.observation_count === "number" ? row.observation_count : 0,
|
|
4307
|
+
appliesTo: {
|
|
4308
|
+
...archetype ? { archetype } : {},
|
|
4309
|
+
...model ? { model } : {}
|
|
4310
|
+
},
|
|
4311
|
+
message: typeof row.message === "string" ? row.message : "",
|
|
4312
|
+
suggestedFix,
|
|
4313
|
+
autoApplicable: false,
|
|
4314
|
+
// reserved — alpha.30+
|
|
4315
|
+
status: asStatus(row.status)
|
|
4316
|
+
};
|
|
4317
|
+
const resolvedAt = asString2(row.resolved_at);
|
|
4318
|
+
if (resolvedAt) out.resolvedAt = resolvedAt;
|
|
4319
|
+
const resolutionSource = asResolutionSource(row.resolution_source);
|
|
4320
|
+
if (resolutionSource) out.resolutionSource = resolutionSource;
|
|
4321
|
+
const resolutionNote = asString2(row.resolution_note);
|
|
4322
|
+
if (resolutionNote) out.resolutionNote = resolutionNote;
|
|
4323
|
+
return out;
|
|
4324
|
+
}
|
|
4325
|
+
function resolveFetch(injected) {
|
|
4326
|
+
return injected ?? ((...args) => globalThis.fetch(...args));
|
|
4327
|
+
}
|
|
4328
|
+
function normalizeEndpoint2(endpoint) {
|
|
4329
|
+
return endpoint.replace(/\/+$/, "");
|
|
4330
|
+
}
|
|
4331
|
+
async function getActionableAdvisories(opts) {
|
|
4332
|
+
const {
|
|
4333
|
+
appId,
|
|
4334
|
+
severity,
|
|
4335
|
+
status,
|
|
4336
|
+
brainEndpoint,
|
|
4337
|
+
brainJwt,
|
|
4338
|
+
brainAnonKey,
|
|
4339
|
+
fetch: injectedFetch
|
|
4340
|
+
} = opts;
|
|
4341
|
+
if (!appId) {
|
|
4342
|
+
throw new Error("getActionableAdvisories: appId is required");
|
|
4343
|
+
}
|
|
4344
|
+
const doFetch = resolveFetch(injectedFetch);
|
|
4345
|
+
const base = normalizeEndpoint2(brainEndpoint);
|
|
4346
|
+
const qs = new URLSearchParams();
|
|
4347
|
+
qs.set("app_id", `eq.${appId}`);
|
|
4348
|
+
if (severity) qs.set("severity", `eq.${severity}`);
|
|
4349
|
+
const effectiveStatus = status ?? "open";
|
|
4350
|
+
if (effectiveStatus !== "all") {
|
|
4351
|
+
qs.set("status", `eq.${effectiveStatus}`);
|
|
4352
|
+
}
|
|
4353
|
+
qs.set("order", "last_observed_at.desc");
|
|
4354
|
+
const url = `${base}/rest/v1/actionable_advisories_v?${qs.toString()}`;
|
|
4355
|
+
let res;
|
|
4356
|
+
try {
|
|
4357
|
+
res = await doFetch(url, {
|
|
4358
|
+
method: "GET",
|
|
4359
|
+
headers: {
|
|
4360
|
+
Authorization: `Bearer ${brainJwt}`,
|
|
4361
|
+
apikey: brainAnonKey,
|
|
4362
|
+
Accept: "application/json"
|
|
4363
|
+
}
|
|
4364
|
+
});
|
|
4365
|
+
} catch (err) {
|
|
4366
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4367
|
+
throw new Error(`getActionableAdvisories: network error: ${msg}`);
|
|
4368
|
+
}
|
|
4369
|
+
if (res.status === 401 || res.status === 403) {
|
|
4370
|
+
throw new Error("getActionableAdvisories: brain auth misconfig");
|
|
4371
|
+
}
|
|
4372
|
+
if (res.status >= 500) {
|
|
4373
|
+
throw new Error(`getActionableAdvisories: brain unavailable (${res.status})`);
|
|
4374
|
+
}
|
|
4375
|
+
if (!res.ok) {
|
|
4376
|
+
throw new Error(`getActionableAdvisories: bad request (${res.status})`);
|
|
4377
|
+
}
|
|
4378
|
+
let rows;
|
|
4379
|
+
try {
|
|
4380
|
+
rows = await res.json();
|
|
4381
|
+
} catch {
|
|
4382
|
+
throw new Error("getActionableAdvisories: malformed brain response");
|
|
4383
|
+
}
|
|
4384
|
+
if (!Array.isArray(rows)) {
|
|
4385
|
+
throw new Error("getActionableAdvisories: expected array from brain");
|
|
4386
|
+
}
|
|
4387
|
+
const out = [];
|
|
4388
|
+
for (const raw of rows) {
|
|
4389
|
+
if (raw && typeof raw === "object") {
|
|
4390
|
+
out.push(rowToAdvisory(raw));
|
|
4391
|
+
}
|
|
4392
|
+
}
|
|
4393
|
+
return out;
|
|
4394
|
+
}
|
|
4395
|
+
async function markAdvisoryResolved(opts) {
|
|
4396
|
+
const {
|
|
4397
|
+
id,
|
|
4398
|
+
resolutionNote,
|
|
4399
|
+
brainEndpoint,
|
|
4400
|
+
brainJwt,
|
|
4401
|
+
brainAnonKey,
|
|
4402
|
+
fetch: injectedFetch
|
|
4403
|
+
} = opts;
|
|
4404
|
+
if (!id) {
|
|
4405
|
+
return { ok: false, reason: "id_required" };
|
|
4406
|
+
}
|
|
4407
|
+
const doFetch = resolveFetch(injectedFetch);
|
|
4408
|
+
const base = normalizeEndpoint2(brainEndpoint);
|
|
4409
|
+
const lookupUrl = `${base}/rest/v1/actionable_advisories_v?id=eq.${encodeURIComponent(id)}&select=app_id,rule`;
|
|
4410
|
+
let lookupRes;
|
|
4411
|
+
try {
|
|
4412
|
+
lookupRes = await doFetch(lookupUrl, {
|
|
4413
|
+
method: "GET",
|
|
4414
|
+
headers: {
|
|
4415
|
+
Authorization: `Bearer ${brainJwt}`,
|
|
4416
|
+
apikey: brainAnonKey,
|
|
4417
|
+
Accept: "application/json"
|
|
4418
|
+
}
|
|
4419
|
+
});
|
|
4420
|
+
} catch (err) {
|
|
4421
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4422
|
+
return { ok: false, reason: `network_error:${msg}` };
|
|
4423
|
+
}
|
|
4424
|
+
if (lookupRes.status === 401 || lookupRes.status === 403) {
|
|
4425
|
+
return { ok: false, reason: "brain_auth_misconfig" };
|
|
4426
|
+
}
|
|
4427
|
+
if (lookupRes.status >= 500) {
|
|
4428
|
+
return { ok: false, reason: "brain_unavailable" };
|
|
4429
|
+
}
|
|
4430
|
+
if (!lookupRes.ok) {
|
|
4431
|
+
return { ok: false, reason: `brain_lookup_failed:${lookupRes.status}` };
|
|
4432
|
+
}
|
|
4433
|
+
let lookupRows;
|
|
4434
|
+
try {
|
|
4435
|
+
lookupRows = await lookupRes.json();
|
|
4436
|
+
} catch {
|
|
4437
|
+
return { ok: false, reason: "brain_lookup_malformed" };
|
|
4438
|
+
}
|
|
4439
|
+
if (!Array.isArray(lookupRows) || lookupRows.length === 0) {
|
|
4440
|
+
return { ok: false, reason: "advisory_not_found" };
|
|
4441
|
+
}
|
|
4442
|
+
const tuple = lookupRows[0];
|
|
4443
|
+
const appId = typeof tuple.app_id === "string" ? tuple.app_id : "";
|
|
4444
|
+
const code = typeof tuple.rule === "string" ? tuple.rule : "";
|
|
4445
|
+
if (!appId || !code) {
|
|
4446
|
+
return { ok: false, reason: "advisory_tuple_invalid" };
|
|
4447
|
+
}
|
|
4448
|
+
const outcomesUrl = `${base}/rest/v1/compile_outcomes?app_id=eq.${encodeURIComponent(appId)}&select=id`;
|
|
4449
|
+
let outcomesRes;
|
|
4450
|
+
try {
|
|
4451
|
+
outcomesRes = await doFetch(outcomesUrl, {
|
|
4452
|
+
method: "GET",
|
|
4453
|
+
headers: {
|
|
4454
|
+
Authorization: `Bearer ${brainJwt}`,
|
|
4455
|
+
apikey: brainAnonKey,
|
|
4456
|
+
Accept: "application/json"
|
|
4457
|
+
}
|
|
4458
|
+
});
|
|
4459
|
+
} catch (err) {
|
|
4460
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4461
|
+
return { ok: false, reason: `network_error:${msg}` };
|
|
4462
|
+
}
|
|
4463
|
+
if (outcomesRes.status === 401 || outcomesRes.status === 403) {
|
|
4464
|
+
return { ok: false, reason: "brain_auth_misconfig" };
|
|
4465
|
+
}
|
|
4466
|
+
if (outcomesRes.status >= 500) {
|
|
4467
|
+
return { ok: false, reason: "brain_unavailable" };
|
|
4468
|
+
}
|
|
4469
|
+
if (!outcomesRes.ok) {
|
|
4470
|
+
return { ok: false, reason: `brain_lookup_failed:${outcomesRes.status}` };
|
|
4471
|
+
}
|
|
4472
|
+
let outcomeRows;
|
|
4473
|
+
try {
|
|
4474
|
+
outcomeRows = await outcomesRes.json();
|
|
4475
|
+
} catch {
|
|
4476
|
+
return { ok: false, reason: "brain_lookup_malformed" };
|
|
4477
|
+
}
|
|
4478
|
+
if (!Array.isArray(outcomeRows)) {
|
|
4479
|
+
return { ok: false, reason: "brain_lookup_malformed" };
|
|
4480
|
+
}
|
|
4481
|
+
const outcomeIds = [];
|
|
4482
|
+
for (const row of outcomeRows) {
|
|
4483
|
+
if (row && typeof row === "object") {
|
|
4484
|
+
const idVal = row.id;
|
|
4485
|
+
if (typeof idVal === "number" && Number.isFinite(idVal)) {
|
|
4486
|
+
outcomeIds.push(idVal);
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
}
|
|
4490
|
+
if (outcomeIds.length === 0) {
|
|
4491
|
+
return { ok: true };
|
|
4492
|
+
}
|
|
4493
|
+
const inList = outcomeIds.join(",");
|
|
4494
|
+
const patchUrl = `${base}/rest/v1/compile_outcome_advisories?outcome_id=in.(${inList})&code=eq.${encodeURIComponent(code)}&resolved_at=is.null`;
|
|
4495
|
+
const patchBody = {
|
|
4496
|
+
resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4497
|
+
resolution_source: "consumer-marked"
|
|
4498
|
+
};
|
|
4499
|
+
if (resolutionNote !== void 0) {
|
|
4500
|
+
patchBody.resolution_note = resolutionNote;
|
|
4501
|
+
}
|
|
4502
|
+
let patchRes;
|
|
4503
|
+
try {
|
|
4504
|
+
patchRes = await doFetch(patchUrl, {
|
|
4505
|
+
method: "PATCH",
|
|
4506
|
+
headers: {
|
|
4507
|
+
Authorization: `Bearer ${brainJwt}`,
|
|
4508
|
+
apikey: brainAnonKey,
|
|
4509
|
+
"Content-Type": "application/json",
|
|
4510
|
+
Accept: "application/json",
|
|
4511
|
+
// PostgREST default is no return; we don't need the row back.
|
|
4512
|
+
Prefer: "return=minimal"
|
|
4513
|
+
},
|
|
4514
|
+
body: JSON.stringify(patchBody)
|
|
4515
|
+
});
|
|
4516
|
+
} catch (err) {
|
|
4517
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4518
|
+
return { ok: false, reason: `network_error:${msg}` };
|
|
4519
|
+
}
|
|
4520
|
+
if (patchRes.status === 401 || patchRes.status === 403) {
|
|
4521
|
+
return { ok: false, reason: "brain_auth_misconfig" };
|
|
4522
|
+
}
|
|
4523
|
+
if (patchRes.status >= 500) {
|
|
4524
|
+
return { ok: false, reason: "brain_unavailable" };
|
|
4525
|
+
}
|
|
4526
|
+
if (!patchRes.ok) {
|
|
4527
|
+
return { ok: false, reason: `patch_failed:${patchRes.status}` };
|
|
4528
|
+
}
|
|
4529
|
+
return { ok: true };
|
|
4530
|
+
}
|
|
4531
|
+
async function markExclusionFindingHandled(opts) {
|
|
4532
|
+
const {
|
|
4533
|
+
appId,
|
|
4534
|
+
archetype,
|
|
4535
|
+
excludedModel,
|
|
4536
|
+
resolution,
|
|
4537
|
+
resolutionNote,
|
|
4538
|
+
brainEndpoint,
|
|
4539
|
+
brainJwt,
|
|
4540
|
+
brainAnonKey,
|
|
4541
|
+
fetch: injectedFetch
|
|
4542
|
+
} = opts;
|
|
4543
|
+
if (!appId) return { ok: false, reason: "app_id_required" };
|
|
4544
|
+
if (!archetype) return { ok: false, reason: "archetype_required" };
|
|
4545
|
+
if (!excludedModel) {
|
|
4546
|
+
return { ok: false, reason: "excluded_model_required" };
|
|
4547
|
+
}
|
|
4548
|
+
if (resolution !== "consumer-marked" && resolution !== "declined" && resolution !== "probed-unblock" && resolution !== "probed-stay-excluded") {
|
|
4549
|
+
return { ok: false, reason: "resolution_invalid" };
|
|
4550
|
+
}
|
|
4551
|
+
const doFetch = resolveFetch(injectedFetch);
|
|
4552
|
+
const base = normalizeEndpoint2(brainEndpoint);
|
|
4553
|
+
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`;
|
|
4554
|
+
const patchBody = {
|
|
4555
|
+
resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4556
|
+
resolution_source: resolution
|
|
4557
|
+
};
|
|
4558
|
+
if (resolutionNote !== void 0) {
|
|
4559
|
+
patchBody.resolution_note = resolutionNote;
|
|
4560
|
+
}
|
|
4561
|
+
let res;
|
|
4562
|
+
try {
|
|
4563
|
+
res = await doFetch(url, {
|
|
4564
|
+
method: "PATCH",
|
|
4565
|
+
headers: {
|
|
4566
|
+
Authorization: `Bearer ${brainJwt}`,
|
|
4567
|
+
apikey: brainAnonKey,
|
|
4568
|
+
"Content-Type": "application/json",
|
|
4569
|
+
Accept: "application/json",
|
|
4570
|
+
// PATCH may match zero rows when already resolved — return=minimal
|
|
4571
|
+
// keeps the response body empty so the success path is uniform.
|
|
4572
|
+
Prefer: "return=minimal"
|
|
4573
|
+
},
|
|
4574
|
+
body: JSON.stringify(patchBody)
|
|
4575
|
+
});
|
|
4576
|
+
} catch (err) {
|
|
4577
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4578
|
+
return { ok: false, reason: `network_error:${msg}` };
|
|
4579
|
+
}
|
|
4580
|
+
if (res.status === 401 || res.status === 403) {
|
|
4581
|
+
return { ok: false, reason: "brain_auth_misconfig" };
|
|
4582
|
+
}
|
|
4583
|
+
if (res.status >= 500) {
|
|
4584
|
+
return { ok: false, reason: "brain_unavailable" };
|
|
4585
|
+
}
|
|
4586
|
+
if (!res.ok) {
|
|
4587
|
+
return { ok: false, reason: `patch_failed:${res.status}` };
|
|
4588
|
+
}
|
|
4589
|
+
return { ok: true };
|
|
4590
|
+
}
|
|
4591
|
+
|
|
1355
4592
|
// src/index.ts
|
|
1356
4593
|
function compile2(ir, opts) {
|
|
1357
4594
|
const result = compile(ir, opts);
|
|
@@ -1359,29 +4596,87 @@ function compile2(ir, opts) {
|
|
|
1359
4596
|
return result;
|
|
1360
4597
|
}
|
|
1361
4598
|
export {
|
|
4599
|
+
ABSOLUTE_FLOOR,
|
|
1362
4600
|
ALIASES,
|
|
1363
4601
|
ALL_ARCHETYPES,
|
|
4602
|
+
ARCHETYPE_FAMILY_FITS,
|
|
4603
|
+
ARCHETYPE_FLOOR_DEFAULT,
|
|
1364
4604
|
CallError,
|
|
4605
|
+
DEFAULT_FINDINGS_ENDPOINT,
|
|
1365
4606
|
DIALECT_VERSION,
|
|
4607
|
+
FamilyResolutionError,
|
|
1366
4608
|
INTENT_ARCHETYPES,
|
|
4609
|
+
LATENCY_TIER_MS,
|
|
4610
|
+
MEASURED_GROUNDING_MIN_N,
|
|
4611
|
+
PRODUCER_OWNED_RULE_CODES,
|
|
4612
|
+
PROVIDER_ENV_KEYS,
|
|
4613
|
+
RULE_SEQUENTIAL_TOOL_CLIFF,
|
|
4614
|
+
TRANSLATOR_FLOOR,
|
|
1367
4615
|
allProfiles,
|
|
4616
|
+
applyArchetypeConvention,
|
|
4617
|
+
applySectionRewrites,
|
|
4618
|
+
attachCacheControlToStreamTextInput,
|
|
1368
4619
|
bucketContext,
|
|
1369
4620
|
bucketHistory,
|
|
1370
4621
|
bucketToolCount,
|
|
1371
4622
|
buildLLMJudge,
|
|
4623
|
+
buildShadowProbeRow,
|
|
1372
4624
|
call,
|
|
1373
4625
|
clearBrain,
|
|
1374
4626
|
compile2 as compile,
|
|
4627
|
+
compileForAISDKv6,
|
|
1375
4628
|
configureBrain,
|
|
1376
4629
|
countTokens,
|
|
4630
|
+
deriveFamilyFromModelId,
|
|
4631
|
+
deriveOwnership,
|
|
1377
4632
|
execute,
|
|
4633
|
+
findBetterFit,
|
|
4634
|
+
getActionableAdvisories,
|
|
4635
|
+
getAllStarterChains,
|
|
4636
|
+
getAllStarterChainsWithGrounding,
|
|
4637
|
+
getArchetypePerfScore,
|
|
4638
|
+
getDefaultFallbackChain,
|
|
4639
|
+
getDefaultFallbackChainWithGrounding,
|
|
4640
|
+
getModelCompatibility,
|
|
4641
|
+
getPerAxisMetrics,
|
|
1378
4642
|
getProfile,
|
|
4643
|
+
getReachabilityDiagnostic,
|
|
4644
|
+
getRecommendedPrimary,
|
|
4645
|
+
getSequentialStarterChain,
|
|
4646
|
+
getSequentialStarterChainWithGrounding,
|
|
4647
|
+
getStaleExclusionFindings,
|
|
4648
|
+
getStarterChain,
|
|
4649
|
+
getStarterChainWithGrounding,
|
|
1379
4650
|
hashShape,
|
|
1380
4651
|
isArchetype,
|
|
4652
|
+
isBrainQueryActiveFor,
|
|
4653
|
+
isBrainSync,
|
|
4654
|
+
isExclusionFindingsBrainActive,
|
|
4655
|
+
isModelReachable,
|
|
4656
|
+
isProviderReachable,
|
|
4657
|
+
latencyTierOf,
|
|
1381
4658
|
learningKey,
|
|
4659
|
+
loadAliasesFromBrain,
|
|
4660
|
+
loadArchetypePerfFromBrain,
|
|
4661
|
+
loadArchetypePerfNFromBrain,
|
|
4662
|
+
loadChainsFromBrain,
|
|
4663
|
+
loadModelsFromBrain,
|
|
4664
|
+
loadPricingFromBrain,
|
|
4665
|
+
markAdvisoryResolved,
|
|
4666
|
+
markExclusionFindingHandled,
|
|
4667
|
+
markPromoteReadyHandled,
|
|
4668
|
+
probeShadow,
|
|
4669
|
+
profileToRow,
|
|
1382
4670
|
profilesByProvider,
|
|
4671
|
+
readBrainReadEnv,
|
|
1383
4672
|
record,
|
|
4673
|
+
recordOutcome,
|
|
4674
|
+
recordShadowProbe,
|
|
1384
4675
|
resetTokenizer,
|
|
4676
|
+
resolveConventionsForProfile,
|
|
4677
|
+
resolvePricingAt,
|
|
4678
|
+
resolveProviderKey,
|
|
4679
|
+
runAdvisor,
|
|
1385
4680
|
setTokenizer,
|
|
1386
4681
|
tryGetProfile
|
|
1387
4682
|
};
|