Skip to content

Fix logging #82

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jun 12, 2025
Merged
13 changes: 1 addition & 12 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ jobs:
pip install -e ".[dev]"
# Install jsonschema for schema validation tests
pip install jsonschema
# Install temporary Google GenAI wheel
pip install temp/google_genai-1.14.0-py3-none-any.whl


- name: Run unit tests
run: |
pytest tests/unit/ -v --junit-xml=junit-unit-${{ matrix.python-version }}.xml
Expand Down Expand Up @@ -74,8 +72,6 @@ jobs:
python -m pip install --upgrade pip
pip install -e ".[dev]"
pip install jsonschema
# Install temporary Google GenAI wheel
pip install temp/google_genai-1.14.0-py3-none-any.whl
# Install Playwright browsers for integration tests
playwright install chromium
playwright install-deps chromium
Expand Down Expand Up @@ -129,8 +125,6 @@ jobs:
python -m pip install --upgrade pip
pip install -e ".[dev]"
pip install jsonschema
# Install temporary Google GenAI wheel
pip install temp/google_genai-1.14.0-py3-none-any.whl

- name: Run API integration tests
run: |
Expand Down Expand Up @@ -170,7 +164,6 @@ jobs:
python -m pip install --upgrade pip
pip install -e ".[dev]"
pip install jsonschema
pip install temp/google_genai-1.14.0-py3-none-any.whl

- name: Run smoke tests
run: |
Expand Down Expand Up @@ -213,8 +206,6 @@ jobs:
python -m pip install --upgrade pip
pip install -e ".[dev]"
pip install jsonschema
# Install temporary Google GenAI wheel
pip install temp/google_genai-1.14.0-py3-none-any.whl
playwright install chromium
playwright install-deps chromium

Expand Down Expand Up @@ -261,8 +252,6 @@ jobs:
python -m pip install --upgrade pip
pip install -e ".[dev]"
pip install jsonschema
# Install temporary Google GenAI wheel
pip install temp/google_genai-1.14.0-py3-none-any.whl
playwright install chromium

- name: Run complete test suite
Expand Down
21 changes: 11 additions & 10 deletions stagehand/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"""Stagehand - The AI Browser Automation Framework"""

from .agent import Agent
from .config import StagehandConfig, default_config
from .handlers.observe_handler import ObserveHandler
from .llm import LLMClient
from .logging import LogConfig, configure_logging
from .main import Stagehand
from .metrics import StagehandFunctionName, StagehandMetrics
from .page import StagehandPage
Expand All @@ -11,36 +15,33 @@
AgentExecuteOptions,
AgentExecuteResult,
AgentProvider,
AvailableModel,
ExtractOptions,
ExtractResult,
ObserveOptions,
ObserveResult,
)
from .utils import configure_logging

__version__ = "0.0.1"

__all__ = [
"Stagehand",
"StagehandConfig",
"default_config",
"StagehandPage",
"Agent",
"configure_logging",
"AgentConfig",
"AgentExecuteOptions",
"AgentExecuteResult",
"AgentProvider",
"ActOptions",
"ActResult",
"AvailableModel",
"ExtractOptions",
"ExtractResult",
"ObserveOptions",
"ObserveResult",
"AgentConfig",
"AgentExecuteOptions",
"AgentExecuteResult",
"AgentProvider",
"ObserveHandler",
"observe",
"LLMClient",
"configure_logging",
"StagehandFunctionName",
"StagehandMetrics",
"LogConfig",
]
16 changes: 8 additions & 8 deletions stagehand/a11y/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
if TYPE_CHECKING:
from stagehand.page import StagehandPage

from ..logging import StagehandLogger
from ..types.a11y import (
AccessibilityNode,
AXNode,
CDPSession,
TreeResult,
)
from ..utils import StagehandLogger, format_simplified_tree
from ..utils import format_simplified_tree


async def _clean_structural_nodes(
Expand Down Expand Up @@ -80,16 +81,16 @@ async def _clean_structural_nodes(
node["role"] = result_value
node_role = result_value
except Exception as tag_name_error:
# Use logger.warning (level 2)
logger.warning(
# Use logger.debug (level 2)
logger.debug(
message=f"Could not fetch tagName for node {backend_node_id}",
auxiliary={
"error": {"value": str(tag_name_error), "type": "string"}
},
)
except Exception as resolve_error:
# Use logger.warning (level 2)
logger.warning(
# Use logger.debug (level 2)
logger.debug(
message=f"Could not resolve DOM node ID {backend_node_id}",
auxiliary={"error": {"value": str(resolve_error), "type": "string"}},
)
Expand Down Expand Up @@ -277,9 +278,8 @@ async def get_accessibility_tree(
try:
await page.disable_cdp_domain("Accessibility")
except Exception:
# Log if disabling fails, but don't raise further
if logger:
logger.warning("Failed to disable Accessibility domain on cleanup.")
# Use logger.debug (level 2)
logger.debug("Failed to disable Accessibility domain on cleanup.")


# JavaScript function to get XPath (remains JavaScript)
Expand Down
10 changes: 9 additions & 1 deletion stagehand/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,20 @@ def __init__(self, stagehand_client, agent_config: AgentConfig):
self._stagehand = stagehand_client
self._config = agent_config # Store the required config

if not self._stagehand._initialized:
self._stagehand.logger.error(
"Stagehand must be initialized before creating an agent. Call await stagehand.init() first."
)
raise RuntimeError(
"Stagehand must be initialized before creating an agent. Call await stagehand.init() first."
)

# Perform provider inference and validation
if self._config.model and not self._config.provider:
if self._config.model in MODEL_TO_PROVIDER_MAP:
self._config.provider = MODEL_TO_PROVIDER_MAP[self._config.model]
else:
self._stagehand.logger.warning(
self._stagehand.logger.error(
f"Could not infer provider for model: {self._config.model}"
)

Expand Down
14 changes: 7 additions & 7 deletions stagehand/agent/anthropic_cua.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ async def run_task(
break

if not agent_action and not task_completed:
self.logger.warning(
self.logger.info(
"Model did not request an action and task not marked complete. Ending task to prevent loop.",
category=StagehandFunctionName.AGENT,
)
Expand Down Expand Up @@ -290,7 +290,7 @@ def _process_provider_response(
block.model_dump() for block in response.content
]
except Exception as e:
self.logger.warning(
self.logger.error(
f"Could not model_dump response.content blocks: {e}",
category=StagehandFunctionName.AGENT,
)
Expand Down Expand Up @@ -337,7 +337,7 @@ def _convert_tool_use_to_agent_action(
and tool_name != "goto"
and tool_name != "navigate_back"
):
self.logger.warning(
self.logger.error(
f"Unsupported tool name from Anthropic: {tool_name}",
category=StagehandFunctionName.AGENT,
)
Expand Down Expand Up @@ -501,7 +501,7 @@ def _convert_tool_use_to_agent_action(
)
action_type_str = "drag" # Normalize
else:
self.logger.warning(
self.logger.error(
"Drag action missing valid start or end coordinates.",
category=StagehandFunctionName.AGENT,
)
Expand Down Expand Up @@ -559,7 +559,7 @@ def _convert_tool_use_to_agent_action(
)
action_type_str = "function"
else:
self.logger.warning(
self.logger.error(
"Goto action from Anthropic missing URL",
category=StagehandFunctionName.AGENT,
)
Expand All @@ -572,7 +572,7 @@ def _convert_tool_use_to_agent_action(
)
action_type_str = "function"
else:
self.logger.warning(
self.logger.error(
f"Unsupported action type '{action_type_str}' from Anthropic computer tool.",
category=StagehandFunctionName.AGENT,
)
Expand Down Expand Up @@ -613,7 +613,7 @@ def _format_action_feedback(
self.format_screenshot(new_screenshot_base64)
)
else:
self.logger.warning(
self.logger.error(
"Missing screenshot for computer tool feedback (empty string passed).",
category=StagehandFunctionName.AGENT,
)
Expand Down
6 changes: 3 additions & 3 deletions stagehand/agent/openai_cua.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def _process_provider_response(
)
# Ensure arguments is a dict, even if empty
if not isinstance(arguments, dict):
self.logger.warning(
self.logger.debug(
f"Function call arguments are not a dict: {arguments}. Using empty dict.",
category="agent",
)
Expand Down Expand Up @@ -464,7 +464,7 @@ async def run_task(
)

if not agent_action and not task_completed:
self.logger.warning(
self.logger.info(
"Model did not request an action and task not marked complete. Ending task to prevent loop.",
category="agent",
)
Expand All @@ -480,7 +480,7 @@ async def run_task(
usage=usage_obj,
)

self.logger.warning("Max steps reached for OpenAI CUA task.", category="agent")
self.logger.info("Max steps reached for OpenAI CUA task.", category="agent")
usage_obj = {
"input_tokens": total_input_tokens,
"output_tokens": total_output_tokens,
Expand Down
2 changes: 1 addition & 1 deletion stagehand/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
)

from .context import StagehandContext
from .logging import StagehandLogger
from .page import StagehandPage
from .utils import StagehandLogger


async def connect_browserbase_browser(
Expand Down
6 changes: 3 additions & 3 deletions stagehand/handlers/act_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ async def _act_from_observe_result(
)

if observe_result.method == "not-supported":
self.logger.warning(
self.logger.error(
message="Cannot execute ObserveResult with unsupported method",
category="act",
auxiliary={
Expand Down Expand Up @@ -229,7 +229,7 @@ async def _act_from_observe_result(
if (
not act_command
): # If both method and description were empty or resulted in an empty command
self.logger.warning(
self.logger.error(
"Self-heal attempt aborted: could not construct a valid command from ObserveResult.",
category="act",
auxiliary={
Expand Down Expand Up @@ -307,7 +307,7 @@ async def _perform_playwright_method(
elif hasattr(locator, method) and callable(getattr(locator, method)):
await fallback_locator_method(context)
else:
self.logger.warning(
self.logger.error(
message="chosen method is invalid",
category="act",
auxiliary={"method": {"value": method, "type": "string"}},
Expand Down
2 changes: 1 addition & 1 deletion stagehand/handlers/act_handler_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ async def handle_possible_page_navigation(
try:
await stagehand_page._wait_for_settled_dom(dom_settle_timeout_ms)
except Exception as e:
logger.warning(
logger.debug(
message="wait for settled DOM timeout hit",
category="action",
auxiliary={
Expand Down
8 changes: 4 additions & 4 deletions stagehand/handlers/cua_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ async def perform_action(self, action: AgentAction) -> ActionExecutionResult:
await self.page.go_back()
return {"success": True}
# Add other function calls like back, forward, reload if needed, similar to TS version
self.logger.warning(
self.logger.error(
f"Unsupported function call: {name}",
category=StagehandFunctionName.AGENT,
)
Expand Down Expand Up @@ -195,7 +195,7 @@ async def perform_action(self, action: AgentAction) -> ActionExecutionResult:
return {"success": True}

else:
self.logger.warning(
self.logger.error(
f"Unsupported action type: {action_type}",
category=StagehandFunctionName.AGENT,
)
Expand Down Expand Up @@ -236,7 +236,7 @@ async def _update_cursor_position(self, x: int, y: int) -> None:
f"window.__stagehandUpdateCursorPosition({x}, {y})"
)
except Exception as e:
self.logger.warning(
self.logger.debug(
f"Failed to call window.__stagehandUpdateCursorPosition: {e}",
category=StagehandFunctionName.AGENT,
)
Expand All @@ -246,7 +246,7 @@ async def _animate_click(self, x: int, y: int) -> None:
try:
await self.page.evaluate(f"window.__stagehandAnimateClick({x}, {y})")
except Exception as e:
self.logger.warning(
self.logger.debug(
f"Failed to call window.__stagehandAnimateClick: {e}",
category=StagehandFunctionName.AGENT,
)
Expand Down
Loading
Loading