-
Notifications
You must be signed in to change notification settings - Fork 12
Update CLAUDE.md #347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update CLAUDE.md #347
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,66 +5,174 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co | |||||||||
| ## Development Commands | ||||||||||
|
|
||||||||||
| ### Setup | ||||||||||
|
|
||||||||||
| - `make venv` - Setup development environment and install git hooks | ||||||||||
| - `make sync` - Sync dependencies with uv lock file | ||||||||||
| - `make update` - Update and lock dependencies | ||||||||||
| - `source .venv/bin/activate && make sync` - Sync dependencies with uv lock file | ||||||||||
| - `source .venv/bin/activate && make update` - Update and lock dependencies | ||||||||||
|
|
||||||||||
| ### Code Quality | ||||||||||
| - `source .venv/bin/activate && make format` - Format code with Ruff (line length 100) | ||||||||||
|
|
||||||||||
| - `source .venv/bin/activate && make format` - Format code with Ruff | ||||||||||
| - `source .venv/bin/activate && make lint` - Run linters (Ruff + Bandit + Pyright strict mode) | ||||||||||
| - `source .venv/bin/activate && make test` - Run pytest with coverage | ||||||||||
| - `source .venv/bin/activate && pytest tests/test_specific.py` - Run single test file | ||||||||||
| - `source .venv/bin/activate && pytest tests/test_specific.py::test_function` - Run specific test | ||||||||||
|
|
||||||||||
| ### Package Management | ||||||||||
| - `uv add <package>` - Add dependency | ||||||||||
| - `uv remove <package>` - Remove dependency | ||||||||||
|
|
||||||||||
| ## Architecture Overview | ||||||||||
|
|
||||||||||
| **draive** is a Python framework for LLM applications built on haiway for state management. | ||||||||||
| Draive is a Python framework (3.12+) for LLM applications built on the **Haiway** framework, leveraging its state, dependency, and task-management facilities. It emphasizes: | ||||||||||
|
|
||||||||||
| 1. **Immutable State Management**: Type-safe, immutable data structures with validation | ||||||||||
| 2. **Context-based Dependency Injection**: Safe state propagation in concurrent environments | ||||||||||
| 3. **Functional Approach**: Pure functions over objects with methods | ||||||||||
| 4. **Structured Concurrency**: Automatic task management and resource cleanup | ||||||||||
| 5. **Haiway Proxy**: draive builds on top of haiway and exports its symbols | ||||||||||
|
|
||||||||||
| ### Core Components | ||||||||||
|
|
||||||||||
| - **Integrations**: Various AI service provider integrations. Including Anthropic, AWS Bedrock, Cohere, Gemini, Mistral, Ollama, OpenAI, VLLM | ||||||||||
| - **Functionalities**: High- and low-level interfaces and implementations of application building blocks, including embedding, **LMM**, evaluation, generation, conversation, guardrails, instructions, resources, prompts, tools, **MCP** support | ||||||||||
| - **Parameters**: Immutable data structures and **parameterized** functions with **JSON Schema** generation, validation, and generic-type support | ||||||||||
| - **Utils**: Application utilities, common types and interfaces | ||||||||||
| - **Helpers**: Implementations of selected functionalities combining other components | ||||||||||
|
|
||||||||||
| ### Core Concepts | ||||||||||
| ### Code Style | ||||||||||
|
|
||||||||||
| **State Management**: Uses haiway's immutable State objects and ctx for dependency injection. All configuration and context flows through state scoping. | ||||||||||
| - Use absolute imports from `draive` package | ||||||||||
| - Put exported symbols into `__init__.py` | ||||||||||
| - Follow Ruff import ordering (standard library, third party, local) | ||||||||||
| - Use Python 3.12+ type features (type unions with `|`, generic syntax) | ||||||||||
| - Use base and abstract types like `Sequence` or `Iterable` instead of concrete | ||||||||||
| - Use custom exceptions for specific errors | ||||||||||
|
|
||||||||||
| **Provider Abstraction**: Unified `LMM` interface across providers (OpenAI, Anthropic, Gemini, Mistral, Ollama, Bedrock). Each provider implements standardized `LMMContext`, `LMMInput`, `LMMCompletion` types. | ||||||||||
| ### Testing Guidelines | ||||||||||
|
|
||||||||||
| **Multimodal Content**: `MultimodalContent` handles text, images, and media uniformly. Content elements are composable and convertible across formats. | ||||||||||
| - Uses pytest with async support. Tests are in `tests/` directory. | ||||||||||
| - Mock dependencies within scope using stubbed functionality state. | ||||||||||
|
Comment on lines
+50
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Unify imperative mood in testing bullets Other bullets start with “Use”; this one starts with “Uses”. Align wording and add the article “the” for clarity. -- Uses pytest with async support. Tests are in `tests/` directory.
+- Use pytest with async support. The tests are in the `tests/` directory.📝 Committable suggestion
Suggested change
🧰 Tools🪛 LanguageTool[uncategorized] ~50-~50: You might be missing the article “the” here. (AI_EN_LECTOR_MISSING_DETERMINER_THE) 🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| ### Key Components | ||||||||||
| ## Examples | ||||||||||
|
|
||||||||||
| **Stages**: Core processing pipeline units that transform `(LMMContext, MultimodalContent)`. Support composition, looping, caching, retry. Examples: `Stage.completion()`, `Stage.sequence()`, `Stage.loop()`. | ||||||||||
| ### Immutability Rules | ||||||||||
|
|
||||||||||
| **Tools**: Function calling via `@tool` decorator. `Toolbox` manages collections. Automatic schema generation and validation. | ||||||||||
| **ALWAYS use these types for collections in State, Config and DataModel classes:** | ||||||||||
| - Use `Sequence[T]` instead of `list[T]` (becomes tuple) | ||||||||||
| - Use `Mapping[K,V]` instead of `dict[K,V]` (becomes immutable) | ||||||||||
| - Use `Set[T]` instead of `set[T]` (becomes frozenset) | ||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
|
|
||||||||||
| **Agents**: Stateful conversation entities with memory. `AgentWorkflow` for multi-agent systems. | ||||||||||
| ```python | ||||||||||
| from typing import Sequence, Mapping, Set | ||||||||||
| from haiway import State | ||||||||||
|
|
||||||||||
| **Generation APIs**: High-level interfaces like `TextGeneration`, `ModelGeneration` that handle complexity while allowing customization. | ||||||||||
| class UserData(State): | ||||||||||
| roles: Sequence[str] # Will be tuple | ||||||||||
| metadata: Mapping[str, Any] # Will be immutable | ||||||||||
| tags: Set[str] # Will be frozenset | ||||||||||
|
|
||||||||||
| ### Component Flow | ||||||||||
| ``` | ||||||||||
| Generation APIs → Stages → LMM → Provider Implementation | ||||||||||
|
|
||||||||||
| ### State Definition Patterns | ||||||||||
|
|
||||||||||
| ```python | ||||||||||
| from typing import Protocol, runtime_checkable | ||||||||||
| from uuid import UUID, uuid4 | ||||||||||
| from haiway import State | ||||||||||
| from draive import Field | ||||||||||
|
|
||||||||||
| # Basic data structure | ||||||||||
| class UserData(State): | ||||||||||
| id: UUID | ||||||||||
| name: str | ||||||||||
| email: str | None = None | ||||||||||
|
|
||||||||||
| # Generic state classes | ||||||||||
| class Container[Element](State): | ||||||||||
| items: Sequence[Element] | ||||||||||
| metadata: Mapping[str, Any] | ||||||||||
|
|
||||||||||
| # Special kind of State supporting loading from external source | ||||||||||
| class UserConfig(Config): | ||||||||||
| value: str | ||||||||||
|
|
||||||||||
| # Serializable counterpart of State | ||||||||||
| class UserModel(DataModel): | ||||||||||
| # Field allows customizing DataModel fields with various options | ||||||||||
| id: UUID = Field(default_factory=uuid4, aliased="user_id") | ||||||||||
| name: str | ||||||||||
|
|
||||||||||
| # Function protocol | ||||||||||
| @runtime_checkable | ||||||||||
| class UserFetching(Protocol): | ||||||||||
| async def __call__(self, id: str) -> UserData: ... | ||||||||||
|
|
||||||||||
| # Functionality state pattern used for dependency injection | ||||||||||
| class UserService(State): | ||||||||||
| # Function implementations | ||||||||||
| user_fetching: UserFetching | ||||||||||
|
|
||||||||||
| # Class method interface to access functions within context | ||||||||||
| @classmethod | ||||||||||
| async def fetch_user(cls, *, id: str) -> UserData: | ||||||||||
| return await ctx.state(cls).user_fetching(id) | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| ### Patterns | ||||||||||
| ### State Updates | ||||||||||
|
|
||||||||||
| 1. **Immutable State**: All state objects are frozen | ||||||||||
| 2. **Context Scoping**: Configuration flows through execution contexts | ||||||||||
| 3. **Async First**: Fully asynchronous throughout | ||||||||||
| 4. **Composability**: Small focused components combine into complex workflows | ||||||||||
| 5. **Type Safety**: Heavy use of generics and protocols | ||||||||||
| ```python | ||||||||||
| # Immutable updates through copy, same for State, Config and DataModel | ||||||||||
| user: UserData = ... | ||||||||||
| updated_user: UserData = user.updated(name="Updated") | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| ### Entry Points | ||||||||||
| ### Resource Management | ||||||||||
|
|
||||||||||
| ```python | ||||||||||
| from contextlib import asynccontextmanager | ||||||||||
| from haiway import ctx, State | ||||||||||
|
|
||||||||||
| class ResourceAccess(State): | ||||||||||
| accessing: ResourceAccessing | ||||||||||
|
|
||||||||||
| @classmethod | ||||||||||
| def access(cls) -> ResourceData: | ||||||||||
| return ctx.state(cls).accessing() | ||||||||||
|
|
||||||||||
| @asynccontextmanager | ||||||||||
| async def create_resource_disposable(): | ||||||||||
| # Create a disposable resource | ||||||||||
| resource: ResourceHandle = await open_resource() | ||||||||||
| try: | ||||||||||
| # Yield the state that will be made available in the context | ||||||||||
| yield ResourceState(accessing=resource.access) | ||||||||||
|
|
||||||||||
| finally: | ||||||||||
| # Cleanup happens automatically when context exits | ||||||||||
| await resource.close() | ||||||||||
|
|
||||||||||
| # Resources are automatically cleaned up and their state included in context | ||||||||||
| async with ctx.scope( | ||||||||||
| "work", | ||||||||||
| disposables=(create_resource_disposable(),) | ||||||||||
| ): | ||||||||||
| # ResourceAccess is now available in the context | ||||||||||
| resource_data: ResourceData = ResourceAccess.access() | ||||||||||
| # Cleanup happens automatically here | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| - Simple: `TextGeneration.generate()`, `ModelGeneration.generate()` | ||||||||||
| - Tools: `@tool` decorator with `tools` parameter | ||||||||||
| - Complex: `Stage` composition and `Agent` systems | ||||||||||
| - Setup: Context managers with provider configs | ||||||||||
| ## Testing Patterns | ||||||||||
|
|
||||||||||
| ### Testing | ||||||||||
| ```python | ||||||||||
| import pytest | ||||||||||
| from haiway import ctx | ||||||||||
|
|
||||||||||
| Uses pytest with async support. Tests are in `tests/` directory. Key test patterns: | ||||||||||
| - Mock LMM responses for unit tests | ||||||||||
| - Use actual providers for integration tests | ||||||||||
| - Test both sync and async code paths | ||||||||||
| @pytest.mark.asyncio | ||||||||||
| async def test_functionality(): | ||||||||||
| # Set up test context | ||||||||||
| async with ctx.scope("test", TestState(value="test")): | ||||||||||
| result = await some_function() | ||||||||||
| assert result == expected_result | ||||||||||
|
|
||||||||||
| @pytest.mark.asyncio | ||||||||||
| async def test_with_mock(): | ||||||||||
| async with ctx.scope("test", ServiceState(fetching=mock_fetching)): | ||||||||||
| # Test with mocked service | ||||||||||
| ``` | ||||||||||
Uh oh!
There was an error while loading. Please reload this page.