arcie 0.1.8 → 0.2.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/dist/_tsup-dts-rollup.d.ts +62 -1
- package/dist/{build-TWNCPXBU.js → build-GKOF7N76.js} +2 -2
- package/dist/{chunk-4WSILP75.js → chunk-3R65GQAE.js} +5 -4
- package/dist/{chunk-4WSILP75.js.map → chunk-3R65GQAE.js.map} +1 -1
- package/dist/{chunk-KVSX4MLK.js → chunk-XZPC3JSU.js} +59 -2
- package/dist/chunk-XZPC3JSU.js.map +1 -0
- package/dist/cli/index.js +7 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/{dev-DCPOO54H.js → dev-XBXOVOVE.js} +299 -113
- package/dist/dev-XBXOVOVE.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/{init-Q2GCMBCJ.js → init-BQK2LLTM.js} +11 -24
- package/dist/init-BQK2LLTM.js.map +1 -0
- package/dist/runner/index.js +2 -2
- package/package.json +1 -1
- package/templates/web-chat/app/api/agents/route.ts +37 -0
- package/templates/web-chat/app/api/chat/route.ts +10 -2
- package/templates/web-chat/components/agent-picker.tsx +102 -0
- package/templates/web-chat/components/chat.tsx +42 -2
- package/templates/web-chat/components/input-bar.tsx +4 -0
- package/dist/chunk-KVSX4MLK.js.map +0 -1
- package/dist/dev-DCPOO54H.js.map +0 -1
- package/dist/init-Q2GCMBCJ.js.map +0 -1
- /package/dist/{build-TWNCPXBU.js.map → build-GKOF7N76.js.map} +0 -0
|
@@ -25,10 +25,12 @@ import {
|
|
|
25
25
|
} from "./chunk-SGWQZZ2A.js";
|
|
26
26
|
import {
|
|
27
27
|
streamAgent
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-3R65GQAE.js";
|
|
29
29
|
import {
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
discoverAgents,
|
|
31
|
+
loadAgent,
|
|
32
|
+
loadAgentById
|
|
33
|
+
} from "./chunk-XZPC3JSU.js";
|
|
32
34
|
import {
|
|
33
35
|
discoverAgent
|
|
34
36
|
} from "./chunk-6XETPLIF.js";
|
|
@@ -36,8 +38,10 @@ import "./chunk-QE46QFID.js";
|
|
|
36
38
|
import "./chunk-PHTJLJOV.js";
|
|
37
39
|
|
|
38
40
|
// src/cli/dev.ts
|
|
41
|
+
import { spawn } from "child_process";
|
|
39
42
|
import { createServer } from "http";
|
|
40
|
-
import {
|
|
43
|
+
import { existsSync as existsSync2 } from "fs";
|
|
44
|
+
import { join as join2, resolve } from "path";
|
|
41
45
|
|
|
42
46
|
// src/cli/tui/renderer/start-block-chat.ts
|
|
43
47
|
import { watch } from "fs";
|
|
@@ -769,6 +773,8 @@ function renderBody(block, width, theme, context) {
|
|
|
769
773
|
return renderWarning(block, width, theme);
|
|
770
774
|
case "result":
|
|
771
775
|
return renderResult(block, width, theme);
|
|
776
|
+
case "command":
|
|
777
|
+
return renderCommand(block, theme);
|
|
772
778
|
case "subagent":
|
|
773
779
|
return renderSubagentHeader(block, width, theme);
|
|
774
780
|
case "agent-header":
|
|
@@ -931,6 +937,11 @@ function paintCommands(line, theme) {
|
|
|
931
937
|
(token) => isPromptControlCommand(token) ? theme.colors.blue(token) : token
|
|
932
938
|
);
|
|
933
939
|
}
|
|
940
|
+
function renderCommand(block, theme) {
|
|
941
|
+
const c = theme.colors;
|
|
942
|
+
const status = block.status === "error" ? `${c.red(theme.glyph.error)} ` : "";
|
|
943
|
+
return [`${c.cyan(theme.glyph.user)} ${status}${c.blue(block.body ?? "")}`];
|
|
944
|
+
}
|
|
934
945
|
function renderResult(block, width, theme) {
|
|
935
946
|
const marker = theme.colors.dim(theme.glyph.elbow);
|
|
936
947
|
const lines = wrap(block.body ?? "", width - 7);
|
|
@@ -1005,6 +1016,24 @@ var TerminalRenderer = class {
|
|
|
1005
1016
|
writeAgentHeader(body) {
|
|
1006
1017
|
this.apply([{ type: "commit", block: { kind: "agent-header", body } }]);
|
|
1007
1018
|
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Echoes a slash-command invocation to scrollback so it chains with the
|
|
1021
|
+
* transcript above (blue `▌ /model`) and the {@link writeCommandResult}
|
|
1022
|
+
* that hangs beneath it can share visual context.
|
|
1023
|
+
*/
|
|
1024
|
+
writeCommandInvocation(text, status) {
|
|
1025
|
+
const block = { kind: "command", body: text };
|
|
1026
|
+
if (status === "error") block.status = "error";
|
|
1027
|
+
this.apply([{ type: "commit", block }]);
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Writes a command outcome hung under the previous invocation with the
|
|
1031
|
+
* elbow connector (`⎿ message`). Multi-line messages soft-wrap under the
|
|
1032
|
+
* elbow.
|
|
1033
|
+
*/
|
|
1034
|
+
writeCommandResult(text) {
|
|
1035
|
+
this.apply([{ type: "commit", block: { kind: "result", body: text } }]);
|
|
1036
|
+
}
|
|
1008
1037
|
readPrompt() {
|
|
1009
1038
|
return new Promise((resolve2) => {
|
|
1010
1039
|
this.#pendingResolve = resolve2;
|
|
@@ -1232,28 +1261,35 @@ async function startBlockChat(options) {
|
|
|
1232
1261
|
if (trimmed.startsWith("/")) {
|
|
1233
1262
|
const command = parsePromptCommand(trimmed);
|
|
1234
1263
|
if (command === null) {
|
|
1235
|
-
renderer.
|
|
1264
|
+
renderer.writeCommandInvocation(trimmed, "error");
|
|
1265
|
+
renderer.writeCommandResult("Unknown command \u2014 try /help");
|
|
1236
1266
|
continue;
|
|
1237
1267
|
}
|
|
1268
|
+
if (command.type === "exit") {
|
|
1269
|
+
renderer.writeCommandInvocation(trimmed);
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
renderer.writeCommandInvocation(trimmed);
|
|
1238
1273
|
switch (command.type) {
|
|
1239
|
-
case "exit":
|
|
1240
|
-
return;
|
|
1241
1274
|
case "help":
|
|
1242
|
-
|
|
1243
|
-
renderer.writeNotice(line);
|
|
1244
|
-
}
|
|
1275
|
+
renderer.writeCommandResult(formatPromptCommandHelp());
|
|
1245
1276
|
continue;
|
|
1246
1277
|
case "clear":
|
|
1247
1278
|
case "new":
|
|
1248
1279
|
for (const op of translator.reset()) renderer.apply([op]);
|
|
1249
1280
|
await commitHeader();
|
|
1250
1281
|
continue;
|
|
1251
|
-
case "extension":
|
|
1252
|
-
await handleExtension(command,
|
|
1282
|
+
case "extension": {
|
|
1283
|
+
const outcome = await handleExtension(command, agentDir);
|
|
1284
|
+
if (outcome.message.length > 0) renderer.writeCommandResult(outcome.message);
|
|
1285
|
+
if (outcome.refresh) await commitHeader();
|
|
1253
1286
|
continue;
|
|
1254
|
-
|
|
1255
|
-
|
|
1287
|
+
}
|
|
1288
|
+
case "loglevel": {
|
|
1289
|
+
const outcome = handleLogLevel(command, logLevelState);
|
|
1290
|
+
renderer.writeCommandResult(outcome.message);
|
|
1256
1291
|
continue;
|
|
1292
|
+
}
|
|
1257
1293
|
}
|
|
1258
1294
|
continue;
|
|
1259
1295
|
}
|
|
@@ -1265,120 +1301,122 @@ async function startBlockChat(options) {
|
|
|
1265
1301
|
renderer.stop();
|
|
1266
1302
|
}
|
|
1267
1303
|
}
|
|
1268
|
-
async function handleExtension(command,
|
|
1304
|
+
async function handleExtension(command, agentDir) {
|
|
1269
1305
|
const argument = command.argument.trim();
|
|
1270
1306
|
switch (command.name) {
|
|
1271
1307
|
case "model":
|
|
1272
|
-
|
|
1273
|
-
return;
|
|
1308
|
+
return handleModel(argument, agentDir);
|
|
1274
1309
|
case "provider":
|
|
1275
|
-
handleProvider(
|
|
1276
|
-
return;
|
|
1310
|
+
return handleProvider(agentDir);
|
|
1277
1311
|
case "channels":
|
|
1278
|
-
handleChannels(argument,
|
|
1279
|
-
return;
|
|
1312
|
+
return handleChannels(argument, agentDir);
|
|
1280
1313
|
default:
|
|
1281
|
-
|
|
1314
|
+
return { message: `/${command.name} is not supported here` };
|
|
1282
1315
|
}
|
|
1283
1316
|
}
|
|
1284
|
-
|
|
1317
|
+
function handleModel(argument, agentDir) {
|
|
1285
1318
|
const current = readAgentModel(agentDir);
|
|
1286
1319
|
if (argument.length === 0) {
|
|
1287
|
-
|
|
1288
|
-
current ? `
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
return;
|
|
1320
|
+
const lines = [
|
|
1321
|
+
current ? `Current model: ${current}` : "No model configured in agent/agent.ts",
|
|
1322
|
+
"Change with: /model <provider/slug>"
|
|
1323
|
+
];
|
|
1324
|
+
return { message: lines.join("\n") };
|
|
1292
1325
|
}
|
|
1293
1326
|
if (current === argument) {
|
|
1294
|
-
|
|
1295
|
-
return;
|
|
1327
|
+
return { message: `Model is already ${argument}` };
|
|
1296
1328
|
}
|
|
1297
1329
|
const changed = writeAgentModel(agentDir, argument);
|
|
1298
1330
|
if (!changed) {
|
|
1299
|
-
|
|
1300
|
-
"
|
|
1301
|
-
|
|
1302
|
-
);
|
|
1303
|
-
return;
|
|
1331
|
+
return {
|
|
1332
|
+
message: "Could not update agent/agent.ts \u2014 file missing or model field not found."
|
|
1333
|
+
};
|
|
1304
1334
|
}
|
|
1305
|
-
|
|
1306
|
-
await commitHeader();
|
|
1335
|
+
return { message: `Model set to ${argument}`, refresh: true };
|
|
1307
1336
|
}
|
|
1308
|
-
function handleProvider(
|
|
1337
|
+
function handleProvider(agentDir) {
|
|
1309
1338
|
const status = providerKeyStatus(agentDir);
|
|
1310
1339
|
const configured = status.filter((row) => row.set);
|
|
1311
1340
|
if (configured.length === 0) {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1341
|
+
return {
|
|
1342
|
+
message: [
|
|
1343
|
+
"No provider keys configured.",
|
|
1344
|
+
"Edit .env.local to add CENCORI_API_KEY or a direct provider key."
|
|
1345
|
+
].join("\n")
|
|
1346
|
+
};
|
|
1315
1347
|
}
|
|
1316
|
-
|
|
1348
|
+
const lines = ["Provider keys:"];
|
|
1317
1349
|
for (const row of status) {
|
|
1318
1350
|
if (row.set) {
|
|
1319
|
-
|
|
1351
|
+
lines.push(` ${row.key} = ${row.masked} (${row.source})`);
|
|
1320
1352
|
} else {
|
|
1321
|
-
|
|
1353
|
+
lines.push(` ${row.key} \u2014 not set`);
|
|
1322
1354
|
}
|
|
1323
1355
|
}
|
|
1356
|
+
return { message: lines.join("\n") };
|
|
1324
1357
|
}
|
|
1325
|
-
function handleChannels(argument,
|
|
1358
|
+
function handleChannels(argument, agentDir) {
|
|
1326
1359
|
if (argument.length === 0) {
|
|
1327
1360
|
const channels = listChannels(agentDir);
|
|
1328
1361
|
if (channels.length === 0) {
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1362
|
+
return {
|
|
1363
|
+
message: ["No channels scaffolded.", "Add one with: /channels add web"].join("\n")
|
|
1364
|
+
};
|
|
1332
1365
|
}
|
|
1333
|
-
|
|
1334
|
-
for (const channel of channels)
|
|
1335
|
-
|
|
1336
|
-
return;
|
|
1366
|
+
const lines = ["Channels:"];
|
|
1367
|
+
for (const channel of channels) lines.push(` ${channel.name} \u2014 ${channel.path}`);
|
|
1368
|
+
lines.push("Add another with: /channels add <kind>");
|
|
1369
|
+
return { message: lines.join("\n") };
|
|
1337
1370
|
}
|
|
1338
1371
|
const parts = argument.split(/\s+/);
|
|
1339
1372
|
const subcommand = parts[0];
|
|
1340
1373
|
const kind = parts[1];
|
|
1341
1374
|
if (subcommand !== "add") {
|
|
1342
|
-
|
|
1343
|
-
return;
|
|
1375
|
+
return { message: `Unknown subcommand '${subcommand}' \u2014 try: /channels add web` };
|
|
1344
1376
|
}
|
|
1345
1377
|
if (kind !== "web") {
|
|
1346
|
-
|
|
1347
|
-
|
|
1378
|
+
return {
|
|
1379
|
+
message: `Unsupported channel kind '${kind ?? ""}' \u2014 only 'web' is supported`
|
|
1380
|
+
};
|
|
1348
1381
|
}
|
|
1349
1382
|
try {
|
|
1350
1383
|
const result = scaffoldWebChat(agentDir);
|
|
1351
1384
|
if (result.alreadyExisted) {
|
|
1352
|
-
|
|
1353
|
-
return;
|
|
1385
|
+
return { message: `channels/web already exists at ${result.targetPath}` };
|
|
1354
1386
|
}
|
|
1355
|
-
|
|
1356
|
-
|
|
1387
|
+
return {
|
|
1388
|
+
message: [
|
|
1389
|
+
`Scaffolded ${result.targetPath}`,
|
|
1390
|
+
"Next: cd into it, npm install, npm run dev"
|
|
1391
|
+
].join("\n")
|
|
1392
|
+
};
|
|
1357
1393
|
} catch (err) {
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
);
|
|
1394
|
+
return {
|
|
1395
|
+
message: `Channel scaffold failed: ${err instanceof Error ? err.message : String(err)}`
|
|
1396
|
+
};
|
|
1362
1397
|
}
|
|
1363
1398
|
}
|
|
1364
|
-
function handleLogLevel(command,
|
|
1399
|
+
function handleLogLevel(command, state) {
|
|
1365
1400
|
const argument = command.argument.trim();
|
|
1366
1401
|
if (argument.length === 0) {
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1402
|
+
return {
|
|
1403
|
+
message: [
|
|
1404
|
+
`Log level: ${state.mode}`,
|
|
1405
|
+
"Change with: /loglevel all | stderr | none",
|
|
1406
|
+
"Note: arcie does not currently capture subprocess logs."
|
|
1407
|
+
].join("\n")
|
|
1408
|
+
};
|
|
1371
1409
|
}
|
|
1372
1410
|
if (!VALID_LOG_MODES.has(argument)) {
|
|
1373
|
-
|
|
1374
|
-
"Invalid log level",
|
|
1375
|
-
`${argument} \u2014 pick one of: all, stderr, none`
|
|
1376
|
-
);
|
|
1377
|
-
return;
|
|
1411
|
+
return { message: `Invalid log level '${argument}' \u2014 pick one of: all, stderr, none` };
|
|
1378
1412
|
}
|
|
1379
1413
|
state.mode = argument;
|
|
1380
|
-
|
|
1381
|
-
|
|
1414
|
+
return {
|
|
1415
|
+
message: [
|
|
1416
|
+
`Log level: ${state.mode}`,
|
|
1417
|
+
"Note: arcie does not currently capture subprocess logs."
|
|
1418
|
+
].join("\n")
|
|
1419
|
+
};
|
|
1382
1420
|
}
|
|
1383
1421
|
async function streamOneTurn(renderer, translator, agentDir, message) {
|
|
1384
1422
|
let sawApproval = false;
|
|
@@ -2094,42 +2132,165 @@ async function listenWithFallback(server, startPort) {
|
|
|
2094
2132
|
`Could not find a free port in ${startPort}..${startPort + MAX_PORT_ATTEMPTS - 1}`
|
|
2095
2133
|
);
|
|
2096
2134
|
}
|
|
2135
|
+
function isPortFree(port) {
|
|
2136
|
+
return new Promise((resolve2) => {
|
|
2137
|
+
const probe = createServer();
|
|
2138
|
+
probe.once("error", () => resolve2(false));
|
|
2139
|
+
probe.once("listening", () => {
|
|
2140
|
+
probe.close(() => resolve2(true));
|
|
2141
|
+
});
|
|
2142
|
+
probe.listen(port);
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
async function findFreePort(startPort, maxAttempts = MAX_PORT_ATTEMPTS) {
|
|
2146
|
+
for (let offset = 0; offset < maxAttempts; offset += 1) {
|
|
2147
|
+
const port = startPort + offset;
|
|
2148
|
+
if (await isPortFree(port)) return port;
|
|
2149
|
+
}
|
|
2150
|
+
throw new Error(`No free port in ${startPort}..${startPort + maxAttempts - 1}`);
|
|
2151
|
+
}
|
|
2152
|
+
function openBrowser(url) {
|
|
2153
|
+
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
2154
|
+
try {
|
|
2155
|
+
const child = spawn(command, [url], {
|
|
2156
|
+
detached: true,
|
|
2157
|
+
stdio: "ignore",
|
|
2158
|
+
shell: process.platform === "win32"
|
|
2159
|
+
});
|
|
2160
|
+
child.unref();
|
|
2161
|
+
} catch {
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
async function waitForHttp(url, timeoutMs = 3e4) {
|
|
2165
|
+
const deadline = Date.now() + timeoutMs;
|
|
2166
|
+
while (Date.now() < deadline) {
|
|
2167
|
+
try {
|
|
2168
|
+
const res = await fetch(url, { method: "GET" });
|
|
2169
|
+
if (res.status < 500) return true;
|
|
2170
|
+
} catch {
|
|
2171
|
+
}
|
|
2172
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
2173
|
+
}
|
|
2174
|
+
return false;
|
|
2175
|
+
}
|
|
2176
|
+
async function installWebDeps(webDir) {
|
|
2177
|
+
return new Promise((resolve2) => {
|
|
2178
|
+
const child = spawn("npm", ["install", "--no-fund", "--no-audit"], {
|
|
2179
|
+
cwd: webDir,
|
|
2180
|
+
stdio: "ignore"
|
|
2181
|
+
});
|
|
2182
|
+
child.once("exit", (code) => resolve2(code === 0));
|
|
2183
|
+
child.once("error", () => resolve2(false));
|
|
2184
|
+
});
|
|
2185
|
+
}
|
|
2186
|
+
async function startWebChannel(agentDir, arcieUrl, webPort) {
|
|
2187
|
+
const webDir = join2(agentDir, "channels", "web");
|
|
2188
|
+
if (!existsSync2(join2(webDir, "package.json"))) return void 0;
|
|
2189
|
+
if (!existsSync2(join2(webDir, "node_modules"))) {
|
|
2190
|
+
console.log(` ${dimmed(`web installing channels/web deps (first run)\u2026`)}`);
|
|
2191
|
+
const installed = await installWebDeps(webDir);
|
|
2192
|
+
if (!installed) {
|
|
2193
|
+
console.log();
|
|
2194
|
+
console.log(` ${grey("\u26A0")} channels/web install failed \u2014 try manually:`);
|
|
2195
|
+
console.log(` ${dimmed(` cd ${webDir} && npm install`)}`);
|
|
2196
|
+
console.log();
|
|
2197
|
+
return void 0;
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
const child = spawn("npm", ["run", "dev", "--", "--port", String(webPort)], {
|
|
2201
|
+
cwd: webDir,
|
|
2202
|
+
env: { ...process.env, ARCIE_URL: arcieUrl },
|
|
2203
|
+
stdio: "ignore",
|
|
2204
|
+
detached: false
|
|
2205
|
+
});
|
|
2206
|
+
const url = `http://localhost:${webPort}`;
|
|
2207
|
+
const ready = await waitForHttp(url, 45e3);
|
|
2208
|
+
if (!ready) {
|
|
2209
|
+
console.log();
|
|
2210
|
+
console.log(` ${grey("\u26A0")} channels/web didn't come up within 45s`);
|
|
2211
|
+
child.kill();
|
|
2212
|
+
return void 0;
|
|
2213
|
+
}
|
|
2214
|
+
return { url, process: child };
|
|
2215
|
+
}
|
|
2097
2216
|
async function devCommand(options) {
|
|
2098
2217
|
const agentDirPath = resolve(process.cwd(), options.agentDir);
|
|
2099
2218
|
const requestedPort = parseInt(options.port, 10);
|
|
2219
|
+
const streamTurn = async (res, body, agentId) => {
|
|
2220
|
+
try {
|
|
2221
|
+
const { message, stream } = JSON.parse(body);
|
|
2222
|
+
if (typeof message !== "string" || message.length === 0) {
|
|
2223
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2224
|
+
res.end(JSON.stringify({ error: "message is required" }));
|
|
2225
|
+
return;
|
|
2226
|
+
}
|
|
2227
|
+
if (stream) {
|
|
2228
|
+
res.writeHead(200, {
|
|
2229
|
+
"Content-Type": "application/x-ndjson",
|
|
2230
|
+
"Cache-Control": "no-cache",
|
|
2231
|
+
Connection: "keep-alive"
|
|
2232
|
+
});
|
|
2233
|
+
const runOpts = agentId !== void 0 ? { agentId } : {};
|
|
2234
|
+
for await (const event of streamAgent(agentDirPath, message, runOpts)) {
|
|
2235
|
+
res.write(JSON.stringify(event) + "\n");
|
|
2236
|
+
}
|
|
2237
|
+
res.end();
|
|
2238
|
+
} else {
|
|
2239
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2240
|
+
const runOpts = agentId !== void 0 ? { agentId } : {};
|
|
2241
|
+
for await (const _event of streamAgent(agentDirPath, message, runOpts)) {
|
|
2242
|
+
}
|
|
2243
|
+
res.end(JSON.stringify({ status: "ok" }));
|
|
2244
|
+
}
|
|
2245
|
+
} catch (err) {
|
|
2246
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2247
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
const listAgents = async () => {
|
|
2251
|
+
const discovered = discoverAgents(agentDirPath);
|
|
2252
|
+
const summaries = await Promise.all(
|
|
2253
|
+
discovered.map(async ({ id }) => {
|
|
2254
|
+
try {
|
|
2255
|
+
const loaded = await loadAgentById(agentDirPath, id);
|
|
2256
|
+
const { config } = loaded.manifest;
|
|
2257
|
+
return {
|
|
2258
|
+
id,
|
|
2259
|
+
name: config.name ?? id,
|
|
2260
|
+
model: config.model,
|
|
2261
|
+
description: config.description ?? ""
|
|
2262
|
+
};
|
|
2263
|
+
} catch {
|
|
2264
|
+
return { id, name: id, model: "", description: "" };
|
|
2265
|
+
}
|
|
2266
|
+
})
|
|
2267
|
+
);
|
|
2268
|
+
return summaries;
|
|
2269
|
+
};
|
|
2100
2270
|
const server = createServer(async (req, res) => {
|
|
2101
|
-
if (await handleSessionsRequest(req, res))
|
|
2271
|
+
if (await handleSessionsRequest(req, res)) return;
|
|
2272
|
+
const method = req.method ?? "GET";
|
|
2273
|
+
const url = req.url ?? "/";
|
|
2274
|
+
if (method === "GET" && url === "/agents") {
|
|
2275
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2276
|
+
res.end(JSON.stringify(await listAgents()));
|
|
2102
2277
|
return;
|
|
2103
2278
|
}
|
|
2104
|
-
|
|
2279
|
+
const agentsMatch = url.match(/^\/agents\/([^/?]+)(?:\?.*)?$/);
|
|
2280
|
+
if (method === "POST" && agentsMatch !== null) {
|
|
2105
2281
|
let body = "";
|
|
2106
2282
|
for await (const chunk of req) body += chunk;
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
if (stream) {
|
|
2110
|
-
res.writeHead(200, {
|
|
2111
|
-
"Content-Type": "application/x-ndjson",
|
|
2112
|
-
"Cache-Control": "no-cache",
|
|
2113
|
-
Connection: "keep-alive"
|
|
2114
|
-
});
|
|
2115
|
-
for await (const event of streamAgent(agentDirPath, message)) {
|
|
2116
|
-
res.write(JSON.stringify(event) + "\n");
|
|
2117
|
-
}
|
|
2118
|
-
res.end();
|
|
2119
|
-
} else {
|
|
2120
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2121
|
-
for await (const _event of streamAgent(agentDirPath, message)) {
|
|
2122
|
-
}
|
|
2123
|
-
res.end(JSON.stringify({ status: "ok" }));
|
|
2124
|
-
}
|
|
2125
|
-
} catch (err) {
|
|
2126
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2127
|
-
res.end(JSON.stringify({ error: String(err) }));
|
|
2128
|
-
}
|
|
2129
|
-
} else {
|
|
2130
|
-
res.writeHead(404);
|
|
2131
|
-
res.end("Not found");
|
|
2283
|
+
await streamTurn(res, body, decodeURIComponent(agentsMatch[1]));
|
|
2284
|
+
return;
|
|
2132
2285
|
}
|
|
2286
|
+
if (method === "POST" && url === "/") {
|
|
2287
|
+
let body = "";
|
|
2288
|
+
for await (const chunk of req) body += chunk;
|
|
2289
|
+
await streamTurn(res, body, void 0);
|
|
2290
|
+
return;
|
|
2291
|
+
}
|
|
2292
|
+
res.writeHead(404);
|
|
2293
|
+
res.end("Not found");
|
|
2133
2294
|
});
|
|
2134
2295
|
let boundPort;
|
|
2135
2296
|
try {
|
|
@@ -2166,25 +2327,50 @@ async function devCommand(options) {
|
|
|
2166
2327
|
);
|
|
2167
2328
|
console.log();
|
|
2168
2329
|
}
|
|
2169
|
-
console.log(` ${dimmed(`http://localhost:${boundPort}`)}`);
|
|
2170
|
-
console.log();
|
|
2171
|
-
console.log(` ${dimmed(`$ curl -X POST http://localhost:${boundPort} \\`)}`);
|
|
2172
|
-
console.log(` ${dimmed(` -H "Content-Type: application/json" \\`)}`);
|
|
2173
|
-
console.log(` ${dimmed(` -d '{"message": "hello"}'`)}`);
|
|
2174
|
-
console.log();
|
|
2330
|
+
console.log(` ${dimmed(`agent http://localhost:${boundPort}`)}`);
|
|
2175
2331
|
const missing = checkProviderKeys(agent.manifest.config.model);
|
|
2176
2332
|
if (missing.length > 0) {
|
|
2333
|
+
console.log();
|
|
2177
2334
|
console.log(` ${grey("\u26A0")} Missing API keys: ${missing.join(", ")}`);
|
|
2178
2335
|
console.log(` ${dimmed(" Set them in .env.local or your environment")}`);
|
|
2179
|
-
console.log();
|
|
2180
2336
|
}
|
|
2181
2337
|
} catch {
|
|
2182
2338
|
console.log(` ${agentDirPath}`);
|
|
2183
2339
|
console.log();
|
|
2184
|
-
console.log(` ${dimmed(`http://localhost:${boundPort}`)}`);
|
|
2185
|
-
|
|
2340
|
+
console.log(` ${dimmed(`agent http://localhost:${boundPort}`)}`);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
let webChannel;
|
|
2344
|
+
if (!options.input && options.noWeb !== true) {
|
|
2345
|
+
const webDir = join2(agentDirPath, "channels", "web");
|
|
2346
|
+
if (existsSync2(webDir)) {
|
|
2347
|
+
try {
|
|
2348
|
+
const webPort = await findFreePort(3001);
|
|
2349
|
+
console.log(` ${dimmed(`web starting on http://localhost:${webPort}\u2026`)}`);
|
|
2350
|
+
webChannel = await startWebChannel(agentDirPath, `http://localhost:${boundPort}`, webPort);
|
|
2351
|
+
if (webChannel !== void 0) {
|
|
2352
|
+
console.log(` ${dimmed(`web http://localhost:${webPort}`)}`);
|
|
2353
|
+
if (options.noOpen !== true) openBrowser(webChannel.url);
|
|
2354
|
+
}
|
|
2355
|
+
} catch (err) {
|
|
2356
|
+
console.log(
|
|
2357
|
+
` ${grey("\u26A0")} could not start web channel: ${err instanceof Error ? err.message : String(err)}`
|
|
2358
|
+
);
|
|
2359
|
+
}
|
|
2186
2360
|
}
|
|
2187
2361
|
}
|
|
2362
|
+
if (!options.input) {
|
|
2363
|
+
console.log();
|
|
2364
|
+
console.log(` ${dimmed("Ctrl+C to stop")}`);
|
|
2365
|
+
console.log();
|
|
2366
|
+
}
|
|
2367
|
+
const shutdown = () => {
|
|
2368
|
+
if (webChannel !== void 0) webChannel.process.kill();
|
|
2369
|
+
server.close();
|
|
2370
|
+
process.exit(0);
|
|
2371
|
+
};
|
|
2372
|
+
process.once("SIGINT", shutdown);
|
|
2373
|
+
process.once("SIGTERM", shutdown);
|
|
2188
2374
|
if (options.input) {
|
|
2189
2375
|
void startBlockChat({ agentDir: agentDirPath });
|
|
2190
2376
|
}
|
|
@@ -2192,4 +2378,4 @@ async function devCommand(options) {
|
|
|
2192
2378
|
export {
|
|
2193
2379
|
devCommand
|
|
2194
2380
|
};
|
|
2195
|
-
//# sourceMappingURL=dev-
|
|
2381
|
+
//# sourceMappingURL=dev-XBXOVOVE.js.map
|