From 56757e376d7948c72d88aed5ff979ad401fe28ca Mon Sep 17 00:00:00 2001 From: Sean McGuire Date: Mon, 22 Dec 2025 16:37:14 -0800 Subject: [PATCH 1/5] Strip caller field from Anthropic tool_use blocks --- stagehand/agent/anthropic_cua.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/stagehand/agent/anthropic_cua.py b/stagehand/agent/anthropic_cua.py index df6c7a2..664edf0 100644 --- a/stagehand/agent/anthropic_cua.py +++ b/stagehand/agent/anthropic_cua.py @@ -295,9 +295,13 @@ def _process_provider_response( if hasattr(response, "content") and isinstance(response.content, list): # Serialize Pydantic models from response.content for history try: - raw_assistant_content_blocks = [ - block.model_dump() for block in response.content - ] + for block in response.content: + block_dict = block.model_dump() + if isinstance(block_dict, dict): + # Anthropic beta responses include a `caller` field on tool_use blocks + # but the API rejects that key on subsequent requests. + block_dict.pop("caller", None) + raw_assistant_content_blocks.append(block_dict) except Exception as e: self.logger.error( f"Could not model_dump response.content blocks: {e}", From 324530eaedeb570c72ae68e53acfe96fdf802271 Mon Sep 17 00:00:00 2001 From: Sean McGuire Date: Mon, 22 Dec 2025 17:24:52 -0800 Subject: [PATCH 2/5] changeset --- .changeset/certain-nice-caracara.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/certain-nice-caracara.md diff --git a/.changeset/certain-nice-caracara.md b/.changeset/certain-nice-caracara.md new file mode 100644 index 0000000..9ffabdb --- /dev/null +++ b/.changeset/certain-nice-caracara.md @@ -0,0 +1,5 @@ +--- +"stagehand": patch +--- + +fix: invalid_request_error when using anthropic cua client From b390a4b80914b84e876eb2aa736d58e8a7d4020d Mon Sep 17 00:00:00 2001 From: Sean McGuire Date: Mon, 22 Dec 2025 17:29:35 -0800 Subject: [PATCH 3/5] formatting --- examples/agent_example_local.py | 54 ++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/examples/agent_example_local.py b/examples/agent_example_local.py index 5d160f5..40145d4 100644 --- a/examples/agent_example_local.py +++ b/examples/agent_example_local.py @@ -26,12 +26,34 @@ load_dotenv() +ANTHROPIC_MODEL = "claude-sonnet-4-20250514" +REPRO_INSTRUCTION = ( + "Step 1: Use the goto tool to open https://example.com/.\n" + "Step 2: After it loads, scroll down and click the 'More information...' link " + "to open the iana.org page, then report the heading text you see." +) +ERROR_SIGNATURES = [ + "messages.1.content.1.tool_use.caller", + "Extra inputs are not permitted", +] + # Configure logging with the utility function configure_logging( level=logging.INFO, # Set to INFO for regular logs, DEBUG for detailed quiet_dependencies=True, # Reduce noise from dependencies ) + +def require_env_var(var_name: str) -> str: + """Fetch a required env var with a helpful error for local runs.""" + value = os.getenv(var_name) + if not value: + raise RuntimeError( + f"{var_name} is not set. Add it to your .env before running this example." + ) + return value + + async def main(): # Build a unified configuration object for Stagehand config = StagehandConfig( @@ -53,19 +75,37 @@ async def main(): await stagehand.page.goto("https://google.com/") console.print("✅ [success]Navigated to Google[/]") - console.print("\n▶️ [highlight] Using Agent to perform a task[/]: playing a game of 2048") + console.print( + "\n▶️ [highlight]Using Anthropic CUA agent[/]: reproducing the tool_use caller bug" + ) + anthropic_api_key = require_env_var("ANTHROPIC_API_KEY") agent = stagehand.agent( - model="gemini-2.5-computer-use-preview-10-2025", - instructions="You are a helpful web navigation assistant that helps users find information. You are currently on the following page: google.com. Do not ask follow up questions, the user will trust your judgement.", - options={"apiKey": os.getenv("GEMINI_API_KEY")} + model=ANTHROPIC_MODEL, + instructions=( + "You are controlling a fullscreen local browser with the Anthropic computer-use tools. " + "Read the current page carefully, decide on your next action, and avoid asking follow-up questions." + ), + options={"apiKey": anthropic_api_key} ) agent_result = await agent.execute( - instruction="Play a game of 2048", - max_steps=20, + instruction=REPRO_INSTRUCTION, + max_steps=5, auto_screenshot=True, ) console.print(agent_result) + if agent_result.message and any( + signature in agent_result.message for signature in ERROR_SIGNATURES + ): + console.print( + "🐛 [error]Reproduced the Anthropic `tool_use.caller` validation error.[/]\n" + " Check the logs above for 'Extra inputs are not permitted' to link back to the GitHub issue." + ) + else: + console.print( + "⚠️ [warning]Bug signature not detected in this run. " + "Re-run the example or tweak the instructions if you need the failing payload." + ) console.print("📊 [info]Agent execution result:[/]") console.print(f"🎯 Completed: [bold]{'Yes' if agent_result.completed else 'No'}[/]") @@ -100,4 +140,4 @@ async def main(): padding=(1, 10), ), ) - asyncio.run(main()) \ No newline at end of file + asyncio.run(main()) From f09bab542bb1b6aac51316927bdb8b69e3329101 Mon Sep 17 00:00:00 2001 From: Sean McGuire Date: Mon, 22 Dec 2025 17:40:33 -0800 Subject: [PATCH 4/5] revert changes to agent_example_local.py --- examples/agent_example_local.py | 54 +++++---------------------------- 1 file changed, 7 insertions(+), 47 deletions(-) diff --git a/examples/agent_example_local.py b/examples/agent_example_local.py index 40145d4..5d160f5 100644 --- a/examples/agent_example_local.py +++ b/examples/agent_example_local.py @@ -26,34 +26,12 @@ load_dotenv() -ANTHROPIC_MODEL = "claude-sonnet-4-20250514" -REPRO_INSTRUCTION = ( - "Step 1: Use the goto tool to open https://example.com/.\n" - "Step 2: After it loads, scroll down and click the 'More information...' link " - "to open the iana.org page, then report the heading text you see." -) -ERROR_SIGNATURES = [ - "messages.1.content.1.tool_use.caller", - "Extra inputs are not permitted", -] - # Configure logging with the utility function configure_logging( level=logging.INFO, # Set to INFO for regular logs, DEBUG for detailed quiet_dependencies=True, # Reduce noise from dependencies ) - -def require_env_var(var_name: str) -> str: - """Fetch a required env var with a helpful error for local runs.""" - value = os.getenv(var_name) - if not value: - raise RuntimeError( - f"{var_name} is not set. Add it to your .env before running this example." - ) - return value - - async def main(): # Build a unified configuration object for Stagehand config = StagehandConfig( @@ -75,37 +53,19 @@ async def main(): await stagehand.page.goto("https://google.com/") console.print("✅ [success]Navigated to Google[/]") - console.print( - "\n▶️ [highlight]Using Anthropic CUA agent[/]: reproducing the tool_use caller bug" - ) - anthropic_api_key = require_env_var("ANTHROPIC_API_KEY") + console.print("\n▶️ [highlight] Using Agent to perform a task[/]: playing a game of 2048") agent = stagehand.agent( - model=ANTHROPIC_MODEL, - instructions=( - "You are controlling a fullscreen local browser with the Anthropic computer-use tools. " - "Read the current page carefully, decide on your next action, and avoid asking follow-up questions." - ), - options={"apiKey": anthropic_api_key} + model="gemini-2.5-computer-use-preview-10-2025", + instructions="You are a helpful web navigation assistant that helps users find information. You are currently on the following page: google.com. Do not ask follow up questions, the user will trust your judgement.", + options={"apiKey": os.getenv("GEMINI_API_KEY")} ) agent_result = await agent.execute( - instruction=REPRO_INSTRUCTION, - max_steps=5, + instruction="Play a game of 2048", + max_steps=20, auto_screenshot=True, ) console.print(agent_result) - if agent_result.message and any( - signature in agent_result.message for signature in ERROR_SIGNATURES - ): - console.print( - "🐛 [error]Reproduced the Anthropic `tool_use.caller` validation error.[/]\n" - " Check the logs above for 'Extra inputs are not permitted' to link back to the GitHub issue." - ) - else: - console.print( - "⚠️ [warning]Bug signature not detected in this run. " - "Re-run the example or tweak the instructions if you need the failing payload." - ) console.print("📊 [info]Agent execution result:[/]") console.print(f"🎯 Completed: [bold]{'Yes' if agent_result.completed else 'No'}[/]") @@ -140,4 +100,4 @@ async def main(): padding=(1, 10), ), ) - asyncio.run(main()) + asyncio.run(main()) \ No newline at end of file From cfcca94f98608e0daa1dd62baa29a59dea381a98 Mon Sep 17 00:00:00 2001 From: Sean McGuire Date: Mon, 22 Dec 2025 17:48:38 -0800 Subject: [PATCH 5/5] formatting --- stagehand/context.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stagehand/context.py b/stagehand/context.py index cd4b13c..27ee327 100644 --- a/stagehand/context.py +++ b/stagehand/context.py @@ -147,6 +147,7 @@ async def _handle_page_close(self, closing_page: StagehandPage): Uses the page switch lock to prevent race conditions with ongoing operations. """ try: + async def handle_with_lock(): async with self.stagehand._page_switch_lock: if self.active_stagehand_page is not closing_page: