All notable changes to the Sentience Python SDK will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
PredicateBrowserAgent is a new high-level agent wrapper that gives you a browser-use-like step() / run() surface, but keeps Predicate’s core philosophy:
- Snapshot-first perception (structured DOM snapshot is the default)
- Verification-first control plane (you can gate progress with deterministic checks)
- Optional vision fallback (bounded) when snapshots aren’t sufficient
It’s built on top of AgentRuntime + RuntimeAgent.
from predicate import AgentRuntime, PredicateBrowserAgent, PredicateBrowserAgentConfig, RuntimeStep
from predicate.llm_provider import OpenAIProvider # or AnthropicProvider / DeepInfraProvider / LocalLLMProvider
runtime = AgentRuntime(backend=...) # PlaywrightBackend, CDPBackendV0, etc.
llm = OpenAIProvider(model="gpt-4o-mini")
agent = PredicateBrowserAgent(
runtime=runtime,
executor=llm,
config=PredicateBrowserAgentConfig(
# Token control: include last N step summaries in the prompt (0 disables history).
history_last_n=2,
),
)
ok = await agent.step(
task_goal="Find pricing and verify checkout button exists",
step=RuntimeStep(goal="Open pricing page"),
)If you want to change the “compact prompt” the executor sees (e.g. fewer fields / different layout), you can override it:
from predicate import PredicateBrowserAgentConfig
def compact_prompt_builder(task_goal, step_goal, dom_context, snapshot, history_summary):
system = "You are a web automation agent. Return ONLY one action: CLICK(id) | TYPE(id, \"text\") | PRESS(\"key\") | FINISH()"
user = f"TASK: {task_goal}\nSTEP: {step_goal}\n\nRECENT:\n{history_summary}\n\nELEMENTS:\n{dom_context}\n\nReturn the single best action:"
return system, user
config = PredicateBrowserAgentConfig(compact_prompt_builder=compact_prompt_builder)If you set captcha.policy="callback", you must provide a handler. The SDK does not include a public CAPTCHA solver.
from predicate import CaptchaConfig, HumanHandoffSolver, PredicateBrowserAgentConfig
config = PredicateBrowserAgentConfig(
captcha=CaptchaConfig(
policy="callback",
# Manual solve in the live session; SDK waits until it clears:
handler=HumanHandoffSolver(timeout_ms=10 * 60_000, poll_ms=1_000),
)
)PredicateBrowserAgent works with any LLMProvider implementation. For a local HF Transformers model:
from predicate.llm_provider import LocalLLMProvider
llm = LocalLLMProvider(model_name="Qwen/Qwen2.5-3B-Instruct", device="auto", load_in_4bit=True)If you want to measure token spend, you can enable best-effort accounting (depends on provider reporting prompt_tokens / completion_tokens / total_tokens in LLMResponse):
from predicate import PredicateBrowserAgentConfig
config = PredicateBrowserAgentConfig(token_usage_enabled=True)
# Later:
usage = agent.get_token_usage()
agent.reset_token_usage()RuntimeAgent now exposes act_once(...) helpers that execute exactly one action without calling runtime.begin_step() / runtime.emit_step_end(). This is intended for external orchestrators (e.g. WebBench) that already own step lifecycle and just want the SDK’s snapshot-first propose+execute block.
await agent.act_once(...) -> strawait agent.act_once_with_snapshot(...) -> (action, snap)await agent.act_once_result(...) -> { action, snap, used_vision }
When you use .eventually() for deterministic checks, you can now automatically increase the snapshot element limit across retries. This helps on long / virtualized pages where a small snapshot limit can miss the target element, causing a false failure.
- AgentRuntime verifications:
AssertionHandle.eventually(..., snapshot_limit_growth=...) - Expect-style verifications:
with_eventually(..., snapshot_limit_growth=...) - Commit:
59125ce19001c457336dccbb3c9463560bd00245
Example
from predicate.verification import exists
# Grow snapshot limit on each retry until the element appears.
await dbg.check(exists("text~'Checkout'"), label="checkout_visible", required=True).eventually(
timeout_s=12,
snapshot_limit_growth={
"start_limit": 60,
"step": 40,
"max_limit": 220,
"apply_on": "only_on_fail", # default; or "all"
},
)- New Module:
predicate.tracing- Built-in tracing infrastructure for debugging and analyzing agent behaviorTracerclass for recording agent executionTraceSinkabstract base class for custom trace storageJsonlTraceSinkfor saving traces to JSONL filesTraceEventdataclass for structured trace events- Trace events:
step_start,snapshot,llm_query,action,step_end,error
- New Module:
predicate.agent_config- Centralized agent configurationAgentConfigdataclass with defaults for snapshot limits, LLM settings, screenshot options
- New Module:
predicate.utils- Snapshot digest utilitiescompute_snapshot_digests()- Generate SHA256 fingerprints for loop detectioncanonical_snapshot_strict()- Digest including element textcanonical_snapshot_loose()- Digest excluding text (layout only)sha256_digest()- Hash computation helper
- New Module:
predicate.formatting- LLM prompt formattingformat_snapshot_for_llm()- Convert snapshots to LLM-friendly text format
- Schema File:
predicate/schemas/trace_v1.json- JSON Schema for trace events, bundled with package
- Added optional
tracerparameter toSentienceAgent.__init__()for execution tracking - Added optional
configparameter toSentienceAgent.__init__()for advanced configuration - Automatic tracing throughout
act()method when tracer is provided - All tracing is opt-in - backward compatible with existing code
- Bumped version from
0.11.0to0.12.0 - Updated
__init__.pyto export new modules:AgentConfig,Tracer,TraceSink,JsonlTraceSink,TraceEvent, and utility functions - Added
MANIFEST.into include JSON schema files in package distribution
- Fixed linting errors across multiple files:
predicate/cli.py- Removed unused variablecode(F841)predicate/inspector.py- Removed unused imports (F401)tests/test_inspector.py- Removed unusedpytestimport (F401)tests/test_recorder.py- Removed unused imports (F401)tests/test_smart_selector.py- Removed unusedpytestimport (F401)tests/test_stealth.py- Addednoqacomments for intentional violations (E402, C901, F541)tests/test_tracing.py- Removed unusedTraceSinkimport (F401)
- Updated
README.mdwith comprehensive "Advanced Features" section covering tracing and utilities - Updated
docs/SDK_MANUAL.mdto v0.12.0 with new "Agent Tracing & Debugging" section - Added examples for:
- Basic tracing setup
- AgentConfig usage
- Snapshot digests for loop detection
- LLM prompt formatting
- Custom trace sinks
- Added comprehensive test suites for new modules:
tests/test_tracing.py- 10 tests for tracing infrastructuretests/test_utils.py- 22 tests for digest utilitiestests/test_formatting.py- 9 tests for LLM formattingtests/test_agent_config.py- 9 tests for configuration
- All 50 new tests passing ✅
No breaking changes! All new features are opt-in:
# Old code continues to work exactly the same
agent = SentienceAgent(browser, llm)
agent.act("Click the button")
# New optional features
tracer = Tracer(run_id="run-123", sink=JsonlTraceSink("trace.jsonl"))
config = AgentConfig(snapshot_limit=100, temperature=0.5)
agent = SentienceAgent(browser, llm, tracer=tracer, config=config)
agent.act("Click the button") # Now traced!# Tracing
from predicate.tracing import Tracer, JsonlTraceSink, TraceEvent, TraceSink
# Configuration
from predicate.agent_config import AgentConfig
# Utilities
from predicate.utils import (
compute_snapshot_digests,
canonical_snapshot_strict,
canonical_snapshot_loose,
sha256_digest
)
# Formatting
from predicate.formatting import format_snapshot_for_llm- This release focuses on developer experience and debugging capabilities
- No changes to browser automation APIs
- No changes to snapshot APIs
- No changes to query/action APIs
- Fully backward compatible with v0.11.0
(Previous changelog entries would go here)