You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Mirrored from external contributor PR browserbase#1978 after approval by @pirate.
Original author: @a7med3liamin
Original PR: browserbase#1978
Approved source head SHA: `2149aa265a04dc37154d5a84411f3ab4d1045897`
@a7med3liamin, please continue any follow-up discussion on this mirrored
PR. When the external PR gets new commits, this same internal PR will be
marked stale until the latest external commit is approved and refreshed
here.
## Original description
- [x] Check the [documentation](https://docs.stagehand.dev/) for
relevant information
- [x] Search existing
[issues](https://github.com/browserbase/stagehand/issues) to avoid
duplicates
Fixesbrowserbase#1776
## Problem
The `keys` tool has no variable substitution in either the live
execution or cache replay paths. When the agent uses `%variableName%`
tokens with the keys tool, the literal token string gets typed instead
of the resolved value.
## Fix
This PR combines two fixes into one:
### 1. Live execution (original fix by @trillville from browserbase#1777)
- Accept `variables` parameter in `keysTool` (matching `typeTool`)
- Call `substituteVariables()` before `page.type()` in the `method ===
"type"` branch
- Pass `variables` to `keysTool` in `createAgentTools`
- Update schema description to advertise available variables to the LLM
- Return original token in result to avoid exposing sensitive values to
LLM
### 2. Cache replay (new fix)
- Import `substituteVariables` in `AgentCache.ts`
- Pass `variables` through to `replayAgentKeysStep`
- Call `substituteVariables(text, variables)` before `page.type()` in
the replay path
Without fix#2, cached `keys` steps with `method="type"` replay by
typing literal `%variableName%` tokens even when variables are provided,
since `replayAgentKeysStep` had no access to the variables map.
## Credit
The live execution fix (part 1) is from @trillville's work in
browserbase#1777/browserbase#1813. We merged it here with the cache replay fix per @pirate's
request to consolidate into a single PR.
<!-- external-contributor-pr:owned source-pr=1978
source-sha=2149aa265a04dc37154d5a84411f3ab4d1045897 claimer=pirate -->
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Add variable substitution to the `keys` tool for both live execution and
cache replay so `%variableName%` tokens are resolved before typing. This
fixes cases where literal tokens were typed and brings parity with the
`type` tool.
- **Bug Fixes**
- Pass `variables` into `keys` and call `substituteVariables()` before
`page.type()`; update the input schema to list available variables.
- In cache replay, forward `variables` to `replayAgentKeysStep` and
substitute before typing to avoid replaying literal tokens.
- Record and return the original tokenized value (not the resolved
value) to avoid leaking sensitive data.
<sup>Written for commit abb3905.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browserbase/stagehand/pull/1983">Review in
cubic</a></sup>
<!-- End of auto-generated description by cubic. -->
---------
Co-authored-by: Ahmed Ali <a7med3liamin@gmail.com>
Co-authored-by: trillville <trillville@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Nick Sweeting <git@sweeting.me>
Add variable substitution to the keys tool in both live execution and cache replay paths. When keys steps with `method="type"` contain `%variableName%` tokens, they are now resolved against the provided variables. This brings the keys tool to parity with the type tool's variable handling.
? `The text to type, or the key/combo to press (Enter, Tab, Cmd+A). Use %variableName% to substitute a variable value. Available: ${Object.keys(variables).join(", ")}`
11
+
: "The text to type, or the key/combo to press (Enter, Tab, Cmd+A)";
12
+
13
+
returntool({
7
14
description: `Send keyboard input to the page without targeting a specific element. Unlike the type tool which clicks then types into coordinates, this sends keystrokes directly to wherever focus currently is.
8
15
9
16
Use method="type" to enter text into the currently focused element. Preferred when: input is already focused, text needs to flow across multiple fields (e.g., verification codes)
10
17
11
18
Use method="press" for navigation keys (Enter, Tab, Escape, Backspace, arrows) and keyboard shortcuts (Cmd+A, Ctrl+C, Shift+Tab).`,
12
19
inputSchema: z.object({
13
20
method: z.enum(["press","type"]),
14
-
value: z
15
-
.string()
16
-
.describe(
17
-
"The text to type, or the key/combo to press (Enter, Tab, Cmd+A)",
18
-
),
21
+
value: z.string().describe(valueDescription),
19
22
repeat: z.number().optional(),
20
23
}),
21
24
execute: async({ method, value, repeat })=>{
@@ -36,14 +39,17 @@ Use method="press" for navigation keys (Enter, Tab, Escape, Backspace, arrows) a
36
39
consttimes=Math.max(1,repeat??1);
37
40
38
41
if(method==="type"){
42
+
// Substitute any %variableName% tokens in the value
0 commit comments