knight-agent 1.1.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/Host.d.ts +23 -0
- package/Host.d.ts.map +1 -0
- package/Host.js +23 -0
- package/Host.js.map +1 -0
- package/base/AbstractAgent.d.ts +100 -0
- package/base/AbstractAgent.d.ts.map +1 -0
- package/base/AbstractAgent.js +23 -0
- package/base/AbstractAgent.js.map +1 -0
- package/base/AbstractDialog.d.ts +54 -0
- package/base/AbstractDialog.d.ts.map +1 -0
- package/base/AbstractDialog.js +86 -0
- package/base/AbstractDialog.js.map +1 -0
- package/base/AbstractModule.d.ts +7 -0
- package/base/AbstractModule.d.ts.map +1 -0
- package/base/AbstractModule.js +13 -0
- package/base/AbstractModule.js.map +1 -0
- package/base/AbstractObject.d.ts +18 -0
- package/base/AbstractObject.d.ts.map +1 -0
- package/base/AbstractObject.js +25 -0
- package/base/AbstractObject.js.map +1 -0
- package/base/AbstractReason.d.ts +44 -0
- package/base/AbstractReason.d.ts.map +1 -0
- package/base/AbstractReason.js +23 -0
- package/base/AbstractReason.js.map +1 -0
- package/base/AbstractSkill.d.ts +25 -0
- package/base/AbstractSkill.d.ts.map +1 -0
- package/base/AbstractSkill.js +3 -0
- package/base/AbstractSkill.js.map +1 -0
- package/base/AbstractTool.d.ts +34 -0
- package/base/AbstractTool.d.ts.map +1 -0
- package/base/AbstractTool.js +3 -0
- package/base/AbstractTool.js.map +1 -0
- package/base/index.d.ts +8 -0
- package/base/index.d.ts.map +1 -0
- package/base/index.js +24 -0
- package/base/index.js.map +1 -0
- package/docs/ARCHITECTURE.md +601 -0
- package/docs/README.md +562 -0
- package/index.d.ts +4 -0
- package/index.d.ts.map +1 -0
- package/index.js +25 -0
- package/index.js.map +1 -0
- package/module/AgentModule/Agent.d.ts +55 -0
- package/module/AgentModule/Agent.d.ts.map +1 -0
- package/module/AgentModule/Agent.js +210 -0
- package/module/AgentModule/Agent.js.map +1 -0
- package/module/AgentModule/AgentModule.d.ts +26 -0
- package/module/AgentModule/AgentModule.d.ts.map +1 -0
- package/module/AgentModule/AgentModule.js +66 -0
- package/module/AgentModule/AgentModule.js.map +1 -0
- package/module/AgentModule/Memory.d.ts +55 -0
- package/module/AgentModule/Memory.d.ts.map +1 -0
- package/module/AgentModule/Memory.js +288 -0
- package/module/AgentModule/Memory.js.map +1 -0
- package/module/AgentModule/index.d.ts +2 -0
- package/module/AgentModule/index.d.ts.map +1 -0
- package/module/AgentModule/index.js +18 -0
- package/module/AgentModule/index.js.map +1 -0
- package/module/DialogModule/Dialog.d.ts +14 -0
- package/module/DialogModule/Dialog.d.ts.map +1 -0
- package/module/DialogModule/Dialog.js +27 -0
- package/module/DialogModule/Dialog.js.map +1 -0
- package/module/DialogModule/DialogModule.d.ts +39 -0
- package/module/DialogModule/DialogModule.d.ts.map +1 -0
- package/module/DialogModule/DialogModule.js +118 -0
- package/module/DialogModule/DialogModule.js.map +1 -0
- package/module/DialogModule/index.d.ts +3 -0
- package/module/DialogModule/index.d.ts.map +1 -0
- package/module/DialogModule/index.js +19 -0
- package/module/DialogModule/index.js.map +1 -0
- package/module/ReasonModule/ChainReason.d.ts +11 -0
- package/module/ReasonModule/ChainReason.d.ts.map +1 -0
- package/module/ReasonModule/ChainReason.js +34 -0
- package/module/ReasonModule/ChainReason.js.map +1 -0
- package/module/ReasonModule/CommanderReason.d.ts +15 -0
- package/module/ReasonModule/CommanderReason.d.ts.map +1 -0
- package/module/ReasonModule/CommanderReason.js +151 -0
- package/module/ReasonModule/CommanderReason.js.map +1 -0
- package/module/ReasonModule/CompetitiveReason.d.ts +13 -0
- package/module/ReasonModule/CompetitiveReason.d.ts.map +1 -0
- package/module/ReasonModule/CompetitiveReason.js +133 -0
- package/module/ReasonModule/CompetitiveReason.js.map +1 -0
- package/module/ReasonModule/PlanReason.d.ts +25 -0
- package/module/ReasonModule/PlanReason.d.ts.map +1 -0
- package/module/ReasonModule/PlanReason.js +133 -0
- package/module/ReasonModule/PlanReason.js.map +1 -0
- package/module/ReasonModule/ReasonModule.d.ts +41 -0
- package/module/ReasonModule/ReasonModule.d.ts.map +1 -0
- package/module/ReasonModule/ReasonModule.js +83 -0
- package/module/ReasonModule/ReasonModule.js.map +1 -0
- package/module/ReasonModule/ReflectReason.d.ts +15 -0
- package/module/ReasonModule/ReflectReason.d.ts.map +1 -0
- package/module/ReasonModule/ReflectReason.js +86 -0
- package/module/ReasonModule/ReflectReason.js.map +1 -0
- package/module/ReasonModule/TreeReason.d.ts +16 -0
- package/module/ReasonModule/TreeReason.d.ts.map +1 -0
- package/module/ReasonModule/TreeReason.js +139 -0
- package/module/ReasonModule/TreeReason.js.map +1 -0
- package/module/ReasonModule/index.d.ts +8 -0
- package/module/ReasonModule/index.d.ts.map +1 -0
- package/module/ReasonModule/index.js +24 -0
- package/module/ReasonModule/index.js.map +1 -0
- package/module/SkillModule/SkillModule.d.ts +42 -0
- package/module/SkillModule/SkillModule.d.ts.map +1 -0
- package/module/SkillModule/SkillModule.js +134 -0
- package/module/SkillModule/SkillModule.js.map +1 -0
- package/module/SkillModule/index.d.ts +2 -0
- package/module/SkillModule/index.d.ts.map +1 -0
- package/module/SkillModule/index.js +18 -0
- package/module/SkillModule/index.js.map +1 -0
- package/module/ToolModule/ToolModule.d.ts +57 -0
- package/module/ToolModule/ToolModule.d.ts.map +1 -0
- package/module/ToolModule/ToolModule.js +220 -0
- package/module/ToolModule/ToolModule.js.map +1 -0
- package/module/ToolModule/ToolRAG.d.ts +38 -0
- package/module/ToolModule/ToolRAG.d.ts.map +1 -0
- package/module/ToolModule/ToolRAG.js +124 -0
- package/module/ToolModule/ToolRAG.js.map +1 -0
- package/module/ToolModule/index.d.ts +3 -0
- package/module/ToolModule/index.d.ts.map +1 -0
- package/module/ToolModule/index.js +19 -0
- package/module/ToolModule/index.js.map +1 -0
- package/module/index.d.ts +6 -0
- package/module/index.d.ts.map +1 -0
- package/module/index.js +22 -0
- package/module/index.js.map +1 -0
- package/package.json +19 -0
- package/utility/InterfaceUtility.d.ts +14 -0
- package/utility/InterfaceUtility.d.ts.map +1 -0
- package/utility/InterfaceUtility.js +3 -0
- package/utility/InterfaceUtility.js.map +1 -0
- package/utility/LogUtility.d.ts +41 -0
- package/utility/LogUtility.d.ts.map +1 -0
- package/utility/LogUtility.js +70 -0
- package/utility/LogUtility.js.map +1 -0
- package/utility/NetworkUtility.d.ts +91 -0
- package/utility/NetworkUtility.d.ts.map +1 -0
- package/utility/NetworkUtility.js +104 -0
- package/utility/NetworkUtility.js.map +1 -0
- package/utility/ObjectUtility.d.ts +134 -0
- package/utility/ObjectUtility.d.ts.map +1 -0
- package/utility/ObjectUtility.js +313 -0
- package/utility/ObjectUtility.js.map +1 -0
- package/utility/OpenAIUtility.d.ts +333 -0
- package/utility/OpenAIUtility.d.ts.map +1 -0
- package/utility/OpenAIUtility.js +95 -0
- package/utility/OpenAIUtility.js.map +1 -0
- package/utility/PromiseUtility.d.ts +9 -0
- package/utility/PromiseUtility.d.ts.map +1 -0
- package/utility/PromiseUtility.js +16 -0
- package/utility/PromiseUtility.js.map +1 -0
- package/utility/StringUtility.d.ts +10 -0
- package/utility/StringUtility.d.ts.map +1 -0
- package/utility/StringUtility.js +42 -0
- package/utility/StringUtility.js.map +1 -0
- package/utility/TimeUtility.d.ts +10 -0
- package/utility/TimeUtility.d.ts.map +1 -0
- package/utility/TimeUtility.js +24 -0
- package/utility/TimeUtility.js.map +1 -0
- package/utility/index.d.ts +9 -0
- package/utility/index.d.ts.map +1 -0
- package/utility/index.js +25 -0
- package/utility/index.js.map +1 -0
package/docs/README.md
ADDED
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
# Knight Agent 2.0 — 使用手册
|
|
2
|
+
|
|
3
|
+
基于 DeepSeek API 的模块化 TypeScript AI Agent 框架。提供 6 种内置推理策略、工具管理、技能能力包、对话持久化和多级 Token 优化。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 目录
|
|
8
|
+
|
|
9
|
+
- [架构概览](#架构概览)
|
|
10
|
+
- [快速开始](#快速开始)
|
|
11
|
+
- [配置](#一配置-agentconfig)
|
|
12
|
+
- [工具 Tool](#二工具-tool)
|
|
13
|
+
- [技能 Skill](#三技能-skill)
|
|
14
|
+
- [对话 Dialog](#四对话-dialog)
|
|
15
|
+
- [推理策略 Reason](#五推理策略-reason)
|
|
16
|
+
- [两个执行路径对比](#六两个执行路径对比)
|
|
17
|
+
- [Token 优化体系](#七token-优化体系)
|
|
18
|
+
- [持久化与快照](#八持久化与快照)
|
|
19
|
+
- [完整示例](#九完整示例多设备控制场景)
|
|
20
|
+
- [Host 模块一览](#十host-模块一览)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 架构概览
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
┌─────────────────────────────────────────────────┐
|
|
28
|
+
│ Host (单例) │
|
|
29
|
+
│ .toolModule .skillModule .reasonModule │
|
|
30
|
+
│ .agentModule .dialogModule │
|
|
31
|
+
└─────────────────────────────────────────────────┘
|
|
32
|
+
↑ 业务层通过 Host.Instance 访问所有模块
|
|
33
|
+
|
|
34
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
35
|
+
│ Tool │ │ Skill │ │ Reason │
|
|
36
|
+
│ 单函数 │───→│ 工具包 │ │ 推理策略 │
|
|
37
|
+
│ 描述符 │ │ +prompt │ │ 6种模式 │
|
|
38
|
+
└──────────┘ └────┬─────┘ └────┬─────┘
|
|
39
|
+
│ │
|
|
40
|
+
▼ ▼
|
|
41
|
+
┌──────────────────────────┐
|
|
42
|
+
│ Dialog │
|
|
43
|
+
│ 持久化 Agent + 策略绑定 │
|
|
44
|
+
│ Skill 作用域控制工具可见 │
|
|
45
|
+
└──────────┬───────────────┘
|
|
46
|
+
│
|
|
47
|
+
▼
|
|
48
|
+
┌──────────────────────────┐
|
|
49
|
+
│ Agent │
|
|
50
|
+
│ 消息缓存 + ReAct 主循环 │
|
|
51
|
+
│ 上下文窗口自动优化 │
|
|
52
|
+
└──────────────────────────┘
|
|
53
|
+
|
|
54
|
+
工具选择管线:
|
|
55
|
+
用户输入
|
|
56
|
+
→ Skill 过滤: resolveTools(dialogId) → 候选工具名
|
|
57
|
+
→ ToolRAG 语义排序: selectTools(query, candidates, topK) → Top-K
|
|
58
|
+
→ Compact Schema: ToAPITools(names, compact=true) → 精简定义
|
|
59
|
+
→ LLM 调用
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 快速开始
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import Host from "knight-agent";
|
|
68
|
+
|
|
69
|
+
// 1. 注册工具
|
|
70
|
+
Host.toolModule.register({
|
|
71
|
+
name: "web/search",
|
|
72
|
+
description: "Search the web for information",
|
|
73
|
+
schema: {
|
|
74
|
+
type: "object",
|
|
75
|
+
properties: { query: { type: "string" } },
|
|
76
|
+
required: ["query"],
|
|
77
|
+
},
|
|
78
|
+
handler: async (args) => {
|
|
79
|
+
const res = await fetch(`https://api.search.com?q=${args.query}`);
|
|
80
|
+
return JSON.stringify(await res.json());
|
|
81
|
+
},
|
|
82
|
+
cacheable: true,
|
|
83
|
+
parallelizable: true,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// 2. 注册技能
|
|
87
|
+
Host.skillModule.register({
|
|
88
|
+
name: "web-research",
|
|
89
|
+
description: "Web search and browsing capability",
|
|
90
|
+
tools: ["web/search"],
|
|
91
|
+
systemPrompt: "You can use web/search to find up-to-date information.",
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// 3. 创建对话
|
|
95
|
+
const dialog = Host.dialogModule.create(
|
|
96
|
+
"Research Task",
|
|
97
|
+
{
|
|
98
|
+
address: "https://api.deepseek.com/v1/chat/completions",
|
|
99
|
+
apiKey: "sk-xxx",
|
|
100
|
+
model: "deepseek-chat",
|
|
101
|
+
temperature: 0.6,
|
|
102
|
+
maxTurns: 20,
|
|
103
|
+
},
|
|
104
|
+
"ChainReason"
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// 4. 启用技能
|
|
108
|
+
Host.skillModule.enable(dialog.id, "web-research");
|
|
109
|
+
|
|
110
|
+
// 5. 发送消息 (自动: Skill过滤→RAG排序→Compact Schema→LLM)
|
|
111
|
+
const result = await dialog.send("What is the latest news about AI?");
|
|
112
|
+
console.log(result.content);
|
|
113
|
+
|
|
114
|
+
// 6. 切换策略 (不影响消息历史)
|
|
115
|
+
dialog.switchStrategy("ReflectReason");
|
|
116
|
+
await dialog.send("Refine the answer with more details.");
|
|
117
|
+
|
|
118
|
+
// 7. 销毁
|
|
119
|
+
Host.dialogModule.destroy(dialog.id);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 一、配置 (AgentConfig)
|
|
125
|
+
|
|
126
|
+
创建 Agent / Dialog 时的统一配置:
|
|
127
|
+
|
|
128
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
129
|
+
|---|---|---|---|
|
|
130
|
+
| `address` | `string` | ✅ | API 端点地址 |
|
|
131
|
+
| `apiKey` | `string` | ✅ | API 密钥 |
|
|
132
|
+
| `model` | `string` | ✅ | 模型名称 |
|
|
133
|
+
| `systemPrompt` | `string` | | 系统提示词 |
|
|
134
|
+
| `enableThinking` | `boolean` | | 思考模式开关,默认 `true` |
|
|
135
|
+
| `reasoningEffort` | `"high" \| "max"` | | 推理强度 |
|
|
136
|
+
| `temperature` | `number` | | 采样温度 (0~2) |
|
|
137
|
+
| `maxTokens` | `number` | | 最大输出 token |
|
|
138
|
+
| `maxTurns` | `number` | | 最大对话轮次 |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 二、工具 (Tool)
|
|
143
|
+
|
|
144
|
+
### 注册工具
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
Host.toolModule.register({
|
|
148
|
+
name: "pc/screenshot", // 支持命名空间: "namespace/name"
|
|
149
|
+
description: "Capture a screenshot of the current desktop",
|
|
150
|
+
schema: {
|
|
151
|
+
type: "object",
|
|
152
|
+
properties: {
|
|
153
|
+
region: { type: "string", enum: ["full", "active", "selection"] }
|
|
154
|
+
},
|
|
155
|
+
required: ["region"],
|
|
156
|
+
},
|
|
157
|
+
handler: async (args) => { /* 调 MCP / API / 本地逻辑 */ return "..."; },
|
|
158
|
+
|
|
159
|
+
// 可选属性
|
|
160
|
+
cacheable: true, // 相同参数缓存结果 (默认 60s TTL)
|
|
161
|
+
retryable: true, // 失败可重试
|
|
162
|
+
maxRetries: 3, // 最大重试次数 (默认 1)
|
|
163
|
+
parallelizable: true, // 可与其他工具并行执行
|
|
164
|
+
requiresApproval: false, // 需人工审批 (预留)
|
|
165
|
+
category: "desktop", // 分类标签
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 管理工具
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
Host.toolModule.registerAll([tool1, tool2]); // 批量注册
|
|
173
|
+
Host.toolModule.unregister("toolName"); // 移除 (自动清缓存+去索引)
|
|
174
|
+
Host.toolModule.get("toolName"); // 获取定义
|
|
175
|
+
Host.toolModule.list(); // 全部
|
|
176
|
+
Host.toolModule.listByCategory("desktop"); // 按分类
|
|
177
|
+
Host.toolModule.count; // 数量
|
|
178
|
+
Host.toolModule.clear(); // 清空全部
|
|
179
|
+
Host.toolModule.invalidateCache(); // 清空全部缓存
|
|
180
|
+
Host.toolModule.invalidateCache("pc/screenshot"); // 精确清除某个工具缓存
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 语义检索 (ToolRAG)
|
|
184
|
+
|
|
185
|
+
当候选工具数 > topK 时自动排序,选择最相关的工具发送给 LLM:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// 默认: 内置关键词匹配 (零依赖)
|
|
189
|
+
const names = await Host.toolModule.selectTools(
|
|
190
|
+
"take a screenshot",
|
|
191
|
+
["pc/screenshot", "file/read", "web/search"],
|
|
192
|
+
5 // topK
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
// 可选: 接入真实 Embedding API 提升精度
|
|
196
|
+
Host.toolModule.setEmbeddingProvider({
|
|
197
|
+
dims: 1536,
|
|
198
|
+
embed: async (text) => fetch("https://api.openai.com/v1/embeddings", {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers: { "Authorization": `Bearer ${key}` },
|
|
201
|
+
body: JSON.stringify({ model: "text-embedding-3-small", input: text }),
|
|
202
|
+
}).then(r => r.json()).then(d => d.data[0].embedding),
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 导出为 OpenAI API 格式
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
const apiTools = Host.toolModule.ToAPITools(["tool1", "tool2"], true);
|
|
210
|
+
// compact=true 时自动裁剪 schema (移除 description/default)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 三、技能 (Skill)
|
|
216
|
+
|
|
217
|
+
Skill 是工具能力包 + 使用指导的组合体。框架通过 Skill 控制每个对话可见的工具范围。
|
|
218
|
+
|
|
219
|
+
### 注册技能
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
Host.skillModule.register({
|
|
223
|
+
name: "Windows Control",
|
|
224
|
+
description: "Control Windows desktop: screenshot, clipboard, window management",
|
|
225
|
+
version: "1.0.0",
|
|
226
|
+
tools: ["pc/screenshot", "pc/clipboard", "pc/window"], // 精确匹配
|
|
227
|
+
systemPrompt: "PC 文件操作前先确认路径是否存在。",
|
|
228
|
+
category: "desktop",
|
|
229
|
+
constraints: {
|
|
230
|
+
maxCallsPerTurn: 5,
|
|
231
|
+
requireApproval: false,
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 工具匹配规则
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
tools: ["pc/screenshot", "pc/clipboard"] // 精确匹配
|
|
240
|
+
tools: ["pc/*"] // 通配: 匹配所有 "pc/" 前缀的工具
|
|
241
|
+
tools: ["pc/screenshot", "android/*"] // 混合
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 对话级启用/禁用
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
Host.skillModule.enable(dialogId, "Windows Control"); // 启用
|
|
248
|
+
Host.skillModule.disable(dialogId, "Windows Control"); // 禁用
|
|
249
|
+
Host.skillModule.getEnabled(dialogId); // 获取启用的技能列表
|
|
250
|
+
Host.skillModule.resolveTools(dialogId); // → ToolDefinition[] (自动展开通配符)
|
|
251
|
+
Host.skillModule.buildPrompt(dialogId); // → 聚合的 systemPrompt 文本
|
|
252
|
+
Host.skillModule.clearDialog(dialogId); // 清理对话绑定
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
> **没有启用任何技能时**,`resolveTools` 返回空数组,Agent 无法调用任何工具。
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 四、对话 (Dialog)
|
|
260
|
+
|
|
261
|
+
Dialog = 持久化 Agent + 绑定推理策略 + Skill 作用域。Agent 随对话存在,不随消息销毁。
|
|
262
|
+
|
|
263
|
+
### 创建
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
const dialog = Host.dialogModule.create(
|
|
267
|
+
"标题", // 对话标题
|
|
268
|
+
{ // AgentConfig (含 apiKey/address)
|
|
269
|
+
address: "https://api.deepseek.com/v1/chat/completions",
|
|
270
|
+
apiKey: "sk-xxx",
|
|
271
|
+
model: "deepseek-chat",
|
|
272
|
+
systemPrompt: "You are a helpful assistant.",
|
|
273
|
+
},
|
|
274
|
+
"ChainReason" // 初始策略 (可选,默认 ChainReason)
|
|
275
|
+
);
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### 发送消息
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
const result = await dialog.send("你好");
|
|
282
|
+
|
|
283
|
+
// DialogResult {
|
|
284
|
+
// success: boolean;
|
|
285
|
+
// content: string; // 助手回复
|
|
286
|
+
// thinking?: string; // CoT 思考过程
|
|
287
|
+
// toolCalls?: ...; // 工具调用记录
|
|
288
|
+
// usage?: { prompt_tokens, completion_tokens, total_tokens };
|
|
289
|
+
// finishReason?: string;
|
|
290
|
+
// strategy: string; // 使用的策略名
|
|
291
|
+
// dialogId: string; // 对话 ID
|
|
292
|
+
// trace?: string[]; // 推理追踪日志
|
|
293
|
+
// reflectionRounds?: number; // 反思轮次 (仅 ReflectReason)
|
|
294
|
+
// }
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 切换策略
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
dialog.switchStrategy("ReflectReason"); // 返回 true/false
|
|
301
|
+
dialog.strategy; // 读取当前策略名
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 生命周期
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
Host.dialogModule.get(dialogId); // 获取 Dialog 实例
|
|
308
|
+
Host.dialogModule.list(); // 列出全部 [{dialogId, title, strategy}]
|
|
309
|
+
Host.dialogModule.count; // 数量
|
|
310
|
+
Host.dialogModule.destroy(dialogId); // 销毁 (内部自动销毁 Agent)
|
|
311
|
+
Host.dialogModule.destroyAll(); // 销毁全部
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## 五、推理策略 (Reason)
|
|
317
|
+
|
|
318
|
+
6 种内置策略,不创建 Dialog 也可直接使用 (一次性 Agent,用完即毁)。
|
|
319
|
+
|
|
320
|
+
### 策略列表
|
|
321
|
+
|
|
322
|
+
| 策略 | 键名 | 适合场景 | Agent 数 |
|
|
323
|
+
|---|---|---|---|
|
|
324
|
+
| **ChainReason** | `"ChainReason"` | 简单问答、事实查询、单步推理 | 1 |
|
|
325
|
+
| **ReflectReason** | `"ReflectReason"` | 代码生成、写作、翻译 (质量敏感) | 1 |
|
|
326
|
+
| **TreeReason** | `"TreeReason"` | 方案设计、多方案对比、开放探索 | 1 |
|
|
327
|
+
| **PlanReason** | `"PlanReason"` | 多步骤任务、开发流程、配置部署 | 1 |
|
|
328
|
+
| **CompetitiveReason** | `"CompetitiveReason"` | 方案决策、多角度分析 | N+1 (裁判) |
|
|
329
|
+
| **CommanderReason** | `"CommanderReason"` | 复杂多模块任务、分工协作 | 1+N (工人) |
|
|
330
|
+
|
|
331
|
+
### 一次性执行 (不创建 Dialog)
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
const result = await Host.reasonModule.execute(
|
|
335
|
+
"Write a debounce function in TypeScript",
|
|
336
|
+
{
|
|
337
|
+
baseConfig: {
|
|
338
|
+
address: "https://api.deepseek.com/v1/chat/completions",
|
|
339
|
+
apiKey: "sk-xxx",
|
|
340
|
+
model: "deepseek-chat",
|
|
341
|
+
},
|
|
342
|
+
// 策略特定参数 (可选)
|
|
343
|
+
competitorCount: 3, // CompetitiveReason: 竞争者数量
|
|
344
|
+
varyTemperature: true, // CompetitiveReason: 温度差异化
|
|
345
|
+
maxWorkers: 3, // CommanderReason: 最大工人数
|
|
346
|
+
},
|
|
347
|
+
"ReflectReason" // 策略名,默认 ChainReason
|
|
348
|
+
);
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### 注册自定义策略
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
import { AbstractReason, ReasonConfig, ReasonResult } from "knight-agent";
|
|
355
|
+
|
|
356
|
+
class MyReason extends AbstractReason {
|
|
357
|
+
public readonly type = "MyReason";
|
|
358
|
+
async execute(input: string, config: ReasonConfig): Promise<ReasonResult> {
|
|
359
|
+
// ... 自定义推理逻辑
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
Host.reasonModule.register("MyReason", new MyReason());
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### 策略管理
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
Host.reasonModule.register("name", reason); // 注册
|
|
370
|
+
Host.reasonModule.unregister("name"); // 注销
|
|
371
|
+
Host.reasonModule.has("ChainReason"); // 存在检查
|
|
372
|
+
Host.reasonModule.get("ReflectReason"); // 获取实例
|
|
373
|
+
Host.reasonModule.list(); // [{name, type}, ...]
|
|
374
|
+
Host.reasonModule.count; // 数量
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## 六、两个执行路径对比
|
|
380
|
+
|
|
381
|
+
| | **一次性 (ReasonModule)** | **持久化 (Dialog)** |
|
|
382
|
+
|---|---|---|
|
|
383
|
+
| Agent 生命周期 | 创建 → 执行 → 销毁 | 创建 → 常驻 → destroy |
|
|
384
|
+
| 消息历史 | 单次,不保留 | 跨轮次累积 |
|
|
385
|
+
| 工具可见 | 全部注册的工具 | 由启用的 Skill 过滤 |
|
|
386
|
+
| RAG 工具排序 | ❌ 不经过 | ✅ 自动排序 |
|
|
387
|
+
| Skill 作用域 | ❌ 不支持 | ✅ 支持 |
|
|
388
|
+
| 快照持久化 | ❌ | ✅ |
|
|
389
|
+
| 使用 | `reasonModule.execute()` | `dialog.send()` |
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## 七、Token 优化体系
|
|
394
|
+
|
|
395
|
+
框架内置 4 级 Token 开销优化,在 `dialog.send()` 路径上自动生效。
|
|
396
|
+
|
|
397
|
+
### P0 — Compact Tool Schema
|
|
398
|
+
|
|
399
|
+
`ToolModule.ToAPITools(names, compact=true)` 递归裁剪 JSONSchema,移除 `description` 和 `default` 字段,仅保留 `type/enum/required/properties/items`。Agent 在每次 `OnSendRequest` 中始终传入 `compact=true`。
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
原始: {"type":"string","description":"Search keywords","default":""}
|
|
403
|
+
精简: {"type":"string"}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### P1 — MemoryPressure 三级阈值
|
|
407
|
+
|
|
408
|
+
`Memory.checkPressure()` 返回 4 级压力状态,触发分级压缩:
|
|
409
|
+
|
|
410
|
+
| 级别 | 阈值 | 操作 | LLM 调用 |
|
|
411
|
+
|------|------|------|---------|
|
|
412
|
+
| `None` | < 70% | 无操作 | 0 |
|
|
413
|
+
| `Mild` | 70-85% | 压缩前 30% 消息为摘要 | 1 |
|
|
414
|
+
| `Moderate` | 85-95% | 压缩远期 + 摘要中间轮次 + 提取实体 | 1-2 |
|
|
415
|
+
| `Critical` | > 95% | 激进裁剪,仅保留最近 3 轮 + 纯文本摘要 | 0-1 |
|
|
416
|
+
|
|
417
|
+
发送请求前自动检测并执行,无需手动干预。
|
|
418
|
+
|
|
419
|
+
### P2 — tiktoken 精确计数
|
|
420
|
+
|
|
421
|
+
使用 tiktoken (`cl100k_base`) 进行字节级 Token 估算,兼容 DeepSeek/OpenAI。
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
import { MemoryPressure } from "knight-agent";
|
|
425
|
+
|
|
426
|
+
const tokens = agent.memory.estimateTokens(); // 精确 Token 数
|
|
427
|
+
const level = agent.memory.checkPressure(); // MemoryPressure 枚举
|
|
428
|
+
if (level > MemoryPressure.None) {
|
|
429
|
+
await agent.memory.optimize(level); // 按级别压缩
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### P3 — ToolRAG 语义检索
|
|
434
|
+
|
|
435
|
+
当候选工具数 > topK 时自动排序选择最相关工具。默认使用零依赖关键词匹配,可接入 Embedding API 提升精度。
|
|
436
|
+
|
|
437
|
+
**优化效果**: 100 个工具注册 → Skill 过滤至 20 个 → RAG 排序取 Top-10 → Compact 裁剪 → 最终 Token 开销约 3% 原始量。
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## 八、持久化与快照
|
|
442
|
+
|
|
443
|
+
框架支持 Dialog 级别的快照导出/恢复 (不含 `apiKey`/`address`)。
|
|
444
|
+
|
|
445
|
+
### 导出
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
const snapshot = Host.dialogModule.export(dialogId);
|
|
449
|
+
// DialogSnapshot {
|
|
450
|
+
// version, createdAt, dialogId, title, strategy,
|
|
451
|
+
// agentSnapshot: { version, createdAt, agentId, turnCount,
|
|
452
|
+
// messages, scratchpad, toolResults, config }
|
|
453
|
+
// }
|
|
454
|
+
|
|
455
|
+
// 保存到数据库
|
|
456
|
+
await db.save("snapshots", snapshot.dialogId, snapshot);
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### 恢复
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
// 需重新提供 apiKey/address (快照中已剥离)
|
|
463
|
+
const config: AgentConfig = {
|
|
464
|
+
address: "https://api.deepseek.com/v1/chat/completions",
|
|
465
|
+
apiKey: "sk-xxx",
|
|
466
|
+
model: "...",
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
const restored = Host.dialogModule.import(snapshot, config);
|
|
470
|
+
await restored.send("Continue from where we left off.");
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## 九、完整示例:多设备控制场景
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
import Host from "knight-agent";
|
|
479
|
+
|
|
480
|
+
// ---- 注册工具 ----
|
|
481
|
+
Host.toolModule.registerAll([
|
|
482
|
+
{
|
|
483
|
+
name: "pc/screenshot",
|
|
484
|
+
description: "截取 PC 当前屏幕",
|
|
485
|
+
schema: { type: "object", properties: { region: { type: "string" } } },
|
|
486
|
+
handler: async (args) => await pcMcp.call("screenshot", args),
|
|
487
|
+
cacheable: true,
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
name: "pc/file_read",
|
|
491
|
+
description: "读取 PC 上的文件内容",
|
|
492
|
+
schema: { type: "object", properties: { filePath: { type: "string" } }, required: ["filePath"] },
|
|
493
|
+
handler: async (args) => await pcMcp.call("file_read", args),
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
name: "android/screenshot",
|
|
497
|
+
description: "截取 Android 当前屏幕",
|
|
498
|
+
schema: { type: "object", properties: {} },
|
|
499
|
+
handler: async () => await androidMcp.call("screenshot", {}),
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: "android/app_install",
|
|
503
|
+
description: "在 Android 设备上安装应用",
|
|
504
|
+
schema: { type: "object", properties: { packageName: { type: "string" } }, required: ["packageName"] },
|
|
505
|
+
handler: async (args) => await androidMcp.call("app_install", args),
|
|
506
|
+
},
|
|
507
|
+
]);
|
|
508
|
+
|
|
509
|
+
// ---- 注册技能 (工具能力包) ----
|
|
510
|
+
Host.skillModule.register({
|
|
511
|
+
name: "PC Control",
|
|
512
|
+
description: "控制 PC 设备",
|
|
513
|
+
tools: ["pc/screenshot", "pc/file_read"],
|
|
514
|
+
systemPrompt: "PC 文件操作前先确认路径是否存在。",
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
Host.skillModule.register({
|
|
518
|
+
name: "Android Control",
|
|
519
|
+
description: "控制 Android 设备",
|
|
520
|
+
tools: ["android/screenshot", "android/app_install"],
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
// ---- 创建对话 ----
|
|
524
|
+
const dialog = Host.dialogModule.create("设备管理", {
|
|
525
|
+
address: "https://api.deepseek.com/v1/chat/completions",
|
|
526
|
+
apiKey: "sk-xxx",
|
|
527
|
+
model: "deepseek-chat",
|
|
528
|
+
systemPrompt: "你是设备管理助手。",
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
Host.skillModule.enable(dialog.id, "PC Control");
|
|
532
|
+
Host.skillModule.enable(dialog.id, "Android Control");
|
|
533
|
+
|
|
534
|
+
// ---- 使用 ----
|
|
535
|
+
const r1 = await dialog.send("给 PC 和 Android 都截个屏");
|
|
536
|
+
console.log(r1.content);
|
|
537
|
+
|
|
538
|
+
dialog.switchStrategy("PlanReason");
|
|
539
|
+
const r2 = await dialog.send("先在 PC 上读取配置文件,根据配置在 Android 上安装对应应用");
|
|
540
|
+
console.log(r2.content);
|
|
541
|
+
console.log(r2.trace); // 计划执行追踪
|
|
542
|
+
|
|
543
|
+
// ---- 导出快照 ----
|
|
544
|
+
const snapshot = Host.dialogModule.export(dialog.id);
|
|
545
|
+
await saveToDatabase(snapshot);
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## 十、Host 模块一览
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
import Host from "knight-agent";
|
|
554
|
+
|
|
555
|
+
Host.toolModule // 工具注册表 + 执行调度 + 缓存 + RAG 检索
|
|
556
|
+
Host.skillModule // 技能注册 + 对话级启用/禁用
|
|
557
|
+
Host.reasonModule // 推理策略注册 + 一次性执行
|
|
558
|
+
Host.dialogModule // 对话池 + 生命周期 + 快照导入导出
|
|
559
|
+
Host.agentModule // Agent 创建/销毁/查询
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
每个模块继承 `AbstractModule` → `AbstractObject`,自动分配 `id` 并注册到全局对象池,可通过 `Host.Instance` 直接访问。
|
package/index.d.ts
ADDED
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC"}
|
package/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.default = void 0;
|
|
21
|
+
__exportStar(require("./Host"), exports);
|
|
22
|
+
__exportStar(require("./module"), exports);
|
|
23
|
+
var Host_1 = require("./Host");
|
|
24
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(Host_1).default; } });
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,yCAAuB;AACvB,2CAAyB;AACzB,+BAAiC;AAAxB,gHAAA,OAAO,OAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AbstractAgent, AgentConfig, AgentRunOptions, AgentSnapshot, AgentRunResult, AgentState } from "../../base";
|
|
2
|
+
import { NetworkUtility, OpenAIUtility } from "../../utility";
|
|
3
|
+
import { Memory } from "./Memory";
|
|
4
|
+
/** 智能体类 */
|
|
5
|
+
export declare class Agent extends AbstractAgent {
|
|
6
|
+
/** 智能体配置 */
|
|
7
|
+
readonly config: AgentConfig;
|
|
8
|
+
/** 记忆管理器(消息缓存 + 草稿区 + 上下文优化) */
|
|
9
|
+
readonly memory: Memory;
|
|
10
|
+
/** 运行状态 */
|
|
11
|
+
private _state;
|
|
12
|
+
/** 对话轮次 */
|
|
13
|
+
private _turnCount;
|
|
14
|
+
/** 当前 run() 的执行选项 */
|
|
15
|
+
private _runOptions?;
|
|
16
|
+
/** 构造函数 */
|
|
17
|
+
constructor(config: AgentConfig);
|
|
18
|
+
/** 当前状态 */
|
|
19
|
+
get state(): AgentState;
|
|
20
|
+
/** 对话轮次 */
|
|
21
|
+
get turnCount(): number;
|
|
22
|
+
/** 思考模式是否开启 */
|
|
23
|
+
get thinkingEnabled(): boolean;
|
|
24
|
+
/** @internal 发送用户消息(缓存→发送→缓存回复) */
|
|
25
|
+
sendUserMessage(content: string): Promise<NetworkUtility.HTTP.Response<OpenAIUtility.OpenAI.ChatResponse>>;
|
|
26
|
+
/** @internal 发送当前消息缓存 */
|
|
27
|
+
sendRequest(): Promise<NetworkUtility.HTTP.Response<OpenAIUtility.OpenAI.ChatResponse>>;
|
|
28
|
+
/** 发送消息缓存中的消息到LLM */
|
|
29
|
+
protected OnSendRequest(overrides?: Partial<OpenAIUtility.OpenAI.ChatRequest>): Promise<NetworkUtility.HTTP.Response<OpenAIUtility.OpenAI.ChatResponse>>;
|
|
30
|
+
/** 发送用户消息(自动缓存用户消息和助手回复) */
|
|
31
|
+
protected OnSend(content: string): Promise<NetworkUtility.HTTP.Response<OpenAIUtility.OpenAI.ChatResponse>>;
|
|
32
|
+
/** 模型基础请求(HTTP POST) */
|
|
33
|
+
OnBaseRequest(apiKey: string, chatRequest: OpenAIUtility.OpenAI.ChatRequest): Promise<NetworkUtility.HTTP.Response<OpenAIUtility.OpenAI.ChatResponse>>;
|
|
34
|
+
/** @internal 执行工具调用(含缓存+重试) */
|
|
35
|
+
executeTool(toolCall: OpenAIUtility.OpenAI.ToolResponse): Promise<string>;
|
|
36
|
+
/** @internal 添加工具结果到消息缓存和记忆 */
|
|
37
|
+
addToolResult(result: string, toolCallId: string): void;
|
|
38
|
+
/** @internal 添加助手消息到缓存(含 tool_calls) */
|
|
39
|
+
addAssistantMessage(content: string, toolCalls?: Array<OpenAIUtility.OpenAI.ToolResponse>): void;
|
|
40
|
+
/** @internal 设置运行状态 */
|
|
41
|
+
setState(state: AgentState): void;
|
|
42
|
+
/**
|
|
43
|
+
* 运行 Agent 主循环
|
|
44
|
+
* 1. 发送用户消息
|
|
45
|
+
* 2. 检查响应
|
|
46
|
+
* 3. 如果模型要求工具调用 → 执行工具 → 继续发送
|
|
47
|
+
* 4. 返回最终结果
|
|
48
|
+
*/
|
|
49
|
+
run(input: string, options?: AgentRunOptions): Promise<AgentRunResult>;
|
|
50
|
+
/** 导出当前状态为可序列化快照 */
|
|
51
|
+
snapshot(): AgentSnapshot;
|
|
52
|
+
/** 从快照恢复状态(需先构造 Agent 再调用此方法) */
|
|
53
|
+
restore(snapshot: AgentSnapshot): void;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=Agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Agent.d.ts","sourceRoot":"","sources":["../../../src/module/AgentModule/Agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAiB,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,MAAM,EAAkB,MAAM,UAAU,CAAC;AAElD,WAAW;AACX,qBAAa,KAAM,SAAQ,aAAa;IAEpC,YAAY;IACZ,SAAgB,MAAM,EAAE,WAAW,CAAC;IACpC,gCAAgC;IAChC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,WAAW;IACX,OAAO,CAAC,MAAM,CAA+B;IAC7C,WAAW;IACX,OAAO,CAAC,UAAU,CAAa;IAC/B,qBAAqB;IACrB,OAAO,CAAC,WAAW,CAAC,CAAkB;IAEtC,WAAW;gBACQ,MAAM,EAAE,WAAW;IAMtC,WAAW;IACX,IAAW,KAAK,IAAI,UAAU,CAAwB;IACtD,WAAW;IACX,IAAW,SAAS,IAAI,MAAM,CAA4B;IAC1D,eAAe;IACf,IAAW,eAAe,IAAI,OAAO,CAA+C;IAIpF,mCAAmC;IACtB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAIvH,yBAAyB;IACZ,WAAW,IAAI,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAIpG,qBAAqB;cACL,aAAa,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAuC9J,4BAA4B;cACZ,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAYjH,wBAAwB;IACX,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAiBnK,+BAA+B;IAClB,WAAW,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAKtF,+BAA+B;IACxB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAM9D,wCAAwC;IACjC,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,IAAI;IAKvG,uBAAuB;IAChB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IASxC;;;;;;OAMG;IACU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IA0EnF,oBAAoB;IACb,QAAQ,IAAI,aAAa;IAuBhC,iCAAiC;IAC1B,OAAO,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;CAUhD"}
|