@hazeljs/inspector 2.0.0 → 2.0.2
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 -7
- package/dist/inspector.module.js +121 -0
- package/package.json +18 -18
- package/ui-dist/assets/index-BMiGVZZN.js +87 -0
- package/ui-dist/index.html +20 -1
- package/ui-dist/assets/index-WT8tdMSx.js +0 -81
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Framework-aware runtime inspector for HazelJS. Explore metadata, routes, modules
|
|
|
9
9
|
- **DevTools UI** – Overview dashboard, search, filters, detail views, runtime stats
|
|
10
10
|
- **JSON API** – Consume inspector data programmatically
|
|
11
11
|
- **Agent OS timelines** – SSE live stream + JSON replay for agent execution steps
|
|
12
|
+
- **Agent Runs** – Durable `AgentRunRepository` list/detail/cancel + in-process metrics/cost strip
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
14
15
|
|
|
@@ -53,13 +54,18 @@ Then run your app and open:
|
|
|
53
54
|
|
|
54
55
|
When agents are registered, Inspector exposes live debugging endpoints:
|
|
55
56
|
|
|
56
|
-
| Endpoint | Description
|
|
57
|
-
| ------------------------------------ |
|
|
58
|
-
| `GET /__hazel/agents/:name/stream` | SSE stream of timeline steps while the agent runs
|
|
59
|
-
| `GET /__hazel/agents/:name/timeline` | JSON replay of recorded timeline steps
|
|
60
|
-
| `POST /__hazel/agents/:name/run` | Run the agent from the UI (optional input prompt)
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
| Endpoint | Description |
|
|
58
|
+
| ------------------------------------ | ------------------------------------------------------------- |
|
|
59
|
+
| `GET /__hazel/agents/:name/stream` | SSE stream of timeline steps while the agent runs |
|
|
60
|
+
| `GET /__hazel/agents/:name/timeline` | JSON replay of recorded timeline steps |
|
|
61
|
+
| `POST /__hazel/agents/:name/run` | Run the agent from the UI (optional input prompt) |
|
|
62
|
+
| `GET /__hazel/runs` | List durable `AgentRun` records (`agentName`, `status` query) |
|
|
63
|
+
| `GET /__hazel/runs/:runId` | Run detail + timeline steps for that execution |
|
|
64
|
+
| `POST /__hazel/runs/:runId/cancel` | Cancel in-flight + mark run cancelled |
|
|
65
|
+
| `GET /__hazel/agents/metrics` | In-process metrics / cost summary |
|
|
66
|
+
|
|
67
|
+
In the Agents panel, use **Run** (executes + streams) or **Timeline** (loads history and opens the live SSE feed).
|
|
68
|
+
Open **Agent Runs** for durable repository records and the cost/metrics strip.
|
|
63
69
|
|
|
64
70
|
```bash
|
|
65
71
|
# Replay last timeline
|
package/dist/inspector.module.js
CHANGED
|
@@ -297,6 +297,123 @@ function createInspectorHandler(service, config, app) {
|
|
|
297
297
|
res.end(JSON.stringify({ entries: agents }));
|
|
298
298
|
return;
|
|
299
299
|
}
|
|
300
|
+
// Agent OS durable runs (AgentRunRepository)
|
|
301
|
+
if ((pathSeg === '/runs' || pathSeg === '/runs/') && req.method === 'GET') {
|
|
302
|
+
try {
|
|
303
|
+
const { AgentService } = require('@hazeljs/agent');
|
|
304
|
+
const container = app.getContainer();
|
|
305
|
+
const svc = container.resolve(AgentService);
|
|
306
|
+
const runtime = svc?.getRuntime?.();
|
|
307
|
+
if (!runtime?.getRunRepository) {
|
|
308
|
+
res.writeHead(503);
|
|
309
|
+
res.end(JSON.stringify({
|
|
310
|
+
error: 'AgentRunRepository not available. Ensure AgentModule + AgentRuntime are configured.',
|
|
311
|
+
}));
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
315
|
+
const agentName = url.searchParams.get('agentName') ?? undefined;
|
|
316
|
+
const status = url.searchParams.get('status') ?? undefined;
|
|
317
|
+
const runs = await runtime.getRunRepository().list(agentName || status
|
|
318
|
+
? {
|
|
319
|
+
...(agentName ? { agentName } : {}),
|
|
320
|
+
...(status ? { status: status } : {}),
|
|
321
|
+
}
|
|
322
|
+
: undefined);
|
|
323
|
+
res.writeHead(200);
|
|
324
|
+
res.end(JSON.stringify({ runs }));
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
res.writeHead(500);
|
|
328
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
329
|
+
}
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const runCancelMatch = pathSeg.match(/^\/runs\/([^/]+)\/cancel\/?$/);
|
|
333
|
+
if (runCancelMatch && req.method === 'POST') {
|
|
334
|
+
const runId = decodeURIComponent(runCancelMatch[1]);
|
|
335
|
+
try {
|
|
336
|
+
const { AgentService, AgentRunStatus } = require('@hazeljs/agent');
|
|
337
|
+
const container = app.getContainer();
|
|
338
|
+
const svc = container.resolve(AgentService);
|
|
339
|
+
const runtime = svc?.getRuntime?.();
|
|
340
|
+
if (!runtime?.getRunRepository) {
|
|
341
|
+
res.writeHead(503);
|
|
342
|
+
res.end(JSON.stringify({ error: 'AgentRunRepository not available' }));
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
runtime.cancel?.(runId);
|
|
346
|
+
const existing = await runtime.getRunRepository().get(runId);
|
|
347
|
+
if (!existing) {
|
|
348
|
+
res.writeHead(404);
|
|
349
|
+
res.end(JSON.stringify({ error: `Run not found: ${runId}` }));
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const updated = await runtime
|
|
353
|
+
.getRunRepository()
|
|
354
|
+
.updateStatus(runId, AgentRunStatus.CANCELLED);
|
|
355
|
+
res.writeHead(200);
|
|
356
|
+
res.end(JSON.stringify({ run: updated }));
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
res.writeHead(500);
|
|
360
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
361
|
+
}
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const runMatch = pathSeg.match(/^\/runs\/([^/]+)\/?$/);
|
|
365
|
+
if (runMatch && req.method === 'GET') {
|
|
366
|
+
const runId = decodeURIComponent(runMatch[1]);
|
|
367
|
+
try {
|
|
368
|
+
const { AgentService } = require('@hazeljs/agent');
|
|
369
|
+
const container = app.getContainer();
|
|
370
|
+
const svc = container.resolve(AgentService);
|
|
371
|
+
const runtime = svc?.getRuntime?.();
|
|
372
|
+
if (!runtime?.getRunRepository) {
|
|
373
|
+
res.writeHead(503);
|
|
374
|
+
res.end(JSON.stringify({ error: 'AgentRunRepository not available' }));
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const run = await runtime.getRunRepository().get(runId);
|
|
378
|
+
if (!run) {
|
|
379
|
+
res.writeHead(404);
|
|
380
|
+
res.end(JSON.stringify({ error: `Run not found: ${runId}` }));
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const steps = svc.getTimeline?.({ executionId: runId }) ?? [];
|
|
384
|
+
res.writeHead(200);
|
|
385
|
+
res.end(JSON.stringify({ run, steps }));
|
|
386
|
+
}
|
|
387
|
+
catch (err) {
|
|
388
|
+
res.writeHead(500);
|
|
389
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
390
|
+
}
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if ((pathSeg === '/agents/metrics' || pathSeg === '/agents/metrics/') &&
|
|
394
|
+
req.method === 'GET') {
|
|
395
|
+
try {
|
|
396
|
+
const { AgentService } = require('@hazeljs/agent');
|
|
397
|
+
const container = app.getContainer();
|
|
398
|
+
const svc = container.resolve(AgentService);
|
|
399
|
+
const runtime = svc?.getRuntime?.();
|
|
400
|
+
if (!runtime) {
|
|
401
|
+
res.writeHead(503);
|
|
402
|
+
res.end(JSON.stringify({ error: 'AgentRuntime not available' }));
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
res.writeHead(200);
|
|
406
|
+
res.end(JSON.stringify({
|
|
407
|
+
metrics: runtime.getMetrics?.() ?? null,
|
|
408
|
+
summary: runtime.getMetricsSummary?.() ?? null,
|
|
409
|
+
}));
|
|
410
|
+
}
|
|
411
|
+
catch (err) {
|
|
412
|
+
res.writeHead(500);
|
|
413
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
414
|
+
}
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
300
417
|
const agentRunMatch = pathSeg.match(/^\/agents\/([^/]+)\/run\/?$/);
|
|
301
418
|
if (agentRunMatch && req.method === 'POST') {
|
|
302
419
|
const agentName = decodeURIComponent(agentRunMatch[1]);
|
|
@@ -554,8 +671,12 @@ function createInspectorHandler(service, config, app) {
|
|
|
554
671
|
'/queues',
|
|
555
672
|
'/websocket',
|
|
556
673
|
'/agents',
|
|
674
|
+
'/agents/metrics',
|
|
557
675
|
'/agents/:name/stream',
|
|
558
676
|
'/agents/:name/timeline',
|
|
677
|
+
'/runs',
|
|
678
|
+
'/runs/:runId',
|
|
679
|
+
'/runs/:runId/cancel',
|
|
559
680
|
'/rag',
|
|
560
681
|
'/prompts',
|
|
561
682
|
'/aifunctions',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hazeljs/inspector",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Framework-aware runtime inspector for HazelJS - metadata explorer and DevTools UI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,22 +22,22 @@
|
|
|
22
22
|
"reflect-metadata": "^0.2.2"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@hazeljs/agent": "^2.0.
|
|
26
|
-
"@hazeljs/ai": "^2.0.
|
|
27
|
-
"@hazeljs/core": "^2.0.
|
|
28
|
-
"@hazeljs/cron": "^2.0.
|
|
29
|
-
"@hazeljs/data": "^2.0.
|
|
30
|
-
"@hazeljs/event-emitter": "^2.0.
|
|
31
|
-
"@hazeljs/flow": "^2.0.
|
|
32
|
-
"@hazeljs/graphql": "^2.0.
|
|
33
|
-
"@hazeljs/grpc": "^2.0.
|
|
34
|
-
"@hazeljs/kafka": "^2.0.
|
|
35
|
-
"@hazeljs/ml": "^2.0.
|
|
36
|
-
"@hazeljs/prompts": "^2.0.
|
|
37
|
-
"@hazeljs/queue": "^2.0.
|
|
38
|
-
"@hazeljs/rag": "^2.0.
|
|
39
|
-
"@hazeljs/serverless": "^2.0.
|
|
40
|
-
"@hazeljs/websocket": "^2.0.
|
|
25
|
+
"@hazeljs/agent": "^2.0.2",
|
|
26
|
+
"@hazeljs/ai": "^2.0.2",
|
|
27
|
+
"@hazeljs/core": "^2.0.2",
|
|
28
|
+
"@hazeljs/cron": "^2.0.2",
|
|
29
|
+
"@hazeljs/data": "^2.0.2",
|
|
30
|
+
"@hazeljs/event-emitter": "^2.0.2",
|
|
31
|
+
"@hazeljs/flow": "^2.0.2",
|
|
32
|
+
"@hazeljs/graphql": "^2.0.2",
|
|
33
|
+
"@hazeljs/grpc": "^2.0.2",
|
|
34
|
+
"@hazeljs/kafka": "^2.0.2",
|
|
35
|
+
"@hazeljs/ml": "^2.0.2",
|
|
36
|
+
"@hazeljs/prompts": "^2.0.2",
|
|
37
|
+
"@hazeljs/queue": "^2.0.2",
|
|
38
|
+
"@hazeljs/rag": "^2.0.2",
|
|
39
|
+
"@hazeljs/serverless": "^2.0.2",
|
|
40
|
+
"@hazeljs/websocket": "^2.0.2"
|
|
41
41
|
},
|
|
42
42
|
"peerDependenciesMeta": {
|
|
43
43
|
"@hazeljs/cron": {
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
-
"@hazeljs/core": "^2.0.
|
|
90
|
+
"@hazeljs/core": "^2.0.2",
|
|
91
91
|
"@types/jest": "^29.5.14",
|
|
92
92
|
"@types/node": "^20.19.39",
|
|
93
93
|
"@typescript-eslint/eslint-plugin": "^8.58.0",
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=(()=>{let e=window.location.pathname.match(/^\/[^/]+/);return e?e[0]:`/__hazel`})(),t=window.location.origin,n=null,r=!1,i=[],a=60;async function o(t=!1){let n=`${e}/inspect${t?`?refresh=1`:``}`,r=await fetch(n);if(!r.ok)throw Error(`Failed to fetch: ${r.status}`);return r.json()}async function s(){let t=await fetch(`${e}/stats`);return t.ok?t.json():{}}async function c(){let t=await fetch(`${e}/env`);return t.ok?t.json():{}}async function l(e){try{let n=await fetch(`${t}${e}`),r=n.ok,i;return i=n.headers.get(`content-type`)?.includes(`application/json`)?await n.json():await n.text(),{status:r?`up`:`down`,ok:r,data:i}}catch{return{status:`down`,ok:!1}}}function u(e){let t=document.getElementById(`loading-overlay`);t&&t.classList.toggle(`hidden`,!e)}function d(e,t){let n=document.getElementById(`status-dot`),r=document.getElementById(`status-text`),i=document.getElementById(`status-uptime`);if(!n||!r||!i)return;let a=e?.health?.ok&&e?.ready?.ok&&e?.startup?.ok,o=e?.health?.ok||e?.ready?.ok||e?.startup?.ok;n.className=`status-dot`+(a?` healthy`:o?``:` unhealthy`),r.textContent=a?`All systems operational`:o?`Degraded`:`Offline`,i.textContent=t.uptimeSeconds==null?``:`Uptime: ${m(t.uptimeSeconds)}`}function f(e){let t=document.getElementById(`quick-stats`);if(!t)return;let n=e&&typeof e==`object`?e:{},r=[];(n.route??0)>0&&r.push(`<span class="quick-stat"><strong>${n.route}</strong> routes</span>`),(n.module??0)>0&&r.push(`<span class="quick-stat"><strong>${n.module}</strong> modules</span>`),(n.provider??0)>0&&r.push(`<span class="quick-stat"><strong>${n.provider}</strong> providers</span>`),(n.cron??0)>0&&r.push(`<span class="quick-stat"><strong>${n.cron}</strong> jobs</span>`),t.innerHTML=r.join(``)||`<span class="quick-stat muted">No data</span>`}function p(e){let t=document.getElementById(`offline-banner`);e&&!t&&(t=document.createElement(`div`),t.id=`offline-banner`,t.className=`offline-banner`,t.innerHTML=`<span>App not running. Check that your server is started.</span><button id="retry-btn">Retry</button>`,document.querySelector(`.content`)?.insertBefore(t,document.querySelector(`.toolbar`)),t.querySelector(`#retry-btn`)?.addEventListener(`click`,()=>X(!0))),t&&t.classList.toggle(`hidden`,!e)}function m(e){return e<60?`${Math.floor(e)}s`:e<3600?`${Math.floor(e/60)}m ${e%60}s`:`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`}function h(e){let t=String(e||``).toUpperCase();return`<span class="badge badge-${t===`GET`?`get`:t===`POST`?`post`:t===`PUT`?`put`:t===`PATCH`?`patch`:t===`DELETE`?`delete`:`default`}">${t||`?`}</span>`}function g(e){return JSON.stringify(e,null,2).replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,e=>{let t=`json-number`;return/^"/.test(e)?t=e.endsWith(`:`)?`json-key`:`json-string`:/true|false/.test(e)?t=`json-boolean`:/null/.test(e)&&(t=`json-null`),`<span class="${t}">${_(e)}</span>`})}function _(e){let t=document.createElement(`div`);return t.textContent=e,t.innerHTML}var v={route:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`,module:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>`,provider:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>`,cron:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`,queue:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>`,websocket:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>`,agent:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/></svg>`,rag:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/><path d="M8 7h8"/><path d="M8 11h8"/></svg>`,prompt:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>`,aifunction:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>`,event:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4"/><path d="M16 2v4"/><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M3 10h18"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/></svg>`,graphql:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18"/><path d="M5 12h14"/><path d="M3 8l9-5 9 5"/><path d="M3 16l9 5 9-5"/></svg>`,grpc:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5l7 7-7 7"/></svg>`,kafka:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><path d="M9 9h6"/><path d="M9 13h6"/><path d="M9 17h4"/></svg>`,flow:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>`,data:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>`,serverless:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg>`,ml:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>`,decorator:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>`},y=[{title:`Framework`,items:[{key:`route`,label:`Routes`},{key:`module`,label:`Modules`},{key:`provider`,label:`Providers`},{key:`decorator`,label:`Decorators`}]},{title:`Scheduled & Async`,items:[{key:`cron`,label:`Cron Jobs`},{key:`queue`,label:`Queues`}]},{title:`AI & Intelligence`,items:[{key:`agent`,label:`Agents`},{key:`aifunction`,label:`AI Functions`},{key:`rag`,label:`RAG`},{key:`prompt`,label:`Prompts`},{key:`ml`,label:`ML`}]},{title:`APIs & Messaging`,items:[{key:`graphql`,label:`GraphQL`},{key:`grpc`,label:`gRPC`},{key:`kafka`,label:`Kafka`},{key:`websocket`,label:`WebSockets`},{key:`event`,label:`Events`}]},{title:`Workflows & Data`,items:[{key:`flow`,label:`Flows`},{key:`data`,label:`Data`},{key:`serverless`,label:`Serverless`}]}];function b(e){let t=document.getElementById(`summary-cards`),n=e&&typeof e==`object`?e:{};t.innerHTML=y.map(e=>`
|
|
2
|
+
<section class="overview-section">
|
|
3
|
+
<h3 class="overview-section-title">${_(e.title)}</h3>
|
|
4
|
+
<div class="overview-section-cards">
|
|
5
|
+
${(Array.isArray(e.items)?e.items:[]).map(e=>`<div class="card" data-kind="${_(e.key)}">
|
|
6
|
+
<div class="card-icon">${v[e.key]??``}</div>
|
|
7
|
+
<div class="card-label">${_(e.label)}</div>
|
|
8
|
+
<div class="card-value">${n[e.key]??0}</div>
|
|
9
|
+
</div>`).join(``)}
|
|
10
|
+
</div>
|
|
11
|
+
</section>
|
|
12
|
+
`).join(``)}var x={heap:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>`,rss:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8"/><path d="M12 17v4"/></svg>`,uptime:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`};function S(e){let t=document.getElementById(`env-info`);t&&(t.innerHTML=`
|
|
13
|
+
<div class="env-item"><strong>Node</strong> ${_(e.nodeVersion??`—`)}</div>
|
|
14
|
+
<div class="env-item"><strong>NODE_ENV</strong> ${_(e.nodeEnv??`—`)}</div>
|
|
15
|
+
<div class="env-item"><strong>Inspector</strong> ${_(e.inspectorVersion??`—`)}</div>
|
|
16
|
+
<div class="env-item"><strong>Platform</strong> ${_(e.platform??`—`)}</div>
|
|
17
|
+
<div class="env-item"><strong>Arch</strong> ${_(e.arch??`—`)}</div>
|
|
18
|
+
`)}function C(e){let t=document.getElementById(`overview-gateway`);if(!t)return;let n=Array.isArray(e.routes)?e.routes:[],r=e.metrics;t.innerHTML=`
|
|
19
|
+
<h3 class="overview-block-title">Gateway</h3>
|
|
20
|
+
<div class="overview-gateway-stats">
|
|
21
|
+
<div class="overview-stat"><span class="stat-value">${n.length}</span><span class="stat-label">Routes</span></div>
|
|
22
|
+
${r?`
|
|
23
|
+
<div class="overview-stat"><span class="stat-value">${r.totalCalls}</span><span class="stat-label">Total Calls</span></div>
|
|
24
|
+
<div class="overview-stat"><span class="stat-value">${r.successCalls}</span><span class="stat-label">Success</span></div>
|
|
25
|
+
<div class="overview-stat"><span class="stat-value">${(r.failureRate??0).toFixed(1)}%</span><span class="stat-label">Failure Rate</span></div>
|
|
26
|
+
<div class="overview-stat"><span class="stat-value">${(r.averageResponseTime??0).toFixed(0)}ms</span><span class="stat-label">Avg Latency</span></div>
|
|
27
|
+
`:``}
|
|
28
|
+
</div>
|
|
29
|
+
${n.length?`<div class="overview-gateway-routes"><strong>Routes:</strong> ${n.slice(0,8).map(e=>`<code>${_(e)}</code>`).join(`, `)}${n.length>8?` <span class="muted">+${n.length-8} more</span>`:``}</div>`:``}
|
|
30
|
+
`,t.classList.remove(`hidden`)}function w(e){let t=document.getElementById(`overview-discovery`);if(!t)return;let n=Array.isArray(e.services)?e.services:[],r=e.instancesByService&&typeof e.instancesByService==`object`?e.instancesByService:{},i=n.slice(0,6).map(e=>`<span class="discovery-service"><code>${_(e)}</code>: ${r[e]??0} instance(s)</span>`).join(`, `);t.innerHTML=`
|
|
31
|
+
<h3 class="overview-block-title">Discovery</h3>
|
|
32
|
+
<div class="overview-discovery-stats">
|
|
33
|
+
<div class="overview-stat"><span class="stat-value">${e.totalServices??0}</span><span class="stat-label">Services</span></div>
|
|
34
|
+
<div class="overview-stat"><span class="stat-value">${e.totalInstances??0}</span><span class="stat-label">Connected Instances</span></div>
|
|
35
|
+
</div>
|
|
36
|
+
${n.length?`<div class="overview-discovery-services">${i}${n.length>6?` <span class="muted">+${n.length-6} more</span>`:``}</div>`:`<p class="muted">No services registered</p>`}
|
|
37
|
+
`,t.classList.remove(`hidden`)}function ee(e){let t=document.getElementById(`overview-resilience`);if(!t)return;let n=Array.isArray(e.circuitBreakerStates)?e.circuitBreakerStates:[],r=n.map(e=>`<span class="cb-state ${(e.state||``).toLowerCase()}"><code>${_(e.name)}</code>: ${_(e.state)}</span>`).join(`, `);t.innerHTML=`
|
|
38
|
+
<h3 class="overview-block-title">Resilience</h3>
|
|
39
|
+
<div class="overview-resilience-stats">
|
|
40
|
+
<div class="overview-stat"><span class="stat-value">${e.circuitBreakers??0}</span><span class="stat-label">Circuit Breakers</span></div>
|
|
41
|
+
</div>
|
|
42
|
+
${n.length?`<div class="overview-resilience-states">${r}</div>`:``}
|
|
43
|
+
`,t.classList.remove(`hidden`)}function te(e){let t=document.getElementById(`health-cards`);t&&(t.innerHTML=[{key:`health`,endpoint:`/health`,label:`Health`,data:e.health},{key:`ready`,endpoint:`/ready`,label:`Ready`,data:e.ready},{key:`startup`,endpoint:`/startup`,label:`Startup`,data:e.startup}].map(e=>{let t=e.data??{status:`unknown`,ok:!1};return`
|
|
44
|
+
<div class="health-card ${t.ok?`healthy`:t.status===`unknown`?`unknown`:`unhealthy`}">
|
|
45
|
+
<h3>${_(e.label)}</h3>
|
|
46
|
+
<div class="status">${t.ok?`Up`:t.status===`unknown`?`Unknown`:`Down`}</div>
|
|
47
|
+
<div class="endpoint">${_(e.endpoint)}</div>
|
|
48
|
+
</div>
|
|
49
|
+
`}).join(``))}function ne(e){let t=document.getElementById(`runtime-cards`),n=e=>(e/1024/1024).toFixed(2);e.memory&&(i.push({heap:e.memory.heapUsed,rss:e.memory.rss,t:Date.now()}),i.length>a&&i.shift()),t.innerHTML=`
|
|
50
|
+
<div class="card">
|
|
51
|
+
<div class="card-icon">${x.heap}</div>
|
|
52
|
+
<div class="card-label">Heap Used</div>
|
|
53
|
+
<div class="card-value">${e.memory?.heapUsed?n(e.memory.heapUsed)+` MB`:`—`}</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="card">
|
|
56
|
+
<div class="card-icon">${x.rss}</div>
|
|
57
|
+
<div class="card-label">RSS Memory</div>
|
|
58
|
+
<div class="card-value">${e.memory?.rss?n(e.memory.rss)+` MB`:`—`}</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="card">
|
|
61
|
+
<div class="card-icon">${x.uptime}</div>
|
|
62
|
+
<div class="card-label">Uptime</div>
|
|
63
|
+
<div class="card-value highlight">${e.uptimeSeconds==null?`—`:m(e.uptimeSeconds)}</div>
|
|
64
|
+
</div>
|
|
65
|
+
`,T()}function T(){let e=document.getElementById(`memory-chart-container`);if(!e||i.length<2){e?.classList.add(`hidden`);return}e.classList.remove(`hidden`);let t=Math.max(...i.map(e=>e.heap)),n=Math.max(...i.map(e=>e.rss)),r=Math.max(t,n,1),a=e=>e/1024/1024/r*100;e.innerHTML=`
|
|
66
|
+
<svg width="100%" height="100%" viewBox="0 0 400 180" preserveAspectRatio="none">
|
|
67
|
+
<polyline fill="none" stroke="var(--accent)" stroke-width="2" points="${i.map((e,t)=>`${t/(i.length-1)*100},${100-a(e.heap)}`).join(` `)}"/>
|
|
68
|
+
</svg>
|
|
69
|
+
<div style="font-size:11px;color:var(--text-muted);margin-top:0.5rem">Heap over time (last ${i.length} samples)</div>
|
|
70
|
+
`}var E={},D=50;function O(e){let t=new Map;for(let n of e){let e=String(n.flowId??``);t.has(e)||t.set(e,[]),t.get(e).push(n)}let n=new Map;for(let[e,r]of t){let t=r.find(e=>!!String(e.nodes??``).trim())??r[0],i=(t.nodes??``).split(/[,]/).map(e=>e.trim()).filter(Boolean);i.length===0&&(i=r.map(e=>e.nodeName).filter(e=>!!e));let a=(t.edges??``).toString().split(/[;,]/).map(e=>e.trim()).filter(Boolean).map(e=>{let t=e.indexOf(`→`);if(t<0)return null;let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();return n&&r?{from:n,to:r}:null}).filter(e=>e!=null);for(let e of r){let t=(e.edges??``).toString().split(/[;,]/);for(let e of t){let t=e.indexOf(`→`);if(t>=0){let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();n&&r&&!a.some(e=>e.from===n&&e.to===r)&&a.push({from:n,to:r})}}}let o=String(t.entryNode??i[0]??``);n.set(e,{nodes:[...new Set(i)],edges:a,entryNode:o})}return n}var k=48,A=24,j=6;function M(e){let t=new Map,n=new Map,r=e.entryNode||e.nodes[0];if(!r)return t;n.set(r,0);let i=[r],a=new Set([r]);for(;i.length>0;){let t=i.shift(),r=n.get(t)??0;for(let o of e.edges)if(o.from===t)if(!a.has(o.to))a.add(o.to),n.set(o.to,r+1),i.push(o.to);else{let e=n.get(o.to)??0;r+1>e&&n.set(o.to,r+1)}}let o=Math.max(0,...Array.from(n.values()));for(let t of e.nodes)n.has(t)||n.set(t,o+1);let s=new Map;for(let[e,t]of n)s.has(t)||s.set(t,[]),s.get(t).push(e);let c=[...s.keys()].sort((e,t)=>e-t);for(let e=0;e<c.length;e++){let n=c[e],r=s.get(n)??[];for(let n=0;n<r.length;n++){let i=r[n],a=j+e*54,o=j+n*28;t.set(i,{x:a,y:o})}}return t}function N(e){let t=document.getElementById(`flow-diagram`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=O(n);if(r.size===0){t?.classList.add(`hidden`);return}let i=k,a=A,o=``;for(let[e,t]of r){let n=M(t);if(n.size===0)continue;let r=Math.max(...Array.from(n.values()).map(e=>e.x))+i+j*2,s=Math.max(...Array.from(n.values()).map(e=>e.y))+a+j*2,c=`<svg class="flow-diagram-svg" viewBox="0 0 ${Math.max(240,r)} ${Math.max(48,s)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:r}of t.edges){let t=n.get(e),o=n.get(r);if(t&&o){let e=t.x+i,n=t.y+a/2,r=o.x,s=o.y+a/2,l=(e+r)/2;c+=`<path d="M ${e} ${n} C ${l} ${n} ${l} ${s} ${r} ${s}" fill="none" stroke="var(--flow-edge)" stroke-width="1" class="flow-edge"/>`;let u=r-4*Math.cos(Math.PI/6),d=s-4*Math.sin(Math.PI/6),f=r-4*Math.cos(-Math.PI/6),p=s-4*Math.sin(-Math.PI/6);c+=`<polygon points="${r},${s} ${u},${d} ${f},${p}" fill="var(--flow-edge)" class="flow-arrow"/>`}}for(let[e,r]of n){let n=e===t.entryNode?`flow-diagram-node entry`:`flow-diagram-node`,o=e.length>10?e.slice(0,8)+`…`:e;c+=`<g class="flow-node-group"><rect class="${n}" x="${r.x}" y="${r.y}" width="${i}" height="${a}" rx="4"/><text x="${r.x+i/2}" y="${r.y+a/2+3}" text-anchor="middle" font-size="9" fill="var(--text-primary)" class="flow-node-label">${_(o)}</text></g>`}c+=`</svg>`,o+=`<div class="flow-diagram-card"><span class="flow-diagram-badge" title="${_(e)}">${_(e)}</span><div class="flow-diagram-svg-wrap">${c}</div></div>`}t.innerHTML=o,t.classList.remove(`hidden`)}function re(e){let t=document.getElementById(`rag-explorer`),n=document.getElementById(`rag-pipeline-select`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=Array.isArray(e)?e:[];if(!i.length){t.classList.add(`hidden`);return}t.classList.remove(`hidden`),n.innerHTML=i.map(e=>`<option value="${_(String(e.pipelineName??``))}">${_(String(e.pipelineName??``))}</option>`).join(``),r.innerHTML=``}async function P(){let t=document.getElementById(`rag-pipeline-select`),n=document.getElementById(`rag-search-input`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=t.value,a=n.value.trim();if(a){r.innerHTML=`<p>Searching...</p>`;try{let t=await fetch(`${e}/rag/${encodeURIComponent(i)}/search?q=${encodeURIComponent(a)}`),n=await t.json();if(!t.ok){r.innerHTML=`<p class="error">${_(n.error??`Search failed`)}</p>`;return}let o=n.results??[];if(!o.length){r.innerHTML=`<p>No results found.</p>`;return}r.innerHTML=o.map(e=>`<div class="rag-result-item"><span class="score">${e.score==null?`—`:(e.score*100).toFixed(1)+`%`}</span> ${_(String(e.content??``).slice(0,200))}${String(e.content??``).length>200?`...`:``}</div>`).join(``)}catch(e){r.innerHTML=`<p class="error">${_(String(e))}</p>`}}}function F(e){let t=document.getElementById(`module-graph-container`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=new Map,i=[],a=n.map(e=>String(e.moduleName??``)).filter(Boolean),o=[...new Set(a)];o.forEach((e,t)=>{let n=Math.floor(t/4),i=t%4;r.set(e,{x:80+i*120,y:40+n*60})});for(let e of n){let t=String(e.moduleName??``),n=e.imports,a=Array.isArray(n)?n:typeof n==`string`?n.split(/[,;]/).map(e=>e.trim()):[];for(let e of a){let n=String(e).trim();n&&(o.includes(n)||r.has(n))&&(i.push({from:t,to:n}),r.has(n)||r.set(n,{x:80+r.size%4*120,y:40+Math.floor(r.size/4)*60}))}}let s=`<svg class="module-graph-svg" viewBox="0 0 500 ${Math.max(200,Math.ceil(o.length/4)*70)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:t}of i){let n=r.get(e),i=r.get(t);n&&i&&(s+=`<line x1="${n.x+50}" y1="${n.y+15}" x2="${i.x+50}" y2="${i.y+15}" stroke="var(--border)" stroke-width="1"/>`)}for(let[e,t]of r)s+=`<rect x="${t.x}" y="${t.y}" width="100" height="30" rx="4" fill="var(--bg-tertiary)" stroke="var(--border)"/>`,s+=`<text x="${t.x+50}" y="${t.y+20}" text-anchor="middle" font-size="11" fill="var(--text-primary)">${_(e.length>12?e.slice(0,10)+`..`:e)}</text>`;s+=`</svg>`,t.innerHTML=s,t.classList.remove(`hidden`)}function I(e,t,n,r,i,a){let o=document.getElementById(e),s=E[e]??{col:n[0],dir:`asc`},c=[...t];a?.sortable&&c.length>0&&c.sort((e,t)=>{let n=e[s.col],r=t[s.col],i=String(n??``).localeCompare(String(r??``),void 0,{numeric:!0});return s.dir===`asc`?i:-i});let l=c.length>D?c.slice(0,D):c,u=c.length>D;if(!t.length){o.innerHTML=`<thead></thead><tbody><tr><td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>No entries found</p></td></tr></tbody>`;return}let d=i??{},f=n.map(e=>{let t=e.replace(/([A-Z])/g,` $1`).trim();return`<th class="${a?.sortable?` sortable ${s.col===e?s.dir:``}`:``}" data-col="${e}">${t}</th>`});if(a?.tryRoute&&f.push(`<th>Actions</th>`),a?.runAgent&&f.push(`<th>Actions</th>`),a?.previewPrompt&&f.push(`<th>Actions</th>`),o.innerHTML=`
|
|
71
|
+
<thead><tr>${f.join(``)}</tr></thead>
|
|
72
|
+
<tbody>
|
|
73
|
+
${l.map(e=>{let t=``;if(a?.tryRoute&&e.fullPath!=null){let n=String(e.fullPath);t=`<td><button class="btn btn-sm try-route" data-method="${String(e.httpMethod??`GET`).toUpperCase()}" data-path="${_(n)}">Try</button></td>`}else if(a?.runAgent&&e.agentName!=null){let n=_(String(e.agentName));t=`<td><button class="btn btn-sm run-agent" data-name="${n}">Run</button> <button class="btn btn-sm timeline-agent" data-name="${n}">Timeline</button></td>`}else a?.previewPrompt&&e.promptKey!=null?t=`<td><button class="btn btn-sm preview-prompt" data-key="${_(String(e.promptKey))}">Preview</button></td>`:(a?.tryRoute||a?.runAgent||a?.previewPrompt)&&(t=`<td></td>`);return`<tr data-id="${e.id??``}" data-json='${JSON.stringify(e).replace(/'/g,`\\'`)}'>
|
|
74
|
+
${n.map(t=>{let n=e[t],r=d[t];return`<td>${r?r(n,e):String(n??`—`)}</td>`}).join(``)}
|
|
75
|
+
${t}
|
|
76
|
+
</tr>`}).join(``)}
|
|
77
|
+
</tbody>
|
|
78
|
+
`,u){let e=document.createElement(`tr`);e.innerHTML=`<td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>Showing ${D} of ${c.length}. Use search to filter.</p></td>`,o.querySelector(`tbody`).appendChild(e)}o.querySelectorAll(`tbody tr[data-json]`).forEach(e=>{e.addEventListener(`click`,t=>{if(t.target.closest(`button`))return;let n=e.dataset.json;n&&U(JSON.parse(n))})}),o.querySelectorAll(`th.sortable`).forEach(o=>{o.addEventListener(`click`,()=>{let c=o.dataset.col;E[e]={col:c,dir:s.col===c&&s.dir===`asc`?`desc`:`asc`},I(e,t,n,r,i,a)})}),o.querySelectorAll(`.try-route`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),L(e.dataset.method??`GET`,e.dataset.path??`/`)})}),o.querySelectorAll(`.run-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),ie(e.dataset.name??``)})}),o.querySelectorAll(`.timeline-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),B(e.dataset.name??``)})}),o.querySelectorAll(`.preview-prompt`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),ue(e.dataset.key??``)})})}function L(e,n){let r=document.getElementById(`route-test-modal`),i=document.getElementById(`test-url`),a=document.getElementById(`test-method`),o=document.getElementById(`test-body-group`),s=document.getElementById(`test-result`);i.value=`${t}${n}`,a.value=e,o.classList.toggle(`hidden`,e===`GET`),s.classList.add(`hidden`),r.classList.remove(`hidden`)}var R=null;function z(e){let t=document.getElementById(`agent-timeline`);if(t){if(!e.length){t.innerHTML=`<p class="muted">No timeline events yet. Run an agent to stream steps.</p>`;return}t.innerHTML=e.map(e=>{let t=_(String(e.type??``)),n=e.state?`<span class="badge">${_(String(e.state))}</span>`:``,r=e.durationMs==null?``:`<span class="muted">${_(String(e.durationMs))}ms</span>`,i=e.confidence==null?``:`<span class="muted">confidence ${_(String(e.confidence))}</span>`,a=e.tokens==null?``:`<span class="muted">${_(String(e.tokens))} tok</span>`,o=e.cost==null?``:`<span class="muted">$${_(String(e.cost))}</span>`,s=e.prompt?`<pre class="timeline-prompt">${_(String(e.prompt).slice(0,400))}</pre>`:``;return`<div class="timeline-step" data-id="${_(String(e.id??``))}">
|
|
79
|
+
<div class="timeline-step-head"><strong>${t}</strong> ${n} ${r} ${i} ${a} ${o}</div>
|
|
80
|
+
${s}
|
|
81
|
+
</div>`}).join(``)}}async function B(t){let n=document.getElementById(`agent-timeline`);n&&(n.innerHTML=`<p class="muted">Loading timeline…</p>`);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`),i=await r.json();if(!r.ok){n&&(n.innerHTML=`<p class="muted">${_(i.error??`Failed`)}</p>`);return}z(i.steps??[])}catch(e){n&&(n.innerHTML=`<p class="muted">${_(String(e))}</p>`)}R&&=(R.close(),null);let r=[];R=new EventSource(`${e}/agents/${encodeURIComponent(t)}/stream`),R.onmessage=e=>{try{let t=JSON.parse(e.data);r.push(t),z(r.slice(-100))}catch{}}}async function ie(t){let n=prompt(`Enter input for agent (or leave empty for empty string):`)??``;B(t);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/run`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({input:n})}),i=await r.json();if(!r.ok){U({error:i.error??`Agent run failed`,status:r.status});return}U({agentName:t,result:i.result});let a=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`);a.ok&&z((await a.json()).steps??[])}catch(e){U({error:String(e),agentName:t})}}function ae(e){let t=document.getElementById(`agent-run-timeline`);if(t){if(!e.length){t.innerHTML=`<p class="muted">No timeline steps for this run.</p>`;return}t.innerHTML=e.map(e=>`<div class="timeline-step"><div class="timeline-step-head"><strong>${_(String(e.type??``))}</strong> ${e.state?`<span class="badge">${_(String(e.state))}</span>`:``} ${e.durationMs==null?``:`<span class="muted">${_(String(e.durationMs))}ms</span>`} ${e.cost==null?``:`<span class="muted">$${_(String(e.cost))}</span>`}</div></div>`).join(``)}}async function oe(){let t=document.getElementById(`agent-runs-cost`);if(t)try{let n=await fetch(`${e}/agents/metrics`),r=await n.json();if(!n.ok){t.textContent=r.error??`Metrics unavailable`;return}let i=r.metrics??{},a=i.executions??{},o=i.performance??{},s=i.llm??{};t.innerHTML=[`<strong>Cost / metrics</strong>`,a.total==null?``:`executions: ${_(String(a.total))}`,a.successRate==null?``:`success: ${_(String(a.successRate))}`,o.averageDuration==null?``:`avg latency: ${_(String(o.averageDuration))}ms`,s.totalTokens==null?``:`tokens: ${_(String(s.totalTokens))}`,r.summary?`<span class="muted">${_(String(r.summary))}</span>`:``].filter(Boolean).join(` · `)}catch(e){t.textContent=String(e)}}async function V(){let t=document.getElementById(`agent-runs-table`);if(!t)return;let n=document.getElementById(`agent-runs-filter-agent`)?.value.trim(),r=document.getElementById(`agent-runs-filter-status`)?.value.trim(),i=new URLSearchParams;n&&i.set(`agentName`,n),r&&i.set(`status`,r),t.innerHTML=`<tr><td class="muted">Loading runs…</td></tr>`,await oe();try{let n=await fetch(`${e}/runs${i.toString()?`?${i}`:``}`),r=await n.json();if(!n.ok){t.innerHTML=`<tr><td class="muted">${_(r.error??`Failed`)}</td></tr>`;return}let a=r.runs??[];if(!a.length){t.innerHTML=`<tr><td class="muted">No AgentRun records. Execute an agent with a durable run store configured.</td></tr>`;return}t.innerHTML=`<thead><tr><th>id</th><th>agent</th><th>status</th><th>updated</th><th></th></tr></thead><tbody>${a.map(e=>{let t=String(e.id??``);return`<tr class="agent-run-row" data-id="${_(t)}" style="cursor:pointer">
|
|
82
|
+
<td><code>${_(t.slice(0,8))}…</code></td>
|
|
83
|
+
<td>${_(String(e.agentName??``))}</td>
|
|
84
|
+
<td><span class="badge">${_(String(e.status??``))}</span></td>
|
|
85
|
+
<td class="muted">${_(String(e.updatedAt??``))}</td>
|
|
86
|
+
<td><button type="button" class="btn btn-sm cancel-run" data-id="${_(t)}">Cancel</button></td>
|
|
87
|
+
</tr>`}).join(``)}</tbody>`,t.querySelectorAll(`.agent-run-row`).forEach(e=>{e.addEventListener(`click`,t=>{t.target.closest(`.cancel-run`)||se(e.dataset.id??``)})}),t.querySelectorAll(`.cancel-run`).forEach(t=>{t.addEventListener(`click`,async n=>{n.stopPropagation();let r=t.dataset.id??``;await fetch(`${e}/runs/${encodeURIComponent(r)}/cancel`,{method:`POST`}),await V()})})}catch(e){t.innerHTML=`<tr><td class="muted">${_(String(e))}</td></tr>`}}async function se(t){let n=document.getElementById(`agent-run-detail`),r=document.getElementById(`agent-run-timeline`);n&&(n.innerHTML=`<p class="muted">Loading…</p>`),r&&(r.innerHTML=``);try{let r=await fetch(`${e}/runs/${encodeURIComponent(t)}`),i=await r.json();if(!r.ok){n&&(n.innerHTML=`<p class="muted">${_(i.error??`Failed`)}</p>`);return}n&&(n.innerHTML=`<pre class="detail-json">${_(JSON.stringify(i.run,null,2))}</pre>`),ae(i.steps??[])}catch(e){n&&(n.innerHTML=`<p class="muted">${_(String(e))}</p>`)}}document.getElementById(`agent-runs-refresh`)?.addEventListener(`click`,()=>{V()});function ce(e){let t=document.getElementById(`prompt-playground-modal`),n=document.getElementById(`playground-key`),r=document.getElementById(`playground-vars`),i=document.getElementById(`playground-output`),a=document.getElementById(`playground-tokens`);n.value=e,r.value=`{}`,i.textContent=``,a.textContent=`—`,t.classList.remove(`hidden`)}async function le(t,n){let r=await fetch(`${e}/prompts/render`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:t,variables:n})});if(!r.ok){let e=await r.json().catch(()=>({error:r.statusText}));throw Error(e.error??`Failed to render`)}return r.json()}function ue(e){ce(e)}var H=null;function U(e){H=e;let t=document.getElementById(`detail-panel`),n=document.getElementById(`detail-title`),r=document.getElementById(`detail-content`);n.textContent=String(e.kind??`Entry`),r.innerHTML=g(e),t.classList.remove(`hidden`)}function de(){H=null,document.getElementById(`detail-panel`).classList.add(`hidden`)}function fe(){if(!H)return;let e=JSON.stringify(H,null,2);navigator.clipboard.writeText(e).then(()=>{let e=document.getElementById(`detail-copy`);if(e){let t=e.textContent;e.textContent=`Copied!`,setTimeout(()=>{e.textContent=t},1500)}})}function pe(e,t){let n=Array.isArray(e)?e:[];if(!t.trim())return n;let r=t.toLowerCase();return n.filter(e=>JSON.stringify(e).toLowerCase().includes(r))}var W={httpMethod:e=>h(String(e??``))},G={enabled:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Enabled`:`Disabled`}</span>`,nextRuns:(e,t)=>{let n=Array.isArray(e)?e:[];return n.length?n.slice(0,3).map(e=>{try{return new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}catch{return e}}).join(`, `)+(n.length>3?`...`:``):`—`}},K={moduleName:e=>String(e??`—`),scope:e=>{let t=String(e??`singleton`);return`<span class="badge ${t===`singleton`?`badge-get`:t===`request`?`badge-post`:`badge-default`}">${t}</span>`}},q={tools:e=>Array.isArray(e)?e.join(`, `):String(e??`—`)},J={streaming:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Yes`:`No`}</span>`};function Y(e,t){try{t()}catch(t){console.error(`[Inspector] ${e} failed:`,t)}}async function X(e=!1){if(!r){r=!0,u(!0),p(!1);try{let t=await o(e),r=Array.isArray(t?.entries)?t.entries:[],i=t?.summary&&typeof t.summary==`object`?t.summary:{},a=t?.overview&&typeof t.overview==`object`?t.overview:{};n={entries:r,summary:i,overview:a},Y(`overview`,()=>b(i)),a.gateway&&Y(`gatewayOverview`,()=>C(a.gateway)),a.discovery&&Y(`discoveryOverview`,()=>w(a.discovery)),a.resilience&&Y(`resilienceOverview`,()=>ee(a.resilience)),[`overview-gateway`,`overview-discovery`,`overview-resilience`].forEach(e=>{let t=document.getElementById(e);t&&!a[e.replace(`overview-`,``)]&&t.classList.add(`hidden`)});let[u,p,m]=await Promise.all([c(),Promise.all([l(`/health`),l(`/ready`),l(`/startup`)]).then(([e,t,n])=>({health:e,ready:t,startup:n})),s()]);S(u),te(p),ne(m),d(p,m),f(i);let h=n.entries.filter(e=>e.kind===`route`),g=n.entries.filter(e=>e.kind===`module`),_=n.entries.filter(e=>e.kind===`provider`),v=n.entries.filter(e=>e.kind===`cron`),y=n.entries.filter(e=>e.kind===`queue`),x=n.entries.filter(e=>e.kind===`websocket`),T=n.entries.filter(e=>e.kind===`agent`),E=n.entries.filter(e=>e.kind===`rag`),D=n.entries.filter(e=>e.kind===`prompt`),O=n.entries.filter(e=>e.kind===`aifunction`),k=n.entries.filter(e=>e.kind===`event`),A=n.entries.filter(e=>e.kind===`graphql`),j=n.entries.filter(e=>e.kind===`grpc`),M=n.entries.filter(e=>e.kind===`kafka`),P=n.entries.filter(e=>e.kind===`flow`),L=n.entries.filter(e=>e.kind===`data`),R=n.entries.filter(e=>e.kind===`serverless`),z=n.entries.filter(e=>e.kind===`ml`);I(`routes-table`,h,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,W,{sortable:!0,tryRoute:!0}),Y(`moduleGraph`,()=>F(g)),I(Z.modules,g,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(Z.providers,_,[`providerName`,`moduleName`,`scope`],`provider`,K,{sortable:!0}),I(Z.jobs,v,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,G),I(Z.queues,y,[`queueName`,`consumerName`,`className`],`queue`),I(Z.websocket,x,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(Z.agents,T,[`agentName`,`className`,`model`,`tools`],`agent`,q,{sortable:!0,runAgent:!0}),I(Z.ai,O,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,J),Y(`ragExplorer`,()=>re(E)),I(Z.rag,E,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(Z.prompts,D,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(Z.events,k,[`eventName`,`className`,`methodName`],`event`),I(Z.graphql,A,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(Z.grpc,j,[`serviceName`,`methodName`,`className`],`grpc`),I(Z.kafka,M,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let B=document.getElementById(`flow-runtime-info`);B&&B.classList.toggle(`hidden`,P.length===0),Y(`flowDiagram`,()=>N(P)),I(Z.flows,P,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`),I(Z.data,L,[`pipelineName`,`className`],`data`),I(Z.serverless,R,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(Z.ml,z,[`modelName`,`version`,`className`],`ml`)}catch(e){let t=String(e),n=t.includes(`Failed to fetch`)||t.includes(`NetworkError`)||t.includes(`Load failed`);p(n),d({health:{ok:!1},ready:{ok:!1},startup:{ok:!1}},{}),f({});let r=document.getElementById(`summary-cards`);if(r){let t=n?`Is the app running?`:`A rendering error occurred. Check the console for details.`;r.innerHTML=`<div class="overview-error"><p>Error: ${_(String(e))}</p><p>${_(t)} <button class="btn btn-sm btn-primary" id="retry-load">Retry</button></p></div>`,document.getElementById(`retry-load`)?.addEventListener(`click`,()=>X(!0))}}finally{r=!1,u(!1)}}}var Z={routes:`routes-table`,modules:`modules-table`,providers:`providers-table`,jobs:`jobs-table`,queues:`queues-table`,websocket:`websocket-table`,agents:`agents-table`,ai:`ai-table`,rag:`rag-table`,prompts:`prompts-table`,events:`events-table`,graphql:`graphql-table`,grpc:`grpc-table`,kafka:`kafka-table`,flows:`flows-table`,data:`data-table`,serverless:`serverless-table`,ml:`ml-table`},me={route:`routes`,module:`modules`,provider:`providers`,cron:`jobs`,queue:`queues`,websocket:`websocket`,agent:`agents`,aifunction:`ai`,rag:`rag`,prompt:`prompts`,event:`events`,graphql:`graphql`,grpc:`grpc`,kafka:`kafka`,flow:`flows`,data:`data`,serverless:`serverless`,ml:`ml`};function Q(e){let t=document.querySelector(`.sidebar nav a[data-tab="${e}"]`);if(t){document.querySelectorAll(`.sidebar nav a`).forEach(e=>e.classList.remove(`active`)),document.querySelectorAll(`.tab-panel`).forEach(e=>e.classList.remove(`active`)),t.classList.add(`active`),document.getElementById(e)?.classList.add(`active`);let n=new URLSearchParams(window.location.search);n.set(`tab`,e),window.history.replaceState({},``,`${window.location.pathname}?${n}`),e===`agent-runs`&&V()}}document.querySelectorAll(`.sidebar nav a`).forEach(e=>{e.addEventListener(`click`,t=>{t.preventDefault();let n=e.dataset.tab;Q(n)})}),document.getElementById(`summary-cards`)?.addEventListener(`click`,e=>{let t=e.target.closest(`.card[data-kind]`);if(t){let e=t.dataset.kind,n=e?me[e]:null;n&&Q(n)}});function he(){X(!0)}document.getElementById(`refresh`)?.addEventListener(`click`,he),document.getElementById(`refresh-sidebar`)?.addEventListener(`click`,he),document.getElementById(`detail-close`).addEventListener(`click`,de),document.getElementById(`detail-copy`)?.addEventListener(`click`,fe),document.getElementById(`export-btn`)?.addEventListener(`click`,()=>{if(!n)return;let e=new Blob([JSON.stringify(n,null,2)],{type:`application/json`}),t=document.createElement(`a`);t.href=URL.createObjectURL(e),t.download=`inspector-snapshot-${new Date().toISOString().slice(0,19).replace(/[T:]/g,`-`)}.json`,t.click(),URL.revokeObjectURL(t.href)});var ge=document.getElementById(`auto-refresh`),$=null;ge?.addEventListener(`change`,()=>{$&&clearInterval($),$=null,ge?.checked&&($=setInterval(()=>X(!1),15e3))}),document.getElementById(`test-route-btn`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`test-url`).value,t=document.getElementById(`test-method`).value,n=document.getElementById(`test-body`),r=document.getElementById(`test-result`);r.classList.remove(`hidden`),r.className=`test-result`,r.textContent=`Sending...`;try{let i={method:t};if(t!==`GET`&&n?.value)try{JSON.parse(n.value),i.body=n.value,i.headers={"Content-Type":`application/json`}}catch{r.className=`test-result error`,r.textContent=`Invalid JSON body`;return}let a=await fetch(e,i),o=await a.text();r.className=`test-result ${a.ok?`success`:`error`}`,r.textContent=`Status: ${a.status}\n\n${o.slice(0,500)}${o.length>500?`...`:``}`}catch(e){r.className=`test-result error`,r.textContent=String(e)}}),document.getElementById(`test-route-cancel`)?.addEventListener(`click`,()=>{document.getElementById(`route-test-modal`).classList.add(`hidden`)}),document.getElementById(`test-method`)?.addEventListener(`change`,e=>{let t=e.target.value;document.getElementById(`test-body-group`).classList.toggle(`hidden`,t===`GET`)}),document.getElementById(`playground-render`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`playground-key`).value,t=document.getElementById(`playground-vars`).value,n=document.getElementById(`playground-output`),r=document.getElementById(`playground-tokens`),i={};try{i=t.trim()?JSON.parse(t):{}}catch{n.textContent=`Invalid JSON in variables`,r.textContent=`—`;return}try{let{rendered:t,tokenEstimate:a}=await le(e,i);n.textContent=t,r.textContent=String(a)}catch(e){n.textContent=String(e),r.textContent=`—`}}),document.getElementById(`playground-close`)?.addEventListener(`click`,()=>{document.getElementById(`prompt-playground-modal`).classList.add(`hidden`)}),document.getElementById(`diff-btn`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.remove(`hidden`)}),document.getElementById(`diff-close`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.add(`hidden`)}),document.getElementById(`diff-load-file`)?.addEventListener(`click`,()=>{document.getElementById(`diff-file`).click()}),document.getElementById(`diff-file`)?.addEventListener(`change`,e=>{let t=e.target.files?.[0];if(!t)return;let n=new FileReader;n.onload=()=>{document.getElementById(`diff-snapshot-b`).value=String(n.result)},n.readAsText(t)}),document.getElementById(`rag-search-btn`)?.addEventListener(`click`,P),document.getElementById(`diff-compare-btn`)?.addEventListener(`click`,()=>{let e=document.getElementById(`diff-snapshot-b`).value.trim(),t=document.getElementById(`diff-result`);if(!n){t.innerHTML=`<p class="error">No current snapshot. Refresh first.</p>`,t.classList.remove(`hidden`);return}let r;try{r=e?JSON.parse(e):{entries:[],summary:{}}}catch{t.innerHTML=`<p class="error">Invalid JSON in Snapshot B.</p>`,t.classList.remove(`hidden`);return}let i=n.entries??[],a=r.entries??[],o=new Set(i.map(e=>e.id)),s=new Set(a.map(e=>e.id)),c=a.filter(e=>!o.has(e.id)),l=i.filter(e=>!s.has(e.id)),u=i.filter(e=>{let t=a.find(t=>t.id===e.id);return t&&JSON.stringify(e)!==JSON.stringify(t)}),d=``;c.length&&(d+=`<p class="added">+ ${c.length} added</p><ul>${c.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),l.length&&(d+=`<p class="removed">− ${l.length} removed</p><ul>${l.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),u.length&&(d+=`<p class="changed">~ ${u.length} changed</p><ul>${u.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),d||=`<p>No differences.</p>`,t.innerHTML=d,t.classList.remove(`hidden`)}),document.getElementById(`search`).addEventListener(`input`,e=>{let t=e.target.value;if(!n)return;let r=pe(n.entries,t),i=n.summary&&typeof n.summary==`object`?n.summary:{};b(Object.fromEntries(Object.entries(i).map(([e])=>[e,r.filter(t=>t.kind===e).length])));let a=r.filter(e=>e.kind===`route`),o=r.filter(e=>e.kind===`module`),s=r.filter(e=>e.kind===`provider`),c=r.filter(e=>e.kind===`cron`),l=r.filter(e=>e.kind===`queue`),u=r.filter(e=>e.kind===`websocket`),d=r.filter(e=>e.kind===`agent`),f=r.filter(e=>e.kind===`rag`),p=r.filter(e=>e.kind===`prompt`),m=r.filter(e=>e.kind===`aifunction`),h=r.filter(e=>e.kind===`event`),g=r.filter(e=>e.kind===`graphql`),_=r.filter(e=>e.kind===`grpc`),v=r.filter(e=>e.kind===`kafka`),y=r.filter(e=>e.kind===`flow`),x=r.filter(e=>e.kind===`data`),S=r.filter(e=>e.kind===`serverless`),C=r.filter(e=>e.kind===`ml`);I(`routes-table`,a,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,W,{sortable:!0,tryRoute:!0}),F(o),I(`modules-table`,o,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(`providers-table`,s,[`providerName`,`moduleName`,`scope`],`provider`,K,{sortable:!0}),I(`jobs-table`,c,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,G),I(`queues-table`,l,[`queueName`,`consumerName`,`className`],`queue`),I(`websocket-table`,u,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(`agents-table`,d,[`agentName`,`className`,`model`,`tools`],`agent`,q,{sortable:!0,runAgent:!0}),I(`ai-table`,m,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,J),re(f),I(`rag-table`,f,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(`prompts-table`,p,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(`events-table`,h,[`eventName`,`className`,`methodName`],`event`),I(`graphql-table`,g,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(`grpc-table`,_,[`serviceName`,`methodName`,`className`],`grpc`),I(`kafka-table`,v,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let w=document.getElementById(`flow-runtime-info`);w&&w.classList.toggle(`hidden`,y.length===0),N(y),I(`flows-table`,y,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`,void 0,{sortable:!0}),I(`data-table`,x,[`pipelineName`,`className`],`data`),I(`serverless-table`,S,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(`ml-table`,C,[`modelName`,`version`,`className`],`ml`)}),X().then(()=>{let e=new URLSearchParams(window.location.search).get(`tab`);e&&Q(e)});
|
package/ui-dist/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>HazelJS Inspector</title>
|
|
7
|
-
<script type="module" crossorigin src="/__hazel/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/__hazel/assets/index-BMiGVZZN.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/__hazel/assets/index-DsSZSL8P.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
<div class="nav-section">
|
|
56
56
|
<span class="nav-section-title">AI & Intelligence</span>
|
|
57
57
|
<a href="#" data-tab="agents"><span class="nav-icon"></span>Agents</a>
|
|
58
|
+
<a href="#" data-tab="agent-runs"><span class="nav-icon"></span>Agent Runs</a>
|
|
58
59
|
<a href="#" data-tab="ai"><span class="nav-icon"></span>AI</a>
|
|
59
60
|
<a href="#" data-tab="rag"><span class="nav-icon"></span>RAG</a>
|
|
60
61
|
<a href="#" data-tab="prompts"><span class="nav-icon"></span>Prompts</a>
|
|
@@ -164,6 +165,24 @@
|
|
|
164
165
|
<div id="agent-timeline" class="agent-timeline"></div>
|
|
165
166
|
</div>
|
|
166
167
|
</div>
|
|
168
|
+
<div id="agent-runs" class="tab-panel">
|
|
169
|
+
<h2 class="section-title">Agent Runs</h2>
|
|
170
|
+
<p class="muted" style="font-size:12px;margin:0 0 8px">
|
|
171
|
+
Durable <code>AgentRun</code> records from the runtime repository. Click a row for detail + timeline.
|
|
172
|
+
</p>
|
|
173
|
+
<div id="agent-runs-cost" class="agent-runs-cost muted" style="font-size:12px;margin:0 0 12px"></div>
|
|
174
|
+
<div class="form-group" style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px">
|
|
175
|
+
<input type="text" id="agent-runs-filter-agent" placeholder="Filter agentName" style="min-width:160px" />
|
|
176
|
+
<input type="text" id="agent-runs-filter-status" placeholder="Filter status" style="min-width:120px" />
|
|
177
|
+
<button id="agent-runs-refresh" class="btn btn-sm btn-primary" type="button">Refresh</button>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="table-container"><table id="agent-runs-table"></table></div>
|
|
180
|
+
<div id="agent-run-detail" class="agent-run-detail" style="margin-top:16px"></div>
|
|
181
|
+
<div class="agent-timeline-panel" style="margin-top:12px">
|
|
182
|
+
<h3 class="section-title">Run Timeline</h3>
|
|
183
|
+
<div id="agent-run-timeline" class="agent-timeline"></div>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
167
186
|
<div id="ai" class="tab-panel">
|
|
168
187
|
<h2 class="section-title">AI Functions</h2>
|
|
169
188
|
<div class="table-container"><table id="ai-table"></table></div>
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=(()=>{let e=window.location.pathname.match(/^\/[^/]+/);return e?e[0]:`/__hazel`})(),t=window.location.origin,n=null,r=!1,i=[],a=60;async function o(t=!1){let n=`${e}/inspect${t?`?refresh=1`:``}`,r=await fetch(n);if(!r.ok)throw Error(`Failed to fetch: ${r.status}`);return r.json()}async function s(){let t=await fetch(`${e}/stats`);return t.ok?t.json():{}}async function c(){let t=await fetch(`${e}/env`);return t.ok?t.json():{}}async function l(e){try{let n=await fetch(`${t}${e}`),r=n.ok,i;return i=n.headers.get(`content-type`)?.includes(`application/json`)?await n.json():await n.text(),{status:r?`up`:`down`,ok:r,data:i}}catch{return{status:`down`,ok:!1}}}function u(e){let t=document.getElementById(`loading-overlay`);t&&t.classList.toggle(`hidden`,!e)}function d(e,t){let n=document.getElementById(`status-dot`),r=document.getElementById(`status-text`),i=document.getElementById(`status-uptime`);if(!n||!r||!i)return;let a=e?.health?.ok&&e?.ready?.ok&&e?.startup?.ok,o=e?.health?.ok||e?.ready?.ok||e?.startup?.ok;n.className=`status-dot`+(a?` healthy`:o?``:` unhealthy`),r.textContent=a?`All systems operational`:o?`Degraded`:`Offline`,i.textContent=t.uptimeSeconds==null?``:`Uptime: ${m(t.uptimeSeconds)}`}function f(e){let t=document.getElementById(`quick-stats`);if(!t)return;let n=e&&typeof e==`object`?e:{},r=[];(n.route??0)>0&&r.push(`<span class="quick-stat"><strong>${n.route}</strong> routes</span>`),(n.module??0)>0&&r.push(`<span class="quick-stat"><strong>${n.module}</strong> modules</span>`),(n.provider??0)>0&&r.push(`<span class="quick-stat"><strong>${n.provider}</strong> providers</span>`),(n.cron??0)>0&&r.push(`<span class="quick-stat"><strong>${n.cron}</strong> jobs</span>`),t.innerHTML=r.join(``)||`<span class="quick-stat muted">No data</span>`}function p(e){let t=document.getElementById(`offline-banner`);e&&!t&&(t=document.createElement(`div`),t.id=`offline-banner`,t.className=`offline-banner`,t.innerHTML=`<span>App not running. Check that your server is started.</span><button id="retry-btn">Retry</button>`,document.querySelector(`.content`)?.insertBefore(t,document.querySelector(`.toolbar`)),t.querySelector(`#retry-btn`)?.addEventListener(`click`,()=>Y(!0))),t&&t.classList.toggle(`hidden`,!e)}function m(e){return e<60?`${Math.floor(e)}s`:e<3600?`${Math.floor(e/60)}m ${e%60}s`:`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`}function h(e){let t=String(e||``).toUpperCase();return`<span class="badge badge-${t===`GET`?`get`:t===`POST`?`post`:t===`PUT`?`put`:t===`PATCH`?`patch`:t===`DELETE`?`delete`:`default`}">${t||`?`}</span>`}function g(e){return JSON.stringify(e,null,2).replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,e=>{let t=`json-number`;return/^"/.test(e)?t=e.endsWith(`:`)?`json-key`:`json-string`:/true|false/.test(e)?t=`json-boolean`:/null/.test(e)&&(t=`json-null`),`<span class="${t}">${_(e)}</span>`})}function _(e){let t=document.createElement(`div`);return t.textContent=e,t.innerHTML}var v={route:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`,module:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>`,provider:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>`,cron:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`,queue:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>`,websocket:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>`,agent:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/></svg>`,rag:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/><path d="M8 7h8"/><path d="M8 11h8"/></svg>`,prompt:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>`,aifunction:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>`,event:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4"/><path d="M16 2v4"/><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M3 10h18"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/></svg>`,graphql:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18"/><path d="M5 12h14"/><path d="M3 8l9-5 9 5"/><path d="M3 16l9 5 9-5"/></svg>`,grpc:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5l7 7-7 7"/></svg>`,kafka:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><path d="M9 9h6"/><path d="M9 13h6"/><path d="M9 17h4"/></svg>`,flow:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>`,data:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>`,serverless:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg>`,ml:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>`,decorator:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>`},y=[{title:`Framework`,items:[{key:`route`,label:`Routes`},{key:`module`,label:`Modules`},{key:`provider`,label:`Providers`},{key:`decorator`,label:`Decorators`}]},{title:`Scheduled & Async`,items:[{key:`cron`,label:`Cron Jobs`},{key:`queue`,label:`Queues`}]},{title:`AI & Intelligence`,items:[{key:`agent`,label:`Agents`},{key:`aifunction`,label:`AI Functions`},{key:`rag`,label:`RAG`},{key:`prompt`,label:`Prompts`},{key:`ml`,label:`ML`}]},{title:`APIs & Messaging`,items:[{key:`graphql`,label:`GraphQL`},{key:`grpc`,label:`gRPC`},{key:`kafka`,label:`Kafka`},{key:`websocket`,label:`WebSockets`},{key:`event`,label:`Events`}]},{title:`Workflows & Data`,items:[{key:`flow`,label:`Flows`},{key:`data`,label:`Data`},{key:`serverless`,label:`Serverless`}]}];function b(e){let t=document.getElementById(`summary-cards`),n=e&&typeof e==`object`?e:{};t.innerHTML=y.map(e=>`
|
|
2
|
-
<section class="overview-section">
|
|
3
|
-
<h3 class="overview-section-title">${_(e.title)}</h3>
|
|
4
|
-
<div class="overview-section-cards">
|
|
5
|
-
${(Array.isArray(e.items)?e.items:[]).map(e=>`<div class="card" data-kind="${_(e.key)}">
|
|
6
|
-
<div class="card-icon">${v[e.key]??``}</div>
|
|
7
|
-
<div class="card-label">${_(e.label)}</div>
|
|
8
|
-
<div class="card-value">${n[e.key]??0}</div>
|
|
9
|
-
</div>`).join(``)}
|
|
10
|
-
</div>
|
|
11
|
-
</section>
|
|
12
|
-
`).join(``)}var x={heap:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>`,rss:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8"/><path d="M12 17v4"/></svg>`,uptime:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`};function S(e){let t=document.getElementById(`env-info`);t&&(t.innerHTML=`
|
|
13
|
-
<div class="env-item"><strong>Node</strong> ${_(e.nodeVersion??`—`)}</div>
|
|
14
|
-
<div class="env-item"><strong>NODE_ENV</strong> ${_(e.nodeEnv??`—`)}</div>
|
|
15
|
-
<div class="env-item"><strong>Inspector</strong> ${_(e.inspectorVersion??`—`)}</div>
|
|
16
|
-
<div class="env-item"><strong>Platform</strong> ${_(e.platform??`—`)}</div>
|
|
17
|
-
<div class="env-item"><strong>Arch</strong> ${_(e.arch??`—`)}</div>
|
|
18
|
-
`)}function C(e){let t=document.getElementById(`overview-gateway`);if(!t)return;let n=Array.isArray(e.routes)?e.routes:[],r=e.metrics;t.innerHTML=`
|
|
19
|
-
<h3 class="overview-block-title">Gateway</h3>
|
|
20
|
-
<div class="overview-gateway-stats">
|
|
21
|
-
<div class="overview-stat"><span class="stat-value">${n.length}</span><span class="stat-label">Routes</span></div>
|
|
22
|
-
${r?`
|
|
23
|
-
<div class="overview-stat"><span class="stat-value">${r.totalCalls}</span><span class="stat-label">Total Calls</span></div>
|
|
24
|
-
<div class="overview-stat"><span class="stat-value">${r.successCalls}</span><span class="stat-label">Success</span></div>
|
|
25
|
-
<div class="overview-stat"><span class="stat-value">${(r.failureRate??0).toFixed(1)}%</span><span class="stat-label">Failure Rate</span></div>
|
|
26
|
-
<div class="overview-stat"><span class="stat-value">${(r.averageResponseTime??0).toFixed(0)}ms</span><span class="stat-label">Avg Latency</span></div>
|
|
27
|
-
`:``}
|
|
28
|
-
</div>
|
|
29
|
-
${n.length?`<div class="overview-gateway-routes"><strong>Routes:</strong> ${n.slice(0,8).map(e=>`<code>${_(e)}</code>`).join(`, `)}${n.length>8?` <span class="muted">+${n.length-8} more</span>`:``}</div>`:``}
|
|
30
|
-
`,t.classList.remove(`hidden`)}function w(e){let t=document.getElementById(`overview-discovery`);if(!t)return;let n=Array.isArray(e.services)?e.services:[],r=e.instancesByService&&typeof e.instancesByService==`object`?e.instancesByService:{},i=n.slice(0,6).map(e=>`<span class="discovery-service"><code>${_(e)}</code>: ${r[e]??0} instance(s)</span>`).join(`, `);t.innerHTML=`
|
|
31
|
-
<h3 class="overview-block-title">Discovery</h3>
|
|
32
|
-
<div class="overview-discovery-stats">
|
|
33
|
-
<div class="overview-stat"><span class="stat-value">${e.totalServices??0}</span><span class="stat-label">Services</span></div>
|
|
34
|
-
<div class="overview-stat"><span class="stat-value">${e.totalInstances??0}</span><span class="stat-label">Connected Instances</span></div>
|
|
35
|
-
</div>
|
|
36
|
-
${n.length?`<div class="overview-discovery-services">${i}${n.length>6?` <span class="muted">+${n.length-6} more</span>`:``}</div>`:`<p class="muted">No services registered</p>`}
|
|
37
|
-
`,t.classList.remove(`hidden`)}function ee(e){let t=document.getElementById(`overview-resilience`);if(!t)return;let n=Array.isArray(e.circuitBreakerStates)?e.circuitBreakerStates:[],r=n.map(e=>`<span class="cb-state ${(e.state||``).toLowerCase()}"><code>${_(e.name)}</code>: ${_(e.state)}</span>`).join(`, `);t.innerHTML=`
|
|
38
|
-
<h3 class="overview-block-title">Resilience</h3>
|
|
39
|
-
<div class="overview-resilience-stats">
|
|
40
|
-
<div class="overview-stat"><span class="stat-value">${e.circuitBreakers??0}</span><span class="stat-label">Circuit Breakers</span></div>
|
|
41
|
-
</div>
|
|
42
|
-
${n.length?`<div class="overview-resilience-states">${r}</div>`:``}
|
|
43
|
-
`,t.classList.remove(`hidden`)}function te(e){let t=document.getElementById(`health-cards`);t&&(t.innerHTML=[{key:`health`,endpoint:`/health`,label:`Health`,data:e.health},{key:`ready`,endpoint:`/ready`,label:`Ready`,data:e.ready},{key:`startup`,endpoint:`/startup`,label:`Startup`,data:e.startup}].map(e=>{let t=e.data??{status:`unknown`,ok:!1};return`
|
|
44
|
-
<div class="health-card ${t.ok?`healthy`:t.status===`unknown`?`unknown`:`unhealthy`}">
|
|
45
|
-
<h3>${_(e.label)}</h3>
|
|
46
|
-
<div class="status">${t.ok?`Up`:t.status===`unknown`?`Unknown`:`Down`}</div>
|
|
47
|
-
<div class="endpoint">${_(e.endpoint)}</div>
|
|
48
|
-
</div>
|
|
49
|
-
`}).join(``))}function ne(e){let t=document.getElementById(`runtime-cards`),n=e=>(e/1024/1024).toFixed(2);e.memory&&(i.push({heap:e.memory.heapUsed,rss:e.memory.rss,t:Date.now()}),i.length>a&&i.shift()),t.innerHTML=`
|
|
50
|
-
<div class="card">
|
|
51
|
-
<div class="card-icon">${x.heap}</div>
|
|
52
|
-
<div class="card-label">Heap Used</div>
|
|
53
|
-
<div class="card-value">${e.memory?.heapUsed?n(e.memory.heapUsed)+` MB`:`—`}</div>
|
|
54
|
-
</div>
|
|
55
|
-
<div class="card">
|
|
56
|
-
<div class="card-icon">${x.rss}</div>
|
|
57
|
-
<div class="card-label">RSS Memory</div>
|
|
58
|
-
<div class="card-value">${e.memory?.rss?n(e.memory.rss)+` MB`:`—`}</div>
|
|
59
|
-
</div>
|
|
60
|
-
<div class="card">
|
|
61
|
-
<div class="card-icon">${x.uptime}</div>
|
|
62
|
-
<div class="card-label">Uptime</div>
|
|
63
|
-
<div class="card-value highlight">${e.uptimeSeconds==null?`—`:m(e.uptimeSeconds)}</div>
|
|
64
|
-
</div>
|
|
65
|
-
`,T()}function T(){let e=document.getElementById(`memory-chart-container`);if(!e||i.length<2){e?.classList.add(`hidden`);return}e.classList.remove(`hidden`);let t=Math.max(...i.map(e=>e.heap)),n=Math.max(...i.map(e=>e.rss)),r=Math.max(t,n,1),a=e=>e/1024/1024/r*100;e.innerHTML=`
|
|
66
|
-
<svg width="100%" height="100%" viewBox="0 0 400 180" preserveAspectRatio="none">
|
|
67
|
-
<polyline fill="none" stroke="var(--accent)" stroke-width="2" points="${i.map((e,t)=>`${t/(i.length-1)*100},${100-a(e.heap)}`).join(` `)}"/>
|
|
68
|
-
</svg>
|
|
69
|
-
<div style="font-size:11px;color:var(--text-muted);margin-top:0.5rem">Heap over time (last ${i.length} samples)</div>
|
|
70
|
-
`}var E={},D=50;function O(e){let t=new Map;for(let n of e){let e=String(n.flowId??``);t.has(e)||t.set(e,[]),t.get(e).push(n)}let n=new Map;for(let[e,r]of t){let t=r.find(e=>!!String(e.nodes??``).trim())??r[0],i=(t.nodes??``).split(/[,]/).map(e=>e.trim()).filter(Boolean);i.length===0&&(i=r.map(e=>e.nodeName).filter(e=>!!e));let a=(t.edges??``).toString().split(/[;,]/).map(e=>e.trim()).filter(Boolean).map(e=>{let t=e.indexOf(`→`);if(t<0)return null;let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();return n&&r?{from:n,to:r}:null}).filter(e=>e!=null);for(let e of r){let t=(e.edges??``).toString().split(/[;,]/);for(let e of t){let t=e.indexOf(`→`);if(t>=0){let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();n&&r&&!a.some(e=>e.from===n&&e.to===r)&&a.push({from:n,to:r})}}}let o=String(t.entryNode??i[0]??``);n.set(e,{nodes:[...new Set(i)],edges:a,entryNode:o})}return n}var k=48,re=24,A=6;function j(e){let t=new Map,n=new Map,r=e.entryNode||e.nodes[0];if(!r)return t;n.set(r,0);let i=[r],a=new Set([r]);for(;i.length>0;){let t=i.shift(),r=n.get(t)??0;for(let o of e.edges)if(o.from===t)if(!a.has(o.to))a.add(o.to),n.set(o.to,r+1),i.push(o.to);else{let e=n.get(o.to)??0;r+1>e&&n.set(o.to,r+1)}}let o=Math.max(0,...Array.from(n.values()));for(let t of e.nodes)n.has(t)||n.set(t,o+1);let s=new Map;for(let[e,t]of n)s.has(t)||s.set(t,[]),s.get(t).push(e);let c=[...s.keys()].sort((e,t)=>e-t);for(let e=0;e<c.length;e++){let n=c[e],r=s.get(n)??[];for(let n=0;n<r.length;n++){let i=r[n],a=A+e*54,o=A+n*28;t.set(i,{x:a,y:o})}}return t}function M(e){let t=document.getElementById(`flow-diagram`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=O(n);if(r.size===0){t?.classList.add(`hidden`);return}let i=k,a=re,o=``;for(let[e,t]of r){let n=j(t);if(n.size===0)continue;let r=Math.max(...Array.from(n.values()).map(e=>e.x))+i+A*2,s=Math.max(...Array.from(n.values()).map(e=>e.y))+a+A*2,c=`<svg class="flow-diagram-svg" viewBox="0 0 ${Math.max(240,r)} ${Math.max(48,s)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:r}of t.edges){let t=n.get(e),o=n.get(r);if(t&&o){let e=t.x+i,n=t.y+a/2,r=o.x,s=o.y+a/2,l=(e+r)/2;c+=`<path d="M ${e} ${n} C ${l} ${n} ${l} ${s} ${r} ${s}" fill="none" stroke="var(--flow-edge)" stroke-width="1" class="flow-edge"/>`;let u=r-4*Math.cos(Math.PI/6),d=s-4*Math.sin(Math.PI/6),f=r-4*Math.cos(-Math.PI/6),p=s-4*Math.sin(-Math.PI/6);c+=`<polygon points="${r},${s} ${u},${d} ${f},${p}" fill="var(--flow-edge)" class="flow-arrow"/>`}}for(let[e,r]of n){let n=e===t.entryNode?`flow-diagram-node entry`:`flow-diagram-node`,o=e.length>10?e.slice(0,8)+`…`:e;c+=`<g class="flow-node-group"><rect class="${n}" x="${r.x}" y="${r.y}" width="${i}" height="${a}" rx="4"/><text x="${r.x+i/2}" y="${r.y+a/2+3}" text-anchor="middle" font-size="9" fill="var(--text-primary)" class="flow-node-label">${_(o)}</text></g>`}c+=`</svg>`,o+=`<div class="flow-diagram-card"><span class="flow-diagram-badge" title="${_(e)}">${_(e)}</span><div class="flow-diagram-svg-wrap">${c}</div></div>`}t.innerHTML=o,t.classList.remove(`hidden`)}function N(e){let t=document.getElementById(`rag-explorer`),n=document.getElementById(`rag-pipeline-select`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=Array.isArray(e)?e:[];if(!i.length){t.classList.add(`hidden`);return}t.classList.remove(`hidden`),n.innerHTML=i.map(e=>`<option value="${_(String(e.pipelineName??``))}">${_(String(e.pipelineName??``))}</option>`).join(``),r.innerHTML=``}async function P(){let t=document.getElementById(`rag-pipeline-select`),n=document.getElementById(`rag-search-input`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=t.value,a=n.value.trim();if(a){r.innerHTML=`<p>Searching...</p>`;try{let t=await fetch(`${e}/rag/${encodeURIComponent(i)}/search?q=${encodeURIComponent(a)}`),n=await t.json();if(!t.ok){r.innerHTML=`<p class="error">${_(n.error??`Search failed`)}</p>`;return}let o=n.results??[];if(!o.length){r.innerHTML=`<p>No results found.</p>`;return}r.innerHTML=o.map(e=>`<div class="rag-result-item"><span class="score">${e.score==null?`—`:(e.score*100).toFixed(1)+`%`}</span> ${_(String(e.content??``).slice(0,200))}${String(e.content??``).length>200?`...`:``}</div>`).join(``)}catch(e){r.innerHTML=`<p class="error">${_(String(e))}</p>`}}}function F(e){let t=document.getElementById(`module-graph-container`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=new Map,i=[],a=n.map(e=>String(e.moduleName??``)).filter(Boolean),o=[...new Set(a)];o.forEach((e,t)=>{let n=Math.floor(t/4),i=t%4;r.set(e,{x:80+i*120,y:40+n*60})});for(let e of n){let t=String(e.moduleName??``),n=e.imports,a=Array.isArray(n)?n:typeof n==`string`?n.split(/[,;]/).map(e=>e.trim()):[];for(let e of a){let n=String(e).trim();n&&(o.includes(n)||r.has(n))&&(i.push({from:t,to:n}),r.has(n)||r.set(n,{x:80+r.size%4*120,y:40+Math.floor(r.size/4)*60}))}}let s=`<svg class="module-graph-svg" viewBox="0 0 500 ${Math.max(200,Math.ceil(o.length/4)*70)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:t}of i){let n=r.get(e),i=r.get(t);n&&i&&(s+=`<line x1="${n.x+50}" y1="${n.y+15}" x2="${i.x+50}" y2="${i.y+15}" stroke="var(--border)" stroke-width="1"/>`)}for(let[e,t]of r)s+=`<rect x="${t.x}" y="${t.y}" width="100" height="30" rx="4" fill="var(--bg-tertiary)" stroke="var(--border)"/>`,s+=`<text x="${t.x+50}" y="${t.y+20}" text-anchor="middle" font-size="11" fill="var(--text-primary)">${_(e.length>12?e.slice(0,10)+`..`:e)}</text>`;s+=`</svg>`,t.innerHTML=s,t.classList.remove(`hidden`)}function I(e,t,n,r,i,a){let o=document.getElementById(e),s=E[e]??{col:n[0],dir:`asc`},c=[...t];a?.sortable&&c.length>0&&c.sort((e,t)=>{let n=e[s.col],r=t[s.col],i=String(n??``).localeCompare(String(r??``),void 0,{numeric:!0});return s.dir===`asc`?i:-i});let l=c.length>D?c.slice(0,D):c,u=c.length>D;if(!t.length){o.innerHTML=`<thead></thead><tbody><tr><td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>No entries found</p></td></tr></tbody>`;return}let d=i??{},f=n.map(e=>{let t=e.replace(/([A-Z])/g,` $1`).trim();return`<th class="${a?.sortable?` sortable ${s.col===e?s.dir:``}`:``}" data-col="${e}">${t}</th>`});if(a?.tryRoute&&f.push(`<th>Actions</th>`),a?.runAgent&&f.push(`<th>Actions</th>`),a?.previewPrompt&&f.push(`<th>Actions</th>`),o.innerHTML=`
|
|
71
|
-
<thead><tr>${f.join(``)}</tr></thead>
|
|
72
|
-
<tbody>
|
|
73
|
-
${l.map(e=>{let t=``;if(a?.tryRoute&&e.fullPath!=null){let n=String(e.fullPath);t=`<td><button class="btn btn-sm try-route" data-method="${String(e.httpMethod??`GET`).toUpperCase()}" data-path="${_(n)}">Try</button></td>`}else if(a?.runAgent&&e.agentName!=null){let n=_(String(e.agentName));t=`<td><button class="btn btn-sm run-agent" data-name="${n}">Run</button> <button class="btn btn-sm timeline-agent" data-name="${n}">Timeline</button></td>`}else a?.previewPrompt&&e.promptKey!=null?t=`<td><button class="btn btn-sm preview-prompt" data-key="${_(String(e.promptKey))}">Preview</button></td>`:(a?.tryRoute||a?.runAgent||a?.previewPrompt)&&(t=`<td></td>`);return`<tr data-id="${e.id??``}" data-json='${JSON.stringify(e).replace(/'/g,`\\'`)}'>
|
|
74
|
-
${n.map(t=>{let n=e[t],r=d[t];return`<td>${r?r(n,e):String(n??`—`)}</td>`}).join(``)}
|
|
75
|
-
${t}
|
|
76
|
-
</tr>`}).join(``)}
|
|
77
|
-
</tbody>
|
|
78
|
-
`,u){let e=document.createElement(`tr`);e.innerHTML=`<td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>Showing ${D} of ${c.length}. Use search to filter.</p></td>`,o.querySelector(`tbody`).appendChild(e)}o.querySelectorAll(`tbody tr[data-json]`).forEach(e=>{e.addEventListener(`click`,t=>{if(t.target.closest(`button`))return;let n=e.dataset.json;n&&H(JSON.parse(n))})}),o.querySelectorAll(`th.sortable`).forEach(o=>{o.addEventListener(`click`,()=>{let c=o.dataset.col;E[e]={col:c,dir:s.col===c&&s.dir===`asc`?`desc`:`asc`},I(e,t,n,r,i,a)})}),o.querySelectorAll(`.try-route`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),L(e.dataset.method??`GET`,e.dataset.path??`/`)})}),o.querySelectorAll(`.run-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),ie(e.dataset.name??``)})}),o.querySelectorAll(`.timeline-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),B(e.dataset.name??``)})}),o.querySelectorAll(`.preview-prompt`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),se(e.dataset.key??``)})})}function L(e,n){let r=document.getElementById(`route-test-modal`),i=document.getElementById(`test-url`),a=document.getElementById(`test-method`),o=document.getElementById(`test-body-group`),s=document.getElementById(`test-result`);i.value=`${t}${n}`,a.value=e,o.classList.toggle(`hidden`,e===`GET`),s.classList.add(`hidden`),r.classList.remove(`hidden`)}var R=null;function z(e){let t=document.getElementById(`agent-timeline`);if(t){if(!e.length){t.innerHTML=`<p class="muted">No timeline events yet. Run an agent to stream steps.</p>`;return}t.innerHTML=e.map(e=>{let t=_(String(e.type??``)),n=e.state?`<span class="badge">${_(String(e.state))}</span>`:``,r=e.durationMs==null?``:`<span class="muted">${_(String(e.durationMs))}ms</span>`,i=e.confidence==null?``:`<span class="muted">confidence ${_(String(e.confidence))}</span>`,a=e.tokens==null?``:`<span class="muted">${_(String(e.tokens))} tok</span>`,o=e.cost==null?``:`<span class="muted">$${_(String(e.cost))}</span>`,s=e.prompt?`<pre class="timeline-prompt">${_(String(e.prompt).slice(0,400))}</pre>`:``;return`<div class="timeline-step" data-id="${_(String(e.id??``))}">
|
|
79
|
-
<div class="timeline-step-head"><strong>${t}</strong> ${n} ${r} ${i} ${a} ${o}</div>
|
|
80
|
-
${s}
|
|
81
|
-
</div>`}).join(``)}}async function B(t){let n=document.getElementById(`agent-timeline`);n&&(n.innerHTML=`<p class="muted">Loading timeline…</p>`);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`),i=await r.json();if(!r.ok){n&&(n.innerHTML=`<p class="muted">${_(i.error??`Failed`)}</p>`);return}z(i.steps??[])}catch(e){n&&(n.innerHTML=`<p class="muted">${_(String(e))}</p>`)}R&&=(R.close(),null);let r=[];R=new EventSource(`${e}/agents/${encodeURIComponent(t)}/stream`),R.onmessage=e=>{try{let t=JSON.parse(e.data);r.push(t),z(r.slice(-100))}catch{}}}async function ie(t){let n=prompt(`Enter input for agent (or leave empty for empty string):`)??``;B(t);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/run`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({input:n})}),i=await r.json();if(!r.ok){H({error:i.error??`Agent run failed`,status:r.status});return}H({agentName:t,result:i.result});let a=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`);a.ok&&z((await a.json()).steps??[])}catch(e){H({error:String(e),agentName:t})}}function ae(e){let t=document.getElementById(`prompt-playground-modal`),n=document.getElementById(`playground-key`),r=document.getElementById(`playground-vars`),i=document.getElementById(`playground-output`),a=document.getElementById(`playground-tokens`);n.value=e,r.value=`{}`,i.textContent=``,a.textContent=`—`,t.classList.remove(`hidden`)}async function oe(t,n){let r=await fetch(`${e}/prompts/render`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:t,variables:n})});if(!r.ok){let e=await r.json().catch(()=>({error:r.statusText}));throw Error(e.error??`Failed to render`)}return r.json()}function se(e){ae(e)}var V=null;function H(e){V=e;let t=document.getElementById(`detail-panel`),n=document.getElementById(`detail-title`),r=document.getElementById(`detail-content`);n.textContent=String(e.kind??`Entry`),r.innerHTML=g(e),t.classList.remove(`hidden`)}function ce(){V=null,document.getElementById(`detail-panel`).classList.add(`hidden`)}function le(){if(!V)return;let e=JSON.stringify(V,null,2);navigator.clipboard.writeText(e).then(()=>{let e=document.getElementById(`detail-copy`);if(e){let t=e.textContent;e.textContent=`Copied!`,setTimeout(()=>{e.textContent=t},1500)}})}function ue(e,t){let n=Array.isArray(e)?e:[];if(!t.trim())return n;let r=t.toLowerCase();return n.filter(e=>JSON.stringify(e).toLowerCase().includes(r))}var U={httpMethod:e=>h(String(e??``))},W={enabled:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Enabled`:`Disabled`}</span>`,nextRuns:(e,t)=>{let n=Array.isArray(e)?e:[];return n.length?n.slice(0,3).map(e=>{try{return new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}catch{return e}}).join(`, `)+(n.length>3?`...`:``):`—`}},G={moduleName:e=>String(e??`—`),scope:e=>{let t=String(e??`singleton`);return`<span class="badge ${t===`singleton`?`badge-get`:t===`request`?`badge-post`:`badge-default`}">${t}</span>`}},K={tools:e=>Array.isArray(e)?e.join(`, `):String(e??`—`)},q={streaming:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Yes`:`No`}</span>`};function J(e,t){try{t()}catch(t){console.error(`[Inspector] ${e} failed:`,t)}}async function Y(e=!1){if(!r){r=!0,u(!0),p(!1);try{let t=await o(e),r=Array.isArray(t?.entries)?t.entries:[],i=t?.summary&&typeof t.summary==`object`?t.summary:{},a=t?.overview&&typeof t.overview==`object`?t.overview:{};n={entries:r,summary:i,overview:a},J(`overview`,()=>b(i)),a.gateway&&J(`gatewayOverview`,()=>C(a.gateway)),a.discovery&&J(`discoveryOverview`,()=>w(a.discovery)),a.resilience&&J(`resilienceOverview`,()=>ee(a.resilience)),[`overview-gateway`,`overview-discovery`,`overview-resilience`].forEach(e=>{let t=document.getElementById(e);t&&!a[e.replace(`overview-`,``)]&&t.classList.add(`hidden`)});let[u,p,m]=await Promise.all([c(),Promise.all([l(`/health`),l(`/ready`),l(`/startup`)]).then(([e,t,n])=>({health:e,ready:t,startup:n})),s()]);S(u),te(p),ne(m),d(p,m),f(i);let h=n.entries.filter(e=>e.kind===`route`),g=n.entries.filter(e=>e.kind===`module`),_=n.entries.filter(e=>e.kind===`provider`),v=n.entries.filter(e=>e.kind===`cron`),y=n.entries.filter(e=>e.kind===`queue`),x=n.entries.filter(e=>e.kind===`websocket`),T=n.entries.filter(e=>e.kind===`agent`),E=n.entries.filter(e=>e.kind===`rag`),D=n.entries.filter(e=>e.kind===`prompt`),O=n.entries.filter(e=>e.kind===`aifunction`),k=n.entries.filter(e=>e.kind===`event`),re=n.entries.filter(e=>e.kind===`graphql`),A=n.entries.filter(e=>e.kind===`grpc`),j=n.entries.filter(e=>e.kind===`kafka`),P=n.entries.filter(e=>e.kind===`flow`),L=n.entries.filter(e=>e.kind===`data`),R=n.entries.filter(e=>e.kind===`serverless`),z=n.entries.filter(e=>e.kind===`ml`);I(`routes-table`,h,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,U,{sortable:!0,tryRoute:!0}),J(`moduleGraph`,()=>F(g)),I(X.modules,g,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(X.providers,_,[`providerName`,`moduleName`,`scope`],`provider`,G,{sortable:!0}),I(X.jobs,v,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,W),I(X.queues,y,[`queueName`,`consumerName`,`className`],`queue`),I(X.websocket,x,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(X.agents,T,[`agentName`,`className`,`model`,`tools`],`agent`,K,{sortable:!0,runAgent:!0}),I(X.ai,O,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,q),J(`ragExplorer`,()=>N(E)),I(X.rag,E,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(X.prompts,D,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(X.events,k,[`eventName`,`className`,`methodName`],`event`),I(X.graphql,re,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(X.grpc,A,[`serviceName`,`methodName`,`className`],`grpc`),I(X.kafka,j,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let B=document.getElementById(`flow-runtime-info`);B&&B.classList.toggle(`hidden`,P.length===0),J(`flowDiagram`,()=>M(P)),I(X.flows,P,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`),I(X.data,L,[`pipelineName`,`className`],`data`),I(X.serverless,R,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(X.ml,z,[`modelName`,`version`,`className`],`ml`)}catch(e){let t=String(e),n=t.includes(`Failed to fetch`)||t.includes(`NetworkError`)||t.includes(`Load failed`);p(n),d({health:{ok:!1},ready:{ok:!1},startup:{ok:!1}},{}),f({});let r=document.getElementById(`summary-cards`);if(r){let t=n?`Is the app running?`:`A rendering error occurred. Check the console for details.`;r.innerHTML=`<div class="overview-error"><p>Error: ${_(String(e))}</p><p>${_(t)} <button class="btn btn-sm btn-primary" id="retry-load">Retry</button></p></div>`,document.getElementById(`retry-load`)?.addEventListener(`click`,()=>Y(!0))}}finally{r=!1,u(!1)}}}var X={routes:`routes-table`,modules:`modules-table`,providers:`providers-table`,jobs:`jobs-table`,queues:`queues-table`,websocket:`websocket-table`,agents:`agents-table`,ai:`ai-table`,rag:`rag-table`,prompts:`prompts-table`,events:`events-table`,graphql:`graphql-table`,grpc:`grpc-table`,kafka:`kafka-table`,flows:`flows-table`,data:`data-table`,serverless:`serverless-table`,ml:`ml-table`},de={route:`routes`,module:`modules`,provider:`providers`,cron:`jobs`,queue:`queues`,websocket:`websocket`,agent:`agents`,aifunction:`ai`,rag:`rag`,prompt:`prompts`,event:`events`,graphql:`graphql`,grpc:`grpc`,kafka:`kafka`,flow:`flows`,data:`data`,serverless:`serverless`,ml:`ml`};function Z(e){let t=document.querySelector(`.sidebar nav a[data-tab="${e}"]`);if(t){document.querySelectorAll(`.sidebar nav a`).forEach(e=>e.classList.remove(`active`)),document.querySelectorAll(`.tab-panel`).forEach(e=>e.classList.remove(`active`)),t.classList.add(`active`),document.getElementById(e)?.classList.add(`active`);let n=new URLSearchParams(window.location.search);n.set(`tab`,e),window.history.replaceState({},``,`${window.location.pathname}?${n}`)}}document.querySelectorAll(`.sidebar nav a`).forEach(e=>{e.addEventListener(`click`,t=>{t.preventDefault();let n=e.dataset.tab;Z(n)})}),document.getElementById(`summary-cards`)?.addEventListener(`click`,e=>{let t=e.target.closest(`.card[data-kind]`);if(t){let e=t.dataset.kind,n=e?de[e]:null;n&&Z(n)}});function Q(){Y(!0)}document.getElementById(`refresh`)?.addEventListener(`click`,Q),document.getElementById(`refresh-sidebar`)?.addEventListener(`click`,Q),document.getElementById(`detail-close`).addEventListener(`click`,ce),document.getElementById(`detail-copy`)?.addEventListener(`click`,le),document.getElementById(`export-btn`)?.addEventListener(`click`,()=>{if(!n)return;let e=new Blob([JSON.stringify(n,null,2)],{type:`application/json`}),t=document.createElement(`a`);t.href=URL.createObjectURL(e),t.download=`inspector-snapshot-${new Date().toISOString().slice(0,19).replace(/[T:]/g,`-`)}.json`,t.click(),URL.revokeObjectURL(t.href)});var fe=document.getElementById(`auto-refresh`),$=null;fe?.addEventListener(`change`,()=>{$&&clearInterval($),$=null,fe?.checked&&($=setInterval(()=>Y(!1),15e3))}),document.getElementById(`test-route-btn`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`test-url`).value,t=document.getElementById(`test-method`).value,n=document.getElementById(`test-body`),r=document.getElementById(`test-result`);r.classList.remove(`hidden`),r.className=`test-result`,r.textContent=`Sending...`;try{let i={method:t};if(t!==`GET`&&n?.value)try{JSON.parse(n.value),i.body=n.value,i.headers={"Content-Type":`application/json`}}catch{r.className=`test-result error`,r.textContent=`Invalid JSON body`;return}let a=await fetch(e,i),o=await a.text();r.className=`test-result ${a.ok?`success`:`error`}`,r.textContent=`Status: ${a.status}\n\n${o.slice(0,500)}${o.length>500?`...`:``}`}catch(e){r.className=`test-result error`,r.textContent=String(e)}}),document.getElementById(`test-route-cancel`)?.addEventListener(`click`,()=>{document.getElementById(`route-test-modal`).classList.add(`hidden`)}),document.getElementById(`test-method`)?.addEventListener(`change`,e=>{let t=e.target.value;document.getElementById(`test-body-group`).classList.toggle(`hidden`,t===`GET`)}),document.getElementById(`playground-render`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`playground-key`).value,t=document.getElementById(`playground-vars`).value,n=document.getElementById(`playground-output`),r=document.getElementById(`playground-tokens`),i={};try{i=t.trim()?JSON.parse(t):{}}catch{n.textContent=`Invalid JSON in variables`,r.textContent=`—`;return}try{let{rendered:t,tokenEstimate:a}=await oe(e,i);n.textContent=t,r.textContent=String(a)}catch(e){n.textContent=String(e),r.textContent=`—`}}),document.getElementById(`playground-close`)?.addEventListener(`click`,()=>{document.getElementById(`prompt-playground-modal`).classList.add(`hidden`)}),document.getElementById(`diff-btn`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.remove(`hidden`)}),document.getElementById(`diff-close`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.add(`hidden`)}),document.getElementById(`diff-load-file`)?.addEventListener(`click`,()=>{document.getElementById(`diff-file`).click()}),document.getElementById(`diff-file`)?.addEventListener(`change`,e=>{let t=e.target.files?.[0];if(!t)return;let n=new FileReader;n.onload=()=>{document.getElementById(`diff-snapshot-b`).value=String(n.result)},n.readAsText(t)}),document.getElementById(`rag-search-btn`)?.addEventListener(`click`,P),document.getElementById(`diff-compare-btn`)?.addEventListener(`click`,()=>{let e=document.getElementById(`diff-snapshot-b`).value.trim(),t=document.getElementById(`diff-result`);if(!n){t.innerHTML=`<p class="error">No current snapshot. Refresh first.</p>`,t.classList.remove(`hidden`);return}let r;try{r=e?JSON.parse(e):{entries:[],summary:{}}}catch{t.innerHTML=`<p class="error">Invalid JSON in Snapshot B.</p>`,t.classList.remove(`hidden`);return}let i=n.entries??[],a=r.entries??[],o=new Set(i.map(e=>e.id)),s=new Set(a.map(e=>e.id)),c=a.filter(e=>!o.has(e.id)),l=i.filter(e=>!s.has(e.id)),u=i.filter(e=>{let t=a.find(t=>t.id===e.id);return t&&JSON.stringify(e)!==JSON.stringify(t)}),d=``;c.length&&(d+=`<p class="added">+ ${c.length} added</p><ul>${c.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),l.length&&(d+=`<p class="removed">− ${l.length} removed</p><ul>${l.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),u.length&&(d+=`<p class="changed">~ ${u.length} changed</p><ul>${u.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),d||=`<p>No differences.</p>`,t.innerHTML=d,t.classList.remove(`hidden`)}),document.getElementById(`search`).addEventListener(`input`,e=>{let t=e.target.value;if(!n)return;let r=ue(n.entries,t),i=n.summary&&typeof n.summary==`object`?n.summary:{};b(Object.fromEntries(Object.entries(i).map(([e])=>[e,r.filter(t=>t.kind===e).length])));let a=r.filter(e=>e.kind===`route`),o=r.filter(e=>e.kind===`module`),s=r.filter(e=>e.kind===`provider`),c=r.filter(e=>e.kind===`cron`),l=r.filter(e=>e.kind===`queue`),u=r.filter(e=>e.kind===`websocket`),d=r.filter(e=>e.kind===`agent`),f=r.filter(e=>e.kind===`rag`),p=r.filter(e=>e.kind===`prompt`),m=r.filter(e=>e.kind===`aifunction`),h=r.filter(e=>e.kind===`event`),g=r.filter(e=>e.kind===`graphql`),_=r.filter(e=>e.kind===`grpc`),v=r.filter(e=>e.kind===`kafka`),y=r.filter(e=>e.kind===`flow`),x=r.filter(e=>e.kind===`data`),S=r.filter(e=>e.kind===`serverless`),C=r.filter(e=>e.kind===`ml`);I(`routes-table`,a,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,U,{sortable:!0,tryRoute:!0}),F(o),I(`modules-table`,o,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(`providers-table`,s,[`providerName`,`moduleName`,`scope`],`provider`,G,{sortable:!0}),I(`jobs-table`,c,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,W),I(`queues-table`,l,[`queueName`,`consumerName`,`className`],`queue`),I(`websocket-table`,u,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(`agents-table`,d,[`agentName`,`className`,`model`,`tools`],`agent`,K,{sortable:!0,runAgent:!0}),I(`ai-table`,m,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,q),N(f),I(`rag-table`,f,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(`prompts-table`,p,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(`events-table`,h,[`eventName`,`className`,`methodName`],`event`),I(`graphql-table`,g,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(`grpc-table`,_,[`serviceName`,`methodName`,`className`],`grpc`),I(`kafka-table`,v,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let w=document.getElementById(`flow-runtime-info`);w&&w.classList.toggle(`hidden`,y.length===0),M(y),I(`flows-table`,y,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`,void 0,{sortable:!0}),I(`data-table`,x,[`pipelineName`,`className`],`data`),I(`serverless-table`,S,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(`ml-table`,C,[`modelName`,`version`,`className`],`ml`)}),Y().then(()=>{let e=new URLSearchParams(window.location.search).get(`tab`);e&&Z(e)});
|