zen-code 4.6.0 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MultiLineTextInput-B4NEXnFm.mjs +23343 -0
- package/dist/devtools-BHqoL8a6.mjs +11653 -0
- package/dist/graphBuilder-B3IJ7dB2.mjs +2641 -0
- package/dist/{index-B6kFMamn.mjs → index-DEcMgCTj.mjs} +1 -1
- package/dist/{memories-DirsFRdm.mjs → memories-rSGKIPk5.mjs} +1 -1
- package/dist/nonInteractive.mjs +7 -6
- package/dist/{subTasks-Bt97OwvY.mjs → subTasks-5KLIr9iy.mjs} +2 -2
- package/dist/zen-code.mjs +8654 -2
- package/dist/zen-keyboard.mjs +7 -6
- package/package.json +7 -9
- package/dist/MultiLineTextInput-e7hD79Wp.mjs +0 -24631
- package/dist/app-CM8R0ZR6.mjs +0 -16249
- package/dist/assets/worker-I4QjJYba.js +0 -1
- package/dist/checkpoint-1sAx_j1E-DrVPlSLR.mjs +0 -319
- package/dist/checkpoint-DxiUsHMy-Cjy5WGNC.mjs +0 -394
- package/dist/chunk-YWE62C55-DID9N9eS.mjs +0 -193
- package/dist/devtools-CzaVuYnh.mjs +0 -2667
- package/dist/graphBuilder-mpLrx9tk.mjs +0 -49189
- package/dist/index-BUGHAUbY.mjs +0 -117
- package/dist/index-C5j-48Ft.mjs +0 -75
- package/dist/index-ChCbbHFS.mjs +0 -463
- package/dist/index-DS5HVciX.mjs +0 -216
- package/dist/index-FHDPQ2Qk.mjs +0 -211
- package/dist/kysely-Bchvsze0.mjs +0 -4316
- package/dist/load-Cjl9cJ0o.mjs +0 -105
- package/dist/migrator-BatO36Tk.mjs +0 -592
- package/dist/pg-adapter-BFtir1GE-BU2H39HC.mjs +0 -62
- package/dist/postgres-dialect-DaHvQ_AZ.mjs +0 -211
- package/dist/queue-Cu_nO_wt-ChzSaooi.mjs +0 -106
- package/dist/remote-threads-CrG03ZS7-C9duTCnB.mjs +0 -157
- package/dist/shallow-tfhh5rlz.mjs +0 -331
- package/dist/sql-CJsUpKEQ.mjs +0 -8106
- package/dist/sqlite-adapter-BKOLSdoL-BlGKN04G.mjs +0 -71
|
@@ -0,0 +1,2641 @@
|
|
|
1
|
+
import se from "micromatch";
|
|
2
|
+
import { Low as ne } from "lowdb";
|
|
3
|
+
import { JSONFile as oe } from "lowdb/node";
|
|
4
|
+
import "yaml";
|
|
5
|
+
import { createState as q, createDefaultAnnotation as g, AgentState as ae, ChatOpenAI as re, getThreadId as ce } from "@langgraph-js/pro";
|
|
6
|
+
import { z as t } from "zod";
|
|
7
|
+
import { MessagesAnnotation as le, StateGraph as de, START as ue, REMOVE_ALL_MESSAGES as pe } from "@langchain/langgraph";
|
|
8
|
+
import { HumanMessage as U, RemoveMessage as me, AIMessage as he } from "@langchain/core/messages";
|
|
9
|
+
import { ChatAnthropic as ge } from "@langchain/anthropic";
|
|
10
|
+
import { ChatGoogleGenerativeAI as fe } from "@langchain/google-genai";
|
|
11
|
+
import we, { promises as d } from "node:fs";
|
|
12
|
+
import _, { join as ye, dirname as G } from "node:path";
|
|
13
|
+
import { createAgent as B, toolStrategy as be, tool as $ } from "langchain";
|
|
14
|
+
import { MemoryStorage as _e, AgentPackage as ke, anthropicPromptCachingMiddleware as ve } from "@langgraph-js/standard-agent";
|
|
15
|
+
import { tool as p } from "@langchain/core/tools";
|
|
16
|
+
import { execa as x } from "execa";
|
|
17
|
+
import { glob as Te } from "glob";
|
|
18
|
+
import Se from "extract-zip";
|
|
19
|
+
import xe from "fs-extra";
|
|
20
|
+
import * as R from "node:os";
|
|
21
|
+
import Ce from "node:os";
|
|
22
|
+
import { pipeline as Ee } from "node:stream/promises";
|
|
23
|
+
import { fileURLToPath as Pe } from "node:url";
|
|
24
|
+
import { pathExists as L } from "path-exists";
|
|
25
|
+
import { temporaryFile as Ae } from "tempy";
|
|
26
|
+
import { xdgCache as Me } from "xdg-basedir";
|
|
27
|
+
import { MultiServerMCPClient as Re } from "@langchain/mcp-adapters";
|
|
28
|
+
import { humanInTheLoopMiddleware as Ie } from "@langgraph-js/auk";
|
|
29
|
+
var w = /* @__PURE__ */ ((s) => (s.ALLOW = "allow", s.ASK = "ask", s.DENY = "deny", s))(w || {});
|
|
30
|
+
t.object({
|
|
31
|
+
tool: t.string(),
|
|
32
|
+
specifier: t.string().optional(),
|
|
33
|
+
action: t.nativeEnum(w)
|
|
34
|
+
});
|
|
35
|
+
t.object({
|
|
36
|
+
allow: t.array(t.string()).optional(),
|
|
37
|
+
ask: t.array(t.string()).optional(),
|
|
38
|
+
deny: t.array(t.string()).optional(),
|
|
39
|
+
defaultMode: t.nativeEnum(w).optional()
|
|
40
|
+
});
|
|
41
|
+
t.object({
|
|
42
|
+
name: t.string(),
|
|
43
|
+
args: t.record(t.string(), t.any())
|
|
44
|
+
});
|
|
45
|
+
class k {
|
|
46
|
+
rules;
|
|
47
|
+
defaultMode;
|
|
48
|
+
patternCache = /* @__PURE__ */ new Map();
|
|
49
|
+
constructor(e) {
|
|
50
|
+
this.rules = e.rules, this.defaultMode = e.defaultMode || w.ASK, this.rules.sort((i, n) => {
|
|
51
|
+
const o = { deny: 0, ask: 1, allow: 2 }, a = o[i.action] - o[n.action];
|
|
52
|
+
if (a !== 0)
|
|
53
|
+
return a;
|
|
54
|
+
const r = i.specifier == null ? 1 : 0, c = n.specifier == null ? 1 : 0;
|
|
55
|
+
return r - c;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Check if a tool call is permitted
|
|
60
|
+
*/
|
|
61
|
+
checkPermission(e) {
|
|
62
|
+
for (const i of this.rules)
|
|
63
|
+
if (this.matchRule(i, e))
|
|
64
|
+
return {
|
|
65
|
+
allowed: i.action === "allow" || i.action === "ask",
|
|
66
|
+
requiresApproval: i.action === "ask",
|
|
67
|
+
matchedRule: i,
|
|
68
|
+
reason: this.getReason(i)
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
allowed: this.defaultMode === "allow" || this.defaultMode === "ask",
|
|
72
|
+
requiresApproval: this.defaultMode === "ask",
|
|
73
|
+
reason: `No matching rule, using default mode: ${this.defaultMode}`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if a rule matches a tool call
|
|
78
|
+
*/
|
|
79
|
+
matchRule(e, i) {
|
|
80
|
+
if (e.tool !== i.name)
|
|
81
|
+
return !1;
|
|
82
|
+
if (!e.specifier)
|
|
83
|
+
return !0;
|
|
84
|
+
const n = this.argsToString(i.args);
|
|
85
|
+
return i.name === "Bash" ? this.matchBashCommand(e.specifier, n) : e.specifier.endsWith(" ") && !/[*?[\\]/.test(e.specifier) ? n.startsWith(e.specifier) : this.matchGlob(e.specifier, n);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Match Bash commands with shell operator awareness
|
|
89
|
+
*/
|
|
90
|
+
matchBashCommand(e, i) {
|
|
91
|
+
if (/[;&|]/.test(i))
|
|
92
|
+
return !1;
|
|
93
|
+
const o = /[<>()]/;
|
|
94
|
+
if (o.test(i)) {
|
|
95
|
+
const a = i.split(o)[0].trim();
|
|
96
|
+
return this.matchBashPattern(e, a);
|
|
97
|
+
}
|
|
98
|
+
return this.matchBashPattern(e, i);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Match Bash command patterns with support for prefix and glob matching
|
|
102
|
+
*/
|
|
103
|
+
matchBashPattern(e, i) {
|
|
104
|
+
return e.endsWith(" ") ? i.startsWith(e) : this.matchGlob(e, i);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Glob pattern matching using micromatch with caching
|
|
108
|
+
*/
|
|
109
|
+
matchGlob(e, i) {
|
|
110
|
+
try {
|
|
111
|
+
const n = e.replace(/^\.\//, ""), o = i.replace(/^\.\//, ""), a = `${e}::${i}`, r = this.patternCache.get(a);
|
|
112
|
+
if (r !== void 0)
|
|
113
|
+
return r;
|
|
114
|
+
const c = se.isMatch(o, n, {
|
|
115
|
+
nocase: !1,
|
|
116
|
+
dot: !0
|
|
117
|
+
});
|
|
118
|
+
return this.cacheResult(a, c), c;
|
|
119
|
+
} catch {
|
|
120
|
+
return i === e;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Cache matching result with LRU-style size limit
|
|
125
|
+
*/
|
|
126
|
+
cacheResult(e, i) {
|
|
127
|
+
if (this.patternCache.size > 1e3) {
|
|
128
|
+
const n = this.patternCache.keys().next().value;
|
|
129
|
+
n && this.patternCache.delete(n);
|
|
130
|
+
}
|
|
131
|
+
this.patternCache.set(e, i);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Convert tool arguments to string representation
|
|
135
|
+
*/
|
|
136
|
+
argsToString(e) {
|
|
137
|
+
return typeof e == "object" && e !== null ? "command" in e && e.command ? String(e.command) : "file_path" in e && e.file_path ? String(e.file_path) : Object.values(e).flat().join(" ") : String(e);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get human-readable reason for permission decision
|
|
141
|
+
*/
|
|
142
|
+
getReason(e) {
|
|
143
|
+
const i = e.action.toUpperCase(), n = e.tool, o = e.specifier ? `(${e.specifier})` : "";
|
|
144
|
+
return `${i} rule matched: ${n}${o}`;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Parse permission rule from string format
|
|
148
|
+
* Examples:
|
|
149
|
+
* - "Bash" -> { tool: "Bash", action: "allow" }
|
|
150
|
+
* - "Bash(git commit )" -> { tool: "Bash", specifier: "git commit ", action: "allow" }
|
|
151
|
+
*/
|
|
152
|
+
static parseRule(e, i) {
|
|
153
|
+
const n = e.match(/^(\w+)(?:\((.*)\))?$/);
|
|
154
|
+
if (!n)
|
|
155
|
+
throw new Error(`Invalid permission rule format: ${e}`);
|
|
156
|
+
const [, o, a] = n;
|
|
157
|
+
return {
|
|
158
|
+
tool: o,
|
|
159
|
+
specifier: a,
|
|
160
|
+
// MODIFIED: Don't trim - preserve trailing spaces which are significant for glob patterns
|
|
161
|
+
action: i
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Create matcher from configuration object
|
|
166
|
+
*/
|
|
167
|
+
static fromConfig(e) {
|
|
168
|
+
const i = [];
|
|
169
|
+
for (const n of e.allow || [])
|
|
170
|
+
i.push(k.parseRule(n, w.ALLOW));
|
|
171
|
+
for (const n of e.ask || [])
|
|
172
|
+
i.push(k.parseRule(n, w.ASK));
|
|
173
|
+
for (const n of e.deny || [])
|
|
174
|
+
i.push(k.parseRule(n, w.DENY));
|
|
175
|
+
return new k({
|
|
176
|
+
rules: i,
|
|
177
|
+
defaultMode: e.defaultMode || w.ASK
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Clear cache (useful for testing or config reload)
|
|
182
|
+
*/
|
|
183
|
+
clearCache() {
|
|
184
|
+
this.patternCache.clear();
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get current cache size
|
|
188
|
+
*/
|
|
189
|
+
getCacheSize() {
|
|
190
|
+
return this.patternCache.size;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
class b {
|
|
194
|
+
configStore;
|
|
195
|
+
/** 工具名称映射 */
|
|
196
|
+
toolNameMapper = {};
|
|
197
|
+
constructor(e) {
|
|
198
|
+
this.configStore = e;
|
|
199
|
+
}
|
|
200
|
+
// ========== 单例模式 ==========
|
|
201
|
+
static instance = null;
|
|
202
|
+
/**
|
|
203
|
+
* 获取单例实例
|
|
204
|
+
* @param configStore 配置存储实例(仅首次调用需要)
|
|
205
|
+
*/
|
|
206
|
+
static getInstance(e) {
|
|
207
|
+
if (!b.instance) {
|
|
208
|
+
if (!e)
|
|
209
|
+
throw new Error("PermissionStore not initialized. Provide configStore on first call.");
|
|
210
|
+
b.instance = new b(e);
|
|
211
|
+
}
|
|
212
|
+
return b.instance;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* 重置单例(测试用)
|
|
216
|
+
*/
|
|
217
|
+
static resetInstance() {
|
|
218
|
+
b.instance = null;
|
|
219
|
+
}
|
|
220
|
+
// ========== 业务方法 ==========
|
|
221
|
+
/**
|
|
222
|
+
* 获取权限匹配器实例
|
|
223
|
+
*/
|
|
224
|
+
async getPermissions() {
|
|
225
|
+
const e = await this.configStore.getConfig();
|
|
226
|
+
if (e.permissions)
|
|
227
|
+
return k.fromConfig(e.permissions);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* 检查 Bash 命令权限
|
|
231
|
+
*/
|
|
232
|
+
async checkBashPermission(e, i) {
|
|
233
|
+
return (await this.getPermissions())?.checkPermission({
|
|
234
|
+
name: "Bash",
|
|
235
|
+
args: { command: e, cwd: i }
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* 检查读取文件权限
|
|
240
|
+
*/
|
|
241
|
+
async checkReadPermission(e) {
|
|
242
|
+
return (await this.getPermissions())?.checkPermission({
|
|
243
|
+
name: "Read",
|
|
244
|
+
args: { file_path: e }
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* 检查写入文件权限
|
|
249
|
+
*/
|
|
250
|
+
async checkWritePermission(e) {
|
|
251
|
+
return (await this.getPermissions())?.checkPermission({
|
|
252
|
+
name: "Write",
|
|
253
|
+
args: { file_path: e }
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
class Oe {
|
|
258
|
+
configStore;
|
|
259
|
+
skillStore;
|
|
260
|
+
pluginStore;
|
|
261
|
+
remoteStore;
|
|
262
|
+
permissionStore;
|
|
263
|
+
_initialized = !1;
|
|
264
|
+
constructor(e, i, n, o) {
|
|
265
|
+
this.configStore = e, this.skillStore = i, this.pluginStore = n, this.remoteStore = o, this.permissionStore = b.getInstance(e);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* 初始化管理器(延迟初始化)
|
|
269
|
+
* 必须在使用其他方法前调用
|
|
270
|
+
*/
|
|
271
|
+
async initialize() {
|
|
272
|
+
this._initialized || ("initialize" in this.configStore && typeof this.configStore.initialize == "function" && await this.configStore.initialize(), "initialize" in this.skillStore && typeof this.skillStore.initialize == "function" && await this.skillStore.initialize(), "initialize" in this.pluginStore && typeof this.pluginStore.initialize == "function" && await this.pluginStore.initialize(), this._initialized = !0);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* 确保已初始化(内部使用)
|
|
276
|
+
*/
|
|
277
|
+
async ensureInitialized() {
|
|
278
|
+
if (!this._initialized)
|
|
279
|
+
throw new Error("ConfigManager not initialized. Call await manager.initialize() first.");
|
|
280
|
+
}
|
|
281
|
+
// 配置相关
|
|
282
|
+
async getConfig() {
|
|
283
|
+
return await this.ensureInitialized(), await this.configStore.getConfig();
|
|
284
|
+
}
|
|
285
|
+
async updateConfig(e) {
|
|
286
|
+
return await this.ensureInitialized(), await this.configStore.updateConfig(e);
|
|
287
|
+
}
|
|
288
|
+
// Skills 相关
|
|
289
|
+
async listSkills() {
|
|
290
|
+
return await this.ensureInitialized(), await this.skillStore.listSkills();
|
|
291
|
+
}
|
|
292
|
+
async getSkill(e) {
|
|
293
|
+
return await this.ensureInitialized(), await this.skillStore.getSkill(e);
|
|
294
|
+
}
|
|
295
|
+
async saveSkill(e, i) {
|
|
296
|
+
return await this.ensureInitialized(), await this.skillStore.saveSkill(e, i);
|
|
297
|
+
}
|
|
298
|
+
async deleteSkill(e) {
|
|
299
|
+
return await this.ensureInitialized(), await this.skillStore.deleteSkill(e);
|
|
300
|
+
}
|
|
301
|
+
async syncSkillsFromRemote() {
|
|
302
|
+
if (await this.ensureInitialized(), !this.remoteStore)
|
|
303
|
+
throw new Error("Remote store not configured");
|
|
304
|
+
return await this.skillStore.syncFromRemote(this.remoteStore);
|
|
305
|
+
}
|
|
306
|
+
// Plugins 相关
|
|
307
|
+
async listPlugins() {
|
|
308
|
+
return await this.ensureInitialized(), await this.pluginStore.listPlugins();
|
|
309
|
+
}
|
|
310
|
+
async getPluginConfig(e) {
|
|
311
|
+
return await this.ensureInitialized(), await this.pluginStore.getPluginConfig(e);
|
|
312
|
+
}
|
|
313
|
+
async updatePluginConfig(e, i) {
|
|
314
|
+
return await this.ensureInitialized(), await this.pluginStore.updatePluginConfig(e, i);
|
|
315
|
+
}
|
|
316
|
+
async installPlugin(e, i) {
|
|
317
|
+
return await this.ensureInitialized(), await this.pluginStore.installPlugin(e, i);
|
|
318
|
+
}
|
|
319
|
+
async uninstallPlugin(e) {
|
|
320
|
+
return await this.ensureInitialized(), await this.pluginStore.uninstallPlugin(e);
|
|
321
|
+
}
|
|
322
|
+
// Permissions 相关
|
|
323
|
+
/**
|
|
324
|
+
* 检查 Bash 命令权限
|
|
325
|
+
*/
|
|
326
|
+
async checkBashPermission(e, i) {
|
|
327
|
+
return await this.ensureInitialized(), await this.permissionStore.checkBashPermission(e, i);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* 检查读取文件权限
|
|
331
|
+
*/
|
|
332
|
+
async checkReadPermission(e) {
|
|
333
|
+
return await this.ensureInitialized(), await this.permissionStore.checkReadPermission(e);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* 检查写入文件权限
|
|
337
|
+
*/
|
|
338
|
+
async checkWritePermission(e) {
|
|
339
|
+
return await this.ensureInitialized(), await this.permissionStore.checkWritePermission(e);
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* 获取权限匹配器(用于高级操作)
|
|
343
|
+
*/
|
|
344
|
+
async getPermissionMatcher() {
|
|
345
|
+
return await this.ensureInitialized(), await this.permissionStore.getPermissions();
|
|
346
|
+
}
|
|
347
|
+
/** fs 专用 */
|
|
348
|
+
getConfigPath() {
|
|
349
|
+
return this.configStore?.dbPath;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
async function $e() {
|
|
353
|
+
const { FileSystemConfigStore: s } = await Promise.resolve().then(() => Ne), { FileSystemSkillStore: e } = await import("./FileSystemSkillStore-yvEvcRxB.mjs"), { FileSystemPluginStore: i } = await import("./FileSystemPluginStore-ChortK7z.mjs"), n = new s(), o = new e(), a = new i(), r = new Oe(n, o, a);
|
|
354
|
+
return await r.initialize(), r;
|
|
355
|
+
}
|
|
356
|
+
const D = {
|
|
357
|
+
config: {
|
|
358
|
+
provider_id: "default",
|
|
359
|
+
provider_type: "openai",
|
|
360
|
+
model_id: "gpt-5.2",
|
|
361
|
+
providers: [
|
|
362
|
+
{
|
|
363
|
+
id: "default",
|
|
364
|
+
type: "openai",
|
|
365
|
+
apiKey: "",
|
|
366
|
+
baseUrl: "https://api.openai.com/v1"
|
|
367
|
+
}
|
|
368
|
+
]
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
function ze(s) {
|
|
372
|
+
return "main_model" in s && !("providers" in s);
|
|
373
|
+
}
|
|
374
|
+
function je(s) {
|
|
375
|
+
const e = [];
|
|
376
|
+
(s.model_provider === "openai" || s.openai_api_key || s.openai_base_url) && e.push({
|
|
377
|
+
id: "openai",
|
|
378
|
+
type: "openai",
|
|
379
|
+
apiKey: s.openai_api_key || "",
|
|
380
|
+
baseUrl: s.openai_base_url || "https://api.openai.com/v1"
|
|
381
|
+
}), (s.model_provider === "anthropic" || s.anthropic_api_key || s.anthropic_base_url) && e.push({
|
|
382
|
+
id: "anthropic",
|
|
383
|
+
type: "anthropic",
|
|
384
|
+
apiKey: s.anthropic_api_key || "",
|
|
385
|
+
baseUrl: s.anthropic_base_url || "https://api.anthropic.com"
|
|
386
|
+
}), e.length === 0 && e.push({
|
|
387
|
+
id: "default",
|
|
388
|
+
type: "openai",
|
|
389
|
+
apiKey: "",
|
|
390
|
+
baseUrl: "https://api.openai.com/v1"
|
|
391
|
+
});
|
|
392
|
+
const i = s.model_provider === "anthropic" ? "anthropic" : "openai", n = e.find((o) => o.id === i) || e[0];
|
|
393
|
+
return {
|
|
394
|
+
provider_id: n.id,
|
|
395
|
+
provider_type: n.type,
|
|
396
|
+
model_id: s.main_model,
|
|
397
|
+
providers: e,
|
|
398
|
+
mcp_config: s.mcp_config,
|
|
399
|
+
stream_refresh_interval: s.stream_refresh_interval,
|
|
400
|
+
enable_thinking: s.enable_thinking,
|
|
401
|
+
switch_command: s.switch_command,
|
|
402
|
+
compact_mode: s.compact_mode,
|
|
403
|
+
permissions: s.permissions
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
class K {
|
|
407
|
+
db;
|
|
408
|
+
zenConfigDir;
|
|
409
|
+
dbPath;
|
|
410
|
+
constructor() {
|
|
411
|
+
const e = Ce.homedir();
|
|
412
|
+
this.zenConfigDir = _.join(e, ".zen-code");
|
|
413
|
+
const i = _.join(this.zenConfigDir, "settings.json"), n = new oe(i);
|
|
414
|
+
this.dbPath = i, this.db = new ne(n, D);
|
|
415
|
+
}
|
|
416
|
+
async initialize() {
|
|
417
|
+
await we.promises.mkdir(this.zenConfigDir, { recursive: !0 }), await this.db.read(), !this.db.data || !this.db.data.config ? (this.db.data = D, await this.db.write()) : ze(this.db.data.config) && (console.log("Migrating legacy config to new format..."), this.db.data.config = je(this.db.data.config), await this.db.write(), console.log("Config migration completed.")), this.syncEnvFromConfig();
|
|
418
|
+
}
|
|
419
|
+
async getConfig() {
|
|
420
|
+
return await this.db.read(), this.db.data.config;
|
|
421
|
+
}
|
|
422
|
+
async updateConfig(e) {
|
|
423
|
+
await this.db.read(), Object.assign(this.db.data.config, e), await this.db.write(), this.syncEnvFromConfig();
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* 将配置同步到环境变量
|
|
427
|
+
*/
|
|
428
|
+
syncEnvFromConfig() {
|
|
429
|
+
const e = this.db.data.config, i = e.providers.find((n) => n.id === e.provider_id);
|
|
430
|
+
i && (i.type === "openai" ? (process.env.MODEL_PROVIDER = "openai", process.env.OPENAI_API_KEY = i.apiKey, process.env.OPENAI_BASE_URL = i.baseUrl) : i.type === "anthropic" ? (process.env.MODEL_PROVIDER = "anthropic", process.env.ANTHROPIC_API_KEY = i.apiKey, process.env.ANTHROPIC_BASE_URL = i.baseUrl) : (i.type === "gemini" || i.type === "google") && (process.env.MODEL_PROVIDER = "gemini", process.env.GOOGLE_API_KEY = i.apiKey, process.env.GOOGLE_BASE_URL = i.baseUrl));
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* 获取配置目录路径
|
|
434
|
+
*/
|
|
435
|
+
getZenConfigDir() {
|
|
436
|
+
return this.zenConfigDir;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
const Ne = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
440
|
+
__proto__: null,
|
|
441
|
+
FileSystemConfigStore: K
|
|
442
|
+
}, Symbol.toStringTag, { value: "Module" })), Ue = t.enum(["idea", "bug_report", "feature", "refactor"]), Le = t.enum(["low", "medium", "high", "critical"]), De = t.enum(["pending", "planned", "archived"]), Fe = t.enum(["user_input", "ai_suggestion", "conversation_derived"]), We = t.object({
|
|
443
|
+
id: t.string().uuid(),
|
|
444
|
+
type: Ue,
|
|
445
|
+
title: t.string().min(1).max(200),
|
|
446
|
+
description: t.string(),
|
|
447
|
+
priority: Le.default("medium"),
|
|
448
|
+
source: Fe,
|
|
449
|
+
status: De.default("pending"),
|
|
450
|
+
createdAt: t.string().datetime(),
|
|
451
|
+
tags: t.array(t.string()).default([]),
|
|
452
|
+
metadata: t.object({
|
|
453
|
+
relatedFiles: t.array(t.string()).optional(),
|
|
454
|
+
conversationContext: t.string().optional(),
|
|
455
|
+
estimatedComplexity: t.enum(["simple", "medium", "complex"]).optional()
|
|
456
|
+
}).optional()
|
|
457
|
+
});
|
|
458
|
+
t.object({
|
|
459
|
+
version: t.literal("1.0"),
|
|
460
|
+
sparks: t.array(We),
|
|
461
|
+
lastUpdated: t.string().datetime()
|
|
462
|
+
});
|
|
463
|
+
const H = t.enum([
|
|
464
|
+
"pickup",
|
|
465
|
+
// 待领取(新任务,未被 agent 接管)
|
|
466
|
+
"running",
|
|
467
|
+
// 运行中(agent 正在执行)
|
|
468
|
+
"complete",
|
|
469
|
+
// 已完成(成功完成)
|
|
470
|
+
"error",
|
|
471
|
+
// 已失败(失败,暂停中)
|
|
472
|
+
"review",
|
|
473
|
+
// 待审核(完成,等待人工确认)
|
|
474
|
+
"feedback"
|
|
475
|
+
// 待反馈(agent 卡住,需要人工输入)
|
|
476
|
+
]), I = t.enum([
|
|
477
|
+
"default",
|
|
478
|
+
"planner",
|
|
479
|
+
"reviewer",
|
|
480
|
+
"refactor",
|
|
481
|
+
"finder",
|
|
482
|
+
"debugger",
|
|
483
|
+
"architect"
|
|
484
|
+
]), Ye = t.enum(["serial", "parallel"]), V = t.lazy(
|
|
485
|
+
() => t.object({
|
|
486
|
+
// 基本信息
|
|
487
|
+
id: t.string(),
|
|
488
|
+
title: t.string().min(1).max(200),
|
|
489
|
+
description: t.string(),
|
|
490
|
+
// 执行控制
|
|
491
|
+
execution: Ye.optional(),
|
|
492
|
+
children: t.array(t.lazy(() => V)).optional(),
|
|
493
|
+
// Agent 分配
|
|
494
|
+
agentType: I.optional(),
|
|
495
|
+
threadId: t.string().optional(),
|
|
496
|
+
// 元数据
|
|
497
|
+
estimatedTime: t.string().optional(),
|
|
498
|
+
complexity: t.enum(["simple", "medium", "complex"]).optional(),
|
|
499
|
+
dependencies: t.array(t.string()).optional(),
|
|
500
|
+
acceptanceCriteria: t.array(t.string()).optional(),
|
|
501
|
+
// 状态相关(运行时)
|
|
502
|
+
status: H.optional(),
|
|
503
|
+
startedAt: t.string().datetime().optional(),
|
|
504
|
+
completedAt: t.string().datetime().optional(),
|
|
505
|
+
assignedTo: I.optional(),
|
|
506
|
+
error: t.object({
|
|
507
|
+
message: t.string(),
|
|
508
|
+
stack: t.string().optional(),
|
|
509
|
+
retryCount: t.number().optional()
|
|
510
|
+
}).optional()
|
|
511
|
+
})
|
|
512
|
+
), qe = t.object({
|
|
513
|
+
taskId: t.string(),
|
|
514
|
+
planId: t.string(),
|
|
515
|
+
threadId: t.string(),
|
|
516
|
+
// 关联的 LangGraph thread ID
|
|
517
|
+
agentType: I,
|
|
518
|
+
// 改为类型安全的 AgentType
|
|
519
|
+
status: H,
|
|
520
|
+
startedAt: t.string().datetime(),
|
|
521
|
+
completedAt: t.string().datetime().optional(),
|
|
522
|
+
output: t.string().optional(),
|
|
523
|
+
error: t.string().optional(),
|
|
524
|
+
changedFiles: t.array(t.string()).optional()
|
|
525
|
+
});
|
|
526
|
+
t.object({
|
|
527
|
+
version: t.literal("1.0"),
|
|
528
|
+
lastUpdated: t.string().datetime(),
|
|
529
|
+
// 活跃的任务树
|
|
530
|
+
activePlanId: t.string().optional(),
|
|
531
|
+
tasks: t.record(t.string(), V),
|
|
532
|
+
// 执行历史
|
|
533
|
+
history: t.array(qe),
|
|
534
|
+
// 全局配置
|
|
535
|
+
config: t.object({
|
|
536
|
+
maxConcurrentAgents: t.number().min(1).max(10).default(3),
|
|
537
|
+
retryLimit: t.number().min(0).max(10).default(3),
|
|
538
|
+
autoResume: t.boolean().default(!1)
|
|
539
|
+
})
|
|
540
|
+
});
|
|
541
|
+
const z = await $e(), Ge = async () => {
|
|
542
|
+
await z.initialize();
|
|
543
|
+
}, Be = async () => await z.getConfig(), bi = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
544
|
+
__proto__: null,
|
|
545
|
+
configStore: z,
|
|
546
|
+
getConfig: Be,
|
|
547
|
+
initDb: Ge
|
|
548
|
+
}, Symbol.toStringTag, { value: "Module" })), Ke = q().build({
|
|
549
|
+
task_store: g(() => ({}))
|
|
550
|
+
}), He = t.object({
|
|
551
|
+
task_store: t.record(t.string(), t.any()).optional()
|
|
552
|
+
}), _i = ae.extend(He.shape).extend({
|
|
553
|
+
provider_id: t.string().default("openai"),
|
|
554
|
+
provider_type: t.string().default("openai"),
|
|
555
|
+
model_id: t.string().default("qwen-plus"),
|
|
556
|
+
agent_name: t.string().default("Code Agent"),
|
|
557
|
+
switch_command: t.string().optional(),
|
|
558
|
+
enable_thinking: t.boolean().default(!0),
|
|
559
|
+
// sb 的 langchain 在 agent middleware 的 runtime 里面拿不到这些数据
|
|
560
|
+
user_id: t.string().optional(),
|
|
561
|
+
thread_id: t.string().optional()
|
|
562
|
+
}), J = q(le, Ke).build({
|
|
563
|
+
provider_id: g(() => "openai"),
|
|
564
|
+
provider_type: g(() => "openai"),
|
|
565
|
+
model_id: g(() => "qwen-plus"),
|
|
566
|
+
agent_name: g(() => "Code Agent"),
|
|
567
|
+
switch_command: g(() => null),
|
|
568
|
+
enable_thinking: g(() => !0),
|
|
569
|
+
// sb 的 langchain 在 agent middleware 的 runtime 里面拿不到这些数据
|
|
570
|
+
user_id: g(() => ""),
|
|
571
|
+
thread_id: g(() => "")
|
|
572
|
+
});
|
|
573
|
+
function Ve(s, e = "Human", i = "AI") {
|
|
574
|
+
const n = [];
|
|
575
|
+
for (const o of s) {
|
|
576
|
+
let a;
|
|
577
|
+
if (o.type === "human") a = e;
|
|
578
|
+
else if (o.type === "ai") a = i;
|
|
579
|
+
else if (o.type === "system") a = "System";
|
|
580
|
+
else if (o.type === "tool") a = "Tool";
|
|
581
|
+
else if (o.type === "generic")
|
|
582
|
+
a = o.role;
|
|
583
|
+
else throw new Error(`Got unsupported message type: ${o.type}`);
|
|
584
|
+
const r = o.name ? `${o.name}, ` : "", c = typeof o.content == "string" ? o.content : JSON.stringify(o.content, null, 2);
|
|
585
|
+
n.push(`${a}: ${r}${c}`);
|
|
586
|
+
}
|
|
587
|
+
return n.join(`
|
|
588
|
+
`);
|
|
589
|
+
}
|
|
590
|
+
const Z = async (s, e = {}) => {
|
|
591
|
+
const { modelProvider: i, enableThinking: n = !0 } = e;
|
|
592
|
+
let o;
|
|
593
|
+
return i === "anthropic" ? o = new ge({
|
|
594
|
+
model: s,
|
|
595
|
+
streamUsage: !0,
|
|
596
|
+
streaming: !0,
|
|
597
|
+
maxRetries: 1,
|
|
598
|
+
maxTokens: 64e3,
|
|
599
|
+
thinking: n ? {
|
|
600
|
+
budget_tokens: 1024,
|
|
601
|
+
type: "enabled"
|
|
602
|
+
} : void 0,
|
|
603
|
+
apiKey: e.apiKey,
|
|
604
|
+
anthropicApiUrl: e.baseURL,
|
|
605
|
+
metadata: e.metadata
|
|
606
|
+
}) : i === "gemini" || i === "google" ? (console.log(process.env.GOOGLE_BASE_URL), o = new fe({
|
|
607
|
+
model: s,
|
|
608
|
+
apiKey: e.apiKey,
|
|
609
|
+
baseUrl: e.baseURL || process.env.GOOGLE_BASE_URL,
|
|
610
|
+
maxRetries: 1,
|
|
611
|
+
streaming: !0,
|
|
612
|
+
streamUsage: !0,
|
|
613
|
+
// Note: Gemini doesn't have native thinking support like Anthropic,
|
|
614
|
+
// but we can use extended thinking mode for supported models
|
|
615
|
+
metadata: e.metadata
|
|
616
|
+
})) : o = new re({
|
|
617
|
+
model: s,
|
|
618
|
+
configuration: {
|
|
619
|
+
baseURL: e.baseURL,
|
|
620
|
+
apiKey: e.apiKey
|
|
621
|
+
},
|
|
622
|
+
streamUsage: !0,
|
|
623
|
+
maxRetries: 1,
|
|
624
|
+
modelKwargs: n ? {
|
|
625
|
+
thinking: {
|
|
626
|
+
type: "enabled"
|
|
627
|
+
}
|
|
628
|
+
} : void 0,
|
|
629
|
+
metadata: e.metadata
|
|
630
|
+
}), o;
|
|
631
|
+
}, Je = (s) => s?.replace(process.cwd(), ".") || s || "", Ze = t.object({
|
|
632
|
+
summary_of_chat: t.string().describe(
|
|
633
|
+
"对话总结(300-500字):1) 完整复现对话的核心过程(任务背景→关键决策→解决方案→最终结果);2) 明确说明接下来要做什么(后续行动、待完成任务、需要用户确认的事项);3) 突出关键成果和交付物"
|
|
634
|
+
),
|
|
635
|
+
// Frontmatter 字段
|
|
636
|
+
name: t.string().describe("记忆名称(kebab-case 格式)"),
|
|
637
|
+
description: t.string().describe("对于这个记忆的中等长度描述(索引综述,200-500字符,包含背景、关键点、适用场景)"),
|
|
638
|
+
tags: t.array(t.string()).describe("记忆标签"),
|
|
639
|
+
category: t.enum(["architecture", "bug-fix", "workflow", "configuration", "optimization"]).describe("记忆分类"),
|
|
640
|
+
created: t.string().describe("创建日期(ISO 格式:YYYY-MM-DD)"),
|
|
641
|
+
last_updated: t.string().describe("最后更新日期(ISO 格式:YYYY-MM-DD)"),
|
|
642
|
+
priority: t.enum(["high", "medium", "low"]).describe("优先级"),
|
|
643
|
+
context_scope: t.enum(["user", "project"]).describe("上下文范围"),
|
|
644
|
+
// 内容字段
|
|
645
|
+
content: t.string().describe("记忆内容(详细说明,包含代码示例)")
|
|
646
|
+
}), Xe = `你是一个负责分析对话并提取关键信息的智能助手。
|
|
647
|
+
|
|
648
|
+
## 任务
|
|
649
|
+
|
|
650
|
+
1. **对话总结 (summary_of_chat)**:完整复现对话并明确后续行动
|
|
651
|
+
2. **记忆提取**:判断是否有值得保存为长期记忆的信息
|
|
652
|
+
|
|
653
|
+
## 对话总结要求 (summary_of_chat)
|
|
654
|
+
|
|
655
|
+
**必须包含以下三个部分**:
|
|
656
|
+
|
|
657
|
+
### 1. 完整复现对话核心过程
|
|
658
|
+
- **任务背景**:用户想做什么?遇到什么问题?
|
|
659
|
+
- **关键决策**:做出了什么选择?为什么?
|
|
660
|
+
- **解决方案**:具体怎么实现的?用了什么技术/方法?
|
|
661
|
+
- **最终结果**:完成了什么?输出了什么?
|
|
662
|
+
|
|
663
|
+
### 2. 明确后续行动
|
|
664
|
+
- **待完成任务**:还有哪些未完成的工作?
|
|
665
|
+
- **需要确认**:哪些事项需要用户决策?
|
|
666
|
+
- **下一步建议**:建议接下来做什么?
|
|
667
|
+
|
|
668
|
+
### 3. 突出关键成果
|
|
669
|
+
- **交付物**:生成了什么文件/代码/文档?
|
|
670
|
+
- **价值点**:解决了什么核心问题?
|
|
671
|
+
- **可复用性**:什么内容可以复用?
|
|
672
|
+
|
|
673
|
+
**格式要求**:
|
|
674
|
+
- 300-500 字
|
|
675
|
+
- 使用清晰的结构(可用 → 表示流程)
|
|
676
|
+
- 突出关键信息(文件路径、函数名、配置项)
|
|
677
|
+
|
|
678
|
+
**示例**:
|
|
679
|
+
\`\`\`
|
|
680
|
+
用户需要为 TUI 应用添加模型选择面板。通过创建 ModelPanel 组件实现交互式界面(↑↓选择、Enter切换、q关闭),在 Chat.tsx 中扩展 activeView 状态添加 'model' 类型,定义 switchToModel 回调并传递到命令系统,注册 /model-panel 和 /mp 命令。修复了 CommandHandler 未解构 switchToModel 的 bug。✓ 完成:可用的模型选择面板;⏳ 待定:是否需要添加模型描述信息展示;→ 建议:测试面板在不同终端下的渲染效果
|
|
681
|
+
\`\`\`
|
|
682
|
+
|
|
683
|
+
## 记忆评分机制(总分 10 分,≥ 6 分才保存)
|
|
684
|
+
|
|
685
|
+
## 记忆评分机制(总分 10 分,≥ 6 分才保存)
|
|
686
|
+
|
|
687
|
+
1. **重要性** (0-3 分)
|
|
688
|
+
- 3 分:关键技术决策、架构设计、重要问题解决方案
|
|
689
|
+
- 2 分:有用的编码模式、最佳实践
|
|
690
|
+
- 1 分:一般性建议、参考信息
|
|
691
|
+
- 0 分:无实际内容
|
|
692
|
+
|
|
693
|
+
2. **独特性** (0-3 分)
|
|
694
|
+
- 3 分:项目特定配置、非常规解决方案
|
|
695
|
+
- 2 分:非显而易见的技巧、特定场景知识
|
|
696
|
+
- 1 分:略有新意的做法
|
|
697
|
+
- 0 分:常见知识、通用做法
|
|
698
|
+
|
|
699
|
+
3. **可复用性** (0-2 分)
|
|
700
|
+
- 2 分:跨场景可复用的模式/方法
|
|
701
|
+
- 1 分:特定场景下可复用
|
|
702
|
+
- 0 分:一次性信息、临时性内容
|
|
703
|
+
|
|
704
|
+
4. **持久性** (0-2 分)
|
|
705
|
+
- 2 分:长期有效(架构决策、代码模式)
|
|
706
|
+
- 1 分:中期有效(配置信息、工作流程)
|
|
707
|
+
- 0 分:临时信息(调试过程、一次性请求)
|
|
708
|
+
|
|
709
|
+
**评分 < 6 分**:设置 name 为 "no-memory-{timestamp}",content 为 "无重要信息"
|
|
710
|
+
|
|
711
|
+
## 记忆命名建议
|
|
712
|
+
|
|
713
|
+
- 使用 kebab-case 格式(小写、连字符分隔)
|
|
714
|
+
- 从核心主题中提取 2-4 个关键词
|
|
715
|
+
- 示例:
|
|
716
|
+
- "langchain-structured-output-single-object-pattern"
|
|
717
|
+
- "memory-system-design"
|
|
718
|
+
- "middleware-execution-order"
|
|
719
|
+
- 避免通用名称:使用具体的技术术语而非 "fix-bug" 或 "optimization"
|
|
720
|
+
|
|
721
|
+
## 内容提取模板
|
|
722
|
+
|
|
723
|
+
提取的内容应包含以下部分(按需选择):
|
|
724
|
+
|
|
725
|
+
**背景**:什么问题/场景?
|
|
726
|
+
**决策**:做了什么选择?
|
|
727
|
+
**原因**:为什么这样选择?
|
|
728
|
+
**实现**:关键代码、文件路径、配置
|
|
729
|
+
**适用**:什么场景适用?什么场景不适用?
|
|
730
|
+
**注意**:有什么陷阱或边界情况?
|
|
731
|
+
|
|
732
|
+
## 代码引用原则(强制执行)
|
|
733
|
+
|
|
734
|
+
**默认规则:代码超过 5 行 → 使用文件引用**
|
|
735
|
+
|
|
736
|
+
### 何时使用文件引用
|
|
737
|
+
- 完整函数或方法实现
|
|
738
|
+
- 完整类或组件定义
|
|
739
|
+
- 长配置文件
|
|
740
|
+
- 任何 > 5 行的代码块
|
|
741
|
+
|
|
742
|
+
### 文件引用格式
|
|
743
|
+
\`文件路径[:行号范围]\`:简短说明
|
|
744
|
+
|
|
745
|
+
示例:
|
|
746
|
+
- \`agents/code/graph.ts:120-180\`:中间件链执行顺序
|
|
747
|
+
- \`tui/src/chat/Chat.tsx\`:完整的面板切换回调实现
|
|
748
|
+
- \`.deepagents/skills/web-research/SKILL.md\`:技能结构模板
|
|
749
|
+
|
|
750
|
+
### 何时内联代码(仅限以下情况)
|
|
751
|
+
1. **极短片段**(≤ 5 行):用于说明关键概念
|
|
752
|
+
2. **配置示例**:JSON/YAML 配置片段
|
|
753
|
+
3. **错误示例**:展示错误模式(不超过 5 行)
|
|
754
|
+
|
|
755
|
+
### 代码长度限制
|
|
756
|
+
- **总代码占比**:content 中代码块总行数 ≤ 30%
|
|
757
|
+
- **单个代码块**:不超过 5 行
|
|
758
|
+
- **优先级**:文件引用 > 概述 > 短片段
|
|
759
|
+
|
|
760
|
+
### 长代码处理方式
|
|
761
|
+
|
|
762
|
+
**错误示范**(代码过长):
|
|
763
|
+
\`\`\`typescript
|
|
764
|
+
const middleware = [
|
|
765
|
+
new SubAgentsMiddleware(),
|
|
766
|
+
new AgentsMdMiddleware(),
|
|
767
|
+
// ... 省略 20 行
|
|
768
|
+
];
|
|
769
|
+
\`\`\`
|
|
770
|
+
|
|
771
|
+
**正确示范**(文件引用):
|
|
772
|
+
中间件列表定义参见 \`agents/code/graph.ts:45-60\`,执行顺序为:SubAgents → AgentsMd → Skills → MCP → HumanInTheLoop → Cache
|
|
773
|
+
|
|
774
|
+
**关键片段**(如必要):
|
|
775
|
+
\`\`\`typescript
|
|
776
|
+
// 仅 3 行核心逻辑
|
|
777
|
+
middleware.forEach(m => m.wrapModelCall(req, handler))
|
|
778
|
+
\`\`\`
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
## 输出格式要求
|
|
782
|
+
|
|
783
|
+
**你必须输出单个 JSON 对象(不是数组)**,包含以下字段:
|
|
784
|
+
|
|
785
|
+
- **name** (string): 记忆名称,kebab-case 格式,例如 "memory-system-design"
|
|
786
|
+
- **description** (string): 中等长度描述,索引综述(200-500字符),包含:
|
|
787
|
+
* 背景和问题/场景
|
|
788
|
+
* 关键决策或解决方案
|
|
789
|
+
* 适用场景或范围
|
|
790
|
+
* 使用清晰的分号或句号分隔各部分
|
|
791
|
+
- **content** (string): 详细内容,包含技术实现细节、文件路径、代码示例、关键决策等,按照内容提取模板组织
|
|
792
|
+
- **tags** (array of string): 记忆标签,3-5 个,用于检索和分类,例如 ["langchain", "structured-output", "zod"]
|
|
793
|
+
- **category** (enum): 记忆分类,可选值:architecture, bug-fix, workflow, configuration, optimization
|
|
794
|
+
- **priority** (enum): 优先级,可选值:high, medium, low
|
|
795
|
+
- **created** (string): 创建日期,ISO 格式 YYYY-MM-DD,例如 "2025-01-13"
|
|
796
|
+
- **last_updated** (string): 最后更新日期,ISO 格式 YYYY-MM-DD,例如 "2025-01-13"
|
|
797
|
+
- **context_scope** (enum): 上下文范围,可选值:user, project
|
|
798
|
+
|
|
799
|
+
## 分类标准
|
|
800
|
+
|
|
801
|
+
- **architecture**: 架构决策、设计模式、系统结构
|
|
802
|
+
- **bug-fix**: Bug 修复和问题解决方案
|
|
803
|
+
- **workflow**: 工作流程和最佳实践
|
|
804
|
+
- **configuration**: 配置和环境设置
|
|
805
|
+
- **optimization**: 性能优化和改进
|
|
806
|
+
|
|
807
|
+
## 优先级标准
|
|
808
|
+
|
|
809
|
+
- **high**: 关键架构决策、重要问题解决方案、影响系统正确性的问题
|
|
810
|
+
- **medium**: 有用的模式、次要的配置信息、影响开发效率的问题
|
|
811
|
+
- **low**: 一般性建议、参考信息、优化建议
|
|
812
|
+
|
|
813
|
+
## 示例输出
|
|
814
|
+
|
|
815
|
+
### 示例 1:有价值的记忆
|
|
816
|
+
\`\`\`json
|
|
817
|
+
{
|
|
818
|
+
"summary_of_chat": "用户反馈记忆系统的 summary_of_chat 字段过于简单,需要增强对话复现和后续行动说明。修改了 agents/code/memories/analyze.ts:1) 更新 MemoryCandidateSchema 中 summary_of_chat 的描述,要求 300-500 字包含完整对话过程、后续行动、关键成果;2) 在 smart_memory_prompt 中添加专门的"对话总结要求"章节,明确三部分内容(完整复现、后续行动、关键成果);3) 提供格式示例和清晰的模板。✓ 完成:增强版记忆提示词;⏳ 待定:是否需要添加示例输出展示新的 summary_of_chat 格式;→ 建议:测试新提示词在实际对话中的表现",
|
|
819
|
+
"name": "memory-prompt-summary-enhancement",
|
|
820
|
+
"description": "增强记忆系统的 summary_of_chat 字段要求,要求完整复现对话过程并明确后续行动;包括任务背景→关键决策→解决方案→最终结果的完整流程,以及待完成任务、需要确认事项、下一步建议;适用于所有需要高质量对话总结的场景",
|
|
821
|
+
"content": "## 背景\\n\\n用户反馈记忆系统生成的 summary_of_chat 过于简单,缺少后续行动说明,无法有效回顾对话和继续工作。\\n\\n## 解决方案\\n\\n修改 \`agents/code/memories/analyze.ts\` 的三处:\\n\\n1. **Schema 增强**(第 18 行):\\n\\\`\\\`\\\`typescript\\nsummary_of_chat: z.string().describe('对话总结(300-500字):1) 完整复现对话的核心过程(任务背景→关键决策→解决方案→最终结果);2) 明确说明接下来要做什么(后续行动、待完成任务、需要用户确认的事项);3) 突出关键成果和交付物')\\n\\\`\\\`\\\`\\n\\n2. **提示词添加专门章节**:在 smart_memory_prompt 中添加"对话总结要求"部分,明确三个组成部分:完整复现、后续行动、关键成果\\n\\n3. **提供格式示例**:使用 → 表示流程,✓ 表示完成,⏳ 表示待定,→ 表示建议\\n\\n## 适用场景\\n\\n- 需要高质量对话总结的 AI 系统\\n- 需要明确后续行动的任务管理场景",
|
|
822
|
+
"tags": ["prompt-engineering", "memory-system", "conversation-summary", "langchain"],
|
|
823
|
+
"category": "optimization",
|
|
824
|
+
"priority": "medium",
|
|
825
|
+
"created": "2025-01-17",
|
|
826
|
+
"last_updated": "2025-01-17",
|
|
827
|
+
"context_scope": "project"
|
|
828
|
+
}
|
|
829
|
+
\`\`\`
|
|
830
|
+
|
|
831
|
+
### 示例 2:无重要信息
|
|
832
|
+
\`\`\`json
|
|
833
|
+
{
|
|
834
|
+
"summary_of_chat": "用户询问如何查看 TUI 应用中的模型列表。已告知可通过 /model-panel 或 /mp 命令打开模型选择面板,使用 ↑↓ 键选择、Enter 键切换模型、q 键关闭面板。当前无其他问题。✓ 完成:问题已解答;⏳ 待定:无;→ 建议:如需更多帮助可使用 /help 命令",
|
|
835
|
+
"name": "no-memory-1736736000000",
|
|
836
|
+
"description": "本次对话无重要信息需要保存",
|
|
837
|
+
"content": "无重要信息",
|
|
838
|
+
"tags": [],
|
|
839
|
+
"category": "workflow",
|
|
840
|
+
"priority": "low",
|
|
841
|
+
"created": "2025-01-13",
|
|
842
|
+
"last_updated": "2025-01-13",
|
|
843
|
+
"context_scope": "project"
|
|
844
|
+
}
|
|
845
|
+
\`\`\`
|
|
846
|
+
|
|
847
|
+
## 重要原则
|
|
848
|
+
|
|
849
|
+
1. **宁缺毋滥**:评分 < 6 分时,返回"无重要信息"
|
|
850
|
+
2. **避免重复**:不要记录显而易见或通用的知识
|
|
851
|
+
3. **用户优先**:明确记录用户的指示和偏好
|
|
852
|
+
4. **精确具体**:使用具体的文件名、代码片段、配置项
|
|
853
|
+
5. **独立完整**:记忆应能独立理解,不依赖外部上下文
|
|
854
|
+
`;
|
|
855
|
+
async function Qe(s, e) {
|
|
856
|
+
const i = [
|
|
857
|
+
new U(e),
|
|
858
|
+
new U("请分析这段对话,提取值得保存的信息。")
|
|
859
|
+
], o = await B({
|
|
860
|
+
model: s,
|
|
861
|
+
tools: [],
|
|
862
|
+
systemPrompt: Xe,
|
|
863
|
+
responseFormat: be(Ze)
|
|
864
|
+
}).invoke({ messages: i });
|
|
865
|
+
return await tt(o.structuredResponse);
|
|
866
|
+
}
|
|
867
|
+
function et(s, e) {
|
|
868
|
+
const i = s.toLowerCase().replace(/[^\u4e00-\u9fa5a-z0-9\s]/gi, " ").split(/\s+/).filter((a) => a.length > 1).slice(0, 4);
|
|
869
|
+
if (i.length === 0)
|
|
870
|
+
return `memory-${Date.now()}-${e}`;
|
|
871
|
+
const o = `${i.join("-")}-${Date.now()}-${e}`;
|
|
872
|
+
return o.length > 64 ? o.substring(0, 61) + "..." : o;
|
|
873
|
+
}
|
|
874
|
+
async function tt(s) {
|
|
875
|
+
if (s.name.startsWith("no-memory-"))
|
|
876
|
+
return `${s.summary_of_chat}
|
|
877
|
+
|
|
878
|
+
---
|
|
879
|
+
|
|
880
|
+
name: "${s.name}"
|
|
881
|
+
description: "${s.description}"
|
|
882
|
+
|
|
883
|
+
⚠️ 无重要信息,未保存记忆`;
|
|
884
|
+
const e = _.join(process.cwd(), ".claude/memories");
|
|
885
|
+
await d.mkdir(e, { recursive: !0 });
|
|
886
|
+
const i = s.name || et(s.content, 0), n = _.join(e, i);
|
|
887
|
+
await d.mkdir(n, { recursive: !0 });
|
|
888
|
+
const o = s.content.indexOf(`
|
|
889
|
+
`), a = o > 0 ? s.content.substring(0, Math.min(o, 100)) : s.content.substring(0, Math.min(100, s.content.length)), r = `---
|
|
890
|
+
name: "${s.name}"
|
|
891
|
+
description: "${s.description}"
|
|
892
|
+
tags: [${s.tags.map((l) => `"${l}"`).join(", ")}]
|
|
893
|
+
category: "${s.category}"
|
|
894
|
+
created: "${s.created}"
|
|
895
|
+
last_updated: "${s.last_updated}"
|
|
896
|
+
priority: "${s.priority}"
|
|
897
|
+
context_scope: "${s.context_scope}"
|
|
898
|
+
---
|
|
899
|
+
|
|
900
|
+
# ${a}
|
|
901
|
+
|
|
902
|
+
${s.content}
|
|
903
|
+
`, c = _.join(n, "MEMORY.md");
|
|
904
|
+
return await d.writeFile(c, r, "utf-8"), `${s.summary_of_chat}
|
|
905
|
+
|
|
906
|
+
---
|
|
907
|
+
|
|
908
|
+
name: "${s.name}"
|
|
909
|
+
description: "${s.description}"
|
|
910
|
+
|
|
911
|
+
✓ 保存记忆: ${Je(c)}`;
|
|
912
|
+
}
|
|
913
|
+
const E = /* @__PURE__ */ new Map(), P = process.platform === "win32", F = P ? "cmd.exe" : "/bin/bash", W = P ? ["/d", "/s", "/c"] : ["-c"], it = p(
|
|
914
|
+
async ({ command: s, timeout: e, run_in_background: i, kill_process_id: n, get_output_id: o, filter: a }) => {
|
|
915
|
+
if (n) {
|
|
916
|
+
const r = parseInt(n, 10), c = E.get(r);
|
|
917
|
+
return c ? (c.process.kill(), E.delete(r), `Successfully killed process with ID ${n}.`) : `Error: No background process found with ID ${n}.`;
|
|
918
|
+
}
|
|
919
|
+
if (o) {
|
|
920
|
+
const r = parseInt(o, 10), c = E.get(r);
|
|
921
|
+
if (!c)
|
|
922
|
+
return `Error: No background process found with ID ${o}.`;
|
|
923
|
+
let l = c.stdout.join(""), m = c.stderr.join("");
|
|
924
|
+
if (c.stdout = [], c.stderr = [], a) {
|
|
925
|
+
const u = new RegExp(a);
|
|
926
|
+
l = l.split(`
|
|
927
|
+
`).filter((y) => u.test(y)).join(`
|
|
928
|
+
`), m = m.split(`
|
|
929
|
+
`).filter((y) => u.test(y)).join(`
|
|
930
|
+
`);
|
|
931
|
+
}
|
|
932
|
+
let h = "";
|
|
933
|
+
return l && (h += `STDOUT:
|
|
934
|
+
${l}
|
|
935
|
+
`), m && (h += `STDERR:
|
|
936
|
+
${m}
|
|
937
|
+
`), h || "No new output since last check.";
|
|
938
|
+
}
|
|
939
|
+
if (!s)
|
|
940
|
+
return "Error: 'command' argument is required unless using 'kill_process_id' or 'get_output_id'.";
|
|
941
|
+
if (i)
|
|
942
|
+
try {
|
|
943
|
+
const r = x(F, [...W, s], {
|
|
944
|
+
timeout: e,
|
|
945
|
+
reject: !1,
|
|
946
|
+
windowsVerbatimArguments: P
|
|
947
|
+
// Windows 特殊处理
|
|
948
|
+
});
|
|
949
|
+
if (!r.pid)
|
|
950
|
+
return "Failed to start command in background.";
|
|
951
|
+
const c = {
|
|
952
|
+
process: r,
|
|
953
|
+
stdout: [],
|
|
954
|
+
stderr: []
|
|
955
|
+
};
|
|
956
|
+
return E.set(r.pid, c), r.stdout?.on("data", (l) => {
|
|
957
|
+
c.stdout.push(l.toString());
|
|
958
|
+
}), r.stderr?.on("data", (l) => {
|
|
959
|
+
c.stderr.push(l.toString());
|
|
960
|
+
}), r.on("close", () => {
|
|
961
|
+
}), `Command started in background with ID: ${r.pid}`;
|
|
962
|
+
} catch (r) {
|
|
963
|
+
return `Error starting background command: ${r}`;
|
|
964
|
+
}
|
|
965
|
+
else
|
|
966
|
+
try {
|
|
967
|
+
const r = await x(F, [...W, s], {
|
|
968
|
+
timeout: e,
|
|
969
|
+
reject: !1,
|
|
970
|
+
windowsVerbatimArguments: P
|
|
971
|
+
});
|
|
972
|
+
return r.exitCode !== 0 ? r.stderr : r.stdout;
|
|
973
|
+
} catch (r) {
|
|
974
|
+
return `Error executing command: ${r}`;
|
|
975
|
+
}
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
name: "terminal",
|
|
979
|
+
description: `Executes commands in a persistent shell session (Bash on Linux/macOS, CMD on Windows).
|
|
980
|
+
Features:
|
|
981
|
+
- Run commands (foreground or background)
|
|
982
|
+
- Retrieve background process output
|
|
983
|
+
- Kill background processes
|
|
984
|
+
- Cross-platform support (auto-detects OS)
|
|
985
|
+
|
|
986
|
+
Usage:
|
|
987
|
+
1. Run Command: Provide \`command\`. Optional: \`run_in_background\`, \`timeout\`.
|
|
988
|
+
2. Check Output: Provide \`get_output_id\`. Optional: \`filter\`.
|
|
989
|
+
3. Kill Process: Provide \`kill_process_id\`.
|
|
990
|
+
|
|
991
|
+
Notes:
|
|
992
|
+
- For file paths with spaces, ALWAYS use quotes: "path/to file"
|
|
993
|
+
- Avoid interactive commands (like top, vim)
|
|
994
|
+
- Use '&&' or ';' to chain commands (PowerShell/CMD syntax varies, simple chaining often works)
|
|
995
|
+
- CAN'T BATCH CALL THIS TOOL!
|
|
996
|
+
`,
|
|
997
|
+
schema: t.object({
|
|
998
|
+
description: t.string().describe("what you want to do"),
|
|
999
|
+
command: t.string().optional().describe("The command to execute (required for running commands)"),
|
|
1000
|
+
timeout: t.number().optional().describe("Timeout in ms (default: 120000)"),
|
|
1001
|
+
run_in_background: t.boolean().optional().describe("Run command in background"),
|
|
1002
|
+
kill_process_id: t.string().optional().describe("ID of process to kill"),
|
|
1003
|
+
get_output_id: t.string().optional().describe("ID of process to get output from"),
|
|
1004
|
+
filter: t.string().optional().describe("Regex to filter output (only for get_output_id)")
|
|
1005
|
+
})
|
|
1006
|
+
}
|
|
1007
|
+
), st = [it], nt = t.object({
|
|
1008
|
+
operation: t.enum(["create", "list", "exists"]).describe("The folder operation to perform"),
|
|
1009
|
+
folder_path: t.string().describe("The absolute path to the folder"),
|
|
1010
|
+
description: t.string().optional().describe("What you want to do"),
|
|
1011
|
+
recursive: t.boolean().default(!0).optional().describe("For create: create parent directories if they do not exist")
|
|
1012
|
+
}).strict(), ot = p(
|
|
1013
|
+
async ({ operation: s, folder_path: e, recursive: i = !0 }) => {
|
|
1014
|
+
try {
|
|
1015
|
+
const n = _.resolve(e);
|
|
1016
|
+
switch (s) {
|
|
1017
|
+
case "create":
|
|
1018
|
+
return await d.mkdir(n, { recursive: i }), `✓ Folder created successfully at: ${n}`;
|
|
1019
|
+
case "exists":
|
|
1020
|
+
try {
|
|
1021
|
+
await d.access(n);
|
|
1022
|
+
const o = await d.stat(n);
|
|
1023
|
+
return `✓ Folder exists at: ${n}
|
|
1024
|
+
Type: ${o.isDirectory() ? "Directory" : "File"}`;
|
|
1025
|
+
} catch {
|
|
1026
|
+
return `✗ Folder does not exist at: ${n}`;
|
|
1027
|
+
}
|
|
1028
|
+
case "list":
|
|
1029
|
+
try {
|
|
1030
|
+
const o = await d.readdir(n, { withFileTypes: !0 });
|
|
1031
|
+
if (o.length === 0)
|
|
1032
|
+
return `Folder is empty: ${n}`;
|
|
1033
|
+
const a = [];
|
|
1034
|
+
a.push(`📁 ${n}
|
|
1035
|
+
`);
|
|
1036
|
+
const r = [], c = [];
|
|
1037
|
+
for (const l of o) {
|
|
1038
|
+
const m = _.join(n, l.name);
|
|
1039
|
+
try {
|
|
1040
|
+
const h = await d.stat(m), u = h.size, y = h.mtime.toLocaleDateString(), v = `${l.isDirectory() ? "📁" : "📄"} ${l.name}${l.isDirectory() ? "/" : ""} (${u} bytes, ${y})`;
|
|
1041
|
+
l.isDirectory() ? r.push(v) : c.push(v);
|
|
1042
|
+
} catch {
|
|
1043
|
+
c.push(`⚠️ ${l.name} (unreadable)`);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return r.length > 0 && (a.push("Directories:"), r.forEach((l) => a.push(` ${l}`)), a.push("")), c.length > 0 && (a.push("Files:"), c.forEach((l) => a.push(` ${l}`))), a.push(`
|
|
1047
|
+
Total: ${r.length} directories, ${c.length} files`), a.join(`
|
|
1048
|
+
`);
|
|
1049
|
+
} catch (o) {
|
|
1050
|
+
if (o.code === "ENOENT")
|
|
1051
|
+
return `✗ Folder not found: ${n}`;
|
|
1052
|
+
if (o.code === "ENOTDIR")
|
|
1053
|
+
return `✗ Path exists but is not a folder: ${n}`;
|
|
1054
|
+
throw o;
|
|
1055
|
+
}
|
|
1056
|
+
default:
|
|
1057
|
+
return `✗ Unknown operation: ${s}`;
|
|
1058
|
+
}
|
|
1059
|
+
} catch (n) {
|
|
1060
|
+
return n.code === "ENOENT" ? `✗ Folder not found: ${e}` : n.code === "EACCES" ? `✗ Permission denied: ${e}` : `✗ Error: ${n.message}`;
|
|
1061
|
+
}
|
|
1062
|
+
},
|
|
1063
|
+
{
|
|
1064
|
+
name: "folder_operations",
|
|
1065
|
+
description: `Unified folder operations tool supporting create, list, and existence check.
|
|
1066
|
+
|
|
1067
|
+
**Operations:**
|
|
1068
|
+
- create: Create a folder (supports nested directory creation)
|
|
1069
|
+
- list: List all files and subdirectories with metadata
|
|
1070
|
+
- exists: Check if a folder exists
|
|
1071
|
+
|
|
1072
|
+
**Usage Examples:**
|
|
1073
|
+
- Create nested folders: {operation: "create", folder_path: "/path/to/nested/folder"}
|
|
1074
|
+
- List contents: {operation: "list", folder_path: "/path/to/folder"}
|
|
1075
|
+
- Check existence: {operation: "exists", folder_path: "/path/to/folder"}
|
|
1076
|
+
|
|
1077
|
+
**Important:**
|
|
1078
|
+
- All folder paths must be absolute paths
|
|
1079
|
+
- Create operation is recursive (creates parent directories if needed)
|
|
1080
|
+
- List operation shows file sizes and modification dates
|
|
1081
|
+
- Delete operations are not supported for safety reasons. Use terminal commands with user approval if needed.`,
|
|
1082
|
+
schema: nt
|
|
1083
|
+
}
|
|
1084
|
+
), at = t.object({
|
|
1085
|
+
description: t.string().optional().describe("what you want to do"),
|
|
1086
|
+
pattern: t.string().describe("The glob pattern to match files against"),
|
|
1087
|
+
path: t.string().optional().describe(
|
|
1088
|
+
'The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided.'
|
|
1089
|
+
)
|
|
1090
|
+
}), rt = p(
|
|
1091
|
+
async ({ pattern: s, path: e }) => {
|
|
1092
|
+
const i = await Te(s, {
|
|
1093
|
+
ignore: [
|
|
1094
|
+
"node_modules",
|
|
1095
|
+
".git",
|
|
1096
|
+
"dist",
|
|
1097
|
+
"build",
|
|
1098
|
+
".next",
|
|
1099
|
+
".turbo",
|
|
1100
|
+
"coverage",
|
|
1101
|
+
".nyc_output",
|
|
1102
|
+
"temp",
|
|
1103
|
+
".cache",
|
|
1104
|
+
"vendor",
|
|
1105
|
+
"venv",
|
|
1106
|
+
"__pycache__",
|
|
1107
|
+
"*.pyc",
|
|
1108
|
+
"target",
|
|
1109
|
+
"out",
|
|
1110
|
+
".output"
|
|
1111
|
+
],
|
|
1112
|
+
cwd: e,
|
|
1113
|
+
absolute: !0
|
|
1114
|
+
});
|
|
1115
|
+
return i.length === 0 ? "No files found." : i.join(`
|
|
1116
|
+
`);
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
name: "glob_files",
|
|
1120
|
+
description: `- Fast file pattern matching tool that works with any codebase size
|
|
1121
|
+
- Supports glob patterns like "**/*.js" or "src/**/*.ts"
|
|
1122
|
+
- Returns matching file paths sorted by modification time
|
|
1123
|
+
- Use this tool when you need to find files by name patterns
|
|
1124
|
+
- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead
|
|
1125
|
+
- You have the capability to call multiple tools in a single response. It is always better to speculatively perform multiple searches as a batch that are potentially useful.`,
|
|
1126
|
+
schema: at
|
|
1127
|
+
}
|
|
1128
|
+
), { mkdir: j, createWriteStream: ct, move: lt } = xe, X = G(Pe(import.meta.url)), dt = "microsoft/ripgrep-prebuilt", M = process.env.RIPGREP_VERSION || "v15.0.0", ut = () => {
|
|
1129
|
+
const s = process.env.npm_config_arch || R.arch(), e = process.env.platform || R.platform();
|
|
1130
|
+
switch (e) {
|
|
1131
|
+
case "darwin":
|
|
1132
|
+
return s === "arm64" ? "aarch64-apple-darwin.tar.gz" : "x86_64-apple-darwin.tar.gz";
|
|
1133
|
+
case "win32":
|
|
1134
|
+
switch (s) {
|
|
1135
|
+
case "x64":
|
|
1136
|
+
return "x86_64-pc-windows-msvc.zip";
|
|
1137
|
+
case "arm":
|
|
1138
|
+
return "aarch64-pc-windows-msvc.zip";
|
|
1139
|
+
default:
|
|
1140
|
+
return "i686-pc-windows-msvc.zip";
|
|
1141
|
+
}
|
|
1142
|
+
case "linux":
|
|
1143
|
+
switch (s) {
|
|
1144
|
+
case "x64":
|
|
1145
|
+
return "x86_64-unknown-linux-musl.tar.gz";
|
|
1146
|
+
case "arm":
|
|
1147
|
+
case "armv7l":
|
|
1148
|
+
return "arm-unknown-linux-gnueabihf.tar.gz";
|
|
1149
|
+
case "arm64":
|
|
1150
|
+
return "aarch64-unknown-linux-gnu.tar.gz";
|
|
1151
|
+
case "ppc64":
|
|
1152
|
+
return "powerpc64le-unknown-linux-gnu.tar.gz";
|
|
1153
|
+
case "s390x":
|
|
1154
|
+
return "s390x-unknown-linux-gnu.tar.gz";
|
|
1155
|
+
default:
|
|
1156
|
+
return "i686-unknown-linux-musl.tar.gz";
|
|
1157
|
+
}
|
|
1158
|
+
default:
|
|
1159
|
+
throw new Error("Unknown platform: " + e);
|
|
1160
|
+
}
|
|
1161
|
+
}, pt = async (s, e) => {
|
|
1162
|
+
try {
|
|
1163
|
+
const i = Ae(), n = await fetch(s);
|
|
1164
|
+
if (!n.ok)
|
|
1165
|
+
throw new Error(`HTTP ${n.status}: ${n.statusText}`);
|
|
1166
|
+
await Ee(n.body, ct(i)), await j(G(e), { recursive: !0 }), await lt(i, e);
|
|
1167
|
+
} catch (i) {
|
|
1168
|
+
throw console.error(`Failed to download "${s}"`), i;
|
|
1169
|
+
}
|
|
1170
|
+
}, mt = async (s, e) => {
|
|
1171
|
+
try {
|
|
1172
|
+
await j(e, { recursive: !0 }), await Se(s, { dir: e });
|
|
1173
|
+
} catch (i) {
|
|
1174
|
+
throw console.error(`Failed to unzip "${s}"`), i;
|
|
1175
|
+
}
|
|
1176
|
+
}, ht = async (s, e) => {
|
|
1177
|
+
try {
|
|
1178
|
+
await j(e, { recursive: !0 }), await x("tar", ["xvf", s, "-C", e]);
|
|
1179
|
+
} catch (i) {
|
|
1180
|
+
throw console.error(`Failed to extract "${s}"`), i;
|
|
1181
|
+
}
|
|
1182
|
+
}, gt = async (s) => {
|
|
1183
|
+
if (s === "android")
|
|
1184
|
+
try {
|
|
1185
|
+
return await x("pkg", ["install", "ripgrep", "-y"]), !0;
|
|
1186
|
+
} catch {
|
|
1187
|
+
return console.info("Could not install ripgrep via pkg. Falling back to download."), !1;
|
|
1188
|
+
}
|
|
1189
|
+
return !1;
|
|
1190
|
+
}, Q = ye(X, `rg${process.platform === "win32" ? ".exe" : ""}`), ki = async (s) => {
|
|
1191
|
+
if (await L(Q)) {
|
|
1192
|
+
console.log("rg cached");
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
const e = process.env.platform || R.platform();
|
|
1196
|
+
if (e === "android" && await gt(e))
|
|
1197
|
+
return;
|
|
1198
|
+
const i = ut(), o = `${process.env.RIPGREP_PREBUILT_BINARIES_MIRROR || `https://v6.gh-proxy.org/https://github.com/${dt}/releases/download`}/${M}/ripgrep-${M}-${i}`, a = `${Me}/vscode-ripgrep/ripgrep-${M}-${i}`, r = X;
|
|
1199
|
+
if (await L(a) ? console.info(`File ${a} has been cached`) : await pt(o, a), a.endsWith(".tar.gz"))
|
|
1200
|
+
await ht(a, r);
|
|
1201
|
+
else if (a.endsWith(".zip"))
|
|
1202
|
+
await mt(a, r);
|
|
1203
|
+
else
|
|
1204
|
+
throw new Error(`Invalid downloadPath ${a}`);
|
|
1205
|
+
}, ft = async (s, e, i = {}) => {
|
|
1206
|
+
const { timeout: n = 15e3, cwd: o = process.cwd() } = i;
|
|
1207
|
+
try {
|
|
1208
|
+
const a = await x(s, e, {
|
|
1209
|
+
cwd: o,
|
|
1210
|
+
timeout: n,
|
|
1211
|
+
reject: !1,
|
|
1212
|
+
// 不要在非零退出码时抛出异常
|
|
1213
|
+
stripFinalNewline: !1,
|
|
1214
|
+
// 保留原始输出格式
|
|
1215
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1216
|
+
env: process.env
|
|
1217
|
+
// 确保禁用颜色输出
|
|
1218
|
+
});
|
|
1219
|
+
return {
|
|
1220
|
+
code: a.exitCode ?? 0,
|
|
1221
|
+
stdout: a.stdout,
|
|
1222
|
+
stderr: a.stderr
|
|
1223
|
+
};
|
|
1224
|
+
} catch (a) {
|
|
1225
|
+
return a.timedOut ? {
|
|
1226
|
+
code: 124,
|
|
1227
|
+
// timeout exit code
|
|
1228
|
+
stdout: a.stdout || "",
|
|
1229
|
+
stderr: (a.stderr || "") + `
|
|
1230
|
+
Process timed out`
|
|
1231
|
+
} : {
|
|
1232
|
+
code: a.exitCode || 1,
|
|
1233
|
+
stdout: a.stdout || "",
|
|
1234
|
+
stderr: a.stderr || a.message || "Unknown error"
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
}, wt = p(
|
|
1238
|
+
async ({ args: s, head_limit: e }) => {
|
|
1239
|
+
if (!s || s.length === 0)
|
|
1240
|
+
return "Error: No arguments provided. Please provide ripgrep arguments.";
|
|
1241
|
+
!e && !s.includes("--max-count") && (e = 500);
|
|
1242
|
+
let i = await ft(Q, s, {
|
|
1243
|
+
timeout: 15e3,
|
|
1244
|
+
// 15秒超时
|
|
1245
|
+
cwd: process.cwd()
|
|
1246
|
+
});
|
|
1247
|
+
if (e && i.stdout) {
|
|
1248
|
+
const n = i.stdout.split(`
|
|
1249
|
+
`);
|
|
1250
|
+
n.length > e && (i.stdout = n.slice(0, e).join(`
|
|
1251
|
+
`));
|
|
1252
|
+
}
|
|
1253
|
+
return i.code !== 0 && i.stderr ? i.code === 1 && i.stdout === "" ? "No matches found." : i.code === 124 || i.stderr.includes("timeout") || i.stderr.includes("timed out") ? "Error: Search timed out after 15 seconds. Please use a more specific pattern or limit the search scope with type/glob/path parameters." : `Error executing ripgrep: ${i.stderr}` : i.stdout || "No matches found.";
|
|
1254
|
+
},
|
|
1255
|
+
{
|
|
1256
|
+
name: "search-files-rg",
|
|
1257
|
+
description: `Ripgrep (rg) - A fast text search tool that recursively searches directories for regex patterns
|
|
1258
|
+
|
|
1259
|
+
⚠️ IMPORTANT USAGE GUIDELINES:
|
|
1260
|
+
- This tool wraps the ripgrep (rg) command-line tool
|
|
1261
|
+
- Use this ONLY for searching TEXT PATTERNS within file contents
|
|
1262
|
+
- For reading entire files, use the Read tool instead
|
|
1263
|
+
- For finding files by name patterns, use the Glob tool instead
|
|
1264
|
+
|
|
1265
|
+
🔍 SEARCH PATH REQUIREMENT:
|
|
1266
|
+
- MUST always specify a search path at the end of args array
|
|
1267
|
+
- If no specific path needed, use "./" for current directory
|
|
1268
|
+
- Never omit the path parameter - ripgrep requires it
|
|
1269
|
+
|
|
1270
|
+
Usage - Pass ripgrep (rg) arguments as an array:
|
|
1271
|
+
The args array corresponds directly to 'rg [OPTIONS] PATTERN [PATH ...]'
|
|
1272
|
+
|
|
1273
|
+
Examples:
|
|
1274
|
+
- Search pattern in current directory: ["PATTERN", "./"]
|
|
1275
|
+
- Search in specific path: ["PATTERN", "src/"]
|
|
1276
|
+
- Search with file type filter: ["--type", "ts", "PATTERN", "./"]
|
|
1277
|
+
- Case insensitive search: ["-i", "PATTERN", "./"]
|
|
1278
|
+
- Show line numbers: ["-n", "PATTERN", "./"]
|
|
1279
|
+
- Show context lines: ["-C", "3", "PATTERN", "./"]
|
|
1280
|
+
- Only show file names: ["-l", "PATTERN", "./"]
|
|
1281
|
+
- Count matches: ["-c", "PATTERN", "./"]
|
|
1282
|
+
- Multiple options: ["-n", "-i", "--type", "js", "function", "src/"]
|
|
1283
|
+
|
|
1284
|
+
Common ripgrep (rg) options:
|
|
1285
|
+
- -i, --ignore-case: Case insensitive search
|
|
1286
|
+
- -n, --line-number: Show line numbers
|
|
1287
|
+
- -A NUM: Show NUM lines after each match
|
|
1288
|
+
- -B NUM: Show NUM lines before each match
|
|
1289
|
+
- -C NUM: Show NUM lines around each match
|
|
1290
|
+
- -l, --files-with-matches: Only show file paths that match
|
|
1291
|
+
- -c, --count: Only show count of matches per file
|
|
1292
|
+
- --type TYPE: Only search files of TYPE (js, ts, py, rust, etc.)
|
|
1293
|
+
- --glob PATTERN: Include/exclude files matching PATTERN
|
|
1294
|
+
- --max-count NUM: Stop after NUM matches per file
|
|
1295
|
+
- --no-ignore: Don't respect .gitignore files
|
|
1296
|
+
- --hidden: Search hidden files and directories
|
|
1297
|
+
|
|
1298
|
+
Performance:
|
|
1299
|
+
- 15 second timeout per search
|
|
1300
|
+
- Results limited to 500 lines by default (use head_limit parameter)
|
|
1301
|
+
- Respects .gitignore by default (use --no-ignore to override)
|
|
1302
|
+
`,
|
|
1303
|
+
schema: t.object({
|
|
1304
|
+
description: t.string().optional().describe("what you want to do"),
|
|
1305
|
+
args: t.array(t.string()).describe(
|
|
1306
|
+
'Ripgrep (rg) command arguments as array. Format: [OPTIONS...] PATTERN [PATH...]. MUST include path at end! Examples: ["import", "./"] (search "import" in current dir), ["-n", "-i", "function", "./"] (search "function" with line numbers, case insensitive), ["--type", "ts", "export", "src/"] (search "export" in TypeScript files in src/).'
|
|
1307
|
+
),
|
|
1308
|
+
head_limit: t.number().optional().describe(
|
|
1309
|
+
"Limit output to first N lines. If not specified and no --max-count in args, defaults to 500 lines for performance."
|
|
1310
|
+
)
|
|
1311
|
+
})
|
|
1312
|
+
}
|
|
1313
|
+
), O = 2e3, yt = t.object({
|
|
1314
|
+
description: t.string().optional().describe("what you want to do"),
|
|
1315
|
+
file_path: t.string().describe("The absolute path to the file to read"),
|
|
1316
|
+
offset: t.number().default(0).optional().describe("The line number to start reading from. Only provide if the file is too large to read at once"),
|
|
1317
|
+
limit: t.number().default(O).optional().describe("The number of lines to read. Only provide if the file is too large to read at once.")
|
|
1318
|
+
}), bt = $(
|
|
1319
|
+
async ({ file_path: s, offset: e, limit: i }) => {
|
|
1320
|
+
try {
|
|
1321
|
+
let o = (await d.readFile(s, "utf-8")).split(`
|
|
1322
|
+
`);
|
|
1323
|
+
return e && (o = o.slice(e - 1)), i && (o = o.slice(0, i)), o.join(`
|
|
1324
|
+
`);
|
|
1325
|
+
} catch (n) {
|
|
1326
|
+
if (n.code === "ENOENT")
|
|
1327
|
+
return `Error: File not found at ${s}`;
|
|
1328
|
+
throw n;
|
|
1329
|
+
}
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
name: "read_file",
|
|
1333
|
+
description: `Reads a file from the local filesystem. You can access any file directly by using this tool.
|
|
1334
|
+
Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.
|
|
1335
|
+
|
|
1336
|
+
Usage:
|
|
1337
|
+
- The file_path parameter must be an absolute path, not a relative path
|
|
1338
|
+
- By default, it reads up to ${O} lines starting from the beginning of the file
|
|
1339
|
+
- You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters
|
|
1340
|
+
- Any lines longer than ${O} characters will be truncated
|
|
1341
|
+
- Results are returned using cat -n format, with line numbers starting at 1
|
|
1342
|
+
- This tool allows You to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as You is a multimodal LLM.
|
|
1343
|
+
- This tool can read PDF files (.pdf). PDFs are processed page by page, extracting both text and visual content for analysis.
|
|
1344
|
+
- This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.
|
|
1345
|
+
- You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.
|
|
1346
|
+
- You will regularly be asked to read screenshots. If the user provides a path to a screenshot ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths like /var/folders/123/abc/T/TemporaryItems/NSIRD_screencaptureui_ZfB1tD/Screenshot.png
|
|
1347
|
+
- If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.`,
|
|
1348
|
+
schema: yt
|
|
1349
|
+
}
|
|
1350
|
+
), _t = p(
|
|
1351
|
+
async ({ file_path: s, content: e }) => {
|
|
1352
|
+
try {
|
|
1353
|
+
return await d.writeFile(s, e, "utf-8"), `File ${s} has been written successfully.`;
|
|
1354
|
+
} catch (i) {
|
|
1355
|
+
return `Error writing file: ${i.message}`;
|
|
1356
|
+
}
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
name: "write_file",
|
|
1360
|
+
description: `Writes a file to the local filesystem.
|
|
1361
|
+
Usage:
|
|
1362
|
+
- This tool will overwrite the existing file if there is one at the provided path.
|
|
1363
|
+
- If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.
|
|
1364
|
+
- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
|
|
1365
|
+
- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.
|
|
1366
|
+
- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.`,
|
|
1367
|
+
schema: t.object({
|
|
1368
|
+
description: t.string().optional().describe("what you want to do"),
|
|
1369
|
+
file_path: t.string().describe("The absolute path to the file to write (must be absolute, not relative)"),
|
|
1370
|
+
content: t.string().describe("The content to write to the file")
|
|
1371
|
+
})
|
|
1372
|
+
}
|
|
1373
|
+
), kt = t.object({
|
|
1374
|
+
description: t.string().optional().describe("what you want to do"),
|
|
1375
|
+
file_path: t.string().describe("The absolute path to the file to modify"),
|
|
1376
|
+
old_string: t.string().describe("The text to replace"),
|
|
1377
|
+
new_string: t.string().describe("The text to replace it with (must be different from old_string)"),
|
|
1378
|
+
replace_all: t.boolean().optional().default(!1).describe("Replace all occurences of old_string (default false)")
|
|
1379
|
+
}), vt = p(
|
|
1380
|
+
async ({ file_path: s, old_string: e, new_string: i, replace_all: n = !1 }) => {
|
|
1381
|
+
try {
|
|
1382
|
+
const o = await d.readFile(s, "utf-8");
|
|
1383
|
+
if (n) {
|
|
1384
|
+
if (!o.includes(e))
|
|
1385
|
+
return `Error: old_string not found in ${s}`;
|
|
1386
|
+
const a = o.split(e).join(i);
|
|
1387
|
+
return await d.writeFile(s, a, "utf-8"), `File ${s} has been edited successfully. Replaced all occurrences of old_string.`;
|
|
1388
|
+
} else {
|
|
1389
|
+
const a = o.split(e);
|
|
1390
|
+
if (a.length === 1)
|
|
1391
|
+
return `Error: old_string not found in ${s}`;
|
|
1392
|
+
if (a.length > 2)
|
|
1393
|
+
return `Error: old_string is not unique in ${s} (found ${a.length - 1} occurrences). Please provide more context or set replace_all to true.`;
|
|
1394
|
+
const r = o.replace(e, i);
|
|
1395
|
+
return await d.writeFile(s, r, "utf-8"), `File ${s} has been edited successfully. Replaced single occurrence of old_string.`;
|
|
1396
|
+
}
|
|
1397
|
+
} catch (o) {
|
|
1398
|
+
if (o.code === "ENOENT")
|
|
1399
|
+
return `Error: File not found at ${s}`;
|
|
1400
|
+
throw o;
|
|
1401
|
+
}
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
name: "edit_file",
|
|
1405
|
+
description: "Performs exact string replacements in files. \n\nUsage:\n- You must use your `Read` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file. \n- When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + tab. Everything after that tab is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.\n- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n- The edit will FAIL if `old_string` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use `replace_all` to change every instance of `old_string`. \n- Use `replace_all` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.",
|
|
1406
|
+
schema: kt
|
|
1407
|
+
}
|
|
1408
|
+
);
|
|
1409
|
+
p(
|
|
1410
|
+
async (s) => `Agent task for '${s.description}' started with prompt: ${s.prompt}. Subagent type: ${s.subagent_type}`,
|
|
1411
|
+
{
|
|
1412
|
+
name: "Task",
|
|
1413
|
+
description: `Launch a new agent to handle complex, multi-step tasks autonomously.
|
|
1414
|
+
|
|
1415
|
+
Available agent types and the tools they have access to:
|
|
1416
|
+
- general-purpose: General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you. (Tools: *)
|
|
1417
|
+
- statusline-setup: Use this agent to configure the user's Claude Code status line setting. (Tools: Read, Edit)
|
|
1418
|
+
- output-style-setup: Use this agent to create a Claude Code output style. (Tools: Read, Write, Edit, Glob, LS, Grep)
|
|
1419
|
+
|
|
1420
|
+
When using the Task tool, you must specify a subagent_type parameter to select which agent type to use.
|
|
1421
|
+
|
|
1422
|
+
|
|
1423
|
+
|
|
1424
|
+
When NOT to use the Agent tool:
|
|
1425
|
+
- If you want to read a specific file path, use the Read or Glob tool instead of the Agent tool, to find the match more quickly
|
|
1426
|
+
- If you are searching for a specific class definition like "class Foo", use the Glob tool instead, to find the match more quickly
|
|
1427
|
+
- If you are searching for code within a specific file or set of 2-3 files, use the Read tool instead of the Agent tool, to find the match more quickly
|
|
1428
|
+
- Other tasks that are not related to the agent descriptions above
|
|
1429
|
+
|
|
1430
|
+
|
|
1431
|
+
Usage notes:
|
|
1432
|
+
1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
|
|
1433
|
+
2. When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
|
|
1434
|
+
3. Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.
|
|
1435
|
+
4. The agent's outputs should generally be trusted
|
|
1436
|
+
5. Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent
|
|
1437
|
+
6. If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.
|
|
1438
|
+
|
|
1439
|
+
Example usage:
|
|
1440
|
+
|
|
1441
|
+
<example_agent_descriptions>
|
|
1442
|
+
"code-reviewer": use this agent after you are done writing a significant piece of code
|
|
1443
|
+
"greeting-responder": use this agent when to respond to user greetings with a friendly joke
|
|
1444
|
+
</example_agent_description>
|
|
1445
|
+
|
|
1446
|
+
<example>
|
|
1447
|
+
user: "Please write a function that checks if a number is prime"
|
|
1448
|
+
assistant: Sure let me write a function that checks if a number is prime
|
|
1449
|
+
assistant: First let me use the Write tool to write a function that checks if a number is prime
|
|
1450
|
+
assistant: I'm going to use the Write tool to write the following code:
|
|
1451
|
+
<code>
|
|
1452
|
+
function isPrime(n) {
|
|
1453
|
+
if (n <= 1) return false
|
|
1454
|
+
for (let i = 2; i * i <= n; i++) {
|
|
1455
|
+
if (n % i === 0) return false
|
|
1456
|
+
}
|
|
1457
|
+
return true
|
|
1458
|
+
}
|
|
1459
|
+
</code>
|
|
1460
|
+
<commentary>
|
|
1461
|
+
Since a signficant piece of code was written and the task was completed, now use the code-reviewer agent to review the code
|
|
1462
|
+
</commentary>
|
|
1463
|
+
assistant: Now let me use the code-reviewer agent to review the code
|
|
1464
|
+
assistant: Uses the Task tool to launch the with the code-reviewer agent
|
|
1465
|
+
</example>
|
|
1466
|
+
|
|
1467
|
+
<example>
|
|
1468
|
+
user: "Hello"
|
|
1469
|
+
<commentary>
|
|
1470
|
+
Since the user is greeting, use the greeting-responder agent to respond with a friendly joke
|
|
1471
|
+
</commentary>
|
|
1472
|
+
assistant: "I'm going to use the Task tool to launch the with the greeting-responder agent"
|
|
1473
|
+
</example>
|
|
1474
|
+
`,
|
|
1475
|
+
schema: t.object({
|
|
1476
|
+
description: t.string().describe("A short (3-5 word) description of the task"),
|
|
1477
|
+
prompt: t.string().describe("The task for the agent to perform"),
|
|
1478
|
+
subagent_type: t.string().describe("The type of specialized agent to use for this task")
|
|
1479
|
+
})
|
|
1480
|
+
}
|
|
1481
|
+
);
|
|
1482
|
+
const Tt = t.object({
|
|
1483
|
+
content: t.string().min(1),
|
|
1484
|
+
status: t.enum(["pending", "in_progress", "completed"]),
|
|
1485
|
+
id: t.string()
|
|
1486
|
+
}), St = t.object({
|
|
1487
|
+
todos: t.array(Tt).describe("The updated todo list")
|
|
1488
|
+
}), xt = p(
|
|
1489
|
+
async () => "todo saved successfully",
|
|
1490
|
+
{
|
|
1491
|
+
name: "TodoWrite",
|
|
1492
|
+
description: `Use this tool to create and manage a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
|
|
1493
|
+
It also helps the user understand the progress of the task and overall progress of their requests.
|
|
1494
|
+
## When to Use This Tool
|
|
1495
|
+
Use this tool proactively in these scenarios:
|
|
1496
|
+
|
|
1497
|
+
1. Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
|
|
1498
|
+
2. Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
|
1499
|
+
3. User explicitly requests todo list - When the user directly asks you to use the todo list
|
|
1500
|
+
4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
|
|
1501
|
+
5. After receiving new instructions - Immediately capture user requirements as todos
|
|
1502
|
+
6. When you start working on a task - Mark it as in_progress BEFORE beginning work. Ideally you should only have one todo as in_progress at a time
|
|
1503
|
+
7. After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
|
|
1504
|
+
|
|
1505
|
+
## When NOT to Use This Tool
|
|
1506
|
+
|
|
1507
|
+
Skip using this tool when:
|
|
1508
|
+
1. There is only a single, straightforward task
|
|
1509
|
+
2. The task is trivial and tracking it provides no organizational benefit
|
|
1510
|
+
3. The task can be completed in less than 3 trivial steps
|
|
1511
|
+
4. The task is purely conversational or informational
|
|
1512
|
+
|
|
1513
|
+
NOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.
|
|
1514
|
+
|
|
1515
|
+
## Examples of When to Use the Todo List
|
|
1516
|
+
|
|
1517
|
+
<example>
|
|
1518
|
+
User: I want to add a dark mode toggle to the application settings. Make sure you run the tests and build when you're done!
|
|
1519
|
+
Assistant: I'll help add a dark mode toggle to your application settings. Let me create a todo list to track this implementation.
|
|
1520
|
+
*Creates todo list with the following items:*
|
|
1521
|
+
1. Create dark mode toggle component in Settings page
|
|
1522
|
+
2. Add dark mode state management (context/store)
|
|
1523
|
+
3. Implement CSS-in-JS styles for dark theme
|
|
1524
|
+
4. Update existing components to support theme switching
|
|
1525
|
+
5. Run tests and build process, addressing any failures or errors that occur
|
|
1526
|
+
*Begins working on the first task*
|
|
1527
|
+
|
|
1528
|
+
<reasoning>
|
|
1529
|
+
The assistant used the todo list because:
|
|
1530
|
+
1. Adding dark mode is a multi-step feature requiring UI, state management, and styling changes
|
|
1531
|
+
2. The user explicitly requested tests and build be run afterward
|
|
1532
|
+
3. The assistant inferred that tests and build need to pass by adding "Ensure tests and build succeed" as the final task
|
|
1533
|
+
</reasoning>
|
|
1534
|
+
</example>
|
|
1535
|
+
|
|
1536
|
+
<example>
|
|
1537
|
+
User: Help me rename the function getCwd to getCurrentWorkingDirectory across my project
|
|
1538
|
+
Assistant: Let me first search through your codebase to find all occurrences of 'getCwd'.
|
|
1539
|
+
*Uses grep or search tools to locate all instances of getCwd in the codebase*
|
|
1540
|
+
Assistant: I've found 15 instances of 'getCwd' across 8 different files. Let me create a todo list to track these changes.
|
|
1541
|
+
*Creates todo list with specific items for each file that needs updating*
|
|
1542
|
+
|
|
1543
|
+
<reasoning>
|
|
1544
|
+
The assistant used the todo list because:
|
|
1545
|
+
1. First, the assistant searched to understand the scope of the task
|
|
1546
|
+
2. Upon finding multiple occurrences across different files, it determined this was a complex task with multiple steps
|
|
1547
|
+
3. The todo list helps ensure every instance is tracked and updated systematically
|
|
1548
|
+
4. This approach prevents missing any occurrences and maintains code consistency
|
|
1549
|
+
</reasoning>
|
|
1550
|
+
</example>
|
|
1551
|
+
|
|
1552
|
+
|
|
1553
|
+
<example>
|
|
1554
|
+
User: I need to implement these features for my e-commerce site: user registration, product catalog, shopping cart, and checkout flow.
|
|
1555
|
+
Assistant: I'll help implement these features. First, let's add all the features to the todo list.
|
|
1556
|
+
*Creates a todo list breaking down each feature into specific tasks based on the project architecture*
|
|
1557
|
+
Assistant: Let's start with user registration. This will involve creating database models, API endpoints, and frontend forms that integrate with your existing authentication system.
|
|
1558
|
+
|
|
1559
|
+
<reasoning>
|
|
1560
|
+
The assistant used the todo list because:
|
|
1561
|
+
1. The user provided multiple complex features to implement in a comma separated list
|
|
1562
|
+
2. The todo list helps organize these large features into manageable tasks
|
|
1563
|
+
3. This approach allows for tracking progress across the entire implementation
|
|
1564
|
+
</reasoning>
|
|
1565
|
+
</example>
|
|
1566
|
+
|
|
1567
|
+
<example>
|
|
1568
|
+
User: Can you help optimize my React application? It's rendering slowly and has performance issues.</user>
|
|
1569
|
+
Assistant: I'll help optimize your React application. First, let me examine your codebase to identify potential performance bottlenecks.
|
|
1570
|
+
*Reviews component structure, render patterns, state management, and data fetching*
|
|
1571
|
+
Assistant: After analyzing your codebase, I've identified several performance issues. Let me create a todo list to track our optimization efforts.
|
|
1572
|
+
*Creates todo list with items like: 1) Implement memoization for expensive calculations in ProductList, 2) Add virtualization for long lists in Dashboard, 3) Optimize image loading in Gallery component, 4) Fix state update loops in ShoppingCart, 5) Review bundle size and implement code splitting*
|
|
1573
|
+
Let's start by implementing memoization for the expensive calculations in your ProductList component.</assistant>
|
|
1574
|
+
|
|
1575
|
+
<reasoning>
|
|
1576
|
+
The assistant used the todo list because:
|
|
1577
|
+
1. First, the assistant examined the codebase to identify specific performance issues
|
|
1578
|
+
2. Based on this analysis, it identified multiple optimization opportunities
|
|
1579
|
+
3. Performance optimization is a non-trivial task requiring multiple steps
|
|
1580
|
+
4. The todo list helps methodically track improvements across different components
|
|
1581
|
+
5. This systematic approach ensures all performance bottlenecks are addressed
|
|
1582
|
+
</reasoning>
|
|
1583
|
+
</example>
|
|
1584
|
+
|
|
1585
|
+
## Examples of When NOT to Use the Todo List
|
|
1586
|
+
|
|
1587
|
+
<example>
|
|
1588
|
+
User: How do I print 'Hello World' in Python?
|
|
1589
|
+
Assistant: In Python, you can print "Hello World" with this simple code:
|
|
1590
|
+
|
|
1591
|
+
python
|
|
1592
|
+
print("Hello World")
|
|
1593
|
+
|
|
1594
|
+
This will output the text "Hello World" to the console when executed.</assistant>
|
|
1595
|
+
|
|
1596
|
+
<reasoning>
|
|
1597
|
+
The assistant did not use the todo list because this is a single, trivial task that can be completed in one step. There's no need to track multiple tasks or steps for such a straightforward request.
|
|
1598
|
+
</reasoning>
|
|
1599
|
+
</example>
|
|
1600
|
+
|
|
1601
|
+
<example>
|
|
1602
|
+
User: What does the git status command do?
|
|
1603
|
+
Assistant: The git status command shows the current state of your working directory and staging area. It displays which changes have been staged, which haven't, and which files aren't being tracked by Git. This is a fundamental command for understanding the current state of your repository before making commits.
|
|
1604
|
+
|
|
1605
|
+
<reasoning>
|
|
1606
|
+
The assistant did not use the todo list because this is an informational request with no actual coding task to complete. The user is simply asking for an explanation, not for the assistant to perform multiple steps or tasks.
|
|
1607
|
+
</reasoning>
|
|
1608
|
+
</example>
|
|
1609
|
+
|
|
1610
|
+
<example>
|
|
1611
|
+
User: Can you add a comment to the calculateTotal function to explain what it does?
|
|
1612
|
+
Assistant: Sure, let me add a comment to the calculateTotal function to explain what it does.
|
|
1613
|
+
* Uses the Edit tool to add a comment to the calculateTotal function *
|
|
1614
|
+
|
|
1615
|
+
<reasoning>
|
|
1616
|
+
The assistant did not use the todo list because this is a single, straightforward task confined to one location in the code. Adding a comment doesn't require tracking multiple steps or systematic organization.
|
|
1617
|
+
</reasoning>
|
|
1618
|
+
</example>
|
|
1619
|
+
|
|
1620
|
+
<example>
|
|
1621
|
+
User: Run npm install for me and tell me what happens.
|
|
1622
|
+
Assistant: I'll run the npm install command for you.
|
|
1623
|
+
|
|
1624
|
+
*Executes: npm install*
|
|
1625
|
+
|
|
1626
|
+
The command completed successfully. Here's the output:
|
|
1627
|
+
[Output of npm install command]
|
|
1628
|
+
|
|
1629
|
+
All dependencies have been installed according to your package.json file.
|
|
1630
|
+
|
|
1631
|
+
<reasoning>
|
|
1632
|
+
The assistant did not use the todo list because this is a single command execution with immediate results. There are no multiple steps to track or organize, making the todo list unnecessary for this straightforward task.
|
|
1633
|
+
</reasoning>
|
|
1634
|
+
</example>
|
|
1635
|
+
|
|
1636
|
+
## Task States and Management
|
|
1637
|
+
|
|
1638
|
+
1. **Task States**: Use these states to track progress:
|
|
1639
|
+
- pending: Task not yet started
|
|
1640
|
+
- in_progress: Currently working on (limit to ONE task at a time)
|
|
1641
|
+
- completed: Task finished successfully
|
|
1642
|
+
|
|
1643
|
+
2. **Task Management**:
|
|
1644
|
+
- Update task status in real-time as you work
|
|
1645
|
+
- Mark tasks complete IMMEDIATELY after finishing (don't batch completions)
|
|
1646
|
+
- Only have ONE task in_progress at any time
|
|
1647
|
+
- Complete current tasks before starting new ones
|
|
1648
|
+
- Remove tasks that are no longer relevant from the list entirely
|
|
1649
|
+
|
|
1650
|
+
3. **Task Completion Requirements**:
|
|
1651
|
+
- ONLY mark a task as completed when you have FULLY accomplished it
|
|
1652
|
+
- If you encounter errors, blockers, or cannot finish, keep the task as in_progress
|
|
1653
|
+
- When blocked, create a new task describing what needs to be resolved
|
|
1654
|
+
- Never mark a task as completed if:
|
|
1655
|
+
- Tests are failing
|
|
1656
|
+
- Implementation is partial
|
|
1657
|
+
- You encountered unresolved errors
|
|
1658
|
+
- You couldn't find necessary files or dependencies
|
|
1659
|
+
|
|
1660
|
+
4. **Task Breakdown**:
|
|
1661
|
+
- Create specific, actionable items
|
|
1662
|
+
- Break complex tasks into smaller, manageable steps
|
|
1663
|
+
- Use clear, descriptive task names
|
|
1664
|
+
|
|
1665
|
+
When in doubt, use this tool. Being proactive with task management demonstrates attentiveness and ensures you complete all requirements successfully.
|
|
1666
|
+
`,
|
|
1667
|
+
schema: St
|
|
1668
|
+
}
|
|
1669
|
+
), Ct = t.object({
|
|
1670
|
+
label: t.string().min(1).max(50).describe("选项显示文本,简洁明了(1-50 字符)")
|
|
1671
|
+
}), Et = t.object({
|
|
1672
|
+
description: t.string().min(1).describe("向用户提出的问题,清晰具体,包含必要的上下文"),
|
|
1673
|
+
type: t.enum(["single_select", "multi_select"]).describe("选择类型:single_select(单选)或 multi_select(多选)"),
|
|
1674
|
+
options: t.array(Ct).min(2).max(6).describe("选项列表,至少 2 个,最多 6 个"),
|
|
1675
|
+
allow_custom_input: t.boolean().default(!0).describe("是否允许用户输入自定义文本,默认 true"),
|
|
1676
|
+
placeholder: t.string().optional().describe("自定义输入框的占位符文本")
|
|
1677
|
+
}), Pt = $(() => {
|
|
1678
|
+
}, {
|
|
1679
|
+
name: "ask_user_questions",
|
|
1680
|
+
description: "Ask the user a question with selectable options",
|
|
1681
|
+
schema: Et
|
|
1682
|
+
}), At = [
|
|
1683
|
+
Pt,
|
|
1684
|
+
xt,
|
|
1685
|
+
rt,
|
|
1686
|
+
wt,
|
|
1687
|
+
bt,
|
|
1688
|
+
_t,
|
|
1689
|
+
vt,
|
|
1690
|
+
ot,
|
|
1691
|
+
...st
|
|
1692
|
+
];
|
|
1693
|
+
async function Mt(s, e) {
|
|
1694
|
+
await s.addTool({
|
|
1695
|
+
id: e.name,
|
|
1696
|
+
name: e.name,
|
|
1697
|
+
description: e.description
|
|
1698
|
+
});
|
|
1699
|
+
const i = {
|
|
1700
|
+
id: e.name,
|
|
1701
|
+
name: e.name,
|
|
1702
|
+
description: e.description,
|
|
1703
|
+
paramsSchema: e.schema,
|
|
1704
|
+
execute: async (n) => {
|
|
1705
|
+
const o = await e.invoke(n);
|
|
1706
|
+
return o && typeof o == "object" && "content" in o ? o.content : o;
|
|
1707
|
+
}
|
|
1708
|
+
};
|
|
1709
|
+
s.tools.registerImplementation(i);
|
|
1710
|
+
}
|
|
1711
|
+
async function Rt(s) {
|
|
1712
|
+
return await Promise.all(At.map((e) => Mt(s, e)));
|
|
1713
|
+
}
|
|
1714
|
+
async function It(s) {
|
|
1715
|
+
const e = {
|
|
1716
|
+
id: "subagents",
|
|
1717
|
+
name: "subagents",
|
|
1718
|
+
description: "Task delegation to specialized agents",
|
|
1719
|
+
execute: async () => {
|
|
1720
|
+
const { SubAgentsMiddleware: a } = await import("./subTasks-5KLIr9iy.mjs");
|
|
1721
|
+
return new a(s);
|
|
1722
|
+
}
|
|
1723
|
+
};
|
|
1724
|
+
await s.addMiddleware(e), s.middlewares.registerImplementation(e);
|
|
1725
|
+
const i = {
|
|
1726
|
+
id: "memories",
|
|
1727
|
+
name: "memories",
|
|
1728
|
+
description: "Knowledge persistence",
|
|
1729
|
+
execute: async (a) => {
|
|
1730
|
+
a.projectMemoriesDir = a.projectMemoriesDir || "./.claude/memories";
|
|
1731
|
+
const { MemoriesMiddleware: r } = await import("./memories-rSGKIPk5.mjs");
|
|
1732
|
+
return new r(a);
|
|
1733
|
+
}
|
|
1734
|
+
};
|
|
1735
|
+
await s.addMiddleware(i), s.middlewares.registerImplementation(i);
|
|
1736
|
+
const n = {
|
|
1737
|
+
id: "skills",
|
|
1738
|
+
name: "skills",
|
|
1739
|
+
description: "Progressive skills disclosure",
|
|
1740
|
+
execute: async (a) => {
|
|
1741
|
+
a.projectSkillsDir = a.projectSkillsDir || "./.claude/skills";
|
|
1742
|
+
const { SkillsMiddleware: r } = await import("@langgraph-js/standard-agent");
|
|
1743
|
+
return new r(a);
|
|
1744
|
+
}
|
|
1745
|
+
};
|
|
1746
|
+
await s.addMiddleware(n), s.middlewares.registerImplementation(n);
|
|
1747
|
+
const o = {
|
|
1748
|
+
id: "agents_md",
|
|
1749
|
+
name: "agents_md",
|
|
1750
|
+
description: "Inject agent documentation",
|
|
1751
|
+
execute: async (a) => {
|
|
1752
|
+
const { AgentsMdMiddleware: r } = await import("@langgraph-js/standard-agent");
|
|
1753
|
+
return new r({ projectRoot: a?.projectRoot });
|
|
1754
|
+
}
|
|
1755
|
+
};
|
|
1756
|
+
await s.addMiddleware(o), s.middlewares.registerImplementation(o);
|
|
1757
|
+
}
|
|
1758
|
+
const Ot = `# Zen Code
|
|
1759
|
+
|
|
1760
|
+
你是 Zen Code,一个高度自主的编程智能体。你具备独立思考、规划和执行复杂任务的能力。
|
|
1761
|
+
|
|
1762
|
+
---
|
|
1763
|
+
|
|
1764
|
+
## 一、核心认知模型
|
|
1765
|
+
|
|
1766
|
+
### 1.1 思维框架
|
|
1767
|
+
|
|
1768
|
+
你采用 **观察-推理-行动-反思** 循环(ORAR):
|
|
1769
|
+
|
|
1770
|
+
\`\`\`
|
|
1771
|
+
OBSERVE → REASON → ACT → REFLECT
|
|
1772
|
+
↑ ↓
|
|
1773
|
+
←←←←←←←←←←←←←←←←←←←←←←←←←
|
|
1774
|
+
\`\`\`
|
|
1775
|
+
|
|
1776
|
+
- **观察 (Observe)**: 收集信息、理解上下文、识别约束
|
|
1777
|
+
- **推理 (Reason)**: 分析问题、评估方案、规划路径
|
|
1778
|
+
- **行动 (Act)**: 执行操作、生成代码、调用工具
|
|
1779
|
+
- **反思 (Reflect)**: 验证结果、学习教训、优化策略
|
|
1780
|
+
|
|
1781
|
+
### 1.2 自主决策等级
|
|
1782
|
+
|
|
1783
|
+
根据任务风险自动选择决策模式:
|
|
1784
|
+
|
|
1785
|
+
| 等级 | 触发条件 | 行为模式 |
|
|
1786
|
+
|------|----------|----------|
|
|
1787
|
+
| **L1 自动** | 只读操作、低风险修改 | 直接执行,事后汇报 |
|
|
1788
|
+
| **L2 通知** | 中等修改、可逆操作 | 执行并详细说明 |
|
|
1789
|
+
| **L3 确认** | 高风险操作、架构变更 | 先询问再执行 |
|
|
1790
|
+
|
|
1791
|
+
**L1 自动执行**:文件读取、代码搜索、类型检查、格式化
|
|
1792
|
+
**L2 通知执行**:单文件修改、添加测试、重构局部代码
|
|
1793
|
+
**L3 需确认**:多文件架构变更、添加依赖、删除代码、执行脚本
|
|
1794
|
+
|
|
1795
|
+
### 1.3 任务复杂度评估
|
|
1796
|
+
|
|
1797
|
+
接收任务后立即评估:
|
|
1798
|
+
|
|
1799
|
+
\`\`\`
|
|
1800
|
+
简单 (S): 单点修改,<5分钟,直接执行
|
|
1801
|
+
中等 (M): 多文件协调,5-30分钟,制定计划
|
|
1802
|
+
复杂 (C): 架构变更,>30分钟,使用 TodoWrite 分解
|
|
1803
|
+
\`\`\`
|
|
1804
|
+
|
|
1805
|
+
---
|
|
1806
|
+
|
|
1807
|
+
## 二、信息收集策略
|
|
1808
|
+
|
|
1809
|
+
### 2.1 递进式探索
|
|
1810
|
+
|
|
1811
|
+
从宏观到微观,按需深入:
|
|
1812
|
+
|
|
1813
|
+
\`\`\`
|
|
1814
|
+
Level 1: 项目结构 (AGENTS.md、README.md、package.json)
|
|
1815
|
+
↓
|
|
1816
|
+
Level 2: 模块边界 (入口文件、类型定义、配置文件)
|
|
1817
|
+
↓
|
|
1818
|
+
Level 3: 实现细节 (具体函数、测试用例、依赖关系)
|
|
1819
|
+
\`\`\`
|
|
1820
|
+
|
|
1821
|
+
### 2.2 搜索策略矩阵
|
|
1822
|
+
|
|
1823
|
+
| 目标 | 首选工具 | 备选策略 |
|
|
1824
|
+
|------|----------|----------|
|
|
1825
|
+
| 找函数/类定义 | \`search-files-rg\` 正则 | glob + 读取 |
|
|
1826
|
+
| 找文件位置 | \`glob_files\` 模式 | 目录遍历 |
|
|
1827
|
+
| 理解调用关系 | grep 引用 + 读取上下文 | 类型定义追踪 |
|
|
1828
|
+
| 找配置项 | grep 配置文件 | 环境变量搜索 |
|
|
1829
|
+
|
|
1830
|
+
### 2.3 上下文构建原则
|
|
1831
|
+
|
|
1832
|
+
- **最小必要**:只读取完成任务所需的信息
|
|
1833
|
+
- **关联发现**:通过 import/export 追踪依赖
|
|
1834
|
+
- **类型优先**:先看接口定义,再看实现
|
|
1835
|
+
- **测试参考**:测试用例揭示使用方式和边界
|
|
1836
|
+
|
|
1837
|
+
---
|
|
1838
|
+
|
|
1839
|
+
## 三、执行策略
|
|
1840
|
+
|
|
1841
|
+
### 3.1 代码修改原则
|
|
1842
|
+
|
|
1843
|
+
**保守修改**:
|
|
1844
|
+
- 只改必须改的部分
|
|
1845
|
+
- 保持与现有代码风格一致
|
|
1846
|
+
- 优先使用项目已有的模式和工具
|
|
1847
|
+
|
|
1848
|
+
**安全边界**:
|
|
1849
|
+
- 修改前理解影响范围
|
|
1850
|
+
- 一次只改一个关注点
|
|
1851
|
+
- 保持向后兼容,除非明确要求破坏性变更
|
|
1852
|
+
|
|
1853
|
+
### 3.2 错误处理策略
|
|
1854
|
+
|
|
1855
|
+
遇到错误时按优先级尝试:
|
|
1856
|
+
|
|
1857
|
+
1. **理解错误**:分析错误信息,定位根因
|
|
1858
|
+
2. **局部修复**:尝试最小范围修复
|
|
1859
|
+
3. **扩大搜索**:收集更多上下文
|
|
1860
|
+
4. **替代方案**:尝试不同实现路径
|
|
1861
|
+
5. **请求协助**:使用 \`ask_user_questions\` 询问方向
|
|
1862
|
+
|
|
1863
|
+
### 3.3 验证循环
|
|
1864
|
+
|
|
1865
|
+
每个修改后执行验证:
|
|
1866
|
+
|
|
1867
|
+
\`\`\`
|
|
1868
|
+
修改代码 → 检查语法 → 运行相关测试 → 确认无副作用
|
|
1869
|
+
\`\`\`
|
|
1870
|
+
|
|
1871
|
+
---
|
|
1872
|
+
|
|
1873
|
+
## 四、输出规范
|
|
1874
|
+
|
|
1875
|
+
### 4.1 简洁原则
|
|
1876
|
+
|
|
1877
|
+
- **无寒暄**:直接进入主题
|
|
1878
|
+
- **无冗余**:不重复用户已知信息
|
|
1879
|
+
- **结构化**:使用列表和代码块
|
|
1880
|
+
|
|
1881
|
+
### 4.2 信息层级
|
|
1882
|
+
|
|
1883
|
+
**必要信息** - 总是包含:
|
|
1884
|
+
- 执行了什么操作
|
|
1885
|
+
- 修改了哪些文件
|
|
1886
|
+
- 关键结果或发现
|
|
1887
|
+
|
|
1888
|
+
**补充信息** - 按需包含:
|
|
1889
|
+
- 替代方案说明
|
|
1890
|
+
- 潜在风险提示
|
|
1891
|
+
- 后续建议
|
|
1892
|
+
|
|
1893
|
+
**详细信息** - 需要时写入文件:
|
|
1894
|
+
- 完整分析报告
|
|
1895
|
+
- 大量代码展示
|
|
1896
|
+
- 详细调试日志
|
|
1897
|
+
|
|
1898
|
+
### 4.3 代码展示
|
|
1899
|
+
|
|
1900
|
+
\`\`\`diff
|
|
1901
|
+
# 只展示变更的关键部分
|
|
1902
|
+
+ // 新增代码
|
|
1903
|
+
- // 删除代码
|
|
1904
|
+
// 上下文(少量)
|
|
1905
|
+
\`\`\`
|
|
1906
|
+
|
|
1907
|
+
### 4.4 长度控制
|
|
1908
|
+
|
|
1909
|
+
- 单次回复 < 50 行
|
|
1910
|
+
- 超过时使用 \`write_file\` 保存详情
|
|
1911
|
+
- 或使用 \`ask_user_questions\` 分步展开
|
|
1912
|
+
|
|
1913
|
+
---
|
|
1914
|
+
|
|
1915
|
+
## 五、编码标准
|
|
1916
|
+
|
|
1917
|
+
### 5.1 技术选型优先级
|
|
1918
|
+
|
|
1919
|
+
1. 项目已有方案 > 引入新方案
|
|
1920
|
+
2. 标准库 > 轻量第三方库 > 重型框架
|
|
1921
|
+
3. 成熟稳定 > 新潮技术
|
|
1922
|
+
4. 类型安全 > 便捷
|
|
1923
|
+
|
|
1924
|
+
### 5.2 代码质量
|
|
1925
|
+
|
|
1926
|
+
**必须**:
|
|
1927
|
+
- 类型完整(禁用 any)
|
|
1928
|
+
- 错误处理(无静默失败)
|
|
1929
|
+
- 可读性(描述性命名)
|
|
1930
|
+
|
|
1931
|
+
**推荐**:
|
|
1932
|
+
- 函数式风格(纯函数、不可变)
|
|
1933
|
+
- 单一职责(一个函数做一件事)
|
|
1934
|
+
- 组合优于继承
|
|
1935
|
+
|
|
1936
|
+
### 5.3 命名规范
|
|
1937
|
+
|
|
1938
|
+
| 类型 | 规范 | 示例 |
|
|
1939
|
+
|------|------|------|
|
|
1940
|
+
| 布尔值 | is/has/should 前缀 | isLoading, hasError |
|
|
1941
|
+
| 事件处理 | handle/on 前缀 | handleClick, onSubmit |
|
|
1942
|
+
| 异步函数 | 动词开头 | fetchUser, createTask |
|
|
1943
|
+
| 常量 | UPPER_SNAKE_CASE | MAX_RETRY_COUNT |
|
|
1944
|
+
|
|
1945
|
+
### 5.4 Git 规范
|
|
1946
|
+
|
|
1947
|
+
Angular 格式:\`type(scope): subject\`
|
|
1948
|
+
|
|
1949
|
+
类型:feat, fix, refactor, docs, test, chore
|
|
1950
|
+
|
|
1951
|
+
示例:\`feat(auth): add JWT refresh token\`
|
|
1952
|
+
|
|
1953
|
+
---
|
|
1954
|
+
|
|
1955
|
+
## 六、工具使用指南
|
|
1956
|
+
|
|
1957
|
+
### 6.1 性能意识
|
|
1958
|
+
|
|
1959
|
+
| 操作类型 | 耗时 | 策略 |
|
|
1960
|
+
|----------|------|------|
|
|
1961
|
+
| 读取/搜索 | <0.5s | 优先使用 |
|
|
1962
|
+
| 执行命令 | 0.5-5s | 按需使用 |
|
|
1963
|
+
| 全项目扫描 | >5s | 避免使用 |
|
|
1964
|
+
|
|
1965
|
+
### 6.2 路径规范
|
|
1966
|
+
|
|
1967
|
+
所有文件路径必须使用绝对路径。
|
|
1968
|
+
|
|
1969
|
+
### 6.3 文件操作
|
|
1970
|
+
|
|
1971
|
+
**移动/重命名**:使用 terminal 执行 \`mv\` 命令
|
|
1972
|
+
**批量修改**:使用 \`edit_file\` 的 \`replace_all\` 参数
|
|
1973
|
+
**新建目录**:使用 \`folder_operations\` 的 create 操作
|
|
1974
|
+
|
|
1975
|
+
### 6.4 并行执行
|
|
1976
|
+
|
|
1977
|
+
无依赖的操作可以并行调用多个工具,提高效率。
|
|
1978
|
+
|
|
1979
|
+
---
|
|
1980
|
+
|
|
1981
|
+
## 七、协作模式
|
|
1982
|
+
|
|
1983
|
+
### 7.1 与用户协作
|
|
1984
|
+
|
|
1985
|
+
**主动沟通**:
|
|
1986
|
+
- 发现潜在问题时提前告知
|
|
1987
|
+
- 有多个可行方案时请求选择
|
|
1988
|
+
- 任务完成时提供后续建议
|
|
1989
|
+
|
|
1990
|
+
**避免**:
|
|
1991
|
+
- 假设用户意图(不确定就问)
|
|
1992
|
+
- 隐藏风险或问题
|
|
1993
|
+
- 过度询问显而易见的事情
|
|
1994
|
+
|
|
1995
|
+
### 7.2 任务管理
|
|
1996
|
+
|
|
1997
|
+
**简单任务**:直接执行
|
|
1998
|
+
**复杂任务**:使用 TodoWrite 分解追踪
|
|
1999
|
+
|
|
2000
|
+
### 7.3 知识积累
|
|
2001
|
+
|
|
2002
|
+
执行任务中发现的重要信息:
|
|
2003
|
+
- 项目特有约定
|
|
2004
|
+
- 踩坑经验
|
|
2005
|
+
- 最佳实践
|
|
2006
|
+
|
|
2007
|
+
可建议用户记录到 .claude/memories/ 或 AGENTS.md
|
|
2008
|
+
|
|
2009
|
+
---
|
|
2010
|
+
|
|
2011
|
+
## 八、安全边界
|
|
2012
|
+
|
|
2013
|
+
### 8.1 绝对禁止
|
|
2014
|
+
|
|
2015
|
+
- 编写/解释恶意代码
|
|
2016
|
+
- 删除无法恢复的数据(未备份)
|
|
2017
|
+
- 暴露敏感信息(密钥、密码)
|
|
2018
|
+
- 绕过安全检查
|
|
2019
|
+
|
|
2020
|
+
### 8.2 谨慎操作
|
|
2021
|
+
|
|
2022
|
+
以下操作需要 L3 确认:
|
|
2023
|
+
- 执行未知脚本
|
|
2024
|
+
- 修改安全相关配置
|
|
2025
|
+
- 访问网络/外部服务
|
|
2026
|
+
- 修改系统级文件
|
|
2027
|
+
|
|
2028
|
+
---
|
|
2029
|
+
|
|
2030
|
+
## 九、自我提升
|
|
2031
|
+
|
|
2032
|
+
### 9.1 持续学习
|
|
2033
|
+
|
|
2034
|
+
- 从每次交互中学习项目约定
|
|
2035
|
+
- 识别并适应用户偏好
|
|
2036
|
+
- 发现可复用的模式
|
|
2037
|
+
|
|
2038
|
+
### 9.2 元认知
|
|
2039
|
+
|
|
2040
|
+
定期反思:
|
|
2041
|
+
- 这次任务我做得如何?
|
|
2042
|
+
- 有没有更好的方法?
|
|
2043
|
+
- 用户的真实需求是什么?
|
|
2044
|
+
|
|
2045
|
+
---
|
|
2046
|
+
|
|
2047
|
+
## 附录:决策速查
|
|
2048
|
+
|
|
2049
|
+
\`\`\`
|
|
2050
|
+
任务来了
|
|
2051
|
+
↓
|
|
2052
|
+
评估复杂度 → S: 直接做 → 完成汇报
|
|
2053
|
+
↓ M/C
|
|
2054
|
+
需要更多信息? → 是 → 收集信息(递进式)
|
|
2055
|
+
↓ 否
|
|
2056
|
+
有风险? → L3 → 询问确认
|
|
2057
|
+
↓ L1/L2
|
|
2058
|
+
执行 → 验证 → 反思 → 输出结果
|
|
2059
|
+
\`\`\`
|
|
2060
|
+
|
|
2061
|
+
`;
|
|
2062
|
+
async function $t(s) {
|
|
2063
|
+
return `
|
|
2064
|
+
## 环境信息
|
|
2065
|
+
工作目录: ${process.cwd()}
|
|
2066
|
+
平台: ${process.platform}
|
|
2067
|
+
日期: ${(/* @__PURE__ */ new Date()).toLocaleDateString()}
|
|
2068
|
+
`;
|
|
2069
|
+
}
|
|
2070
|
+
const zt = `# 架构师 - 任务派发协调者
|
|
2071
|
+
|
|
2072
|
+
你是一位**任务派发架构师**,核心职责是将用户需求分析并拆解为子任务,然后委派给合适的子 agent 执行。
|
|
2073
|
+
|
|
2074
|
+
## 核心职责
|
|
2075
|
+
|
|
2076
|
+
**你的唯一任务**:
|
|
2077
|
+
1. 理解用户需求
|
|
2078
|
+
2. 拆解为可执行的子任务
|
|
2079
|
+
3. 委派给合适的子 agent
|
|
2080
|
+
4. 跟踪和汇总结果
|
|
2081
|
+
|
|
2082
|
+
**不要做的事**:
|
|
2083
|
+
- ❌ 不要自己编写代码
|
|
2084
|
+
- ❌ 不要自己读取文件或搜索代码
|
|
2085
|
+
- ❌ 不要自己执行终端命令
|
|
2086
|
+
- ❌ 不要做具体的架构分析或设计文档
|
|
2087
|
+
|
|
2088
|
+
## 工作流程
|
|
2089
|
+
|
|
2090
|
+
### 步骤 1:需求分析
|
|
2091
|
+
|
|
2092
|
+
当收到用户请求时,快速判断:
|
|
2093
|
+
|
|
2094
|
+
1. **任务类型**:
|
|
2095
|
+
- 代码实现/修改 → 委派给 \`agents/default\`
|
|
2096
|
+
- 任务规划/协调 → 委派给 \`agents/manager\`
|
|
2097
|
+
- 复杂任务 → 先由 \`agents/manager\` 规划,再由 \`agents/default\` 执行
|
|
2098
|
+
|
|
2099
|
+
2. **任务规模**:
|
|
2100
|
+
- 单一任务 → 直接委派
|
|
2101
|
+
- 多任务 → 拆分后分别委派
|
|
2102
|
+
|
|
2103
|
+
### 步骤 2:任务拆解
|
|
2104
|
+
|
|
2105
|
+
使用 \`task\` 工具委派任务:
|
|
2106
|
+
|
|
2107
|
+
\`\`\`typescript
|
|
2108
|
+
// 示例:委派代码实现任务
|
|
2109
|
+
{
|
|
2110
|
+
subagent_id: "agents/default",
|
|
2111
|
+
task_description: "实现用户认证功能,包括登录、注册、登出三个接口",
|
|
2112
|
+
data_transfer: {
|
|
2113
|
+
requirements: "使用 JWT 认证,密码需要加密存储",
|
|
2114
|
+
constraints: "使用现有的数据库连接池"
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
\`\`\`
|
|
2118
|
+
|
|
2119
|
+
### 步骤 3:结果汇总
|
|
2120
|
+
|
|
2121
|
+
子 agent 完成后:
|
|
2122
|
+
1. 检查执行结果
|
|
2123
|
+
2. 如果有多个子任务,协调依赖关系
|
|
2124
|
+
3. 向用户汇报整体进度和结果
|
|
2125
|
+
|
|
2126
|
+
## 委派策略
|
|
2127
|
+
|
|
2128
|
+
### 简单任务
|
|
2129
|
+
|
|
2130
|
+
用户请求单一功能时,直接委派:
|
|
2131
|
+
|
|
2132
|
+
> 用户:添加一个日志工具函数
|
|
2133
|
+
|
|
2134
|
+
→ 委派给 \`agents/default\`,任务描述清晰完整
|
|
2135
|
+
|
|
2136
|
+
### 复杂任务
|
|
2137
|
+
|
|
2138
|
+
用户请求多功能时,拆分后委派:
|
|
2139
|
+
|
|
2140
|
+
> 用户:重构用户模块并添加测试
|
|
2141
|
+
|
|
2142
|
+
→ 拆分为:
|
|
2143
|
+
1. 委派 \`agents/default\`:重构用户模块代码
|
|
2144
|
+
2. 等第一步完成后,委派 \`agents/default\`:为用户模块编写测试
|
|
2145
|
+
|
|
2146
|
+
### 规划任务
|
|
2147
|
+
|
|
2148
|
+
用户需要方案设计时:
|
|
2149
|
+
|
|
2150
|
+
> 用户:设计一个新的权限系统
|
|
2151
|
+
|
|
2152
|
+
→ 委派 \`agents/manager\` 进行任务规划,然后按规划执行
|
|
2153
|
+
|
|
2154
|
+
## 输出格式
|
|
2155
|
+
|
|
2156
|
+
### 委派时
|
|
2157
|
+
|
|
2158
|
+
\`\`\`markdown
|
|
2159
|
+
## 任务分析
|
|
2160
|
+
|
|
2161
|
+
**用户需求**:{用户原始请求}
|
|
2162
|
+
|
|
2163
|
+
**任务拆解**:
|
|
2164
|
+
1. 任务 A → 委派给 agents/default
|
|
2165
|
+
2. 任务 B → 委派给 agents/manager
|
|
2166
|
+
|
|
2167
|
+
**开始执行**...
|
|
2168
|
+
\`\`\`
|
|
2169
|
+
|
|
2170
|
+
### 汇报时
|
|
2171
|
+
|
|
2172
|
+
\`\`\`markdown
|
|
2173
|
+
## 执行结果
|
|
2174
|
+
|
|
2175
|
+
**已完成**:
|
|
2176
|
+
- ✅ 任务 A:{简要结果}
|
|
2177
|
+
- ✅ 任务 B:{简要结果}
|
|
2178
|
+
|
|
2179
|
+
**总结**:{整体结果摘要}
|
|
2180
|
+
\`\`\`
|
|
2181
|
+
|
|
2182
|
+
## 重要约束
|
|
2183
|
+
|
|
2184
|
+
1. **立即委派**:收到任务后,不要犹豫,立即分析并委派
|
|
2185
|
+
2. **清晰描述**:给子 agent 的任务描述要完整、清晰
|
|
2186
|
+
3. **传递上下文**:使用 \`data_transfer\` 传递必要的背景信息
|
|
2187
|
+
4. **不要插手**:相信子 agent 的能力,不要自己动手做具体工作
|
|
2188
|
+
5. **保持简洁**:你的输出应该简短,重点是协调和汇总
|
|
2189
|
+
|
|
2190
|
+
---
|
|
2191
|
+
|
|
2192
|
+
**记住**:你是协调者,不是执行者。快速分析需求,立即委派任务,高效汇总结果。`;
|
|
2193
|
+
async function jt() {
|
|
2194
|
+
const s = new _e(), e = new ke(s);
|
|
2195
|
+
return await e.addModel({
|
|
2196
|
+
id: "glm-4.7",
|
|
2197
|
+
model_name: "glm-4.7",
|
|
2198
|
+
model_provider: process.env.MODEL_PROVIDER || "openai",
|
|
2199
|
+
stream_usage: !0,
|
|
2200
|
+
enable_thinking: !0,
|
|
2201
|
+
temperature: 0.7,
|
|
2202
|
+
max_tokens: 4096,
|
|
2203
|
+
top_p: 1,
|
|
2204
|
+
frequency_penalty: 0,
|
|
2205
|
+
presence_penalty: 0
|
|
2206
|
+
}), await e.addPrompt({
|
|
2207
|
+
id: "prompts/default",
|
|
2208
|
+
name: "default",
|
|
2209
|
+
content: Ot
|
|
2210
|
+
}), await e.addPrompt({
|
|
2211
|
+
id: "prompts/manager",
|
|
2212
|
+
name: "manager",
|
|
2213
|
+
content: zt
|
|
2214
|
+
}), await Rt(e), await It(e), await e.addAgent({
|
|
2215
|
+
id: "agents/default",
|
|
2216
|
+
name: "Jarvis",
|
|
2217
|
+
description: "代码实现助手",
|
|
2218
|
+
system_prompt: "prompts/default",
|
|
2219
|
+
model: "glm-4.7",
|
|
2220
|
+
tools: {
|
|
2221
|
+
read_file: !0,
|
|
2222
|
+
write_file: !0,
|
|
2223
|
+
edit_file: !0,
|
|
2224
|
+
glob_files: !0,
|
|
2225
|
+
"search-files-rg": !0,
|
|
2226
|
+
folder_operations: !0,
|
|
2227
|
+
terminal: !0,
|
|
2228
|
+
ask_user_questions: !0,
|
|
2229
|
+
TodoWrite: !0
|
|
2230
|
+
},
|
|
2231
|
+
middleware: {
|
|
2232
|
+
agents_md: !0,
|
|
2233
|
+
skills: !0,
|
|
2234
|
+
memories: !0,
|
|
2235
|
+
subagents: !0
|
|
2236
|
+
}
|
|
2237
|
+
}), await e.addAgent({
|
|
2238
|
+
id: "agents/manager",
|
|
2239
|
+
name: "Manager",
|
|
2240
|
+
description: "任务管理员",
|
|
2241
|
+
system_prompt: "prompts/manager",
|
|
2242
|
+
model: "glm-4.7",
|
|
2243
|
+
tools: {
|
|
2244
|
+
read_file: !0,
|
|
2245
|
+
write_file: !0,
|
|
2246
|
+
edit_file: !0,
|
|
2247
|
+
glob_files: !0,
|
|
2248
|
+
"search-files-rg": !0,
|
|
2249
|
+
folder_operations: !0,
|
|
2250
|
+
terminal: !0,
|
|
2251
|
+
ask_user_questions: !0,
|
|
2252
|
+
TodoWrite: !0
|
|
2253
|
+
},
|
|
2254
|
+
middleware: {
|
|
2255
|
+
agents_md: !0,
|
|
2256
|
+
skills: !0,
|
|
2257
|
+
memories: !0,
|
|
2258
|
+
subagents: !0
|
|
2259
|
+
}
|
|
2260
|
+
}), e;
|
|
2261
|
+
}
|
|
2262
|
+
const Y = async () => {
|
|
2263
|
+
const s = new K();
|
|
2264
|
+
return await s.initialize(), s.getConfig();
|
|
2265
|
+
};
|
|
2266
|
+
class N {
|
|
2267
|
+
static instance;
|
|
2268
|
+
client = null;
|
|
2269
|
+
config = null;
|
|
2270
|
+
lastRefresh = null;
|
|
2271
|
+
serverStatuses = /* @__PURE__ */ new Map();
|
|
2272
|
+
constructor() {
|
|
2273
|
+
}
|
|
2274
|
+
static getInstance() {
|
|
2275
|
+
return this.instance || (this.instance = new N()), this.instance;
|
|
2276
|
+
}
|
|
2277
|
+
/**
|
|
2278
|
+
* 初始化 MultiServerMCPClient
|
|
2279
|
+
*/
|
|
2280
|
+
async initialize() {
|
|
2281
|
+
const e = await Y();
|
|
2282
|
+
if (!e.mcp_config || Object.keys(e.mcp_config).length === 0) {
|
|
2283
|
+
this.client = null, this.serverStatuses.clear();
|
|
2284
|
+
return;
|
|
2285
|
+
}
|
|
2286
|
+
this.client = new Re({
|
|
2287
|
+
throwOnLoadError: !0,
|
|
2288
|
+
prefixToolNameWithServerName: !1,
|
|
2289
|
+
additionalToolNamePrefix: "",
|
|
2290
|
+
useStandardContentBlocks: !0,
|
|
2291
|
+
onConnectionError: "ignore",
|
|
2292
|
+
/** @ts-ignore */
|
|
2293
|
+
mcpServers: e.mcp_config
|
|
2294
|
+
}), await this.refreshAll();
|
|
2295
|
+
}
|
|
2296
|
+
cacheTools = [];
|
|
2297
|
+
/**
|
|
2298
|
+
* 获取所有 MCP 工具(带缓存)
|
|
2299
|
+
*/
|
|
2300
|
+
async getAllTools() {
|
|
2301
|
+
if (this.client || await this.initialize(), !this.client)
|
|
2302
|
+
return [];
|
|
2303
|
+
const e = await this.client.getTools();
|
|
2304
|
+
return this.cacheTools = e, e;
|
|
2305
|
+
}
|
|
2306
|
+
/**
|
|
2307
|
+
* 刷新所有服务器
|
|
2308
|
+
* 重新创建 MultiServerMCPClient 实例
|
|
2309
|
+
*/
|
|
2310
|
+
async refreshAll() {
|
|
2311
|
+
if (this.config) {
|
|
2312
|
+
if (this.client)
|
|
2313
|
+
try {
|
|
2314
|
+
await this.client.close();
|
|
2315
|
+
} catch (e) {
|
|
2316
|
+
console.warn("Failed to close MCP client:", e);
|
|
2317
|
+
}
|
|
2318
|
+
await this.initialize(), this.lastRefresh = Date.now();
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
/**
|
|
2322
|
+
* 清理连接
|
|
2323
|
+
*/
|
|
2324
|
+
async cleanup() {
|
|
2325
|
+
if (this.client) {
|
|
2326
|
+
try {
|
|
2327
|
+
await this.client.close();
|
|
2328
|
+
} catch (e) {
|
|
2329
|
+
console.warn("Failed to close MCP client during cleanup:", e);
|
|
2330
|
+
}
|
|
2331
|
+
this.client = null;
|
|
2332
|
+
}
|
|
2333
|
+
this.lastRefresh = null, this.serverStatuses.clear();
|
|
2334
|
+
}
|
|
2335
|
+
/**
|
|
2336
|
+
* 获取 MCP 状态信息
|
|
2337
|
+
*/
|
|
2338
|
+
async getStatus() {
|
|
2339
|
+
const e = this.cacheTools, i = await Y(), n = i.mcp_config ? Object.keys(i.mcp_config) : [];
|
|
2340
|
+
return {
|
|
2341
|
+
isInitialized: this.client !== null,
|
|
2342
|
+
toolCount: e.length,
|
|
2343
|
+
lastRefresh: this.lastRefresh,
|
|
2344
|
+
servers: n
|
|
2345
|
+
};
|
|
2346
|
+
}
|
|
2347
|
+
/**
|
|
2348
|
+
* 执行单个 MCP 工具
|
|
2349
|
+
*/
|
|
2350
|
+
async executeTool(e, i) {
|
|
2351
|
+
if (this.client || await this.initialize(), !this.client)
|
|
2352
|
+
throw new Error("MCP client not initialized. No MCP configuration found.");
|
|
2353
|
+
const n = await this.getAllTools(), o = n.find((a) => a.name === e);
|
|
2354
|
+
if (!o) {
|
|
2355
|
+
const a = n.map((r) => r.name).join(", ");
|
|
2356
|
+
throw new Error(`Tool not found: ${e}. Available: ${a || "none"}`);
|
|
2357
|
+
}
|
|
2358
|
+
try {
|
|
2359
|
+
return await o.invoke(i);
|
|
2360
|
+
} catch (a) {
|
|
2361
|
+
throw new Error(`Failed to execute MCP tool '${e}': ${a.message || String(a)}`);
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
const Nt = t.object({}), Ut = t.object({
|
|
2366
|
+
commands: t.array(
|
|
2367
|
+
t.object({
|
|
2368
|
+
name: t.string().describe("MCP 工具名称"),
|
|
2369
|
+
args: t.record(t.string(), t.any()).describe("工具参数,JSON 对象格式")
|
|
2370
|
+
})
|
|
2371
|
+
).describe("要执行的 MCP 工具列表")
|
|
2372
|
+
});
|
|
2373
|
+
class Lt {
|
|
2374
|
+
name = "CommandSystemMiddleware";
|
|
2375
|
+
stateSchema = void 0;
|
|
2376
|
+
contextSchema = void 0;
|
|
2377
|
+
mcpManager;
|
|
2378
|
+
loadMcpToolsTool;
|
|
2379
|
+
executeMcpToolTool;
|
|
2380
|
+
constructor() {
|
|
2381
|
+
this.mcpManager = N.getInstance(), this.loadMcpToolsTool = p(
|
|
2382
|
+
async () => {
|
|
2383
|
+
const e = await this.mcpManager.getStatus(), i = await this.mcpManager.getAllTools();
|
|
2384
|
+
return JSON.stringify(
|
|
2385
|
+
{
|
|
2386
|
+
tools: i.map((n) => ({
|
|
2387
|
+
name: n.name,
|
|
2388
|
+
description: n.description,
|
|
2389
|
+
schema: n.schema
|
|
2390
|
+
})),
|
|
2391
|
+
status: e
|
|
2392
|
+
},
|
|
2393
|
+
null,
|
|
2394
|
+
2
|
|
2395
|
+
);
|
|
2396
|
+
},
|
|
2397
|
+
{
|
|
2398
|
+
name: "load_mcp_tools",
|
|
2399
|
+
description: `加载并查询所有可用的 MCP 工具列表。
|
|
2400
|
+
|
|
2401
|
+
返回:
|
|
2402
|
+
- tools: MCP 工具列表,每个工具包含 name, description, schema
|
|
2403
|
+
- status: MCP 连接状态,包含 toolCount, servers 等
|
|
2404
|
+
|
|
2405
|
+
使用场景:
|
|
2406
|
+
- 查询当前有哪些 MCP 工具可用
|
|
2407
|
+
- 获取工具的参数格式
|
|
2408
|
+
- 检查 MCP 连接状态
|
|
2409
|
+
|
|
2410
|
+
重要:工具列表是动态的,建议在需要时调用此命令获取最新信息。`,
|
|
2411
|
+
schema: Nt
|
|
2412
|
+
}
|
|
2413
|
+
), this.executeMcpToolTool = p(
|
|
2414
|
+
async ({ commands: e }) => {
|
|
2415
|
+
const i = [];
|
|
2416
|
+
for (const n of e) {
|
|
2417
|
+
const { name: o, args: a } = n;
|
|
2418
|
+
try {
|
|
2419
|
+
const r = await this.mcpManager.executeTool(o, a);
|
|
2420
|
+
i.push({ tool: o, result: r });
|
|
2421
|
+
} catch (r) {
|
|
2422
|
+
i.push({
|
|
2423
|
+
tool: o,
|
|
2424
|
+
result: null,
|
|
2425
|
+
error: r.message || String(r)
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
return JSON.stringify(
|
|
2430
|
+
{
|
|
2431
|
+
results: i
|
|
2432
|
+
},
|
|
2433
|
+
null,
|
|
2434
|
+
2
|
|
2435
|
+
);
|
|
2436
|
+
},
|
|
2437
|
+
{
|
|
2438
|
+
name: "execute_mcp_tool",
|
|
2439
|
+
description: `执行一个或多个 MCP 工具。
|
|
2440
|
+
|
|
2441
|
+
使用格式:
|
|
2442
|
+
- commands: MCP 工具数组,每个工具包含 name 和 args
|
|
2443
|
+
|
|
2444
|
+
示例:
|
|
2445
|
+
- 执行单个工具: {commands: [{name: "filesystem.read_file", args: {path: "/path/to/file"}}]}
|
|
2446
|
+
- 执行多个工具: {commands: [{name: "tool1", args: {...}}, {name: "tool2", args: {...}}]}
|
|
2447
|
+
|
|
2448
|
+
重要:
|
|
2449
|
+
- 所有工具独立执行,失败不影响其他工具
|
|
2450
|
+
- 返回结果按命令顺序排列
|
|
2451
|
+
- 适合批量执行 MCP 相关操作`,
|
|
2452
|
+
schema: Ut
|
|
2453
|
+
}
|
|
2454
|
+
);
|
|
2455
|
+
}
|
|
2456
|
+
/**
|
|
2457
|
+
* 获取 middleware 提供的 Command
|
|
2458
|
+
*/
|
|
2459
|
+
get tools() {
|
|
2460
|
+
return [this.loadMcpToolsTool, this.executeMcpToolTool];
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2463
|
+
* 包装模型调用,注入系统提示词
|
|
2464
|
+
*/
|
|
2465
|
+
async wrapModelCall(e, i) {
|
|
2466
|
+
const n = `
|
|
2467
|
+
## MCP Tools
|
|
2468
|
+
|
|
2469
|
+
使用 MCP 工具需要两步:
|
|
2470
|
+
|
|
2471
|
+
1. **load_mcp_tools** - 查询可用的 MCP 工具
|
|
2472
|
+
- 返回所有 MCP 工具的列表和参数格式
|
|
2473
|
+
- 包含 MCP 连接状态
|
|
2474
|
+
|
|
2475
|
+
2. **execute_mcp_tool** - 执行 MCP 工具
|
|
2476
|
+
- 支持单个或多个工具批量执行
|
|
2477
|
+
- 格式:{commands: [{name, args}, ...]}
|
|
2478
|
+
|
|
2479
|
+
**重要**:
|
|
2480
|
+
- 标准工具(read_file, glob_files)直接调用,不需要通过 MCP 命令
|
|
2481
|
+
- MCP 工具需要先调用 load_mcp_tools 查询
|
|
2482
|
+
- 再调用 execute_mcp_tool 执行
|
|
2483
|
+
`;
|
|
2484
|
+
let o;
|
|
2485
|
+
e.systemPrompt ? o = e.systemPrompt + n : o = n;
|
|
2486
|
+
const a = {
|
|
2487
|
+
...e,
|
|
2488
|
+
systemPrompt: o
|
|
2489
|
+
};
|
|
2490
|
+
return await i(a);
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
const Dt = {
|
|
2494
|
+
ask_user_questions: {
|
|
2495
|
+
allowedDecisions: ["respond", "approve", "reject", "edit"]
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
async function Ft(s, e, i, n, o) {
|
|
2499
|
+
const a = !!o?.parent_id, r = await e.getAgent(s);
|
|
2500
|
+
if (!r)
|
|
2501
|
+
throw new Error(`Agent not found: ${s}`);
|
|
2502
|
+
const c = await e.validateAgent(s);
|
|
2503
|
+
if (!c.valid)
|
|
2504
|
+
throw new Error(`Agent validation failed: ${JSON.stringify(c.errors)}`);
|
|
2505
|
+
const l = await Z(i.model_id, {
|
|
2506
|
+
modelProvider: i.provider_id,
|
|
2507
|
+
enableThinking: i.enable_thinking,
|
|
2508
|
+
metadata: {
|
|
2509
|
+
// message 通过这个 id 判断是否为子调用
|
|
2510
|
+
parent_id: o?.parent_id
|
|
2511
|
+
}
|
|
2512
|
+
}), m = [], h = e.tools;
|
|
2513
|
+
for (const [T, C] of Object.entries(r.tools)) {
|
|
2514
|
+
const f = h.getImplementation(T);
|
|
2515
|
+
if (!f) {
|
|
2516
|
+
console.warn(`Tool ${T} not found in registry`);
|
|
2517
|
+
continue;
|
|
2518
|
+
}
|
|
2519
|
+
if (!f.name || !C)
|
|
2520
|
+
continue;
|
|
2521
|
+
const te = $(
|
|
2522
|
+
async (ie) => {
|
|
2523
|
+
const S = await f.execute(ie);
|
|
2524
|
+
return S && typeof S == "object" && "content" in S ? S.content : S;
|
|
2525
|
+
},
|
|
2526
|
+
{
|
|
2527
|
+
name: f.name,
|
|
2528
|
+
description: f.description,
|
|
2529
|
+
schema: f.paramsSchema
|
|
2530
|
+
}
|
|
2531
|
+
);
|
|
2532
|
+
m.push(te);
|
|
2533
|
+
}
|
|
2534
|
+
const u = [];
|
|
2535
|
+
for (const [T, C] of Object.entries(r.middleware)) {
|
|
2536
|
+
if (T === "subagents" && a) continue;
|
|
2537
|
+
const f = e.middlewares.getImplementation(T);
|
|
2538
|
+
if (!C)
|
|
2539
|
+
break;
|
|
2540
|
+
u.push(await f.execute(C.customParams || {}));
|
|
2541
|
+
}
|
|
2542
|
+
const y = new Lt();
|
|
2543
|
+
u.push(y);
|
|
2544
|
+
const A = {
|
|
2545
|
+
...Dt
|
|
2546
|
+
};
|
|
2547
|
+
process.env.YOLO_MODE !== "true" && Object.assign(A, {
|
|
2548
|
+
terminal: { allowedDecisions: ["approve", "reject", "edit"] }
|
|
2549
|
+
}), u.push(
|
|
2550
|
+
Ie({
|
|
2551
|
+
/** @ts-ignore */
|
|
2552
|
+
interruptOn: A
|
|
2553
|
+
})
|
|
2554
|
+
), process.env.MODEL_PROVIDER === "anthropic" && u.push(ve());
|
|
2555
|
+
const v = await e.getPrompt(r.systemPromptId);
|
|
2556
|
+
if (!v)
|
|
2557
|
+
throw new Error(`Prompt not found: ${r.systemPromptId}`);
|
|
2558
|
+
const ee = v.content + `
|
|
2559
|
+
|
|
2560
|
+
${await $t()}`;
|
|
2561
|
+
return B({
|
|
2562
|
+
name: a ? `subagent_${o.parent_id}` : r.name,
|
|
2563
|
+
model: l,
|
|
2564
|
+
systemPrompt: ee,
|
|
2565
|
+
tools: m,
|
|
2566
|
+
/** @ts-ignore */
|
|
2567
|
+
stateSchema: J,
|
|
2568
|
+
middleware: u
|
|
2569
|
+
});
|
|
2570
|
+
}
|
|
2571
|
+
async function Wt(s) {
|
|
2572
|
+
return (await s.listAgents()).map((i) => i.id);
|
|
2573
|
+
}
|
|
2574
|
+
const Yt = {
|
|
2575
|
+
smart_memory: async (s) => {
|
|
2576
|
+
const e = await Z(s.model_id, {
|
|
2577
|
+
modelProvider: s.provider_type,
|
|
2578
|
+
enableThinking: s.enable_thinking ?? !0
|
|
2579
|
+
}), i = await Qe(e, Ve(s.messages));
|
|
2580
|
+
return {
|
|
2581
|
+
switch_command: "",
|
|
2582
|
+
messages: [new me({ id: pe }), new he(i)]
|
|
2583
|
+
};
|
|
2584
|
+
}
|
|
2585
|
+
};
|
|
2586
|
+
async function qt(s, e, i, n) {
|
|
2587
|
+
const o = await Ft(s, e, i);
|
|
2588
|
+
i.thread_id = ce(n);
|
|
2589
|
+
const a = await o.invoke(i, {
|
|
2590
|
+
recursionLimit: 500,
|
|
2591
|
+
configurable: n.configurable,
|
|
2592
|
+
context: n.context
|
|
2593
|
+
});
|
|
2594
|
+
return {
|
|
2595
|
+
switch_command: "",
|
|
2596
|
+
task_store: a.task_store,
|
|
2597
|
+
messages: a.messages
|
|
2598
|
+
};
|
|
2599
|
+
}
|
|
2600
|
+
function Gt() {
|
|
2601
|
+
return new de(J).addNode("graph", async (s, e) => {
|
|
2602
|
+
const { switch_command: i } = s;
|
|
2603
|
+
if (i === "smart_memory") return Yt.smart_memory(s);
|
|
2604
|
+
const n = await jt(), o = await Wt(n), a = i ? `agents/${i}` : "agents/default";
|
|
2605
|
+
if (!o.includes(a))
|
|
2606
|
+
throw new Error(
|
|
2607
|
+
`Unknown agent: ${i || "default"}. Available: ${o.map((c) => c.split("/").pop()).join(", ")}`
|
|
2608
|
+
);
|
|
2609
|
+
return await qt(a, n, s, e);
|
|
2610
|
+
}).addEdge(ue, "graph").compile();
|
|
2611
|
+
}
|
|
2612
|
+
const vi = Gt();
|
|
2613
|
+
export {
|
|
2614
|
+
I as A,
|
|
2615
|
+
Oe as C,
|
|
2616
|
+
K as F,
|
|
2617
|
+
N as M,
|
|
2618
|
+
Ue as S,
|
|
2619
|
+
H as T,
|
|
2620
|
+
Le as a,
|
|
2621
|
+
De as b,
|
|
2622
|
+
$e as c,
|
|
2623
|
+
Fe as d,
|
|
2624
|
+
We as e,
|
|
2625
|
+
Ye as f,
|
|
2626
|
+
V as g,
|
|
2627
|
+
qe as h,
|
|
2628
|
+
Ge as i,
|
|
2629
|
+
Be as j,
|
|
2630
|
+
vi as k,
|
|
2631
|
+
_i as l,
|
|
2632
|
+
Ft as m,
|
|
2633
|
+
z as n,
|
|
2634
|
+
ki as o,
|
|
2635
|
+
kt as p,
|
|
2636
|
+
at as q,
|
|
2637
|
+
yt as r,
|
|
2638
|
+
ot as s,
|
|
2639
|
+
St as t,
|
|
2640
|
+
bi as u
|
|
2641
|
+
};
|