Skip to content

Zakk-Yang/smart-team

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Smart Team

A flexible and extensible framework for building multi-agent systems with support for OpenAI, Anthropic, and Ollama models.

Features

  • Multi-agent orchestration system
  • Support for multiple LLM providers:
    • OpenAI
    • Anthropic
    • Ollama (Local models)
  • Function calling capabilities
  • Specialized agents for different tasks:
    • Weather information
    • Web search
    • Code assistance
  • Dynamic agent switching based on task requirements
  • You can define your own agents and functions
  • Currently, it is for educational purposes only, not for production use
  • Run the main.py file to start the agent framework (don't forget to set up your API keys in the .env file)

Installation

Clone the repository:

git clone https://github.com/Zakk-Yang/smart-team.git
cd smart-team

Install the package:

pip install -e .

Requirements

  • Python 3.8+
  • OpenAI API key (for OpenAI models)
  • Anthropic API key (for Claude models)
  • Ollama installed locally (for local models)

Environment Setup

Create a .env file with your API keys:

OPENAI_API_KEY=your_openai_key
ANTHROPIC_API_KEY=your_anthropic_key

For Ollama, ensure you have it installed and running locally (default: http://localhost:11434) (Ollama models are not ideal in function calling, so I suggest to use OpenAI or Anthropic instead)

Usage

Create your own main.py file:

"""Main entry point for the agent framework"""

from enum import Enum, auto
from anthropic import Anthropic
from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional
import os
from dynamic_agent.utils.function_schema import create_function_schema, SchemaFormat
from smart_team.agents.agent_functions import (
    create_virtualenv,
    install_package,
    execute_code,
    get_weather,
    search_and_fetch_content,
)
from smart_team.agents.base_agent import BaseAgent
from smart_team.agents.anthropic_agent import AnthropicAgent
from smart_team.agents.openai_agent import OpenAIAgent
from smart_team.agents.ollama_agent import OllamaAgent


def transfer_to_weather(task: str) -> BaseAgent:
    """Transfer control to the weather bot
    Args:
        task (str, optional): Give the weather bot the task.
    """
    return weather_bot


def transfer_to_search(task: str) -> BaseAgent:
    """Transfer control to the search bot
    Args:
        task (str, optional): Give the search bot the task.
    """
    return search_bot


def transfer_to_orchestrator(task: str) -> BaseAgent:
    """Transfer control back to the ochestrator when assigned tasks are done or need additional supports
    Args:
        task (str, optional): Update the ochestrator what have been done and what errors have been made.
    """
    return orchestrator


def transfer_to_code(task: str) -> BaseAgent:
    """Transfer control to the code bot
    Args:
        task (str, optional): Give the code bot the task.
    """
    return code_bot


# Initialize the weather bot
weather_bot = OpenAIAgent(
    api_key=os.getenv("OPENAI_API_KEY"),
    model="gpt-4o-mini",
    name="WeatherBot",
    instructions="""
    You are the weather bot. Your role is to:
    1. Get weather information for specified locations
    2. After completing the task, return control to orchestrator
    3. DO NOT suggest additional weather checks unless asked by the user
    4. Initiaite multiple functions in the same result
    """,
    functions=[get_weather, transfer_to_orchestrator],
)

# Initialize the weather bot
search_bot = OpenAIAgent(
    api_key=os.getenv("OPENAI_API_KEY"),
    model="gpt-4o-mini",
    name="SearchBot",
    instructions="""
    You are the Search bot. Your role is to:
    1. Get required information using search_and_fetch_content function
    2. For multiple search quries, execute the function multiple times
    3. After completing the task, return control to orchestrator
    """,
    functions=[search_and_fetch_content, transfer_to_orchestrator],
)


# Initialize the code bot
code_bot = AnthropicAgent(
    name="CodeBot",
    model="claude-3-5-sonnet-latest",
    instructions="""
    You are the coding assistant. Your role is to:
    1. Help users with coding tasks and questions
    2. Create env (stick to the env name as python_env), install packages, generate and debug code
    3. Initiaite multiple functions in the same result(create_virtualenv, install_package, execute_code, transfer_to_orchestrator)
    4. After completing a task, return control to orchestrator
    5. DO NOT suggest additional coding tasks unless asked by the user
    6. Always transfer control back to the orchestrator using transfer_to_orchestrator
    """,
    api_key=os.getenv("ANTHROPIC_API_KEY"),
    functions=[
        create_virtualenv,
        install_package,
        execute_code,
        transfer_to_orchestrator,
    ],
)

# Initialize the orchestrator
orchestrator = AnthropicAgent(
    api_key=os.getenv("ANTHROPIC_API_KEY"),
    model="claude-3-5-sonnet-latest",
    is_orchestrator=True,
    name="OrchestratorBot",
    instructions="""
    You are the orchestrator bot. Your role is to:
    1. Transfer control to other bots based on user input:
        - Analyze the request and determine which bot should handle it
        - Use transfer functions as follows:
            - Example: transfer_to_agentx(task = "Get temperature in New York")
    
    2. When a taks is done by an agent, it will be transfered to you for you to decide which agent to transfer to for the next task
    3. Always summarize what have been done and what errors have been made
    4. When loads of information is retrieved(for example, multiple search results), always make good structure of it using bullet points
    """,
    functions=[
        transfer_to_weather,
        transfer_to_search,
        transfer_to_code,
    ],
)


def main():
    active_agent = orchestrator
    cross_agent_memories = []
    while True:
        messages = []
        if cross_agent_memories and active_agent.is_ochestrator is True:
            messages.append(
                {
                    "role": "assistant",
                    "content": f"The following is the hitorical conversation history: {str(cross_agent_memories)}",
                }
            )
        else:
            messages = []
            user_input = input("\nEnter your request (or 'exit' to quit): ")
            if user_input.lower() == "exit":
                break
            messages = [
                {
                    "role": "user",
                    "content": (
                        f"{user_input} + {active_agent.instructions} + The following is the hitorical conversation history(null if none): {str(cross_agent_memories)}"
                    ).strip(),
                }
            ]
        result = active_agent.send_message(messages)
        print(result.text)
        cross_agent_memories.append({"role": "user", "content": user_input})
        cross_agent_memories.append({"role": "assistant", "content": result.text})

        while result.function_calls:
            for func_call in result.function_calls:
                func_name = func_call["name"]
                func_params = func_call["parameters"]
                cross_agent_memories.append(
                    {
                        "role": "assistant",
                        "content": f"{active_agent.name} Is Starting Function Call: {func_name}({func_params})",
                    }
                )
                ################# Start Transfer and Execution Logic #################
                if func_name.startswith("transfer_to_"):
                    print(f"Transferring to {func_name}!!!")
                    func = next(
                        (f for f in active_agent.functions if f.__name__ == func_name),
                        None,
                    )
                    new_agent = func(**func_params)
                    active_agent = new_agent
                    print(f"New Agent Name:{active_agent.name}")
                    cross_agent_memories.append(
                        {
                            "role": "assistant",
                            "content": f"{active_agent.name} is Transferring Function Call: {func_name}({func_params})",
                        }
                    )
                    agent_memory = [
                        mem
                        for mem in cross_agent_memories
                        if mem["content"].startswith(active_agent.name)
                    ]
                    # New Agent Function Execution After Transfer
                    messages = [
                        {
                            "role": "user",
                            "content": (
                                str(agent_memory) + active_agent.instructions
                            ).strip(),
                        }
                    ]
                    result = active_agent.send_message(messages)
                    print(result)

                    agent_function_mapping = {
                        fun.__name__: fun for fun in active_agent.functions
                    }
                    should_break = False
                    ################ Run the Agent Functions ################
                    while (
                        active_agent.is_ochestrator is not True
                        and result.function_calls
                    ):
                        # Execute the agent functions
                        for func_call in result.function_calls:
                            try:
                                func_name = func_call["name"]
                                # Check for transfer to orchestrator first
                                if func_name == "transfer_to_orchestrator":
                                    should_break = True
                                    break

                                func_params = func_call["parameters"]
                                func = agent_function_mapping[func_name]
                                func_result = func(**func_call["parameters"])
                                print(
                                    f"{active_agent.name} Finished the Function Result:{func_name} Finished. Result: {func_result}"
                                )
                                cross_agent_memories.append(
                                    {
                                        "role": "assistant",
                                        "content": f"{active_agent.name} Finished the Function Call: {func_name}({func_params} with {func_result})",
                                    }
                                )

                            except Exception as e:
                                error_msg = {
                                    "role": "assistant",
                                    "content": f"Error executing {func_name}: {str(e)}",
                                }
                                print(error_msg)
                                cross_agent_memories.append(error_msg)

                        if should_break:
                            break

                        # Only send new message if we're continuing
                        agent_memory = [
                            mem
                            for mem in cross_agent_memories
                            if mem["content"].startswith(active_agent.name)
                        ]
                        messages = [
                            {
                                "role": "user",
                                "content": (
                                    str(agent_memory) + active_agent.instructions
                                ).strip(),
                            }
                        ]
                        print(messages)
                        result = active_agent.send_message(messages)


if __name__ == "__main__":
    main()

License

MIT License

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published