@ai-zen/agents-sdk 0.8.0 → 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 +29 -0
- package/README.md +2 -2
- package/README.zh.md +2 -2
- package/dist/config/constants.js +5 -11
- package/dist/index.d.ts +1 -1
- package/dist/runtime/TaskMigrationService.d.ts +27 -3
- package/dist/runtime/TaskMigrationService.js +45 -15
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.1] - 2026-08-28
|
|
4
|
+
|
|
5
|
+
### 🔧 Fixed
|
|
6
|
+
|
|
7
|
+
- **SDK-produced messages now always carry an `id`, aligned with core 4.1.0's required `Message.id`** — `TaskMigrationService.createPostMessages()` returns a `Message.User`, and the default agent / sub-agent definitions (`DEFAULT_AGENT_DEFINITION` / `DEFAULT_SUBAGENT_DEFINITION`) build their messages via `Message.System` / `Message.User`. This removes the last places where a bare object literal `{ role, content }` was assigned to `AgentNS.Message`, which would now fail to compile under core 4.1.0 (where `Message.id` is non-optional). Consumers no longer need to patch a missing `id` on SDK-generated messages (e.g. a desktop-side `ensureId` bridge)
|
|
8
|
+
- **No breaking change to public API** — only internal message construction was switched to the `Message` factory methods; exported types and method signatures are unchanged
|
|
9
|
+
|
|
10
|
+
### ✅ Tests
|
|
11
|
+
|
|
12
|
+
- SDK suite re-checked green against core 4.1.0 (`Message.id` required)
|
|
13
|
+
|
|
14
|
+
## [0.9.0] - 2026-08-28
|
|
15
|
+
|
|
16
|
+
### 🎯 Optimized
|
|
17
|
+
|
|
18
|
+
- **`TaskMigrationService.migrate` gains a `strategy` switch** — controls how history is handled after migration:
|
|
19
|
+
- **`omit` (default)**: history messages are marked `omit: true` (kept in `agent.messages` for audit/replay, but `Agent.formatHistory()` filters them out), and a "conversation breakpoint" message (handoff doc + handover instructions, role=user) is appended as the new context start. The sequence sent to the model becomes `[definition.messages, breakpoint message]`. Reuses Core's existing `omit` mechanism — no Core changes needed.
|
|
20
|
+
- **`prune`**: physically drops history, keeping only `definition.messages` + breakpoint message (the previous replace behavior).
|
|
21
|
+
- The default can be set via `strategy` when constructing `TaskMigrationService`, and overridden per `migrate()` call (`MigrationStrategy` type is exported).
|
|
22
|
+
- `agent.messages` is rebuilt via a **shallow copy** to avoid mutating objects referenced by `definition.messages` (prevents polluting the template).
|
|
23
|
+
- `historyText` (fed to the model to generate the handoff doc) now **filters omitted history**, so repeated migrations don't re-feed old omitted history to the model.
|
|
24
|
+
- `AutoMigratePlugin` still only decides *when* to trigger — no changes needed.
|
|
25
|
+
|
|
26
|
+
### ✅ Tests
|
|
27
|
+
|
|
28
|
+
- `TaskMigrationService` / `AutoMigratePlugin` assertions updated to the omit semantics (history marked omit + trailing breakpoint + system prompt preserved).
|
|
29
|
+
- New case: `historyText` filters already-omitted history.
|
|
30
|
+
- New case: `strategy=prune` (constructor default + `migrate` param override) physically drops history.
|
|
31
|
+
|
|
3
32
|
## [0.8.0] - 2026-08-24
|
|
4
33
|
|
|
5
34
|
### ⚠️ Breaking
|
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ await agent.send("Hello");
|
|
|
81
81
|
| `runtime` | ✅ Implemented — Provider, Capabilities, createAgent, MCP connection management, task migration |
|
|
82
82
|
| `plugin` | ✅ Implemented — AutoMigratePlugin / AutoRefreshToolsPlugin / ContextGuardPlugin / UnknownToolHintPlugin |
|
|
83
83
|
| `shared` | ✅ Implemented — SdkError + injectable Logger |
|
|
84
|
-
| Tests | ✅
|
|
84
|
+
| Tests | ✅ 452 passing, 51 files, all green (incl. real-API chat & viewImage e2e) |
|
|
85
85
|
|
|
86
86
|
## Built-in Tools
|
|
87
87
|
|
|
@@ -118,7 +118,7 @@ Conditionally injected based on the active model / config:
|
|
|
118
118
|
|
|
119
119
|
| Plugin | Description |
|
|
120
120
|
|--------|-------------|
|
|
121
|
-
| `AutoMigratePlugin` | Automatically triggers task migration when the context overflows; delegates the actual migration to the injected `TaskMigrationService` instance, which reuses the agent's own model client |
|
|
121
|
+
| `AutoMigratePlugin` | Automatically triggers task migration when the context overflows; delegates the actual migration to the injected `TaskMigrationService` instance (history handled per `strategy`: default `omit` keeps it auditable, optional `prune` drops it), which reuses the agent's own model client |
|
|
122
122
|
| `AutoRefreshToolsPlugin` | Re-scans the file system before each `send()` to refresh the tool list |
|
|
123
123
|
| `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 |
|
|
124
124
|
| `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
|
@@ -80,7 +80,7 @@ await agent.send("你好");
|
|
|
80
80
|
| `runtime` | ✅ 已实现 — Provider、Capabilities、createAgent、MCP 连接管理、任务迁移 |
|
|
81
81
|
| `plugin` | ✅ 已实现 — AutoMigratePlugin / AutoRefreshToolsPlugin / ContextGuardPlugin / UnknownToolHintPlugin |
|
|
82
82
|
| `shared` | ✅ 已实现 — SdkError + 可注入 Logger |
|
|
83
|
-
| 测试 | ✅
|
|
83
|
+
| 测试 | ✅ 452 通过,51 个文件,全绿(含真实 API 聊天与 viewImage e2e) |
|
|
84
84
|
|
|
85
85
|
## 内置工具
|
|
86
86
|
|
|
@@ -117,7 +117,7 @@ await agent.send("你好");
|
|
|
117
117
|
|
|
118
118
|
| 插件 | 说明 |
|
|
119
119
|
|------|------|
|
|
120
|
-
| `AutoMigratePlugin` |
|
|
120
|
+
| `AutoMigratePlugin` | 上下文超限时自动触发任务迁移,生成交接文档并追加对话断点(历史按 `strategy` 处理:默认 `omit` 标记保留可审计,可选 `prune` 物理剔除;委托注入的 `TaskMigrationService`,复用 Agent 自身的模型调用) |
|
|
121
121
|
| `AutoRefreshToolsPlugin` | 每次 `send()` 前重新扫描文件系统,刷新工具列表 |
|
|
122
122
|
| `ContextGuardPlugin` | 上下文安全护栏 — 每轮发请求前检测上一轮 `usage.prompt_tokens`,超过 `maxTokens × ratio`(默认 1.5,即 +50%)时抛 `ContextOverflowError` 中断对话,防止读入超大文件导致上下文失控 |
|
|
123
123
|
| `UnknownToolHintPlugin` | 未知工具智能提示 — LLM 调用不存在的工具时,根据 MCP 配置引导使用 `call_mcp_tool` / 提示权限问题(调用方显式 `agent.use` 注册) |
|
package/dist/config/constants.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Message } from "@ai-zen/agents-core";
|
|
2
2
|
// ---------------------------------------------------------------------------
|
|
3
3
|
// 默认 Agent
|
|
4
4
|
// ---------------------------------------------------------------------------
|
|
@@ -10,17 +10,14 @@ export const DEFAULT_AGENT_DEFINITION = {
|
|
|
10
10
|
name: "默认助手",
|
|
11
11
|
description: "默认的 AI 助手,适用于日常问答和任务执行。",
|
|
12
12
|
messages: [
|
|
13
|
-
|
|
14
|
-
role: AgentNS.Role.System,
|
|
15
|
-
content: `你是一个严谨可靠的智能助手。请用中文回复,说话风格参照官方文件。
|
|
13
|
+
Message.System(`你是一个严谨可靠的智能助手。请用中文回复,说话风格参照官方文件。
|
|
16
14
|
|
|
17
15
|
- 开动脑筋 — 主动思考、灵活运用工具,而不是机械执行
|
|
18
16
|
- 实事求是 — 知之为知之,不知为不知,而不是凭空编造;如果用户意图不明确,应先提问澄清,而不是自行脑补
|
|
19
17
|
- 一切行动听指挥 — 严格遵循用户指令,而不是自作主张
|
|
20
18
|
- 安全第一 — 风险操作先告知确认,而不是盲目执行
|
|
21
19
|
- 能打胜仗 — 写优秀的代码,而不是只限于能用的代码
|
|
22
|
-
- 有矛盾就问 —
|
|
23
|
-
},
|
|
20
|
+
- 有矛盾就问 — 如果用户指令中存在自相矛盾之处,应指出矛盾并请求澄清,而不是自行取舍`),
|
|
24
21
|
],
|
|
25
22
|
permissions: {
|
|
26
23
|
tools: { allow: ["*"] },
|
|
@@ -40,11 +37,8 @@ export const DEFAULT_SUBAGENT_DEFINITION = {
|
|
|
40
37
|
name: "通用助手",
|
|
41
38
|
description: "一个通用的子 Agent,擅长独立完成各类任务。",
|
|
42
39
|
messages: [
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
content: "你是一个通用助手子 Agent,被父 Agent 委派来独立完成具体任务。请根据给定的任务描述,主动调用你的工具(文件读写、执行命令、搜索等)来分析和完成任务。完成任务后直接返回结果,不需要解释你的思考过程。\n\n⚠️ 强制性要求:\n1. 如果任务描述中存在任何不明确、模糊或缺失的信息(包括但不限于具体目标、文件路径、约束条件、预期产出等),你必须直接拒绝执行,并明确列出哪些信息不明确或缺失,要求父 Agent 提供更完整的任务上下文。不得自行假设、猜测或脑补任何信息。\n2. 如果任务描述中存在自相矛盾的信息(如相互冲突的要求、不一致的文件路径、矛盾的约束条件等),你必须及时指出矛盾之处,并要求父 Agent 澄清后再执行。",
|
|
46
|
-
},
|
|
47
|
-
{ role: AgentNS.Role.User, content: "{{task}}" },
|
|
40
|
+
Message.System("你是一个通用助手子 Agent,被父 Agent 委派来独立完成具体任务。请根据给定的任务描述,主动调用你的工具(文件读写、执行命令、搜索等)来分析和完成任务。完成任务后直接返回结果,不需要解释你的思考过程。\n\n⚠️ 强制性要求:\n1. 如果任务描述中存在任何不明确、模糊或缺失的信息(包括但不限于具体目标、文件路径、约束条件、预期产出等),你必须直接拒绝执行,并明确列出哪些信息不明确或缺失,要求父 Agent 提供更完整的任务上下文。不得自行假设、猜测或脑补任何信息。\n2. 如果任务描述中存在自相矛盾的信息(如相互冲突的要求、不一致的文件路径、矛盾的约束条件等),你必须及时指出矛盾之处,并要求父 Agent 澄清后再执行。"),
|
|
41
|
+
Message.User("{{task}}"),
|
|
48
42
|
],
|
|
49
43
|
permissions: {
|
|
50
44
|
tools: { allow: ["*"] },
|
package/dist/index.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export type { McpConnectOptions } from "./runtime/McpConnectionManager.js";
|
|
|
23
23
|
export { SdkCallbackTool } from "./runtime/SdkCallbackTool.js";
|
|
24
24
|
export type { SdkCallbackToolOptions } from "./runtime/SdkCallbackTool.js";
|
|
25
25
|
export { TaskMigrationService } from "./runtime/TaskMigrationService.js";
|
|
26
|
-
export type { MigrationContext, TaskMigrationServiceOptions, } from "./runtime/TaskMigrationService.js";
|
|
26
|
+
export type { MigrationContext, MigrationStrategy, TaskMigrationServiceOptions, } from "./runtime/TaskMigrationService.js";
|
|
27
27
|
export { AutoMigratePlugin } from "./plugin/AutoMigratePlugin.js";
|
|
28
28
|
export type { AutoMigrateOptions } from "./plugin/AutoMigratePlugin.js";
|
|
29
29
|
export { AutoRefreshToolsPlugin } from "./plugin/AutoRefreshToolsPlugin.js";
|
|
@@ -24,6 +24,13 @@ export interface MigrationContext {
|
|
|
24
24
|
/** 生成的交接文档(迁移完成后填充) */
|
|
25
25
|
handoffDoc?: string;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* 迁移后的历史处理策略。
|
|
29
|
+
*
|
|
30
|
+
* - `omit`(默认):将历史消息标记 `omit: true`,仍保留在 `agent.messages` 可审计/回放,但不再发送给模型;
|
|
31
|
+
* - `prune`:物理剔除历史,只保留 `definition.messages`(系统提示等模板)+ 追加的对话断点。
|
|
32
|
+
*/
|
|
33
|
+
export type MigrationStrategy = "omit" | "prune";
|
|
27
34
|
/**
|
|
28
35
|
* 任务迁移服务构造参数。
|
|
29
36
|
*/
|
|
@@ -34,6 +41,8 @@ export interface TaskMigrationServiceOptions {
|
|
|
34
41
|
model?: string;
|
|
35
42
|
/** 生成交接文档所用模型参数(可选;未传则 migrate 时回退到 agent.modelConfig) */
|
|
36
43
|
modelConfig?: Record<string, unknown>;
|
|
44
|
+
/** 迁移后历史处理策略,默认 `omit`(标记历史保留可审计)。可选 `prune`(物理剔除)。 */
|
|
45
|
+
strategy?: MigrationStrategy;
|
|
37
46
|
/** 迁移前钩子(服务持有)。迁移开始前触发,此时 agent.messages 仍为完整旧历史 */
|
|
38
47
|
onBeforeMigrate?: (ctx: MigrationContext) => void | Promise<void>;
|
|
39
48
|
/** 迁移后钩子(服务持有)。迁移完成后触发,交接文档已注入 agent.messages */
|
|
@@ -52,7 +61,7 @@ export interface TaskMigrationServiceOptions {
|
|
|
52
61
|
*
|
|
53
62
|
* 职责:
|
|
54
63
|
* 1. 生成交接文档的提示词 / 注入格式(静态纯工具,供上层使用)
|
|
55
|
-
* 2. 执行完整迁移(串行化 → 模型生成 →
|
|
64
|
+
* 2. 执行完整迁移(串行化 → 模型生成 → 按策略处理历史 + 追加对话断点),并暴露迁移前后钩子(实例方法)
|
|
56
65
|
*
|
|
57
66
|
* 设计上,`AutoMigratePlugin` 只负责「何时触发」(检测 token 超限),
|
|
58
67
|
* 实际迁移逻辑统一收敛到本服务,从而让手动迁移与自动迁移复用同一条链路。
|
|
@@ -71,9 +80,15 @@ export declare class TaskMigrationService {
|
|
|
71
80
|
private client?;
|
|
72
81
|
private model?;
|
|
73
82
|
private modelConfig?;
|
|
83
|
+
private strategy;
|
|
74
84
|
private logger;
|
|
75
85
|
constructor(options?: TaskMigrationServiceOptions);
|
|
76
86
|
static createPrompt(): string;
|
|
87
|
+
/**
|
|
88
|
+
* 生成迁移后追加的「对话断点」消息(role=user):交接文档 + 接手指令。
|
|
89
|
+
* 该消息是 omit 迁移方案中新上下文的起点,模型看到的序列为
|
|
90
|
+
* `[definition.messages, 断点消息]`(历史消息已被标记 omit,不再发送)。
|
|
91
|
+
*/
|
|
77
92
|
static createPostMessages(handoffDoc: string): AgentNS.Message[];
|
|
78
93
|
/**
|
|
79
94
|
* 序列化消息为 `[role]: content` 文本,供模型理解完整对话历史。
|
|
@@ -84,21 +99,30 @@ export declare class TaskMigrationService {
|
|
|
84
99
|
*/
|
|
85
100
|
private generateHandoff;
|
|
86
101
|
/**
|
|
87
|
-
* 执行完整迁移:序列化历史 → 模型生成交接文档 →
|
|
102
|
+
* 执行完整迁移:序列化历史 → 模型生成交接文档 → 按策略处理历史并追加对话断点 → 触发钩子。
|
|
103
|
+
*
|
|
104
|
+
* 策略(`strategy`,构造函数默认 / 本参数可覆盖):
|
|
105
|
+
* - `omit`(默认):`agent.definition.messages`(模板)保留,其余既有历史标记 `omit: true`(仍存于
|
|
106
|
+
* `agent.messages` 可审计/回放但不再发送给模型),末尾追加「对话断点」消息。因此 `formatHistory()`
|
|
107
|
+
* 发送给模型的是 `[definition.messages, 断点消息]` —— 历史被压缩但并不删除。
|
|
108
|
+
* - `prune`:物理剔除历史,只保留 `definition.messages` + 断点消息(即原先的替换行为)。
|
|
88
109
|
*
|
|
89
110
|
* 设计约束:
|
|
90
|
-
* - 不重建 Agent
|
|
111
|
+
* - 不重建 Agent,保留所有引用与插件绑定(仅重建消息列表)
|
|
91
112
|
* - 钩子(onBeforeMigrate / onMigrated)抛错会被捕获并记录,**不中断**迁移流程
|
|
92
113
|
* - 生成失败 / 未取到交接文档时抛错,此时 `agent.messages` 保持原样(不会被部分修改)
|
|
93
114
|
*
|
|
94
115
|
* @param params.agent 当前对话 Agent
|
|
95
116
|
* @param params.promptTokens 当前 prompt token 用量(可选)
|
|
96
117
|
* @param params.maxTokens 上下文阈值(可选)
|
|
118
|
+
* @param params.strategy 本次迁移的历史处理策略(可选,覆盖构造时的默认值)
|
|
97
119
|
* @returns 完整的迁移上下文(含生成的交接文档)
|
|
98
120
|
*/
|
|
99
121
|
migrate(params: {
|
|
100
122
|
agent: SdkAgent;
|
|
101
123
|
promptTokens?: number;
|
|
102
124
|
maxTokens?: number;
|
|
125
|
+
/** 本次迁移的历史处理策略(可选,覆盖构造时的默认值) */
|
|
126
|
+
strategy?: MigrationStrategy;
|
|
103
127
|
}): Promise<MigrationContext>;
|
|
104
128
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Message } from "@ai-zen/agents-core";
|
|
2
2
|
import { getLogger } from "../shared/logger.js";
|
|
3
3
|
/**
|
|
4
4
|
* 任务迁移服务。
|
|
@@ -11,7 +11,7 @@ import { getLogger } from "../shared/logger.js";
|
|
|
11
11
|
*
|
|
12
12
|
* 职责:
|
|
13
13
|
* 1. 生成交接文档的提示词 / 注入格式(静态纯工具,供上层使用)
|
|
14
|
-
* 2. 执行完整迁移(串行化 → 模型生成 →
|
|
14
|
+
* 2. 执行完整迁移(串行化 → 模型生成 → 按策略处理历史 + 追加对话断点),并暴露迁移前后钩子(实例方法)
|
|
15
15
|
*
|
|
16
16
|
* 设计上,`AutoMigratePlugin` 只负责「何时触发」(检测 token 超限),
|
|
17
17
|
* 实际迁移逻辑统一收敛到本服务,从而让手动迁移与自动迁移复用同一条链路。
|
|
@@ -30,14 +30,16 @@ export class TaskMigrationService {
|
|
|
30
30
|
client;
|
|
31
31
|
model;
|
|
32
32
|
modelConfig;
|
|
33
|
+
strategy;
|
|
33
34
|
logger;
|
|
34
35
|
constructor(options = {}) {
|
|
35
|
-
const { onBeforeMigrate, onMigrated, logger, client, model, modelConfig } = options;
|
|
36
|
+
const { onBeforeMigrate, onMigrated, logger, client, model, modelConfig, strategy } = options;
|
|
36
37
|
this.onBeforeMigrate = onBeforeMigrate;
|
|
37
38
|
this.onMigrated = onMigrated;
|
|
38
39
|
this.client = client;
|
|
39
40
|
this.model = model;
|
|
40
41
|
this.modelConfig = modelConfig;
|
|
42
|
+
this.strategy = strategy ?? "omit";
|
|
41
43
|
this.logger = logger ?? getLogger();
|
|
42
44
|
}
|
|
43
45
|
static createPrompt() {
|
|
@@ -64,6 +66,11 @@ export class TaskMigrationService {
|
|
|
64
66
|
`- 接手后建议的操作步骤`,
|
|
65
67
|
].join("\n");
|
|
66
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* 生成迁移后追加的「对话断点」消息(role=user):交接文档 + 接手指令。
|
|
71
|
+
* 该消息是 omit 迁移方案中新上下文的起点,模型看到的序列为
|
|
72
|
+
* `[definition.messages, 断点消息]`(历史消息已被标记 omit,不再发送)。
|
|
73
|
+
*/
|
|
67
74
|
static createPostMessages(handoffDoc) {
|
|
68
75
|
const content = [
|
|
69
76
|
"这是上一轮对话的任务交接文档。请先阅读交接文档,理解上下文后再继续协助用户完成任务。",
|
|
@@ -76,7 +83,7 @@ export class TaskMigrationService {
|
|
|
76
83
|
"",
|
|
77
84
|
"请确认你已理解以上内容,然后询问用户接下来需要什么帮助。",
|
|
78
85
|
].join("\n");
|
|
79
|
-
return [
|
|
86
|
+
return [Message.User(content)];
|
|
80
87
|
}
|
|
81
88
|
/**
|
|
82
89
|
* 序列化消息为 `[role]: content` 文本,供模型理解完整对话历史。
|
|
@@ -109,21 +116,31 @@ export class TaskMigrationService {
|
|
|
109
116
|
return handoffDoc;
|
|
110
117
|
}
|
|
111
118
|
/**
|
|
112
|
-
* 执行完整迁移:序列化历史 → 模型生成交接文档 →
|
|
119
|
+
* 执行完整迁移:序列化历史 → 模型生成交接文档 → 按策略处理历史并追加对话断点 → 触发钩子。
|
|
120
|
+
*
|
|
121
|
+
* 策略(`strategy`,构造函数默认 / 本参数可覆盖):
|
|
122
|
+
* - `omit`(默认):`agent.definition.messages`(模板)保留,其余既有历史标记 `omit: true`(仍存于
|
|
123
|
+
* `agent.messages` 可审计/回放但不再发送给模型),末尾追加「对话断点」消息。因此 `formatHistory()`
|
|
124
|
+
* 发送给模型的是 `[definition.messages, 断点消息]` —— 历史被压缩但并不删除。
|
|
125
|
+
* - `prune`:物理剔除历史,只保留 `definition.messages` + 断点消息(即原先的替换行为)。
|
|
113
126
|
*
|
|
114
127
|
* 设计约束:
|
|
115
|
-
* - 不重建 Agent
|
|
128
|
+
* - 不重建 Agent,保留所有引用与插件绑定(仅重建消息列表)
|
|
116
129
|
* - 钩子(onBeforeMigrate / onMigrated)抛错会被捕获并记录,**不中断**迁移流程
|
|
117
130
|
* - 生成失败 / 未取到交接文档时抛错,此时 `agent.messages` 保持原样(不会被部分修改)
|
|
118
131
|
*
|
|
119
132
|
* @param params.agent 当前对话 Agent
|
|
120
133
|
* @param params.promptTokens 当前 prompt token 用量(可选)
|
|
121
134
|
* @param params.maxTokens 上下文阈值(可选)
|
|
135
|
+
* @param params.strategy 本次迁移的历史处理策略(可选,覆盖构造时的默认值)
|
|
122
136
|
* @returns 完整的迁移上下文(含生成的交接文档)
|
|
123
137
|
*/
|
|
124
138
|
async migrate(params) {
|
|
125
|
-
const { agent, promptTokens, maxTokens } = params;
|
|
126
|
-
const
|
|
139
|
+
const { agent, promptTokens, maxTokens, strategy: overrideStrategy } = params;
|
|
140
|
+
const strategy = overrideStrategy ?? this.strategy;
|
|
141
|
+
// 序列化有效上下文:过滤已标记 omit 的历史,避免重复迁移时把旧省略历史再次喂给模型。
|
|
142
|
+
// historyText 供模型生成交接文档,而 messageCountBefore 仍记录本次迁移前的消息总数。
|
|
143
|
+
const historyText = TaskMigrationService.serializeMessages(agent.messages.filter((m) => !m.omit));
|
|
127
144
|
const messageCountBefore = agent.messages.length;
|
|
128
145
|
// 生成交接文档所用模型调用:优先使用构造时传入的 client/model/modelConfig,
|
|
129
146
|
// 未传则回退到 agent 自带的(无需 Provider / 独立迁移 Agent)。
|
|
@@ -150,13 +167,26 @@ export class TaskMigrationService {
|
|
|
150
167
|
}
|
|
151
168
|
// 生成交接文档
|
|
152
169
|
const handoffDoc = await this.generateHandoff(client, model, modelConfig, historyText);
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
170
|
+
// 重建消息列表:按策略处理历史(omit 标记保留 / prune 物理剔除),并追加「对话断点」消息。
|
|
171
|
+
// 均用浅拷贝/新数组,避免直接修改 definition.messages 引用的对象(防止污染模板)。
|
|
172
|
+
const breakpointMessages = TaskMigrationService.createPostMessages(handoffDoc);
|
|
173
|
+
let nextMessages;
|
|
174
|
+
if (strategy === "prune") {
|
|
175
|
+
// 物理剔除:只保留模板消息 + 断点
|
|
176
|
+
nextMessages = [...agent.definition.messages, ...breakpointMessages];
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
// omit(默认):以 definition.messages 长度为界保留模板消息,其余历史统一标记 omit
|
|
180
|
+
const preserveCount = Math.min(agent.definition.messages.length, agent.messages.length);
|
|
181
|
+
nextMessages = [
|
|
182
|
+
...agent.messages.map((m, i) => ({
|
|
183
|
+
...m,
|
|
184
|
+
omit: i >= preserveCount ? true : m.omit,
|
|
185
|
+
})),
|
|
186
|
+
...breakpointMessages,
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
agent.messages = nextMessages;
|
|
160
190
|
// 迁移后上下文(含 handoffDoc,与迁移前上下文独立)
|
|
161
191
|
const afterCtx = {
|
|
162
192
|
agent,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-zen/agents-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
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",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
20
20
|
"dayjs": "^1.11.21",
|
|
21
21
|
"openai": "^7.5.0",
|
|
22
|
-
"@ai-zen/agents-core": "^4.
|
|
22
|
+
"@ai-zen/agents-core": "^4.1.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^24.12.2",
|