Metadata-Version: 2.4
Name: nuncio
Version: 0.1.3
Summary: Nuncio Communication Protocol Core Python SDK
License: Apache-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: protobuf<7.0.0,>=6.31.1
Requires-Dist: websockets>=12.0
Provides-Extra: dev
Requires-Dist: grpcio-tools>=1.80.0; extra == "dev"
Dynamic: license-file

# Nuncio Python SDK (`nuncio`)

[![License: Apache-2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
[![Python Versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-indigo.svg)](#)

Python SDK for the **Nuncio Communication Protocol**—the open-source, cooperative peer-to-peer agent communication standard.

---

## 🌟 Overview

Nuncio makes agent‑to‑agent and tool-using communication simple, bi-directional, and robust. It gives you a clean, versioned binary envelope, a predictable handshake, and native patterns for routing, negotiation, text streaming, and errors—all over WebSockets using Google Protocol Buffers (v3).

This SDK implements the Nuncio specification, making it easy to:
*   **Build Nuncio Clients** that connect to any peer or router.
*   **Create Nuncio Server Routers** that coordinate and route messages between agents.
*   **Utilize Standardized Envelopes** for RPC execution, streaming chunks, capability negotiation, and peer discovery.
*   **Suspend Workflows** cleanly using native human-in-the-loop approval intercepts.

---

## 📦 Installation

Install the official package via pip:
```bash
pip install nuncio
```

Or using `uv`:
```bash
uv pip install nuncio
```

---

## 🚀 Quickstart

Get a P2P agent connection running in less than a minute.

### 1. Start the Nuncio Router/Server
Create a server that routes envelopes to agents based on their specific roles (e.g. `RESEARCH_AGENT`):

```python
from nuncio.server import NuncioServer

# Initialize the router server
server = NuncioServer(host="127.0.0.1", port=8080)
print("Starting Nuncio Router on port 8080...")
server.run()
```

### 2. Connect Client A (The Tool-Providing Responder)
This client registers as `RESEARCH_AGENT` and responds to requests:

```python
import asyncio
from nuncio.client import NuncioClient, NuncioBuilders
from nuncio.nuncio_pb2 import MessageType

async def main() -> None:
    # Initialize connection registration
    client = NuncioClient(
        uri="ws://localhost:8080/nuncio",
        role="RESEARCH_AGENT",
        agent_id="research-alpha",
        token="demo-token",
        capabilities=["web_search", "code_eval"],
    )
    await client.connect()
    print("Research Agent online & waiting for tasks...")

    while True:
        incoming = await client.recv_envelope()
        
        # Respond to requests
        if incoming.type == MessageType.REQUEST:
            print(f"Received Request: {incoming.request.intent} (ID: {incoming.request.request_id})")
            
            response = NuncioBuilders.response(
                intent=incoming.request.intent,
                request_id=incoming.request.request_id,
                content="Search results: Nuncio is an open agent protocol.",
                confidence=0.98,
            )
            
            # Send back the correlated response envelope
            env = client.build_envelope(MessageType.RESPONSE)
            env.response.CopyFrom(response)
            await client.send_envelope(env)

asyncio.run(main())
```

### 3. Connect Client B (The Coordinating Requester)
This client connects as `COORDINATOR_AGENT` and requests tools/delegations from any available research agent on the network:

```python
import asyncio
from nuncio.client import NuncioClient, NuncioBuilders
from nuncio.nuncio_pb2 import MessageType

async def main() -> None:
    client = NuncioClient(
        uri="ws://localhost:8080/nuncio",
        role="COORDINATOR_AGENT",
        agent_id="coordinator-main",
        token="demo-token",
        capabilities=[],
    )
    await client.connect()
    print("Coordinator Agent online.")

    # Target any agent matching the logical role 'RESEARCH_AGENT'
    request = NuncioBuilders.request(intent="search_agent_protocol")
    env = client.build_envelope(MessageType.REQUEST)
    env.request.CopyFrom(request)
    env.target_role = "RESEARCH_AGENT"  # Symmetric routing target
    
    await client.send_envelope(env)
    print("Task dispatched...")

    # Wait for the bi-directional response
    incoming = await client.recv_envelope()
    if incoming.type == MessageType.RESPONSE:
        print(f"Response Received: {incoming.response.content}")
    elif incoming.type == MessageType.ERROR:
        print(f"Error Received: {incoming.error.message}")

asyncio.run(main())
```

---

## ⚖️ License

Nuncio is open-source software licensed under the **Apache License 2.0**. See the [LICENSE](LICENSE) file for details.
