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>
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
- Official Documentation: https://fastapi.tiangolo.com/
- Version: 0.123.9 (Dec 2025)
- Key Topics:
- Path operations and routing
- Request/response models with Pydantic
- Dependency injection
- Background tasks
- WebSocket and streaming support
- PyPI: https://pypi.org/project/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
- Official Documentation: https://ai.pydantic.dev/
- Version: 1.27.0 (Dec 2025)
- Status: Dependency installed, ready for future integration
- Key Topics (for future implementation):
- Agent creation and configuration
- LLM provider integration (Ollama support)
- Structured outputs with Pydantic
- Streaming responses
- Tool/function calling
- RunContext and dynamic configuration
- MCP server integration
- GitHub: https://github.com/pydantic/pydantic-ai
- PyPI: https://pypi.org/project/pydantic-ai/
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
- GitHub: https://github.com/sysid/sse-starlette
- Version: 3.0.2 (Oct 2025)
- Key Topics:
- Server-Sent Events implementation
- Streaming event responses
- Integration with FastAPI/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
.envfiles 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