# Agency Context Source: https://agency-swarm.ai/additional-features/agency-context Sharing data and state across tools and agents using agency context. `Agency Context` is run-scoped data stored on `MasterContext`. It lets tools and agents share structured data during a run without putting that data in messages. Agency context lives in the `MasterContext` for a run. Keep session state outside the `Agency` instance and pass it into each call with `context_override`. `Agency(user_context=...)` and `agency.user_context` are deprecated and will be removed in the next major release. They still work, but emit a `DeprecationWarning`. To migrate, keep your state in a dictionary you own, pass it with `context_override`, and carry the updated state forward from `response.context_wrapper.context.user_context` as shown in [Session Management](#session-management) below. ## Understanding Agency Context Agency context is useful when your agents interact with multiple tools that need to exchange information. Here's why: * **Without Agency Context**: Suppose `Tool A` collects data that `Tool B` needs. The agent must explicitly pass this data as a parameter to `Tool B`, consuming tokens and potentially hitting message limits. Without Agency Context * **With Agency Context**: `Tool A` can store the required data in the agency context, and `Tool B` can retrieve it without needing direct parameter passing. This approach reduces complexity, saves tokens, and enables additional workflows. With Agency Context ## Using Agency Context The agency context is accessible in both FunctionTools and BaseTools using `.get` and `.set`, which let you access and modify the MasterContext passed during execution. Below is an example of how it can be used across tools. In this example, calling the Query Database tool stores database context, which is later retrieved by the Answer Question tool. For BaseTools, access the agency context using `self.context`. ```python theme={null} from agency_swarm.tools import BaseTool from pydantic import Field class QueryDatabase(BaseTool): """ Retrieves data from the database and stores it in the agency context. """ question: str = Field(..., description="The query to execute.") async def run(self): # Fetch data based on the question context = query_database_api(self.question) # Store the context in the agency context assert self.context is not None self.context.set('database_context', context) self.context.set('last_query', self.question) return "Database context has been retrieved and stored successfully." class AnswerQuestion(BaseTool): """ Provides answers based on the context stored in the agency context. """ async def run(self): # Access the stored context assert self.context is not None context = self.context.get('database_context') if not context: return "Database context is missing. Please call the query_database tool first." # Generate an answer using the context answer = f"Answer derived from context: {context}" return answer ``` For FunctionTools, access the context using the following methods: * **Setting** a value: `ctx.context.set('key', value)` * **Getting** a value: `ctx.context.get('key', default_value)` ```python theme={null} from agency_swarm import MasterContext, RunContextWrapper, function_tool @function_tool async def query_database(ctx: RunContextWrapper[MasterContext], question: str) -> str: """ Retrieves data from the database and stores it in the agency context. """ # Fetch data based on the question context = query_database_api(question) # Store the context in the agency context ctx.context.set('database_context', context) ctx.context.set('last_query', question) return "Database context has been retrieved and stored successfully." @function_tool async def answer_question(ctx: RunContextWrapper[MasterContext]) -> str: """ Provides answers based on the context stored in the agency context. """ # Access the stored context context = ctx.context.get('database_context') if not context: return "Database context is missing. Please call the query_database tool first." # Generate an answer using the context answer = f"Answer derived from context: {context}" return answer ``` ## Advanced Agency Context Patterns ### Complex Data Structures Agency context can store any Python object, making it useful for complex workflows: ```python theme={null} @function_tool async def analyze_market_data(ctx: RunContextWrapper[MasterContext], symbols: str) -> str: """Analyzes multiple stocks and stores data.""" symbol_list = symbols.split(',') market_analysis = { 'timestamp': datetime.now().isoformat(), 'symbols': {}, 'summary': {}, 'analyst': ctx.context.current_agent_name } for symbol in symbol_list: # Simulate market data fetch market_analysis['symbols'][symbol] = { 'price': 150.0, 'volume': 1000000, 'trend': 'bullish' } # Store in agency context ctx.context.set('market_analysis', market_analysis) ctx.context.set('analysis_complete', True) return f"Market analysis complete for {len(symbol_list)} symbols" ``` ### Workflow Coordination Use agency context to coordinate multi-step workflows: ```python theme={null} @function_tool async def step_1_data_collection(ctx: RunContextWrapper[MasterContext], params: str) -> str: """First step in a multi-step workflow.""" # Perform step 1 result = collect_data(params) # Store progress in agency context ctx.context.set('workflow_step_1', result) ctx.context.set('workflow_status', 'step_1_complete') return "Step 1 complete. Ready for step 2." @function_tool async def step_2_data_processing(ctx: RunContextWrapper[MasterContext]) -> str: """Second step that depends on first step.""" # Check if step 1 is complete if ctx.context.get('workflow_status') != 'step_1_complete': return "Error: Step 1 must be completed first" # Get data from step 1 step_1_data = ctx.context.get('workflow_step_1') # Process the data result = process_data(step_1_data) # Update progress ctx.context.set('workflow_step_2', result) ctx.context.set('workflow_status', 'step_2_complete') return "Step 2 complete. Workflow finished." ``` ### Session Management Keep session state outside the agency and pass it into each run: ```python theme={null} agency = Agency(entry_agent, communication_flows=[(entry_agent, worker_agent)]) session_context = { 'session_id': 'user_123', 'user_preferences': { 'language': 'en', 'timezone': 'UTC', 'risk_tolerance': 'moderate' }, 'session_start': datetime.now().isoformat() } response = await agency.get_response( "Analyze my portfolio.", context_override=session_context, ) # Carry tool changes into the next turn through caller-owned state. session_context = response.context_wrapper.context.user_context next_response = await agency.get_response( "Use the same preferences for the next analysis.", context_override=session_context, ) ``` ## Best Practices ### Use Descriptive Keys Use clear, descriptive keys to avoid conflicts between different agents and workflows: ```python theme={null} # Good: Descriptive keys ctx.context.set('user_portfolio_analysis_2024', data) ctx.context.set('market_data_AAPL_realtime', market_data) # Avoid: Generic keys that might conflict ctx.context.set('data', data) ctx.context.set('result', result) ``` ### Provide Default Values Always provide sensible defaults when retrieving data: ```python theme={null} # Good: Provides default user_prefs = ctx.context.get('user_preferences', {}) risk_level = ctx.context.get('risk_tolerance', 'moderate') # Risky: No default, might return None risk_level = ctx.context.get('risk_tolerance') ``` ### Clean Up Unneeded Data For long-running sessions, clean up temporary data before carrying the context into the next run: ```python theme={null} @function_tool async def cleanup_temporary_data(ctx: RunContextWrapper[MasterContext]) -> str: """Cleans up temporary analysis data.""" temp_keys = ['temp_calculation_1', 'temp_calculation_2', 'scratch_data'] for key in temp_keys: if key in ctx.context.user_context: del ctx.context.user_context[key] return "Temporary data cleaned up successfully" ``` ## Migrating tools If you're migrating from Agency Swarm v0.x, and want to use new FunctionTool instead of BaseTool, here's how you can do that: **BaseTool Pattern:** ```python theme={null} class MyTool(BaseTool): async def run(self): assert self.context is not None self.context.set("key", "value") data = self.context.get("key", "default") return "Done" ``` **FunctionTool Pattern:** ```python theme={null} @function_tool async def my_tool(ctx: RunContextWrapper[MasterContext], param: str) -> str: """Updated tool using agency context.""" ctx.context.set("key", "value") data = ctx.context.get("key", "default") return "Done" ``` ## Example: Complete Workflow For a full example showing agency context in action, see the [Agency Context Workflow Example](https://github.com/VRSEN/agency-swarm/blob/main/examples/agency_context.py) which demonstrates: * Multi-step data collection and analysis * Cross-agent data sharing * Session management * Workflow coordination * Context monitoring and debugging Agency context eliminates complex parameter passing during a run while keeping session state separate from the agency definition. # Azure OpenAI Source: https://agency-swarm.ai/additional-features/azure-openai Integrate Azure OpenAI with Agency Swarm to ensure secure data processing and enhanced privacy. Many organizations prioritize data privacy and are cautious about sharing their data with any third-parties. By leveraging Azure OpenAI, you can ensure that your data is processed only within your own secure Azure environment, and not even shared with OpenAI itself. Running OpenAI models on Azure is the same as deploying your own open source model on any other cloud provider. ## Prerequisites Before you begin, ensure you have the following: 1. Create an Azure Account with an active subscription. [Create an account here](https://azure.microsoft.com/en-us/free/). 2. Get approved access to the OpenAI Service on Azure. 3. Create an Azure OpenAI resource in [one of the available regions](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#assistants-preview) and deploy a model to it. 4. Obtain the endpoint URL and API key for the OpenAI resource. ## Setting Up Azure OpenAI with Agency Swarm To use Azure OpenAI, you need to configure the client to connect to your Azure OpenAI resource as follows: ```python theme={null} import os from openai import AsyncAzureOpenAI # Create a custom AsyncOpenAI client for Azure azure_agent = AsyncAzureOpenAI( api_key=os.getenv("AZURE_OPENAI_KEY"), azure_endpoint=os.getenv("AZURE_ENDPOINT"), api_version=os.getenv("AZURE_API_VERSION"), ) ``` Set the `model` parameter inside each agent to use your custom client and model: ```python theme={null} from agency_swarm import Agent, OpenAIChatCompletionsModel # Define your agent and pass the custom client into the model azure_agent = Agent( name="AzureAgent", instructions="You are a helpful assistant", model=OpenAIChatCompletionsModel( model="gpt-6-luna", openai_client=azure_agent, ), ) ``` Model deployment name might be different from the standard OpenAI model names. It is set by you when you deploy a model to Azure. A client stored on a model outlives a single event loop: httpx2 binds pooled connections to the loop that created them, so a fixed client can crash on the next `get_response_sync`. Pass `http_client=loop_scoped_http_client()` (from `agency_swarm`) when building `azure_agent` so its requests run on the caller's loop. See [Third-party models](/additional-features/third-party-models). After configuring the client and updating the agents, you can run your agency as usual: ```python theme={null} import asyncio from agency_swarm import Agency agency=Agency(azure_agent) agency.tui() ``` The first terminal run downloads the matching terminal app automatically. For other model providers (Anthropic, Google, AWS Bedrock, etc.), see [Third-Party Models](/additional-features/third-party-models). # Common Use Cases Source: https://agency-swarm.ai/additional-features/custom-communication-flows/common-use-cases Explore common use cases for custom communication flows in Agency Swarm. In the following sections, we'll look at some common use cases for creating custom communication flows and how to implement them in Agency Swarm. #### 1. Adjusting Parameters and Descriptions Customize parameters by subclassing `SendMessage` and declaring extra fields directly on the class: ```python theme={null} from pydantic import Field from agency_swarm import SendMessage class SendMessageTask(SendMessage): """Use this tool to send tasks to other agents within your agency.""" tool_name = "send_message_task" # optional, defaults to "send_message" task: str = Field( description=( "Specify the task required for the recipient agent to complete. Focus on " "clarifying what the task entails rather than providing exact instructions." ) ) ``` #### 2. Adding Additional Fields You can add extra fields to capture more context, like key moments and decisions: ```python theme={null} from pydantic import Field from agency_swarm import SendMessage class SendMessageWithContext(SendMessage): """SendMessage with key moments and decisions tracking.""" tool_name = "send_message_with_context" key_moments: str = Field( description=( "Document critical moments and decision points from the current conversation " "that the recipient agent needs to understand. Include context about what " "has been decided or prioritized that will guide the recipient's tool selection " "and task execution. For example: 'User decided to prioritize performance over cost', " "'Analysis focus shifted to Q4 optimization', etc." ) ) decisions: str = Field( description=( "Summarize the specific decisions made that will directly impact which tools " "or approaches the recipient agent should use. Be explicit about choices that " "narrow down the scope of work. For example: 'Prioritized performance analysis " "over cost reduction', 'Selected React over Vue for frontend', etc. This helps " "the recipient agent choose the most appropriate tools and approach." ) ) ``` **Usage:** ```python theme={null} from agency_swarm import Agency, Agent agent = Agent( name="MyAgent", instructions="You are a helpful assistant.", ) other_agent = Agent(name="OtherAgent", instructions="Provide supporting context.") agency = Agency( agent, other_agent, communication_flows=[(agent > other_agent, SendMessageWithContext)], ) ``` If you have any ideas for new communication flows, please either adjust this page in docs, or add your new send message tool in the `agency_swarm/tools/send_message` folder and open a PR! # Overview Source: https://agency-swarm.ai/additional-features/custom-communication-flows/overview Learn how to customize communication flows for your agency. Multi-agent communication is the core functionality of any multi-agent system. Unlike all other frameworks, Agency Swarm not only allows you to define communication flows in any way you want (uniform communication flows), but also to configure the underlying logic for this feature. This means that you can create entirely new types of communication or adjust it to your own needs. Below you will find a guide on how to do all this, along with some common examples. ## Pre-Made SendMessage Classes Agency Swarm contains multiple commonly requested classes for communication flows. Currently, the following classes are available: | Class Name | Description | When to Use | Code Link | | - | - | - | - | | `SendMessage` (default) | This is the default class for sending messages to other agents. It uses synchronous communication with basic COT (Chain of Thought) prompting and allows agents to relay files and modify system instructions for each other. | Suitable for most use cases. Balances speed and functionality. | [link](https://github.com/VRSEN/agency-swarm/blob/main/src/agency_swarm/tools/send_message.py) | | `Handoff` | Enables unidirectional transfer of control to a specialized agent. When a handoff occurs, the receiving agent takes over the interaction and continues the conversation. (`SendMessageHandoff` is deprecated.) | Use for routing queries to specialized agents or sequential workflows where control should transfer completely. | [link](https://github.com/VRSEN/agency-swarm/blob/main/src/agency_swarm/tools/send_message.py) | #### Customizing Communication Flows To select your own custom send message tool, simply provide it as the last argument to the communication flow tuple. ```python theme={null} from agency_swarm import Agent, Handoff ceo = Agent( name="CeoAgent", instructions="You are a helpful assistant.", ) worker = Agent( name="WorkerAgent", instructions="You are a helpful assistant.", ) agency = Agency(ceo, communication_flows=[(ceo > worker, Handoff)]) ``` Here, the `Handoff` tool will be used specifically for `ceo -> worker` communication and nowhere else. If there were other agents in the agency connected to ceo, they would be using regular `SendMessage` for agent-to-agent conversations. ## Creating Your Own Unique Communication Flows To create your own communication flow, you will first need to extend the `FunctionTool` class from the agents SDK. The `SendMessage` class is built on top of `FunctionTool`, providing a flexible foundation for creating custom communication patterns tailored to your specific needs. ### Custom SendMessage Class To customize SendMessage parameters, extend the `SendMessage` class and declare extra fields directly as class-level annotations with `Field()`: ```python theme={null} from pydantic import Field from agency_swarm import SendMessage class CustomSendMessage(SendMessage): """ Use this tool to facilitate direct, synchronous communication between specialized agents within your agency. """ tool_name = "send_message_custom" # Optional: custom name for this tool key_moments: str = Field(description="Critical context and decision points relevant to the task") decisions: str = Field(description="Specific decisions that guide tool choice and approach") ``` The fields are automatically discovered and merged into the tool schema. ### Key Components In general, all `SendMessage` tools have the following components: 1. **FunctionTool Base**: Extends the `FunctionTool` class from the agents SDK, providing async execution and standardized tool interfaces. 2. **Dynamic Initialization**: Tools are created dynamically for specific sender->recipient pairs with custom parameter schemas. 3. **JSON Schema**: Parameters are defined using JSON schema for validation and type safety. 4. **Async Communication**: Uses `async/await` for non-blocking communication between agents. When creating your own `SendMessage` tools, extend `FunctionTool` and implement the `on_invoke_tool` method with your custom communication logic. If you are planning to create an agent that has access to multiple SendMessage tools (using communication flow pattern), each tool **must** have a unique name, which **must** start with `send_message`. Set it via the `tool_name` class attribute, e.g. `tool_name = "send_message_formatted"`. ### Custom Handoff Class By default, whenever a handoff occurs, prior to transferring the chat, a special system message will be added to the chat history to remind the recipient agent that a handoff has happened. This helps to reduce the amount of hallucinations and agent confusion whenever a chat transfer happens. You can customize the reminder message or disable it entirely by defining a custom Handoff class as follows (see [`add_reminder`](https://github.com/VRSEN/agency-swarm/blob/main/src/agency_swarm/tools/send_message.py) and [`handoff_reminder`](https://github.com/VRSEN/agency-swarm/blob/main/src/agency_swarm/agent/core.py) parameters). Set `handoff_reminder` on the agent that receives the handoff so the message appears in its context: ```python theme={null} from agency_swarm import Agency, Agent, Handoff class NoReminderHandoff(Handoff): add_reminder = False # Set to False to completely remove the extra message sender = Agent(name="NoReminderSender") recipient = Agent(name="NoReminderAgent") agency = Agency( sender, recipient, communication_flows=[(sender > recipient, NoReminderHandoff)], ) ``` ```python theme={null} from agency_swarm import Agency, Agent, Handoff sender = Agent(name="CustomHandoffSender") recipient = Agent( name="CustomHandoffAgent", # Delivered to this agent whenever it receives a handoff. handoff_reminder="You are now the active agent. Summarize received context and answer user query.", ) agency = Agency( sender, recipient, communication_flows=[(sender > recipient, Handoff)], ) ``` ### Common Use Cases For detailed **Common Use Cases**, please refer to the [Common Use Cases](./common-use-cases) subpage. ## Conclusion Agency Swarm has been designed to give you, the developer, full control over your systems. It is the only framework that does not hard-code any prompts, parameters, or even worse, agents for you. With this new feature, the last part of the system that you couldn't fully customize to your own needs is now gone! So, we want to encourage you to keep experimenting and designing your own unique communication flows. While the examples above should serve as a good starting point, they do not even merely scratch the surface of what's possible here! We are looking forward to seeing what you will create. Please share it in our [Discord server](https://discord.gg/7HcABDpFPG) so we can all learn from each other. # Deployment to Production Source: https://agency-swarm.ai/additional-features/deployment-to-production Step-by-step guide for deploying your agency in a production environment. **Recommended:** Use the [Starter Template](/welcome/getting-started/starter-template) for production. It ships with FastAPI endpoints, auth, and a clean project layout. ## Required Environment Variables Before deploying, ensure these are set in your production environment: | Variable | Required | Description | | - | - | - | | `OPENAI_API_KEY` | Yes | Your OpenAI API key | | `APP_TOKEN` | Recommended | Authentication token for FastAPI endpoints | Thread persistence uses callbacks you define to store threads in any database you choose. This guide assumes you have already created an agency. If you haven't, check out the [Getting Started](/welcome/installation) guide. Before deploying, ensure you have thoroughly tested all tools and agents. Run the test cases in each tool file and verify the agency works end-to-end using demo methods. ## Deployment Process By default, every time you create a new `Agency()`, it starts a fresh conversation thread. In production, you usually need to resume prior conversations or handle multiple users. Persist the full conversation history for each chat, including user-facing turns and agent-to-agent handoffs. Chat persistence is handled through callback functions passed to the Agency constructor: ```python theme={null} from agents import TResponseInputItem from agency_swarm import Agency def save_threads(messages: list[TResponseInputItem], chat_id: str) -> None: save_threads_to_db(chat_id, messages) def load_threads(chat_id: str) -> list[TResponseInputItem]: return load_threads_from_db(chat_id) agency = Agency( agent1, agent2, communication_flows=[(agent1, agent2)], load_threads_callback=lambda: load_threads(chat_id), save_threads_callback=lambda messages: save_threads(messages, chat_id), ) ``` If you switch model providers for an existing saved chat, old tool/event items may no longer replay correctly. Start a new chat, or keep only `{role, content}` messages. Use FastAPI in one of two ways: * Single agency: call `agency.run_fastapi(...)` from an `Agency` instance. * Multiple agencies and/or standalone tools: use top-level `run_fastapi(agencies=..., tools=[...])`. There can be multiple agencies in one server, and each agency key becomes its own endpoint prefix. ```python theme={null} from agency_swarm import Agency, Agent, function_tool, run_fastapi @function_tool def health_check() -> str: return "ok" def create_support_agency(load_threads_callback=None): support = Agent(name="Support", instructions="You are a support agent.") return Agency( support, name="support", load_threads_callback=load_threads_callback, ) def create_sales_agency(load_threads_callback=None): sales = Agent(name="Sales", instructions="You are a sales agent.") return Agency( sales, name="sales", load_threads_callback=load_threads_callback, ) run_fastapi( agencies={ "support": create_support_agency, "sales": create_sales_agency, }, tools=[health_check], app_token_env="APP_TOKEN", cors_origins=["https://your-app.example"], ) ``` `run_fastapi(agencies=...)` injects `load_threads_callback` per request (for `chat_history`) and does not inject `save_threads_callback`. If you need server-side persistence writes, wire that explicitly in your application flow. This creates separate agency endpoints plus tool endpoints, for example: * `/support/get_response` and `/support/get_response_stream` * `/sales/get_response` and `/sales/get_response_stream` * `/tool/health_check` FastAPI details: * [Setting Up FastAPI Endpoints](/additional-features/fastapi-integration#setting-up-fastapi-endpoints) * [Authentication](/additional-features/fastapi-integration#authentication) * [Implementation reference (multiple agencies and tools)](/additional-features/fastapi-integration#implementation-reference) * [API Usage Example](/additional-features/fastapi-integration#api-usage-example) If you need tools hosted separately from your agency service, expose tools as APIs and connect them with [OpenAPI schemas](/core-framework/tools/openapi-schemas), or use [MCP Integration](/core-framework/tools/mcp-integration). Use the [Starter Template](/welcome/getting-started/starter-template) as your production base. It already includes FastAPI wiring and deployment defaults. * Create a repo from the template * Set `OPENAI_API_KEY` and `APP_TOKEN` * Follow the template README to deploy If you are wiring your own server, see [FastAPI Integration](/additional-features/fastapi-integration) for endpoint and parameter details (`host`, `port`, `app_token_env`, `cors_origins`, `enable_agui`). # FastAPI Integration Source: https://agency-swarm.ai/additional-features/fastapi-integration Serving your agencies and tools as APIs with FastAPI. Agency Swarm supports serving your agencies and tools as production-ready HTTP APIs using [FastAPI](https://fastapi.tiangolo.com/). This enables you to interact with your agents and tools over HTTP, integrate with other services, or connect it to web frontends. ## Installation FastAPI integration is an **optional installation**. To install all required dependencies, run: ```bash theme={null} pip install "agency-swarm[fastapi]" ``` ## Setting Up FastAPI Endpoints You can expose your agencies and tools as API endpoints using the `run_fastapi()` function. ### Example: Create an API endpoint for a single agency ```python theme={null} from agency_swarm import Agency, Agent agent = Agent( name="Assistant", instructions="You are a helpful assistant." ) agency = Agency(agent, name="test_agency") agency.run_fastapi() ``` | Param | Type | Default | Description | | - | - | - | - | | `host` | string | `"127.0.0.1"` | Interface to bind the server. Pass `"0.0.0.0"` to bind all interfaces. | | `port` | integer | `8000` | Port to serve FastAPI on. | | `app_token_env` | string | `"APP_TOKEN"` | Env var name for the bearer token; if missing, auth is disabled. | | `return_app` | boolean | `false` | Return the FastAPI app instead of running the server. | | `cors_origins` | list | `["*"]` | Allowed CORS origins. When set to `["*"]`, `allow_credentials` is automatically set to `False` for security. | | `enable_agui` | boolean | `false` | Enable AG-UI streaming (hides the cancel endpoint). | | `enable_logging` | boolean | `false` | Track requests and expose `/get_logs` at the server root. | | `logs_dir` | string | `"activity-logs"` | Folder for request logs when logging is enabled. | | `allowed_local_file_dirs` | list | `None` | Allowlist for local `file_urls`; paths outside the list are rejected. | | `enable_realtime` | boolean | `false` | Mount `//realtime` websocket route(s) in addition to REST endpoints. | | `realtime_options` | object | `{}` | Realtime session overrides (for example `provider`, `model`, `voice`, `turn_detection`). | | `oauth_user_id_dependency` | FastAPI dependency | `None` | Trusted authentication dependency required for OAuth-enabled agencies. It must return a stable, non-secret user ID. | | `verify_oauth_callback_user` | boolean | `false` | Apply `oauth_user_id_dependency` to `/auth/callback` and reject a code whose pending flow belongs to another user. Requires browsers to carry authentication (cookie or session). | * Agencies are served at: * `/your_agency_name/get_response` (POST) * `/your_agency_name/get_response_stream` (POST, streaming responses) * `/your_agency_name/cancel_response_stream` (POST; not registered when `enable_agui=True`) * `/your_agency_name/get_metadata` (GET) * `/your_agency_name/realtime` (WebSocket; when `enable_realtime=True`) * `/get_logs` (GET; when `enable_logging=True`) * Tools registered via `tools=[...]` are available at `/tool/ToolClassName` (BaseTools) or `/tool/function_name` (function tools). * OpenAPI and interactive docs: `/openapi.json`, `/docs`, `/redoc`. **Non-streaming (`/get_response`):** ```json theme={null} { "response": "Hello! How can I help you today?", "new_messages": [ { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "Hello"}], "agent": "Assistant", "callerAgent": null, "timestamp": 1704067200000 }, { "type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "Hello! How can I help you today?"}], "agent": "Assistant", "callerAgent": null, "timestamp": 1704067201000 } ], "usage": {"input_tokens": 50, "output_tokens": 12, "total_cost": 0.0001}, "file_ids_map": {"document.pdf": "file-abc123"} } ``` **Streaming (`/get_response_stream`):** ``` event: meta data: {"run_id": "550e8400-e29b-41d4-a716-446655440000"} data: {"data": {"data": {"type": "response.output_text.delta", "delta": "Hello"}}} data: {"data": {"data": {"type": "response.output_text.delta", "delta": "!"}}} event: messages data: {"new_messages": [...], "run_id": "...", "cancelled": false, "usage": {...}, "file_ids_map": {...}} event: end data: [DONE] ``` **Cancel (`/cancel_response_stream`):** ```json theme={null} { "ok": true, "run_id": "550e8400-e29b-41d4-a716-446655440000", "cancelled": true, "cancel_mode": "immediate", "new_messages": [...] } ``` **Metadata (`/get_metadata`):** ```json theme={null} { "nodes": [ { "id": "Assistant", "type": "agent", "data": { "label": "Assistant", "description": "Main assistant agent", "conversationStarters": ["Support: I need help with billing"], "quickReplies": ["hi", "hello"], "isEntryPoint": true, "toolCount": 2, "tools": [ { "name": "example_tool", "type": "function", "description": "...", "inputSchema": {"type": "object", "properties": {"text": {"type": "string"}}} } ] } } ], "edges": [ {"id": "CEO->Developer", "source": "CEO", "target": "Developer", "type": "communication"} ], "metadata": { "agencyName": "my_agency", "totalAgents": 2, "totalTools": 4, "agents": ["CEO", "Developer"], "entryPoints": ["CEO"] }, "agency_swarm_version": "1.0.0" } ``` Conversation starters appear under `data.conversationStarters`, and quick-reply phrases appear under `data.quickReplies` when configured. See [Agent Overview](/core-framework/agents/overview). **Tool (`/tool/`):** ```json theme={null} { "response": "Output returned by the tool" } ``` Responses include a `usage` object with token counts and cost by default. For streaming, the final `event: messages` payload includes the same `usage` object. To understand what's inside `usage`, see [Observability](/additional-features/observability#usage-payload). Usage tracking is configured on the agent (not on FastAPI): ```python theme={null} from agency_swarm import Agent, ModelSettings agent = Agent( name="Assistant", instructions="You are a helpful assistant.", model_settings=ModelSettings(include_usage=False), ) ``` If you're using LiteLLM models and want usage in streaming responses, keep `include_usage=True`. Stream cancellation uses an in-memory registry per process. Use single-worker deployments (e.g., uvicorn `workers=1`) or sticky routing so cancel requests reach the same worker. ### Authentication Set the environment variable named by `app_token_env` (default `APP_TOKEN`) to require `Authorization: Bearer ` on every endpoint. When the variable is absent, authentication is disabled. ### Implementation reference ```python theme={null} from agency_swarm import Agency, Agent, function_tool, run_fastapi # Example tools using agents SDK @function_tool def example_tool(example_field: str) -> str: """Example tool with input field.""" return f"Result of ExampleTool operation with {example_field}" @function_tool def test_tool(example_field: str) -> str: """Test tool with input field.""" return f"Result of TestTool operation with {example_field}" # Create agents agent1 = Agent(name="Assistant1", instructions="You are assistant 1.") agent2 = Agent(name="Assistant2", instructions="You are assistant 2.") # Create agency factory functions for proper thread management def create_agency_1(load_threads_callback=None, save_threads_callback=None): return Agency( agent1, name="test_agency_1", load_threads_callback=load_threads_callback, save_threads_callback=save_threads_callback, ) def create_agency_2(load_threads_callback=None, save_threads_callback=None): return Agency( agent2, name="test_agency_2", load_threads_callback=load_threads_callback, save_threads_callback=save_threads_callback, ) run_fastapi( agencies={ "test_agency_1": create_agency_1, "test_agency_2": create_agency_2, }, tools=[example_tool, test_tool], enable_realtime=True, realtime_options={"provider": "openai", "model": "gpt-realtime-2.1-mini"}, ) ``` Endpoints follow the reference above; tool schemas mirror the definitions of `example_tool` and `test_tool`. *** ## API Usage Example You can interact with your agents and tools using HTTP requests: ```python theme={null} import requests agency_url = "http://127.0.0.1:8000/test_agency_1/get_response" payload = { "message": "Hello", "client_config": { "base_url": "https://my-openai-gateway.example.com/v1", "api_key": "sk-...", # override per request }, } headers = { "Authorization": "Bearer 123" # Replace with your actual token if needed } agency_response = requests.post(agency_url, json=payload, headers=headers) print("Status code:", agency_response.status_code) print("Response:", agency_response.json()) ``` | Field | Type | Required | Description | | - | - | - | - | | `message` | string or structured list | Yes | User message to start or continue the conversation. Use a structured Responses input list for inline `input_text`, `input_image`, or `input_file` content. | | `chat_history` | list | No | Flat list of prior messages with metadata (`agent`, `callerAgent`, `timestamp`) to preserve context. | | `recipient_agent` | string | No | Target agent when you want to direct the next turn. | | `file_ids` | list | No | IDs of already uploaded files to attach. | | `file_urls` | object | No | `{filename: url_or_absolute_path}` map. Local paths require `allowed_local_file_dirs` on `run_fastapi`. | | `additional_instructions` | string | No | Extra guidance for the current request. | | `user_context` | object | No | Structured data passed to [Agency Context](/additional-features/agency-context) without exposing it to the LLM. | | `client_config` | object | No | Override `base_url` / `api_key` for this request (and optional `litellm_keys` for `litellm/` models). | ### How user\_context is applied * Passed as run-scoped `context_override`. * Useful for structured data (ids, preferences, feature flags) you do not want in the prompt. * Accessible within tools for the duration of the run. See [Agency Context](/additional-features/agency-context). ### How client\_config is applied * Applies only to **OpenAI models** (no prefix or `openai/...`) and **LiteLLM models** (`litellm/...`). * **Custom Model subclasses** are not modified; the request still runs, but the override is skipped. * For LiteLLM, you can provide `litellm_keys` to pass different keys per provider. Requires LiteLLM installed. ### client\_config fields * `base_url` (string, optional): Override the API base URL for this request. * `api_key` (string, optional): Override the API key for this request. * `litellm_keys` (object, optional): Only for `litellm/...` models. * Map `provider_name` → `api_key`. * Example: `{"anthropic": "...", "gemini": "..."}` **OpenAI model override (gpt-4o):** ```json theme={null} { "message": "Hello", "client_config": { "base_url": "https://my-openai-gateway.example.com/v1", "api_key": "sk-..." } } ``` **LiteLLM mixed providers (requires LiteLLM installed — see [Third-Party Models](/additional-features/third-party-models) for installation):** ```json theme={null} { "message": "Hello", "client_config": { "base_url": "https://my-litellm-proxy.example.com", "litellm_keys": { "anthropic": "sk-ant-...", "gemini": "AIza..." } } } ``` ## Cancelling Active Streams The streaming endpoint supports cancellation via two methods: ### 1. Automatic Cancellation on Disconnect When a client disconnects (tab close, refresh, network failure), the stream is automatically cancelled to preserve token costs. ### 2. Cancel Endpoint Call the cancel endpoint with the `run_id` received from the first event of the streaming response. This will allow you to retrieve intermediate results that were generated before the run cancellation. Optionally include `cancel_mode` (defaults to `immediate`): * `immediate` — stop right away and return messages that were fully generated; the in-progress message is discarded. * `after_turn` — finish the current turn, then stop. ```python theme={null} import requests # Cancel an active stream cancel_url = "http://127.0.0.1:8000/test_agency/cancel_response_stream" payload = {"run_id": "your-run-id", "cancel_mode": "after_turn"} # cancel_mode is optional response = requests.post(cancel_url, json=payload) # Returns: {"ok": True, "run_id": "...", "cancelled": True, "cancel_mode": "after_turn", "new_messages": [...]} ``` *** ### OAuth-enabled agencies Provide a trusted FastAPI dependency that authenticates the request and returns a stable, non-secret user ID: ```python theme={null} from fastapi import Depends from agency_swarm import run_fastapi from my_app.auth import User, get_current_user def get_oauth_user_id(user: User = Depends(get_current_user)) -> str: return user.id run_fastapi( agencies={"my-agency": create_agency}, oauth_user_id_dependency=get_oauth_user_id, ) ``` If any agent uses `MCPServerOAuth`, `run_fastapi` automatically: * Adds `/auth/callback` and `/auth/status/{state}` routes * Defers OAuth MCP discovery until the model explicitly invokes `authenticate_mcp_server(server_name)` (so startup never forces auth) * Emits deterministic OAuth stream events on `/get_response_stream`: * `event: oauth_redirect` with `{state, server, auth_url}` * `event: oauth_status` with `{state, server, status}` where `status` is `pending`, `authorized`, `error:`, or `timeout` * SSE keepalive comments every 15 seconds while OAuth is pending: `: keepalive ` * Uses the authenticated ID from `oauth_user_id_dependency` to store tokens per user * Keeps OAuth callback state in an in-process registry. For multi-worker deployments, an external `oauth_registry` shares callback state only; token files must also use a shared persistent `oauth_token_path`. Otherwise, use sticky routing or a single worker. * Requires streaming: `POST /{agency}/get_response` returns `400` when OAuth-enabled MCP servers are present. Use `POST /{agency}/get_response_stream` (or `enable_agui=True`) and buffer the stream if you need a single final response. * Applies a 10-minute OAuth wait timeout per request. On timeout, the stream emits `oauth_status` = `timeout` and closes cleanly. `oauth_user_id_dependency` is required for OAuth-enabled agencies. Do not trust a user ID read directly from a request header or body. FastAPI wiring remains request-scoped and carries the OAuth prompts automatically. ### Binding the callback to a user The provider redirects the browser to `/auth/callback` as a plain navigation, so it carries no bearer token. By default the callback therefore matches the authorization code to its pending flow by the `state` parameter alone. `state` is 32 bytes of URL-safe randomness, and `/auth/status/{state}` is already restricted to the user who owns the flow. If your deployment authenticates browsers with a cookie or session, set `verify_oauth_callback_user=True` and make `oauth_user_id_dependency` resolve that session. The callback then rejects a code whose pending flow belongs to a different user, which closes the remaining session-fixation gap for anyone who learns a victim's pending `state`. Leave it off when the dependency only reads a bearer token: the redirect would fail authentication and every OAuth flow would break. For `HostedMCPTool`, FastAPI cannot infer whether a remote MCP server is public or OAuth-protected. To enable hosted OAuth, wrap only the protected tool with `enable_hosted_mcp_tool_oauth(...)` and leave `tool_config.authorization` empty. The tool is withheld until the model invokes `authenticate_mcp_server(server_name)`, so unrelated messages do not start OAuth. `run_fastapi(...)` creates an in-memory callback-state registry by default. For multiple workers, an external `oauth_registry` shares callback state only; configure each Agency with an `oauth_token_path` on shared persistent storage as well. Otherwise, use sticky routing or a single worker. Public hosted MCP servers should stay unwrapped. For OAuth-protected FastMCP servers, schema discovery (`list_tools`) is auth-protected. Discovery is deferred until the model invokes `authenticate_mcp_server(server_name)`, so startup does not force OAuth. Set `redirect_uri` on `MCPServerOAuth` to the publicly reachable URL that forwards to the FastAPI `/auth/callback` route (for example, your ingress hostname plus `/auth/callback`). You can also set `OAUTH_CALLBACK_URL` or `_REDIRECT_URI` as a fallback. If you do not override it, `MCPServerOAuth` defaults to `http://localhost:8000/auth/callback` for local development. In production, you must expose and route the callback path back to the issuing pod (sticky routing or shared state), or the OAuth flow will time out. *** ## Serving Standalone Tools Expose tools as simple HTTP endpoints for external systems, webhooks, or other agents to call directly without agency orchestration. ```python theme={null} from agency_swarm import BaseTool, run_fastapi class Address(BaseTool): street: str zip_code: int def run(self) -> str: return f"{self.street} {self.zip_code}" run_fastapi(tools=[Address], port=8080) ``` This creates: * `POST /tool/Address` — execute the tool * `GET /openapi.json` — full OpenAPI schema * `GET /docs` — interactive Swagger UI Use `ToolFactory.get_openapi_schema()` to generate the OpenAPI spec programmatically: ```python theme={null} from agency_swarm.tools import ToolFactory schema = ToolFactory.get_openapi_schema( [Address], url="https://your-server.com", title="My Tools API" ) print(schema) # Returns a JSON string ``` *** ## File Attachments Attach files to agency requests using `file_ids` or `file_urls` in the payload: ```json theme={null} { "message": "Summarize this document", "file_urls": {"report.pdf": "https://example.com/report.pdf"} } ``` For inline Responses attachments that should not be uploaded through the Files API, pass a structured `message`: ```json theme={null} { "message": [ { "role": "user", "content": [ {"type": "input_image", "image_url": "data:image/png;base64,...", "detail": "auto"}, {"type": "input_text", "text": "Describe this image"} ] } ] } ``` With manual `chat_history`, clients can keep structured attachment parts in history so follow-up turns work without reattaching. This may resend inline attachment content or references; it does not reuse server-managed state, `previous_response_id`, Conversations, or `file_id` values. The response includes `file_ids_map` with the uploaded file IDs: ```json theme={null} { "response": "...", "file_ids_map": {"report.pdf": "file-abc123"} } ``` When `file_urls` is used, Agency Swarm also prepends a `system` message for that turn that records the original source string for each attached file. That system message is included in `new_messages`, so if your client persists `new_messages` as chat history, later turns will keep the original attachment source URL or local path in model context. **Supported filetypes:** `.pdf`, `.jpeg`, `.jpg`, `.gif`, `.png`, `.c`, `.cs`, `.cpp`, `.csv`, `.html`, `.java`, `.json`, `.php`, `.py`, `.rb`, `.css`, `.js`, `.sh`, `.ts`, `.pkl`, `.tar`, `.xlsx`, `.xml`, `.zip`, `.doc`, `.docx`, `.md`, `.pptx`, `.tex`, `.txt` To support passing local filepaths in the `file_urls` field, set `allowed_local_file_dirs` on `run_fastapi`: ```python theme={null} run_fastapi(agencies=..., allowed_local_file_dirs=["/data/uploads"]) ``` Then pass absolute file paths in `file_urls`: ```json theme={null} {"file_urls": {"doc.pdf": "/data/uploads/doc.pdf"}} ``` Invalid paths return an `error` field in the response body. `allowed_local_file_dirs` uses strict request-time validation for invalid entries: if an entry exists but is not a directory, local `file_urls` requests fail with an error. Missing directories are skipped and can be created later. The `/get_metadata` field `allowed_local_file_dirs` lists only currently usable directory entries. # Few-Shot Examples Source: https://agency-swarm.ai/additional-features/few-shot-examples Guide agent responses using few-shot prompting. **Few-shot prompting** is a powerful technique where you provide a small number of sample interactions (typically 2 to 5) to guide your agent's behavior. This method helps the agent understand the desired output format and task requirements by learning from the given examples, thereby improving performance without writing extensive instructions. ## Crafting Effective Examples * **Provide Task Demonstrations**: Use examples that clearly illustrate the tasks that your agents will perform. * **Use Realistic Scenarios**: Include interactions that mirror actual conversations that your agent will handle. * **Use Preferred Tone and Style**: Ensure the agent's replies in your examples match your desired brand voice. ## Defining Few-Shot Examples In **Agency Swarm**, few-shot examples are earlier messages that show the style you want. Put them in `instructions` as plain text or pass them as message history to `get_response` / `get_response_stream`. Optional fields like `attachments` and `metadata` can be included in message history but are not required for basic examples. ## Using Few-Shot Examples Pick one of these ways: ```python theme={null} from agency_swarm import Agency, Agent support_agent = Agent( name="CustomerSupportAgent", instructions="You assist customers with troubleshooting.", ) agency = Agency(support_agent) examples = [ {"role": "user", "content": "My device won't turn on."}, {"role": "assistant", "content": "Please hold the power button for 10 seconds to restart the device."}, ] new_message = {"role": "user", "content": "It still won't start."} response = await agency.get_response(examples + [new_message]) ``` ```python theme={null} from agency_swarm import Agent instructions = """ You assist customers with troubleshooting. Example: User: My device won't turn on. Assistant: Please hold the power button for 10 seconds to restart the device. """ agent = Agent( name="CustomerSupportAgent", instructions=instructions, ) ``` Message history is more scalable. Instructions are best for short examples. See more advanced features in [Agent Class](/core-framework/agents/advanced-configuration) # Input Guardrails Source: https://agency-swarm.ai/additional-features/guardrails/input-guardrails Validate incoming messages before they reach the agent. Input guardrails validate incoming messages **before** they reach the agent. They screen both user input and inter-agent communication. ## Simplified Input Processing Agency Swarm automatically extracts text content from messages, so your guardrails receive clean text instead of full message objects. ## Function Signature Each input guardrail receives three parameters: ```python theme={null} from agency_swarm import Agent, GuardrailFunctionOutput, RunContextWrapper, input_guardrail @input_guardrail async def my_input_guardrail( context: RunContextWrapper, agent: Agent, user_input: str | list[str], ) -> GuardrailFunctionOutput: """Validate user input.""" return GuardrailFunctionOutput(output_info="", tripwire_triggered=False) ``` **Parameters:** * `context`: Run context wrapper with access to shared state. * `agent`: The Agent instance receiving the input. * `user_input`: Extracted text content. * Single message: a string containing the message content. * Multiple consecutive messages: a list of strings, one per message. **Return:** * `GuardrailFunctionOutput` with: * `tripwire_triggered` (bool): `True` if validation failed. * `output_info` (str): Guidance message returned to the caller. File and image inputs inside messages are not passed to input guardrails. ## Input Types When a user sends multiple messages: ```json theme={null} [ {"role": "user", "content": "Hi"}, {"role": "user", "content": "How are you?"} ] ``` Your guardrail receives: ```python theme={null} ["Hi", "How are you?"] ``` This allows you to process each new input message individually or validate them as a group. ## Basic Input Guardrail ```python theme={null} from agency_swarm import Agent, GuardrailFunctionOutput, RunContextWrapper, input_guardrail @input_guardrail async def require_task_prefix( context: RunContextWrapper, agent: Agent, user_input: str | list[str] ) -> GuardrailFunctionOutput: text = user_input if isinstance(user_input, str) else " ".join(user_input) blocked = not text.startswith("Request:") return GuardrailFunctionOutput( output_info="Prefix your request with 'Request:' describing what you need." if blocked else "", tripwire_triggered=blocked, ) agent = Agent( name="CustomerSupportAgent", instructions="You are a helpful customer support agent.", input_guardrails=[require_task_prefix], ) ``` ## Practical Example: Filtering Off-Topic Questions Use input guardrails to keep agents focused on their domain. This example delegates relevance decisions to an evaluator agent: ```python theme={null} from agency_swarm import ( Agent, GuardrailFunctionOutput, ModelSettings, Reasoning, RunContextWrapper, input_guardrail, ) from pydantic import BaseModel class RelevanceDecision(BaseModel): is_relevant: bool reason: str guardrail_agent = Agent( name="GuardrailAgent", instructions=( "You screen incoming messages for a customer-support assistant. " "Treat questions about account access, billing, and troubleshooting as relevant. " "Flag any unrelated requests as irrelevant." ), model="gpt-6-luna", model_settings=ModelSettings(reasoning=Reasoning(effort="low")), output_type=RelevanceDecision, ) @input_guardrail async def require_support_topic( context: RunContextWrapper, agent: Agent, user_input: str | list[str] ) -> GuardrailFunctionOutput: candidate = user_input if isinstance(user_input, str) else "\n".join(user_input) guardrail_result = await guardrail_agent.get_response(candidate, context=context.context) decision = RelevanceDecision.model_validate(guardrail_result.final_output) if not decision.is_relevant: return GuardrailFunctionOutput( output_info="Only support questions are allowed. Ask about billing, account access, or troubleshooting.", tripwire_triggered=True, ) return GuardrailFunctionOutput(output_info="", tripwire_triggered=False) support_agent = Agent( name="CustomerSupportAgent", instructions="You help customers resolve account, billing, and troubleshooting issues.", model="gpt-6-luna", input_guardrails=[require_support_topic], raise_input_guardrail_error=False, # Non-strict mode: guidance returned as assistant message ) ``` See the full example at [`examples/guardrails_input.py`](https://github.com/VRSEN/agency-swarm/blob/main/examples/guardrails_input.py). ## Non-strict vs Strict Mode Input guardrails support two modes that control how guidance is delivered. Use `raise_input_guardrail_error` to control this behavior. ### Non-strict Mode (Default) **Setting:** `raise_input_guardrail_error=False` In non-strict mode, guardrail guidance flows naturally as assistant output: * Guidance is returned as `final_output` (non-streaming) or `message_output_created` event (streaming). * No exception is raised. * Guidance persists as an assistant message with `message_origin="input_guardrail_message"`. ### Strict Mode **Setting:** `raise_input_guardrail_error=True` In strict mode, guardrail failures abort the turn immediately: * `InputGuardrailTripwireTriggered` is raised. * Guidance persists as a system message with `message_origin="input_guardrail_error"`. * The turn is aborted before the agent processes input. * The caller must handle the exception. ```python theme={null} from agency_swarm import Agent, InputGuardrailTripwireTriggered agent = Agent( name="CustomerSupportAgent", instructions="You are a helpful customer support agent.", input_guardrails=[require_task_prefix], raise_input_guardrail_error=True, ) try: response = await agency.get_response("Hello!") except InputGuardrailTripwireTriggered as exc: print(f"Validation failed: {exc.guardrail_result.output_info}") ``` ### Comparison Table | Mode | `raise_input_guardrail_error` | Caller sees | Persisted entry | Role | Use case | | - | - | - | - | - | - | | **Non-strict** | `False` (default) | Guardrail text as `final_output` or streaming event | Assistant message (`input_guardrail_message`) | `assistant` | Conversational flows, helpful guidance | | **Strict** | `True` | `InputGuardrailTripwireTriggered` exception | System message (`input_guardrail_error`) | `system` | Hard requirements, compliance, security | **Use non-strict mode when:** * You want a conversational user experience. * Agents are communicating with each other internally. * Guardrail feedback is helpful guidance, not a hard block. * You do not want to write exception handling code. **Use strict mode when:** * You are enforcing non-negotiable requirements. * Security or compliance rules must block processing. * You want explicit control over error handling. * The caller should know immediately that validation failed. ```text theme={null} RunItemStreamEvent( name='message_output_created', item=MessageOutputItem( raw_item=ResponseOutputMessage( id='msg_input_guardrail_guidance', content=[ResponseOutputText(text="Prefix your request...")], role='assistant', status='completed' ) ) ) ``` ## Guardrails in Message History Each guardrail trigger is recorded in chat history with a guidance entry. Every entry carries `message_origin` to identify which guardrail fired. For most use cases, `role`, `content`, and `message_origin` are enough. Additional metadata is mainly for tracing multi-agent runs. ### Message Origin Values * `input_guardrail_message`: Input guardrail in non-strict mode. * `input_guardrail_error`: Input guardrail in strict mode. * `output_guardrail_error`: Output guardrail failure (always a system message). ### Persistence Behavior | Mode | `raise_input_guardrail_error` | Streaming Event | Persisted Entry | | - | - | - | - | | **Non-strict** | `False` (default) | `message_output_created` with guidance text | Assistant message, `message_origin="input_guardrail_message"` | | **Strict** | `True` | `{"type": "error", "content": guidance}` | System message, `message_origin="input_guardrail_error"` | `validation_attempts` does not apply to input guardrails. Input guardrails trigger immediately on validation failure. ### Message History After Guardrails Trip When an input guardrail trips, agent-to-agent request messages remain in history alongside guardrail guidance. This preserves context so calling agents can adjust their approach. Output guardrail messages also persist in history to guide retry attempts. ```json theme={null} [ { "role": "assistant", "content": "Please, prefix your request with 'Support:' describing what you need.", "message_origin": "input_guardrail_message", "agent": "CustomerSupportAgent" }, { "role": "assistant", "content": "When chatting with this agent, provide your name first.", "message_origin": "input_guardrail_message", "agent": "DatabaseAgent", "callerAgent": "CustomerSupportAgent" }, { "role": "system", "content": "Do not include email addresses in your response.", "message_origin": "output_guardrail_error", "agent": "DatabaseAgent", "callerAgent": "CustomerSupportAgent" } ] ``` ## Internal Agent Communication For many agent-to-agent flows, non-strict mode (`raise_input_guardrail_error=False`) is easier to work with because guidance is returned inline instead of raising exceptions mid-chain. Due to the nature of handoffs, using `Handoff` for agent-to-agent communication can bypass input guardrails between agents. # Output Guardrails Source: https://agency-swarm.ai/additional-features/guardrails/output-guardrails Validate agent responses before they reach users. Output guardrails validate agent responses **before** they reach users or other agents. When a guardrail trips, the agent receives feedback and retries. ## Function Signature Each output guardrail receives three parameters: ```python theme={null} from agency_swarm import Agent, GuardrailFunctionOutput, RunContextWrapper, output_guardrail from pydantic import BaseModel @output_guardrail async def my_output_guardrail( context: RunContextWrapper, agent: Agent, response_text: str | BaseModel, ) -> GuardrailFunctionOutput: """Validate agent output.""" return GuardrailFunctionOutput(output_info="", tripwire_triggered=False) ``` **Parameters:** * `context`: Run context wrapper with access to shared state. * `agent`: The Agent instance generating the response. * `response_text`: The agent response as a string, or a structured model when `output_type` is set. **Return:** * `GuardrailFunctionOutput` with: * `tripwire_triggered` (bool): `True` if validation failed. * `output_info` (str): Feedback message sent to the agent when `tripwire_triggered=True`. ## Basic Output Guardrail ```python theme={null} from agency_swarm import Agent, GuardrailFunctionOutput, RunContextWrapper, output_guardrail @output_guardrail async def response_content_guardrail( context: RunContextWrapper, agent: Agent, response_text: str ) -> GuardrailFunctionOutput: tripwire_triggered = "bad word" in response_text.lower() output_info = "Please avoid using inappropriate language." if tripwire_triggered else "" return GuardrailFunctionOutput(output_info=output_info, tripwire_triggered=tripwire_triggered) agent = Agent( name="CustomerSupportAgent", instructions="You are a helpful customer support agent.", output_guardrails=[response_content_guardrail], ) ``` ## Practical Example: Preventing Sensitive Information Leaks ```python theme={null} from agency_swarm import Agent, GuardrailFunctionOutput, RunContextWrapper, output_guardrail @output_guardrail(name="ForbidSensitiveEmail") async def forbid_sensitive_email( context: RunContextWrapper, agent: Agent, response_text: str ) -> GuardrailFunctionOutput: if "@" in response_text: return GuardrailFunctionOutput( output_info="Do not share email addresses. Offer to connect via the support portal instead.", tripwire_triggered=True, ) return GuardrailFunctionOutput(output_info="", tripwire_triggered=False) support_agent = Agent( name="SupportPilot", instructions="You handle customer support. Official email: support@example.com.", model="gpt-6-luna", output_guardrails=[forbid_sensitive_email], validation_attempts=1, ) ``` See the full example at [`examples/guardrails_output.py`](https://github.com/VRSEN/agency-swarm/blob/main/examples/guardrails_output.py). ## Example: Simple Format Enforcement ```python theme={null} import json from agency_swarm import GuardrailFunctionOutput, RunContextWrapper, output_guardrail @output_guardrail(name="RequireJSONFormat") async def require_json_format( context: RunContextWrapper, agent: Agent, response_text: str ) -> GuardrailFunctionOutput: try: json.loads(response_text) return GuardrailFunctionOutput(output_info="", tripwire_triggered=False) except json.JSONDecodeError: return GuardrailFunctionOutput( output_info="Response must be valid JSON. Wrap your response in curly braces.", tripwire_triggered=True, ) ``` ## Output Guardrail Retry Flow When an output guardrail trips, the agent gets multiple chances to fix its response. The `validation_attempts` parameter controls this behavior. ### How Retry Works The agent produces its initial response. Each output guardrail validates the response. The agent receives a **system message** containing the guardrail `output_info`. The agent generates a new response, informed by that message. This cycle continues up to `validation_attempts` times. `OutputGuardrailTripwireTriggered` is raised. ## Configure `validation_attempts` ```python theme={null} agent = Agent( name="CustomerSupportAgent", instructions="You are a helpful customer support agent.", output_guardrails=[response_content_guardrail], validation_attempts=2, ) ``` | Setting | Behavior | | - | - | | `validation_attempts=0` | Fail-fast (no retry, immediate exception) | | `validation_attempts=1` | Default (one retry after initial failure) | | `validation_attempts=2+` | Multiple retries for more complex validations | Each retry sends the guardrail `output_info` message to the agent as a system message, giving the agent context to adjust its response. ## Handling Validation Failures ```python theme={null} from agency_swarm import OutputGuardrailTripwireTriggered try: response = await agency.get_response("Hello!") except OutputGuardrailTripwireTriggered as exc: print(f"Validation failed: {exc.guardrail_result.output_info}") ``` ## Message History Output guardrail failures are stored as system messages with `message_origin="output_guardrail_error"`. For most use cases, `role`, `content`, and `message_origin` are enough. Extra metadata is mainly for debugging and run tracing. | Origin | Meaning | | - | - | | `output_guardrail_error` | Output guardrail failure (system message) | ```json theme={null} { "role": "system", "content": "You are not allowed to include your email address in your response. Ask agent to redirect user to the contact page: https://www.example.com/contact", "message_origin": "output_guardrail_error", "agent": "DatabaseAgent", "callerAgent": "CustomerSupportAgent", "agent_run_id": "agent_run_id", "parent_run_id": "call_id", "timestamp": 1758103770629217, "type": "message" } ``` ## Agent-to-Agent Validation Use guardrails to control how agents communicate with each other. When adding communication flows between agents, the recipient agent's guardrails define the message format. ```python theme={null} from agency_swarm import Agency, Agent, GuardrailFunctionOutput, RunContextWrapper, input_guardrail, output_guardrail @input_guardrail(name="RequireTaskPrefix") async def require_task_prefix( context: RunContextWrapper, agent: Agent, agent_input: str | list[str] ) -> GuardrailFunctionOutput: text = agent_input if isinstance(agent_input, str) else " ".join(agent_input) blocked = not text.startswith("Task:") return GuardrailFunctionOutput( output_info="ERROR: Requests to this agent must begin with 'Task:'" if blocked else "", tripwire_triggered=blocked, ) @output_guardrail(name="RequireResponsePrefix") async def require_response_prefix( context: RunContextWrapper, agent: Agent, response_text: str ) -> GuardrailFunctionOutput: blocked = not response_text.startswith("Response:") return GuardrailFunctionOutput( output_info="ERROR: Responses must start with 'Response:'" if blocked else "", tripwire_triggered=blocked, ) ceo = Agent(name="CEO", instructions="You are the CEO agent.") worker = Agent( name="Worker", instructions="You are the worker agent.", input_guardrails=[require_task_prefix], output_guardrails=[require_response_prefix], raise_input_guardrail_error=True, ) agency = Agency(ceo, communication_flows=[(ceo, worker)]) ``` In this example: * If the CEO sends a message that does not start with `Task:`, the worker input guardrail triggers. * The CEO receives an error and adjusts its message. * The worker output guardrail enforces `Response:` in returned messages. Agent-to-agent messages are always single strings, so input guardrails for inter-agent communication receive a string (not a list). # Guardrails Overview Source: https://agency-swarm.ai/additional-features/guardrails/overview Screen agent inputs and review outputs with guardrails. Guardrails are checkpoint functions that keep agent behavior safe and predictable. Use them to validate incoming messages before execution and validate responses before delivery. ## Choose the Right Guardrail | Type | Runs When | On Failure | Page | | - | - | - | - | | **Input Guardrails** | Before the agent processes input | Return guidance (non-strict) or raise `InputGuardrailTripwireTriggered` (strict) | [Input Guardrails](/additional-features/guardrails/input-guardrails) | | **Output Guardrails** | After the agent drafts output, before delivery | Retry up to `validation_attempts`, then raise `OutputGuardrailTripwireTriggered` | [Output Guardrails](/additional-features/guardrails/output-guardrails) | ## Runnable GitHub Examples * Input guardrails example: [`examples/guardrails_input.py`](https://github.com/VRSEN/agency-swarm/blob/main/examples/guardrails_input.py) * Output guardrails example: [`examples/guardrails_output.py`](https://github.com/VRSEN/agency-swarm/blob/main/examples/guardrails_output.py) ## Best Practices * Keep each guardrail focused on one responsibility. * Write clear `output_info` messages so the model knows how to recover. * Use non-strict mode for guidance and strict mode for hard requirements. * For tool argument validation (field/model validators), use [Input Validation](/core-framework/tools/custom-tools/validation). # MCP Tools Server Source: https://agency-swarm.ai/additional-features/mcp-tools-server Serving your tools as MCP (Model Context Protocol) endpoints. Agency Swarm supports serving your tools as production-ready MCP (Model Context Protocol) endpoints. This enables AI models to interact with your tools remotely over HTTP, making them accessible to any MCP-compatible client or AI system. ## Setting Up MCP Server To expose tools as a standalone MCP endpoint, use the `run_mcp()` function from the integrations module. This will create an MCP server that will serve provided tools over the streamable HTTP protocol. ### Example: Serving Individual Tools ```python theme={null} from agency_swarm import function_tool, run_mcp from pydantic import BaseModel, Field class InputArgs(BaseModel): input_field: str = Field(..., description="Test input for the tool") @function_tool async def echo_function(args: InputArgs) -> str: """Returns a unique id""" return f"Tool called with input: {args.input_field}" # Start MCP server with individual tools. # This will setup a streamable-http server by default on port 8000 run_mcp(tools=[echo_function]) ``` ### Configuration Options The `run_mcp()` function accepts several configuration parameters: ```python theme={null} run_mcp( tools=[ExampleTool, TestTool], # List of Function tools or BaseTools host="127.0.0.1", # Host to bind server to ("0.0.0.0" binds all interfaces) port=8000, # Port to bind server to app_token_env="APP_TOKEN", # Environment variable for auth token server_name="mcp-tools-server", # MCP server identifier return_app=False, # Return app instead of running server transport="streamable-http" # Preferred mcp protocol to use ) ``` ### Authentication Authentication is controlled via environment variables: ```python theme={null} import os os.environ["APP_TOKEN"] = "your-secret-token" # Or set in .env file ``` If no `APP_TOKEN` is set, **authentication will be disabled** and the server will accept all requests. *** ## MCP Client Usage This example shows how to use a local MCP server with stdio transport: ```python theme={null} import asyncio from agents.mcp.server import MCPServerStdio, MCPServerStdioParams from agency_swarm import Agency, Agent # Set up local MCP server using stdio transport stdio_server = MCPServerStdio( MCPServerStdioParams( command="python", # or "npx" if available # Path to your MCP server script or npx arguments args=["./path/to/your/mcp_server.py"] ), cache_tools_list=True ) # Create agent with local MCP server mcp_agent = Agent( name="LocalMCPAgent", mcp_servers=[stdio_server], ) agency = Agency(mcp_agent) async def run_local_example(): await stdio_server.connect() response = await agency.get_response("List all mcp tools") print(response.final_output) await stdio_server.cleanup() if __name__ == "__main__": asyncio.run(run_local_example()) ``` This example shows how to connect to a hosted MCP server over HTTP: ```python theme={null} import os import asyncio from agency_swarm import Agency, Agent, HostedMCPTool # Create agent with hosted MCP server mcp_agent = Agent( name="HostedMCPAgent", tools=[ HostedMCPTool( tool_config={ "type": "mcp", "server_label": "mcp-tools-server", # Update with your hosted MCP server URL "server_url": "https://your-server.com/mcp/", "require_approval": "never", "headers": { "Authorization": ( f"Bearer {os.getenv('APP_TOKEN', 'your-token')}" ) } } ), ], ) agency = Agency(mcp_agent) async def run_hosted_example(): # HostedMCPTools do not require manual connection response = await agency.get_response("List all mcp tools") print(response.final_output) if __name__ == "__main__": asyncio.run(run_hosted_example()) ``` For hosted MCP servers, ensure your server is accessible from the internet. You can use tools like ngrok for local development. ## See Also * [Agents SDK MCP guide](https://openai.github.io/openai-agents-python/mcp/) * [Agents SDK MCP server reference](https://openai.github.io/openai-agents-python/ref/mcp/server/) # Observability Source: https://agency-swarm.ai/additional-features/observability Track and analyze your agent performance and behavior by connecting with third party observability tools. Agency Swarm supports multiple observability approaches to help you track and analyze your agent's behavior and performance. ## Usage Payload When usage tracking is enabled, responses include a `usage` object with token counts and cost. ```json theme={null} { "response": "Test response", "new_messages": [], "usage": { "request_count": 1, "cached_tokens": 0, "input_tokens": 10, "output_tokens": 20, "total_tokens": 30, "total_cost": 0.0 } } ``` **Fields:** * `request_count`: Number of model requests * `cached_tokens`: Tokens served from cache (if available) * `input_tokens`: Tokens sent to the model * `output_tokens`: Tokens generated by the model * `total_tokens`: Total tokens for the request * `total_cost`: Estimated cost (USD) * `reasoning_tokens` (optional): Reasoning tokens (if available) **Where you'll see it:** * [FastAPI Integration](/additional-features/fastapi-integration): `POST /get_response` returns JSON with `usage`, and the final `event: messages` in `POST /get_response_stream` includes `usage`. * [Running an Agency](/core-framework/agencies/running-agency#track-usage-and-cost): use `/cost` in the TUI to see session usage and cost. ## Supported Observability Platforms Agency Swarm supports three main observability approaches: Built-in tracing using OpenAI's native tools Advanced tracing and debugging platform Specialized agent monitoring and analytics ## Getting Started Let's walk through setting up each tracing solution. You can use them individually or combine them for monitoring. OpenAI tracing is built into Agency Swarm and requires no additional packages. ```python theme={null} from agency_swarm import trace async def openai_tracing(input_message: str) -> str: agency_instance = create_agency() with trace("OpenAI tracing"): response = await agency_instance.get_response(message=input_message) return response.final_output ``` After running your code, view your traces at [platform.openai.com/traces](https://platform.openai.com/traces) ```bash theme={null} pip install langfuse ``` ```bash theme={null} export LANGFUSE_SECRET_KEY= export LANGFUSE_PUBLIC_KEY= export LANGFUSE_HOST= ``` ```python theme={null} from langfuse import observe @observe() async def langfuse_tracing(input_message: str) -> str: agency_instance = create_agency() @observe() async def get_response_wrapper(message: str): return await agency_instance.get_response(message=message) response = await get_response_wrapper(input_message) return response.final_output ``` Access your traces at [cloud.langfuse.com](https://cloud.langfuse.com) and select your project. ```bash theme={null} pip install agentops ``` ```bash theme={null} export AGENTOPS_API_KEY= ``` ```python theme={null} import agentops async def agentops_tracing(input_message: str) -> str: agentops.init( auto_start_session=True, trace_name="Agentops tracing", tags=["openai", "agentops-example"] ) tracer = agentops.start_trace( trace_name="Agentops tracing", tags=["openai", "agentops-example"] ) agency_instance = create_agency() response = await agency_instance.get_response(message=input_message) agentops.end_trace(tracer, end_state="Success") return response.final_output ``` When you run your code, AgentOps will print a session replay URL in the console that looks like: `https://app.agentops.ai/sessions?trace_id=` ## Implementation Example For a complete working example that demonstrates all three tracing methods with a multi-agent agency, see [observability.py](https://github.com/VRSEN/agency-swarm/blob/main/examples/observability.py) in the examples directory. The example shows: * How to set up a basic agency with CEO, Developer, and Data Analyst roles * Implementation of all three tracing methods (OpenAI, Langfuse, AgentOps) * A sample tool for data analysis * Error handling and proper tracing setup You can run the example with: ```bash theme={null} python examples/observability_demo.py ``` For more information about each platform's capabilities and configuration options, refer to their respective documentation: * [OpenAI Documentation](https://platform.openai.com/docs) * [Langfuse Documentation](https://langfuse.com/docs) * [AgentOps Documentation](https://docs.agentops.ai) # Streaming Source: https://agency-swarm.ai/additional-features/streaming Implementing streaming in Agency Swarm. Streaming enables agents to return outputs immediately, significantly improving user experience. Instead of waiting for the entire response to be generated, the user can see the response being generated in real-time. ## Streaming Responses In Agency Swarm, streaming is handled through the `get_response_stream` method. The framework returns [StreamEvent](https://openai.github.io/openai-agents-python/ref/stream_events/#agents.stream_events.StreamEvent) objects as they are returned by OpenAI, providing direct access to the underlying streaming events. ```python theme={null} async def stream_response(message: str): """Stream a response and handle events properly.""" full_text = "" async for event in agency.get_response_stream(message): # Handle streaming events with data if hasattr(event, "data"): data = event.data # Only capture actual response text, not tool call arguments if hasattr(data, "delta") and hasattr(data, "type"): if data.type == "response.output_text.delta": # Stream the actual response text in real-time delta_text = data.delta if delta_text: print(delta_text, end="", flush=True) full_text += delta_text # Skip tool call deltas (we don't want to show those to users) elif data.type == "response.function_call_arguments.delta": continue # Handle validation errors elif isinstance(event, dict): event_type = event.get("event", event.get("type")) if event_type == "error": print(f"\n❌ Error: {event.get('content', event.get('data', 'Unknown error'))}") break print("\n✅ Stream complete") return full_text # Usage await stream_response("I want you to build me a website") ``` ## Streaming from Tools Tools can inject events into the parent SSE stream while they execute. This is especially useful when a tool runs a sub-agent or a long-running operation and you want the client to receive live progress updates alongside the normal agent output. ### Accessing the Streaming Context Inside any `BaseTool.run()` method, two properties give you access to the live stream: | Field | Type | What it is | | - | - | - | | `self.context.streaming_context` | `StreamingContext \| None` | The queue that feeds the parent stream. `None` when the request is not streaming. | | `self.tool_call_id` | `str \| None` | The unique ID of this specific tool invocation. Use it to let clients correlate events with the tool call. | ```python theme={null} streaming_ctx = self.context.streaming_context tool_call_id = self.tool_call_id or "" ``` `streaming_ctx` is `None` when the request is not streaming, so always guard before calling `put_event`. Any object passed to `streaming_ctx.put_event(event)` is forwarded into the same stream your client is already consuming. There are three ways to use this, depending on how informative you want the events to be. ### Method 1: Raw values The simplest option — emit any plain value directly. Useful for quick progress strings during development. ```python theme={null} class MyTool(BaseTool): """Does something and reports progress.""" async def run(self): streaming_ctx = self.context.streaming_context if streaming_ctx: await streaming_ctx.put_event("step 1/3: fetching data…") data = await _fetch() if streaming_ctx: await streaming_ctx.put_event("step 2/3: processing…") result = await _process(data) if streaming_ctx: await streaming_ctx.put_event("step 3/3: done.") return result ``` On the consumer side: ```python theme={null} async for event in agency.get_response_stream(message): if isinstance(event, str): print(f"[tool] {event}") ``` ### Method 2: Existing SDK event types While neither the OpenAI API nor the `agents` SDK contains event types specifically designed for streaming output from tool execution, you can construct a [`RawResponsesStreamEvent`](https://openai.github.io/openai-agents-python/ref/stream_events/#agents.stream_events.RawResponsesStreamEvent) wrapping a `ResponseTextDeltaEvent` directly inside the tool. The internal tracking fields (`item_id`, `content_index`, etc.) just need placeholder values — the consumer's existing delta-handling code treats it identically to a normal LLM text delta. ```python theme={null} from agents import RawResponsesStreamEvent from openai.types.responses import ResponseTextDeltaEvent from agency_swarm.tools import BaseTool from pydantic import Field class MyTool(BaseTool): """Does something and streams progress as text deltas.""" task: str = Field(..., description="The task to perform") async def run(self): streaming_ctx = self.context.streaming_context async def emit_delta(text: str) -> None: if streaming_ctx: await streaming_ctx.put_event( RawResponsesStreamEvent( data=ResponseTextDeltaEvent( content_index=0, output_index=0, sequence_number=0, item_id="tool_progress", logprobs=[], delta=text, type="response.output_text.delta", ) ) ) await emit_delta("Starting…") result = await _perform_task(self.task) await emit_delta(" Done.") return result ``` On the consumer side, these events are indistinguishable from regular LLM text deltas unless you inspect the `item_id` you set on the event: ```python theme={null} from agents import RawResponsesStreamEvent from openai.types.responses import ResponseTextDeltaEvent async for event in agency.get_response_stream(message): if isinstance(event, RawResponsesStreamEvent) and isinstance(event.data, ResponseTextDeltaEvent): if event.data.item_id == "tool_progress": print(f"[tool] {event.data.delta}", end="", flush=True) else: print(event.data.delta, end="", flush=True) ``` ### Method 3: Custom event model For the most informative output you can construct your own class that includes structured metadata — status, tool call ID for correlation, error details, etc. No built-in SDK type covers tool execution progress, so this is the recommended approach for production use, but it will require explicit checks on the consumer side to separate these events from standard SDK events. ```python theme={null} from typing import Literal from pydantic import BaseModel, Field from agency_swarm.tools import BaseTool class ToolProgressEvent(BaseModel): """Streaming progress event emitted by a tool invocation.""" call_id: str status: Literal["in_progress", "completed", "failed"] = "in_progress" delta: str | None = None error: str | None = None class LongRunningTool(BaseTool): """A tool that reports live progress through the parent stream.""" task: str = Field(..., description="The task to perform") async def run(self): streaming_ctx = self.context.streaming_context tool_call_id = self.tool_call_id or "" async def emit(status: str, delta: str | None = None, error: str | None = None) -> None: if streaming_ctx: await streaming_ctx.put_event( ToolProgressEvent(call_id=tool_call_id, status=status, delta=delta, error=error) ) await emit("in_progress", delta="Starting…") try: result = await _perform_task(self.task) await emit("completed") return result except Exception as exc: await emit("failed", error=str(exc)) raise ``` On the consumer side, filter by type: ```python theme={null} async for event in agency.get_response_stream(message): if isinstance(event, ToolProgressEvent): print(f"[{event.status}] {event.delta or ''}") ``` Regardless of the chosen method, events emitted via `put_event()` are only visible to the **client consuming the stream** — the calling agent never sees them. From the agent's perspective, the tool returns only its final `return` value, which is what gets added to the conversation history and passed back to the model. # Third-Party Models Source: https://agency-swarm.ai/additional-features/third-party-models Use models from Anthropic, Google, AWS, or self-hosted open-source models via LiteLLM. While OpenAI is generally recommended, there are situations where you might prefer third-party models. Agency Swarm supports proprietary providers (Anthropic, Google, AWS) and self-hosted open-source models (Llama, Mistral, etc.) through LiteLLM integration: ## LiteLLM Integration Since Agents SDK no longer uses assistants, most of the previously available frameworks became incompatible with it. One of the few frameworks that has been ported for the new SDK is [LiteLLM](https://docs.litellm.ai/docs/response_api), which you can use to connect your agent to various providers (Anthropic, Google Vertex AI, AWS Bedrock, Azure) as well as self-hosted open-source models via Ollama, vLLM, and other local serving solutions. **LiteLLM cannot be installed with pip.** Every LiteLLM release still declares `openai<3` in its package metadata, while Agency Swarm requires `openai>=3`. The pin is stale — LiteLLM runs fine on openai 3.x — but pip refuses to install both packages together. Install with **uv** and the override shown in the steps below, or run LiteLLM in a separate environment. Install Agency Swarm with the `litellm` extra. With uv, add the override to your `pyproject.toml` first so the stale `openai<3` pin is ignored during resolution: ```toml theme={null} # pyproject.toml [tool.uv] override-dependencies = ["openai>=3,<4"] ``` ```bash theme={null} uv add "agency-swarm[litellm]" ``` On pip, `pip install "agency-swarm[litellm]"` fails on the pin conflict. Running `pip install agency-swarm` and then `pip install litellm --no-deps` works around it but skips LiteLLM's own dependencies, so it is fragile and unsupported. Create an agent that connects to your LiteLLM proxy: ```python theme={null} import os from agency_swarm import Agent from agents.extensions.models.litellm_model import LitellmModel # Requires GOOGLE_API_KEY environment variable set gemini_agent = Agent( name="GeminiAgent", instructions="You are a helpful assistant", model="litellm/gemini/gemini-2.0-flash" ) ``` Set up your agency and start using third-party models: ```python theme={null} from agency_swarm import Agency agency = Agency(gemini_agent) agency.tui() ``` The first terminal run downloads the matching terminal app automatically. The LiteLLM proxy is a standalone server — install it in its own environment so its `openai<3` pin never touches your Agency Swarm install: ```bash theme={null} uv tool install "litellm[proxy]" # or: pipx install "litellm[proxy]" ``` Create a `config.yaml` file to configure your models and providers: ```yaml theme={null} model_list: - model_name: gemini-flash litellm_params: model: gemini/gemini-2.0-flash api_key: os.environ/GEMINI_API_KEY # or paste your key directly here - model_name: claude-sonnet litellm_params: model: anthropic/claude-3-5-sonnet-20240620 api_key: os.environ/ANTHROPIC_API_KEY - model_name: llama-groq litellm_params: model: groq/llama-3.1-70b-versatile api_key: os.environ/GROQ_API_KEY general_settings: store_prompts_in_spend_logs: true # Enable session management ``` Add your API keys to your environment variables: ```bash theme={null} export GEMINI_API_KEY="your-gemini-api-key" export ANTHROPIC_API_KEY="your-anthropic-api-key" export GROQ_API_KEY="your-groq-api-key" ``` Launch the LiteLLM proxy server with your configuration: ```bash theme={null} litellm --config /path/to/config.yaml # Server will start on http://localhost:4000 ``` Create an agent that connects to your LiteLLM proxy: ```python theme={null} import os from openai import AsyncOpenAI from agency_swarm import Agent, OpenAIChatCompletionsModel custom_client = AsyncOpenAI( api_key="xxx", # Any if proxy key wasn't set base_url="http://localhost:4000", ) gemini_agent = Agent( name="GeminiAgent", instructions="You are a helpful assistant", model=OpenAIChatCompletionsModel( model="gemini/gemini-2.0-flash", openai_client=custom_client ) ) ``` A custom `AsyncOpenAI` stored on a model outlives a single event loop — each `get_response`/`get_response_sync` run can use a new one, and httpx2 binds pooled connections to the loop that created them. Pass `http_client=loop_scoped_http_client()` (from `agency_swarm`) when building the client so every request runs on the caller's loop instead of crashing on the second run: ```python theme={null} from agency_swarm import loop_scoped_http_client custom_client = AsyncOpenAI( api_key="xxx", base_url="http://localhost:4000", http_client=loop_scoped_http_client(), ) ``` Set up your agency and start using third-party models: ```python theme={null} from agency_swarm import Agency agency = Agency(gemini_agent) agency.tui() ``` The first terminal run downloads the matching terminal app automatically. ## Using model-specific tools Some models, like gemini or claude have their internal tools, which can be attached to an agent by utilizing `extra_body` parameter in agent's `model_settings`: ```python theme={null} import os from agency_swarm import Agent from agents.extensions.models.litellm_model import LitellmModel # Requires GOOGLE_API_KEY environment variable set gemini_agent = Agent( name="GeminiAgent", instructions="You are a helpful assistant", model="litellm/gemini/gemini-2.0-flash" ) # Requires XAI_API_KEY environment variable set grok_agent = Agent( name="GrokAgent", instructions="You are a helpful assistant", model="litellm/xai/grok-4-0709" ) ``` Here both Grok and Gemini agents will be able to use their native search tools, which are similar to OpenAI's WebSearch() tool. Consider checking out [LiteLLM's documentation](https://docs.litellm.ai/docs) to find a full list of supported tools. ## Limitations Be aware of the limitations when using third-party models. * **Hosted tools are not supported**: Patched agents are not able to utilize hosted tools, such as WebSearch, FileSearch, CodeInterpreter and others. * **Patched and unpatched models should not use handoffs to communicate**: You may use standard OpenAI client and patched agents in a single agency, however using handoff to transfer chat from patched model to unpatched or vice-versa will lead to an error. * **Function calling may not be supported by some third-party models**: This limitation prevents the agent from communicating with other agents in the agency. Therefore, it must be positioned at the end of the agency chart and cannot utilize any tools. * **RAG is typically limited**: Most open-source implementations have restricted Retrieval-Augmented Generation capabilities. It is recommended to develop a custom tool with your own vector database. * **Potential library conflicts**: the Agents SDK is still a fairly new framework which is being actively developed and improved. Due to that, there might be potential conflicts between litellm and openai-agents packages on recent releases. For Azure OpenAI, see [Azure OpenAI](/additional-features/azure-openai). ## Future Plans Updates will be provided as new open-source assistant API implementations stabilize. If you successfully integrate other projects with agency-swarm, please share your experience through an issue or pull request. # Deployment Source: https://agency-swarm.ai/additional-features/voice-agents/deployment Run the realtime FastAPI bridge, serve the bundled web client, and connect Twilio phone calls. Use this guide once your agent is ready and you want to host a realtime bridge or connect phone infrastructure. It builds on the [Overview](./overview) and assumes your agents are ready for deployment. ## Host the FastAPI bridge `run_realtime` starts a FastAPI app that proxies between your Agency Swarm agents and a supported realtime provider (OpenAI or xAI). The helper already converts your agency to the realtime runtime, exposes a `/realtime` websocket, and streams events back to callers. ```python theme={null} from agency_swarm import Agency from agency_swarm.integrations import run_realtime from voice_agent import voice_agent agency = Agency(voice_agent) run_realtime( agency=agency, provider="openai", model="gpt-realtime-2", host="0.0.0.0", port=8000, turn_detection={"type": "server_vad"}, ) ``` ```bash theme={null} python app.py ``` The server prints every incoming websocket connection. Set `voice=` to pick the voice for the whole call, or leave it out to use the entry agent's voice—see [one voice per call](./overview#one-voice-per-call). Supply `cors_origins` when you deploy behind a browser client that runs on a different domain. `run_realtime(..., return_app=True)` returns the FastAPI `app` object if you want to mount it inside an existing application rather than start a dedicated Uvicorn process. ## Serve voice endpoints from `run_fastapi` Keep your existing REST endpoints and add realtime voice routes with one flag: ```python theme={null} run_fastapi( agencies={"support": create_agency}, enable_realtime=True, realtime_options={ "model": "gpt-realtime-2", "turn_detection": {"type": "server_vad", "interrupt_response": True}, }, enable_logging=True, ) ``` `enable_realtime=True` mounts `/support/realtime` alongside the normal JSON endpoints. Pass `realtime_options` when you want to override model settings (they map directly to `run_realtime` keyword arguments). Authentication and logging apply to the new websocket route automatically. For xAI sessions: ```python theme={null} run_realtime( agency=agency, provider="xai", model="grok-voice-think-fast-1.0", ) ``` Agency Swarm adds the selected xAI model to the realtime websocket URL as `?model=` because xAI selects voice models from the connection query string. ## Serve the packaged browser client A ready-made WebAudio frontend ships with the library. Launch it with your own agency in one call: ```python theme={null} from agency_swarm.ui.demos.realtime import RealtimeDemoLauncher RealtimeDemoLauncher.start(agency, model="gpt-realtime-2", voice="marin") ``` This mounts the frontend and websocket bridge under the same process—ideal for internal demos or QA. For a runnable script, see [`examples/interactive/realtime/demo.py`](https://github.com/VRSEN/agency-swarm/blob/main/examples/interactive/realtime/demo.py). ## Twilio phone calls Pass a Twilio number to `run_realtime` to expose a media-stream bridge. The helper exposes `/incoming-call` (returns TwiML) and `/twilio/media-stream` for bidirectional audio. ```python theme={null} run_realtime( agency=agency, model="gpt-realtime-2", twilio_number="+15551234567", twilio_audio_format="g711_ulaw", twilio_greeting="Connecting you to the assistant.", ) ``` Deployment checklist: 1. Start the server and expose it publicly, e.g. `ngrok http 8000`. 2. In the Twilio Console, set your phone number’s voice webhook to `https:///incoming-call`. 3. Call the number—the helper streams audio in both directions and reuses your existing tools and handoffs. For a lower-level implementation (custom playback tracking, fine-grained buffering), see the [Twilio demo README](https://github.com/VRSEN/agency-swarm/blob/main/src/agency_swarm/ui/demos/realtime/twilio/README.md). Set `OPENAI_API_KEY` or `XAI_API_KEY` for the realtime provider you selected. You configure the phone number and webhook in the Twilio Console, so this bridge does not read a Twilio account SID or auth token. Keep provider keys out of source control. # Overview Source: https://agency-swarm.ai/additional-features/voice-agents/overview Design voice-first assistants with the same Agency Swarm agents you already use. Agency Swarm reuses your existing `Agent` definitions for voice. This page shows how to adapt agents for spoken conversations. ## Try it locally Save this as `voice_demo.py`. It starts the packaged browser client on your computer, so you can speak with your agent before you host anything. ```python theme={null} from agency_swarm import Agency, Agent from agency_swarm.ui.demos.realtime import RealtimeDemoLauncher voice_agent = Agent( name="Voice Concierge", instructions="You are a friendly concierge. Keep answers brief.", voice="marin", ) RealtimeDemoLauncher.start(Agency(voice_agent), host="127.0.0.1") ``` 1. Install the voice extra: `pip install "agency-swarm[voice]"`. 2. Set `OPENAI_API_KEY`, then run `python voice_demo.py`. 3. Open [http://127.0.0.1:8000](http://127.0.0.1:8000), click **Connect**, and allow microphone access. When you are ready to host the browser client or connect phone calls, use the [Deployment](./deployment) guide. ## What you can build * **Phone receptionist** — answers calls, routes to specialists, captures caller details. * **Live support triage** — gathers context, lets callers interrupt, and escalates to a human or another agent. * **Language coach** — listens, corrects pronunciation, and keeps the dialogue short and encouraging. ## Prerequisites * Access to a supported realtime provider: * OpenAI (`gpt-realtime-2` is the Agency Swarm default; see [OpenAI's realtime model catalog](https://developers.openai.com/api/docs/models/all#realtime-and-audio) for other models and current pricing) * xAI (`grok-voice-think-fast-1.0` is the Agency Swarm default; see [xAI's Speech to Speech guide](https://docs.x.ai/developers/model-capabilities/audio/speech-to-speech#model-selection) for current model availability) * The voice extra: ```bash theme={null} pip install "agency-swarm[voice]" ``` ## Define your agent (same API) You keep using the standard `Agent` class—voice agents are regular agents with the same tools, handoffs, and instructions. ```python theme={null} from agency_swarm import Agent, function_tool @function_tool def lookup_order(order_id: str) -> str: """Return a short order status by ID.""" return f"Order {order_id} has shipped and will arrive soon." voice_agent = Agent( name="Voice Concierge", instructions=( "You are a friendly concierge. Answer in one or two sentences and offer to look up order " "details when the caller mentions a number." ), tools=[lookup_order], voice="marin", ) ``` Keep using the same agent definitions—add `voice=` only when you care about the spoken persona. Set `voice` to any supported realtime token: * OpenAI voices: `alloy`, `ash`, `ballad`, `cedar`, `coral`, `echo`, `marin`, `sage`, `shimmer`, `verse` * xAI voices: `ara`, `eve`, `leo`, `rex`, `sal` ## One voice per call **A call uses a single voice from start to finish.** Once the model has spoken, the realtime API refuses to switch voices—OpenAI answers with a `cannot_update_voice` error. Agency Swarm therefore picks the voice as the call starts and keeps it, even when the call hands off to another agent. The voice comes from the first place that sets one: 1. The `voice=` you pass to `run_realtime()` or the demo launcher. 2. The `voice=` on your **entry agent**—the agent that answers the call. 3. The provider's own default when neither is set. A `voice=` on any other agent is not used for that call. It is still worth setting: that agent uses its own voice whenever it is the one answering. If you want variety without picking voices by hand, build the agency with `randomize_agent_voices=True`. Every agent without an explicit voice gets a deterministic random pick from the provider's list, and the entry agent's pick becomes the voice for the call. Pass `voice_random_seed=` to keep the picks stable between runs. ## Add handoffs (optional) Handoffs work exactly as they do in text mode. Register your flows once and they will carry over to voice sessions. ```python theme={null} from agency_swarm import Agency, Agent, Handoff billing = Agent(name="Billing", instructions="Handle billing questions briefly.") faq = Agent(name="FAQ", instructions="Answer frequently asked questions.") concierge = Agent( name="Concierge", instructions="Greet the caller, collect intent, then hand off when a specialist is needed.", voice="marin", ) agency = Agency( concierge, communication_flows=[ (concierge > billing, Handoff), (concierge > faq, Handoff), ], ) ``` When the concierge hands off, the specialist takes over the conversation with its own instructions and tools. The caller keeps hearing the concierge's `marin` voice for the rest of the call, so give the specialists a different name or greeting if you want the switch to be obvious. ## Next steps * Try the [realtime browser demo](https://github.com/VRSEN/agency-swarm/tree/main/examples/interactive/realtime) * [Deploy your agents](./deployment) for phone calls using Twilio. * Review OpenAI’s realtime [Quickstart](https://openai.github.io/openai-agents-python/realtime/quickstart/) and [Guide](https://openai.github.io/openai-agents-python/realtime/guide/) for protocol details—Agency Swarm builds on those primitives. # Contributing to Agency Swarm Source: https://agency-swarm.ai/contributing/contributing Learn how to contribute to Agency Swarm We welcome contributions to Agency Swarm! By contributing, you help improve the framework for everyone. Here's how you can get involved: ## Setting Up Your Development Environment ### Prerequisites * Python 3.12 or higher * Pip * Git ### Setup 1. Clone the repository: ```bash theme={null} git clone https://github.com/VRSEN/agency-swarm.git cd agency-swarm ``` 2. Create and activate a virtual environment (recommended): ```bash theme={null} python -m venv .venv source .venv/bin/activate # On Windows use `.venv\Scripts\activate` ``` 3. Install dependencies including development tools: ```bash theme={null} pip install -e ".[dev]" ``` 4. Install Pre-Commit Hooks: ```bash theme={null} pip install pre-commit pre-commit install ``` ## Running Tests Testing ensures that your contributions work as intended and do not break existing functionality. Ensure all test dependencies are installed. ```bash theme={null} pip install -e ".[dev]" ``` Run the test suite using Pytest. ```bash theme={null} pytest ``` Check the test coverage to ensure comprehensive testing. ```bash theme={null} pytest --cov=agency_swarm tests/ ``` ## Submitting Changes Create a branch for your work: ```bash theme={null} git checkout -b feature/your-feature-name ``` Commit your updates: ```bash theme={null} git add . git commit -m "Add [feature]: Description" ``` Push your branch: ```bash theme={null} git push origin feature/your-feature-name ``` Open a pull request on GitHub: ```markdown theme={null} - Provide a concise title and description. - Reference related issues. ``` ### Code Style and Linting This project uses `ruff` for linting and code formatting. Configuration for this tool can be found in `pyproject.toml`. Before committing your changes, please check and fix linting errors: ```bash theme={null} ruff check . --fix ``` It's recommended to install these tools in your development environment. If you followed the setup instructions, they should already be installed via: ```bash theme={null} pip install -e ".[dev]" ``` # Agent Swarm TUI Source: https://agency-swarm.ai/core-framework/agencies/agent-swarm-cli Start the terminal UI with the main npx launcher, then expand optional sections only if you need them. Agent Swarm TUI is the terminal UI for Agency Swarm. Use it when you want to build or test your Agency Swarm project in the terminal. ## Start the TUI For most users, the right way to start is: ```bash theme={null} npx @vrsen/agentswarm ``` This is the main launch path. It handles first-run setup, helps you choose or create an agency, and then opens the terminal UI. Run it from your project root. If you are starting fresh, run it in a new empty folder. You do not need to install the TUI globally first. Agent Swarm TUI startup screen ## Before You Start Make sure you have: * Node.js 20 or newer so `npx` is available * Python 3.12 or newer available for Agency Swarm projects * a model provider credential if you want to send prompts right away, or you can add it later with `/auth` * an existing agency project, or a starting point from [From Scratch](/welcome/getting-started/from-scratch) or the [Starter Template](/welcome/getting-started/starter-template) ## What Happens on First Launch On first launch, you will usually see this flow: Start with `npx @vrsen/agentswarm`. The launcher can reuse the current Agency Swarm project, create a starter project, or connect to an agency that is already running. The launcher checks for a project `.venv`. If it needs to create one, it asks first and then installs the project dependencies before opening the TUI. The TUI opens for the agency you selected during onboarding. If you do not already have a usable model provider configured, use `/auth`. This is the path we recommend for onboarding, videos, and first-time users. ## What You Can Do in the TUI Once the TUI is running, you get: * a keyboard-first terminal workflow * session history, export, and `/compact` * `/agents` to switch between Plan, Build, and Run, and to pick which swarm or agent gets your next prompt * `@AgentName` mentions to route a prompt to a specific top-level agent * `@` file and resource references when you start from a local project * `Tab` autocomplete for both agent mentions and file and resource references Agent Swarm TUI agent picker ### Plan, Build, and Run `/agents` switches between three modes: * **Plan** designs changes to your agency with the Agent Builder before any files change. * **Build** implements those changes in your project files with the Agent Builder. Plan and Build work without a running Agency Swarm server. * **Run** sends your prompts to your live agency through the Agency Swarm server. Press `Tab` to toggle between Plan and Build, or to cycle through swarm targets while in Run. Returning to Run after a Build session restarts the local server from your current project files and refreshes dependencies from your manifest, without upgrading packages that already satisfy it. If the agency fails to start, the full error stays visible in `/agents` so you can fix it in Build and retry. ## Optional Paths If this is your first run, you can ignore everything below. Use the same `npx @vrsen/agentswarm` command, then choose **Connect to a running Agent Swarm** during onboarding. Inside the TUI, the same flow is available as `/connect`. The launcher asks for: 1. the Agency Swarm server URL 2. whether the server needs a bearer token 3. the agency id, if automatic discovery does not already find it Use it when: * a local Agency Swarm server is already running * you want to connect to a remote Agency Swarm server * the server is protected and needs a bearer token Current limitations for this path: * `/models` does not switch the models configured inside your Agency Swarm backend yet * local file tools are not available; if you want the TUI to work directly on project files, start with `npx @vrsen/agentswarm` from that project directory instead Use your Python config to choose backend models and providers. If your project already launches from Python, `agency.tui()` still works as the secondary entrypoint. ```python theme={null} agency.tui() ``` Then start your project the usual way: ```bash theme={null} python agency.py ``` This path stays bound to the exact `Agency` instance you passed in Python. It starts the local bridge for that agency, then opens the TUI connected to it. Use it when your team already starts the project from Python and you want a quick TUI test path without switching directories or changing entrypoints. `tui(show_reasoning=False)` is not supported in the new TUI yet. ## Related Pages * [Installation](/welcome/installation) * [From Scratch](/welcome/getting-started/from-scratch) * [Third-Party Models](/additional-features/third-party-models) * [Running an Agency](/core-framework/agencies/running-agency) * [FastAPI Integration](/additional-features/fastapi-integration) * [API Reference](/references/api) # Communication Flows Source: https://agency-swarm.ai/core-framework/agencies/communication-flows Understanding communication flows in Agency Swarm. Always start with one agent. Never build two agents simultaneously unless you know exactly what you're doing. The more agents you have, the harder it becomes to train them on specific tasks. ## Orchestration Patterns Agency Swarm supports flexible orchestration patterns. Unlike all other frameworks, communication flows in Agency Swarm are **uniform**, meaning they can be defined in any way you want. | Pattern | Description | Reliability | Autonomy | Costs | When to Use | | - | - | - | - | - | - | | **Handoff** | Control transfers completely to another agent who continues the conversation | Very High | Low | Lower | Sequential workflows where each step requires tight feedback from the user | | **Orchestrator-Worker** | One agent assigns tasks to multiple agents and compiles their responses | Lower (mitigated with guardrails) | Very High | Higher | Complex multi-step tasks with independent not-very-high stakes steps | *Scroll table to the right to see the full description of each pattern.* **Examples**: * **Handoff**: Creative script writing with planner and script writer agents - requires tight user feedback at each stage to refine the story direction * **Orchestrator-Worker**: News aggregation and research from various sources - quality of individual sources isn't critical, main agent filters and compiles them ## Handoff Pattern Control transfers completely to another agent who takes over the interaction. The receiving agent gets full conversation history and continues from there. ```python theme={null} from agency_swarm import Agent from agency_swarm import Handoff # Triage agent routes to specialists triage_agent = Agent( name="TriageAgent", instructions="Assess customer inquiries and route to appropriate specialist", ) billing_specialist = Agent( name="BillingSpecialist", description="Handles billing inquiries, payment issues, and invoice questions", instructions="Resolve customer billing issues with full context from previous conversation", ) technical_specialist = Agent( name="TechnicalSpecialist", description="Handles technical support and troubleshooting", instructions="Provide technical support with full conversation history", ) agency = Agency( triage_agent, communication_flows=[ (triage_agent, billing_specialist, Handoff), # Handoff to billing (triage_agent, technical_specialist, Handoff), # Handoff to technical ] ) ``` The TriageAgent transfers control completely to the appropriate specialist, who receives full conversation history and continues the interaction. Control does not return to TriageAgent. ## Orchestrator-Worker Pattern One agent assigns tasks to multiple other agents and compiles their responses. Agents use other agents as specialized tools through the `SendMessage` mechanism. Control always returns to the orchestrator after each delegation. ```python theme={null} # Portfolio Manager orchestrates investment research portfolio_manager = Agent( name="PortfolioManager", instructions="Orchestrate investment research by gathering data, delegating analysis, and compiling recommendations", tools=[fetch_market_data], ) risk_analyst = Agent( name="RiskAnalyst", instructions="Specialize in investment risk analysis", tools=[analyze_risk_factors], output_type=RiskAssessment, # Structured output ) report_generator = Agent( name="ReportGenerator", instructions="Generate professional investment reports", tools=[create_report], ) agency = Agency( portfolio_manager, # Entry point and orchestrator communication_flows=[ (portfolio_manager, risk_analyst), # Can request risk analysis (portfolio_manager, report_generator), # Can request report generation ] ) ``` The Portfolio Manager delegates to specialists, receives their structured responses, and compiles them into a final investment decision. ## Understanding Communication Flows Communication flows are defined using tuples in the `communication_flows` parameter: ```python theme={null} from agency_swarm import Agency from agency_swarm import Handoff agency = Agency( ceo, dev, # Entry points - agents that can communicate with users communication_flows=[ (ceo, dev, Handoff), # CEO can transfer the user to the developer (ceo, dev), # CEO can assign tasks to developer (dev, va) # developer can assign tasks to virtual assistant ] ) ``` Each tuple `(sender, receiver)`, `(sender > receiver)`, or `(receiver < sender)` defines a directional communication path. Entry points are agents that can communicate with users. In the example above, the CEO can transfer the user to the Developer and the developer will proceed to interact with the user directly. At the same time, the CEO can assign tasks to both Developer and Virtual Assistant, so they will run in parallel in different threads and come back with their results to the CEO. ## Under the Hood Agency Swarm uses a `SendMessage` tool for inter-agent communication. Defining communication flows adds recipients to this tool. For advanced customization, see [Custom Communication Flows](/additional-features/custom-communication-flows/overview). # Overview Source: https://agency-swarm.ai/core-framework/agencies/overview Understanding agencies in Agency Swarm. Agency in Agency Swarm is a collection of agents that can collaborate with one another. ## Benefits of Using an Agency Utilizing an Agency consisting of multiple agents offers several benefits: Agents within an agency can supervise each other, reducing mistakes and handling unexpected scenarios more effectively. Adding more agents allows for longer sequences of actions, enabling the completion of more complex tasks before delivering results to the user. Agencies allow you to scale your solutions seamlessly by adding more agents, as the complexity of your system grows. Start with a minimal number of agents. Fine-tune them to ensure they function correctly before adding more. Introducing too many agents initially can make debugging and understanding interactions challenging. In the latest version, the Agency class orchestrates a collection of `Agent` instances based on a defined structure. It provides enhanced thread management, persistence hooks, and improved communication patterns between agents. ## Agency Parameters Overview of parameters in the new `Agency` class: | Name | Parameter | Description | | - | - | - | | Entry Points | `*entry_points_args` | Positional arguments representing Agent instances that serve as entry points for external interaction. These agents can be directly messaged by users. | | Communication Flows *(optional)* | `communication_flows` | List of (sender, receiver) tuples defining allowed agent-to-agent message paths. Example: `[(ceo, dev), (ceo, va)]`. Default: `None` | | Name *(optional)* | `name` | A name for the agency instance. Default: `None` | | Shared Instructions *(optional)* | `shared_instructions` | Instructions prepended to all agents' system prompts in a string format or a path to markdown file. Default: `None` | | Shared Tools *(optional)* | `shared_tools` | List of tool instances or BaseTool classes to add to all agents. Default: `None` | | Shared Tools Folder *(optional)* | `shared_tools_folder` | Path to a folder containing tool files to load and share with all agents. Default: `None` | | Shared Files Folder *(optional)* | `shared_files_folder` | Path to a folder of files to upload and share with all agents via a common vector store. Default: `None` | | Shared MCP Servers *(optional)* | `shared_mcp_servers` | List of MCP server instances to attach to all agents. Default: `None` | | Send Message Tool Class *(optional)* | `send_message_tool_class` | Fallback SendMessage tool class when a `communication_flows` entry does not specify its own tool. Prefer configuring SendMessage variants directly through `communication_flows`. Default: `None` | | Load Threads Callback *(optional)* | `load_threads_callback` | A callable to load conversation threads for persistence. Default: `None` | | Save Threads Callback *(optional)* | `save_threads_callback` | A callable to save conversation threads for persistence. Default: `None` | ## Example Quick example of how to create an agency with 3 agents using the new structure: ```python theme={null} from datetime import datetime from agency_swarm import Agency, function_tool from .ceo import CEO from .developer import Developer from .virtual_assistant import VirtualAssistant ceo = CEO() dev = Developer() va = VirtualAssistant() @function_tool def get_current_time() -> str: """Get the current time.""" return datetime.now().isoformat() # New structure: entry points as positional args, communication flows as keyword arg agency = Agency( ceo, dev, # Entry points - these agents can interact with users communication_flows=[ (ceo, dev), # CEO can initiate communication with Developer (ceo, va), # CEO can initiate communication with Virtual Assistant (dev, va) # Developer can initiate communication with Virtual Assistant ], shared_instructions="./shared_instructions.md", shared_tools=[get_current_time], # Available to all agents ) ``` ## Next Steps Make sure to learn more about [Communication Flows](/core-framework/agencies/communication-flows) and [Running an Agency](/core-framework/agencies/running-agency). # Running an Agency Source: https://agency-swarm.ai/core-framework/agencies/running-agency How to run an Agency. When it comes to running your agency, Agency Swarm provides 3 main methods: 1. **CopilotKit/AG-UI Interface**: The most modern and recommended way to get started. 2. **Get Response**: For backend or custom integrations. 3. **Terminal Version**: Best for quick debugging and testing. ## Pre-requisites for CopilotKit/AG-UI Demo To use the CopilotKit/AG-UI demo (`copilot_demo()`), make sure you have the following installed: * **Node.js** (v18 or newer recommended): [Download Node.js](https://nodejs.org/) * **npm** (comes with Node.js) If these requirements are not met, the demo will not start and you will see an error message. ## CopilotKit/AG-UI Interface To open a CopilotKit interface, use the `copilot_demo` method: ```python theme={null} agency.copilot_demo() ``` This will launch both the backend and a Next.js frontend. Simply follow the `localhost` link from the terminal to start using your agency in a chat-based UI. ## Get Response To get a response from your agency directly in code, use the async `get_response` method: ```python theme={null} import asyncio async def main(): result = await agency.get_response("I want you to build me a website") print(result.final_output) asyncio.run(main()) ``` **With additional parameters:** ```python theme={null} async def main(): result = await agency.get_response( message="I want you to build me a website", additional_instructions="This is an additional instruction for the task.", recipient_agent=dev # Optional: specify which agent to send to ) print(result.final_output) asyncio.run(main()) ``` **Synchronous version:** ```python theme={null} result = agency.get_response_sync( message="I want you to build me a website", additional_instructions="This is an additional instruction for the task.", recipient_agent=dev # Optional: specify which agent to send to ) print(result.final_output) ``` **Parameters**: * `message`: The message to send to the agency. * `additional_instructions` (optional): Additional instructions that will be appended at the end of instructions for the recipient agent. * `recipient_agent` (optional): The agent to which the message should be sent. ## Track Usage and Cost Use the `/cost` command in the TUI to see the current session usage and cost. TUI /cost output showing session usage and cost To understand what's inside the `usage` object, see [Observability](/additional-features/observability#usage-payload). If you're running your agency as an HTTP API, see [Serving Agencies as APIs](/additional-features/fastapi-integration). ## Terminal UI The recommended terminal launch path is: ```bash theme={null} npx @vrsen/agentswarm ``` Run it from your project root when you want the launcher to handle first-run setup and open the terminal UI for you. This path lets the launcher detect the agency from your project and open the TUI connected to it. Use it when you want the easiest setup path. For the full launch flow, first-run auth, and the optional terminal launch paths, see [Agent Swarm TUI](/core-framework/agencies/agent-swarm-cli). If you already launch from Python, `agency.tui()` is still supported: ```python theme={null} agency.tui() ``` Use `agency.tui(reload=False)` if you want to turn off hot reload on file changes. This Python path stays bound to the `Agency` instance you launch from code by starting the local bridge automatically. When using the terminal to run the agency, you can send messages directly to any top-level agent by using the "mentions" feature. To do this, start your message with the agent's name preceded by an @ symbol (for example, `@Developer I want you to build me a website`). This directs your message to the specified agent instead of the CEO. You can also press the tab key to autocomplete the agent's name. `tui(show_reasoning=False)` is not supported in the new TUI yet. # Agency Visualization Source: https://agency-swarm.ai/core-framework/agencies/visualization Create interactive HTML visualizations and get ReactFlow-compatible data Agency Swarm provides two visualization methods: 1. **`visualize()`** - Creates interactive HTML files 2. **`get_agency_graph()`** - Returns ReactFlow-compatible JSON ## `visualize()` Creates a self-contained HTML file with interactive agency visualization. ```python theme={null} def visualize( self, output_file: str = "agency_visualization.html", include_tools: bool = True, open_browser: bool = True ) -> str ``` ### Parameters | Parameter | Type | Default | Description | | - | - | - | - | | `output_file` | `str` | `"agency_visualization.html"` | Path to save HTML file | | `include_tools` | `bool` | `True` | Whether to include agent tools | | `open_browser` | `bool` | `True` | Whether to open in browser | ### Example ```python theme={null} from agency_swarm import Agency, Agent, function_tool @function_tool def analyze_data(data: str) -> str: """Analyze data""" return f"Analysis: {data}" analyst = Agent( name="Analyst", instructions="You analyze data.", tools=[analyze_data] ) manager = Agent( name="Manager", instructions="You coordinate work." ) agency = Agency( manager, communication_flows=[(manager, analyst)], name="Analysis Agency" ) # Create visualization html_file = agency.visualize() print(f"Saved to: {html_file}") ``` ## `get_agency_graph()` Returns ReactFlow-compatible JSON data for custom frontend integration. ```python theme={null} def get_agency_graph( self, include_tools: bool = True ) -> dict[str, Any] ``` ### Returns ```python theme={null} { "nodes": [ { "id": "Manager", "type": "agent", "position": {"x": 100, "y": 50}, "data": { "label": "Manager", "description": "Agent description", "isEntryPoint": True, "toolCount": 0 } } ], "edges": [ { "id": "Manager->Analyst", "source": "Manager", "target": "Analyst", "type": "communication" } ] } ``` ### Node Types * **Agent nodes**: `type: "agent"` with agent metadata * **Tool nodes**: `type: "tool"` with parent agent reference ### Edge Types * **Communication**: `type: "communication"` between agents * **Ownership**: `type: "owns"` from agent to tool ## Frontend Integration Expose `get_agency_graph()` in your API, then use the JSON directly in React: ```tsx theme={null} import ReactFlow from 'reactflow'; const agencyData = await fetch('/your-graph-endpoint').then(r => r.json()); function AgencyVisualization() { return (
); } ```
# Advanced Configuration Source: https://agency-swarm.ai/core-framework/agents/advanced-configuration Learn advanced configuration options for your agents in Agency Swarm. All parameters inside the `Agent` class follow the same structure as the OpenAI Agents SDK [`Agent`](https://openai.github.io/openai-agents-python/ref/agent/#agents.agent.Agent). However, there are a few advanced parameters that require more explanation. ### Parallel Tool Calls Controls whether tools execute in parallel or sequentially for a given agent. ```python theme={null} from agency_swarm import Agent, ModelSettings agent = Agent( name="MyAgent", instructions="...", model_settings=ModelSettings(parallel_tool_calls=False), ) ``` To force sequential execution for a specific tool regardless of that setting, set `one_call_at_a_time = True` in the tool’s `ToolConfig`. See [Advanced Tool Configuration](/core-framework/tools/custom-tools/configuration). ### File Search If your `files_folder` ends with `_vs_`, Agency Swarm automatically associates files with that Vector Store and adds `FileSearchTool` to the Agent. The `include_search_results` behavior can be toggled via the Agent’s `include_search_results` flag. ### Web Search Sources ```python theme={null} from agency_swarm import Agent, WebSearchTool agent = Agent( name="Researcher", instructions="Search the web and summarize findings.", tools=[WebSearchTool()], include_web_search_sources=True, # default ) ``` With `include_web_search_sources=True` (default), `WebSearchTool` calls include source URLs. Set `include_web_search_sources=False` to skip this. ### System Reminders Use `system_reminders` when you want the agent to see a short reminder at a supported trigger, without writing hooks. ```python theme={null} from agency_swarm import Agent agent = Agent( name="SupportAgent", instructions="Answer clearly and keep the user moving forward.", system_reminders="Before replying, end with one clear next step.", ) ``` A plain string or callable is added on every model call of each top-level user turn. It appears only in the model input and is **not saved** in the thread history. For a long autonomous run that may call many tools before it returns, add a checkpoint reminder: ```python theme={null} from agency_swarm import Agent, EveryNToolCalls agent = Agent( name="ResearchAgent", instructions="Complete the full research task before replying. Use tools as needed.", system_reminders=[ "Before replying, end with one clear next step.", EveryNToolCalls(15, "Pause and summarize progress before using more tools."), ], ) ``` `EveryNToolCalls` counts local function tools and hosted tools (such as `WebSearchTool` and `FileSearchTool`) separately for each agent within one logical run. A logical run starts with a user request to an agency or a direct call to `Runner` imported from `agency_swarm`. Handoffs and resumed interruptions stay in that run. The count resets when the run completes, fails, or is cancelled. For each configured `EveryNToolCalls`, if parallel tool calls cross several of its thresholds before the next model call, Agency Swarm produces exactly one reminder for that model call. It keeps the modulo remainder—the calls left after dividing by `n`—toward the next threshold. If the reminder needs agency context, pass a callable: ```python theme={null} from agency_swarm import Agent, MasterContext, RunContextWrapper def build_reminder(ctx: RunContextWrapper[MasterContext], _agent: Agent) -> str: customer_name = ctx.context.user_context.get("customer_name", "the user") return f"Greet {customer_name} by name and end with one next step." agent = Agent( name="SupportAgent", instructions="Answer clearly and keep the user moving forward.", system_reminders=build_reminder, ) ``` Use `system_reminders` for normal reminders. Use `hooks` only when you need custom lifecycle behavior beyond these built-in triggers. The reminder boundary lives on `agency_swarm.Runner` — import `Runner` from `agency_swarm`, not `agents`, when you run an agent directly. It keeps reminders out of saved history just like an `Agency` does. Calling `agents.Runner` directly gives you stock SDK behavior with no reminder handling. If you save a run state to resume an interrupted run later, serialize it with `run_state_to_json` and restore it with `run_state_from_json`: ```python theme={null} from agency_swarm import Runner, run_state_from_json, run_state_to_json result = await Runner.run(agent, "next") state_json = run_state_to_json(result.to_state()) restored = await run_state_from_json(agent, state_json) result = await Runner.run(agent, restored) ``` Use these instead of the SDK's `RunState.to_json()` / `RunState.from_json()`. The plain SDK methods drop the reminder state, so reminder counts restart on resume. ### Conversation starters cache Conversation starters are the suggested prompts you see in the chat UI. When enabled, cache can instantly replay the first reply without calling the LLM. ```python theme={null} from agency_swarm import Agent agent = Agent( name="SupportAgent", instructions="You are helpful.", model="gpt-6-luna", conversation_starters=["Support: I need help with billing"], cache_conversation_starters=True, ) ``` In this example: * The UI shows the starter prompt “Support: I need help with billing”. * The FastAPI `/get_metadata` response exposes starters as `conversationStarters`. * With `cache_conversation_starters=True`, the first plain-text user message can replay a saved reply when it exactly matches a configured starter. Streaming the cached reply includes events for text, tool calls, reasoning, and handoffs. If you change key agent settings (like instructions, tools, or model), the cache for first-turn responses is rebuilt. Per-run overrides like `additional_instructions`, `context_override`, or `hooks_override` skip replay and call the LLM. Cache files live under `AGENCY_SWARM_CHATS_DIR` (defaults to `.agency_swarm`) in `starter_cache/`. In production, point `AGENCY_SWARM_CHATS_DIR` at persistent storage to keep instant replies across restarts. See also: [Agent Overview](/core-framework/agents/overview), [FastAPI Integration](/additional-features/fastapi-integration). ### Output Validation Use `output_guardrails` on the `Agent` to validate outputs. See the detailed guide: [Guardrails](/additional-features/guardrails/overview). ### Few‑Shot Examples You can include few‑shot examples in `instructions` as plain text or pass message history to `get_response` / `get_response_stream`. ```python theme={null} from agency_swarm import Agent agent = Agent(name="MyAgent", instructions="You are a helpful assistant.") examples = [ {"role": "user", "content": "Hi!"}, {"role": "assistant", "content": "Hello!"}, ] new_message = {"role": "user", "content": "Can you help me write a short summary?"} response = await agent.get_response(examples + [new_message]) ``` See also: [Few‑Shot Examples](/additional-features/few-shot-examples). # Built-in Tools Source: https://agency-swarm.ai/core-framework/agents/built-in-tools Learn how to use built-in tools in Agency Swarm. In the latest version, Agency Swarm leverages tools from the [Agents SDK](https://openai.github.io/openai-agents-python/ref/tool/). This provides access to a comprehensive set of production-ready tools maintained by OpenAI. ## Available Tools The agents SDK provides the following built-in tools: ### Hosted Tools * **`WebSearchTool`** - Lets an agent search the web * **`FileSearchTool`** - Allows retrieving information from your OpenAI Vector Stores * **`ComputerTool`** - Allows automating computer use tasks * **`CodeInterpreterTool`** - Lets the LLM execute code in a sandboxed environment * **`ImageGenerationTool`** - Generates images from a prompt * **`LocalShellTool`** - Runs shell commands on your machine ### Function Tools * **`FunctionTool`** - Custom function-based tools using the `@function_tool` decorator ### MCP (Model Context Protocol) Tools * **`HostedMCPTool`** - Exposes a remote MCP server's tools to the model **When to use each tool:** * **Web Search**: Real-time information retrieval, current events, up-to-date data * **File Search**: Enriching agent knowledge, reducing hallucinations, querying documents * **Computer Tool**: Automating computer use tasks, UI interactions, testing applications * **Code Interpreter**: Data analysis, calculations, executing code in a sandboxed environment * **Image Generation**: Creating visual content, illustrations, design assets from prompts * **Local Shell**: System administration, file operations, running shell commands * **Function Tool**: Creating custom tools with specific business logic using Python functions * **Hosted MCP Tool**: Accessing tools from remote Model Context Protocol servers ### WebSearchTool Sources (all checked URLs) ```python theme={null} from agency_swarm import Agent, WebSearchTool agent = Agent( name="ResearchAgent", instructions="Search the web and summarize the best sources.", tools=[WebSearchTool()], ) ``` Use `include_web_search_sources=False` if you do not want source URLs in web-search tool calls. For detailed documentation and additional configuration options, refer to the [agents SDK tool documentation](https://openai.github.io/openai-agents-python/ref/tool/). # Overview Source: https://agency-swarm.ai/core-framework/agents/overview Understanding Agents in Agency Swarm. Agents are the core building blocks of the Agency Swarm framework. Each agent is specialized for a specific role and is designed to perform a specific set of processes within an agency. ## Key Characteristics of Agents Agents can decide the next best action to achieve a goal autonomously within the guardrails. Agents sense the environment, interpret observations, and self-correct based on feedback. Agents can take initiative (monitor, plan, act) and surprise you with the results, or escalate when needed. ## Defining AI agents **An AI agent is an autonomous, goal-driven system that perceives its environment, dynamically uses tools and APIs to take actions, adapts proactively within guardrails, and can collaborate with other agents or humans.** Now, let's breakdown this definition: * **Autonomous** - Agents define their own execution flow independently without hardcoded logic, unlike traditional workflows * **Goal-driven** - Agents are focused on outcomes, rather than on invididual steps * **Perceives environment** - Agents observe the real-world and use the feedback to validate its own actions (e.g., a coding agent testing its code) * **Dynamic tool use** - Agents generate value through actions rather than just responses (most critical characteristic) * **Adapts within guardrails** - Agents balance autonomy with safety constraints for enterprise reliability * **Collaboration** - Agents can work seamlessly with other agents or humans in multi-agent systems ## Agent Parameters In agency swarm, to create an agent, you need to instantiate the `Agent` class. | Name | Parameter | Description | | - | - | - | | Name *(required)* | `name` | The name of the agent. | | Instructions *(optional)* | `instructions` | The instructions for the agent. Will be used as the "system prompt" when this agent is invoked. Can be a string or a function that dynamically generates instructions. Default: `None` | | Description *(optional)* | `description` | A description of the agent's role or purpose, used to convey agent's role to other agents. Default: `None` | | Model *(optional)* | `model` | The model implementation to use when invoking the LLM. Omitting it or passing `model=None` selects Agency Swarm's `gpt-6-luna` default. To use a different supported model, pass its name or model object explicitly. | | Model Settings *(optional)* | `model_settings` | Configures model-specific tuning parameters (e.g. temperature, top\_p). See [ModelSettings documentation](https://openai.github.io/openai-agents-python/ref/model_settings/) for details. Agency Swarm applies the model-specific SDK defaults, then fills unset fields with `truncation="auto"` and `include_usage=True`. The default `gpt-6-luna` reasoning effort is `"medium"`; it does not accept `temperature` or `top_p`, so remove them or pass a model that accepts them. | | Tools *(optional)* | `tools` | A list of tools that the agent can use. Default: `[]` | | Tools Folder *(optional)* | `tools_folder` | Path to a directory containing tool definitions. Tools are automatically discovered and loaded from this directory. Supports both BaseTool subclasses and modern FunctionTool instances. Default: `None` | | Files Folder *(optional)* | `files_folder` | Path to a local folder for managing files associated with this agent. If the folder name follows the pattern `*_vs_`, files uploaded via `upload_file` will also be added to the specified OpenAI Vector Store, and a `FileSearchTool` will be automatically added. Default: `None` | | MCP Servers *(optional)* | `mcp_servers` | A list of Model Context Protocol servers that the agent can use. Non-OAuth servers are converted into tools on run. OAuth servers are deferred behind `authenticate_mcp_server(server_name)` so auth is only triggered when the model explicitly requests it. Default: `[]` | | Input Guardrails *(optional)* | `input_guardrails` | A list of checks that run in parallel to the agent's execution, before generating a response. Default: `[]` | | Output Guardrails *(optional)* | `output_guardrails` | A list of checks that run on the final output of the agent, after generating a response. Default: `[]` | | Output Type *(optional)* | `output_type` | The type of the output object. If not provided, the output will be `str`. In most cases, you should pass a regular Python type (e.g. a dataclass, Pydantic model, TypedDict, etc). Default: `None` | | Name | Parameter | Description | | - | - | - | | MCP Config *(optional)* | `mcp_config` | Configuration for MCP servers. Default: `MCPConfig()` | | API headers *(optional)*
API params *(optional)* | `api_headers`

`api_params` | Additional parameters to include into tools converted from OpenAPI schemas. Default: `None` | | Schemas Folder *(optional)* | `schemas_folder` | Path to a directory containing openapi schema files in .json format. Schemas are automatically converted into FunctionTools. Default: `None` | | Validation Attempts *(optional)* | `validation_attempts` | Number of retries when an output guardrail trips. Default: `1` | | Raise Input Guardrail Error *(optional)* | `raise_input_guardrail_error` | If set to `True`, input guardrail errors raise an exception. If set to `False`, the guardrail message is returned as the agent's response. Default: `False` | | System Reminders *(optional)* | `system_reminders` | Transient reminders shown to the model at supported triggers. A string runs on every model call of each top-level user turn; use `EveryNToolCalls(...)` for within-run tool checkpoints. Default: `None` | | Handoff Reminder *(optional)* | `handoff_reminder` | Replaces the default handoff reminder system message with a given string. Default: "Transfer completed. You are \[recipient\_agent\_name]. Please continue the task." | | Include Search Results *(optional)* | `include_search_results` | Include search results in FileSearchTool output for citation extraction. Default: `False` | | Include Web Search Sources *(optional)* | `include_web_search_sources` | Include source URLs from WebSearchTool calls. Default: `True` | | Conversation Starters *(optional)* | `conversation_starters` | List of short user prompts for UIs. Each starter must be a non-empty string. Default: `None` | | Quick Replies *(optional)* | `quick_replies` | First-turn user phrases used for cached responses. These phrases are not shown as `conversation_starters` in the UI. Each value must be a non-empty string. Default: `None`. | | Starter Cache *(optional)* | `cache_conversation_starters` | Enables caching for `conversation_starters`. When `True`, a first-turn message that matches a `conversation_starter` can return a cached response instead of calling the model. This setting does not affect `quick_replies`. See [Advanced Configuration](/core-framework/agents/advanced-configuration#conversation-starters-cache). Default: `False`. |
To see a full list of agent parameters, refer to [OpenAI documentation](https://openai.github.io/openai-agents-python/ref/agent/#agents.agent.Agent). Please note that agent handoff parameters are not supported. To enable handoffs, use `communication_flows` with the `Handoff` tool class as [shown here](/additional-features/custom-communication-flows/overview) Agency Swarm runs the default `gpt-6-luna` model with reasoning effort set to `"medium"`. To use a different reasoning effort, pass `reasoning=Reasoning(effort="low")` (or another supported effort) inside `ModelSettings`. ## Agent Template Create a new agent by instantiating the Agent class: ```python theme={null} from agency_swarm import Agent, ModelSettings, Reasoning example_agent = Agent( name="agent_name", description="agent_description", model="gpt-6-luna", instructions="./instructions.md", files_folder="./files", tools_folder="./tools", tools=[], model_settings=ModelSettings( reasoning=Reasoning(effort="medium"), ), ) ``` You can adjust the parameters to fit the agent to your use case. # OpenClawAgent Source: https://agency-swarm.ai/core-framework/third-party-agents/openclaw-agent Use an OpenClaw worker inside an Agency Swarm agency. `OpenClawAgent` gives you a clean way to plug an OpenClaw worker into an Agency Swarm agency. Use it when Agency Swarm should stay in charge of delegation while OpenClaw handles one specialized branch. ## Start With One Import ```python theme={null} from agency_swarm.agents import OpenClawAgent ``` ## Use It In An Agency ```python theme={null} from agency_swarm import Agency from agency_swarm.agents import Agent, OpenClawAgent coordinator = Agent( name="Coordinator", description="Routes work to the right specialist.", instructions="Delegate OpenClaw-specific tasks to OpenClawWorker.", model="gpt-6-luna", ) openclaw_worker = OpenClawAgent( name="OpenClawWorker", description="Handles OpenClaw-native work.", instructions="Act as an OpenClaw specialist worker.", ) agency = Agency( coordinator, communication_flows=[(coordinator, openclaw_worker)], ) ``` This example assumes `OpenClawAgent` can already reach a running OpenClaw endpoint. By default it calls the local `/openclaw/v1` proxy, so either mount that proxy in the same FastAPI app or point the agent at a custom `base_url`. ## Choose How To Reach OpenClaw ```python theme={null} from agency_swarm.agents import OpenClawAgent openclaw_worker = OpenClawAgent( name="OpenClawWorker", description="OpenClaw specialist", instructions="Handle the delegated OpenClaw work and return the result.", ) ``` This uses the local `/openclaw/v1` proxy in the same app. Before you use this path, mount that proxy in the same app with `attach_openclaw_to_fastapi(app)`. Install the FastAPI extras for that path: `pip install "agency-swarm[fastapi]"`. That mounted runtime also needs a working `openclaw` gateway command and a compatible Node installation. If `OPENCLAW_PROXY_PORT` is set, `OpenClawAgent` uses that port. Otherwise it falls back to `PORT`, then `8000`. ```python theme={null} from agency_swarm.agents import OpenClawAgent openclaw_worker = OpenClawAgent( name="OpenClawWorker", description="OpenClaw specialist", instructions="Handle the delegated OpenClaw work and return the result.", host="127.0.0.1", port=18080, api_path="/openclaw/v1", ) ``` Use this when you run more than one OpenClaw-backed worker. ```python theme={null} from agency_swarm.agents import OpenClawAgent openclaw_worker = OpenClawAgent( name="OpenClawWorker", description="OpenClaw specialist", instructions="Handle the delegated OpenClaw work and return the result.", base_url="http://127.0.0.1:18789/v1", api_key="your-openclaw-token", ) ``` Use this when you are talking to a raw OpenClaw gateway that serves `/v1` directly. If the remote server is another Agency Swarm app using this integration, use its `/openclaw/v1` path instead of `/v1`. When that remote server is a delegated worker, start it with `OPENCLAW_TOOL_MODE=worker`. If it is plain OpenClaw outside Agency Swarm, disable its competing delegation paths in that runtime instead of copying this env var blindly. Raw `/v1` gateways default to the upstream provider model, not `openclaw:main`. If that remote server expects a different model id, pass it with `model="openclaw:custom"` so this agent matches the target runtime. If you point to another Agency Swarm worker at `/openclaw/v1`, pass that worker's `api_key=` explicitly unless you are using the same in-process proxy. ## Collaboration Pattern Use `OpenClawAgent` as a worker. Do not use it as the top-level delegator. Why: * Agency Swarm owns the recursive collaboration loop * OpenClaw has its own native messaging and session tools * keeping Agency Swarm on top preserves clean run hierarchy in the frontend When a normal Agency Swarm agent delegates to `OpenClawAgent`, the streamed events already carry the same `parent_run_id`, `agent_run_id`, `agent`, and `callerAgent` fields the current frontend uses for nested runs. ## Tools And Limits `OpenClawAgent` is not the same thing as giving OpenClaw your normal Agency Swarm Python tools. Today, the clean extension paths for OpenClaw itself are: * OpenClaw plugin tools via `api.registerTool(...)` * MCP servers exposed to OpenClaw * OpenClaw tool policy config such as allowlists and deny lists Use plain Agency Swarm tools on your normal orchestrator agent. Use OpenClaw plugins or MCP when you need to extend OpenClaw itself. If your Agency Swarm app should also start the OpenClaw runtime, attach the proxy to the same FastAPI app: ```python theme={null} from agency_swarm import Agency from agency_swarm.agents import Agent, OpenClawAgent from agency_swarm.integrations.fastapi import run_fastapi from agency_swarm.integrations.openclaw import attach_openclaw_to_fastapi def create_agency(load_threads_callback=None): coordinator = Agent( name="Coordinator", description="Routes work to the OpenClaw worker.", instructions="Delegate OpenClaw-specific work to OpenClawWorker.", model="gpt-6-luna", ) openclaw_worker = OpenClawAgent( name="OpenClawWorker", description="OpenClaw specialist", instructions="Handle the delegated OpenClaw work and return the result.", ) return Agency( coordinator, communication_flows=[(coordinator, openclaw_worker)], load_threads_callback=load_threads_callback, ) app = run_fastapi( agencies={"support": create_agency}, app_token_env="APP_TOKEN", return_app=True, ) if app is None: raise RuntimeError("FastAPI app failed to start") attach_openclaw_to_fastapi(app) ``` When that runtime is meant to be a delegated worker, start the app with: ```bash theme={null} OPENCLAW_TOOL_MODE=worker python main.py ``` That worker mode disables the OpenClaw messaging paths that compete with Agency Swarm delegation. `OpenClawAgent` can receive delegated work, but it should not be the sender in Agency Swarm communication flows. If you need deeper tool customization inside OpenClaw, use OpenClaw plugins or MCP instead of trying to pass ordinary Agency Swarm Python tools through the wrapper. # Third-Party Agents Source: https://agency-swarm.ai/core-framework/third-party-agents/overview Import external agent runtimes into Agency Swarm. Agency Swarm can import agents that run outside the normal Agency Swarm Python stack. Use this section when you want Agency Swarm to stay in charge of orchestration, but hand one part of the work to another agent runtime. Use OpenClaw as a delegated worker inside an Agency Swarm agency. # Built-in Tools Source: https://agency-swarm.ai/core-framework/tools/built-in-tools Ready-to-use tools that ship with Agency Swarm framework. Agency Swarm includes a set of built-in tools that provide common functionality for your agents. These tools are production-ready and can be used immediately without additional configuration. ## Quick Overview Execute Python code in an isolated environment with persistent state. Run shell commands in a persistent terminal session. Load and process local images and PDF files. ## Tool Details Executes Python code in an isolated IPython environment with persistent state between calls. ### Use Cases **Data Analysis** Analyze and process datasets **Calculations** Perform mathematical and statistical operations **Testing** Test code snippets in a safe environment **Scripts** Run Python scripts and automation ### Usage Example ```python theme={null} from agency_swarm import Agent from agency_swarm.tools import IPythonInterpreter data_analyst = Agent( name="Data Analyst", description="Analyzes data using Python", instructions="./instructions.md", tools=[IPythonInterpreter] ) ``` Similar to the Agents SDK `LocalShellTool`, but works with any model. Executes shell commands in a persistent terminal session, maintaining state across multiple commands. ### Use Cases **CLI Commands** Execute command-line operations **File Operations** Navigate and manage file systems **Git Operations** Version control and repository management **Build Operations** Run build scripts and compile code ### Usage Example ```python theme={null} from agency_swarm import Agent from agency_swarm.tools import PersistentShellTool devops_agent = Agent( name="DevOps Agent", description="Manages deployment and infrastructure", instructions="./instructions.md", tools=[PersistentShellTool] ) ``` Loads local files and returns them in the appropriate format for the agent to view. Only supports images and PDF files. For other file types, use the `FileSearch` and `CodeInterpreter` tools from the Agents SDK. ### Use Cases **Image Processing** Load and analyze image files **PDF Reading** Extract and process PDF content **User Files** Handle user-uploaded file attachments **File Analysis** Inspect and analyze local files ### Usage Example ```python theme={null} from agency_swarm import Agent from agency_swarm.tools import LoadFileAttachment file_processor = Agent( name="File Processor", description="Processes and analyzes local files", instructions="./instructions.md", tools=[LoadFileAttachment] ) ``` The agent can use both absolute paths and paths relative to the current working directory. Make sure to instruct your agent accordingly on how to use this tool. *** ## Next Steps Build your own tools from scratch Convert APIs into tools Use Model Context Protocol tools # Best Practices & Tips Source: https://agency-swarm.ai/core-framework/tools/custom-tools/best-practices Best practices and real-world examples for Agency Swarm tools. Although the tool interface is straightforward and simple to use, there are actually quite a few practices and tricks that you can use to get significantly better results. ### Provide Hints for the Agent Based on your tool's logic, you can provide hints for the agent in tool output on what to do next. ```python theme={null} from agency_swarm import MasterContext, RunContextWrapper, function_tool from pydantic import BaseModel, Field class QueryDatabaseArgs(BaseModel): question: str = Field(..., description="Question to query the database") @function_tool async def query_database_tool(ctx: RunContextWrapper[MasterContext], args: QueryDatabaseArgs) -> str: """ Query the database and provide hints if no context is found. """ # query your database here context = query_database(args.question) # context not found if context is None: # tell agent what to do next raise ValueError("No context found. Please propose to the user to change the topic.") else: # return the context to the agent return context def query_database(question: str): # Your database query logic here pass ``` ### Use Shared State to Control the Tool Flow Use agency context (previously shared state) to validate previous actions taken by this or other agents, before allowing it to proceed with the next action. ```python theme={null} from agency_swarm import MasterContext, RunContextWrapper, function_tool from pydantic import BaseModel, Field class Action2Args(BaseModel): input: str = Field(..., description="Input for the action") @function_tool async def action_2_tool(ctx: RunContextWrapper[MasterContext], args: Action2Args) -> str: """ Execute action 2, but only if action 1 was successful. """ # Access shared context to check previous action action_1_result = ctx.context.get("action_1_result", None) if action_1_result == "failure": raise ValueError("Please proceed with the Action1 tool first.") else: return "Success. The action has been taken." ``` ### Use Special Types Restrict the agent to only use specific values for a field, instead of letting it wander by itself. ```python theme={null} from typing import Literal from agency_swarm import MasterContext, RunContextWrapper, function_tool from pydantic import BaseModel, EmailStr, Field class RunCommandArgs(BaseModel): command: Literal["start", "stop"] = Field(..., description="Command to execute: 'start' or 'stop'.") @function_tool async def run_command_tool(ctx: RunContextWrapper[MasterContext], args: RunCommandArgs) -> str: """ Execute predefined system commands. """ if args.command == "start": # Start command logic return "System started" elif args.command == "stop": # Stop command logic return "System stopped" else: raise ValueError("Invalid command") # Example with EmailStr class EmailSenderArgs(BaseModel): recipient: EmailStr = Field(..., description="Email recipient's address.") subject: str = Field(..., description="Email subject") body: str = Field(..., description="Email body") @function_tool async def email_sender_tool(ctx: RunContextWrapper[MasterContext], args: EmailSenderArgs) -> str: """ Send email to specified recipient. """ # Email sending logic here return f"Email sent to {args.recipient}" ``` ### Combine Multiple Methods Combine multiple methods to make your execution flow more readable. ```python theme={null} from agency_swarm import MasterContext, RunContextWrapper, function_tool from pydantic import BaseModel, Field class CompositeToolArgs(BaseModel): input_data: str = Field(..., description="Input data for the composite operation.") @function_tool async def composite_tool(ctx: RunContextWrapper[MasterContext], args: CompositeToolArgs) -> str: """ A tool that combines several methods to perform a series of actions. """ # Step 1: Process data processed_data = await process_data(args.input_data) # Step 2: Analyze results analysis = await analyze_results(processed_data) # Step 3: Format output output = await format_output(analysis) return output async def process_data(data: str) -> str: # Implement data processing logic return f"Processed: {data}" async def analyze_results(data: str) -> str: # Implement analysis logic return f"Analysis of: {data}" async def format_output(data: str) -> str: # Implement output formatting return f"Formatted: {data}" ``` ### Include a Test Case Include test cases at the bottom of each tool file. ```python theme={null} if __name__ == "__main__": import asyncio import json from agency_swarm import MasterContext, RunContextWrapper async def test_email_sender(): # Test the email sender tool ctx = MasterContext(user_context={}, thread_manager=None, agents={}) run_ctx = RunContextWrapper(context=ctx) args = EmailSenderArgs( recipient="user@example.com", subject="Project Update", body="The project is on track." ) args_json = {"args": args.model_dump()} result = await email_sender_tool.on_invoke_tool(run_ctx, json.dumps(args_json)) assert "Email sent" in result print("Test passed!") asyncio.run(test_email_sender()) ``` ## Next Steps We highly recommend you explore the resources provided in the [Pydantic is all you need](/core-framework/tools/custom-tools/pydantic-is-all-you-need) section. # Advanced Tool Configuration Source: https://agency-swarm.ai/core-framework/tools/custom-tools/configuration Advanced features and patterns for Agency Swarm tools. Besides standard Pydantic features, you can also use a special `ToolConfig` class to customize tool behavior within the framework: ## Available `ToolConfig` Parameters The following parameters are supported, with version compatibility noted: | Name | Type | Description | When to Use | Default Value | | - | - | - | - | - | | `one_call_at_a_time` | `bool` | Prevents concurrent execution for a specific tool. If you want to adjust parallel tool calling for all tools, prefer configuring `model_settings=ModelSettings(parallel_tool_calls=...)`. Use this per-tool setting when you need strict sequencing. | Use for database operations, API calls with rate limits, or actions that depend on previous results. | `False` | | `strict` | `bool` | Enables strict mode, which ensures the agent will always provide **perfect** tool inputs that 100% match your schema. Has limitations. See [OpenAI Docs](https://platform.openai.com/docs/guides/structured-outputs#supported-schemas). | Use for mission-critical tools or tools that have nested Pydantic model schemas. | `False` | ## Usage To use one of the available parameters, simply add a `class ToolConfig` block to your tool class: ```python theme={null} class MyCustomTool(BaseTool): # ... class ToolConfig: one_call_at_a_time = True strict = False async def run(self): # ... ``` # Multimodal Tool Outputs Source: https://agency-swarm.ai/core-framework/tools/custom-tools/multimodal-outputs Return images and files from your tools. ## What This Feature Unlocks Returning images and files from the tools enables real agentic feedback loops on completely new modalities. For example, instead of dumping all the data into an agent, and hoping for the best, you can generate a visualization or analyze PDF reports, and allow the agent to provide insights based on that output. Just like a real data analyst. This saves your context window and unlocks autonomous agentic workflows for a lot of new use cases: ## New Use Cases Agents can check websites autonomously and iterate until all elements are properly positioned, enabling them to tackle complex projects without manual screenshot feedback. Provide brand guidelines, logos, and messaging, then let agents iterate on image and video generation (including Sora 2) until outputs fully match your expectations. Build agents that help visually impaired individuals navigate websites or create customer support agents that see the user's current webpage for better assistance. Generate visual graphs and analyze PDF reports, then let agents provide insights based on these outputs without overloading the context window. ## Output Formats ### Images (PNG, JPG) To return an image from a tool, you can either: 1. Use the `ToolOutputImage` class. 2. Return a dict with the `type` set to `"image"` and either `image_url` (URL or data URL) or `file_id`. 3. Use our convenience `tool_output_image_from_path` function. ```python theme={null} from agency_swarm import BaseTool, ToolOutputImage, ToolOutputImageDict from agency_swarm.tools.utils import tool_output_image_from_path from pydantic import Field class FetchGalleryImage(BaseTool): """Return a static gallery image.""" detail: str = Field(default="auto", description="Level of detail") def run(self) -> ToolOutputImage: return ToolOutputImage( image_url="https://upload.wikimedia.org/wikipedia/commons/0/0c/GoldenGateBridge-001.jpg", detail=self.detail, ) class FetchGalleryImageDict(BaseTool): """Dict variant of the same image output.""" detail: str = Field(default="auto", description="Level of detail") def run(self) -> ToolOutputImageDict: return { "type": "image", "image_url": "https://upload.wikimedia.org/wikipedia/commons/0/0c/GoldenGateBridge-001.jpg", "detail": self.detail, } class FetchLocalImage(BaseTool): """Load an image from disk using the helper.""" path: str = Field(default="examples/data/landscape_scene.png", description="Image to publish") def run(self) -> ToolOutputImage: return tool_output_image_from_path(self.path, detail="auto") ``` ### Files (PDF) Similarly to return a file from a tool: ```python theme={null} from agency_swarm import BaseTool, ToolOutputFileContent from agency_swarm.tools.utils import tool_output_file_from_path, tool_output_file_from_url from pydantic import Field class FetchReferenceReport(BaseTool): """Return a reference PDF hosted remotely.""" source_url: str = Field( default="https://raw.githubusercontent.com/VRSEN/agency-swarm/main/examples/data/sample_report.pdf", description="Remote file to share", ) def run(self) -> ToolOutputFileContent: return ToolOutputFileContent(file_url=self.source_url) class FetchLocalReport(BaseTool): """Return a report stored on disk.""" path: str = Field(default="examples/data/sample_report.pdf", description="Local file path") def run(self) -> ToolOutputFileContent: return tool_output_file_from_path(self.path) class FetchRemoteReport(BaseTool): """Return a remote file using the helper.""" archive_url: str = Field(default="https://example.com/document.pdf", description="File to expose") def run(self) -> ToolOutputFileContent: return tool_output_file_from_url(self.archive_url) ``` When you choose `file_data`, include `filename` to hint a download name; URL-based outputs rely on the remote server metadata instead. `tool_output_file_from_path` only supports PDF files. **Need to load local files without custom logic?** Use the built-in [`LoadFileAttachment`](/core-framework/tools/built-in-tools#loadfileattachment) tool instead of creating a custom tool. It handles both images and PDFs and uses these same utility functions under the hood. ### Combining Multiple Outputs Return multiple outputs by returning a list from `run`. ```python theme={null} from agency_swarm import BaseTool, ToolOutputFileContent, ToolOutputImage, ToolOutputText class PrepareShowcase(BaseTool): """Return rich media and a short description.""" teaser_a: str = "https://example.com/teaser-a.png" teaser_b: str = "https://example.com/teaser-b.png" report_id: str = "file-report-123" def run(self) -> list: return [ ToolOutputImage(image_url=self.teaser_a), ToolOutputImage(image_url=self.teaser_b), ToolOutputText(text="Gallery updated: Teaser A and Teaser B now live."), ToolOutputFileContent(file_id=self.report_id), ] ``` ## Complete Example (Chart generation tool) Here's a complete example using `BaseTool`: ```python theme={null} from agency_swarm import Agent, BaseTool, ToolOutputImage from pydantic import Field import base64 import matplotlib.pyplot as plt import io class GenerateChartTool(BaseTool): """Generate a bar chart from data.""" data: list[float] = Field(..., description="Data points for the chart") labels: list[str] = Field(..., description="Labels for each data point") def run(self) -> ToolOutputImage: """Generate and return the chart as a base64-encoded image.""" # Create the chart fig, ax = plt.subplots() ax.bar(self.labels, self.data) # Convert to base64 buf = io.BytesIO() plt.savefig(buf, format='png') buf.seek(0) image_base64 = base64.b64encode(buf.read()).decode('utf-8') plt.close() # Return in multimodal format return ToolOutputImage(image_url=f"data:image/png;base64,{image_base64}") # Create an agent with the tool agent = Agent( name="DataViz", instructions="You generate charts and visualizations for data analysis.", tools=[GenerateChartTool] ) ``` `function_tool` decorators and `BaseTool` classes both support multimodal outputs in the exact same way. ```python theme={null} from agency_swarm import ToolOutputImage, function_tool @function_tool def fetch_gallery_image() -> ToolOutputImage: return ToolOutputImage( image_url="https://upload.wikimedia.org/wikipedia/commons/0/0c/GoldenGateBridge-001.jpg", detail="auto", ) ``` ## Tips & Best Practices * Base64-encoded images can be large. Use file references for large content. * Compress screenshots and other visuals before returning them to cut token usage without sacrificing clarity. * Include the image names in your textual response whenever you return more than one image so the agent can reference them unambiguously. ## Real Examples * \[TBD: Include repo from YouTube video] * [`examples/multimodal_outputs.py`](https://github.com/VRSEN/agency-swarm/blob/main/examples/multimodal_outputs.py) # Pydantic is All You Need Source: https://agency-swarm.ai/core-framework/tools/custom-tools/pydantic-is-all-you-need How Pydantic solved AI agent reliability. The idea of using Pydantic to validate tool calls and responses is not new. It was popularized by Jason Liu in his library called [Instructor](https://github.com/instructor-ai/instructor). To really understand why it's such a game changer, we recommend watching this video: ``` Here's an example of the **Custom GPT's** response based on this input: custom-gpt-screenshot.png ### API For web api, simply use `additionalInstructions` in the `get_response` POST endpoint. For more details, see: [API reference](/platform/integrations/api/get-response) # How Credits Work Source: https://agency-swarm.ai/platform/how-credits-work Everything you need to know about credits. ## Understanding Credits Credits are your usage balance on the platform. They power everything your agents do—from quick replies to long-running, multi-step workflows in sandboxes. Instead of charging per request or per feature, we use credits to provide transparent, usage-based billing. The more complex the task, the more credits it uses. Simple interactions cost less; heavy compute and long-running agents cost more. ### What Consumes Credits Credit usage depends on task complexity and how long your sandbox runs. | Resource | Description | | - | - | | **AI Tokens** | Processing requests through LLMs, image generation, and other AI models | | **Compute** | Running agents in your custom sandboxes and execution environments | | **Agent Builds** | Creating, configuring, and deploying new agents | | **File Storage** | Storing and managing files created during your tasks | | **Web Searches** | Searching the internet for information needed to complete tasks | | **Third-Party Services** | Accessing external APIs and integrated services that extend your agent's capabilities | * After a task completes, **AI token usage stops**, but **compute** can continue until your sandbox stops (timeout). * **Storage and downloads** can still use a small number of credits while agents are idle. * If you use **your own API keys**, we don’t deduct credits for AI tokens or other third-party services. ### Credit Types Credits fall into three categories. They are deducted in a specific order to maximize value: Use-it-or-lose-it credits that reset to 25 every day. Your main allocation, refreshed each billing cycle. Extra credits you can purchase anytime that never expire. | Credit type | Who gets them | Amount | Refresh | Rollover | Notes | | - | - | - | - | - | - | | **Daily** | All users (Free and Pro) | 25 credits per day | Every 24 hours at midnight UTC | No — unused daily credits reset and do not accumulate | Use-it-or-lose-it. Resets to 25 at midnight UTC. | | **Monthly** | Pro users only | 2,000 credits per month | At the start of each billing cycle | No — unused monthly credits do not carry over | Main plan allocation. Refreshes each billing cycle. | | **Refill** | Anyone who purchases them | Based on purchase | One-time purchase | Yes — refill credits never expire | One-time purchase. Never expires. | ### Credit Usage Priority When you run a task, credits are consumed in this order: 1. **Daily credits** (used first) 2. **Monthly credits** (used second) 3. **Refill credits** (used last) This ensures expiring credits are always used before your permanent refill credits. We prioritize expiring credits so you get maximum value from every plan. Refill credits stay available as your backup. ## Monitoring Your Usage Track credit consumption in [**Settings → Billing**](https://agencii.ai/settings/?tab=billing) to review: * **Current balance:** remaining daily, monthly, and refill credits * **Usage by agency:** credit consumption per agency to highlight the most resource-intensive builds ## Credit Refunds If a task fails because of a system error on our side, we automatically refund the credits used for that task. Refunds are not issued for tasks that fail due to user-provided instructions, external service issues, or reaching task limits. Provide clear, detailed instructions to minimize unnecessary usage. ## Tips for Optimising Credit Usage Give clear, detailed requests so agents complete tasks efficiently. Group similar tasks together to reduce repeated setup work. Review intermediate results on complex workflows before committing additional credits. ## FAQ Daily credits reset every 24 hours at midnight UTC. Monthly credits refresh at the start of each billing cycle, on the same date you started your subscription. Yes. Pro users can purchase refill credits at any time, and those credits never expire. You'll receive notifications when your balance is low. You can wait for the daily refresh, upgrade to Pro for monthly credits, or purchase refill credits on PRO plan. Daily and monthly credits do not roll over. Refill credits remain in your account until you use them. # Create agency upload Source: https://agency-swarm.ai/platform/integrations/api/create-agency-upload /openapi.json post /create_agency_upload Signs a 15-minute, size-limited upload form for an API integration with persistent agency storage. Call this from your server after checking which app member owns the file. POST multipart/form-data to uploadUrl with every uploadFields entry followed by the file field. Uploads are limited to 20 MiB. Pass resource as a sandboxFiles path when starting a completion. # Create new chat Source: https://agency-swarm.ai/platform/integrations/api/create-new-chat /openapi.json post /create_new_chat Creates a new chat instance for a user based on a provided API integration. Requires a valid platform token in the headers for authentication. Ensure the apiIntegrationId corresponds to an existing integration. # Get API consumer allowance Source: https://agency-swarm.ai/platform/integrations/api/get-api-consumer-allowance /openapi.json post /get_api_consumer_allowance Returns the live read model for the current UTC usage period and lazily rolls an expired period forward. # Get response Source: https://agency-swarm.ai/platform/integrations/api/get-response /openapi.json post /get_response Processes a message using the specified API integration and returns a response from the agent. Requires a valid platform token. Ensure the apiIntegrationId is valid. Supports continuing existing chats via chatId or aliasChatId and attaching files with tools. # Register API consumer Source: https://agency-swarm.ai/platform/integrations/api/register-api-consumer /openapi.json post /register_api_consumer Idempotently registers one application member. Allowance values are controlled by the integration owner and cannot be supplied by this route. # Set API consumer status Source: https://agency-swarm.ai/platform/integrations/api/set-api-consumer-status /openapi.json post /set_api_consumer_status Enables or disables AI access for a registered consumer. This route cannot change monetary limits or renewal dates. # Stream API v2 completion Source: https://agency-swarm.ai/platform/integrations/api/stream-api-v2-completion /openapi.json post /get_completion_v2 Starts an SSE agent run. When allowances are enabled, consumerId and usageRequestId are required. An in-progress response may finish above the limit; the next request is rejected. Every request must use the integration owner's API key. Errors with X-Agent-Run-Admitted: false were rejected before reserving a run. If that header is absent after an interruption, check chat status using the same usageRequestId before retrying. A failed response stays in chat history. Its attachments are not sent again in later turns; attach them again to retry. Other messages and their successful attachments remain available. # Members allowance Source: https://agency-swarm.ai/platform/integrations/member-allowances Set a monthly AI usage limit for each member of an app built with the Agencii API. ## Give every member room to use your agents If you build an app around your agents, you may want each member to have their own monthly AI allowance. For example, a course platform could give every student access to a coaching agent while keeping one student's usage from consuming the budget for everyone else. **Members allowance** lets you set that limit in Agencii. Your app can show a member's remaining allowance, but its users cannot change the limit themselves. Open your **API integration**, select **Members allowance**, turn on limits, and choose an amount. The default applies to every member registered through that integration. Your app [registers each person](/platform/integrations/api/register-api-consumer) with a stable user ID. Agencii returns a `consumerId` that your app uses for their agent requests. Registering the same person again keeps their existing allowance and usage. Include the `consumerId` and a unique `usageRequestId` when you [stream an API v2 response](/platform/integrations/api/stream-api-v2-completion). Agencii checks the allowance before starting the run and returns HTTP `429` if the member has reached their limit. The members table shows each person's AI usage, renewal date, and access status. Your app can [read a member's current allowance](/platform/integrations/api/get-api-consumer-allowance). You can change one member's allowance or [pause their AI access](/platform/integrations/api/set-api-consumer-status) without changing the default for everyone else. When a member reaches their limit, Agencii blocks their **next** agent request. A response already in progress can finish, so usage may end slightly above the limit. Their allowance renews each month on the date they first registered, at 00:00 UTC. For someone who joined on the 29th, 30th, or 31st, renewal falls on the last day of shorter months. Unused allowance does not roll over. Members allowance currently tracks AI model usage for API v2 agent responses. It does not include sandbox compute, uploads, or file storage. It is separate from the credits used to pay for your Agencii account. ## Example: a course with AI coaches Suppose your course has 500 students and several agents. Set a \$20 monthly default for your API integration. Every registered student gets their own allowance, even when they use different agents. If one student needs extra support, edit that student's limit in the members table. Your course app can read their remaining allowance and explain when it renews. To connect your app, see the [API integration guide](/platform/integrations/web-api). Templates for building apps like this are coming soon. # n8n Source: https://agency-swarm.ai/platform/integrations/n8n-integration Connect your Agencii agents to n8n workflows using the Agencii community node. ## Feature Overview n8n is a flexible workflow automation platform that lets you connect dozens of services in visual flows. The Agencii **n8n community node** (`n8n-nodes-agencii`) connects your agents to these workflows so your agencies can receive tasks, run tools, and send back answers directly inside n8n. ## Prerequisites * **Agencii Platform account** with at least one deployed agency and agent. * **Platform API Key** – available under **Settings → API Keys** in the Agencii dashboard. * **n8n instance** with permissions to install **Community Nodes**. Existing users currently need to use a self-hosted n8n instance to install the Agencii community node, as the `n8n-nodes-agencii` npm package is in the process of verification. For more details on how this works in n8n, see the n8n community nodes installation guide at [https://docs.n8n.io/integrations/community-nodes/installation/](https://docs.n8n.io/integrations/community-nodes/installation/). ## Step 1: Set up n8n Integration in Agencii 1. In the Agencii dashboard, open **Deploy → Platforms** from the sidebar and click **New Platform**. Create a new platform modal with n8n option 2. In the **Create a New Platform** dialog, select **n8n** and click **Create Platform**. Select n8n as the platform type 3. On the **Configure n8n Integration** screen, choose: * **Agency** – the agency you want n8n to talk to. * **Default Agent** – the agent that will receive messages from this integration. * **Integration Name** – an internal name that will also help you identify the node inside n8n. * **Integration Description** – optional context for future reference. 4. Click **Save and continue**. Configure n8n integration with agency and default agent After saving, you’ll see the **Copy n8n Data** screen. It includes: * **NPM package name**: `n8n-nodes-agencii` – used to install the node in n8n Community Nodes. * **Integration ID** – a unique identifier that routes messages from n8n to this specific Agencii integration. * **API Key hint** – your first platform API key (you can manage keys under **Settings → API Keys**). Copy n8n data showing npm package name, integration ID and API key hint Keep the **Integration ID** handy—you’ll paste it into the Agencii node inside n8n. To connect Agencii with n8n, copy the NPM package name above and install it in the **Community Nodes** section of your n8n profile settings. After installation, you can use the **Agencii** node in your workflows. To understand the available actions and properties, please refer to the Agencii n8n documentation page. ## Step 2: Install the Agencii Community Node in n8n Install community node modal with n8n-nodes-agencii package name 1. In your n8n instance, go to **Settings → Community Nodes**. You can learn more about installing and managing community nodes in the official n8n docs at [https://docs.n8n.io/integrations/community-nodes/installation/](https://docs.n8n.io/integrations/community-nodes/installation/). 2. Click **Install** and enter the package name: ```bash theme={null} n8n-nodes-agencii ``` 3. Confirm the installation. After it completes, an **Agencii** node will appear in your n8n node palette. Agencii node package listed in Community nodes Workflow canvas with Agencii node selected from the node list ## Step 3: Use the Agencii Node in a Workflow The Agencii node exposes a single operation designed to send messages to your agency and receive structured responses. 1. Add an **Agencii** node to your workflow. Agencii Send message to agency node with parameters filled in Agencii node details with available actions 2. Select your **Agencii API** credentials. 3. Under **Resource**, choose **Chat**, and under **Operation**, select **Send Message**. 4. Configure the main fields: * **Integration ID** *(required)* – paste the Integration ID from your Agencii n8n Platform integration. * **Message** *(required)* – the prompt or instruction you want your default agent to process. * **Session ID** *(optional)* – reuse the `sessionId` from a previous run to continue the same conversation; leave empty to start a new session. * **User Context** *(optional)* – a JSON object with structured data (user IDs, preferences, feature flags) passed to [Agency Context](/additional-features/agency-context). This data is accessible within your agent's tools but is **not** exposed to the LLM. The Agencii node returns a JSON payload with (among others): * `text` / `response` – the main answer from your agency. * `sessionId` – the session identifier to reuse for multi-turn conversations. * `n8nIntegrationId` – the platform integration that handled the request. You can pass these values into downstream nodes (e.g., email, CRM, webhooks) to build complete automations. ## Example Use Cases * **Human-in-the-loop review** – send form or CRM data to your agency, then route the response into an approval step. * **Content generation pipelines** – trigger the Agencii node from schedules or webhooks and store generated content in Google Sheets, Notion, or a database. * **Multi-step analysis** – chain multiple Agencii nodes while reusing `sessionId` to keep context across data enrichment, analysis, and recommendation steps. # Slack Source: https://agency-swarm.ai/platform/integrations/slack-integration Learn how to integrate your agents with Slack ## **Feature Overview:** With Slack Integrations, you can create custom bots tailored to your workspace. These apps can be installed and managed within your workspace, enabling a wide range of automated functions and interactions. Currently, the Slack bots created via agencii can respond in: * **Direct Messages (DMs):** Screenshot of a bot responding to a Direct Message * **Public Chats** when mentioned by name (e.g., `@BotName`): Screenshot of a bot responding to a mention in a Public Chat ## Privacy Statement When apps are created on our platform, we don't have access to your workspace or its members. The OAuth permissions requested are minimal and support only the app's core functions. You can revoke the OAuth token from Slack at any time. You retain ownership of the app and can distribute it freely, regardless of user growth. For your privacy, **messages are not stored in our database**. *** ## **Creating a Custom Slack Bot** 1. **Select Your Agent:** Select the agent to be integrated into your slack app. This agent will be used to generate responses. 2. **Set the Integration Name:** This name refers to the bot's name, which will be used to mention it in public chats. Typically, you might want to set it to you agent name, although you can make it different if you wish. 3. **Provide an Integration Description:** This is a short description of your bot, used for reference only. (So you don't forget why you created it) 1. **Click "Create Slack App":** This will redirect you to the Slack Developer portal (`api.slack.com`), where you will need to authenticate and select the correct workspace for your application. 2. **Select Your Workspace and Click "Next":** This workspace will be the owner of your application, although you can still allow other workspaces to install it on their side. 3. **Click "Create":** Simply click create to continue. The application will be pre-configured with all the necessary settings. 4. **Copy credentials:** Copy your client id, client secret and signing secret, and paste them into the corresponding fields Keep your credentials secure to prevent potential exposure of your app. 1. **Install on Slack:** Click on the "Install on Slack" button to install your app. Alternatively, you can copy an installation link and send it to your client, or another workspace owner. 2. **Grant Permission:** Slack will prompt you to grant permission to exchange the OAuth token. Click "Allow" to sync your app with the integration. ✅ **That's it!** Now you can use your Agent in Slack! ## Limitations * Files are currently **not supported**. Apps created under the current limitations will receive full **future support**, as we ship any new features. *** ## **Troubleshooting** If the automatic OAuth flow fails, you can manually install the app. 1. Find your Bot User OAuth Token in your app on [api.slack.com](https://api.slack.com/). 2. Click "Install to your workspace" to generate the necessary tokens. 3. Copy and paste the token into the "Manual Slack Installation" dialog and click "Install." *** # API Source: https://agency-swarm.ai/platform/integrations/web-api Reference documentation for the Agencii Platform API. ## Feature Overview API Integrations provide a set of endpoints allowing you to run your agents on custom backends or on other unsupported channels. ⚡ Live Postman Example: [Go to Postman →](https://www.postman.com/vrsen-ai/agencii-api/overview) *** ## Authentication * **Note**: You can only use platform tokens for these endpoints. Find or create one inside **Profile Icon > API Keys**. * **Headers**: * `Authorization`: `Bearer ` * **Example**: `Bearer sk-agencii-H7sb111...` * `Content-Type`: `application/json` *** ## Endpoints Start a new conversation session. Get a response from your agent. Stream an agent run with member attribution and file attachments. Upload a member's file where your agent can read it with sandbox tools. *** ## Recover an interrupted API v2 request Use a unique `usageRequestId` for each request. If an error includes `X-Agent-Run-Admitted: false`, the request was rejected before a run started. If a connection ends without that header, the agent may still be working. Read `/get_chat_messages` and match `status.usageRequestId` before retrying. An older completed response does not mean the current run has finished. ## Additional Notes * All timestamps are in ISO 8601 format. * Ensure that your `apiIntegrationId` is valid and corresponds to an existing integration. * Replace placeholder values with actual data when making requests. * The `attachments` parameter in `/get_response` allows you to include files and specify tools for processing. * API v1 behavior is unchanged and does not enforce per-consumer allowances. *** # WhatsApp Source: https://agency-swarm.ai/platform/integrations/whatsapp-integration Learn how to integrate your agents with WhatsApp using Twilio ## Feature Overview Seamlessly connect your **agents** to **WhatsApp** using **Twilio**, a messaging service that significantly simplifies WhatsApp Sender Business profile setup. Screenshot 2025-02-17 at 13.24.37.png 🔒 All chats, conversations and messages are not stored in our database to ensure your or your client’s privacy. *** ## Prerequisites * A verified **Twilio Account** ([Sign up here](https://login.twilio.com/u/signup)) with a provisioned phone number. * A verified **Facebook Business account** ([Learn more](https://www.facebook.com/business/help/1710077379203657)) and a verified **WhatsApp Business Portfolio** ([How to verify your WhatsApp Business Account](https://www.facebook.com/business/help/2087193751603668?id=2129163877102343)). ## Creating a WhatsApp Agent via Twilio 1. Go to [Twilio Console](https://console.twilio.com/us1/develop/sms/senders/whatsapp-senders) and click on the **'Create New Sender'** button to begin the setup. Screenshot 2025-02-17 at 13.40.04.png 2. Follow all the necessary steps on **Twilio's** end to complete the integration. Twilio has already documented the entire process, so you can refer to their official guides via this link: [https://www.twilio.com/docs/whatsapp/self-sign-up](https://www.twilio.com/docs/whatsapp/self-sign-up) Screenshot 2025-02-17 at 13.48.59.png 3. Once you have a **verified** WhatsApp Sender with the status set to **Online**, you can proceed to the next steps. 1. Go to [https://agencii.ai/whatsapp/](https://agencii.ai/whatsapp/) and click on the **'Connect WhatsApp'** button to begin the setup. 2. Enter your Agent details Screenshot 2025-02-17 at 14.51.15.png 1. **Select your Twilio account** from the dashboard. Screenshot 2025-02-17 at 15.27.03.png 2. To add a new account, copy and paste your **Account SID** and **Auth Token** from the bottom of the Twilio dashboard. Screenshot 2025-02-17 at 15.27.55.png 3. (Optional) If you have a Subaccount, paste the Subaccount SID as well. 4. Click **Create** 1. Find your WhatsApp Sender SID in the Twilio Console under **Messaging** → **Senders** → **WhatsApp Senders**, then copy it from the URL. Example: [https://console.twilio.com/us1/develop/sms/senders/whatsapp-senders/details/XEXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX](https://console.twilio.com/us1/develop/sms/senders/whatsapp-senders/details/XEXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX) Screenshot 2025-02-17 at 15.40.42.png 2. Add whatsapp sender on agencii Screenshot 2025-02-17 at 15.29.05.png Copy each webhook integration URL and paste it into the **Twilio WhatsApp Sender configuration profile**, ensuring each URL is placed in the corresponding textbox. Screenshot 2025-02-17 at 15.43.40.png Screenshot 2025-02-17 at 15.42.34.png ✅ **That's it!** Now you can chat with your Agent via WhatsApp. # Website Widget Source: https://agency-swarm.ai/platform/integrations/widget Embed the Agencii chat widget on any site in minutes. ## Feature Overview * Launch your existing agent as an embeddable web widget with zero additional hosting. * Switch agencies on the fly by updating the widget in the dashboard — no code redeploy needed. * Personalize every deployment with optional `additionalInstructions` that shape the assistant's behavior per site. Widget preview ## Prerequisites * Deployed Agency in the Agencii dashboard. ## Quick Start 1. In the Agencii dashboard, open **Deploy → Widgets** and create a new widget. 2. Configure the widget's name, description, position and conversation starters. 3. Customize the widget's appearance by choosing a theme mode, logo, and color scheme. 4. Select the agency and any selectable agents. 5. Configure advanced settings such as Allowed Domains and auto-open behavior as needed. 6. Save changes. 7. Test your widget! 1. In the Agencii dashboard, open **Deploy → Widgets** and find the widget you created. 2. Click the three-dot menu on the right side of the widget row and select **Embed**. Embed widget 3. Copy the embedding script. 4. Paste the script into your website's HTML file (or adjust the script to your needs). 5. Load the page and confirm the widget works as expected. 1. In the Agencii dashboard, open **Deploy → Widgets** and find the widget you created. 2. Click the **Share** button on the right side of the widget row. 3. This opens a new window with the widget embedded on a blank page. Live widget embedded on a landing page You can embed several widgets on the same page by using the embedding script multiple times with different `widgetId`s and `chatContainer` selectors. If you are prototyping locally, temporarily add `http://localhost:3000` (or your dev origin) to the widget's allowed domains list if you are using the Allowed Domains feature. ## Widget Controls You can control the widget from your site/app by dispatching a `CustomEvent` named **"widget-control"** on `window` with a `detail` payload. The widget listens for this event and performs the requested action. **Event name:** `widget-control` ```tsx theme={null} interface WidgetControlEventDetail { /** Command name */ type: 'open-widget' | 'send-message-to-widget' | 'set-widget-context'; /** Command-specific payload (not used for set-widget-context) */ data?: boolean | string; /** Target widget instance */ widgetId: string; // e.g., 'WIDGET_123' /** Structured data passed to Agency Context */ userContext?: Record; /** Extra guidance for the agent */ additionalInstructions?: string; } ``` **Dispatch pattern:** ```tsx theme={null} window.dispatchEvent( new CustomEvent('widget-control', { detail: { type, data, widgetId }, }) ); ``` The widget must be initialized on the page. Replace `WIDGET_ID` with the identifier from your embed script. ## Commands ### Open or close the widget Opens or closes the widget UI. **Type:** `open-widget` **Data:** `boolean` — `true` to **open**, `false` to **close**. ```jsx Open theme={null} window.dispatchEvent( new CustomEvent('widget-control', { detail: { type: 'open-widget', data: true, widgetId: WIDGET_ID, }, }) ); ``` ```jsx Close theme={null} window.dispatchEvent( new CustomEvent('widget-control', { detail: { type: 'open-widget', data: false, widgetId: WIDGET_ID, }, }) ); ``` #### Typical use cases * Bind to a "Chat" / "Support" button to open the widget. * Close the widget after a route change or when a modal shows. ### Set widget context Sets persistent context for **all future messages** — both programmatic (`send-message-to-widget`) and user-typed. **Type:** `set-widget-context` | Property | Type | Required | Description | | - | - | - | - | | `userContext` | object | No | Structured data (user IDs, preferences, feature flags) passed to [Agency Context](/additional-features/agency-context). Accessible within tools but **not** exposed to the LLM. | | `additionalInstructions` | string | No | Extra guidance for the agent on all subsequent requests. | ```jsx theme={null} window.dispatchEvent( new CustomEvent('widget-control', { detail: { type: 'set-widget-context', widgetId: WIDGET_ID, userContext: { customerId: '123' }, additionalInstructions: 'Be helpful', }, }) ); ``` Use `set-widget-context` once on page load to inject user-specific data (e.g., customer ID, subscription tier) so every conversation automatically has access to it. ### Send a message to the widget Programmatically sends a text message into the widget (e.g., seed a greeting or pass context). This event does not open the widget automatically, so dispatch an `open-widget` event first. **Type:** `send-message-to-widget` | Property | Type | Required | Description | | - | - | - | - | | `data` | string | Yes | The message body to send. | | `userContext` | object | No | Structured data (user IDs, preferences, feature flags) passed to [Agency Context](/additional-features/agency-context). Accessible within tools but **not** exposed to the LLM. **Overrides** any context set via `set-widget-context`. | | `additionalInstructions` | string | No | Extra guidance for the agent on this specific request. **Overrides** any instructions set via `set-widget-context`. | ```jsx Basic theme={null} window.dispatchEvent( new CustomEvent('widget-control', { detail: { type: 'send-message-to-widget', data: 'Hi', widgetId: WIDGET_ID, }, }) ); ``` ```jsx With Context theme={null} window.dispatchEvent( new CustomEvent('widget-control', { detail: { type: 'send-message-to-widget', data: 'Hello world', widgetId: WIDGET_ID, userContext: { customerId: '123', tier: 'premium' }, additionalInstructions: 'Be extra helpful', }, }) ); ``` ## Multiple Widgets on One Page If you embed multiple widget instances, dispatch events with the **specific** `widgetId` you want to control. The widget code should internally ignore events addressed to other IDs. ```jsx theme={null} const SALES_WIDGET = 'WIDGET_SALES'; const SUPPORT_WIDGET = 'WIDGET_SUPPORT'; // Open Support, keep Sales unchanged window.dispatchEvent(new CustomEvent('widget-control', { detail: { type: 'open-widget', data: true, widgetId: SUPPORT_WIDGET }, })); ``` # Zapier Source: https://agency-swarm.ai/platform/integrations/zapier-integration Learn how to integrate your agents with Zapier. ## Feature Overview Zapier is a no-code automation platform that helps you connect over 7,000 apps and build automated workflows without writing any code. Integrate your **agents** with Zapier to extend their reach to countless services--responding to emails, updating spreadsheets, posting to social channels, and more. Screenshot 2025-05-05 at 23.02.14.png To protect your privacy and that of your clients, none of your chats, conversations, or messages are stored in our database. 🔒 ## Prerequisites * **Zapier Account** ([Sign up](https://zapier.com/)). * **Platform API Key** – You can find it under **Settings → [API Keys](https://agencii.ai/settings/?tab=apiKeys)**. ## Set up Zapier 1. Navigate to **Platforms** in the sidebar and select **New Platform** to begin setup. Screenshot_2025-05-05_at_23.22.13.png 2. Select **Zapier** and click on **Create Platform**. Screenshot_2025-05-05_at_23.22.13.png 3. Enter the required information for your Zapier integration, including integration name, the agent you want to connect, and a description, then click on **Save and continue**. Screenshot_2025-05-05_at_23.23.19.png The Agencii app is not yet available in the Zapier marketplace. To access it, use the **Install** button for early access. Screenshot 2025-02-17 at 15.40.42.png Screenshot 2025-02-17 at 15.29.05.png Accept the invitation to install the app & start building your automation with Agencii Zapier App✨ Agencii Zapier App ## Available Actions **Authorization**: * **Platform API Key** – Available under **Settings → [API Keys](https://agencii.ai/settings/?tab=apiKeys)**.

The Prompt action enables your agent to generate responses based on given inputs. This action processes a prompt, context, or input data and returns a response that is relevant to the context. This can be used for automating conversations, supporting decision-making, and executing tasks intelligently within workflows.

Understanding these properties is essential because they define how your agent will receive and interpret data from Zapier. Each property directly controls what the agent sees, what it responds to, and how it behaves in an automation. The identifier for your zapier integration, found on the integration page. Example: "HVC7YxC1YBSuTtDwGK7a" The text you want to send to the connected agent. Example: "Write a blog post with agent's knowledge" The identifier for an existing conversation. If not provided, the system will create a new chat. A JSON object with structured data (user IDs, preferences, feature flags) passed to [Agency Context](/additional-features/agency-context). This data is accessible within your agent's tools but is **not** exposed to the LLM. The identifier of the zapier integration used. Example: "HVC7YxC1YBSuTtDwGK7a" The text response generated by your agent. The conversation identifier - either newly created or the one you provided.
Additional actions and triggers are under development and will be added in future updates. # Onboarding Source: https://agency-swarm.ai/platform/marketplace/onboarding Learn how to templatize your agents on our marketplace. When posting an agency on our marketplace, you can define a custom `OnboardingTool` to allow end users to customize your agents for their own businesses. ## Why Customization is Important? When building AI agents, you might encounter clients who want to deploy agents for the same roles. For example, almost every company employs an **accountant**. And so, if you built an accounting agent for one company, you might want to reuse it later. However, although the **general process** for the same role across various companies is similar, the **specific process** is always unique. For example, one company might do accounting **weekly**, another one **monthly**. One company might use **Xero**, another one **Quick books**. One company prefers to send invoices via **email**, another one via their **customer portal**, and so on. As you can see, **even if you built an agent for the same role at one company, it’s not gonna be useful at another company**. ## How Agencii Solves Agent Onboarding On our platform, we tackle this issue by creating a custom `OnboardingTool` class. Inside this tool class, you can define all the parameters that you need in order to customize your agents before deployment. For our accounting agent above, for example, this class might look like this: ```python theme={null} from agency_swarm.tools import BaseTool from pydantic import Field import os from dotenv import load_dotenv from typing import Literal load_dotenv() class OnboardingTool(BaseTool): """ Customizes the accounting agent based on the client's specific accounting processes, software, and preferences before deployment. """ agent_name: str = Field( ..., description="Name of your accounting agent visible to the user." ) business_overview: str = Field( ..., description="Brief business overview including industry, size, and accounting needs." ) accounting_frequency: Literal["weekly", "monthly", "quarterly"] = Field( ..., description="How often accounting tasks should be performed." ) accounting_software: Literal["xero", "quickbooks", "freshbooks", "sage", "other"] = Field( ..., description="The accounting software platform the client uses." ) invoice_delivery_method: Literal["email", "customer_portal", "both"] = Field( ..., description="Preferred method for sending invoices to clients." ) def run(self): """ Programmatically writes a JSON config containing all user-provided accounting parameters to onboarding_config.json, in the exact same directory as this tool file. """ import json # Get tool directory path tool_dir = os.path.dirname(os.path.abspath(__file__)) config_path = os.path.join(tool_dir, "onboarding_config.json") # Dynamically collect all pydantic model fields into a dict config = self.model_dump() # Write config file try: with open(config_path, "w", encoding="utf-8") as f: json.dump(config, f, indent=2, ensure_ascii=False) return f"Accounting agent configuration created at: {config_path}" except Exception as e: return f"Error writing config file: {str(e)}" if __name__ == "__main__": # Test with sample accounting client data tool = OnboardingTool( agent_name="Acme Corp Accounting Agent", business_overview="Mid-size manufacturing company with 50 employees.", accounting_frequency="monthly", accounting_software="xero", invoice_delivery_method="customer_portal" ) print(tool.run()) ``` **Key things to note**: * `OnboardingTool` must extend `BaseTool` class. * File name must be `onboarding_tool.py` * The file needs to be placed in the **repository root directory**. * All field descriptions will be displayed during the onboarding process on our platform. * We will replace “\_” with spaces, capitalize fields names and display them as titles, unless you `ui:title` parameter is provided. ## How This Will Look On Agencii When users deploy your agents from the marketplace, we will parse this class into a JSON schema and display it as a form: onboarding form example All that the user who wants to deploy your agency needs to do is simply fill out this form! That's it! ## Step-by-Step Guide: How to Create Your Own Agent Onboarding Form 1. **Copy our template and place it in `onboarding_tool.py` file in the root directory:** ```python theme={null} from agency_swarm.tools import BaseTool from pydantic import Field import os from dotenv import load_dotenv from typing import Literal load_dotenv() class OnboardingTool(BaseTool): """ Customizes your agent based on client-specific requirements before deployment. Replace the fields below with parameters relevant to your use case. """ # String fields - use for names, descriptions, and text inputs agent_name: str = Field( ..., description="Name of your agent visible to the user." ) business_overview: str = Field( ..., description="Brief overview of the client's business or requirements." ) # String fields for additional context additional_notes: str = Field( ..., description="Any additional notes or special requirements for the agent." ) def run(self): """ Saves the configuration as a Python file with a config object """ import pprint tool_dir = os.path.dirname(os.path.abspath(__file__)) config_path = os.path.join(tool_dir, "onboarding_config.py") config = self.model_dump(mode="python") try: # Generate Python code with Python-safe literals (None/True/False) python_code = ( "# Auto-generated onboarding configuration\n\n" f"config = {pprint.pformat(config, sort_dicts=True)}\n" ) with open(config_path, "w", encoding="utf-8") as f: f.write(python_code) return f"Configuration saved at: {config_path}\n\nYou can now import it with:\nfrom onboarding_config import config" except Exception as e: return f"Error writing config file: {str(e)}" if __name__ == "__main__": tool = OnboardingTool( agent_name="Example Agent", business_overview="Example business description", additional_notes="Any special requirements go here" ) print(tool.run()) ``` 2. Add your own specific fields with pydantic that are required to fine-tune your agents: ```python theme={null} # Example: Adding Literal field (dropdown menu) from typing import Literal class OnboardingTool(BaseTool): # ... # Literal field - creates a dropdown with predefined options model: Literal["gpt-4o", "gpt-6-luna"] = Field( ..., description="Select the AI model to use for the agent." ) # ... ``` 3. **Execute the tool file:** ```python theme={null} python onboarding_tool.py ``` This will generate `onboarding_config.py` next to your onboarding tool file. 4. **Customize your agents** Use the values from the generated [config.py](http://config.py) file in your code to customize your agents: ```python theme={null} from agency_swarm import Agent from onboarding_config import config import os current_dir = os.path.dirname(os.path.abspath(__file__)) instructions_path = os.path.join(current_dir, "instructions.md") def render_instructions(): with open(instructions_path, "r") as file: instructions = file.read() instructions = instructions.format( agent_name=config["agent_name"], business_overview=config["business_overview"], additional_notes=config["additional_notes"] ) return instructions rag_agent = Agent( name=onboarding_config["agent_name"], description=onboarding_config["agent_description"], instructions=render_instructions(), files_folder="./files", model=config["model"], ) ``` In this example we: * Customized the instructions. * Customized the model. 5. Deploy and list on marketplace 1. Deploy your agent as usual, just make sure to commit the default `onboarding_config`for your own account. 2. Test the agency is working as expected on your account first. 3. List your agent on our marketplace by going to [https://agencii.ai/marketplace/](https://agencii.ai/marketplace/) That’s it! This is how simple it is to customize and scale your agents with our platform. ## Advanced Fields & Parameters We use [react-jsonschema-form](https://rjsf-team.github.io/react-jsonschema-form/docs/) to render the onboarding form. You can use the following uiSchema parameters to customize the form: * `ui:widget`: controls which UI component is used for the field. (e.g. `text`, `textarea`, etc.) * `ui:options`: controls widget-specific options (e.g. `rows`, `inputType`, `label`, etc.). * `ui:title`: overrides the field’s title. * `ui:description`: overrides the field’s description. * `ui:readonly`: makes the field read-only. * `ui:disabled`: disables user interaction entirely. * `required`: belongs in the **JSON schema**, not the uiSchema. ### File Uploads To upload your files, you must add `"x-file-upload-path"` , and the type of the field must be set `list[str]` . ```python theme={null} # List fields - use for multiple selections or file uploads accountant_agent_knowledge: list[str] = Field( ..., description="Files that accountant agent must have as knowledge.", json_schema_extra={ "x-file-upload-path": "./accountant_agent/files", # standard JSON Schema }, ) ``` After user uploads the files, they will be added to `./accountant_agent/files` folder. ### Multiline Text Inputs `ui:widget` parameter in `json_schema_extra` controls UI component displayed in the onboarding form ```python theme={null} additional_notes: Optional[str] = Field( None, description="Any additional notes for the agent to go into prompt.", json_schema_extra={ "ui:widget": "textarea", }, ) ``` ## A Note on Form Updates * If you push a change to the form, **the users of your agents will be required to re-enter any new and updated fields**. Do this with caution! * The summary of the commit that triggered the update will be displayed to the user in the form as the reason for the update. * The new version won’t be deployed for the users until they complete an onboarding form. # OpenClaw Source: https://agency-swarm.ai/platform/marketplace/openclaw Deploy your own private OpenClaw assistant on Agent Swarm. OpenClaw is a personal AI assistant you run in your own environment. On Agent Swarm, you can launch it from a ready template and chat with it inside your workspace in a few clicks. Create your own repository from the official OpenClaw starter template. Learn what OpenClaw can do and how its workspace files work. ## Launch OpenClaw On Agent Swarm Open [agency-ai-solutions/openclaw-starter-template](https://github.com/agency-ai-solutions/openclaw-starter-template). Click **Use this template** and create a repository in your own GitHub account or organization. Use this template dropdown In Agent Swarm, connect your GitHub account and pick the repository you created from the template. Turn on **Persistent File Storage** for the swarm before the first deploy. For Agent Swarm deploys, set `OPENCLAW_HOME=/app/mnt/openclaw`. The file browser should show that same path directly, not a raw `/mnt` root. Default deploy: add `OPENAI_API_KEY` in **Secrets Vault** before you deploy. If you later switch away from the default OpenAI GPT-5.4 setup, add the matching provider secret for that model too. Optional advanced settings: * `OPENCLAW_PROVIDER_MODEL` only if you want a different provider or model * `ANTHROPIC_API_KEY` only if you switch to an Anthropic model * `OPENCLAW_GATEWAY_TOKEN` only if you want to override the internal gateway token For the first deploy, enter only what is necessary: * the assistant name * one short instruction about what it should help with Add longer role descriptions, multi-step rules, and extra setup in the OpenClaw workspace files after deploy. Start the deployment, wait for the build to finish, then open the chat and send your first message. ## Customize OpenClaw After Deploy OpenClaw keeps its own workspace files on persistent storage. That is where you update its personality, rules, and long-term notes. Agency Swarm now writes the default OpenClaw workspace to `/app/mnt/openclaw/workspace`. At the storage root, you should also see sibling folders like `logs` and `state`. The most important files are: * `AGENTS.md` for operating rules and priorities * `SOUL.md` for voice, tone, and personality * `USER.md` for user-specific preferences * `MEMORY.md` for durable notes you want OpenClaw to keep To replace them: 1. Open your deployed agent 2. Go to **Customization** -> **Persistent File Storage** 3. Open `/app/mnt/openclaw/workspace` 4. Upload the replacement file Agent Swarm persistent file storage view for OpenClaw workspace If OpenClaw starts behaving strangely, check both the onboarding instructions and the workspace files. They are both part of the final behavior. If you are upgrading an older deploy, OpenClaw may still have legacy files under `.openclaw/workspace` until the integration migrates them to the cleaner `workspace` path. ## What You Get * A private OpenClaw deployment running on Agent Swarm * Normal chat inside your Agent Swarm workspace * Persistent OpenClaw files under `/app/mnt/openclaw` * A clean upgrade path through the starter template repo This deployment is meant for one trusted user or one trusted team. The provider secrets you add in Agent Swarm are available inside the sandbox so OpenClaw can call model providers. Review [OpenClaw Security](https://docs.openclaw.ai/gateway/security) before you expose access more broadly. ## Want To Use It In Code? If you want to use OpenClaw inside your own Agency Swarm code, continue with [OpenClawAgent](/core-framework/third-party-agents/openclaw-agent). # Agencii Platform Source: https://agency-swarm.ai/platform/overview Learn about the Agencii AI Platform ## Overview Agencii Platform is built on top of our framework, so you can focus on what matters most: **building your AI agents, not deploying them**. It significantly simplifies the **deployment**, **management**, and **integration** of your agents, eliminating technical barriers and unnecessary complexity. ## Free Community We also offer a [free Skool community](https://www.skool.com/agency-ai/about) with resources to help you get started: * 📚 AI Agent Developer Course & Playbooks * 💬 Weekly Q\&A Calls * 👨‍💻 Professional Developer Support * 📄 Templates and Agents * 🤝 Project Collaboration * ✨ Feature & Playbook Requests ## Future Roadmap We’re building an AI agent builder platform that lets you build and customize agents for any use case. Notable features include: * [x] **Agent Hosting & Runtime:** Deploy agents built with the framework directly from GitHub in a few clicks. * [x] **Vertical Agent Marketplace:** Share and import community-built agents directly within the platform. * [ ] **Agent Builder:** Lovable-type UI to build AI agents directly within the platform. * [ ] **Agent Swarm:** A unified UI with super agents that complete general tasks (coding, presentations, docs, spreadsheets, etc) and build other agents for tasks they can’t do yet. * [ ] **Background Agents:** Agents can be scheduled by you to execute tasks autonomously in the background. * [ ] **Workspaces:** Role-based access controls and shared workspaces for seamless collaboration with your clients. * [ ] **Workflows:** Build agentic AI workflows to automate more rigid repetitive business processes. * [ ] **Analytics:** Comprehensive analytics and reporting with a focus on cost, outcomes, and ROI. * [ ] **Enterprise Security & Compliance:** SOC2 compliance, single sign-on (SSO), advanced encryption, and audit capabilities. ## Get Started 🚀 To get started, [sign up for a free account](https://agencii.ai/signup). Start with the [Starter Template guide](/welcome/getting-started/starter-template) for an Agencii-compatible setup. **Happy building!** # Pricing Source: https://agency-swarm.ai/platform/pricing Explore our current subscription plans. ## Pricing Plans Choose a plan based on how many agencies you want to run and how much monthly capacity you need. **\$0 forever** * **25 daily credits** * No monthly credits * Up to 5 agencies **\$20/month** * **25 daily credits** * **2,000 monthly credits** * **Unlimited agencies** ## Refill Credits (Pro) Pro users can buy one-time refill credits. You can also enable **configurable auto-recharge** to top up automatically when your balance gets low. | Price | Credits | | - | - | | **\$30** | **3,000 credits** | | **\$100** | **10,000 credits** | Credits power both plans. Learn more in [How Credits Work](/platform/how-credits-work). # API Reference Source: https://agency-swarm.ai/references/api Gain a deeper understanding of the core classes and methods available in Agency Swarm. ## Agency Class The Agency class orchestrates a collection of Agent instances based on entry points and communication flows. ```python theme={null} from agency_swarm import Agency, Agent class Agency: def __init__( self, *entry_point_agents: Agent, communication_flows: list[CommunicationFlowEntry] | None = None, name: str | None = None, shared_instructions: str | None = None, shared_tools: list[Tool] | None = None, shared_tools_folder: str | None = None, shared_files_folder: str | None = None, shared_mcp_servers: list[Any] | None = None, send_message_tool_class: type | None = None, load_threads_callback: ThreadLoadCallback | None = None, save_threads_callback: ThreadSaveCallback | None = None, randomize_agent_voices: bool = False, voice_random_seed: int | None = None, ): """ Initialize an Agency instance. Parameters: *entry_point_agents: Agent instances serving as entry points for external interaction communication_flows: Flexible communication flow definitions supporting tuples and AgentFlow objects name: Optional name for the agency shared_instructions: Instruction text or file path applied to every agent shared_tools: Tool instances or BaseTool classes to add to all agents (each agent gets independent copies) shared_tools_folder: Path to folder containing tool files to load and share with all agents shared_files_folder: Path to folder of files to upload and share with all agents via a common vector store shared_mcp_servers: MCP server instances to attach to all agents send_message_tool_class: Fallback SendMessage tool class when a communication flow does not define its own load_threads_callback: Callable used to load persisted conversation threads save_threads_callback: Callable used to save conversation threads randomize_agent_voices: Assign provider-supported random voices to agents that do not set `voice` voice_random_seed: Optional seed used to make voice randomization deterministic """ ``` > **Note:** `CommunicationFlowEntry` is a type alias defined in `agency_swarm.agency.core` > that accepts `(Agent, Agent)` tuples, `AgentFlow` chains, or those accompanied by a > custom SendMessage tool class. > **Advanced Note:** `Handoff` from `agency_swarm` is the Agency Swarm communication-flow class. > `SDKHandoff` exposes the raw OpenAI Agents SDK handoff type for advanced interoperability. ### Key Attributes * **`agents`** (dict\[str, Agent]): Dictionary mapping agent names to their instances * **`entry_points`** (list\[Agent]): Agents designated as entry points for external interaction * **`thread_manager`** (ThreadManager): Manager responsible for handling conversation threads * **`event_stream_merger`** (EventStreamMerger): Aggregates streaming events from concurrent agent runs * **`persistence_hooks`** (PersistenceHooks | None): Optional hooks for loading/saving thread state * **`shared_instructions`** (str | None): Instructions prepended to every agent's system prompt * **`shared_tools`** (list\[Tool] | None): Tool instances or BaseTool classes shared with all agents * **`shared_tools_folder`** (str | None): Path to folder containing shared tool files * **`shared_files_folder`** (str | None): Path to folder of files shared via a common vector store * **`shared_mcp_servers`** (list\[Any] | None): MCP server instances attached to all agents * **`send_message_tool_class`** (type | None): Fallback SendMessage tool when no flow-specific tool is set ### Key Methods ```python get_response theme={null} async def get_response( self, message: str | list[TResponseInputItem], recipient_agent: str | Agent | None = None, context_override: dict[str, Any] | None = None, hooks_override: RunHooks | None = None, run_config: RunConfig | None = None, file_ids: list[str] | None = None, additional_instructions: str | None = None, agency_context_override: AgencyContext | None = None, **kwargs: Any, ) -> RunResult: """ Initiate an interaction with a specified agent within the agency. Parameters: message: The input message for the agent recipient_agent: Target agent instance or name (defaults to first entry point) context_override: Run-scoped context passed into MasterContext.user_context hooks_override: Specific hooks to use for this run, overriding agency defaults run_config: Configuration for the agent run file_ids: Additional file IDs for the agent run additional_instructions: Additional instructions for this run only agency_context_override: Run-scoped agency context override (for example, isolated thread history) **kwargs: Additional arguments passed to the target agent's get_response Returns: RunResult: The result of the agent execution chain """ ``` ```python get_response_sync theme={null} def get_response_sync( self, message: str | list[TResponseInputItem], recipient_agent: str | Agent | None = None, context_override: dict[str, Any] | None = None, hooks_override: RunHooks | None = None, run_config: RunConfig | None = None, file_ids: list[str] | None = None, additional_instructions: str | None = None, agency_context_override: AgencyContext | None = None, **kwargs: Any, ) -> RunResult: """ Initiate an interaction with a specified agent within the agency. Parameters: message: The input message for the agent recipient_agent: Target agent instance or name (defaults to first entry point) context_override: Run-scoped context passed into MasterContext.user_context hooks_override: Specific hooks to use for this run, overriding agency defaults run_config: Configuration for the agent run file_ids: Additional file IDs for the agent run additional_instructions: Additional instructions for this run only agency_context_override: Run-scoped agency context override (for example, isolated thread history) **kwargs: Additional arguments passed to the target agent's get_response Returns: RunResult: The result of the agent execution chain """ ``` ```python get_response_stream theme={null} def get_response_stream( self, message: str | list[TResponseInputItem], recipient_agent: str | Agent | None = None, context_override: dict[str, Any] | None = None, hooks_override: RunHooks | None = None, run_config_override: RunConfig | None = None, file_ids: list[str] | None = None, additional_instructions: str | None = None, agency_context_override: AgencyContext | None = None, **kwargs: Any, ) -> StreamingRunResponse: """ Initiate a streaming interaction with a specified agent within the agency. Parameters: message: The input message for the agent recipient_agent: Target agent instance or name (defaults to first entry point) context_override: Run-scoped context passed into MasterContext.user_context hooks_override: Specific hooks for this run run_config_override: Specific run configuration for this run file_ids: Additional file IDs for the agent run additional_instructions: Additional instructions for this run only agency_context_override: Run-scoped agency context override (for example, isolated thread history) **kwargs: Additional arguments passed to get_response_stream Returns: StreamingRunResponse: Wrapper over the streaming agent execution, yielding events """ ``` ```python run_fastapi theme={null} def run_fastapi( self, host: str = "127.0.0.1", port: int = 8000, app_token_env: str = "APP_TOKEN", cors_origins: list[str] | None = None, enable_agui: bool = False, enable_realtime: bool = False, realtime_options: dict[str, Any] | None = None, oauth_user_id_dependency: OAuthUserIdDependency | None = None, verify_oauth_callback_user: bool = False, ): """ Serve this agency via the FastAPI integration. Parameters: host: Host address to bind the server port: Port number to bind the server app_token_env: Environment variable name for authentication token cors_origins: List of allowed CORS origins enable_agui: Enable Agency UI interface enable_realtime: Mount `//realtime` websocket routes realtime_options: Optional realtime overrides (for example provider/model/voice) oauth_user_id_dependency: Trusted authentication dependency required for OAuth-enabled agencies. It must return a stable, non-secret user ID. verify_oauth_callback_user: Reject an OAuth callback whose pending flow belongs to a different user. Requires browser-carried authentication (cookie or session). """ ``` ```python get_agency_graph theme={null} def get_agency_graph( self, include_tools: bool = True, ) -> dict[str, Any]: """ Returns a ReactFlow-compatible JSON graph representing the agency's organization. Parameters: include_tools: Whether to include agent tools as separate nodes Returns: dict: ReactFlow-compatible structure with nodes and edges """ ``` ```python get_metadata theme={null} def get_metadata( self, include_tools: bool = True, ) -> dict[str, Any]: """ Returns combined graph data and summary metadata for the agency. Parameters: include_tools: Whether to include agent tools as separate nodes Returns: dict: Graph data plus metadata fields like agencyName, totalAgents, totalTools, agents, entryPoints. Tool entries include inputSchema when available. """ ``` ```python visualize theme={null} def visualize( self, output_file: str = "agency_visualization.html", include_tools: bool = True, open_browser: bool = True, ) -> str: """ Create an HTML visualization of the agency structure. Parameters: output_file: Path to save the HTML file include_tools: Whether to include agent tools in visualization open_browser: Whether to automatically open in browser Returns: str: Path to the generated HTML file """ ``` ```python tui theme={null} def tui(self, show_reasoning: bool | None = None, reload: bool = True) -> None: """ Run the terminal UI for the agency (set reload=False to disable hot reload on file changes). """ ``` ```python copilot_demo theme={null} def copilot_demo( self, host: str = "127.0.0.1", port: int = 8000, frontend_port: int = 3000, cors_origins: list[str] | None = None, ) -> None: """ Run the bundled copilot demo for the agency. """ ``` For provisioning and current terminal limitations, see [Agent Swarm TUI](/core-framework/agencies/agent-swarm-cli). ## Agent Class The Agent class extends the base `agents.Agent` with capabilities for multi-agent collaboration within an Agency. ```python theme={null} from agency_swarm import Agent, ModelSettings class Agent(BaseAgent[MasterContext]): def __init__(self, **kwargs: Any): """ Initialize an Agency Swarm Agent. Parameters: name (str): Agent name (**required**) instructions (str | Path | None): System prompt text or path description (str | None): Optional role description for send_message tools files_folder (str | Path | None): Folder for local file management and vector stores tools_folder (str | Path | None): Directory for automatic tool discovery schemas_folder (str | Path | None): Directory containing OpenAPI schemas for tool generation api_headers (dict[str, dict[str, str]] | None): Per-schema HTTP headers for generated tools api_params (dict[str, dict[str, Any]] | None): Per-schema default parameters for generated tools include_search_results (bool): Include search results in FileSearchTool output (default False) include_web_search_sources (bool): Include source URLs for WebSearchTool output (default True) validation_attempts (int): Number of retries when output guardrails trigger (default 1) raise_input_guardrail_error (bool): Controls input guardrail behavior—False enables non-strict mode (guidance as assistant message), True enables strict mode (raises exceptions). Default: False system_reminders (str | Callable | SystemReminder | list[str | Callable | SystemReminder] | None): Transient reminders injected before model calls. Plain strings and callables run on every model call of each top-level user turn. handoff_reminder (str | None): Custom reminder text when handing off to another agent model (str | Model | None): Model identifier. Omitting it or passing None selects "gpt-6-luna"; pass another model name or Model instance explicitly to use it. model_settings (ModelSettings | None): Model configuration overrides tools (list[Tool] | None): Explicit tool instances to register mcp_servers (list[MCPServer] | None): Model Context Protocol servers to attach mcp_config (MCPConfig | None): Configuration for MCP servers input_guardrails (list[InputGuardrail] | None): Pre-execution validation hooks output_guardrails (list[OutputGuardrail] | None): Post-execution validation hooks output_type (type[Any] | AgentOutputSchemaBase | None): Type of final output structure hooks (AgentHooks | None): Lifecycle callbacks from the agents SDK tool_use_behavior ("run_llm_again" | "stop_on_first_tool" | StopAtTools | dict[str, Any] | Callable): Tool execution policy passed through to the agents SDK reset_tool_choice (bool | None): Whether to reset tool choice after tool calls voice (str | None): Realtime session voice used when this agent is the entry agent """ ``` ### Key Attributes * **`files_folder`** (str | Path | None): Local folder for file management and vector stores * **`tools_folder`** (str | Path | None): Directory for automatic tool discovery and loading * **`schemas_folder`** (str | Path | None): Folder scanned for OpenAPI schemas to auto-generate tools * **`api_headers` / `api_params`** (dict): Per-schema metadata applied when generating tools * **`description`** (str | None): Agent role description for dynamic send\_message tools * **`include_search_results`** (bool): Whether FileSearchTool responses include citation context * **`include_web_search_sources`** (bool): Whether WebSearchTool responses include source URLs * **`validation_attempts`** (int): Retry count for output guardrail enforcement * **`raise_input_guardrail_error`** (bool): Controls input guardrail mode—False for non-strict (guidance as assistant), True for strict (raises exceptions). * **`system_reminders`** (list\[SystemReminder]): Transient reminders injected before model calls. Plain strings and callables run on every model call of each top-level user turn. * **`handoff_reminder`** (str | None): Custom reminder appended to handoff prompts * **`tool_concurrency_manager`** (ToolConcurrencyManager): Coordinates concurrent tool execution * **`voice`** (str | None): Realtime session voice used when this agent is the entry agent. A session keeps one voice from start to finish, so a voice set on any other agent is not heard. ### Core Execution Methods ```python get_response theme={null} async def get_response( self, message: str | list[TResponseInputItem], sender_name: str | None = None, context_override: dict[str, Any] | None = None, hooks_override: RunHooks | None = None, run_config_override: RunConfig | None = None, file_ids: list[str] | None = None, additional_instructions: str | None = None, agency_context: AgencyContext | None = None, **kwargs: Any, ) -> RunResult: """ Run the agent's turn in the conversation loop. Parameters: message: Input message as string or structured input items list sender_name: Name of sending agent (None for user interactions) context_override: Run-scoped context passed into MasterContext.user_context hooks_override: Optional hooks to override default agent hooks run_config_override: Optional run configuration settings file_ids: List of OpenAI file IDs to attach to the message additional_instructions: Additional instructions for this run only agency_context: Injected AgencyContext (auto-created when running standalone) **kwargs: Additional keyword arguments forwarded to the agents SDK (e.g., max_turns) Returns: RunResult: The complete execution result from the agents SDK """ ``` ```python get_response_stream theme={null} def get_response_stream( self, message: str | list[TResponseInputItem], sender_name: str | None = None, context_override: dict[str, Any] | None = None, hooks_override: RunHooks | None = None, run_config_override: RunConfig | None = None, file_ids: list[str] | None = None, additional_instructions: str | None = None, agency_context: AgencyContext | None = None, **kwargs: Any, ) -> StreamingRunResponse: """ Run the agent's turn in streaming mode. Parameters: message: Input message or list of message items sender_name: Name of sending agent (None for user interactions) context_override: Run-scoped context passed into MasterContext.user_context hooks_override: Optional hooks to override default agent hooks run_config_override: Optional run configuration file_ids: List of OpenAI file IDs to attach to the message additional_instructions: Additional instructions for this run only agency_context: Injected AgencyContext (auto-created when running standalone) **kwargs: Additional keyword arguments forwarded to the agents SDK Returns: StreamingRunResponse: Async iterable over streamed events with access to the final result """ ``` ### Tool Management ```python add_tool theme={null} def add_tool(self, tool: Tool) -> None: """ Add a Tool instance to the agent's list of tools. Parameters: tool: The agents.Tool instance to add Raises: TypeError: If tool is not an instance of agents.Tool """ ``` ```python register_subagent theme={null} def register_subagent( self, recipient_agent: "Agent", send_message_tool_class: type | None = None, runtime_state: AgentRuntimeState | None = None, ) -> None: """ Register another agent as a subagent for communication. Creates a dynamic `send_message_to_` tool for inter-agent communication. Parameters: recipient_agent: The Agent instance to register as a recipient send_message_tool_class: Optional custom SendMessage override for this pair runtime_state: Optional runtime state container injected by the owning Agency Raises: TypeError: If recipient_agent is not a valid Agent instance ValueError: If attempting to register the agent itself as a subagent """ ``` ### File Management ```python upload_file theme={null} def upload_file(self, file_path: str, include_in_vector_store: bool = True) -> str: """ Upload a file using the agent's file manager. Parameters: file_path: Path to the file to upload include_in_vector_store: Whether to add file to vector store Returns: str: File ID of the uploaded file Raises: RuntimeError: If the agent has no file manager configured """ ``` # Agency Swarm Tutorials Source: https://agency-swarm.ai/tutorials/tutorials Learn how to use Agency Swarm to automate workflows through practical examples Deploy AI agents in your business using our template. Covers strategies, best practices, and examples. Create AI agent teams with Cursor template. Build a content creation agency step-by-step. Master async mode, parallel tool calling, and open-source model integration. Learn how to create AI agents that evolve and improve over time. Master advanced techniques for continuous learning, adaptation, and performance optimization. Real-world applications and implementations of AI agents in business automation. Integrate open source models and Assistance API v2 features into your projects. Learn AI agent development from scratch, including building a Social Media Marketing Agency. ## Example Projects Use GPT-4 Vision for QA testing. Create custom agents. # Agency Swarm vs Other Frameworks Source: https://agency-swarm.ai/welcome/ai-agency-vs-other-frameworks Compare Agency Swarm with other multi-agent AI frameworks. ## Summary In summary, Agency Swarm is the only framework that has: It doesn't write prompts for you, giving you full control over agent behavior. Prevents hallucinations with automatic type checking and error correction. Allows you to define communication flows in any way you want. ## Detailed Comparison Here's how Agency Swarm compares to 2 other most popular multi-agent frameworks. | **Criteria** | **Agency Swarm** | **AutoGen** | **CrewAI** | | - | - | - | - | | **Origins** | ✅ Originated from a real AI agency building AI agents for clients worldwide. | ✅ Originated as a research experiment. | ❌ Originated as a funding vehicle, rather than a real production framework. | | **Design & Architecture** | ✅ Super lightweight framework with minimal abstractions. Built on top of the OpenAI Assistants and Responses API. | ✅ Event-driven architecture with support for both ChatCompletions, Assistants and Responses API. | ❌ Lacks a clear architectural design. Built on top of LangChain with numerous unnecessary abstractions. | | **Reliability** | ✅ Robust type checking and validation for all tools with Pydantic. Input and output validation with agent's [guardrails system](/additional-features/guardrails/overview) | ❌ Type hints but no validation. | ❌ Some validation is possible when using BaseTool, although the interface is not convenient to use. | | **Flexibility** | ✅ No predefined prompts. Uniform communication. | ✅ Contains overridable predefined prompts. Customizable communication via GroupChat (model/custom speaker selection). | ❌ Numerous predefined prompts. Flows add conditional routing; customization remains limited. | | **Scalability** | ✅ Easily scalable. Adding another agent only requires passing it to the Agency class. | ⚠️ Simple to add agents; complex graphs need custom orchestration. | ⚠️ Easy to add agents; Flows enable conditional orchestration, but customization is limited. | | **Deployability** | ✅ Easily deployable with special [callback functions](/additional-features/deployment-to-production). Offers open-source templates and tutorials. | ⚠️ Studio for build/debug; production requires self-hosted SDK deployment. | ❌ Deployment via enterprise platform. No open-source deployment guides. | | **Open Source Model Support** | ✅ Supports over a dozen models through [LiteLLM SDK](https://docs.litellm.ai/docs). | ✅ Moderate open-source model support. | ✅ Full open-source model support. | If you want to challenge any of these claims, or if some of the issues disappear as frameworks mature, please open an issue on [GitHub](https://github.com/VRSEN/agency-swarm). ## Summary * **Agency Swarm** - best for **real business-oriented use cases**. * **AutoGen** - best for **research, experimentation and novel AI applications**. * **CrewAI** - best for **local development and playgrounds** with open-source models. # Cursor AI Source: https://agency-swarm.ai/welcome/getting-started/cursor-ide Getting started with Cursor.