Metadata-Version: 2.4
Name: ai-parrot
Version: 0.22.3
Summary: Chatbot services for Navigator, based on Langchain
Author-email: Jesus Lara <jesuslara@phenobarbital.info>
License-Expression: MIT
Project-URL: Homepage, https://github.com/phenobarbital/ai-parrot
Project-URL: Source, https://github.com/phenobarbital/ai-parrot
Project-URL: Tracker, https://github.com/phenobarbital/ai-parrot/issues
Project-URL: Documentation, https://github.com/phenobarbital/ai-parrot/
Project-URL: Funding, https://paypal.me/phenobarbital
Project-URL: Say Thanks!, https://saythanks.io/to/phenobarbital
Keywords: asyncio,asyncpg,aioredis,aiomcache,artificial intelligence,ai,chatbot,agents
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: POSIX :: Linux
Classifier: Environment :: Web Environment
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Framework :: AsyncIO
Classifier: Typing :: Typed
Requires-Python: >=3.10.1
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Cython==3.0.11
Requires-Dist: faiss-cpu>=1.9.0
Requires-Dist: jq==1.7.0
Requires-Dist: rank_bm25==0.2.2
Requires-Dist: tabulate==0.9.0
Requires-Dist: sentencepiece==0.2.1
Requires-Dist: markdown2==2.5.4
Requires-Dist: psycopg-binary==3.2.6
Requires-Dist: python-datamodel>=0.10.17
Requires-Dist: backoff==2.2.1
Requires-Dist: asyncdb>=2.11.6
Requires-Dist: google-cloud-bigquery>=3.30.0
Requires-Dist: numexpr==2.10.2
Requires-Dist: fpdf==1.7.2
Requires-Dist: python-docx==1.1.2
Requires-Dist: typing-extensions<5,>=4.14.1
Requires-Dist: navconfig[default]>=1.7.13
Requires-Dist: navigator-auth>=0.17.2
Requires-Dist: navigator-session>=0.6.5
Requires-Dist: navigator-api[locale,uvloop]>=2.13.5
Requires-Dist: matplotlib==3.10.0
Requires-Dist: seaborn==0.13.2
Requires-Dist: pydub==0.25.1
Requires-Dist: click>=8.1.7
Requires-Dist: async-notify[all]>=1.4.2
Requires-Dist: markitdown>=0.1.2
Requires-Dist: ddgs>=9.5.2
Requires-Dist: xmltodict>=0.14.2
Requires-Dist: pytesseract>=0.3.13
Requires-Dist: python-statemachine==2.5.0
Requires-Dist: aiohttp-swagger3==0.10.0
Requires-Dist: PyYAML>=6.0.2
Requires-Dist: python-arango-async==1.2.0
Requires-Dist: asyncdb[arangodb,bigquery,boto3,influxdb,mongodb]>=2.12.0
Requires-Dist: brotli==1.2.0
Requires-Dist: urllib3==2.6.3
Requires-Dist: aioquic==1.3.0
Requires-Dist: pylsqpack==0.3.23
Requires-Dist: aiohttp-sse-client==0.2.1
Requires-Dist: prance>=25.4.8.0
Requires-Dist: openapi-schema-validator==0.6.3
Requires-Dist: praw>=7.8.1
Requires-Dist: weasyprint==68.0
Requires-Dist: apscheduler==3.11.2
Requires-Dist: pydantic==2.12.5
Requires-Dist: aiohttp-cors>=0.8.1
Requires-Dist: querysource>=3.17.10
Requires-Dist: pywa>=3.8.0
Provides-Extra: agents
Requires-Dist: sentence_transformers==5.0.0; extra == "agents"
Requires-Dist: yfinance==0.2.54; extra == "agents"
Requires-Dist: youtube_search==2.1.2; extra == "agents"
Requires-Dist: wikipedia==1.4.0; extra == "agents"
Requires-Dist: mediawikiapi==1.2; extra == "agents"
Requires-Dist: pyowm==3.3.0; extra == "agents"
Requires-Dist: stackapi==0.3.1; extra == "agents"
Requires-Dist: duckduckgo-search==8.1.1; extra == "agents"
Requires-Dist: google-search-results==2.4.2; extra == "agents"
Requires-Dist: google-api-python-client>=2.151.0; extra == "agents"
Requires-Dist: networkx>=3.0; extra == "agents"
Requires-Dist: decorator>=5; extra == "agents"
Requires-Dist: autoviz==0.1.905; extra == "agents"
Requires-Dist: spacy==3.8.6; extra == "agents"
Requires-Dist: html2text==2025.4.15; extra == "agents"
Requires-Dist: httpx-sse==0.4.1; extra == "agents"
Requires-Dist: mcp==1.15.0; extra == "agents"
Requires-Dist: sse-starlette==3.0.2; extra == "agents"
Requires-Dist: requests-oauthlib==2.0.0; extra == "agents"
Requires-Dist: undetected-chromedriver==3.5.5; extra == "agents"
Requires-Dist: selenium==4.35.0; extra == "agents"
Requires-Dist: playwright==1.52.0; extra == "agents"
Requires-Dist: streamlit==1.50.0; extra == "agents"
Requires-Dist: jira==3.10.5; extra == "agents"
Requires-Dist: arxiv==2.2.0; extra == "agents"
Requires-Dist: docker==7.1.0; extra == "agents"
Requires-Dist: aiogoogle==5.17.0; extra == "agents"
Requires-Dist: rq==2.6.0; extra == "agents"
Requires-Dist: zeep[async]==4.3.1; extra == "agents"
Requires-Dist: branca==0.8.2; extra == "agents"
Requires-Dist: folium==0.20.0; extra == "agents"
Requires-Dist: webdriver-manager==4.0.2; extra == "agents"
Requires-Dist: prophet==1.2.1; extra == "agents"
Requires-Dist: folium==0.20.0; extra == "agents"
Requires-Dist: opensearch-py==3.1.0; extra == "agents"
Requires-Dist: cairosvg>=2.7; extra == "agents"
Requires-Dist: python-pptx==1.0.2; extra == "agents"
Requires-Dist: markdownify==1.1.0; extra == "agents"
Requires-Dist: python-docx==1.1.2; extra == "agents"
Requires-Dist: pymupdf==1.26.3; extra == "agents"
Requires-Dist: pymupdf4llm==0.0.27; extra == "agents"
Requires-Dist: pdf4llm==0.0.27; extra == "agents"
Requires-Dist: alpaca-py>=0.43.2; extra == "agents"
Requires-Dist: defillama-sdk>=0.1.0; extra == "agents"
Requires-Dist: pandas-ta-classic>=0.3.59; extra == "agents"
Requires-Dist: TA-Lib>=0.4.32; extra == "agents"
Requires-Dist: aioimaplib>=1.1.0; extra == "agents"
Requires-Dist: gmqtt>=0.6.15; extra == "agents"
Requires-Dist: azure-identity>=1.18.0; extra == "agents"
Requires-Dist: msgraph-sdk>=1.8.0; extra == "agents"
Requires-Dist: microsoft-kiota-authentication-azure>=1.2.0; extra == "agents"
Provides-Extra: charts
Requires-Dist: matplotlib>=3.7; extra == "charts"
Requires-Dist: cairosvg>=2.7; extra == "charts"
Requires-Dist: svglib>=1.5; extra == "charts"
Requires-Dist: reportlab>=4.0; extra == "charts"
Provides-Extra: agents-lite
Requires-Dist: yfinance==0.2.54; extra == "agents-lite"
Requires-Dist: youtube_search==2.1.2; extra == "agents-lite"
Requires-Dist: wikipedia==1.4.0; extra == "agents-lite"
Requires-Dist: mediawikiapi==1.2; extra == "agents-lite"
Requires-Dist: pyowm==3.3.0; extra == "agents-lite"
Requires-Dist: stackapi==0.3.1; extra == "agents-lite"
Requires-Dist: duckduckgo-search==8.1.1; extra == "agents-lite"
Requires-Dist: google-search-results==2.4.2; extra == "agents-lite"
Requires-Dist: google-api-python-client>=2.151.0; extra == "agents-lite"
Requires-Dist: networkx>=3.0; extra == "agents-lite"
Requires-Dist: decorator>=5; extra == "agents-lite"
Requires-Dist: html2text==2025.4.15; extra == "agents-lite"
Requires-Dist: httpx-sse==0.4.1; extra == "agents-lite"
Requires-Dist: mcp==1.15.0; extra == "agents-lite"
Requires-Dist: sse-starlette==3.0.2; extra == "agents-lite"
Requires-Dist: requests-oauthlib==2.0.0; extra == "agents-lite"
Requires-Dist: jira==3.10.5; extra == "agents-lite"
Requires-Dist: arxiv==2.2.0; extra == "agents-lite"
Requires-Dist: docker==7.1.0; extra == "agents-lite"
Requires-Dist: aiogoogle==5.17.0; extra == "agents-lite"
Requires-Dist: rq==2.6.0; extra == "agents-lite"
Requires-Dist: zeep[async]==4.3.1; extra == "agents-lite"
Requires-Dist: branca==0.8.2; extra == "agents-lite"
Requires-Dist: folium==0.20.0; extra == "agents-lite"
Requires-Dist: opensearch-py==3.1.0; extra == "agents-lite"
Provides-Extra: loaders
Requires-Dist: mammoth==1.8.0; extra == "loaders"
Requires-Dist: pytube==15.0.0; extra == "loaders"
Requires-Dist: youtube_transcript_api==1.0.3; extra == "loaders"
Requires-Dist: yt-dlp==2025.8.22; extra == "loaders"
Requires-Dist: ebooklib>=0.19; extra == "loaders"
Requires-Dist: whisperx==3.4.2; extra == "loaders"
Requires-Dist: av==15.1.0; extra == "loaders"
Requires-Dist: resemblyzer==0.1.4; extra == "loaders"
Requires-Dist: pyannote-audio==3.4.0; extra == "loaders"
Requires-Dist: pyannote-core==5.0.0; extra == "loaders"
Requires-Dist: pyannote-database==5.1.3; extra == "loaders"
Requires-Dist: pyannote-metrics==3.2.1; extra == "loaders"
Requires-Dist: pyannote-pipeline==3.0.1; extra == "loaders"
Requires-Dist: pytorch-lightning==2.5.5; extra == "loaders"
Requires-Dist: pytorch-metric-learning==2.9.0; extra == "loaders"
Requires-Dist: nvidia-cudnn-cu12==9.1.0.70; extra == "loaders"
Requires-Dist: moviepy==2.2.1; extra == "loaders"
Requires-Dist: decorator>=5; extra == "loaders"
Requires-Dist: ffmpeg==1.4; extra == "loaders"
Requires-Dist: paddleocr==3.2.0; extra == "loaders"
Provides-Extra: embeddings
Requires-Dist: sentence-transformers>=5.0.0; extra == "embeddings"
Requires-Dist: tiktoken==0.9.0; extra == "embeddings"
Requires-Dist: chromadb==0.6.3; extra == "embeddings"
Requires-Dist: bm25s[full]==0.2.14; extra == "embeddings"
Requires-Dist: simsimd>=4.3.1; extra == "embeddings"
Requires-Dist: tokenizers<=0.21.1,>=0.20.0; extra == "embeddings"
Requires-Dist: safetensors>=0.4.3; extra == "embeddings"
Provides-Extra: ml-heavy
Requires-Dist: torch==2.6.0; extra == "ml-heavy"
Requires-Dist: torchaudio==2.6.0; extra == "ml-heavy"
Requires-Dist: numpy<2.2,>=2.1; extra == "ml-heavy"
Requires-Dist: accelerate==0.34.2; extra == "ml-heavy"
Requires-Dist: bitsandbytes==0.44.1; extra == "ml-heavy"
Requires-Dist: datasets>=3.0.2; extra == "ml-heavy"
Requires-Dist: transformers<=4.51.3,>=4.51.1; extra == "ml-heavy"
Requires-Dist: tensorflow>=2.19.1; extra == "ml-heavy"
Requires-Dist: tf-keras==2.19.0; extra == "ml-heavy"
Requires-Dist: opencv-python==4.10.0.84; extra == "ml-heavy"
Provides-Extra: vectors
Requires-Dist: ai-parrot[embeddings,ml-heavy]; extra == "vectors"
Provides-Extra: mcp
Requires-Dist: google-genai>=1.61.0; extra == "mcp"
Requires-Dist: openai==2.8.1; extra == "mcp"
Requires-Dist: yfinance==0.2.54; extra == "mcp"
Requires-Dist: youtube_search==2.1.2; extra == "mcp"
Requires-Dist: wikipedia==1.4.0; extra == "mcp"
Requires-Dist: mediawikiapi==1.2; extra == "mcp"
Requires-Dist: pyowm==3.3.0; extra == "mcp"
Requires-Dist: stackapi==0.3.1; extra == "mcp"
Requires-Dist: duckduckgo-search==8.1.1; extra == "mcp"
Requires-Dist: google-search-results==2.4.2; extra == "mcp"
Requires-Dist: google-api-python-client>=2.151.0; extra == "mcp"
Requires-Dist: networkx>=3.0; extra == "mcp"
Requires-Dist: decorator>=5; extra == "mcp"
Requires-Dist: html2text==2025.4.15; extra == "mcp"
Requires-Dist: httpx-sse==0.4.1; extra == "mcp"
Requires-Dist: mcp==1.15.0; extra == "mcp"
Requires-Dist: sse-starlette==3.0.2; extra == "mcp"
Requires-Dist: requests-oauthlib==2.0.0; extra == "mcp"
Requires-Dist: jira==3.10.5; extra == "mcp"
Requires-Dist: arxiv==2.2.0; extra == "mcp"
Requires-Dist: docker==7.1.0; extra == "mcp"
Requires-Dist: aiogoogle==5.17.0; extra == "mcp"
Requires-Dist: rq==2.6.0; extra == "mcp"
Requires-Dist: zeep[async]==4.3.1; extra == "mcp"
Requires-Dist: branca==0.8.2; extra == "mcp"
Requires-Dist: folium==0.20.0; extra == "mcp"
Requires-Dist: opensearch-py==3.1.0; extra == "mcp"
Provides-Extra: images
Requires-Dist: torchvision==0.21.0; extra == "images"
Requires-Dist: timm==1.0.15; extra == "images"
Requires-Dist: ultralytics==8.3.179; extra == "images"
Requires-Dist: albumentations==2.0.6; extra == "images"
Requires-Dist: filetype==1.2.0; extra == "images"
Requires-Dist: imagehash==4.3.1; extra == "images"
Requires-Dist: pgvector==0.4.1; extra == "images"
Requires-Dist: pyheif==0.8.0; extra == "images"
Requires-Dist: exif==1.6.1; extra == "images"
Requires-Dist: pillow-avif-plugin==1.5.2; extra == "images"
Requires-Dist: pillow-heif==0.22.0; extra == "images"
Requires-Dist: python-xmp-toolkit==2.0.2; extra == "images"
Requires-Dist: exifread==3.5.1; extra == "images"
Requires-Dist: transformers<=4.51.3,>=4.51.1; extra == "images"
Requires-Dist: ffmpeg==1.4; extra == "images"
Requires-Dist: holoviews==1.21.0; extra == "images"
Requires-Dist: bokeh==3.7.3; extra == "images"
Requires-Dist: pandas-bokeh==0.5.5; extra == "images"
Requires-Dist: plotly==5.22.0; extra == "images"
Requires-Dist: ipywidgets==8.1.0; extra == "images"
Requires-Dist: altair==5.5.0; extra == "images"
Provides-Extra: whisperx
Requires-Dist: whisperx==3.4.2; extra == "whisperx"
Requires-Dist: av==15.1.0; extra == "whisperx"
Requires-Dist: torch==2.6.0; extra == "whisperx"
Requires-Dist: torchaudio==2.6.0; extra == "whisperx"
Requires-Dist: torchvision==0.21.0; extra == "whisperx"
Requires-Dist: pyannote-audio==3.4.0; extra == "whisperx"
Requires-Dist: pyannote-core==5.0.0; extra == "whisperx"
Requires-Dist: pyannote-database==5.1.3; extra == "whisperx"
Requires-Dist: pyannote-metrics==3.2.1; extra == "whisperx"
Requires-Dist: pyannote-pipeline==3.0.1; extra == "whisperx"
Requires-Dist: pytorch-lightning==2.5.5; extra == "whisperx"
Requires-Dist: pytorch-metric-learning==2.9.0; extra == "whisperx"
Requires-Dist: nvidia-cudnn-cu12==9.1.0.70; extra == "whisperx"
Requires-Dist: torch-audiomentations==0.12.0; extra == "whisperx"
Requires-Dist: torch-pitch-shift==1.2.5; extra == "whisperx"
Requires-Dist: torchmetrics==1.8.2; extra == "whisperx"
Provides-Extra: anthropic
Requires-Dist: anthropic[aiohttp]==0.61.0; extra == "anthropic"
Requires-Dist: claude-agent-sdk>=0.1.0; extra == "anthropic"
Provides-Extra: openai
Requires-Dist: openai==2.8.1; extra == "openai"
Requires-Dist: tiktoken==0.9.0; extra == "openai"
Provides-Extra: google
Requires-Dist: google-api-python-client<=2.177.0,>=2.166.0; extra == "google"
Requires-Dist: google-cloud-texttospeech==2.27.0; extra == "google"
Requires-Dist: google-genai>=1.61.0; extra == "google"
Requires-Dist: google-cloud-aiplatform==1.110.0; extra == "google"
Provides-Extra: groq
Requires-Dist: groq==0.33.0; extra == "groq"
Provides-Extra: llms
Requires-Dist: google-genai>=1.61.0; extra == "llms"
Requires-Dist: openai==2.8.1; extra == "llms"
Requires-Dist: groq==0.33.0; extra == "llms"
Requires-Dist: anthropic[aiohttp]==0.61.0; extra == "llms"
Requires-Dist: claude-agent-sdk>=0.1.0; extra == "llms"
Requires-Dist: xai-sdk>=0.1.0; extra == "llms"
Provides-Extra: integrations
Requires-Dist: querysource>=3.17.9; extra == "integrations"
Requires-Dist: async-notify[all]>=1.5.2; extra == "integrations"
Requires-Dist: azure-teambots>=0.1.1; extra == "integrations"
Provides-Extra: milvus
Requires-Dist: pymilvus==2.4.8; extra == "milvus"
Requires-Dist: milvus==2.3.5; extra == "milvus"
Provides-Extra: chroma
Requires-Dist: chroma==0.2.0; extra == "chroma"
Provides-Extra: eda
Requires-Dist: ydata-profiling==4.16.1; extra == "eda"
Requires-Dist: sweetviz==2.1.4; extra == "eda"
Provides-Extra: security
Requires-Dist: pytector[gguf]==0.2.0; extra == "security"
Provides-Extra: xai
Requires-Dist: xai-sdk>=0.1.0; extra == "xai"
Provides-Extra: all
Requires-Dist: ai-parrot[agents,images,integrations,llms,loaders,vectors]; extra == "all"
Provides-Extra: all-fast
Requires-Dist: ai-parrot[agents-lite,embeddings,integrations,llms]; extra == "all-fast"
Provides-Extra: dev
Requires-Dist: pytest>=7.2.2; extra == "dev"
Requires-Dist: pytest-asyncio==1.2.0; extra == "dev"
Requires-Dist: pytest-xdist==3.3.1; extra == "dev"
Requires-Dist: pytest-assume==2.4.3; extra == "dev"
Requires-Dist: pytest-mock==3.15.1; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: pylint; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: coverage; extra == "dev"
Requires-Dist: maturin==1.9.6; extra == "dev"
Dynamic: license-file

# AI-Parrot 🦜

**AI-Parrot** is a powerful, async-first Python framework for building, extending, and orchestrating AI Agents and Chatbots. Built on top of `navigator-api`, it provides a unified interface for interacting with various LLM providers, managing tools, conducting agent-to-agent (A2A) communication, and serving agents via the Model Context Protocol (MCP).

Whether you need a simple chatbot, a complex multi-agent orchestration workflow, or a robust production-ready AI service, AI-Parrot exposes the primitives to build it efficiently.

## 🚀 Key Features

*   **Unified Agent API**: Simple interface (`Chatbot`) to create agents with memory, tools, and RAG capabilities.
*   **Tool Management**: Easy-to-use decorators (`@tool`) and class-based toolkits (`AbstractToolkit`) to give your agents capabilities.
*   **Orchestration & Workflow**: `AgentCrew` for managing multi-agent workflows (Sequential, Parallel, Flow, Loop).
*   **Advanced Connectivity**:
    *   **A2A (Agent-to-Agent)**: Native protocol for agents to discover and talk to each other.
    *   **MCP (Model Context Protocol)**: Expose your agents as MCP servers or consume external MCP servers.
*   **OpenAPI Integration**: Consume any OpenAPI specification as a dynamic toolkit (`OpenAPIToolkit`).
*   **Scheduling**: Built-in task scheduling for agents using the `@schedule` decorator.
*   **Multi-Provider Support**: Switch seamlessy between OpenAI, Anthropic, Google Gemini, Groq, and more.
*   **Integrations**: Native support for exposing bots via Telegram, MS Teams, and Slack.

---

## 📦 Installation

```bash
pip install ai-parrot
```

For specific provider support (e.g., Anthropic, Google):

```bash
pip install "ai-parrot[anthropic,google]"
```

---

## ⚡ Quick Start

Create a simple weather chatbot in just a few lines of code:

```python
import asyncio
from parrot.bots import Chatbot
from parrot.tools import tool

# 1. Define a tool
@tool
def get_weather(location: str) -> str:
    """Get the current weather for a location."""
    return f"The weather in {location} is Sunny, 25°C"

async def main():
    # 2. Create the Agent
    bot = Chatbot(
        name="WeatherBot",
        llm="openai:gpt-4o",  # Provider:Model
        tools=[get_weather],
        system_prompt="You are a helpful weather assistant."
    )
    
    # 3. Configure (loads tools, connects to memory)
    await bot.configure()

    # 4. Chat!
    response = await bot.ask("What's the weather like in Madrid?")
    print(response)

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

---

## 🏗️ Architecture

AI-Parrot is designed with a modular architecture enabling agents to be both consumers and providers of tools and services.

```mermaid
graph TD
    User["User / Client"] --> API["AgentTalk Handlers"]
    API --> Bot["Chatbot / BaseBot"]
    
    subgraph "Agent Core"
        Bot --> Memory["Memory / Vector Store"]
        Bot --> LLM["LLM Client (OpenAI/Anthropic/Etc)"]
        Bot --> TM["Tool Manager"]
    end
    
    subgraph "Tools & Capabilities"
        TM --> LocalTools["Local Tools (@tool)"]
        TM --> Toolkits["Toolkits (OpenAPI/Custom)"]
        TM --> MCPServer["External MCP Servers"]
    end
    
    subgraph "Connectivity"
        Bot -.-> A2A["A2A Protocol (Client/Server)"]
        Bot -.-> MCP["MCP Protocol (Server)"]
        Bot -.-> Integrations["Telegram / MS Teams"]
    end
    
    subgraph "Orchestration"
        Crew["AgentCrew"] --> Bot
        Crew --> OtherBots["Other Agents"]
    end
```

---

## 🧩 Core Concepts

### Agents (`Chatbot`)
The `Chatbot` class is your main entry point. It handles conversation history, RAG (Retrieval-Augmented Generation), and tool execution loop.

```python
bot = Chatbot(
    name="MyAgent",
    model="anthropic:claude-3-5-sonnet-20240620",
    enable_memory=True
)
```

### Tools

#### Functional Tools (`@tool`)
The simplest way to create a tool. The docstring and type hints are automatically used to generate the schema for the LLM.

```python
from parrot.tools import tool

@tool
def calculate_vat(amount: float, rate: float = 0.20) -> float:
    """Calculate VAT for a given amount."""
    return amount * rate
```

#### Class-Based Toolkits (`AbstractToolkit`)
Group related tools into a reusable class. All public async methods become tools.

```python
from parrot.tools import AbstractToolkit

class MathToolkit(AbstractToolkit):
    async def add(self, a: int, b: int) -> int:
        """Add two numbers."""
        return a + b
        
    async def multiply(self, a: int, b: int) -> int:
        """Multiply two numbers."""
        return a * b
```

#### OpenAPI Toolkit (`OpenAPIToolkit`)
Dynamically generate tools from any OpenAPI/Swagger specification.

```python
from parrot.tools.openapi_toolkit import OpenAPIToolkit

petstore = OpenAPIToolkit(
    spec="https://petstore.swagger.io/v2/swagger.json",
    service="petstore"
)

# Now your agent can call petstore_get_pet_by_id, etc.
bot = Chatbot(name="PetBot", tools=petstore.get_tools())
```

### Orchestration (`AgentCrew`)
orchestrate multiple agents to solve complex tasks using `AgentCrew`.

**Supported Modes:**
*   **Sequential**: Agents run one after another, passing context.
*   **Parallel**: Independent tasks run concurrently.
*   **Flow**: DAG-based execution defined by dependencies.
*   **Loop**: Iterative execution until a condition is met.

```python
from parrot.bots.orchestration import AgentCrew

crew = AgentCrew(
    name="ResearchTeam",
    agents=[researcher_agent, writer_agent]
)

# Define a Flow
# Writer waits for Researcher to finish
crew.task_flow(researcher_agent, writer_agent)

await crew.run_flow("Research the latest advancements in Quantum Computing")
```

### Scheduling (`@schedule`)
Give your agents agency to run tasks in the background.

```python
from parrot.scheduler import schedule, ScheduleType

class DailyBot(Chatbot):
    @schedule(schedule_type=ScheduleType.DAILY, hour=9, minute=0)
    async def morning_briefing(self):
        news = await self.ask("Summarize today's top tech news")
        await self.send_notification(news)
```

---

## 🔌 Connectivity & Exposure

### Agent-to-Agent (A2A) Protocol
Agents can discover and talk to each other using the A2A protocol.

**Expose an Agent:**
```python
# In your server setup (aiohttp)
from parrot.a2a import A2AServer

a2a = A2AServer(my_agent)
a2a.setup(app, url="https://my-agent.com")
```

**Consume an Agent:**
```python
from parrot.a2a import A2AClient

async with A2AClient("https://remote-agent.com") as client:
    response = await client.send_message("Hello from another agent!")
```

### Model Context Protocol (MCP)
**AI-Parrot** has first-class support for MCP.

**Consume MCP Servers:**
Give your agent access to filesystem, git, or any other MCP server.
```python
# In Chatbot config
mcp_servers = [
    MCPServerConfig(
        name="filesystem",
        command="npx",
        args=["-y", "@modelcontextprotocol/server-filesystem", "/home/user"]
    )
]
await bot.setup_mcp_servers(mcp_servers)
```

**Expose Agent as MCP Server:**
Allow Claude Desktop or other MCP clients to use your agent as a tool.
```python
# (Configuration details in documentation)
```

### Platform Integrations
Expose your bots natively to chat platforms defined in your `parrot.conf`:
*   **Telegram**
*   **Microsoft Teams**
*   **Slack**
*   **WhatsApp**

---

## 🤖 Supported LLM Clients

AI-Parrot supports a wide range of LLM providers via `parrot.clients`:

*   **OpenAI** (`openai`)
*   **Anthropic** (`anthropic`, `claude`)
*   **Google Gemini** (`google`)
*   **Groq** (`groq`)
*   **X.AI** (`grok`)
*   **HuggingFace** (`hf`)
*   **Ollama/Local** (via OpenAI compatible endpoint)

---

## 🤝 Community & Support

*   **Issues**: [GitHub Tracker](https://github.com/phenobarbital/ai-parrot/issues)
*   **Discussion**: [GitHub Discussions](https://github.com/phenobarbital/ai-parrot/discussions)
*   **Contribution**: Pull requests are welcome! Please read `CONTRIBUTING.md`.

---
*Built with ❤️ by the Navigator Team*
