Skip to content

Commit 5723545

Browse files
author
SentienceDEV
committed
Merge pull request #1 from SentienceAPI/week2
Week 2 completed
2 parents 6f70931 + b8b1402 commit 5723545

File tree

4 files changed

+93
-16
lines changed

4 files changed

+93
-16
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Python SDK for Sentience AI Agent Browser Automation.
99
```bash
1010
cd sdk-python
1111
pip install -e .
12+
13+
# Install Playwright browsers (required)
14+
playwright install chromium
1215
```
1316

1417
## Quick Start

examples/hello.py

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,49 @@
66

77

88
def main():
9-
with SentienceBrowser(headless=False) as browser:
10-
# Check if extension API is available
11-
bridge_ok = browser.page.evaluate("typeof window.sentience !== 'undefined'")
12-
print(f"bridge_ok={bridge_ok}")
13-
14-
if bridge_ok:
15-
print("✅ Extension loaded successfully!")
16-
else:
17-
print("❌ Extension not loaded")
9+
try:
10+
with SentienceBrowser(headless=False) as browser:
11+
# Navigate to a page to ensure extension is active
12+
browser.page.goto("https://example.com")
13+
browser.page.wait_for_load_state("networkidle")
14+
15+
# Check if extension API is available
16+
bridge_ok = browser.page.evaluate("""
17+
() => {
18+
return typeof window.sentience !== 'undefined' &&
19+
typeof window.sentience.snapshot === 'function';
20+
}
21+
""")
22+
print(f"bridge_ok={bridge_ok}")
23+
24+
if bridge_ok:
25+
print("✅ Extension loaded successfully!")
26+
# Try a quick snapshot to verify it works
27+
try:
28+
result = browser.page.evaluate("window.sentience.snapshot({ limit: 1 })")
29+
if result.get("status") == "success":
30+
print(f"✅ Snapshot test: Found {len(result.get('elements', []))} elements")
31+
else:
32+
print(f"⚠️ Snapshot returned: {result.get('status')}")
33+
except Exception as e:
34+
print(f"⚠️ Snapshot test failed: {e}")
35+
else:
36+
print("❌ Extension not loaded")
37+
# Debug info
38+
debug_info = browser.page.evaluate("""
39+
() => {
40+
return {
41+
sentience_defined: typeof window.sentience !== 'undefined',
42+
registry_defined: typeof window.sentience_registry !== 'undefined',
43+
snapshot_defined: typeof window.sentience?.snapshot !== 'undefined'
44+
};
45+
}
46+
""")
47+
print(f"Debug info: {debug_info}")
48+
except Exception as e:
49+
print(f"❌ Error: {e}")
50+
import traceback
51+
traceback.print_exc()
1852

1953

2054
if __name__ == "__main__":
1.69 KB
Binary file not shown.

sentience/browser.py

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ def __init__(self, license_key: Optional[str] = None, headless: bool = False):
3131
def start(self) -> None:
3232
"""Launch browser with extension loaded"""
3333
# Get extension path (sentience-chrome directory)
34+
# __file__ is sdk-python/sentience/browser.py, so:
35+
# parent = sdk-python/sentience/
36+
# parent.parent = sdk-python/
37+
# parent.parent.parent = Sentience/ (project root)
3438
repo_root = Path(__file__).parent.parent.parent
3539
extension_source = repo_root / "sentience-chrome"
3640

@@ -62,6 +66,11 @@ def start(self) -> None:
6266
if pkg_source.exists():
6367
pkg_dest = os.path.join(temp_dir, "pkg")
6468
shutil.copytree(pkg_source, pkg_dest, dirs_exist_ok=True)
69+
else:
70+
raise FileNotFoundError(
71+
f"WASM files not found at {pkg_source}. "
72+
"Build the extension first: cd sentience-chrome && ./build.sh"
73+
)
6574

6675
# Launch Playwright
6776
self.playwright = sync_playwright().start()
@@ -83,10 +92,28 @@ def start(self) -> None:
8392
else:
8493
self.page = self.context.new_page()
8594

95+
# Navigate to a real page so extension can inject
96+
# Extension content scripts only run on actual pages (not about:blank)
97+
# Use a simple page that loads quickly
98+
self.page.goto("https://example.com", wait_until="domcontentloaded")
99+
100+
# Give extension time to initialize (WASM loading is async)
101+
self.page.wait_for_timeout(1000)
102+
86103
# Wait for extension to load
87-
self._wait_for_extension()
104+
if not self._wait_for_extension():
105+
# Extension might need more time, try waiting a bit longer
106+
self.page.wait_for_timeout(2000)
107+
if not self._wait_for_extension():
108+
raise RuntimeError(
109+
"Extension failed to load after navigation. Make sure:\n"
110+
"1. Extension is built (cd sentience-chrome && ./build.sh)\n"
111+
"2. All files are present (manifest.json, content.js, injected_api.js, pkg/)\n"
112+
"3. Check browser console for errors\n"
113+
f"4. Extension path: {temp_dir}"
114+
)
88115

89-
def _wait_for_extension(self, timeout: int = 10000) -> bool:
116+
def _wait_for_extension(self, timeout: int = 15000) -> bool:
90117
"""Wait for window.sentience API to be available"""
91118
import time
92119
start = time.time()
@@ -95,16 +122,29 @@ def _wait_for_extension(self, timeout: int = 10000) -> bool:
95122
try:
96123
result = self.page.evaluate("""
97124
() => {
98-
return typeof window.sentience !== 'undefined' &&
99-
typeof window.sentience.snapshot === 'function';
125+
// Check if sentience API exists
126+
if (typeof window.sentience === 'undefined') {
127+
return { ready: false, reason: 'window.sentience not defined' };
128+
}
129+
// Check if snapshot function exists
130+
if (typeof window.sentience.snapshot !== 'function') {
131+
return { ready: false, reason: 'snapshot function not available' };
132+
}
133+
// Check if WASM module is loaded
134+
if (window.sentience_registry === undefined) {
135+
return { ready: false, reason: 'registry not initialized' };
136+
}
137+
return { ready: true };
100138
}
101139
""")
102-
if result:
140+
141+
if isinstance(result, dict) and result.get("ready"):
103142
return True
104-
except Exception:
143+
except Exception as e:
144+
# Continue waiting on errors
105145
pass
106146

107-
time.sleep(0.1)
147+
time.sleep(0.2)
108148

109149
return False
110150

0 commit comments

Comments
 (0)