@ai-zen/agents-sdk 1.0.0-alpha.21 → 1.0.0-alpha.22

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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.0-alpha.22] - 2026-10-28
4
+
5
+ > 中断策略(`abortedMessageStrategy` / `abortedToolRoundStrategy`)从「调用方各自传参」
6
+ > 升级为**配置项**:写进 `config.json`,`createAgent()` 自动读取。
7
+
8
+ ### ✨ 新增
9
+
10
+ - **`AppConfig` 新增两个策略字段**(`types/index.ts`):
11
+ - `abortedMessageStrategy?: "keep" | "drop"` —— 被中断的 assistant 已输出的思考 / 正文是否保留。`keep` 让模型下一轮能接着半截往下说,不再「失忆重来」。
12
+ - `abortedToolRoundStrategy?: "fill" | "drop"` —— 被中断 / 结果不完整的工具轮次如何归一。`fill` 整轮保留并给未完成结果补原因,保证 `tool_calls` 与结果一一配对。
13
+ - **出厂默认写 `keep` + `fill`**(`DEFAULT_APP_CONFIG`):`keep` 是产品层结论(core 的库级默认仍是 `drop`),`fill` 与 core 默认一致、无行为变化。
14
+ - **`createAgent()` 从 `scope.config` 取策略**:优先级为「显式参数 > `scope.config` > core 默认值」。上游(CLI / Desktop)不必自己读配置再转一道参数,子 Agent 创建时也自然继承同一份策略。
15
+ - **配置迁移补齐策略字段**(`migrateConfig`):缺失或非法的 `abortedMessageStrategy` / `abortedToolRoundStrategy` 一律写回出厂默认(`changed` 置真,`ensureDefaultConfig()` 会落盘一次)。于是「配置文件里写着的就是运行时用的」,各端不再需要 `?? "keep"` 式兜底。
16
+
17
+ ### ✅ 测试
18
+
19
+ - 全量 **57 文件 / 612 例通过**(6 skipped,alpha.21 时 608 例)。
20
+ - `migrate.test.ts` 20 → 22 例:补齐缺失策略、非法值改写、合法值原样保留且 `changed=false`;原「无需迁移返回原对象」用例补上策略字段。
21
+ - `createAgent.test.ts` 6 → 8 例:策略取自 `scope.config`、显式参数覆盖配置、config 未写时回落 core 默认(`drop` / `fill`)。
22
+
3
23
  ## [1.0.0-alpha.21] - 2026-10-28
4
24
 
5
25
  ### ✨ 新增
package/README.md CHANGED
@@ -125,6 +125,8 @@ Conditionally injected based on the active model / config:
125
125
 
126
126
  Tool output protection: `AppConfig.maxToolOutput` (in characters, default 32768) is the unified ceiling for tool output. Each tool handles overflow itself — `exec` dumps `stdout.log` / `stderr.log` separately (returning head/tail previews per stream), `find_text` / `glob` / `ls` dump `result.json` (returning a head preview), and `read` only warns and suggests batched reads via `range`. Dumps go to `<tmpdir>/ai-zen/tool-output/<tool>-<timestamp>-<random>/`, one directory per call, with no self-cleanup. See [`docs/sdk-design-v1.md` §12](docs/sdk-design-v1.md).
127
127
 
128
+ Interrupt strategies live in the config: `AppConfig.abortedMessageStrategy` (`keep` / `drop`, factory `keep` — the model can continue the half-sentence after an interrupt) and `AppConfig.abortedToolRoundStrategy` (`fill` / `drop`, factory `fill` — whole rounds go in or out, because `tool_calls` must pair with results). `createAgent()` reads them from `scope.config` when no explicit option is passed, keeping a single source of truth.
129
+
128
130
  ## Built-in Plugins
129
131
 
130
132
  | Plugin | Description |
package/README.zh.md CHANGED
@@ -124,6 +124,8 @@ await scope.dispose(); // 断开 MCP、释放插件资源
124
124
 
125
125
  工具输出保护:`AppConfig.maxToolOutput`(字符数,缺省 32768)是工具输出的统一上限,超限时由各工具自行处置——`exec` 分文件落盘 `stdout.log` / `stderr.log`(返回各流头尾预览),`find_text` / `glob` / `ls` 落盘 `result.json`(返回头部预览),`read` 仅警告并提示用 `range` 分批读取。落盘目录为 `<tmpdir>/ai-zen/tool-output/<工具名>-<时间戳>-<随机串>/`,每次调用独立、不自清理。详见 [`docs/sdk-design-v1.md` §12](docs/sdk-design-v1.md)。
126
126
 
127
+ 中断策略进配置:`AppConfig.abortedMessageStrategy`(`keep` / `drop`,出厂 `keep`——中断后模型能接着半截往下说)与 `AppConfig.abortedToolRoundStrategy`(`fill` / `drop`,出厂 `fill`——整轮进出,`tool_calls` 必须与结果配对)。`createAgent()` 不传参数时直接取 `scope.config`,于是策略只有一个真相源。
128
+
127
129
  ## 内置插件
128
130
 
129
131
  | 插件 | 说明 |
@@ -237,6 +237,11 @@ export const DEFAULT_APP_CONFIG = {
237
237
  defaultMigrationModel: "deepseek-flash",
238
238
  // 工具输出上限(字符数),与 DEFAULT_MAX_TOOL_OUTPUT 保持一致
239
239
  maxToolOutput: 32_768,
240
+ // 中断策略:出厂取「保留已输出的内容」—— 中断后模型能接着半截往下说,
241
+ // 而不是「失忆重来」(core 的库级默认是 drop,产品层认为那是坑);
242
+ // 工具轮次保持整轮进出(fill),服务端要求 tool_calls 与结果一一配对。
243
+ abortedMessageStrategy: "keep",
244
+ abortedToolRoundStrategy: "fill",
240
245
  };
241
246
  // ---------------------------------------------------------------------------
242
247
  // 默认 MCP 配置(socket-pty 终端 MCP + chrome-devtools 浏览器调试 MCP)
@@ -58,10 +58,18 @@ export declare function migrateModelReasoning(model: Model): {
58
58
  * 迁移整个配置。只处理对话模型(`models`)——
59
59
  * 图片模型(`imageModels`)既没有上下文阈值、也没有思考概念。
60
60
  *
61
- * 同时清除已废弃的 `defaultModel`:模型的真相源已改为 `AgentDefinition.modelId`,
62
- * 配置级默认值连同字段一起消失(旧值先由 `ConfigManager.bootstrap()` 搬到默认 Agent 上)。
61
+ * 同时做两件字段级收敛:
62
+ * - 清除已废弃的 `defaultModel`(模型真相源已改为 `AgentDefinition.modelId`);
63
+ * - 补齐中断策略(`abortedMessageStrategy` / `abortedToolRoundStrategy`):把缺失或
64
+ * 非法值写成出厂默认。这样「配置即事实」——文件里写着的就是运行时用的,不再需要
65
+ * 使用方各自 `?? "keep"` 地兵分两路兜底。
63
66
  */
64
67
  export declare function migrateConfig(config: AppConfig): {
65
68
  config: AppConfig;
66
69
  changed: boolean;
67
70
  };
71
+ /** 合法的中断策略取值(与 core 的枚举一致) */
72
+ export declare const ABORTED_MESSAGE_STRATEGIES: readonly ["keep", "drop"];
73
+ export declare const ABORTED_TOOL_ROUND_STRATEGIES: readonly ["fill", "drop"];
74
+ /** 缺失 / 非法 → 出厂默认;返回是否有改动(直接改写传入对象) */
75
+ export declare function normalizeAbortStrategies(config: AppConfig): boolean;
@@ -103,8 +103,11 @@ export function migrateModelReasoning(model) {
103
103
  * 迁移整个配置。只处理对话模型(`models`)——
104
104
  * 图片模型(`imageModels`)既没有上下文阈值、也没有思考概念。
105
105
  *
106
- * 同时清除已废弃的 `defaultModel`:模型的真相源已改为 `AgentDefinition.modelId`,
107
- * 配置级默认值连同字段一起消失(旧值先由 `ConfigManager.bootstrap()` 搬到默认 Agent 上)。
106
+ * 同时做两件字段级收敛:
107
+ * - 清除已废弃的 `defaultModel`(模型真相源已改为 `AgentDefinition.modelId`);
108
+ * - 补齐中断策略(`abortedMessageStrategy` / `abortedToolRoundStrategy`):把缺失或
109
+ * 非法值写成出厂默认。这样「配置即事实」——文件里写着的就是运行时用的,不再需要
110
+ * 使用方各自 `?? "keep"` 地兵分两路兜底。
108
111
  */
109
112
  export function migrateConfig(config) {
110
113
  let changed = false;
@@ -121,7 +124,25 @@ export function migrateConfig(config) {
121
124
  delete next.defaultModel;
122
125
  changed = true;
123
126
  }
127
+ if (normalizeAbortStrategies(next))
128
+ changed = true;
124
129
  if (!changed)
125
130
  return { config, changed };
126
131
  return { config: next, changed };
127
132
  }
133
+ /** 合法的中断策略取值(与 core 的枚举一致) */
134
+ export const ABORTED_MESSAGE_STRATEGIES = ["keep", "drop"];
135
+ export const ABORTED_TOOL_ROUND_STRATEGIES = ["fill", "drop"];
136
+ /** 缺失 / 非法 → 出厂默认;返回是否有改动(直接改写传入对象) */
137
+ export function normalizeAbortStrategies(config) {
138
+ let changed = false;
139
+ if (!ABORTED_MESSAGE_STRATEGIES.includes(config.abortedMessageStrategy)) {
140
+ config.abortedMessageStrategy = DEFAULT_APP_CONFIG.abortedMessageStrategy;
141
+ changed = true;
142
+ }
143
+ if (!ABORTED_TOOL_ROUND_STRATEGIES.includes(config.abortedToolRoundStrategy)) {
144
+ config.abortedToolRoundStrategy = DEFAULT_APP_CONFIG.abortedToolRoundStrategy;
145
+ changed = true;
146
+ }
147
+ return changed;
148
+ }
@@ -2,7 +2,10 @@ import { SdkAgent } from "./SdkAgent.js";
2
2
  import type { Scope } from "../scope/Scope.js";
3
3
  import type { AbortedMessageStrategy, AbortedToolRoundStrategy } from "@ai-zen/agents-core";
4
4
  /**
5
- * `createAgent` 的可选行为开关(不传则全部沿用 core 默认值)。
5
+ * `createAgent` 的可选行为开关。
6
+ *
7
+ * 不传时先取 `scope.config`(`config.json`)里的同名配置,再往下才是 core 默认值:
8
+ * 中断策略属于**产品配置**,调用方不该自己读配置再转一道参数。
6
9
  */
7
10
  export interface CreateAgentOptions {
8
11
  /** 工具轮次被中断(或结果不完整)时的归一策略(core 默认 `fill`) */
@@ -10,8 +13,9 @@ export interface CreateAgentOptions {
10
13
  /** `fill` 策略下,未完成工具结果的填充原因 */
11
14
  abortedToolRoundReason?: string;
12
15
  /**
13
- * 被中断的 assistant 消息(已输出的内容 / 思考)如何处置(core 默认 `drop`)。
14
- * 传 `keep` 可让模型在下一轮接着半截往下说,而不是忘掉自己说过什么。
16
+ * 被中断的 assistant 消息(已输出的内容 / 思考)如何处置(未传时取 `scope.config`,
17
+ * 再缺则用 core 默认 `drop`)。
18
+ * `keep` 可让模型在下一轮接着半截往下说,而不是忘掉自己说过什么。
15
19
  */
16
20
  abortedMessageStrategy?: AbortedMessageStrategy;
17
21
  }
@@ -40,10 +40,12 @@ export async function createAgent(scope, agentId, options = {}) {
40
40
  // 快照后,运行时改动只作用于会话副本,模板保持纯净。
41
41
  messages: [...(definition.messages ?? [])],
42
42
  tools,
43
- // 中断相关策略:不传则由 core 取默认值(工具轮次 fill / 消息保留 drop)
44
- abortedToolRoundStrategy: options.abortedToolRoundStrategy,
43
+ // 中断相关策略:**显式参数 > `scope.config` > core 默认值**。
44
+ // 中间那一层是「配置即事实」:策略写在 `config.json` 里,各端(CLI / Desktop)
45
+ // 不必自己读配置再转成参数,子 Agent 创建时也能自然继承同一份策略。
46
+ abortedToolRoundStrategy: options.abortedToolRoundStrategy ?? scope.config?.abortedToolRoundStrategy,
45
47
  abortedToolRoundReason: options.abortedToolRoundReason,
46
- abortedMessageStrategy: options.abortedMessageStrategy,
48
+ abortedMessageStrategy: options.abortedMessageStrategy ?? scope.config?.abortedMessageStrategy,
47
49
  });
48
50
  return agent;
49
51
  }
@@ -1,4 +1,4 @@
1
- import type { AgentNS } from "@ai-zen/agents-core";
1
+ import type { AgentNS, AbortedMessageStrategy, AbortedToolRoundStrategy } from "@ai-zen/agents-core";
2
2
  /** 单维度权限策略:allow 或 deny 互斥 */
3
3
  export type PermissionPolicy = {
4
4
  allow: string[];
@@ -200,6 +200,27 @@ export interface AppConfig {
200
200
  * (如 read/find_text 对 300KB 文件的读取上限)。
201
201
  */
202
202
  maxToolOutput?: number;
203
+ /**
204
+ * 被中断的 assistant 消息(已输出的思考 / 正文)如何处置。
205
+ *
206
+ * - `keep`:保留已输出的部分(恢复为 `Completed`)—— 模型下一轮能接着半截往下说,
207
+ * 不会「失忆重来」。**出厂默认**。
208
+ * - `drop`:丢弃(保持 `Aborted`,不进下一轮上下文)。core 的库级默认。
209
+ *
210
+ * 只管**不带工具调用**的消息;工具轮次由 {@link abortedToolRoundStrategy} 决定。
211
+ * 缺省时由 `createAgent()` 回落 core 默认值(`drop`),出厂配置已写 `keep`。
212
+ */
213
+ abortedMessageStrategy?: AbortedMessageStrategy;
214
+ /**
215
+ * 被中断 / 结果不完整的工具轮次如何归一。
216
+ *
217
+ * - `fill`:保留整轮(assistant 恢复为 `Completed`,未完成的结果补原因)——**出厂默认**,
218
+ * 服务端要求「N 个 tool_calls 对 N 条结果」,整轮进出才不会报错。
219
+ * - `drop`:整轮出列(assistant 与其结果都不发给模型)。
220
+ *
221
+ * 缺省时由 `createAgent()` 回落 core 默认值(`fill`)。
222
+ */
223
+ abortedToolRoundStrategy?: AbortedToolRoundStrategy;
203
224
  }
204
225
  /**
205
226
  * 工具环境 — Scope 的能力插件在实例化内置工具时注入的环境信息。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-zen/agents-sdk",
3
- "version": "1.0.0-alpha.21",
3
+ "version": "1.0.0-alpha.22",
4
4
  "description": "AI-Zen Agents SDK — shared business logic for CLI and Desktop",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",