@ai-setting/roy-plugin-task-show 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +263 -0
- package/dist/collector.d.ts +104 -0
- package/dist/collector.d.ts.map +1 -0
- package/dist/collector.js +247 -0
- package/dist/collector.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +107 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +332 -0
- package/dist/plugin.js.map +1 -0
- package/dist/server.d.ts +79 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +570 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/dist/url-injector.d.ts +53 -0
- package/dist/url-injector.d.ts.map +1 -0
- package/dist/url-injector.js +69 -0
- package/dist/url-injector.js.map +1 -0
- package/package.json +70 -0
- package/plugin.json +62 -0
- package/public/app.js +133 -0
- package/public/index.html +34 -0
- package/public/style.css +240 -0
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# roy-plugin-task-show
|
|
2
|
+
|
|
3
|
+
> A [roy-agent](https://example/roy-agent) plugin that visualizes the tool-call
|
|
4
|
+
> chain of every task on a local web service and injects the visualization URL
|
|
5
|
+
> back into the task's tool output.
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
When loaded into a `roy-agent` host, this plugin:
|
|
10
|
+
|
|
11
|
+
1. Listens to the `tool:after.execute` and `task:after.update` hook points.
|
|
12
|
+
2. Records every tool invocation (tool name, args, result preview, duration,
|
|
13
|
+
success flag, timestamp) into an in-memory collector keyed by task id.
|
|
14
|
+
3. When a task transitions to a terminal status (`completed` / `failed` /
|
|
15
|
+
`cancelled`), mutates the **last** tool result to append a markdown link to
|
|
16
|
+
the visualization page.
|
|
17
|
+
4. Serves the visualization on a local HTTP server (default
|
|
18
|
+
`http://127.0.0.1:7788/`).
|
|
19
|
+
|
|
20
|
+
The result: every task in the chat gets a 🔗 link the user can click to open
|
|
21
|
+
a mermaid-powered flow chart showing exactly how the agent solved it.
|
|
22
|
+
|
|
23
|
+
## Repository layout
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
roy-plugin-task-show/
|
|
27
|
+
├── plugin.json ← roy-agent plugin manifest
|
|
28
|
+
├── package.json
|
|
29
|
+
├── tsconfig.json
|
|
30
|
+
├── README.md
|
|
31
|
+
├── public/ ← static frontend (HTML/CSS/JS, served by Node http)
|
|
32
|
+
│ ├── index.html
|
|
33
|
+
│ ├── style.css
|
|
34
|
+
│ └── app.js
|
|
35
|
+
├── src/
|
|
36
|
+
│ ├── index.ts ← public API (re-exports)
|
|
37
|
+
│ ├── types.ts ← shared types & default config
|
|
38
|
+
│ ├── collector.ts ← in-memory tool-call collector
|
|
39
|
+
│ ├── server.ts ← tiny standalone Node http server (no deps)
|
|
40
|
+
│ ├── url-injector.ts ← tool-result mutation helpers
|
|
41
|
+
│ ├── plugin.ts ← the TaskShowPlugin class (BasePlugin-compatible)
|
|
42
|
+
│ └── core-stub.d.ts ← type stub for the optional core peer dep
|
|
43
|
+
├── test/
|
|
44
|
+
│ ├── collector.test.ts
|
|
45
|
+
│ ├── url-injector.test.ts
|
|
46
|
+
│ ├── server.test.ts
|
|
47
|
+
│ └── plugin.test.ts
|
|
48
|
+
└── scripts/
|
|
49
|
+
├── verify-service.ts ← end-to-end check (port 7788 + curl pages)
|
|
50
|
+
└── run-demo.ts ← demo that simulates a real task lifecycle
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
This plugin lives in its own package. Inside a `roy-agent` workspace:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# (already wired in monorepo workspaces — otherwise `pnpm add ./roy-plugin-task-show`)
|
|
59
|
+
pnpm install
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Or run it standalone for demo purposes:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cd roy-plugin-task-show
|
|
66
|
+
bun install
|
|
67
|
+
bun run build
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Loading into roy-agent
|
|
71
|
+
|
|
72
|
+
`roy-agent`'s plugin loader (`EnvironmentService.loadPlugins()`) supports
|
|
73
|
+
two plugin forms:
|
|
74
|
+
|
|
75
|
+
| form | how it works |
|
|
76
|
+
| --------------------------------- | --------------------------------------------------------- |
|
|
77
|
+
| `import('@scope/plugin')` | Dynamically imports a module and instantiates the plugin. |
|
|
78
|
+
| file path (`/abs/path/to/plug.js`)| Treated as an external `ToolPlugin` script. |
|
|
79
|
+
|
|
80
|
+
For this plugin, we ship a **named export** so it slots into the same
|
|
81
|
+
mechanism used by `task-tag`, `lsp`, etc.
|
|
82
|
+
|
|
83
|
+
### Option A — register via the loader (recommended)
|
|
84
|
+
|
|
85
|
+
In `roy-agent`'s CLI args:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
roy-agent interactive --plugin task-show
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This works out of the box once `@roy-agent/task-show` is added to the
|
|
92
|
+
workspaces' plugin allow-list. To register it manually, add a case to the
|
|
93
|
+
`loadPlugins()` switch in `packages/cli/src/services/environment.service.ts`:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
case "task-show": {
|
|
97
|
+
const { createTaskShowPlugin } = await import("@roy-agent/task-show");
|
|
98
|
+
plugin = createTaskShowPlugin({ port: 7788 });
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Option B — wire directly in interactive / act mode
|
|
104
|
+
|
|
105
|
+
If you only need it locally, drop the plugin init into the
|
|
106
|
+
`interactive-shutdown.ts` (or `act.ts`) flow next to the
|
|
107
|
+
`pluginAdapterDispose` plumbing. The plugin's lifecycle is:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { createTaskShowPlugin } from "@roy-agent/task-show";
|
|
111
|
+
|
|
112
|
+
const taskShow = createTaskShowPlugin({ port: 7788 });
|
|
113
|
+
await taskShow.init({
|
|
114
|
+
registerHook: (def) => myPluginComponent.register(def),
|
|
115
|
+
getComponent: (name) => env.getComponent(name),
|
|
116
|
+
getConfig: (key) => configComponent?.get(key),
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Later, on shutdown:
|
|
120
|
+
await taskShow.dispose();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The plugin registers hooks for:
|
|
124
|
+
|
|
125
|
+
- `tool:after.execute` — collects every tool call (priority 50).
|
|
126
|
+
- `task:after.update` — freezes the session and (optionally) injects the
|
|
127
|
+
visualization URL into the last tool result (priority 60).
|
|
128
|
+
|
|
129
|
+
## Configuration
|
|
130
|
+
|
|
131
|
+
All config lives in `plugin.json` (and is overridable at construction time):
|
|
132
|
+
|
|
133
|
+
| key | type | default | description |
|
|
134
|
+
| ------------------- | -------- | ----------- | -------------------------------------------------------- |
|
|
135
|
+
| `port` | number | `7788` | HTTP port for the visualization service. |
|
|
136
|
+
| `host` | string | `127.0.0.1` | HTTP host. Use `0.0.0.0` to allow LAN access. |
|
|
137
|
+
| `autoStart` | boolean | `true` | Start the HTTP server when `init()` is called. |
|
|
138
|
+
| `maxStoredTasks` | number | `50` | Max sessions kept in memory. Older ones are evicted. |
|
|
139
|
+
| `urlInjectEnabled` | boolean | `true` | Append the visualization URL to the last tool result. |
|
|
140
|
+
| `publicDir` | string | `public` | Directory holding the static frontend. |
|
|
141
|
+
|
|
142
|
+
Override at construction time:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
createTaskShowPlugin({
|
|
146
|
+
port: 9000,
|
|
147
|
+
urlInjectEnabled: false,
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## HTTP API
|
|
152
|
+
|
|
153
|
+
| route | description |
|
|
154
|
+
| --------------------------- | ------------------------------------------------------ |
|
|
155
|
+
| `GET /` | Index of recent task sessions. |
|
|
156
|
+
| `GET /task/:taskId` | Per-task page with mermaid flow + tool-call table. |
|
|
157
|
+
| `GET /api/sessions` | JSON list of all sessions (newest first). |
|
|
158
|
+
| `GET /api/sessions/:taskId` | JSON detail of one session (full payload). |
|
|
159
|
+
| `GET /static/*` | Static frontend assets (`style.css`, `app.js`). |
|
|
160
|
+
|
|
161
|
+
If the configured `port` is already in use, the service falls back to an OS
|
|
162
|
+
assigned port and logs the actual URL to stderr.
|
|
163
|
+
|
|
164
|
+
## Tool result injection format
|
|
165
|
+
|
|
166
|
+
When a task reaches a terminal status, the plugin appends a banner to the
|
|
167
|
+
**last** tool result that was recorded for that task:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
…original tool output…
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
📊 **可视化工具调用链路**: <http://127.0.0.1:7788/task/1234>
|
|
174
|
+
(浏览器访问即可查看 mermaid 流程图:每个工具调用、参数、结果摘要、耗时)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
It also sets `result.metadata.task_visualization_url` so chat clients that
|
|
178
|
+
prefer structured fields can render the link from there.
|
|
179
|
+
|
|
180
|
+
The mutation is **non-destructive** — the original output is preserved, the
|
|
181
|
+
banner is appended after a `---` divider, and LLM agents can still parse
|
|
182
|
+
the response.
|
|
183
|
+
|
|
184
|
+
## Development
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# Type-check + build
|
|
188
|
+
bun run build
|
|
189
|
+
|
|
190
|
+
# Run unit tests (collector, url-injector, server, plugin)
|
|
191
|
+
bun test
|
|
192
|
+
|
|
193
|
+
# End-to-end check (boots the service, hits it, asserts response)
|
|
194
|
+
bun run verify
|
|
195
|
+
|
|
196
|
+
# Manual demo (boots the service + simulates a real task lifecycle)
|
|
197
|
+
bun run start:demo
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Debug logging
|
|
201
|
+
|
|
202
|
+
Set `TASK_SHOW_DEBUG=1` to enable verbose logging from the collector:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
TASK_SHOW_DEBUG=1 bun run start:demo
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Hook payload reference
|
|
209
|
+
|
|
210
|
+
### `tool:after.execute` (collected)
|
|
211
|
+
|
|
212
|
+
The plugin accepts the standard payload the `globalHookManager` emits for
|
|
213
|
+
this hook:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
{
|
|
217
|
+
tool: { name: string, ... },
|
|
218
|
+
args: Record<string, unknown>,
|
|
219
|
+
context: { taskId?: number, ... },
|
|
220
|
+
result: { success: boolean, output: string, error?: string, metadata?: any },
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
It also recognizes (in priority order):
|
|
225
|
+
- `ctx.currentTaskId`
|
|
226
|
+
- `metadata.current_task_id` (top-level)
|
|
227
|
+
- `result.metadata.current_task_id`
|
|
228
|
+
|
|
229
|
+
If no task id can be recovered, the call lands in a synthetic session so
|
|
230
|
+
the visualization still works.
|
|
231
|
+
|
|
232
|
+
### `task:after.update` (consumed)
|
|
233
|
+
|
|
234
|
+
The plugin accepts the standard `TaskUpdateContext`:
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
{ data: { task: { id: number, status: string, title?: string } } }
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
as well as duck-typed variants like `{ taskId, status, title }`. The plugin
|
|
241
|
+
only injects the URL when `status` is one of `completed`, `failed`,
|
|
242
|
+
`cancelled` — intermediate statuses are ignored.
|
|
243
|
+
|
|
244
|
+
## Limitations & follow-ups
|
|
245
|
+
|
|
246
|
+
- **Memory-only**: the collector keeps data in memory only. Restarting the
|
|
247
|
+
host process drops everything. Persisting to a file would be a small
|
|
248
|
+
follow-up.
|
|
249
|
+
- **Single host**: if you launch multiple `roy-agent` instances on the same
|
|
250
|
+
machine, change the `port` to avoid clashes (the service falls back to a
|
|
251
|
+
random port automatically, but the URL won't be predictable).
|
|
252
|
+
- **Mermaid CDN**: the frontend loads `mermaid@10` from jsDelivr. Air-gapped
|
|
253
|
+
deployments should vendor a copy locally.
|
|
254
|
+
- **No agent-level hooks**: the plugin currently does not subscribe to
|
|
255
|
+
`agent:after.execute` because the agent tool loop already fires
|
|
256
|
+
`tool:after.execute` per tool. If you want a "task finished" view that
|
|
257
|
+
includes the final agent message, listen to `agent:after.execute` too.
|
|
258
|
+
- **No file persistence**: data lives only in memory. A future improvement
|
|
259
|
+
would be a tiny SQLite sink so a restart still shows recent tasks.
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
MIT
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview In-memory collector for tool-call traces.
|
|
3
|
+
*
|
|
4
|
+
* Each task has its own append-only log of `ToolCallRecord`s. The collector
|
|
5
|
+
* exposes simple getters used by the HTTP layer; eviction keeps the memory
|
|
6
|
+
* footprint bounded (oldest tasks are dropped past `maxStoredTasks`).
|
|
7
|
+
*/
|
|
8
|
+
import type { TaskSession, TaskShowConfig } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* ToolCallCollector
|
|
11
|
+
*
|
|
12
|
+
* Owns the `Map<taskId, TaskSession>` and exposes:
|
|
13
|
+
* - recordToolCall(): append a single tool call record
|
|
14
|
+
* - getSession(): read-only snapshot
|
|
15
|
+
* - listSessions(): sorted snapshot for the index page
|
|
16
|
+
* - finalizeOnTaskUpdate(): mark session as completed/failed and stamp the
|
|
17
|
+
* visualization URL (called from the `task:after.update` hook)
|
|
18
|
+
*
|
|
19
|
+
* The collector is intentionally synchronous apart from the explicit async
|
|
20
|
+
* hook handlers — that keeps the mental model simple.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ToolCallCollector {
|
|
23
|
+
private readonly sessions;
|
|
24
|
+
private readonly cfg;
|
|
25
|
+
private readonly logger;
|
|
26
|
+
/** callback used by the server to know when data has changed (no-op in tests). */
|
|
27
|
+
private readonly onChange?;
|
|
28
|
+
constructor(cfg: TaskShowConfig, options?: {
|
|
29
|
+
onChange?: () => void;
|
|
30
|
+
logPrefix?: string;
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Get a defensive snapshot of one task's session (or undefined).
|
|
34
|
+
*/
|
|
35
|
+
getSession(taskId: number): TaskSession | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* List every session, sorted by `startedAt` descending (newest first).
|
|
38
|
+
*/
|
|
39
|
+
listSessions(): TaskSession[];
|
|
40
|
+
/**
|
|
41
|
+
* Convenience accessor used by the server to build per-task URLs.
|
|
42
|
+
*/
|
|
43
|
+
size(): number;
|
|
44
|
+
/**
|
|
45
|
+
* Append a `tool:after.execute` invocation into the right session.
|
|
46
|
+
*
|
|
47
|
+
* - If `explicitTaskId` is supplied (or recovered from the hook metadata),
|
|
48
|
+
* the record lands under that task.
|
|
49
|
+
* - Otherwise we open a synthetic session so demo runs without a
|
|
50
|
+
* TaskComponent still produce a nice flowchart.
|
|
51
|
+
*/
|
|
52
|
+
recordToolCall(opts: {
|
|
53
|
+
toolName: string;
|
|
54
|
+
args: Record<string, unknown>;
|
|
55
|
+
success: boolean;
|
|
56
|
+
outputPreview: string;
|
|
57
|
+
error?: string;
|
|
58
|
+
durationMs: number;
|
|
59
|
+
timestamp: number;
|
|
60
|
+
iteration?: number;
|
|
61
|
+
metadata?: Record<string, unknown>;
|
|
62
|
+
ctx?: any;
|
|
63
|
+
explicitTaskId?: number;
|
|
64
|
+
}): number;
|
|
65
|
+
/**
|
|
66
|
+
* Mark a task as completed/failed and freeze its `endedAt`. Used by the
|
|
67
|
+
* `task:after.update` hook.
|
|
68
|
+
*
|
|
69
|
+
* Returns the (possibly updated) session, or undefined if no session
|
|
70
|
+
* existed. The visualization URL is computed by the server (no hard
|
|
71
|
+
* coupling), so this method only persists the timestamp.
|
|
72
|
+
*/
|
|
73
|
+
finalizeOnTaskUpdate(opts: {
|
|
74
|
+
taskId: number;
|
|
75
|
+
newStatus: TaskSession["status"];
|
|
76
|
+
title?: string;
|
|
77
|
+
timestamp?: number;
|
|
78
|
+
}): TaskSession | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Stamp or refresh a session's title (used by `recordTaskTitle` from any
|
|
81
|
+
* context that happens to know the title, e.g. task:before.create).
|
|
82
|
+
*/
|
|
83
|
+
setTaskTitle(taskId: number, title: string): void;
|
|
84
|
+
/**
|
|
85
|
+
* Clear all data. Useful in tests and when the plugin is disposed.
|
|
86
|
+
*/
|
|
87
|
+
clear(): void;
|
|
88
|
+
/**
|
|
89
|
+
* Drop the oldest non-running sessions once we exceed `maxStoredTasks`.
|
|
90
|
+
*
|
|
91
|
+
* "Running" sessions are never evicted because the user may still be
|
|
92
|
+
* interacting with the page; we simply remove the oldest `completed`
|
|
93
|
+
* / `failed` / `cancelled` sessions.
|
|
94
|
+
*/
|
|
95
|
+
private evictIfNeeded;
|
|
96
|
+
/**
|
|
97
|
+
* Defensive deep clone so external code never mutates internal state.
|
|
98
|
+
* We use JSON because all payloads must already be JSON-serializable
|
|
99
|
+
* (they come from the tool hook / TaskComponent and include args/output
|
|
100
|
+
* previews).
|
|
101
|
+
*/
|
|
102
|
+
private cloneSession;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,WAAW,EAEX,cAAc,EACf,MAAM,YAAY,CAAC;AA6DpB;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAiB;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAa;gBAGrC,GAAG,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;IAOzD;;OAEG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAMnD;;OAEG;IACH,YAAY,IAAI,WAAW,EAAE;IAM7B;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;;;;;;OAOG;IACH,cAAc,CAAC,IAAI,EAAE;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC9B,OAAO,EAAE,OAAO,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,GAAG,CAAC,EAAE,GAAG,CAAC;QACV,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,MAAM;IA6CV;;;;;;;OAOG;IACH,oBAAoB,CAAC,IAAI,EAAE;QACzB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;QACjC,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,WAAW,GAAG,SAAS;IAe3B;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAOjD;;OAEG;IACH,KAAK,IAAI,IAAI;IASb;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAoBrB;;;;;OAKG;IACH,OAAO,CAAC,YAAY;CAGrB"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview In-memory collector for tool-call traces.
|
|
3
|
+
*
|
|
4
|
+
* Each task has its own append-only log of `ToolCallRecord`s. The collector
|
|
5
|
+
* exposes simple getters used by the HTTP layer; eviction keeps the memory
|
|
6
|
+
* footprint bounded (oldest tasks are dropped past `maxStoredTasks`).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Tiny logger helper that respects a configurable prefix. We avoid pulling in
|
|
10
|
+
* the host `createLogger` because the plugin should remain self-contained.
|
|
11
|
+
*/
|
|
12
|
+
class TinyLogger {
|
|
13
|
+
prefix;
|
|
14
|
+
constructor(prefix) {
|
|
15
|
+
this.prefix = prefix;
|
|
16
|
+
}
|
|
17
|
+
info(msg) {
|
|
18
|
+
if (typeof process !== "undefined" && process.env?.TASK_SHOW_DEBUG) {
|
|
19
|
+
// eslint-disable-next-line no-console
|
|
20
|
+
console.log(`[${this.prefix}] ${msg}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
warn(msg) {
|
|
24
|
+
// eslint-disable-next-line no-console
|
|
25
|
+
console.warn(`[${this.prefix}] WARN ${msg}`);
|
|
26
|
+
}
|
|
27
|
+
error(msg) {
|
|
28
|
+
// eslint-disable-next-line no-console
|
|
29
|
+
console.error(`[${this.prefix}] ERROR ${msg}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the "current" task id from a ToolHookContext.
|
|
34
|
+
*
|
|
35
|
+
* The roy-agent tool hook metadata typically carries the `current_task_id`
|
|
36
|
+
* (see `getCurrentTaskId()` in tool-component.ts). When absent — for example
|
|
37
|
+
* in tests — we accept a caller-supplied override.
|
|
38
|
+
*/
|
|
39
|
+
function extractTaskId(ctx, metadata) {
|
|
40
|
+
if (typeof ctx?.currentTaskId === "number")
|
|
41
|
+
return ctx.currentTaskId;
|
|
42
|
+
if (typeof metadata?.current_task_id === "number") {
|
|
43
|
+
return metadata.current_task_id;
|
|
44
|
+
}
|
|
45
|
+
if (metadata?.current_task_id !== undefined &&
|
|
46
|
+
typeof metadata.current_task_id === "number") {
|
|
47
|
+
return metadata.current_task_id;
|
|
48
|
+
}
|
|
49
|
+
// Common field name set by the tool-component (matches result.metadata)
|
|
50
|
+
if (ctx?.result?.metadata?.current_task_id !== undefined &&
|
|
51
|
+
typeof ctx.result.metadata.current_task_id === "number") {
|
|
52
|
+
return ctx.result.metadata.current_task_id;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Run-level fallback task id. We mint a synthetic id when the tool hook does
|
|
58
|
+
* not carry one — useful for the bundled demo, where no TaskComponent exists.
|
|
59
|
+
*/
|
|
60
|
+
let synthCounter = 1_900_000_000;
|
|
61
|
+
/**
|
|
62
|
+
* ToolCallCollector
|
|
63
|
+
*
|
|
64
|
+
* Owns the `Map<taskId, TaskSession>` and exposes:
|
|
65
|
+
* - recordToolCall(): append a single tool call record
|
|
66
|
+
* - getSession(): read-only snapshot
|
|
67
|
+
* - listSessions(): sorted snapshot for the index page
|
|
68
|
+
* - finalizeOnTaskUpdate(): mark session as completed/failed and stamp the
|
|
69
|
+
* visualization URL (called from the `task:after.update` hook)
|
|
70
|
+
*
|
|
71
|
+
* The collector is intentionally synchronous apart from the explicit async
|
|
72
|
+
* hook handlers — that keeps the mental model simple.
|
|
73
|
+
*/
|
|
74
|
+
export class ToolCallCollector {
|
|
75
|
+
sessions = new Map();
|
|
76
|
+
cfg;
|
|
77
|
+
logger;
|
|
78
|
+
/** callback used by the server to know when data has changed (no-op in tests). */
|
|
79
|
+
onChange;
|
|
80
|
+
constructor(cfg, options) {
|
|
81
|
+
this.cfg = cfg;
|
|
82
|
+
this.onChange = options?.onChange;
|
|
83
|
+
this.logger = new TinyLogger(options?.logPrefix ?? "task-show:collector");
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get a defensive snapshot of one task's session (or undefined).
|
|
87
|
+
*/
|
|
88
|
+
getSession(taskId) {
|
|
89
|
+
const s = this.sessions.get(taskId);
|
|
90
|
+
if (!s)
|
|
91
|
+
return undefined;
|
|
92
|
+
return this.cloneSession(s);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* List every session, sorted by `startedAt` descending (newest first).
|
|
96
|
+
*/
|
|
97
|
+
listSessions() {
|
|
98
|
+
return Array.from(this.sessions.values())
|
|
99
|
+
.map((s) => this.cloneSession(s))
|
|
100
|
+
.sort((a, b) => b.startedAt - a.startedAt);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Convenience accessor used by the server to build per-task URLs.
|
|
104
|
+
*/
|
|
105
|
+
size() {
|
|
106
|
+
return this.sessions.size;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Append a `tool:after.execute` invocation into the right session.
|
|
110
|
+
*
|
|
111
|
+
* - If `explicitTaskId` is supplied (or recovered from the hook metadata),
|
|
112
|
+
* the record lands under that task.
|
|
113
|
+
* - Otherwise we open a synthetic session so demo runs without a
|
|
114
|
+
* TaskComponent still produce a nice flowchart.
|
|
115
|
+
*/
|
|
116
|
+
recordToolCall(opts) {
|
|
117
|
+
const taskId = opts.explicitTaskId ??
|
|
118
|
+
extractTaskId(opts.ctx, opts.metadata) ??
|
|
119
|
+
synthCounter++;
|
|
120
|
+
let session = this.sessions.get(taskId);
|
|
121
|
+
if (!session) {
|
|
122
|
+
session = {
|
|
123
|
+
taskId,
|
|
124
|
+
title: "", // populated later by finalizeOnTaskUpdate or setTaskTitle
|
|
125
|
+
startedAt: opts.timestamp,
|
|
126
|
+
status: "running",
|
|
127
|
+
toolCalls: [],
|
|
128
|
+
};
|
|
129
|
+
this.sessions.set(taskId, session);
|
|
130
|
+
}
|
|
131
|
+
const sequence = session.toolCalls.length + 1;
|
|
132
|
+
const hasAttachment = detectAttachment(opts.args);
|
|
133
|
+
const record = {
|
|
134
|
+
sequence,
|
|
135
|
+
toolName: opts.toolName,
|
|
136
|
+
args: opts.args,
|
|
137
|
+
success: opts.success,
|
|
138
|
+
outputPreview: opts.outputPreview,
|
|
139
|
+
error: opts.error,
|
|
140
|
+
durationMs: opts.durationMs,
|
|
141
|
+
timestamp: opts.timestamp,
|
|
142
|
+
iteration: opts.iteration,
|
|
143
|
+
metadata: opts.metadata,
|
|
144
|
+
hasAttachment,
|
|
145
|
+
};
|
|
146
|
+
session.toolCalls.push(record);
|
|
147
|
+
this.logger.info(`Recorded #${sequence} ${opts.toolName} (${opts.success ? "ok" : "fail"}) → task=${taskId}`);
|
|
148
|
+
this.evictIfNeeded();
|
|
149
|
+
this.onChange?.();
|
|
150
|
+
return taskId;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Mark a task as completed/failed and freeze its `endedAt`. Used by the
|
|
154
|
+
* `task:after.update` hook.
|
|
155
|
+
*
|
|
156
|
+
* Returns the (possibly updated) session, or undefined if no session
|
|
157
|
+
* existed. The visualization URL is computed by the server (no hard
|
|
158
|
+
* coupling), so this method only persists the timestamp.
|
|
159
|
+
*/
|
|
160
|
+
finalizeOnTaskUpdate(opts) {
|
|
161
|
+
const session = this.sessions.get(opts.taskId);
|
|
162
|
+
if (!session)
|
|
163
|
+
return undefined;
|
|
164
|
+
session.status = opts.newStatus;
|
|
165
|
+
session.endedAt = opts.timestamp ?? Date.now();
|
|
166
|
+
if (opts.title)
|
|
167
|
+
session.title = opts.title;
|
|
168
|
+
this.logger.info(`Task ${opts.taskId} → ${opts.newStatus} (${session.toolCalls.length} tool calls)`);
|
|
169
|
+
this.onChange?.();
|
|
170
|
+
return this.cloneSession(session);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Stamp or refresh a session's title (used by `recordTaskTitle` from any
|
|
174
|
+
* context that happens to know the title, e.g. task:before.create).
|
|
175
|
+
*/
|
|
176
|
+
setTaskTitle(taskId, title) {
|
|
177
|
+
const session = this.sessions.get(taskId);
|
|
178
|
+
if (!session)
|
|
179
|
+
return;
|
|
180
|
+
session.title = title;
|
|
181
|
+
this.onChange?.();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Clear all data. Useful in tests and when the plugin is disposed.
|
|
185
|
+
*/
|
|
186
|
+
clear() {
|
|
187
|
+
this.sessions.clear();
|
|
188
|
+
this.onChange?.();
|
|
189
|
+
}
|
|
190
|
+
// -----------------------------------------------------------------------
|
|
191
|
+
// helpers
|
|
192
|
+
// -----------------------------------------------------------------------
|
|
193
|
+
/**
|
|
194
|
+
* Drop the oldest non-running sessions once we exceed `maxStoredTasks`.
|
|
195
|
+
*
|
|
196
|
+
* "Running" sessions are never evicted because the user may still be
|
|
197
|
+
* interacting with the page; we simply remove the oldest `completed`
|
|
198
|
+
* / `failed` / `cancelled` sessions.
|
|
199
|
+
*/
|
|
200
|
+
evictIfNeeded() {
|
|
201
|
+
const limit = this.cfg.maxStoredTasks;
|
|
202
|
+
if (this.sessions.size <= limit)
|
|
203
|
+
return;
|
|
204
|
+
const evictable = Array.from(this.sessions.values())
|
|
205
|
+
.filter((s) => s.status !== "running")
|
|
206
|
+
.sort((a, b) => a.startedAt - b.startedAt);
|
|
207
|
+
const overflow = this.sessions.size - limit;
|
|
208
|
+
let removed = 0;
|
|
209
|
+
for (const s of evictable) {
|
|
210
|
+
if (removed >= overflow)
|
|
211
|
+
break;
|
|
212
|
+
this.sessions.delete(s.taskId);
|
|
213
|
+
removed += 1;
|
|
214
|
+
}
|
|
215
|
+
if (removed > 0) {
|
|
216
|
+
this.logger.warn(`Evicted ${removed} sessions (limit ${limit})`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Defensive deep clone so external code never mutates internal state.
|
|
221
|
+
* We use JSON because all payloads must already be JSON-serializable
|
|
222
|
+
* (they come from the tool hook / TaskComponent and include args/output
|
|
223
|
+
* previews).
|
|
224
|
+
*/
|
|
225
|
+
cloneSession(s) {
|
|
226
|
+
return JSON.parse(JSON.stringify(s));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Detect whether the tool args suggest an attachment (image/pdf/etc.).
|
|
231
|
+
*
|
|
232
|
+
* The hook payload is free-form, but we look at common field names used by
|
|
233
|
+
* `read_file`, `attach`, and similar tools. This is a soft heuristic — false
|
|
234
|
+
* positives are fine, the frontend just renders an "📎" badge.
|
|
235
|
+
*/
|
|
236
|
+
function detectAttachment(args) {
|
|
237
|
+
if (!args)
|
|
238
|
+
return false;
|
|
239
|
+
const target = args.file_path ??
|
|
240
|
+
args.path ??
|
|
241
|
+
args.file ??
|
|
242
|
+
args.attachmentPath;
|
|
243
|
+
if (typeof target !== "string")
|
|
244
|
+
return false;
|
|
245
|
+
return /\.(png|jpe?g|webp|gif|bmp|pdf)$/i.test(target);
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public API for the roy-plugin-task-show package.
|
|
3
|
+
*
|
|
4
|
+
* The host loader typically does:
|
|
5
|
+
* import TaskShowPlugin, { createTaskShowPlugin } from "@.../roy-plugin-task-show";
|
|
6
|
+
* const plugin = createTaskShowPlugin({ port: 7788 });
|
|
7
|
+
* plugin.init(env);
|
|
8
|
+
*/
|
|
9
|
+
export { TaskShowPlugin, createTaskShowPlugin, } from "./plugin.js";
|
|
10
|
+
export type { TaskShowPluginInterface } from "./plugin.js";
|
|
11
|
+
export { DEFAULT_CONFIG, } from "./types.js";
|
|
12
|
+
export type { TaskShowConfig, PluginEnvLike, TaskSession, ToolCallRecord, } from "./types.js";
|
|
13
|
+
export { ToolCallCollector, } from "./collector.js";
|
|
14
|
+
export { TaskShowServer, } from "./server.js";
|
|
15
|
+
export type { ServerInfo } from "./server.js";
|
|
16
|
+
export { buildVisualizationUrl, buildIndexUrl, injectVisualizationUrl, appendVisualizationBanner, } from "./url-injector.js";
|
|
17
|
+
export type { InjectionResult } from "./url-injector.js";
|
|
18
|
+
import TaskShowPlugin from "./plugin.js";
|
|
19
|
+
export default TaskShowPlugin;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,cAAc,EACd,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,EACL,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,cAAc,EACd,aAAa,EACb,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,cAAc,MAAM,aAAa,CAAC;AACzC,eAAe,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public API for the roy-plugin-task-show package.
|
|
3
|
+
*
|
|
4
|
+
* The host loader typically does:
|
|
5
|
+
* import TaskShowPlugin, { createTaskShowPlugin } from "@.../roy-plugin-task-show";
|
|
6
|
+
* const plugin = createTaskShowPlugin({ port: 7788 });
|
|
7
|
+
* plugin.init(env);
|
|
8
|
+
*/
|
|
9
|
+
export { TaskShowPlugin, createTaskShowPlugin, } from "./plugin.js";
|
|
10
|
+
export { DEFAULT_CONFIG, } from "./types.js";
|
|
11
|
+
export { ToolCallCollector, } from "./collector.js";
|
|
12
|
+
export { TaskShowServer, } from "./server.js";
|
|
13
|
+
export { buildVisualizationUrl, buildIndexUrl, injectVisualizationUrl, appendVisualizationBanner, } from "./url-injector.js";
|
|
14
|
+
import TaskShowPlugin from "./plugin.js";
|
|
15
|
+
export default TaskShowPlugin;
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,cAAc,EACd,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,cAAc,GACf,MAAM,YAAY,CAAC;AAQpB,OAAO,EACL,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAG3B,OAAO,cAAc,MAAM,aAAa,CAAC;AACzC,eAAe,cAAc,CAAC"}
|