Switch to CAI structure from swarm inspiration

Signed-off-by: Víctor Mayoral Vilches <v.mayoralv@gmail.com>
This commit is contained in:
Víctor Mayoral Vilches 2025-01-09 13:20:31 +01:00
parent 0d3a036902
commit c3e3983143
35 changed files with 104 additions and 102 deletions

View File

@ -1,34 +1,34 @@
![Swarm Logo](assets/logo.png)
![CAI Logo](assets/logo.png)
# Swarm (experimental, educational)
# CAI (experimental, educational)
An educational framework exploring ergonomic, lightweight multi-agent orchestration.
> [!WARNING]
> Swarm is currently an experimental sample framework intended to explore ergonomic interfaces for multi-agent systems. It is not intended to be used in production, and therefore has no official support. (This also means we will not be reviewing PRs or issues!)
> CAI is currently an experimental sample framework intended to explore ergonomic interfaces for multi-agent systems. It is not intended to be used in production, and therefore has no official support. (This also means we will not be reviewing PRs or issues!)
>
> The primary goal of Swarm is to showcase the handoff & routines patterns explored in the [Orchestrating Agents: Handoffs & Routines](https://cookbook.openai.com/examples/orchestrating_agents) cookbook. It is not meant as a standalone library, and is primarily for educational purposes.
> The primary goal of CAI is to showcase the handoff & routines patterns explored in the [Orchestrating Agents: Handoffs & Routines](https://cookbook.openai.com/examples/orchestrating_agents) cookbook. It is not meant as a standalone library, and is primarily for educational purposes.
## Install
Requires Python 3.10+
```shell
pip install git+ssh://git@github.com/openai/swarm.git
pip install git+ssh://git@github.com/openai/cai.git
```
or
```shell
pip install git+https://github.com/openai/swarm.git
pip install git+https://github.com/openai/cai.git
```
## Usage
```python
from swarm import Swarm, Agent
from cai import CAI, Agent
client = Swarm()
client = CAI()
def transfer_to_agent_b():
return agent_b
@ -64,7 +64,7 @@ What can I assist?
- [Overview](#overview)
- [Examples](#examples)
- [Documentation](#documentation)
- [Running Swarm](#running-swarm)
- [Running CAI](#running-cai)
- [Agents](#agents)
- [Functions](#functions)
- [Streaming](#streaming)
@ -73,20 +73,20 @@ What can I assist?
# Overview
Swarm focuses on making agent **coordination** and **execution** lightweight, highly controllable, and easily testable.
CAI focuses on making agent **coordination** and **execution** lightweight, highly controllable, and easily testable.
It accomplishes this through two primitive abstractions: `Agent`s and **handoffs**. An `Agent` encompasses `instructions` and `tools`, and can at any point choose to hand off a conversation to another `Agent`.
These primitives are powerful enough to express rich dynamics between tools and networks of agents, allowing you to build scalable, real-world solutions while avoiding a steep learning curve.
> [!NOTE]
> Swarm Agents are not related to Assistants in the Assistants API. They are named similarly for convenience, but are otherwise completely unrelated. Swarm is entirely powered by the Chat Completions API and is hence stateless between calls.
> CAI Agents are not related to Assistants in the Assistants API. They are named similarly for convenience, but are otherwise completely unrelated. CAI is entirely powered by the Chat Completions API and is hence stateless between calls.
## Why Swarm
## Why CAI
Swarm explores patterns that are lightweight, scalable, and highly customizable by design. Approaches similar to Swarm are best suited for situations dealing with a large number of independent capabilities and instructions that are difficult to encode into a single prompt.
CAI explores patterns that are lightweight, scalable, and highly customizable by design. Approaches similar to CAI are best suited for situations dealing with a large number of independent capabilities and instructions that are difficult to encode into a single prompt.
The Assistants API is a great option for developers looking for fully-hosted threads and built in memory management and retrieval. However, Swarm is an educational resource for developers curious to learn about multi-agent orchestration. Swarm runs (almost) entirely on the client and, much like the Chat Completions API, does not store state between calls.
The Assistants API is a great option for developers looking for fully-hosted threads and built in memory management and retrieval. However, CAI is an educational resource for developers curious to learn about multi-agent orchestration. CAI runs (almost) entirely on the client and, much like the Chat Completions API, does not store state between calls.
# Examples
@ -101,23 +101,23 @@ Check out `/examples` for inspiration! Learn more about each one in its README.
# Documentation
![Swarm Diagram](assets/swarm_diagram.png)
![CAI Diagram](assets/swarm_diagram.png)
## Running Swarm
## Running CAI
Start by instantiating a Swarm client (which internally just instantiates an `OpenAI` client).
Start by instantiating a CAI client (which internally just instantiates an `OpenAI` client).
```python
from swarm import Swarm
from cai import CAI
client = Swarm()
client = CAI()
```
### `client.run()`
Swarm's `run()` function is analogous to the `chat.completions.create()` function in the Chat Completions API it takes `messages` and returns `messages` and saves no state between calls. Importantly, however, it also handles Agent function execution, hand-offs, context variable references, and can take multiple turns before returning to the user.
CAI's `run()` function is analogous to the `chat.completions.create()` function in the Chat Completions API it takes `messages` and returns `messages` and saves no state between calls. Importantly, however, it also handles Agent function execution, hand-offs, context variable references, and can take multiple turns before returning to the user.
At its core, Swarm's `client.run()` implements the following loop:
At its core, CAI's `client.run()` implements the following loop:
1. Get a completion from the current Agent
2. Execute tool calls and append results
@ -138,7 +138,7 @@ At its core, Swarm's `client.run()` implements the following loop:
| **stream** | `bool` | If `True`, enables streaming responses | `False` |
| **debug** | `bool` | If `True`, enables debug logging | `False` |
Once `client.run()` is finished (after potentially multiple calls to agents and tools) it will return a `Response` containing all the relevant updated state. Specifically, the new `messages`, the last `Agent` to be called, and the most up-to-date `context_variables`. You can pass these values (plus new user messages) in to your next execution of `client.run()` to continue the interaction where it left off much like `chat.completions.create()`. (The `run_demo_loop` function implements an example of a full execution loop in `/swarm/repl/repl.py`.)
Once `client.run()` is finished (after potentially multiple calls to agents and tools) it will return a `Response` containing all the relevant updated state. Specifically, the new `messages`, the last `Agent` to be called, and the most up-to-date `context_variables`. You can pass these values (plus new user messages) in to your next execution of `client.run()` to continue the interaction where it left off much like `chat.completions.create()`. (The `run_demo_loop` function implements an example of a full execution loop in `/cai/repl/repl.py`.)
#### `Response` Fields
@ -198,7 +198,7 @@ Hi John, how can I assist you today?
## Functions
- Swarm `Agent`s can call python functions directly.
- CAI `Agent`s can call python functions directly.
- Function should usually return a `str` (values will be attempted to be cast as a `str`).
- If a function returns an `Agent`, execution will be transferred to that `Agent`.
- If a function defines a `context_variables` parameter, it will be populated by the `context_variables` passed into `client.run()`.
@ -282,7 +282,7 @@ Sales Agent
### Function Schemas
Swarm automatically converts functions into a JSON Schema that is passed into Chat Completions `tools`.
CAI automatically converts functions into a JSON Schema that is passed into Chat Completions `tools`.
- Docstrings are turned into the function `description`.
- Parameters without default values are set to `required`.
@ -328,7 +328,7 @@ for chunk in stream:
print(chunk)
```
Uses the same events as [Chat Completions API streaming](https://platform.openai.com/docs/api-reference/streaming). See `process_and_print_streaming_response` in `/swarm/repl/repl.py` as an example.
Uses the same events as [Chat Completions API streaming](https://platform.openai.com/docs/api-reference/streaming). See `process_and_print_streaming_response` in `/cai/repl/repl.py` as an example.
Two new event types have been added:
@ -337,14 +337,14 @@ Two new event types have been added:
# Evaluations
Evaluations are crucial to any project, and we encourage developers to bring their own eval suites to test the performance of their swarms. For reference, we have some examples for how to eval swarm in the `airline`, `weather_agent` and `triage_agent` quickstart examples. See the READMEs for more details.
Evaluations are crucial to any project, and we encourage developers to bring their own eval suites to test the performance of their swarms. For reference, we have some examples for how to eval cai in the `airline`, `weather_agent` and `triage_agent` quickstart examples. See the READMEs for more details.
# Utils
Use the `run_demo_loop` to test out your swarm! This will run a REPL on your command line. Supports streaming.
Use the `run_demo_loop` to test out your cai! This will run a REPL on your command line. Supports streaming.
```python
from swarm.repl import run_demo_loop
from cai.repl import run_demo_loop
...
run_demo_loop(agent, stream=True)
```

7
cai/__init__.py Normal file
View File

@ -0,0 +1,7 @@
"""
A library to build Bug Bounty-level grade Cybersecurity AIs (CAIs).
"""
from .core import CAI
from .types import Agent, Response
__all__ = ["CAI", "Agent", "Response"]

View File

@ -1,7 +1,7 @@
"""
Core module for the Swarm library.
Core module for the CAI library.
This module contains the main Swarm class which handles chat completions,
This module contains the main CAI class which handles chat completions,
tool calls, and agent interactions. It provides both synchronous and
streaming interfaces for running conversations with AI agents.
@ -34,9 +34,9 @@ from .types import (
__CTX_VARS_NAME__ = "context_variables"
class Swarm:
class CAI:
"""
Main class for the Swarm library.
Main class for the CAI library.
"""
def __init__(self, client=None,
@ -174,7 +174,7 @@ class Swarm:
execute_tools: bool = True,
):
"""
Run the swarm and stream the results.
Run the cai and stream the results.
"""
active_agent = agent
context_variables = copy.deepcopy(context_variables)
@ -271,7 +271,7 @@ class Swarm:
execute_tools: bool = True,
) -> Response:
"""
Run the swarm and return the final response.
Run the cai and return the final response.
"""
if stream:
return self.run_and_stream(

View File

@ -1,6 +1,6 @@
"""
This module provides a REPL interface for testing and
interacting with Swarm agents.
interacting with CAI agents.
"""
from .repl import run_demo_loop # noqa: F401

View File

@ -1,15 +1,15 @@
"""
This module provides a REPL interface for testing and
interacting with Swarm agents.
interacting with CAI agents.
"""
import json
from swarm import Swarm # pylint: disable=import-error
from cai import CAI # pylint: disable=import-error
def process_and_print_streaming_response(response): # pylint: disable=inconsistent-return-statements # noqa: E501
"""
Process and print streaming responses from Swarm.
Process and print streaming responses from CAI.
"""
content = ""
last_sender = ""
@ -43,7 +43,7 @@ def process_and_print_streaming_response(response): # pylint: disable=inconsist
def pretty_print_messages(messages) -> None:
"""
Pretty print messages from Swarm.
Pretty print messages from CAI.
"""
for message in messages:
if message["role"] != "assistant":
@ -71,10 +71,10 @@ def run_demo_loop(
starting_agent, context_variables=None, stream=False, debug=False
) -> None:
"""
Run the demo loop for Swarm.
Run the demo loop for CAI.
"""
client = Swarm()
print("Starting Swarm CLI 🐝")
client = CAI()
print("Starting CAI CLI 🐝")
messages = []
agent = starting_agent

View File

@ -1,5 +1,5 @@
"""
This module contains type definitions for the Swarm library.
This module contains type definitions for the CAI library.
"""
from typing import List, Callable, Union, Optional
@ -17,7 +17,7 @@ AgentFunction = Callable[[], Union[str, "Agent", dict]]
class Agent(BaseModel): # pylint: disable=too-few-public-methods
"""
Represents an agent in the Swarm.
Represents an agent in the CAI.
"""
name: str = "Agent"
@ -31,7 +31,7 @@ class Agent(BaseModel): # pylint: disable=too-few-public-methods
class Response(BaseModel): # pylint: disable=too-few-public-methods
"""
Represents a response from the Swarm.
Represents a response from the CAI.
"""
messages: List = []

View File

@ -1,5 +1,5 @@
"""
This module contains utility functions for the Swarm library.
This module contains utility functions for the CAI library.
"""
import inspect

View File

@ -1,7 +1,7 @@
# Airline customer service
This example demonstrates a multi-agent setup for handling different customer service requests in an airline context using the Swarm framework. The agents can triage requests, handle flight modifications, cancellations, and lost baggage cases.
This example uses the helper function `run_demo_loop`, which allows us to create an interactive Swarm session.
This example demonstrates a multi-agent setup for handling different customer service requests in an airline context using the CAI framework. The agents can triage requests, handle flight modifications, cancellations, and lost baggage cases.
This example uses the helper function `run_demo_loop`, which allows us to create an interactive CAI session.
## Agents
@ -13,7 +13,7 @@ This example uses the helper function `run_demo_loop`, which allows us to create
## Setup
Once you have installed dependencies and Swarm, run the example using:
Once you have installed dependencies and CAI, run the example using:
```shell
python3 main.py

View File

@ -3,7 +3,7 @@ from data.routines.baggage.policies import *
from data.routines.flight_modification.policies import *
from data.routines.prompts import STARTER_PROMPT
from swarm import Agent
from cai import Agent
def transfer_to_flight_modification():

View File

@ -2,7 +2,7 @@ import datetime
import json
import uuid
from swarm import Swarm
from cai import CAI
def run_function_evals(agent, test_cases, n=1, eval_path=None):
@ -10,7 +10,7 @@ def run_function_evals(agent, test_cases, n=1, eval_path=None):
results = []
eval_id = str(uuid.uuid4())
eval_timestamp = datetime.datetime.now().isoformat()
client = Swarm()
client = CAI()
for test_case in test_cases:
case_correct = 0

View File

@ -1,5 +1,5 @@
from configs.agents import *
from swarm.repl import run_demo_loop
from cai.repl import run_demo_loop
context_variables = {
"customer_context": """Here is what you know about the customer's details:

View File

@ -1,6 +1,6 @@
# Swarm basic
# CAI basic
This folder contains basic examples demonstrating core Swarm capabilities. These examples show the simplest implementations of Swarm, with one input message, and a corresponding output. The `simple_loop_no_helpers` has a while loop to demonstrate how to create an interactive Swarm session.
This folder contains basic examples demonstrating core CAI capabilities. These examples show the simplest implementations of CAI, with one input message, and a corresponding output. The `simple_loop_no_helpers` has a while loop to demonstrate how to create an interactive CAI session.
### Examples

View File

@ -1,6 +1,6 @@
from swarm import Swarm, Agent
from cai import CAI, Agent
client = Swarm()
client = CAI()
english_agent = Agent(
model="qwen2.5:14b",

View File

@ -1,6 +1,6 @@
from swarm import Swarm, Agent
from cai import CAI, Agent
client = Swarm()
client = CAI()
agent = Agent(
name="Agent",

View File

@ -1,6 +1,6 @@
from swarm import Swarm, Agent
from cai import CAI, Agent
client = Swarm()
client = CAI()
def instructions(context_variables):

View File

@ -1,6 +1,6 @@
from swarm import Swarm, Agent
from cai import CAI, Agent
client = Swarm()
client = CAI()
def get_weather(location) -> str:

View File

@ -1,6 +1,6 @@
from swarm import Swarm, Agent
from cai import CAI, Agent
client = Swarm()
client = CAI()
my_agent = Agent(
name="Agent",

View File

@ -1,7 +1,7 @@
# Personal shopper
This Swarm is a personal shopping agent that can help with making sales and refunding orders.
This example uses the helper function `run_demo_loop`, which allows us to create an interactive Swarm session.
This CAI is a personal shopping agent that can help with making sales and refunding orders.
This example uses the helper function `run_demo_loop`, which allows us to create an interactive CAI session.
In this example, we also use a Sqlite3 database with customer information and transaction data.
## Overview
@ -14,7 +14,7 @@ The personal shopper example includes three main agents to handle various custom
## Setup
Once you have installed dependencies and Swarm, run the example using:
Once you have installed dependencies and CAI, run the example using:
```shell
python3 main.py

View File

@ -2,9 +2,9 @@ import datetime
import random
import database
from swarm import Agent
from swarm.agents import create_triage_agent
from swarm.repl import run_demo_loop
from cai import Agent
from cai.agents import create_triage_agent
from cai.repl import run_demo_loop
def refund_item(user_id, item_id):

View File

@ -1,7 +1,7 @@
# Support bot
This example is a customer service bot which includes a user interface agent and a help center agent with several tools.
This example uses the helper function `run_demo_loop`, which allows us to create an interactive Swarm session.
This example uses the helper function `run_demo_loop`, which allows us to create an interactive CAI session.
## Overview

View File

@ -3,8 +3,8 @@ import re
import qdrant_client
from openai import OpenAI
from swarm import Agent
from swarm.repl import run_demo_loop
from cai import Agent
from cai.repl import run_demo_loop
# Initialize connections
client = OpenAI()

View File

@ -3,8 +3,8 @@ import re
import qdrant_client
from openai import OpenAI
from swarm import Agent
from swarm.repl import run_demo_loop
from cai import Agent
from cai.repl import run_demo_loop
# Initialize connections
client = OpenAI()

View File

@ -1,11 +1,11 @@
# Triage agent
This example is a Swarm containing a triage agent, which takes in user inputs and chooses whether to respond directly, or triage the request
This example is a CAI containing a triage agent, which takes in user inputs and chooses whether to respond directly, or triage the request
to a sales or refunds agent.
## Setup
To run the triage agent Swarm:
To run the triage agent CAI:
1. Run

View File

@ -1,4 +1,4 @@
from swarm import Agent
from cai import Agent
def process_refund(item_id, reason="NOT SPECIFIED"):

View File

@ -1,10 +1,10 @@
from swarm import Swarm
from cai import CAI
from agents import triage_agent, sales_agent, refunds_agent
from evals_util import evaluate_with_llm_bool, BoolEvalResult
import pytest
import json
client = Swarm()
client = CAI()
CONVERSATIONAL_EVAL_SYSTEM_PROMPT = """
You will be provided with a conversation between a user and an agent, as well as a main goal for the conversation.

View File

@ -1,4 +1,4 @@
from swarm.repl import run_demo_loop
from cai.repl import run_demo_loop
from agents import triage_agent
if __name__ == "__main__":

View File

@ -4,7 +4,7 @@ This example is a weather agent demonstrating function calling with a single age
## Setup
To run the weather agent Swarm:
To run the weather agent CAI:
1. Run

View File

@ -1,6 +1,6 @@
import json
from swarm import Agent
from cai import Agent
def get_weather(location, time="now"):

View File

@ -1,8 +1,8 @@
from swarm import Swarm
from cai import CAI
from agents import weather_agent
import pytest
client = Swarm()
client = CAI()
def run_and_get_tool_calls(agent, query):

View File

@ -1,4 +1,4 @@
from swarm.repl import run_demo_loop
from cai.repl import run_demo_loop
from agents import weather_agent
if __name__ == "__main__":

View File

@ -1,8 +1,8 @@
[metadata]
name = swarm
name = cai
version = 0.1.0
author = OpenAI Solutions
description = A lightweight, stateless multi-agent orchestration framework.
author = Alias Robotics
description = A lightweight, ergonomic framework for building Bug Bounty-level grade Cybersecurity AIs (CAIs)
long_description = file: README.md
long_description_content_type = text/markdown
license = MIT

View File

@ -1,5 +0,0 @@
"""A library to build Bug Bounty-level grade Cybersecurity AIs."""
from .core import Swarm
from .types import Agent, Response
__all__ = ["Swarm", "Agent", "Response"]

View File

@ -1,5 +1,5 @@
from unittest.mock import MagicMock
from swarm.types import ChatCompletionMessage, ChatCompletionMessageToolCall, Function
from cai.types import ChatCompletionMessage, ChatCompletionMessageToolCall, Function
from openai import OpenAI
from openai.types.chat.chat_completion import ChatCompletion, Choice
import json

View File

@ -1,5 +1,5 @@
import pytest
from swarm import Swarm, Agent
from cai import CAI, Agent
from tests.mock_client import MockOpenAIClient, create_mock_response
from unittest.mock import Mock
import json
@ -20,7 +20,7 @@ def mock_openai_client():
def test_run_with_simple_message(mock_openai_client: MockOpenAIClient):
agent = Agent()
# set up client and run
client = Swarm(client=mock_openai_client)
client = CAI(client=mock_openai_client)
messages = [{"role": "user", "content": "Hello, how are you?"}]
response = client.run(agent=agent, messages=messages)
@ -61,7 +61,7 @@ def test_tool_call(mock_openai_client: MockOpenAIClient):
)
# set up client and run
client = Swarm(client=mock_openai_client)
client = CAI(client=mock_openai_client)
response = client.run(agent=agent, messages=messages)
get_weather_mock.assert_called_once_with(location=expected_location)
@ -101,7 +101,7 @@ def test_execute_tools_false(mock_openai_client: MockOpenAIClient):
)
# set up client and run
client = Swarm(client=mock_openai_client)
client = CAI(client=mock_openai_client)
response = client.run(agent=agent, messages=messages, execute_tools=False)
print(response)
@ -139,7 +139,7 @@ def test_handoff(mock_openai_client: MockOpenAIClient):
)
# set up client and run
client = Swarm(client=mock_openai_client)
client = CAI(client=mock_openai_client)
messages = [{"role": "user", "content": "I want to talk to agent 2"}]
response = client.run(agent=agent1, messages=messages)

View File

@ -1,4 +1,4 @@
from swarm.util import function_to_json
from cai.util import function_to_json
def test_basic_function():