@lazyingart/agintiflow 0.6.0 → 0.8.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 +22 -8
- package/docs/agent-runtime-pipe.md +14 -0
- package/package.json +6 -2
- package/public/app.js +40 -5
- package/public/index.html +4 -1
- package/public/styles.css +22 -0
- package/scripts/setup-agent-toolchain-docker.sh +13 -1
- package/scripts/smoke-capabilities.js +4 -0
- package/scripts/smoke-cli-chat.js +76 -0
- package/scripts/smoke-inbox.js +36 -0
- package/scripts/smoke-web-api.js +3 -0
- package/src/agent-runner.js +47 -5
- package/src/capabilities.js +10 -1
- package/src/cli.js +77 -5
- package/src/command-policy.js +33 -9
- package/src/config.js +6 -6
- package/src/docker-sandbox.js +79 -6
- package/src/interactive-cli.js +241 -0
- package/src/model-client.js +3 -1
- package/src/session-store.js +29 -0
- package/src/task-profiles.js +1 -1
- package/src/web-db.js +8 -5
- package/web.js +25 -3
package/src/model-client.js
CHANGED
|
@@ -146,7 +146,7 @@ export async function createPlan(client, config, state) {
|
|
|
146
146
|
state.startUrl ? `Suggested start URL: ${state.startUrl}` : "",
|
|
147
147
|
config.allowedDomains.length > 0 ? `Allowed domains: ${config.allowedDomains.join(", ")}` : "",
|
|
148
148
|
config.allowShellTool
|
|
149
|
-
? `Shell tool is enabled in ${config.commandCwd}. In Docker, this path is mounted as /workspace. Use relative paths or /workspace paths, not absolute host temp paths. Sandbox mode: ${config.sandboxMode}. Package install policy: ${config.packageInstallPolicy}. For npm/pip/conda/venv setup, explain the need and wait for approval unless policy is allow.`
|
|
149
|
+
? `Shell tool is enabled in ${config.commandCwd}. In Docker, this path is mounted as /workspace with persistent /aginti-env and /aginti-cache mounts. Use relative paths or /workspace paths, not absolute host temp paths. Sandbox mode: ${config.sandboxMode}. Package install policy: ${config.packageInstallPolicy}. For npm/pip/conda/venv setup, explain the need and wait for approval unless policy is allow.`
|
|
150
150
|
: "",
|
|
151
151
|
config.allowFileTools
|
|
152
152
|
? `Workspace file tools are enabled in ${config.commandCwd}: list_files, read_file, search_files, write_file, apply_patch. Keep all paths workspace-relative, for example plot_fx.svg or docs/report.tex, and avoid secrets.`
|
|
@@ -159,6 +159,8 @@ export async function createPlan(client, config, state) {
|
|
|
159
159
|
"Work like a practical coding agent: inspect when useful, edit with file tools, run safe checks when they add confidence, and keep outputs inside the workspace.",
|
|
160
160
|
"Use the canvas tunnel for outputs the user would likely want to inspect visually, such as figures, PDFs, screenshots, images, important markdown, or generated files.",
|
|
161
161
|
"For environment or system-maintenance work, prefer project-local dry-run plans/scripts unless the configured policy explicitly allows stronger actions.",
|
|
162
|
+
"Docker language/toolchain installs should prefer /aginti-env or project files so they persist across runs; apt/apk changes are ephemeral unless the image is rebuilt.",
|
|
163
|
+
"If the run is close to the max-step limit, finish with the best complete artifact and honest limitations instead of starting a new approach.",
|
|
162
164
|
"Plan for a complete result, not endless exploration; finish once the request is satisfied and checks have passed or been honestly skipped.",
|
|
163
165
|
"Return a numbered plan only.",
|
|
164
166
|
]
|
package/src/session-store.js
CHANGED
|
@@ -10,6 +10,7 @@ export class SessionStore {
|
|
|
10
10
|
this.statePath = path.join(this.sessionDir, "state.json");
|
|
11
11
|
this.planPath = path.join(this.sessionDir, "plan.md");
|
|
12
12
|
this.eventsPath = path.join(this.sessionDir, "events.jsonl");
|
|
13
|
+
this.inboxPath = path.join(this.sessionDir, "inbox.jsonl");
|
|
13
14
|
this.storageStatePath = path.join(this.sessionDir, "storage-state.json");
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -59,6 +60,34 @@ export class SessionStore {
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
async appendInbox(content, metadata = {}) {
|
|
64
|
+
await this.ensure();
|
|
65
|
+
const text = String(content || "").trim();
|
|
66
|
+
if (!text) return;
|
|
67
|
+
const line = JSON.stringify({
|
|
68
|
+
timestamp: new Date().toISOString(),
|
|
69
|
+
content: text,
|
|
70
|
+
...metadata,
|
|
71
|
+
});
|
|
72
|
+
await fs.appendFile(this.inboxPath, `${line}\n`, "utf8");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async drainInbox() {
|
|
76
|
+
await this.ensure();
|
|
77
|
+
let raw = "";
|
|
78
|
+
try {
|
|
79
|
+
raw = await fs.readFile(this.inboxPath, "utf8");
|
|
80
|
+
} catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
await fs.writeFile(this.inboxPath, "", "utf8");
|
|
84
|
+
return raw
|
|
85
|
+
.split("\n")
|
|
86
|
+
.map((line) => line.trim())
|
|
87
|
+
.filter(Boolean)
|
|
88
|
+
.map((line) => JSON.parse(line));
|
|
89
|
+
}
|
|
90
|
+
|
|
62
91
|
async saveSnapshot(step, snapshot) {
|
|
63
92
|
await this.ensure();
|
|
64
93
|
const filename = `step-${String(step).padStart(3, "0")}.snapshot.json`;
|
package/src/task-profiles.js
CHANGED
|
@@ -66,7 +66,7 @@ export const TASK_PROFILES = {
|
|
|
66
66
|
id: "latex",
|
|
67
67
|
label: "LaTeX",
|
|
68
68
|
prompt:
|
|
69
|
-
"For LaTeX/PDF tasks, create source and figures in a subfolder, compile when a TeX toolchain is available, and send the PDF through the canvas tunnel.",
|
|
69
|
+
"For LaTeX/PDF tasks, create source and figures in a subfolder, compile when a TeX toolchain is available, and send the PDF through the canvas tunnel. In Docker, use /workspace for project outputs and the persistent Python/conda/tool cache under /aginti-env when setup is needed.",
|
|
70
70
|
tools: ["files", "shell", "canvas", "sandbox"],
|
|
71
71
|
},
|
|
72
72
|
maintenance: {
|
package/src/web-db.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { DatabaseSync } from "node:sqlite";
|
|
4
4
|
import { getModelPresets } from "./model-routing.js";
|
|
5
5
|
|
|
6
|
-
const PREFERENCES_SCHEMA_VERSION =
|
|
6
|
+
const PREFERENCES_SCHEMA_VERSION = 4;
|
|
7
7
|
|
|
8
8
|
function defaultPreferences(baseDir) {
|
|
9
9
|
const presets = getModelPresets();
|
|
@@ -13,7 +13,7 @@ function defaultPreferences(baseDir) {
|
|
|
13
13
|
provider: "deepseek",
|
|
14
14
|
model: presets.fast.model,
|
|
15
15
|
headless: true,
|
|
16
|
-
maxSteps:
|
|
16
|
+
maxSteps: 24,
|
|
17
17
|
startUrl: "",
|
|
18
18
|
allowedDomains: "",
|
|
19
19
|
commandCwd: path.resolve(baseDir),
|
|
@@ -23,7 +23,7 @@ function defaultPreferences(baseDir) {
|
|
|
23
23
|
preferredWrapper: "codex",
|
|
24
24
|
wrapperTimeoutMs: 120000,
|
|
25
25
|
sandboxMode: "docker-workspace",
|
|
26
|
-
packageInstallPolicy: "
|
|
26
|
+
packageInstallPolicy: "allow",
|
|
27
27
|
useDockerSandbox: true,
|
|
28
28
|
dockerSandboxImage: "agintiflow-sandbox:latest",
|
|
29
29
|
allowPasswords: false,
|
|
@@ -89,8 +89,11 @@ export class WebDatabase {
|
|
|
89
89
|
preferences.sandboxMode = "docker-workspace";
|
|
90
90
|
preferences.useDockerSandbox = true;
|
|
91
91
|
}
|
|
92
|
-
if (parsed.packageInstallPolicy
|
|
93
|
-
preferences.packageInstallPolicy = "
|
|
92
|
+
if ((parsed.packageInstallPolicy || "") !== "allow") {
|
|
93
|
+
preferences.packageInstallPolicy = "allow";
|
|
94
|
+
}
|
|
95
|
+
if (!Number.isFinite(Number(parsed.maxSteps)) || Number(parsed.maxSteps) < 24) {
|
|
96
|
+
preferences.maxSteps = 24;
|
|
94
97
|
}
|
|
95
98
|
this.savePreferences(preferences);
|
|
96
99
|
}
|
package/web.js
CHANGED
|
@@ -130,7 +130,7 @@ function normalizePreferencePayload(body = {}, current = db.getPreferences()) {
|
|
|
130
130
|
? providerDefaults.model
|
|
131
131
|
: current.model || modelPresets.fast.model || providerDefaults.model,
|
|
132
132
|
headless: typeof body.headless === "boolean" ? body.headless : Boolean(current.headless),
|
|
133
|
-
maxSteps: Number.isFinite(parsedMaxSteps) && parsedMaxSteps > 0 ? parsedMaxSteps : Number(current.maxSteps) ||
|
|
133
|
+
maxSteps: Number.isFinite(parsedMaxSteps) && parsedMaxSteps > 0 ? parsedMaxSteps : Number(current.maxSteps) || 24,
|
|
134
134
|
startUrl: typeof body.startUrl === "string" ? body.startUrl.trim() : current.startUrl || "",
|
|
135
135
|
allowedDomains:
|
|
136
136
|
typeof body.allowedDomains === "string" ? body.allowedDomains.trim() : current.allowedDomains || "",
|
|
@@ -156,7 +156,7 @@ function normalizePreferencePayload(body = {}, current = db.getPreferences()) {
|
|
|
156
156
|
: Boolean(current.useDockerSandbox),
|
|
157
157
|
sandboxMode,
|
|
158
158
|
packageInstallPolicy: normalizePackageInstallPolicy(
|
|
159
|
-
body.packageInstallPolicy || current.packageInstallPolicy || "prompt"
|
|
159
|
+
body.packageInstallPolicy || current.packageInstallPolicy || (sandboxMode === "host" ? "prompt" : "allow")
|
|
160
160
|
),
|
|
161
161
|
dockerSandboxImage:
|
|
162
162
|
typeof body.dockerSandboxImage === "string" && body.dockerSandboxImage.trim()
|
|
@@ -519,7 +519,7 @@ app.get("/api/config", async (_req, res) => {
|
|
|
519
519
|
deepseek: publicProviderDefault("deepseek"),
|
|
520
520
|
mock: publicProviderDefault("mock"),
|
|
521
521
|
headless: true,
|
|
522
|
-
maxSteps:
|
|
522
|
+
maxSteps: 24,
|
|
523
523
|
},
|
|
524
524
|
taskProfiles: listTaskProfiles(),
|
|
525
525
|
routing: {
|
|
@@ -768,6 +768,28 @@ app.post("/api/sessions/:sessionId/messages", async (req, res) => {
|
|
|
768
768
|
return;
|
|
769
769
|
}
|
|
770
770
|
|
|
771
|
+
if (!isSafeSessionId(sessionId)) {
|
|
772
|
+
res.status(400).json({ error: "Invalid session id." });
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
const active = runs.get(sessionId);
|
|
777
|
+
if (active?.status === "running") {
|
|
778
|
+
const store = sessionStore(sessionId);
|
|
779
|
+
await store.appendInbox(content, { source: "web" });
|
|
780
|
+
await store.appendEvent("conversation.queued_input", { prompt: content, source: "web" }).catch(() => {});
|
|
781
|
+
active.logs.push({
|
|
782
|
+
at: new Date().toISOString(),
|
|
783
|
+
kind: "event",
|
|
784
|
+
message: "conversation.queued_input",
|
|
785
|
+
data: { prompt: content, source: "web" },
|
|
786
|
+
});
|
|
787
|
+
active.updatedAt = new Date().toISOString();
|
|
788
|
+
db.upsertSession(active);
|
|
789
|
+
res.json({ sessionId, queued: true });
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
|
|
771
793
|
try {
|
|
772
794
|
await ensureNotRunning(sessionId);
|
|
773
795
|
} catch (error) {
|