@armadra/agent 0.6.1 → 0.6.3
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 +80 -0
- package/CHANGELOG.zh-CN.md +56 -0
- package/README.md +168 -575
- package/README.zh-CN.md +165 -596
- package/dist/agent/session-settings.d.ts +4 -1
- package/dist/agent/session-settings.js +7 -2
- package/dist/agent/session.d.ts +6 -0
- package/dist/agent/session.js +8 -0
- package/dist/agent/subagent-background.d.ts +75 -0
- package/dist/agent/subagent-background.js +209 -0
- package/dist/agent/subagent-registry.d.ts +24 -5
- package/dist/agent/subagent-registry.js +64 -92
- package/dist/agent/types-w5.d.ts +11 -1
- package/dist/agent/types.d.ts +5 -0
- package/dist/agents/builtin.js +0 -1
- package/dist/agents/external.js +0 -1
- package/dist/agents/parse.js +4 -3
- package/dist/agents/result.d.ts +7 -1
- package/dist/agents/result.js +20 -1
- package/dist/agents/task-control.d.ts +13 -2
- package/dist/agents/task-record.d.ts +13 -1
- package/dist/agents/task-record.js +32 -0
- package/dist/agents/types.d.ts +5 -1
- package/dist/ai/apis/chatgpt-backend.d.ts +7 -2
- package/dist/ai/apis/chatgpt-backend.js +12 -4
- package/dist/ai/providers/discovered-cache.d.ts +29 -12
- package/dist/ai/providers/discovered-cache.js +72 -12
- package/dist/ai/providers/registry.js +7 -6
- package/dist/ai/types.d.ts +5 -0
- package/dist/auth/chatgpt/backend-client.d.ts +14 -4
- package/dist/auth/chatgpt/backend-client.js +41 -8
- package/dist/auth/chatgpt/cli.d.ts +2 -1
- package/dist/auth/chatgpt/cli.js +14 -7
- package/dist/auth/chatgpt/follow.d.ts +16 -0
- package/dist/auth/chatgpt/follow.js +51 -0
- package/dist/auth/chatgpt/presets.d.ts +8 -0
- package/dist/auth/chatgpt/presets.js +12 -0
- package/dist/auth/testing/fake-oauth.d.ts +4 -1
- package/dist/auth/testing/fake-oauth.js +24 -1
- package/dist/bundle/ama.cjs +2016 -664
- package/dist/cli/compose-agents.d.ts +2 -1
- package/dist/cli/compose-agents.js +11 -2
- package/dist/cli/compose-providers.d.ts +2 -1
- package/dist/cli/compose-providers.js +6 -3
- package/dist/cli/startup-steps.js +4 -1
- package/dist/cli/subcommands/models-discover.d.ts +5 -2
- package/dist/cli/subcommands/models-discover.js +52 -10
- package/dist/config/json-schema.js +10 -2
- package/dist/config/key-docs.js +9 -3
- package/dist/config/merge.d.ts +1 -1
- package/dist/config/merge.js +20 -3
- package/dist/config/schema-w5.js +4 -2
- package/dist/config/schema-w6.d.ts +1 -1
- package/dist/config/schema-w6.js +2 -1
- package/dist/config/schema.js +2 -0
- package/dist/config/settings-registry.js +4 -0
- package/dist/config/types-w5.d.ts +10 -0
- package/dist/config/types-w5.js +2 -0
- package/dist/config/types-w6.d.ts +5 -0
- package/dist/config/types.d.ts +3 -1
- package/dist/git/info.d.ts +19 -0
- package/dist/git/info.js +64 -8
- package/dist/i18n/catalog.d.ts +52 -8
- package/dist/i18n/messages/agents.d.ts +56 -0
- package/dist/i18n/messages/agents.js +58 -2
- package/dist/i18n/messages/auth.d.ts +12 -0
- package/dist/i18n/messages/auth.js +20 -0
- package/dist/i18n/messages/config-keys.d.ts +8 -0
- package/dist/i18n/messages/config-keys.js +18 -10
- package/dist/i18n/messages/config.d.ts +8 -0
- package/dist/i18n/messages/interactive-startup.d.ts +0 -16
- package/dist/i18n/messages/interactive-startup.js +0 -16
- package/dist/i18n/messages/interactive.d.ts +23 -16
- package/dist/i18n/messages/interactive.js +25 -0
- package/dist/i18n/messages/print.d.ts +4 -0
- package/dist/i18n/messages/print.js +4 -0
- package/dist/i18n/messages/report.js +4 -4
- package/dist/i18n/messages/settings.d.ts +6 -0
- package/dist/i18n/messages/settings.js +6 -0
- package/dist/i18n/messages/subcommands-config.d.ts +4 -0
- package/dist/i18n/messages/subcommands-config.js +4 -0
- package/dist/i18n/messages/subcommands.d.ts +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/modes/commands-core.js +8 -4
- package/dist/modes/interactive/agent-bar.d.ts +3 -1
- package/dist/modes/interactive/agent-bar.js +12 -5
- package/dist/modes/interactive/agent-ui.d.ts +21 -3
- package/dist/modes/interactive/agent-ui.js +81 -12
- package/dist/modes/interactive/agent-view.d.ts +4 -0
- package/dist/modes/interactive/agent-view.js +14 -1
- package/dist/modes/interactive/approval-dock.d.ts +51 -0
- package/dist/modes/interactive/approval-dock.js +112 -0
- package/dist/modes/interactive/approval-ui.d.ts +43 -0
- package/dist/modes/interactive/approval-ui.js +64 -0
- package/dist/modes/interactive/commands.js +4 -1
- package/dist/modes/interactive/event-notices.d.ts +6 -1
- package/dist/modes/interactive/event-notices.js +7 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -2
- package/dist/modes/interactive/interactive-mode.js +33 -38
- package/dist/modes/interactive/key-dispatch.d.ts +21 -4
- package/dist/modes/interactive/key-dispatch.js +60 -8
- package/dist/modes/interactive/line/line-mode.js +5 -0
- package/dist/modes/interactive/run-indicator.d.ts +15 -0
- package/dist/modes/interactive/run-indicator.js +37 -5
- package/dist/modes/interactive/session-events.js +5 -1
- package/dist/modes/interactive/startup-header.d.ts +29 -14
- package/dist/modes/interactive/startup-header.js +93 -59
- package/dist/modes/interactive/startup-logo.d.ts +83 -0
- package/dist/modes/interactive/startup-logo.js +183 -0
- package/dist/modes/interactive/status-area.d.ts +18 -0
- package/dist/modes/interactive/status-area.js +67 -1
- package/dist/modes/interactive/status-bar.d.ts +9 -1
- package/dist/modes/interactive/status-bar.js +43 -11
- package/dist/modes/interactive/status-line.d.ts +2 -0
- package/dist/modes/interactive/status-line.js +11 -6
- package/dist/modes/interactive/status-quota.d.ts +44 -0
- package/dist/modes/interactive/status-quota.js +135 -0
- package/dist/modes/interactive/subagent-view.d.ts +1 -0
- package/dist/modes/interactive/subagent-view.js +8 -0
- package/dist/modes/interactive/task-background.d.ts +31 -0
- package/dist/modes/interactive/task-background.js +68 -0
- package/dist/modes/interactive/tool-view.d.ts +7 -1
- package/dist/modes/interactive/tool-view.js +24 -1
- package/dist/modes/print/print-mode.d.ts +11 -0
- package/dist/modes/print/print-mode.js +36 -1
- package/dist/modes/rpc/commands.d.ts +2 -1
- package/dist/modes/rpc/commands.js +9 -1
- package/dist/rpc.d.ts +13 -0
- package/dist/rpc.js +3 -0
- package/dist/tools/task-ctl.d.ts +2 -0
- package/dist/tools/task-ctl.js +7 -2
- package/dist/tools/task.d.ts +11 -0
- package/dist/tools/task.js +20 -2
- package/dist/tui/components/editor.d.ts +2 -0
- package/dist/tui/components/editor.js +4 -0
- package/dist/tui/components/loader.d.ts +5 -1
- package/dist/tui/components/loader.js +18 -5
- package/dist/tui/keybindings.d.ts +8 -3
- package/dist/tui/keybindings.js +8 -3
- package/docs/agents.md +52 -28
- package/docs/en/host-api.md +5 -1
- package/docs/en/providers.md +8 -4
- package/docs/en/rpc.md +19 -7
- package/docs/en/sessions.md +3 -1
- package/docs/en/tui.md +84 -66
- package/docs/host-api.md +5 -1
- package/docs/providers.md +29 -12
- package/docs/rpc.md +19 -7
- package/docs/sessions.md +2 -1
- package/docs/tui-design.md +42 -29
- package/docs/tui.md +67 -49
- package/package.json +1 -1
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
* - [W5-H2] plan 模式产出计划、`plan.unattended: stop`(缺省)没人审批:stderr 一行(计划文件与审批办法)、
|
|
22
22
|
* json 带 `planPending{planId, version, filePath}`、退出码 9。
|
|
23
23
|
* - [W5-H2] `--image` / `@图片` 超限时按 config `images.resize` 缩放(缺省 auto)。
|
|
24
|
+
* - [W7-B2] 后台子 Agent(显式 `background:true` 或 `subagents.background: always`):主回合结束后若还有任务
|
|
25
|
+
* 在跑或通知待投递,stderr 一行提示并等它们结束、跑完通知回合再输出(最终文本 = 最后一条助手回复);
|
|
26
|
+
* 受 `--max-turns` / `--max-cost` / `limits.*` 约束(到限即停止等待,退出码 8),SIGINT / SIGTERM 照常中止
|
|
27
|
+
* (未结束的任务随会话关闭被停止);json 结果带 `tasks`(同 `getStats().tasks`)。
|
|
24
28
|
* - 退出码:最终助手消息 `error / aborted` 或提示被拒 → 1;有工具调用被拒 → 7;到达预算 → 8;
|
|
25
29
|
* 计划待审批 → 9;SIGINT 130、SIGTERM 143(先 abort)。
|
|
26
30
|
*/
|
|
@@ -29,6 +33,7 @@ import { ExitCode } from "../../cli/exit-codes.js";
|
|
|
29
33
|
import { errorText, lastAssistant, onStdoutClosed, onTerminationSignals } from "../shared.js";
|
|
30
34
|
import { toJsonLine, toWireEvent } from "./json-event.js";
|
|
31
35
|
import { formatUsd } from "../../agent/limits.js";
|
|
36
|
+
import { registryOf } from "../../agent/subagent-registry.js";
|
|
32
37
|
import { promptImages, sessionModel } from "../image-input.js";
|
|
33
38
|
import { msg } from "../../i18n/index.js";
|
|
34
39
|
export function joinPrompt(argument, piped) {
|
|
@@ -118,9 +123,15 @@ export async function runPrintMode(runtime, context) {
|
|
|
118
123
|
const denied = [];
|
|
119
124
|
let limit;
|
|
120
125
|
let plan;
|
|
126
|
+
let stopWaiting = () => undefined;
|
|
127
|
+
const stopped = new Promise((resolve) => {
|
|
128
|
+
stopWaiting = resolve;
|
|
129
|
+
});
|
|
121
130
|
const unsubscribe = session.subscribe((event) => {
|
|
122
|
-
if (event.type === "limit_reached")
|
|
131
|
+
if (event.type === "limit_reached") {
|
|
123
132
|
limit ??= event;
|
|
133
|
+
stopWaiting();
|
|
134
|
+
}
|
|
124
135
|
else if (event.type === "plan_proposed")
|
|
125
136
|
plan = event;
|
|
126
137
|
else if (event.type === "plan_resolved" && event.planId === plan?.planId)
|
|
@@ -139,16 +150,25 @@ export async function runPrintMode(runtime, context) {
|
|
|
139
150
|
let signalled;
|
|
140
151
|
const offSignals = onTerminationSignals((code) => {
|
|
141
152
|
signalled ??= code;
|
|
153
|
+
stopWaiting();
|
|
142
154
|
void session.abort();
|
|
143
155
|
});
|
|
144
156
|
let stdoutClosed = false;
|
|
145
157
|
const offEpipe = onStdoutClosed(() => {
|
|
146
158
|
stdoutClosed = true;
|
|
159
|
+
stopWaiting();
|
|
147
160
|
void session.abort();
|
|
148
161
|
});
|
|
149
162
|
let failure;
|
|
150
163
|
try {
|
|
151
164
|
await session.prompt(prompt, images.length > 0 ? { images } : {});
|
|
165
|
+
const ended = lastAssistant(session)?.stopReason;
|
|
166
|
+
if (signalled === undefined &&
|
|
167
|
+
!stdoutClosed &&
|
|
168
|
+
limit === undefined &&
|
|
169
|
+
ended !== "error" &&
|
|
170
|
+
ended !== "aborted")
|
|
171
|
+
await waitBackgroundTasks(session, stopped, io);
|
|
152
172
|
}
|
|
153
173
|
catch (error) {
|
|
154
174
|
failure = errorText(error);
|
|
@@ -183,6 +203,7 @@ export async function runPrintMode(runtime, context) {
|
|
|
183
203
|
cost: stats.cost,
|
|
184
204
|
cacheHitRate: stats.cacheHitRate,
|
|
185
205
|
...(stats.cache !== undefined ? { cache: stats.cache } : {}),
|
|
206
|
+
...(stats.tasks !== undefined ? { tasks: stats.tasks } : {}),
|
|
186
207
|
...(denied.length > 0 ? { deniedTools: denied } : {}),
|
|
187
208
|
...(plan !== undefined
|
|
188
209
|
? {
|
|
@@ -230,6 +251,20 @@ export async function runPrintMode(runtime, context) {
|
|
|
230
251
|
return ExitCode.ToolDenied;
|
|
231
252
|
return ExitCode.Ok;
|
|
232
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* [W7-B2] 主回合结束后等后台任务与它们的通知回合(docs/agents-concurrency-plan.md §2.6、§6 Q5)。
|
|
256
|
+
* `settled()`(subagent-background.ts)等到没有运行中任务且通知投递链(含通知回合)结束;`stopped`:SIGINT /
|
|
257
|
+
* SIGTERM、stdout 关闭或预算到限时 resolve,立即停止等待。没有子 Agent 注册表时直接返回。
|
|
258
|
+
*/
|
|
259
|
+
export async function waitBackgroundTasks(session, stopped, io) {
|
|
260
|
+
const registry = registryOf(session.state.sessionId);
|
|
261
|
+
if (registry === undefined)
|
|
262
|
+
return;
|
|
263
|
+
const running = registry.list().filter((task) => task.status === "running").length;
|
|
264
|
+
if (running > 0)
|
|
265
|
+
io.stderr(msg().print.print.waitingTasks(running));
|
|
266
|
+
await Promise.race([registry.settled(), stopped]);
|
|
267
|
+
}
|
|
233
268
|
/** stderr 一行:计划已落盘待审批(-p 不替人批准)。 */
|
|
234
269
|
export function describePlanPending(plan) {
|
|
235
270
|
const where = plan.filePath ?? plan.planId;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RPC 命令分派表(设计 §13.2、src/rpc.ts
|
|
2
|
+
* RPC 命令分派表(设计 §13.2、src/rpc.ts 的命令表,现 44 条)。[B6]
|
|
3
3
|
*
|
|
4
4
|
* - 提示类(prompt / steer / follow_up)不等运行结束:会话开始运行(`before_agent_start` /
|
|
5
5
|
* `agent_start`)、入队或被处理后立刻应答 `{ disposition }`;运行中的进展走事件。
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* - [W5-F] 计划:声明 `plans` 能力后计划审批交客户端(`plan_proposed` → `plan_response`),未声明按
|
|
12
12
|
* `plan.unattended`;`approve_fresh` 在这里新建会话并以计划全文开新回合。`get_tasks / get_agents`
|
|
13
13
|
* 读 `RpcContext.tasks / agents`(W5-G 的注册表与发现结果;未装配时回空表)。
|
|
14
|
+
* - [W7-B2] `background_task { taskId? }` → `{ backgrounded }`(`session.backgroundTask`,B1)。
|
|
14
15
|
*/
|
|
15
16
|
import type { AgentInfo } from "../../agents/types.js";
|
|
16
17
|
import type { TaskRegistryView } from "../../tools/types.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RPC 命令分派表(设计 §13.2、src/rpc.ts
|
|
2
|
+
* RPC 命令分派表(设计 §13.2、src/rpc.ts 的命令表,现 44 条)。[B6]
|
|
3
3
|
*
|
|
4
4
|
* - 提示类(prompt / steer / follow_up)不等运行结束:会话开始运行(`before_agent_start` /
|
|
5
5
|
* `agent_start`)、入队或被处理后立刻应答 `{ disposition }`;运行中的进展走事件。
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* - [W5-F] 计划:声明 `plans` 能力后计划审批交客户端(`plan_proposed` → `plan_response`),未声明按
|
|
12
12
|
* `plan.unattended`;`approve_fresh` 在这里新建会话并以计划全文开新回合。`get_tasks / get_agents`
|
|
13
13
|
* 读 `RpcContext.tasks / agents`(W5-G 的注册表与发现结果;未装配时回空表)。
|
|
14
|
+
* - [W7-B2] `background_task { taskId? }` → `{ backgrounded }`(`session.backgroundTask`,B1)。
|
|
14
15
|
*/
|
|
15
16
|
import { formatModelRef } from "../../ai/providers/channels.js";
|
|
16
17
|
import { AgentSessionImpl } from "../../agent/session.js";
|
|
@@ -312,5 +313,12 @@ export const handlers = {
|
|
|
312
313
|
get_agents: async (_p, ctx) => ({ agents: [...(ctx.agents?.() ?? [])] }),
|
|
313
314
|
// [W6-T2] 轨迹(docs/wave6-plan.md §2.6;分页 / 增量 / 脱敏见 trace/query.ts)
|
|
314
315
|
get_trace: async (p, ctx) => sessionTrace(ctx.session(), p ?? {}),
|
|
316
|
+
// [W7-B2] 前台任务转后台:工具调用立即返回、任务继续,完成后照常通知
|
|
317
|
+
background_task: async (p, ctx) => {
|
|
318
|
+
const taskId = p?.taskId;
|
|
319
|
+
if (taskId !== undefined && typeof taskId !== "string")
|
|
320
|
+
throw new AmaError("invalid_arguments", msg().print.rpc.badTaskId);
|
|
321
|
+
return { backgrounded: ctx.session().backgroundTask(taskId) };
|
|
322
|
+
},
|
|
315
323
|
};
|
|
316
324
|
export const RPC_COMMAND_TYPES = Object.keys(handlers);
|
package/dist/rpc.d.ts
CHANGED
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
* - [W6-C0] 第六波(docs/wave6-plan.md §2.6、§4.4):命令 `get_trace`(参数 `RpcGetTraceParams`、返回
|
|
20
20
|
* `RpcW6Results`,W6-T2 实现,之前回 `not_implemented`);事件 `quota_update`;`permission_request.context`
|
|
21
21
|
* 可带 `toolCallId`;`keySource` 可为 `oauth`。`RPC_PROTOCOL_VERSION` 不变。
|
|
22
|
+
* - [W7-B2] 后台子 Agent(docs/agents-concurrency-plan.md §2.5):命令 `background_task { taskId? }` →
|
|
23
|
+
* `RpcW7Results`(无 taskId = 全部前台运行中任务;对已结束 / 已在后台的任务回空表);事件
|
|
24
|
+
* `subagent_background` 由 `SessionEvent` 派生。`RPC_PROTOCOL_VERSION` 不变。
|
|
22
25
|
*/
|
|
23
26
|
import type { AssistantEvent, ImageBlock, ModelThinkingLevel, Usage } from "./ai/types.js";
|
|
24
27
|
import type { PlanData, PlanDecisionKind, QueueMode, SessionEvent, TodoItemView } from "./agent/types.js";
|
|
@@ -139,6 +142,16 @@ export interface RpcCommandMap {
|
|
|
139
142
|
get_tasks: NoParams;
|
|
140
143
|
get_agents: NoParams;
|
|
141
144
|
get_trace: RpcGetTraceParams;
|
|
145
|
+
background_task: {
|
|
146
|
+
taskId?: string;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** [W7-B2] 第七波命令成功时的 `data` 形状。 */
|
|
150
|
+
export interface RpcW7Results {
|
|
151
|
+
/** 实际转了后台的 taskId(含被打断的 `task_ctl wait`);没有可转的为空表。 */
|
|
152
|
+
background_task: {
|
|
153
|
+
backgrounded: string[];
|
|
154
|
+
};
|
|
142
155
|
}
|
|
143
156
|
/** [W6-C0] `get_trace` 的参数。 */
|
|
144
157
|
export interface RpcGetTraceParams {
|
package/dist/rpc.js
CHANGED
|
@@ -19,5 +19,8 @@
|
|
|
19
19
|
* - [W6-C0] 第六波(docs/wave6-plan.md §2.6、§4.4):命令 `get_trace`(参数 `RpcGetTraceParams`、返回
|
|
20
20
|
* `RpcW6Results`,W6-T2 实现,之前回 `not_implemented`);事件 `quota_update`;`permission_request.context`
|
|
21
21
|
* 可带 `toolCallId`;`keySource` 可为 `oauth`。`RPC_PROTOCOL_VERSION` 不变。
|
|
22
|
+
* - [W7-B2] 后台子 Agent(docs/agents-concurrency-plan.md §2.5):命令 `background_task { taskId? }` →
|
|
23
|
+
* `RpcW7Results`(无 taskId = 全部前台运行中任务;对已结束 / 已在后台的任务回空表);事件
|
|
24
|
+
* `subagent_background` 由 `SessionEvent` 派生。`RPC_PROTOCOL_VERSION` 不变。
|
|
22
25
|
*/
|
|
23
26
|
export const RPC_PROTOCOL_VERSION = 1;
|
package/dist/tools/task-ctl.d.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* 与父一致,运行时拒绝;
|
|
8
8
|
* - `wait` / `output` 是轮询类调用(`annotations.pollable`,重复调用检测豁免);
|
|
9
9
|
* - `send` = 续聊放后台:等价于 `task{taskId, prompt, background:true}`,完成后同样收到通知。
|
|
10
|
+
* - [W7-B1] `wait` 被转后台(`background()`,TUI `Ctrl+B` / RPC `background_task`)打断时立即返回固定
|
|
11
|
+
* 文案,要求模型不要再等。
|
|
10
12
|
*/
|
|
11
13
|
import type { ToolDefinition } from "./types.js";
|
|
12
14
|
export declare const TASK_CTL_TOOL = "task_ctl";
|
package/dist/tools/task-ctl.js
CHANGED
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
* 与父一致,运行时拒绝;
|
|
8
8
|
* - `wait` / `output` 是轮询类调用(`annotations.pollable`,重复调用检测豁免);
|
|
9
9
|
* - `send` = 续聊放后台:等价于 `task{taskId, prompt, background:true}`,完成后同样收到通知。
|
|
10
|
+
* - [W7-B1] `wait` 被转后台(`background()`,TUI `Ctrl+B` / RPC `background_task`)打断时立即返回固定
|
|
11
|
+
* 文案,要求模型不要再等。
|
|
10
12
|
*/
|
|
11
|
-
import { capTaskText, formatTokens } from "../agents/result.js";
|
|
13
|
+
import { capTaskText, formatTokens, waitDetachedText } from "../agents/result.js";
|
|
12
14
|
import { taskControl } from "../agents/task-control.js";
|
|
13
15
|
export const TASK_CTL_TOOL = "task_ctl";
|
|
14
16
|
export const DEFAULT_WAIT_MS = 30_000;
|
|
@@ -96,7 +98,10 @@ export function createTaskCtlTool() {
|
|
|
96
98
|
}
|
|
97
99
|
case "wait": {
|
|
98
100
|
const timeout = Math.min(Math.max(input.timeoutMs ?? DEFAULT_WAIT_MS, 0), MAX_WAIT_MS);
|
|
99
|
-
const
|
|
101
|
+
const signal = control.detachSignal(taskId);
|
|
102
|
+
const result = await control.wait(taskId, timeout, { signal });
|
|
103
|
+
if (result === undefined && signal.aborted)
|
|
104
|
+
return { content: waitDetachedText(taskId) };
|
|
100
105
|
if (result === undefined) {
|
|
101
106
|
const turns = control.get(taskId)?.turns ?? 0;
|
|
102
107
|
return {
|
package/dist/tools/task.d.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* - `agent`:子 Agent 类型(内置 general / explore / plan、`.ama/agents/*.md`)或外部 Agent;缺省
|
|
6
6
|
* general。描述里列出可用类型(catalog 由 compose-agents.ts 经 `bindTaskAgents` 绑定;没绑定时
|
|
7
7
|
* 只列内置类型)。
|
|
8
|
+
* - [W7-B1] 缺省前台 / 后台由 `subagents.background` 决定(交互 / RPC / ACP 后台,`-p` 前台),描述随之
|
|
9
|
+
* 二选一(`bindTaskBackground`);前台任务可被 `background()` 转后台,工具立即以固定文案返回。
|
|
8
10
|
* - `background`:立即返回 taskId,完成后父会话收到 `<task-notification>`;`taskId`:向已有子会话
|
|
9
11
|
* 追加消息(续聊,忽略 agent / tools / model);`isolation: "worktree"`:在独立 git worktree 里跑。
|
|
10
12
|
* - **parallel**:同一回复里的多个 task 真并行(会话注册表的池限流,缺省 4);与 sequential 工具
|
|
@@ -33,9 +35,18 @@ export interface TaskInput {
|
|
|
33
35
|
/** 预留(并发上限在会话的任务注册表,见 agent/subagent-registry.ts)。 */
|
|
34
36
|
export interface TaskToolOptions {
|
|
35
37
|
}
|
|
38
|
+
/** 缺省前台(`-p`、`subagents.background: never`)时的描述。 */
|
|
39
|
+
export declare const FOREGROUND_DESCRIPTION: string;
|
|
40
|
+
/** [W7-B1] 缺省后台(交互 / RPC / ACP,docs/agents-concurrency-plan.md §2.6)时的描述。 */
|
|
41
|
+
export declare const BACKGROUND_DESCRIPTION: string;
|
|
36
42
|
/** 描述里类型清单的标题(清单本身另有 400 token 预算,见 agents/catalog.ts)。 */
|
|
37
43
|
export declare const TASK_AGENTS_HEADING = "\nAgents:\n";
|
|
38
44
|
/** 组装根把会话的类型目录绑到 task 工具上(描述里的类型清单)。 */
|
|
39
45
|
export declare function bindTaskAgents(tool: ToolDefinition | undefined, catalog: AgentCatalog): void;
|
|
46
|
+
/**
|
|
47
|
+
* [W7-B1] 组装根把本进程的缺省前台 / 后台(`subagents.background` 按运行模式解析后)绑到 task 工具:
|
|
48
|
+
* 决定描述用哪一版。会话内不变(缓存前缀稳定);没绑定按缺省前台。
|
|
49
|
+
*/
|
|
50
|
+
export declare function bindTaskBackground(tool: ToolDefinition | undefined, background: boolean): void;
|
|
40
51
|
export declare function buildSubagentRequest(input: TaskInput, ctx: ToolContext): SubagentRequest | string;
|
|
41
52
|
export declare function createTaskTool(_options?: TaskToolOptions): ToolDefinition<TaskInput>;
|
package/dist/tools/task.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* - `agent`:子 Agent 类型(内置 general / explore / plan、`.ama/agents/*.md`)或外部 Agent;缺省
|
|
6
6
|
* general。描述里列出可用类型(catalog 由 compose-agents.ts 经 `bindTaskAgents` 绑定;没绑定时
|
|
7
7
|
* 只列内置类型)。
|
|
8
|
+
* - [W7-B1] 缺省前台 / 后台由 `subagents.background` 决定(交互 / RPC / ACP 后台,`-p` 前台),描述随之
|
|
9
|
+
* 二选一(`bindTaskBackground`);前台任务可被 `background()` 转后台,工具立即以固定文案返回。
|
|
8
10
|
* - `background`:立即返回 taskId,完成后父会话收到 `<task-notification>`;`taskId`:向已有子会话
|
|
9
11
|
* 追加消息(续聊,忽略 agent / tools / model);`isolation: "worktree"`:在独立 git worktree 里跑。
|
|
10
12
|
* - **parallel**:同一回复里的多个 task 真并行(会话注册表的池限流,缺省 4);与 sequential 工具
|
|
@@ -24,17 +26,32 @@ const THINKING = [
|
|
|
24
26
|
"high",
|
|
25
27
|
"xhigh",
|
|
26
28
|
];
|
|
27
|
-
|
|
29
|
+
/** 缺省前台(`-p`、`subagents.background: never`)时的描述。 */
|
|
30
|
+
export const FOREGROUND_DESCRIPTION = "Delegate to a sub-agent (fresh context; give full instructions). Returns its final report. " +
|
|
28
31
|
"Tasks in one reply run in parallel; writers should use isolation worktree. background: " +
|
|
29
32
|
"returns a taskId now (see task_ctl); taskId: continue that task.";
|
|
33
|
+
/** [W7-B1] 缺省后台(交互 / RPC / ACP,docs/agents-concurrency-plan.md §2.6)时的描述。 */
|
|
34
|
+
export const BACKGROUND_DESCRIPTION = "Delegate to a sub-agent (fresh context; give full instructions). Runs in the background by " +
|
|
35
|
+
"default: returns a taskId; a <task-notification> follows when done, so keep working. " +
|
|
36
|
+
"background:false if your next step needs the result. taskId: continue a task. Tasks in one " +
|
|
37
|
+
"reply run in parallel; writers use isolation worktree.";
|
|
30
38
|
/** 描述里类型清单的标题(清单本身另有 400 token 预算,见 agents/catalog.ts)。 */
|
|
31
39
|
export const TASK_AGENTS_HEADING = "\nAgents:\n";
|
|
32
40
|
const catalogs = new WeakMap();
|
|
41
|
+
const backgrounds = new WeakMap();
|
|
33
42
|
/** 组装根把会话的类型目录绑到 task 工具上(描述里的类型清单)。 */
|
|
34
43
|
export function bindTaskAgents(tool, catalog) {
|
|
35
44
|
if (tool !== undefined)
|
|
36
45
|
catalogs.set(tool, catalog);
|
|
37
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* [W7-B1] 组装根把本进程的缺省前台 / 后台(`subagents.background` 按运行模式解析后)绑到 task 工具:
|
|
49
|
+
* 决定描述用哪一版。会话内不变(缓存前缀稳定);没绑定按缺省前台。
|
|
50
|
+
*/
|
|
51
|
+
export function bindTaskBackground(tool, background) {
|
|
52
|
+
if (tool !== undefined)
|
|
53
|
+
backgrounds.set(tool, background);
|
|
54
|
+
}
|
|
38
55
|
function fail(message) {
|
|
39
56
|
return { content: message, isError: true };
|
|
40
57
|
}
|
|
@@ -87,7 +104,8 @@ export function createTaskTool(_options = {}) {
|
|
|
87
104
|
label: "Task",
|
|
88
105
|
get description() {
|
|
89
106
|
const catalog = catalogs.get(tool) ?? new AgentCatalog();
|
|
90
|
-
|
|
107
|
+
const base = backgrounds.get(tool) === true ? BACKGROUND_DESCRIPTION : FOREGROUND_DESCRIPTION;
|
|
108
|
+
return `${base}${TASK_AGENTS_HEADING}${catalog.describe()}`;
|
|
91
109
|
},
|
|
92
110
|
parameters: {
|
|
93
111
|
type: "object",
|
|
@@ -88,6 +88,8 @@ export declare class Editor implements Component, Focusable {
|
|
|
88
88
|
col: number;
|
|
89
89
|
};
|
|
90
90
|
get isCompletionOpen(): boolean;
|
|
91
|
+
/** 正在用 ↑↓ 浏览输入历史(编辑后即退出)。 */
|
|
92
|
+
get isBrowsingHistory(): boolean;
|
|
91
93
|
getHistory(): readonly string[];
|
|
92
94
|
setHistory(entries: readonly string[]): void;
|
|
93
95
|
addToHistory(text: string): void;
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* 运行指示(设计 §12.1、§12.6;终端界面视觉设计 v1 §3.7)。[B4]
|
|
3
3
|
*
|
|
4
4
|
* 一行 `⠋ 动词 · 已用时 · 附加项…`:spinner `accent`、动词正文色、其余 `dim`,以 ` · ` 连接。
|
|
5
|
-
* - `setVerb(verb, extras, { elapsed })` 换动词(思考中 / 回复中 / 运行 bash / 等待确认……);
|
|
5
|
+
* - `setVerb(verb, extras, { elapsed, optional })` 换动词(思考中 / 回复中 / 运行 bash / 等待确认……);
|
|
6
|
+
* `optional` 是排在附加项之后的可丢弃项(按键提示),整行放不下时从后往前丢,而不是被截断;
|
|
6
7
|
* `setMessage(text)` 是只换动词的旧接口。
|
|
7
8
|
* - 帧取 `theme.glyphs.spinner`(Unicode 10 帧 80 ms、ASCII 4 帧 250 ms);`frame` 暴露当前帧字形,
|
|
8
9
|
* `onFrame` 让别的组件(运行中的工具摘要行)与 Loader 同帧换字,保证一帧只多改一行。
|
|
@@ -27,6 +28,8 @@ export interface LoaderOptions {
|
|
|
27
28
|
export interface LoaderVerbOptions {
|
|
28
29
|
/** 本动词是否显示已用时(缺省跟随 `showElapsed`)。 */
|
|
29
30
|
elapsed?: boolean;
|
|
31
|
+
/** 可丢弃的附加项:宽度不够时从后往前整项丢掉(缺省没有)。 */
|
|
32
|
+
optional?: readonly string[];
|
|
30
33
|
}
|
|
31
34
|
export declare function formatElapsed(ms: number): string;
|
|
32
35
|
export declare class Loader implements Component {
|
|
@@ -37,6 +40,7 @@ export declare class Loader implements Component {
|
|
|
37
40
|
private startedAt;
|
|
38
41
|
private verb;
|
|
39
42
|
private extras;
|
|
43
|
+
private optional;
|
|
40
44
|
private verbElapsed;
|
|
41
45
|
private lastElapsed;
|
|
42
46
|
private readonly listeners;
|
|
@@ -2,17 +2,21 @@
|
|
|
2
2
|
* 运行指示(设计 §12.1、§12.6;终端界面视觉设计 v1 §3.7)。[B4]
|
|
3
3
|
*
|
|
4
4
|
* 一行 `⠋ 动词 · 已用时 · 附加项…`:spinner `accent`、动词正文色、其余 `dim`,以 ` · ` 连接。
|
|
5
|
-
* - `setVerb(verb, extras, { elapsed })` 换动词(思考中 / 回复中 / 运行 bash / 等待确认……);
|
|
5
|
+
* - `setVerb(verb, extras, { elapsed, optional })` 换动词(思考中 / 回复中 / 运行 bash / 等待确认……);
|
|
6
|
+
* `optional` 是排在附加项之后的可丢弃项(按键提示),整行放不下时从后往前丢,而不是被截断;
|
|
6
7
|
* `setMessage(text)` 是只换动词的旧接口。
|
|
7
8
|
* - 帧取 `theme.glyphs.spinner`(Unicode 10 帧 80 ms、ASCII 4 帧 250 ms);`frame` 暴露当前帧字形,
|
|
8
9
|
* `onFrame` 让别的组件(运行中的工具摘要行)与 Loader 同帧换字,保证一帧只多改一行。
|
|
9
10
|
* - `animation: false`:spinner 固定为 `glyphs.spinnerStatic`,定时器每秒一次,已用时变了才请求重绘。
|
|
10
11
|
* - `stop()` 后不再触发渲染。时钟可注入便于测试。
|
|
11
12
|
*/
|
|
12
|
-
import { truncateToWidth } from "../ansi.js";
|
|
13
|
+
import { truncateToWidth, visibleWidth } from "../ansi.js";
|
|
13
14
|
import { UNICODE_GLYPHS } from "../glyphs.js";
|
|
14
15
|
/** Unicode 帧表(兼容旧导出;实际帧取 `theme.glyphs.spinner`)。 */
|
|
15
16
|
export const LOADER_FRAMES = UNICODE_GLYPHS.spinner;
|
|
17
|
+
function sameList(a, b) {
|
|
18
|
+
return a.length === b.length && a.every((e, i) => e === b[i]);
|
|
19
|
+
}
|
|
16
20
|
export function formatElapsed(ms) {
|
|
17
21
|
const total = Math.max(0, Math.floor(ms / 1000));
|
|
18
22
|
if (total < 60)
|
|
@@ -29,6 +33,7 @@ export class Loader {
|
|
|
29
33
|
startedAt;
|
|
30
34
|
verb;
|
|
31
35
|
extras = [];
|
|
36
|
+
optional = [];
|
|
32
37
|
verbElapsed;
|
|
33
38
|
lastElapsed = "";
|
|
34
39
|
listeners = new Set();
|
|
@@ -65,12 +70,13 @@ export class Loader {
|
|
|
65
70
|
setVerb(verb, extras = [], options = {}) {
|
|
66
71
|
const same = verb === this.verb &&
|
|
67
72
|
options.elapsed === this.verbElapsed &&
|
|
68
|
-
extras
|
|
69
|
-
|
|
73
|
+
sameList(extras, this.extras) &&
|
|
74
|
+
sameList(options.optional ?? [], this.optional);
|
|
70
75
|
if (same)
|
|
71
76
|
return;
|
|
72
77
|
this.verb = verb;
|
|
73
78
|
this.extras = [...extras];
|
|
79
|
+
this.optional = [...(options.optional ?? [])];
|
|
74
80
|
this.verbElapsed = options.elapsed;
|
|
75
81
|
this.requestRender();
|
|
76
82
|
}
|
|
@@ -142,7 +148,14 @@ export class Loader {
|
|
|
142
148
|
for (const extra of this.extras)
|
|
143
149
|
parts.push(dim(extra));
|
|
144
150
|
const spinner = theme ? theme.fg("accent", this.frame) : this.frame;
|
|
145
|
-
|
|
151
|
+
const line = (items) => `${spinner} ${items.join(dim(" · "))}`;
|
|
152
|
+
for (const extra of this.optional) {
|
|
153
|
+
const next = [...parts, dim(extra)];
|
|
154
|
+
if (visibleWidth(line(next)) > width)
|
|
155
|
+
break;
|
|
156
|
+
parts.push(dim(extra));
|
|
157
|
+
}
|
|
158
|
+
return [truncateToWidth(line(parts), width)];
|
|
146
159
|
}
|
|
147
160
|
invalidate() { }
|
|
148
161
|
}
|
|
@@ -45,10 +45,15 @@ export declare const DEFAULT_KEYBINDINGS: {
|
|
|
45
45
|
/** [W5-U] 粘贴剪贴板图片(写进数据目录,输入框插入 `@路径`)。 */
|
|
46
46
|
readonly "app.paste.image": readonly ["ctrl+v"];
|
|
47
47
|
/**
|
|
48
|
-
* [W6-A] 进入 Agent
|
|
49
|
-
*
|
|
48
|
+
* [W6-A / W7-A] 进入 Agent 栏:输入为空、补全未开、有子 Agent 任务即可(不要求栏可见);有字时 `↓` 仍是
|
|
49
|
+
* 下移 / 历史,并给一次提示。`Ctrl+B` 不再进栏(tmux 缺省前缀会吃掉它),留给 `app.tasks.background`。
|
|
50
50
|
*/
|
|
51
|
-
readonly "app.agents.focus": readonly ["
|
|
51
|
+
readonly "app.agents.focus": readonly ["down"];
|
|
52
|
+
/**
|
|
53
|
+
* [W7-C] 有阻塞中的前台子 Agent 任务(或 `task_ctl wait`)时全部转后台,不看输入框;没有时落回编辑器
|
|
54
|
+
* (`tui.editor.cursorLeft` 的 `ctrl+b`)。tmux 里按 `C-b C-b` 透传。
|
|
55
|
+
*/
|
|
56
|
+
readonly "app.tasks.background": readonly ["ctrl+b"];
|
|
52
57
|
};
|
|
53
58
|
export type ActionId = keyof typeof DEFAULT_KEYBINDINGS;
|
|
54
59
|
export type KeybindingOverrides = Partial<Record<ActionId, readonly string[]>>;
|
package/dist/tui/keybindings.js
CHANGED
|
@@ -48,10 +48,15 @@ export const DEFAULT_KEYBINDINGS = {
|
|
|
48
48
|
/** [W5-U] 粘贴剪贴板图片(写进数据目录,输入框插入 `@路径`)。 */
|
|
49
49
|
"app.paste.image": ["ctrl+v"],
|
|
50
50
|
/**
|
|
51
|
-
* [W6-A] 进入 Agent
|
|
52
|
-
*
|
|
51
|
+
* [W6-A / W7-A] 进入 Agent 栏:输入为空、补全未开、有子 Agent 任务即可(不要求栏可见);有字时 `↓` 仍是
|
|
52
|
+
* 下移 / 历史,并给一次提示。`Ctrl+B` 不再进栏(tmux 缺省前缀会吃掉它),留给 `app.tasks.background`。
|
|
53
53
|
*/
|
|
54
|
-
"app.agents.focus": ["
|
|
54
|
+
"app.agents.focus": ["down"],
|
|
55
|
+
/**
|
|
56
|
+
* [W7-C] 有阻塞中的前台子 Agent 任务(或 `task_ctl wait`)时全部转后台,不看输入框;没有时落回编辑器
|
|
57
|
+
* (`tui.editor.cursorLeft` 的 `ctrl+b`)。tmux 里按 `C-b C-b` 透传。
|
|
58
|
+
*/
|
|
59
|
+
"app.tasks.background": ["ctrl+b"],
|
|
55
60
|
};
|
|
56
61
|
export function isActionId(id) {
|
|
57
62
|
return Object.prototype.hasOwnProperty.call(DEFAULT_KEYBINDINGS, id);
|
package/docs/agents.md
CHANGED
|
@@ -38,7 +38,7 @@ model: fast # inherit(缺省)| fast | strong(models.aliases)| provider/m
|
|
|
38
38
|
thinking: low
|
|
39
39
|
max-turns: 20 # 缺省 30
|
|
40
40
|
isolation: none # none(缺省)| worktree
|
|
41
|
-
background: false
|
|
41
|
+
background: false # 不写 = 按 config subagents.background
|
|
42
42
|
runner: ama # ama(缺省)| claude | codex | acp:<程序>
|
|
43
43
|
---
|
|
44
44
|
|
|
@@ -60,16 +60,16 @@ runner: ama # ama(缺省)| claude | codex | acp:<程序>
|
|
|
60
60
|
|
|
61
61
|
### `task` 参数
|
|
62
62
|
|
|
63
|
-
| 参数 | 说明
|
|
64
|
-
| ------------------------------------------------ |
|
|
65
|
-
| `prompt` | 必填,完整的任务说明
|
|
66
|
-
| `agent` | 类型名,缺省 `general`;也可以是外部 Agent(见「外部 Agent」节)
|
|
67
|
-
| `description` | 显示用的短标签
|
|
68
|
-
| `background` | `true`:立即返回 `taskId
|
|
69
|
-
| `taskId` | 续聊:向已有任务的子会话追加一条消息(忽略 `agent` / `tools` / `model`)
|
|
70
|
-
| `isolation` | `worktree`:在独立 git worktree 里运行
|
|
71
|
-
| `budgetUsd` | 外部 Agent 的美元预算
|
|
72
|
-
| `tools` / `model` / `thinkingLevel` / `maxTurns` | 保留的高级参数(描述里不展开)
|
|
63
|
+
| 参数 | 说明 |
|
|
64
|
+
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
65
|
+
| `prompt` | 必填,完整的任务说明 |
|
|
66
|
+
| `agent` | 类型名,缺省 `general`;也可以是外部 Agent(见「外部 Agent」节) |
|
|
67
|
+
| `description` | 显示用的短标签 |
|
|
68
|
+
| `background` | `true`:立即返回 `taskId`,完成后父会话收到通知;`false`:等结果。缺省取类型的 `background`,类型没写时按 `subagents.background`(见下文「前台与后台」) |
|
|
69
|
+
| `taskId` | 续聊:向已有任务的子会话追加一条消息(忽略 `agent` / `tools` / `model`) |
|
|
70
|
+
| `isolation` | `worktree`:在独立 git worktree 里运行 |
|
|
71
|
+
| `budgetUsd` | 外部 Agent 的美元预算 |
|
|
72
|
+
| `tools` / `model` / `thinkingLevel` / `maxTurns` | 保留的高级参数(描述里不展开) |
|
|
73
73
|
|
|
74
74
|
同一条回复里的多个 `task` **并行**执行,由会话的任务池限流(`subagents.maxConcurrent`,缺省 4);排队超过
|
|
75
75
|
`subagents.maxPending`(缺省 16)直接报错,提示模型不要重试。并行且会写文件的任务请用 `isolation: "worktree"`。
|
|
@@ -79,9 +79,31 @@ runner: ama # ama(缺省)| claude | codex | acp:<程序>
|
|
|
79
79
|
全文写到会话目录的 `outputs/<会话 id>-<taskId>.md`(内存会话写到系统临时目录)。轮数用尽且最后一步停在工具结果上时,
|
|
80
80
|
ama 以「不允许调用工具」再跑一轮要最终报告,结果前加 `[Turn limit reached; …]`,状态 `max_turns`。
|
|
81
81
|
|
|
82
|
+
### 前台与后台
|
|
83
|
+
|
|
84
|
+
是否后台的优先级:调用参数 `background` > 类型定义的 `background:` > config `subagents.background`。
|
|
85
|
+
`subagents.background` 缺省 `auto`:交互界面、RPC、ACP 下后台(模型需要结果才写 `background: false`),`-p` 下前台;
|
|
86
|
+
`always` / `never` 固定。两种缺省对应两版 `task` 工具描述,会话内不变,不影响缓存前缀稳定。
|
|
87
|
+
|
|
88
|
+
前台任务运行中可以转后台,任务不中断,`task` 工具调用立即返回一段固定英文结果(含 `taskId` 与输出文件),完成后照常发
|
|
89
|
+
`<task-notification>`:
|
|
90
|
+
|
|
91
|
+
- 交互界面:`Ctrl+B` / `/tasks bg [id]` / Agent 栏里按 `b`(见 [tui.md](tui.md)「子 Agent」);
|
|
92
|
+
- RPC:`background_task { taskId? }`([rpc.md](rpc.md)),SDK:`session.backgroundTask(taskId?)`,返回实际转了的 `taskId`;
|
|
93
|
+
不给 `taskId` 时转全部前台运行中任务,正在 `task_ctl wait` 的等待也一并打断;
|
|
94
|
+
- 自动:`subagents.autoBackgroundAfterMs` 大于 0 时,前台任务运行超过该毫秒数自动转后台(缺省 0 关闭)。
|
|
95
|
+
|
|
96
|
+
转后台发 `subagent_background { taskId, parentToolCallId, reason }` 事件(`user` / `timeout` / `host`)。
|
|
97
|
+
父会话 `Esc` 中断只连带中止仍在前台的任务,后台任务不受影响;停止后台任务用 `task_ctl stop` 或 `/tasks stop`。
|
|
98
|
+
|
|
99
|
+
`-p` 下(缺省前台)显式 `background: true` 仍生效:主回合结束后若还有任务在跑或通知待投递,stderr 一行提示,等它们结束、
|
|
100
|
+
跑完通知回合再输出,输出的文本是最后一条助手回复;等待受 `--max-turns` / `--max-cost` / `limits.*` 约束(到限停止等待、
|
|
101
|
+
退出码 8),`Ctrl+C` / SIGTERM 照常中止(未结束的任务随会话关闭被停止,退出码 130 / 143)。`--output-format json` 的结果带
|
|
102
|
+
`tasks`(同 `getStats().tasks`)。
|
|
103
|
+
|
|
82
104
|
### 后台任务与 `task_ctl`
|
|
83
105
|
|
|
84
|
-
|
|
106
|
+
后台任务立即返回 `taskId` 与输出文件路径。任务完成后,ama 在父会话空闲时投递一条 user 消息(`origin: "task"`)
|
|
85
107
|
并开始新回合;父正忙则等这一轮结束再投递,不打断。多条通知按完成顺序到达:
|
|
86
108
|
|
|
87
109
|
```text
|
|
@@ -95,13 +117,13 @@ ama 以「不允许调用工具」再跑一轮要最终报告,结果前加 `[T
|
|
|
95
117
|
|
|
96
118
|
`task_ctl` 的动作:
|
|
97
119
|
|
|
98
|
-
| `action` | 说明
|
|
99
|
-
| -------- |
|
|
100
|
-
| `list` | 列出本会话的任务:编号、类型、状态、轮数、token、耗时、是否后台、描述
|
|
101
|
-
| `wait` | 等任务结束(`timeoutMs` 缺省 30 000,最多 600 000
|
|
102
|
-
| `stop` | 停止任务,返回终态
|
|
103
|
-
| `output` | 运行中返回已有输出,结束后返回最终文本(同样有 50 KB 上限)
|
|
104
|
-
| `send` | 向任务追加一条消息并放到后台运行(等价于 `task{taskId, prompt, background:true}`)
|
|
120
|
+
| `action` | 说明 |
|
|
121
|
+
| -------- | ------------------------------------------------------------------------------------------------------- |
|
|
122
|
+
| `list` | 列出本会话的任务:编号、类型、状态、轮数、token、耗时、是否后台、描述 |
|
|
123
|
+
| `wait` | 等任务结束(`timeoutMs` 缺省 30 000,最多 600 000);超时说明仍在运行;被转后台时立即返回并说明不必再等 |
|
|
124
|
+
| `stop` | 停止任务,返回终态 |
|
|
125
|
+
| `output` | 运行中返回已有输出,结束后返回最终文本(同样有 50 KB 上限) |
|
|
126
|
+
| `send` | 向任务追加一条消息并放到后台运行(等价于 `task{taskId, prompt, background:true}`) |
|
|
105
127
|
|
|
106
128
|
### 续聊、保留与 resume
|
|
107
129
|
|
|
@@ -122,20 +144,22 @@ worktree 里的编辑不记进父会话的检查点。注意:worktree 不共
|
|
|
122
144
|
|
|
123
145
|
### 事件与统计
|
|
124
146
|
|
|
125
|
-
RPC / SDK 事件 `subagent_start` / `subagent_update` / `subagent_end` 见 [rpc.md](rpc.md)「子 Agent 事件」。
|
|
147
|
+
RPC / SDK 事件 `subagent_start` / `subagent_update` / `subagent_background` / `subagent_end` 见 [rpc.md](rpc.md)「子 Agent 事件」。
|
|
126
148
|
`getStats().tasks` 给出任务总数、运行中数量与按状态的计数;子会话的缓存命中与重计费仍汇总在 `cache.subagents`。
|
|
127
149
|
RPC `get_tasks` / `get_agents` 返回任务快照与可用类型(来源、定义文件路径)。交互界面的 `/tasks`、`/agents` 与 task 工具行的折叠显示见 [tui.md](tui.md)「子 Agent」。
|
|
128
150
|
|
|
129
151
|
### 配置
|
|
130
152
|
|
|
131
|
-
| 键 | 说明
|
|
132
|
-
| --------------------------------- |
|
|
133
|
-
| `subagents.maxConcurrent` | 同时运行的子 Agent,缺省 4
|
|
134
|
-
| `subagents.maxPending` | 排队上限,缺省 16
|
|
135
|
-
| `subagents.defaultModel` | 子 Agent 缺省模型,不设继承父会话
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
153
|
+
| 键 | 说明 |
|
|
154
|
+
| --------------------------------- | -------------------------------------------------------------------------------- |
|
|
155
|
+
| `subagents.maxConcurrent` | 同时运行的子 Agent,缺省 4 |
|
|
156
|
+
| `subagents.maxPending` | 排队上限,缺省 16 |
|
|
157
|
+
| `subagents.defaultModel` | 子 Agent 缺省模型,不设继承父会话 |
|
|
158
|
+
| `subagents.background` | `auto`(缺省)\| `always` \| `never`,见「前台与后台」;用户 / 项目 / 宿主级都认 |
|
|
159
|
+
| `subagents.autoBackgroundAfterMs` | 前台任务运行超过该毫秒数自动转后台,缺省 0(关闭);用户 / 项目级都认 |
|
|
160
|
+
| `agents.dirs` | 追加的定义目录 |
|
|
161
|
+
| `agents.<类型>.model` | 某个类型的模型(如让 `explore` 用便宜模型) |
|
|
162
|
+
| `models.aliases.fast` / `.strong` | 定义文件里 `model: fast / strong` 的映射 |
|
|
139
163
|
|
|
140
164
|
### 限制
|
|
141
165
|
|
package/docs/en/host-api.md
CHANGED
|
@@ -164,4 +164,8 @@ Return `"warm"` / `"stop"` (a Promise is fine). `"stop"` skips the request and s
|
|
|
164
164
|
|
|
165
165
|
## Embedding in Armadra
|
|
166
166
|
|
|
167
|
-
Armadra starts ama with a profile: `ama --profile <path>`. The profile's `host` points to its adapter (`ama-armadra.cjs`) and also carries instructions, skillDirs, hooksFile, authFile, sessionDir and `trustProject`. The adapter returns `undefined` when `ARMADRA_NODE_ID` is missing, so the same profile behaves as plain ama outside the canvas.
|
|
167
|
+
Armadra starts ama with a profile: `ama --profile <path>`. The profile's `host` points to its adapter (`ama-armadra.cjs`) and also carries instructions, skillDirs, hooksFile, authFile, sessionDir and `trustProject`. The adapter returns `undefined` when `ARMADRA_NODE_ID` is missing, so the same profile behaves as plain ama outside the canvas.
|
|
168
|
+
|
|
169
|
+
Interface defaults with a profile: `ui.quietStartup: "header"` and `ui.statusLine: "compact"` (the last line is the status bar, which the host parses by `·`). The agent bar (`ui.agentBar`) is no longer off by default; it is `auto` as in a standalone terminal. A host that shows sub-tasks itself and does not want the bar writes `{ "ui": { "agentBar": "off" } }` into the config file its profile's `config` points to.
|
|
170
|
+
|
|
171
|
+
Contract details are in [docs/design/coordinator-agent.md](https://github.com/yovinchen/Armadra/blob/main/docs/design/coordinator-agent.md) in the Armadra repository.
|