feat(platform): add new services, tools, tests and crews modules
New router intelligence modules (26 files): alert_ingest/store, audit_store, architecture_pressure, backlog_generator/store, cost_analyzer, data_governance, dependency_scanner, drift_analyzer, incident_* (5 files), llm_enrichment, platform_priority_digest, provider_budget, release_check_runner, risk_* (6 files), signature_state_store, sofiia_auto_router, tool_governance New services: - sofiia-console: Dockerfile, adapters/, monitor/nodes/ops/voice modules, launchd, react static - memory-service: integration_endpoints, integrations, voice_endpoints, static UI - aurora-service: full app suite (analysis, job_store, orchestrator, reporting, schemas, subagents) - sofiia-supervisor: new supervisor service - aistalk-bridge-lite: Telegram bridge lite - calendar-service: CalDAV calendar service with reminders - mlx-stt-service / mlx-tts-service: Apple Silicon speech services - binance-bot-monitor: market monitor service - node-worker: STT/TTS memory providers New tools (9): agent_email, browser_tool, contract_tool, observability_tool, oncall_tool, pr_reviewer_tool, repo_tool, safe_code_executor, secure_vault New crews: agromatrix_crew (10 modules: depth_classifier, doc_facts, doc_focus, farm_state, light_reply, llm_factory, memory_manager, proactivity, reflection_engine, session_context, style_adapter, telemetry) Tests: 85+ test files for all new modules Made-with: Cursor
This commit is contained in:
1
tools/browser_tool/tests/__init__.py
Normal file
1
tools/browser_tool/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# BrowserTool Tests
|
||||
140
tools/browser_tool/tests/test_extract.py
Normal file
140
tools/browser_tool/tests/test_extract.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
Test 2: Bank Account Data Extraction
|
||||
|
||||
Demonstrates:
|
||||
- Login to bank portal
|
||||
- Extract account balances
|
||||
- Extract transaction history
|
||||
- Extract credit card info
|
||||
- Handle multi-page data
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from browser_tool import BrowserTool
|
||||
|
||||
|
||||
def test_bank_extraction():
|
||||
"""Test extracting data from a bank account"""
|
||||
|
||||
browser = BrowserTool(
|
||||
agent_id="sofiia-test",
|
||||
headless=False,
|
||||
stealth=True
|
||||
)
|
||||
|
||||
print("=== Starting browser session ===")
|
||||
session = browser.start_session()
|
||||
print(f"Session: {session['session_id']}")
|
||||
|
||||
# Navigate to demo bank site (using a simple example)
|
||||
print("\n=== Navigating to bank login ===")
|
||||
browser.goto("https://demo.aponline.com.au/login")
|
||||
|
||||
# Take screenshot
|
||||
browser.screenshot("/tmp/bank_login.png")
|
||||
|
||||
# Observe login fields
|
||||
print("\n=== Observing bank login page ===")
|
||||
actions = browser.observe("What login fields are available?")
|
||||
print(f"Found {len(actions)} elements")
|
||||
|
||||
# Note: In production, you'd use actual bank credentials
|
||||
# For demo, we'll just show the extraction part
|
||||
|
||||
# After login, extract account data
|
||||
print("\n=== Extracting account balances ===")
|
||||
balances = browser.extract(
|
||||
"Extract all account balances and account numbers",
|
||||
schema={
|
||||
"account_name": "string",
|
||||
"account_number": "string",
|
||||
"balance": "number",
|
||||
"currency": "string"
|
||||
}
|
||||
)
|
||||
print(f"Found {balances.get('count', 0)} accounts")
|
||||
for acc in balances.get('data', [])[:5]:
|
||||
print(f" - {acc}")
|
||||
|
||||
# Extract transactions
|
||||
print("\n=== Extracting transactions ===")
|
||||
transactions = browser.extract(
|
||||
"Extract recent transactions with date, description, amount",
|
||||
schema={
|
||||
"date": "string",
|
||||
"description": "string",
|
||||
"amount": "number",
|
||||
"type": "string"
|
||||
}
|
||||
)
|
||||
print(f"Found {transactions.get('count', 0)} transactions")
|
||||
for tx in transactions.get('data', [])[:10]:
|
||||
print(f" - {tx}")
|
||||
|
||||
# Extract credit card info
|
||||
print("\n=== Extracting credit card info ===")
|
||||
cards = browser.extract(
|
||||
"Extract credit card details",
|
||||
schema={
|
||||
"card_name": "string",
|
||||
"last_4": "string",
|
||||
"balance": "number",
|
||||
"limit": "number"
|
||||
}
|
||||
)
|
||||
print(f"Found {cards.get('count', 0)} cards")
|
||||
|
||||
# Extract pending payments
|
||||
print("\n=== Extracting pending payments ===")
|
||||
pending = browser.extract("Extract pending payments or bills")
|
||||
print(f"Found {pending.get('count', 0)} pending items")
|
||||
|
||||
# Screenshot of dashboard
|
||||
browser.screenshot("/tmp/bank_dashboard.png")
|
||||
|
||||
# Close
|
||||
print("\n=== Closing session ===")
|
||||
browser.close_session()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def test_crypto_exchange():
|
||||
"""Test extracting data from crypto exchange"""
|
||||
|
||||
browser = BrowserTool(agent_id="sofiia-test", headless=True)
|
||||
session = browser.start_session()
|
||||
|
||||
# Navigate to crypto exchange (e.g., Binance demo)
|
||||
print("\n=== Navigating to exchange ===")
|
||||
browser.goto("https://www.binance.com/en/trade/BTC_USDT")
|
||||
|
||||
# Wait for page load
|
||||
import time
|
||||
time.sleep(3)
|
||||
|
||||
# Extract balances
|
||||
print("\n=== Extracting wallet balances ===")
|
||||
balances = browser.extract("Extract all wallet balances")
|
||||
print(f"Found {balances.get('count', 0)} wallets")
|
||||
|
||||
# Extract current price
|
||||
print("\n=== Extracting BTC price ===")
|
||||
price = browser.extract("Extract BTC/USDT current price")
|
||||
print(f"Price data: {price}")
|
||||
|
||||
# Extract open orders
|
||||
orders = browser.extract("Extract open orders")
|
||||
print(f"Open orders: {orders.get('count', 0)}")
|
||||
|
||||
browser.screenshot("/tmp/exchange_dashboard.png")
|
||||
browser.close_session()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_bank_extraction()
|
||||
181
tools/browser_tool/tests/test_form.py
Normal file
181
tools/browser_tool/tests/test_form.py
Normal file
@@ -0,0 +1,181 @@
|
||||
"""
|
||||
Test 3: Form Filling
|
||||
|
||||
Demonstrates:
|
||||
- Complex form filling (registration, checkout, survey)
|
||||
- Multiple field types (text, checkbox, radio, select)
|
||||
- File upload
|
||||
- Form validation
|
||||
- Multi-step forms
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from browser_tool import BrowserTool
|
||||
|
||||
|
||||
def test_registration_form():
|
||||
"""Test filling a registration form"""
|
||||
|
||||
browser = BrowserTool(
|
||||
agent_id="sofiia-test",
|
||||
headless=False,
|
||||
stealth=True
|
||||
)
|
||||
|
||||
print("=== Starting browser session ===")
|
||||
session = browser.start_session()
|
||||
print(f"Session: {session['session_id']}")
|
||||
|
||||
# Navigate to registration form
|
||||
print("\n=== Navigating to registration form ===")
|
||||
browser.goto("https://www.w3schools.com/html/html_forms.asp")
|
||||
|
||||
# Take initial screenshot
|
||||
browser.screenshot("/tmp/form_initial.png")
|
||||
|
||||
# Observe form fields
|
||||
print("\n=== Observing form ===")
|
||||
actions = browser.observe("What form fields are available?")
|
||||
print(f"Found {len(actions)} interactable elements")
|
||||
|
||||
# Fill text fields
|
||||
print("\n=== Filling form fields ===")
|
||||
result = browser.fill_form([
|
||||
{"name": "firstname", "value": "John", "type": "text"},
|
||||
{"name": "lastname", "value": "Doe", "type": "text"},
|
||||
{"name": "email", "value": "john.doe@example.com", "type": "email"}
|
||||
])
|
||||
print(f"Text fields filled: {result}")
|
||||
|
||||
# Fill password fields
|
||||
browser.fill_form([
|
||||
{"name": "password", "value": "SecurePass123!", "type": "password"},
|
||||
{"name": "confirm_password", "value": "SecurePass123!", "type": "password"}
|
||||
])
|
||||
|
||||
# Fill checkboxes
|
||||
browser.fill_form([
|
||||
{"name": "terms", "value": "on", "type": "checkbox", "checked": True},
|
||||
{"name": "newsletter", "value": "on", "type": "checkbox", "checked": False}
|
||||
])
|
||||
|
||||
# Fill select dropdown
|
||||
browser.fill_form([
|
||||
{"name": "country", "value": "US", "type": "select"},
|
||||
{"name": "language", "value": "en", "type": "select"}
|
||||
])
|
||||
|
||||
# Screenshot after filling
|
||||
browser.screenshot("/tmp/form_filled.png")
|
||||
|
||||
# Submit form using act
|
||||
print("\n=== Submitting form ===")
|
||||
try:
|
||||
result = browser.act("Click the Submit button")
|
||||
print(f"Submit result: {result}")
|
||||
except Exception as e:
|
||||
print(f"Act failed: {e}")
|
||||
|
||||
# Wait for response
|
||||
import time
|
||||
time.sleep(2)
|
||||
|
||||
# Check result
|
||||
print(f"Current URL: {browser.get_current_url()}")
|
||||
browser.screenshot("/tmp/form_submitted.png")
|
||||
|
||||
# Extract success message
|
||||
result = browser.extract("Extract any success or error message")
|
||||
print(f"Result message: {result}")
|
||||
|
||||
# Close
|
||||
print("\n=== Closing session ===")
|
||||
browser.close_session()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def test_checkout_form():
|
||||
"""Test filling a checkout form"""
|
||||
|
||||
browser = BrowserTool(agent_id="sofiia-test", headless=False)
|
||||
session = browser.start_session()
|
||||
|
||||
# Navigate to checkout
|
||||
print("\n=== Navigating to checkout ===")
|
||||
browser.goto("https://demo.hook.agency/checkout")
|
||||
|
||||
# Fill shipping info
|
||||
print("\n=== Filling shipping info ===")
|
||||
browser.fill_form([
|
||||
{"name": "shipping_first_name", "value": "Jane", "type": "text"},
|
||||
{"name": "shipping_last_name", "value": "Smith", "type": "text"},
|
||||
{"name": "shipping_address", "value": "123 Main Street", "type": "text"},
|
||||
{"name": "shipping_city", "value": "New York", "type": "text"},
|
||||
{"name": "shipping_state", "value": "NY", "type": "text"},
|
||||
{"name": "shipping_zip", "value": "10001", "type": "text"},
|
||||
{"name": "shipping_country", "value": "US", "type": "select"},
|
||||
{"name": "shipping_phone", "value": "+1-555-123-4567", "type": "tel"}
|
||||
])
|
||||
|
||||
# Fill payment info (demo only!)
|
||||
print("\n=== Filling payment info ===")
|
||||
browser.fill_form([
|
||||
{"name": "card_number", "value": "4111111111111111", "type": "text"},
|
||||
{"name": "card_expiry", "value": "12/25", "type": "text"},
|
||||
{"name": "card_cvv", "value": "123", "type": "text"}
|
||||
])
|
||||
|
||||
# Click place order
|
||||
browser.act("Click the Place Order button")
|
||||
|
||||
import time
|
||||
time.sleep(3)
|
||||
|
||||
# Check order confirmation
|
||||
browser.screenshot("/tmp/checkout_complete.png")
|
||||
result = browser.extract("Extract order confirmation number")
|
||||
print(f"Order result: {result}")
|
||||
|
||||
browser.close_session()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def test_survey_form():
|
||||
"""Test filling a survey form"""
|
||||
|
||||
browser = BrowserTool(agent_id="sofiia-test", headless=False)
|
||||
session = browser.start_session()
|
||||
|
||||
# Navigate to survey
|
||||
browser.goto("https://www.surveymonkey.com/r/2VDKLVC")
|
||||
|
||||
# Get page info
|
||||
print(f"Page title: {browser.get_page_text()[:200]}...")
|
||||
|
||||
# Fill survey questions using act (natural language)
|
||||
questions = [
|
||||
"Select Very Satisfied for question about satisfaction",
|
||||
"Select Yes for question about recommendation",
|
||||
"Select 3-5 years for question about experience"
|
||||
]
|
||||
|
||||
for q in questions:
|
||||
try:
|
||||
result = browser.act(q)
|
||||
print(f" {q}: {result.get('success', False)}")
|
||||
except Exception as e:
|
||||
print(f" {q}: skipped")
|
||||
|
||||
browser.screenshot("/tmp/survey_complete.png")
|
||||
browser.close_session()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_registration_form()
|
||||
145
tools/browser_tool/tests/test_login.py
Normal file
145
tools/browser_tool/tests/test_login.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
Test 1: Gmail Login Flow
|
||||
|
||||
Demonstrates:
|
||||
- Starting a browser session with stealth mode
|
||||
- Navigating to Gmail
|
||||
- Filling login credentials
|
||||
- Handling 2FA
|
||||
- Taking screenshot at each step
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from browser_tool import BrowserTool
|
||||
|
||||
|
||||
def test_gmail_login():
|
||||
"""Test Gmail login flow"""
|
||||
|
||||
# Initialize browser with stealth mode
|
||||
browser = BrowserTool(
|
||||
agent_id="sofiia-test",
|
||||
headless=False, # Set to True for production
|
||||
stealth=True,
|
||||
proxy=None # Optional: "http://proxy:8080"
|
||||
)
|
||||
|
||||
print("=== Starting browser session ===")
|
||||
session = browser.start_session()
|
||||
print(f"Session: {session['session_id']}, Provider: {session['provider']}")
|
||||
|
||||
# Navigate to Gmail
|
||||
print("\n=== Navigating to Gmail ===")
|
||||
browser.goto("https://mail.google.com/mail/u/0/")
|
||||
|
||||
# Take screenshot
|
||||
screenshot = browser.screenshot("/tmp/gmail_login.png")
|
||||
print(f"Screenshot: {screenshot}")
|
||||
|
||||
# Observe page
|
||||
print("\n=== Observing page ===")
|
||||
actions = browser.observe("What login fields are available?")
|
||||
print(f"Found {len(actions)} interactable elements")
|
||||
|
||||
# Fill email
|
||||
print("\n=== Filling email ===")
|
||||
result = browser.fill_form([
|
||||
{"name": "identifier", "value": "your-email@gmail.com", "type": "email"}
|
||||
])
|
||||
print(f"Form fill result: {result}")
|
||||
|
||||
# Click next
|
||||
browser.act("Click the Next button")
|
||||
|
||||
import time
|
||||
time.sleep(2)
|
||||
|
||||
# Take screenshot after email
|
||||
browser.screenshot("/tmp/gmail_email_filled.png")
|
||||
|
||||
# Fill password (use act for natural language)
|
||||
print("\n=== Filling password ===")
|
||||
try:
|
||||
result = browser.act("Type your-password-here into the password field")
|
||||
except:
|
||||
# Fallback to fill_form
|
||||
result = browser.fill_form([
|
||||
{"name": "password", "value": "your-password-here", "type": "password"}
|
||||
])
|
||||
print(f"Password filled: {result}")
|
||||
|
||||
# Click next to login
|
||||
browser.act("Click the Next button")
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
# Check if logged in
|
||||
print(f"\nCurrent URL: {browser.get_current_url()}")
|
||||
|
||||
# Take screenshot after login attempt
|
||||
browser.screenshot("/tmp/gmail_after_login.png")
|
||||
|
||||
# If 2FA required, observe and handle
|
||||
if "verify" in browser.get_current_url().lower() or "consent" in browser.get_current_url().lower():
|
||||
print("\n=== 2FA/CONSENT detected ===")
|
||||
actions = browser.observe("What verification options are available?")
|
||||
print(f"Available: {actions}")
|
||||
|
||||
# Extract inbox info if logged in
|
||||
if "inbox" in browser.get_current_url().lower():
|
||||
print("\n=== Extracting inbox info ===")
|
||||
inbox_data = browser.extract("Extract email subjects from inbox")
|
||||
print(f"Found {inbox_data.get('count', 0)} emails")
|
||||
|
||||
# Close session
|
||||
print("\n=== Closing session ===")
|
||||
result = browser.close_session()
|
||||
print(f"Status: {result['status']}")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def test_gmail_with_otp():
|
||||
"""Test Gmail login with OTP handling"""
|
||||
|
||||
browser = BrowserTool(agent_id="sofiia-test", headless=False)
|
||||
session = browser.start_session()
|
||||
|
||||
# Navigate to Gmail
|
||||
browser.goto("https://mail.google.com/mail/u/0/")
|
||||
|
||||
# Fill email
|
||||
browser.fill_form([{"name": "identifier", "value": "your-email@gmail.com"}])
|
||||
browser.act("Click Next")
|
||||
|
||||
import time
|
||||
time.sleep(2)
|
||||
|
||||
# Fill password
|
||||
browser.fill_form([{"name": "password", "value": "your-password"}])
|
||||
browser.act("Click Next")
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
# Wait for OTP input
|
||||
print("\n=== Waiting for OTP ===")
|
||||
browser.wait_for("input[type='tel']", timeout=30)
|
||||
|
||||
# Observe OTP field
|
||||
actions = browser.observe("What OTP input is available?")
|
||||
print(f"OTP fields: {actions}")
|
||||
|
||||
# Note: You'd need to get OTP from email/Authenticator app
|
||||
# Then fill it:
|
||||
# browser.fill_form([{"name": "code", "value": "123456", "type": "text"}])
|
||||
|
||||
browser.close_session()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_gmail_login()
|
||||
Reference in New Issue
Block a user