@rudderjs/telescope 13.0.2 → 14.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/README.md +13 -1
- package/dist/collectors/exception.d.ts +13 -0
- package/dist/collectors/exception.d.ts.map +1 -1
- package/dist/collectors/exception.js +13 -0
- package/dist/collectors/exception.js.map +1 -1
- package/dist/collectors/request.d.ts.map +1 -1
- package/dist/collectors/request.js +15 -4
- package/dist/collectors/request.js.map +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -1
- package/dist/routes.d.ts +8 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +20 -6
- package/dist/routes.js.map +1 -1
- package/dist/storage.d.ts +26 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +34 -6
- package/dist/storage.js.map +1 -1
- package/dist/stream.d.ts +23 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +96 -0
- package/dist/stream.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -1
- package/dist/views/vanilla/EntryList.d.ts +8 -0
- package/dist/views/vanilla/EntryList.d.ts.map +1 -1
- package/dist/views/vanilla/EntryList.js +62 -11
- package/dist/views/vanilla/EntryList.js.map +1 -1
- package/dist/views/vanilla/Layout.d.ts.map +1 -1
- package/dist/views/vanilla/Layout.js +6 -1
- package/dist/views/vanilla/Layout.js.map +1 -1
- package/dist/views/vanilla/details/ai-views.d.ts +16 -0
- package/dist/views/vanilla/details/ai-views.d.ts.map +1 -0
- package/dist/views/vanilla/details/ai-views.js +136 -0
- package/dist/views/vanilla/details/ai-views.js.map +1 -0
- package/dist/views/vanilla/details/format.d.ts +16 -0
- package/dist/views/vanilla/details/format.d.ts.map +1 -0
- package/dist/views/vanilla/details/format.js +45 -0
- package/dist/views/vanilla/details/format.js.map +1 -0
- package/dist/views/vanilla/details/request-views.d.ts +15 -0
- package/dist/views/vanilla/details/request-views.d.ts.map +1 -0
- package/dist/views/vanilla/details/request-views.js +135 -0
- package/dist/views/vanilla/details/request-views.js.map +1 -0
- package/dist/views/vanilla/details/views.d.ts.map +1 -1
- package/dist/views/vanilla/details/views.js +3 -295
- package/dist/views/vanilla/details/views.js.map +1 -1
- package/package.json +18 -18
package/dist/stream.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TelescopeEntry, EntryType } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Fan-out a recorded entry to every connected dashboard. Called from
|
|
4
|
+
* `Telescope.record()` after the recording-toggle check and before the
|
|
5
|
+
* storage write — dashboard latency tracks the in-process emit, not
|
|
6
|
+
* however long persistence takes.
|
|
7
|
+
*
|
|
8
|
+
* Slow or broken subscribers are silently dropped (the SSE response's
|
|
9
|
+
* `cancel()` handler also unregisters them when the client disconnects).
|
|
10
|
+
*/
|
|
11
|
+
export declare function notifySubscribers(entry: TelescopeEntry): void;
|
|
12
|
+
/** @internal — used by tests to inspect subscriber count. */
|
|
13
|
+
export declare function subscriberCount(): number;
|
|
14
|
+
/** @internal — used by tests to reset between cases. */
|
|
15
|
+
export declare function _resetSubscribers(): void;
|
|
16
|
+
/**
|
|
17
|
+
* Build the SSE streaming `Response` for `GET <path>/api/stream`. Optionally
|
|
18
|
+
* filter the firehose to a single `EntryType` via `?type=request` — matches
|
|
19
|
+
* the per-page dashboard URL so each list view subscribes only to what it
|
|
20
|
+
* renders.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createStreamResponse(typeFilter: EntryType | null): Response;
|
|
23
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAoC3D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAU7D;AAED,6DAA6D;AAC7D,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wDAAwD;AACxD,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,SAAS,GAAG,IAAI,GAAG,QAAQ,CAiD3E"}
|
package/dist/stream.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const _g = globalThis;
|
|
2
|
+
const _subKey = '__rudderjs_telescope_subscribers__';
|
|
3
|
+
function subscribers() {
|
|
4
|
+
let s = _g[_subKey];
|
|
5
|
+
if (!s) {
|
|
6
|
+
s = new Set();
|
|
7
|
+
_g[_subKey] = s;
|
|
8
|
+
}
|
|
9
|
+
return s;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Fan-out a recorded entry to every connected dashboard. Called from
|
|
13
|
+
* `Telescope.record()` after the recording-toggle check and before the
|
|
14
|
+
* storage write — dashboard latency tracks the in-process emit, not
|
|
15
|
+
* however long persistence takes.
|
|
16
|
+
*
|
|
17
|
+
* Slow or broken subscribers are silently dropped (the SSE response's
|
|
18
|
+
* `cancel()` handler also unregisters them when the client disconnects).
|
|
19
|
+
*/
|
|
20
|
+
export function notifySubscribers(entry) {
|
|
21
|
+
const subs = subscribers();
|
|
22
|
+
for (const sub of subs) {
|
|
23
|
+
if (sub.type && sub.type !== entry.type)
|
|
24
|
+
continue;
|
|
25
|
+
try {
|
|
26
|
+
sub.write(entry);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
subs.delete(sub);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** @internal — used by tests to inspect subscriber count. */
|
|
34
|
+
export function subscriberCount() {
|
|
35
|
+
return subscribers().size;
|
|
36
|
+
}
|
|
37
|
+
/** @internal — used by tests to reset between cases. */
|
|
38
|
+
export function _resetSubscribers() {
|
|
39
|
+
subscribers().clear();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build the SSE streaming `Response` for `GET <path>/api/stream`. Optionally
|
|
43
|
+
* filter the firehose to a single `EntryType` via `?type=request` — matches
|
|
44
|
+
* the per-page dashboard URL so each list view subscribes only to what it
|
|
45
|
+
* renders.
|
|
46
|
+
*/
|
|
47
|
+
export function createStreamResponse(typeFilter) {
|
|
48
|
+
const encoder = new TextEncoder();
|
|
49
|
+
let sub = null;
|
|
50
|
+
let heartbeat = null;
|
|
51
|
+
const stream = new ReadableStream({
|
|
52
|
+
start(controller) {
|
|
53
|
+
sub = {
|
|
54
|
+
type: typeFilter,
|
|
55
|
+
write(entry) {
|
|
56
|
+
// Throws if the controller is closed — caught by notifySubscribers
|
|
57
|
+
// which removes us from the registry.
|
|
58
|
+
controller.enqueue(encoder.encode(`event: entry\ndata: ${JSON.stringify(entry)}\n\n`));
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
subscribers().add(sub);
|
|
62
|
+
// Immediate open frame so the client's `onopen` fires without waiting
|
|
63
|
+
// for the first real entry.
|
|
64
|
+
controller.enqueue(encoder.encode(': open\n\n'));
|
|
65
|
+
// Keepalive every 30s — below the common 60s proxy idle timeout, above
|
|
66
|
+
// a wasteful sub-10s cadence. SSE clients silently ignore `:` comments.
|
|
67
|
+
heartbeat = setInterval(() => {
|
|
68
|
+
try {
|
|
69
|
+
controller.enqueue(encoder.encode(': keepalive\n\n'));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
if (heartbeat)
|
|
73
|
+
clearInterval(heartbeat);
|
|
74
|
+
}
|
|
75
|
+
}, 30_000);
|
|
76
|
+
heartbeat.unref?.();
|
|
77
|
+
},
|
|
78
|
+
cancel() {
|
|
79
|
+
if (sub)
|
|
80
|
+
subscribers().delete(sub);
|
|
81
|
+
if (heartbeat)
|
|
82
|
+
clearInterval(heartbeat);
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
return new Response(stream, {
|
|
86
|
+
headers: {
|
|
87
|
+
'Content-Type': 'text/event-stream',
|
|
88
|
+
'Cache-Control': 'no-cache, no-transform',
|
|
89
|
+
'Connection': 'keep-alive',
|
|
90
|
+
// Disable nginx proxy buffering — without this, entries pile up
|
|
91
|
+
// server-side until the buffer fills and dashboards look frozen.
|
|
92
|
+
'X-Accel-Buffering': 'no',
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAwBA,MAAM,EAAE,GAAG,UAAqC,CAAA;AAChD,MAAM,OAAO,GAAG,oCAAoC,CAAA;AAEpD,SAAS,WAAW;IAClB,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAgC,CAAA;IAClD,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,CAAC,GAAG,IAAI,GAAG,EAAE,CAAA;QACb,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACjB,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAqB;IACrD,MAAM,IAAI,GAAG,WAAW,EAAE,CAAA;IAC1B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI;YAAE,SAAQ;QACjD,IAAI,CAAC;YACH,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAClB,CAAC;IACH,CAAC;AACH,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,eAAe;IAC7B,OAAO,WAAW,EAAE,CAAC,IAAI,CAAA;AAC3B,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,iBAAiB;IAC/B,WAAW,EAAE,CAAC,KAAK,EAAE,CAAA;AACvB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAA4B;IAC/D,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;IACjC,IAAI,GAAG,GAA4B,IAAI,CAAA;IACvC,IAAI,SAAS,GAA0C,IAAI,CAAA;IAE3D,MAAM,MAAM,GAAG,IAAI,cAAc,CAAa;QAC5C,KAAK,CAAC,UAAU;YACd,GAAG,GAAG;gBACJ,IAAI,EAAE,UAAU;gBAChB,KAAK,CAAC,KAAK;oBACT,mEAAmE;oBACnE,sCAAsC;oBACtC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,uBAAuB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;gBACxF,CAAC;aACF,CAAA;YACD,WAAW,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAEtB,sEAAsE;YACtE,4BAA4B;YAC5B,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;YAEhD,uEAAuE;YACvE,wEAAwE;YACxE,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;gBAC3B,IAAI,CAAC;oBACH,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAA;gBACvD,CAAC;gBAAC,MAAM,CAAC;oBACP,IAAI,SAAS;wBAAE,aAAa,CAAC,SAAS,CAAC,CAAA;gBACzC,CAAC;YACH,CAAC,EAAE,MAAM,CAAC,CAAA;YACV,SAAS,CAAC,KAAK,EAAE,EAAE,CAAA;QACrB,CAAC;QAED,MAAM;YACJ,IAAI,GAAG;gBAAE,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAClC,IAAI,SAAS;gBAAE,aAAa,CAAC,SAAS,CAAC,CAAA;QACzC,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;QAC1B,OAAO,EAAE;YACP,cAAc,EAAO,mBAAmB;YACxC,eAAe,EAAM,wBAAwB;YAC7C,YAAY,EAAS,YAAY;YACjC,gEAAgE;YAChE,iEAAiE;YACjE,mBAAmB,EAAE,IAAI;SAC1B;KACF,CAAC,CAAA;AACJ,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
export type EntryType = 'request' | 'query' | 'job' | 'exception' | 'log' | 'mail' | 'notification' | 'event' | 'cache' | 'schedule' | 'model' | 'command' | 'broadcast' | 'sync' | 'http' | 'gate' | 'dump' | 'ai' | 'mcp' | 'view';
|
|
2
|
+
/**
|
|
3
|
+
* Map an `EntryType` to the URL slug used by the dashboard list API.
|
|
4
|
+
*
|
|
5
|
+
* Shared between the server (`routes.ts` registers `${apiPrefix}/${slug}`)
|
|
6
|
+
* and the client (`EntryList.ts` fetches `${apiPrefix}/${slug}?...`). A
|
|
7
|
+
* drift between the two sites silently 404s the listing API and the table
|
|
8
|
+
* renders empty — historically a recurring footgun.
|
|
9
|
+
*
|
|
10
|
+
* Both sites must call this helper rather than inlining the slug logic.
|
|
11
|
+
* Adding a new `EntryType` means updating this function in lockstep.
|
|
12
|
+
*/
|
|
13
|
+
export declare function toApiSlug(type: EntryType): string;
|
|
2
14
|
export interface TelescopeEntry {
|
|
3
15
|
id: string;
|
|
4
16
|
batchId: string | null;
|
|
@@ -91,6 +103,23 @@ export interface TelescopeConfig {
|
|
|
91
103
|
*/
|
|
92
104
|
hideRequestFields?: string[] | undefined;
|
|
93
105
|
auth?: null | ((req: unknown) => boolean | Promise<boolean>) | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* How the dashboard receives new entries.
|
|
108
|
+
*
|
|
109
|
+
* - `'polling'` (default): the entry list re-fetches every `pollInterval` ms
|
|
110
|
+
* when "Live" is toggled on. Works through any HTTP proxy, no extra wire
|
|
111
|
+
* protocol.
|
|
112
|
+
* - `'stream'`: the dashboard subscribes to a Server-Sent Events endpoint
|
|
113
|
+
* (`<path>/api/stream`) and the server pushes new entries as they're
|
|
114
|
+
* recorded. Lower latency, no spinning request count. Half-duplex —
|
|
115
|
+
* one connection per dashboard tab.
|
|
116
|
+
*
|
|
117
|
+
* Stream mode is pure HTTP (no peer deps); the recording toggle and auth
|
|
118
|
+
* gate still apply.
|
|
119
|
+
*/
|
|
120
|
+
updates?: 'polling' | 'stream' | undefined;
|
|
121
|
+
/** Poll interval in ms when `updates === 'polling'`. Default `2000`. Ignored in stream mode. */
|
|
122
|
+
pollInterval?: number | undefined;
|
|
94
123
|
}
|
|
95
124
|
export declare const defaultConfig: Required<Omit<TelescopeConfig, 'auth' | 'sqlitePath'>> & {
|
|
96
125
|
auth: TelescopeConfig['auth'];
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
// ─── Entry Types ───────────────────────────────────────────
|
|
2
|
+
/**
|
|
3
|
+
* Map an `EntryType` to the URL slug used by the dashboard list API.
|
|
4
|
+
*
|
|
5
|
+
* Shared between the server (`routes.ts` registers `${apiPrefix}/${slug}`)
|
|
6
|
+
* and the client (`EntryList.ts` fetches `${apiPrefix}/${slug}?...`). A
|
|
7
|
+
* drift between the two sites silently 404s the listing API and the table
|
|
8
|
+
* renders empty — historically a recurring footgun.
|
|
9
|
+
*
|
|
10
|
+
* Both sites must call this helper rather than inlining the slug logic.
|
|
11
|
+
* Adding a new `EntryType` means updating this function in lockstep.
|
|
12
|
+
*/
|
|
13
|
+
export function toApiSlug(type) {
|
|
14
|
+
if (type === 'query')
|
|
15
|
+
return 'queries';
|
|
16
|
+
if (type === 'view')
|
|
17
|
+
return 'views';
|
|
18
|
+
if (type === 'http' || type === 'ai' || type === 'mcp')
|
|
19
|
+
return type;
|
|
20
|
+
return `${type}s`;
|
|
21
|
+
}
|
|
2
22
|
export const defaultConfig = {
|
|
3
23
|
enabled: true,
|
|
4
24
|
path: 'telescope',
|
|
@@ -34,5 +54,7 @@ export const defaultConfig = {
|
|
|
34
54
|
hideRequestHeaders: ['authorization', 'cookie', 'set-cookie', 'x-csrf-token', 'x-api-key', 'x-real-ip'],
|
|
35
55
|
hideRequestFields: ['password', 'password_confirmation', 'token', 'secret'],
|
|
36
56
|
auth: null,
|
|
57
|
+
updates: 'polling',
|
|
58
|
+
pollInterval: 2000,
|
|
37
59
|
};
|
|
38
60
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8DAA8D;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAwB9D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,SAAS,CAAC,IAAe;IACvC,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,SAAS,CAAA;IACtC,IAAI,IAAI,KAAK,MAAM;QAAG,OAAO,OAAO,CAAA;IACpC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,CAAA;IACnE,OAAO,GAAG,IAAI,GAAG,CAAA;AACnB,CAAC;AA4HD,MAAM,CAAC,MAAM,aAAa,GAAmH;IAC3I,OAAO,EAAe,IAAI;IAC1B,IAAI,EAAkB,WAAW;IACjC,OAAO,EAAe,QAAQ;IAC9B,UAAU,EAAY,eAAe;IACrC,UAAU,EAAY,IAAI;IAC1B,eAAe,EAAO,EAAE;IACxB,cAAc,EAAQ,IAAI;IAC1B,aAAa,EAAS,IAAI;IAC1B,UAAU,EAAY,IAAI;IAC1B,gBAAgB,EAAM,IAAI;IAC1B,UAAU,EAAY,IAAI;IAC1B,UAAU,EAAY,IAAI;IAC1B,mBAAmB,EAAG,IAAI;IAC1B,YAAY,EAAU,IAAI;IAC1B,WAAW,EAAW,IAAI;IAC1B,cAAc,EAAQ,IAAI;IAC1B,YAAY,EAAU,IAAI;IAC1B,cAAc,EAAQ,IAAI;IAC1B,gBAAgB,EAAM,IAAI;IAC1B,UAAU,EAAY,IAAI;IAC1B,UAAU,EAAY,IAAI;IAC1B,UAAU,EAAY,IAAI;IAC1B,WAAW,EAAW,IAAI;IAC1B,QAAQ,EAAc,IAAI;IAC1B,SAAS,EAAa,IAAI;IAC1B,WAAW,EAAW,IAAI;IAC1B,qBAAqB,EAAE,GAAG;IAC1B,cAAc,EAAQ,CAAC,aAAa,EAAE,SAAS,CAAC;IAChD,kBAAkB,EAAI,GAAG;IACzB,eAAe,EAAO,IAAI;IAC1B,gBAAgB,EAAM,IAAI;IAC1B,kBAAkB,EAAI,CAAC,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,CAAC;IACzG,iBAAiB,EAAK,CAAC,UAAU,EAAE,uBAAuB,EAAE,OAAO,EAAE,QAAQ,CAAC;IAC9E,IAAI,EAAkB,IAAI;IAC1B,OAAO,EAAe,SAAS;IAC/B,YAAY,EAAU,IAAI;CAC3B,CAAA"}
|
|
@@ -15,6 +15,14 @@ export interface EntryListProps {
|
|
|
15
15
|
pageKey: string;
|
|
16
16
|
title: string;
|
|
17
17
|
columns: Column[];
|
|
18
|
+
/**
|
|
19
|
+
* Live-update transport. `'polling'` re-fetches the list endpoint every
|
|
20
|
+
* `pollInterval` ms; `'stream'` opens an SSE connection to
|
|
21
|
+
* `<apiPrefix>/stream?type=<type>` and prepends entries as they arrive.
|
|
22
|
+
*/
|
|
23
|
+
updates: 'polling' | 'stream';
|
|
24
|
+
/** Poll cadence in ms when `updates === 'polling'`. */
|
|
25
|
+
pollInterval: number;
|
|
18
26
|
}
|
|
19
27
|
/**
|
|
20
28
|
* Generic master/list page for any watcher type. Renders a table with
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntryList.d.ts","sourceRoot":"","sources":["../../../src/views/vanilla/EntryList.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EntryList.d.ts","sourceRoot":"","sources":["../../../src/views/vanilla/EntryList.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,MAAM;IACrB,KAAK,EAAO,MAAM,CAAA;IAClB,sEAAsE;IACtE,GAAG,EAAS,MAAM,CAAA;IAClB,KAAK,CAAC,EAAM,OAAO,CAAA;IACnB,IAAI,CAAC,EAAO,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAG,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,8EAA8E;IAC9E,IAAI,EAAO,MAAM,CAAA;IACjB,uFAAuF;IACvF,OAAO,EAAI,MAAM,CAAA;IACjB,KAAK,EAAM,MAAM,CAAA;IACjB,OAAO,EAAI,MAAM,EAAE,CAAA;IACnB;;;;OAIG;IACH,OAAO,EAAO,SAAS,GAAG,QAAQ,CAAA;IAClC,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAuOvD"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Layout } from './Layout.js';
|
|
2
|
+
import { toApiSlug } from '../../types.js';
|
|
2
3
|
/**
|
|
3
4
|
* Generic master/list page for any watcher type. Renders a table with
|
|
4
5
|
* search + tag filter + pagination. Each row links to the detail page
|
|
@@ -9,7 +10,7 @@ import { Layout } from './Layout.js';
|
|
|
9
10
|
* Phase 2b added the `?tag=` filter and tag pill column.
|
|
10
11
|
*/
|
|
11
12
|
export function EntryList(props) {
|
|
12
|
-
const { basePath, apiPrefix, type, pageKey, title, columns } = props;
|
|
13
|
+
const { basePath, apiPrefix, type, pageKey, title, columns, updates, pollInterval } = props;
|
|
13
14
|
const colHeaders = columns.map(c => {
|
|
14
15
|
const align = c.className?.includes('text-right') ? 'text-right' : 'text-left';
|
|
15
16
|
return `<th class="px-4 py-3 ${align} text-xs uppercase font-medium text-gray-500 dark:text-gray-400">${c.label}</th>`;
|
|
@@ -24,21 +25,19 @@ export function EntryList(props) {
|
|
|
24
25
|
return `<td class="px-4 py-3 ${c.className ?? ''}" x-text="${c.key}"></td>`;
|
|
25
26
|
}).join('\n ');
|
|
26
27
|
const activePath = `/${pageKey}`;
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
: type === 'view' ? 'views'
|
|
31
|
-
: `${type}s`;
|
|
28
|
+
// Slug mapping is shared with routes.ts via `toApiSlug` (see types.ts).
|
|
29
|
+
// The resolved string is inlined into the rendered Alpine script below.
|
|
30
|
+
const apiPath = toApiSlug(type);
|
|
32
31
|
const body = `
|
|
33
32
|
<div x-data="entryList()" x-init="load()" x-cloak>
|
|
34
33
|
<div class="flex items-center justify-between mb-6 gap-4 flex-wrap">
|
|
35
34
|
<h2 class="text-xl font-bold">${title}</h2>
|
|
36
35
|
<div class="flex gap-2 items-center">
|
|
37
|
-
<button @click="toggleAutoRefresh()" :title="autoRefresh ? '
|
|
36
|
+
<button @click="toggleAutoRefresh()" :title="autoRefresh ? (transport === 'stream' ? 'Streaming (click to disable)' : 'Polling (click to disable)') : 'Live off (click to enable)'"
|
|
38
37
|
class="text-xs border rounded-lg px-3 py-1.5 transition flex items-center gap-1.5"
|
|
39
38
|
:class="autoRefresh ? 'border-green-300 dark:border-green-700 bg-green-50 dark:bg-green-950 text-green-700 dark:text-green-400' : 'border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800'">
|
|
40
39
|
<span class="w-2 h-2 rounded-full" :class="autoRefresh ? 'bg-green-500 animate-pulse' : 'bg-gray-400'"></span>
|
|
41
|
-
<span x-text="autoRefresh ? 'Live' : 'Live'"></span>
|
|
40
|
+
<span x-text="autoRefresh ? (transport === 'stream' ? 'Live · stream' : 'Live') : 'Live'"></span>
|
|
42
41
|
</button>
|
|
43
42
|
<input type="text" x-model="search" @input.debounce.300ms="load()"
|
|
44
43
|
placeholder="Search..." class="text-sm border border-gray-300 dark:border-gray-700 rounded-lg px-3 py-1.5 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none">
|
|
@@ -107,14 +106,17 @@ export function EntryList(props) {
|
|
|
107
106
|
search: '',
|
|
108
107
|
tag: new URLSearchParams(window.location.search).get('tag') || '',
|
|
109
108
|
autoRefresh: localStorage.getItem('telescope.autoRefresh') === 'true',
|
|
109
|
+
transport: '${updates}',
|
|
110
110
|
_refreshTimer: null,
|
|
111
|
+
_eventSource: null,
|
|
112
|
+
_perPage: 50,
|
|
111
113
|
|
|
112
114
|
init() {
|
|
113
115
|
if (this.autoRefresh) this.startAutoRefresh()
|
|
114
116
|
},
|
|
115
117
|
|
|
116
118
|
async load() {
|
|
117
|
-
const params = new URLSearchParams({ page: this.page, per_page:
|
|
119
|
+
const params = new URLSearchParams({ page: this.page, per_page: this._perPage })
|
|
118
120
|
if (this.search) params.set('search', this.search)
|
|
119
121
|
if (this.tag) params.set('tag', this.tag)
|
|
120
122
|
const data = await fetch('${apiPrefix}/${apiPath}?' + params).then(r => r.json())
|
|
@@ -130,17 +132,66 @@ export function EntryList(props) {
|
|
|
130
132
|
},
|
|
131
133
|
|
|
132
134
|
startAutoRefresh() {
|
|
133
|
-
if (this.
|
|
134
|
-
this.
|
|
135
|
+
if (this.transport === 'stream') this.startStream()
|
|
136
|
+
else this.startPolling()
|
|
135
137
|
},
|
|
136
138
|
|
|
137
139
|
stopAutoRefresh() {
|
|
140
|
+
this.stopStream()
|
|
141
|
+
this.stopPolling()
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
startPolling() {
|
|
145
|
+
if (this._refreshTimer) return
|
|
146
|
+
this._refreshTimer = setInterval(() => this.load(), ${pollInterval})
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
stopPolling() {
|
|
138
150
|
if (this._refreshTimer) {
|
|
139
151
|
clearInterval(this._refreshTimer)
|
|
140
152
|
this._refreshTimer = null
|
|
141
153
|
}
|
|
142
154
|
},
|
|
143
155
|
|
|
156
|
+
startStream() {
|
|
157
|
+
if (this._eventSource) return
|
|
158
|
+
const url = '${apiPrefix}/stream' + (${JSON.stringify(type)} ? '?type=' + ${JSON.stringify(type)} : '')
|
|
159
|
+
const es = new EventSource(url)
|
|
160
|
+
es.addEventListener('entry', (e) => this.onStreamEntry(e))
|
|
161
|
+
this._eventSource = es
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
stopStream() {
|
|
165
|
+
if (this._eventSource) {
|
|
166
|
+
this._eventSource.close()
|
|
167
|
+
this._eventSource = null
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
onStreamEntry(e) {
|
|
172
|
+
// New entries belong on page 1. While the user is paginating
|
|
173
|
+
// through history, suppress live prepends so their position
|
|
174
|
+
// doesn't shift under them.
|
|
175
|
+
if (this.page > 1) return
|
|
176
|
+
|
|
177
|
+
let entry
|
|
178
|
+
try { entry = JSON.parse(e.data) } catch { return }
|
|
179
|
+
|
|
180
|
+
// Client-side filter parity with the polling endpoint's server
|
|
181
|
+
// filters: search matches any string field in tags; tag filter
|
|
182
|
+
// matches exactly.
|
|
183
|
+
if (this.tag && !(entry.tags || []).includes(this.tag)) return
|
|
184
|
+
if (this.search) {
|
|
185
|
+
const hay = JSON.stringify(entry).toLowerCase()
|
|
186
|
+
if (!hay.includes(this.search.toLowerCase())) return
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this.entries.unshift(entry)
|
|
190
|
+
if (this.entries.length > this._perPage) this.entries.pop()
|
|
191
|
+
this.meta.total = (this.meta.total || 0) + 1
|
|
192
|
+
this.meta.last_page = Math.max(1, Math.ceil(this.meta.total / this._perPage))
|
|
193
|
+
},
|
|
194
|
+
|
|
144
195
|
goTo(id) {
|
|
145
196
|
window.dispatchEvent(new CustomEvent('telescope:navigate', { detail: '${basePath}/${pageKey}/' + id }))
|
|
146
197
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntryList.js","sourceRoot":"","sources":["../../../src/views/vanilla/EntryList.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"EntryList.js","sourceRoot":"","sources":["../../../src/views/vanilla/EntryList.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,SAAS,EAAkB,MAAM,gBAAgB,CAAA;AA8B1D;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,KAAqB;IAC7C,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,KAAK,CAAA;IAE3F,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACjC,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAA;QAC9E,OAAO,wBAAwB,KAAK,oEAAoE,CAAC,CAAC,KAAK,OAAO,CAAA;IACxH,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;IAE3B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QAC/B,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YACZ,OAAO,2HAA2H,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,GAAG,gBAAgB,CAAA;QAC5K,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACX,OAAO,0CAA0C,CAAC,CAAC,SAAS,IAAI,EAAE,aAAa,CAAC,CAAC,GAAG,SAAS,CAAA;QAC/F,CAAC;QACD,OAAO,wBAAwB,CAAC,CAAC,SAAS,IAAI,EAAE,aAAa,CAAC,CAAC,GAAG,SAAS,CAAA;IAC7E,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;IAE7B,MAAM,UAAU,GAAG,IAAI,OAAO,EAAE,CAAA;IAChC,wEAAwE;IACxE,wEAAwE;IACxE,MAAM,OAAO,GAAG,SAAS,CAAC,IAAiB,CAAC,CAAA;IAE5C,MAAM,IAAI,GAAG;;;wCAGyB,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;gBA0B7B,UAAU;;;;;;;;kBAQR,QAAQ;;;;;;;;;;;;;6BAaG,OAAO,CAAC,MAAM,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA4BvB,OAAO;;;;;;;;;;;;;wCAaS,SAAS,IAAI,OAAO;;;;;;;;;;;;;;;;;;;;;;;;kEAwBM,YAAY;;;;;;;;;;;;2BAYnD,SAAS,eAAe,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,iBAAiB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oFAsCxB,QAAQ,IAAI,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCzF,CAAA;IAEZ,OAAO,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAA;AACtD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Layout.d.ts","sourceRoot":"","sources":["../../../src/views/vanilla/Layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAG,MAAM,CAAA;IACb,IAAI,EAAG,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAO,MAAM,CAAA;IAClB,IAAI,EAAQ,MAAM,CAAA;IAClB,QAAQ,EAAI,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"Layout.d.ts","sourceRoot":"","sources":["../../../src/views/vanilla/Layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAG,MAAM,CAAA;IACb,IAAI,EAAG,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAO,MAAM,CAAA;IAClB,IAAI,EAAQ,MAAM,CAAA;IAClB,QAAQ,EAAI,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CA4NjD"}
|
|
@@ -202,7 +202,8 @@ export function Layout(props) {
|
|
|
202
202
|
_isPopState: false,
|
|
203
203
|
|
|
204
204
|
stopPageTimers() {
|
|
205
|
-
//
|
|
205
|
+
// Tear down any per-page auto-refresh timers and open SSE
|
|
206
|
+
// connections from the previous EntryList before swapping <main>.
|
|
206
207
|
const mainEl = document.getElementById('telescope-main')
|
|
207
208
|
if (mainEl) {
|
|
208
209
|
mainEl.querySelectorAll('[x-data]').forEach(el => {
|
|
@@ -212,6 +213,10 @@ export function Layout(props) {
|
|
|
212
213
|
clearInterval(data._refreshTimer)
|
|
213
214
|
data._refreshTimer = null
|
|
214
215
|
}
|
|
216
|
+
if (data._eventSource) {
|
|
217
|
+
data._eventSource.close()
|
|
218
|
+
data._eventSource = null
|
|
219
|
+
}
|
|
215
220
|
}
|
|
216
221
|
}
|
|
217
222
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Layout.js","sourceRoot":"","sources":["../../../src/views/vanilla/Layout.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Layout.js","sourceRoot":"","sources":["../../../src/views/vanilla/Layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type SafeString } from '../_html.js';
|
|
2
|
+
import type { TelescopeEntry } from '../../../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Detail view for the `ai` watcher — one entry per agent run, with
|
|
5
|
+
* conversation tabs (input/output), token-usage card, and an execution
|
|
6
|
+
* tab group that drills into tool calls and per-step iterations.
|
|
7
|
+
*
|
|
8
|
+
* The two `render*` helpers below are AI-specific (they unpack the
|
|
9
|
+
* provider-agnostic shapes telescope's AI collector records) so they
|
|
10
|
+
* live with this view rather than in `sections.ts`. If a future watcher
|
|
11
|
+
* needs the same shape, promote them — but don't pre-emptively.
|
|
12
|
+
*/
|
|
13
|
+
type ViewFn = (entry: TelescopeEntry) => SafeString;
|
|
14
|
+
export declare const AiView: ViewFn;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=ai-views.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-views.d.ts","sourceRoot":"","sources":["../../../../src/views/vanilla/details/ai-views.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD;;;;;;;;;GASG;AAEH,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,UAAU,CAAA;AAmEnD,eAAO,MAAM,MAAM,EAAE,MA2EpB,CAAA"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { html, raw } from '../_html.js';
|
|
2
|
+
import { Card, KeyValueTable, JsonBlock, CodeBlock, Badge, Tabs } from './sections.js';
|
|
3
|
+
import { escape } from './format.js';
|
|
4
|
+
function renderToolCalls(toolCalls) {
|
|
5
|
+
if (toolCalls.length === 0)
|
|
6
|
+
return html ``;
|
|
7
|
+
// `html\`\`` natively renders SafeString[] — `.map(...).join('')` was the
|
|
8
|
+
// legacy footgun shape (each SafeString.toString() returns its raw value,
|
|
9
|
+
// then raw() re-wraps). Pass the array directly so a future copy of this
|
|
10
|
+
// code doesn't re-introduce the join-then-re-escape bug elsewhere.
|
|
11
|
+
return html `${toolCalls.map((tc) => {
|
|
12
|
+
const t = tc;
|
|
13
|
+
const name = String(t['name'] ?? t['toolName'] ?? '—');
|
|
14
|
+
const duration = t['duration'] != null ? `${t['duration']}ms` : null;
|
|
15
|
+
const approved = t['approved'] === true;
|
|
16
|
+
const needsApproval = t['requiresApproval'] === true;
|
|
17
|
+
const args = t['args'] ?? t['input'] ?? t['arguments'];
|
|
18
|
+
const result = t['result'] ?? t['output'];
|
|
19
|
+
const approvalBadge = needsApproval
|
|
20
|
+
? raw(`<span class="ml-1 inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300">${approved ? 'Approved' : 'Pending'}</span>`)
|
|
21
|
+
: '';
|
|
22
|
+
return html `
|
|
23
|
+
<div class="border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden mb-2">
|
|
24
|
+
<div class="flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
|
|
25
|
+
${Badge(name)}
|
|
26
|
+
${approvalBadge}
|
|
27
|
+
${duration ? raw(`<span class="text-xs text-gray-400 dark:text-gray-500 ml-auto">${escape(duration)}</span>`) : ''}
|
|
28
|
+
</div>
|
|
29
|
+
${args !== undefined ? html `
|
|
30
|
+
<details class="group">
|
|
31
|
+
<summary class="px-3 py-1.5 text-xs font-medium text-gray-500 dark:text-gray-400 cursor-pointer select-none hover:bg-gray-50 dark:hover:bg-gray-800">Args</summary>
|
|
32
|
+
<div class="px-3 pb-2">${JsonBlock(args)}</div>
|
|
33
|
+
</details>
|
|
34
|
+
` : ''}
|
|
35
|
+
${result !== undefined ? html `
|
|
36
|
+
<details class="group">
|
|
37
|
+
<summary class="px-3 py-1.5 text-xs font-medium text-gray-500 dark:text-gray-400 cursor-pointer select-none hover:bg-gray-50 dark:hover:bg-gray-800">Result</summary>
|
|
38
|
+
<div class="px-3 pb-2">${JsonBlock(result)}</div>
|
|
39
|
+
</details>
|
|
40
|
+
` : ''}
|
|
41
|
+
</div>
|
|
42
|
+
`;
|
|
43
|
+
})}`;
|
|
44
|
+
}
|
|
45
|
+
function renderSteps(steps) {
|
|
46
|
+
if (steps.length <= 1)
|
|
47
|
+
return html ``;
|
|
48
|
+
return html `${steps.map((s, i) => {
|
|
49
|
+
const step = s;
|
|
50
|
+
const usage = step['usage'];
|
|
51
|
+
const tokens = usage ? (usage['totalTokens'] ?? usage['total_tokens']) : undefined;
|
|
52
|
+
const tcCount = Array.isArray(step['toolCalls']) ? step['toolCalls'].length : (step['toolCallCount'] ?? 0);
|
|
53
|
+
const finishReason = step['finishReason'] ?? step['finish_reason'];
|
|
54
|
+
return html `
|
|
55
|
+
<div class="border border-gray-200 dark:border-gray-700 rounded-lg px-3 py-2 mb-2">
|
|
56
|
+
${Card(null, KeyValueTable({
|
|
57
|
+
Iteration: i + 1,
|
|
58
|
+
Tokens: tokens != null ? String(tokens) : '—',
|
|
59
|
+
'Tool Calls': String(tcCount),
|
|
60
|
+
'Finish Reason': finishReason ? Badge(String(finishReason)) : raw('<span class="text-gray-300 dark:text-gray-600">—</span>'),
|
|
61
|
+
}))}
|
|
62
|
+
</div>
|
|
63
|
+
`;
|
|
64
|
+
})}`;
|
|
65
|
+
}
|
|
66
|
+
export const AiView = (entry) => {
|
|
67
|
+
const c = entry.content;
|
|
68
|
+
const status = String(c['status'] ?? '');
|
|
69
|
+
const statusBadge = status === 'failed'
|
|
70
|
+
? raw(`<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300">Failed</span>`)
|
|
71
|
+
: raw(`<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300">Completed</span>`);
|
|
72
|
+
const finishReason = c['finishReason'] ?? c['finish_reason'];
|
|
73
|
+
const streaming = c['streaming'] === true ? 'Yes' : 'No';
|
|
74
|
+
const toolCalls = Array.isArray(c['toolCalls']) ? c['toolCalls'] : [];
|
|
75
|
+
const steps = Array.isArray(c['steps']) ? c['steps'] : [];
|
|
76
|
+
const usage = c['usage'];
|
|
77
|
+
const requestRows = {
|
|
78
|
+
Status: statusBadge,
|
|
79
|
+
Agent: c['agentName'] ?? c['agent'] ?? '—',
|
|
80
|
+
Model: c['model'] ? Badge(String(c['model'])) : raw('<span class="text-gray-300 dark:text-gray-600">—</span>'),
|
|
81
|
+
Provider: c['provider'] ?? '—',
|
|
82
|
+
Duration: c['duration'] != null ? `${c['duration']}ms` : '—',
|
|
83
|
+
'Finish Reason': finishReason ? Badge(String(finishReason)) : raw('<span class="text-gray-300 dark:text-gray-600">—</span>'),
|
|
84
|
+
Steps: steps.length > 0 ? steps.length : (c['stepCount'] ?? '—'),
|
|
85
|
+
'Tool Calls': toolCalls.length > 0 ? toolCalls.length : (c['toolCallCount'] ?? '—'),
|
|
86
|
+
Streaming: streaming,
|
|
87
|
+
};
|
|
88
|
+
if (c['conversationId']) {
|
|
89
|
+
requestRows['Conversation ID'] = raw(`<span class="font-mono text-xs">${escape(String(c['conversationId']))}</span>`);
|
|
90
|
+
}
|
|
91
|
+
const failoverAttempts = c['failoverAttempts'];
|
|
92
|
+
if (failoverAttempts != null && failoverAttempts > 0) {
|
|
93
|
+
requestRows['Failover Attempts'] = failoverAttempts;
|
|
94
|
+
}
|
|
95
|
+
const inputValue = c['input'];
|
|
96
|
+
const outputValue = c['output'];
|
|
97
|
+
const errorValue = c['error'];
|
|
98
|
+
const inputStr = typeof inputValue === 'string' ? inputValue : JSON.stringify(inputValue, null, 2);
|
|
99
|
+
const outputStr = typeof outputValue === 'string' ? outputValue : JSON.stringify(outputValue, null, 2);
|
|
100
|
+
return html `
|
|
101
|
+
${Card('AI Request', KeyValueTable(requestRows))}
|
|
102
|
+
|
|
103
|
+
${usage ? Card('Token Usage', KeyValueTable({
|
|
104
|
+
Prompt: usage['promptTokens'] ?? usage['prompt_tokens'] ?? '—',
|
|
105
|
+
Completion: usage['completionTokens'] ?? usage['completion_tokens'] ?? '—',
|
|
106
|
+
Total: usage['totalTokens'] ?? usage['total_tokens'] ?? '—',
|
|
107
|
+
})) : ''}
|
|
108
|
+
|
|
109
|
+
${(() => {
|
|
110
|
+
const conversationTabs = [];
|
|
111
|
+
if (outputValue !== undefined && outputValue !== null) {
|
|
112
|
+
conversationTabs.push({ label: 'Output', content: CodeBlock(outputStr, { maxHeight: '[400px]' }) });
|
|
113
|
+
}
|
|
114
|
+
if (inputValue !== undefined && inputValue !== null) {
|
|
115
|
+
conversationTabs.push({ label: 'Input', content: CodeBlock(inputStr, { maxHeight: '[200px]' }) });
|
|
116
|
+
}
|
|
117
|
+
return conversationTabs.length > 0 ? Tabs(conversationTabs) : '';
|
|
118
|
+
})()}
|
|
119
|
+
|
|
120
|
+
${errorValue
|
|
121
|
+
? Card('Error', raw(`<pre class="text-sm text-red-600 dark:text-red-400 whitespace-pre-wrap break-words">${escape(typeof errorValue === 'string' ? errorValue : JSON.stringify(errorValue, null, 2))}</pre>`))
|
|
122
|
+
: ''}
|
|
123
|
+
|
|
124
|
+
${(() => {
|
|
125
|
+
const executionTabs = [];
|
|
126
|
+
if (toolCalls.length > 0) {
|
|
127
|
+
executionTabs.push({ label: `Tool Calls (${toolCalls.length})`, content: renderToolCalls(toolCalls) });
|
|
128
|
+
}
|
|
129
|
+
if (steps.length > 1) {
|
|
130
|
+
executionTabs.push({ label: `Steps (${steps.length})`, content: renderSteps(steps) });
|
|
131
|
+
}
|
|
132
|
+
return executionTabs.length > 0 ? Tabs(executionTabs) : '';
|
|
133
|
+
})()}
|
|
134
|
+
`;
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=ai-views.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-views.js","sourceRoot":"","sources":["../../../../src/views/vanilla/details/ai-views.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatting helpers used across per-watcher detail views.
|
|
3
|
+
*
|
|
4
|
+
* Kept package-internal — none of these are re-exported from the package
|
|
5
|
+
* entry. They're tiny, side-effect free, and only meaningful within the
|
|
6
|
+
* dashboard rendering pipeline.
|
|
7
|
+
*/
|
|
8
|
+
/** HTML-escape a value for use inside raw template strings. */
|
|
9
|
+
export declare function escape(s: string): string;
|
|
10
|
+
/** Format a Date (or ISO string) using the browser's locale. */
|
|
11
|
+
export declare function formatTimestamp(d: Date | string): string;
|
|
12
|
+
/** Format a byte count with the smallest unit that keeps the magnitude ≥ 1. */
|
|
13
|
+
export declare function formatBytes(bytes: number): string;
|
|
14
|
+
/** Tailwind class string for an HTTP status badge — colored by status range. */
|
|
15
|
+
export declare function statusColor(status: number): string;
|
|
16
|
+
//# sourceMappingURL=format.d.ts.map
|