sentienceapi 0.90.12__py3-none-any.whl → 0.92.2__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 (63) hide show
  1. sentience/__init__.py +14 -5
  2. sentience/_extension_loader.py +40 -0
  3. sentience/action_executor.py +215 -0
  4. sentience/actions.py +408 -25
  5. sentience/agent.py +804 -310
  6. sentience/agent_config.py +3 -0
  7. sentience/async_api.py +101 -0
  8. sentience/base_agent.py +95 -0
  9. sentience/browser.py +594 -25
  10. sentience/browser_evaluator.py +299 -0
  11. sentience/cloud_tracing.py +458 -36
  12. sentience/conversational_agent.py +79 -45
  13. sentience/element_filter.py +136 -0
  14. sentience/expect.py +98 -2
  15. sentience/extension/background.js +56 -185
  16. sentience/extension/content.js +117 -289
  17. sentience/extension/injected_api.js +799 -1374
  18. sentience/extension/manifest.json +1 -1
  19. sentience/extension/pkg/sentience_core.js +190 -396
  20. sentience/extension/pkg/sentience_core_bg.wasm +0 -0
  21. sentience/extension/release.json +47 -47
  22. sentience/formatting.py +9 -53
  23. sentience/inspector.py +183 -1
  24. sentience/llm_interaction_handler.py +191 -0
  25. sentience/llm_provider.py +256 -28
  26. sentience/llm_provider_utils.py +120 -0
  27. sentience/llm_response_builder.py +153 -0
  28. sentience/models.py +66 -1
  29. sentience/overlay.py +109 -2
  30. sentience/protocols.py +228 -0
  31. sentience/query.py +1 -1
  32. sentience/read.py +95 -3
  33. sentience/recorder.py +223 -3
  34. sentience/schemas/trace_v1.json +102 -9
  35. sentience/screenshot.py +48 -2
  36. sentience/sentience_methods.py +86 -0
  37. sentience/snapshot.py +309 -64
  38. sentience/snapshot_diff.py +141 -0
  39. sentience/text_search.py +119 -5
  40. sentience/trace_event_builder.py +129 -0
  41. sentience/trace_file_manager.py +197 -0
  42. sentience/trace_indexing/index_schema.py +95 -7
  43. sentience/trace_indexing/indexer.py +117 -14
  44. sentience/tracer_factory.py +119 -6
  45. sentience/tracing.py +172 -8
  46. sentience/utils/__init__.py +40 -0
  47. sentience/utils/browser.py +46 -0
  48. sentience/utils/element.py +257 -0
  49. sentience/utils/formatting.py +59 -0
  50. sentience/utils.py +1 -1
  51. sentience/visual_agent.py +2056 -0
  52. sentience/wait.py +70 -4
  53. {sentienceapi-0.90.12.dist-info → sentienceapi-0.92.2.dist-info}/METADATA +61 -22
  54. sentienceapi-0.92.2.dist-info/RECORD +65 -0
  55. sentienceapi-0.92.2.dist-info/licenses/LICENSE +24 -0
  56. sentienceapi-0.92.2.dist-info/licenses/LICENSE-APACHE +201 -0
  57. sentienceapi-0.92.2.dist-info/licenses/LICENSE-MIT +21 -0
  58. sentience/extension/test-content.js +0 -4
  59. sentienceapi-0.90.12.dist-info/RECORD +0 -46
  60. sentienceapi-0.90.12.dist-info/licenses/LICENSE.md +0 -43
  61. {sentienceapi-0.90.12.dist-info → sentienceapi-0.92.2.dist-info}/WHEEL +0 -0
  62. {sentienceapi-0.90.12.dist-info → sentienceapi-0.92.2.dist-info}/entry_points.txt +0 -0
  63. {sentienceapi-0.90.12.dist-info → sentienceapi-0.92.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,299 @@
1
+ """
2
+ Browser evaluation helper for common window.sentience API patterns.
3
+
4
+ Consolidates repeated patterns for:
5
+ - Waiting for extension injection
6
+ - Calling window.sentience methods
7
+ - Error handling with diagnostics
8
+ """
9
+
10
+ from typing import Any, Optional, Union
11
+
12
+ from playwright.async_api import Page as AsyncPage
13
+ from playwright.sync_api import Page
14
+
15
+ from .browser import AsyncSentienceBrowser, SentienceBrowser
16
+ from .sentience_methods import SentienceMethod
17
+
18
+
19
+ class BrowserEvaluator:
20
+ """Helper class for common browser evaluation patterns"""
21
+
22
+ @staticmethod
23
+ def wait_for_extension(
24
+ page: Page | AsyncPage,
25
+ timeout_ms: int = 5000,
26
+ ) -> None:
27
+ """
28
+ Wait for window.sentience API to be available.
29
+
30
+ Args:
31
+ page: Playwright Page instance (sync or async)
32
+ timeout_ms: Timeout in milliseconds (default: 5000)
33
+
34
+ Raises:
35
+ RuntimeError: If extension fails to inject within timeout
36
+ """
37
+ if hasattr(page, "wait_for_function"):
38
+ # Sync page
39
+ try:
40
+ page.wait_for_function(
41
+ "typeof window.sentience !== 'undefined'",
42
+ timeout=timeout_ms,
43
+ )
44
+ except Exception as e:
45
+ diag = BrowserEvaluator._gather_diagnostics(page)
46
+ raise RuntimeError(
47
+ f"Sentience extension failed to inject window.sentience API. "
48
+ f"Is the extension loaded? Diagnostics: {diag}"
49
+ ) from e
50
+ else:
51
+ # Async page - should use async version
52
+ raise TypeError("Use wait_for_extension_async for async pages")
53
+
54
+ @staticmethod
55
+ async def wait_for_extension_async(
56
+ page: AsyncPage,
57
+ timeout_ms: int = 5000,
58
+ ) -> None:
59
+ """
60
+ Wait for window.sentience API to be available (async).
61
+
62
+ Args:
63
+ page: Playwright AsyncPage instance
64
+ timeout_ms: Timeout in milliseconds (default: 5000)
65
+
66
+ Raises:
67
+ RuntimeError: If extension fails to inject within timeout
68
+ """
69
+ try:
70
+ await page.wait_for_function(
71
+ "typeof window.sentience !== 'undefined'",
72
+ timeout=timeout_ms,
73
+ )
74
+ except Exception as e:
75
+ diag = await BrowserEvaluator._gather_diagnostics_async(page)
76
+ raise RuntimeError(
77
+ f"Sentience extension failed to inject window.sentience API. "
78
+ f"Is the extension loaded? Diagnostics: {diag}"
79
+ ) from e
80
+
81
+ @staticmethod
82
+ def _gather_diagnostics(page: Page | AsyncPage) -> dict[str, Any]:
83
+ """
84
+ Gather diagnostics about extension state.
85
+
86
+ Args:
87
+ page: Playwright Page instance
88
+
89
+ Returns:
90
+ Dictionary with diagnostic information
91
+ """
92
+ try:
93
+ if hasattr(page, "evaluate"):
94
+ # Sync page
95
+ return page.evaluate(
96
+ """() => ({
97
+ sentience_defined: typeof window.sentience !== 'undefined',
98
+ extension_id: document.documentElement.dataset.sentienceExtensionId || 'not set',
99
+ url: window.location.href
100
+ })"""
101
+ )
102
+ else:
103
+ return {"error": "Could not gather diagnostics - invalid page type"}
104
+ except Exception:
105
+ return {"error": "Could not gather diagnostics"}
106
+
107
+ @staticmethod
108
+ async def _gather_diagnostics_async(page: AsyncPage) -> dict[str, Any]:
109
+ """
110
+ Gather diagnostics about extension state (async).
111
+
112
+ Args:
113
+ page: Playwright AsyncPage instance
114
+
115
+ Returns:
116
+ Dictionary with diagnostic information
117
+ """
118
+ try:
119
+ return await page.evaluate(
120
+ """() => ({
121
+ sentience_defined: typeof window.sentience !== 'undefined',
122
+ extension_id: document.documentElement.dataset.sentienceExtensionId || 'not set',
123
+ url: window.location.href
124
+ })"""
125
+ )
126
+ except Exception:
127
+ return {"error": "Could not gather diagnostics"}
128
+
129
+ @staticmethod
130
+ def invoke(
131
+ page: Page,
132
+ method: SentienceMethod | str,
133
+ *args: Any,
134
+ **kwargs: Any,
135
+ ) -> Any:
136
+ """
137
+ Invoke a window.sentience method with error handling (sync).
138
+
139
+ Args:
140
+ page: Playwright Page instance (sync)
141
+ method: SentienceMethod enum value or method name string (e.g., SentienceMethod.SNAPSHOT or "snapshot")
142
+ *args: Positional arguments to pass to the method
143
+ **kwargs: Keyword arguments to pass to the method
144
+
145
+ Returns:
146
+ Result from the method call
147
+
148
+ Raises:
149
+ RuntimeError: If method is not available or call fails
150
+
151
+ Example:
152
+ ```python
153
+ result = BrowserEvaluator.invoke(page, SentienceMethod.SNAPSHOT, limit=50)
154
+ success = BrowserEvaluator.invoke(page, SentienceMethod.CLICK, element_id)
155
+ ```
156
+ """
157
+ # Convert enum to string if needed
158
+ method_name = method.value if isinstance(method, SentienceMethod) else method
159
+
160
+ # Build JavaScript call
161
+ if args and kwargs:
162
+ # Both args and kwargs - use object spread
163
+ js_code = f"""
164
+ (args, kwargs) => {{
165
+ return window.sentience.{method_name}(...args, kwargs);
166
+ }}
167
+ """
168
+ result = page.evaluate(js_code, list(args), kwargs)
169
+ elif args:
170
+ # Only args
171
+ js_code = f"""
172
+ (args) => {{
173
+ return window.sentience.{method_name}(...args);
174
+ }}
175
+ """
176
+ result = page.evaluate(js_code, list(args))
177
+ elif kwargs:
178
+ # Only kwargs - pass as single object
179
+ js_code = f"""
180
+ (options) => {{
181
+ return window.sentience.{method_name}(options);
182
+ }}
183
+ """
184
+ result = page.evaluate(js_code, kwargs)
185
+ else:
186
+ # No arguments
187
+ js_code = f"""
188
+ () => {{
189
+ return window.sentience.{method_name}();
190
+ }}
191
+ """
192
+ result = page.evaluate(js_code)
193
+
194
+ return result
195
+
196
+ @staticmethod
197
+ async def invoke_async(
198
+ page: AsyncPage,
199
+ method: SentienceMethod | str,
200
+ *args: Any,
201
+ **kwargs: Any,
202
+ ) -> Any:
203
+ """
204
+ Invoke a window.sentience method with error handling (async).
205
+
206
+ Args:
207
+ page: Playwright AsyncPage instance
208
+ method: SentienceMethod enum value or method name string (e.g., SentienceMethod.SNAPSHOT or "snapshot")
209
+ *args: Positional arguments to pass to the method
210
+ **kwargs: Keyword arguments to pass to the method
211
+
212
+ Returns:
213
+ Result from the method call
214
+
215
+ Raises:
216
+ RuntimeError: If method is not available or call fails
217
+
218
+ Example:
219
+ ```python
220
+ result = await BrowserEvaluator.invoke_async(page, SentienceMethod.SNAPSHOT, limit=50)
221
+ success = await BrowserEvaluator.invoke_async(page, SentienceMethod.CLICK, element_id)
222
+ ```
223
+ """
224
+ # Convert enum to string if needed
225
+ method_name = method.value if isinstance(method, SentienceMethod) else method
226
+
227
+ # Build JavaScript call
228
+ if args and kwargs:
229
+ js_code = f"""
230
+ (args, kwargs) => {{
231
+ return window.sentience.{method_name}(...args, kwargs);
232
+ }}
233
+ """
234
+ result = await page.evaluate(js_code, list(args), kwargs)
235
+ elif args:
236
+ js_code = f"""
237
+ (args) => {{
238
+ return window.sentience.{method_name}(...args);
239
+ }}
240
+ """
241
+ result = await page.evaluate(js_code, list(args))
242
+ elif kwargs:
243
+ js_code = f"""
244
+ (options) => {{
245
+ return window.sentience.{method_name}(options);
246
+ }}
247
+ """
248
+ result = await page.evaluate(js_code, kwargs)
249
+ else:
250
+ js_code = f"""
251
+ () => {{
252
+ return window.sentience.{method_name}();
253
+ }}
254
+ """
255
+ result = await page.evaluate(js_code)
256
+
257
+ return result
258
+
259
+ @staticmethod
260
+ def verify_method_exists(
261
+ page: Page,
262
+ method: SentienceMethod | str,
263
+ ) -> bool:
264
+ """
265
+ Verify that a window.sentience method exists.
266
+
267
+ Args:
268
+ page: Playwright Page instance (sync)
269
+ method: SentienceMethod enum value or method name string
270
+
271
+ Returns:
272
+ True if method exists, False otherwise
273
+ """
274
+ method_name = method.value if isinstance(method, SentienceMethod) else method
275
+ try:
276
+ return page.evaluate(f"typeof window.sentience.{method_name} !== 'undefined'")
277
+ except Exception:
278
+ return False
279
+
280
+ @staticmethod
281
+ async def verify_method_exists_async(
282
+ page: AsyncPage,
283
+ method: SentienceMethod | str,
284
+ ) -> bool:
285
+ """
286
+ Verify that a window.sentience method exists (async).
287
+
288
+ Args:
289
+ page: Playwright AsyncPage instance
290
+ method: SentienceMethod enum value or method name string
291
+
292
+ Returns:
293
+ True if method exists, False otherwise
294
+ """
295
+ method_name = method.value if isinstance(method, SentienceMethod) else method
296
+ try:
297
+ return await page.evaluate(f"typeof window.sentience.{method_name} !== 'undefined'")
298
+ except Exception:
299
+ return False