Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
333 changes: 323 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,326 @@
# AgentKit
# AgentKit ⚡️

AgentKit is a lightweight, provider-agnostic ReAct agent framework in Python built from scratch without external agent frameworks (such as LangChain or LlamaIndex). It provides a production-grade ReAct reasoning loop, automated Pydantic-based tool schema generation, pluggable LLM adapters (Google Gemini and OpenAI), session caching in Redis, and durable execution tracing in PostgreSQL, exposed via a FastAPI REST service.
[![CI](https://github.com/getdownandcode/AgentKit/actions/workflows/ci.yml/badge.svg)](https://github.com/getdownandcode/AgentKit/actions/workflows/ci.yml)
[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
[![FastAPI](https://img.shields.io/badge/FastAPI-0.115%2B-009688.svg)](https://fastapi.tiangolo.com)
[![Pydantic v2](https://img.shields.io/badge/Pydantic-v2-E92063.svg)](https://docs.pydantic.dev/)
[![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
[![Checked with mypy](https://img.shields.io/badge/mypy-strict-blue.svg)](https://mypy-lang.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

> **Status**: Project scaffolding and warm-up phase complete. See [docs/PLAN.md](docs/PLAN.md) for the implementation roadmap and [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the architecture design.
**AgentKit** is a lightweight, provider-agnostic, production-grade ReAct (Reasoning + Acting) autonomous agent framework written entirely in Python from scratch — **with zero external agent frameworks** (no LangChain, no LlamaIndex, no CrewAI).

## Documentation
- [Agent Specifications](docs/SPEC.md)
- [Architecture & Data Flow](docs/ARCHITECTURE.md)
- [Agent & Engineering Guidelines](AGENTS.md)
- [Implementation Plan & Backlog](docs/PLAN.md)
- [Architecture Decision Log](docs/DECISIONS.md)
- [Progress Log](docs/PROGRESS.md)
Designed from first principles for reliability, auditability, and production deployment, AgentKit implements an explicit ReAct state machine, automated Pydantic v2 tool schema synthesis, multi-provider LLM adapters (Google Gemini and OpenAI), dual-store persistence (ephemeral Redis session caching + durable PostgreSQL step-level execution tracing), and a secure FastAPI service.

---

## Key Features

- **Built From Scratch**: Transparent, debuggable async ReAct reasoning loop. No hidden chains, no monkey-patched prompts.
- **Provider-Agnostic LLM Layer**: First-class support for **Google Gemini** (`google-genai`) and **OpenAI** (`openai`), with an isolated `FakeLLMClient` for deterministic offline testing.
- **Declarative Type-Safe Tools**: Register Python functions with the `@tool` decorator. Function signatures, type hints, and docstrings are introspected into strict JSON Schema and dynamic Pydantic argument validators.
- **Production Built-in Tools**:
- `calculator`: AST-parsed mathematical evaluator with strict operator whitelisting and recursion/exponent limits.
- `sql_readonly`: Read-only SQL executor with single-SELECT AST validation, comment stripping, and DDL/DML blocking.
- `read_file`: Path traversal and symlink escape defended sandboxed file reader.
- `http_fetch`: SSRF-protected HTTP client blocking private subnets, loopbacks, and cloud metadata endpoints.
- `web_search`: Search provider adapter with result truncation.
- **Dual-Store Persistence**:
- **Redis**: Sliding-window session memory and high-throughput sliding window rate limiter.
- **PostgreSQL**: Durable execution audit trails with step-by-step latency, token counts, and tool outcomes.
- **Enterprise-Grade Reliability**:
- Exponential backoff retry with full jitter for transient LLM errors.
- Global run timeout, per-tool timeout guards, and consecutive duplicate tool call loop detection.
- Structured contextual JSON logging (`run_id`, `step_no`, duration) with zero raw confidential prompt leakage.
- **Containerized & CI-Ready**: Multi-stage production `Dockerfile`, `docker-compose.yml` with healthchecks, and full GitHub Actions CI matrix (`ruff`, `mypy`, `pytest` >= 85% coverage).

---

## Architecture & Data Flow

```mermaid
flowchart TD
User["Client / Caller"] -->|"HTTP POST /runs"| API["FastAPI Layer (agentkit/api)"]
API -->|"Auth & Rate Limiting"| Middleware["Auth (X-API-Key) & Redis Rate Limiter"]
Middleware -->|"Dispatches Run"| Core["ReAct Agent Runtime (agentkit/core)"]

subgraph "Core ReAct Execution Loop"
Core -->|"1. Format History & Tools"| LLM["LLM Client Adapter (agentkit/llm)"]
LLM -->|"2. Model Reasoning"| Provider["Gemini / OpenAI / Fake"]
Provider -->|"3. Tool Call Request"| Core
Core -->|"4. Duplicate & Loop Check"| Guard["Guards & Circuit Breakers"]
Guard -->|"5. Execute Tool"| Executor["Tool Registry (agentkit/tools)"]
Executor -->|"6. Tool Output (ok/error)"| Core
Core -->|"7. Append Result Turn"| LLM
end

subgraph "Persistence & Telemetry"
Core -->|"Session Context"| RedisStore[("Redis (Session TTL)")]
Core -->|"Step Traces & Run Records"| PGStore[("PostgreSQL (Durable Audit)")]
end

Core -->|"Final Synthesized Answer"| API
API -->|"JSON Response"| User
```

### Layering Rules
AgentKit enforces a unidirectional dependency hierarchy:
$$\text{API Layer} \longrightarrow \text{Core Layer} \longrightarrow (\text{LLM}, \text{Tools}, \text{Memory}, \text{DB})$$
Lower layers never import from upper layers. Dependencies are passed explicitly via constructors and FastAPI dependency injection.

---

## Quickstart Guide

### 1. Prerequisites
- Python 3.11+ (Python 3.12 recommended)
- Docker & Docker Compose (optional for local containerized stack)
- Git

### 2. Installation
```bash
# Clone the repository
git clone https://github.com/getdownandcode/AgentKit.git
cd AgentKit

# Create and activate virtual environment
python3 -m venv .venv
source .venv/bin/activate

# Install package with all runtime and development dependencies
pip install --upgrade pip
pip install -e ".[dev]"
```

### 3. Environment Configuration
Copy the sample environment file and set your credentials:
```bash
cp .env.example .env
```

Edit `.env`:
```ini
ENVIRONMENT=development
LOG_LEVEL=INFO

# LLM Providers (at least one key or use offline mode)
LLM_PROVIDER=gemini
GEMINI_API_KEY=your_gemini_api_key_here
OPENAI_API_KEY=your_openai_api_key_here

# Persistence
DATABASE_URL=postgresql+asyncpg://agentkit:agentkit_password@localhost:5432/agentkit
REDIS_URL=redis://localhost:6379/0

# Security
API_KEYS=dev_key_1,dev_key_2
JWT_SECRET=super_secret_jwt_key_at_least_32_bytes_long
```

### 4. Running with Docker Compose (Recommended)
Launch the API, PostgreSQL, and Redis together with automatic migrations:
```bash
docker compose up -d --build

# Verify all services are healthy
docker compose ps
```

Check API health:
```bash
curl -s http://localhost:8000/health | jq .
```

### 5. Running the Multi-Tool Demo
AgentKit includes a complete multi-tool demo script that seeds a database and combines SQL analysis with mathematical calculation:

```bash
# Completely offline demo (using FakeLLMClient - no API keys required!)
python examples/demo.py --offline

# Or live with Gemini:
python examples/demo.py --provider gemini
```

---

## 10-Line `@tool` Tutorial

Creating a custom tool in AgentKit requires only native Python typing and the `@tool` decorator. AgentKit automatically parses argument types, docstring parameter documentation, and registers JSON Schema validators.

```python
from agentkit.tools.registry import default_registry, tool


@tool
def currency_converter(amount: float, from_curr: str, to_curr: str) -> float:
"""Convert an amount from one fiat currency to another.

Args:
amount: Numerical money amount to convert.
from_curr: ISO 3-letter source currency code (e.g. USD).
to_curr: ISO 3-letter target currency code (e.g. EUR).
"""
rates = {"USD": 1.0, "EUR": 0.92, "GBP": 0.79, "JPY": 155.0}
amount_in_usd = amount / rates[from_curr.upper()]
return round(amount_in_usd * rates[to_curr.upper()], 2)


# Schema is automatically generated and inspectable
schema = default_registry.get("currency_converter").schema
print(schema.parameters)
```

Tools can be synchronous or asynchronous (`async def`), and can be attached to custom scoped registries:
```python
from agentkit.tools.registry import ToolRegistry

isolated_registry = ToolRegistry()
isolated_registry.register(currency_converter)
```

---

## Provider Extension Guide

Adding a new LLM provider (such as Anthropic Claude, Mistral, or a local vLLM endpoint) is straightforward. Simply implement the `LLMClient` abstract interface:

```python
from collections.abc import Sequence
from agentkit.llm.base import LLMClient, LLMResponse, Message, TokenUsage
from agentkit.tools.models import ToolSchema


class AnthropicClient(LLMClient):
"""Custom Anthropic Claude adapter for AgentKit."""

def __init__(self, api_key: str, model: str = "claude-3-5-sonnet-20241022") -> None:
self.api_key = api_key
self.model = model

async def chat(
self,
messages: Sequence[Message],
tools: Sequence[ToolSchema] | None = None,
system_prompt: str | None = None,
) -> LLMResponse:
# 1. Translate neutral AgentKit Message sequence to Anthropic format
# 2. Translate neutral ToolSchema to Anthropic tool definitions
# 3. Call client API asynchronously
# 4. Return neutral LLMResponse(text=..., tool_calls=[...], usage=...)
...
```

Register your client in `agentkit/llm/factory.py`:
```python
# In agentkit/llm/factory.py
if normalized_provider == "anthropic":
return AnthropicClient(api_key=api_key or settings.ANTHROPIC_API_KEY, model=model)
```

---

## Sample Trace Output

Every reasoning step in AgentKit is captured as a structured `StepTrace` and recorded to the active `TraceSink` (such as `PostgresTraceSink` or `InMemoryTraceSink`):

```json
{
"run_id": "8e3b52d4-1a93-4a1e-8e81-cf1b41db61e8",
"step_number": 2,
"thought": "SQL query returned total revenue of $3,200.00. Now calculating 8.5% sales tax.",
"tool_calls": [
{
"id": "call_calc_4981",
"name": "calculator",
"arguments": {
"expression": "3200 * 1.085"
}
}
],
"tool_results": [
{
"tool_call_id": "call_calc_4981",
"tool_name": "calculator",
"ok": true,
"output": "3472.0",
"error": null,
"duration_ms": 1
}
],
"input_tokens": 420,
"output_tokens": 45,
"step_duration_ms": 380,
"timestamp": "2026-09-29T23:26:11.993000Z"
}
```

View run traces programmatically via REST API:
```bash
curl -H "X-API-Key: YOUR_API_KEY" http://localhost:8000/runs/{run_id}/trace | jq .
```

---

## Architectural Decisions (ADR Summary)

Key architectural trade-offs are documented in [docs/DECISIONS.md](docs/DECISIONS.md):

- **ADR-001: Framework-less Agent Runtime**: Built directly on Python standard libraries and async primitives to eliminate framework bloat, prevent hidden prompt modifications, and allow exact step debugging.
- **ADR-002: Neutral LLM Adapter Layer**: Pluggable `LLMClient` protocol ensures that changing model providers requires zero changes to the core reasoning loop.
- **ADR-003: Tiered Dual-Store Persistence**:
- Redis manages ephemeral conversation sliding windows with automatic TTL expiration and rate limiting.
- PostgreSQL retains permanent, queryable execution audits and performance metrics.
- **ADR-004: Declarative Tool Introspection**: Pydantic v2 runtime introspection automatically converts native Python type hints into JSON Schema and validates tool arguments before execution.

---

## Production AWS Deployment

AgentKit is designed to run reliably as a single-node containerized deployment on AWS EC2 behind a TLS reverse proxy (Caddy or Nginx) with automated database backups to S3.

Complete step-by-step instructions, including security group rules, systemd service daemon configuration, and AWS SSM secret retrieval, are available in the [AWS Deployment Guide](docs/DEPLOY.md).

---

## Testing & Quality Assurance

AgentKit enforces strict code quality and comprehensive test coverage across all layers:

```bash
# Run the complete test suite
pytest -v

# Run with test coverage report (enforcing >=85% threshold)
pytest --cov=agentkit --cov-report=term-missing --cov-fail-under=85

# Run Ruff linter and formatter check
ruff check .
ruff format --check .

# Run Mypy strict type-checker
mypy agentkit tests examples
```

All pull requests trigger the automated GitHub Actions CI matrix running on Python 3.11 and 3.12 with live PostgreSQL 16 and Redis 7 service containers.

---

## Limitations & Future Roadmap

### Current Limitations
- **Sequential Tool Execution**: In the current ReAct loop, multiple tool calls in a single turn are executed sequentially rather than in parallel.
- **Single-Node API**: Rate limiting and session caching use a single Redis instance; distributed Redis cluster configurations are not yet automated.
- **Synchronous Responses**: The `/runs` REST endpoint returns when the full run completes; Server-Sent Events (SSE) streaming is not yet enabled.

### Future Roadmap
- [ ] **Parallel Tool Execution**: Dispatch independent tool calls concurrently using `asyncio.gather()`.
- [ ] **Streaming SSE Token Protocol**: Real-time streaming of thoughts, tool invocations, and token chunks over Server-Sent Events.
- [ ] **Multi-Agent Orchestration**: Hierarchical supervisor-worker agent delegation without external frameworks.
- [ ] **Human-in-the-Loop Interrupts**: Pausing execution for human approval before invoking sensitive tools (e.g., destructive actions or payment APIs).

---

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
Loading