@lazyingart/agintiflow 0.10.0 → 0.11.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 +1 -1
- package/docs/large-codebase-engineering.md +26 -0
- package/package.json +1 -1
- package/public/app.js +16 -6
- package/scripts/smoke-coding-tools.js +21 -0
- package/src/agent-runner.js +6 -0
- package/src/cli.js +8 -2
- package/src/config.js +8 -2
- package/src/engineering-guidance.js +102 -0
- package/src/interactive-cli.js +9 -1
- package/src/model-client.js +3 -0
- package/src/model-routing.js +23 -0
- package/src/task-profiles.js +6 -6
- package/src/web-db.js +4 -1
package/README.md
CHANGED
|
@@ -71,7 +71,7 @@ Inside chat, type normal requests such as `write a small Python CLI app with tes
|
|
|
71
71
|
|
|
72
72
|
For code edits, AgInTiFlow routes patch/refactor/database-style tasks to DeepSeek v4 pro by default and exposes `apply_patch` as a deterministic workspace tool. It supports exact replacements, Codex-style patch envelopes, and unified diffs, with preflight checks, path guardrails, hashes, and compact per-file diffs. See [docs/patch-tools.md](docs/patch-tools.md).
|
|
73
73
|
|
|
74
|
-
For larger repositories, use `--profile large-codebase` or choose **Large codebase engineering** in the web UI.
|
|
74
|
+
For larger repositories, use `--profile large-codebase` or choose **Large codebase engineering** in the web UI. The web default stays **Auto**, and Auto now escalates codebase/system/debugging prompts to the same engineering loop when needed. Complex work routes to DeepSeek v4 pro, starts with `inspect_project`, then uses search/read/patch/check loops inspired by Codex, Copilot SDK, Claude Code, Gemini CLI, Qwen, and Claw Code. See [docs/large-codebase-engineering.md](docs/large-codebase-engineering.md).
|
|
75
75
|
|
|
76
76
|
For raster image work, AgInTiFlow has an optional `image_generation` skill backed by the `generate_image` tool and a local `GRSAI` key. The skill tells DeepSeek when image generation is appropriate; the tool calls GRS AI Nano Banana, saves manifests/images under `artifacts/images`, and sends the result to the canvas. See [docs/auxiliary-image-generation.md](docs/auxiliary-image-generation.md).
|
|
77
77
|
|
|
@@ -10,6 +10,8 @@ Local agent references informed the design:
|
|
|
10
10
|
- Copilot-style SDK surfaces: structured tools, session persistence, plan/history/workspace APIs, and explicit permission hooks.
|
|
11
11
|
- Claude/Claw-style safety: project-local status, container-first execution, read-only operations by default, and clear failure recovery.
|
|
12
12
|
- Gemini/Qwen-style extensibility: capability discovery through profiles and tools rather than hardcoding one model behavior.
|
|
13
|
+
- Claw-style `doctor` discipline: check health and environment before treating system symptoms as code bugs.
|
|
14
|
+
- Claude/Codex-style context discipline: read instructions, manifests, entry points, and failing tests before touching broad files.
|
|
13
15
|
|
|
14
16
|
## Skill vs Tool
|
|
15
17
|
|
|
@@ -47,3 +49,27 @@ aginti --profile large-codebase "fix the failing tests"
|
|
|
47
49
|
or choose **Large codebase engineering** in the web task-profile dropdown.
|
|
48
50
|
|
|
49
51
|
Smart routing sends this profile to DeepSeek v4 pro even when the user prompt is short.
|
|
52
|
+
|
|
53
|
+
## Auto Profile Behavior
|
|
54
|
+
|
|
55
|
+
The web app still defaults to **Auto**. Auto does not mean weak. When the prompt mentions a large repo, system bug, failing tests, setup, install, migration, or a known language stack, AgInTiFlow adds engineering guidance and raises the step budget automatically.
|
|
56
|
+
|
|
57
|
+
Examples:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
aginti "debug this Python project system bug and fix failing tests"
|
|
61
|
+
aginti "fix the Rust workspace build"
|
|
62
|
+
aginti "repair the Docker setup and run the Node tests"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
These route to DeepSeek v4 pro when the complexity score is high enough.
|
|
66
|
+
|
|
67
|
+
## Cross-Language Playbook
|
|
68
|
+
|
|
69
|
+
AgInTiFlow gives DeepSeek stack-specific reminders without hardcoding a solution:
|
|
70
|
+
|
|
71
|
+
- JS/TS: inspect package scripts and lockfiles, then run focused `node`, `tsc`, or test commands.
|
|
72
|
+
- Python: inspect `pyproject.toml` or requirements, prefer project-local venv/conda/Docker, then run focused pytest/module checks.
|
|
73
|
+
- Rust/Go/JVM/C/C++: inspect native manifests, format only touched files when possible, and start with narrow build/test targets.
|
|
74
|
+
- R/Stan/LaTeX: keep toolchains project-local or Docker-backed, compile from the right directory, and publish useful artifacts to canvas.
|
|
75
|
+
- System tasks: diagnose first, capture versions/logs, write reversible scripts, use Docker for installs, and avoid silent host-level changes.
|
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -775,12 +775,25 @@ function renderTaskProfiles(selected = "auto") {
|
|
|
775
775
|
taskProfileField.value = profiles.some((profile) => profile.id === selected) ? selected : "auto";
|
|
776
776
|
}
|
|
777
777
|
|
|
778
|
-
|
|
778
|
+
const COMPLEX_ENGINEERING_HINT = /\b(large|complex|complicated|monorepo|codebase|repository|repo-wide|multi[- ]file|cross[- ]file|architecture|refactor|migration|regression|root cause|failing tests?|fix build|system bug|debug|performance|security)\b/i;
|
|
779
|
+
|
|
780
|
+
function recommendedMaxStepsForProfile(profile = "auto", goal = "") {
|
|
779
781
|
if (profile === "large-codebase") return 36;
|
|
780
782
|
if (profile === "latex") return 30;
|
|
783
|
+
if (COMPLEX_ENGINEERING_HINT.test(goal || "")) return 36;
|
|
784
|
+
if (/\b(latex|tex|pdflatex|latexmk|pdf|website|app|docker|system|install|setup|debug)\b/i.test(goal || "")) return 30;
|
|
781
785
|
return 24;
|
|
782
786
|
}
|
|
783
787
|
|
|
788
|
+
function ensureRecommendedMaxStepsForCurrentTask() {
|
|
789
|
+
const maxStepsField = document.querySelector("#maxSteps");
|
|
790
|
+
const goalField = document.querySelector("#goal");
|
|
791
|
+
const recommended = recommendedMaxStepsForProfile(taskProfileField?.value || "auto", goalField?.value || "");
|
|
792
|
+
if (maxStepsField && Number(maxStepsField.value || 0) < recommended) {
|
|
793
|
+
maxStepsField.value = String(recommended);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
784
797
|
function renderWrapperStatus(wrappers = lastWrappers) {
|
|
785
798
|
lastWrappers = wrappers || [];
|
|
786
799
|
if (lastWrappers.length === 0) {
|
|
@@ -1966,11 +1979,7 @@ packageInstallPolicyField.addEventListener("change", updatePackageWarning);
|
|
|
1966
1979
|
allowWrapperToolsField.addEventListener("change", () => renderWrapperStatus());
|
|
1967
1980
|
preferredWrapperField.addEventListener("change", () => renderWrapperStatus());
|
|
1968
1981
|
taskProfileField?.addEventListener("change", () => {
|
|
1969
|
-
|
|
1970
|
-
const recommended = recommendedMaxStepsForProfile(taskProfileField.value);
|
|
1971
|
-
if (maxStepsField && Number(maxStepsField.value || 0) < recommended) {
|
|
1972
|
-
maxStepsField.value = String(recommended);
|
|
1973
|
-
}
|
|
1982
|
+
ensureRecommendedMaxStepsForCurrentTask();
|
|
1974
1983
|
schedulePreferenceSave();
|
|
1975
1984
|
});
|
|
1976
1985
|
|
|
@@ -2048,6 +2057,7 @@ form.addEventListener("submit", async (event) => {
|
|
|
2048
2057
|
setLogs(t("goalRequired"), "empty");
|
|
2049
2058
|
return;
|
|
2050
2059
|
}
|
|
2060
|
+
ensureRecommendedMaxStepsForCurrentTask();
|
|
2051
2061
|
|
|
2052
2062
|
const payload = {
|
|
2053
2063
|
...formPayload(),
|
|
@@ -5,6 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { repairModelMessageHistory, runAgent } from "../src/agent-runner.js";
|
|
7
7
|
import { resolveRuntimeConfig } from "../src/config.js";
|
|
8
|
+
import { engineeringGuidanceForTask, recommendedMaxStepsForTask } from "../src/engineering-guidance.js";
|
|
8
9
|
import { selectModelRoute } from "../src/model-routing.js";
|
|
9
10
|
import { SessionStore } from "../src/session-store.js";
|
|
10
11
|
import { executeWorkspaceTool } from "../src/workspace-tools.js";
|
|
@@ -93,6 +94,24 @@ try {
|
|
|
93
94
|
taskProfile: "large-codebase",
|
|
94
95
|
});
|
|
95
96
|
assert(/pro/i.test(largeProfileRoute.model), "large-codebase profile did not route to DeepSeek pro");
|
|
97
|
+
const autoSystemRoute = selectModelRoute({
|
|
98
|
+
routingMode: "smart",
|
|
99
|
+
provider: "deepseek",
|
|
100
|
+
goal: "debug this Python project system bug and fix failing tests",
|
|
101
|
+
taskProfile: "auto",
|
|
102
|
+
});
|
|
103
|
+
assert(/pro/i.test(autoSystemRoute.model), "auto system/code problem did not route to DeepSeek pro");
|
|
104
|
+
assert(
|
|
105
|
+
recommendedMaxStepsForTask({
|
|
106
|
+
goal: "debug this Python project system bug and fix failing tests",
|
|
107
|
+
taskProfile: "auto",
|
|
108
|
+
complexityScore: autoSystemRoute.complexityScore,
|
|
109
|
+
}) >= 36,
|
|
110
|
+
"auto system/code problem did not get engineering step budget"
|
|
111
|
+
);
|
|
112
|
+
const guidance = engineeringGuidanceForTask("debug this Python project system bug and fix failing tests", "auto");
|
|
113
|
+
assert(guidance.includes("Python:"), "engineering guidance did not include Python stack advice");
|
|
114
|
+
assert(guidance.includes("System/shell:"), "engineering guidance did not include system stack advice");
|
|
96
115
|
|
|
97
116
|
await fs.mkdir(path.join(workspace, "src"), { recursive: true });
|
|
98
117
|
await fs.mkdir(path.join(workspace, "test"), { recursive: true });
|
|
@@ -264,6 +283,8 @@ try {
|
|
|
264
283
|
"deepseek_history_repair",
|
|
265
284
|
"deepseek_pro_patch_route",
|
|
266
285
|
"large_profile_pro_route",
|
|
286
|
+
"auto_system_pro_route",
|
|
287
|
+
"auto_engineering_guidance",
|
|
267
288
|
"inspect_project",
|
|
268
289
|
"mock_inspect_project",
|
|
269
290
|
"write_file",
|
package/src/agent-runner.js
CHANGED
|
@@ -18,6 +18,7 @@ import { executeWorkspaceTool, resolveWorkspacePath, summarizeWorkspaceTools, WO
|
|
|
18
18
|
import { normalizeCanvasPayload } from "./artifact-tunnel.js";
|
|
19
19
|
import { getTaskProfile } from "./task-profiles.js";
|
|
20
20
|
import { generateImage, listAuxiliarySkills } from "./auxiliary-tools.js";
|
|
21
|
+
import { engineeringGuidanceForTask } from "./engineering-guidance.js";
|
|
21
22
|
|
|
22
23
|
const exec = promisify(execCallback);
|
|
23
24
|
const BROWSER_TOOLS = new Set(["open_url", "open_workspace_file", "preview_workspace", "click", "type", "scroll", "press", "back"]);
|
|
@@ -233,6 +234,7 @@ export function repairModelMessageHistory(state, config = {}) {
|
|
|
233
234
|
function createInitialState(config, sessionId) {
|
|
234
235
|
const now = new Date().toISOString();
|
|
235
236
|
const taskProfile = getTaskProfile(config.taskProfile);
|
|
237
|
+
const engineeringGuidance = engineeringGuidanceForTask(config.goal, config.taskProfile);
|
|
236
238
|
return {
|
|
237
239
|
sessionId,
|
|
238
240
|
createdAt: now,
|
|
@@ -283,6 +285,7 @@ function createInitialState(config, sessionId) {
|
|
|
283
285
|
.join(", ")}. Use generate_image for real raster image/photo/illustration/cover/poster/logo requests when appropriate; if the key is missing, ask the user to run /auxilliary grsai or aginti login grsai.`
|
|
284
286
|
: "Auxiliary skills are disabled for this run.",
|
|
285
287
|
`Task profile: ${taskProfile.label}. ${taskProfile.prompt}`,
|
|
288
|
+
engineeringGuidance,
|
|
286
289
|
"A frontend canvas/artifacts tunnel exists. Use send_to_canvas when important markdown, diffs, screenshots, images, or workspace files should be highlighted in the UI. It is optional and ordinary final text can still go directly to finish.",
|
|
287
290
|
"For visual-output requests such as draw, plot, graph, chart, diagram, figure, image, or visualization, proactively publish a canvas artifact even when the user does not mention canvas. If workspace file tools are enabled, prefer creating a small SVG or markdown artifact and call send_to_canvas with selected=true.",
|
|
288
291
|
"Work like a practical coding agent: orient with inspect_project/search/read, patch code with apply_patch, run safe checks when they add confidence, iterate on failures, and keep outputs inside the workspace.",
|
|
@@ -321,6 +324,7 @@ function createInitialState(config, sessionId) {
|
|
|
321
324
|
.join(" ")}`
|
|
322
325
|
: "",
|
|
323
326
|
`Task profile: ${taskProfile.label}. ${taskProfile.prompt}`,
|
|
327
|
+
engineeringGuidance,
|
|
324
328
|
"Canvas/artifacts tunnel: available through send_to_canvas for optional frontend rendering.",
|
|
325
329
|
"Visual-output requests should produce a canvas artifact without requiring the user to ask for canvas explicitly.",
|
|
326
330
|
"Use file, shell, browser, canvas, and wrapper tools when they are useful; choose the workflow from the user's request. For complicated engineering tasks, keep a tight loop: inspect, choose minimal files, patch, run focused checks, repair, then summarize.",
|
|
@@ -410,6 +414,7 @@ function applyContinuationPrompt(state, config, observers) {
|
|
|
410
414
|
if (!config.resume || !config.goal) return;
|
|
411
415
|
|
|
412
416
|
const taskProfile = getTaskProfile(config.taskProfile);
|
|
417
|
+
const engineeringGuidance = engineeringGuidanceForTask(config.goal, config.taskProfile);
|
|
413
418
|
ensureChatState(state);
|
|
414
419
|
state.goal = config.goal;
|
|
415
420
|
state.provider = config.provider;
|
|
@@ -436,6 +441,7 @@ function applyContinuationPrompt(state, config, observers) {
|
|
|
436
441
|
? `Agent wrappers: selected=${normalizeWrapperName(config.preferredWrapper)}; ${wrapperStatusText()}`
|
|
437
442
|
: "",
|
|
438
443
|
`Task profile: ${taskProfile.label}. ${taskProfile.prompt}`,
|
|
444
|
+
engineeringGuidance,
|
|
439
445
|
]
|
|
440
446
|
.filter(Boolean)
|
|
441
447
|
.join("\n"),
|
package/src/cli.js
CHANGED
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
setProviderKey,
|
|
15
15
|
showProjectSession,
|
|
16
16
|
} from "./project.js";
|
|
17
|
-
import {
|
|
17
|
+
import { listTaskProfiles } from "./task-profiles.js";
|
|
18
|
+
import { recommendedMaxStepsForTask } from "./engineering-guidance.js";
|
|
18
19
|
import { promptAndSaveDeepSeekKey, promptHidden, shouldPromptForDeepSeek } from "./auth-onboarding.js";
|
|
19
20
|
import fs from "node:fs/promises";
|
|
20
21
|
import path from "node:path";
|
|
@@ -256,7 +257,12 @@ function agentDefaults(args) {
|
|
|
256
257
|
sandboxMode: args.sandboxMode || "docker-workspace",
|
|
257
258
|
packageInstallPolicy: args.packageInstallPolicy || "allow",
|
|
258
259
|
useDockerSandbox: args.useDockerSandbox ?? true,
|
|
259
|
-
maxSteps:
|
|
260
|
+
maxSteps:
|
|
261
|
+
args.maxSteps ||
|
|
262
|
+
recommendedMaxStepsForTask({
|
|
263
|
+
goal: args.goal || "",
|
|
264
|
+
taskProfile: args.taskProfile || (args.latex ? "latex" : "auto"),
|
|
265
|
+
}),
|
|
260
266
|
};
|
|
261
267
|
|
|
262
268
|
if (defaults.sandboxMode === "host") {
|
package/src/config.js
CHANGED
|
@@ -4,7 +4,8 @@ import { getProviderDefaults, normalizeRoutingMode, selectModelRoute } from "./m
|
|
|
4
4
|
import { normalizePackageInstallPolicy, normalizeSandboxMode } from "./command-policy.js";
|
|
5
5
|
import { normalizeWrapperName } from "./tool-wrappers.js";
|
|
6
6
|
import { loadProjectEnv, resolveProjectRoot } from "./project.js";
|
|
7
|
-
import {
|
|
7
|
+
import { normalizeTaskProfile } from "./task-profiles.js";
|
|
8
|
+
import { recommendedMaxStepsForTask } from "./engineering-guidance.js";
|
|
8
9
|
|
|
9
10
|
function parseBoolean(value, fallback) {
|
|
10
11
|
if (value === undefined) return fallback;
|
|
@@ -43,6 +44,11 @@ export function resolveRuntimeConfig(args, overrides = {}) {
|
|
|
43
44
|
});
|
|
44
45
|
|
|
45
46
|
const defaults = getProviderDefaults(route.provider);
|
|
47
|
+
const defaultMaxSteps = recommendedMaxStepsForTask({
|
|
48
|
+
goal: args.goal || "",
|
|
49
|
+
taskProfile,
|
|
50
|
+
complexityScore: route.complexityScore,
|
|
51
|
+
});
|
|
46
52
|
const packageDir = path.resolve(overrides.packageDir || process.env.AGINTIFLOW_PACKAGE_DIR || baseDir);
|
|
47
53
|
const dockerRequested = parseBoolean(overrides.useDockerSandbox ?? args.useDockerSandbox ?? process.env.USE_DOCKER_SANDBOX, true);
|
|
48
54
|
const requestedSandboxMode =
|
|
@@ -67,7 +73,7 @@ export function resolveRuntimeConfig(args, overrides = {}) {
|
|
|
67
73
|
apiKey: overrides.apiKey || defaults.apiKey,
|
|
68
74
|
baseURL: overrides.baseURL || defaults.baseURL,
|
|
69
75
|
model: route.model || defaults.model,
|
|
70
|
-
maxSteps: parseNumber(overrides.maxSteps ?? args.maxSteps ?? process.env.MAX_STEPS,
|
|
76
|
+
maxSteps: parseNumber(overrides.maxSteps ?? args.maxSteps ?? process.env.MAX_STEPS, defaultMaxSteps),
|
|
71
77
|
headless: parseBoolean(overrides.headless ?? args.headless ?? process.env.HEADLESS, false),
|
|
72
78
|
allowedDomains: Array.isArray(overrides.allowedDomains)
|
|
73
79
|
? overrides.allowedDomains
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { defaultMaxStepsForProfile, normalizeTaskProfile } from "./task-profiles.js";
|
|
2
|
+
|
|
3
|
+
const LANGUAGE_HINTS = [
|
|
4
|
+
{
|
|
5
|
+
id: "javascript-typescript",
|
|
6
|
+
pattern: /\b(node|npm|pnpm|yarn|bun|javascript|typescript|react|vue|svelte|next\.?js|vite|express)\b/i,
|
|
7
|
+
text:
|
|
8
|
+
"JS/TS: inspect package.json and lockfiles, identify package manager, use npm/pnpm/yarn scripts before inventing commands, prefer targeted node --check/tsc/test runs before broad builds.",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "python",
|
|
12
|
+
pattern: /\b(python|pytest|pip|uv|poetry|conda|venv|jupyter|fastapi|django|flask|pandas|numpy)\b/i,
|
|
13
|
+
text:
|
|
14
|
+
"Python: inspect pyproject/requirements, prefer project-local venv/uv/conda or Docker, run python -m pytest or focused module checks, avoid global package installs on host.",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "rust",
|
|
18
|
+
pattern: /\b(rust|cargo|crate|clippy|rustfmt|tokio|actix)\b/i,
|
|
19
|
+
text:
|
|
20
|
+
"Rust: inspect Cargo.toml/workspace crates, run cargo fmt/check/test on the narrowest crate first, preserve Cargo.lock discipline, avoid broad workspace runs until focused checks pass.",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "go",
|
|
24
|
+
pattern: /\b(golang|go test|go mod|goroutine|gin|grpc)\b/i,
|
|
25
|
+
text:
|
|
26
|
+
"Go: inspect go.mod, use go test ./pkg-or-target first, run gofmt on touched files, avoid changing module paths unless required.",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "java-jvm",
|
|
30
|
+
pattern: /\b(java|kotlin|gradle|maven|spring|junit|jvm)\b/i,
|
|
31
|
+
text:
|
|
32
|
+
"JVM: inspect pom.xml/build.gradle/settings.gradle, use focused Maven/Gradle test targets, keep generated build outputs out of source patches.",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "c-cpp",
|
|
36
|
+
pattern: /\b(c\+\+|cpp|cmake|makefile|gcc|clang|native|segfault|asan|valgrind)\b/i,
|
|
37
|
+
text:
|
|
38
|
+
"C/C++: inspect CMake/Make/build scripts, prefer out-of-tree builds, run compile-only or narrow tests first, use sanitizers only when available and safe.",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "shell-system",
|
|
42
|
+
pattern: /\b(shell|bash|zsh|system|systemd|docker|linux|ubuntu|debian|apt|yum|dnf|brew|service|permission denied|port|network)\b/i,
|
|
43
|
+
text:
|
|
44
|
+
"System/shell: diagnose first with read-only commands, capture versions/logs, make reversible scripts, use Docker for installs/toolchains, and only use host-level changes when policy explicitly allows them.",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "r-stats",
|
|
48
|
+
pattern: /\b(rstats|r language|cmdstanr|stan|renv|tidyverse|shiny)\b/i,
|
|
49
|
+
text:
|
|
50
|
+
"R/Stan: inspect renv/DESCRIPTION and project notes, prefer project-local libraries or Docker, validate scripts with non-interactive Rscript commands when available.",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "latex",
|
|
54
|
+
pattern: /\b(latex|tex|pdflatex|latexmk|bibtex|biber|pdf)\b/i,
|
|
55
|
+
text:
|
|
56
|
+
"LaTeX: keep source/figures together, compile from the document directory, run enough passes for refs/bibliography, publish PDF/source artifacts to canvas.",
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
const COMPLEX_ENGINEERING_PATTERN =
|
|
61
|
+
/\b(large|complex|complicated|monorepo|codebase|repository|repo-wide|multi[- ]file|cross[- ]file|architecture|refactor|migration|regression|root cause|failing tests?|fix build|system bug|debug|performance|security)\b/i;
|
|
62
|
+
|
|
63
|
+
export function engineeringGuidanceForTask(goal = "", taskProfile = "auto") {
|
|
64
|
+
const normalizedProfile = normalizeTaskProfile(taskProfile);
|
|
65
|
+
const text = String(goal || "");
|
|
66
|
+
const matched = LANGUAGE_HINTS.filter((hint) => hint.pattern.test(text));
|
|
67
|
+
const wantsComplex =
|
|
68
|
+
normalizedProfile === "large-codebase" ||
|
|
69
|
+
normalizedProfile === "maintenance" ||
|
|
70
|
+
COMPLEX_ENGINEERING_PATTERN.test(text) ||
|
|
71
|
+
text.length > 500;
|
|
72
|
+
|
|
73
|
+
if (!wantsComplex && matched.length === 0) return "";
|
|
74
|
+
|
|
75
|
+
const lines = [
|
|
76
|
+
"Engineering operating mode:",
|
|
77
|
+
"Use the proven coding-agent loop: inspect_project, read instructions/manifests, search exact symbols/errors, patch small coherent batches, run focused checks, repair failures, then summarize changed files and residual risks.",
|
|
78
|
+
"Keep CLI and web behavior equivalent: use the same workspace, sessions, profiles, file tools, shell policy, Docker mounts, and canvas artifacts.",
|
|
79
|
+
"For large repositories, preserve context by reading fewer but more relevant files; prefer deterministic tools and diffs over long model memory.",
|
|
80
|
+
"For system repair, act like a doctor: gather evidence first, avoid silent destructive host changes, prefer Docker or project-local scripts for installs, and make every stronger action explicit in logs.",
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
if (matched.length > 0) {
|
|
84
|
+
lines.push("Stack-specific checks:");
|
|
85
|
+
for (const hint of matched.slice(0, 5)) lines.push(`- ${hint.text}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function recommendedMaxStepsForTask({ goal = "", taskProfile = "auto", complexityScore = 0 } = {}) {
|
|
92
|
+
const normalizedProfile = normalizeTaskProfile(taskProfile);
|
|
93
|
+
const profileDefault = defaultMaxStepsForProfile(normalizedProfile);
|
|
94
|
+
const text = String(goal || "");
|
|
95
|
+
if (normalizedProfile === "large-codebase" || complexityScore >= 3 || COMPLEX_ENGINEERING_PATTERN.test(text)) {
|
|
96
|
+
return Math.max(profileDefault, 36);
|
|
97
|
+
}
|
|
98
|
+
if (/\b(latex|tex|pdflatex|latexmk|pdf|website|app|docker|system|install|setup|debug)\b/i.test(text)) {
|
|
99
|
+
return Math.max(profileDefault, 30);
|
|
100
|
+
}
|
|
101
|
+
return profileDefault;
|
|
102
|
+
}
|
package/src/interactive-cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { loadConfig } from "./config.js";
|
|
|
6
6
|
import { initProject, listProjectSessions, providerKeyStatus, setProviderKey } from "./project.js";
|
|
7
7
|
import { normalizePackageInstallPolicy, normalizeSandboxMode } from "./command-policy.js";
|
|
8
8
|
import { defaultMaxStepsForProfile, normalizeTaskProfile } from "./task-profiles.js";
|
|
9
|
+
import { recommendedMaxStepsForTask } from "./engineering-guidance.js";
|
|
9
10
|
import { promptAndSaveDeepSeekKey, promptHidden, shouldPromptForDeepSeek } from "./auth-onboarding.js";
|
|
10
11
|
|
|
11
12
|
const useColor = Boolean(input.isTTY && output.isTTY && process.env.AGINTIFLOW_NO_COLOR !== "1");
|
|
@@ -673,6 +674,13 @@ async function handleCommand(line, state, packageDir) {
|
|
|
673
674
|
|
|
674
675
|
async function runPrompt(prompt, state, packageDir) {
|
|
675
676
|
const controller = new AbortController();
|
|
677
|
+
const runMaxSteps = Math.max(
|
|
678
|
+
state.maxSteps,
|
|
679
|
+
recommendedMaxStepsForTask({
|
|
680
|
+
goal: prompt,
|
|
681
|
+
taskProfile: state.taskProfile,
|
|
682
|
+
})
|
|
683
|
+
);
|
|
676
684
|
const config = loadConfig(
|
|
677
685
|
{
|
|
678
686
|
provider: state.provider,
|
|
@@ -688,7 +696,7 @@ async function runPrompt(prompt, state, packageDir) {
|
|
|
688
696
|
allowDestructive: state.allowDestructive,
|
|
689
697
|
preferredWrapper: state.preferredWrapper,
|
|
690
698
|
taskProfile: state.taskProfile,
|
|
691
|
-
maxSteps:
|
|
699
|
+
maxSteps: runMaxSteps,
|
|
692
700
|
headless: state.headless,
|
|
693
701
|
resume: state.sessionId,
|
|
694
702
|
goal: prompt,
|
package/src/model-client.js
CHANGED
|
@@ -2,6 +2,7 @@ import OpenAI from "openai";
|
|
|
2
2
|
import { normalizeWrapperName, wrapperStatusText } from "./tool-wrappers.js";
|
|
3
3
|
import { getTaskProfile } from "./task-profiles.js";
|
|
4
4
|
import { listAuxiliarySkills } from "./auxiliary-tools.js";
|
|
5
|
+
import { engineeringGuidanceForTask } from "./engineering-guidance.js";
|
|
5
6
|
|
|
6
7
|
export function createClient(config) {
|
|
7
8
|
if (config.provider === "mock") {
|
|
@@ -173,6 +174,7 @@ function mockChatResponse(content, toolCalls = []) {
|
|
|
173
174
|
|
|
174
175
|
export async function createPlan(client, config, state) {
|
|
175
176
|
const taskProfile = getTaskProfile(config.taskProfile);
|
|
177
|
+
const engineeringGuidance = engineeringGuidanceForTask(state.goal, config.taskProfile);
|
|
176
178
|
if (client.mock) {
|
|
177
179
|
return [
|
|
178
180
|
"1. Inspect the request and prefer the local shell when available.",
|
|
@@ -212,6 +214,7 @@ export async function createPlan(client, config, state) {
|
|
|
212
214
|
.join(", ")}. For raster image generation requests, plan to use generate_image when a GRSAI key is available; otherwise ask the user to run /auxilliary grsai or aginti login grsai.`
|
|
213
215
|
: "Auxiliary skills are disabled for this run.",
|
|
214
216
|
`Task profile: ${taskProfile.label}. ${taskProfile.prompt}`,
|
|
217
|
+
engineeringGuidance,
|
|
215
218
|
"A canvas/artifacts tunnel is available through send_to_canvas. Use it when an output should be highlighted visually, such as screenshots, image files, important markdown, diffs, or generated artifact paths. It is optional for ordinary text answers.",
|
|
216
219
|
"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.",
|
|
217
220
|
"For large apps, websites, LaTeX documents, Python/C/shell projects, or system tasks, plan a coherent minimal implementation, then use tools to create files, run checks, and publish artifacts.",
|
package/src/model-routing.js
CHANGED
|
@@ -29,12 +29,35 @@ const COMPLEXITY_KEYWORDS = [
|
|
|
29
29
|
"docker",
|
|
30
30
|
"ci",
|
|
31
31
|
"github",
|
|
32
|
+
"system",
|
|
33
|
+
"systemd",
|
|
34
|
+
"permission denied",
|
|
35
|
+
"install",
|
|
36
|
+
"setup",
|
|
37
|
+
"toolchain",
|
|
38
|
+
"conda",
|
|
39
|
+
"venv",
|
|
40
|
+
"kubernetes",
|
|
41
|
+
"nginx",
|
|
42
|
+
"postgres",
|
|
43
|
+
"redis",
|
|
44
|
+
"segfault",
|
|
45
|
+
"typescript",
|
|
46
|
+
"python",
|
|
47
|
+
"rust",
|
|
48
|
+
"cargo",
|
|
49
|
+
"golang",
|
|
50
|
+
"cmake",
|
|
51
|
+
"gradle",
|
|
52
|
+
"maven",
|
|
32
53
|
];
|
|
33
54
|
|
|
34
55
|
const COMPLEX_ROUTE_HINTS = [
|
|
35
56
|
/\b(large|big|complex|complicated)\s+(repo|repository|codebase|project|task)\b/i,
|
|
36
57
|
/\b(multi[- ]file|cross[- ]file|repo[- ]wide|workspace[- ]wide)\b/i,
|
|
37
58
|
/\b(root cause|regression|failing tests?|fix the build|make it pass)\b/i,
|
|
59
|
+
/\b(system bug|system problem|permission denied|service failed|daemon|systemd|toolchain|install|setup)\b/i,
|
|
60
|
+
/\b(conda|venv|python|node|typescript|rust|cargo|golang|java|gradle|maven|cmake|c\+\+)\b.*\b(project|app|tests?|build|compile|fix)\b/i,
|
|
38
61
|
/\blatex\b/i,
|
|
39
62
|
/\btexlive\b/i,
|
|
40
63
|
/\bpdflatex\b/i,
|
package/src/task-profiles.js
CHANGED
|
@@ -3,15 +3,15 @@ export const TASK_PROFILES = {
|
|
|
3
3
|
id: "auto",
|
|
4
4
|
label: "Auto",
|
|
5
5
|
prompt:
|
|
6
|
-
"Infer the task type from the user request.
|
|
7
|
-
tools: ["browser", "shell", "files", "canvas"],
|
|
6
|
+
"Infer the task type from the user request. For short tasks, use the smallest safe tool sequence that completes the work. For codebase, system, debugging, migration, or multi-language tasks, switch into the engineering loop: inspect, read/search exact context, patch incrementally, run focused checks, repair failures, and summarize changed files plus residual risks.",
|
|
7
|
+
tools: ["browser", "shell", "files", "canvas", "inspect_project"],
|
|
8
8
|
},
|
|
9
9
|
code: {
|
|
10
10
|
id: "code",
|
|
11
11
|
label: "Code writing",
|
|
12
12
|
prompt:
|
|
13
|
-
"Act like a coding agent:
|
|
14
|
-
tools: ["files", "shell", "sandbox"],
|
|
13
|
+
"Act like a coding agent across languages: inspect project manifests and conventions, edit workspace files with patches, run useful focused checks, iterate on failures, and report changed files and residual risks.",
|
|
14
|
+
tools: ["inspect_project", "files", "shell", "sandbox"],
|
|
15
15
|
},
|
|
16
16
|
"large-codebase": {
|
|
17
17
|
id: "large-codebase",
|
|
@@ -87,8 +87,8 @@ export const TASK_PROFILES = {
|
|
|
87
87
|
id: "maintenance",
|
|
88
88
|
label: "System maintenance",
|
|
89
89
|
prompt:
|
|
90
|
-
"For system maintenance, diagnose first, use Docker for broad installs when available,
|
|
91
|
-
tools: ["shell", "sandbox", "files"],
|
|
90
|
+
"For system maintenance and system bugs, diagnose first with read-only evidence, use Docker for broad installs/toolchains when available, generate reversible project-local scripts, follow the configured trust/package policy for host-level changes, and stop with clear next actions if stronger permission is needed.",
|
|
91
|
+
tools: ["shell", "sandbox", "files", "inspect_project"],
|
|
92
92
|
},
|
|
93
93
|
};
|
|
94
94
|
|
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 = 5;
|
|
7
7
|
|
|
8
8
|
function defaultPreferences(baseDir) {
|
|
9
9
|
const presets = getModelPresets();
|
|
@@ -95,6 +95,9 @@ export class WebDatabase {
|
|
|
95
95
|
if (!Number.isFinite(Number(parsed.maxSteps)) || Number(parsed.maxSteps) < 24) {
|
|
96
96
|
preferences.maxSteps = 24;
|
|
97
97
|
}
|
|
98
|
+
if ((parsed.preferencesSchemaVersion || 1) < 5) {
|
|
99
|
+
preferences.taskProfile = "auto";
|
|
100
|
+
}
|
|
98
101
|
this.savePreferences(preferences);
|
|
99
102
|
}
|
|
100
103
|
return preferences;
|