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
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,35 @@ All notable changes to the Sentience Python SDK will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### 2026-02-13

#### Expanded deterministic verifications (adaptive resnapshotting)

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**

```python
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"
},
)
```

## [0.12.0] - 2025-12-26

### Added
Expand Down
11 changes: 10 additions & 1 deletion predicate/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,13 @@
)
from .playwright_backend import PlaywrightBackend
from .protocol import BrowserBackend, LayoutMetrics, ViewportInfo
from .sentience_context import SentienceContext, SentienceContextState, TopElementSelector
from .sentience_context import (
PredicateContext,
PredicateContextState,
SentienceContext,
SentienceContextState,
TopElementSelector,
)
from .snapshot import CachedSnapshot, snapshot

__all__ = [
Expand All @@ -117,6 +123,9 @@
# SentienceContext (Token-Slasher Context Middleware)
"SentienceContext",
"SentienceContextState",
# PredicateContext (rebrand alias)
"PredicateContext",
"PredicateContextState",
"TopElementSelector",
# Backend-agnostic functions
"snapshot",
Expand Down
13 changes: 11 additions & 2 deletions predicate/backends/sentience_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

Example usage:
from browser_use import Agent
from predicate.backends import SentienceContext
from predicate.backends import PredicateContext

ctx = SentienceContext(show_overlay=True)
ctx = PredicateContext(show_overlay=True)
state = await ctx.build(agent.browser_session, goal="Click the first Show HN post")
if state:
agent.add_context(state.prompt_block) # or however browser-use injects state
Expand Down Expand Up @@ -469,3 +469,12 @@ def _compress_href(self, href: str | None) -> str:
pass

return "item"


# ---------------------------------------------------------------------------
# Predicate-named counterparts (canonical moving forward).
# Keep Sentience* names for backward compatibility.
# ---------------------------------------------------------------------------

PredicateContext = SentienceContext
PredicateContextState = SentienceContextState
47 changes: 47 additions & 0 deletions predicate/integrations/browser_use/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
Browser Use integration (Predicate plugin).

This package provides a low-friction integration layer that lets browser-use users
attach Predicate's deterministic verification (AgentRuntime / PredicateDebugger)
to existing Browser Use agent loops via lifecycle hooks and optional tools.

Public surface is intentionally small and may evolve.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING: # pragma: no cover
from .plugin import (
PredicateBrowserUsePlugin,
PredicateBrowserUsePluginConfig,
PredicateBrowserUseVerificationError,
StepCheckSpec,
)

__all__ = [
"PredicateBrowserUsePlugin",
"PredicateBrowserUsePluginConfig",
"PredicateBrowserUseVerificationError",
"StepCheckSpec",
]


def __getattr__(name: str) -> Any: # pragma: no cover
if name in __all__:
from .plugin import ( # local import keeps linting/packaging robust
PredicateBrowserUsePlugin,
PredicateBrowserUsePluginConfig,
PredicateBrowserUseVerificationError,
StepCheckSpec,
)

return {
"PredicateBrowserUsePlugin": PredicateBrowserUsePlugin,
"PredicateBrowserUsePluginConfig": PredicateBrowserUsePluginConfig,
"PredicateBrowserUseVerificationError": PredicateBrowserUseVerificationError,
"StepCheckSpec": StepCheckSpec,
}[name]
raise AttributeError(name)

Loading
Loading