page-action-cache 2.0.9 → 2026.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +100 -306
  2. package/openclaw.plugin.json +23 -14
  3. package/package.json +28 -21
  4. package/dist/browser-action-executor.d.ts +0 -87
  5. package/dist/browser-action-executor.d.ts.map +0 -1
  6. package/dist/browser-action-executor.js +0 -283
  7. package/dist/browser-action-executor.js.map +0 -1
  8. package/dist/cache-invalidation.d.ts +0 -129
  9. package/dist/cache-invalidation.d.ts.map +0 -1
  10. package/dist/cache-invalidation.js +0 -266
  11. package/dist/cache-invalidation.js.map +0 -1
  12. package/dist/cache-manager.d.ts +0 -83
  13. package/dist/cache-manager.d.ts.map +0 -1
  14. package/dist/cache-manager.js +0 -184
  15. package/dist/cache-manager.js.map +0 -1
  16. package/dist/index.d.ts +0 -11
  17. package/dist/index.d.ts.map +0 -1
  18. package/dist/index.js +0 -408
  19. package/dist/index.js.map +0 -1
  20. package/dist/multi-level-cache.d.ts +0 -127
  21. package/dist/multi-level-cache.d.ts.map +0 -1
  22. package/dist/multi-level-cache.js +0 -364
  23. package/dist/multi-level-cache.js.map +0 -1
  24. package/dist/scenario-recognizer.d.ts +0 -35
  25. package/dist/scenario-recognizer.d.ts.map +0 -1
  26. package/dist/scenario-recognizer.js +0 -93
  27. package/dist/scenario-recognizer.js.map +0 -1
  28. package/dist/types.d.ts +0 -62
  29. package/dist/types.d.ts.map +0 -1
  30. package/dist/types.js +0 -6
  31. package/dist/types.js.map +0 -1
  32. package/dist/variable-extractor.d.ts +0 -56
  33. package/dist/variable-extractor.d.ts.map +0 -1
  34. package/dist/variable-extractor.js +0 -161
  35. package/dist/variable-extractor.js.map +0 -1
  36. package/src/browser-action-executor.ts +0 -337
  37. package/src/cache-invalidation.ts +0 -342
  38. package/src/cache-manager.ts +0 -211
  39. package/src/index.ts +0 -468
  40. package/src/multi-level-cache.ts +0 -480
  41. package/src/scenario-recognizer.ts +0 -121
  42. package/src/types-mock.d.ts +0 -18
  43. package/src/types.ts +0 -66
  44. package/src/variable-extractor.ts +0 -206
package/src/index.ts DELETED
@@ -1,468 +0,0 @@
1
- /**
2
- * Page Action Cache - OpenClaw Extension
3
- * 页面操作缓存扩展 - OpenClaw 扩展
4
- */
5
-
6
- import type { OpenClawPluginApi } from './types-mock.js';
7
- import type { ScenarioType } from './types.js';
8
- import { scenarioRecognizer } from './scenario-recognizer.js';
9
- import { multiLevelCache } from './multi-level-cache.js';
10
- import { cacheInvalidation } from './cache-invalidation.js';
11
- import { browserActionExecutor } from './browser-action-executor.js';
12
-
13
- /**
14
- * 主扩展入口
15
- */
16
- export function register(api: OpenClawPluginApi): void {
17
- console.log('[PageActionCache] Initializing extension...');
18
-
19
- // 获取插件配置 - 详细日志
20
- const rawConfig = api.getConfig?.();
21
- console.log('[PageActionCache] Raw config object:', JSON.stringify(rawConfig, null, 2));
22
-
23
- // 检查配置对象是否有效
24
- let config = rawConfig;
25
- if (!config || typeof config !== 'object') {
26
- console.log('[PageActionCache] Invalid config object type:', typeof rawConfig);
27
- // 配置无效,使用空对象继续
28
- config = {};
29
- }
30
-
31
- const pluginConfig = config?.plugins?.entries?.['page-action-cache'] ?? {};
32
- console.log('[PageActionCache] Plugin config for page-action-cache:', JSON.stringify(pluginConfig, null, 2));
33
-
34
- const pageActionCacheConfig = pluginConfig ?? {};
35
- console.log('[PageActionCache] Parsed pageActionCacheConfig:', JSON.stringify(pageActionCacheConfig, null, 2));
36
-
37
- const enabled = pageActionCacheConfig.enabled !== false;
38
- console.log('[PageActionCache] Enabled status:', enabled);
39
-
40
- if (!enabled) {
41
- console.log('[PageActionCache] Extension disabled by configuration');
42
- return;
43
- }
44
-
45
- console.log('[PageActionCache] Extension enabled, proceeding with tool registration...');
46
-
47
- // 应用配置
48
- if (pageActionCacheConfig.cacheLevelStrategy) {
49
- multiLevelCache.setStrategy(pageActionCacheConfig.cacheLevelStrategy);
50
- console.log('[PageActionCache] Set cache level strategy:', pageActionCacheConfig.cacheLevelStrategy);
51
- }
52
-
53
- if (pageActionCacheConfig.llmClassificationThreshold !== undefined) {
54
- multiLevelCache.setLLMThreshold(pageActionCacheConfig.llmClassificationThreshold);
55
- console.log('[PageActionCache] Set LLM classification threshold:', pageActionCacheConfig.llmClassificationThreshold);
56
- }
57
-
58
- if (pageActionCacheConfig.invalidationStrategy) {
59
- cacheInvalidation.setStrategy(pageActionCacheConfig.invalidationStrategy);
60
- console.log('[PageActionCache] Set invalidation strategy:', pageActionCacheConfig.invalidationStrategy);
61
- }
62
-
63
- if (pageActionCacheConfig.changeInvalidationThreshold !== undefined) {
64
- cacheInvalidation.setChangeThreshold(pageActionCacheConfig.changeInvalidationThreshold);
65
- console.log('[PageActionCache] Set change invalidation threshold:', pageActionCacheConfig.changeInvalidationThreshold);
66
- }
67
-
68
- // 注册缓存执行工具
69
- api.registerTool({
70
- name: 'browser_cache_execute',
71
- description: '执行缓存的页面操作序列,支持自动缓存匹配、场景识别和变量提取',
72
- async execute(ctx: { config?: any; params?: any }) {
73
- try {
74
- console.log('[PageActionCache] browser_cache_execute called');
75
- console.log('[PageActionCache] Context type:', typeof ctx);
76
- console.log('[PageActionCache] Context config:', ctx.config ? JSON.stringify(ctx.config, null, 2) : 'null');
77
- console.log('[PageActionCache] Context params:', ctx.params ? JSON.stringify(ctx.params, null, 2) : 'null');
78
-
79
- // 从插件配置中读取 enabled 状态
80
- const pluginConfig = ctx.config?.plugins?.entries?.['page-action-cache'] ?? {};
81
- const enabled = pluginConfig.enabled !== false;
82
-
83
- if (!enabled) {
84
- console.log('[PageActionCache] Extension disabled by context config');
85
- return {
86
- success: false,
87
- message: 'Extension is disabled',
88
- executedActions: 0,
89
- skippedActions: 0,
90
- failedActions: 0,
91
- savedTime: 0
92
- };
93
- }
94
-
95
- const params = ctx.params || {};
96
- const url = params.url;
97
- const viewport = params.viewport || '1920x1080';
98
- const scenario = params.scenario;
99
- const actions = params.actions;
100
- const useCache = params.useCache !== false; // 默认使用缓存
101
- const forceRefresh = params.forceRefresh === true;
102
- const llmClassificationScore = params.llmClassificationScore;
103
-
104
- console.log('[PageActionCache] Parsed params:', { url, viewport, scenario, useCache, forceRefresh, llmClassificationScore });
105
-
106
- if (!url) {
107
- return {
108
- success: false,
109
- message: 'Missing required parameter: url',
110
- executedActions: 0,
111
- skippedActions: 0,
112
- failedActions: 0,
113
- savedTime: 0
114
- };
115
- }
116
-
117
- // 识别场景
118
- let recognizedScenario: string = scenario || scenarioRecognizer.recognize(url);
119
- console.log('[PageActionCache] Recognized scenario:', recognizedScenario);
120
-
121
- let cachedEntry = null;
122
- let isCacheHit = false;
123
- let executedActions = 0;
124
- let skippedActions = 0;
125
- let failedActions = 0;
126
- let savedTime = 0;
127
- let cacheId = '';
128
-
129
- // 尝试从缓存中查找
130
- if (useCache && !forceRefresh) {
131
- console.log('[PageActionCache] Checking cache...');
132
- cachedEntry = multiLevelCache.queryCache(url, viewport);
133
-
134
- if (cachedEntry) {
135
- console.log('[PageActionCache] Cache hit found:', cachedEntry.id);
136
- isCacheHit = true;
137
- cacheId = cachedEntry.id;
138
-
139
- // 检查页面是否发生变化(如果提供了 HTML)
140
- if (pageActionCacheConfig.pageChangeDetectionEnabled && params.html) {
141
- const shouldInvalidate = cacheInvalidation.shouldInvalidate(url, viewport, params.html);
142
- if (shouldInvalidate) {
143
- console.log('[PageActionCache] Page changed, cache invalidated');
144
- multiLevelCache.deleteCache(url, viewport);
145
- cachedEntry = null;
146
- isCacheHit = false;
147
- } else {
148
- console.log('[PageActionCache] Page unchanged, cache valid');
149
- }
150
- }
151
- } else {
152
- console.log('[PageActionCache] Cache miss');
153
- }
154
- }
155
-
156
- // 如果没有缓存或需要强制刷新,执行新的操作
157
- if (!cachedEntry) {
158
- console.log('[PageActionCache] Executing new actions...');
159
- if (!actions || actions.length === 0) {
160
- return {
161
- success: false,
162
- message: 'No actions provided and no cache found',
163
- executedActions: 0,
164
- skippedActions: 0,
165
- failedActions: 0,
166
- savedTime: 0
167
- };
168
- }
169
-
170
- // 执行操作
171
- const actionResults: any[] = [];
172
- for (let i = 0; i < actions.length; i++) {
173
- const action: any = actions[i];
174
- console.log('[PageActionCache] Executing action', i + 1, ':', action.type);
175
-
176
- try {
177
- const startTime = Date.now();
178
- let result: any;
179
-
180
- switch (action.type) {
181
- case 'navigate':
182
- if (!action.params?.url) {
183
- result = { success: false, message: 'Missing URL' };
184
- } else {
185
- // 模拟导航操作
186
- console.log('[PageActionCache] Navigating to:', action.params.url);
187
- result = { success: true, message: `Navigated to ${action.params.url}` };
188
- }
189
- break;
190
-
191
- case 'click':
192
- if (!action.params?.selector) {
193
- result = { success: false, message: 'Missing selector' };
194
- } else {
195
- console.log('[PageActionCache] Clicking:', action.params.selector);
196
- result = { success: true, message: `Clicked ${action.params.selector}` };
197
- }
198
- break;
199
-
200
- case 'type':
201
- if (!action.params?.selector || action.params?.text === undefined) {
202
- result = { success: false, message: 'Missing selector or text' };
203
- } else {
204
- console.log('[PageActionCache] Typing:', action.params.text);
205
- result = { success: true, message: `Typed text` };
206
- }
207
- break;
208
-
209
- case 'screenshot':
210
- console.log('[PageActionCache] Taking screenshot');
211
- result = { success: true, message: 'Screenshot taken' };
212
- break;
213
-
214
- case 'script':
215
- if (!action.params?.script) {
216
- result = { success: false, message: 'Missing script' };
217
- } else {
218
- console.log('[PageActionCache] Executing script');
219
- result = { success: true, message: 'Script executed' };
220
- }
221
- break;
222
-
223
- default:
224
- result = { success: false, message: `Unknown action type: ${action.type}` };
225
- }
226
-
227
- const executionTime = Date.now() - startTime;
228
- result.executionTime = executionTime;
229
- actionResults.push(result);
230
-
231
- if (result.success) {
232
- executedActions++;
233
- } else {
234
- failedActions++;
235
- }
236
-
237
- } catch (error) {
238
- console.error('[PageActionCache] Action execution error:', error);
239
- failedActions++;
240
- actionResults.push({
241
- success: false,
242
- message: `Error: ${error instanceof Error ? error.message : String(error)}`
243
- });
244
- }
245
- }
246
-
247
- // 保存到缓存
248
- const processedActions = actions.map((action: any, index: number) => ({
249
- type: action.type,
250
- params: action.params,
251
- successCount: actionResults[index]?.success ? 1 : 0,
252
- failCount: actionResults[index]?.success ? 0 : 1
253
- }));
254
-
255
- cacheId = multiLevelCache.addCache(
256
- url,
257
- viewport,
258
- processedActions,
259
- recognizedScenario as ScenarioType,
260
- llmClassificationScore
261
- );
262
-
263
- // 保存页面快照(如果提供了 HTML)
264
- if (params.html) {
265
- cacheInvalidation.saveSnapshot(url, viewport, params.html);
266
- }
267
-
268
- console.log('[PageActionCache] Saved to cache with ID:', cacheId);
269
- savedTime = 0; // 首次执行不节省时间
270
- } else {
271
- // 使用缓存执行
272
- console.log('[PageActionCache] Using cached entry...');
273
- const result = await browserActionExecutor.executeCacheEntry(cachedEntry as any);
274
- executedActions = result.executedActions;
275
- skippedActions = result.skippedActions;
276
- failedActions = result.failedActions;
277
- savedTime = result.savedTime;
278
- console.log('[PageActionCache] Cache execution result:', result);
279
- }
280
-
281
- // 生成返回消息
282
- let message = isCacheHit ? 'Cached Execution' : 'New Execution';
283
- message += '\n\n';
284
- message += `Execution completed ${isCacheHit ? 'from cache' : 'successfully'}\n\n`;
285
- message += `- Executed Actions: ${executedActions}\n`;
286
- message += `- Skipped Actions: ${skippedActions}\n`;
287
- message += `- Failed Actions: ${failedActions}\n`;
288
- message += `- Saved Time: ${savedTime}ms\n\n`;
289
- message += `Cache ID: ${cacheId}\n`;
290
- message += `URL: ${url}\n`;
291
- message += `Scenario: ${recognizedScenario}\n`;
292
-
293
- if (isCacheHit && cachedEntry) {
294
- message += `Cache Level: ${cachedEntry.level}\n`;
295
- message += `Access Count: ${cachedEntry.accessCount}\n`;
296
- }
297
-
298
- console.log('[PageActionCache] Returning result:', message);
299
-
300
- return {
301
- success: failedActions === 0,
302
- message,
303
- executedActions,
304
- skippedActions,
305
- failedActions,
306
- savedTime,
307
- cacheId,
308
- url,
309
- scenario: recognizedScenario,
310
- isCacheHit,
311
- cacheLevel: cachedEntry?.level
312
- };
313
-
314
- } catch (error) {
315
- console.error('[PageActionCache] Error in browser_cache_execute:', error);
316
- const errorMessage = error instanceof Error ? error.message : String(error);
317
- return {
318
- success: false,
319
- message: `Error: ${errorMessage}`,
320
- executedActions: 0,
321
- skippedActions: 0,
322
- failedActions: 0,
323
- savedTime: 0
324
- };
325
- }
326
- }
327
- });
328
-
329
- // 注册缓存统计工具
330
- api.registerTool({
331
- name: 'browser_cache_stats',
332
- description: '查看页面操作缓存的统计信息',
333
- async execute(ctx: { config?: any; params?: any }) {
334
- try {
335
- console.log('[PageActionCache] browser_cache_stats called');
336
-
337
- const pluginConfig = ctx.config?.plugins?.entries?.['page-action-cache'] ?? {};
338
- const enabled = pluginConfig.enabled !== false;
339
-
340
- if (!enabled) {
341
- return {
342
- success: false,
343
- message: 'Extension is disabled'
344
- };
345
- }
346
-
347
- const stats = multiLevelCache.getStats();
348
- const invalidationStats = cacheInvalidation.getInvalidationStats();
349
-
350
- console.log('[PageActionCache] Stats:', stats);
351
- console.log('[PageActionCache] Invalidation stats:', invalidationStats);
352
-
353
- // 生成统计报告
354
- let message = '## Page Action Cache Statistics\n\n';
355
- message += '### Overall Performance\n';
356
- message += `- Total Cache Entries: ${stats.totalEntries}\n`;
357
- message += `- Total Cache Hits: ${stats.totalHits}\n`;
358
- message += `- Cache Hit Rate: ${stats.hitRate.toFixed(2)}%\n\n`;
359
-
360
- message += '### Multi-Level Cache Distribution\n';
361
- for (const [level, levelStats] of Object.entries(stats.levelStats)) {
362
- message += `#### ${level} Cache\n`;
363
- message += `- Size: ${levelStats.size}/${levelStats.maxCapacity} (${(levelStats.usageRate * 100).toFixed(1)}% full)\n`;
364
- message += `- Average Access Count: ${levelStats.avgAccessCount.toFixed(1)}\n\n`;
365
- }
366
-
367
- message += '### Cache Invalidation\n';
368
- message += `- Total Snapshots: ${invalidationStats.totalSnapshots}\n`;
369
- message += `- Active Snapshots: ${invalidationStats.activeSnapshots}\n`;
370
- message += `- Invalidation Rate: ${(invalidationStats.invalidationRate * 100).toFixed(2)}%\n`;
371
-
372
- return {
373
- success: true,
374
- message,
375
- stats,
376
- invalidationStats
377
- };
378
-
379
- } catch (error) {
380
- console.error('[PageActionCache] Error in browser_cache_stats:', error);
381
- return {
382
- success: false,
383
- message: `Error: ${error instanceof Error ? error.message : String(error)}`
384
- };
385
- }
386
- }
387
- });
388
-
389
- // 注册缓存清空工具
390
- api.registerTool({
391
- name: 'browser_cache_clear',
392
- description: '清空页面操作缓存',
393
- async execute(ctx: { config?: any; params?: any }) {
394
- try {
395
- console.log('[PageActionCache] browser_cache_clear called');
396
- console.log('[PageActionCache] Context params:', ctx.params ? JSON.stringify(ctx.params, null, 2) : 'null');
397
-
398
- const pluginConfig = ctx.config?.plugins?.entries?.['page-action-cache'] ?? {};
399
- const enabled = pluginConfig.enabled !== false;
400
-
401
- if (!enabled) {
402
- return {
403
- success: false,
404
- message: 'Extension is disabled'
405
- };
406
- }
407
-
408
- const params = ctx.params || {};
409
- const level = params.level || 'all'; // 'all', 'L3', 'L2', 'L1'
410
- const url = params.url;
411
- const viewport = params.viewport;
412
-
413
- console.log('[PageActionCache] Clear params:', { level, url, viewport });
414
-
415
- let cleared = 0;
416
-
417
- if (level === 'all') {
418
- if (url) {
419
- // 清空特定 URL 的所有缓存
420
- multiLevelCache.deleteCacheByUrl(url);
421
- cacheInvalidation.invalidateByUrl(url);
422
- cleared = 1;
423
- } else {
424
- // 清空所有缓存
425
- multiLevelCache.clearAll();
426
- cacheInvalidation.reset();
427
- cleared = 1;
428
- }
429
- } else if (level === 'L3' || level === 'L2' || level === 'L1') {
430
- if (url && viewport) {
431
- multiLevelCache.deleteCache(url, viewport);
432
- cacheInvalidation.invalidate(url, viewport);
433
- cleared = 1;
434
- } else {
435
- multiLevelCache.clearLevel(level);
436
- cleared = 1;
437
- }
438
- }
439
-
440
- console.log('[PageActionCache] Cleared cache entries');
441
-
442
- const levelText = level === 'all' ? 'all caches' : `${level} cache`;
443
- const urlText = url ? ` for ${url}` : '';
444
- const message = `Cleared ${levelText}${urlText}`;
445
-
446
- return {
447
- success: true,
448
- message,
449
- level,
450
- url,
451
- cleared
452
- };
453
-
454
- } catch (error) {
455
- console.error('[PageActionCache] Error in browser_cache_clear:', error);
456
- return {
457
- success: false,
458
- message: `Error: ${error instanceof Error ? error.message : String(error)}`
459
- };
460
- }
461
- }
462
- });
463
-
464
- console.log('[PageActionCache] All tools registered successfully');
465
- }
466
-
467
- // Export register as registerTools for backward compatibility with tests
468
- export const registerTools = register;