|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" |
| 3 | +Neo N3 Research Skill Agent Demo |
| 4 | +
|
| 5 | +This example demonstrates how to use the SpoonReactSkill agent with the |
| 6 | +Neo Query skill for comprehensive blockchain data analysis. |
| 7 | +
|
| 8 | +Features: |
| 9 | +- Skill-based agent for Neo N3 |
| 10 | +- Script-based Neo RPC integration (via neo-query skill) |
| 11 | +- Advanced analysis of blocks, addresses, and governance |
| 12 | +""" |
| 13 | + |
| 14 | +import os |
| 15 | +import sys |
| 16 | +import asyncio |
| 17 | +import logging |
| 18 | +from pathlib import Path |
| 19 | +from dotenv import load_dotenv |
| 20 | + |
| 21 | +from spoon_ai.agents import SpoonReactSkill |
| 22 | +from spoon_ai.chat import ChatBot |
| 23 | + |
| 24 | +# Load environment variables |
| 25 | +load_dotenv(override=True) |
| 26 | + |
| 27 | +# Configure logging |
| 28 | +logging.basicConfig( |
| 29 | + level=logging.INFO, |
| 30 | + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' |
| 31 | +) |
| 32 | +logger = logging.getLogger(__name__) |
| 33 | + |
| 34 | +# Path to example skills |
| 35 | +EXAMPLES_SKILLS_PATH = str(Path(__file__).parent / "skills") |
| 36 | + |
| 37 | + |
| 38 | +class NeoResearchSkillAgent(SpoonReactSkill): |
| 39 | + """ |
| 40 | + A Neo-focused research agent that uses the neo-query skill |
| 41 | + for deep blockchain data analysis. |
| 42 | + """ |
| 43 | + |
| 44 | + def __init__(self, **kwargs): |
| 45 | + # Set default values before super().__init__ |
| 46 | + kwargs.setdefault('name', 'neo_research_skill_agent') |
| 47 | + kwargs.setdefault('description', 'AI agent specialized in Neo N3 blockchain research') |
| 48 | + kwargs.setdefault('system_prompt', self._get_system_prompt()) |
| 49 | + kwargs.setdefault('max_steps', 10) |
| 50 | + kwargs.setdefault('_default_timeout', 120.0) |
| 51 | + |
| 52 | + # Configure skill paths to include examples/skills |
| 53 | + kwargs.setdefault('skill_paths', [EXAMPLES_SKILLS_PATH]) |
| 54 | + |
| 55 | + # Enable scripts for data query |
| 56 | + kwargs.setdefault('scripts_enabled', True) |
| 57 | + |
| 58 | + super().__init__(**kwargs) |
| 59 | + |
| 60 | + @staticmethod |
| 61 | + def _get_system_prompt() -> str: |
| 62 | + return """You are a top-tier Neo N3 Blockchain Analyst. |
| 63 | +
|
| 64 | +Your mission is to provide deep, accurate, and professional analysis of the Neo ecosystem. |
| 65 | +You have access to the `neo-query` skill, which provides direct RPC access to Neo data. |
| 66 | +
|
| 67 | +When analyzing Neo topics: |
| 68 | +1. Use `run_script_neo-query_neo_rpc_query` to fetch real-time data. |
| 69 | +2. For addresses: Always check balances (NEO/GAS) and recent transfer history to understand the user's profile. |
| 70 | +3. For governance: Use committee and candidate tools to explain the voting landscape. |
| 71 | +4. For contracts: Look for verification status and analyze recent invocation logs if needed. |
| 72 | +5. Context: Default to Neo Testnet unless Mainnet is specified. |
| 73 | +
|
| 74 | +Structure your responses professionally, using tables for data comparison where appropriate. |
| 75 | +Always explain technical terms (like NEP-17, GAS, UInt160) in a user-friendly way. |
| 76 | +""" |
| 77 | + |
| 78 | + async def initialize(self, __context=None): |
| 79 | + """Initialize the agent and activate Neo skills.""" |
| 80 | + await super().initialize(__context) |
| 81 | + |
| 82 | + skills = self.list_skills() |
| 83 | + logger.info(f"Available skills: {skills}") |
| 84 | + |
| 85 | + async def analyze(self, query: str) -> str: |
| 86 | + logger.info(f"Starting Neo analysis: {query}") |
| 87 | + response = await self.run(query) |
| 88 | + return response |
| 89 | + |
| 90 | + |
| 91 | +async def demo_neo_analysis(): |
| 92 | + """Run a demo of Neo blockchain analysis.""" |
| 93 | + print("\n" + "=" * 60) |
| 94 | + print("Neo N3 Research Skill Agent Demo") |
| 95 | + print("(Powered by neo-query skill scripts)") |
| 96 | + print("=" * 60) |
| 97 | + |
| 98 | + # Create agent |
| 99 | + agent = NeoResearchSkillAgent( |
| 100 | + llm=ChatBot(), |
| 101 | + auto_trigger_skills=True |
| 102 | + ) |
| 103 | + |
| 104 | + # Initialize |
| 105 | + await agent.initialize() |
| 106 | + |
| 107 | + # Test cases |
| 108 | + test_queries = [ |
| 109 | + "What is the current status of the Neo Testnet? Show me the latest block height and committee members.", |
| 110 | + "Check the balance and recent NEP-17 activity for Neo address NUTtedVrz5RgKAdCvtKiq3sRkb9pizcewe.", |
| 111 | + "Search for a contract named 'Flamingo' and tell me its hash and verification status." |
| 112 | + ] |
| 113 | + |
| 114 | + for i, query in enumerate(test_queries, 1): |
| 115 | + print(f"\n[Test {i}] Query: {query}") |
| 116 | + print("-" * 60) |
| 117 | + response = await agent.analyze(query) |
| 118 | + print(f"\nAnalysis Result:\n{response}") |
| 119 | + print("-" * 60) |
| 120 | + await asyncio.sleep(2) |
| 121 | + |
| 122 | + |
| 123 | +async def demo_interactive(): |
| 124 | + """Interactive mode for Neo research.""" |
| 125 | + print("\n" + "=" * 60) |
| 126 | + print("Neo N3 Research Agent - Interactive Mode") |
| 127 | + print("Type your Neo-related questions (e.g., 'Check balance of N...', 'Who is in the council?')") |
| 128 | + print("Type 'exit' to quit.") |
| 129 | + print("=" * 60) |
| 130 | + |
| 131 | + agent = NeoResearchSkillAgent(llm=ChatBot()) |
| 132 | + await agent.initialize() |
| 133 | + |
| 134 | + while True: |
| 135 | + try: |
| 136 | + user_input = input("\nYou: ").strip() |
| 137 | + if not user_input or user_input.lower() in ['exit', 'quit', 'q']: |
| 138 | + break |
| 139 | + |
| 140 | + response = await agent.analyze(user_input) |
| 141 | + print(f"\nAgent: {response}") |
| 142 | + except KeyboardInterrupt: |
| 143 | + break |
| 144 | + except Exception as e: |
| 145 | + print(f"Error: {e}") |
| 146 | + |
| 147 | +async def main(): |
| 148 | + # Intelligent LLM Provider selection |
| 149 | + from spoon_ai.llm.manager import get_llm_manager |
| 150 | + if not (os.getenv("OPENAI_API_KEY") or os.getenv("GEMINI_API_KEY") or os.getenv("OPENROUTER_API_KEY")): |
| 151 | + print("Error: No LLM API key found.") |
| 152 | + sys.exit(1) |
| 153 | + |
| 154 | + print("\nSelect demo mode:") |
| 155 | + print("1. Automatic Demo (3 scenarios)") |
| 156 | + print("2. Interactive mode") |
| 157 | + |
| 158 | + choice = input("\nEnter choice (1-2, default=1): ").strip() or "1" |
| 159 | + |
| 160 | + if choice == "1": |
| 161 | + await demo_neo_analysis() |
| 162 | + else: |
| 163 | + await demo_interactive() |
| 164 | + |
| 165 | + |
| 166 | +if __name__ == "__main__": |
| 167 | + asyncio.run(main()) |
| 168 | + |
0 commit comments