Skip to content

Commit 2bfd612

Browse files
Guard frame-graph debug setter in agent loop
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 3bcbd74 commit 2bfd612

3 files changed

Lines changed: 66 additions & 1 deletion

File tree

‎currentState.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ HyperAgent exposes a TypeScript SDK for browser automation with three primary pa
203203
- `syncFrameContextManager()` now guards trap-prone frame-manager `setDebug` calls, preserving sync flow with sanitized debug warnings.
204204
- Hardened cache-hydration debug handling in a11y context provider:
205205
- `hydrateFrameContextFromSnapshot()` now guards trap-prone frame-manager `setDebug` calls so cache hydration continues instead of aborting early.
206+
- Hardened frame-graph debug artifact capture in agent loop:
207+
- `writeFrameGraphSnapshot()` now guards trap-prone frame-manager `setDebug` calls and still proceeds with frame graph serialization.
208+
- Added regression coverage to ensure debug-setter traps do not downgrade into "Failed to write frame graph" failures.
206209
- Refreshed remaining staged-flow wording in the CDP deep dive around OOPIF discovery to describe current execution-context sync progression without stale "Need Phase 4" phrasing.
207210
- Hardened CDP command dispatch in Playwright session adapter:
208211
- `PlaywrightSessionAdapter.send()` now guards trap-prone `session.send` method reads and wraps sync send failures with sanitized/diagnostic context.

‎src/agent/tools/agent.test.ts‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,54 @@ describe("runAgentTask completion behavior", () => {
12011201
}
12021202
});
12031203

1204+
it("continues frame-graph snapshot writing when frame-manager debug setter throws", async () => {
1205+
const page = createMockPage();
1206+
const getCDPClientSpy = jest
1207+
.spyOn(cdp, "getCDPClient")
1208+
.mockResolvedValue({} as Awaited<ReturnType<typeof cdp.getCDPClient>>);
1209+
const getOrCreateFrameContextManagerSpy = jest
1210+
.spyOn(cdp, "getOrCreateFrameContextManager")
1211+
.mockReturnValue({
1212+
setDebug: () => {
1213+
throw new Error(`frame-debug\u0000\n${"x".repeat(10_000)}`);
1214+
},
1215+
toJSON: () => ({ frames: [] }),
1216+
} as unknown as ReturnType<typeof cdp.getOrCreateFrameContextManager>);
1217+
const writeSpy = jest.spyOn(fs, "writeFileSync").mockImplementation(() => {
1218+
return undefined;
1219+
});
1220+
const warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
1221+
const ctx = createRepeatedActionThenCompleteCtx(1);
1222+
ctx.debug = true;
1223+
1224+
try {
1225+
const result = await runAgentTask(ctx, createTaskState(page), {
1226+
debugDir: "debug/test",
1227+
});
1228+
expect(result.status).toBe(TaskStatus.COMPLETED);
1229+
expect(getCDPClientSpy).toHaveBeenCalled();
1230+
expect(getOrCreateFrameContextManagerSpy).toHaveBeenCalled();
1231+
const warning = String(
1232+
warnSpy.mock.calls.find((call) =>
1233+
String(call[0] ?? "").includes("Failed to configure frame graph debug mode")
1234+
)?.[0] ?? ""
1235+
);
1236+
expect(warning).toContain("[truncated");
1237+
expect(warning).not.toContain("\u0000");
1238+
expect(warning).not.toContain("\n");
1239+
expect(
1240+
warnSpy.mock.calls.some((call) =>
1241+
String(call[0] ?? "").includes("Failed to write frame graph")
1242+
)
1243+
).toBe(false);
1244+
} finally {
1245+
getCDPClientSpy.mockRestore();
1246+
getOrCreateFrameContextManagerSpy.mockRestore();
1247+
writeSpy.mockRestore();
1248+
warnSpy.mockRestore();
1249+
}
1250+
});
1251+
12041252
it("truncates oversized structured-output diagnostics", async () => {
12051253
const page = createMockPage();
12061254
const hugeRaw = "x".repeat(120_000);

‎src/agent/tools/agent.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,21 @@ const writeFrameGraphSnapshot = async (
332332
try {
333333
const cdpClient = await getCDPClient(page);
334334
const frameManager = getOrCreateFrameContextManager(cdpClient);
335-
frameManager.setDebug(debug);
335+
if (typeof frameManager.setDebug === "function") {
336+
try {
337+
frameManager.setDebug(debug);
338+
} catch (error) {
339+
if (debug) {
340+
console.warn(
341+
`[FrameContext] Failed to configure frame graph debug mode: ${formatDiagnosticText(
342+
error,
343+
MAX_RUNTIME_ACTION_MESSAGE_CHARS,
344+
"unknown error"
345+
)}`
346+
);
347+
}
348+
}
349+
}
336350
const data = frameManager.toJSON();
337351
fs.writeFileSync(`${dir}/frames.json`, safeJsonStringify(data));
338352
} catch (error) {

0 commit comments

Comments
 (0)