@lazyingart/agintiflow 0.20.7 → 0.20.9
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 -0
- package/docs/cli-i18n.md +84 -0
- package/docs/model-selection.md +3 -0
- package/package.json +1 -1
- package/references/model-routing-provider-design.md +3 -1
- package/scripts/smoke-cli-chat.js +15 -0
- package/scripts/smoke-model-roles.js +28 -0
- package/src/agent-runner.js +3 -0
- package/src/cli.js +18 -1
- package/src/config.js +3 -0
- package/src/i18n.js +435 -0
- package/src/interactive-cli.js +163 -159
- package/src/model-routing.js +7 -5
- package/src/web-db.js +2 -1
- package/web.js +3 -19
package/README.md
CHANGED
|
@@ -69,10 +69,15 @@ Start an interactive Codex-style CLI chat from any project folder:
|
|
|
69
69
|
aginti
|
|
70
70
|
# or explicitly:
|
|
71
71
|
aginti chat
|
|
72
|
+
# choose a UI language, or omit it to follow your system locale:
|
|
73
|
+
aginti --language ja
|
|
74
|
+
aginti --language zh-Hans
|
|
72
75
|
```
|
|
73
76
|
|
|
74
77
|
Inside chat, type normal requests such as `write a small Python CLI app with tests`. The default is Docker workspace mode with approved package installs, so coding, plotting, and LaTeX tasks can set up project-local tools without touching the host. Use `/help` for commands, `/login` or `/auth` to paste a provider key, `/instructions` to inspect `AGINTI.md`, `/latex on` for PDF work, `/docker off` only when you intentionally want host mode, `/sessions` to list project runs, and `/resume latest` or `/resume <session-id>` to continue work. Type `/` then Tab for command completion. `Ctrl+J` inserts a new line in the colored input panel, Enter sends, arrow keys move through wrapped multiline input, and `Ctrl+A`/`Ctrl+E` jump to the current line start/end. During an active run, Enter sends the draft as an ASAP pipe message (`→`) and Tab queues it for after the run (`↳`); ASAP messages are consumed before after-finish queued prompts, Alt+Up edits the last piped message, and Shift+Left edits the last after-finish queued message. Idle Esc is ignored so it does not disturb the input panel; during a run, Esc waits when `→` messages are pending and otherwise stops the run cleanly. Ctrl+C always stops and prints the resume command. The input panel always shows the current `cwd` footer and a single live status row, so long goals and tool updates are compacted instead of flooding the transcript. Assistant responses start on a fresh line after the `aginti>` header with a colored response gutter and render common Markdown, including headings, inline code, bold text, lists, quotes, code fences, tables, and red/green patch diff lines. Resuming a session prints the full saved chat history with wrapped messages before the prompt.
|
|
75
78
|
|
|
79
|
+
CLI and app language can follow the system locale or be set with `--language`, `--lang`, `-L`, or the interactive `/language` command. Supported codes are `en`, `ja`, `zh-Hans`, `zh-Hant`, `ko`, `fr`, `es`, `ar`, `vi`, `de`, and `ru`; longer names plus old `jp` and `cn-*` aliases still work. See [docs/cli-i18n.md](docs/cli-i18n.md).
|
|
80
|
+
|
|
76
81
|
`aginti init` creates `AGINTI.md` at the project root. This is the editable project-instruction file for both CLI and web runs, similar to `AGENTS.md` or project memory in other agents. Keep durable preferences, commands, and constraints there, but never secrets. You can edit it manually or ask in chat, for example: `update AGINTI.md to remember that this project uses pytest and npm run check`.
|
|
77
82
|
|
|
78
83
|
For code edits, AgInTiFlow routes patch/refactor/database-style tasks to DeepSeek v4 pro by default and exposes `apply_patch` as a deterministic workspace tool. It supports exact replacements, Codex-style patch envelopes, and unified diffs, with preflight checks, path guardrails, hashes, and compact per-file diffs. See [docs/patch-tools.md](docs/patch-tools.md).
|
package/docs/cli-i18n.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# CLI And App Language
|
|
2
|
+
|
|
3
|
+
AgInTiFlow supports a shared language preference for the interactive CLI, one-shot CLI runs, web defaults, and model prompt context.
|
|
4
|
+
|
|
5
|
+
## Supported Canonical Languages
|
|
6
|
+
|
|
7
|
+
| Canonical | Language | Common aliases |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `en` | English | `english` |
|
|
10
|
+
| `ja` | Japanese | `jp`, `japanese` |
|
|
11
|
+
| `zh-Hans` | Simplified Chinese | `zh-s`, `zh s`, `cn`, `cn-s`, `cn s`, `zh-cn`, `simplified` |
|
|
12
|
+
| `zh-Hant` | Traditional Chinese | `zh-t`, `zh t`, `cn-t`, `cn t`, `zh-tw`, `zh-hk`, `traditional` |
|
|
13
|
+
| `ko` | Korean | `korean` |
|
|
14
|
+
| `fr` | French | `french` |
|
|
15
|
+
| `es` | Spanish | `spanish` |
|
|
16
|
+
| `ar` | Arabic | `arabic` |
|
|
17
|
+
| `vi` | Vietnamese | `vietnamese` |
|
|
18
|
+
| `de` | German | `deutsch`, `german` |
|
|
19
|
+
| `ru` | Russian | `russian` |
|
|
20
|
+
|
|
21
|
+
## Defaults
|
|
22
|
+
|
|
23
|
+
If no language is passed, AgInTiFlow follows the system language from:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
AGINTI_LANGUAGE -> LANGUAGE -> LC_ALL -> LC_MESSAGES -> LANG
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If none of those map to a supported locale, English is used.
|
|
30
|
+
|
|
31
|
+
## CLI Usage
|
|
32
|
+
|
|
33
|
+
Start the interactive CLI in a specific language:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
aginti --language ja
|
|
37
|
+
aginti --language zh-Hans
|
|
38
|
+
aginti --language zh-Hant
|
|
39
|
+
aginti --language ko
|
|
40
|
+
aginti --language fr
|
|
41
|
+
aginti --language es
|
|
42
|
+
aginti --language ar
|
|
43
|
+
aginti --language vi
|
|
44
|
+
aginti --language de
|
|
45
|
+
aginti --language ru
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Inside interactive chat:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
/language
|
|
52
|
+
/language auto
|
|
53
|
+
/language en
|
|
54
|
+
/language ja
|
|
55
|
+
/language zh-Hans
|
|
56
|
+
/language zh-Hant
|
|
57
|
+
/language ko
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`/lang` is an alias for `/language`.
|
|
61
|
+
|
|
62
|
+
One-shot tasks also accept the same option:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
aginti --language zh-Hans "list files and summarize this project"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The selected language localizes the launch banner subtitle, prompt hint, help text, status labels, and language status. It also adds language guidance to the model context so the assistant usually replies in the selected UI language unless the user asks for another language.
|
|
69
|
+
|
|
70
|
+
## Web App
|
|
71
|
+
|
|
72
|
+
The web app already has an 11-language dropdown. Launching web with a language seeds the project-local default:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
aginti web --language de --port 3210
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The web preference is stored in the project-local `.sessions/web-state.sqlite` database, so the CLI and web app can share sessions while each frontend keeps its own UI controls.
|
|
79
|
+
|
|
80
|
+
## Notes
|
|
81
|
+
|
|
82
|
+
- `zh-Hans` and `zh-Hant` are the canonical Chinese values. `zh-s`, `zh-t`, `cn-s`, `cn-t`, `cn s`, and `cn t` remain compatibility aliases.
|
|
83
|
+
- API keys and `.aginti/.env` values are never translated, printed, or exposed through the language system.
|
|
84
|
+
- Model output language is guidance, not a hard safety filter. If the user asks in a different language or explicitly requests another output language, the model should follow that request.
|
package/docs/model-selection.md
CHANGED
|
@@ -48,12 +48,15 @@ Interactive commands:
|
|
|
48
48
|
|
|
49
49
|
In the interactive CLI, `/provider`, `/route`, `/model`, `/spare`, and `/auxiliary model` without arguments open selectors. Use Up/Down/Left/Right to move through choices, Enter to confirm, and Esc to cancel. Slash-command hints use the same arrow selection behavior: type a prefix such as `/mo`, use arrows to choose `/model` or `/models`, then press Enter or Tab.
|
|
50
50
|
|
|
51
|
+
`/route`, `/model`, and `/spare` intentionally share the same text-model selector so users do not need to learn three different catalogs. The shared list is grouped as DeepSeek, Venice Uncensored, Venice GPT/Claude/Gemma/Qwen, OpenAI, Qwen, and Mock. OpenAI entries show the recommended default reasoning effort in the description; `/spare` stores that reasoning value when selected.
|
|
52
|
+
|
|
51
53
|
`/venice` opens a two-step selector for the Venice route and main models. The current text choices are:
|
|
52
54
|
|
|
53
55
|
```text
|
|
54
56
|
venice/venice-uncensored-1-2
|
|
55
57
|
venice/venice-uncensored
|
|
56
58
|
venice/gemma-4-uncensored
|
|
59
|
+
Disable Venice
|
|
57
60
|
```
|
|
58
61
|
|
|
59
62
|
For scripts or non-interactive terminals, `/venice` uses Venice 1.2 for both roles. You can also set both roles directly with `/venice 1.2`, `/venice 1.1`, or `/venice gemma`. Use two values to set route and main separately, for example `/venice 1.2 gemma`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a web-first coding agent and CLI with DeepSeek routing, sandboxed tools, model providers, canvas artifacts, and optional wrappers.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -53,7 +53,9 @@ Interactive equivalents:
|
|
|
53
53
|
/auxiliary model grsai/nano-banana-2
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
`/
|
|
56
|
+
`/route`, `/model`, and `/spare` share a single text-model selector. The selector is grouped as DeepSeek, Venice Uncensored, Venice GPT/Claude/Gemma/Qwen, OpenAI, Qwen, and Mock so the user sees the same union of route/main/spare-capable models in every role.
|
|
57
|
+
|
|
58
|
+
`/venice` opens a route/main selector for Venice text models. The selector includes `venice/venice-uncensored-1-2` (Venice 1.2), `venice/venice-uncensored` (Venice 1.1), `venice/gemma-4-uncensored` (Gemma 4), and a Disable Venice option. In non-interactive shells, `/venice` keeps script compatibility by selecting `venice/venice-uncensored-1-2` for both roles. `/venice 1.2 gemma` sets route to Venice 1.2 and main to Gemma 4; `/venice off` or the Disable Venice selector option restores `deepseek/deepseek-v4-flash` for route and `deepseek/deepseek-v4-pro` for main.
|
|
57
59
|
|
|
58
60
|
The web UI should expose model names as dropdowns, not free-text fields. The left panel should stay focused on common daily controls, while model-role editing and less-used switches live in an Advanced settings modal. The terminal-like capability panels belong after the runtime log so the left control panel remains short.
|
|
59
61
|
|
|
@@ -30,6 +30,7 @@ function runCli(args, inputText) {
|
|
|
30
30
|
env: {
|
|
31
31
|
...process.env,
|
|
32
32
|
AGINTIFLOW_RUNTIME_DIR: "",
|
|
33
|
+
AGINTI_LANGUAGE: "en",
|
|
33
34
|
},
|
|
34
35
|
});
|
|
35
36
|
|
|
@@ -153,6 +154,15 @@ try {
|
|
|
153
154
|
) {
|
|
154
155
|
throw new Error("terminal prompt layout did not render visual-only input padding safely");
|
|
155
156
|
}
|
|
157
|
+
const zhPromptLayout = buildPromptLayout("", 0, 90, 24, { language: "zh-Hans", commandCwd: "/tmp/aginti-project" });
|
|
158
|
+
const zhPromptText = zhPromptLayout.renderedRows.map((line) => line.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "")).join("\n");
|
|
159
|
+
if (!zhPromptText.includes("输入任务")) {
|
|
160
|
+
throw new Error("terminal prompt layout did not localize the empty input hint");
|
|
161
|
+
}
|
|
162
|
+
const jaLaunchHeader = buildLaunchHeaderLines({ width: 120, packageVersion: "0.0.0", animated: false, language: "ja" }).join("\n");
|
|
163
|
+
if (!jaLaunchHeader.includes("Web ファースト")) {
|
|
164
|
+
throw new Error("launch header did not localize by language option");
|
|
165
|
+
}
|
|
156
166
|
const hugePromptLayout = buildPromptLayout(Array.from({ length: 30 }, (_unused, index) => `line ${index + 1}`).join("\n"), 120, 80, 20);
|
|
157
167
|
if (hugePromptLayout.renderedRows.length > 12 || !hugePromptLayout.renderedRows.some((line) => line.includes("earlier input row"))) {
|
|
158
168
|
throw new Error("terminal prompt layout did not bound redraw size for large prompts");
|
|
@@ -220,6 +230,10 @@ try {
|
|
|
220
230
|
if (!helpResult.stdout.includes("/auxiliary") || helpResult.stdout.includes(misspelledAuxiliary)) {
|
|
221
231
|
throw new Error("interactive help did not expose only the correctly spelled /auxiliary command");
|
|
222
232
|
}
|
|
233
|
+
const zhHelpResult = await runCli(["chat", "--language", "zh-Hans"], "/help\n/exit\n");
|
|
234
|
+
if (!zhHelpResult.stdout.includes("命令:") || !zhHelpResult.stdout.includes("输入普通任务")) {
|
|
235
|
+
throw new Error("interactive --language zh-Hans did not localize CLI help");
|
|
236
|
+
}
|
|
223
237
|
const skillsResult = await runChat("/skills website\n/exit\n");
|
|
224
238
|
if (!skillsResult.stdout.includes("website-app") || !skillsResult.stdout.includes("Website And App Builder")) {
|
|
225
239
|
throw new Error("interactive /skills did not show matching built-in skills");
|
|
@@ -283,6 +297,7 @@ try {
|
|
|
283
297
|
"large-launch-header",
|
|
284
298
|
"prompt-layout",
|
|
285
299
|
"prompt-redraw-fast-path",
|
|
300
|
+
"cli-i18n",
|
|
286
301
|
"user-prompt-label",
|
|
287
302
|
"escape-policy",
|
|
288
303
|
"live-input-status-layout",
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
selectModelRoute,
|
|
11
11
|
} from "../src/model-routing.js";
|
|
12
12
|
import { parseTextToolCalls, usesTextToolProtocol } from "../src/model-client.js";
|
|
13
|
+
import { modelRoleChoices } from "../src/interactive-cli.js";
|
|
13
14
|
|
|
14
15
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
15
16
|
|
|
@@ -111,6 +112,32 @@ assert(MODEL_PROVIDER_GROUPS["venice-gpt"].provider === "venice", "venice-gpt gr
|
|
|
111
112
|
assert(modelsForProviderGroup("venice-gemma").some((item) => item.id === "gemma-4-uncensored"), "venice-gemma bucket missing Gemma");
|
|
112
113
|
assert(modelsForProviderGroup("venice-uncensored").some((item) => item.id === "e2ee-venice-uncensored-24b-p"), "venice-uncensored bucket missing Venice 1.1");
|
|
113
114
|
assert(AUXILIARY_MODEL_CATALOG["venice-image"].some((item) => item.id === "gpt-image-2"), "Venice image catalog missing GPT Image 2");
|
|
115
|
+
const routeChoices = modelRoleChoices("route").map((item) => `${item.provider}/${item.model}`);
|
|
116
|
+
const mainChoices = modelRoleChoices("main").map((item) => `${item.provider}/${item.model}`);
|
|
117
|
+
const spareChoices = modelRoleChoices("spare").map((item) => `${item.provider}/${item.model}`);
|
|
118
|
+
assert(JSON.stringify(routeChoices) === JSON.stringify(mainChoices), "route and main selectors should share the same text-model list");
|
|
119
|
+
assert(JSON.stringify(routeChoices) === JSON.stringify(spareChoices), "route and spare selectors should share the same text-model list");
|
|
120
|
+
for (const expected of [
|
|
121
|
+
"deepseek/deepseek-v4-flash",
|
|
122
|
+
"deepseek/deepseek-v4-pro",
|
|
123
|
+
"venice/venice-uncensored-1-2",
|
|
124
|
+
"venice/venice-uncensored",
|
|
125
|
+
"venice/gemma-4-uncensored",
|
|
126
|
+
"venice/openai-gpt-55",
|
|
127
|
+
"venice/claude-sonnet-4-6",
|
|
128
|
+
"venice/qwen3-6-27b",
|
|
129
|
+
"openai/gpt-5.5",
|
|
130
|
+
"openai/gpt-5.4",
|
|
131
|
+
"openai/gpt-5.4-mini",
|
|
132
|
+
"openai/gpt-5.3-codex",
|
|
133
|
+
"openai/gpt-5.3-codex-spark",
|
|
134
|
+
"qwen/qwen-plus",
|
|
135
|
+
"mock/mock-agent",
|
|
136
|
+
]) {
|
|
137
|
+
assert(routeChoices.includes(expected), `shared model selector missing ${expected}`);
|
|
138
|
+
}
|
|
139
|
+
assert(!routeChoices.includes("venice/e2ee-venice-uncensored-24b-p"), "shared model selector should hide unstable E2EE Venice 1.1");
|
|
140
|
+
assert(modelRoleChoices("auxiliary").some((item) => item.provider === "grsai"), "auxiliary selector missing GRS AI");
|
|
114
141
|
const parsedTextToolCalls = parseTextToolCalls('[TOOL_CALLS]list_files[ARGS]call_123[ARGS]{"path":".","maxDepth":1}');
|
|
115
142
|
assert(parsedTextToolCalls.length === 1, "Venice text tool-call parser did not detect encoded tool call");
|
|
116
143
|
assert(parsedTextToolCalls[0].function.name === "list_files", "Venice text tool-call parser returned wrong tool name");
|
|
@@ -151,6 +178,7 @@ console.log(
|
|
|
151
178
|
"route-overrides",
|
|
152
179
|
"provider-groups",
|
|
153
180
|
"auxiliary-catalog",
|
|
181
|
+
"shared-model-selectors",
|
|
154
182
|
"venice-text-tool-parser",
|
|
155
183
|
"cli-models-command",
|
|
156
184
|
"venice-shortcut",
|
package/src/agent-runner.js
CHANGED
|
@@ -25,6 +25,7 @@ import { readProjectInstructions } from "./project.js";
|
|
|
25
25
|
import { formatSkillsForPrompt, selectSkillsForGoal } from "./skill-library.js";
|
|
26
26
|
import { hostShellOption, platformInfo, platformLabel } from "./platform.js";
|
|
27
27
|
import { captureTmuxPane, listTmuxSessions, sendTmuxKeys, startTmuxSession } from "./tmux-tools.js";
|
|
28
|
+
import { languageInstruction } from "./i18n.js";
|
|
28
29
|
|
|
29
30
|
const exec = promisify(execCallback);
|
|
30
31
|
const BROWSER_TOOLS = new Set(["open_url", "open_workspace_file", "preview_workspace", "click", "type", "scroll", "press", "back"]);
|
|
@@ -300,6 +301,7 @@ async function createInitialState(config, sessionId) {
|
|
|
300
301
|
"Prefer short, deliberate actions over guessing.",
|
|
301
302
|
"Never navigate outside the allowed domains when an allowlist exists.",
|
|
302
303
|
"Avoid destructive actions, purchases, account changes, and sensitive workflows.",
|
|
304
|
+
languageInstruction(config.language || "en"),
|
|
303
305
|
projectInstructionContext,
|
|
304
306
|
"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.",
|
|
305
307
|
config.allowShellTool
|
|
@@ -351,6 +353,7 @@ async function createInitialState(config, sessionId) {
|
|
|
351
353
|
role: "user",
|
|
352
354
|
content: [
|
|
353
355
|
`Goal: ${config.goal}`,
|
|
356
|
+
languageInstruction(config.language || "en"),
|
|
354
357
|
config.startUrl ? `Suggested start URL: ${config.startUrl}` : "",
|
|
355
358
|
config.allowedDomains.length > 0 ? `Allowed domains: ${config.allowedDomains.join(", ")}` : "",
|
|
356
359
|
config.allowShellTool
|
package/src/cli.js
CHANGED
|
@@ -25,6 +25,7 @@ import { listTaskProfiles } from "./task-profiles.js";
|
|
|
25
25
|
import { recommendedMaxStepsForTask } from "./engineering-guidance.js";
|
|
26
26
|
import { normalizeAuthProvider, promptHidden, runAuthWizard, shouldPromptForDeepSeek } from "./auth-onboarding.js";
|
|
27
27
|
import { listSkills, selectSkillsForGoal } from "./skill-library.js";
|
|
28
|
+
import { languageLabel, resolveLanguage } from "./i18n.js";
|
|
28
29
|
import fs from "node:fs/promises";
|
|
29
30
|
import path from "node:path";
|
|
30
31
|
import { fileURLToPath } from "node:url";
|
|
@@ -87,6 +88,7 @@ export function parseArgs(argv) {
|
|
|
87
88
|
listSkills: false,
|
|
88
89
|
latex: false,
|
|
89
90
|
image: false,
|
|
91
|
+
language: "",
|
|
90
92
|
};
|
|
91
93
|
|
|
92
94
|
const parts = [];
|
|
@@ -110,6 +112,18 @@ export function parseArgs(argv) {
|
|
|
110
112
|
i += 1;
|
|
111
113
|
continue;
|
|
112
114
|
}
|
|
115
|
+
if (arg === "--language" || arg === "--lang" || arg === "-L") {
|
|
116
|
+
const first = readOption(argv, i);
|
|
117
|
+
const second = argv[i + 2] && !String(argv[i + 2]).startsWith("--") ? argv[i + 2] : "";
|
|
118
|
+
if (["cn", "zh"].includes(String(first || "").toLowerCase()) && ["s", "t"].includes(String(second || "").toLowerCase())) {
|
|
119
|
+
result.language = `${first}-${second}`;
|
|
120
|
+
i += 2;
|
|
121
|
+
} else {
|
|
122
|
+
result.language = first;
|
|
123
|
+
i += 1;
|
|
124
|
+
}
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
113
127
|
if (arg === "--start-url") {
|
|
114
128
|
result.startUrl = readOption(argv, i);
|
|
115
129
|
i += 1;
|
|
@@ -345,8 +359,9 @@ export function parseArgs(argv) {
|
|
|
345
359
|
|
|
346
360
|
function printUsage() {
|
|
347
361
|
console.log(
|
|
348
|
-
'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti models OR aginti skills [query] OR aginti auth [deepseek|openai|qwen|venice|grsai] OR aginti resume [latest|<session-id>] ["prompt"] OR aginti queue <session-id> "message" OR aginti [--image] [--latex] [--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"'
|
|
362
|
+
'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti models OR aginti skills [query] OR aginti auth [deepseek|openai|qwen|venice|grsai] OR aginti resume [latest|<session-id>] ["prompt"] OR aginti queue <session-id> "message" OR aginti [--language en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru] [--image] [--latex] [--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"'
|
|
349
363
|
);
|
|
364
|
+
console.log(`Languages: ${["en", "ja", "zh-Hans", "zh-Hant", "ko", "fr", "es", "ar", "vi", "de", "ru"].map((code) => `${code}=${languageLabel(code)}`).join(", ")}`);
|
|
350
365
|
}
|
|
351
366
|
|
|
352
367
|
function providerLabel(provider) {
|
|
@@ -361,6 +376,7 @@ function providerLabel(provider) {
|
|
|
361
376
|
function agentDefaults(args) {
|
|
362
377
|
const defaults = {
|
|
363
378
|
...args,
|
|
379
|
+
language: resolveLanguage(args.language || process.env.AGINTI_LANGUAGE || ""),
|
|
364
380
|
allowShellTool: args.allowShellTool ?? true,
|
|
365
381
|
allowFileTools: args.allowFileTools ?? true,
|
|
366
382
|
allowAuxiliaryTools: args.allowAuxiliaryTools ?? true,
|
|
@@ -728,6 +744,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
728
744
|
if (args.web) {
|
|
729
745
|
if (args.port) process.env.PORT = String(args.port);
|
|
730
746
|
if (args.host) process.env.HOST = String(args.host);
|
|
747
|
+
if (args.language) process.env.AGINTI_LANGUAGE = resolveLanguage(args.language);
|
|
731
748
|
process.env.AGINTIFLOW_PACKAGE_DIR = packageDir;
|
|
732
749
|
await import("../web.js");
|
|
733
750
|
return;
|
package/src/config.js
CHANGED
|
@@ -6,6 +6,7 @@ import { normalizeWrapperName } from "./tool-wrappers.js";
|
|
|
6
6
|
import { loadProjectEnv, resolveProjectRoot } from "./project.js";
|
|
7
7
|
import { normalizeTaskProfile } from "./task-profiles.js";
|
|
8
8
|
import { recommendedMaxStepsForTask } from "./engineering-guidance.js";
|
|
9
|
+
import { resolveLanguage } from "./i18n.js";
|
|
9
10
|
|
|
10
11
|
function parseBoolean(value, fallback) {
|
|
11
12
|
if (value === undefined) return fallback;
|
|
@@ -47,6 +48,7 @@ export function resolveRuntimeConfig(args, overrides = {}) {
|
|
|
47
48
|
: "deepseek");
|
|
48
49
|
const routingMode = normalizeRoutingMode(overrides.routingMode || args.routingMode || process.env.AGENT_ROUTING_MODE || "smart");
|
|
49
50
|
const taskProfile = normalizeTaskProfile(overrides.taskProfile || args.taskProfile || process.env.AGINTI_TASK_PROFILE || "auto");
|
|
51
|
+
const language = resolveLanguage(overrides.language || args.language || process.env.AGINTI_LANGUAGE || "");
|
|
50
52
|
const route = selectModelRoute({
|
|
51
53
|
routingMode,
|
|
52
54
|
provider: requestedProvider,
|
|
@@ -94,6 +96,7 @@ export function resolveRuntimeConfig(args, overrides = {}) {
|
|
|
94
96
|
sessionId: overrides.sessionId || args.sessionId || process.env.SESSION_ID || `web-agent-${crypto.randomUUID()}`,
|
|
95
97
|
routingMode,
|
|
96
98
|
taskProfile,
|
|
99
|
+
language,
|
|
97
100
|
routeReason: route.reason,
|
|
98
101
|
routeComplexityScore: route.complexityScore,
|
|
99
102
|
modelRoles,
|