@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 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. This 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).
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.10.0",
3
+ "version": "0.11.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",
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
- function recommendedMaxStepsForProfile(profile = "auto") {
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
- const maxStepsField = document.querySelector("#maxSteps");
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",
@@ -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 { defaultMaxStepsForProfile, listTaskProfiles } from "./task-profiles.js";
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: args.maxSteps || defaultMaxStepsForProfile(args.taskProfile || (args.latex ? "latex" : "auto")),
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 { defaultMaxStepsForProfile, normalizeTaskProfile } from "./task-profiles.js";
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, defaultMaxStepsForProfile(taskProfile)),
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
+ }
@@ -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: state.maxSteps,
699
+ maxSteps: runMaxSteps,
692
700
  headless: state.headless,
693
701
  resume: state.sessionId,
694
702
  goal: prompt,
@@ -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.",
@@ -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,
@@ -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. Prefer the smallest safe tool sequence that actually completes the work, preserve workspace files, run useful checks, and summarize what changed.",
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: understand the request, edit workspace files, run useful safe checks, iterate on failures, and report changed files and residual risks.",
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, and follow the configured trust/package policy for host-level changes.",
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 = 4;
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;