@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 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
- Package installation also makes a best-effort, non-blocking webapp initialization. Install never fails because the optional local webapp could not start.
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.196",
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.CI === "true" || process.env.AGINTIFLOW_SKIP_POSTINSTALL_WEBAPP === "1") {
10
+ if (!shouldStartPostinstallWebApp(process.env)) {
10
11
  process.exit(0);
11
12
  }
12
13