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
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,40 @@ with browser:

</details>

<details>
<summary><h3>🔍 Agent Runtime Verification</h3></summary>

`AgentRuntime` provides assertion predicates for runtime verification in agent loops, enabling programmatic verification of browser state during execution.

```python
from sentience import (
AgentRuntime, SentienceBrowser,
url_contains, exists, all_of
)
from sentience.tracer_factory import create_tracer

browser = SentienceBrowser()
browser.start()
tracer = create_tracer(run_id="my-run", upload_trace=False)
runtime = AgentRuntime(browser, browser.page, tracer)

# Navigate and take snapshot
browser.page.goto("https://example.com")
runtime.begin_step("Verify page")
runtime.snapshot()

# Run assertions
runtime.assert_(url_contains("example.com"), "on_correct_domain")
runtime.assert_(exists("role=heading"), "has_heading")
runtime.assert_done(exists("text~'Example'"), "task_complete")

print(f"Task done: {runtime.is_task_done}")
```

**See example:** [`examples/agent_runtime_verification.py`](examples/agent_runtime_verification.py)

</details>

<details>
<summary><h3>🧰 Snapshot Utilities</h3></summary>

Expand Down
126 changes: 126 additions & 0 deletions examples/agent_runtime_verification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
"""
Example: Agent Runtime with Verification Loop

Demonstrates how to use AgentRuntime for runtime verification in agent loops.
The AgentRuntime provides assertion predicates to verify browser state during execution.

Key features:
- 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)

Usage:
python examples/agent_runtime_verification.py
"""

import os

from sentience import (
AgentRuntime,
SentienceBrowser,
all_of,
exists,
not_exists,
url_contains,
url_matches,
)
from sentience.tracer_factory import create_tracer


def main():
# Get API key from environment
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)
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)

# 4. Navigate to a page
print("Navigating to example.com...\n")
browser.page.goto("https://example.com")
browser.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()
print(f"Snapshot taken: {len(snapshot.elements)} elements found\n")

# 7. 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")

# 8. 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")

# 9. 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)}")

# 10. 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}")

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!")


if __name__ == "__main__":
main()
29 changes: 29 additions & 0 deletions sentience/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .actions import click, click_rect, press, scroll_to, type_text
from .agent import SentienceAgent, SentienceAgentAsync
from .agent_config import AgentConfig
from .agent_runtime import AgentRuntime

# Agent Layer (Phase 1 & 2)
from .base_agent import BaseAgent
Expand Down Expand Up @@ -70,6 +71,21 @@

# Formatting (v0.12.0+)
from .utils.formatting import format_snapshot_for_llm

# Verification (agent assertion loop)
from .verification import (
AssertContext,
AssertOutcome,
Predicate,
all_of,
any_of,
custom,
element_count,
exists,
not_exists,
url_contains,
url_matches,
)
from .visual_agent import SentienceVisualAgent, SentienceVisualAgentAsync
from .wait import wait_for

Expand Down Expand Up @@ -160,4 +176,17 @@
# Enums
"SentienceMethod",
"AgentAction",
# Verification (agent assertion loop)
"AgentRuntime",
"AssertContext",
"AssertOutcome",
"Predicate",
"url_matches",
"url_contains",
"exists",
"not_exists",
"element_count",
"all_of",
"any_of",
"custom",
]
Loading
Loading