@ai-zen/agents-sdk 0.5.2 → 0.5.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 +12 -0
- package/dist/capabilities/discovery/mcp.js +1 -0
- package/dist/capabilities/implements/mcpTools.js +6 -1
- package/dist/config/ConfigManager.d.ts +24 -2
- package/dist/config/ConfigManager.js +68 -3
- package/dist/config/constants.d.ts +9 -0
- package/dist/config/constants.js +19 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -2
- package/dist/plugin/ContextGuardPlugin.d.ts +34 -0
- package/dist/plugin/ContextGuardPlugin.js +37 -0
- package/dist/shared/errors.d.ts +16 -0
- package/dist/shared/errors.js +25 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.3] - 2026-08-05
|
|
4
|
+
|
|
5
|
+
### 🚀 新功能
|
|
6
|
+
|
|
7
|
+
- **初始化时默认释放含 socket-pty 的 mcp.json** — `ConfigManager.bootstrap()` 新增 `ensureDefaultMcpConfig()`,首启在 `~/.ai-zen/mcp.json` 写入默认 MCP 配置(含 socket-pty 终端 server,`command: npx -y @ai-zen/socket-pty mcp`),文件已存在则幂等不覆盖;新增 `readMcpConfig()` / `writeMcpConfig()` 读写方法;新增并导出 `DEFAULT_MCP_CONFIG` 常量
|
|
8
|
+
- **`load_mcp` 透传 server description** — `McpServerConfig` 新增 `description?` 字段,`discoverMcpServers` 解析不再丢弃;`load_mcp` 的 `server` 参数枚举按 `- {id}: {description}` 拼接各 server 说明供 LLM 参考(与 `load_skill` 同构)
|
|
9
|
+
- **新增 `ContextGuardPlugin` 上下文安全护栏** — 在每次内循环**发请求前**(`onInnerLoopStart`,Core 中位于 try 块外)检测上一轮 `usage.prompt_tokens`,超过 `maxTokens × ratio`(默认 1.2,即超阈 20%)时抛出 `ContextOverflowError` 中断对话,防止读入超大文件导致上下文失控。与 `AutoMigratePlugin` 职责分离、区间互补;无需改动 Core
|
|
10
|
+
|
|
11
|
+
### 🆕 新增导出
|
|
12
|
+
|
|
13
|
+
- `DEFAULT_MCP_CONFIG`(constants)、`ContextGuardPlugin`、`ContextOverflowError`
|
|
14
|
+
|
|
3
15
|
## [0.5.2] - 2026-08-03
|
|
4
16
|
|
|
5
17
|
### 🚀 新功能
|
|
@@ -16,6 +16,11 @@ export function createLoadMcpTool(mcpManager, filteredMcps) {
|
|
|
16
16
|
}
|
|
17
17
|
const ids = filteredMcps.map((s) => s.id);
|
|
18
18
|
const param = createDisclosureParam(ids, "选择一个 MCP 服务器", EMPTY_HINT);
|
|
19
|
+
// 拼接各 MCP 服务器的描述供 LLM 参考(对齐 load_skill 的处理方式)
|
|
20
|
+
const mcpDescriptions = filteredMcps
|
|
21
|
+
.map((s) => ` - ${s.id}: ${s.description || "无描述"}`)
|
|
22
|
+
.join("\n");
|
|
23
|
+
const serverIdDescription = `${param.description}\n\n各 MCP 服务器说明:\n${mcpDescriptions || " 无可用 MCP 服务器"}`;
|
|
19
24
|
return new CallbackTool({
|
|
20
25
|
function: {
|
|
21
26
|
name: "load_mcp",
|
|
@@ -25,7 +30,7 @@ export function createLoadMcpTool(mcpManager, filteredMcps) {
|
|
|
25
30
|
properties: {
|
|
26
31
|
server: {
|
|
27
32
|
type: "string",
|
|
28
|
-
description:
|
|
33
|
+
description: serverIdDescription,
|
|
29
34
|
...(param.enum ? { enum: param.enum } : {}),
|
|
30
35
|
},
|
|
31
36
|
},
|
|
@@ -37,7 +37,7 @@ export declare class ConfigManager {
|
|
|
37
37
|
*/
|
|
38
38
|
ensureDefaultSubAgent(): Promise<AgentDefinition | null>;
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
40
|
+
* 一对初始化:目录 + config.json + 默认 Agent + 默认 SubAgent + 默认 MCP。
|
|
41
41
|
* 已有文件不会被覆盖。
|
|
42
42
|
*/
|
|
43
43
|
bootstrap(): Promise<{
|
|
@@ -45,5 +45,27 @@ export declare class ConfigManager {
|
|
|
45
45
|
agent: AgentDefinition | null;
|
|
46
46
|
subAgent: AgentDefinition | null;
|
|
47
47
|
}>;
|
|
48
|
+
/** mcp.json 路径:{basePath}/mcp.json */
|
|
49
|
+
get mcpPath(): string;
|
|
50
|
+
/**
|
|
51
|
+
* 确保 basePath/mcp.json 存在。不存在时写入出厂默认 MCP 配置(含 socket-pty)。
|
|
52
|
+
* 已有文件不被覆盖,尊重用户已配置的 MCP 服务器。
|
|
53
|
+
* @returns 返回当前生效的 MCP 配置原始内容
|
|
54
|
+
*/
|
|
55
|
+
ensureDefaultMcpConfig(): Promise<Record<string, unknown>>;
|
|
56
|
+
/**
|
|
57
|
+
* 读取 basePath/mcp.json,不存在时返回空结构。
|
|
58
|
+
*/
|
|
59
|
+
readMcpConfig(): Promise<{
|
|
60
|
+
mcpServers: Record<string, unknown>;
|
|
61
|
+
}>;
|
|
62
|
+
/**
|
|
63
|
+
* 原子写入 mcp.json。
|
|
64
|
+
*/
|
|
65
|
+
writeMcpConfig(config: {
|
|
66
|
+
mcpServers: Record<string, unknown>;
|
|
67
|
+
}): Promise<void>;
|
|
68
|
+
/** 原子写 JSON 文件(先写 .tmp 再 rename,避免半成品)。 */
|
|
69
|
+
private writeJson;
|
|
48
70
|
}
|
|
49
|
-
export { DEFAULT_AGENT_ID, DEFAULT_AGENT_DEFINITION, DEFAULT_SUBAGENT_ID, DEFAULT_SUBAGENT_DEFINITION, DEFAULT_APP_CONFIG, CONFIG_SUB_DIRS, } from "./constants.js";
|
|
71
|
+
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";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
-
import { DEFAULT_AGENT_ID, DEFAULT_AGENT_DEFINITION, DEFAULT_SUBAGENT_ID, DEFAULT_SUBAGENT_DEFINITION, DEFAULT_APP_CONFIG, CONFIG_SUB_DIRS, } from "./constants.js";
|
|
3
|
+
import { DEFAULT_AGENT_ID, DEFAULT_AGENT_DEFINITION, DEFAULT_SUBAGENT_ID, DEFAULT_SUBAGENT_DEFINITION, DEFAULT_APP_CONFIG, DEFAULT_MCP_CONFIG, CONFIG_SUB_DIRS, } from "./constants.js";
|
|
4
4
|
/**
|
|
5
5
|
* 配置管理器 — 负责配置文件的读写、目录初始化、默认实体创建。
|
|
6
6
|
*/
|
|
@@ -143,7 +143,7 @@ export class ConfigManager {
|
|
|
143
143
|
return definition;
|
|
144
144
|
}
|
|
145
145
|
/**
|
|
146
|
-
*
|
|
146
|
+
* 一对初始化:目录 + config.json + 默认 Agent + 默认 SubAgent + 默认 MCP。
|
|
147
147
|
* 已有文件不会被覆盖。
|
|
148
148
|
*/
|
|
149
149
|
async bootstrap() {
|
|
@@ -151,7 +151,72 @@ export class ConfigManager {
|
|
|
151
151
|
const config = await this.ensureDefaultConfig();
|
|
152
152
|
const agent = await this.ensureDefaultAgent();
|
|
153
153
|
const subAgent = await this.ensureDefaultSubAgent();
|
|
154
|
+
await this.ensureDefaultMcpConfig();
|
|
154
155
|
return { config, agent, subAgent };
|
|
155
156
|
}
|
|
157
|
+
// -----------------------------------------------------------------------
|
|
158
|
+
// MCP 配置(~/.ai-zen/mcp.json)
|
|
159
|
+
// -----------------------------------------------------------------------
|
|
160
|
+
/** mcp.json 路径:{basePath}/mcp.json */
|
|
161
|
+
get mcpPath() {
|
|
162
|
+
return join(this.basePath, "mcp.json");
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 确保 basePath/mcp.json 存在。不存在时写入出厂默认 MCP 配置(含 socket-pty)。
|
|
166
|
+
* 已有文件不被覆盖,尊重用户已配置的 MCP 服务器。
|
|
167
|
+
* @returns 返回当前生效的 MCP 配置原始内容
|
|
168
|
+
*/
|
|
169
|
+
async ensureDefaultMcpConfig() {
|
|
170
|
+
const mcpPath = this.mcpPath;
|
|
171
|
+
try {
|
|
172
|
+
await fs.access(mcpPath);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// 不存在 → 写入默认
|
|
176
|
+
await this.ensureDirs();
|
|
177
|
+
await this.writeJson(mcpPath, DEFAULT_MCP_CONFIG);
|
|
178
|
+
return { ...DEFAULT_MCP_CONFIG };
|
|
179
|
+
}
|
|
180
|
+
// 已存在 → 不覆盖,读取返回
|
|
181
|
+
return JSON.parse(await fs.readFile(mcpPath, "utf-8"));
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 读取 basePath/mcp.json,不存在时返回空结构。
|
|
185
|
+
*/
|
|
186
|
+
async readMcpConfig() {
|
|
187
|
+
const mcpPath = this.mcpPath;
|
|
188
|
+
try {
|
|
189
|
+
await fs.access(mcpPath);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return { mcpServers: {} };
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
return JSON.parse(await fs.readFile(mcpPath, "utf-8"));
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return { mcpServers: {} };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* 原子写入 mcp.json。
|
|
203
|
+
*/
|
|
204
|
+
async writeMcpConfig(config) {
|
|
205
|
+
await this.ensureDirs();
|
|
206
|
+
await this.writeJson(this.mcpPath, config);
|
|
207
|
+
}
|
|
208
|
+
/** 原子写 JSON 文件(先写 .tmp 再 rename,避免半成品)。 */
|
|
209
|
+
async writeJson(path, data) {
|
|
210
|
+
const dir = dirname(path);
|
|
211
|
+
try {
|
|
212
|
+
await fs.access(dir);
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
await fs.mkdir(dir, { recursive: true });
|
|
216
|
+
}
|
|
217
|
+
const tmpPath = path + ".tmp";
|
|
218
|
+
await fs.writeFile(tmpPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
219
|
+
await fs.rename(tmpPath, path);
|
|
220
|
+
}
|
|
156
221
|
}
|
|
157
|
-
export { DEFAULT_AGENT_ID, DEFAULT_AGENT_DEFINITION, DEFAULT_SUBAGENT_ID, DEFAULT_SUBAGENT_DEFINITION, DEFAULT_APP_CONFIG, CONFIG_SUB_DIRS, } from "./constants.js";
|
|
222
|
+
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";
|
|
@@ -9,6 +9,15 @@ export declare const DEFAULT_SUBAGENT_ID = "sub-agent-default";
|
|
|
9
9
|
export declare const DEFAULT_SUBAGENT_DEFINITION: Omit<AgentDefinition, "createdAt" | "updatedAt">;
|
|
10
10
|
/** SDK 出厂默认 AppConfig。CLI/Desktop 首次初始化时使用。 */
|
|
11
11
|
export declare const DEFAULT_APP_CONFIG: AppConfig;
|
|
12
|
+
/**
|
|
13
|
+
* SDK 出厂默认 MCP 服务器配置(mcp.json 内容,业界标准格式)。
|
|
14
|
+
* 首次初始化时释放到 ~/.ai-zen/mcp.json,让用户开箱即用 socket-pty 终端能力。
|
|
15
|
+
*
|
|
16
|
+
* 若文件已存在则不覆盖(尊重用户已有配置)。
|
|
17
|
+
*/
|
|
18
|
+
export declare const DEFAULT_MCP_CONFIG: {
|
|
19
|
+
mcpServers: Record<string, unknown>;
|
|
20
|
+
};
|
|
12
21
|
/**
|
|
13
22
|
* 标准共享子目录列表(不包含运行时目录)。
|
|
14
23
|
*
|
package/dist/config/constants.js
CHANGED
|
@@ -179,6 +179,25 @@ export const DEFAULT_APP_CONFIG = {
|
|
|
179
179
|
defaultMigrationModel: "deepseek-v4-flash",
|
|
180
180
|
};
|
|
181
181
|
// ---------------------------------------------------------------------------
|
|
182
|
+
// 默认 MCP 配置(socket-pty 终端 MCP)
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
/**
|
|
185
|
+
* SDK 出厂默认 MCP 服务器配置(mcp.json 内容,业界标准格式)。
|
|
186
|
+
* 首次初始化时释放到 ~/.ai-zen/mcp.json,让用户开箱即用 socket-pty 终端能力。
|
|
187
|
+
*
|
|
188
|
+
* 若文件已存在则不覆盖(尊重用户已有配置)。
|
|
189
|
+
*/
|
|
190
|
+
export const DEFAULT_MCP_CONFIG = {
|
|
191
|
+
mcpServers: {
|
|
192
|
+
"socket-pty": {
|
|
193
|
+
type: "stdio",
|
|
194
|
+
command: "npx",
|
|
195
|
+
args: ["-y", "@ai-zen/socket-pty", "mcp"],
|
|
196
|
+
description: "可托管的伪终端(pty):spawn/read/wait/write/resize/status/kill",
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
182
201
|
// 目录
|
|
183
202
|
// ---------------------------------------------------------------------------
|
|
184
203
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { discoverSkills, readSkill } from "./capabilities/discovery/skills.js";
|
|
|
9
9
|
export type { SkillInfo, Frontmatter } from "./capabilities/discovery/skills.js";
|
|
10
10
|
export { discoverMcpServers } from "./capabilities/discovery/mcp.js";
|
|
11
11
|
export { discoverUserTools } from "./capabilities/discovery/usertools.js";
|
|
12
|
-
export { ConfigManager, DEFAULT_AGENT_ID, DEFAULT_AGENT_DEFINITION, DEFAULT_SUBAGENT_ID, DEFAULT_SUBAGENT_DEFINITION, DEFAULT_APP_CONFIG, CONFIG_SUB_DIRS, } from "./config/ConfigManager.js";
|
|
12
|
+
export { ConfigManager, DEFAULT_AGENT_ID, DEFAULT_AGENT_DEFINITION, DEFAULT_SUBAGENT_ID, DEFAULT_SUBAGENT_DEFINITION, DEFAULT_APP_CONFIG, DEFAULT_MCP_CONFIG, CONFIG_SUB_DIRS, } from "./config/ConfigManager.js";
|
|
13
13
|
export { EntityRepository } from "./shared/EntityRepository.js";
|
|
14
14
|
export { AgentRepository } from "./crud/AgentRepository.js";
|
|
15
15
|
export { Provider } from "./runtime/Provider.js";
|
|
@@ -26,6 +26,8 @@ export type { BuildMigrationAgentOptions } from "./runtime/TaskMigrationService.
|
|
|
26
26
|
export { AutoMigratePlugin } from "./plugin/AutoMigratePlugin.js";
|
|
27
27
|
export type { AutoMigrateOptions } from "./plugin/AutoMigratePlugin.js";
|
|
28
28
|
export { AutoRefreshToolsPlugin } from "./plugin/AutoRefreshToolsPlugin.js";
|
|
29
|
+
export { ContextGuardPlugin } from "./plugin/ContextGuardPlugin.js";
|
|
30
|
+
export type { ContextGuardOptions } from "./plugin/ContextGuardPlugin.js";
|
|
29
31
|
export { BUILTIN_TOOL_CLASSES } from "./capabilities/implements/builtin/index.js";
|
|
30
32
|
export { CwdTool, ReadFileTool, WriteFileTool, ExecTool, MkdirTool, RmTool, GlobTool, LsTool, ExistTool, FindTextTool, DownloadFileTool, RenameTool, CopyTool, BatchEditTool, EditTool, ExecAsyncTool, SleepTool, } from "./capabilities/implements/builtin/index.js";
|
|
31
33
|
export { GenerateImageTool } from "./capabilities/implements/builtin/GenerateImageTool.js";
|
|
@@ -34,4 +36,4 @@ export { createLoadMcpTool, createCallMcpTool, createReadMcpResourceTool } from
|
|
|
34
36
|
export { createSubAgentTool } from "./capabilities/implements/subAgentTools.js";
|
|
35
37
|
export { getLogger, setLogger } from "./shared/logger.js";
|
|
36
38
|
export type { Logger, LogFunctions } from "./shared/logger.js";
|
|
37
|
-
export { SdkError } from "./shared/errors.js";
|
|
39
|
+
export { SdkError, ContextOverflowError } from "./shared/errors.js";
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ export { discoverSkills, readSkill } from "./capabilities/discovery/skills.js";
|
|
|
8
8
|
export { discoverMcpServers } from "./capabilities/discovery/mcp.js";
|
|
9
9
|
export { discoverUserTools } from "./capabilities/discovery/usertools.js";
|
|
10
10
|
// 配置 — ConfigManager
|
|
11
|
-
export { ConfigManager, DEFAULT_AGENT_ID, DEFAULT_AGENT_DEFINITION, DEFAULT_SUBAGENT_ID, DEFAULT_SUBAGENT_DEFINITION, DEFAULT_APP_CONFIG, CONFIG_SUB_DIRS, } from "./config/ConfigManager.js";
|
|
11
|
+
export { ConfigManager, DEFAULT_AGENT_ID, DEFAULT_AGENT_DEFINITION, DEFAULT_SUBAGENT_ID, DEFAULT_SUBAGENT_DEFINITION, DEFAULT_APP_CONFIG, DEFAULT_MCP_CONFIG, CONFIG_SUB_DIRS, } from "./config/ConfigManager.js";
|
|
12
12
|
// CRUD — 实体仓储(仅 Agent 定义等能力实体)
|
|
13
13
|
export { EntityRepository } from "./shared/EntityRepository.js";
|
|
14
14
|
export { AgentRepository } from "./crud/AgentRepository.js";
|
|
@@ -23,6 +23,7 @@ export { TaskMigrationService } from "./runtime/TaskMigrationService.js";
|
|
|
23
23
|
// 插件
|
|
24
24
|
export { AutoMigratePlugin } from "./plugin/AutoMigratePlugin.js";
|
|
25
25
|
export { AutoRefreshToolsPlugin } from "./plugin/AutoRefreshToolsPlugin.js";
|
|
26
|
+
export { ContextGuardPlugin } from "./plugin/ContextGuardPlugin.js";
|
|
26
27
|
// 工具 — 内置工具类 + 动态工具工厂
|
|
27
28
|
export { BUILTIN_TOOL_CLASSES } from "./capabilities/implements/builtin/index.js";
|
|
28
29
|
export { CwdTool, ReadFileTool, WriteFileTool, ExecTool, MkdirTool, RmTool, GlobTool, LsTool, ExistTool, FindTextTool, DownloadFileTool, RenameTool, CopyTool, BatchEditTool, EditTool, ExecAsyncTool, SleepTool, } from "./capabilities/implements/builtin/index.js";
|
|
@@ -32,4 +33,4 @@ export { createLoadMcpTool, createCallMcpTool, createReadMcpResourceTool } from
|
|
|
32
33
|
export { createSubAgentTool } from "./capabilities/implements/subAgentTools.js";
|
|
33
34
|
// 共享
|
|
34
35
|
export { getLogger, setLogger } from "./shared/logger.js";
|
|
35
|
-
export { SdkError } from "./shared/errors.js";
|
|
36
|
+
export { SdkError, ContextOverflowError } from "./shared/errors.js";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AgentPlugin, SendContext } from "../runtime/SdkAgent.js";
|
|
2
|
+
export interface ContextGuardOptions {
|
|
3
|
+
/** 上下文告警阈值(token)。用量超过 maxTokens × ratio 即中断。 */
|
|
4
|
+
maxTokens: number;
|
|
5
|
+
/**
|
|
6
|
+
* 超出比例。用量 > maxTokens × ratio 时判定为「严重超限」(如读入超大文件),
|
|
7
|
+
* 在请求前抛出 ContextOverflowError 中断对话。默认 1.2(即 +20%)。
|
|
8
|
+
*/
|
|
9
|
+
ratio?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 上下文安全护栏插件。
|
|
13
|
+
*
|
|
14
|
+
* 在每次内循环**发请求前**检测上一轮用量(usage.prompt_tokens):
|
|
15
|
+
* - 若用量超过 maxTokens × ratio,说明上下文已严重超限(通常因读入超大文件),
|
|
16
|
+
* 在请求前抛出 ContextOverflowError,**中断对话**,交由上层向用户报错。
|
|
17
|
+
*
|
|
18
|
+
* 与迁移插件职责分离:
|
|
19
|
+
* - ContextGuardPlugin 只做「严重超限即中断」的安全兜底,绝不继续对话/迁移;
|
|
20
|
+
* - AutoMigratePlugin 在正常范围内(超 maxTokens 但未达硬上限)做交接迁移。
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* agent.use(new ContextGuardPlugin({ maxTokens: 250_000 }));
|
|
24
|
+
* agent.use(new AutoMigratePlugin({
|
|
25
|
+
* maxTokens: 250_000,
|
|
26
|
+
* migrationAgent,
|
|
27
|
+
* }));
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare class ContextGuardPlugin implements AgentPlugin {
|
|
31
|
+
private options;
|
|
32
|
+
constructor(options: ContextGuardOptions);
|
|
33
|
+
onInnerLoopStart(ctx: SendContext): Promise<void>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ContextOverflowError } from "../shared/errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* 上下文安全护栏插件。
|
|
4
|
+
*
|
|
5
|
+
* 在每次内循环**发请求前**检测上一轮用量(usage.prompt_tokens):
|
|
6
|
+
* - 若用量超过 maxTokens × ratio,说明上下文已严重超限(通常因读入超大文件),
|
|
7
|
+
* 在请求前抛出 ContextOverflowError,**中断对话**,交由上层向用户报错。
|
|
8
|
+
*
|
|
9
|
+
* 与迁移插件职责分离:
|
|
10
|
+
* - ContextGuardPlugin 只做「严重超限即中断」的安全兜底,绝不继续对话/迁移;
|
|
11
|
+
* - AutoMigratePlugin 在正常范围内(超 maxTokens 但未达硬上限)做交接迁移。
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* agent.use(new ContextGuardPlugin({ maxTokens: 250_000 }));
|
|
15
|
+
* agent.use(new AutoMigratePlugin({
|
|
16
|
+
* maxTokens: 250_000,
|
|
17
|
+
* migrationAgent,
|
|
18
|
+
* }));
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export class ContextGuardPlugin {
|
|
22
|
+
options;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.options = options;
|
|
25
|
+
}
|
|
26
|
+
async onInnerLoopStart(ctx) {
|
|
27
|
+
const { agent } = ctx;
|
|
28
|
+
const { maxTokens, ratio = 1.2 } = this.options;
|
|
29
|
+
// 首轮请求前尚无用量数据,跳过(只能在发出首轮请求、拿到 usage 后才有据可查)
|
|
30
|
+
const promptTokens = agent.lastUsage?.prompt_tokens;
|
|
31
|
+
if (promptTokens == null)
|
|
32
|
+
return;
|
|
33
|
+
if (promptTokens > maxTokens * ratio) {
|
|
34
|
+
throw new ContextOverflowError(promptTokens, maxTokens, ratio);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
package/dist/shared/errors.d.ts
CHANGED
|
@@ -6,3 +6,19 @@ export declare class SdkError extends Error {
|
|
|
6
6
|
readonly code: string;
|
|
7
7
|
constructor(code: string, message: string, cause?: Error);
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* 上下文超限错误。由 ContextGuardPlugin 在请求前抛出,用于中断对话。
|
|
11
|
+
* 触发条件通常是上下文 token 用量远超阈值(如读入超大文件),
|
|
12
|
+
* 继续对话已无意义且会持续放大费用/延迟,故由上层捕获后向用户显式报错。
|
|
13
|
+
*/
|
|
14
|
+
export declare class ContextOverflowError extends Error {
|
|
15
|
+
/** 触发中断时的刚用量(usage.prompt_tokens) */
|
|
16
|
+
readonly promptTokens: number;
|
|
17
|
+
/** 配置的告警阈值(maxTokens) */
|
|
18
|
+
readonly maxTokens: number;
|
|
19
|
+
/** 实际生效的硬上限(maxTokens × ratio,越界即中断) */
|
|
20
|
+
readonly threshold: number;
|
|
21
|
+
/** 超出比例(如 1.2 表示 20%) */
|
|
22
|
+
readonly ratio: number;
|
|
23
|
+
constructor(promptTokens: number, maxTokens: number, ratio: number);
|
|
24
|
+
}
|
package/dist/shared/errors.js
CHANGED
|
@@ -13,3 +13,28 @@ export class SdkError extends Error {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* 上下文超限错误。由 ContextGuardPlugin 在请求前抛出,用于中断对话。
|
|
18
|
+
* 触发条件通常是上下文 token 用量远超阈值(如读入超大文件),
|
|
19
|
+
* 继续对话已无意义且会持续放大费用/延迟,故由上层捕获后向用户显式报错。
|
|
20
|
+
*/
|
|
21
|
+
export class ContextOverflowError extends Error {
|
|
22
|
+
/** 触发中断时的刚用量(usage.prompt_tokens) */
|
|
23
|
+
promptTokens;
|
|
24
|
+
/** 配置的告警阈值(maxTokens) */
|
|
25
|
+
maxTokens;
|
|
26
|
+
/** 实际生效的硬上限(maxTokens × ratio,越界即中断) */
|
|
27
|
+
threshold;
|
|
28
|
+
/** 超出比例(如 1.2 表示 20%) */
|
|
29
|
+
ratio;
|
|
30
|
+
constructor(promptTokens, maxTokens, ratio) {
|
|
31
|
+
const threshold = maxTokens * ratio;
|
|
32
|
+
super(`🛑 上下文严重超限:已用 ${promptTokens} token,超过硬上限 ${threshold}(${Math.round((ratio - 1) * 100)}%,配置上限 ${maxTokens})。` +
|
|
33
|
+
`当前对话可能因读入超大文件而失控,已中断,请检查并重新开始。`);
|
|
34
|
+
this.name = "ContextOverflowError";
|
|
35
|
+
this.promptTokens = promptTokens;
|
|
36
|
+
this.maxTokens = maxTokens;
|
|
37
|
+
this.threshold = threshold;
|
|
38
|
+
this.ratio = ratio;
|
|
39
|
+
}
|
|
40
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -91,6 +91,8 @@ export interface McpServerConfig {
|
|
|
91
91
|
transport: "stdio" | "http" | "sse";
|
|
92
92
|
/** 是否禁用,默认为 false */
|
|
93
93
|
disabled?: boolean;
|
|
94
|
+
/** 服务器描述(供 load_mcp 呈现给 LLM,非连接必需) */
|
|
95
|
+
description?: string;
|
|
94
96
|
command?: string;
|
|
95
97
|
args?: string[];
|
|
96
98
|
env?: Record<string, string>;
|