sentienceapi 0.92.2__py3-none-any.whl → 0.98.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sentienceapi might be problematic. Click here for more details.

Files changed (64) hide show
  1. sentience/__init__.py +107 -2
  2. sentience/_extension_loader.py +156 -1
  3. sentience/action_executor.py +2 -0
  4. sentience/actions.py +354 -9
  5. sentience/agent.py +4 -0
  6. sentience/agent_runtime.py +840 -0
  7. sentience/asserts/__init__.py +70 -0
  8. sentience/asserts/expect.py +621 -0
  9. sentience/asserts/query.py +383 -0
  10. sentience/async_api.py +8 -1
  11. sentience/backends/__init__.py +137 -0
  12. sentience/backends/actions.py +372 -0
  13. sentience/backends/browser_use_adapter.py +241 -0
  14. sentience/backends/cdp_backend.py +393 -0
  15. sentience/backends/exceptions.py +211 -0
  16. sentience/backends/playwright_backend.py +194 -0
  17. sentience/backends/protocol.py +216 -0
  18. sentience/backends/sentience_context.py +469 -0
  19. sentience/backends/snapshot.py +483 -0
  20. sentience/browser.py +230 -74
  21. sentience/canonicalization.py +207 -0
  22. sentience/cloud_tracing.py +65 -24
  23. sentience/constants.py +6 -0
  24. sentience/cursor_policy.py +142 -0
  25. sentience/extension/content.js +35 -0
  26. sentience/extension/injected_api.js +310 -15
  27. sentience/extension/manifest.json +1 -1
  28. sentience/extension/pkg/sentience_core.d.ts +22 -22
  29. sentience/extension/pkg/sentience_core.js +192 -144
  30. sentience/extension/pkg/sentience_core_bg.wasm +0 -0
  31. sentience/extension/release.json +29 -29
  32. sentience/failure_artifacts.py +241 -0
  33. sentience/integrations/__init__.py +6 -0
  34. sentience/integrations/langchain/__init__.py +12 -0
  35. sentience/integrations/langchain/context.py +18 -0
  36. sentience/integrations/langchain/core.py +326 -0
  37. sentience/integrations/langchain/tools.py +180 -0
  38. sentience/integrations/models.py +46 -0
  39. sentience/integrations/pydanticai/__init__.py +15 -0
  40. sentience/integrations/pydanticai/deps.py +20 -0
  41. sentience/integrations/pydanticai/toolset.py +468 -0
  42. sentience/llm_provider.py +695 -18
  43. sentience/models.py +536 -3
  44. sentience/ordinal.py +280 -0
  45. sentience/query.py +66 -4
  46. sentience/schemas/trace_v1.json +27 -1
  47. sentience/snapshot.py +384 -93
  48. sentience/snapshot_diff.py +39 -54
  49. sentience/text_search.py +1 -0
  50. sentience/trace_event_builder.py +20 -1
  51. sentience/trace_indexing/indexer.py +3 -49
  52. sentience/tracer_factory.py +1 -3
  53. sentience/verification.py +618 -0
  54. sentience/visual_agent.py +3 -1
  55. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/METADATA +198 -40
  56. sentienceapi-0.98.0.dist-info/RECORD +92 -0
  57. sentience/utils.py +0 -296
  58. sentienceapi-0.92.2.dist-info/RECORD +0 -65
  59. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/WHEEL +0 -0
  60. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/entry_points.txt +0 -0
  61. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/licenses/LICENSE +0 -0
  62. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/licenses/LICENSE-APACHE +0 -0
  63. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/licenses/LICENSE-MIT +0 -0
  64. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/top_level.txt +0 -0
sentience/__init__.py CHANGED
@@ -2,9 +2,39 @@
2
2
  Sentience Python SDK - AI Agent Browser Automation
3
3
  """
4
4
 
5
- from .actions import click, click_rect, press, type_text
5
+ # Extension helpers (for browser-use integration)
6
+ from ._extension_loader import (
7
+ get_extension_dir,
8
+ get_extension_version,
9
+ verify_extension_injected,
10
+ verify_extension_injected_async,
11
+ verify_extension_version,
12
+ verify_extension_version_async,
13
+ )
14
+ from .actions import click, click_rect, press, scroll_to, type_text
6
15
  from .agent import SentienceAgent, SentienceAgentAsync
7
16
  from .agent_config import AgentConfig
17
+ from .agent_runtime import AgentRuntime, AssertionHandle
18
+
19
+ # Backend-agnostic actions (aliased to avoid conflict with existing actions)
20
+ # Browser backends (for browser-use integration)
21
+ from .backends import (
22
+ BrowserBackend,
23
+ BrowserUseAdapter,
24
+ BrowserUseCDPTransport,
25
+ CachedSnapshot,
26
+ CDPBackendV0,
27
+ CDPTransport,
28
+ LayoutMetrics,
29
+ PlaywrightBackend,
30
+ ViewportInfo,
31
+ )
32
+ from .backends import click as backend_click
33
+ from .backends import scroll as backend_scroll
34
+ from .backends import scroll_to_element as backend_scroll_to_element
35
+ from .backends import snapshot as backend_snapshot
36
+ from .backends import type_text as backend_type_text
37
+ from .backends import wait_for_stable as backend_wait_for_stable
8
38
 
9
39
  # Agent Layer (Phase 1 & 2)
10
40
  from .base_agent import BaseAgent
@@ -13,6 +43,7 @@ from .browser import SentienceBrowser
13
43
  # Tracing (v0.12.0+)
14
44
  from .cloud_tracing import CloudTraceSink, SentienceLogger
15
45
  from .conversational_agent import ConversationalAgent
46
+ from .cursor_policy import CursorPolicy
16
47
  from .expect import expect
17
48
  from .generator import ScriptGenerator, generate
18
49
  from .inspector import Inspector, inspect
@@ -21,6 +52,8 @@ from .llm_provider import (
21
52
  LLMProvider,
22
53
  LLMResponse,
23
54
  LocalLLMProvider,
55
+ LocalVisionLLMProvider,
56
+ MLXVLMProvider,
24
57
  OpenAIProvider,
25
58
  )
26
59
  from .models import ( # Agent Layer Models
@@ -47,6 +80,9 @@ from .models import ( # Agent Layer Models
47
80
  ViewportRect,
48
81
  WaitResult,
49
82
  )
83
+
84
+ # Ordinal support (Phase 3)
85
+ from .ordinal import OrdinalIntent, boost_ordinal_elements, detect_ordinal_intent, select_by_ordinal
50
86
  from .overlay import clear_overlay, show_overlay
51
87
  from .query import find, query
52
88
  from .read import read
@@ -70,12 +106,59 @@ from .utils import (
70
106
 
71
107
  # Formatting (v0.12.0+)
72
108
  from .utils.formatting import format_snapshot_for_llm
109
+
110
+ # Verification (agent assertion loop)
111
+ from .verification import (
112
+ AssertContext,
113
+ AssertOutcome,
114
+ Predicate,
115
+ all_of,
116
+ any_of,
117
+ custom,
118
+ element_count,
119
+ exists,
120
+ is_checked,
121
+ is_collapsed,
122
+ is_disabled,
123
+ is_enabled,
124
+ is_expanded,
125
+ is_unchecked,
126
+ not_exists,
127
+ url_contains,
128
+ url_matches,
129
+ value_contains,
130
+ value_equals,
131
+ )
73
132
  from .visual_agent import SentienceVisualAgent, SentienceVisualAgentAsync
74
133
  from .wait import wait_for
75
134
 
76
- __version__ = "0.92.2"
135
+ __version__ = "0.98.0"
77
136
 
78
137
  __all__ = [
138
+ # Extension helpers (for browser-use integration)
139
+ "get_extension_dir",
140
+ "get_extension_version",
141
+ "verify_extension_injected",
142
+ "verify_extension_injected_async",
143
+ "verify_extension_version",
144
+ "verify_extension_version_async",
145
+ # Browser backends (for browser-use integration)
146
+ "BrowserBackend",
147
+ "CDPTransport",
148
+ "CDPBackendV0",
149
+ "PlaywrightBackend",
150
+ "BrowserUseAdapter",
151
+ "BrowserUseCDPTransport",
152
+ "ViewportInfo",
153
+ "LayoutMetrics",
154
+ "backend_snapshot",
155
+ "CachedSnapshot",
156
+ # Backend-agnostic actions (prefixed to avoid conflicts)
157
+ "backend_click",
158
+ "backend_type_text",
159
+ "backend_scroll",
160
+ "backend_scroll_to_element",
161
+ "backend_wait_for_stable",
79
162
  # Core SDK
80
163
  "SentienceBrowser",
81
164
  "Snapshot",
@@ -90,7 +173,9 @@ __all__ = [
90
173
  "click",
91
174
  "type_text",
92
175
  "press",
176
+ "scroll_to",
93
177
  "click_rect",
178
+ "CursorPolicy",
94
179
  "wait_for",
95
180
  "expect",
96
181
  "Inspector",
@@ -119,6 +204,8 @@ __all__ = [
119
204
  "OpenAIProvider",
120
205
  "AnthropicProvider",
121
206
  "LocalLLMProvider",
207
+ "LocalVisionLLMProvider",
208
+ "MLXVLMProvider",
122
209
  "SentienceAgent",
123
210
  "SentienceAgentAsync",
124
211
  "SentienceVisualAgent",
@@ -159,4 +246,22 @@ __all__ = [
159
246
  # Enums
160
247
  "SentienceMethod",
161
248
  "AgentAction",
249
+ # Verification (agent assertion loop)
250
+ "AgentRuntime",
251
+ "AssertContext",
252
+ "AssertOutcome",
253
+ "Predicate",
254
+ "url_matches",
255
+ "url_contains",
256
+ "exists",
257
+ "not_exists",
258
+ "element_count",
259
+ "all_of",
260
+ "any_of",
261
+ "custom",
262
+ # Ordinal support (Phase 3)
263
+ "OrdinalIntent",
264
+ "detect_ordinal_intent",
265
+ "select_by_ordinal",
266
+ "boost_ordinal_elements",
162
267
  ]
@@ -1,8 +1,19 @@
1
1
  """
2
- Shared extension loading logic for sync and async implementations
2
+ Shared extension loading logic for sync and async implementations.
3
+
4
+ Provides:
5
+ - get_extension_dir(): Returns path to bundled extension (for browser-use integration)
6
+ - verify_extension_injected(): Verifies window.sentience API is available
7
+ - get_extension_version(): Gets extension version from manifest
8
+ - verify_extension_version(): Checks SDK-extension version compatibility
3
9
  """
4
10
 
11
+ import json
5
12
  from pathlib import Path
13
+ from typing import TYPE_CHECKING, Any
14
+
15
+ if TYPE_CHECKING:
16
+ from .protocols import AsyncPageProtocol, PageProtocol
6
17
 
7
18
 
8
19
  def find_extension_path() -> Path:
@@ -38,3 +49,147 @@ def find_extension_path() -> Path:
38
49
  f"2. {dev_ext_path}\n"
39
50
  "Make sure the extension is built and 'sentience/extension' directory exists."
40
51
  )
52
+
53
+
54
+ def get_extension_dir() -> str:
55
+ """
56
+ Get path to the bundled Sentience extension directory.
57
+
58
+ Use this to load the extension into browser-use or other Chromium-based browsers:
59
+
60
+ from sentience import get_extension_dir
61
+ from browser_use import BrowserSession, BrowserProfile
62
+
63
+ profile = BrowserProfile(
64
+ args=[f"--load-extension={get_extension_dir()}"],
65
+ )
66
+ session = BrowserSession(browser_profile=profile)
67
+
68
+ Returns:
69
+ Absolute path to extension directory as string
70
+
71
+ Raises:
72
+ FileNotFoundError: If extension not found in package
73
+ """
74
+ return str(find_extension_path())
75
+
76
+
77
+ def get_extension_version() -> str:
78
+ """
79
+ Get the version of the bundled extension from manifest.json.
80
+
81
+ Returns:
82
+ Version string (e.g., "2.2.0")
83
+
84
+ Raises:
85
+ FileNotFoundError: If extension or manifest not found
86
+ """
87
+ ext_path = find_extension_path()
88
+ manifest_path = ext_path / "manifest.json"
89
+ with open(manifest_path) as f:
90
+ manifest = json.load(f)
91
+ return manifest.get("version", "unknown")
92
+
93
+
94
+ def verify_extension_injected(page: "PageProtocol") -> bool:
95
+ """
96
+ Verify the Sentience extension injected window.sentience API (sync).
97
+
98
+ Call this after navigating to a page to confirm the extension is working:
99
+
100
+ browser.goto("https://example.com")
101
+ if not verify_extension_injected(browser.page):
102
+ raise RuntimeError("Extension not injected")
103
+
104
+ Args:
105
+ page: Playwright Page object (sync)
106
+
107
+ Returns:
108
+ True if window.sentience.snapshot is available, False otherwise
109
+ """
110
+ try:
111
+ result = page.evaluate(
112
+ "(() => !!(window.sentience && typeof window.sentience.snapshot === 'function'))()"
113
+ )
114
+ return bool(result)
115
+ except Exception:
116
+ return False
117
+
118
+
119
+ async def verify_extension_injected_async(page: "AsyncPageProtocol") -> bool:
120
+ """
121
+ Verify the Sentience extension injected window.sentience API (async).
122
+
123
+ Call this after navigating to a page to confirm the extension is working:
124
+
125
+ await browser.goto("https://example.com")
126
+ if not await verify_extension_injected_async(browser.page):
127
+ raise RuntimeError("Extension not injected")
128
+
129
+ Args:
130
+ page: Playwright Page object (async)
131
+
132
+ Returns:
133
+ True if window.sentience.snapshot is available, False otherwise
134
+ """
135
+ try:
136
+ result = await page.evaluate(
137
+ "(() => !!(window.sentience && typeof window.sentience.snapshot === 'function'))()"
138
+ )
139
+ return bool(result)
140
+ except Exception:
141
+ return False
142
+
143
+
144
+ def verify_extension_version(page: "PageProtocol", expected: str | None = None) -> str | None:
145
+ """
146
+ Check extension version exposed in page (sync).
147
+
148
+ The extension sets window.__SENTIENCE_EXTENSION_VERSION__ when injected.
149
+
150
+ Args:
151
+ page: Playwright Page object (sync)
152
+ expected: If provided, raises RuntimeError on mismatch
153
+
154
+ Returns:
155
+ Version string if found, None if not set (page may not have injected yet)
156
+
157
+ Raises:
158
+ RuntimeError: If expected version provided and doesn't match
159
+ """
160
+ try:
161
+ got = page.evaluate("window.__SENTIENCE_EXTENSION_VERSION__ || null")
162
+ except Exception:
163
+ got = None
164
+
165
+ if expected and got and got != expected:
166
+ raise RuntimeError(f"Sentience extension version mismatch: expected {expected}, got {got}")
167
+ return got
168
+
169
+
170
+ async def verify_extension_version_async(
171
+ page: "AsyncPageProtocol", expected: str | None = None
172
+ ) -> str | None:
173
+ """
174
+ Check extension version exposed in page (async).
175
+
176
+ The extension sets window.__SENTIENCE_EXTENSION_VERSION__ when injected.
177
+
178
+ Args:
179
+ page: Playwright Page object (async)
180
+ expected: If provided, raises RuntimeError on mismatch
181
+
182
+ Returns:
183
+ Version string if found, None if not set (page may not have injected yet)
184
+
185
+ Raises:
186
+ RuntimeError: If expected version provided and doesn't match
187
+ """
188
+ try:
189
+ got = await page.evaluate("window.__SENTIENCE_EXTENSION_VERSION__ || null")
190
+ except Exception:
191
+ got = None
192
+
193
+ if expected and got and got != expected:
194
+ raise RuntimeError(f"Sentience extension version mismatch: expected {expected}, got {got}")
195
+ return got
@@ -96,6 +96,7 @@ class ActionExecutor:
96
96
  "element_id": element_id,
97
97
  "outcome": result.outcome,
98
98
  "url_changed": result.url_changed,
99
+ "cursor": getattr(result, "cursor", None),
99
100
  }
100
101
 
101
102
  # Parse TYPE(42, "hello world")
@@ -170,6 +171,7 @@ class ActionExecutor:
170
171
  "element_id": element_id,
171
172
  "outcome": result.outcome,
172
173
  "url_changed": result.url_changed,
174
+ "cursor": getattr(result, "cursor", None),
173
175
  }
174
176
 
175
177
  # Parse TYPE(42, "hello world")