|
9 | 9 | from typing import TYPE_CHECKING, Any, Optional |
10 | 10 |
|
11 | 11 | from .actions import click, click_async, press, press_async, type_text, type_text_async |
| 12 | +from .agent_config import AgentConfig |
12 | 13 | from .base_agent import BaseAgent, BaseAgentAsync |
13 | 14 | from .browser import AsyncSentienceBrowser, SentienceBrowser |
14 | 15 | from .llm_provider import LLMProvider, LLMResponse |
|
25 | 26 | from .snapshot import snapshot, snapshot_async |
26 | 27 |
|
27 | 28 | if TYPE_CHECKING: |
28 | | - from .agent_config import AgentConfig |
29 | 29 | from .tracing import Tracer |
30 | 30 |
|
31 | 31 |
|
@@ -78,8 +78,9 @@ def __init__( |
78 | 78 | self.default_snapshot_limit = default_snapshot_limit |
79 | 79 | self.verbose = verbose |
80 | 80 | self.tracer = tracer |
81 | | - self.config = config |
| 81 | + self.config = config or AgentConfig() |
82 | 82 |
|
| 83 | + # Screenshot sequence counter |
83 | 84 | # Execution history |
84 | 85 | self.history: list[dict[str, Any]] = [] |
85 | 86 |
|
@@ -150,6 +151,21 @@ def act( # noqa: C901 |
150 | 151 | if snap_opts.goal is None: |
151 | 152 | snap_opts.goal = goal |
152 | 153 |
|
| 154 | + # Apply AgentConfig screenshot settings if not overridden by snapshot_options |
| 155 | + if snapshot_options is None and self.config: |
| 156 | + if self.config.capture_screenshots: |
| 157 | + # Create ScreenshotConfig from AgentConfig |
| 158 | + snap_opts.screenshot = ScreenshotConfig( |
| 159 | + format=self.config.screenshot_format, |
| 160 | + quality=( |
| 161 | + self.config.screenshot_quality |
| 162 | + if self.config.screenshot_format == "jpeg" |
| 163 | + else None |
| 164 | + ), |
| 165 | + ) |
| 166 | + else: |
| 167 | + snap_opts.screenshot = False |
| 168 | + |
153 | 169 | # Call snapshot with options object (matches TypeScript API) |
154 | 170 | snap = snapshot(self.browser, snap_opts) |
155 | 171 |
|
@@ -178,14 +194,36 @@ def act( # noqa: C901 |
178 | 194 | for el in filtered_elements[:50] # Limit to first 50 for performance |
179 | 195 | ] |
180 | 196 |
|
| 197 | + # Build snapshot event data |
| 198 | + snapshot_data = { |
| 199 | + "url": snap.url, |
| 200 | + "element_count": len(snap.elements), |
| 201 | + "timestamp": snap.timestamp, |
| 202 | + "elements": elements_data, # Add element data for overlay |
| 203 | + } |
| 204 | + |
| 205 | + # Always include screenshot in trace event for studio viewer compatibility |
| 206 | + # CloudTraceSink will extract and upload screenshots separately, then remove |
| 207 | + # screenshot_base64 from events before uploading the trace file. |
| 208 | + if snap.screenshot: |
| 209 | + # Extract base64 string from data URL if needed |
| 210 | + if snap.screenshot.startswith("data:image"): |
| 211 | + # Format: "data:image/jpeg;base64,{base64_string}" |
| 212 | + screenshot_base64 = ( |
| 213 | + snap.screenshot.split(",", 1)[1] |
| 214 | + if "," in snap.screenshot |
| 215 | + else snap.screenshot |
| 216 | + ) |
| 217 | + else: |
| 218 | + screenshot_base64 = snap.screenshot |
| 219 | + |
| 220 | + snapshot_data["screenshot_base64"] = screenshot_base64 |
| 221 | + if snap.screenshot_format: |
| 222 | + snapshot_data["screenshot_format"] = snap.screenshot_format |
| 223 | + |
181 | 224 | self.tracer.emit( |
182 | 225 | "snapshot", |
183 | | - { |
184 | | - "url": snap.url, |
185 | | - "element_count": len(snap.elements), |
186 | | - "timestamp": snap.timestamp, |
187 | | - "elements": elements_data, # Add element data for overlay |
188 | | - }, |
| 226 | + snapshot_data, |
189 | 227 | step_id=step_id, |
190 | 228 | ) |
191 | 229 |
|
@@ -721,8 +759,9 @@ def __init__( |
721 | 759 | self.default_snapshot_limit = default_snapshot_limit |
722 | 760 | self.verbose = verbose |
723 | 761 | self.tracer = tracer |
724 | | - self.config = config |
| 762 | + self.config = config or AgentConfig() |
725 | 763 |
|
| 764 | + # Screenshot sequence counter |
726 | 765 | # Execution history |
727 | 766 | self.history: list[dict[str, Any]] = [] |
728 | 767 |
|
@@ -790,6 +829,23 @@ async def act( # noqa: C901 |
790 | 829 | if snap_opts.goal is None: |
791 | 830 | snap_opts.goal = goal |
792 | 831 |
|
| 832 | + # Apply AgentConfig screenshot settings if not overridden by snapshot_options |
| 833 | + # Only apply if snapshot_options wasn't provided OR if screenshot wasn't explicitly set |
| 834 | + # (snapshot_options.screenshot defaults to False, so we check if it's still False) |
| 835 | + if self.config and (snapshot_options is None or snap_opts.screenshot is False): |
| 836 | + if self.config.capture_screenshots: |
| 837 | + # Create ScreenshotConfig from AgentConfig |
| 838 | + snap_opts.screenshot = ScreenshotConfig( |
| 839 | + format=self.config.screenshot_format, |
| 840 | + quality=( |
| 841 | + self.config.screenshot_quality |
| 842 | + if self.config.screenshot_format == "jpeg" |
| 843 | + else None |
| 844 | + ), |
| 845 | + ) |
| 846 | + else: |
| 847 | + snap_opts.screenshot = False |
| 848 | + |
793 | 849 | # Call snapshot with options object (matches TypeScript API) |
794 | 850 | snap = await snapshot_async(self.browser, snap_opts) |
795 | 851 |
|
@@ -818,14 +874,36 @@ async def act( # noqa: C901 |
818 | 874 | for el in filtered_elements[:50] # Limit to first 50 for performance |
819 | 875 | ] |
820 | 876 |
|
| 877 | + # Build snapshot event data |
| 878 | + snapshot_data = { |
| 879 | + "url": snap.url, |
| 880 | + "element_count": len(snap.elements), |
| 881 | + "timestamp": snap.timestamp, |
| 882 | + "elements": elements_data, # Add element data for overlay |
| 883 | + } |
| 884 | + |
| 885 | + # Always include screenshot in trace event for studio viewer compatibility |
| 886 | + # CloudTraceSink will extract and upload screenshots separately, then remove |
| 887 | + # screenshot_base64 from events before uploading the trace file. |
| 888 | + if snap.screenshot: |
| 889 | + # Extract base64 string from data URL if needed |
| 890 | + if snap.screenshot.startswith("data:image"): |
| 891 | + # Format: "data:image/jpeg;base64,{base64_string}" |
| 892 | + screenshot_base64 = ( |
| 893 | + snap.screenshot.split(",", 1)[1] |
| 894 | + if "," in snap.screenshot |
| 895 | + else snap.screenshot |
| 896 | + ) |
| 897 | + else: |
| 898 | + screenshot_base64 = snap.screenshot |
| 899 | + |
| 900 | + snapshot_data["screenshot_base64"] = screenshot_base64 |
| 901 | + if snap.screenshot_format: |
| 902 | + snapshot_data["screenshot_format"] = snap.screenshot_format |
| 903 | + |
821 | 904 | self.tracer.emit( |
822 | 905 | "snapshot", |
823 | | - { |
824 | | - "url": snap.url, |
825 | | - "element_count": len(snap.elements), |
826 | | - "timestamp": snap.timestamp, |
827 | | - "elements": elements_data, # Add element data for overlay |
828 | | - }, |
| 906 | + snapshot_data, |
829 | 907 | step_id=step_id, |
830 | 908 | ) |
831 | 909 |
|
|
0 commit comments