@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/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
+ };