Skip to content

Commit 517e3f6

Browse files
authored
Merge pull request #101 from SentienceAPI/missing_fields2
trace should include snapshot elements; more fixes to seq_num, etc
2 parents 8a513d4 + 13dc4c6 commit 517e3f6

File tree

6 files changed

+54
-43
lines changed

6 files changed

+54
-43
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "sentienceapi"
7-
version = "0.91.0"
7+
version = "0.91.1"
88
description = "Python SDK for Sentience AI Agent Browser Automation"
99
readme = "README.md"
1010
requires-python = ">=3.11"

sentience/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
)
7171
from .wait import wait_for
7272

73-
__version__ = "0.91.0"
73+
__version__ = "0.91.1"
7474

7575
__all__ = [
7676
# Core SDK

sentience/agent.py

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -198,29 +198,16 @@ def act( # noqa: C901
198198

199199
# Emit snapshot trace event if tracer is enabled
200200
if self.tracer:
201-
# Include element data for live overlay visualization
202-
# Use filtered_elements for overlay (only relevant elements)
203-
elements_data = [
204-
{
205-
"id": el.id,
206-
"bbox": {
207-
"x": el.bbox.x,
208-
"y": el.bbox.y,
209-
"width": el.bbox.width,
210-
"height": el.bbox.height,
211-
},
212-
"role": el.role,
213-
"text": el.text[:50] if el.text else "", # Truncate for brevity
214-
}
215-
for el in filtered_elements[:50] # Limit to first 50 for performance
216-
]
201+
# Include ALL elements with full data for DOM tree display
202+
# Use snap.elements (all elements) not filtered_elements
203+
elements_data = [el.model_dump() for el in snap.elements]
217204

218205
# Build snapshot event data
219206
snapshot_data = {
220207
"url": snap.url,
221208
"element_count": len(snap.elements),
222209
"timestamp": snap.timestamp,
223-
"elements": elements_data, # Add element data for overlay
210+
"elements": elements_data, # Full element data for DOM tree
224211
}
225212

226213
# Always include screenshot in trace event for studio viewer compatibility
@@ -983,29 +970,16 @@ async def act( # noqa: C901
983970

984971
# Emit snapshot trace event if tracer is enabled
985972
if self.tracer:
986-
# Include element data for live overlay visualization
987-
# Use filtered_elements for overlay (only relevant elements)
988-
elements_data = [
989-
{
990-
"id": el.id,
991-
"bbox": {
992-
"x": el.bbox.x,
993-
"y": el.bbox.y,
994-
"width": el.bbox.width,
995-
"height": el.bbox.height,
996-
},
997-
"role": el.role,
998-
"text": el.text[:50] if el.text else "", # Truncate for brevity
999-
}
1000-
for el in filtered_elements[:50] # Limit to first 50 for performance
1001-
]
973+
# Include ALL elements with full data for DOM tree display
974+
# Use snap.elements (all elements) not filtered_elements
975+
elements_data = [el.model_dump() for el in snap.elements]
1002976

1003977
# Build snapshot event data
1004978
snapshot_data = {
1005979
"url": snap.url,
1006980
"element_count": len(snap.elements),
1007981
"timestamp": snap.timestamp,
1008-
"elements": elements_data, # Add element data for overlay
982+
"elements": elements_data, # Full element data for DOM tree
1009983
}
1010984

1011985
# Always include screenshot in trace event for studio viewer compatibility

sentience/cloud_tracing.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,10 @@ def _generate_index(self) -> None:
270270
try:
271271
from .trace_indexing import write_trace_index
272272

273-
write_trace_index(str(self._path))
273+
# Use frontend format to ensure 'step' field is present (1-based)
274+
# Frontend derives sequence from step.step - 1, so step must be valid
275+
index_path = Path(str(self._path).replace(".jsonl", ".index.json"))
276+
write_trace_index(str(self._path), str(index_path), frontend_format=True)
274277
except Exception as e:
275278
# Non-fatal: log but don't crash
276279
print(f"⚠️ Failed to generate trace index: {e}")
@@ -322,10 +325,28 @@ def _upload_index(self) -> None:
322325
self.logger.warning("No upload URL in index upload response")
323326
return
324327

325-
# Read and compress index file
326-
with open(index_path, "rb") as f:
327-
index_data = f.read()
328+
# Read index file and update trace_file.path to cloud storage path
329+
with open(index_path, encoding="utf-8") as f:
330+
index_json = json.load(f)
328331

332+
# Extract cloud storage path from trace upload URL
333+
# upload_url format: https://...digitaloceanspaces.com/traces/{run_id}.jsonl.gz
334+
# Extract path: traces/{run_id}.jsonl.gz
335+
try:
336+
from urllib.parse import urlparse
337+
338+
parsed_url = urlparse(self.upload_url)
339+
# Extract path after domain (e.g., /traces/run-123.jsonl.gz -> traces/run-123.jsonl.gz)
340+
cloud_trace_path = parsed_url.path.lstrip("/")
341+
# Update trace_file.path in index
342+
if "trace_file" in index_json and isinstance(index_json["trace_file"], dict):
343+
index_json["trace_file"]["path"] = cloud_trace_path
344+
except Exception as e:
345+
if self.logger:
346+
self.logger.warning(f"Failed to extract cloud path from upload URL: {e}")
347+
348+
# Serialize updated index to JSON
349+
index_data = json.dumps(index_json, indent=2).encode("utf-8")
329350
compressed_index = gzip.compress(index_data)
330351
index_size = len(compressed_index)
331352
self.index_file_size_bytes = index_size # Track index file size

sentience/trace_indexing/indexer.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,26 @@ def _compute_snapshot_digest(snapshot_data: dict[str, Any]) -> str:
5858
# Canonicalize elements
5959
canonical_elements = []
6060
for elem in elements:
61+
# Extract is_primary and is_clickable from visual_cues if present
62+
visual_cues = elem.get("visual_cues", {})
63+
is_primary = (
64+
visual_cues.get("is_primary", False)
65+
if isinstance(visual_cues, dict)
66+
else elem.get("is_primary", False)
67+
)
68+
is_clickable = (
69+
visual_cues.get("is_clickable", False)
70+
if isinstance(visual_cues, dict)
71+
else elem.get("is_clickable", False)
72+
)
73+
6174
canonical_elem = {
6275
"id": elem.get("id"),
6376
"role": elem.get("role", ""),
6477
"text_norm": _normalize_text(elem.get("text")),
6578
"bbox": _round_bbox(elem.get("bbox", {"x": 0, "y": 0, "width": 0, "height": 0})),
66-
"is_primary": elem.get("is_primary", False),
67-
"is_clickable": elem.get("is_clickable", False),
79+
"is_primary": is_primary,
80+
"is_clickable": is_clickable,
6881
}
6982
canonical_elements.append(canonical_elem)
7083

sentience/tracing.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,10 @@ def _generate_index(self) -> None:
230230
try:
231231
from .trace_indexing import write_trace_index
232232

233-
write_trace_index(str(self.path))
233+
# Use frontend format to ensure 'step' field is present (1-based)
234+
# Frontend derives sequence from step.step - 1, so step must be valid
235+
index_path = Path(self.path).with_suffix(".index.json")
236+
write_trace_index(str(self.path), str(index_path), frontend_format=True)
234237
except Exception as e:
235238
# Non-fatal: log but don't crash
236239
print(f"⚠️ Failed to generate trace index: {e}")

0 commit comments

Comments
 (0)