@lazyingart/agintiflow 0.20.57 → 0.20.59
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 +47 -0
- package/docs/runtime-modes-and-autonomy.md +29 -0
- package/package.json +1 -1
- package/scripts/smoke-capabilities.js +34 -0
- package/src/agent-runner.js +2 -0
- package/src/auth-onboarding.js +3 -1
- package/src/behavior-contract.js +290 -0
- package/src/cli.js +76 -45
- package/src/interactive-cli.js +22 -5
- package/src/model-client.js +2 -1
- package/src/project.js +7 -31
- package/src/scs-controller.js +9 -5
package/README.md
CHANGED
|
@@ -47,6 +47,7 @@ Most agent tools are either a chat box with hidden state or an expensive one-mod
|
|
|
47
47
|
| --- | --- |
|
|
48
48
|
| Cheap intelligence changes the architecture | DeepSeek V4 Flash and Pro make it practical to spend more calls on routing, scouting, review, and recovery instead of forcing one expensive call to do everything. |
|
|
49
49
|
| Inspectable beats mysterious | Plans, tool calls, file diffs, command output, canvas artifacts, and session events are saved and resumable. |
|
|
50
|
+
| Disciplined by default | `AGINTI.md` starts with a behavior contract: surface ambiguity, keep edits surgical, avoid speculative complexity, verify outcomes, and respect permission blockers. |
|
|
50
51
|
| Role-based models | Route, main, spare, wrapper, and auxiliary image roles are separate. You can use cheap route models, stronger main models, optional OpenAI/Qwen/Venice routes, and GRS AI/Venice image tools. |
|
|
51
52
|
| Scouts before big work | Parallel scouts can cheaply map architecture, tests, risks, symbols, and integration points before the main executor edits anything. |
|
|
52
53
|
| SCS for high-risk work | Student-Committee-Supervisor mode adds a typed gate: committee drafts, student approves/monitors, supervisor executes. Use `/scs` or `--scs auto`. |
|
|
@@ -64,6 +65,19 @@ aginti init
|
|
|
64
65
|
aginti
|
|
65
66
|
```
|
|
66
67
|
|
|
68
|
+
`aginti init` creates a disciplined `AGINTI.md` by default: project identity, ambiguity protocol, surgical-change policy, verification contract, permission policy, artifact naming, commands, style, and definition of done. For a smaller or domain-specific starting point:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
aginti init --list-templates
|
|
72
|
+
aginti init --template minimal
|
|
73
|
+
aginti init --template coding
|
|
74
|
+
aginti init --template research
|
|
75
|
+
aginti init --template writing
|
|
76
|
+
aginti init --template design
|
|
77
|
+
aginti init --template aaps
|
|
78
|
+
aginti init --template supervision
|
|
79
|
+
```
|
|
80
|
+
|
|
67
81
|
On first interactive use, AgInTiFlow opens an auth wizard if no main model key is found. Pick DeepSeek, OpenAI, Qwen, or Venice, paste the key, and it saves to the ignored project-local `.aginti/.env` file with restricted permissions. You can rerun setup any time:
|
|
68
82
|
|
|
69
83
|
```bash
|
|
@@ -73,6 +87,16 @@ aginti auth venice
|
|
|
73
87
|
aginti login grsai
|
|
74
88
|
```
|
|
75
89
|
|
|
90
|
+
Provider signup and key pages:
|
|
91
|
+
|
|
92
|
+
| Provider | Register / key page | API base URL used by AgInTiFlow |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| DeepSeek | [https://platform.deepseek.com/api_keys](https://platform.deepseek.com/api_keys) | `https://api.deepseek.com` |
|
|
95
|
+
| Venice | [https://venice.ai/settings/api](https://venice.ai/settings/api) | `https://api.venice.ai/api/v1` |
|
|
96
|
+
| OpenAI | [https://platform.openai.com/api-keys](https://platform.openai.com/api-keys) | `https://api.openai.com/v1` |
|
|
97
|
+
| Qwen / DashScope | [https://bailian.console.aliyun.com/](https://bailian.console.aliyun.com/) | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1` |
|
|
98
|
+
| GRS AI image tools | [https://grsai.ai/dashboard/api-keys](https://grsai.ai/dashboard/api-keys) | Configure with `/auxiliary grsai` or `aginti login grsai` |
|
|
99
|
+
|
|
76
100
|
Launch the web UI from the same project:
|
|
77
101
|
|
|
78
102
|
```bash
|
|
@@ -135,6 +159,29 @@ aginti --resume <session-id> \
|
|
|
135
159
|
|
|
136
160
|
Permission behavior is intentionally consistent: writes inside the current project are allowed through file tools, network/setup runs are normal in approved Docker workspace mode, and outside-project or trusted-host actions stop with a clear blocker plus a suggested rerun command. See [runtime modes and autonomy](docs/runtime-modes-and-autonomy.md) for the full contract.
|
|
137
161
|
|
|
162
|
+
## Permission Recipes
|
|
163
|
+
|
|
164
|
+
Use these when you want explicit control instead of the default interactive policy:
|
|
165
|
+
|
|
166
|
+
| Mode | Command | What it permits |
|
|
167
|
+
| --- | --- | --- |
|
|
168
|
+
| Strict inspection | `aginti --sandbox-mode docker-readonly --package-install-policy block --allow-shell --no-file-tools --no-web-search "inspect this project without edits"` | Enforced read-only project inspection through shell commands such as `ls`, `rg`, `cat`, and test commands that do not write. No file-tool writes, web calls, workspace writes, or installs. |
|
|
169
|
+
| Full write in current folder | `aginti --sandbox-mode docker-workspace --package-install-policy allow --approve-package-installs --allow-shell --allow-file-tools "build and test this project"` | Read/write inside the current project folder, run network/setup commands in Docker, keep host safer. |
|
|
170
|
+
| Full host computer access | `aginti --sandbox-mode host --package-install-policy allow --approve-package-installs --allow-shell --allow-file-tools --allow-destructive "perform the trusted host maintenance task"` | Direct host shell and destructive actions. Use only when you trust the task and want whole-host access. |
|
|
171
|
+
|
|
172
|
+
For resume:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
aginti --resume <session-id> \
|
|
176
|
+
--sandbox-mode host \
|
|
177
|
+
--package-install-policy allow \
|
|
178
|
+
--approve-package-installs \
|
|
179
|
+
--allow-shell \
|
|
180
|
+
--allow-file-tools \
|
|
181
|
+
--allow-destructive \
|
|
182
|
+
"continue with trusted host access"
|
|
183
|
+
```
|
|
184
|
+
|
|
138
185
|
## Real Screenshots
|
|
139
186
|
|
|
140
187
|
| CLI launch | Web app overview |
|
|
@@ -70,6 +70,35 @@ aginti --resume <session-id> \
|
|
|
70
70
|
"Continue after approval and verify the output was created in this run."
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
Three practical permission recipes:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Strict inspection: enforced read-only shell inspection, no file-tool writes, no web, no installs.
|
|
77
|
+
aginti --sandbox-mode docker-readonly \
|
|
78
|
+
--package-install-policy block \
|
|
79
|
+
--allow-shell \
|
|
80
|
+
--no-file-tools \
|
|
81
|
+
--no-web-search \
|
|
82
|
+
"inspect this project without edits"
|
|
83
|
+
|
|
84
|
+
# Full write in the current project folder, with setup commands isolated in Docker.
|
|
85
|
+
aginti --sandbox-mode docker-workspace \
|
|
86
|
+
--package-install-policy allow \
|
|
87
|
+
--approve-package-installs \
|
|
88
|
+
--allow-shell \
|
|
89
|
+
--allow-file-tools \
|
|
90
|
+
"build and test this project"
|
|
91
|
+
|
|
92
|
+
# Full host computer access for trusted maintenance.
|
|
93
|
+
aginti --sandbox-mode host \
|
|
94
|
+
--package-install-policy allow \
|
|
95
|
+
--approve-package-installs \
|
|
96
|
+
--allow-shell \
|
|
97
|
+
--allow-file-tools \
|
|
98
|
+
--allow-destructive \
|
|
99
|
+
"perform the trusted host maintenance task"
|
|
100
|
+
```
|
|
101
|
+
|
|
73
102
|
For host-only work, use the stricter trusted form deliberately:
|
|
74
103
|
|
|
75
104
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.59",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Low-cost, project-aware Web and CLI agents with DeepSeek/Venice/OpenAI routing, visible tool calls, durable sessions, scouts, AAPS, SCS, and guarded local execution.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -32,10 +32,43 @@ async function runCli(args, envOverrides = {}) {
|
|
|
32
32
|
return result.stdout;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
async function runCliIn(cwd, args, envOverrides = {}) {
|
|
36
|
+
const result = await execFileAsync(process.execPath, [path.join(repoRoot, "bin/aginti-cli.js"), ...args], {
|
|
37
|
+
cwd,
|
|
38
|
+
timeout: 20000,
|
|
39
|
+
maxBuffer: 2 * 1024 * 1024,
|
|
40
|
+
env: {
|
|
41
|
+
...process.env,
|
|
42
|
+
AGINTIFLOW_RUNTIME_DIR: "",
|
|
43
|
+
AGINTIFLOW_HOME: agintiflowHome,
|
|
44
|
+
...envOverrides,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
return result.stdout;
|
|
48
|
+
}
|
|
49
|
+
|
|
35
50
|
try {
|
|
36
51
|
await runCli(["init"]);
|
|
37
52
|
const agintiMd = await fs.readFile(path.join(tempRoot, "AGINTI.md"), "utf8");
|
|
38
53
|
assert(agintiMd.includes("Project instructions for AgInTiFlow agents."), "init did not create AGINTI.md");
|
|
54
|
+
assert(agintiMd.includes("## Agent Operating Contract"), "default init did not include the behavior contract");
|
|
55
|
+
assert(agintiMd.includes("## Verification Contract"), "default init did not include verification contract");
|
|
56
|
+
assert(agintiMd.includes("## Permission And Safety Contract"), "default init did not include permission contract");
|
|
57
|
+
assert(agintiMd.includes("## Definition Of Done"), "default init did not include definition of done");
|
|
58
|
+
const templates = await runCli(["init", "--list-templates"]);
|
|
59
|
+
assert(templates.includes("disciplined") && templates.includes("supervision"), "init did not list instruction templates");
|
|
60
|
+
const minimalRoot = path.join(tempRoot, "minimal-template");
|
|
61
|
+
await fs.mkdir(minimalRoot);
|
|
62
|
+
const minimalOutput = await runCliIn(minimalRoot, ["init", "--template", "minimal"]);
|
|
63
|
+
const minimalMd = await fs.readFile(path.join(minimalRoot, "AGINTI.md"), "utf8");
|
|
64
|
+
assert(minimalOutput.includes("template=minimal"), "minimal init did not report template");
|
|
65
|
+
assert(minimalMd.includes("## Agent Contract"), "minimal template did not create compact contract");
|
|
66
|
+
assert(!minimalMd.includes("## Architecture Notes"), "minimal template should stay compact");
|
|
67
|
+
const codingRoot = path.join(tempRoot, "coding-template");
|
|
68
|
+
await fs.mkdir(codingRoot);
|
|
69
|
+
await runCliIn(codingRoot, ["init", "coding"]);
|
|
70
|
+
const codingMd = await fs.readFile(path.join(codingRoot, "AGINTI.md"), "utf8");
|
|
71
|
+
assert(codingMd.includes("## Coding Profile Notes"), "coding template did not add coding appendix");
|
|
39
72
|
const capabilities = JSON.parse(await runCli(["capabilities", "--json"]));
|
|
40
73
|
assert(capabilities.project.root === tempRoot, "capabilities did not use cwd as project root");
|
|
41
74
|
assert(capabilities.project.commandCwd === tempRoot, "capabilities did not default commandCwd to project root");
|
|
@@ -168,6 +201,7 @@ try {
|
|
|
168
201
|
"git-policy",
|
|
169
202
|
"skills-capability",
|
|
170
203
|
"env-sandbox-defaults",
|
|
204
|
+
"aginti-md-contract-templates",
|
|
171
205
|
],
|
|
172
206
|
},
|
|
173
207
|
null,
|
package/src/agent-runner.js
CHANGED
|
@@ -28,6 +28,7 @@ import { captureTmuxPane, listTmuxSessions, sendTmuxKeys, startTmuxSession } fro
|
|
|
28
28
|
import { languageInstruction } from "./i18n.js";
|
|
29
29
|
import { flushHousekeeping } from "./housekeeping.js";
|
|
30
30
|
import { buildFailedCommandAdvice, buildPermissionAdvice } from "./permission-advice.js";
|
|
31
|
+
import { formatBehaviorContractForPrompt } from "./behavior-contract.js";
|
|
31
32
|
import {
|
|
32
33
|
buildSupervisorInstruction,
|
|
33
34
|
createScsPlan,
|
|
@@ -353,6 +354,7 @@ async function createInitialState(config, sessionId) {
|
|
|
353
354
|
"Avoid destructive actions, purchases, account changes, and sensitive workflows.",
|
|
354
355
|
languageInstruction(config.language || "en"),
|
|
355
356
|
projectInstructionContext,
|
|
357
|
+
formatBehaviorContractForPrompt(),
|
|
356
358
|
"Treat AGINTI.md as durable project memory and operating instructions for this project. The user can edit it manually or ask you in chat to update it; use workspace file tools for that and never store secrets there.",
|
|
357
359
|
config.allowShellTool
|
|
358
360
|
? config.useDockerSandbox
|
package/src/auth-onboarding.js
CHANGED
|
@@ -41,13 +41,14 @@ export const MAIN_AUTH_PROVIDERS = [
|
|
|
41
41
|
label: "Qwen",
|
|
42
42
|
keyName: "QWEN_API_KEY",
|
|
43
43
|
description: "Qwen OpenAI-compatible route",
|
|
44
|
+
keyUrl: "https://bailian.console.aliyun.com/",
|
|
44
45
|
},
|
|
45
46
|
{
|
|
46
47
|
id: "venice",
|
|
47
48
|
label: "Venice",
|
|
48
49
|
keyName: "VENICE_API_KEY",
|
|
49
50
|
description: "Venice OpenAI-compatible text and image routes",
|
|
50
|
-
keyUrl: "https://venice.ai",
|
|
51
|
+
keyUrl: "https://venice.ai/settings/api",
|
|
51
52
|
},
|
|
52
53
|
];
|
|
53
54
|
|
|
@@ -56,6 +57,7 @@ const AUXILIARY_AUTH_PROVIDER = {
|
|
|
56
57
|
label: "GRS AI / Nano Banana",
|
|
57
58
|
keyName: "GRSAI",
|
|
58
59
|
description: "optional image generation",
|
|
60
|
+
keyUrl: "https://grsai.ai/dashboard/api-keys",
|
|
59
61
|
};
|
|
60
62
|
|
|
61
63
|
const AUTH_ALIASES = {
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
export const INSTRUCTION_TEMPLATE_IDS = [
|
|
2
|
+
"minimal",
|
|
3
|
+
"disciplined",
|
|
4
|
+
"coding",
|
|
5
|
+
"research",
|
|
6
|
+
"writing",
|
|
7
|
+
"design",
|
|
8
|
+
"aaps",
|
|
9
|
+
"supervision",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const TEMPLATE_DESCRIPTIONS = {
|
|
13
|
+
minimal: "Short project memory for tiny or experimental folders.",
|
|
14
|
+
disciplined: "Default robust agent contract for normal project work.",
|
|
15
|
+
coding: "Coding-focused contract with commands, tests, style, and architecture notes.",
|
|
16
|
+
research: "Research-focused contract with sources, reproducibility, and citation notes.",
|
|
17
|
+
writing: "Writing-focused contract with audience, style, outline, and publication notes.",
|
|
18
|
+
design: "Design-focused contract with visual system, assets, QA, and artifact notes.",
|
|
19
|
+
aaps: "AAPS workflow contract with phase criteria, tools, checks, and artifacts.",
|
|
20
|
+
supervision: "Supervisor/student contract for monitored agent work and evidence gates.",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const TEMPLATE_ALIASES = {
|
|
24
|
+
default: "disciplined",
|
|
25
|
+
standard: "disciplined",
|
|
26
|
+
full: "disciplined",
|
|
27
|
+
careful: "disciplined",
|
|
28
|
+
karpathy: "disciplined",
|
|
29
|
+
code: "coding",
|
|
30
|
+
dev: "coding",
|
|
31
|
+
software: "coding",
|
|
32
|
+
paper: "research",
|
|
33
|
+
docs: "writing",
|
|
34
|
+
doc: "writing",
|
|
35
|
+
article: "writing",
|
|
36
|
+
visual: "design",
|
|
37
|
+
ui: "design",
|
|
38
|
+
workflow: "aaps",
|
|
39
|
+
student: "supervision",
|
|
40
|
+
supervise: "supervision",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export function normalizeInstructionTemplate(value = "disciplined", fallback = "disciplined") {
|
|
44
|
+
const raw = String(value || "").trim().toLowerCase();
|
|
45
|
+
const normalized = TEMPLATE_ALIASES[raw] || raw;
|
|
46
|
+
if (INSTRUCTION_TEMPLATE_IDS.includes(normalized)) return normalized;
|
|
47
|
+
return INSTRUCTION_TEMPLATE_IDS.includes(fallback) ? fallback : "disciplined";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function listInstructionTemplates() {
|
|
51
|
+
return INSTRUCTION_TEMPLATE_IDS.map((id) => ({
|
|
52
|
+
id,
|
|
53
|
+
description: TEMPLATE_DESCRIPTIONS[id] || "",
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function formatInstructionTemplateList() {
|
|
58
|
+
return listInstructionTemplates()
|
|
59
|
+
.map((item) => `${item.id.padEnd(12)} ${item.description}`)
|
|
60
|
+
.join("\n");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function formatBehaviorContractForPrompt({ mode = "runtime" } = {}) {
|
|
64
|
+
const prefix = mode === "plan" ? "Planning discipline contract:" : "AgInTiFlow discipline contract:";
|
|
65
|
+
return [
|
|
66
|
+
prefix,
|
|
67
|
+
"Surface ambiguity instead of silently guessing when interpretations change scope, safety, or implementation.",
|
|
68
|
+
"Prefer the smallest coherent change that satisfies the request; do not add speculative features or abstractions.",
|
|
69
|
+
"Make surgical edits: no drive-by refactors, unrelated formatting churn, or deletion of code you did not need to touch.",
|
|
70
|
+
"Define or infer concrete success criteria for non-trivial work, then run focused checks or state why checks are unavailable.",
|
|
71
|
+
"Respect the permission contract: if a tool is blocked, stop and present the safe rerun/approval path instead of retrying variants.",
|
|
72
|
+
"Keep artifacts durable and discoverable with descriptive non-conflicting names; never overwrite unless the user clearly asked.",
|
|
73
|
+
].join(" ");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function scsContractCriteria() {
|
|
77
|
+
return [
|
|
78
|
+
"Assumptions and ambiguities are explicit enough for the phase.",
|
|
79
|
+
"The phase is the smallest coherent step toward the user goal.",
|
|
80
|
+
"The plan avoids speculative features, broad rewrites, and unrelated cleanup.",
|
|
81
|
+
"The phase has concrete success criteria and an evidence/check path.",
|
|
82
|
+
"Permission, secret, destructive-action, and artifact-overwrite risks are called out.",
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function lines(...items) {
|
|
87
|
+
return items.join("\n");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function baseSections() {
|
|
91
|
+
return lines(
|
|
92
|
+
"# AGINTI.md",
|
|
93
|
+
"",
|
|
94
|
+
"Project instructions for AgInTiFlow agents.",
|
|
95
|
+
"",
|
|
96
|
+
"This file is durable project memory. Edit it directly or ask AgInTiFlow to update it during chat. Keep secrets in `.aginti/.env`, not here.",
|
|
97
|
+
"",
|
|
98
|
+
"## Project Identity",
|
|
99
|
+
"",
|
|
100
|
+
"- Project name:",
|
|
101
|
+
"- What this project does:",
|
|
102
|
+
"- Primary users:",
|
|
103
|
+
"- Main workflows to preserve:",
|
|
104
|
+
"- Explicit non-goals:",
|
|
105
|
+
"",
|
|
106
|
+
"## Current Priorities",
|
|
107
|
+
"",
|
|
108
|
+
"-",
|
|
109
|
+
"",
|
|
110
|
+
"## Agent Operating Contract",
|
|
111
|
+
"",
|
|
112
|
+
"- Inspect before editing: read this file, relevant README/docs, manifests, entry points, tests, and exact files related to the request.",
|
|
113
|
+
"- State assumptions when the request is ambiguous. If multiple interpretations would lead to different implementations, ask or present options before editing.",
|
|
114
|
+
"- Prefer the smallest coherent change that solves the user's actual request.",
|
|
115
|
+
"- Do not add speculative features, abstractions, configurability, rewrites, or broad refactors unless requested.",
|
|
116
|
+
"- Do not change adjacent formatting, comments, naming, or style just because it looks improvable.",
|
|
117
|
+
"- Every changed line should trace to the task or to cleanup caused by the task.",
|
|
118
|
+
"- Match existing project style even if another style is personally preferable.",
|
|
119
|
+
"- If you notice unrelated issues, report them separately rather than editing them.",
|
|
120
|
+
"",
|
|
121
|
+
"## Verification Contract",
|
|
122
|
+
"",
|
|
123
|
+
"For non-trivial work, define success criteria before implementation:",
|
|
124
|
+
"",
|
|
125
|
+
"- Target behavior:",
|
|
126
|
+
"- Files or surfaces likely affected:",
|
|
127
|
+
"- Verification command(s):",
|
|
128
|
+
"- Manual checks, if needed:",
|
|
129
|
+
"",
|
|
130
|
+
"Preferred loop:",
|
|
131
|
+
"",
|
|
132
|
+
"1. Reproduce or inspect the issue.",
|
|
133
|
+
"2. Make the smallest coherent change.",
|
|
134
|
+
"3. Run focused checks.",
|
|
135
|
+
"4. Repair failures caused by the change.",
|
|
136
|
+
"5. Summarize changed files, checks run, and residual risks.",
|
|
137
|
+
"",
|
|
138
|
+
"Do not claim success without a concrete check, unless no check exists and that limitation is stated.",
|
|
139
|
+
"",
|
|
140
|
+
"## Permission And Safety Contract",
|
|
141
|
+
"",
|
|
142
|
+
"- Current project folder writes are allowed when file tools are enabled.",
|
|
143
|
+
"- Do not write outside this project unless the user explicitly asks and the runtime permits it.",
|
|
144
|
+
"- Never print or store secrets in logs, docs, commits, screenshots, or artifacts.",
|
|
145
|
+
"- Do not edit `.git`, `.env`, dependency caches, generated vendor folders, or large binary files unless explicitly requested.",
|
|
146
|
+
"- Destructive actions, host maintenance, sudo, publishing, deployment, and broad cleanup require explicit user intent and the appropriate runtime mode.",
|
|
147
|
+
"- If blocked by policy, stop and suggest the safest rerun command instead of trying command variants.",
|
|
148
|
+
"",
|
|
149
|
+
"## File And Artifact Policy",
|
|
150
|
+
"",
|
|
151
|
+
"- Use descriptive, non-conflicting filenames for generated docs, stories, images, reports, screenshots, and artifacts.",
|
|
152
|
+
"- Avoid generic names such as `output.txt`, `story.txt`, or `result.png` unless the user asked for that exact path.",
|
|
153
|
+
"- Do not overwrite existing files unless the user asked to update, replace, patch, or overwrite them.",
|
|
154
|
+
"- Keep durable outputs in project folders where the user can find them.",
|
|
155
|
+
"",
|
|
156
|
+
"## Commands",
|
|
157
|
+
"",
|
|
158
|
+
"- Install:",
|
|
159
|
+
"- Build:",
|
|
160
|
+
"- Test:",
|
|
161
|
+
"- Lint:",
|
|
162
|
+
"- Typecheck:",
|
|
163
|
+
"- Format:",
|
|
164
|
+
"- Preview/run:",
|
|
165
|
+
"- Deploy/publish:",
|
|
166
|
+
"",
|
|
167
|
+
"## Architecture Notes",
|
|
168
|
+
"",
|
|
169
|
+
"- Main entry points:",
|
|
170
|
+
"- Important directories:",
|
|
171
|
+
"- Generated directories:",
|
|
172
|
+
"- Files agents should avoid:",
|
|
173
|
+
"- External services:",
|
|
174
|
+
"",
|
|
175
|
+
"## Style And Conventions",
|
|
176
|
+
"",
|
|
177
|
+
"- Language/runtime:",
|
|
178
|
+
"- Package manager:",
|
|
179
|
+
"- Formatting style:",
|
|
180
|
+
"- Test framework:",
|
|
181
|
+
"- Error handling style:",
|
|
182
|
+
"- Naming conventions:",
|
|
183
|
+
"",
|
|
184
|
+
"## Definition Of Done",
|
|
185
|
+
"",
|
|
186
|
+
"A task is done when:",
|
|
187
|
+
"",
|
|
188
|
+
"- The requested behavior is implemented or the blocker is clearly reported.",
|
|
189
|
+
"- Relevant checks were run, or missing checks are stated.",
|
|
190
|
+
"- The diff is scoped to the request.",
|
|
191
|
+
"- Generated artifacts are named clearly.",
|
|
192
|
+
"- Git status and residual risks are summarized when relevant."
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function minimalSections() {
|
|
197
|
+
return lines(
|
|
198
|
+
"# AGINTI.md",
|
|
199
|
+
"",
|
|
200
|
+
"Project instructions for AgInTiFlow agents.",
|
|
201
|
+
"",
|
|
202
|
+
"Keep secrets in `.aginti/.env`, not here.",
|
|
203
|
+
"",
|
|
204
|
+
"## Project",
|
|
205
|
+
"",
|
|
206
|
+
"- Purpose:",
|
|
207
|
+
"- Important commands:",
|
|
208
|
+
"- Files or directories to avoid:",
|
|
209
|
+
"",
|
|
210
|
+
"## Agent Contract",
|
|
211
|
+
"",
|
|
212
|
+
"- Inspect relevant files before editing.",
|
|
213
|
+
"- Prefer small, surgical changes.",
|
|
214
|
+
"- Avoid speculative features and broad refactors.",
|
|
215
|
+
"- Run focused checks when available.",
|
|
216
|
+
"- Use descriptive non-conflicting filenames for generated outputs."
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function templateAppendix(template) {
|
|
221
|
+
if (template === "coding") {
|
|
222
|
+
return lines(
|
|
223
|
+
"",
|
|
224
|
+
"## Coding Profile Notes",
|
|
225
|
+
"",
|
|
226
|
+
"- Prefer tests or focused repro commands before and after fixes.",
|
|
227
|
+
"- Keep public APIs stable unless the task explicitly changes them.",
|
|
228
|
+
"- Check callers before changing shared functions.",
|
|
229
|
+
"- Record package-manager and test commands as they become known."
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
if (template === "research") {
|
|
233
|
+
return lines(
|
|
234
|
+
"",
|
|
235
|
+
"## Research Profile Notes",
|
|
236
|
+
"",
|
|
237
|
+
"- Track sources, dates accessed, datasets, assumptions, and limitations.",
|
|
238
|
+
"- Prefer primary sources and reproducible scripts/notebooks when possible.",
|
|
239
|
+
"- Separate evidence, interpretation, and speculation."
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
if (template === "writing") {
|
|
243
|
+
return lines(
|
|
244
|
+
"",
|
|
245
|
+
"## Writing Profile Notes",
|
|
246
|
+
"",
|
|
247
|
+
"- Track audience, tone, outline, publication target, and reference style.",
|
|
248
|
+
"- Preserve the user's voice; do not over-polish into generic AI prose.",
|
|
249
|
+
"- Keep drafts, revisions, and final exports clearly named."
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
if (template === "design") {
|
|
253
|
+
return lines(
|
|
254
|
+
"",
|
|
255
|
+
"## Design Profile Notes",
|
|
256
|
+
"",
|
|
257
|
+
"- Define visual direction, audience, assets, constraints, and acceptance screenshots.",
|
|
258
|
+
"- Prefer intentional typography, spacing, color, and motion over generic layouts.",
|
|
259
|
+
"- Save source assets and exported previews with durable names."
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
if (template === "aaps") {
|
|
263
|
+
return lines(
|
|
264
|
+
"",
|
|
265
|
+
"## AAPS Profile Notes",
|
|
266
|
+
"",
|
|
267
|
+
"- Treat `.aaps` files as top-down workflow specifications.",
|
|
268
|
+
"- Each phase should list goal, allowed tools, write scope, checks, artifacts, and stop conditions.",
|
|
269
|
+
"- Validate or compile workflows before reporting success."
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
if (template === "supervision") {
|
|
273
|
+
return lines(
|
|
274
|
+
"",
|
|
275
|
+
"## Supervision Profile Notes",
|
|
276
|
+
"",
|
|
277
|
+
"- The supervised agent does the actual project work; the supervisor monitors evidence and capability gaps.",
|
|
278
|
+
"- Verify artifacts directly instead of trusting self-reports.",
|
|
279
|
+
"- If the student fails due to missing skill/tool/policy, improve AgInTiFlow and resume the same session."
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
return "";
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function buildAgintiInstructions(template = "disciplined") {
|
|
286
|
+
const normalized = normalizeInstructionTemplate(template);
|
|
287
|
+
const body = normalized === "minimal" ? minimalSections() : `${baseSections()}${templateAppendix(normalized)}`;
|
|
288
|
+
return `${body}\n`;
|
|
289
|
+
}
|
|
290
|
+
|
package/src/cli.js
CHANGED
|
@@ -35,6 +35,7 @@ import { maybeAutoUpdate } from "./auto-update.js";
|
|
|
35
35
|
import { readHousekeepingSummary } from "./housekeeping.js";
|
|
36
36
|
import { handleSkillMeshCommand } from "./skillmesh.js";
|
|
37
37
|
import { handleAapsCliCommand } from "./aaps-adapter.js";
|
|
38
|
+
import { formatInstructionTemplateList, normalizeInstructionTemplate } from "./behavior-contract.js";
|
|
38
39
|
import fs from "node:fs/promises";
|
|
39
40
|
import path from "node:path";
|
|
40
41
|
import { fileURLToPath } from "node:url";
|
|
@@ -404,7 +405,7 @@ export function parseArgs(argv) {
|
|
|
404
405
|
|
|
405
406
|
function printUsage() {
|
|
406
407
|
console.log(
|
|
407
|
-
'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti update OR aginti models OR aginti aaps [status|init|files|validate|compile|check|run] OR aginti skills [query] OR aginti skillmesh [status|off|record|share|sync|serve|service] OR aginti housekeeping [--json] OR aginti auth [deepseek|openai|qwen|venice|grsai] OR aginti resume [--all-sessions] [latest|<session-id>] ["prompt"] OR aginti --remove-empty-sessions OR aginti --remove-sessions OR aginti queue <session-id> "message" OR aginti [--no-auto-update] [--language en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru] [--image] [--latex] [--scs|--scs auto|--no-scs] [--routing smart|fast|complex|manual] [--provider deepseek|openai|qwen|venice|mock] [--model MODEL] [--route-model MODEL] [--main-model MODEL] [--spare-model MODEL --spare-reasoning medium] [--aux-provider grsai|venice --aux-model MODEL] [--sandbox-mode host|docker-readonly|docker-workspace] [--package-install-policy block|prompt|allow] [--approve-package-installs] [--allow-shell|--no-shell] [--allow-file-tools|--no-file-tools] [--web-search|--no-web-search] [--parallel-scouts|--no-parallel-scouts --scout-count 1..10] [--allow-auxiliary-tools|--no-auxiliary-tools] [--allow-wrappers --wrapper codex --wrapper-model gpt-5.5] [--list-models|--list-routes] "your task"'
|
|
408
|
+
'Usage: aginti [chat] OR aginti init [--template minimal|disciplined|coding|research|writing|design|aaps|supervision] OR aginti web [--port 3210] OR aginti update OR aginti models OR aginti aaps [status|init|files|validate|compile|check|run] OR aginti skills [query] OR aginti skillmesh [status|off|record|share|sync|serve|service] OR aginti housekeeping [--json] OR aginti auth [deepseek|openai|qwen|venice|grsai] OR aginti resume [--all-sessions] [latest|<session-id>] ["prompt"] OR aginti --remove-empty-sessions OR aginti --remove-sessions OR aginti queue <session-id> "message" OR aginti [--no-auto-update] [--language en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru] [--image] [--latex] [--scs|--scs auto|--no-scs] [--routing smart|fast|complex|manual] [--provider deepseek|openai|qwen|venice|mock] [--model MODEL] [--route-model MODEL] [--main-model MODEL] [--spare-model MODEL --spare-reasoning medium] [--aux-provider grsai|venice --aux-model MODEL] [--sandbox-mode host|docker-readonly|docker-workspace] [--package-install-policy block|prompt|allow] [--approve-package-installs] [--allow-shell|--no-shell] [--allow-file-tools|--no-file-tools] [--web-search|--no-web-search] [--parallel-scouts|--no-parallel-scouts --scout-count 1..10] [--allow-auxiliary-tools|--no-auxiliary-tools] [--allow-wrappers --wrapper codex --wrapper-model gpt-5.5] [--list-models|--list-routes] "your task"'
|
|
408
409
|
);
|
|
409
410
|
console.log(`Languages: ${["en", "ja", "zh-Hans", "zh-Hant", "ko", "fr", "es", "ar", "vi", "de", "ru"].map((code) => `${code}=${languageLabel(code)}`).join(", ")}`);
|
|
410
411
|
}
|
|
@@ -585,11 +586,34 @@ async function printHousekeeping(argv = []) {
|
|
|
585
586
|
function printInitResult(result) {
|
|
586
587
|
console.log(`AgInTiFlow project initialized: ${result.projectRoot}`);
|
|
587
588
|
console.log(`instructions=${result.instructionsPath}`);
|
|
589
|
+
if (result.template) console.log(`template=${result.template}`);
|
|
588
590
|
console.log(`control=${result.controlDir}`);
|
|
589
591
|
console.log(`projectSessions=${result.sessionsDir}`);
|
|
590
592
|
console.log(`created=${result.created.length} updated=${result.updated.length} skipped=${result.skipped.length}`);
|
|
591
593
|
}
|
|
592
594
|
|
|
595
|
+
function parseInitOptions(argv = []) {
|
|
596
|
+
let template = "disciplined";
|
|
597
|
+
let list = false;
|
|
598
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
599
|
+
const arg = argv[index];
|
|
600
|
+
if (arg === "--template" || arg === "-t") {
|
|
601
|
+
template = readOption(argv, index) || template;
|
|
602
|
+
index += 1;
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
if (arg === "--list-templates" || arg === "templates" || arg === "list") {
|
|
606
|
+
list = true;
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
if (!arg.startsWith("-")) template = arg;
|
|
610
|
+
}
|
|
611
|
+
return {
|
|
612
|
+
template: normalizeInstructionTemplate(template),
|
|
613
|
+
list,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
593
617
|
function printDoctorReport(report) {
|
|
594
618
|
console.log(`AgInTiFlow ${report.package.version} (npm latest: ${report.package.npmLatest})`);
|
|
595
619
|
console.log(`node=${report.node.version} ok=${report.node.ok}`);
|
|
@@ -1101,66 +1125,73 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1101
1125
|
return;
|
|
1102
1126
|
}
|
|
1103
1127
|
|
|
1104
|
-
if (
|
|
1128
|
+
if (commandArgv.includes("--remove-empty-sessions") || commandArgv[0] === "remove-empty-sessions") {
|
|
1105
1129
|
await handleRemoveSessionsCommand({ emptyOnly: true });
|
|
1106
1130
|
return;
|
|
1107
1131
|
}
|
|
1108
1132
|
|
|
1109
|
-
if (
|
|
1133
|
+
if (commandArgv.includes("--remove-sessions") || commandArgv[0] === "remove-sessions") {
|
|
1110
1134
|
await handleRemoveSessionsCommand({ emptyOnly: false });
|
|
1111
1135
|
return;
|
|
1112
1136
|
}
|
|
1113
1137
|
|
|
1114
|
-
if (
|
|
1115
|
-
|
|
1138
|
+
if (commandArgv[0] === "init") {
|
|
1139
|
+
const initOptions = parseInitOptions(commandArgv.slice(1));
|
|
1140
|
+
if (initOptions.list) {
|
|
1141
|
+
console.log(formatInstructionTemplateList());
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
printInitResult(await initProject(commandCwd, { template: initOptions.template }));
|
|
1116
1145
|
return;
|
|
1117
1146
|
}
|
|
1118
1147
|
|
|
1119
|
-
if (
|
|
1120
|
-
const parsed = parseArgs(
|
|
1148
|
+
if (commandArgv[0] === "doctor") {
|
|
1149
|
+
const parsed = parseArgs(commandArgv.slice(1).filter((arg) => arg !== "--json" && arg !== "--capabilities"));
|
|
1121
1150
|
const config = loadConfig(
|
|
1122
1151
|
{
|
|
1123
1152
|
...parsed,
|
|
1124
1153
|
goal: "doctor",
|
|
1154
|
+
commandCwd,
|
|
1125
1155
|
allowShellTool: parsed.allowShellTool ?? true,
|
|
1126
1156
|
allowFileTools: parsed.allowFileTools ?? true,
|
|
1127
1157
|
},
|
|
1128
|
-
{ packageDir, baseDir:
|
|
1158
|
+
{ packageDir, baseDir: commandCwd }
|
|
1129
1159
|
);
|
|
1130
|
-
const report =
|
|
1131
|
-
? await buildCapabilityReport(
|
|
1132
|
-
: await doctorReport(
|
|
1133
|
-
if (
|
|
1134
|
-
else if (
|
|
1160
|
+
const report = commandArgv.includes("--capabilities")
|
|
1161
|
+
? await buildCapabilityReport(commandCwd, packageJson.version, config)
|
|
1162
|
+
: await doctorReport(commandCwd, packageJson.version, config);
|
|
1163
|
+
if (commandArgv.includes("--json")) console.log(JSON.stringify(report, null, 2));
|
|
1164
|
+
else if (commandArgv.includes("--capabilities")) printCapabilityReport(report);
|
|
1135
1165
|
else printDoctorReport(report);
|
|
1136
1166
|
return;
|
|
1137
1167
|
}
|
|
1138
1168
|
|
|
1139
|
-
if (
|
|
1140
|
-
const parsed = parseArgs(
|
|
1169
|
+
if (commandArgv[0] === "capabilities") {
|
|
1170
|
+
const parsed = parseArgs(commandArgv.slice(1).filter((arg) => arg !== "--json"));
|
|
1141
1171
|
const config = loadConfig(
|
|
1142
1172
|
{
|
|
1143
1173
|
...parsed,
|
|
1144
1174
|
goal: "capabilities",
|
|
1175
|
+
commandCwd,
|
|
1145
1176
|
allowShellTool: parsed.allowShellTool ?? true,
|
|
1146
1177
|
allowFileTools: parsed.allowFileTools ?? true,
|
|
1147
1178
|
},
|
|
1148
|
-
{ packageDir, baseDir:
|
|
1179
|
+
{ packageDir, baseDir: commandCwd }
|
|
1149
1180
|
);
|
|
1150
|
-
const report = await buildCapabilityReport(
|
|
1151
|
-
if (
|
|
1181
|
+
const report = await buildCapabilityReport(commandCwd, packageJson.version, config);
|
|
1182
|
+
if (commandArgv.includes("--json")) console.log(JSON.stringify(report, null, 2));
|
|
1152
1183
|
else printCapabilityReport(report);
|
|
1153
1184
|
return;
|
|
1154
1185
|
}
|
|
1155
1186
|
|
|
1156
|
-
if (
|
|
1157
|
-
await printHousekeeping(
|
|
1187
|
+
if (commandArgv[0] === "housekeeping" || commandArgv[0] === "housekeeper") {
|
|
1188
|
+
await printHousekeeping(commandArgv.slice(1));
|
|
1158
1189
|
return;
|
|
1159
1190
|
}
|
|
1160
1191
|
|
|
1161
|
-
if (
|
|
1192
|
+
if (commandArgv[0] === "skillmesh" || commandArgv[0] === "skillsync" || commandArgv[0] === "skill-sync" || commandArgv[0] === "skill-share") {
|
|
1162
1193
|
try {
|
|
1163
|
-
await handleSkillMeshCommand(
|
|
1194
|
+
await handleSkillMeshCommand(commandArgv.slice(1));
|
|
1164
1195
|
} catch (error) {
|
|
1165
1196
|
console.error(error instanceof Error ? error.message : String(error));
|
|
1166
1197
|
process.exit(1);
|
|
@@ -1168,63 +1199,63 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1168
1199
|
return;
|
|
1169
1200
|
}
|
|
1170
1201
|
|
|
1171
|
-
if (
|
|
1202
|
+
if (commandArgv[0] === "keys/status") {
|
|
1172
1203
|
await handleKeyCommand(["status"]);
|
|
1173
1204
|
return;
|
|
1174
1205
|
}
|
|
1175
1206
|
|
|
1176
|
-
if (
|
|
1177
|
-
await handleKeyCommand(
|
|
1207
|
+
if (commandArgv[0] === "keys") {
|
|
1208
|
+
await handleKeyCommand(commandArgv.slice(1));
|
|
1178
1209
|
return;
|
|
1179
1210
|
}
|
|
1180
1211
|
|
|
1181
|
-
if (
|
|
1182
|
-
const provider = normalizeAuthProvider(
|
|
1183
|
-
if (
|
|
1184
|
-
const result = await runAuthWizard(
|
|
1212
|
+
if (commandArgv[0] === "auth" || commandArgv[0] === "login") {
|
|
1213
|
+
const provider = normalizeAuthProvider(commandArgv[1] || "", "");
|
|
1214
|
+
if (commandArgv[0] === "auth" || (!provider && process.stdin.isTTY)) {
|
|
1215
|
+
const result = await runAuthWizard(commandCwd, { provider });
|
|
1185
1216
|
printAuthWizardResult(result);
|
|
1186
1217
|
return;
|
|
1187
1218
|
}
|
|
1188
1219
|
const target = provider || "deepseek";
|
|
1189
|
-
const key =
|
|
1220
|
+
const key = commandArgv.includes("--stdin") || !process.stdin.isTTY
|
|
1190
1221
|
? await readStdin()
|
|
1191
1222
|
: await promptHidden(`${providerLabel(target)} API key/token: `);
|
|
1192
1223
|
if (!key) {
|
|
1193
1224
|
console.error("No key saved.");
|
|
1194
1225
|
process.exit(1);
|
|
1195
1226
|
}
|
|
1196
|
-
const result = await setProviderKey(
|
|
1227
|
+
const result = await setProviderKey(commandCwd, target, key);
|
|
1197
1228
|
console.log(`saved ${result.provider} key to project-local ignored env (${result.keyName})`);
|
|
1198
1229
|
return;
|
|
1199
1230
|
}
|
|
1200
1231
|
|
|
1201
|
-
if (
|
|
1202
|
-
await handleSessionsCommand(
|
|
1232
|
+
if (commandArgv[0] === "sessions") {
|
|
1233
|
+
await handleSessionsCommand(commandArgv.slice(1));
|
|
1203
1234
|
return;
|
|
1204
1235
|
}
|
|
1205
1236
|
|
|
1206
|
-
if (
|
|
1207
|
-
await handleStorageCommand(
|
|
1237
|
+
if (commandArgv[0] === "storage") {
|
|
1238
|
+
await handleStorageCommand(commandArgv.slice(1));
|
|
1208
1239
|
return;
|
|
1209
1240
|
}
|
|
1210
1241
|
|
|
1211
|
-
if (
|
|
1242
|
+
if (commandArgv[0] === "models" || commandArgv[0] === "model") {
|
|
1212
1243
|
printModels();
|
|
1213
1244
|
return;
|
|
1214
1245
|
}
|
|
1215
1246
|
|
|
1216
|
-
if (
|
|
1217
|
-
printSkills(
|
|
1247
|
+
if (commandArgv[0] === "skills" || commandArgv[0] === "skill") {
|
|
1248
|
+
printSkills(commandArgv.slice(1).join(" ").trim());
|
|
1218
1249
|
return;
|
|
1219
1250
|
}
|
|
1220
1251
|
|
|
1221
|
-
if (
|
|
1222
|
-
await handleQueueCommand(
|
|
1252
|
+
if (commandArgv[0] === "queue") {
|
|
1253
|
+
await handleQueueCommand(commandArgv.slice(1));
|
|
1223
1254
|
return;
|
|
1224
1255
|
}
|
|
1225
1256
|
|
|
1226
|
-
if (
|
|
1227
|
-
const resumeArgv =
|
|
1257
|
+
if (commandArgv[0] === "resume") {
|
|
1258
|
+
const resumeArgv = commandArgv.slice(1);
|
|
1228
1259
|
const allSessions = resumeArgv.includes("--all-sessions");
|
|
1229
1260
|
const positional = resumeArgv.filter((arg) => arg !== "--all-sessions");
|
|
1230
1261
|
let sessionId = positional[0] || "";
|
|
@@ -1237,20 +1268,20 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1237
1268
|
}
|
|
1238
1269
|
if (!sessionId) return;
|
|
1239
1270
|
if (!prompt) {
|
|
1240
|
-
await startInteractiveCli(agentDefaults({ ...parseArgs([]), resume: sessionId }), {
|
|
1271
|
+
await startInteractiveCli(agentDefaults({ ...parseArgs([]), resume: sessionId, commandCwd }), {
|
|
1241
1272
|
packageDir,
|
|
1242
1273
|
packageVersion: packageJson.version,
|
|
1243
1274
|
});
|
|
1244
1275
|
return;
|
|
1245
1276
|
}
|
|
1246
|
-
const resumeArgs = agentDefaults({ ...parseArgs([prompt]), resume: sessionId, goal: prompt });
|
|
1277
|
+
const resumeArgs = agentDefaults({ ...parseArgs([prompt]), resume: sessionId, goal: prompt, commandCwd });
|
|
1247
1278
|
if (!(await ensureDeepSeekKeyForOneShot(resumeArgs))) process.exit(1);
|
|
1248
1279
|
const config = loadConfig(resumeArgs, { packageDir });
|
|
1249
1280
|
await runAgent(config);
|
|
1250
1281
|
return;
|
|
1251
1282
|
}
|
|
1252
1283
|
|
|
1253
|
-
const args = parseArgs(
|
|
1284
|
+
const args = { ...parseArgs(commandArgv), commandCwd };
|
|
1254
1285
|
|
|
1255
1286
|
if (args.web) {
|
|
1256
1287
|
if (args.port) process.env.PORT = String(args.port);
|
package/src/interactive-cli.js
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
} from "./skillmesh.js";
|
|
36
36
|
import { normalizeScsMode } from "./scs-controller.js";
|
|
37
37
|
import { formatAapsResult, runAapsAction } from "./aaps-adapter.js";
|
|
38
|
+
import { formatInstructionTemplateList, normalizeInstructionTemplate } from "./behavior-contract.js";
|
|
38
39
|
|
|
39
40
|
const useColor = Boolean(input.isTTY && output.isTTY && process.env.AGINTIFLOW_NO_COLOR !== "1");
|
|
40
41
|
const ansi = {
|
|
@@ -108,6 +109,12 @@ const SLASH_COMMANDS = [
|
|
|
108
109
|
"/web",
|
|
109
110
|
"/exit",
|
|
110
111
|
];
|
|
112
|
+
|
|
113
|
+
function parseInitTemplateValue(value = "") {
|
|
114
|
+
const parts = String(value || "").trim().split(/\s+/).filter(Boolean);
|
|
115
|
+
if (parts[0] === "template" || parts[0] === "--template" || parts[0] === "-t") return normalizeInstructionTemplate(parts[1]);
|
|
116
|
+
return normalizeInstructionTemplate(parts[0] || "disciplined");
|
|
117
|
+
}
|
|
111
118
|
const promptHistory = [];
|
|
112
119
|
let activeRunInput = null;
|
|
113
120
|
let cliLanguage = resolveLanguage();
|
|
@@ -2565,9 +2572,14 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2565
2572
|
return true;
|
|
2566
2573
|
}
|
|
2567
2574
|
if (command === "instructions" || command === "memory") {
|
|
2568
|
-
if (value === "
|
|
2569
|
-
|
|
2570
|
-
|
|
2575
|
+
if (value === "templates") {
|
|
2576
|
+
printAgentMessage(`Available AGINTI.md templates:\n${formatInstructionTemplateList()}`);
|
|
2577
|
+
return true;
|
|
2578
|
+
}
|
|
2579
|
+
if (value === "init" || value.startsWith("init ")) {
|
|
2580
|
+
const template = parseInitTemplateValue(value.replace(/^init\b\s*/, ""));
|
|
2581
|
+
const result = await initProject(process.cwd(), { template });
|
|
2582
|
+
printAgentMessage(`AGINTI.md ready at ${result.instructionsPath}\ntemplate=${result.template}`);
|
|
2571
2583
|
return true;
|
|
2572
2584
|
}
|
|
2573
2585
|
const instructions = await readProjectInstructions(process.cwd(), { maxBytes: 4000 });
|
|
@@ -3079,8 +3091,13 @@ async function handleCommand(line, state, packageDir) {
|
|
|
3079
3091
|
return true;
|
|
3080
3092
|
}
|
|
3081
3093
|
if (command === "init") {
|
|
3082
|
-
|
|
3083
|
-
|
|
3094
|
+
if (value === "templates" || value === "list") {
|
|
3095
|
+
printAgentMessage(`Available AGINTI.md templates:\n${formatInstructionTemplateList()}`);
|
|
3096
|
+
return true;
|
|
3097
|
+
}
|
|
3098
|
+
const template = parseInitTemplateValue(value);
|
|
3099
|
+
const result = await initProject(process.cwd(), { template });
|
|
3100
|
+
printAgentMessage(`initialized project=${result.projectRoot}\nAGINTI.md=${result.instructionsPath}\ntemplate=${result.template}`);
|
|
3084
3101
|
return true;
|
|
3085
3102
|
}
|
|
3086
3103
|
if (command === "web") {
|
package/src/model-client.js
CHANGED
|
@@ -5,6 +5,7 @@ import { listAuxiliarySkills } from "./auxiliary-tools.js";
|
|
|
5
5
|
import { engineeringGuidanceForTask } from "./engineering-guidance.js";
|
|
6
6
|
import { formatSkillsForPrompt, selectSkillsForGoal } from "./skill-library.js";
|
|
7
7
|
import { platformInfo, platformLabel } from "./platform.js";
|
|
8
|
+
import { formatBehaviorContractForPrompt } from "./behavior-contract.js";
|
|
8
9
|
|
|
9
10
|
export function createClient(config) {
|
|
10
11
|
if (config.provider === "mock") {
|
|
@@ -498,7 +499,7 @@ export async function createPlan(client, config, state) {
|
|
|
498
499
|
{
|
|
499
500
|
role: "system",
|
|
500
501
|
content:
|
|
501
|
-
|
|
502
|
+
`You are planning a browser, shell, workspace, and coding-agent task. The plan is only a launchpad: after planning, the runtime will continue with tools until the task is complete or genuinely blocked. Prefer real workspace edits/checks over advice-only answers. If a local shell command can satisfy the goal, prefer that before browser actions. Treat any suggested start URL as optional. ${formatBehaviorContractForPrompt({ mode: "plan" })} Write a concise execution plan with 3 to 6 steps. Mention risks or blockers when relevant. Keep it short and practical.`,
|
|
502
503
|
},
|
|
503
504
|
{
|
|
504
505
|
role: "user",
|
package/src/project.js
CHANGED
|
@@ -6,6 +6,7 @@ import { promisify } from "node:util";
|
|
|
6
6
|
import { listAgentWrappers } from "./tool-wrappers.js";
|
|
7
7
|
import { getDockerSandboxStatus } from "./docker-sandbox.js";
|
|
8
8
|
import { platformInfo, platformLabel, platformSetupHints } from "./platform.js";
|
|
9
|
+
import { buildAgintiInstructions, normalizeInstructionTemplate } from "./behavior-contract.js";
|
|
9
10
|
import {
|
|
10
11
|
LEGACY_PROJECT_SESSIONS_DIR_NAME,
|
|
11
12
|
PROJECT_SESSIONS_DIR_NAME,
|
|
@@ -157,35 +158,8 @@ export async function ensureProjectSessionStorage(projectRoot = process.cwd()) {
|
|
|
157
158
|
return paths;
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
export function defaultAgintiInstructions() {
|
|
161
|
-
return
|
|
162
|
-
"# AGINTI.md",
|
|
163
|
-
"",
|
|
164
|
-
"Project instructions for AgInTiFlow agents.",
|
|
165
|
-
"",
|
|
166
|
-
"Edit this file directly or ask AgInTiFlow to update it during chat. Keep durable project preferences here; keep secrets in `.aginti/.env` instead.",
|
|
167
|
-
"",
|
|
168
|
-
"## Project Goals",
|
|
169
|
-
"",
|
|
170
|
-
"- Describe what this project is for.",
|
|
171
|
-
"- Note the main user-facing workflows the agent should preserve.",
|
|
172
|
-
"",
|
|
173
|
-
"## Agent Preferences",
|
|
174
|
-
"",
|
|
175
|
-
"- Prefer small, inspectable changes over broad rewrites.",
|
|
176
|
-
"- Read relevant files before editing.",
|
|
177
|
-
"- Run focused checks when tools and dependencies are available.",
|
|
178
|
-
"- Keep generated artifacts in project folders with clear names.",
|
|
179
|
-
"",
|
|
180
|
-
"## Useful Commands",
|
|
181
|
-
"",
|
|
182
|
-
"- Add build, test, lint, preview, or compile commands here.",
|
|
183
|
-
"",
|
|
184
|
-
"## Notes",
|
|
185
|
-
"",
|
|
186
|
-
"- Add project-specific terminology, style preferences, and known constraints here.",
|
|
187
|
-
"",
|
|
188
|
-
].join("\n");
|
|
161
|
+
export function defaultAgintiInstructions(template = "disciplined") {
|
|
162
|
+
return buildAgintiInstructions(template);
|
|
189
163
|
}
|
|
190
164
|
|
|
191
165
|
export async function readProjectInstructions(projectRoot = process.cwd(), { maxBytes = 24_000 } = {}) {
|
|
@@ -272,8 +246,9 @@ async function ensureLine(filePath, lines) {
|
|
|
272
246
|
return { changed: true, path: filePath, added: missing };
|
|
273
247
|
}
|
|
274
248
|
|
|
275
|
-
export async function initProject(projectRoot = process.cwd()) {
|
|
249
|
+
export async function initProject(projectRoot = process.cwd(), { template = "disciplined" } = {}) {
|
|
276
250
|
const paths = projectPaths(projectRoot);
|
|
251
|
+
const instructionTemplate = normalizeInstructionTemplate(template);
|
|
277
252
|
const created = [];
|
|
278
253
|
const updated = [];
|
|
279
254
|
const skipped = [];
|
|
@@ -300,7 +275,7 @@ export async function initProject(projectRoot = process.cwd()) {
|
|
|
300
275
|
await fsp.mkdir(paths.globalSessionsDir, { recursive: true });
|
|
301
276
|
await ensureFile(
|
|
302
277
|
paths.agintiInstructionsPath,
|
|
303
|
-
defaultAgintiInstructions()
|
|
278
|
+
defaultAgintiInstructions(instructionTemplate)
|
|
304
279
|
);
|
|
305
280
|
await ensureFile(
|
|
306
281
|
paths.controlReadmePath,
|
|
@@ -370,6 +345,7 @@ export async function initProject(projectRoot = process.cwd()) {
|
|
|
370
345
|
created,
|
|
371
346
|
updated,
|
|
372
347
|
skipped,
|
|
348
|
+
template: instructionTemplate,
|
|
373
349
|
};
|
|
374
350
|
}
|
|
375
351
|
|
package/src/scs-controller.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { redactSensitiveText, redactValue } from "./redaction.js";
|
|
2
|
+
import { formatBehaviorContractForPrompt, scsContractCriteria } from "./behavior-contract.js";
|
|
2
3
|
|
|
3
4
|
export const SCS_MODES = ["off", "on", "auto"];
|
|
4
5
|
|
|
@@ -67,9 +68,10 @@ export function shouldActivateScs(mode = "off", context = {}) {
|
|
|
67
68
|
function fallbackPlan(goal = "") {
|
|
68
69
|
return [
|
|
69
70
|
"1. Inspect the workspace, project instructions, and relevant manifests before editing.",
|
|
70
|
-
"2.
|
|
71
|
-
"3.
|
|
72
|
-
"4.
|
|
71
|
+
"2. State assumptions or ambiguities that could change scope, safety, or implementation.",
|
|
72
|
+
"3. Make the smallest coherent implementation or research pass that satisfies the request.",
|
|
73
|
+
"4. Run targeted checks or document why checks are unavailable.",
|
|
74
|
+
"5. Finish only after concrete evidence supports the result.",
|
|
73
75
|
].join("\n");
|
|
74
76
|
}
|
|
75
77
|
|
|
@@ -207,6 +209,7 @@ export function buildSupervisorInstruction(scs = {}) {
|
|
|
207
209
|
return [
|
|
208
210
|
"SCS mode is enabled. You are the supervisor executor.",
|
|
209
211
|
"Execute the approved phase plan. You may choose exact tools and paths, but you may not replace the strategic plan with a new one.",
|
|
212
|
+
formatBehaviorContractForPrompt(),
|
|
210
213
|
"If tool evidence invalidates the plan, stop repeating the failed path and explain the blocker through finish or wait for student review.",
|
|
211
214
|
"Approved phase plan:",
|
|
212
215
|
scs.plan || fallbackPlan(),
|
|
@@ -225,6 +228,7 @@ function normalizeCommitteePlan(parsed, goal = "") {
|
|
|
225
228
|
phaseGoal: compact(parsed.phase_goal || parsed.phaseGoal || goal || "Complete the requested task.", 260),
|
|
226
229
|
plan,
|
|
227
230
|
acceptanceCriteria: normalizeStringList(parsed.acceptance_criteria || parsed.acceptanceCriteria, [
|
|
231
|
+
...scsContractCriteria(),
|
|
228
232
|
"The requested outcome is present in the workspace or answer.",
|
|
229
233
|
"Relevant checks were run or skipped with a concrete reason.",
|
|
230
234
|
]),
|
|
@@ -280,7 +284,7 @@ export async function createScsPlan(client, config, state, context = {}) {
|
|
|
280
284
|
{
|
|
281
285
|
role: "system",
|
|
282
286
|
content:
|
|
283
|
-
|
|
287
|
+
`You are the SCS committee. Draft one practical next-phase plan only. You cannot approve it and you cannot call tools. ${formatBehaviorContractForPrompt({ mode: "plan" })} Return strict JSON with keys: role, phase_goal, plan, acceptance_criteria, allowed_tools, stop_conditions.`,
|
|
284
288
|
},
|
|
285
289
|
{
|
|
286
290
|
role: "user",
|
|
@@ -299,7 +303,7 @@ export async function createScsPlan(client, config, state, context = {}) {
|
|
|
299
303
|
{
|
|
300
304
|
role: "system",
|
|
301
305
|
content:
|
|
302
|
-
|
|
306
|
+
`You are the SCS student monitor. You may approve_plan or veto_plan only. Judge whether the committee phase plan is safe, scoped, minimal, permission-aware, and evidence-oriented. ${formatBehaviorContractForPrompt({ mode: "plan" })} Return strict JSON with keys: role, decision, confidence, evidence, reason, next_required_action.`,
|
|
303
307
|
},
|
|
304
308
|
{
|
|
305
309
|
role: "user",
|