@armadra/agent 0.8.1 → 0.9.1
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 +19 -0
- package/CHANGELOG.zh-CN.md +19 -0
- package/dist/ai/providers/catalog-data.js +2 -2
- package/dist/ai/providers/models-dev-data.js +11 -11
- package/dist/bundle/ama.cjs +24 -18
- package/dist/checkpoints/backend.js +6 -1
- package/dist/drivers/acp/client.d.ts +11 -2
- package/dist/drivers/acp/client.js +8 -4
- package/docs/en/reference/acp.md +3 -2
- package/docs/reference/acp.md +7 -3
- package/package.json +1 -1
|
@@ -21,6 +21,8 @@ export function createCheckpointBackendFactory(settings) {
|
|
|
21
21
|
return undefined;
|
|
22
22
|
let tracker;
|
|
23
23
|
let registered = false;
|
|
24
|
+
// 登记会话根目录的写入(mkdir → tmp → rename);snapshot 等它结束,收尾时不会还有文件在落盘
|
|
25
|
+
let registering = Promise.resolve();
|
|
24
26
|
const warn = (message) => ctx.log("warn", message);
|
|
25
27
|
const get = () => {
|
|
26
28
|
tracker ??= new CheckpointTracker({
|
|
@@ -34,7 +36,7 @@ export function createCheckpointBackendFactory(settings) {
|
|
|
34
36
|
});
|
|
35
37
|
if (!registered && settings.sessionsRoot !== undefined) {
|
|
36
38
|
registered = true;
|
|
37
|
-
registerSessionRoot(settings.dataDir, settings.sessionsRoot).catch((error) => ctx.log("debug", msg().session.checkpoints.registerFailed(String(error))));
|
|
39
|
+
registering = registerSessionRoot(settings.dataDir, settings.sessionsRoot).catch((error) => ctx.log("debug", msg().session.checkpoints.registerFailed(String(error))));
|
|
38
40
|
}
|
|
39
41
|
return tracker;
|
|
40
42
|
};
|
|
@@ -79,6 +81,9 @@ export function createCheckpointBackendFactory(settings) {
|
|
|
79
81
|
hooks,
|
|
80
82
|
snapshot: async (userEntryId) => {
|
|
81
83
|
try {
|
|
84
|
+
// 先让登记写完再记检查点:检查点条目落盘之后请求马上发出,不能再被它拖住
|
|
85
|
+
get();
|
|
86
|
+
await registering;
|
|
82
87
|
const shadowCommit = await shadowSnapshot(userEntryId);
|
|
83
88
|
await get().snapshot(userEntryId, shadowCommit !== undefined ? { shadowCommit } : {});
|
|
84
89
|
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* JSON-RPC over NDJSON({@link JsonRpcPeer}),手写零依赖;`@armadra/agent/acp` 导出供 Armadra 复用。
|
|
5
5
|
*
|
|
6
|
-
* - 不声明 `fs`
|
|
6
|
+
* - 不声明 `fs` 能力:Agent 发来的 `fs/*` 请求一律 method not found。`terminal` 同理,除非构造参数给了
|
|
7
|
+
* `onTerminal`:此时声明 `terminal: true`,`terminal/*` 请求交给它(ama 自己作客户端不给)。
|
|
7
8
|
* - `session/request_permission` 交给 `onPermission`(驱动再交给 ama 的审批通道,只交给人);
|
|
8
9
|
* 没有处理器时按无人值守回首个 `reject_once`(没有则 cancelled)。
|
|
9
10
|
* - `cancel(sessionId)` 发 `session/cancel` 通知,并让该会话所有挂起的权限请求回 `cancelled`
|
|
@@ -29,6 +30,12 @@ export interface AcpClientHandlers {
|
|
|
29
30
|
* `signal`:该会话被 cancel、连接关闭时 abort(此时回 `{ action: "cancel" }`,不必再答)。
|
|
30
31
|
*/
|
|
31
32
|
onElicitation?(params: AcpElicitationParams, signal: AbortSignal): Promise<AcpElicitationResult>;
|
|
33
|
+
/**
|
|
34
|
+
* `terminal/*`(create / output / wait_for_exit / kill / release):宿主替 Agent 起终端。给了它才声明
|
|
35
|
+
* `clientCapabilities.terminal: true` 并把这些请求交给它;`method` 是完整方法名,`params` 原样交回,返回值即
|
|
36
|
+
* 答复,抛 `RpcError` 回对应错误。`signal`:连接关闭时 abort。权限、cwd 限制与输出上限由宿主负责。
|
|
37
|
+
*/
|
|
38
|
+
onTerminal?(method: string, params: unknown, signal: AbortSignal): Promise<unknown>;
|
|
32
39
|
onProtocolError?(line: string, reason: string): void;
|
|
33
40
|
onClose?(): void;
|
|
34
41
|
}
|
|
@@ -45,12 +52,14 @@ export declare class AcpClient {
|
|
|
45
52
|
* 本版客户端支持的可选能力,供宿主做特性检测(旧版没有这个字段,旧一点的只有 `mcpServers`):
|
|
46
53
|
* - `mcpServers`:开会话时可经 {@link AcpSessionOptions} 传 MCP 服务器;
|
|
47
54
|
* - `elicitation`:构造参数 `onElicitation` 接 `elicitation/create`;
|
|
48
|
-
* - `configOptions`:`setConfigOption` 与开会话答的 `configOptions
|
|
55
|
+
* - `configOptions`:`setConfigOption` 与开会话答的 `configOptions`;
|
|
56
|
+
* - `terminal`:构造参数 `onTerminal` 接 `terminal/*`。
|
|
49
57
|
*/
|
|
50
58
|
static readonly features: {
|
|
51
59
|
readonly mcpServers: true;
|
|
52
60
|
readonly elicitation: true;
|
|
53
61
|
readonly configOptions: true;
|
|
62
|
+
readonly terminal: true;
|
|
54
63
|
};
|
|
55
64
|
private readonly peer;
|
|
56
65
|
/** sessionId → 挂起权限请求的取消器。 */
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* JSON-RPC over NDJSON({@link JsonRpcPeer}),手写零依赖;`@armadra/agent/acp` 导出供 Armadra 复用。
|
|
5
5
|
*
|
|
6
|
-
* - 不声明 `fs`
|
|
6
|
+
* - 不声明 `fs` 能力:Agent 发来的 `fs/*` 请求一律 method not found。`terminal` 同理,除非构造参数给了
|
|
7
|
+
* `onTerminal`:此时声明 `terminal: true`,`terminal/*` 请求交给它(ama 自己作客户端不给)。
|
|
7
8
|
* - `session/request_permission` 交给 `onPermission`(驱动再交给 ama 的审批通道,只交给人);
|
|
8
9
|
* 没有处理器时按无人值守回首个 `reject_once`(没有则 cancelled)。
|
|
9
10
|
* - `cancel(sessionId)` 发 `session/cancel` 通知,并让该会话所有挂起的权限请求回 `cancelled`
|
|
@@ -50,9 +51,10 @@ export class AcpClient {
|
|
|
50
51
|
* 本版客户端支持的可选能力,供宿主做特性检测(旧版没有这个字段,旧一点的只有 `mcpServers`):
|
|
51
52
|
* - `mcpServers`:开会话时可经 {@link AcpSessionOptions} 传 MCP 服务器;
|
|
52
53
|
* - `elicitation`:构造参数 `onElicitation` 接 `elicitation/create`;
|
|
53
|
-
* - `configOptions`:`setConfigOption` 与开会话答的 `configOptions
|
|
54
|
+
* - `configOptions`:`setConfigOption` 与开会话答的 `configOptions`;
|
|
55
|
+
* - `terminal`:构造参数 `onTerminal` 接 `terminal/*`。
|
|
54
56
|
*/
|
|
55
|
-
static features = { mcpServers: true, elicitation: true, configOptions: true };
|
|
57
|
+
static features = { mcpServers: true, elicitation: true, configOptions: true, terminal: true };
|
|
56
58
|
peer;
|
|
57
59
|
/** sessionId → 挂起权限请求的取消器。 */
|
|
58
60
|
pendingPermissions = new Map();
|
|
@@ -105,7 +107,7 @@ export class AcpClient {
|
|
|
105
107
|
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
106
108
|
clientCapabilities: {
|
|
107
109
|
fs: { readTextFile: false, writeTextFile: false },
|
|
108
|
-
terminal:
|
|
110
|
+
terminal: this.options.onTerminal !== undefined,
|
|
109
111
|
session: { configOptions: {} },
|
|
110
112
|
...(this.options.onElicitation !== undefined ? { elicitation: {} } : {}),
|
|
111
113
|
},
|
|
@@ -175,6 +177,8 @@ export class AcpClient {
|
|
|
175
177
|
async onRequest(method, params, connection) {
|
|
176
178
|
if (method === ACP_METHODS.elicitationCreate && this.options.onElicitation !== undefined)
|
|
177
179
|
return this.onElicitation(params, connection);
|
|
180
|
+
if (method.startsWith("terminal/") && this.options.onTerminal !== undefined)
|
|
181
|
+
return this.options.onTerminal(method, params, connection);
|
|
178
182
|
if (method !== ACP_METHODS.requestPermission)
|
|
179
183
|
throw new RpcError(RPC_ERRORS.methodNotFound, `client does not support ${method}`);
|
|
180
184
|
const request = params;
|
package/docs/en/reference/acp.md
CHANGED
|
@@ -149,7 +149,7 @@ The model uses ACP agents through `task(agent="acp:<program>")` (ama itself is `
|
|
|
149
149
|
|
|
150
150
|
`AcpClient` (`@armadra/agent/acp`): `initialize`, `newSession`, `resumeSession` (preferred, no replay), `loadSession`, `listSessions`, `closeSession`, `prompt`, `setMode`, `cancel`.
|
|
151
151
|
|
|
152
|
-
- Declared client capabilities: `session.configOptions: {}` (select options; boolean is not declared); `fs`
|
|
152
|
+
- Declared client capabilities: `session.configOptions: {}` (select options; boolean is not declared); `fs` is not declared (`fs/*` requests from the agent answer method not found) and `terminal` only when `onTerminal` is given (see below), and neither is `auth.terminal` (ama has no interactive terminal to lend to the agent).
|
|
153
153
|
- `$/cancel_request` is on in both directions: aborting the `signal` of a request after it was sent tells the agent to withdraw it; when the agent withdraws a pending `session/request_permission` / `elicitation/create`, the handler's `signal` aborts and the answer is `cancelled` / `cancel` (a choice the handler makes afterwards does not count).
|
|
154
154
|
- `session/request_permission` goes to `onPermission`; without a handler the first `reject_once` is answered (unattended).
|
|
155
155
|
- `cancel(sessionId)` sends `session/cancel` and answers `cancelled` to that session's pending permission requests (required by the spec).
|
|
@@ -157,7 +157,8 @@ The model uses ACP agents through `task(agent="acp:<program>")` (ama itself is `
|
|
|
157
157
|
- `mcpServers` of session-open calls (`newSession` / `resumeSession` / `loadSession`) defaults to an empty array; a host can pass a third argument `{ mcpServers }` (for stdio, `{ name, command, args, env: [{ name, value }] }`), which is forwarded to the agent as is. `AcpClient.features.mcpServers === true` signals support (older versions have no `features`). ama itself, as a client, still passes none.
|
|
158
158
|
- `elicitation/create` (the agent asking a human for structured input): only when the constructor is given `onElicitation(params, signal)` does `initialize` declare `clientCapabilities.elicitation` and accept this request; otherwise it is not declared and the request answers method not found (as in older versions). Answers are normalized to `{ action: "accept" | "decline" | "cancel", content? }` (`content` only with accept; unknown actions count as cancel); pending ones answer `{ action: "cancel" }` on `cancel(sessionId)` and when the connection closes. ama itself, as a client, gives no handler and never fills in forms for a human.
|
|
159
159
|
- Session config options: the `configOptions` of session-open answers (new / load / resume) are passed through; `setConfigOption(sessionId, configId, value)` sends `session/set_config_option`, and the answer is the new state of all options.
|
|
160
|
-
- `
|
|
160
|
+
- `terminal/*` (the agent asking the host for a terminal): only when the constructor is given `onTerminal(method, params, signal)` does `initialize` declare `clientCapabilities.terminal: true`; `terminal/create|output|wait_for_exit|kill|release` are then handed to it with the params untouched, its return value is the answer and throwing `RpcError` answers with that error. Without it `terminal: false` is declared and the requests answer method not found (as in older versions). Permissions, cwd restriction and output limits are the host's job; ama itself, as a client, gives no handler.
|
|
161
|
+
- `AcpClient.features`: `{ mcpServers, elicitation, configOptions, terminal }`, for feature detection by hosts.
|
|
161
162
|
|
|
162
163
|
`AcpDriver` implements the driver contract (`AgentDriver`) on top of the client:
|
|
163
164
|
|
package/docs/reference/acp.md
CHANGED
|
@@ -155,8 +155,8 @@ stdin 关闭后等已开始的运行结束再退出(0);`ama` 进程的 std
|
|
|
155
155
|
|
|
156
156
|
`AcpClient`(`@armadra/agent/acp`):`initialize`、`newSession`、`resumeSession`(优先,不回放)、`loadSession`、`listSessions`、`closeSession`、`prompt`、`setMode`、`cancel`。
|
|
157
157
|
|
|
158
|
-
- 声明的客户端能力:`session.configOptions: {}`(接 select 型配置项,不声明 boolean);不声明 `fs`
|
|
159
|
-
`
|
|
158
|
+
- 声明的客户端能力:`session.configOptions: {}`(接 select 型配置项,不声明 boolean);不声明 `fs`(Agent 发来的 `fs/*` 请求回 method not found);`terminal` 只在构造参数给了
|
|
159
|
+
`onTerminal` 时声明(见下),也不声明 `auth.terminal`(ama 没有可借给 Agent 的交互终端)。
|
|
160
160
|
- 线路两侧开 `$/cancel_request`:本端请求的 `signal` 在发出后 abort 会通知 Agent 撤回;Agent 撤回挂起的
|
|
161
161
|
`session/request_permission` / `elicitation/create` 时处理器的 `signal` abort,答 `cancelled` / `cancel`(处理器之后给的选择不作数)。
|
|
162
162
|
- `session/request_permission` 交给 `onPermission`;没有处理器时回首个 `reject_once`(无人值守)。
|
|
@@ -171,7 +171,11 @@ stdin 关闭后等已开始的运行结束再退出(0);`ama` 进程的 std
|
|
|
171
171
|
与连接关闭时挂起的一律回 `{ action: "cancel" }`。ama 自己作客户端时不给处理器,从不替人填表。
|
|
172
172
|
- 会话配置项:开会话(new / load / resume)答的 `configOptions` 原样交回;`setConfigOption(sessionId, configId, value)` 发
|
|
173
173
|
`session/set_config_option`,答复是全部配置项的新状态。
|
|
174
|
-
- `
|
|
174
|
+
- `terminal/*`(Agent 向宿主要终端):构造参数给了 `onTerminal(method, params, signal)` 才在 `initialize` 声明
|
|
175
|
+
`clientCapabilities.terminal: true`,并把 `terminal/create|output|wait_for_exit|kill|release` 连同原样参数交给它,返回值即答复,
|
|
176
|
+
抛 `RpcError` 回对应错误;没给时声明 `terminal: false`、请求回 method not found(与旧版相同)。权限、cwd 限制与输出上限由宿主负责;
|
|
177
|
+
ama 自己作客户端时不给处理器。
|
|
178
|
+
- `AcpClient.features`:`{ mcpServers, elicitation, configOptions, terminal }`,宿主据此做特性检测。
|
|
175
179
|
|
|
176
180
|
`AcpDriver` 在客户端之上实现驱动契约(`AgentDriver`):
|
|
177
181
|
|