|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to AI coding assistants when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Banks is a Python prompt programming language and templating system for LLM applications. It provides a Jinja2-based template engine with specialized extensions and filters for creating dynamic prompts, managing chat messages, handling multimodal content (images/audio/video/documents), and integrating with various LLM providers through LiteLLM. |
| 8 | + |
| 9 | +## Quick Reference |
| 10 | + |
| 11 | +```bash |
| 12 | +# Most common commands |
| 13 | +hatch run test # Run unit tests |
| 14 | +hatch run lint:all # Run all linting checks |
| 15 | +hatch run lint:fmt # Auto-format code |
| 16 | +hatch run test tests/test_foo.py # Run specific test file |
| 17 | +``` |
| 18 | + |
| 19 | +## Development Commands |
| 20 | + |
| 21 | +### Testing |
| 22 | +- Run tests: `hatch run test` |
| 23 | +- Run tests with coverage: `hatch run test-cov` |
| 24 | +- Generate coverage report: `hatch run cov` |
| 25 | +- Run specific test file: `hatch run test tests/test_foo.py` |
| 26 | +- Run e2e tests: `hatch run test tests/e2e/` (requires API keys) |
| 27 | + |
| 28 | +### Linting and Type Checking |
| 29 | +- Format code: `hatch run lint:fmt` |
| 30 | +- Auto-fix lint issues: `hatch run lint:fix` |
| 31 | +- Check formatting: `hatch run lint:check` |
| 32 | +- Run type checking: `hatch run lint:typing` |
| 33 | +- Run pylint: `hatch run lint:lint` |
| 34 | +- Run all lint checks: `hatch run lint:all` |
| 35 | + |
| 36 | +### Documentation |
| 37 | +- Build docs: `hatch run docs build` |
| 38 | +- Serve docs locally: `hatch run docs serve` (available at http://127.0.0.1:8000/) |
| 39 | + |
| 40 | +### Environment Management |
| 41 | +- All commands use Hatch environments with automatic dependency management |
| 42 | +- Uses `uv` as the installer for faster dependency resolution |
| 43 | +- Python 3.9+ supported (tested on 3.10-3.14) |
| 44 | + |
| 45 | +## Architecture Overview |
| 46 | + |
| 47 | +### Core Components |
| 48 | + |
| 49 | +**Prompt Classes** (`src/banks/prompt.py`): |
| 50 | +- `BasePrompt`: Base class with template rendering, metadata, versioning, and caching |
| 51 | +- `Prompt`: Synchronous prompt rendering with `text()` and `chat_messages()` methods |
| 52 | +- `AsyncPrompt`: Asynchronous version (requires `BANKS_ASYNC_ENABLED=true`) |
| 53 | +- `PromptRegistry`: Protocol interface for prompt storage backends |
| 54 | + |
| 55 | +**Type System** (`src/banks/types.py`): |
| 56 | +- `ChatMessage`: Core chat message structure with role and content |
| 57 | +- `ContentBlock`: Handles different content types (text, image_url, audio, video, document) with optional cache control |
| 58 | +- `Tool`: Function calling support with automatic schema generation from Python callables |
| 59 | +- `CacheControl`: Anthropic-style prompt caching metadata |
| 60 | + |
| 61 | +**Template Environment** (`src/banks/env.py`): |
| 62 | +- Global Jinja2 environment with Banks-specific extensions and filters |
| 63 | +- Async support detection and configuration |
| 64 | +- Custom template loader integration |
| 65 | + |
| 66 | +**Error Types** (`src/banks/errors.py`): |
| 67 | +- `MissingDependencyError`: Optional dependencies not installed |
| 68 | +- `AsyncError`: Asyncio support misconfiguration |
| 69 | +- `CanaryWordError`: Canary word leaked (prompt injection detection) |
| 70 | +- `PromptNotFoundError`: Prompt not found in registry |
| 71 | +- `InvalidPromptError`: Invalid prompt format |
| 72 | +- `LLMError`: LLM provider errors |
| 73 | + |
| 74 | +### Extensions System |
| 75 | + |
| 76 | +**Chat Extension** (`src/banks/extensions/chat.py`): |
| 77 | +- `{% chat role="..." %}...{% endchat %}` blocks for structured message creation |
| 78 | +- Automatic conversion to `ChatMessage` objects during rendering |
| 79 | + |
| 80 | +**Completion Extension** (`src/banks/extensions/completion.py`): |
| 81 | +- `{% completion model="..." %}...{% endcompletion %}` for in-prompt LLM calls |
| 82 | +- Integrated with LiteLLM for multi-provider support |
| 83 | +- Function calling support within completion blocks |
| 84 | + |
| 85 | +### Filters System |
| 86 | + |
| 87 | +**Core Filters** (`src/banks/filters/`): |
| 88 | +- `image`: Convert file paths/URLs/bytes to base64-encoded image content blocks |
| 89 | +- `audio`: Convert audio files to base64-encoded audio content blocks |
| 90 | +- `video`: Convert video files to base64-encoded video content blocks |
| 91 | +- `document`: Convert documents (PDF, TXT, HTML, CSS, XML, CSV, RTF, JS, JSON) to base64-encoded content blocks |
| 92 | +- `cache_control`: Add Anthropic cache control metadata to content blocks |
| 93 | +- `tool`: Convert Python callables to LLM function call schemas |
| 94 | +- `lemmatize`: Text lemmatization using simplemma |
| 95 | + |
| 96 | +**Filter Pattern**: Filters wrap content in `<content_block>` tags and are only useful within `{% chat %}` blocks. |
| 97 | + |
| 98 | +### Registry System |
| 99 | + |
| 100 | +**Storage Backends** (`src/banks/registries/`): |
| 101 | +- `DirectoryTemplateRegistry`: File system-based prompt storage |
| 102 | +- `FileTemplateRegistry`: Single file-based storage |
| 103 | +- `RedisTemplateRegistry`: Redis-backed storage for distributed scenarios |
| 104 | +- All registries implement the `PromptRegistry` protocol |
| 105 | + |
| 106 | +### Caching System |
| 107 | + |
| 108 | +**Render Cache** (`src/banks/cache.py`): |
| 109 | +- `RenderCache`: Protocol interface for caching rendered prompts |
| 110 | +- `DefaultCache`: In-memory cache using pickle-serialized context as key |
| 111 | +- Prevents re-rendering identical template + context combinations |
| 112 | + |
| 113 | +### Configuration |
| 114 | + |
| 115 | +**Config System** (`src/banks/config.py`): |
| 116 | +- Environment variable-based configuration with `BANKS_` prefix |
| 117 | +- `BANKS_ASYNC_ENABLED`: Enable async template rendering (must be set before import) |
| 118 | +- `BANKS_USER_DATA_PATH`: Custom user data directory |
| 119 | + |
| 120 | +## Key Development Patterns |
| 121 | + |
| 122 | +### Template Rendering Flow |
| 123 | +1. Templates parsed by Jinja2 environment with Banks extensions |
| 124 | +2. Chat blocks converted to JSON during rendering |
| 125 | +3. `chat_messages()` parses JSON back to `ChatMessage` objects |
| 126 | +4. Caching layer prevents re-rendering identical contexts |
| 127 | + |
| 128 | +### Multimodal Content Handling |
| 129 | +- Images/audio/video/documents converted to base64 during filter application |
| 130 | +- Filters accept file paths, URLs, or raw bytes |
| 131 | +- Content blocks maintain type safety and metadata |
| 132 | +- Cache control integrated at content block level |
| 133 | + |
| 134 | +### Function Calling Integration |
| 135 | +- Python functions automatically converted to LLM schemas via introspection |
| 136 | +- Docstring parsing for parameter descriptions |
| 137 | +- Type annotations converted to JSON Schema |
| 138 | + |
| 139 | +### Async Support Architecture |
| 140 | +- Global environment state requires async decision at import time |
| 141 | +- `BANKS_ASYNC_ENABLED` must be set before importing banks modules |
| 142 | +- `AsyncPrompt` provides `await`-able rendering methods |
| 143 | + |
| 144 | +## Testing |
| 145 | + |
| 146 | +### Test Markers |
| 147 | +- `@pytest.mark.e2e`: End-to-end tests requiring external services |
| 148 | +- `@pytest.mark.redis`: Tests requiring a running Redis instance |
| 149 | + |
| 150 | +### Required Environment Variables for E2E Tests |
| 151 | +- `OPENAI_API_KEY`: For OpenAI-based tests |
| 152 | +- `ANTHROPIC_API_KEY`: For Anthropic-based tests |
| 153 | + |
| 154 | +### Test Data |
| 155 | +- Test fixtures in `tests/data/` (images, audio, video, PDFs) |
| 156 | +- Template examples in `tests/templates/` |
| 157 | + |
| 158 | +### Running Specific Tests |
| 159 | +```bash |
| 160 | +hatch run test tests/test_image.py # Single file |
| 161 | +hatch run test tests/test_image.py::test_name # Single test |
| 162 | +hatch run test -k "image" # Tests matching pattern |
| 163 | +``` |
| 164 | + |
| 165 | +## Code Style |
| 166 | + |
| 167 | +### Formatting |
| 168 | +- Line length: 120 characters |
| 169 | +- Use ruff for formatting and linting |
| 170 | +- Imports sorted with `banks` as first-party |
| 171 | + |
| 172 | +### Type Hints |
| 173 | +- All public functions should have type annotations |
| 174 | +- Use `from __future__ import annotations` for forward references |
| 175 | +- MyPy strict mode enforced |
| 176 | + |
| 177 | +### Conventions |
| 178 | +- SPDX license headers in all source files |
| 179 | +- Docstrings for public APIs |
| 180 | +- Relative imports banned (use absolute `from banks.x import y`) |
| 181 | + |
| 182 | +## Public API |
| 183 | + |
| 184 | +The main exports from `banks` package: |
| 185 | +```python |
| 186 | +from banks import Prompt, AsyncPrompt, ChatMessage, config, env |
| 187 | +``` |
| 188 | + |
| 189 | +## Dependencies |
| 190 | + |
| 191 | +**Core (required)**: |
| 192 | +- `jinja2`: Core templating engine |
| 193 | +- `pydantic`: Type validation and serialization |
| 194 | +- `griffe`: Code introspection utilities |
| 195 | +- `platformdirs`: Cross-platform data directory handling |
| 196 | +- `filetype`: File type detection for multimodal content |
| 197 | +- `deprecated`: Deprecation decorators |
| 198 | + |
| 199 | +**Optional**: |
| 200 | +- `litellm`: Multi-provider LLM integration (`banks[all]`) |
| 201 | +- `redis`: Redis registry backend (`banks[all]`) |
| 202 | +- `simplemma`: Lemmatization filter (dev dependency) |
| 203 | + |
| 204 | +## CI/CD |
| 205 | + |
| 206 | +- **test.yml**: Runs tests on Python 3.10-3.14 |
| 207 | +- **docs.yml**: Builds and deploys documentation |
| 208 | +- **release.yml**: Handles package releases |
| 209 | + |
| 210 | +## PR Guidelines |
| 211 | + |
| 212 | +Follow conventional commit prefixes for PR titles: |
| 213 | +- `fix:` - Bug fixes |
| 214 | +- `feat:` - New features |
| 215 | +- `chore:` - Maintenance |
| 216 | +- `docs:` - Documentation |
| 217 | +- `refactor:` - Code refactoring |
| 218 | +- `test:` - Test additions/changes |
0 commit comments