(no commit message)
This commit is contained in:
351
README.md
351
README.md
@@ -1,4 +1,4 @@
|
|||||||
# ClaudeAgent - DSPy Module for Claude Code SDK
|
# ClaudeCode - DSPy Module for Claude Code SDK
|
||||||
|
|
||||||
A DSPy module that wraps the Claude Code Python SDK with a signature-driven interface. Each agent instance maintains a stateful conversation session, making it perfect for multi-turn agentic workflows.
|
A DSPy module that wraps the Claude Code Python SDK with a signature-driven interface. Each agent instance maintains a stateful conversation session, making it perfect for multi-turn agentic workflows.
|
||||||
|
|
||||||
@@ -11,15 +11,16 @@ A DSPy module that wraps the Claude Code Python SDK with a signature-driven inte
|
|||||||
- **Multi-turn conversations** - Context preserved across calls
|
- **Multi-turn conversations** - Context preserved across calls
|
||||||
- **Output field descriptions** - Automatically enhance prompts
|
- **Output field descriptions** - Automatically enhance prompts
|
||||||
- **Async support** - Both sync and async execution modes
|
- **Async support** - Both sync and async execution modes
|
||||||
|
- **Modaic Hub Integration** - Push and pull agents from Modaic Hub
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install with uv
|
# Install with uv
|
||||||
uv add claude-agent-sdk dspy nest-asyncio
|
uv add claude-agent-sdk dspy modaic nest-asyncio
|
||||||
|
|
||||||
# Or with pip
|
# Or with pip
|
||||||
pip install claude-agent-sdk dspy nest-asyncio
|
pip install claude-agent-sdk dspy modaic nest-asyncio
|
||||||
```
|
```
|
||||||
|
|
||||||
**Prerequisites:**
|
**Prerequisites:**
|
||||||
@@ -27,19 +28,77 @@ pip install claude-agent-sdk dspy nest-asyncio
|
|||||||
- Claude Code CLI installed (get it from [code.claude.com](https://code.claude.com))
|
- Claude Code CLI installed (get it from [code.claude.com](https://code.claude.com))
|
||||||
- Anthropic API key set in `ANTHROPIC_API_KEY` environment variable
|
- Anthropic API key set in `ANTHROPIC_API_KEY` environment variable
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start with Modaic Hub (Recommended)
|
||||||
|
|
||||||
|
The fastest way to use ClaudeCode is to pull a pre-configured agent from Modaic Hub.
|
||||||
|
|
||||||
|
### 1. Set up environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy the example file
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# Edit .env with your keys
|
||||||
|
ANTHROPIC_API_KEY="<YOUR_ANTHROPIC_API_KEY>"
|
||||||
|
MODAIC_TOKEN="<YOUR_MODAIC_TOKEN>" # Optional, for pushing to hub
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Load from Modaic Hub
|
||||||
|
|
||||||
|
```python
|
||||||
|
from modaic import AutoProgram
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
class FileList(BaseModel):
|
||||||
|
files: list[str]
|
||||||
|
|
||||||
|
# Load pre-compiled agent from hub
|
||||||
|
agent = AutoProgram.from_precompiled(
|
||||||
|
"farouk1/claude-code",
|
||||||
|
config={
|
||||||
|
"signature": "message:str -> output:FileList",
|
||||||
|
"working_directory": ".",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use it!
|
||||||
|
result = agent(message="List Python files here")
|
||||||
|
print(result.output.files) # Typed access
|
||||||
|
print(result.usage) # Token usage
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Override Config Options
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Load with custom configuration
|
||||||
|
agent = AutoProgram.from_precompiled(
|
||||||
|
"farouk1/claude-code",
|
||||||
|
config={
|
||||||
|
"signature": "message:str -> answer:str",
|
||||||
|
"model": "sonnet",
|
||||||
|
"permission_mode": "acceptEdits",
|
||||||
|
"allowed_tools": ["Read", "Write", "Bash"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
For local development and creating your own agents:
|
||||||
|
|
||||||
### Basic String Output
|
### Basic String Output
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import dspy
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
from claude_agent import ClaudeAgent
|
|
||||||
|
|
||||||
# Define signature
|
# Create config
|
||||||
sig = dspy.Signature('message:str -> answer:str')
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> answer:str",
|
||||||
|
working_directory="."
|
||||||
|
)
|
||||||
|
|
||||||
# Create agent
|
# Create agent
|
||||||
agent = ClaudeAgent(sig, working_directory=".")
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
# Use it
|
# Use it
|
||||||
result = agent(message="What files are in this directory?")
|
result = agent(message="What files are in this directory?")
|
||||||
@@ -51,6 +110,7 @@ print(result.usage) # Token counts
|
|||||||
### Structured Output with Pydantic
|
### Structured Output with Pydantic
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
class BugReport(BaseModel):
|
class BugReport(BaseModel):
|
||||||
@@ -58,94 +118,92 @@ class BugReport(BaseModel):
|
|||||||
description: str
|
description: str
|
||||||
affected_files: list[str]
|
affected_files: list[str]
|
||||||
|
|
||||||
sig = dspy.Signature('message:str -> report:BugReport')
|
# Create config with Pydantic output
|
||||||
agent = ClaudeAgent(sig, working_directory=".")
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> report:BugReport",
|
||||||
|
working_directory="."
|
||||||
|
)
|
||||||
|
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
result = agent(message="Analyze the bug in error.log")
|
result = agent(message="Analyze the bug in error.log")
|
||||||
print(result.report.severity) # Typed access!
|
print(result.report.severity) # Typed access!
|
||||||
print(result.report.affected_files)
|
print(result.report.affected_files)
|
||||||
```
|
```
|
||||||
|
|
||||||
## API Reference
|
### Push to Modaic Hub
|
||||||
|
|
||||||
### ClaudeAgent
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class ClaudeAgent(dspy.Module):
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
|
|
||||||
|
# Create your agent
|
||||||
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> answer:str",
|
||||||
|
working_directory=".",
|
||||||
|
model="claude-opus-4-5-20251101",
|
||||||
|
permission_mode="acceptEdits",
|
||||||
|
)
|
||||||
|
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
|
# Test it locally
|
||||||
|
result = agent(message="Test my agent")
|
||||||
|
print(result.answer)
|
||||||
|
|
||||||
|
# Push to Modaic Hub
|
||||||
|
agent.push_to_hub("your-username/your-agent-name")
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### ClaudeCodeConfig
|
||||||
|
|
||||||
|
Configuration object for ClaudeCode agents.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ClaudeCodeConfig:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
signature: str | type[Signature],
|
signature: str | type[Signature], # Required
|
||||||
working_directory: str,
|
working_directory: str = ".", # Default: "."
|
||||||
model: Optional[str] = None,
|
model: str = "claude-opus-4-5-20251101", # Default model
|
||||||
permission_mode: Optional[str] = None,
|
permission_mode: str | None = None, # Optional
|
||||||
allowed_tools: Optional[list[str]] = None,
|
allowed_tools: list[str] | None = None, # Optional
|
||||||
disallowed_tools: Optional[list[str]] = None,
|
disallowed_tools: list[str] | None = None, # Optional
|
||||||
sandbox: Optional[dict[str, Any]] = None,
|
sandbox: dict[str, Any] | None = None, # Optional
|
||||||
system_prompt: Optional[str | dict[str, Any]] = None,
|
system_prompt: str | dict | None = None, # Optional
|
||||||
api_key: Optional[str] = None,
|
api_key: str | None = None, # Optional (uses env var)
|
||||||
**kwargs: Any,
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Parameters
|
**Parameters:**
|
||||||
|
|
||||||
**Required:**
|
- **`signature`** (required) - DSPy signature defining input/output fields (must have exactly 1 input and 1 output)
|
||||||
|
- **`working_directory`** - Directory where Claude will execute commands (default: `"."`)
|
||||||
|
- **`model`** - Claude model to use (default: `"claude-opus-4-5-20251101"`)
|
||||||
|
- **`permission_mode`** - Permission mode: `"default"`, `"acceptEdits"`, `"plan"`, `"bypassPermissions"`
|
||||||
|
- **`allowed_tools`** - List of allowed tool names (e.g., `["Read", "Write", "Bash"]`)
|
||||||
|
- **`disallowed_tools`** - List of disallowed tool names
|
||||||
|
- **`sandbox`** - Sandbox configuration dict
|
||||||
|
- **`system_prompt`** - Custom system prompt or preset config
|
||||||
|
- **`api_key`** - Anthropic API key (falls back to `ANTHROPIC_API_KEY` env var)
|
||||||
|
|
||||||
- **`signature`** (`str | type[Signature]`)
|
### ClaudeCode
|
||||||
- DSPy signature defining input/output fields
|
|
||||||
- Must have exactly 1 input field and 1 output field
|
|
||||||
- Examples:
|
|
||||||
- String format: `'message:str -> answer:str'`
|
|
||||||
- Class format: `MySignature` (subclass of `dspy.Signature`)
|
|
||||||
|
|
||||||
- **`working_directory`** (`str`)
|
Main agent class.
|
||||||
- Directory where Claude will execute commands
|
|
||||||
- Example: `"."`, `"/path/to/project"`
|
|
||||||
|
|
||||||
**Optional:**
|
```python
|
||||||
|
class ClaudeCode(PrecompiledProgram):
|
||||||
|
def __init__(self, config: ClaudeCodeConfig)
|
||||||
|
```
|
||||||
|
|
||||||
- **`model`** (`Optional[str]`)
|
**Parameters:**
|
||||||
- Model to use: `"sonnet"`, `"opus"`, `"haiku"`
|
|
||||||
- Default: Claude Code default (typically Sonnet)
|
|
||||||
|
|
||||||
- **`permission_mode`** (`Optional[str]`)
|
- **`config`** - ClaudeCodeConfig instance with agent configuration
|
||||||
- Controls permission behavior:
|
|
||||||
- `"default"` - Standard permission checks
|
|
||||||
- `"acceptEdits"` - Auto-accept file edits
|
|
||||||
- `"plan"` - Planning mode (no execution)
|
|
||||||
- `"bypassPermissions"` - Bypass all checks (use with caution!)
|
|
||||||
- Default: `"default"`
|
|
||||||
|
|
||||||
- **`allowed_tools`** (`Optional[list[str]]`)
|
|
||||||
- List of allowed tool names
|
|
||||||
- Examples: `["Read", "Write", "Bash", "Glob"]`
|
|
||||||
- Default: All tools allowed
|
|
||||||
|
|
||||||
- **`disallowed_tools`** (`Optional[list[str]]`)
|
|
||||||
- List of disallowed tool names
|
|
||||||
- Default: `[]`
|
|
||||||
|
|
||||||
- **`sandbox`** (`Optional[dict[str, Any]]`)
|
|
||||||
- Sandbox configuration for command execution
|
|
||||||
- Example: `{"enabled": True, "network": {"allowLocalBinding": True}}`
|
|
||||||
- Default: `None`
|
|
||||||
|
|
||||||
- **`system_prompt`** (`Optional[str | dict[str, Any]]`)
|
|
||||||
- Custom system prompt or preset configuration
|
|
||||||
- String: Custom prompt
|
|
||||||
- Dict: Preset config like `{"type": "preset", "preset": "claude_code", "append": "..."}`
|
|
||||||
- Default: `None` (uses Claude Code default)
|
|
||||||
|
|
||||||
- **`api_key`** (`Optional[str]`)
|
|
||||||
- Anthropic API key
|
|
||||||
- Falls back to `ANTHROPIC_API_KEY` environment variable
|
|
||||||
- Default: `None`
|
|
||||||
|
|
||||||
- **`**kwargs`** - Additional `ClaudeAgentOptions` parameters
|
|
||||||
|
|
||||||
#### Methods
|
#### Methods
|
||||||
|
|
||||||
##### `forward(**kwargs) -> Prediction`
|
##### `__call__(**kwargs) -> Prediction` (or `forward`)
|
||||||
|
|
||||||
Execute the agent with an input message.
|
Execute the agent with an input message.
|
||||||
|
|
||||||
@@ -160,19 +218,42 @@ Execute the agent with an input message.
|
|||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```python
|
```python
|
||||||
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> answer:str",
|
||||||
|
working_directory="."
|
||||||
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
result = agent(message="Hello")
|
result = agent(message="Hello")
|
||||||
print(result.answer) # Access typed output
|
print(result.answer) # Access typed output
|
||||||
print(result.trace) # List of execution items
|
print(result.trace) # List of execution items
|
||||||
print(result.usage) # Token usage stats
|
print(result.usage) # Token usage stats
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### `push_to_hub(repo_id: str) -> None`
|
||||||
|
|
||||||
|
Push the agent to Modaic Hub.
|
||||||
|
|
||||||
|
**Arguments:**
|
||||||
|
- `repo_id` - Repository ID in format "username/repo-name"
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```python
|
||||||
|
agent.push_to_hub("your-username/your-agent")
|
||||||
|
```
|
||||||
|
|
||||||
##### `aforward(**kwargs) -> Prediction`
|
##### `aforward(**kwargs) -> Prediction`
|
||||||
|
|
||||||
Async version of `forward()` for use in async contexts.
|
Async version of `__call__()` for use in async contexts.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```python
|
```python
|
||||||
async def main():
|
async def main():
|
||||||
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> answer:str",
|
||||||
|
working_directory="."
|
||||||
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
result = await agent.aforward(message="Hello")
|
result = await agent.aforward(message="Hello")
|
||||||
print(result.answer)
|
print(result.answer)
|
||||||
```
|
```
|
||||||
@@ -183,17 +264,31 @@ async def main():
|
|||||||
|
|
||||||
Get the session ID for this agent instance.
|
Get the session ID for this agent instance.
|
||||||
|
|
||||||
- Returns `None` until first `forward()` call
|
- Returns `None` until first call
|
||||||
- Persists across multiple `forward()` calls
|
- Persists across multiple calls
|
||||||
- Useful for debugging and logging
|
- Useful for debugging and logging
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```python
|
```python
|
||||||
agent = ClaudeAgent(sig, working_directory=".")
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> answer:str",
|
||||||
|
working_directory="."
|
||||||
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
print(agent.session_id) # None
|
print(agent.session_id) # None
|
||||||
|
|
||||||
result = agent(message="Hello")
|
result = agent(message="Hello")
|
||||||
print(agent.session_id) # '0199e95f-2689-7501-a73d-038d77dd7320'
|
print(agent.session_id) # 'eb1b2f39-e04c-4506-9398-b50053b1fd83'
|
||||||
|
```
|
||||||
|
|
||||||
|
##### `config: ClaudeCodeConfig`
|
||||||
|
|
||||||
|
Access to the agent's configuration.
|
||||||
|
|
||||||
|
```python
|
||||||
|
print(agent.config.model) # 'claude-opus-4-5-20251101'
|
||||||
|
print(agent.config.working_directory) # '.'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage Patterns
|
## Usage Patterns
|
||||||
@@ -203,7 +298,13 @@ print(agent.session_id) # '0199e95f-2689-7501-a73d-038d77dd7320'
|
|||||||
Each agent instance maintains a stateful session:
|
Each agent instance maintains a stateful session:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
agent = ClaudeAgent(sig, working_directory=".")
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
|
|
||||||
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> answer:str",
|
||||||
|
working_directory=".",
|
||||||
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
# Turn 1
|
# Turn 1
|
||||||
result1 = agent(message="What's the main bug?")
|
result1 = agent(message="What's the main bug?")
|
||||||
@@ -226,12 +327,19 @@ print(agent.session_id)
|
|||||||
Want a new conversation? Create a new agent:
|
Want a new conversation? Create a new agent:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
|
|
||||||
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> answer:str",
|
||||||
|
working_directory=".",
|
||||||
|
)
|
||||||
|
|
||||||
# Agent 1 - Task A
|
# Agent 1 - Task A
|
||||||
agent1 = ClaudeAgent(sig, working_directory=".")
|
agent1 = ClaudeCode(config)
|
||||||
result1 = agent1(message="Analyze bug in module A")
|
result1 = agent1(message="Analyze bug in module A")
|
||||||
|
|
||||||
# Agent 2 - Task B (no context from Agent 1)
|
# Agent 2 - Task B (no context from Agent 1)
|
||||||
agent2 = ClaudeAgent(sig, working_directory=".")
|
agent2 = ClaudeCode(config)
|
||||||
result2 = agent2(message="Analyze bug in module B")
|
result2 = agent2(message="Analyze bug in module B")
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -240,6 +348,9 @@ result2 = agent2(message="Analyze bug in module B")
|
|||||||
Enhance prompts with field descriptions:
|
Enhance prompts with field descriptions:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
import dspy
|
||||||
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
|
|
||||||
class MySignature(dspy.Signature):
|
class MySignature(dspy.Signature):
|
||||||
"""Analyze code architecture."""
|
"""Analyze code architecture."""
|
||||||
|
|
||||||
@@ -249,7 +360,11 @@ class MySignature(dspy.Signature):
|
|||||||
"1) Architecture overview, 2) Key components, 3) Dependencies"
|
"1) Architecture overview, 2) Key components, 3) Dependencies"
|
||||||
)
|
)
|
||||||
|
|
||||||
agent = ClaudeAgent(MySignature, working_directory=".")
|
config = ClaudeCodeConfig(
|
||||||
|
signature=MySignature,
|
||||||
|
working_directory=".",
|
||||||
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
result = agent(message="Analyze this codebase")
|
result = agent(message="Analyze this codebase")
|
||||||
|
|
||||||
# The description is automatically appended to the prompt
|
# The description is automatically appended to the prompt
|
||||||
@@ -260,7 +375,13 @@ result = agent(message="Analyze this codebase")
|
|||||||
Access detailed execution information:
|
Access detailed execution information:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from claude_agent import ToolUseItem, ToolResultItem
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig, ToolUseItem, ToolResultItem
|
||||||
|
|
||||||
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> answer:str",
|
||||||
|
working_directory=".",
|
||||||
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
result = agent(message="Fix the bug")
|
result = agent(message="Fix the bug")
|
||||||
|
|
||||||
@@ -294,28 +415,33 @@ print(f"Total: {result.usage.total_tokens}")
|
|||||||
Control what the agent can do:
|
Control what the agent can do:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
|
|
||||||
# Read-only (safest)
|
# Read-only (safest)
|
||||||
agent = ClaudeAgent(
|
config = ClaudeCodeConfig(
|
||||||
sig,
|
signature="message:str -> answer:str",
|
||||||
working_directory=".",
|
working_directory=".",
|
||||||
permission_mode="default",
|
permission_mode="default",
|
||||||
allowed_tools=["Read", "Glob", "Grep"],
|
allowed_tools=["Read", "Glob", "Grep"],
|
||||||
)
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
# Auto-accept file edits
|
# Auto-accept file edits
|
||||||
agent = ClaudeAgent(
|
config = ClaudeCodeConfig(
|
||||||
sig,
|
signature="message:str -> answer:str",
|
||||||
working_directory=".",
|
working_directory=".",
|
||||||
permission_mode="acceptEdits",
|
permission_mode="acceptEdits",
|
||||||
allowed_tools=["Read", "Write", "Edit"],
|
allowed_tools=["Read", "Write", "Edit"],
|
||||||
)
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
# Sandbox mode for command execution
|
# Sandbox mode for command execution
|
||||||
agent = ClaudeAgent(
|
config = ClaudeCodeConfig(
|
||||||
sig,
|
signature="message:str -> answer:str",
|
||||||
working_directory=".",
|
working_directory=".",
|
||||||
sandbox={"enabled": True},
|
sandbox={"enabled": True},
|
||||||
)
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Advanced Examples
|
## Advanced Examples
|
||||||
@@ -324,6 +450,7 @@ agent = ClaudeAgent(
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
|
|
||||||
class CodeReview(BaseModel):
|
class CodeReview(BaseModel):
|
||||||
summary: str = Field(description="High-level summary")
|
summary: str = Field(description="High-level summary")
|
||||||
@@ -331,15 +458,14 @@ class CodeReview(BaseModel):
|
|||||||
severity: str = Field(description="critical, high, medium, or low")
|
severity: str = Field(description="critical, high, medium, or low")
|
||||||
recommendations: list[str] = Field(description="Actionable recommendations")
|
recommendations: list[str] = Field(description="Actionable recommendations")
|
||||||
|
|
||||||
sig = dspy.Signature('message:str -> review:CodeReview')
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> review:CodeReview",
|
||||||
agent = ClaudeAgent(
|
|
||||||
sig,
|
|
||||||
working_directory="/path/to/project",
|
working_directory="/path/to/project",
|
||||||
model="sonnet",
|
model="sonnet",
|
||||||
permission_mode="default",
|
permission_mode="default",
|
||||||
allowed_tools=["Read", "Glob", "Grep"],
|
allowed_tools=["Read", "Glob", "Grep"],
|
||||||
)
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
result = agent(message="Review the changes in src/main.py")
|
result = agent(message="Review the changes in src/main.py")
|
||||||
|
|
||||||
@@ -351,13 +477,15 @@ for issue in result.review.issues:
|
|||||||
### Example 2: Iterative Debugging
|
### Example 2: Iterative Debugging
|
||||||
|
|
||||||
```python
|
```python
|
||||||
sig = dspy.Signature('message:str -> response:str')
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
agent = ClaudeAgent(
|
|
||||||
sig,
|
config = ClaudeCodeConfig(
|
||||||
|
signature="message:str -> response:str",
|
||||||
working_directory=".",
|
working_directory=".",
|
||||||
permission_mode="acceptEdits",
|
permission_mode="acceptEdits",
|
||||||
allowed_tools=["Read", "Write", "Bash"],
|
allowed_tools=["Read", "Write", "Bash"],
|
||||||
)
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
# Turn 1: Find the bug
|
# Turn 1: Find the bug
|
||||||
result1 = agent(message="Find the bug in src/calculator.py")
|
result1 = agent(message="Find the bug in src/calculator.py")
|
||||||
@@ -380,10 +508,14 @@ print(result4.response)
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from claude_dspy import ClaudeCode, ClaudeCodeConfig
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
sig = dspy.Signature('message:str -> answer:str')
|
config = ClaudeCodeConfig(
|
||||||
agent = ClaudeAgent(sig, working_directory=".")
|
signature="message:str -> answer:str",
|
||||||
|
working_directory=".",
|
||||||
|
)
|
||||||
|
agent = ClaudeCode(config)
|
||||||
|
|
||||||
# Use aforward in async context
|
# Use aforward in async context
|
||||||
result = await agent.aforward(message="Analyze this code")
|
result = await agent.aforward(message="Analyze this code")
|
||||||
@@ -409,20 +541,20 @@ When accessing `result.trace`, you'll see various item types:
|
|||||||
|
|
||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
### Signature <20> Claude Flow
|
### Signature <20> Claude Flow
|
||||||
|
|
||||||
```
|
```
|
||||||
1. Define signature: 'message:str -> answer:str'
|
1. Define signature: 'message:str -> answer:str'
|
||||||
|
|
||||||
2. ClaudeAgent validates (must have 1 input, 1 output)
|
2. ClaudeCode validates (must have 1 input, 1 output)
|
||||||
|
|
||||||
3. __init__ creates ClaudeSDKClient with options
|
3. __init__ creates ClaudeSDKClient with options
|
||||||
|
|
||||||
4. forward(message="...") extracts message
|
4. forward(message="...") extracts message
|
||||||
|
|
||||||
5. If output field has desc <20> append to message
|
5. If output field has desc <20> append to message
|
||||||
|
|
||||||
6. If output type ` str <20> generate JSON schema
|
6. If output type ` str <20> generate JSON schema
|
||||||
|
|
||||||
7. Call client.query(message) with optional output_format
|
7. Call client.query(message) with optional output_format
|
||||||
|
|
||||||
@@ -452,9 +584,9 @@ sig = dspy.Signature('message:str -> report:BugReport')
|
|||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Error: "ClaudeAgent requires exactly 1 input field"
|
### Error: "ClaudeCode requires exactly 1 input field"
|
||||||
|
|
||||||
Your signature has too many or too few fields. ClaudeAgent expects exactly one input and one output:
|
Your signature has too many or too few fields. ClaudeCode expects exactly one input and one output:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# L Wrong - multiple inputs
|
# L Wrong - multiple inputs
|
||||||
@@ -498,7 +630,7 @@ async def main():
|
|||||||
|
|
||||||
### Why 1 input, 1 output?
|
### Why 1 input, 1 output?
|
||||||
|
|
||||||
ClaudeAgent is designed for conversational agentic workflows. The input is always a message/prompt, and the output is always a response. This keeps the interface simple and predictable.
|
ClaudeCode is designed for conversational agentic workflows. The input is always a message/prompt, and the output is always a response. This keeps the interface simple and predictable.
|
||||||
|
|
||||||
For complex inputs, compose them into the message:
|
For complex inputs, compose them into the message:
|
||||||
|
|
||||||
@@ -510,7 +642,7 @@ result = agent(message=message)
|
|||||||
|
|
||||||
### Why stateful sessions?
|
### Why stateful sessions?
|
||||||
|
|
||||||
Agents often need multi-turn context (e.g., "fix the bug" <20> "write tests for it"). Stateful sessions make this natural without manual history management.
|
Agents often need multi-turn context (e.g., "fix the bug" <20> "write tests for it"). Stateful sessions make this natural without manual history management.
|
||||||
|
|
||||||
Want fresh context? Create a new agent instance.
|
Want fresh context? Create a new agent instance.
|
||||||
|
|
||||||
@@ -526,7 +658,7 @@ The trace provides full visibility into agent execution.
|
|||||||
|
|
||||||
## Comparison with CodexAgent
|
## Comparison with CodexAgent
|
||||||
|
|
||||||
| Feature | CodexAgent | ClaudeAgent |
|
| Feature | CodexAgent | ClaudeCode |
|
||||||
|---------|-----------|-------------|
|
|---------|-----------|-------------|
|
||||||
| SDK | OpenAI Codex SDK | Claude Code Python SDK |
|
| SDK | OpenAI Codex SDK | Claude Code Python SDK |
|
||||||
| Thread management | Built-in thread ID | Session-based (ClaudeSDKClient) |
|
| Thread management | Built-in thread ID | Session-based (ClaudeSDKClient) |
|
||||||
@@ -535,6 +667,7 @@ The trace provides full visibility into agent execution.
|
|||||||
| Tool types | Codex-specific | Claude Code tools (Bash, Read, Write, etc.) |
|
| Tool types | Codex-specific | Claude Code tools (Bash, Read, Write, etc.) |
|
||||||
| Sandbox | Simple mode enum | Detailed config dict |
|
| Sandbox | Simple mode enum | Detailed config dict |
|
||||||
| Permission control | Sandbox modes | Permission modes + allowed_tools |
|
| Permission control | Sandbox modes | Permission modes + allowed_tools |
|
||||||
|
| Configuration | Direct parameters | Config object (ClaudeCodeConfig) |
|
||||||
|
|
||||||
## Examples Directory
|
## Examples Directory
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user