Metadata-Version: 2.4
Name: swarmforge
Version: 0.7.0
Summary: Headless framework for multi-agent chat runtime and evaluation.
License-Expression: MIT
Project-URL: Homepage, https://github.com/Rvey/swarm-forge
Project-URL: Repository, https://github.com/Rvey/swarm-forge
Project-URL: Documentation, https://github.com/Rvey/swarm-forge/tree/main/docs
Project-URL: Issues, https://github.com/Rvey/swarm-forge/issues
Keywords: agents,multi-agent,swarm,openrouter,fastapi,evaluation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: openai>=1.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: api
Requires-Dist: fastapi>=0.104.0; extra == "api"
Requires-Dist: uvicorn>=0.24.0; extra == "api"
Provides-Extra: dev
Requires-Dist: build>=1.2.0; extra == "dev"
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: fastapi>=0.104.0; extra == "dev"
Requires-Dist: httpx>=0.27.0; extra == "dev"
Requires-Dist: twine>=5.1.0; extra == "dev"
Dynamic: license-file

# SwarmForge

SwarmForge is a Python package for authoring, running, and evaluating multi-agent swarms. You define the swarm graph, provide the model-turn callback, and keep sessions, handoffs, tools, checkpoints, and evaluation artifacts under your control.

- Explicit graph-based multi-agent runtime
- Python tool execution with inferred JSON schema
- OpenRouter, Gemini, and other OpenAI-compatible provider support
- FastAPI transport for stateless and session-backed HTTP flows
- Evaluation helpers for graph snapshots, scenario seeds, and artifact scoring

## Install

Python `3.11+` is required.

```bash
pip install swarmforge
```

If you want the FastAPI transport too:

```bash
pip install "swarmforge[api]"
```

Provider-backed examples, the demo UI, and local API runs load a nearby `.env` automatically. Copy `.env.example` to `.env`, then set `MODEL_PROVIDER`, `LLM_MODEL`, and the matching API key before using any runnable example:

```bash
cp .env.example .env
```

## Quick Start

The shortest path is a single-node swarm with a real provider-backed turn runner:

```python
import asyncio
import json

from swarmforge.env import require_env_vars
from swarmforge.evaluation.provider import ModelConfig, OpenAIClientWrapper
from swarmforge.swarm import (
    AgentTurnConfig,
    AgentTurnResult,
    InMemorySessionStore,
    SwarmDefinition,
    SwarmNode,
    SwarmSession,
    process_swarm_stream,
)


class ProviderBackedTurnRunner:
    def __init__(self) -> None:
        self.client = OpenAIClientWrapper(ModelConfig())

    async def run_turn(self, *, agent_node, contents, config: AgentTurnConfig):
        del agent_node
        messages = []
        if config.system_instruction:
            messages.append({"role": "system", "content": config.system_instruction})

        for item in contents:
            role = str(item.get("role") or "user").strip()
            if role == "model":
                role = "assistant"
            message = {"role": role, "content": item.get("content", "")}
            if role == "tool":
                if item.get("tool_call_id"):
                    message["tool_call_id"] = item.get("tool_call_id")
                if item.get("name"):
                    message["name"] = item.get("name")
            messages.append(message)

        response = self.client.chat_completion(messages=messages, tools=config.tools)
        assistant_message = response.choices[0].message
        tool_calls = []
        if assistant_message.tool_calls:
            for tool_call in assistant_message.tool_calls:
                args = tool_call.function.arguments
                if not isinstance(args, dict):
                    args = json.loads(args or "{}")
                tool_calls.append(
                    {
                        "id": tool_call.id,
                        "name": tool_call.function.name,
                        "args": args,
                    }
                )

        return AgentTurnResult(
            response_text=assistant_message.content or "",
            tool_calls=tool_calls,
            raw_response=response,
        )


swarm = SwarmDefinition(
    id="assistant",
    name="Assistant Swarm",
    nodes=[
        SwarmNode(
            id="assistant",
            node_key="assistant",
            name="Assistant",
            intent="Handle general requests",
            system_prompt="You are a concise assistant.",
            capabilities=["Answer questions"],
            is_entry_node=True,
        )
    ],
)


async def main():
    require_env_vars("MODEL_PROVIDER", "LLM_MODEL")
    session = SwarmSession(id="session-1", swarm=swarm)
    store = InMemorySessionStore()
    async for event in process_swarm_stream(
        session,
        "Give me a concise summary.",
        store=store,
        turn_runner=ProviderBackedTurnRunner(),
    ):
        print(json.dumps(event, indent=2))


if __name__ == "__main__":
    asyncio.run(main())
```

The final `done` event contains the real model output, so the wording varies by provider and model. When you are ready to add routing, continue with the multi-agent flow in the docs.

## Package Surfaces

- `swarmforge.swarm`
  Runtime models, session state, orchestration, tool execution, and stores.
- `swarmforge.authoring`
  Prompt templates, payload validation, and graph compilation helpers.
- `swarmforge.evaluation`
  Graph snapshots, scenario generation, feasibility checks, and artifact scoring.
- `swarmforge.api`
  FastAPI application factory built on the same runtime primitives.

## Providers

SwarmForge ships with an OpenAI-compatible provider wrapper. OpenRouter is the default path, and Gemini is built in as an alternative mode.

Start from the repository `.env.example` and explicitly set both the provider and the model you want to use.

OpenRouter `.env`:

```dotenv
MODEL_PROVIDER=openrouter
LLM_MODEL=openrouter/auto
OPENROUTER_API_KEY=sk-or-...
OPENROUTER_SITE_URL=https://your-app.example
OPENROUTER_APP_NAME="Your App Name"
```

Gemini `.env`:

```dotenv
MODEL_PROVIDER=gemini
LLM_MODEL=gemini-3-flash-preview
GEMINI_API_KEY=...
```

Minimal client setup:

```python
from swarmforge.evaluation.provider import ModelConfig, OpenAIClientWrapper

client = OpenAIClientWrapper(ModelConfig())
```

`ModelConfig()` reads `MODEL_PROVIDER`, `LLM_MODEL`, and the matching API key from `.env` or the shell environment.

## FastAPI Transport

You can expose the runtime over HTTP without changing your swarm definitions:

```bash
pip install "swarmforge[api]"
uvicorn swarmforge.api.fastapi:create_fastapi_app --factory --reload
```

That app exposes both stateless run endpoints and session-backed endpoints with SSE streaming.

## Documentation

- [Getting Started](https://github.com/Rvey/swarm-forge/blob/main/docs/getting-started.md)
- [Create Your First Agent](https://github.com/Rvey/swarm-forge/blob/main/docs/create-first-agent.md)
- [Create Your First Multi-Agent Swarm](https://github.com/Rvey/swarm-forge/blob/main/docs/create-first-multi-agent-swarm.md)
- [Authoring](https://github.com/Rvey/swarm-forge/blob/main/docs/authoring.md)
- [Orchestration](https://github.com/Rvey/swarm-forge/blob/main/docs/orchestration.md)
- [Providers](https://github.com/Rvey/swarm-forge/blob/main/docs/providers.md)
- [API](https://github.com/Rvey/swarm-forge/blob/main/docs/api.md)
- [Evaluation](https://github.com/Rvey/swarm-forge/blob/main/docs/evaluation.md)
- [Examples](https://github.com/Rvey/swarm-forge/blob/main/docs/examples.md)

## Source Examples

The repository includes end-to-end example scripts under [examples/](https://github.com/Rvey/swarm-forge/tree/main/examples). Those scripts are useful when you want runnable reference flows for authoring, orchestration, evaluation, provider integration, or FastAPI transport. Provider-backed examples and the local FastAPI example read from `.env.example`-style settings.

The demo UI under `demo-ui/` reads the same root `.env` for its default API base, provider, and model. Its Vite scripts create `.env` from `.env.example` automatically when the file is missing.

## Contributing

Core modification, docs development, demo UI work, and PyPI release steps are documented in [CONTRIBUTING.md](https://github.com/Rvey/swarm-forge/blob/main/CONTRIBUTING.md).
