@lazyingart/agintiflow 0.6.0 → 0.7.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 +13 -3
- package/package.json +4 -2
- package/scripts/smoke-cli-chat.js +76 -0
- package/src/agent-runner.js +10 -0
- package/src/cli.js +39 -5
- package/src/interactive-cli.js +225 -0
package/README.md
CHANGED
|
@@ -46,6 +46,16 @@ aginti --list-profiles
|
|
|
46
46
|
aginti --sandbox-status --sandbox-mode docker-readonly
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
Start an interactive Codex-style CLI chat from any project folder:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
aginti
|
|
53
|
+
# or explicitly:
|
|
54
|
+
aginti chat
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Inside chat, type normal requests such as `write a small Python CLI app with tests`. Use `/help` for commands, `/docker on` to switch to Docker workspace mode with approved package installs, `/sessions` to list project runs, and `/resume <session-id>` to continue work.
|
|
58
|
+
|
|
49
59
|
Launch the local web UI from an installed package:
|
|
50
60
|
|
|
51
61
|
```bash
|
|
@@ -71,8 +81,8 @@ aginti doctor --capabilities
|
|
|
71
81
|
aginti sessions list
|
|
72
82
|
aginti sessions show <session-id>
|
|
73
83
|
aginti resume <session-id> "continue with a short follow-up"
|
|
74
|
-
aginti --profile code
|
|
75
|
-
aginti --
|
|
84
|
+
aginti --profile code "write a small Python CLI app with tests"
|
|
85
|
+
aginti --sandbox-mode docker-workspace --approve-package-installs "set up this project and run the tests"
|
|
76
86
|
```
|
|
77
87
|
|
|
78
88
|
Run from a source checkout:
|
|
@@ -324,7 +334,7 @@ Package policy values:
|
|
|
324
334
|
| `prompt` | Return a clear approval-required error; the UI can switch to approved. |
|
|
325
335
|
| `allow` | Permit package/setup commands. Docker workspace mode also allows broader shell/network commands while keeping secrets and npm publishing blocked. |
|
|
326
336
|
|
|
327
|
-
Toolchain commands such as `python3 plot.py`, `latexmk -pdf paper.tex`, and `pdflatex -interaction=nonstopmode -halt-on-error paper.tex` are allowlisted only when the shell tool is enabled. In Docker mode
|
|
337
|
+
Toolchain commands such as `python3 plot.py`, `latexmk -pdf paper.tex`, and `pdflatex -interaction=nonstopmode -halt-on-error paper.tex` are allowlisted only when the shell tool is enabled. In Docker mode the project folder is mounted as `/workspace`; any file written to `/workspace/report.pdf` appears on the host as `<your-project>/report.pdf`. CLI runs print both the host workspace and the Docker mapping before execution. File and canvas tools accept both normal relative paths and Docker virtual paths like `/workspace/report.pdf`, while other absolute host paths remain blocked.
|
|
328
338
|
|
|
329
339
|
Safe preflight endpoints:
|
|
330
340
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a resumable Playwright website-control agent with OpenAI-compatible tool calling.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"scripts/install-docker-ubuntu.sh",
|
|
42
42
|
"scripts/setup-agent-toolchain-docker.sh",
|
|
43
43
|
"scripts/real-deepseek-capabilities.js",
|
|
44
|
+
"scripts/smoke-cli-chat.js",
|
|
44
45
|
"scripts/smoke-coding-tools.js",
|
|
45
46
|
"scripts/smoke-capabilities.js",
|
|
46
47
|
"scripts/smoke-toolchain-docker.js",
|
|
@@ -59,10 +60,11 @@
|
|
|
59
60
|
"check": "node --check run.js && node --check web.js && node --check bin/aginti-cli.js && node --check src/*.js",
|
|
60
61
|
"setup:toolchain-docker": "scripts/setup-agent-toolchain-docker.sh",
|
|
61
62
|
"smoke:coding-tools": "node scripts/smoke-coding-tools.js",
|
|
63
|
+
"smoke:cli-chat": "node scripts/smoke-cli-chat.js",
|
|
62
64
|
"smoke:toolchain-docker": "node scripts/smoke-toolchain-docker.js",
|
|
63
65
|
"smoke:web-api": "node scripts/smoke-web-api.js",
|
|
64
66
|
"real:deepseek": "node scripts/real-deepseek-capabilities.js",
|
|
65
|
-
"test": "npm run check && npm run smoke:web-api && npm run smoke:coding-tools && npm run smoke:capabilities",
|
|
67
|
+
"test": "npm run check && npm run smoke:web-api && npm run smoke:coding-tools && npm run smoke:capabilities && npm run smoke:cli-chat",
|
|
66
68
|
"pack:dry-run": "npm pack --dry-run",
|
|
67
69
|
"smoke:capabilities": "node scripts/smoke-capabilities.js"
|
|
68
70
|
},
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-cli-chat-"));
|
|
10
|
+
const binPath = path.join(repoRoot, "bin/aginti-cli.js");
|
|
11
|
+
|
|
12
|
+
function runChat(inputText) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const child = spawn(
|
|
15
|
+
process.execPath,
|
|
16
|
+
[binPath, "chat", "--provider", "mock", "--routing", "manual", "--profile", "code"],
|
|
17
|
+
{
|
|
18
|
+
cwd: tempRoot,
|
|
19
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
20
|
+
env: {
|
|
21
|
+
...process.env,
|
|
22
|
+
AGINTIFLOW_RUNTIME_DIR: "",
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
let stdout = "";
|
|
28
|
+
let stderr = "";
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
child.kill("SIGTERM");
|
|
31
|
+
reject(new Error("interactive chat smoke timed out"));
|
|
32
|
+
}, 25000);
|
|
33
|
+
|
|
34
|
+
child.stdout.on("data", (chunk) => {
|
|
35
|
+
stdout += String(chunk);
|
|
36
|
+
});
|
|
37
|
+
child.stderr.on("data", (chunk) => {
|
|
38
|
+
stderr += String(chunk);
|
|
39
|
+
});
|
|
40
|
+
child.on("error", (error) => {
|
|
41
|
+
clearTimeout(timer);
|
|
42
|
+
reject(error);
|
|
43
|
+
});
|
|
44
|
+
child.on("close", (code) => {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
if (code === 0) resolve({ stdout, stderr });
|
|
47
|
+
else reject(new Error(`interactive chat exited ${code}\n${stdout}\n${stderr}`));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
child.stdin.end(inputText);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const result = await runChat("Create notes/interactive.md with a short CLI chat smoke message\n/exit\n");
|
|
56
|
+
const written = await fs.readFile(path.join(tempRoot, "notes/interactive.md"), "utf8");
|
|
57
|
+
if (!written.includes("Created by AgInTiFlow mock mode.")) {
|
|
58
|
+
throw new Error("interactive chat did not create the expected file");
|
|
59
|
+
}
|
|
60
|
+
if (!result.stdout.includes("Interactive agent chat")) {
|
|
61
|
+
throw new Error("interactive chat did not print its banner");
|
|
62
|
+
}
|
|
63
|
+
console.log(
|
|
64
|
+
JSON.stringify(
|
|
65
|
+
{
|
|
66
|
+
ok: true,
|
|
67
|
+
projectRoot: tempRoot,
|
|
68
|
+
checks: ["interactive-chat", "mock-file-write"],
|
|
69
|
+
},
|
|
70
|
+
null,
|
|
71
|
+
2
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
} finally {
|
|
75
|
+
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
76
|
+
}
|
package/src/agent-runner.js
CHANGED
|
@@ -791,6 +791,16 @@ export async function runAgent(config) {
|
|
|
791
791
|
console.log(`Provider: ${config.provider}`);
|
|
792
792
|
console.log(`Model: ${config.model}`);
|
|
793
793
|
console.log(`Routing: ${config.routingMode} (${config.routeReason})`);
|
|
794
|
+
console.log(`Workspace: ${config.commandCwd}`);
|
|
795
|
+
console.log(`Sessions: ${config.sessionsDir}`);
|
|
796
|
+
if (config.useDockerSandbox) {
|
|
797
|
+
console.log(
|
|
798
|
+
`Docker: image=${config.dockerSandboxImage} mode=${config.sandboxMode} packagePolicy=${config.packageInstallPolicy}`
|
|
799
|
+
);
|
|
800
|
+
console.log(`Docker workspace: /workspace -> ${config.commandCwd}`);
|
|
801
|
+
} else if (config.allowShellTool) {
|
|
802
|
+
console.log(`Shell: host policy=${config.packageInstallPolicy}`);
|
|
803
|
+
}
|
|
794
804
|
if (state.plan) {
|
|
795
805
|
console.log("\nPlan:");
|
|
796
806
|
console.log(state.plan);
|
package/src/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import { listAgentWrappers } from "./tool-wrappers.js";
|
|
|
4
4
|
import { getModelPresets } from "./model-routing.js";
|
|
5
5
|
import { getDockerSandboxStatus, runDockerPreflight } from "./docker-sandbox.js";
|
|
6
6
|
import { buildCapabilityReport, printCapabilityReport } from "./capabilities.js";
|
|
7
|
+
import { startInteractiveCli } from "./interactive-cli.js";
|
|
7
8
|
import {
|
|
8
9
|
doctorReport,
|
|
9
10
|
initProject,
|
|
@@ -52,6 +53,7 @@ export function parseArgs(argv) {
|
|
|
52
53
|
sandboxStatus: false,
|
|
53
54
|
sandboxPreflight: false,
|
|
54
55
|
web: false,
|
|
56
|
+
interactive: false,
|
|
55
57
|
port: "",
|
|
56
58
|
host: "",
|
|
57
59
|
listProfiles: false,
|
|
@@ -64,6 +66,10 @@ export function parseArgs(argv) {
|
|
|
64
66
|
result.web = true;
|
|
65
67
|
continue;
|
|
66
68
|
}
|
|
69
|
+
if (arg === "chat" || arg === "interactive" || arg === "--chat" || arg === "--interactive") {
|
|
70
|
+
result.interactive = true;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
67
73
|
if (arg === "--port") {
|
|
68
74
|
result.port = readOption(argv, i);
|
|
69
75
|
i += 1;
|
|
@@ -133,6 +139,10 @@ export function parseArgs(argv) {
|
|
|
133
139
|
result.allowShellTool = true;
|
|
134
140
|
continue;
|
|
135
141
|
}
|
|
142
|
+
if (arg === "--no-shell") {
|
|
143
|
+
result.allowShellTool = false;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
136
146
|
if (arg === "--allow-destructive" || arg === "--trusted-host-shell") {
|
|
137
147
|
result.allowDestructive = true;
|
|
138
148
|
continue;
|
|
@@ -197,6 +207,12 @@ export function parseArgs(argv) {
|
|
|
197
207
|
return result;
|
|
198
208
|
}
|
|
199
209
|
|
|
210
|
+
function printUsage() {
|
|
211
|
+
console.log(
|
|
212
|
+
'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti [--routing smart|fast|complex|manual] [--provider deepseek|openai|mock] [--sandbox-mode host|docker-readonly|docker-workspace] [--package-install-policy block|prompt|allow] [--approve-package-installs] [--allow-shell|--no-shell] [--allow-destructive] [--allow-file-tools|--no-file-tools] [--allow-wrappers --wrapper codex] [--sandbox-status|--sandbox-preflight] "your task"'
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
200
216
|
function printRoutes() {
|
|
201
217
|
const presets = getModelPresets();
|
|
202
218
|
for (const preset of Object.values(presets)) {
|
|
@@ -312,6 +328,11 @@ async function handleSessionsCommand(argv) {
|
|
|
312
328
|
}
|
|
313
329
|
|
|
314
330
|
export async function main(argv = process.argv.slice(2)) {
|
|
331
|
+
if (argv[0] === "--help" || argv[0] === "help" || argv[0] === "-h") {
|
|
332
|
+
printUsage();
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
315
336
|
if (argv[0] === "--version" || argv[0] === "version" || argv[0] === "-v") {
|
|
316
337
|
console.log(packageJson.version);
|
|
317
338
|
return;
|
|
@@ -393,13 +414,21 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
393
414
|
console.error('Usage: aginti resume <session-id> "new prompt"');
|
|
394
415
|
process.exit(1);
|
|
395
416
|
}
|
|
396
|
-
const config = loadConfig(
|
|
417
|
+
const config = loadConfig(
|
|
418
|
+
{ ...parseArgs([prompt]), resume: sessionId, goal: prompt, allowShellTool: true, allowFileTools: true },
|
|
419
|
+
{ packageDir }
|
|
420
|
+
);
|
|
397
421
|
await runAgent(config);
|
|
398
422
|
return;
|
|
399
423
|
}
|
|
400
424
|
|
|
401
425
|
const args = parseArgs(argv);
|
|
402
426
|
|
|
427
|
+
if (args.interactive || (!args.goal && !args.resume && process.stdin.isTTY)) {
|
|
428
|
+
await startInteractiveCli(args, { packageDir, packageVersion: packageJson.version });
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
403
432
|
if (args.web) {
|
|
404
433
|
if (args.port) process.env.PORT = String(args.port);
|
|
405
434
|
if (args.host) process.env.HOST = String(args.host);
|
|
@@ -433,12 +462,17 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
433
462
|
}
|
|
434
463
|
|
|
435
464
|
if (!args.goal && !args.resume) {
|
|
436
|
-
|
|
437
|
-
'Usage: aginti-cli web [--port 3210] OR aginti-cli [--routing smart|fast|complex|manual] [--provider deepseek|openai|mock] [--sandbox-mode host|docker-readonly|docker-workspace] [--package-install-policy block|prompt|allow] [--approve-package-installs] [--allow-shell] [--allow-destructive] [--allow-file-tools|--no-file-tools] [--allow-wrappers --wrapper codex] [--sandbox-status|--sandbox-preflight] "your task"'
|
|
438
|
-
);
|
|
465
|
+
printUsage();
|
|
439
466
|
process.exit(1);
|
|
440
467
|
}
|
|
441
468
|
|
|
442
|
-
const config = loadConfig(
|
|
469
|
+
const config = loadConfig(
|
|
470
|
+
{
|
|
471
|
+
...args,
|
|
472
|
+
allowShellTool: args.allowShellTool ?? true,
|
|
473
|
+
allowFileTools: args.allowFileTools ?? true,
|
|
474
|
+
},
|
|
475
|
+
{ packageDir }
|
|
476
|
+
);
|
|
443
477
|
await runAgent(config);
|
|
444
478
|
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import readline from "node:readline/promises";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
import { runAgent } from "./agent-runner.js";
|
|
4
|
+
import { loadConfig } from "./config.js";
|
|
5
|
+
import { initProject, listProjectSessions } from "./project.js";
|
|
6
|
+
import { normalizePackageInstallPolicy, normalizeSandboxMode } from "./command-policy.js";
|
|
7
|
+
import { normalizeTaskProfile } from "./task-profiles.js";
|
|
8
|
+
|
|
9
|
+
function printHelp() {
|
|
10
|
+
console.log(
|
|
11
|
+
[
|
|
12
|
+
"Commands:",
|
|
13
|
+
" /help Show this help.",
|
|
14
|
+
" /status Show active route, workspace, sandbox, and session.",
|
|
15
|
+
" /new Start a fresh session on the next message.",
|
|
16
|
+
" /resume <session-id> Continue a saved session.",
|
|
17
|
+
" /sessions List recent sessions in this project.",
|
|
18
|
+
" /profile <name> Set task profile, e.g. code, website, latex, maintenance.",
|
|
19
|
+
" /routing <mode> Set routing: smart, fast, complex, manual.",
|
|
20
|
+
" /provider <name> Set provider: deepseek, openai, mock.",
|
|
21
|
+
" /model <name> Set an explicit model, or /model auto.",
|
|
22
|
+
" /docker on Use docker-workspace with approved package installs.",
|
|
23
|
+
" /docker off Use host shell policy.",
|
|
24
|
+
" /installs block|prompt|allow",
|
|
25
|
+
" /cwd <path> Change command workspace.",
|
|
26
|
+
" /exit Quit.",
|
|
27
|
+
"",
|
|
28
|
+
"Type a normal request to run the agent. Example: write a Python CLI app with tests",
|
|
29
|
+
].join("\n")
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function printStatus(state) {
|
|
34
|
+
console.log(`project=${process.cwd()}`);
|
|
35
|
+
console.log(`cwd=${state.commandCwd || process.cwd()}`);
|
|
36
|
+
console.log(`session=${state.sessionId || "new"}`);
|
|
37
|
+
console.log(`provider=${state.provider || "auto"} routing=${state.routingMode} model=${state.model || "auto"}`);
|
|
38
|
+
console.log(`profile=${state.taskProfile} maxSteps=${state.maxSteps}`);
|
|
39
|
+
console.log(
|
|
40
|
+
`shell=${state.allowShellTool} files=${state.allowFileTools} sandbox=${state.sandboxMode} installs=${state.packageInstallPolicy}`
|
|
41
|
+
);
|
|
42
|
+
if (state.sandboxMode !== "host") {
|
|
43
|
+
console.log(`dockerWorkspace=/workspace -> ${state.commandCwd || process.cwd()}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function createState(args = {}) {
|
|
48
|
+
return {
|
|
49
|
+
provider: args.provider || "",
|
|
50
|
+
model: args.model || "",
|
|
51
|
+
routingMode: args.routingMode || "smart",
|
|
52
|
+
commandCwd: args.commandCwd || process.cwd(),
|
|
53
|
+
sandboxMode: normalizeSandboxMode(args.sandboxMode || "host"),
|
|
54
|
+
packageInstallPolicy: normalizePackageInstallPolicy(args.packageInstallPolicy || "prompt"),
|
|
55
|
+
allowShellTool: args.allowShellTool ?? true,
|
|
56
|
+
allowFileTools: args.allowFileTools ?? true,
|
|
57
|
+
allowWrapperTools: args.allowWrapperTools ?? false,
|
|
58
|
+
allowDestructive: args.allowDestructive ?? false,
|
|
59
|
+
preferredWrapper: args.preferredWrapper || "codex",
|
|
60
|
+
taskProfile: normalizeTaskProfile(args.taskProfile || "auto"),
|
|
61
|
+
headless: args.headless ?? false,
|
|
62
|
+
maxSteps: Number.isFinite(args.maxSteps) && args.maxSteps > 0 ? args.maxSteps : 15,
|
|
63
|
+
sessionId: args.resume || "",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function handleCommand(line, state, packageDir) {
|
|
68
|
+
const [command, ...rest] = line.slice(1).trim().split(/\s+/);
|
|
69
|
+
const value = rest.join(" ").trim();
|
|
70
|
+
|
|
71
|
+
if (!command || command === "help" || command === "?") {
|
|
72
|
+
printHelp();
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
if (command === "exit" || command === "quit" || command === "q") return false;
|
|
76
|
+
if (command === "status") {
|
|
77
|
+
printStatus(state);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (command === "new") {
|
|
81
|
+
state.sessionId = "";
|
|
82
|
+
console.log("Next message will start a new session.");
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
if (command === "resume") {
|
|
86
|
+
if (!value) console.log("Usage: /resume <session-id>");
|
|
87
|
+
else {
|
|
88
|
+
state.sessionId = value;
|
|
89
|
+
console.log(`Resuming ${state.sessionId}`);
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
if (command === "sessions") {
|
|
94
|
+
const sessions = await listProjectSessions(process.cwd(), 20);
|
|
95
|
+
if (sessions.length === 0) console.log("No project-local sessions found.");
|
|
96
|
+
else {
|
|
97
|
+
for (const session of sessions) {
|
|
98
|
+
const goal = session.goal ? ` ${session.goal.slice(0, 80)}` : "";
|
|
99
|
+
console.log(`${session.sessionId} ${session.provider}/${session.model} ${session.updatedAt}${goal}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
if (command === "profile") {
|
|
105
|
+
state.taskProfile = normalizeTaskProfile(value || "auto");
|
|
106
|
+
console.log(`profile=${state.taskProfile}`);
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (command === "routing") {
|
|
110
|
+
state.routingMode = value || "smart";
|
|
111
|
+
console.log(`routing=${state.routingMode}`);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
if (command === "provider") {
|
|
115
|
+
state.provider = value === "auto" ? "" : value;
|
|
116
|
+
console.log(`provider=${state.provider || "auto"}`);
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (command === "model") {
|
|
120
|
+
state.model = value === "auto" ? "" : value;
|
|
121
|
+
console.log(`model=${state.model || "auto"}`);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
if (command === "installs") {
|
|
125
|
+
state.packageInstallPolicy = normalizePackageInstallPolicy(value || "prompt");
|
|
126
|
+
console.log(`installs=${state.packageInstallPolicy}`);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
if (command === "docker") {
|
|
130
|
+
if (value === "on") {
|
|
131
|
+
state.sandboxMode = "docker-workspace";
|
|
132
|
+
state.packageInstallPolicy = "allow";
|
|
133
|
+
console.log(`docker=on /workspace -> ${state.commandCwd || process.cwd()} installs=allow`);
|
|
134
|
+
} else if (value === "off") {
|
|
135
|
+
state.sandboxMode = "host";
|
|
136
|
+
state.packageInstallPolicy = "prompt";
|
|
137
|
+
console.log("docker=off sandbox=host installs=prompt");
|
|
138
|
+
} else {
|
|
139
|
+
console.log("Usage: /docker on OR /docker off");
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
if (command === "cwd") {
|
|
144
|
+
state.commandCwd = value || process.cwd();
|
|
145
|
+
console.log(`cwd=${state.commandCwd}`);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
if (command === "init") {
|
|
149
|
+
const result = await initProject(process.cwd());
|
|
150
|
+
console.log(`initialized project=${result.projectRoot}`);
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
if (command === "web") {
|
|
154
|
+
const port = value || "3220";
|
|
155
|
+
console.log(`Run in another terminal: aginti web --port ${port}`);
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
console.log(`Unknown command: /${command}. Use /help.`);
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function runPrompt(prompt, state, packageDir) {
|
|
164
|
+
const config = loadConfig(
|
|
165
|
+
{
|
|
166
|
+
provider: state.provider,
|
|
167
|
+
model: state.model,
|
|
168
|
+
routingMode: state.routingMode,
|
|
169
|
+
commandCwd: state.commandCwd,
|
|
170
|
+
sandboxMode: state.sandboxMode,
|
|
171
|
+
packageInstallPolicy: state.packageInstallPolicy,
|
|
172
|
+
allowShellTool: state.allowShellTool,
|
|
173
|
+
allowFileTools: state.allowFileTools,
|
|
174
|
+
allowWrapperTools: state.allowWrapperTools,
|
|
175
|
+
allowDestructive: state.allowDestructive,
|
|
176
|
+
preferredWrapper: state.preferredWrapper,
|
|
177
|
+
taskProfile: state.taskProfile,
|
|
178
|
+
maxSteps: state.maxSteps,
|
|
179
|
+
headless: state.headless,
|
|
180
|
+
resume: state.sessionId,
|
|
181
|
+
goal: prompt,
|
|
182
|
+
},
|
|
183
|
+
{ packageDir, baseDir: process.cwd() }
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const result = await runAgent(config);
|
|
187
|
+
state.sessionId = result.sessionId || state.sessionId;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export async function startInteractiveCli(args = {}, { packageDir, packageVersion } = {}) {
|
|
191
|
+
const state = createState(args);
|
|
192
|
+
const rl = readline.createInterface({ input, output, terminal: Boolean(input.isTTY && output.isTTY) });
|
|
193
|
+
|
|
194
|
+
console.log(`AgInTiFlow ${packageVersion || ""}`.trim());
|
|
195
|
+
console.log(`Project: ${process.cwd()}`);
|
|
196
|
+
console.log("Interactive agent chat. Type /help for commands, /exit to quit.");
|
|
197
|
+
printStatus(state);
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
while (true) {
|
|
201
|
+
let answer = "";
|
|
202
|
+
try {
|
|
203
|
+
answer = await rl.question("\naginti> ");
|
|
204
|
+
} catch (error) {
|
|
205
|
+
if (error?.code === "ERR_USE_AFTER_CLOSE") break;
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
const line = answer.trim();
|
|
209
|
+
if (!line) continue;
|
|
210
|
+
if (line.startsWith("/")) {
|
|
211
|
+
const keepGoing = await handleCommand(line, state, packageDir);
|
|
212
|
+
if (!keepGoing) break;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
await runPrompt(line, state, packageDir);
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error(`error: ${error.message}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} finally {
|
|
223
|
+
rl.close();
|
|
224
|
+
}
|
|
225
|
+
}
|