@warlock.js/devtools 5.31.0 → 5.33.0
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/CHANGELOG.md +15 -0
- package/cjs/ai-source-lia4YS30.cjs +212 -0
- package/cjs/ai-source-lia4YS30.cjs.map +1 -0
- package/cjs/index.cjs +2 -727
- package/cjs/{server-CQ0qhO8c.cjs → server-BNlyhwiR.cjs} +62 -3
- package/cjs/server-BNlyhwiR.cjs.map +1 -0
- package/cjs/src-CiNStw0i.cjs +699 -0
- package/cjs/src-CiNStw0i.cjs.map +1 -0
- package/esm/caller-location.mjs.map +1 -1
- package/esm/devtools-connector.d.mts +2 -4
- package/esm/devtools-connector.d.mts.map +1 -1
- package/esm/devtools-connector.mjs +6 -0
- package/esm/devtools-connector.mjs.map +1 -1
- package/esm/index.d.mts +2 -1
- package/esm/process-panel.mjs +16 -0
- package/esm/process-panel.mjs.map +1 -0
- package/esm/server/ai-routes.mjs +32 -0
- package/esm/server/ai-routes.mjs.map +1 -0
- package/esm/server/guard.mjs +1 -1
- package/esm/server/guard.mjs.map +1 -1
- package/esm/server/index.mjs +4 -0
- package/esm/server/index.mjs.map +1 -1
- package/esm/server/process-routes.mjs +11 -0
- package/esm/server/process-routes.mjs.map +1 -0
- package/esm/server/requests-routes.mjs +1 -0
- package/esm/server/requests-routes.mjs.map +1 -1
- package/esm/server/stream-route.mjs +4 -0
- package/esm/server/stream-route.mjs.map +1 -1
- package/esm/sources/ai-source.d.mts +29 -0
- package/esm/sources/ai-source.d.mts.map +1 -0
- package/esm/sources/ai-source.mjs +136 -0
- package/esm/sources/ai-source.mjs.map +1 -0
- package/esm/sources/log-source.mjs +1 -1
- package/esm/sources/query-source.mjs +1 -1
- package/esm/types.d.mts +45 -30
- package/esm/types.d.mts.map +1 -1
- package/esm/ui-root.mjs.map +1 -1
- package/llms-full.txt +85 -1
- package/llms.txt +1 -1
- package/package.json +9 -5
- package/skills/devtools-overview/SKILL.md +85 -1
- package/ui/app.css +13 -0
- package/ui/app.js +213 -16
- package/ui/index.html +2 -0
- package/cjs/index.cjs.map +0 -1
- package/cjs/server-CQ0qhO8c.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@ All notable changes to `@warlock.js/devtools` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
6
|
|
|
7
|
+
## 5.33.0 - 2026-10-19
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- AI panel at `/__warlock` and AI runs in HTTP request details, powered by optional `@warlock.js/ai-panoptic`: model, token/cache usage, historical cost, provider cache-hit trips, tool timings, retries, truncation and compaction metadata.
|
|
12
|
+
- Read-only AI list/detail endpoints and `ai` stream updates behind the existing development/loopback guard, with install guidance when Panoptic is unavailable.
|
|
13
|
+
- Bounded content-free trace retention, request-local correlation and cleanup with the dashboard Clear action and connector shutdown; application exporter/cache stores remain independent.
|
|
14
|
+
- Add a read-only Processes panel and guarded `/api/processes` endpoint, discovering the application registration generated by `warlock add process` only in development.
|
|
15
|
+
|
|
16
|
+
## 5.32.0 - 2026-10-18
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Pin the package development compiler to TypeScript 7.0.2 and use explicit Node types and source roots with supported module resolution.
|
|
21
|
+
|
|
7
22
|
## 5.31.0 - 2026-10-18
|
|
8
23
|
|
|
9
24
|
### Changed
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
//#region ../../packages/devtools/src/safe-value.ts
|
|
2
|
+
const MAX_DEPTH = 6;
|
|
3
|
+
/**
|
|
4
|
+
* A JSON-safe snapshot of a value devtools keeps for later display.
|
|
5
|
+
*
|
|
6
|
+
* Log contexts and phase attributes are app data: they can hold live objects
|
|
7
|
+
* (a request, its socket) whose graphs are circular and which must not be kept
|
|
8
|
+
* alive by the collector anyway. Plain objects and arrays are copied; anything
|
|
9
|
+
* with a `toJSON()` is serialized through it; other class instances collapse
|
|
10
|
+
* to `[ClassName]`, cycles to `[Circular]`, and nesting past a fixed depth to
|
|
11
|
+
* `[Object]` / `[Array]`.
|
|
12
|
+
*/
|
|
13
|
+
function toSafeValue(value) {
|
|
14
|
+
return snapshot(value, 0, /* @__PURE__ */ new WeakSet());
|
|
15
|
+
}
|
|
16
|
+
function snapshot(value, depth, seen) {
|
|
17
|
+
if (value === null || value === void 0) return value;
|
|
18
|
+
switch (typeof value) {
|
|
19
|
+
case "string":
|
|
20
|
+
case "number":
|
|
21
|
+
case "boolean": return value;
|
|
22
|
+
case "bigint": return value.toString();
|
|
23
|
+
case "symbol": return value.toString();
|
|
24
|
+
case "function": return;
|
|
25
|
+
}
|
|
26
|
+
const object = value;
|
|
27
|
+
if (seen.has(object)) return "[Circular]";
|
|
28
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString();
|
|
29
|
+
if (value instanceof Error) return {
|
|
30
|
+
name: value.name,
|
|
31
|
+
message: value.message
|
|
32
|
+
};
|
|
33
|
+
if (depth >= MAX_DEPTH) return Array.isArray(value) ? "[Array]" : "[Object]";
|
|
34
|
+
seen.add(object);
|
|
35
|
+
try {
|
|
36
|
+
if (Array.isArray(value)) return value.map((item) => snapshot(item, depth + 1, seen));
|
|
37
|
+
const prototype = Object.getPrototypeOf(object);
|
|
38
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
39
|
+
const toJSON = object.toJSON;
|
|
40
|
+
if (typeof toJSON === "function") try {
|
|
41
|
+
return snapshot(toJSON.call(object), depth + 1, seen);
|
|
42
|
+
} catch {
|
|
43
|
+
return `[${constructorName(object)}]`;
|
|
44
|
+
}
|
|
45
|
+
return `[${constructorName(object)}]`;
|
|
46
|
+
}
|
|
47
|
+
const copy = {};
|
|
48
|
+
for (const [key, entry] of Object.entries(object)) {
|
|
49
|
+
const safe = snapshot(entry, depth + 1, seen);
|
|
50
|
+
if (safe !== void 0) copy[key] = safe;
|
|
51
|
+
}
|
|
52
|
+
return copy;
|
|
53
|
+
} finally {
|
|
54
|
+
seen.delete(object);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function constructorName(object) {
|
|
58
|
+
return object.constructor?.name || "Object";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region ../../packages/devtools/src/sources/ai-source.ts
|
|
63
|
+
const AI_INSTALL_GUIDANCE = "Install @warlock.js/ai and @warlock.js/ai-panoptic, then restart warlock dev. Import @warlock.js/ai-panoptic and enable ai.config({ panoptic: { observeAll: true } }). If already installed, check that both packages are compatible and can be loaded.";
|
|
64
|
+
/** Summaries use root usage once: nested spans already roll up into it. */
|
|
65
|
+
function summarizeAiTrace(trace, cost) {
|
|
66
|
+
const models = /* @__PURE__ */ new Set();
|
|
67
|
+
let toolCalls = 0;
|
|
68
|
+
let retries = 0;
|
|
69
|
+
let cacheHits;
|
|
70
|
+
let incomplete = false;
|
|
71
|
+
let truncatedTrips = 0;
|
|
72
|
+
let compactions = 0;
|
|
73
|
+
let skippedCompactions = 0;
|
|
74
|
+
let providerCompactions = 0;
|
|
75
|
+
const visit = (span) => {
|
|
76
|
+
const attributes = span.attributes ?? {};
|
|
77
|
+
const model = attributes["agent.model.name"];
|
|
78
|
+
const provider = attributes["agent.model.provider"];
|
|
79
|
+
if (typeof model === "string") models.add(typeof provider === "string" ? `${provider}/${model}` : model);
|
|
80
|
+
if (span.type === "tool") toolCalls += 1;
|
|
81
|
+
if (typeof attributes.retries === "number") retries += attributes.retries;
|
|
82
|
+
if (typeof attributes["agent.cacheHits"] === "number") cacheHits = (cacheHits ?? 0) + attributes["agent.cacheHits"];
|
|
83
|
+
if (typeof attributes["agent.truncatedTrips"] === "number") truncatedTrips += attributes["agent.truncatedTrips"];
|
|
84
|
+
if (typeof attributes["agent.providerCompactions"] === "number") providerCompactions += attributes["agent.providerCompactions"];
|
|
85
|
+
if (Array.isArray(attributes["agent.compactions"])) {
|
|
86
|
+
const records = attributes["agent.compactions"];
|
|
87
|
+
for (const record of records) {
|
|
88
|
+
if (typeof record !== "object" || record === null || !("type" in record)) continue;
|
|
89
|
+
if (record.type === "applied") compactions += 1;
|
|
90
|
+
if (record.type === "skipped") skippedCompactions += 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
incomplete ||= span.status === "incomplete" || span.error?.type === "AgentIncompleteError" || span.error?.type === "AGENT_INCOMPLETE";
|
|
94
|
+
span.children.forEach(visit);
|
|
95
|
+
};
|
|
96
|
+
visit(trace.root);
|
|
97
|
+
return {
|
|
98
|
+
traceId: trace.traceId,
|
|
99
|
+
requestId: trace.requestId,
|
|
100
|
+
sessionId: trace.sessionId,
|
|
101
|
+
name: trace.root.name,
|
|
102
|
+
status: trace.root.status,
|
|
103
|
+
startedAt: trace.startedAt,
|
|
104
|
+
duration: trace.duration,
|
|
105
|
+
usage: trace.usage,
|
|
106
|
+
cost,
|
|
107
|
+
models: [...models],
|
|
108
|
+
toolCalls,
|
|
109
|
+
retries,
|
|
110
|
+
cacheHits,
|
|
111
|
+
incomplete,
|
|
112
|
+
truncatedTrips,
|
|
113
|
+
compactions,
|
|
114
|
+
skippedCompactions,
|
|
115
|
+
providerCompactions
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Content-free snapshot; never retain prompts, completions or tool arguments/results. */
|
|
119
|
+
function snapshotSpan(span) {
|
|
120
|
+
return {
|
|
121
|
+
spanId: span.spanId,
|
|
122
|
+
parentSpanId: span.parentSpanId,
|
|
123
|
+
traceId: span.traceId,
|
|
124
|
+
sessionId: span.sessionId,
|
|
125
|
+
name: span.name,
|
|
126
|
+
version: span.version,
|
|
127
|
+
type: span.type,
|
|
128
|
+
status: span.status,
|
|
129
|
+
startedAt: span.startedAt,
|
|
130
|
+
endedAt: span.endedAt,
|
|
131
|
+
duration: span.duration,
|
|
132
|
+
usage: structuredClone(span.usage),
|
|
133
|
+
error: span.error ? {
|
|
134
|
+
type: span.error.type,
|
|
135
|
+
message: span.error.message
|
|
136
|
+
} : void 0,
|
|
137
|
+
attributes: toSafeValue(span.attributes),
|
|
138
|
+
children: span.children.map(snapshotSpan)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Optional, lazy integration. Retains only traces collected after devtools boots,
|
|
143
|
+
* using Panoptic's bounded query store; existing exporter/cache stores stay independent.
|
|
144
|
+
*/
|
|
145
|
+
async function attachAiSource(capacity) {
|
|
146
|
+
let panoptic;
|
|
147
|
+
try {
|
|
148
|
+
panoptic = await import("@warlock.js/ai-panoptic");
|
|
149
|
+
if (typeof panoptic.subscribeTraces !== "function") throw new Error("Trace subscription unavailable");
|
|
150
|
+
} catch {
|
|
151
|
+
return {
|
|
152
|
+
available: false,
|
|
153
|
+
message: AI_INSTALL_GUIDANCE,
|
|
154
|
+
dispose() {}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const { currentRequestId } = await Promise.resolve().then(() => require("./src-CiNStw0i.cjs")).then((n) => n.current_request_id_exports);
|
|
158
|
+
const store = panoptic.createInMemoryTraceStore({ capacity });
|
|
159
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
160
|
+
const detach = panoptic.subscribeTraces((trace) => {
|
|
161
|
+
const requestId = currentRequestId() ?? trace.requestId;
|
|
162
|
+
store.add({
|
|
163
|
+
...trace,
|
|
164
|
+
requestId,
|
|
165
|
+
usage: structuredClone(trace.usage),
|
|
166
|
+
root: snapshotSpan(trace.root)
|
|
167
|
+
});
|
|
168
|
+
for (const listener of listeners) try {
|
|
169
|
+
listener({
|
|
170
|
+
traceId: trace.traceId,
|
|
171
|
+
requestId
|
|
172
|
+
});
|
|
173
|
+
} catch {}
|
|
174
|
+
});
|
|
175
|
+
return {
|
|
176
|
+
available: true,
|
|
177
|
+
store,
|
|
178
|
+
summarize: (trace) => summarizeAiTrace(trace, panoptic.totalCostUsd(trace.usage)),
|
|
179
|
+
subscribe(listener) {
|
|
180
|
+
listeners.add(listener);
|
|
181
|
+
return () => {
|
|
182
|
+
listeners.delete(listener);
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
dispose() {
|
|
186
|
+
detach();
|
|
187
|
+
listeners.clear();
|
|
188
|
+
store.clear();
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//#endregion
|
|
194
|
+
Object.defineProperty(exports, "AI_INSTALL_GUIDANCE", {
|
|
195
|
+
enumerable: true,
|
|
196
|
+
get: function () {
|
|
197
|
+
return AI_INSTALL_GUIDANCE;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
Object.defineProperty(exports, "attachAiSource", {
|
|
201
|
+
enumerable: true,
|
|
202
|
+
get: function () {
|
|
203
|
+
return attachAiSource;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
Object.defineProperty(exports, "toSafeValue", {
|
|
207
|
+
enumerable: true,
|
|
208
|
+
get: function () {
|
|
209
|
+
return toSafeValue;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
//# sourceMappingURL=ai-source-lia4YS30.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-source-lia4YS30.cjs","names":[],"sources":["../../../../../../../packages/devtools/src/safe-value.ts","../../../../../../../packages/devtools/src/sources/ai-source.ts"],"sourcesContent":["const MAX_DEPTH = 6;\n\n/**\n * A JSON-safe snapshot of a value devtools keeps for later display.\n *\n * Log contexts and phase attributes are app data: they can hold live objects\n * (a request, its socket) whose graphs are circular and which must not be kept\n * alive by the collector anyway. Plain objects and arrays are copied; anything\n * with a `toJSON()` is serialized through it; other class instances collapse\n * to `[ClassName]`, cycles to `[Circular]`, and nesting past a fixed depth to\n * `[Object]` / `[Array]`.\n */\nexport function toSafeValue(value: unknown): unknown {\n return snapshot(value, 0, new WeakSet());\n}\n\nfunction snapshot(value: unknown, depth: number, seen: WeakSet<object>): unknown {\n if (value === null || value === undefined) return value;\n\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n return value;\n case \"bigint\":\n return value.toString();\n case \"symbol\":\n return value.toString();\n case \"function\":\n return undefined;\n }\n\n const object = value as object;\n\n if (seen.has(object)) return \"[Circular]\";\n if (value instanceof Date)\n return Number.isNaN(value.getTime()) ? \"Invalid Date\" : value.toISOString();\n if (value instanceof Error) return { name: value.name, message: value.message };\n\n if (depth >= MAX_DEPTH) return Array.isArray(value) ? \"[Array]\" : \"[Object]\";\n\n seen.add(object);\n\n try {\n if (Array.isArray(value)) return value.map((item) => snapshot(item, depth + 1, seen));\n\n const prototype = Object.getPrototypeOf(object);\n\n if (prototype !== Object.prototype && prototype !== null) {\n const toJSON = (object as { toJSON?: unknown }).toJSON;\n\n if (typeof toJSON === \"function\") {\n try {\n return snapshot(toJSON.call(object), depth + 1, seen);\n } catch {\n return `[${constructorName(object)}]`;\n }\n }\n\n return `[${constructorName(object)}]`;\n }\n\n const copy: Record<string, unknown> = {};\n\n for (const [key, entry] of Object.entries(object)) {\n const safe = snapshot(entry, depth + 1, seen);\n if (safe !== undefined) copy[key] = safe;\n }\n\n return copy;\n } finally {\n seen.delete(object);\n }\n}\n\nfunction constructorName(object: object): string {\n return (object as { constructor?: { name?: string } }).constructor?.name || \"Object\";\n}\n","import type { Trace, TraceSpan, TraceStoreContract } from \"@warlock.js/ai-panoptic\";\nimport { toSafeValue } from \"../safe-value\";\nimport type { DevtoolsDisposer } from \"../types\";\n\nexport const AI_INSTALL_GUIDANCE =\n \"Install @warlock.js/ai and @warlock.js/ai-panoptic, then restart warlock dev. Import @warlock.js/ai-panoptic and enable ai.config({ panoptic: { observeAll: true } }). If already installed, check that both packages are compatible and can be loaded.\";\n\nexport type DevtoolsAiEvent = { traceId: string; requestId?: string };\n\n/** Only the connector's development branch constructs this source. */\nexport type DevtoolsAiSource =\n | { available: false; message: string; dispose: DevtoolsDisposer }\n | {\n available: true;\n store: TraceStoreContract;\n summarize: (trace: Trace) => DevtoolsAiRun;\n subscribe: (listener: (event: DevtoolsAiEvent) => void) => DevtoolsDisposer;\n dispose: DevtoolsDisposer;\n };\n\nexport type DevtoolsAiRun = {\n traceId: string;\n requestId?: string;\n sessionId?: string;\n name: string;\n status: TraceSpan[\"status\"];\n startedAt: string;\n duration: number;\n usage: Trace[\"usage\"];\n cost?: number;\n models: string[];\n toolCalls: number;\n retries: number;\n cacheHits?: number;\n incomplete: boolean;\n truncatedTrips: number;\n compactions: number;\n skippedCompactions: number;\n providerCompactions: number;\n};\n\n/** Summaries use root usage once: nested spans already roll up into it. */\nexport function summarizeAiTrace(trace: Trace, cost?: number): DevtoolsAiRun {\n const models = new Set<string>();\n let toolCalls = 0;\n let retries = 0;\n let cacheHits: number | undefined;\n let incomplete = false;\n let truncatedTrips = 0;\n let compactions = 0;\n let skippedCompactions = 0;\n let providerCompactions = 0;\n const visit = (span: TraceSpan): void => {\n const attributes = span.attributes ?? {};\n const model = attributes[\"agent.model.name\"];\n const provider = attributes[\"agent.model.provider\"];\n if (typeof model === \"string\")\n models.add(typeof provider === \"string\" ? `${provider}/${model}` : model);\n if (span.type === \"tool\") toolCalls += 1;\n if (typeof attributes.retries === \"number\") retries += attributes.retries;\n if (typeof attributes[\"agent.cacheHits\"] === \"number\")\n cacheHits = (cacheHits ?? 0) + attributes[\"agent.cacheHits\"];\n if (typeof attributes[\"agent.truncatedTrips\"] === \"number\")\n truncatedTrips += attributes[\"agent.truncatedTrips\"];\n if (typeof attributes[\"agent.providerCompactions\"] === \"number\")\n providerCompactions += attributes[\"agent.providerCompactions\"];\n if (Array.isArray(attributes[\"agent.compactions\"])) {\n const records: unknown[] = attributes[\"agent.compactions\"];\n for (const record of records) {\n if (typeof record !== \"object\" || record === null || !(\"type\" in record)) continue;\n if (record.type === \"applied\") compactions += 1;\n if (record.type === \"skipped\") skippedCompactions += 1;\n }\n }\n incomplete ||=\n span.status === \"incomplete\" ||\n span.error?.type === \"AgentIncompleteError\" ||\n span.error?.type === \"AGENT_INCOMPLETE\";\n span.children.forEach(visit);\n };\n visit(trace.root);\n return {\n traceId: trace.traceId,\n requestId: trace.requestId,\n sessionId: trace.sessionId,\n name: trace.root.name,\n status: trace.root.status,\n startedAt: trace.startedAt,\n duration: trace.duration,\n usage: trace.usage,\n cost,\n models: [...models],\n toolCalls,\n retries,\n cacheHits,\n incomplete,\n truncatedTrips,\n compactions,\n skippedCompactions,\n providerCompactions,\n };\n}\n\n/** Content-free snapshot; never retain prompts, completions or tool arguments/results. */\nfunction snapshotSpan(span: TraceSpan): TraceSpan {\n return {\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n traceId: span.traceId,\n sessionId: span.sessionId,\n name: span.name,\n version: span.version,\n type: span.type,\n status: span.status,\n startedAt: span.startedAt,\n endedAt: span.endedAt,\n duration: span.duration,\n usage: structuredClone(span.usage),\n error: span.error ? { type: span.error.type, message: span.error.message } : undefined,\n attributes: toSafeValue(span.attributes) as Record<string, unknown> | undefined,\n children: span.children.map(snapshotSpan),\n };\n}\n\n/**\n * Optional, lazy integration. Retains only traces collected after devtools boots,\n * using Panoptic's bounded query store; existing exporter/cache stores stay independent.\n */\nexport async function attachAiSource(capacity: number): Promise<DevtoolsAiSource> {\n let panoptic: typeof import(\"@warlock.js/ai-panoptic\");\n try {\n panoptic = await import(\"@warlock.js/ai-panoptic\");\n if (typeof panoptic.subscribeTraces !== \"function\")\n throw new Error(\"Trace subscription unavailable\");\n } catch {\n return { available: false, message: AI_INSTALL_GUIDANCE, dispose() {} };\n }\n\n const { currentRequestId } = await import(\"../current-request-id\");\n const store = panoptic.createInMemoryTraceStore({ capacity });\n const listeners = new Set<(event: DevtoolsAiEvent) => void>();\n const detach = panoptic.subscribeTraces((trace) => {\n // Read ALS before any asynchronous exporter work, including for runs that\n // finish after the HTTP response. Never use sessionId as a request id.\n const requestId = currentRequestId() ?? trace.requestId;\n store.add({\n ...trace,\n requestId,\n usage: structuredClone(trace.usage),\n root: snapshotSpan(trace.root),\n });\n for (const listener of listeners) {\n try {\n listener({ traceId: trace.traceId, requestId });\n } catch {\n /* isolate clients */\n }\n }\n });\n\n return {\n available: true,\n store,\n summarize: (trace) => summarizeAiTrace(trace, panoptic.totalCostUsd(trace.usage)),\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n dispose() {\n detach();\n listeners.clear();\n store.clear();\n },\n };\n}\n"],"mappings":"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"}
|