@botbotgo/agent-harness 0.0.307 → 0.0.309
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 +46 -10
- package/README.zh.md +46 -10
- package/dist/api.d.ts +3 -1
- package/dist/api.js +3 -0
- package/dist/cli.d.ts +12 -1
- package/dist/cli.js +331 -41
- package/dist/config/runtime/workspace.yaml +16 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +14 -0
- package/dist/mcp.js +175 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/resource/isolation.js +6 -1
- package/dist/runtime/adapter/model/invocation-request.d.ts +1 -0
- package/dist/runtime/adapter/model/invocation-request.js +4 -0
- package/dist/runtime/harness.d.ts +1 -0
- package/dist/runtime/harness.js +4 -0
- package/dist/workspace/compile.js +135 -5
- package/dist/workspace/object-loader.js +27 -17
- package/dist/workspace/resource-compilers.js +3 -3
- package/dist/workspace/support/source-protocols.d.ts +19 -0
- package/dist/workspace/support/source-protocols.js +192 -0
- package/dist/workspace/support/workspace-ref-utils.d.ts +4 -0
- package/dist/workspace/support/workspace-ref-utils.js +4 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
2
3
|
import { EventEmitter } from "node:events";
|
|
3
|
-
import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
4
|
+
import { existsSync, openSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
5
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
6
|
import { createInterface as createReadlineInterface } from "node:readline";
|
|
5
7
|
import { Writable } from "node:stream";
|
|
6
8
|
import path from "node:path";
|
|
@@ -14,7 +16,7 @@ import { serveA2aOverHttp } from "./protocol/a2a/http.js";
|
|
|
14
16
|
import { serveAgUiOverHttp } from "./protocol/ag-ui/http.js";
|
|
15
17
|
import { serveAcpOverHttp } from "./protocol/acp/http.js";
|
|
16
18
|
import { serveAcpOverStdio } from "./protocol/acp/stdio.js";
|
|
17
|
-
import { serveRuntimeMcpOverStdio } from "./mcp.js";
|
|
19
|
+
import { serveRuntimeMcpOverStdio, serveRuntimeMcpOverStreamableHttp } from "./mcp.js";
|
|
18
20
|
import { interpolateEnvPlaceholders } from "./workspace/yaml-object-reader.js";
|
|
19
21
|
function renderUsage() {
|
|
20
22
|
return `Usage:
|
|
@@ -23,7 +25,11 @@ function renderUsage() {
|
|
|
23
25
|
agent-harness [-w <path>] [prompt]
|
|
24
26
|
botbotgo [-w <path>] [prompt]
|
|
25
27
|
agent-harness acp serve [--workspace <path>] [--transport stdio|http] [--host <hostname>] [--port <port>]
|
|
28
|
+
agent-harness acp start [--workspace <path>] [--host <hostname>] [--port <port>]
|
|
29
|
+
agent-harness acp stop [--workspace <path>]
|
|
26
30
|
agent-harness a2a serve [--workspace <path>] [--host <hostname>] [--port <port>]
|
|
31
|
+
agent-harness a2a start [--workspace <path>] [--host <hostname>] [--port <port>]
|
|
32
|
+
agent-harness a2a stop [--workspace <path>]
|
|
27
33
|
agent-harness ag-ui serve [--workspace <path>] [--host <hostname>] [--port <port>]
|
|
28
34
|
agent-harness runtime overview [--workspace <path>] [--limit <n>] [--json]
|
|
29
35
|
agent-harness runtime health [--workspace <path>] [--json]
|
|
@@ -34,7 +40,12 @@ function renderUsage() {
|
|
|
34
40
|
agent-harness runtime scheduled-run --workspace <path> --schedule <scheduleId>
|
|
35
41
|
agent-harness runtime export request --workspace <path> --session <sessionId> --request <requestId> [--artifacts] [--artifact-contents] [--health] [--json]
|
|
36
42
|
agent-harness runtime export session --workspace <path> --session <sessionId> [--artifacts] [--artifact-contents] [--health] [--json]
|
|
37
|
-
agent-harness runtime-mcp serve [--workspace <path>]
|
|
43
|
+
agent-harness runtime-mcp serve [--workspace <path>] [--transport stdio|streamable-http] [--host <hostname>] [--port <port>]
|
|
44
|
+
agent-harness runtime-mcp start [--workspace <path>] [--host <hostname>] [--port <port>]
|
|
45
|
+
agent-harness runtime-mcp stop [--workspace <path>]
|
|
46
|
+
agent-harness mcp serve [--workspace <path>] [--transport stdio|streamable-http] [--host <hostname>] [--port <port>]
|
|
47
|
+
agent-harness mcp start [--workspace <path>] [--host <hostname>] [--port <port>]
|
|
48
|
+
agent-harness mcp stop [--workspace <path>]
|
|
38
49
|
|
|
39
50
|
Run botbotgo or agent-harness from any folder.
|
|
40
51
|
If ./config/ is absent, the runtime falls back to the bundled system defaults and bundled resources.
|
|
@@ -80,9 +91,9 @@ function parseInitOptions(args) {
|
|
|
80
91
|
}
|
|
81
92
|
return { options };
|
|
82
93
|
}
|
|
83
|
-
function parseAcpServeOptions(args) {
|
|
94
|
+
function parseAcpServeOptions(args, defaultTransport = "stdio") {
|
|
84
95
|
let workspaceRoot;
|
|
85
|
-
let transport =
|
|
96
|
+
let transport = defaultTransport;
|
|
86
97
|
let hostname;
|
|
87
98
|
let port;
|
|
88
99
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -134,6 +145,23 @@ function parseAcpServeOptions(args) {
|
|
|
134
145
|
}
|
|
135
146
|
return { workspaceRoot, transport, hostname, port };
|
|
136
147
|
}
|
|
148
|
+
function parseWorkspaceOnlyOptions(args) {
|
|
149
|
+
let workspaceRoot;
|
|
150
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
151
|
+
const arg = args[index];
|
|
152
|
+
if (arg === "--workspace") {
|
|
153
|
+
const value = args[index + 1];
|
|
154
|
+
if (!value) {
|
|
155
|
+
return { error: "Missing value for --workspace" };
|
|
156
|
+
}
|
|
157
|
+
workspaceRoot = value;
|
|
158
|
+
index += 1;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
return { error: `Unknown option: ${arg}` };
|
|
162
|
+
}
|
|
163
|
+
return { workspaceRoot };
|
|
164
|
+
}
|
|
137
165
|
function parseHttpServeOptions(args, serviceLabel = "HTTP") {
|
|
138
166
|
let workspaceRoot;
|
|
139
167
|
let hostname;
|
|
@@ -175,6 +203,60 @@ function parseHttpServeOptions(args, serviceLabel = "HTTP") {
|
|
|
175
203
|
}
|
|
176
204
|
return { workspaceRoot, hostname, port };
|
|
177
205
|
}
|
|
206
|
+
function parseRuntimeMcpServeOptions(args, defaultTransport = "stdio") {
|
|
207
|
+
let workspaceRoot;
|
|
208
|
+
let transport = defaultTransport;
|
|
209
|
+
let hostname;
|
|
210
|
+
let port;
|
|
211
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
212
|
+
const arg = args[index];
|
|
213
|
+
if (arg === "--workspace") {
|
|
214
|
+
const value = args[index + 1];
|
|
215
|
+
if (!value) {
|
|
216
|
+
return { transport, hostname, port, error: "Missing value for --workspace" };
|
|
217
|
+
}
|
|
218
|
+
workspaceRoot = value;
|
|
219
|
+
index += 1;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (arg === "--transport") {
|
|
223
|
+
const value = args[index + 1];
|
|
224
|
+
if (!value) {
|
|
225
|
+
return { transport, hostname, port, error: "Missing value for --transport" };
|
|
226
|
+
}
|
|
227
|
+
if (value !== "stdio" && value !== "streamable-http") {
|
|
228
|
+
return { transport, hostname, port, error: `Unsupported runtime MCP transport: ${value}` };
|
|
229
|
+
}
|
|
230
|
+
transport = value;
|
|
231
|
+
index += 1;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (arg === "--host") {
|
|
235
|
+
const value = args[index + 1];
|
|
236
|
+
if (!value) {
|
|
237
|
+
return { transport, hostname, port, error: "Missing value for --host" };
|
|
238
|
+
}
|
|
239
|
+
hostname = value;
|
|
240
|
+
index += 1;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (arg === "--port") {
|
|
244
|
+
const value = args[index + 1];
|
|
245
|
+
if (!value) {
|
|
246
|
+
return { transport, hostname, port, error: "Missing value for --port" };
|
|
247
|
+
}
|
|
248
|
+
const parsedPort = Number.parseInt(value, 10);
|
|
249
|
+
if (!Number.isFinite(parsedPort) || parsedPort < 0) {
|
|
250
|
+
return { transport, hostname, port, error: `Invalid runtime MCP port: ${value}` };
|
|
251
|
+
}
|
|
252
|
+
port = parsedPort;
|
|
253
|
+
index += 1;
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
return { transport, hostname, port, error: `Unknown option: ${arg}` };
|
|
257
|
+
}
|
|
258
|
+
return { workspaceRoot, transport, hostname, port };
|
|
259
|
+
}
|
|
178
260
|
function parseChatOptions(args) {
|
|
179
261
|
let workspaceRoot;
|
|
180
262
|
let agentId;
|
|
@@ -250,9 +332,66 @@ function isTopLevelCliCommand(value) {
|
|
|
250
332
|
|| value === "acp"
|
|
251
333
|
|| value === "a2a"
|
|
252
334
|
|| value === "ag-ui"
|
|
335
|
+
|| value === "mcp"
|
|
253
336
|
|| value === "runtime"
|
|
254
337
|
|| value === "runtime-mcp";
|
|
255
338
|
}
|
|
339
|
+
function resolveManagedServiceRoot(workspaceRoot) {
|
|
340
|
+
return path.join(workspaceRoot, ".botbotgo", "services");
|
|
341
|
+
}
|
|
342
|
+
function managedServiceStatePath(workspaceRoot, service) {
|
|
343
|
+
return path.join(resolveManagedServiceRoot(workspaceRoot), `${service}.json`);
|
|
344
|
+
}
|
|
345
|
+
function managedServiceLogPath(workspaceRoot, service, stream) {
|
|
346
|
+
return path.join(resolveManagedServiceRoot(workspaceRoot), `${service}.${stream}.log`);
|
|
347
|
+
}
|
|
348
|
+
async function readManagedServiceState(workspaceRoot, service) {
|
|
349
|
+
const statePath = managedServiceStatePath(workspaceRoot, service);
|
|
350
|
+
if (!existsSync(statePath)) {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
return JSON.parse(await readFile(statePath, "utf8"));
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async function writeManagedServiceState(state) {
|
|
361
|
+
const statePath = managedServiceStatePath(state.workspaceRoot, state.service);
|
|
362
|
+
await mkdir(path.dirname(statePath), { recursive: true });
|
|
363
|
+
await writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`, "utf8");
|
|
364
|
+
}
|
|
365
|
+
async function clearManagedServiceState(workspaceRoot, service) {
|
|
366
|
+
await rm(managedServiceStatePath(workspaceRoot, service), { force: true });
|
|
367
|
+
}
|
|
368
|
+
function defaultIsManagedProcessRunning(pid) {
|
|
369
|
+
try {
|
|
370
|
+
process.kill(pid, 0);
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function defaultSignalManagedProcess(pid, signal) {
|
|
378
|
+
process.kill(pid, signal);
|
|
379
|
+
}
|
|
380
|
+
async function defaultSpawnManagedCliProcess(input) {
|
|
381
|
+
await mkdir(path.dirname(input.stdoutPath), { recursive: true });
|
|
382
|
+
const stdoutFd = openSync(input.stdoutPath, "a");
|
|
383
|
+
const stderrFd = openSync(input.stderrPath, "a");
|
|
384
|
+
const child = spawn(process.execPath, [fileURLToPath(import.meta.url), ...input.args], {
|
|
385
|
+
cwd: input.cwd,
|
|
386
|
+
detached: true,
|
|
387
|
+
stdio: ["ignore", stdoutFd, stderrFd],
|
|
388
|
+
});
|
|
389
|
+
child.unref();
|
|
390
|
+
return { pid: child.pid };
|
|
391
|
+
}
|
|
392
|
+
async function sleep(ms) {
|
|
393
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
394
|
+
}
|
|
256
395
|
function parseRuntimeInspectOptions(args) {
|
|
257
396
|
let workspaceRoot;
|
|
258
397
|
let json = false;
|
|
@@ -821,11 +960,6 @@ function renderHealthSnapshot(snapshot, workspacePath) {
|
|
|
821
960
|
}
|
|
822
961
|
return `${lines.join("\n")}\n`;
|
|
823
962
|
}
|
|
824
|
-
async function sleep(ms) {
|
|
825
|
-
await new Promise((resolve) => {
|
|
826
|
-
setTimeout(resolve, ms);
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
963
|
function renderApprovalList(approvals) {
|
|
830
964
|
if (approvals.length === 0) {
|
|
831
965
|
return "No approvals matched.\n";
|
|
@@ -2041,6 +2175,10 @@ export async function runCli(argv, io = {}, deps = {}) {
|
|
|
2041
2175
|
const serveAcpHttp = deps.serveAcpOverHttp ?? serveAcpOverHttp;
|
|
2042
2176
|
const serveAcp = deps.serveAcpOverStdio ?? serveAcpOverStdio;
|
|
2043
2177
|
const serveRuntimeMcp = deps.serveRuntimeMcpOverStdio ?? serveRuntimeMcpOverStdio;
|
|
2178
|
+
const serveRuntimeMcpStreamableHttp = deps.serveRuntimeMcpOverStreamableHttp ?? serveRuntimeMcpOverStreamableHttp;
|
|
2179
|
+
const spawnManagedCliProcess = deps.spawnManagedCliProcess ?? defaultSpawnManagedCliProcess;
|
|
2180
|
+
const isManagedProcessRunning = deps.isManagedProcessRunning ?? defaultIsManagedProcessRunning;
|
|
2181
|
+
const signalManagedProcess = deps.signalManagedProcess ?? defaultSignalManagedProcess;
|
|
2044
2182
|
const createChatClient = deps.createChatClient ?? (async (input) => {
|
|
2045
2183
|
if (input.transport === "http") {
|
|
2046
2184
|
return createAcpHttpHarnessClient({
|
|
@@ -2342,6 +2480,68 @@ export async function runCli(argv, io = {}, deps = {}) {
|
|
|
2342
2480
|
return 1;
|
|
2343
2481
|
}
|
|
2344
2482
|
};
|
|
2483
|
+
const startManagedHttpService = async (service, workspacePath, args) => {
|
|
2484
|
+
const existing = await readManagedServiceState(workspacePath, service);
|
|
2485
|
+
if (existing && isManagedProcessRunning(existing.pid)) {
|
|
2486
|
+
stderr(`${service.toUpperCase()} service is already running for ${workspacePath} (pid ${existing.pid}).\n`);
|
|
2487
|
+
return 0;
|
|
2488
|
+
}
|
|
2489
|
+
if (existing) {
|
|
2490
|
+
await clearManagedServiceState(workspacePath, service);
|
|
2491
|
+
}
|
|
2492
|
+
const stdoutPath = managedServiceLogPath(workspacePath, service, "stdout");
|
|
2493
|
+
const stderrPath = managedServiceLogPath(workspacePath, service, "stderr");
|
|
2494
|
+
const spawned = await spawnManagedCliProcess({
|
|
2495
|
+
args,
|
|
2496
|
+
cwd: workspacePath,
|
|
2497
|
+
stdoutPath,
|
|
2498
|
+
stderrPath,
|
|
2499
|
+
});
|
|
2500
|
+
if (!spawned.pid || spawned.pid <= 0) {
|
|
2501
|
+
stderr(`Failed to start ${service.toUpperCase()} service for ${workspacePath}.\n`);
|
|
2502
|
+
return 1;
|
|
2503
|
+
}
|
|
2504
|
+
await writeManagedServiceState({
|
|
2505
|
+
pid: spawned.pid,
|
|
2506
|
+
service,
|
|
2507
|
+
workspaceRoot: workspacePath,
|
|
2508
|
+
transport: service === "mcp" ? "streamable-http" : "http",
|
|
2509
|
+
startedAt: new Date().toISOString(),
|
|
2510
|
+
stdoutPath,
|
|
2511
|
+
stderrPath,
|
|
2512
|
+
});
|
|
2513
|
+
await sleep(250);
|
|
2514
|
+
if (!isManagedProcessRunning(spawned.pid)) {
|
|
2515
|
+
await clearManagedServiceState(workspacePath, service);
|
|
2516
|
+
stderr(`Failed to keep ${service.toUpperCase()} service running for ${workspacePath}. Check ${stderrPath}.\n`);
|
|
2517
|
+
return 1;
|
|
2518
|
+
}
|
|
2519
|
+
stderr(`Started ${service.toUpperCase()} service for ${workspacePath} (pid ${spawned.pid}). Logs: ${stdoutPath}, ${stderrPath}\n`);
|
|
2520
|
+
return 0;
|
|
2521
|
+
};
|
|
2522
|
+
const stopManagedHttpService = async (service, workspacePath) => {
|
|
2523
|
+
const existing = await readManagedServiceState(workspacePath, service);
|
|
2524
|
+
if (!existing) {
|
|
2525
|
+
stderr(`No managed ${service.toUpperCase()} service is recorded for ${workspacePath}.\n`);
|
|
2526
|
+
return 0;
|
|
2527
|
+
}
|
|
2528
|
+
if (!isManagedProcessRunning(existing.pid)) {
|
|
2529
|
+
await clearManagedServiceState(workspacePath, service);
|
|
2530
|
+
stderr(`Managed ${service.toUpperCase()} service for ${workspacePath} is already stopped.\n`);
|
|
2531
|
+
return 0;
|
|
2532
|
+
}
|
|
2533
|
+
signalManagedProcess(existing.pid, "SIGTERM");
|
|
2534
|
+
for (let attempt = 0; attempt < 20; attempt += 1) {
|
|
2535
|
+
await sleep(100);
|
|
2536
|
+
if (!isManagedProcessRunning(existing.pid)) {
|
|
2537
|
+
await clearManagedServiceState(workspacePath, service);
|
|
2538
|
+
stderr(`Stopped ${service.toUpperCase()} service for ${workspacePath}.\n`);
|
|
2539
|
+
return 0;
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
stderr(`Timed out while stopping ${service.toUpperCase()} service for ${workspacePath} (pid ${existing.pid}).\n`);
|
|
2543
|
+
return 1;
|
|
2544
|
+
};
|
|
2345
2545
|
if (command === "init") {
|
|
2346
2546
|
if (!projectName?.trim()) {
|
|
2347
2547
|
stderr(renderUsage());
|
|
@@ -2392,28 +2592,58 @@ export async function runCli(argv, io = {}, deps = {}) {
|
|
|
2392
2592
|
}
|
|
2393
2593
|
if (command === "acp") {
|
|
2394
2594
|
const [subcommand, ...subcommandArgs] = [projectName, ...rest];
|
|
2395
|
-
if (subcommand !== "serve") {
|
|
2595
|
+
if (subcommand !== "serve" && subcommand !== "start" && subcommand !== "stop") {
|
|
2396
2596
|
stderr(renderUsage());
|
|
2397
2597
|
return 1;
|
|
2398
2598
|
}
|
|
2399
|
-
const
|
|
2400
|
-
|
|
2401
|
-
|
|
2599
|
+
const parsedStop = subcommand === "stop" ? parseWorkspaceOnlyOptions(subcommandArgs) : undefined;
|
|
2600
|
+
const parsedServe = subcommand !== "stop"
|
|
2601
|
+
? parseAcpServeOptions(subcommandArgs, subcommand === "start" ? "http" : "stdio")
|
|
2602
|
+
: undefined;
|
|
2603
|
+
const parseError = parsedStop?.error ?? parsedServe?.error;
|
|
2604
|
+
if (parseError) {
|
|
2605
|
+
stderr(`${parseError}\n`);
|
|
2402
2606
|
stderr(renderUsage());
|
|
2403
2607
|
return 1;
|
|
2404
2608
|
}
|
|
2405
2609
|
try {
|
|
2406
|
-
const
|
|
2407
|
-
const
|
|
2610
|
+
const workspaceRoot = parsedStop?.workspaceRoot ?? parsedServe?.workspaceRoot;
|
|
2611
|
+
const workspacePath = resolveCliWorkspaceRoot(cwd, workspaceRoot);
|
|
2612
|
+
const workspaceError = validateCliWorkspaceRoot(workspacePath, workspaceRoot);
|
|
2408
2613
|
if (workspaceError) {
|
|
2409
2614
|
stderr(`${workspaceError}\n`);
|
|
2410
2615
|
return 1;
|
|
2411
2616
|
}
|
|
2617
|
+
if (subcommand === "start") {
|
|
2618
|
+
if (!parsedServe) {
|
|
2619
|
+
stderr(renderUsage());
|
|
2620
|
+
return 1;
|
|
2621
|
+
}
|
|
2622
|
+
if (parsedServe.transport !== "http") {
|
|
2623
|
+
stderr("ACP start only supports --transport http. Use `acp serve --transport stdio` for stdio clients.\n");
|
|
2624
|
+
return 1;
|
|
2625
|
+
}
|
|
2626
|
+
const args = ["acp", "serve", "--workspace", workspacePath, "--transport", "http"];
|
|
2627
|
+
if (parsedServe.hostname) {
|
|
2628
|
+
args.push("--host", parsedServe.hostname);
|
|
2629
|
+
}
|
|
2630
|
+
if (typeof parsedServe.port === "number") {
|
|
2631
|
+
args.push("--port", String(parsedServe.port));
|
|
2632
|
+
}
|
|
2633
|
+
return startManagedHttpService("acp", workspacePath, args);
|
|
2634
|
+
}
|
|
2635
|
+
if (subcommand === "stop") {
|
|
2636
|
+
return stopManagedHttpService("acp", workspacePath);
|
|
2637
|
+
}
|
|
2638
|
+
if (!parsedServe) {
|
|
2639
|
+
stderr(renderUsage());
|
|
2640
|
+
return 1;
|
|
2641
|
+
}
|
|
2412
2642
|
const runtime = await createHarness(workspacePath);
|
|
2413
|
-
if (
|
|
2643
|
+
if (parsedServe.transport === "http") {
|
|
2414
2644
|
const server = await serveAcpHttp(runtime, {
|
|
2415
|
-
hostname:
|
|
2416
|
-
port:
|
|
2645
|
+
hostname: parsedServe.hostname,
|
|
2646
|
+
port: parsedServe.port,
|
|
2417
2647
|
});
|
|
2418
2648
|
stderr(`Serving ACP over http from ${workspacePath} at ${server.rpcUrl} (events ${server.eventsUrl})\n`);
|
|
2419
2649
|
await server.completed;
|
|
@@ -2469,27 +2699,47 @@ export async function runCli(argv, io = {}, deps = {}) {
|
|
|
2469
2699
|
}
|
|
2470
2700
|
if (command === "a2a") {
|
|
2471
2701
|
const [subcommand, ...subcommandArgs] = [projectName, ...rest];
|
|
2472
|
-
if (subcommand !== "serve") {
|
|
2702
|
+
if (subcommand !== "serve" && subcommand !== "start" && subcommand !== "stop") {
|
|
2473
2703
|
stderr(renderUsage());
|
|
2474
2704
|
return 1;
|
|
2475
2705
|
}
|
|
2476
|
-
const
|
|
2477
|
-
|
|
2478
|
-
|
|
2706
|
+
const parsedStop = subcommand === "stop" ? parseWorkspaceOnlyOptions(subcommandArgs) : undefined;
|
|
2707
|
+
const parsedServe = subcommand !== "stop" ? parseHttpServeOptions(subcommandArgs, "A2A") : undefined;
|
|
2708
|
+
const parseError = parsedStop?.error ?? parsedServe?.error;
|
|
2709
|
+
if (parseError) {
|
|
2710
|
+
stderr(`${parseError}\n`);
|
|
2479
2711
|
stderr(renderUsage());
|
|
2480
2712
|
return 1;
|
|
2481
2713
|
}
|
|
2482
2714
|
try {
|
|
2483
|
-
const
|
|
2484
|
-
const
|
|
2715
|
+
const workspaceRoot = parsedStop?.workspaceRoot ?? parsedServe?.workspaceRoot;
|
|
2716
|
+
const workspacePath = resolveCliWorkspaceRoot(cwd, workspaceRoot);
|
|
2717
|
+
const workspaceError = validateCliWorkspaceRoot(workspacePath, workspaceRoot);
|
|
2485
2718
|
if (workspaceError) {
|
|
2486
2719
|
stderr(`${workspaceError}\n`);
|
|
2487
2720
|
return 1;
|
|
2488
2721
|
}
|
|
2722
|
+
if (subcommand === "start") {
|
|
2723
|
+
const args = ["a2a", "serve", "--workspace", workspacePath];
|
|
2724
|
+
if (parsedServe?.hostname) {
|
|
2725
|
+
args.push("--host", parsedServe.hostname);
|
|
2726
|
+
}
|
|
2727
|
+
if (typeof parsedServe?.port === "number") {
|
|
2728
|
+
args.push("--port", String(parsedServe.port));
|
|
2729
|
+
}
|
|
2730
|
+
return startManagedHttpService("a2a", workspacePath, args);
|
|
2731
|
+
}
|
|
2732
|
+
if (subcommand === "stop") {
|
|
2733
|
+
return stopManagedHttpService("a2a", workspacePath);
|
|
2734
|
+
}
|
|
2735
|
+
if (!parsedServe) {
|
|
2736
|
+
stderr(renderUsage());
|
|
2737
|
+
return 1;
|
|
2738
|
+
}
|
|
2489
2739
|
const runtime = await createHarness(workspacePath);
|
|
2490
2740
|
const server = await serveA2a(runtime, {
|
|
2491
|
-
hostname:
|
|
2492
|
-
port:
|
|
2741
|
+
hostname: parsedServe.hostname,
|
|
2742
|
+
port: parsedServe.port,
|
|
2493
2743
|
});
|
|
2494
2744
|
stderr(`Serving A2A over http from ${workspacePath} at ${server.rpcUrl} (card ${server.agentCardUrl})\n`);
|
|
2495
2745
|
await server.completed;
|
|
@@ -2502,33 +2752,73 @@ export async function runCli(argv, io = {}, deps = {}) {
|
|
|
2502
2752
|
return 1;
|
|
2503
2753
|
}
|
|
2504
2754
|
}
|
|
2505
|
-
if (command === "runtime-mcp") {
|
|
2755
|
+
if (command === "mcp" || command === "runtime-mcp") {
|
|
2506
2756
|
const [subcommand, ...subcommandArgs] = [projectName, ...rest];
|
|
2507
|
-
if (subcommand !== "serve") {
|
|
2757
|
+
if (subcommand !== "serve" && subcommand !== "start" && subcommand !== "stop") {
|
|
2508
2758
|
stderr(renderUsage());
|
|
2509
2759
|
return 1;
|
|
2510
2760
|
}
|
|
2511
|
-
const
|
|
2512
|
-
|
|
2513
|
-
|
|
2761
|
+
const parsedStop = subcommand === "stop" ? parseWorkspaceOnlyOptions(subcommandArgs) : undefined;
|
|
2762
|
+
const parsedServe = subcommand !== "stop"
|
|
2763
|
+
? parseRuntimeMcpServeOptions(subcommandArgs, subcommand === "start" ? "streamable-http" : "stdio")
|
|
2764
|
+
: undefined;
|
|
2765
|
+
const parseError = parsedStop?.error ?? parsedServe?.error;
|
|
2766
|
+
if (parseError) {
|
|
2767
|
+
stderr(`${parseError}\n`);
|
|
2514
2768
|
stderr(renderUsage());
|
|
2515
2769
|
return 1;
|
|
2516
2770
|
}
|
|
2517
2771
|
try {
|
|
2518
|
-
const
|
|
2519
|
-
const
|
|
2772
|
+
const workspaceRoot = parsedStop?.workspaceRoot ?? parsedServe?.workspaceRoot;
|
|
2773
|
+
const workspacePath = resolveCliWorkspaceRoot(cwd, workspaceRoot);
|
|
2774
|
+
const workspaceError = validateCliWorkspaceRoot(workspacePath, workspaceRoot);
|
|
2520
2775
|
if (workspaceError) {
|
|
2521
2776
|
stderr(`${workspaceError}\n`);
|
|
2522
2777
|
return 1;
|
|
2523
2778
|
}
|
|
2779
|
+
if (subcommand === "start") {
|
|
2780
|
+
if (!parsedServe) {
|
|
2781
|
+
stderr(renderUsage());
|
|
2782
|
+
return 1;
|
|
2783
|
+
}
|
|
2784
|
+
if (parsedServe.transport !== "streamable-http") {
|
|
2785
|
+
stderr("MCP start only supports --transport streamable-http. Use `mcp serve --transport stdio` for stdio clients.\n");
|
|
2786
|
+
return 1;
|
|
2787
|
+
}
|
|
2788
|
+
const args = ["mcp", "serve", "--workspace", workspacePath, "--transport", "streamable-http"];
|
|
2789
|
+
if (parsedServe.hostname) {
|
|
2790
|
+
args.push("--host", parsedServe.hostname);
|
|
2791
|
+
}
|
|
2792
|
+
if (typeof parsedServe.port === "number") {
|
|
2793
|
+
args.push("--port", String(parsedServe.port));
|
|
2794
|
+
}
|
|
2795
|
+
return startManagedHttpService("mcp", workspacePath, args);
|
|
2796
|
+
}
|
|
2797
|
+
if (subcommand === "stop") {
|
|
2798
|
+
return stopManagedHttpService("mcp", workspacePath);
|
|
2799
|
+
}
|
|
2800
|
+
if (!parsedServe) {
|
|
2801
|
+
stderr(renderUsage());
|
|
2802
|
+
return 1;
|
|
2803
|
+
}
|
|
2524
2804
|
const runtime = await createHarness(workspacePath);
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2805
|
+
if (parsedServe.transport === "streamable-http") {
|
|
2806
|
+
const server = await serveRuntimeMcpStreamableHttp(runtime, {
|
|
2807
|
+
hostname: parsedServe.hostname,
|
|
2808
|
+
port: parsedServe.port,
|
|
2809
|
+
});
|
|
2810
|
+
stderr(`Serving runtime MCP over streamable HTTP from ${workspacePath} at ${server.url}\n`);
|
|
2811
|
+
await server.completed;
|
|
2812
|
+
}
|
|
2813
|
+
else {
|
|
2814
|
+
stderr(`Serving runtime MCP over stdio from ${workspacePath}\n`);
|
|
2815
|
+
const server = await serveRuntimeMcp(runtime);
|
|
2816
|
+
await new Promise((resolve, reject) => {
|
|
2817
|
+
process.stdin.on("end", resolve);
|
|
2818
|
+
process.stdin.on("error", reject);
|
|
2819
|
+
});
|
|
2820
|
+
await server.close();
|
|
2821
|
+
}
|
|
2532
2822
|
await runtime.stop();
|
|
2533
2823
|
return 0;
|
|
2534
2824
|
}
|
|
@@ -29,6 +29,22 @@ spec:
|
|
|
29
29
|
# agent-harness feature: stable runtime profile identifier for this data folder.
|
|
30
30
|
profile: default
|
|
31
31
|
|
|
32
|
+
# agent-harness feature: explicit tool and skill discovery sources.
|
|
33
|
+
# The default local workspace contract stays:
|
|
34
|
+
# - tools from ./resources/tools
|
|
35
|
+
# - skills from ./resources/skills
|
|
36
|
+
#
|
|
37
|
+
# Supported source forms today:
|
|
38
|
+
# - tools: file://<folder>, npm://<package-or-spec>
|
|
39
|
+
# - skills: file://<folder-or-SKILL.md>, http(s)://.../SKILL.md
|
|
40
|
+
#
|
|
41
|
+
# Discovery never traverses node_modules directories.
|
|
42
|
+
sources:
|
|
43
|
+
tools:
|
|
44
|
+
- file://./resources/tools
|
|
45
|
+
skills:
|
|
46
|
+
- file://./resources/skills
|
|
47
|
+
|
|
32
48
|
# agent-harness feature: runtime-level task queue and maximum number of concurrent requests.
|
|
33
49
|
# Additional requests wait in the harness queue until a slot becomes available.
|
|
34
50
|
concurrency:
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { AgentHarnessAcpServer, AgentHarnessRuntime, cancelRequest, createAgentHarness, createAcpServer, createAcpStdioClient, createRuntimeMcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, exportFlow, exportSequence, exportRequestPackage, exportSessionPackage, replayEvaluationBundle, getArtifact, getAgent, getApproval, getOperatorOverview, getRequestPlanState, getRequest, getHealth, listMemories, listRequestTraceItems, getSession, listAgentSkills, listRequestArtifacts, listApprovals, listRequests, listRequestEvents, listSessionSummaries, listSessions, memorize, normalizeUserChatInput, recordArtifact, request, recall, removeMemory, resolveApproval, serveA2aHttp, serveAcpHttp, serveAcpStdio, serveAgUiHttp, serveRuntimeMcpOverStdio, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
|
|
1
|
+
export { AgentHarnessAcpServer, AgentHarnessRuntime, cancelRequest, createAgentHarness, createAcpServer, createAcpStdioClient, createRuntimeMcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, exportFlow, exportSequence, exportRequestPackage, exportSessionPackage, replayEvaluationBundle, getArtifact, getAgent, getApproval, getOperatorOverview, getRequestPlanState, getRequest, getHealth, listMemories, listRequestTraceItems, getSession, listAgentSkills, listRequestArtifacts, listApprovals, listRequests, listRequestEvents, listSessionSummaries, listSessions, memorize, normalizeUserChatInput, recordArtifact, request, recall, removeMemory, resolveApproval, serveA2aHttp, serveAcpHttp, serveAcpStdio, serveAgUiHttp, serveRuntimeMcpOverStdio, serveRuntimeMcpOverStreamableHttp, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
|
|
2
2
|
export { AcpHarnessClient, InProcessHarnessClient, createAcpHarnessClient, createAcpHttpHarnessClient, createAcpStdioHarnessClient, createAgentHarnessClient, createInProcessHarnessClient, } from "./client.js";
|
|
3
3
|
export { createKnowledgeModule, readKnowledgeRuntimeConfig } from "./knowledge/index.js";
|
|
4
4
|
export { readProceduralMemoryRuntimeConfig } from "./procedural/index.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { AgentHarnessAcpServer, AgentHarnessRuntime, cancelRequest, createAgentHarness, createAcpServer, createAcpStdioClient, createRuntimeMcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, exportFlow, exportSequence, exportRequestPackage, exportSessionPackage, replayEvaluationBundle, getArtifact, getAgent, getApproval, getOperatorOverview, getRequestPlanState, getRequest, getHealth, listMemories, listRequestTraceItems, getSession, listAgentSkills, listRequestArtifacts, listApprovals, listRequests, listRequestEvents, listSessionSummaries, listSessions, memorize, normalizeUserChatInput, recordArtifact, request, recall, removeMemory, resolveApproval, serveA2aHttp, serveAcpHttp, serveAcpStdio, serveAgUiHttp, serveRuntimeMcpOverStdio, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
|
|
1
|
+
export { AgentHarnessAcpServer, AgentHarnessRuntime, cancelRequest, createAgentHarness, createAcpServer, createAcpStdioClient, createRuntimeMcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, exportFlow, exportSequence, exportRequestPackage, exportSessionPackage, replayEvaluationBundle, getArtifact, getAgent, getApproval, getOperatorOverview, getRequestPlanState, getRequest, getHealth, listMemories, listRequestTraceItems, getSession, listAgentSkills, listRequestArtifacts, listApprovals, listRequests, listRequestEvents, listSessionSummaries, listSessions, memorize, normalizeUserChatInput, recordArtifact, request, recall, removeMemory, resolveApproval, serveA2aHttp, serveAcpHttp, serveAcpStdio, serveAgUiHttp, serveRuntimeMcpOverStdio, serveRuntimeMcpOverStreamableHttp, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
|
|
2
2
|
export { AcpHarnessClient, InProcessHarnessClient, createAcpHarnessClient, createAcpHttpHarnessClient, createAcpStdioHarnessClient, createAgentHarnessClient, createInProcessHarnessClient, } from "./client.js";
|
|
3
3
|
export { createKnowledgeModule, readKnowledgeRuntimeConfig } from "./knowledge/index.js";
|
|
4
4
|
export { readProceduralMemoryRuntimeConfig } from "./procedural/index.js";
|
package/dist/mcp.d.ts
CHANGED
|
@@ -19,6 +19,19 @@ export type RuntimeMcpServerOptions = {
|
|
|
19
19
|
version?: string;
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
|
+
export type RuntimeMcpStreamableHttpServerOptions = RuntimeMcpServerOptions & {
|
|
23
|
+
hostname?: string;
|
|
24
|
+
port?: number;
|
|
25
|
+
path?: string;
|
|
26
|
+
};
|
|
27
|
+
export type RuntimeMcpStreamableHttpServer = {
|
|
28
|
+
hostname: string;
|
|
29
|
+
port: number;
|
|
30
|
+
path: string;
|
|
31
|
+
url: string;
|
|
32
|
+
completed: Promise<void>;
|
|
33
|
+
close: () => Promise<void>;
|
|
34
|
+
};
|
|
22
35
|
type RuntimeMcpRuntime = {
|
|
23
36
|
listSessions: (filter?: {
|
|
24
37
|
agentId?: string;
|
|
@@ -59,4 +72,5 @@ export declare function createToolMcpServerFromTools(tools: ToolMcpServerTool[],
|
|
|
59
72
|
export declare function serveToolsOverStdioFromHarness(tools: ToolMcpServerTool[], options: ToolMcpServerOptions): Promise<McpServer>;
|
|
60
73
|
export declare function createRuntimeMcpServer(runtime: RuntimeMcpRuntime, options?: RuntimeMcpServerOptions): Promise<McpServer>;
|
|
61
74
|
export declare function serveRuntimeMcpOverStdio(runtime: RuntimeMcpRuntime, options?: RuntimeMcpServerOptions): Promise<McpServer>;
|
|
75
|
+
export declare function serveRuntimeMcpOverStreamableHttp(runtime: RuntimeMcpRuntime, options?: RuntimeMcpStreamableHttpServerOptions): Promise<RuntimeMcpStreamableHttpServer>;
|
|
62
76
|
export {};
|