@mtharrison/loupe 1.0.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/dist/store.js ADDED
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TraceStore = void 0;
4
+ const node_events_1 = require("node:events");
5
+ const utils_1 = require("./utils");
6
+ class TraceStore extends node_events_1.EventEmitter {
7
+ maxTraces;
8
+ order;
9
+ traces;
10
+ constructor(options = {}) {
11
+ super();
12
+ this.maxTraces = Math.max(1, Number(options.maxTraces) || 1000);
13
+ this.order = [];
14
+ this.traces = new Map();
15
+ }
16
+ recordInvokeStart(context, request) {
17
+ return this.recordStart('invoke', context, request);
18
+ }
19
+ recordInvokeFinish(traceId, response) {
20
+ const trace = this.traces.get(traceId);
21
+ if (!trace) {
22
+ return;
23
+ }
24
+ trace.response = (0, utils_1.safeClone)(response);
25
+ trace.usage = (0, utils_1.safeClone)(response?.usage);
26
+ trace.status = 'ok';
27
+ trace.endedAt = new Date().toISOString();
28
+ this.publish('trace:update', traceId, { trace: this.cloneTrace(trace) });
29
+ }
30
+ recordStreamStart(context, request) {
31
+ return this.recordStart('stream', context, request);
32
+ }
33
+ recordStreamChunk(traceId, chunk) {
34
+ const trace = this.traces.get(traceId);
35
+ if (!trace || !trace.stream) {
36
+ return;
37
+ }
38
+ const clone = (0, utils_1.safeClone)(chunk);
39
+ if (clone && typeof clone === 'object') {
40
+ clone.offsetMs = Math.max(0, Date.now() - Date.parse(trace.startedAt));
41
+ }
42
+ trace.stream.events.push(clone);
43
+ if (chunk?.type === 'chunk') {
44
+ trace.stream.chunkCount += 1;
45
+ if (trace.stream.firstChunkMs === null) {
46
+ trace.stream.firstChunkMs = Date.now() - Date.parse(trace.startedAt);
47
+ }
48
+ if (typeof chunk.content === 'string') {
49
+ trace.stream.reconstructed.message.content = `${trace.stream.reconstructed.message.content || ''}${chunk.content}`;
50
+ }
51
+ }
52
+ if (chunk?.type === 'begin') {
53
+ trace.stream.reconstructed.message.role = chunk.role;
54
+ }
55
+ if (chunk?.type === 'finish') {
56
+ trace.response = clone;
57
+ trace.usage = (0, utils_1.safeClone)(chunk.usage);
58
+ trace.stream.reconstructed.message = {
59
+ ...((0, utils_1.safeClone)(chunk.message) || {}),
60
+ content: trace.stream.reconstructed.message.content ||
61
+ (typeof chunk.message?.content === 'string' ? chunk.message.content : chunk.message?.content ?? null),
62
+ };
63
+ trace.stream.reconstructed.tool_calls = (0, utils_1.safeClone)(chunk.tool_calls || []);
64
+ trace.stream.reconstructed.usage = (0, utils_1.safeClone)(chunk.usage || null);
65
+ trace.status = 'ok';
66
+ trace.endedAt = new Date().toISOString();
67
+ }
68
+ this.publish('trace:update', traceId, { trace: this.cloneTrace(trace) });
69
+ }
70
+ recordStreamFinish(traceId, chunk) {
71
+ this.recordStreamChunk(traceId, chunk);
72
+ }
73
+ recordError(traceId, error) {
74
+ const trace = this.traces.get(traceId);
75
+ if (!trace) {
76
+ return;
77
+ }
78
+ trace.error = (0, utils_1.toErrorPayload)(error);
79
+ trace.status = 'error';
80
+ trace.endedAt = new Date().toISOString();
81
+ this.publish('trace:update', traceId, { trace: this.cloneTrace(trace) });
82
+ }
83
+ list(filters = {}) {
84
+ const items = this.filteredTraces(filters).map(utils_1.toSummary);
85
+ const response = {
86
+ items,
87
+ total: this.order.length,
88
+ filtered: items.length,
89
+ };
90
+ if (filters.groupBy) {
91
+ response.groups = groupTraceSummaries(items, filters.groupBy);
92
+ }
93
+ return response;
94
+ }
95
+ get(traceId) {
96
+ const trace = this.traces.get(traceId);
97
+ return trace ? this.cloneTrace(trace) : null;
98
+ }
99
+ clear() {
100
+ this.order = [];
101
+ this.traces.clear();
102
+ this.publish('trace:clear', null, {});
103
+ }
104
+ hierarchy(filters = {}) {
105
+ const traces = this.filteredTraces(filters);
106
+ if (filters.groupBy) {
107
+ return {
108
+ total: this.order.length,
109
+ filtered: traces.length,
110
+ rootNodes: buildGroupHierarchy(traces, filters.groupBy),
111
+ };
112
+ }
113
+ const roots = new Map();
114
+ for (const trace of traces) {
115
+ const sessionId = trace.hierarchy.sessionId || 'unknown-session';
116
+ const sessionNode = getOrCreateNode(roots, `session:${sessionId}`, 'session', `Session ${sessionId}`, {
117
+ sessionId,
118
+ chatId: trace.hierarchy.chatId,
119
+ });
120
+ const lineage = [sessionNode];
121
+ const rootActorId = trace.hierarchy.rootActorId || 'unknown-actor';
122
+ const actorNode = getOrCreateNode(sessionNode.children, `actor:${sessionId}:${rootActorId}`, 'actor', rootActorId, {
123
+ actorId: rootActorId,
124
+ rootActorId,
125
+ sessionId,
126
+ topLevelAgentId: trace.hierarchy.topLevelAgentId,
127
+ });
128
+ lineage.push(actorNode);
129
+ let currentNode = actorNode;
130
+ if (trace.hierarchy.kind === 'guardrail') {
131
+ const label = `${trace.hierarchy.guardrailPhase || 'guardrail'} guardrail`;
132
+ currentNode = getOrCreateNode(currentNode.children, `guardrail:${sessionId}:${rootActorId}:${trace.context.guardrailType || label}`, 'guardrail', label, {
133
+ guardrailPhase: trace.hierarchy.guardrailPhase || null,
134
+ guardrailType: trace.context.guardrailType || null,
135
+ systemType: trace.context.systemType || null,
136
+ watchdogPhase: trace.hierarchy.watchdogPhase || null,
137
+ });
138
+ lineage.push(currentNode);
139
+ }
140
+ else if (trace.hierarchy.childActorId) {
141
+ currentNode = getOrCreateNode(currentNode.children, `child-actor:${sessionId}:${rootActorId}:${trace.hierarchy.childActorId}`, 'child-actor', trace.hierarchy.childActorId, {
142
+ actorId: trace.hierarchy.childActorId,
143
+ childActorId: trace.hierarchy.childActorId,
144
+ delegatedAgentId: trace.hierarchy.delegatedAgentId,
145
+ });
146
+ lineage.push(currentNode);
147
+ }
148
+ if (trace.hierarchy.stage) {
149
+ currentNode = getOrCreateNode(currentNode.children, `stage:${sessionId}:${rootActorId}:${trace.hierarchy.childActorId || 'root'}:${trace.hierarchy.stage}`, 'stage', trace.hierarchy.stage, {
150
+ stage: trace.hierarchy.stage,
151
+ workflowState: trace.hierarchy.workflowState,
152
+ });
153
+ lineage.push(currentNode);
154
+ }
155
+ const traceNode = createTraceNode(trace);
156
+ currentNode.children.set(traceNode.id, traceNode);
157
+ for (const node of new Set(lineage)) {
158
+ applyTraceRollup(node, trace);
159
+ }
160
+ }
161
+ return {
162
+ total: this.order.length,
163
+ filtered: traces.length,
164
+ rootNodes: [...roots.values()].map(serialiseNode),
165
+ };
166
+ }
167
+ recordStart(mode, context, request) {
168
+ const traceContext = (0, utils_1.normalizeTraceContext)(context, mode);
169
+ const traceId = randomId();
170
+ const startedAt = new Date().toISOString();
171
+ const trace = {
172
+ context: traceContext,
173
+ endedAt: null,
174
+ error: null,
175
+ hierarchy: traceContext.hierarchy,
176
+ id: traceId,
177
+ kind: traceContext.kind,
178
+ mode,
179
+ model: traceContext.model,
180
+ provider: traceContext.provider,
181
+ request: {
182
+ input: (0, utils_1.safeClone)(request?.input),
183
+ options: {
184
+ ...(request?.options ? (0, utils_1.safeClone)(request.options) : {}),
185
+ headers: (0, utils_1.sanitizeHeaders)(request?.options?.headers),
186
+ },
187
+ },
188
+ response: null,
189
+ startedAt,
190
+ status: 'pending',
191
+ stream: mode === 'stream'
192
+ ? {
193
+ chunkCount: 0,
194
+ events: [],
195
+ firstChunkMs: null,
196
+ reconstructed: {
197
+ message: { role: null, content: null },
198
+ tool_calls: [],
199
+ usage: null,
200
+ },
201
+ }
202
+ : null,
203
+ tags: traceContext.tags,
204
+ usage: null,
205
+ };
206
+ this.order.push(traceId);
207
+ this.traces.set(traceId, trace);
208
+ this.evictIfNeeded();
209
+ this.publish('trace:add', traceId, { trace: this.cloneTrace(trace) });
210
+ return traceId;
211
+ }
212
+ evictIfNeeded() {
213
+ while (this.order.length > this.maxTraces) {
214
+ const oldest = this.order.shift();
215
+ const removed = oldest ? this.traces.get(oldest) : null;
216
+ if (oldest) {
217
+ this.traces.delete(oldest);
218
+ }
219
+ this.publish('trace:evict', oldest || null, removed ? { trace: this.cloneTrace(removed) } : {});
220
+ }
221
+ }
222
+ cloneTrace(trace) {
223
+ return (0, utils_1.safeClone)(trace);
224
+ }
225
+ filteredTraces(filters = {}) {
226
+ const tagFilters = normalizeTagFilters(filters.tags || filters.tagFilters);
227
+ return this.order
228
+ .map((id) => this.traces.get(id))
229
+ .filter(Boolean)
230
+ .filter((trace) => {
231
+ if (filters.status && trace.status !== filters.status) {
232
+ return false;
233
+ }
234
+ if (filters.kind && trace.kind !== filters.kind) {
235
+ return false;
236
+ }
237
+ if (filters.model && trace.model !== filters.model) {
238
+ return false;
239
+ }
240
+ if (filters.provider && trace.provider !== filters.provider) {
241
+ return false;
242
+ }
243
+ if (filters.traceIds && !filters.traceIds.includes(trace.id)) {
244
+ return false;
245
+ }
246
+ if (tagFilters.length > 0) {
247
+ for (const [key, value] of tagFilters) {
248
+ if (trace.tags[key] !== value) {
249
+ return false;
250
+ }
251
+ }
252
+ }
253
+ if (filters.search) {
254
+ const needle = String(filters.search).toLowerCase();
255
+ const haystack = JSON.stringify({
256
+ context: trace.context,
257
+ error: trace.error,
258
+ request: trace.request,
259
+ response: trace.response,
260
+ stream: trace.stream,
261
+ tags: trace.tags,
262
+ }).toLowerCase();
263
+ if (!haystack.includes(needle)) {
264
+ return false;
265
+ }
266
+ }
267
+ return true;
268
+ })
269
+ .reverse();
270
+ }
271
+ publish(type, traceId, payload) {
272
+ const event = {
273
+ type,
274
+ traceId,
275
+ timestamp: new Date().toISOString(),
276
+ ...payload,
277
+ };
278
+ this.emit('event', event);
279
+ }
280
+ }
281
+ exports.TraceStore = TraceStore;
282
+ function groupTraceSummaries(items, groupBy) {
283
+ const groups = new Map();
284
+ for (const item of items) {
285
+ const groupValue = item.tags[groupBy] || 'ungrouped';
286
+ const group = groups.get(groupValue) || {
287
+ value: groupValue,
288
+ count: 0,
289
+ items: [],
290
+ };
291
+ group.count += 1;
292
+ group.items.push(item);
293
+ groups.set(groupValue, group);
294
+ }
295
+ return [...groups.values()];
296
+ }
297
+ function normalizeTagFilters(value) {
298
+ if (!value) {
299
+ return [];
300
+ }
301
+ const entries = Array.isArray(value) ? value : [value];
302
+ return entries
303
+ .flatMap((entry) => String(entry).split(','))
304
+ .map((entry) => entry.trim())
305
+ .filter(Boolean)
306
+ .map((entry) => {
307
+ const [key, ...rest] = entry.split(':');
308
+ return [key, rest.join(':')];
309
+ })
310
+ .filter(([key, filterValue]) => key && filterValue);
311
+ }
312
+ function getOrCreateNode(collection, id, type, label, meta = {}) {
313
+ if (!collection.has(id)) {
314
+ collection.set(id, {
315
+ id,
316
+ type,
317
+ label,
318
+ count: 0,
319
+ meta,
320
+ traceIds: [],
321
+ children: new Map(),
322
+ });
323
+ }
324
+ return collection.get(id);
325
+ }
326
+ function createTraceNode(trace) {
327
+ return {
328
+ id: `trace:${trace.id}`,
329
+ type: 'trace',
330
+ label: trace.model ? `${trace.model} ${trace.mode}` : trace.id,
331
+ count: 1,
332
+ meta: {
333
+ costUsd: (0, utils_1.getUsageCostUsd)(trace.usage),
334
+ traceId: trace.id,
335
+ status: trace.status,
336
+ provider: trace.provider,
337
+ model: trace.model,
338
+ },
339
+ traceIds: [trace.id],
340
+ children: new Map(),
341
+ };
342
+ }
343
+ function applyTraceRollup(node, trace) {
344
+ node.traceIds.push(trace.id);
345
+ node.count += 1;
346
+ const traceCost = (0, utils_1.getUsageCostUsd)(trace.usage);
347
+ if (traceCost !== null) {
348
+ node.meta.costUsd = (typeof node.meta.costUsd === 'number' ? node.meta.costUsd : 0) + traceCost;
349
+ }
350
+ }
351
+ function serialiseNode(node) {
352
+ return {
353
+ id: node.id,
354
+ type: node.type,
355
+ label: node.label,
356
+ count: node.count,
357
+ traceIds: [...node.traceIds],
358
+ meta: (0, utils_1.safeClone)(node.meta),
359
+ children: [...node.children.values()].map(serialiseNode),
360
+ };
361
+ }
362
+ function buildGroupHierarchy(traces, groupBy) {
363
+ const groups = new Map();
364
+ for (const trace of traces) {
365
+ const value = trace.tags[groupBy] || 'ungrouped';
366
+ const node = getOrCreateNode(groups, `group:${groupBy}:${value}`, 'group', `${groupBy}: ${value}`, {
367
+ groupBy,
368
+ value,
369
+ });
370
+ applyTraceRollup(node, trace);
371
+ node.children.set(`trace:${trace.id}`, createTraceNode(trace));
372
+ }
373
+ return [...groups.values()].map(serialiseNode);
374
+ }
375
+ function randomId() {
376
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
377
+ }
@@ -0,0 +1,6 @@
1
+ export type ThemeMode = 'light' | 'dark';
2
+ export declare const THEME_STORAGE_KEY = "llm-trace-theme";
3
+ export declare function isThemeMode(value: unknown): value is ThemeMode;
4
+ export declare function resolvePreferredTheme(): ThemeMode;
5
+ export declare function applyTheme(theme: ThemeMode): void;
6
+ export declare function renderThemeBootstrapScript(): string;
package/dist/theme.js ADDED
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.THEME_STORAGE_KEY = void 0;
4
+ exports.isThemeMode = isThemeMode;
5
+ exports.resolvePreferredTheme = resolvePreferredTheme;
6
+ exports.applyTheme = applyTheme;
7
+ exports.renderThemeBootstrapScript = renderThemeBootstrapScript;
8
+ exports.THEME_STORAGE_KEY = 'llm-trace-theme';
9
+ function isThemeMode(value) {
10
+ return value === 'light' || value === 'dark';
11
+ }
12
+ function resolvePreferredTheme() {
13
+ const documentRef = getDocument();
14
+ if (documentRef) {
15
+ const theme = documentRef.documentElement?.dataset?.theme;
16
+ if (isThemeMode(theme)) {
17
+ return theme;
18
+ }
19
+ }
20
+ const windowRef = getWindow();
21
+ if (windowRef) {
22
+ try {
23
+ const stored = windowRef.localStorage?.getItem(exports.THEME_STORAGE_KEY);
24
+ if (isThemeMode(stored)) {
25
+ return stored;
26
+ }
27
+ }
28
+ catch (_error) {
29
+ // Ignore storage errors and fall back to system preference.
30
+ }
31
+ if (windowRef.matchMedia?.('(prefers-color-scheme: dark)').matches) {
32
+ return 'dark';
33
+ }
34
+ }
35
+ return 'light';
36
+ }
37
+ function applyTheme(theme) {
38
+ const documentRef = getDocument();
39
+ if (documentRef) {
40
+ documentRef.documentElement.dataset.theme = theme;
41
+ documentRef.documentElement.style.colorScheme = theme;
42
+ }
43
+ const windowRef = getWindow();
44
+ if (windowRef) {
45
+ try {
46
+ windowRef.localStorage?.setItem(exports.THEME_STORAGE_KEY, theme);
47
+ }
48
+ catch (_error) {
49
+ // Ignore storage errors in local dev.
50
+ }
51
+ }
52
+ }
53
+ function renderThemeBootstrapScript() {
54
+ return `(function(){try{var key=${JSON.stringify(exports.THEME_STORAGE_KEY)};var stored=localStorage.getItem(key);var theme=(stored==='light'||stored==='dark')?stored:((window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches)?'dark':'light');document.documentElement.dataset.theme=theme;document.documentElement.style.colorScheme=theme;}catch(_err){document.documentElement.dataset.theme='light';document.documentElement.style.colorScheme='light';}})();`;
55
+ }
56
+ function getWindow() {
57
+ if (typeof globalThis !== 'object' || !('window' in globalThis)) {
58
+ return null;
59
+ }
60
+ return globalThis.window ?? null;
61
+ }
62
+ function getDocument() {
63
+ if (typeof globalThis !== 'object' || !('document' in globalThis)) {
64
+ return null;
65
+ }
66
+ return globalThis.document ?? null;
67
+ }
@@ -0,0 +1,209 @@
1
+ export type TraceMode = 'invoke' | 'stream';
2
+ export type TraceStatus = 'pending' | 'ok' | 'error';
3
+ export type TraceConfig = {
4
+ host?: string;
5
+ maxTraces?: number;
6
+ port?: number;
7
+ uiHotReload?: boolean;
8
+ };
9
+ export type TraceTags = Record<string, string>;
10
+ export type TraceContext = {
11
+ actorId?: string | null;
12
+ actorType?: string | null;
13
+ guardrailPhase?: string | null;
14
+ guardrailType?: string | null;
15
+ kind?: string | null;
16
+ model?: string | null;
17
+ parentSessionId?: string | null;
18
+ provider?: string | null;
19
+ rootActorId?: string | null;
20
+ rootSessionId?: string | null;
21
+ sessionId?: string | null;
22
+ stage?: string | null;
23
+ tags?: Record<string, string | null | undefined>;
24
+ tenantId?: string | null;
25
+ userId?: string | null;
26
+ agentId?: string | null;
27
+ chatId?: string | null;
28
+ contextType?: string | null;
29
+ parentChatId?: string | null;
30
+ rootChatId?: string | null;
31
+ systemType?: string | null;
32
+ topLevelAgentId?: string | null;
33
+ watchdogPhase?: string | null;
34
+ workflowState?: string | null;
35
+ };
36
+ export type TraceHierarchy = {
37
+ childActorId: string | null;
38
+ guardrailPhase: string | null;
39
+ guardrailType: string | null;
40
+ kind: string;
41
+ rootActorId: string;
42
+ sessionId: string;
43
+ stage: string | null;
44
+ chatId: string;
45
+ delegatedAgentId: string | null;
46
+ systemType: string | null;
47
+ topLevelAgentId: string;
48
+ watchdogPhase: string | null;
49
+ workflowState: string | null;
50
+ };
51
+ export type NormalizedTraceContext = {
52
+ actorId: string | null;
53
+ actorType: string | null;
54
+ guardrailPhase: string | null;
55
+ guardrailType: string | null;
56
+ hierarchy: TraceHierarchy;
57
+ kind: string;
58
+ model: string | null;
59
+ parentSessionId: string | null;
60
+ provider: string | null;
61
+ rootActorId: string | null;
62
+ rootSessionId: string | null;
63
+ sessionId: string | null;
64
+ stage: string | null;
65
+ tags: TraceTags;
66
+ tenantId: string | null;
67
+ userId: string | null;
68
+ agentId: string | null;
69
+ chatId: string | null;
70
+ contextType: string | null;
71
+ parentChatId: string | null;
72
+ rootChatId: string | null;
73
+ systemType: string | null;
74
+ topLevelAgentId: string | null;
75
+ watchdogPhase: string | null;
76
+ workflowState: string | null;
77
+ };
78
+ export type TraceRequest = {
79
+ input?: Record<string, any>;
80
+ options?: Record<string, any>;
81
+ };
82
+ export type TraceRecord = {
83
+ context: NormalizedTraceContext;
84
+ endedAt: string | null;
85
+ error: Record<string, any> | null;
86
+ hierarchy: TraceHierarchy;
87
+ id: string;
88
+ kind: string;
89
+ mode: TraceMode;
90
+ model: string | null;
91
+ provider: string | null;
92
+ request: {
93
+ input?: Record<string, any>;
94
+ options: Record<string, any>;
95
+ };
96
+ response: Record<string, any> | null;
97
+ startedAt: string;
98
+ status: TraceStatus;
99
+ stream: null | {
100
+ chunkCount: number;
101
+ events: Record<string, any>[];
102
+ firstChunkMs: number | null;
103
+ reconstructed: {
104
+ message: Record<string, any>;
105
+ tool_calls: Record<string, any>[];
106
+ usage: Record<string, any> | null;
107
+ };
108
+ };
109
+ tags: TraceTags;
110
+ usage: Record<string, any> | null;
111
+ };
112
+ export type TraceSummary = {
113
+ costUsd: number | null;
114
+ durationMs: number | null;
115
+ endedAt: string | null;
116
+ hierarchy: TraceHierarchy;
117
+ id: string;
118
+ kind: string;
119
+ mode: TraceMode;
120
+ model: string | null;
121
+ provider: string | null;
122
+ requestPreview: string;
123
+ responsePreview: string;
124
+ startedAt: string;
125
+ status: TraceStatus;
126
+ stream: null | {
127
+ chunkCount: number;
128
+ firstChunkMs: number | null;
129
+ };
130
+ tags: TraceTags;
131
+ };
132
+ export type TraceEvent = {
133
+ timestamp: string;
134
+ trace?: TraceRecord;
135
+ traceId: string | null;
136
+ type: string;
137
+ };
138
+ export type UIReloadEvent = {
139
+ timestamp: string;
140
+ traceId: null;
141
+ type: 'ui:reload';
142
+ };
143
+ export type TraceListResponse = {
144
+ filtered: number;
145
+ groups?: Array<{
146
+ count: number;
147
+ items: TraceSummary[];
148
+ value: string;
149
+ }>;
150
+ items: TraceSummary[];
151
+ total: number;
152
+ };
153
+ export type HierarchyNode = {
154
+ children: HierarchyNode[];
155
+ count: number;
156
+ id: string;
157
+ label: string;
158
+ meta: Record<string, any>;
159
+ traceIds: string[];
160
+ type: string;
161
+ };
162
+ export type HierarchyResponse = {
163
+ filtered: number;
164
+ rootNodes: HierarchyNode[];
165
+ total: number;
166
+ };
167
+ export type TraceFilters = {
168
+ groupBy?: string;
169
+ kind?: string;
170
+ model?: string;
171
+ provider?: string;
172
+ search?: string;
173
+ status?: string;
174
+ tagFilters?: string[];
175
+ tags?: string[];
176
+ traceIds?: string[];
177
+ };
178
+ export interface ChatModelLike<TInput = any, TOptions = any, TValue = any, TChunk = any> {
179
+ invoke(input: TInput, options?: TOptions): Promise<TValue>;
180
+ stream(input: TInput, options?: TOptions): AsyncGenerator<TChunk>;
181
+ }
182
+ export type TraceServer = {
183
+ broadcast(event: TraceEvent | UIReloadEvent): void;
184
+ close(): void;
185
+ start(): Promise<{
186
+ host: string;
187
+ port: number;
188
+ url: string;
189
+ } | null>;
190
+ };
191
+ export type UIWatchController = {
192
+ stop(): Promise<void>;
193
+ };
194
+ export type LocalLLMTracer = {
195
+ configure(config?: TraceConfig): void;
196
+ isEnabled(): boolean;
197
+ recordError(traceId: string, error: unknown): void;
198
+ recordInvokeFinish(traceId: string, response: unknown): void;
199
+ recordInvokeStart(context: TraceContext, request: TraceRequest): string;
200
+ recordStreamChunk(traceId: string, chunk: unknown): void;
201
+ recordStreamFinish(traceId: string, chunk: unknown): void;
202
+ recordStreamStart(context: TraceContext, request: TraceRequest): string;
203
+ startServer(): Promise<{
204
+ host: string;
205
+ port: number;
206
+ url: string;
207
+ } | null>;
208
+ store: any;
209
+ };
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ import { type UIWatchController } from './types';
2
+ export declare function buildUIAssets(): Promise<void>;
3
+ export declare function maybeStartUIWatcher(onReload: () => void, enabled?: boolean): Promise<UIWatchController | null>;