Metadata-Version: 2.4
Name: cogent-ai
Version: 1.19.5
Summary: Production AI agent framework with memory control and semantic caching
Project-URL: Homepage, https://github.com/milad-o/cogent
Project-URL: Repository, https://github.com/milad-o/cogent
Project-URL: Issues, https://github.com/milad-o/cogent/issues
Author: Milad Olad
License: MIT
License-File: LICENSE
Keywords: agents,ai,caching,llm,memory,reasoning,tools
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.13
Requires-Dist: anthropic>=0.86.0
Requires-Dist: azure-ai-inference>=1.0.0b9
Requires-Dist: httpx>=0.28.1
Requires-Dist: networkx>=3.6
Requires-Dist: openai>=1.0.0
Requires-Dist: pydantic-settings>=2.12.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: rapidfuzz>=3.14.3
Requires-Dist: rich>=14.3.3
Provides-Extra: a2a
Requires-Dist: a2a-sdk[http-server]>=0.3.0; extra == 'a2a'
Requires-Dist: uvicorn>=0.38.0; extra == 'a2a'
Provides-Extra: all
Requires-Dist: a2a-sdk[http-server]>=0.3.0; extra == 'all'
Requires-Dist: aiosqlite>=0.21.0; extra == 'all'
Requires-Dist: anthropic>=0.86.0; extra == 'all'
Requires-Dist: asyncpg>=0.31.0; extra == 'all'
Requires-Dist: azure-ai-inference>=1.0.0b9; extra == 'all'
Requires-Dist: azure-identity>=1.25.1; extra == 'all'
Requires-Dist: beautifulsoup4>=4.14.2; extra == 'all'
Requires-Dist: cerebras-cloud-sdk>=1.64.1; extra == 'all'
Requires-Dist: cohere>=5.20.0; extra == 'all'
Requires-Dist: ddgs>=9.9.1; extra == 'all'
Requires-Dist: faiss-cpu<2,>=1.7; (python_version < '3.14') and extra == 'all'
Requires-Dist: fastapi>=0.115.0; extra == 'all'
Requires-Dist: google-genai>=1.57.0; extra == 'all'
Requires-Dist: gravis>=0.1.0; extra == 'all'
Requires-Dist: greenlet>=3.2.4; extra == 'all'
Requires-Dist: groq>=0.15.0; extra == 'all'
Requires-Dist: matplotlib>=3.9.0; extra == 'all'
Requires-Dist: mcp>=1.22.0; extra == 'all'
Requires-Dist: pandas>=2.2.0; extra == 'all'
Requires-Dist: pdfplumber>=0.11.8; extra == 'all'
Requires-Dist: playwright>=1.56.0; extra == 'all'
Requires-Dist: psycopg2-binary>=2.9.11; extra == 'all'
Requires-Dist: pyarrow>=22.0.0; extra == 'all'
Requires-Dist: pymupdf-layout>=1.26.6; extra == 'all'
Requires-Dist: pymupdf4llm>=0.2.6; extra == 'all'
Requires-Dist: pymupdf>=1.26.6; extra == 'all'
Requires-Dist: pypdf>=6.4.0; extra == 'all'
Requires-Dist: pyvis>=0.3.2; extra == 'all'
Requires-Dist: qdrant-client>=1.16.2; extra == 'all'
Requires-Dist: rank-bm25>=0.2.2; extra == 'all'
Requires-Dist: redis>=5.0.0; extra == 'all'
Requires-Dist: reportlab>=4.4.5; extra == 'all'
Requires-Dist: scipy>=1.17.0; extra == 'all'
Requires-Dist: seaborn>=0.13.0; extra == 'all'
Requires-Dist: sentence-transformers>=5.2.0; extra == 'all'
Requires-Dist: sqlalchemy>=2.0.44; extra == 'all'
Requires-Dist: starlette>=0.50.0; extra == 'all'
Requires-Dist: uvicorn>=0.38.0; extra == 'all'
Requires-Dist: websockets>=15.0.1; extra == 'all'
Provides-Extra: all-backend
Requires-Dist: aiosqlite>=0.21.0; extra == 'all-backend'
Requires-Dist: asyncpg>=0.31.0; extra == 'all-backend'
Requires-Dist: faiss-cpu<2,>=1.7; (python_version < '3.14') and extra == 'all-backend'
Requires-Dist: greenlet>=3.2.4; extra == 'all-backend'
Requires-Dist: psycopg2-binary>=2.9.11; extra == 'all-backend'
Requires-Dist: qdrant-client>=1.16.2; extra == 'all-backend'
Requires-Dist: rank-bm25>=0.2.2; extra == 'all-backend'
Requires-Dist: redis>=5.0.0; extra == 'all-backend'
Requires-Dist: scipy>=1.17.0; extra == 'all-backend'
Requires-Dist: sentence-transformers>=5.2.0; extra == 'all-backend'
Requires-Dist: sqlalchemy>=2.0.44; extra == 'all-backend'
Provides-Extra: all-providers
Requires-Dist: anthropic>=0.86.0; extra == 'all-providers'
Requires-Dist: azure-ai-inference>=1.0.0b9; extra == 'all-providers'
Requires-Dist: azure-identity>=1.25.1; extra == 'all-providers'
Requires-Dist: cerebras-cloud-sdk>=1.64.1; extra == 'all-providers'
Requires-Dist: cohere>=5.20.0; extra == 'all-providers'
Requires-Dist: google-genai>=1.57.0; extra == 'all-providers'
Requires-Dist: groq>=0.15.0; extra == 'all-providers'
Provides-Extra: analytics
Requires-Dist: pyarrow>=22.0.0; extra == 'analytics'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.86.0; extra == 'anthropic'
Provides-Extra: api
Requires-Dist: fastapi>=0.115.0; extra == 'api'
Requires-Dist: starlette>=0.50.0; extra == 'api'
Requires-Dist: uvicorn>=0.38.0; extra == 'api'
Provides-Extra: azure
Requires-Dist: azure-ai-inference>=1.0.0b9; extra == 'azure'
Requires-Dist: azure-identity>=1.25.1; extra == 'azure'
Provides-Extra: browser
Requires-Dist: playwright>=1.56.0; extra == 'browser'
Provides-Extra: cerebras
Requires-Dist: cerebras-cloud-sdk>=1.64.1; extra == 'cerebras'
Provides-Extra: cohere
Requires-Dist: cohere>=5.20.0; extra == 'cohere'
Provides-Extra: database
Requires-Dist: aiosqlite>=0.21.0; extra == 'database'
Requires-Dist: asyncpg>=0.31.0; extra == 'database'
Requires-Dist: greenlet>=3.2.4; extra == 'database'
Requires-Dist: psycopg2-binary>=2.9.11; extra == 'database'
Requires-Dist: sqlalchemy>=2.0.44; extra == 'database'
Provides-Extra: document
Requires-Dist: pdfplumber>=0.11.8; extra == 'document'
Requires-Dist: pymupdf-layout>=1.26.6; extra == 'document'
Requires-Dist: pymupdf4llm>=0.2.6; extra == 'document'
Requires-Dist: pymupdf>=1.26.6; extra == 'document'
Requires-Dist: pypdf>=6.4.0; extra == 'document'
Requires-Dist: reportlab>=4.4.5; extra == 'document'
Provides-Extra: gemini
Requires-Dist: google-genai>=1.57.0; extra == 'gemini'
Provides-Extra: groq
Requires-Dist: groq>=0.15.0; extra == 'groq'
Provides-Extra: infrastructure
Requires-Dist: redis>=5.0.0; extra == 'infrastructure'
Provides-Extra: mcp
Requires-Dist: mcp>=1.22.0; extra == 'mcp'
Requires-Dist: websockets>=15.0.1; extra == 'mcp'
Provides-Extra: retrieval
Requires-Dist: rank-bm25>=0.2.2; extra == 'retrieval'
Requires-Dist: sentence-transformers>=5.2.0; extra == 'retrieval'
Provides-Extra: vector-stores
Requires-Dist: faiss-cpu<2,>=1.7; (python_version < '3.14') and extra == 'vector-stores'
Requires-Dist: qdrant-client>=1.16.2; extra == 'vector-stores'
Requires-Dist: scipy>=1.17.0; extra == 'vector-stores'
Provides-Extra: visualization
Requires-Dist: gravis>=0.1.0; extra == 'visualization'
Requires-Dist: matplotlib>=3.9.0; extra == 'visualization'
Requires-Dist: pandas>=2.2.0; extra == 'visualization'
Requires-Dist: pyvis>=0.3.2; extra == 'visualization'
Requires-Dist: seaborn>=0.13.0; extra == 'visualization'
Provides-Extra: web
Requires-Dist: beautifulsoup4>=4.14.2; extra == 'web'
Requires-Dist: ddgs>=9.9.1; extra == 'web'
Description-Content-Type: text/markdown

# Cogent

<p align="center">
  <strong>Build AI agents that actually work.</strong>
</p>

<p align="center">
  📚 <strong>Documentation: <a href="https://milad-o.github.io/cogent">https://milad-o.github.io/cogent</a></strong>
</p>

<p align="center">
  <a href="https://pypi.org/project/cogent-ai/"><img src="https://img.shields.io/pypi/v/cogent-ai?style=flat-square&logo=pypi&logoColor=white" alt="Version"></a>
  <a href="https://pypi.org/project/cogent-ai/"><img src="https://img.shields.io/pypi/dm/cogent-ai?style=flat-square&logo=pypi&logoColor=white&label=downloads" alt="Downloads"></a>
  <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.13+-3776AB?style=flat-square&logo=python&logoColor=white" alt="Python"></a>
  <a href="https://github.com/milad-o/cogent/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-10B981?style=flat-square" alt="License"></a>
  <a href="https://milad-o.github.io/cogent"><img src="https://img.shields.io/badge/docs-latest-09B6A2?style=flat-square&logo=readthedocs&logoColor=white" alt="Documentation"></a>
  <a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&style=flat-square" alt="Ruff"></a>
  <a href="https://github.com/milad-o/cogent/commits/main"><img src="https://img.shields.io/github/last-commit/milad-o/cogent?style=flat-square&logo=github" alt="Last Commit"></a>
  <br>
  <a href="https://github.com/milad-o/cogent/tree/main/tests"><img src="https://img.shields.io/badge/unit_tests-1472-2596BE?style=flat-square&logo=pytest&logoColor=white" alt="Unit Tests"></a>
  <a href="https://github.com/milad-o/cogent/tree/main/tests/integration"><img src="https://img.shields.io/badge/integration_tests-344-7C3AED?style=flat-square&logo=pytest&logoColor=white" alt="Integration Tests"></a>
  <a href="https://github.com/milad-o/cogent/tree/main/tests"><img src="https://img.shields.io/badge/total_tests-1816-10B981?style=flat-square&logo=pytest&logoColor=white" alt="Total Tests"></a>
</p>

<p align="center">
  <a href="#installation">Installation</a> •
  <a href="#quick-start">Quick Start</a> •
  <a href="#what-makes-cogent-different">Why Cogent</a> •
  <a href="#features">Features</a> •
  <a href="#examples">Examples</a> •
  <a href="https://milad-o.github.io/cogent">Docs</a>
</p>

---

## Installation

> The package is [`cogent-ai`](https://pypi.org/project/cogent-ai/) on PyPI. You import it as `cogent`.

```bash
# uv (recommended)
uv add cogent-ai

# pip
pip install cogent-ai

# Everything (all providers, vector stores, retrieval, browser, etc.)
uv add "cogent-ai[all]"
```

<details>
<summary>More install options (git, source, extras)</summary>

```bash
# From GitHub (latest unreleased)
uv add git+https://github.com/milad-o/cogent.git
pip install git+https://github.com/milad-o/cogent.git

# Specific extras
uv add "cogent-ai[vector-stores,retrieval]"
uv add "cogent-ai[anthropic,gemini]"

# From source
git clone https://github.com/milad-o/cogent.git && cd cogent
uv sync --group dev --group test
```

| Extra | What it adds |
|-------|-------------|
| `anthropic`, `azure`, `cerebras`, `cohere`, `gemini`, `groq` | Individual LLM provider SDKs |
| `all-providers` | All LLM providers |
| `vector-stores` | FAISS, Qdrant, SciPy |
| `retrieval` | BM25, sentence-transformers |
| `database` | SQLAlchemy, aiosqlite, asyncpg |
| `web` | BeautifulSoup4, DuckDuckGo search |
| `browser` | Playwright |
| `document` | PDF, Word, Markdown loaders |
| `a2a` | Agent2Agent protocol (a2a-sdk) |
| `all-backend` | vector-stores + retrieval + database + infrastructure |
| `all` | Everything |

</details>

---

## Quick Start

```python
import asyncio
from cogent import Agent, tool

@tool
def get_weather(city: str) -> str:
    """Get current weather for a city."""
    return f"Weather in {city}: 72°F, sunny"

async def main():
    agent = Agent(
        name="Assistant",
        model="gpt4",  # or "claude", "gemini", "grok", "deepseek", ...
        tools=[get_weather],
    )
    result = await agent.run("What's the weather in Tokyo?")
    print(result)

asyncio.run(main())
```

Set `OPENAI_API_KEY` (or the relevant provider key) in your environment or `.env` file.

---

## What Makes Cogent Different

Most agent frameworks add layers: graph runtimes, chain abstractions, runnable pipelines, state machines. Each layer adds latency and complexity. Cogent strips all of that out.

### The Executor: A Tight Loop, Not a Graph

The core of Cogent is a **procedural async loop** that calls the LLM directly, executes tools in parallel, and repeats:

```
LLM call → tool calls? → parallel execution → append results → repeat
```

No graph nodes, no edge traversal, no intermediate representations. The executor calls the provider SDK directly (`model.ainvoke(messages)`) with native message types. Model and tool bindings are cached at construction—zero per-iteration overhead.

```python
from cogent import Agent, tool

@tool
def search(query: str) -> str:
    """Search the web."""
    return f"Results for: {query}"

@tool
def calculate(expression: str) -> float:
    """Evaluate a math expression."""
    return eval(expression)

agent = Agent(name="Assistant", model="gpt4", tools=[search, calculate])

# Both tools run concurrently when the LLM requests them in the same turn
result = await agent.run("Search for Python market share and calculate 0.35 * 8.1B")
```

For maximum performance, bypass the Agent class entirely:

```python
from cogent.executors import run

result = await run(
    "Search for Python tutorials and summarize the top 3",
    tools=[search, summarize],
    model="gpt4",
)
```

**What's eliminated vs. typical frameworks:**

| Overhead | Cogent |
|----------|--------|
| Graph runtime (nodes, edges, state machines) | Procedural loop |
| Chain/Runnable abstraction layers | Direct `await model.ainvoke()` |
| Per-call tool binding | Cached once at construction |
| Sequential tool execution | `asyncio.gather` with semaphore (20 concurrent) |
| Separate retry framework | Built into the loop (LLM + per-tool) |

### Memory Is Orthogonal to Execution

Memory layers (conversation, ACC, long-term, semantic cache) live outside the executor loop. The executor deals with the immediate message list only. This means you can swap memory strategies without affecting execution performance.

**Bounded memory (ACC)** — Standard agents dump everything into context until it overflows. [Adaptive Context Control](docs/acc.md) uses bio-inspired bounded working memory with prioritized retention and automatic eviction:

```python
from cogent.memory import Memory
from cogent.memory.acc import ACCConfig

agent = Agent(name="Assistant", model="gpt4", memory=Memory(acc=ACCConfig(max_tokens=4000)))
```

**Semantic caching** — Similar queries hit a cache instead of the LLM. Cogent matches on reasoning artifacts (intents, plans) semantically, achieving 80%+ hit rates. See [docs/memory.md](docs/memory.md#semantic-cache).

### Composition, Not Framework Lock-In

The Agent class composes independent pieces—tools, capabilities, memory, interceptors, observer, subagents, MCP servers—without coupling them. Each is optional. You can use the standalone `run()` function with just tools and a model string, or build a full agent with every feature attached.

---

## Features

### Tools & Capabilities

Define tools with `@tool`—Cogent extracts the JSON schema from type hints and docstrings automatically:

```python
from cogent import tool

@tool
def search(query: str, max_results: int = 10) -> str:
    """Search the web for information."""
    return f"Found {max_results} results for: {query}"
```

Plug in batteries-included capabilities for filesystem, web search, code execution, browser automation, databases, PDFs, spreadsheets, shell, and MCP servers:

```python
from cogent.capabilities import FileSystem, CodeSandbox, WebSearch, MCP

agent = Agent(
    name="Assistant",
    model="gpt4",
    tools=[search],
    capabilities=[FileSystem(allowed_paths=["./project"]), CodeSandbox(), WebSearch()],
    mcps=MCP(command="npx", args=["-y", "@modelcontextprotocol/server-filesystem", "."]),
)
```

### Subagents & Delegation

Pass agents as `subagents=` and Cogent wires them as callable tools. The coordinator decides when to delegate. Token usage, duration, and delegation chains propagate automatically.

```python
analyst = Agent(name="analyst", model="gpt4", instructions="Analyze data.")
researcher = Agent(name="researcher", model="gpt4", instructions="Research trends.")

coordinator = Agent(
    name="coordinator",
    model="gpt4",
    subagents=[analyst, researcher],
)
result = await coordinator.run("Analyze Q4 e-commerce growth")
```

### Agent2Agent (A2A)

Connect to remote agents or expose yours over the network:

```python
from cogent.agent import A2AAgent, A2AServer

# Use a remote agent as a subagent
remote = A2AAgent(name="analyst", url="http://localhost:10088")
coordinator = Agent(name="lead", model="gpt4", subagents=[remote])

# Expose an agent as an A2A server
agent.serve(port=10002)
```

### Structured Output

Return Pydantic models, dataclasses, TypedDicts, primitives, Literals, Unions, Enums, or dicts—with automatic validation and retry:

```python
from pydantic import BaseModel

class Analysis(BaseModel):
    sentiment: str
    confidence: float
    topics: list[str]

result = await agent.run("Analyze: I love this product!", returns=Analysis)
print(result.content.data.sentiment)  # "positive"
```

### Observability

Attach an `Observer` to see what your agent does—tool calls, LLM requests, token counts, timing, memory events:

```python
from cogent.observability import Observer

agent = Agent(
    name="Assistant",
    model="gpt4",
    observer=Observer(llm_calls=True, timestamps=True),
)
```

### Resilience & Interceptors

Two-tier recovery (systematic retry + LLM-driven recovery), plus composable middleware for budget guards, PII redaction, rate limiting, and tool gates:

```python
from cogent.agent import ResilienceConfig
from cogent.interceptors import BudgetGuard, PIIShield

agent = Agent(
    name="Safe",
    model="gpt4",
    resilience=ResilienceConfig(max_retries=3, on_exhaustion="ask_agent"),
    intercept=[BudgetGuard(max_model_calls=100), PIIShield(patterns=["email", "ssn"])],
)
```

### Streaming & Reasoning

```python
# Real-time token streaming
async for chunk in agent.run_stream("Write a poem"):
    print(chunk.content, end="", flush=True)

# Extended thinking with configurable styles
agent = Agent(name="Thinker", model="gpt4", reasoning=True)
```

### RAG Pipeline

Document loading (PDF, Word, HTML, CSV, JSON, code), multiple splitting strategies (semantic, markdown, sentence, token), vector stores (FAISS, Qdrant, Chroma, PgVector), and 12 retriever strategies. See [docs/retrievers.md](docs/retrievers.md).

### Memory & Persistence

Conversation history, long-term memory with fuzzy matching, scoped views, and pluggable stores (in-memory, SQLite, PostgreSQL, Redis). See [docs/memory.md](docs/memory.md).

---

## Supported Models

Use string aliases for convenience, factory functions for flexibility, or direct instantiation for full control.

```python
agent = Agent("Helper", model="gpt4")     # OpenAI
agent = Agent("Helper", model="claude")    # Anthropic
agent = Agent("Helper", model="gemini")    # Google
agent = Agent("Helper", model="grok")      # xAI
agent = Agent("Helper", model="deepseek")  # DeepSeek
agent = Agent("Helper", model="llama")     # Groq
agent = Agent("Helper", model="ollama")    # Local (Ollama)
```

<details>
<summary>Full provider table</summary>

| Provider | Chat | Embeddings | Aliases |
|----------|------|------------|---------|
| OpenAI | `OpenAIChat` | `OpenAIEmbedding` | `"gpt4"`, `"gpt-4o"`, `"gpt-4o-mini"` |
| Azure | `AzureOpenAIChat` | `AzureOpenAIEmbedding` | — |
| Azure AI Foundry | `AzureAIFoundryChat` | — | — |
| Anthropic | `AnthropicChat` | — | `"claude"`, `"claude-opus"` |
| Gemini | `GeminiChat` | `GeminiEmbedding` | `"gemini"`, `"gemini-pro"` |
| Groq | `GroqChat` | — | `"llama"`, `"mixtral"` |
| xAI | `XAIChat` | — | `"grok"` |
| DeepSeek | `DeepSeekChat` | — | `"deepseek"` |
| Cerebras | `CerebrasChat` | — | `"cerebras"` |
| Mistral | `MistralChat` | `MistralEmbedding` | `"mistral"`, `"codestral"` |
| Cohere | `CohereChat` | `CohereEmbedding` | `"command"`, `"command-r"` |
| OpenRouter | `OpenRouterChat` | — | `"or-gpt4o"`, `"or-claude"` |
| Cloudflare | `CloudflareChat` | `CloudflareEmbedding` | — |
| Ollama | `OllamaChat` | `OllamaEmbedding` | `"ollama"` |
| Custom | `CustomChat` | `CustomEmbedding` | — |

</details>

---

## Configuration

Set provider keys via environment variables or `.env`:

```bash
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=...
GOOGLE_API_KEY=...
GROQ_API_KEY=...
XAI_API_KEY=...
OLLAMA_HOST=http://localhost:11434  # local models
```

---

## Examples

The [`examples/`](examples/) directory has runnable demos organized by category:

| Category | Highlights |
|----------|-----------|
| [**Basics**](examples/basics/) | Hello world, streaming, structured output, taskboard |
| [**Capabilities**](examples/capabilities/) | Filesystem, browser, code sandbox, web search, database, knowledge graphs, MCP, shell, spreadsheets |
| [**Advanced**](examples/advanced/) | ACC memory, semantic cache, interceptors, human-in-the-loop, reasoning, delegation |
| [**Long-Running**](examples/long_running/) | Async-await patterns, suspend/resume for multi-session workflows |
| [**Retrieval**](examples/retrieval/) | PDF summarization, vision extraction, 12 retriever strategies, HyDE |
| [**Observability**](examples/observability/) | Observer, shared observers, subagent lineage, custom formatters |
| [**Subagents**](examples/subagent/) | Delegation patterns |
| [**A2A**](examples/a2a/) | Remote agent communication |

---

## Development

```bash
uv sync --group dev --group test
uv run pytest                  # run all tests (1816 unit + integration)
uv run pytest tests/integration # run integration tests only
uv run ruff check src/cogent   # lint
uv run mypy src/cogent         # type check
```

---

## License

MIT — see [LICENSE](LICENSE).
