diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml index 55e4b49f..5f58b11d 100644 --- a/.github/workflows/codacy.yml +++ b/.github/workflows/codacy.yml @@ -40,7 +40,7 @@ jobs: # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - name: Run Codacy Analysis CLI - uses: codacy/codacy-analysis-cli-action@5cc54a75f9ad88159bb54046196d920e40e367a5 + uses: codacy/codacy-analysis-cli-action@33d455949345bddfdb845fba76b57b70cc83754b with: # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository # You can also omit the token and run the tools that support default configurations diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 889774f0..bd98222f 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -25,7 +25,7 @@ jobs: - name: Build package run: python -m build - name: Publish package - uses: pypa/gh-action-pypi-publish@2f6f737ca5f74c637829c0f5c3acd0e29ea5e8bf + uses: pypa/gh-action-pypi-publish@e53eb8b103ffcb59469888563dc324e3c8ba6f06 with: user: __token__ password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.gitignore b/.gitignore index 62014a4f..d142b5e4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,11 +11,13 @@ dataframe/ static/generated runs chroma +Unit Testing Agent_state.json swarms/__pycache__ venv .DS_Store - +Cargo.lock .DS_STORE +Cargo.lock swarms/agents/.DS_Store _build diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..87d3cd0a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "swarms-runtime" # The name of your project +version = "0.1.0" # The current version, adhering to semantic versioning +edition = "2021" # Specifies which edition of Rust you're using, e.g., 2018 or 2021 +authors = ["Your Name "] # Optional: specify the package authors +license = "MIT" # Optional: the license for your project +description = "A brief description of my project" # Optional: a short description of your project + +[dependencies] +cpython = "0.5" +rayon = "1.5" + +[dependencies.pyo3] +version = "0.20.3" +features = ["extension-module", "auto-initialize"] diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..91b75cae --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +# Use an official CUDA runtime as a parent image +FROM nvidia/cuda:11.4.2-runtime-ubuntu20.04 + +# Set the working directory in the container to /app +WORKDIR /app + +# Copy the current directory contents into the container at /app +COPY . /app + +# Install any needed packages specified in requirements.txt +RUN apt-get update && apt-get install -y \ + python3-pip \ + && rm -rf /var/lib/apt/lists/* +RUN pip3 install --no-cache-dir -r requirements.txt + +# Make port 80 available to the world outside this container +EXPOSE 80 + +# Define environment variable +# ENV NAME World + +# Run app.py when the container launches +CMD ["python3", "example.py"] \ No newline at end of file diff --git a/README.md b/README.md index 1b22bc10..4361355f 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Run example in Collab: is located inside the text! ```python -import os -from dotenv import load_dotenv -from swarms import OpenAIChat, Task, RecursiveWorkflow, Agent +import os + +from dotenv import load_dotenv + +from swarms import Agent, OpenAIChat, RecursiveWorkflow, Task # Load environment variables from .env file load_dotenv() @@ -293,8 +282,6 @@ workflow.add(task3) # Run the workflow workflow.run() - - ``` @@ -310,7 +297,7 @@ import os from dotenv import load_dotenv -from swarms import Anthropic, Gemini, Mixtral, OpenAIChat, ModelParallelizer +from swarms import Anthropic, Gemini, Mixtral, ModelParallelizer, OpenAIChat load_dotenv() @@ -352,10 +339,7 @@ import os from dotenv import load_dotenv -from swarms import ( - OpenAIChat, - Conversation, -) +from swarms import Conversation, OpenAIChat conv = Conversation( time_enabled=True, @@ -370,6 +354,7 @@ api_key = os.environ.get("OPENAI_API_KEY") # Initialize the language model llm = OpenAIChat(openai_api_key=api_key, model_name="gpt-4") + # Run the language model in a loop def interactive_conversation(llm): conv = Conversation() @@ -378,9 +363,7 @@ def interactive_conversation(llm): conv.add("user", user_input) if user_input.lower() == "quit": break - task = ( - conv.return_history_as_string() - ) # Get the conversation history + task = conv.return_history_as_string() # Get the conversation history out = llm(task) conv.add("assistant", out) print( @@ -392,7 +375,6 @@ def interactive_conversation(llm): # Replace with your LLM instance interactive_conversation(llm) - ``` @@ -411,7 +393,7 @@ import os from dotenv import load_dotenv # Import the OpenAIChat model and the Agent struct -from swarms import OpenAIChat, Agent, SwarmNetwork +from swarms import Agent, OpenAIChat, SwarmNetwork # Load the environment variables load_dotenv() @@ -448,11 +430,8 @@ print(out) # Run all the agents in the swarm network on a task -out = swarmnet.run_many_agents( - "Generate a 10,000 word blog on health and wellness." -) +out = swarmnet.run_many_agents("Generate a 10,000 word blog on health and wellness.") print(out) - ``` @@ -519,8 +498,6 @@ else: # Output the result of the task print(f"Task result: {task.result}") - - ``` --- @@ -541,14 +518,7 @@ from dotenv import load_dotenv from transformers import AutoModelForCausalLM, AutoTokenizer # Import the models, structs, and telemetry modules -from swarms import ( - Gemini, - GPT4VisionAPI, - Mixtral, - OpenAI, - ToolAgent, - BlocksList, -) +from swarms import BlocksList, Gemini, GPT4VisionAPI, Mixtral, OpenAI, ToolAgent # Load the environment variables load_dotenv() @@ -558,9 +528,7 @@ openai_api_key = os.getenv("OPENAI_API_KEY") gemini_api_key = os.getenv("GEMINI_API_KEY") # Tool Agent -model = AutoModelForCausalLM.from_pretrained( - "databricks/dolly-v2-12b" -) +model = AutoModelForCausalLM.from_pretrained("databricks/dolly-v2-12b") tokenizer = AutoTokenizer.from_pretrained("databricks/dolly-v2-12b") json_schema = { "type": "object", @@ -571,9 +539,7 @@ json_schema = { "courses": {"type": "array", "items": {"type": "string"}}, }, } -toolagent = ToolAgent( - model=model, tokenizer=tokenizer, json_schema=json_schema -) +toolagent = ToolAgent(model=model, tokenizer=tokenizer, json_schema=json_schema) # Blocks List which enables you to build custom swarms by adding classes or functions swarm = BlocksList( @@ -625,9 +591,7 @@ blocks_by_parent_name = swarm.get_by_parent_name(swarm.name) blocks_by_parent_type = swarm.get_by_parent_type(type(swarm).__name__) # Get blocks by parent description -blocks_by_parent_description = swarm.get_by_parent_description( - swarm.description -) +blocks_by_parent_description = swarm.get_by_parent_description(swarm.description) # Run the block in the swarm inference = swarm.run_block(toolagent, "Hello World") @@ -642,25 +606,27 @@ Here's a production grade swarm ready for real-world deployment in a factory and ```python -from swarms.structs import Agent import os + from dotenv import load_dotenv + from swarms.models import GPT4VisionAPI from swarms.prompts.logistics import ( + Efficiency_Agent_Prompt, Health_Security_Agent_Prompt, - Quality_Control_Agent_Prompt, Productivity_Agent_Prompt, + Quality_Control_Agent_Prompt, Safety_Agent_Prompt, Security_Agent_Prompt, Sustainability_Agent_Prompt, - Efficiency_Agent_Prompt, ) +from swarms.structs import Agent # Load ENV load_dotenv() api_key = os.getenv("OPENAI_API_KEY") -# GPT4VisionAPI +# GPT4VisionAPI llm = GPT4VisionAPI(openai_api_key=api_key) # Image for analysis @@ -692,9 +658,7 @@ productivity_agent = Agent( ) # Initiailize safety agent -safety_agent = Agent( - llm=llm, sop=Safety_Agent_Prompt, max_loops=1, multi_modal=True -) +safety_agent = Agent(llm=llm, sop=Safety_Agent_Prompt, max_loops=1, multi_modal=True) # Init the security agent security_agent = Agent( @@ -754,7 +718,9 @@ Run the agent with multiple modalities useful for various real-world tasks in ma ```python # Description: This is an example of how to use the Agent class to run a multi-modal workflow import os + from dotenv import load_dotenv + from swarms.models.gpt4_vision_api import GPT4VisionAPI from swarms.structs import Agent @@ -781,17 +747,11 @@ img = "assembly_line.jpg" ## Initialize the workflow agent = Agent( - llm=llm, - max_loops="auto", - autosave=True, - dashboard=True, - multi_modal=True + llm=llm, max_loops="auto", autosave=True, dashboard=True, multi_modal=True ) # Run the workflow on a task agent.run(task=task, img=img) - - ``` --- @@ -863,14 +823,10 @@ model = QwenVLMultiModal( ) # Run the model -response = model( - "Hello, how are you?", "https://example.com/image.jpg" -) +response = model("Hello, how are you?", "https://example.com/image.jpg") # Print the response print(response) - - ``` @@ -888,7 +844,6 @@ out = model.run("Analyze the reciepts in this image", "docs.jpg") # Print the output print(out) - ``` @@ -929,8 +884,6 @@ model.set_max_length(200) # Clear the chat history of the model model.clear_chat_history() - - ``` ## Radically Simple AI Model APIs @@ -947,9 +900,7 @@ We provide a vast array of language and multi-modal model APIs for you to genera from swarms.models import Anthropic # Initialize an instance of the Anthropic class -model = Anthropic( - anthropic_api_key="" -) +model = Anthropic(anthropic_api_key="") # Using the run method completion_1 = model.run("What is the capital of France?") @@ -958,7 +909,6 @@ print(completion_1) # Using the __call__ method completion_2 = model("How far is the moon from the earth?", stop=["miles", "km"]) print(completion_2) - ``` @@ -970,12 +920,16 @@ from swarms.models import HuggingfaceLLM custom_config = { "quantize": True, "quantization_config": {"load_in_4bit": True}, - "verbose": True + "verbose": True, } -inference = HuggingfaceLLM(model_id="NousResearch/Nous-Hermes-2-Vision-Alpha", **custom_config) +inference = HuggingfaceLLM( + model_id="NousResearch/Nous-Hermes-2-Vision-Alpha", **custom_config +) # Generate text based on a prompt -prompt_text = "Create a list of known biggest risks of structural collapse with references" +prompt_text = ( + "Create a list of known biggest risks of structural collapse with references" +) generated_text = inference(prompt_text) print(generated_text) ``` @@ -1033,7 +987,6 @@ task = "A person is walking on the street." # Generate the video! video_path = zeroscope(task) print(video_path) - ``` @@ -1187,11 +1140,61 @@ Join our growing community around the world, for real-time support, ideas, and d ## Discovery Call Book a discovery call to learn how Swarms can lower your operating costs by 40% with swarms of autonomous agents in lightspeed. [Click here to book a time that works for you!](https://calendly.com/swarm-corp/30min?month=2023-11) + + ## Accelerate Backlog Help us accelerate our backlog by supporting us financially! Note, we're an open source corporation and so all the revenue we generate is through donations at the moment ;) + +## File Structure +The swarms package has been meticlously crafted for extreme use-ability and understanding, the swarms package is split up into various modules such as `swarms.agents` that holds pre-built agents, `swarms.structs` that holds a vast array of structures like `Agent` and multi agent structures. The 3 most important are `structs`, `models`, and `agents`. + +```sh +├── __init__.py +├── agents +├── artifacts +├── chunkers +├── cli +├── loaders +├── memory +├── models +├── prompts +├── structs +├── telemetry +├── tokenizers +├── tools +├── utils +└── workers +``` + +## Docker Instructions + +This application uses Docker with CUDA support. To build and run the Docker container, follow these steps: + +### Prerequisites + +- Make sure you have [Docker installed](https://docs.docker.com/get-docker/) on your machine. +- Ensure your machine has an NVIDIA GPU and [NVIDIA Docker support](https://github.com/NVIDIA/nvidia-docker) installed. + +### Building the Docker Image + +To build the Docker image, navigate to the root directory containing the `Dockerfile` and run the following command: + +```bash +docker build --gpus all -t swarms +``` +### Running the Docker Container +To run the Docker container, use the following command: + +`docker run --gpus all -p 4000:80 swarms` + +Replace swarms with the name of your Docker image, and replace 4000:80 with your actual port mapping. The format is hostPort:containerPort. + +Now, your application should be running with CUDA support! + + ## Swarm Newsletter 🤖 🤖 🤖 📧 Sign up to the Swarm newsletter to receive updates on the latest Autonomous agent research papers, step by step guides on creating multi-agent app, and much more Swarmie goodiness 😊 diff --git a/docs/applications/discord.md b/docs/applications/discord.md index cae3c8c1..dd7de16c 100644 --- a/docs/applications/discord.md +++ b/docs/applications/discord.md @@ -64,6 +64,7 @@ Initialize the `llm` (Language Learning Model) with your OpenAI API key: ```python from swarms.models import OpenAIChat + llm = OpenAIChat( openai_api_key="Your_OpenAI_API_Key", temperature=0.5, @@ -74,6 +75,7 @@ Initialize the bot with the `llm`: ```python from apps.discord import Bot + bot = Bot(llm=llm) ``` diff --git a/docs/assets/img/reliabilitythrough.png b/docs/assets/img/reliabilitythrough.png new file mode 100644 index 00000000..91d55480 Binary files /dev/null and b/docs/assets/img/reliabilitythrough.png differ diff --git a/docs/corporate/data_room.md b/docs/corporate/data_room.md index 946f209f..0b7b1afb 100644 --- a/docs/corporate/data_room.md +++ b/docs/corporate/data_room.md @@ -52,7 +52,6 @@ ## **Introdution** Swarms provides automation-as-a-service through swarms of autonomous agents that work together as a team. We enable our customers to build, deploy, and scale production-grade multi-agent applications to automate real-world tasks. - ### **Vision** Our vision for 2024 is to provide the most reliable infrastructure for deploying autonomous agents into the real world through the Swarm Cloud, our premier cloud platform for the scalable deployment of Multi-Modal Autonomous Agents. The platform focuses on delivering maximum value to users by only taking a small fee when utilizing the agents for the hosted compute power needed to host the agents. @@ -69,15 +68,33 @@ The team has thousands of hours building and optimizing autonomous agents. Leade Key milestones: get 80K framework users in January 2024, start contracts in target verticals, introduce commercial products in 2025 with various pricing models. +### **Resources** +#### **Pre-Seed Pitch Deck** +- [Here is our pitch deck for our preseed round](https://drive.google.com/file/d/1c76gK5UIdrfN4JOSpSlvVBEOpzR9emWc/view?usp=sharing) -### **The Swarm Corporation Memo** +#### **The Swarm Corporation Memo** To learn more about our mission, vision, plans for GTM, and much more please refer to the [Swarm Memo here](https://docs.google.com/document/d/1hS_nv_lFjCqLfnJBoF6ULY9roTbSgSuCkvXvSUSc7Lo/edit?usp=sharing) + + +## **Financial Documents** +This section is dedicated entirely for corporate documents. + +- [Cap Table](https://docs.google.com/spreadsheets/d/1wuTWbfhYaY5Xp6nSQ9R0wDtSpwSS9coHxsjKd0UbIDc/edit?usp=sharing) + +- [Cashflow Prediction Sheet](https://docs.google.com/spreadsheets/d/1HQEHCIXXMHajXMl5sj8MEfcQtWfOnD7GjHtNiocpD60/edit?usp=sharing) + + +------ + ## **Product** Swarms is an open source framework for developers in python to enable seamless, reliable, and scalable multi-agent orchestration through modularity, customization, and precision. -[Here is the official Swarms Github Page:](https://github.com/kyegomez/swarms) +- [Swarms Github Page:](https://github.com/kyegomez/swarms) +- [Swarms Memo](https://docs.google.com/document/d/1hS_nv_lFjCqLfnJBoF6ULY9roTbSgSuCkvXvSUSc7Lo/edit) +- [Swarms Project Board](https://github.com/users/kyegomez/projects/1) +- [Swarms Website](https://www.swarms.world/g) ### Product Growth Metrics | Name | Description | Link | @@ -93,3 +110,4 @@ Swarms is an open source framework for developers in python to enable seamless, | Github Traffic Metrics | Metrics related to traffic, such as views and clones on Github. | [Github Traffic Metrics](https://github.com/kyegomez/swarms/graphs/traffic) | | Issues with the framework | Current open issues for the product on Github. | [![GitHub issues](https://img.shields.io/github/issues/kyegomez/swarms)](https://github.com/kyegomez/swarms/issues) | + diff --git a/docs/corporate/faq.md b/docs/corporate/faq.md index 99e78ac7..b2bad0d4 100644 --- a/docs/corporate/faq.md +++ b/docs/corporate/faq.md @@ -1,7 +1,110 @@ -This page summarizes questions we were asked on [Discord](https://discord.gg/gnWRz88eym), Hacker News, and Reddit. Feel free to post a question to [Discord](https://discord.gg/gnWRz88eym) or open a discussion on our [Github Page](https://github.com/kyegomez) or hit us up directly: [kye@apac.ai](mailto:hello@swarms.ai). +### FAQ on Swarm Intelligence and Multi-Agent Systems -## 1. How is Swarms different from LangChain? +#### What is an agent in the context of AI and swarm intelligence? -Swarms is an open source alternative to LangChain and differs in its approach to creating LLM pipelines and DAGs. In addition to agents, it uses more general-purpose DAGs and pipelines. A close proxy might be *Airflow for LLMs*. Swarms still implements chain of thought logic for prompt tasks that use "tools" but it also supports any type of input / output (images, audio, etc.). +In artificial intelligence (AI), an agent refers to an LLM with some objective to accomplish. +In swarm intelligence, each agent interacts with other agents and possibly the environment to achieve complex collective behaviors or solve problems more efficiently than individual agents could on their own. + +#### What do you need Swarms at all? +Individual agents are limited by a vast array of issues such as context window loss, single task execution, hallucination, and no collaboration. + + +#### How does a swarm work? + +A swarm works through the principles of decentralized control, local interactions, and simple rules followed by each agent. Unlike centralized systems, where a single entity dictates the behavior of all components, in a swarm, each agent makes its own decisions based on local information and interactions with nearby agents. These local interactions lead to the emergence of complex, organized behaviors or solutions at the collective level, enabling the swarm to tackle tasks efficiently. + +#### Why do you need more agents in a swarm? + +More agents in a swarm can enhance its problem-solving capabilities, resilience, and efficiency. With more agents: + +- **Diversity and Specialization**: The swarm can leverage a wider range of skills, knowledge, and perspectives, allowing for more creative and effective solutions to complex problems. +- **Scalability**: Adding more agents can increase the swarm's capacity to handle larger tasks or multiple tasks simultaneously. +- **Robustness**: A larger number of agents enhances the system's redundancy and fault tolerance, as the failure of a few agents has a minimal impact on the overall performance of the swarm. + +#### Isn't it more expensive to use more agents? + +While deploying more agents can initially increase costs, especially in terms of computational resources, hosting, and potentially API usage, there are several factors and strategies that can mitigate these expenses: + +- **Efficiency at Scale**: Larger swarms can often solve problems more quickly or effectively, reducing the overall computational time and resources required. +- **Optimization and Caching**: Implementing optimizations and caching strategies can reduce redundant computations, lowering the workload on individual agents and the overall system. +- **Dynamic Scaling**: Utilizing cloud services that offer dynamic scaling can ensure you only pay for the resources you need when you need them, optimizing cost-efficiency. + +#### Can swarms make decisions better than individual agents? + +Yes, swarms can make better decisions than individual agents for several reasons: + +- **Collective Intelligence**: Swarms combine the knowledge and insights of multiple agents, leading to more informed and well-rounded decision-making processes. +- **Error Correction**: The collaborative nature of swarms allows for error checking and correction among agents, reducing the likelihood of mistakes. +- **Adaptability**: Swarms are highly adaptable to changing environments or requirements, as the collective can quickly reorganize or shift strategies based on new information. + +#### How do agents in a swarm communicate? + +Communication in a swarm can vary based on the design and purpose of the system but generally involves either direct or indirect interactions: + +- **Direct Communication**: Agents exchange information directly through messaging, signals, or other communication protocols designed for the system. +- **Indirect Communication**: Agents influence each other through the environment, a method known as stigmergy. Actions by one agent alter the environment, which in turn influences the behavior of other agents. + +#### Are swarms only useful in computational tasks? + +While swarms are often associated with computational tasks, their applications extend far beyond. Swarms can be utilized in: + +- **Robotics**: Coordinating multiple robots for tasks like search and rescue, exploration, or surveillance. +- **Environmental Monitoring**: Using sensor networks to monitor pollution, wildlife, or climate conditions. +- **Social Sciences**: Modeling social behaviors or economic systems to understand complex societal dynamics. +- **Healthcare**: Coordinating care strategies in hospital settings or managing pandemic responses through distributed data analysis. + +#### How do you ensure the security of a swarm system? + +Security in swarm systems involves: + +- **Encryption**: Ensuring all communications between agents are encrypted to prevent unauthorized access or manipulation. +- **Authentication**: Implementing strict authentication mechanisms to verify the identity of each agent in the swarm. +- **Resilience to Attacks**: Designing the swarm to continue functioning effectively even if some agents are compromised or attacked, utilizing redundancy and fault tolerance strategies. + +#### How do individual agents within a swarm share insights without direct learning mechanisms like reinforcement learning? + +In the context of pre-trained Large Language Models (LLMs) that operate within a swarm, sharing insights typically involves explicit communication and data exchange protocols rather than direct learning mechanisms like reinforcement learning. Here's how it can work: + +- **Shared Databases and Knowledge Bases**: Agents can write to and read from a shared database or knowledge base where insights, generated content, and relevant data are stored. This allows agents to benefit from the collective experience of the swarm by accessing information that other agents have contributed. + +- **APIs for Information Exchange**: Custom APIs can facilitate the exchange of information between agents. Through these APIs, agents can request specific information or insights from others within the swarm, effectively sharing knowledge without direct learning. + +#### How do you balance the autonomy of individual LLMs with the need for coherent collective behavior in a swarm? + +Balancing autonomy with collective coherence in a swarm of LLMs involves: + +- **Central Coordination Mechanism**: Implementing a lightweight central coordination mechanism that can assign tasks, distribute information, and collect outputs from individual LLMs. This ensures that while each LLM operates autonomously, their actions are aligned with the swarm's overall objectives. + +- **Standardized Communication Protocols**: Developing standardized protocols for how LLMs communicate and share information ensures that even though each agent works autonomously, the information exchange remains coherent and aligned with the collective goals. + +#### How do LLM swarms adapt to changing environments or tasks without machine learning techniques? + +Adaptation in LLM swarms, without relying on machine learning techniques for dynamic learning, can be achieved through: + +- **Dynamic Task Allocation**: A central system or distributed algorithm can dynamically allocate tasks to different LLMs based on the changing environment or requirements. This ensures that the most suitable LLMs are addressing tasks for which they are best suited as conditions change. + +- **Pre-trained Versatility**: Utilizing a diverse set of pre-trained LLMs with different specialties or training data allows the swarm to select the most appropriate agent for a task as the requirements evolve. + +- **In Context Learning**: In context learning is another mechanism that can be employed within LLM swarms to adapt to changing environments or tasks. This approach involves leveraging the collective knowledge and experiences of the swarm to facilitate learning and improve performance. Here's how it can work: + + +#### Can LLM swarms operate in physical environments, or are they limited to digital spaces? + +LLM swarms primarily operate in digital spaces, given their nature as software entities. However, they can interact with physical environments indirectly through interfaces with sensors, actuaries, or other devices connected to the Internet of Things (IoT). For example, LLMs can process data from physical sensors and control devices based on their outputs, enabling applications like smart home management or autonomous vehicle navigation. + +#### Without direct learning from each other, how do agents in a swarm improve over time? + +Improvement over time in a swarm of pre-trained LLMs, without direct learning from each other, can be achieved through: + +- **Human Feedback**: Incorporating feedback from human operators or users can guide adjustments to the usage patterns or selection criteria of LLMs within the swarm, optimizing performance based on observed outcomes. + +- **Periodic Re-training and Updating**: The individual LLMs can be periodically re-trained or updated by their developers based on collective insights and feedback from their deployment within swarms. While this does not involve direct learning from each encounter, it allows the LLMs to improve over time based on aggregated experiences. + +These adjustments to the FAQ reflect the specific context of pre-trained LLMs operating within a swarm, focusing on communication, coordination, and adaptation mechanisms that align with their capabilities and constraints. + + +#### Conclusion + +Swarms represent a powerful paradigm in AI, offering innovative solutions to complex, dynamic problems through collective intelligence and decentralized control. While challenges exist, particularly regarding cost and security, strategic design and management can leverage the strengths of swarm intelligence to achieve remarkable efficiency, adaptability, and robustness in a wide range of applications. \ No newline at end of file diff --git a/docs/examples/bingchat.md b/docs/examples/bingchat.md index 5ff93c63..3dabbf2e 100644 --- a/docs/examples/bingchat.md +++ b/docs/examples/bingchat.md @@ -46,6 +46,7 @@ You can also specify the conversation style: ```python from bing_chat import ConversationStyle + response = chat("Tell me a joke", style=ConversationStyle.creative) print(response) ``` diff --git a/docs/examples/flow.md b/docs/examples/flow.md index 92842491..2e635111 100644 --- a/docs/examples/flow.md +++ b/docs/examples/flow.md @@ -107,16 +107,17 @@ Now, let's create your first Agent. A Agent represents a chain-like structure th # Import necessary modules ```python -from swarms.models import OpenAIChat # Zephr, Mistral +from swarms.models import OpenAIChat # Zephr, Mistral from swarms.structs import Agent -api_key = ""# Initialize the language model (LLM) -llm = OpenAIChat(openai_api_key=api_key, temperature=0.5, max_tokens=3000)# Initialize the Agent object +api_key = "" # Initialize the language model (LLM) +llm = OpenAIChat( + openai_api_key=api_key, temperature=0.5, max_tokens=3000 +) # Initialize the Agent object -agent = Agent(llm=llm, max_loops=5)# Run the agent +agent = Agent(llm=llm, max_loops=5) # Run the agent out = agent.run("Create an financial analysis on the following metrics") print(out) - ``` ### [3. Initializing the Agent Object](https://github.com/kyegomez/swarms) diff --git a/docs/examples/omni_agent.md b/docs/examples/omni_agent.md index 56a6c996..e4d65498 100644 --- a/docs/examples/omni_agent.md +++ b/docs/examples/omni_agent.md @@ -55,7 +55,7 @@ from swarms.models import OpenAIChat llm = OpenAIChat(openai_api_key="sk-") agent = OmniModalAgent(llm) -response = agent.run("Create an video of a swarm of fish concept art, game art") +response = agent.run("Create an video of a swarm of fish concept art, game art") print(response) ``` diff --git a/docs/examples/revgpt.md b/docs/examples/revgpt.md index 5aa17af4..69107b40 100644 --- a/docs/examples/revgpt.md +++ b/docs/examples/revgpt.md @@ -35,7 +35,6 @@ The abstraction provided in `revgpt.py` is designed to simplify your interaction 1. **Import the Necessary Modules:** ```python -import os from dotenv import load_dotenv from revgpt import AbstractChatGPT ``` diff --git a/docs/examples/stacked_worker.md b/docs/examples/stacked_worker.md index cdcc537c..914d1754 100644 --- a/docs/examples/stacked_worker.md +++ b/docs/examples/stacked_worker.md @@ -28,8 +28,8 @@ The provided code showcases a system built around a worker node that utilizes va The code begins with import statements, bringing in necessary modules and classes. Key imports include the `OpenAIChat` class, which represents a language model, and several custom agents and tools from the `swarms` package. ```python -import os import interpreter # Assuming this is a custom module + from swarms.agents.hf_agents import HFAgent from swarms.agents.omni_modal_agent import OmniModalAgent from swarms.models import OpenAIChat @@ -59,11 +59,7 @@ All defined tools are appended to a list called `tools`. This list is later used ```python # Append tools to a list -tools = [ - hf_agent, - omni_agent, - compile -] +tools = [hf_agent, omni_agent, compile] ``` ### Initializing a Worker Node @@ -263,8 +259,6 @@ response = node.run(task) # Print the response print(response) - - ``` diff --git a/docs/examples/worker.md b/docs/examples/worker.md index 8fe2bf75..cd082aa4 100644 --- a/docs/examples/worker.md +++ b/docs/examples/worker.md @@ -53,11 +53,11 @@ Voila! You’re now ready to summon your Worker. Here’s a simple way to invoke the Worker and give it a task: ```python -from swarms.models import OpenAIChat from swarms import Worker +from swarms.models import OpenAIChat llm = OpenAIChat( - #enter your api key + # enter your api key openai_api_key="", temperature=0.5, ) @@ -75,8 +75,6 @@ node = Worker( task = "What were the winning boston marathon times for the past 5 years (ending in 2022)? Generate a table of the year, name, country of origin, and times." response = node.run(task) print(response) - - ``` diff --git a/docs/limits_of_individual_agents.md b/docs/limits_of_individual_agents.md new file mode 100644 index 00000000..6a05daa8 --- /dev/null +++ b/docs/limits_of_individual_agents.md @@ -0,0 +1,55 @@ +# The Limits of Individual Agents + +![Reliable Agents](docs/assets/img/reliabilitythrough.png) + + +Individual agents have pushed the boundaries of what machines can learn and accomplish. However, despite their impressive capabilities, these agents face inherent limitations that can hinder their effectiveness in complex, real-world applications. This blog explores the critical constraints of individual agents, such as context window limits, hallucination, single-task threading, and lack of collaboration, and illustrates how multi-agent collaboration can address these limitations. In short, + +- Context Window Limits +- Single Task Execution +- Hallucination +- No collaboration + + + +#### Context Window Limits + +One of the most significant constraints of individual agents, particularly in the domain of language models, is the context window limit. This limitation refers to the maximum amount of information an agent can consider at any given time. For instance, many language models can only process a fixed number of tokens (words or characters) in a single inference, restricting their ability to understand and generate responses based on longer texts. This limitation can lead to a lack of coherence in longer compositions and an inability to maintain context in extended conversations or documents. + +#### Hallucination + +Hallucination in AI refers to the phenomenon where an agent generates information that is not grounded in the input data or real-world facts. This can manifest as making up facts, entities, or events that do not exist or are incorrect. Hallucinations pose a significant challenge in ensuring the reliability and trustworthiness of AI-generated content, particularly in critical applications such as news generation, academic research, and legal advice. + +#### Single Task Threading + +Individual agents are often designed to excel at specific tasks, leveraging their architecture and training data to optimize performance in a narrowly defined domain. However, this specialization can also be a drawback, as it limits the agent's ability to multitask or adapt to tasks that fall outside its primary domain. Single-task threading means an agent may excel in language translation but struggle with image recognition or vice versa, necessitating the deployment of multiple specialized agents for comprehensive AI solutions. + +#### Lack of Collaboration + +Traditional AI agents operate in isolation, processing inputs and generating outputs independently. This isolation limits their ability to leverage diverse perspectives, share knowledge, or build upon the insights of other agents. In complex problem-solving scenarios, where multiple facets of a problem need to be addressed simultaneously, this lack of collaboration can lead to suboptimal solutions or an inability to tackle multifaceted challenges effectively. + +# The Elegant yet Simple Solution + +- ## Multi-Agent Collaboration + +Recognizing the limitations of individual agents, researchers and practitioners have explored the potential of multi-agent collaboration as a means to transcend these constraints. Multi-agent systems comprise several agents that can interact, communicate, and collaborate to achieve common goals or solve complex problems. This collaborative approach offers several advantages: + +#### Overcoming Context Window Limits + +By dividing a large task among multiple agents, each focusing on different segments of the problem, multi-agent systems can effectively overcome the context window limits of individual agents. For instance, in processing a long document, different agents could be responsible for understanding and analyzing different sections, pooling their insights to generate a coherent understanding of the entire text. + +#### Mitigating Hallucination + +Through collaboration, agents can cross-verify facts and information, reducing the likelihood of hallucinations. If one agent generates a piece of information, other agents can provide checks and balances, verifying the accuracy against known data or through consensus mechanisms. + +#### Enhancing Multitasking Capabilities + +Multi-agent systems can tackle tasks that require a diverse set of skills by leveraging the specialization of individual agents. For example, in a complex project that involves both natural language processing and image analysis, one agent specialized in text can collaborate with another specialized in visual data, enabling a comprehensive approach to the task. + +#### Facilitating Collaboration and Knowledge Sharing + +Multi-agent collaboration inherently encourages the sharing of knowledge and insights, allowing agents to learn from each other and improve their collective performance. This can be particularly powerful in scenarios where iterative learning and adaptation are crucial, such as dynamic environments or tasks that evolve over time. + +### Conclusion + +While individual AI agents have made remarkable strides in various domains, their inherent limitations necessitate innovative approaches to unlock the full potential of artificial intelligence. Multi-agent collaboration emerges as a compelling solution, offering a pathway to transcend individual constraints through collective intelligence. By harnessing the power of collaborative AI, we can address more complex, multifaceted problems, paving the way for more versatile, efficient, and effective AI systems in the future. \ No newline at end of file diff --git a/docs/swarms/agents/abstractagent.md b/docs/swarms/agents/abstractagent.md index cdd06715..8833c164 100644 --- a/docs/swarms/agents/abstractagent.md +++ b/docs/swarms/agents/abstractagent.md @@ -37,7 +37,6 @@ class AbstractAgent: def memory(self, memory_store): """init memory""" - pass def reset(self): """(Abstract method) Reset the agent.""" @@ -82,7 +81,7 @@ agent.reset() The `run` method allows the agent to perform a specific task. ```python -agent.run('some_task') +agent.run("some_task") ``` #### 3. `chat` @@ -90,7 +89,7 @@ agent.run('some_task') The `chat` method enables communication with the agent through a series of messages. ```python -messages = [{'id': 1, 'text': 'Hello, agent!'}, {'id': 2, 'text': 'How are you?'}] +messages = [{"id": 1, "text": "Hello, agent!"}, {"id": 2, "text": "How are you?"}] agent.chat(messages) ``` @@ -99,7 +98,7 @@ agent.chat(messages) The `step` method allows the agent to process a single message. ```python -agent.step('Hello, agent!') +agent.step("Hello, agent!") ``` ### Asynchronous Methods diff --git a/docs/swarms/agents/message.md b/docs/swarms/agents/message.md index 87794ebc..413ac016 100644 --- a/docs/swarms/agents/message.md +++ b/docs/swarms/agents/message.md @@ -44,7 +44,7 @@ class Message: def __repr__(self): """ __repr__ represents the string representation of the Message object. - + Returns: (str) A string containing the timestamp, sender, and content of the message. """ @@ -60,10 +60,7 @@ The `Message` class represents a message in the agent system. Upon initializatio Creating a `Message` object and displaying its string representation. ```python -mes = Message( - sender = "Kye", - content = "Hello! How are you?" -) +mes = Message(sender="Kye", content="Hello! How are you?") print(mes) ``` @@ -80,9 +77,7 @@ Creating a `Message` object with metadata. ```python metadata = {"priority": "high", "category": "urgent"} mes_with_metadata = Message( - sender = "Alice", - content = "Important update", - metadata = metadata + sender="Alice", content="Important update", metadata=metadata ) print(mes_with_metadata) @@ -98,10 +93,7 @@ Output: Creating a `Message` object without providing metadata. ```python -mes_no_metadata = Message( - sender = "Bob", - content = "Reminder: Meeting at 2PM" -) +mes_no_metadata = Message(sender="Bob", content="Reminder: Meeting at 2PM") print(mes_no_metadata) ``` diff --git a/docs/swarms/agents/omni_agent.md b/docs/swarms/agents/omni_agent.md index a80da0e6..888e824f 100644 --- a/docs/swarms/agents/omni_agent.md +++ b/docs/swarms/agents/omni_agent.md @@ -39,10 +39,12 @@ For streaming mode, this function yields the response token by token, ensuring a ## Examples & Use Cases Initialize the `OmniModalAgent` and communicate with it: ```python +import os + +from dotenv import load_dotenv + from swarms.agents.omni_modal_agent import OmniModalAgent, OpenAIChat from swarms.models import OpenAIChat -from dotenv import load_dotenv -import os # Load the environment variables load_dotenv() diff --git a/docs/swarms/agents/toolagent.md b/docs/swarms/agents/toolagent.md index ebb00623..35a31f99 100644 --- a/docs/swarms/agents/toolagent.md +++ b/docs/swarms/agents/toolagent.md @@ -69,6 +69,7 @@ The `ToolAgent` class takes the following arguments: ```python from transformers import AutoModelForCausalLM, AutoTokenizer + from swarms import ToolAgent # Creating a model and tokenizer @@ -82,11 +83,8 @@ json_schema = { "name": {"type": "string"}, "age": {"type": "number"}, "is_student": {"type": "boolean"}, - "courses": { - "type": "array", - "items": {"type": "string"} - } - } + "courses": {"type": "array", "items": {"type": "string"}}, + }, } # Defining a task diff --git a/docs/swarms/agents/workeragent.md b/docs/swarms/agents/workeragent.md index e46ec1af..aaa71653 100644 --- a/docs/swarms/agents/workeragent.md +++ b/docs/swarms/agents/workeragent.md @@ -38,7 +38,7 @@ worker = Worker( human_in_the_loop=False, temperature=0.5, llm=some_language_model, - openai_api_key="my_key" + openai_api_key="my_key", ) worker.run("What's the weather in Miami?") ``` @@ -56,11 +56,11 @@ worker.send() ```python external_tools = [MyTool1(), MyTool2()] worker = Worker( -name="My Worker", -role="Worker", -external_tools=external_tools, -human_in_the_loop=False, -temperature=0.5, + name="My Worker", + role="Worker", + external_tools=external_tools, + human_in_the_loop=False, + temperature=0.5, ) ``` diff --git a/docs/swarms/chunkers/basechunker.md b/docs/swarms/chunkers/basechunker.md index 33b03312..11c32dc5 100644 --- a/docs/swarms/chunkers/basechunker.md +++ b/docs/swarms/chunkers/basechunker.md @@ -69,7 +69,9 @@ from basechunker import BaseChunker, ChunkSeparator chunker = BaseChunker() # Text to be chunked -input_text = "This is a long text that needs to be split into smaller chunks for processing." +input_text = ( + "This is a long text that needs to be split into smaller chunks for processing." +) # Chunk the text chunks = chunker.chunk(input_text) diff --git a/docs/swarms/chunkers/pdf_chunker.md b/docs/swarms/chunkers/pdf_chunker.md index 8c92060d..d3eb02a9 100644 --- a/docs/swarms/chunkers/pdf_chunker.md +++ b/docs/swarms/chunkers/pdf_chunker.md @@ -62,8 +62,8 @@ Let's explore how to use the `PdfChunker` class with different scenarios and app #### Example 1: Basic Chunking ```python -from swarms.chunkers.pdf_chunker import PdfChunker from swarms.chunkers.chunk_seperator import ChunkSeparator +from swarms.chunkers.pdf_chunker import PdfChunker # Initialize the PdfChunker pdf_chunker = PdfChunker() @@ -82,8 +82,8 @@ for idx, chunk in enumerate(chunks, start=1): #### Example 2: Custom Separators ```python -from swarms.chunkers.pdf_chunker import PdfChunker from swarms.chunkers.chunk_seperator import ChunkSeparator +from swarms.chunkers.pdf_chunker import PdfChunker # Define custom separators for PDF chunking custom_separators = [ChunkSeparator("\n\n"), ChunkSeparator(". ")] diff --git a/docs/swarms/index.md b/docs/swarms/index.md index 98c6b7a3..b052b6ce 100644 --- a/docs/swarms/index.md +++ b/docs/swarms/index.md @@ -28,7 +28,6 @@ We have a small gallery of examples to run here, [for more check out the docs to - Enterprise Grade + Production Grade: `Agent` is designed and optimized for automating real-world tasks at scale! ```python - from swarms.models import OpenAIChat from swarms.structs import Agent @@ -64,9 +63,6 @@ out = agent.run("Generate a 10,000 word blog on health and wellness.") # out = agent.print_history_and_memory() # # out = agent.save_state("flow_state.json") # print(out) - - - ``` ------ @@ -82,9 +78,7 @@ from swarms.structs import Agent from swarms.structs.sequential_workflow import SequentialWorkflow # Example usage -api_key = ( - "" # Your actual API key here -) +api_key = "" # Your actual API key here # Initialize the language agent llm = OpenAIChat( @@ -118,7 +112,6 @@ workflow.run() # Output the results for task in workflow.tasks: print(f"Task: {task.description}, Result: {task.result}") - ``` --- diff --git a/docs/swarms/memory/pg.md b/docs/swarms/memory/pg.md index 84878a76..3695e11c 100644 --- a/docs/swarms/memory/pg.md +++ b/docs/swarms/memory/pg.md @@ -110,7 +110,9 @@ def setup( ```python # Initialize the PgVectorVectorStore instance -vector_store = PgVectorVectorStore(connection_string="your-db-connection-string", table_name="your-table-name") +vector_store = PgVectorVectorStore( + connection_string="your-db-connection-string", table_name="your-table-name" +) # Set up the database with default settings vector_store.setup() @@ -120,10 +122,14 @@ vector_store.setup() ```python # Initialize the PgVectorVectorStore instance -vector_store = PgVectorVectorStore(connection_string="your-db-connection-string", table_name="your-table-name") +vector_store = PgVectorVectorStore( + connection_string="your-db-connection-string", table_name="your-table-name" +) # Set up the database with customized settings -vector_store.setup(create_schema=False, install_uuid_extension=True, install_vector_extension=True) +vector_store.setup( + create_schema=False, install_uuid_extension=True, install_vector_extension=True +) ``` ### 4.2 Upserting Vectors @@ -137,7 +143,7 @@ def upsert_vector( vector_id: Optional[str] = None, namespace: Optional[str] = None, meta: Optional[dict] = None, - **kwargs + **kwargs, ) -> str: """ Inserts or updates a vector in the collection. @@ -158,7 +164,9 @@ def upsert_vector( ```python # Initialize the PgVectorVectorStore instance -vector_store = PgVectorVectorStore(connection_string="your-db-connection-string", table_name="your-table-name") +vector_store = PgVectorVectorStore( + connection_string="your-db-connection-string", table_name="your-table-name" +) # Define a vector and upsert it vector = [0.1, 0.2, 0.3, 0.4] @@ -167,10 +175,7 @@ namespace = "your-namespace" meta = {"key1": "value1", "key2": "value2"} vector_store.upsert_vector( - vector=vector, - vector_id=vector_id, - namespace=namespace, - meta=meta + vector=vector, vector_id=vector_id, namespace=namespace, meta=meta ) ``` @@ -222,9 +227,7 @@ else: The `load_entries` method allows you to load all vector entries from the collection, optionally filtering by namespace. ```python -def load_entries( - self, namespace: Optional[str] = None -) -> list[BaseVectorStore.Entry]: +def load_entries(self, namespace: Optional[str] = None) -> list[BaseVectorStore.Entry]: """ Retrieves all vector entries from the collection, optionally filtering to only those that match the provided namespace. @@ -240,7 +243,9 @@ def load_entries( ```python # Initialize the PgVectorVectorStore instance -vector_store = PgVectorVectorStore(connection_string="your-db-connection-string", table_name="your-table-name") +vector_store = PgVectorVectorStore( + connection_string="your-db-connection-string", table_name="your-table-name" +) # Load all vector entries in the specified namespace entries = vector_store.load_entries(namespace="your-namespace") @@ -266,7 +271,7 @@ def query( namespace: Optional[str] = None, include_vectors: bool = False, distance_metric: str = "cosine_distance", - **kwargs + **kwargs, ) -> list[BaseVectorStore.QueryResult]: """ Performs a search on the collection to find vectors similar to the provided input vector, @@ -290,7 +295,9 @@ def query( ```python # Initialize the PgVectorVectorStore instance -vector_store = PgVectorVectorStore(connection_string="your-db-connection-string", table_name="your-table-name") +vector_store = PgVectorVectorStore( + connection_string="your-db-connection-string", table_name="your-table-name" +) # Perform a vector query query_string = "your-query-string" @@ -304,7 +311,7 @@ results = vector_store.query( count=count, namespace=namespace, include_vectors=include_vectors, - distance_metric=distance_metric + distance_metric=distance_metric, ) # Process the query results diff --git a/docs/swarms/memory/pinecone.md b/docs/swarms/memory/pinecone.md index 830d10fe..f8ca0f2e 100644 --- a/docs/swarms/memory/pinecone.md +++ b/docs/swarms/memory/pinecone.md @@ -174,7 +174,7 @@ pv = PineconeVector( api_key="your-api-key", index_name="your-index-name", environment="us-west1-gcp", - project_name="your-project-name" + project_name="your-project-name", ) ``` @@ -198,12 +198,7 @@ vector_id = "unique-vector-id" namespace = "your-namespace" meta = {"key1": "value1", "key2": "value2"} -pv.upsert_vector( - vector=vector, - vector_id=vector_id, - namespace=namespace, - meta=meta -) +pv.upsert_vector(vector=vector, vector_id=vector_id, namespace=namespace, meta=meta) ``` ### 4.4 Querying the Index @@ -222,7 +217,7 @@ results = pv.query( count=count, namespace=namespace, include_vectors=include_vectors, - include_metadata=include_metadata + include_metadata=include_metadata, ) # Process the query results diff --git a/docs/swarms/memory/qdrant.md b/docs/swarms/memory/qdrant.md index 3717d94f..cfc65670 100644 --- a/docs/swarms/memory/qdrant.md +++ b/docs/swarms/memory/qdrant.md @@ -14,7 +14,15 @@ pip install qdrant-client sentence-transformers httpx ```python class Qdrant: - def __init__(self, api_key: str, host: str, port: int = 6333, collection_name: str = "qdrant", model_name: str = "BAAI/bge-small-en-v1.5", https: bool = True): + def __init__( + self, + api_key: str, + host: str, + port: int = 6333, + collection_name: str = "qdrant", + model_name: str = "BAAI/bge-small-en-v1.5", + https: bool = True, + ): ... ``` @@ -60,10 +68,7 @@ qdrant_client = Qdrant(api_key="your_api_key", host="localhost", port=6333) ### Example 2: Adding Vectors to a Collection ```python -documents = [ - {"page_content": "Sample text 1"}, - {"page_content": "Sample text 2"} -] +documents = [{"page_content": "Sample text 1"}, {"page_content": "Sample text 2"}] operation_info = qdrant_client.add_vectors(documents) print(operation_info) diff --git a/docs/swarms/memory/short_term_memory.md b/docs/swarms/memory/short_term_memory.md index 2aabbd5c..9ee3a738 100644 --- a/docs/swarms/memory/short_term_memory.md +++ b/docs/swarms/memory/short_term_memory.md @@ -125,7 +125,9 @@ def update_short_term(self, index, role: str, message: str, *args, **kwargs): ##### Example: Updating a Message in Short-Term Memory ```python -memory.update_short_term(index=0, role="Updated Role", message="Updated message content.") +memory.update_short_term( + index=0, role="Updated Role", message="Updated message content." +) ``` #### 7. `clear` diff --git a/docs/swarms/memory/weaviate.md b/docs/swarms/memory/weaviate.md index b23baedf..dc264653 100644 --- a/docs/swarms/memory/weaviate.md +++ b/docs/swarms/memory/weaviate.md @@ -82,7 +82,7 @@ weaviate_client.create_collection( {"name": "property1", "dataType": ["string"]}, {"name": "property2", "dataType": ["int"]}, ], - vectorizer_config=None # Optional vectorizer configuration + vectorizer_config=None, # Optional vectorizer configuration ) ``` @@ -99,8 +99,7 @@ The `add` method allows you to add an object to a specified collection in Weavia ```python weaviate_client.add( - collection_name="my_collection", - properties={"property1": "value1", "property2": 42} + collection_name="my_collection", properties={"property1": "value1", "property2": 42} ) ``` @@ -142,7 +141,7 @@ The `update` method allows you to update an object in a specified collection in weaviate_client.update( collection_name="my_collection", object_id="object123", - properties={"property1": "new_value", "property2": 99} + properties={"property1": "new_value", "property2": 99}, ) ``` @@ -158,10 +157,7 @@ The `delete` method allows you to delete an object from a specified collection i #### Usage ```python -weaviate_client.delete( - collection_name="my_collection", - object_id="object123" -) +weaviate_client.delete(collection_name="my_collection", object_id="object123") ``` ## Examples @@ -175,28 +171,21 @@ weaviate_client.create_collection( name="people", properties=[ {"name": "name", "dataType": ["string"]}, - {"name": "age", "dataType": ["int"]} - ] + {"name": "age", "dataType": ["int"]}, + ], ) ``` ### Example 2: Adding an Object ```python -weaviate_client.add( - collection_name="people", - properties={"name": "John", "age": 30} -) +weaviate_client.add(collection_name="people", properties={"name": "John", "age": 30}) ``` ### Example 3: Querying Objects ```python -results = weaviate_client.query( - collection_name="people", - query="name:John", - limit=5 -) +results = weaviate_client.query(collection_name="people", query="name:John", limit=5) ``` These examples cover the basic operations of creating collections, adding objects, and querying objects using the Weaviate API Client. diff --git a/docs/swarms/models/anthropic.md b/docs/swarms/models/anthropic.md index 85e7a428..438adfbe 100644 --- a/docs/swarms/models/anthropic.md +++ b/docs/swarms/models/anthropic.md @@ -72,9 +72,7 @@ class Anthropic: from swarms.models import Anthropic # Initialize an instance of the Anthropic class -model = Anthropic( - anthropic_api_key="" -) +model = Anthropic(anthropic_api_key="") # Using the run method completion_1 = model.run("What is the capital of France?") diff --git a/docs/swarms/models/base_multimodal_model.md b/docs/swarms/models/base_multimodal_model.md index 13efa11c..c1a8373d 100644 --- a/docs/swarms/models/base_multimodal_model.md +++ b/docs/swarms/models/base_multimodal_model.md @@ -149,7 +149,9 @@ model = BaseMultiModalModel( ) # Run the model with a text task and an image URL -response = model.run("Generate a summary of this text", "https://www.example.com/image.jpg") +response = model.run( + "Generate a summary of this text", "https://www.example.com/image.jpg" +) print(response) ``` @@ -209,6 +211,7 @@ for response in responses: ```python from swarms.models import BaseMultiModalModel + class CustomMultiModalModel(BaseMultiModalModel): def __init__(self, model_name, custom_parameter, *args, **kwargs): # Call the parent class constructor @@ -226,6 +229,7 @@ class CustomMultiModalModel(BaseMultiModalModel): # You can use self.custom_parameter and other inherited attributes pass + # Create an instance of your custom multimodal model custom_model = CustomMultiModalModel( model_name="your_custom_model_name", @@ -236,7 +240,9 @@ custom_model = CustomMultiModalModel( ) # Run your custom model -response = custom_model.run("Generate a summary of this text", "https://www.example.com/image.jpg") +response = custom_model.run( + "Generate a summary of this text", "https://www.example.com/image.jpg" +) print(response) # Generate a summary using your custom model diff --git a/docs/swarms/models/bingchat.md b/docs/swarms/models/bingchat.md index 70c184d3..a98aa8be 100644 --- a/docs/swarms/models/bingchat.md +++ b/docs/swarms/models/bingchat.md @@ -39,7 +39,6 @@ print(response) ```python from swarms.models.bing_chat import BingChat - edgegpt = BingChat(cookies_path="./path/to/cookies.json") response = edgegpt("Hello, my name is ChatGPT") print(response) @@ -48,7 +47,9 @@ print(response) 3. Generate an image based on a text prompt: ```python -image_path = edgegpt.create_img("Sunset over mountains", output_dir="./output", auth_cookie="your_auth_cookie") +image_path = edgegpt.create_img( + "Sunset over mountains", output_dir="./output", auth_cookie="your_auth_cookie" +) print(f"Generated image saved at {image_path}") ``` @@ -59,7 +60,9 @@ from swarms.models.bing_chat import BingChat edgegpt = BingChat(cookies_path="./path/to/cookies.json") -image_path = edgegpt.create_img("Sunset over mountains", output_dir="./output", auth_cookie="your_auth_cookie") +image_path = edgegpt.create_img( + "Sunset over mountains", output_dir="./output", auth_cookie="your_auth_cookie" +) print(f"Generated image saved at {image_path}") ``` diff --git a/docs/swarms/models/biogpt.md b/docs/swarms/models/biogpt.md index c43557b6..bb4e8914 100644 --- a/docs/swarms/models/biogpt.md +++ b/docs/swarms/models/biogpt.md @@ -83,7 +83,6 @@ print(generated_text) ```python from swarms.models import BioGPT - # Initialize the BioGPT model biogpt = BioGPT() @@ -99,7 +98,6 @@ print(features) ```python from swarms.models import BioGPT - # Initialize the BioGPT model biogpt = BioGPT() diff --git a/docs/swarms/models/distilled_whisperx.md b/docs/swarms/models/distilled_whisperx.md index e9339c1e..79c8c2ea 100644 --- a/docs/swarms/models/distilled_whisperx.md +++ b/docs/swarms/models/distilled_whisperx.md @@ -29,7 +29,7 @@ from swarms.models import DistilWhisperModel model_wrapper = DistilWhisperModel() # Initialize with a specific model ID -model_wrapper = DistilWhisperModel(model_id='distil-whisper/distil-large-v2') +model_wrapper = DistilWhisperModel(model_id="distil-whisper/distil-large-v2") ``` ## Attributes @@ -62,7 +62,7 @@ Transcribes audio input synchronously. ```python # Synchronous transcription -transcription = model_wrapper.transcribe('path/to/audio.mp3') +transcription = model_wrapper.transcribe("path/to/audio.mp3") print(transcription) ``` @@ -84,7 +84,7 @@ Transcribes audio input asynchronously. import asyncio # Asynchronous transcription -transcription = asyncio.run(model_wrapper.async_transcribe('path/to/audio.mp3')) +transcription = asyncio.run(model_wrapper.async_transcribe("path/to/audio.mp3")) print(transcription) ``` @@ -103,7 +103,7 @@ Simulates real-time transcription of an audio file. ```python # Real-time transcription simulation -model_wrapper.real_time_transcribe('path/to/audio.mp3', chunk_duration=5) +model_wrapper.real_time_transcribe("path/to/audio.mp3", chunk_duration=5) ``` ## Error Handling diff --git a/docs/swarms/models/gpt4v.md b/docs/swarms/models/gpt4v.md index 69968623..5ad80cd9 100644 --- a/docs/swarms/models/gpt4v.md +++ b/docs/swarms/models/gpt4v.md @@ -107,16 +107,16 @@ The `__call__` method is a convenient way to run the GPT-4 Vision model. It has ```python def __call__(task: str, img: str) -> str: """ - Run the GPT-4 Vision model (callable). + Run the GPT-4 Vision model (callable). - Parameters: - - task (str): The task or question related to the image. - - img + Parameters: + - task (str): The task or question related to the image. + - img - (str): URL of the image to analyze. + (str): URL of the image to analyze. - Returns: - str: The model's response. + Returns: + str: The model's response. """ ``` diff --git a/docs/swarms/models/huggingface.md b/docs/swarms/models/huggingface.md index 8606d8f2..50aaa2a1 100644 --- a/docs/swarms/models/huggingface.md +++ b/docs/swarms/models/huggingface.md @@ -114,9 +114,11 @@ from swarms.models import HuggingfaceLLM custom_config = { "quantize": True, "quantization_config": {"load_in_4bit": True}, - "verbose": True + "verbose": True, } -inference = HuggingfaceLLM(model_id="NousResearch/Nous-Hermes-2-Vision-Alpha", **custom_config) +inference = HuggingfaceLLM( + model_id="NousResearch/Nous-Hermes-2-Vision-Alpha", **custom_config +) # Generate text based on a prompt prompt_text = "Tell me a joke" diff --git a/docs/swarms/models/idefics.md b/docs/swarms/models/idefics.md index 04822fdd..57125038 100644 --- a/docs/swarms/models/idefics.md +++ b/docs/swarms/models/idefics.md @@ -36,7 +36,9 @@ model = Idefics() 2. Generate text based on prompts: ```python -prompts = ["User: What is in this image? https://upload.wikimedia.org/wikipedia/commons/8/86/Id%C3%A9fix.JPG"] +prompts = [ + "User: What is in this image? https://upload.wikimedia.org/wikipedia/commons/8/86/Id%C3%A9fix.JPG" +] response = model(prompts) print(response) ``` @@ -47,7 +49,9 @@ print(response) from swarms.models import Idefics model = Idefics() -prompts = ["User: What is in this image? https://upload.wikimedia.org/wikipedia/commons/8/86/Id%C3%A9fix.JPG"] +prompts = [ + "User: What is in this image? https://upload.wikimedia.org/wikipedia/commons/8/86/Id%C3%A9fix.JPG" +] response = model(prompts) print(response) ``` diff --git a/docs/swarms/models/index.md b/docs/swarms/models/index.md index 93883779..9e001eea 100644 --- a/docs/swarms/models/index.md +++ b/docs/swarms/models/index.md @@ -42,9 +42,10 @@ OpenAI(api_key: str, system: str = None, console: bool = True, model: str = None **Usage Example:** ```python -from swarms import OpenAI import asyncio +from swarms import OpenAI + chat = OpenAI(api_key="YOUR_OPENAI_API_KEY") response = chat.generate("Hello, how can I assist you?") @@ -126,7 +127,10 @@ GooglePalm(model_name: str = "models/chat-bison-001", google_api_key: str = None from swarms import GooglePalm google_palm = GooglePalm() -messages = [{"role": "system", "content": "You are a helpful assistant"}, {"role": "user", "content": "Tell me a joke"}] +messages = [ + {"role": "system", "content": "You are a helpful assistant"}, + {"role": "user", "content": "Tell me a joke"}, +] response = google_palm.generate(messages) print(response["choices"][0]["text"]) diff --git a/docs/swarms/models/kosmos.md b/docs/swarms/models/kosmos.md index 1735e153..a19ea791 100644 --- a/docs/swarms/models/kosmos.md +++ b/docs/swarms/models/kosmos.md @@ -30,7 +30,9 @@ kosmos = Kosmos() 2. Perform Multimodal Grounding: ```python -kosmos.multimodal_grounding("Find the red apple in the image.", "https://example.com/apple.jpg") +kosmos.multimodal_grounding( + "Find the red apple in the image.", "https://example.com/apple.jpg" +) ``` ### Example 1 - Multimodal Grounding @@ -40,13 +42,17 @@ from swarms.models.kosmos_two import Kosmos kosmos = Kosmos() -kosmos.multimodal_grounding("Find the red apple in the image.", "https://example.com/apple.jpg") +kosmos.multimodal_grounding( + "Find the red apple in the image.", "https://example.com/apple.jpg" +) ``` 3. Perform Referring Expression Comprehension: ```python -kosmos.referring_expression_comprehension("Show me the green bottle.", "https://example.com/bottle.jpg") +kosmos.referring_expression_comprehension( + "Show me the green bottle.", "https://example.com/bottle.jpg" +) ``` ### Example 2 - Referring Expression Comprehension @@ -56,13 +62,17 @@ from swarms.models.kosmos_two import Kosmos kosmos = Kosmos() -kosmos.referring_expression_comprehension("Show me the green bottle.", "https://example.com/bottle.jpg") +kosmos.referring_expression_comprehension( + "Show me the green bottle.", "https://example.com/bottle.jpg" +) ``` 4. Generate Referring Expressions: ```python -kosmos.referring_expression_generation("It is on the table.", "https://example.com/table.jpg") +kosmos.referring_expression_generation( + "It is on the table.", "https://example.com/table.jpg" +) ``` ### Example 3 - Referring Expression Generation @@ -72,7 +82,9 @@ from swarms.models.kosmos_two import Kosmos kosmos = Kosmos() -kosmos.referring_expression_generation("It is on the table.", "https://example.com/table.jpg") +kosmos.referring_expression_generation( + "It is on the table.", "https://example.com/table.jpg" +) ``` 5. Perform Grounded Visual Question Answering (VQA): @@ -127,7 +139,10 @@ kosmos.grounded_image_captioning_detailed("https://example.com/beach.jpg") ```python image = kosmos.get_image("https://example.com/image.jpg") -entities = [("apple", (0, 3), [(0.2, 0.3, 0.4, 0.5)]), ("banana", (4, 9), [(0.6, 0.2, 0.8, 0.4)])] +entities = [ + ("apple", (0, 3), [(0.2, 0.3, 0.4, 0.5)]), + ("banana", (4, 9), [(0.6, 0.2, 0.8, 0.4)]), +] kosmos.draw_entity_boxes_on_image(image, entities, show=True) ``` @@ -139,24 +154,38 @@ from swarms.models.kosmos_two import Kosmos kosmos = Kosmos() image = kosmos.get_image("https://example.com/image.jpg") -entities = [("apple", (0, 3), [(0.2, 0.3, 0.4, 0.5)]), ("banana", (4, 9), [(0.6, 0.2, 0.8, 0.4)])] +entities = [ + ("apple", (0, 3), [(0.2, 0.3, 0.4, 0.5)]), + ("banana", (4, 9), [(0.6, 0.2, 0.8, 0.4)]), +] kosmos.draw_entity_boxes_on_image(image, entities, show=True) ``` 9. Generate Boxes for Entities: ```python -entities = [("apple", (0, 3), [(0.2, 0.3, 0.4, 0.5)]), ("banana", (4, 9), [(0.6, 0.2, 0.8, 0.4)])] -image = kosmos.generate_boxes("Find the apple and the banana in the image.", "https://example.com/image.jpg") +entities = [ + ("apple", (0, 3), [(0.2, 0.3, 0.4, 0.5)]), + ("banana", (4, 9), [(0.6, 0.2, 0.8, 0.4)]), +] +image = kosmos.generate_boxes( + "Find the apple and the banana in the image.", "https://example.com/image.jpg" +) ``` ### Example 8 - Generating Boxes for Entities ```python from swarms.models.kosmos_two import Kosmos + kosmos = Kosmos() -entities = [("apple", (0, 3), [(0.2, 0.3, 0.4, 0.5)]), ("banana", (4, 9), [(0.6, 0.2, 0.8, 0.4)])] -image = kosmos.generate_boxes("Find the apple and the banana in the image.", "https://example.com/image.jpg") +entities = [ + ("apple", (0, 3), [(0.2, 0.3, 0.4, 0.5)]), + ("banana", (4, 9), [(0.6, 0.2, 0.8, 0.4)]), +] +image = kosmos.generate_boxes( + "Find the apple and the banana in the image.", "https://example.com/image.jpg" +) ``` ## How Kosmos Works diff --git a/docs/swarms/models/mistral.md b/docs/swarms/models/mistral.md index c8dc179c..6c38cd97 100644 --- a/docs/swarms/models/mistral.md +++ b/docs/swarms/models/mistral.md @@ -150,7 +150,6 @@ Example: ```python from swarms.models import Mistral - model = Mistral() task = "Translate the following English text to French: 'Hello, how are you?'" result = model.run(task) diff --git a/docs/swarms/models/mpt.md b/docs/swarms/models/mpt.md index 41f3ec74..0592284b 100644 --- a/docs/swarms/models/mpt.md +++ b/docs/swarms/models/mpt.md @@ -52,10 +52,10 @@ class MPT7B: from swarms.models import MPT7B # Initialize the MPT7B class -mpt = MPT7B('mosaicml/mpt-7b-storywriter', 'EleutherAI/gpt-neox-20b', max_tokens=150) +mpt = MPT7B("mosaicml/mpt-7b-storywriter", "EleutherAI/gpt-neox-20b", max_tokens=150) # Generate text -output = mpt.run('generate', 'Once upon a time in a land far, far away...') +output = mpt.run("generate", "Once upon a time in a land far, far away...") print(output) ``` @@ -77,13 +77,16 @@ print(outputs) ```python import asyncio + from swarms.models import MPT7B # Initialize the MPT7B class -mpt = MPT7B('mosaicml/mpt-7b-storywriter', 'EleutherAI/gpt-neox-20b', max_tokens=150) +mpt = MPT7B("mosaicml/mpt-7b-storywriter", "EleutherAI/gpt-neox-20b", max_tokens=150) # Generate text asynchronously -output = asyncio.run(mpt.run_async('generate', 'Once upon a time in a land far, far away...')) +output = asyncio.run( + mpt.run_async("generate", "Once upon a time in a land far, far away...") +) print(output) ``` diff --git a/docs/swarms/models/openai.md b/docs/swarms/models/openai.md index f173619d..ae547631 100644 --- a/docs/swarms/models/openai.md +++ b/docs/swarms/models/openai.md @@ -168,7 +168,11 @@ prompt = "Translate the following English text to French: 'Hello, how are you?'" generated_text = openai.generate(prompt, max_tokens=50) # Generate text from multiple prompts -prompts = ["Translate this: 'Good morning' to Spanish.", "Summarize the following article:", article_text] +prompts = [ + "Translate this: 'Good morning' to Spanish.", + "Summarize the following article:", + article_text, +] generated_texts = openai.generate(prompts, max_tokens=100) # Generate text asynchronously @@ -188,7 +192,7 @@ custom_options = { "max_tokens": 100, "top_p": 0.9, "frequency_penalty": 0.2, - "presence_penalty": 0.4 + "presence_penalty": 0.4, } generated_text = openai.generate(prompt, **custom_options) ``` diff --git a/docs/swarms/models/openai_chat.md b/docs/swarms/models/openai_chat.md index a2ef9811..d7d9b2eb 100644 --- a/docs/swarms/models/openai_chat.md +++ b/docs/swarms/models/openai_chat.md @@ -150,7 +150,9 @@ user_message = "User: Tell me another joke." response = openai_chat.generate([user_message]) # Print the generated response -print(response[0][0].text) # Output: "Assistant: Why don't scientists trust atoms? Because they make up everything!" +print( + response[0][0].text +) # Output: "Assistant: Why don't scientists trust atoms? Because they make up everything!" ``` ### Example 3: Asynchronous Generation @@ -158,12 +160,14 @@ print(response[0][0].text) # Output: "Assistant: Why don't scientists trust ato ```python import asyncio + # Define an asynchronous function for generating responses async def generate_responses(): user_message = "User: Tell me a fun fact." async for chunk in openai_chat.stream([user_message]): print(chunk.text) + # Run the asynchronous generation function asyncio.run(generate_responses()) ``` diff --git a/docs/swarms/models/vilt.md b/docs/swarms/models/vilt.md index e2c6f325..2cb56b22 100644 --- a/docs/swarms/models/vilt.md +++ b/docs/swarms/models/vilt.md @@ -26,20 +26,26 @@ To use the Vilt model, follow these steps: ```python from swarms.models import Vilt + model = Vilt() ``` 2. Call the model with a text question and an image URL: ```python -output = model("What is this image?", "http://images.cocodataset.org/val2017/000000039769.jpg") +output = model( + "What is this image?", "http://images.cocodataset.org/val2017/000000039769.jpg" +) ``` ### Example 1 - Image Questioning ```python model = Vilt() -output = model("What are the objects in this image?", "http://images.cocodataset.org/val2017/000000039769.jpg") +output = model( + "What are the objects in this image?", + "http://images.cocodataset.org/val2017/000000039769.jpg", +) print(output) ``` @@ -47,7 +53,10 @@ print(output) ```python model = Vilt() -output = model("Describe the scene in this image.", "http://images.cocodataset.org/val2017/000000039769.jpg") +output = model( + "Describe the scene in this image.", + "http://images.cocodataset.org/val2017/000000039769.jpg", +) print(output) ``` @@ -55,7 +64,10 @@ print(output) ```python model = Vilt() -output = model("Tell me more about the landmark in this image.", "http://images.cocodataset.org/val2017/000000039769.jpg") +output = model( + "Tell me more about the landmark in this image.", + "http://images.cocodataset.org/val2017/000000039769.jpg", +) print(output) ``` diff --git a/docs/swarms/models/vllm.md b/docs/swarms/models/vllm.md index 06a7c8f8..778c1b2b 100644 --- a/docs/swarms/models/vllm.md +++ b/docs/swarms/models/vllm.md @@ -63,7 +63,7 @@ custom_vllm = vLLM( trust_remote_code=True, revision="abc123", temperature=0.7, - top_p=0.8 + top_p=0.8, ) ``` @@ -108,7 +108,7 @@ custom_vllm = vLLM( trust_remote_code=True, revision="abc123", temperature=0.7, - top_p=0.8 + top_p=0.8, ) # Generate text with custom configuration @@ -128,7 +128,7 @@ vllm = vLLM() tasks = [ "Translate the following sentence to French: 'Hello, world!'", "Write a short story set in a futuristic world.", - "Summarize the main points of a news article about climate change." + "Summarize the main points of a news article about climate change.", ] for task in tasks: diff --git a/docs/swarms/models/zephyr.md b/docs/swarms/models/zephyr.md index d9522711..76782ead 100644 --- a/docs/swarms/models/zephyr.md +++ b/docs/swarms/models/zephyr.md @@ -45,6 +45,7 @@ To use the Zephyr model, follow these steps: ```python from swarms.models import Zephyr + model = Zephyr(max_new_tokens=300, temperature=0.7, top_k=50, top_p=0.95) ``` diff --git a/docs/swarms/swarms/abstractswarm.md b/docs/swarms/structs/abstractswarm.md similarity index 99% rename from docs/swarms/swarms/abstractswarm.md rename to docs/swarms/structs/abstractswarm.md index 78e28493..6bdf736b 100644 --- a/docs/swarms/swarms/abstractswarm.md +++ b/docs/swarms/structs/abstractswarm.md @@ -47,9 +47,11 @@ The `AbstractSwarm` class is an abstract base class that serves as the foundatio ```python from abc import ABC, abstractmethod -from typing import Optional, List, Dict, Any +from typing import List + from swarms.swarms.base import AbstractWorker + class AbstractSwarm(ABC): """ Abstract class for swarm simulation architectures @@ -58,12 +60,12 @@ class AbstractSwarm(ABC): --------- ... """ + # The class definition and constructor are provided here. @abstractmethod def __init__(self, workers: List["AbstractWorker"]): """Initialize the swarm with workers""" - pass # Other abstract methods are listed here. ``` diff --git a/docs/swarms/structs/agent.md b/docs/swarms/structs/agent.md index f04bba02..8408b0b8 100644 --- a/docs/swarms/structs/agent.md +++ b/docs/swarms/structs/agent.md @@ -68,7 +68,9 @@ final_response = agent.run(initial_task) You can collect feedback during the conversation using the `provide_feedback` method: ```python -agent.provide_feedback("Generate an SOP for new sales employees on the best cold sales practices") +agent.provide_feedback( + "Generate an SOP for new sales employees on the best cold sales practices" +) ``` ### Stopping Condition @@ -78,9 +80,11 @@ You can define a custom stopping condition using a function. For example, you ca ```python from swarms.structs import Agent + def stop_when_repeats(response: str) -> bool: return "Stop" in response.lower() + agent = Agent(llm=my_language_model, max_loops=5, stopping_condition=stop_when_repeats) ``` @@ -107,9 +111,9 @@ Here are three usage examples: ### Example 1: Simple Conversation ```python -from swarms.structs import Agent # Select any Language model from the models folder from swarms.models import Mistral, OpenAIChat +from swarms.structs import Agent llm = Mistral() # llm = OpenAIChat() @@ -128,9 +132,11 @@ final_response = agent.run(initial_task) ```python from swarms.structs import Agent + def stop_when_repeats(response: str) -> bool: return "Stop" in response.lower() + agent = Agent(llm=llm, max_loops=5, stopping_condition=stop_when_repeats) ``` diff --git a/docs/swarms/structs/artifact.md b/docs/swarms/structs/artifact.md index 52444d9f..9e00f083 100644 --- a/docs/swarms/structs/artifact.md +++ b/docs/swarms/structs/artifact.md @@ -41,9 +41,7 @@ class Artifact(BaseModel): ) relative_path: Optional[str] = Field( None, - description=( - "Relative path of the artifact in the agent's workspace" - ), + description=("Relative path of the artifact in the agent's workspace"), example="python/code/", ) ``` @@ -64,7 +62,7 @@ from swarms.structs import Artifact artifact_instance = Artifact( artifact_id="b225e278-8b4c-4f99-a696-8facf19f0e56", file_name="main.py", - relative_path="python/code/" + relative_path="python/code/", ) ``` @@ -85,8 +83,7 @@ If the `relative_path` attribute is not provided during artifact creation, it wi ```python artifact_instance_no_path = Artifact( - artifact_id="c280s347-9b7d-3c68-m337-7abvf50j23k", - file_name="script.js" + artifact_id="c280s347-9b7d-3c68-m337-7abvf50j23k", file_name="script.js" ) print(artifact_instance_no_path.relative_path) diff --git a/docs/swarms/structs/artifactupload.md b/docs/swarms/structs/artifactupload.md index 533f7d53..90b30f58 100644 --- a/docs/swarms/structs/artifactupload.md +++ b/docs/swarms/structs/artifactupload.md @@ -15,9 +15,7 @@ class ArtifactUpload(BaseModel): file: bytes = Field(..., description="File to upload") relative_path: Optional[str] = Field( None, - description=( - "Relative path of the artifact in the agent's workspace" - ), + description=("Relative path of the artifact in the agent's workspace"), example="python/code/", ) ``` @@ -32,10 +30,12 @@ The `ArtifactUpload` class is used to create an instance of an artifact upload. from swarms.structs import ArtifactUpload # Uploading a file with no relative path -upload_no_path = ArtifactUpload(file=b'example_file_contents') +upload_no_path = ArtifactUpload(file=b"example_file_contents") # Uploading a file with a relative path -upload_with_path = ArtifactUpload(file=b'example_file_contents', relative_path="python/code/") +upload_with_path = ArtifactUpload( + file=b"example_file_contents", relative_path="python/code/" +) ``` In the above example, `upload_no_path` is an instance of `ArtifactUpload` with no specified `relative_path`, whereas `upload_with_path` is an instance of `ArtifactUpload` with the `relative_path` set to "python/code/". diff --git a/docs/swarms/swarms/autoscaler.md b/docs/swarms/structs/autoscaler.md similarity index 94% rename from docs/swarms/swarms/autoscaler.md rename to docs/swarms/structs/autoscaler.md index 703ae860..6d07d3b1 100644 --- a/docs/swarms/swarms/autoscaler.md +++ b/docs/swarms/structs/autoscaler.md @@ -36,7 +36,9 @@ Initializes the `AutoScaler` with a predefined number of agents and sets up conf ```python from swarms import AutoScaler -scaler = AutoScaler(initial_agents=5, scale_up_factor=3, idle_threshold=0.1, busy_threshold=0.8) +scaler = AutoScaler( + initial_agents=5, scale_up_factor=3, idle_threshold=0.1, busy_threshold=0.8 +) ``` --- @@ -140,7 +142,9 @@ scaler.start() from swarms import AutoScaler # Initialize the scaler -auto_scaler = AutoScaler(initial_agents=15, scale_up_factor=2, idle_threshold=0.2, busy_threshold=0.7) +auto_scaler = AutoScaler( + initial_agents=15, scale_up_factor=2, idle_threshold=0.2, busy_threshold=0.7 +) # Start the monitoring and task processing auto_scaler.start() @@ -161,7 +165,6 @@ auto_scaler.start() for i in range(100): # Adding tasks auto_scaler.add_task(f"Task {i}") - ``` diff --git a/docs/swarms/structs/baseworkflow.md b/docs/swarms/structs/baseworkflow.md index ee048af8..2cb4b5eb 100644 --- a/docs/swarms/structs/baseworkflow.md +++ b/docs/swarms/structs/baseworkflow.md @@ -13,19 +13,19 @@ Base class for workflows. Source Code: ```python - class BaseWorkflow(BaseStructure): - """ - Base class for workflows. +class BaseWorkflow(BaseStructure): +""" +Base class for workflows. - Attributes: - task_pool (list): A list to store tasks. + Attributes: + task_pool (list): A list to store tasks. - Methods: - add(task: Task = None, tasks: List[Task] = None, *args, **kwargs): - Adds a task or a list of tasks to the task pool. - run(): - Abstract method to run the workflow. - """ + Methods: + add(task: Task = None, tasks: List[Task] = None, *args, **kwargs): + Adds a task or a list of tasks to the task pool. + run(): + Abstract method to run the workflow. +""" ``` For the usage examples and additional in-depth documentation please visit [BaseWorkflow](https://github.com/swarms-modules/structs/blob/main/baseworkflow.md#swarms-structs) diff --git a/docs/swarms/structs/groupchatmanager.md b/docs/swarms/structs/groupchatmanager.md index 623a1fbf..cb2ce035 100644 --- a/docs/swarms/structs/groupchatmanager.md +++ b/docs/swarms/structs/groupchatmanager.md @@ -24,7 +24,7 @@ agents = Agent() manager = GroupChatManager(groupchat, selector) # Call the group chat manager passing a specific chat task -result = manager('Discuss the agenda for the upcoming meeting') +result = manager("Discuss the agenda for the upcoming meeting") ``` Explanation: @@ -67,9 +67,7 @@ class GroupChatManager: Returns: str: The response from the group chat. """ - self.groupchat.messages.append( - {"role": self.selector.name, "content": task} - ) + self.groupchat.messages.append({"role": self.selector.name, "content": task}) for i in range(self.groupchat.max_round): speaker = self.groupchat.select_speaker( last_speaker=self.selector, selector=self.selector diff --git a/docs/swarms/structs/json.md b/docs/swarms/structs/json.md new file mode 100644 index 00000000..a495a0ce --- /dev/null +++ b/docs/swarms/structs/json.md @@ -0,0 +1,134 @@ +# **Documentation for `swarms.structs.JSON` Class** + +The `swarms.structs.JSON` class is a helper class that provides a templated framework for creating new classes that deal with JSON objects and need to validate these objects against a JSON Schema. Being an abstract base class (ABC), the `JSON` class allows for the creation of subclasses that implement specific behavior while ensuring that they all adhere to a common interface, particularly the `validate` method. + +Given that documenting the entire code provided in full detail would exceed our platform's limitations, below is a generated documentation for the `JSON` class following the steps you provided. This is an outline and would need to be expanded upon to reach the desired word count and thoroughness in a full, professional documentation. + +--- + +## Introduction + +JSON (JavaScript Object Notation) is a lightweight data interchange format that is easy for humans to read and write and easy for machines to parse and generate. `swarms.structs.JSON` class aims to provide a basic structure for utilizing JSON and validating it against a pre-defined schema. This is essential for applications where data integrity and structure are crucial, such as configurations for applications, communications over networks, and data storage. + +## Class Definition + +| Parameter | Type | Description | +|---------------|------------|------------------------------------| +| `schema_path` | `str` | The path to the JSON schema file. | + +### `JSON.__init__(self, schema_path)` +Class constructor that initializes a `JSON` object with the specified JSON schema path. +```python +def __init__(self, schema_path): + self.schema_path = schema_path + self.schema = self.load_schema() +``` + +### `JSON.load_schema(self)` +Private method that loads and returns the JSON schema from the file specified at the `schema_path`. + +### `JSON.validate(self, data)` +Abstract method that needs to be implemented by subclasses to validate input `data` against the JSON schema. + +--- + +## Functionality and Usage + +### Why use `JSON` Class + +The `JSON` class abstracts away the details of loading and validating JSON data, allowing for easy implementation in any subclass that needs to handle JSON input. It sets up a standard for all subclasses to follow, ensuring consistency across different parts of code or different projects. + +By enforcing a JSON schema, the `JSON` class helps maintain the integrity of the data, catching errors early in the process of reading and writing JSON. + +### Step-by-step Guide + +1. Subclass the `JSON` class. +2. Provide an implementation for the `validate` method. +3. Use the provided schema to enforce required fields and types within your JSON data. + +--- + +## Example Usage + +### Implementing a Subclass + +Suppose we have a JSON Schema in `config_schema.json` for application configuration. + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "debug": { + "type": "boolean" + }, + "window_size": { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 2, + "maxItems": 2 + } + }, + "required": ["debug", "window_size"] +} +``` + +Now we'll create a subclass `AppConfig` that uses this schema. + +```python +from swarms.structs import JSON + + +class AppConfig(JSON): + def __init__(self, schema_path): + super().__init__(schema_path) + + def validate(self, config_data): + # Here we'll use a JSON Schema validation library like jsonschema + from jsonschema import ValidationError, validate + + try: + validate(instance=config_data, schema=self.schema) + except ValidationError as e: + print(f"Invalid configuration: {e}") + return False + return True + + +# Main Example Usage + +if __name__ == "__main__": + config = {"debug": True, "window_size": [800, 600]} + + app_config = AppConfig("config_schema.json") + + if app_config.validate(config): + print("Config is valid!") + else: + print("Config is invalid.") +``` + +In this example, an `AppConfig` class that inherits from `JSON` is created. The `validate` method is implemented to check whether a configuration dictionary is valid against the provided schema. + +### Note + +- Validate real JSON data using this class in a production environment. +- Catch and handle any exceptions as necessary to avoid application crashes. +- Extend functionality within subclasses as required for your application. + +--- + +## Additional Information and Tips + +- Use detailed JSON Schemas for complex data validation. +- Use the jsonschema library for advanced validation features. + +## References and Resources + +- Official Python Documentation for ABCs: https://docs.python.org/3/library/abc.html +- JSON Schema: https://json-schema.org/ +- jsonschema Python package: https://pypi.org/project/jsonschema/ + +This generated documentation serves as a template and starting point intended for creating in-depth, practical documentation. Expanding upon each section, in practice, would involve deeper code examples, common patterns and pitfalls, and more thorough explanations of the `JSON` class internals and how to best utilize them in various real-world scenarios. diff --git a/docs/swarms/structs/majorityvoting.md b/docs/swarms/structs/majorityvoting.md new file mode 100644 index 00000000..4c7f7612 --- /dev/null +++ b/docs/swarms/structs/majorityvoting.md @@ -0,0 +1,111 @@ +# `MajorityVoting` Documentation + +## Overview + +The `swarms.structs` library provides a flexible architecture for creating and managing swarms of agents capable of performing tasks and making decisions based on majority voting. This documentation will guide you through the `MajorityVoting` class, explaining its purpose, architecture, and usage with examples. + +## Table of Contents + +- [Introduction](#introduction) +- [Installation](#installation) +- [The `MajorityVoting` Class](#the-majorityvoting-class) + - [Class Definition](#class-definition) + - [Parameters](#parameters) + - [Methods](#methods) + - [`__init__`](#__init__) + - [`run`](#run) +- [Usage Examples](#usage-examples) + - [Basic Usage](#basic-usage) + - [Concurrent Execution](#concurrent-execution) + - [Asynchronous Execution](#asynchronous-execution) +- [Advanced Features](#advanced-features) +- [Troubleshooting and FAQ](#troubleshooting-and-faq) +- [Conclusion](#conclusion) +- [References](#references) + +## Introduction + +The `swarms.structs` library introduces a mode of distributed computation through "agents" that collaborate to determine the outcome of tasks using a majority voting system. It becomes crucial in scenarios where collective decision-making is preferred over individual agent accuracy. + +## Installation + +To install the `swarms.structs` library, run the following command: + +```bash +pip install swarms-structs +``` + +## The `MajorityVoting` Class + +The `MajorityVoting` class is a high-level abstraction used to coordinate a group of agents that perform tasks and return results. These results are then aggregated to form a majority vote, determining the final output. + +### Class Definition + +### Parameters + +| Parameter | Type | Default | Description | +|-----------------|------------|----------|----------------------------------------------------------------------| +| agents | List[Agent]| Required | A list of agent instances to participate in the voting process. | +| concurrent | bool | False | Enables concurrent execution using threading if set to `True`. | +| multithreaded | bool | False | Enables execution using multiple threads if set to `True`. | +| multiprocess | bool | False | Enables execution using multiple processes if set to `True`. | +| asynchronous | bool | False | Enables asynchronous execution if set to `True`. | +| output_parser | callable | None | A function to parse the output from the majority voting function. | +| autosave | bool | False | Enables automatic saving of the process state if set to `True`. (currently not used in source code) | +| verbose | bool | False | Enables verbose logging if set to `True`. | + +### Methods + +#### `__init__` + +The constructor for the `MajorityVoting` class. Initializes a new majority voting system with the given configuration. + +*This method doesn't return any value.* + +#### `run` + +Executes the given task by all participating agents and aggregates the results through majority voting. + +| Parameter | Type | Description | +|-----------|-----------|----------------------------------| +| task | str | The task to be performed. | +| *args | list | Additional positional arguments. | +| **kwargs | dict | Additional keyword arguments. | + +*Returns:* List[Any] - The result based on the majority vote. + +## Usage Examples + +### Basic Usage + +```python +from swarms.structs.agent import Agent +from swarms.structs.majority_voting import MajorityVoting + + +def create_agent(name): + return Agent(name) + + +agents = [create_agent(name) for name in ["GPT-3", "Codex", "Tabnine"]] +majority_voting = MajorityVoting(agents) +result = majority_voting.run("What is the capital of France?") +print(result) # Output: Paris +``` + +### Concurrent Execution + +```python +majority_voting = MajorityVoting(agents, concurrent=True) +result = majority_voting.run("What is the largest continent?") +print(result) # Example Output: Asia +``` + +### Asynchronous Execution + +```python +majority_voting = MajorityVoting(agents, asynchronous=True) +result = majority_voting.run("What is the square root of 16?") +print(result) # Output: 4 +``` + diff --git a/docs/swarms/structs/nonlinearworkflow.md b/docs/swarms/structs/nonlinearworkflow.md index 1974de24..09d00074 100644 --- a/docs/swarms/structs/nonlinearworkflow.md +++ b/docs/swarms/structs/nonlinearworkflow.md @@ -60,7 +60,7 @@ task3 = Task(llm, "Find a hotel in Paris") # Initialize the NonlinearWorkflow workflow = NonlinearWorkflow() # Add tasks to the workflow with dependencies -workflow.add(task1, task2.name) +workflow.add(task1, task2.name) workflow.add(task2, task3.name) workflow.add(task3, "OpenAIChat Initialization") # Execute the workflow @@ -82,7 +82,7 @@ task3 = Task(llm, "Find a hotel in Paris") # Initialize the NonlinearWorkflow workflow = NonlinearWorkflow() # Add tasks to the workflow with dependencies -workflow.add(task1) +workflow.add(task1) workflow.add(task2, task1.name) workflow.add(task3, task1.name, task2.name) # Execute the workflow diff --git a/docs/swarms/structs/sequential_workflow.md b/docs/swarms/structs/sequential_workflow.md index 6f6d8954..74ee1acb 100644 --- a/docs/swarms/structs/sequential_workflow.md +++ b/docs/swarms/structs/sequential_workflow.md @@ -310,9 +310,7 @@ from swarms.structs import Agent from swarms.structs.sequential_workflow import SequentialWorkflow # Example usage -api_key = ( - "" # Your actual API key here -) +api_key = "" # Your actual API key here # Initialize the language agent llm = OpenAIChat( @@ -350,9 +348,7 @@ from swarms.structs import Agent from swarms.structs.sequential_workflow import SequentialWorkflow # Example usage -api_key = ( - "" # Your actual API key here -) +api_key = "" # Your actual API key here # Initialize the language agent llm = OpenAIChat( @@ -393,9 +389,7 @@ from swarms.structs import Agent from swarms.structs.sequential_workflow import SequentialWorkflow # Example usage -api_key = ( - "" # Your actual API key here -) +api_key = "" # Your actual API key here # Initialize the language agent llm = OpenAIChat( @@ -436,9 +430,7 @@ from swarms.structs import Agent from swarms.structs.sequential_workflow import SequentialWorkflow # Example usage -api_key = ( - "" # Your actual API key here -) +api_key = "" # Your actual API key here # Initialize the language agent llm = OpenAIChat( diff --git a/docs/swarms/structs/stackoverflowswarm.md b/docs/swarms/structs/stackoverflowswarm.md new file mode 100644 index 00000000..c3e83b47 --- /dev/null +++ b/docs/swarms/structs/stackoverflowswarm.md @@ -0,0 +1,114 @@ +# StackOverflowSwarm Class Documentation + +## Overview + +The `StackOverflowSwarm` class is part of the `swarms.structs` library. It is designed to simulate a collective intelligence or swarm intelligence scenario where multiple individual agents (referred to as `Agent` objects) come together to solve problems or answer questions typically found on platforms like Stack Overflow. This class is helpful in experiments involving cooperative multi-agent interactions, decision-making, and problem-solving, primarily when applied to question-and-answer scenarios. + +Swarm intelligence is modeled after social insects and natural systems where the collective behavior of decentralized, self-organized systems leads to the solving of complex tasks. `StackOverflowSwarm`, as a mini-framework within this library, provides a way to simulate such systems programmatically. + +The design of the `StackOverflowSwarm` class is intended to allow easy tracking of multi-agent interactions, the ability to autosave conversations, provide verbose outputs for monitoring purposes, and deal with problem-solving in a structured manner. This document provides a deep dive into the class' mechanisms, its architecture, and comprehensive usage examples for developers and researchers interested in swarm intelligence applications. + +## Class Definition + +### StackOverflowSwarm Attributes: + +| Attribute | Type | Description | +|-----------------|---------------------|-----------------------------------------------------------------------------| +| `agents` | `List[Agent]` | The list of agents in the swarm. | +| `autosave` | `bool` | Flag indicating whether to automatically save the conversation. | +| `verbose` | `bool` | Flag indicating whether to display verbose output. | +| `save_filepath` | `str` | The filepath to save the conversation. | +| `conversation` | `Conversation` | The conversation object for storing the interactions. | +| `eval_agent` | `Agent` or `None` | An optional evaluation agent within the swarm (not used in provided code). | +| `upvotes` | `int` | Counter for the number of upvotes per post (initialized as 0). | +| `downvotes` | `int` | Counter for the number of downvotes per post (initialized as 0). | +| `forum` | `List` | An empty list to represent the forum for the agents to interact. | + +### StackOverflowSwarm Method: `__init__` + +| Argument | Type | Default | Description | +|------------------|---------------|----------------------------------|---------------------------------------------------| +| `agents` | `List[Agent]` | Required | The list of agents in the swarm. | +| `autosave` | `bool` | `False` | Whether to automatically save the conversation. | +| `verbose` | `bool` | `False` | Whether to display verbose output. | +| `save_filepath` | `str` | `"stack_overflow_swarm.json"` | The filepath to save the conversation. | +| `eval_agent` | `Agent` | `None` | An optional eval agent (not entirely implemented).| +| `*args` | `variable` | | Variable length argument list. | +| `**kwargs` | `variable` | | Arbitrary keyword arguments. | + +### StackOverflowSwarm Method: `run` + +| Argument | Type | Description | +|-----------|----------|------------------------------------------------------------------------| +| `task` | `str` | The task to be performed by the agents. | +| `*args` | `variable`| Variable length argument list. | +| `**kwargs`| `variable`| Arbitrary keyword arguments. | + +#### Return + +| Type | Description | +|--------------|---------------------------------------------| +| `List[str]` | The conversation history as a list of strings.| + +### API Usage and Examples + +**Initializing and Running a StackOverflowSwarm** + +```python +from swarms.structs.agent import Agent +from swarms.structs.stack_overflow_swarm import StackOverflowSwarm + + +# Define custom Agents with some logic (placeholder for actual Agent implementation) +class CustomAgent(Agent): + def run(self, conversation, *args, **kwargs): + return "This is a response from CustomAgent." + + +# Initialize agents +agent1 = CustomAgent(ai_name="Agent1") +agent2 = CustomAgent(ai_name="Agent2") + +# Create a swarm +swarm = StackOverflowSwarm(agents=[agent1, agent2], autosave=True, verbose=True) + +# Define a task +task_description = "How can I iterate over a list in Python?" + +# Run the swarm with a task +conversation_history = swarm.run(task_description) + +# Output the conversation history +print(conversation_history) +``` + +### How the Swarm Works + +The `StackOverflowSwarm` starts by initializing agents, autosave preferences, conversation object, upvote/downvote counters, and a forum list to manage inter-agent communication. When the `run` method is invoked, it adds the given task to the conversation, logging this addition if verbose mode is enabled. + +Each agent in the swarm runs its logic, possibly taking the current conversation history into consideration (the exact logic depends on the agent's implementation) and then responds to the task. Each agent's response is added to the conversation and logged. + +If autosave is enabled, the conversation is saved to the specified file path. The `run` method ultimately returns the conversation history as a string, which could also be a serialized JSON depending on the implementation of `Agent` and `Conversation`. + +### Considerations + +- This is a high-level conceptual example and lacks the detailed implementations of `Agent`, `Conversation`, and the actual `run` logic within each `Agent`. +- The `eval_agent` attribute and related logic have not been implemented in the provided code. + +### Common Issues + +- Since the implementation of `Agent` and `Conversation` is not provided, one must ensure these components are compatible with the `StackOverflowSwarm` class for the interconnectivity and conversation saving/management to function correctly. +- It is essential to handle exceptions and errors within the `run` methods of each `Agent` to ensure that the failure of one agent does not halt the entire swarm. + +### Additional Resources + +For further exploration into swarm intelligence, collective behavior in natural and artificial systems, and multi-agent problem solving: + +1. Bonabeau, E., Dorigo, M., & Theraulaz, G. (1999). Swarm Intelligence: From Natural to Artificial Systems. Oxford University Press. +2. Kennedy, J., Eberhart, R. C., & Shi, Y. (2001). Swarm Intelligence. Morgan Kaufmann. +3. [Multi-Agent Systems Virtual Labs](http://multiagent.fr) +4. [PyTorch – Deep Learning and Artificial Intelligence](https://pytorch.org) + +### Note + +This documentation provides an overview of the `StackOverflowSwarm` class, its attributes, and methods. It should be adapted and expanded upon with actual code implementations for proper functionality and achieving the desired behavior in a swarm-based system. diff --git a/docs/swarms/structs/stepinput.md b/docs/swarms/structs/stepinput.md index ad4be016..2230ccdf 100644 --- a/docs/swarms/structs/stepinput.md +++ b/docs/swarms/structs/stepinput.md @@ -12,10 +12,7 @@ The `StepInput` class is defined as follows: class StepInput(BaseModel): __root__: Any = Field( ..., - description=( - "Input parameters for the task step. Any value is" - " allowed." - ), + description=("Input parameters for the task step. Any value is" " allowed."), example='{\n"file_to_refactor": "models.py"\n}', ) ``` @@ -29,10 +26,7 @@ The `StepInput` class is designed to accept any input value, providing flexibili ```python from swarms.structs import StepInput -input_params = { - "file_to_refactor": "models.py", - "refactor_method": "code" -} +input_params = {"file_to_refactor": "models.py", "refactor_method": "code"} step_input = StepInput(__root__=input_params) ``` @@ -42,10 +36,7 @@ In this example, we import the `StepInput` class from the `swarms.structs` libra ```python from swarms.structs import StepInput -input_params = { - "input_path": "data.csv", - "output_path": "result.csv" -} +input_params = {"input_path": "data.csv", "output_path": "result.csv"} step_input = StepInput(__root__=input_params) ``` @@ -56,7 +47,7 @@ In this example, we again create an instance of `StepInput` by passing a diction from swarms.structs import StepInput file_path = "config.json" -with open(file_path, 'r') as f: +with open(file_path) as f: input_data = json.load(f) step_input = StepInput(__root__=input_data) diff --git a/docs/swarms/structs/swarmnetwork.md b/docs/swarms/structs/swarmnetwork.md index 2c2f74e5..efbdf279 100644 --- a/docs/swarms/structs/swarmnetwork.md +++ b/docs/swarms/structs/swarmnetwork.md @@ -28,6 +28,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + agent = Agent() swarm = SwarmNetwork(agents=[agent]) swarm.add_task("task") @@ -41,6 +42,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + agent = Agent() swarm = SwarmNetwork(agents=[agent]) await swarm.async_add_task("task") @@ -57,6 +59,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + agent = Agent() swarm = SwarmNetwork(agents=[agent]) swarm.run_single_agent(agent_id, "task") @@ -72,6 +75,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + agent = Agent() swarm = SwarmNetwork(agents=[agent]) swarm.run_many_agents("task") @@ -85,6 +89,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + agent = Agent() swarm = SwarmNetwork(agents=[agent]) swarm.list_agents() @@ -98,6 +103,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + agent = Agent() swarm = SwarmNetwork() swarm.add_agent(agent) @@ -111,6 +117,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + agent = Agent() swarm = SwarmNetwork(agents=[agent]) swarm.remove_agent(agent_id) @@ -124,6 +131,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + swarm = SwarmNetwork() swarm.scale_up(num_agents=5) ``` @@ -136,6 +144,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + swarm = SwarmNetwork(agents=[agent1, agent2, agent3, agent4, agent5]) swarm.scale_down(num_agents=2) ``` @@ -146,6 +155,7 @@ The `SwarmNetwork` class has the following parameters: ```python from swarms.structs.agent import Agent from swarms.structs.swarm_net import SwarmNetwork + agent = Agent() swarm = SwarmNetwork(agents=[agent]) swarm.create_apis_for_agents() diff --git a/docs/swarms/structs/task.md b/docs/swarms/structs/task.md index 7e829b66..f6a72aef 100644 --- a/docs/swarms/structs/task.md +++ b/docs/swarms/structs/task.md @@ -8,8 +8,9 @@ ```python # Example 1: Creating and executing a Task -from swarms.structs import Task, Agent from swarms.models import OpenAIChat +from swarms.structs import Agent, Task + agent = Agent(llm=OpenAIChat(openai_api_key=""), max_loops=1, dashboard=False) task = Task(agent=agent) task.execute("What's the weather in miami") diff --git a/docs/swarms/structs/taskinput.md b/docs/swarms/structs/taskinput.md index e7a0be68..8e9ed33f 100644 --- a/docs/swarms/structs/taskinput.md +++ b/docs/swarms/structs/taskinput.md @@ -20,11 +20,14 @@ The `TaskInput` class encapsulates the input parameters in a structured format. #### Usage Example 1: Using TaskInput for Debugging ```python from pydantic import BaseModel, Field + from swarms.structs import TaskInput + class DebugInput(TaskInput): debug: bool + # Creating an instance of DebugInput debug_params = DebugInput(__root__={"debug": True}) @@ -35,11 +38,14 @@ print(debug_params.debug) # Output: True #### Usage Example 2: Using TaskInput for Task Modes ```python from pydantic import BaseModel, Field + from swarms.structs import TaskInput + class ModeInput(TaskInput): mode: str + # Creating an instance of ModeInput mode_params = ModeInput(__root__={"mode": "benchmarks"}) @@ -50,12 +56,15 @@ print(mode_params.mode) # Output: benchmarks #### Usage Example 3: Using TaskInput with Arbitrary Parameters ```python from pydantic import BaseModel, Field + from swarms.structs import TaskInput + class ArbitraryInput(TaskInput): message: str quantity: int + # Creating an instance of ArbitraryInput arbitrary_params = ArbitraryInput(__root__={"message": "Hello, world!", "quantity": 5}) diff --git a/docs/swarms/structs/taskqueuebase.md b/docs/swarms/structs/taskqueuebase.md new file mode 100644 index 00000000..0feee648 --- /dev/null +++ b/docs/swarms/structs/taskqueuebase.md @@ -0,0 +1,130 @@ + +# `TaskQueueBase` + +## Introduction +The `swarms.structs` library is a key component of a multi-agent system's task management infrastructure. It provides the necessary classes and methods to create and manage queues of tasks that can be distributed among a swarm of agents. The purpose of this documentation is to guide users through the proper use of the `TaskQueueBase` class, which serves as an abstract base class for implementing task queues. + +## TaskQueueBase Class + +```python +import threading +from abc import ABC, abstractmethod + +# Include any additional imports that are relevant to decorators and other classes such as Task and Agent if needed + +# Definition of the synchronized_queue decorator (if necessary) + + +class TaskQueueBase(ABC): + def __init__(self): + self.lock = threading.Lock() + + @synchronized_queue + @abstractmethod + def add_task(self, task: Task) -> bool: + pass + + @synchronized_queue + @abstractmethod + def get_task(self, agent: Agent) -> Task: + pass + + @synchronized_queue + @abstractmethod + def complete_task(self, task_id: str): + pass + + @synchronized_queue + @abstractmethod + def reset_task(self, task_id: str): + pass +``` + +### Architecture and Purpose +The `TaskQueueBase` class provides an abstract interface for task queue implementations. This class uses the `threading.Lock` to ensure mutual exclusion, making it suitable for concurrent environments. The `@synchronized_queue` decorator implies that each method should be synchronized to prevent race conditions. + +Tasks are generally represented by the `Task` class, and agents by the `Agent` class. Implementations of the `TaskQueueBase` will provide the logic to store tasks, distribute them to agents, and manage their lifecycles. + +#### Methods and Their Arguments + +Here's an overview of each method and its arguments: + +| Method | Arguments | Return Type | Description | +|----------------|----------------|-------------|-----------------------------------------------------------------------------------------------| +| add_task | task (Task) | bool | Adds a task to the queue and returns True if successfully added, False otherwise. | +| get_task | agent (Agent) | Task | Retrieves the next task for the given agent. | +| complete_task | task_id (str) | None | Marks the task identified by task_id as completed. | +| reset_task | task_id (str) | None | Resets the task identified by task_id, typically done if an agent fails to complete the task. | + +### Example Usage + +Below are three examples of how the `TaskQueueBase` class can be implemented and used. + +**Note:** The actual code for decorators, Task, Agent, and concrete implementations of `TaskQueueBase` is not provided and should be created as per specific requirements. + +#### Example 1: Basic Implementation + +```python +# file: basic_queue.py + +# Assume synchronized_queue decorator is defined elsewhere +from decorators import synchronized_queue + +from swarms.structs import Agent, Task, TaskQueueBase + + +class BasicTaskQueue(TaskQueueBase): + def __init__(self): + super().__init__() + self.tasks = [] + + @synchronized_queue + def add_task(self, task: Task) -> bool: + self.tasks.append(task) + return True + + @synchronized_queue + def get_task(self, agent: Agent) -> Task: + return self.tasks.pop(0) + + @synchronized_queue + def complete_task(self, task_id: str): + # Logic to mark task as completed + pass + + @synchronized_queue + def reset_task(self, task_id: str): + # Logic to reset the task + pass + + +# Usage +queue = BasicTaskQueue() +# Add task, assuming Task object is created +queue.add_task(someTask) +# Get task for an agent, assuming Agent object is created +task = queue.get_task(someAgent) +``` + +#### Example 2: Priority Queue Implementation + +```python +# file: priority_queue.py +# Similar to example 1, but tasks are managed based on priority within add_task and get_task methods +``` + +#### Example 3: Persistent Queue Implementation + +```python +# file: persistent_queue.py +# An example demonstrating tasks being saved to a database or filesystem. Methods would include logic for persistence. +``` + +### Additional Information and Common Issues + +This section would provide insights on thread safety, error handling, and best practices in working with task queues in a multi-agent system. + +### References + +Links to further resources and any academic papers or external documentation related to task queues and multi-agent systems would be included here. + diff --git a/docs/swarms/swarms/godmode.md b/docs/swarms/swarms/godmode.md deleted file mode 100644 index 6655c954..00000000 --- a/docs/swarms/swarms/godmode.md +++ /dev/null @@ -1,249 +0,0 @@ -# `ModelParallelizer` Documentation - -## Table of Contents -1. [Understanding the Purpose](#understanding-the-purpose) -2. [Overview and Introduction](#overview-and-introduction) -3. [Class Definition](#class-definition) -4. [Functionality and Usage](#functionality-and-usage) -5. [Additional Information](#additional-information) -6. [Examples](#examples) -7. [Conclusion](#conclusion) - -## 1. Understanding the Purpose - -To create comprehensive documentation for the `ModelParallelizer` class, let's begin by understanding its purpose and functionality. - -### Purpose and Functionality - -`ModelParallelizer` is a class designed to facilitate the orchestration of multiple Language Model Models (LLMs) to perform various tasks simultaneously. It serves as a powerful tool for managing, distributing, and collecting responses from these models. - -Key features and functionality include: - -- **Parallel Task Execution**: `ModelParallelizer` can distribute tasks to multiple LLMs and execute them in parallel, improving efficiency and reducing response time. - -- **Structured Response Presentation**: The class presents the responses from LLMs in a structured tabular format, making it easy for users to compare and analyze the results. - -- **Task History Tracking**: `ModelParallelizer` keeps a record of tasks that have been submitted, allowing users to review previous tasks and responses. - -- **Asynchronous Execution**: The class provides options for asynchronous task execution, which can be particularly useful for handling a large number of tasks. - -Now that we have an understanding of its purpose, let's proceed to provide a detailed overview and introduction. - -## 2. Overview and Introduction - -### Overview - -The `ModelParallelizer` class is a crucial component for managing and utilizing multiple LLMs in various natural language processing (NLP) tasks. Its architecture and functionality are designed to address the need for parallel processing and efficient response handling. - -### Importance and Relevance - -In the rapidly evolving field of NLP, it has become common to use multiple language models to achieve better results in tasks such as translation, summarization, and question answering. `ModelParallelizer` streamlines this process by allowing users to harness the capabilities of several LLMs simultaneously. - -Key points: - -- **Parallel Processing**: `ModelParallelizer` leverages multithreading to execute tasks concurrently, significantly reducing the time required for processing. - -- **Response Visualization**: The class presents responses in a structured tabular format, enabling users to visualize and analyze the outputs from different LLMs. - -- **Task Tracking**: Developers can track the history of tasks submitted to `ModelParallelizer`, making it easier to manage and monitor ongoing work. - -### Architecture and How It Works - -The architecture and working of `ModelParallelizer` can be summarized in four steps: - -1. **Task Reception**: `ModelParallelizer` receives a task from the user. - -2. **Task Distribution**: The class distributes the task to all registered LLMs. - -3. **Response Collection**: `ModelParallelizer` collects the responses generated by the LLMs. - -4. **Response Presentation**: Finally, the class presents the responses from all LLMs in a structured tabular format, making it easy for users to compare and analyze the results. - -Now that we have an overview, let's proceed with a detailed class definition. - -## 3. Class Definition - -### Class Attributes - -- `llms`: A list of LLMs (Language Model Models) that `ModelParallelizer` manages. - -- `last_responses`: Stores the responses from the most recent task. - -- `task_history`: Keeps a record of all tasks submitted to `ModelParallelizer`. - -### Methods - -The `ModelParallelizer` class defines various methods to facilitate task distribution, execution, and response presentation. Let's examine some of the key methods: - -- `run(task)`: Distributes a task to all LLMs, collects responses, and returns them. - -- `print_responses(task)`: Prints responses from all LLMs in a structured tabular format. - -- `run_all(task)`: Runs the task on all LLMs sequentially and returns responses. - -- `arun_all(task)`: Asynchronously runs the task on all LLMs and returns responses. - -- `print_arun_all(task)`: Prints responses from all LLMs after asynchronous execution. - -- `save_responses_to_file(filename)`: Saves responses to a file for future reference. - -- `load_llms_from_file(filename)`: Loads LLMs from a file, making it easy to configure `ModelParallelizer` for different tasks. - -- `get_task_history()`: Retrieves the task history, allowing users to review previous tasks. - -- `summary()`: Provides a summary of task history and the last responses, aiding in post-processing and analysis. - -Now that we have covered the class definition, let's delve into the functionality and usage of `ModelParallelizer`. - -## 4. Functionality and Usage - -### Distributing a Task and Collecting Responses - -One of the primary use cases of `ModelParallelizer` is to distribute a task to all registered LLMs and collect their responses. This can be achieved using the `run(task)` method. Below is an example: - -```python -parallelizer = ModelParallelizer(llms) -responses = parallelizer.run("Translate the following English text to French: 'Hello, how are you?'") -``` - -### Printing Responses - -To present the responses from all LLMs in a structured tabular format, use the `print_responses(task)` method. Example: - -```python -parallelizer.print_responses("Summarize the main points of 'War and Peace.'") -``` - -### Saving Responses to a File - -Users can save the responses to a file using the `save_responses_to_file(filename)` method. This is useful for archiving and reviewing responses later. Example: - -```python -parallelizer.save_responses_to_file("responses.txt") -``` - -### Task History - -The `ModelParallelizer` class keeps track of the task history. Developers can access the task history using the `get_task_history()` method. Example: - -```python -task_history = parallelizer.get_task_history() -for i, task in enumerate(task_history): - print(f"Task {i + 1}: {task}") -``` - -## 5. Additional Information - -### Parallel Execution - -`ModelParallelizer` employs multithreading to execute tasks concurrently. This parallel processing capability significantly improves the efficiency of handling multiple tasks simultaneously. - -### Response Visualization - -The structured tabular format used for presenting responses simplifies the comparison and analysis of outputs from different LLMs. - -## 6. Examples - -Let's explore additional usage examples to illustrate the versatility of `ModelParallelizer` in handling various NLP tasks. - -### Example 1: Sentiment Analysis - -```python -from swarms.models import OpenAIChat -from swarms.swarms import ModelParallelizer -from swarms.workers.worker import Worker - -# Create an instance of an LLM for sentiment analysis -llm = OpenAIChat(model_name="gpt-4", openai_api_key="api-key", temperature=0.5) - -# Create worker agents -worker1 = Worker( - llm=llm, - ai_name="Bumble Bee", - ai_role="Worker in a swarm", - external_tools=None, - human_in_the_loop=False, - temperature=0.5, -) -worker2 = Worker - -( - llm=llm, - ai_name="Optimus Prime", - ai_role="Worker in a swarm", - external_tools=None, - human_in_the_loop=False, - temperature=0.5, -) -worker3 = Worker( - llm=llm, - ai_name="Megatron", - ai_role="Worker in a swarm", - external_tools=None, - human_in_the_loop=False, - temperature=0.5, -) - -# Register the worker agents with ModelParallelizer -agents = [worker1, worker2, worker3] -parallelizer = ModelParallelizer(agents) - -# Task for sentiment analysis -task = "Please analyze the sentiment of the following sentence: 'This movie is amazing!'" - -# Print responses from all agents -parallelizer.print_responses(task) -``` - -### Example 2: Translation - -```python -from swarms.models import OpenAIChat - -from swarms.swarms import ModelParallelizer - -# Define LLMs for translation tasks -translator1 = OpenAIChat(model_name="translator-en-fr", openai_api_key="api-key", temperature=0.7) -translator2 = OpenAIChat(model_name="translator-en-es", openai_api_key="api-key", temperature=0.7) -translator3 = OpenAIChat(model_name="translator-en-de", openai_api_key="api-key", temperature=0.7) - -# Register translation agents with ModelParallelizer -translators = [translator1, translator2, translator3] -parallelizer = ModelParallelizer(translators) - -# Task for translation -task = "Translate the following English text to French: 'Hello, how are you?'" - -# Print translated responses from all agents -parallelizer.print_responses(task) -``` - -### Example 3: Summarization - -```python -from swarms.models import OpenAIChat - -from swarms.swarms import ModelParallelizer - - -# Define LLMs for summarization tasks -summarizer1 = OpenAIChat(model_name="summarizer-en", openai_api_key="api-key", temperature=0.6) -summarizer2 = OpenAIChat(model_name="summarizer-en", openai_api_key="api-key", temperature=0.6) -summarizer3 = OpenAIChat(model_name="summarizer-en", openai_api_key="api-key", temperature=0.6) - -# Register summarization agents with ModelParallelizer -summarizers = [summarizer1, summarizer2, summarizer3] -parallelizer = ModelParallelizer(summarizers) - -# Task for summarization -task = "Summarize the main points of the article titled 'Climate Change and Its Impact on the Environment.'" - -# Print summarized responses from all agents -parallelizer.print_responses(task) -``` - -## 7. Conclusion - -In conclusion, the `ModelParallelizer` class is a powerful tool for managing and orchestrating multiple Language Model Models in natural language processing tasks. Its ability to distribute tasks, collect responses, and present them in a structured format makes it invaluable for streamlining NLP workflows. By following the provided documentation, users can harness the full potential of `ModelParallelizer` to enhance their natural language processing projects. - -For further information on specific LLMs or advanced usage, refer to the documentation of the respective models and their APIs. Additionally, external resources on parallel execution and response visualization can provide deeper insights into these topics. \ No newline at end of file diff --git a/docs/swarms/swarms/groupchat.md b/docs/swarms/swarms/groupchat.md deleted file mode 100644 index bf9cbaad..00000000 --- a/docs/swarms/swarms/groupchat.md +++ /dev/null @@ -1,167 +0,0 @@ -# Swarms Framework Documentation - ---- - -## Overview - -The Swarms framework is a Python library designed to facilitate the creation and management of a simulated group chat environment. This environment can be used for a variety of purposes, such as training conversational agents, role-playing games, or simulating dialogues for machine learning purposes. The core functionality revolves around managing the agent of messages between different agents within the chat, as well as handling the selection and responses of these agents based on the conversation's context. - -### Purpose - -The purpose of the Swarms framework, and specifically the `GroupChat` and `GroupChatManager` classes, is to simulate a dynamic and interactive conversation between multiple agents. This simulates a real-time chat environment where each participant is represented by an agent with a specific role and behavioral patterns. These agents interact within the rules of the group chat, controlled by the `GroupChatManager`. - -### Key Features - -- **Agent Interaction**: Allows multiple agents to communicate within a group chat scenario. -- **Message Management**: Handles the storage and agent of messages within the group chat. -- **Role Play**: Enables agents to assume specific roles and interact accordingly. -- **Conversation Context**: Maintains the context of the conversation for appropriate responses by agents. - ---- - -## GroupChat Class - -The `GroupChat` class is the backbone of the Swarms framework's chat simulation. It maintains the list of agents participating in the chat, the messages that have been exchanged, and the logic to reset the chat and determine the next speaker. - -### Class Definition - -#### Parameters - -| Parameter | Type | Description | Default Value | -|------------|---------------------|--------------------------------------------------------------|---------------| -| agents | List[Agent] | List of agent flows participating in the group chat. | None | -| messages | List[Dict] | List of message dictionaries exchanged in the group chat. | None | -| max_round | int | Maximum number of rounds/messages allowed in the group chat. | 10 | -| admin_name | str | The name of the admin agent in the group chat. | "Admin" | - -#### Class Properties and Methods - -- `agent_names`: Returns a list of the names of the agents in the group chat. -- `reset()`: Clears all messages from the group chat. -- `agent_by_name(name: str) -> Agent`: Finds and returns an agent by name. -- `next_agent(agent: Agent) -> Agent`: Returns the next agent in the list. -- `select_speaker_msg() -> str`: Returns the message for selecting the next speaker. -- `select_speaker(last_speaker: Agent, selector: Agent) -> Agent`: Logic to select the next speaker based on the last speaker and the selector agent. -- `_participant_roles() -> str`: Returns a string listing all participant roles. -- `format_history(messages: List[Dict]) -> str`: Formats the history of messages for display or processing. - -### Usage Examples - -#### Example 1: Initializing a GroupChat - -```python -from swarms.structs.agent import Agent -from swarms.groupchat import GroupChat - -# Assuming Agent objects (flow1, flow2, flow3) are initialized and configured -agents = [flow1, flow2, flow3] -group_chat = GroupChat(agents=agents, messages=[], max_round=10) -``` - -#### Example 2: Resetting a GroupChat - -```python -group_chat.reset() -``` - -#### Example 3: Selecting a Speaker - -```python -last_speaker = agents[0] # Assuming this is a Agent object representing the last speaker -selector = agents[1] # Assuming this is a Agent object with the selector role - -next_speaker = group_chat.select_speaker(last_speaker, selector) -``` - ---- - -## GroupChatManager Class - -The `GroupChatManager` class acts as a controller for the `GroupChat` instance. It orchestrates the interaction between agents, prompts for tasks, and manages the rounds of conversation. - -### Class Definition - -#### Constructor Parameters - -| Parameter | Type | Description | -|------------|-------------|------------------------------------------------------| -| groupchat | GroupChat | The GroupChat instance that the manager will handle. | -| selector | Agent | The Agent object that selects the next speaker. | - -#### Methods - -- `__call__(task: str)`: Invokes the GroupChatManager with a given task string to start the conversation. - -### Usage Examples - -#### Example 1: Initializing GroupChatManager - -```python -from swarms.groupchat import GroupChat, GroupChatManager -from swarms.structs.agent import Agent - -# Initialize your agents and group chat as shown in previous examples -chat_manager = GroupChatManager(groupchat=group_chat, selector=manager) -``` - -#### Example 2: Starting a Conversation - -```python -# Start the group chat with a task -chat_history = chat_manager("Start a conversation about space exploration.") -``` - -#### Example 3: Using the Call Method - -```python -# The call method is the same as starting a conversation -chat_history = chat_manager.__call__("Discuss recent advances in AI.") -``` - ---- - -## Conclusion - -In summary, the Swarms framework offers a unique and effective solution for simulating group chat environments. Its `GroupChat` and `GroupChatManager` classes provide the necessary infrastructure to create dynamic conversations between agents, manage messages, and maintain the context of the dialogue. This framework can be instrumental in developing more sophisticated conversational agents, experimenting with social dynamics in chat environments, and providing a rich dataset for machine learning applications. - -By leveraging the framework's features, users can create complex interaction scenarios that closely mimic real-world group communication. This can prove to be a valuable asset in the fields of artificial intelligence, computational social science, and beyond. - ---- - -### Frequently Asked Questions (FAQ) - -**Q: Can the Swarms framework handle real-time interactions between agents?** - -A: The Swarms framework is designed to simulate group chat environments. While it does not handle real-time interactions as they would occur on a network, it can simulate the agent of conversation in a way that mimics real-time communication. - -**Q: Is the Swarms framework capable of natural language processing?** - -A: The framework itself is focused on the structure and management of group chats. It does not inherently include natural language processing (NLP) capabilities. However, it can be integrated with NLP tools to enhance the simulation with language understanding and generation features. - -**Q: Can I customize the roles and behaviors of agents within the framework?** - -A: Yes, the framework is designed to be flexible. You can define custom roles and behaviors for agents to fit the specific requirements of your simulation scenario. - -**Q: What are the limitations of the Swarms framework?** - -A: The framework is constrained by its design to simulate text-based group chats. It is not suitable for voice or video communication simulations. Additionally, its effectiveness depends on the sophistication of the agents’ decision-making logic, which is outside the framework itself. - -**Q: Is it possible to integrate the Swarms framework with other chat services?** - -A: The framework is can be integrated with any chat services. However, it could potentially be adapted to work with chat service APIs, where the agents could be used to simulate user behavior within a real chat application. - -**Q: How does the `GroupChatManager` select the next speaker?** - -A: The `GroupChatManager` uses a selection mechanism, which is typically based on the conversation's context and the roles of the agents, to determine the next speaker. The specifics of this mechanism can be customized to match the desired agent of the conversation. - -**Q: Can I contribute to the Swarms framework or suggest features?** - -A: As with many open-source projects, contributions and feature suggestions can usually be made through the project's repository on platforms like GitHub. It's best to check with the maintainers of the Swarms framework for their contribution guidelines. - -**Q: Are there any tutorials or community support for new users of the Swarms framework?** - -A: Documentation and usage examples are provided with the framework. Community support may be available through forums, chat groups, or the platform where the framework is hosted. Tutorials may also be available from third-party educators or in official documentation. - -**Q: What programming skills do I need to use the Swarms framework effectively?** - -A: You should have a good understanding of Python programming, including experience with classes and methods. Familiarity with the principles of agent-based modeling and conversational AI would also be beneficial. diff --git a/docs/swarms/tokenizers/basetokenizer.md b/docs/swarms/tokenizers/basetokenizer.md index 16db07fc..325640ee 100644 --- a/docs/swarms/tokenizers/basetokenizer.md +++ b/docs/swarms/tokenizers/basetokenizer.md @@ -25,18 +25,19 @@ The `BaseTokenizer` class provides the structure for creating tokenizers. It inc ```python from swarms.tokenizers import BaseTokenizer -class SimpleTokenizer(BaseTokenizer): +class SimpleTokenizer(BaseTokenizer): def count_tokens(self, text: Union[str, List[dict]]) -> int: if isinstance(text, str): # Split text by spaces as a simple tokenization approach return len(text.split()) elif isinstance(text, list): # Assume list of dictionaries with 'token' key - return sum(len(item['token'].split()) for item in text) + return sum(len(item["token"].split()) for item in text) else: raise TypeError("Unsupported type for text") + # Usage example tokenizer = SimpleTokenizer(max_tokens=100) text = "This is an example sentence to tokenize." diff --git a/docs/swarms/tokenizers/coheretokenizer.md b/docs/swarms/tokenizers/coheretokenizer.md index 5a11b8ce..197346a3 100644 --- a/docs/swarms/tokenizers/coheretokenizer.md +++ b/docs/swarms/tokenizers/coheretokenizer.md @@ -57,7 +57,7 @@ def count_tokens(self, text: str | list) -> int: Args: text (str | list): The input text to tokenize. - + Returns: int: The number of tokens in the text. @@ -82,13 +82,14 @@ First, the Cohere client must be initialized and passed in to create an instance ```python from cohere import Client + from swarms.tokenizers import CohereTokenizer # Initialize Cohere client with your API key -cohere_client = Client('your-api-key') +cohere_client = Client("your-api-key") # Instantiate the tokenizer -tokenizer = CohereTokenizer(model='your-model-name', client=cohere_client) +tokenizer = CohereTokenizer(model="your-model-name", client=cohere_client) ``` ### Count Tokens Example 1 diff --git a/docs/swarms/tokenizers/huggingfacetokenizer.md b/docs/swarms/tokenizers/huggingfacetokenizer.md index 8cf7fd77..9330b3be 100644 --- a/docs/swarms/tokenizers/huggingfacetokenizer.md +++ b/docs/swarms/tokenizers/huggingfacetokenizer.md @@ -76,7 +76,7 @@ Tokenizes given text when the object is called like a function. from swarms.tokenizers import HuggingFaceTokenizer # Initialize the tokenizer with the path to your tokenizer model. -tokenizer = HuggingFaceTokenizer('/path/to/your/model_dir') +tokenizer = HuggingFaceTokenizer("/path/to/your/model_dir") ``` ### 2. Encoding Text diff --git a/docs/swarms/tokenizers/openaitokenizer.md b/docs/swarms/tokenizers/openaitokenizer.md index 9e051c32..94918261 100644 --- a/docs/swarms/tokenizers/openaitokenizer.md +++ b/docs/swarms/tokenizers/openaitokenizer.md @@ -50,7 +50,7 @@ Given the extensive nature of this class, several examples are provided for each ```python from swarms.tokenizers import OpenAITokenizer -tokenizer = OpenAITokenizer(model='gpt-4') +tokenizer = OpenAITokenizer(model="gpt-4") ``` This example creates a new instance of `OpenAITokenizer` set to work with the GPT-4 model. @@ -61,7 +61,7 @@ This example creates a new instance of `OpenAITokenizer` set to work with the GP text = "Hello, this is an example text to tokenize." # Initialize the tokenizer -tokenizer = OpenAITokenizer(model='gpt-4') +tokenizer = OpenAITokenizer(model="gpt-4") # Count tokens num_tokens = tokenizer.count_tokens(text) @@ -78,7 +78,7 @@ messages = [ {"name": "Bob", "message": "I'm good! Just working on some code."}, ] -tokenizer = OpenAITokenizer(model='gpt-3.5-turbo') +tokenizer = OpenAITokenizer(model="gpt-3.5-turbo") # Count tokens for a list of messages num_tokens = tokenizer.len(messages, model="gpt-3.5-turbo-0613") diff --git a/docs/swarms/tokenizers/sentencepiecetokenizer.md b/docs/swarms/tokenizers/sentencepiecetokenizer.md index 390dbb07..ac6f2a2f 100644 --- a/docs/swarms/tokenizers/sentencepiecetokenizer.md +++ b/docs/swarms/tokenizers/sentencepiecetokenizer.md @@ -14,7 +14,7 @@ In `SentencePieceTokenizer`, the tokenization process is language-agnostic and e class SentencePieceTokenizer: """ Tokenizer of sentencepiece. - + Args: model_file (str): the path of the tokenizer model """ @@ -45,7 +45,7 @@ Parameter | Type | Description ```python from swarms.tokenizers import SentencePieceTokenizer -tokenizer = SentencePieceTokenizer(model_file='your_model.model') +tokenizer = SentencePieceTokenizer(model_file="your_model.model") ``` ### Properties: Vocabulary Information diff --git a/docs/swarms/utils/check_device.md b/docs/swarms/utils/check_device.md index bdb8c780..a944dc1f 100644 --- a/docs/swarms/utils/check_device.md +++ b/docs/swarms/utils/check_device.md @@ -36,16 +36,18 @@ This function does not take any mandatory argument. However, it supports optiona ### Example 1: Basic Usage ```python -import torch import logging + +import torch + from swarms.utils import check_device # Basic usage device = check_device( - log_level=logging.INFO, - memory_threshold=0.8, - capability_threshold=3.5, - return_type="list" + log_level=logging.INFO, + memory_threshold=0.8, + capability_threshold=3.5, + return_type="list", ) ``` @@ -53,24 +55,24 @@ device = check_device( ```python import torch -import logging + from swarms.utils import check_device # When CUDA is not available device = check_device() -print(device) # If CUDA is not available it should return torch.device('cpu') +print(device) # If CUDA is not available it should return torch.device('cpu') ``` ### Example 3: Multiple GPU Available ```python import torch -import logging + from swarms.utils import check_device # When multiple GPUs are available device = check_device() -print(device) # Should return a list of available GPU devices +print(device) # Should return a list of available GPU devices ``` ## Tips and Additional Information diff --git a/docs/swarms/utils/extract_code_from_markdown.md b/docs/swarms/utils/extract_code_from_markdown.md index f6f76835..fdef5018 100644 --- a/docs/swarms/utils/extract_code_from_markdown.md +++ b/docs/swarms/utils/extract_code_from_markdown.md @@ -57,14 +57,13 @@ Below are three examples of how you might use this function: Extracting code blocks from a simple markdown string. ```python -import re from swarms.utils import extract_code_from_markdown -markdown_string = '''# Example +markdown_string = """# Example This is an example of a code block: ```python print("Hello World!") -``` ''' +``` """ print(extract_code_from_markdown(markdown_string)) ``` @@ -75,13 +74,15 @@ Extracting code blocks from a markdown file. ```python import re + def extract_code_from_markdown(markdown_content: str) -> str: pattern = r"```(?:\w+\n)?(.*?)```" matches = re.findall(pattern, markdown_content, re.DOTALL) return "\n".join(code.strip() for code in matches) + # Assume that 'example.md' contains multiple code blocks -with open('example.md', 'r') as file: +with open("example.md") as file: markdown_content = file.read() print(extract_code_from_markdown(markdown_content)) ``` @@ -93,17 +94,20 @@ Using the function in a pipeline to extract and then analyze code blocks. ```python import re + def extract_code_from_markdown(markdown_content: str) -> str: pattern = r"```(?:\w+\n)?(.*?)```" matches = re.findall(pattern, markdown_content, re.DOTALL) return "\n".join(code.strip() for code in matches) + def analyze_code_blocks(code: str): # Add your analysis logic here - pass + pass + # Assume that 'example.md' contains multiple code blocks -with open('example.md', 'r') as file: +with open("example.md") as file: markdown_content = file.read() code_blocks = extract_code_from_markdown(markdown_content) analyze_code_blocks(code_blocks) diff --git a/docs/swarms/utils/find_image_path.md b/docs/swarms/utils/find_image_path.md index 59c9c127..844cbe78 100644 --- a/docs/swarms/utils/find_image_path.md +++ b/docs/swarms/utils/find_image_path.md @@ -40,15 +40,9 @@ The function `find_image_path` performs text parsing and pattern recognition to ```python def find_image_path(text): pattern = r"([A-Za-z]:\\[^:\n]*?\.(png|jpg|jpeg|PNG|JPG|JPEG))|(/[^:\n]*?\.(png|jpg|jpeg|PNG|JPG|JPEG))" - matches = [ - match.group() - for match in re.finditer(pattern, text) - if match.group() - ] + matches = [match.group() for match in re.finditer(pattern, text) if match.group()] matches += [match.replace("\\", "") for match in matches if match] - existing_paths = [ - match for match in matches if os.path.exists(match) - ] + existing_paths = [match for match in matches if os.path.exists(match)] return max(existing_paths, key=len) if existing_paths else None ``` @@ -75,7 +69,9 @@ Consider the case where the text has multiple image paths. from swarms.utils import find_image_path text = "Here is an image path: /home/user/image1.png. Here is another one: C:\\Users\\User\\Documents\\image2.jpeg" -print(find_image_path(text)) # Outputs: the longest image path (depends on your file system and existing files) +print( + find_image_path(text) +) # Outputs: the longest image path (depends on your file system and existing files) ``` **Example 3:** diff --git a/docs/swarms/utils/limit_tokens_from_string.md b/docs/swarms/utils/limit_tokens_from_string.md index b096ebad..bc2cf8cf 100644 --- a/docs/swarms/utils/limit_tokens_from_string.md +++ b/docs/swarms/utils/limit_tokens_from_string.md @@ -73,7 +73,7 @@ from swarms.utils import limit_tokens_from_string string = "In case the method does not find the specified model, it will fall back to gpt2 model." # model -model = "gpt-4" +model = "gpt-4" output = limit_tokens_from_string(string, model=model) ``` diff --git a/docs/swarms/utils/load_model_torch.md b/docs/swarms/utils/load_model_torch.md index ddcd7ee6..7effabb6 100644 --- a/docs/swarms/utils/load_model_torch.md +++ b/docs/swarms/utils/load_model_torch.md @@ -50,12 +50,14 @@ This function can be used directly inside your code as shown in the following ex Loading a model without specifying a device results in the function choosing the most optimal available device automatically. ```python -from swarms.utils import load_model_torch import torch.nn as nn +from swarms.utils import load_model_torch + # Assume `mymodel.pth` is in the current directory model_path = "./mymodel.pth" + # Define your model architecture if the model file only contains state dict class MyModel(nn.Module): def __init__(self): @@ -65,6 +67,7 @@ class MyModel(nn.Module): def forward(self, x): return self.linear(x) + model = MyModel() # Load the model diff --git a/docs/swarms/utils/math_eval.md b/docs/swarms/utils/math_eval.md index 691089f8..19eb9517 100644 --- a/docs/swarms/utils/math_eval.md +++ b/docs/swarms/utils/math_eval.md @@ -15,6 +15,8 @@ Let's say you have two functions: `ground_truth` and `generated_func`, that have @math_eval(ground_truth, generated_func) def test_func(x): return x + + result1, result2 = test_func(5) print(f"Result from ground_truth: {result1}") print(f"Result from generated_func: {result2}") @@ -46,6 +48,7 @@ Here's how to implement the `math_eval` decorator: import functools import logging + def math_eval(func1, func2): """Math evaluation decorator.""" @@ -65,9 +68,7 @@ def math_eval(func1, func2): result2 = None if result1 != result2: - logging.warning( - f"Outputs do not match: {result1} != {result2}" - ) + logging.warning(f"Outputs do not match: {result1} != {result2}") return result1, result2 diff --git a/docs/swarms/utils/metrics_decorator.md b/docs/swarms/utils/metrics_decorator.md index aeafe151..17850ba1 100644 --- a/docs/swarms/utils/metrics_decorator.md +++ b/docs/swarms/utils/metrics_decorator.md @@ -70,6 +70,7 @@ def text_generator(self, text: str): # language generation implementation goes here return tokens + # Instantiate the class and call the decorated function obj = ClassName() obj.text_generator("Hello, world!") diff --git a/docs/swarms/utils/pdf_to_text.md b/docs/swarms/utils/pdf_to_text.md index aecde1a9..3ec73039 100644 --- a/docs/swarms/utils/pdf_to_text.md +++ b/docs/swarms/utils/pdf_to_text.md @@ -1,7 +1,7 @@ # pdf_to_text -## Introduction -The function `pdf_to_text` is a Python utility for converting a PDF file into a string of text content. It leverages the `PyPDF2` library, an excellent Python library for processing PDF files. The function takes in a PDF file's path and reads its content, subsequently returning the extracted textual data. +## Introduction +The function `pdf_to_text` is a Python utility for converting a PDF file into a string of text content. It leverages the `pypdf` library, an excellent Python library for processing PDF files. The function takes in a PDF file's path and reads its content, subsequently returning the extracted textual data. This function can be very useful when you want to extract textual information from PDF files automatically. For instance, when processing a large number of documents, performing textual analysis, or when you're dealing with text data that is only available in PDF format. @@ -34,14 +34,14 @@ def pdf_to_text(pdf_path: str) -> str: ## Function Description -`pdf_to_text` utilises the `PdfReader` function from the `PyPDF2` library to read the PDF file. If the PDF file does not exist at the specified path or there was an error while reading the file, appropriate exceptions will be raised. It then iterates through each page in the PDF and uses the `extract_text` function to extract the text content from each page. These contents are then concatenated into a single variable and returned as the result. +`pdf_to_text` utilises the `PdfReader` function from the `pypdf` library to read the PDF file. If the PDF file does not exist at the specified path or there was an error while reading the file, appropriate exceptions will be raised. It then iterates through each page in the PDF and uses the `extract_text` function to extract the text content from each page. These contents are then concatenated into a single variable and returned as the result. ## Usage Examples -To use this function, you first need to install the `PyPDF2` library. It can be installed via pip: +To use this function, you first need to install the `pypdf` library. It can be installed via pip: ```python -!pip install pypdf2 +!pip install pypdf ``` Then, you should import the `pdf_to_text` function: @@ -54,7 +54,7 @@ Here is an example of how to use `pdf_to_text`: ```python # Define the path to the pdf file -pdf_path = 'sample.pdf' +pdf_path = "sample.pdf" # Use the function to extract text text = pdf_to_text(pdf_path) @@ -68,4 +68,4 @@ print(text) - This function reads the text from the PDF. It does not handle images, graphical elements, or any non-text content. - If the PDF contains scanned images rather than textual data, the `extract_text` function may not be able to extract any text. In such cases, you would require OCR (Optical Character Recognition) tools to extract the text. - Be aware of the possibility that the output string might contain special characters or escape sequences because they were part of the PDF's content. You might need to clean the resulting text according to your requirements. -- The function uses the PyPDF2 library to facilitate the PDF reading and text extraction. For any issues related to PDF manipulation, consult the [PyPDF2 library documentation](https://pythonhosted.org/PyPDF2/). +- The function uses the pypdf library to facilitate the PDF reading and text extraction. For any issues related to PDF manipulation, consult the [pypdf library documentation](https://pypdf.readthedocs.io/en/stable/). diff --git a/docs/swarms/utils/prep_torch_inference.md b/docs/swarms/utils/prep_torch_inference.md index 68598fa8..0fde2503 100644 --- a/docs/swarms/utils/prep_torch_inference.md +++ b/docs/swarms/utils/prep_torch_inference.md @@ -56,7 +56,8 @@ Here are some examples of how you can use the `prep_torch_inference` method. Bef ```python import torch -from swarms.utils import prep_torch_inference, load_model_torch + +from swarms.utils import load_model_torch, prep_torch_inference ``` ### Example 1: Load a model for inference on CPU diff --git a/docs/swarms/utils/print_class_parameters.md b/docs/swarms/utils/print_class_parameters.md index 3c09578f..84e0104f 100644 --- a/docs/swarms/utils/print_class_parameters.md +++ b/docs/swarms/utils/print_class_parameters.md @@ -94,16 +94,16 @@ def print_class_parameters(cls, api_format: bool = False): if api_format: param_dict = {} for name, param in params.items(): - if name == "self": - continue - param_dict[name] = str(param.annotation) + if name == "self": + continue + param_dict[name] = str(param.annotation) return param_dict # Print the parameters for name, param in params.items(): - if name == "self": - continue - print(f"Parameter: {name}, Type: {param.annotation}") + if name == "self": + continue + print(f"Parameter: {name}, Type: {param.annotation}") except Exception as e: print(f"An error occurred while inspecting the class: {e}") diff --git a/docs/swarms/workers/base.md b/docs/swarms/workers/base.md index 8991210b..9da45ba3 100644 --- a/docs/swarms/workers/base.md +++ b/docs/swarms/workers/base.md @@ -37,43 +37,46 @@ class AbstractWorker: Args: name (str): Name of the worker. """ - + @property def name(self): """Get the name of the worker.""" - pass def run(self, task: str): """Run the worker agent once.""" - pass - def send(self, message: Union[Dict, str], recipient, request_reply: Optional[bool] = None): + def send( + self, message: Union[Dict, str], recipient, request_reply: Optional[bool] = None + ): """Send a message to another worker.""" - pass - async def a_send(self, message: Union[Dict, str], recipient, request_reply: Optional[bool] = None): + async def a_send( + self, message: Union[Dict, str], recipient, request_reply: Optional[bool] = None + ): """Send a message to another worker asynchronously.""" - pass - def receive(self, message: Union[Dict, str], sender, request_reply: Optional[bool] = None): + def receive( + self, message: Union[Dict, str], sender, request_reply: Optional[bool] = None + ): """Receive a message from another worker.""" - pass - async def a_receive(self, message: Union[Dict, str], sender, request_reply: Optional[bool] = None): + async def a_receive( + self, message: Union[Dict, str], sender, request_reply: Optional[bool] = None + ): """Receive a message from another worker asynchronously.""" - pass def reset(self): """Reset the worker.""" - pass - def generate_reply(self, messages: Optional[List[Dict]] = None, sender=None, **kwargs) -> Union[str, Dict, None]: + def generate_reply( + self, messages: Optional[List[Dict]] = None, sender=None, **kwargs + ) -> Union[str, Dict, None]: """Generate a reply based on received messages.""" - pass - async def a_generate_reply(self, messages: Optional[List[Dict]] = None, sender=None, **kwargs) -> Union[str, Dict, None]: + async def a_generate_reply( + self, messages: Optional[List[Dict]] = None, sender=None, **kwargs + ) -> Union[str, Dict, None]: """Generate a reply based on received messages asynchronously.""" - pass ``` ### 2.2 Attributes @@ -121,6 +124,7 @@ class MyWorker(AbstractWorker): def run(self, task: str): print(f"{self.name} is performing task: {task}") + worker = MyWorker("Worker1") worker.run("Collect data") ``` @@ -155,6 +159,7 @@ The `a_send()` method is an asynchronous version of the `send()` method, allowin ```python import asyncio + async def main(): worker1 = AbstractWorker("Worker1") worker2 = AbstractWorker("Worker2") @@ -162,6 +167,7 @@ async def main(): message = "Hello, Worker2!" await worker1.a_send(message, worker2) + loop = asyncio.get_event_loop() loop.run_until_complete(main()) ``` @@ -208,6 +214,7 @@ The `a_receive()` method is an asynchronous version of the `receive()` method, a ```python import asyncio + async def main(): worker1 = AbstractWorker("Worker1") worker2 = AbstractWorker("Worker2") @@ -218,6 +225,7 @@ async def main(): await worker1.a_receive(message1, worker2) await worker1.a_receive(message2, worker2) + loop = asyncio.get_event_loop() loop.run_until_complete(main()) ``` @@ -233,6 +241,7 @@ class MyWorker(AbstractWorker): def reset(self): print(f"{self.name} has been reset.") + worker = MyWorker("Worker1") worker.reset() ``` @@ -253,13 +262,16 @@ The `generate_reply()` method is a placeholder for generating a reply based on r ```python class MyWorker(AbstractWorker): - def generate_reply(self, messages: Optional[List[Dict]] = None, sender=None, **kwargs) -> Union[str, Dict, None]: + def generate_reply( + self, messages: Optional[List[Dict]] = None, sender=None, **kwargs + ) -> Union[str, Dict, None]: if messages: # Generate a reply based on received messages return f"Received {len(messages)} messages from {sender.name}." else: return None + worker1 = MyWorker("Worker1") worker2 = MyWorker("Worker2") @@ -284,6 +296,7 @@ The `a_generate_reply()` method is an asynchronous version of the `generate_repl ```python import asyncio + async def main(): worker1 = AbstractWorker("Worker1") worker2 = AbstractWorker("Worker2") @@ -294,6 +307,7 @@ async def main(): if reply: print(f"{worker2.name} generated a reply: {reply}") + loop = asyncio.get_event_loop() loop.run_until_complete(main()) ``` @@ -312,12 +326,16 @@ Start by creating a custom worker class that inherits from `AbstractWorker`. Def class CustomWorker(AbstractWorker): def run(self, task: str): print(f"{self.name} is performing task: {task}") - - def receive(self, message: Union[Dict, str], sender, request_reply: Optional[bool] = None): + + def receive( + self, message: Union[Dict, str], sender, request_reply: Optional[bool] = None + ): if isinstance(message, str): print(f"{self.name} received a text message from {sender.name}: {message}") elif isinstance(message, dict): - print(f"{self.name} received a dictionary message from {sender.name}: {message}") + print( + f"{self.name} received a dictionary message from {sender.name}: {message}" + ) ``` ### Step 2: Create Custom Worker Instances @@ -355,7 +373,9 @@ Customize the `generate_reply()` method to allow your workers to generate replie ```python class CustomWorker(AbstractWorker): - def generate_reply(self, messages: Optional[List[Dict]] = None, sender=None, **kwargs) -> Union[str, Dict, None]: + def generate_reply( + self, messages: Optional[List[Dict]] = None, sender=None, **kwargs + ) -> Union[str, Dict, None]: if messages: # Generate a reply based on received messages return f"Received {len(messages)} messages from {sender.name}." diff --git a/docs/swarms/workers/index.md b/docs/swarms/workers/index.md index 9cf75e8b..3662fd8a 100644 --- a/docs/swarms/workers/index.md +++ b/docs/swarms/workers/index.md @@ -49,11 +49,11 @@ Makes the Worker class callable. When an instance of the class is called, it wil ### **Example 1**: Basic usage with default parameters: ```python -from swarms.models import OpenAIChat from swarms import Worker +from swarms.models import OpenAIChat llm = OpenAIChat( - #enter your api key + # enter your api key openai_api_key="", temperature=0.5, ) @@ -195,17 +195,16 @@ response = node.run(task) # Print the response print(response) - ``` ### **Example 3**: Usage with human in the loop: ```python -from swarms.models import OpenAIChat from swarms import Worker +from swarms.models import OpenAIChat llm = OpenAIChat( - #enter your api key + # enter your api key openai_api_key="", temperature=0.5, ) @@ -223,7 +222,6 @@ node = Worker( task = "What were the winning boston marathon times for the past 5 years (ending in 2022)? Generate a table of the year, name, country of origin, and times." response = node.run(task) print(response) - ``` ## **Mathematical Description**: diff --git a/docs/why_swarms.md b/docs/why_swarms.md new file mode 100644 index 00000000..f157af6d --- /dev/null +++ b/docs/why_swarms.md @@ -0,0 +1,53 @@ +# Why Swarms? + +The need for multiple agents to work together in artificial intelligence (AI) and particularly in the context of Large Language Models (LLMs) stems from several inherent limitations and challenges in handling complex, dynamic, and multifaceted tasks with single-agent systems. Collaborating with multiple agents offers a pathway to enhance computational efficiency, cognitive diversity, and problem-solving capabilities. This section delves into the rationale behind employing multi-agent systems and strategizes on overcoming the associated expenses, such as API bills and hosting costs. + +### Why Multiple Agents Are Necessary + +#### 1. **Cognitive Diversity** + +Different agents can bring varied perspectives, knowledge bases, and problem-solving approaches to a task. This diversity is crucial in complex problem-solving scenarios where a single approach might not be sufficient. Cognitive diversity enhances creativity, leading to innovative solutions and the ability to tackle a broader range of problems. + +#### 2. **Specialization and Expertise** + +In many cases, tasks are too complex for a single agent to handle efficiently. By dividing the task among multiple specialized agents, each can focus on a segment where it excels, thereby increasing the overall efficiency and effectiveness of the solution. This approach leverages the expertise of individual agents to achieve superior performance in tasks that require multifaceted knowledge and skills. + +#### 3. **Scalability and Flexibility** + +Multi-agent systems can more easily scale to handle large-scale or evolving tasks. Adding more agents to the system can increase its capacity or capabilities, allowing it to adapt to larger workloads or new types of tasks. This scalability is essential in dynamic environments where the demand and nature of tasks can change rapidly. + +#### 4. **Robustness and Redundancy** + +Collaboration among multiple agents enhances the system's robustness by introducing redundancy. If one agent fails or encounters an error, others can compensate, ensuring the system remains operational. This redundancy is critical in mission-critical applications where failure is not an option. + +### Overcoming Expenses with API Bills and Hosting + +Deploying multiple agents, especially when relying on cloud-based services or APIs, can incur significant costs. Here are strategies to manage and reduce these expenses: + +#### 1. **Optimize Agent Efficiency** + +Before scaling up the number of agents, ensure each agent operates as efficiently as possible. This can involve refining algorithms, reducing unnecessary API calls, and optimizing data processing to minimize computational requirements and, consequently, the associated costs. + +#### 2. **Use Open Source and Self-Hosted Solutions** + +Where possible, leverage open-source models and technologies that can be self-hosted. While there is an initial investment in setting up the infrastructure, over time, self-hosting can significantly reduce costs related to API calls and reliance on third-party services. + +#### 3. **Implement Intelligent Caching** + +Caching results for frequently asked questions or common tasks can drastically reduce the need for repeated computations or API calls. Intelligent caching systems can determine what information to store and for how long, optimizing the balance between fresh data and computational savings. + +#### 4. **Dynamic Scaling and Load Balancing** + +Use cloud services that offer dynamic scaling and load balancing to adjust the resources allocated based on the current demand. This ensures you're not paying for idle resources during low-usage periods while still being able to handle high demand when necessary. + +#### 5. **Collaborative Cost-Sharing Models** + +In scenarios where multiple stakeholders benefit from the multi-agent system, consider implementing a cost-sharing model. This approach distributes the financial burden among the users or beneficiaries, making it more sustainable. + +#### 6. **Monitor and Analyze Costs** + +Regularly monitor and analyze your usage and associated costs to identify potential savings. Many cloud providers offer tools to track and forecast expenses, helping you to adjust your usage patterns and configurations to minimize costs without sacrificing performance. + +### Conclusion + +The collaboration of multiple agents in AI systems presents a robust solution to the complexity, specialization, scalability, and robustness challenges inherent in single-agent approaches. While the associated costs can be significant, strategic optimization, leveraging open-source technologies, intelligent caching, dynamic resource management, collaborative cost-sharing, and diligent monitoring can mitigate these expenses. By adopting these strategies, organizations can harness the power of multi-agent systems to tackle complex problems more effectively and efficiently, ensuring the sustainable deployment of these advanced technologies. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index dd928dab..385d8ad1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -58,8 +58,9 @@ nav: - Home: - Overview: "index.md" - Contributing: "contributing.md" + - Limitations of Individual Agents: "limits_of_individual_agents.md" - Swarms: - - Overview: "swarms/index.md" + - Overview: "swarms/index.md" - swarms.agents: - Agents: - WorkerAgent: "swarms/agents/workeragent.md" @@ -104,6 +105,7 @@ nav: - stepinput: "swarms/structs/stepinput.md" - artifact: "swarms/structs/artifact.md" - task: "swarms/structs/task.md" + - Task Queue Base: "swarms/structs/taskqueuebase.md" - Workflows: - recursiveworkflow: "swarms/structs/recursiveworkflow.md" - concurrentworkflow: "swarms/structs/concurrentworkflow.md" @@ -116,6 +118,7 @@ nav: - groupchat: "swarms/structs/groupchat.md" - swarmnetwork: "swarms/structs/swarmnetwork.md" - groupchatmanager: "swarms/structs/groupchatmanager.md" + - MajorityVoting: "swarms/structs/majorityvoting.md" - swarms.tokenizers: - Language: - Tokenizer: "swarms/tokenizers/tokenizer.md" diff --git a/playground/agents/multi_modal_auto_agent_example.py b/playground/agents/multi_modal_auto_agent_example.py index d32a6221..65f8fa2b 100644 --- a/playground/agents/multi_modal_auto_agent_example.py +++ b/playground/agents/multi_modal_auto_agent_example.py @@ -1,8 +1,9 @@ # Description: This is an example of how to use the Agent class to run a multi-modal workflow import os + from dotenv import load_dotenv -from swarms.models.gpt4_vision_api import GPT4VisionAPI -from swarms.structs import Agent + +from swarms import Agent, GPT4VisionAPI # Load the environment variables load_dotenv() diff --git a/playground/agents/multion_agent.py b/playground/agents/multion_agent.py new file mode 100644 index 00000000..2bbe7e92 --- /dev/null +++ b/playground/agents/multion_agent.py @@ -0,0 +1,49 @@ +import timeit + +from swarms import Agent, ConcurrentWorkflow, Task +from swarms.agents.multion_agent import MultiOnAgent + +# model +model = MultiOnAgent(multion_api_key="api-key") + + +# out = model.run("search for a recipe") +agent = Agent( + agent_name="MultiOnAgent", + description="A multi-on agent that performs browsing tasks.", + llm=model, + max_loops=1, + system_prompt=None, +) + +# logger.info("[Agent][ID][MultiOnAgent][Initialized][Successfully") + +# Task +task = Task( + agent=agent, + description="Download https://www.coachcamel.com/", +) + +# Swarm +# logger.info( +# f"Running concurrent workflow with task: {task.description}" +# ) + +# Measure execution time +start_time = timeit.default_timer() + +workflow = ConcurrentWorkflow( + max_workers=20, + autosave=True, + print_results=True, + return_results=True, +) + +# Add task to workflow +workflow.add(task) +workflow.run() + +# Calculate execution time +execution_time = timeit.default_timer() - start_time +# logger.info(f"Execution time: {execution_time} seconds") +print(f"Execution time: {execution_time} seconds") diff --git a/playground/agents/perimeter_defense_agent.py b/playground/agents/perimeter_defense_agent.py new file mode 100644 index 00000000..d235fa22 --- /dev/null +++ b/playground/agents/perimeter_defense_agent.py @@ -0,0 +1,72 @@ +import os + +from dotenv import load_dotenv + +import swarms.prompts.security_team as stsp +from swarms.models import GPT4VisionAPI +from swarms.structs import Agent + +# Load environment variables and initialize the Vision API +load_dotenv() +api_key = os.getenv("OPENAI_API_KEY") + +llm = GPT4VisionAPI(openai_api_key=api_key) + +# Image for analysis +img = "bank_robbery.jpg" + +# Initialize agents with respective prompts for security tasks +crowd_analysis_agent = Agent( + llm=llm, + sop=stsp.CROWD_ANALYSIS_AGENT_PROMPT, + max_loops=1, + multi_modal=True, +) + +weapon_detection_agent = Agent( + llm=llm, + sop=stsp.WEAPON_DETECTION_AGENT_PROMPT, + max_loops=1, + multi_modal=True, +) + +surveillance_monitoring_agent = Agent( + llm=llm, + sop=stsp.SURVEILLANCE_MONITORING_AGENT_PROMPT, + max_loops=1, + multi_modal=True, +) + +emergency_response_coordinator = Agent( + llm=llm, + sop=stsp.EMERGENCY_RESPONSE_COORDINATOR_PROMPT, + max_loops=1, + multi_modal=True, +) + +# Run agents with respective tasks on the same image +crowd_analysis = crowd_analysis_agent.run( + "Analyze the crowd dynamics in the scene", img +) + +weapon_detection_analysis = weapon_detection_agent.run( + "Inspect the scene for any potential threats", img +) + +surveillance_monitoring_analysis = surveillance_monitoring_agent.run( + "Monitor the overall scene for unusual activities", img +) + +emergency_response_analysis = emergency_response_coordinator.run( + "Develop a response plan based on the scene analysis", img +) + +# Process and output results for each task +# Example output (uncomment to use): +print(f"Crowd Analysis: {crowd_analysis}") +print(f"Weapon Detection Analysis: {weapon_detection_analysis}") +print( + "Surveillance Monitoring Analysis:" + f" {surveillance_monitoring_analysis}" +) +print(f"Emergency Response Analysis: {emergency_response_analysis}") diff --git a/playground/agents/simple_agent_example.py b/playground/agents/simple_agent_example.py index 5d9d57ed..b79b8f59 100644 --- a/playground/agents/simple_agent_example.py +++ b/playground/agents/simple_agent_example.py @@ -3,12 +3,11 @@ import os from dotenv import load_dotenv from swarms import ( - OpenAIChat, Conversation, + OpenAIChat, detect_markdown, extract_code_from_markdown, ) - from swarms.tools.code_executor import CodeExecutor conv = Conversation( diff --git a/playground/agents/tool_agent.py b/playground/agents/tool_agent.py index 0a95f42c..a6445b39 100644 --- a/playground/agents/tool_agent.py +++ b/playground/agents/tool_agent.py @@ -1,5 +1,6 @@ # Import necessary libraries from transformers import AutoModelForCausalLM, AutoTokenizer + from swarms import ToolAgent # Load the pre-trained model and tokenizer diff --git a/playground/agents/worker_example.py b/playground/agents/worker_example.py index 9e215e83..a2117e46 100644 --- a/playground/agents/worker_example.py +++ b/playground/agents/worker_example.py @@ -1,8 +1,10 @@ # Importing necessary modules import os + from dotenv import load_dotenv -from swarms.agents.worker_agent import Worker + from swarms import OpenAIChat +from swarms.agents.worker_agent import Worker # Loading environment variables from .env file load_dotenv() diff --git a/playground/demos/accountant_team/account_team2_example.py b/playground/demos/accountant_team/account_team2_example.py index 1b9d3659..6ad030a9 100644 --- a/playground/demos/accountant_team/account_team2_example.py +++ b/playground/demos/accountant_team/account_team2_example.py @@ -1,5 +1,7 @@ import os + from dotenv import load_dotenv + from swarms.models import Anthropic, OpenAIChat from swarms.prompts.accountant_swarm_prompts import ( DECISION_MAKING_PROMPT, diff --git a/playground/demos/ad_gen/ad_gen_example.py b/playground/demos/ad_gen/ad_gen_example.py index b665b63a..978ab502 100644 --- a/playground/demos/ad_gen/ad_gen_example.py +++ b/playground/demos/ad_gen/ad_gen_example.py @@ -1,9 +1,11 @@ -import random import os +import random + from dotenv import load_dotenv + from swarms.models import OpenAIChat -from swarms.structs import Agent from swarms.models.stable_diffusion import StableDiffusion +from swarms.structs import Agent load_dotenv() openai_api_key = os.getenv("OPENAI_API_KEY") diff --git a/playground/demos/assembly/assembly_example.py b/playground/demos/assembly/assembly_example.py index 704c80d4..7ac97ab0 100644 --- a/playground/demos/assembly/assembly_example.py +++ b/playground/demos/assembly/assembly_example.py @@ -1,5 +1,5 @@ -from swarms.structs import Agent from swarms.models.gpt4_vision_api import GPT4VisionAPI +from swarms.structs import Agent llm = GPT4VisionAPI() diff --git a/playground/demos/autotemp/autotemp_example.py b/playground/demos/autotemp/autotemp_example.py index baf8f091..f086f112 100644 --- a/playground/demos/autotemp/autotemp_example.py +++ b/playground/demos/autotemp/autotemp_example.py @@ -1,4 +1,5 @@ import re + from swarms.models.openai_models import OpenAIChat diff --git a/playground/demos/autotemp/blog_gen_example.py b/playground/demos/autotemp/blog_gen_example.py index e11a1521..fe2a2317 100644 --- a/playground/demos/autotemp/blog_gen_example.py +++ b/playground/demos/autotemp/blog_gen_example.py @@ -1,7 +1,9 @@ import os + +from autotemp import AutoTemp from termcolor import colored + from swarms.models import OpenAIChat -from autotemp import AutoTemp from swarms.structs import SequentialWorkflow diff --git a/playground/demos/developer_swarm/main_example.py b/playground/demos/developer_swarm/main_example.py index 18c0a346..0a2e2a95 100644 --- a/playground/demos/developer_swarm/main_example.py +++ b/playground/demos/developer_swarm/main_example.py @@ -6,7 +6,7 @@ This is a simple example of how to use the swarms library to create a swarm of d The swarm is composed of two agents: - Documentation agent: writes documentation for a given code snippet. - Tests agent: writes tests for a given code snippet. - + The swarm is initialized with a language model that is used by the agents to generate text. In this example, we use the OpenAI GPT-3 language model. Agent: @@ -14,6 +14,7 @@ Documentation agent -> Tests agent """ + import os from dotenv import load_dotenv diff --git a/playground/demos/education/education_example.py b/playground/demos/education/education_example.py index 77f16f1b..31c08f0d 100644 --- a/playground/demos/education/education_example.py +++ b/playground/demos/education/education_example.py @@ -1,9 +1,10 @@ import os + from dotenv import load_dotenv -from swarms.models import OpenAIChat -from swarms.models.stable_diffusion import StableDiffusion -from swarms.structs import Agent, SequentialWorkflow + import swarms.prompts.education as edu_prompts +from swarms import Agent, SequentialWorkflow +from swarms.models import OpenAIChat # Load environment variables load_dotenv() @@ -15,9 +16,6 @@ llm = OpenAIChat( openai_api_key=api_key, temperature=0.5, max_tokens=3000 ) -# Initialize Stable Diffusion -sd_api = StableDiffusion(api_key=stability_api_key) - # User preferences (can be dynamically set in a real application) user_preferences = { "subjects": "Cognitive Architectures", @@ -60,8 +58,6 @@ workflow.add(sample_lesson_agent, "Generate a practice test") workflow.run() # Generate an image using Stable Diffusion -image_result = sd_api.run(image_prompt) - # Output results for each task for task in workflow.tasks: print( @@ -70,7 +66,4 @@ for task in workflow.tasks: ) # Output image result -print( - "Image Generation Task: Generate an image for the interactive" - f" lesson\nResult: {image_result}" -) +print("Image Generation Task: Generate an image for the interactive") diff --git a/playground/demos/gemini_benchmarking/gemini_chat_example.py b/playground/demos/gemini_benchmarking/gemini_chat_example.py index 6d9dc7ae..2ea6a900 100644 --- a/playground/demos/gemini_benchmarking/gemini_chat_example.py +++ b/playground/demos/gemini_benchmarking/gemini_chat_example.py @@ -1,5 +1,7 @@ import os + from dotenv import load_dotenv + from swarms.models.gemini import Gemini from swarms.prompts.react import react_prompt diff --git a/playground/demos/gemini_benchmarking/gemini_react_example.py b/playground/demos/gemini_benchmarking/gemini_react_example.py index 022405e9..37765baf 100644 --- a/playground/demos/gemini_benchmarking/gemini_react_example.py +++ b/playground/demos/gemini_benchmarking/gemini_react_example.py @@ -1,5 +1,7 @@ import os + from dotenv import load_dotenv + from swarms.models.gemini import Gemini from swarms.prompts.react import react_prompt diff --git a/playground/demos/grupa/app_example.py b/playground/demos/grupa/app_example.py index 3ab52e22..ff5fc27d 100644 --- a/playground/demos/grupa/app_example.py +++ b/playground/demos/grupa/app_example.py @@ -1,12 +1,12 @@ import os from dotenv import load_dotenv +from termcolor import colored from swarms.models import OpenAIChat from swarms.prompts.code_interpreter import CODE_INTERPRETER +from swarms.prompts.programming import DOCUMENTATION_SOP, TEST_SOP from swarms.structs import Agent -from swarms.prompts.programming import TEST_SOP, DOCUMENTATION_SOP -from termcolor import colored load_dotenv() diff --git a/playground/demos/jarvis_multi_modal_auto_agent/jarvis_example.py b/playground/demos/jarvis_multi_modal_auto_agent/jarvis_example.py index 05cd4fff..cce61fba 100644 --- a/playground/demos/jarvis_multi_modal_auto_agent/jarvis_example.py +++ b/playground/demos/jarvis_multi_modal_auto_agent/jarvis_example.py @@ -1,9 +1,8 @@ -from swarms.structs import Agent from swarms.models.gpt4_vision_api import GPT4VisionAPI from swarms.prompts.multi_modal_autonomous_instruction_prompt import ( MULTI_MODAL_AUTO_AGENT_SYSTEM_PROMPT_1, ) - +from swarms.structs import Agent llm = GPT4VisionAPI() diff --git a/playground/demos/langchain_example/langchain_example.py b/playground/demos/langchain_example/langchain_example.py index 803e7857..0e47684e 100644 --- a/playground/demos/langchain_example/langchain_example.py +++ b/playground/demos/langchain_example/langchain_example.py @@ -1,8 +1,10 @@ import os + from dotenv import load_dotenv -from swarms import Agent from langchain.llms import OpenAIChat +from swarms import Agent + # Loading environment variables from .env file load_dotenv() diff --git a/playground/demos/logistics/logistics_example.py b/playground/demos/logistics/logistics_example.py index 108ec702..48d8b9ce 100644 --- a/playground/demos/logistics/logistics_example.py +++ b/playground/demos/logistics/logistics_example.py @@ -1,16 +1,18 @@ -from swarms.structs import Agent import os + from dotenv import load_dotenv + from swarms.models import GPT4VisionAPI from swarms.prompts.logistics import ( + Efficiency_Agent_Prompt, Health_Security_Agent_Prompt, - Quality_Control_Agent_Prompt, Productivity_Agent_Prompt, + Quality_Control_Agent_Prompt, Safety_Agent_Prompt, Security_Agent_Prompt, Sustainability_Agent_Prompt, - Efficiency_Agent_Prompt, ) +from swarms.structs import Agent # from swarms.utils.banana_wrapper import banana diff --git a/playground/demos/multi_modal_autonomous_agents/multi_modal_auto_agent_example.py b/playground/demos/multi_modal_autonomous_agents/multi_modal_auto_agent_example.py index 74be8d5a..007776ac 100644 --- a/playground/demos/multi_modal_autonomous_agents/multi_modal_auto_agent_example.py +++ b/playground/demos/multi_modal_autonomous_agents/multi_modal_auto_agent_example.py @@ -1,6 +1,5 @@ -from swarms.structs import Agent from swarms.models.gpt4_vision_api import GPT4VisionAPI - +from swarms.structs import Agent llm = GPT4VisionAPI() diff --git a/playground/demos/multimodal_tot/main_example.py b/playground/demos/multimodal_tot/main_example.py index 2d5ed653..2a0494dc 100644 --- a/playground/demos/multimodal_tot/main_example.py +++ b/playground/demos/multimodal_tot/main_example.py @@ -2,8 +2,8 @@ Multi Modal tree of thoughts that leverages the GPT-4 language model and the Stable Diffusion model to generate a multimodal output and evaluate the output based a metric from 0.0 to 1.0 and then run a search algorithm using DFS and BFS and return the best output. - - + + task: Generate an image of a swarm of bees -> Image generator -> GPT4V evaluates the img from 0.0 to 1.0 -> DFS/BFS -> return the best output @@ -16,10 +16,12 @@ task: Generate an image of a swarm of bees -> Image generator -> GPT4V evaluates """ import os + from dotenv import load_dotenv +from termcolor import colored + from swarms.models.gpt4_vision_api import GPT4VisionAPI from swarms.models.stable_diffusion import StableDiffusion -from termcolor import colored # Load the environment variables load_dotenv() diff --git a/playground/demos/nutrition/nutrition_example.py b/playground/demos/nutrition/nutrition_example.py index 428560e3..b4331db6 100644 --- a/playground/demos/nutrition/nutrition_example.py +++ b/playground/demos/nutrition/nutrition_example.py @@ -1,7 +1,9 @@ -import os import base64 +import os + import requests from dotenv import load_dotenv + from swarms.models import OpenAIChat from swarms.structs import Agent diff --git a/playground/demos/personal_assistant/better_communication_example.py b/playground/demos/personal_assistant/better_communication_example.py index c6e79eb7..e0ff75cc 100644 --- a/playground/demos/personal_assistant/better_communication_example.py +++ b/playground/demos/personal_assistant/better_communication_example.py @@ -1,5 +1,5 @@ -import time import os +import time import pygame import speech_recognition as sr diff --git a/playground/demos/personal_stylist/personal_stylist_example.py b/playground/demos/personal_stylist/personal_stylist_example.py index b8641aa3..dde64cb7 100644 --- a/playground/demos/personal_stylist/personal_stylist_example.py +++ b/playground/demos/personal_stylist/personal_stylist_example.py @@ -1,14 +1,16 @@ -from swarms.structs import Agent import os + from dotenv import load_dotenv + from swarms.models import GPT4VisionAPI from swarms.prompts.personal_stylist import ( - HAIRCUT_STYLIST_AGENT_PROMPT, - MAKEUP_STYLIST_AGENT_PROMPT, + ACCESSORIES_STYLIST_AGENT_PROMPT, BEARD_STYLIST_AGENT_PROMPT, CLOTHING_STYLIST_AGENT_PROMPT, - ACCESSORIES_STYLIST_AGENT_PROMPT, + HAIRCUT_STYLIST_AGENT_PROMPT, + MAKEUP_STYLIST_AGENT_PROMPT, ) +from swarms.structs import Agent # Load environment variables load_dotenv() diff --git a/playground/demos/positive_med/positive_med_example.py b/playground/demos/positive_med/positive_med_example.py index b92b9586..09cbb411 100644 --- a/playground/demos/positive_med/positive_med_example.py +++ b/playground/demos/positive_med/positive_med_example.py @@ -20,6 +20,7 @@ Distribution Agent: - Optimize writer prompt to create longer and more enjoyeable blogs - Use Local Models like Storywriter """ + import os from termcolor import colored diff --git a/playground/demos/security_team/IMG_1625.MOV b/playground/demos/security_team/IMG_1625.MOV new file mode 100644 index 00000000..9bbb3574 Binary files /dev/null and b/playground/demos/security_team/IMG_1625.MOV differ diff --git a/playground/demos/security_team/security_team_example.py b/playground/demos/security_team/security_team_example.py index f00b0295..d391fe32 100644 --- a/playground/demos/security_team/security_team_example.py +++ b/playground/demos/security_team/security_team_example.py @@ -1,8 +1,11 @@ import os + from dotenv import load_dotenv +from termcolor import colored + +import swarms.prompts.security_team as stsp from swarms.models import GPT4VisionAPI from swarms.structs import Agent -import swarms.prompts.security_team as stsp # Load environment variables and initialize the Vision API load_dotenv() @@ -11,25 +14,21 @@ api_key = os.getenv("OPENAI_API_KEY") llm = GPT4VisionAPI(openai_api_key=api_key) # Image for analysis -img = "bank_robbery.jpg" +# img = "IMG_1617.jpeg" +img = "ubase1.jpeg" +img2 = "ubase2.jpeg" # Initialize agents with respective prompts for security tasks crowd_analysis_agent = Agent( + agent_name="Crowd Analysis Agent", llm=llm, sop=stsp.CROWD_ANALYSIS_AGENT_PROMPT, max_loops=1, multi_modal=True, ) -# Facial Recognition Agent is currently not operational -# facial_recognition_agent = Agent( -# llm=llm, -# sop=stsp.FACIAL_RECOGNITION_AGENT_PROMPT, -# max_loops=1, -# multi_modal=True, -# ) - weapon_detection_agent = Agent( + agent_name="Weapon Detection Agent", llm=llm, sop=stsp.WEAPON_DETECTION_AGENT_PROMPT, max_loops=1, @@ -37,6 +36,7 @@ weapon_detection_agent = Agent( ) surveillance_monitoring_agent = Agent( + agent_name="Surveillance Monitoring Agent", llm=llm, sop=stsp.SURVEILLANCE_MONITORING_AGENT_PROMPT, max_loops=1, @@ -44,37 +44,27 @@ surveillance_monitoring_agent = Agent( ) emergency_response_coordinator = Agent( + agent_name="Emergency Response Coordinator", # "Emergency Response Coordinator llm=llm, sop=stsp.EMERGENCY_RESPONSE_COORDINATOR_PROMPT, max_loops=1, multi_modal=True, ) -# Run agents with respective tasks on the same image -crowd_analysis = crowd_analysis_agent.run( - "Analyze the crowd dynamics in the scene", img -) - -# Facial Recognition Agent is currently not operational -# facial_recognition_analysis = facial_recognition_agent.run( -# "Identify any known individuals in the scene", img -# ) - +colored("Security Team Analysis", "green") +colored("Inspect the scene for any potential threats", "green") +colored("Weapon Detection Analysis", "green") weapon_detection_analysis = weapon_detection_agent.run( "Inspect the scene for any potential threats", img ) + +colored("Surveillance Monitoring Analysis", "cyan") surveillance_monitoring_analysis = surveillance_monitoring_agent.run( "Monitor the overall scene for unusual activities", img ) +colored("Emergency Response Analysis", "red") emergency_response_analysis = emergency_response_coordinator.run( "Develop a response plan based on the scene analysis", img ) - -# Process and output results for each task -# Example output (uncomment to use): -# print(f"Crowd Analysis: {crowd_analysis}") -# print(f"Weapon Detection Analysis: {weapon_detection_analysis}") -# print(f"Surveillance Monitoring Analysis: {surveillance_monitoring_analysis}") -# print(f"Emergency Response Analysis: {emergency_response_analysis}") diff --git a/playground/demos/simple_rag/simple_rag.py b/playground/demos/simple_rag/simple_rag.py index 129d59c4..c6ffbe15 100644 --- a/playground/demos/simple_rag/simple_rag.py +++ b/playground/demos/simple_rag/simple_rag.py @@ -1,4 +1,4 @@ -from swarms import Agent, OpenAIChat, ChromaDB +from swarms import Agent, ChromaDB, OpenAIChat # Making an instance of the ChromaDB class memory = ChromaDB( diff --git a/playground/demos/simple_rag/simple_rag_text.py b/playground/demos/simple_rag/simple_rag_text.py deleted file mode 100644 index 8e8e3cb0..00000000 --- a/playground/demos/simple_rag/simple_rag_text.py +++ /dev/null @@ -1,24 +0,0 @@ -# Text embeddings, image embeddings, and multimodal embeddings -# Add text and image embeddings into postgresl database - -from swarms.models.jina_embeds import JinaEmbeddings -from swarms.models.gigabind import Gigabind - -# Model -model = JinaEmbeddings( - max_length=8192, - device="cuda", - quantize=True, - huggingface_api_key="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", -) - - -# Encode text - -embeddings = model("Encode this super long document text") - - -# Embed images or text -model = Gigabind() - -multi_modal_embeddings = model(text=[text], imgs=[img1, img2, img3]) diff --git a/playground/demos/swarm_of_mma_manufacturing/main_example.py b/playground/demos/swarm_of_mma_manufacturing/main_example.py index 05b0e8e5..02a3cc1a 100644 --- a/playground/demos/swarm_of_mma_manufacturing/main_example.py +++ b/playground/demos/swarm_of_mma_manufacturing/main_example.py @@ -1,18 +1,19 @@ """ Swarm of multi modal autonomous agents for manufacturing! ---------------------------------------------------------- +--------------------------------------------------------- Health Security agent: Agent that monitors the health of working conditions: input image of factory output: health safety index 0.0 - 1.0 being the highest Quality Control agent: Agent that monitors the quality of the product: input image of product output: quality index 0.0 - 1.0 being the highest Productivity agent: Agent that monitors the productivity of the factory: input image of factory output: productivity index 0.0 - 1.0 being the highest Safety agent: Agent that monitors the safety of the factory: input image of factory output: safety index 0.0 - 1.0 being the highest Security agent: Agent that monitors the security of the factory: input image of factory output: security index 0.0 - 1.0 being the highest Sustainability agent: Agent that monitors the sustainability of the factory: input image of factory output: sustainability index 0.0 - 1.0 being the highest -Efficiency agent: Agent that monitors the efficiency of the factory: input image of factory output: efficiency index 0.0 - 1.0 being the highest +Efficiency agent: Agent that monitors the efficiency of the factory: input image of factory output: efficiency index 0.0 - 1.0 being the highest Agent: -health security agent -> quality control agent -> productivity agent -> safety agent -> security agent -> sustainability agent -> efficiency agent +health security agent -> quality control agent -> productivity agent -> safety agent -> security agent -> sustainability agent -> efficiency agent """ + import os from dotenv import load_dotenv diff --git a/playground/demos/urban_planning/urban_planning_example.py b/playground/demos/urban_planning/urban_planning_example.py index e85b4d31..2a52ced7 100644 --- a/playground/demos/urban_planning/urban_planning_example.py +++ b/playground/demos/urban_planning/urban_planning_example.py @@ -1,8 +1,10 @@ import os + from dotenv import load_dotenv -from swarms.models import OpenAIChat, GPT4VisionAPI -from swarms.structs import Agent, SequentialWorkflow + import swarms.prompts.urban_planning as upp +from swarms.models import GPT4VisionAPI, OpenAIChat +from swarms.structs import Agent, SequentialWorkflow # Load environment variables load_dotenv() diff --git a/playground/diy/hierchical_example.py b/playground/diy/hierchical_example.py deleted file mode 100644 index 0734c4f6..00000000 --- a/playground/diy/hierchical_example.py +++ /dev/null @@ -1,29 +0,0 @@ -from swarms import HierarchicalSwarm - - -swarm = HierarchicalSwarm( - openai_api_key="key", - model_type="openai", - model_id="gpt-4", - use_vectorstore=False, - use_async=False, - human_in_the_loop=False, - logging_enabled=False, -) - -# run the swarm with an objective -result = swarm.run("Design a new car") - -# or huggingface -swarm = HierarchicalSwarm( - model_type="huggingface", - model_id="tiaueu/falcon", - use_vectorstore=True, - embedding_size=768, - use_async=False, - human_in_the_loop=True, - logging_enabled=False, -) - -# Run the swarm with a particular objective -result = swarm.run("Write a sci-fi short story") diff --git a/playground/memory/chroma_usage_example.py b/playground/memory/chroma_usage_example.py index c17efa3a..b2fc3ce0 100644 --- a/playground/memory/chroma_usage_example.py +++ b/playground/memory/chroma_usage_example.py @@ -1,11 +1,15 @@ -from swarms.memory import chroma +from swarms.memory import ChromaDB -chromadbcl = chroma.ChromaClient() - -chromadbcl.add_vectors( - ["This is a document", "BONSAIIIIIII", "the walking dead"] +# Initialize the memory +chroma = ChromaDB( + metric="cosine", + limit_tokens=1000, + verbose=True, ) -results = chromadbcl.search_vectors("zombie", limit=1) +# Add text +text = "This is a test" +chroma.add(text) -print(results) +# Search for similar text +similar_text = chroma.query(text) diff --git a/playground/memory/qdrant/usage_example.py b/playground/memory/qdrant.py similarity index 90% rename from playground/memory/qdrant/usage_example.py rename to playground/memory/qdrant.py index 2b7c4a8e..8004ae02 100644 --- a/playground/memory/qdrant/usage_example.py +++ b/playground/memory/qdrant.py @@ -1,4 +1,5 @@ from langchain.document_loaders import CSVLoader + from swarms.memory import qdrant loader = CSVLoader( @@ -13,7 +14,6 @@ docs = loader.load() qdrant_client = qdrant.Qdrant( host="https://697ea26c-2881-4e17-8af4-817fcb5862e8.europe-west3-0.gcp.cloud.qdrant.io", collection_name="qdrant", - api_key="BhG2_yINqNU-aKovSEBadn69Zszhbo5uaqdJ6G_qDkdySjAljvuPqQ", ) qdrant_client.add_vectors(docs) diff --git a/playground/models/anthropic_example.py b/playground/models/anthropic_example.py index 940892ca..0f966b6b 100644 --- a/playground/models/anthropic_example.py +++ b/playground/models/anthropic_example.py @@ -1,6 +1,5 @@ from swarms.models.anthropic import Anthropic - model = Anthropic(anthropic_api_key="") diff --git a/playground/models/azure_openai.py b/playground/models/azure_openai.py new file mode 100644 index 00000000..aeda11c5 --- /dev/null +++ b/playground/models/azure_openai.py @@ -0,0 +1,10 @@ +from swarms.models.azure_openai_llm import AzureOpenAI + +# Initialize Azure OpenAI +model = AzureOpenAI() + +# Run the model +model( + "Create a youtube script for a video on how to use the swarms" + " framework" +) diff --git a/playground/models/bingchat_example.py b/playground/models/bingchat_example.py index 2af8472c..05e912c6 100644 --- a/playground/models/bingchat_example.py +++ b/playground/models/bingchat_example.py @@ -1,8 +1,9 @@ +import os + +from swarms.models import OpenAIChat from swarms.models.bing_chat import BingChat -from swarms.workers.worker import Worker from swarms.tools.autogpt import EdgeGPTTool, tool -from swarms.models import OpenAIChat -import os +from swarms.workers.worker import Worker api_key = os.getenv("OPENAI_API_KEY") diff --git a/playground/models/cohere_example.py b/playground/models/cohere_example.py index eb389db0..3a54956a 100644 --- a/playground/models/cohere_example.py +++ b/playground/models/cohere_example.py @@ -1,6 +1,5 @@ from swarms.models.cohere_chat import Cohere - cohere = Cohere(model="command-light", cohere_api_key="") out = cohere("Hello, how are you?") diff --git a/playground/models/dalle3_concurrent_example.py b/playground/models/dalle3_concurrent_example.py index de7f9cbb..e31f1cd8 100644 --- a/playground/models/dalle3_concurrent_example.py +++ b/playground/models/dalle3_concurrent_example.py @@ -1,12 +1,14 @@ """ -User task ->> GPT4 for prompt enrichment ->> Dalle3V for image generation -->> GPT4Vision for image captioning ->> Dalle3 better image +User task ->> GPT4 for prompt enrichment ->> Dalle3V for image generation +->> GPT4Vision for image captioning ->> Dalle3 better image """ -from swarms.models.dalle3 import Dalle3 + import os +from swarms.models.dalle3 import Dalle3 + api_key = os.environ["OPENAI_API_KEY"] dalle3 = Dalle3(openai_api_key=api_key, n=1) diff --git a/playground/models/distilled_whiserpx_example.py b/playground/models/distilled_whiserpx_example.py index 0742a1bc..1f6f0bc1 100644 --- a/playground/models/distilled_whiserpx_example.py +++ b/playground/models/distilled_whiserpx_example.py @@ -1,4 +1,5 @@ import asyncio + from swarms.models.distilled_whisperx import DistilWhisperModel model_wrapper = DistilWhisperModel() diff --git a/playground/models/gemini_example.py b/playground/models/gemini_example.py index 42fa4e74..75553bfc 100644 --- a/playground/models/gemini_example.py +++ b/playground/models/gemini_example.py @@ -1,5 +1,7 @@ import os + from dotenv import load_dotenv + from swarms.models.gemini import Gemini load_dotenv() diff --git a/playground/models/gpt4_v_example.py b/playground/models/gpt4_v_example.py index 822ec726..5c7a889e 100644 --- a/playground/models/gpt4_v_example.py +++ b/playground/models/gpt4_v_example.py @@ -1,6 +1,5 @@ from swarms.models.gpt4v import GPT4Vision - gpt4vision = GPT4Vision(openai_api_key="") img = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/VFPt_Solenoid_correct2.svg/640px-VFPt_Solenoid_correct2.svg.png" diff --git a/playground/models/miqu.py b/playground/models/miqu.py index f3fc1b4d..a4c9430a 100644 --- a/playground/models/miqu.py +++ b/playground/models/miqu.py @@ -1,6 +1,5 @@ from swarms import Mistral - # Initialize the model model = Mistral( model_name="miqudev/miqu-1-70b", diff --git a/playground/models/roboflow_example.py b/playground/models/roboflow_example.py index e7cae29e..56572fd5 100644 --- a/playground/models/roboflow_example.py +++ b/playground/models/roboflow_example.py @@ -1,6 +1,5 @@ from swarms import RoboflowMultiModal - # Initialize the model model = RoboflowMultiModal( api_key="api", diff --git a/playground/models/tts_speech_example.py b/playground/models/tts_speech_example.py index be38912c..6c33f944 100644 --- a/playground/models/tts_speech_example.py +++ b/playground/models/tts_speech_example.py @@ -1,7 +1,9 @@ -from swarms import OpenAITTS import os + from dotenv import load_dotenv +from swarms import OpenAITTS + load_dotenv() tts = OpenAITTS( diff --git a/playground/structs/flow_example.py b/playground/structs/agent_basic_customize.py similarity index 100% rename from playground/structs/flow_example.py rename to playground/structs/agent_basic_customize.py diff --git a/playground/structs/agent_with_longterm.py b/playground/structs/agent_with_longterm_memory.py similarity index 93% rename from playground/structs/agent_with_longterm.py rename to playground/structs/agent_with_longterm_memory.py index e803d095..588d6546 100644 --- a/playground/structs/agent_with_longterm.py +++ b/playground/structs/agent_with_longterm_memory.py @@ -3,7 +3,7 @@ import os from dotenv import load_dotenv # Import the OpenAIChat model and the Agent struct -from swarms import Agent, OpenAIChat, ChromaDB +from swarms import Agent, ChromaDB, OpenAIChat # Load the environment variables load_dotenv() diff --git a/playground/structs/agent_with_tools_example.py b/playground/structs/agent_with_tools_example.py index 99f21638..dc0dff4b 100644 --- a/playground/structs/agent_with_tools_example.py +++ b/playground/structs/agent_with_tools_example.py @@ -1,11 +1,11 @@ """ - - -tool decorated func [search_api] -> agent which parses the docs of the tool func + + +tool decorated func [search_api] -> agent which parses the docs of the tool func -> injected into prompt -> agent will output json containing tool usage -> agent output will be parsed -> tool executed -> terminal response can be returned to agent for self-healing - - + + """ import os @@ -13,8 +13,7 @@ import os from dotenv import load_dotenv # Import the OpenAIChat model and the Agent struct -from swarms.models import OpenAIChat -from swarms.structs import Agent +from swarms import Agent, OpenAIChat from swarms.tools.tool import tool # Load the environment variables @@ -69,7 +68,11 @@ llm = OpenAIChat( ## Initialize the workflow agent = Agent( - llm=llm, max_loops=1, dashboard=True, tools=[search_api] + agent_name="Research Agent", + llm=llm, + max_loops=1, + dashboard=True, + tools=[search_api, weather_api, rapid_api], ) # Run the workflow on a task diff --git a/playground/structs/autoscaler_example.py b/playground/structs/autoscaler_example.py index 8b808db6..aa7cf0c0 100644 --- a/playground/structs/autoscaler_example.py +++ b/playground/structs/autoscaler_example.py @@ -7,7 +7,6 @@ from swarms.models import OpenAIChat from swarms.structs import Agent from swarms.structs.autoscaler import AutoScaler - # Load the environment variables load_dotenv() diff --git a/playground/structs/basic_agent_with_azure_openai.py b/playground/structs/basic_agent_with_azure_openai.py new file mode 100644 index 00000000..76135a9f --- /dev/null +++ b/playground/structs/basic_agent_with_azure_openai.py @@ -0,0 +1,14 @@ +from swarms import Agent, AzureOpenAI + +## Initialize the workflow +agent = Agent( + llm=AzureOpenAI(), + max_loops="auto", + autosave=True, + dashboard=False, + streaming_on=True, + verbose=True, +) + +# Run the workflow on a task +agent("Understand the risk profile of this account") diff --git a/playground/structs/chat_example.py b/playground/structs/chat_example.py deleted file mode 100644 index 08783068..00000000 --- a/playground/structs/chat_example.py +++ /dev/null @@ -1,11 +0,0 @@ -from swarms import Orchestrator, Worker - -# Instantiate the Orchestrator with 10 agents -orchestrator = Orchestrator( - Worker, agent_list=[Worker] * 10, task_queue=[] -) - -# Agent 1 sends a message to Agent 2 -orchestrator.chat( - sender_id=1, receiver_id=2, message="Hello, Agent 2!" -) diff --git a/playground/structs/company_example.py b/playground/structs/company_example.py index 72396c61..abdee607 100644 --- a/playground/structs/company_example.py +++ b/playground/structs/company_example.py @@ -1,5 +1,3 @@ -# Example - import os from dotenv import load_dotenv diff --git a/playground/structs/concurrent_workflow_example.py b/playground/structs/concurrent_workflow_example.py index 98531388..8d8babde 100644 --- a/playground/structs/concurrent_workflow_example.py +++ b/playground/structs/concurrent_workflow_example.py @@ -1,6 +1,8 @@ import os + from dotenv import load_dotenv -from swarms import OpenAIChat, Task, ConcurrentWorkflow, Agent + +from swarms import Agent, ConcurrentWorkflow, OpenAIChat, Task # Load environment variables from .env file load_dotenv() diff --git a/playground/structs/debate_example.py b/playground/structs/debate_example.py index 5108d527..7cf0290b 100644 --- a/playground/structs/debate_example.py +++ b/playground/structs/debate_example.py @@ -5,10 +5,8 @@ import tenacity from langchain.chat_models import ChatOpenAI from langchain.output_parsers import RegexParser from langchain.prompts import PromptTemplate -from langchain.schema import ( - HumanMessage, - SystemMessage, -) +from langchain.schema import HumanMessage, SystemMessage + from swarms import Worker diff --git a/playground/structs/dialogue_simulator_example.py b/playground/structs/dialogue_simulator_example.py index ee9241b6..a7cdfe16 100644 --- a/playground/structs/dialogue_simulator_example.py +++ b/playground/structs/dialogue_simulator_example.py @@ -1,5 +1,4 @@ -from swarms.swarms import DialogueSimulator -from swarms.workers.worker import Worker +from swarms import DialogueSimulator, Worker from swarms.models import OpenAIChat llm = OpenAIChat( diff --git a/playground/structs/easy_example.py b/playground/structs/easy_example.py index 2a537c10..bebdb11a 100644 --- a/playground/structs/easy_example.py +++ b/playground/structs/easy_example.py @@ -1,7 +1,14 @@ -from swarms import swarm +from swarms import Agent, OpenAIChat -# Use the function -api_key = "APIKEY" -objective = "What is the capital of the UK?" -result = swarm(api_key, objective) -print(result) # Prints: "The capital of the UK is London." +## Initialize the workflow +agent = Agent( + llm=OpenAIChat(), + max_loops=1, + autosave=True, + dashboard=False, + streaming_on=True, + verbose=True, +) + +# Run the workflow on a task +agent("Find a chick fil a equivalent in hayes valley") diff --git a/playground/structs/godmode_example.py b/playground/structs/godmode_example.py index 46f71393..53e6b32e 100644 --- a/playground/structs/godmode_example.py +++ b/playground/structs/godmode_example.py @@ -2,8 +2,8 @@ import os from dotenv import load_dotenv +from swarms import ModelParallelizer from swarms.models import Anthropic, Gemini, Mixtral, OpenAIChat -from swarms.swarms import ModelParallelizer load_dotenv() diff --git a/playground/structs/groupchat_example.py b/playground/structs/groupchat_example.py index b9ab5761..5c9d1a7c 100644 --- a/playground/structs/groupchat_example.py +++ b/playground/structs/groupchat_example.py @@ -1,6 +1,5 @@ -from swarms import OpenAI, Agent -from swarms.structs.groupchat import GroupChatManager, GroupChat - +from swarms import Agent, OpenAI +from swarms.structs.groupchat import GroupChat, GroupChatManager api_key = "" diff --git a/playground/structs/gui_app_example.py b/playground/structs/gui_app_example.py index 751cb03a..662f8a46 100644 --- a/playground/structs/gui_app_example.py +++ b/playground/structs/gui_app_example.py @@ -1,6 +1,5 @@ from swarms import HierarchicalSwarm - # Retrieve your API key from the environment or replace with your actual key api_key = "sksdsds" diff --git a/playground/structs/kyle_hackathon.py b/playground/structs/kyle_hackathon.py new file mode 100644 index 00000000..1de48f1b --- /dev/null +++ b/playground/structs/kyle_hackathon.py @@ -0,0 +1,87 @@ +import os + +from dotenv import load_dotenv + +from swarms import Agent, OpenAIChat +from swarms.agents.multion_agent import MultiOnAgent +from swarms.memory.chroma_db import ChromaDB +from swarms.tools.tool import tool +from swarms.utils.code_interpreter import SubprocessCodeInterpreter + +# Load the environment variables +load_dotenv() + + +# Memory +chroma_db = ChromaDB() + + +# MultiOntool +@tool +def multion_tool( + task: str, + api_key: str = os.environ.get("MULTION_API_KEY"), +): + """ + Executes a task using the MultiOnAgent. + + Args: + task (str): The task to be executed. + api_key (str, optional): The API key for the MultiOnAgent. Defaults to the value of the MULTION_API_KEY environment variable. + + Returns: + The result of the task execution. + """ + multion = MultiOnAgent(multion_api_key=api_key) + return multion(task) + + +# Execute the interpreter tool +@tool +def execute_interpreter_tool( + code: str, +): + """ + Executes a single command using the interpreter. + + Args: + task (str): The command to be executed. + + Returns: + None + """ + out = SubprocessCodeInterpreter(debug_mode=True) + out = out.run(code) + return code + + +# Get the API key from the environment +api_key = os.environ.get("OPENAI_API_KEY") + +# Initialize the language model +llm = OpenAIChat( + temperature=0.5, + openai_api_key=api_key, +) + + +# Initialize the workflow +agent = Agent( + agent_name="Research Agent", + agent_description="An agent that performs research tasks.", + system_prompt="Perform a research task.", + llm=llm, + max_loops=1, + dashboard=True, + # tools=[multion_tool, execute_interpreter_tool], + verbose=True, + long_term_memory=chroma_db, + stopping_token="done", +) + +# Run the workflow on a task +out = agent.run( + "Generate a 10,000 word blog on health and wellness, and say done" + " when you are done" +) +print(out) diff --git a/playground/structs/majority_voting.py b/playground/structs/majority_voting.py new file mode 100644 index 00000000..149fd587 --- /dev/null +++ b/playground/structs/majority_voting.py @@ -0,0 +1,21 @@ +from swarms import Agent, MajorityVoting, OpenAIChat + +# Initialize the llm +llm = OpenAIChat() + +# Initialize the agents +agent1 = Agent(agent_name="worker-1", llm=llm, max_loops=1) +agent2 = Agent(agent_name="worker-2", llm=llm, max_loops=1) +agent3 = Agent(agent_name="worker3", llm=llm, max_loops=1) + + +# Initialize the majority voting +mv = MajorityVoting( + agents=[agent1, agent2, agent3], + concurrent=True, + multithreaded=True, +) + + +# Start the majority voting +mv.run("What is the capital of France?") diff --git a/playground/structs/message_pool_example.py b/playground/structs/message_pool_example.py new file mode 100644 index 00000000..6dbad128 --- /dev/null +++ b/playground/structs/message_pool_example.py @@ -0,0 +1,19 @@ +from swarms import OpenAIChat +from swarms.structs.agent import Agent +from swarms.structs.message_pool import MessagePool + +agent1 = Agent(llm=OpenAIChat(), agent_name="agent1") +agent2 = Agent(llm=OpenAIChat(), agent_name="agent2") +agent3 = Agent(llm=OpenAIChat(), agent_name="agent3") + +moderator = Agent(agent_name="moderator") +agents = [agent1, agent2, agent3] +message_pool = MessagePool( + agents=agents, moderator=moderator, turns=5 +) +message_pool.add(agent=agent1, content="Hello, agent2!", turn=1) +message_pool.add(agent=agent2, content="Hello, agent1!", turn=1) +message_pool.add(agent=agent3, content="Hello, agent1!", turn=1) +message_pool.get_all_messages() +message_pool.get_visible_messages(agent=agent1, turn=1) +message_pool.get_visible_messages(agent=agent2, turn=1) diff --git a/playground/structs/multi_agent_debate_example.py b/playground/structs/multi_agent_debate_example.py index 6124a21c..7a456fbc 100644 --- a/playground/structs/multi_agent_debate_example.py +++ b/playground/structs/multi_agent_debate_example.py @@ -1,9 +1,9 @@ +from swarms.models import OpenAIChat from swarms.swarms.multi_agent_debate import ( MultiAgentDebate, select_speaker, ) from swarms.workers.worker import Worker -from swarms.models import OpenAIChat llm = OpenAIChat() diff --git a/playground/structs/multi_modal_flow_example.py b/playground/structs/multi_modal_flow_example.py index b29c8bfd..ffc59367 100644 --- a/playground/structs/multi_modal_flow_example.py +++ b/playground/structs/multi_modal_flow_example.py @@ -1,5 +1,5 @@ # This might not work in the beginning but it's a starting point -from swarms.structs import Agent, GPT4V +from swarms.structs import GPT4V, Agent llm = GPT4V() diff --git a/multi_modal_rag_agent.py b/playground/structs/multi_modal_rag_agent.py similarity index 99% rename from multi_modal_rag_agent.py rename to playground/structs/multi_modal_rag_agent.py index b7944638..ff758e28 100644 --- a/multi_modal_rag_agent.py +++ b/playground/structs/multi_modal_rag_agent.py @@ -1,10 +1,12 @@ # Importing necessary modules import os + from dotenv import load_dotenv + from swarms import Agent, OpenAIChat -from swarms.tools.tool import tool -from swarms.prompts.visual_cot import VISUAL_CHAIN_OF_THOUGHT from swarms.memory.chroma_db import ChromaDB +from swarms.prompts.visual_cot import VISUAL_CHAIN_OF_THOUGHT +from swarms.tools.tool import tool # Loading environment variables from .env file load_dotenv() diff --git a/playground/structs/orchestrate_example.py b/playground/structs/orchestrate_example.py index b0e17588..6b91b74f 100644 --- a/playground/structs/orchestrate_example.py +++ b/playground/structs/orchestrate_example.py @@ -1,4 +1,4 @@ -from swarms import Worker, Orchestrator +from swarms import Orchestrator, Worker node = Worker( openai_api_key="", diff --git a/playground/structs/orchestrator_example.py b/playground/structs/orchestrator_example.py deleted file mode 100644 index b0e17588..00000000 --- a/playground/structs/orchestrator_example.py +++ /dev/null @@ -1,19 +0,0 @@ -from swarms import Worker, Orchestrator - -node = Worker( - openai_api_key="", - ai_name="Optimus Prime", -) - - -# Instantiate the Orchestrator with 10 agents -orchestrator = Orchestrator( - node, agent_list=[node] * 10, task_queue=[] -) - -# Agent 7 sends a message to Agent 9 -orchestrator.chat( - sender_id=7, - receiver_id=9, - message="Can you help me with this task?", -) diff --git a/playground/structs/recursive_example.py b/playground/structs/recursive_example.py index 9760b606..cc3dcf0f 100644 --- a/playground/structs/recursive_example.py +++ b/playground/structs/recursive_example.py @@ -1,6 +1,8 @@ import os + from dotenv import load_dotenv -from swarms import OpenAIChat, Task, RecursiveWorkflow, Agent + +from swarms import Agent, OpenAIChat, RecursiveWorkflow, Task # Load environment variables from .env file load_dotenv() diff --git a/playground/structs/sequential_workflow_example.py b/playground/structs/sequential_workflow_example.py index 7fa110bc..4f31684a 100644 --- a/playground/structs/sequential_workflow_example.py +++ b/playground/structs/sequential_workflow_example.py @@ -1,4 +1,4 @@ -from swarms import OpenAIChat, Agent, Task, SequentialWorkflow +from swarms import Agent, OpenAIChat, SequentialWorkflow, Task # Example usage llm = OpenAIChat( @@ -44,5 +44,5 @@ workflow.add(tasks=[task1, task2]) workflow.run() # # Output the results -# for task in workflow.tasks: -# print(f"Task: {task.description}, Result: {task.result}") +for task in workflow.tasks: + print(f"Task: {task.description}, Result: {task.result}") diff --git a/playground/structs/social_app_example.py b/playground/structs/social_app_example.py deleted file mode 100644 index 8bf90bf5..00000000 --- a/playground/structs/social_app_example.py +++ /dev/null @@ -1,19 +0,0 @@ -from ..swarms import HierarchicalSwarm - -# Retrieve your API key from the environment or replace with your actual key -api_key = "sksdsds" - -# Initialize HierarchicalSwarm with your API key -swarm = HierarchicalSwarm(openai_api_key=api_key) - -# Define an objective -objective = """ -Please develop and serve a simple community web service. -People can signup, login, post, comment. -Post and comment should be visible at once. -I want it to have neumorphism-style. -The ports you can use are 4500 and 6500. -""" - -# Run HierarchicalSwarm -swarm.run(objective) diff --git a/playground/structs/swarm_network_example.py b/playground/structs/swarm_network_example.py index de9c53b6..1675ca8b 100644 --- a/playground/structs/swarm_network_example.py +++ b/playground/structs/swarm_network_example.py @@ -3,7 +3,7 @@ import os from dotenv import load_dotenv # Import the OpenAIChat model and the Agent struct -from swarms import OpenAIChat, Agent, SwarmNetwork +from swarms import Agent, OpenAIChat, SwarmNetwork # Load the environment variables load_dotenv() diff --git a/playground/structs/swarms_example.py b/playground/structs/swarms_example.py deleted file mode 100644 index 9f015807..00000000 --- a/playground/structs/swarms_example.py +++ /dev/null @@ -1,16 +0,0 @@ -from swarms import HierarchicalSwarm - -# Retrieve your API key from the environment or replace with your actual key -api_key = "" - -# Initialize HierarchicalSwarm with your API key -swarm = HierarchicalSwarm(api_key) - -# Define an objective -objective = ( - "Find 20 potential customers for a HierarchicalSwarm based AI" - " Agent automation infrastructure" -) - -# Run HierarchicalSwarm -swarm.run(objective) diff --git a/playground/structs/todo_app_example.py b/playground/structs/todo_app_example.py deleted file mode 100644 index 627c72df..00000000 --- a/playground/structs/todo_app_example.py +++ /dev/null @@ -1,20 +0,0 @@ -from swarms import HierarchicalSwarm - - -# Retrieve your API key from the environment or replace with your actual key -api_key = "sksdsds" - -# Initialize HierarchicalSwarm with your API key -swarm = HierarchicalSwarm(openai_api_key=api_key) - -# Define an objective -objective = """ -Please develop and serve a simple web TODO app. -The user can list all TODO items and add or delete each TODO item. -I want it to have neumorphism-style. -The ports you can use are 4500 and 6500. - -""" - -# Run HierarchicalSwarm -swarm.run(objective) diff --git a/playground/structs/tool_utils_example.py b/playground/structs/tool_utils_example.py deleted file mode 100644 index ff7e17c2..00000000 --- a/playground/structs/tool_utils_example.py +++ /dev/null @@ -1,19 +0,0 @@ -from swarms.tools.tool import tool -from swarms.tools.tool_func_doc_scraper import scrape_tool_func_docs - - -@tool -def search_api(query: str) -> str: - """Search API - - Args: - query (str): _description_ - - Returns: - str: _description_ - """ - print(f"Searching API for {query}") - - -tool_docs = scrape_tool_func_docs(search_api) -print(tool_docs) diff --git a/playground/structs/workflow_example.py b/playground/structs/workflow_example.py deleted file mode 100644 index 91bff00a..00000000 --- a/playground/structs/workflow_example.py +++ /dev/null @@ -1,8 +0,0 @@ -from swarms.structs.workflow import Workflow -from swarms.models import OpenAIChat - - -llm = OpenAIChat() - - -workflow = Workflow(llm) diff --git a/playground/swarms_example.ipynb b/playground/swarms_example.ipynb index 2d7779b1..cdd2ebb7 100644 --- a/playground/swarms_example.ipynb +++ b/playground/swarms_example.ipynb @@ -1,111 +1,112 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "private_outputs": true, - "provenance": [], - "gpuType": "T4" - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - }, - "accelerator": "GPU" + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "private_outputs": true, + "provenance": [], + "gpuType": "T4" }, - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "cs5RHepmhkEh" - }, - "outputs": [], - "source": [ - "!pip3 install swarms" - ] - }, - { - "cell_type": "markdown", - "source": [ - "Copied from the repo, example.py\n", - "Enter your OpenAI API key here." - ], - "metadata": { - "id": "-d9k3egzgp2_" - } - }, - { - "cell_type": "code", - "source": [ - "from swarms.models import OpenAIChat\n", - "from swarms.structs import Agent\n", - "\n", - "api_key = \"\"\n", - "\n", - "# Initialize the language model, this model can be swapped out with Anthropic, ETC, Huggingface Models like Mistral, ETC\n", - "llm = OpenAIChat(\n", - " # model_name=\"gpt-4\"\n", - " openai_api_key=api_key,\n", - " temperature=0.5,\n", - " # max_tokens=100,\n", - ")\n", - "\n", - "\n", - "## Initialize the workflow\n", - "agent = Agent(\n", - " llm=llm,\n", - " max_loops=5,\n", - " dashboard=True,\n", - " # tools = [search_api, slack, ]\n", - " # stopping_condition=None, # You can define a stopping condition as needed.\n", - " # loop_interval=1,\n", - " # retry_attempts=3,\n", - " # retry_interval=1,\n", - " # interactive=False, # Set to 'True' for interactive mode.\n", - " # dynamic_temperature=False, # Set to 'True' for dynamic temperature handling.\n", - ")\n", - "\n", - "# out = agent.load_state(\"flow_state.json\")\n", - "# temp = agent.dynamic_temperature()\n", - "# filter = agent.add_response_filter(\"Trump\")\n", - "out = agent.run(\n", - " \"Generate a 10,000 word blog on mental clarity and the benefits of meditation.\"\n", - ")\n", - "# out = agent.validate_response(out)\n", - "# out = agent.analyze_feedback(out)\n", - "# out = agent.print_history_and_memory()\n", - "# # out = agent.save_state(\"flow_state.json\")\n", - "# print(out)" - ], - "metadata": { - "id": "K1Sbq4UkgVjk" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "Look at the log, which may be empty." - ], - "metadata": { - "id": "6VtgQ0F4BNc-" - } - }, - { - "cell_type": "code", - "source": [ - "!cat errors.txt" - ], - "metadata": { - "id": "RqL5LL3xBLWR" - }, - "execution_count": null, - "outputs": [] - } - ] + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cs5RHepmhkEh" + }, + "outputs": [], + "source": [ + "!pip3 install swarms" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Copied from the repo, example.py\n", + "Enter your OpenAI API key here." + ], + "metadata": { + "id": "-d9k3egzgp2_" + } + }, + { + "cell_type": "code", + "source": [ + "from swarms.models import OpenAIChat\n", + "from swarms.structs import Agent\n", + "\n", + "api_key = \"\"\n", + "\n", + "# Initialize the language model, this model can be swapped out with Anthropic, ETC, Huggingface Models like Mistral, ETC\n", + "llm = OpenAIChat(\n", + " # model_name=\"gpt-4\"\n", + " openai_api_key=api_key,\n", + " temperature=0.5,\n", + " # max_tokens=100,\n", + ")\n", + "\n", + "\n", + "## Initialize the workflow\n", + "agent = Agent(\n", + " llm=llm,\n", + " max_loops=5,\n", + " dashboard=True,\n", + " # tools = [search_api, slack, ]\n", + " # stopping_condition=None, # You can define a stopping condition as needed.\n", + " # loop_interval=1,\n", + " # retry_attempts=3,\n", + " # retry_interval=1,\n", + " # interactive=False, # Set to 'True' for interactive mode.\n", + " # dynamic_temperature=False, # Set to 'True' for dynamic temperature handling.\n", + ")\n", + "\n", + "# out = agent.load_state(\"flow_state.json\")\n", + "# temp = agent.dynamic_temperature()\n", + "# filter = agent.add_response_filter(\"Trump\")\n", + "out = agent.run(\n", + " \"Generate a 10,000 word blog on mental clarity and the benefits\"\n", + " \" of meditation.\"\n", + ")\n", + "# out = agent.validate_response(out)\n", + "# out = agent.analyze_feedback(out)\n", + "# out = agent.print_history_and_memory()\n", + "# # out = agent.save_state(\"flow_state.json\")\n", + "# print(out)" + ], + "metadata": { + "id": "K1Sbq4UkgVjk" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Look at the log, which may be empty." + ], + "metadata": { + "id": "6VtgQ0F4BNc-" + } + }, + { + "cell_type": "code", + "source": [ + "!cat errors.txt" + ], + "metadata": { + "id": "RqL5LL3xBLWR" + }, + "execution_count": null, + "outputs": [] + } + ] } \ No newline at end of file diff --git a/playground/tools/agent_with_tools_example.py b/playground/tools/agent_with_tools_example.py index 3bad0b1d..35b61703 100644 --- a/playground/tools/agent_with_tools_example.py +++ b/playground/tools/agent_with_tools_example.py @@ -1,8 +1,10 @@ import os -from swarms.models import OpenAIChat -from swarms.structs import Agent + from dotenv import load_dotenv +from swarms import Agent, OpenAIChat +from swarms.tools.tool import tool + load_dotenv() api_key = os.environ.get("OPENAI_API_KEY") @@ -10,24 +12,25 @@ api_key = os.environ.get("OPENAI_API_KEY") llm = OpenAIChat(api_key=api_key) -# @tool -# def search_api(query: str) -> str: -# """Search API -# Args: -# query (str): _description_ +@tool +def search_api(query: str) -> str: + """Search API + + Args: + query (str): _description_ -# Returns: -# str: _description_ -# """ -# print(f"Searching API for {query}") + Returns: + str: _description_ + """ + print(f"Searching API for {query}") ## Initialize the workflow agent = Agent( llm=llm, max_loops=5, - # tools=[search_api], + tools=[search_api], dashboard=True, ) diff --git a/playground/tools/tool_prompt_scaper_example.py b/playground/tools/tool_prompt_scaper_example.py deleted file mode 100644 index 2c0434d6..00000000 --- a/playground/tools/tool_prompt_scaper_example.py +++ /dev/null @@ -1,22 +0,0 @@ -from swarms.tools.tool import tool -from swarms.tools.tool_func_doc_scraper import scrape_tool_func_docs - -# Define a tool by decorating a function with the tool decorator and providing a docstring - - -@tool(return_direct=True) -def search_api(query: str): - """Search the web for the query - - Args: - query (str): _description_ - - Returns: - _type_: _description_ - """ - return f"Search results for {query}" - - -# Scrape the tool func docs to prepare for injection into the agent prompt -out = scrape_tool_func_docs(search_api) -print(out) diff --git a/playground/utils/pandas_to_str.py b/playground/utils/pandas_to_str.py new file mode 100644 index 00000000..fccf84eb --- /dev/null +++ b/playground/utils/pandas_to_str.py @@ -0,0 +1,11 @@ +import pandas as pd +from swarms import dataframe_to_text + +# # Example usage: +df = pd.DataFrame({ + 'A': [1, 2, 3], + 'B': [4, 5, 6], + 'C': [7, 8, 9], +}) + +print(dataframe_to_text(df)) diff --git a/playground/workflow_example_example.py b/playground/workflow_example_example.py deleted file mode 100644 index 78909dc7..00000000 --- a/playground/workflow_example_example.py +++ /dev/null @@ -1,10 +0,0 @@ -from swarms import Workflow -from swarms.models import ChatOpenAI - -workflow = Workflow(ChatOpenAI) - -workflow.add("What's the weather in miami") -workflow.add("Provide details for {{ parent_output }}") -workflow.add("Summarize the above information: {{ parent_output}}") - -workflow.run() diff --git a/pyproject.toml b/pyproject.toml index 2623bf8f..03304a3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,9 +2,10 @@ requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" + [tool.poetry] name = "swarms" -version = "4.1.3" +version = "4.2.1" description = "Swarms - Pytorch" license = "MIT" authors = ["Kye Gomez "] @@ -41,7 +42,7 @@ datasets = "*" optimum = "1.15.0" diffusers = "*" toml = "*" -PyPDF2 = "3.0.1" +pypdf = "4.0.1" accelerate = "*" anthropic = "*" sentencepiece = "0.1.98" @@ -49,6 +50,7 @@ httpx = "0.24.1" tiktoken = "0.4.0" attrs = "22.2.0" ratelimit = "2.2.1" +loguru = "0.7.2" cohere = "4.24" huggingface-hub = "*" pydantic = "1.10.12" @@ -75,11 +77,9 @@ pinecone-client = "*" roboflow = "*" - [tool.poetry.group.lint.dependencies] ruff = ">=0.0.249,<0.1.7" types-toml = "^0.10.8.1" -types-redis = "^4.3.21.6" types-pytz = "^2023.3.0.0" black = "^23.1.0" types-chardet = "^5.0.4.6" diff --git a/requirements.txt b/requirements.txt index e6496205..3eebf063 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,8 +14,9 @@ huggingface-hub google-generativeai==0.3.1 sentencepiece==0.1.98 requests_mock -PyPDF2==3.0.1 +pypdf==4.0.1 accelerate==0.22.0 +loguru==0.7.2 chromadb tensorflow optimum @@ -31,7 +32,7 @@ einops==0.7.0 opencv-python-headless==4.8.1.78 numpy openai==0.28.0 -opencv-python==4.7.0.72 +opencv-python==4.9.0.80 timm yapf autopep8 @@ -41,7 +42,7 @@ rich==13.5.2 mkdocs mkdocs-material mkdocs-glightbox -pre-commit==3.2.2 +pre-commit==3.6.2 peft psutil ultralytics diff --git a/scripts/auto_docs.py b/scripts/auto_tests_docs/auto_docs.py similarity index 71% rename from scripts/auto_docs.py rename to scripts/auto_tests_docs/auto_docs.py index f469e9ec..570793c8 100644 --- a/scripts/auto_docs.py +++ b/scripts/auto_tests_docs/auto_docs.py @@ -7,19 +7,12 @@ from dotenv import load_dotenv from scripts.auto_tests_docs.docs import DOCUMENTATION_WRITER_SOP from swarms import OpenAIChat +from swarms.structs.majority_voting import MajorityVoting +from swarms.structs.stackoverflow_swarm import StackOverflowSwarm +from swarms.structs.task_queue_base import TaskQueueBase +from swarms.structs.tool_json_schema import JSON ########## -from swarms.tokenizers.r_tokenizers import ( - SentencePieceTokenizer, - HuggingFaceTokenizer, - Tokenizer, -) -from swarms.tokenizers.base_tokenizer import BaseTokenizer -from swarms.tokenizers.openai_tokenizers import OpenAITokenizer -from swarms.tokenizers.anthropic_tokenizer import ( - AnthropicTokenizer, -) -from swarms.tokenizers.cohere_tokenizer import CohereTokenizer #################### @@ -47,7 +40,7 @@ def process_documentation(cls): # Process with OpenAI model (assuming the model's __call__ method takes this input and returns processed content) processed_content = model( - DOCUMENTATION_WRITER_SOP(input_content, "swarms.tokenizers") + DOCUMENTATION_WRITER_SOP(input_content, "swarms.structs") ) # doc_content = f"# {cls.__name__}\n\n{processed_content}\n" @@ -67,13 +60,10 @@ def process_documentation(cls): def main(): classes = [ - SentencePieceTokenizer, - HuggingFaceTokenizer, - Tokenizer, - BaseTokenizer, - OpenAITokenizer, - AnthropicTokenizer, - CohereTokenizer, + JSON, + MajorityVoting, + StackOverflowSwarm, + TaskQueueBase, ] threads = [] for cls in classes: @@ -87,7 +77,7 @@ def main(): for thread in threads: thread.join() - print("Documentation generated in 'swarms.tokenizers' directory.") + print("Documentation generated in 'swarms.structs' directory.") if __name__ == "__main__": diff --git a/scripts/auto_tests_docs/auto_docs_omni.py b/scripts/auto_tests_docs/auto_docs_omni.py index 3ae647a7..7fd3cde6 100644 --- a/scripts/auto_tests_docs/auto_docs_omni.py +++ b/scripts/auto_tests_docs/auto_docs_omni.py @@ -3,10 +3,10 @@ import os import threading from dotenv import load_dotenv + from scripts.auto_tests_docs.docs import DOCUMENTATION_WRITER_SOP from swarms import OpenAIChat - ########### diff --git a/scripts/auto_tests_docs/auto_tests.py b/scripts/auto_tests_docs/auto_tests.py index 87d891d2..c9d7c95e 100644 --- a/scripts/auto_tests_docs/auto_tests.py +++ b/scripts/auto_tests_docs/auto_tests.py @@ -2,35 +2,39 @@ import inspect import os import re import threading -from swarms import OpenAIChat -from scripts.auto_tests_docs.docs import TEST_WRITER_SOP_PROMPT - -######### -from swarms.tokenizers.r_tokenizers import ( - SentencePieceTokenizer, - HuggingFaceTokenizer, - Tokenizer, -) -from swarms.tokenizers.base_tokenizer import BaseTokenizer -from swarms.tokenizers.openai_tokenizers import OpenAITokenizer -from swarms.tokenizers.anthropic_tokenizer import ( - AnthropicTokenizer, -) -from swarms.tokenizers.cohere_tokenizer import CohereTokenizer ######## from dotenv import load_dotenv +from scripts.auto_tests_docs.docs import TEST_WRITER_SOP_PROMPT +from swarms import OpenAIChat + +######### +from swarms.memory.dict_internal_memory import DictInternalMemory +from swarms.memory.dict_shared_memory import DictSharedMemory +from swarms.memory.lanchain_chroma import LangchainChromaVectorMemory + load_dotenv() api_key = os.getenv("OPENAI_API_KEY") model = OpenAIChat( - model_name="gpt-4", openai_api_key=api_key, max_tokens=4000, ) +# agent = Agent( +# llm=model, +# agent_name="Unit Testing Agent", +# agent_description=( +# "This agent is responsible for generating unit tests for" +# " the swarms package." +# ), +# autosave=True, +# system_prompt=None, +# max_loops=1, +# ) + def extract_code_from_markdown(markdown_content: str): """ @@ -61,12 +65,11 @@ def create_test(cls): f" {cls.__name__}\n\nDocumentation:\n{doc}\n\nSource" f" Code:\n{source}" ) - print(input_content) # Process with OpenAI model (assuming the model's __call__ method takes this input and returns processed content) processed_content = model( TEST_WRITER_SOP_PROMPT( - input_content, "swarms", "swarms.tokenizers" + input_content, "swarms", "swarms.memory" ) ) processed_content = extract_code_from_markdown(processed_content) @@ -74,7 +77,7 @@ def create_test(cls): doc_content = f"# {cls.__name__}\n\n{processed_content}\n" # Create the directory if it doesn't exist - dir_path = "tests/tokenizers" + dir_path = "tests/memory" os.makedirs(dir_path, exist_ok=True) # Write the processed documentation to a Python file @@ -85,13 +88,9 @@ def create_test(cls): def main(): classes = [ - SentencePieceTokenizer, - HuggingFaceTokenizer, - Tokenizer, - BaseTokenizer, - OpenAITokenizer, - AnthropicTokenizer, - CohereTokenizer, + DictInternalMemory, + DictSharedMemory, + LangchainChromaVectorMemory, ] threads = [] for cls in classes: @@ -103,7 +102,7 @@ def main(): for thread in threads: thread.join() - print("Tests generated in 'tests/tokenizers' directory.") + print("Tests generated in 'tests/memory' directory.") if __name__ == "__main__": diff --git a/scripts/auto_tests_docs/mkdocs_handler.py b/scripts/auto_tests_docs/mkdocs_handler.py index a61defa8..8b1dc0a0 100644 --- a/scripts/auto_tests_docs/mkdocs_handler.py +++ b/scripts/auto_tests_docs/mkdocs_handler.py @@ -28,4 +28,4 @@ def generate_file_list(directory, output_file): # Use the function to generate the file list -generate_file_list("docs/swarms/tokenizers", "file_list.txt") +generate_file_list("docs/swarms/structs", "file_list.txt") diff --git a/scripts/auto_tests_docs/update_mkdocs.py b/scripts/auto_tests_docs/update_mkdocs.py index dfde53cb..d169a15f 100644 --- a/scripts/auto_tests_docs/update_mkdocs.py +++ b/scripts/auto_tests_docs/update_mkdocs.py @@ -14,7 +14,7 @@ def update_mkdocs( - base_path: The base path where documentation Markdown files are stored. - mkdocs_file: The path to the mkdocs.yml file. """ - with open(mkdocs_file, "r") as file: + with open(mkdocs_file) as file: mkdocs_config = yaml.safe_load(file) # Find or create the 'zeta.nn.modules' section in 'nav' diff --git a/scripts/get_package_requirements.py b/scripts/get_package_requirements.py index 9494409b..99e139da 100644 --- a/scripts/get_package_requirements.py +++ b/scripts/get_package_requirements.py @@ -3,7 +3,7 @@ import pkg_resources def get_package_versions(requirements_path, output_path): try: - with open(requirements_path, "r") as file: + with open(requirements_path) as file: requirements = file.readlines() except FileNotFoundError: print(f"Error: The file '{requirements_path}' was not found.") diff --git a/scripts/requirementstxt_to_pyproject.py b/scripts/requirementstxt_to_pyproject.py index 5710db61..811ac7be 100644 --- a/scripts/requirementstxt_to_pyproject.py +++ b/scripts/requirementstxt_to_pyproject.py @@ -1,10 +1,10 @@ -import toml import pkg_resources +import toml def update_pyproject_versions(pyproject_path): try: - with open(pyproject_path, "r") as file: + with open(pyproject_path) as file: data = toml.load(file) except FileNotFoundError: print(f"Error: The file '{pyproject_path}' was not found.") diff --git a/scripts/rust_scripts/concurrent_exec.rs b/scripts/rust_scripts/concurrent_exec.rs new file mode 100644 index 00000000..e1f23533 --- /dev/null +++ b/scripts/rust_scripts/concurrent_exec.rs @@ -0,0 +1,93 @@ +use pyo3::prelude::*; +use pyo3::wrap_pyfunction; +use pyo3::types::IntoPyDict; +use rayon::{ThreadPool, ThreadPoolBuilder}; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, Instant}; +use std::thread; + + +#[pymodule] +fn rust_module(py: Python, m: &PyModule) -> PyResult<()> { + m.add_function(wrap_pyfunction!(concurrent_exec, m)?)?; + Ok(()) +} + +/// This function wraps Python code in Rust concurrency for ultra high performance. +/// +/// # Arguments +/// +/// * `py_codes` - A vector of string slices that holds the Python codes to be executed. +/// * `timeout` - An optional duration to specify a timeout for the Python code execution. +/// * `num_threads` - The number of threads to use for executing the Python code. +/// * `error_handler` - A function to handle errors during Python code execution. +/// * `log_function` - A function to log the execution of the Python code. +/// * `result_handler` - A function to handle the results of the Python code execution. +/// +/// # Example +/// +/// ``` +/// let py_codes = vec!["print('Hello, World!')", "print('Hello, Rust!')"]; +/// let timeout = Some(Duration::from_secs(5)); +/// let num_threads = 4; +/// let error_handler = |e| eprintln!("Error: {}", e); +/// let log_function = |s| println!("Log: {}", s); +/// let result_handler = |r| println!("Result: {:?}", r); +/// execute_python_codes(py_codes, timeout, num_threads, error_handler, log_function, result_handler); +/// ``` + +#[pyfunction] +pub fn concurrent_exec( + py_codes: Vec<&str>, + timeout: Option, + num_threads: usize, + error_handler: F, + log_function: G, + result_handler: H, +) -> PyResult>> +where + F: Fn(&str), + G: Fn(&str), + H: Fn(&PyResult<()>), +{ + let gil = Python::acquire_gil(); + let py = gil.python(); + let py_codes = Arc::new(Mutex::new(py_codes)); + let results = Arc::new(Mutex::new(Vec::new())); + let pool = ThreadPool::new(num_threads); + + pool.install(|| { + py_codes.par_iter().for_each(|code| { + let locals = [("__name__", "__main__")].into_py_dict(py); + let globals = [("__name__", "__main__")].into_py_dict(py); + + log_function(&format!("Executing Python code: {}", code)); + let result = py.run(code, Some(globals), Some(locals)); + + match timeout { + Some(t) => { + let now = Instant::now(); + let timeout_thread = thread::spawn(move || { + while now.elapsed() < t { + if let Ok(_) = result { + break; + } + } + if now.elapsed() >= t { + error_handler(&format!("Python code execution timed out: {}", code)); + } + }); + + timeout_thread.join().unwrap(); + } + None => {} + } + + results.lock().unwrap().push(result.clone(result)); + result_handler(&result); + }); + }); + + pool.join(); + Ok(results.lock().unwrap().clone()) +} \ No newline at end of file diff --git a/scripts/rust_scripts/cuda_wrapper.rs b/scripts/rust_scripts/cuda_wrapper.rs new file mode 100644 index 00000000..7516088b --- /dev/null +++ b/scripts/rust_scripts/cuda_wrapper.rs @@ -0,0 +1,71 @@ +use pyo3::prelude::*; +use rustacuda::prelude::*; +use rustacuda::memory::DeviceBox; +use std::error::Error; +use std::ffi::CString; + +#[pymodule] +fn rust_cuda(_py: Python, m: &PyModule) -> PyResult<()> { + #[pyfn(m, "execute_on_device")] + fn execute_on_device(py: Python, device_id: u32, a: f32, b: f32) -> PyResult { + /// The result of executing the CUDA operation. + let result = py.allow_threads(|| { + execute_cuda(device_id, a, b) + }); + match result { + Ok(res) => Ok(res), + Err(err) => Err(PyErr::new::(format!("{}", err))), + } + } + Ok(()) +} + +fn execute_cuda(device_id: u32, a: f32, b: f32) -> Result> { + rustacuda::init(CudaFlags::empty())?; + let device = Device::get_device(device_id)?; + /// Creates a new CUDA context and pushes it onto the current thread's stack. + /// + /// # Arguments + /// + /// * `flags` - The flags to be used when creating the context. + /// * `device` - The device on which the context will be created. + /// + /// # Returns + /// + /// The newly created CUDA context. + /// + /// # Errors + /// + /// Returns an error if the context creation fails. + /// + /// # Example + /// + /// ```rust + /// use swarms::cuda_wrapper::Context; + /// + /// let device = 0; + /// let context = Context::create_and_push(ContextFlags::MAP_HOST | ContextFlags::SCHED_AUTO, device)?; + /// ``` + pub fn create_and_push(flags: ContextFlags, device: i32) -> Result { + // implementation goes here + } + let context = Context::create_and_push(ContextFlags::MAP_HOST | ContextFlags::SCHED_AUTO, device)?; + let module_data = CString::new(include_str!("../resources/add.ptx"))?; + let module = Module::load_from_string(&module_data)?; + let stream = Stream::new(StreamFlags::NON_BLOCKING, None)?; + let mut x = DeviceBox::new(&a)?; + let mut y = DeviceBox::new(&b)?; + let mut result = DeviceBox::new(&0.0f32)?; + unsafe { + launch!(module.sum<<<1, 1, 0, stream>>>( + x.as_device_ptr(), + y.as_device_ptr(), + result.as_device_ptr(), + 1 + ))?; + } + stream.synchronize()?; + let mut result_host = 0.0f32; + result.copy_to(&mut result_host)?; + Ok(result_host) +} \ No newline at end of file diff --git a/scripts/rust_scripts/file_utils.rs b/scripts/rust_scripts/file_utils.rs new file mode 100644 index 00000000..62d8ccb0 --- /dev/null +++ b/scripts/rust_scripts/file_utils.rs @@ -0,0 +1,37 @@ +use std::fs::File; +use std::io::prelude::*; +use std::time::Instant; +use std::io::{BufReader, io}; +use ranyon::prelude::{IntoParallelRefIterator, ParallelIterator}; + +fn read_file(path: &str) -> Vec { + /// Reads the contents of a file located at the specified path. + /// + /// # Arguments + /// + /// * `path` - The path to the file. + /// + /// # Returns + /// + /// A `Result` containing a vector of strings representing the lines of the file if the file was successfully read, + /// or an `io::Error` if there was an error reading the file. + /// + /// # Example + /// + /// ``` + /// use std::io; + /// use std::fs::File; + /// use std::io::BufReader; + /// + /// fn read_file(path: &str) -> io::Result> { + /// let contents: io::Result> = BufReader::new(File::open(path).expect("Could not open file")) + /// .lines() + /// .collect(); + /// contents + /// } + /// ``` + let contents: io::Result> = BufReader::new(File::open(path).expect("Could not open file")) + .lines() + .collect(); + return contents.expect("Could not read file"); +} \ No newline at end of file diff --git a/scripts/rust_scripts/multi_threading.rs b/scripts/rust_scripts/multi_threading.rs new file mode 100644 index 00000000..0e75606f --- /dev/null +++ b/scripts/rust_scripts/multi_threading.rs @@ -0,0 +1,113 @@ +/// This module provides a multi-threading processor for executing Python modules and functions in parallel. +/// It utilizes the `rayon` crate for parallel processing and the `pyo3` crate for interacting with the Python interpreter. +/// The `multithreading_processor` function takes a vector of `PythonModule` structs and the number of threads to use. +/// Each `PythonModule` struct contains the name of the Python module, the name of the function to call, and any arguments to pass to the function. +/// The function imports the Python module, calls the specified function, and sends any errors encountered back to the main thread. +/// If an import error occurs, a `PythonError::ImportError` is returned. +/// If a function call error occurs, a `PythonError::FunctionError` is returned. + +use pyo3::prelude::*; +use pyo3::wrap_pyfunction; +use rayon::prelude::*; +use std::sync::mpsc::{channel, Sender}; +use std::sync::{Arc, Mutex}; +use log::{info, error}; + +struct PythonModule<'a> { + name: &'a str, + function: &'a str, +} + +enum PythonError { + ImportError(String), + FunctionError(String), +} + +#[pyfunction] +fn my_module(py: Python, m: &PyModule) -> PyResult<()> { + m.add_function(wrap_pyfunction!(process_python_modules, m)?)?; + Ok(()) +} + + + +/// The function returns `Ok(())` if all modules are processed successfully. +/// Note: This code assumes that the necessary dependencies (`pyo3`, `rayon`, `log`) are already imported and initialized. +/// +/// # Arguments +/// +/// * `modules` - A vector of `PythonModule` structs representing the Python modules and functions to execute. +/// * `num_threads` - The number of threads to use for parallel processing. +/// +/// # Examples +/// +/// ``` +/// use pyo3::types::PyModule; +/// use pyo3::types::PyResult; +/// use pyo3::prelude::*; +/// +/// struct PythonModule<'a> { +/// name: &'a str, +/// function: &'a str, +/// args: Vec<&'a str>, +/// } +/// +/// #[pymodule] +/// fn multithreading_processor(modules: Vec, num_threads: usize) -> Result<(), PythonError> { +/// // Function implementation +/// Ok(()) +/// } +/// ``` +/// +/// # Errors +/// +/// Returns a `PythonError` if an import error or a function call error occurs. +/// +/// # Panics +/// +/// This function does not panic. +/// +/// # Safety +/// +/// This function is safe to call, but it assumes that the necessary dependencies (`pyo3`, `rayon`, `log`) are already imported and initialized. +// Initialize Python interpreter +#[pyfunction] +fn process_python_modules(modules: Vec, num_threads: usize) -> Result<(), PythonError> { + + let gil = Python::acquire_gil(); + let py = gil.python(); + + // Set the global thread pool's configuration + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build_global() + .unwrap(); + + // Create a channel to send errors from threads to the main thread + let (tx, rx) = channel(); + let tx = Arc::new(Mutex::new(tx)); + + // Process each Python module in parallel + modules.par_iter().for_each(|module| { + let result = PyModule::import(py, module.name) + .map_err(|_| PythonError::ImportError(module.name.to_string())) + .and_then(|m| m.call0(module.function) + .map_err(|_| PythonError::FunctionError(module.function.to_string()))); + + if let Err(e) = result { + let tx = tx.lock().unwrap(); + tx.send(e).unwrap(); + } + }); + + // Check for errors + drop(tx); // Close the sender + for error in rx { + match error { + PythonError::ImportError(module) => error!("Failed to import module {}", module), + PythonError::FunctionError(function) => error!("Failed to call function {}", function), + } + } + + Ok(()) +} \ No newline at end of file diff --git a/sequential_workflow_with_agents.py b/sequential_workflow_with_agents.py new file mode 100644 index 00000000..06f071db --- /dev/null +++ b/sequential_workflow_with_agents.py @@ -0,0 +1,36 @@ +from swarms import Agent, OpenAIChat, SequentialWorkflow + +# Example usage +llm = OpenAIChat( + temperature=0.5, + max_tokens=3000, +) + +# Initialize the Agent with the language agent +agent1 = Agent( + agent_name="John the writer", + llm=llm, + max_loops=1, + dashboard=False, +) + + +# Create another Agent for a different task +agent2 = Agent("Summarizer", llm=llm, max_loops=1, dashboard=False) + + +# Create the workflow +workflow = SequentialWorkflow( + name="Blog Generation Workflow", + description=( + "Generate a youtube transcript on how to deploy agents into" + " production" + ), + max_loops=1, + autosave=True, + dashboard=False, + agents=[agent1, agent2], +) + +# Run the workflow +workflow.run() diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 00000000..50781398 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,59 @@ +use pyo3::prelude::*; +use pyo3::types::PyList; +use rayon::prelude::*; +use std::fs; +use std::time::Instant; + +// Define the new execute function +fn exec_concurrently(script_path: &str, threads: usize) -> PyResult<()> { + (0..threads).into_par_iter().for_each(|_| { + Python::with_gil(|py| { + let sys = py.import("sys").unwrap(); + let path: &PyList = match sys.getattr("path") { + Ok(path) => match path.downcast() { + Ok(path) => path, + Err(e) => { + eprintln!("Failed to downcast path: {:?}", e); + return; + } + }, + Err(e) => { + eprintln!("Failed to get path attribute: {:?}", e); + return; + } + }; + + if let Err(e) = path.append("lib/python3.11/site-packages") { + eprintln!("Failed to append path: {:?}", e); + } + + let script = fs::read_to_string(script_path).unwrap(); + py.run(&script, None, None).unwrap(); + }); + }); + Ok(()) +} + +fn main() -> PyResult<()> { + let args: Vec = std::env::args().collect(); + let threads = 20; + + if args.len() < 2 { + eprintln!("Usage: {} ", args[0]); + std::process::exit(1); + } + let script_path = &args[1]; + + let start = Instant::now(); + + // Call the execute function + exec_concurrently(script_path, threads)?; + + let duration = start.elapsed(); + match fs::write("/tmp/elapsed.time", format!("booting time: {:?}", duration)) { + Ok(_) => println!("Successfully wrote elapsed time to /tmp/elapsed.time"), + Err(e) => eprintln!("Failed to write elapsed time: {:?}", e), + } + + Ok(()) +} diff --git a/swarms/__init__.py b/swarms/__init__.py index d88d9bf8..66063891 100644 --- a/swarms/__init__.py +++ b/swarms/__init__.py @@ -5,12 +5,13 @@ bootup() from swarms.agents import * # noqa: E402, F403 -from swarms.structs import * # noqa: E402, F403 +from swarms.artifacts import * # noqa: E402, F403 +from swarms.chunkers import * # noqa: E402, F403 +from swarms.loaders import * # noqa: E402, F403 from swarms.models import * # noqa: E402, F403 -from swarms.telemetry import * # noqa: E402, F403 -from swarms.utils import * # noqa: E402, F403 from swarms.prompts import * # noqa: E402, F403 +from swarms.structs import * # noqa: E402, F403 +from swarms.telemetry import * # noqa: E402, F403 from swarms.tokenizers import * # noqa: E402, F403 -from swarms.loaders import * # noqa: E402, F403 -from swarms.artifacts import * # noqa: E402, F403 -from swarms.chunkers import * # noqa: E402, F403 +from swarms.tools import * # noqa: E402, F403 +from swarms.utils import * # noqa: E402, F403 diff --git a/swarms/agents/__init__.py b/swarms/agents/__init__.py index 461baa16..b213748e 100644 --- a/swarms/agents/__init__.py +++ b/swarms/agents/__init__.py @@ -1,3 +1,4 @@ +from swarms.agents.agent_wrapper import agent_wrapper from swarms.agents.base import AbstractAgent from swarms.agents.omni_modal_agent import OmniModalAgent from swarms.agents.simple_agent import SimpleAgent @@ -15,7 +16,6 @@ from swarms.agents.stopping_conditions import ( ) from swarms.agents.tool_agent import ToolAgent from swarms.agents.worker_agent import Worker -from swarms.agents.agent_wrapper import agent_wrapper __all__ = [ "AbstractAgent", diff --git a/swarms/agents/base.py b/swarms/agents/base.py index 22c0addc..08cf07bf 100644 --- a/swarms/agents/base.py +++ b/swarms/agents/base.py @@ -37,7 +37,6 @@ class AbstractAgent: def memory(self, memory_store): """init memory""" - pass def reset(self): """(Abstract method) Reset the agent.""" diff --git a/swarms/agents/developer_agents.py b/swarms/agents/developer_agents.py new file mode 100644 index 00000000..4392af03 --- /dev/null +++ b/swarms/agents/developer_agents.py @@ -0,0 +1,136 @@ +from swarms.prompts.documentation import DOCUMENTATION_WRITER_SOP +from swarms.prompts.tests import TEST_WRITER_SOP_PROMPT +from swarms.structs.agent import Agent + + +class UnitTesterAgent: + """ + This class represents a unit testing agent responsible for generating unit tests for the swarms package. + + Attributes: + - llm: The low-level model used by the agent. + - agent_name (str): The name of the agent. + - agent_description (str): The description of the agent. + - max_loops (int): The maximum number of loops the agent can run. + - SOP_PROMPT: The system output prompt used by the agent. + - agent: The underlying agent object used for running tasks. + + Methods: + - run(task: str, *args, **kwargs) -> str: Run the agent with the given task and return the response. + """ + + def __init__( + self, + llm, + agent_name: str = "Unit Testing Agent", + agent_description: str = "This agent is responsible for generating unit tests for the swarms package.", + max_loops: int = 1, + sop: str = None, + module: str = None, + path: str = None, + autosave: bool = True, + *args, + **kwargs, + ): + super().__init__() + self.llm = llm + self.agent_name = agent_name + self.agent_description = agent_description + self.max_loops = max_loops + self.sop = sop + self.module = module + self.path = path + self.autosave = autosave + + self.agent = Agent( + llm=llm, + agent_name=agent_name, + agent_description=agent_description, + autosave=self.autosave, + system_prompt=agent_description, + max_loops=max_loops, + *args, + **kwargs, + ) + + def run(self, task: str, module: str, path: str, *args, **kwargs): + """ + Run the agent with the given task. + + Args: + - task (str): The task to run the agent with. + + Returns: + - str: The response from the agent. + """ + return self.agent.run( + TEST_WRITER_SOP_PROMPT(task, self.module, self.path), + *args, + **kwargs, + ) + + +class DocumentorAgent: + """ + This class represents a documentor agent responsible for generating unit tests for the swarms package. + + Attributes: + - llm: The low-level model used by the agent. + - agent_name (str): The name of the agent. + - agent_description (str): The description of the agent. + - max_loops (int): The maximum number of loops the agent can run. + - SOP_PROMPT: The system output prompt used by the agent. + - agent: The underlying agent object used for running tasks. + + Methods: + - run(task: str, *args, **kwargs) -> str: Run the agent with the given task and return the response. + """ + + def __init__( + self, + llm, + agent_name: str = "Documentor Agent", + agent_description: str = "This agent is responsible for generating unit tests for the swarms package.", + max_loops: int = 1, + sop: str = None, + module: str = None, + path: str = None, + autosave: bool = True, + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + self.llm = llm + self.agent_name = agent_name + self.agent_description = agent_description + self.max_loops = max_loops + self.sop = sop + self.module = module + self.path = path + self.autosave = autosave + + self.agent = Agent( + llm=llm, + agent_name=agent_name, + agent_description=agent_description, + autosave=self.autosave, + system_prompt=agent_description, + max_loops=max_loops, + *args, + **kwargs, + ) + + def run(self, task: str, module: str, path: str, *args, **kwargs): + """ + Run the agent with the given task. + + Args: + - task (str): The task to run the agent with. + + Returns: + - str: The response from the agent. + """ + return self.agent.run( + DOCUMENTATION_WRITER_SOP(task, self.module) * args, + **kwargs, + ) diff --git a/swarms/agents/multion_agent.py b/swarms/agents/multion_agent.py new file mode 100644 index 00000000..efeb5a43 --- /dev/null +++ b/swarms/agents/multion_agent.py @@ -0,0 +1,70 @@ +import os + +import multion +from dotenv import load_dotenv + +from swarms.models.base_llm import AbstractLLM + +# Load environment variables +load_dotenv() + +# Muliton key +MULTION_API_KEY = os.getenv("MULTION_API_KEY") + + +class MultiOnAgent(AbstractLLM): + """ + Represents a multi-on agent that performs browsing tasks. + + Args: + max_steps (int): The maximum number of steps to perform during browsing. + starting_url (str): The starting URL for browsing. + + Attributes: + max_steps (int): The maximum number of steps to perform during browsing. + starting_url (str): The starting URL for browsing. + """ + + def __init__( + self, + multion_api_key: str = MULTION_API_KEY, + max_steps: int = 4, + starting_url: str = "https://www.google.com", + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + self.multion_api_key = multion_api_key + self.max_steps = max_steps + self.starting_url = starting_url + + def run(self, task: str, *args, **kwargs): + """ + Runs a browsing task. + + Args: + task (str): The task to perform during browsing. + *args: Additional positional arguments. + **kwargs: Additional keyword arguments. + + Returns: + dict: The response from the browsing task. + """ + multion.login( + use_api=True, + multion_api_key=str(self.multion_api_key), + *args, + **kwargs, + ) + + response = multion.browse( + { + "cmd": task, + "url": self.starting_url, + "maxSteps": self.max_steps, + }, + *args, + **kwargs, + ) + + return response.result, response.status, response.lastUrl diff --git a/swarms/agents/omni_modal_agent.py b/swarms/agents/omni_modal_agent.py index 113ec461..8f2dabc5 100644 --- a/swarms/agents/omni_modal_agent.py +++ b/swarms/agents/omni_modal_agent.py @@ -142,5 +142,4 @@ class OmniModalAgent: print(token) """ - for token in response.split(): - yield token + yield from response.split() diff --git a/swarms/agents/simple_agent.py b/swarms/agents/simple_agent.py index 757715dd..ba67933c 100644 --- a/swarms/agents/simple_agent.py +++ b/swarms/agents/simple_agent.py @@ -1,9 +1,10 @@ -from swarms.structs.conversation import Conversation -from swarms.models.base_llm import AbstractLLM -from typing import Any import importlib import pkgutil +from typing import Any + import swarms.models +from swarms.models.base_llm import AbstractLLM +from swarms.structs.conversation import Conversation def get_llm_by_name(name: str): diff --git a/swarms/agents/worker_agent.py b/swarms/agents/worker_agent.py index d254acef..c0e7f464 100644 --- a/swarms/agents/worker_agent.py +++ b/swarms/agents/worker_agent.py @@ -1,5 +1,5 @@ import os -from typing import Any, List +from typing import List import faiss from langchain.docstore import InMemoryDocstore @@ -7,6 +7,7 @@ from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import FAISS from langchain_experimental.autonomous_agents import AutoGPT +from swarms.tools.tool import BaseTool from swarms.utils.decorators import error_decorator, timing_decorator @@ -48,7 +49,7 @@ class Worker: temperature: float = 0.5, llm=None, openai_api_key: str = None, - tools: List[Any] = None, + tools: List[BaseTool] = None, embedding_size: int = 1536, search_kwargs: dict = {"k": 8}, verbose: bool = False, @@ -165,7 +166,7 @@ class Worker: # @log_decorator @error_decorator @timing_decorator - def run(self, task: str = None, img=None, *args, **kwargs): + def run(self, task: str = None, *args, **kwargs): """ Run the autonomous agent on a given task. @@ -195,7 +196,7 @@ class Worker: - `results`: The results of the agent's processing. """ try: - results = self.run(task, *args, **kwargs) - return results + result = self.agent.run([task], *args, **kwargs) + return result except Exception as error: raise RuntimeError(f"Error while running agent: {error}") diff --git a/swarms/artifacts/base_artifact.py b/swarms/artifacts/base_artifact.py index 3edf7ad3..aad07a7b 100644 --- a/swarms/artifacts/base_artifact.py +++ b/swarms/artifacts/base_artifact.py @@ -1,9 +1,10 @@ from __future__ import annotations -from typing import Any + import json import uuid from abc import ABC, abstractmethod from dataclasses import dataclass +from typing import Any @dataclass diff --git a/swarms/artifacts/text_artifact.py b/swarms/artifacts/text_artifact.py index e800ad51..5fdfe4fa 100644 --- a/swarms/artifacts/text_artifact.py +++ b/swarms/artifacts/text_artifact.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import Optional + from dataclasses import dataclass, field + from swarms.artifacts.base_artifact import BaseArtifact from swarms.tokenizers.base_tokenizer import BaseTokenizer @@ -33,7 +34,7 @@ class TextArtifact(BaseArtifact): _embedding: list[float] = field(default_factory=list) @property - def embedding(self) -> Optional[list[float]]: + def embedding(self) -> list[float] | None: return None if len(self._embedding) == 0 else self._embedding def __add__(self, other: BaseArtifact) -> TextArtifact: @@ -42,7 +43,7 @@ class TextArtifact(BaseArtifact): def __bool__(self) -> bool: return bool(self.value.strip()) - def generate_embedding(self, model) -> Optional[list[float]]: + def generate_embedding(self, model) -> list[float] | None: self._embedding.clear() self._embedding.extend(model.embed_string(str(self.value))) diff --git a/swarms/chunkers/__init__.py b/swarms/chunkers/__init__.py index ccc8814e..b55d15c2 100644 --- a/swarms/chunkers/__init__.py +++ b/swarms/chunkers/__init__.py @@ -1,5 +1,5 @@ -from swarms.chunkers.chunk_seperator import ChunkSeparator from swarms.chunkers.base_chunker import BaseChunker +from swarms.chunkers.chunk_seperator import ChunkSeparator from swarms.chunkers.text_chunker import TextChunker __all__ = ["ChunkSeparator", "BaseChunker", "TextChunker"] diff --git a/swarms/chunkers/base_chunker.py b/swarms/chunkers/base_chunker.py index a63b3ac7..47f73a4e 100644 --- a/swarms/chunkers/base_chunker.py +++ b/swarms/chunkers/base_chunker.py @@ -1,7 +1,8 @@ from __future__ import annotations + from abc import ABC -from typing import Optional from dataclasses import dataclass, field + from swarms.artifacts.text_artifact import TextArtifact from swarms.chunkers.chunk_seperator import ChunkSeparator from swarms.tokenizers.base_tokenizer import BaseTokenizer @@ -47,7 +48,7 @@ class BaseChunker(ABC): def _chunk_recursively( self, chunk: str, - current_separator: Optional[ChunkSeparator] = None, + current_separator: ChunkSeparator | None = None, ) -> list[str]: """ Recursively chunk the given chunk into smaller subchunks. diff --git a/swarms/cli/_cli.py b/swarms/cli/_cli.py index 9b1365ae..831f1718 100644 --- a/swarms/cli/_cli.py +++ b/swarms/cli/_cli.py @@ -1,4 +1,5 @@ import argparse + from swarms.agents.simple_agent import SimpleAgent, get_llm_by_name diff --git a/swarms/cli/run_file.py b/swarms/cli/run_file.py index 171c6c56..60b621a3 100644 --- a/swarms/cli/run_file.py +++ b/swarms/cli/run_file.py @@ -1,5 +1,5 @@ -import sys import subprocess +import sys def run_file(filename: str): diff --git a/swarms/loaders/pdf_loader.py b/swarms/loaders/pdf_loader.py deleted file mode 100644 index f3db1448..00000000 --- a/swarms/loaders/pdf_loader.py +++ /dev/null @@ -1,77 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from pathlib import Path -from typing import IO, Dict, List, Optional - -from PyPDF2 import PdfReader - -from swarms.utils.hash import str_to_hash - - -@dataclass -class TextArtifact: - text: str - - -@dataclass -class PDFLoader: - """ - A class for loading PDF files and extracting text artifacts. - - Args: - tokenizer (str): The tokenizer to use for chunking the text. - max_tokens (int): The maximum number of tokens per chunk. - - Methods: - load(source, password=None, *args, **kwargs): - Load a single PDF file and extract text artifacts. - - load_collection(sources, password=None, *args, **kwargs): - Load a collection of PDF files and extract text artifacts. - - Private Methods: - _load_pdf(stream, password=None): - Load a PDF file and extract text artifacts. - - Attributes: - tokenizer (str): The tokenizer used for chunking the text. - max_tokens (int): The maximum number of tokens per chunk. - """ - - tokenizer: str - max_tokens: int - - def __post_init__(self): - self.chunker = PdfChunker( - tokenizer=self.tokenizer, max_tokens=self.max_tokens - ) - - def load( - self, - source: str | IO | Path, - password: Optional[str] = None, - *args, - **kwargs, - ) -> List[TextArtifact]: - return self._load_pdf(source, password) - - def load_collection( - self, - sources: List[str | IO | Path], - password: Optional[str] = None, - *args, - **kwargs, - ) -> Dict[str, List[TextArtifact]]: - return { - str_to_hash(str(s)): self._load_pdf(s, password) - for s in sources - } - - def _load_pdf( - self, stream: str | IO | Path, password: Optional[str] - ) -> List[TextArtifact]: - reader = PdfReader(stream, strict=True, password=password) - return [ - TextArtifact(text=p.extract_text()) for p in reader.pages - ] diff --git a/swarms/memory/__init__.py b/swarms/memory/__init__.py index 2dca8172..72318d28 100644 --- a/swarms/memory/__init__.py +++ b/swarms/memory/__init__.py @@ -1,11 +1,14 @@ -from swarms.memory.base_vectordb import AbstractVectorDatabase +from swarms.memory.action_subtask import ActionSubtaskEntry from swarms.memory.base_db import AbstractDatabase +from swarms.memory.base_vectordb import AbstractVectorDatabase +from swarms.memory.chroma_db import ChromaDB +from swarms.memory.dict_internal_memory import DictInternalMemory +from swarms.memory.dict_shared_memory import DictSharedMemory +from swarms.memory.lanchain_chroma import LangchainChromaVectorMemory from swarms.memory.short_term_memory import ShortTermMemory from swarms.memory.sqlite import SQLiteDB -from swarms.memory.weaviate_db import WeaviateDB from swarms.memory.visual_memory import VisualShortTermMemory -from swarms.memory.action_subtask import ActionSubtaskEntry -from swarms.memory.chroma_db import ChromaDB +from swarms.memory.weaviate_db import WeaviateDB __all__ = [ "AbstractVectorDatabase", @@ -16,4 +19,7 @@ __all__ = [ "VisualShortTermMemory", "ActionSubtaskEntry", "ChromaDB", + "DictInternalMemory", + "DictSharedMemory", + "LangchainChromaVectorMemory", ] diff --git a/swarms/memory/base_db.py b/swarms/memory/base_db.py index 0501def7..eb3e6f00 100644 --- a/swarms/memory/base_db.py +++ b/swarms/memory/base_db.py @@ -21,8 +21,6 @@ class AbstractDatabase(ABC): """ - pass - @abstractmethod def close(self): """ @@ -32,8 +30,6 @@ class AbstractDatabase(ABC): """ - pass - @abstractmethod def execute_query(self, query): """ @@ -46,8 +42,6 @@ class AbstractDatabase(ABC): """ - pass - @abstractmethod def fetch_all(self): """ @@ -60,8 +54,6 @@ class AbstractDatabase(ABC): """ - pass - @abstractmethod def fetch_one(self): """ @@ -74,8 +66,6 @@ class AbstractDatabase(ABC): """ - pass - @abstractmethod def add(self, table, data): """ @@ -89,8 +79,6 @@ class AbstractDatabase(ABC): """ - pass - @abstractmethod def query(self, table, condition): """ @@ -107,8 +95,6 @@ class AbstractDatabase(ABC): """ - pass - @abstractmethod def get(self, table, id): """ @@ -125,8 +111,6 @@ class AbstractDatabase(ABC): """ - pass - @abstractmethod def update(self, table, id, data): """ @@ -141,8 +125,6 @@ class AbstractDatabase(ABC): """ - pass - @abstractmethod def delete(self, table, id): """ @@ -155,5 +137,3 @@ class AbstractDatabase(ABC): id (int): The ID of the record to be deleted. """ - - pass diff --git a/swarms/memory/base_vectordb.py b/swarms/memory/base_vectordb.py index 06f42007..6b34d244 100644 --- a/swarms/memory/base_vectordb.py +++ b/swarms/memory/base_vectordb.py @@ -21,8 +21,6 @@ class AbstractVectorDatabase(ABC): """ - pass - @abstractmethod def close(self): """ @@ -32,8 +30,6 @@ class AbstractVectorDatabase(ABC): """ - pass - @abstractmethod def query(self, query: str): """ @@ -46,8 +42,6 @@ class AbstractVectorDatabase(ABC): """ - pass - @abstractmethod def fetch_all(self): """ @@ -60,8 +54,6 @@ class AbstractVectorDatabase(ABC): """ - pass - @abstractmethod def fetch_one(self): """ @@ -74,8 +66,6 @@ class AbstractVectorDatabase(ABC): """ - pass - @abstractmethod def add(self, doc: str): """ @@ -89,8 +79,6 @@ class AbstractVectorDatabase(ABC): """ - pass - @abstractmethod def get(self, query: str): """ @@ -107,8 +95,6 @@ class AbstractVectorDatabase(ABC): """ - pass - @abstractmethod def update(self, doc): """ @@ -123,8 +109,6 @@ class AbstractVectorDatabase(ABC): """ - pass - @abstractmethod def delete(self, message): """ @@ -137,5 +121,3 @@ class AbstractVectorDatabase(ABC): id (int): The ID of the record to be deleted. """ - - pass diff --git a/swarms/memory/chroma_db.py b/swarms/memory/chroma_db.py index 4418e90d..dcb0e19f 100644 --- a/swarms/memory/chroma_db.py +++ b/swarms/memory/chroma_db.py @@ -1,20 +1,15 @@ -import os -import numpy as np import logging +import os import uuid -from typing import Optional, Callable, List +from typing import Callable, List, Optional import chromadb +import numpy as np from dotenv import load_dotenv -# from chromadb.utils.data import ImageLoader -from chromadb.utils.embedding_functions import ( - OpenCLIPEmbeddingFunction, -) from swarms.utils.data_to_text import data_to_text from swarms.utils.markdown_message import display_markdown_message - # Load environment variables load_dotenv() @@ -47,8 +42,8 @@ class ChromaDB: def __init__( self, - metric: str, - output_dir: str, + metric: str = "cosine", + output_dir: str = "swarms", limit_tokens: Optional[int] = 1000, n_results: int = 2, embedding_function: Callable = None, @@ -94,7 +89,7 @@ class ChromaDB: # If multimodal set the embedding model to OpenCLIP if multimodal: - self.embedding_function = OpenCLIPEmbeddingFunction() + self.embedding_function = None # Create ChromaDB client self.client = chromadb.Client() diff --git a/swarms/memory/cosine_similarity.py b/swarms/memory/cosine_similarity.py index 6e7b1df3..94c5e585 100644 --- a/swarms/memory/cosine_similarity.py +++ b/swarms/memory/cosine_similarity.py @@ -1,4 +1,5 @@ """Math utils.""" + import logging from typing import List, Optional, Tuple, Union diff --git a/swarms/memory/dict_internal_memory.py b/swarms/memory/dict_internal_memory.py new file mode 100644 index 00000000..daba0b0d --- /dev/null +++ b/swarms/memory/dict_internal_memory.py @@ -0,0 +1,86 @@ +import uuid +from abc import ABC, abstractmethod +from typing import Any, Dict, List, Tuple + + +class InternalMemoryBase(ABC): + """Abstract base class for internal memory of agents in the swarm.""" + + def __init__(self, n_entries): + """Initialize the internal memory. In the current architecture the memory always consists of a set of soltuions or evaluations. + During the operation, the agent should retrivie best solutions from it's internal memory based on the score. + + Moreover, the project is designed around LLMs for the proof of concepts, so we treat all entry content as a string. + """ + self.n_entries = n_entries + + @abstractmethod + def add(self, score, entry): + """Add an entry to the internal memory.""" + raise NotImplementedError + + @abstractmethod + def get_top_n(self, n): + """Get the top n entries from the internal memory.""" + raise NotImplementedError + + +class DictInternalMemory(InternalMemoryBase): + def __init__(self, n_entries: int): + """ + Initialize the internal memory. In the current architecture the memory always consists of a set of solutions or evaluations. + Simple key-value store for now. + + Args: + n_entries (int): The maximum number of entries to keep in the internal memory. + """ + super().__init__(n_entries) + self.data: Dict[str, Dict[str, Any]] = {} + + def add(self, score: float, content: Any) -> None: + """ + Add an entry to the internal memory. + + Args: + score (float): The score or fitness value associated with the entry. + content (Any): The content of the entry. + + Returns: + None + """ + random_key: str = str(uuid.uuid4()) + self.data[random_key] = {"score": score, "content": content} + + # keep only the best n entries + sorted_data: List[Tuple[str, Dict[str, Any]]] = sorted( + self.data.items(), + key=lambda x: x[1]["score"], + reverse=True, + ) + self.data = dict(sorted_data[: self.n_entries]) + + def get_top_n(self, n: int) -> List[Tuple[str, Dict[str, Any]]]: + """ + Get the top n entries from the internal memory. + + Args: + n (int): The number of top entries to retrieve. + + Returns: + List[Tuple[str, Dict[str, Any]]]: A list of tuples containing the random keys and corresponding entry data. + """ + sorted_data: List[Tuple[str, Dict[str, Any]]] = sorted( + self.data.items(), + key=lambda x: x[1]["score"], + reverse=True, + ) + return sorted_data[:n] + + def len(self) -> int: + """ + Get the number of entries in the internal memory. + + Returns: + int: The number of entries in the internal memory. + """ + return len(self.data) diff --git a/swarms/memory/dict_shared_memory.py b/swarms/memory/dict_shared_memory.py new file mode 100644 index 00000000..f81e2fd4 --- /dev/null +++ b/swarms/memory/dict_shared_memory.py @@ -0,0 +1,98 @@ +import datetime +import json +import os +import threading +import uuid +from pathlib import Path +from typing import Any, Dict + + +class DictSharedMemory: + """A class representing a shared memory that stores entries as a dictionary. + + Attributes: + file_loc (Path): The file location where the memory is stored. + lock (threading.Lock): A lock used for thread synchronization. + + Methods: + __init__(self, file_loc: str = None) -> None: Initializes the shared memory. + add_entry(self, score: float, agent_id: str, agent_cycle: int, entry: Any) -> bool: Adds an entry to the internal memory. + get_top_n(self, n: int) -> None: Gets the top n entries from the internal memory. + write_to_file(self, data: Dict[str, Dict[str, Any]]) -> bool: Writes the internal memory to a file. + """ + + def __init__(self, file_loc: str = None) -> None: + """Initialize the shared memory. In the current architecture the memory always consists of a set of soltuions or evaluations. + Moreover, the project is designed around LLMs for the proof of concepts, so we treat all entry content as a string. + """ + if file_loc is not None: + self.file_loc = Path(file_loc) + if not self.file_loc.exists(): + self.file_loc.touch() + + self.lock = threading.Lock() + + def add( + self, + score: float, + agent_id: str, + agent_cycle: int, + entry: Any, + ) -> bool: + """Add an entry to the internal memory.""" + with self.lock: + entry_id = str(uuid.uuid4()) + data = {} + epoch = datetime.datetime.utcfromtimestamp(0) + epoch = ( + datetime.datetime.utcnow() - epoch + ).total_seconds() + data[entry_id] = { + "agent": agent_id, + "epoch": epoch, + "score": score, + "cycle": agent_cycle, + "content": entry, + } + status = self.write_to_file(data) + self.plot_performance() + return status + + def get_top_n(self, n: int) -> None: + """Get the top n entries from the internal memory.""" + with self.lock: + with open(self.file_loc) as f: + try: + file_data = json.load(f) + except Exception as e: + file_data = {} + raise e + + sorted_data = dict( + sorted( + file_data.items(), + key=lambda item: item[1]["score"], + reverse=True, + ) + ) + top_n = dict(list(sorted_data.items())[:n]) + return top_n + + def write_to_file(self, data: Dict[str, Dict[str, Any]]) -> bool: + """Write the internal memory to a file.""" + if self.file_loc is not None: + with open(self.file_loc) as f: + try: + file_data = json.load(f) + except Exception as e: + file_data = {} + raise e + + file_data = file_data | data + with open(self.file_loc, "w") as f: + json.dump(file_data, f, indent=4) + + f.flush() + os.fsync(f.fileno()) + + return True diff --git a/swarms/memory/lanchain_chroma.py b/swarms/memory/lanchain_chroma.py new file mode 100644 index 00000000..95a2e9e3 --- /dev/null +++ b/swarms/memory/lanchain_chroma.py @@ -0,0 +1,196 @@ +import threading +from pathlib import Path + +from langchain.chains import RetrievalQA +from langchain.chains.question_answering import load_qa_chain +from langchain.embeddings.openai import OpenAIEmbeddings +from langchain.text_splitter import CharacterTextSplitter +from langchain.vectorstores import Chroma + +from swarms.models.openai_models import OpenAIChat + + +def synchronized_mem(method): + """ + Decorator that synchronizes access to a method using a lock. + + Args: + method: The method to be decorated. + + Returns: + The decorated method. + """ + + def wrapper(self, *args, **kwargs): + with self.lock: + try: + return method(self, *args, **kwargs) + except Exception as e: + print(f"Failed to execute {method.__name__}: {e}") + + return wrapper + + +class LangchainChromaVectorMemory: + """ + A class representing a vector memory for storing and retrieving text entries. + + Attributes: + loc (str): The location of the vector memory. + chunk_size (int): The size of each text chunk. + chunk_overlap_frac (float): The fraction of overlap between text chunks. + embeddings (OpenAIEmbeddings): The embeddings used for text representation. + count (int): The current count of text entries in the vector memory. + lock (threading.Lock): A lock for thread safety. + db (Chroma): The Chroma database for storing text entries. + qa (RetrievalQA): The retrieval QA system for answering questions. + + Methods: + __init__: Initializes the VectorMemory object. + _init_db: Initializes the Chroma database. + _init_retriever: Initializes the retrieval QA system. + add_entry: Adds an entry to the vector memory. + search_memory: Searches the vector memory for similar entries. + ask_question: Asks a question to the vector memory. + """ + + def __init__( + self, + loc=None, + chunk_size: int = 1000, + chunk_overlap_frac: float = 0.1, + *args, + **kwargs, + ): + """ + Initializes the VectorMemory object. + + Args: + loc (str): The location of the vector memory. If None, defaults to "./tmp/vector_memory". + chunk_size (int): The size of each text chunk. + chunk_overlap_frac (float): The fraction of overlap between text chunks. + """ + if loc is None: + loc = "./tmp/vector_memory" + self.loc = Path(loc) + self.chunk_size = chunk_size + self.chunk_overlap = chunk_size * chunk_overlap_frac + self.embeddings = OpenAIEmbeddings() + self.count = 0 + self.lock = threading.Lock() + + self.db = self._init_db() + self.qa = self._init_retriever() + + def _init_db(self): + """ + Initializes the Chroma database. + + Returns: + Chroma: The initialized Chroma database. + """ + texts = [ + "init" + ] # TODO find how to initialize Chroma without any text + chroma_db = Chroma.from_texts( + texts=texts, + embedding=self.embeddings, + persist_directory=str(self.loc), + ) + self.count = chroma_db._collection.count() + return chroma_db + + def _init_retriever(self): + """ + Initializes the retrieval QA system. + + Returns: + RetrievalQA: The initialized retrieval QA system. + """ + model = OpenAIChat( + model_name="gpt-3.5-turbo", + ) + qa_chain = load_qa_chain(model, chain_type="stuff") + retriever = self.db.as_retriever( + search_type="mmr", search_kwargs={"k": 10} + ) + qa = RetrievalQA( + combine_documents_chain=qa_chain, retriever=retriever + ) + return qa + + @synchronized_mem + def add(self, entry: str): + """ + Add an entry to the internal memory. + + Args: + entry (str): The entry to be added. + + Returns: + bool: True if the entry was successfully added, False otherwise. + """ + text_splitter = CharacterTextSplitter( + chunk_size=self.chunk_size, + chunk_overlap=self.chunk_overlap, + separator=" ", + ) + texts = text_splitter.split_text(entry) + + self.db.add_texts(texts) + self.count += self.db._collection.count() + self.db.persist() + return True + + @synchronized_mem + def search_memory( + self, query: str, k=10, type="mmr", distance_threshold=0.5 + ): + """ + Searching the vector memory for similar entries. + + Args: + query (str): The query to search for. + k (int): The number of results to return. + type (str): The type of search to perform: "cos" or "mmr". + distance_threshold (float): The similarity threshold to use for the search. Results with distance > similarity_threshold will be dropped. + + Returns: + list[str]: A list of the top k results. + """ + self.count = self.db._collection.count() + if k > self.count: + k = self.count - 1 + if k <= 0: + return None + + if type == "mmr": + texts = self.db.max_marginal_relevance_search( + query=query, k=k, fetch_k=min(20, self.count) + ) + texts = [text.page_content for text in texts] + elif type == "cos": + texts = self.db.similarity_search_with_score( + query=query, k=k + ) + texts = [ + text[0].page_content + for text in texts + if text[-1] < distance_threshold + ] + + return texts + + @synchronized_mem + def query(self, question: str): + """ + Ask a question to the vector memory. + + Args: + question (str): The question to ask. + + Returns: + str: The answer to the question. + """ + answer = self.qa.run(question) + return answer diff --git a/swarms/memory/pg.py b/swarms/memory/pg.py index d96b475d..b04beacf 100644 --- a/swarms/memory/pg.py +++ b/swarms/memory/pg.py @@ -1,5 +1,6 @@ import uuid from typing import Any, List, Optional + from sqlalchemy import JSON, Column, String, create_engine from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.ext.declarative import declarative_base diff --git a/swarms/memory/pinecone.py b/swarms/memory/pinecone.py index b1c0edf3..d33cb9cd 100644 --- a/swarms/memory/pinecone.py +++ b/swarms/memory/pinecone.py @@ -1,7 +1,9 @@ from typing import Optional -from swarms.memory.base_vectordb import AbstractVectorDatabase + import pinecone from attr import define, field + +from swarms.memory.base_vectordb import AbstractVectorDatabase from swarms.utils.hash import str_to_hash diff --git a/swarms/memory/short_term_memory.py b/swarms/memory/short_term_memory.py index d380fba5..34e32d5d 100644 --- a/swarms/memory/short_term_memory.py +++ b/swarms/memory/short_term_memory.py @@ -1,7 +1,8 @@ +import json import logging -from swarms.structs.base import BaseStructure import threading -import json + +from swarms.structs.base import BaseStructure class ShortTermMemory(BaseStructure): @@ -181,7 +182,7 @@ class ShortTermMemory(BaseStructure): """ try: with self.lock: - with open(filename, "r") as f: + with open(filename) as f: data = json.load(f) self.short_term_memory = data.get( "short_term_memory", [] diff --git a/swarms/memory/sqlite.py b/swarms/memory/sqlite.py index 542be34b..7a391303 100644 --- a/swarms/memory/sqlite.py +++ b/swarms/memory/sqlite.py @@ -1,4 +1,5 @@ -from typing import List, Tuple, Any, Optional +from typing import Any, List, Optional, Tuple + from swarms.memory.base_vectordb import AbstractVectorDatabase try: diff --git a/swarms/memory/utils.py b/swarms/memory/utils.py index 42801237..4dbbff80 100644 --- a/swarms/memory/utils.py +++ b/swarms/memory/utils.py @@ -5,8 +5,8 @@ from typing import List, Tuple, Type import numpy as np -from swarms.structs.document import Document from swarms.memory.cosine_similarity import cosine_similarity +from swarms.structs.document import Document class DistanceStrategy(str, Enum): diff --git a/swarms/memory/visual_memory.py b/swarms/memory/visual_memory.py index 46a59509..1361d6ec 100644 --- a/swarms/memory/visual_memory.py +++ b/swarms/memory/visual_memory.py @@ -1,5 +1,5 @@ -from typing import List from datetime import datetime +from typing import List class VisualShortTermMemory: diff --git a/swarms/models/__init__.py b/swarms/models/__init__.py index 00d9d1f2..3f8fb3e2 100644 --- a/swarms/models/__init__.py +++ b/swarms/models/__init__.py @@ -1,87 +1,73 @@ -############################################ LLMs -from swarms.models.base_llm import AbstractLLM # noqa: E402 from swarms.models.anthropic import Anthropic # noqa: E402 -from swarms.models.petals import Petals # noqa: E402 -from swarms.models.mistral import Mistral # noqa: E402 -from swarms.models.openai_models import ( - OpenAI, - AzureOpenAI, - OpenAIChat, -) # noqa: E402 +from swarms.models.base_embedding_model import BaseEmbeddingModel +from swarms.models.base_llm import AbstractLLM # noqa: E402 +from swarms.models.base_multimodal_model import BaseMultiModalModel -# from swarms.models.vllm import vLLM # noqa: E402 -from swarms.models.zephyr import Zephyr # noqa: E402 +# noqa: E402 from swarms.models.biogpt import BioGPT # noqa: E402 -from swarms.models.huggingface import HuggingfaceLLM # noqa: E402 -from swarms.models.wizard_storytelling import ( - WizardLLMStoryTeller, -) # noqa: E402 -from swarms.models.mpt import MPT7B # noqa: E402 -from swarms.models.mixtral import Mixtral # noqa: E402 - -# from swarms.models.modelscope_pipeline import ModelScopePipeline -# from swarms.models.modelscope_llm import ( -# ModelScopeAutoModel, -# ) # noqa: E402 -from swarms.models.together import TogetherLLM # noqa: E402 - -################# MultiModal Models -from swarms.models.base_multimodal_model import ( - BaseMultiModalModel, -) # noqa: E402 -from swarms.models.idefics import Idefics # noqa: E402 -from swarms.models.vilt import Vilt # noqa: E402 -from swarms.models.nougat import Nougat # noqa: E402 -from swarms.models.layoutlm_document_qa import ( - LayoutLMDocumentQA, -) # noqa: E402 -from swarms.models.gpt4_vision_api import GPT4VisionAPI # noqa: E402 -from swarms.models.openai_tts import OpenAITTS # noqa: E402 -from swarms.models.gemini import Gemini # noqa: E402 -from swarms.models.gigabind import Gigabind # noqa: E402 -from swarms.models.zeroscope import ZeroscopeTTV # noqa: E402 -from swarms.models.timm import TimmModel # noqa: E402 -from swarms.models.ultralytics_model import ( - UltralyticsModel, -) # noqa: E402 - -# from swarms.models.vip_llava import VipLlavaMultiModal # noqa: E402 -from swarms.models.llava import LavaMultiModal # noqa: E402 -from swarms.models.qwen import QwenVLMultiModal # noqa: E402 from swarms.models.clipq import CLIPQ # noqa: E402 -from swarms.models.kosmos_two import Kosmos # noqa: E402 -from swarms.models.fuyu import Fuyu # noqa: E402 -from swarms.models.roboflow_model import RoboflowMultiModal -from swarms.models.sam_supervision import SegmentAnythingMarkGenerator # from swarms.models.dalle3 import Dalle3 # from swarms.models.distilled_whisperx import DistilWhisperModel # noqa: E402 # from swarms.models.whisperx_model import WhisperX # noqa: E402 # from swarms.models.kosmos_two import Kosmos # noqa: E402 # from swarms.models.cog_agent import CogAgent # noqa: E402 +## Function calling models +from swarms.models.fire_function import FireFunctionCaller +from swarms.models.fuyu import Fuyu # noqa: E402 +from swarms.models.gemini import Gemini # noqa: E402 +from swarms.models.gigabind import Gigabind # noqa: E402 +from swarms.models.gpt4_vision_api import GPT4VisionAPI # noqa: E402 +from swarms.models.huggingface import HuggingfaceLLM # noqa: E402 +from swarms.models.idefics import Idefics # noqa: E402 +from swarms.models.kosmos_two import Kosmos # noqa: E402 +from swarms.models.layoutlm_document_qa import LayoutLMDocumentQA +# noqa: E402 +from swarms.models.llava import LavaMultiModal # noqa: E402 +from swarms.models.mistral import Mistral # noqa: E402 +from swarms.models.mixtral import Mixtral # noqa: E402 +from swarms.models.mpt import MPT7B # noqa: E402 +from swarms.models.nougat import Nougat # noqa: E402 +from swarms.models.openai_models import ( + AzureOpenAI, + OpenAI, + OpenAIChat, +) -################# Tokenizers +# noqa: E402 +from swarms.models.openai_tts import OpenAITTS # noqa: E402 +from swarms.models.petals import Petals # noqa: E402 +from swarms.models.qwen import QwenVLMultiModal # noqa: E402 +from swarms.models.roboflow_model import RoboflowMultiModal +from swarms.models.sam_supervision import SegmentAnythingMarkGenerator +from swarms.models.sampling_params import SamplingParams, SamplingType +from swarms.models.timm import TimmModel # noqa: E402 +# from swarms.models.modelscope_pipeline import ModelScopePipeline +# from swarms.models.modelscope_llm import ( +# ModelScopeAutoModel, +# ) # noqa: E402 +from swarms.models.together import TogetherLLM # noqa: E402 ############## Types -from swarms.models.types import ( - TextModality, - ImageModality, +from swarms.models.types import ( # noqa: E402 AudioModality, - VideoModality, + ImageModality, MultimodalData, -) # noqa: E402 - -# 3############ Embedding models -from swarms.models.base_embedding_model import BaseEmbeddingModel + TextModality, + VideoModality, +) +from swarms.models.ultralytics_model import UltralyticsModel +# noqa: E402 +from swarms.models.vilt import Vilt # noqa: E402 +from swarms.models.wizard_storytelling import WizardLLMStoryTeller -##### Utils -from swarms.models.sampling_params import ( - SamplingType, - SamplingParams, -) # noqa: E402 +# noqa: E402 +# from swarms.models.vllm import vLLM # noqa: E402 +from swarms.models.zephyr import Zephyr # noqa: E402 +from swarms.models.zeroscope import ZeroscopeTTV # noqa: E402 __all__ = [ "AbstractLLM", @@ -101,7 +87,6 @@ __all__ = [ "HuggingfaceLLM", "MPT7B", "WizardLLMStoryTeller", - # "GPT4Vision", # "Dalle3", # "DistilWhisperModel", "GPT4VisionAPI", @@ -119,7 +104,6 @@ __all__ = [ "TogetherLLM", "TimmModel", "UltralyticsModel", - # "VipLlavaMultiModal", "LavaMultiModal", "QwenVLMultiModal", "CLIPQ", @@ -130,4 +114,5 @@ __all__ = [ "SegmentAnythingMarkGenerator", "SamplingType", "SamplingParams", + "FireFunctionCaller", ] diff --git a/swarms/models/anthropic.py b/swarms/models/anthropic.py index 0e4690f9..5292f202 100644 --- a/swarms/models/anthropic.py +++ b/swarms/models/anthropic.py @@ -24,14 +24,12 @@ from langchain.callbacks.manager import ( CallbackManagerForLLMRun, ) from langchain.llms.base import LLM -from pydantic import Field, SecretStr, root_validator from langchain.schema.language_model import BaseLanguageModel from langchain.schema.output import GenerationChunk from langchain.schema.prompt import PromptValue -from langchain.utils import ( - get_from_dict_or_env, -) +from langchain.utils import get_from_dict_or_env from packaging.version import parse +from pydantic import Field, SecretStr, root_validator from requests import HTTPError, Response diff --git a/swarms/models/azure_openai_llm.py b/swarms/models/azure_openai_llm.py new file mode 100644 index 00000000..aebb03fb --- /dev/null +++ b/swarms/models/azure_openai_llm.py @@ -0,0 +1,223 @@ +from __future__ import annotations + +import logging +import os +from typing import Any, Callable, Mapping + +import openai +from langchain_core.pydantic_v1 import ( + Field, + SecretStr, + root_validator, +) +from langchain_core.utils import ( + convert_to_secret_str, + get_from_dict_or_env, +) +from langchain_openai.llms.base import BaseOpenAI + +logger = logging.getLogger(__name__) + + +class AzureOpenAI(BaseOpenAI): + """Azure-specific OpenAI large language models. + + To use, you should have the ``openai`` python package installed, and the + environment variable ``OPENAI_API_KEY`` set with your API key. + + Any parameters that are valid to be passed to the openai.create call can be passed + in, even if not explicitly saved on this class. + + Example: + .. code-block:: python + + from swarms import AzureOpenAI + + openai = AzureOpenAI(model_name="gpt-3.5-turbo-instruct") + """ + + azure_endpoint: str | None = None + """Your Azure endpoint, including the resource. + + Automatically inferred from env var `AZURE_OPENAI_ENDPOINT` if not provided. + + Example: `https://example-resource.azure.openai.com/` + """ + deployment_name: str | None = Field( + default=None, alias="azure_deployment" + ) + """A model deployment. + + If given sets the base client URL to include `/deployments/{azure_deployment}`. + Note: this means you won't be able to use non-deployment endpoints. + """ + openai_api_version: str = Field(default="", alias="api_version") + """Automatically inferred from env var `OPENAI_API_VERSION` if not provided.""" + openai_api_key: SecretStr | None = Field( + default=None, alias="api_key" + ) + """Automatically inferred from env var `AZURE_OPENAI_API_KEY` if not provided.""" + azure_ad_token: SecretStr | None = None + """Your Azure Active Directory token. + + Automatically inferred from env var `AZURE_OPENAI_AD_TOKEN` if not provided. + + For more: + https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id. + """ # noqa: E501 + azure_ad_token_provider: Callable[[], str] | None = None + """A function that returns an Azure Active Directory token. + + Will be invoked on every request. + """ + openai_api_type: str = "" + """Legacy, for openai<1.0.0 support.""" + validate_base_url: bool = True + """For backwards compatibility. If legacy val openai_api_base is passed in, try to + infer if it is a base_url or azure_endpoint and update accordingly. + """ + + @classmethod + def get_lc_namespace(cls) -> list[str]: + """Get the namespace of the langchain object.""" + return ["langchain", "llms", "openai"] + + @root_validator() + def validate_environment(cls, values: dict) -> dict: + """Validate that api key and python package exists in environment.""" + if values["n"] < 1: + raise ValueError("n must be at least 1.") + if values["streaming"] and values["n"] > 1: + raise ValueError("Cannot stream results when n > 1.") + if values["streaming"] and values["best_of"] > 1: + raise ValueError( + "Cannot stream results when best_of > 1." + ) + + # Check OPENAI_KEY for backwards compatibility. + # TODO: Remove OPENAI_API_KEY support to avoid possible conflict when using + # other forms of azure credentials. + openai_api_key = ( + values["openai_api_key"] + or os.getenv("AZURE_OPENAI_API_KEY") + or os.getenv("OPENAI_API_KEY") + ) + values["openai_api_key"] = ( + convert_to_secret_str(openai_api_key) + if openai_api_key + else None + ) + + values["azure_endpoint"] = values[ + "azure_endpoint" + ] or os.getenv("AZURE_OPENAI_ENDPOINT") + azure_ad_token = values["azure_ad_token"] or os.getenv( + "AZURE_OPENAI_AD_TOKEN" + ) + values["azure_ad_token"] = ( + convert_to_secret_str(azure_ad_token) + if azure_ad_token + else None + ) + values["openai_api_base"] = values[ + "openai_api_base" + ] or os.getenv("OPENAI_API_BASE") + values["openai_proxy"] = get_from_dict_or_env( + values, + "openai_proxy", + "OPENAI_PROXY", + default="", + ) + values["openai_organization"] = ( + values["openai_organization"] + or os.getenv("OPENAI_ORG_ID") + or os.getenv("OPENAI_ORGANIZATION") + ) + values["openai_api_version"] = values[ + "openai_api_version" + ] or os.getenv("OPENAI_API_VERSION") + values["openai_api_type"] = get_from_dict_or_env( + values, + "openai_api_type", + "OPENAI_API_TYPE", + default="azure", + ) + # For backwards compatibility. Before openai v1, no distinction was made + # between azure_endpoint and base_url (openai_api_base). + openai_api_base = values["openai_api_base"] + if openai_api_base and values["validate_base_url"]: + if "/openai" not in openai_api_base: + values["openai_api_base"] = ( + values["openai_api_base"].rstrip("/") + "/openai" + ) + raise ValueError( + "As of openai>=1.0.0, Azure endpoints should be" + " specified via the `azure_endpoint` param not" + " `openai_api_base` (or alias `base_url`)." + ) + if values["deployment_name"]: + raise ValueError( + "As of openai>=1.0.0, if `deployment_name` (or" + " alias `azure_deployment`) is specified then" + " `openai_api_base` (or alias `base_url`) should" + " not be. Instead use `deployment_name` (or alias" + " `azure_deployment`) and `azure_endpoint`." + ) + values["deployment_name"] = None + client_params = { + "api_version": values["openai_api_version"], + "azure_endpoint": values["azure_endpoint"], + "azure_deployment": values["deployment_name"], + "api_key": ( + values["openai_api_key"].get_secret_value() + if values["openai_api_key"] + else None + ), + "azure_ad_token": ( + values["azure_ad_token"].get_secret_value() + if values["azure_ad_token"] + else None + ), + "azure_ad_token_provider": values[ + "azure_ad_token_provider" + ], + "organization": values["openai_organization"], + "base_url": values["openai_api_base"], + "timeout": values["request_timeout"], + "max_retries": values["max_retries"], + "default_headers": values["default_headers"], + "default_query": values["default_query"], + "http_client": values["http_client"], + } + values["client"] = openai.AzureOpenAI( + **client_params + ).completions + values["async_client"] = openai.AsyncAzureOpenAI( + **client_params + ).completions + + return values + + @property + def _identifying_params(self) -> Mapping[str, Any]: + return { + **{"deployment_name": self.deployment_name}, + **super()._identifying_params, + } + + @property + def _invocation_params(self) -> dict[str, Any]: + openai_params = {"model": self.deployment_name} + return {**openai_params, **super()._invocation_params} + + @property + def _llm_type(self) -> str: + """Return type of llm.""" + return "azure" + + @property + def lc_attributes(self) -> dict[str, Any]: + return { + "openai_api_type": self.openai_api_type, + "openai_api_version": self.openai_api_version, + } diff --git a/swarms/models/base_embedding_model.py b/swarms/models/base_embedding_model.py index 218e52aa..4cdead11 100644 --- a/swarms/models/base_embedding_model.py +++ b/swarms/models/base_embedding_model.py @@ -2,15 +2,14 @@ from __future__ import annotations from abc import ABC, abstractmethod from dataclasses import dataclass, field -from typing import Optional import numpy as np -from swarms.chunkers.base_chunker import BaseChunker -from swarms.chunkers.text_chunker import TextChunker -from swarms.utils.exponential_backoff import ExponentialBackoffMixin from swarms.artifacts.text_artifact import TextArtifact +from swarms.chunkers.base_chunker import BaseChunker +from swarms.chunkers.text_chunker import TextChunker from swarms.tokenizers.base_tokenizer import BaseTokenizer +from swarms.utils.exponential_backoff import ExponentialBackoffMixin @dataclass @@ -26,7 +25,7 @@ class BaseEmbeddingModel( """ model: str = None - tokenizer: Optional[BaseTokenizer] = None + tokenizer: BaseTokenizer | None = None chunker: BaseChunker = field(init=False) def __post_init__(self) -> None: diff --git a/swarms/models/base_llm.py b/swarms/models/base_llm.py index bc1f67c7..d69f21a8 100644 --- a/swarms/models/base_llm.py +++ b/swarms/models/base_llm.py @@ -123,7 +123,6 @@ class AbstractLLM(ABC): @metrics_decorator def run(self, task: Optional[str] = None, *args, **kwargs) -> str: """generate text using language model""" - pass async def arun(self, task: Optional[str] = None, *args, **kwargs): """Asynchronous run @@ -190,7 +189,6 @@ class AbstractLLM(ABC): def generate_summary(self, text: str) -> str: """Generate Summary""" - pass def set_temperature(self, value: float): """Set Temperature""" diff --git a/swarms/models/base_multimodal_model.py b/swarms/models/base_multimodal_model.py index c4a5890a..25975eaa 100644 --- a/swarms/models/base_multimodal_model.py +++ b/swarms/models/base_multimodal_model.py @@ -105,7 +105,6 @@ class BaseMultiModalModel: **kwargs, ): """Run the model""" - pass def __call__( self, @@ -127,7 +126,6 @@ class BaseMultiModalModel: async def arun(self, task: str, img: str, *args, **kwargs): """Run the model asynchronously""" - pass def get_img_from_web(self, img: str, *args, **kwargs): """Get the image from the web""" @@ -294,7 +292,6 @@ class BaseMultiModalModel: @abstractmethod def generate_summary(self, text: str) -> str: """Generate Summary""" - pass def set_temperature(self, value: float): """Set Temperature""" diff --git a/swarms/models/base_tts.py b/swarms/models/base_tts.py index 60896856..402b8501 100644 --- a/swarms/models/base_tts.py +++ b/swarms/models/base_tts.py @@ -1,7 +1,8 @@ import wave +from abc import abstractmethod from typing import Optional + from swarms.models.base_llm import AbstractLLM -from abc import abstractmethod class BaseTTSModel(AbstractLLM): @@ -47,7 +48,6 @@ class BaseTTSModel(AbstractLLM): Args: filepath (Optional[str], optional): _description_. Defaults to None. """ - pass def load(self, filepath: Optional[str] = None): """Load the model from a file. @@ -55,7 +55,6 @@ class BaseTTSModel(AbstractLLM): Args: filepath (Optional[str], optional): _description_. Defaults to None. """ - pass @abstractmethod def run(self, task: str, *args, **kwargs): @@ -64,7 +63,6 @@ class BaseTTSModel(AbstractLLM): Args: task (str): _description_ """ - pass def __call__(self, task: str, *args, **kwargs): """Call the model on the given task. diff --git a/swarms/models/base_ttv.py b/swarms/models/base_ttv.py index 6ef959e8..ee795c26 100644 --- a/swarms/models/base_ttv.py +++ b/swarms/models/base_ttv.py @@ -1,9 +1,11 @@ -from abc import abstractmethod -from swarms.models.base_llm import AbstractLLM -from diffusers.utils import export_to_video -from typing import Optional, List import asyncio +from abc import abstractmethod from concurrent.futures import ThreadPoolExecutor +from typing import List, Optional + +from diffusers.utils import export_to_video + +from swarms.models.base_llm import AbstractLLM class BaseTextToVideo(AbstractLLM): diff --git a/swarms/models/biogpt.py b/swarms/models/biogpt.py index 9ee5b513..a5ec7b7b 100644 --- a/swarms/models/biogpt.py +++ b/swarms/models/biogpt.py @@ -1,4 +1,4 @@ -""" +r""" BioGPT Pre-trained language models have attracted increasing attention in the biomedical domain, inspired by their great success in the general natural language domain. @@ -35,10 +35,10 @@ advantage of BioGPT on biomedical literature to generate fluent descriptions for import torch from transformers import ( + BioGptForCausalLM, + BioGptTokenizer, pipeline, set_seed, - BioGptTokenizer, - BioGptForCausalLM, ) diff --git a/swarms/models/chest_agent.py b/swarms/models/chest_agent.py index 2867596c..7bf4e850 100644 --- a/swarms/models/chest_agent.py +++ b/swarms/models/chest_agent.py @@ -1,4 +1,5 @@ import io + import requests import torch from PIL import Image @@ -7,6 +8,7 @@ from transformers import ( AutoProcessor, GenerationConfig, ) + from swarms.models.base_multimodal_model import ( BaseMultiModalModel, ) # noqa: F401 diff --git a/swarms/models/clipq.py b/swarms/models/clipq.py index 7e49e74a..e6d587c9 100644 --- a/swarms/models/clipq.py +++ b/swarms/models/clipq.py @@ -8,19 +8,16 @@ from transformers import CLIPModel, CLIPProcessor class CLIPQ: - """ - ClipQ is an CLIQ based model that can be used to generate captions for images. - - - Attributes: - model_name (str): The name of the model to be used. - query_text (str): The query text to be used for the model. + """CLIPQ model for image and text retrieval Args: - model_name (str): The name of the model to be used. - query_text (str): The query text to be used for the model. - + model_name (str): The name of the CLIP model to use + query_text (str): The query text to use for the model + Example: + >>> clipq = CLIPQ() + >>> image = clipq.fetch_image_from_url() + >>> vectors = clipq.get_vectors(image) """ diff --git a/swarms/models/cog_agent.py b/swarms/models/cog_agent.py index 2d0d09e9..35217c48 100644 --- a/swarms/models/cog_agent.py +++ b/swarms/models/cog_agent.py @@ -1,6 +1,7 @@ import torch -from PIL import Image from modelscope import AutoModelForCausalLM, AutoTokenizer +from PIL import Image + from swarms.models.base_multimodal_model import BaseMultiModalModel device_check = "cuda" if torch.cuda.is_available() else "cpu" diff --git a/swarms/models/cog_vlm.py b/swarms/models/cog_vlm.py new file mode 100644 index 00000000..a3f820c5 --- /dev/null +++ b/swarms/models/cog_vlm.py @@ -0,0 +1,528 @@ +import base64 +import os +import time +from io import BytesIO +from typing import List, Literal, Optional, Tuple, Union + +import torch +from PIL import Image +from pydantic import BaseModel, Field +from transformers import ( + AutoModelForCausalLM, + LlamaTokenizer, + TextIteratorStreamer, +) + +from swarms.models.base_multimodal_model import BaseMultiModalModel +from swarms.utils.logger import logger + +MODEL_PATH = "THUDM/cogvlm-chat-hf" +TOKENIZER_PATH = "lmsys/vicuna-7b-v1.5" +DEVICE = "cuda" if torch.cuda.is_available() else "cpu" +QUANT_ENABLED = False + + +class ImageUrl(BaseModel): + url: str + + +class TextContent(BaseModel): + type: Literal["text"] + text: str + + +class ImageUrlContent(BaseModel): + type: Literal["image_url"] + image_url: ImageUrl + + +ContentItem = Union[TextContent, ImageUrlContent] + + +class ChatMessageInput(BaseModel): + role: Literal["user", "assistant", "system"] + content: Union[str, List[ContentItem]] + name: Optional[str] = None + + +class ChatMessageResponse(BaseModel): + role: Literal["assistant"] + content: str = None + name: Optional[str] = None + + +class DeltaMessage(BaseModel): + role: Optional[Literal["user", "assistant", "system"]] = None + content: Optional[str] = None + + +class ChatCompletionRequest(BaseModel): + model: str + messages: List[ChatMessageInput] + temperature: Optional[float] = 0.8 + top_p: Optional[float] = 0.8 + max_tokens: Optional[int] = None + stream: Optional[bool] = False + # Additional parameters + repetition_penalty: Optional[float] = 1.0 + + +class ChatCompletionResponseChoice(BaseModel): + index: int + message: ChatMessageResponse + + +class ChatCompletionResponseStreamChoice(BaseModel): + index: int + delta: DeltaMessage + + +class UsageInfo(BaseModel): + prompt_tokens: int = 0 + total_tokens: int = 0 + completion_tokens: Optional[int] = 0 + + +class ChatCompletionResponse(BaseModel): + model: str + object: Literal["chat.completion", "chat.completion.chunk"] + choices: List[ + Union[ + ChatCompletionResponseChoice, + ChatCompletionResponseStreamChoice, + ] + ] + created: Optional[int] = Field( + default_factory=lambda: int(time.time()) + ) + usage: Optional[UsageInfo] = None + + +# async def create_chat_completion(request: ChatCompletionRequest): +# global model, tokenizer + +# gen_params = dict( +# messages=request.messages, +# temperature=request.temperature, +# top_p=request.top_p, +# max_tokens=request.max_tokens or 1024, +# echo=False, +# stream=request.stream, +# ) + +# # if request.stream: +# # predict(request.model, gen_params) +# # response = generate_cogvlm(model, tokenizer, gen_params) + +# usage = UsageInfo() + +# message = ChatMessageResponse( +# role="assistant", +# content=response["text"], +# ) +# logger.debug(f"==== message ====\n{message}") +# choice_data = ChatCompletionResponseChoice( +# index=0, +# message=message, +# ) +# task_usage = UsageInfo.model_validate(response["usage"]) +# for usage_key, usage_value in task_usage.model_dump().items(): +# setattr( +# usage, usage_key, getattr(usage, usage_key) + usage_value +# ) +# return ChatCompletionResponse( +# model=request.model, +# choices=[choice_data], +# object="chat.completion", +# usage=usage, +# ) + + +class CogVLMMultiModal(BaseMultiModalModel): + """ + Initializes the CogVLM model. + + Args: + model_name (str): The path or name of the pre-trained model. + tokenizer (str): The path or name of the tokenizer. + device (str): The device to run the model on. + quantize (bool): Whether to enable quantization. + torch_type (str): The torch data type to use. + temperature (float): The temperature for sampling. + top_p (float): The top-p value for sampling. + max_tokens (int): The maximum number of tokens to generate. + echo (bool): Whether to echo the input text. + stream (bool): Whether to stream the output. + repetition_penalty (float): The repetition penalty for sampling. + do_sample (bool): Whether to use sampling during generation. + *args: Additional positional arguments. + **kwargs: Additional keyword arguments. + + Methods: + run: Generates a response using the CogVLM model. + generate_stream_cogvlm: Generates a stream of responses using the CogVLM model in inference mode. + process_history_and_images: Processes history messages to extract text, identify the last user query, and convert base64 encoded image URLs to PIL images. + + Example: + >>> model = CogVLMMultiModal() + >>> response = model("Describe this image with meticlous details.", "https://example.com/image.jpg") + >>> print(response) + """ + + def __init__( + self, + model_name: str = MODEL_PATH, + tokenizer: str = TOKENIZER_PATH, + device: str = DEVICE, + quantize: bool = QUANT_ENABLED, + torch_type: str = "float16", + temperature: float = 0.5, + top_p: float = 0.9, + max_tokens: int = 3500, + echo: bool = False, + stream: bool = False, + repetition_penalty: float = 1.0, + do_sample: bool = True, + *args, + **kwargs, + ): + super().__init__() + self.model_name = model_name + self.device = device + self.tokenizer = tokenizer + self.device = device + self.quantize = quantize + self.torch_type = torch_type + self.temperature = temperature + self.top_p = top_p + self.max_tokens = max_tokens + self.echo = echo + self.stream = stream + self.repetition_penalty = repetition_penalty + self.do_sample = do_sample + + if os.environ.get("QUANT_ENABLED"): + pass + else: + with torch.cuda.device(device): + __, total_bytes = torch.cuda.mem_get_info() + total_gb = total_bytes / (1 << 30) + if total_gb < 40: + pass + + torch.cuda.empty_cache() + + self.tokenizer = LlamaTokenizer.from_pretrained( + tokenizer, trust_remote_code=True + ) + + if ( + torch.cuda.is_available() + and torch.cuda.get_device_capability()[0] >= 8 + ): + torch_type = torch.bfloat16 + else: + torch_type = torch.float16 + + print( + f"========Use torch type as:{torch_type} with" + f" device:{device}========\n\n" + ) + + if "cuda" in device: + if QUANT_ENABLED: + self.model = AutoModelForCausalLM.from_pretrained( + model_name, + load_in_4bit=True, + trust_remote_code=True, + torch_dtype=torch_type, + low_cpu_mem_usage=True, + *args, + **kwargs, + ).eval() + else: + self.model = ( + AutoModelForCausalLM.from_pretrained( + model_name, + load_in_4bit=False, + trust_remote_code=True, + torch_dtype=torch_type, + low_cpu_mem_usage=True, + *args, + **kwargs, + ) + .to(device) + .eval() + ) + + else: + self.model = ( + AutoModelForCausalLM.from_pretrained( + model_name, + trust_remote_code=True, + *args, + **kwargs, + ) + .float() + .to(device) + .eval() + ) + + def run(self, task: str, img: str, *args, **kwargs): + """ + Generates a response using the CogVLM model. It processes the chat history and image data, if any, + and then invokes the model to generate a response. + """ + messages = [task] + + params = dict( + messages=messages, + temperature=self.temperature, + repitition_penalty=self.repetition_penalty, + top_p=self.top_p, + max_new_tokens=self.max_tokens, + ) + + for response in self.generate_stream_cogvlm(params): + pass + + return response + + @torch.inference_mode() + def generate_stream_cogvlm( + self, + params: dict, + ): + """ + Generates a stream of responses using the CogVLM model in inference mode. + It's optimized to handle continuous input-output interactions with the model in a streaming manner. + """ + messages = params["messages"] + temperature = float(params.get("temperature", 1.0)) + repetition_penalty = float( + params.get("repetition_penalty", 1.0) + ) + top_p = float(params.get("top_p", 1.0)) + max_new_tokens = int(params.get("max_tokens", 256)) + query, history, image_list = self.process_history_and_images( + messages + ) + + logger.debug(f"==== request ====\n{query}") + + input_by_model = self.model.build_conversation_input_ids( + self.tokenizer, + query=query, + history=history, + images=[image_list[-1]], + ) + inputs = { + "input_ids": ( + input_by_model["input_ids"] + .unsqueeze(0) + .to(self.device) + ), + "token_type_ids": ( + input_by_model["token_type_ids"] + .unsqueeze(0) + .to(self.device) + ), + "attention_mask": ( + input_by_model["attention_mask"] + .unsqueeze(0) + .to(self.device) + ), + "images": [ + [ + input_by_model["images"][0] + .to(self.device) + .to(self.torch_type) + ] + ], + } + if ( + "cross_images" in input_by_model + and input_by_model["cross_images"] + ): + inputs["cross_images"] = [ + [ + input_by_model["cross_images"][0] + .to(self.device) + .to(self.torch_type) + ] + ] + + input_echo_len = len(inputs["input_ids"][0]) + streamer = TextIteratorStreamer( + tokenizer=self.tokenizer, + timeout=60.0, + skip_promptb=True, + skip_special_tokens=True, + ) + gen_kwargs = { + "repetition_penalty": repetition_penalty, + "max_new_tokens": max_new_tokens, + "do_sample": True if temperature > 1e-5 else False, + "top_p": top_p if temperature > 1e-5 else 0, + "streamer": streamer, + } + if temperature > 1e-5: + gen_kwargs["temperature"] = temperature + + total_len = 0 + generated_text = "" + with torch.no_grad(): + self.model.generate(**inputs, **gen_kwargs) + for next_text in streamer: + generated_text += next_text + yield { + "text": generated_text, + "usage": { + "prompt_tokens": input_echo_len, + "completion_tokens": ( + total_len - input_echo_len + ), + "total_tokens": total_len, + }, + } + ret = { + "text": generated_text, + "usage": { + "prompt_tokens": input_echo_len, + "completion_tokens": total_len - input_echo_len, + "total_tokens": total_len, + }, + } + yield ret + + def process_history_and_images( + self, + messages: List[ChatMessageInput], + ) -> Tuple[ + Optional[str], + Optional[List[Tuple[str, str]]], + Optional[List[Image.Image]], + ]: + """ + Process history messages to extract text, identify the last user query, + and convert base64 encoded image URLs to PIL images. + + Args: + messages(List[ChatMessageInput]): List of ChatMessageInput objects. + return: A tuple of three elements: + - The last user query as a string. + - Text history formatted as a list of tuples for the model. + - List of PIL Image objects extracted from the messages. + """ + formatted_history = [] + image_list = [] + last_user_query = "" + + for i, message in enumerate(messages): + role = message.role + content = message.content + + # Extract text content + if isinstance(content, list): # text + text_content = " ".join( + item.text + for item in content + if isinstance(item, TextContent) + ) + else: + text_content = content + + # Extract image data + if isinstance(content, list): # image + for item in content: + if isinstance(item, ImageUrlContent): + image_url = item.image_url.url + if image_url.startswith( + "data:image/jpeg;base64," + ): + base64_encoded_image = image_url.split( + "data:image/jpeg;base64," + )[1] + image_data = base64.b64decode( + base64_encoded_image + ) + image = Image.open( + BytesIO(image_data) + ).convert("RGB") + image_list.append(image) + + # Format history + if role == "user": + if i == len(messages) - 1: + last_user_query = text_content + else: + formatted_history.append((text_content, "")) + elif role == "assistant": + if formatted_history: + if formatted_history[-1][1] != "": + raise AssertionError( + "the last query is answered. answer" + f" again. {formatted_history[-1][0]}," + f" {formatted_history[-1][1]}," + f" {text_content}" + ) + formatted_history[-1] = ( + formatted_history[-1][0], + text_content, + ) + else: + raise AssertionError( + "assistant reply before user" + ) + else: + raise AssertionError(f"unrecognized role: {role}") + + return last_user_query, formatted_history, image_list + + async def predict(self, params: dict): + """ + Handle streaming predictions. It continuously generates responses for a given input stream. + This is particularly useful for real-time, continuous interactions with the model. + """ + + choice_data = ChatCompletionResponseStreamChoice( + index=0, + delta=DeltaMessage(role="assistant"), + finish_reason=None, + ) + chunk = ChatCompletionResponse( + model=self.model_name, + choices=[choice_data], + object="chat.completion.chunk", + ) + yield f"{chunk.model_dump_json(exclude_unset=True)}" + + previous_text = "" + for new_response in self.generate_stream_cogvlm(params): + decoded_unicode = new_response["text"] + delta_text = decoded_unicode[len(previous_text) :] + previous_text = decoded_unicode + delta = DeltaMessage( + content=delta_text, + role="assistant", + ) + choice_data = ChatCompletionResponseStreamChoice( + index=0, + delta=delta, + ) + chunk = ChatCompletionResponse( + model=self.model_name, + choices=[choice_data], + object="chat.completion.chunk", + ) + yield f"{chunk.model_dump_json(exclude_unset=True)}" + choice_data = ChatCompletionResponseStreamChoice( + index=0, + delta=DeltaMessage(), + ) + chunk = ChatCompletionResponse( + model=self.model_name, + choices=[choice_data], + object="chat.completion.chunk", + ) + yield f"{chunk.model_dump_json(exclude_unset=True)}" diff --git a/swarms/models/cohere_chat.py b/swarms/models/cohere_chat.py index 1a31d82e..98cc30bb 100644 --- a/swarms/models/cohere_chat.py +++ b/swarms/models/cohere_chat.py @@ -1,14 +1,6 @@ import logging from typing import Any, Callable, Dict, List, Optional -from tenacity import ( - before_sleep_log, - retry, - retry_if_exception_type, - stop_after_attempt, - wait_exponential, -) - from langchain.callbacks.manager import ( AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun, @@ -16,8 +8,15 @@ from langchain.callbacks.manager import ( from langchain.llms.base import LLM from langchain.llms.utils import enforce_stop_tokens from langchain.load.serializable import Serializable -from pydantic import Extra, Field, root_validator from langchain.utils import get_from_dict_or_env +from pydantic import Extra, Field, root_validator +from tenacity import ( + before_sleep_log, + retry, + retry_if_exception_type, + stop_after_attempt, + wait_exponential, +) logger = logging.getLogger(__name__) @@ -35,7 +34,7 @@ def _create_retry_decorator(llm) -> Callable[[Any], Any]: wait=wait_exponential( multiplier=1, min=min_seconds, max=max_seconds ), - retry=(retry_if_exception_type(cohere.error.CohereError)), + retry=retry_if_exception_type(cohere.error.CohereError), before_sleep=before_sleep_log(logger, logging.WARNING), ) diff --git a/swarms/models/embeddings_base.py b/swarms/models/embeddings_base.py index b0f5e22e..e91c415f 100644 --- a/swarms/models/embeddings_base.py +++ b/swarms/models/embeddings_base.py @@ -1,4 +1,5 @@ """Interface for embedding models.""" + from abc import ABC, abstractmethod from typing import List diff --git a/swarms/models/fire_function.py b/swarms/models/fire_function.py new file mode 100644 index 00000000..f61ec2bd --- /dev/null +++ b/swarms/models/fire_function.py @@ -0,0 +1,89 @@ +import json +from typing import Any + +from transformers import AutoModelForCausalLM, AutoTokenizer + +from swarms.models.base_llm import AbstractLLM + + +class FireFunctionCaller(AbstractLLM): + """ + A class that represents a caller for the FireFunction model. + + Args: + model_name (str): The name of the model to be used. + device (str): The device to be used. + function_spec (Any): The specification of the function. + max_tokens (int): The maximum number of tokens. + system_prompt (str): The system prompt. + *args: Variable length argument list. + **kwargs: Arbitrary keyword arguments. + + Methods: + run(self, task: str, *args, **kwargs) -> None: Run the function with the given task and arguments. + + Examples: + >>> fire_function_caller = FireFunctionCaller() + >>> fire_function_caller.run("Add 2 and 3") + """ + + def __init__( + self, + model_name: str = "fireworks-ai/firefunction-v1", + device: str = "cuda", + function_spec: Any = None, + max_tokens: int = 3000, + system_prompt: str = "You are a helpful assistant with access to functions. Use them if required.", + *args, + **kwargs, + ): + super().__init__(model_name, device) + self.model_name = model_name + self.device = device + self.fucntion_spec = function_spec + self.max_tokens = max_tokens + self.system_prompt = system_prompt + + self.model = AutoModelForCausalLM.from_pretrained( + model_name, device_map="auto", *args, **kwargs + ) + self.tokenizer = AutoTokenizer.from_pretrained(model_name) + + self.functions = json.dumps(function_spec, indent=4) + + def run(self, task: str, *args, **kwargs): + """ + Run the function with the given task and arguments. + + Args: + task (str): The task to be performed. + *args: Variable length argument list. + **kwargs: Arbitrary keyword arguments. + + Returns: + None + """ + messages = [ + {"role": "functions", "content": self.functions}, + { + "role": "system", + "content": self.system_prompt, + }, + { + "role": "user", + "content": task, + }, + ] + + model_inputs = self.tokenizer.apply_chat_template( + messages, return_tensors="pt" + ).to(self.model.device) + + generated_ids = self.model.generate( + model_inputs, + max_new_tokens=self.max_tokens, + *args, + **kwargs, + ) + decoded = self.tokenizer.batch_decode(generated_ids) + print(decoded[0]) diff --git a/swarms/models/gemini.py b/swarms/models/gemini.py index d12ea7d9..249e9c53 100644 --- a/swarms/models/gemini.py +++ b/swarms/models/gemini.py @@ -5,7 +5,6 @@ from pathlib import Path from dotenv import load_dotenv from PIL import Image - from swarms.models.base_multimodal_model import BaseMultiModalModel try: diff --git a/swarms/models/gpt4_sam.py b/swarms/models/gpt4_sam.py index aef0181f..37dde6a0 100644 --- a/swarms/models/gpt4_sam.py +++ b/swarms/models/gpt4_sam.py @@ -1,10 +1,11 @@ +from typing import Any + import cv2 from swarms.models.base_multimodal_model import BaseMultiModalModel from swarms.models.sam_supervision import SegmentAnythingMarkGenerator from swarms.utils.supervision_masking import refine_marks from swarms.utils.supervision_visualizer import MarkVisualizer -from typing import Any class GPT4VSAM(BaseMultiModalModel): diff --git a/swarms/models/gpt4_vision_api.py b/swarms/models/gpt4_vision_api.py index 57553bb9..5966a0b6 100644 --- a/swarms/models/gpt4_vision_api.py +++ b/swarms/models/gpt4_vision_api.py @@ -8,6 +8,7 @@ import aiohttp import requests from dotenv import load_dotenv from termcolor import colored + from swarms.models.base_multimodal_model import BaseMultiModalModel try: @@ -298,8 +299,6 @@ class GPT4VisionAPI(BaseMultiModalModel): if self.streaming_enabled: content = self.stream_response(content) - else: - pass if self.beautify: content = colored(content, "cyan") @@ -362,8 +361,6 @@ class GPT4VisionAPI(BaseMultiModalModel): if self.streaming_enabled: content = self.stream_response(content) - else: - pass if self.beautify: content = colored(content, "cyan") diff --git a/swarms/models/huggingface_pipeline.py b/swarms/models/huggingface_pipeline.py index e61d1080..e8d1afb9 100644 --- a/swarms/models/huggingface_pipeline.py +++ b/swarms/models/huggingface_pipeline.py @@ -1,6 +1,7 @@ from abc import abstractmethod -from termcolor import colored + import torch +from termcolor import colored from swarms.models.base_llm import AbstractLLM diff --git a/swarms/models/idefics.py b/swarms/models/idefics.py index b014fbce..cc654221 100644 --- a/swarms/models/idefics.py +++ b/swarms/models/idefics.py @@ -1,8 +1,10 @@ +from typing import Callable, Optional + import torch -from transformers import AutoProcessor, IdeficsForVisionText2Text from termcolor import colored +from transformers import AutoProcessor, IdeficsForVisionText2Text + from swarms.models.base_multimodal_model import BaseMultiModalModel -from typing import Optional, Callable def autodetect_device(): diff --git a/swarms/models/jina_embeds.py b/swarms/models/jina_embeds.py index ea621993..06689752 100644 --- a/swarms/models/jina_embeds.py +++ b/swarms/models/jina_embeds.py @@ -1,5 +1,5 @@ -import os import logging +import os import torch from numpy.linalg import norm @@ -9,6 +9,7 @@ from transformers import ( AutoTokenizer, BitsAndBytesConfig, ) + from swarms.models.base_embedding_model import BaseEmbeddingModel diff --git a/swarms/models/kosmos_two.py b/swarms/models/kosmos_two.py index 6bc4d810..0399f943 100644 --- a/swarms/models/kosmos_two.py +++ b/swarms/models/kosmos_two.py @@ -41,7 +41,7 @@ class Kosmos(BaseMultiModalModel): *args, **kwargs, ): - super(Kosmos, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.max_new_tokens = max_new_tokens diff --git a/swarms/models/layoutlm_document_qa.py b/swarms/models/layoutlm_document_qa.py index ad5b0628..09aa9a1a 100644 --- a/swarms/models/layoutlm_document_qa.py +++ b/swarms/models/layoutlm_document_qa.py @@ -2,7 +2,9 @@ LayoutLMDocumentQA is a multimodal good for visual question answering on real world docs lik invoice, pdfs, etc """ + from transformers import pipeline + from swarms.models.base_multimodal_model import BaseMultiModalModel @@ -29,7 +31,7 @@ class LayoutLMDocumentQA(BaseMultiModalModel): *args, **kwargs, ): - super(LayoutLMDocumentQA, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.model_name = model_name self.task_type = task_type self.pipeline = pipeline(task_type, model=model_name) diff --git a/swarms/models/llama_function_caller.py b/swarms/models/llama_function_caller.py index 78169208..92593377 100644 --- a/swarms/models/llama_function_caller.py +++ b/swarms/models/llama_function_caller.py @@ -3,14 +3,15 @@ # !pip install transformers # !pip install bitsandbytes +from typing import Callable, Dict, List + import torch from transformers import ( - AutoTokenizer, AutoModelForCausalLM, + AutoTokenizer, BitsAndBytesConfig, TextStreamer, ) -from typing import Callable, Dict, List class LlamaFunctionCaller: diff --git a/swarms/models/llava.py b/swarms/models/llava.py index bcc1b09f..5aa4681f 100644 --- a/swarms/models/llava.py +++ b/swarms/models/llava.py @@ -1,8 +1,10 @@ +from io import BytesIO +from typing import Tuple, Union + import requests from PIL import Image from transformers import AutoProcessor, LlavaForConditionalGeneration -from typing import Tuple, Union -from io import BytesIO + from swarms.models.base_multimodal_model import BaseMultiModalModel diff --git a/swarms/models/mistral.py b/swarms/models/mistral.py index 6cfb6f77..dc7ba462 100644 --- a/swarms/models/mistral.py +++ b/swarms/models/mistral.py @@ -1,8 +1,8 @@ import torch from transformers import AutoModelForCausalLM, AutoTokenizer -from swarms.structs.message import Message from swarms.models.base_llm import AbstractLLM +from swarms.structs.message import Message class Mistral(AbstractLLM): diff --git a/swarms/models/mixtral.py b/swarms/models/mixtral.py index 6f3a9c7d..21720845 100644 --- a/swarms/models/mixtral.py +++ b/swarms/models/mixtral.py @@ -1,5 +1,7 @@ from typing import Optional + from transformers import AutoModelForCausalLM, AutoTokenizer + from swarms.models.base_llm import AbstractLLM diff --git a/swarms/models/model_registry.py b/swarms/models/model_registry.py index 6da04282..ee5bab81 100644 --- a/swarms/models/model_registry.py +++ b/swarms/models/model_registry.py @@ -1,5 +1,5 @@ -import pkgutil import inspect +import pkgutil class ModelRegistry: diff --git a/swarms/models/mpt.py b/swarms/models/mpt.py index 56f1bbdb..543e3f41 100644 --- a/swarms/models/mpt.py +++ b/swarms/models/mpt.py @@ -1,6 +1,7 @@ +import logging + import torch from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline -import logging class MPT7B: diff --git a/swarms/models/nougat.py b/swarms/models/nougat.py index 453c6cae..8c95b9c1 100644 --- a/swarms/models/nougat.py +++ b/swarms/models/nougat.py @@ -8,7 +8,9 @@ format - Extracting metadata from pdfs """ + import re + import torch from PIL import Image from transformers import NougatProcessor, VisionEncoderDecoderModel @@ -94,9 +96,7 @@ class Nougat: # Convert the matches to a readable format cleaned_data = [ - "Date: {}, Amount: {}".format( - date, amount.replace(",", "") - ) + f"Date: {date}, Amount: {amount.replace(',', '')}" for date, amount in matches ] diff --git a/swarms/models/odin.py b/swarms/models/odin.py index 6a842af4..68bfaffd 100644 --- a/swarms/models/odin.py +++ b/swarms/models/odin.py @@ -1,7 +1,9 @@ import os + import supervision as sv -from ultralytics_example import YOLO from tqdm import tqdm +from ultralytics_example import YOLO + from swarms.models.base_llm import AbstractLLM from swarms.utils.download_weights_from_url import ( download_weights_from_url, @@ -34,7 +36,7 @@ class Odin(AbstractLLM): confidence_threshold: float = 0.3, iou_threshold: float = 0.7, ): - super(Odin, self).__init__() + super().__init__() self.source_weights_path = source_weights_path self.confidence_threshold = confidence_threshold self.iou_threshold = iou_threshold diff --git a/swarms/models/open_dalle.py b/swarms/models/open_dalle.py index b43d6c2e..57e8846b 100644 --- a/swarms/models/open_dalle.py +++ b/swarms/models/open_dalle.py @@ -1,7 +1,8 @@ -from typing import Optional, Any +from typing import Any, Optional import torch from diffusers import AutoPipelineForText2Image + from swarms.models.base_multimodal_model import BaseMultiModalModel diff --git a/swarms/models/openai_embeddings.py b/swarms/models/openai_embeddings.py index 0cbbdbee..c8151bdb 100644 --- a/swarms/models/openai_embeddings.py +++ b/swarms/models/openai_embeddings.py @@ -2,18 +2,7 @@ from __future__ import annotations import logging import warnings -from typing import ( - Any, - Callable, - Dict, - List, - Literal, - Optional, - Sequence, - Set, - Tuple, - Union, -) +from typing import Any, Callable, Literal, Sequence import numpy as np from pydantic import BaseModel, Extra, Field, root_validator @@ -25,6 +14,7 @@ from tenacity import ( stop_after_attempt, wait_exponential, ) + from swarms.models.embeddings_base import Embeddings @@ -36,7 +26,7 @@ def get_from_dict_or_env( return values.get(key) or os.getenv(env_key) or default -def get_pydantic_field_names(cls: Any) -> Set[str]: +def get_pydantic_field_names(cls: Any) -> set[str]: return set(cls.__annotations__.keys()) @@ -156,6 +146,7 @@ class OpenAIEmbeddings(BaseModel, Embeddings): .. code-block:: python from langchain.embeddings import OpenAIEmbeddings + openai = OpenAIEmbeddings(openai_api_key="my-api-key") In order to use the library with Microsoft Azure endpoints, you need to set @@ -168,6 +159,7 @@ class OpenAIEmbeddings(BaseModel, Embeddings): .. code-block:: python import os + os.environ["OPENAI_API_TYPE"] = "azure" os.environ["OPENAI_API_BASE"] = "https:// Dict[str, Any]: + def build_extra(cls, values: dict[str, Any]) -> dict[str, Any]: """Build extra kwargs from additional params that were passed in.""" all_required_field_names = get_pydantic_field_names(cls) extra = values.get("model_kwargs", {}) @@ -265,7 +256,7 @@ class OpenAIEmbeddings(BaseModel, Embeddings): return values @root_validator() - def validate_environment(cls, values: Dict) -> Dict: + def validate_environment(cls, values: dict) -> dict: """Validate that api key and python package exists in environment.""" values["openai_api_key"] = get_from_dict_or_env( values, "openai_api_key", "OPENAI_API_KEY" @@ -320,7 +311,7 @@ class OpenAIEmbeddings(BaseModel, Embeddings): return values @property - def _invocation_params(self) -> Dict: + def _invocation_params(self) -> dict: openai_args = { "model": self.model, "request_timeout": self.request_timeout, @@ -345,12 +336,12 @@ class OpenAIEmbeddings(BaseModel, Embeddings): def _get_len_safe_embeddings( self, - texts: List[str], + texts: list[str], *, engine: str, - chunk_size: Optional[int] = None, - ) -> List[List[float]]: - embeddings: List[List[float]] = [ + chunk_size: int | None = None, + ) -> list[list[float]]: + embeddings: list[list[float]] = [ [] for _ in range(len(texts)) ] try: @@ -390,7 +381,7 @@ class OpenAIEmbeddings(BaseModel, Embeddings): ) indices.append(i) - batched_embeddings: List[List[float]] = [] + batched_embeddings: list[list[float]] = [] _chunk_size = chunk_size or self.chunk_size if self.show_progress_bar: @@ -413,10 +404,10 @@ class OpenAIEmbeddings(BaseModel, Embeddings): r["embedding"] for r in response["data"] ) - results: List[List[List[float]]] = [ + results: list[list[list[float]]] = [ [] for _ in range(len(texts)) ] - num_tokens_in_batch: List[List[int]] = [ + num_tokens_in_batch: list[list[int]] = [ [] for _ in range(len(texts)) ] for i in range(len(indices)): @@ -445,12 +436,12 @@ class OpenAIEmbeddings(BaseModel, Embeddings): # https://github.com/openai/openai-cookbook/blob/main/examples/Embedding_long_inputs.ipynb async def _aget_len_safe_embeddings( self, - texts: List[str], + texts: list[str], *, engine: str, - chunk_size: Optional[int] = None, - ) -> List[List[float]]: - embeddings: List[List[float]] = [ + chunk_size: int | None = None, + ) -> list[list[float]]: + embeddings: list[list[float]] = [ [] for _ in range(len(texts)) ] try: @@ -490,7 +481,7 @@ class OpenAIEmbeddings(BaseModel, Embeddings): ) indices.append(i) - batched_embeddings: List[List[float]] = [] + batched_embeddings: list[list[float]] = [] _chunk_size = chunk_size or self.chunk_size for i in range(0, len(tokens), _chunk_size): response = await async_embed_with_retry( @@ -502,10 +493,10 @@ class OpenAIEmbeddings(BaseModel, Embeddings): r["embedding"] for r in response["data"] ) - results: List[List[List[float]]] = [ + results: list[list[list[float]]] = [ [] for _ in range(len(texts)) ] - num_tokens_in_batch: List[List[int]] = [ + num_tokens_in_batch: list[list[int]] = [ [] for _ in range(len(texts)) ] for i in range(len(indices)): @@ -533,8 +524,8 @@ class OpenAIEmbeddings(BaseModel, Embeddings): return embeddings def embed_documents( - self, texts: List[str], chunk_size: Optional[int] = 0 - ) -> List[List[float]]: + self, texts: list[str], chunk_size: int | None = 0 + ) -> list[list[float]]: """Call out to OpenAI's embedding endpoint for embedding search docs. Args: @@ -552,8 +543,8 @@ class OpenAIEmbeddings(BaseModel, Embeddings): ) async def aembed_documents( - self, texts: List[str], chunk_size: Optional[int] = 0 - ) -> List[List[float]]: + self, texts: list[str], chunk_size: int | None = 0 + ) -> list[list[float]]: """Call out to OpenAI's embedding endpoint async for embedding search docs. Args: @@ -570,7 +561,7 @@ class OpenAIEmbeddings(BaseModel, Embeddings): texts, engine=self.deployment ) - def embed_query(self, text: str) -> List[float]: + def embed_query(self, text: str) -> list[float]: """Call out to OpenAI's embedding endpoint for embedding query text. Args: @@ -581,7 +572,7 @@ class OpenAIEmbeddings(BaseModel, Embeddings): """ return self.embed_documents([text])[0] - async def aembed_query(self, text: str) -> List[float]: + async def aembed_query(self, text: str) -> list[float]: """Call out to OpenAI's embedding endpoint async for embedding query text. Args: diff --git a/swarms/models/openai_models.py b/swarms/models/openai_models.py index b1aa0117..2ee56fdb 100644 --- a/swarms/models/openai_models.py +++ b/swarms/models/openai_models.py @@ -10,16 +10,9 @@ from typing import ( AsyncIterator, Callable, Collection, - Dict, Iterator, - List, Literal, Mapping, - Optional, - Set, - Tuple, - Type, - Union, ) from langchain.callbacks.manager import ( @@ -61,11 +54,12 @@ def _log_error_once(msg: str) -> None: def create_base_retry_decorator( - error_types: List[Type[BaseException]], + error_types: list[type[BaseException]], max_retries: int = 1, - run_manager: Optional[ - Union[AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun] - ] = None, + run_manager: ( + AsyncCallbackManagerForLLMRun | CallbackManagerForLLMRun + ) + | None = None, ) -> Callable[[Any], Any]: """Create a retry decorator for a given LLM and provided list of error types.""" @@ -92,7 +86,7 @@ def create_base_retry_decorator( max_seconds = 10 # Wait 2^x * 1 second between each retry starting with # 4 seconds, then up to 10 seconds, then 10 seconds afterwards - retry_instance: "retry_base" = retry_if_exception_type( + retry_instance: retry_base = retry_if_exception_type( error_types[0] ) for error in error_types[1:]: @@ -116,9 +110,9 @@ def is_openai_v1() -> bool: def update_token_usage( - keys: Set[str], - response: Dict[str, Any], - token_usage: Dict[str, Any], + keys: set[str], + response: dict[str, Any], + token_usage: dict[str, Any], ) -> None: """Update token usage.""" _keys_to_use = keys.intersection(response["usage"]) @@ -130,7 +124,7 @@ def update_token_usage( def _stream_response_to_generation_chunk( - stream_response: Dict[str, Any], + stream_response: dict[str, Any], ) -> GenerationChunk: """Convert a stream response to a generation chunk.""" return GenerationChunk( @@ -147,7 +141,7 @@ def _stream_response_to_generation_chunk( def _update_response( - response: Dict[str, Any], stream_response: Dict[str, Any] + response: dict[str, Any], stream_response: dict[str, Any] ) -> None: """Update response from the stream response.""" response["choices"][0]["text"] += stream_response["choices"][0][ @@ -161,7 +155,7 @@ def _update_response( ]["logprobs"] -def _streaming_response_template() -> Dict[str, Any]: +def _streaming_response_template() -> dict[str, Any]: return { "choices": [ { @@ -174,10 +168,11 @@ def _streaming_response_template() -> Dict[str, Any]: def _create_retry_decorator( - llm: Union[BaseOpenAI, OpenAIChat], - run_manager: Optional[ - Union[AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun] - ] = None, + llm: BaseOpenAI | OpenAIChat, + run_manager: ( + AsyncCallbackManagerForLLMRun | CallbackManagerForLLMRun + ) + | None = None, ) -> Callable[[Any], Any]: import openai @@ -196,8 +191,8 @@ def _create_retry_decorator( def completion_with_retry( - llm: Union[BaseOpenAI, OpenAIChat], - run_manager: Optional[CallbackManagerForLLMRun] = None, + llm: BaseOpenAI | OpenAIChat, + run_manager: CallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> Any: """Use tenacity to retry the completion call.""" @@ -213,8 +208,8 @@ def completion_with_retry( async def acompletion_with_retry( - llm: Union[BaseOpenAI, OpenAIChat], - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, + llm: BaseOpenAI | OpenAIChat, + run_manager: AsyncCallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> Any: """Use tenacity to retry the async completion call.""" @@ -234,12 +229,12 @@ class BaseOpenAI(BaseLLM): """Base OpenAI large language model class.""" @property - def lc_secrets(self) -> Dict[str, str]: + def lc_secrets(self) -> dict[str, str]: return {"openai_api_key": "OPENAI_API_KEY"} @property - def lc_attributes(self) -> Dict[str, Any]: - attributes: Dict[str, Any] = {} + def lc_attributes(self) -> dict[str, Any]: + attributes: dict[str, Any] = {} if self.openai_api_base != "": attributes["openai_api_base"] = self.openai_api_base @@ -278,32 +273,28 @@ class BaseOpenAI(BaseLLM): """How many completions to generate for each prompt.""" best_of: int = 1 """Generates best_of completions server-side and returns the "best".""" - model_kwargs: Dict[str, Any] = Field(default_factory=dict) + model_kwargs: dict[str, Any] = Field(default_factory=dict) """Holds any model parameters valid for `create` call not explicitly specified.""" - openai_api_key: Optional[str] = None - openai_api_base: Optional[str] = None - openai_organization: Optional[str] = None + openai_api_key: str | None = None + openai_api_base: str | None = None + openai_organization: str | None = None # to support explicit proxy for OpenAI - openai_proxy: Optional[str] = None + openai_proxy: str | None = None batch_size: int = 20 """Batch size to use when passing multiple documents to generate.""" - request_timeout: Optional[Union[float, Tuple[float, float]]] = ( - None - ) + request_timeout: float | tuple[float, float] | None = None """Timeout for requests to OpenAI completion API. Default is 600 seconds.""" - logit_bias: Optional[Dict[str, float]] = Field( - default_factory=dict - ) + logit_bias: dict[str, float] | None = Field(default_factory=dict) """Adjust the probability of specific tokens being generated.""" max_retries: int = 6 """Maximum number of retries to make when generating.""" streaming: bool = False """Whether to stream the results or not.""" - allowed_special: Union[Literal["all"], AbstractSet[str]] = set() + allowed_special: Literal["all"] | AbstractSet[str] = set() """Set of special tokens that are allowed。""" - disallowed_special: Union[Literal["all"], Collection[str]] = "all" + disallowed_special: Literal["all"] | Collection[str] = "all" """Set of special tokens that are not allowed。""" - tiktoken_model_name: Optional[str] = None + tiktoken_model_name: str | None = None """The model name to pass to tiktoken when using this class. Tiktoken is used to count the number of tokens in documents to constrain them to be under a certain limit. By default, when set to None, this will @@ -314,7 +305,7 @@ class BaseOpenAI(BaseLLM): API but with different models. In those cases, in order to avoid erroring when tiktoken is called, you can specify a model name to use here.""" - def __new__(cls, **data: Any) -> Union[OpenAIChat, BaseOpenAI]: # type: ignore + def __new__(cls, **data: Any) -> OpenAIChat | BaseOpenAI: # type: ignore """Initialize the OpenAI object.""" data.get("model_name", "") return super().__new__(cls) @@ -325,7 +316,7 @@ class BaseOpenAI(BaseLLM): allow_population_by_field_name = True @root_validator(pre=True) - def build_extra(cls, values: Dict[str, Any]) -> Dict[str, Any]: + def build_extra(cls, values: dict[str, Any]) -> dict[str, Any]: """Build extra kwargs from additional params that were passed in.""" all_required_field_names = get_pydantic_field_names(cls) extra = values.get("model_kwargs", {}) @@ -335,7 +326,7 @@ class BaseOpenAI(BaseLLM): return values @root_validator() - def validate_environment(cls, values: Dict) -> Dict: + def validate_environment(cls, values: dict) -> dict: """Validate that api key and python package exists in environment.""" values["openai_api_key"] = get_from_dict_or_env( values, "openai_api_key", "OPENAI_API_KEY" @@ -376,7 +367,7 @@ class BaseOpenAI(BaseLLM): return values @property - def _default_params(self) -> Dict[str, Any]: + def _default_params(self) -> dict[str, Any]: """Get the default parameters for calling OpenAI API.""" normal_params = { "temperature": self.temperature, @@ -399,8 +390,8 @@ class BaseOpenAI(BaseLLM): def _stream( self, prompt: str, - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, + stop: list[str] | None = None, + run_manager: CallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> Iterator[GenerationChunk]: params = {**self._invocation_params, **kwargs, "stream": True} @@ -427,8 +418,8 @@ class BaseOpenAI(BaseLLM): async def _astream( self, prompt: str, - stop: Optional[List[str]] = None, - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, + stop: list[str] | None = None, + run_manager: AsyncCallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> AsyncIterator[GenerationChunk]: params = {**self._invocation_params, **kwargs, "stream": True} @@ -454,9 +445,9 @@ class BaseOpenAI(BaseLLM): def _generate( self, - prompts: List[str], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, + prompts: list[str], + stop: list[str] | None = None, + run_manager: CallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> LLMResult: """Call out to OpenAI's endpoint with k unique prompts. @@ -478,7 +469,7 @@ class BaseOpenAI(BaseLLM): params = {**params, **kwargs} sub_prompts = self.get_sub_prompts(params, prompts, stop) choices = [] - token_usage: Dict[str, int] = {} + token_usage: dict[str, int] = {} # Get the token usage from the response. # Includes prompt, completion, and total tokens used. _keys = {"completion_tokens", "prompt_tokens", "total_tokens"} @@ -489,7 +480,7 @@ class BaseOpenAI(BaseLLM): "Cannot stream results with multiple prompts." ) - generation: Optional[GenerationChunk] = None + generation: GenerationChunk | None = None for chunk in self._stream( _prompts[0], stop, run_manager, **kwargs ): @@ -528,9 +519,9 @@ class BaseOpenAI(BaseLLM): async def _agenerate( self, - prompts: List[str], - stop: Optional[List[str]] = None, - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, + prompts: list[str], + stop: list[str] | None = None, + run_manager: AsyncCallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> LLMResult: """Call out to OpenAI's endpoint async with k unique prompts.""" @@ -538,7 +529,7 @@ class BaseOpenAI(BaseLLM): params = {**params, **kwargs} sub_prompts = self.get_sub_prompts(params, prompts, stop) choices = [] - token_usage: Dict[str, int] = {} + token_usage: dict[str, int] = {} # Get the token usage from the response. # Includes prompt, completion, and total tokens used. _keys = {"completion_tokens", "prompt_tokens", "total_tokens"} @@ -549,7 +540,7 @@ class BaseOpenAI(BaseLLM): "Cannot stream results with multiple prompts." ) - generation: Optional[GenerationChunk] = None + generation: GenerationChunk | None = None async for chunk in self._astream( _prompts[0], stop, run_manager, **kwargs ): @@ -588,10 +579,10 @@ class BaseOpenAI(BaseLLM): def get_sub_prompts( self, - params: Dict[str, Any], - prompts: List[str], - stop: Optional[List[str]] = None, - ) -> List[List[str]]: + params: dict[str, Any], + prompts: list[str], + stop: list[str] | None = None, + ) -> list[list[str]]: """Get the sub prompts for llm call.""" if stop is not None: if "stop" in params: @@ -618,8 +609,8 @@ class BaseOpenAI(BaseLLM): def create_llm_result( self, choices: Any, - prompts: List[str], - token_usage: Dict[str, int], + prompts: list[str], + token_usage: dict[str, int], ) -> LLMResult: """Create the LLMResult from the choices and prompts.""" generations = [] @@ -646,9 +637,9 @@ class BaseOpenAI(BaseLLM): ) @property - def _invocation_params(self) -> Dict[str, Any]: + def _invocation_params(self) -> dict[str, Any]: """Get the parameters used to invoke the model.""" - openai_creds: Dict[str, Any] = { + openai_creds: dict[str, Any] = { "api_key": self.openai_api_key, "api_base": self.openai_api_base, "organization": self.openai_organization, @@ -672,7 +663,7 @@ class BaseOpenAI(BaseLLM): """Return type of llm.""" return "openai" - def get_token_ids(self, text: str) -> List[int]: + def get_token_ids(self, text: str) -> list[int]: """Get the token IDs using the tiktoken package.""" # tiktoken NOT supported for Python < 3.8 if sys.version_info[1] < 8: @@ -797,11 +788,12 @@ class OpenAI(BaseOpenAI): .. code-block:: python from langchain.llms import OpenAI + openai = OpenAI(model_name="text-davinci-003") """ @property - def _invocation_params(self) -> Dict[str, Any]: + def _invocation_params(self) -> dict[str, Any]: return { **{"model": self.model_name}, **super()._invocation_params, @@ -821,6 +813,7 @@ class AzureOpenAI(BaseOpenAI): .. code-block:: python from langchain.llms import AzureOpenAI + openai = AzureOpenAI(model_name="text-davinci-003") """ @@ -830,7 +823,7 @@ class AzureOpenAI(BaseOpenAI): openai_api_version: str = "" @root_validator() - def validate_azure_settings(cls, values: Dict) -> Dict: + def validate_azure_settings(cls, values: dict) -> dict: values["openai_api_version"] = get_from_dict_or_env( values, "openai_api_version", @@ -849,7 +842,7 @@ class AzureOpenAI(BaseOpenAI): } @property - def _invocation_params(self) -> Dict[str, Any]: + def _invocation_params(self) -> dict[str, Any]: openai_params = { "engine": self.deployment_name, "api_type": self.openai_api_type, @@ -863,7 +856,7 @@ class AzureOpenAI(BaseOpenAI): return "azure" @property - def lc_attributes(self) -> Dict[str, Any]: + def lc_attributes(self) -> dict[str, Any]: return { "openai_api_type": self.openai_api_type, "openai_api_version": self.openai_api_version, @@ -898,28 +891,29 @@ class OpenAIChat(BaseLLM): .. code-block:: python from langchain.llms import OpenAIChat + openaichat = OpenAIChat(model_name="gpt-3.5-turbo") """ client: Any #: :meta private: model_name: str = "gpt-4-1106-preview" - model_kwargs: Dict[str, Any] = Field(default_factory=dict) - openai_api_key: Optional[str] = None - openai_api_base: Optional[str] = None - openai_proxy: Optional[str] = None + model_kwargs: dict[str, Any] = Field(default_factory=dict) + openai_api_key: str | None = None + openai_api_base: str | None = None + openai_proxy: str | None = None max_retries: int = 6 """Maximum number of retries to make when generating.""" - prefix_messages: List = Field(default_factory=list) + prefix_messages: list = Field(default_factory=list) """Series of messages for Chat input.""" streaming: bool = False """Whether to stream the results or not.""" - allowed_special: Union[Literal["all"], AbstractSet[str]] = set() + allowed_special: Literal["all"] | AbstractSet[str] = set() """Set of special tokens that are allowed。""" - disallowed_special: Union[Literal["all"], Collection[str]] = "all" + disallowed_special: Literal["all"] | Collection[str] = "all" """Set of special tokens that are not allowed。""" @root_validator(pre=True) - def build_extra(cls, values: Dict[str, Any]) -> Dict[str, Any]: + def build_extra(cls, values: dict[str, Any]) -> dict[str, Any]: """Build extra kwargs from additional params that were passed in.""" all_required_field_names = { field.alias for field in cls.__fields__.values() @@ -937,7 +931,7 @@ class OpenAIChat(BaseLLM): return values @root_validator() - def validate_environment(cls, values: Dict) -> Dict: + def validate_environment(cls, values: dict) -> dict: """Validate that api key and python package exists in environment.""" openai_api_key = get_from_dict_or_env( values, "openai_api_key", "OPENAI_API_KEY" @@ -987,13 +981,13 @@ class OpenAIChat(BaseLLM): return values @property - def _default_params(self) -> Dict[str, Any]: + def _default_params(self) -> dict[str, Any]: """Get the default parameters for calling OpenAI API.""" return self.model_kwargs def _get_chat_params( - self, prompts: List[str], stop: Optional[List[str]] = None - ) -> Tuple: + self, prompts: list[str], stop: list[str] | None = None + ) -> tuple: if len(prompts) > 1: raise ValueError( "OpenAIChat currently only supports single prompt," @@ -1002,7 +996,7 @@ class OpenAIChat(BaseLLM): messages = self.prefix_messages + [ {"role": "user", "content": prompts[0]} ] - params: Dict[str, Any] = { + params: dict[str, Any] = { **{"model": self.model_name}, **self._default_params, } @@ -1021,8 +1015,8 @@ class OpenAIChat(BaseLLM): def _stream( self, prompt: str, - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, + stop: list[str] | None = None, + run_manager: CallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> Iterator[GenerationChunk]: messages, params = self._get_chat_params([prompt], stop) @@ -1041,8 +1035,8 @@ class OpenAIChat(BaseLLM): async def _astream( self, prompt: str, - stop: Optional[List[str]] = None, - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, + stop: list[str] | None = None, + run_manager: AsyncCallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> AsyncIterator[GenerationChunk]: messages, params = self._get_chat_params([prompt], stop) @@ -1060,13 +1054,13 @@ class OpenAIChat(BaseLLM): def _generate( self, - prompts: List[str], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, + prompts: list[str], + stop: list[str] | None = None, + run_manager: CallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> LLMResult: if self.streaming: - generation: Optional[GenerationChunk] = None + generation: GenerationChunk | None = None for chunk in self._stream( prompts[0], stop, run_manager, **kwargs ): @@ -1101,13 +1095,13 @@ class OpenAIChat(BaseLLM): async def _agenerate( self, - prompts: List[str], - stop: Optional[List[str]] = None, - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, + prompts: list[str], + stop: list[str] | None = None, + run_manager: AsyncCallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> LLMResult: if self.streaming: - generation: Optional[GenerationChunk] = None + generation: GenerationChunk | None = None async for chunk in self._astream( prompts[0], stop, run_manager, **kwargs ): @@ -1153,7 +1147,7 @@ class OpenAIChat(BaseLLM): """Return type of llm.""" return "openai-chat" - def get_token_ids(self, text: str) -> List[int]: + def get_token_ids(self, text: str) -> list[int]: """Get the token IDs using the tiktoken package.""" # tiktoken NOT supported for Python < 3.8 if sys.version_info[1] < 8: diff --git a/swarms/models/palm.py b/swarms/models/palm.py index d61d4856..ee0cbea2 100644 --- a/swarms/models/palm.py +++ b/swarms/models/palm.py @@ -1,7 +1,7 @@ from __future__ import annotations import logging -from typing import Any, Callable, Dict, List, Optional +from typing import Any, Callable from langchain.callbacks.manager import CallbackManagerForLLMRun from langchain.llms import BaseLLM @@ -85,19 +85,19 @@ class GooglePalm(BaseLLM, BaseModel): """Google PaLM models.""" client: Any #: :meta private: - google_api_key: Optional[str] + google_api_key: str | None model_name: str = "models/text-bison-001" """Model name to use.""" temperature: float = 0.7 """Run inference with this temperature. Must by in the closed interval [0.0, 1.0].""" - top_p: Optional[float] = None + top_p: float | None = None """Decode using nucleus sampling: consider the smallest set of tokens whose probability sum is at least top_p. Must be in the closed interval [0.0, 1.0].""" - top_k: Optional[int] = None + top_k: int | None = None """Decode using top-k sampling: consider the set of top_k most probable tokens. Must be positive.""" - max_output_tokens: Optional[int] = None + max_output_tokens: int | None = None """Maximum number of tokens to include in a candidate. Must be greater than zero. If unset, will default to 64.""" n: int = 1 @@ -105,7 +105,7 @@ class GooglePalm(BaseLLM, BaseModel): not return the full n completions if duplicates are generated.""" @root_validator() - def validate_environment(cls, values: Dict) -> Dict: + def validate_environment(cls, values: dict) -> dict: """Validate api key, python package exists.""" google_api_key = get_from_dict_or_env( values, "google_api_key", "GOOGLE_API_KEY" @@ -152,9 +152,9 @@ class GooglePalm(BaseLLM, BaseModel): def _generate( self, - prompts: List[str], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, + prompts: list[str], + stop: list[str] | None = None, + run_manager: CallbackManagerForLLMRun | None = None, **kwargs: Any, ) -> LLMResult: generations = [] diff --git a/swarms/models/petals.py b/swarms/models/petals.py index 7abc4590..7ceeef8b 100644 --- a/swarms/models/petals.py +++ b/swarms/models/petals.py @@ -1,4 +1,4 @@ -from transformers import AutoTokenizer, AutoModelForCausalLM +from transformers import AutoModelForCausalLM, AutoTokenizer class Petals: diff --git a/swarms/models/sam.py b/swarms/models/sam.py index 110d80b7..c51a2517 100644 --- a/swarms/models/sam.py +++ b/swarms/models/sam.py @@ -1,8 +1,9 @@ +from typing import List + +import requests import torch from PIL import Image -import requests from transformers import SamModel, SamProcessor -from typing import List device = "cuda" if torch.cuda.is_available() else "cpu" diff --git a/swarms/models/sam_supervision.py b/swarms/models/sam_supervision.py index 549844c2..5649f187 100644 --- a/swarms/models/sam_supervision.py +++ b/swarms/models/sam_supervision.py @@ -1,17 +1,18 @@ +from typing import Optional + import cv2 import numpy as np import supervision as sv from PIL import Image from transformers import ( - pipeline, + SamImageProcessor, SamModel, SamProcessor, - SamImageProcessor, + pipeline, ) -from typing import Optional -from swarms.utils.supervision_masking import masks_to_marks from swarms.models.base_multimodal_model import BaseMultiModalModel +from swarms.utils.supervision_masking import masks_to_marks class SegmentAnythingMarkGenerator(BaseMultiModalModel): diff --git a/swarms/models/sampling_params.py b/swarms/models/sampling_params.py index c2fdd121..d231c295 100644 --- a/swarms/models/sampling_params.py +++ b/swarms/models/sampling_params.py @@ -1,4 +1,5 @@ """Sampling parameters for text generation.""" + from enum import IntEnum from functools import cached_property from typing import Callable, List, Optional, Union @@ -104,7 +105,7 @@ class SamplingParams: use_beam_search: bool = False, length_penalty: float = 1.0, early_stopping: Union[bool, str] = False, - stop: Optional[Union[str, List[str]]] = None, + stop: Union[str, List[str], None] = None, stop_token_ids: Optional[List[int]] = None, include_stop_str_in_output: bool = False, ignore_eos: bool = False, diff --git a/swarms/models/speecht5.py b/swarms/models/speecht5.py index cc6ef931..b9f2653b 100644 --- a/swarms/models/speecht5.py +++ b/swarms/models/speecht5.py @@ -26,15 +26,16 @@ Blog Post: [https://huggingface.co/blog/speecht5] Demo: [https://huggingface.co/spaces/Matthijs/speecht5-tts-demo] """ -import torch + import soundfile as sf +import torch +from datasets import load_dataset from transformers import ( - pipeline, - SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan, + SpeechT5Processor, + pipeline, ) -from datasets import load_dataset class SpeechT5: diff --git a/swarms/models/ssd_1b.py b/swarms/models/ssd_1b.py index d3b9086b..4479c866 100644 --- a/swarms/models/ssd_1b.py +++ b/swarms/models/ssd_1b.py @@ -7,11 +7,11 @@ from typing import List import backoff import torch +from cachetools import TTLCache from diffusers import StableDiffusionXLPipeline from PIL import Image from pydantic import validator from termcolor import colored -from cachetools import TTLCache @dataclass diff --git a/swarms/models/stable_diffusion.py b/swarms/models/stable_diffusion.py index a0068531..9ae45604 100644 --- a/swarms/models/stable_diffusion.py +++ b/swarms/models/stable_diffusion.py @@ -1,11 +1,12 @@ import base64 import os -import requests -import uuid import shutil -from dotenv import load_dotenv +import uuid from typing import List +import requests +from dotenv import load_dotenv + load_dotenv() stable_api_key = os.environ.get("STABLE_API_KEY") diff --git a/swarms/models/test_fire_function.py b/swarms/models/test_fire_function.py new file mode 100644 index 00000000..082d954d --- /dev/null +++ b/swarms/models/test_fire_function.py @@ -0,0 +1,44 @@ +from unittest.mock import MagicMock + +from swarms.models.fire_function import FireFunctionCaller + + +def test_fire_function_caller_run(mocker): + # Create mock model and tokenizer + model = MagicMock() + tokenizer = MagicMock() + mocker.patch.object(FireFunctionCaller, "model", model) + mocker.patch.object(FireFunctionCaller, "tokenizer", tokenizer) + + # Create mock task and arguments + task = "Add 2 and 3" + args = (2, 3) + kwargs = {} + + # Create mock generated_ids and decoded output + generated_ids = [1, 2, 3] + decoded_output = "5" + model.generate.return_value = generated_ids + tokenizer.batch_decode.return_value = [decoded_output] + + # Create FireFunctionCaller instance + fire_function_caller = FireFunctionCaller() + + # Run the function + fire_function_caller.run(task, *args, **kwargs) + + # Assert model.generate was called with the correct inputs + model.generate.assert_called_once_with( + tokenizer.apply_chat_template.return_value, + max_new_tokens=fire_function_caller.max_tokens, + *args, + **kwargs, + ) + + # Assert tokenizer.batch_decode was called with the correct inputs + tokenizer.batch_decode.assert_called_once_with(generated_ids) + + # Assert the decoded output is printed + assert decoded_output in mocker.patch.object( + print, "call_args_list" + ) diff --git a/swarms/models/timm.py b/swarms/models/timm.py index de0484f2..f08afda3 100644 --- a/swarms/models/timm.py +++ b/swarms/models/timm.py @@ -3,6 +3,7 @@ from typing import List import timm import torch from torch import Tensor + from swarms.models.base_multimodal_model import BaseMultiModalModel diff --git a/swarms/models/types.py b/swarms/models/types.py index 460d0ef7..10957329 100644 --- a/swarms/models/types.py +++ b/swarms/models/types.py @@ -1,6 +1,7 @@ -from pydantic import BaseModel from typing import List, Optional +from pydantic import BaseModel + class TextModality(BaseModel): content: str diff --git a/swarms/models/ultralytics_model.py b/swarms/models/ultralytics_model.py index edb9984c..3cb9c956 100644 --- a/swarms/models/ultralytics_model.py +++ b/swarms/models/ultralytics_model.py @@ -1,7 +1,9 @@ -from swarms.models.base_multimodal_model import BaseMultiModalModel -from ultralytics import YOLO from typing import List +from ultralytics import YOLO + +from swarms.models.base_multimodal_model import BaseMultiModalModel + class UltralyticsModel(BaseMultiModalModel): """ diff --git a/swarms/models/vllm.py b/swarms/models/vllm.py index 0caeb3c8..cf9cda45 100644 --- a/swarms/models/vllm.py +++ b/swarms/models/vllm.py @@ -1,4 +1,5 @@ import torch + from swarms.models.base_llm import AbstractLLM if torch.cuda.is_available() or torch.cuda.device_count() > 0: diff --git a/swarms/models/zephyr.py b/swarms/models/zephyr.py index c5772295..205ec2e5 100644 --- a/swarms/models/zephyr.py +++ b/swarms/models/zephyr.py @@ -1,4 +1,5 @@ """Zephyr by HF""" + import torch from transformers import pipeline diff --git a/swarms/prompts/__init__.py b/swarms/prompts/__init__.py index 93416a9b..edec5906 100644 --- a/swarms/prompts/__init__.py +++ b/swarms/prompts/__init__.py @@ -1,4 +1,5 @@ from swarms.prompts.code_interpreter import CODE_INTERPRETER +from swarms.prompts.documentation import DOCUMENTATION_WRITER_SOP from swarms.prompts.finance_agent_prompt import FINANCE_AGENT_PROMPT from swarms.prompts.growth_agent_prompt import GROWTH_AGENT_PROMPT from swarms.prompts.legal_agent_prompt import LEGAL_AGENT_PROMPT @@ -6,7 +7,6 @@ from swarms.prompts.operations_agent_prompt import ( OPERATIONS_AGENT_PROMPT, ) from swarms.prompts.product_agent_prompt import PRODUCT_AGENT_PROMPT -from swarms.prompts.documentation import DOCUMENTATION_WRITER_SOP from swarms.prompts.schema_generator import SchemaGenerator __all__ = [ diff --git a/swarms/prompts/base.py b/swarms/prompts/base.py index a0e28c71..d104f468 100644 --- a/swarms/prompts/base.py +++ b/swarms/prompts/base.py @@ -1,7 +1,7 @@ from __future__ import annotations from abc import abstractmethod -from typing import TYPE_CHECKING, Any, Dict, List, Sequence +from typing import TYPE_CHECKING, Any, Sequence from pydantic import Field @@ -94,8 +94,8 @@ class BaseMessage(Serializable): class BaseMessageChunk(BaseMessage): def _merge_kwargs_dict( - self, left: Dict[str, Any], right: Dict[str, Any] - ) -> Dict[str, Any]: + self, left: dict[str, Any], right: dict[str, Any] + ) -> dict[str, Any]: """Merge additional_kwargs from another BaseMessageChunk into this one.""" merged = left.copy() for k, v in right.items(): @@ -223,7 +223,7 @@ def _message_to_dict(message: BaseMessage) -> dict: return {"type": message.type, "data": message.dict()} -def messages_to_dict(messages: Sequence[BaseMessage]) -> List[dict]: +def messages_to_dict(messages: Sequence[BaseMessage]) -> list[dict]: """Convert a sequence of Messages to a list of dictionaries. Args: @@ -251,7 +251,7 @@ def _message_from_dict(message: dict) -> BaseMessage: raise ValueError(f"Got unexpected message type: {_type}") -def messages_from_dict(messages: List[dict]) -> List[BaseMessage]: +def messages_from_dict(messages: list[dict]) -> list[BaseMessage]: """Convert a sequence of messages from dicts to Message objects. Args: diff --git a/swarms/prompts/chat_prompt.py b/swarms/prompts/chat_prompt.py index 013aee28..49a0aa23 100644 --- a/swarms/prompts/chat_prompt.py +++ b/swarms/prompts/chat_prompt.py @@ -1,7 +1,7 @@ from __future__ import annotations from abc import abstractmethod -from typing import Dict, List, Sequence +from typing import Sequence class Message: @@ -11,7 +11,7 @@ class Message: """ def __init__( - self, content: str, role: str, additional_kwargs: Dict = None + self, content: str, role: str, additional_kwargs: dict = None ): self.content = content self.role = role @@ -33,7 +33,7 @@ class HumanMessage(Message): self, content: str, role: str = "Human", - additional_kwargs: Dict = None, + additional_kwargs: dict = None, example: bool = False, ): super().__init__(content, role, additional_kwargs) @@ -52,7 +52,7 @@ class AIMessage(Message): self, content: str, role: str = "AI", - additional_kwargs: Dict = None, + additional_kwargs: dict = None, example: bool = False, ): super().__init__(content, role, additional_kwargs) @@ -72,7 +72,7 @@ class SystemMessage(Message): self, content: str, role: str = "System", - additional_kwargs: Dict = None, + additional_kwargs: dict = None, ): super().__init__(content, role, additional_kwargs) @@ -90,7 +90,7 @@ class FunctionMessage(Message): content: str, role: str = "Function", name: str = None, - additional_kwargs: Dict = None, + additional_kwargs: dict = None, ): super().__init__(content, role, additional_kwargs) self.name = name @@ -105,7 +105,7 @@ class ChatMessage(Message): """ def __init__( - self, content: str, role: str, additional_kwargs: Dict = None + self, content: str, role: str, additional_kwargs: dict = None ): super().__init__(content, role, additional_kwargs) @@ -135,7 +135,7 @@ def message_to_dict(message: Message) -> dict: return {"type": message.get_type(), "data": message.__dict__} -def messages_to_dict(messages: Sequence[Message]) -> List[dict]: +def messages_to_dict(messages: Sequence[Message]) -> list[dict]: return [message_to_dict(m) for m in messages] @@ -155,5 +155,5 @@ def message_from_dict(message: dict) -> Message: raise ValueError(f"Got unexpected message type: {_type}") -def messages_from_dict(messages: List[dict]) -> List[Message]: +def messages_from_dict(messages: list[dict]) -> list[Message]: return [message_from_dict(m) for m in messages] diff --git a/swarms/prompts/worker_prompt.py b/swarms/prompts/worker_prompt.py index 165fa058..08636516 100644 --- a/swarms/prompts/worker_prompt.py +++ b/swarms/prompts/worker_prompt.py @@ -3,12 +3,12 @@ import datetime time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") -def worker_tools_sop_promp(name: str, memory: str): +def worker_tools_sop_promp(name: str, memory: str, time=time): out = """ You are {name}, Your decisions must always be made independently without seeking user assistance. Play to your strengths as an LLM and pursue simple strategies with no legal complications. - If you have completed all your tasks, make sure to use the "finish" command. + If you have completed all your tasks, make sure to use the 'finish' command. GOALS: @@ -19,11 +19,11 @@ def worker_tools_sop_promp(name: str, memory: str): 1. ~4000 word limit for short term memory. Your short term memory is short, so immediately save important information to files. 2. If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember. 3. No user assistance - 4. Exclusively use the commands listed in double quotes e.g. "command name" + 4. Exclusively use the commands listed in double quotes e.g. 'command name' Commands: - 1. finish: use this to signal that you have finished all your objectives, args: "response": "final response to let people know you have finished your objectives" + 1. finish: use this to signal that you have finished all your objectives, args: 'response': 'final response to let people know you have finished your objectives' Resources: @@ -42,17 +42,17 @@ def worker_tools_sop_promp(name: str, memory: str): You should only respond in JSON format as described below Response Format: { - "thoughts": { - "text": "thought", - "reasoning": "reasoning", - "plan": "- short bulleted - list that conveys - long-term plan", - "criticism": "constructive self-criticism", - "speak": "thoughts summary to say to user" + 'thoughts': { + 'text': 'thoughts', + 'reasoning': 'reasoning', + 'plan': '- short bulleted - list that conveys - long-term plan', + 'criticism': 'constructive self-criticism', + 'speak': 'thoughts summary to say to user' }, - "command": { - "name": "command name", - "args": { - "arg name": "value" + 'command': { + 'name': 'command name', + 'args': { + 'arg name': 'value' } } } @@ -62,6 +62,6 @@ def worker_tools_sop_promp(name: str, memory: str): [{memory}] Human: Determine which next command to use, and respond using the format specified above: - """.format(name=name, memory=memory, time=time) + """.format(name=name, time=time, memory=memory) return str(out) diff --git a/swarms/structs/SWARMS.md b/swarms/structs/SWARMS.md index 1a417831..070eb176 100644 --- a/swarms/structs/SWARMS.md +++ b/swarms/structs/SWARMS.md @@ -31,7 +31,7 @@ class Orchestrator(ABC): # Break down main_task into smaller tasks # ... return sub_tasks - + def aggregate_results(self, sub_results: List[Any]) -> Any: # Combine results from sub-tasks into a cohesive output # ... diff --git a/swarms/structs/__init__.py b/swarms/structs/__init__.py index ec75cb9f..d604cf07 100644 --- a/swarms/structs/__init__.py +++ b/swarms/structs/__init__.py @@ -1,4 +1,5 @@ from swarms.structs.agent import Agent +from swarms.structs.agent_base import AgentJob from swarms.structs.autoscaler import AutoScaler from swarms.structs.base import BaseStructure from swarms.structs.base_swarm import AbstractSwarm @@ -8,16 +9,27 @@ from swarms.structs.concurrent_workflow import ConcurrentWorkflow from swarms.structs.conversation import Conversation from swarms.structs.graph_workflow import GraphWorkflow from swarms.structs.groupchat import GroupChat, GroupChatManager +from swarms.structs.majority_voting import ( + MajorityVoting, + majority_voting, + most_frequent, + parse_code_completion, +) from swarms.structs.message import Message from swarms.structs.model_parallizer import ModelParallelizer from swarms.structs.multi_agent_collab import MultiAgentCollaboration +from swarms.structs.multi_process_workflow import ( + MultiProcessingWorkflow, +) +from swarms.structs.multi_threaded_workflow import ( + MultiThreadedWorkflow, +) from swarms.structs.nonlinear_workflow import NonlinearWorkflow from swarms.structs.plan import Plan from swarms.structs.recursive_workflow import RecursiveWorkflow from swarms.structs.schemas import ( Artifact, ArtifactUpload, - Step, StepInput, StepOutput, StepRequestBody, @@ -25,6 +37,7 @@ from swarms.structs.schemas import ( TaskRequestBody, ) from swarms.structs.sequential_workflow import SequentialWorkflow +from swarms.structs.stackoverflow_swarm import StackOverflowSwarm from swarms.structs.step import Step from swarms.structs.swarm_net import SwarmNetwork from swarms.structs.swarming_architectures import ( @@ -48,6 +61,11 @@ from swarms.structs.swarming_architectures import ( star_swarm, ) from swarms.structs.task import Task +from swarms.structs.task_queue_base import ( + TaskQueueBase, + synchronized_queue, +) +from swarms.structs.tool_json_schema import JSON from swarms.structs.utils import ( detect_markdown, distribute_tasks, @@ -57,13 +75,6 @@ from swarms.structs.utils import ( find_token_in_text, parse_tasks, ) -from swarms.structs.tool_json_schema import JSON -from swarms.structs.majority_voting import ( - most_frequent, - parse_code_completion, - majority_voting, -) - __all__ = [ "Agent", @@ -123,4 +134,11 @@ __all__ = [ "most_frequent", "parse_code_completion", "majority_voting", + "MajorityVoting", + "StackOverflowSwarm", + "synchronized_queue", + "TaskQueueBase", + "MultiProcessingWorkflow", + "MultiThreadedWorkflow", + "AgentJob", ] diff --git a/swarms/structs/agent.py b/swarms/structs/agent.py index 3b059617..9d2a5e1a 100644 --- a/swarms/structs/agent.py +++ b/swarms/structs/agent.py @@ -3,32 +3,35 @@ import json import logging import os import random +import sys import time import uuid from typing import Any, Callable, Dict, List, Optional, Tuple +import yaml +from loguru import logger from termcolor import colored from swarms.memory.base_vectordb import AbstractVectorDatabase -from swarms.prompts.agent_system_prompts import ( - AGENT_SYSTEM_PROMPT_3, -) +from swarms.prompts.agent_system_prompts import AGENT_SYSTEM_PROMPT_3 from swarms.prompts.multi_modal_autonomous_instruction_prompt import ( MULTI_MODAL_AUTO_AGENT_SYSTEM_PROMPT_1, ) +from swarms.prompts.worker_prompt import worker_tools_sop_promp from swarms.structs.conversation import Conversation +from swarms.structs.schemas import Step from swarms.tokenizers.base_tokenizer import BaseTokenizer +from swarms.tools.exec_tool import execute_tool_by_name from swarms.tools.tool import BaseTool from swarms.utils.code_interpreter import SubprocessCodeInterpreter from swarms.utils.data_to_text import data_to_text -from swarms.utils.logger import logger -from swarms.utils.parse_code import ( - extract_code_from_markdown, -) +from swarms.utils.parse_code import extract_code_from_markdown from swarms.utils.pdf_to_text import pdf_to_text from swarms.utils.token_count_tiktoken import limit_tokens_from_string -from swarms.tools.exec_tool import execute_tool_by_name -from swarms.prompts.worker_prompt import worker_tools_sop_promp +from swarms.utils.video_to_frames import ( + save_frames_as_images, + video_to_frames, +) # Utils @@ -50,6 +53,22 @@ def agent_id(): return str(uuid.uuid4()) +# Task ID generator +def task_id(): + """ + Generate a unique task ID. + + Returns: + str: A string representation of a UUID. + """ + return str(uuid.uuid4()) + + +# Step ID generator +def step_id(): + return str(uuid.uuid1()) + + class Agent: """ Agent is the backbone to connect LLMs with tools and long term memory. Agent also provides the ability to @@ -145,7 +164,7 @@ class Agent: id: str = agent_id, llm: Any = None, template: Optional[str] = None, - max_loops: int = 1, + max_loops: Optional[int] = 1, stopping_condition: Optional[Callable[[str], bool]] = None, loop_interval: int = 1, retry_attempts: int = 3, @@ -181,6 +200,16 @@ class Agent: docs_folder: str = None, verbose: bool = False, parser: Optional[Callable] = None, + best_of_n: Optional[int] = None, + callback: Optional[Callable] = None, + metadata: Optional[Dict[str, Any]] = None, + callbacks: Optional[List[Callable]] = None, + logger_handler: Any = sys.stderr, + search_algorithm: Optional[Callable] = None, + logs_to_filename: Optional[str] = None, + evaluator: Optional[Callable] = None, + output_json: bool = False, + stopping_func: Optional[Callable] = None, *args, **kwargs, ): @@ -226,9 +255,20 @@ class Agent: self.docs_folder = docs_folder self.verbose = verbose self.parser = parser + self.best_of_n = best_of_n + self.callback = callback + self.metadata = metadata + self.callbacks = callbacks + self.logger_handler = logger_handler + self.search_algorithm = search_algorithm + self.logs_to_filename = logs_to_filename + self.evaluator = evaluator + self.output_json = output_json + self.stopping_func = stopping_func # The max_loops will be set dynamically if the dynamic_loop if self.dynamic_loops: + logger.info("Dynamic loops enabled") self.max_loops = "auto" # If multimodal = yes then set the sop to the multimodal sop @@ -243,7 +283,9 @@ class Agent: self.feedback = [] # Initialize the code executor - self.code_executor = SubprocessCodeInterpreter() + self.code_executor = SubprocessCodeInterpreter( + debug_mode=True, + ) # If the preset stopping token is enabled then set the stopping token to the preset stopping token if preset_stopping_token: @@ -262,11 +304,12 @@ class Agent: self.get_docs_from_doc_folders() # If tokenizer and context length exists then: - if self.tokenizer and self.context_length: - self.truncate_history() + # if self.tokenizer and self.context_length: + # self.truncate_history() - if verbose: - logger.setLevel(logging.DEBUG) + # If verbose is enabled then set the logger level to info + # if verbose: + # logger.setLevel(logging.INFO) # If tools are provided then set the tool prompt by adding to sop if self.tools: @@ -288,6 +331,24 @@ class Agent: # Initialize the llm with the conditional variables # self.llm = llm(*args, **kwargs) + # Step cache + self.step_cache = [] + + # Set the logger handler + if logger_handler: + logger.add( + f"{self.agent_name}.log", + level="INFO", + colorize=True, + format=( + "{time} {message}" + ), + backtrace=True, + diagnose=True, + ) + + # logger.info("Creating Agent {}".format(self.agent_name)) + def set_system_prompt(self, system_prompt: str): """Set the system prompt""" self.system_prompt = system_prompt @@ -322,6 +383,7 @@ class Agent: if hasattr(self.llm, "temperature"): # Randomly change the temperature attribute of self.llm object self.llm.temperature = random.uniform(0.0, 1.0) + logger.info(f"Temperature: {self.llm.temperature}") else: # Use a default temperature self.llm.temperature = 0.7 @@ -339,6 +401,7 @@ class Agent: def add_task_to_memory(self, task: str): """Add the task to the memory""" try: + logger.info(f"Adding task to memory: {task}") self.short_memory.add(f"{self.user_name}: {task}") except Exception as error: print( @@ -350,6 +413,7 @@ class Agent: def add_message_to_memory(self, message: str): """Add the message to the memory""" try: + logger.info(f"Adding message to memory: {message}") self.short_memory.add( role=self.agent_name, content=message ) @@ -493,6 +557,7 @@ class Agent: self, task: Optional[str] = None, img: Optional[str] = None, + video: Optional[str] = None, *args, **kwargs, ): @@ -511,10 +576,16 @@ class Agent: """ try: + if video: + video_to_frames(video) + frames = save_frames_as_images(video) + for frame in frames: + img = frame + # Activate Autonomous agent message self.activate_autonomous_agent() - response = task # or combined_prompt + # response = task # or combined_prompt history = self._history(self.user_name, task) # If dashboard = True then print the dashboard @@ -533,20 +604,13 @@ class Agent: self.loop_count_print(loop_count, self.max_loops) print("\n") - # Check to see if stopping token is in the output to stop the loop - if self.stopping_token: - if self._check_stopping_condition( - response - ) or parse_done_token(response): - break - # Adjust temperature, comment if no work if self.dynamic_temperature_enabled: print(colored("Adjusting temperature...", "blue")) self.dynamic_temperature() # Preparing the prompt - task = self.agent_history_prompt(history=response) + task = self.agent_history_prompt(history=task) attempt = 0 while attempt < self.retry_attempts: @@ -565,6 +629,60 @@ class Agent: ) print(response) + if self.output_json: + response = extract_code_from_markdown( + response + ) + + # Add the response to the history + history.append(response) + + # Log each step + step = Step( + input=str(task), + task_id=str(task_id), + step_id=str(step_id), + output=str(response), + status="running", + ) + + if self.evaluator: + evaluated_response = self.evaluator( + response + ) + + out = ( + f"Response: {response}\nEvaluated" + f" Response: {evaluated_response}" + ) + out = self.short_memory.add( + "Evaluator", out + ) + + # Stopping logic for agents + if self.stopping_token: + # Check if the stopping token is in the response + if self.stopping_token in response: + break + + if self.stopping_condition: + if self._check_stopping_condition( + response + ): + break + + # if self.parse_done_token: + # if parse_done_token(response): + # break + + if self.stopping_func is not None: + if self.stopping_func(response) is True: + break + + # If the stopping condition is met then break + self.step_cache.append(step) + logging.info(f"Step: {step}") + # If parser exists then parse the response if self.parser: response = self.parser(response) @@ -600,8 +718,6 @@ class Agent: ) attempt += 1 time.sleep(self.retry_interval) - # Add the response to the history - history.append(response) time.sleep(self.loop_interval) # Add the history to the memory @@ -640,20 +756,6 @@ class Agent: """ self.run(task, img, *args, **kwargs) - def _run(self, **kwargs: Any) -> str: - """Run the agent on a task - - Returns: - str: _description_ - """ - try: - task = self.format_prompt(**kwargs) - response, history = self._generate(task, task) - logging.info(f"Message history: {history}") - return response - except Exception as error: - print(colored(f"Error running agent: {error}", "red")) - def agent_history_prompt( self, history: str = None, @@ -671,23 +773,20 @@ class Agent: if self.sop: system_prompt = self.system_prompt agent_history_prompt = f""" - SYSTEM_PROMPT: {system_prompt} + role: system + {system_prompt} Follow this standard operating procedure (SOP) to complete tasks: {self.sop} - ----------------- - ################ CHAT HISTORY #################### {history} """ return agent_history_prompt else: system_prompt = self.system_prompt agent_history_prompt = f""" - SYSTEM_PROMPT: {system_prompt} - - - ################ CHAT HISTORY #################### + System : {system_prompt} + {history} """ return agent_history_prompt @@ -721,6 +820,7 @@ class Agent: Returns: _type_: _description_ """ + logger.info(f"Adding memory: {message}") return self.short_memory.add( role=self.agent_name, content=message ) @@ -733,10 +833,12 @@ class Agent: tasks (List[str]): A list of tasks to run. """ try: + logger.info(f"Running concurrent tasks: {tasks}") task_coroutines = [ self.run_async(task, **kwargs) for task in tasks ] completed_tasks = await asyncio.gather(*task_coroutines) + logger.info(f"Completed tasks: {completed_tasks}") return completed_tasks except Exception as error: print( @@ -752,6 +854,7 @@ class Agent: def bulk_run(self, inputs: List[Dict[str, Any]]) -> List[str]: try: """Generate responses for multiple input sets.""" + logger.info(f"Running bulk tasks: {inputs}") return [self.run(**input_data) for input_data in inputs] except Exception as error: print(colored(f"Error running bulk run: {error}", "red")) @@ -778,7 +881,7 @@ class Agent: Args: file_path (str): The path to the file containing the saved agent history. """ - with open(file_path, "r") as f: + with open(file_path) as f: self.short_memory = json.load(f) print(f"Loaded agent history from {file_path}") @@ -844,6 +947,7 @@ class Agent: """ try: + logger.info(f"Running a single step: {task}") # Generate the response using lm response = self.llm(task, **kwargs) @@ -923,6 +1027,7 @@ class Agent: """ + logger.info(f"Adding response filter: {filter_word}") self.reponse_filters.append(filter_word) def apply_reponse_filters(self, response: str) -> str: @@ -930,6 +1035,9 @@ class Agent: Apply the response filters to the response """ + logger.info( + f"Applying response filters to response: {response}" + ) for word in self.response_filters: response = response.replace(word, "[FILTERED]") return response @@ -941,11 +1049,13 @@ class Agent: response = agent.filtered_run("Generate a report on finance") print(response) """ + logger.info(f"Running filtered task: {task}") raw_response = self.run(task) return self.apply_response_filters(raw_response) def interactive_run(self, max_loops: int = 5) -> None: """Interactive run mode""" + logger.info("Running in interactive mode") response = input("Start the cnversation") for i in range(max_loops): @@ -955,27 +1065,21 @@ class Agent: # Get user input response = input("You: ") - def streamed_generation(self, prompt: str) -> str: + def save_to_yaml(self, file_path: str) -> None: """ - Stream the generation of the response + Save the agent to a YAML file Args: - prompt (str): The prompt to use - - Example: - # Feature 4: Streamed generation - response = agent.streamed_generation("Generate a report on finance") - print(response) - + file_path (str): The path to the YAML file """ - tokens = list(prompt) - response = "" - for token in tokens: - time.sleep(0.1) - response += token - print(token, end="", flush=True) - print() - return response + try: + logger.info(f"Saving agent to YAML file: {file_path}") + with open(file_path, "w") as f: + yaml.dump(self.__dict__, f) + except Exception as error: + print( + colored(f"Error saving agent to YAML: {error}", "red") + ) def save_state(self, file_path: str) -> None: """ @@ -988,6 +1092,7 @@ class Agent: >>> agent.save_state('saved_flow.json') """ try: + logger.info(f"Saving agent state to: {file_path}") state = { "agent_id": str(self.id), "agent_name": self.agent_name, @@ -1067,54 +1172,55 @@ class Agent: >>> agent.run("Continue with the task") """ - with open(file_path, "r") as f: - state = json.load(f) - - # Restore other saved attributes - self.id = state.get("agent_id", self.id) - self.agent_name = state.get("agent_name", self.agent_name) - self.agent_description = state.get( - "agent_description", self.agent_description - ) - self.system_prompt = state.get( - "system_prompt", self.system_prompt - ) - self.sop = state.get("sop", self.sop) - self.short_memory = state.get("short_memory", []) - self.max_loops = state.get("max_loops", 5) - self.loop_interval = state.get("loop_interval", 1) - self.retry_attempts = state.get("retry_attempts", 3) - self.retry_interval = state.get("retry_interval", 1) - self.interactive = state.get("interactive", False) - - print(f"Agent state loaded from {file_path}") + try: + with open(file_path) as f: + state = json.load(f) + + # Restore other saved attributes + self.id = state.get("agent_id", self.id) + self.agent_name = state.get("agent_name", self.agent_name) + self.agent_description = state.get( + "agent_description", self.agent_description + ) + self.system_prompt = state.get( + "system_prompt", self.system_prompt + ) + self.sop = state.get("sop", self.sop) + self.short_memory = state.get("short_memory", []) + self.max_loops = state.get("max_loops", 5) + self.loop_interval = state.get("loop_interval", 1) + self.retry_attempts = state.get("retry_attempts", 3) + self.retry_interval = state.get("retry_interval", 1) + self.interactive = state.get("interactive", False) + + print(f"Agent state loaded from {file_path}") + except Exception as error: + print( + colored(f"Error loading agent state: {error}", "red") + ) def retry_on_failure( - self, function, retries: int = 3, retry_delay: int = 1 + self, + function: callable, + retries: int = 3, + retry_delay: int = 1, ): """Retry wrapper for LLM calls.""" - attempt = 0 - while attempt < retries: - try: - return function() - except Exception as error: - logging.error(f"Error generating response: {error}") - attempt += 1 - time.sleep(retry_delay) - raise Exception("All retry attempts failed") - - def generate_reply(self, history: str, **kwargs) -> str: - """ - Generate a response based on initial or task - """ - prompt = f""" - - SYSTEM_PROMPT: {self.system_prompt} - - History: {history} - """ - response = self.llm(prompt, **kwargs) - return {"role": self.agent_name, "content": response} + try: + logger.info(f"Retrying function: {function}") + attempt = 0 + while attempt < retries: + try: + return function() + except Exception as error: + logging.error( + f"Error generating response: {error}" + ) + attempt += 1 + time.sleep(retry_delay) + raise Exception("All retry attempts failed") + except Exception as error: + print(colored(f"Error retrying function: {error}", "red")) def update_system_prompt(self, system_prompt: str): """Upddate the system message""" @@ -1144,9 +1250,13 @@ class Agent: """ text -> parse_code by looking for code inside 6 backticks `````-> run_code """ - parsed_code = extract_code_from_markdown(code) - run_code = self.code_executor.run(parsed_code) - return run_code + try: + logger.info(f"Running code: {code}") + parsed_code = extract_code_from_markdown(code) + run_code = self.code_executor.run(parsed_code) + return run_code + except Exception as error: + logger.debug(f"Error running code: {error}") def pdf_connector(self, pdf: str = None): """Transforms the pdf into text @@ -1157,9 +1267,13 @@ class Agent: Returns: _type_: _description_ """ - pdf = pdf or self.pdf_path - text = pdf_to_text(pdf) - return text + try: + pdf = pdf or self.pdf_path + text = pdf_to_text(pdf) + return text + except Exception as error: + print(f"Error connecting to the pdf: {error}") + raise error def pdf_chunker(self, text: str = None, num_limits: int = 1000): """Chunk the pdf into sentences @@ -1183,12 +1297,15 @@ class Agent: Returns: _type_: _description_ """ - for doc in docs: - data = data_to_text(doc) + try: + for doc in docs: + data = data_to_text(doc) - return self.short_memory.add( - role=self.user_name, content=data - ) + return self.short_memory.add( + role=self.user_name, content=data + ) + except Exception as error: + print(colored(f"Error ingesting docs: {error}", "red")) def ingest_pdf(self, pdf: str): """Ingest the pdf into the memory @@ -1199,22 +1316,37 @@ class Agent: Returns: _type_: _description_ """ - text = pdf_to_text(pdf) - return self.short_memory.add( - role=self.user_name, content=text - ) + try: + logger.info(f"Ingesting pdf: {pdf}") + text = pdf_to_text(pdf) + return self.short_memory.add( + role=self.user_name, content=text + ) + except Exception as error: + print(colored(f"Error ingesting pdf: {error}", "red")) def receieve_mesage(self, name: str, message: str): """Receieve a message""" - message = f"{name}: {message}" - return self.short_memory.add(role=name, content=message) + try: + message = f"{name}: {message}" + return self.short_memory.add(role=name, content=message) + except Exception as error: + print(colored(f"Error receiving message: {error}", "red")) def send_agent_message( self, agent_name: str, message: str, *args, **kwargs ): """Send a message to the agent""" - message = f"{agent_name}: {message}" - return self.run(message, *args, **kwargs) + try: + logger.info(f"Sending agent message: {message}") + message = f"{agent_name}: {message}" + return self.run(message, *args, **kwargs) + except Exception as error: + print( + colored( + f"Error sending agent message: {error}", "red" + ) + ) def truncate_history(self): """ @@ -1241,13 +1373,22 @@ class Agent: def get_docs_from_doc_folders(self): """Get the docs from the files""" - # Get the list of files then extract them and add them to the memory - files = os.listdir(self.docs_folder) + try: + logger.info("Getting docs from doc folders") + # Get the list of files then extract them and add them to the memory + files = os.listdir(self.docs_folder) - # Extract the text from the files - for file in files: - text = data_to_text(file) + # Extract the text from the files + for file in files: + text = data_to_text(file) - return self.short_memory.add( - role=self.user_name, content=text - ) + return self.short_memory.add( + role=self.user_name, content=text + ) + except Exception as error: + print( + colored( + f"Error getting docs from doc folders: {error}", + "red", + ) + ) diff --git a/swarms/structs/agent_base.py b/swarms/structs/agent_base.py new file mode 100644 index 00000000..8f1a3669 --- /dev/null +++ b/swarms/structs/agent_base.py @@ -0,0 +1,20 @@ +import threading +from typing import Callable, Tuple + + +class AgentJob(threading.Thread): + """A class that handles multithreading logic. + + Args: + function (Callable): The function to be executed in a separate thread. + args (Tuple): The arguments to be passed to the function. + """ + + def __init__(self, function: Callable, args: Tuple): + threading.Thread.__init__(self) + self.function = function + self.args = args + + def run(self) -> None: + """Runs the function in a separate thread.""" + self.function(*self.args) diff --git a/swarms/structs/async_workflow.py b/swarms/structs/async_workflow.py index b46061b2..6cf9e312 100644 --- a/swarms/structs/async_workflow.py +++ b/swarms/structs/async_workflow.py @@ -1,6 +1,8 @@ import asyncio from dataclasses import dataclass, field from typing import Any, Callable, List, Optional + +from swarms.structs.agent import Agent from swarms.structs.task import Task from swarms.utils.logger import logger @@ -41,8 +43,9 @@ class AsyncWorkflow: results: List[Any] = field(default_factory=list) loop: Optional[asyncio.AbstractEventLoop] = None stopping_condition: Optional[Callable] = None + agents: List[Agent] = None - async def add(self, task: Any, tasks: List[Any]): + async def add(self, task: Any = None, tasks: List[Any] = None): """Add tasks to the workflow""" try: if tasks: diff --git a/swarms/structs/autoscaler.py b/swarms/structs/autoscaler.py index f26247d5..4996b7d5 100644 --- a/swarms/structs/autoscaler.py +++ b/swarms/structs/autoscaler.py @@ -7,12 +7,12 @@ from typing import Callable, Dict, List, Optional from termcolor import colored from swarms.structs.agent import Agent +from swarms.structs.base import BaseStructure from swarms.utils.decorators import ( error_decorator, log_decorator, timing_decorator, ) -from swarms.structs.base import BaseStructure class AutoScaler(BaseStructure): @@ -241,7 +241,7 @@ class AutoScaler(BaseStructure): task = self.task_queue.get() if task: available_agent = next( - (agent for agent in self.agents_pool) + agent for agent in self.agents_pool ) if available_agent: available_agent.run(task) diff --git a/swarms/structs/base.py b/swarms/structs/base.py index adfa974d..9d3b4c15 100644 --- a/swarms/structs/base.py +++ b/swarms/structs/base.py @@ -1,11 +1,12 @@ +import asyncio +import concurrent.futures import json import os from abc import ABC -from typing import Optional, Any, Dict, List -from datetime import datetime -import asyncio -import concurrent.futures from concurrent.futures import ThreadPoolExecutor +from datetime import datetime +from typing import Any, Dict, List, Optional + import psutil try: @@ -81,7 +82,6 @@ class BaseStructure(ABC): def run(self, *args, **kwargs): """Run the structure.""" - pass def save_to_file(self, data: Any, file_path: str): """Save data to file. @@ -102,7 +102,7 @@ class BaseStructure(ABC): Returns: Any: _description_ """ - with open(file_path, "r") as file: + with open(file_path) as file: return json.load(file) def save_metadata(self, metadata: Dict[str, Any]): diff --git a/swarms/structs/base_multiagent_structure.py b/swarms/structs/base_multiagent_structure.py new file mode 100644 index 00000000..48388df5 --- /dev/null +++ b/swarms/structs/base_multiagent_structure.py @@ -0,0 +1,197 @@ +import json +from typing import List, Optional, Sequence + +import yaml + +from swarms.structs.agent import Agent +from swarms.structs.conversation import Conversation +from swarms.utils.logger import logger + + +class BaseMultiAgentStructure: + """ + Base class for a multi-agent structure. + + Args: + agents (List[Agent], optional): List of agents in the structure. Defaults to None. + callbacks (Optional[Sequence[callable]], optional): List of callbacks for the structure. Defaults to None. + autosave (bool, optional): Flag indicating whether to enable autosave. Defaults to False. + logging (bool, optional): Flag indicating whether to enable logging. Defaults to False. + *args: Variable length argument list. + **kwargs: Arbitrary keyword arguments. + + Attributes: + agents (List[Agent]): List of agents in the structure. + callbacks (Optional[Sequence[callable]]): List of callbacks for the structure. + autosave (bool): Flag indicating whether autosave is enabled. + logging (bool): Flag indicating whether logging is enabled. + conversation (Conversation): Conversation object for the structure. + + Methods: + metadata(): Get the metadata of the multi-agent structure. + save_to_json(filename: str): Save the current state of the multi-agent structure to a JSON file. + load_from_json(filename: str): Load the state of the multi-agent structure from a JSON file. + """ + + def __init__( + self, + agents: List[Agent] = None, + callbacks: Optional[Sequence[callable]] = None, + autosave: bool = False, + logging: bool = False, + return_metadata: bool = False, + metadata_filename: str = "multiagent_structure_metadata.json", + *args, + **kwargs, + ): + self.agents = agents + self.callbacks = callbacks + self.autosave = autosave + self.logging = logging + self.return_metadata = return_metadata + self.metadata_filename = metadata_filename + self.conversation = Conversation( + time_enabled=True, *args, **kwargs + ) + if self.logging: + self.logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", + ) + + # Handle the case where the agents are not provided + # Handle agents + for agent in self.agents: + if not isinstance(agent, Agent): + raise TypeError("Agents must be of type Agent.") + + if self.agents is None: + self.agents = [] + + # Handle the case where the callbacks are not provided + if self.callbacks is None: + self.callbacks = [] + + # Handle the case where the autosave is not provided + if self.autosave is None: + self.autosave = False + + # Handle the case where the logging is not provided + if self.logging is None: + self.logging = False + + # Handle callbacks + if callbacks is not None: + for callback in self.callbacks: + if not callable(callback): + raise TypeError("Callback must be callable.") + + # Handle autosave + if autosave: + self.save_to_json(metadata_filename) + + def metadata(self): + """ + Get the metadata of the multi-agent structure. + + Returns: + dict: The metadata of the multi-agent structure. + """ + return { + "agents": self.agents, + "callbacks": self.callbacks, + "autosave": self.autosave, + "logging": self.logging, + "conversation": self.conversation, + } + + def save_to_json(self, filename: str): + """ + Save the current state of the multi-agent structure to a JSON file. + + Args: + filename (str): The name of the file to save the multi-agent structure to. + + Returns: + None + """ + try: + with open(filename, "w") as f: + json.dump(self.__dict__, f) + except Exception as e: + logger.error(e) + + def load_from_json(self, filename: str): + """ + Load the state of the multi-agent structure from a JSON file. + + Args: + filename (str): The name of the file to load the multi-agent structure from. + + Returns: + None + """ + try: + with open(filename) as f: + self.__dict__ = json.load(f) + except Exception as e: + logger.error(e) + + def save_to_yaml(self, filename: str): + """ + Save the current state of the multi-agent structure to a YAML file. + + Args: + filename (str): The name of the file to save the multi-agent structure to. + + Returns: + None + """ + try: + with open(filename, "w") as f: + yaml.dump(self.__dict__, f) + except Exception as e: + logger.error(e) + + def load_from_yaml(self, filename: str): + """ + Load the state of the multi-agent structure from a YAML file. + + Args: + filename (str): The name of the file to load the multi-agent structure from. + + Returns: + None + """ + try: + with open(filename) as f: + self.__dict__ = yaml.load(f) + except Exception as e: + logger.error(e) + + def __repr__(self): + return f"{self.__class__.__name__}({self.__dict__})" + + def __str__(self): + return f"{self.__class__.__name__}({self.__dict__})" + + def __len__(self): + return len(self.agents) + + def __getitem__(self, index): + return self.agents[index] + + def __setitem__(self, index, value): + self.agents[index] = value + + def __delitem__(self, index): + del self.agents[index] + + def __iter__(self): + return iter(self.agents) + + def __reversed__(self): + return reversed(self.agents) + + def __contains__(self, value): + return value in self.agents diff --git a/swarms/structs/base_swarm.py b/swarms/structs/base_swarm.py index fe81df4e..ed910546 100644 --- a/swarms/structs/base_swarm.py +++ b/swarms/structs/base_swarm.py @@ -1,9 +1,8 @@ import asyncio -from abc import ABC +from abc import ABC, abstractmethod from concurrent.futures import ThreadPoolExecutor, as_completed from typing import Any, Callable, Dict, List, Optional - from swarms.structs.agent import Agent @@ -59,17 +58,14 @@ class AbstractSwarm(ABC): """Initialize the swarm with agents""" self.agents = agents self.max_loops = max_loops - pass # @abstractmethod def communicate(self): """Communicate with the swarm through the orchestrator, protocols, and the universal communication layer""" - pass # @abstractmethod def run(self): """Run the swarm""" - pass def __call__( self, @@ -89,34 +85,28 @@ class AbstractSwarm(ABC): def step(self): """Step the swarm""" - pass # @abstractmethod def add_agent(self, agent: "Agent"): """Add a agent to the swarm""" - pass # @abstractmethod def remove_agent(self, agent: "Agent"): """Remove a agent from the swarm""" - pass # @abstractmethod def broadcast( self, message: str, sender: Optional["Agent"] = None ): """Broadcast a message to all agents""" - pass # @abstractmethod def reset(self): """Reset the swarm""" - pass # @abstractmethod def plan(self, task: str): """agents must individually plan using a workflow or pipeline""" - pass # @abstractmethod def direct_message( @@ -126,27 +116,22 @@ class AbstractSwarm(ABC): recipient: "Agent", ): """Send a direct message to a agent""" - pass # @abstractmethod def autoscaler(self, num_agents: int, agent: ["Agent"]): """Autoscaler that acts like kubernetes for autonomous agents""" - pass # @abstractmethod def get_agent_by_id(self, id: str) -> "Agent": """Locate a agent by id""" - pass # @abstractmethod def get_agent_by_name(self, name: str) -> "Agent": """Locate a agent by name""" - pass # @abstractmethod def assign_task(self, agent: "Agent", task: Any) -> Dict: """Assign a task to a agent""" - pass # @abstractmethod def get_all_tasks(self, agent: "Agent", task: Any): @@ -155,67 +140,54 @@ class AbstractSwarm(ABC): # @abstractmethod def get_finished_tasks(self) -> List[Dict]: """Get all finished tasks""" - pass # @abstractmethod def get_pending_tasks(self) -> List[Dict]: """Get all pending tasks""" - pass # @abstractmethod def pause_agent(self, agent: "Agent", agent_id: str): """Pause a agent""" - pass # @abstractmethod def resume_agent(self, agent: "Agent", agent_id: str): """Resume a agent""" - pass # @abstractmethod def stop_agent(self, agent: "Agent", agent_id: str): """Stop a agent""" - pass # @abstractmethod def restart_agent(self, agent: "Agent"): """Restart agent""" - pass # @abstractmethod def scale_up(self, num_agent: int): """Scale up the number of agents""" - pass # @abstractmethod def scale_down(self, num_agent: int): """Scale down the number of agents""" - pass # @abstractmethod def scale_to(self, num_agent: int): """Scale to a specific number of agents""" - pass # @abstractmethod def get_all_agents(self) -> List["Agent"]: """Get all agents""" - pass # @abstractmethod def get_swarm_size(self) -> int: """Get the size of the swarm""" - pass # #@abstractmethod def get_swarm_status(self) -> Dict: """Get the status of the swarm""" - pass # #@abstractmethod def save_swarm_state(self): """Save the swarm state""" - pass def batched_run(self, tasks: List[Any], *args, **kwargs): """_summary_ @@ -432,3 +404,59 @@ class AbstractSwarm(ABC): self.agents, ) return list(responses) + + @abstractmethod + def add_swarm_entry(self, swarm): + """ + Add the information of a joined Swarm to the registry. + + Args: + swarm (SwarmManagerBase): Instance of SwarmManagerBase representing the joined Swarm. + + Returns: + None + """ + + @abstractmethod + def add_agent_entry(self, agent: Agent): + """ + Add the information of an Agent to the registry. + + Args: + agent (Agent): Instance of Agent representing the Agent. + + Returns: + None + """ + + @abstractmethod + def retrieve_swarm_information(self, swarm_id: str): + """ + Retrieve the information of a specific Swarm from the registry. + + Args: + swarm_id (str): Unique identifier of the Swarm. + + Returns: + SwarmManagerBase: Instance of SwarmManagerBase representing the retrieved Swarm, or None if not found. + """ + + @abstractmethod + def retrieve_joined_agents(self, agent_id: str) -> List[Agent]: + """ + Retrieve the information the Agents which have joined the registry. + + Returns: + Agent: Instance of Agent representing the retrieved Agent, or None if not found. + """ + + @abstractmethod + def join_swarm( + self, from_entity: Agent | Agent, to_entity: Agent + ): + """ + Add a relationship between a Swarm and an Agent or other Swarm to the registry. + + Args: + from (Agent | SwarmManagerBase): Instance of Agent or SwarmManagerBase representing the source of the relationship. + """ diff --git a/swarms/structs/base_workflow.py b/swarms/structs/base_workflow.py index 03e503cc..17b98ce8 100644 --- a/swarms/structs/base_workflow.py +++ b/swarms/structs/base_workflow.py @@ -3,8 +3,10 @@ from typing import Any, Dict, List, Optional from termcolor import colored +from swarms.structs.agent import Agent from swarms.structs.base import BaseStructure from swarms.structs.task import Task +from swarms.utils.loguru_logger import logger class BaseWorkflow(BaseStructure): @@ -14,18 +16,27 @@ class BaseWorkflow(BaseStructure): Attributes: task_pool (list): A list to store tasks. - Methods: - add(task: Task = None, tasks: List[Task] = None, *args, **kwargs): - Adds a task or a list of tasks to the task pool. - run(): - Abstract method to run the workflow. + """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.task_pool = [] + self.agent_pool = [] + + # Logging + logger.info("Number of agents activated:") + if self.agents: + logger.info(f"Agents: {len(self.agents)}") + else: + logger.info("No agents activated.") - def add( + if self.task_pool: + logger.info(f"Task Pool Size: {len(self.task_pool)}") + else: + logger.info("Task Pool is empty.") + + def add_task( self, task: Task = None, tasks: List[Task] = None, @@ -51,6 +62,9 @@ class BaseWorkflow(BaseStructure): "You must provide a task or a list of tasks" ) + def add_agent(self, agent: Agent, *args, **kwargs): + return self.agent_pool(agent) + def run(self): """ Abstract method to run the workflow. @@ -62,7 +76,6 @@ class BaseWorkflow(BaseStructure): Abstract method for the sequential loop. """ # raise NotImplementedError("You must implement this method") - pass def __log(self, message: str): """ @@ -298,7 +311,7 @@ class BaseWorkflow(BaseStructure): try: filepath = filepath or self.restore_state_filepath - with open(filepath, "r") as f: + with open(filepath) as f: state = json.load(f) self.max_loops = state["max_loops"] self.tasks = [] @@ -319,3 +332,55 @@ class BaseWorkflow(BaseStructure): "red", ) ) + + def workflow_dashboard(self, **kwargs) -> None: + """ + Displays a dashboard for the workflow. + + Args: + **kwargs: Additional keyword arguments to pass to the dashboard. + + Examples: + >>> from swarms.models import OpenAIChat + >>> from swarms.structs import SequentialWorkflow + >>> llm = OpenAIChat(openai_api_key="") + >>> workflow = SequentialWorkflow(max_loops=1) + >>> workflow.add("What's the weather in miami", llm) + >>> workflow.add("Create a report on these metrics", llm) + >>> workflow.workflow_dashboard() + + """ + print( + colored( + f""" + Sequential Workflow Dashboard + -------------------------------- + Name: {self.name} + Description: {self.description} + task_pool: {len(self.task_pool)} + Max Loops: {self.max_loops} + Autosave: {self.autosave} + Autosave Filepath: {self.saved_state_filepath} + Restore Filepath: {self.restore_state_filepath} + -------------------------------- + Metadata: + kwargs: {kwargs} + """, + "cyan", + attrs=["bold", "underline"], + ) + ) + + def workflow_bootup(self, **kwargs) -> None: + """ + Workflow bootup. + + """ + print( + colored( + """ + Sequential Workflow Initializing...""", + "green", + attrs=["bold", "underline"], + ) + ) diff --git a/swarms/structs/blocksdict.py b/swarms/structs/blocksdict.py index 93aab729..0f978eee 100644 --- a/swarms/structs/blocksdict.py +++ b/swarms/structs/blocksdict.py @@ -1,8 +1,4 @@ -from typing import ( - Any, - Dict, - Optional, -) +from typing import Any, Dict, Optional from swarms.structs.base import BaseStructure diff --git a/swarms/structs/blockslist.py b/swarms/structs/blockslist.py index b2a4db08..fca1e846 100644 --- a/swarms/structs/blockslist.py +++ b/swarms/structs/blockslist.py @@ -1,8 +1,4 @@ -from typing import ( - Any, - List, - Optional, -) +from typing import Any, List, Optional from swarms.structs.base import BaseStructure diff --git a/swarms/structs/company.py b/swarms/structs/company.py index 11b6d61f..06b7bdfe 100644 --- a/swarms/structs/company.py +++ b/swarms/structs/company.py @@ -2,8 +2,8 @@ from dataclasses import dataclass, field from typing import Dict, List, Optional, Union from swarms.structs.agent import Agent -from swarms.utils.logger import logger from swarms.structs.conversation import Conversation +from swarms.utils.logger import logger @dataclass diff --git a/swarms/structs/concurrent_workflow.py b/swarms/structs/concurrent_workflow.py index 8aa5399b..f36df3b3 100644 --- a/swarms/structs/concurrent_workflow.py +++ b/swarms/structs/concurrent_workflow.py @@ -1,10 +1,9 @@ import concurrent.futures from dataclasses import dataclass, field -from typing import Dict, List, Optional, Callable +from typing import Callable, Dict, List, Optional from swarms.structs.base import BaseStructure from swarms.structs.task import Task - from swarms.utils.logger import logger diff --git a/swarms/structs/conversation.py b/swarms/structs/conversation.py index c4bcdba5..4f426cbf 100644 --- a/swarms/structs/conversation.py +++ b/swarms/structs/conversation.py @@ -1,5 +1,6 @@ import datetime import json +from typing import Optional from termcolor import colored @@ -61,7 +62,7 @@ class Conversation(BaseStructure): def __init__( self, - system_prompt: str, + system_prompt: Optional[str] = None, time_enabled: bool = False, database: AbstractDatabase = None, autosave: bool = False, @@ -199,7 +200,7 @@ class Conversation(BaseStructure): Args: filename (str): filename to import from """ - with open(filename, "r") as f: + with open(filename) as f: for line in f: role, content = line.split(": ", 1) self.add(role, content.strip()) @@ -249,7 +250,7 @@ class Conversation(BaseStructure): """ # Load the conversation history from a JSON file if filename is not None: - with open(filename, "r") as f: + with open(filename) as f: self.conversation_history = json.load(f) def search_keyword_in_conversation(self, keyword: str): diff --git a/swarms/structs/debate.py b/swarms/structs/debate.py new file mode 100644 index 00000000..95c889d3 --- /dev/null +++ b/swarms/structs/debate.py @@ -0,0 +1,364 @@ +import json +import os +from datetime import datetime +from typing import List + +from swarms.structs.agent import Agent + +NAME_LIST = [ + "Affirmative side", + "Negative side", + "Moderator", +] + + +class DebatePlayer(Agent): + def __init__(self, llm, name: str, *args, **kwargs) -> None: + """Create a player in the debate + + Args: + model_name(str): model name + name (str): name of this player + temperature (float): higher values make the output more random, while lower values make it more focused and deterministic + openai_api_key (str): As the parameter name suggests + sleep_time (float): sleep because of rate limits + """ + super().__init__(llm=llm, agent_name=name, *args, **kwargs) + + +class Debate: + """Create a debate + + Args: + model_name (str): openai model name + temperature (float): higher values make the output more random, while lower values make it more focused and deterministic + num_players (int): num of players + save_file_dir (str): dir path to json file + openai_api_key (str): As the parameter name suggests + prompts_path (str): prompts path (json file) + max_round (int): maximum Rounds of Debate + sleep_time (float): sleep because of rate limits + """ + + def __init__( + self, + debate_agents: List[DebatePlayer], + temperature: float = 0, + num_players: int = 3, + save_file_dir: str = None, + prompts_path: str = None, + max_round: int = 3, + sleep_time: float = 0, + ) -> None: + self.debate_agents = debate_agents + self.num_players = num_players + self.save_file_dir = save_file_dir + self.max_round = max_round + self.sleep_time = sleep_time + + # init save file + now = datetime.now() + current_time = now.strftime("%Y-%m-%d_%H:%M:%S") + self.save_file = { + "start_time": current_time, + "end_time": "", + "temperature": temperature, + "num_players": num_players, + "success": False, + "src_lng": "", + "tgt_lng": "", + "source": "", + "reference": "", + "base_translation": "", + "debate_translation": "", + "Reason": "", + "Supported Side": "", + "players": {}, + } + prompts = json.load(open(prompts_path)) + self.save_file.update(prompts) + self.init_prompt() + + if self.save_file["base_translation"] == "": + self.create_base() + + # creat&init agents + self.create_agents() + self.init_agents() + + def init_prompt(self): + def prompt_replace(key): + self.save_file[key] = ( + self.save_file[key] + .replace("##src_lng##", self.save_file["src_lng"]) + .replace("##tgt_lng##", self.save_file["tgt_lng"]) + .replace("##source##", self.save_file["source"]) + .replace( + "##base_translation##", + self.save_file["base_translation"], + ) + ) + + prompt_replace("base_prompt") + prompt_replace("player_meta_prompt") + prompt_replace("moderator_meta_prompt") + prompt_replace("judge_prompt_last2") + + def create_base(self): + print( + "\n===== Translation Task" + f" =====\n{self.save_file['base_prompt']}\n" + ) + agent = DebatePlayer( + name="Baseline", + openai_api_key=self.openai_api_key, + ) + agent.add_message_to_memory(self.save_file["base_prompt"]) + base_translation = agent.ask() + agent.add_message_to_memory(base_translation) + self.save_file["base_translation"] = base_translation + self.save_file["affirmative_prompt"] = self.save_file[ + "affirmative_prompt" + ].replace("##base_translation##", base_translation) + self.save_file["players"][agent.name] = agent.memory_lst + + def create_agents(self): + # creates players + self.players = [ + DebatePlayer( + model_name=self.model_name, + name=name, + ) + for name in NAME_LIST + ] + self.affirmative = self.players[0] + self.negative = self.players[1] + self.moderator = self.players[2] + + def init_agents(self): + # start: set meta prompt + self.affirmative.system_prompt( + self.save_file["player_meta_prompt"] + ) + self.negative.system_prompt( + self.save_file["player_meta_prompt"] + ) + self.moderator.system_prompt( + self.save_file["moderator_meta_prompt"] + ) + + # start: first round debate, state opinions + print("===== Debate Round-1 =====\n") + self.affirmative.add_message_to_memory( + self.save_file["affirmative_prompt"] + ) + self.aff_ans = self.affirmative.ask() + self.affirmative.add_message_to_memory(self.aff_ans) + + self.negative.add_message_to_memory( + self.save_file["negative_prompt"].replace( + "##aff_ans##", self.aff_ans + ) + ) + self.neg_ans = self.negative.ask() + self.negative.add_message_to_memory(self.neg_ans) + + self.moderator.add_message_to_memory( + self.save_file["moderator_prompt"] + .replace("##aff_ans##", self.aff_ans) + .replace("##neg_ans##", self.neg_ans) + .replace("##round##", "first") + ) + self.mod_ans = self.moderator.ask() + self.moderator.add_message_to_memory(self.mod_ans) + self.mod_ans = eval(self.mod_ans) + + def round_dct(self, num: int): + dct = { + 1: "first", + 2: "second", + 3: "third", + 4: "fourth", + 5: "fifth", + 6: "sixth", + 7: "seventh", + 8: "eighth", + 9: "ninth", + 10: "tenth", + } + return dct[num] + + def save_file_to_json(self, id): + now = datetime.now() + current_time = now.strftime("%Y-%m-%d_%H:%M:%S") + save_file_path = os.path.join( + self.save_file_dir, f"{id}.json" + ) + + self.save_file["end_time"] = current_time + json_str = json.dumps( + self.save_file, ensure_ascii=False, indent=4 + ) + with open(save_file_path, "w") as f: + f.write(json_str) + + def broadcast(self, msg: str): + """Broadcast a message to all players. + Typical use is for the host to announce public information + + Args: + msg (str): the message + """ + # print(msg) + for player in self.players: + player.add_message_to_memory(msg) + + def speak(self, speaker: str, msg: str): + """The speaker broadcast a message to all other players. + + Args: + speaker (str): name of the speaker + msg (str): the message + """ + if not msg.startswith(f"{speaker}: "): + msg = f"{speaker}: {msg}" + # print(msg) + for player in self.players: + if player.name != speaker: + player.add_message_to_memory(msg) + + def ask_and_speak(self, player: DebatePlayer): + ans = player.ask() + player.add_message_to_memory(ans) + self.speak(player.name, ans) + + def run(self): + for round in range(self.max_round - 1): + if self.mod_ans["debate_translation"] != "": + break + else: + print(f"===== Debate Round-{round+2} =====\n") + self.affirmative.add_message_to_memory( + self.save_file["debate_prompt"].replace( + "##oppo_ans##", self.neg_ans + ) + ) + self.aff_ans = self.affirmative.ask() + self.affirmative.add_message_to_memory(self.aff_ans) + + self.negative.add_message_to_memory( + self.save_file["debate_prompt"].replace( + "##oppo_ans##", self.aff_ans + ) + ) + self.neg_ans = self.negative.ask() + self.negative.add_message_to_memory(self.neg_ans) + + self.moderator.add_message_to_memory( + self.save_file["moderator_prompt"] + .replace("##aff_ans##", self.aff_ans) + .replace("##neg_ans##", self.neg_ans) + .replace("##round##", self.round_dct(round + 2)) + ) + self.mod_ans = self.moderator.ask() + self.moderator.add_message_to_memory(self.mod_ans) + self.mod_ans = eval(self.mod_ans) + + if self.mod_ans["debate_translation"] != "": + self.save_file.update(self.mod_ans) + self.save_file["success"] = True + + # ultimate deadly technique. + else: + judge_player = DebatePlayer( + model_name=self.model_name, + name="Judge", + temperature=self.temperature, + openai_api_key=self.openai_api_key, + sleep_time=self.sleep_time, + ) + aff_ans = self.affirmative.memory_lst[2]["content"] + neg_ans = self.negative.memory_lst[2]["content"] + + judge_player.system_prompt( + self.save_file["moderator_meta_prompt"] + ) + + # extract answer candidates + judge_player.add_message_to_memory( + self.save_file["judge_prompt_last1"] + .replace("##aff_ans##", aff_ans) + .replace("##neg_ans##", neg_ans) + ) + ans = judge_player.ask() + judge_player.add_message_to_memory(ans) + + # select one from the candidates + judge_player.add_message_to_memory( + self.save_file["judge_prompt_last2"] + ) + ans = judge_player.ask() + judge_player.add_message_to_memory(ans) + + ans = eval(ans) + if ans["debate_translation"] != "": + self.save_file["success"] = True + # save file + self.save_file.update(ans) + self.players.append(judge_player) + + for player in self.players: + self.save_file["players"][player.name] = player.memory_lst + + +# def parse_args(): +# parser = argparse.ArgumentParser("", formatter_class=argparse.ArgumentDefaultsHelpFormatter) + +# parser.add_argument("-i", "--input-file", type=str, required=True, help="Input file path") +# parser.add_argument("-o", "--output-dir", type=str, required=True, help="Output file dir") +# parser.add_argument("-lp", "--lang-pair", type=str, required=True, help="Language pair") +# parser.add_argument("-k", "--api-key", type=str, required=True, help="OpenAI api key") +# parser.add_argument("-m", "--model-name", type=str, default="gpt-3.5-turbo", help="Model name") +# parser.add_argument("-t", "--temperature", type=float, default=0, help="Sampling temperature") + +# return parser.parse_args() + + +# if __name__ == "__main__": +# args = parse_args() +# openai_api_key = args.api_key + +# current_script_path = os.path.abspath(__file__) +# MAD_path = current_script_path.rsplit("/", 2)[0] + +# src_lng, tgt_lng = args.lang_pair.split('-') +# src_full = Language.make(language=src_lng).display_name() +# tgt_full = Language.make(language=tgt_lng).display_name() + +# config = json.load(open(f"{MAD_path}/code/utils/config4tran.json", "r")) + +# inputs = open(args.input_file, "r").readlines() +# inputs = [l.strip() for l in inputs] + +# save_file_dir = args.output_dir +# if not os.path.exists(save_file_dir): +# os.mkdir(save_file_dir) + +# for id, input in enumerate(tqdm(inputs)): +# # files = os.listdir(save_file_dir) +# # if f"{id}.json" in files: +# # continue + +# prompts_path = f"{save_file_dir}/{id}-config.json" + +# config['source'] = input.split('\t')[0] +# config['reference'] = input.split('\t')[1] +# config['src_lng'] = src_full +# config['tgt_lng'] = tgt_full + +# with open(prompts_path, 'w') as file: +# json.dump(config, file, ensure_ascii=False, indent=4) + +# debate = Debate(save_file_dir=save_file_dir, num_players=3, openai_api_key=openai_api_key, prompts_path=prompts_path, temperature=0, sleep_time=0) +# debate.run() +# debate.save_file_to_json(id) diff --git a/swarms/structs/graph_workflow.py b/swarms/structs/graph_workflow.py index c4bcea7e..23d90339 100644 --- a/swarms/structs/graph_workflow.py +++ b/swarms/structs/graph_workflow.py @@ -1,8 +1,7 @@ -from swarms.structs.base import BaseStructure - - import logging +from swarms.structs.base import BaseStructure + class GraphWorkflow(BaseStructure): """ diff --git a/swarms/structs/groupchat.py b/swarms/structs/groupchat.py index 21fff944..57cb6472 100644 --- a/swarms/structs/groupchat.py +++ b/swarms/structs/groupchat.py @@ -1,6 +1,7 @@ import logging from dataclasses import dataclass from typing import Dict, List + from swarms.structs.agent import Agent logger = logging.getLogger(__name__) diff --git a/swarms/structs/load_balancer.py b/swarms/structs/load_balancer.py index f0038335..5e0178d7 100644 --- a/swarms/structs/load_balancer.py +++ b/swarms/structs/load_balancer.py @@ -1,5 +1,6 @@ -from typing import Optional, List import multiprocessing as mp +from typing import List, Optional + from swarms.structs.base import BaseStructure diff --git a/swarms/structs/long_swarm.py b/swarms/structs/long_swarm.py new file mode 100644 index 00000000..e24a3e08 --- /dev/null +++ b/swarms/structs/long_swarm.py @@ -0,0 +1,151 @@ +from typing import List + +from swarms.structs.agent import Agent +from swarms.utils.parse_code import extract_code_from_markdown + + +class LongContextSwarmLeader: + """ + Represents a leader in a long context swarm. + + Args: + - llm (str): The language model to use for the agent. + - agents (List[Agent]): The agents in the swarm. + - prompt_template_json (str): The SOP template in JSON format. + - return_parsed (bool): Whether to return the parsed output. + + """ + + def __init__( + self, + llm, + agents: List[Agent] = None, + prompt_template_json: str = None, + return_parsed: bool = False, + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + self.llm = llm + self.agents = agents + self.prompt_template_json = prompt_template_json + self.return_parsed = return_parsed + + # Create an instance of the Agent class + self.agent = Agent( + llm=llm, + system_prompt=None, + sop=self.prompt_template_json, + *args, + **kwargs, + ) + + def prep_schema(self, task: str, *args, **kwargs): + """ + Returns a formatted string containing the metadata of all agents in the swarm. + + Parameters: + - task (str): The description of the task. + + Returns: + - prompt (str): The formatted string containing the agent metadata. + """ + prompt = f""" + + You need to recruit a team of members to solve a + task. Select the appropriate member based on the + task description: + + # Task Description + {task} + + # Members + + Your output must follow this JSON schema below in markdown format: + {{ + "agent_id": "string", + "agent_name": "string", + "agent_description": "string" + }} + + """ + for agent in self.agents: + prompt += ( + f"Member Name: {agent.ai_name}\nMember ID:" + f" {agent.id}\nMember Description:" + f" {agent.description}\n\n" + ) + + return prompt + + def prep_schema_second(self, task_description: str, task: str): + prompt = f""" + You are the leader of a team of {len(self.agents)} + members. Your team will need to collaborate to + solve a task. The rule is: + + 1. Only you know the task description and task + objective; the other members do not. + 2. But they will receive different documents that + may contain answers, and you need to send them + an instruction to query their document. + 3. Your instruction need to include your + understanding of the task and what you need them + to focus on. If necessary, your instructions can + explicitly include the task objective. + 4. Finally, you need to complete the task based on + the query results they return. + + # Task Description: + {task_description} + + # Task Objective: + {task} + + # Generate Instruction for Members: + Now, you need to generate an instruction for all + team members. You can ask them to answer a + certain question, or to extract information related + to the task, based on their respective documents. + Your output must following the JSON + format: {{"type": "instruction", "content": + "your_instruction_content"}} + + """ + return prompt + + def run(self, task: str, *args, **kwargs): + """ + Executes the specified task using the agent's run method. + + Args: + task: The task to be executed. + *args: Additional positional arguments for the task. + **kwargs: Additional keyword arguments for the task. + + Returns: + The result of the task execution. + """ + task = self.prep_schema(task) + out = self.agent.run(task, *args, **kwargs) + + if self.return_parsed: + out = extract_code_from_markdown(out) + + return out + + +# class LongContextSwarm(BaseSwarm): +# def __init__( +# self, +# agents: List[Agent], +# Leader: Agent, +# team_loops: int, +# *args, +# **kwargs, +# ): +# super().__init__() +# self.agents = agents +# self.leader = Leader +# self.team_loops = team_loops +# self.chunks = len(agents) diff --git a/swarms/structs/majority_voting.py b/swarms/structs/majority_voting.py index c911b9f0..a2b414ba 100644 --- a/swarms/structs/majority_voting.py +++ b/swarms/structs/majority_voting.py @@ -1,5 +1,27 @@ +import asyncio +import concurrent.futures import re +import sys from collections import Counter +from multiprocessing import Pool +from typing import Any, List + +from loguru import logger + +from swarms.structs.agent import Agent +from swarms.structs.conversation import Conversation + +# Configure loguru logger with advanced settings +logger.remove() +logger.add( + sys.stderr, + colorize=True, + format="{time} {message}", + backtrace=True, + diagnose=True, + enqueue=True, + catch=True, +) def extract_last_python_code_block(text): @@ -95,3 +117,150 @@ def majority_voting(answers: list): counter = Counter(answers) answer = counter.most_common(1)[0][0] return answer + + +class MajorityVoting: + """ + Class representing a majority voting system for agents. + + Args: + agents (List[Agent]): A list of agents to use in the majority voting system. + concurrent (bool, optional): Whether to run the agents concurrently. Defaults to False. + multithreaded (bool, optional): Whether to run the agents using multithreading. Defaults to False. + multiprocess (bool, optional): Whether to run the agents using multiprocessing. Defaults to False. + asynchronous (bool, optional): Whether to run the agents asynchronously. Defaults to False. + output_parser (callable, optional): A callable function to parse the output of the majority voting system. Defaults to None. + + Examples: + >>> from swarms.structs.agent import Agent + >>> from swarms.structs.majority_voting import MajorityVoting + >>> agents = [ + ... Agent("GPT-3"), + ... Agent("Codex"), + ... Agent("Tabnine"), + ... ] + >>> majority_voting = MajorityVoting(agents) + >>> majority_voting.run("What is the capital of France?") + 'Paris' + + """ + + def __init__( + self, + agents: List[Agent], + concurrent: bool = False, + multithreaded: bool = False, + multiprocess: bool = False, + asynchronous: bool = False, + output_parser: callable = None, + autosave: bool = False, + verbose: bool = False, + *args, + **kwargs, + ): + self.agents = agents + self.concurrent = concurrent + self.multithreaded = multithreaded + self.multiprocess = multiprocess + self.asynchronous = asynchronous + self.output_parser = output_parser + self.autosave = autosave + self.verbose = verbose + + self.conversation = Conversation( + time_enabled=True, *args, **kwargs + ) + + # If autosave is enabled, save the conversation to a file + if self.autosave: + self.conversation.save() + + # Log the agents + logger.info("Initializing majority voting system") + # Length of agents + logger.info(f"Number of agents: {len(self.agents)}") + logger.info( + "Agents:" + f" {', '.join(agent.agent_name for agent in self.agents)}" + ) + + def run(self, task: str, *args, **kwargs) -> List[Any]: + """ + Runs the majority voting system and returns the majority vote. + + Args: + task (str): The task to be performed by the agents. + *args: Variable length argument list. + **kwargs: Arbitrary keyword arguments. + + Returns: + List[Any]: The majority vote. + + """ + # Route to each agent + if self.concurrent: + with concurrent.futures.ThreadPoolExecutor() as executor: + # Log the agents + logger.info("Running agents concurrently") + futures = [ + executor.submit(agent.run, task, *args) + for agent in self.agents + ] + results = [ + future.result() + for future in concurrent.futures.as_completed( + futures + ) + ] + elif self.multithreaded: + logger.info("Running agents using multithreading") + with concurrent.futures.ThreadPoolExecutor() as executor: + results = [ + executor.submit(agent.run, task, *args) + for agent in self.agents + ] + results = [future.result() for future in results] + elif self.multiprocess: + logger.info("Running agents using multiprocessing") + with Pool() as pool: + results = pool.starmap( + Agent.run, + [(agent, task, *args) for agent in self.agents], + ) + elif self.asynchronous: + loop = asyncio.get_event_loop() + tasks = [ + loop.run_in_executor(None, agent.run, task, *args) + for agent in self.agents + ] + results = loop.run_until_complete(asyncio.gather(*tasks)) + loop.close() + else: + results = [ + agent.run(task, *args) for agent in self.agents + ] + + # Add responses to conversation and log them + for agent, response in zip(self.agents, results): + logger.info(f"[{agent.agent_id}][{response}]") + + response = ( + response if isinstance(response, list) else [response] + ) + self.conversation.add(agent.agent_name, response) + logger.info(f"[{agent.agent_id}][{response}]") + + # Perform majority voting on the conversation + majority_vote = majority_voting(self.conversation.responses) + + # Log the majority vote + logger.info(f"Majority vote: {majority_vote}") + + # If an output parser is provided, parse the output + if self.output_parser: + majority_vote = self.output_parser( + majority_vote, *args, **kwargs + ) + + # Return the majority vote + return majority_vote diff --git a/swarms/structs/message_pool.py b/swarms/structs/message_pool.py new file mode 100644 index 00000000..37dbb19e --- /dev/null +++ b/swarms/structs/message_pool.py @@ -0,0 +1,214 @@ +import hashlib +from time import time_ns +from typing import Callable, List, Optional, Sequence, Union + +from swarms.structs.agent import Agent +from swarms.structs.base_swarm import BaseSwarm +from swarms.utils.loguru_logger import logger + + +def _hash(input: str): + """ + Hashes the input string using SHA256 algorithm. + + Args: + input (str): The string to be hashed. + + Returns: + str: The hexadecimal representation of the hash value. + """ + hex_dig = hashlib.sha256(input.encode("utf-8")).hexdigest() + return hex_dig + + +def msg_hash( + agent: Agent, content: str, turn: int, msg_type: str = "text" +): + """ + Generate a hash value for a message. + + Args: + agent (Agent): The agent sending the message. + content (str): The content of the message. + turn (int): The turn number of the message. + msg_type (str, optional): The type of the message. Defaults to "text". + + Returns: + int: The hash value of the message. + """ + time = time_ns() + return _hash( + f"agent: {agent.agent_name}\ncontent: {content}\ntimestamp:" + f" {str(time)}\nturn: {turn}\nmsg_type: {msg_type}" + ) + + +class MessagePool(BaseSwarm): + """ + A class representing a message pool for agents in a swarm. + + Attributes: + agents (Optional[Sequence[Agent]]): The list of agents in the swarm. + moderator (Optional[Agent]): The moderator agent. + turns (Optional[int]): The number of turns. + routing_function (Optional[Callable]): The routing function for message distribution. + show_names (Optional[bool]): Flag indicating whether to show agent names. + messages (List[Dict]): The list of messages in the pool. + + Examples: + >>> from swarms.structs.agent import Agent + >>> from swarms.structs.message_pool import MessagePool + >>> agent1 = Agent(agent_name="agent1") + >>> agent2 = Agent(agent_name="agent2") + >>> agent3 = Agent(agent_name="agent3") + >>> moderator = Agent(agent_name="moderator") + >>> agents = [agent1, agent2, agent3] + >>> message_pool = MessagePool(agents=agents, moderator=moderator, turns=5) + >>> message_pool.add(agent=agent1, content="Hello, agent2!", turn=1) + >>> message_pool.add(agent=agent2, content="Hello, agent1!", turn=1) + >>> message_pool.add(agent=agent3, content="Hello, agent1!", turn=1) + >>> message_pool.get_all_messages() + [{'agent': Agent(agent_name='agent1'), 'content': 'Hello, agent2!', 'turn': 1, 'visible_to': 'all', 'logged': True}, {'agent': Agent(agent_name='agent2'), 'content': 'Hello, agent1!', 'turn': 1, 'visible_to': 'all', 'logged': True}, {'agent': Agent(agent_name='agent3'), 'content': 'Hello, agent1!', 'turn': 1, 'visible_to': 'all', 'logged': True}] + >>> message_pool.get_visible_messages(agent=agent1, turn=1) + [{'agent': Agent(agent_name='agent1'), 'content': 'Hello, agent2!', 'turn': 1, 'visible_to': 'all', 'logged': True}, {'agent': Agent(agent_name='agent2'), 'content': 'Hello, agent1!', 'turn': 1, 'visible_to': 'all', 'logged': True}, {'agent': Agent(agent_name='agent3'), 'content': 'Hello, agent1!', 'turn': 1, 'visible_to': 'all', 'logged': True}] + >>> message_pool.get_visible_messages(agent=agent2, turn=1) + [{'agent': Agent(agent_name='agent1'), 'content': 'Hello, agent2!', 'turn': 1, 'visible_to': 'all', 'logged': True}, {'agent': Agent(agent_name='agent2'), 'content': 'Hello, agent1!', 'turn': 1, 'visible_to': 'all', 'logged': True}, {'agent': Agent(agent_name='agent3'), 'content': 'Hello, agent1!', 'turn': 1, 'visible_to': 'all', 'logged': True}] + """ + + def __init__( + self, + agents: Optional[Sequence[Agent]] = None, + moderator: Optional[Agent] = None, + turns: Optional[int] = 5, + routing_function: Optional[Callable] = None, + show_names: Optional[bool] = False, + autosave: Optional[bool] = False, + *args, + **kwargs, + ): + super().__init__() + + self.agent = agents + self.moderator = moderator + self.turns = turns + self.routing_function = routing_function + self.show_names = show_names + self.autosave = autosave + + self.messages = [] + + logger.info("MessagePool initialized") + logger.info(f"Number of agents: {len(agents)}") + logger.info( + f"Agents: {[agent.agent_name for agent in agents]}" + ) + logger.info(f"moderator: {moderator.agent_name} is available") + logger.info(f"Number of turns: {turns}") + + def add( + self, + agent: Agent, + content: str, + turn: int, + visible_to: Union[str, List[str]] = "all", + logged: bool = True, + ): + """ + Add a message to the pool. + + Args: + agent (Agent): The agent sending the message. + content (str): The content of the message. + turn (int): The turn number. + visible_to (Union[str, List[str]], optional): The agents who can see the message. Defaults to "all". + logged (bool, optional): Flag indicating whether the message should be logged. Defaults to True. + """ + + self.messages.append( + { + "agent": agent, + "content": content, + "turn": turn, + "visible_to": visible_to, + "logged": logged, + } + ) + logger.info(f"Message added: {content}") + + def reset(self): + """ + Reset the message pool. + """ + self.messages = [] + logger.info("MessagePool reset") + + def last_turn(self): + """ + Get the last turn number. + + Returns: + int: The last turn number. + """ + if len(self.messages) == 0: + return 0 + else: + return self.messages[-1]["turn"] + + @property + def last_message(self): + """ + Get the last message in the pool. + + Returns: + dict: The last message. + """ + if len(self.messages) == 0: + return None + else: + return self.messages[-1] + + def get_all_messages(self): + """ + Get all messages in the pool. + + Returns: + List[Dict]: The list of all messages. + """ + return self.messages + + def get_visible_messages(self, agent: Agent, turn: int): + """ + Get the visible messages for a given agent and turn. + + Args: + agent (Agent): The agent. + turn (int): The turn number. + + Returns: + List[Dict]: The list of visible messages. + """ + # Get the messages before the current turn + prev_messages = [ + message + for message in self.messages + if message["turn"] < turn + ] + + visible_messages = [] + for message in prev_messages: + if ( + message["visible_to"] == "all" + or agent.agent_name in message["visible_to"] + ): + visible_messages.append(message) + return visible_messages + + def query(self, query: str): + """ + Query a message from the messages list and then pass it to the moderator + """ + return [ + (mod, content) + for mod, content in self.messages + if mod == self.moderator + ] diff --git a/swarms/structs/model_parallizer.py b/swarms/structs/model_parallizer.py index 828d4ef4..9d27f14c 100644 --- a/swarms/structs/model_parallizer.py +++ b/swarms/structs/model_parallizer.py @@ -96,7 +96,7 @@ class ModelParallelizer: @classmethod def load_llms_from_file(cls, filename): """Load llms from file""" - with open(filename, "r") as file: + with open(filename) as file: llms = [line.strip() for line in file.readlines()] return cls(llms) diff --git a/swarms/structs/multi_agent_collab.py b/swarms/structs/multi_agent_collab.py index 64b030d0..8359068d 100644 --- a/swarms/structs/multi_agent_collab.py +++ b/swarms/structs/multi_agent_collab.py @@ -299,7 +299,7 @@ class MultiAgentCollaboration: def load(self): """Loads the state of all agents.""" - with open(self.saved_file_path_name, "r") as file: + with open(self.saved_file_path_name) as file: state = json.load(file) self._step = state["step"] self.results = state["results"] diff --git a/swarms/structs/multi_agent_rag.py b/swarms/structs/multi_agent_rag.py deleted file mode 100644 index 91d8c39d..00000000 --- a/swarms/structs/multi_agent_rag.py +++ /dev/null @@ -1,85 +0,0 @@ -from dataclasses import dataclass -from typing import List, Optional - -from swarms.memory.base_vectordatabase import AbstractVectorDatabase -from swarms.structs.agent import Agent - - -@dataclass -class MultiAgentRag: - """ - Represents a multi-agent RAG (Relational Agent Graph) structure. - - Attributes: - agents (List[Agent]): List of agents in the multi-agent RAG. - db (AbstractVectorDatabase): Database used for querying. - verbose (bool): Flag indicating whether to print verbose output. - """ - - agents: List[Agent] - db: AbstractVectorDatabase - verbose: bool = False - - def query_database(self, query: str): - """ - Queries the database using the given query string. - - Args: - query (str): The query string. - - Returns: - List: The list of results from the database. - """ - results = [] - for agent in self.agents: - agent_results = agent.long_term_memory_prompt(query) - results.extend(agent_results) - return results - - def get_agent_by_id(self, agent_id) -> Optional[Agent]: - """ - Retrieves an agent from the multi-agent RAG by its ID. - - Args: - agent_id: The ID of the agent to retrieve. - - Returns: - Agent or None: The agent with the specified ID, or None if not found. - """ - for agent in self.agents: - if agent.agent_id == agent_id: - return agent - return None - - def add_message( - self, sender: Agent, message: str, *args, **kwargs - ): - """ - Adds a message to the database. - - Args: - sender (Agent): The agent sending the message. - message (str): The message to add. - *args: Additional positional arguments. - **kwargs: Additional keyword arguments. - - Returns: - int: The ID of the added message. - """ - doc = f"{sender.ai_name}: {message}" - - return self.db.add(doc) - - def query(self, message: str, *args, **kwargs): - """ - Queries the database using the given message. - - Args: - message (str): The message to query. - *args: Additional positional arguments. - **kwargs: Additional keyword arguments. - - Returns: - List: The list of results from the database. - """ - return self.db.query(message) diff --git a/swarms/structs/multi_process_workflow.py b/swarms/structs/multi_process_workflow.py new file mode 100644 index 00000000..39c69eaa --- /dev/null +++ b/swarms/structs/multi_process_workflow.py @@ -0,0 +1,197 @@ +import logging +from functools import wraps +from multiprocessing import Manager, Pool, cpu_count +from time import sleep +from typing import List + +from swarms.structs.base_workflow import BaseWorkflow +from swarms.structs.task import Task + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", +) + + +# Retry on failure +def retry_on_failure(max_retries: int = 3, delay: int = 5): + """ + Decorator that retries a function a specified number of times on failure. + + Args: + max_retries (int): The maximum number of retries (default: 3). + delay (int): The delay in seconds between retries (default: 5). + + Returns: + The result of the function if it succeeds within the maximum number of retries, + otherwise None. + """ + + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + for _ in range(max_retries): + try: + return func(*args, **kwargs) + except Exception as error: + logging.error( + f"Error: {str(error)}, retrying in" + f" {delay} seconds..." + ) + sleep(delay) + return None + + return wrapper + + return decorator + + +class MultiProcessingWorkflow(BaseWorkflow): + """ + Initialize a MultiProcessWorkflow object. + + Args: + max_workers (int): The maximum number of workers to use for parallel processing. + autosave (bool): Flag indicating whether to automatically save the workflow. + tasks (List[Task]): A list of Task objects representing the workflow tasks. + *args: Additional positional arguments. + **kwargs: Additional keyword arguments. + + Example: + >>> from swarms.structs.multi_process_workflow import MultiProcessingWorkflow + >>> from swarms.structs.task import Task + >>> from datetime import datetime + >>> from time import sleep + >>> + >>> # Define a simple task + >>> def simple_task(): + >>> sleep(1) + >>> return datetime.now() + >>> + >>> # Create a task object + >>> task = Task( + >>> name="Simple Task", + >>> execute=simple_task, + >>> priority=1, + >>> ) + >>> + >>> # Create a workflow with the task + >>> workflow = MultiProcessingWorkflow(tasks=[task]) + >>> + >>> # Run the workflow + >>> results = workflow.run(task) + >>> + >>> # Print the results + >>> print(results) + """ + + def __init__( + self, + max_workers: int = 5, + autosave: bool = True, + tasks: List[Task] = None, + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + self.max_workers = max_workers + self.autosave = autosave + self.tasks = sorted( + tasks or [], key=lambda task: task.priority, reverse=True + ) + + self.max_workers or cpu_count() + + if tasks is None: + tasks = [] + + self.tasks = tasks + + def execute_task(self, task: Task, *args, **kwargs): + """Execute a task and handle exceptions. + + Args: + task (Task): The task to execute. + *args: Additional positional arguments for the task execution. + **kwargs: Additional keyword arguments for the task execution. + + Returns: + Any: The result of the task execution. + + """ + try: + result = task.execute(*args, **kwargs) + + logging.info( + f"Task {task} completed successfully with result" + f" {result}" + ) + + if self.autosave: + self._autosave_task_result(task, result) + + except Exception as e: + logging.error( + ( + "An error occurred during execution of task" + f" {task}: {str(e)}" + ), + exc_info=True, + ) + return None + + def run(self, task: Task, *args, **kwargs): + """Run the workflow. + + Args: + task (Task): The task to run. + *args: Additional positional arguments for the task execution. + **kwargs: Additional keyword arguments for the task execution. + + Returns: + List[Any]: The results of all executed tasks. + + """ + try: + results = [] + with Manager() as manager: + with Pool( + processes=self.max_workers, *args, **kwargs + ) as pool: + # Using manager.list() to collect results in a process safe way + results_list = manager.list() + jobs = [ + pool.apply_async( + self.execute_task, + (task,), + callback=results_list.append, + timeout=task.timeout, + *args, + **kwargs, + ) + for task in self.tasks + ] + + # Wait for all jobs to complete + for job in jobs: + job.get() + + results = list(results_list) + + return results + except Exception as error: + logging.error(f"Error in run: {error}") + return None + + def _autosave_task_result(self, task: Task, result): + """Autosave task result. This should be adapted based on how autosaving is implemented. + + Args: + task (Task): The task for which to autosave the result. + result (Any): The result of the task execution. + + """ + # Note: This method might need to be adapted to ensure it's process-safe, depending on how autosaving is implemented. + logging.info(f"Autosaving result for task {task}: {result}") + # Actual autosave logic here diff --git a/swarms/structs/multi_threaded_workflow.py b/swarms/structs/multi_threaded_workflow.py new file mode 100644 index 00000000..475251ba --- /dev/null +++ b/swarms/structs/multi_threaded_workflow.py @@ -0,0 +1,158 @@ +import logging +import queue +import threading +from concurrent.futures import ( + FIRST_COMPLETED, + ThreadPoolExecutor, + wait, +) +from typing import List + +from swarms.structs.base_workflow import BaseWorkflow +from swarms.structs.task import Task + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", +) + + +class PriorityTask: + """ + Represents a task with a priority level. + + Attributes: + task (Task): The task to be executed. + priority (int): The priority level of the task. + """ + + def __init__(self, task: Task, priority: int = 0): + self.task = task + self.priority = priority + + def __lt__(self, other): + return self.priority < other.priority + + +class MultiThreadedWorkflow(BaseWorkflow): + """ + Represents a multi-threaded workflow that executes tasks concurrently using a thread pool. + + Args: + max_workers (int): The maximum number of worker threads in the thread pool. Default is 5. + autosave (bool): Flag indicating whether to automatically save task results. Default is True. + tasks (List[PriorityTask]): List of priority tasks to be executed. Default is an empty list. + retry_attempts (int): The maximum number of retry attempts for failed tasks. Default is 3. + *args: Variable length argument list. + **kwargs: Arbitrary keyword arguments. + + Attributes: + max_workers (int): The maximum number of worker threads in the thread pool. + autosave (bool): Flag indicating whether to automatically save task results. + retry_attempts (int): The maximum number of retry attempts for failed tasks. + tasks_queue (PriorityQueue): The queue that holds the priority tasks. + lock (Lock): The lock used for thread synchronization. + + Methods: + execute_tasks: Executes the tasks in the thread pool and returns the results. + _autosave_task_result: Autosaves the result of a task. + + """ + + def __init__( + self, + max_workers: int = 5, + autosave: bool = True, + tasks: List[PriorityTask] = None, + retry_attempts: int = 3, + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + self.max_workers = max_workers + self.autosave = autosave + self.retry_attempts = retry_attempts + if tasks is None: + tasks = [] + self.tasks_queue = queue.PriorityQueue() + for task in tasks: + self.tasks_queue.put(task) + self.lock = threading.Lock() + + def run(self): + """ + Executes the tasks in the thread pool and returns the results. + + Returns: + List: The list of results from the executed tasks. + + """ + results = [] + with ThreadPoolExecutor( + max_workers=self.max_workers + ) as executor: + future_to_task = {} + for _ in range(self.tasks_queue.qsize()): + priority_task = self.tasks_queue.get_nowait() + future = executor.submit(priority_task.task.execute) + future_to_task[future] = ( + priority_task.task, + 0, + ) # (Task, attempt) + + while future_to_task: + # Wait for the next future to complete + done, _ = wait( + future_to_task.keys(), return_when=FIRST_COMPLETED + ) + + for future in done: + task, attempt = future_to_task.pop(future) + try: + result = future.result() + results.append(result) + logging.info( + f"Task {task} completed successfully with" + f" result: {result}" + ) + if self.autosave: + self._autosave_task_result(task, result) + except Exception as e: + logging.error( + ( + f"Attempt {attempt+1} failed for task" + f" {task}: {str(e)}" + ), + exc_info=True, + ) + if attempt + 1 < self.retry_attempts: + # Retry the task + retry_future = executor.submit( + task.execute + ) + future_to_task[retry_future] = ( + task, + attempt + 1, + ) + else: + logging.error( + f"Task {task} failed after" + f" {self.retry_attempts} attempts." + ) + + return results + + def _autosave_task_result(self, task: Task, result): + """ + Autosaves the result of a task. + + Args: + task (Task): The task whose result needs to be autosaved. + result: The result of the task. + + """ + with self.lock: + logging.info( + f"Autosaving result for task {task}: {result}" + ) + # Actual autosave logic goes here diff --git a/swarms/structs/nonlinear_workflow.py b/swarms/structs/nonlinear_workflow.py index 0fc1d200..d86ef028 100644 --- a/swarms/structs/nonlinear_workflow.py +++ b/swarms/structs/nonlinear_workflow.py @@ -1,5 +1,5 @@ -from swarms.structs.task import Task from swarms.structs.base import BaseStructure +from swarms.structs.task import Task from swarms.utils.logger import logger # noqa: F401 diff --git a/swarms/structs/recursive_workflow.py b/swarms/structs/recursive_workflow.py index afeb91b7..60d33fe4 100644 --- a/swarms/structs/recursive_workflow.py +++ b/swarms/structs/recursive_workflow.py @@ -1,10 +1,9 @@ +import logging from typing import List from swarms.structs.base import BaseStructure from swarms.structs.task import Task -import logging - logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) diff --git a/swarms/structs/schemas.py b/swarms/structs/schemas.py index f7f5441e..f4cf6a3b 100644 --- a/swarms/structs/schemas.py +++ b/swarms/structs/schemas.py @@ -1,7 +1,7 @@ from __future__ import annotations from enum import Enum -from typing import Any, List, Optional +from typing import Any from pydantic import BaseModel, Field @@ -34,7 +34,7 @@ class Artifact(BaseModel): file_name: str = Field( ..., description="Filename of the artifact", example="main.py" ) - relative_path: Optional[str] = Field( + relative_path: str | None = Field( None, description=( "Relative path of the artifact in the agent's workspace" @@ -45,7 +45,7 @@ class Artifact(BaseModel): class ArtifactUpload(BaseModel): file: bytes = Field(..., description="File to upload") - relative_path: Optional[str] = Field( + relative_path: str | None = Field( None, description=( "Relative path of the artifact in the agent's workspace" @@ -77,14 +77,14 @@ class StepOutput(BaseModel): class TaskRequestBody(BaseModel): - input: Optional[str] = Field( + input: str | None = Field( None, description="Input prompt for the task.", example=( "Write the words you receive to the file 'output.txt'." ), ) - additional_input: Optional[TaskInput] = None + additional_input: TaskInput | None = None class Task(TaskRequestBody): @@ -93,7 +93,7 @@ class Task(TaskRequestBody): description="The ID of the task.", example="50da533e-3904-4401-8a07-c49adf88b5eb", ) - artifacts: List[Artifact] = Field( + artifacts: list[Artifact] = Field( [], description="A list of artifacts that the task has produced.", example=[ @@ -104,12 +104,12 @@ class Task(TaskRequestBody): class StepRequestBody(BaseModel): - input: Optional[str] = Field( + input: str | None = Field( None, description="Input prompt for the step.", example="Washington", ) - additional_input: Optional[StepInput] = None + additional_input: StepInput | None = None class Status(Enum): @@ -129,7 +129,7 @@ class Step(StepRequestBody): description="The ID of the task step.", example="6bb1801a-fd80-45e8-899a-4dd723cc602e", ) - name: Optional[str] = Field( + name: str | None = Field( None, description="The name of the task step.", example="Write to file", @@ -137,7 +137,7 @@ class Step(StepRequestBody): status: Status = Field( ..., description="The status of the task step." ) - output: Optional[str] = Field( + output: str | None = Field( None, description="Output of the task step.", example=( @@ -146,12 +146,12 @@ class Step(StepRequestBody): " None: """Resets the workflow by clearing the results of each task.""" @@ -144,217 +174,65 @@ class SequentialWorkflow: ), ) - def save_workflow_state( - self, - filepath: Optional[str] = "sequential_workflow_state.json", - **kwargs, - ) -> None: - """ - Saves the workflow state to a json file. - - Args: - filepath (str): The path to save the workflow state to. - - Examples: - >>> from swarms.models import OpenAIChat - >>> from swarms.structs import SequentialWorkflow - >>> llm = OpenAIChat(openai_api_key="") - >>> workflow = SequentialWorkflow(max_loops=1) - >>> workflow.add("What's the weather in miami", llm) - >>> workflow.add("Create a report on these metrics", llm) - >>> workflow.save_workflow_state("sequential_workflow_state.json") - """ - try: - filepath = filepath or self.saved_state_filepath - - with open(filepath, "w") as f: - # Saving the state as a json for simplicuty - state = { - "task_pool": [ - { - "description": task.description, - "args": task.args, - "kwargs": task.kwargs, - "result": task.result, - "history": task.history, - } - for task in self.task_pool - ], - "max_loops": self.max_loops, - } - json.dump(state, f, indent=4) - - logger.info( - "[INFO][SequentialWorkflow] Saved workflow state to" - f" {filepath}" - ) - except Exception as error: - logger.error( - colored( - f"Error saving workflow state: {error}", - "red", - ) - ) - - def workflow_bootup(self, **kwargs) -> None: - """ - Workflow bootup. - - """ - print( - colored( - """ - Sequential Workflow Initializing...""", - "green", - attrs=["bold", "underline"], - ) - ) - - def workflow_dashboard(self, **kwargs) -> None: - """ - Displays a dashboard for the workflow. - - Args: - **kwargs: Additional keyword arguments to pass to the dashboard. - - Examples: - >>> from swarms.models import OpenAIChat - >>> from swarms.structs import SequentialWorkflow - >>> llm = OpenAIChat(openai_api_key="") - >>> workflow = SequentialWorkflow(max_loops=1) - >>> workflow.add("What's the weather in miami", llm) - >>> workflow.add("Create a report on these metrics", llm) - >>> workflow.workflow_dashboard() - - """ - print( - colored( - f""" - Sequential Workflow Dashboard - -------------------------------- - Name: {self.name} - Description: {self.description} - task_pool: {len(self.task_pool)} - Max Loops: {self.max_loops} - Autosave: {self.autosave} - Autosave Filepath: {self.saved_state_filepath} - Restore Filepath: {self.restore_state_filepath} - -------------------------------- - Metadata: - kwargs: {kwargs} - """, - "cyan", - attrs=["bold", "underline"], - ) - ) - - def workflow_shutdown(self, **kwargs) -> None: - """Shuts down the workflow.""" - print( - colored( - """ - Sequential Workflow Shutdown...""", - "red", - attrs=["bold", "underline"], - ) - ) - - def load_workflow_state( - self, filepath: str = None, **kwargs - ) -> None: - """ - Loads the workflow state from a json file and restores the workflow state. - - Args: - filepath (str): The path to load the workflow state from. - - Examples: - >>> from swarms.models import OpenAIChat - >>> from swarms.structs import SequentialWorkflow - >>> llm = OpenAIChat(openai_api_key="") - >>> workflow = SequentialWorkflow(max_loops=1) - >>> workflow.add("What's the weather in miami", llm) - >>> workflow.add("Create a report on these metrics", llm) - >>> workflow.save_workflow_state("sequential_workflow_state.json") - >>> workflow.load_workflow_state("sequential_workflow_state.json") - - """ - try: - filepath = filepath or self.restore_state_filepath - - with open(filepath, "r") as f: - state = json.load(f) - self.max_loops = state["max_loops"] - self.task_pool = [] - for task_state in state["task_pool"]: - task = Task( - description=task_state["description"], - agent=task_state["agent"], - args=task_state["args"], - kwargs=task_state["kwargs"], - result=task_state["result"], - history=task_state["history"], - ) - self.task_pool.append(task) - - print( - "[INFO][SequentialWorkflow] Loaded workflow state" - f" from {filepath}" - ) - except Exception as error: - logger.error( - colored( - f"Error loading workflow state: {error}", - "red", - ) - ) - def run(self) -> None: """ Run the workflow. Raises: - ValueError: If a Agent instance is used as a task and the 'task' argument is not provided. + ValueError: If an Agent instance is used as a task and the 'task' argument is not provided. """ - try: - self.workflow_bootup() - loops = 0 - while loops < self.max_loops: - for i in range(len(self.task_pool)): - task = self.task_pool[i] - # Check if the current task can be executed - if task.result is None: - # Get the inputs for the current task - task.context(task) - - result = task.execute() - - # Pass the inputs to the next task - if i < len(self.task_pool) - 1: - next_task = self.task_pool[i + 1] - next_task.description = result - - # Execute the current task - task.execute() - - # Autosave the workflow state - if self.autosave: - self.save_workflow_state( - "sequential_workflow_state.json" - ) - - self.workflow_shutdown() - loops += 1 - except Exception as e: - logger.error( - colored( - ( - "Error initializing the Sequential workflow:" - f" {e} try optimizing your inputs like the" - " agent class and task description" - ), - "red", - attrs=["bold", "underline"], - ) - ) + self.workflow_bootup() + loops = 0 + while loops < self.max_loops: + for i, agent in enumerate(self.agents): + logger.info(f"Agent {i+1} is executing the task.") + out = agent(self.description) + self.conversation.add(agent.agent_name, str(out)) + prompt = self.conversation.return_history_as_string() + print(prompt) + print("Next agent...........") + out = agent(prompt) + + return out + # try: + # self.workflow_bootup() + # loops = 0 + # while loops < self.max_loops: + # for i in range(len(self.task_pool)): + # task = self.task_pool[i] + # # Check if the current task can be executed + # if task.result is None: + # # Get the inputs for the current task + # task.context(task) + + # result = task.execute() + + # # Pass the inputs to the next task + # if i < len(self.task_pool) - 1: + # next_task = self.task_pool[i + 1] + # next_task.description = result + + # # Execute the current task + # task.execute() + + # # Autosave the workflow state + # if self.autosave: + # self.save_workflow_state( + # "sequential_workflow_state.json" + # ) + + # self.workflow_shutdown() + # loops += 1 + # except Exception as e: + # logger.error( + # colored( + # ( + # "Error initializing the Sequential workflow:" + # f" {e} try optimizing your inputs like the" + # " agent class and task description" + # ), + # "red", + # attrs=["bold", "underline"], + # ) + # ) diff --git a/swarms/structs/stackoverflow_swarm.py b/swarms/structs/stackoverflow_swarm.py new file mode 100644 index 00000000..1c2f2138 --- /dev/null +++ b/swarms/structs/stackoverflow_swarm.py @@ -0,0 +1,89 @@ +from typing import List + +from swarms.structs.agent import Agent +from swarms.structs.base_multiagent_structure import ( + BaseMultiAgentStructure, +) +from swarms.structs.conversation import Conversation +from swarms.utils.logger import logger + + +class StackOverflowSwarm(BaseMultiAgentStructure): + """ + Represents a swarm of agents that work together to solve a problem or answer a question on Stack Overflow. + + Attributes: + agents (List[Agent]): The list of agents in the swarm. + autosave (bool): Flag indicating whether to automatically save the conversation. + verbose (bool): Flag indicating whether to display verbose output. + save_filepath (str): The filepath to save the conversation. + conversation (Conversation): The conversation object for storing the interactions. + + Examples: + >>> from swarms.structs.agent import Agent + >>> from swarms.structs.stack_overflow_swarm import StackOverflowSwarm + """ + + def __init__( + self, + agents: List[Agent], + autosave: bool = False, + verbose: bool = False, + save_filepath: str = "stack_overflow_swarm.json", + eval_agent: Agent = None, + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + self.agents = agents + self.autosave = autosave + self.verbose = verbose + self.save_filepath = save_filepath + self.eval_agent = eval_agent + + # Configure conversation + self.conversation = Conversation( + time_enabled=True, + autosave=autosave, + save_filepath=save_filepath, + *args, + **kwargs, + ) + + # Counter for the number of upvotes per post + self.upvotes = 0 + + # Counter for the number of downvotes per post + self.downvotes = 0 + + # Forum for the agents to interact + self.forum = [] + + def run(self, task: str, *args, **kwargs): + """ + Run the swarm to solve a problem or answer a question like stack overflow + + Args: + task (str): The task to be performed by the agents. + *args: Variable length argument list. + **kwargs: Arbitrary keyword arguments. + + Returns: + List[str]: The conversation history. + """ + # Add the task to the conversation + self.conversation.add("Human", task) + logger.info(f"Task: {task} Added to the Forum.") + + # Run the agents and get their responses and append to the conversation + for agent in self.agents: + response = agent.run( + self.conversation.return_history_as_string(), + *args, + **kwargs, + ) + # Add to the conversation + self.conversation.add(agent.ai_name, f"{response}") + logger.info(f"[{agent.ai_name}]: [{response}]") + + return self.conversation.return_history_as_string() diff --git a/swarms/structs/swarm_redis_registry.py b/swarms/structs/swarm_redis_registry.py new file mode 100644 index 00000000..a17549cd --- /dev/null +++ b/swarms/structs/swarm_redis_registry.py @@ -0,0 +1,176 @@ +from dataclasses import asdict +from typing import List + +import networkx as nx +import redis +from redis.commands.graph import Graph, Node + +from swarms.structs.agent import Agent +from swarms.structs.base_swarm import AbstractSwarm + + +class SwarmRelationship: + JOINED = "joined" + + +class RedisSwarmRegistry(AbstractSwarm): + """ + Initialize the SwarmRedisRegistry object. + + Args: + host (str): The hostname or IP address of the Redis server. Default is "localhost". + port (int): The port number of the Redis server. Default is 6379. + db: The Redis database number. Default is 0. + graph_name (str): The name of the RedisGraph graph. Default is "swarm_registry". + """ + + def __init__( + self, + host: str = "localhost", + port: int = 6379, + db=0, + graph_name: str = "swarm_registry", + ): + self.redis = redis.StrictRedis( + host=host, port=port, db=db, decode_responses=True + ) + self.redis_graph = Graph(self.redis, graph_name) + self.graph = nx.DiGraph() + + def _entity_to_node(self, entity: Agent | Agent) -> Node: + """ + Converts an Agent or Swarm object to a Node object. + + Args: + entity (Agent | Agent): The Agent or Swarm object to convert. + + Returns: + Node: The converted Node object. + """ + return Node( + node_id=entity.id, + alias=entity.agent_name, + label=entity.agent_description, + properties=asdict(entity), + ) + + def _add_node(self, node: Agent | Agent): + """ + Adds a node to the graph. + + Args: + node (Agent | Agent): The Agent or Swarm node to add. + """ + self.graph.add_node(node.id) + if isinstance(node, Agent): + self.add_swarm_entry(node) + elif isinstance(node, Agent): + self.add_agent_entry(node) + + def _add_edge(self, from_node: Node, to_node: Node, relationship): + """ + Adds an edge between two nodes in the graph. + + Args: + from_node (Node): The source node of the edge. + to_node (Node): The target node of the edge. + relationship: The relationship type between the nodes. + """ + match_query = ( + f"MATCH (a:{from_node.label}),(b:{to_node.label}) WHERE" + f" a.id = {from_node.id} AND b.id = {to_node.id}" + ) + + query = f""" + {match_query} + CREATE (a)-[r:joined]->(b) RETURN r + """.replace("\n", "") + + self.redis_graph.query(query) + + def add_swarm_entry(self, swarm: Agent): + """ + Adds a swarm entry to the graph. + + Args: + swarm (Agent): The swarm object to add. + """ + node = self._entity_to_node(swarm) + self._persist_node(node) + + def add_agent_entry(self, agent: Agent): + """ + Adds an agent entry to the graph. + + Args: + agent (Agent): The agent object to add. + """ + node = self._entity_to_node(agent) + self._persist_node(node) + + def join_swarm( + self, + from_entity: Agent | Agent, + to_entity: Agent, + ): + """ + Adds an edge between two nodes in the graph. + + Args: + from_entity (Agent | Agent): The source entity of the edge. + to_entity (Agent): The target entity of the edge. + + Returns: + Any: The result of adding the edge. + """ + from_node = self._entity_to_node(from_entity) + to_node = self._entity_to_node(to_entity) + + return self._add_edge( + from_node, to_node, SwarmRelationship.JOINED + ) + + def _persist_node(self, node: Node): + """ + Persists a node in the graph. + + Args: + node (Node): The node to persist. + """ + query = f"CREATE {node}" + self.redis_graph.query(query) + + def retrieve_swarm_information(self, swarm_id: int) -> Agent: + """ + Retrieves swarm information from the registry. + + Args: + swarm_id (int): The ID of the swarm to retrieve. + + Returns: + Agent: The retrieved swarm information as an Agent object. + """ + swarm_key = f"swarm:{swarm_id}" + swarm_data = self.redis.hgetall(swarm_key) + if swarm_data: + # Parse the swarm_data and return an instance of AgentBase + # You can use the retrieved data to populate the AgentBase attributes + + return Agent(**swarm_data) + return None + + def retrieve_joined_agents(self) -> List[Agent]: + """ + Retrieves a list of joined agents from the registry. + + Returns: + List[Agent]: The retrieved joined agents as a list of Agent objects. + """ + agent_data = self.redis_graph.query( + "MATCH (a:agent)-[:joined]->(b:manager) RETURN a" + ) + if agent_data: + # Parse the agent_data and return an instance of AgentBase + # You can use the retrieved data to populate the AgentBase attributes + return [Agent(**agent_data) for agent_data in agent_data] + return None diff --git a/swarms/structs/swarming_architectures.py b/swarms/structs/swarming_architectures.py index ad3ad4ed..0f0ff885 100644 --- a/swarms/structs/swarming_architectures.py +++ b/swarms/structs/swarming_architectures.py @@ -1,7 +1,8 @@ +import asyncio import math from typing import List + from swarms.structs.agent import Agent -import asyncio from swarms.utils.logger import logger diff --git a/swarms/structs/task.py b/swarms/structs/task.py index fb89b7bf..5f25eedb 100644 --- a/swarms/structs/task.py +++ b/swarms/structs/task.py @@ -2,17 +2,11 @@ import sched import time from dataclasses import dataclass, field from datetime import datetime -from typing import ( - Any, - Callable, - Dict, - List, - Union, -) +from typing import Any, Callable, Dict, List, Union from swarms.structs.agent import Agent -from swarms.utils.logger import logger from swarms.structs.conversation import Conversation +from swarms.utils.logger import logger @dataclass diff --git a/swarms/structs/task_queue_base.py b/swarms/structs/task_queue_base.py new file mode 100644 index 00000000..968023b0 --- /dev/null +++ b/swarms/structs/task_queue_base.py @@ -0,0 +1,82 @@ +import threading +from abc import ABC, abstractmethod + +from swarms.structs.agent import Agent +from swarms.structs.task import Task + + +def synchronized_queue(method): + """ + Decorator that synchronizes access to the decorated method using a lock. + The lock is acquired before executing the method and released afterwards. + + Args: + method: The method to be decorated. + + Returns: + The decorated method. + """ + timeout_sec = 5 + + def wrapper(self, *args, **kwargs): + with self.lock: + self.lock.acquire(timeout=timeout_sec) + try: + return method(self, *args, **kwargs) + except Exception as e: + print(f"Failed to execute {method.__name__}: {e}") + finally: + self.lock.release() + + return wrapper + + +class TaskQueueBase(ABC): + def __init__(self): + self.lock = threading.Lock() + + @synchronized_queue + @abstractmethod + def add_task(self, task: Task) -> bool: + """Adds a task to the queue. + + Args: + task (Task): The task to be added to the queue. + + Returns: + bool: True if the task was successfully added, False otherwise. + """ + raise NotImplementedError + + @synchronized_queue + @abstractmethod + def get_task(self, agent: Agent) -> Task: + """Gets the next task from the queue. + + Args: + agent (Agent): The agent requesting the task. + + Returns: + Task: The next task from the queue. + """ + raise NotImplementedError + + @synchronized_queue + @abstractmethod + def complete_task(self, task_id: str): + """Sets the task as completed. + + Args: + task_id (str): The ID of the task to be marked as completed. + """ + raise NotImplementedError + + @synchronized_queue + @abstractmethod + def reset_task(self, task_id: str): + """Resets the task if the agent failed to complete it. + + Args: + task_id (str): The ID of the task to be reset. + """ + raise NotImplementedError diff --git a/swarms/structs/test_majority_voting.py b/swarms/structs/test_majority_voting.py new file mode 100644 index 00000000..dcd25f0b --- /dev/null +++ b/swarms/structs/test_majority_voting.py @@ -0,0 +1,152 @@ +from unittest.mock import MagicMock + +import pytest + +from swarms.structs.agent import Agent +from swarms.structs.majority_voting import MajorityVoting + + +def test_majority_voting_run_concurrent(mocker): + # Create mock agents + agent1 = MagicMock(spec=Agent) + agent2 = MagicMock(spec=Agent) + agent3 = MagicMock(spec=Agent) + + # Create mock majority voting + mv = MajorityVoting( + agents=[agent1, agent2, agent3], + concurrent=True, + multithreaded=False, + ) + + # Create mock conversation + conversation = MagicMock() + mv.conversation = conversation + + # Create mock results + results = ["Paris", "Paris", "Lyon"] + + # Mock agent.run method + agent1.run.return_value = results[0] + agent2.run.return_value = results[1] + agent3.run.return_value = results[2] + + # Run majority voting + majority_vote = mv.run("What is the capital of France?") + + # Assert agent.run method was called with the correct task + agent1.run.assert_called_once_with( + "What is the capital of France?" + ) + agent2.run.assert_called_once_with( + "What is the capital of France?" + ) + agent3.run.assert_called_once_with( + "What is the capital of France?" + ) + + # Assert conversation.add method was called with the correct responses + conversation.add.assert_any_call(agent1.agent_name, results[0]) + conversation.add.assert_any_call(agent2.agent_name, results[1]) + conversation.add.assert_any_call(agent3.agent_name, results[2]) + + # Assert majority vote is correct + assert majority_vote is not None + + +def test_majority_voting_run_multithreaded(mocker): + # Create mock agents + agent1 = MagicMock(spec=Agent) + agent2 = MagicMock(spec=Agent) + agent3 = MagicMock(spec=Agent) + + # Create mock majority voting + mv = MajorityVoting( + agents=[agent1, agent2, agent3], + concurrent=False, + multithreaded=True, + ) + + # Create mock conversation + conversation = MagicMock() + mv.conversation = conversation + + # Create mock results + results = ["Paris", "Paris", "Lyon"] + + # Mock agent.run method + agent1.run.return_value = results[0] + agent2.run.return_value = results[1] + agent3.run.return_value = results[2] + + # Run majority voting + majority_vote = mv.run("What is the capital of France?") + + # Assert agent.run method was called with the correct task + agent1.run.assert_called_once_with( + "What is the capital of France?" + ) + agent2.run.assert_called_once_with( + "What is the capital of France?" + ) + agent3.run.assert_called_once_with( + "What is the capital of France?" + ) + + # Assert conversation.add method was called with the correct responses + conversation.add.assert_any_call(agent1.agent_name, results[0]) + conversation.add.assert_any_call(agent2.agent_name, results[1]) + conversation.add.assert_any_call(agent3.agent_name, results[2]) + + # Assert majority vote is correct + assert majority_vote is not None + + +@pytest.mark.asyncio +async def test_majority_voting_run_asynchronous(mocker): + # Create mock agents + agent1 = MagicMock(spec=Agent) + agent2 = MagicMock(spec=Agent) + agent3 = MagicMock(spec=Agent) + + # Create mock majority voting + mv = MajorityVoting( + agents=[agent1, agent2, agent3], + concurrent=False, + multithreaded=False, + asynchronous=True, + ) + + # Create mock conversation + conversation = MagicMock() + mv.conversation = conversation + + # Create mock results + results = ["Paris", "Paris", "Lyon"] + + # Mock agent.run method + agent1.run.return_value = results[0] + agent2.run.return_value = results[1] + agent3.run.return_value = results[2] + + # Run majority voting + majority_vote = await mv.run("What is the capital of France?") + + # Assert agent.run method was called with the correct task + agent1.run.assert_called_once_with( + "What is the capital of France?" + ) + agent2.run.assert_called_once_with( + "What is the capital of France?" + ) + agent3.run.assert_called_once_with( + "What is the capital of France?" + ) + + # Assert conversation.add method was called with the correct responses + conversation.add.assert_any_call(agent1.agent_name, results[0]) + conversation.add.assert_any_call(agent2.agent_name, results[1]) + conversation.add.assert_any_call(agent3.agent_name, results[2]) + + # Assert majority vote is correct + assert majority_vote is not None diff --git a/swarms/structs/tool_json_schema.py b/swarms/structs/tool_json_schema.py index d71df718..a5c0d070 100644 --- a/swarms/structs/tool_json_schema.py +++ b/swarms/structs/tool_json_schema.py @@ -20,7 +20,7 @@ class JSON(ABC): Returns: dict: The loaded JSON schema. """ - with open(self.schema_path, "r") as f: + with open(self.schema_path) as f: return json.load(f) @abstractmethod @@ -34,4 +34,3 @@ class JSON(ABC): Raises: NotImplementedError: This method needs to be implemented by the subclass. """ - pass diff --git a/swarms/structs/utils.py b/swarms/structs/utils.py index 634021e2..dd32b3df 100644 --- a/swarms/structs/utils.py +++ b/swarms/structs/utils.py @@ -1,6 +1,7 @@ -import re import json -from typing import Dict, Any, List, Optional +import re +from typing import Any, Dict, List, Optional + from swarms.structs.agent import Agent diff --git a/swarms/telemetry/__init__.py b/swarms/telemetry/__init__.py index 3a7e61d3..8c13871a 100644 --- a/swarms/telemetry/__init__.py +++ b/swarms/telemetry/__init__.py @@ -3,12 +3,12 @@ from swarms.telemetry.log_all import log_all_calls, log_calls from swarms.telemetry.sys_info import ( get_cpu_info, - get_swarms_verison, get_os_version, get_package_mismatches, get_pip_version, get_python_version, get_ram_info, + get_swarms_verison, system_info, ) from swarms.telemetry.user_utils import ( diff --git a/swarms/telemetry/auto_upgrade_swarms.py b/swarms/telemetry/auto_upgrade_swarms.py index 96f843a7..98e59a59 100644 --- a/swarms/telemetry/auto_upgrade_swarms.py +++ b/swarms/telemetry/auto_upgrade_swarms.py @@ -1,4 +1,5 @@ import subprocess + from swarms.telemetry.check_update import check_for_update diff --git a/swarms/telemetry/bootup.py b/swarms/telemetry/bootup.py index edcd1aca..b5b8a85c 100644 --- a/swarms/telemetry/bootup.py +++ b/swarms/telemetry/bootup.py @@ -1,5 +1,5 @@ -from swarms.utils.disable_logging import disable_logging from swarms.telemetry.auto_upgrade_swarms import auto_update +from swarms.utils.disable_logging import disable_logging def bootup(): diff --git a/swarms/telemetry/check_update.py b/swarms/telemetry/check_update.py index 2cdbd986..2a5df8a9 100644 --- a/swarms/telemetry/check_update.py +++ b/swarms/telemetry/check_update.py @@ -1,10 +1,10 @@ +import importlib.util +import sys + import pkg_resources import requests from packaging import version -import importlib.util -import sys - # borrowed from: https://stackoverflow.com/a/1051266/656011 def check_for_package(package): diff --git a/swarms/telemetry/main.py b/swarms/telemetry/main.py index fe00fecf..9f772bdc 100644 --- a/swarms/telemetry/main.py +++ b/swarms/telemetry/main.py @@ -1,7 +1,8 @@ +import datetime import logging -import pymongo import platform -import datetime + +import pymongo class Telemetry: diff --git a/swarms/telemetry/sys_info.py b/swarms/telemetry/sys_info.py index a4857e11..3669fbbd 100644 --- a/swarms/telemetry/sys_info.py +++ b/swarms/telemetry/sys_info.py @@ -58,7 +58,7 @@ def get_ram_info(): def get_package_mismatches(file_path="pyproject.toml"): - with open(file_path, "r") as file: + with open(file_path) as file: pyproject = toml.load(file) dependencies = pyproject["tool"]["poetry"]["dependencies"] dev_dependencies = pyproject["tool"]["poetry"]["group"]["dev"][ diff --git a/swarms/telemetry/user_utils.py b/swarms/telemetry/user_utils.py index 4d4fb166..32261cfe 100644 --- a/swarms/telemetry/user_utils.py +++ b/swarms/telemetry/user_utils.py @@ -1,9 +1,10 @@ import hashlib import platform -import uuid import socket -from swarms.telemetry.sys_info import system_info +import uuid + from swarms.telemetry.check_update import check_for_package +from swarms.telemetry.sys_info import system_info # Helper functions @@ -43,7 +44,7 @@ def get_system_info(): "ip_address": socket.gethostbyname(socket.gethostname()), "mac_address": ":".join( [ - "{:02x}".format((uuid.getnode() >> elements) & 0xFF) + f"{(uuid.getnode() >> elements) & 0xFF:02x}" for elements in range(0, 2 * 6, 8) ][::-1] ), diff --git a/swarms/tokenizers/__init__.py b/swarms/tokenizers/__init__.py index 02129cb9..d62146ca 100644 --- a/swarms/tokenizers/__init__.py +++ b/swarms/tokenizers/__init__.py @@ -1,15 +1,15 @@ -from swarms.tokenizers.r_tokenizers import ( - SentencePieceTokenizer, - HuggingFaceTokenizer, - Tokenizer, -) -from swarms.tokenizers.base_tokenizer import BaseTokenizer -from swarms.tokenizers.openai_tokenizers import OpenAITokenizer from swarms.tokenizers.anthropic_tokenizer import ( - import_optional_dependency, AnthropicTokenizer, + import_optional_dependency, ) +from swarms.tokenizers.base_tokenizer import BaseTokenizer from swarms.tokenizers.cohere_tokenizer import CohereTokenizer +from swarms.tokenizers.openai_tokenizers import OpenAITokenizer +from swarms.tokenizers.r_tokenizers import ( + HuggingFaceTokenizer, + SentencePieceTokenizer, + Tokenizer, +) __all__ = [ "SentencePieceTokenizer", diff --git a/swarms/tokenizers/anthropic_tokenizer.py b/swarms/tokenizers/anthropic_tokenizer.py index 94bced96..77cd07c3 100644 --- a/swarms/tokenizers/anthropic_tokenizer.py +++ b/swarms/tokenizers/anthropic_tokenizer.py @@ -3,7 +3,6 @@ from __future__ import annotations from dataclasses import dataclass from importlib import import_module from types import ModuleType -from typing import Optional from anthropic import Anthropic @@ -16,7 +15,7 @@ INSTALL_MAPPING = { } -def import_optional_dependency(name: str) -> Optional[ModuleType]: +def import_optional_dependency(name: str) -> ModuleType | None: """Import an optional dependency. If a dependency is missing, an ImportError with a nice message will be raised. diff --git a/swarms/tokenizers/base_tokenizer.py b/swarms/tokenizers/base_tokenizer.py index a14bbd09..fd1bc339 100644 --- a/swarms/tokenizers/base_tokenizer.py +++ b/swarms/tokenizers/base_tokenizer.py @@ -2,7 +2,6 @@ from __future__ import annotations from abc import ABC, abstractmethod from dataclasses import dataclass, field -from typing import List, Union @dataclass @@ -20,12 +19,12 @@ class BaseTokenizer(ABC): stop_token: str = "<|Response|>" def __post_init__(self): - self.stop_sequences: List[str] = field( + self.stop_sequences: list[str] = field( default_factory=lambda: ["<|Response|>"], init=False, ) - def count_tokens_left(self, text: Union[str, List[dict]]) -> int: + def count_tokens_left(self, text: str | list[dict]) -> int: """ Counts the number of tokens left based on the given text. @@ -43,7 +42,7 @@ class BaseTokenizer(ABC): return 0 @abstractmethod - def count_tokens(self, text: Union[str, List[dict]]) -> int: + def count_tokens(self, text: str | list[dict]) -> int: """ Counts the number of tokens in the given text. diff --git a/swarms/tokenizers/cohere_tokenizer.py b/swarms/tokenizers/cohere_tokenizer.py index 7387c836..e6164f5b 100644 --- a/swarms/tokenizers/cohere_tokenizer.py +++ b/swarms/tokenizers/cohere_tokenizer.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass + from cohere import Client diff --git a/swarms/tokenizers/openai_tokenizers.py b/swarms/tokenizers/openai_tokenizers.py index b77a8efd..9b02943b 100644 --- a/swarms/tokenizers/openai_tokenizers.py +++ b/swarms/tokenizers/openai_tokenizers.py @@ -1,9 +1,11 @@ from __future__ import annotations + import logging from dataclasses import dataclass, field + import tiktoken from tiktoken import Encoding -from typing import Optional + from swarms.tokenizers.base_tokenizer import BaseTokenizer @@ -39,7 +41,7 @@ class OpenAITokenizer(BaseTokenizer): Sets the default maximum number of tokens. """ self.max_tokens: int = field( - default_factory=lambda: self.default_max_tokens() + default_factory=self.default_max_tokens ) self.DEFAULT_OPENAI_GPT_3_COMPLETION_MODEL = ( @@ -102,7 +104,7 @@ class OpenAITokenizer(BaseTokenizer): ) - offset def count_tokens( - self, text: str | list[dict], model: Optional[str] = None + self, text: str | list[dict], model: str | None = None ) -> int: """ Counts the number of tokens in the given text. @@ -171,7 +173,7 @@ class OpenAITokenizer(BaseTokenizer): else: return len(self.encoding.encode(text)) - def len(self, text: str | list[dict], model: Optional[str]): + def len(self, text: str | list[dict], model: str | None): """ Returns the length of the text in tokens. If a model is provided, uses that model for encoding. diff --git a/swarms/tokenizers/r_tokenizers.py b/swarms/tokenizers/r_tokenizers.py index cf8253fc..f807b6ff 100644 --- a/swarms/tokenizers/r_tokenizers.py +++ b/swarms/tokenizers/r_tokenizers.py @@ -59,7 +59,7 @@ class SentencePieceTokenizer: def _maybe_add_prefix_space(self, tokens, decoded): """maybe add prefix space for incremental decoding.""" if ( - len(tokens) + tokens and not decoded.startswith(" ") and tokens[0] in self.prefix_space_tokens ): @@ -179,7 +179,7 @@ class HuggingFaceTokenizer: model_dir, "generation_config.json" ) if osp.exists(generation_config_file): - with open(generation_config_file, "r") as f: + with open(generation_config_file) as f: cfg = json.load(f) self.model.eos_token_id = cfg["eos_token_id"] elif hasattr(self.model, "eod_id"): # Qwen remote @@ -228,7 +228,7 @@ class HuggingFaceTokenizer: ): """maybe add prefix space for incremental decoding.""" if ( - len(tokens) + tokens and not decoded.startswith(" ") and tokens[0] in self.prefix_space_tokens ): @@ -300,7 +300,7 @@ class HuggingFaceTokenizer: encoded = self.model.encode(s, **kwargs) if not add_bos: # in the middle of a session - if len(encoded) and encoded[0] == self.bos_token_id: + if encoded and encoded[0] == self.bos_token_id: encoded = encoded[1:] return encoded diff --git a/swarms/tools/__init__.py b/swarms/tools/__init__.py index c36c9608..8d98894a 100644 --- a/swarms/tools/__init__.py +++ b/swarms/tools/__init__.py @@ -1,18 +1,18 @@ -from swarms.tools.tool_func_doc_scraper import scrape_tool_func_docs from swarms.tools.code_executor import CodeExecutor -from swarms.tools.tool_utils import ( - tool_find_by_name, - extract_tool_commands, - parse_and_execute_tools, - execute_tools, -) -from swarms.tools.tool import BaseTool, Tool, StructuredTool, tool from swarms.tools.exec_tool import ( AgentAction, - BaseAgentOutputParser, - preprocess_json_input, AgentOutputParser, + BaseAgentOutputParser, execute_tool_by_name, + preprocess_json_input, +) +from swarms.tools.tool import BaseTool, StructuredTool, Tool, tool +from swarms.tools.tool_func_doc_scraper import scrape_tool_func_docs +from swarms.tools.tool_utils import ( + execute_tools, + extract_tool_commands, + parse_and_execute_tools, + tool_find_by_name, ) __all__ = [ diff --git a/swarms/tools/code_executor.py b/swarms/tools/code_executor.py index 3c369dae..5a85f14d 100644 --- a/swarms/tools/code_executor.py +++ b/swarms/tools/code_executor.py @@ -1,6 +1,6 @@ import os -import tempfile import subprocess +import tempfile class CodeExecutor: diff --git a/swarms/tools/format_tools.py b/swarms/tools/format_tools.py index 2e620135..46565f76 100644 --- a/swarms/tools/format_tools.py +++ b/swarms/tools/format_tools.py @@ -1,13 +1,14 @@ -from typing import List, Union, Dict, Any +import json +from typing import Any, Dict, List, Union + +from termcolor import cprint +from transformers import PreTrainedModel, PreTrainedTokenizer from swarms.tools.logits_processor import ( NumberStoppingCriteria, OutputNumbersTokens, StringStoppingCriteria, ) -from termcolor import cprint -from transformers import PreTrainedModel, PreTrainedTokenizer -import json GENERATION_MARKER = "|GENERATION|" diff --git a/swarms/tools/logits_processor.py b/swarms/tools/logits_processor.py index ed7fef18..f67ff451 100644 --- a/swarms/tools/logits_processor.py +++ b/swarms/tools/logits_processor.py @@ -1,9 +1,9 @@ +import torch from transformers import ( - PreTrainedTokenizer, LogitsWarper, + PreTrainedTokenizer, StoppingCriteria, ) -import torch class StringStoppingCriteria(StoppingCriteria): diff --git a/swarms/tools/tool.py b/swarms/tools/tool.py index f0090493..53436614 100644 --- a/swarms/tools/tool.py +++ b/swarms/tools/tool.py @@ -1,4 +1,5 @@ """Base implementation for tools or skills.""" + from __future__ import annotations import asyncio @@ -7,17 +8,7 @@ import warnings from abc import abstractmethod from functools import partial from inspect import signature -from typing import ( - Any, - Awaitable, - Callable, - Dict, - List, - Optional, - Tuple, - Type, - Union, -) +from typing import Any, Awaitable, Callable, Dict, Union from langchain.callbacks.base import BaseCallbackManager from langchain.callbacks.manager import ( @@ -27,8 +18,12 @@ from langchain.callbacks.manager import ( CallbackManagerForToolRun, Callbacks, ) - from langchain.load.serializable import Serializable +from langchain.schema.runnable import ( + Runnable, + RunnableConfig, + RunnableSerializable, +) from pydantic import ( BaseModel, Extra, @@ -37,11 +32,6 @@ from pydantic import ( root_validator, validate_arguments, ) -from langchain.schema.runnable import ( - Runnable, - RunnableConfig, - RunnableSerializable, -) class SchemaAnnotationError(TypeError): @@ -50,7 +40,7 @@ class SchemaAnnotationError(TypeError): def _create_subset_model( name: str, model: BaseModel, field_names: list -) -> Type[BaseModel]: +) -> type[BaseModel]: """Create a pydantic model with only a subset of model's fields.""" fields = {} for field_name in field_names: @@ -60,7 +50,7 @@ def _create_subset_model( def _get_filtered_args( - inferred_model: Type[BaseModel], + inferred_model: type[BaseModel], func: Callable, ) -> dict: """Get the arguments from a function's signature.""" @@ -83,7 +73,7 @@ class _SchemaConfig: def create_schema_from_function( model_name: str, func: Callable, -) -> Type[BaseModel]: +) -> type[BaseModel]: """Create a pydantic schema from a function's signature. Args: model_name: Name to assign to the generated pydandic schema @@ -114,8 +104,6 @@ class ToolException(Exception): to the agent as observation, and printed in red on the console. """ - pass - class BaseTool(RunnableSerializable[Union[str, Dict], Any]): """Interface swarms tools must implement.""" @@ -158,7 +146,7 @@ class ChildTool(BaseTool): You can provide few-shot examples as a part of the description. """ - args_schema: Optional[Type[BaseModel]] = None + args_schema: type[BaseModel] | None = None """Pydantic model class to validate and parse the tool's input arguments.""" return_direct: bool = False """Whether to return the tool's output directly. Setting this to True means @@ -170,26 +158,26 @@ class ChildTool(BaseTool): callbacks: Callbacks = Field(default=None, exclude=True) """Callbacks to be called during tool execution.""" - callback_manager: Optional[BaseCallbackManager] = Field( + callback_manager: BaseCallbackManager | None = Field( default=None, exclude=True ) """Deprecated. Please use callbacks instead.""" - tags: Optional[List[str]] = None + tags: list[str] | None = None """Optional list of tags associated with the tool. Defaults to None These tags will be associated with each call to this tool, and passed as arguments to the handlers defined in `callbacks`. You can use these to eg identify a specific instance of a tool with its use case. """ - metadata: Optional[Dict[str, Any]] = None + metadata: dict[str, Any] | None = None """Optional metadata associated with the tool. Defaults to None This metadata will be associated with each call to this tool, and passed as arguments to the handlers defined in `callbacks`. You can use these to eg identify a specific instance of a tool with its use case. """ - handle_tool_error: Optional[ - Union[bool, str, Callable[[ToolException], str]] - ] = False + handle_tool_error: ( + bool | str | Callable[[ToolException], str] | None + ) = False """Handle the content of the ToolException thrown.""" class Config(Serializable.Config): @@ -214,7 +202,7 @@ class ChildTool(BaseTool): # --- Runnable --- @property - def input_schema(self) -> Type[BaseModel]: + def input_schema(self) -> type[BaseModel]: """The tool's input schema.""" if self.args_schema is not None: return self.args_schema @@ -223,8 +211,8 @@ class ChildTool(BaseTool): def invoke( self, - input: Union[str, Dict], - config: Optional[RunnableConfig] = None, + input: str | dict, + config: RunnableConfig | None = None, **kwargs: Any, ) -> Any: config = config or {} @@ -239,8 +227,8 @@ class ChildTool(BaseTool): async def ainvoke( self, - input: Union[str, Dict], - config: Optional[RunnableConfig] = None, + input: str | dict, + config: RunnableConfig | None = None, **kwargs: Any, ) -> Any: config = config or {} @@ -257,8 +245,8 @@ class ChildTool(BaseTool): def _parse_input( self, - tool_input: Union[str, Dict], - ) -> Union[str, Dict[str, Any]]: + tool_input: str | dict, + ) -> str | dict[str, Any]: """Convert tool input to pydantic model.""" input_args = self.args_schema if isinstance(tool_input, str): @@ -277,7 +265,7 @@ class ChildTool(BaseTool): return tool_input @root_validator(skip_on_failure=True) - def raise_deprecation(cls, values: Dict) -> Dict: + def raise_deprecation(cls, values: dict) -> dict: """Raise deprecation warning if callback_manager is used.""" if values.get("callback_manager") is not None: warnings.warn( @@ -319,8 +307,8 @@ class ChildTool(BaseTool): ) def _to_args_and_kwargs( - self, tool_input: Union[str, Dict] - ) -> Tuple[Tuple, Dict]: + self, tool_input: str | dict + ) -> tuple[tuple, dict]: # For backwards compatibility, if run_input is a string, # pass as a positional argument. if isinstance(tool_input, str): @@ -330,15 +318,15 @@ class ChildTool(BaseTool): def run( self, - tool_input: Union[str, Dict], - verbose: Optional[bool] = None, - start_color: Optional[str] = "green", - color: Optional[str] = "green", + tool_input: str | dict, + verbose: bool | None = None, + start_color: str | None = "green", + color: str | None = "green", callbacks: Callbacks = None, *, - tags: Optional[List[str]] = None, - metadata: Optional[Dict[str, Any]] = None, - run_name: Optional[str] = None, + tags: list[str] | None = None, + metadata: dict[str, Any] | None = None, + run_name: str | None = None, **kwargs: Any, ) -> Any: """Run the tool.""" @@ -422,15 +410,15 @@ class ChildTool(BaseTool): async def arun( self, - tool_input: Union[str, Dict], - verbose: Optional[bool] = None, - start_color: Optional[str] = "green", - color: Optional[str] = "green", + tool_input: str | dict, + verbose: bool | None = None, + start_color: str | None = "green", + color: str | None = "green", callbacks: Callbacks = None, *, - tags: Optional[List[str]] = None, - metadata: Optional[Dict[str, Any]] = None, - run_name: Optional[str] = None, + tags: list[str] | None = None, + metadata: dict[str, Any] | None = None, + run_name: str | None = None, **kwargs: Any, ) -> Any: """Run the tool asynchronously.""" @@ -523,16 +511,16 @@ class Tool(BaseTool): """Tool that takes in function or coroutine directly.""" description: str = "" - func: Optional[Callable[..., str]] + func: Callable[..., str] | None """The function to run when the tool is called.""" - coroutine: Optional[Callable[..., Awaitable[str]]] = None + coroutine: Callable[..., Awaitable[str]] | None = None """The asynchronous version of the function.""" # --- Runnable --- async def ainvoke( self, - input: Union[str, Dict], - config: Optional[RunnableConfig] = None, + input: str | dict, + config: RunnableConfig | None = None, **kwargs: Any, ) -> Any: if not self.coroutine: @@ -555,8 +543,8 @@ class Tool(BaseTool): return {"tool_input": {"type": "string"}} def _to_args_and_kwargs( - self, tool_input: Union[str, Dict] - ) -> Tuple[Tuple, Dict]: + self, tool_input: str | dict + ) -> tuple[tuple, dict]: """Convert tool input to pydantic model.""" args, kwargs = super()._to_args_and_kwargs(tool_input) # For backwards compatibility. The tool must be run with a single input @@ -571,7 +559,7 @@ class Tool(BaseTool): def _run( self, *args: Any, - run_manager: Optional[CallbackManagerForToolRun] = None, + run_manager: CallbackManagerForToolRun | None = None, **kwargs: Any, ) -> Any: """Use the tool.""" @@ -597,7 +585,7 @@ class Tool(BaseTool): async def _arun( self, *args: Any, - run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + run_manager: AsyncCallbackManagerForToolRun | None = None, **kwargs: Any, ) -> Any: """Use the tool asynchronously.""" @@ -629,26 +617,25 @@ class Tool(BaseTool): def __init__( self, name: str, - func: Optional[Callable], + func: Callable | None, description: str, **kwargs: Any, ) -> None: """Initialize tool.""" - super(Tool, self).__init__( + super().__init__( name=name, func=func, description=description, **kwargs ) @classmethod def from_function( cls, - func: Optional[Callable], + func: Callable | None, name: str, # We keep these required to support backwards compatibility description: str, return_direct: bool = False, - args_schema: Optional[Type[BaseModel]] = None, - coroutine: Optional[ - Callable[..., Awaitable[Any]] - ] = None, # This is last for compatibility, but should be after func + args_schema: type[BaseModel] | None = None, + coroutine: (Callable[..., Awaitable[Any]]) + | None = None, # This is last for compatibility, but should be after func **kwargs: Any, ) -> Tool: """Initialize tool from a function.""" @@ -671,20 +658,20 @@ class StructuredTool(BaseTool): """Tool that can operate on any number of inputs.""" description: str = "" - args_schema: Type[BaseModel] = Field( + args_schema: type[BaseModel] = Field( ..., description="The tool schema." ) """The input arguments' schema.""" - func: Optional[Callable[..., Any]] + func: Callable[..., Any] | None """The function to run when the tool is called.""" - coroutine: Optional[Callable[..., Awaitable[Any]]] = None + coroutine: Callable[..., Awaitable[Any]] | None = None """The asynchronous version of the function.""" # --- Runnable --- async def ainvoke( self, - input: Union[str, Dict], - config: Optional[RunnableConfig] = None, + input: str | dict, + config: RunnableConfig | None = None, **kwargs: Any, ) -> Any: if not self.coroutine: @@ -705,7 +692,7 @@ class StructuredTool(BaseTool): def _run( self, *args: Any, - run_manager: Optional[CallbackManagerForToolRun] = None, + run_manager: CallbackManagerForToolRun | None = None, **kwargs: Any, ) -> Any: """Use the tool.""" @@ -731,7 +718,7 @@ class StructuredTool(BaseTool): async def _arun( self, *args: Any, - run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + run_manager: AsyncCallbackManagerForToolRun | None = None, **kwargs: Any, ) -> str: """Use the tool asynchronously.""" @@ -761,12 +748,12 @@ class StructuredTool(BaseTool): @classmethod def from_function( cls, - func: Optional[Callable] = None, - coroutine: Optional[Callable[..., Awaitable[Any]]] = None, - name: Optional[str] = None, - description: Optional[str] = None, + func: Callable | None = None, + coroutine: Callable[..., Awaitable[Any]] | None = None, + name: str | None = None, + description: str | None = None, return_direct: bool = False, - args_schema: Optional[Type[BaseModel]] = None, + args_schema: type[BaseModel] | None = None, infer_schema: bool = True, **kwargs: Any, ) -> StructuredTool: @@ -835,9 +822,9 @@ class StructuredTool(BaseTool): def tool( - *args: Union[str, Callable, Runnable], + *args: str | Callable | Runnable, return_direct: bool = False, - args_schema: Optional[Type[BaseModel]] = None, + args_schema: type[BaseModel] | None = None, infer_schema: bool = True, ) -> Callable: """Make tools out of functions, can be used with or without arguments. @@ -863,6 +850,7 @@ def tool( # Searches the API for the query. return + @tool("search", return_direct=True) def search_api(query: str) -> str: # Searches the API for the query. @@ -870,9 +858,7 @@ def tool( """ def _make_with_name(tool_name: str) -> Callable: - def _make_tool( - dec_func: Union[Callable, Runnable] - ) -> BaseTool: + def _make_tool(dec_func: Callable | Runnable) -> BaseTool: if isinstance(dec_func, Runnable): runnable = dec_func @@ -885,7 +871,7 @@ def tool( ) async def ainvoke_wrapper( - callbacks: Optional[Callbacks] = None, + callbacks: Callbacks | None = None, **kwargs: Any, ) -> Any: return await runnable.ainvoke( @@ -893,7 +879,7 @@ def tool( ) def invoke_wrapper( - callbacks: Optional[Callbacks] = None, + callbacks: Callbacks | None = None, **kwargs: Any, ) -> Any: return runnable.invoke( @@ -902,9 +888,7 @@ def tool( coroutine = ainvoke_wrapper func = invoke_wrapper - schema: Optional[Type[BaseModel]] = ( - runnable.input_schema - ) + schema: type[BaseModel] | None = runnable.input_schema description = repr(runnable) elif inspect.iscoroutinefunction(dec_func): coroutine = dec_func diff --git a/swarms/tools/tool_func_doc_scraper.py b/swarms/tools/tool_func_doc_scraper.py index d233bfae..fccfc6a1 100644 --- a/swarms/tools/tool_func_doc_scraper.py +++ b/swarms/tools/tool_func_doc_scraper.py @@ -1,5 +1,6 @@ import inspect from typing import Callable + from termcolor import colored diff --git a/swarms/tools/tool_utils.py b/swarms/tools/tool_utils.py index a5a4e47c..ee6b6391 100644 --- a/swarms/tools/tool_utils.py +++ b/swarms/tools/tool_utils.py @@ -2,9 +2,7 @@ import json import re from typing import Any, List -from swarms.prompts.tools import ( - SCENARIOS, -) +from swarms.prompts.tools import SCENARIOS from swarms.tools.tool import BaseTool from swarms.tools.tool_func_doc_scraper import scrape_tool_func_docs diff --git a/swarms/utils/README.md b/swarms/utils/README.md index 8934d6f2..df8b294e 100644 --- a/swarms/utils/README.md +++ b/swarms/utils/README.md @@ -100,13 +100,16 @@ Here's the pseudocode algorithm for a `WorkerNode` class that includes a vector In Python, this could look something like: ```python -from langchain.vectorstores import FAISS +from collections import deque +from typing import Any, Dict + +import faiss from langchain.docstore import InMemoryDocstore from langchain.embeddings import OpenAIEmbeddings -import faiss +from langchain.vectorstores import FAISS + from swarms.workers.auto_agent import AutoGPT -from collections import deque -from typing import Dict, Any + class WorkerNode: def __init__(self, llm: AutoGPT, vectorstore: FAISS): @@ -118,20 +121,24 @@ class WorkerNode: def receive_task(self, task): self.task_queue.append(task) - self.task_status[task] = 'pending' + self.task_status[task] = "pending" def complete_task(self): task = self.task_queue.popleft() result = self.llm.run(task) self.completed_tasks.append(result) - self.task_status[task] = 'completed' + self.task_status[task] = "completed" # Insert task result into the vectorstore self.vectorstore.insert(task, result) return result def communicate(self): # Share task results and status through vectorstore - completed_tasks = [(task, self.task_status[task]) for task in self.task_queue if self.task_status[task] == 'completed'] + completed_tasks = [ + (task, self.task_status[task]) + for task in self.task_queue + if self.task_status[task] == "completed" + ] for task, status in completed_tasks: self.vectorstore.insert(task, status) ``` diff --git a/swarms/utils/__init__.py b/swarms/utils/__init__.py index 220bc3e6..6527d7c1 100644 --- a/swarms/utils/__init__.py +++ b/swarms/utils/__init__.py @@ -1,7 +1,19 @@ from swarms.utils.class_args_wrapper import print_class_parameters from swarms.utils.code_interpreter import SubprocessCodeInterpreter +from swarms.utils.data_to_text import ( + csv_to_text, + data_to_text, + json_to_text, + txt_to_text, +) from swarms.utils.device_checker_cuda import check_device +from swarms.utils.download_img import download_img_from_url +from swarms.utils.download_weights_from_url import ( + download_weights_from_url, +) +from swarms.utils.exponential_backoff import ExponentialBackoffMixin from swarms.utils.find_img_path import find_image_path +from swarms.utils.json_output_parser import JsonOutputParser from swarms.utils.llm_metrics_decorator import metrics_decorator from swarms.utils.load_model_torch import load_model_torch from swarms.utils.markdown_message import display_markdown_message @@ -11,38 +23,31 @@ from swarms.utils.pdf_to_text import pdf_to_text from swarms.utils.prep_torch_model_inference import ( prep_torch_inference, ) -from swarms.utils.token_count_tiktoken import limit_tokens_from_string -from swarms.utils.data_to_text import ( - csv_to_text, - json_to_text, - txt_to_text, - data_to_text, -) -from swarms.utils.try_except_wrapper import try_except_wrapper -from swarms.utils.download_weights_from_url import ( - download_weights_from_url, -) -from swarms.utils.save_logs import parse_log_file - - -######## -from swarms.utils.yaml_output_parser import YamlOutputParser -from swarms.utils.json_output_parser import JsonOutputParser from swarms.utils.remove_json_whitespace import ( remove_whitespace_from_json, remove_whitespace_from_yaml, ) -from swarms.utils.exponential_backoff import ExponentialBackoffMixin -from swarms.utils.download_img import download_img_from_url +from swarms.utils.save_logs import parse_log_file from swarms.utils.supervision_masking import ( FeatureType, compute_mask_iou_vectorized, - mask_non_max_suppression, filter_masks_by_relative_area, + mask_non_max_suppression, masks_to_marks, refine_marks, ) from swarms.utils.supervision_visualizer import MarkVisualizer +from swarms.utils.token_count_tiktoken import limit_tokens_from_string +from swarms.utils.try_except_wrapper import try_except_wrapper +from swarms.utils.video_to_frames import ( + save_frames_as_images, + video_to_frames, +) + +######## +from swarms.utils.yaml_output_parser import YamlOutputParser +from swarms.utils.pandas_to_str import dataframe_to_text + __all__ = [ "SubprocessCodeInterpreter", @@ -77,4 +82,7 @@ __all__ = [ "masks_to_marks", "refine_marks", "MarkVisualizer", + "video_to_frames", + "save_frames_as_images", + "dataframe_to_text", ] diff --git a/swarms/utils/apa.py b/swarms/utils/apa.py index fa73b7b4..05b25c5c 100644 --- a/swarms/utils/apa.py +++ b/swarms/utils/apa.py @@ -1,8 +1,8 @@ -from enum import Enum, unique, auto import abc -from typing import List, Optional import json from dataclasses import dataclass, field +from enum import Enum, auto, unique +from typing import List, Optional @unique @@ -146,9 +146,7 @@ class Singleton(abc.ABCMeta, type): def __call__(cls, *args, **kwargs): """Call method for the singleton metaclass.""" if cls not in cls._instances: - cls._instances[cls] = super(Singleton, cls).__call__( - *args, **kwargs - ) + cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] diff --git a/swarms/utils/check_function_result.py b/swarms/utils/check_function_result.py index 0da3ad91..b3c88491 100644 --- a/swarms/utils/check_function_result.py +++ b/swarms/utils/check_function_result.py @@ -1,25 +1,25 @@ -import signal -import platform -import os -import multiprocessing -import tempfile import contextlib -from typing import Dict, Optional import faulthandler import io +import multiprocessing +import os +import platform +import signal +import tempfile +from typing import Dict, Optional class WriteOnlyStringIO(io.StringIO): """StringIO that throws an exception when it's read from""" def read(self, *args, **kwargs): - raise IOError + raise OSError def readline(self, *args, **kwargs): - raise IOError + raise OSError def readlines(self, *args, **kwargs): - raise IOError + raise OSError def readable(self, *args, **kwargs): """Returns True if the IO object can be read.""" diff --git a/swarms/utils/code_interpreter.py b/swarms/utils/code_interpreter.py index 9e27b668..a586a1eb 100644 --- a/swarms/utils/code_interpreter.py +++ b/swarms/utils/code_interpreter.py @@ -1,6 +1,6 @@ +import queue import subprocess import threading -import queue import time import traceback @@ -20,10 +20,12 @@ class SubprocessCodeInterpreter: Example: """ - def __init__(self): - self.start_cmd = "" + def __init__( + self, + start_cmd: str = "", + debug_mode: bool = False, + ): self.process = None - self.debug_mode = False self.output_queue = queue.Queue() self.done = threading.Event() diff --git a/swarms/utils/data_to_text.py b/swarms/utils/data_to_text.py index 55f6e6cd..d8d72986 100644 --- a/swarms/utils/data_to_text.py +++ b/swarms/utils/data_to_text.py @@ -1,24 +1,25 @@ -import os import csv import json +import os + from swarms.utils.pdf_to_text import pdf_to_text def csv_to_text(file): - with open(file, "r") as file: + with open(file) as file: reader = csv.reader(file) data = list(reader) return str(data) def json_to_text(file): - with open(file, "r") as file: + with open(file) as file: data = json.load(file) return json.dumps(data) def txt_to_text(file): - with open(file, "r") as file: + with open(file) as file: data = file.read() return data @@ -28,7 +29,7 @@ def md_to_text(file): raise FileNotFoundError( f"No such file or directory: '{file}'" ) - with open(file, "r") as file: + with open(file) as file: data = file.read() return data @@ -71,8 +72,8 @@ def data_to_text(file): elif ext == ".md": return md_to_text(file) else: - with open(file, "r") as file: + with open(file) as file: data = file.read() return data except Exception as e: - raise IOError(f"Error reading file: {file}") from e + raise OSError(f"Error reading file: {file}") from e diff --git a/swarms/utils/device_checker_cuda.py b/swarms/utils/device_checker_cuda.py index dbf2191c..11b4559c 100644 --- a/swarms/utils/device_checker_cuda.py +++ b/swarms/utils/device_checker_cuda.py @@ -1,6 +1,7 @@ -import torch import logging -from typing import Union, List, Any +from typing import Any, List, Union + +import torch from torch.cuda import memory_allocated, memory_reserved diff --git a/swarms/utils/disable_logging.py b/swarms/utils/disable_logging.py index 7f04555f..a5ad63cf 100644 --- a/swarms/utils/disable_logging.py +++ b/swarms/utils/disable_logging.py @@ -1,17 +1,9 @@ import logging import os import warnings -import sys -import logging -import os -import warnings -import sys def disable_logging(): - log_file = open("errors.txt", "w") - sys.stderr = log_file - warnings.filterwarnings("ignore", category=UserWarning) # disable tensorflow warnings @@ -33,6 +25,11 @@ def disable_logging(): "numexpr", "git", "wandb.docker.auth", + "langchain", + "distutils", + "urllib3", + "elasticsearch", + "packaging", ]: logger = logging.getLogger(logger_name) logger.setLevel(logging.ERROR) diff --git a/swarms/utils/dist_utils.py b/swarms/utils/dist_utils.py index 76d9e03c..f255d506 100644 --- a/swarms/utils/dist_utils.py +++ b/swarms/utils/dist_utils.py @@ -11,7 +11,6 @@ from torch.distributed._tensor import ( ) from zeta.nn import QuantizedLN - try: from peft.tuners.lora import Linear as LoRALinear except ImportError: diff --git a/swarms/utils/download_img.py b/swarms/utils/download_img.py index 7791a80e..301e1ef6 100644 --- a/swarms/utils/download_img.py +++ b/swarms/utils/download_img.py @@ -1,4 +1,5 @@ from io import BytesIO + import requests from PIL import Image @@ -26,6 +27,6 @@ def download_img_from_url(url: str): print("Image downloaded successfully.") except requests.exceptions.RequestException as e: - raise IOError("Error while downloading the image.") from e - except IOError as e: - raise IOError("Error while saving the image.") from e + raise OSError("Error while downloading the image.") from e + except OSError as e: + raise OSError("Error while saving the image.") from e diff --git a/swarms/utils/execute_futures.py b/swarms/utils/execute_futures.py index bc2d47ef..13d9518e 100644 --- a/swarms/utils/execute_futures.py +++ b/swarms/utils/execute_futures.py @@ -1,12 +1,12 @@ from concurrent import futures from concurrent.futures import Future -from typing import TypeVar, Dict +from typing import Dict, TypeVar T = TypeVar("T") def execute_futures_dict( - fs_dict: Dict[str, Future[T]] + fs_dict: Dict[str, Future[T]], ) -> Dict[str, T]: """Execute a dictionary of futures and return the results. diff --git a/swarms/utils/exponential_backoff.py b/swarms/utils/exponential_backoff.py index 2238064a..cd00016c 100644 --- a/swarms/utils/exponential_backoff.py +++ b/swarms/utils/exponential_backoff.py @@ -1,7 +1,8 @@ import logging from abc import ABC from dataclasses import dataclass -from tenacity import Retrying, wait_exponential, stop_after_attempt + +from tenacity import Retrying, stop_after_attempt, wait_exponential @dataclass diff --git a/swarms/utils/hash.py b/swarms/utils/hash.py index 725cc6ba..0e82766b 100644 --- a/swarms/utils/hash.py +++ b/swarms/utils/hash.py @@ -1,6 +1,7 @@ -import pandas as pd import hashlib +import pandas as pd + def dataframe_to_hash(dataframe: pd.DataFrame) -> str: return hashlib.sha256( diff --git a/swarms/utils/json_output_parser.py b/swarms/utils/json_output_parser.py index 724d5ed5..4f76c3a5 100644 --- a/swarms/utils/json_output_parser.py +++ b/swarms/utils/json_output_parser.py @@ -1,6 +1,7 @@ import json import re from typing import Type, TypeVar + from pydantic import BaseModel, ValidationError T = TypeVar("T", bound=BaseModel) diff --git a/swarms/utils/jsonl_utils.py b/swarms/utils/jsonl_utils.py index 6f52caf5..95a0d9d6 100644 --- a/swarms/utils/jsonl_utils.py +++ b/swarms/utils/jsonl_utils.py @@ -1,8 +1,7 @@ -from typing import Iterable, Dict import gzip import json import os - +from typing import Dict, Iterable ROOT = os.path.dirname(os.path.abspath(__file__)) @@ -29,7 +28,7 @@ def stream_jsonl(filename: str) -> Iterable[Dict]: yield json.loads(line) else: - with open(filename, "r") as fp: + with open(filename) as fp: for line in fp: if any(not x.isspace() for x in line): yield json.loads(line) diff --git a/swarms/utils/loggers.py b/swarms/utils/loggers.py index 68477132..7ec3fcd2 100644 --- a/swarms/utils/loggers.py +++ b/swarms/utils/loggers.py @@ -1,14 +1,16 @@ """Logging modules""" + +import json import logging import os import random import re import time -import json from logging import LogRecord from typing import Any from colorama import Fore, Style + from swarms.utils.apa import Action, ToolCallStatus diff --git a/swarms/utils/loguru_logger.py b/swarms/utils/loguru_logger.py new file mode 100644 index 00000000..dbbed560 --- /dev/null +++ b/swarms/utils/loguru_logger.py @@ -0,0 +1,10 @@ +from loguru import logger + +logger.add( + "MessagePool.log", + level="INFO", + colorize=True, + format="{time} {message}", + backtrace=True, + diagnose=True, +) diff --git a/swarms/utils/main.py b/swarms/utils/main.py index b94fae11..9dbd47fd 100644 --- a/swarms/utils/main.py +++ b/swarms/utils/main.py @@ -108,7 +108,7 @@ class Code: self.value = value def __str__(self): - return "%d" % self.value + return f"{int(self.value)}" class Color(Code): diff --git a/swarms/utils/pandas_to_str.py b/swarms/utils/pandas_to_str.py new file mode 100644 index 00000000..64415487 --- /dev/null +++ b/swarms/utils/pandas_to_str.py @@ -0,0 +1,49 @@ +import pandas as pd + + +def dataframe_to_text( + df: pd.DataFrame, + parsing_func: callable = None, +) -> str: + """ + Convert a pandas DataFrame to a string representation. + + Args: + df (pd.DataFrame): The pandas DataFrame to convert. + parsing_func (callable, optional): A function to parse the resulting text. Defaults to None. + + Returns: + str: The string representation of the DataFrame. + + Example: + >>> df = pd.DataFrame({ + ... 'A': [1, 2, 3], + ... 'B': [4, 5, 6], + ... 'C': [7, 8, 9], + ... }) + >>> print(dataframe_to_text(df)) + + """ + # Get a string representation of the dataframe + df_str = df.to_string() + + # Get a string representation of the column names + info_str = df.info() + + # Combine the dataframe string and the info string + text = f"DataFrame:\n{df_str}\n\nInfo:\n{info_str}" + + if parsing_func: + text = parsing_func(text) + + return text + + +# # # Example usage: +# df = pd.DataFrame({ +# 'A': [1, 2, 3], +# 'B': [4, 5, 6], +# 'C': [7, 8, 9], +# }) + +# print(dataframe_to_text(df)) diff --git a/swarms/utils/pdf_to_text.py b/swarms/utils/pdf_to_text.py index 6d589ad5..4877f3b1 100644 --- a/swarms/utils/pdf_to_text.py +++ b/swarms/utils/pdf_to_text.py @@ -1,11 +1,11 @@ import sys try: - import PyPDF2 + import pypdf except ImportError: print( - "PyPDF2 not installed. Please install it using: pip install" - " PyPDF2" + "pypdf not installed. Please install it using: pip install" + " pypdf" ) sys.exit(1) @@ -27,7 +27,7 @@ def pdf_to_text(pdf_path): try: # Open the PDF file with open(pdf_path, "rb") as file: - pdf_reader = PyPDF2.PdfReader(file) + pdf_reader = pypdf.PdfReader(file) text = "" # Iterate through each page and extract text diff --git a/swarms/utils/prep_torch_model_inference.py b/swarms/utils/prep_torch_model_inference.py index 41bc07cc..1b88cab5 100644 --- a/swarms/utils/prep_torch_model_inference.py +++ b/swarms/utils/prep_torch_model_inference.py @@ -1,4 +1,5 @@ import torch + from swarms.utils.load_model_torch import load_model_torch diff --git a/swarms/utils/remove_json_whitespace.py b/swarms/utils/remove_json_whitespace.py index a5b3f7de..0a043e7c 100644 --- a/swarms/utils/remove_json_whitespace.py +++ b/swarms/utils/remove_json_whitespace.py @@ -1,4 +1,5 @@ import json + import yaml diff --git a/swarms/utils/save_logs.py b/swarms/utils/save_logs.py index c8193905..dd8810b1 100644 --- a/swarms/utils/save_logs.py +++ b/swarms/utils/save_logs.py @@ -25,7 +25,7 @@ def parse_log_file(filename: str): log_entries = [] - with open(filename, "r") as file: + with open(filename) as file: for line in file: parts = line.split(" - ") # Check if the log entry has the correct format diff --git a/swarms/utils/serializable.py b/swarms/utils/serializable.py index de9444ef..9e85e783 100644 --- a/swarms/utils/serializable.py +++ b/swarms/utils/serializable.py @@ -54,7 +54,7 @@ class Serializable(BaseModel, ABC): Return a map of constructor argument names to secret ids. eg. {"openai_api_key": "OPENAI_API_KEY"} """ - return dict() + return {} @property def lc_attributes(self) -> Dict: @@ -80,7 +80,7 @@ class Serializable(BaseModel, ABC): if not self.lc_serializable: return self.to_json_not_implemented() - secrets = dict() + secrets = {} # Get latest values for kwargs if there is an attribute with same name lc_kwargs = { k: getattr(self, k, v) diff --git a/swarms/utils/video_to_frames.py b/swarms/utils/video_to_frames.py new file mode 100644 index 00000000..528e45b0 --- /dev/null +++ b/swarms/utils/video_to_frames.py @@ -0,0 +1,43 @@ +from typing import List + +import cv2 + + +def video_to_frames(video_file: str) -> List: + """ + Convert a video into frames. + + Args: + video_file (str): The path to the video file. + + Returns: + List[np.array]: A list of frames from the video. + """ + # Open the video file + vidcap = cv2.VideoCapture(video_file) + + frames = [] + success, image = vidcap.read() + + while success: + frames.append(image) + success, image = vidcap.read() + + return frames + + +def save_frames_as_images(frames, output_dir) -> None: + """ + Save a list of frames as image files. + + Args: + frames (list of np.array): The list of frames. + output_dir (str): The directory where the images will be saved. + """ + for i, frame in enumerate(frames): + cv2.imwrite(f"{output_dir}/frame{i}.jpg", frame) + + +# out = save_frames_as_images(frames, "playground/demos/security_team/frames") + +# print(out) diff --git a/swarms/utils/yaml_output_parser.py b/swarms/utils/yaml_output_parser.py index 61be311b..5832bf16 100644 --- a/swarms/utils/yaml_output_parser.py +++ b/swarms/utils/yaml_output_parser.py @@ -1,7 +1,8 @@ import json import re -import yaml from typing import Type, TypeVar + +import yaml from pydantic import BaseModel, ValidationError T = TypeVar("T", bound=BaseModel) diff --git a/tests/README.md b/tests/README.md index dc527d9f..617f0a8a 100644 --- a/tests/README.md +++ b/tests/README.md @@ -11,27 +11,31 @@ In Python, this would look something like: ```python import pytest + def test_WorkerNode_create_agent(): # assuming llm, tools, and vectorstore are initialized properly worker_node = WorkerNode(llm, tools, vectorstore) - worker_node.create_agent('test_agent', 'test_role', False, {}) + worker_node.create_agent("test_agent", "test_role", False, {}) assert worker_node.agent is not None assert worker_node.agent.chain.verbose + def test_WorkerNode_run_agent(): worker_node = WorkerNode(llm, tools, vectorstore) - worker_node.create_agent('test_agent', 'test_role', False, {}) - worker_node.run_agent('test prompt') # check it runs without error + worker_node.create_agent("test_agent", "test_role", False, {}) + worker_node.run_agent("test prompt") # check it runs without error + def test_BossNode_create_task(): # assuming llm, vectorstore, task_execution_chain are initialized properly boss_node = BossNode(llm, vectorstore, task_execution_chain, False, 3) - task = boss_node.create_task('test task') - assert task == {'objective': 'test task'} + task = boss_node.create_task("test task") + assert task == {"objective": "test task"} + def test_BossNode_execute_task(): boss_node = BossNode(llm, vectorstore, task_execution_chain, False, 3) - task = boss_node.create_task('test task') + task = boss_node.create_task("test task") boss_node.execute_task(task) # check it runs without error ``` @@ -51,21 +55,23 @@ Here is an example of what these tests could look like: ```python def test_WorkerNode_tools(): worker_node = WorkerNode(llm, tools, vectorstore) - worker_node.create_agent('test_agent', 'test_role', False, {}) - + worker_node.create_agent("test_agent", "test_role", False, {}) + # Check that all tools are instantiated for tool in worker_node.tools: assert tool is not None + def test_BossNode_AgentExecutor(): boss_node = BossNode(llm, vectorstore, task_execution_chain, False, 3) - + # Check that the AgentExecutor is correctly initialized assert boss_node.baby_agi.task_execution_chain is not None + def test_BossNode_LLMChain(): boss_node = BossNode(llm, vectorstore, task_execution_chain, False, 3) - + # Check that the LLMChain in ZeroShotAgent is working assert boss_node.baby_agi.task_execution_chain.agent.llm_chain is not None ``` diff --git a/tests/agents/test_multion.py b/tests/agents/test_multion.py new file mode 100644 index 00000000..23614934 --- /dev/null +++ b/tests/agents/test_multion.py @@ -0,0 +1,59 @@ +from unittest.mock import MagicMock, patch + +import pytest + +from swarms.agents.multion_agent import MultiOnAgent + + +@patch("swarms.agents.multion_agent.multion") +def test_multion_agent_run(mock_multion): + mock_response = MagicMock() + mock_response.result = "result" + mock_response.status = "status" + mock_response.lastUrl = "lastUrl" + mock_multion.browse.return_value = mock_response + + agent = MultiOnAgent( + multion_api_key="test_key", + max_steps=5, + starting_url="https://www.example.com", + ) + result, status, last_url = agent.run("task") + + assert result == "result" + assert status == "status" + assert last_url == "lastUrl" + mock_multion.browse.assert_called_once_with( + { + "cmd": "task", + "url": "https://www.example.com", + "maxSteps": 5, + } + ) + + +# Additional tests for different tasks +@pytest.mark.parametrize( + "task", ["task1", "task2", "task3", "task4", "task5"] +) +@patch("swarms.agents.multion_agent.multion") +def test_multion_agent_run_different_tasks(mock_multion, task): + mock_response = MagicMock() + mock_response.result = "result" + mock_response.status = "status" + mock_response.lastUrl = "lastUrl" + mock_multion.browse.return_value = mock_response + + agent = MultiOnAgent( + multion_api_key="test_key", + max_steps=5, + starting_url="https://www.example.com", + ) + result, status, last_url = agent.run(task) + + assert result == "result" + assert status == "status" + assert last_url == "lastUrl" + mock_multion.browse.assert_called_once_with( + {"cmd": task, "url": "https://www.example.com", "maxSteps": 5} + ) diff --git a/tests/engines/test_cuda_wrapper.rs b/tests/engines/test_cuda_wrapper.rs new file mode 100644 index 00000000..45695965 --- /dev/null +++ b/tests/engines/test_cuda_wrapper.rs @@ -0,0 +1,26 @@ +#[cfg(test)] +mod tests { + use super::*; + use pyo3::types::IntoPyDict; + + #[test] + fn test_execute_on_device() { + let gil = Python::acquire_gil(); + let py = gil.python(); + + // Define a Python module for testing + let rust_cuda = PyModule::new(py, "rust_cuda").unwrap(); + rust_cuda.add_function(wrap_pyfunction!(execute_on_device, rust_cuda).unwrap()).unwrap(); + + // Test the execute_on_device function + let result: PyResult = rust_cuda.call1("execute_on_device", (0, 1.0f32, 2.0f32)).unwrap().extract().unwrap(); + assert!(result.is_ok()); + } + + #[test] + fn test_execute_cuda() { + // Test the execute_cuda function + let result = execute_cuda(0, 1.0f32, 2.0f32); + assert!(result.is_ok()); + } +} \ No newline at end of file diff --git a/tests/engines/test_multithreading.rs b/tests/engines/test_multithreading.rs new file mode 100644 index 00000000..9085554e --- /dev/null +++ b/tests/engines/test_multithreading.rs @@ -0,0 +1,62 @@ +#[cfg(test)] +mod tests { + use super::*; + use pyo3::types::IntoPyDict; + + #[test] + fn test_process_python_modules() { + let gil = Python::acquire_gil(); + let py = gil.python(); + + // Define a Python module for testing + let code = r#" + def test_function(): + return "Hello, World!" + "#; + let test_module = PyModule::new(py, "test_module").unwrap(); + test_module.add_function(wrap_pyfunction!(test_function, test_module).unwrap()).unwrap(); + test_module.add(py, "test_function", code).unwrap(); + + // Define a PythonModule struct for testing + let test_python_module = PythonModule { + name: "test_module", + function: "test_function", + }; + + // Test the process_python_modules function + let result = process_python_modules(vec![test_python_module], 1); + assert!(result.is_ok()); + } + + #[test] + fn test_process_python_modules_import_error() { + // Define a PythonModule struct with a non-existent module + let test_python_module = PythonModule { + name: "non_existent_module", + function: "test_function", + }; + + // Test the process_python_modules function + let result = process_python_modules(vec![test_python_module], 1); + assert!(matches!(result, Err(PythonError::ImportError(_)))); + } + + #[test] + fn test_process_python_modules_function_error() { + let gil = Python::acquire_gil(); + let py = gil.python(); + + // Define a Python module for testing + let test_module = PyModule::new(py, "test_module").unwrap(); + + // Define a PythonModule struct with a non-existent function + let test_python_module = PythonModule { + name: "test_module", + function: "non_existent_function", + }; + + // Test the process_python_modules function + let result = process_python_modules(vec![test_python_module], 1); + assert!(matches!(result, Err(PythonError::FunctionError(_)))); + } +} \ No newline at end of file diff --git a/tests/memory/test_dictinternalmemory.py b/tests/memory/test_dictinternalmemory.py new file mode 100644 index 00000000..7658eb7c --- /dev/null +++ b/tests/memory/test_dictinternalmemory.py @@ -0,0 +1,71 @@ +# DictInternalMemory + +from uuid import uuid4 + +import pytest + +from swarms.memory import DictInternalMemory + +# Example of an extensive suite of tests for DictInternalMemory. + + +# Fixture for repeatedly initializing the class with different numbers of entries. +@pytest.fixture(params=[1, 5, 10, 100]) +def memory(request): + return DictInternalMemory(n_entries=request.param) + + +# Basic Tests +def test_initialization(memory): + assert memory.len() == 0 + + +def test_single_add(memory): + memory.add(10, {"data": "test"}) + assert memory.len() == 1 + + +def test_memory_limit_enforced(memory): + entries_to_add = memory.n_entries + 10 + for i in range(entries_to_add): + memory.add(i, {"data": f"test{i}"}) + assert memory.len() == memory.n_entries + + +# Parameterized Tests +@pytest.mark.parametrize( + "scores, best_score", [([10, 5, 3], 10), ([1, 2, 3], 3)] +) +def test_get_top_n(scores, best_score, memory): + for score in scores: + memory.add(score, {"data": f"test{score}"}) + top_entry = memory.get_top_n(1) + assert top_entry[0][1]["score"] == best_score + + +# Exception Testing +@pytest.mark.parametrize("invalid_n", [-1, 0]) +def test_invalid_n_entries_raises_exception(invalid_n): + with pytest.raises(ValueError): + DictInternalMemory(invalid_n) + + +# Mocks and Monkeypatching +def test_add_with_mocked_uuid4(monkeypatch, memory): + # Mock the uuid4 function to return a known value + class MockUUID: + hex = "1234abcd" + + monkeypatch.setattr(uuid4, "__str__", lambda: MockUUID.hex) + memory.add(20, {"data": "mock_uuid"}) + assert MockUUID.hex in memory.data + + +# Test using Mocks to simulate I/O or external interactions here +# ... + +# More tests to hit edge cases, concurrency issues, etc. +# ... + +# Tests for concurrency issues, if relevant +# ... diff --git a/tests/memory/test_dictsharedmemory.py b/tests/memory/test_dictsharedmemory.py new file mode 100644 index 00000000..a41ccd8f --- /dev/null +++ b/tests/memory/test_dictsharedmemory.py @@ -0,0 +1,92 @@ +import os +import tempfile + +import pytest + +from swarms.memory import DictSharedMemory + +# Utility functions or fixtures might come first + + +@pytest.fixture +def memory_file(): + with tempfile.NamedTemporaryFile("w+", delete=False) as tmp_file: + yield tmp_file.name + os.unlink(tmp_file.name) + + +@pytest.fixture +def memory_instance(memory_file): + return DictSharedMemory(file_loc=memory_file) + + +# Basic tests + + +def test_init(memory_file): + memory = DictSharedMemory(file_loc=memory_file) + assert os.path.exists( + memory.file_loc + ), "Memory file should be created if non-existent" + + +def test_add_entry(memory_instance): + success = memory_instance.add(9.5, "agent123", 1, "Test Entry") + assert success, "add_entry should return True on success" + + +def test_add_entry_thread_safety(memory_instance): + # We could create multiple threads to test the thread safety of the add_entry method + pass + + +def test_get_top_n(memory_instance): + memory_instance.add(9.5, "agent123", 1, "Entry A") + memory_instance.add(8.5, "agent124", 1, "Entry B") + top_1 = memory_instance.get_top_n(1) + assert ( + len(top_1) == 1 + ), "get_top_n should return the correct number of top entries" + + +# Parameterized tests + + +@pytest.mark.parametrize( + "scores, agent_ids, expected_top_score", + [ + ([1.0, 2.0, 3.0], ["agent1", "agent2", "agent3"], 3.0), + # add more test cases + ], +) +def test_parametrized_get_top_n( + memory_instance, scores, agent_ids, expected_top_score +): + for score, agent_id in zip(scores, agent_ids): + memory_instance.add( + score, agent_id, 1, f"Entry by {agent_id}" + ) + top_1 = memory_instance.get_top_n(1) + top_score = next(iter(top_1.values()))["score"] + assert ( + top_score == expected_top_score + ), "get_top_n should return the entry with top score" + + +# Exception testing + + +def test_add_entry_invalid_input(memory_instance): + with pytest.raises(ValueError): + memory_instance.add( + "invalid_score", "agent123", 1, "Test Entry" + ) + + +# Mocks and monkey-patching + + +def test_write_fails_due_to_permissions(memory_instance, mocker): + mocker.patch("builtins.open", side_effect=PermissionError) + with pytest.raises(PermissionError): + memory_instance.add(9.5, "agent123", 1, "Test Entry") diff --git a/tests/memory/test_langchainchromavectormemory.py b/tests/memory/test_langchainchromavectormemory.py new file mode 100644 index 00000000..ee882c6c --- /dev/null +++ b/tests/memory/test_langchainchromavectormemory.py @@ -0,0 +1,96 @@ +# LangchainChromaVectorMemory + +from unittest.mock import MagicMock, patch + +import pytest + +from swarms.memory import LangchainChromaVectorMemory + + +# Fixtures for setting up the memory and mocks +@pytest.fixture() +def vector_memory(tmp_path): + loc = tmp_path / "vector_memory" + return LangchainChromaVectorMemory(loc=loc) + + +@pytest.fixture() +def embeddings_mock(): + with patch("swarms.memory.OpenAIEmbeddings") as mock: + yield mock + + +@pytest.fixture() +def chroma_mock(): + with patch("swarms.memory.Chroma") as mock: + yield mock + + +@pytest.fixture() +def qa_mock(): + with patch("swarms.memory.RetrievalQA") as mock: + yield mock + + +# Example test cases +def test_initialization_default_settings(vector_memory): + assert vector_memory.chunk_size == 1000 + assert ( + vector_memory.chunk_overlap == 100 + ) # assuming default overlap of 0.1 + assert vector_memory.loc.exists() + + +def test_add_entry(vector_memory, embeddings_mock): + with patch.object( + vector_memory.db, "add_texts" + ) as add_texts_mock: + vector_memory.add("Example text") + add_texts_mock.assert_called() + + +def test_search_memory_returns_list(vector_memory): + result = vector_memory.search_memory("example query", k=5) + assert isinstance(result, list) + + +def test_ask_question_returns_string(vector_memory, qa_mock): + result = vector_memory.query("What is the color of the sky?") + assert isinstance(result, str) + + +@pytest.mark.parametrize( + "query,k,type,expected", + [ + ("example query", 5, "mmr", [MagicMock()]), + ( + "example query", + 0, + "mmr", + None, + ), # Expected none when k is 0 or negative + ( + "example query", + 3, + "cos", + [MagicMock()], + ), # Mocked object as a placeholder + ], +) +def test_search_memory_different_params( + vector_memory, query, k, type, expected +): + with patch.object( + vector_memory.db, + "max_marginal_relevance_search", + return_value=expected, + ): + with patch.object( + vector_memory.db, + "similarity_search_with_score", + return_value=expected, + ): + result = vector_memory.search_memory( + query, k=k, type=type + ) + assert len(result) == (k if k > 0 else 0) diff --git a/tests/memory/test_pinecone.py b/tests/memory/test_pinecone.py index f385f058..a7d4fcea 100644 --- a/tests/memory/test_pinecone.py +++ b/tests/memory/test_pinecone.py @@ -1,5 +1,6 @@ import os from unittest.mock import patch + from swarms.memory.pinecone import PineconeDB api_key = os.getenv("PINECONE_API_KEY") or "" diff --git a/tests/memory/test_qdrant.py b/tests/memory/test_qdrant.py index eb9bfef6..5f82814c 100644 --- a/tests/memory/test_qdrant.py +++ b/tests/memory/test_qdrant.py @@ -1,6 +1,7 @@ -import pytest from unittest.mock import Mock, patch +import pytest + from swarms.memory.qdrant import Qdrant diff --git a/tests/memory/test_short_term_memory.py b/tests/memory/test_short_term_memory.py index 0b66b749..132da5f6 100644 --- a/tests/memory/test_short_term_memory.py +++ b/tests/memory/test_short_term_memory.py @@ -1,6 +1,7 @@ -from swarms.memory.short_term_memory import ShortTermMemory import threading +from swarms.memory.short_term_memory import ShortTermMemory + def test_init(): memory = ShortTermMemory() diff --git a/tests/memory/test_sqlite.py b/tests/memory/test_sqlite.py index 6b4213b0..49d61ef7 100644 --- a/tests/memory/test_sqlite.py +++ b/tests/memory/test_sqlite.py @@ -1,5 +1,7 @@ -import pytest import sqlite3 + +import pytest + from swarms.memory.sqlite import SQLiteDB diff --git a/tests/memory/test_weaviate.py b/tests/memory/test_weaviate.py index f9e61c8f..d1a69da0 100644 --- a/tests/memory/test_weaviate.py +++ b/tests/memory/test_weaviate.py @@ -1,5 +1,7 @@ -import pytest from unittest.mock import Mock, patch + +import pytest + from swarms.memory import WeaviateDB diff --git a/tests/models/test_biogpt.py b/tests/models/test_biogpt.py index 38be125d..e6093729 100644 --- a/tests/models/test_biogpt.py +++ b/tests/models/test_biogpt.py @@ -9,9 +9,7 @@ from transformers import BioGptForCausalLM, BioGptTokenizer # Fixture for BioGPT instance @pytest.fixture def biogpt_instance(): - from swarms.models import ( - BioGPT, - ) + from swarms.models import BioGPT return BioGPT() @@ -20,28 +18,32 @@ def biogpt_instance(): def test_biomedical_response_1(biogpt_instance): question = "What are the functions of the mitochondria?" response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) # 37. Test for a genetics-based question def test_genetics_response(biogpt_instance): question = "Can you explain the Mendelian inheritance?" response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) # 38. Test for a question about viruses def test_virus_response(biogpt_instance): question = "How do RNA viruses replicate?" response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) # 39. Test for a cell biology related question def test_cell_biology_response(biogpt_instance): question = "Describe the cell cycle and its phases." response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) # 40. Test for a question about protein structure @@ -51,28 +53,32 @@ def test_protein_structure_response(biogpt_instance): " structures in proteins?" ) response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) # 41. Test for a pharmacology question def test_pharmacology_response(biogpt_instance): question = "How do beta blockers work?" response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) # 42. Test for an anatomy-based question def test_anatomy_response(biogpt_instance): question = "Describe the structure of the human heart." response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) # 43. Test for a question about bioinformatics def test_bioinformatics_response(biogpt_instance): question = "What is a BLAST search?" response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) # 44. Test for a neuroscience question @@ -81,14 +87,16 @@ def test_neuroscience_response(biogpt_instance): "Explain the function of synapses in the nervous system." ) response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) # 45. Test for an immunology question def test_immunology_response(biogpt_instance): question = "What is the role of T cells in the immune response?" response = biogpt_instance(question) - assert response and isinstance(response, str) + assert response + assert isinstance(response, str) def test_init(bio_gpt): diff --git a/tests/models/test_cohere.py b/tests/models/test_cohere.py index 5e6fc948..8a1147d3 100644 --- a/tests/models/test_cohere.py +++ b/tests/models/test_cohere.py @@ -3,6 +3,7 @@ from unittest.mock import Mock, patch import pytest from dotenv import load_dotenv + from swarms.models.cohere_chat import BaseCohere, Cohere # Load the environment variables diff --git a/tests/models/test_elevenlab.py b/tests/models/test_elevenlab.py index 0ba975ca..da41ca53 100644 --- a/tests/models/test_elevenlab.py +++ b/tests/models/test_elevenlab.py @@ -1,11 +1,13 @@ +import os +from unittest.mock import mock_open, patch + import pytest -from unittest.mock import patch, mock_open +from dotenv import load_dotenv + from swarms.models.eleven_labs import ( - ElevenLabsText2SpeechTool, ElevenLabsModel, + ElevenLabsText2SpeechTool, ) -import os -from dotenv import load_dotenv load_dotenv() diff --git a/tests/models/test_fire_function_caller.py b/tests/models/test_fire_function_caller.py new file mode 100644 index 00000000..082d954d --- /dev/null +++ b/tests/models/test_fire_function_caller.py @@ -0,0 +1,44 @@ +from unittest.mock import MagicMock + +from swarms.models.fire_function import FireFunctionCaller + + +def test_fire_function_caller_run(mocker): + # Create mock model and tokenizer + model = MagicMock() + tokenizer = MagicMock() + mocker.patch.object(FireFunctionCaller, "model", model) + mocker.patch.object(FireFunctionCaller, "tokenizer", tokenizer) + + # Create mock task and arguments + task = "Add 2 and 3" + args = (2, 3) + kwargs = {} + + # Create mock generated_ids and decoded output + generated_ids = [1, 2, 3] + decoded_output = "5" + model.generate.return_value = generated_ids + tokenizer.batch_decode.return_value = [decoded_output] + + # Create FireFunctionCaller instance + fire_function_caller = FireFunctionCaller() + + # Run the function + fire_function_caller.run(task, *args, **kwargs) + + # Assert model.generate was called with the correct inputs + model.generate.assert_called_once_with( + tokenizer.apply_chat_template.return_value, + max_new_tokens=fire_function_caller.max_tokens, + *args, + **kwargs, + ) + + # Assert tokenizer.batch_decode was called with the correct inputs + tokenizer.batch_decode.assert_called_once_with(generated_ids) + + # Assert the decoded output is printed + assert decoded_output in mocker.patch.object( + print, "call_args_list" + ) diff --git a/tests/models/test_gemini.py b/tests/models/test_gemini.py index 2a1d4ad4..a61d1676 100644 --- a/tests/models/test_gemini.py +++ b/tests/models/test_gemini.py @@ -1,5 +1,7 @@ +from unittest.mock import Mock, patch + import pytest -from unittest.mock import patch, Mock + from swarms.models.gemini import Gemini diff --git a/tests/models/test_gpt4_vision_api.py b/tests/models/test_gpt4_vision_api.py index 26f60960..ac797280 100644 --- a/tests/models/test_gpt4_vision_api.py +++ b/tests/models/test_gpt4_vision_api.py @@ -1,8 +1,9 @@ import asyncio import os from unittest.mock import AsyncMock, Mock, mock_open, patch -from aiohttp import ClientResponseError + import pytest +from aiohttp import ClientResponseError from dotenv import load_dotenv from requests.exceptions import RequestException diff --git a/tests/models/test_hf.py b/tests/models/test_hf.py index 48dcd008..cbbba940 100644 --- a/tests/models/test_hf.py +++ b/tests/models/test_hf.py @@ -1,8 +1,8 @@ -import torch import logging from unittest.mock import patch import pytest +import torch from swarms.models.huggingface import HuggingfaceLLM @@ -83,18 +83,12 @@ def test_load_model(mock_huggingface_llm): llm = HuggingfaceLLM(model_id="test_model") llm.load_model() - # Ensure that the load_model function is called - assert True - # Test running the model def test_run(mock_huggingface_llm): llm = HuggingfaceLLM(model_id="test_model") llm.run("Test prompt") - # Ensure that the run function is called - assert True - # Test for setting max_length def test_llm_set_max_length(llm_instance): diff --git a/tests/models/test_idefics.py b/tests/models/test_idefics.py index 25a8dd5b..3bfee679 100644 --- a/tests/models/test_idefics.py +++ b/tests/models/test_idefics.py @@ -1,10 +1,12 @@ -import pytest from unittest.mock import patch + +import pytest import torch + from swarms.models.idefics import ( + AutoProcessor, Idefics, IdeficsForVisionText2Text, - AutoProcessor, ) diff --git a/tests/models/test_jina_embeds.py b/tests/models/test_jina_embeds.py index dd102d7c..0f59e477 100644 --- a/tests/models/test_jina_embeds.py +++ b/tests/models/test_jina_embeds.py @@ -1,5 +1,6 @@ import pytest import torch + from swarms.models.jina_embeds import JinaEmbeddings @@ -61,7 +62,8 @@ def test_cosine_similarity(model): embeddings2 = model.run(task2) sim = model.cos_sim(embeddings1, embeddings2) assert isinstance(sim, torch.Tensor) - assert sim.item() >= -1.0 and sim.item() <= 1.0 + assert sim.item() >= -1.0 + assert sim.item() <= 1.0 def test_failed_load_model(caplog): diff --git a/tests/models/test_llama_function_caller.py b/tests/models/test_llama_function_caller.py index 56ad481d..1e9df654 100644 --- a/tests/models/test_llama_function_caller.py +++ b/tests/models/test_llama_function_caller.py @@ -1,4 +1,5 @@ import pytest + from swarms.models.llama_function_caller import LlamaFunctionCaller diff --git a/tests/models/test_mistral.py b/tests/models/test_mistral.py index 10b47810..432c02c1 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -1,4 +1,5 @@ from unittest.mock import patch + from swarms.models.mistral import Mistral diff --git a/tests/models/test_mixtral.py b/tests/models/test_mixtral.py index 9eb31af0..a68a9026 100644 --- a/tests/models/test_mixtral.py +++ b/tests/models/test_mixtral.py @@ -1,5 +1,7 @@ +from unittest.mock import MagicMock, patch + import pytest -from unittest.mock import patch, MagicMock + from swarms.models.mixtral import Mixtral diff --git a/tests/models/test_open_dalle.py b/tests/models/test_open_dalle.py index 2483d705..4ff14e10 100644 --- a/tests/models/test_open_dalle.py +++ b/tests/models/test_open_dalle.py @@ -1,5 +1,6 @@ import pytest import torch + from swarms.models.open_dalle import OpenDalle diff --git a/tests/models/test_openaitts.py b/tests/models/test_openaitts.py index b6a4a7ff..42745284 100644 --- a/tests/models/test_openaitts.py +++ b/tests/models/test_openaitts.py @@ -1,5 +1,7 @@ +from unittest.mock import MagicMock, patch + import pytest -from unittest.mock import patch, MagicMock + from swarms.models.openai_tts import OpenAITTS diff --git a/tests/models/test_qwen.py b/tests/models/test_qwen.py index 28178fc0..a920256c 100644 --- a/tests/models/test_qwen.py +++ b/tests/models/test_qwen.py @@ -1,4 +1,5 @@ from unittest.mock import Mock, patch + from swarms.models.qwen import QwenVLMultiModal diff --git a/tests/models/test_speech_t5.py b/tests/models/test_speech_t5.py index a33272fc..d32c21db 100644 --- a/tests/models/test_speech_t5.py +++ b/tests/models/test_speech_t5.py @@ -1,6 +1,8 @@ -import pytest import os + +import pytest import torch + from swarms.models.speecht5 import SpeechT5 diff --git a/tests/models/test_ssd_1b.py b/tests/models/test_ssd_1b.py index 39e4264e..f658f853 100644 --- a/tests/models/test_ssd_1b.py +++ b/tests/models/test_ssd_1b.py @@ -1,7 +1,8 @@ import pytest -from swarms.models.ssd_1b import SSD1B from PIL import Image +from swarms.models.ssd_1b import SSD1B + # Create fixtures if needed @pytest.fixture diff --git a/tests/models/test_timm.py b/tests/models/test_timm.py index fae5f704..4af689e5 100644 --- a/tests/models/test_timm.py +++ b/tests/models/test_timm.py @@ -1,7 +1,9 @@ from unittest.mock import patch -from swarms.models import TimmModel + import torch +from swarms.models import TimmModel + def test_timm_model_init(): with patch("swarms.models.timm.list_models") as mock_list_models: diff --git a/tests/models/test_timm_model.py b/tests/models/test_timm_model.py index 0ced344e..b2f8f6c9 100644 --- a/tests/models/test_timm_model.py +++ b/tests/models/test_timm_model.py @@ -1,6 +1,8 @@ from unittest.mock import Mock -import torch + import pytest +import torch + from swarms.models.timm import TimmModel diff --git a/tests/models/test_togther.py b/tests/models/test_togther.py index 43a99b00..dd2a2f89 100644 --- a/tests/models/test_togther.py +++ b/tests/models/test_togther.py @@ -1,8 +1,10 @@ -import requests +import logging +from unittest.mock import Mock, patch + import pytest -from unittest.mock import patch, Mock +import requests + from swarms.models.together import TogetherLLM -import logging @pytest.fixture diff --git a/tests/models/test_ultralytics.py b/tests/models/test_ultralytics.py index 3e7a7b5c..cca1d023 100644 --- a/tests/models/test_ultralytics.py +++ b/tests/models/test_ultralytics.py @@ -1,4 +1,5 @@ from unittest.mock import patch + from swarms.models.ultralytics_model import UltralyticsModel diff --git a/tests/models/test_vilt.py b/tests/models/test_vilt.py index 99e6848e..d849f98e 100644 --- a/tests/models/test_vilt.py +++ b/tests/models/test_vilt.py @@ -1,6 +1,8 @@ +from unittest.mock import Mock, patch + import pytest -from unittest.mock import patch, Mock -from swarms.models.vilt import Vilt, Image, requests + +from swarms.models.vilt import Image, Vilt, requests # Fixture for Vilt instance diff --git a/tests/models/test_yi_200k.py b/tests/models/test_yi_200k.py index 9f3c236f..b31daa3e 100644 --- a/tests/models/test_yi_200k.py +++ b/tests/models/test_yi_200k.py @@ -1,6 +1,7 @@ import pytest import torch from transformers import AutoTokenizer + from swarms.models.yi_200k import Yi34B200k diff --git a/tests/structs/test_agent.py b/tests/structs/test_agent.py index 8e5b11be..5be7f31a 100644 --- a/tests/structs/test_agent.py +++ b/tests/structs/test_agent.py @@ -184,7 +184,7 @@ def test_save_different_memory(basic_flow, tmp_path): file_path = tmp_path / "memory.json" basic_flow.memory.append(["Task1", "Task2", "Task3"]) basic_flow.save(file_path) - with open(file_path, "r") as f: + with open(file_path) as f: data = json.load(f) assert data == [["Task1", "Task2", "Task3"]] diff --git a/tests/structs/test_autoscaler.py b/tests/structs/test_autoscaler.py index ac3da51a..2e5585bf 100644 --- a/tests/structs/test_autoscaler.py +++ b/tests/structs/test_autoscaler.py @@ -1,9 +1,8 @@ import os - -from dotenv import load_dotenv from unittest.mock import MagicMock, patch import pytest +from dotenv import load_dotenv from swarms.models import OpenAIChat from swarms.structs import Agent diff --git a/tests/structs/test_base.py b/tests/structs/test_base.py index 8b54dec0..971f966b 100644 --- a/tests/structs/test_base.py +++ b/tests/structs/test_base.py @@ -1,6 +1,8 @@ -import pytest import os from datetime import datetime + +import pytest + from swarms.structs.base import BaseStructure @@ -52,7 +54,7 @@ class TestBaseStructure: base_structure.log_error(error_message) log_file = os.path.join(tmp_dir, "TestStructure_errors.log") - with open(log_file, "r") as file: + with open(log_file) as file: lines = file.readlines() assert len(lines) == 1 assert lines[0] == f"{error_message}\n" @@ -83,7 +85,7 @@ class TestBaseStructure: base_structure.log_event(event, event_type) log_file = os.path.join(tmp_dir, "TestStructure_events.log") - with open(log_file, "r") as file: + with open(log_file) as file: lines = file.readlines() assert len(lines) == 1 assert ( @@ -122,7 +124,7 @@ class TestBaseStructure: await base_structure.log_error_async(error_message) log_file = os.path.join(tmp_dir, "TestStructure_errors.log") - with open(log_file, "r") as file: + with open(log_file) as file: lines = file.readlines() assert len(lines) == 1 assert lines[0] == f"{error_message}\n" @@ -165,7 +167,7 @@ class TestBaseStructure: await base_structure.log_event_async(event, event_type) log_file = os.path.join(tmp_dir, "TestStructure_events.log") - with open(log_file, "r") as file: + with open(log_file) as file: lines = file.readlines() assert len(lines) == 1 assert ( diff --git a/tests/structs/test_base_workflow.py b/tests/structs/test_base_workflow.py index 17be5ea8..ccb7a563 100644 --- a/tests/structs/test_base_workflow.py +++ b/tests/structs/test_base_workflow.py @@ -1,11 +1,12 @@ +import json import os + import pytest -import json +from dotenv import load_dotenv + from swarms.models import OpenAIChat from swarms.structs import BaseWorkflow -from dotenv import load_dotenv - load_dotenv() api_key = os.environ.get("OPENAI_API_KEY") diff --git a/tests/structs/test_company.py b/tests/structs/test_company.py index 0b1ec105..6de14da1 100644 --- a/tests/structs/test_company.py +++ b/tests/structs/test_company.py @@ -1,7 +1,8 @@ import pytest + +from swarms import OpenAIChat from swarms.structs.agent import Agent from swarms.structs.company import Company -from swarms import OpenAIChat # Mock OpenAIChat instance llm = OpenAIChat(openai_api_key="test_key", max_tokens=4000) diff --git a/tests/structs/test_concurrent_workflow.py b/tests/structs/test_concurrent_workflow.py index 206e8e2a..e3fabdd5 100644 --- a/tests/structs/test_concurrent_workflow.py +++ b/tests/structs/test_concurrent_workflow.py @@ -1,6 +1,7 @@ -from unittest.mock import Mock, create_autospec, patch from concurrent.futures import Future -from swarms.structs import ConcurrentWorkflow, Task, Agent +from unittest.mock import Mock, create_autospec, patch + +from swarms.structs import Agent, ConcurrentWorkflow, Task def test_add(): diff --git a/tests/structs/test_conversation.py b/tests/structs/test_conversation.py index 84673a42..049f3fb3 100644 --- a/tests/structs/test_conversation.py +++ b/tests/structs/test_conversation.py @@ -1,4 +1,5 @@ import pytest + from swarms.structs.conversation import Conversation diff --git a/tests/structs/test_json.py b/tests/structs/test_json.py new file mode 100644 index 00000000..9ba11072 --- /dev/null +++ b/tests/structs/test_json.py @@ -0,0 +1,73 @@ +# JSON + +# Contents of test_json.py, which must be placed in the `tests/` directory. + +import json + +import pytest + +from swarms.tokenizers import JSON + + +# Fixture for reusable JSON schema file paths +@pytest.fixture +def valid_schema_path(tmp_path): + d = tmp_path / "sub" + d.mkdir() + p = d / "schema.json" + p.write_text( + '{"type": "object", "properties": {"name": {"type":' + ' "string"}}}' + ) + return str(p) + + +@pytest.fixture +def invalid_schema_path(tmp_path): + d = tmp_path / "sub" + d.mkdir() + p = d / "invalid_schema.json" + p.write_text("this is not a valid JSON") + return str(p) + + +# This test class must be subclassed as JSON class is abstract +class TestableJSON(JSON): + def validate(self, data): + # Here must be a real validation implementation for testing + pass + + +# Basic tests +def test_initialize_json(valid_schema_path): + json_obj = TestableJSON(valid_schema_path) + assert json_obj.schema_path == valid_schema_path + assert "name" in json_obj.schema["properties"] + + +def test_load_schema_failure(invalid_schema_path): + with pytest.raises(json.JSONDecodeError): + TestableJSON(invalid_schema_path) + + +# Mocking tests +def test_validate_calls_method(monkeypatch): + # Mock the validate method to check that it is being called + pass + + +# Exception tests +def test_initialize_with_nonexistent_schema(): + with pytest.raises(FileNotFoundError): + TestableJSON("nonexistent_path.json") + + +# Tests on different Python versions if applicable +# ... + + +# Grouping tests marked as slow if they perform I/O operations +@pytest.mark.slow +def test_loading_large_schema(): + # Test with a large json file + pass diff --git a/tests/structs/test_majority_voting.py b/tests/structs/test_majority_voting.py new file mode 100644 index 00000000..dcd25f0b --- /dev/null +++ b/tests/structs/test_majority_voting.py @@ -0,0 +1,152 @@ +from unittest.mock import MagicMock + +import pytest + +from swarms.structs.agent import Agent +from swarms.structs.majority_voting import MajorityVoting + + +def test_majority_voting_run_concurrent(mocker): + # Create mock agents + agent1 = MagicMock(spec=Agent) + agent2 = MagicMock(spec=Agent) + agent3 = MagicMock(spec=Agent) + + # Create mock majority voting + mv = MajorityVoting( + agents=[agent1, agent2, agent3], + concurrent=True, + multithreaded=False, + ) + + # Create mock conversation + conversation = MagicMock() + mv.conversation = conversation + + # Create mock results + results = ["Paris", "Paris", "Lyon"] + + # Mock agent.run method + agent1.run.return_value = results[0] + agent2.run.return_value = results[1] + agent3.run.return_value = results[2] + + # Run majority voting + majority_vote = mv.run("What is the capital of France?") + + # Assert agent.run method was called with the correct task + agent1.run.assert_called_once_with( + "What is the capital of France?" + ) + agent2.run.assert_called_once_with( + "What is the capital of France?" + ) + agent3.run.assert_called_once_with( + "What is the capital of France?" + ) + + # Assert conversation.add method was called with the correct responses + conversation.add.assert_any_call(agent1.agent_name, results[0]) + conversation.add.assert_any_call(agent2.agent_name, results[1]) + conversation.add.assert_any_call(agent3.agent_name, results[2]) + + # Assert majority vote is correct + assert majority_vote is not None + + +def test_majority_voting_run_multithreaded(mocker): + # Create mock agents + agent1 = MagicMock(spec=Agent) + agent2 = MagicMock(spec=Agent) + agent3 = MagicMock(spec=Agent) + + # Create mock majority voting + mv = MajorityVoting( + agents=[agent1, agent2, agent3], + concurrent=False, + multithreaded=True, + ) + + # Create mock conversation + conversation = MagicMock() + mv.conversation = conversation + + # Create mock results + results = ["Paris", "Paris", "Lyon"] + + # Mock agent.run method + agent1.run.return_value = results[0] + agent2.run.return_value = results[1] + agent3.run.return_value = results[2] + + # Run majority voting + majority_vote = mv.run("What is the capital of France?") + + # Assert agent.run method was called with the correct task + agent1.run.assert_called_once_with( + "What is the capital of France?" + ) + agent2.run.assert_called_once_with( + "What is the capital of France?" + ) + agent3.run.assert_called_once_with( + "What is the capital of France?" + ) + + # Assert conversation.add method was called with the correct responses + conversation.add.assert_any_call(agent1.agent_name, results[0]) + conversation.add.assert_any_call(agent2.agent_name, results[1]) + conversation.add.assert_any_call(agent3.agent_name, results[2]) + + # Assert majority vote is correct + assert majority_vote is not None + + +@pytest.mark.asyncio +async def test_majority_voting_run_asynchronous(mocker): + # Create mock agents + agent1 = MagicMock(spec=Agent) + agent2 = MagicMock(spec=Agent) + agent3 = MagicMock(spec=Agent) + + # Create mock majority voting + mv = MajorityVoting( + agents=[agent1, agent2, agent3], + concurrent=False, + multithreaded=False, + asynchronous=True, + ) + + # Create mock conversation + conversation = MagicMock() + mv.conversation = conversation + + # Create mock results + results = ["Paris", "Paris", "Lyon"] + + # Mock agent.run method + agent1.run.return_value = results[0] + agent2.run.return_value = results[1] + agent3.run.return_value = results[2] + + # Run majority voting + majority_vote = await mv.run("What is the capital of France?") + + # Assert agent.run method was called with the correct task + agent1.run.assert_called_once_with( + "What is the capital of France?" + ) + agent2.run.assert_called_once_with( + "What is the capital of France?" + ) + agent3.run.assert_called_once_with( + "What is the capital of France?" + ) + + # Assert conversation.add method was called with the correct responses + conversation.add.assert_any_call(agent1.agent_name, results[0]) + conversation.add.assert_any_call(agent2.agent_name, results[1]) + conversation.add.assert_any_call(agent3.agent_name, results[2]) + + # Assert majority vote is correct + assert majority_vote is not None diff --git a/tests/structs/test_majorityvoting.py b/tests/structs/test_majorityvoting.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/structs/test_message_pool.py b/tests/structs/test_message_pool.py new file mode 100644 index 00000000..cfbb4df5 --- /dev/null +++ b/tests/structs/test_message_pool.py @@ -0,0 +1,117 @@ +from swarms import OpenAIChat +from swarms.structs.agent import Agent +from swarms.structs.message_pool import MessagePool + + +def test_message_pool_initialization(): + agent1 = Agent(llm=OpenAIChat(), agent_name="agent1") + agent2 = Agent(llm=OpenAIChat(), agent_name="agent1") + moderator = Agent(llm=OpenAIChat(), agent_name="agent1") + agents = [agent1, agent2] + message_pool = MessagePool( + agents=agents, moderator=moderator, turns=5 + ) + + assert message_pool.agent == agents + assert message_pool.moderator == moderator + assert message_pool.turns == 5 + assert message_pool.messages == [] + + +def test_message_pool_add(): + agent1 = Agent(llm=OpenAIChat(), agent_name="agent1") + message_pool = MessagePool( + agents=[agent1], moderator=agent1, turns=5 + ) + message_pool.add(agent=agent1, content="Hello, world!", turn=1) + + assert message_pool.messages == [ + { + "agent": agent1, + "content": "Hello, world!", + "turn": 1, + "visible_to": "all", + "logged": True, + } + ] + + +def test_message_pool_reset(): + agent1 = Agent(llm=OpenAIChat(), agent_name="agent1") + message_pool = MessagePool( + agents=[agent1], moderator=agent1, turns=5 + ) + message_pool.add(agent=agent1, content="Hello, world!", turn=1) + message_pool.reset() + + assert message_pool.messages == [] + + +def test_message_pool_last_turn(): + agent1 = Agent(llm=OpenAIChat(), agent_name="agent1") + message_pool = MessagePool( + agents=[agent1], moderator=agent1, turns=5 + ) + message_pool.add(agent=agent1, content="Hello, world!", turn=1) + + assert message_pool.last_turn() == 1 + + +def test_message_pool_last_message(): + agent1 = Agent(llm=OpenAIChat(), agent_name="agent1") + message_pool = MessagePool( + agents=[agent1], moderator=agent1, turns=5 + ) + message_pool.add(agent=agent1, content="Hello, world!", turn=1) + + assert message_pool.last_message == { + "agent": agent1, + "content": "Hello, world!", + "turn": 1, + "visible_to": "all", + "logged": True, + } + + +def test_message_pool_get_all_messages(): + agent1 = Agent(llm=OpenAIChat(), agent_name="agent1") + message_pool = MessagePool( + agents=[agent1], moderator=agent1, turns=5 + ) + message_pool.add(agent=agent1, content="Hello, world!", turn=1) + + assert message_pool.get_all_messages() == [ + { + "agent": agent1, + "content": "Hello, world!", + "turn": 1, + "visible_to": "all", + "logged": True, + } + ] + + +def test_message_pool_get_visible_messages(): + agent1 = Agent(llm=OpenAIChat(), agent_name="agent1") + agent2 = Agent(agent_name="agent2") + message_pool = MessagePool( + agents=[agent1, agent2], moderator=agent1, turns=5 + ) + message_pool.add( + agent=agent1, + content="Hello, agent2!", + turn=1, + visible_to=[agent2.agent_name], + ) + + assert message_pool.get_visible_messages( + agent=agent2, turn=2 + ) == [ + { + "agent": agent1, + "content": "Hello, agent2!", + "turn": 1, + "visible_to": [agent2.agent_name], + "logged": True, + } + ] diff --git a/tests/structs/test_model_parallizer.py b/tests/structs/test_model_parallizer.py index 37ca43db..a0840608 100644 --- a/tests/structs/test_model_parallizer.py +++ b/tests/structs/test_model_parallizer.py @@ -1,11 +1,12 @@ import pytest -from swarms.structs.model_parallizer import ModelParallelizer + from swarms.models import ( + GPT4VisionAPI, HuggingfaceLLM, Mixtral, - GPT4VisionAPI, ZeroscopeTTV, ) +from swarms.structs.model_parallizer import ModelParallelizer # Initialize the models custom_config = { diff --git a/tests/structs/test_multi_agent_collab.py b/tests/structs/test_multi_agent_collab.py index 475b32b3..555771e7 100644 --- a/tests/structs/test_multi_agent_collab.py +++ b/tests/structs/test_multi_agent_collab.py @@ -1,12 +1,12 @@ import json import os -import pytest from unittest.mock import Mock -from swarms.structs import Agent + +import pytest + from swarms.models import OpenAIChat -from swarms.structs.multi_agent_collab import ( - MultiAgentCollaboration, -) +from swarms.structs import Agent +from swarms.structs.multi_agent_collab import MultiAgentCollaboration # Sample agents for testing agent1 = Agent(llm=OpenAIChat(), max_loops=2) @@ -126,7 +126,7 @@ def test_save(collaboration, tmp_path): collaboration.saved_file_path_name = tmp_path / "test_save.json" collaboration.save() - with open(collaboration.saved_file_path_name, "r") as file: + with open(collaboration.saved_file_path_name) as file: saved_data = json.load(file) assert saved_data["_step"] == collaboration._step diff --git a/tests/structs/test_nonlinear_workflow.py b/tests/structs/test_nonlinear_workflow.py index 8919fc76..2544a7e4 100644 --- a/tests/structs/test_nonlinear_workflow.py +++ b/tests/structs/test_nonlinear_workflow.py @@ -1,6 +1,7 @@ import pytest -from swarms.structs import NonlinearWorkflow, Task + from swarms.models import OpenAIChat +from swarms.structs import NonlinearWorkflow, Task class TestNonlinearWorkflow: diff --git a/tests/structs/test_recursive_workflow.py b/tests/structs/test_recursive_workflow.py index 171c7cad..5b24f921 100644 --- a/tests/structs/test_recursive_workflow.py +++ b/tests/structs/test_recursive_workflow.py @@ -1,5 +1,7 @@ -import pytest from unittest.mock import Mock, create_autospec + +import pytest + from swarms.models import OpenAIChat from swarms.structs import RecursiveWorkflow, Task diff --git a/tests/structs/test_task.py b/tests/structs/test_task.py index 8a76549c..de0352af 100644 --- a/tests/structs/test_task.py +++ b/tests/structs/test_task.py @@ -1,3 +1,5 @@ +import datetime +from datetime import timedelta from unittest.mock import Mock import pytest @@ -9,8 +11,6 @@ from swarms.prompts.multi_modal_autonomous_instruction_prompt import ( ) from swarms.structs.agent import Agent from swarms.structs.task import Task -import datetime -from datetime import timedelta load_dotenv() diff --git a/tests/structs/test_taskqueuebase.py b/tests/structs/test_taskqueuebase.py new file mode 100644 index 00000000..512f72ae --- /dev/null +++ b/tests/structs/test_taskqueuebase.py @@ -0,0 +1,105 @@ +# TaskQueueBase + +import threading +from unittest.mock import Mock + +import pytest + +from swarms.tokenizers import Agent, Task, TaskQueueBase + + +# Create mocked instances of dependencies +@pytest.fixture() +def task(): + return Mock(spec=Task) + + +@pytest.fixture() +def agent(): + return Mock(spec=Agent) + + +@pytest.fixture() +def concrete_task_queue(): + class ConcreteTaskQueue(TaskQueueBase): + def add_task(self, task): + pass # Here you would add concrete implementation of add_task + + def get_task(self, agent): + pass # Concrete implementation of get_task + + def complete_task(self, task_id): + pass # Concrete implementation of complete_task + + def reset_task(self, task_id): + pass # Concrete implementation of reset_task + + return ConcreteTaskQueue() + + +def test_task_queue_initialization(concrete_task_queue): + assert isinstance(concrete_task_queue, TaskQueueBase) + assert isinstance(concrete_task_queue.lock, threading.Lock) + + +def test_add_task_success(concrete_task_queue, task): + # Assuming add_task returns True on success + assert concrete_task_queue.add_task(task) is True + + +def test_add_task_failure(concrete_task_queue, task): + # Assuming the task is somehow invalid + # Note: Concrete implementation requires logic defining what an invalid task is + concrete_task_queue.add_task(task) + assert ( + concrete_task_queue.add_task(task) is False + ) # Adding the same task again + + +@pytest.mark.parametrize("invalid_task", [None, "", {}, []]) +def test_add_task_invalid_input(concrete_task_queue, invalid_task): + with pytest.raises(TypeError): + concrete_task_queue.add_task(invalid_task) + + +def test_get_task_success(concrete_task_queue, agent): + # Assuming there's a mechanism to populate queue + # You will need to add a task before getting it + task = Mock(spec=Task) + concrete_task_queue.add_task(task) + assert concrete_task_queue.get_task(agent) == task + + +# def test_get_task_no_tasks_available(concrete_task_queue, agent): +# with pytest.raises( +# EmptyQueueError +# ): # Assuming such an exception exists +# concrete_task_queue.get_task(agent) + + +def test_complete_task_success(concrete_task_queue): + task_id = "test_task_123" + # Populating queue and completing task assumed + assert concrete_task_queue.complete_task(task_id) is None + + +# def test_complete_task_with_invalid_id(concrete_task_queue): +# invalid_task_id = "invalid_id" +# with pytest.raises( +# TaskNotFoundError +# ): # Assuming such an exception exists +# concrete_task_queue.complete_task(invalid_task_id) + + +def test_reset_task_success(concrete_task_queue): + task_id = "test_task_123" + # Populating queue and resetting task assumed + assert concrete_task_queue.reset_task(task_id) is None + + +# def test_reset_task_with_invalid_id(concrete_task_queue): +# invalid_task_id = "invalid_id" +# with pytest.raises( +# TaskNotFoundError +# ): # Assuming such an exception exists +# concrete_task_queue.reset_task(invalid_task_id) diff --git a/tests/structs/test_tests_graph_workflow.py b/tests/structs/test_tests_graph_workflow.py index c4bafd35..cb5b17a7 100644 --- a/tests/structs/test_tests_graph_workflow.py +++ b/tests/structs/test_tests_graph_workflow.py @@ -1,4 +1,5 @@ import pytest + from swarms.structs.graph_workflow import GraphWorkflow diff --git a/tests/test_upload_tests_to_issues.py b/tests/test_upload_tests_to_issues.py index 15de1245..0857c58a 100644 --- a/tests/test_upload_tests_to_issues.py +++ b/tests/test_upload_tests_to_issues.py @@ -1,5 +1,6 @@ import os import subprocess + import requests from dotenv import load_dotenv diff --git a/tests/tokenizers/test_anthropictokenizer.py b/tests/tokenizers/test_anthropictokenizer.py index 5d49b5eb..14b2fd86 100644 --- a/tests/tokenizers/test_anthropictokenizer.py +++ b/tests/tokenizers/test_anthropictokenizer.py @@ -1,6 +1,7 @@ # AnthropicTokenizer import pytest + from swarms.tokenizers.anthropic_tokenizer import AnthropicTokenizer diff --git a/tests/tokenizers/test_basetokenizer.py b/tests/tokenizers/test_basetokenizer.py index 9bd5d9c6..3956d2de 100644 --- a/tests/tokenizers/test_basetokenizer.py +++ b/tests/tokenizers/test_basetokenizer.py @@ -1,6 +1,7 @@ # BaseTokenizer import pytest + from swarms.tokenizers.base_tokenizer import BaseTokenizer diff --git a/tests/tokenizers/test_coheretokenizer.py b/tests/tokenizers/test_coheretokenizer.py index 65633d9a..2607cf9a 100644 --- a/tests/tokenizers/test_coheretokenizer.py +++ b/tests/tokenizers/test_coheretokenizer.py @@ -1,8 +1,10 @@ # CohereTokenizer +from unittest.mock import MagicMock + import pytest + from swarms.tokenizers.cohere_tokenizer import CohereTokenizer -from unittest.mock import MagicMock @pytest.fixture diff --git a/tests/tokenizers/test_huggingfacetokenizer.py b/tests/tokenizers/test_huggingfacetokenizer.py index 3a0d29af..1eedb6e5 100644 --- a/tests/tokenizers/test_huggingfacetokenizer.py +++ b/tests/tokenizers/test_huggingfacetokenizer.py @@ -1,8 +1,10 @@ # HuggingFaceTokenizer -import pytest import os from unittest.mock import patch + +import pytest + from swarms.tokenizers.r_tokenizers import HuggingFaceTokenizer diff --git a/tests/tokenizers/test_openaitokenizer.py b/tests/tokenizers/test_openaitokenizer.py index 229db92d..3c24748d 100644 --- a/tests/tokenizers/test_openaitokenizer.py +++ b/tests/tokenizers/test_openaitokenizer.py @@ -1,6 +1,7 @@ # OpenAITokenizer import pytest + import swarms.tokenizers.openai_tokenizers as tokenizers diff --git a/tests/tokenizers/test_tokenizer.py b/tests/tokenizers/test_tokenizer.py index ea40a2e0..b868f0a1 100644 --- a/tests/tokenizers/test_tokenizer.py +++ b/tests/tokenizers/test_tokenizer.py @@ -1,8 +1,9 @@ # Tokenizer -from swarms.tokenizers.r_tokenizers import Tokenizer from unittest.mock import patch +from swarms.tokenizers.r_tokenizers import Tokenizer + def test_initializer_existing_model_file(): with patch("os.path.exists", return_value=True): diff --git a/tests/utils/test_check_device.py b/tests/utils/test_check_device.py index d542803a..503a3774 100644 --- a/tests/utils/test_check_device.py +++ b/tests/utils/test_check_device.py @@ -1,5 +1,7 @@ -import torch import logging + +import torch + from swarms.utils import check_device # For the purpose of the test, we're assuming that the `memory_allocated` diff --git a/tests/utils/test_class_args_wrapper.py b/tests/utils/test_class_args_wrapper.py index a222ffe9..99d38b2c 100644 --- a/tests/utils/test_class_args_wrapper.py +++ b/tests/utils/test_class_args_wrapper.py @@ -1,11 +1,13 @@ -import pytest -from io import StringIO from contextlib import redirect_stdout -from swarms.utils.class_args_wrapper import print_class_parameters -from swarms.structs.agent import Agent +from io import StringIO + +import pytest from fastapi import FastAPI from fastapi.testclient import TestClient +from swarms.structs.agent import Agent +from swarms.utils.class_args_wrapper import print_class_parameters + app = FastAPI() diff --git a/tests/utils/test_device.py b/tests/utils/test_device.py index 14399de9..9be83be4 100644 --- a/tests/utils/test_device.py +++ b/tests/utils/test_device.py @@ -1,6 +1,8 @@ -import torch from unittest.mock import MagicMock + import pytest +import torch + from swarms.utils.device_checker_cuda import check_device diff --git a/tests/utils/test_display_markdown_message.py b/tests/utils/test_display_markdown_message.py index 048038b2..1b7cadaa 100644 --- a/tests/utils/test_display_markdown_message.py +++ b/tests/utils/test_display_markdown_message.py @@ -1,10 +1,12 @@ # import necessary modules +from unittest import mock + import pytest -from swarms.utils import display_markdown_message from rich.console import Console from rich.markdown import Markdown from rich.rule import Rule -from unittest import mock + +from swarms.utils import display_markdown_message def test_basic_message(): diff --git a/tests/utils/test_extract_code_from_markdown.py b/tests/utils/test_extract_code_from_markdown.py index 9d37fc94..eb1a3e5d 100644 --- a/tests/utils/test_extract_code_from_markdown.py +++ b/tests/utils/test_extract_code_from_markdown.py @@ -1,4 +1,5 @@ import pytest + from swarms.utils import extract_code_from_markdown diff --git a/tests/utils/test_find_image_path.py b/tests/utils/test_find_image_path.py index 9fbc09ee..29b1c627 100644 --- a/tests/utils/test_find_image_path.py +++ b/tests/utils/test_find_image_path.py @@ -1,8 +1,10 @@ # Filename: test_utils.py +import os + import pytest + from swarms.utils import find_image_path -import os def test_find_image_path_no_images(): diff --git a/tests/utils/test_limit_tokens_from_string.py b/tests/utils/test_limit_tokens_from_string.py index 5b5f8efd..4d68dccb 100644 --- a/tests/utils/test_limit_tokens_from_string.py +++ b/tests/utils/test_limit_tokens_from_string.py @@ -1,4 +1,5 @@ import pytest + from swarms.utils import limit_tokens_from_string diff --git a/tests/utils/test_load_model_torch.py b/tests/utils/test_load_model_torch.py index ef2c17d4..c2018c6a 100644 --- a/tests/utils/test_load_model_torch.py +++ b/tests/utils/test_load_model_torch.py @@ -1,6 +1,7 @@ import pytest import torch from torch import nn + from swarms.utils import load_model_torch diff --git a/tests/utils/test_load_models_torch.py b/tests/utils/test_load_models_torch.py index 707f1ce4..3f09f411 100644 --- a/tests/utils/test_load_models_torch.py +++ b/tests/utils/test_load_models_torch.py @@ -1,6 +1,8 @@ +from unittest.mock import MagicMock + import pytest import torch -from unittest.mock import MagicMock + from swarms.utils.load_model_torch import load_model_torch diff --git a/tests/utils/test_metrics_decorator.py b/tests/utils/test_metrics_decorator.py index 7a676657..719d50a7 100644 --- a/tests/utils/test_metrics_decorator.py +++ b/tests/utils/test_metrics_decorator.py @@ -1,10 +1,11 @@ # pytest imports -import pytest +import time from unittest.mock import Mock +import pytest + # Imports from your project from swarms.utils import metrics_decorator -import time # Basic successful test diff --git a/tests/utils/test_pdf_to_text.py b/tests/utils/test_pdf_to_text.py index 57e3b33f..257364b4 100644 --- a/tests/utils/test_pdf_to_text.py +++ b/tests/utils/test_pdf_to_text.py @@ -1,12 +1,13 @@ +import pypdf import pytest -import PyPDF2 + from swarms.utils import pdf_to_text @pytest.fixture def pdf_file(tmpdir): - pdf_writer = PyPDF2.PdfWriter() - pdf_page = PyPDF2.pdf.PageObject.createBlankPage(None, 200, 200) + pdf_writer = pypdf.PdfWriter() + pdf_page = pypdf.PageObject.create_blank_page(None, 200, 200) pdf_writer.add_page(pdf_page) pdf_file = tmpdir.join("temp.pdf") with open(pdf_file, "wb") as output: diff --git a/tests/utils/test_prep_torch_inference.py b/tests/utils/test_prep_torch_inference.py index 8ee33fbc..6af4a9a7 100644 --- a/tests/utils/test_prep_torch_inference.py +++ b/tests/utils/test_prep_torch_inference.py @@ -1,7 +1,9 @@ import unittest +from unittest.mock import Mock + import pytest import torch -from unittest.mock import Mock + from swarms.utils import prep_torch_inference diff --git a/tests/utils/test_prep_torch_model_inference.py b/tests/utils/test_prep_torch_model_inference.py index 4a13bee1..07da4e97 100644 --- a/tests/utils/test_prep_torch_model_inference.py +++ b/tests/utils/test_prep_torch_model_inference.py @@ -1,5 +1,7 @@ -import torch from unittest.mock import MagicMock + +import torch + from swarms.utils.prep_torch_model_inference import ( prep_torch_inference, ) diff --git a/tests/utils/test_print_class_parameters.py b/tests/utils/test_print_class_parameters.py index ae824170..9a133ae4 100644 --- a/tests/utils/test_print_class_parameters.py +++ b/tests/utils/test_print_class_parameters.py @@ -1,4 +1,5 @@ import pytest + from swarms.utils import print_class_parameters diff --git a/tests/utils/test_subprocess_code_interpreter.py b/tests/utils/test_subprocess_code_interpreter.py index 3ce54530..3bb800f5 100644 --- a/tests/utils/test_subprocess_code_interpreter.py +++ b/tests/utils/test_subprocess_code_interpreter.py @@ -1,10 +1,12 @@ -import pytest +import queue import subprocess import threading -import queue -from swarms.utils.code_interpreter import ( + +import pytest + +from swarms.utils.code_interpreter import ( # Adjust the import according to your project structure SubprocessCodeInterpreter, -) # Adjust the import according to your project structure +) # Fixture for the SubprocessCodeInterpreter instance