Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## 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

### Code Quality
- `source .venv/bin/activate && make format` - Format code with Ruff (line length 100)
- `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.

### Core Concepts

**State Management**: Uses haiway's immutable State objects and ctx for dependency injection. All configuration and context flows through state scoping.

**Provider Abstraction**: Unified `LMM` interface across providers (OpenAI, Anthropic, Gemini, Mistral, Ollama, Bedrock). Each provider implements standardized `LMMContext`, `LMMInput`, `LMMCompletion` types.

**Multimodal Content**: `MultimodalContent` handles text, images, and media uniformly. Content elements are composable and convertible across formats.

### Key Components

**Stages**: Core processing pipeline units that transform `(LMMContext, MultimodalContent)`. Support composition, looping, caching, retry. Examples: `Stage.completion()`, `Stage.sequence()`, `Stage.loop()`.

**Tools**: Function calling via `@tool` decorator. `Toolbox` manages collections. Automatic schema generation and validation.

**Agents**: Stateful conversation entities with memory. `AgentWorkflow` for multi-agent systems.

**Generation APIs**: High-level interfaces like `TextGeneration`, `ModelGeneration` that handle complexity while allowing customization.

### Component Flow
```
Generation APIs → Stages → LMM → Provider Implementation
```

### Patterns

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

### Entry Points

- Simple: `TextGeneration.generate()`, `ModelGeneration.generate()`
- Tools: `@tool` decorator with `tools` parameter
- Complex: `Stage` composition and `Agent` systems
- Setup: Context managers with provider configs

### Testing

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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "hatchling.build"
[project]
name = "draive"
description = "Framework designed to simplify and accelerate the development of LLM-based applications."
version = "0.66.1"
version = "0.66.2"
readme = "README.md"
maintainers = [
{ name = "Kacper Kaliński", email = "kacper.kalinski@miquido.com" },
Expand Down
2 changes: 2 additions & 0 deletions src/draive/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@
Stage,
StageCondition,
StageException,
StageState,
stage,
)
from draive.tokenization import Tokenization
Expand Down Expand Up @@ -333,6 +334,7 @@
"Stage",
"StageCondition",
"StageException",
"StageState",
"State",
"TextContent",
"TextEmbedding",
Expand Down
42 changes: 42 additions & 0 deletions src/draive/commons/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,48 @@ def to_mapping(
) -> Mapping[str, Any]:
return self._values

@property
def kind(self) -> str | None:
match self._values.get("kind"):
case str() as kind:
return kind

case _:
return None

def with_kind(
self,
kind: str,
/,
) -> Self:
return self.__class__(
{
**self._values,
"kind": kind,
}
)

@property
def name(self) -> str | None:
match self._values.get("name"):
case str() as name:
return name

case _:
return None

def with_name(
self,
name: str,
/,
) -> Self:
return self.__class__(
{
**self._values,
"name": name,
}
)

@property
def description(self) -> str | None:
match self._values.get("description"):
Expand Down
2 changes: 1 addition & 1 deletion src/draive/prompts/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def __init__(
"_check_availability",
availability_check
or (
lambda: True # available by default
lambda meta: True # available by default
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix the protocol inconsistency causing a runtime error.

The default lambda now expects a meta parameter, but the PromptAvailabilityCheck protocol (lines 18-19) still defines functions as taking no parameters, and the available property (line 69) calls _check_availability() with no arguments. This will cause a TypeError at runtime.

To fix this inconsistency, you need to update both the protocol definition and the function call:

 class PromptAvailabilityCheck(Protocol):
-    def __call__(self) -> bool: ...
+    def __call__(self, meta: Meta) -> bool: ...

And update the available property to pass the metadata:

 @property
 def available(self) -> bool:
     try:
-        return self._check_availability()
+        return self._check_availability(self.declaration.meta)
 
     except Exception:
         return False
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
lambda meta: True # available by default
class PromptAvailabilityCheck(Protocol):
- def __call__(self) -> bool: ...
+ def __call__(self, meta: Meta) -> bool: ...
@property
def available(self) -> bool:
try:
- return self._check_availability()
+ return self._check_availability(self.declaration.meta)
except Exception:
return False
🤖 Prompt for AI Agents
In src/draive/prompts/template.py around line 62, the default lambda function
expects a 'meta' parameter, but the PromptAvailabilityCheck protocol (lines
18-19) defines functions with no parameters, and the 'available' property (line
69) calls _check_availability() without arguments, causing a runtime TypeError.
To fix this, update the PromptAvailabilityCheck protocol to define the function
as accepting a 'meta' parameter, and modify the 'available' property to call
_check_availability() with the appropriate metadata argument.

),
)

Expand Down
4 changes: 4 additions & 0 deletions src/draive/stages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
StageExecution,
StageMerging,
StageResultTransforming,
StageRouting,
StageState,
StageStateAccessing,
)

Expand All @@ -17,6 +19,8 @@
"StageExecution",
"StageMerging",
"StageResultTransforming",
"StageRouting",
"StageState",
"StageStateAccessing",
"stage",
)
Loading