@warmdrift/kgauto-compiler 2.0.0-alpha.7 → 2.0.0-alpha.71
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 +176 -46
- package/dist/brain-proxy.d.mts +113 -0
- package/dist/brain-proxy.d.ts +113 -0
- package/dist/brain-proxy.js +193 -0
- package/dist/brain-proxy.mjs +6 -0
- package/dist/chunk-4UO4CCSP.mjs +1620 -0
- package/dist/chunk-65ZMX5OT.mjs +169 -0
- package/dist/{chunk-5TI6PNSK.mjs → chunk-BVEXV5KC.mjs} +11 -0
- package/dist/chunk-NBO4R5PC.mjs +313 -0
- package/dist/chunk-P3TOAEG4.mjs +56 -0
- package/dist/chunk-RO22VFIF.mjs +29 -0
- package/dist/chunk-SBFSYCQG.mjs +719 -0
- package/dist/chunk-URFQR3SB.mjs +203 -0
- package/dist/dialect.d.mts +41 -3
- package/dist/dialect.d.ts +41 -3
- package/dist/dialect.js +14 -2
- package/dist/dialect.mjs +5 -3
- package/dist/glassbox/index.d.mts +59 -0
- package/dist/glassbox/index.d.ts +59 -0
- package/dist/glassbox/index.js +312 -0
- package/dist/glassbox/index.mjs +12 -0
- package/dist/glassbox-routes/format.d.mts +24 -0
- package/dist/glassbox-routes/format.d.ts +24 -0
- package/dist/glassbox-routes/format.js +86 -0
- package/dist/glassbox-routes/format.mjs +18 -0
- package/dist/glassbox-routes/index.d.mts +191 -0
- package/dist/glassbox-routes/index.d.ts +191 -0
- package/dist/glassbox-routes/index.js +2888 -0
- package/dist/glassbox-routes/index.mjs +667 -0
- package/dist/glassbox-routes/react/index.d.mts +74 -0
- package/dist/glassbox-routes/react/index.d.ts +74 -0
- package/dist/glassbox-routes/react/index.js +819 -0
- package/dist/glassbox-routes/react/index.mjs +754 -0
- package/dist/index.d.mts +2745 -17
- package/dist/index.d.ts +2745 -17
- package/dist/index.js +9006 -1651
- package/dist/index.mjs +5103 -367
- package/dist/ir-BEQ28muo.d.ts +1608 -0
- package/dist/ir-CnnJST_N.d.mts +1608 -0
- package/dist/key-health.d.mts +131 -0
- package/dist/key-health.d.ts +131 -0
- package/dist/key-health.js +228 -0
- package/dist/key-health.mjs +6 -0
- package/dist/profiles.d.mts +292 -2
- package/dist/profiles.d.ts +292 -2
- package/dist/profiles.js +1231 -16
- package/dist/profiles.mjs +9 -1
- package/dist/types-B--CYzMo.d.ts +131 -0
- package/dist/types-BDFrJkma.d.mts +131 -0
- package/dist/types-DSeJJ6tt.d.ts +149 -0
- package/dist/types-DeGRCTlJ.d.mts +149 -0
- package/package.json +54 -8
- package/dist/chunk-MBEI5UOM.mjs +0 -409
- package/dist/profiles-B3eNQ2py.d.ts +0 -619
- package/dist/profiles-Py8c7zjJ.d.mts +0 -619
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// src/brain-proxy.ts
|
|
2
|
+
var SEGMENT_TO_TABLE = {
|
|
3
|
+
outcomes: "compile_outcomes",
|
|
4
|
+
compile_outcome_advisories: "compile_outcome_advisories",
|
|
5
|
+
compile_outcome_quality: "compile_outcome_quality",
|
|
6
|
+
probe_outcomes: "probe_outcomes",
|
|
7
|
+
// alpha.62 (eval spine): golden-set capture. Only receives rows when the
|
|
8
|
+
// consumer has explicitly opted in via KGAUTO_GOLDEN_CAPTURE — the segment
|
|
9
|
+
// existing here does not by itself store anything.
|
|
10
|
+
golden_irs: "kgauto_golden_irs"
|
|
11
|
+
};
|
|
12
|
+
var KNOWN_SEGMENTS = Object.keys(SEGMENT_TO_TABLE);
|
|
13
|
+
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
14
|
+
function jsonResponse(status, body) {
|
|
15
|
+
return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS });
|
|
16
|
+
}
|
|
17
|
+
function bearerOf(req) {
|
|
18
|
+
const header = req.headers.get("Authorization") ?? "";
|
|
19
|
+
const match = /^Bearer\s+(.+)$/i.exec(header);
|
|
20
|
+
return match?.[1]?.trim() ?? "";
|
|
21
|
+
}
|
|
22
|
+
function requireString(name, value) {
|
|
23
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
24
|
+
throw new Error(`createBrainForwardRoutes: ${name} is required`);
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
function isNumericOutcomeId(value) {
|
|
29
|
+
return typeof value === "number" || typeof value === "string" && /^\d+$/.test(value);
|
|
30
|
+
}
|
|
31
|
+
function createBrainForwardRoutes(config) {
|
|
32
|
+
const ingestSecret = requireString("ingestSecret", config.ingestSecret);
|
|
33
|
+
const brainUrl = requireString("brainUrl", config.brainUrl).replace(/\/+$/, "");
|
|
34
|
+
const serviceKey = requireString("serviceKey", config.serviceKey);
|
|
35
|
+
const fetchFn = config.fetchImpl ?? fetch;
|
|
36
|
+
async function resolveQualityOutcomeIds(body) {
|
|
37
|
+
const rows = Array.isArray(body) ? body : [body];
|
|
38
|
+
const handles = [
|
|
39
|
+
...new Set(
|
|
40
|
+
rows.map((r) => r?.outcome_id).filter(
|
|
41
|
+
(v) => typeof v === "string" && !isNumericOutcomeId(v)
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
];
|
|
45
|
+
if (handles.length === 0) return body;
|
|
46
|
+
const list = handles.map((h) => `"${h.replace(/"/g, "")}"`).join(",");
|
|
47
|
+
const url = `${brainUrl}/rest/v1/compile_outcomes?select=id,handle&handle=in.(${encodeURIComponent(list)})&order=id.desc`;
|
|
48
|
+
let idByHandle;
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetchFn(url, {
|
|
51
|
+
headers: { apikey: serviceKey, Authorization: `Bearer ${serviceKey}` }
|
|
52
|
+
});
|
|
53
|
+
if (!res.ok) {
|
|
54
|
+
const text = await res.text().catch(() => "<no body>");
|
|
55
|
+
return jsonResponse(502, {
|
|
56
|
+
error: "handle-resolution-failed",
|
|
57
|
+
table: "compile_outcome_quality",
|
|
58
|
+
status: res.status,
|
|
59
|
+
detail: text
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const found = await res.json();
|
|
63
|
+
idByHandle = /* @__PURE__ */ new Map();
|
|
64
|
+
for (const r of found) {
|
|
65
|
+
if (!idByHandle.has(r.handle)) idByHandle.set(r.handle, r.id);
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
return jsonResponse(502, {
|
|
69
|
+
error: "handle-resolution-failed",
|
|
70
|
+
table: "compile_outcome_quality",
|
|
71
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const unresolved = handles.filter((h) => !idByHandle.has(h));
|
|
75
|
+
if (unresolved.length > 0) {
|
|
76
|
+
return jsonResponse(404, {
|
|
77
|
+
error: "handle_not_found",
|
|
78
|
+
table: "compile_outcome_quality",
|
|
79
|
+
unresolved
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const rewritten = rows.map(
|
|
83
|
+
(r) => typeof r?.outcome_id === "string" && idByHandle.has(r.outcome_id) ? { ...r, outcome_id: idByHandle.get(r.outcome_id) } : r
|
|
84
|
+
);
|
|
85
|
+
return Array.isArray(body) ? rewritten : rewritten[0];
|
|
86
|
+
}
|
|
87
|
+
async function handle(req, segment) {
|
|
88
|
+
try {
|
|
89
|
+
if (req.method !== "POST") {
|
|
90
|
+
return jsonResponse(405, {
|
|
91
|
+
error: "method-not-allowed",
|
|
92
|
+
method: req.method,
|
|
93
|
+
allowed: ["POST"]
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const table = SEGMENT_TO_TABLE[segment];
|
|
97
|
+
if (!table) {
|
|
98
|
+
return jsonResponse(404, {
|
|
99
|
+
error: "unknown-brain-forward-segment",
|
|
100
|
+
segment,
|
|
101
|
+
known: KNOWN_SEGMENTS
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (bearerOf(req) !== ingestSecret) {
|
|
105
|
+
return jsonResponse(401, { error: "unauthorized" });
|
|
106
|
+
}
|
|
107
|
+
let body;
|
|
108
|
+
try {
|
|
109
|
+
body = await req.json();
|
|
110
|
+
} catch {
|
|
111
|
+
return jsonResponse(400, { error: "invalid-json" });
|
|
112
|
+
}
|
|
113
|
+
let row = Array.isArray(body) ? body : { ...body };
|
|
114
|
+
if (table === "compile_outcome_quality") {
|
|
115
|
+
const outcome = await resolveQualityOutcomeIds(row);
|
|
116
|
+
if (outcome instanceof Response) return outcome;
|
|
117
|
+
row = outcome;
|
|
118
|
+
}
|
|
119
|
+
const wantsRepresentation = /return=representation/i.test(
|
|
120
|
+
req.headers.get("Prefer") ?? ""
|
|
121
|
+
);
|
|
122
|
+
let brainRes;
|
|
123
|
+
try {
|
|
124
|
+
brainRes = await fetchFn(`${brainUrl}/rest/v1/${table}`, {
|
|
125
|
+
method: "POST",
|
|
126
|
+
headers: {
|
|
127
|
+
apikey: serviceKey,
|
|
128
|
+
Authorization: `Bearer ${serviceKey}`,
|
|
129
|
+
"Content-Type": "application/json",
|
|
130
|
+
Prefer: wantsRepresentation ? "return=representation" : "return=minimal"
|
|
131
|
+
},
|
|
132
|
+
body: JSON.stringify(row)
|
|
133
|
+
});
|
|
134
|
+
} catch (err) {
|
|
135
|
+
return jsonResponse(502, {
|
|
136
|
+
error: "brain-unreachable",
|
|
137
|
+
table,
|
|
138
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (brainRes.ok) {
|
|
142
|
+
if (wantsRepresentation) {
|
|
143
|
+
const text2 = await brainRes.text().catch(() => "");
|
|
144
|
+
if (text2.length > 0) {
|
|
145
|
+
return new Response(text2, { status: 201, headers: JSON_HEADERS });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return jsonResponse(201, { ok: true });
|
|
149
|
+
}
|
|
150
|
+
const text = await brainRes.text().catch(() => "<no body>");
|
|
151
|
+
return jsonResponse(brainRes.status, {
|
|
152
|
+
error: "brain-write-failed",
|
|
153
|
+
table,
|
|
154
|
+
status: brainRes.status,
|
|
155
|
+
detail: text
|
|
156
|
+
});
|
|
157
|
+
} catch (err) {
|
|
158
|
+
return jsonResponse(500, {
|
|
159
|
+
error: "brain-forward-internal-error",
|
|
160
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { handle, segments: KNOWN_SEGMENTS };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export {
|
|
168
|
+
createBrainForwardRoutes
|
|
169
|
+
};
|
|
@@ -45,12 +45,22 @@ var INTENT_ARCHETYPES = {
|
|
|
45
45
|
name: "transform",
|
|
46
46
|
description: "Change format or style while preserving content",
|
|
47
47
|
examples: ["markdown \u2192 html", "formal \u2192 casual", "translate"]
|
|
48
|
+
},
|
|
49
|
+
judge: {
|
|
50
|
+
name: "judge",
|
|
51
|
+
description: "Pairwise comparison of two candidate outputs for the same input",
|
|
52
|
+
examples: ["golden-set eval A/B verdict", "model-swap non-inferiority check", "response bake-off"]
|
|
48
53
|
}
|
|
49
54
|
};
|
|
50
55
|
var ALL_ARCHETYPES = Object.keys(INTENT_ARCHETYPES);
|
|
51
56
|
function isArchetype(name) {
|
|
52
57
|
return name in INTENT_ARCHETYPES;
|
|
53
58
|
}
|
|
59
|
+
function resolveOutputMode(args) {
|
|
60
|
+
if (args.declared) return args.declared;
|
|
61
|
+
if (args.structuredOutput === true) return "json";
|
|
62
|
+
return args.toolCount > 0 ? "tool_call" : "text";
|
|
63
|
+
}
|
|
54
64
|
function bucketContext(tokens) {
|
|
55
65
|
if (tokens < 1e3) return "tiny";
|
|
56
66
|
if (tokens < 4e3) return "small";
|
|
@@ -87,6 +97,7 @@ export {
|
|
|
87
97
|
INTENT_ARCHETYPES,
|
|
88
98
|
ALL_ARCHETYPES,
|
|
89
99
|
isArchetype,
|
|
100
|
+
resolveOutputMode,
|
|
90
101
|
bucketContext,
|
|
91
102
|
bucketToolCount,
|
|
92
103
|
bucketHistory,
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
// src/glassbox/types.ts
|
|
2
|
+
var GLASSBOX_STREAM_TTL_MS = 6e4;
|
|
3
|
+
|
|
4
|
+
// src/glassbox/pubsub-upstash.ts
|
|
5
|
+
var UpstashPubSub = class {
|
|
6
|
+
url;
|
|
7
|
+
token;
|
|
8
|
+
fetchImpl;
|
|
9
|
+
blockMs;
|
|
10
|
+
maxLen;
|
|
11
|
+
constructor(cfg) {
|
|
12
|
+
this.url = cfg.url.replace(/\/$/, "");
|
|
13
|
+
this.token = cfg.token;
|
|
14
|
+
this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
15
|
+
this.blockMs = cfg.blockMs ?? 100;
|
|
16
|
+
this.maxLen = cfg.maxLen ?? 100;
|
|
17
|
+
}
|
|
18
|
+
async publish(channelKey, event) {
|
|
19
|
+
const key = channelKey;
|
|
20
|
+
const payload = JSON.stringify(event);
|
|
21
|
+
await this.cmd([
|
|
22
|
+
"XADD",
|
|
23
|
+
key,
|
|
24
|
+
"MAXLEN",
|
|
25
|
+
"~",
|
|
26
|
+
String(this.maxLen),
|
|
27
|
+
"*",
|
|
28
|
+
"event",
|
|
29
|
+
payload
|
|
30
|
+
]);
|
|
31
|
+
await this.cmd(["EXPIRE", key, String(Math.ceil(GLASSBOX_STREAM_TTL_MS / 1e3))]);
|
|
32
|
+
}
|
|
33
|
+
subscribe(channelKey) {
|
|
34
|
+
const key = channelKey;
|
|
35
|
+
const self = this;
|
|
36
|
+
let cursor = "$";
|
|
37
|
+
let cancelled = false;
|
|
38
|
+
let ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
|
|
39
|
+
return new ReadableStream({
|
|
40
|
+
async start(controller) {
|
|
41
|
+
try {
|
|
42
|
+
while (!cancelled && Date.now() < ttlDeadline) {
|
|
43
|
+
const resp = await self.cmd([
|
|
44
|
+
"XREAD",
|
|
45
|
+
"BLOCK",
|
|
46
|
+
String(self.blockMs),
|
|
47
|
+
"STREAMS",
|
|
48
|
+
key,
|
|
49
|
+
cursor
|
|
50
|
+
]);
|
|
51
|
+
if (cancelled) break;
|
|
52
|
+
const parsed = parseXReadResult(resp.result);
|
|
53
|
+
if (parsed.entries.length === 0) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
for (const entry of parsed.entries) {
|
|
57
|
+
const evt = decodeEvent(entry.fields);
|
|
58
|
+
if (evt) {
|
|
59
|
+
try {
|
|
60
|
+
controller.enqueue(evt);
|
|
61
|
+
} catch {
|
|
62
|
+
cancelled = true;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
cursor = entry.id;
|
|
67
|
+
}
|
|
68
|
+
ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
|
|
69
|
+
}
|
|
70
|
+
} catch (err) {
|
|
71
|
+
if (!cancelled) {
|
|
72
|
+
try {
|
|
73
|
+
controller.error(err);
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
controller.close();
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
cancel() {
|
|
85
|
+
cancelled = true;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async cmd(args) {
|
|
90
|
+
const res = await this.fetchImpl(this.url, {
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: {
|
|
93
|
+
Authorization: `Bearer ${this.token}`,
|
|
94
|
+
"Content-Type": "application/json"
|
|
95
|
+
},
|
|
96
|
+
body: JSON.stringify(args)
|
|
97
|
+
});
|
|
98
|
+
if (!res.ok) {
|
|
99
|
+
throw new Error(`Upstash ${args[0]} failed: HTTP ${res.status}`);
|
|
100
|
+
}
|
|
101
|
+
const json = await res.json();
|
|
102
|
+
if (json.error) {
|
|
103
|
+
throw new Error(`Upstash ${args[0]} failed: ${json.error}`);
|
|
104
|
+
}
|
|
105
|
+
return json;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
function traceChannel(traceId) {
|
|
109
|
+
return `glassbox:trace:${traceId}`;
|
|
110
|
+
}
|
|
111
|
+
function appChannel(appId) {
|
|
112
|
+
return `glassbox:app:${appId}`;
|
|
113
|
+
}
|
|
114
|
+
function decodeEvent(fields) {
|
|
115
|
+
const raw = fields["event"];
|
|
116
|
+
if (!raw) return void 0;
|
|
117
|
+
try {
|
|
118
|
+
const parsed = JSON.parse(raw);
|
|
119
|
+
if (typeof parsed.kind === "string" && typeof parsed.at === "number") {
|
|
120
|
+
return parsed;
|
|
121
|
+
}
|
|
122
|
+
return void 0;
|
|
123
|
+
} catch {
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function parseXReadResult(raw) {
|
|
128
|
+
if (!Array.isArray(raw)) return { entries: [] };
|
|
129
|
+
const entries = [];
|
|
130
|
+
for (const stream of raw) {
|
|
131
|
+
if (!Array.isArray(stream) || stream.length < 2) continue;
|
|
132
|
+
const streamEntries = stream[1];
|
|
133
|
+
if (!Array.isArray(streamEntries)) continue;
|
|
134
|
+
for (const entry of streamEntries) {
|
|
135
|
+
if (!Array.isArray(entry) || entry.length < 2) continue;
|
|
136
|
+
const id = String(entry[0]);
|
|
137
|
+
const flat = entry[1];
|
|
138
|
+
if (!Array.isArray(flat)) continue;
|
|
139
|
+
const fields = {};
|
|
140
|
+
for (let i = 0; i < flat.length; i += 2) {
|
|
141
|
+
const k = flat[i];
|
|
142
|
+
const v = flat[i + 1];
|
|
143
|
+
if (typeof k === "string") fields[k] = String(v ?? "");
|
|
144
|
+
}
|
|
145
|
+
entries.push({ id, fields });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return { entries };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// src/glassbox/pubsub-memory.ts
|
|
152
|
+
var MemoryPubSub = class {
|
|
153
|
+
subscribers = /* @__PURE__ */ new Map();
|
|
154
|
+
async publish(channelKey, event) {
|
|
155
|
+
const subs = this.subscribers.get(channelKey);
|
|
156
|
+
if (!subs || subs.size === 0) return;
|
|
157
|
+
for (const sub of subs) {
|
|
158
|
+
if (sub.closed) continue;
|
|
159
|
+
try {
|
|
160
|
+
sub.controller.enqueue(event);
|
|
161
|
+
} catch {
|
|
162
|
+
sub.closed = true;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
this.refreshTtl(channelKey, sub);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
subscribe(channelKey) {
|
|
169
|
+
const self = this;
|
|
170
|
+
let sub;
|
|
171
|
+
return new ReadableStream({
|
|
172
|
+
start(controller) {
|
|
173
|
+
sub = {
|
|
174
|
+
controller,
|
|
175
|
+
ttlTimer: setTimeout(() => {
|
|
176
|
+
self.closeSubscriber(channelKey, sub);
|
|
177
|
+
}, GLASSBOX_STREAM_TTL_MS),
|
|
178
|
+
closed: false
|
|
179
|
+
};
|
|
180
|
+
let set = self.subscribers.get(channelKey);
|
|
181
|
+
if (!set) {
|
|
182
|
+
set = /* @__PURE__ */ new Set();
|
|
183
|
+
self.subscribers.set(channelKey, set);
|
|
184
|
+
}
|
|
185
|
+
set.add(sub);
|
|
186
|
+
},
|
|
187
|
+
cancel() {
|
|
188
|
+
if (sub) self.removeSubscriber(channelKey, sub);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Refresh the rolling TTL for a subscriber after an event lands. Replaces
|
|
194
|
+
* the existing timer with a fresh 60s one.
|
|
195
|
+
*/
|
|
196
|
+
refreshTtl(channelKey, sub) {
|
|
197
|
+
clearTimeout(sub.ttlTimer);
|
|
198
|
+
sub.ttlTimer = setTimeout(() => {
|
|
199
|
+
this.closeSubscriber(channelKey, sub);
|
|
200
|
+
}, GLASSBOX_STREAM_TTL_MS);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Close the subscriber's stream cleanly and remove from the fan-out set.
|
|
204
|
+
* Idempotent — safe to call multiple times.
|
|
205
|
+
*/
|
|
206
|
+
closeSubscriber(channelKey, sub) {
|
|
207
|
+
if (sub.closed) return;
|
|
208
|
+
sub.closed = true;
|
|
209
|
+
clearTimeout(sub.ttlTimer);
|
|
210
|
+
try {
|
|
211
|
+
sub.controller.close();
|
|
212
|
+
} catch {
|
|
213
|
+
}
|
|
214
|
+
this.removeSubscriber(channelKey, sub);
|
|
215
|
+
}
|
|
216
|
+
removeSubscriber(channelKey, sub) {
|
|
217
|
+
clearTimeout(sub.ttlTimer);
|
|
218
|
+
const set = this.subscribers.get(channelKey);
|
|
219
|
+
if (!set) return;
|
|
220
|
+
set.delete(sub);
|
|
221
|
+
if (set.size === 0) this.subscribers.delete(channelKey);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Test-only reset. Tears down all subscribers, clears all state. Calling
|
|
225
|
+
* outside of tests is harmless but cancels every active stream.
|
|
226
|
+
*/
|
|
227
|
+
_reset() {
|
|
228
|
+
for (const [, set] of this.subscribers) {
|
|
229
|
+
for (const sub of set) {
|
|
230
|
+
this.closeSubscriber("", sub);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
this.subscribers.clear();
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// src/glassbox/emit.ts
|
|
238
|
+
var activePubSub;
|
|
239
|
+
function getPubSub() {
|
|
240
|
+
if (activePubSub) return activePubSub;
|
|
241
|
+
const url = readEnv("UPSTASH_REDIS_URL");
|
|
242
|
+
const token = readEnv("UPSTASH_REDIS_TOKEN");
|
|
243
|
+
if (url && token) {
|
|
244
|
+
activePubSub = new UpstashPubSub({ url, token });
|
|
245
|
+
} else {
|
|
246
|
+
activePubSub = new MemoryPubSub();
|
|
247
|
+
}
|
|
248
|
+
return activePubSub;
|
|
249
|
+
}
|
|
250
|
+
function readEnv(key) {
|
|
251
|
+
try {
|
|
252
|
+
if (typeof process !== "undefined" && process.env) {
|
|
253
|
+
const v = process.env[key];
|
|
254
|
+
return v && v.trim() !== "" ? v : void 0;
|
|
255
|
+
}
|
|
256
|
+
} catch {
|
|
257
|
+
}
|
|
258
|
+
return void 0;
|
|
259
|
+
}
|
|
260
|
+
function emitGlassboxEvent(traceId, appId, kind, data) {
|
|
261
|
+
if (!traceId) return;
|
|
262
|
+
const event = { kind, at: Date.now(), data };
|
|
263
|
+
const ps = getPubSub();
|
|
264
|
+
try {
|
|
265
|
+
const p1 = ps.publish(traceChannel(traceId), event);
|
|
266
|
+
if (p1 && typeof p1.then === "function") {
|
|
267
|
+
p1.catch(() => {
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
} catch {
|
|
271
|
+
}
|
|
272
|
+
if (appId) {
|
|
273
|
+
try {
|
|
274
|
+
const p2 = ps.publish(appChannel(appId), event);
|
|
275
|
+
if (p2 && typeof p2.then === "function") {
|
|
276
|
+
p2.catch(() => {
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
} catch {
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function emitCompileStart(traceId, appId, data) {
|
|
284
|
+
emitGlassboxEvent(traceId, appId, "compile.start", data);
|
|
285
|
+
}
|
|
286
|
+
function emitCompileDone(traceId, appId, data) {
|
|
287
|
+
emitGlassboxEvent(traceId, appId, "compile.done", data);
|
|
288
|
+
}
|
|
289
|
+
function emitExecuteAttempt(traceId, appId, data) {
|
|
290
|
+
emitGlassboxEvent(traceId, appId, "execute.attempt", data);
|
|
291
|
+
}
|
|
292
|
+
function emitExecuteSuccess(traceId, appId, data) {
|
|
293
|
+
emitGlassboxEvent(traceId, appId, "execute.success", data);
|
|
294
|
+
}
|
|
295
|
+
function emitAdvisoryFired(traceId, appId, data) {
|
|
296
|
+
emitGlassboxEvent(traceId, appId, "advisory.fired", data);
|
|
297
|
+
}
|
|
298
|
+
function emitFallbackWalked(traceId, appId, data) {
|
|
299
|
+
emitGlassboxEvent(traceId, appId, "fallback.walked", data);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export {
|
|
303
|
+
GLASSBOX_STREAM_TTL_MS,
|
|
304
|
+
traceChannel,
|
|
305
|
+
appChannel,
|
|
306
|
+
getPubSub,
|
|
307
|
+
emitCompileStart,
|
|
308
|
+
emitCompileDone,
|
|
309
|
+
emitExecuteAttempt,
|
|
310
|
+
emitExecuteSuccess,
|
|
311
|
+
emitAdvisoryFired,
|
|
312
|
+
emitFallbackWalked
|
|
313
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// src/glassbox-routes/format.ts
|
|
2
|
+
function formatAgo(iso, now = Date.now()) {
|
|
3
|
+
const t = Date.parse(iso);
|
|
4
|
+
if (Number.isNaN(t)) return iso;
|
|
5
|
+
const sec = Math.max(0, Math.floor((now - t) / 1e3));
|
|
6
|
+
if (sec < 60) return `${sec}s ago`;
|
|
7
|
+
if (sec < 3600) return `${Math.floor(sec / 60)}m ago`;
|
|
8
|
+
if (sec < 86400) return `${Math.floor(sec / 3600)}h ago`;
|
|
9
|
+
return `${Math.floor(sec / 86400)}d ago`;
|
|
10
|
+
}
|
|
11
|
+
function shortTraceId(traceId) {
|
|
12
|
+
return traceId.slice(-6);
|
|
13
|
+
}
|
|
14
|
+
function formatCost(usd) {
|
|
15
|
+
if (usd === void 0 || usd === null || Number.isNaN(usd)) return "\u2014";
|
|
16
|
+
if (usd === 0) return "$0.0000";
|
|
17
|
+
if (usd < 0.01) return `$${usd.toFixed(4)}`;
|
|
18
|
+
return `$${usd.toFixed(3)}`;
|
|
19
|
+
}
|
|
20
|
+
function formatMs(ms) {
|
|
21
|
+
if (ms === void 0 || ms === null) return "\u2014";
|
|
22
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
23
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
24
|
+
}
|
|
25
|
+
function formatOrDash(v) {
|
|
26
|
+
if (v === void 0 || v === null) return "\u2014";
|
|
27
|
+
if (typeof v === "number") return v.toLocaleString();
|
|
28
|
+
return v;
|
|
29
|
+
}
|
|
30
|
+
function inputRatioLabel(status) {
|
|
31
|
+
switch (status) {
|
|
32
|
+
case "green":
|
|
33
|
+
return "healthy";
|
|
34
|
+
case "yellow":
|
|
35
|
+
return "borderline";
|
|
36
|
+
case "red":
|
|
37
|
+
return "input-heavy";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function formatMutation(mutation) {
|
|
41
|
+
const m = /^(.*)-(\d+)-to-(\d+)$/.exec(mutation);
|
|
42
|
+
if (m) {
|
|
43
|
+
return `${m[1]} (${m[2]} \u2192 ${m[3]})`;
|
|
44
|
+
}
|
|
45
|
+
return mutation;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
formatAgo,
|
|
50
|
+
shortTraceId,
|
|
51
|
+
formatCost,
|
|
52
|
+
formatMs,
|
|
53
|
+
formatOrDash,
|
|
54
|
+
inputRatioLabel,
|
|
55
|
+
formatMutation
|
|
56
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appChannel,
|
|
3
|
+
getPubSub,
|
|
4
|
+
traceChannel
|
|
5
|
+
} from "./chunk-NBO4R5PC.mjs";
|
|
6
|
+
|
|
7
|
+
// src/glassbox/subscribe.ts
|
|
8
|
+
function emptyStream() {
|
|
9
|
+
return new ReadableStream({
|
|
10
|
+
start(controller) {
|
|
11
|
+
controller.close();
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function subscribe(traceId) {
|
|
16
|
+
if (!traceId) return emptyStream();
|
|
17
|
+
return getPubSub().subscribe(traceChannel(traceId));
|
|
18
|
+
}
|
|
19
|
+
function subscribeApp({
|
|
20
|
+
appId
|
|
21
|
+
}) {
|
|
22
|
+
if (!appId) return emptyStream();
|
|
23
|
+
return getPubSub().subscribe(appChannel(appId));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
subscribe,
|
|
28
|
+
subscribeApp
|
|
29
|
+
};
|