Metadata-Version: 2.4
Name: koan-ai
Version: 0.1.0
Summary: KOAN - Knowledge-Oriented Agent Network: A context graph-native framework for AI agents
Project-URL: Homepage, https://github.com/koan-framework/koan
Project-URL: Documentation, https://github.com/koan-framework/koan/tree/main/docs
Project-URL: Repository, https://github.com/koan-framework/koan.git
Project-URL: Issues, https://github.com/koan-framework/koan/issues
Project-URL: Changelog, https://github.com/koan-framework/koan/blob/main/CHANGELOG.md
Author: KOAN Contributors
License-Expression: MIT
License-File: LICENSE
Keywords: agents,ai,context-graph,decision-tracing,graph,llm,multi-agent,orchestration
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: anyio>=4.4
Requires-Dist: httpx>=0.28.1
Requires-Dist: orjson>=3.11
Requires-Dist: pydantic-settings>=2.11.0
Requires-Dist: pydantic>=2.12.3
Requires-Dist: python-dotenv>=1.2.1
Requires-Dist: structlog>=25.5.0
Requires-Dist: tenacity>=9.1.2
Requires-Dist: typing-extensions>=4.15
Provides-Extra: all
Requires-Dist: aiosqlite>=0.20; extra == 'all'
Requires-Dist: anthropic>=0.84.0; extra == 'all'
Requires-Dist: beautifulsoup4>=4.12; extra == 'all'
Requires-Dist: chromadb>=1.5.2; extra == 'all'
Requires-Dist: jinja2>=3.1; extra == 'all'
Requires-Dist: lxml>=5.0; extra == 'all'
Requires-Dist: mcp>=1.26.0; extra == 'all'
Requires-Dist: neo4j-graphrag>=1.13.0; extra == 'all'
Requires-Dist: neo4j>=6.1.0; extra == 'all'
Requires-Dist: numpy>=2.0; extra == 'all'
Requires-Dist: openai-agents>=0.10.2; extra == 'all'
Requires-Dist: openai>=2.26.0; extra == 'all'
Requires-Dist: opentelemetry-api>=1.38.0; extra == 'all'
Requires-Dist: opentelemetry-exporter-otlp>=1.38.0; extra == 'all'
Requires-Dist: opentelemetry-sdk>=1.38.0; extra == 'all'
Requires-Dist: pypdf>=4.0; extra == 'all'
Requires-Dist: python-docx>=1.1; extra == 'all'
Requires-Dist: rich>=14.2.0; extra == 'all'
Requires-Dist: sqlalchemy>=2.0.44; extra == 'all'
Requires-Dist: tiktoken>=0.12.0; extra == 'all'
Requires-Dist: typer>=0.12; extra == 'all'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.84.0; extra == 'anthropic'
Provides-Extra: cli
Requires-Dist: rich>=14.2.0; extra == 'cli'
Requires-Dist: typer>=0.12; extra == 'cli'
Provides-Extra: demos
Requires-Dist: fastapi>=0.135.1; extra == 'demos'
Requires-Dist: sse-starlette>=3.3.2; extra == 'demos'
Requires-Dist: uvicorn>=0.41.0; extra == 'demos'
Provides-Extra: docs
Requires-Dist: beautifulsoup4>=4.12; extra == 'docs'
Requires-Dist: lxml>=5.0; extra == 'docs'
Requires-Dist: pypdf>=4.0; extra == 'docs'
Requires-Dist: python-docx>=1.1; extra == 'docs'
Provides-Extra: graph
Requires-Dist: neo4j-graphrag>=1.13.0; extra == 'graph'
Requires-Dist: neo4j>=6.1.0; extra == 'graph'
Provides-Extra: graph-falkordb
Requires-Dist: falkordb>=1.6.0; extra == 'graph-falkordb'
Provides-Extra: graph-memgraph
Requires-Dist: neo4j>=6.1.0; extra == 'graph-memgraph'
Provides-Extra: graph-neo4j
Requires-Dist: neo4j-graphrag>=1.13.0; extra == 'graph-neo4j'
Requires-Dist: neo4j>=6.1.0; extra == 'graph-neo4j'
Provides-Extra: llm
Requires-Dist: anthropic>=0.84.0; extra == 'llm'
Requires-Dist: openai-agents>=0.10.2; extra == 'llm'
Requires-Dist: openai>=2.26.0; extra == 'llm'
Requires-Dist: tiktoken>=0.12.0; extra == 'llm'
Provides-Extra: mcp
Requires-Dist: mcp>=1.26.0; extra == 'mcp'
Provides-Extra: memory
Requires-Dist: aiosqlite>=0.20; extra == 'memory'
Requires-Dist: sqlalchemy>=2.0.44; extra == 'memory'
Provides-Extra: openai
Requires-Dist: openai-agents>=0.10.2; extra == 'openai'
Requires-Dist: openai>=2.26.0; extra == 'openai'
Requires-Dist: tiktoken>=0.12.0; extra == 'openai'
Provides-Extra: prompts
Requires-Dist: jinja2>=3.1; extra == 'prompts'
Provides-Extra: streaming
Requires-Dist: anthropic>=0.84.0; extra == 'streaming'
Requires-Dist: openai-agents>=0.10.2; extra == 'streaming'
Requires-Dist: openai>=2.26.0; extra == 'streaming'
Requires-Dist: tiktoken>=0.12.0; extra == 'streaming'
Provides-Extra: telemetry
Requires-Dist: opentelemetry-api>=1.38.0; extra == 'telemetry'
Requires-Dist: opentelemetry-exporter-otlp>=1.38.0; extra == 'telemetry'
Requires-Dist: opentelemetry-sdk>=1.38.0; extra == 'telemetry'
Provides-Extra: vector
Requires-Dist: chromadb>=1.5.2; extra == 'vector'
Requires-Dist: numpy>=2.0; extra == 'vector'
Description-Content-Type: text/markdown

# KOAN

**Knowledge-Oriented Agent Network**

A context graph-native framework for intelligent, grounded, and traceable AI agents.

KOAN connects LLM-powered agents to property graph databases, so every decision an agent makes is recorded as a traceable node in a decision graph. This enables precedent search, policy governance, gap detection, and full audit trails across multi-agent systems.

## Features

- **Unified LLM Client** -- OpenAI and Anthropic with automatic retry, streaming, and cost tracking
- **Structured Output** -- Parse LLM responses into typed Pydantic models
- **Tool System** -- `@tool` decorator with automatic JSON schema generation
- **Agent Orchestration** -- ReAct agents, sequential chains, parallel fan-out, supervisor, and orchestrator patterns
- **Streaming** -- Token-by-token streaming for agents, orchestrators, and SSE endpoints
- **MCP Integration** -- Build and connect to Model Context Protocol servers
- **Context Graphs** -- Trace every agent decision into Neo4j, Memgraph, or FalkorDB
- **Graph-Augmented Reasoning** -- Agents read past decisions, entity history, and policies from the graph before reasoning, then write new traces back (closed loop)
- **Self-Organizing Policies** -- Policies emerge automatically from repeated tool patterns, gate available tools, and retire when feedback turns negative
- **Feedback-Weighted Precedents** -- Past decisions carry feedback scores so agents learn which approaches worked and which didn't
- **Precedent Search** -- Find past decisions for the same entity, with confidence and outcome data
- **Policy Governance** -- Link decisions to policies, detect ungoverned gaps
- **Memory** -- Thread-scoped conversation history (SQLite), vector memory (ChromaDB), forkable threads with checkpoint/rewind (time travel)
- **Observability** -- OpenTelemetry tracing, structured logging, per-call cost tracking
- **CLI** -- `koan verify`, `koan init`, `koan mcp dev`, `koan graph init`

## Install

```bash
pip install koan-ai
```

With LLM providers:

```bash
pip install koan-ai[llm]          # OpenAI + Anthropic
pip install koan-ai[openai]       # OpenAI only
pip install koan-ai[anthropic]    # Anthropic only
```

With context graphs:

```bash
pip install koan-ai[graph-neo4j]     # Neo4j
pip install koan-ai[graph-memgraph]  # Memgraph
pip install koan-ai[graph-falkordb]  # FalkorDB
```

Everything:

```bash
pip install koan-ai[all]
```

> **Note**: The PyPI package is `koan-ai`, but the import name is `koan`:
> ```python
> import koan
> from koan.agents import ReactAgent
> ```

## Quickstart

### 1. Basic LLM Call

```python
import asyncio
from koan.llm.client import LLMClient
from koan.llm.config import LLMConfig
from koan.types import Message

async def main():
    async with LLMClient() as client:
        config = LLMConfig(provider="openai", model="gpt-4o-mini")
        messages = [Message(role="user", content="What is KOAN?")]
        response = await client.complete(config, messages)
        print(response.text)

asyncio.run(main())
```

### 2. Agent with Tools

```python
import asyncio
from koan.agents import AgentConfig, ReactAgent
from koan.llm.client import LLMClient
from koan.tools import ToolRegistry, tool

@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"22C and sunny in {city}"

async def main():
    async with LLMClient() as client:
        registry = ToolRegistry()
        registry.add(get_weather)

        agent = ReactAgent(
            "weather-bot",
            client=client,
            config=AgentConfig(
                provider="openai",
                model="gpt-4o-mini",
                system_prompt="Use tools to answer questions.",
            ),
            tools=registry,
        )

        result = await agent.run("What's the weather in Tokyo?")
        print(result.output)

asyncio.run(main())
```

### 3. Multi-Agent Orchestrator

```python
from koan.agents import Orchestrator, ReactAgent, RuleRouter

orchestrator = Orchestrator(
    agents={
        "finance": finance_agent,
        "hr": hr_agent,
    },
    router=RuleRouter({
        "stock": "finance", "price": "finance",
        "employee": "hr", "pto": "hr",
    }),
)

result = await orchestrator.run("What is the stock price of AAPL?")
```

### 4. Decision Tracing with Context Graphs

```python
from koan.graph import DecisionTracer, GraphConfig, create_graph_client

config = GraphConfig(provider="falkordb", uri="redis://localhost:6379")

async with create_graph_client(config) as graph:
    async with DecisionTracer(graph, run_id="r-1", agent_id="bot", thread_id="t-1") as tracer:
        decision_id = await tracer.record_decision(
            description="Classified as billing inquiry",
            decision_type="classification",
            confidence=0.95,
            reasoning="Keywords: invoice, payment",
        )
        await tracer.record_action(
            decision_id=decision_id,
            action_type="tool_call",
            tool_name="lookup_billing",
        )
        await tracer.record_outcome(status="success", result="Resolved")
```

### 5. Streaming Agent Events

```python
from koan.agents import StreamingReactAgent, ToolCallStart, TextDelta, AgentComplete

agent = StreamingReactAgent("bot", client=client, config=config, tools=registry)

async for event in agent.run_stream("What is 17 + 28?"):
    if isinstance(event, TextDelta):
        print(event.text, end="", flush=True)
    elif isinstance(event, ToolCallStart):
        print(f"\n[calling {event.tool_name}...]")
    elif isinstance(event, AgentComplete):
        print(f"\nDone ({event.tool_calls_made} tool calls)")
```

## Architecture

```
koan/
├── llm/          # Unified LLM client (OpenAI, Anthropic)
├── output/       # Structured output parsing (Pydantic)
├── prompts/      # Jinja2 prompt templates
├── streaming/    # Token streaming, SSE helpers
├── tools/        # @tool decorator, registry, execution
├── memory/       # Thread store (SQLite), vector memory (ChromaDB)
├── agents/       # ReAct, Chain, Parallel, Orchestrator, Supervisor
├── mcp/          # MCP server builder + client
├── graph/        # Context graphs (Neo4j, Memgraph, FalkorDB)
├── telemetry/    # OpenTelemetry, structured logging, cost tracking
└── cli/          # Developer CLI (verify, init, mcp dev, graph init)
```

### Context Graph Schema

```
Agent -EXECUTED-> Run -CONTAINS-> Decision -LED_TO-> Action
                   |                  |
                   +-PRODUCED-> Outcome  |-GOVERNED_BY-> Policy
                                         |-REFERENCED-> Entity
                                         +-CITED_PRECEDENT-> Decision
```

## Graph Database Setup

Start a graph database with Docker:

```bash
# FalkorDB (Redis protocol)
docker compose -f docker/docker-compose.graph.yml --profile falkordb up -d

# Neo4j (Bolt protocol)
docker compose -f docker/docker-compose.graph.yml --profile neo4j up -d

# Memgraph (Bolt protocol)
docker compose -f docker/docker-compose.graph.yml --profile memgraph up -d
```

## CLI

```bash
koan verify          # Check API keys and installed packages
koan init [path]     # Scaffold a new KOAN project
koan mcp dev <file>  # Run an MCP server in dev mode
koan graph init      # Initialize graph database schema
```

## Examples

See the [examples/](examples/) directory for working demonstrations:

| Example | Description |
|---------|-------------|
| `01_basic_completion.py` | Simplest LLM call |
| `02_structured_output.py` | Pydantic model as output |
| `03_streaming_chat.py` | Token-by-token streaming |
| `04_tool_agent.py` | Agent with custom tools |
| `05_multi_agent.py` | Orchestrator + sub-agents |
| `09_streaming_tool_agent.py` | Streaming agent with tools |
| `10_streaming_orchestrator.py` | Streaming multi-agent |
| `12_supervisor.py` | Supervisor pattern |
| `13_mcp_server_client.py` | MCP server + client |
| `15_supervisor_mcp_agents.py` | Per-agent MCP servers |
| `16_context_graph.py` | Full context graph lifecycle |
| `17_graph_augmented_agent.py` | Graph-augmented agent (closed loop) |
| `18_feedback_and_calibration.py` | Human feedback and confidence calibration |

## Demos

Eight interactive demo apps (FastAPI + browser UI) showcasing KOAN in action:

| Demo | Port | Features |
|------|------|----------|
| **Demo 1** — Simple Chat | 8001 | ReactAgent, tools, SQLite threads, SSE streaming |
| **Demo 2** — Graph Chat | 8002 | GraphAugmentedAgent, feedback, context graph |
| **Demo 3** — Multi-Agent | 8003 | Orchestrator, RuleRouter, 3 agents |
| **Demo 4** — Full Stack | 8004 | Multi-agent + graph, evaluation, calibration |
| **Demo 5** — Self-Organizing | CLI | Full policy lifecycle: emergence → gating → retirement |
| **Demo 6** — Legal Assistant | 8006 | Case lookup, document search, motion drafting |
| **Demo 7** — Medical Triage | 8007 | Patient vitals, labs, medication & allergy checks |
| **Demo 8** — Investment Advisor | 8008 | Portfolio risk, trade execution, market data |

Demos 5-8 demonstrate the self-organizing policy lifecycle across different domains. See [demos/](demos/) for setup instructions and [demos/TEST_QUESTIONS.md](demos/TEST_QUESTIONS.md) for copy-paste test scripts.

## Development

```bash
# Install uv
curl -Ls https://astral.sh/uv/install.sh | sh

# Clone and setup
git clone https://github.com/koan-framework/koan.git
cd koan
uv sync --group dev

# Run tests
uv run pytest                                      # Unit tests (no external deps)
uv run pytest -m integration                       # Integration tests (needs API keys)
uv run pytest -m graph                             # Graph tests (needs Docker)

# Lint and type check
uv run ruff check src/
uv run pyright src/
```

## License

MIT
