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
507 changes: 495 additions & 12 deletions .github/workflows/ci.yaml

Large diffs are not rendered by default.

218 changes: 86 additions & 132 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,155 +1,109 @@
# CLAUDE.md - LLM Guidance for Graphite Repository
# CLAUDE.md

## Repository Overview
This is **Graphite** (published as `grafi` on PyPI) - an event-driven framework for building AI agents using modular, composable workflows. The framework emphasizes observability, idempotency, auditability, and restorability for enterprise-grade AI applications.
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

Graphite (PyPI: `grafi`) is an event-driven framework for building AI agents using modular, composable workflows. The framework emphasizes observability, idempotency, auditability, and restorability for enterprise-grade AI applications.

## Development Commands

### Setup
```bash
# Install dependencies
poetry install

# Install with development dependencies
poetry install --with dev
```

### Code Quality
```bash
# Run linting
# Run linting and formatting
ruff check .
ruff format .

# Run type checking
mypy .

# Run formatting
ruff format .

# Run tests
# Run all tests
pytest

# Run a single test file
pytest tests/path/to/test_file.py

# Run a specific test
pytest tests/path/to/test_file.py::test_function_name

# Run tests with coverage
pytest --cov=grafi
```

### Pre-commit
```bash
# Install pre-commit hooks
# Pre-commit hooks
pre-commit install

# Run pre-commit on all files
pre-commit run --all-files
```

## Architecture Overview

### Core Components
- **Assistants**: High-level orchestration layer managing AI agent workflows
- **Nodes**: Discrete workflow components with event subscriptions
- **Tools**: Functions that transform input data to output
- **Workflow**: Pub/sub orchestration with in-memory queuing

### Key Patterns
- **Event-driven Architecture**: All components communicate through events
- **Event Sourcing**: Events stored in durable event store as single source of truth
- **Command Pattern**: Clear separation between request initiators and executors
- **Pub/Sub**: Lightweight FIFO message queuing for component interactions

## Important File Locations

### Core Framework
- `grafi/` - Main framework code
- `grafi/agents/` - Built-in agents (ReAct, etc.)
- `grafi/events/` - Event sourcing implementation
- `grafi/workflows/` - Workflow orchestration
- `grafi/tools/` - Built-in tools and utilities
- `grafi/nodes/` - workflow components with event subscriptions and publishing

### Tests
- `tests/` - Unit tests
- `tests_integration/` - Integration tests
- `tests_integration/react_assistant/` - ReAct agent examples

### Documentation
- `docs/` - Documentation source
- `README.md` - Main documentation
- `pyproject.toml` - Project configuration

## Development Guidelines

### Code Style
- Follow PEP 8 with 88 character line limit
- Use type hints for all functions
## Architecture

The framework has three conceptual layers coordinated through pub/sub workflow orchestration:

### Layer Hierarchy

1. **Assistants** (`grafi/assistants/`) - Top-level orchestration managing complete request lifecycles. Assistants own a Workflow and delegate execution to it.

2. **Workflows** (`grafi/workflows/`) - Orchestrate interactions among Nodes using pub/sub with in-memory FIFO message queuing. `EventDrivenWorkflow` is the primary implementation.

3. **Nodes** (`grafi/nodes/`) - Discrete workflow components that subscribe to Topics, execute Tools, and publish results. A Node wraps a Tool and handles event subscriptions/publishing.

4. **Tools** (`grafi/tools/`) - Core execution units that transform input to output. Categories:
- `llms/` - LLM integrations (OpenAI, Claude, Gemini, Ollama, DeepSeek, OpenRouter)
- `function_calls/` - External API tools (Tavily, DuckDuckGo, Google Search, MCP)
- `functions/` - Custom function tools

### Event System

All components communicate through events stored in durable event stores (`grafi/common/event_stores/`):
- `EventStore` - Abstract base for event persistence
- `EventStoreInMemory` - In-memory implementation
- `EventStorePostgres` - PostgreSQL implementation for production

Events flow through Topics (`grafi/topics/`):
- `InputTopic` - Entry point for workflow input
- `OutputTopic` - Terminal point with output conditions
- `Topic` - General-purpose with optional conditions

### Builder Pattern

All major components use a builder pattern for construction:
```python
Node.builder().name("MyNode").tool(my_tool).subscribe(topic).publish_to(output_topic).build()
```

### Subscription Expressions

Nodes can subscribe to multiple topics with boolean logic:
```python
SubscriptionBuilder().subscribed_to(topicA).or_().subscribed_to(topicB).build()
```

## Code Style

- Line length: 88 characters
- Use double quotes for strings
- Format with `ruff format`

### Event-Driven Patterns
- All state changes should emit events
- Use event decorators for automatic capture
- Maintain event ordering and idempotency
- Store events in durable event store

### Testing
- Write unit tests for all new functionality
- Include integration tests for workflows
- Test event sourcing and recovery scenarios
- Mock external dependencies appropriately

## Common Tasks

### Creating New Agents
1. Extend base agent classes in `grafi/assistants/`
2. implement designed workflow with node and tools
3. Define tool integrations
4. Add comprehensive tests

### Adding New Tools
1. Create tool in `grafi/tools/`
2. Every subfolder has a definition of a tool, check if tools matches to the correct category
2. Implement tool interface
3. Add event capturing decorators
4. Include usage examples

### Workflow Development
1. Define workflow nodes and connections
2. Set up pub/sub topics
3. Build Nodes that execute Tools
4. Test recovery scenarios

## Dependencies
- **Core**: pydantic, openai, loguru, jsonpickle
- **Observability**: arize-otel, openinference-instrumentation-openai
- **Dev**: pytest, ruff, mypy, pre-commit
- **Optional**: chromadb, llama-index, tavily-python, anthropic

## Best Practices

### Event Design
- Events should be immutable
- Include all necessary context
- Use consistent event schemas
- Consider event versioning

### Error Handling
- Implement proper error recovery
- Use event sourcing for state restoration
- Log errors with context
- Provide meaningful error messages

### Performance
- Use async/await patterns where appropriate
- Implement proper resource cleanup
- Consider memory usage with large event stores
- Profile critical paths

## Security Considerations
- Validate all inputs
- Sanitize event data
- Implement proper authentication
- Audit sensitive operations

## Getting Help
- Check existing tests for usage patterns
- Review integration examples
- Consult framework documentation
- Look at built-in agent implementations
- Type hints required for all functions
- Use `typing_extensions.TypedDict` instead of `typing.TypedDict`

## Key Patterns

### Creating an Agent

See `grafi/agents/react_agent.py` for the canonical example. Key steps:
1. Define Topics (input, output, intermediate)
2. Create Nodes with Tools, subscriptions, and publish targets
3. Compose Nodes into a Workflow
4. Wrap in an Assistant with `_construct_workflow()` method

### Event Recovery

Workflows can resume from interruption by replaying events from the event store. See `tests_integration/react_assistant/react_assistant_recovery_example.py` for implementation.

### InvokeContext

Tracks request lifecycles with:
- `conversation_id` - Groups multiple invokes in a conversation
- `assistant_request_id` - Tracks requests at assistant level
- `invoke_id` - Individual request identifier
- `user_id` - User identifier
2 changes: 1 addition & 1 deletion grafi/tools/function_calls/impl/mcp_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

class MCPTool(FunctionCallTool):
"""
MCPTool extends FunctionCallTool to provide web search functionality using the MCP API.
MCPTool extends FunctionCallTool to provide functionality using the MCP API.
"""

# Set up API key and MCP client
Expand Down
10 changes: 9 additions & 1 deletion grafi/tools/functions/function_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import Callable
from typing import List
from typing import Self
from typing import TypeVar
from typing import Union

import cloudpickle
Expand Down Expand Up @@ -49,6 +50,10 @@ async def invoke(
) -> MsgsAGen:
try:
response = self.function(input_data)
if inspect.isasyncgen(response):
async for item in response:
yield self.to_messages(response=item)
return
if inspect.isawaitable(response):
response = await response

Expand Down Expand Up @@ -126,7 +131,10 @@ async def from_dict(cls, data: dict[str, Any]) -> "FunctionTool":
)


class FunctionToolBuilder(ToolBuilder[FunctionTool]):
T_FT = TypeVar("T_FT", bound=FunctionTool)


class FunctionToolBuilder(ToolBuilder[T_FT]):
"""Builder for FunctionTool instances."""

def role(self, role: str) -> Self:
Expand Down
Loading
Loading