@warmdrift/kgauto-compiler 2.0.0-alpha.16 → 2.0.0-alpha.17
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/chunk-NUTC7NUC.mjs +298 -0
- package/dist/glassbox/index.d.mts +159 -0
- package/dist/glassbox/index.d.ts +159 -0
- package/dist/glassbox/index.js +300 -0
- package/dist/glassbox/index.mjs +20 -0
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +357 -2
- package/dist/index.mjs +77 -2
- package/dist/{profiles-BoLYdl7F.d.mts → ir-C3P4gDt0.d.mts} +13 -134
- package/dist/{profiles-CVB2_5C8.d.ts → ir-CFHU3BUT.d.ts} +13 -134
- package/dist/profiles.d.mts +137 -2
- package/dist/profiles.d.ts +137 -2
- package/package.json +7 -2
package/dist/index.js
CHANGED
|
@@ -2925,9 +2925,321 @@ function ensureCrossProviderTail(opts) {
|
|
|
2925
2925
|
return { chain };
|
|
2926
2926
|
}
|
|
2927
2927
|
|
|
2928
|
+
// src/glassbox/types.ts
|
|
2929
|
+
var GLASSBOX_STREAM_TTL_MS = 6e4;
|
|
2930
|
+
|
|
2931
|
+
// src/glassbox/pubsub-memory.ts
|
|
2932
|
+
var MemoryPubSub = class {
|
|
2933
|
+
subscribers = /* @__PURE__ */ new Map();
|
|
2934
|
+
async publish(traceId, event) {
|
|
2935
|
+
const subs = this.subscribers.get(traceId);
|
|
2936
|
+
if (!subs || subs.size === 0) return;
|
|
2937
|
+
for (const sub of subs) {
|
|
2938
|
+
if (sub.closed) continue;
|
|
2939
|
+
try {
|
|
2940
|
+
sub.controller.enqueue(event);
|
|
2941
|
+
} catch {
|
|
2942
|
+
sub.closed = true;
|
|
2943
|
+
continue;
|
|
2944
|
+
}
|
|
2945
|
+
this.refreshTtl(traceId, sub);
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
subscribe(traceId) {
|
|
2949
|
+
const self = this;
|
|
2950
|
+
let sub;
|
|
2951
|
+
return new ReadableStream({
|
|
2952
|
+
start(controller) {
|
|
2953
|
+
sub = {
|
|
2954
|
+
controller,
|
|
2955
|
+
ttlTimer: setTimeout(() => {
|
|
2956
|
+
self.closeSubscriber(traceId, sub);
|
|
2957
|
+
}, GLASSBOX_STREAM_TTL_MS),
|
|
2958
|
+
closed: false
|
|
2959
|
+
};
|
|
2960
|
+
let set = self.subscribers.get(traceId);
|
|
2961
|
+
if (!set) {
|
|
2962
|
+
set = /* @__PURE__ */ new Set();
|
|
2963
|
+
self.subscribers.set(traceId, set);
|
|
2964
|
+
}
|
|
2965
|
+
set.add(sub);
|
|
2966
|
+
},
|
|
2967
|
+
cancel() {
|
|
2968
|
+
if (sub) self.removeSubscriber(traceId, sub);
|
|
2969
|
+
}
|
|
2970
|
+
});
|
|
2971
|
+
}
|
|
2972
|
+
/**
|
|
2973
|
+
* Refresh the rolling TTL for a subscriber after an event lands. Replaces
|
|
2974
|
+
* the existing timer with a fresh 60s one.
|
|
2975
|
+
*/
|
|
2976
|
+
refreshTtl(traceId, sub) {
|
|
2977
|
+
clearTimeout(sub.ttlTimer);
|
|
2978
|
+
sub.ttlTimer = setTimeout(() => {
|
|
2979
|
+
this.closeSubscriber(traceId, sub);
|
|
2980
|
+
}, GLASSBOX_STREAM_TTL_MS);
|
|
2981
|
+
}
|
|
2982
|
+
/**
|
|
2983
|
+
* Close the subscriber's stream cleanly and remove from the fan-out set.
|
|
2984
|
+
* Idempotent — safe to call multiple times.
|
|
2985
|
+
*/
|
|
2986
|
+
closeSubscriber(traceId, sub) {
|
|
2987
|
+
if (sub.closed) return;
|
|
2988
|
+
sub.closed = true;
|
|
2989
|
+
clearTimeout(sub.ttlTimer);
|
|
2990
|
+
try {
|
|
2991
|
+
sub.controller.close();
|
|
2992
|
+
} catch {
|
|
2993
|
+
}
|
|
2994
|
+
this.removeSubscriber(traceId, sub);
|
|
2995
|
+
}
|
|
2996
|
+
removeSubscriber(traceId, sub) {
|
|
2997
|
+
clearTimeout(sub.ttlTimer);
|
|
2998
|
+
const set = this.subscribers.get(traceId);
|
|
2999
|
+
if (!set) return;
|
|
3000
|
+
set.delete(sub);
|
|
3001
|
+
if (set.size === 0) this.subscribers.delete(traceId);
|
|
3002
|
+
}
|
|
3003
|
+
/**
|
|
3004
|
+
* Test-only reset. Tears down all subscribers, clears all state. Calling
|
|
3005
|
+
* outside of tests is harmless but cancels every active stream.
|
|
3006
|
+
*/
|
|
3007
|
+
_reset() {
|
|
3008
|
+
for (const [, set] of this.subscribers) {
|
|
3009
|
+
for (const sub of set) {
|
|
3010
|
+
this.closeSubscriber("", sub);
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
this.subscribers.clear();
|
|
3014
|
+
}
|
|
3015
|
+
};
|
|
3016
|
+
|
|
3017
|
+
// src/glassbox/pubsub-upstash.ts
|
|
3018
|
+
var UpstashPubSub = class {
|
|
3019
|
+
url;
|
|
3020
|
+
token;
|
|
3021
|
+
fetchImpl;
|
|
3022
|
+
blockMs;
|
|
3023
|
+
maxLen;
|
|
3024
|
+
constructor(cfg) {
|
|
3025
|
+
this.url = cfg.url.replace(/\/$/, "");
|
|
3026
|
+
this.token = cfg.token;
|
|
3027
|
+
this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
3028
|
+
this.blockMs = cfg.blockMs ?? 100;
|
|
3029
|
+
this.maxLen = cfg.maxLen ?? 100;
|
|
3030
|
+
}
|
|
3031
|
+
async publish(traceId, event) {
|
|
3032
|
+
const key = streamKey(traceId);
|
|
3033
|
+
const payload = JSON.stringify(event);
|
|
3034
|
+
await this.cmd([
|
|
3035
|
+
"XADD",
|
|
3036
|
+
key,
|
|
3037
|
+
"MAXLEN",
|
|
3038
|
+
"~",
|
|
3039
|
+
String(this.maxLen),
|
|
3040
|
+
"*",
|
|
3041
|
+
"event",
|
|
3042
|
+
payload
|
|
3043
|
+
]);
|
|
3044
|
+
await this.cmd(["EXPIRE", key, String(Math.ceil(GLASSBOX_STREAM_TTL_MS / 1e3))]);
|
|
3045
|
+
}
|
|
3046
|
+
subscribe(traceId) {
|
|
3047
|
+
const key = streamKey(traceId);
|
|
3048
|
+
const self = this;
|
|
3049
|
+
let cursor = "$";
|
|
3050
|
+
let cancelled = false;
|
|
3051
|
+
let ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
|
|
3052
|
+
return new ReadableStream({
|
|
3053
|
+
async start(controller) {
|
|
3054
|
+
try {
|
|
3055
|
+
while (!cancelled && Date.now() < ttlDeadline) {
|
|
3056
|
+
const resp = await self.cmd([
|
|
3057
|
+
"XREAD",
|
|
3058
|
+
"BLOCK",
|
|
3059
|
+
String(self.blockMs),
|
|
3060
|
+
"STREAMS",
|
|
3061
|
+
key,
|
|
3062
|
+
cursor
|
|
3063
|
+
]);
|
|
3064
|
+
if (cancelled) break;
|
|
3065
|
+
const parsed = parseXReadResult(resp.result);
|
|
3066
|
+
if (parsed.entries.length === 0) {
|
|
3067
|
+
continue;
|
|
3068
|
+
}
|
|
3069
|
+
for (const entry of parsed.entries) {
|
|
3070
|
+
const evt = decodeEvent(entry.fields);
|
|
3071
|
+
if (evt) {
|
|
3072
|
+
try {
|
|
3073
|
+
controller.enqueue(evt);
|
|
3074
|
+
} catch {
|
|
3075
|
+
cancelled = true;
|
|
3076
|
+
break;
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
cursor = entry.id;
|
|
3080
|
+
}
|
|
3081
|
+
ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
|
|
3082
|
+
}
|
|
3083
|
+
} catch (err) {
|
|
3084
|
+
if (!cancelled) {
|
|
3085
|
+
try {
|
|
3086
|
+
controller.error(err);
|
|
3087
|
+
} catch {
|
|
3088
|
+
}
|
|
3089
|
+
return;
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
try {
|
|
3093
|
+
controller.close();
|
|
3094
|
+
} catch {
|
|
3095
|
+
}
|
|
3096
|
+
},
|
|
3097
|
+
cancel() {
|
|
3098
|
+
cancelled = true;
|
|
3099
|
+
}
|
|
3100
|
+
});
|
|
3101
|
+
}
|
|
3102
|
+
async cmd(args) {
|
|
3103
|
+
const res = await this.fetchImpl(this.url, {
|
|
3104
|
+
method: "POST",
|
|
3105
|
+
headers: {
|
|
3106
|
+
Authorization: `Bearer ${this.token}`,
|
|
3107
|
+
"Content-Type": "application/json"
|
|
3108
|
+
},
|
|
3109
|
+
body: JSON.stringify(args)
|
|
3110
|
+
});
|
|
3111
|
+
if (!res.ok) {
|
|
3112
|
+
throw new Error(`Upstash ${args[0]} failed: HTTP ${res.status}`);
|
|
3113
|
+
}
|
|
3114
|
+
const json = await res.json();
|
|
3115
|
+
if (json.error) {
|
|
3116
|
+
throw new Error(`Upstash ${args[0]} failed: ${json.error}`);
|
|
3117
|
+
}
|
|
3118
|
+
return json;
|
|
3119
|
+
}
|
|
3120
|
+
};
|
|
3121
|
+
function streamKey(traceId) {
|
|
3122
|
+
return `glassbox:trace:${traceId}`;
|
|
3123
|
+
}
|
|
3124
|
+
function decodeEvent(fields) {
|
|
3125
|
+
const raw = fields["event"];
|
|
3126
|
+
if (!raw) return void 0;
|
|
3127
|
+
try {
|
|
3128
|
+
const parsed = JSON.parse(raw);
|
|
3129
|
+
if (typeof parsed.kind === "string" && typeof parsed.at === "number") {
|
|
3130
|
+
return parsed;
|
|
3131
|
+
}
|
|
3132
|
+
return void 0;
|
|
3133
|
+
} catch {
|
|
3134
|
+
return void 0;
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
function parseXReadResult(raw) {
|
|
3138
|
+
if (!Array.isArray(raw)) return { entries: [] };
|
|
3139
|
+
const entries = [];
|
|
3140
|
+
for (const stream of raw) {
|
|
3141
|
+
if (!Array.isArray(stream) || stream.length < 2) continue;
|
|
3142
|
+
const streamEntries = stream[1];
|
|
3143
|
+
if (!Array.isArray(streamEntries)) continue;
|
|
3144
|
+
for (const entry of streamEntries) {
|
|
3145
|
+
if (!Array.isArray(entry) || entry.length < 2) continue;
|
|
3146
|
+
const id = String(entry[0]);
|
|
3147
|
+
const flat = entry[1];
|
|
3148
|
+
if (!Array.isArray(flat)) continue;
|
|
3149
|
+
const fields = {};
|
|
3150
|
+
for (let i = 0; i < flat.length; i += 2) {
|
|
3151
|
+
const k = flat[i];
|
|
3152
|
+
const v = flat[i + 1];
|
|
3153
|
+
if (typeof k === "string") fields[k] = String(v ?? "");
|
|
3154
|
+
}
|
|
3155
|
+
entries.push({ id, fields });
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
return { entries };
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
// src/glassbox/emit.ts
|
|
3162
|
+
var activePubSub;
|
|
3163
|
+
function getPubSub() {
|
|
3164
|
+
if (activePubSub) return activePubSub;
|
|
3165
|
+
const url = readEnv("UPSTASH_REDIS_URL");
|
|
3166
|
+
const token = readEnv("UPSTASH_REDIS_TOKEN");
|
|
3167
|
+
if (url && token) {
|
|
3168
|
+
activePubSub = new UpstashPubSub({ url, token });
|
|
3169
|
+
} else {
|
|
3170
|
+
activePubSub = new MemoryPubSub();
|
|
3171
|
+
}
|
|
3172
|
+
return activePubSub;
|
|
3173
|
+
}
|
|
3174
|
+
function readEnv(key) {
|
|
3175
|
+
try {
|
|
3176
|
+
if (typeof process !== "undefined" && process.env) {
|
|
3177
|
+
const v = process.env[key];
|
|
3178
|
+
return v && v.trim() !== "" ? v : void 0;
|
|
3179
|
+
}
|
|
3180
|
+
} catch {
|
|
3181
|
+
}
|
|
3182
|
+
return void 0;
|
|
3183
|
+
}
|
|
3184
|
+
function emitGlassboxEvent(traceId, kind, data) {
|
|
3185
|
+
if (!traceId) return;
|
|
3186
|
+
const event = { kind, at: Date.now(), data };
|
|
3187
|
+
const ps = getPubSub();
|
|
3188
|
+
try {
|
|
3189
|
+
const p = ps.publish(traceId, event);
|
|
3190
|
+
if (p && typeof p.then === "function") {
|
|
3191
|
+
p.catch(() => {
|
|
3192
|
+
});
|
|
3193
|
+
}
|
|
3194
|
+
} catch {
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
function emitCompileStart(traceId, data) {
|
|
3198
|
+
emitGlassboxEvent(traceId, "compile.start", data);
|
|
3199
|
+
}
|
|
3200
|
+
function emitCompileDone(traceId, data) {
|
|
3201
|
+
emitGlassboxEvent(traceId, "compile.done", data);
|
|
3202
|
+
}
|
|
3203
|
+
function emitExecuteAttempt(traceId, data) {
|
|
3204
|
+
emitGlassboxEvent(traceId, "execute.attempt", data);
|
|
3205
|
+
}
|
|
3206
|
+
function emitExecuteSuccess(traceId, data) {
|
|
3207
|
+
emitGlassboxEvent(traceId, "execute.success", data);
|
|
3208
|
+
}
|
|
3209
|
+
function emitAdvisoryFired(traceId, data) {
|
|
3210
|
+
emitGlassboxEvent(traceId, "advisory.fired", data);
|
|
3211
|
+
}
|
|
3212
|
+
function emitFallbackWalked(traceId, data) {
|
|
3213
|
+
emitGlassboxEvent(traceId, "fallback.walked", data);
|
|
3214
|
+
}
|
|
3215
|
+
|
|
2928
3216
|
// src/call.ts
|
|
2929
3217
|
async function call(ir, opts = {}) {
|
|
3218
|
+
const traceId = generateTraceId();
|
|
3219
|
+
safeEmit(
|
|
3220
|
+
() => emitCompileStart(traceId, {
|
|
3221
|
+
appId: ir.appId,
|
|
3222
|
+
archetype: ir.intent.archetype,
|
|
3223
|
+
models: ir.models
|
|
3224
|
+
})
|
|
3225
|
+
);
|
|
2930
3226
|
const initial = compileAndRegister(ir, opts);
|
|
3227
|
+
safeEmit(
|
|
3228
|
+
() => emitCompileDone(traceId, {
|
|
3229
|
+
target: initial.target,
|
|
3230
|
+
provider: initial.provider,
|
|
3231
|
+
fallbackChain: initial.fallbackChain,
|
|
3232
|
+
tokensIn: initial.tokensIn,
|
|
3233
|
+
estimatedCostUsd: initial.estimatedCostUsd,
|
|
3234
|
+
mutationsApplied: initial.mutationsApplied,
|
|
3235
|
+
advisories: initial.advisories
|
|
3236
|
+
})
|
|
3237
|
+
);
|
|
3238
|
+
for (const adv of initial.advisories) {
|
|
3239
|
+
safeEmit(
|
|
3240
|
+
() => emitAdvisoryFired(traceId, { code: adv.code, message: adv.message })
|
|
3241
|
+
);
|
|
3242
|
+
}
|
|
2931
3243
|
const start = Date.now();
|
|
2932
3244
|
const attempts = [];
|
|
2933
3245
|
const rawTargets = [initial.target, ...initial.fallbackChain];
|
|
@@ -3058,6 +3370,9 @@ async function call(ir, opts = {}) {
|
|
|
3058
3370
|
continue;
|
|
3059
3371
|
}
|
|
3060
3372
|
}
|
|
3373
|
+
safeEmit(
|
|
3374
|
+
() => emitExecuteAttempt(traceId, { model: targetModel, attemptIndex: i })
|
|
3375
|
+
);
|
|
3061
3376
|
const exec = await execute(activeCompile.request, {
|
|
3062
3377
|
apiKeys: opts.apiKeys,
|
|
3063
3378
|
fetchImpl: opts.fetchImpl,
|
|
@@ -3067,6 +3382,14 @@ async function call(ir, opts = {}) {
|
|
|
3067
3382
|
if (validated.ok) {
|
|
3068
3383
|
attempts.push({ model: targetModel, status: "success" });
|
|
3069
3384
|
const latencyMs2 = Date.now() - start;
|
|
3385
|
+
safeEmit(
|
|
3386
|
+
() => emitExecuteSuccess(traceId, {
|
|
3387
|
+
model: targetModel,
|
|
3388
|
+
tokensIn: validated.response.tokens.input,
|
|
3389
|
+
tokensOut: validated.response.tokens.output,
|
|
3390
|
+
latencyMs: latencyMs2
|
|
3391
|
+
})
|
|
3392
|
+
);
|
|
3070
3393
|
await record({
|
|
3071
3394
|
handle: initial.handle,
|
|
3072
3395
|
tokensIn: validated.response.tokens.input,
|
|
@@ -3083,6 +3406,20 @@ async function call(ir, opts = {}) {
|
|
|
3083
3406
|
cacheCreationInputTokens: validated.response.tokens.cacheCreated
|
|
3084
3407
|
});
|
|
3085
3408
|
const fellOver = targetModel !== initial.target;
|
|
3409
|
+
const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
|
|
3410
|
+
if (fellOver) {
|
|
3411
|
+
const firstFailed = attempts.find((a) => a.status !== "success");
|
|
3412
|
+
if (firstFailed) {
|
|
3413
|
+
safeEmit(
|
|
3414
|
+
() => emitFallbackWalked(traceId, {
|
|
3415
|
+
from: initial.target,
|
|
3416
|
+
to: targetModel,
|
|
3417
|
+
reason: fallbackReason ?? "unknown",
|
|
3418
|
+
attempt: firstFailed
|
|
3419
|
+
})
|
|
3420
|
+
);
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3086
3423
|
return {
|
|
3087
3424
|
handle: initial.handle,
|
|
3088
3425
|
actualModel: targetModel,
|
|
@@ -3094,9 +3431,10 @@ async function call(ir, opts = {}) {
|
|
|
3094
3431
|
attempts,
|
|
3095
3432
|
servedBy: targetModel,
|
|
3096
3433
|
fellOverFrom: fellOver ? initial.target : void 0,
|
|
3097
|
-
fallbackReason
|
|
3434
|
+
fallbackReason,
|
|
3098
3435
|
unreachableFiltered,
|
|
3099
|
-
policyBlockedFiltered
|
|
3436
|
+
policyBlockedFiltered,
|
|
3437
|
+
traceId
|
|
3100
3438
|
};
|
|
3101
3439
|
}
|
|
3102
3440
|
attempts.push({
|
|
@@ -3193,6 +3531,23 @@ function normalizeFallbackReason(attempts) {
|
|
|
3193
3531
|
if (code === "auth" || code === "auth_inferred") return "provider_auth_failed";
|
|
3194
3532
|
return "provider_error";
|
|
3195
3533
|
}
|
|
3534
|
+
function generateTraceId() {
|
|
3535
|
+
try {
|
|
3536
|
+
const g = globalThis;
|
|
3537
|
+
if (g.crypto && typeof g.crypto.randomUUID === "function") {
|
|
3538
|
+
return g.crypto.randomUUID();
|
|
3539
|
+
}
|
|
3540
|
+
} catch {
|
|
3541
|
+
}
|
|
3542
|
+
const hex = (n) => Math.floor(Math.random() * Math.pow(16, n)).toString(16).padStart(n, "0");
|
|
3543
|
+
return `${hex(8)}-${hex(4)}-${hex(4)}-${hex(4)}-${hex(12)}`;
|
|
3544
|
+
}
|
|
3545
|
+
function safeEmit(fn) {
|
|
3546
|
+
try {
|
|
3547
|
+
fn();
|
|
3548
|
+
} catch {
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3196
3551
|
|
|
3197
3552
|
// src/oracle.ts
|
|
3198
3553
|
var DEFAULT_DIMENSIONS = ["correctness", "completeness", "conciseness", "format"];
|
package/dist/index.mjs
CHANGED
|
@@ -18,6 +18,14 @@ import {
|
|
|
18
18
|
profilesByProvider,
|
|
19
19
|
tryGetProfile
|
|
20
20
|
} from "./chunk-7MTHFSNY.mjs";
|
|
21
|
+
import {
|
|
22
|
+
emitAdvisoryFired,
|
|
23
|
+
emitCompileDone,
|
|
24
|
+
emitCompileStart,
|
|
25
|
+
emitExecuteAttempt,
|
|
26
|
+
emitExecuteSuccess,
|
|
27
|
+
emitFallbackWalked
|
|
28
|
+
} from "./chunk-NUTC7NUC.mjs";
|
|
21
29
|
|
|
22
30
|
// src/tokenizer.ts
|
|
23
31
|
var tokenizerImpl = defaultCharBasedCounter;
|
|
@@ -1723,7 +1731,31 @@ function ensureCrossProviderTail(opts) {
|
|
|
1723
1731
|
|
|
1724
1732
|
// src/call.ts
|
|
1725
1733
|
async function call(ir, opts = {}) {
|
|
1734
|
+
const traceId = generateTraceId();
|
|
1735
|
+
safeEmit(
|
|
1736
|
+
() => emitCompileStart(traceId, {
|
|
1737
|
+
appId: ir.appId,
|
|
1738
|
+
archetype: ir.intent.archetype,
|
|
1739
|
+
models: ir.models
|
|
1740
|
+
})
|
|
1741
|
+
);
|
|
1726
1742
|
const initial = compileAndRegister(ir, opts);
|
|
1743
|
+
safeEmit(
|
|
1744
|
+
() => emitCompileDone(traceId, {
|
|
1745
|
+
target: initial.target,
|
|
1746
|
+
provider: initial.provider,
|
|
1747
|
+
fallbackChain: initial.fallbackChain,
|
|
1748
|
+
tokensIn: initial.tokensIn,
|
|
1749
|
+
estimatedCostUsd: initial.estimatedCostUsd,
|
|
1750
|
+
mutationsApplied: initial.mutationsApplied,
|
|
1751
|
+
advisories: initial.advisories
|
|
1752
|
+
})
|
|
1753
|
+
);
|
|
1754
|
+
for (const adv of initial.advisories) {
|
|
1755
|
+
safeEmit(
|
|
1756
|
+
() => emitAdvisoryFired(traceId, { code: adv.code, message: adv.message })
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1727
1759
|
const start = Date.now();
|
|
1728
1760
|
const attempts = [];
|
|
1729
1761
|
const rawTargets = [initial.target, ...initial.fallbackChain];
|
|
@@ -1854,6 +1886,9 @@ async function call(ir, opts = {}) {
|
|
|
1854
1886
|
continue;
|
|
1855
1887
|
}
|
|
1856
1888
|
}
|
|
1889
|
+
safeEmit(
|
|
1890
|
+
() => emitExecuteAttempt(traceId, { model: targetModel, attemptIndex: i })
|
|
1891
|
+
);
|
|
1857
1892
|
const exec = await execute(activeCompile.request, {
|
|
1858
1893
|
apiKeys: opts.apiKeys,
|
|
1859
1894
|
fetchImpl: opts.fetchImpl,
|
|
@@ -1863,6 +1898,14 @@ async function call(ir, opts = {}) {
|
|
|
1863
1898
|
if (validated.ok) {
|
|
1864
1899
|
attempts.push({ model: targetModel, status: "success" });
|
|
1865
1900
|
const latencyMs2 = Date.now() - start;
|
|
1901
|
+
safeEmit(
|
|
1902
|
+
() => emitExecuteSuccess(traceId, {
|
|
1903
|
+
model: targetModel,
|
|
1904
|
+
tokensIn: validated.response.tokens.input,
|
|
1905
|
+
tokensOut: validated.response.tokens.output,
|
|
1906
|
+
latencyMs: latencyMs2
|
|
1907
|
+
})
|
|
1908
|
+
);
|
|
1866
1909
|
await record({
|
|
1867
1910
|
handle: initial.handle,
|
|
1868
1911
|
tokensIn: validated.response.tokens.input,
|
|
@@ -1879,6 +1922,20 @@ async function call(ir, opts = {}) {
|
|
|
1879
1922
|
cacheCreationInputTokens: validated.response.tokens.cacheCreated
|
|
1880
1923
|
});
|
|
1881
1924
|
const fellOver = targetModel !== initial.target;
|
|
1925
|
+
const fallbackReason = fellOver ? normalizeFallbackReason(attempts) : void 0;
|
|
1926
|
+
if (fellOver) {
|
|
1927
|
+
const firstFailed = attempts.find((a) => a.status !== "success");
|
|
1928
|
+
if (firstFailed) {
|
|
1929
|
+
safeEmit(
|
|
1930
|
+
() => emitFallbackWalked(traceId, {
|
|
1931
|
+
from: initial.target,
|
|
1932
|
+
to: targetModel,
|
|
1933
|
+
reason: fallbackReason ?? "unknown",
|
|
1934
|
+
attempt: firstFailed
|
|
1935
|
+
})
|
|
1936
|
+
);
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1882
1939
|
return {
|
|
1883
1940
|
handle: initial.handle,
|
|
1884
1941
|
actualModel: targetModel,
|
|
@@ -1890,9 +1947,10 @@ async function call(ir, opts = {}) {
|
|
|
1890
1947
|
attempts,
|
|
1891
1948
|
servedBy: targetModel,
|
|
1892
1949
|
fellOverFrom: fellOver ? initial.target : void 0,
|
|
1893
|
-
fallbackReason
|
|
1950
|
+
fallbackReason,
|
|
1894
1951
|
unreachableFiltered,
|
|
1895
|
-
policyBlockedFiltered
|
|
1952
|
+
policyBlockedFiltered,
|
|
1953
|
+
traceId
|
|
1896
1954
|
};
|
|
1897
1955
|
}
|
|
1898
1956
|
attempts.push({
|
|
@@ -1989,6 +2047,23 @@ function normalizeFallbackReason(attempts) {
|
|
|
1989
2047
|
if (code === "auth" || code === "auth_inferred") return "provider_auth_failed";
|
|
1990
2048
|
return "provider_error";
|
|
1991
2049
|
}
|
|
2050
|
+
function generateTraceId() {
|
|
2051
|
+
try {
|
|
2052
|
+
const g = globalThis;
|
|
2053
|
+
if (g.crypto && typeof g.crypto.randomUUID === "function") {
|
|
2054
|
+
return g.crypto.randomUUID();
|
|
2055
|
+
}
|
|
2056
|
+
} catch {
|
|
2057
|
+
}
|
|
2058
|
+
const hex = (n) => Math.floor(Math.random() * Math.pow(16, n)).toString(16).padStart(n, "0");
|
|
2059
|
+
return `${hex(8)}-${hex(4)}-${hex(4)}-${hex(4)}-${hex(12)}`;
|
|
2060
|
+
}
|
|
2061
|
+
function safeEmit(fn) {
|
|
2062
|
+
try {
|
|
2063
|
+
fn();
|
|
2064
|
+
} catch {
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
1992
2067
|
|
|
1993
2068
|
// src/oracle.ts
|
|
1994
2069
|
var DEFAULT_DIMENSIONS = ["correctness", "completeness", "conciseness", "format"];
|
|
@@ -538,6 +538,18 @@ interface CallResult {
|
|
|
538
538
|
* case.
|
|
539
539
|
*/
|
|
540
540
|
policyBlockedFiltered?: string[];
|
|
541
|
+
/**
|
|
542
|
+
* alpha.17. Unique identifier for this call() invocation, generated at
|
|
543
|
+
* call() entry via crypto.randomUUID(). Returned on success and emitted
|
|
544
|
+
* as the routing key for Glass-Box observability events
|
|
545
|
+
* (compile.start, compile.done, execute.attempt, execute.success,
|
|
546
|
+
* fallback.walked, advisory.fired). Pass the same id to
|
|
547
|
+
* `subscribe(traceId)` from `@warmdrift/kgauto-compiler/glassbox` to
|
|
548
|
+
* tap the in-flight event stream.
|
|
549
|
+
*
|
|
550
|
+
* Always present on success. Additive, non-breaking.
|
|
551
|
+
*/
|
|
552
|
+
traceId: string;
|
|
541
553
|
}
|
|
542
554
|
/**
|
|
543
555
|
* Thrown when call() exhausts the fallback chain without success.
|
|
@@ -624,137 +636,4 @@ interface RecordInput {
|
|
|
624
636
|
ttftMs?: number;
|
|
625
637
|
}
|
|
626
638
|
|
|
627
|
-
|
|
628
|
-
* Model profiles — executable knowledge about each provider/model.
|
|
629
|
-
*
|
|
630
|
-
* Unlike v1 which carried `known_failures` as prose strings, v2 makes them
|
|
631
|
-
* executable: cliffs trigger guards, lowering describes the wire format,
|
|
632
|
-
* recovery handlers describe what to do after specific failures.
|
|
633
|
-
*
|
|
634
|
-
* Each profile is the answer to "if I want to call THIS model with THIS
|
|
635
|
-
* shape of work, what does it need from me, and what should I do when it
|
|
636
|
-
* fails?"
|
|
637
|
-
*/
|
|
638
|
-
|
|
639
|
-
type StructuredOutputCapability = 'native' | 'grammar' | 'none';
|
|
640
|
-
type SystemPromptMode = 'inline' | 'separate' | 'as_developer' | 'unsupported';
|
|
641
|
-
type CacheStrategy = 'cache_control' | 'cachedContent' | 'unsupported';
|
|
642
|
-
interface CliffRule {
|
|
643
|
-
/** What metric triggers this cliff. */
|
|
644
|
-
metric: 'input_tokens' | 'tool_count' | 'history_turns' | 'thinking_with_short_output';
|
|
645
|
-
/** Threshold — meaning depends on metric. */
|
|
646
|
-
threshold: number;
|
|
647
|
-
/** What action to take when triggered. */
|
|
648
|
-
action: 'downgrade_quality_warning' | 'drop_to_top_relevant' | 'force_thinking_budget_zero' | 'force_terse_output' | 'escalate_target' | 'strip_tools';
|
|
649
|
-
/**
|
|
650
|
-
* Optional: only fire this cliff when the IR's intent.archetype matches.
|
|
651
|
-
* Used for archetype-specific failure modes (e.g. Gemini Flash returns
|
|
652
|
-
* empty when summarize is offered tools).
|
|
653
|
-
*/
|
|
654
|
-
whenIntent?: IntentArchetypeName;
|
|
655
|
-
/** Human-readable reason for digest reporting. */
|
|
656
|
-
reason: string;
|
|
657
|
-
}
|
|
658
|
-
interface RecoveryRule {
|
|
659
|
-
/** What signal triggers recovery. */
|
|
660
|
-
signal: 'empty_response_after_tool' | 'empty_response' | 'malformed_function_call' | 'rate_limit' | 'model_not_found' | 'context_overflow';
|
|
661
|
-
/** Action: retry with adjusted params, or escalate to next fallback. */
|
|
662
|
-
action: 'retry_with_params' | 'escalate' | 'log_only';
|
|
663
|
-
/** When action=retry_with_params, the param adjustments to apply. */
|
|
664
|
-
retryParams?: Record<string, unknown>;
|
|
665
|
-
/** Max retries with this rule. */
|
|
666
|
-
maxRetries?: number;
|
|
667
|
-
/** Human-readable reason for digest reporting. */
|
|
668
|
-
reason: string;
|
|
669
|
-
}
|
|
670
|
-
interface LoweringSpec {
|
|
671
|
-
/** Where the system prompt goes. */
|
|
672
|
-
system: {
|
|
673
|
-
mode: SystemPromptMode;
|
|
674
|
-
field?: string;
|
|
675
|
-
};
|
|
676
|
-
/** Cache strategy + parameters. */
|
|
677
|
-
cache: {
|
|
678
|
-
strategy: CacheStrategy;
|
|
679
|
-
/** Min tokens before caching is worth it (provider rules). */
|
|
680
|
-
minTokens?: number;
|
|
681
|
-
/** Discount factor on cached input (0.1 = 10% of normal price). */
|
|
682
|
-
discount?: number;
|
|
683
|
-
/** TTL hint in seconds. */
|
|
684
|
-
ttlSeconds?: number;
|
|
685
|
-
};
|
|
686
|
-
/** Tool format identifier — see lower.ts for supported formats. */
|
|
687
|
-
tools?: {
|
|
688
|
-
format: 'anthropic' | 'google' | 'openai' | 'deepseek';
|
|
689
|
-
};
|
|
690
|
-
/** Thinking config — present iff this model has a thinking knob. */
|
|
691
|
-
thinking?: {
|
|
692
|
-
/** Field path on the request. */
|
|
693
|
-
field: string;
|
|
694
|
-
/** Default value when caller hasn't specified. */
|
|
695
|
-
default?: number | 'auto' | 'off';
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
interface ModelProfile {
|
|
699
|
-
id: string;
|
|
700
|
-
provider: Provider;
|
|
701
|
-
status: 'current' | 'preview' | 'legacy';
|
|
702
|
-
maxContextTokens: number;
|
|
703
|
-
maxOutputTokens: number;
|
|
704
|
-
maxTools: number;
|
|
705
|
-
parallelToolCalls: boolean;
|
|
706
|
-
structuredOutput: StructuredOutputCapability;
|
|
707
|
-
systemPromptMode: SystemPromptMode;
|
|
708
|
-
streaming: boolean;
|
|
709
|
-
cliffs: CliffRule[];
|
|
710
|
-
costInputPer1m: number;
|
|
711
|
-
costOutputPer1m: number;
|
|
712
|
-
lowering: LoweringSpec;
|
|
713
|
-
recovery: RecoveryRule[];
|
|
714
|
-
strengths: string[];
|
|
715
|
-
weaknesses: string[];
|
|
716
|
-
notes?: string;
|
|
717
|
-
verifiedAgainstDocs?: string;
|
|
718
|
-
/**
|
|
719
|
-
* Hand-curated per-archetype performance score on a 0-10 scale.
|
|
720
|
-
*
|
|
721
|
-
* 10 = frontier on this archetype (e.g. Opus 4.7 on critique)
|
|
722
|
-
* 8 = strong second tier (Sonnet on plan, Pro on extract)
|
|
723
|
-
* 7 = competent (Haiku on classify, Flash on hunt)
|
|
724
|
-
* 5 = acceptable for tolerant archetypes (Flash-Lite on classify)
|
|
725
|
-
* 3 = degraded (Flash on critique, DeepSeek on hunt)
|
|
726
|
-
*
|
|
727
|
-
* Missing archetypes default to `5` (no data, neutral). Each non-default
|
|
728
|
-
* value should carry a one-line rationale in the profile's note or inline
|
|
729
|
-
* comment citing brain evidence, family prior, or "starter hypothesis —
|
|
730
|
-
* verify with telemetry."
|
|
731
|
-
*
|
|
732
|
-
* Source today: hand-curated from master plan §3.3 + §6.2 starter tables.
|
|
733
|
-
* Source tomorrow (alpha.10+): brain `archetype_model_evidence` view.
|
|
734
|
-
*
|
|
735
|
-
* Anti-hallucination guardrail (master plan §2.5): when the watcher's
|
|
736
|
-
* `--audit-fields` flag flags a profile stale (>90 days since
|
|
737
|
-
* verifiedAgainstDocs), the archetypePerf values get re-audited
|
|
738
|
-
* alongside capability fields. AI-trained intuition is NOT a valid
|
|
739
|
-
* source — only docs or brain evidence.
|
|
740
|
-
*
|
|
741
|
-
* alpha.9.
|
|
742
|
-
*/
|
|
743
|
-
archetypePerf?: Partial<Record<IntentArchetypeName, number>>;
|
|
744
|
-
}
|
|
745
|
-
declare const ALIASES: Record<string, string>;
|
|
746
|
-
interface ProfileBrainHook {
|
|
747
|
-
getProfile?: (canonicalId: string) => ModelProfile | undefined;
|
|
748
|
-
resolveAlias?: (id: string) => string | undefined;
|
|
749
|
-
}
|
|
750
|
-
/** @internal — called by models-brain.ts at module load. */
|
|
751
|
-
declare function _setProfileBrainHook(hook: ProfileBrainHook): void;
|
|
752
|
-
declare function getProfile(id: string): ModelProfile;
|
|
753
|
-
declare function tryGetProfile(id: string): ModelProfile | undefined;
|
|
754
|
-
declare function allProfiles(): readonly ModelProfile[];
|
|
755
|
-
/** @internal — bundled-only access for adapters that need a non-brain
|
|
756
|
-
* fallback baseline (avoids a brain → profiles → brain re-entry). */
|
|
757
|
-
declare function allProfilesRaw(): readonly ModelProfile[];
|
|
758
|
-
declare function profilesByProvider(provider: Provider): readonly ModelProfile[];
|
|
759
|
-
|
|
760
|
-
export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type FallbackReason as F, type HistoryCachePolicy as H, type IntentDeclaration as I, type LoweringSpec as L, type ModelProfile as M, type NormalizedResponse as N, type OracleScore as O, type ProviderOverrides as P, type RecordInput as R, type StructuredOutputCapability as S, type ToolCall as T, _setProfileBrainHook as _, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type CompileResult as e, type Provider as f, ALIASES as g, type CacheStrategy as h, type CallAttempt as i, CallError as j, type CliffRule as k, type Constraints as l, type Message as m, type MutationApplied as n, type NormalizedTokens as o, type PromptSection as p, type RecoveryRule as q, type SystemPromptMode as r, type ToolDefinition as s, allProfiles as t, getProfile as u, profilesByProvider as v, tryGetProfile as w, allProfilesRaw as x };
|
|
639
|
+
export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type FallbackReason as F, type HistoryCachePolicy as H, type IntentDeclaration as I, type Message as M, type NormalizedResponse as N, type OracleScore as O, type ProviderOverrides as P, type RecordInput as R, type ToolCall as T, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type CompileResult as e, type Provider as f, type CallAttempt as g, CallError as h, type Constraints as i, type MutationApplied as j, type NormalizedTokens as k, type PromptSection as l, type ToolDefinition as m };
|