From 93335b0e538dacee50c543d518ce2acfeb4b1dd2 Mon Sep 17 00:00:00 2001 From: Darcy Liu Date: Sat, 14 Mar 2026 18:11:33 +0000 Subject: [PATCH] refactor: graduate dead_code tests to tests/, delete obsolete artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrated (dead_code/ → tests/ with cleanup): - test_duckduckgo_search.py → tests/test_web_search.py - test_fda_run.py → tests/test_fda_navigation_simple.py - test_fda_detailed.py → tests/test_fda_navigation_detailed.py - test_fda_headed.py → tests/test_fda_navigation_headed.py - test_fda_simple_headed.py → tests/test_fda_navigation_simple_headed.py Cleanup applied to all migrated tests: - Removed stale sys.path.insert (tests/ is inside the package now) - Consistent TARGET_URL constant at module level - Consistent if __name__ == "__main__" guard Deleted (already live or obsolete): - dead_code/core/ (memory entities/ops already in smolclaw/agent/) - dead_code/tools/ (smolagents-style registry superseded by EIM) - dead_code/fix_event_sourcing.py (one-time repair script, already applied) dead_code/ directory fully removed. Co-Authored-By: Claude Sonnet 4.6 --- dead_code/core/__init__.py | 1 - dead_code/core/memory/__init__.py | 21 - dead_code/core/memory/operations.py | 48 --- dead_code/core/memory/store.py | 55 --- dead_code/fix_event_sourcing.py | 33 -- dead_code/tools/__init__.py | 5 - dead_code/tools/builtin/__init__.py | 1 - dead_code/tools/builtin/browser.py | 397 ------------------ dead_code/tools/registry.py | 31 -- .../test_fda_navigation_detailed.py | 77 ++-- .../test_fda_navigation_headed.py | 92 ++-- .../test_fda_navigation_simple.py | 46 +- .../test_fda_navigation_simple_headed.py | 59 ++- .../test_web_search.py | 41 +- 14 files changed, 121 insertions(+), 786 deletions(-) delete mode 100644 dead_code/core/__init__.py delete mode 100644 dead_code/core/memory/__init__.py delete mode 100644 dead_code/core/memory/operations.py delete mode 100644 dead_code/core/memory/store.py delete mode 100644 dead_code/fix_event_sourcing.py delete mode 100644 dead_code/tools/__init__.py delete mode 100644 dead_code/tools/builtin/__init__.py delete mode 100644 dead_code/tools/builtin/browser.py delete mode 100644 dead_code/tools/registry.py rename dead_code/test_fda_detailed.py => tests/test_fda_navigation_detailed.py (72%) rename dead_code/test_fda_headed.py => tests/test_fda_navigation_headed.py (76%) rename dead_code/test_fda_run.py => tests/test_fda_navigation_simple.py (70%) rename dead_code/test_fda_simple_headed.py => tests/test_fda_navigation_simple_headed.py (73%) rename dead_code/test_duckduckgo_search.py => tests/test_web_search.py (81%) diff --git a/dead_code/core/__init__.py b/dead_code/core/__init__.py deleted file mode 100644 index 8754a7b..0000000 --- a/dead_code/core/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Core SmolClaw engine — memory, session, and agent loop primitives.""" diff --git a/dead_code/core/memory/__init__.py b/dead_code/core/memory/__init__.py deleted file mode 100644 index 132e7ee..0000000 --- a/dead_code/core/memory/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Memory sub-package — entities and operations for experience and prompt caching.""" - -from core.memory.store import Experience, ExperienceMemory, PromptCache, from_dict, to_dict -from core.memory.operations import ( - FindSimilarExperiences, - GetSuccessfulPatterns, - LoadExperiences, - SaveExperience, -) - -__all__ = [ - "Experience", - "ExperienceMemory", - "PromptCache", - "from_dict", - "to_dict", - "FindSimilarExperiences", - "GetSuccessfulPatterns", - "LoadExperiences", - "SaveExperience", -] diff --git a/dead_code/core/memory/operations.py b/dead_code/core/memory/operations.py deleted file mode 100644 index 06eb5e2..0000000 --- a/dead_code/core/memory/operations.py +++ /dev/null @@ -1,48 +0,0 @@ -"""Memory operations — load, save, query experiences and prompt cache.""" - -from datetime import datetime -from typing import List - -from core.memory.store import Experience, ExperienceMemory -from agentic_navigator.repositories.ExperienceRepository import ExperienceRepository - - -class LoadExperiences: - @staticmethod - def execute(memory: ExperienceMemory) -> ExperienceMemory: - """Loads experiences from persistent storage into memory.""" - memory.experiences = ExperienceRepository.load(memory.memory_file) - return memory - - -class SaveExperience: - @staticmethod - def execute(memory: ExperienceMemory, experience: Experience) -> ExperienceMemory: - """Saves a new experience to memory and persists it.""" - experience.timestamp = datetime.now().isoformat() - memory.experiences.append(experience) - ExperienceRepository.save(memory.memory_file, memory.experiences) - return memory - - -class FindSimilarExperiences: - @staticmethod - def execute(memory: ExperienceMemory, current_context: str, limit: int = 5) -> List[Experience]: - """Finds similar past experiences based on keyword matching.""" - similar = [] - context_lower = current_context.lower() - keywords = context_lower.split()[:5] - - for exp in memory.experiences: - exp_context = exp.context.lower() - if any(keyword in exp_context for keyword in keywords): - similar.append(exp) - - return similar[-limit:] - - -class GetSuccessfulPatterns: - @staticmethod - def execute(memory: ExperienceMemory, task_description: str) -> List[Experience]: - """Retrieves successful navigation patterns for similar tasks.""" - return [exp for exp in memory.experiences if exp.task == task_description and exp.success] diff --git a/dead_code/core/memory/store.py b/dead_code/core/memory/store.py deleted file mode 100644 index 6bce73a..0000000 --- a/dead_code/core/memory/store.py +++ /dev/null @@ -1,55 +0,0 @@ -"""Memory store entities — Experience, ExperienceMemory, PromptCache.""" - -from typing import Dict, List - - -class Experience: - def __init__(self): - self.task: str = "" - self.start_url: str = "" - self.context: str = "" - self.actions: List[Dict] = [] - self.success: bool = False - self.final_url: str = "" - self.result: str = "" - self.timestamp: str = "" - - -def to_dict(experience: "Experience") -> Dict: - """Serialize an Experience entity to a dictionary.""" - return { - "task": experience.task, - "start_url": experience.start_url, - "context": experience.context, - "actions": experience.actions, - "success": experience.success, - "final_url": experience.final_url, - "result": experience.result, - "timestamp": experience.timestamp, - } - - -def from_dict(data: Dict) -> "Experience": - """Deserialize a dictionary to an Experience entity.""" - exp = Experience() - exp.task = data.get("task", "") - exp.start_url = data.get("start_url", "") - exp.context = data.get("context", "") - exp.actions = data.get("actions", []) - exp.success = data.get("success", False) - exp.final_url = data.get("final_url", "") - exp.result = data.get("result", "") - exp.timestamp = data.get("timestamp", "") - return exp - - -class ExperienceMemory: - def __init__(self): - self.memory_file: str = "navigation_missions.json" - self.experiences: List[Experience] = [] - - -class PromptCache: - def __init__(self): - self.cache_file: str = "keyword_cache.json" - self.cache: Dict[str, str] = {} diff --git a/dead_code/fix_event_sourcing.py b/dead_code/fix_event_sourcing.py deleted file mode 100644 index 7a8c392..0000000 --- a/dead_code/fix_event_sourcing.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python3 -"""Fix event_sourcing.py syntax errors.""" - -import re - -with open('smolclaw/cognitive/event_sourcing.py', 'r') as f: - content = f.read() - -# Fix unclosed strings - look for the pattern and close it -lines = content.split('\n') -fixed_lines = [] - -for i, line in enumerate(lines): - # Fix unclosed "plan_generated strings - if 'self.event_type = "plan_generated' in line and not line.strip().endswith('")'): - fixed_lines.append(' self.event_type = "plan_generated"') - elif 'PLAN_GENERATED = "plan_generated' in line and not line.strip().endswith('")'): - fixed_lines.append(' PLAN_GENERATED = "plan_generated"') - # Fix corrupted fold method - elif 'def fold(self, initial, reducer):' in line: - fixed_lines.append(' def fold(self, initial, reducer):') - # Skip next few corrupted lines - skip = 0 - else: - # Skip corrupted lines after fold - if 'def fold' in ''.join(lines[max(0,i-2):i]) and ('initial: T' in line or 'reducer: Callable' in line or ') -> T:' in line): - continue - fixed_lines.append(line) - -with open('smolclaw/cognitive/event_sourcing.py', 'w') as f: - f.write('\n'.join(fixed_lines)) - -print('✅ Fixed event_sourcing.py') diff --git a/dead_code/tools/__init__.py b/dead_code/tools/__init__.py deleted file mode 100644 index 18c08cd..0000000 --- a/dead_code/tools/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Top-level tools package — canonical location for all SmolClaw tools.""" - -from tools.registry import SmolhandTools, ToolRegistry - -__all__ = ["ToolRegistry", "SmolhandTools"] diff --git a/dead_code/tools/builtin/__init__.py b/dead_code/tools/builtin/__init__.py deleted file mode 100644 index b66eb55..0000000 --- a/dead_code/tools/builtin/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Built-in tool implementations.""" diff --git a/dead_code/tools/builtin/browser.py b/dead_code/tools/builtin/browser.py deleted file mode 100644 index fd440af..0000000 --- a/dead_code/tools/builtin/browser.py +++ /dev/null @@ -1,397 +0,0 @@ -"""Browser automation tools — smolagents @tool wrappers.""" - -import json -from typing import Optional, Tuple - -from helium import get_driver -from smolagents import WebSearchTool, tool - -from browser_subagents.services import ( - BrowserLayerService, - DOMExplorerLayerService, - FlorenceVisionLayerService, - QLearningLayerService, -) -from agentic_navigator.entities.browser.Browser import Browser -from agentic_navigator.entities.browser.NavigationStack import NavigationStack -from agentic_navigator.entities.browser.Tab import Tab - -_navigation_stack = NavigationStack() -_tabs = {} -_tab_counter = 0 -_current_tab_id = None -_task_q_layer = QLearningLayerService() - - -def get_navigation_stack() -> NavigationStack: - """Exposes the shared navigation stack for orchestrators/tests.""" - return _navigation_stack - - -def _tool_name(tool_obj) -> str: - """Normalizes function/class tool objects to a displayable name.""" - if hasattr(tool_obj, "name") and tool_obj.name: - return str(tool_obj.name) - if hasattr(tool_obj, "__name__"): - return str(tool_obj.__name__) - return tool_obj.__class__.__name__ - - -def _set_active_tab(tab_id: Optional[str]) -> None: - for candidate_id, tab in _tabs.items(): - tab.active = candidate_id == tab_id - - -def _sync_tab_snapshot(tab_id: str, append_history: bool = False) -> None: - tab = _tabs.get(tab_id) - if tab is None: - return - - try: - driver = get_driver() - tab.window_handle = driver.current_window_handle - current_url = driver.current_url - tab.url = current_url - if append_history and current_url and (not tab.history or tab.history[-1] != current_url): - tab.history.append(current_url) - except Exception: - return - - -def _probe_current_page() -> Tuple[bool, str]: - try: - page = BrowserLayerService.current_page_state() - current_url = str(page.get("url", "")) - page_source = page.get("page_source", "") - if not page_source: - return False, "Current page source is empty." - return True, current_url - except Exception as exc: - return False, str(exc) - - -def _activate_live_tab(exclude_tab_id: Optional[str] = None) -> Tuple[Optional[str], Optional[str]]: - from agentic_navigator.interactions.tab.Switch import SwitchTab - - original_tab_id = _current_tab_id - candidate_ids = [tab_id for tab_id in _tabs.keys() if tab_id != exclude_tab_id] - for tab_id in candidate_ids: - if not SwitchTab.execute(_tabs, tab_id): - continue - - is_live, detail = _probe_current_page() - if is_live: - _sync_tab_snapshot(tab_id) - _set_active_tab(tab_id) - return tab_id, detail - - if original_tab_id and original_tab_id in _tabs: - SwitchTab.execute(_tabs, original_tab_id) - _sync_tab_snapshot(original_tab_id) - _set_active_tab(original_tab_id) - - return None, None - - -def _recover_live_page(action_name: str) -> Optional[str]: - global _current_tab_id - - if _current_tab_id and _current_tab_id in _tabs: - _set_active_tab(_current_tab_id) - _sync_tab_snapshot(_current_tab_id) - is_live, _ = _probe_current_page() - if is_live: - return None - - recovered_tab_id, recovered_url = _activate_live_tab(exclude_tab_id=_current_tab_id) - if recovered_tab_id: - _current_tab_id = recovered_tab_id - return ( - f"Current page was unavailable. Switched to {recovered_tab_id} " - f"({recovered_url}) before running {action_name}." - ) - - return None - - -@tool -def get_DOM_Tree() -> str: - """Retrieves the full DOM tree of the current page as a JSON string.""" - recovery_note = _recover_live_page("get_DOM_Tree") - dom_tree_json = BrowserLayerService.dom_tree_json() - if recovery_note: - return f"{recovery_note}\n{dom_tree_json}" - return dom_tree_json - - -@tool -def get_browser_snapshot() -> str: - """Returns a normalized JSON snapshot of URL/title/DOM/link context from the shared browser tool layer.""" - recovery_note = _recover_live_page("get_browser_snapshot") - payload = BrowserLayerService.page_snapshot_json() - if recovery_note: - return f"{recovery_note}\n{payload}" - return payload - - -@tool -def analyze_visual_context(prompt_hint: str = "") -> str: - """Layer 2 vision bridge: captures screenshot and returns Florence-backed visual context for main agent prompting.""" - recovery_note = _recover_live_page("analyze_visual_context") - payload = FlorenceVisionLayerService.describe_current_view_json(prompt_hint) - if recovery_note: - return f"{recovery_note}\n{payload}" - return payload - - -@tool -def explore_dom_with_astar(target: str, keyword_values: str = None, top_k: int = 5) -> str: - """Layer 3 exploration: ranks current-page links using A* heuristic signals around href/text context.""" - recovery_note = _recover_live_page("explore_dom_with_astar") - - keyword_weights = {} - if keyword_values: - try: - payload = json.loads(keyword_values) - if isinstance(payload, dict): - keyword_weights = payload - except Exception: - keyword_weights = {} - - result = DOMExplorerLayerService.explore_json(target, keyword_weights=keyword_weights, top_k=top_k) - if recovery_note: - return f"{recovery_note}\n{result}" - return result - - -@tool -def score_task_progress_q_learning(task_prompt: str, llm_score: float = None, action_name: str = "observe") -> str: - """Layer 4 navigation reward: computes task/page vector reward and updates Q-value for current page state.""" - recovery_note = _recover_live_page("score_task_progress_q_learning") - payload = _task_q_layer.score_current_page_json(task_prompt, action_name=action_name, llm_score=llm_score) - if recovery_note: - return f"{recovery_note}\n{payload}" - return payload - - -@tool -def set_browser_url(url: str) -> str: - """Sets the browser to navigate to a specific URL.""" - from agentic_navigator.interactions.navigation.GoToURL import GoToURL - - global _current_tab_id - - current_tab = _tabs.get(_current_tab_id) if _current_tab_id else None - result = GoToURL.execute(url, _navigation_stack, current_tab) - if _current_tab_id: - _sync_tab_snapshot(_current_tab_id, append_history=True) - return result - - -@tool -def create_new_tab(url: str = None) -> str: - """Creates a new browser tab and optionally navigates to a URL.""" - from agentic_navigator.interactions.tab.Create import CreateTab - - global _tab_counter, _current_tab_id - - _, _tab_counter, tab_id = CreateTab.execute(_tabs, _tab_counter, url) - _current_tab_id = tab_id - _set_active_tab(tab_id) - _sync_tab_snapshot(tab_id, append_history=True) - return f"Created new tab with ID: {tab_id}" - - -@tool -def switch_to_tab(tab_id: str) -> str: - """Switches to the specified browser tab.""" - from agentic_navigator.interactions.tab.Switch import SwitchTab - - global _current_tab_id - - success = SwitchTab.execute(_tabs, tab_id) - if success: - _current_tab_id = tab_id - _set_active_tab(tab_id) - _sync_tab_snapshot(tab_id) - return f"Switched to tab: {tab_id}" - return f"Failed to switch to tab: {tab_id}" - - -@tool -def close_tab(tab_id: str) -> str: - """Closes the specified browser tab.""" - from agentic_navigator.interactions.tab.Close import CloseTab - - global _current_tab_id - - success, new_current = CloseTab.execute(_tabs, tab_id, _current_tab_id) - _current_tab_id = new_current - _set_active_tab(_current_tab_id) - if success: - return f"Closed tab: {tab_id}" - return f"Failed to close tab: {tab_id}" - - -@tool -def list_open_tabs() -> str: - """Lists tracked open tabs so the agent can inspect and switch between them.""" - tabs = [] - for tab_id, tab in _tabs.items(): - tabs.append( - { - "tab_id": tab_id, - "url": tab.url, - "active": tab.active, - "history_length": len(tab.history), - "window_handle_known": bool(tab.window_handle), - } - ) - - return json.dumps( - { - "current_tab_id": _current_tab_id, - "tabs": tabs, - }, - indent=2, - ) - - -@tool -def find_path_to_target(target: str, keyword_values: str = None) -> str: - """Uses a depth-1 scout interaction to find best URL for target.""" - from agentic_navigator.interactions.scout.FindPathToTarget import FindPathToTarget - - result = FindPathToTarget.execute(target, keyword_values) - if result.error: - return json.dumps( - { - "error": result.error, - "logs": result.logs, - "top_links_checked": result.top_links_checked, - }, - indent=2, - ) - - return json.dumps( - { - "best_url": result.best_url, - "confidence_score": result.confidence_score, - "reason": result.reason, - "logs": result.logs, - }, - indent=2, - ) - - -@tool -def get_address() -> str: - """Gets address information from browser and host.""" - from agentic_navigator.interactions.location.GetAddress import GetAddress - - recovery_note = _recover_live_page("get_address") - address = GetAddress.execute() - payload = json.dumps( - { - "current_page_url": address.current_page_url, - "system_hostname": address.system_hostname, - "local_ip_address": address.local_ip_address, - "browser_title": address.browser_title, - }, - indent=2, - ) - if recovery_note: - return f"{recovery_note}\n{payload}" - return payload - - -@tool -def get_geolocation() -> str: - """Gets geolocation information from browser geolocation API.""" - from agentic_navigator.interactions.location.GetGeoLocation import GetGeoLocation - - geo = GetGeoLocation.execute() - return json.dumps( - { - "latitude": geo.latitude, - "longitude": geo.longitude, - "accuracy": geo.accuracy, - "altitude": geo.altitude, - "heading": geo.heading, - "speed": geo.speed, - "success": geo.success, - "error": geo.error, - }, - indent=2, - ) - - -@tool -def quit_browser() -> str: - """Safely quits the browser and returns a confirmation string.""" - from agentic_navigator.interactions.browser.Quit import QuitBrowser - - browser = Browser() - browser.is_running = True - return QuitBrowser.execute(browser) - - -@tool -def think(query: str) -> str: - """Calls the cognitive strategy interaction.""" - from agentic_navigator.interactions.thinking.Think import Think - - return Think.execute(query) - - -@tool -def search_item_ctrl_f(text: str, nth_result: int = 1) -> str: - """Searches for text on page and focuses the nth match.""" - from agentic_navigator.interactions.navigation.SearchOnPage import SearchOnPage - - recovery_note = _recover_live_page("search_item_ctrl_f") - result = SearchOnPage.execute(text, nth_result) - if recovery_note: - return f"{recovery_note}\n{result}" - return result - - -@tool -def go_back() -> str: - """Goes back to previous page using shared navigation stack.""" - from agentic_navigator.interactions.navigation.GoBack import GoBack - - return GoBack.execute(_navigation_stack) - - -@tool -def close_popups() -> str: - """Closes visible modal/popups via ESC.""" - from agentic_navigator.interactions.navigation.ClosePopups import ClosePopups - - return ClosePopups.execute() - - -def all_browser_tools(): - """Returns all browser tools in registration order.""" - return [ - WebSearchTool(), - go_back, - close_popups, - search_item_ctrl_f, - get_DOM_Tree, - get_browser_snapshot, - analyze_visual_context, - explore_dom_with_astar, - score_task_progress_q_learning, - list_open_tabs, - set_browser_url, - create_new_tab, - switch_to_tab, - close_tab, - find_path_to_target, - get_address, - get_geolocation, - think, - quit_browser, - ] diff --git a/dead_code/tools/registry.py b/dead_code/tools/registry.py deleted file mode 100644 index c25f173..0000000 --- a/dead_code/tools/registry.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Tool registry — ToolRegistry class and SmolhandTools adapter.""" - -from typing import Any, Callable, Dict - -from tools.builtin.browser import all_browser_tools, _tool_name, get_navigation_stack - - -class ToolRegistry: - """Central registry for all available tools.""" - - @staticmethod - def get_all_tools(): - """Returns all registered tools for the agent.""" - return all_browser_tools() - - @staticmethod - def get_tool_names(): - """Returns names of all registered tools.""" - return [_tool_name(t) for t in all_browser_tools()] - - -class SmolhandTools: - @staticmethod - def as_name_map() -> Dict[str, Callable[..., Any]]: - tools = ToolRegistry.get_all_tools() - mapping: Dict[str, Callable[..., Any]] = {} - for tool in tools: - name = getattr(tool, "name", None) or getattr(tool, "__name__", None) - if name: - mapping[name] = tool - return mapping diff --git a/dead_code/test_fda_detailed.py b/tests/test_fda_navigation_detailed.py similarity index 72% rename from dead_code/test_fda_detailed.py rename to tests/test_fda_navigation_detailed.py index 287ed5e..fc99dae 100644 --- a/dead_code/test_fda_detailed.py +++ b/tests/test_fda_navigation_detailed.py @@ -1,118 +1,97 @@ #!/usr/bin/env python3 -"""Test run: Navigate to FDA website and extract information.""" +"""Test: Navigate to FDA website and extract information (detailed with event replay).""" -import sys -import os import json -# Add project to path -sys.path.insert(0, os.path.dirname(__file__)) - -# Load environment from dotenv import load_dotenv load_dotenv() from smolclaw.cognitive_loop import CognitiveLoop +TARGET_URL = "https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfRL/rl.cfm" + + def main(): print("\n" + "=" * 70) print(" SmolClaw Cognitive System - FDA Website Navigation") print("=" * 70) - - # Target URL - target_url = "https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfRL/rl.cfm" - - print(f"\n🎯 Target Website: {target_url}") + + print(f"\n🎯 Target Website: {TARGET_URL}") print("\n📋 Task: Navigate to the FDA Registration & Listing page") print(" and describe what information is available") - - # Create cognitive loop + loop = CognitiveLoop(max_loops=15, persistence_path="./fda_test_events") - - # Process intent + intent = f""" - Navigate to {target_url} - + Navigate to {TARGET_URL} + Tasks: 1. Go to the FDA Registration & Listing page 2. Describe what you see on the page 3. Identify the main sections and links 4. Tell me what actions can be performed on this page - + Use your vision and exploration tools to analyze the page. """ - + print(f"\n📝 Intent: Navigate and analyze FDA website") print("\n" + "=" * 70) print(" Starting Cognitive Processing") print("=" * 70) - + try: - # Process through cognitive loop result = loop.process_intent(intent) - - # Get final state state = loop.get_state() - - # Get event history events = loop.replay() - + print("\n" + "=" * 70) print(" Cognitive Processing Results") print("=" * 70) - + print(f"\n✅ Success: {result.get('success', False)}") print(f"📄 Result Summary: {result.get('result', 'N/A')[:300]}") - + print(f"\n📊 Final Agent State: {state.get('agent_state', {}).get('state', 'unknown')}") print(f"📈 Total Events: {state.get('event_count', 0)}") - - # Show planner statistics + planner_stats = state.get('planner_stats', {}) print(f"\n🧠 Planner Statistics:") print(f" - Plans Generated: {planner_stats.get('total_plans', 0)}") print(f" - Success Rate: {planner_stats.get('success_rate', 0):.1%}") - - # Show event summary + print(f"\n📋 Event Summary:") event_types = {} for event in events: event_type = event.get('event_type', 'unknown') event_types[event_type] = event_types.get(event_type, 0) + 1 - for event_type, count in sorted(event_types.items()): print(f" - {event_type}: {count}") - - # Show read model state + read_model = state.get('read_model', {}) if read_model: print(f"\n📊 Read Model:") print(f" - Current Goal: {read_model.get('current_goal', 'N/A')[:100]}") print(f" - Tools Used: {len(read_model.get('executed_tools', []))}") - + print("\n" + "=" * 70) print(" ✅ FDA Website Test Complete") print("=" * 70) - print(f"\n💾 Event log saved to: ./fda_test_events/") - print("\n") - - # Save detailed results + print(f"\n💾 Event log saved to: ./fda_test_events/\n") + with open('fda_test_results.json', 'w') as f: - json.dump({ - 'result': result, - 'state': state, - 'event_count': len(events), - }, f, indent=2, default=str) - + json.dump({'result': result, 'state': state, 'event_count': len(events)}, f, indent=2, default=str) + print("📁 Detailed results saved to: fda_test_results.json\n") - + except Exception as e: print(f"\n❌ Error: {e}") import traceback traceback.print_exc() return 1 - + return 0 + if __name__ == "__main__": + import sys sys.exit(main()) diff --git a/dead_code/test_fda_headed.py b/tests/test_fda_navigation_headed.py similarity index 76% rename from dead_code/test_fda_headed.py rename to tests/test_fda_navigation_headed.py index 8469d01..65db635 100644 --- a/dead_code/test_fda_headed.py +++ b/tests/test_fda_navigation_headed.py @@ -1,74 +1,59 @@ #!/usr/bin/env python3 -"""Test run: Navigate to FDA website with HEADED browser (visible).""" +"""Test: Navigate to FDA website with a HEADED (visible) browser and cognitive analysis.""" -import sys -import os import json import time -# Add project to path -sys.path.insert(0, os.path.dirname(__file__)) - -# Load environment from dotenv import load_dotenv load_dotenv() +TARGET_URL = "https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfRL/rl.cfm" + + def main(): print("\n" + "=" * 70) print(" SmolClaw - FDA Website Navigation (HEADED BROWSER)") print("=" * 70) - - # Target URL - target_url = "https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfRL/rl.cfm" - - print(f"\n🎯 Target: {target_url}") + + print(f"\n🎯 Target: {TARGET_URL}") print("🖥️ Browser: HEADED (visible window)") print("\n⏳ Starting browser navigation...") print("=" * 70) - + try: - # Import browser dependencies print("\n[1/6] Loading browser modules...") from smolclaw.tools.smolhand import BrowserLayerService from smolclaw.cognitive import EventStore, IntentReceivedEvent - - # Initialize browser (HEADED - not headless) + print("[2/6] Initializing HEADED browser...") from smolclaw.agent.config.BrowserConfig import BrowserConfig from smolclaw.agent.interactions.browser.Initialize import InitializeBrowser - + config = BrowserConfig() - config.headless = False # HEADED browser! + config.headless = False browser = InitializeBrowser.execute(config) - print(" ✓ Browser launched (visible window)") - - # Navigate to FDA website + print(f"[3/6] Navigating to FDA website...") - from smolclaw.agent.tools.ToolRegistry import set_browser_url - - nav_result = set_browser_url(target_url) + from smolclaw.agent.tools.ToolRegistry import set_browser_url, get_browser_snapshot + + nav_result = set_browser_url(TARGET_URL) print(f" ✓ Navigation result: {nav_result[:100]}") - - # Wait for page to load + print("[4/6] Waiting for page to load...") - time.sleep(3) # Wait for page load - - # Get page snapshot + time.sleep(3) + print("[5/6] Capturing page snapshot...") - from smolclaw.agent.tools.ToolRegistry import get_browser_snapshot - snapshot = get_browser_snapshot() snapshot_data = json.loads(snapshot) - + print("\n" + "=" * 70) print(" Page Information") print("=" * 70) print(f"\n📄 URL: {snapshot_data.get('url', 'N/A')}") print(f"📝 Title: {snapshot_data.get('title', 'N/A')}") print(f"📊 Links Found: {len(snapshot_data.get('links', []))}") - - # Show some links + links = snapshot_data.get('links', [])[:10] if links: print(f"\n🔗 Sample Links (first 10):") @@ -76,44 +61,39 @@ def main(): href = link.get('href', '')[:60] text = link.get('text', '')[:40] print(f" {i}. {text} → {href}") - - # Use vision tools + print("\n[6/6] Analyzing page with cognitive tools...") from smolclaw.cognitive_loop import CognitiveLoop - + loop = CognitiveLoop(max_loops=5) - intent = f""" - Analyze the current FDA page at {target_url} - + Analyze the current FDA page at {TARGET_URL} + Tasks: 1. Describe what sections are visible 2. Identify the main purpose of this page 3. List the main actions available 4. Extract any important information """ - + result = loop.process_intent(intent) - + print("\n" + "=" * 70) print(" Cognitive Analysis Results") print("=" * 70) print(f"\n✅ Success: {result.get('success', False)}") print(f"📄 Analysis: {result.get('result', 'N/A')[:500]}") - - # Get state + state = loop.get_state() print(f"\n📊 Agent State: {state.get('agent_state', {}).get('state', 'unknown')}") print(f"📈 Events: {state.get('event_count', 0)}") - + print("\n" + "=" * 70) print(" ✅ FDA Website Test Complete (HEADED)") print("=" * 70) print("\n💡 Browser window is still open.") - print(" You can interact with it manually or close it.") - print("\n") - - # Save results + print(" You can interact with it manually or close it.\n") + results = { 'url': snapshot_data.get('url'), 'title': snapshot_data.get('title'), @@ -122,30 +102,28 @@ def main(): 'cognitive_result': result, 'timestamp': time.time(), } - with open('fda_headed_results.json', 'w') as f: json.dump(results, f, indent=2, default=str) - print("📁 Results saved to: fda_headed_results.json\n") - - # Keep browser open for user to see + print("⏳ Browser will close in 10 seconds...") time.sleep(10) - - # Cleanup + print("\n[Cleanup] Closing browser...") from smolclaw.agent.interactions.browser.Quit import QuitBrowser browser.is_running = True QuitBrowser.execute(browser) print(" ✓ Browser closed") - + return 0 - + except Exception as e: print(f"\n❌ Error: {e}") import traceback traceback.print_exc() return 1 + if __name__ == "__main__": + import sys sys.exit(main()) diff --git a/dead_code/test_fda_run.py b/tests/test_fda_navigation_simple.py similarity index 70% rename from dead_code/test_fda_run.py rename to tests/test_fda_navigation_simple.py index ea3b48c..99d961a 100644 --- a/dead_code/test_fda_run.py +++ b/tests/test_fda_navigation_simple.py @@ -1,68 +1,58 @@ #!/usr/bin/env python3 -"""Test run: Navigate to FDA website using SmolClaw cognitive system.""" +"""Test: Navigate to FDA website using SmolClaw cognitive system (simple smoke test).""" -import sys -import os - -# Add project to path -sys.path.insert(0, os.path.dirname(__file__)) - -# Load environment from dotenv import load_dotenv load_dotenv() from smolclaw.cognitive_loop import CognitiveLoop +TARGET_URL = "https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfRL/rl.cfm" + + def main(): print("\n" + "=" * 70) print(" SmolClaw Cognitive System - FDA Website Test") print("=" * 70) - - # Target URL - target_url = "https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfRL/rl.cfm" - - print(f"\n🎯 Target: {target_url}") + + print(f"\n🎯 Target: {TARGET_URL}") print("\nStarting cognitive loop...") - - # Create cognitive loop + loop = CognitiveLoop(max_loops=10) - - # Process intent - intent = f"Navigate to {target_url} and tell me what you see on the page" - + intent = f"Navigate to {TARGET_URL} and tell me what you see on the page" + print(f"\n📝 Intent: {intent}") print("\n" + "=" * 70) - + try: result = loop.process_intent(intent) - + print("\n" + "=" * 70) print(" Result") print("=" * 70) print(f"\n✅ Success: {result.get('success', False)}") print(f"📄 Result: {result.get('result', 'N/A')[:500]}") - - # Show state + state = loop.get_state() print(f"\n📊 Agent State: {state.get('agent_state', 'unknown')}") print(f"📈 Events Recorded: {state.get('event_count', 0)}") - - # Show planner stats + planner_stats = state.get('planner_stats', {}) print(f"🧠 Plans Generated: {planner_stats.get('total_plans', 0)}") print(f"📊 Success Rate: {planner_stats.get('success_rate', 0):.1%}") - + print("\n" + "=" * 70) print(" ✅ Test Complete") print("=" * 70 + "\n") - + except Exception as e: print(f"\n❌ Error: {e}") import traceback traceback.print_exc() return 1 - + return 0 + if __name__ == "__main__": + import sys sys.exit(main()) diff --git a/dead_code/test_fda_simple_headed.py b/tests/test_fda_navigation_simple_headed.py similarity index 73% rename from dead_code/test_fda_simple_headed.py rename to tests/test_fda_navigation_simple_headed.py index 41a7b68..f68c948 100644 --- a/dead_code/test_fda_simple_headed.py +++ b/tests/test_fda_navigation_simple_headed.py @@ -1,90 +1,79 @@ #!/usr/bin/env python3 -"""Simple test: Navigate to FDA website with HEADED browser.""" +"""Test: Navigate to FDA website with a HEADED (visible) browser — minimal smoke test.""" -import sys -import os +import json import time -# Add project to path -sys.path.insert(0, os.path.dirname(__file__)) - -# Load environment from dotenv import load_dotenv load_dotenv() +TARGET_URL = "https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfRL/rl.cfm" + + def main(): print("\n" + "=" * 70) print(" SmolClaw - FDA Website Test (HEADED BROWSER)") print("=" * 70) - - target_url = "https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfRL/rl.cfm" - - print(f"\n🎯 Target: {target_url}") + + print(f"\n🎯 Target: {TARGET_URL}") print("🖥️ Browser: HEADED (visible)") print("\n⏳ Starting...") - + try: - # Initialize browser print("\n[1/4] Initializing browser...") from smolclaw.agent.config.BrowserConfig import BrowserConfig from smolclaw.agent.interactions.browser.Initialize import InitializeBrowser - + config = BrowserConfig() - config.headless = False # HEADED! + config.headless = False browser = InitializeBrowser.execute(config) print(" ✓ Browser launched") - - # Navigate + print(f"\n[2/4] Navigating to FDA...") from smolclaw.agent.tools.ToolRegistry import set_browser_url, get_browser_snapshot - - result = set_browser_url(target_url) + + result = set_browser_url(TARGET_URL) print(f" ✓ {result[:80]}") - - # Wait + print("\n[3/4] Waiting for page load (5 sec)...") time.sleep(5) - - # Get snapshot + print("\n[4/4] Getting page info...") snapshot = get_browser_snapshot() - - import json data = json.loads(snapshot) - + print("\n" + "=" * 70) print(" Page Loaded Successfully!") print("=" * 70) print(f"\n📄 URL: {data.get('url', 'N/A')}") print(f"📝 Title: {data.get('title', 'N/A')}") print(f"🔗 Links: {len(data.get('links', []))}") - + print("\n" + "=" * 70) print(" ✅ Success! Browser is open and visible.") print("=" * 70) print("\n💡 The browser window should be visible on your screen.") - print(" It will close automatically in 10 seconds.") - print("\n") - - # Wait so user can see + print(" It will close automatically in 10 seconds.\n") + for i in range(10, 0, -1): print(f" Closing in {i}... ", end='\r', flush=True) time.sleep(1) - - # Cleanup + print("\n[Cleanup] Closing browser...") browser.is_running = True from smolclaw.agent.interactions.browser.Quit import QuitBrowser QuitBrowser.execute(browser) print(" ✓ Closed") - + return 0 - + except Exception as e: print(f"\n❌ Error: {e}") import traceback traceback.print_exc() return 1 + if __name__ == "__main__": + import sys sys.exit(main()) diff --git a/dead_code/test_duckduckgo_search.py b/tests/test_web_search.py similarity index 81% rename from dead_code/test_duckduckgo_search.py rename to tests/test_web_search.py index 2f3b3aa..f023ff5 100644 --- a/dead_code/test_duckduckgo_search.py +++ b/tests/test_web_search.py @@ -1,69 +1,60 @@ #!/usr/bin/env python3 -"""Test: Use DuckDuckGo web search tool.""" +"""Test: Use DuckDuckGo web search tool via smolagents WebSearchTool.""" -import sys -import os - -# Add project to path -sys.path.insert(0, os.path.dirname(__file__)) - -# Load environment from dotenv import load_dotenv load_dotenv() + def main(): print("\n" + "=" * 70) print(" SmolClaw - DuckDuckGo Web Search Test") print("=" * 70) - + print("\n✅ Yes! SmolClaw uses smolagents!") print("✅ Yes! It has DuckDuckGo search via WebSearchTool!") - + print("\n" + "=" * 70) print(" Testing Web Search Tool") print("=" * 70) - + try: - # Import the search tool print("\n[1/3] Loading WebSearchTool from smolagents...") from smolagents import WebSearchTool - + search_tool = WebSearchTool() print(f" ✓ Tool name: {search_tool.name}") print(f" ✓ Description: {search_tool.description[:100]}...") - - # Test search + print("\n[2/3] Performing DuckDuckGo search...") query = "FDA device registration requirements 2025" print(f" Query: {query}") - + result = search_tool(query) - + print(f" ✓ Search completed!") print(f" ✓ Results length: {len(result)} characters") - - # Show results + print("\n[3/3] Search Results:") print("=" * 70) - # Show first 1000 chars print(result[:1000]) if len(result) > 1000: print(f"\n... ({len(result) - 1000} more characters)") - + print("\n" + "=" * 70) print(" ✅ DuckDuckGo Search Test Complete!") print("=" * 70) print("\n💡 The WebSearchTool uses DuckDuckGo by default!") - print(" No API key required - it's free and open source!") - print("\n") - + print(" No API key required - it's free and open source!\n") + return 0 - + except Exception as e: print(f"\n❌ Error: {e}") import traceback traceback.print_exc() return 1 + if __name__ == "__main__": + import sys sys.exit(main())