@lazyingart/agintiflow 0.20.8 → 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/package.json +1 -1
- package/scripts/smoke-cli-chat.js +15 -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 +79 -49
- 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/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",
|
|
@@ -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",
|
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,
|
package/src/i18n.js
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
export const SUPPORTED_LANGUAGES = [
|
|
2
|
+
"en",
|
|
3
|
+
"ja",
|
|
4
|
+
"zh-Hans",
|
|
5
|
+
"zh-Hant",
|
|
6
|
+
"ko",
|
|
7
|
+
"fr",
|
|
8
|
+
"es",
|
|
9
|
+
"ar",
|
|
10
|
+
"vi",
|
|
11
|
+
"de",
|
|
12
|
+
"ru",
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export const LANGUAGE_LABELS = {
|
|
16
|
+
en: "English",
|
|
17
|
+
ja: "日本語",
|
|
18
|
+
"zh-Hans": "简体中文",
|
|
19
|
+
"zh-Hant": "繁體中文",
|
|
20
|
+
ko: "한국어",
|
|
21
|
+
fr: "Français",
|
|
22
|
+
es: "Español",
|
|
23
|
+
ar: "العربية",
|
|
24
|
+
vi: "Tiếng Việt",
|
|
25
|
+
de: "Deutsch",
|
|
26
|
+
ru: "Русский",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const LANGUAGE_ALIASES = new Map(
|
|
30
|
+
Object.entries({
|
|
31
|
+
"": "",
|
|
32
|
+
auto: "",
|
|
33
|
+
system: "",
|
|
34
|
+
default: "",
|
|
35
|
+
en: "en",
|
|
36
|
+
eng: "en",
|
|
37
|
+
english: "en",
|
|
38
|
+
ja: "ja",
|
|
39
|
+
jp: "ja",
|
|
40
|
+
jpn: "ja",
|
|
41
|
+
japanese: "ja",
|
|
42
|
+
"日本語": "ja",
|
|
43
|
+
cn: "zh-Hans",
|
|
44
|
+
zh: "zh-Hans",
|
|
45
|
+
"cn-s": "zh-Hans",
|
|
46
|
+
"cn_s": "zh-Hans",
|
|
47
|
+
cns: "zh-Hans",
|
|
48
|
+
"zh-s": "zh-Hans",
|
|
49
|
+
"zh_s": "zh-Hans",
|
|
50
|
+
zhs: "zh-Hans",
|
|
51
|
+
simplified: "zh-Hans",
|
|
52
|
+
simplifiedchinese: "zh-Hans",
|
|
53
|
+
"zh-cn": "zh-Hans",
|
|
54
|
+
"zh_cn": "zh-Hans",
|
|
55
|
+
"zh-hans": "zh-Hans",
|
|
56
|
+
"zh_hans": "zh-Hans",
|
|
57
|
+
zhhans: "zh-Hans",
|
|
58
|
+
"zh-sg": "zh-Hans",
|
|
59
|
+
"zh_sg": "zh-Hans",
|
|
60
|
+
"简体": "zh-Hans",
|
|
61
|
+
"简体中文": "zh-Hans",
|
|
62
|
+
"cn-t": "zh-Hant",
|
|
63
|
+
"cn_t": "zh-Hant",
|
|
64
|
+
cnt: "zh-Hant",
|
|
65
|
+
"zh-t": "zh-Hant",
|
|
66
|
+
"zh_t": "zh-Hant",
|
|
67
|
+
zht: "zh-Hant",
|
|
68
|
+
traditional: "zh-Hant",
|
|
69
|
+
traditionalchinese: "zh-Hant",
|
|
70
|
+
"zh-tw": "zh-Hant",
|
|
71
|
+
"zh_tw": "zh-Hant",
|
|
72
|
+
"zh-hk": "zh-Hant",
|
|
73
|
+
"zh_hk": "zh-Hant",
|
|
74
|
+
"zh-mo": "zh-Hant",
|
|
75
|
+
"zh_mo": "zh-Hant",
|
|
76
|
+
"zh-hant": "zh-Hant",
|
|
77
|
+
"zh_hant": "zh-Hant",
|
|
78
|
+
zhhant: "zh-Hant",
|
|
79
|
+
"繁體": "zh-Hant",
|
|
80
|
+
"繁體中文": "zh-Hant",
|
|
81
|
+
ko: "ko",
|
|
82
|
+
kr: "ko",
|
|
83
|
+
kor: "ko",
|
|
84
|
+
korean: "ko",
|
|
85
|
+
"한국어": "ko",
|
|
86
|
+
fr: "fr",
|
|
87
|
+
fra: "fr",
|
|
88
|
+
french: "fr",
|
|
89
|
+
français: "fr",
|
|
90
|
+
es: "es",
|
|
91
|
+
spa: "es",
|
|
92
|
+
spanish: "es",
|
|
93
|
+
español: "es",
|
|
94
|
+
ar: "ar",
|
|
95
|
+
ara: "ar",
|
|
96
|
+
arabic: "ar",
|
|
97
|
+
"العربية": "ar",
|
|
98
|
+
vi: "vi",
|
|
99
|
+
vie: "vi",
|
|
100
|
+
vietnamese: "vi",
|
|
101
|
+
"tiếngviệt": "vi",
|
|
102
|
+
de: "de",
|
|
103
|
+
deu: "de",
|
|
104
|
+
ger: "de",
|
|
105
|
+
german: "de",
|
|
106
|
+
deutsch: "de",
|
|
107
|
+
ru: "ru",
|
|
108
|
+
rus: "ru",
|
|
109
|
+
russian: "ru",
|
|
110
|
+
русский: "ru",
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const TRANSLATIONS = {
|
|
115
|
+
en: {
|
|
116
|
+
launchSubtitle: "web-first agent workspace",
|
|
117
|
+
launchTagline: "browser + shell + files + docker + web search + scouts",
|
|
118
|
+
interactiveIntro: "Interactive agent chat. Type /help for commands, /exit to quit.",
|
|
119
|
+
promptEmpty: "type a request, /help, Enter to send, Ctrl+J for newline",
|
|
120
|
+
helpTitle: "Commands:",
|
|
121
|
+
helpHelp: "Show this help.",
|
|
122
|
+
helpStatus: "Show active route, workspace, sandbox, and session.",
|
|
123
|
+
helpLogin: "Pick, paste, and save project-local API keys.",
|
|
124
|
+
helpInstructions: "Show AGINTI.md project instructions status.",
|
|
125
|
+
helpModels: "Show route/main/spare/wrapper/auxiliary model roles.",
|
|
126
|
+
helpVenice: "Pick Venice route/main models, or restore DeepSeek defaults.",
|
|
127
|
+
helpRoute: "Open route selector, or set routing/fast route model.",
|
|
128
|
+
helpModel: "Open main-model selector, or set the active/main model.",
|
|
129
|
+
helpSpare: "Open spare selector, or set e.g. /spare openai/gpt-5.4 medium.",
|
|
130
|
+
helpWrapper: "Configure optional external wrapper.",
|
|
131
|
+
helpAuxiliary: "Manage optional auxiliary skills, including image generation.",
|
|
132
|
+
helpNew: "Start a fresh session on the next message.",
|
|
133
|
+
helpResume: "Continue a saved session.",
|
|
134
|
+
helpSessions: "List recent sessions in this project.",
|
|
135
|
+
helpSkills: "List Markdown skills selected for a topic.",
|
|
136
|
+
helpProfile: "Set task profile, e.g. code, website, latex, maintenance.",
|
|
137
|
+
helpWebSearch: "Enable or disable the web_search tool.",
|
|
138
|
+
helpScouts: "Enable parallel DeepSeek scouts and set scout count.",
|
|
139
|
+
helpRouting: "Set routing: smart, fast, complex, manual.",
|
|
140
|
+
helpProvider: "Open provider selector, or set deepseek/openai/qwen/venice/mock.",
|
|
141
|
+
helpDockerOn: "Use docker-workspace with approved package installs.",
|
|
142
|
+
helpDockerOff: "Use host shell policy.",
|
|
143
|
+
helpLatex: "Use the LaTeX/PDF profile in Docker with a larger step budget.",
|
|
144
|
+
helpInstalls: "Set package install policy.",
|
|
145
|
+
helpCwd: "Change command workspace.",
|
|
146
|
+
helpLanguage: "Set CLI language, or use system locale with /language auto.",
|
|
147
|
+
helpExit: "Quit.",
|
|
148
|
+
helpNormalRequest: "Type a normal request to run the agent. Example: write a Python CLI app with tests",
|
|
149
|
+
helpAutocomplete: "Type / then Tab to autocomplete commands.",
|
|
150
|
+
helpQueue: "While a run is active, Enter pipes a message into the current run (→), Tab queues it after finish (↳).",
|
|
151
|
+
helpEditQueue: "Alt+Up edits the last piped message; Shift+Left edits the last queued message.",
|
|
152
|
+
helpEsc: "Esc is ignored while idle. During a run, Esc waits for pending → pipe messages or stops if none; Ctrl+C always stops.",
|
|
153
|
+
languageSet: "language={language} ({label})",
|
|
154
|
+
languageUsage: "Usage: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
155
|
+
project: "Project",
|
|
156
|
+
statusNew: "new",
|
|
157
|
+
statusIdle: "idle",
|
|
158
|
+
systemLanguage: "system",
|
|
159
|
+
},
|
|
160
|
+
ja: {
|
|
161
|
+
launchSubtitle: "Web ファーストのエージェント作業環境",
|
|
162
|
+
launchTagline: "ブラウザ + シェル + ファイル + Docker + Web 検索 + スカウト",
|
|
163
|
+
interactiveIntro: "対話型エージェントチャットです。/help でコマンド、/exit で終了します。",
|
|
164
|
+
promptEmpty: "依頼を入力。/help、Enter で送信、Ctrl+J で改行",
|
|
165
|
+
helpTitle: "コマンド:",
|
|
166
|
+
helpHelp: "このヘルプを表示します。",
|
|
167
|
+
helpStatus: "現在のルート、作業場所、サンドボックス、セッションを表示します。",
|
|
168
|
+
helpLogin: "プロジェクトローカルの API キーを選択・貼り付け・保存します。",
|
|
169
|
+
helpInstructions: "AGINTI.md のプロジェクト指示状態を表示します。",
|
|
170
|
+
helpModels: "route/main/spare/wrapper/auxiliary のモデル役割を表示します。",
|
|
171
|
+
helpVenice: "Venice の route/main モデルを選択、または DeepSeek 既定値に戻します。",
|
|
172
|
+
helpRoute: "ルート選択を開くか、ルーティング/高速ルートモデルを設定します。",
|
|
173
|
+
helpModel: "メインモデル選択を開くか、active/main モデルを設定します。",
|
|
174
|
+
helpSpare: "スペア選択を開くか、例: /spare openai/gpt-5.4 medium を設定します。",
|
|
175
|
+
helpWrapper: "任意の外部ラッパーを設定します。",
|
|
176
|
+
helpAuxiliary: "画像生成を含む補助スキルを管理します。",
|
|
177
|
+
helpNew: "次のメッセージで新しいセッションを開始します。",
|
|
178
|
+
helpResume: "保存済みセッションを続行します。",
|
|
179
|
+
helpSessions: "このプロジェクトの最近のセッションを一覧します。",
|
|
180
|
+
helpSkills: "トピックに合う Markdown スキルを一覧します。",
|
|
181
|
+
helpProfile: "code、website、latex、maintenance などのタスクプロファイルを設定します。",
|
|
182
|
+
helpWebSearch: "web_search ツールを有効/無効にします。",
|
|
183
|
+
helpScouts: "並列 DeepSeek スカウトを有効化し数を設定します。",
|
|
184
|
+
helpRouting: "routing を smart、fast、complex、manual に設定します。",
|
|
185
|
+
helpProvider: "プロバイダ選択を開くか deepseek/openai/qwen/venice/mock を設定します。",
|
|
186
|
+
helpDockerOn: "承認済みパッケージインストール付き docker-workspace を使います。",
|
|
187
|
+
helpDockerOff: "ホストシェルポリシーを使います。",
|
|
188
|
+
helpLatex: "Docker で LaTeX/PDF プロファイルと大きめのステップ数を使います。",
|
|
189
|
+
helpInstalls: "パッケージインストールポリシーを設定します。",
|
|
190
|
+
helpCwd: "コマンド作業場所を変更します。",
|
|
191
|
+
helpLanguage: "CLI 言語を設定、または /language auto でシステムロケールを使います。",
|
|
192
|
+
helpExit: "終了します。",
|
|
193
|
+
helpNormalRequest: "通常の依頼を入力するとエージェントが実行します。例: write a Python CLI app with tests",
|
|
194
|
+
helpAutocomplete: "/ を入力して Tab でコマンド補完します。",
|
|
195
|
+
helpQueue: "実行中は Enter で現在の実行へパイプ (→)、Tab で完了後キュー (↳)。",
|
|
196
|
+
helpEditQueue: "Alt+Up で最後のパイプ、Shift+Left で最後のキューを編集します。",
|
|
197
|
+
helpEsc: "アイドル中の Esc は無視。実行中は保留中の → を待つか停止します。Ctrl+C は常に停止します。",
|
|
198
|
+
languageSet: "language={language} ({label})",
|
|
199
|
+
languageUsage: "使用法: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
200
|
+
project: "プロジェクト",
|
|
201
|
+
statusNew: "new",
|
|
202
|
+
statusIdle: "idle",
|
|
203
|
+
systemLanguage: "システム",
|
|
204
|
+
},
|
|
205
|
+
"zh-Hans": {
|
|
206
|
+
launchSubtitle: "网页优先的智能体工作区",
|
|
207
|
+
launchTagline: "浏览器 + Shell + 文件 + Docker + 网页搜索 + Scouts",
|
|
208
|
+
interactiveIntro: "交互式智能体聊天。输入 /help 查看命令,/exit 退出。",
|
|
209
|
+
promptEmpty: "输入任务,/help 查看帮助,Enter 发送,Ctrl+J 换行",
|
|
210
|
+
helpTitle: "命令:",
|
|
211
|
+
helpHelp: "显示帮助。",
|
|
212
|
+
helpStatus: "显示当前路由、工作区、沙盒和会话。",
|
|
213
|
+
helpLogin: "选择、粘贴并保存项目本地 API Key。",
|
|
214
|
+
helpInstructions: "显示 AGINTI.md 项目指令状态。",
|
|
215
|
+
helpModels: "显示 route/main/spare/wrapper/auxiliary 模型角色。",
|
|
216
|
+
helpVenice: "选择 Venice route/main 模型,或恢复 DeepSeek 默认值。",
|
|
217
|
+
helpRoute: "打开路由选择器,或设置 routing/快速路由模型。",
|
|
218
|
+
helpModel: "打开主模型选择器,或设置 active/main 模型。",
|
|
219
|
+
helpSpare: "打开备用模型选择器,或设置例如 /spare openai/gpt-5.4 medium。",
|
|
220
|
+
helpWrapper: "配置可选外部 wrapper。",
|
|
221
|
+
helpAuxiliary: "管理可选辅助技能,包括图像生成。",
|
|
222
|
+
helpNew: "下一条消息开始新会话。",
|
|
223
|
+
helpResume: "继续已保存会话。",
|
|
224
|
+
helpSessions: "列出本项目最近会话。",
|
|
225
|
+
helpSkills: "列出为主题选择的 Markdown 技能。",
|
|
226
|
+
helpProfile: "设置任务 profile,例如 code、website、latex、maintenance。",
|
|
227
|
+
helpWebSearch: "启用或禁用 web_search 工具。",
|
|
228
|
+
helpScouts: "启用并设置并行 DeepSeek scouts 数量。",
|
|
229
|
+
helpRouting: "设置 routing: smart、fast、complex、manual。",
|
|
230
|
+
helpProvider: "打开 provider 选择器,或设置 deepseek/openai/qwen/venice/mock。",
|
|
231
|
+
helpDockerOn: "使用允许安装包的 docker-workspace。",
|
|
232
|
+
helpDockerOff: "使用主机 shell 策略。",
|
|
233
|
+
helpLatex: "在 Docker 中使用 LaTeX/PDF profile 和更大步骤数。",
|
|
234
|
+
helpInstalls: "设置包安装策略。",
|
|
235
|
+
helpCwd: "修改命令工作区。",
|
|
236
|
+
helpLanguage: "设置 CLI 语言,或用 /language auto 跟随系统语言。",
|
|
237
|
+
helpExit: "退出。",
|
|
238
|
+
helpNormalRequest: "输入普通任务即可运行智能体。例如: write a Python CLI app with tests",
|
|
239
|
+
helpAutocomplete: "输入 / 后按 Tab 自动补全命令。",
|
|
240
|
+
helpQueue: "运行中 Enter 会把消息立即传入当前任务 (→),Tab 会排到结束后执行 (↳)。",
|
|
241
|
+
helpEditQueue: "Alt+Up 编辑上一条立即消息;Shift+Left 编辑上一条排队消息。",
|
|
242
|
+
helpEsc: "空闲时 Esc 不操作。运行中 Esc 等待待处理 → 消息或停止;Ctrl+C 始终停止。",
|
|
243
|
+
languageSet: "language={language} ({label})",
|
|
244
|
+
languageUsage: "用法: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
245
|
+
project: "项目",
|
|
246
|
+
statusNew: "new",
|
|
247
|
+
statusIdle: "idle",
|
|
248
|
+
systemLanguage: "系统",
|
|
249
|
+
},
|
|
250
|
+
"zh-Hant": {
|
|
251
|
+
launchSubtitle: "網頁優先的智能體工作區",
|
|
252
|
+
launchTagline: "瀏覽器 + Shell + 檔案 + Docker + 網頁搜尋 + Scouts",
|
|
253
|
+
interactiveIntro: "互動式智能體聊天。輸入 /help 查看命令,/exit 離開。",
|
|
254
|
+
promptEmpty: "輸入任務,/help 查看說明,Enter 送出,Ctrl+J 換行",
|
|
255
|
+
helpTitle: "命令:",
|
|
256
|
+
helpHelp: "顯示說明。",
|
|
257
|
+
helpStatus: "顯示目前路由、工作區、沙盒與會話。",
|
|
258
|
+
helpLogin: "選擇、貼上並儲存專案本地 API Key。",
|
|
259
|
+
helpInstructions: "顯示 AGINTI.md 專案指令狀態。",
|
|
260
|
+
helpModels: "顯示 route/main/spare/wrapper/auxiliary 模型角色。",
|
|
261
|
+
helpVenice: "選擇 Venice route/main 模型,或恢復 DeepSeek 預設值。",
|
|
262
|
+
helpRoute: "開啟路由選擇器,或設定 routing/快速路由模型。",
|
|
263
|
+
helpModel: "開啟主模型選擇器,或設定 active/main 模型。",
|
|
264
|
+
helpSpare: "開啟備用模型選擇器,或設定例如 /spare openai/gpt-5.4 medium。",
|
|
265
|
+
helpWrapper: "設定可選外部 wrapper。",
|
|
266
|
+
helpAuxiliary: "管理可選輔助技能,包括圖像生成。",
|
|
267
|
+
helpNew: "下一則訊息開始新會話。",
|
|
268
|
+
helpResume: "繼續已儲存會話。",
|
|
269
|
+
helpSessions: "列出本專案最近會話。",
|
|
270
|
+
helpSkills: "列出為主題選擇的 Markdown 技能。",
|
|
271
|
+
helpProfile: "設定任務 profile,例如 code、website、latex、maintenance。",
|
|
272
|
+
helpWebSearch: "啟用或停用 web_search 工具。",
|
|
273
|
+
helpScouts: "啟用並設定並行 DeepSeek scouts 數量。",
|
|
274
|
+
helpRouting: "設定 routing: smart、fast、complex、manual。",
|
|
275
|
+
helpProvider: "開啟 provider 選擇器,或設定 deepseek/openai/qwen/venice/mock。",
|
|
276
|
+
helpDockerOn: "使用允許安裝套件的 docker-workspace。",
|
|
277
|
+
helpDockerOff: "使用主機 shell 策略。",
|
|
278
|
+
helpLatex: "在 Docker 中使用 LaTeX/PDF profile 和較大步數。",
|
|
279
|
+
helpInstalls: "設定套件安裝策略。",
|
|
280
|
+
helpCwd: "修改命令工作區。",
|
|
281
|
+
helpLanguage: "設定 CLI 語言,或用 /language auto 跟隨系統語言。",
|
|
282
|
+
helpExit: "離開。",
|
|
283
|
+
helpNormalRequest: "輸入普通任務即可執行智能體。例如: write a Python CLI app with tests",
|
|
284
|
+
helpAutocomplete: "輸入 / 後按 Tab 自動補全命令。",
|
|
285
|
+
helpQueue: "執行中 Enter 會把訊息立即傳入目前任務 (→),Tab 會排到結束後執行 (↳)。",
|
|
286
|
+
helpEditQueue: "Alt+Up 編輯上一條立即訊息;Shift+Left 編輯上一條排隊訊息。",
|
|
287
|
+
helpEsc: "空閒時 Esc 不操作。執行中 Esc 等待待處理 → 訊息或停止;Ctrl+C 始終停止。",
|
|
288
|
+
languageSet: "language={language} ({label})",
|
|
289
|
+
languageUsage: "用法: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
290
|
+
project: "專案",
|
|
291
|
+
statusNew: "new",
|
|
292
|
+
statusIdle: "idle",
|
|
293
|
+
systemLanguage: "系統",
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const FALLBACKS = {
|
|
298
|
+
ko: {
|
|
299
|
+
launchSubtitle: "웹 우선 에이전트 작업공간",
|
|
300
|
+
launchTagline: "브라우저 + 셸 + 파일 + Docker + 웹 검색 + 스카우트",
|
|
301
|
+
interactiveIntro: "대화형 에이전트 채팅입니다. /help 명령, /exit 종료.",
|
|
302
|
+
promptEmpty: "요청을 입력하세요. /help, Enter 전송, Ctrl+J 줄바꿈",
|
|
303
|
+
helpTitle: "명령:",
|
|
304
|
+
languageSet: "language={language} ({label})",
|
|
305
|
+
languageUsage: "사용법: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
306
|
+
project: "프로젝트",
|
|
307
|
+
systemLanguage: "시스템",
|
|
308
|
+
},
|
|
309
|
+
fr: {
|
|
310
|
+
launchSubtitle: "espace agent web-first",
|
|
311
|
+
launchTagline: "navigateur + shell + fichiers + Docker + recherche web + scouts",
|
|
312
|
+
interactiveIntro: "Chat agent interactif. Tapez /help pour les commandes, /exit pour quitter.",
|
|
313
|
+
promptEmpty: "tapez une demande, /help, Entrée pour envoyer, Ctrl+J pour une nouvelle ligne",
|
|
314
|
+
helpTitle: "Commandes:",
|
|
315
|
+
languageSet: "language={language} ({label})",
|
|
316
|
+
languageUsage: "Usage: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
317
|
+
project: "Projet",
|
|
318
|
+
systemLanguage: "système",
|
|
319
|
+
},
|
|
320
|
+
es: {
|
|
321
|
+
launchSubtitle: "espacio de agente centrado en web",
|
|
322
|
+
launchTagline: "navegador + shell + archivos + Docker + búsqueda web + scouts",
|
|
323
|
+
interactiveIntro: "Chat interactivo del agente. Escribe /help para comandos, /exit para salir.",
|
|
324
|
+
promptEmpty: "escribe una solicitud, /help, Enter para enviar, Ctrl+J para nueva línea",
|
|
325
|
+
helpTitle: "Comandos:",
|
|
326
|
+
languageSet: "language={language} ({label})",
|
|
327
|
+
languageUsage: "Uso: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
328
|
+
project: "Proyecto",
|
|
329
|
+
systemLanguage: "sistema",
|
|
330
|
+
},
|
|
331
|
+
ar: {
|
|
332
|
+
launchSubtitle: "مساحة عمل وكيل تعتمد الويب أولاً",
|
|
333
|
+
launchTagline: "متصفح + صدفة + ملفات + Docker + بحث ويب + كشافة",
|
|
334
|
+
interactiveIntro: "محادثة وكيل تفاعلية. اكتب /help للأوامر و /exit للخروج.",
|
|
335
|
+
promptEmpty: "اكتب طلباً، /help، Enter للإرسال، Ctrl+J لسطر جديد",
|
|
336
|
+
helpTitle: "الأوامر:",
|
|
337
|
+
languageSet: "language={language} ({label})",
|
|
338
|
+
languageUsage: "الاستخدام: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
339
|
+
project: "المشروع",
|
|
340
|
+
systemLanguage: "النظام",
|
|
341
|
+
},
|
|
342
|
+
vi: {
|
|
343
|
+
launchSubtitle: "không gian agent ưu tiên web",
|
|
344
|
+
launchTagline: "trình duyệt + shell + tệp + Docker + tìm kiếm web + scouts",
|
|
345
|
+
interactiveIntro: "Chat agent tương tác. Gõ /help để xem lệnh, /exit để thoát.",
|
|
346
|
+
promptEmpty: "nhập yêu cầu, /help, Enter để gửi, Ctrl+J xuống dòng",
|
|
347
|
+
helpTitle: "Lệnh:",
|
|
348
|
+
languageSet: "language={language} ({label})",
|
|
349
|
+
languageUsage: "Cách dùng: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
350
|
+
project: "Dự án",
|
|
351
|
+
systemLanguage: "hệ thống",
|
|
352
|
+
},
|
|
353
|
+
de: {
|
|
354
|
+
launchSubtitle: "web-first Agent-Arbeitsbereich",
|
|
355
|
+
launchTagline: "Browser + Shell + Dateien + Docker + Websuche + Scouts",
|
|
356
|
+
interactiveIntro: "Interaktiver Agent-Chat. /help für Befehle, /exit zum Beenden.",
|
|
357
|
+
promptEmpty: "Anfrage eingeben, /help, Enter zum Senden, Ctrl+J für neue Zeile",
|
|
358
|
+
helpTitle: "Befehle:",
|
|
359
|
+
languageSet: "language={language} ({label})",
|
|
360
|
+
languageUsage: "Nutzung: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
361
|
+
project: "Projekt",
|
|
362
|
+
systemLanguage: "System",
|
|
363
|
+
},
|
|
364
|
+
ru: {
|
|
365
|
+
launchSubtitle: "web-first рабочая область агента",
|
|
366
|
+
launchTagline: "браузер + shell + файлы + Docker + веб-поиск + scouts",
|
|
367
|
+
interactiveIntro: "Интерактивный чат агента. /help для команд, /exit для выхода.",
|
|
368
|
+
promptEmpty: "введите запрос, /help, Enter отправить, Ctrl+J новая строка",
|
|
369
|
+
helpTitle: "Команды:",
|
|
370
|
+
languageSet: "language={language} ({label})",
|
|
371
|
+
languageUsage: "Использование: /language auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru",
|
|
372
|
+
project: "Проект",
|
|
373
|
+
systemLanguage: "система",
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
for (const [language, values] of Object.entries(FALLBACKS)) {
|
|
378
|
+
TRANSLATIONS[language] = { ...TRANSLATIONS.en, ...values };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function cleanLanguage(value = "") {
|
|
382
|
+
return String(value || "")
|
|
383
|
+
.trim()
|
|
384
|
+
.replace(/\.(utf-?8|utf8)$/i, "")
|
|
385
|
+
.replace(/@.*$/, "")
|
|
386
|
+
.toLowerCase()
|
|
387
|
+
.replace(/\s+/g, "");
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export function normalizeLanguage(value = "", fallback = "en") {
|
|
391
|
+
const direct = String(value || "").trim();
|
|
392
|
+
if (SUPPORTED_LANGUAGES.includes(direct)) return direct;
|
|
393
|
+
const cleaned = cleanLanguage(value);
|
|
394
|
+
if (LANGUAGE_ALIASES.has(cleaned)) return LANGUAGE_ALIASES.get(cleaned) || fallback;
|
|
395
|
+
const dash = cleaned.replace(/_/g, "-");
|
|
396
|
+
if (LANGUAGE_ALIASES.has(dash)) return LANGUAGE_ALIASES.get(dash) || fallback;
|
|
397
|
+
if (dash.startsWith("zh-tw") || dash.startsWith("zh-hk") || dash.startsWith("zh-mo")) return "zh-Hant";
|
|
398
|
+
if (dash.startsWith("zh")) return "zh-Hans";
|
|
399
|
+
if (dash.startsWith("ja")) return "ja";
|
|
400
|
+
if (dash.startsWith("ko")) return "ko";
|
|
401
|
+
if (dash.startsWith("fr")) return "fr";
|
|
402
|
+
if (dash.startsWith("es")) return "es";
|
|
403
|
+
if (dash.startsWith("ar")) return "ar";
|
|
404
|
+
if (dash.startsWith("vi")) return "vi";
|
|
405
|
+
if (dash.startsWith("de")) return "de";
|
|
406
|
+
if (dash.startsWith("ru")) return "ru";
|
|
407
|
+
if (dash.startsWith("en")) return "en";
|
|
408
|
+
return SUPPORTED_LANGUAGES.includes(fallback) ? fallback : "en";
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export function detectSystemLanguage(env = process.env) {
|
|
412
|
+
return normalizeLanguage(env.AGINTI_LANGUAGE || env.LANGUAGE || env.LC_ALL || env.LC_MESSAGES || env.LANG || "en", "en");
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export function resolveLanguage(value = "", env = process.env) {
|
|
416
|
+
const cleaned = cleanLanguage(value);
|
|
417
|
+
if (!cleaned || ["auto", "system", "default"].includes(cleaned)) return detectSystemLanguage(env);
|
|
418
|
+
return normalizeLanguage(value, detectSystemLanguage(env));
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export function languageLabel(language = "en") {
|
|
422
|
+
return LANGUAGE_LABELS[normalizeLanguage(language)] || LANGUAGE_LABELS.en;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export function t(key, language = "en", values = {}) {
|
|
426
|
+
const normalized = normalizeLanguage(language);
|
|
427
|
+
const text = TRANSLATIONS[normalized]?.[key] || TRANSLATIONS.en[key] || key;
|
|
428
|
+
return Object.entries(values).reduce((result, [name, value]) => result.replaceAll(`{${name}}`, String(value)), text);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export function languageInstruction(language = "en") {
|
|
432
|
+
const normalized = normalizeLanguage(language);
|
|
433
|
+
if (normalized === "en") return "User interface language: English. Reply in the user's requested language; otherwise English is acceptable.";
|
|
434
|
+
return `User interface language: ${languageLabel(normalized)} (${normalized}). Prefer replying in this language unless the user explicitly requests another language.`;
|
|
435
|
+
}
|
package/src/interactive-cli.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
getModelRoleDefaults,
|
|
18
18
|
modelsForProviderGroup,
|
|
19
19
|
} from "./model-routing.js";
|
|
20
|
+
import { languageLabel, resolveLanguage, t } from "./i18n.js";
|
|
20
21
|
|
|
21
22
|
const useColor = Boolean(input.isTTY && output.isTTY && process.env.AGINTIFLOW_NO_COLOR !== "1");
|
|
22
23
|
const ansi = {
|
|
@@ -74,6 +75,8 @@ const SLASH_COMMANDS = [
|
|
|
74
75
|
"/routing",
|
|
75
76
|
"/provider",
|
|
76
77
|
"/model",
|
|
78
|
+
"/language",
|
|
79
|
+
"/lang",
|
|
77
80
|
"/docker",
|
|
78
81
|
"/latex",
|
|
79
82
|
"/installs",
|
|
@@ -84,6 +87,16 @@ const SLASH_COMMANDS = [
|
|
|
84
87
|
];
|
|
85
88
|
const promptHistory = [];
|
|
86
89
|
let activeRunInput = null;
|
|
90
|
+
let cliLanguage = resolveLanguage();
|
|
91
|
+
|
|
92
|
+
function setCliLanguage(language = "") {
|
|
93
|
+
cliLanguage = resolveLanguage(language || "");
|
|
94
|
+
return cliLanguage;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function tr(key, values = {}) {
|
|
98
|
+
return t(key, cliLanguage, values);
|
|
99
|
+
}
|
|
87
100
|
|
|
88
101
|
function color(value, ...codes) {
|
|
89
102
|
if (!useColor || codes.length === 0) return String(value);
|
|
@@ -534,9 +547,9 @@ function launchTitleLines(contentWidth) {
|
|
|
534
547
|
return largeWidth <= contentWidth ? LARGE_LAUNCH_TITLE : COMPACT_LAUNCH_TITLE;
|
|
535
548
|
}
|
|
536
549
|
|
|
537
|
-
export function buildLaunchHeaderLines({ packageVersion = "", frame = 2, width = terminalWidth(), animated = true } = {}) {
|
|
538
|
-
const subtitle = "
|
|
539
|
-
const tagline = "
|
|
550
|
+
export function buildLaunchHeaderLines({ packageVersion = "", frame = 2, width = terminalWidth(), animated = true, language = cliLanguage } = {}) {
|
|
551
|
+
const subtitle = t("launchSubtitle", language);
|
|
552
|
+
const tagline = t("launchTagline", language);
|
|
540
553
|
const version = packageVersion ? `v${packageVersion}` : "";
|
|
541
554
|
const terminalColumns = Math.max(Number(width) || 80, 50);
|
|
542
555
|
const contentWidth = Math.min(Math.max(terminalColumns - 8, 58), 112);
|
|
@@ -561,9 +574,9 @@ export function buildLaunchHeaderLines({ packageVersion = "", frame = 2, width =
|
|
|
561
574
|
return boxLines.map((line) => `${indent}${line}`);
|
|
562
575
|
}
|
|
563
576
|
|
|
564
|
-
async function renderLaunchHeader(packageVersion = "") {
|
|
577
|
+
async function renderLaunchHeader(packageVersion = "", language = cliLanguage) {
|
|
565
578
|
if (!useColor || process.env.AGINTIFLOW_NO_ANIMATION === "1") {
|
|
566
|
-
console.log(buildLaunchHeaderLines({ packageVersion, animated: false }).join("\n"));
|
|
579
|
+
console.log(buildLaunchHeaderLines({ packageVersion, animated: false, language }).join("\n"));
|
|
567
580
|
return;
|
|
568
581
|
}
|
|
569
582
|
|
|
@@ -572,7 +585,7 @@ async function renderLaunchHeader(packageVersion = "") {
|
|
|
572
585
|
let previousLineCount = 0;
|
|
573
586
|
output.write(ansi.cursorHide);
|
|
574
587
|
for (let frame = 0; frame < 18; frame += 1) {
|
|
575
|
-
const lines = [...paddingLines, ...buildLaunchHeaderLines({ packageVersion, frame, animated: true })];
|
|
588
|
+
const lines = [...paddingLines, ...buildLaunchHeaderLines({ packageVersion, frame, animated: true, language })];
|
|
576
589
|
if (previousLineCount > 0) output.write(`\x1b[${previousLineCount}A`);
|
|
577
590
|
output.write(lines.map((line) => `\r${ansi.clearLine}${line}`).join("\n"));
|
|
578
591
|
output.write("\n");
|
|
@@ -583,47 +596,45 @@ async function renderLaunchHeader(packageVersion = "") {
|
|
|
583
596
|
}
|
|
584
597
|
|
|
585
598
|
function printHelp() {
|
|
599
|
+
const command = (name, detail, key) => `${name.padEnd(28)} ${tr(key) || detail}`;
|
|
586
600
|
printAgentMessage(
|
|
587
601
|
[
|
|
588
|
-
"
|
|
589
|
-
"
|
|
590
|
-
"
|
|
591
|
-
"
|
|
592
|
-
"
|
|
593
|
-
"
|
|
594
|
-
"
|
|
595
|
-
"
|
|
596
|
-
"
|
|
597
|
-
"
|
|
598
|
-
"
|
|
599
|
-
"
|
|
600
|
-
"
|
|
601
|
-
"
|
|
602
|
-
"
|
|
603
|
-
"
|
|
604
|
-
"
|
|
605
|
-
"
|
|
606
|
-
"
|
|
607
|
-
"
|
|
608
|
-
"
|
|
609
|
-
"
|
|
610
|
-
"
|
|
611
|
-
"
|
|
612
|
-
"
|
|
613
|
-
"
|
|
614
|
-
"
|
|
615
|
-
"
|
|
616
|
-
"
|
|
617
|
-
"
|
|
618
|
-
" /installs block|prompt|allow",
|
|
619
|
-
" /cwd <path> Change command workspace.",
|
|
620
|
-
" /exit Quit.",
|
|
602
|
+
tr("helpTitle"),
|
|
603
|
+
` ${command("/help", "Show this help.", "helpHelp")}`,
|
|
604
|
+
` ${command("/status", "Show active route, workspace, sandbox, and session.", "helpStatus")}`,
|
|
605
|
+
` ${command("/login [deepseek|openai|qwen|venice|grsai]", "Pick, paste, and save project-local API keys.", "helpLogin")}`,
|
|
606
|
+
` ${command("/auth [deepseek|openai|qwen|venice|grsai]", "Alias for /login.", "helpLogin")}`,
|
|
607
|
+
` ${command("/instructions", "Show AGINTI.md project instructions status.", "helpInstructions")}`,
|
|
608
|
+
` ${command("/memory", "Alias for /instructions.", "helpInstructions")}`,
|
|
609
|
+
` ${command("/models", "Show route/main/spare/wrapper/auxiliary model roles.", "helpModels")}`,
|
|
610
|
+
` ${command("/venice [off|model]", "Pick Venice route/main models, or restore DeepSeek defaults.", "helpVenice")}`,
|
|
611
|
+
` ${command("/route [mode|provider/model]", "Open route selector, or set routing/fast route model.", "helpRoute")}`,
|
|
612
|
+
` ${command("/model [provider/model]", "Open main-model selector, or set the active/main model.", "helpModel")}`,
|
|
613
|
+
` ${command("/spare [provider/model] [reasoning]", "Open spare selector, or set e.g. /spare openai/gpt-5.4 medium.", "helpSpare")}`,
|
|
614
|
+
` ${command("/wrapper [on|off|codex model reasoning]", "Configure optional external wrapper.", "helpWrapper")}`,
|
|
615
|
+
` ${command("/auxiliary [status|grsai|venice|model [provider/model]|on|off|image]", "Manage optional auxiliary skills, including image generation.", "helpAuxiliary")}`,
|
|
616
|
+
` ${command("/new", "Start a fresh session on the next message.", "helpNew")}`,
|
|
617
|
+
` ${command("/resume <session-id>", "Continue a saved session.", "helpResume")}`,
|
|
618
|
+
` ${command("/sessions", "List recent sessions in this project.", "helpSessions")}`,
|
|
619
|
+
` ${command("/skills [query]", "List Markdown skills selected for a topic.", "helpSkills")}`,
|
|
620
|
+
` ${command("/profile <name>", "Set task profile, e.g. code, website, latex, maintenance.", "helpProfile")}`,
|
|
621
|
+
` ${command("/web-search on|off", "Enable or disable the web_search tool.", "helpWebSearch")}`,
|
|
622
|
+
` ${command("/scouts on|off|<1-10>", "Enable parallel DeepSeek scouts and set scout count.", "helpScouts")}`,
|
|
623
|
+
` ${command("/routing <mode>", "Set routing: smart, fast, complex, manual.", "helpRouting")}`,
|
|
624
|
+
` ${command("/provider [name]", "Open provider selector, or set deepseek/openai/qwen/venice/mock.", "helpProvider")}`,
|
|
625
|
+
` ${command("/docker on", "Use docker-workspace with approved package installs.", "helpDockerOn")}`,
|
|
626
|
+
` ${command("/docker off", "Use host shell policy.", "helpDockerOff")}`,
|
|
627
|
+
` ${command("/latex on", "Use the LaTeX/PDF profile in Docker with a larger step budget.", "helpLatex")}`,
|
|
628
|
+
` ${command("/installs block|prompt|allow", "Set package install policy.", "helpInstalls")}`,
|
|
629
|
+
` ${command("/cwd <path>", "Change command workspace.", "helpCwd")}`,
|
|
630
|
+
` ${command("/language [auto|en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru]", "Set CLI language.", "helpLanguage")}`,
|
|
631
|
+
` ${command("/exit", "Quit.", "helpExit")}`,
|
|
621
632
|
"",
|
|
622
|
-
"
|
|
623
|
-
"
|
|
624
|
-
"
|
|
625
|
-
"
|
|
626
|
-
"
|
|
633
|
+
tr("helpNormalRequest"),
|
|
634
|
+
tr("helpAutocomplete"),
|
|
635
|
+
tr("helpQueue"),
|
|
636
|
+
tr("helpEditQueue"),
|
|
637
|
+
tr("helpEsc"),
|
|
627
638
|
].join("\n")
|
|
628
639
|
);
|
|
629
640
|
}
|
|
@@ -754,7 +765,7 @@ export function buildPromptLayout(buffer = "", cursor = 0, width = terminalWidth
|
|
|
754
765
|
? options.suggestions
|
|
755
766
|
: commandSuggestions(safeBuffer.split("\n")[0] || "");
|
|
756
767
|
const suggestionIndex = clamp(Number(options.suggestionIndex) || 0, 0, Math.max(suggestions.length - 1, 0));
|
|
757
|
-
const emptyHint = "
|
|
768
|
+
const emptyHint = t("promptEmpty", options.language || cliLanguage);
|
|
758
769
|
const visible = promptVisibleWindow(rows, cursorRow, height);
|
|
759
770
|
const renderedRows = [];
|
|
760
771
|
let renderedCursorRow = cursorRow - visible.start;
|
|
@@ -973,6 +984,7 @@ function readTtyPrompt(options = {}) {
|
|
|
973
984
|
const suggestions = commandSuggestions(suggestionAnchor || buffer.split("\n")[0] || "");
|
|
974
985
|
rendered = renderPromptBuffer(buffer, cursor, rendered, {
|
|
975
986
|
...options,
|
|
987
|
+
language: options.language || cliLanguage,
|
|
976
988
|
suggestions,
|
|
977
989
|
suggestionIndex,
|
|
978
990
|
});
|
|
@@ -1178,7 +1190,7 @@ function readTtyPrompt(options = {}) {
|
|
|
1178
1190
|
|
|
1179
1191
|
async function readPromptAnswer(rl, state = {}) {
|
|
1180
1192
|
if (input.isTTY && output.isTTY && typeof input.setRawMode === "function") {
|
|
1181
|
-
return readTtyPrompt({ commandCwd: state.commandCwd || process.cwd() });
|
|
1193
|
+
return readTtyPrompt({ commandCwd: state.commandCwd || process.cwd(), language: state.language || cliLanguage });
|
|
1182
1194
|
}
|
|
1183
1195
|
return rl.question(userPrompt());
|
|
1184
1196
|
}
|
|
@@ -1261,6 +1273,7 @@ class LiveRunInput {
|
|
|
1261
1273
|
}
|
|
1262
1274
|
this.rendered = renderPromptBuffer(this.buffer, this.cursor, this.rendered, {
|
|
1263
1275
|
commandCwd: this.commandCwd,
|
|
1276
|
+
language: this.state.language || cliLanguage,
|
|
1264
1277
|
statusLine: this.statusLine,
|
|
1265
1278
|
pendingAsap: this.pendingAsap,
|
|
1266
1279
|
pendingQueued: this.pendingQueued,
|
|
@@ -1292,6 +1305,7 @@ class LiveRunInput {
|
|
|
1292
1305
|
moveVertical(direction) {
|
|
1293
1306
|
const layout = buildPromptLayout(this.buffer, this.cursor, terminalWidth(), terminalHeight(), {
|
|
1294
1307
|
commandCwd: this.commandCwd,
|
|
1308
|
+
language: this.state.language || cliLanguage,
|
|
1295
1309
|
statusLine: this.statusLine,
|
|
1296
1310
|
pendingAsap: this.pendingAsap,
|
|
1297
1311
|
pendingQueued: this.pendingQueued,
|
|
@@ -1496,6 +1510,7 @@ function printStatus(state) {
|
|
|
1496
1510
|
printSystemLine(`cwd=${state.commandCwd || process.cwd()}`);
|
|
1497
1511
|
printSystemLine(`session=${state.sessionId || "new"}`);
|
|
1498
1512
|
printSystemLine(`status=${state.status || "idle"}${state.activeGoal ? ` workingOn=${state.activeGoal}` : ""}`);
|
|
1513
|
+
printSystemLine(`language=${state.language || cliLanguage} (${languageLabel(state.language || cliLanguage)})`);
|
|
1499
1514
|
if (state.lastEvent) printSystemLine(`last=${state.lastEvent}`);
|
|
1500
1515
|
printSystemLine(`provider=${state.provider || "auto"} routing=${state.routingMode} model=${state.model || "auto"}`);
|
|
1501
1516
|
printSystemLine(
|
|
@@ -1638,6 +1653,7 @@ function createState(args = {}) {
|
|
|
1638
1653
|
auxiliaryProvider: args.auxiliaryProvider || "grsai",
|
|
1639
1654
|
auxiliaryModel: args.auxiliaryModel || "nano-banana-2",
|
|
1640
1655
|
taskProfile: normalizeTaskProfile(args.taskProfile || "auto"),
|
|
1656
|
+
language: resolveLanguage(args.language || process.env.AGINTI_LANGUAGE || ""),
|
|
1641
1657
|
headless: args.headless ?? false,
|
|
1642
1658
|
maxSteps:
|
|
1643
1659
|
Number.isFinite(args.maxSteps) && args.maxSteps > 0
|
|
@@ -2202,6 +2218,18 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2202
2218
|
);
|
|
2203
2219
|
return true;
|
|
2204
2220
|
}
|
|
2221
|
+
if (command === "language" || command === "lang") {
|
|
2222
|
+
if (!value) {
|
|
2223
|
+
printSystemLine(tr("languageSet", { language: state.language || cliLanguage, label: languageLabel(state.language || cliLanguage) }));
|
|
2224
|
+
printAgentMessage(tr("languageUsage"));
|
|
2225
|
+
return true;
|
|
2226
|
+
}
|
|
2227
|
+
const nextLanguage = resolveLanguage(value);
|
|
2228
|
+
state.language = nextLanguage;
|
|
2229
|
+
setCliLanguage(nextLanguage);
|
|
2230
|
+
printSystemLine(tr("languageSet", { language: nextLanguage, label: languageLabel(nextLanguage) }));
|
|
2231
|
+
return true;
|
|
2232
|
+
}
|
|
2205
2233
|
if (command === "login" || command === "auth") {
|
|
2206
2234
|
await promptAndSaveProviderKey(value || "deepseek", state);
|
|
2207
2235
|
return true;
|
|
@@ -2628,6 +2656,7 @@ async function runPrompt(prompt, state, packageDir) {
|
|
|
2628
2656
|
auxiliaryProvider: state.auxiliaryProvider,
|
|
2629
2657
|
auxiliaryModel: state.auxiliaryModel,
|
|
2630
2658
|
taskProfile: state.taskProfile,
|
|
2659
|
+
language: state.language || cliLanguage,
|
|
2631
2660
|
maxSteps: runMaxSteps,
|
|
2632
2661
|
headless: state.headless,
|
|
2633
2662
|
resume: state.sessionId,
|
|
@@ -2729,6 +2758,7 @@ async function runPrompt(prompt, state, packageDir) {
|
|
|
2729
2758
|
|
|
2730
2759
|
export async function startInteractiveCli(args = {}, { packageDir, packageVersion } = {}) {
|
|
2731
2760
|
const state = createState(args);
|
|
2761
|
+
setCliLanguage(state.language);
|
|
2732
2762
|
const rl =
|
|
2733
2763
|
input.isTTY && output.isTTY
|
|
2734
2764
|
? null
|
|
@@ -2739,10 +2769,10 @@ export async function startInteractiveCli(args = {}, { packageDir, packageVersio
|
|
|
2739
2769
|
completer: commandCompleter,
|
|
2740
2770
|
});
|
|
2741
2771
|
|
|
2742
|
-
await renderLaunchHeader(packageVersion);
|
|
2743
|
-
printSystemLine(
|
|
2772
|
+
await renderLaunchHeader(packageVersion, state.language);
|
|
2773
|
+
printSystemLine(`${tr("project")}: ${process.cwd()}`);
|
|
2744
2774
|
await maybeOnboardDeepSeekKey(state);
|
|
2745
|
-
printAgentMessage("
|
|
2775
|
+
printAgentMessage(tr("interactiveIntro"));
|
|
2746
2776
|
printStatus(state);
|
|
2747
2777
|
await printResumeHistory(state);
|
|
2748
2778
|
|
package/src/web-db.js
CHANGED
|
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { DatabaseSync } from "node:sqlite";
|
|
4
4
|
import { getModelPresets, getModelRoleDefaults } from "./model-routing.js";
|
|
5
|
+
import { resolveLanguage } from "./i18n.js";
|
|
5
6
|
|
|
6
7
|
const PREFERENCES_SCHEMA_VERSION = 7;
|
|
7
8
|
|
|
@@ -44,7 +45,7 @@ function defaultPreferences(baseDir) {
|
|
|
44
45
|
dockerSandboxImage: "agintiflow-sandbox:latest",
|
|
45
46
|
allowPasswords: false,
|
|
46
47
|
allowDestructive: false,
|
|
47
|
-
language: "
|
|
48
|
+
language: resolveLanguage(process.env.AGINTI_LANGUAGE || ""),
|
|
48
49
|
taskProfile: "auto",
|
|
49
50
|
};
|
|
50
51
|
}
|
package/web.js
CHANGED
|
@@ -24,6 +24,7 @@ import { loadProjectEnv, projectPaths, providerKeyStatus, setProviderKey } from
|
|
|
24
24
|
import { buildCapabilityReport } from "./src/capabilities.js";
|
|
25
25
|
import { listSkills } from "./src/skill-library.js";
|
|
26
26
|
import { platformInfo, platformLabel, platformSetupHints } from "./src/platform.js";
|
|
27
|
+
import { normalizeLanguage } from "./src/i18n.js";
|
|
27
28
|
import {
|
|
28
29
|
buildArtifacts,
|
|
29
30
|
countUnreadArtifacts,
|
|
@@ -45,24 +46,6 @@ const port = Number(process.env.PORT || 3210);
|
|
|
45
46
|
const host = process.env.HOST || "127.0.0.1";
|
|
46
47
|
const runs = new Map();
|
|
47
48
|
const db = new WebDatabase(baseDir);
|
|
48
|
-
const supportedLanguages = new Set([
|
|
49
|
-
"en",
|
|
50
|
-
"ar",
|
|
51
|
-
"es",
|
|
52
|
-
"fr",
|
|
53
|
-
"ja",
|
|
54
|
-
"ko",
|
|
55
|
-
"vi",
|
|
56
|
-
"zh-Hans",
|
|
57
|
-
"zh-Hant",
|
|
58
|
-
"de",
|
|
59
|
-
"ru",
|
|
60
|
-
]);
|
|
61
|
-
|
|
62
|
-
function normalizeLanguage(language, fallback = "en") {
|
|
63
|
-
if (supportedLanguages.has(language)) return language;
|
|
64
|
-
return supportedLanguages.has(fallback) ? fallback : "en";
|
|
65
|
-
}
|
|
66
49
|
|
|
67
50
|
function sessionStore(sessionId) {
|
|
68
51
|
return new SessionStore(sessionsDir, sessionId);
|
|
@@ -231,7 +214,7 @@ function normalizePreferencePayload(body = {}, current = db.getPreferences()) {
|
|
|
231
214
|
allowPasswords: typeof body.allowPasswords === "boolean" ? body.allowPasswords : Boolean(current.allowPasswords),
|
|
232
215
|
allowDestructive:
|
|
233
216
|
typeof body.allowDestructive === "boolean" ? body.allowDestructive : Boolean(current.allowDestructive),
|
|
234
|
-
language: normalizeLanguage(body.language, current.language),
|
|
217
|
+
language: normalizeLanguage(body.language || process.env.AGINTI_LANGUAGE || current.language, current.language || "en"),
|
|
235
218
|
};
|
|
236
219
|
}
|
|
237
220
|
|
|
@@ -310,6 +293,7 @@ function buildRunConfig(body, overrides = {}) {
|
|
|
310
293
|
dockerSandboxImage: merged.dockerSandboxImage,
|
|
311
294
|
commandCwd: merged.commandCwd,
|
|
312
295
|
taskProfile: merged.taskProfile,
|
|
296
|
+
language: merged.language,
|
|
313
297
|
baseDir,
|
|
314
298
|
packageDir,
|
|
315
299
|
sessionId: overrides.sessionId,
|