@lazyingart/agintiflow 0.8.3 → 0.8.4
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 +3 -1
- package/package.json +1 -1
- package/scripts/smoke-cli-chat.js +22 -13
- package/src/cli.js +14 -9
- package/src/interactive-cli.js +70 -7
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ aginti
|
|
|
54
54
|
aginti chat
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
Inside chat, type normal requests such as `write a small Python CLI app with tests`. The default is now Docker workspace mode with approved package installs, so coding, plotting, and LaTeX tasks can set up project-local tools without touching the host. Use `/help` for commands, `/latex on` for PDF work, `/docker off` only when you intentionally want host mode, `/sessions` to list project runs, and `/resume <session-id>` to continue work. Ctrl+C exits cleanly
|
|
57
|
+
Inside chat, type normal requests such as `write a small Python CLI app with tests`. The default is now Docker workspace mode with approved package installs, so coding, plotting, and LaTeX tasks can set up project-local tools without touching the host. Use `/help` for commands, `/latex on` for PDF work, `/docker off` only when you intentionally want host mode, `/sessions` to list project runs, and `/resume latest` or `/resume <session-id>` to continue work. Ctrl+C exits cleanly, prints the active resume command when a session exists, and lists recent sessions when no new session has started yet.
|
|
58
58
|
|
|
59
59
|
Launch the local web UI from an installed package:
|
|
60
60
|
|
|
@@ -80,6 +80,8 @@ aginti capabilities
|
|
|
80
80
|
aginti doctor --capabilities
|
|
81
81
|
aginti sessions list
|
|
82
82
|
aginti sessions show <session-id>
|
|
83
|
+
aginti resume
|
|
84
|
+
aginti resume latest
|
|
83
85
|
aginti resume <session-id> "continue with a short follow-up"
|
|
84
86
|
aginti queue <session-id> "extra instruction for the running agent"
|
|
85
87
|
aginti --profile code "write a small Python CLI app with tests"
|
package/package.json
CHANGED
|
@@ -10,19 +10,19 @@ const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-cli-chat-")
|
|
|
10
10
|
const binPath = path.join(repoRoot, "bin/aginti-cli.js");
|
|
11
11
|
|
|
12
12
|
function runChat(inputText) {
|
|
13
|
+
return runCli(["chat", "--provider", "mock", "--routing", "manual", "--profile", "code"], inputText);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function runCli(args, inputText) {
|
|
13
17
|
return new Promise((resolve, reject) => {
|
|
14
|
-
const child = spawn(
|
|
15
|
-
|
|
16
|
-
[
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
AGINTIFLOW_RUNTIME_DIR: "",
|
|
23
|
-
},
|
|
24
|
-
}
|
|
25
|
-
);
|
|
18
|
+
const child = spawn(process.execPath, [binPath, ...args], {
|
|
19
|
+
cwd: tempRoot,
|
|
20
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
21
|
+
env: {
|
|
22
|
+
...process.env,
|
|
23
|
+
AGINTIFLOW_RUNTIME_DIR: "",
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
26
|
|
|
27
27
|
let stdout = "";
|
|
28
28
|
let stderr = "";
|
|
@@ -60,12 +60,21 @@ try {
|
|
|
60
60
|
if (!result.stdout.includes("Interactive agent chat")) {
|
|
61
61
|
throw new Error("interactive chat did not print its banner");
|
|
62
62
|
}
|
|
63
|
+
if (!result.stdout.includes("status=running workingOn=") || !result.stdout.includes("status=idle session=")) {
|
|
64
|
+
throw new Error("interactive chat did not print simple run status updates");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const latest = await runCli(["resume"], "/exit\n");
|
|
68
|
+
if (!latest.stdout.includes("session=") || !latest.stdout.includes("Interactive agent chat")) {
|
|
69
|
+
throw new Error("bare aginti resume did not open the latest session interactively");
|
|
70
|
+
}
|
|
71
|
+
|
|
63
72
|
console.log(
|
|
64
73
|
JSON.stringify(
|
|
65
74
|
{
|
|
66
75
|
ok: true,
|
|
67
76
|
projectRoot: tempRoot,
|
|
68
|
-
checks: ["interactive-chat", "mock-file-write"],
|
|
77
|
+
checks: ["interactive-chat", "mock-file-write", "run-status", "resume-latest"],
|
|
69
78
|
},
|
|
70
79
|
null,
|
|
71
80
|
2
|
package/src/cli.js
CHANGED
|
@@ -219,7 +219,7 @@ export function parseArgs(argv) {
|
|
|
219
219
|
|
|
220
220
|
function printUsage() {
|
|
221
221
|
console.log(
|
|
222
|
-
'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti resume
|
|
222
|
+
'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti resume [latest|<session-id>] ["prompt"] OR aginti queue <session-id> "message" OR aginti [--latex] [--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"'
|
|
223
223
|
);
|
|
224
224
|
}
|
|
225
225
|
|
|
@@ -356,6 +356,13 @@ async function handleSessionsCommand(argv) {
|
|
|
356
356
|
process.exit(1);
|
|
357
357
|
}
|
|
358
358
|
|
|
359
|
+
async function resolveResumeSessionId(sessionId) {
|
|
360
|
+
if (sessionId && sessionId !== "latest") return sessionId;
|
|
361
|
+
const sessions = await listProjectSessions(process.cwd(), 1);
|
|
362
|
+
if (sessions[0]?.sessionId) return sessions[0].sessionId;
|
|
363
|
+
throw new Error("No project-local sessions found. Run `aginti sessions list` to check this folder.");
|
|
364
|
+
}
|
|
365
|
+
|
|
359
366
|
async function handleQueueCommand(argv) {
|
|
360
367
|
const sessionId = argv[0] || "";
|
|
361
368
|
const content = argv.slice(1).join(" ").trim();
|
|
@@ -456,23 +463,21 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
456
463
|
}
|
|
457
464
|
|
|
458
465
|
if (argv[0] === "resume") {
|
|
459
|
-
|
|
466
|
+
let sessionId = argv[1] || "";
|
|
460
467
|
const prompt = argv.slice(2).join(" ").trim();
|
|
461
|
-
|
|
462
|
-
|
|
468
|
+
try {
|
|
469
|
+
sessionId = await resolveResumeSessionId(sessionId);
|
|
470
|
+
} catch (error) {
|
|
471
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
463
472
|
process.exit(1);
|
|
464
473
|
}
|
|
465
|
-
if (!prompt
|
|
474
|
+
if (!prompt) {
|
|
466
475
|
await startInteractiveCli(agentDefaults({ ...parseArgs([]), resume: sessionId }), {
|
|
467
476
|
packageDir,
|
|
468
477
|
packageVersion: packageJson.version,
|
|
469
478
|
});
|
|
470
479
|
return;
|
|
471
480
|
}
|
|
472
|
-
if (!prompt) {
|
|
473
|
-
console.error('Usage: aginti resume <session-id> "new prompt"');
|
|
474
|
-
process.exit(1);
|
|
475
|
-
}
|
|
476
481
|
const config = loadConfig(agentDefaults({ ...parseArgs([prompt]), resume: sessionId, goal: prompt }), { packageDir });
|
|
477
482
|
await runAgent(config);
|
|
478
483
|
return;
|
package/src/interactive-cli.js
CHANGED
|
@@ -35,6 +35,8 @@ function printStatus(state) {
|
|
|
35
35
|
console.log(`project=${process.cwd()}`);
|
|
36
36
|
console.log(`cwd=${state.commandCwd || process.cwd()}`);
|
|
37
37
|
console.log(`session=${state.sessionId || "new"}`);
|
|
38
|
+
console.log(`status=${state.status || "idle"}${state.activeGoal ? ` workingOn=${state.activeGoal}` : ""}`);
|
|
39
|
+
if (state.lastEvent) console.log(`last=${state.lastEvent}`);
|
|
38
40
|
console.log(`provider=${state.provider || "auto"} routing=${state.routingMode} model=${state.model || "auto"}`);
|
|
39
41
|
console.log(`profile=${state.taskProfile} maxSteps=${state.maxSteps}`);
|
|
40
42
|
console.log(
|
|
@@ -49,7 +51,22 @@ function isAbortError(error) {
|
|
|
49
51
|
return error?.code === "ABORT_ERR" || error?.name === "AbortError";
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
function
|
|
54
|
+
function formatSessionLine(session) {
|
|
55
|
+
const goal = session.goal ? ` ${session.goal.slice(0, 72)}` : "";
|
|
56
|
+
return `${session.sessionId} ${session.provider || "unknown"}/${session.model || "unknown"} ${session.updatedAt || ""}${goal}`.trim();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function latestSession() {
|
|
60
|
+
const sessions = await listProjectSessions(process.cwd(), 1);
|
|
61
|
+
return sessions[0] || null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function printStatusEvent(state, label, details = "") {
|
|
65
|
+
state.lastEvent = details ? `${label}: ${details}` : label;
|
|
66
|
+
console.log(`status=${state.status || "running"} ${state.lastEvent}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function printResumeHint(state) {
|
|
53
70
|
const sessionId = state.sessionId || "";
|
|
54
71
|
console.log("");
|
|
55
72
|
if (sessionId) {
|
|
@@ -58,7 +75,15 @@ function printResumeHint(state) {
|
|
|
58
75
|
console.log(`One-shot: aginti resume ${sessionId} "continue"`);
|
|
59
76
|
} else {
|
|
60
77
|
console.log("Interrupted. No active session yet.");
|
|
61
|
-
|
|
78
|
+
const sessions = await listProjectSessions(process.cwd(), 5).catch(() => []);
|
|
79
|
+
if (sessions.length > 0) {
|
|
80
|
+
console.log("Recent sessions:");
|
|
81
|
+
for (const session of sessions) console.log(` ${formatSessionLine(session)}`);
|
|
82
|
+
console.log(`Resume latest: aginti resume ${sessions[0].sessionId}`);
|
|
83
|
+
console.log("List all: aginti sessions list");
|
|
84
|
+
} else {
|
|
85
|
+
console.log("Restart: aginti");
|
|
86
|
+
}
|
|
62
87
|
}
|
|
63
88
|
}
|
|
64
89
|
|
|
@@ -101,8 +126,15 @@ async function handleCommand(line, state, packageDir) {
|
|
|
101
126
|
return true;
|
|
102
127
|
}
|
|
103
128
|
if (command === "resume") {
|
|
104
|
-
if (!value
|
|
105
|
-
|
|
129
|
+
if (!value || value === "latest") {
|
|
130
|
+
const latest = await latestSession();
|
|
131
|
+
if (!latest) {
|
|
132
|
+
console.log("No project-local sessions found. Use /new or type a request to start one.");
|
|
133
|
+
} else {
|
|
134
|
+
state.sessionId = latest.sessionId;
|
|
135
|
+
console.log(`Resuming latest ${formatSessionLine(latest)}`);
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
106
138
|
state.sessionId = value;
|
|
107
139
|
console.log(`Resuming ${state.sessionId}`);
|
|
108
140
|
}
|
|
@@ -216,8 +248,39 @@ async function runPrompt(prompt, state, packageDir) {
|
|
|
216
248
|
{ packageDir, baseDir: process.cwd() }
|
|
217
249
|
);
|
|
218
250
|
|
|
219
|
-
|
|
251
|
+
state.sessionId = config.resume || config.sessionId || state.sessionId;
|
|
252
|
+
state.status = "running";
|
|
253
|
+
state.activeGoal = prompt.replace(/\s+/g, " ").slice(0, 120);
|
|
254
|
+
state.lastEvent = "";
|
|
255
|
+
console.log(`session=${state.sessionId}`);
|
|
256
|
+
console.log(`status=running workingOn=${state.activeGoal}`);
|
|
257
|
+
|
|
258
|
+
const result = await runAgent({
|
|
259
|
+
...config,
|
|
260
|
+
onEvent: (type, data = {}) => {
|
|
261
|
+
if (type === "plan.created") {
|
|
262
|
+
printStatusEvent(state, "planned");
|
|
263
|
+
} else if (type === "tool.started") {
|
|
264
|
+
printStatusEvent(state, "tool", data.toolName || "unknown");
|
|
265
|
+
} else if (type === "tool.completed") {
|
|
266
|
+
printStatusEvent(state, "tool_done", data.toolName || "unknown");
|
|
267
|
+
} else if (type === "tool.blocked") {
|
|
268
|
+
printStatusEvent(state, "tool_blocked", data.toolName || data.reason || "unknown");
|
|
269
|
+
} else if (type === "conversation.queued_input_applied") {
|
|
270
|
+
printStatusEvent(state, "queued_input_applied");
|
|
271
|
+
} else if (type === "session.finished") {
|
|
272
|
+
printStatusEvent(state, "finished");
|
|
273
|
+
} else if (type === "session.stopped") {
|
|
274
|
+
printStatusEvent(state, "stopped", data.reason || "");
|
|
275
|
+
} else if (type === "model.responded") {
|
|
276
|
+
printStatusEvent(state, "model_responded", data.content ? data.content.slice(0, 80).replace(/\s+/g, " ") : "");
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
});
|
|
220
280
|
state.sessionId = result.sessionId || state.sessionId;
|
|
281
|
+
state.status = result.stopped ? "stopped" : "idle";
|
|
282
|
+
state.activeGoal = "";
|
|
283
|
+
console.log(`status=${state.status} session=${state.sessionId}`);
|
|
221
284
|
}
|
|
222
285
|
|
|
223
286
|
export async function startInteractiveCli(args = {}, { packageDir, packageVersion } = {}) {
|
|
@@ -237,7 +300,7 @@ export async function startInteractiveCli(args = {}, { packageDir, packageVersio
|
|
|
237
300
|
} catch (error) {
|
|
238
301
|
if (error?.code === "ERR_USE_AFTER_CLOSE") break;
|
|
239
302
|
if (isAbortError(error)) {
|
|
240
|
-
printResumeHint(state);
|
|
303
|
+
await printResumeHint(state);
|
|
241
304
|
break;
|
|
242
305
|
}
|
|
243
306
|
throw error;
|
|
@@ -254,7 +317,7 @@ export async function startInteractiveCli(args = {}, { packageDir, packageVersio
|
|
|
254
317
|
await runPrompt(line, state, packageDir);
|
|
255
318
|
} catch (error) {
|
|
256
319
|
if (isAbortError(error)) {
|
|
257
|
-
printResumeHint(state);
|
|
320
|
+
await printResumeHint(state);
|
|
258
321
|
break;
|
|
259
322
|
}
|
|
260
323
|
console.error(`error: ${error.message}`);
|