99"""
1010
1111import asyncio
12- import json
1312import logging
1413import os
1514import sys
1615import uuid
17- from pathlib import Path
1816from datetime import datetime
17+ from pathlib import Path
18+ from typing import Callable
1919
2020from dotenv import load_dotenv
2121from rich .console import Console
2626# Add parent directory to path for importing predicate_secure
2727sys .path .insert (0 , str (Path (__file__ ).parent .parent / "src" ))
2828
29- from predicate_secure import SecureAgent
30- from predicate_secure .openclaw_adapter import OpenClawConfig
29+ from local_llm_verifier import ( # noqa: E402
30+ VerificationPlan ,
31+ create_verifier_from_env ,
32+ )
3133
32- # Import local LLM verifier
33- from local_llm_verifier import VerificationPlan , create_verifier_from_env
34+ from predicate_secure import SecureAgent # noqa: E402
3435
3536# Setup logging
3637logging .basicConfig (
@@ -119,9 +120,7 @@ def _init_tracer(self):
119120 )
120121 except Exception as e :
121122 logger .warning (f"Failed to initialize cloud tracer: { e } " )
122- console .print (
123- f" [yellow]⚠[/yellow] Cloud tracer initialization failed: { e } \n "
124- )
123+ console .print (f" [yellow]⚠[/yellow] Cloud tracer initialization failed: { e } \n " )
125124
126125 def _init_secure_agent (self ):
127126 """Initialize SecureAgent with predicate-authority integration."""
@@ -136,9 +135,6 @@ def _init_secure_agent(self):
136135
137136 try :
138137 # Create secure agent with browser-like config
139- # Note: SecureAgent expects an agent object, so we'll create a simple wrapper
140- from predicate import PredicateBrowser
141-
142138 # Create browser config (but don't start yet)
143139 browser_config = {
144140 "headless" : os .getenv ("BROWSER_HEADLESS" , "false" ).lower () == "true" ,
@@ -154,9 +150,9 @@ def _init_secure_agent(self):
154150 trace_format = "console" ,
155151 )
156152
157- console .print (f "[green]✓[/green] SecureAgent initialized" )
153+ console .print ("[green]✓[/green] SecureAgent initialized" )
158154 console .print (f" Policy: { self .policy_file } " )
159- console .print (f " Mode: strict (fail-closed)" )
155+ console .print (" Mode: strict (fail-closed)" )
160156 console .print (f" Principal: { self .principal_id } \n " )
161157
162158 except Exception as e :
@@ -258,7 +254,7 @@ async def _run_browser_task(self):
258254
259255 console .print ("\n [green]✓[/green] Task completed successfully\n " )
260256
261- async def _authorized_action (self , action : str , target : str , executor : callable ):
257+ async def _authorized_action (self , action : str , target : str , executor : Callable ):
262258 """Execute an action with pre-authorization and post-verification.
263259
264260 This is the core loop demonstrating:
@@ -304,7 +300,7 @@ async def _authorized_action(self, action: str, target: str, executor: callable)
304300 try :
305301 result = executor ()
306302 # Await if the result is a coroutine
307- if hasattr (result , ' __await__' ):
303+ if hasattr (result , " __await__" ):
308304 result = await result
309305 console .print (" [green]✓[/green] Action executed" )
310306 except Exception as e :
@@ -372,17 +368,8 @@ def _check_authorization(self, action: str, target: str) -> bool:
372368
373369 For this demo, we'll use simplified logic based on the policy.
374370 """
375- # Map demo actions to policy actions
376- action_map = {
377- "navigate" : "browser.navigate" ,
378- "snapshot" : "browser.snapshot" ,
379- "click" : "browser.click" ,
380- "type" : "browser.type" ,
381- }
382-
383- policy_action = action_map .get (action , action )
384-
385371 # Simple checks based on our policy
372+ # In production, this would use policy_action from action_map for proper validation
386373 if action == "navigate" :
387374 # Check if target URL is in allowed domains
388375 allowed_domains = ["example.com" , "google.com" , "wikipedia.org" ]
@@ -413,7 +400,9 @@ async def _find_and_click_link(self, snapshot, link_text: str):
413400 return
414401
415402 console .print (f" [green]✓[/green] Found element: { element .text } (ID: { element .id } )" )
416- console .print (f" [dim]Role: { element .role } , Clickable: { element .visual_cues .is_clickable } [/dim]" )
403+ console .print (
404+ f" [dim]Role: { element .role } , Clickable: { element .visual_cues .is_clickable } [/dim]"
405+ )
417406
418407 # Click the element using the authorized action pattern
419408 # Post-verification will automatically check that URL contains "example-domains" after click
@@ -440,7 +429,9 @@ async def _click_element(self, element):
440429 element .bbox .x + element .bbox .width / 2 ,
441430 element .bbox .y + element .bbox .height / 2 ,
442431 )
443- console .print (f" [dim]Clicked at coordinates: ({ element .bbox .x } , { element .bbox .y } )[/dim]" )
432+ console .print (
433+ f" [dim]Clicked at coordinates: ({ element .bbox .x } , { element .bbox .y } )[/dim]"
434+ )
444435
445436 async def _get_page_summary (self ) -> str :
446437 """Get summary of current page state."""
@@ -465,8 +456,8 @@ async def _get_page_summary(self) -> str:
465456 async def _take_snapshot (self ):
466457 """Take a snapshot of the current page."""
467458 # Use snapshot_async which handles API vs extension automatically
468- from predicate .snapshot import snapshot_async
469459 from predicate .models import SnapshotOptions
460+ from predicate .snapshot import snapshot_async
470461
471462 # Take snapshot with overlay enabled to show element highlights
472463 # This makes it visual and educational - you can see what elements are detected!
@@ -496,9 +487,9 @@ def _execute_verifications(self, plan: VerificationPlan) -> bool:
496487 try :
497488 passed = self ._execute_predicate (verif .predicate , verif .args )
498489 if passed :
499- console .print (f " [green]✓[/green] Passed" )
490+ console .print (" [green]✓[/green] Passed" )
500491 else :
501- console .print (f " [red]✗[/red] Failed" )
492+ console .print (" [red]✗[/red] Failed" )
502493 all_passed = False
503494 except Exception as e :
504495 console .print (f" [red]✗[/red] Error: { e } " )
@@ -518,7 +509,7 @@ def _execute_predicate(self, predicate: str, args: list) -> bool:
518509 try :
519510 if predicate == "url_contains" :
520511 substring = args [0 ] if args else ""
521- return substring in self .browser .page .url
512+ return bool ( substring in self .browser .page .url )
522513
523514 elif predicate == "url_changed" :
524515 # For demo, assume URL changed if we navigated
@@ -530,18 +521,18 @@ def _execute_predicate(self, predicate: str, args: list) -> bool:
530521
531522 elif predicate == "element_exists" :
532523 selector = args [0 ] if args else ""
533- return self .browser .page .locator (selector ).count () > 0
524+ return bool ( self .browser .page .locator (selector ).count () > 0 )
534525
535526 elif predicate == "element_visible" :
536527 selector = args [0 ] if args else ""
537- return self .browser .page .locator (selector ).is_visible ()
528+ return bool ( self .browser .page .locator (selector ).is_visible () )
538529
539530 else :
540- logger .warning (f "Unknown predicate: { predicate } " )
531+ logger .warning ("Unknown predicate: %s" , predicate )
541532 return False
542533
543534 except Exception as e :
544- logger .warning (f "Predicate execution failed: { e } " )
535+ logger .warning ("Predicate execution failed: %s" , e )
545536 return False
546537
547538 async def _cleanup (self ):
0 commit comments