feat(cache): add custom tool caching and fix replay navigation timing#1562
feat(cache): add custom tool caching and fix replay navigation timing#1562hoverlover wants to merge 3 commits intobrowserbase:mainfrom
Conversation
This commit adds two improvements to the agent cache replay system: 1. Custom Tool Caching (fixes browserbase#1558) - Add AgentReplayCustomToolStep type for caching custom tool invocations - Wrap custom tools with recording logic via wrapToolsForRecording() - Record custom tool calls in both AISDK (hybrid) and CUA agent modes - Replay custom tools by re-executing with cached arguments - Thread tools parameter through tryReplay and related methods 2. Navigation Waiting (fixes browserbase#1561) - Detect URL changes after actions during replay - Wait for page load (waitForLoadState) before continuing to next step - Apply to replayAgentActStep, replayAgentFillFormStep, replayAgentKeysStep - Prevents race conditions where steps execute before navigation completes These changes enable reliable cache replay for workflows that include: - Custom form-filling tools (fillUsername, fillPassword, etc.) - Multi-page navigation sequences - Form submissions via Enter key Co-Authored-By: Claude <noreply@anthropic.com>
|
Greptile SummaryThis PR extends agent cache replay to support custom tools and fixes navigation timing issues during replay. The implementation wraps custom tools to record their invocations and detects URL changes to wait for page load completion. Key Changes:
Critical Issue Found:
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant V3
participant AgentCache
participant Handler
participant CustomTool
participant Page
User->>V3: agent({ tools, cacheDir })
V3->>V3: wrapToolsForRecording(tools)
Note over V3: Wraps tools to record invocations
alt Cache Hit
V3->>AgentCache: tryReplay(cacheContext, tools)
AgentCache->>AgentCache: Load cached steps
loop For each cached step
alt Custom Tool Step
AgentCache->>CustomTool: execute(cached args)
CustomTool-->>AgentCache: result
else Navigation Action
AgentCache->>Page: takeDeterministicAction()
Page-->>AgentCache: action result
AgentCache->>AgentCache: Check URL change
alt URL Changed
AgentCache->>Page: waitForLoadState("load", 10000)
Page-->>AgentCache: load complete
end
end
end
AgentCache-->>V3: cached result
V3-->>User: result
else Cache Miss
V3->>V3: beginAgentReplayRecording()
V3->>Handler: execute/stream(wrappedTools)
loop Agent execution
Handler->>CustomTool: execute(args)
Note over CustomTool: Wrapped tool records invocation
CustomTool->>V3: recordAgentReplayStep({ type: "custom_tool" })
CustomTool-->>Handler: tool result
Handler->>Page: perform actions
Page-->>Handler: action results
end
Handler-->>V3: final result
V3->>V3: endAgentReplayRecording()
V3->>AgentCache: store(steps, result)
V3-->>User: result
end
|
| const replayed = await this.agentCache.tryReplay( | ||
| cacheContext, | ||
| undefined, | ||
| tools, |
There was a problem hiding this comment.
logic: passing unwrapped tools instead of wrappedTools here - replay will execute the original tools without recording wrappers, causing double-recording if cache miss falls through to re-execution
| tools, | |
| tools: wrappedTools, |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/lib/v3/v3.ts
Line: 1856:1856
Comment:
**logic:** passing unwrapped `tools` instead of `wrappedTools` here - replay will execute the original tools without recording wrappers, causing double-recording if cache miss falls through to re-execution
```suggestion
tools: wrappedTools,
```
How can I resolve this? If you propose a fix, please make it concise.| const replayed = await this.agentCache.tryReplayAsStream( | ||
| cacheContext, | ||
| llmClient, | ||
| tools, |
There was a problem hiding this comment.
logic: passing unwrapped tools instead of wrappedTools - same issue in streaming mode
| tools, | |
| tools: wrappedTools, |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/lib/v3/v3.ts
Line: 1944:1944
Comment:
**logic:** passing unwrapped `tools` instead of `wrappedTools` - same issue in streaming mode
```suggestion
tools: wrappedTools,
```
How can I resolve this? If you propose a fix, please make it concise.| const replayed = await this.agentCache.tryReplay( | ||
| cacheContext, | ||
| llmClient, |
There was a problem hiding this comment.
logic: passing unwrapped tools instead of wrappedTools - same issue in non-streaming mode (second agent handler path)
| const replayed = await this.agentCache.tryReplay( | |
| cacheContext, | |
| llmClient, | |
| const replayed = await this.agentCache.tryReplay( | |
| cacheContext, | |
| llmClient, | |
| wrappedTools, |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/lib/v3/v3.ts
Line: 1989:1991
Comment:
**logic:** passing unwrapped `tools` instead of `wrappedTools` - same issue in non-streaming mode (second agent handler path)
```suggestion
const replayed = await this.agentCache.tryReplay(
cacheContext,
llmClient,
wrappedTools,
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
1 issue found across 4 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/core/lib/v3/v3.ts">
<violation number="1" location="packages/core/lib/v3/v3.ts:1955">
P2: Recording is started before stream creation without error handling; exceptions leave cache stuck in recording state</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
If handler.stream() throws after beginAgentReplayRecording() is called, the recording state was never cleaned up, leaving the cache stuck in recording mode. Added try-catch around stream creation to call discardAgentReplayRecording() on error, matching the error handling in non-streaming mode. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Clarifies why unwrapped tools (not wrappedTools) are passed to tryReplay(). During replay, tools execute with cached arguments - using wrappedTools would cause the recording wrapper to record these replayed calls, leading to duplicate cache entries. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Response to Review CommentsRe: Using
|
Summary
This PR adds two improvements to the agent cache replay system:
1. Custom Tool Caching (fixes #1558)
Custom tools (like form-filling helpers) were not being recorded or replayed from cache, causing workflows to fail on cache replay.
Changes:
AgentReplayCustomToolSteptype for caching custom tool invocationswrapToolsForRecording()toolsparameter throughtryReplayand related methods2. Navigation Waiting (fixes #1561)
Cache replay was executing steps too fast without waiting for page navigation to complete, causing subsequent steps to run on the wrong page.
Changes:
waitForLoadState) before continuing to next stepreplayAgentActStep,replayAgentFillFormStep,replayAgentKeysStepTest Plan
Tested with a real-world workflow:
fillUsernameandfillPasswordtoolsfillSearchtoolFiles Changed
packages/core/lib/v3/types/private/cache.ts- AddAgentReplayCustomToolSteptypepackages/core/lib/v3/v3.ts- AddwrapToolsForRecording(), update tool threadingpackages/core/lib/v3/handlers/v3CuaAgentHandler.ts- Add custom tool recording for CUA modepackages/core/lib/v3/cache/AgentCache.ts- Add custom tool replay, add navigation waitingSummary by cubic
Add custom tool caching to agent replay and wait for navigation between steps. This fixes tool-based workflows and prevents steps from running on the wrong page.
New Features
Bug Fixes
Written for commit 36d3274. Summary will update on new commits.