├── .env.example ├── .github └── ISSUE_TEMPLATE │ └── new_crew.md ├── .gitignore ├── .gitmodules ├── .replit ├── .streamlit └── config.toml ├── CONTRIBUTING.md ├── README.md ├── aibtc-v1 ├── app.py ├── chat.py ├── components │ ├── agents_tab.py │ ├── execution_tab.py │ ├── tasks_tab.py │ └── tools_tab.py ├── crews │ ├── clarity_code_generator_v2.py │ ├── smart_contract_analyzer_v2.py │ ├── trading_analyzer.py │ ├── user_chat_specialist.py │ └── wallet_summarizer.py ├── run_clarinet.py └── utils │ ├── callbacks.py │ ├── clarinet.py │ ├── clarity.py │ ├── crews.py │ ├── scripts.py │ ├── session.py │ └── vector.py ├── clarinet ├── glibc-2.34 │ ├── ld-linux-x86-64.so.2 │ ├── libc.so.6 │ └── libgcc_s.so.1 └── setup-clarinet.sh ├── legacy_code ├── agents.py ├── aibtc-v1 │ ├── agents.py │ ├── tasks.py │ └── tools.py ├── bitcoin_crew_app.py ├── bitcoin_crew_app_selections.py ├── meeting_preparation.py ├── meeting_summary.py ├── news_examples.py ├── old_aibtcdev_streamlit.py ├── run_crew.py ├── run_managed_crew.py └── tools │ ├── aibtc_token.py │ ├── bun_runner.py │ ├── onchain_resources.py │ ├── wallet.py │ └── web_scraper.py ├── replit.nix └── requirements.txt /.env.example: -------------------------------------------------------------------------------- 1 | # REPLIT SETTINGS 2 | 3 | # USE THE SECRETS TAB ON REPLIT TO INPUT THESE VALUES 4 | 5 | # The .env file is used to store the API keys and other sensitive information for the application when not hosted on Replit. 6 | 7 | # APPLICATION SETTINGS 8 | 9 | # LLM_MODEL=OpenAI 10 | 11 | ## LOCAL MODEL CONFIG 12 | 13 | #OPENAI_API_BASE=http://192.168.0.178:5000/v1 14 | #OPENAI_MODEL_NAME=anything-goes-here 15 | #OPENAI_API_KEY=sk-no-key-needed-leave-as-is 16 | 17 | ## OPENAI CONFIG 18 | 19 | OPENAI_MODEL_NAME=gpt-3.5-turbo 20 | OPENAI_API_KEY=sk-put-your-key-here 21 | 22 | ## LANGSMITH CONFIG (OPTIONAL) 23 | #LANGCHAIN_TRACING_V2=true 24 | #LANGCHAIN_ENDPOINT="https://api.smith.langchain.com" 25 | #LANGCHAIN_API_KEY="lsv2_pt_your-api-key 26 | #LANGCHAIN_PROJECT="project-name" 27 | 28 | # TOOLS SETTINGS 29 | 30 | # testnet or mainnet 31 | NETWORK=testnet 32 | # seed phrase for scripts to use 33 | MNEMONIC=use a twelve or twenty four word seed phrase for the scripts and be sure to keep it safe and never share with anyone 34 | # the index of the account to use for the scripts 35 | # first account = index 0 36 | ACCOUNT_INDEX=0 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new_crew.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New Crew Proposal 3 | about: Propose a new crew with agents, tasks, and execution loop 4 | title: "Crew: " 5 | labels: crew-proposal 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Crew Purpose/Goal 11 | Provide a high-level purpose or goal for this crew. What is the main objective you want to achieve? 12 | 13 | ## Agents 14 | Define the agents that will be part of this crew. Include their roles, goals, backstory, and any specific tools they will use. 15 | 16 | ### Agent 1 17 | - **Role**: [Role of the agent] 18 | - **Goal**: [Goal of the agent] 19 | - **Backstory**: [Backstory of the agent] 20 | - **Tools**: [List of tools] 21 | 22 | ### Agent 2 23 | - **Role**: [Role of the agent] 24 | - **Goal**: [Goal of the agent] 25 | - **Backstory**: [Backstory of the agent] 26 | - **Tools**: [List of tools] 27 | 28 | *(Add more agents as needed)* 29 | 30 | ## Tasks 31 | Define the tasks that need to be accomplished. Include a description, the expected output, the tools to be used, and the agent responsible. 32 | 33 | ### Task 1 34 | - **Description**: [Description of the task] 35 | - **Expected Output**: [Expected output] 36 | - **Tools**: [List of tools] 37 | - **Agent**: [Agent responsible] 38 | 39 | ### Task 2 40 | - **Description**: [Description of the task] 41 | - **Expected Output**: [Expected output] 42 | - **Tools**: [List of tools] 43 | - **Agent**: [Agent responsible] 44 | 45 | *(Add more tasks as needed)* 46 | 47 | ## Execution Loop 48 | Define the execution loop for the crew. How should the tasks be executed? Sequentially, in parallel, or using another process? 49 | 50 | - **Execution Process**: [sequential/parallel/other] 51 | - **Details**: [Additional details about the execution process] 52 | 53 | ## Additional Information 54 | Include any other relevant information or context that might be helpful for understanding the crew proposal. 55 | 56 | ## Submission Checklist 57 | - [ ] High-level purpose/goal of the crew is defined 58 | - [ ] Agents are defined with roles, goals, backstories, and tools 59 | - [ ] Tasks are clearly defined with descriptions, expected outputs, tools, and responsible agents 60 | - [ ] Execution loop is specified 61 | - [ ] Additional relevant information is included 62 | 63 | --- 64 | 65 | Thank you for your proposal! Once submitted, the crew will be reviewed and feedback will be provided. 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /env 2 | .env 3 | __pycache__ 4 | myenv 5 | .flox 6 | .venv/ 7 | shell.nix 8 | chroma 9 | 10 | # generated clarinet files/folders 11 | working_dir 12 | clarinet/bin 13 | clarinet/run-clarinet.sh 14 | clarinet/clarinet-config 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "agent-tools-ts"] 2 | path = agent-tools-ts 3 | url = https://github.com/aibtcdev/agent-tools-ts.git 4 | branch = main 5 | -------------------------------------------------------------------------------- /.replit: -------------------------------------------------------------------------------- 1 | entrypoint = "aibtc-v1/app.py" 2 | 3 | run = "bash $PWD/clarinet/setup-clarinet.sh && pip install -U -r $PWD/requirements.txt && streamlit run --server.headless true aibtc-v1/app.py" 4 | 5 | modules = ["python-3.11", "nodejs-18"] 6 | 7 | hidden = [".pythonlibs", ".streamlit"] 8 | 9 | [nix] 10 | channel = "stable-24_05" 11 | 12 | [deployment] 13 | build = ["sh", "-c", "bash $PWD/clarinet/setup-clarinet.sh && pip install -U -r $PWD/requirements.txt"] 14 | run = ["sh", "-c", "streamlit run --server.address 0.0.0.0 --server.headless true --server.runOnSave false aibtc-v1/app.py -- --server.enableCORS false --server.enableWebsocketCompression false"] 15 | ignorePorts = false 16 | deploymentTarget = "cloudrun" 17 | 18 | [[ports]] 19 | localPort = 8501 20 | externalPort = 80 21 | -------------------------------------------------------------------------------- /.streamlit/config.toml: -------------------------------------------------------------------------------- 1 | [theme] 2 | primaryColor = "#FF4F03" 3 | backgroundColor = "#000000" 4 | secondaryBackgroundColor = "#58595B" 5 | textColor = "#FFFFFF" 6 | # font="sans serif" 7 | [browser] 8 | gatherUsageStats = false 9 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to AIBTC AI Agent Crew 2 | 3 | We're excited that you're interested in contributing to the AIBTC AI Agent Crews! This document provides guidelines for contributing to make the process smooth and effective for everyone involved. 4 | 5 | ## How to Contribute 6 | 7 | ### Reporting Issues 8 | 9 | - Check if the issue has already been reported in the [GitHub Issues](https://github.com/aibtcdev/ai-agent-crew/issues). 10 | - If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/aibtcdev/ai-agent-crew/issues/new). 11 | - Clearly describe the issue, including steps to reproduce when it is a bug. 12 | 13 | ### Suggesting Enhancements 14 | 15 | - Open a new issue with a clear title and detailed description of the suggested enhancement. 16 | - Provide any relevant examples or mock-ups if possible. 17 | 18 | ### Pull Requests 19 | 20 | 1. Fork the repository and create your branch from `main`. 21 | 2. If you've added code that should be tested, add tests. 22 | 3. Ensure your code follows the existing style guidelines. 23 | 4. Make sure your code lints. 24 | 5. Issue a pull request! 25 | 26 | ## Development Setup 27 | 28 | 1. Clone the repository: 29 | 30 | ``` 31 | git clone --recurse-submodules https://github.com/aibtcdev/ai-agent-crew.git 32 | ``` 33 | 34 | 2. Set up a virtual environment: 35 | 36 | ``` 37 | conda create -n ai-agent-crew python=3.11 38 | conda activate ai-agent-crew 39 | ``` 40 | 41 | 3. Install dependencies: 42 | 43 | ``` 44 | pip install -r requirements.txt 45 | ``` 46 | 47 | 4. Copy `.env.example` to `.env` and fill in your API keys and other configuration. 48 | 49 | 5. Set up the agent-tools-ts submodule: 50 | 51 | Follow the setup instructions in the `agent-tools-ts/README.md`, excluding the `.env` instructions which are handled in the top-level `ai-agent-crew` files. 52 | 53 | ## Project Structure 54 | 55 | - `aibtc-v1/app.py`: Main Streamlit application 56 | - `aibtc-v1/crews/`: AI agent crews 57 | - `aibtc-v1/components/`: Streamlit UI components 58 | - `aibtc-v1/utils/`: Utility functions and classes 59 | - `agent-tools-ts/`: Submodule for TypeScript blockchain tools 60 | 61 | ## Adding a New Crew 62 | 63 | To add a new crew: 64 | 65 | 1. Create a new Python file in the `aibtc-v1/crews/` directory. 66 | 2. Define a new class that inherits from `AIBTC_Crew` in `aibtc-v1/utils/crews.py`. 67 | 3. Implement the required methods: `setup_agents()`, `setup_tasks()`, and `render_crew()`. 68 | 4. Update the `aibtc-v1/utils/session.py` file to include your new crew in the `generate_crew_mapping()` function. 69 | 70 | ## Coding Standards 71 | 72 | - Follow [PEP 8](https://www.python.org/dev/peps/pep-0008/) for Python code style. 73 | - Use type hints for function arguments and return values. 74 | - Write docstrings for all functions, classes, and modules. 75 | - Keep functions small and focused on a single task. 76 | - Use meaningful variable and function names. 77 | 78 | ## Documentation 79 | 80 | - Update the README.md if you change functionality. 81 | - Document new features, commands, or significant changes. 82 | - Keep code comments up-to-date. 83 | 84 | ## Commit Messages 85 | 86 | - Use clear and meaningful commit messages. 87 | - Start the commit message with a short summary (up to 50 characters). 88 | - If necessary, add a detailed description after a blank line. 89 | 90 | ## Pull Request Process 91 | 92 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a build. 93 | 2. Update the README.md with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations, and container parameters. 94 | 3. Submit a pull request that clearly describes the changes for maintainers to review. 95 | 96 | ## Questions? 97 | 98 | If you have any questions about contributing, feel free to ask in the [AIBTC Discord](https://discord.gg/Z59Z3FNbEX) or reach out to us on Twitter [@aibtcdev](https://x.com/aibtcdev). 99 | 100 | Thank you for your interest in improving AIBTC AI Agent Crew! 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AIBTC Working Group Logo 2 | 3 | # AIBTC AI Agent Crew 4 | 5 | > [!IMPORTANT] 6 | > This repo is now deprecated in favor of: 7 | > - a TS front-end with Next.js at [aibtcdev-frontend](https://github.com/aibtcdev/aibtcdev-frontend) 8 | > - a Python back-end with CrewAI at [aibtcdev-backend](https://github.com/aibtcdev/aibtcdev-backend) 9 | > 10 | > Be sure to follow along with the latest [on our X account](https://x.com/aibtcdev) and [join our Discord](https://discord.gg/Z59Z3FNbEX)! 11 | 12 | ## Description 13 | 14 | > [!CAUTION] 15 | > This is an early experiment, agents do automatic things, here be dragons, run at your own risk. 16 | 17 | AIBTC AI Agent Crew is a Python-based project that leverages AI agents to perform various tasks related to Bitcoin and the Stacks blockchain. It provides a Streamlit user interface for interacting with these AI agents and visualizing their outputs. 18 | 19 | The project uses the [CrewAI framework](https://crewai.com) to create and manage AI agents, tasks, and tools. It integrates with the `agent-tools-ts` submodule to perform low-level blockchain operations. 20 | 21 | ## Key Features 22 | 23 | Streamlit UI for easy interaction with AI agents 24 | Multiple specialized crews for different blockchain-related tasks 25 | Integration with various LLM providers (OpenAI, Anthropic, Ollama) 26 | Extensible architecture for adding new crews and tools 27 | 28 | ## Development 29 | 30 | ### Tech Stack 31 | 32 | - Python 3.11 33 | - Streamlit for the user interface 34 | - CrewAI and CrewAI Tools for AI agent management 35 | - Langchain for language model interactions 36 | - Bun.js (via submodule) for TypeScript-based blockchain tools 37 | 38 | ### Prerequisites 39 | 40 | - Python 3.11 (virtual environment recommended) 41 | - Git 42 | 43 | ### Installation 44 | 45 | 1. Clone the repository with submodules: 46 | 47 | ``` 48 | git clone --recurse-submodules https://github.com/aibtcdev/ai-agent-crew.git 49 | cd ai-agent-crew 50 | ``` 51 | 52 | 2. Create and activate a virtual environment (using [miniconda](https://docs.anaconda.com/miniconda/)): 53 | 54 | ``` 55 | conda create -n ai-agent-crew python=3.11 56 | conda activate ai-agent-crew 57 | ``` 58 | 59 | 3. Install dependencies: 60 | 61 | ``` 62 | pip install -r requirements.txt 63 | ``` 64 | 65 | 4. Set up the `agent-tools-ts` submodule: 66 | 67 | Follow the setup instructions in the [agent-tools-ts README](./agent-tools-ts/README.md) to install Bun.js 68 | 69 | ### Configuration 70 | 71 | 1. Copy the .env.example file to .env: 72 | 73 | ``` 74 | cp .env.example .env 75 | ``` 76 | 77 | 2. Edit the `.env` file to set your API keys and other configuration options. 78 | 79 | ### Usage 80 | 81 | To run the Streamlit app: 82 | 83 | ``` 84 | streamlit run aibtc-v1/app.py 85 | ``` 86 | 87 | This will start the Streamlit server and open the application in your default web browser. 88 | 89 | ### Project Structure 90 | 91 | `aibtc-v1/app.py`: Main Streamlit application entry point 92 | `aibtc-v1/crews/`: Contains different AI agent crews (e.g., `SmartContractAnalyzerCrew`, `WalletSummaryCrew`) 93 | `aibtc-v1/components/`: Streamlit UI components for different tabs 94 | `aibtc-v1/utils/`: Utility functions and classes 95 | `agent-tools-ts/`: Submodule for TypeScript-based blockchain tools 96 | 97 | ### Adding New Crews 98 | 99 | To add a new crew: 100 | 101 | 1. Create a new Python file in the `aibtc-v1/crews/` directory. 102 | 2. Define a new class that inherits from `AIBTC_Crew` in `aibtc-v1/utils/crews.py`. 103 | 3. Implement the required methods: `setup_agents()`, `setup_tasks()`, and `render_crew()`. 104 | 4. Update the `aibtc-v1/utils/session.py` file to include your new crew in the `generate_crew_mapping()` function. 105 | 106 | ### Setting up the Wallet 107 | 108 | This repository also imports the `aibtcdev/agent-tools-ts` repository as a submodule. 109 | 110 | This provides TypeScript functions to interact with a Stacks wallet using Stacks.js. 111 | 112 | To update the submodule, run the following command: 113 | `git submodule update --remote --merge` 114 | 115 | Within the `scripts` directory is a `.env.example` file, you can disregard it as the top-level `.env.example` file for this repository covers all the needed values. 116 | 117 | Within the `scripts/src` directory are various scripts that can be run to interact with the wallet tooling. These should be wrapped as a CrewAI `@tool` for LLMs to access it. 118 | 119 | ## Contributing 120 | 121 | We welcome contributions! Please see our [CONTRIBUTING.md](./CONTRIBUTING.md) file for details on how to get started. 122 | 123 | ## Contact 124 | 125 | If you have any questions about contributing, please open an issue, ask in the [AIBTC Discord](https://discord.gg/Z59Z3FNbEX) or reach out to us on X [@aibtcdev](https://x.com/aibtcdev). 126 | -------------------------------------------------------------------------------- /aibtc-v1/app.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from components.agents_tab import render_agents_tab 3 | from components.execution_tab import render_execution_tab 4 | from components.tasks_tab import render_tasks_tab 5 | from components.tools_tab import render_tools_tab 6 | from crews.user_chat_specialist import render_crew 7 | from utils.session import init_session_state 8 | 9 | 10 | # set up streamlit page 11 | st.set_page_config( 12 | page_title="AIBTC Crews", 13 | layout="wide", 14 | ) 15 | 16 | # custom css styling 17 | custom_styles = """ 18 | 172 | """ 173 | st.write(custom_styles, unsafe_allow_html=True) 174 | 175 | 176 | # initialize session state 177 | init_session_state() 178 | 179 | 180 | # Display logo full width 181 | st.image( 182 | "https://aibtc.dev/logos/aibtcdev-primary-logo-white-wide-1000px.png", 183 | use_column_width=True, 184 | ) 185 | 186 | # Add icon links 187 | icon_links_html = """ 188 | 208 | """ 209 | 210 | # moved below the image for chat input 211 | st.divider() 212 | st.markdown(icon_links_html, unsafe_allow_html=True) 213 | st.divider() 214 | 215 | 216 | # initialize crew selections 217 | # available_crews = list(st.session_state.crew_mapping.keys()) 218 | 219 | # Display crew selection 220 | # crew_selection = st.selectbox("Select your crew:", available_crews) 221 | 222 | # Main layout with tabs 223 | # tab1, tab2, tab3, tab4 = st.tabs(["Run 🏃", "Agents", "Tools", "Tasks"]) 224 | 225 | # with tab1: 226 | # render_execution_tab(crew_selection) 227 | 228 | # with tab2: 229 | # render_agents_tab(crew_selection) 230 | 231 | # with tab3: 232 | # render_tools_tab(crew_selection) 233 | 234 | # with tab4: 235 | # render_tasks_tab(crew_selection) 236 | 237 | # render just execution page with one crew 238 | # render_execution_tab("User Chat Specialist") 239 | 240 | # render the crew directly outside class def 241 | render_crew() 242 | -------------------------------------------------------------------------------- /aibtc-v1/chat.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | import logging 3 | from typing import Dict, Any 4 | from utils.session import init_session_state 5 | 6 | # Initialize session state 7 | init_session_state() 8 | 9 | # Set up Streamlit page 10 | st.set_page_config(page_title="AIBTC Chatbot", layout="centered") 11 | 12 | # Constants 13 | AVAILABLE_CREWS: Dict[str, Dict[str, Any]] = st.session_state.crew_mapping 14 | 15 | 16 | def load_custom_styles(): 17 | custom_styles = """ 18 | 155 | """ 156 | st.write(custom_styles, unsafe_allow_html=True) 157 | 158 | 159 | def generate_initial_welcome_message() -> str: 160 | message = "Welcome to AIBTC! I can help you run different crews of agents. Here are the available options:\n\n" 161 | message += "\n".join( 162 | f"- **{name}**: {info['description']}" for name, info in AVAILABLE_CREWS.items() 163 | ) 164 | message += "\n\nYou can ask me more about any of these or tell me what you want to do, and I'll recommend a crew to run." 165 | return message 166 | 167 | 168 | INITIAL_WELCOME_MESSAGE = generate_initial_welcome_message() 169 | 170 | 171 | def initialize_session_state(): 172 | if st.session_state.messages == []: 173 | st.session_state.messages = [ 174 | {"role": "Bot", "content": INITIAL_WELCOME_MESSAGE} 175 | ] 176 | if "crew_selected" not in st.session_state: 177 | st.session_state.crew_selected = None 178 | if "conversation_context" not in st.session_state: 179 | st.session_state.conversation_context = "awaiting_selection" 180 | if "crew_step_container" not in st.session_state: 181 | st.session_state.crew_step_container = st.empty() 182 | if "crew_task_container" not in st.session_state: 183 | st.session_state.crew_task_container = st.empty() 184 | if "crew_step_callback" not in st.session_state: 185 | st.session_state.crew_step_callback = [] 186 | if "crew_task_callback" not in st.session_state: 187 | st.session_state.crew_task_callback = [] 188 | 189 | 190 | def add_to_chat(speaker: str, message: str): 191 | st.chat_message(speaker).write(message) 192 | st.session_state.messages.append({"role": speaker, "content": message}) 193 | 194 | 195 | def handle_conversation(user_input: str) -> tuple: 196 | options = "\n".join( 197 | f"- {name}: {info['description']}" for name, info in AVAILABLE_CREWS.items() 198 | ) 199 | messages = [ 200 | { 201 | "role": "system", 202 | "content": ( 203 | "You are a specialized assistant designed to help users select the most appropriate CrewAI for their needs. " 204 | "Your task is to analyze the user's input and determine which CrewAI is most relevant from the following options:\n" 205 | f"{options}\n" 206 | "\nYour response should strictly include the exact name of the relevant CrewAI, " 207 | "followed by any required parameters. " 208 | "Example: Wallet Analysis || SP2SDRD31DZD2477M39Q0GTH18G0WJH4J984JKQE8" 209 | "Do not provide any additional information, explanations, or suggestions. " 210 | "If the user's input is unclear, ask a clarifying question to gather more information." 211 | ), 212 | }, 213 | {"role": "user", "content": user_input}, 214 | ] 215 | 216 | response = st.session_state.llm.call(messages=messages) 217 | 218 | try: 219 | response_content = response 220 | print(response_content) 221 | if "||" in response_content: 222 | crew_name, parameters = map(str.strip, response_content.split("||")) 223 | return crew_name, parameters, response_content 224 | except (KeyError, IndexError, ValueError) as e: 225 | logging.error(f"Error parsing LLM response: {e}") 226 | 227 | return None, None, response 228 | 229 | 230 | def run_crew_ai(crew_name: str, parameters: str) -> str: 231 | st.write("Step Progress:") 232 | st.session_state.crew_step_container = st.empty() 233 | st.write("Task Progress:") 234 | st.session_state.crew_task_container = st.empty() 235 | st.session_state.crew_step_callback = [] 236 | st.session_state.crew_task_callback = [] 237 | 238 | crew_class = AVAILABLE_CREWS.get(crew_name, {}).get("class") 239 | if not crew_class: 240 | return f"CrewAI {crew_name} is not implemented yet." 241 | 242 | crew_instance = crew_class(st.session_state.embedder) 243 | crew_instance.setup_agents(st.session_state.llm) 244 | crew_instance.setup_tasks(parameters) 245 | crew = crew_instance.create_crew() 246 | 247 | with st.spinner(f"Running {crew_name} CrewAI..."): 248 | result = crew.kickoff() 249 | 250 | st.success(f"Execution complete for {crew_name}!") 251 | st.subheader("Analysis Results") 252 | return f"Execution complete for {crew_name} CrewAI. Results: {result.raw}" 253 | 254 | 255 | def handle_user_input(user_input: str): 256 | context = st.session_state.conversation_context 257 | 258 | if context == "awaiting_selection": 259 | crew_name, parameters, response = handle_conversation(user_input) 260 | print(crew_name) 261 | if crew_name: 262 | add_to_chat( 263 | "Bot", 264 | f"Great! Executing the {crew_name} CrewAI with parameters: {parameters}...", 265 | ) 266 | try: 267 | crew_output = run_crew_ai(crew_name, parameters) 268 | add_to_chat("Bot", f"**{crew_name} Output:**\n{crew_output}") 269 | except Exception as e: 270 | logging.error(f"Error executing CrewAI: {e}") 271 | add_to_chat( 272 | "Bot", "There was an error executing the CrewAI. Please try again." 273 | ) 274 | st.session_state.crew_selected = crew_name 275 | st.session_state.conversation_context = "crew_executed" 276 | else: 277 | add_to_chat("Bot", response) 278 | 279 | elif context == "crew_executed": 280 | add_to_chat( 281 | "Bot", 282 | "I've executed the CrewAI you selected. Would you like to run another CrewAI or discuss the results?", 283 | ) 284 | st.session_state.conversation_context = "awaiting_selection" 285 | 286 | 287 | def main(): 288 | st.title("AIBTC.DEV Chatbot") 289 | load_custom_styles() 290 | initialize_session_state() 291 | 292 | for msg in st.session_state.messages: 293 | st.chat_message(msg["role"]).write(msg["content"]) 294 | 295 | user_input = st.chat_input("Type your message here...") 296 | 297 | if user_input: 298 | add_to_chat("User", user_input) 299 | handle_user_input(user_input) 300 | 301 | 302 | if __name__ == "__main__": 303 | main() 304 | -------------------------------------------------------------------------------- /aibtc-v1/components/agents_tab.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import streamlit as st 3 | from utils.session import get_crew_class 4 | 5 | 6 | def render_agents_tab(crew_selection): 7 | crew_class = get_crew_class(crew_selection) 8 | if crew_class is None: 9 | st.warning( 10 | f"No crew found for {crew_selection}. Please check your crew definitions." 11 | ) 12 | return 13 | 14 | crew_instance = crew_class() 15 | crew_instance.setup_agents(st.session_state.llm) 16 | 17 | if not crew_instance.agents: 18 | st.warning( 19 | f"No agents found for {crew_selection}. Please check your crew definition." 20 | ) 21 | else: 22 | for agent in crew_instance.agents: 23 | with st.container(): 24 | try: 25 | st.markdown(f"#### {agent.role}") 26 | st.markdown(f"**Goal:** {agent.goal}") 27 | st.markdown(f"**Backstory:** {agent.backstory}") 28 | 29 | tool_data = [] 30 | for tool in agent.tools: 31 | tool_name = tool.name if hasattr(tool, "name") else str(tool) 32 | tool_data.append({"Tool": tool_name}) 33 | 34 | if tool_data: 35 | df = pd.DataFrame(tool_data) 36 | st.dataframe( 37 | df, 38 | column_config={ 39 | "Tool": st.column_config.TextColumn( 40 | "Tool", 41 | width="medium", 42 | help="Name of the tool", 43 | ), 44 | }, 45 | hide_index=True, 46 | use_container_width=True, 47 | ) 48 | else: 49 | st.write("No tools available for this agent.") 50 | except Exception as e: 51 | st.error(f"Error displaying agent {agent.role}: {str(e)}") 52 | 53 | st.markdown("---") 54 | -------------------------------------------------------------------------------- /aibtc-v1/components/execution_tab.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from utils.session import get_crew_class 3 | 4 | 5 | def render_execution_tab(crew_selection): 6 | crew_class = get_crew_class(crew_selection) 7 | 8 | if crew_class is None: 9 | st.warning( 10 | f"No crew found for {crew_selection}. Please check your crew definitions." 11 | ) 12 | return 13 | 14 | try: 15 | # Create an instance of the crew class and call its render_crew method 16 | crew_instance = crew_class() 17 | crew_instance.render_crew() 18 | except AttributeError: 19 | st.error( 20 | f"The selected crew '{crew_selection}' doesn't have a render_crew method." 21 | ) 22 | except Exception as e: 23 | st.error(f"An error occurred while rendering the crew: {str(e)}") 24 | -------------------------------------------------------------------------------- /aibtc-v1/components/tasks_tab.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from utils.session import get_crew_class, get_crew_inputs 3 | 4 | 5 | def render_tasks_tab(crew_selection): 6 | crew_class = get_crew_class(crew_selection) 7 | if crew_class is None: 8 | st.warning( 9 | f"No crew found for {crew_selection}. Please check your crew definitions." 10 | ) 11 | return 12 | 13 | input_names = get_crew_inputs(crew_selection) 14 | 15 | # Create an instance of the crew 16 | crew_instance = crew_class() 17 | 18 | # Create mock data 19 | mock_data = {input_name: f"mock_{input_name}" for input_name in input_names} 20 | 21 | # Pass the mock data to the setup_tasks method 22 | llm = st.session_state.llm 23 | crew_instance.setup_agents(llm) 24 | crew_instance.setup_tasks(**mock_data) 25 | 26 | if hasattr(crew_instance, "tasks") and crew_instance.tasks: 27 | for i, task in enumerate(crew_instance.tasks, 1): 28 | st.markdown(f"#### Task {i}") 29 | st.markdown(f"{task.description}") 30 | st.markdown(f"*Expected Output:* {task.expected_output}") 31 | st.markdown("---") 32 | else: 33 | st.error("No tasks have been set up for this crew.") 34 | -------------------------------------------------------------------------------- /aibtc-v1/components/tools_tab.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import re 3 | import streamlit as st 4 | from utils.session import get_crew_class 5 | 6 | 7 | def extract_bun_run_command(source: str) -> str: 8 | lines = source.split("\n") 9 | bun_run_lines = [] 10 | in_bun_run = False 11 | parentheses_count = 0 12 | 13 | for line in lines: 14 | if "BunScriptRunner.bun_run" in line: 15 | in_bun_run = True 16 | 17 | if in_bun_run: 18 | bun_run_lines.append(line.strip()) 19 | parentheses_count += line.count("(") - line.count(")") 20 | 21 | if parentheses_count == 0: 22 | break 23 | 24 | joined_command = " ".join(bun_run_lines) 25 | 26 | # normalize spacing 27 | normalized_command = re.sub(r"\s*([(),])\s*", r"\1 ", joined_command) 28 | normalized_command = re.sub(r"\s+", " ", normalized_command) 29 | normalized_command = normalized_command.replace("( ", "(").replace(" )", ")") 30 | 31 | return normalized_command.strip() 32 | 33 | 34 | def render_tools_tab(crew_selection): 35 | crew_class = get_crew_class(crew_selection) 36 | 37 | if crew_class is None: 38 | st.warning( 39 | f"No crew found for {crew_selection}. Please check your crew definitions." 40 | ) 41 | return 42 | 43 | try: 44 | tools = crew_class.get_all_tools() 45 | except Exception as e: 46 | st.error(f"Error getting tools: {str(e)}") 47 | tools = [] 48 | 49 | if not tools: 50 | st.error("No tools found for this crew.") 51 | else: 52 | for tool in tools: 53 | st.markdown(f"#### {tool.name}") 54 | st.write(f"**Description:**: {tool.description}") 55 | # get the function signature 56 | sig = inspect.signature(tool.func) 57 | params = sig.parameters 58 | 59 | if params: 60 | st.write("**Arguments:**") 61 | for param_name, param in params.items(): 62 | if param_name == "dummy_arg": 63 | st.write(f"(none)") 64 | else: 65 | st.write( 66 | f"- {param_name}: {param.annotation.__name__ if param.annotation != inspect.Parameter.empty else 'Any'}" 67 | ) 68 | else: 69 | st.write("**Arguments:** No arguments") 70 | st.markdown("---") 71 | -------------------------------------------------------------------------------- /aibtc-v1/crews/clarity_code_generator_v2.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import os 3 | import streamlit as st 4 | from crewai import Agent, Task 5 | from crewai_tools import tool, Tool 6 | from textwrap import dedent 7 | from utils.clarinet import ClarinetInterface 8 | from utils.clarity import clarityFunctionsList, clarityHints, clarityKeywordsList 9 | from utils.crews import AIBTC_Crew, display_token_usage 10 | from utils.scripts import get_timestamp 11 | 12 | 13 | class ClarityCodeGeneratorCrewV2(AIBTC_Crew): 14 | def __init__(self, embedder): 15 | super().__init__( 16 | "Clarity Code Generator V2", 17 | "Generate Clarity code for a smart contract on the Stacks blockchain.", 18 | embedder, 19 | ) 20 | 21 | def setup_agents(self, llm): 22 | clarity_environment_maintainer = Agent( 23 | role="Clarity Environment Maintainer", 24 | goal="Ensure the Clarity environment is set up correctly and ready for code generation and review.", 25 | backstory=dedent( 26 | "You are responsible for maintaining the Clarity environment, ensuring that all tools and dependencies are correctly installed and configured. " 27 | "Your goal is to provide a stable and reliable environment for generating and reviewing Clarity code." 28 | ), 29 | tools=[AgentTools.initialize_clarinet], 30 | allow_delegation=False, 31 | memory=True, 32 | verbose=True, 33 | llm=llm, 34 | ) 35 | self.add_agent(clarity_environment_maintainer) 36 | 37 | clarity_project_manager = Agent( 38 | role="Clarity Project Manager", 39 | goal="Create a new Clarinet project and add the generated Clarity code to it.", 40 | backstory=dedent( 41 | "You are a skilled project manager with expertise in setting up Clarinet projects for smart contract development.", 42 | ), 43 | tools=[ 44 | AgentTools.create_clarinet_project, 45 | ], 46 | allow_delegation=False, 47 | memory=True, 48 | verbose=True, 49 | llm=llm, 50 | ) 51 | self.add_agent(clarity_project_manager) 52 | 53 | clarity_code_generator = Agent( 54 | role="Clarity Code Generator", 55 | goal="Generate Clarity code for a smart contract on the Stacks blockchain based on user input requirements.", 56 | backstory=dedent( 57 | "You are an expert in Clarity, a smart contract language for the Stacks blockchain. " 58 | "Your goal is to write secure, efficient, and functional Clarity code based on specific user requirements. " 59 | "You should tailor your code generation to meet the exact needs described in the user input. " 60 | f"Remember to follow the Clarity hints for best practices:\n{clarityHints}" 61 | f"{clarityKeywordsList}" 62 | f"{clarityFunctionsList}" 63 | ), 64 | tools=[AgentTools.add_new_smart_contract, AgentTools.update_smart_contract], 65 | allow_delegation=False, 66 | memory=True, 67 | verbose=True, 68 | llm=llm, 69 | ) 70 | self.add_agent(clarity_code_generator) 71 | 72 | clarity_code_reviewer = Agent( 73 | role="Clarity Code Reviewer", 74 | goal="Review the generated Clarity code, create a Clarinet project, and check its syntax.", 75 | backstory=dedent( 76 | "You are a meticulous Clarity code reviewer known for ensuring smart contract security and code quality on the Stacks blockchain. " 77 | "Your goal is to analyze the generated code by checking the syntax, providing detailed feedback on any issues found. " 78 | "If you encounter issues, provide detailed context and ask the Clarity Code Generator to update the contract. " 79 | "Do not continue until the code passes the syntax check. " 80 | f"Remember to follow the Clarity hints for best practices:\n{clarityHints}" 81 | ), 82 | tools=[ 83 | AgentTools.check_all_smart_contract_syntax, 84 | ], 85 | allow_delegation=True, 86 | memory=True, 87 | verbose=True, 88 | llm=llm, 89 | ) 90 | self.add_agent(clarity_code_reviewer) 91 | 92 | clarity_code_reporter = Agent( 93 | role="Clarity Code Reporter", 94 | goal="Create a detailed report on the code quality, syntax check results, and any issues found.", 95 | backstory=dedent( 96 | "You are a skilled Clarity code reporter, responsible for creating detailed reports on the quality and syntax of Clarity code. " 97 | "Your goal is to provide a comprehensive analysis of the code review results, highlighting any issues found and suggesting improvements." 98 | "You ensure that the output clearly presents both the code and its review in a user-friendly Markdown format." 99 | f"Remember to follow the Clarity hints for best practices:\n{clarityHints}" 100 | ), 101 | tools=[], 102 | allow_delegation=False, 103 | memory=True, 104 | verbose=True, 105 | llm=llm, 106 | ) 107 | self.add_agent(clarity_code_reporter) 108 | 109 | def setup_tasks(self, user_input): 110 | setup_clarinet_environment = Task( 111 | description="Initialize the Clarinet environment to ensure all tools and dependencies are correctly set up.", 112 | expected_output="A confirmation that the Clarinet environment has been successfully initialized.", 113 | agent=self.agents[0], # clarity_environment_maintainer 114 | ) 115 | self.add_task(setup_clarinet_environment) 116 | 117 | create_clarinet_project = Task( 118 | description=f"Create a new Clarinet project to manage the generated Clarity code based on the user's input: {user_input}", 119 | expected_output="A confirmation that the Clarinet project has been successfully created.", 120 | agent=self.agents[1], # clarity_project_manager 121 | ) 122 | self.add_task(create_clarinet_project) 123 | 124 | generate_clarity_code = Task( 125 | description=( 126 | f"Generate a Clarity code snippet for a smart contract on the Stacks blockchain based on the following user requirements: {user_input}. " 127 | "Ensure the code is secure, efficient, and properly handles exceptions. " 128 | "Store the generated code using your tools to create a new smart contract." 129 | ), 130 | expected_output="The generated Clarity code snippet for the smart contract, saved in the Clarinet project.", 131 | agent=self.agents[2], # clarity_code_generator 132 | ) 133 | self.add_task(generate_clarity_code) 134 | 135 | # TODO: check for and add requirements 136 | # needs to be able to get all requirements currently in project 137 | # needs to be able to add requirements if needed before syntax check 138 | # might also be callable from reviewer if issue found in syntax check 139 | 140 | review_clarity_code = Task( 141 | description=( 142 | "Review the generated Clarity code by checking its syntax using your tools. " 143 | "Provide a detailed report on the code quality, syntax check results, and any issues found. " 144 | f"Consider how well the code meets the original user requirements: {user_input}. " 145 | "Delegate to the Clarity Code Generator until the code passes the syntax check." 146 | ), 147 | expected_output="Once the syntax check passes, a detailed report on the code quality, syntax check results, and any issues found.", 148 | agent=self.agents[3], # clarity_code_reviewer 149 | context=[generate_clarity_code], 150 | ) 151 | self.add_task(review_clarity_code) 152 | 153 | compile_clarity_code_report = Task( 154 | description=( 155 | "Combine the generated Clarity code and the code review report into a comprehensive output that can be displayed in the Streamlit app. " 156 | f"Ensure that the output clearly shows how the code meets the original user requirements: {user_input}. " 157 | ), 158 | expected_output="The final output that includes the Clarity code, the code review report, and how it addresses the user's requirements.", 159 | agent=self.agents[4], # clarity_code_reporter 160 | context=[generate_clarity_code, review_clarity_code], 161 | ) 162 | self.add_task(compile_clarity_code_report) 163 | 164 | @staticmethod 165 | def get_task_inputs(): 166 | return ["user_input"] 167 | 168 | @classmethod 169 | def get_all_tools(cls): 170 | return AgentTools.get_all_tools() 171 | 172 | def render_crew(self): 173 | st.subheader("Clarity Code Generator V2 🧙") 174 | st.markdown( 175 | "Generate valid Clarity code for a smart contract on the Stacks blockchain based on user input requirements." 176 | ) 177 | 178 | with st.form("clarity_code_generator_form"): 179 | user_input = st.text_input( 180 | "Smart Contract Requirements", 181 | help="Enter your smart contract requirements", 182 | placeholder="Implement a function called `calculate-average` that takes a list of unsigned integers and returns the average as a response type. Handle the case where the list is empty.", 183 | ) 184 | submitted = st.form_submit_button("Generate Clarity Code") 185 | 186 | if submitted and user_input: 187 | st.subheader("Clarity Code Generation Progress") 188 | try: 189 | # create containers for real-time updates 190 | st.write("Tool Outputs:") 191 | st.session_state.crew_step_container = st.empty() 192 | st.write("Task Progress:") 193 | st.session_state.crew_task_container = st.empty() 194 | 195 | # reset callback lists 196 | st.session_state.crew_step_callback = [] 197 | st.session_state.crew_task_callback = [] 198 | 199 | # get LLM from session state 200 | llm = st.session_state.llm 201 | 202 | # create and run the crew 203 | print("Creating Clarity Code Generator V2 Crew...") 204 | clarity_code_generator_crew_class = ClarityCodeGeneratorCrewV2() 205 | clarity_code_generator_crew_class.setup_agents(llm) 206 | clarity_code_generator_crew_class.setup_tasks(user_input) 207 | clarity_code_generator_crew = ( 208 | clarity_code_generator_crew_class.create_crew() 209 | ) 210 | 211 | with st.spinner("Generating Clarity code..."): 212 | print("Running Clarity Code Generator V2 Crew...") 213 | result = clarity_code_generator_crew.kickoff() 214 | 215 | st.success("Code generation complete!") 216 | 217 | display_token_usage(result.token_usage) 218 | 219 | st.subheader("Clarity Code Generation Results") 220 | 221 | result_str = str(result.raw) 222 | st.markdown(result_str) 223 | 224 | timestamp = get_timestamp() 225 | file_name = f"{timestamp}_generated_clarity_code.clar" 226 | 227 | st.download_button( 228 | label="Download Clarity Code (Text)", 229 | data=result_str, 230 | file_name=file_name, 231 | mime="text/plain", 232 | ) 233 | except Exception as e: 234 | st.error(f"Error during code generation: {e}") 235 | st.error("Please check your inputs and try again.") 236 | else: 237 | st.write( 238 | "Please enter your smart contract requirements and click 'Generate Clarity Code'." 239 | ) 240 | 241 | 242 | ######################### 243 | # Agent Tools 244 | ######################### 245 | 246 | 247 | class AgentTools: 248 | clarinet_interface = None # hodls ClarinetInterface instance 249 | 250 | @staticmethod 251 | @tool("Initialize Clarinet") 252 | def initialize_clarinet() -> str: 253 | """Initialize Clarinet by detecting the Clarinet binary and setting up the environment.""" 254 | AgentTools.clarinet_interface = ClarinetInterface() 255 | try: 256 | AgentTools.clarinet_interface.initialize_clarinet() 257 | return "Clarinet initialized successfully." 258 | except Exception as e: 259 | return f"Error initializing Clarinet: {str(e)}" 260 | 261 | @staticmethod 262 | @tool("Create New Clarinet Project") 263 | def create_clarinet_project(project_name: str) -> str: 264 | """Create a new Clarinet project with the given name.""" 265 | if not AgentTools.clarinet_interface: 266 | return ( 267 | "Error: Clarinet is not initialized. Please initialize Clarinet first." 268 | ) 269 | result = AgentTools.clarinet_interface.create_project(project_name) 270 | if result["returncode"] != 0: 271 | return f"Error creating Clarinet project: {result['stdout'] + result['stderr']}" 272 | return f"Successfully created new Clarinet project: {project_name}\n{result['stdout']}" 273 | 274 | @staticmethod 275 | @tool("Add New Smart Contract") 276 | def add_new_smart_contract(contract_name: str, contract_code: str) -> str: 277 | """Add a new smart contract to the Clarinet project with the given name and code.""" 278 | if ( 279 | not AgentTools.clarinet_interface 280 | or not AgentTools.clarinet_interface.project_dir 281 | ): 282 | return "Error: Clarinet project is not created. Please create a Clarinet project first." 283 | result = AgentTools.clarinet_interface.add_contract(contract_name) 284 | if result["returncode"] != 0: 285 | return f"Error adding smart contract: {result['stderr']}" 286 | 287 | # Write the contract code to the contract file 288 | contract_file_path = os.path.join( 289 | AgentTools.clarinet_interface.project_dir, 290 | "contracts", 291 | f"{contract_name}.clar", 292 | ) 293 | try: 294 | with open(contract_file_path, "w") as f: 295 | f.write(contract_code) 296 | return ( 297 | f"Successfully added new contract '{contract_name}'\n{result['stdout']}" 298 | ) 299 | except Exception as e: 300 | return f"Error writing contract code: {str(e)}" 301 | 302 | @staticmethod 303 | @tool("Update Smart Contract") 304 | def update_smart_contract(contract_name: str, contract_code: str) -> str: 305 | """Update an existing smart contract in the Clarinet project with the given name and code.""" 306 | if ( 307 | not AgentTools.clarinet_interface 308 | or not AgentTools.clarinet_interface.project_dir 309 | ): 310 | return "Error: Clarinet project is not created. Please create a Clarinet project first." 311 | result = AgentTools.clarinet_interface.update_contract( 312 | contract_name, contract_code 313 | ) 314 | if result["returncode"] != 0: 315 | return f"Error updating smart contract: {result['stderr']}" 316 | return f"Successfully updated contract '{contract_name}'\n{result['stdout']}" 317 | 318 | @staticmethod 319 | @tool("Check All Smart Contracts Syntax") 320 | def check_all_smart_contract_syntax() -> str: 321 | """Check the syntax of all of the smart contracts in the Clarinet project.""" 322 | if ( 323 | not AgentTools.clarinet_interface 324 | or not AgentTools.clarinet_interface.project_dir 325 | ): 326 | return "Error: Clarinet project is not created. Please create a Clarinet project first." 327 | result = AgentTools.clarinet_interface.check_all_contracts() 328 | if result["returncode"] != 0: 329 | return f"Syntax errors found:\n{result['stdout']}\n{result['stderr']}" 330 | return f"Syntax check passed:\n{result['stdout']}" 331 | 332 | @staticmethod 333 | @tool("Check Smart Contract Syntax") 334 | def check_single_smart_contract_syntax(contract_name: str) -> str: 335 | """Check the syntax of a specific smart contract in the Clarinet project.""" 336 | if ( 337 | not AgentTools.clarinet_interface 338 | or not AgentTools.clarinet_interface.project_dir 339 | ): 340 | return "Error: Clarinet project is not created. Please create a Clarinet project first." 341 | result = AgentTools.clarinet_interface.check_contract(contract_name) 342 | if result["returncode"] != 0: 343 | return f"Syntax errors found for contract '{contract_name}':\n{result['stdout']}\n{result['stderr']}" 344 | return ( 345 | f"Syntax check passed for contract '{contract_name}':\n{result['stdout']}" 346 | ) 347 | 348 | @staticmethod 349 | @tool("Add Mainnet Contract as Requirement") 350 | def add_mainnet_contract_as_requirement(contract_id: str) -> str: 351 | """Add a mainnet contract as a requirement to the Clarinet project.""" 352 | if ( 353 | not AgentTools.clarinet_interface 354 | or not AgentTools.clarinet_interface.project_dir 355 | ): 356 | return "Error: Clarinet project is not created. Please create a Clarinet project first." 357 | result = AgentTools.clarinet_interface.add_requirement(contract_id) 358 | if result["returncode"] != 0: 359 | return f"Error adding mainnet contract as requirement: {result['stderr']}" 360 | return f"Successfully added mainnet contract '{contract_id}' as requirement.\n{result['stdout']}" 361 | 362 | @classmethod 363 | def get_all_tools(cls): 364 | members = inspect.getmembers(cls) 365 | tools = [ 366 | member 367 | for name, member in members 368 | if isinstance(member, Tool) 369 | or (hasattr(member, "__wrapped__") and isinstance(member.__wrapped__, Tool)) 370 | ] 371 | return tools 372 | -------------------------------------------------------------------------------- /aibtc-v1/crews/trading_analyzer.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import streamlit as st 3 | from crewai import Agent, Task 4 | from crewai_tools import tool, Tool 5 | from textwrap import dedent 6 | from utils.crews import AIBTC_Crew, display_token_usage 7 | import requests 8 | 9 | 10 | # Custom Crew Class for Cryptocurrency Trading 11 | class TradingAnalyzerCrew(AIBTC_Crew): 12 | def __init__(self, embedder): 13 | super().__init__( 14 | "Trading Analyzer", 15 | "This crew analyzes Stacks cryptocurrency price history and provides trading signals.", 16 | embedder, 17 | ) 18 | 19 | def setup_agents(self, llm): 20 | # Agent for pulling market data 21 | market_data_agent = Agent( 22 | role="Market Data Retriever", 23 | goal="Collect historical and real-time price data for the specified cryptocurrency, broken down by Stacks block intervals. Ensure accuracy by retrieving prices from multiple DEXs and identifying anomalies.", 24 | tools=[ 25 | AgentTools.get_crypto_price_history, 26 | AgentTools.get_all_swaps, 27 | AgentTools.get_pool_volume, 28 | ], 29 | backstory=( 30 | "You are a specialized market data retriever with access to various decentralized exchanges (DEXs). " 31 | "Your primary responsibility is to gather accurate historical and real-time price data, format it into structured datasets, " 32 | "and provide granular data at the Stacks block level to support trading strategy analysis." 33 | ), 34 | verbose=True, 35 | llm=llm, 36 | ) 37 | self.add_agent(market_data_agent) 38 | 39 | # Agent for analyzing trading strategies 40 | strategy_analyzer_agent = Agent( 41 | role="Quantitative Trading Strategy Analyzer", 42 | goal="Analyze recent price trends and perform statistical analysis on historical data to identify trading signals. " 43 | "Provide actionable recommendations (Hold, Buy, or Sell) based on moving averages, volatility patterns, and volume changes.", 44 | tools=[], # Add any specific tools if applicable. 45 | backstory=( 46 | "You are a seasoned quantitative trading expert with deep expertise in financial market analysis and strategy development. " 47 | "You specialize in leveraging various technical indicators, such as moving averages, RSI, and MACD, to identify potential trading signals " 48 | "and execute profitable strategies. Your analysis is rooted in a thorough examination of price movements and market dynamics over the last 100 or more blocks." 49 | ), 50 | verbose=True, # Set verbose to False to streamline responses. 51 | llm=llm, 52 | ) 53 | self.add_agent(strategy_analyzer_agent) 54 | 55 | def setup_tasks(self, crypto_symbol): 56 | # Task to retrieve historical volume data 57 | merge_data_task = Task( 58 | description="Merges data from the into a single dataset." 59 | f"Collect the information for token {crypto_symbol} using the tool `Get All Avaliable Token Info`." 60 | f"Data should include the token pool volume using the tool `Get Token Pool Volume` using the pool_id" 61 | f"Data should include prices using the tool `Get Token Price History` using the address", 62 | expected_output=( 63 | "A structured dataset containing volume history, including fields block height, volume, and price. The dataset should be free of gaps and anomalies, ensuring completeness for accurate analysis." 64 | ), 65 | agent=self.agents[0], # market_data_agent 66 | ) 67 | self.add_task(merge_data_task) 68 | 69 | # Task to analyze the price data with a trading strategy 70 | analyze_strategy_task = Task( 71 | description=( 72 | f"Analyze the historical price and volume data of {crypto_symbol} over the last 100 blocks to identify trading signals. " 73 | "Use the following predefined strategies:\n" 74 | "1. **Trend Analysis**: Evaluate using 50-period and 100-period moving averages to detect short-term and long-term trends.\n" 75 | "2. **Volatility Analysis**: Calculate standard deviation and identify any sudden price spikes or drops.\n" 76 | "3. **Volume Analysis**: Check for unusual volume shifts to identify potential breakouts or breakdowns.\n" 77 | "4. **Support and Resistance Levels**: Identify key support and resistance levels based on price patterns.\n" 78 | "5. **Momentum Indicators**: Apply RSI and MACD to detect overbought or oversold conditions.\n\n" 79 | "Based on your analysis, provide a single recommendation: **Buy**, **Sell**, or **Hold**. Include a concise reason for your decision." 80 | ), 81 | expected_output="A recommendation of either 'Buy', 'Sell', or 'Hold', along with a brief explanation justifying your decision based on the analysis.", 82 | agent=self.agents[1], # market_data_agent 83 | ) 84 | self.add_task(analyze_strategy_task) 85 | 86 | @staticmethod 87 | def get_task_inputs(): 88 | return ["crypto_symbol"] 89 | 90 | @classmethod 91 | def get_all_tools(cls): 92 | return AgentTools.get_all_tools() 93 | 94 | def render_crew(self): 95 | st.subheader("Crypto Trading Analysis") 96 | st.markdown( 97 | "This tool will analyze Stacks cryptocurrency price history and provide trading signals." 98 | ) 99 | 100 | with st.form("crypto_trading_form"): 101 | crypto_symbol = st.text_input( 102 | "Cryptocurrency Symbol", 103 | help="Enter the symbol of the cryptocurrency (e.g., ALEX, WELSH, DIKO)", 104 | ) 105 | submitted = st.form_submit_button("Analyze") 106 | 107 | if submitted and crypto_symbol: 108 | st.subheader("Analysis Progress") 109 | 110 | try: 111 | st.write("Step Progress:") 112 | st.session_state.crew_step_container = st.empty() 113 | st.write("Task Progress:") 114 | st.session_state.crew_task_container = st.empty() 115 | 116 | st.session_state.crew_step_callback = [] 117 | st.session_state.crew_task_callback = [] 118 | 119 | llm = st.session_state.llm 120 | 121 | trading_class = TradingAnalyzerCrew() 122 | trading_class.setup_agents(llm) 123 | trading_class.setup_tasks(crypto_symbol) 124 | crypto_trading_crew = trading_class.create_crew() 125 | 126 | with st.spinner("Analyzing..."): 127 | result = crypto_trading_crew.kickoff() 128 | 129 | st.success("Analysis complete!") 130 | 131 | # display_token_usage(result.token_usage) 132 | 133 | st.subheader("Analysis Results") 134 | 135 | # Display results 136 | result_str = str(result.raw) 137 | st.markdown(result_str) 138 | 139 | # Display disclaimer 140 | st.markdown( 141 | """### Disclaimer 142 | The information and recommendations provided on this website are for demonstration purposes only and do not constitute financial advice. Our multi-agent AI system analyzes historical cryptocurrency data to generate buy, sell, or hold suggestions. However, artificial intelligence can produce unexpected or inaccurate results, including hallucinations. These recommendations should not be relied upon for making trading decisions. Always consult with a qualified financial advisor before making any investment decisions. 143 | """ 144 | ) 145 | 146 | except Exception as e: 147 | st.error(f"An error occurred: {str(e)}") 148 | st.write("Please check your inputs and try again.") 149 | else: 150 | st.write( 151 | "Enter Cryptocurrency Symbol, then click 'Analyze' to see results." 152 | ) 153 | 154 | 155 | # Agent Tools 156 | class AgentTools: 157 | @staticmethod 158 | @tool("Get Token Price History") 159 | def get_crypto_price_history(token_address: str): 160 | """Retrieve historical price data for a specified cryptocurrency symbol.""" 161 | url = f"https://api.alexgo.io/v1/price_history/{token_address}?limit=100" 162 | headers = { 163 | "Accept": "application/json", 164 | } 165 | 166 | response = requests.get(url, headers=headers) 167 | 168 | if not response.ok: 169 | raise Exception( 170 | f"Failed to get token price history: {response.status_text}" 171 | ) 172 | 173 | data = response.json() 174 | 175 | price_history = data.get("prices", []) 176 | formatted_history = "\n".join( 177 | f"Block Height: {price['block_height']}, Price: {price['avg_price_usd']}" 178 | for price in price_history 179 | ) 180 | 181 | return f"Token: {data['token']}\n{formatted_history}" 182 | 183 | @staticmethod 184 | @tool("Get All Avaliable Token Info") 185 | def get_all_swaps(): 186 | """Retrieve all swap data from the Alex API and return a formatted string.""" 187 | url = "https://api.alexgo.io/v1/allswaps" 188 | headers = { 189 | "Accept": "application/json", 190 | } 191 | 192 | response = requests.get(url, headers=headers) 193 | 194 | if not response.ok: 195 | raise Exception(f"Failed to get all swaps: {response.status_text}") 196 | 197 | data = response.json() 198 | 199 | formatted_swaps = "\n".join( 200 | dedent( 201 | f"""Pool ID: {swap['id']}, Quote: {swap['quote']}, Symbol: {swap['quoteSymbol']}, Address: {swap['quoteId']}""" 202 | ).strip() 203 | for swap in data 204 | ) 205 | 206 | return formatted_swaps 207 | 208 | @staticmethod 209 | @tool("Get Token Pool Volume History") 210 | def get_pool_volume(pool_token_id: str): 211 | """Retrieve pool volume data for a specified pool token ID.""" 212 | url = f"https://api.alexgo.io/v1/pool_volume/{pool_token_id}?limit=100" 213 | headers = { 214 | "Accept": "application/json", 215 | } 216 | 217 | response = requests.get(url, headers=headers) 218 | 219 | if not response.ok: 220 | raise Exception(f"Failed to get pool volume: {response.status_text}") 221 | 222 | data = response.json() 223 | 224 | volume_values = data.get("volume_values", []) 225 | formatted_volume = "\n".join( 226 | f"Block Height: {volume['block_height']}, Volume: {volume['volume_24h']}" 227 | for volume in volume_values 228 | ) 229 | 230 | return f"Token: {data['token']}\n{formatted_volume}" 231 | 232 | @classmethod 233 | def get_all_tools(cls): 234 | members = inspect.getmembers(cls) 235 | tools = [ 236 | member 237 | for name, member in members 238 | if isinstance(member, Tool) 239 | or (hasattr(member, "__wrapped__") and isinstance(member.__wrapped__, Tool)) 240 | ] 241 | return tools 242 | -------------------------------------------------------------------------------- /aibtc-v1/crews/user_chat_specialist.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import streamlit as st 3 | from crewai import Agent, Task 4 | from crewai.agents.parser import AgentAction 5 | from crewai.tasks.task_output import TaskOutput 6 | from crewai_tools import tool, Tool 7 | from textwrap import dedent 8 | from crews.smart_contract_analyzer_v2 import SmartContractAnalyzerV2 9 | from crews.wallet_summarizer import WalletSummaryCrew 10 | from crews.trading_analyzer import TradingAnalyzerCrew 11 | from crews.clarity_code_generator_v2 import ClarityCodeGeneratorCrewV2 12 | from utils.crews import AIBTC_Crew 13 | from utils.scripts import get_pretty_timestamp 14 | 15 | 16 | def truncate_text(text: str, max_length: int = 80): 17 | return text if len(text) <= max_length else f"{text[:max_length]}..." 18 | 19 | 20 | def add_to_chat(speaker: str, message: str, subtask=False): 21 | if "messages" not in st.session_state: 22 | st.session_state.messages = [] 23 | st.session_state.messages.append({"role": speaker, "content": message}) 24 | avatar = ( 25 | "https://aibtc.dev/logos/aibtcdev-avatar-250px.png" 26 | if speaker == "assistant" 27 | else None 28 | ) 29 | 30 | if subtask: 31 | with st.session_state.status_container: 32 | with st.chat_message(name=speaker, avatar=avatar): 33 | for line in message.split("\n"): 34 | st.markdown(line) 35 | else: 36 | with st.session_state.chat_container: 37 | with st.chat_message(name=speaker, avatar=avatar): 38 | for line in message.split("\n"): 39 | st.markdown(line) 40 | 41 | 42 | def update_status(label: str, state: str = "running"): 43 | # state can be "running", "complete", "error" 44 | st.session_state.status_container.update(label=label) 45 | 46 | 47 | def set_active_crew(crew_name: str): 48 | st.session_state.active_crew = crew_name 49 | 50 | 51 | def chat_tool_callback(action: AgentAction): 52 | """Callback function to display any tool output from the crew.""" 53 | update_status( 54 | f"[{st.session_state.active_crew}] Used tool: {action.tool}...", "running" 55 | ) 56 | add_to_chat( 57 | "assistant", 58 | f"[{st.session_state.active_crew}]\n**Used tool:** {action.tool}\n**Tool input:**\n{action.tool_input}\n**Tool output:** *(truncated)*\n{truncate_text(action.result, 300)}", 59 | True, 60 | ) 61 | 62 | 63 | def chat_task_callback(task: TaskOutput): 64 | """Callback function to display any task output from the crew.""" 65 | task_description = task.description 66 | task_name = getattr( 67 | task, "name", None 68 | ) # default to None if name attribute is not present 69 | computed_name = task_name if task_name else (truncate_text(task_description)) 70 | update_status( 71 | f"[{st.session_state.active_crew}] Completed task: {computed_name}...", 72 | "running", 73 | ) 74 | add_to_chat( 75 | "assistant", 76 | f"[{st.session_state.active_crew}]\n**Completed task:** {computed_name}", 77 | True, 78 | ) 79 | 80 | 81 | class UserChatSpecialistCrew(AIBTC_Crew): 82 | def __init__(self, embedder): 83 | super().__init__( 84 | "User Chat Specialist", 85 | "This crew is responsible for chat interactions with the user and providing support.", 86 | embedder, 87 | ) 88 | 89 | def setup_agents(self, llm): 90 | chat_specialist = Agent( 91 | role="Chat Specialist", 92 | goal="You are responsible for interacting with the user and translating their query into an action.", 93 | backstory="You are trained to understand the user's query and provide the information they need with your tools, then analyzing the connection between the user's input and the result.", 94 | tools=AgentTools.get_all_tools(), 95 | verbose=True, 96 | memory=False, 97 | allow_delegation=True, 98 | llm=llm, 99 | ) 100 | self.add_agent(chat_specialist) 101 | 102 | def setup_tasks(self, user_input): 103 | review_user_input = Task( 104 | name="Review User Input", 105 | description=dedent( 106 | f""" 107 | The user is talking to you in chat format. You are tasked with reviewing the user's input and taking 1 of 2 actions: 108 | 1. If the user's input is a question without a task, do not execute a crew and clearly answer the question. 109 | 2. If the user's input is a task, use the appropriate tool to execute the task and summarize the result. 110 | ### User Input 111 | {user_input} 112 | """ 113 | ), 114 | expected_output="The appropriate action has been taken.", 115 | agent=self.agents[0], # chat_specialist 116 | ) 117 | self.add_task(review_user_input) 118 | 119 | @staticmethod 120 | def get_task_inputs(): 121 | return ["user_input"] 122 | 123 | @classmethod 124 | def get_all_tools(cls): 125 | return AgentTools.get_all_tools() 126 | 127 | 128 | def render_crew(): 129 | # setup and display initial instructions 130 | initial_instructions = st.empty() 131 | initial_instructions.markdown( 132 | dedent( 133 | """ 134 | Welcome to AIBTC! Some ways to test my abilities: 135 | - Please analyze SP97M6Z0T8MHKJ6NZE0GS6TRERCG3GW1WVJ4NVGT.aibtcdev-airdrop-1 136 | - Tell me about the wallet SP97M6Z0T8MHKJ6NZE0GS6TRERCG3GW1WVJ4NVGT 137 | - Would you kindly analyze the trading strategy for WELSH? 138 | - Create a Clarity function that sums a list of three uints 139 | """ 140 | ) 141 | ) 142 | 143 | # initialize chat history 144 | if "chat_history" not in st.session_state: 145 | st.session_state.chat_history = [] 146 | 147 | # intialize main chat container to hold chat messages and status messages 148 | st.session_state.full_chat_container = st.container() 149 | 150 | # create text input field for user at the bottom 151 | if user_input := st.chat_input("What would you like to do?"): 152 | 153 | # clear initial instructions 154 | initial_instructions.empty() 155 | # initialize chat and status container for updates 156 | with st.session_state.full_chat_container: 157 | st.session_state.chat_container = st.empty() 158 | st.session_state.chat_container = st.container() 159 | st.session_state.status_container = st.empty() 160 | st.session_state.status_container = st.status(label="Ready to assist!") 161 | 162 | # add user input to chat 163 | add_to_chat("user", user_input) 164 | # update status container 165 | update_status("Creating a plan and finding the right crew...", "running") 166 | 167 | # initialize the crew 168 | crew_class = UserChatSpecialistCrew(st.session_state.embedder) 169 | crew_class.setup_agents(st.session_state.llm) 170 | crew_class.setup_tasks(user_input) 171 | crew = crew_class.create_crew() 172 | crew.step_callback = chat_tool_callback 173 | crew.task_callback = chat_task_callback 174 | crew.planning = True 175 | 176 | # set active agent in state 177 | set_active_crew(crew_class.name) 178 | 179 | # kick off the crew (long-running) 180 | with st.session_state.status_container: 181 | result = crew.kickoff() 182 | 183 | # add crew's result to chat 184 | set_active_crew(crew_class.name) 185 | add_to_chat("assistant", result.raw) 186 | add_to_chat("assistant", "Is there anything else I can help you with?") 187 | 188 | # store chat history from messages in state 189 | st.session_state.chat_history.append( 190 | {"timestamp": get_pretty_timestamp(), "messages": st.session_state.messages} 191 | ) 192 | # clear messages in state 193 | st.session_state.messages = [] 194 | 195 | # show chat history in popover 196 | if st.session_state.chat_history: 197 | st.markdown("### Chat History") 198 | for chat in st.session_state.chat_history: 199 | with st.popover(f"Chat from {chat['timestamp']}"): 200 | # download chat as text file 201 | st.download_button( 202 | label="Download Chat", 203 | data="\n".join( 204 | [ 205 | f"{message['role']}: {message['content']}" 206 | for message in chat["messages"] 207 | ] 208 | ), 209 | file_name=f"chat_{chat['timestamp']}-AIBTC.txt", 210 | mime="text/plain", 211 | ) 212 | # display chat messages 213 | for message in chat["messages"]: 214 | role = message["role"] 215 | content = message["content"] 216 | avatar = ( 217 | "https://aibtc.dev/logos/aibtcdev-avatar-250px.png" 218 | if role == "assistant" 219 | else None 220 | ) 221 | with st.chat_message(name=role, avatar=avatar): 222 | for line in content.split("\n"): 223 | st.markdown(line) 224 | 225 | 226 | ######################### 227 | # Agent Tools 228 | ######################### 229 | 230 | 231 | class AgentTools: 232 | @staticmethod 233 | @tool("Execute Smart Contract Analyzer Crew") 234 | def execute_smart_contract_analyzer_crew(contract_identifier: str): 235 | """Execute the Smart Contract Analyzer Crew to give a comprehensive review of a provided smart contract.""" 236 | try: 237 | if isinstance(contract_identifier, dict): 238 | contract_identifier = contract_identifier.get("contract_identifier", "") 239 | crew_class = SmartContractAnalyzerV2(st.session_state.embedder) 240 | crew_class.setup_agents(st.session_state.llm) 241 | crew_class.setup_tasks(contract_identifier) 242 | crew = crew_class.create_crew() 243 | crew.step_callback = chat_tool_callback 244 | crew.task_callback = chat_task_callback 245 | crew.planning = True 246 | set_active_crew(crew_class.name) 247 | update_status(f"Executing {crew_class.name}...", "running") 248 | result = crew.kickoff() 249 | return result 250 | except Exception as e: 251 | return f"Error executing Smart Contract Analyzer Crew: {e}" 252 | 253 | @staticmethod 254 | @tool("Execute Wallet Analyzer Crew") 255 | def execute_wallet_analyzer_crew(address: str): 256 | """Execute the Wallet Analyzer Crew to give a comprehensive review of a provided wallet address.""" 257 | try: 258 | # check if address is json param and extract value 259 | if isinstance(address, dict): 260 | address = address.get("address", "") 261 | crew_class = WalletSummaryCrew(st.session_state.embedder) 262 | crew_class.setup_agents(st.session_state.llm) 263 | crew_class.setup_tasks(address) 264 | crew = crew_class.create_crew() 265 | crew.step_callback = chat_tool_callback 266 | crew.task_callback = chat_task_callback 267 | crew.planning = True 268 | set_active_crew(crew_class.name) 269 | update_status(f"Executing {crew_class.name}...", "running") 270 | result = crew.kickoff() 271 | return result 272 | except Exception as e: 273 | return f"Error executing Wallet Analyzer Crew: {e}" 274 | 275 | @staticmethod 276 | @tool("Execute Trading Analyzer Crew") 277 | def execute_trading_analyzer_crew(crypto_symbol: str): 278 | """Execute the Trading Analyzer Crew to give a comprehensive review of a provided trading strategy.""" 279 | try: 280 | if isinstance(crypto_symbol, dict): 281 | crypto_symbol = crypto_symbol.get("crypto_symbol", "") 282 | crew_class = TradingAnalyzerCrew(st.session_state.embedder) 283 | crew_class.setup_agents(st.session_state.llm) 284 | crew_class.setup_tasks(crypto_symbol) 285 | crew = crew_class.create_crew() 286 | crew.step_callback = chat_tool_callback 287 | crew.task_callback = chat_task_callback 288 | crew.planning = True 289 | set_active_crew(crew_class.name) 290 | update_status(f"Executing {crew_class.name}...", "running") 291 | result = crew.kickoff() 292 | return result 293 | except Exception as e: 294 | return f"Error executing Trading Analyzer Crew: {e}" 295 | 296 | @staticmethod 297 | @tool("Execute Clarity Code Generator Crew") 298 | def execute_clarity_code_generator_crew(user_input: str): 299 | """Execute the Clarity Code Generator Crew to generate Clarity code for a provided smart contract.""" 300 | try: 301 | if isinstance(user_input, dict): 302 | user_input = user_input.get("user_input", "") 303 | crew_class = ClarityCodeGeneratorCrewV2(st.session_state.embedder) 304 | crew_class.setup_agents(st.session_state.llm) 305 | crew_class.setup_tasks(user_input) 306 | crew = crew_class.create_crew() 307 | crew.step_callback = chat_tool_callback 308 | crew.task_callback = chat_task_callback 309 | crew.planning = True 310 | set_active_crew(crew_class.name) 311 | update_status(f"Executing {crew_class.name}...", "running") 312 | result = crew.kickoff() 313 | return result 314 | except Exception as e: 315 | return f"Error executing Clarity Code Generator Crew: {e}" 316 | 317 | @staticmethod 318 | @tool("List all past chat messages") 319 | def get_all_past_messages(): 320 | """Get all past chat messages between you and the user for context.""" 321 | return st.session_state.messages 322 | 323 | @staticmethod 324 | @tool("List all available agent tools") 325 | def get_all_available_tools(): 326 | """Get all available tools you have access to in order to assist the user.""" 327 | # make an array of {name: tool_name, description: tool_description} 328 | tools = [] 329 | for tool in AgentTools.get_all_tools(): 330 | tools.append({"name": tool.name, "description": tool.description}) 331 | return tools 332 | 333 | @classmethod 334 | def get_all_tools(cls): 335 | members = inspect.getmembers(cls) 336 | tools = [ 337 | member 338 | for name, member in members 339 | if isinstance(member, Tool) 340 | or (hasattr(member, "__wrapped__") and isinstance(member.__wrapped__, Tool)) 341 | ] 342 | return tools 343 | -------------------------------------------------------------------------------- /aibtc-v1/crews/wallet_summarizer.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import streamlit as st 3 | from crewai import Agent, Task 4 | from crewai_tools import tool, Tool 5 | from textwrap import dedent 6 | from utils.crews import AIBTC_Crew, display_token_usage 7 | from utils.scripts import BunScriptRunner, get_timestamp 8 | 9 | 10 | class WalletSummaryCrew(AIBTC_Crew): 11 | def __init__(self, embedder): 12 | super().__init__( 13 | "Wallet Summarizer", 14 | "This crew analyzes a wallet's activity and holdings on the Stacks blockchain.", 15 | embedder, 16 | ) 17 | 18 | def setup_agents(self, llm): 19 | wallet_agent = Agent( 20 | role="Wallet Data and Transaction Retriever", 21 | goal=dedent( 22 | """ 23 | Retrieve basic wallet information and summarize transactions for the specified wallet. 24 | Focus on providing a detailed analysis of the wallet balance and transaction data, including types, dates, events, and involved parties. 25 | Ensure the output is formatted correctly and is ready for use in further analysis or reporting. 26 | """ 27 | ), 28 | tools=[ 29 | AgentTools.get_address_balance_detailed, 30 | AgentTools.get_address_transactions, 31 | AgentTools.get_bns_address, 32 | ], 33 | backstory=dedent( 34 | """ 35 | You are a blockchain data analyst specializing in wallet activity on the Stacks blockchain. 36 | You have access to various tools to retrieve detailed information about wallet addresses balance details and transactions. 37 | You excel at extracting meaningful insights and ensure accurate transaction details are provided. 38 | Focus on the data within transactions, summarizing key details such as transaction types, dates, events, and involved parties. 39 | """ 40 | ), 41 | verbose=True, 42 | llm=llm, 43 | ) 44 | self.add_agent(wallet_agent) 45 | 46 | pattern_recognizer = Agent( 47 | role="Pattern Recognition Specialist", 48 | goal="Identify recurring patterns, unusual activities, and long-term trends in wallet behavior.", 49 | tools=[], 50 | backstory=dedent( 51 | """ 52 | You are an expert in blockchain data analysis with a keen eye for patterns and anomalies. 53 | Your specialty is in recognizing recurring behaviors, identifying unusual activities, and 54 | spotting long-term trends in wallet usage on the Stacks blockchain. 55 | """ 56 | ), 57 | verbose=True, 58 | llm=llm, 59 | ) 60 | self.add_agent(pattern_recognizer) 61 | 62 | def setup_tasks(self, address): 63 | retrieve_wallet_info_task = Task( 64 | description=dedent( 65 | f""" 66 | Retrieve detailed wallet balance information for the specified address. 67 | 68 | **Address:** {address} 69 | 70 | Ensure the output is clear and suitable for use as context. 71 | """ 72 | ), 73 | expected_output="The only fields should be returned wallet address, STX balance, NFT holdings, and FT holdings. Simplified for context usage.", 74 | agent=self.agents[0], # wallet_agent 75 | ) 76 | self.add_task(retrieve_wallet_info_task) 77 | 78 | retrieve_transactions_task = Task( 79 | description=dedent( 80 | f""" 81 | Retrieve the last transactions associated with the following address: 82 | 83 | **Address:** {address} 84 | 85 | Ensure your summary is clear and focuses on the actual data within the transactions. Do not describe or summarize the structure of the data itself. 86 | """ 87 | ), 88 | expected_output=dedent( 89 | """ 90 | A summary of each transaction, including: 91 | - Transaction Status 92 | - Sender Address 93 | - Block Time (ISO format) 94 | - Transaction Type 95 | - Contract Name (if applicable) 96 | - Function Name (if applicable) 97 | - Recipient Address (if applicable) 98 | - MicroSTX Sent 99 | - MicroSTX Received 100 | 101 | Focus on content, not structure. 102 | """ 103 | ), 104 | agent=self.agents[0], # wallet_agent 105 | ) 106 | self.add_task(retrieve_transactions_task) 107 | 108 | analyze_historical_data_task = Task( 109 | description=dedent( 110 | f""" 111 | Analyze the historical data for the wallet address: {address} 112 | 113 | Your analysis should include: 114 | 1. Trends in transaction frequency and volume over time 115 | 2. Changes in asset holdings (STX, NFTs, FTs) over time 116 | 3. Significant events or turning points in the wallet's history 117 | 118 | Provide insights on how the wallet's usage has evolved and any notable patterns observed. 119 | """ 120 | ), 121 | expected_output="A comprehensive analysis of historical trends, including transaction patterns, asset holding changes, and significant events in the wallet's history.", 122 | agent=self.agents[1], # pattern_recognizer 123 | ) 124 | self.add_task(analyze_historical_data_task) 125 | 126 | @staticmethod 127 | def get_task_inputs(): 128 | return ["address"] 129 | 130 | @classmethod 131 | def get_all_tools(cls): 132 | return AgentTools.get_all_tools() 133 | 134 | def render_crew(self): 135 | st.subheader("Wallet Summarizer") 136 | st.markdown( 137 | "This tool will analyze a wallet's activity and holdings on the Stacks blockchain." 138 | ) 139 | 140 | with st.form("wallet_summary_form"): 141 | address = st.text_input("Address", help="Enter the wallet address") 142 | submitted = st.form_submit_button("Analyze Wallet") 143 | 144 | if submitted and address: 145 | st.subheader("Analysis Progress") 146 | try: 147 | st.write("Step Progress:") 148 | st.session_state.crew_step_container = st.empty() 149 | st.write("Task Progress:") 150 | st.session_state.crew_task_container = st.empty() 151 | 152 | st.session_state.crew_step_callback = [] 153 | st.session_state.crew_task_callback = [] 154 | 155 | llm = st.session_state.llm 156 | 157 | wallet_summary_crew_class = WalletSummaryCrew() 158 | wallet_summary_crew_class.setup_agents(llm) 159 | wallet_summary_crew_class.setup_tasks(address) 160 | wallet_summary_crew = wallet_summary_crew_class.create_crew() 161 | 162 | with st.spinner("Analyzing..."): 163 | result = wallet_summary_crew.kickoff() 164 | 165 | st.success("Analysis complete!") 166 | 167 | display_token_usage(result.token_usage) 168 | 169 | st.subheader("Analysis Results") 170 | 171 | result_str = str(result.raw) 172 | st.markdown(result_str) 173 | 174 | timestamp = get_timestamp() 175 | 176 | st.download_button( 177 | label="Download Analysis Report (Text)", 178 | data=result_str, 179 | file_name=f"{timestamp}_wallet_summary_analysis.txt", 180 | mime="text/plain", 181 | ) 182 | 183 | except Exception as e: 184 | st.error(f"An error occurred: {str(e)}") 185 | st.write("Please check your inputs and try again.") 186 | else: 187 | st.write( 188 | "Enter Wallet Address, then click 'Analyze Wallet' to see results." 189 | ) 190 | 191 | 192 | ######################### 193 | # Agent Tools 194 | ######################### 195 | 196 | 197 | class AgentTools: 198 | 199 | @staticmethod 200 | @tool("Get Address Balance Detailed") 201 | def get_address_balance_detailed(address: str): 202 | """Get detailed balance information for a given address.""" 203 | # helper if address is sent as json 204 | if isinstance(address, dict) and "address" in address: 205 | address = address["address"] 206 | return BunScriptRunner.bun_run( 207 | "stacks-wallet", "get-address-balance-detailed.ts", address 208 | ) 209 | 210 | @staticmethod 211 | @tool("Get Address Transactions") 212 | def get_address_transactions(address: str): 213 | """Get 20 most recent transactions for a given address.""" 214 | # helper if address is sent as json 215 | if isinstance(address, dict) and "address" in address: 216 | address = address["address"] 217 | return BunScriptRunner.bun_run( 218 | "stacks-wallet", "get-transactions-by-address.ts", address 219 | ) 220 | 221 | @staticmethod 222 | @tool("Translate BNS Name to Address") 223 | def get_bns_address(name: str): 224 | """Get the address that is tied to a bns name.""" 225 | return BunScriptRunner.bun_run("stacks-bns", "get-address-by-bns.ts", name) 226 | 227 | @classmethod 228 | def get_all_tools(cls): 229 | members = inspect.getmembers(cls) 230 | tools = [ 231 | member 232 | for name, member in members 233 | if isinstance(member, Tool) 234 | or (hasattr(member, "__wrapped__") and isinstance(member.__wrapped__, Tool)) 235 | ] 236 | return tools 237 | -------------------------------------------------------------------------------- /aibtc-v1/run_clarinet.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | 5 | class ClarinetExecutor: 6 | 7 | @classmethod 8 | def _find_project_root(cls): 9 | current_dir = os.path.dirname(os.path.abspath(__file__)) 10 | while True: 11 | if os.path.exists(os.path.join(current_dir, "ai-agent-crew")): 12 | return os.path.join(current_dir, "ai-agent-crew") 13 | parent_dir = os.path.dirname(current_dir) 14 | if parent_dir == current_dir: 15 | raise FileNotFoundError("Could not find project root directory") 16 | current_dir = parent_dir 17 | 18 | @classmethod 19 | def _setup_global_config(cls): 20 | home_dir = os.path.expanduser("~") 21 | clarinet_config_dir = os.path.join(home_dir, ".clarinet") 22 | clarinetrc_path = os.path.join(clarinet_config_dir, "clarinetrc.toml") 23 | 24 | os.makedirs(clarinet_config_dir, exist_ok=True) 25 | 26 | if not os.path.exists(clarinetrc_path): 27 | with open(clarinetrc_path, "w") as f: 28 | f.write("enable_telemetry = true\nenable_hints = false\n") 29 | 30 | @classmethod 31 | def _setup_working_dir(cls): 32 | cls._setup_paths() 33 | os.makedirs(cls.CLARINET_WORKING_DIR, exist_ok=True) 34 | 35 | @classmethod 36 | def _setup_paths(cls): 37 | project_root = cls._find_project_root() 38 | cls.CLARINET_SETUP_DIR = os.path.join(project_root, "clarinet") 39 | cls.CLARINET_BIN_DIR = os.path.join(cls.CLARINET_SETUP_DIR, "bin") 40 | cls.CLARINET_BIN_PATH = os.path.join(cls.CLARINET_BIN_DIR, "clarinet") 41 | cls.CLARINET_DEPS_DIR = os.path.join(cls.CLARINET_SETUP_DIR, "glibc-2.34") 42 | cls.CLARINET_WORKING_DIR = os.path.join( 43 | project_root, "aibtc-v1", "crews", "working_dir" 44 | ) 45 | cls.CLARINET_CONFIG_FILE = os.path.join( 46 | cls.CLARINET_SETUP_DIR, "clarinet-config" 47 | ) 48 | 49 | @classmethod 50 | def run_clarinet_command(cls, command, cwd=None): 51 | # setup global config before each run 52 | cls._setup_global_config() 53 | # setup working dir before each run 54 | cls._setup_working_dir() 55 | # setup paths before each run 56 | cls._setup_paths() 57 | 58 | # check that the clarinet binary exists 59 | if not os.path.exists(cls.CLARINET_BIN_PATH): 60 | raise FileNotFoundError( 61 | f"Clarinet binary not found at {cls.CLARINET_BIN_PATH}" 62 | ) 63 | 64 | # source the clarinet-config file 65 | with open(cls.CLARINET_CONFIG_FILE, "r") as config_file: 66 | for line in config_file: 67 | if line.startswith("export"): 68 | key, value = line.strip().split("=", 1) 69 | key = key.split()[-1] # remove 'export' from the key 70 | os.environ[key] = value.strip('"') 71 | 72 | # copy the environment variables 73 | env = os.environ.copy() 74 | 75 | # run the command 76 | args = [cls.CLARINET_BIN_PATH] + command 77 | return subprocess.run( 78 | args, 79 | check=True, 80 | cwd=cwd or cls.CLARINET_WORKING_DIR, 81 | env=env, 82 | capture_output=True, 83 | text=True, 84 | ) 85 | -------------------------------------------------------------------------------- /aibtc-v1/utils/callbacks.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from typing import Dict, Any, Union 3 | from crewai.tasks.task_output import TaskOutput 4 | from crewai.agents.parser import AgentAction 5 | 6 | 7 | def format_task_output(task_output: TaskOutput) -> str: 8 | """Format TaskOutput for display.""" 9 | output = f"**Description**: {task_output.description}\n\n" 10 | output += f"**Agent**: {task_output.agent}\n\n" 11 | 12 | if task_output.expected_output: 13 | output += f"**Expected Output**: {task_output.expected_output}\n\n" 14 | 15 | # output += f"**Output Format**: {task_output.output_format.value}\n\n" 16 | 17 | # if task_output.output_format.value == "JSON": 18 | # output += f"**JSON Output**:\n```json\n{task_output.json}\n```\n\n" 19 | # elif task_output.pydantic: 20 | # output += f"**Structured Output**:\n```\n{task_output.pydantic}\n```\n\n" 21 | # else: 22 | # output += f"**Raw Output**:\n{task_output.raw}\n\n" 23 | 24 | return output 25 | 26 | 27 | def format_agent_action(agent_action: AgentAction) -> str: 28 | """Format AgentAction for display.""" 29 | output = f"**Thought**: {agent_action.thought}\n\n" 30 | output += f"**Action**: {agent_action.tool}\n\n" 31 | output += f"**Input**: {agent_action.tool_input}\n\n" 32 | # if hasattr(agent_action, "result"): 33 | # output += f"**Result**: {agent_action.result}\n\n" 34 | return output 35 | 36 | 37 | def crew_step_callback(step: Union[Dict[str, Any], AgentAction]): 38 | if "crew_step_callback" not in st.session_state: 39 | st.session_state.crew_step_callback = [] 40 | st.session_state.crew_step_callback.append(step) 41 | with st.session_state.crew_step_container.container(): 42 | with st.expander("Completed Steps", expanded=False): 43 | for i, step_data in enumerate(st.session_state.crew_step_callback): 44 | st.markdown(f"#### Step {i+1}") 45 | if isinstance(step_data, dict) and "task_output" in step_data: 46 | task_output = TaskOutput(**step_data["task_output"]) 47 | st.markdown(format_task_output(task_output)) 48 | elif isinstance(step_data, AgentAction): 49 | st.markdown(format_agent_action(step_data)) 50 | else: 51 | st.markdown(f"```\n{step_data}\n```") 52 | if i < len(st.session_state.crew_step_callback) - 1: 53 | st.markdown("---") 54 | 55 | 56 | def crew_task_callback(task: TaskOutput): 57 | if "crew_task_callback" not in st.session_state: 58 | st.session_state.crew_task_callback = [] 59 | st.session_state.crew_task_callback.append(task) 60 | with st.session_state.crew_task_container.container(): 61 | with st.expander("Completed Tasks", expanded=True): 62 | for i, task_output in enumerate(st.session_state.crew_task_callback): 63 | st.markdown(f"#### Task {i+1}") 64 | st.markdown(format_task_output(task_output)) 65 | if i < len(st.session_state.crew_task_callback) - 1: 66 | st.markdown("---") 67 | -------------------------------------------------------------------------------- /aibtc-v1/utils/clarinet.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import shutil 4 | 5 | 6 | class ClarinetInterface: 7 | def __init__(self): 8 | self.env = os.environ.copy() 9 | self.clarinet_binary = None 10 | self.project_dir = None 11 | self.working_dir = None 12 | 13 | def initialize_clarinet(self): 14 | # Setup Clarinet configuration 15 | self.setup_clarinet_config() 16 | # Find project root 17 | project_root = self.find_project_root() 18 | if project_root is None: 19 | raise FileNotFoundError("Could not find project root directory") 20 | 21 | # Setup working directory 22 | self.working_dir = os.path.join( 23 | project_root, "ai-agent-crew", "aibtc-v1", "crews", "working_dir" 24 | ) 25 | os.makedirs(self.working_dir, exist_ok=True) 26 | 27 | # Attempt to find Clarinet binary 28 | self.clarinet_binary = shutil.which("clarinet") 29 | 30 | if self.clarinet_binary: 31 | # Clarinet is installed globally 32 | print(f"Using global Clarinet binary at {self.clarinet_binary}") 33 | else: 34 | # Clarinet is not installed globally, check for local installation 35 | self.setup_paths(project_root) 36 | self.clarinet_binary = self.CLARINET_BIN_PATH 37 | if not os.path.exists(self.clarinet_binary): 38 | raise FileNotFoundError( 39 | f"Clarinet binary not found at {self.clarinet_binary}. Please install Clarinet." 40 | ) 41 | print(f"Using local Clarinet binary at {self.clarinet_binary}") 42 | 43 | # If we're on Replit, set LD_LIBRARY_PATH 44 | if os.environ.get("REPL_ID"): 45 | print( 46 | "Detected Replit environment. Setting LD_LIBRARY_PATH for patched Clarinet." 47 | ) 48 | self.update_environment() 49 | # Update os.environ so that subprocess and shutil.which can find the dependencies 50 | os.environ.update( 51 | { 52 | "PATH": self.env["PATH"], 53 | "LD_LIBRARY_PATH": self.env["LD_LIBRARY_PATH"], 54 | } 55 | ) 56 | else: 57 | # Not on Replit, LD_LIBRARY_PATH is not needed 58 | print( 59 | "Not running on Replit. LD_LIBRARY_PATH is not required for local Clarinet." 60 | ) 61 | 62 | def find_project_root(self): 63 | clarinet_script_dir = os.path.dirname(os.path.abspath(__file__)) 64 | print(f"Clarinet script directory: {clarinet_script_dir}") 65 | project_root = os.path.dirname(os.path.dirname(clarinet_script_dir)) 66 | print(f"Project root directory: {project_root}") 67 | return project_root 68 | 69 | def setup_clarinet_config(self): 70 | home_dir = os.path.expanduser("~") 71 | clarinet_config_dir = os.path.join(home_dir, ".clarinet") 72 | clarinetrc_path = os.path.join(clarinet_config_dir, "clarinetrc.toml") 73 | 74 | os.makedirs(clarinet_config_dir, exist_ok=True) 75 | 76 | if not os.path.exists(clarinetrc_path): 77 | with open(clarinetrc_path, "w") as f: 78 | f.write("enable_telemetry = true\nenable_hints = false\n") 79 | 80 | def setup_paths(self, project_root): 81 | self.CLARINET_SETUP_DIR = os.path.join(project_root, "clarinet") 82 | self.CLARINET_BIN_DIR = os.path.join(self.CLARINET_SETUP_DIR, "bin") 83 | self.CLARINET_BIN_PATH = os.path.join(self.CLARINET_BIN_DIR, "clarinet") 84 | self.CLARINET_DEPS_DIR = os.path.join(self.CLARINET_SETUP_DIR, "glibc-2.34") 85 | 86 | def update_environment(self): 87 | # Update PATH and LD_LIBRARY_PATH for the local Clarinet binary 88 | path = self.env.get("PATH", "") 89 | ld_library_path = self.env.get("LD_LIBRARY_PATH", "") 90 | self.env["PATH"] = f"{self.CLARINET_BIN_DIR}:{path}" 91 | self.env["LD_LIBRARY_PATH"] = ( 92 | f"{self.CLARINET_DEPS_DIR}:/usr/lib/x86_64-linux-gnu:{ld_library_path}" 93 | ) 94 | 95 | def create_project(self, project_name): 96 | # Set the project directory 97 | self.project_dir = os.path.join(self.working_dir, project_name) 98 | # Ensure the working directory exists 99 | os.makedirs(self.working_dir, exist_ok=True) 100 | # Create the project 101 | cmd = [self.clarinet_binary, "new", project_name] 102 | return self.run_command(cmd, cwd=self.working_dir) 103 | 104 | def run_command(self, command, cwd=None): 105 | result = subprocess.run( 106 | command, 107 | cwd=cwd or self.project_dir, 108 | env=self.env, 109 | capture_output=True, 110 | text=True, 111 | ) 112 | return { 113 | "stdout": result.stdout, 114 | "stderr": result.stderr, 115 | "returncode": result.returncode, 116 | } 117 | 118 | def add_contract(self, contract_name): 119 | cmd = [self.clarinet_binary, "contract", "new", contract_name] 120 | return self.run_command(cmd) 121 | 122 | def update_contract(self, contract_name, contract_code): 123 | contract_file_path = os.path.join( 124 | self.project_dir, "contracts", f"{contract_name}.clar" 125 | ) 126 | 127 | # Write the contract code to the file (overwrite if exists) 128 | try: 129 | with open(contract_file_path, "w") as f: 130 | f.write(contract_code) 131 | return { 132 | "stdout": f"Contract '{contract_name}' updated successfully.", 133 | "stderr": "", 134 | "returncode": 0, 135 | } 136 | except Exception as e: 137 | return { 138 | "stdout": "", 139 | "stderr": f"Error writing contract code for contract name {contract_name}: {e}", 140 | "returncode": 1, 141 | } 142 | 143 | def remove_contract(self, contract_name): 144 | cmd = [self.clarinet_binary, "contract", "rm", contract_name] 145 | return self.run_command(cmd) 146 | 147 | def check_all_contracts(self): 148 | cmd = [self.clarinet_binary, "check"] 149 | return self.run_command(cmd) 150 | 151 | def check_contract(self, contract_name): 152 | cmd = [self.clarinet_binary, "check", contract_name] 153 | return self.run_command(cmd) 154 | 155 | def add_requirement(self, contract_id): 156 | cmd = [self.clarinet_binary, "requirements", "add", contract_id] 157 | return self.run_command(cmd) 158 | -------------------------------------------------------------------------------- /aibtc-v1/utils/crews.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from crewai import Agent, Task, Crew, Process 3 | from typing import List 4 | from utils.callbacks import crew_step_callback, crew_task_callback 5 | 6 | 7 | class AIBTC_Crew: 8 | def __init__(self, name: str, description: str, embedder: any): 9 | self.name = name 10 | self.description = description 11 | self.embedder = embedder 12 | self.agents: List[Agent] = [] 13 | self.tasks: List[Task] = [] 14 | 15 | def add_agent(self, agent: Agent): 16 | self.agents.append(agent) 17 | 18 | def add_task(self, task: Task): 19 | self.tasks.append(task) 20 | 21 | def create_crew(self) -> Crew: 22 | return Crew( 23 | agents=self.agents, 24 | tasks=self.tasks, 25 | process=Process.sequential, 26 | verbose=True, 27 | memory=True, 28 | embedder=self.embedder, 29 | step_callback=crew_step_callback, 30 | task_callback=crew_task_callback, 31 | ) 32 | 33 | def render_crew(self): 34 | pass 35 | 36 | 37 | def display_token_usage(token_usage): 38 | st.subheader("Token Usage") 39 | col1, col2 = st.columns(2) 40 | with col1: 41 | st.metric("Total Tokens", token_usage.total_tokens) 42 | st.metric("Prompt Tokens", token_usage.prompt_tokens) 43 | with col2: 44 | st.metric("Completion Tokens", token_usage.completion_tokens) 45 | st.metric("Successful Requests", token_usage.successful_requests) 46 | -------------------------------------------------------------------------------- /aibtc-v1/utils/scripts.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from datetime import datetime 3 | 4 | 5 | def get_timestamp(): 6 | return datetime.now().strftime("%Y%m%d%H%M%S") 7 | 8 | 9 | def get_pretty_timestamp(): 10 | return datetime.now().strftime("%Y-%m-%d %H:%M:%S") 11 | 12 | 13 | # generic runner for Bun.js scripts 14 | class BunScriptRunner: 15 | working_dir = "./agent-tools-ts/" 16 | script_dir = "src" 17 | 18 | @staticmethod 19 | def bun_run(contract_name: str, script_name: str, arg: str = None): 20 | """Runs a TypeScript script using bun with an optional positional argument.""" 21 | command = [ 22 | "bun", 23 | "run", 24 | f"{BunScriptRunner.script_dir}/{contract_name}/{script_name}", 25 | ] 26 | 27 | # Append the optional argument if provided 28 | if arg is not None: 29 | command.append(arg) 30 | 31 | try: 32 | result = subprocess.run( 33 | command, 34 | check=True, 35 | text=True, 36 | capture_output=True, 37 | cwd=BunScriptRunner.working_dir, 38 | ) 39 | return {"output": result.stdout, "error": None, "success": True} 40 | except subprocess.CalledProcessError as e: 41 | return {"output": None, "error": e.stderr, "success": False} 42 | -------------------------------------------------------------------------------- /aibtc-v1/utils/session.py: -------------------------------------------------------------------------------- 1 | import anthropic 2 | import inspect 3 | import importlib 4 | import os 5 | import streamlit as st 6 | from dotenv import load_dotenv 7 | from langchain_openai import ChatOpenAI 8 | from langchain_ollama import ChatOllama 9 | from typing import Optional 10 | from crewai import Agent, LLM 11 | 12 | from utils.crews import AIBTC_Crew 13 | 14 | 15 | def load_env_vars(): 16 | load_dotenv() 17 | env_vars = {} 18 | for key, value in os.environ.items(): 19 | env_vars[key] = value 20 | return env_vars 21 | 22 | 23 | def init_session_state(): 24 | env_vars = load_env_vars() 25 | 26 | if "messages" not in st.session_state: 27 | st.session_state.messages = [] 28 | 29 | if "agents" not in st.session_state: 30 | st.session_state.agents = {} 31 | 32 | if "tasks" not in st.session_state: 33 | st.session_state.tasks = {} 34 | 35 | if "tasks_search_term" not in st.session_state: 36 | st.session_state.tasks_search_term = "" 37 | 38 | # Initialize other session state variables 39 | defaults = { 40 | "api_key": env_vars.get("OPENAI_API_KEY", ""), 41 | "api_base": env_vars.get("OPENAI_API_BASE", "https://api.openai.com/v1"), 42 | "model": env_vars.get("OPENAI_MODEL_NAME", "gpt-4o-mini"), 43 | "embedder_provider": env_vars.get("OPENAI_EMBEDDER_PROVIDER", "openai"), 44 | "embedder_model": env_vars.get( 45 | "OPENAI_EMBEDDER_MODEL", "text-embedding-3-small" 46 | ), 47 | } 48 | 49 | for key, value in defaults.items(): 50 | if key not in st.session_state: 51 | st.session_state[key] = value 52 | 53 | # Initialize the LLMs 54 | if "llm" not in st.session_state: 55 | st.session_state.llm = LLM( 56 | model=st.session_state.model, 57 | api_key=st.session_state.api_key, 58 | base_url=st.session_state.api_base, 59 | ) 60 | st.session_state.embedder = { 61 | "provider": st.session_state.embedder_provider, 62 | "config": {"model": st.session_state.embedder_model}, 63 | } 64 | 65 | if "crew_mapping" not in st.session_state: 66 | st.session_state.crew_mapping = generate_crew_mapping() 67 | 68 | 69 | def update_session_state(key, value): 70 | st.session_state[key] = value 71 | 72 | 73 | def generate_crew_mapping(): 74 | crew_mapping = {} 75 | 76 | current_file = os.path.abspath(__file__) 77 | current_dir = os.path.dirname(current_file) 78 | crews_dir = os.path.join(current_dir, "..", "crews") 79 | 80 | if not os.path.exists(crews_dir): 81 | raise FileNotFoundError(f"The crews directory does not exist: {crews_dir}") 82 | 83 | crew_files = [ 84 | f for f in os.listdir(crews_dir) if f.endswith(".py") and not f.startswith("__") 85 | ] 86 | 87 | for filename in crew_files: 88 | module_name = f"crews.{filename[:-3]}" 89 | try: 90 | module = importlib.import_module(module_name) 91 | 92 | for name, obj in inspect.getmembers(module): 93 | if ( 94 | inspect.isclass(obj) 95 | and issubclass(obj, AIBTC_Crew) 96 | and obj != AIBTC_Crew 97 | ): 98 | # Create an instance to get the name 99 | try: 100 | instance = obj(st.session_state.embedder) 101 | crew_name = instance.name 102 | crew_description = instance.description 103 | except Exception as e: 104 | print(f"Error creating instance of {name}: {e}") 105 | crew_name = name.replace("Crew", "").replace("_", " ") 106 | 107 | crew_mapping[crew_name] = { 108 | "description": crew_description, 109 | "class": obj, 110 | "task_inputs": getattr(obj, "get_task_inputs", lambda: []), 111 | } 112 | except ImportError as e: 113 | print(f"Error importing {module_name}: {e}") 114 | 115 | return crew_mapping 116 | 117 | 118 | def get_crew_class(crew_name: str) -> Optional[type]: 119 | crew_info = st.session_state.crew_mapping.get(crew_name) 120 | return crew_info["class"] if crew_info else None 121 | 122 | 123 | def get_crew_inputs(crew_name: str): 124 | crew_info = st.session_state.crew_mapping.get(crew_name) 125 | if crew_info and "task_inputs" in crew_info: 126 | return crew_info["task_inputs"]() 127 | return [] 128 | -------------------------------------------------------------------------------- /aibtc-v1/utils/vector.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from bs4 import BeautifulSoup 4 | from crewai_tools import Tool 5 | from dotenv import load_dotenv 6 | from langchain_community.vectorstores import Chroma 7 | from langchain.schema import Document 8 | from langchain.text_splitter import RecursiveCharacterTextSplitter 9 | from litellm import embedding 10 | from chromadb import Client as ChromaClient 11 | from chromadb.config import Settings 12 | import chromadb 13 | import streamlit as st 14 | 15 | load_dotenv() 16 | 17 | 18 | class AIBTCEmbeddings: 19 | """A class to get embeddings using LiteLLM.""" 20 | 21 | def __init__(self): 22 | self.model_name = os.getenv("OPENAI_EMBEDDER_MODEL", "text-embedding-3-small") 23 | 24 | def get_embedding(self, text): 25 | """Retrieve embeddings for a given text using LiteLLM.""" 26 | response = embedding(model=self.model_name, input=[text]) 27 | if not response or "data" not in response or not response["data"]: 28 | raise Exception(f"Failed to get embeddings: {response}") 29 | return response["data"][0]["embedding"] 30 | 31 | def embed_documents(self, texts): 32 | """Embed a list of texts (documents) using LiteLLM.""" 33 | return [self.get_embedding(text) for text in texts] 34 | 35 | def embed_query(self, query): 36 | """Embed a single query string using LiteLLM.""" 37 | return self.get_embedding(query) 38 | 39 | 40 | def fetch_clarity_book_content(website_url: str): 41 | """Fetch and parse the content of the provided URL using Beautiful Soup. Targets the main article content.""" 42 | response = requests.get(website_url) 43 | soup = BeautifulSoup(response.content, "html.parser") 44 | 45 | article = soup.select_one("section#article article") 46 | if not article: 47 | return "" 48 | 49 | title = article.find("h2") 50 | title_text = title.text if title else "" 51 | 52 | for element in article.select(".code, .buttons"): 53 | element.decompose() 54 | 55 | content = article.get_text(separator="\n", strip=True) 56 | 57 | full_content = f"{title_text}\n\n{content}" 58 | 59 | return full_content 60 | 61 | 62 | def create_vector_store(urls, chunk_size=1000, chunk_overlap=200): 63 | """Create a vector store from a list of URLs using LiteLLM embeddings.""" 64 | documents = [] 65 | for url in urls: 66 | content = fetch_clarity_book_content(url) 67 | documents.append(Document(page_content=content, metadata={"source": url})) 68 | 69 | # Split the documents into smaller chunks 70 | text_splitter = RecursiveCharacterTextSplitter( 71 | chunk_size=chunk_size, chunk_overlap=chunk_overlap 72 | ) 73 | splits = text_splitter.split_documents(documents) 74 | 75 | # Initialize AIBTCEmbeddings 76 | aibtc_embeddings = AIBTCEmbeddings() 77 | 78 | # Create embeddings for each document chunk 79 | embeddings = aibtc_embeddings.embed_documents([doc.page_content for doc in splits]) 80 | 81 | # Create a new Chroma client 82 | chroma_client = chromadb.PersistentClient(path="./chroma") 83 | 84 | # Create or get a collection in Chroma for storing embeddings 85 | collection = chroma_client.get_or_create_collection(name="example_collection") 86 | 87 | # Add the document chunks, metadata, and their embeddings to the Chroma collection 88 | collection.add( 89 | documents=[doc.page_content for doc in splits], 90 | metadatas=[doc.metadata for doc in splits], 91 | ids=[str(i) for i in range(len(splits))], 92 | embeddings=embeddings, 93 | ) 94 | 95 | return collection 96 | 97 | 98 | def create_vector_search_tool(vector_store, name, description): 99 | """Create a vector search tool using the given vector store.""" 100 | 101 | def search_func(query: str): 102 | results = vector_store.similarity_search(query, k=3) 103 | return "\n\n".join( 104 | f"From {doc.metadata['source']}:\n{doc.page_content}" for doc in results 105 | ) 106 | 107 | return Tool(name=name, func=search_func, description=description) 108 | 109 | 110 | # Define the URLs for different sections of the Clarity book 111 | clarity_book_code_vector_store = create_vector_store( 112 | [ 113 | "https://book.clarity-lang.org/ch04-00-storing-data.html", 114 | "https://book.clarity-lang.org/ch05-00-functions.html", 115 | "https://book.clarity-lang.org/ch03-00-keywords.html", 116 | "https://book.clarity-lang.org/ch02-00-types.html", 117 | ] 118 | ) 119 | 120 | clarity_book_function_vector_store = create_vector_store( 121 | [ 122 | "https://book.clarity-lang.org/ch05-00-functions.html", 123 | "https://book.clarity-lang.org/ch05-01-public-functions.html", 124 | "https://book.clarity-lang.org/ch05-02-private-functions.html", 125 | "https://book.clarity-lang.org/ch05-03-read-only-functions.html", 126 | ] 127 | ) 128 | -------------------------------------------------------------------------------- /clarinet/glibc-2.34/ld-linux-x86-64.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aibtcdev/ai-agent-crew/e8908baebdfed41531068252cc28b2b2f3f48efd/clarinet/glibc-2.34/ld-linux-x86-64.so.2 -------------------------------------------------------------------------------- /clarinet/glibc-2.34/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aibtcdev/ai-agent-crew/e8908baebdfed41531068252cc28b2b2f3f48efd/clarinet/glibc-2.34/libc.so.6 -------------------------------------------------------------------------------- /clarinet/glibc-2.34/libgcc_s.so.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aibtcdev/ai-agent-crew/e8908baebdfed41531068252cc28b2b2f3f48efd/clarinet/glibc-2.34/libgcc_s.so.1 -------------------------------------------------------------------------------- /clarinet/setup-clarinet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # get the script location in ./clarinet folder 6 | CLARINET_SETUP_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 7 | 8 | # set up environment 9 | CLARINET_BIN_DIR="$CLARINET_SETUP_DIR/bin" 10 | CLARINET_DEPS_DIR="$CLARINET_SETUP_DIR/glibc-2.34" 11 | 12 | # create directories 13 | mkdir -p "$CLARINET_SETUP_DIR" 14 | mkdir -p "$CLARINET_BIN_DIR" 15 | mkdir -p "$CLARINET_DEPS_DIR" 16 | 17 | # download and extract clarinet 2.9.0 18 | curl -L -o "clarinet.tar.gz" "https://github.com/hirosystems/clarinet/releases/download/v2.9.0/clarinet-linux-x64-glibc.tar.gz" 19 | tar -xzf "clarinet.tar.gz" -C "$CLARINET_BIN_DIR" 20 | rm "clarinet.tar.gz" 21 | chmod +x "$CLARINET_BIN_DIR/clarinet" 22 | echo "Clarinet installed to $CLARINET_BIN_DIR/clarinet" 23 | 24 | # check if REPL_ID env var is set 25 | if [ -z "$REPL_ID" ]; then 26 | echo "REPL_ID environment variable not set. Skipping Clarinet patching." 27 | exit 0 28 | fi 29 | 30 | # patch clarinet to use glibc 2.34 31 | # replit defaults to the newer 2.39 32 | # this is a workaround to use the older version 33 | if command -v patchelf >/dev/null 2>&1; then 34 | echo "Patching Clarinet to use custom GLIBC 2.34..." 35 | patchelf --set-interpreter "$CLARINET_DEPS_DIR/ld-linux-x86-64.so.2" "$CLARINET_BIN_DIR/clarinet" 36 | patchelf --set-rpath "$CLARINET_DEPS_DIR" "$CLARINET_BIN_DIR/clarinet" 37 | echo "Clarinet patched to use custom GLIBC 2.34" 38 | else 39 | echo "patchelf not found. Skipping Clarinet patching." 40 | fi 41 | -------------------------------------------------------------------------------- /legacy_code/agents.py: -------------------------------------------------------------------------------- 1 | from crewai import Agent 2 | from textwrap import dedent 3 | from tools.wallet import WalletTools 4 | from tools.aibtc_token import AIBTCTokenTools 5 | from tools.onchain_resources import OnchainResourcesTools 6 | from tools.web_scraper import WebTools 7 | 8 | 9 | class MeetingsCrew: 10 | @staticmethod 11 | def website_scraper(llm=None): 12 | kwargs = {} 13 | if llm is not None: 14 | kwargs["llm"] = llm 15 | 16 | return Agent( 17 | role="Website Scraper", 18 | goal="Gather relevant information from the provided links. Be verbose, provide as much of the content and necessary context as possible.", 19 | backstory=( 20 | "You are a skilled website scraper, capable of extracting valuable information from the website code of any given source." 21 | " Your expertise in web scraping allows you to gather data efficiently and accurately, providing valuable information for further analysis." 22 | " You always use the correct tool for the job based on the URL provided." 23 | ), 24 | verbose=True, 25 | memory=True, 26 | allow_delegation=False, 27 | tools=[ 28 | WebTools.scrape_x_or_twitter_url, 29 | ], 30 | ) 31 | 32 | @staticmethod 33 | def meeting_writer(llm=None): 34 | kwargs = {} 35 | if llm is not None: 36 | kwargs["llm"] = llm 37 | 38 | return Agent( 39 | role="Writer", 40 | goal="Summarize the gathered information and always return results in markdown format, adhering strictly to provided examples.", 41 | backstory=( 42 | "You have a talent for distilling complex information into clear, concise summaries. " 43 | "You ensure that all summaries adhere to the format provided in good examples, making the information accessible and engaging." 44 | ), 45 | verbose=True, 46 | memory=True, 47 | tools=[], 48 | allow_delegation=False, 49 | ) 50 | 51 | 52 | class BitcoinCrew: 53 | 54 | @staticmethod 55 | def account_manager(llm=None): 56 | kwargs = {} 57 | if llm is not None: 58 | kwargs["llm"] = llm 59 | 60 | return Agent( 61 | role="Account Manager", 62 | goal="Read context and execute tasks using tools to interact with a configured wallet.", 63 | memory=True, 64 | tools=[ 65 | WalletTools.get_wallet_addresses, 66 | WalletTools.get_wallet_status, 67 | WalletTools.get_transaction_data, 68 | WalletTools.get_transaction_status, 69 | AIBTCTokenTools.get_aibtc_balance, 70 | AIBTCTokenTools.get_faucet_drip, 71 | ], 72 | backstory=dedent( 73 | """\ 74 | You are an account manager with the ability to interact with the Bitcoin and Stacks blockchain. 75 | Your job is to read the context and execute tasks using your tools to interact with the wallet. 76 | For any transaction sent, the transaction ID can be used to check the status of the transaction. 77 | """ 78 | ), 79 | allow_delegation=False, 80 | verbose=True, 81 | **kwargs, 82 | ) 83 | 84 | @staticmethod 85 | def resource_manager(llm=None): 86 | kwargs = {} 87 | if llm is not None: 88 | kwargs["llm"] = llm 89 | 90 | return Agent( 91 | role="Resource Manager", 92 | goal="Read context and execute tasks using tools to interact with on-chain resources. Double check that all required arguments are included for the tools.", 93 | memory=True, 94 | tools=[ 95 | WalletTools.get_wallet_status, 96 | OnchainResourcesTools.get_recent_payment_data, 97 | OnchainResourcesTools.get_resource_data, 98 | OnchainResourcesTools.get_user_data_by_address, 99 | OnchainResourcesTools.pay_invoice_for_resource, 100 | AIBTCTokenTools.get_aibtc_balance, 101 | AIBTCTokenTools.get_faucet_drip, 102 | ], 103 | backstory=dedent( 104 | """\ 105 | You are a resource manager with the ability to interact with on-chain resources. 106 | Your job is to read the context and execute tasks using your tools to interact with on-chain resources. 107 | """ 108 | ), 109 | allow_delegation=False, 110 | verbose=True, 111 | **kwargs, 112 | ) 113 | -------------------------------------------------------------------------------- /legacy_code/aibtc-v1/agents.py: -------------------------------------------------------------------------------- 1 | from crewai import Agent 2 | from crews.tools import ( 3 | AIBTCTokenTools, 4 | AIBTCResourceTools, 5 | StacksWalletTools, 6 | WebsiteTools, 7 | ) 8 | 9 | 10 | def get_website_scraper(llm=None): 11 | kwargs = {} 12 | if llm is not None: 13 | kwargs["llm"] = llm 14 | 15 | return Agent( 16 | role="Website Scraper", 17 | goal="Gather relevant information from the provided links. Be verbose, provide as much of the content and necessary context as possible.", 18 | backstory="You are a skilled website scraper, capable of extracting valuable information from the website code of any given source. Your expertise in web scraping allows you to gather data efficiently and accurately, providing valuable information for further analysis. You always use the correct tool for the job based on the URL provided.", 19 | verbose=True, 20 | memory=True, 21 | allow_delegation=False, 22 | tools=[WebsiteTools.scrape_x_or_twitter_url], 23 | **kwargs 24 | ) 25 | 26 | 27 | def get_meeting_writer(llm=None): 28 | kwargs = {} 29 | if llm is not None: 30 | kwargs["llm"] = llm 31 | 32 | return Agent( 33 | role="Meeting Writer", 34 | goal="Summarize the gathered information and always return results in markdown format, adhering strictly to provided examples.", 35 | backstory="You have a talent for distilling complex information into clear, concise summaries. You ensure that all summaries adhere to the format provided in good examples, making the information accessible and engaging.", 36 | verbose=True, 37 | memory=True, 38 | allow_delegation=False, 39 | tools=[], 40 | **kwargs 41 | ) 42 | 43 | 44 | def get_wallet_account_manager(llm=None): 45 | kwargs = {} 46 | if llm is not None: 47 | kwargs["llm"] = llm 48 | 49 | return Agent( 50 | role="Account Manager", 51 | goal="Read context and execute tasks using tools to interact with a configured wallet.", 52 | backstory="You are an account manager with the ability to interact with the Bitcoin and Stacks blockchain. Your job is to read the context and execute tasks using your tools to interact with the wallet. For any transaction sent, the transaction ID can be used to check the status of the transaction.", 53 | memory=True, 54 | tools=[ 55 | StacksWalletTools.get_wallet_addresses, 56 | StacksWalletTools.get_wallet_status, 57 | StacksWalletTools.get_transaction_data, 58 | StacksWalletTools.get_transaction_status, 59 | AIBTCTokenTools.get_aibtc_balance, 60 | AIBTCTokenTools.get_faucet_drip, 61 | ], 62 | allow_delegation=False, 63 | verbose=True, 64 | **kwargs 65 | ) 66 | 67 | 68 | def get_onchain_resource_manager(llm=None): 69 | kwargs = {} 70 | if llm is not None: 71 | kwargs["llm"] = llm 72 | 73 | return Agent( 74 | role="Resource Manager", 75 | goal="Read context and execute tasks using tools to interact with on-chain resources. Double check that all required arguments are included for the tools.", 76 | backstory="You are an expert in managing on-chain resources. You are able to read the context and execute tasks using your tools to interact with on-chain resources.", 77 | memory=True, 78 | tools=[ 79 | AIBTCResourceTools.get_recent_payment_data, 80 | AIBTCResourceTools.get_resource_data, 81 | AIBTCResourceTools.get_user_data_by_address, 82 | AIBTCResourceTools.pay_invoice_for_resource, 83 | ], 84 | verbose=True, 85 | allow_delegation=False, 86 | **kwargs 87 | ) 88 | 89 | 90 | def get_transaction_manager(llm=None): 91 | kwargs = {} 92 | if llm is not None: 93 | kwargs["llm"] = llm 94 | 95 | return Agent( 96 | role="Transaction Manager", 97 | goal="Manage Bitcoin and Stacks transactions and provide information.", 98 | backstory="You are an expert in managing transactions and understanding complex on-chain data.", 99 | memory=True, 100 | tools=[ 101 | StacksWalletTools.get_transaction_data, 102 | StacksWalletTools.get_transaction_status, 103 | ], 104 | verbose=True, 105 | allow_delegation=False, 106 | **kwargs 107 | ) -------------------------------------------------------------------------------- /legacy_code/aibtc-v1/tasks.py: -------------------------------------------------------------------------------- 1 | from crewai import Task 2 | 3 | 4 | def get_wallet_status(agent): 5 | return Task( 6 | description="Get the current wallet status and display the information.", 7 | expected_output="A detailed report of the current wallet status including balance and recent transactions.", 8 | agent=agent, 9 | ) 10 | 11 | 12 | def get_aibtc_balance(agent): 13 | return Task( 14 | description="Retrieve and display the current aiBTC balance.", 15 | expected_output="The current aiBTC balance as a numerical value with appropriate units.", 16 | agent=agent, 17 | ) 18 | 19 | 20 | def get_aibtc_faucet_drip(agent): 21 | return Task( 22 | description="Request aiBTC from the faucet and display the transaction ID.", 23 | expected_output="The transaction ID of the aiBTC faucet drip request.", 24 | agent=agent, 25 | ) 26 | 27 | 28 | def get_aibtc_resource_data(agent): 29 | return Task( 30 | description="Retrieve and display resource data for a given address", 31 | expected_output="A detailed report of the resource data associated with the provided address.", 32 | agent=agent, 33 | ) 34 | -------------------------------------------------------------------------------- /legacy_code/aibtc-v1/tools.py: -------------------------------------------------------------------------------- 1 | from crewai_tools import SeleniumScrapingTool, tool 2 | from utils.scripts import BunScriptRunner 3 | 4 | ### ALL CLASSES AND FUNCTIONS BELOW ARE AGENT TOOLS ### 5 | 6 | 7 | class AIBTCResourceTools: 8 | @staticmethod 9 | @tool("Get recent payment data for an address") 10 | def get_recent_payment_data(address: str): 11 | """Get the recent payment data for a given address.""" 12 | return BunScriptRunner.bun_run( 13 | "aibtcdev-resources", "get-recent-payment-data-by-address.ts", address 14 | ) 15 | 16 | @staticmethod 17 | @tool("Get resource data for a resource") 18 | def get_resource_data(dummy_arg: None): 19 | """Get the resource data for the resource.""" 20 | return BunScriptRunner.bun_run("aibtcdev-resources", "get-resource-by-name.ts") 21 | 22 | @staticmethod 23 | @tool("Get user data by address") 24 | def get_user_data_by_address(address: str): 25 | """Get the user data for a given address.""" 26 | return BunScriptRunner.bun_run( 27 | "aibtcdev-resources", "get-user-data-by-address.ts", address 28 | ) 29 | 30 | @staticmethod 31 | @tool("Pay invoice for resource") 32 | def pay_invoice_for_resource(dummy_arg: None): 33 | """Pay the invoice for a given resource.""" 34 | return BunScriptRunner.bun_run("aibtcdev-resources", "pay-invoice.ts") 35 | 36 | 37 | class AIBTCTokenTools: 38 | @staticmethod 39 | @tool("Get current aiBTC balance") 40 | def get_aibtc_balance(dummy_arg=None): 41 | """Get the aiBTC balance of the currently configured wallet.""" 42 | return BunScriptRunner.bun_run("aibtcdev-aibtc-token", "get-balance.ts") 43 | 44 | @staticmethod 45 | @tool("Get 10,000 aiBTC from the faucet") 46 | def get_faucet_drip(dummy_arg=None): 47 | """Transfers 10,000 aiBTC from the faucet to your configured address and returns a transaction ID.""" 48 | return BunScriptRunner.bun_run("aibtcdev-aibtc-token", "faucet-drip.ts") 49 | 50 | @staticmethod 51 | @tool("Get 1,000,000 aiBTC from the faucet") 52 | def get_faucet_drop(dummy_arg=None): 53 | """Transfers 1,000,000 aiBTC from the faucet to your configured address and returns a transaction ID.""" 54 | return BunScriptRunner.bun_run("aibtcdev-aibtc-token", "faucet-drop.ts") 55 | 56 | @staticmethod 57 | @tool("Get 100,000,000 aiBTC from the faucet") 58 | def get_faucet_flood(dummy_arg=None): 59 | """Transfers 100,000,000 aiBTC from the faucet to your configured address and returns a transaction ID.""" 60 | return BunScriptRunner.bun_run("aibtcdev-aibtc-token", "get-faucet-flood.ts") 61 | 62 | 63 | class StacksBNSTools: 64 | @staticmethod 65 | @tool("Get BNS name for an address") 66 | def get_bns_name_for_address(address: str): 67 | """Get the on-chain BNS name for a given Stacks address.""" 68 | return BunScriptRunner.bun_run("stacks-bns", "get-bns-name.ts", address) 69 | 70 | @staticmethod 71 | @tool("Get address for a BNS name") 72 | def get_address_for_bns_name(bns_name: str): 73 | """Get the on-chain Stacks address for a given BNS name.""" 74 | return BunScriptRunner.bun_run( 75 | "stacks-bns", "get-address-for-bns-name.ts", bns_name 76 | ) 77 | 78 | @staticmethod 79 | @tool("Check if BNS name is available") 80 | def check_bns_name_availability(bns_name: str): 81 | """Check if a given BNS name is available.""" 82 | return BunScriptRunner.bun_run("stacks-bns", "check-available.ts", bns_name) 83 | 84 | @staticmethod 85 | @tool("Preorder a BNS name (step 1)") 86 | def preorder_bns_name_step_1(bns_name: str): 87 | """Preorder a BNS name, step 1 of 2, transaction is required to be successful before registering in step 2.""" 88 | return BunScriptRunner.bun_run("stacks-bns", "preorder.ts", bns_name) 89 | 90 | @staticmethod 91 | @tool("Register a BNS name (step 2)") 92 | def register_bns_name_step_2(bns_name: str): 93 | """Register a BNS name, step 2 of 2, transaction is required to be successful before registering in step 2.""" 94 | return BunScriptRunner.bun_run("stacks-bns", "register.ts", bns_name) 95 | 96 | 97 | class StacksWalletTools: 98 | @staticmethod 99 | @tool("Get Wallet Addresses") 100 | def get_wallet_addresses(dummy_arg=None): 101 | """Get a list of the available addresses of the configured wallet by index.""" 102 | return BunScriptRunner.bun_run("wallet", "get-wallet-addresses.ts") 103 | 104 | @staticmethod 105 | @tool("Get Wallet Status") 106 | def get_wallet_status(dummy_arg=None): 107 | """Get information about the currently configured wallet address.""" 108 | return BunScriptRunner.bun_run("wallet", "get-wallet-status.ts") 109 | 110 | @staticmethod 111 | @tool("Get Transaction Data") 112 | def get_transaction_data(transaction_id: str): 113 | """Get an object that contains information about a given transaction ID.""" 114 | return BunScriptRunner.bun_run("wallet", "get-transaction.ts", transaction_id) 115 | 116 | @staticmethod 117 | @tool("Get Transaction Status") 118 | def get_transaction_status(transaction_id: str): 119 | """Get only the status of the transaction, usually pending or complete.""" 120 | return BunScriptRunner.bun_run( 121 | "wallet", "get-transaction-status.ts", transaction_id 122 | ) 123 | 124 | @staticmethod 125 | @tool("Sign Message") 126 | def sign_message(dummy_arg=None): 127 | """Sign a message with the configured wallet address.""" 128 | return BunScriptRunner.bun_run("wallet", "sign-message.ts") 129 | 130 | @staticmethod 131 | @tool("Get Address Balance Detailed") 132 | def get_address_balance_detailed(address: str): 133 | """Get detailed balance information for a given address.""" 134 | return BunScriptRunner.bun_run( 135 | "stacks-wallet", "get-address-balance-detailed.ts", address 136 | ) 137 | 138 | @staticmethod 139 | @tool("Get Address Transactions") 140 | def get_address_transactions(address: str): 141 | """Get 20 most recent transactions for a given address.""" 142 | return BunScriptRunner.bun_run( 143 | "stacks-wallet", "get-transactions-by-address.ts", address 144 | ) 145 | 146 | 147 | class WebsiteTools: 148 | @staticmethod 149 | @tool("Scrape Reddit URL") 150 | def scrape_reddit_url(website_url: str): 151 | """Targeted tool to scrape the provided Reddit URL using Selenium.""" 152 | scraping_tool = SeleniumScrapingTool(website_url=website_url, class_name="main") 153 | return scraping_tool._run() 154 | 155 | @staticmethod 156 | @tool("Scrape X (formerly Twitter) URL") 157 | def scrape_x_or_twitter_url(website_url: str): 158 | """Targeted tool to scrape the provided X (formerly Twitter) URL using Selenium.""" 159 | scraping_tool = SeleniumScrapingTool( 160 | website_url=website_url, class_name="css-175oi2r" 161 | ) 162 | return scraping_tool._run() 163 | 164 | @staticmethod 165 | @tool("Scrape Generic URL") 166 | def scrape_generic_url(website_url: str): 167 | """Scrape the provided URL using Selenium if the URL is unrecognized and it does not match any other tool.""" 168 | scraping_tool = SeleniumScrapingTool(website_url=website_url) 169 | return scraping_tool._run() 170 | 171 | 172 | # for the UI, returns dict of tool groups for display 173 | # automatically includes any function in the class 174 | def get_tool_groups(): 175 | return { 176 | "AIBTC Resources": AIBTCResourceTools, 177 | "AIBTC Token": AIBTCTokenTools, 178 | "Stacks BNS": StacksBNSTools, 179 | "Stacks Wallet": StacksWalletTools, 180 | "Website Tools": WebsiteTools, 181 | } 182 | -------------------------------------------------------------------------------- /legacy_code/bitcoin_crew_app.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from crewai import Crew, Process, Task 3 | from agents import BitcoinCrew 4 | 5 | # set global vars 6 | from dotenv import load_dotenv 7 | from langchain.globals import set_debug 8 | 9 | load_dotenv() 10 | set_debug(False) 11 | 12 | from langchain_openai import ChatOpenAI 13 | 14 | default_llm = ChatOpenAI( 15 | # model="gpt-4-turbo-preview" 16 | model="gpt-3.5-turbo-0125" 17 | ) 18 | 19 | 20 | def engage_crew_with_tasks(account_manger_tasks, resource_manager_tasks): 21 | # define agents 22 | account_manager_agent = BitcoinCrew.account_manager() 23 | resource_manager_agent = BitcoinCrew.resource_manager() 24 | 25 | # create a crew 26 | bitcoin_crew = Crew( 27 | agents=[account_manager_agent, resource_manager_agent], 28 | process=Process.sequential, 29 | tasks=account_manger_tasks + resource_manager_tasks, 30 | verbose=1, 31 | ) 32 | 33 | # run the crew against all tasks 34 | bitcoin_crew_result = bitcoin_crew.kickoff() 35 | 36 | return bitcoin_crew_result 37 | 38 | 39 | def run_bitcoin_crew_app(): 40 | st.title("Bitcoin Crew") 41 | 42 | # define agents 43 | account_manager_agent = BitcoinCrew.account_manager() 44 | resource_manager_agent = BitcoinCrew.resource_manager() 45 | 46 | # define the tasks 47 | account_manger_tasks = [ 48 | Task( 49 | description="What information do you know about the currently configured wallet?", 50 | agent=account_manager_agent, 51 | expected_output="The wallet address index, address, and nonce.", 52 | ), 53 | Task( 54 | description="What other wallet addresses do you have access to?", 55 | agent=account_manager_agent, 56 | expected_output="A list of wallet addresses organized by index.", 57 | ), 58 | Task( 59 | description="What is the aiBTC balance for your currently configured wallet?", 60 | agent=account_manager_agent, 61 | expected_output="The balance of aiBTC for the configured wallet.", 62 | ), 63 | Task( 64 | description="Get aiBTC from the faucet", 65 | agent=account_manager_agent, 66 | expected_output="The transaction ID for the aiBTC faucet drip.", 67 | ), 68 | Task( 69 | description="Get the transaction status for the aiBTC faucet drip", 70 | agent=account_manager_agent, 71 | expected_output="The status of the transaction for the aiBTC faucet drip.", 72 | ), 73 | ] 74 | resource_manager_tasks = [ 75 | Task( 76 | description="Get our configured wallet address and remember to use it in later tasks.", 77 | agent=resource_manager_agent, 78 | expected_output="The wallet address for the configured wallet.", 79 | ), 80 | Task( 81 | description="Get our most recent payment data", 82 | agent=resource_manager_agent, 83 | expected_output="The most recent payment data for our address.", 84 | ), 85 | Task( 86 | description="Get the available resource data", 87 | agent=resource_manager_agent, 88 | expected_output="The available resources in the contract.", 89 | ), 90 | Task( 91 | description="Get our user data by using the address from wallet status", 92 | agent=resource_manager_agent, 93 | expected_output="The user data for the address from the contract.", 94 | ), 95 | Task( 96 | description="Pay an invoice for a resource", 97 | agent=resource_manager_agent, 98 | expected_output="The transaction ID for the invoice payment.", 99 | ), 100 | Task( 101 | description="Get the transaction status for the invoice payment using the txid.", 102 | agent=resource_manager_agent, 103 | expected_output="The status of the transaction for the invoice payment.", 104 | ), 105 | ] 106 | 107 | tab1, tab2, tab3 = st.tabs(["Agents", "Tasks", "Engage Crew"]) 108 | 109 | with tab1: 110 | st.subheader(f"{account_manager_agent.role}") 111 | st.markdown(f"**Goal**: {account_manager_agent.goal}") 112 | st.markdown(f"**Backstory**: {account_manager_agent.backstory}") 113 | 114 | st.subheader(f"{resource_manager_agent.role}") 115 | st.markdown(f"**Goal**: {resource_manager_agent.goal}") 116 | st.markdown(f"**Backstory**: {resource_manager_agent.backstory}") 117 | 118 | with tab2: 119 | st.subheader("Account Manager Tasks") 120 | for task in account_manger_tasks: 121 | st.markdown(f"- {task.description}") 122 | 123 | st.subheader("Resource Manager Tasks") 124 | for task in resource_manager_tasks: 125 | st.markdown(f"- {task.description}") 126 | 127 | with tab3: 128 | if st.button("Engage Crew"): 129 | with st.expander("Running automated crew of AI agents!"): 130 | import sys 131 | import re 132 | import json 133 | 134 | class StreamToExpander: 135 | def __init__(self, expander): 136 | self.expander = expander 137 | self.buffer = [] 138 | self.current_agent = None 139 | 140 | def write(self, data): 141 | cleaned_data = re.sub(r"\x1B\[[0-9;]*[mK]", "", data) 142 | lines = cleaned_data.split("\n") 143 | for line in lines: 144 | if line.strip(): 145 | if "Working Agent:" in line: 146 | self.flush() 147 | agent_name = line.split("Working Agent:")[ 148 | -1 149 | ].strip() 150 | if agent_name != self.current_agent: 151 | self.current_agent = agent_name 152 | self.expander.markdown( 153 | f"### {self.current_agent}" 154 | ) 155 | else: 156 | self.buffer.append(line) 157 | else: 158 | self.buffer.append(line) 159 | 160 | def flush(self): 161 | if self.buffer: 162 | json_string = "\n".join(self.buffer) 163 | try: 164 | json_data = json.loads(json_string) 165 | self.expander.json(json_data) 166 | except json.JSONDecodeError: 167 | self.expander.text(json_string) 168 | self.buffer = [] 169 | 170 | sys.stdout = StreamToExpander(st) 171 | with st.spinner("Engaging Crew..."): 172 | crew_result = engage_crew_with_tasks( 173 | account_manger_tasks, resource_manager_tasks 174 | ) 175 | sys.stdout.flush() # Flush any remaining output 176 | 177 | st.header("Results:") 178 | st.markdown("```json\n" + crew_result + "\n```") 179 | 180 | 181 | if __name__ == "__main__": 182 | run_bitcoin_crew_app() 183 | -------------------------------------------------------------------------------- /legacy_code/bitcoin_crew_app_selections.py: -------------------------------------------------------------------------------- 1 | import io 2 | import contextlib 3 | import re 4 | import time 5 | import threading 6 | import streamlit as st 7 | from crewai import Crew, Process, Task 8 | from crewai.tasks import TaskOutput 9 | from agents import BitcoinCrew 10 | 11 | # set global vars 12 | from dotenv import load_dotenv 13 | from langchain.globals import set_debug 14 | 15 | load_dotenv() 16 | set_debug(False) 17 | 18 | from langchain_openai import ChatOpenAI 19 | 20 | 21 | @contextlib.contextmanager 22 | def capture_stdout(): 23 | buffer = io.StringIO() 24 | with contextlib.redirect_stdout(buffer): 25 | yield buffer 26 | 27 | 28 | default_llm = ChatOpenAI( 29 | # model="gpt-4-turbo-preview" 30 | model="gpt-3.5-turbo-0125" 31 | ) 32 | 33 | 34 | # initialize agent messages and avatars 35 | agent_messages = {} 36 | agent_avatars = { 37 | "Account Manager": "https://bitcoinfaces.xyz/api/get-image?name=account-manager", 38 | "Resource Manager": "https://bitcoinfaces.xyz/api/get-image?name=resource-manager", 39 | } 40 | 41 | # initialize chat history 42 | if "messages" not in st.session_state: 43 | st.session_state.messages = [] 44 | 45 | 46 | def task_output_to_string(output: TaskOutput) -> str: 47 | return f"Description: {output.description}\nSummary: {output.summary}\nResult: {output.result}" 48 | 49 | 50 | def get_task_description(output: TaskOutput) -> str: 51 | return f"{output.description}" 52 | 53 | 54 | def get_task_result(output: TaskOutput) -> str: 55 | return f"{output.raw_output}" 56 | 57 | 58 | def format_chat_message(agent_name, message): 59 | return f"**{agent_name}:**\n{message}" 60 | 61 | 62 | def display_agent_output(agent, messages, avatar_url, placeholder): 63 | with placeholder.container(): 64 | for message in messages: 65 | with st.chat_message(agent, avatar=avatar_url): 66 | st.write(format_chat_message(agent, message)) 67 | time.sleep(0.1) # Add a small delay for better visibility 68 | st.session_state.messages.append( 69 | {"role": agent, "content": "\n".join(messages)} 70 | ) 71 | 72 | 73 | file_output = [] 74 | 75 | 76 | def streamlit_callback(output: TaskOutput): 77 | agent_name = "Account Manager" # temporary 78 | 79 | if agent_name not in agent_messages: 80 | agent_messages[agent_name] = [] 81 | 82 | output_str = task_output_to_string(output) 83 | task_description = get_task_description(output) 84 | task_result = get_task_result(output) 85 | file_output.append(f"\n**{task_description}**\n\n{task_result}") 86 | agent_messages[agent_name].append(f"{task_description}\n\n{task_result}") 87 | 88 | # Update Streamlit UI in real-time 89 | avatar_url = agent_avatars.get(agent_name) 90 | placeholder = st.empty() # Create a placeholder for dynamic content 91 | display_agent_output( 92 | agent_name, agent_messages[agent_name], avatar_url, placeholder 93 | ) 94 | 95 | 96 | def engage_crew_with_tasks(selected_tasks): 97 | print("Engaging crew with tasks:", selected_tasks) 98 | # Clear the session state before engaging the crew 99 | st.session_state.messages = [] 100 | 101 | # define agents 102 | account_manager_agent = BitcoinCrew.account_manager() 103 | resource_manager_agent = BitcoinCrew.resource_manager() 104 | 105 | # Create a crew 106 | bitcoin_crew = Crew( 107 | agents=[account_manager_agent, resource_manager_agent], 108 | process=Process.sequential, 109 | tasks=selected_tasks, 110 | verbose=1, 111 | task_callback=lambda output: streamlit_callback(output), 112 | ) 113 | 114 | print("Kicking off the crew") 115 | crew_result = bitcoin_crew.kickoff() 116 | 117 | # Create a YYYY-MM-DD-HH-MM timestamp 118 | from datetime import datetime 119 | 120 | file_timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M") 121 | 122 | # create generated-meeting-agenda.md file with the result 123 | with open(f"wallet/{file_timestamp}-completed-tasks.md", "w") as file: 124 | file.write("# Wallet Crew\n\n") 125 | file.write("\n".join(file_output)) 126 | file.write("## Final Result\n\n") 127 | file.write(crew_result) 128 | 129 | 130 | def run_bitcoin_crew_app(): 131 | st.title("Bitcoin Crew") 132 | 133 | # define agents 134 | account_manager_agent = BitcoinCrew.account_manager() 135 | resource_manager_agent = BitcoinCrew.resource_manager() 136 | 137 | # define the tasks 138 | account_manger_tasks = [ 139 | Task( 140 | description="What information do you know about the currently configured wallet?", 141 | agent=account_manager_agent, 142 | expected_output="A markdown list including the wallet address index, address, and nonce.", 143 | ), 144 | Task( 145 | description="What other wallet addresses do you have access to?", 146 | agent=account_manager_agent, 147 | expected_output="A markdown list of wallet addresses organized by index.", 148 | ), 149 | Task( 150 | description="What is the aiBTC balance for your currently configured wallet?", 151 | agent=account_manager_agent, 152 | expected_output="The balance of aiBTC for the configured wallet in human readable form.", 153 | ), 154 | Task( 155 | description="Get aiBTC from the faucet", 156 | agent=account_manager_agent, 157 | expected_output="The transaction ID for the aiBTC faucet drip in human readable form.", 158 | ), 159 | Task( 160 | description="Get the transaction status for the aiBTC faucet drip", 161 | agent=account_manager_agent, 162 | expected_output="The status of the transaction for the aiBTC faucet drip in human readable form.", 163 | ), 164 | ] 165 | resource_manager_tasks = [ 166 | Task( 167 | description="Get our configured wallet address and remember to use it in later tasks.", 168 | agent=resource_manager_agent, 169 | expected_output="The wallet address for the configured wallet.", 170 | ), 171 | Task( 172 | description="Get our most recent payment data", 173 | agent=resource_manager_agent, 174 | expected_output="The most recent payment data for our address.", 175 | ), 176 | Task( 177 | description="Get the available resource data", 178 | agent=resource_manager_agent, 179 | expected_output="The available resources in the contract.", 180 | ), 181 | Task( 182 | description="Get our user data by using the address from wallet status", 183 | agent=resource_manager_agent, 184 | expected_output="The user data for the address from the contract.", 185 | ), 186 | Task( 187 | description="Pay an invoice for a resource", 188 | agent=resource_manager_agent, 189 | expected_output="The transaction ID for the invoice payment.", 190 | ), 191 | Task( 192 | description="Get the transaction status for the invoice payment using the txid.", 193 | agent=resource_manager_agent, 194 | expected_output="The status of the transaction for the invoice payment.", 195 | ), 196 | ] 197 | 198 | tab1, tab2, tab3 = st.tabs(["Agents", "Tasks", "Engage Crew"]) 199 | 200 | with tab1: 201 | st.subheader(f"{account_manager_agent.role}") 202 | st.markdown(f"**Goal**: {account_manager_agent.goal}") 203 | st.markdown(f"**Backstory**: {account_manager_agent.backstory}") 204 | 205 | st.subheader(f"{resource_manager_agent.role}") 206 | st.markdown(f"**Goal**: {resource_manager_agent.goal}") 207 | st.markdown(f"**Backstory**: {resource_manager_agent.backstory}") 208 | 209 | with tab2: 210 | st.subheader("Account Manager Tasks") 211 | selected_account_manager_tasks = [] 212 | for task in account_manger_tasks: 213 | if st.checkbox(task.description, key=f"account_manager_{task.description}"): 214 | selected_account_manager_tasks.append(task) 215 | 216 | st.subheader("Resource Manager Tasks") 217 | selected_resource_manager_tasks = [] 218 | for task in resource_manager_tasks: 219 | if st.checkbox( 220 | task.description, key=f"resource_manager_{task.description}" 221 | ): 222 | selected_resource_manager_tasks.append(task) 223 | 224 | selected_tasks = ( 225 | selected_account_manager_tasks + selected_resource_manager_tasks 226 | ) 227 | 228 | with tab3: 229 | st.subheader("Selected Tasks") 230 | if selected_tasks: 231 | for task in selected_tasks: 232 | st.write(f"- {task.description}") 233 | else: 234 | st.write("No tasks selected.") 235 | 236 | if st.button("Engage Crew", use_container_width=True): 237 | print("Engage Crew button clicked") 238 | with st.spinner("Engaging Crew..."): 239 | engage_crew_with_tasks(selected_tasks) 240 | print("Crew execution completed") 241 | 242 | 243 | if __name__ == "__main__": 244 | run_bitcoin_crew_app() 245 | -------------------------------------------------------------------------------- /legacy_code/meeting_preparation.py: -------------------------------------------------------------------------------- 1 | from crewai import Crew, Process, Task 2 | from crewai.tasks import TaskOutput 3 | from agents import MeetingsCrew 4 | from news_examples import good_example, bad_example 5 | 6 | from dotenv import load_dotenv 7 | from langchain.globals import set_debug 8 | 9 | load_dotenv() 10 | set_debug(False) 11 | 12 | from langchain_openai import ChatOpenAI 13 | 14 | default_llm = ChatOpenAI(model="gpt-4o") 15 | 16 | scraped_content_list = [] 17 | key_points_list = [] 18 | news_list = [] 19 | 20 | 21 | def build_scraped_content_list(crew_output: TaskOutput): 22 | scraped_content_list.append(crew_output.raw_output) 23 | 24 | 25 | def build_key_points_list(crew_output: TaskOutput): 26 | key_points_list.append(crew_output.raw_output) 27 | 28 | 29 | def build_news_list(url, content, summary): 30 | news_item = {"url": url, "content": content, "summary": summary} 31 | news_list.append(news_item) 32 | 33 | 34 | def create_scrape_website_task(url): 35 | return Task( 36 | description=( 37 | f"Provided URL: {url}. Fetch the contents of this tweet and return the raw content for use in a later step. " 38 | "Ensure you extract all relevant text content from the tweet without any HTML tags or extraneous information." 39 | ), 40 | expected_output="The entire contents of the tweet excluding any HTML code. Example: 'Tweet content here.'", 41 | agent=MeetingsCrew.website_scraper(), 42 | callback=build_scraped_content_list, 43 | ) 44 | 45 | 46 | def create_extract_key_points_task(url, scrape_task: Task): 47 | return Task( 48 | description=( 49 | "Using the tweet content, extract key points focusing on the most important information. " 50 | "Summarize the tweet in 1-2 sentences and format it according to the provided good example. " 51 | "Ensure the summary sentence includes a link to the original tweet in markdown format, and format any supporting points as bullet points." 52 | ), 53 | expected_output="Key points extracted from the tweet content, including the summary sentence with a markdown link to the original tweet. Example: 'Summary sentence [tweet_author](tweet_url).'", 54 | agent=MeetingsCrew.meeting_writer(), 55 | context=[scrape_task], 56 | callback=build_key_points_list, 57 | ) 58 | 59 | 60 | def create_task_list(url_list): 61 | tasks = [] 62 | for url in url_list: 63 | scrape_task = create_scrape_website_task(url) 64 | tasks.append(scrape_task) 65 | extract_key_points_task = create_extract_key_points_task(url, scrape_task) 66 | tasks.append(extract_key_points_task) 67 | return tasks 68 | 69 | 70 | def format_news_item(url, content, summary): 71 | tweet_author = url.split("/")[3] 72 | formatted_item = f"{summary} [{tweet_author}]({url})\n\n" 73 | if "-" in content: 74 | bullet_points = content.split("- ")[1:] 75 | for point in bullet_points: 76 | formatted_item += f"- {point.strip()}\n" 77 | return formatted_item 78 | 79 | 80 | def engage_crew_with_tasks(url_list): 81 | task_list = create_task_list(url_list) 82 | 83 | info_gathering_crew = Crew( 84 | agents=[ 85 | MeetingsCrew.website_scraper(), 86 | MeetingsCrew.meeting_writer(), 87 | ], 88 | process=Process.sequential, 89 | tasks=task_list, 90 | verbose=0, 91 | ) 92 | 93 | info_gathering_crew.kickoff() 94 | 95 | print("--------------------------------------------------") 96 | print(f"URL List: {len(url_list)} items.") 97 | print(url_list) 98 | print("--------------------------------------------------") 99 | 100 | print("--------------------------------------------------") 101 | print(f"Scraped Content List: {len(scraped_content_list)} items.") 102 | print(scraped_content_list) 103 | print("--------------------------------------------------") 104 | 105 | print("--------------------------------------------------") 106 | print(f"Key Points List: {len(key_points_list)} items.") 107 | print(key_points_list) 108 | print("--------------------------------------------------") 109 | 110 | for i in range(len(url_list)): 111 | build_news_list(url_list[i], scraped_content_list[i], key_points_list[i]) 112 | 113 | print("--------------------------------------------------") 114 | print("News List:") 115 | print(news_list) 116 | print("--------------------------------------------------") 117 | 118 | formatted_news_list = "" 119 | for item in news_list: 120 | formatted_news_list += format_news_item( 121 | item["url"], item["content"], item["summary"] 122 | ) 123 | 124 | agenda_preparation_crew = Crew( 125 | agents=[MeetingsCrew.meeting_writer()], 126 | process=Process.sequential, 127 | tasks=[ 128 | Task( 129 | description=( 130 | "The provided news list contains a URL, scraped content, and generated summary for each news item." 131 | "Your job is to review all of the news items and create a markdown file with a summary of the key points extracted from the tweets." 132 | "Ensure that the format adheres to the good example provided below and avoid the issues in the bad example." 133 | "[START GOOD EXAMPLE]" 134 | f"{good_example}" 135 | "[END GOOD EXAMPLE]" 136 | "[START BAD EXAMPLE]" 137 | f"{bad_example}" 138 | "[END BAD EXAMPLE]" 139 | "[START NEWS LIST]" 140 | f"{formatted_news_list}" 141 | "[END NEWS LIST]" 142 | ), 143 | expected_output=( 144 | "A markdown file with the L3 heading 'Latest AI News' and a bullet point summary of all the related information from each tweet. Example: 'Summary sentence [tweet_author](tweet_url).'" 145 | ), 146 | agent=MeetingsCrew.meeting_writer(), 147 | ) 148 | ], 149 | verbose=2, 150 | ) 151 | 152 | crew_result = agenda_preparation_crew.kickoff() 153 | 154 | print("--------------------------------------------------") 155 | print("Meeting Agenda Preparation Crew Final Result:") 156 | print(crew_result) 157 | print("--------------------------------------------------") 158 | 159 | from datetime import datetime 160 | 161 | file_timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M") 162 | 163 | with open(f"agendas/{file_timestamp}-generated-meeting-agenda.md", "w") as file: 164 | file.write("## Latest AI News\n") 165 | file.write(crew_result) 166 | 167 | 168 | if __name__ == "__main__": 169 | url_list = [ 170 | "https://x.com/hirosystems/status/1796579639982440751", 171 | "https://x.com/LangChainAI/status/1796942281821585864", 172 | "https://x.com/rohanpaul_ai/status/1798457077037469962", 173 | "https://x.com/Steve8708/status/1798720674875560220", 174 | ] 175 | engage_crew_with_tasks(url_list) 176 | -------------------------------------------------------------------------------- /legacy_code/meeting_summary.py: -------------------------------------------------------------------------------- 1 | from crewai import Crew, Process, Task 2 | from agents import MeetingsCrew 3 | 4 | # set global vars 5 | 6 | from dotenv import load_dotenv 7 | from langchain.globals import set_debug 8 | 9 | load_dotenv() 10 | set_debug(False) 11 | 12 | # set global llm 13 | 14 | from langchain_openai import ChatOpenAI 15 | 16 | default_llm = ChatOpenAI( 17 | model="gpt-4o" 18 | # model="gpt-4-turbo-preview" 19 | # model="gpt-3.5-turbo-0125" 20 | ) 21 | 22 | # load the transcript file 23 | 24 | # load the chat notes 25 | -------------------------------------------------------------------------------- /legacy_code/news_examples.py: -------------------------------------------------------------------------------- 1 | good_example = """ 2 | Survey of Americans shows [47% haven't heard of ChatGPT](https://x.com/emollick/status/1795515457228935658) 3 | 4 | - 7% use it on a daily basis 5 | - our intersection is even smaller 6 | - shows how early we are! 7 | 8 | Concept of an [agent-computer interface](https://x.com/JamesAlcorn94/status/1794897317503631394) 9 | 10 | - SWE-agent paper shows agents need LLM-native interfaces 11 | - Agent-computer interface vs human-computer interface 12 | - Existing interfaces (especially GUI) cause problems for agents 13 | - Agents could design their own (smart contracts come to mind!) 14 | 15 | CodeAct framework [suggests using Python instead of JSON](https://x.com/_philschmid/status/1795853856628199619) 16 | 17 | - LLM generates python code as the action 18 | - LLM executes python code with an interpreter 19 | - Captures output or error message, then refines 20 | - Released a [paper](https://huggingface.co/papers/2402.01030) and [related dataset](https://huggingface.co/datasets/xingyaoww/code-act) for training 21 | 22 | Great O'Reilly write-up on [building with LLMs](https://www.oreilly.com/radar/what-we-learned-from-a-year-of-building-with-llms-part-i/) 23 | 24 | - hard to develop products beyond demos 25 | - advice on prompting techniques, structured inputs 26 | - RAG is preferable to fine-tuning 27 | - multi-step workflows perform better 28 | - evaluation is critical, LLM-as-Judge can help assess 29 | - tackle hallucination through prompting and guardrails 30 | 31 | Running LLMs continues to get easier 32 | 33 | - Llama.cpp [available through Brew](https://x.com/victormustar/status/1795778241744998614) 34 | - AutoAWQ now [using Flash Attention 2](https://x.com/rohanpaul_ai/status/1795196332166070289) 35 | - can run Mixtral 8x7B MoE with 24gb GPU VRAM 36 | - Jan [surpassed 1M downloads!](https://x.com/janframework/status/1795328213478215999) 37 | - local, offline, ChatGPT-like interface and more 38 | - can host local models with OpenAI API 39 | 40 | SambaNova designed [a chip that outperforms GPUs](https://x.com/IntuitMachine/status/1795570166706720909) 41 | 42 | - the RDU architecture solves current limitations 43 | - performance similar to Groq, impressive output 44 | - this sector will undoubtedly continue to grow 45 | 46 | ChatGPT [system prompts leaked!](https://x.com/myfear/status/1795549367580950814) 47 | 48 | - modular in design, adapted based on available functionality 49 | - extracted through a custom prompt (common technique) 50 | 51 | New paper: [Detecting text from an LLM](https://x.com/jihoontack/status/1795350959482400890) 52 | 53 | - ReMoDetect uses reward models to detect aligned LLM-generated texts 54 | - uses human preference for AI-generated text to create reward model 55 | - continually fine-tunes the reward model to further increase predicted rewards 56 | 57 | Lots of new models across a lot of categories 58 | 59 | - Mistral [released Codestral 22B](https://x.com/dchaplot/status/1795823340533469560) (super powerful, restrictive licensing) 60 | - LLM360 [released K2-65B](https://x.com/llm360/status/1795833911580438807) (fully-open LLM) 61 | - OpenDriveLab [released Vista 2.5B](https://x.com/kashyap7x/status/1795354164874408363) (driving world model) 62 | - Cartesia [released Sonic](https://x.com/cartesia_ai/status/1795856778456084596) (generative voice model and API) 63 | - 2noise [released ChatTTS](https://x.com/Xianbao_QIAN/status/1795490474461118804) (voice generation model) 64 | - Qwen [download stats](https://x.com/huybery/status/1795432194460340708) and Qwen2 coming soon! 65 | 66 | Crazy [reverse turing test](https://x.com/AISafetyMemes/status/1795309403824165184) 67 | 68 | - LLMs playing "who's the human" using Claude, GPT4, and Gemini 69 | - eerie but fascinating, video games will never be the same! 70 | """ 71 | 72 | bad_example = """ 73 | - [Whether you're preparing for a hackathon or building an app, you'll eventually need on-chain data. 74 | 75 | RSVP in the link below]([https://x.com/hirosystems/status/1796579639982440751](https://x.com/hirosystems/status/1796579639982440751)) 76 | 77 | - Hosting a workshop next Tues to show an easy way to build lightweight databases of on-chain events for Stacks 78 | 79 | - [LangChain is an open source project called GPT Computer Assistant that aims to replicate the ChatGPT desktop app. The project can be found on GitHub at https://github.com/onuratakan/gpt-computer-assistant.](https://x.com/LangChainAI/status/1796942281821585864) 80 | 81 | - Easily installed via pip 82 | - Allows users to send text and screenshots to receive a voice response 83 | - Praises the speed of the OSS community 84 | - [Mesop, open-source Python UI framework used at Google to build AI/ML apps - Open sourced by Google](https://x.com/rohanpaul_ai/status/1798457077037469962) 85 | 86 | - Mesop is an open-source Python UI framework 87 | - Used at Google to build AI/ML apps 88 | - Google has open sourced Mesop 89 | - [Steve (Builder.io) would love your feedback https://github.com/BuilderIO/micro-agent…its customizable to your specific test criteria (vitest, jest, lint, tsc, etc)](https://x.com/Steve8708/status/1798720674875560220) 90 | 91 | - More useful than just asking chatgpt for code and having to discover where it's broken 92 | - Customizable to specific test criteria like vitest, jest, lint, tsc 93 | """ 94 | -------------------------------------------------------------------------------- /legacy_code/old_aibtcdev_streamlit.py: -------------------------------------------------------------------------------- 1 | import anthropic 2 | import streamlit as st 3 | from crewai import Crew, Agent, Task, Process 4 | from langchain_openai import ChatOpenAI 5 | from tools.wallet import WalletTools 6 | from tools.aibtc_token import AIBTCTokenTools 7 | from tools.onchain_resources import OnchainResourcesTools 8 | from utils import get_model_settings, save_model_settings, init_session_state 9 | 10 | 11 | # Set up Streamlit page 12 | st.set_page_config(page_title="AIBTCdev Crews", layout="wide") 13 | st.title("AIBTCdev Crews") 14 | 15 | # Get model settings 16 | MODEL_SETTINGS = get_model_settings() 17 | 18 | # Initialize session state 19 | init_session_state(MODEL_SETTINGS) 20 | 21 | 22 | def update_model(): 23 | model_name = st.session_state.llm_model 24 | model_settings = MODEL_SETTINGS.get(model_name, MODEL_SETTINGS["OpenAi"]) 25 | st.session_state.api_base = model_settings["OPENAI_API_BASE"] 26 | st.session_state.model_name = model_settings["OPENAI_MODEL_NAME"] 27 | 28 | 29 | def get_llm(): 30 | if st.session_state.llm_model == "Anthropic": 31 | return anthropic.Anthropic(api_key=st.session_state.api_key) 32 | else: 33 | return ChatOpenAI( 34 | model=st.session_state.model_name, 35 | openai_api_key=st.session_state.api_key, 36 | openai_api_base=st.session_state.api_base, 37 | ) 38 | 39 | 40 | # Sidebar Configuration 41 | with st.sidebar: 42 | st.title("AIBTCdev Settings") 43 | 44 | with st.expander("LLM Settings", expanded=True): 45 | llm_options = list(MODEL_SETTINGS.keys()) 46 | 47 | st.selectbox( 48 | "Select LLM Provider", 49 | options=llm_options, 50 | key="llm_model", 51 | on_change=update_model, 52 | ) 53 | 54 | st.text_input("API Base", value=st.session_state.api_base, key="api_base") 55 | st.text_input("Model", value=st.session_state.model_name, key="model_name") 56 | st.text_input( 57 | "API Key", value=st.session_state.api_key, key="api_key", type="password" 58 | ) 59 | 60 | st.divider() 61 | 62 | if st.button("Clear Chat"): 63 | st.session_state.messages = [] 64 | 65 | with st.expander("Manage Model Settings", expanded=False): 66 | new_provider = st.text_input("New Provider Name") 67 | new_model_name = st.text_input("New Model Name") 68 | new_api_base = st.text_input("New API Base") 69 | 70 | if st.button("Add/Update Provider"): 71 | if new_provider and new_model_name and new_api_base: 72 | MODEL_SETTINGS[new_provider] = { 73 | "OPENAI_MODEL_NAME": new_model_name, 74 | "OPENAI_API_BASE": new_api_base, 75 | } 76 | save_model_settings(MODEL_SETTINGS) 77 | st.success(f"Provider {new_provider} added/updated successfully!") 78 | else: 79 | st.error("Please fill in all fields to add/update a provider.") 80 | 81 | provider_to_remove = st.selectbox( 82 | "Select Provider to Remove", options=list(MODEL_SETTINGS.keys()) 83 | ) 84 | if st.button("Remove Provider"): 85 | if provider_to_remove in MODEL_SETTINGS: 86 | del MODEL_SETTINGS[provider_to_remove] 87 | save_model_settings(MODEL_SETTINGS) 88 | st.success(f"Provider {provider_to_remove} removed successfully!") 89 | else: 90 | st.error("Selected provider not found.") 91 | 92 | # Define agents 93 | try: 94 | llm = get_llm() 95 | 96 | wallet_manager = Agent( 97 | role="Wallet Manager", 98 | goal="Manage Bitcoin wallet operations and provide information", 99 | backstory="You are an expert in Bitcoin wallet management with deep knowledge of blockchain technology.", 100 | tools=[ 101 | WalletTools.get_wallet_status, 102 | WalletTools.get_wallet_addresses, 103 | WalletTools.get_transaction_data, 104 | WalletTools.get_transaction_status, 105 | AIBTCTokenTools.get_aibtc_balance, 106 | AIBTCTokenTools.get_faucet_drip, 107 | ], 108 | verbose=True, 109 | llm=llm, 110 | ) 111 | 112 | resource_manager = Agent( 113 | role="Resource Manager", 114 | goal="Manage on-chain resources and provide relevant information", 115 | backstory="You are an expert in managing blockchain resources and understanding complex on-chain data.", 116 | tools=[ 117 | OnchainResourcesTools.get_recent_payment_data, 118 | OnchainResourcesTools.get_resource_data, 119 | OnchainResourcesTools.get_user_data_by_address, 120 | OnchainResourcesTools.pay_invoice_for_resource, 121 | ], 122 | verbose=True, 123 | llm=llm, 124 | ) 125 | 126 | st.session_state.agents["Wallet Manager"] = wallet_manager 127 | st.session_state.agents["Resource Manager"] = resource_manager 128 | 129 | except Exception as e: 130 | st.error(f"Error initializing language model: {str(e)}") 131 | st.stop() 132 | 133 | # Define tasks 134 | wallet_status_task = Task( 135 | description="Get the current wallet status and display the information.", 136 | expected_output="A detailed report of the current wallet status including balance and recent transactions.", 137 | agent=wallet_manager, 138 | ) 139 | 140 | aibtc_balance_task = Task( 141 | description="Retrieve and display the current aiBTC balance.", 142 | expected_output="The current aiBTC balance as a numerical value with appropriate units.", 143 | agent=wallet_manager, 144 | ) 145 | 146 | faucet_drip_task = Task( 147 | description="Request aiBTC from the faucet and display the transaction ID.", 148 | expected_output="The transaction ID of the aiBTC faucet drip request.", 149 | agent=wallet_manager, 150 | ) 151 | 152 | get_resource_data_task = Task( 153 | description="Retrieve and display resource data for a given address", 154 | expected_output="A detailed report of the resource data associated with the provided address.", 155 | agent=resource_manager, 156 | ) 157 | 158 | st.session_state.tasks["Get Wallet Status"] = wallet_status_task 159 | st.session_state.tasks["Get aiBTC Balance"] = aibtc_balance_task 160 | st.session_state.tasks["Get aiBTC Faucet Drip"] = faucet_drip_task 161 | st.session_state.tasks["Get Resource Data"] = get_resource_data_task 162 | 163 | # Define crews 164 | wallet_crew = Crew( 165 | agents=[wallet_manager], 166 | tasks=[wallet_status_task, aibtc_balance_task, faucet_drip_task], 167 | process=Process.sequential, 168 | verbose=2, 169 | ) 170 | 171 | resource_crew = Crew( 172 | agents=[resource_manager], 173 | tasks=[get_resource_data_task], 174 | process=Process.sequential, 175 | verbose=2, 176 | ) 177 | 178 | st.session_state.crews["Wallet Crew"] = wallet_crew 179 | st.session_state.crews["Resource Crew"] = resource_crew 180 | 181 | 182 | # Tab functions 183 | def agents_tab(): 184 | st.header("Configured Agents") 185 | for agent_name, agent in st.session_state.agents.items(): 186 | with st.expander(agent_name): 187 | st.write(f"Role: {agent.role}") 188 | st.write(f"Goal: {agent.goal}") 189 | st.write(f"Backstory: {agent.backstory}") 190 | st.write("Tools:") 191 | for tool in agent.tools: 192 | st.write(f"- {tool.name}") 193 | 194 | 195 | def tasks_tab(): 196 | st.header("Configured Tasks") 197 | for task_name, task in st.session_state.tasks.items(): 198 | with st.expander(task_name): 199 | st.write(f"Description: {task.description}") 200 | st.write(f"Agent: {task.agent.role}") 201 | 202 | 203 | def crews_tab(): 204 | st.header("Configured Crews") 205 | for crew_name, crew in st.session_state.crews.items(): 206 | with st.expander(crew_name): 207 | st.write("Agents:") 208 | for agent in crew.agents: 209 | st.write(f"- {agent.role}") 210 | st.write("Tasks:") 211 | for task in crew.tasks: 212 | st.write(f"- {task.description}") 213 | 214 | 215 | def execution_tab(): 216 | st.header("Execution") 217 | initial_input = st.text_area( 218 | "Initial Input", "Enter your instructions or query here..." 219 | ) 220 | selected_crew = st.selectbox( 221 | "Select Crew", options=list(st.session_state.crews.keys()) 222 | ) 223 | 224 | crew = st.session_state.crews[selected_crew] 225 | available_tasks = [task.description for task in crew.tasks] 226 | selected_tasks = st.multiselect("Select Tasks", options=available_tasks) 227 | 228 | if st.button("Execute"): 229 | st.write("Execution Output:") 230 | # Filter the crew's tasks based on the selected task descriptions 231 | tasks_to_execute = [ 232 | task for task in crew.tasks if task.description in selected_tasks 233 | ] 234 | 235 | # Update the crew's tasks 236 | crew.tasks = tasks_to_execute 237 | 238 | # Execute the crew 239 | result = crew.kickoff() 240 | st.write(result) 241 | 242 | 243 | # Update crew definitions to include all possible tasks 244 | wallet_crew = Crew( 245 | agents=[wallet_manager], 246 | tasks=[wallet_status_task, aibtc_balance_task, faucet_drip_task], 247 | process=Process.sequential, 248 | verbose=2, 249 | ) 250 | 251 | resource_crew = Crew( 252 | agents=[resource_manager], 253 | tasks=[get_resource_data_task], 254 | process=Process.sequential, 255 | verbose=2, 256 | ) 257 | 258 | st.session_state.crews["Wallet Crew"] = wallet_crew 259 | st.session_state.crews["Resource Crew"] = resource_crew 260 | 261 | # Main layout with tabs 262 | tab1, tab2, tab3, tab4 = st.tabs(["Agents", "Tasks", "Crews", "Execution"]) 263 | 264 | with tab1: 265 | agents_tab() 266 | 267 | with tab2: 268 | tasks_tab() 269 | 270 | with tab3: 271 | crews_tab() 272 | 273 | with tab4: 274 | execution_tab() 275 | 276 | # Run the Streamlit app 277 | if __name__ == "__main__": 278 | st.sidebar.markdown("Welcome to AIBTCdev Interactive Wallet Manager!") 279 | -------------------------------------------------------------------------------- /legacy_code/run_crew.py: -------------------------------------------------------------------------------- 1 | from crewai import Crew, Process, Task 2 | from agents import BitcoinCrew 3 | 4 | # set global vars 5 | from dotenv import load_dotenv 6 | from langchain.globals import set_debug 7 | 8 | load_dotenv() 9 | set_debug(False) 10 | 11 | from langchain_openai import ChatOpenAI 12 | 13 | default_llm = ChatOpenAI( 14 | model="gpt-4o" 15 | # model="gpt-4-turbo-preview" 16 | # model="gpt-3.5-turbo-0125" 17 | ) 18 | 19 | 20 | def engage_crew_with_tasks(): 21 | # define agents 22 | account_manager_agent = BitcoinCrew.account_manager() 23 | resource_manager_agent = BitcoinCrew.resource_manager() 24 | 25 | # define the tasks 26 | account_manger_tasks = [ 27 | Task( 28 | description="What information do you know about the currently configured wallet?", 29 | agent=account_manager_agent, 30 | expected_output="The wallet address index, address, and nonce.", 31 | ), 32 | Task( 33 | description="What other wallet addresses do you have access to?", 34 | agent=account_manager_agent, 35 | expected_output="A list of wallet addresses organized by index.", 36 | ), 37 | Task( 38 | description="What is the aiBTC balance for your currently configured wallet?", 39 | agent=account_manager_agent, 40 | expected_output="The balance of aiBTC for the configured wallet.", 41 | ), 42 | Task( 43 | description="Get aiBTC from the faucet", 44 | agent=account_manager_agent, 45 | expected_output="The transaction ID for the aiBTC faucet drip.", 46 | ), 47 | Task( 48 | description="Get the transaction status for the aiBTC faucet drip", 49 | agent=account_manager_agent, 50 | expected_output="The status of the transaction for the aiBTC faucet drip.", 51 | ), 52 | ] 53 | resource_manager_tasks = [ 54 | Task( 55 | description="Get our configured wallet address and remember to use it in later tasks.", 56 | agent=resource_manager_agent, 57 | expected_output="The wallet address for the configured wallet.", 58 | ), 59 | Task( 60 | description="Get our most recent payment data", 61 | agent=resource_manager_agent, 62 | expected_output="The most recent payment data for our address.", 63 | ), 64 | Task( 65 | description="Get the available resource data", 66 | agent=resource_manager_agent, 67 | expected_output="The available resources in the contract.", 68 | ), 69 | Task( 70 | description="Get our user data by using the address from wallet status", 71 | agent=resource_manager_agent, 72 | expected_output="The user data for the address from the contract.", 73 | ), 74 | Task( 75 | description="Pay an invoice for a resource", 76 | agent=resource_manager_agent, 77 | expected_output="The transaction ID for the invoice payment.", 78 | ), 79 | Task( 80 | description="Get the transaction status for the invoice payment using the txid.", 81 | agent=resource_manager_agent, 82 | expected_output="The status of the transaction for the invoice payment.", 83 | ), 84 | ] 85 | 86 | # create a crew 87 | bitcoin_crew = Crew( 88 | agents=[account_manager_agent, resource_manager_agent], 89 | process=Process.sequential, 90 | tasks=account_manger_tasks + resource_manager_tasks, 91 | verbose=2, 92 | ) 93 | 94 | # run the crew against all tasks 95 | bitcoin_crew_result = bitcoin_crew.kickoff() 96 | 97 | # print the result 98 | print("--------------------------------------------------") 99 | print("Bitcoin Crew Final Result:") 100 | print(bitcoin_crew_result) 101 | print("--------------------------------------------------") 102 | 103 | 104 | if __name__ == "__main__": 105 | engage_crew_with_tasks() 106 | -------------------------------------------------------------------------------- /legacy_code/run_managed_crew.py: -------------------------------------------------------------------------------- 1 | from crewai import Crew, Process, Task 2 | from agents import BitcoinCrew 3 | 4 | # set global vars 5 | from dotenv import load_dotenv 6 | from langchain.globals import set_debug 7 | 8 | load_dotenv() 9 | set_debug(False) 10 | 11 | from langchain_openai import ChatOpenAI 12 | 13 | manager_llm = ChatOpenAI(model="gpt-4-turbo-preview") 14 | 15 | employee_llm = ChatOpenAI(model="gpt-3.5-turbo-0125") 16 | 17 | required_tasks = [ 18 | Task( 19 | description="What information do you know about the currently configured wallet?", 20 | expected_output="The wallet address index, address, and nonce.", 21 | ), 22 | Task( 23 | description="What other wallet addresses do you have access to?", 24 | expected_output="A list of wallet addresses organized by index.", 25 | ), 26 | Task( 27 | description="What is the aiBTC balance for your currently configured wallet?", 28 | expected_output="The balance of aiBTC for the configured wallet.", 29 | ), 30 | Task( 31 | description="Get aiBTC from the faucet", 32 | expected_output="The transaction ID for the aiBTC faucet drip.", 33 | ), 34 | Task( 35 | description="Get the transaction status for the aiBTC faucet drip", 36 | expected_output="The status of the transaction for the aiBTC faucet drip.", 37 | ), 38 | Task( 39 | description="Get our configured wallet address and remember to use it in later tasks.", 40 | expected_output="The wallet address for the configured wallet.", 41 | ), 42 | Task( 43 | description="Get our most recent payment data", 44 | expected_output="The most recent payment data for the configured wallet.", 45 | ), 46 | Task( 47 | description="Get the available resource data", 48 | expected_output="The available resources for the configured wallet.", 49 | ), 50 | Task( 51 | description="Get our user data by using the address from wallet status", 52 | expected_output="The user data for the address from the contract.", 53 | ), 54 | Task( 55 | description="Pay an invoice for a resource", 56 | expected_output="The transaction ID for the invoice payment.", 57 | ), 58 | Task( 59 | description="Get the transaction status for the invoice payment using the txid.", 60 | expected_output="The status of the transaction for the invoice payment.", 61 | ), 62 | ] 63 | 64 | 65 | def engage_crew_with_tasks(): 66 | # define agents 67 | account_manager_agent = BitcoinCrew.account_manager(llm=employee_llm) 68 | resource_manager_agent = BitcoinCrew.resource_manager(llm=employee_llm) 69 | 70 | # create a crew 71 | bitcoin_crew = Crew( 72 | agents=[account_manager_agent, resource_manager_agent], 73 | process=Process.hierarchical, 74 | manager_llm=manager_llm, 75 | tasks=required_tasks, 76 | verbose=2, 77 | ) 78 | 79 | # run the crew against all tasks 80 | bitcoin_crew_result = bitcoin_crew.kickoff() 81 | 82 | # print the result 83 | print("--------------------------------------------------") 84 | print("Bitcoin Crew Final Result:") 85 | print(bitcoin_crew_result) 86 | print("--------------------------------------------------") 87 | 88 | 89 | if __name__ == "__main__": 90 | engage_crew_with_tasks() 91 | -------------------------------------------------------------------------------- /legacy_code/tools/aibtc_token.py: -------------------------------------------------------------------------------- 1 | from .bun_runner import BunScriptRunner 2 | from langchain.tools import tool 3 | 4 | 5 | class AIBTCTokenTools: 6 | @tool("Get current aiBTC balance") 7 | @staticmethod 8 | def get_aibtc_balance(dummy_arg=None): 9 | """Get the aiBTC balance of the currently configured wallet.""" 10 | return BunScriptRunner.bun_run("stacks-m2m-aibtc", "get-balance.ts") 11 | 12 | @tool("Get 10,000 aiBTC from the faucet") 13 | @staticmethod 14 | def get_faucet_drip(dummy_arg=None): 15 | """Transfers 10,000 aiBTC from the faucet to your configured address and returns a transaction ID.""" 16 | return BunScriptRunner.bun_run("stacks-m2m-aibtc", "faucet-drip.ts") 17 | 18 | @tool("Get 1,000,000 aiBTC from the faucet") 19 | @staticmethod 20 | def get_faucet_drop(dummy_arg=None): 21 | """Transfers 1,000,000 aiBTC from the faucet to your configured address and returns a transaction ID.""" 22 | return BunScriptRunner.bun_run("stacks-m2m-aibtc", "faucet-drop.ts") 23 | 24 | @tool("Get 100,000,000 aiBTC from the faucet") 25 | @staticmethod 26 | def get_faucet_flood(dummy_arg=None): 27 | """Transfers 100,000,000 aiBTC from the faucet to your configured address and returns a transaction ID.""" 28 | return BunScriptRunner.bun_run("stacks-m2m-aibtc", "get-faucet-flood.ts") 29 | -------------------------------------------------------------------------------- /legacy_code/tools/bun_runner.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | class BunScriptRunner: 4 | working_dir = "./agent-tools-ts/" 5 | script_dir = "src" 6 | 7 | @staticmethod 8 | def bun_run(contract_name: str, script_name: str, arg: str = None): 9 | """Runs a TypeScript script using bun with an optional positional argument.""" 10 | command = [ 11 | "bun", 12 | "run", 13 | f"{BunScriptRunner.script_dir}/{contract_name}/{script_name}", 14 | ] 15 | 16 | # Append the optional argument if provided 17 | if arg is not None: 18 | command.append(arg) 19 | 20 | try: 21 | result = subprocess.run( 22 | command, 23 | check=True, 24 | text=True, 25 | capture_output=True, 26 | cwd=BunScriptRunner.working_dir, 27 | ) 28 | return {"output": result.stdout, "error": None, "success": True} 29 | except subprocess.CalledProcessError as e: 30 | return {"output": None, "error": e.stderr, "success": False} 31 | -------------------------------------------------------------------------------- /legacy_code/tools/onchain_resources.py: -------------------------------------------------------------------------------- 1 | from .bun_runner import BunScriptRunner 2 | from langchain.tools import tool 3 | 4 | 5 | class OnchainResourcesTools: 6 | @tool("Get recent payment data for an address") 7 | @staticmethod 8 | def get_recent_payment_data(address: str): 9 | """Get the recent payment data for a given address.""" 10 | return BunScriptRunner.bun_run( 11 | "stacks-m2m-v2", "get-recent-payment-data-by-address.ts", address 12 | ) 13 | 14 | @tool("Get resource data for a resource") 15 | @staticmethod 16 | def get_resource_data(dummy_arg: None): 17 | """Get the resource data for the resource.""" 18 | return BunScriptRunner.bun_run("stacks-m2m-v2", "get-resource-by-name.ts") 19 | 20 | @tool("Get user data by address") 21 | @staticmethod 22 | def get_user_data_by_address(address: str): 23 | """Get the user data for a given address.""" 24 | return BunScriptRunner.bun_run( 25 | "stacks-m2m-v2", "get-user-data-by-address.ts", address 26 | ) 27 | 28 | @tool("Pay invoice for resource") 29 | @staticmethod 30 | def pay_invoice_for_resource(dummy_arg: None): 31 | """Pay the invoice for a given resource.""" 32 | return BunScriptRunner.bun_run("stacks-m2m-v2", "pay-invoice.ts") 33 | -------------------------------------------------------------------------------- /legacy_code/tools/wallet.py: -------------------------------------------------------------------------------- 1 | from .bun_runner import BunScriptRunner 2 | from langchain.tools import tool 3 | 4 | 5 | class WalletTools: 6 | @tool("Get Wallet Addresses") 7 | @staticmethod 8 | def get_wallet_addresses(dummy_arg=None): 9 | """Get a list of the available addresses of the configured wallet by index.""" 10 | return BunScriptRunner.bun_run("wallet", "get-wallet-addresses.ts") 11 | 12 | @tool("Get Wallet Status") 13 | @staticmethod 14 | def get_wallet_status(dummy_arg=None): 15 | """Get information about the currently configured wallet address.""" 16 | return BunScriptRunner.bun_run("wallet", "get-wallet-status.ts") 17 | 18 | @tool("Get Transaction Data") 19 | @staticmethod 20 | def get_transaction_data(transaction_id: str): 21 | """Get an object that contains information about a given transaction ID.""" 22 | return BunScriptRunner.bun_run("wallet", "get-transaction.ts", transaction_id) 23 | 24 | @tool("Get Transaction Status") 25 | @staticmethod 26 | def get_transaction_status(transaction_id: str): 27 | """Get only the status of the transaction, usually pending or complete.""" 28 | return BunScriptRunner.bun_run( 29 | "wallet", "get-transaction-status.ts", transaction_id 30 | ) 31 | 32 | @tool("Sign Message") 33 | @staticmethod 34 | def sign_message(dummy_arg=None): 35 | """Sign a message with the configured wallet address.""" 36 | return BunScriptRunner.bun_run("wallet", "sign-message.ts") 37 | -------------------------------------------------------------------------------- /legacy_code/tools/web_scraper.py: -------------------------------------------------------------------------------- 1 | from crewai_tools import SeleniumScrapingTool, tool 2 | 3 | 4 | class WebTools: 5 | @staticmethod 6 | @tool 7 | def scrape_reddit_url(website_url: str): 8 | """Targeted tool to scrape the provided Reddit URL using Selenium.""" 9 | scraping_tool = SeleniumScrapingTool(website_url=website_url, class_name="main") 10 | return scraping_tool._run() 11 | 12 | @staticmethod 13 | @tool 14 | def scrape_x_or_twitter_url(website_url: str): 15 | """Targeted tool to scrape the provided X (formerly Twitter) URL using Selenium.""" 16 | scraping_tool = SeleniumScrapingTool( 17 | website_url=website_url, class_name="css-175oi2r" 18 | ) 19 | return scraping_tool._run() 20 | 21 | @staticmethod 22 | @tool 23 | def scrape_generic_url(website_url: str): 24 | """Scrape the provided URL using Selenium if the URL is unrecognized and it does not match any other tool.""" 25 | scraping_tool = SeleniumScrapingTool(website_url=website_url) 26 | return scraping_tool._run() 27 | -------------------------------------------------------------------------------- /replit.nix: -------------------------------------------------------------------------------- 1 | {pkgs}: { 2 | deps = [ 3 | pkgs.bun 4 | pkgs.glibcLocales 5 | pkgs.bash 6 | pkgs.libxcrypt 7 | ]; 8 | } 9 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | anthropic 2 | chromadb 3 | crewai 4 | crewai_tools 5 | langchain 6 | langchain_ollama 7 | langchain_openai 8 | pandas 9 | pydantic 10 | python-dotenv 11 | PyYAML 12 | streamlit 13 | streamlit-mermaid 14 | ollama --------------------------------------------------------------------------------