nodebench-mcp 2.28.0 → 2.30.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 +86 -0
- package/dist/engine/conformance.d.ts +31 -0
- package/dist/engine/conformance.js +81 -0
- package/dist/engine/conformance.js.map +1 -0
- package/dist/engine/server.d.ts +23 -0
- package/dist/engine/server.js +404 -0
- package/dist/engine/server.js.map +1 -0
- package/dist/engine/session.d.ts +53 -0
- package/dist/engine/session.js +139 -0
- package/dist/engine/session.js.map +1 -0
- package/dist/index.js +32 -7
- package/dist/index.js.map +1 -1
- package/dist/tools/designGovernanceTools.d.ts +20 -0
- package/dist/tools/designGovernanceTools.js +872 -0
- package/dist/tools/designGovernanceTools.js.map +1 -0
- package/dist/tools/openclawTools.d.ts +1 -0
- package/dist/tools/openclawTools.js +780 -0
- package/dist/tools/openclawTools.js.map +1 -1
- package/dist/tools/progressiveDiscoveryTools.js +3 -3
- package/dist/tools/progressiveDiscoveryTools.js.map +1 -1
- package/dist/tools/toolRegistry.js +190 -0
- package/dist/tools/toolRegistry.js.map +1 -1
- package/dist/toolsetRegistry.js +4 -0
- package/dist/toolsetRegistry.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -194,6 +194,92 @@ All analytics data is stored locally in `~/.nodebench/analytics.db` and never le
|
|
|
194
194
|
|
|
195
195
|
---
|
|
196
196
|
|
|
197
|
+
## Headless Engine API (v2.30.0)
|
|
198
|
+
|
|
199
|
+
NodeBench now ships a **headless, API-first Agentic Engine** — plug it into any client workflow and sell results, not software seats.
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Start MCP server with engine API on port 6276
|
|
203
|
+
npx nodebench-mcp --engine
|
|
204
|
+
|
|
205
|
+
# With auth token
|
|
206
|
+
npx nodebench-mcp --engine --engine-secret "your-token"
|
|
207
|
+
# or: ENGINE_SECRET=your-token npx nodebench-mcp --engine
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### API Endpoints
|
|
211
|
+
|
|
212
|
+
| Method | Path | Purpose |
|
|
213
|
+
|--------|------|---------|
|
|
214
|
+
| GET | `/` | Engine status, tool count, uptime |
|
|
215
|
+
| GET | `/api/health` | Health check |
|
|
216
|
+
| GET | `/api/tools` | List all available tools |
|
|
217
|
+
| POST | `/api/tools/:name` | Execute a single tool |
|
|
218
|
+
| GET | `/api/workflows` | List all 32 workflow chains |
|
|
219
|
+
| POST | `/api/workflows/:name` | Execute a workflow (with SSE streaming) |
|
|
220
|
+
| POST | `/api/sessions` | Create an isolated session |
|
|
221
|
+
| GET | `/api/sessions/:id` | Session status + call history |
|
|
222
|
+
| GET | `/api/sessions/:id/trace` | Full disclosure trace |
|
|
223
|
+
| GET | `/api/sessions/:id/report` | Conformance report |
|
|
224
|
+
| DELETE | `/api/sessions/:id` | End session |
|
|
225
|
+
| GET | `/api/presets` | List presets with tool counts |
|
|
226
|
+
|
|
227
|
+
### Quick Examples
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Execute a single tool
|
|
231
|
+
curl -X POST http://127.0.0.1:6276/api/tools/discover_tools \
|
|
232
|
+
-H "Content-Type: application/json" \
|
|
233
|
+
-d '{"args": {"query": "security audit"}, "preset": "full"}'
|
|
234
|
+
|
|
235
|
+
# Run a workflow with streaming
|
|
236
|
+
curl -N -X POST http://127.0.0.1:6276/api/workflows/fix_bug \
|
|
237
|
+
-H "Content-Type: application/json" \
|
|
238
|
+
-d '{"preset": "web_dev", "streaming": true}'
|
|
239
|
+
|
|
240
|
+
# Create a session, execute tools, get conformance report
|
|
241
|
+
SESSION=$(curl -s -X POST http://127.0.0.1:6276/api/sessions \
|
|
242
|
+
-H "Content-Type: application/json" \
|
|
243
|
+
-d '{"preset": "web_dev"}' | jq -r .sessionId)
|
|
244
|
+
|
|
245
|
+
curl -X POST "http://127.0.0.1:6276/api/tools/run_recon" \
|
|
246
|
+
-H "Content-Type: application/json" \
|
|
247
|
+
-d "{\"args\": {\"focusArea\": \"web\"}, \"sessionId\": \"$SESSION\"}"
|
|
248
|
+
|
|
249
|
+
curl "http://127.0.0.1:6276/api/sessions/$SESSION/report"
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Conformance Reports
|
|
253
|
+
|
|
254
|
+
Every workflow execution produces a conformance report scoring:
|
|
255
|
+
- **Step completeness** — did all required tools execute?
|
|
256
|
+
- **Quality gate** — did the quality gate pass?
|
|
257
|
+
- **Test layers** — were unit/integration/e2e results logged?
|
|
258
|
+
- **Flywheel** — was the methodology completed?
|
|
259
|
+
- **Learnings** — were findings banked for next time?
|
|
260
|
+
|
|
261
|
+
Grades: A (90+) / B (75+) / C (60+) / D (40+) / F (<40). Sell these reports as "Zero-bug deployment certificates" or "Automated WebMCP Conformance Reports."
|
|
262
|
+
|
|
263
|
+
### SSE Streaming
|
|
264
|
+
|
|
265
|
+
Workflow execution supports Server-Sent Events for real-time progress:
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
event: start
|
|
269
|
+
data: {"workflow":"fix_bug","totalSteps":7,"sessionId":"eng_..."}
|
|
270
|
+
|
|
271
|
+
event: step
|
|
272
|
+
data: {"stepIndex":0,"tool":"search_all_knowledge","status":"running"}
|
|
273
|
+
|
|
274
|
+
event: step
|
|
275
|
+
data: {"stepIndex":0,"tool":"search_all_knowledge","status":"complete","durationMs":42}
|
|
276
|
+
|
|
277
|
+
event: complete
|
|
278
|
+
data: {"totalSteps":7,"totalDurationMs":340,"conformanceScore":88,"grade":"B"}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
197
283
|
## What You Get — The AI Flywheel
|
|
198
284
|
|
|
199
285
|
The default setup (no `--preset` flag) gives you **50 tools** that implement the complete [AI Flywheel](https://github.com/HomenShum/nodebench-ai/blob/main/AI_FLYWHEEL.md) methodology — two interlocking loops that compound quality over time:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine Conformance Scoring
|
|
3
|
+
*
|
|
4
|
+
* Computes a deterministic conformance score from a session's tool call history.
|
|
5
|
+
* Used to generate "Conformance Reports" — the sellable output of the engine.
|
|
6
|
+
*/
|
|
7
|
+
import type { EngineSession } from "./session.js";
|
|
8
|
+
export interface ConformanceBreakdown {
|
|
9
|
+
stepsCompleted: boolean;
|
|
10
|
+
qualityGatePassed: boolean;
|
|
11
|
+
testLayersLogged: boolean;
|
|
12
|
+
flywheelCompleted: boolean;
|
|
13
|
+
learningsRecorded: boolean;
|
|
14
|
+
reconPerformed: boolean;
|
|
15
|
+
verificationCycleStarted: boolean;
|
|
16
|
+
noErrors: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface ConformanceReport {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
preset: string;
|
|
21
|
+
score: number;
|
|
22
|
+
grade: "A" | "B" | "C" | "D" | "F";
|
|
23
|
+
breakdown: ConformanceBreakdown;
|
|
24
|
+
summary: string;
|
|
25
|
+
totalSteps: number;
|
|
26
|
+
successfulSteps: number;
|
|
27
|
+
failedSteps: number;
|
|
28
|
+
totalDurationMs: number;
|
|
29
|
+
generatedAt: number;
|
|
30
|
+
}
|
|
31
|
+
export declare function computeConformance(session: EngineSession, expectedSteps?: number): ConformanceReport;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine Conformance Scoring
|
|
3
|
+
*
|
|
4
|
+
* Computes a deterministic conformance score from a session's tool call history.
|
|
5
|
+
* Used to generate "Conformance Reports" — the sellable output of the engine.
|
|
6
|
+
*/
|
|
7
|
+
const FLYWHEEL_TOOLS = [
|
|
8
|
+
"start_flywheel",
|
|
9
|
+
"log_flywheel_step",
|
|
10
|
+
"run_quality_gate",
|
|
11
|
+
];
|
|
12
|
+
const TEST_TOOLS = [
|
|
13
|
+
"log_test_result",
|
|
14
|
+
];
|
|
15
|
+
const LEARNING_TOOLS = [
|
|
16
|
+
"log_learning",
|
|
17
|
+
"save_session_note",
|
|
18
|
+
"search_all_knowledge",
|
|
19
|
+
];
|
|
20
|
+
const RECON_TOOLS = [
|
|
21
|
+
"run_recon",
|
|
22
|
+
"log_recon_finding",
|
|
23
|
+
];
|
|
24
|
+
const VERIFICATION_TOOLS = [
|
|
25
|
+
"start_verification_cycle",
|
|
26
|
+
"log_verification_step",
|
|
27
|
+
];
|
|
28
|
+
const QUALITY_GATE_TOOLS = [
|
|
29
|
+
"run_quality_gate",
|
|
30
|
+
];
|
|
31
|
+
function hasToolCalled(history, toolNames) {
|
|
32
|
+
return history.some((r) => toolNames.includes(r.toolName) && r.status === "success");
|
|
33
|
+
}
|
|
34
|
+
function countByStatus(history, status) {
|
|
35
|
+
return history.filter((r) => r.status === status).length;
|
|
36
|
+
}
|
|
37
|
+
export function computeConformance(session, expectedSteps) {
|
|
38
|
+
const history = session.callHistory;
|
|
39
|
+
const successful = countByStatus(history, "success");
|
|
40
|
+
const failed = countByStatus(history, "error");
|
|
41
|
+
const total = history.length;
|
|
42
|
+
const totalDurationMs = history.reduce((sum, r) => sum + r.durationMs, 0);
|
|
43
|
+
const breakdown = {
|
|
44
|
+
stepsCompleted: expectedSteps ? successful >= expectedSteps : successful > 0,
|
|
45
|
+
qualityGatePassed: hasToolCalled(history, QUALITY_GATE_TOOLS),
|
|
46
|
+
testLayersLogged: hasToolCalled(history, TEST_TOOLS),
|
|
47
|
+
flywheelCompleted: hasToolCalled(history, FLYWHEEL_TOOLS),
|
|
48
|
+
learningsRecorded: hasToolCalled(history, LEARNING_TOOLS),
|
|
49
|
+
reconPerformed: hasToolCalled(history, RECON_TOOLS),
|
|
50
|
+
verificationCycleStarted: hasToolCalled(history, VERIFICATION_TOOLS),
|
|
51
|
+
noErrors: failed === 0,
|
|
52
|
+
};
|
|
53
|
+
// Score: each check is worth 12.5 points (8 checks × 12.5 = 100)
|
|
54
|
+
const checks = Object.values(breakdown);
|
|
55
|
+
const passed = checks.filter(Boolean).length;
|
|
56
|
+
const score = Math.round((passed / checks.length) * 100);
|
|
57
|
+
const grade = score >= 90 ? "A" :
|
|
58
|
+
score >= 75 ? "B" :
|
|
59
|
+
score >= 60 ? "C" :
|
|
60
|
+
score >= 40 ? "D" : "F";
|
|
61
|
+
const failedChecks = Object.entries(breakdown)
|
|
62
|
+
.filter(([, v]) => !v)
|
|
63
|
+
.map(([k]) => k.replace(/([A-Z])/g, " $1").toLowerCase().trim());
|
|
64
|
+
const summary = score === 100
|
|
65
|
+
? `All conformance checks passed. ${successful}/${total} tool calls succeeded in ${totalDurationMs}ms.`
|
|
66
|
+
: `Score ${score}/100 (${grade}). Missing: ${failedChecks.join(", ")}. ${successful}/${total} calls succeeded.`;
|
|
67
|
+
return {
|
|
68
|
+
sessionId: session.id,
|
|
69
|
+
preset: session.preset,
|
|
70
|
+
score,
|
|
71
|
+
grade,
|
|
72
|
+
breakdown,
|
|
73
|
+
summary,
|
|
74
|
+
totalSteps: total,
|
|
75
|
+
successfulSteps: successful,
|
|
76
|
+
failedSteps: failed,
|
|
77
|
+
totalDurationMs,
|
|
78
|
+
generatedAt: Date.now(),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.js","sourceRoot":"","sources":["../../src/engine/conformance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NodeBench Engine — Headless API-First Agentic Engine
|
|
3
|
+
*
|
|
4
|
+
* HTTP server exposing MCP tool handlers as a REST API.
|
|
5
|
+
* Supports: tool execution, workflow chains (with SSE streaming),
|
|
6
|
+
* session management, preset gating, and conformance reports.
|
|
7
|
+
*
|
|
8
|
+
* Port: 6276 (follows 6274 dashboard, 6275 brief convention)
|
|
9
|
+
*/
|
|
10
|
+
import type { McpTool } from "../types.js";
|
|
11
|
+
import type { WorkflowChain } from "../tools/toolRegistry.js";
|
|
12
|
+
export interface EngineServerConfig {
|
|
13
|
+
toolMap: Map<string, McpTool>;
|
|
14
|
+
allTools: McpTool[];
|
|
15
|
+
workflowChains: Record<string, WorkflowChain>;
|
|
16
|
+
presets: Record<string, string[]>;
|
|
17
|
+
toolsetMap: Record<string, McpTool[]>;
|
|
18
|
+
toolToToolset: Map<string, string>;
|
|
19
|
+
secret?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function startEngineServer(config: EngineServerConfig, preferredPort?: number): Promise<number>;
|
|
22
|
+
export declare function stopEngineServer(): void;
|
|
23
|
+
export declare function getEngineUrl(): string | null;
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NodeBench Engine — Headless API-First Agentic Engine
|
|
3
|
+
*
|
|
4
|
+
* HTTP server exposing MCP tool handlers as a REST API.
|
|
5
|
+
* Supports: tool execution, workflow chains (with SSE streaming),
|
|
6
|
+
* session management, preset gating, and conformance reports.
|
|
7
|
+
*
|
|
8
|
+
* Port: 6276 (follows 6274 dashboard, 6275 brief convention)
|
|
9
|
+
*/
|
|
10
|
+
import { createServer } from "node:http";
|
|
11
|
+
import { createSession, getSession, endSession, listSessions, executeToolInSession, getSessionCount, } from "./session.js";
|
|
12
|
+
import { computeConformance } from "./conformance.js";
|
|
13
|
+
// ── State ─────────────────────────────────────────────────────────────
|
|
14
|
+
let _server = null;
|
|
15
|
+
let _port = 0;
|
|
16
|
+
let _config = null;
|
|
17
|
+
const _startedAt = Date.now();
|
|
18
|
+
// ── Server Lifecycle ──────────────────────────────────────────────────
|
|
19
|
+
export function startEngineServer(config, preferredPort = 6276) {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
if (_server) {
|
|
22
|
+
resolve(_port);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
_config = config;
|
|
26
|
+
_server = createServer((req, res) => handleRequest(req, res));
|
|
27
|
+
let attempts = 0;
|
|
28
|
+
const maxRetries = 5;
|
|
29
|
+
function tryListen(port) {
|
|
30
|
+
_server.once("error", (err) => {
|
|
31
|
+
if (err.code === "EADDRINUSE" && attempts < maxRetries) {
|
|
32
|
+
attempts++;
|
|
33
|
+
tryListen(port + 1);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
reject(err);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
_server.listen(port, "127.0.0.1", () => {
|
|
40
|
+
_port = port;
|
|
41
|
+
resolve(port);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
tryListen(preferredPort);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function stopEngineServer() {
|
|
48
|
+
if (_server) {
|
|
49
|
+
_server.close();
|
|
50
|
+
_server = null;
|
|
51
|
+
_port = 0;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function getEngineUrl() {
|
|
55
|
+
return _port ? `http://127.0.0.1:${_port}` : null;
|
|
56
|
+
}
|
|
57
|
+
// ── Helpers ───────────────────────────────────────────────────────────
|
|
58
|
+
function json(res, data, status = 200) {
|
|
59
|
+
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
|
|
60
|
+
res.end(JSON.stringify(data));
|
|
61
|
+
}
|
|
62
|
+
function error(res, message, status = 400) {
|
|
63
|
+
json(res, { ok: false, error: message }, status);
|
|
64
|
+
}
|
|
65
|
+
function parseBody(req) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
let body = "";
|
|
68
|
+
req.on("data", (chunk) => { body += chunk; });
|
|
69
|
+
req.on("end", () => {
|
|
70
|
+
if (!body) {
|
|
71
|
+
resolve({});
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
resolve(JSON.parse(body));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
reject(new Error("Invalid JSON body"));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
req.on("error", reject);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function checkAuth(req, res) {
|
|
85
|
+
if (!_config?.secret)
|
|
86
|
+
return true;
|
|
87
|
+
const auth = req.headers.authorization;
|
|
88
|
+
if (auth === `Bearer ${_config.secret}`)
|
|
89
|
+
return true;
|
|
90
|
+
error(res, "Unauthorized", 401);
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
function getToolMeta(name) {
|
|
94
|
+
const toolset = _config?.toolToToolset.get(name) ?? "unknown";
|
|
95
|
+
return { category: toolset };
|
|
96
|
+
}
|
|
97
|
+
// ── Request Router ────────────────────────────────────────────────────
|
|
98
|
+
async function handleRequest(req, res) {
|
|
99
|
+
const url = new URL(req.url || "/", `http://127.0.0.1:${_port}`);
|
|
100
|
+
const path = url.pathname;
|
|
101
|
+
const method = req.method ?? "GET";
|
|
102
|
+
// CORS
|
|
103
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
104
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
105
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
106
|
+
if (method === "OPTIONS") {
|
|
107
|
+
res.writeHead(204);
|
|
108
|
+
res.end();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (!checkAuth(req, res))
|
|
112
|
+
return;
|
|
113
|
+
try {
|
|
114
|
+
// ── Root ──────────────────────────────────────
|
|
115
|
+
if (path === "/" && method === "GET") {
|
|
116
|
+
return json(res, {
|
|
117
|
+
engine: "nodebench-engine",
|
|
118
|
+
version: "1.0.0",
|
|
119
|
+
toolCount: _config?.allTools.length ?? 0,
|
|
120
|
+
uptimeMs: Date.now() - _startedAt,
|
|
121
|
+
activeSessions: getSessionCount(),
|
|
122
|
+
endpoints: [
|
|
123
|
+
"GET /api/health",
|
|
124
|
+
"GET /api/tools",
|
|
125
|
+
"POST /api/tools/:toolName",
|
|
126
|
+
"GET /api/workflows",
|
|
127
|
+
"POST /api/workflows/:chainName",
|
|
128
|
+
"POST /api/sessions",
|
|
129
|
+
"GET /api/sessions",
|
|
130
|
+
"GET /api/sessions/:id",
|
|
131
|
+
"GET /api/sessions/:id/trace",
|
|
132
|
+
"GET /api/sessions/:id/report",
|
|
133
|
+
"DELETE /api/sessions/:id",
|
|
134
|
+
"GET /api/presets",
|
|
135
|
+
],
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// ── Health ────────────────────────────────────
|
|
139
|
+
if (path === "/api/health" && method === "GET") {
|
|
140
|
+
return json(res, {
|
|
141
|
+
ok: true,
|
|
142
|
+
uptimeMs: Date.now() - _startedAt,
|
|
143
|
+
toolCount: _config?.allTools.length ?? 0,
|
|
144
|
+
activeSessions: getSessionCount(),
|
|
145
|
+
memoryMb: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// ── List Tools ───────────────────────────────
|
|
149
|
+
if (path === "/api/tools" && method === "GET") {
|
|
150
|
+
const tools = (_config?.allTools ?? []).map((t) => ({
|
|
151
|
+
name: t.name,
|
|
152
|
+
description: t.description.slice(0, 200),
|
|
153
|
+
inputSchema: t.inputSchema,
|
|
154
|
+
...getToolMeta(t.name),
|
|
155
|
+
}));
|
|
156
|
+
return json(res, { ok: true, count: tools.length, tools });
|
|
157
|
+
}
|
|
158
|
+
// ── Execute Tool ─────────────────────────────
|
|
159
|
+
const toolExecMatch = path.match(/^\/api\/tools\/([^/]+)$/);
|
|
160
|
+
if (toolExecMatch && method === "POST") {
|
|
161
|
+
const toolName = decodeURIComponent(toolExecMatch[1]);
|
|
162
|
+
const body = await parseBody(req);
|
|
163
|
+
const args = body.args ?? {};
|
|
164
|
+
const presetName = body.preset ?? "full";
|
|
165
|
+
// Use session if provided, else create ephemeral
|
|
166
|
+
let session;
|
|
167
|
+
if (body.sessionId) {
|
|
168
|
+
const existing = getSession(body.sessionId);
|
|
169
|
+
if (!existing)
|
|
170
|
+
return error(res, `Session "${body.sessionId}" not found`, 404);
|
|
171
|
+
session = existing;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
session = createSession(presetName, _config.presets, _config.toolsetMap, _config.toolMap);
|
|
175
|
+
}
|
|
176
|
+
const record = await executeToolInSession(session, toolName, args);
|
|
177
|
+
// Clean up ephemeral sessions
|
|
178
|
+
if (!body.sessionId)
|
|
179
|
+
endSession(session.id);
|
|
180
|
+
return json(res, {
|
|
181
|
+
ok: record.status === "success",
|
|
182
|
+
toolName,
|
|
183
|
+
result: record.result,
|
|
184
|
+
meta: {
|
|
185
|
+
durationMs: record.durationMs,
|
|
186
|
+
sessionId: session.id,
|
|
187
|
+
...getToolMeta(toolName),
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
// ── List Workflows ───────────────────────────
|
|
192
|
+
if (path === "/api/workflows" && method === "GET") {
|
|
193
|
+
const chains = _config?.workflowChains ?? {};
|
|
194
|
+
const workflows = Object.entries(chains).map(([key, chain]) => ({
|
|
195
|
+
key,
|
|
196
|
+
name: chain.name,
|
|
197
|
+
description: chain.description,
|
|
198
|
+
stepCount: chain.steps.length,
|
|
199
|
+
steps: chain.steps.map((s, i) => ({ index: i, tool: s.tool, action: s.action })),
|
|
200
|
+
}));
|
|
201
|
+
return json(res, { ok: true, count: workflows.length, workflows });
|
|
202
|
+
}
|
|
203
|
+
// ── Execute Workflow ─────────────────────────
|
|
204
|
+
const workflowExecMatch = path.match(/^\/api\/workflows\/([^/]+)$/);
|
|
205
|
+
if (workflowExecMatch && method === "POST") {
|
|
206
|
+
const chainName = decodeURIComponent(workflowExecMatch[1]);
|
|
207
|
+
const chain = _config?.workflowChains[chainName];
|
|
208
|
+
if (!chain)
|
|
209
|
+
return error(res, `Workflow "${chainName}" not found`, 404);
|
|
210
|
+
const body = await parseBody(req);
|
|
211
|
+
const stepArgs = body.stepArgs ?? {};
|
|
212
|
+
const presetName = body.preset ?? "full";
|
|
213
|
+
const streaming = body.streaming === true;
|
|
214
|
+
// Create or reuse session
|
|
215
|
+
let session;
|
|
216
|
+
if (body.sessionId) {
|
|
217
|
+
const existing = getSession(body.sessionId);
|
|
218
|
+
if (!existing)
|
|
219
|
+
return error(res, `Session "${body.sessionId}" not found`, 404);
|
|
220
|
+
session = existing;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
session = createSession(presetName, _config.presets, _config.toolsetMap, _config.toolMap);
|
|
224
|
+
}
|
|
225
|
+
if (streaming) {
|
|
226
|
+
return executeWorkflowStreaming(res, session, chain, chainName, stepArgs, !body.sessionId);
|
|
227
|
+
}
|
|
228
|
+
// Non-streaming: execute all steps, return batch result
|
|
229
|
+
const results = [];
|
|
230
|
+
for (let i = 0; i < chain.steps.length; i++) {
|
|
231
|
+
const step = chain.steps[i];
|
|
232
|
+
const args = stepArgs[step.tool] ?? {};
|
|
233
|
+
const record = await executeToolInSession(session, step.tool, args);
|
|
234
|
+
results.push({
|
|
235
|
+
stepIndex: i,
|
|
236
|
+
tool: step.tool,
|
|
237
|
+
action: step.action,
|
|
238
|
+
status: record.status,
|
|
239
|
+
durationMs: record.durationMs,
|
|
240
|
+
result: record.result,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
const report = computeConformance(session, chain.steps.length);
|
|
244
|
+
if (!body.sessionId)
|
|
245
|
+
endSession(session.id);
|
|
246
|
+
return json(res, {
|
|
247
|
+
ok: true,
|
|
248
|
+
workflow: chainName,
|
|
249
|
+
totalSteps: chain.steps.length,
|
|
250
|
+
results,
|
|
251
|
+
conformance: report,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// ── Create Session ───────────────────────────
|
|
255
|
+
if (path === "/api/sessions" && method === "POST") {
|
|
256
|
+
const body = await parseBody(req);
|
|
257
|
+
const presetName = body.preset ?? "default";
|
|
258
|
+
const session = createSession(presetName, _config.presets, _config.toolsetMap, _config.toolMap);
|
|
259
|
+
return json(res, {
|
|
260
|
+
ok: true,
|
|
261
|
+
sessionId: session.id,
|
|
262
|
+
preset: session.preset,
|
|
263
|
+
toolCount: session.toolMap.size,
|
|
264
|
+
createdAt: session.createdAt,
|
|
265
|
+
}, 201);
|
|
266
|
+
}
|
|
267
|
+
// ── List Sessions ────────────────────────────
|
|
268
|
+
if (path === "/api/sessions" && method === "GET") {
|
|
269
|
+
return json(res, { ok: true, sessions: listSessions() });
|
|
270
|
+
}
|
|
271
|
+
// ── Session Detail ───────────────────────────
|
|
272
|
+
const sessionDetailMatch = path.match(/^\/api\/sessions\/([^/]+)$/);
|
|
273
|
+
if (sessionDetailMatch && method === "GET") {
|
|
274
|
+
const session = getSession(decodeURIComponent(sessionDetailMatch[1]));
|
|
275
|
+
if (!session)
|
|
276
|
+
return error(res, "Session not found", 404);
|
|
277
|
+
return json(res, {
|
|
278
|
+
ok: true,
|
|
279
|
+
id: session.id,
|
|
280
|
+
preset: session.preset,
|
|
281
|
+
status: session.status,
|
|
282
|
+
toolCount: session.toolMap.size,
|
|
283
|
+
callCount: session.callHistory.length,
|
|
284
|
+
createdAt: session.createdAt,
|
|
285
|
+
lastActivity: session.lastActivity,
|
|
286
|
+
callHistory: session.callHistory.map((r) => ({
|
|
287
|
+
id: r.id,
|
|
288
|
+
toolName: r.toolName,
|
|
289
|
+
status: r.status,
|
|
290
|
+
durationMs: r.durationMs,
|
|
291
|
+
timestamp: r.timestamp,
|
|
292
|
+
})),
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
// ── Session Trace ────────────────────────────
|
|
296
|
+
const sessionTraceMatch = path.match(/^\/api\/sessions\/([^/]+)\/trace$/);
|
|
297
|
+
if (sessionTraceMatch && method === "GET") {
|
|
298
|
+
const session = getSession(decodeURIComponent(sessionTraceMatch[1]));
|
|
299
|
+
if (!session)
|
|
300
|
+
return error(res, "Session not found", 404);
|
|
301
|
+
return json(res, {
|
|
302
|
+
ok: true,
|
|
303
|
+
sessionId: session.id,
|
|
304
|
+
events: session.disclosureEvents,
|
|
305
|
+
callHistory: session.callHistory,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
// ── Session Report ───────────────────────────
|
|
309
|
+
const sessionReportMatch = path.match(/^\/api\/sessions\/([^/]+)\/report$/);
|
|
310
|
+
if (sessionReportMatch && method === "GET") {
|
|
311
|
+
const session = getSession(decodeURIComponent(sessionReportMatch[1]));
|
|
312
|
+
if (!session)
|
|
313
|
+
return error(res, "Session not found", 404);
|
|
314
|
+
const report = computeConformance(session);
|
|
315
|
+
return json(res, { ok: true, report });
|
|
316
|
+
}
|
|
317
|
+
// ── Delete Session ───────────────────────────
|
|
318
|
+
if (sessionDetailMatch && method === "DELETE") {
|
|
319
|
+
const deleted = endSession(decodeURIComponent(sessionDetailMatch[1]));
|
|
320
|
+
if (!deleted)
|
|
321
|
+
return error(res, "Session not found", 404);
|
|
322
|
+
return json(res, { ok: true, deleted: true });
|
|
323
|
+
}
|
|
324
|
+
// ── List Presets ─────────────────────────────
|
|
325
|
+
if (path === "/api/presets" && method === "GET") {
|
|
326
|
+
const presets = _config?.presets ?? {};
|
|
327
|
+
const toolsetMap = _config?.toolsetMap ?? {};
|
|
328
|
+
const list = Object.entries(presets).map(([name, domains]) => {
|
|
329
|
+
let toolCount = 0;
|
|
330
|
+
for (const d of domains) {
|
|
331
|
+
toolCount += toolsetMap[d]?.length ?? 0;
|
|
332
|
+
}
|
|
333
|
+
return { name, domains, toolCount };
|
|
334
|
+
});
|
|
335
|
+
return json(res, { ok: true, presets: list });
|
|
336
|
+
}
|
|
337
|
+
// ── 404 ──────────────────────────────────────
|
|
338
|
+
error(res, "Not found", 404);
|
|
339
|
+
}
|
|
340
|
+
catch (err) {
|
|
341
|
+
error(res, err.message ?? "Internal server error", 500);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// ── SSE Workflow Execution ────────────────────────────────────────────
|
|
345
|
+
async function executeWorkflowStreaming(res, session, chain, chainName, stepArgs, ephemeral) {
|
|
346
|
+
res.writeHead(200, {
|
|
347
|
+
"Content-Type": "text/event-stream",
|
|
348
|
+
"Cache-Control": "no-cache",
|
|
349
|
+
Connection: "keep-alive",
|
|
350
|
+
"Access-Control-Allow-Origin": "*",
|
|
351
|
+
});
|
|
352
|
+
function send(event, data) {
|
|
353
|
+
res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
|
|
354
|
+
}
|
|
355
|
+
send("start", { workflow: chainName, totalSteps: chain.steps.length, sessionId: session.id });
|
|
356
|
+
for (let i = 0; i < chain.steps.length; i++) {
|
|
357
|
+
const step = chain.steps[i];
|
|
358
|
+
const args = stepArgs[step.tool] ?? {};
|
|
359
|
+
// Emit running event
|
|
360
|
+
const runningEvent = {
|
|
361
|
+
kind: "tool.invoke",
|
|
362
|
+
toolName: step.tool,
|
|
363
|
+
stepIndex: i,
|
|
364
|
+
status: "running",
|
|
365
|
+
timestamp: Date.now(),
|
|
366
|
+
};
|
|
367
|
+
session.disclosureEvents.push(runningEvent);
|
|
368
|
+
send("step", { stepIndex: i, tool: step.tool, action: step.action, status: "running" });
|
|
369
|
+
// Execute
|
|
370
|
+
const record = await executeToolInSession(session, step.tool, args);
|
|
371
|
+
// Emit complete event
|
|
372
|
+
const completeEvent = {
|
|
373
|
+
kind: "tool.invoke",
|
|
374
|
+
toolName: step.tool,
|
|
375
|
+
stepIndex: i,
|
|
376
|
+
status: record.status === "success" ? "complete" : "error",
|
|
377
|
+
data: record.result,
|
|
378
|
+
timestamp: Date.now(),
|
|
379
|
+
};
|
|
380
|
+
session.disclosureEvents.push(completeEvent);
|
|
381
|
+
send("step", {
|
|
382
|
+
stepIndex: i,
|
|
383
|
+
tool: step.tool,
|
|
384
|
+
action: step.action,
|
|
385
|
+
status: record.status === "success" ? "complete" : "error",
|
|
386
|
+
durationMs: record.durationMs,
|
|
387
|
+
result: record.result,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
// Final conformance
|
|
391
|
+
const report = computeConformance(session, chain.steps.length);
|
|
392
|
+
send("complete", {
|
|
393
|
+
workflow: chainName,
|
|
394
|
+
totalSteps: chain.steps.length,
|
|
395
|
+
totalDurationMs: report.totalDurationMs,
|
|
396
|
+
conformanceScore: report.score,
|
|
397
|
+
grade: report.grade,
|
|
398
|
+
sessionId: session.id,
|
|
399
|
+
});
|
|
400
|
+
if (ephemeral)
|
|
401
|
+
endSession(session.id);
|
|
402
|
+
res.end();
|
|
403
|
+
}
|
|
404
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/engine/server.ts"],"names":[],"mappings":"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"}
|