Skip to content

FastAPI Tools Swarm Example ​

This page embeds the full source for examples/fastapi_tools_swarm.py.

python
"""Example: expose a code-defined swarm with shared runtime tools through FastAPI."""

from __future__ import annotations

import uvicorn

from swarmforge.api import create_swarm_app
from swarmforge.env import get_env, get_env_int
from swarmforge.swarm import SwarmDefinition, SwarmNode, SwarmVariable, function_tool


SHARED_STATE = {"tenant": "acme"}


async def lookup_order(order_id: str, context=None, state=None):
    """Fetch order status for a customer order."""

    return {
        "order_id": order_id,
        "tenant": (state or context.shared_state)["tenant"],
        "account_id": context.state.get("account_id"),
        "status": "shipped",
    }


TOOL_SWARM = SwarmDefinition(
    id="ops",
    name="Ops Swarm",
    nodes=[
        SwarmNode(
            id="ops-agent",
            node_key="ops",
            name="Ops",
            system_prompt="Use lookup_order when the user asks for an order update.",
            enabled_tools=[function_tool(handler=lookup_order)],
            is_entry_node=True,
        )
    ],
    variables=[
        SwarmVariable(
            key_name="account_id",
            description="Customer account identifier shared with tools",
            reducer_rule="overwrite",
        )
    ],
)


app = create_swarm_app(
    TOOL_SWARM,
    tool_state=SHARED_STATE,
    title="Swarm Tool API",
)


if __name__ == "__main__":
    uvicorn.run(
        app,
        host=get_env("SWARMFORGE_HOST", default="127.0.0.1") or "127.0.0.1",
        port=get_env_int("SWARMFORGE_PORT", default=8000),
    )

Run:

bash
python examples/fastapi_tools_swarm.py

Communicate with the API using curl:

  1. Create a session with an initial variable payload:
bash
curl -X POST http://127.0.0.1:8000/sessions \
    -H 'Content-Type: application/json' \
    -d '{
        "session_id": "ops-1",
        "state": {
            "account_id": "ACME-991"
        }
    }'
  1. Send a message with a per-turn payload containing variables and user input:
bash
curl -X POST http://127.0.0.1:8000/sessions/ops-1/messages \
    -H 'Content-Type: application/json' \
    -d '{
        "user_input": "Where is order 123?",
        "state": {
            "account_id": "ACME-991"
        }
    }'

Expected return (example shape):

json
{
    "events": [
        { "event": "open",       "data": { "currentAgent": "Ops" } },
        { "event": "tool_use",   "data": { "agentName": "Ops", "functionCalls": [{ "name": "lookup_order" }] } },
        { "event": "text_chunk", "data": { "text_chunk": "Order 123 ", "agentName": "Ops" } },
        { "event": "text_chunk", "data": { "text_chunk": "has shipped.", "agentName": "Ops" } },
        { "event": "done",       "data": { "fullText": "Order 123 has shipped.", "agentName": "Ops" } }
    ],
    "session": {
        "id": "ops-1"
    },
    "checkpoints": []
}

The exact event list and final text can vary by model, but the response always includes events, session, and checkpoints.

Fast mode variant ​

You can enable fast mode on the same swarm to skip the model turn and run lookup_order directly. Add behavior_config={"fast_mode_enabled": True} to the node, mark the tool with "fast_enabled": True, and optionally send per-turn arguments through fast_tool_params in the request state:

bash
curl -X POST http://127.0.0.1:8000/sessions/ops-1/messages \
  -H 'Content-Type: application/json' \
  -d '{
    "user_input": "Track my order",
    "state": {
      "fast_tool_params": {
        "lookup_order": {"order_id": "A-99"}
      }
    }
  }'

When fast mode triggers, the event sequence becomes ["open", "fast_tool_use", "done"] instead of the usual model-turn events.

Released as open source.