page-action-cache 1.0.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.
Files changed (73) hide show
  1. package/dist/actions-executor.d.ts +62 -0
  2. package/dist/actions-executor.d.ts.map +1 -0
  3. package/dist/actions-executor.js +339 -0
  4. package/dist/actions-executor.js.map +1 -0
  5. package/dist/cache-invalidator.d.ts +70 -0
  6. package/dist/cache-invalidator.d.ts.map +1 -0
  7. package/dist/cache-invalidator.js +212 -0
  8. package/dist/cache-invalidator.js.map +1 -0
  9. package/dist/cache-store.d.ts +80 -0
  10. package/dist/cache-store.d.ts.map +1 -0
  11. package/dist/cache-store.js +361 -0
  12. package/dist/cache-store.js.map +1 -0
  13. package/dist/cache-strategy.d.ts +65 -0
  14. package/dist/cache-strategy.d.ts.map +1 -0
  15. package/dist/cache-strategy.js +237 -0
  16. package/dist/cache-strategy.js.map +1 -0
  17. package/dist/hooks-entry.d.ts +18 -0
  18. package/dist/hooks-entry.d.ts.map +1 -0
  19. package/dist/hooks-entry.js +27 -0
  20. package/dist/hooks-entry.js.map +1 -0
  21. package/dist/hooks.d.ts +10 -0
  22. package/dist/hooks.d.ts.map +1 -0
  23. package/dist/hooks.js +277 -0
  24. package/dist/hooks.js.map +1 -0
  25. package/dist/index.d.ts +24 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +34 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/scenario-recognizer.d.ts +45 -0
  30. package/dist/scenario-recognizer.d.ts.map +1 -0
  31. package/dist/scenario-recognizer.js +213 -0
  32. package/dist/scenario-recognizer.js.map +1 -0
  33. package/dist/security-policy.d.ts +62 -0
  34. package/dist/security-policy.d.ts.map +1 -0
  35. package/dist/security-policy.js +219 -0
  36. package/dist/security-policy.js.map +1 -0
  37. package/dist/tools.d.ts +209 -0
  38. package/dist/tools.d.ts.map +1 -0
  39. package/dist/tools.js +383 -0
  40. package/dist/tools.js.map +1 -0
  41. package/dist/types.d.ts +336 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +8 -0
  44. package/dist/types.js.map +1 -0
  45. package/dist/ux-enhancer.d.ts +60 -0
  46. package/dist/ux-enhancer.d.ts.map +1 -0
  47. package/dist/ux-enhancer.js +218 -0
  48. package/dist/ux-enhancer.js.map +1 -0
  49. package/dist/variable-resolver.d.ts +28 -0
  50. package/dist/variable-resolver.d.ts.map +1 -0
  51. package/dist/variable-resolver.js +201 -0
  52. package/dist/variable-resolver.js.map +1 -0
  53. package/docs/API.md +555 -0
  54. package/docs/IMPLEMENTATION.md +1792 -0
  55. package/docs/INTEGRATION.md +387 -0
  56. package/docs/README.md +183 -0
  57. package/index.ts +118 -0
  58. package/openclaw.plugin.json +208 -0
  59. package/package.json +76 -0
  60. package/skills/page-action-cache/SKILL.md +216 -0
  61. package/src/actions-executor.ts +441 -0
  62. package/src/cache-invalidator.ts +271 -0
  63. package/src/cache-store.ts +457 -0
  64. package/src/cache-strategy.ts +327 -0
  65. package/src/hooks-entry.ts +114 -0
  66. package/src/hooks.ts +332 -0
  67. package/src/index.ts +104 -0
  68. package/src/scenario-recognizer.ts +259 -0
  69. package/src/security-policy.ts +268 -0
  70. package/src/tools.ts +437 -0
  71. package/src/types.ts +482 -0
  72. package/src/ux-enhancer.ts +266 -0
  73. package/src/variable-resolver.ts +258 -0
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Security Policy
3
+ * 安全策略 - 敏感变量检测、加密存储、访问控制
4
+ */
5
+
6
+ import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
7
+ import type { AtomicAction, PageActionCacheEntry, VariableMap } from "./types.js";
8
+
9
+ // ============================================================================
10
+ // 配置
11
+ // ============================================================================
12
+
13
+ const SENSITIVE_FIELDS = new Set([
14
+ "password",
15
+ "pwd",
16
+ "token",
17
+ "secret",
18
+ "key",
19
+ "code",
20
+ "otp",
21
+ ]);
22
+
23
+ const ENCRYPTION_KEY = "default-key-change-in-production"; // 生产环境应从配置读取
24
+ const ENCRYPTION_ALGORITHM = "aes-256-gcm";
25
+
26
+ // ============================================================================
27
+ // Security Policy 类
28
+ // ============================================================================
29
+
30
+ /**
31
+ * 安全策略
32
+ */
33
+ export class SecurityPolicy {
34
+ private allowedUserIds: Set<string>;
35
+
36
+ constructor(allowedUserIds: string[] = []) {
37
+ this.allowedUserIds = new Set(allowedUserIds);
38
+ }
39
+
40
+ // -------------------------------------------------------------------------
41
+ // 敏感字段检测
42
+ // -------------------------------------------------------------------------
43
+
44
+ /**
45
+ * 检查操作是否包含敏感变量
46
+ */
47
+ isSensitiveAction(action: AtomicAction): boolean {
48
+ if (!action.variable) {
49
+ return false;
50
+ }
51
+
52
+ return SENSITIVE_FIELDS.has(action.variable.toLowerCase());
53
+ }
54
+
55
+ /**
56
+ * 检查变量映射是否包含敏感数据
57
+ */
58
+ hasSensitiveData(variables: VariableMap): boolean {
59
+ for (const key of Object.keys(variables)) {
60
+ if (SENSITIVE_FIELDS.has(key.toLowerCase())) {
61
+ return true;
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ * 获取敏感字段列表
69
+ */
70
+ getSensitiveFields(): string[] {
71
+ return Array.from(SENSITIVE_FIELDS);
72
+ }
73
+
74
+ // -------------------------------------------------------------------------
75
+ // 加密/解密
76
+ // -------------------------------------------------------------------------
77
+
78
+ /**
79
+ * 加密数据
80
+ */
81
+ encrypt(data: string): string {
82
+ try {
83
+ const iv = randomBytes(16);
84
+ const cipher = createCipheriv(
85
+ ENCRYPTION_ALGORITHM,
86
+ Buffer.from(ENCRYPTION_KEY),
87
+ iv
88
+ );
89
+
90
+ let encrypted = cipher.update(data, "utf8", "hex");
91
+ encrypted += cipher.final("hex");
92
+ const authTag = cipher.getAuthTag();
93
+
94
+ return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted}`;
95
+ } catch (error) {
96
+ console.error("[SecurityPolicy] Encryption failed:", error);
97
+ return data; // 失败时返回原数据
98
+ }
99
+ }
100
+
101
+ /**
102
+ * 解密数据
103
+ */
104
+ decrypt(encrypted: string): string {
105
+ try {
106
+ const [ivHex, authTagHex, data] = encrypted.split(":");
107
+
108
+ if (!ivHex || !authTagHex || !data) {
109
+ return encrypted; // 格式错误,返回原数据
110
+ }
111
+
112
+ const iv = Buffer.from(ivHex, "hex");
113
+ const authTag = Buffer.from(authTagHex, "hex");
114
+ const decipher = createDecipheriv(
115
+ ENCRYPTION_ALGORITHM,
116
+ Buffer.from(ENCRYPTION_KEY),
117
+ iv
118
+ );
119
+
120
+ decipher.setAuthTag(authTag);
121
+
122
+ let decrypted = decipher.update(data, "hex", "utf8");
123
+ decrypted += decipher.final("utf8");
124
+
125
+ return decrypted;
126
+ } catch (error) {
127
+ console.error("[SecurityPolicy] Decryption failed:", error);
128
+ return encrypted; // 失败时返回原数据
129
+ }
130
+ }
131
+
132
+ /**
133
+ * 加密缓存条目中的敏感变量
134
+ */
135
+ encryptCacheEntry(entry: PageActionCacheEntry): PageActionCacheEntry {
136
+ if (!entry.variables) {
137
+ return entry;
138
+ }
139
+
140
+ const encrypted = { ...entry };
141
+ encrypted.variables = {} as VariableMap;
142
+
143
+ for (const [key, value] of Object.entries(entry.variables)) {
144
+ if (SENSITIVE_FIELDS.has(key.toLowerCase()) && typeof value === "string") {
145
+ // 敏感字段加密
146
+ (encrypted.variables as any)[key] = this.encrypt(value);
147
+ } else {
148
+ (encrypted.variables as any)[key] = value;
149
+ }
150
+ }
151
+
152
+ return encrypted;
153
+ }
154
+
155
+ /**
156
+ * 解密缓存条目中的敏感变量
157
+ */
158
+ decryptCacheEntry(entry: PageActionCacheEntry): PageActionCacheEntry {
159
+ if (!entry.variables) {
160
+ return entry;
161
+ }
162
+
163
+ const decrypted = { ...entry };
164
+ decrypted.variables = {} as VariableMap;
165
+
166
+ for (const [key, value] of Object.entries(entry.variables)) {
167
+ if (SENSITIVE_FIELDS.has(key.toLowerCase()) && typeof value === "string") {
168
+ // 敏感字段解密
169
+ (decrypted.variables as any)[key] = this.decrypt(value);
170
+ } else {
171
+ (decrypted.variables as any)[key] = value;
172
+ }
173
+ }
174
+
175
+ return decrypted;
176
+ }
177
+
178
+ // -------------------------------------------------------------------------
179
+ // 访问控制
180
+ // -------------------------------------------------------------------------
181
+
182
+ /**
183
+ * 检查是否允许访问
184
+ */
185
+ canAccessCache(userId?: string): boolean {
186
+ if (this.allowedUserIds.size === 0) {
187
+ return true; // 没有限制,允许所有用户
188
+ }
189
+
190
+ if (!userId) {
191
+ return false; // 没有用户 ID,拒绝访问
192
+ }
193
+
194
+ return this.allowedUserIds.has(userId);
195
+ }
196
+
197
+ /**
198
+ * 添加允许的用户 ID
199
+ */
200
+ addAllowedUserId(userId: string): void {
201
+ this.allowedUserIds.add(userId);
202
+ }
203
+
204
+ /**
205
+ * 移除允许的用户 ID
206
+ */
207
+ removeAllowedUserId(userId: string): void {
208
+ this.allowedUserIds.delete(userId);
209
+ }
210
+
211
+ // -------------------------------------------------------------------------
212
+ // 日志脱敏
213
+ // -------------------------------------------------------------------------
214
+
215
+ /**
216
+ * 脱敏处理(用于日志输出)
217
+ */
218
+ sanitizeForLogging(data: any): any {
219
+ if (typeof data !== "object" || data === null) {
220
+ return data;
221
+ }
222
+
223
+ const sanitized: any = Array.isArray(data) ? [] : {};
224
+
225
+ for (const [key, value] of Object.entries(data)) {
226
+ if (SENSITIVE_FIELDS.has(key.toLowerCase())) {
227
+ // 敏感字段脱敏
228
+ sanitized[key] = "***REDACTED***";
229
+ } else if (typeof value === "object") {
230
+ // 递归处理嵌套对象
231
+ sanitized[key] = this.sanitizeForLogging(value);
232
+ } else {
233
+ sanitized[key] = value;
234
+ }
235
+ }
236
+
237
+ return sanitized;
238
+ }
239
+
240
+ /**
241
+ * 脱敏处理操作列表
242
+ */
243
+ sanitizeActions(actions: AtomicAction[]): AtomicAction[] {
244
+ return actions.map((action) => {
245
+ const sanitized = { ...action };
246
+
247
+ // 脱敏操作中的敏感文本
248
+ if (sanitized.type === "type" && this.isSensitiveAction(action)) {
249
+ (sanitized as any).text = "***REDACTED***";
250
+ }
251
+
252
+ return sanitized;
253
+ });
254
+ }
255
+ }
256
+
257
+ // ============================================================================
258
+ // 单例
259
+ // ============================================================================
260
+
261
+ let securityPolicyInstance: SecurityPolicy | null = null;
262
+
263
+ export function getSecurityPolicy(allowedUserIds?: string[]): SecurityPolicy {
264
+ if (!securityPolicyInstance) {
265
+ securityPolicyInstance = new SecurityPolicy(allowedUserIds);
266
+ }
267
+ return securityPolicyInstance;
268
+ }
package/src/tools.ts ADDED
@@ -0,0 +1,437 @@
1
+ /**
2
+ * Custom Tools
3
+ * 自定义工具 - 提供给 LLM 使用的工具接口
4
+ */
5
+
6
+ import type {
7
+ VariableMap,
8
+ PageViewport,
9
+ } from "./types.js";
10
+ import { getCacheStore } from "./cache-store.js";
11
+ import { getScenarioRecognizer } from "./scenario-recognizer.js";
12
+ import { getUXEnhancer } from "./ux-enhancer.js";
13
+ import { getActionsExecutor } from "./actions-executor.js";
14
+
15
+ // ============================================================================
16
+ // 工具定义
17
+ // ============================================================================
18
+
19
+ /**
20
+ * execute_cached 工具 - 执行缓存的页面操作序列
21
+ */
22
+ export function createExecuteCachedTool() {
23
+ return {
24
+ name: "execute_cached",
25
+ label: "Execute Cached Actions",
26
+ description:
27
+ "执行缓存的页面操作序列,跳过 LLM 分析。大幅降低 token 消耗和操作延迟。",
28
+ parameters: {
29
+ type: "object",
30
+ properties: {
31
+ cacheKey: {
32
+ type: "string",
33
+ description: "缓存键(从 cache_info 中获取)",
34
+ },
35
+ fromIndex: {
36
+ type: "number",
37
+ description: "从第几个操作开始执行(默认 0)",
38
+ },
39
+ toIndex: {
40
+ type: "number",
41
+ description: "执行到第几个操作(不指定则执行全部)",
42
+ },
43
+ dryRun: {
44
+ type: "boolean",
45
+ description: "试运行模式,不实际执行",
46
+ },
47
+ force: {
48
+ type: "boolean",
49
+ description: "强制执行(忽略页面变化检测)",
50
+ },
51
+ },
52
+ },
53
+ required: ["cacheKey"],
54
+ };
55
+ }
56
+
57
+ /**
58
+ * execute_cached 工具执行函数
59
+ */
60
+ export async function executeCached(_toolCallId: string, args: any) {
61
+ const {
62
+ cacheKey,
63
+ fromIndex,
64
+ toIndex,
65
+ dryRun = false,
66
+ force = false,
67
+ } = args;
68
+
69
+ const cacheStore = getCacheStore();
70
+ const uxEnhancer = getUXEnhancer();
71
+
72
+ // 获取缓存条目
73
+ const entry = cacheStore.listEntries().find((e) => e.key === cacheKey);
74
+
75
+ if (!entry) {
76
+ return {
77
+ content: [
78
+ {
79
+ type: "text",
80
+ text: "缓存不存在或已过期。请重新分析页面。",
81
+ },
82
+ ],
83
+ };
84
+ }
85
+
86
+ // 检查页面变化(强制模式跳过)
87
+ if (!force && !dryRun) {
88
+ // TODO: 实际获取页面 HTML 进行检测
89
+ // const html = await fetchPageHTML(entry.url, entry.viewport);
90
+ // const changeResult = await cacheInvalidator.detectPageChange(html, entry.url, entry.viewport, entry);
91
+
92
+ // 简化处理:暂时跳过检测
93
+ console.log(`[execute_cached] Skipping page change detection for ${entry.url}`);
94
+ }
95
+
96
+ // 解析变量
97
+ let variables: VariableMap = {};
98
+ if (entry.variables) {
99
+ variables = entry.variables;
100
+ }
101
+
102
+ // 获取执行器
103
+ const executor = getActionsExecutor();
104
+
105
+ if (dryRun) {
106
+ // 试运行模式,只返回不执行
107
+ const actionsToExecute = entry.actions.slice(
108
+ fromIndex || 0,
109
+ toIndex !== undefined ? toIndex + 1 : undefined
110
+ );
111
+
112
+ return {
113
+ content: [
114
+ {
115
+ type: "text",
116
+ text: uxEnhancer.generateDryRunResult(actionsToExecute),
117
+ },
118
+ ],
119
+ };
120
+ }
121
+
122
+ // 逐个执行操作
123
+ const results = await executor.executeBatch(entry.actions, variables, {
124
+ fromIndex,
125
+ toIndex,
126
+ atomic: true, // 原子执行
127
+ });
128
+
129
+ // 更新缓存统计
130
+ cacheStore.updateExecutionStats(cacheKey, results);
131
+
132
+ return {
133
+ content: [
134
+ {
135
+ type: "text",
136
+ text: uxEnhancer.generateExecutionReport(results, force),
137
+ },
138
+ ],
139
+ };
140
+ }
141
+
142
+ /**
143
+ * cache_stats 工具 - 查看缓存统计
144
+ */
145
+ export function createCacheStatsTool() {
146
+ return {
147
+ name: "cache_stats",
148
+ label: "Cache Statistics",
149
+ description: "查看页面操作缓存的统计信息,包括命中率、节省的 token 等。",
150
+ parameters: {
151
+ type: "object",
152
+ properties: {},
153
+ },
154
+ };
155
+ }
156
+
157
+ /**
158
+ * cache_stats 工具执行函数
159
+ */
160
+ export async function cacheStats(_toolCallId: string, _args: any) {
161
+ const uxEnhancer = getUXEnhancer();
162
+
163
+ return {
164
+ content: [
165
+ {
166
+ type: "text",
167
+ text: uxEnhancer.generateStatsReport(),
168
+ },
169
+ ],
170
+ };
171
+ }
172
+
173
+ /**
174
+ * cache_list 工具 - 列出所有缓存
175
+ */
176
+ export function createCacheListTool() {
177
+ return {
178
+ name: "cache_list",
179
+ label: "List Cache Entries",
180
+ description: "列出所有页面操作缓存条目,包括场景、URL、访问次数等。",
181
+ parameters: {
182
+ type: "object",
183
+ properties: {
184
+ limit: {
185
+ type: "number",
186
+ description: "最多返回的条目数(默认 20)",
187
+ },
188
+ filterScenario: {
189
+ type: "string",
190
+ description: "按场景过滤(如 login, checkout)",
191
+ },
192
+ },
193
+ },
194
+ };
195
+ }
196
+
197
+ /**
198
+ * cache_list 工具执行函数
199
+ */
200
+ export async function cacheList(_toolCallId: string, args: any) {
201
+ const { limit = 20, filterScenario } = args;
202
+ const cacheStore = getCacheStore();
203
+
204
+ let entries = cacheStore.listEntries();
205
+
206
+ // 过滤场景
207
+ if (filterScenario) {
208
+ entries = entries.filter((e) => e.scenario === filterScenario);
209
+ }
210
+
211
+ // 限制数量
212
+ entries = entries.slice(0, limit);
213
+
214
+ let text = `\n【缓存条目列表】(共 ${entries.length} 条)\n\n`;
215
+
216
+ entries.forEach((entry, i) => {
217
+ text += `${i + 1}. ${entry.scenario} (${entry.cacheLevel})\n`;
218
+ text += ` URL: ${entry.url}\n`;
219
+ text += ` 访问次数: ${entry.accessCount}\n`;
220
+ text += ` 成功率: ${((entry.successCount / (entry.successCount + entry.failCount || 1)) * 100).toFixed(0)}%\n`;
221
+ text += ` 最后访问: ${new Date(entry.lastAccessTime).toLocaleString()}\n\n`;
222
+ });
223
+
224
+ return {
225
+ content: [
226
+ {
227
+ type: "text",
228
+ text,
229
+ },
230
+ ],
231
+ };
232
+ }
233
+
234
+ /**
235
+ * cache_clear 工具 - 清空缓存
236
+ */
237
+ export function createCacheClearTool() {
238
+ return {
239
+ name: "cache_clear",
240
+ label: "Clear Cache",
241
+ description: "清空所有页面操作缓存。慎用!",
242
+ parameters: {
243
+ type: "object",
244
+ properties: {
245
+ scenario: {
246
+ type: "string",
247
+ description: "只清空指定场景的缓存(可选)",
248
+ },
249
+ },
250
+ },
251
+ };
252
+ }
253
+
254
+ /**
255
+ * cache_clear 工具执行函数
256
+ */
257
+ export async function cacheClear(_toolCallId: string, args: any) {
258
+ const { scenario } = args;
259
+ const cacheStore = getCacheStore();
260
+
261
+ if (scenario) {
262
+ // 清空指定场景
263
+ let count = 0;
264
+ const entries = cacheStore.listEntries();
265
+ for (const entry of entries) {
266
+ if (entry.scenario === scenario) {
267
+ cacheStore.delete(entry.url, entry.viewport);
268
+ count++;
269
+ }
270
+ }
271
+ return {
272
+ content: [
273
+ {
274
+ type: "text",
275
+ text: `已清空场景 "${scenario}" 的 ${count} 条缓存。`,
276
+ },
277
+ ],
278
+ };
279
+ } else {
280
+ // 清空所有缓存
281
+ cacheStore.clear();
282
+ return {
283
+ content: [
284
+ {
285
+ type: "text",
286
+ text: "已清空所有缓存。",
287
+ },
288
+ ],
289
+ };
290
+ }
291
+ }
292
+
293
+ /**
294
+ * scenario_list 工具 - 列出所有场景
295
+ */
296
+ export function createScenarioListTool() {
297
+ return {
298
+ name: "scenario_list",
299
+ label: "List Scenarios",
300
+ description: "列出所有支持的缓存场景及其匹配规则。",
301
+ parameters: {
302
+ type: "object",
303
+ properties: {},
304
+ },
305
+ };
306
+ }
307
+
308
+ /**
309
+ * scenario_list 工具执行函数
310
+ */
311
+ export async function scenarioList(_toolCallId: string, _args: any) {
312
+ const scenarioRecognizer = getScenarioRecognizer();
313
+ const rules = scenarioRecognizer.getRules();
314
+
315
+ let text = "\n【支持的缓存场景】\n\n";
316
+
317
+ rules.forEach((rule, i) => {
318
+ text += `${i + 1}. ${rule.scenario}\n`;
319
+ text += ` 关键词: ${rule.keywords.join(", ")}\n`;
320
+ text += ` URL 模式: ${rule.urlPatterns.join(", ") || "无"}\n`;
321
+ text += ` 缓存层级: ${rule.cacheLevel}\n`;
322
+ text += ` 置信度: ${rule.confidence}\n\n`;
323
+ });
324
+
325
+ return {
326
+ content: [
327
+ {
328
+ type: "text",
329
+ text,
330
+ },
331
+ ],
332
+ };
333
+ }
334
+
335
+ /**
336
+ * force_refresh 工具 - 强制刷新指定缓存
337
+ */
338
+ export function createForceRefreshTool() {
339
+ return {
340
+ name: "force_refresh",
341
+ label: "Force Refresh Cache",
342
+ description: "强制刷新指定页面的缓存,下次访问将重新分析。",
343
+ parameters: {
344
+ type: "object",
345
+ properties: {
346
+ url: {
347
+ type: "string",
348
+ description: "页面 URL",
349
+ },
350
+ viewport: {
351
+ type: "object",
352
+ description: "视口尺寸(可选)",
353
+ properties: {
354
+ width: { type: "number" },
355
+ height: { type: "number" },
356
+ },
357
+ },
358
+ },
359
+ },
360
+ required: ["url"],
361
+ };
362
+ }
363
+
364
+ /**
365
+ * force_refresh 工具执行函数
366
+ */
367
+ export async function forceRefresh(_toolCallId: string, args: any) {
368
+ const { url, viewport } = args;
369
+ const cacheStore = getCacheStore();
370
+
371
+ const vp: PageViewport = viewport || { width: 1920, height: 1080 };
372
+
373
+ const deleted = cacheStore.delete(url, vp);
374
+
375
+ if (deleted) {
376
+ return {
377
+ content: [
378
+ {
379
+ type: "text",
380
+ text: `已强制刷新缓存:${url}`,
381
+ },
382
+ ],
383
+ };
384
+ } else {
385
+ return {
386
+ content: [
387
+ {
388
+ type: "text",
389
+ text: `未找到缓存:${url}`,
390
+ },
391
+ ],
392
+ };
393
+ }
394
+ }
395
+
396
+ // ============================================================================
397
+ // 工具注册表
398
+ // ============================================================================
399
+
400
+ export const CACHE_TOOLS = [
401
+ {
402
+ definition: createExecuteCachedTool(),
403
+ execute: executeCached,
404
+ },
405
+ {
406
+ definition: createCacheStatsTool(),
407
+ execute: cacheStats,
408
+ },
409
+ {
410
+ definition: createCacheListTool(),
411
+ execute: cacheList,
412
+ },
413
+ {
414
+ definition: createCacheClearTool(),
415
+ execute: cacheClear,
416
+ },
417
+ {
418
+ definition: createScenarioListTool(),
419
+ execute: scenarioList,
420
+ },
421
+ {
422
+ definition: createForceRefreshTool(),
423
+ execute: forceRefresh,
424
+ },
425
+ ];
426
+
427
+ /**
428
+ * 获取所有工具定义
429
+ */
430
+ export function getToolDefinitions() {
431
+ return CACHE_TOOLS.map((tool) => ({
432
+ name: tool.definition.name,
433
+ label: tool.definition.label,
434
+ description: tool.definition.description,
435
+ parameters: tool.definition.parameters,
436
+ }));
437
+ }