@deepagents/devtool 0.0.0-stage → 7.0.1

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 CHANGED
@@ -1,3 +1,101 @@
1
- # Temporary Holding Version
1
+ # `@deepagents/devtool`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Development-only Zukhruf DevTool UI. `devtool()` returns a mountable Hono app
4
+ containing only the bundled browser assets and their SPA fallback; consumers do
5
+ not import React or CSS, and the DevTool owns no listener, port, runtime
6
+ object, credentials, or proxy.
7
+
8
+ ```sh
9
+ npm install --save-dev @deepagents/devtool
10
+ ```
11
+
12
+ The host owns one Hono server and chooses each plugin's mount. This example
13
+ chooses `/zukhruf/v1` for the authenticated HTTP plugin and `/devtool` for the
14
+ UI:
15
+
16
+ ```ts
17
+ import { serve } from '@hono/node-server';
18
+ import { Hono } from 'hono';
19
+
20
+ import { devtool } from '@deepagents/devtool';
21
+ import { fileTelemetry, tracesHttp } from '@deepagents/devtool/traces';
22
+ import { AgentRuntime, defineAgent } from '@deepagents/experimental/zukhruf';
23
+ import { type HttpEnv, http } from '@deepagents/experimental/zukhruf/http';
24
+
25
+ const traceTelemetry = fileTelemetry({ path: './telemetry.jsonl' });
26
+ const runtime = new AgentRuntime(
27
+ defineAgent({
28
+ ...declaration,
29
+ plugins: [...declaration.plugins, traceTelemetry],
30
+ }),
31
+ );
32
+ await using host = await runtime.initialize(runtimeOptions);
33
+ await using worker = await host.work();
34
+
35
+ const app = new Hono<HttpEnv>();
36
+ app.use('/zukhruf/v1/*', (context, next) => {
37
+ context.set('userId', 'demo');
38
+ return next();
39
+ });
40
+ app.route('/zukhruf/v1', http(host, tracesHttp(traceTelemetry)));
41
+ app.route('/devtool', devtool({ protocolPath: '/zukhruf/v1' }));
42
+
43
+ await using server = serve({
44
+ fetch: app.fetch,
45
+ hostname: '127.0.0.1',
46
+ port: 4317,
47
+ });
48
+ console.info('http://127.0.0.1:4317/devtool');
49
+ ```
50
+
51
+ `http(host)` uses Hono's effective mount to produce discovery links. For the
52
+ example mount, `GET /zukhruf/v1/info` returns:
53
+
54
+ ```json
55
+ {
56
+ "capabilities": {
57
+ "history": { "href": "/zukhruf/v1/history" },
58
+ "chat": { "href": "/zukhruf/v1/session" },
59
+ "events": { "href": "/zukhruf/v1/events" },
60
+ "traces": { "href": "/zukhruf/v1/traces" }
61
+ }
62
+ }
63
+ ```
64
+
65
+ `history`, `chat`, and `events` are always advertised by `http(host)`. **New Chat**,
66
+ conversation loading, streaming, and cancellation use the session protocol on
67
+ the current origin, so the host's own authentication middleware guards every
68
+ runtime request. The owner event stream keeps conversation status and child
69
+ progress current without browser polling. Runtime health comes from
70
+ `GET /zukhruf/v1/health`.
71
+
72
+ `traces` appears only when the runtime installs the `fileTelemetry()` plugin
73
+ from `@deepagents/devtool/traces` and the host passes
74
+ `tracesHttp(traceTelemetry)` from the same subpath to `http()`.
75
+ The plugin instance contributes the AI SDK OpenTelemetry integration and a
76
+ transport-neutral trace reader; the definition-bound HTTP projection adds the
77
+ runtime's authenticated trace routes and discovery entry. Together they
78
+ correlate the conversation, stream, and agent identifiers on each turn, project
79
+ the Halo-compatible JSONL in place inside the runtime process, and serve
80
+ `GET /zukhruf/v1/traces/:chatId` and `GET /zukhruf/v1/traces/:chatId/:traceId`
81
+ behind the Zukhruf authentication boundary. Ownership comes from the
82
+ authenticated `userId`; the file URI is never exposed and the browser never
83
+ sends a user ID. Without the plugin, `/info` omits `traces` and the UI hides
84
+ every **Traces** link. Recording controls are honored and disabled payloads are
85
+ labelled as not recorded.
86
+
87
+ `schedules` appears only when the runtime installs `schedules()` and the host
88
+ passes `schedulesHttp(scheduled)` from
89
+ `@deepagents/experimental/zukhruf/schedules/http` to `http()`. The authenticated
90
+ projection provides task creation and editing, pause/resume, archive/purge, Run
91
+ now, per-task runs, cancellation, explicit review, and the owner-wide
92
+ pending-review inbox. Omitting the projection removes the discovery capability
93
+ and hides **Scheduled** navigation.
94
+
95
+ The UI follows both host-selected Hono mounts. `devtool({ protocolPath })`
96
+ injects its effective UI mount as the document base and the same-origin absolute
97
+ protocol path as the discovery target. `protocolPath` defaults to
98
+ `/zukhruf/v1`. Assets, React Router, deep links, refresh, and Back therefore work
99
+ beneath any UI path while runtime requests follow the configured protocol mount.
100
+ For this example, `/devtool` and `/devtool/` load the shell, assets load beneath
101
+ `/devtool/assets/`, and `/devtool` redirects to `/devtool/history`.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Static DevTool UI. Mount with `app.route(path, devtool({ protocolPath }))` on
3
+ * the same origin that mounts `http(runtime)` at `protocolPath`.
4
+ */
5
+ export declare function devtool({ protocolPath, }?: {
6
+ protocolPath?: string;
7
+ }): import("hono/hono-base").HonoBase<{}, {
8
+ "/assets/*": {
9
+ $get: {
10
+ input: {};
11
+ output: {};
12
+ outputFormat: string;
13
+ status: import("hono/utils/http-status").StatusCode;
14
+ };
15
+ };
16
+ } & {
17
+ "*": {
18
+ $get: {
19
+ input: {};
20
+ output: {};
21
+ outputFormat: string;
22
+ status: import("hono/utils/http-status").StatusCode;
23
+ };
24
+ };
25
+ }, "/", "*">;
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,wBAAgB,OAAO,CAAC,EACtB,YAA4B,GAC7B,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO;;;;;;;;;;;;;;;;;;aAgChC"}
package/dist/index.js ADDED
@@ -0,0 +1,44 @@
1
+ // packages/devtool/host/src/index.ts
2
+ import { serveStatic } from "@hono/node-server/serve-static";
3
+ import { Hono } from "hono";
4
+ import { html } from "hono/html";
5
+ import { basePath } from "hono/route";
6
+ import { readFile } from "node:fs/promises";
7
+ import { fileURLToPath } from "node:url";
8
+ var ui = fileURLToPath(new URL("./ui/", import.meta.url));
9
+ var shell = await readFile(
10
+ new URL("./ui/index.html", import.meta.url),
11
+ "utf8"
12
+ );
13
+ function devtool({
14
+ protocolPath = "/zukhruf/v1"
15
+ } = {}) {
16
+ const parsed = new URL(protocolPath, "http://localhost");
17
+ if (parsed.origin !== "http://localhost" || parsed.pathname !== protocolPath) {
18
+ throw new TypeError(
19
+ "devtool: protocolPath must be a same-origin absolute path"
20
+ );
21
+ }
22
+ const infoPath = `${protocolPath.replace(/\/+$/, "")}/info`;
23
+ return new Hono().use(
24
+ "/assets/*",
25
+ serveStatic({
26
+ root: ui,
27
+ rewriteRequestPath: (path, context) => path.slice(basePath(context).replace(/\/$/, "").length)
28
+ })
29
+ ).get("/assets/*", (context) => context.notFound()).get("*", async (context) => {
30
+ const mount = basePath(context).replace(/\/$/, "");
31
+ const base = await html`<base href="${mount}/" />`;
32
+ const configuration = await html`<meta
33
+ name="deepagents-zukhruf-info"
34
+ content="${infoPath}"
35
+ />`;
36
+ return context.html(
37
+ shell.replace("<head>", `<head>${base}${configuration}`)
38
+ );
39
+ });
40
+ }
41
+ export {
42
+ devtool
43
+ };
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["import { serveStatic } from '@hono/node-server/serve-static';\nimport { Hono } from 'hono';\nimport { html } from 'hono/html';\nimport { basePath } from 'hono/route';\nimport { readFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\n\nconst ui = fileURLToPath(new URL('./ui/', import.meta.url));\nconst shell = await readFile(\n new URL('./ui/index.html', import.meta.url),\n 'utf8',\n);\n\n/**\n * Static DevTool UI. Mount with `app.route(path, devtool({ protocolPath }))` on\n * the same origin that mounts `http(runtime)` at `protocolPath`.\n */\nexport function devtool({\n protocolPath = '/zukhruf/v1',\n}: { protocolPath?: string } = {}) {\n const parsed = new URL(protocolPath, 'http://localhost');\n if (\n parsed.origin !== 'http://localhost' ||\n parsed.pathname !== protocolPath\n ) {\n throw new TypeError(\n 'devtool: protocolPath must be a same-origin absolute path',\n );\n }\n const infoPath = `${protocolPath.replace(/\\/+$/, '')}/info`;\n return new Hono()\n .use(\n '/assets/*',\n serveStatic({\n root: ui,\n rewriteRequestPath: (path, context) =>\n path.slice(basePath(context).replace(/\\/$/, '').length),\n }),\n )\n .get('/assets/*', (context) => context.notFound())\n .get('*', async (context) => {\n const mount = basePath(context).replace(/\\/$/, '');\n const base = await html`<base href=\"${mount}/\" />`;\n const configuration = await html`<meta\n name=\"deepagents-zukhruf-info\"\n content=\"${infoPath}\"\n />`;\n return context.html(\n shell.replace('<head>', `<head>${base}${configuration}`),\n );\n });\n}\n"],
5
+ "mappings": ";AAAA,SAAS,mBAAmB;AAC5B,SAAS,YAAY;AACrB,SAAS,YAAY;AACrB,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAE9B,IAAM,KAAK,cAAc,IAAI,IAAI,SAAS,YAAY,GAAG,CAAC;AAC1D,IAAM,QAAQ,MAAM;AAAA,EAClB,IAAI,IAAI,mBAAmB,YAAY,GAAG;AAAA,EAC1C;AACF;AAMO,SAAS,QAAQ;AAAA,EACtB,eAAe;AACjB,IAA+B,CAAC,GAAG;AACjC,QAAM,SAAS,IAAI,IAAI,cAAc,kBAAkB;AACvD,MACE,OAAO,WAAW,sBAClB,OAAO,aAAa,cACpB;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,GAAG,aAAa,QAAQ,QAAQ,EAAE,CAAC;AACpD,SAAO,IAAI,KAAK,EACb;AAAA,IACC;AAAA,IACA,YAAY;AAAA,MACV,MAAM;AAAA,MACN,oBAAoB,CAAC,MAAM,YACzB,KAAK,MAAM,SAAS,OAAO,EAAE,QAAQ,OAAO,EAAE,EAAE,MAAM;AAAA,IAC1D,CAAC;AAAA,EACH,EACC,IAAI,aAAa,CAAC,YAAY,QAAQ,SAAS,CAAC,EAChD,IAAI,KAAK,OAAO,YAAY;AAC3B,UAAM,QAAQ,SAAS,OAAO,EAAE,QAAQ,OAAO,EAAE;AACjD,UAAM,OAAO,MAAM,mBAAmB,KAAK;AAC3C,UAAM,gBAAgB,MAAM;AAAA;AAAA,mBAEf,QAAQ;AAAA;AAErB,WAAO,QAAQ;AAAA,MACb,MAAM,QAAQ,UAAU,SAAS,IAAI,GAAG,aAAa,EAAE;AAAA,IACzD;AAAA,EACF,CAAC;AACL;",
6
+ "names": []
7
+ }
@@ -0,0 +1,53 @@
1
+ import type { ConversationId } from '@deepagents/experimental/zukhruf';
2
+ export type RecordingState = 'recorded' | 'not-recorded';
3
+ export interface AgentTraceSummary {
4
+ id: string;
5
+ chatId: string;
6
+ userId: string;
7
+ streamId: string;
8
+ agentName: string;
9
+ agentPath: string;
10
+ workflowName: string;
11
+ startedAt: string | null;
12
+ endedAt: string | null;
13
+ status: 'running' | 'completed' | 'failed' | 'cancelled';
14
+ stepCount: number;
15
+ finishReason: string | null;
16
+ usage: {
17
+ inputTokens: number;
18
+ outputTokens: number;
19
+ };
20
+ recording: {
21
+ inputs: RecordingState;
22
+ outputs: RecordingState;
23
+ };
24
+ }
25
+ export interface AgentTraceSpan {
26
+ id: string;
27
+ traceId: string;
28
+ parentId: string | null;
29
+ startedAt: string;
30
+ endedAt: string | null;
31
+ status: 'running' | 'completed' | 'failed' | 'cancelled';
32
+ type: string;
33
+ name: string;
34
+ input?: unknown;
35
+ output?: unknown;
36
+ usage?: unknown;
37
+ error?: unknown;
38
+ data: Record<string, unknown>;
39
+ }
40
+ export type AgentTrace = AgentTraceSummary & {
41
+ spans: AgentTraceSpan[];
42
+ };
43
+ export interface AgentTraceReader {
44
+ list(conversation: ConversationId): Promise<AgentTraceSummary[]>;
45
+ get(conversation: ConversationId, traceId: string): Promise<AgentTrace | undefined>;
46
+ }
47
+ export declare class FileTraceAdapter implements AgentTraceReader {
48
+ #private;
49
+ constructor(path: URL);
50
+ list({ chatId, userId }: ConversationId): Promise<AgentTraceSummary[]>;
51
+ get({ chatId, userId }: ConversationId, traceId: string): Promise<AgentTrace | undefined>;
52
+ }
53
+ //# sourceMappingURL=file-trace-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-trace-adapter.d.ts","sourceRoot":"","sources":["../../src/traces/file-trace-adapter.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAUvE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,cAAc,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,SAAS,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,OAAO,EAAE,cAAc,CAAA;KAAE,CAAC;CAChE;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG;IAAE,KAAK,EAAE,cAAc,EAAE,CAAA;CAAE,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,YAAY,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACjE,GAAG,CACD,YAAY,EAAE,cAAc,EAC5B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;CACpC;AAeD,qBAAa,gBAAiB,YAAW,gBAAgB;;gBAG3C,IAAI,EAAE,GAAG;IAIf,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAStE,GAAG,CACP,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,cAAc,EAClC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;CAgBnC"}
@@ -0,0 +1,4 @@
1
+ import type { AgentPluginDefinition } from '@deepagents/experimental/zukhruf';
2
+ import type { FileTelemetryInstance } from './index.ts';
3
+ export declare function tracesHttp(definition: AgentPluginDefinition<FileTelemetryInstance>): import("@deepagents/experimental/zukhruf/http").HttpProjection;
4
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/traces/http.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,qBAAqB,EAEtB,MAAM,kCAAkC,CAAC;AAW1C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAKxD,wBAAgB,UAAU,CACxB,UAAU,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,kEAMzD"}
@@ -0,0 +1,11 @@
1
+ import type { FileTelemetryOptions } from '@deepagents/context/telemetry/file';
2
+ import type { AgentPluginDefinition } from '@deepagents/experimental/zukhruf';
3
+ import type { AgentTraceReader } from './file-trace-adapter.ts';
4
+ export * from './file-trace-adapter.ts';
5
+ export { tracesHttp } from './http.ts';
6
+ export interface FileTelemetryInstance {
7
+ readonly traces: AgentTraceReader;
8
+ }
9
+ /** AI SDK OpenTelemetry spans persisted in Halo's flat JSONL format. */
10
+ export declare function fileTelemetry(options: FileTelemetryOptions): AgentPluginDefinition<FileTelemetryInstance>;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/traces/index.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,KAAK,EACV,qBAAqB,EAEtB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAcvC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;CACnC;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,GAC5B,qBAAqB,CAAC,qBAAqB,CAAC,CA2B9C"}