@ai-zen/cli 0.6.3 → 0.8.0
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 +62 -0
- package/README.md +29 -20
- package/README.zh.md +27 -18
- package/dist/auto-migrate-confirm-plugin.d.ts +58 -0
- package/dist/auto-migrate-confirm-plugin.d.ts.map +1 -0
- package/dist/auto-migrate-confirm-plugin.js +79 -0
- package/dist/auto-migrate-confirm-plugin.js.map +1 -0
- package/dist/conversation-commands/help.d.ts.map +1 -1
- package/dist/conversation-commands/help.js +5 -8
- package/dist/conversation-commands/help.js.map +1 -1
- package/dist/conversation-commands/index.d.ts +2 -4
- package/dist/conversation-commands/index.d.ts.map +1 -1
- package/dist/conversation-commands/index.js +21 -21
- package/dist/conversation-commands/index.js.map +1 -1
- package/dist/conversation-commands/registry.d.ts +46 -0
- package/dist/conversation-commands/registry.d.ts.map +1 -0
- package/dist/conversation-commands/registry.js +58 -0
- package/dist/conversation-commands/registry.js.map +1 -0
- package/dist/conversation-runner.d.ts.map +1 -1
- package/dist/conversation-runner.js +19 -19
- package/dist/conversation-runner.js.map +1 -1
- package/dist/slash-hint-prompt.d.ts +41 -0
- package/dist/slash-hint-prompt.d.ts.map +1 -0
- package/dist/slash-hint-prompt.js +92 -0
- package/dist/slash-hint-prompt.js.map +1 -0
- package/dist/sub-agent-guard-plugin.d.ts +45 -0
- package/dist/sub-agent-guard-plugin.d.ts.map +1 -0
- package/dist/sub-agent-guard-plugin.js +47 -0
- package/dist/sub-agent-guard-plugin.js.map +1 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,67 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.0] - 2026-09-28
|
|
4
|
+
|
|
5
|
+
### 🚀 新功能
|
|
6
|
+
|
|
7
|
+
- **子 Agent 上下文护栏(`SubAgentGuardInstallerPlugin`)** — 补上「主 Agent 有护栏、子 Agent 无护栏」的缺口(新增 `src/sub-agent-guard-plugin.ts`):
|
|
8
|
+
- **背景**:SDK 的子 Agent 由 `AgentTool` / `AgentToolLazy` 在委派时 `new Agent({...})` 构建,新建实例不携带任何插件(`Agent._plugins` 每实例私有,不向子 Agent 传播),且子 Agent 走 `run()` 而非 `send()`(`onBeforeSend` / `onAfterSend` 不会触发)——因此主 Agent 上的 `ContextGuardPlugin` 与自动迁移插件对子 Agent 完全无效,子 Agent 的内循环没有约束
|
|
9
|
+
- **介入点**:core 4.2.0 的 `onSubAgentStart` 钩子在「子 Agent 已构建、尚未 `run()`」时由宿主 Agent 分发,载荷携带子 Agent 实例;`use()` 只是把插件推入 `_plugins`,而钩子分发每次都实时遍历该列表,故在钩子内安插对**本次 `run()` 立即生效**(无需 `init()`,`AgentTool` 也不调用子 Agent 的 `init()`)
|
|
10
|
+
- **约束口径**:把主 Agent 同款的 `ContextGuardPlugin` 装到子 Agent 上——同一 `maxTokens`(当前模型 `maxContextTokens`)、同样不传 ratio(沿用 SDK 默认 1.5),使「上下文 token 超过 `maxTokens` × 1.5 即中断」对子 Agent 同样成立;**不设轮次上限、不设工具调用次数上限**(仅此一项限制)
|
|
11
|
+
- **中断语义为「软中断」**:子 Agent 的 run 立即结束,异常经 `AgentTool` 的 `finally`(分发 `onSubAgentEnd`)上抛至父 Agent,而父 Agent 默认 `allowJsonParseError = true`,故被降级为一条工具结果文本(`执行工具 X 时出错: …`),父 Agent 继续下一轮——停掉烧钱的子 Agent,但不终止用户对话
|
|
12
|
+
- **递归覆盖**:安装器在委派时把自身一并装给子 Agent,故子 Agent 再委派(孙级)同样受约束(默认 SubAgent 定义为 `subagents: deny`,该路径默认不触发,仅在放开递归时生效)
|
|
13
|
+
- **覆盖范围**:仅 core 的 `AgentTool` / `AgentToolLazy` 两条委派路径(均分发 `onSubAgentStart`);SDK 的 `call_skill_sub_agent`(技能子 Agent)不分发该钩子,本次不覆盖
|
|
14
|
+
|
|
15
|
+
### ⚠️ 依赖升级
|
|
16
|
+
|
|
17
|
+
- **`@ai-zen/agents-core` 升至 `^4.2.0`、`@ai-zen/agents-sdk` 升至 `^0.10.0`** — `src/version.ts` 由实际安装版本读取,版本横幅随之显示 core `4.2.0` / sdk `0.10.0`;SDK 0.10.0 新增的 `load_mcp` `include_manifest` 开关为向后兼容的可选参数(默认 `true`,行为与升级前逐字一致),CLI 无需适配
|
|
18
|
+
|
|
19
|
+
### 🔧 修复
|
|
20
|
+
|
|
21
|
+
- **子 Agent 事件对齐 core 4.2.0 的改名与载荷结构** — core 4.2.0 将事件 `sub-agent` 更名为 `sub-agent-start`,载荷由 `{ agent: 子 Agent, ctx }` 改为 `SubAgentContext = { agent: 主 Agent, subAgent: 子 Agent, toolCallContext }`。`src/conversation-runner.ts` 同步适配:事件监听与注销改用 `sub-agent-start`(此前监听旧名将不再触发,子 Agent 流式渲染会静默失效);子 Agent 实例改取自 `subAgent` 字段,工具名改取自 `toolCallContext.tool_call.function.name`(此前读取已不存在的 `ctx` 字段会在 `sub-agent-end` 回调中抛错)
|
|
22
|
+
|
|
23
|
+
### ✅ 测试
|
|
24
|
+
|
|
25
|
+
- 新增 `src/sub-agent-guard-plugin.test.ts`(6 个用例):安装器的装载清单与「不拒绝委派」、安插后对本次 `run()` 立即生效(无需 `init()`)、用量恰好等于硬上限时放行、首轮无 usage 数据时放行、阈值随传入 `maxTokens` 变化、孙级传染
|
|
26
|
+
- `tsc --noEmit` 类型检查、全量单测与 `npm run build` 通过(74 passed / 9 files)
|
|
27
|
+
|
|
28
|
+
## [0.7.0] - 2026-09-20
|
|
29
|
+
|
|
30
|
+
### 🚀 新功能
|
|
31
|
+
|
|
32
|
+
- **自动迁移二次确认** — 上下文 token 超限触发的自动迁移不再静默执行,迁移前先向用户确认(新增 `src/auto-migrate-confirm-plugin.ts`):
|
|
33
|
+
- `AutoMigrateConfirmPlugin` 继承 SDK 的 `AutoMigratePlugin`,**仅在「超阈值」与「调用迁移」之间插入一次确认**:阈值判断、迁移调用与错误处理仍复用基类,实际迁移仍委托共享的 `migrationService`(与 `/migrate` 同一条链路)——即 SDK 侧「只负责触发」的语义不变,确认是 CLI 层的增量
|
|
34
|
+
- 确认框展示当前用量与阈值(如 `260000/250000 tokens`)并说明影响(生成交接文档 → 保存当前对话 → 开启新会话继续),**默认「是」**(回车即迁移,与 `/migrate` 默认值一致)
|
|
35
|
+
- 选择「否」仅跳过**本次**迁移,不记录隐式状态:当前对话不受影响(历史未被剔除),可继续提问或随时 `/migrate`;仍处超限状态时下次发送后再次询问,并提示继续增长至严重超限会被 `ContextGuardPlugin` 中断
|
|
36
|
+
- **非交互环境不询问**:仅在 stdin 与 stdout 均为 TTY 时弹出确认框;管道、重定向、e2e 脚本无确认通道,保持既有静默自动迁移行为(不阻塞等待输入、不额外输出,管道语义不变)
|
|
37
|
+
- 对话装配处(`src/conversation-runner.ts`)改注册 `AutoMigrateConfirmPlugin`,其余插件(`ContextGuardPlugin` 护栏位置)不变
|
|
38
|
+
- **对话内命令提示** — 对话输入行键入 `/` 即实时列出可用命令及说明,继续输入按前缀收敛候选,无匹配时提示「无匹配命令(输入 /help 查看全部)」:
|
|
39
|
+
- 新增 `src/slash-hint-prompt.ts`:继承 inquirer 的 input 提示并覆写 `render`,将候选命令作为底栏(`bottomContent`)交由 inquirer 的 `ScreenManager` 渲染,复用其折行、终端缩放、擦除与光标归位处理,渲染表现与其它提示一致
|
|
40
|
+
- **仅提示,不改变提交语义**:回车始终提交输入原文,命令仍由 `dispatchCommand` 按完整名称精确匹配分发(不做前缀补全、不做高亮选择)
|
|
41
|
+
- 非 TTY 环境(stdin/stdout 重定向、e2e 脚本)自动不渲染提示,退化为普通输入行,既有输出行为不变
|
|
42
|
+
- 普通聊天内容(非 `/` 开头)不产生任何提示
|
|
43
|
+
- 对话主循环输入改由 `src/slash-hint-prompt.ts` 的 `askInput()` 提供(`src/conversation-runner.ts` 不再直接构造输入提示)
|
|
44
|
+
|
|
45
|
+
### 🎯 优化
|
|
46
|
+
|
|
47
|
+
- **对话命令清单收敛为唯一来源** — 新增 `src/conversation-commands/registry.ts` 集中声明命令名、别名与说明,由分发(`index.ts`)、帮助(`help.ts`)与输入提示三处共用:
|
|
48
|
+
- **别名不再重复登记**:registry 声明的别名由 `index.ts` 自动展开为处理函数表的键;registry 声明了命令却未注册处理函数时于启动阶段即报错(fail-fast)
|
|
49
|
+
- `/help` 输出改由 registry 渲染,命令列按最长命令串对齐,与输入提示列宽一致(命令与说明文案保持不变)
|
|
50
|
+
- `getCommandNames()` 迁至 registry,`conversation-commands/index.ts` 原样再导出,调用方无需改动
|
|
51
|
+
|
|
52
|
+
### ⚠️ 依赖约束
|
|
53
|
+
|
|
54
|
+
- **引用了 inquirer 内部模块** `inquirer/lib/prompts/input.js` — inquirer 9 未导出 BasePrompt/InputPrompt,实现命令提示底栏只能深层导入(inquirer@9 的 `package.json` 无 `exports` 字段,ESM 深层导入已在 Node 26 + inquirer 9.3.8 下实测可用)。类型声明见 `src/typings/inquirer-internals.d.ts`;**升级 inquirer 主版本时须回归验证该模块路径与 `render` 行为**
|
|
55
|
+
- **未新增运行时依赖**,`pnpm-lock.yaml` 不变
|
|
56
|
+
|
|
57
|
+
### ✅ 测试
|
|
58
|
+
|
|
59
|
+
- 新增 `src/auto-migrate-confirm-plugin.test.ts`(阈值判断、确认与拒绝分支、非交互降级、TTY 判定与默认确认文案)
|
|
60
|
+
- 新增 `src/slash-hint-prompt.test.ts`(提示文本生成 + 底栏渲染,覆盖 TTY / 非 TTY / 已提交 / 错误行分支)
|
|
61
|
+
- 新增 `src/conversation-commands/registry.test.ts`(元数据、别名折叠、前缀匹配、命令分发与别名等价)
|
|
62
|
+
- `tsc` 类型检查与全量单测通过(68 passed / 8 files),`npm run build` 成功
|
|
63
|
+
- 构建产物在真实 TTY 下实测:输入 `/` 列出全部命令、`/b` 收敛为 `/back`、回车提交原文且提示行正确擦除;`/help` 输出格式与列宽正常
|
|
64
|
+
|
|
3
65
|
## [0.6.3] - 2026-09-01
|
|
4
66
|
|
|
5
67
|
### 🔧 修复
|
package/README.md
CHANGED
|
@@ -58,7 +58,14 @@ If you exit a conversation without saving (or the process is killed), the conver
|
|
|
58
58
|
|
|
59
59
|
### Conversation Commands
|
|
60
60
|
|
|
61
|
-
While in a conversation, all commands start with
|
|
61
|
+
While in a conversation, all commands start with `/`. Typing `/` lists the available commands, with descriptions, right below the input line; typing more characters narrows the candidates by prefix:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
💬 You: /b
|
|
65
|
+
/back Undo messages (roll back to a specific point and resend)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
> Hints are display-only and do not change submission semantics: Enter always submits exactly what you typed, and commands are matched by their full names. An unrecognized `/xxx` command reports "Unknown command".
|
|
62
69
|
|
|
63
70
|
| Command | Description |
|
|
64
71
|
|---------|-------------|
|
|
@@ -73,10 +80,12 @@ While in a conversation, all commands start with `/`:
|
|
|
73
80
|
|
|
74
81
|
### Conversation Migration
|
|
75
82
|
|
|
76
|
-
When the API response's `usage.prompt_tokens` exceeds the model's `maxContextTokens`, the system
|
|
83
|
+
When the API response's `usage.prompt_tokens` exceeds the model's `maxContextTokens`, the system first asks for a **second confirmation** (showing current usage and the threshold, defaulting to "yes"; choosing "no" skips this migration and leaves the current conversation untouched), then generates a **handover document** summarizing completed tasks, pending items, and key decisions. A new conversation session is created with this document as context, ensuring seamless continuation. The confirmation only appears when both stdin and stdout are TTYs; non-interactive scenarios such as pipes and redirections keep the previous automatic migration behavior.
|
|
77
84
|
|
|
78
85
|
You can also manually trigger a migration at any time by typing `/migrate` in the conversation — no need to wait for the token limit. Both automatic and manual migration delegate to the SDK's `TaskMigrationService`, so the handoff document is always produced consistently.
|
|
79
86
|
|
|
87
|
+
The same context guard also applies to **sub-agents**: at each delegation boundary (`onSubAgentStart`) the CLI installs the same `ContextGuardPlugin` (same `maxTokens`) onto the newly built sub-agent, so a delegated sub-agent is interrupted as soon as its context exceeds the hard limit. This is transparent — a normally-running sub-agent is unaffected.
|
|
88
|
+
|
|
80
89
|
The migration prompt template includes:
|
|
81
90
|
- **Conversation Breakpoint** — Last user/AI exchange verbatim
|
|
82
91
|
- **Completed Tasks** — Task titles and output paths
|
|
@@ -103,7 +112,7 @@ zen hook uninstall
|
|
|
103
112
|
|
|
104
113
|
## Configuration
|
|
105
114
|
|
|
106
|
-
Configuration is stored in `~/.ai-zen/
|
|
115
|
+
Configuration is stored in `~/.ai-zen/config.json` (or `$AI_ZEN_DIR/config.json` if set), shared with other AI-Zen clients. The `maxContextTokens` field on each model sets the migration threshold (typically ~25% of the model's actual context window, e.g. 250,000 for a 1M-token model).
|
|
107
116
|
|
|
108
117
|
```jsonc
|
|
109
118
|
{
|
|
@@ -126,15 +135,15 @@ Configuration is stored in `~/.ai-zen/cli/config.json` (or `$AI_ZEN_DIR/cli/conf
|
|
|
126
135
|
],
|
|
127
136
|
"imageModels": [
|
|
128
137
|
{
|
|
129
|
-
"id": "cogview-
|
|
130
|
-
"name": "CogView-
|
|
138
|
+
"id": "cogview-4",
|
|
139
|
+
"name": "CogView-4",
|
|
131
140
|
"endpointId": "bigmodelcn",
|
|
132
|
-
"modelName": "cogview-
|
|
141
|
+
"modelName": "cogview-4",
|
|
133
142
|
"defaultSize": "1024x1024"
|
|
134
143
|
}
|
|
135
144
|
],
|
|
136
145
|
"defaultModel": "deepseek-v4-flash",
|
|
137
|
-
"defaultImageModel": "cogview-
|
|
146
|
+
"defaultImageModel": "cogview-4",
|
|
138
147
|
"defaultAgent": "default",
|
|
139
148
|
"defaultMigrationModel": "deepseek-v4-flash"
|
|
140
149
|
}
|
|
@@ -148,8 +157,8 @@ Configuration is stored in `~/.ai-zen/cli/config.json` (or `$AI_ZEN_DIR/cli/conf
|
|
|
148
157
|
|
|
149
158
|
```
|
|
150
159
|
~/.ai-zen/ ← Shared root (AI_ZEN_DIR)
|
|
160
|
+
├── config.json ← Endpoints & models (shared with other AI-Zen clients)
|
|
151
161
|
├── cli/ ← CLI runtime data
|
|
152
|
-
│ ├── config.json ← CLI endpoints, models
|
|
153
162
|
│ ├── conversations/ ← CLI conversations
|
|
154
163
|
│ └── drafts/ ← CLI drafts
|
|
155
164
|
├── agents/ ← Agent definitions (shared)
|
|
@@ -185,9 +194,11 @@ Configuration is stored in `~/.ai-zen/cli/config.json` (or `$AI_ZEN_DIR/cli/conf
|
|
|
185
194
|
|
|
186
195
|
MCP server configurations are merged from multiple sources (high to low priority):
|
|
187
196
|
|
|
188
|
-
1. Project
|
|
189
|
-
2. Project
|
|
190
|
-
3.
|
|
197
|
+
1. Project shared `./.mcp.json` (collected from cwd up to git root)
|
|
198
|
+
2. Project personal `./.ai-zen/mcp.json` (same)
|
|
199
|
+
3. Project convention `./.agents/mcp.json`
|
|
200
|
+
4. User-level `~/.ai-zen/mcp.json`
|
|
201
|
+
5. User convention `~/.agents/mcp.json`
|
|
191
202
|
|
|
192
203
|
Same-named servers in higher priority override lower ones.
|
|
193
204
|
|
|
@@ -263,7 +274,7 @@ MCP servers are configured in `mcp.json` files:
|
|
|
263
274
|
{
|
|
264
275
|
"mcpServers": {
|
|
265
276
|
"my-server": {
|
|
266
|
-
"
|
|
277
|
+
"type": "stdio",
|
|
267
278
|
"command": "node",
|
|
268
279
|
"args": ["server.js"],
|
|
269
280
|
"env": {
|
|
@@ -276,9 +287,9 @@ MCP servers are configured in `mcp.json` files:
|
|
|
276
287
|
|
|
277
288
|
Connection lifecycle (connect, reconnect with exponential backoff, idle timeout) is fully managed by the SDK's `McpConnectionManager`.
|
|
278
289
|
|
|
279
|
-
### OAuth (HTTP transport only) —
|
|
290
|
+
### OAuth (HTTP transport only) — Not Yet Supported
|
|
280
291
|
|
|
281
|
-
OAuth 2.0
|
|
292
|
+
The OAuth 2.0 authorization flow (the `oauth` field in `mcp.json`) has its types defined and a `mcp-oauth/` storage directory reserved, but is not implemented yet. An HTTP MCP server configured with `oauth` currently fails to connect due to the missing token.
|
|
282
293
|
|
|
283
294
|
## Preset Endpoints
|
|
284
295
|
|
|
@@ -293,14 +304,12 @@ OAuth 2.0 授权流程(`mcp.json` 中的 `oauth` 字段)已定义类型和
|
|
|
293
304
|
| ID | Name | Endpoint |
|
|
294
305
|
|----|------|----------|
|
|
295
306
|
| `gpt-5.5` | GPT-5.5 | OpenAI |
|
|
296
|
-
| `glm-5.2` | GLM-5.2 | ZhipuAI |
|
|
297
307
|
| `glm-5.1` | GLM-5.1 | ZhipuAI |
|
|
298
|
-
| `glm-
|
|
299
|
-
| `glm-5-turbo` | GLM-5-Turbo | ZhipuAI |
|
|
300
|
-
| `glm-5v-turbo` | GLM-5V-Turbo | ZhipuAI |
|
|
308
|
+
| `glm-5v-turbo` | GLM-5V-Turbo (vision) | ZhipuAI |
|
|
301
309
|
| `glm-4.7-flash` | GLM-4.7-Flash | ZhipuAI |
|
|
302
310
|
| `deepseek-v4-pro` | DeepSeek-V4-Pro | DeepSeek |
|
|
303
311
|
| `deepseek-v4-flash` | DeepSeek-V4-Flash | DeepSeek (**default**) |
|
|
312
|
+
| `deepseek-v4-flash-vision-exp` | DeepSeek-V4-Flash-Vision-Exp (vision) | DeepSeek |
|
|
304
313
|
|
|
305
314
|
## Development
|
|
306
315
|
|
|
@@ -317,9 +326,9 @@ pnpm start
|
|
|
317
326
|
pnpm test
|
|
318
327
|
|
|
319
328
|
# E2E tests (requires API key in .env.local)
|
|
320
|
-
pnpm test
|
|
329
|
+
pnpm test:e2e
|
|
321
330
|
```
|
|
322
331
|
|
|
323
332
|
## License
|
|
324
333
|
|
|
325
|
-
|
|
334
|
+
MIT
|
package/README.zh.md
CHANGED
|
@@ -58,7 +58,14 @@ zen 你好,请介绍一下你自己。
|
|
|
58
58
|
|
|
59
59
|
### 对话命令
|
|
60
60
|
|
|
61
|
-
对话中输入的所有命令以 `/`
|
|
61
|
+
对话中输入的所有命令以 `/` 开头。输入 `/` 会在输入行下方实时列出可用命令及说明,继续输入即按前缀收敛候选:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
💬 你: /b
|
|
65
|
+
/back 撤回消息(可修改后重发)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
> 提示仅作展示,不改变提交语义:回车始终提交当前输入原文,命令按完整名称精确匹配;输入未识别的 `/xxx` 命令会提示「未知命令」。
|
|
62
69
|
|
|
63
70
|
| 命令 | 说明 |
|
|
64
71
|
|------|------|
|
|
@@ -73,10 +80,12 @@ zen 你好,请介绍一下你自己。
|
|
|
73
80
|
|
|
74
81
|
### 任务迁移
|
|
75
82
|
|
|
76
|
-
当 API 响应中的 `usage.prompt_tokens` 超过模型的 `maxContextTokens`
|
|
83
|
+
当 API 响应中的 `usage.prompt_tokens` 超过模型的 `maxContextTokens` 时,系统会先**二次确认**(展示当前用量与阈值,默认「是」;选择「否」则跳过本次迁移、当前对话不受影响),确认后生成**交接文档**,汇总已完成任务、待办事项和关键决策,然后创建新会话并将交接文档注入为上下文,实现无缝衔接。确认框仅在 stdin/stdout 均为 TTY 时出现;管道、重定向等非交互场景无确认通道,保持既有自动迁移行为。
|
|
77
84
|
|
|
78
85
|
你也可以在对话中随时输入 `/migrate` 手动触发迁移,而无需等待 token 超限。手动与自动迁移均委托给 SDK 的 `TaskMigrationService`,交接文档生成始终一致。
|
|
79
86
|
|
|
87
|
+
同样的上下文护栏也作用于**子 Agent**:每次委派边界(`onSubAgentStart`)CLI 都会把同一个 `ContextGuardPlugin`(同一 `maxTokens`)安插到新建的子 Agent 上,因此被委派的子 Agent 在上下文超出硬上限时同样会被中断。该过程是透明的,正常运行的子 Agent 不受影响。
|
|
88
|
+
|
|
80
89
|
迁移提示词模板包含:
|
|
81
90
|
- **对话断点** — 最后一段对话原文引用
|
|
82
91
|
- **已完成的任务** — 任务标题和产出路径
|
|
@@ -103,7 +112,7 @@ zen hook uninstall
|
|
|
103
112
|
|
|
104
113
|
## 配置管理
|
|
105
114
|
|
|
106
|
-
配置文件存储在 `~/.ai-zen/
|
|
115
|
+
配置文件存储在 `~/.ai-zen/config.json`(或 `$AI_ZEN_DIR/config.json`),与其他 AI-Zen 客户端共享。其中 `maxContextTokens` 是迁移触发阈值(通常设为模型实际上下文窗口的约 25%,例如 1M tokens 的模型设为 250,000)。
|
|
107
116
|
|
|
108
117
|
```jsonc
|
|
109
118
|
{
|
|
@@ -126,15 +135,15 @@ zen hook uninstall
|
|
|
126
135
|
],
|
|
127
136
|
"imageModels": [
|
|
128
137
|
{
|
|
129
|
-
"id": "cogview-
|
|
130
|
-
"name": "CogView-
|
|
138
|
+
"id": "cogview-4",
|
|
139
|
+
"name": "CogView-4",
|
|
131
140
|
"endpointId": "bigmodelcn",
|
|
132
|
-
"modelName": "cogview-
|
|
141
|
+
"modelName": "cogview-4",
|
|
133
142
|
"defaultSize": "1024x1024"
|
|
134
143
|
}
|
|
135
144
|
],
|
|
136
145
|
"defaultModel": "deepseek-v4-flash",
|
|
137
|
-
"defaultImageModel": "cogview-
|
|
146
|
+
"defaultImageModel": "cogview-4",
|
|
138
147
|
"defaultAgent": "default",
|
|
139
148
|
"defaultMigrationModel": "deepseek-v4-flash"
|
|
140
149
|
}
|
|
@@ -148,8 +157,8 @@ zen hook uninstall
|
|
|
148
157
|
|
|
149
158
|
```
|
|
150
159
|
~/.ai-zen/ ← 共享根(AI_ZEN_DIR)
|
|
160
|
+
├── config.json ← 端点与模型配置(与其他 AI-Zen 客户端共享)
|
|
151
161
|
├── cli/ ← CLI 运行时数据
|
|
152
|
-
│ ├── config.json ← CLI 的端点、模型配置
|
|
153
162
|
│ ├── conversations/ ← CLI 对话记录
|
|
154
163
|
│ └── drafts/ ← CLI 草稿
|
|
155
164
|
├── agents/ ← Agent 定义(共享)
|
|
@@ -185,9 +194,11 @@ zen hook uninstall
|
|
|
185
194
|
|
|
186
195
|
MCP 服务器配置从多个来源合并(优先级从高到低):
|
|
187
196
|
|
|
188
|
-
1.
|
|
189
|
-
2.
|
|
190
|
-
3.
|
|
197
|
+
1. 项目共享 `./.mcp.json`(从 cwd 向上到 git root 沿途收集)
|
|
198
|
+
2. 项目个人 `./.ai-zen/mcp.json`(同上)
|
|
199
|
+
3. 项目规范 `./.agents/mcp.json`
|
|
200
|
+
4. 用户级 `~/.ai-zen/mcp.json`
|
|
201
|
+
5. 用户规范 `~/.agents/mcp.json`
|
|
191
202
|
|
|
192
203
|
同名 server 高优先级覆盖低优先级。
|
|
193
204
|
|
|
@@ -263,7 +274,7 @@ MCP 服务器配置在 `mcp.json` 文件中:
|
|
|
263
274
|
{
|
|
264
275
|
"mcpServers": {
|
|
265
276
|
"my-server": {
|
|
266
|
-
"
|
|
277
|
+
"type": "stdio",
|
|
267
278
|
"command": "node",
|
|
268
279
|
"args": ["server.js"],
|
|
269
280
|
"env": {
|
|
@@ -293,14 +304,12 @@ OAuth 2.0 授权流程(`mcp.json` 中的 `oauth` 字段)已定义类型和
|
|
|
293
304
|
| ID | 名称 | 端点 |
|
|
294
305
|
|----|------|------|
|
|
295
306
|
| `gpt-5.5` | GPT-5.5 | OpenAI |
|
|
296
|
-
| `glm-5.2` | GLM-5.2 | 智谱AI |
|
|
297
307
|
| `glm-5.1` | GLM-5.1 | 智谱AI |
|
|
298
|
-
| `glm-
|
|
299
|
-
| `glm-5-turbo` | GLM-5-Turbo | 智谱AI |
|
|
300
|
-
| `glm-5v-turbo` | GLM-5V-Turbo | 智谱AI |
|
|
308
|
+
| `glm-5v-turbo` | GLM-5V-Turbo(视觉) | 智谱AI |
|
|
301
309
|
| `glm-4.7-flash` | GLM-4.7-Flash | 智谱AI |
|
|
302
310
|
| `deepseek-v4-pro` | DeepSeek-V4-Pro | DeepSeek |
|
|
303
311
|
| `deepseek-v4-flash` | DeepSeek-V4-Flash | DeepSeek(**默认模型**) |
|
|
312
|
+
| `deepseek-v4-flash-vision-exp` | DeepSeek-V4-Flash-Vision-Exp(视觉) | DeepSeek |
|
|
304
313
|
|
|
305
314
|
## 开发
|
|
306
315
|
|
|
@@ -317,9 +326,9 @@ pnpm start
|
|
|
317
326
|
pnpm test
|
|
318
327
|
|
|
319
328
|
# 端到端测试(需在 .env.local 中配置 API Key)
|
|
320
|
-
pnpm test
|
|
329
|
+
pnpm test:e2e
|
|
321
330
|
```
|
|
322
331
|
|
|
323
332
|
## 许可
|
|
324
333
|
|
|
325
|
-
|
|
334
|
+
MIT
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoMigrateConfirmPlugin — 自动迁移「二次确认」插件(CLI 层)。
|
|
3
|
+
*
|
|
4
|
+
* 背景:SDK 的 `AutoMigratePlugin` 在 `usage.prompt_tokens` 超过阈值时**静默**触发迁移,
|
|
5
|
+
* 而迁移会保存当前对话并以交接文档开启新会话。为让用户对这次「上下文切换」有知情权与
|
|
6
|
+
* 否决权,CLI 在自动迁移前补一道二次确认。
|
|
7
|
+
*
|
|
8
|
+
* 职责边界(沿用 SDK 的分工,不重复实现「何时迁移」的语义):
|
|
9
|
+
* - 是否触发:本插件先向用户确认,得到许可后委托基类的 `onAfterSend` 完成阈值判断与迁移调用;
|
|
10
|
+
* - 实际迁移:仍由共享的 `TaskMigrationService` 实例执行(与 /migrate 手动迁移同一条链路)。
|
|
11
|
+
* 因此本插件的增量仅有一处:在超阈值与调用迁移之间插入一次确认。
|
|
12
|
+
*
|
|
13
|
+
* 交互约定:
|
|
14
|
+
* - 仅在 stdin 与 stdout **均为 TTY**(人类交互终端)时询问;
|
|
15
|
+
* - 非交互环境(管道、重定向、e2e 脚本)没有确认通道,保持既有行为——直接自动迁移,
|
|
16
|
+
* 不阻塞等待输入、不额外输出,管道语义不变;
|
|
17
|
+
* - 确认框默认「是」(回车即迁移),与 /migrate 手动迁移的默认值保持一致;
|
|
18
|
+
* - 用户拒绝时仅跳过**本次**迁移,不记录任何隐式状态:只要仍处于超限状态,下次发送后
|
|
19
|
+
* 会再次询问;跳过不影响当前对话(历史未被剔除,语义与迁移前一致)。
|
|
20
|
+
*/
|
|
21
|
+
import { AutoMigratePlugin } from "@ai-zen/agents-sdk";
|
|
22
|
+
import type { SendContext, TaskMigrationService } from "@ai-zen/agents-sdk";
|
|
23
|
+
/** 触发自动迁移时的用量信息(供确认文案与自定义询问实现使用) */
|
|
24
|
+
export interface AutoMigrateTriggerInfo {
|
|
25
|
+
/** 当前 prompt token 用量 */
|
|
26
|
+
promptTokens: number;
|
|
27
|
+
/** 上下文阈值(当前模型的 maxContextTokens) */
|
|
28
|
+
maxTokens: number;
|
|
29
|
+
}
|
|
30
|
+
export interface AutoMigrateConfirmOptions {
|
|
31
|
+
/** 迁移服务实例(与手动迁移 /migrate 共用同一实例) */
|
|
32
|
+
service: TaskMigrationService;
|
|
33
|
+
/** 触发迁移的上下文阈值 */
|
|
34
|
+
maxTokens: number;
|
|
35
|
+
/** 是否需要向用户确认;默认「stdin 与 stdout 均为 TTY」。可注入,便于单测 */
|
|
36
|
+
shouldConfirm?: () => boolean;
|
|
37
|
+
/** 确认实现;默认为 inquirer 确认框。可注入,便于单测 */
|
|
38
|
+
confirm?: (info: AutoMigrateTriggerInfo) => Promise<boolean>;
|
|
39
|
+
}
|
|
40
|
+
/** 默认交互判定:仅当 stdin 与 stdout 均为 TTY 时才具备确认通道 */
|
|
41
|
+
export declare function canPromptUser(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* 默认确认实现:inquirer 确认框。
|
|
44
|
+
* 默认「是」——回车即迁移,保持自动迁移的既有默认行为不被阻塞。
|
|
45
|
+
*/
|
|
46
|
+
export declare function confirmAutoMigrate(info: AutoMigrateTriggerInfo): Promise<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* 自动迁移二次确认插件。
|
|
49
|
+
*
|
|
50
|
+
* 继承 SDK 的 `AutoMigratePlugin` 以复用其触发语义(阈值判断 + 委托共享迁移服务),
|
|
51
|
+
* 仅在「超阈值」与「调用迁移」之间插入一次用户确认。
|
|
52
|
+
*/
|
|
53
|
+
export declare class AutoMigrateConfirmPlugin extends AutoMigratePlugin {
|
|
54
|
+
private readonly confirmOptions;
|
|
55
|
+
constructor(options: AutoMigrateConfirmOptions);
|
|
56
|
+
onAfterSend(ctx: SendContext): Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=auto-migrate-confirm-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-migrate-confirm-plugin.d.ts","sourceRoot":"","sources":["../src/auto-migrate-confirm-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,oCAAoC;AACpC,MAAM,WAAW,sBAAsB;IACrC,yBAAyB;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,oCAAoC;IACpC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC;IAC9B,qCAAqC;IACrC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D;AAED,+CAA+C;AAC/C,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,iBAAiB;IAC7D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA4B;gBAE/C,OAAO,EAAE,yBAAyB;IAKxC,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAmCnD"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoMigrateConfirmPlugin — 自动迁移「二次确认」插件(CLI 层)。
|
|
3
|
+
*
|
|
4
|
+
* 背景:SDK 的 `AutoMigratePlugin` 在 `usage.prompt_tokens` 超过阈值时**静默**触发迁移,
|
|
5
|
+
* 而迁移会保存当前对话并以交接文档开启新会话。为让用户对这次「上下文切换」有知情权与
|
|
6
|
+
* 否决权,CLI 在自动迁移前补一道二次确认。
|
|
7
|
+
*
|
|
8
|
+
* 职责边界(沿用 SDK 的分工,不重复实现「何时迁移」的语义):
|
|
9
|
+
* - 是否触发:本插件先向用户确认,得到许可后委托基类的 `onAfterSend` 完成阈值判断与迁移调用;
|
|
10
|
+
* - 实际迁移:仍由共享的 `TaskMigrationService` 实例执行(与 /migrate 手动迁移同一条链路)。
|
|
11
|
+
* 因此本插件的增量仅有一处:在超阈值与调用迁移之间插入一次确认。
|
|
12
|
+
*
|
|
13
|
+
* 交互约定:
|
|
14
|
+
* - 仅在 stdin 与 stdout **均为 TTY**(人类交互终端)时询问;
|
|
15
|
+
* - 非交互环境(管道、重定向、e2e 脚本)没有确认通道,保持既有行为——直接自动迁移,
|
|
16
|
+
* 不阻塞等待输入、不额外输出,管道语义不变;
|
|
17
|
+
* - 确认框默认「是」(回车即迁移),与 /migrate 手动迁移的默认值保持一致;
|
|
18
|
+
* - 用户拒绝时仅跳过**本次**迁移,不记录任何隐式状态:只要仍处于超限状态,下次发送后
|
|
19
|
+
* 会再次询问;跳过不影响当前对话(历史未被剔除,语义与迁移前一致)。
|
|
20
|
+
*/
|
|
21
|
+
import chalk from "chalk";
|
|
22
|
+
import inquirer from "inquirer";
|
|
23
|
+
import { AutoMigratePlugin } from "@ai-zen/agents-sdk";
|
|
24
|
+
/** 默认交互判定:仅当 stdin 与 stdout 均为 TTY 时才具备确认通道 */
|
|
25
|
+
export function canPromptUser() {
|
|
26
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 默认确认实现:inquirer 确认框。
|
|
30
|
+
* 默认「是」——回车即迁移,保持自动迁移的既有默认行为不被阻塞。
|
|
31
|
+
*/
|
|
32
|
+
export async function confirmAutoMigrate(info) {
|
|
33
|
+
const { confirmed } = await inquirer.prompt([
|
|
34
|
+
{
|
|
35
|
+
type: "confirm",
|
|
36
|
+
name: "confirmed",
|
|
37
|
+
message: `检测到上下文即将超限(${info.promptTokens}/${info.maxTokens} tokens),是否立即执行任务迁移?\n` +
|
|
38
|
+
"迁移将:生成交接文档 → 保存当前对话 → 开启新会话继续。",
|
|
39
|
+
default: true,
|
|
40
|
+
},
|
|
41
|
+
]);
|
|
42
|
+
return Boolean(confirmed);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 自动迁移二次确认插件。
|
|
46
|
+
*
|
|
47
|
+
* 继承 SDK 的 `AutoMigratePlugin` 以复用其触发语义(阈值判断 + 委托共享迁移服务),
|
|
48
|
+
* 仅在「超阈值」与「调用迁移」之间插入一次用户确认。
|
|
49
|
+
*/
|
|
50
|
+
export class AutoMigrateConfirmPlugin extends AutoMigratePlugin {
|
|
51
|
+
confirmOptions;
|
|
52
|
+
constructor(options) {
|
|
53
|
+
super({ service: options.service, maxTokens: options.maxTokens });
|
|
54
|
+
this.confirmOptions = options;
|
|
55
|
+
}
|
|
56
|
+
async onAfterSend(ctx) {
|
|
57
|
+
const { maxTokens, shouldConfirm = canPromptUser, confirm = confirmAutoMigrate, } = this.confirmOptions;
|
|
58
|
+
const promptTokens = ctx.agent.lastUsage?.prompt_tokens;
|
|
59
|
+
// 未超阈值(或无用量信息):无需询问,交由基类按原语义处理
|
|
60
|
+
if (promptTokens == null || promptTokens <= maxTokens) {
|
|
61
|
+
await super.onAfterSend(ctx);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// 非交互环境:没有确认通道,保持既有「静默自动迁移」行为,不阻塞、不额外输出
|
|
65
|
+
if (!shouldConfirm()) {
|
|
66
|
+
await super.onAfterSend(ctx);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const confirmed = await confirm({ promptTokens, maxTokens });
|
|
70
|
+
if (!confirmed) {
|
|
71
|
+
console.log(chalk.yellow("\n⏭️ 已跳过本次任务迁移,继续当前对话。\n"));
|
|
72
|
+
console.log(chalk.gray("💡 上下文仍接近上限:可随时输入 /migrate 手动迁移;若继续增长至严重超限,对话会被安全护栏中断。\n"));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// 用户已确认:交由基类完成「触发 + 委托共享迁移服务」的原逻辑
|
|
76
|
+
await super.onAfterSend(ctx);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=auto-migrate-confirm-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-migrate-confirm-plugin.js","sourceRoot":"","sources":["../src/auto-migrate-confirm-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAsBvD,+CAA+C;AAC/C,MAAM,UAAU,aAAa;IAC3B,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAA4B;IAE5B,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAyB;QAClE;YACE,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,WAAW;YACjB,OAAO,EACL,cAAc,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,wBAAwB;gBACzE,gCAAgC;YAClC,OAAO,EAAE,IAAI;SACd;KACF,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,wBAAyB,SAAQ,iBAAiB;IAC5C,cAAc,CAA4B;IAE3D,YAAY,OAAkC;QAC5C,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,GAAgB;QAChC,MAAM,EACJ,SAAS,EACT,aAAa,GAAG,aAAa,EAC7B,OAAO,GAAG,kBAAkB,GAC7B,GAAG,IAAI,CAAC,cAAc,CAAC;QAExB,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,aAAa,CAAC;QAExD,+BAA+B;QAC/B,IAAI,YAAY,IAAI,IAAI,IAAI,YAAY,IAAI,SAAS,EAAE,CAAC;YACtD,MAAM,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,wCAAwC;QACxC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;YACrB,MAAM,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CACR,0DAA0D,CAC3D,CACF,CAAC;YACF,OAAO;QACT,CAAC;QAED,kCAAkC;QAClC,MAAM,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/conversation-commands/help.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/conversation-commands/help.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD,wBAAsB,UAAU,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxE"}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
+
import { COMMAND_LABEL_WIDTH, getCommandHints } from "./registry.js";
|
|
2
3
|
export async function handleHelp(ctx) {
|
|
3
4
|
console.log(chalk.blue.bold("\n📖 可用命令:\n"));
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
console.log(
|
|
8
|
-
console.log(` ${chalk.cyan("/editor")} 使用系统编辑器输入长消息`);
|
|
9
|
-
console.log(` ${chalk.cyan("/clear")} 清屏`);
|
|
10
|
-
console.log(` ${chalk.cyan("/migrate")} 手动任务迁移(生成交接文档并开启新会话)`);
|
|
11
|
-
console.log(` ${chalk.cyan("/help")} 显示此帮助\n`);
|
|
5
|
+
for (const hint of getCommandHints()) {
|
|
6
|
+
console.log(` ${chalk.cyan(hint.label.padEnd(COMMAND_LABEL_WIDTH))}${chalk.gray(hint.description)}`);
|
|
7
|
+
}
|
|
8
|
+
console.log();
|
|
12
9
|
}
|
|
13
10
|
//# sourceMappingURL=help.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/conversation-commands/help.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/conversation-commands/help.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAwB;IACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IAE7C,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CACT,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CACzF,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ConversationContext } from "../types.js";
|
|
2
|
+
/** 全部命令名(含别名,升序) */
|
|
3
|
+
export { getCommandNames } from "./registry.js";
|
|
2
4
|
/**
|
|
3
5
|
* 判断输入是否为命令(以 / 开头)
|
|
4
6
|
*/
|
|
@@ -8,8 +10,4 @@ export declare function isCommand(input: string): boolean;
|
|
|
8
10
|
* @returns true 表示是命令且已处理,false 表示不是命令
|
|
9
11
|
*/
|
|
10
12
|
export declare function dispatchCommand(ctx: ConversationContext): Promise<boolean>;
|
|
11
|
-
/**
|
|
12
|
-
* 获取所有命令名称列表(用于提示信息)
|
|
13
|
-
*/
|
|
14
|
-
export declare function getCommandNames(): string[];
|
|
15
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conversation-commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAkB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conversation-commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAkB,MAAM,aAAa,CAAC;AA2ClE,oBAAoB;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,mBAAmB,GACvB,OAAO,CAAC,OAAO,CAAC,CAiBlB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getCommandHints } from "./registry.js";
|
|
1
2
|
import { handleExit } from "./exit.js";
|
|
2
3
|
import { handleSave } from "./save.js";
|
|
3
4
|
import { handleNew } from "./new.js";
|
|
@@ -7,12 +8,11 @@ import { handleClear } from "./clear.js";
|
|
|
7
8
|
import { handleHelp } from "./help.js";
|
|
8
9
|
import { handleMigrate } from "./migrate.js";
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
* key
|
|
11
|
+
* 命令处理函数表
|
|
12
|
+
* key 为主命令名(不含 / 前缀),命令名/别名/说明的声明见 ./registry.ts
|
|
12
13
|
*/
|
|
13
|
-
const
|
|
14
|
+
const handlers = {
|
|
14
15
|
exit: handleExit,
|
|
15
|
-
quit: handleExit,
|
|
16
16
|
save: handleSave,
|
|
17
17
|
new: handleNew,
|
|
18
18
|
back: handleBack,
|
|
@@ -21,6 +21,23 @@ const commands = {
|
|
|
21
21
|
help: handleHelp,
|
|
22
22
|
migrate: handleMigrate,
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* 命令注册表
|
|
26
|
+
* key 为命令名称(不含 / 前缀,含别名),value 为处理函数
|
|
27
|
+
* 别名按 registry 自动展开:新增别名只需改动 ./registry.ts
|
|
28
|
+
*/
|
|
29
|
+
const commands = {};
|
|
30
|
+
for (const hint of getCommandHints()) {
|
|
31
|
+
const primary = hint.names[0];
|
|
32
|
+
const handler = handlers[primary];
|
|
33
|
+
if (!handler) {
|
|
34
|
+
throw new Error(`对话命令 "${primary}" 已在 conversation-commands/registry.ts 声明,但未注册处理函数`);
|
|
35
|
+
}
|
|
36
|
+
for (const name of hint.names)
|
|
37
|
+
commands[name] = handler;
|
|
38
|
+
}
|
|
39
|
+
/** 全部命令名(含别名,升序) */
|
|
40
|
+
export { getCommandNames } from "./registry.js";
|
|
24
41
|
/**
|
|
25
42
|
* 判断输入是否为命令(以 / 开头)
|
|
26
43
|
*/
|
|
@@ -46,21 +63,4 @@ export async function dispatchCommand(ctx) {
|
|
|
46
63
|
await handler(ctx);
|
|
47
64
|
return true;
|
|
48
65
|
}
|
|
49
|
-
/**
|
|
50
|
-
* 获取所有命令名称列表(用于提示信息)
|
|
51
|
-
*/
|
|
52
|
-
export function getCommandNames() {
|
|
53
|
-
// 去重(exit 和 quit 指向同一处理函数)
|
|
54
|
-
const names = new Set();
|
|
55
|
-
names.add("exit");
|
|
56
|
-
names.add("quit");
|
|
57
|
-
names.add("save");
|
|
58
|
-
names.add("new");
|
|
59
|
-
names.add("back");
|
|
60
|
-
names.add("editor");
|
|
61
|
-
names.add("clear");
|
|
62
|
-
names.add("help");
|
|
63
|
-
names.add("migrate");
|
|
64
|
-
return Array.from(names).sort();
|
|
65
|
-
}
|
|
66
66
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/conversation-commands/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C;;;GAGG;AACH,MAAM,QAAQ,GAAmC;IAC/C,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/conversation-commands/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C;;;GAGG;AACH,MAAM,QAAQ,GAAmC;IAC/C,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,UAAU;IAChB,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,WAAW;IAClB,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,aAAa;CACvB,CAAC;AAEF;;;;GAIG;AACH,MAAM,QAAQ,GAAmC,EAAE,CAAC;AACpD,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,SAAS,OAAO,oDAAoD,CACrE,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK;QAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;AAC1D,CAAC;AAED,oBAAoB;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAwB;IAExB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IAExB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEpC,eAAe;IACf,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACpD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAElC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,uBAAuB,CAAC,CAAC;QACvD,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 对话命令元数据 — 对话命令清单的唯一来源
|
|
3
|
+
*
|
|
4
|
+
* 命令名、别名与说明集中声明于此,由三类消费方共用:
|
|
5
|
+
* - 分发:`./index.ts` 按主命令名装配处理函数表,并按别名自动展开
|
|
6
|
+
* - 帮助:`./help.ts` 渲染 `/help` 输出
|
|
7
|
+
* - 提示:`../slash-hint-prompt.ts` 渲染输入 `/` 时的实时候选提示
|
|
8
|
+
*
|
|
9
|
+
* 新增、改名或调整说明只需改动本文件。本模块为纯数据与纯函数,
|
|
10
|
+
* 不依赖 inquirer / chalk,可直接单测。
|
|
11
|
+
*/
|
|
12
|
+
/** 单个对话命令的元数据 */
|
|
13
|
+
export interface CommandMeta {
|
|
14
|
+
/** 主命令名(不含 `/` 前缀),同时是处理函数表的键 */
|
|
15
|
+
name: string;
|
|
16
|
+
/** 等价别名(不含 `/` 前缀) */
|
|
17
|
+
aliases?: string[];
|
|
18
|
+
/** 一句话说明 */
|
|
19
|
+
description: string;
|
|
20
|
+
}
|
|
21
|
+
/** 命令元数据表(数组顺序即展示顺序) */
|
|
22
|
+
export declare const COMMAND_REGISTRY: readonly CommandMeta[];
|
|
23
|
+
/** 命令展示条目:等价写法(如 `/exit` `/quit`)折叠为一条 */
|
|
24
|
+
export interface CommandHint {
|
|
25
|
+
/** 全部等价写法(不含 `/` 前缀),首个为主命令名 */
|
|
26
|
+
names: string[];
|
|
27
|
+
/** 展示用命令串,如 `/exit /quit` */
|
|
28
|
+
label: string;
|
|
29
|
+
/** 一句话说明 */
|
|
30
|
+
description: string;
|
|
31
|
+
}
|
|
32
|
+
/** 展开全部命令为展示条目(别名折叠) */
|
|
33
|
+
export declare function getCommandHints(): CommandHint[];
|
|
34
|
+
/**
|
|
35
|
+
* 命令列展示宽度:按最长展示命令串对齐,供 `/help` 与输入提示共用。
|
|
36
|
+
* 展示命令串均为 ASCII,`padEnd` 的字符数即显示宽度。
|
|
37
|
+
*/
|
|
38
|
+
export declare const COMMAND_LABEL_WIDTH: number;
|
|
39
|
+
/**
|
|
40
|
+
* 前缀匹配命令
|
|
41
|
+
* @param keyword 不含 `/` 前缀的输入片段;空串(即仅输入了 `/`)返回全部命令
|
|
42
|
+
*/
|
|
43
|
+
export declare function matchCommandHints(keyword: string): CommandHint[];
|
|
44
|
+
/** 全部命令名(含别名,升序),供启动横幅等场景展示 */
|
|
45
|
+
export declare function getCommandNames(): string[];
|
|
46
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,iBAAiB;AACjB,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAwB;AACxB,eAAO,MAAM,gBAAgB,EAAE,SAAS,WAAW,EASlD,CAAC;AAEF,0CAA0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAwB;AACxB,wBAAgB,eAAe,IAAI,WAAW,EAAE,CAS/C;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QACqC,CAAC;AAEtE;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAOhE;AAED,+BAA+B;AAC/B,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAM1C"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 对话命令元数据 — 对话命令清单的唯一来源
|
|
3
|
+
*
|
|
4
|
+
* 命令名、别名与说明集中声明于此,由三类消费方共用:
|
|
5
|
+
* - 分发:`./index.ts` 按主命令名装配处理函数表,并按别名自动展开
|
|
6
|
+
* - 帮助:`./help.ts` 渲染 `/help` 输出
|
|
7
|
+
* - 提示:`../slash-hint-prompt.ts` 渲染输入 `/` 时的实时候选提示
|
|
8
|
+
*
|
|
9
|
+
* 新增、改名或调整说明只需改动本文件。本模块为纯数据与纯函数,
|
|
10
|
+
* 不依赖 inquirer / chalk,可直接单测。
|
|
11
|
+
*/
|
|
12
|
+
/** 命令元数据表(数组顺序即展示顺序) */
|
|
13
|
+
export const COMMAND_REGISTRY = [
|
|
14
|
+
{ name: "exit", aliases: ["quit"], description: "退出对话(会提示是否保存)" },
|
|
15
|
+
{ name: "save", description: "保存当前对话" },
|
|
16
|
+
{ name: "new", description: "重置会话(清空历史)" },
|
|
17
|
+
{ name: "back", description: "撤回消息(可修改后重发)" },
|
|
18
|
+
{ name: "editor", description: "使用系统编辑器输入长消息" },
|
|
19
|
+
{ name: "clear", description: "清屏" },
|
|
20
|
+
{ name: "migrate", description: "手动任务迁移(生成交接文档并开启新会话)" },
|
|
21
|
+
{ name: "help", description: "显示此帮助" },
|
|
22
|
+
];
|
|
23
|
+
/** 展开全部命令为展示条目(别名折叠) */
|
|
24
|
+
export function getCommandHints() {
|
|
25
|
+
return COMMAND_REGISTRY.map((command) => {
|
|
26
|
+
const names = [command.name, ...(command.aliases ?? [])];
|
|
27
|
+
return {
|
|
28
|
+
names,
|
|
29
|
+
label: names.map((name) => `/${name}`).join(" "),
|
|
30
|
+
description: command.description,
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 命令列展示宽度:按最长展示命令串对齐,供 `/help` 与输入提示共用。
|
|
36
|
+
* 展示命令串均为 ASCII,`padEnd` 的字符数即显示宽度。
|
|
37
|
+
*/
|
|
38
|
+
export const COMMAND_LABEL_WIDTH = Math.max(...getCommandHints().map((hint) => hint.label.length)) + 3;
|
|
39
|
+
/**
|
|
40
|
+
* 前缀匹配命令
|
|
41
|
+
* @param keyword 不含 `/` 前缀的输入片段;空串(即仅输入了 `/`)返回全部命令
|
|
42
|
+
*/
|
|
43
|
+
export function matchCommandHints(keyword) {
|
|
44
|
+
const normalized = keyword.trim().toLowerCase();
|
|
45
|
+
if (!normalized)
|
|
46
|
+
return getCommandHints();
|
|
47
|
+
return getCommandHints().filter((hint) => hint.names.some((name) => name.startsWith(normalized)));
|
|
48
|
+
}
|
|
49
|
+
/** 全部命令名(含别名,升序),供启动横幅等场景展示 */
|
|
50
|
+
export function getCommandNames() {
|
|
51
|
+
const names = new Set();
|
|
52
|
+
for (const hint of getCommandHints()) {
|
|
53
|
+
for (const name of hint.names)
|
|
54
|
+
names.add(name);
|
|
55
|
+
}
|
|
56
|
+
return Array.from(names).sort();
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,wBAAwB;AACxB,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,eAAe,EAAE;IACjE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE;IACvC,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE;IAC1C,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE;IAC7C,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE;IAC/C,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE;IACpC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,sBAAsB,EAAE;IACxD,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE;CACvC,CAAC;AAYF,wBAAwB;AACxB,MAAM,UAAU,eAAe;IAC7B,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;QACzD,OAAO;YACL,KAAK;YACL,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAChD,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAC9B,IAAI,CAAC,GAAG,CAAC,GAAG,eAAe,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;AAEtE;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAChD,IAAI,CAAC,UAAU;QAAE,OAAO,eAAe,EAAE,CAAC;IAE1C,OAAO,eAAe,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CACvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CACvD,CAAC;AACJ,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,eAAe;IAC7B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,EAAE,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-runner.d.ts","sourceRoot":"","sources":["../src/conversation-runner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"conversation-runner.d.ts","sourceRoot":"","sources":["../src/conversation-runner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AA0D9C,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqJpF"}
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* CLI 层只负责:流式渲染、命令处理、UI 交互。
|
|
6
6
|
*/
|
|
7
7
|
import chalk from "chalk";
|
|
8
|
-
import inquirer from "inquirer";
|
|
9
8
|
import { AgentNS } from "@ai-zen/agents-core";
|
|
10
|
-
import {
|
|
9
|
+
import { AutoRefreshToolsPlugin, ContextGuardPlugin } from "@ai-zen/agents-sdk";
|
|
10
|
+
import { AutoMigrateConfirmPlugin } from "./auto-migrate-confirm-plugin.js";
|
|
11
|
+
import { SubAgentGuardInstallerPlugin } from "./sub-agent-guard-plugin.js";
|
|
11
12
|
import { DeltaRenderer } from "./delta-renderer.js";
|
|
12
13
|
import { createAgent } from "./agent-creator.js";
|
|
13
14
|
import { readConfig } from "./config.js";
|
|
@@ -18,6 +19,7 @@ import { createMigrationService } from "./migration-service.js";
|
|
|
18
19
|
import { ensureEndpointConfig } from "./config-wizard.js";
|
|
19
20
|
import { formatShortTime } from "./format-time.js";
|
|
20
21
|
import { dispatchCommand, getCommandNames } from "./conversation-commands/index.js";
|
|
22
|
+
import { askInput } from "./slash-hint-prompt.js";
|
|
21
23
|
// ==================== 发送消息 ====================
|
|
22
24
|
async function sendAndStream(ctx) {
|
|
23
25
|
console.log(chalk.green.bold("\n🤖 AI:"));
|
|
@@ -91,7 +93,13 @@ export async function runConversation(options) {
|
|
|
91
93
|
// 作为安全护栏置于迁移插件之前:防止读入超大文件等突发超限在迁移生效前撑爆上下文。
|
|
92
94
|
agent.use(new ContextGuardPlugin({ maxTokens }));
|
|
93
95
|
// autoMigrate — 检测 token 超限时自动迁移。仅负责触发(何时迁移),实际迁移委托给共享的 migrationService。
|
|
94
|
-
|
|
96
|
+
// 触发后先做一次「二次确认」(AutoMigrateConfirmPlugin,CLI 层):非交互环境无确认通道,
|
|
97
|
+
// 保持既有静默自动迁移行为;用户拒绝则跳过本次迁移、不改变当前对话。
|
|
98
|
+
agent.use(new AutoMigrateConfirmPlugin({ service: migrationService, maxTokens }));
|
|
99
|
+
// subAgentGuard — 子 Agent 上下文护栏:委派前给子 Agent 安插主 Agent 同款的
|
|
100
|
+
// ContextGuardPlugin(同一 maxTokens)。子 Agent 由 SDK 新建实例、不继承宿主插件
|
|
101
|
+
// (且走 run() 而非 send()),故必须经 onSubAgentStart 显式安插。
|
|
102
|
+
agent.use(new SubAgentGuardInstallerPlugin({ maxTokens }));
|
|
95
103
|
}
|
|
96
104
|
// 初始化所有插件
|
|
97
105
|
await agent.init();
|
|
@@ -115,23 +123,22 @@ export async function runConversation(options) {
|
|
|
115
123
|
process.stdout.write(chalk.red(`\n❌ 错误: ${error?.message || error}\n`));
|
|
116
124
|
};
|
|
117
125
|
// ============ 子 Agent 渲染 ============
|
|
118
|
-
const onSubAgent = (
|
|
119
|
-
const
|
|
120
|
-
const toolName = event.ctx?.function_call?.name || "子任务";
|
|
126
|
+
const onSubAgent = ({ subAgent, toolCallContext }) => {
|
|
127
|
+
const toolName = toolCallContext?.tool_call?.function?.name || "子任务";
|
|
121
128
|
process.stdout.write(chalk.yellow.bold(`\n 🧩 ${toolName}:\n`));
|
|
122
129
|
subAgent.events.on("open", onRun);
|
|
123
130
|
subAgent.events.on("chunk", onChunk);
|
|
124
131
|
subAgent.events.on("error", onError);
|
|
125
132
|
};
|
|
126
|
-
const onSubAgentEnd = ({
|
|
127
|
-
const toolName =
|
|
133
|
+
const onSubAgentEnd = ({ toolCallContext }) => {
|
|
134
|
+
const toolName = toolCallContext?.tool_call?.function?.name || "子任务";
|
|
128
135
|
process.stdout.write(chalk.gray(`\n ✅ ${toolName} 完成\n`));
|
|
129
136
|
};
|
|
130
137
|
// ============ 注册事件 ============
|
|
131
138
|
ctx.agent.events.on("open", onRun);
|
|
132
139
|
ctx.agent.events.on("chunk", onChunk);
|
|
133
140
|
ctx.agent.events.on("error", onError);
|
|
134
|
-
ctx.agent.events.on("sub-agent", onSubAgent);
|
|
141
|
+
ctx.agent.events.on("sub-agent-start", onSubAgent);
|
|
135
142
|
ctx.agent.events.on("sub-agent-end", onSubAgentEnd);
|
|
136
143
|
// ============ 初始消息 ============
|
|
137
144
|
if (query) {
|
|
@@ -141,15 +148,8 @@ export async function runConversation(options) {
|
|
|
141
148
|
}
|
|
142
149
|
// ============ 主循环 ============
|
|
143
150
|
while (ctx.running) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
type: "input",
|
|
147
|
-
name: "question",
|
|
148
|
-
message: chalk.cyan("你:"),
|
|
149
|
-
prefix: "💬",
|
|
150
|
-
},
|
|
151
|
-
]);
|
|
152
|
-
ctx.input = question.trim();
|
|
151
|
+
// 命令提示(输入 / 时列出候选命令)由输入提示自行渲染,此处只取输入内容
|
|
152
|
+
ctx.input = await askInput();
|
|
153
153
|
if (!ctx.input)
|
|
154
154
|
continue;
|
|
155
155
|
const handled = await dispatchCommand(ctx);
|
|
@@ -169,7 +169,7 @@ export async function runConversation(options) {
|
|
|
169
169
|
ctx.agent.events.off("open", onRun);
|
|
170
170
|
ctx.agent.events.off("chunk", onChunk);
|
|
171
171
|
ctx.agent.events.off("error", onError);
|
|
172
|
-
ctx.agent.events.off("sub-agent", onSubAgent);
|
|
172
|
+
ctx.agent.events.off("sub-agent-start", onSubAgent);
|
|
173
173
|
ctx.agent.events.off("sub-agent-end", onSubAgentEnd);
|
|
174
174
|
console.log(chalk.blue.bold("\n👋 再见!\n"));
|
|
175
175
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-runner.js","sourceRoot":"","sources":["../src/conversation-runner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,
|
|
1
|
+
{"version":3,"file":"conversation-runner.js","sourceRoot":"","sources":["../src/conversation-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 对话输入提示 — 输入 `/` 时在输入行下方实时列出可用命令
|
|
3
|
+
*
|
|
4
|
+
* 实现方式:继承 inquirer 的 input 提示,仅覆写 `render`,把候选命令作为
|
|
5
|
+
* 底栏(bottomContent)交给 inquirer 的 ScreenManager 渲染,从而复用其折行、
|
|
6
|
+
* 终端缩放、擦除与光标归位处理,与其它提示的渲染行为保持一致。
|
|
7
|
+
*
|
|
8
|
+
* 设计边界:
|
|
9
|
+
* - 非 TTY(stdin/stdout 被重定向、e2e 脚本)不渲染提示,退化为普通输入行;
|
|
10
|
+
* - 仅作提示,不改变提交语义:回车始终提交当前输入原文,由
|
|
11
|
+
* `dispatchCommand` 按精确命令名分发(不做前缀补全、不做高亮选择);
|
|
12
|
+
* - 普通聊天内容(非 `/` 开头)不产生任何提示。
|
|
13
|
+
*/
|
|
14
|
+
import InputPrompt from "inquirer/lib/prompts/input.js";
|
|
15
|
+
/** 注册到 inquirer 的自定义提示类型名 */
|
|
16
|
+
export declare const SLASH_HINT_PROMPT_TYPE = "conversationInput";
|
|
17
|
+
/**
|
|
18
|
+
* 生成命令提示底栏文本(纯函数,便于单测)
|
|
19
|
+
* @param line 当前输入行;非 `/` 开头一律返回空串
|
|
20
|
+
*/
|
|
21
|
+
export declare function renderCommandHint(line: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* 带命令提示的对话输入提示
|
|
24
|
+
*
|
|
25
|
+
* `render` 为 inquirer@9 `lib/prompts/input.js#render` 的等价实现,差异仅在于
|
|
26
|
+
* 额外注入命令提示底栏;升级 inquirer 主版本时需比对上游实现(见
|
|
27
|
+
* `src/typings/inquirer-internals.d.ts` 的说明)。
|
|
28
|
+
*
|
|
29
|
+
* 导出仅为注册(`registerSlashHintPrompt`)与单测使用,业务侧请使用 `askInput`。
|
|
30
|
+
*/
|
|
31
|
+
export declare class SlashHintPrompt extends InputPrompt {
|
|
32
|
+
render(error?: string): void;
|
|
33
|
+
}
|
|
34
|
+
/** 注册自定义提示类型(幂等) */
|
|
35
|
+
export declare function registerSlashHintPrompt(): void;
|
|
36
|
+
/**
|
|
37
|
+
* 读取一行对话输入
|
|
38
|
+
* @returns 去除首尾空白后的输入内容(用户直接回车时为空串)
|
|
39
|
+
*/
|
|
40
|
+
export declare function askInput(): Promise<string>;
|
|
41
|
+
//# sourceMappingURL=slash-hint-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slash-hint-prompt.d.ts","sourceRoot":"","sources":["../src/slash-hint-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,WAAW,MAAM,+BAA+B,CAAC;AAMxD,6BAA6B;AAC7B,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAK1D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYtD;AAED;;;;;;;;GAQG;AACH,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;CAyB7B;AAKD,oBAAoB;AACpB,wBAAgB,uBAAuB,IAAI,IAAI,CAI9C;AAED;;;GAGG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAahD"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 对话输入提示 — 输入 `/` 时在输入行下方实时列出可用命令
|
|
3
|
+
*
|
|
4
|
+
* 实现方式:继承 inquirer 的 input 提示,仅覆写 `render`,把候选命令作为
|
|
5
|
+
* 底栏(bottomContent)交给 inquirer 的 ScreenManager 渲染,从而复用其折行、
|
|
6
|
+
* 终端缩放、擦除与光标归位处理,与其它提示的渲染行为保持一致。
|
|
7
|
+
*
|
|
8
|
+
* 设计边界:
|
|
9
|
+
* - 非 TTY(stdin/stdout 被重定向、e2e 脚本)不渲染提示,退化为普通输入行;
|
|
10
|
+
* - 仅作提示,不改变提交语义:回车始终提交当前输入原文,由
|
|
11
|
+
* `dispatchCommand` 按精确命令名分发(不做前缀补全、不做高亮选择);
|
|
12
|
+
* - 普通聊天内容(非 `/` 开头)不产生任何提示。
|
|
13
|
+
*/
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import inquirer from "inquirer";
|
|
16
|
+
import InputPrompt from "inquirer/lib/prompts/input.js";
|
|
17
|
+
import { COMMAND_LABEL_WIDTH, matchCommandHints, } from "./conversation-commands/registry.js";
|
|
18
|
+
/** 注册到 inquirer 的自定义提示类型名 */
|
|
19
|
+
export const SLASH_HINT_PROMPT_TYPE = "conversationInput";
|
|
20
|
+
/** 无匹配命令时的提示文案 */
|
|
21
|
+
const NO_MATCH_HINT = "无匹配命令(输入 /help 查看全部)";
|
|
22
|
+
/**
|
|
23
|
+
* 生成命令提示底栏文本(纯函数,便于单测)
|
|
24
|
+
* @param line 当前输入行;非 `/` 开头一律返回空串
|
|
25
|
+
*/
|
|
26
|
+
export function renderCommandHint(line) {
|
|
27
|
+
if (!line.startsWith("/"))
|
|
28
|
+
return "";
|
|
29
|
+
const hints = matchCommandHints(line.slice(1));
|
|
30
|
+
if (hints.length === 0)
|
|
31
|
+
return " " + chalk.gray(NO_MATCH_HINT);
|
|
32
|
+
return hints
|
|
33
|
+
.map((hint) => ` ${chalk.cyan(hint.label.padEnd(COMMAND_LABEL_WIDTH))}${chalk.gray(hint.description)}`)
|
|
34
|
+
.join("\n");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 带命令提示的对话输入提示
|
|
38
|
+
*
|
|
39
|
+
* `render` 为 inquirer@9 `lib/prompts/input.js#render` 的等价实现,差异仅在于
|
|
40
|
+
* 额外注入命令提示底栏;升级 inquirer 主版本时需比对上游实现(见
|
|
41
|
+
* `src/typings/inquirer-internals.d.ts` 的说明)。
|
|
42
|
+
*
|
|
43
|
+
* 导出仅为注册(`registerSlashHintPrompt`)与单测使用,业务侧请使用 `askInput`。
|
|
44
|
+
*/
|
|
45
|
+
export class SlashHintPrompt extends InputPrompt {
|
|
46
|
+
render(error) {
|
|
47
|
+
const isFinal = this.status === "answered";
|
|
48
|
+
const appendContent = isFinal ? this.answer : this.rl.line;
|
|
49
|
+
const { transformer } = this.opt;
|
|
50
|
+
let message = this.getQuestion();
|
|
51
|
+
message += transformer
|
|
52
|
+
? transformer(appendContent, this.answers, { isFinal })
|
|
53
|
+
: isFinal
|
|
54
|
+
? chalk.cyan(appendContent)
|
|
55
|
+
: appendContent;
|
|
56
|
+
// 底栏:命令提示(仅真实终端、且尚未提交时渲染)
|
|
57
|
+
let bottomContent = !isFinal && process.stdout.isTTY ? renderCommandHint(this.rl.line) : "";
|
|
58
|
+
if (error) {
|
|
59
|
+
const errorLine = chalk.red(">> ") + error;
|
|
60
|
+
bottomContent = bottomContent
|
|
61
|
+
? `${bottomContent}\n${errorLine}`
|
|
62
|
+
: errorLine;
|
|
63
|
+
}
|
|
64
|
+
this.screen.render(message, bottomContent);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** 是否已注册(避免重复注册同一提示类型) */
|
|
68
|
+
let registered = false;
|
|
69
|
+
/** 注册自定义提示类型(幂等) */
|
|
70
|
+
export function registerSlashHintPrompt() {
|
|
71
|
+
if (registered)
|
|
72
|
+
return;
|
|
73
|
+
inquirer.registerPrompt(SLASH_HINT_PROMPT_TYPE, SlashHintPrompt);
|
|
74
|
+
registered = true;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 读取一行对话输入
|
|
78
|
+
* @returns 去除首尾空白后的输入内容(用户直接回车时为空串)
|
|
79
|
+
*/
|
|
80
|
+
export async function askInput() {
|
|
81
|
+
registerSlashHintPrompt();
|
|
82
|
+
const { question } = await inquirer.prompt([
|
|
83
|
+
{
|
|
84
|
+
type: SLASH_HINT_PROMPT_TYPE,
|
|
85
|
+
name: "question",
|
|
86
|
+
message: chalk.cyan("你:"),
|
|
87
|
+
prefix: "💬",
|
|
88
|
+
},
|
|
89
|
+
]);
|
|
90
|
+
return (question ?? "").trim();
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=slash-hint-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slash-hint-prompt.js","sourceRoot":"","sources":["../src/slash-hint-prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 子 Agent 护栏安装器(CLI 层)— SubAgentGuardInstallerPlugin
|
|
3
|
+
*
|
|
4
|
+
* 背景:SDK 的子 Agent 由 `AgentTool` / `AgentToolLazy` 在委派时 `new Agent({...})` 构建,
|
|
5
|
+
* 新建实例不携带任何插件(`Agent._plugins` 每实例私有,不向子 Agent 传播),且子 Agent 走
|
|
6
|
+
* `run()` 而非 `send()`(`onBeforeSend` / `onAfterSend` 不会触发)。因此主 Agent 上的
|
|
7
|
+
* `ContextGuardPlugin` 对子 Agent 完全无效:子 Agent 的内循环没有上下文 token 护栏。
|
|
8
|
+
*
|
|
9
|
+
* 介入点:core 4.2.0 的 `onSubAgentStart` 钩子在「子 Agent 已构建、尚未 run()」时由宿主 Agent
|
|
10
|
+
* 分发,载荷携带子 Agent 实例。`use()` 只是把插件推入 `_plugins`,而钩子分发每次都实时遍历
|
|
11
|
+
* 该列表,故在钩子内安插对**本次 run 立即生效**(无需 init;AgentTool 也不会调用子 Agent 的
|
|
12
|
+
* init)。
|
|
13
|
+
*
|
|
14
|
+
* 约束口径(与主 Agent 一致,仅此一项):把主 Agent 同款的 `ContextGuardPlugin` 装到子 Agent 上
|
|
15
|
+
* —— 同一 `maxTokens`(当前模型 `maxContextTokens`)、同样不传 ratio(沿用 SDK 默认 1.5),
|
|
16
|
+
* 使「上下文 token 超过 maxTokens × 1.5 即中断」对子 Agent 同样成立。
|
|
17
|
+
* **不设**轮次上限,**不设**工具调用次数上限。
|
|
18
|
+
*
|
|
19
|
+
* 中断语义:抛错即结束子 Agent 的 run;异常经 `AgentTool` 的 finally(分发 onSubAgentEnd)
|
|
20
|
+
* 上抛至父 Agent,因父 Agent 默认 `allowJsonParseError = true` 而降级为一条工具结果文本
|
|
21
|
+
* (`执行工具 X 时出错: …`),父 Agent 继续下一轮——即「软中断」:停掉越界的子 Agent,但不
|
|
22
|
+
* 终止用户对话(如需硬停,父 Agent 须设 allowJsonParseError=false)。
|
|
23
|
+
*
|
|
24
|
+
* 覆盖范围:仅覆盖 core 的 `AgentTool` / `AgentToolLazy` 两条委派路径(均分发 onSubAgentStart)。
|
|
25
|
+
* SDK 的 `call_skill_sub_agent`(技能子 Agent)不分发该钩子,暂不覆盖。
|
|
26
|
+
*/
|
|
27
|
+
import type { AgentPlugin } from "@ai-zen/agents-sdk";
|
|
28
|
+
import type { SubAgentContext } from "@ai-zen/agents-core";
|
|
29
|
+
export interface SubAgentGuardOptions {
|
|
30
|
+
/** 子 Agent 的上下文 token 阈值;与主 Agent 同源(当前模型的 `maxContextTokens`) */
|
|
31
|
+
maxTokens: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 子 Agent 护栏安装器(装在**宿主 Agent** 上)。
|
|
35
|
+
*
|
|
36
|
+
* 每次委派边界把 `ContextGuardPlugin` 装到子 Agent 身上(阈值与主 Agent 相同),并递归安插
|
|
37
|
+
* 自身,使子 Agent 再委派(孙级)时同样受约束。始终返回 undefined,永不拒绝委派——是否中断
|
|
38
|
+
* 由 `ContextGuardPlugin` 按阈值决定。
|
|
39
|
+
*/
|
|
40
|
+
export declare class SubAgentGuardInstallerPlugin implements AgentPlugin {
|
|
41
|
+
private readonly maxTokens;
|
|
42
|
+
constructor(options: SubAgentGuardOptions);
|
|
43
|
+
onSubAgentStart({ subAgent }: SubAgentContext): void;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=sub-agent-guard-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sub-agent-guard-plugin.d.ts","sourceRoot":"","sources":["../src/sub-agent-guard-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,qBAAa,4BAA6B,YAAW,WAAW;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,EAAE,oBAAoB;IAIzC,eAAe,CAAC,EAAE,QAAQ,EAAE,EAAE,eAAe,GAAG,IAAI;CASrD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 子 Agent 护栏安装器(CLI 层)— SubAgentGuardInstallerPlugin
|
|
3
|
+
*
|
|
4
|
+
* 背景:SDK 的子 Agent 由 `AgentTool` / `AgentToolLazy` 在委派时 `new Agent({...})` 构建,
|
|
5
|
+
* 新建实例不携带任何插件(`Agent._plugins` 每实例私有,不向子 Agent 传播),且子 Agent 走
|
|
6
|
+
* `run()` 而非 `send()`(`onBeforeSend` / `onAfterSend` 不会触发)。因此主 Agent 上的
|
|
7
|
+
* `ContextGuardPlugin` 对子 Agent 完全无效:子 Agent 的内循环没有上下文 token 护栏。
|
|
8
|
+
*
|
|
9
|
+
* 介入点:core 4.2.0 的 `onSubAgentStart` 钩子在「子 Agent 已构建、尚未 run()」时由宿主 Agent
|
|
10
|
+
* 分发,载荷携带子 Agent 实例。`use()` 只是把插件推入 `_plugins`,而钩子分发每次都实时遍历
|
|
11
|
+
* 该列表,故在钩子内安插对**本次 run 立即生效**(无需 init;AgentTool 也不会调用子 Agent 的
|
|
12
|
+
* init)。
|
|
13
|
+
*
|
|
14
|
+
* 约束口径(与主 Agent 一致,仅此一项):把主 Agent 同款的 `ContextGuardPlugin` 装到子 Agent 上
|
|
15
|
+
* —— 同一 `maxTokens`(当前模型 `maxContextTokens`)、同样不传 ratio(沿用 SDK 默认 1.5),
|
|
16
|
+
* 使「上下文 token 超过 maxTokens × 1.5 即中断」对子 Agent 同样成立。
|
|
17
|
+
* **不设**轮次上限,**不设**工具调用次数上限。
|
|
18
|
+
*
|
|
19
|
+
* 中断语义:抛错即结束子 Agent 的 run;异常经 `AgentTool` 的 finally(分发 onSubAgentEnd)
|
|
20
|
+
* 上抛至父 Agent,因父 Agent 默认 `allowJsonParseError = true` 而降级为一条工具结果文本
|
|
21
|
+
* (`执行工具 X 时出错: …`),父 Agent 继续下一轮——即「软中断」:停掉越界的子 Agent,但不
|
|
22
|
+
* 终止用户对话(如需硬停,父 Agent 须设 allowJsonParseError=false)。
|
|
23
|
+
*
|
|
24
|
+
* 覆盖范围:仅覆盖 core 的 `AgentTool` / `AgentToolLazy` 两条委派路径(均分发 onSubAgentStart)。
|
|
25
|
+
* SDK 的 `call_skill_sub_agent`(技能子 Agent)不分发该钩子,暂不覆盖。
|
|
26
|
+
*/
|
|
27
|
+
import { ContextGuardPlugin } from "@ai-zen/agents-sdk";
|
|
28
|
+
/**
|
|
29
|
+
* 子 Agent 护栏安装器(装在**宿主 Agent** 上)。
|
|
30
|
+
*
|
|
31
|
+
* 每次委派边界把 `ContextGuardPlugin` 装到子 Agent 身上(阈值与主 Agent 相同),并递归安插
|
|
32
|
+
* 自身,使子 Agent 再委派(孙级)时同样受约束。始终返回 undefined,永不拒绝委派——是否中断
|
|
33
|
+
* 由 `ContextGuardPlugin` 按阈值决定。
|
|
34
|
+
*/
|
|
35
|
+
export class SubAgentGuardInstallerPlugin {
|
|
36
|
+
maxTokens;
|
|
37
|
+
constructor(options) {
|
|
38
|
+
this.maxTokens = options.maxTokens;
|
|
39
|
+
}
|
|
40
|
+
onSubAgentStart({ subAgent }) {
|
|
41
|
+
// 与主 Agent 完全同款:同一 maxTokens,不传 ratio(沿用 ContextGuardPlugin 默认 1.5)
|
|
42
|
+
subAgent.use(new ContextGuardPlugin({ maxTokens: this.maxTokens }));
|
|
43
|
+
// 传染到孙级:子 Agent 若再委派,其子 Agent 同样被安插
|
|
44
|
+
subAgent.use(new SubAgentGuardInstallerPlugin({ maxTokens: this.maxTokens }));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=sub-agent-guard-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sub-agent-guard-plugin.js","sourceRoot":"","sources":["../src/sub-agent-guard-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AASxD;;;;;;GAMG;AACH,MAAM,OAAO,4BAA4B;IACtB,SAAS,CAAS;IAEnC,YAAY,OAA6B;QACvC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACrC,CAAC;IAED,eAAe,CAAC,EAAE,QAAQ,EAAmB;QAC3C,oEAAoE;QACpE,QAAQ,CAAC,GAAG,CAAC,IAAI,kBAAkB,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAEpE,oCAAoC;QACpC,QAAQ,CAAC,GAAG,CACV,IAAI,4BAA4B,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAChE,CAAC;IACJ,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-zen/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "AI-ZEN CLI - interactive conversation terminal with file tools and draft recovery",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"author": "LZQCN",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@ai-zen/agents-core": "^4.
|
|
24
|
-
"@ai-zen/agents-sdk": "^0.
|
|
23
|
+
"@ai-zen/agents-core": "^4.2.0",
|
|
24
|
+
"@ai-zen/agents-sdk": "^0.10.0",
|
|
25
25
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
26
26
|
"chalk": "^5.3.0",
|
|
27
27
|
"dayjs": "^1.11.21",
|