Skip to content

Commit 62e1a7c

Browse files
refresh act cache on self-heal (#1191)
# why # what changed # test plan
1 parent 9121e98 commit 62e1a7c

File tree

1 file changed

+88
-2
lines changed

1 file changed

+88
-2
lines changed

packages/core/lib/v3/cache/ActCache.ts

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createHash } from "crypto";
22
import type { ActHandler } from "../handlers/actHandler";
33
import type { LLMClient } from "../llm/LLMClient";
4-
import type { ActResult, Logger } from "../types/public";
4+
import type { Action, ActResult, Logger } from "../types/public";
55
import type { Page } from "../understudy/page";
66
import { CacheStorage } from "./CacheStorage";
77
import { safeGetPageUrl } from "./utils";
@@ -100,7 +100,7 @@ export class ActCache {
100100
},
101101
});
102102

103-
return await this.replayCachedActions(entry, page, timeout);
103+
return await this.replayCachedActions(context, entry, page, timeout);
104104
}
105105

106106
async store(context: ActCacheContext, result: ActResult): Promise<void> {
@@ -157,6 +157,7 @@ export class ActCache {
157157
}
158158

159159
private async replayCachedActions(
160+
context: ActCacheContext,
160161
entry: CachedActEntry,
161162
page: Page,
162163
timeout?: number,
@@ -206,6 +207,19 @@ export class ActCache {
206207
actionResults[actionResults.length - 1]?.actionDescription ||
207208
entry.actions[entry.actions.length - 1]?.description ||
208209
entry.instruction;
210+
211+
if (
212+
success &&
213+
actions.length > 0 &&
214+
this.haveActionsChanged(entry.actions, actions)
215+
) {
216+
await this.refreshCacheEntry(context, {
217+
...entry,
218+
actions,
219+
message,
220+
actionDescription,
221+
});
222+
}
209223
return {
210224
success,
211225
message,
@@ -217,6 +231,78 @@ export class ActCache {
217231
return await this.runWithTimeout(execute, timeout);
218232
}
219233

234+
private haveActionsChanged(original: Action[], updated: Action[]): boolean {
235+
if (original.length !== updated.length) {
236+
return true;
237+
}
238+
239+
for (let i = 0; i < original.length; i += 1) {
240+
const orig = original[i];
241+
const next = updated[i];
242+
if (!next) {
243+
return true;
244+
}
245+
246+
if (orig.selector !== next.selector) {
247+
return true;
248+
}
249+
250+
if (orig.description !== next.description) {
251+
return true;
252+
}
253+
254+
if ((orig.method ?? "") !== (next.method ?? "")) {
255+
return true;
256+
}
257+
258+
const origArgs = orig.arguments ?? [];
259+
const nextArgs = next.arguments ?? [];
260+
if (origArgs.length !== nextArgs.length) {
261+
return true;
262+
}
263+
264+
for (let j = 0; j < origArgs.length; j += 1) {
265+
if (origArgs[j] !== nextArgs[j]) {
266+
return true;
267+
}
268+
}
269+
}
270+
271+
return false;
272+
}
273+
274+
private async refreshCacheEntry(
275+
context: ActCacheContext,
276+
entry: CachedActEntry,
277+
): Promise<void> {
278+
const { error, path } = await this.storage.writeJson(
279+
`${context.cacheKey}.json`,
280+
entry,
281+
);
282+
283+
if (error && path) {
284+
this.logger({
285+
category: "cache",
286+
message: "failed to update act cache entry after self-heal",
287+
level: 0,
288+
auxiliary: {
289+
error: { value: String(error), type: "string" },
290+
},
291+
});
292+
return;
293+
}
294+
295+
this.logger({
296+
category: "cache",
297+
message: "act cache entry updated after self-heal",
298+
level: 2,
299+
auxiliary: {
300+
instruction: { value: context.instruction, type: "string" },
301+
url: { value: context.pageUrl, type: "string" },
302+
},
303+
});
304+
}
305+
220306
private async runWithTimeout<T>(
221307
run: () => Promise<T>,
222308
timeout?: number,

0 commit comments

Comments
 (0)