Metadata-Version: 2.4
Name: penguiflow
Version: 3.11.2
Summary: Async-first orchestration library for multi-agent and data pipelines
Author: PenguiFlow Team
License-Expression: MIT
Project-URL: Homepage, https://github.com/hurtener/penguiflow
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic>=2.6
Requires-Dist: click>=8.1
Requires-Dist: pyyaml>=6.0
Requires-Dist: fastapi>=0.118
Requires-Dist: uvicorn>=0.32
Requires-Dist: databricks-mcp>=0.6.0
Requires-Dist: mcp<2,>=1.26
Provides-Extra: dev
Requires-Dist: mypy>=1.8; extra == "dev"
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: coverage[toml]>=7.0; extra == "dev"
Requires-Dist: hypothesis>=6.103; extra == "dev"
Requires-Dist: ruff>=0.2; extra == "dev"
Requires-Dist: ag-ui-protocol>=0.0.42; extra == "dev"
Requires-Dist: jsonschema>=4.23; extra == "dev"
Requires-Dist: fastapi>=0.118; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: jinja2>=3.1; extra == "dev"
Requires-Dist: pyyaml>=6.0; extra == "dev"
Requires-Dist: uvicorn>=0.32; extra == "dev"
Requires-Dist: tenacity>=9.0.0; extra == "dev"
Requires-Dist: aiohttp>=3.9.0; extra == "dev"
Requires-Dist: markitdown>=0.1.5; extra == "dev"
Requires-Dist: grpcio>=1.70.0; extra == "dev"
Requires-Dist: grpcio-status>=1.70.0; extra == "dev"
Requires-Dist: grpcio-tools>=1.70.0; extra == "dev"
Requires-Dist: googleapis-common-protos>=1.66.0; extra == "dev"
Requires-Dist: protobuf>=5.26.0; extra == "dev"
Requires-Dist: openai>=2.0.0; extra == "dev"
Requires-Dist: anthropic>=0.75.0; extra == "dev"
Requires-Dist: google-genai>=1.57.0; extra == "dev"
Requires-Dist: boto3>=1.42.0; extra == "dev"
Requires-Dist: pydantic-ai-slim[openai,openrouter]<2,>=1.107.0; extra == "dev"
Requires-Dist: genai-prices<1,>=0.0.66; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs>=1.6; extra == "docs"
Requires-Dist: mkdocs-material<9.7,>=9.6; extra == "docs"
Requires-Dist: mkdocstrings[python]>=0.25; extra == "docs"
Provides-Extra: cli
Requires-Dist: ag-ui-protocol>=0.0.42; extra == "cli"
Requires-Dist: jinja2>=3.1; extra == "cli"
Requires-Dist: fastapi>=0.118; extra == "cli"
Requires-Dist: uvicorn>=0.32; extra == "cli"
Provides-Extra: a2a-server
Requires-Dist: fastapi>=0.118; extra == "a2a-server"
Provides-Extra: a2a-grpc
Requires-Dist: grpcio>=1.70.0; extra == "a2a-grpc"
Requires-Dist: grpcio-status>=1.70.0; extra == "a2a-grpc"
Requires-Dist: grpcio-tools>=1.70.0; extra == "a2a-grpc"
Requires-Dist: googleapis-common-protos>=1.66.0; extra == "a2a-grpc"
Requires-Dist: protobuf>=5.26.0; extra == "a2a-grpc"
Requires-Dist: openai>=2.0.0; extra == "a2a-grpc"
Requires-Dist: anthropic>=0.75.0; extra == "a2a-grpc"
Requires-Dist: google-genai>=1.57.0; extra == "a2a-grpc"
Requires-Dist: boto3>=1.42.0; extra == "a2a-grpc"
Provides-Extra: a2a-client
Requires-Dist: httpx>=0.27; extra == "a2a-client"
Provides-Extra: planner
Requires-Dist: litellm>=1.94.0; extra == "planner"
Requires-Dist: dspy>=3.0.3; extra == "planner"
Requires-Dist: fastmcp>=3.0; extra == "planner"
Requires-Dist: utcp>=1.1.0; extra == "planner"
Requires-Dist: utcp-http>=1.0.0; extra == "planner"
Requires-Dist: tenacity>=9.0.0; extra == "planner"
Requires-Dist: aiohttp>=3.9.0; extra == "planner"
Requires-Dist: jsonschema>=4.23; extra == "planner"
Provides-Extra: web
Requires-Dist: aiohttp>=3.9.0; extra == "web"
Requires-Dist: markitdown>=0.1.5; extra == "web"
Provides-Extra: llm
Requires-Dist: openai>=2.0.0; extra == "llm"
Requires-Dist: anthropic>=0.75.0; extra == "llm"
Requires-Dist: google-genai>=1.57.0; extra == "llm"
Requires-Dist: boto3>=1.42.0; extra == "llm"
Requires-Dist: databricks-sdk>=0.77.0; extra == "llm"
Provides-Extra: tools-cli
Requires-Dist: utcp-cli>=1.0.0; extra == "tools-cli"
Provides-Extra: tools-websocket
Requires-Dist: utcp-websocket>=1.0.0; extra == "tools-websocket"
Provides-Extra: pricing
Requires-Dist: genai-prices<1,>=0.0.66; extra == "pricing"
Provides-Extra: pydantic-ai
Requires-Dist: pydantic-ai-slim[openai,openrouter]<2,>=1.107.0; extra == "pydantic-ai"
Requires-Dist: genai-prices<1,>=0.0.66; extra == "pydantic-ai"
Dynamic: license-file

# PenguiFlow

<p align="center">
  <img src="asset/Penguiflow.png" alt="PenguiFlow logo" width="220">
</p>

<p align="center">
  <a href="https://github.com/hurtener/penguiflow/actions/workflows/ci.yml"><img src="https://github.com/hurtener/penguiflow/actions/workflows/ci.yml/badge.svg" alt="CI Status"></a>
  <a href="https://pypi.org/project/penguiflow/"><img src="https://img.shields.io/pypi/v/penguiflow.svg" alt="PyPI version"></a>
  <a href="https://hurtener.github.io/penguiflow/"><img src="https://img.shields.io/badge/docs-mkdocs%20material-teal" alt="Docs"></a>
  <a href="https://nightly.link/hurtener/penguiflow/workflows/benchmarks/main/benchmarks.json.zip"><img src="https://img.shields.io/badge/benchmarks-latest-orange" alt="Benchmarks"></a>
  <a href="https://github.com/hurtener/penguiflow/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a>
</p>

A Python-native runtime for **typed, steerable, bounded** AI agents — and the deterministic pipelines under them.

PenguiFlow runs async node graphs where every hop validates its data, every run stays inside a budget, and the same core powers both a deterministic data pipeline and a tool-using agent. It is asyncio-only and built on Pydantic v2, with no heavy runtime dependencies.

## Why PenguiFlow

Many agent and pipeline frameworks are loosely-typed loops: a node returns the wrong shape and you find out several hops later, a planner runs past its budget with no ceiling, a crash loses the run's state, and approving a risky step means not automating it. PenguiFlow treats those as the framework's responsibility, not yours:

- **Typed at every boundary.** Each node validates its input and output against Pydantic models, so malformed data is caught at its source instead of downstream.
- **Bounded by design.** Bounded queues apply real backpressure; per-trace deadlines, hop budgets, and cancellation keep loops and fan-outs from running away.
- **Steerable mid-run.** Pause for human approval (HITL), inject steering events, and resume — without losing the trajectory so far.
- **Durable and observable.** An optional `StateStore` persists events for audit and recovery; every run carries a `trace_id`, can stream partial output, and records its trajectory.
- **One runtime for agents and pipelines.** The `ReactPlanner` (JSON-first tool orchestration, parallel fan-out and joins, pause/resume) runs on the exact same typed, bounded core as a plain data flow.

## Architecture at a glance

```
┌─────────────────────────────────────────────────────────────┐
│  Agents      ReactPlanner · ToolNode (MCP / UTCP / HTTP)      │
│              JSON tool loop · HITL pause/resume · fan-out/join│
├─────────────────────────────────────────────────────────────┤
│  Flow        async node graph · bounded queues (backpressure)│
│  runtime     routers · subflows · streaming                  │
├─────────────────────────────────────────────────────────────┤
│  Envelope    Message: trace_id · deadline · hop budget · meta │
│  Reliability per-node retries / timeouts · per-trace cancel   │
├─────────────────────────────────────────────────────────────┤
│  Ops         StateStore (durable events) · metrics / hooks    │
└─────────────────────────────────────────────────────────────┘
     emit()  ──►   typed in/out validated at every node   ──►  fetch()
```

## Concepts at a glance

- **Flow**: a directed graph (runtime) you `run()`, `emit()` into, and `fetch()` results from.
- **Node**: an async function plus a `NodePolicy` (validation, retries, timeout).
- **Message** *(recommended for production)*: `Message(payload=..., headers=Headers(tenant=...), trace_id=...)` enabling trace correlation, cancellation, deadlines, and streaming.
- **ReactPlanner** *(agents)*: a JSON-first planning loop over your tools, with pause/resume, parallel calls, and trajectory logging.
- **StateStore** *(optional)*: durability, audit, and event persistence for distributed, ops-ready deployments.

## Install

Requirements: Python **3.11+**

```bash
pip install penguiflow
```

Common extras:

```bash
pip install "penguiflow[planner]"      # ReactPlanner + ToolNode integrations
pip install "penguiflow[llm]"          # native LLM provider SDKs
pip install "penguiflow[a2a-server]"   # A2A HTTP+JSON server bindings
pip install "penguiflow[a2a-client]"   # A2A client bindings
```

If you use `uv`:

```bash
uv pip install penguiflow
```

## Quickstart

PenguiFlow has two entry points that share the same runtime: a **typed pipeline** you wire yourself, and an **agent** scaffolded from a template.

### 1) Typed pipeline (runtime)

```python
from __future__ import annotations

import asyncio

from pydantic import BaseModel

from penguiflow import ModelRegistry, Node, NodePolicy, create


class In(BaseModel):
    text: str


class Out(BaseModel):
    upper: str


async def to_upper(msg: In, _ctx) -> Out:
    return Out(upper=msg.text.upper())


async def main() -> None:
    node = Node(to_upper, name="to_upper", policy=NodePolicy(validate="both"))

    registry = ModelRegistry()
    registry.register("to_upper", In, Out)

    flow = create(node.to())
    flow.run(registry=registry)

    await flow.emit(In(text="hello"))
    result: Out = await flow.fetch()
    await flow.stop()

    print(result.upper)


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

### 2) Agent (ReactPlanner via CLI — fastest path)

```bash
uv run penguiflow new my-agent --template react
cd my-agent
uv sync
uv run penguiflow dev --project-root .
```

## Documentation

- Docs site (MkDocs): https://hurtener.github.io/penguiflow/
- API reference (every public symbol): https://hurtener.github.io/penguiflow/reference/api/
- Source docs in repo: [docs/](docs/)

Suggested starting points (in-repo sources):

- Getting started: [docs/getting-started/quickstart.md](docs/getting-started/quickstart.md)
- Core runtime: [docs/core/flows-and-nodes.md](docs/core/flows-and-nodes.md), [docs/core/messages-and-envelopes.md](docs/core/messages-and-envelopes.md)
- Planner: [docs/planner/overview.md](docs/planner/overview.md)
- Tool integrations: [docs/tools/configuration.md](docs/tools/configuration.md)
- Deployment runbooks: [docs/deployment/production-deployment.md](docs/deployment/production-deployment.md)
- Observability runbooks: [docs/observability/metrics-and-alerts.md](docs/observability/metrics-and-alerts.md)
- CLI: [docs/cli/overview.md](docs/cli/overview.md)

## Stability, versioning, and public API

PenguiFlow is on the **3.x** line and follows SemVer with a documented public API surface — additions are additive, and breaking changes are called out in the changelog.

- Changelog: [CHANGELOG.md](CHANGELOG.md)
- Versioning & deprecations: [VERSIONING.md](VERSIONING.md)
- Public API surface: [docs/reference/public-api.md](docs/reference/public-api.md)

## Contributing, security, and support

- Contributing: [CONTRIBUTING.md](CONTRIBUTING.md)
- Code of Conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
- Security: [SECURITY.md](SECURITY.md)
- Support: [SUPPORT.md](SUPPORT.md)

## License

MIT — see [LICENSE](LICENSE).
