Skip to main content

A multi-agent orchestration framework for Python develpoed by Sajib Hossain

Project description

Squadria

squadria is a lightweight Python framework for orchestrating role-based AI agents. It gives you simple building blocks to define an assistant persona, assign tasks, and run multi-step workflows where one step can feed context into the next.

Features

  • Persona-driven agents (Actor) with configurable LLM abstraction
  • Structured task objects (Job) with expected output guidance
  • Sequential, parallel, and hierarchical orchestration (Squad)
  • Plugin abstraction (Plugin) with automatic parameter schema generation
  • Small, readable core focused on extensibility

Installation

pip install squadria

Quick Start

Set your provider API key first (example for OpenAI):

export OPENAI_API_KEY="your_api_key_here"

Sequential Execution

Create and run a simple two-step workflow where each job can use prior job context:

from squadria import Actor, Job, Squad

researcher = Actor(
    title="Senior Tech Researcher",
    objective="Find practical trends in AI tooling.",
    expertise="You analyze current AI engineering practices.",
    tone=["concise", "analytical"],
    language="English",
    model="gpt-4o-mini",
    verbose=True,
    trace_level="minimal",
    guardrails=["personal_info", "medicine"],
)

writer = Actor(
    title="Technical Writer",
    objective="Turn research into a clear summary.",
    expertise="You explain technical topics for developers.",
    tone=["clear", "engaging"],
    language="English",
    model="gpt-4o-mini",
    verbose=True,
)

research_job = Job(
    description="List 3 current trends in AI agent frameworks.",
    expected_output="Three bullet points with one sentence each.",
    actor=researcher,
    max_retries=10,
)

writing_job = Job(
    description="Write a short 2-paragraph overview from the research context.",
    expected_output="Two short paragraphs.",
    actor=writer,
)

squad = Squad(
    actors=[researcher, writer],
    jobs=[research_job, writing_job],
    process="sequential",
    trace_level="minimal",
)

final_result = squad.kickoff()
print(final_result)

Using a Dedicated LLM Object

Use LLM(...) when you want model-level controls in one place.

from squadria import Actor, Job, LLM, Squad

llm = LLM(
    model="gpt-4o-mini",
    temperature=0.2,
    timeout=120,
    max_tokens=1200,
)

agent = Actor(
    title="Concise Analyst",
    objective="Answer clearly and briefly.",
    expertise="You provide practical summaries.",
    tone=["concise"],
    llm=llm,
    verbose=True,
)

job = Job(
    description="Summarize why orchestration frameworks are useful.",
    expected_output="A short practical summary.",
    actor=agent,
)

squad = Squad(actors=[agent], jobs=[job], process="sequential")
print(squad.kickoff())

Supported LLM(...) parameters include:

  • model
  • temperature
  • timeout
  • max_tokens
  • top_p
  • frequency_penalty
  • presence_penalty
  • stop
  • base_url
  • api_key
  • custom_params (forwarded to LiteLLM)

custom_params cannot override reserved keys: model, messages, tools.

Define Client Once, Reuse Across LLMs

With a client-first setup, you can define one client and reuse it for multiple LLM objects.

from squadria import Actor, Job, LLM, LiteLLMClient, Squad

shared_client = LiteLLMClient()

research_llm = LLM(model="gpt-4o-mini", temperature=0.2, client=shared_client)
writer_llm = LLM(model="gpt-4o-mini", temperature=0.7, client=shared_client)

researcher = Actor(
    title="Researcher",
    objective="Find key points.",
    expertise="You summarize concise findings.",
    llm=research_llm,
)

writer = Actor(
    title="Writer",
    objective="Write clean final output.",
    expertise="You convert notes to readable prose.",
    llm=writer_llm,
)

jobs = [
    Job(
        description="List three practical insights about orchestration frameworks.",
        expected_output="Three concise bullets.",
        actor=researcher,
    ),
    Job(
        description="Turn the insights into two short paragraphs.",
        expected_output="Two clear paragraphs.",
        actor=writer,
    ),
]

squad = Squad(actors=[researcher, writer], jobs=jobs, process="sequential")
print(squad.kickoff())

Custom Client Implementation

If you want full transport control, implement BaseLLMClient and plug it into LLM.

from typing import Any, Dict
from squadria import BaseLLMClient, LLM

class MyClient(BaseLLMClient):
    def complete(self, payload: Dict[str, Any]) -> Any:
        # Send payload to your own gateway/provider here.
        # Return a provider response object (any shape).
        return {"text": "Final Output: Hello from custom client"}

    def extract_text(self, response: Any) -> str:
        # Convert your provider response shape into plain text.
        return str(response.get("text", ""))

llm = LLM(
    model="my-gateway-model",
    client=MyClient(),
)

Custom LLM Implementation

Use BaseLLM when you want a fully custom provider/client implementation.

from typing import Dict, List, Optional
from squadria import Actor, BaseLLM, Job, Squad

class CustomLLM(BaseLLM):
    def call(self, messages, tools: Optional[List[dict]] = None) -> str:
        if isinstance(messages, str):
            prompt = messages
        else:
            prompt = "\n".join(
                f"{item.get('role', 'user')}: {item.get('content', '')}" for item in messages
            )
        return f"Final Output: Custom provider response for -> {prompt[:120]}"

custom_llm = CustomLLM(model="my-custom-model")

agent = Actor(
    title="Custom LLM Agent",
    objective="Use a custom model backend.",
    expertise="You route through a custom LLM implementation.",
    tone=["concise"],
    llm=custom_llm,
)

job = Job(
    description="Explain why custom LLM interfaces are useful.",
    expected_output="A short practical explanation.",
    actor=agent,
)

squad = Squad(actors=[agent], jobs=[job], process="sequential")
print(squad.kickoff())

Parallel Execution

Use parallel mode when jobs are independent and do not need chained context.

from squadria import Actor, Job, Squad

researcher = Actor(
    title="Research Analyst",
    objective="Collect concise findings.",
    expertise="You summarize important points quickly.",
    tone=["concise", "analytical"],
    language="English",
    model="gpt-4o-mini",
    verbose=True,
)

reviewer = Actor(
    title="Risk Reviewer",
    objective="Identify practical risks clearly.",
    expertise="You review technical trade-offs.",
    tone=["direct", "clear"],
    language="English",
    model="gpt-4o-mini",
    verbose=True,
)

benefits_job = Job(
    description="List 3 practical benefits of multi-agent orchestration.",
    expected_output="Three bullet points.",
    actor=researcher,
    max_retries=10,
)

risks_job = Job(
    description="List 3 practical risks of multi-agent orchestration.",
    expected_output="Three bullet points.",
    actor=reviewer,
    max_retries=10,
)

squad = Squad(
    actors=[researcher, reviewer],
    jobs=[benefits_job, risks_job],
    process="parallel",
    trace_level="minimal",
)

final_result = squad.kickoff()
print(final_result)

Hierarchical Execution

Use a manager actor to plan subtasks, delegate them to workers, and synthesize final output.

from squadria import Actor, Job, Squad

manager = Actor(
    title="Engineering Manager",
    objective="Break goals into tasks and synthesize final output.",
    expertise="You are strong at decomposition and delegation.",
    tone=["structured", "decisive"],
    language="English",
    model="gpt-4o-mini",
)

researcher = Actor(
    title="Research Analyst",
    objective="Collect evidence quickly.",
    expertise="You summarize findings with references.",
    tone=["concise"],
    language="English",
    model="gpt-4o-mini",
)

writer = Actor(
    title="Technical Writer",
    objective="Write clear final prose.",
    expertise="You communicate complex ideas simply.",
    tone=["clear"],
    language="English",
    model="gpt-4o-mini",
)

top_level_job = Job(
    description="Create a short brief on modern AI agent orchestration patterns.",
    expected_output="A concise, structured brief.",
    actor=manager,
    max_retries=10,
)

squad = Squad(
    actors=[manager, researcher, writer],
    jobs=[top_level_job],
    process="hierarchical",
    manager=manager,
)

result = squad.kickoff()
print(result)

Core Concepts

Persona Configuration

Defines the personality and constraints for an agent:

  • title: role name
  • objective: what the agent tries to achieve
  • expertise: domain background for grounding
  • tone: list of style adjectives
  • language: response language (default: English)

Actor accepts these fields directly as constructor parameters.

Actor

Wraps LLM execution. It:

  • auto-generates a unique id (UUID string)
  • accepts persona fields directly: title, objective, expertise, optional tone, optional language
  • accepts either model="..." or llm=LLM(...)
  • accepts optional guardrails (built-in and custom)
  • when verbose=True, prints step-by-step console traces
  • accepts optional trace_level (minimal or detailed, default: minimal)
  • builds a system prompt from persona data
  • optionally includes plugin descriptions
  • delegates model calls through the LLM object
  • returns the model output text

LLM, BaseLLM, and Client Layer

  • LLM is Squadria's default model wrapper and supports common generation parameters.
  • BaseLLM is the abstract interface for custom providers.
  • BaseLLMClient is the transport contract used by LLM and defines:
    • complete(payload) to send requests
    • extract_text(response) to normalize response text
  • LiteLLMClient is the default production client implementation.
  • You can pass llm=LLM(...) to an Actor for advanced configuration, or use model="..." for quick setup.

Guardrails

Guardrails are optional Actor-level safety constraints.

Built-in guardrail keys:

  • personal_info
  • medicine
  • self_harm
  • violence
  • illegal_activities
  • financial_advice

You can configure them with:

  • built-ins as strings: guardrails=["medicine", "personal_info"]
  • object-style custom rules: guardrails=["medicine", {"name": "no_legal_advice", "rule": "Do not provide legal advice.", "severity": "high"}]

For custom rules, only rule is required. name and severity are optional metadata.

Job

Represents a single task with:

  • description
  • expected_output
  • actor
  • optional context
  • optional max_retries (default: 10)
  • auto-generated id (UUID string)

Squad

Supports three process modes:

  • sequential: chains context from one job to the next
  • parallel: executes all jobs concurrently and returns combined ordered output
  • hierarchical: manager plans worker tasks (JSON plan), workers execute, manager synthesizes final output
  • auto-generated id (UUID string)
  • optional trace_level (minimal or detailed, default: minimal)

Plugin

Wraps a Python function into a reusable capability object and generates a JSON schema for function arguments using Pydantic.

Plugin Example

from squadria.plugins.base import Plugin

def add(a: int, b: int) -> int:
    return a + b

math_plugin = Plugin(
    name="adder",
    description="Adds two numbers",
    func=add,
)

print(math_plugin.execute(a=2, b=3))  # 5
print(math_plugin.get_description())   # includes auto-generated schema

API Surface

Top-level imports available from squadria:

  • Actor
  • BaseLLM
  • BaseLLMClient
  • Job
  • LLM
  • LiteLLMClient
  • Plugin
  • Squad

Persona schema classes are internal implementation details and are not part of the top-level public interface.

Notes

  • Current orchestration modes are sequential, parallel, and hierarchical.
  • Hierarchical mode requires manager=... and at least one worker actor.
  • Ensure your API key is set for the model provider you choose.
  • This framework is intentionally minimal and designed to be extended.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

squadria-0.1.9.tar.gz (13.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

squadria-0.1.9-py3-none-any.whl (20.0 kB view details)

Uploaded Python 3

File details

Details for the file squadria-0.1.9.tar.gz.

File metadata

  • Download URL: squadria-0.1.9.tar.gz
  • Upload date:
  • Size: 13.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for squadria-0.1.9.tar.gz
Algorithm Hash digest
SHA256 611b42cb4130a4281d361499958fcea2d8d6d17c1f18cc9bc0c83137106644a5
MD5 e7465994518b74770355c72d0aa58d2e
BLAKE2b-256 2ea13b672461e417ea95842310f6db1ee4d450df3a51d832a0685962067dc072

See more details on using hashes here.

File details

Details for the file squadria-0.1.9-py3-none-any.whl.

File metadata

  • Download URL: squadria-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 20.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for squadria-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 dd4b2b8d2f63b12ff64ff6502cd0983fccfd76362fa5b208fc757d5aecfc6b87
MD5 ae38e18eb0efac9bb515ac89f14837db
BLAKE2b-256 01f8cdf4630db69f442fffe1017b7fc1835320105b13e1d7b9d33b2be8c14588

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page