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.
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.
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 ↗
02 / Bring your own knowledge
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.
01
Normalize
Route PDFs, images, Office files, archives and email into content artifacts with source provenance. Office conversion uses a configured converter.
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.
Carry conversation history through an agent session, with summarization options. Export and import messages when your application needs to save or move a conversation.
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.
Provider and storage integrations have their own optional dependencies and configuration. Conversation history lives in process unless exported; retrieval filters vary by backend.
03 / Give agents capabilities
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.
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.
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.
Package reusable instructions, configuration and declared resources as skills. Include their instructions in the agent context and load supporting references only when needed.
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.
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.
Explore real source for a model-backed document pipeline, local parallel orchestration, and a workflow that asks for human input.
Document processing
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.
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.
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.
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 = Noneasyncdef plan(state: MapReduceState) -> dict:
# No state mutation; the dispatch router below decides what runs next.return {}
asyncdef process_item(state: MapReduceState) -> dict:
assert state.item is not Nonereturn {"processed": [f"processed:{state.item}"]}
asyncdef 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]
asyncdef 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
Human input
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.
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")
asyncdef 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
returnawait agent(f"revise per feedback '{decision}': {draft}")
Exact source excerpt
06 / Make behavior observable
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.
01
Traces and explanations
Connect native OpenTelemetry instrumentation to the host’s exporters. Record pipeline events and build trace, audit and explanation reports.
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.
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.
Attach prompt and output guard middleware, validation and application-specific checks. These checks complement your service’s access controls and review policies.
Set MODEL and the matching provider credentials in your environment or local .env file. Follow the complete document example for ingestion, extraction and review.
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.