@lazyingart/agintiflow 0.20.196 → 0.20.197
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 +5 -1
- package/bin/aginti-public-research.js +33 -0
- package/bin/aginti-safe-chat.js +34 -0
- package/docs/machine-run.md +18 -0
- package/docs/public-research-wrapper.md +162 -0
- package/docs/safe-chat.md +106 -0
- package/package.json +25 -4
- package/public/app.js +17 -0
- package/public/styles.css +11 -0
- package/references/agent-execution-policy-and-context-budget-2026-07-30.md +70 -0
- package/scripts/postinstall-webapp.js +2 -1
- package/scripts/seed-supervised-homework.js +330 -0
- package/scripts/smoke-agentlink.js +225 -0
- package/scripts/smoke-execution-policy.js +180 -0
- package/scripts/smoke-public-research-wrapper.js +277 -0
- package/scripts/smoke-run-stdin.js +74 -0
- package/scripts/smoke-safe-chat.js +653 -0
- package/scripts/smoke-scs-evidence-visibility.js +107 -0
- package/scripts/smoke-web-api.js +4 -4
- package/scripts/smoke-web-autostart.js +15 -0
- package/scripts/smoke-web-ui.js +3 -3
- package/src/agent-runner.js +124 -10
- package/src/cli.js +78 -0
- package/src/config.js +34 -1
- package/src/context-budget-controller.js +91 -0
- package/src/execution-policy.js +84 -0
- package/src/postinstall-policy.js +9 -0
- package/src/public-research-server.js +175 -0
- package/src/public-research-wrapper.js +517 -0
- package/src/safe-chat-server.js +231 -0
- package/src/safe-chat-wrapper.js +570 -0
- package/src/task-profiles.js +7 -0
- package/web.js +48 -0
package/README.md
CHANGED
|
@@ -109,7 +109,7 @@ Provider signup and key pages:
|
|
|
109
109
|
|
|
110
110
|
The CLI quietly auto-starts or reuses the local web UI from the same project. It tries `http://127.0.0.1:3210` first, then `3211`, `3212`, and so on if the port is already occupied by another project. The active URL is shown in the CLI launch header. If startup is blocked, stale, or unavailable, the same header row shows the recovery hint; run `/webapp [port]` inside the CLI to retry, `/webapp stop [port]` to stop the compatible local webapp, or `/webapp restart [port]` to stop and relaunch the local webapp with the current project and canonical `~/.agintiflow` session home. Use `/webapp disable` or `aginti webapp disable` to persistently disable automatic webapp startup and update-time restarts; use `/webapp enable` or `aginti webapp enable` to restore them. After a successful `aginti update` or accepted startup auto-update, AgInTiFlow restarts the compatible local webapp only when webapp auto-start is enabled.
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
Global CLI installation also makes a best-effort, non-blocking webapp initialization. Project dependency installs remain side-effect free by default; set `AGINTIFLOW_POSTINSTALL_WEBAPP=1` only when a local dependency install should start Studio. Installation never fails because the optional local webapp could not start.
|
|
113
113
|
|
|
114
114
|
Launch the web UI explicitly when you want a foreground web server:
|
|
115
115
|
|
|
@@ -152,6 +152,9 @@ aginti --language de
|
|
|
152
152
|
| Goal | Command |
|
|
153
153
|
| --- | --- |
|
|
154
154
|
| Start interactive chat | `aginti` or `aginti chat` |
|
|
155
|
+
| Run one clean machine turn | `printf '%s\n' 'task' \| aginti run --stdin --json --task-profile chatops --no-scs -s safe` |
|
|
156
|
+
| Start the narrow public-research backend | Project-local `./node_modules/.bin/aginti-public-research --port 3211`; see [deployment boundary](docs/public-research-wrapper.md) |
|
|
157
|
+
| Start the authenticated text-only fallback | Project-local `./node_modules/.bin/aginti-safe-chat --port 3212`; see [safe-chat boundary](docs/safe-chat.md) |
|
|
155
158
|
| Start local web app | Auto-starts with `aginti`; detached command is `aginti webapp`; disable/enable auto-start with `aginti webapp disable` / `aginti webapp enable`; stop with `aginti webapp stop`; restart with `aginti webapp restart`; foreground mode is `aginti web --port 3210` |
|
|
156
159
|
| Save provider keys | `aginti auth`, `/auth`, `/login` |
|
|
157
160
|
| Review current repo | `/review [focus]` |
|
|
@@ -400,6 +403,7 @@ More detail:
|
|
|
400
403
|
| Runtime modes and autonomy | [docs/runtime-modes-and-autonomy.md](docs/runtime-modes-and-autonomy.md) |
|
|
401
404
|
| Skills and tools | [docs/skills-and-tools.md](docs/skills-and-tools.md) |
|
|
402
405
|
| Image reading and web research | [docs/perception-and-web-research.md](docs/perception-and-web-research.md) |
|
|
406
|
+
| Server-owned text-only fallback | [docs/safe-chat.md](docs/safe-chat.md) |
|
|
403
407
|
| Skill Mesh | [docs/skillmesh.md](docs/skillmesh.md) |
|
|
404
408
|
| Housekeeping logs | [docs/housekeeping.md](docs/housekeeping.md) |
|
|
405
409
|
| npm publishing | [docs/npm-publishing.md](docs/npm-publishing.md) |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { listenPublicResearchServer } from "../src/public-research-server.js";
|
|
3
|
+
|
|
4
|
+
function optionValue(argv, name) {
|
|
5
|
+
const index = argv.indexOf(name);
|
|
6
|
+
return index >= 0 ? argv[index + 1] : "";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const argv = process.argv.slice(2);
|
|
10
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
11
|
+
console.log("Usage: aginti-public-research [--host 127.0.0.1] [--port 3211]");
|
|
12
|
+
console.log("Starts only the fail-closed public research API; it does not start AgInTiFlow Studio or chat.");
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const running = await listenPublicResearchServer({
|
|
17
|
+
host: optionValue(argv, "--host") || undefined,
|
|
18
|
+
port: optionValue(argv, "--port") || undefined,
|
|
19
|
+
}).catch((error) => {
|
|
20
|
+
console.error(`aginti-public-research unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
21
|
+
process.exitCode = 1;
|
|
22
|
+
return null;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (running) {
|
|
26
|
+
console.log(`aginti-public-research: ${running.url}`);
|
|
27
|
+
const stop = () => {
|
|
28
|
+
running.server.close(() => process.exit(0));
|
|
29
|
+
setTimeout(() => process.exit(1), 1500).unref?.();
|
|
30
|
+
};
|
|
31
|
+
process.once("SIGINT", stop);
|
|
32
|
+
process.once("SIGTERM", stop);
|
|
33
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { listenSafeChatServer } from "../src/safe-chat-server.js";
|
|
3
|
+
import { redactSensitiveText } from "../src/redaction.js";
|
|
4
|
+
|
|
5
|
+
function optionValue(argv, name) {
|
|
6
|
+
const index = argv.indexOf(name);
|
|
7
|
+
return index >= 0 ? argv[index + 1] : "";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const argv = process.argv.slice(2);
|
|
11
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
12
|
+
console.log("Usage: aginti-safe-chat [--host 127.0.0.1] [--port 3212]");
|
|
13
|
+
console.log("Starts the authenticated loopback-only, server-owned DeepSeek text fallback.");
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const running = await listenSafeChatServer({
|
|
18
|
+
host: optionValue(argv, "--host") || undefined,
|
|
19
|
+
port: optionValue(argv, "--port") || undefined,
|
|
20
|
+
}).catch((error) => {
|
|
21
|
+
console.error(`aginti-safe-chat unavailable: ${redactSensitiveText(error instanceof Error ? error.message : String(error))}`);
|
|
22
|
+
process.exitCode = 1;
|
|
23
|
+
return null;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (running) {
|
|
27
|
+
console.log(`aginti-safe-chat: ${running.url}`);
|
|
28
|
+
const stop = () => {
|
|
29
|
+
running.server.close(() => process.exit(0));
|
|
30
|
+
setTimeout(() => process.exit(1), 1500).unref?.();
|
|
31
|
+
};
|
|
32
|
+
process.once("SIGINT", stop);
|
|
33
|
+
process.once("SIGTERM", stop);
|
|
34
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Machine Run Interface
|
|
2
|
+
|
|
3
|
+
Use `aginti run` when another local application needs one AgInTiFlow turn without interactive CLI output.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
printf '%s\n' 'Summarize this evidence.' |
|
|
7
|
+
aginti run --stdin --json --task-profile chatops --no-scs -s safe
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
`--json` writes exactly one JSON object to stdout:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{"ok":true,"sessionId":"...","result":"...","stopped":false,"failed":false,"reason":""}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Runtime headers, plans, tool logs, and sandbox diagnostics are suppressed. A missing key, timeout, empty result, or stopped run returns `ok: false` and a nonzero exit code. Callers must forward only `result`, never stderr or the full runtime state.
|
|
17
|
+
|
|
18
|
+
The `chatops` profile treats the current request as the sole source of authority. It avoids unrelated workspace artifacts and does not use tools for simple conversation. Use `-s safe` for read-only routing and research. Use `-s normal` with the default Docker workspace only when the request needs current-project artifacts. Do not use `-s danger` for unattended chat transports.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Public Research Wrapper
|
|
2
|
+
|
|
3
|
+
AgInTiFlow exposes an optional fail-closed backend route for apps that need a narrow server-owned research helper without exposing model or provider controls to clients.
|
|
4
|
+
|
|
5
|
+
This route is intended for product backends such as EchoMind AI Agent. It is not a replacement for normal AgInTiFlow chat.
|
|
6
|
+
|
|
7
|
+
## Capability Classification
|
|
8
|
+
|
|
9
|
+
- **Existing capability:** AgInTiFlow already has a server-owned Codex exec adapter, input/output redaction, bounded subprocess handling, and a disposable per-request workspace.
|
|
10
|
+
- **System-level gap addressed here:** normal AgInTiFlow chat and Studio expose too much tool and API surface for a narrow application backend. The standalone server exposes only health, readiness, status, and research routes. Prompts travel over stdin rather than process arguments.
|
|
11
|
+
- **Deployment/setup gap:** hard host-filesystem and domain-level network isolation cannot be created honestly by an npm process alone. Production must provide the external container/VM and egress firewall described below. The route remains unavailable until that boundary is explicitly attested.
|
|
12
|
+
|
|
13
|
+
The EchoMind server should call this narrow service only for explicit public-research work. Normal EchoMind chat does not need to invoke AgInTiFlow.
|
|
14
|
+
|
|
15
|
+
## Project-Local Installation
|
|
16
|
+
|
|
17
|
+
Install without a global package:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install --save-exact @lazyingart/agintiflow
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Project dependency installation does not auto-start AgInTiFlow Studio. The package postinstall hook reserves that behavior for global CLI installs or explicit `AGINTIFLOW_POSTINSTALL_WEBAPP=1` opt-in.
|
|
24
|
+
|
|
25
|
+
Start only the narrow service:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
./node_modules/.bin/aginti-public-research --host 127.0.0.1 --port 3211
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Programmatic imports are also available:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import { runPublicResearchWrapper } from "@lazyingart/agintiflow/public-research";
|
|
35
|
+
import { listenPublicResearchServer } from "@lazyingart/agintiflow/public-research/server";
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Importing these modules does not start AgInTiFlow chat, Studio, sessions, model routing, or project tools.
|
|
39
|
+
|
|
40
|
+
## API
|
|
41
|
+
|
|
42
|
+
`GET /ready`
|
|
43
|
+
|
|
44
|
+
Returns `200` only when the route is available, otherwise `503`.
|
|
45
|
+
|
|
46
|
+
`GET /v1/research/status`
|
|
47
|
+
|
|
48
|
+
Returns availability, policy, and limits. It intentionally does not return model names.
|
|
49
|
+
|
|
50
|
+
`POST /v1/research`
|
|
51
|
+
|
|
52
|
+
Request:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"query": "Summarize public NIH guidance about reproducible literature searches.",
|
|
57
|
+
"context": "Optional non-secret app context.",
|
|
58
|
+
"allowedDomains": ["nih.gov"]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Response:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"ok": true,
|
|
67
|
+
"feature": "public-research-wrapper",
|
|
68
|
+
"route": "server-owned-codex",
|
|
69
|
+
"modelExposed": false,
|
|
70
|
+
"answer": "..."
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Compatibility aliases remain available at `/api/public-research/status` and `/api/public-research`.
|
|
75
|
+
|
|
76
|
+
The endpoint rejects client-controlled provider, model, cwd, env, token, sandbox, and wrapper fields. Successful answers must include citations whose domains are within the server allowlist. Process stderr/stdout diagnostics are never returned to clients.
|
|
77
|
+
|
|
78
|
+
## Enablement
|
|
79
|
+
|
|
80
|
+
The route is disabled by default and fails closed until all required server-side conditions are true:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
export AGINTI_PUBLIC_RESEARCH_ENABLED=1
|
|
84
|
+
export AGINTI_PUBLIC_RESEARCH_BOUNDARY=external-strict
|
|
85
|
+
export AGINTI_PUBLIC_RESEARCH_CODEX_HOME=/srv/aginti-public-codex
|
|
86
|
+
export AGINTI_PUBLIC_RESEARCH_ALLOWED_DOMAINS="nih.gov pubmed.ncbi.nlm.nih.gov arxiv.org"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Optional bounds:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
export AGINTI_PUBLIC_RESEARCH_TIMEOUT_MS=90000
|
|
93
|
+
export AGINTI_PUBLIC_RESEARCH_MAX_CONCURRENCY=1
|
|
94
|
+
export AGINTI_PUBLIC_RESEARCH_CODEX_MODEL=server-owned-model
|
|
95
|
+
export AGINTI_PUBLIC_RESEARCH_CODEX_REASONING=medium
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Do not set `AGINTI_PUBLIC_RESEARCH_CODEX_HOME` to the user's normal home directory or normal `~/.codex`. Use a dedicated service-owned Codex profile.
|
|
99
|
+
|
|
100
|
+
`AGINTI_PUBLIC_RESEARCH_BOUNDARY=external-strict` is an operator attestation, not a substitute for isolation. Set it only after the deployment requirements below are enforced. Without it, readiness fails closed.
|
|
101
|
+
|
|
102
|
+
The standalone server binds to loopback by default. Remote binding additionally requires:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
export AGINTI_PUBLIC_RESEARCH_ALLOW_REMOTE=1
|
|
106
|
+
export AGINTI_PUBLIC_RESEARCH_BEARER_TOKEN=server-owned-random-value
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Do not pass this bearer token to end-user clients. EchoMind server-side code owns it.
|
|
110
|
+
|
|
111
|
+
## Security Boundary
|
|
112
|
+
|
|
113
|
+
The wrapper:
|
|
114
|
+
|
|
115
|
+
- runs `codex exec --ephemeral` from a disposable temp workspace;
|
|
116
|
+
- passes the research prompt through stdin, not command-line arguments;
|
|
117
|
+
- sets `HOME`, `XDG_CONFIG_HOME`, `XDG_CACHE_HOME`, and temp paths to disposable directories;
|
|
118
|
+
- passes only a minimal environment to the Codex process;
|
|
119
|
+
- uses a dedicated `CODEX_HOME` supplied by the server operator;
|
|
120
|
+
- rejects likely secret inputs before invoking Codex;
|
|
121
|
+
- rejects secret-like model output and does not return process diagnostics;
|
|
122
|
+
- enforces timeout, output-size, and concurrency limits;
|
|
123
|
+
- configures the Codex web-search tool with the server-selected domain allowlist;
|
|
124
|
+
- requires the same public allowlist in the research prompt and returned citations;
|
|
125
|
+
- fails closed if disabled, unavailable, or not configured.
|
|
126
|
+
|
|
127
|
+
The npm process cannot prove that the host filesystem or arbitrary network destinations are unreachable. A production deployment must enforce all of the following before setting `AGINTI_PUBLIC_RESEARCH_BOUNDARY=external-strict`:
|
|
128
|
+
|
|
129
|
+
1. Run the standalone service as a non-root user inside a dedicated container, microVM, or equivalent sandbox.
|
|
130
|
+
2. Mount no host home, application repository, EchoMind data, Docker socket, SSH agent, or cloud metadata credentials.
|
|
131
|
+
3. Mount only the dedicated Codex service profile needed for authentication, preferably read-only.
|
|
132
|
+
4. Use an ephemeral writable filesystem or tmpfs with bounded size; discard it when the service restarts.
|
|
133
|
+
5. Drop capabilities and apply no-new-privileges, PID, memory, CPU, wall-time, and process limits.
|
|
134
|
+
6. Deny private, loopback, link-local, and metadata destinations at the network boundary.
|
|
135
|
+
7. Permit only required Codex control-plane endpoints at the local egress boundary. Codex web-search source access is separately constrained with `tools.web_search.allowed_domains`; do not enable alternate browser, MCP, or shell-network tools in this service.
|
|
136
|
+
8. Do not log request bodies, authorization headers, Codex prompts, subprocess arguments, or model output.
|
|
137
|
+
|
|
138
|
+
Codex `--sandbox read-only` is retained as defense in depth, but it is not the host-isolation boundary: read-only mode still permits reads. The external sandbox is what must prevent host home and repository access.
|
|
139
|
+
|
|
140
|
+
## Smallest Deployment Shape
|
|
141
|
+
|
|
142
|
+
Use one narrow sidecar/service:
|
|
143
|
+
|
|
144
|
+
```text
|
|
145
|
+
EchoMind client
|
|
146
|
+
-> EchoMind server (decides whether public research is needed)
|
|
147
|
+
-> loopback/private authenticated aginti-public-research
|
|
148
|
+
-> disposable codex exec worker
|
|
149
|
+
-> allowlisted egress boundary
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Keep concurrency at `1` initially, timeout at or below `90s`, and output below `12k` characters. Scale by adding isolated service replicas rather than sharing host access or widening the route.
|
|
153
|
+
|
|
154
|
+
## EchoMind Integration Shape
|
|
155
|
+
|
|
156
|
+
EchoMind should call this route only for explicit public research tasks:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
EchoMind client -> EchoMind server -> narrow research service -> server-owned Codex exec
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
EchoMind clients should never send model names, provider names, keys, cwd values, user home paths, repository paths, or secrets to this route.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Safe Chat
|
|
2
|
+
|
|
3
|
+
AgInTiFlow provides an optional narrow text fallback for server applications. It calls a server-owned DeepSeek route directly and intentionally has no agent loop, tools, filesystem, shell, browser, sessions, artifacts, or persistence.
|
|
4
|
+
|
|
5
|
+
This service is suitable for a bounded fallback response after an application has already classified a primary provider quota or capacity error. It must not be exposed directly to an end-user client.
|
|
6
|
+
|
|
7
|
+
## Install and Start
|
|
8
|
+
|
|
9
|
+
After a release containing this capability is published, install the package locally and start only the narrow service:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install --save-exact @lazyingart/agintiflow
|
|
13
|
+
./node_modules/.bin/aginti-safe-chat --host 127.0.0.1 --port 3212
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Required server environment:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
export AGINTI_SAFE_CHAT_ENABLED=1
|
|
20
|
+
export AGINTI_SAFE_CHAT_BEARER_TOKEN=server-owned-random-value
|
|
21
|
+
export DEEPSEEK_API_KEY=server-owned-deepseek-key
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Optional server-owned configuration:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
export AGINTI_SAFE_CHAT_DEEPSEEK_MODEL=deepseek-v4-flash
|
|
28
|
+
export AGINTI_SAFE_CHAT_DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
|
|
29
|
+
export AGINTI_SAFE_CHAT_TIMEOUT_MS=60000
|
|
30
|
+
export AGINTI_SAFE_CHAT_MAX_CONCURRENCY=1
|
|
31
|
+
export AGINTI_SAFE_CHAT_MAX_TOKENS=2048
|
|
32
|
+
export AGINTI_SAFE_CHAT_OUTPUT_CHARS=12000
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Do not put the bearer token or DeepSeek key in client code, request bodies, command-line arguments, logs, or source control. Use a protected service environment file or secret store.
|
|
36
|
+
The bearer token must contain at least 24 characters.
|
|
37
|
+
The provider endpoint is fail-closed to the exact production hostname `api.deepseek.com` over HTTPS. Credentials, query strings, fragments, alternate hosts, and non-default ports are rejected.
|
|
38
|
+
|
|
39
|
+
## API
|
|
40
|
+
|
|
41
|
+
Every endpoint, including health and readiness, requires:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
Authorization: Bearer <server-owned-token>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`GET /health`
|
|
48
|
+
|
|
49
|
+
`GET /ready`
|
|
50
|
+
|
|
51
|
+
`GET /v1/chat/status`
|
|
52
|
+
|
|
53
|
+
`POST /v1/chat`
|
|
54
|
+
|
|
55
|
+
Request:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"prompt": "Explain this idea briefly.",
|
|
60
|
+
"history": [
|
|
61
|
+
{ "role": "user", "content": "Earlier question" },
|
|
62
|
+
{ "role": "assistant", "content": "Earlier answer" }
|
|
63
|
+
],
|
|
64
|
+
"locale": "en"
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Response:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"ok": true,
|
|
73
|
+
"feature": "safe-chat",
|
|
74
|
+
"answer": "...",
|
|
75
|
+
"code": "ok",
|
|
76
|
+
"retryable": false,
|
|
77
|
+
"modelExposed": false,
|
|
78
|
+
"providerExposed": false
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Compatibility aliases are available at `/api/safe-chat/status` and `/api/safe-chat`.
|
|
83
|
+
|
|
84
|
+
The request schema accepts only `prompt`, bounded `history`, and an optional short locale. Client-controlled provider, model, key, base URL, system prompt, tool, filesystem, command, environment, and sandbox fields are rejected. Responses never expose provider/model names or upstream diagnostics.
|
|
85
|
+
|
|
86
|
+
If the calling server cancels a programmatic request or its HTTP connection closes before the response, the upstream request is aborted. Programmatic callers receive a frozen, non-retryable `cancelled` result; a disconnected HTTP caller receives no late response.
|
|
87
|
+
|
|
88
|
+
Programmatic imports:
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
import { getSafeChatStatus, runSafeChat } from "@lazyingart/agintiflow/safe-chat";
|
|
92
|
+
import { listenSafeChatServer } from "@lazyingart/agintiflow/safe-chat/server";
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Deployment Boundary
|
|
96
|
+
|
|
97
|
+
- Bind only to loopback. The server rejects remote bind addresses.
|
|
98
|
+
- Require a separate bearer token even on loopback.
|
|
99
|
+
- Run under a dedicated non-root service account with a minimal environment.
|
|
100
|
+
- Give the process only the DeepSeek credential and service configuration it needs.
|
|
101
|
+
- Do not source an interactive shell profile from the service.
|
|
102
|
+
- Do not mount application repositories, user homes, Docker sockets, SSH agents, or cloud metadata credentials.
|
|
103
|
+
- Do not log authorization headers, request bodies, prompts, responses, or provider diagnostics.
|
|
104
|
+
- Keep concurrency and output limits low, and let the calling application own account quotas, idempotency, cancellation, and fallback eligibility.
|
|
105
|
+
|
|
106
|
+
The caller should invoke this service at most once for a classified primary-provider quota or capacity failure. Authentication, policy, invalid-input, and unsafe-output errors must remain fail-closed.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.197",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -30,6 +30,14 @@
|
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
|
+
"exports": {
|
|
34
|
+
"./public-research": "./src/public-research-wrapper.js",
|
|
35
|
+
"./public-research/server": "./src/public-research-server.js",
|
|
36
|
+
"./safe-chat": "./src/safe-chat-wrapper.js",
|
|
37
|
+
"./safe-chat/server": "./src/safe-chat-server.js",
|
|
38
|
+
"./package.json": "./package.json",
|
|
39
|
+
"./*": "./*"
|
|
40
|
+
},
|
|
33
41
|
"files": [
|
|
34
42
|
"AGENTS.md",
|
|
35
43
|
"LICENSE",
|
|
@@ -52,7 +60,9 @@
|
|
|
52
60
|
"scripts/setup-agent-toolchain-docker.sh",
|
|
53
61
|
"scripts/real-deepseek-capabilities.js",
|
|
54
62
|
"scripts/postinstall-webapp.js",
|
|
63
|
+
"scripts/seed-supervised-homework.js",
|
|
55
64
|
"scripts/smoke-auxiliary-tools.js",
|
|
65
|
+
"scripts/smoke-agentlink.js",
|
|
56
66
|
"scripts/smoke-auth.js",
|
|
57
67
|
"scripts/smoke-aaps-adapter.js",
|
|
58
68
|
"scripts/smoke-canvas-artifacts.js",
|
|
@@ -60,16 +70,21 @@
|
|
|
60
70
|
"scripts/smoke-coding-tools.js",
|
|
61
71
|
"scripts/smoke-docker-command.js",
|
|
62
72
|
"scripts/smoke-dynamic-step-budget.js",
|
|
73
|
+
"scripts/smoke-execution-policy.js",
|
|
63
74
|
"scripts/smoke-capabilities.js",
|
|
64
75
|
"scripts/smoke-auto-update.js",
|
|
65
76
|
"scripts/smoke-inbox.js",
|
|
66
77
|
"scripts/smoke-long-jobs.js",
|
|
78
|
+
"scripts/smoke-run-stdin.js",
|
|
67
79
|
"scripts/smoke-mcp.js",
|
|
68
80
|
"scripts/fixtures/mcp-stdio-smoke-server.mjs",
|
|
69
81
|
"scripts/smoke-model-roles.js",
|
|
70
82
|
"scripts/smoke-platform.js",
|
|
71
83
|
"scripts/smoke-perception-research.js",
|
|
72
84
|
"scripts/smoke-permission-modes.js",
|
|
85
|
+
"scripts/smoke-public-research-wrapper.js",
|
|
86
|
+
"scripts/smoke-safe-chat.js",
|
|
87
|
+
"scripts/smoke-scs-evidence-visibility.js",
|
|
73
88
|
"scripts/smoke-runtime-compat.js",
|
|
74
89
|
"scripts/smoke-skills.js",
|
|
75
90
|
"scripts/smoke-skillmesh.js",
|
|
@@ -87,15 +102,18 @@
|
|
|
87
102
|
],
|
|
88
103
|
"bin": {
|
|
89
104
|
"aginti": "bin/aginti-cli.js",
|
|
90
|
-
"aginti-cli": "bin/aginti-cli.js"
|
|
105
|
+
"aginti-cli": "bin/aginti-cli.js",
|
|
106
|
+
"aginti-public-research": "bin/aginti-public-research.js",
|
|
107
|
+
"aginti-safe-chat": "bin/aginti-safe-chat.js"
|
|
91
108
|
},
|
|
92
109
|
"scripts": {
|
|
93
110
|
"start": "node run.js",
|
|
94
111
|
"web": "node web.js",
|
|
95
|
-
"check": "node --check run.js && node --check web.js && node --check bin/aginti-cli.js && node --check src/*.js && node --check src/mcp/*.js && node --check public/app.js && node --check scripts/seed-supervised-homework.js && node --check scripts/smoke-agentlink.js && node --check scripts/smoke-mcp.js && node --check scripts/smoke-web-ui.js && node --check scripts/smoke-scs-evidence-visibility.js && node --check scripts/fixtures/mcp-stdio-smoke-server.mjs",
|
|
112
|
+
"check": "node --check run.js && node --check web.js && node --check bin/aginti-cli.js && node --check bin/aginti-public-research.js && node --check bin/aginti-safe-chat.js && node --check src/*.js && node --check src/mcp/*.js && node --check public/app.js && node --check scripts/postinstall-webapp.js && node --check scripts/seed-supervised-homework.js && node --check scripts/smoke-agentlink.js && node --check scripts/smoke-execution-policy.js && node --check scripts/smoke-mcp.js && node --check scripts/smoke-public-research-wrapper.js && node --check scripts/smoke-safe-chat.js && node --check scripts/smoke-web-ui.js && node --check scripts/smoke-scs-evidence-visibility.js && node --check scripts/fixtures/mcp-stdio-smoke-server.mjs",
|
|
96
113
|
"setup:toolchain-docker": "scripts/setup-agent-toolchain-docker.sh",
|
|
97
114
|
"smoke:coding-tools": "node scripts/smoke-coding-tools.js",
|
|
98
115
|
"smoke:dynamic-step-budget": "node scripts/smoke-dynamic-step-budget.js",
|
|
116
|
+
"smoke:execution-policy": "node scripts/smoke-execution-policy.js",
|
|
99
117
|
"smoke:aaps-adapter": "node scripts/smoke-aaps-adapter.js",
|
|
100
118
|
"smoke:auxiliary-tools": "node scripts/smoke-auxiliary-tools.js",
|
|
101
119
|
"smoke:auth": "node scripts/smoke-auth.js",
|
|
@@ -109,11 +127,14 @@
|
|
|
109
127
|
"smoke:toolchain-docker": "node scripts/smoke-toolchain-docker.js",
|
|
110
128
|
"smoke:inbox": "node scripts/smoke-inbox.js",
|
|
111
129
|
"smoke:long-jobs": "node scripts/smoke-long-jobs.js",
|
|
130
|
+
"smoke:run-stdin": "node scripts/smoke-run-stdin.js",
|
|
112
131
|
"smoke:mcp": "node scripts/smoke-mcp.js",
|
|
113
132
|
"smoke:model-roles": "node scripts/smoke-model-roles.js",
|
|
114
133
|
"smoke:platform": "node scripts/smoke-platform.js",
|
|
115
134
|
"smoke:perception-research": "node scripts/smoke-perception-research.js",
|
|
116
135
|
"smoke:permission-modes": "node scripts/smoke-permission-modes.js",
|
|
136
|
+
"smoke:public-research": "node scripts/smoke-public-research-wrapper.js",
|
|
137
|
+
"smoke:safe-chat": "node scripts/smoke-safe-chat.js",
|
|
117
138
|
"smoke:runtime-compat": "node scripts/smoke-runtime-compat.js",
|
|
118
139
|
"smoke:tmux-tools": "node scripts/smoke-tmux-tools.js",
|
|
119
140
|
"smoke:web-api": "node scripts/smoke-web-api.js",
|
|
@@ -128,7 +149,7 @@
|
|
|
128
149
|
"storage:migrate": "node bin/aginti-cli.js storage migrate",
|
|
129
150
|
"publish:env": "node scripts/npm-publish-from-env.js publish --access public",
|
|
130
151
|
"publish:env:whoami": "node scripts/npm-publish-from-env.js whoami",
|
|
131
|
-
"test": "npm run check && npm run smoke:runtime-compat && npm run smoke:autoupdate && npm run smoke:web-api && npm run smoke:web-ui && npm run smoke:web-autostart && npm run smoke:webapp-command && npm run smoke:web-port-fallback && npm run smoke:docker-command && npm run smoke:coding-tools && npm run smoke:dynamic-step-budget && npm run smoke:aaps-adapter && npm run smoke:auxiliary-tools && npm run smoke:perception-research && npm run smoke:auth && npm run smoke:agentlink && npm run smoke:canvas-artifacts && npm run smoke:capabilities && npm run smoke:mcp && npm run smoke:model-roles && npm run smoke:platform && npm run smoke:permission-modes && npm run smoke:skills && npm run smoke:skillmesh && npm run smoke:tmux-tools && npm run smoke:long-jobs && npm run smoke:cli-chat && npm run smoke:inbox",
|
|
152
|
+
"test": "npm run check && npm run smoke:runtime-compat && npm run smoke:autoupdate && npm run smoke:web-api && npm run smoke:web-ui && npm run smoke:web-autostart && npm run smoke:webapp-command && npm run smoke:web-port-fallback && npm run smoke:docker-command && npm run smoke:coding-tools && npm run smoke:dynamic-step-budget && npm run smoke:execution-policy && npm run smoke:aaps-adapter && npm run smoke:auxiliary-tools && npm run smoke:perception-research && npm run smoke:public-research && npm run smoke:safe-chat && npm run smoke:auth && npm run smoke:agentlink && npm run smoke:canvas-artifacts && npm run smoke:capabilities && npm run smoke:mcp && npm run smoke:model-roles && npm run smoke:platform && npm run smoke:permission-modes && npm run smoke:skills && npm run smoke:skillmesh && npm run smoke:tmux-tools && npm run smoke:long-jobs && npm run smoke:run-stdin && npm run smoke:cli-chat && npm run smoke:inbox",
|
|
132
153
|
"pack:dry-run": "npm pack --dry-run",
|
|
133
154
|
"smoke:capabilities": "node scripts/smoke-capabilities.js"
|
|
134
155
|
},
|
package/public/app.js
CHANGED
|
@@ -2196,6 +2196,21 @@ function renderPlanEvent(entry) {
|
|
|
2196
2196
|
`;
|
|
2197
2197
|
}
|
|
2198
2198
|
|
|
2199
|
+
function renderExecutionEvent(entry) {
|
|
2200
|
+
const data = entry.data || {};
|
|
2201
|
+
const tier = data.tier || (entry.eventType === "plan.skipped" ? "focused" : "execution");
|
|
2202
|
+
const reason = data.reason || entry.content || "";
|
|
2203
|
+
return `
|
|
2204
|
+
<article class="event-card event-focused">
|
|
2205
|
+
<div class="event-card-meta">
|
|
2206
|
+
<span>${escapeHtml(tier)}</span>
|
|
2207
|
+
<span>${entry.at ? escapeHtml(new Date(entry.at).toLocaleString()) : ""}</span>
|
|
2208
|
+
</div>
|
|
2209
|
+
${reason ? `<div class="chat-content">${escapeHtml(reason)}</div>` : ""}
|
|
2210
|
+
</article>
|
|
2211
|
+
`;
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2199
2214
|
function embeddedWorkspaceChangesFromText(value = "") {
|
|
2200
2215
|
const lines = String(value || "").split(/\r?\n/);
|
|
2201
2216
|
const changes = [];
|
|
@@ -2376,6 +2391,7 @@ function renderStatusEvent(entry) {
|
|
|
2376
2391
|
function renderStructuredEvent(entry) {
|
|
2377
2392
|
const message = entry.message || entry.eventType || "";
|
|
2378
2393
|
if (message === "plan.created") return renderPlanEvent(entry);
|
|
2394
|
+
if (message === "plan.skipped" || message === "execution.policy_selected") return renderExecutionEvent(entry);
|
|
2379
2395
|
if (message === "command.output") return renderCommandOutputLog(entry);
|
|
2380
2396
|
if (message === "file.changed") return renderWorkspaceChangeEvent(entry);
|
|
2381
2397
|
if (message === "tool.blocked" && entry.data?.permissionAdvice) return renderPermissionApproval(entry);
|
|
@@ -2396,6 +2412,7 @@ function renderStructuredEvent(entry) {
|
|
|
2396
2412
|
}
|
|
2397
2413
|
if (
|
|
2398
2414
|
message === "budget.initialized" ||
|
|
2415
|
+
message === "history.compacted_for_context_budget" ||
|
|
2399
2416
|
message === "conversation.continued" ||
|
|
2400
2417
|
message === "conversation.queued_input_applied" ||
|
|
2401
2418
|
message === "session.finished" ||
|
package/public/styles.css
CHANGED
|
@@ -1594,10 +1594,21 @@ button.danger {
|
|
|
1594
1594
|
linear-gradient(180deg, rgba(240, 253, 250, 0.9), rgba(255, 251, 235, 0.74));
|
|
1595
1595
|
}
|
|
1596
1596
|
|
|
1597
|
+
.event-focused {
|
|
1598
|
+
border-color: rgba(14, 165, 233, 0.34);
|
|
1599
|
+
background:
|
|
1600
|
+
radial-gradient(circle at 0% 0%, rgba(14, 165, 233, 0.15), transparent 28%),
|
|
1601
|
+
linear-gradient(180deg, rgba(240, 249, 255, 0.9), rgba(240, 253, 250, 0.74));
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1597
1604
|
#logs .event-plan {
|
|
1598
1605
|
background: rgba(15, 23, 42, 0.58);
|
|
1599
1606
|
}
|
|
1600
1607
|
|
|
1608
|
+
#logs .event-focused {
|
|
1609
|
+
background: rgba(15, 23, 42, 0.58);
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1601
1612
|
.event-patch {
|
|
1602
1613
|
border-color: rgba(192, 132, 252, 0.38);
|
|
1603
1614
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Agent Execution Policy and Context Budget Review
|
|
2
|
+
|
|
3
|
+
Date: 2026-07-30
|
|
4
|
+
|
|
5
|
+
## Goal
|
|
6
|
+
|
|
7
|
+
Make AgInTiFlow fast for simple work and durable for complex work without turning isolated task examples into hard-coded behavior.
|
|
8
|
+
|
|
9
|
+
## Sibling Evidence
|
|
10
|
+
|
|
11
|
+
- Claw Code separates optional planning and effort controls from ordinary execution. Its runtime performs threshold-based automatic compaction and records removed-message metadata in `rust/crates/runtime/src/compact.rs`, `conversation.rs`, and `session.rs`.
|
|
12
|
+
- Gemini CLI runs `ChatCompressionService` before long histories become unstable and exposes a configurable compression threshold in `packages/core/src/context/chatCompressionService.ts`, `core/client.ts`, and `config/config.ts`. It also keeps loop detection separate from compression.
|
|
13
|
+
- Codex has model-context-window-aware automatic compaction, explicit token-budget guidance, and regression tests for repeated compaction and post-compaction growth in `codex-rs/core/tests/suite/compact.rs` and `token_budget.rs`.
|
|
14
|
+
- AgInTi-OverTree added a useful external-agent boundary in `src/codex-agent.js`: process-group cancellation, structured event ingestion, resumable thread identity, and terminal-state persistence. Its `src/workspace-backend.js` also rejects path escape and symlink traversal. These mechanisms are reusable; paper-specific naming and UI modules are not.
|
|
15
|
+
- Copilot SDK keeps session lifecycle, event transport, tool execution, and cancellation behind typed session APIs. The reusable lesson is lifecycle separation, not provider-specific session types.
|
|
16
|
+
|
|
17
|
+
## AgInTiFlow Findings
|
|
18
|
+
|
|
19
|
+
### System-level gaps
|
|
20
|
+
|
|
21
|
+
1. Every non-greeting run made a separate planning model request, even when smart routing had already assigned a low complexity score.
|
|
22
|
+
2. The default initial step budget remained 24 or more for simple focused tasks.
|
|
23
|
+
3. History compaction only happened after a provider timeout. Long successful runs could carry repeated snapshots and tool results until latency or provider failure forced recovery.
|
|
24
|
+
4. Execution decisions were distributed across model routing, SCS activation, parallel scouts, surgical context, and step budgets without one persisted execution-policy record.
|
|
25
|
+
5. Task profiles declare tool groups, but the runtime still sends the full tool schema. Profile-aware tool-surface reduction remains a future system improvement.
|
|
26
|
+
|
|
27
|
+
### Core-skill gaps
|
|
28
|
+
|
|
29
|
+
- Long/background jobs already have a deterministic handoff tool and do not need another prompt-only workaround.
|
|
30
|
+
- Writing, JSON, image/perception, MCP, AgentLink, and research specialists exist. Their main remaining issue is routing them through a smaller initial capability surface when the task is narrow.
|
|
31
|
+
|
|
32
|
+
## Implemented Policy
|
|
33
|
+
|
|
34
|
+
AgInTiFlow now selects one of two execution tiers:
|
|
35
|
+
|
|
36
|
+
- `focused`: low-complexity work starts directly in the agent loop, skips a separate planning request, and defaults to at most 12 initial steps. Explicit user step limits are preserved.
|
|
37
|
+
- `thorough`: complex routing, complexity score 3 or higher, SCS, and high-risk task profiles retain planning, scouts where applicable, dynamic budgets, and evidence validation.
|
|
38
|
+
|
|
39
|
+
The runtime records `execution.policy_selected` and either `plan.created` or `plan.skipped`. This makes the decision visible in saved sessions, CLI output, and the web timeline.
|
|
40
|
+
|
|
41
|
+
## Context Budget
|
|
42
|
+
|
|
43
|
+
The runtime now estimates persisted message size before each model step.
|
|
44
|
+
|
|
45
|
+
- Default mode: `auto`
|
|
46
|
+
- Default threshold: 180,000 message characters
|
|
47
|
+
- Default compact target: up to 60,000 characters
|
|
48
|
+
- Environment controls:
|
|
49
|
+
- `AGINTI_CONTEXT_BUDGET_MODE=off|auto|on`
|
|
50
|
+
- `AGINTI_CONTEXT_BUDGET_CHARS=<positive integer>`
|
|
51
|
+
- `AGINTI_CONTEXT_TARGET_CHARS=<positive integer>`
|
|
52
|
+
|
|
53
|
+
Compaction keeps:
|
|
54
|
+
|
|
55
|
+
- system instructions;
|
|
56
|
+
- the authoritative current goal;
|
|
57
|
+
- original user requests;
|
|
58
|
+
- current plan;
|
|
59
|
+
- recent tool/model evidence;
|
|
60
|
+
- current sandbox, task-profile, step, and browser state.
|
|
61
|
+
|
|
62
|
+
It removes native tool-call/result history only after converting it into a compact evidence ledger. The runtime records before/after sizes in `history.compacted_for_context_budget`.
|
|
63
|
+
|
|
64
|
+
## Next General Improvements
|
|
65
|
+
|
|
66
|
+
1. Add profile-aware progressive tool disclosure. Begin with a small universal tool set and expose specialist/browser/MCP/tmux tools only when task routing or the model requests that capability.
|
|
67
|
+
2. Replace character-only budgeting with provider usage tokens when usage metadata is available, retaining character estimation as a cross-provider fallback.
|
|
68
|
+
3. Add loop/stall detection independent of step count: repeated identical tool calls, repeated equivalent failures, and no-evidence cycles should trigger strategy repair or a truthful blocker.
|
|
69
|
+
|
|
70
|
+
These belong in AgInTiFlow core. Paper-specific editors, Xiaoyunque defaults, scientific protocols, and project output conventions remain custom skills or application adapters.
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { shouldStartPostinstallWebApp } from "../src/postinstall-policy.js";
|
|
4
5
|
import { ensureAgintiWebApp } from "../src/web-autostart.js";
|
|
5
6
|
|
|
6
7
|
const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
7
8
|
const cwd = process.env.INIT_CWD || process.cwd();
|
|
8
9
|
|
|
9
|
-
if (process.env
|
|
10
|
+
if (!shouldStartPostinstallWebApp(process.env)) {
|
|
10
11
|
process.exit(0);
|
|
11
12
|
}
|
|
12
13
|
|