@ai-zen/agents-sdk 1.0.0-alpha.0 → 1.0.0-alpha.10
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 +153 -0
- package/README.md +15 -14
- package/README.zh.md +15 -14
- package/dist/agent-plugins/AutoMigratePlugin.d.ts +33 -7
- package/dist/agent-plugins/AutoMigratePlugin.js +20 -6
- package/dist/agent-plugins/ContextGuardPlugin.d.ts +13 -3
- package/dist/agent-plugins/ContextGuardPlugin.js +9 -6
- package/dist/config/ConfigManager.d.ts +29 -1
- package/dist/config/ConfigManager.js +84 -2
- package/dist/config/constants.d.ts +3 -1
- package/dist/config/constants.js +77 -39
- package/dist/config/factory-skills.d.ts +33 -0
- package/dist/config/factory-skills.js +126 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -2
- package/dist/runtime/HandoffGuardPlugin.d.ts +35 -0
- package/dist/runtime/HandoffGuardPlugin.js +65 -0
- package/dist/runtime/HandoffService.d.ts +199 -0
- package/dist/runtime/HandoffService.js +372 -0
- package/dist/scope/plugins/builtin/BatchEditTool.js +1 -1
- package/dist/scope/plugins/builtin/DownloadFileTool.js +1 -1
- package/dist/scope/plugins/builtin/ExecTool.js +2 -2
- package/dist/scope/plugins/builtin/FindTextTool.js +6 -6
- package/dist/scope/plugins/builtin/GenerateImageTool.d.ts +1 -1
- package/dist/scope/plugins/builtin/GenerateImageTool.js +7 -7
- package/dist/scope/plugins/builtin/GlobTool.js +1 -1
- package/dist/scope/plugins/builtin/InspectFileTool.d.ts +2 -2
- package/dist/scope/plugins/builtin/InspectFileTool.js +5 -5
- package/dist/scope/plugins/builtin/LsTool.js +1 -1
- package/dist/scope/plugins/builtin/{ReadFileTool.d.ts → ReadTool.d.ts} +1 -1
- package/dist/scope/plugins/builtin/{ReadFileTool.js → ReadTool.js} +3 -3
- package/dist/scope/plugins/builtin/{ExecAsyncTool.d.ts → SpawnTool.d.ts} +1 -1
- package/dist/scope/plugins/builtin/{ExecAsyncTool.js → SpawnTool.js} +2 -2
- package/dist/scope/plugins/builtin/ViewImageTool.js +2 -2
- package/dist/scope/plugins/builtin/{WriteFileTool.d.ts → WriteTool.d.ts} +1 -1
- package/dist/scope/plugins/builtin/{WriteFileTool.js → WriteTool.js} +2 -2
- package/dist/scope/plugins/builtin/index.d.ts +4 -4
- package/dist/scope/plugins/builtin/index.js +7 -7
- package/dist/scope/plugins/builtin/outputGuard.d.ts +2 -2
- package/dist/scope/plugins/builtin/outputGuard.js +1 -1
- package/dist/types/index.d.ts +24 -3
- package/package.json +3 -3
- package/dist/runtime/TaskMigrationService.d.ts +0 -128
- package/dist/runtime/TaskMigrationService.js +0 -211
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,158 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.0-alpha.10] - 2026-10-20
|
|
4
|
+
|
|
5
|
+
### 💥 Breaking Changes
|
|
6
|
+
|
|
7
|
+
- **`TaskMigrationService` → `HandoffService`,并拆成 `handoff()` / `migrate()` 两层** —— 「交接」(写交接文档)与「迁移」(交接 + 开新会话)此前混在一个方法里,现在概念与 API 一一对应:
|
|
8
|
+
- `handoff(params)`:停工 → 核实 → 写文档 → 校验(失败降级)。**不改动会话**;
|
|
9
|
+
- `migrate(params)`:`handoff()` 之后按 `strategy` 清历史并注入断点消息。
|
|
10
|
+
- 类型随迁:`MigrationContext` → `HandoffContext`(新增 `mode` / `requestedMode` / `handoffPath` / `migrating`),`TaskMigrationServiceOptions` → `HandoffServiceOptions`(新增 `handoffDir` / `mode` / `skillDirs` / `minHandoffBytes`)。
|
|
11
|
+
- 钩子重命名:`onBeforeMigrate` → `onBeforeHandoff`,新增 `onHandoff`(文档写好、清历史之前)。
|
|
12
|
+
- **交接文档改由「原 agent 在自己会话里写」(`mode: "self"`,默认)**,而非另起一次独立的摘要调用。原实现把历史序列化成 `[role]: content` 后交给一个无工具、无原会话上下文的调用,工具名与调用参数在序列化时全部丢失,写文档的一方也无法核实分支/改动/测试状态,只能靠推演——这是文档质量差的根因。现在的 `self` 回合:原 agent 保留全部上下文与工具,可 `read` / `exec` / `git status` 核实后落盘。
|
|
13
|
+
- **`summary`(旧的独立摘要)保留为逃生模式**,并作为 `self` 失败时的**单向**降级目标(无 `write` 工具 / 文件缺失或过小(重试一次)/ 工具或护栏报错)。反向永不发生——那会在上下文最满的时刻再加一次全量请求。
|
|
14
|
+
- **`AutoMigrateOptions` 新增 `resolveMode`**,把「用谁交接」从插件继承转移到回调:返回 `HandoffMode` 或 `null`(跳过本次迁移)。原 CLI 的 `AutoMigrateConfirmPlugin` 子类因此退化为纯回调。
|
|
15
|
+
|
|
16
|
+
### ✨ 新增
|
|
17
|
+
|
|
18
|
+
- **`HandoffGuardPlugin`**:交接回合的一次性工具守卫。只放行 `write` 到交接文档(绝对路径归一后比较),拒绝 `edit` / `batch_edit` / `rm` / `rename` / `mkdir` / `copy`。拒绝返回字符串(软拒绝)而非抛错——抛错会被 core 标记为 Error + `isPreventDefault`,整轮交接直接死。边界如实记录:挡不住 `exec`,它降低误操作概率,不是沙箱。
|
|
19
|
+
- **`ContextGuardPlugin` 新增 `isSuspended` / `suspendedRatio`**:交接回合(`service.busy`)把硬上限从 `× 1.5` 放宽到 `× 2`,既不被误杀又保留熔断。
|
|
20
|
+
- **出厂 Skill 机制**:`ConfigManager.ensureFactorySkills()` 在 `bootstrap()` 中释放 / 同步 `skills/handoff/SKILL.md`。覆盖策略与 `syncManagedModels` 同构——frontmatter 标 `metadata.custom: "true"` 视为用户自有、永不覆盖;否则随版本同步。内容以字符串常量内联在 `config/factory-skills.ts`(`tsc` 直接编译,无需打包非 TS 资源)。
|
|
21
|
+
- **交接模板的唯一真相源改为 Skill**:`HANDOFF_SECTIONS` / `createPrompt()` 已删除,代码只保留「读 Skill → 注入 → 校验文件 → 读不到时用 `FALLBACK_HANDOFF_TEMPLATE`」。Skill 只讲「怎么写」,代码只讲「写到哪、有什么能力」(本体系无模板变量引擎,不发明占位符)。
|
|
22
|
+
- `HandoffService.createHandoffFileName()`(`<YYYYMMDD-HHmmss>-<会话id前8位>.md`)、`createHandoffInstruction()`、`createPostMessages(handoffPath)`(断点**只给路径**,由接手方 `read`)。
|
|
23
|
+
|
|
24
|
+
### 🔧 修复
|
|
25
|
+
|
|
26
|
+
- **交接触发的无限递归**:交接回合本身是一次 `send()`,其 `onAfterSend` 会再次进入 `AutoMigratePlugin`。现以 `service.busy` 让行(`handoff()` / `migrate()` 共用一把锁,顺带拒绝重入)。
|
|
27
|
+
- **交接回合被自己触发/被护栏击杀**:交接恰好发生在上下文最满的时刻。除 `busy` 让行外,交接回合开跑前清空 `agent.lastUsage`(纵深防御),并由调用方在迁移后清空(否则护栏拿交接回合用量误杀新会话第一条消息)。
|
|
28
|
+
|
|
29
|
+
### ✅ 测试
|
|
30
|
+
|
|
31
|
+
- 新增 `HandoffService.test.ts`(24 例)、`HandoffGuardPlugin.test.ts`(7 例)、`factory-skills.test.ts`(7 例);重写 `AutoMigratePlugin.test.ts`、`ContextGuardPlugin.test.ts`(新增 `isSuspended` 4 例)。全量 **54 文件 / 525 用例**通过,`tsc --noEmit` 与 `build` 零错误。
|
|
32
|
+
|
|
33
|
+
### 📄 Docs
|
|
34
|
+
|
|
35
|
+
- `docs/sdk-design-v1.md` §18 重写为「任务交接(HandoffService)」(两层语义、Template 单一真相源、两种执行者、自交接三道保险、接口、断点只给路径);§17 插件章节、目录树与消费示例同步。
|
|
36
|
+
- `README.md` / `README.zh.md`、`../docs/{en,zh}/sdk.md`、`architecture.md`、`getting-started.md` 及网站镜像同步。
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## [1.0.0-alpha.9] - 2026-10-14
|
|
40
|
+
|
|
41
|
+
### ⚠️ Dependency
|
|
42
|
+
|
|
43
|
+
- **`@ai-zen/agents-core` bumped to `^4.5.1`** — docs-only patch; no SDK source change.
|
|
44
|
+
|
|
45
|
+
### 📄 Docs
|
|
46
|
+
|
|
47
|
+
- Corrected the factory-defaults description in `docs/sdk-design-v1.md`: the preset **model count is 8** (was 7), and `DEFAULT_MCP_CONFIG` ships **two** servers (`socket-pty` + `chrome-devtools`).
|
|
48
|
+
|
|
49
|
+
## [1.0.0-alpha.8] - 2026-10-14
|
|
50
|
+
|
|
51
|
+
### ⚠️ Dependency
|
|
52
|
+
|
|
53
|
+
- **`@ai-zen/agents-core` bumped to `^4.5.0`** — picks up `AgentNS.Message.subAgentUsage` and the `sumUsage()` primitive. The skill sub-agent tool (`call_skill_sub_agent`) is built on `AgentToolLazy`, so it inherits the delegation-boundary stamping with no SDK source change.
|
|
54
|
+
|
|
55
|
+
## [1.0.0-alpha.7] - 2026-10-14
|
|
56
|
+
|
|
57
|
+
### ⚠️ Dependency
|
|
58
|
+
|
|
59
|
+
- **`@ai-zen/agents-core` bumped to `^4.4.0`** — picks up `AgentNS.Message.usage` (per-message token usage, stamped from the final stream chunk). No SDK source change; the `workspace:^` range resolves to `^4.4.0` on publish.
|
|
60
|
+
|
|
61
|
+
## [1.0.0-alpha.6] - 2026-10-13
|
|
62
|
+
|
|
63
|
+
### 💥 Breaking Changes
|
|
64
|
+
|
|
65
|
+
- **`exec_async` renamed to `spawn`** — the tool wraps `child_process.spawn` and returns `{ success, pid, message }`, so the new name matches both the implementation and the "start a process, get its pid" contract. It also pairs cleanly with `exec`: `exec` runs and **waits** (captures output, has a `timeout`), `spawn` starts and **returns immediately**. Permission lists, skill `allowed-tools` and any prompt naming `exec_async` must switch to `spawn`. The behaviour is otherwise unchanged — still shell-parsed, still does **not** capture output (redirect to a file if you need it).
|
|
66
|
+
- **Built-in tool classes renamed to match their new tool names** — `ReadFileTool` → `ReadTool`, `WriteFileTool` → `WriteTool`, `ExecAsyncTool` → `SpawnTool`, with the source files renamed to match. The classes re-exported from `@ai-zen/agents-sdk` change accordingly, so consumers importing them by name must update.
|
|
67
|
+
|
|
68
|
+
## [1.0.0-alpha.5] - 2026-10-13
|
|
69
|
+
|
|
70
|
+
### 💥 Breaking Changes
|
|
71
|
+
|
|
72
|
+
- **All built-in tool names unified on `snake_case`** — the multi-word tools that used camelCase were renamed. A tool name is the API contract the model sees and is matched **verbatim** by the permission system, so any `permissions.allow` / `deny` list, skill `allowed-tools` entry or prompt that names a tool must be updated:
|
|
73
|
+
|
|
74
|
+
| old | new |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `readFile` | `read` |
|
|
77
|
+
| `writeFile` | `write` |
|
|
78
|
+
| `inspectFile` | `inspect_file` |
|
|
79
|
+
| `findText` | `find_text` |
|
|
80
|
+
| `batchEdit` | `batch_edit` |
|
|
81
|
+
| `downloadFile` | `download_file` |
|
|
82
|
+
| `generateImage` | `generate_image` |
|
|
83
|
+
| `viewImage` | `view_image` |
|
|
84
|
+
|
|
85
|
+
Single-word tools (`cwd`, `edit`, `glob`, `ls`, `mkdir`, `rm`, `rename`, `copy`, `exec`, `exist`, `sleep`), the already-`snake_case` `exec_async`, the MCP / skill wrapper tools and core's `indexed_search` are unchanged. Tool descriptions and docs were updated in the same pass.
|
|
86
|
+
|
|
87
|
+
### 🔧 Changed
|
|
88
|
+
|
|
89
|
+
- **Dependency `@ai-zen/agents-core` bumped to `^4.3.2`** (carries the `indexedSearch` → `indexed_search` rename).
|
|
90
|
+
|
|
91
|
+
### 📄 Docs
|
|
92
|
+
|
|
93
|
+
- Current-version references in `docs/zh` and `docs/en` updated to `1.0.0-alpha.5`.
|
|
94
|
+
|
|
95
|
+
## [1.0.0-alpha.4] - 2026-10-13
|
|
96
|
+
|
|
97
|
+
### 🔧 Changed
|
|
98
|
+
|
|
99
|
+
- **Dependency `@ai-zen/agents-core` bumped to `^4.3.1`** (declared as `workspace:^`, expanded to `^4.3.1` at publish time). Pulls in core 4.3.1's fix for interrupted parallel tool rounds — the assistant message carrying `tool_calls` and its results now stay all-in or all-out, so an interrupted parallel tool call no longer leaves orphan `tool` results that the server rejects. `AgentContext` gains `abortedToolRoundStrategy` (default `"fill"`) and `abortedToolRoundReason`; set `agent.abortedToolRoundStrategy = "drop"` to drop the whole round instead
|
|
100
|
+
|
|
101
|
+
### 📄 Docs
|
|
102
|
+
|
|
103
|
+
- Current-version references in `docs/zh` and `docs/en` updated to `1.0.0-alpha.4`.
|
|
104
|
+
|
|
105
|
+
## [1.0.0-alpha.3] - 2026-10-03
|
|
106
|
+
|
|
107
|
+
### 🔧 Fixed
|
|
108
|
+
|
|
109
|
+
- **`generateImage` `model` parameter description no longer points at a host-CLI command** — the description used to read "配置中的图片模型可通过 'aiz config show' 查看" (the configured image models can be viewed via `aiz config show`). Since tool descriptions ship inside every request's `tools` payload, that hint propagated into **every layer** of the agent stack: the model would `exec("aiz config show")`, but the CLI resolves a bare `aiz config show` invocation as stdio mode with the instruction `config show` — i.e. a **brand-new agent** — whose own `generateImage` description repeats the very same hint, producing a self-referential recursion that keeps spawning nested agents. The parameter now reads "若指定的模型不存在,本工具会返回当前可用的模型列表" (if the specified model does not exist, this tool returns the list of currently available models), which matches the actual `!imageModel` branch in `call()` and stops the model from shelling out to the host CLI.
|
|
110
|
+
|
|
111
|
+
### 📄 Docs
|
|
112
|
+
|
|
113
|
+
- Current-version references in `docs/zh` and `docs/en` updated to `1.0.0-alpha.3`.
|
|
114
|
+
|
|
115
|
+
## [1.0.0-alpha.2] - 2026-10-03
|
|
116
|
+
|
|
117
|
+
### 🚀 New Features
|
|
118
|
+
|
|
119
|
+
- **`chrome-devtools` added to the factory default MCP config** — `DEFAULT_MCP_CONFIG` now ships two servers instead of one: alongside `socket-pty`, a freshly released `~/.ai-zen/mcp.json` includes `chrome-devtools` (`npx -y chrome-devtools-mcp@latest`, Google's official `chrome-devtools-mcp`), so browser debugging and automation work out of the box — page navigation, performance traces, network and console inspection, screenshots. Existing `mcp.json` files are still never overwritten, so user configurations (including custom flags such as `--executablePath`) are untouched. Defined in `packages/sdk/src/config/constants.ts`, released by `ConfigManager.ensureDefaultMcpConfig()`.
|
|
120
|
+
|
|
121
|
+
### ✅ Tests
|
|
122
|
+
|
|
123
|
+
- `ConfigManager.bootstrap.test.ts` now asserts the factory-default `mcp.json` carries both `socket-pty` and `chrome-devtools` (the latter resolved from the `chrome-devtools-mcp` package via `npx`), covering both the `bootstrap()` and `ensureDefaultMcpConfig()` paths.
|
|
124
|
+
|
|
125
|
+
### 📄 Docs
|
|
126
|
+
|
|
127
|
+
- Factory-default MCP descriptions in `docs/zh/mcp.md` / `docs/en/mcp.md` and `docs/zh/sdk.md` / `docs/en/sdk.md` now list both `socket-pty` and `chrome-devtools`.
|
|
128
|
+
- Current-version references in `docs/zh` and `docs/en` updated to `1.0.0-alpha.2`.
|
|
129
|
+
|
|
130
|
+
## [1.0.0-alpha.1] - 2026-10-03
|
|
131
|
+
|
|
132
|
+
### 💥 Breaking Changes
|
|
133
|
+
|
|
134
|
+
- **Factory model catalog refreshed (verified against vendor sources on 2026-10-03)** — every stale or retired model ID in `DEFAULT_APP_CONFIG.models` is replaced:
|
|
135
|
+
- **OpenAI**: `gpt-5.5` → `gpt-6-astra` / `gpt-6.1-sol` / `gpt-6-luna`
|
|
136
|
+
- **Zhipu**: `glm-5.1` / `glm-5v-turbo` → `glm-5.3` / `glm-5.3-flash` / `glm-5.3-flashx`
|
|
137
|
+
- **DeepSeek**: `deepseek-v4-pro` / `deepseek-v4-flash` / `deepseek-v4-flash-vision-exp` → `deepseek-flash`. The two V4-Flash variants were retired by the vendor, and V4-Pro requests are routed to V4.1-Flash.
|
|
138
|
+
- Defaults: `defaultModel` / `defaultMigrationModel` move from `deepseek-v4-flash` to `deepseek-flash`.
|
|
139
|
+
- **`Model.maxContextTokens` semantics clarified — it is the task-migration (handoff) trigger threshold, not the model context window** — `AutoMigratePlugin` does not estimate or learn: it only compares `usage.prompt_tokens` from the API response against this value. The previous comment read "上下文窗口 token 上限" ("context window token limit"), which is why values had been filled in with raw window sizes. Values are now ~25% of the real window (250K for ≥1M-window models), except `glm-4.7-flash` (200K window) which uses 100K.
|
|
140
|
+
|
|
141
|
+
### 🚀 New Features
|
|
142
|
+
|
|
143
|
+
- **Managed model catalog sync (`custom` opt-out)** — `ConfigManager.ensureDefaultConfig()` now reconciles the factory catalog on every `bootstrap()`. Entries in `models` / `imageModels` that do **not** carry `custom: true` are dropped and replaced by the latest `DEFAULT_APP_CONFIG` definitions; entries marked `custom: true` are treated as user-owned and kept verbatim (user wins on id collision, no duplicates). A dangling `defaultModel` / `defaultImageModel` / `defaultMigrationModel` falls back to the factory default, so no reference is ever left pointing at a removed model. `endpoints` are never managed. The sync is idempotent — it only writes when something actually changed. Implemented in `ConfigManager.syncManagedModels`.
|
|
144
|
+
- **`Model` / `ImageModel` gained an optional `custom?: boolean` field** — marks an entry as user-owned so the factory sync leaves it untouched.
|
|
145
|
+
|
|
146
|
+
### ✅ Tests
|
|
147
|
+
|
|
148
|
+
- Added coverage for the model catalog sync: stale non-custom entries replaced, `custom: true` entries preserved, user version winning on id collision without duplication, image models reconciled, dangling default IDs falling back, and idempotency across repeated calls.
|
|
149
|
+
- E2E model IDs updated to the current vendor names (`deepseek-flash`).
|
|
150
|
+
|
|
151
|
+
### 📄 Docs
|
|
152
|
+
|
|
153
|
+
- Current-version references in `docs/zh` and `docs/en` updated to `1.0.0-alpha.1`.
|
|
154
|
+
- `DEFAULT_APP_CONFIG` row in `sdk-design-v0.md` updated to the new model catalog.
|
|
155
|
+
|
|
3
156
|
## [1.0.0-alpha.0] - 2026-09-30
|
|
4
157
|
|
|
5
158
|
### 💥 Breaking Changes
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ Desktop ──┘ │
|
|
|
21
21
|
types ← pure types, zero business dependencies (incl. ToolEnv)
|
|
22
22
|
config ← ConfigManager + constants: config.json read/write + directory setup + factory defaults
|
|
23
23
|
crud ← capability-entity CRUD (Agent definitions; conversations/drafts are persisted by each consumer)
|
|
24
|
-
runtime ← model factory + Agent assembly + task migration (createModel / createAgent / SdkAgent /
|
|
24
|
+
runtime ← model factory + Agent assembly + task handoff/migration (createModel / createAgent / SdkAgent / HandoffService / HandoffGuardPlugin)
|
|
25
25
|
scope ← Scope orchestration container + ScopePlugin contract + PermissionEvaluator / disclosure + plugins/ (5 self-contained capability sources: discovery + tools + plugin)
|
|
26
26
|
agent-plugins ← Agent plugins (autoMigrate, autoRefreshTools, contextGuard, unknownToolHint)
|
|
27
27
|
shared ← logging, errors
|
|
@@ -68,8 +68,9 @@ const scope = new Scope({
|
|
|
68
68
|
await scope.init();
|
|
69
69
|
|
|
70
70
|
const agent = await createAgent(scope, "my-agent");
|
|
71
|
-
const
|
|
72
|
-
agent.use(new
|
|
71
|
+
const handoffService = new HandoffService({ handoffDir: "/work/.ai-zen/handoffs", skillDirs });
|
|
72
|
+
agent.use(new ContextGuardPlugin({ maxTokens, isSuspended: () => handoffService.busy }));
|
|
73
|
+
agent.use(new AutoMigratePlugin({ service: handoffService, maxTokens }));
|
|
73
74
|
agent.use(new AutoRefreshToolsPlugin());
|
|
74
75
|
agent.use(new UnknownToolHintPlugin({ scope }));
|
|
75
76
|
await agent.init();
|
|
@@ -97,21 +98,21 @@ All built-in tools are classes (extending `SdkCallbackTool`), instantiated by th
|
|
|
97
98
|
| Tool | Description |
|
|
98
99
|
|------|-------------|
|
|
99
100
|
| `cwd` | Get the current working directory |
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
101
|
+
| `read` | Read a file (optional `range` for line/column slicing; oversized output warns and suggests batched reads) |
|
|
102
|
+
| `inspect_file` | Inspect a file's structural overview (line count, column distribution, etc.); streamed scan, not limited by the 300KB read threshold |
|
|
103
|
+
| `write` | Write a file |
|
|
103
104
|
| `exec` | Execute a command (supports `timeout`; oversized stdout+stderr is dumped to `stdout.log` / `stderr.log`) |
|
|
104
|
-
| `
|
|
105
|
+
| `spawn` | Execute a command asynchronously, returns immediately without waiting |
|
|
105
106
|
| `mkdir` | Create a directory |
|
|
106
107
|
| `rm` | Delete a file or directory |
|
|
107
108
|
| `glob` | Scan and find files using glob patterns (oversized output dumped to `result.json`) |
|
|
108
109
|
| `ls` | List directory contents (oversized output dumped to `result.json`) |
|
|
109
110
|
| `exist` | Check whether a file or directory exists |
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
111
|
+
| `find_text` | Search for text or regex in files (oversized output dumped to `result.json`) |
|
|
112
|
+
| `download_file` | Download a file from a URL and save it locally |
|
|
112
113
|
| `rename` | Rename or move a file/directory |
|
|
113
114
|
| `copy` | Copy a file or directory |
|
|
114
|
-
| `
|
|
115
|
+
| `batch_edit` | Batch-edit file text (only unmatched items are echoed back; successful ones are counted) |
|
|
115
116
|
| `edit` | Edit text in a file |
|
|
116
117
|
| `sleep` | Wait for a specified number of milliseconds |
|
|
117
118
|
|
|
@@ -119,16 +120,16 @@ Conditionally injected based on the active model / config:
|
|
|
119
120
|
|
|
120
121
|
| Tool | Injection Condition | Description |
|
|
121
122
|
|------|---------------------|-------------|
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
123
|
+
| `generate_image` | Only when `defaultImageModel` is configured | Generate an image from a text description |
|
|
124
|
+
| `view_image` | Only for vision models (the agent's `modelId` resolves to a model with `vision: true`) | View / analyze an image: local images are auto-uploaded via the Files API, network URLs are referenced directly |
|
|
124
125
|
|
|
125
|
-
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), `
|
|
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).
|
|
126
127
|
|
|
127
128
|
## Built-in Plugins
|
|
128
129
|
|
|
129
130
|
| Plugin | Description |
|
|
130
131
|
|--------|-------------|
|
|
131
|
-
| `AutoMigratePlugin` | Automatically triggers task migration when the context overflows; delegates the actual migration to the injected `
|
|
132
|
+
| `AutoMigratePlugin` | Automatically triggers task migration when the context overflows; delegates the actual migration to the injected `HandoffService` (history handled per `strategy`: default `omit` keeps it auditable, optional `prune` drops it). `resolveMode` lets the caller pick the handoff executor or skip the round. Steps aside while `service.busy` to avoid the handoff→migrate→handoff recursion |
|
|
132
133
|
| `AutoRefreshToolsPlugin` | Re-scans the file system before each `send()` to refresh the tool list |
|
|
133
134
|
| `ContextGuardPlugin` | Context safety guard — before each request, throws `ContextOverflowError` (interrupting the conversation) when the previous round's `usage.prompt_tokens` exceeds `maxTokens × ratio` (default 1.5), preventing context runaway from reading oversized files |
|
|
134
135
|
| `UnknownToolHintPlugin` | Smarter unknown-tool hints — when the LLM calls a nonexistent tool, guides it to `call_mcp_tool` / points out permission issues based on MCP config (opt-in via `agent.use`) |
|
package/README.zh.md
CHANGED
|
@@ -20,7 +20,7 @@ Desktop ──┘ │
|
|
|
20
20
|
types ← 纯类型,零业务依赖(含 ToolEnv 工具环境)
|
|
21
21
|
config ← ConfigManager + constants:读写 config.json + 目录初始化 + 出厂默认
|
|
22
22
|
crud ← 能力实体 CRUD(Agent 定义等;会话/草稿已下放给各端自行持久化)
|
|
23
|
-
runtime ← 模型工厂 + Agent 组装 +
|
|
23
|
+
runtime ← 模型工厂 + Agent 组装 + 任务交接/迁移(createModel / createAgent / SdkAgent / HandoffService / HandoffGuardPlugin)
|
|
24
24
|
scope ← Scope 编排容器 + ScopePlugin 契约 + PermissionEvaluator / disclosure + plugins/(5 个自包含能力来源:发现 + 工具 + 插件)
|
|
25
25
|
agent-plugins ← Agent 插件(autoMigrate、autoRefreshTools、contextGuard、unknownToolHint)
|
|
26
26
|
shared ← 日志、错误
|
|
@@ -67,8 +67,9 @@ const scope = new Scope({
|
|
|
67
67
|
await scope.init();
|
|
68
68
|
|
|
69
69
|
const agent = await createAgent(scope, "my-agent");
|
|
70
|
-
const
|
|
71
|
-
agent.use(new
|
|
70
|
+
const handoffService = new HandoffService({ handoffDir: "/work/.ai-zen/handoffs", skillDirs });
|
|
71
|
+
agent.use(new ContextGuardPlugin({ maxTokens, isSuspended: () => handoffService.busy }));
|
|
72
|
+
agent.use(new AutoMigratePlugin({ service: handoffService, maxTokens }));
|
|
72
73
|
agent.use(new AutoRefreshToolsPlugin());
|
|
73
74
|
agent.use(new UnknownToolHintPlugin({ scope }));
|
|
74
75
|
await agent.init();
|
|
@@ -96,21 +97,21 @@ await scope.dispose(); // 断开 MCP、释放插件资源
|
|
|
96
97
|
| 工具 | 说明 |
|
|
97
98
|
|------|------|
|
|
98
99
|
| `cwd` | 获取当前工作目录 |
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
100
|
+
| `read` | 读取文件(可选 `range` 按行列范围读取;输出超限仅警告并提示用 `range` 分批) |
|
|
101
|
+
| `inspect_file` | 勘察文件结构概况(行数、列数分布等),流式扫描不受 300KB 限制 |
|
|
102
|
+
| `write` | 写入文件 |
|
|
102
103
|
| `exec` | 执行命令(支持 `timeout` 超时参数;stdout+stderr 超限时分文件落盘 `stdout.log` / `stderr.log`) |
|
|
103
|
-
| `
|
|
104
|
+
| `spawn` | 异步执行命令,启动后立即返回,不等待结果 |
|
|
104
105
|
| `mkdir` | 创建目录 |
|
|
105
106
|
| `rm` | 删除文件或目录 |
|
|
106
107
|
| `glob` | 使用 glob 模式扫描查找文件(输出超限落盘 `result.json`) |
|
|
107
108
|
| `ls` | 列出目录内容(输出超限落盘 `result.json`) |
|
|
108
109
|
| `exist` | 检查文件或目录是否存在 |
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
110
|
+
| `find_text` | 在文件中搜索文本或正则(输出超限落盘 `result.json`) |
|
|
111
|
+
| `download_file` | 从 URL 下载文件并保存到本地 |
|
|
111
112
|
| `rename` | 重命名或移动文件/目录 |
|
|
112
113
|
| `copy` | 复制文件或目录 |
|
|
113
|
-
| `
|
|
114
|
+
| `batch_edit` | 批量编辑文件文本(仅回显未匹配项,成功项只计数) |
|
|
114
115
|
| `edit` | 编辑文件中的文本 |
|
|
115
116
|
| `sleep` | 等待指定毫秒数后继续 |
|
|
116
117
|
|
|
@@ -118,16 +119,16 @@ await scope.dispose(); // 断开 MCP、释放插件资源
|
|
|
118
119
|
|
|
119
120
|
| 工具 | 注入条件 | 说明 |
|
|
120
121
|
|------|----------|------|
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
122
|
+
| `generate_image` | 配置了 `defaultImageModel` 才注册 | 根据文字描述生成图片 |
|
|
123
|
+
| `view_image` | 仅视觉模型可用(Agent 的 `modelId` 解析为 `vision: true` 的模型) | 查看/分析图片:本地图片自动经 Files API 上传,网络 URL 直接引用 |
|
|
123
124
|
|
|
124
|
-
工具输出保护:`AppConfig.maxToolOutput`(字符数,缺省 32768)是工具输出的统一上限,超限时由各工具自行处置——`exec` 分文件落盘 `stdout.log` / `stderr.log`(返回各流头尾预览),`
|
|
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)。
|
|
125
126
|
|
|
126
127
|
## 内置插件
|
|
127
128
|
|
|
128
129
|
| 插件 | 说明 |
|
|
129
130
|
|------|------|
|
|
130
|
-
| `AutoMigratePlugin` |
|
|
131
|
+
| `AutoMigratePlugin` | 上下文超限时自动触发任务迁移(历史按 `strategy` 处理:默认 `omit` 标记保留可审计,可选 `prune` 物理剔除),委托注入的 `HandoffService`;`resolveMode` 让调用方决定交接执行者或跳过本轮;`service.busy` 期间让行,避免「交接→迁移→交接」递归 |
|
|
131
132
|
| `AutoRefreshToolsPlugin` | 每次 `send()` 前重新扫描文件系统,刷新工具列表 |
|
|
132
133
|
| `ContextGuardPlugin` | 上下文安全护栏 — 每轮发请求前检测上一轮 `usage.prompt_tokens`,超过 `maxTokens × ratio`(默认 1.5,即 +50%)时抛 `ContextOverflowError` 中断对话,防止读入超大文件导致上下文失控 |
|
|
133
134
|
| `UnknownToolHintPlugin` | 未知工具智能提示 — LLM 调用不存在的工具时,根据 MCP 配置引导使用 `call_mcp_tool` / 提示权限问题(调用方显式 `agent.use` 注册) |
|
|
@@ -1,23 +1,49 @@
|
|
|
1
1
|
import type { AgentPlugin, SendContext } from "@ai-zen/agents-core";
|
|
2
|
-
import {
|
|
2
|
+
import type { HandoffMode, HandoffService } from "../runtime/HandoffService.js";
|
|
3
|
+
/** 触发迁移时的用量信息(供执行者选择、确认文案使用) */
|
|
4
|
+
export interface AutoMigrateTriggerInfo {
|
|
5
|
+
/** 当前 prompt token 用量 */
|
|
6
|
+
promptTokens: number;
|
|
7
|
+
/** 上下文阈值(当前模型的 maxContextTokens) */
|
|
8
|
+
maxTokens: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 迁移执行者解析器:只负责「用什么方式交接」,不负责「何时迁移」。
|
|
12
|
+
*
|
|
13
|
+
* - 返回 `HandoffMode` → 用该执行者迁移;
|
|
14
|
+
* - 返回 `null` → 跳过本次迁移(例如用户拒绝);
|
|
15
|
+
* - 未提供 → 使用 `HandoffService` 构造时的默认执行者。
|
|
16
|
+
*/
|
|
17
|
+
export type AutoMigrateModeResolver = (info: AutoMigrateTriggerInfo) => HandoffMode | null | Promise<HandoffMode | null>;
|
|
3
18
|
export interface AutoMigrateOptions {
|
|
4
|
-
/**
|
|
5
|
-
service:
|
|
19
|
+
/** 交接服务实例(持有交接前后钩子;编排 handoff / migrate 两条链路) */
|
|
20
|
+
service: HandoffService;
|
|
6
21
|
/** 触发迁移的上下文阈值 */
|
|
7
22
|
maxTokens: number;
|
|
23
|
+
/**
|
|
24
|
+
* 执行者解析(可选)。上层可在此弹确认框、读用户偏好,
|
|
25
|
+
* 或直接返回 `null` 表达「本次不迁移」——**无需**再继承本插件。
|
|
26
|
+
*/
|
|
27
|
+
resolveMode?: AutoMigrateModeResolver;
|
|
8
28
|
}
|
|
9
29
|
/**
|
|
10
|
-
* 自动迁移插件
|
|
30
|
+
* 自动迁移插件 —— 只负责「何时触发」,实际迁移统一委托给持有的 `HandoffService`。
|
|
11
31
|
*
|
|
12
|
-
* 当
|
|
13
|
-
* 唯一运行时参数,其余(模型、迁移前后钩子)已由服务在构造时持有。
|
|
32
|
+
* 当 `usage.prompt_tokens` 超过 maxTokens 时触发迁移:
|
|
14
33
|
*
|
|
15
34
|
* ```ts
|
|
16
35
|
* agent.use(new AutoMigratePlugin({
|
|
17
|
-
* service:
|
|
36
|
+
* service: handoffService,
|
|
18
37
|
* maxTokens: 250_000,
|
|
38
|
+
* resolveMode: async ({ promptTokens, maxTokens }) =>
|
|
39
|
+
* (await askUser(promptTokens, maxTokens)) ? "self" : null,
|
|
19
40
|
* }));
|
|
20
41
|
* ```
|
|
42
|
+
*
|
|
43
|
+
* 两层让行(缺一不可):
|
|
44
|
+
* - `service.busy`:交接回合本身就是一次 `send()`,其 `onAfterSend` 会再次到这里;
|
|
45
|
+
* 不跳过就会「交接触发迁移 → 迁移再交接」无限递归;
|
|
46
|
+
* - 交接回合结束后的用量也仍可能超阈值,故 busy 判断必须覆盖整个交接 + 迁移过程。
|
|
21
47
|
*/
|
|
22
48
|
export declare class AutoMigratePlugin implements AgentPlugin {
|
|
23
49
|
private options;
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { getLogger } from "../shared/logger.js";
|
|
2
2
|
const log = getLogger();
|
|
3
3
|
/**
|
|
4
|
-
* 自动迁移插件
|
|
4
|
+
* 自动迁移插件 —— 只负责「何时触发」,实际迁移统一委托给持有的 `HandoffService`。
|
|
5
5
|
*
|
|
6
|
-
* 当
|
|
7
|
-
* 唯一运行时参数,其余(模型、迁移前后钩子)已由服务在构造时持有。
|
|
6
|
+
* 当 `usage.prompt_tokens` 超过 maxTokens 时触发迁移:
|
|
8
7
|
*
|
|
9
8
|
* ```ts
|
|
10
9
|
* agent.use(new AutoMigratePlugin({
|
|
11
|
-
* service:
|
|
10
|
+
* service: handoffService,
|
|
12
11
|
* maxTokens: 250_000,
|
|
12
|
+
* resolveMode: async ({ promptTokens, maxTokens }) =>
|
|
13
|
+
* (await askUser(promptTokens, maxTokens)) ? "self" : null,
|
|
13
14
|
* }));
|
|
14
15
|
* ```
|
|
16
|
+
*
|
|
17
|
+
* 两层让行(缺一不可):
|
|
18
|
+
* - `service.busy`:交接回合本身就是一次 `send()`,其 `onAfterSend` 会再次到这里;
|
|
19
|
+
* 不跳过就会「交接触发迁移 → 迁移再交接」无限递归;
|
|
20
|
+
* - 交接回合结束后的用量也仍可能超阈值,故 busy 判断必须覆盖整个交接 + 迁移过程。
|
|
15
21
|
*/
|
|
16
22
|
export class AutoMigratePlugin {
|
|
17
23
|
options;
|
|
@@ -20,14 +26,22 @@ export class AutoMigratePlugin {
|
|
|
20
26
|
}
|
|
21
27
|
async onAfterSend(ctx) {
|
|
22
28
|
const agent = ctx.agent;
|
|
23
|
-
const { service, maxTokens } = this.options;
|
|
29
|
+
const { service, maxTokens, resolveMode } = this.options;
|
|
30
|
+
// 交接/迁移进行中:让行(防递归)
|
|
31
|
+
if (service.busy)
|
|
32
|
+
return;
|
|
24
33
|
const promptTokens = agent.lastUsage?.prompt_tokens;
|
|
25
34
|
if (promptTokens == null)
|
|
26
35
|
return;
|
|
27
36
|
if (promptTokens <= maxTokens)
|
|
28
37
|
return;
|
|
29
38
|
try {
|
|
30
|
-
|
|
39
|
+
const mode = resolveMode
|
|
40
|
+
? await resolveMode({ promptTokens, maxTokens })
|
|
41
|
+
: undefined;
|
|
42
|
+
if (mode === null)
|
|
43
|
+
return; // 用户选择跳过本次迁移
|
|
44
|
+
await service.migrate({ agent, promptTokens, maxTokens, mode: mode ?? undefined });
|
|
31
45
|
}
|
|
32
46
|
catch (err) {
|
|
33
47
|
log.error(`[autoMigrate] 迁移失败: ${err?.message ?? err}`);
|
|
@@ -7,6 +7,15 @@ export interface ContextGuardOptions {
|
|
|
7
7
|
* 在请求前抛出 ContextOverflowError 中断对话。默认 1.5(即 +50%)。
|
|
8
8
|
*/
|
|
9
9
|
ratio?: number;
|
|
10
|
+
/**
|
|
11
|
+
* 是否处于「需要放宽」的阶段(例如交接回合)。返回 true 时改用 `suspendedRatio`。
|
|
12
|
+
*
|
|
13
|
+
* 为什么需要:交接恰好发生在上下文最满的时刻,而交接回合本身还要再发 1~2 次请求。
|
|
14
|
+
* 若仍按 1.5 倍判定,正常交接会被护栏误杀;完全让行又会失去熔断,故改为放宽而非放行。
|
|
15
|
+
*/
|
|
16
|
+
isSuspended?: () => boolean;
|
|
17
|
+
/** 放宽后的比例,默认 2.0(即 maxTokens × 2) */
|
|
18
|
+
suspendedRatio?: number;
|
|
10
19
|
}
|
|
11
20
|
/**
|
|
12
21
|
* 上下文安全护栏插件。
|
|
@@ -18,13 +27,14 @@ export interface ContextGuardOptions {
|
|
|
18
27
|
* 与迁移插件职责分离:
|
|
19
28
|
* - ContextGuardPlugin 只做「严重超限即中断」的安全兜底,绝不继续对话/迁移;
|
|
20
29
|
* - AutoMigratePlugin 在正常范围内(超 maxTokens 但未达硬上限)做交接迁移。
|
|
30
|
+
* - 交接回合由 `isSuspended` 放宽阈值(而非完全让行),保证交接不被误杀、又保留熔断。
|
|
21
31
|
*
|
|
22
32
|
* ```ts
|
|
23
|
-
* agent.use(new ContextGuardPlugin({
|
|
24
|
-
* agent.use(new AutoMigratePlugin({
|
|
25
|
-
* service: new TaskMigrationService({ onMigrated }),
|
|
33
|
+
* agent.use(new ContextGuardPlugin({
|
|
26
34
|
* maxTokens: 250_000,
|
|
35
|
+
* isSuspended: () => handoffService.busy,
|
|
27
36
|
* }));
|
|
37
|
+
* agent.use(new AutoMigratePlugin({ service: handoffService, maxTokens: 250_000 }));
|
|
28
38
|
* ```
|
|
29
39
|
*/
|
|
30
40
|
export declare class ContextGuardPlugin implements AgentPlugin {
|
|
@@ -9,13 +9,14 @@ import { ContextOverflowError } from "../shared/errors.js";
|
|
|
9
9
|
* 与迁移插件职责分离:
|
|
10
10
|
* - ContextGuardPlugin 只做「严重超限即中断」的安全兜底,绝不继续对话/迁移;
|
|
11
11
|
* - AutoMigratePlugin 在正常范围内(超 maxTokens 但未达硬上限)做交接迁移。
|
|
12
|
+
* - 交接回合由 `isSuspended` 放宽阈值(而非完全让行),保证交接不被误杀、又保留熔断。
|
|
12
13
|
*
|
|
13
14
|
* ```ts
|
|
14
|
-
* agent.use(new ContextGuardPlugin({
|
|
15
|
-
* agent.use(new AutoMigratePlugin({
|
|
16
|
-
* service: new TaskMigrationService({ onMigrated }),
|
|
15
|
+
* agent.use(new ContextGuardPlugin({
|
|
17
16
|
* maxTokens: 250_000,
|
|
17
|
+
* isSuspended: () => handoffService.busy,
|
|
18
18
|
* }));
|
|
19
|
+
* agent.use(new AutoMigratePlugin({ service: handoffService, maxTokens: 250_000 }));
|
|
19
20
|
* ```
|
|
20
21
|
*/
|
|
21
22
|
export class ContextGuardPlugin {
|
|
@@ -25,13 +26,15 @@ export class ContextGuardPlugin {
|
|
|
25
26
|
}
|
|
26
27
|
async onInnerLoopStart(ctx) {
|
|
27
28
|
const { agent } = ctx;
|
|
28
|
-
const { maxTokens, ratio = 1.5 } = this.options;
|
|
29
|
+
const { maxTokens, ratio = 1.5, isSuspended, suspendedRatio = 2 } = this.options;
|
|
29
30
|
// 首轮请求前尚无用量数据,跳过(只能在发出首轮请求、拿到 usage 后才有据可查)
|
|
30
31
|
const promptTokens = agent.lastUsage?.prompt_tokens;
|
|
31
32
|
if (promptTokens == null)
|
|
32
33
|
return;
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
// 交接回合等需要放宽的阶段:放宽阈值但保留熔断
|
|
35
|
+
const effectiveRatio = isSuspended?.() ? suspendedRatio : ratio;
|
|
36
|
+
if (promptTokens > maxTokens * effectiveRatio) {
|
|
37
|
+
throw new ContextOverflowError(promptTokens, maxTokens, effectiveRatio);
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
}
|
|
@@ -18,6 +18,11 @@ export declare class ConfigManager {
|
|
|
18
18
|
ensureDirs(): Promise<void>;
|
|
19
19
|
/**
|
|
20
20
|
* 确保 config.json 存在。不存在时写入出厂默认配置 DSL。
|
|
21
|
+
*
|
|
22
|
+
* 已存在时执行「出厂模型清单同步」(见 syncManagedModels):
|
|
23
|
+
* models / imageModels 中凡是**没有** `custom: true` 的条目一律视为出厂托管,
|
|
24
|
+
* 会被移除并替换为 DEFAULT_APP_CONFIG 中的最新定义;标了 `custom: true` 的
|
|
25
|
+
* 条目视为用户自有,原样保留。同步结果与磁盘内容一致时不写盘。
|
|
21
26
|
*/
|
|
22
27
|
ensureDefaultConfig(): Promise<AppConfig>;
|
|
23
28
|
/**
|
|
@@ -47,10 +52,21 @@ export declare class ConfigManager {
|
|
|
47
52
|
agent: AgentDefinition | null;
|
|
48
53
|
subAgent: AgentDefinition | null;
|
|
49
54
|
}>;
|
|
55
|
+
/**
|
|
56
|
+
* 释放 / 同步出厂 Skill。
|
|
57
|
+
*
|
|
58
|
+
* 覆盖策略与 `syncManagedModels` 同构:
|
|
59
|
+
* - 磁盘上不存在 → 写入出厂内容;
|
|
60
|
+
* - 存在且 frontmatter 标了 `custom: "true"` → 用户自有,原样保留;
|
|
61
|
+
* - 存在但未标 → 视为出厂托管,同步为当前版本内容(内容相同则不写盘)。
|
|
62
|
+
*
|
|
63
|
+
* @returns 实际写入的 Skill id 列表(内容未变化 / 用户自有 均不计入)
|
|
64
|
+
*/
|
|
65
|
+
ensureFactorySkills(): Promise<string[]>;
|
|
50
66
|
/** mcp.json 路径:{basePath}/mcp.json */
|
|
51
67
|
get mcpPath(): string;
|
|
52
68
|
/**
|
|
53
|
-
* 确保 basePath/mcp.json 存在。不存在时写入出厂默认 MCP 配置(含 socket-pty)。
|
|
69
|
+
* 确保 basePath/mcp.json 存在。不存在时写入出厂默认 MCP 配置(含 socket-pty 与 chrome-devtools)。
|
|
54
70
|
* 已有文件不被覆盖,尊重用户已配置的 MCP 服务器。
|
|
55
71
|
* @returns 返回当前生效的 MCP 配置原始内容
|
|
56
72
|
*/
|
|
@@ -70,4 +86,16 @@ export declare class ConfigManager {
|
|
|
70
86
|
/** 原子写 JSON 文件(先写 .tmp 再 rename,避免半成品)。 */
|
|
71
87
|
private writeJson;
|
|
72
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* 同步出厂托管的模型清单(与默认 Agent 的 custom 机制一致)。
|
|
91
|
+
*
|
|
92
|
+
* 规则:
|
|
93
|
+
* - 未标 `custom: true` 的条目 → 由 SDK 托管,从结果中移除,改用 defaults 中的最新定义;
|
|
94
|
+
* - 标了 `custom: true` 的条目 → 用户自有,原样保留;与出厂定义同 id 时用户版本优先;
|
|
95
|
+
* - 默认模型 ID(defaultModel / defaultImageModel / defaultMigrationModel)
|
|
96
|
+
* 在合并后若已不存在 → 回退到出厂默认,避免悬空引用。
|
|
97
|
+
*
|
|
98
|
+
* 端点(endpoints)不参与托管,始终保持用户配置。
|
|
99
|
+
*/
|
|
100
|
+
export declare function syncManagedModels(config: AppConfig): AppConfig;
|
|
73
101
|
export { DEFAULT_AGENT_ID, DEFAULT_AGENT_DEFINITION, DEFAULT_SUBAGENT_ID, DEFAULT_SUBAGENT_DEFINITION, DEFAULT_APP_CONFIG, DEFAULT_MCP_CONFIG, CONFIG_SUB_DIRS, } from "./constants.js";
|