Firefly Agentic

From a single agent. To a complete system.

Build AI applications with typed agents, coordinated workflows and knowledge from your own data. Connect tools, review decisions and follow each run—all in composable Python, built on Pydantic AI.

One application. Composable intelligence.
Runtime & foundation
  • Python 3.13+
  • Pydantic AI
  • Async Python
Explore on GitHub

Give intelligence a path to follow.

Some work follows a graph. Some unfolds as Python runs. Firefly Agentic supports both, so you can coordinate specialized agents without hiding the application’s control flow.

PipelineBuilder

Stateful pipelines

Define a graph of agents and ordinary functions around typed, shared state. Route on results, merge parallel work and add a review gate where the application needs one.

  • Pydantic state and field reducers
  • Conditional routes, cycles and Send fan-out
  • Node timeouts, retries and checkpoint recovery
Explore this programming model

@workflow

Dynamic Python workflows

Write an async function with @workflow. Call specialized agents, fan out with parallel or map_agents, and use normal Python to combine their outputs.

  • Typed sub-agent calls and streaming
  • Shared concurrency and usage controls
  • Journaled calls and human-input interrupts
Explore this programming model

Choose the persistence backend and the approval policy for your application. Graph checkpoints restore pipeline state; workflow journals reuse recorded call outputs when the Python function runs again. How journals work

Turn your data into useful context.

Compose the path from a source document to relevant context. Keep retrieval, memory and model calls as separate pieces you can inspect and replace.

  1. Normalize

    Route PDFs, images, Office files, archives and email into content artifacts with source provenance. Office conversion uses a configured converter.

    Explore normalize
  2. Chunk

    Split text or chunk Markdown by headings and retain section breadcrumbs. Choose compression when context needs to be shorter.

    Explore chunk
  3. Embed

    Use a shared embedding interface with provider adapters and batching. EmbeddingStep connects vector generation to a pipeline.

    Explore embed
  4. Retrieve

    Search a selected vector backend and pass matching results into the next step. Scope namespaces to a tenant and workspace when your application needs it.

    Explore retrieve

Embedding adapters

OpenAI · Azure OpenAI · Cohere · Google · Mistral · Voyage AI · Amazon Bedrock · Ollama

Vector storage

In-memory · Chroma · SQLite-vec · Pinecone · Qdrant · pgvector

Conversation memory

Carry conversation history through an agent session, with summarization options. Export and import messages when your application needs to save or move a conversation.

Explore memory

Working memory

Keep intermediate facts and task context in scopes. Select an in-memory, file, SQLite, PostgreSQL or MongoDB store for the data your application needs to retain.

Explore memory

Provider and storage integrations have their own optional dependencies and configuration. Conversation history lives in process unless exported; retrieval filters vary by backend.

Connect the tools.
Keep the boundaries.

Bring your application’s knowledge and actions into each agent. Choose its output contract, available tools and reusable skills.

Connecting from Java?
Typed agents, reusable expertise

Return structured Pydantic outputs, inject application dependencies and compose instructions. Classifier, extractor, router, summarizer and conversational templates provide starting points.

Read the implementation
Specialists that work together

Delegate to a selected agent or fan a task out to multiple agents and combine their results. Workflow runners can target configured FireflyAgent instances and registry names.

Read the implementation
Tools from your application

Expose Python functions with @firefly_tool, group them in ToolKit, and add validation, timeouts or caching. Native Pydantic AI toolsets provide an integration path for MCP tools.

Read the implementation
Reusable skills and resources

Package reusable instructions, configuration and declared resources as skills. Include their instructions in the agent context and load supporting references only when needed.

Read the implementation
Human approval at the action boundary

Mark native tools as requiring approval. Deferred tool requests let the host collect approvals or denials and resume the agent. Pipelines also support an explicit Pause gate.

Read the implementation
Optional sandboxed Python execution

Use the Monty execution extra for Python snippets with explicit host functions and resource limits. The host controls the functions exposed to the sandbox and their authorization.

Read the implementation

Choose a strategy. Review the result.

Use reasoning patterns as application components, then check outputs against the criteria that matter to your workflow.

Validate before accepting

Combine schemas, rule checks and grounding checks. OutputReviewer feeds validation feedback into bounded retries.

Read the implementation

Evaluate what you retrieve

Measure retrieval with precision, recall, MRR and nDCG; use model-based evaluators for answer quality when configured.

Read the implementation

Compare and refine

Use verification loops, adversarial review, judge panels and cascades with explicit acceptance criteria.

Read the implementation

See the parts work together.

Explore real source for a model-backed document pipeline, local parallel orchestration, and a workflow that asks for human input.

From a document to reviewed, structured data.

The repository’s document-processing example combines ingestion, classification, typed extraction, validation and an explanation of the result. Each stage is an explicit node with its own execution policy.

  • A PDF tool supplies page-marked text to the pipeline.
  • An extraction agent uses a toolkit, scoped memory and structured output review.
  • Validation can call Reflexion to revise failed fields before assembly.
Open the complete source

Exact repository excerpt; step definitions and setup are in the linked file. Running the complete example requires a configured model, credentials, network access and PDF dependencies.

examples/idp_pipeline.pyPython
def build_pipeline():
    """Build the IDP pipeline DAG with event handler."""
    dag = (
        PipelineBuilder("idp-pipeline")
        .add_node("ingest", CallableStep(ingest_step), timeout_seconds=90)
        .add_node("split", CallableStep(split_step_fn), timeout_seconds=120)
        .add_node("classify", CallableStep(classify_step_fn), timeout_seconds=180)
        .add_node(
            "extract",
            CallableStep(extract_step_fn),
            retry_max=1,
            timeout_seconds=300,
        )
        .add_node("validate", CallableStep(validate_step_fn), timeout_seconds=180)
        .add_node("assemble", CallableStep(assemble_step_fn))
        .add_node("explain", CallableStep(explain_step_fn), timeout_seconds=120)
        .chain(
            "ingest",
            "split",
            "classify",
            "extract",
            "validate",
            "assemble",
            "explain",
        )
        .build_dag()
    )
    return PipelineEngine(dag, event_handler=IDPEventHandler())
Exact source excerpt

Dispatch the work. Merge the results.

This local example isolates the orchestration mechanics: one Send per item, concurrent workers, and an extend reducer that accumulates their updates before aggregation.

  • Each worker receives its own item in typed state.
  • Returned updates merge through the declared field reducer.
  • The common successor reads the collected results.
Open the complete source

Exact repository excerpt using ordinary Python functions. It runs without a model or credentials; the processed strings demonstrate state flow, not generated AI results.

examples/pipeline_state.pyPython
class MapReduceState(BaseModel):
    items: list[str] = []
    processed: Annotated[list[str], extend] = []
    summary: str | None = None
    # Per-Send payload field — each worker receives its own item here.
    item: str | None = None


async def plan(state: MapReduceState) -> dict:
    # No state mutation; the dispatch router below decides what runs next.
    return {}


async def process_item(state: MapReduceState) -> dict:
    assert state.item is not None
    return {"processed": [f"processed:{state.item}"]}


async def aggregate(state: MapReduceState) -> dict:
    return {"summary": f"Processed {len(state.processed)} items: {state.processed}"}


def dispatch(state: MapReduceState) -> list[Send]:
    # One Send per item — workers run concurrently. The ``extend`` reducer on
    # ``processed`` merges all worker outputs into one list.
    return [Send("process_item", {"item": x}) for x in state.items]


async def run_map_reduce() -> None:
    print("=== 2. Map-reduce via Send ===\n")

    pipeline = (
        PipelineBuilder("mapreduce", state=MapReduceState)
        .add_node(plan)
        .add_node(process_item)
        .add_node(aggregate)
        .add_edge(process_item, aggregate)
        .branch(plan, dispatch)
        .build()
    )
    result = await pipeline.invoke(MapReduceState(items=["alpha", "beta", "gamma", "delta"]))
    print(f"  summary: {result.state.summary}")
Exact source excerpt

Let a workflow ask before continuing.

This documented workflow drafts a reply, requests human input and either returns the approved draft or asks an agent to revise it. The implementation raises an interrupt at human() and records the supplied response in a journal.

  • The workflow is an ordinary async Python function.
  • agent() returns the configured agent’s output.
  • human() pauses for input; the host supplies it and re-runs with the same journal.
Open the complete source

Exact documentation excerpt, backed by the workflow runtime and human-input tests. Imports, runner/model setup and the host’s interrupt/resume handler are in the linked guide; model calls require configuration.

docs/workflows.mdPython
@workflow(name="triage")
async def triage(args, ctx):
    draft = await agent(f"draft a reply to: {args}")
    decision = await human(f"Approve this reply?\n\n{draft}")
    if decision.lower().startswith("y"):
        return draft
    return await agent(f"revise per feedback '{decision}': {draft}")
Exact source excerpt

Understand the run. Control the next one.

Make agent behavior part of your application’s operations, with visibility into model calls, tools, latency and usage.

Traces and explanations

Connect native OpenTelemetry instrumentation to the host’s exporters. Record pipeline events and build trace, audit and explanation reports.

Explore the implementation

Usage and cost awareness

Track tokens, latency and resolved model costs. Configure quota checks, usage thresholds and cost middleware for your workload; in-flight calls can exceed recorded usage thresholds.

Explore the implementation

Resilience and model selection

Configure retries, circuit breakers and fallback models. Model specifications hold provider settings and credential references; workflow routing can select models by cost or task complexity.

Explore the implementation

Guards around inputs and outputs

Attach prompt and output guard middleware, validation and application-specific checks. These checks complement your service’s access controls and review policies.

Explore the implementation

Explore locally. Then connect a model.

Start with reproducible orchestration, then move to the model-backed example that matches your application. Use Python 3.13+ and uv.

  1. Install the framework and examples

    Clone the source and install its documented optional integrations. For your own project, select only the extras you need.

    git clone https://github.com/fireflyframework/fireflyframework-agentic.git
    cd fireflyframework-agentic
    uv sync --all-extras
    Follow this step
  2. Run state, parallelism and approval locally

    Exercise branching, Send fan-out, reducers and checkpoint resume using ordinary Python functions. This example needs no model account or API key.

    uv run python examples/pipeline_state.py
    Follow this step
  3. Connect the model for your application

    Set MODEL and the matching provider credentials in your environment or local .env file. Follow the complete document example for ingestion, extraction and review.

    uv run python examples/idp_pipeline.py
    Follow this step

A separate bridge for Java services.

Firefly Agentic Bridge is a Java client project for calling a hosted agentic service. The Python core runs inside an application and does not expose a server itself; connect the bridge to a host that implements its expected service contract.

  • Reactive Java client

    The client exposes single responses with Reactor Mono and event streams with Flux, so calls can participate in a reactive Java application.

    Explore the implementation
  • HTTP calls and streamed events

    The REST transport sends agent requests and decodes server-sent events, with configurable timeouts, retries and authentication headers.

    Explore the implementation

Keep building.

Start with the guides. Follow the source. Shape the system around your application.

Implementation references

Content reviewed against the source on 2026-09-24. Examples and implementation links are pinned to the reviewed revision.

Part of a wider ecosystem.

One approach to enterprise applications. Explore the framework that fits your team.

Explore the frameworks