Skip to content

Commit 3f09c3e

Browse files
authored
Merge pull request #95 from SentienceAPI/screenshot2_embedded
upload screenshots along with traces
2 parents b065781 + dab939e commit 3f09c3e

File tree

4 files changed

+220
-181
lines changed

4 files changed

+220
-181
lines changed

sentience/agent.py

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ def __init__(
8181
self.config = config or AgentConfig()
8282

8383
# Screenshot sequence counter
84-
self._screenshot_sequence = 0
85-
8684
# Execution history
8785
self.history: list[dict[str, Any]] = []
8886

@@ -174,21 +172,6 @@ def act( # noqa: C901
174172
if snap.status != "success":
175173
raise RuntimeError(f"Snapshot failed: {snap.error}")
176174

177-
# Store screenshot if captured
178-
if snap.screenshot and self.tracer:
179-
self._screenshot_sequence += 1
180-
seq = self._screenshot_sequence
181-
182-
# Store screenshot in CloudTraceSink if available
183-
if hasattr(self.tracer.sink, "store_screenshot"):
184-
self.tracer.sink.store_screenshot(
185-
sequence=seq,
186-
screenshot_data=snap.screenshot,
187-
format=snap.screenshot_format
188-
or (self.config.screenshot_format if self.config else "jpeg"),
189-
step_id=step_id,
190-
)
191-
192175
# Apply element filtering based on goal
193176
filtered_elements = self.filter_elements(snap, goal)
194177

@@ -211,14 +194,36 @@ def act( # noqa: C901
211194
for el in filtered_elements[:50] # Limit to first 50 for performance
212195
]
213196

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+
214224
self.tracer.emit(
215225
"snapshot",
216-
{
217-
"url": snap.url,
218-
"element_count": len(snap.elements),
219-
"timestamp": snap.timestamp,
220-
"elements": elements_data, # Add element data for overlay
221-
},
226+
snapshot_data,
222227
step_id=step_id,
223228
)
224229

@@ -757,8 +762,6 @@ def __init__(
757762
self.config = config or AgentConfig()
758763

759764
# Screenshot sequence counter
760-
self._screenshot_sequence = 0
761-
762765
# Execution history
763766
self.history: list[dict[str, Any]] = []
764767

@@ -847,21 +850,6 @@ async def act( # noqa: C901
847850
if snap.status != "success":
848851
raise RuntimeError(f"Snapshot failed: {snap.error}")
849852

850-
# Store screenshot if captured
851-
if snap.screenshot and self.tracer:
852-
self._screenshot_sequence += 1
853-
seq = self._screenshot_sequence
854-
855-
# Store screenshot in CloudTraceSink if available
856-
if hasattr(self.tracer.sink, "store_screenshot"):
857-
self.tracer.sink.store_screenshot(
858-
sequence=seq,
859-
screenshot_data=snap.screenshot,
860-
format=snap.screenshot_format
861-
or (self.config.screenshot_format if self.config else "jpeg"),
862-
step_id=step_id,
863-
)
864-
865853
# Apply element filtering based on goal
866854
filtered_elements = self.filter_elements(snap, goal)
867855

@@ -884,14 +872,36 @@ async def act( # noqa: C901
884872
for el in filtered_elements[:50] # Limit to first 50 for performance
885873
]
886874

875+
# Build snapshot event data
876+
snapshot_data = {
877+
"url": snap.url,
878+
"element_count": len(snap.elements),
879+
"timestamp": snap.timestamp,
880+
"elements": elements_data, # Add element data for overlay
881+
}
882+
883+
# Always include screenshot in trace event for studio viewer compatibility
884+
# CloudTraceSink will extract and upload screenshots separately, then remove
885+
# screenshot_base64 from events before uploading the trace file.
886+
if snap.screenshot:
887+
# Extract base64 string from data URL if needed
888+
if snap.screenshot.startswith("data:image"):
889+
# Format: "data:image/jpeg;base64,{base64_string}"
890+
screenshot_base64 = (
891+
snap.screenshot.split(",", 1)[1]
892+
if "," in snap.screenshot
893+
else snap.screenshot
894+
)
895+
else:
896+
screenshot_base64 = snap.screenshot
897+
898+
snapshot_data["screenshot_base64"] = screenshot_base64
899+
if snap.screenshot_format:
900+
snapshot_data["screenshot_format"] = snap.screenshot_format
901+
887902
self.tracer.emit(
888903
"snapshot",
889-
{
890-
"url": snap.url,
891-
"element_count": len(snap.elements),
892-
"timestamp": snap.timestamp,
893-
"elements": elements_data, # Add element data for overlay
894-
},
904+
snapshot_data,
895905
step_id=step_id,
896906
)
897907

0 commit comments

Comments
 (0)