Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 32 additions & 41 deletions examples/agent_runtime_verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,63 @@
The AgentRuntime provides assertion predicates to verify browser state during execution.

Key features:
- BrowserBackendV0 protocol: Framework-agnostic browser integration
- Predicate helpers: url_matches, url_contains, exists, not_exists, element_count
- Combinators: all_of, any_of for complex conditions
- Task completion: assert_done() for goal verification
- Trace integration: Assertions emitted to trace for Studio timeline

Requirements:
- SENTIENCE_API_KEY (Pro or Enterprise tier)
- SENTIENCE_API_KEY (Pro or Enterprise tier) - optional, enables Gateway refinement

Usage:
python examples/agent_runtime_verification.py
"""

import asyncio
import os

from sentience import (
AgentRuntime,
SentienceBrowser,
all_of,
exists,
not_exists,
url_contains,
url_matches,
)
from sentience.tracer_factory import create_tracer
from sentience import AsyncSentienceBrowser
from sentience.agent_runtime import AgentRuntime
from sentience.tracing import JsonlTraceSink, Tracer
from sentience.verification import all_of, exists, not_exists, url_contains, url_matches


def main():
# Get API key from environment
async def main():
# Get API key from environment (optional - enables Pro tier features)
sentience_key = os.environ.get("SENTIENCE_API_KEY")

if not sentience_key:
print("Error: SENTIENCE_API_KEY not set")
return

print("Starting Agent Runtime Verification Demo\n")

# 1. Create tracer for verification event emission
run_id = "verification-demo"
tracer = create_tracer(api_key=sentience_key, run_id=run_id, upload_trace=False)
sink = JsonlTraceSink(f"traces/{run_id}.jsonl")
tracer = Tracer(run_id=run_id, sink=sink)
print(f"Run ID: {run_id}\n")

# 2. Create browser
browser = SentienceBrowser(api_key=sentience_key, headless=False)
browser.start()

try:
# 3. Create AgentRuntime with browser, page, and tracer
runtime = AgentRuntime(browser, browser.page, tracer)
# 2. Create browser using AsyncSentienceBrowser
async with AsyncSentienceBrowser(headless=False) as browser:
page = await browser.new_page()

# 3. Create AgentRuntime using from_sentience_browser factory
# This wraps the browser/page into the new BrowserBackendV0 architecture
runtime = await AgentRuntime.from_sentience_browser(
browser=browser,
page=page,
tracer=tracer,
sentience_api_key=sentience_key, # Optional: enables Pro tier Gateway refinement
)

# 4. Navigate to a page
print("Navigating to example.com...\n")
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")
await page.goto("https://example.com")
await page.wait_for_load_state("networkidle")

# 5. Begin a verification step
runtime.begin_step("Verify page loaded correctly")

# 6. Take a snapshot (required for element assertions)
snapshot = runtime.snapshot()
snapshot = await runtime.snapshot()
print(f"Snapshot taken: {len(snapshot.elements)} elements found\n")

# 7. Run assertions against current state
Expand Down Expand Up @@ -108,19 +106,12 @@ def main():
print(f" Required passed: {runtime.required_assertions_passed()}")
print(f" Task complete: {runtime.is_task_done}")

except Exception as e:
print(f"\nError during execution: {e}")
raise

finally:
# Close tracer and browser
print("\nClosing tracer...")
tracer.close(blocking=True)
print(f"Trace saved to: ~/.sentience/traces/{run_id}.jsonl")

browser.close()
print("Done!")
# Close tracer after browser context exits
print("\nClosing tracer...")
tracer.close()
print(f"Trace saved to: traces/{run_id}.jsonl")
print("Done!")


if __name__ == "__main__":
main()
asyncio.run(main())
142 changes: 142 additions & 0 deletions examples/browser-use/agent_runtime_browser_use.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
"""
Example: Agent Runtime with browser-use Integration

Demonstrates how to use AgentRuntime with browser-use library via BrowserBackendV0 protocol.
This pattern enables framework-agnostic browser integration for agent verification loops.

Key features:
- BrowserUseAdapter: Wraps browser-use BrowserSession into CDPBackendV0
- BrowserBackendV0 protocol: Minimal interface for browser operations
- Direct AgentRuntime construction: No need for from_sentience_browser factory

Requirements:
- browser-use library: pip install browser-use
- SENTIENCE_API_KEY (optional) - enables Pro tier Gateway refinement

Usage:
python examples/agent_runtime_browser_use.py
"""

import asyncio
import os

from sentience import get_extension_dir
from sentience.agent_runtime import AgentRuntime
from sentience.backends import BrowserUseAdapter
from sentience.tracing import JsonlTraceSink, Tracer
from sentience.verification import all_of, exists, not_exists, url_contains, url_matches

# browser-use imports (requires: pip install browser-use)
try:
from browser_use import BrowserProfile, BrowserSession
except ImportError:
print("Error: browser-use library not installed.")
print("Install with: pip install browser-use")
exit(1)


async def main():
# Get API key from environment (optional - enables Pro tier features)
sentience_key = os.environ.get("SENTIENCE_API_KEY")

print("Starting Agent Runtime with browser-use Integration Demo\n")

# 1. Create tracer for verification event emission
run_id = "browser-use-demo"
sink = JsonlTraceSink(f"traces/{run_id}.jsonl")
tracer = Tracer(run_id=run_id, sink=sink)
print(f"Run ID: {run_id}\n")

# 2. Create browser-use session with Sentience extension loaded
# The extension is required for snapshot() to work
extension_dir = get_extension_dir()
profile = BrowserProfile(
args=[f"--load-extension={extension_dir}"],
headless=False,
)
session = BrowserSession(browser_profile=profile)
await session.start()

try:
# 3. Create BrowserBackendV0 using BrowserUseAdapter
# This wraps the browser-use session into the standard backend protocol
adapter = BrowserUseAdapter(session)
backend = await adapter.create_backend()
print("Created CDPBackendV0 from browser-use session\n")

# 4. Create AgentRuntime directly with backend
# For Pro tier, pass sentience_api_key for Gateway element refinement
runtime = AgentRuntime(
backend=backend,
tracer=tracer,
sentience_api_key=sentience_key, # Optional: enables Pro tier
)

# 5. Navigate using browser-use
page = await session.get_current_page()
print("Navigating to example.com...\n")
await page.goto("https://example.com")
await page.wait_for_load_state("networkidle")

# 6. Begin a verification step
runtime.begin_step("Verify page loaded correctly")

# 7. Take a snapshot (uses Sentience extension via backend.eval())
snapshot = await runtime.snapshot()
print(f"Snapshot taken: {len(snapshot.elements)} elements found\n")

# 8. Run assertions against current state
print("Running assertions:\n")

# URL assertions
url_ok = runtime.assert_(url_contains("example.com"), "on_example_domain")
print(f" [{'PASS' if url_ok else 'FAIL'}] on_example_domain")

url_match = runtime.assert_(url_matches(r"https://.*example\.com"), "url_is_https")
print(f" [{'PASS' if url_match else 'FAIL'}] url_is_https")

# Element assertions
has_heading = runtime.assert_(exists("role=heading"), "has_heading")
print(f" [{'PASS' if has_heading else 'FAIL'}] has_heading")

no_error = runtime.assert_(not_exists("text~'Error'"), "no_error_message")
print(f" [{'PASS' if no_error else 'FAIL'}] no_error_message")

# Combined assertion with all_of
page_ready = runtime.assert_(
all_of(url_contains("example"), exists("role=link")),
"page_fully_ready",
)
print(f" [{'PASS' if page_ready else 'FAIL'}] page_fully_ready")

# 9. Check if task is done (required assertion)
task_complete = runtime.assert_done(
exists("text~'Example Domain'"),
"reached_example_page",
)
print(f"\n [{'DONE' if task_complete else 'NOT DONE'}] reached_example_page")

# 10. Get accumulated assertions for step_end event
assertions_data = runtime.get_assertions_for_step_end()
print(f"\nTotal assertions: {len(assertions_data['assertions'])}")
print(f"Task done: {assertions_data.get('task_done', False)}")

# 11. Check overall status
print("\nVerification Summary:")
print(f" All passed: {runtime.all_assertions_passed()}")
print(f" Required passed: {runtime.required_assertions_passed()}")
print(f" Task complete: {runtime.is_task_done}")

finally:
# Close browser-use session
await session.close()

# Close tracer
print("\nClosing tracer...")
tracer.close()
print(f"Trace saved to: traces/{run_id}.jsonl")
print("Done!")


if __name__ == "__main__":
asyncio.run(main())
Binary file modified screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading