Metadata-Version: 2.4
Name: penguiflow
Version: 3.5.0
Summary: Async-first orchestration library for multi-agent and data pipelines
Author: PenguiFlow Team
License: MIT License
        
        Copyright (c) 2025 hurtener
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
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
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"
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.77.3; 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"
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>

Async-first orchestration library for **typed, reliable, concurrent** workflows — from deterministic data pipelines to LLM agents.

## Why PenguiFlow

- **Graph runtime**: run async node graphs with bounded queues (backpressure).
- **Reliability controls**: per-node timeouts + retries, plus per-trace cancellation and deadlines (envelope mode).
- **Streaming**: emit partial output (`StreamChunk`) and a final answer with deterministic correlation.
- **Planner (ReactPlanner)**: JSON-first tool orchestration with pause/resume (HITL), parallel fan-out + joins, and trajectory logging.
- **Tool integrations**: native + ToolNode (MCP / UTCP / HTTP) with auth and resilience patterns.

## Concepts at a glance

- **Flow**: a directed graph (runtime) you `run()`, `emit()` into, and `fetch()` results from.
- **Node**: an async function + `NodePolicy` (validation, retries, timeout).
- **Message** *(recommended for production)*: `Message(payload=..., headers=Headers(tenant=...), trace_id=...)` enabling trace correlation, cancellation, deadlines, and streaming.
- **StateStore** *(optional)*: durability/audit/event persistence for distributed and “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[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

### 1) Minimal typed flow (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) 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 (canonical)

- Docs site (MkDocs): https://hurtener.github.io/penguiflow/
- 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 follows a **2.x** line and aims to follow SemVer with a clear public surface.

- 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).
