diff --git a/ai/src/fuzzforge_ai/__init__.py b/ai/src/fuzzforge_ai/__init__.py index 5b343a2..cca81fc 100644 --- a/ai/src/fuzzforge_ai/__init__.py +++ b/ai/src/fuzzforge_ai/__init__.py @@ -3,6 +3,11 @@ FuzzForge AI Module - Agent-to-Agent orchestration system This module integrates the fuzzforge_ai components into FuzzForge, providing intelligent AI agent capabilities for security analysis. + +Usage: + from fuzzforge_ai.a2a_wrapper import send_agent_task + from fuzzforge_ai.agent import FuzzForgeAgent + from fuzzforge_ai.config_manager import ConfigManager """ # Copyright (c) 2025 FuzzingLabs # @@ -16,9 +21,4 @@ providing intelligent AI agent capabilities for security analysis. # Additional attribution and requirements are provided in the NOTICE file. -__version__ = "0.6.0" - -from .agent import FuzzForgeAgent -from .config_manager import ConfigManager - -__all__ = ['FuzzForgeAgent', 'ConfigManager'] \ No newline at end of file +__version__ = "0.6.0" \ No newline at end of file diff --git a/ai/src/fuzzforge_ai/config_bridge.py b/ai/src/fuzzforge_ai/config_bridge.py index df81aef..32a7905 100644 --- a/ai/src/fuzzforge_ai/config_bridge.py +++ b/ai/src/fuzzforge_ai/config_bridge.py @@ -21,10 +21,10 @@ except ImportError: # pragma: no cover - used when CLI not available raise ImportError( "ProjectConfigManager is unavailable. Install the FuzzForge CLI " "package or supply a compatible configuration object." - ) from exc + ) def __getattr__(name): # pragma: no cover - defensive - raise ImportError("ProjectConfigManager unavailable") from exc + raise ImportError("ProjectConfigManager unavailable") ProjectConfigManager = _ProjectConfigManager diff --git a/examples/test_a2a_simple.py b/examples/test_a2a_simple.py new file mode 100644 index 0000000..5b9cd9e --- /dev/null +++ b/examples/test_a2a_simple.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +""" +Simple example of using the A2A wrapper +Run from project root: python examples/test_a2a_simple.py +""" +import asyncio + + +async def main(): + # Clean import! + from fuzzforge_ai.a2a_wrapper import send_agent_task + + print("Sending task to agent at http://127.0.0.1:10900...") + + result = await send_agent_task( + url="http://127.0.0.1:10900/a2a/litellm_agent", + model="gpt-4o-mini", + provider="openai", + prompt="You are concise.", + message="Give me a simple Python function that adds two numbers.", + context="test_session", + timeout=120 + ) + + print(f"\nContext ID: {result.context_id}") + print(f"\nResponse:\n{result.text}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/test_a2a_wrapper.py b/test_a2a_wrapper.py new file mode 100755 index 0000000..8e97065 --- /dev/null +++ b/test_a2a_wrapper.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +""" +Test script for A2A wrapper module +Sends tasks to the task-agent to verify functionality +""" +import asyncio +import sys +from pathlib import Path + +# Add ai module to path +ai_src = Path(__file__).parent / "ai" / "src" +sys.path.insert(0, str(ai_src)) + +from fuzzforge_ai.a2a_wrapper import send_agent_task, get_agent_config + + +async def test_basic_task(): + """Test sending a basic task to the agent""" + print("=" * 80) + print("Test 1: Basic task without model specification") + print("=" * 80) + + result = await send_agent_task( + url="http://127.0.0.1:10900/a2a/litellm_agent", + message="What is 2+2? Answer in one sentence.", + timeout=30 + ) + + print(f"Context ID: {result.context_id}") + print(f"Response:\n{result.text}") + print() + return result.context_id + + +async def test_with_model_and_prompt(): + """Test sending a task with custom model and prompt""" + print("=" * 80) + print("Test 2: Task with model and prompt specification") + print("=" * 80) + + result = await send_agent_task( + url="http://127.0.0.1:10900/a2a/litellm_agent", + model="gpt-4o-mini", + provider="openai", + prompt="You are a concise Python expert. Answer in 2 sentences max.", + message="Write a simple Python function that checks if a number is prime.", + context="python_test", + timeout=60 + ) + + print(f"Context ID: {result.context_id}") + print(f"Response:\n{result.text}") + print() + return result.context_id + + +async def test_fuzzing_task(): + """Test a fuzzing-related task""" + print("=" * 80) + print("Test 3: Fuzzing harness generation task") + print("=" * 80) + + result = await send_agent_task( + url="http://127.0.0.1:10900/a2a/litellm_agent", + model="gpt-4o-mini", + provider="openai", + prompt="You are a security testing expert. Provide practical, working code.", + message="Generate a simple fuzzing harness for a C function that parses JSON strings. Include only the essential code.", + context="fuzzing_session", + timeout=90 + ) + + print(f"Context ID: {result.context_id}") + print(f"Response:\n{result.text}") + print() + + +async def test_get_config(): + """Test getting agent configuration""" + print("=" * 80) + print("Test 4: Get agent configuration") + print("=" * 80) + + config = await get_agent_config( + url="http://127.0.0.1:10900/a2a/litellm_agent", + timeout=30 + ) + + print(f"Agent Config:\n{config}") + print() + + +async def test_multi_turn(): + """Test multi-turn conversation with same context""" + print("=" * 80) + print("Test 5: Multi-turn conversation") + print("=" * 80) + + # First message + result1 = await send_agent_task( + url="http://127.0.0.1:10900/a2a/litellm_agent", + message="What is the capital of France?", + context="geography_quiz", + timeout=30 + ) + print(f"Q1: What is the capital of France?") + print(f"A1: {result1.text}") + print() + + # Follow-up in same context + result2 = await send_agent_task( + url="http://127.0.0.1:10900/a2a/litellm_agent", + message="What is the population of that city?", + context="geography_quiz", # Same context + timeout=30 + ) + print(f"Q2: What is the population of that city?") + print(f"A2: {result2.text}") + print() + + +async def main(): + """Run all tests""" + print("\n" + "=" * 80) + print("FuzzForge A2A Wrapper Test Suite") + print("=" * 80 + "\n") + + try: + # Run tests + await test_basic_task() + await test_with_model_and_prompt() + await test_fuzzing_task() + await test_get_config() + await test_multi_turn() + + print("=" * 80) + print("āœ… All tests completed successfully!") + print("=" * 80) + + except Exception as e: + print(f"\nāŒ Test failed with error: {e}") + import traceback + traceback.print_exc() + return 1 + + return 0 + + +if __name__ == "__main__": + exit_code = asyncio.run(main()) + sys.exit(exit_code)