diff --git a/README.md b/README.md index d3367db..32c85b6 100644 --- a/README.md +++ b/README.md @@ -1,399 +1,212 @@ -# AgentKit ⚡️ +# AgentKit [![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) -**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). - -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 over a dedicated non-superuser role (`DATABASE_READONLY_URL`, `default_transaction_read_only`, `SELECT`-only grants, fail-closed when unconfigured). A statement lexer accepts a single `SELECT`/`WITH`, rejects comments, DDL/DML and privileged built-ins (`pg_read_file`, `setval`, `query_to_xml`, …), and clamps `LIMIT ALL`/oversized limits in SQL. - - `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; registered only when `SEARCH_API_KEY` is configured. -- **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. - - Client disconnects never leave zombie runs: cancellation persists a terminal `canceled` status plus repaired session history inside `asyncio.shield` before re-raising. - - 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 -``` +AgentKit is a Python service for running tool-using AI agents. A client submits a goal, the agent asks a language model what to do, runs any requested tools, and returns a final answer. Runs and tool steps are recorded so they can be inspected later. -### 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. +The runtime is implemented in this repository rather than delegated to an agent framework. It supports Google Gemini and OpenAI; tests use a fake model client so the normal test suite does not need provider credentials. ---- +## What happens during a run -## Quickstart Guide +1. FastAPI validates the request, checks the API key, and applies rate limiting. +2. The agent loads prior conversation messages for the optional session ID. +3. The selected model returns either an answer or one or more tool calls. +4. The tool registry validates each call against a generated Pydantic schema and runs it with timeout and output-size limits. +5. The agent sends tool results back to the model and repeats until it gets a final answer or reaches a guardrail. +6. Session history is stored in Redis; run records and step traces are stored in PostgreSQL. -### 1. Prerequisites -- Python 3.11+ (Python 3.12 recommended) -- Docker & Docker Compose (optional for local containerized stack) -- Git +Run requests are synchronous: `POST /runs` returns after the agent finishes. The loop has maximum-step, run-timeout, tool-timeout, and repeated-call protections. -### 2. Installation -```bash -# Clone the repository -git clone https://github.com/getdownandcode/AgentKit.git -cd AgentKit +## Start the service -# Create and activate virtual environment -python3 -m venv .venv -source .venv/bin/activate +### Requirements -# Install package with all runtime and development dependencies -pip install --upgrade pip -pip install -e ".[dev]" -``` +- Python 3.11 or later +- Docker with the Compose plugin +- An API key for the model provider you choose (Gemini by default, or OpenAI) + +### Configure and start -### 3. Environment Configuration -Copy the sample environment file and set your credentials: ```bash +git clone https://github.com/getdownandcode/AgentKit.git +cd AgentKit cp .env.example .env ``` -Edit `.env`: -```ini -# LLM Providers (at least one key or use offline mode) -LLM_PROVIDER=gemini -LLM_MODEL=gemini-3.1-flash-lite -GEMINI_API_KEY=your_gemini_api_key_here -OPENAI_API_KEY=your_openai_api_key_here - -# Persistence. Credentials are components, not parts of a URL: AgentKit escapes them -# while it builds DATABASE_URL / DATABASE_READONLY_URL, so a password may contain -# '/', '+' or '=' (as `openssl rand -base64 24` output does). -POSTGRES_HOST=localhost -POSTGRES_PORT=5432 -POSTGRES_USER=agentkit -POSTGRES_PASSWORD=agentkit_password -POSTGRES_DB=agentkit -POSTGRES_READONLY_USER=agentkit_readonly -POSTGRES_READONLY_PASSWORD=agentkit_readonly_password -REDIS_PASSWORD=redis_password -REDIS_URL=redis://localhost:6379/0 - -# Security (API_KEYS is required; the app refuses to start without it) -API_KEYS=dev_key_1,dev_key_2 - -# Optional: retry policy for transient LLM failures (429/5xx/network) -LLM_MAX_RETRIES=3 -LLM_RETRY_BASE_DELAY_S=0.5 -LLM_RETRY_MAX_DELAY_S=10 -RETRY_AFTER_FALLBACK_S=60 -``` +Edit `.env` before starting Compose. Replace the example values for: -### 4. Running with Docker Compose (Recommended) -Launch the API, PostgreSQL, and Redis together with automatic migrations. +- `POSTGRES_PASSWORD` +- `POSTGRES_READONLY_PASSWORD` +- `REDIS_PASSWORD` +- `API_KEYS` +- `GEMINI_API_KEY` or `OPENAI_API_KEY`, according to `LLM_PROVIDER` -`API_KEYS` is required in every environment, not just under compose. `Settings` rejects an -empty value, so a deployment that forgets to configure its keys fails at startup rather than -serving unauthenticated traffic with a key published in the repository. `docker-compose.yml` -ships no default either; `down`, `ps` and `logs` still work without it. +Use distinct, randomly generated passwords and API keys. The Compose stack rejects missing or weak datastore passwords and an empty API key list. Keep `.env` private; it contains secrets. Compose binds PostgreSQL and Redis to localhost by default. -```bash -export API_KEYS=ak_local_dev_key # or place API_KEYS in your .env -docker compose up -d --build +Start the application: -# Verify all services are healthy +```bash +docker compose up --build -d docker compose ps ``` -Check API health: +Compose starts PostgreSQL and Redis, runs migrations and demo-data seeding, provisions the dedicated read-only SQL role, then starts the API on `http://localhost:8000`. + +Check service health: + ```bash -curl -s http://localhost:8000/health | jq . +curl -sS http://localhost:8000/health ``` -### 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: +### Make your first request + +Use one key from the comma-separated `API_KEYS` setting as the `X-API-Key` header: ```bash -# Against real infrastructure (PostgreSQL + Redis from your .env). -# Run and step records are persisted exactly as they would be in production. -docker compose up -d postgres redis -alembic upgrade head -python examples/demo.py --provider gemini +export AGENTKIT_API_KEY='your-local-api-key' -# Or completely offline (FakeLLMClient + in-memory SQLite - no services, no API keys) -python examples/demo.py --offline +curl -sS -X POST http://localhost:8000/runs \ + -H "X-API-Key: $AGENTKIT_API_KEY" \ + -H 'Content-Type: application/json' \ + -d '{"goal":"Calculate 19 percent tax on 250"}' ``` -The demo prints the run ID; you can then inspect what it wrote: +Copy the `run_id` from the response and set it below: ```bash -curl -s -H "X-API-Key: $API_KEYS" "http://localhost:8000/runs//trace" | jq . -``` +export RUN_ID='paste-run-id-from-response' ---- +curl -sS -H "X-API-Key: $AGENTKIT_API_KEY" \ + "http://localhost:8000/runs/$RUN_ID" -## 10-Line `@tool` Tutorial +curl -sS -H "X-API-Key: $AGENTKIT_API_KEY" \ + "http://localhost:8000/runs/$RUN_ID/trace" +``` -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. +You can inspect the interactive API schema at [http://localhost:8000/docs](http://localhost:8000/docs). `GET /health` is public; run and tool endpoints require authentication. -```python -from agentkit.tools.registry import default_registry, tool +## Try the demo without services +To see the agent loop without Docker, a model API key, or external services, install the package and run the scripted offline demo: -@tool -def currency_converter(amount: float, from_curr: str, to_curr: str) -> float: - """Convert an amount from one fiat currency to another. +```bash +python3 -m venv .venv +source .venv/bin/activate +python -m pip install -e '.[dev]' +python examples/demo.py --offline +``` - 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) +The demo uses `FakeLLMClient` and in-memory stores. It is intended to show the flow, not to test a live model. The live demo options and configuration are described by `python examples/demo.py --help`. +## How the repository is organized -# Schema is automatically generated and inspectable -schema = default_registry.get("currency_converter").schema -print(schema.parameters) -``` +| Path | What belongs here | +| --- | --- | +| `agentkit/api/` | FastAPI app, routes, request/response schemas, authentication, rate limiting, and dependency wiring. | +| `agentkit/core/` | The ReAct run loop, run types and errors, logging context, and trace interfaces. | +| `agentkit/llm/` | The provider-neutral LLM interface, Gemini and OpenAI adapters, factory, retry wrapper, and fake client. | +| `agentkit/tools/` | Tool models, schema generation, registry, executor, and built-in tools. | +| `agentkit/memory/` | Redis session history, PostgreSQL run storage, and the tiered store that combines them. | +| `agentkit/db/` | SQLAlchemy models and database/session setup. | +| `agentkit/config.py` | Pydantic settings loaded from environment variables and `.env`. | +| `migrations/` | Alembic schema migrations. | +| `scripts/` | Deployment credential checks, demo seeding, and read-only SQL role provisioning. | +| `examples/` | Runnable examples, including `demo.py`. | +| `tests/unit/` | Fast tests for isolated components; external LLMs are mocked. | +| `tests/integration/` | API and workflow tests using local test doubles and SQLite. | +| `tests/real/` | Opt-in tests against live PostgreSQL and Redis. | +| `docs/` | Architecture, deployment, specification, design decisions, audit notes, and progress log. | -Tools can be synchronous or asynchronous (`async def`), and can be attached to custom scoped registries: -```python -from agentkit.tools.registry import ToolRegistry +The API assembles the provider, persistence, trace, and tool-registry dependencies and passes them to the agent. This keeps HTTP handling and provider-specific SDK details outside the run loop. -isolated_registry = ToolRegistry() -isolated_registry.register(currency_converter) -``` +## Built-in tools ---- +The standard API registry includes these tools: -## Provider Extension Guide +- `calculator` evaluates arithmetic through a restricted AST evaluator. +- `read_file` reads files under the configured sandbox directory and blocks traversal and symlink escapes. +- `http_fetch` fetches HTTP(S) resources while blocking private, loopback, link-local, and metadata addresses. +- `sql_readonly` runs a single read-only query using a dedicated PostgreSQL role. It fails closed when that role is not configured. +- `web_search` is included only when `SEARCH_API_KEY` is set. -Adding a new LLM provider (such as Anthropic Claude, Mistral, or a local vLLM endpoint) is straightforward. Simply implement the `LLMClient` abstract interface: +Tool arguments are validated against JSON Schema derived from Python function annotations. Synchronous tools run outside the event loop; tool results and errors are returned in a structured form. -```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=...) - ... -``` +## API at a glance -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) -``` +| Method and path | Purpose | Authentication | +| --- | --- | --- | +| `GET /health` | Liveness and database/Redis connectivity status. | No | +| `GET /tools` | List registered tools and their input schemas. | `X-API-Key` | +| `POST /runs` | Execute a goal; accepts `goal` and optional `session_id`. | `X-API-Key` | +| `GET /runs/{run_id}` | Read run status, answer, and token totals. | `X-API-Key` | +| `GET /runs/{run_id}/trace` | Read ordered tool steps and their results. | `X-API-Key` | ---- - -## 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" -} -``` +All run and tool endpoints are rate limited. The service does not currently expose background runs, cancellation, streaming responses, or a run-list endpoint. See the generated OpenAPI page for request and response details. -View run traces programmatically via REST API: -```bash -curl -H "X-API-Key: YOUR_API_KEY" http://localhost:8000/runs/{run_id}/trace | jq . -``` +## Configuration -Token attribution note: when one model turn requests several tool calls, the turn's token usage is recorded on that step's *first* successfully recorded tool-call row and sibling rows report `0` on the token columns — so `sum(steps.*) <= runs.total_*` always holds and zero-token rows mean "this row does not carry the turn's usage", not "no tokens were used" (see [docs/DECISIONS.md](docs/DECISIONS.md) ADR-021). +`.env.example` lists the supported environment variables. The main settings are: ---- +| Setting | Purpose | +| --- | --- | +| `LLM_PROVIDER`, `LLM_MODEL` | Select `gemini` or `openai` and the model name. | +| `GEMINI_API_KEY`, `OPENAI_API_KEY` | Provider credentials. Set the key for the selected provider. | +| `API_KEYS` | Required comma-separated client keys for protected endpoints. | +| `POSTGRES_*`, `POSTGRES_READONLY_*` | PostgreSQL connection components and the separate read-only tool role. | +| `REDIS_URL`, `REDIS_PASSWORD` | Redis session and rate-limit storage. | +| `MAX_STEPS`, `RUN_TIMEOUT_S`, `TOOL_TIMEOUT_S` | Agent execution limits. | +| `SESSION_TTL_S`, `SESSION_MAX_MESSAGES` | Session-history expiry and size bound. | +| `RETRY_AFTER_FALLBACK_S` | Fallback wait in seconds when a provider rate-limit response has no valid retry header. | +| `SEARCH_API_KEY` | Enables the optional `web_search` tool. | +| `FILE_TOOL_BASE_DIR` | Root directory available to `read_file`. | -## Architectural Decisions (ADR Summary) +Settings can also be overridden through environment variables. In Compose, the datastore hostnames are set to the service names; `localhost` in the host `.env` file is for host-run commands and does not leak into the containers. -Key architectural trade-offs are documented in [docs/DECISIONS.md](docs/DECISIONS.md): +For production deployment, credential handling, backups, and network setup, use the [deployment guide](docs/DEPLOY.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. +## Add a tool ---- +Create a typed function and register it with a `ToolRegistry`: -## Production AWS Deployment +```python +from agentkit.tools.registry import ToolRegistry, tool -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. +registry = ToolRegistry() -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). ---- +@tool(registry=registry) +def add_numbers(left: int, right: int) -> int: + """Add two integers.""" + return left + right -## Testing & Quality Assurance +schema = registry.schemas()[0] +schema.name, schema.parameters +``` -AgentKit enforces strict code quality and comprehensive test coverage across all layers: +The decorator derives the argument schema from the function signature. The registry can then be passed to an `Agent` or injected into an application. The executor wraps tool output or a handled tool failure in a structured `ToolResult`. -```bash -# Run the complete hermetic test suite (no services required) -pytest -v +## Run checks -# Run with test coverage report (enforcing >=85% threshold) -pytest --cov=agentkit --cov-report=term-missing --cov-fail-under=85 +The default test suite is hermetic and does not need PostgreSQL, Redis, or real LLM credentials: -# Run Ruff linter and formatter check +```bash +pytest ruff check . ruff format --check . - -# Run Mypy strict type-checker -mypy agentkit tests examples +mypy agentkit tests ``` -### Two test tiers - -The default suite is hermetic: SQLite, `fakeredis` and `FakeLLMClient` stand in for -PostgreSQL, Redis and the LLM providers, so `pytest` runs in about two seconds with no -services. A second, opt-in tier runs the same components against **live** PostgreSQL and -Redis, covering behaviour the hermetic tier structurally cannot assert: - -- native `uuid` / `json` / `timestamptz` columns and asyncpg parameter binding -- real foreign-key enforcement and `ON DELETE CASCADE` (SQLite ignores FKs by default) -- Alembic migrations applied through the real PostgreSQL dialect -- genuine Redis TTL expiry and the hiredis codec -- the Lua-backed atomic rate limiter under concurrency +Tests under `tests/real/` are opt-in. They use real PostgreSQL and Redis and can clear run/step rows and test-session keys, so use a dedicated test database: ```bash -# Start the services the tier needs docker compose up -d postgres redis - -# Run only the real-infrastructure suite. REDIS_PASSWORD is completed into a -# credential-less REDIS_TEST_URL, so a hardened (--requirepass) Redis authenticates. AGENTKIT_REAL_INFRA=1 pytest -m real_infra tests/real - -# Or point it at any other PostgreSQL / Redis -AGENTKIT_REAL_INFRA=1 \ - DATABASE_TEST_URL=postgresql+asyncpg://user:pass@localhost:5432/agentkit_test \ - REDIS_TEST_URL=redis://localhost:6379/15 \ - REDIS_PASSWORD=their_password \ - pytest -m real_infra tests/real ``` -Without `AGENTKIT_REAL_INFRA=1` these tests skip, so the default `pytest` invocation stays -hermetic. The suite truncates the `runs` and `steps` tables and deletes only -`session:*` / `ratelimit:*` Redis keys, so point it at a dedicated test database. - -### CI - -All pull requests trigger GitHub Actions with three jobs: `Lint & Type Check`; a hermetic -`Test Hermetic` matrix across Python 3.11 and 3.12 with coverage gating; and -`Test Against Live PostgreSQL and Redis`, which runs the `real_infra` tier against real -PostgreSQL 16 and Redis 7 service containers. - -### Live Infrastructure Verification Report - -All core agent capabilities, multi-step PostgreSQL queries, AST calculators, security defenses (SQL injection, path traversal), and rate limiters have been validated end-to-end against live PostgreSQL, Redis, and Google Gemini API in Docker Compose. See the full audit telemetry and verbatim command logs in [docs/E2E_REPORT.md](docs/E2E_REPORT.md). - ---- - -## 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). - ---- +For design details, see [Architecture](docs/ARCHITECTURE.md), [Decisions](docs/DECISIONS.md), [Specification](docs/SPEC.md), and [Deployment](docs/DEPLOY.md). ## License -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. +AgentKit is licensed under the MIT License. See [LICENSE](LICENSE). diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index e24c9ef..c0ff7c8 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -81,6 +81,7 @@ This document tracks execution progress across all backlog tasks, including pull | ROADMAP-03 | ROADMAP | read_file Read-After-Stat Race | `fix/roadmap-02-03-04-tools-hardening` | #120 | 1 | Done | Byte cap enforced on a bounded `read(max_bytes + 1)` in one open; closes #95 | | ROADMAP-04 | ROADMAP | Calculator Non-Finite Result Guard | `fix/roadmap-02-03-04-tools-hardening` | #120 | 1 | Done | `math.isfinite` result check, inf literals rejected, pow pair guard named; closes #96 | | GH-92/111/113 | OPS | Operational Error Reporting | `fix/error-reporting-issues` | #123 | 6 | In Review | Invalid Postgres ports, sanitized agent failures and logged trace writes, settings-based OpenAI fallback, structured Gemini classification; addresses #92, #111 and item 5 of #113 | +| DOC-README | DOC | README Repository Guide | `docs/readme-overview` | #124 | 2 | In Review | Reorganized the README around the run flow, setup, first API request, source layout, API endpoints, configuration, and test tiers. | --- @@ -522,3 +523,9 @@ This document tracks execution progress across all backlog tasks, including pull - **PR**: https://github.com/getdownandcode/AgentKit/pull/123 - **Commits**: 6 (three issue-specific fixes, initial progress bookkeeping, review fix, and this commit correcting the count) - **Notes**: **#92** — `audit_credentials()` now catches the `ValueError` raised by component-mode Postgres URL resolution for a malformed `POSTGRES_PORT`, reports one stable `POSTGRES_PORT is not a valid integer.` problem, and continues the audit without a traceback. **#111** — duplicate-tool failure reasons keep the tool name and loop category without echoing arguments; execution logs no longer include raw arguments; trace-sink errors are logged at `WARNING` with `run_id`/`step_no` while the run continues; OpenAI credentials come only from `Settings`, and rate-limit handling honors the `retry-after-ms` and `retry-after` response headers (numeric seconds or HTTP-date) before using the configured `RETRY_AFTER_FALLBACK_S` (default 60). A Codex review follow-up added regression coverage for header precedence, milliseconds conversion, malformed headers, fallback and HTTP-date parsing. **#113 item 5** — Gemini error classification inspects structured API status/reason fields and selects `code` only when non-null before falling back to `status_code`. Regression tests also cover malformed port input, sensitive failure reasons, trace logging, configured retry fallback, and structured Gemini errors. Verified: full `pytest` suite passes (real-infrastructure tier skipped because disabled), `ruff check .`, `ruff format --check .`, and `mypy agentkit` pass. The other six independent #113 findings remain outside this PR. + +### PR #124: README Repository Guide +- **Status**: In Review +- **PR**: https://github.com/getdownandcode/AgentKit/pull/124 +- **Commits**: 2 (README rewrite plus this progress update) +- **Notes**: Replaced the long feature-and-roadmap-oriented README with a reader-oriented guide: what a run does, Compose setup and required secrets, a first authenticated request, offline demo, source-directory map, built-in tools, actual API endpoints, settings, tests, and links to deeper docs. Removed stale examples that did not match current APIs and provider interfaces. Reviewed commands and endpoint descriptions against the current application and Compose configuration; `git diff --check` passed.