Files
tatlock/AGENTS.md
T
jpmschweitzerandClaude 62edb111bd Clean up documentation to reflect current implementation
Remove confusing references to unimplemented features and clarify
what's currently working vs prepared for future integration.

README.md Changes:
- Update title to reflect mock API (not "with Ollama Backend")
- Remove architecture diagram showing Ollama/PydanticAI integration
- Clarify current status section (mock API, integration prepared)
- Fix uvicorn command: main:app → src.main:app
- Update model examples: llama2 → mistral-nemo:latest
- Mark Ollama requirements as future (not currently needed)
- Update environment variables (Ollama config commented out)
- Clarify API endpoints return mock responses
- Update CVE check date: 2025-12-05 → 2025-12-06
- Fix testing section to use requirements-dev.txt
- Remove Ollama troubleshooting (not connected yet)
- Mark production Ollama considerations as future
- Remove redundant changelog section (use CHANGELOG.md)

AGENTS.md Changes:
- Clarify project overview (mock API, not integrated)
- Add status indicators to components section
- Mark PydanticAI section as "for future implementation"
- Mark Ollama section as "ready for future integration"
- Add target model: mistral-nemo:latest
- Update OpenAI compatibility section with implemented status
- Fix Pydantic version: 2.10+ → 2.11+ (matches requirements)
- Add implementation status to development guidelines
- Mark common patterns as implemented vs future reference
- Update CVE check date: 2025-12-05 → 2025-12-06

CHANGELOG.md Changes:
- Clarify PydanticAI line: "for LLM integration" →
  "dependency (ready for future integration)"

Key Improvements:
- Clear distinction between implemented vs prepared features
- No misleading references to Ollama/PydanticAI integration
- Accurate model names (mistral-nemo:latest)
- Correct command examples (src.main:app)
- Proper date stamps (2025-12-06)
- Removed confusing troubleshooting for unconnected services

Status: Documentation now accurately reflects v0.1.0 mock API

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 11:07:19 +01:00

12 KiB

LLM Agent Instructions

This document contains instructions and documentation references for AI assistants working with this codebase.

Project Overview

This project implements an OpenAI-compatible API endpoint using FastAPI, with streaming support. Currently returns mock responses - infrastructure prepared for future Ollama/PydanticAI integration.

Current State: Production-ready mock API with OpenAI-compatible format Future Integration: Ollama and PydanticAI (client code ready, not connected)

Components

  • FastAPI: Web framework for the API layer
  • SSE-Starlette: Server-Sent Events for streaming responses
  • Pydantic: Request/response validation
  • PydanticAI: Dependency installed, ready for future LLM integration
  • Ollama: Async client implemented, ready for future connection

Documentation References

Core Framework Documentation

FastAPI

Uvicorn

  • Official Documentation: https://www.uvicorn.org/
  • Version: 0.38.0 (Oct 2025)
  • Key Topics:
    • ASGI server configuration
    • Deployment settings
    • Logging and monitoring
    • SSL/TLS configuration

AI/LLM Integration

PydanticAI

Pydantic

  • Official Documentation: https://docs.pydantic.dev/latest/
  • Version: 2.11+ (Required for PydanticAI, currently using >=2.11,<2.13)
  • Key Topics:
    • Data validation and serialization
    • Field types and validators
    • Model configuration
    • JSON schema generation

HTTP and Streaming

HTTPX

  • Official Documentation: https://www.python-httpx.org/
  • Version: 0.28.1
  • Key Topics:
    • Async HTTP client for Ollama communication
    • Streaming responses
    • Timeout configuration
    • Connection pooling

SSE-Starlette

Ollama Integration

Ollama API

  • Official Documentation: https://github.com/ollama/ollama/blob/main/docs/api.md
  • Status: Async client implemented in src/ollama/client.py, ready for future integration
  • Key Topics (for future implementation):
    • REST API endpoints
    • Streaming responses
    • Model management
    • Generate and chat endpoints
    • Model configuration
  • Current Model Target: mistral-nemo:latest

OpenAI API Compatibility

OpenAI API Reference

  • Official Documentation: https://platform.openai.com/docs/api-reference
  • Implemented Endpoints:
    • /v1/chat/completions - Chat completion with streaming (mock responses)
    • /v1/models - List available models (mock listing)
  • Future Endpoints:
    • 🚧 /v1/completions - Text completion (legacy)
    • 🚧 /v1/embeddings - Text embeddings
  • Implemented Features:
    • Streaming with Server-Sent Events
    • Message format compatibility
    • Response structure compatibility
    • OpenAI error format
    • Request validation with Pydantic

FastAPI Best Practices

This project follows best practices from github.com/zhanymkanov/fastapi-best-practices

Project Structure

Domain-Based Organization: Code is organized by domain/feature rather than by file type:

src/
├── chat/                  # Chat completions domain
│   ├── router.py          # FastAPI routes
│   ├── schemas.py         # Pydantic request/response models
│   ├── service.py         # Business logic
│   ├── dependencies.py    # Domain-specific dependencies
│   ├── constants.py       # Domain constants
│   └── __init__.py
├── models/                # Models listing domain
│   ├── router.py
│   ├── schemas.py
│   ├── service.py
│   └── __init__.py
├── core/                  # Shared utilities
│   ├── config.py          # Global configuration
│   ├── models.py          # Custom base Pydantic models
│   ├── exceptions.py      # Global exceptions
│   ├── dependencies.py    # Shared dependencies
│   └── router.py          # Core routes (health, root)
├── ollama/                # Ollama client layer
│   ├── client.py          # Async Ollama HTTP client
│   ├── schemas.py         # Ollama API models
│   └── __init__.py
└── main.py                # Application factory & configuration

Key Principles:

  • Each domain has its own router, schemas, models, service, etc.
  • Cross-domain imports use explicit naming: from src.auth import constants as auth_constants
  • Main.py focuses on configuration, middleware, and exception handlers
  • Business logic stays in service modules
  • Routes delegate to services for all business logic

Async/Await Best Practices

Critical Understanding: FastAPI handles sync and async routes differently:

  • Async routes (async def): Called directly in event loop

    • Use ONLY for non-blocking operations
    • Perfect for await httpx.get(), database queries, file I/O
    • NEVER use blocking calls like time.sleep() - this blocks entire server
  • Sync routes (def): Run in thread pool

    • Use for CPU-intensive work or blocking SDKs
    • Blocking I/O won't freeze the event loop
    • Example: time.sleep(10) is safe here

Example:

@router.get("/terrible")
async def terrible():
    time.sleep(10)  # ❌ BLOCKS ENTIRE SERVER

@router.get("/good")
def good():
    time.sleep(10)  # ✅ Runs in thread pool

@router.get("/perfect")
async def perfect():
    await asyncio.sleep(10)  # ✅ Non-blocking async

For CPU-intensive tasks: Use separate worker processes (not threads) due to Python's GIL.

Pydantic Configuration

Custom Base Model: All schemas inherit from CustomBaseModel for consistent behavior:

# src/core/models.py
class CustomBaseModel(BaseModel):
    model_config = ConfigDict(
        json_encoders={datetime: datetime_to_iso_str},
        populate_by_name=True,
        use_enum_values=True,
        validate_assignment=True,
    )

    def serializable_dict(self, **kwargs):
        """Return dict with only JSON-serializable fields."""
        return jsonable_encoder(self.model_dump(**kwargs))

Benefits:

  • Consistent datetime serialization across all responses
  • Alias support for field name flexibility
  • Easy JSON encoding for logging/debugging

Decoupled Settings: Split configuration by domain instead of one monolithic file:

# src/core/config.py - Global settings
class Config(BaseSettings):
    DATABASE_URL: PostgresDsn
    ENVIRONMENT: Environment

# src/chat/config.py - Chat-specific settings
class ChatConfig(BaseSettings):
    MAX_TOKENS: int
    DEFAULT_TEMPERATURE: float

Dependency Injection Patterns

Validation with Dependencies: Use dependencies for complex validations:

async def valid_post_id(post_id: UUID4) -> dict:
    """Validate post exists in database."""
    post = await service.get_by_id(post_id)
    if not post:
        raise PostNotFound()
    return post

@router.get("/posts/{post_id}")
async def get_post(post: dict = Depends(valid_post_id)):
    return post  # Already validated!

Chaining Dependencies: Build reusable validation layers:

async def valid_owned_post(
    post: dict = Depends(valid_post_id),
    token_data: dict = Depends(parse_jwt_data),
) -> dict:
    if post["creator_id"] != token_data["user_id"]:
        raise UserNotOwner()
    return post

Dependency Caching: Dependencies are cached within request scope - FastAPI only executes each dependency once per request, even if used multiple times.

Application Factory Pattern

Main.py uses factory pattern for testability and configuration:

def create_application() -> FastAPI:
    """Create and configure FastAPI app."""
    app = FastAPI(title=config.APP_NAME)

    # Add middleware
    app.add_middleware(CORSMiddleware, ...)

    # Register exception handlers
    register_exception_handlers(app)

    # Include routers
    app.include_router(chat_router, prefix="/v1")

    return app

app = create_application()

Development Guidelines

Code Structure (Current Implementation)

  • Use async/await for ALL I/O operations (database, HTTP, file access)
  • Use sync (def) for blocking SDKs or CPU-intensive work
  • Implement proper error handling and logging
  • Follow dependency injection for validation and shared resources
  • Use Pydantic models for ALL request/response validation
  • Keep business logic in service modules, not routers
  • Domain-based project structure (not file-type based)

Security Considerations

  • Validate all inputs using Pydantic models
  • Use environment variables for sensitive configuration
  • Keep dependencies updated (all CVE-checked as of 2025-12-06)
  • Minor version locking for supply chain protection
  • 🚧 Implement rate limiting for API endpoints (future)
  • 🚧 Add authentication/API keys (future)

Testing (Current Coverage: 62%)

  • Integration tests for API endpoints
  • Streaming functionality with 20s timeout protection
  • Async test support with pytest-asyncio
  • Validate OpenAI API compatibility
  • Mock responses for all endpoints
  • 🚧 Future: Mock Ollama responses when integrated

Configuration

  • Use .env files for local development
  • Document all environment variables in README
  • Provide sensible defaults where possible
  • BaseSettings from pydantic-settings
  • 🚧 Support container-based configuration (future)

Common Patterns

Streaming Response Pattern ( Implemented)

See src/chat/router.py for the current implementation:

from sse_starlette.sse import EventSourceResponse
from fastapi import FastAPI

async def event_generator():
    # Currently yields mock lorem ipsum chunks
    # Future: Stream from Ollama/PydanticAI
    yield {"data": chunk.model_dump_json()}
    yield {"data": "[DONE]"}

@app.post("/stream")
async def stream():
    return EventSourceResponse(event_generator())

PydanticAI Agent Pattern (🚧 Future Reference)

For future integration when connecting to Ollama:

from pydantic_ai import Agent

agent = Agent(
    'ollama:mistral-nemo',  # Target model
    # Configuration here
)

# Use the agent
result = await agent.run('Your prompt')

OpenAI-Compatible Response Format ( Implemented)

Current implementation in src/chat/schemas.py:

{
    "id": "chatcmpl-123",
    "object": "chat.completion.chunk",
    "created": 1234567890,
    "model": "mistral-nemo:latest",
    "choices": [{
        "index": 0,
        "delta": {"content": "response"},
        "finish_reason": None
    }]
}

Update Policy

This document should be updated when:

  • Package versions are upgraded
  • New major features are added
  • Breaking API changes occur
  • Security vulnerabilities are discovered

Last updated: 2025-12-06