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.
- package/dist/actions-executor.d.ts +62 -0
- package/dist/actions-executor.d.ts.map +1 -0
- package/dist/actions-executor.js +339 -0
- package/dist/actions-executor.js.map +1 -0
- package/dist/cache-invalidator.d.ts +70 -0
- package/dist/cache-invalidator.d.ts.map +1 -0
- package/dist/cache-invalidator.js +212 -0
- package/dist/cache-invalidator.js.map +1 -0
- package/dist/cache-store.d.ts +80 -0
- package/dist/cache-store.d.ts.map +1 -0
- package/dist/cache-store.js +361 -0
- package/dist/cache-store.js.map +1 -0
- package/dist/cache-strategy.d.ts +65 -0
- package/dist/cache-strategy.d.ts.map +1 -0
- package/dist/cache-strategy.js +237 -0
- package/dist/cache-strategy.js.map +1 -0
- package/dist/hooks-entry.d.ts +18 -0
- package/dist/hooks-entry.d.ts.map +1 -0
- package/dist/hooks-entry.js +27 -0
- package/dist/hooks-entry.js.map +1 -0
- package/dist/hooks.d.ts +10 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +277 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/scenario-recognizer.d.ts +45 -0
- package/dist/scenario-recognizer.d.ts.map +1 -0
- package/dist/scenario-recognizer.js +213 -0
- package/dist/scenario-recognizer.js.map +1 -0
- package/dist/security-policy.d.ts +62 -0
- package/dist/security-policy.d.ts.map +1 -0
- package/dist/security-policy.js +219 -0
- package/dist/security-policy.js.map +1 -0
- package/dist/tools.d.ts +209 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +383 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +336 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/ux-enhancer.d.ts +60 -0
- package/dist/ux-enhancer.d.ts.map +1 -0
- package/dist/ux-enhancer.js +218 -0
- package/dist/ux-enhancer.js.map +1 -0
- package/dist/variable-resolver.d.ts +28 -0
- package/dist/variable-resolver.d.ts.map +1 -0
- package/dist/variable-resolver.js +201 -0
- package/dist/variable-resolver.js.map +1 -0
- package/docs/API.md +555 -0
- package/docs/IMPLEMENTATION.md +1792 -0
- package/docs/INTEGRATION.md +387 -0
- package/docs/README.md +183 -0
- package/index.ts +118 -0
- package/openclaw.plugin.json +208 -0
- package/package.json +76 -0
- package/skills/page-action-cache/SKILL.md +216 -0
- package/src/actions-executor.ts +441 -0
- package/src/cache-invalidator.ts +271 -0
- package/src/cache-store.ts +457 -0
- package/src/cache-strategy.ts +327 -0
- package/src/hooks-entry.ts +114 -0
- package/src/hooks.ts +332 -0
- package/src/index.ts +104 -0
- package/src/scenario-recognizer.ts +259 -0
- package/src/security-policy.ts +268 -0
- package/src/tools.ts +437 -0
- package/src/types.ts +482 -0
- package/src/ux-enhancer.ts +266 -0
- package/src/variable-resolver.ts +258 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache Strategy
|
|
3
|
+
* 缓存策略 - 缓存层级策略和匹配策略
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { CacheLevel, ScenarioMatch, PageActionCacheEntry } from "./types.js";
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// 缓存策略接口
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 缓存策略接口
|
|
14
|
+
*/
|
|
15
|
+
export interface CacheStrategy {
|
|
16
|
+
/**
|
|
17
|
+
* 决定缓存层级
|
|
18
|
+
*/
|
|
19
|
+
decideCacheLevel(match: ScenarioMatch | null): CacheLevel;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 判断是否应该使用缓存
|
|
23
|
+
*/
|
|
24
|
+
shouldUseCache(
|
|
25
|
+
entry: PageActionCacheEntry,
|
|
26
|
+
match: ScenarioMatch | null
|
|
27
|
+
): boolean;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 计算缓存得分
|
|
31
|
+
*/
|
|
32
|
+
calculateScore(entry: PageActionCacheEntry): number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// 自动策略
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 自动缓存策略
|
|
41
|
+
*/
|
|
42
|
+
export class AutoCacheStrategy implements CacheStrategy {
|
|
43
|
+
decideCacheLevel(match: ScenarioMatch | null): CacheLevel {
|
|
44
|
+
if (!match) {
|
|
45
|
+
return "L1"; // 无匹配,使用 L1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 根据置信度决定层级
|
|
49
|
+
if (match.confidence >= 85) {
|
|
50
|
+
return "L3"; // 高置信度,场景级
|
|
51
|
+
} else if (match.confidence >= 70) {
|
|
52
|
+
return "L2"; // 中等置信度,流程级
|
|
53
|
+
} else {
|
|
54
|
+
return "L1"; // 低置信度,原子级
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
shouldUseCache(
|
|
59
|
+
entry: PageActionCacheEntry,
|
|
60
|
+
match: ScenarioMatch | null
|
|
61
|
+
): boolean {
|
|
62
|
+
// 检查过期
|
|
63
|
+
if (Date.now() > entry.expiresAt) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 检查成功率
|
|
68
|
+
const total = entry.successCount + entry.failCount;
|
|
69
|
+
if (total > 5 && entry.successCount / total < 0.6) {
|
|
70
|
+
return false; // 成功率太低
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 检查访问次数
|
|
74
|
+
if (entry.accessCount === 0) {
|
|
75
|
+
return true; // 新缓存,可以使用
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// L3 缓存直接使用
|
|
79
|
+
if (entry.cacheLevel === "L3") {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// L2 缓存需要匹配
|
|
84
|
+
if (entry.cacheLevel === "L2" && match && match.confidence >= 70) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// L1 缓存谨慎使用
|
|
89
|
+
if (entry.cacheLevel === "L1" && match && match.confidence >= 50) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
calculateScore(entry: PageActionCacheEntry): number {
|
|
97
|
+
// 计算缓存得分(0-100)
|
|
98
|
+
let score = 0;
|
|
99
|
+
|
|
100
|
+
// 层级权重
|
|
101
|
+
switch (entry.cacheLevel) {
|
|
102
|
+
case "L3":
|
|
103
|
+
score += 40;
|
|
104
|
+
break;
|
|
105
|
+
case "L2":
|
|
106
|
+
score += 25;
|
|
107
|
+
break;
|
|
108
|
+
case "L1":
|
|
109
|
+
score += 10;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 访问次数权重
|
|
114
|
+
score += Math.min(entry.accessCount * 2, 20);
|
|
115
|
+
|
|
116
|
+
// 成功率权重
|
|
117
|
+
const total = entry.successCount + entry.failCount;
|
|
118
|
+
if (total > 0) {
|
|
119
|
+
score += (entry.successCount / total) * 30;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 平均执行时间权重(越快越好)
|
|
123
|
+
if (entry.avgExecutionTime > 0) {
|
|
124
|
+
score += Math.max(0, 10 - entry.avgExecutionTime / 100);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return Math.min(score, 100);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ============================================================================
|
|
132
|
+
// L3 优先策略
|
|
133
|
+
// ============================================================================
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* L3 优先策略
|
|
137
|
+
*/
|
|
138
|
+
export class L3OnlyCacheStrategy implements CacheStrategy {
|
|
139
|
+
decideCacheLevel(_match: ScenarioMatch | null): CacheLevel {
|
|
140
|
+
return "L3";
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
shouldUseCache(
|
|
144
|
+
entry: PageActionCacheEntry,
|
|
145
|
+
match: ScenarioMatch | null
|
|
146
|
+
): boolean {
|
|
147
|
+
// 只使用 L3 缓存
|
|
148
|
+
if (entry.cacheLevel !== "L3") {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 检查过期
|
|
153
|
+
if (Date.now() > entry.expiresAt) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 检查匹配
|
|
158
|
+
if (!match || match.confidence < 85) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
calculateScore(entry: PageActionCacheEntry): number {
|
|
166
|
+
// L3 缓存才有得分
|
|
167
|
+
if (entry.cacheLevel !== "L3") {
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let score = 50; // 基础分
|
|
172
|
+
|
|
173
|
+
// 访问次数
|
|
174
|
+
score += Math.min(entry.accessCount * 3, 30);
|
|
175
|
+
|
|
176
|
+
// 成功率
|
|
177
|
+
const total = entry.successCount + entry.failCount;
|
|
178
|
+
if (total > 0) {
|
|
179
|
+
score += (entry.successCount / total) * 20;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return Math.min(score, 100);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ============================================================================
|
|
187
|
+
// L2 优先策略
|
|
188
|
+
// ============================================================================
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* L2 优先策略
|
|
192
|
+
*/
|
|
193
|
+
export class L2OnlyCacheStrategy implements CacheStrategy {
|
|
194
|
+
decideCacheLevel(match: ScenarioMatch | null): CacheLevel {
|
|
195
|
+
if (match && match.confidence >= 70) {
|
|
196
|
+
return "L2";
|
|
197
|
+
}
|
|
198
|
+
return "L1";
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
shouldUseCache(
|
|
202
|
+
entry: PageActionCacheEntry,
|
|
203
|
+
_match: ScenarioMatch | null
|
|
204
|
+
): boolean {
|
|
205
|
+
// 使用 L2 或 L1 缓存
|
|
206
|
+
if (entry.cacheLevel === "L3") {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 检查过期
|
|
211
|
+
if (Date.now() > entry.expiresAt) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
calculateScore(entry: PageActionCacheEntry): number {
|
|
219
|
+
// L2 和 L1 缓存才有得分
|
|
220
|
+
if (entry.cacheLevel === "L3") {
|
|
221
|
+
return 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let score = entry.cacheLevel === "L2" ? 40 : 20;
|
|
225
|
+
|
|
226
|
+
// 访问次数
|
|
227
|
+
score += Math.min(entry.accessCount * 2, 25);
|
|
228
|
+
|
|
229
|
+
// 成功率
|
|
230
|
+
const total = entry.successCount + entry.failCount;
|
|
231
|
+
if (total > 0) {
|
|
232
|
+
score += (entry.successCount / total) * 35;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return Math.min(score, 100);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// L1 优先策略
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* L1 优先策略
|
|
245
|
+
*/
|
|
246
|
+
export class L1OnlyCacheStrategy implements CacheStrategy {
|
|
247
|
+
decideCacheLevel(_match: ScenarioMatch | null): CacheLevel {
|
|
248
|
+
return "L1";
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
shouldUseCache(
|
|
252
|
+
entry: PageActionCacheEntry,
|
|
253
|
+
_match: ScenarioMatch | null
|
|
254
|
+
): boolean {
|
|
255
|
+
// 只使用 L1 缓存
|
|
256
|
+
if (entry.cacheLevel !== "L1") {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 检查过期
|
|
261
|
+
if (Date.now() > entry.expiresAt) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
calculateScore(entry: PageActionCacheEntry): number {
|
|
269
|
+
// L1 缓存才有得分
|
|
270
|
+
if (entry.cacheLevel !== "L1") {
|
|
271
|
+
return 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
let score = 20; // 基础分
|
|
275
|
+
|
|
276
|
+
// 访问次数
|
|
277
|
+
score += Math.min(entry.accessCount * 2, 40);
|
|
278
|
+
|
|
279
|
+
// 成功率
|
|
280
|
+
const total = entry.successCount + entry.failCount;
|
|
281
|
+
if (total > 0) {
|
|
282
|
+
score += (entry.successCount / total) * 40;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return Math.min(score, 100);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ============================================================================
|
|
290
|
+
// 策略工厂
|
|
291
|
+
// ============================================================================
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* 缓存策略工厂
|
|
295
|
+
*/
|
|
296
|
+
export class CacheStrategyFactory {
|
|
297
|
+
/**
|
|
298
|
+
* 创建缓存策略
|
|
299
|
+
*/
|
|
300
|
+
createStrategy(strategy: "auto" | "l3-only" | "l2-only" | "l1-only"): CacheStrategy {
|
|
301
|
+
switch (strategy) {
|
|
302
|
+
case "auto":
|
|
303
|
+
return new AutoCacheStrategy();
|
|
304
|
+
case "l3-only":
|
|
305
|
+
return new L3OnlyCacheStrategy();
|
|
306
|
+
case "l2-only":
|
|
307
|
+
return new L2OnlyCacheStrategy();
|
|
308
|
+
case "l1-only":
|
|
309
|
+
return new L1OnlyCacheStrategy();
|
|
310
|
+
default:
|
|
311
|
+
return new AutoCacheStrategy();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ============================================================================
|
|
317
|
+
// 单例
|
|
318
|
+
// ============================================================================
|
|
319
|
+
|
|
320
|
+
let strategyFactoryInstance: CacheStrategyFactory | null = null;
|
|
321
|
+
|
|
322
|
+
export function getCacheStrategyFactory(): CacheStrategyFactory {
|
|
323
|
+
if (!strategyFactoryInstance) {
|
|
324
|
+
strategyFactoryInstance = new CacheStrategyFactory();
|
|
325
|
+
}
|
|
326
|
+
return strategyFactoryInstance;
|
|
327
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page Action Cache Extension - Entry Point
|
|
3
|
+
* 页面操作缓存扩展 - 入口点
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { registerPageActionCacheHooks } from "./hooks.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Plugin config interface
|
|
10
|
+
*/
|
|
11
|
+
interface PageActionCacheConfig {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
autoUseCache?: boolean;
|
|
14
|
+
scenarioRecognitionEnabled?: boolean;
|
|
15
|
+
llmClassificationThreshold?: number;
|
|
16
|
+
cacheLevelStrategy?: "auto" | "l3-only" | "l2-only" | "l1-only";
|
|
17
|
+
defaultCacheLevel?: "L3" | "L2" | "L1";
|
|
18
|
+
pageChangeDetectionEnabled?: boolean;
|
|
19
|
+
changeInvalidationThreshold?: number;
|
|
20
|
+
invalidationStrategy?: "soft" | "hard";
|
|
21
|
+
variableExtractionEnabled?: boolean;
|
|
22
|
+
allowUserConfirmVariables?: boolean;
|
|
23
|
+
encryptSensitiveCache?: boolean;
|
|
24
|
+
accessControlEnabled?: boolean;
|
|
25
|
+
logSanitizationEnabled?: boolean;
|
|
26
|
+
showCacheStatusToUser?: boolean;
|
|
27
|
+
enableUserCacheConfirmation?: boolean;
|
|
28
|
+
enableUserForcedRefresh?: boolean;
|
|
29
|
+
enableUserCacheErrorReport?: boolean;
|
|
30
|
+
trackExecutionStats?: boolean;
|
|
31
|
+
statsUpdateInterval?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Default plugin configuration
|
|
36
|
+
*/
|
|
37
|
+
const DEFAULT_CONFIG: Required<PageActionCacheConfig> = {
|
|
38
|
+
enabled: true,
|
|
39
|
+
autoUseCache: true,
|
|
40
|
+
scenarioRecognitionEnabled: true,
|
|
41
|
+
llmClassificationThreshold: 70,
|
|
42
|
+
cacheLevelStrategy: "auto",
|
|
43
|
+
defaultCacheLevel: "L3",
|
|
44
|
+
pageChangeDetectionEnabled: true,
|
|
45
|
+
changeInvalidationThreshold: 80,
|
|
46
|
+
invalidationStrategy: "soft",
|
|
47
|
+
variableExtractionEnabled: true,
|
|
48
|
+
allowUserConfirmVariables: false,
|
|
49
|
+
encryptSensitiveCache: false,
|
|
50
|
+
accessControlEnabled: false,
|
|
51
|
+
logSanitizationEnabled: true,
|
|
52
|
+
showCacheStatusToUser: true,
|
|
53
|
+
enableUserCacheConfirmation: false,
|
|
54
|
+
enableUserForcedRefresh: true,
|
|
55
|
+
enableUserCacheErrorReport: true,
|
|
56
|
+
trackExecutionStats: true,
|
|
57
|
+
statsUpdateInterval: 60,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Plugin definition - OpenClaw plugin API format
|
|
62
|
+
*/
|
|
63
|
+
const pageActionCachePlugin = {
|
|
64
|
+
id: "page-action-cache",
|
|
65
|
+
name: "Page Action Cache",
|
|
66
|
+
version: "1.0.0",
|
|
67
|
+
description:
|
|
68
|
+
"Browser operation cache extension - caches common page action sequences to reduce token consumption and operation latency",
|
|
69
|
+
author: "OpenClaw",
|
|
70
|
+
license: "MIT",
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Register the plugin with OpenClaw
|
|
74
|
+
*/
|
|
75
|
+
register(api: any) {
|
|
76
|
+
try {
|
|
77
|
+
// Get plugin config from OpenClaw config
|
|
78
|
+
const pluginConfig = api.config?.plugins?.entries?.["page-action-cache"]?.config || {};
|
|
79
|
+
|
|
80
|
+
// Merge with defaults
|
|
81
|
+
const config = { ...DEFAULT_CONFIG, ...pluginConfig };
|
|
82
|
+
|
|
83
|
+
// Register hooks and initialize extension
|
|
84
|
+
if (config.enabled) {
|
|
85
|
+
registerPageActionCacheHooks(api, config);
|
|
86
|
+
console.log("[PageActionCache] Extension initialized successfully");
|
|
87
|
+
} else {
|
|
88
|
+
console.log("[PageActionCache] Extension disabled");
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error("[PageActionCache] Failed to initialize extension:", error);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Default export - OpenClaw plugin format (function)
|
|
98
|
+
*/
|
|
99
|
+
export default function (api: any) {
|
|
100
|
+
pageActionCachePlugin.register(api);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Named export - direct initialization for manual use
|
|
105
|
+
*/
|
|
106
|
+
export { pageActionCachePlugin };
|
|
107
|
+
export function initializePageActionCache(api: any, config?: any): void {
|
|
108
|
+
try {
|
|
109
|
+
registerPageActionCacheHooks(api, config);
|
|
110
|
+
console.log("[PageActionCache] Extension initialized successfully");
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error("[PageActionCache] Failed to initialize extension:", error);
|
|
113
|
+
}
|
|
114
|
+
}
|