@warmdrift/kgauto-compiler 2.0.0-alpha.3
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 +198 -0
- package/dist/chunk-5TI6PNSK.mjs +95 -0
- package/dist/chunk-MBEI5UOM.mjs +409 -0
- package/dist/dialect.d.mts +99 -0
- package/dist/dialect.d.ts +99 -0
- package/dist/dialect.js +127 -0
- package/dist/dialect.mjs +22 -0
- package/dist/index.d.mts +238 -0
- package/dist/index.d.ts +238 -0
- package/dist/index.js +1804 -0
- package/dist/index.mjs +1286 -0
- package/dist/profiles-BiyrF36f.d.mts +489 -0
- package/dist/profiles-C5lVqF8_.d.ts +489 -0
- package/dist/profiles.d.mts +2 -0
- package/dist/profiles.d.ts +2 -0
- package/dist/profiles.js +437 -0
- package/dist/profiles.mjs +14 -0
- package/package.json +59 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1286 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALL_ARCHETYPES,
|
|
3
|
+
DIALECT_VERSION,
|
|
4
|
+
INTENT_ARCHETYPES,
|
|
5
|
+
bucketContext,
|
|
6
|
+
bucketHistory,
|
|
7
|
+
bucketToolCount,
|
|
8
|
+
hashShape,
|
|
9
|
+
isArchetype,
|
|
10
|
+
learningKey
|
|
11
|
+
} from "./chunk-5TI6PNSK.mjs";
|
|
12
|
+
import {
|
|
13
|
+
ALIASES,
|
|
14
|
+
allProfiles,
|
|
15
|
+
getProfile,
|
|
16
|
+
profilesByProvider,
|
|
17
|
+
tryGetProfile
|
|
18
|
+
} from "./chunk-MBEI5UOM.mjs";
|
|
19
|
+
|
|
20
|
+
// src/tokenizer.ts
|
|
21
|
+
var tokenizerImpl = defaultCharBasedCounter;
|
|
22
|
+
function defaultCharBasedCounter(text) {
|
|
23
|
+
if (!text) return 0;
|
|
24
|
+
return Math.max(1, Math.ceil(text.length / 4));
|
|
25
|
+
}
|
|
26
|
+
function setTokenizer(impl) {
|
|
27
|
+
tokenizerImpl = impl;
|
|
28
|
+
}
|
|
29
|
+
function resetTokenizer() {
|
|
30
|
+
tokenizerImpl = defaultCharBasedCounter;
|
|
31
|
+
}
|
|
32
|
+
function countTokens(text) {
|
|
33
|
+
if (!text) return 0;
|
|
34
|
+
try {
|
|
35
|
+
const n = tokenizerImpl(text);
|
|
36
|
+
return Number.isFinite(n) && n >= 0 ? n : defaultCharBasedCounter(text);
|
|
37
|
+
} catch {
|
|
38
|
+
return defaultCharBasedCounter(text);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function countToolTokens(tool) {
|
|
42
|
+
const namePart = countTokens(tool.name);
|
|
43
|
+
const descPart = tool.description ? countTokens(tool.description) : 0;
|
|
44
|
+
const paramPart = tool.parameters ? countTokens(JSON.stringify(tool.parameters)) : 0;
|
|
45
|
+
return namePart + descPart + paramPart + 8;
|
|
46
|
+
}
|
|
47
|
+
function countMessagesTokens(messages) {
|
|
48
|
+
let total = 0;
|
|
49
|
+
for (const m of messages) {
|
|
50
|
+
total += countTokens(m.content) + 4;
|
|
51
|
+
}
|
|
52
|
+
return total;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/passes.ts
|
|
56
|
+
function passSlice(ir) {
|
|
57
|
+
const intent = ir.intent.archetype;
|
|
58
|
+
const before = ir.sections.length;
|
|
59
|
+
const kept = ir.sections.filter((s) => !s.intents || s.intents.length === 0 || s.intents.includes(intent));
|
|
60
|
+
const dropped = before - kept.length;
|
|
61
|
+
if (dropped === 0) return { value: ir, mutations: [] };
|
|
62
|
+
return {
|
|
63
|
+
value: { ...ir, sections: kept },
|
|
64
|
+
mutations: [
|
|
65
|
+
{
|
|
66
|
+
id: `slice-${dropped}`,
|
|
67
|
+
source: "static_pass",
|
|
68
|
+
passName: "slice",
|
|
69
|
+
description: `Dropped ${dropped} of ${before} sections not tagged for intent=${intent}`
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function passDedupe(ir) {
|
|
75
|
+
const seen = /* @__PURE__ */ new Map();
|
|
76
|
+
const order = [];
|
|
77
|
+
for (const s of ir.sections) {
|
|
78
|
+
const key = simpleHash(s.text.trim());
|
|
79
|
+
if (!seen.has(key)) {
|
|
80
|
+
seen.set(key, s);
|
|
81
|
+
order.push(key);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const deduped = order.map((k) => seen.get(k));
|
|
85
|
+
const dropped = ir.sections.length - deduped.length;
|
|
86
|
+
if (dropped === 0) return { value: ir, mutations: [] };
|
|
87
|
+
return {
|
|
88
|
+
value: { ...ir, sections: deduped },
|
|
89
|
+
mutations: [
|
|
90
|
+
{
|
|
91
|
+
id: `dedupe-${dropped}`,
|
|
92
|
+
source: "static_pass",
|
|
93
|
+
passName: "dedupe",
|
|
94
|
+
description: `Removed ${dropped} duplicate section(s) (by text hash)`
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function passToolRelevance(ir, opts = {}) {
|
|
100
|
+
if (!ir.tools || ir.tools.length === 0) return { value: ir, mutations: [] };
|
|
101
|
+
const threshold = opts.threshold ?? 0.2;
|
|
102
|
+
const intent = ir.intent.archetype;
|
|
103
|
+
const scored = ir.tools.map((t) => {
|
|
104
|
+
const score = t.relevanceByIntent?.[intent] ?? 0.5;
|
|
105
|
+
return { tool: t, score };
|
|
106
|
+
});
|
|
107
|
+
const kept = scored.filter((s) => s.score >= threshold).sort((a, b) => b.score - a.score).map((s) => s.tool);
|
|
108
|
+
const limited = opts.maxKeep ? kept.slice(0, opts.maxKeep) : kept;
|
|
109
|
+
const dropped = ir.tools.length - limited.length;
|
|
110
|
+
if (dropped === 0) return { value: ir, mutations: [] };
|
|
111
|
+
return {
|
|
112
|
+
value: { ...ir, tools: limited },
|
|
113
|
+
mutations: [
|
|
114
|
+
{
|
|
115
|
+
id: `tool-relevance-${dropped}`,
|
|
116
|
+
source: "static_pass",
|
|
117
|
+
passName: "tool_relevance",
|
|
118
|
+
description: `Dropped ${dropped} of ${ir.tools.length} tools below relevance ${threshold} for intent=${intent}`
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function passCompressHistory(ir, opts = {}) {
|
|
124
|
+
const history = ir.history;
|
|
125
|
+
if (!history || history.length === 0) return { value: ir, mutations: [] };
|
|
126
|
+
const keepRecent = opts.keepRecent ?? 4;
|
|
127
|
+
const summarizeOlderThan = opts.summarizeOlderThan ?? 8;
|
|
128
|
+
if (history.length <= summarizeOlderThan) return { value: ir, mutations: [] };
|
|
129
|
+
const cutIndex = history.length - keepRecent;
|
|
130
|
+
const old = history.slice(0, cutIndex);
|
|
131
|
+
const recent = history.slice(cutIndex);
|
|
132
|
+
const userTurns = old.filter((m) => m.role === "user");
|
|
133
|
+
const firstUserLine = userTurns[0]?.content.split("\n")[0]?.slice(0, 200) ?? "";
|
|
134
|
+
const summary = {
|
|
135
|
+
role: "system",
|
|
136
|
+
content: `[Earlier conversation: ${old.length} turns omitted. First user message: "${firstUserLine}"]`
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
value: { ...ir, history: [summary, ...recent] },
|
|
140
|
+
mutations: [
|
|
141
|
+
{
|
|
142
|
+
id: `compress-history-${old.length}`,
|
|
143
|
+
source: "static_pass",
|
|
144
|
+
passName: "compress_history",
|
|
145
|
+
description: `Compressed ${old.length} old turns into 1 summary line (kept ${keepRecent} recent)`
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function passApplyCliffs(ir, profile, estimatedInputTokens) {
|
|
151
|
+
const mutations = [];
|
|
152
|
+
const hints = { qualityWarning: [] };
|
|
153
|
+
let nextIR = ir;
|
|
154
|
+
for (const cliff of profile.cliffs) {
|
|
155
|
+
let triggered = false;
|
|
156
|
+
switch (cliff.metric) {
|
|
157
|
+
case "input_tokens":
|
|
158
|
+
triggered = estimatedInputTokens >= cliff.threshold;
|
|
159
|
+
break;
|
|
160
|
+
case "tool_count":
|
|
161
|
+
triggered = (nextIR.tools?.length ?? 0) >= cliff.threshold;
|
|
162
|
+
break;
|
|
163
|
+
case "history_turns":
|
|
164
|
+
triggered = (nextIR.history?.length ?? 0) >= cliff.threshold;
|
|
165
|
+
break;
|
|
166
|
+
case "thinking_with_short_output":
|
|
167
|
+
triggered = !!nextIR.constraints?.expectedShortOutput;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
if (triggered && cliff.whenIntent && nextIR.intent.archetype !== cliff.whenIntent) {
|
|
171
|
+
triggered = false;
|
|
172
|
+
}
|
|
173
|
+
if (!triggered) continue;
|
|
174
|
+
switch (cliff.action) {
|
|
175
|
+
case "drop_to_top_relevant": {
|
|
176
|
+
const targetCount = Math.min(
|
|
177
|
+
Math.floor(cliff.threshold * 0.75),
|
|
178
|
+
Math.max(1, Math.floor((nextIR.tools?.length ?? 0) / 2))
|
|
179
|
+
);
|
|
180
|
+
if (nextIR.tools && nextIR.tools.length > targetCount) {
|
|
181
|
+
const intent = nextIR.intent.archetype;
|
|
182
|
+
const scored = nextIR.tools.map((t) => ({ tool: t, score: t.relevanceByIntent?.[intent] ?? 0.5 })).sort((a, b) => b.score - a.score).slice(0, targetCount).map((s) => s.tool);
|
|
183
|
+
nextIR = { ...nextIR, tools: scored };
|
|
184
|
+
mutations.push({
|
|
185
|
+
id: `cliff-${cliff.metric}`,
|
|
186
|
+
source: "cliff_guard",
|
|
187
|
+
passName: "apply_cliffs",
|
|
188
|
+
description: `${profile.id}: ${cliff.reason}; trimmed tools to ${targetCount}`
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case "force_thinking_budget_zero":
|
|
194
|
+
hints.forceThinkingZero = true;
|
|
195
|
+
mutations.push({
|
|
196
|
+
id: `cliff-thinking-zero`,
|
|
197
|
+
source: "cliff_guard",
|
|
198
|
+
passName: "apply_cliffs",
|
|
199
|
+
description: `${profile.id}: ${cliff.reason}`
|
|
200
|
+
});
|
|
201
|
+
break;
|
|
202
|
+
case "force_terse_output":
|
|
203
|
+
hints.forceTerseOutput = true;
|
|
204
|
+
mutations.push({
|
|
205
|
+
id: `cliff-terse`,
|
|
206
|
+
source: "cliff_guard",
|
|
207
|
+
passName: "apply_cliffs",
|
|
208
|
+
description: `${profile.id}: ${cliff.reason}`
|
|
209
|
+
});
|
|
210
|
+
break;
|
|
211
|
+
case "downgrade_quality_warning":
|
|
212
|
+
hints.qualityWarning.push(cliff.reason);
|
|
213
|
+
mutations.push({
|
|
214
|
+
id: `cliff-quality-warning`,
|
|
215
|
+
source: "cliff_guard",
|
|
216
|
+
passName: "apply_cliffs",
|
|
217
|
+
description: `${profile.id}: ${cliff.reason}`
|
|
218
|
+
});
|
|
219
|
+
break;
|
|
220
|
+
case "escalate_target":
|
|
221
|
+
hints.escalateRequested = true;
|
|
222
|
+
mutations.push({
|
|
223
|
+
id: `cliff-escalate`,
|
|
224
|
+
source: "cliff_guard",
|
|
225
|
+
passName: "apply_cliffs",
|
|
226
|
+
description: `${profile.id}: ${cliff.reason}`
|
|
227
|
+
});
|
|
228
|
+
break;
|
|
229
|
+
case "strip_tools": {
|
|
230
|
+
const droppedCount = nextIR.tools?.length ?? 0;
|
|
231
|
+
if (droppedCount > 0) {
|
|
232
|
+
nextIR = { ...nextIR, tools: [] };
|
|
233
|
+
mutations.push({
|
|
234
|
+
id: `cliff-strip-tools${cliff.whenIntent ? `-${cliff.whenIntent}` : ""}`,
|
|
235
|
+
source: "cliff_guard",
|
|
236
|
+
passName: "apply_cliffs",
|
|
237
|
+
description: `${profile.id}: ${cliff.reason} \u2014 stripped ${droppedCount} tools`
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return { value: { ir: nextIR, loweringHints: hints }, mutations };
|
|
245
|
+
}
|
|
246
|
+
function passScoreTargets(ir, opts) {
|
|
247
|
+
const constraints = ir.constraints ?? {};
|
|
248
|
+
const policy = opts.policy ?? {};
|
|
249
|
+
const blockedSet = new Set(policy.blockedModels ?? []);
|
|
250
|
+
const preferredSet = new Set(policy.preferredModels ?? []);
|
|
251
|
+
const scores = [];
|
|
252
|
+
const policyMutations = [];
|
|
253
|
+
for (const modelId of ir.models) {
|
|
254
|
+
let profile;
|
|
255
|
+
try {
|
|
256
|
+
profile = opts.profilesById(modelId);
|
|
257
|
+
} catch {
|
|
258
|
+
scores.push({
|
|
259
|
+
modelId,
|
|
260
|
+
estimatedCostUsd: 0,
|
|
261
|
+
fits: false,
|
|
262
|
+
rejectReasons: ["unknown_model_id"],
|
|
263
|
+
qualityScore: 0,
|
|
264
|
+
rank: -Infinity
|
|
265
|
+
});
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const reasons = [];
|
|
269
|
+
if (blockedSet.has(modelId)) {
|
|
270
|
+
reasons.push(`blocked_by_policy (consumer gated this model \u2014 see CompilePolicy.blockedModels)`);
|
|
271
|
+
}
|
|
272
|
+
if (opts.estimatedInputTokens > profile.maxContextTokens * 0.9) {
|
|
273
|
+
reasons.push(`exceeds context budget (${opts.estimatedInputTokens} > 0.9*${profile.maxContextTokens})`);
|
|
274
|
+
}
|
|
275
|
+
if ((ir.tools?.length ?? 0) > profile.maxTools) {
|
|
276
|
+
reasons.push(`exceeds maxTools (${ir.tools?.length} > ${profile.maxTools})`);
|
|
277
|
+
}
|
|
278
|
+
if (constraints.structuredOutput && profile.structuredOutput === "none") {
|
|
279
|
+
reasons.push(`structuredOutput requested but model has none`);
|
|
280
|
+
}
|
|
281
|
+
let qualityPenalty = 0;
|
|
282
|
+
for (const cliff of profile.cliffs) {
|
|
283
|
+
if (cliff.action !== "downgrade_quality_warning") continue;
|
|
284
|
+
let triggered = false;
|
|
285
|
+
if (cliff.metric === "input_tokens") triggered = opts.estimatedInputTokens >= cliff.threshold;
|
|
286
|
+
if (cliff.metric === "tool_count") triggered = (ir.tools?.length ?? 0) >= cliff.threshold;
|
|
287
|
+
if (triggered) qualityPenalty += 0.3;
|
|
288
|
+
}
|
|
289
|
+
const estimatedCostUsd = opts.estimatedInputTokens / 1e6 * profile.costInputPer1m;
|
|
290
|
+
if (policy.maxCostPerCallUsd !== void 0 && estimatedCostUsd > policy.maxCostPerCallUsd) {
|
|
291
|
+
reasons.push(
|
|
292
|
+
`exceeds_max_cost_per_call (estimated $${estimatedCostUsd.toFixed(4)} > policy ceiling $${policy.maxCostPerCallUsd.toFixed(4)})`
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
const baseQuality = profile.strengths.includes("reasoning") ? 0.85 : profile.strengths.includes("quality") ? 0.8 : 0.6;
|
|
296
|
+
const qualityScore = Math.max(0, baseQuality - qualityPenalty);
|
|
297
|
+
const callerOrderBoost = (ir.models.length - ir.models.indexOf(modelId)) * 0.1;
|
|
298
|
+
const costPenalty = estimatedCostUsd * 5;
|
|
299
|
+
const preferredBoost = preferredSet.has(modelId) ? 0.5 : 0;
|
|
300
|
+
const rank = qualityScore + callerOrderBoost - costPenalty - reasons.length * 10 + preferredBoost;
|
|
301
|
+
scores.push({
|
|
302
|
+
modelId,
|
|
303
|
+
estimatedCostUsd,
|
|
304
|
+
fits: reasons.length === 0,
|
|
305
|
+
rejectReasons: reasons,
|
|
306
|
+
qualityScore,
|
|
307
|
+
rank
|
|
308
|
+
});
|
|
309
|
+
if (blockedSet.has(modelId)) {
|
|
310
|
+
policyMutations.push({
|
|
311
|
+
id: `policy-blocked-${modelId}`,
|
|
312
|
+
source: "compile_policy",
|
|
313
|
+
passName: "score_targets",
|
|
314
|
+
description: `Model ${modelId} excluded by CompilePolicy.blockedModels`
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
if (policy.maxCostPerCallUsd !== void 0 && estimatedCostUsd > policy.maxCostPerCallUsd && !blockedSet.has(modelId)) {
|
|
318
|
+
policyMutations.push({
|
|
319
|
+
id: `policy-over-cost-${modelId}`,
|
|
320
|
+
source: "compile_policy",
|
|
321
|
+
passName: "score_targets",
|
|
322
|
+
description: `Model ${modelId} excluded \u2014 estimated cost $${estimatedCostUsd.toFixed(4)} exceeds policy ceiling $${policy.maxCostPerCallUsd.toFixed(4)}`
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (preferredSet.has(modelId) && reasons.length === 0) {
|
|
326
|
+
policyMutations.push({
|
|
327
|
+
id: `policy-preferred-${modelId}`,
|
|
328
|
+
source: "compile_policy",
|
|
329
|
+
passName: "score_targets",
|
|
330
|
+
description: `Model ${modelId} rank boosted by CompilePolicy.preferredModels`
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return { value: scores, mutations: policyMutations };
|
|
335
|
+
}
|
|
336
|
+
function computeShape(ir, estimatedInputTokens) {
|
|
337
|
+
return {
|
|
338
|
+
contextBucket: bucketContext(estimatedInputTokens),
|
|
339
|
+
toolCountBucket: bucketToolCount(ir.tools?.length ?? 0),
|
|
340
|
+
historyDepth: bucketHistory(ir.history?.length ?? 0),
|
|
341
|
+
outputMode: ir.constraints?.structuredOutput ? "json" : ir.tools?.length ? "tool_call" : "text",
|
|
342
|
+
hasExamples: ir.sections.some((s) => /\bexample\b/i.test(s.id))
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function estimateInputTokens(ir) {
|
|
346
|
+
const sectionTokens = ir.sections.reduce((sum, s) => sum + countTokens(s.text), 0);
|
|
347
|
+
const toolTokens = (ir.tools ?? []).reduce((sum, t) => sum + countToolTokens(t), 0);
|
|
348
|
+
const historyTokens = countMessagesTokens(ir.history ?? []);
|
|
349
|
+
const turnTokens = ir.currentTurn ? countTokens(ir.currentTurn.content) + 4 : 0;
|
|
350
|
+
return sectionTokens + toolTokens + historyTokens + turnTokens + 6;
|
|
351
|
+
}
|
|
352
|
+
function simpleHash(s) {
|
|
353
|
+
let h = 5381;
|
|
354
|
+
for (let i = 0; i < s.length; i++) {
|
|
355
|
+
h = (h << 5) + h + s.charCodeAt(i) | 0;
|
|
356
|
+
}
|
|
357
|
+
return (h >>> 0).toString(36);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/lower.ts
|
|
361
|
+
function lower(ir, profile, hints = {}) {
|
|
362
|
+
switch (profile.provider) {
|
|
363
|
+
case "anthropic":
|
|
364
|
+
return lowerAnthropic(ir, profile, hints);
|
|
365
|
+
case "google":
|
|
366
|
+
return lowerGoogle(ir, profile, hints);
|
|
367
|
+
case "openai":
|
|
368
|
+
return lowerOpenAI(ir, profile, hints);
|
|
369
|
+
case "deepseek":
|
|
370
|
+
return lowerDeepSeek(ir, profile);
|
|
371
|
+
default:
|
|
372
|
+
throw new Error(`No lowering implementation for provider: ${profile.provider}`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
function lowerAnthropic(ir, profile, hints) {
|
|
376
|
+
const systemBlocks = buildAnthropicSystemBlocks(ir.sections, profile);
|
|
377
|
+
const messages = buildAnthropicMessages(ir.history ?? [], ir.currentTurn);
|
|
378
|
+
const tools = ir.tools ? toAnthropicTools(ir.tools) : void 0;
|
|
379
|
+
const cacheableTokens = computeCacheableTokens(systemBlocks);
|
|
380
|
+
const cacheSavings = cacheableTokens / 1e6 * profile.costInputPer1m * (1 - (profile.lowering.cache.discount ?? 0.1));
|
|
381
|
+
return {
|
|
382
|
+
request: {
|
|
383
|
+
provider: "anthropic",
|
|
384
|
+
model: profile.id,
|
|
385
|
+
system: systemBlocks,
|
|
386
|
+
messages,
|
|
387
|
+
tools,
|
|
388
|
+
max_tokens: hints.forceTerseOutput ? 200 : Math.min(profile.maxOutputTokens, 4096)
|
|
389
|
+
},
|
|
390
|
+
diagnostics: {
|
|
391
|
+
cacheableTokens,
|
|
392
|
+
estimatedCacheSavingsUsd: cacheSavings
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function buildAnthropicSystemBlocks(sections, profile) {
|
|
397
|
+
if (sections.length === 0) return [];
|
|
398
|
+
const ordered = sortSections(sections);
|
|
399
|
+
const minTokens = profile.lowering.cache.minTokens ?? 1024;
|
|
400
|
+
const cacheable = [];
|
|
401
|
+
const dynamic = [];
|
|
402
|
+
for (const s of ordered) {
|
|
403
|
+
if (s.cacheable) cacheable.push(s);
|
|
404
|
+
else dynamic.push(s);
|
|
405
|
+
}
|
|
406
|
+
const blocks = [];
|
|
407
|
+
if (cacheable.length > 0) {
|
|
408
|
+
const cacheText = cacheable.map((s) => s.text).join("\n\n");
|
|
409
|
+
const cacheTextTokens = countTokens(cacheText);
|
|
410
|
+
const block = {
|
|
411
|
+
type: "text",
|
|
412
|
+
text: cacheText
|
|
413
|
+
};
|
|
414
|
+
if (cacheTextTokens >= minTokens) {
|
|
415
|
+
block.cache_control = { type: "ephemeral" };
|
|
416
|
+
}
|
|
417
|
+
blocks.push(block);
|
|
418
|
+
}
|
|
419
|
+
for (const s of dynamic) {
|
|
420
|
+
blocks.push({ type: "text", text: s.text });
|
|
421
|
+
}
|
|
422
|
+
return blocks;
|
|
423
|
+
}
|
|
424
|
+
function buildAnthropicMessages(history, currentTurn) {
|
|
425
|
+
const out = [];
|
|
426
|
+
for (const m of history) {
|
|
427
|
+
if (m.role === "system") continue;
|
|
428
|
+
out.push({ role: m.role, content: m.parts ?? m.content });
|
|
429
|
+
}
|
|
430
|
+
if (currentTurn && currentTurn.role !== "system") {
|
|
431
|
+
out.push({ role: currentTurn.role, content: currentTurn.parts ?? currentTurn.content });
|
|
432
|
+
}
|
|
433
|
+
return out;
|
|
434
|
+
}
|
|
435
|
+
function toAnthropicTools(tools) {
|
|
436
|
+
return tools.map((t) => ({
|
|
437
|
+
name: t.name,
|
|
438
|
+
description: t.description ?? "",
|
|
439
|
+
input_schema: t.parameters ?? { type: "object", properties: {} }
|
|
440
|
+
}));
|
|
441
|
+
}
|
|
442
|
+
function computeCacheableTokens(blocks) {
|
|
443
|
+
let total = 0;
|
|
444
|
+
for (const b of blocks) {
|
|
445
|
+
if (b.cache_control) total += countTokens(b.text);
|
|
446
|
+
}
|
|
447
|
+
return total;
|
|
448
|
+
}
|
|
449
|
+
function lowerGoogle(ir, profile, hints) {
|
|
450
|
+
const ordered = sortSections(ir.sections);
|
|
451
|
+
const systemText = ordered.map((s) => s.text).join("\n\n");
|
|
452
|
+
const generationConfig = {};
|
|
453
|
+
if (hints.forceThinkingZero && profile.lowering.thinking) {
|
|
454
|
+
setNestedField(generationConfig, profile.lowering.thinking.field.replace(/^generationConfig\./, ""), 0);
|
|
455
|
+
}
|
|
456
|
+
if (hints.forceTerseOutput) {
|
|
457
|
+
generationConfig.maxOutputTokens = 200;
|
|
458
|
+
}
|
|
459
|
+
if (ir.constraints?.structuredOutput && profile.structuredOutput === "native") {
|
|
460
|
+
generationConfig.responseMimeType = "application/json";
|
|
461
|
+
}
|
|
462
|
+
const contents = buildGoogleContents(ir.history ?? [], ir.currentTurn);
|
|
463
|
+
const tools = ir.tools && ir.tools.length > 0 ? toGoogleTools(ir.tools) : void 0;
|
|
464
|
+
const cacheable = ordered.filter((s) => s.cacheable);
|
|
465
|
+
const cacheableTokens = cacheable.reduce((sum, s) => sum + countTokens(s.text), 0);
|
|
466
|
+
const minTokens = profile.lowering.cache.minTokens ?? 4096;
|
|
467
|
+
const meetsMin = cacheableTokens >= minTokens;
|
|
468
|
+
const cacheSavings = meetsMin ? cacheableTokens / 1e6 * profile.costInputPer1m * (1 - (profile.lowering.cache.discount ?? 0.25)) : 0;
|
|
469
|
+
return {
|
|
470
|
+
request: {
|
|
471
|
+
provider: "google",
|
|
472
|
+
model: profile.id,
|
|
473
|
+
systemInstruction: systemText ? { role: "system", parts: [{ text: systemText }] } : void 0,
|
|
474
|
+
contents,
|
|
475
|
+
tools,
|
|
476
|
+
generationConfig: Object.keys(generationConfig).length > 0 ? generationConfig : void 0
|
|
477
|
+
},
|
|
478
|
+
diagnostics: {
|
|
479
|
+
cacheableTokens: meetsMin ? cacheableTokens : 0,
|
|
480
|
+
estimatedCacheSavingsUsd: cacheSavings
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
function buildGoogleContents(history, currentTurn) {
|
|
485
|
+
const out = [];
|
|
486
|
+
for (const m of history) {
|
|
487
|
+
if (m.role === "system") continue;
|
|
488
|
+
out.push({
|
|
489
|
+
role: m.role === "assistant" ? "model" : m.role,
|
|
490
|
+
parts: m.parts ?? [{ text: m.content }]
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
if (currentTurn && currentTurn.role !== "system") {
|
|
494
|
+
out.push({
|
|
495
|
+
role: currentTurn.role === "assistant" ? "model" : currentTurn.role,
|
|
496
|
+
parts: currentTurn.parts ?? [{ text: currentTurn.content }]
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
return out;
|
|
500
|
+
}
|
|
501
|
+
function toGoogleTools(tools) {
|
|
502
|
+
return [
|
|
503
|
+
{
|
|
504
|
+
functionDeclarations: tools.map((t) => ({
|
|
505
|
+
name: t.name,
|
|
506
|
+
description: t.description ?? "",
|
|
507
|
+
parameters: t.parameters ?? { type: "object", properties: {} }
|
|
508
|
+
}))
|
|
509
|
+
}
|
|
510
|
+
];
|
|
511
|
+
}
|
|
512
|
+
function lowerOpenAI(ir, profile, hints) {
|
|
513
|
+
const ordered = sortSections(ir.sections);
|
|
514
|
+
const systemText = ordered.map((s) => s.text).join("\n\n");
|
|
515
|
+
const systemRole = profile.systemPromptMode === "as_developer" ? "developer" : "system";
|
|
516
|
+
const messages = systemText ? [{ role: systemRole, content: systemText }] : [];
|
|
517
|
+
for (const m of ir.history ?? []) {
|
|
518
|
+
if (m.role === "system") continue;
|
|
519
|
+
messages.push({ role: m.role, content: m.parts ?? m.content });
|
|
520
|
+
}
|
|
521
|
+
if (ir.currentTurn && ir.currentTurn.role !== "system") {
|
|
522
|
+
messages.push({
|
|
523
|
+
role: ir.currentTurn.role,
|
|
524
|
+
content: ir.currentTurn.parts ?? ir.currentTurn.content
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
return {
|
|
528
|
+
request: {
|
|
529
|
+
provider: "openai",
|
|
530
|
+
model: profile.id,
|
|
531
|
+
messages,
|
|
532
|
+
tools: ir.tools && ir.tools.length > 0 ? toOpenAITools(ir.tools) : void 0,
|
|
533
|
+
response_format: ir.constraints?.structuredOutput ? { type: "json_object" } : void 0,
|
|
534
|
+
reasoning_effort: hints.forceTerseOutput ? "low" : void 0
|
|
535
|
+
},
|
|
536
|
+
diagnostics: { cacheableTokens: 0, estimatedCacheSavingsUsd: 0 }
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
function toOpenAITools(tools) {
|
|
540
|
+
return tools.map((t) => ({
|
|
541
|
+
type: "function",
|
|
542
|
+
function: {
|
|
543
|
+
name: t.name,
|
|
544
|
+
description: t.description ?? "",
|
|
545
|
+
parameters: t.parameters ?? { type: "object", properties: {} }
|
|
546
|
+
}
|
|
547
|
+
}));
|
|
548
|
+
}
|
|
549
|
+
function lowerDeepSeek(ir, profile) {
|
|
550
|
+
const ordered = sortSections(ir.sections);
|
|
551
|
+
const systemText = ordered.map((s) => s.text).join("\n\n");
|
|
552
|
+
const messages = systemText ? [{ role: "system", content: systemText }] : [];
|
|
553
|
+
for (const m of ir.history ?? []) {
|
|
554
|
+
if (m.role === "system") continue;
|
|
555
|
+
messages.push({ role: m.role, content: m.parts ?? m.content });
|
|
556
|
+
}
|
|
557
|
+
if (ir.currentTurn && ir.currentTurn.role !== "system") {
|
|
558
|
+
messages.push({
|
|
559
|
+
role: ir.currentTurn.role,
|
|
560
|
+
content: ir.currentTurn.parts ?? ir.currentTurn.content
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
return {
|
|
564
|
+
request: {
|
|
565
|
+
provider: "deepseek",
|
|
566
|
+
model: profile.id,
|
|
567
|
+
messages,
|
|
568
|
+
tools: ir.tools && ir.tools.length > 0 ? ir.tools.slice(0, 1).map((t) => ({
|
|
569
|
+
type: "function",
|
|
570
|
+
function: {
|
|
571
|
+
name: t.name,
|
|
572
|
+
description: t.description ?? "",
|
|
573
|
+
parameters: t.parameters ?? { type: "object", properties: {} }
|
|
574
|
+
}
|
|
575
|
+
})) : void 0
|
|
576
|
+
},
|
|
577
|
+
diagnostics: { cacheableTokens: 0, estimatedCacheSavingsUsd: 0 }
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
function sortSections(sections) {
|
|
581
|
+
return [...sections].sort((a, b) => {
|
|
582
|
+
const wa = a.weight ?? 100;
|
|
583
|
+
const wb = b.weight ?? 100;
|
|
584
|
+
return wa - wb;
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
function setNestedField(obj, path, value) {
|
|
588
|
+
const parts = path.split(".");
|
|
589
|
+
let cursor = obj;
|
|
590
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
591
|
+
const key = parts[i];
|
|
592
|
+
if (!(key in cursor) || typeof cursor[key] !== "object" || cursor[key] === null) {
|
|
593
|
+
cursor[key] = {};
|
|
594
|
+
}
|
|
595
|
+
cursor = cursor[key];
|
|
596
|
+
}
|
|
597
|
+
cursor[parts[parts.length - 1]] = value;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// src/compile.ts
|
|
601
|
+
var counter = 0;
|
|
602
|
+
function makeHandle() {
|
|
603
|
+
counter = (counter + 1) % 1e6;
|
|
604
|
+
return `c${Date.now().toString(36)}-${counter.toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
605
|
+
}
|
|
606
|
+
function compile(ir, opts = {}) {
|
|
607
|
+
const resolver = opts.profileResolver ?? getProfile;
|
|
608
|
+
validateIR(ir);
|
|
609
|
+
const sliced = passSlice(ir);
|
|
610
|
+
const deduped = passDedupe(sliced.value);
|
|
611
|
+
const toolFiltered = passToolRelevance(deduped.value, {
|
|
612
|
+
threshold: opts.toolRelevanceThreshold
|
|
613
|
+
});
|
|
614
|
+
const compressed = passCompressHistory(toolFiltered.value, {
|
|
615
|
+
summarizeOlderThan: opts.compressHistoryAfter
|
|
616
|
+
});
|
|
617
|
+
let workingIR = compressed.value;
|
|
618
|
+
const accumulatedMutations = [
|
|
619
|
+
...sliced.mutations,
|
|
620
|
+
...deduped.mutations,
|
|
621
|
+
...toolFiltered.mutations,
|
|
622
|
+
...compressed.mutations
|
|
623
|
+
];
|
|
624
|
+
const inputTokens = estimateInputTokens(workingIR);
|
|
625
|
+
const scores = passScoreTargets(workingIR, {
|
|
626
|
+
estimatedInputTokens: inputTokens,
|
|
627
|
+
profilesById: resolver,
|
|
628
|
+
policy: opts.policy
|
|
629
|
+
});
|
|
630
|
+
accumulatedMutations.push(...scores.mutations);
|
|
631
|
+
const target = pickTarget(workingIR, scores.value);
|
|
632
|
+
if (!target) {
|
|
633
|
+
throw new Error(
|
|
634
|
+
`compile(): no allowed model fits the request. Scores: ${JSON.stringify(scores.value, null, 2)}`
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
const profile = resolver(target.modelId);
|
|
638
|
+
const fallbackChain = scores.value.filter((s) => s.modelId !== target.modelId && s.fits).sort((a, b) => b.rank - a.rank).map((s) => s.modelId);
|
|
639
|
+
const cliffs = passApplyCliffs(workingIR, profile, inputTokens);
|
|
640
|
+
workingIR = cliffs.value.ir;
|
|
641
|
+
accumulatedMutations.push(...cliffs.mutations);
|
|
642
|
+
const lowered = lower(workingIR, profile, {
|
|
643
|
+
forceThinkingZero: cliffs.value.loweringHints.forceThinkingZero,
|
|
644
|
+
forceTerseOutput: cliffs.value.loweringHints.forceTerseOutput
|
|
645
|
+
});
|
|
646
|
+
validateFinalFit(workingIR, profile, inputTokens);
|
|
647
|
+
const handle = makeHandle();
|
|
648
|
+
const finalShape = computeShape(workingIR, inputTokens);
|
|
649
|
+
const _learningKey = learningKey(ir.intent.archetype, profile.id, finalShape);
|
|
650
|
+
return {
|
|
651
|
+
handle,
|
|
652
|
+
target: profile.id,
|
|
653
|
+
provider: profile.provider,
|
|
654
|
+
request: lowered.request,
|
|
655
|
+
tokensIn: inputTokens,
|
|
656
|
+
estimatedCostUsd: target.estimatedCostUsd,
|
|
657
|
+
mutationsApplied: accumulatedMutations,
|
|
658
|
+
fallbackChain,
|
|
659
|
+
diagnostics: {
|
|
660
|
+
sectionsKept: workingIR.sections.length,
|
|
661
|
+
sectionsDropped: ir.sections.length - workingIR.sections.length,
|
|
662
|
+
toolsKept: workingIR.tools?.length ?? 0,
|
|
663
|
+
toolsDropped: (ir.tools?.length ?? 0) - (workingIR.tools?.length ?? 0),
|
|
664
|
+
historyKept: workingIR.history?.length ?? 0,
|
|
665
|
+
historyDropped: (ir.history?.length ?? 0) - (workingIR.history?.length ?? 0),
|
|
666
|
+
cacheableTokens: lowered.diagnostics.cacheableTokens,
|
|
667
|
+
estimatedCacheSavingsUsd: lowered.diagnostics.estimatedCacheSavingsUsd
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
function validateIR(ir) {
|
|
672
|
+
if (!ir.appId) throw new Error("compile(): ir.appId is required");
|
|
673
|
+
if (!ir.intent || !ir.intent.archetype) {
|
|
674
|
+
throw new Error("compile(): ir.intent.archetype is required (use a dialect-v1 archetype)");
|
|
675
|
+
}
|
|
676
|
+
if (!Array.isArray(ir.models) || ir.models.length === 0) {
|
|
677
|
+
throw new Error("compile(): ir.models must be a non-empty array");
|
|
678
|
+
}
|
|
679
|
+
if (!Array.isArray(ir.sections)) {
|
|
680
|
+
throw new Error("compile(): ir.sections must be an array");
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function pickTarget(ir, scores) {
|
|
684
|
+
if (ir.constraints?.forceModel) {
|
|
685
|
+
const forced = scores.find((s) => s.modelId === ir.constraints.forceModel);
|
|
686
|
+
if (forced && forced.fits) return forced;
|
|
687
|
+
if (forced) {
|
|
688
|
+
throw new Error(
|
|
689
|
+
`compile(): forceModel="${ir.constraints.forceModel}" does not fit: ${forced.rejectReasons.join("; ")}`
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
const fitting = scores.filter((s) => s.fits).sort((a, b) => b.rank - a.rank);
|
|
694
|
+
return fitting[0];
|
|
695
|
+
}
|
|
696
|
+
function validateFinalFit(ir, profile, tokens) {
|
|
697
|
+
if (tokens > profile.maxContextTokens) {
|
|
698
|
+
throw new Error(
|
|
699
|
+
`compile(): final IR is ${tokens} tokens, exceeds ${profile.id} context (${profile.maxContextTokens})`
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
if ((ir.tools?.length ?? 0) > profile.maxTools) {
|
|
703
|
+
throw new Error(
|
|
704
|
+
`compile(): final IR has ${ir.tools?.length} tools, exceeds ${profile.id} maxTools (${profile.maxTools})`
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// src/brain.ts
|
|
710
|
+
var activeConfig;
|
|
711
|
+
function configureBrain(config) {
|
|
712
|
+
const endpoint = config.endpoint.replace(/\/outcomes\/?$/, "");
|
|
713
|
+
activeConfig = { ...config, endpoint };
|
|
714
|
+
}
|
|
715
|
+
function clearBrain() {
|
|
716
|
+
activeConfig = void 0;
|
|
717
|
+
}
|
|
718
|
+
var compileRegistry = /* @__PURE__ */ new Map();
|
|
719
|
+
var REGISTRY_MAX_ENTRIES = 1e4;
|
|
720
|
+
function registerCompile(appId, archetype, ir, result) {
|
|
721
|
+
if (compileRegistry.size >= REGISTRY_MAX_ENTRIES) {
|
|
722
|
+
const cutoff = Math.floor(REGISTRY_MAX_ENTRIES * 0.25);
|
|
723
|
+
let evicted = 0;
|
|
724
|
+
for (const k of compileRegistry.keys()) {
|
|
725
|
+
compileRegistry.delete(k);
|
|
726
|
+
if (++evicted >= cutoff) break;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
const tokens = result.tokensIn;
|
|
730
|
+
const shape = computeShape(
|
|
731
|
+
{
|
|
732
|
+
appId,
|
|
733
|
+
intent: { name: archetype, archetype },
|
|
734
|
+
sections: ir.sections,
|
|
735
|
+
tools: ir.tools,
|
|
736
|
+
history: ir.history,
|
|
737
|
+
models: ir.models,
|
|
738
|
+
constraints: ir.constraints
|
|
739
|
+
},
|
|
740
|
+
tokens
|
|
741
|
+
);
|
|
742
|
+
const shapeKey = `${shape.contextBucket}-${shape.toolCountBucket}-${shape.historyDepth}-${shape.outputMode}`;
|
|
743
|
+
compileRegistry.set(result.handle, {
|
|
744
|
+
appId,
|
|
745
|
+
archetype,
|
|
746
|
+
model: result.target,
|
|
747
|
+
provider: result.provider,
|
|
748
|
+
shapeKey,
|
|
749
|
+
learningKey: learningKey(archetype, result.target, shape),
|
|
750
|
+
estimatedTokensIn: tokens,
|
|
751
|
+
mutationsApplied: result.mutationsApplied.map((m) => m.id),
|
|
752
|
+
startedAt: Date.now()
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
async function record(input) {
|
|
756
|
+
const reg = compileRegistry.get(input.handle);
|
|
757
|
+
if (reg) compileRegistry.delete(input.handle);
|
|
758
|
+
if (!activeConfig) {
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const payload = buildPayload(input, reg);
|
|
762
|
+
const config = activeConfig;
|
|
763
|
+
const fetchFn = config.fetchImpl ?? fetch;
|
|
764
|
+
const send = async () => {
|
|
765
|
+
try {
|
|
766
|
+
const res = await fetchFn(`${config.endpoint}/outcomes`, {
|
|
767
|
+
method: "POST",
|
|
768
|
+
headers: {
|
|
769
|
+
"Content-Type": "application/json",
|
|
770
|
+
...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}
|
|
771
|
+
},
|
|
772
|
+
body: JSON.stringify(payload)
|
|
773
|
+
});
|
|
774
|
+
if (!res.ok) {
|
|
775
|
+
const text = await res.text().catch(() => "<no body>");
|
|
776
|
+
throw new Error(`brain ${res.status}: ${text}`);
|
|
777
|
+
}
|
|
778
|
+
} catch (err) {
|
|
779
|
+
(config.onError ?? defaultOnError)(err);
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
if (config.sync) {
|
|
783
|
+
await send();
|
|
784
|
+
} else {
|
|
785
|
+
void send();
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
function defaultOnError(err) {
|
|
789
|
+
console.warn("[kgauto] brain record failed:", err);
|
|
790
|
+
}
|
|
791
|
+
function buildPayload(input, reg) {
|
|
792
|
+
const compileTarget = reg?.model;
|
|
793
|
+
const actual = input.actualModel ?? compileTarget;
|
|
794
|
+
const requested = input.actualModel && compileTarget && input.actualModel !== compileTarget ? compileTarget : void 0;
|
|
795
|
+
return {
|
|
796
|
+
handle: input.handle,
|
|
797
|
+
app_id: reg?.appId,
|
|
798
|
+
intent_archetype: reg?.archetype,
|
|
799
|
+
model: actual,
|
|
800
|
+
requested_model: requested,
|
|
801
|
+
provider: reg?.provider,
|
|
802
|
+
shape_key: reg?.shapeKey,
|
|
803
|
+
learning_key: reg?.learningKey,
|
|
804
|
+
mutations_applied: reg?.mutationsApplied ?? [],
|
|
805
|
+
tokens_in: input.tokensIn,
|
|
806
|
+
tokens_out: input.tokensOut,
|
|
807
|
+
estimated_tokens_in: reg?.estimatedTokensIn,
|
|
808
|
+
latency_ms: input.latencyMs,
|
|
809
|
+
success: input.success,
|
|
810
|
+
empty_response: input.emptyResponse ?? input.tokensOut === 0,
|
|
811
|
+
error_type: input.errorType,
|
|
812
|
+
tools_called: input.toolsCalled,
|
|
813
|
+
oracle_score: input.oracleScore?.score,
|
|
814
|
+
oracle_dimensions: input.oracleScore?.dimensions,
|
|
815
|
+
oracle_rationale: input.oracleScore?.rationale,
|
|
816
|
+
prompt_preview: input.promptPreview,
|
|
817
|
+
response_preview: input.responsePreview,
|
|
818
|
+
dialect_version: "v1"
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// src/ir.ts
|
|
823
|
+
var CallError = class extends Error {
|
|
824
|
+
attempts;
|
|
825
|
+
lastErrorCode;
|
|
826
|
+
lastStatus;
|
|
827
|
+
constructor(message, attempts, lastStatus, lastErrorCode) {
|
|
828
|
+
super(message);
|
|
829
|
+
this.name = "CallError";
|
|
830
|
+
this.attempts = attempts;
|
|
831
|
+
this.lastStatus = lastStatus;
|
|
832
|
+
this.lastErrorCode = lastErrorCode;
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
// src/execute.ts
|
|
837
|
+
var ANTHROPIC_URL = "https://api.anthropic.com/v1/messages";
|
|
838
|
+
var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
|
|
839
|
+
var DEEPSEEK_URL = "https://api.deepseek.com/chat/completions";
|
|
840
|
+
async function execute(request, opts = {}) {
|
|
841
|
+
const merged = applyOverrides(request, opts.providerOverrides);
|
|
842
|
+
switch (merged.provider) {
|
|
843
|
+
case "anthropic":
|
|
844
|
+
return executeAnthropic(merged, opts);
|
|
845
|
+
case "google":
|
|
846
|
+
return executeGoogle(merged, opts);
|
|
847
|
+
case "openai":
|
|
848
|
+
return executeOpenAI(merged, opts);
|
|
849
|
+
case "deepseek":
|
|
850
|
+
return executeDeepSeek(merged, opts);
|
|
851
|
+
default: {
|
|
852
|
+
const _exhaustive = merged;
|
|
853
|
+
throw new Error(`execute(): no executor for provider: ${JSON.stringify(_exhaustive)}`);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
async function executeAnthropic(request, opts) {
|
|
858
|
+
const apiKey = opts.apiKeys?.anthropic ?? process.env.ANTHROPIC_API_KEY;
|
|
859
|
+
if (!apiKey) {
|
|
860
|
+
return terminalError(401, "auth", "ANTHROPIC_API_KEY missing");
|
|
861
|
+
}
|
|
862
|
+
const { provider: _provider, ...body } = request;
|
|
863
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
864
|
+
let res;
|
|
865
|
+
let json;
|
|
866
|
+
try {
|
|
867
|
+
res = await fetchFn(ANTHROPIC_URL, {
|
|
868
|
+
method: "POST",
|
|
869
|
+
headers: {
|
|
870
|
+
"x-api-key": apiKey,
|
|
871
|
+
"anthropic-version": "2023-06-01",
|
|
872
|
+
"content-type": "application/json"
|
|
873
|
+
},
|
|
874
|
+
body: JSON.stringify(body)
|
|
875
|
+
});
|
|
876
|
+
json = await res.json().catch(() => ({}));
|
|
877
|
+
} catch (err) {
|
|
878
|
+
return retryableError(0, "network_error", String(err), null);
|
|
879
|
+
}
|
|
880
|
+
if (!res.ok) return classifyHttpError(res.status, json);
|
|
881
|
+
return { ok: true, status: res.status, response: normalizeAnthropic(json) };
|
|
882
|
+
}
|
|
883
|
+
function normalizeAnthropic(raw) {
|
|
884
|
+
const r = raw;
|
|
885
|
+
const text = (r.content ?? []).filter((b) => b.type === "text" && typeof b.text === "string").map((b) => b.text).join("");
|
|
886
|
+
const toolCalls = (r.content ?? []).filter((b) => b.type === "tool_use" && b.name && b.id).map((b) => ({ id: b.id, name: b.name, args: b.input ?? {} }));
|
|
887
|
+
const tokens = {
|
|
888
|
+
input: r.usage?.input_tokens ?? 0,
|
|
889
|
+
output: r.usage?.output_tokens ?? 0,
|
|
890
|
+
total: (r.usage?.input_tokens ?? 0) + (r.usage?.output_tokens ?? 0),
|
|
891
|
+
cached: r.usage?.cache_read_input_tokens,
|
|
892
|
+
cacheCreated: r.usage?.cache_creation_input_tokens
|
|
893
|
+
};
|
|
894
|
+
return { text, structuredOutput: null, toolCalls, tokens, finishReason: r.stop_reason, raw };
|
|
895
|
+
}
|
|
896
|
+
async function executeGoogle(request, opts) {
|
|
897
|
+
const apiKey = opts.apiKeys?.google ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
|
|
898
|
+
if (!apiKey) {
|
|
899
|
+
return terminalError(401, "auth", "GOOGLE_API_KEY/GEMINI_API_KEY missing");
|
|
900
|
+
}
|
|
901
|
+
const { provider: _provider, model, ...body } = request;
|
|
902
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model)}:generateContent?key=${encodeURIComponent(apiKey)}`;
|
|
903
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
904
|
+
let res;
|
|
905
|
+
let json;
|
|
906
|
+
try {
|
|
907
|
+
res = await fetchFn(url, {
|
|
908
|
+
method: "POST",
|
|
909
|
+
headers: { "content-type": "application/json" },
|
|
910
|
+
body: JSON.stringify(body)
|
|
911
|
+
});
|
|
912
|
+
json = await res.json().catch(() => ({}));
|
|
913
|
+
} catch (err) {
|
|
914
|
+
return retryableError(0, "network_error", String(err), null);
|
|
915
|
+
}
|
|
916
|
+
if (!res.ok) return classifyHttpError(res.status, json);
|
|
917
|
+
return { ok: true, status: res.status, response: normalizeGoogle(json) };
|
|
918
|
+
}
|
|
919
|
+
function normalizeGoogle(raw) {
|
|
920
|
+
const r = raw;
|
|
921
|
+
const candidate = r.candidates?.[0];
|
|
922
|
+
const parts = candidate?.content?.parts ?? [];
|
|
923
|
+
const text = parts.filter((p) => typeof p.text === "string").map((p) => p.text).join("");
|
|
924
|
+
const toolCalls = parts.filter((p) => p.functionCall?.name).map((p, i) => ({
|
|
925
|
+
id: `gemini-call-${i}`,
|
|
926
|
+
name: p.functionCall.name,
|
|
927
|
+
args: p.functionCall.args ?? {}
|
|
928
|
+
}));
|
|
929
|
+
const u = r.usageMetadata ?? {};
|
|
930
|
+
const tokens = {
|
|
931
|
+
input: u.promptTokenCount ?? 0,
|
|
932
|
+
output: u.candidatesTokenCount ?? 0,
|
|
933
|
+
total: u.totalTokenCount ?? (u.promptTokenCount ?? 0) + (u.candidatesTokenCount ?? 0),
|
|
934
|
+
cached: u.cachedContentTokenCount
|
|
935
|
+
};
|
|
936
|
+
return { text, structuredOutput: null, toolCalls, tokens, finishReason: candidate?.finishReason, raw };
|
|
937
|
+
}
|
|
938
|
+
async function executeOpenAI(request, opts) {
|
|
939
|
+
const apiKey = opts.apiKeys?.openai ?? process.env.OPENAI_API_KEY;
|
|
940
|
+
if (!apiKey) {
|
|
941
|
+
return terminalError(401, "auth", "OPENAI_API_KEY missing");
|
|
942
|
+
}
|
|
943
|
+
const { provider: _provider, ...body } = request;
|
|
944
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
945
|
+
let res;
|
|
946
|
+
let json;
|
|
947
|
+
try {
|
|
948
|
+
res = await fetchFn(OPENAI_URL, {
|
|
949
|
+
method: "POST",
|
|
950
|
+
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
951
|
+
body: JSON.stringify(body)
|
|
952
|
+
});
|
|
953
|
+
json = await res.json().catch(() => ({}));
|
|
954
|
+
} catch (err) {
|
|
955
|
+
return retryableError(0, "network_error", String(err), null);
|
|
956
|
+
}
|
|
957
|
+
if (!res.ok) return classifyHttpError(res.status, json);
|
|
958
|
+
return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
|
|
959
|
+
}
|
|
960
|
+
async function executeDeepSeek(request, opts) {
|
|
961
|
+
const apiKey = opts.apiKeys?.deepseek ?? process.env.DEEPSEEK_API_KEY;
|
|
962
|
+
if (!apiKey) {
|
|
963
|
+
return terminalError(401, "auth", "DEEPSEEK_API_KEY missing");
|
|
964
|
+
}
|
|
965
|
+
const { provider: _provider, ...body } = request;
|
|
966
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
967
|
+
let res;
|
|
968
|
+
let json;
|
|
969
|
+
try {
|
|
970
|
+
res = await fetchFn(DEEPSEEK_URL, {
|
|
971
|
+
method: "POST",
|
|
972
|
+
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
973
|
+
body: JSON.stringify(body)
|
|
974
|
+
});
|
|
975
|
+
json = await res.json().catch(() => ({}));
|
|
976
|
+
} catch (err) {
|
|
977
|
+
return retryableError(0, "network_error", String(err), null);
|
|
978
|
+
}
|
|
979
|
+
if (!res.ok) return classifyHttpError(res.status, json);
|
|
980
|
+
return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
|
|
981
|
+
}
|
|
982
|
+
function normalizeOpenAILike(raw) {
|
|
983
|
+
const r = raw;
|
|
984
|
+
const choice = r.choices?.[0];
|
|
985
|
+
const text = choice?.message?.content ?? "";
|
|
986
|
+
const toolCalls = (choice?.message?.tool_calls ?? []).filter((tc) => tc.function?.name).map((tc, i) => ({
|
|
987
|
+
id: tc.id ?? `tc-${i}`,
|
|
988
|
+
name: tc.function.name,
|
|
989
|
+
args: tryParseJson(tc.function?.arguments) ?? {}
|
|
990
|
+
}));
|
|
991
|
+
const u = r.usage ?? {};
|
|
992
|
+
const tokens = {
|
|
993
|
+
input: u.prompt_tokens ?? 0,
|
|
994
|
+
output: u.completion_tokens ?? 0,
|
|
995
|
+
total: u.total_tokens ?? (u.prompt_tokens ?? 0) + (u.completion_tokens ?? 0),
|
|
996
|
+
cached: u.prompt_tokens_details?.cached_tokens
|
|
997
|
+
};
|
|
998
|
+
return { text, structuredOutput: null, toolCalls, tokens, finishReason: choice?.finish_reason, raw };
|
|
999
|
+
}
|
|
1000
|
+
function applyOverrides(request, overrides) {
|
|
1001
|
+
if (!overrides) return request;
|
|
1002
|
+
const layer = overrides[request.provider];
|
|
1003
|
+
if (!layer) return request;
|
|
1004
|
+
return { ...request, ...layer };
|
|
1005
|
+
}
|
|
1006
|
+
function classifyHttpError(status, body) {
|
|
1007
|
+
const message = extractErrorMessage(body) ?? `HTTP ${status}`;
|
|
1008
|
+
if (status === 429) {
|
|
1009
|
+
return { ok: false, status, errorType: "retryable", errorCode: "rate_limit", message, raw: body };
|
|
1010
|
+
}
|
|
1011
|
+
if (status === 408) {
|
|
1012
|
+
return { ok: false, status, errorType: "retryable", errorCode: "timeout", message, raw: body };
|
|
1013
|
+
}
|
|
1014
|
+
if (status >= 500) {
|
|
1015
|
+
return { ok: false, status, errorType: "retryable", errorCode: "server_error", message, raw: body };
|
|
1016
|
+
}
|
|
1017
|
+
if (status === 404) {
|
|
1018
|
+
return { ok: false, status, errorType: "retryable", errorCode: "model_not_found", message, raw: body };
|
|
1019
|
+
}
|
|
1020
|
+
if (status === 401 || status === 403) {
|
|
1021
|
+
return { ok: false, status, errorType: "terminal", errorCode: "auth", message, raw: body };
|
|
1022
|
+
}
|
|
1023
|
+
if (status === 400) {
|
|
1024
|
+
return { ok: false, status, errorType: "terminal", errorCode: "invalid_request", message, raw: body };
|
|
1025
|
+
}
|
|
1026
|
+
return { ok: false, status, errorType: "terminal", errorCode: "unknown", message, raw: body };
|
|
1027
|
+
}
|
|
1028
|
+
function extractErrorMessage(body) {
|
|
1029
|
+
if (!body || typeof body !== "object") return void 0;
|
|
1030
|
+
const b = body;
|
|
1031
|
+
if (b.error && typeof b.error === "object") {
|
|
1032
|
+
const e = b.error;
|
|
1033
|
+
if (typeof e.message === "string") return e.message;
|
|
1034
|
+
}
|
|
1035
|
+
if (typeof b.message === "string") return b.message;
|
|
1036
|
+
return void 0;
|
|
1037
|
+
}
|
|
1038
|
+
function terminalError(status, code, message) {
|
|
1039
|
+
return { ok: false, status, errorType: "terminal", errorCode: code, message, raw: null };
|
|
1040
|
+
}
|
|
1041
|
+
function retryableError(status, code, message, raw) {
|
|
1042
|
+
return { ok: false, status, errorType: "retryable", errorCode: code, message, raw };
|
|
1043
|
+
}
|
|
1044
|
+
function tryParseJson(s) {
|
|
1045
|
+
if (typeof s !== "string" || s.length === 0) return void 0;
|
|
1046
|
+
try {
|
|
1047
|
+
const parsed = JSON.parse(s);
|
|
1048
|
+
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
1049
|
+
} catch {
|
|
1050
|
+
return void 0;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// src/call.ts
|
|
1055
|
+
async function call(ir, opts = {}) {
|
|
1056
|
+
const initial = compileAndRegister(ir, opts);
|
|
1057
|
+
const start = Date.now();
|
|
1058
|
+
const attempts = [];
|
|
1059
|
+
const targetsToTry = [initial.target, ...initial.fallbackChain];
|
|
1060
|
+
let activeCompile = initial;
|
|
1061
|
+
let lastErr;
|
|
1062
|
+
for (let i = 0; i < targetsToTry.length; i++) {
|
|
1063
|
+
const targetModel = targetsToTry[i];
|
|
1064
|
+
if (i > 0) {
|
|
1065
|
+
try {
|
|
1066
|
+
activeCompile = compileAndRegister(
|
|
1067
|
+
{
|
|
1068
|
+
...ir,
|
|
1069
|
+
models: ir.models.includes(targetModel) ? ir.models : [targetModel, ...ir.models],
|
|
1070
|
+
constraints: { ...ir.constraints ?? {}, forceModel: targetModel }
|
|
1071
|
+
},
|
|
1072
|
+
opts
|
|
1073
|
+
);
|
|
1074
|
+
} catch (err) {
|
|
1075
|
+
attempts.push({
|
|
1076
|
+
model: targetModel,
|
|
1077
|
+
status: "terminal",
|
|
1078
|
+
errorCode: "compile_error",
|
|
1079
|
+
message: err instanceof Error ? err.message : String(err)
|
|
1080
|
+
});
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
const exec = await execute(activeCompile.request, {
|
|
1085
|
+
apiKeys: opts.apiKeys,
|
|
1086
|
+
fetchImpl: opts.fetchImpl,
|
|
1087
|
+
providerOverrides: opts.providerOverrides
|
|
1088
|
+
});
|
|
1089
|
+
if (exec.ok) {
|
|
1090
|
+
attempts.push({ model: targetModel, status: "success" });
|
|
1091
|
+
const latencyMs2 = Date.now() - start;
|
|
1092
|
+
const responseWithStructured = withStructuredOutput(exec.response, ir);
|
|
1093
|
+
void record({
|
|
1094
|
+
handle: initial.handle,
|
|
1095
|
+
tokensIn: responseWithStructured.tokens.input,
|
|
1096
|
+
tokensOut: responseWithStructured.tokens.output,
|
|
1097
|
+
latencyMs: latencyMs2,
|
|
1098
|
+
success: true,
|
|
1099
|
+
emptyResponse: responseWithStructured.tokens.output === 0,
|
|
1100
|
+
toolsCalled: responseWithStructured.toolCalls.map((tc) => tc.name),
|
|
1101
|
+
actualModel: targetModel !== initial.target ? targetModel : void 0,
|
|
1102
|
+
responsePreview: responseWithStructured.text.slice(0, 200)
|
|
1103
|
+
});
|
|
1104
|
+
return {
|
|
1105
|
+
handle: initial.handle,
|
|
1106
|
+
actualModel: targetModel,
|
|
1107
|
+
requestedModel: initial.target,
|
|
1108
|
+
provider: activeCompile.provider,
|
|
1109
|
+
response: responseWithStructured,
|
|
1110
|
+
latencyMs: latencyMs2,
|
|
1111
|
+
mutationsApplied: activeCompile.mutationsApplied,
|
|
1112
|
+
attempts
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
attempts.push({
|
|
1116
|
+
model: targetModel,
|
|
1117
|
+
status: exec.errorType,
|
|
1118
|
+
errorCode: exec.errorCode,
|
|
1119
|
+
message: exec.message
|
|
1120
|
+
});
|
|
1121
|
+
lastErr = exec;
|
|
1122
|
+
if (exec.errorType === "terminal" || opts.noFallback) {
|
|
1123
|
+
break;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
const latencyMs = Date.now() - start;
|
|
1127
|
+
void record({
|
|
1128
|
+
handle: initial.handle,
|
|
1129
|
+
tokensIn: 0,
|
|
1130
|
+
tokensOut: 0,
|
|
1131
|
+
latencyMs,
|
|
1132
|
+
success: false,
|
|
1133
|
+
errorType: lastErr?.errorCode
|
|
1134
|
+
});
|
|
1135
|
+
throw new CallError(
|
|
1136
|
+
`call(): all attempts failed${lastErr ? ` \u2014 ${lastErr.errorCode}: ${lastErr.message}` : ""}`,
|
|
1137
|
+
attempts,
|
|
1138
|
+
lastErr?.status,
|
|
1139
|
+
lastErr?.errorCode
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1142
|
+
function compileAndRegister(ir, opts) {
|
|
1143
|
+
const result = compile(ir, {
|
|
1144
|
+
policy: opts.policy,
|
|
1145
|
+
toolRelevanceThreshold: opts.toolRelevanceThreshold,
|
|
1146
|
+
compressHistoryAfter: opts.compressHistoryAfter
|
|
1147
|
+
});
|
|
1148
|
+
registerCompile(ir.appId, ir.intent.archetype, ir, result);
|
|
1149
|
+
return result;
|
|
1150
|
+
}
|
|
1151
|
+
function withStructuredOutput(response, ir) {
|
|
1152
|
+
if (!ir.constraints?.structuredOutput) return response;
|
|
1153
|
+
if (!response.text) return response;
|
|
1154
|
+
try {
|
|
1155
|
+
const parsed = JSON.parse(response.text);
|
|
1156
|
+
return { ...response, structuredOutput: parsed };
|
|
1157
|
+
} catch (err) {
|
|
1158
|
+
return {
|
|
1159
|
+
...response,
|
|
1160
|
+
structuredOutput: null,
|
|
1161
|
+
parseError: err instanceof Error ? err.message : String(err)
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// src/oracle.ts
|
|
1167
|
+
var DEFAULT_DIMENSIONS = ["correctness", "completeness", "conciseness", "format"];
|
|
1168
|
+
var judgeCallTimes = [];
|
|
1169
|
+
function buildLLMJudge(opts) {
|
|
1170
|
+
const dimensions = opts.dimensions ?? DEFAULT_DIMENSIONS;
|
|
1171
|
+
const rateLimit = opts.rateLimitPerMin;
|
|
1172
|
+
return async (ctx) => {
|
|
1173
|
+
if (rateLimit) {
|
|
1174
|
+
const now = Date.now();
|
|
1175
|
+
judgeCallTimes = judgeCallTimes.filter((t) => now - t < 6e4);
|
|
1176
|
+
if (judgeCallTimes.length >= rateLimit) {
|
|
1177
|
+
return { score: 0.5, rationale: "judge rate-limited; default neutral" };
|
|
1178
|
+
}
|
|
1179
|
+
judgeCallTimes.push(now);
|
|
1180
|
+
}
|
|
1181
|
+
const prompt = buildJudgePrompt(ctx, dimensions);
|
|
1182
|
+
let raw;
|
|
1183
|
+
try {
|
|
1184
|
+
raw = await opts.judgeCall(prompt);
|
|
1185
|
+
} catch (err) {
|
|
1186
|
+
return {
|
|
1187
|
+
score: 0.5,
|
|
1188
|
+
rationale: `judge error: ${err instanceof Error ? err.message : String(err)}`
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
return parseJudgeOutput(raw, dimensions);
|
|
1192
|
+
};
|
|
1193
|
+
}
|
|
1194
|
+
function buildJudgePrompt(ctx, dimensions) {
|
|
1195
|
+
return `You are an oracle scoring an AI response. Output ONLY a JSON object, no other text.
|
|
1196
|
+
|
|
1197
|
+
Intent archetype: ${ctx.archetype}
|
|
1198
|
+
App: ${ctx.appId} / ${ctx.intentName}
|
|
1199
|
+
Tools were involved: ${ctx.hadTools}
|
|
1200
|
+
|
|
1201
|
+
User asked:
|
|
1202
|
+
${ctx.userTurn ?? "<not provided>"}
|
|
1203
|
+
|
|
1204
|
+
Response:
|
|
1205
|
+
${ctx.response.slice(0, 4e3)}
|
|
1206
|
+
|
|
1207
|
+
Score from 0.0 to 1.0 on each dimension. 1.0 = perfect, 0.5 = mediocre, 0.0 = wrong.
|
|
1208
|
+
Be honest \u2014 most responses are 0.5-0.8. Reserve 0.9+ for genuinely excellent.
|
|
1209
|
+
|
|
1210
|
+
Respond with this JSON shape:
|
|
1211
|
+
{
|
|
1212
|
+
"score": <overall 0..1>,
|
|
1213
|
+
"dimensions": { ${dimensions.map((d) => `"${d}": <0..1>`).join(", ")} },
|
|
1214
|
+
"rationale": "<one sentence>"
|
|
1215
|
+
}`;
|
|
1216
|
+
}
|
|
1217
|
+
function parseJudgeOutput(raw, dimensions) {
|
|
1218
|
+
const cleaned = raw.replace(/^```(?:json)?\s*/i, "").replace(/\s*```\s*$/, "").trim();
|
|
1219
|
+
let parsed;
|
|
1220
|
+
try {
|
|
1221
|
+
parsed = JSON.parse(cleaned);
|
|
1222
|
+
} catch {
|
|
1223
|
+
const match = cleaned.match(/\{[\s\S]*\}/);
|
|
1224
|
+
if (match) {
|
|
1225
|
+
try {
|
|
1226
|
+
parsed = JSON.parse(match[0]);
|
|
1227
|
+
} catch {
|
|
1228
|
+
return { score: 0.5, rationale: "judge output unparseable" };
|
|
1229
|
+
}
|
|
1230
|
+
} else {
|
|
1231
|
+
return { score: 0.5, rationale: "judge output unparseable" };
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1235
|
+
return { score: 0.5, rationale: "judge output not an object" };
|
|
1236
|
+
}
|
|
1237
|
+
const obj = parsed;
|
|
1238
|
+
const score = clamp(typeof obj.score === "number" ? obj.score : 0.5);
|
|
1239
|
+
const dims = {};
|
|
1240
|
+
if (obj.dimensions && typeof obj.dimensions === "object") {
|
|
1241
|
+
for (const d of dimensions) {
|
|
1242
|
+
const v = obj.dimensions[d];
|
|
1243
|
+
dims[d] = clamp(typeof v === "number" ? v : 0.5);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
const rationale = typeof obj.rationale === "string" ? obj.rationale : void 0;
|
|
1247
|
+
return { score, dimensions: Object.keys(dims).length > 0 ? dims : void 0, rationale };
|
|
1248
|
+
}
|
|
1249
|
+
function clamp(n) {
|
|
1250
|
+
if (!Number.isFinite(n)) return 0.5;
|
|
1251
|
+
return Math.max(0, Math.min(1, n));
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// src/index.ts
|
|
1255
|
+
function compile2(ir, opts) {
|
|
1256
|
+
const result = compile(ir, opts);
|
|
1257
|
+
registerCompile(ir.appId, ir.intent.archetype, ir, result);
|
|
1258
|
+
return result;
|
|
1259
|
+
}
|
|
1260
|
+
export {
|
|
1261
|
+
ALIASES,
|
|
1262
|
+
ALL_ARCHETYPES,
|
|
1263
|
+
CallError,
|
|
1264
|
+
DIALECT_VERSION,
|
|
1265
|
+
INTENT_ARCHETYPES,
|
|
1266
|
+
allProfiles,
|
|
1267
|
+
bucketContext,
|
|
1268
|
+
bucketHistory,
|
|
1269
|
+
bucketToolCount,
|
|
1270
|
+
buildLLMJudge,
|
|
1271
|
+
call,
|
|
1272
|
+
clearBrain,
|
|
1273
|
+
compile2 as compile,
|
|
1274
|
+
configureBrain,
|
|
1275
|
+
countTokens,
|
|
1276
|
+
execute,
|
|
1277
|
+
getProfile,
|
|
1278
|
+
hashShape,
|
|
1279
|
+
isArchetype,
|
|
1280
|
+
learningKey,
|
|
1281
|
+
profilesByProvider,
|
|
1282
|
+
record,
|
|
1283
|
+
resetTokenizer,
|
|
1284
|
+
setTokenizer,
|
|
1285
|
+
tryGetProfile
|
|
1286
|
+
};
|