@armadra/agent 0.7.3 → 0.7.5
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/CHANGELOG.md +48 -0
- package/CHANGELOG.zh-CN.md +48 -0
- package/dist/agent/retry.d.ts +14 -5
- package/dist/agent/retry.js +30 -8
- package/dist/agent/session-cache-key.d.ts +8 -0
- package/dist/agent/session-cache-key.js +46 -0
- package/dist/agent/session-cache.d.ts +2 -3
- package/dist/agent/session-cache.js +19 -37
- package/dist/agent/session-classifier.d.ts +3 -2
- package/dist/agent/session-classifier.js +36 -10
- package/dist/agent/session-compaction.d.ts +24 -5
- package/dist/agent/session-compaction.js +54 -20
- package/dist/agent/session-core.d.ts +2 -0
- package/dist/agent/session-run.d.ts +12 -0
- package/dist/agent/session-run.js +29 -10
- package/dist/agent/session-subagent.d.ts +8 -1
- package/dist/agent/session-subagent.js +37 -14
- package/dist/agent/session-sync.d.ts +8 -2
- package/dist/agent/session-sync.js +7 -10
- package/dist/agent/session-tools.js +3 -2
- package/dist/agent/subagent-fork.d.ts +67 -0
- package/dist/agent/subagent-fork.js +87 -0
- package/dist/agent/subagent-registry.d.ts +2 -2
- package/dist/agent/subagent-registry.js +2 -2
- package/dist/agent/tool-availability.d.ts +8 -0
- package/dist/agent/tool-availability.js +8 -0
- package/dist/agent/tool-runner.js +13 -4
- package/dist/agent/worktree.d.ts +8 -0
- package/dist/agent/worktree.js +51 -4
- package/dist/agents/parse.js +6 -1
- package/dist/agents/task-record.js +3 -0
- package/dist/agents/types.d.ts +2 -0
- package/dist/ai/apis/anthropic-messages.js +10 -5
- package/dist/ai/apis/anthropic-request.d.ts +2 -1
- package/dist/ai/apis/anthropic-request.js +15 -4
- package/dist/ai/apis/cache-params.js +2 -1
- package/dist/ai/apis/google-generative-ai.js +4 -2
- package/dist/ai/apis/google-request.js +2 -1
- package/dist/ai/apis/max-tokens.d.ts +42 -0
- package/dist/ai/apis/max-tokens.js +121 -0
- package/dist/ai/apis/openai-completions.js +10 -5
- package/dist/ai/apis/openai-request.js +4 -2
- package/dist/ai/apis/openai-responses-request.js +3 -2
- package/dist/ai/apis/openai-responses.js +9 -5
- package/dist/ai/apis/shared.d.ts +3 -1
- package/dist/ai/apis/shared.js +21 -3
- package/dist/ai/cache/fingerprint.d.ts +4 -1
- package/dist/ai/cache/fingerprint.js +18 -1
- package/dist/ai/cache/miss.d.ts +2 -1
- package/dist/ai/cache/miss.js +9 -3
- package/dist/ai/cache/reporting.js +5 -1
- package/dist/ai/cache/types.d.ts +10 -2
- package/dist/ai/cache/warmer.d.ts +6 -1
- package/dist/ai/cache/warmer.js +7 -0
- package/dist/ai/context.d.ts +12 -4
- package/dist/ai/context.js +43 -24
- package/dist/ai/fake/fake-provider.d.ts +8 -1
- package/dist/ai/fake/fake-provider.js +19 -7
- package/dist/ai/fake/fake-script.d.ts +2 -0
- package/dist/ai/http.d.ts +17 -9
- package/dist/ai/http.js +33 -13
- package/dist/ai/image-intern.d.ts +29 -0
- package/dist/ai/image-intern.js +58 -0
- package/dist/ai/json-body.d.ts +63 -0
- package/dist/ai/json-body.js +286 -0
- package/dist/ai/overflow.js +5 -0
- package/dist/ai/providers/catalog-data.js +13 -13
- package/dist/ai/providers/catalog.d.ts +33 -0
- package/dist/ai/providers/catalog.js +105 -6
- package/dist/ai/providers/enrich.d.ts +13 -3
- package/dist/ai/providers/enrich.js +87 -31
- package/dist/ai/sse.d.ts +3 -2
- package/dist/ai/sse.js +3 -2
- package/dist/ai/types.d.ts +9 -2
- package/dist/bundle/ama.cjs +3637 -1973
- package/dist/cli/bootstrap.js +13 -5
- package/dist/cli/compose-agents.js +3 -0
- package/dist/cli/compose-extensions.js +2 -0
- package/dist/cli/compose-request.d.ts +20 -0
- package/dist/cli/compose-request.js +37 -0
- package/dist/cli/compose-session.js +2 -2
- package/dist/cli/deps.d.ts +1 -1
- package/dist/cli/subcommands/model-meta.d.ts +2 -1
- package/dist/cli/subcommands/model-meta.js +3 -2
- package/dist/codemode/host-side.d.ts +11 -4
- package/dist/codemode/host-side.js +25 -6
- package/dist/codemode/tool.d.ts +2 -0
- package/dist/codemode/tool.js +4 -0
- package/dist/config/json-schema.js +9 -2
- package/dist/config/key-docs.js +13 -4
- package/dist/config/schema-w5.js +9 -1
- package/dist/config/schema.d.ts +1 -1
- package/dist/config/schema.js +19 -3
- package/dist/config/settings-registry.js +6 -0
- package/dist/config/types-w5.d.ts +2 -0
- package/dist/config/types.d.ts +19 -1
- package/dist/config/types.js +4 -0
- package/dist/i18n/catalog.d.ts +13 -2
- package/dist/i18n/messages/cli.d.ts +2 -0
- package/dist/i18n/messages/cli.js +2 -0
- package/dist/i18n/messages/config-keys.d.ts +10 -0
- package/dist/i18n/messages/config-keys.js +12 -2
- package/dist/i18n/messages/config.d.ts +14 -0
- package/dist/i18n/messages/config.js +4 -0
- package/dist/i18n/messages/errors.d.ts +3 -2
- package/dist/i18n/messages/errors.js +15 -2
- package/dist/i18n/messages/report.d.ts +2 -0
- package/dist/i18n/messages/report.js +2 -0
- package/dist/i18n/messages/settings.d.ts +4 -0
- package/dist/i18n/messages/settings.js +6 -2
- package/dist/i18n/messages/subcommands.d.ts +2 -2
- package/dist/i18n/messages/subcommands.js +4 -2
- package/dist/modes/acp/acp-server.js +30 -18
- package/dist/modes/acp/acp-sessions.d.ts +22 -0
- package/dist/modes/acp/acp-sessions.js +68 -0
- package/dist/modes/context-report.js +3 -2
- package/dist/modes/print/json-event.d.ts +12 -1
- package/dist/modes/print/json-event.js +48 -1
- package/dist/modes/rpc/rpc-mode.d.ts +1 -0
- package/dist/modes/rpc/rpc-mode.js +9 -2
- package/dist/modes/session-report.d.ts +1 -1
- package/dist/modes/session-report.js +12 -6
- package/dist/rpc.d.ts +5 -2
- package/dist/session/line-reader.d.ts +28 -0
- package/dist/session/line-reader.js +82 -0
- package/dist/session/list.d.ts +14 -0
- package/dist/session/list.js +150 -0
- package/dist/session/manager.d.ts +23 -3
- package/dist/session/manager.js +91 -62
- package/dist/session/migrate.d.ts +2 -1
- package/dist/session/migrate.js +2 -1
- package/dist/session/offload.d.ts +51 -0
- package/dist/session/offload.js +195 -0
- package/dist/session/projection.d.ts +16 -3
- package/dist/session/projection.js +96 -29
- package/dist/session/scan.d.ts +3 -3
- package/dist/session/scan.js +9 -18
- package/dist/session/store.d.ts +15 -4
- package/dist/session/store.js +54 -38
- package/dist/session/types.d.ts +7 -2
- package/dist/tools/bash.d.ts +1 -1
- package/dist/tools/bash.js +5 -4
- package/dist/tools/glob.d.ts +2 -2
- package/dist/tools/glob.js +2 -2
- package/dist/tools/grep.js +4 -6
- package/dist/tools/image-file.js +2 -1
- package/dist/tools/read-lines.d.ts +71 -0
- package/dist/tools/read-lines.js +224 -0
- package/dist/tools/read.d.ts +6 -2
- package/dist/tools/read.js +47 -27
- package/dist/tools/task.d.ts +9 -0
- package/dist/tools/task.js +21 -8
- package/dist/tools/truncate.d.ts +7 -0
- package/dist/tools/truncate.js +11 -0
- package/dist/tools/types.d.ts +13 -0
- package/dist/trace/build-index.js +13 -1
- package/dist/tui/ansi.d.ts +2 -0
- package/dist/tui/ansi.js +7 -3
- package/dist/tui/components/editor-buffer.js +2 -2
- package/dist/tui/components/editor.js +5 -6
- package/dist/tui/keys.js +2 -2
- package/dist/tui/stdin-buffer.js +3 -3
- package/docs/acp.md +8 -1
- package/docs/agents.md +42 -6
- package/docs/codemode.md +4 -2
- package/docs/en/acp.md +3 -2
- package/docs/en/host-api.md +1 -1
- package/docs/en/permissions.md +2 -2
- package/docs/en/providers.md +54 -20
- package/docs/en/rpc.md +23 -7
- package/docs/en/sessions.md +4 -2
- package/docs/en/tui.md +2 -2
- package/docs/permissions.md +4 -1
- package/docs/providers.md +85 -22
- package/docs/rpc.md +22 -6
- package/docs/session-format.md +13 -2
- package/docs/sessions.md +3 -1
- package/docs/tui.md +1 -1
- package/package.json +2 -2
package/dist/cli/bootstrap.js
CHANGED
|
@@ -76,7 +76,8 @@ export async function bootstrap(argsIn, deps, io) {
|
|
|
76
76
|
request = { kind: "resume", id };
|
|
77
77
|
}
|
|
78
78
|
const sessionRequest = request;
|
|
79
|
-
|
|
79
|
+
// [#165] 会话替换后跟随当前会话(闭包只经它取,启动会话的 manager 不被常驻)
|
|
80
|
+
let sessionManager = await step(ExitCode.Session, m().steps.session, () => deps.sessions.open(sessionRequest, { sessionDir: paths.sessionDir, cwd: paths.cwd }));
|
|
80
81
|
let sessionCwd = sessionManager.cwd;
|
|
81
82
|
if (!existsSync(sessionCwd)) {
|
|
82
83
|
const replacement = interactive ? await deps.ui?.askCwd?.(sessionCwd) : undefined;
|
|
@@ -281,6 +282,8 @@ export async function bootstrap(argsIn, deps, io) {
|
|
|
281
282
|
uiBroker: () => uiBroker,
|
|
282
283
|
onSessionReplaced: (next) => {
|
|
283
284
|
session = next;
|
|
285
|
+
sessionManager = next.manager ?? sessionManager;
|
|
286
|
+
assembly.sessionManager = sessionManager;
|
|
284
287
|
},
|
|
285
288
|
sessionStartContext: () => sessionStartContext,
|
|
286
289
|
unattended,
|
|
@@ -302,7 +305,7 @@ export async function bootstrap(argsIn, deps, io) {
|
|
|
302
305
|
if (Object.keys(overrides).length > 0)
|
|
303
306
|
assembly.overrides = overrides;
|
|
304
307
|
session = await step(ExitCode.RuntimeError, m().steps.assembly, () => deps.session.create(assembly));
|
|
305
|
-
const active = session;
|
|
308
|
+
const active = session; // 只同步使用:闭包捕获它会让启动会话常驻(#165)
|
|
306
309
|
let disposed;
|
|
307
310
|
shutdown = (reason) => {
|
|
308
311
|
disposed ??= (async () => {
|
|
@@ -310,7 +313,7 @@ export async function bootstrap(argsIn, deps, io) {
|
|
|
310
313
|
await hooks.run("SessionEnd", { reason }).catch(() => undefined);
|
|
311
314
|
await disposeHost(host, (e) => warn(m().hostDisposeFailed(String(e))));
|
|
312
315
|
// 会话被替换过时 dispose 当前那个(旧会话由替换方负责)
|
|
313
|
-
await
|
|
316
|
+
await session?.dispose();
|
|
314
317
|
})();
|
|
315
318
|
return disposed;
|
|
316
319
|
};
|
|
@@ -339,8 +342,13 @@ export async function bootstrap(argsIn, deps, io) {
|
|
|
339
342
|
providers,
|
|
340
343
|
model,
|
|
341
344
|
thinkingLevel,
|
|
342
|
-
|
|
343
|
-
|
|
345
|
+
// [#165] 跟随当前会话(ACP 关掉启动会话后它可被回收)
|
|
346
|
+
get sessionManager() {
|
|
347
|
+
return sessionManager;
|
|
348
|
+
},
|
|
349
|
+
get session() {
|
|
350
|
+
return session;
|
|
351
|
+
},
|
|
344
352
|
hooks,
|
|
345
353
|
host,
|
|
346
354
|
permission,
|
|
@@ -56,6 +56,9 @@ export function subagentEnvironment(deps, catalog) {
|
|
|
56
56
|
const pending = config.subagents?.maxPending;
|
|
57
57
|
if (pending !== undefined)
|
|
58
58
|
env.maxPending = pending;
|
|
59
|
+
const retain = config.subagents?.retainSessions; // [M-F] 子会话句柄 LRU 上限
|
|
60
|
+
if (retain !== undefined)
|
|
61
|
+
env.retain = retain;
|
|
59
62
|
// [W7-B1] 缺省后台与自动转后台(配置键 W7-B2 登记于 config/types-w5.ts)
|
|
60
63
|
const sub = config.subagents;
|
|
61
64
|
env.background = resolveTaskBackground(sub?.background, deps.assembly.unattended === true);
|
|
@@ -25,6 +25,7 @@ import { createLimitsExtension } from "../agent/limits.js";
|
|
|
25
25
|
import { createRemindersExtension, remindersSettings } from "../agent/reminders.js";
|
|
26
26
|
import { planExtensionFor } from "../plan/compose.js";
|
|
27
27
|
import { createSubagentsFactory } from "./compose-agents.js";
|
|
28
|
+
import { requestTimeoutsFactory } from "./compose-request.js";
|
|
28
29
|
import { createExternalStatsExtension } from "../drivers/store.js";
|
|
29
30
|
export function composeExtensions(deps) {
|
|
30
31
|
return [
|
|
@@ -42,5 +43,6 @@ export function composeExtensions(deps) {
|
|
|
42
43
|
// [W5-E] 外部 Agent 记账 → SessionStats.external(只主会话)
|
|
43
44
|
({ core }) => core.depth > 0 ? undefined : createExternalStatsExtension(() => core.manager.branch()),
|
|
44
45
|
createSubagentsFactory(deps), // [W5-G] 子 Agent 任务注册表
|
|
46
|
+
requestTimeoutsFactory(deps), // [ME-C] request.streamIdleTimeoutMs → 每次请求的流中空闲上限
|
|
45
47
|
];
|
|
46
48
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模型请求的流中空闲超时(docs/model-efficiency-plan.md D18)。[ME-C]
|
|
3
|
+
*
|
|
4
|
+
* 等响应头仍由 `request.idleTimeoutMs` / `AMA_IDLE_TIMEOUT_MS`(compose-session.ts `idleTimeoutFrom`)
|
|
5
|
+
* 决定;流开始后两块数据之间的上限读 `AMA_STREAM_IDLE_TIMEOUT_MS` > config
|
|
6
|
+
* `request.streamIdleTimeoutMs`,都没有时协议层取缺省 180 000(ai/http.ts)。
|
|
7
|
+
*
|
|
8
|
+
* `session.ts` 不加行:值经会话扩展的 `wrapStream` 写进每次请求的 `StreamOptions.streamIdleTimeoutMs`
|
|
9
|
+
* (已显式给出的不覆盖);工厂对主会话与 task 子会话都装(子会话沿用父的扩展表)。
|
|
10
|
+
*/
|
|
11
|
+
import type { SessionExtensionFactory } from "../agent/session-extensions.js";
|
|
12
|
+
import type { AmaConfig } from "../config/types.js";
|
|
13
|
+
import type { ComposeExtensionDeps } from "./compose-extensions.js";
|
|
14
|
+
export declare const STREAM_IDLE_TIMEOUT_ENV = "AMA_STREAM_IDLE_TIMEOUT_MS";
|
|
15
|
+
/** 流中空闲超时:环境变量 > config;都没有 → undefined。0 关闭;非法的环境变量值忽略并 warning。 */
|
|
16
|
+
export declare function streamIdleTimeoutFrom(config: Pick<AmaConfig, "request">, env?: NodeJS.ProcessEnv, warn?: (message: string) => void): number | undefined;
|
|
17
|
+
/** 给每次请求补上 `streamIdleTimeoutMs`(调用方已给出的不覆盖)。 */
|
|
18
|
+
export declare function streamIdleExtension(ms: number): SessionExtensionFactory;
|
|
19
|
+
/** compose-extensions.ts 表里的一行:配置或环境变量给了值才装。 */
|
|
20
|
+
export declare function requestTimeoutsFactory(deps: ComposeExtensionDeps): SessionExtensionFactory;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模型请求的流中空闲超时(docs/model-efficiency-plan.md D18)。[ME-C]
|
|
3
|
+
*
|
|
4
|
+
* 等响应头仍由 `request.idleTimeoutMs` / `AMA_IDLE_TIMEOUT_MS`(compose-session.ts `idleTimeoutFrom`)
|
|
5
|
+
* 决定;流开始后两块数据之间的上限读 `AMA_STREAM_IDLE_TIMEOUT_MS` > config
|
|
6
|
+
* `request.streamIdleTimeoutMs`,都没有时协议层取缺省 180 000(ai/http.ts)。
|
|
7
|
+
*
|
|
8
|
+
* `session.ts` 不加行:值经会话扩展的 `wrapStream` 写进每次请求的 `StreamOptions.streamIdleTimeoutMs`
|
|
9
|
+
* (已显式给出的不覆盖);工厂对主会话与 task 子会话都装(子会话沿用父的扩展表)。
|
|
10
|
+
*/
|
|
11
|
+
import { msg } from "../i18n/index.js";
|
|
12
|
+
export const STREAM_IDLE_TIMEOUT_ENV = "AMA_STREAM_IDLE_TIMEOUT_MS";
|
|
13
|
+
/** 流中空闲超时:环境变量 > config;都没有 → undefined。0 关闭;非法的环境变量值忽略并 warning。 */
|
|
14
|
+
export function streamIdleTimeoutFrom(config, env = process.env, warn = () => undefined) {
|
|
15
|
+
const raw = env[STREAM_IDLE_TIMEOUT_ENV];
|
|
16
|
+
if (raw !== undefined && raw.trim() !== "") {
|
|
17
|
+
const value = Number(raw);
|
|
18
|
+
if (Number.isFinite(value) && value >= 0)
|
|
19
|
+
return value;
|
|
20
|
+
warn(msg().cli.composeSession.invalidStreamIdleTimeout(raw));
|
|
21
|
+
}
|
|
22
|
+
return config.request?.streamIdleTimeoutMs;
|
|
23
|
+
}
|
|
24
|
+
/** 给每次请求补上 `streamIdleTimeoutMs`(调用方已给出的不覆盖)。 */
|
|
25
|
+
export function streamIdleExtension(ms) {
|
|
26
|
+
return () => ({
|
|
27
|
+
id: "request-timeouts",
|
|
28
|
+
wrapStream: (stream) => (model, context, options) => stream(model, context, options.streamIdleTimeoutMs === undefined
|
|
29
|
+
? { ...options, streamIdleTimeoutMs: ms }
|
|
30
|
+
: options),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** compose-extensions.ts 表里的一行:配置或环境变量给了值才装。 */
|
|
34
|
+
export function requestTimeoutsFactory(deps) {
|
|
35
|
+
const ms = streamIdleTimeoutFrom(deps.assembly.config, deps.env, (message) => deps.log("warn", message));
|
|
36
|
+
return ms === undefined ? () => undefined : streamIdleExtension(ms);
|
|
37
|
+
}
|
|
@@ -411,8 +411,8 @@ export async function createSessionAlongside(target, request, options = {}) {
|
|
|
411
411
|
const { assembly } = record;
|
|
412
412
|
const sessionDir = assembly.paths.sessionDir;
|
|
413
413
|
const fresh = (id) => assembly.overrides?.noSession === true
|
|
414
|
-
? SessionManager.inMemory(current.cwd)
|
|
415
|
-
: SessionManager.create(sessionDirForCwd(sessionDir, current.cwd), current.cwd, id !== undefined ? { id } : {});
|
|
414
|
+
? SessionManager.inMemory(record.current.cwd)
|
|
415
|
+
: SessionManager.create(sessionDirForCwd(sessionDir, record.current.cwd), record.current.cwd, id !== undefined ? { id } : {});
|
|
416
416
|
let manager;
|
|
417
417
|
if (request.kind === "new")
|
|
418
418
|
manager = fresh();
|
package/dist/cli/deps.d.ts
CHANGED
|
@@ -107,7 +107,7 @@ export interface SessionAssembly {
|
|
|
107
107
|
/**
|
|
108
108
|
* 模式层把当前会话换成另一个(`/new`、`/resume`、`/fork`、RPC `switch_session`)后调用:
|
|
109
109
|
* bootstrap 让 HostApi.session.*、宿主 sendUser、Hook 公共字段与退出时的 dispose 跟随 `next`。
|
|
110
|
-
* 旧会话由调用方自行 dispose;`Runtime.session`
|
|
110
|
+
* 旧会话由调用方自行 dispose;`Runtime.session` / `sessionManager` 也随之指向 `next`(#165)。
|
|
111
111
|
*/
|
|
112
112
|
onSessionReplaced(next: AgentSession): void;
|
|
113
113
|
/** SessionStart Hook 的 additionalContext(系统提示 hooks 节);首次装配系统提示时读取。 */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 模型元数据的一行描述(`ama models list`、`ama config show`、`ama providers`):上下文、输出、思考、
|
|
3
|
-
* 图片、渠道,以及每个字段来自哪里(config / 目录 /
|
|
3
|
+
* 图片、渠道,以及每个字段来自哪里(config / 目录 / 按 id 继承的目录 / models.dev / 缺省)、继承的
|
|
4
|
+
* 目录条目与 models.dev 匹配。
|
|
4
5
|
*/
|
|
5
6
|
import { type ModelMetadata } from "../../ai/providers/enrich.js";
|
|
6
7
|
import type { Model, ProviderRegistryApi } from "../../ai/types.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 模型元数据的一行描述(`ama models list`、`ama config show`、`ama providers`):上下文、输出、思考、
|
|
3
|
-
* 图片、渠道,以及每个字段来自哪里(config / 目录 /
|
|
3
|
+
* 图片、渠道,以及每个字段来自哪里(config / 目录 / 按 id 继承的目录 / models.dev / 缺省)、继承的
|
|
4
|
+
* 目录条目与 models.dev 匹配。
|
|
4
5
|
*/
|
|
5
6
|
import { sourceText } from "../../ai/providers/enrich.js";
|
|
6
7
|
import { matchLabel } from "../../ai/providers/models-dev.js";
|
|
@@ -52,5 +53,5 @@ export function sourcesLine(metadata) {
|
|
|
52
53
|
};
|
|
53
54
|
const parts = Object.keys(label).map((field) => `${label[field]} ${sourceText(metadata.sources[field])}`);
|
|
54
55
|
const match = metadata.looked ? matchLabel(metadata.match) : undefined;
|
|
55
|
-
return t.sources(parts, match, metadata.toolCall === false);
|
|
56
|
+
return t.sources(parts, match, metadata.toolCall === false, metadata.catalog);
|
|
56
57
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* codemode 父进程侧:起子进程、转发工具调用、超时杀树(设计 §5.5 沙箱第 1–4 条)。[B10]
|
|
3
3
|
*
|
|
4
|
-
* - 命令行:`<node> --permission --allow-fs-read=<入口>
|
|
5
|
-
* <入口> --ama-codemode-sandbox
|
|
4
|
+
* - 命令行:`<node> --max-old-space-size=<MB> --permission --allow-fs-read=<入口>
|
|
5
|
+
* --disallow-code-generation-from-strings <入口> --ama-codemode-sandbox`;堆上限取 `codemode.maxHeapMb`
|
|
6
|
+
* (缺省 256,0 不加),超出时子进程 OOM 退出,映射为脚本错误(docs/memory-plan.md D10);Node 22.0–22.12 用 `--experimental-permission`。不授予文件写、
|
|
6
7
|
* 子进程、worker、addon、inspector 权限;以空环境启动(拿不到密钥与会话路径);嵌入 Electron
|
|
7
8
|
* 时设 `ELECTRON_RUN_AS_NODE=1` 运行同一可执行文件。
|
|
8
9
|
* - 入口:bundle 里是 ama.cjs 同目录的 `ama-sandbox.cjs`(构建脚本定义 `__AMA_SANDBOX_ENTRY__`);
|
|
@@ -25,10 +26,12 @@ import { type ScriptOptions, type StoreSnapshot, type ToolDecl } from "./protoco
|
|
|
25
26
|
export declare const MAX_COLLECTED_OUTPUT_CHARS: number;
|
|
26
27
|
/** 外层 abort 后等子进程自行结束的宽限。 */
|
|
27
28
|
export declare const ABORT_GRACE_MS = 500;
|
|
29
|
+
/** 子进程 V8 老生代堆上限(MB)缺省值;`codemode.maxHeapMb` 覆盖,0 不设上限。 */
|
|
30
|
+
export declare const DEFAULT_CODEMODE_HEAP_MB = 256;
|
|
28
31
|
/** 子进程入口的绝对路径(realpath);找不到 → undefined。 */
|
|
29
32
|
export declare function resolveSandboxEntry(moduleUrl?: string): string | undefined;
|
|
30
|
-
/** 子进程参数(不含可执行文件)。 */
|
|
31
|
-
export declare function sandboxArgs(entry: string, capability?: Pick<SandboxCapability, "permissionFlag"
|
|
33
|
+
/** 子进程参数(不含可执行文件)。V8 选项必须在 `--permission` 与脚本之前。 */
|
|
34
|
+
export declare function sandboxArgs(entry: string, capability?: Pick<SandboxCapability, "permissionFlag">, heapMb?: number): string[];
|
|
32
35
|
/** codemode 子进程的 OS 沙箱策略:拒绝网络,任何位置都不可写。 */
|
|
33
36
|
export declare const CODEMODE_OS_POLICY: OsSandboxPolicy;
|
|
34
37
|
/** 完整命令行:`<node> <sandboxArgs>`,有 OS 沙箱时再经它包装。 */
|
|
@@ -53,7 +56,11 @@ export interface SandboxRunRequest {
|
|
|
53
56
|
os?: Pick<OsSandboxStatus, "kind" | "path">;
|
|
54
57
|
/** true:必须经 OS 沙箱启动(Node 22 / 24 的 strict 依赖它),包装不了直接失败。 */
|
|
55
58
|
requireOsSandbox?: boolean;
|
|
59
|
+
/** 子进程堆上限(MB),缺省 DEFAULT_CODEMODE_HEAP_MB;0 不设上限。 */
|
|
60
|
+
maxHeapMb?: number;
|
|
56
61
|
}
|
|
62
|
+
/** 子进程因堆上限 OOM 退出时给模型的文案(固定英文)。 */
|
|
63
|
+
export declare function heapLimitError(heapMb: number): string;
|
|
57
64
|
export interface SandboxRunResult {
|
|
58
65
|
ok: boolean;
|
|
59
66
|
error?: string;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* codemode 父进程侧:起子进程、转发工具调用、超时杀树(设计 §5.5 沙箱第 1–4 条)。[B10]
|
|
3
3
|
*
|
|
4
|
-
* - 命令行:`<node> --permission --allow-fs-read=<入口>
|
|
5
|
-
* <入口> --ama-codemode-sandbox
|
|
4
|
+
* - 命令行:`<node> --max-old-space-size=<MB> --permission --allow-fs-read=<入口>
|
|
5
|
+
* --disallow-code-generation-from-strings <入口> --ama-codemode-sandbox`;堆上限取 `codemode.maxHeapMb`
|
|
6
|
+
* (缺省 256,0 不加),超出时子进程 OOM 退出,映射为脚本错误(docs/memory-plan.md D10);Node 22.0–22.12 用 `--experimental-permission`。不授予文件写、
|
|
6
7
|
* 子进程、worker、addon、inspector 权限;以空环境启动(拿不到密钥与会话路径);嵌入 Electron
|
|
7
8
|
* 时设 `ELECTRON_RUN_AS_NODE=1` 运行同一可执行文件。
|
|
8
9
|
* - 入口:bundle 里是 ama.cjs 同目录的 `ama-sandbox.cjs`(构建脚本定义 `__AMA_SANDBOX_ENTRY__`);
|
|
@@ -29,6 +30,8 @@ import { LineSplitter, SANDBOX_MAIN_FLAG, decodeChildLine, encodeLine, } from ".
|
|
|
29
30
|
export const MAX_COLLECTED_OUTPUT_CHARS = 16 * 1024 * 1024;
|
|
30
31
|
/** 外层 abort 后等子进程自行结束的宽限。 */
|
|
31
32
|
export const ABORT_GRACE_MS = 500;
|
|
33
|
+
/** 子进程 V8 老生代堆上限(MB)缺省值;`codemode.maxHeapMb` 覆盖,0 不设上限。 */
|
|
34
|
+
export const DEFAULT_CODEMODE_HEAP_MB = 256;
|
|
32
35
|
/** 子进程入口的绝对路径(realpath);找不到 → undefined。 */
|
|
33
36
|
export function resolveSandboxEntry(moduleUrl = import.meta.url) {
|
|
34
37
|
const here = dirname(fileURLToPath(moduleUrl));
|
|
@@ -44,9 +47,11 @@ export function resolveSandboxEntry(moduleUrl = import.meta.url) {
|
|
|
44
47
|
}
|
|
45
48
|
return undefined;
|
|
46
49
|
}
|
|
47
|
-
/** 子进程参数(不含可执行文件)。 */
|
|
48
|
-
export function sandboxArgs(entry, capability = detectSandboxCapability()) {
|
|
50
|
+
/** 子进程参数(不含可执行文件)。V8 选项必须在 `--permission` 与脚本之前。 */
|
|
51
|
+
export function sandboxArgs(entry, capability = detectSandboxCapability(), heapMb = DEFAULT_CODEMODE_HEAP_MB) {
|
|
52
|
+
const heap = Math.floor(heapMb);
|
|
49
53
|
return [
|
|
54
|
+
...(heap > 0 ? [`--max-old-space-size=${heap}`] : []),
|
|
50
55
|
capability.permissionFlag,
|
|
51
56
|
`--allow-fs-read=${entry}`,
|
|
52
57
|
"--disallow-code-generation-from-strings",
|
|
@@ -75,9 +80,14 @@ export function sandboxEnv(versions = process.versions, platform = process.platf
|
|
|
75
80
|
}
|
|
76
81
|
return env;
|
|
77
82
|
}
|
|
83
|
+
/** 子进程因堆上限 OOM 退出时给模型的文案(固定英文)。 */
|
|
84
|
+
export function heapLimitError(heapMb) {
|
|
85
|
+
return `Script exceeded the codemode memory limit (${heapMb} MB); process the data in smaller pieces`;
|
|
86
|
+
}
|
|
78
87
|
export async function runSandbox(request) {
|
|
79
88
|
const started = Date.now();
|
|
80
89
|
const entry = request.entry ?? resolveSandboxEntry();
|
|
90
|
+
const heapMb = Math.floor(request.maxHeapMb ?? DEFAULT_CODEMODE_HEAP_MB);
|
|
81
91
|
const base = {
|
|
82
92
|
outputs: [],
|
|
83
93
|
timedOut: false,
|
|
@@ -96,7 +106,7 @@ export async function runSandbox(request) {
|
|
|
96
106
|
if (request.signal.aborted) {
|
|
97
107
|
return { ...base, ok: false, error: "Script aborted", aborted: true, elapsedMs: 0 };
|
|
98
108
|
}
|
|
99
|
-
const command = sandboxCommand(request.nodePath ?? process.execPath, sandboxArgs(entry, request.capability), request.os ?? osSandboxStatus());
|
|
109
|
+
const command = sandboxCommand(request.nodePath ?? process.execPath, sandboxArgs(entry, request.capability, heapMb), request.os ?? osSandboxStatus());
|
|
100
110
|
if (request.requireOsSandbox === true && !command.networkDenied) {
|
|
101
111
|
return {
|
|
102
112
|
...base,
|
|
@@ -121,6 +131,7 @@ export async function runSandbox(request) {
|
|
|
121
131
|
result.pid = pid;
|
|
122
132
|
let collected = 0;
|
|
123
133
|
let stderr = "";
|
|
134
|
+
let outOfMemory = false;
|
|
124
135
|
let settled = false;
|
|
125
136
|
let finish;
|
|
126
137
|
const finished = new Promise((resolve) => (finish = resolve));
|
|
@@ -166,7 +177,11 @@ export async function runSandbox(request) {
|
|
|
166
177
|
child.stdin.on("error", () => { });
|
|
167
178
|
child.stderr.setEncoding("utf8");
|
|
168
179
|
child.stderr.on("data", (chunk) => {
|
|
169
|
-
stderr =
|
|
180
|
+
stderr = stderr + chunk;
|
|
181
|
+
// 原生栈可能把 OOM 那行挤出 4000 字符的尾部:在截断前判定
|
|
182
|
+
if (heapMb > 0 && /heap out of memory/i.test(stderr))
|
|
183
|
+
outOfMemory = true;
|
|
184
|
+
stderr = stderr.slice(-4000);
|
|
170
185
|
});
|
|
171
186
|
const splitter = new LineSplitter();
|
|
172
187
|
const onLine = (line) => {
|
|
@@ -247,6 +262,10 @@ export async function runSandbox(request) {
|
|
|
247
262
|
onLine(line);
|
|
248
263
|
if (pid !== undefined && !isWindows)
|
|
249
264
|
untrackProcessGroup(pid);
|
|
265
|
+
if (outOfMemory) {
|
|
266
|
+
settle({ ok: false, error: heapLimitError(heapMb) });
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
250
269
|
const detail = stderr.trim().split("\n").slice(-3).join(" | ");
|
|
251
270
|
settle({
|
|
252
271
|
ok: false,
|
package/dist/codemode/tool.d.ts
CHANGED
package/dist/codemode/tool.js
CHANGED
|
@@ -222,6 +222,7 @@ export function createCodemodeTool(options) {
|
|
|
222
222
|
requireOsSandbox: strictNeedsOsSandbox(capability),
|
|
223
223
|
...(options.entry !== undefined ? { entry: options.entry } : {}),
|
|
224
224
|
...(options.nodePath !== undefined ? { nodePath: options.nodePath } : {}),
|
|
225
|
+
...(options.maxHeapMb !== undefined ? { maxHeapMb: options.maxHeapMb } : {}),
|
|
225
226
|
callTool: async (name, args, signal) => {
|
|
226
227
|
if (!callable.has(name))
|
|
227
228
|
throw new Error(`Tool ${name} is not available in codemode`);
|
|
@@ -316,6 +317,9 @@ export function codemodeToolFactory(overrides = {}) {
|
|
|
316
317
|
const budget = ctx.config.codemode?.inlineBudget;
|
|
317
318
|
if (budget !== undefined)
|
|
318
319
|
options.inlineBudget = budget;
|
|
320
|
+
const heapMb = ctx.config.codemode?.maxHeapMb;
|
|
321
|
+
if (heapMb !== undefined)
|
|
322
|
+
options.maxHeapMb = heapMb;
|
|
319
323
|
const maxChars = ctx.config.tools?.maxToolResultChars;
|
|
320
324
|
if (maxChars !== undefined)
|
|
321
325
|
options.maxResultChars = maxChars;
|
|
@@ -11,7 +11,7 @@ import { PERMISSION_MODES_STRICT_FIRST } from "../permissions/types.js";
|
|
|
11
11
|
import { msg } from "../i18n/index.js";
|
|
12
12
|
import { defaultFor, isDynamicDefault, keyDoc } from "./key-docs.js";
|
|
13
13
|
import { HOOK_TIMEOUT_MAX_MS, THINKING_LEVELS } from "./schema.js";
|
|
14
|
-
import { CACHE_RETENTIONS, CHANNEL_NAME_PATTERN, CHECKPOINT_MODES, SANDBOX_ENABLED_MODES, SANDBOX_NETWORK_MODES, CODEMODE_MODES, IMAGE_RESIZE_MODES, PLAN_BASH_MODES_STRICT_FIRST, PLAN_UNATTENDED_MODES, STATUS_LINE_MODES, TOOLS_PRESET_INPUTS, LANGUAGE_SETTINGS, AGENT_BAR_MODES, CHATGPT_FLAVORS, MEMORY_SCOPES, MEMORY_SUBAGENT_MODES, } from "./types.js";
|
|
14
|
+
import { CACHE_RETENTIONS, CHANNEL_NAME_PATTERN, CHECKPOINT_MODES, SANDBOX_ENABLED_MODES, SANDBOX_NETWORK_MODES, CODEMODE_MODES, IMAGE_RESIZE_MODES, PLAN_BASH_MODES_STRICT_FIRST, PLAN_UNATTENDED_MODES, STATUS_LINE_MODES, TOOLS_PRESET_INPUTS, LANGUAGE_SETTINGS, AGENT_BAR_MODES, CHATGPT_FLAVORS, MEMORY_SCOPES, MEMORY_SUBAGENT_MODES, MIN_CONTEXT_BUDGET, } from "./types.js";
|
|
15
15
|
import { AGENT_ID_PATTERN } from "./schema-w5.js";
|
|
16
16
|
import { AGENTS_RESERVED_KEYS, SUBAGENT_BACKGROUND_MODES } from "./types-w5.js";
|
|
17
17
|
export const CONFIG_SCHEMA_FILE = "config.schema.json";
|
|
@@ -89,6 +89,10 @@ function providerSchema() {
|
|
|
89
89
|
description: m.modelsDev,
|
|
90
90
|
anyOf: [{ type: "string", pattern: "^[^/]+/.+$" }, { const: false }],
|
|
91
91
|
},
|
|
92
|
+
catalog: {
|
|
93
|
+
description: m.modelCatalog,
|
|
94
|
+
anyOf: [{ type: "string", pattern: "^[^/]+/.+$" }, { const: false }],
|
|
95
|
+
},
|
|
92
96
|
headers: stringRecord,
|
|
93
97
|
compat,
|
|
94
98
|
promptCache: object({ short: num(), long: num(), minTokens: num() }),
|
|
@@ -156,6 +160,7 @@ function w5Sections() {
|
|
|
156
160
|
defaultModel: str(),
|
|
157
161
|
background: oneOf(SUBAGENT_BACKGROUND_MODES),
|
|
158
162
|
autoBackgroundAfterMs: num(0),
|
|
163
|
+
retainSessions: num(0),
|
|
159
164
|
}),
|
|
160
165
|
models: object({ aliases: object({ fast: str(), strong: str() }), enabled: strings }),
|
|
161
166
|
fallbackModel: str(),
|
|
@@ -244,6 +249,7 @@ function buildBaseSchema() {
|
|
|
244
249
|
enabled: bool(),
|
|
245
250
|
reserveTokens: num(0),
|
|
246
251
|
keepRecentTokens: num(0),
|
|
252
|
+
contextBudget: num(MIN_CONTEXT_BUDGET),
|
|
247
253
|
prune: object({
|
|
248
254
|
keepResults: num(0),
|
|
249
255
|
clearAtLeast: { anyOf: [{ const: "auto" }, { type: "number", minimum: 0 }] },
|
|
@@ -267,6 +273,7 @@ function buildBaseSchema() {
|
|
|
267
273
|
mode: oneOf(CODEMODE_MODES),
|
|
268
274
|
inlineBudget: num(0),
|
|
269
275
|
requireStrict: bool(),
|
|
276
|
+
maxHeapMb: num(0),
|
|
270
277
|
}),
|
|
271
278
|
hooks: object({ timeoutMs: num(1, HOOK_TIMEOUT_MAX_MS) }),
|
|
272
279
|
ui: object({
|
|
@@ -295,7 +302,7 @@ function buildBaseSchema() {
|
|
|
295
302
|
missNotices: bool(),
|
|
296
303
|
warmSubagents: bool(),
|
|
297
304
|
}),
|
|
298
|
-
request: object({ idleTimeoutMs: num(0) }),
|
|
305
|
+
request: object({ idleTimeoutMs: num(0), streamIdleTimeoutMs: num(0) }),
|
|
299
306
|
checkpoints: object({
|
|
300
307
|
mode: oneOf(CHECKPOINT_MODES),
|
|
301
308
|
maxFileBytes: num(0),
|
package/dist/config/key-docs.js
CHANGED
|
@@ -14,15 +14,18 @@ import { DEFAULT_CODEX_CLIENT_VERSION } from "../auth/chatgpt/presets.js";
|
|
|
14
14
|
import { messagesFor, msg } from "../i18n/index.js";
|
|
15
15
|
import { DEFAULT_INLINE_BUDGET } from "../codemode/declarations.js";
|
|
16
16
|
import { DEFAULT_CONFIG, mergeConfig } from "./merge.js";
|
|
17
|
-
import { DEFAULT_CACHE_CONFIG, DEFAULT_CHECKPOINTS_CONFIG } from "./types.js";
|
|
17
|
+
import { DEFAULT_CACHE_CONFIG, DEFAULT_CHECKPOINTS_CONFIG, DEFAULT_STREAM_IDLE_TIMEOUT_MS, } from "./types.js";
|
|
18
18
|
/** 代码里生效、但 DEFAULT_CONFIG 不写的缺省(写进去会改变合并结果或 `config.codemode` 的有无)。 */
|
|
19
19
|
const IMPLICIT_DEFAULTS = {
|
|
20
20
|
providers: {},
|
|
21
21
|
permission: { builtinDeny: true, autoSafeCommands: [] },
|
|
22
22
|
tools: { default: [] },
|
|
23
|
-
codemode: { inlineBudget: DEFAULT_INLINE_BUDGET, requireStrict: false },
|
|
23
|
+
codemode: { inlineBudget: DEFAULT_INLINE_BUDGET, requireStrict: false, maxHeapMb: 256 },
|
|
24
24
|
cache: { ...DEFAULT_CACHE_CONFIG },
|
|
25
|
-
request: {
|
|
25
|
+
request: {
|
|
26
|
+
idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
|
|
27
|
+
streamIdleTimeoutMs: DEFAULT_STREAM_IDLE_TIMEOUT_MS,
|
|
28
|
+
},
|
|
26
29
|
ui: {
|
|
27
30
|
compact: false,
|
|
28
31
|
logo: "auto",
|
|
@@ -56,7 +59,13 @@ const IMPLICIT_DEFAULTS = {
|
|
|
56
59
|
images: { resize: "auto" },
|
|
57
60
|
plan: { bash: "readonly", unattended: "stop" },
|
|
58
61
|
agents: { maxConcurrent: 3, dirs: [] },
|
|
59
|
-
subagents: {
|
|
62
|
+
subagents: {
|
|
63
|
+
maxConcurrent: 4,
|
|
64
|
+
maxPending: 16,
|
|
65
|
+
background: "auto",
|
|
66
|
+
autoBackgroundAfterMs: 0,
|
|
67
|
+
retainSessions: 4,
|
|
68
|
+
},
|
|
60
69
|
reminders: { todo: true, fileChanges: true, contextPressure: true, budget: true },
|
|
61
70
|
todo: { reminder: 10 },
|
|
62
71
|
};
|
package/dist/config/schema-w5.js
CHANGED
|
@@ -83,12 +83,20 @@ export function validateConfigW5(c, config) {
|
|
|
83
83
|
c.oneOf(s, "thinkingLevel", p, THINKING_LEVELS);
|
|
84
84
|
});
|
|
85
85
|
checkAgents(c, config);
|
|
86
|
-
checkSection(c, config, "subagents", [
|
|
86
|
+
checkSection(c, config, "subagents", [
|
|
87
|
+
"maxConcurrent",
|
|
88
|
+
"maxPending",
|
|
89
|
+
"defaultModel",
|
|
90
|
+
"background",
|
|
91
|
+
"autoBackgroundAfterMs",
|
|
92
|
+
"retainSessions",
|
|
93
|
+
], (s, p) => {
|
|
87
94
|
c.number(s, "maxConcurrent", p, 1, 64);
|
|
88
95
|
c.number(s, "maxPending", p, 0, 1024);
|
|
89
96
|
c.string(s, "defaultModel", p);
|
|
90
97
|
c.oneOf(s, "background", p, SUBAGENT_BACKGROUND_MODES);
|
|
91
98
|
c.number(s, "autoBackgroundAfterMs", p, 0);
|
|
99
|
+
c.number(s, "retainSessions", p, 0);
|
|
92
100
|
});
|
|
93
101
|
checkSection(c, config, "models", ["aliases", "enabled"], (s, p) => {
|
|
94
102
|
c.stringArray(s, "enabled", p);
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 校验结果是诊断列表:`severity: "error"` 拒绝该文件(启动退出码 3),`"warning"` 只提示
|
|
6
6
|
* (未知字段等)。`path` 是 JSON 指针风格的字段路径(`permission.mode`、`hooks.PreToolUse[0]`)。
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
8
|
+
import { type AmaConfig, type AuthFile, type ProfileFile, type TrustFile } from "./types.js";
|
|
9
9
|
import { type Diagnostic } from "./checker.js";
|
|
10
10
|
import type { HookConfig } from "../hooks/types.js";
|
|
11
11
|
export type { AmaConfig, AuthFile, ProfileFile, TrustFile, TrustEntry, ProviderConfig, PermissionConfig, CompactionConfig, RetryConfig, ToolsConfig, ToolsPreset, ToolsPresetInput, CodemodeConfig, CodemodeMode, HooksSettings, UiConfig, SkillsConfig, CacheConfig, CheckpointsConfig, ModelConfig, ModelOverride, ChannelConfig, } from "./types.js";
|
package/dist/config/schema.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { isAbsolute } from "node:path";
|
|
9
9
|
import { msg } from "../i18n/index.js";
|
|
10
|
+
import { MIN_CONTEXT_BUDGET, } from "./types.js";
|
|
10
11
|
import { Checker, THINKING_LEVELS, checkSection, join, } from "./checker.js";
|
|
11
12
|
import { W5_COMPACTION_KEYS, W5_CONFIG_KEYS, W5_UI_KEYS, checkCompactionW5, checkUiW5, validateConfigW5, } from "./schema-w5.js";
|
|
12
13
|
import { W6_CONFIG_KEYS, W6_UI_KEYS, checkOAuthEntry, checkProfileMemory, checkUiW6, validateConfigW6, } from "./schema-w6.js";
|
|
@@ -93,6 +94,12 @@ function checkModels(c, value, path, channels) {
|
|
|
93
94
|
(typeof modelsDev !== "string" || !/^[^/]+\/.+$/.test(modelsDev))) {
|
|
94
95
|
c.error(join(p, "modelsDev"), msg().config.schema.modelsDev);
|
|
95
96
|
}
|
|
97
|
+
const catalog = item["catalog"];
|
|
98
|
+
if (catalog !== undefined &&
|
|
99
|
+
catalog !== false &&
|
|
100
|
+
(typeof catalog !== "string" || !/^[^/]+\/.+$/.test(catalog))) {
|
|
101
|
+
c.error(join(p, "catalog"), msg().config.schema.catalog);
|
|
102
|
+
}
|
|
96
103
|
c.stringArray(item, "channels", p);
|
|
97
104
|
const used = item["channels"];
|
|
98
105
|
if (Array.isArray(used)) {
|
|
@@ -221,11 +228,18 @@ export function validateConfig(value) {
|
|
|
221
228
|
c.error(join(p, "builtinDeny"), msg().config.schema.builtinDeny);
|
|
222
229
|
}
|
|
223
230
|
});
|
|
224
|
-
const compactionKeys = [
|
|
231
|
+
const compactionKeys = [
|
|
232
|
+
"enabled",
|
|
233
|
+
"reserveTokens",
|
|
234
|
+
"keepRecentTokens",
|
|
235
|
+
"contextBudget",
|
|
236
|
+
...W5_COMPACTION_KEYS,
|
|
237
|
+
];
|
|
225
238
|
checkSection(c, value, "compaction", compactionKeys, (s, p) => {
|
|
226
239
|
c.boolean(s, "enabled", p);
|
|
227
240
|
c.number(s, "reserveTokens", p);
|
|
228
241
|
c.number(s, "keepRecentTokens", p);
|
|
242
|
+
c.number(s, "contextBudget", p, MIN_CONTEXT_BUDGET);
|
|
229
243
|
checkCompactionW5(c, s, p);
|
|
230
244
|
});
|
|
231
245
|
checkSection(c, value, "retry", ["enabled", "maxRetries", "baseDelayMs", "maxDelayMs"], (s, p) => {
|
|
@@ -241,10 +255,11 @@ export function validateConfig(value) {
|
|
|
241
255
|
c.number(s, "bashTimeoutMs", p, 1);
|
|
242
256
|
c.stringArray(s, "disabled", p);
|
|
243
257
|
});
|
|
244
|
-
checkSection(c, value, "codemode", ["mode", "inlineBudget", "requireStrict"], (s, p) => {
|
|
258
|
+
checkSection(c, value, "codemode", ["mode", "inlineBudget", "requireStrict", "maxHeapMb"], (s, p) => {
|
|
245
259
|
c.oneOf(s, "mode", p, CODEMODE_MODES);
|
|
246
260
|
c.number(s, "inlineBudget", p, 0);
|
|
247
261
|
c.boolean(s, "requireStrict", p);
|
|
262
|
+
c.number(s, "maxHeapMb", p, 0);
|
|
248
263
|
});
|
|
249
264
|
checkSection(c, value, "hooks", ["timeoutMs"], (s, p) => {
|
|
250
265
|
c.number(s, "timeoutMs", p, 1, HOOK_TIMEOUT_MAX_MS);
|
|
@@ -281,8 +296,9 @@ export function validateConfig(value) {
|
|
|
281
296
|
checkUiW6(c, s, p);
|
|
282
297
|
});
|
|
283
298
|
checkSection(c, value, "skills", ["dirs"], (s, p) => c.stringArray(s, "dirs", p));
|
|
284
|
-
checkSection(c, value, "request", ["idleTimeoutMs"], (s, p) => {
|
|
299
|
+
checkSection(c, value, "request", ["idleTimeoutMs", "streamIdleTimeoutMs"], (s, p) => {
|
|
285
300
|
c.number(s, "idleTimeoutMs", p, 0);
|
|
301
|
+
c.number(s, "streamIdleTimeoutMs", p, 0);
|
|
286
302
|
});
|
|
287
303
|
checkSection(c, value, "checkpoints", ["mode", "maxFileBytes", "keep"], (s, p) => {
|
|
288
304
|
c.oneOf(s, "mode", p, CHECKPOINT_MODES);
|
|
@@ -57,6 +57,7 @@ const ROWS = [
|
|
|
57
57
|
row("codemode.mode", "tools", "restart", "tighten", { prefix: true }),
|
|
58
58
|
row("codemode.inlineBudget", "tools", "restart", "deny", { prefix: true }),
|
|
59
59
|
row("codemode.requireStrict", "tools", "restart", "deny"),
|
|
60
|
+
row("codemode.maxHeapMb", "tools", "restart", "deny"),
|
|
60
61
|
row("tools.maxToolResultChars", "tools", "nextSession", "deny"),
|
|
61
62
|
row("tools.bashTimeoutMs", "tools", "restart", "deny"),
|
|
62
63
|
row("images.resize", "tools", "restart", "deny"),
|
|
@@ -64,6 +65,7 @@ const ROWS = [
|
|
|
64
65
|
row("compaction.enabled", "context", "now", "any"),
|
|
65
66
|
row("compaction.reserveTokens", "context", "nextSession", "any"),
|
|
66
67
|
row("compaction.keepRecentTokens", "context", "nextSession", "any"),
|
|
68
|
+
row("compaction.contextBudget", "context", "nextSession", "any", { kind: "optionalNumber" }),
|
|
67
69
|
row("compaction.prune.keepResults", "context", "nextSession", "deny"),
|
|
68
70
|
row("compaction.prune.clearAtLeast", "context", "nextSession", "deny"),
|
|
69
71
|
row("cache.warming", "context", "now", "deny", { envOverride: "AMA_CACHE_WARMING" }),
|
|
@@ -74,6 +76,9 @@ const ROWS = [
|
|
|
74
76
|
row("request.idleTimeoutMs", "context", "nextSession", "deny", {
|
|
75
77
|
envOverride: "AMA_IDLE_TIMEOUT_MS",
|
|
76
78
|
}),
|
|
79
|
+
row("request.streamIdleTimeoutMs", "context", "nextSession", "deny", {
|
|
80
|
+
envOverride: "AMA_STREAM_IDLE_TIMEOUT_MS",
|
|
81
|
+
}),
|
|
77
82
|
row("retry.enabled", "context", "now", "deny"),
|
|
78
83
|
row("retry.maxRetries", "context", "nextSession", "deny"),
|
|
79
84
|
row("retry.baseDelayMs", "context", "nextSession", "deny"),
|
|
@@ -95,6 +100,7 @@ const ROWS = [
|
|
|
95
100
|
row("agents.sessionBudgetUsd", "agents", "nextSession", "deny", { kind: "optionalNumber" }),
|
|
96
101
|
row("subagents.maxConcurrent", "agents", "nextSession", "deny"),
|
|
97
102
|
row("subagents.maxPending", "agents", "nextSession", "deny"),
|
|
103
|
+
row("subagents.retainSessions", "agents", "nextSession", "deny"),
|
|
98
104
|
// [W7-B2] 改 task 工具描述(缺省后台 / 前台两种文案),故 prefix
|
|
99
105
|
row("subagents.background", "agents", "restart", "any", { prefix: true }),
|
|
100
106
|
row("subagents.autoBackgroundAfterMs", "agents", "restart", "any"),
|
|
@@ -77,6 +77,8 @@ export interface SubagentsConfig {
|
|
|
77
77
|
background?: SubagentBackgroundMode;
|
|
78
78
|
/** [W7-B2] 前台任务运行超过该毫秒数自动转后台;缺省 0 关闭。用户 / 项目级都认。 */
|
|
79
79
|
autoBackgroundAfterMs?: number;
|
|
80
|
+
/** [M-F] 已结束子会话保留在内存的句柄数(LRU),缺省 4;超出的续聊时从会话文件重开。只认用户级。 */
|
|
81
|
+
retainSessions?: number;
|
|
80
82
|
}
|
|
81
83
|
/** `models.enabled` 的一项:`provider/model[@channel]` 或 `provider/*`。 */
|
|
82
84
|
export declare const MODELS_ENABLED_REF: RegExp;
|
package/dist/config/types.d.ts
CHANGED
|
@@ -31,6 +31,11 @@ export type ModelConfig = Partial<Omit<Model, "id" | "provider" | "channel" | "c
|
|
|
31
31
|
channels?: string[];
|
|
32
32
|
/** models.dev 条目 `provider/model`(显式匹配);false 关闭 models.dev 补全。 */
|
|
33
33
|
modelsDev?: string | false;
|
|
34
|
+
/**
|
|
35
|
+
* [ME-C0] 从内置目录继承模型固有属性:缺省按 id 别名自动匹配;`"provider/id"` 显式指定;false 关闭
|
|
36
|
+
* (docs/model-efficiency-plan.md D10,实现归 ME-D)。
|
|
37
|
+
*/
|
|
38
|
+
catalog?: string | false;
|
|
34
39
|
};
|
|
35
40
|
/** 只改元数据的覆盖项(含模型级 `api` 与 `channels`)。 */
|
|
36
41
|
export type ModelOverride = ModelConfig;
|
|
@@ -83,6 +88,8 @@ export interface CompactionConfig {
|
|
|
83
88
|
enabled?: boolean;
|
|
84
89
|
reserveTokens?: number;
|
|
85
90
|
keepRecentTokens?: number;
|
|
91
|
+
/** [ME-C0] 软窗口(≥ 32768):档一 / 档二 / context_pressure 的窗口取 min(模型窗口, 它);缺省 = 模型窗口。 */
|
|
92
|
+
contextBudget?: number;
|
|
86
93
|
/** [W5-C0] 档一裁剪参数(W5-H1);只认用户级。 */
|
|
87
94
|
prune?: PruneConfig;
|
|
88
95
|
/** [W5-C0] 不被档一裁剪的工具名(W5-H1);只认用户级。 */
|
|
@@ -129,6 +136,8 @@ export interface CodemodeConfig {
|
|
|
129
136
|
inlineBudget?: number;
|
|
130
137
|
/** true:运行时 Node 的权限模型不隔离网络(Node 22 / 24)时直接禁用 codemode。 */
|
|
131
138
|
requireStrict?: boolean;
|
|
139
|
+
/** [M-F] 脚本子进程的 V8 堆上限(MB,`--max-old-space-size`),缺省 256,0 不加;只认用户级。 */
|
|
140
|
+
maxHeapMb?: number;
|
|
132
141
|
}
|
|
133
142
|
export interface HooksSettings {
|
|
134
143
|
timeoutMs?: number;
|
|
@@ -183,9 +192,18 @@ export declare const DEFAULT_CACHE_CONFIG: Readonly<Required<CacheConfig>>;
|
|
|
183
192
|
* 模型请求(W4-C)。只认用户级 / profile;环境变量 `AMA_IDLE_TIMEOUT_MS` 覆盖 `idleTimeoutMs`。
|
|
184
193
|
*/
|
|
185
194
|
export interface RequestConfig {
|
|
186
|
-
/**
|
|
195
|
+
/** 等响应头的最长时间(毫秒);缺省 300 000,0 关闭。流中的间隔见 `streamIdleTimeoutMs`。 */
|
|
187
196
|
idleTimeoutMs?: number;
|
|
197
|
+
/**
|
|
198
|
+
* [ME-C0] 流中两块数据之间的最长间隔(毫秒);缺省 180 000,0 关闭;环境变量
|
|
199
|
+
* `AMA_STREAM_IDLE_TIMEOUT_MS` 覆盖(cli/compose-request.ts)。
|
|
200
|
+
*/
|
|
201
|
+
streamIdleTimeoutMs?: number;
|
|
188
202
|
}
|
|
203
|
+
/** [ME-C0] `compaction.contextBudget` 的下限。 */
|
|
204
|
+
export declare const MIN_CONTEXT_BUDGET = 32768;
|
|
205
|
+
/** [ME-C0] `request.streamIdleTimeoutMs` 的缺省(毫秒)。 */
|
|
206
|
+
export declare const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 180000;
|
|
189
207
|
export declare const CHECKPOINT_MODES: readonly CheckpointMode[];
|
|
190
208
|
/**
|
|
191
209
|
* 检查点(docs/rewind-plan.md §5)。环境变量 `AMA_CHECKPOINTS` 覆盖 `mode`;项目级只接受
|