@@ -31,13 +31,20 @@ Use `AgentRuntime` to add Jest-style assertions to your agent loops. Verify brow
3131``` python
3232import asyncio
3333from sentience import AsyncSentienceBrowser, AgentRuntime
34- from sentience.verification import url_contains, exists, all_of
34+ from sentience.verification import (
35+ url_contains,
36+ exists,
37+ all_of,
38+ is_enabled,
39+ is_checked,
40+ value_equals,
41+ )
3542from sentience.tracing import Tracer, JsonlTraceSink
3643
3744async def main ():
3845 # Create tracer
3946 tracer = Tracer(run_id = " my-run" , sink = JsonlTraceSink(" trace.jsonl" ))
40-
47+
4148 # Create browser and runtime
4249 async with AsyncSentienceBrowser() as browser:
4350 page = await browser.new_page()
@@ -46,30 +53,43 @@ async def main():
4653 page = page,
4754 tracer = tracer
4855 )
49-
56+
5057 # Navigate and take snapshot
5158 await page.goto(" https://example.com" )
5259 runtime.begin_step(" Verify page loaded" )
5360 await runtime.snapshot()
54-
55- # Run assertions (Jest-style)
61+
62+ # v1: deterministic assertions (Jest-style)
5663 runtime.assert_(url_contains(" example.com" ), label = " on_correct_domain" )
5764 runtime.assert_(exists(" role=heading" ), label = " has_heading" )
5865 runtime.assert_(all_of([
5966 exists(" role=button" ),
6067 exists(" role=link" )
6168 ]), label = " has_interactive_elements" )
62-
69+
70+ # v1: state-aware assertions (when Gateway refinement is enabled)
71+ runtime.assert_(is_enabled(" role=button" ), label = " button_enabled" )
72+ runtime.assert_(is_checked(" role=checkbox name~'subscribe'" ), label = " subscribe_checked_if_present" )
73+ runtime.assert_(value_equals(" role=textbox name~'email'" , " user@example.com" ), label = " email_value_if_present" )
74+
75+ # v2: retry loop with snapshot confidence gating + exhaustion
76+ ok = await runtime.check(
77+ exists(" role=heading" ),
78+ label = " heading_eventually_visible" ,
79+ required = True ,
80+ ).eventually(timeout_s = 10.0 , poll_s = 0.25 , min_confidence = 0.7 , max_snapshot_attempts = 3 )
81+ print (" eventually() result:" , ok)
82+
6383 # Check task completion
6484 if runtime.assert_done(exists(" text~'Example'" ), label = " task_complete" ):
6585 print (" ✅ Task completed!" )
66-
86+
6787 print (f " Task done: { runtime.is_task_done} " )
6888
6989asyncio.run(main())
7090```
7191
72- ** See example :** [ ` examples/agent_runtime_verification.py ` ] ( examples/agent_runtime_verification.py )
92+ ** See examples :** [ ` examples/asserts/ ` ] ( examples/asserts/ )
7393
7494## 🚀 Quick Start: Choose Your Abstraction Level
7595
@@ -183,56 +203,35 @@ scroll_to(browser, button.id, behavior='instant', block='start')
183203---
184204
185205<details >
186- <summary ><h2 >💼 Real-World Example: Amazon Shopping Bot </h2 ></summary >
206+ <summary ><h2 >💼 Real-World Example: Assertion-driven navigation </h2 ></summary >
187207
188- This example demonstrates navigating Amazon, finding products, and adding items to cart :
208+ This example shows how to use ** assertions + ` .eventually() ` ** to make an agent loop resilient :
189209
190210``` python
191- from sentience import SentienceBrowser, snapshot, find, click
192- import time
193-
194- with SentienceBrowser(headless = False ) as browser:
195- # Navigate to Amazon Best Sellers
196- browser.goto(" https://www.amazon.com/gp/bestsellers/" , wait_until = " domcontentloaded" )
197- time.sleep(2 ) # Wait for dynamic content
198-
199- # Take snapshot and find products
200- snap = snapshot(browser)
201- print (f " Found { len (snap.elements)} elements " )
202-
203- # Find first product in viewport using spatial filtering
204- products = [
205- el for el in snap.elements
206- if el.role == " link"
207- and el.visual_cues.is_clickable
208- and el.in_viewport
209- and not el.is_occluded
210- and el.bbox.y < 600 # First row
211- ]
212-
213- if products:
214- # Sort by position (left to right, top to bottom)
215- products.sort(key = lambda e : (e.bbox.y, e.bbox.x))
216- first_product = products[0 ]
211+ import asyncio
212+ import os
213+ from sentience import AsyncSentienceBrowser, AgentRuntime
214+ from sentience.tracing import Tracer, JsonlTraceSink
215+ from sentience.verification import url_contains, exists
217216
218- print (f " Clicking: { first_product.text} " )
219- result = click(browser, first_product.id)
217+ async def main ():
218+ tracer = Tracer(run_id = " verified-run" , sink = JsonlTraceSink(" trace_verified.jsonl" ))
219+ async with AsyncSentienceBrowser(headless = True ) as browser:
220+ page = await browser.new_page()
221+ runtime = await AgentRuntime.from_sentience_browser(browser = browser, page = page, tracer = tracer)
222+ runtime.sentience_api_key = os.getenv(" SENTIENCE_API_KEY" ) # optional, enables Gateway diagnostics
220223
221- # Wait for product page
222- browser.page.wait_for_load_state(" networkidle" )
223- time.sleep(2 )
224+ await page.goto(" https://example.com" )
225+ runtime.begin_step(" Verify we're on the right page" )
224226
225- # Find and click "Add to Cart" button
226- product_snap = snapshot(browser)
227- add_to_cart = find(product_snap, " role=button text~'add to cart'" )
227+ await runtime.check(url_contains(" example.com" ), label = " on_domain" , required = True ).eventually(
228+ timeout_s = 10.0 , poll_s = 0.25 , min_confidence = 0.7 , max_snapshot_attempts = 3
229+ )
230+ runtime.assert_(exists(" role=heading" ), label = " heading_present" )
228231
229- if add_to_cart:
230- cart_result = click(browser, add_to_cart.id)
231- print (f " Added to cart: { cart_result.success} " )
232+ asyncio.run(main())
232233```
233234
234- ** 📖 See the complete tutorial:** [ Amazon Shopping Guide] ( ../docs/AMAZON_SHOPPING_GUIDE.md )
235-
236235</details >
237236
238237---
0 commit comments