|
|
|
@@ -0,0 +1,986 @@
|
|
|
|
|
# Common Tasks & Recipes Guide
|
|
|
|
|
|
|
|
|
|
This guide provides step-by-step recipes for the most frequent operations in CleverAgents. Each recipe includes copy-paste examples, best practices, and troubleshooting tips.
|
|
|
|
|
|
|
|
|
|
## Table of Contents
|
|
|
|
|
|
|
|
|
|
- [Getting Started](#getting-started)
|
|
|
|
|
- [Working with Actors](#working-with-actors)
|
|
|
|
|
- [Creating and Using Skills](#creating-and-using-skills)
|
|
|
|
|
- [Defining Tools](#defining-tools)
|
|
|
|
|
- [Managing Resources](#managing-resources)
|
|
|
|
|
- [Using the Plan Lifecycle](#using-the-plan-lifecycle)
|
|
|
|
|
- [Configuration & Providers](#configuration--providers)
|
|
|
|
|
- [Integration Patterns](#integration-patterns)
|
|
|
|
|
- [Troubleshooting](#troubleshooting)
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Getting Started
|
|
|
|
|
|
|
|
|
|
### Recipe 1: Install and Verify CleverAgents
|
|
|
|
|
|
|
|
|
|
**Objective:** Set up CleverAgents and verify the installation works correctly.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Install the package:
|
|
|
|
|
```bash
|
|
|
|
|
pip install cleveragents
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Verify installation:
|
|
|
|
|
```bash
|
|
|
|
|
agents --version
|
|
|
|
|
agents --help
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Check available commands:
|
|
|
|
|
```bash
|
|
|
|
|
agents plan --help
|
|
|
|
|
agents actor --help
|
|
|
|
|
agents skill --help
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Use a virtual environment to isolate dependencies
|
|
|
|
|
- Keep the package updated: `pip install --upgrade cleveragents`
|
|
|
|
|
- Review the [Architecture](../architecture.md) document to understand core concepts
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **Command not found:** Ensure the virtual environment is activated
|
|
|
|
|
- **Version mismatch:** Run `pip install --upgrade cleveragents` to get the latest version
|
|
|
|
|
- **Import errors:** Check that all dependencies are installed with `pip list`
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### Recipe 2: Configure Your First Provider
|
|
|
|
|
|
|
|
|
|
**Objective:** Set up an AI provider (OpenAI, Anthropic, etc.) for use with agents.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Create a configuration file at `~/.cleveragents/config.yaml`:
|
|
|
|
|
```yaml
|
|
|
|
|
providers:
|
|
|
|
|
openai:
|
|
|
|
|
api_key: ${OPENAI_API_KEY}
|
|
|
|
|
model: gpt-4
|
|
|
|
|
temperature: 0.7
|
|
|
|
|
anthropic:
|
|
|
|
|
api_key: ${ANTHROPIC_API_KEY}
|
|
|
|
|
model: claude-3-sonnet-20240229
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Set environment variables:
|
|
|
|
|
```bash
|
|
|
|
|
export OPENAI_API_KEY="sk-..."
|
|
|
|
|
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Verify configuration:
|
|
|
|
|
```bash
|
|
|
|
|
agents config show
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Never commit API keys to version control; use environment variables
|
|
|
|
|
- Use `.env` files locally with tools like `python-dotenv`
|
|
|
|
|
- Test provider connectivity before building complex agents
|
|
|
|
|
- Rotate API keys regularly for security
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **Provider not found:** Verify the provider name matches supported providers in [API Reference](../api/providers.md)
|
|
|
|
|
- **Authentication failed:** Check that environment variables are set correctly
|
|
|
|
|
- **Connection timeout:** Verify network connectivity and API endpoint availability
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Working with Actors
|
|
|
|
|
|
|
|
|
|
### Recipe 3: Create a Basic Actor from YAML
|
|
|
|
|
|
|
|
|
|
**Objective:** Define a simple actor that can respond to user queries.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Create a file `my_actor.yaml`:
|
|
|
|
|
```yaml
|
|
|
|
|
name: "helpful-assistant"
|
|
|
|
|
version: "1.0.0"
|
|
|
|
|
description: "A helpful assistant that answers questions"
|
|
|
|
|
|
|
|
|
|
actor:
|
|
|
|
|
type: "reactive"
|
|
|
|
|
provider: "openai"
|
|
|
|
|
model: "gpt-4"
|
|
|
|
|
|
|
|
|
|
system_prompt: |
|
|
|
|
|
You are a helpful assistant. Answer questions clearly and concisely.
|
|
|
|
|
Always be respectful and accurate.
|
|
|
|
|
|
|
|
|
|
skills:
|
|
|
|
|
- name: "web_search"
|
|
|
|
|
description: "Search the web for information"
|
|
|
|
|
- name: "calculator"
|
|
|
|
|
description: "Perform mathematical calculations"
|
|
|
|
|
|
|
|
|
|
tools:
|
|
|
|
|
- name: "file_reader"
|
|
|
|
|
description: "Read files from the filesystem"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Load and test the actor:
|
|
|
|
|
```bash
|
|
|
|
|
agents actor load my_actor.yaml
|
|
|
|
|
agents actor test my_actor.yaml --input "What is 2+2?"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Use the actor in your application:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.actor import ActorFactory
|
|
|
|
|
|
|
|
|
|
actor = ActorFactory.from_yaml("my_actor.yaml")
|
|
|
|
|
response = actor.process("What is the capital of France?")
|
|
|
|
|
print(response)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Use descriptive names for actors (e.g., `document-analyzer`, `code-reviewer`)
|
|
|
|
|
- Document the actor's purpose and capabilities in the description
|
|
|
|
|
- Test actors with various inputs before deploying
|
|
|
|
|
- Version your actors and track changes in git
|
|
|
|
|
- Use environment variables for sensitive configuration
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **YAML parsing error:** Validate YAML syntax using `yamllint` or online validators
|
|
|
|
|
- **Provider not configured:** Ensure the provider is set up (see Recipe 2)
|
|
|
|
|
- **Skills not found:** Verify skill names match registered skills in your environment
|
|
|
|
|
- **Model not available:** Check that the specified model is available from your provider
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### Recipe 4: Create a LangGraph-Based Actor
|
|
|
|
|
|
|
|
|
|
**Objective:** Build a more sophisticated actor using LangGraph for complex workflows.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Create `langgraph_actor.yaml`:
|
|
|
|
|
```yaml
|
|
|
|
|
name: "research-assistant"
|
|
|
|
|
version: "1.0.0"
|
|
|
|
|
description: "An assistant that researches topics and synthesizes information"
|
|
|
|
|
|
|
|
|
|
actor:
|
|
|
|
|
type: "langgraph"
|
|
|
|
|
provider: "anthropic"
|
|
|
|
|
model: "claude-3-sonnet-20240229"
|
|
|
|
|
|
|
|
|
|
graph:
|
|
|
|
|
nodes:
|
|
|
|
|
- name: "analyze_query"
|
|
|
|
|
description: "Analyze the user's query to understand intent"
|
|
|
|
|
type: "llm"
|
|
|
|
|
|
|
|
|
|
- name: "search_information"
|
|
|
|
|
description: "Search for relevant information"
|
|
|
|
|
type: "tool"
|
|
|
|
|
tools:
|
|
|
|
|
- "web_search"
|
|
|
|
|
- "database_query"
|
|
|
|
|
|
|
|
|
|
- name: "synthesize_response"
|
|
|
|
|
description: "Synthesize findings into a coherent response"
|
|
|
|
|
type: "llm"
|
|
|
|
|
|
|
|
|
|
edges:
|
|
|
|
|
- from: "analyze_query"
|
|
|
|
|
to: "search_information"
|
|
|
|
|
- from: "search_information"
|
|
|
|
|
to: "synthesize_response"
|
|
|
|
|
|
|
|
|
|
checkpointing: true
|
|
|
|
|
memory_type: "conversation_buffer"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Implement the actor in Python:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.langgraph import LangGraphActorBuilder
|
|
|
|
|
from langgraph.graph import StateGraph
|
|
|
|
|
from typing import TypedDict
|
|
|
|
|
|
|
|
|
|
class ResearchState(TypedDict):
|
|
|
|
|
query: str
|
|
|
|
|
analysis: str
|
|
|
|
|
search_results: list[str]
|
|
|
|
|
response: str
|
|
|
|
|
|
|
|
|
|
builder = LangGraphActorBuilder("research-assistant")
|
|
|
|
|
|
|
|
|
|
async def analyze_query(state: ResearchState):
|
|
|
|
|
# Analyze the query
|
|
|
|
|
return {"analysis": "..."}
|
|
|
|
|
|
|
|
|
|
async def search_information(state: ResearchState):
|
|
|
|
|
# Search for information
|
|
|
|
|
return {"search_results": [...]}
|
|
|
|
|
|
|
|
|
|
async def synthesize_response(state: ResearchState):
|
|
|
|
|
# Synthesize findings
|
|
|
|
|
return {"response": "..."}
|
|
|
|
|
|
|
|
|
|
# Build the graph
|
|
|
|
|
graph = StateGraph(ResearchState)
|
|
|
|
|
graph.add_node("analyze_query", analyze_query)
|
|
|
|
|
graph.add_node("search_information", search_information)
|
|
|
|
|
graph.add_node("synthesize_response", synthesize_response)
|
|
|
|
|
|
|
|
|
|
graph.add_edge("analyze_query", "search_information")
|
|
|
|
|
graph.add_edge("search_information", "synthesize_response")
|
|
|
|
|
graph.set_entry_point("analyze_query")
|
|
|
|
|
graph.set_finish_point("synthesize_response")
|
|
|
|
|
|
|
|
|
|
compiled_graph = graph.compile()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Test the actor:
|
|
|
|
|
```python
|
|
|
|
|
result = await compiled_graph.ainvoke({
|
|
|
|
|
"query": "What are the latest developments in AI?"
|
|
|
|
|
})
|
|
|
|
|
print(result["response"])
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Use TypedDict for clear state definition
|
|
|
|
|
- Name nodes with descriptive verb-based names
|
|
|
|
|
- Include error handling in each node
|
|
|
|
|
- Use checkpointing for workflow resumption
|
|
|
|
|
- Test each node independently before integrating
|
|
|
|
|
- Document state transitions and expected outputs
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **State validation error:** Ensure all state fields are properly typed in TypedDict
|
|
|
|
|
- **Node not found:** Verify node names match in graph edges
|
|
|
|
|
- **Async/await issues:** Ensure all async functions are properly awaited
|
|
|
|
|
- **Memory overflow:** Implement state pruning for long conversations
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Creating and Using Skills
|
|
|
|
|
|
|
|
|
|
### Recipe 5: Define a Custom Skill
|
|
|
|
|
|
|
|
|
|
**Objective:** Create a reusable skill that agents can invoke.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Create a skill definition file `skills/summarizer.yaml`:
|
|
|
|
|
```yaml
|
|
|
|
|
name: "text-summarizer"
|
|
|
|
|
version: "1.0.0"
|
|
|
|
|
description: "Summarizes long text into concise summaries"
|
|
|
|
|
|
|
|
|
|
skill:
|
|
|
|
|
inputs:
|
|
|
|
|
- name: "text"
|
|
|
|
|
type: "string"
|
|
|
|
|
description: "The text to summarize"
|
|
|
|
|
required: true
|
|
|
|
|
- name: "length"
|
|
|
|
|
type: "string"
|
|
|
|
|
description: "Summary length (short, medium, long)"
|
|
|
|
|
default: "medium"
|
|
|
|
|
|
|
|
|
|
outputs:
|
|
|
|
|
- name: "summary"
|
|
|
|
|
type: "string"
|
|
|
|
|
description: "The summarized text"
|
|
|
|
|
- name: "key_points"
|
|
|
|
|
type: "array"
|
|
|
|
|
description: "Key points extracted from the text"
|
|
|
|
|
|
|
|
|
|
implementation:
|
|
|
|
|
type: "llm"
|
|
|
|
|
provider: "openai"
|
|
|
|
|
prompt: |
|
|
|
|
|
Summarize the following text in {{length}} format.
|
|
|
|
|
Extract key points as a bullet list.
|
|
|
|
|
|
|
|
|
|
Text: {{text}}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Implement the skill in Python:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.skills import Skill, SkillInput, SkillOutput
|
|
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
|
|
class TextSummarizerSkill(Skill):
|
|
|
|
|
name = "text-summarizer"
|
|
|
|
|
version = "1.0.0"
|
|
|
|
|
|
|
|
|
|
def __init__(self, llm_provider):
|
|
|
|
|
self.llm = llm_provider
|
|
|
|
|
|
|
|
|
|
async def execute(
|
|
|
|
|
self,
|
|
|
|
|
text: str,
|
|
|
|
|
length: str = "medium"
|
|
|
|
|
) -> dict[str, Any]:
|
|
|
|
|
"""Execute the summarization skill."""
|
|
|
|
|
prompt = f"""
|
|
|
|
|
Summarize the following text in {length} format.
|
|
|
|
|
Extract key points as a bullet list.
|
|
|
|
|
|
|
|
|
|
Text: {text}
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
response = await self.llm.generate(prompt)
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
"summary": response.summary,
|
|
|
|
|
"key_points": response.key_points
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Register and use the skill:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.skills import SkillRegistry
|
|
|
|
|
|
|
|
|
|
registry = SkillRegistry()
|
|
|
|
|
registry.register(TextSummarizerSkill(llm_provider))
|
|
|
|
|
|
|
|
|
|
# Use in an actor
|
|
|
|
|
skill = registry.get("text-summarizer")
|
|
|
|
|
result = await skill.execute(
|
|
|
|
|
text="Long document text...",
|
|
|
|
|
length="short"
|
|
|
|
|
)
|
|
|
|
|
print(result["summary"])
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Keep skills focused on a single responsibility
|
|
|
|
|
- Provide clear input/output documentation
|
|
|
|
|
- Include validation for input parameters
|
|
|
|
|
- Handle errors gracefully with meaningful messages
|
|
|
|
|
- Test skills independently before integrating with actors
|
|
|
|
|
- Version skills and track breaking changes
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **Skill not found:** Verify the skill is registered in the registry
|
|
|
|
|
- **Input validation error:** Check that all required inputs are provided
|
|
|
|
|
- **Provider error:** Ensure the provider is configured and available
|
|
|
|
|
- **Timeout:** Increase timeout for long-running operations
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Defining Tools
|
|
|
|
|
|
|
|
|
|
### Recipe 6: Create a Custom Tool
|
|
|
|
|
|
|
|
|
|
**Objective:** Define a tool that agents can use to interact with external systems.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Create a tool definition `tools/database_query.yaml`:
|
|
|
|
|
```yaml
|
|
|
|
|
name: "database-query"
|
|
|
|
|
version: "1.0.0"
|
|
|
|
|
description: "Query a database and retrieve results"
|
|
|
|
|
|
|
|
|
|
tool:
|
|
|
|
|
type: "function"
|
|
|
|
|
|
|
|
|
|
inputs:
|
|
|
|
|
- name: "query"
|
|
|
|
|
type: "string"
|
|
|
|
|
description: "SQL query to execute"
|
|
|
|
|
required: true
|
|
|
|
|
- name: "database"
|
|
|
|
|
type: "string"
|
|
|
|
|
description: "Database name"
|
|
|
|
|
default: "default"
|
|
|
|
|
|
|
|
|
|
outputs:
|
|
|
|
|
- name: "results"
|
|
|
|
|
type: "array"
|
|
|
|
|
description: "Query results as array of objects"
|
|
|
|
|
- name: "row_count"
|
|
|
|
|
type: "integer"
|
|
|
|
|
description: "Number of rows returned"
|
|
|
|
|
|
|
|
|
|
safety_profile:
|
|
|
|
|
- restriction: "sql_injection"
|
|
|
|
|
level: "high"
|
|
|
|
|
- restriction: "data_access"
|
|
|
|
|
level: "medium"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Implement the tool in Python:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.tool import Tool, ToolInput, ToolOutput
|
|
|
|
|
from typing import Any
|
|
|
|
|
import sqlite3
|
|
|
|
|
|
|
|
|
|
class DatabaseQueryTool(Tool):
|
|
|
|
|
name = "database-query"
|
|
|
|
|
version = "1.0.0"
|
|
|
|
|
|
|
|
|
|
def __init__(self, db_path: str):
|
|
|
|
|
self.db_path = db_path
|
|
|
|
|
|
|
|
|
|
async def execute(
|
|
|
|
|
self,
|
|
|
|
|
query: str,
|
|
|
|
|
database: str = "default"
|
|
|
|
|
) -> dict[str, Any]:
|
|
|
|
|
"""Execute a database query safely."""
|
|
|
|
|
# Validate query to prevent SQL injection
|
|
|
|
|
if not self._is_safe_query(query):
|
|
|
|
|
raise ValueError("Query contains potentially unsafe patterns")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
conn = sqlite3.connect(self.db_path)
|
|
|
|
|
cursor = conn.cursor()
|
|
|
|
|
cursor.execute(query)
|
|
|
|
|
results = cursor.fetchall()
|
|
|
|
|
conn.close()
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
"results": [dict(row) for row in results],
|
|
|
|
|
"row_count": len(results)
|
|
|
|
|
}
|
|
|
|
|
except sqlite3.Error as e:
|
|
|
|
|
raise RuntimeError(f"Database error: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def _is_safe_query(self, query: str) -> bool:
|
|
|
|
|
"""Validate query safety."""
|
|
|
|
|
dangerous_keywords = ["DROP", "DELETE", "TRUNCATE"]
|
|
|
|
|
return not any(kw in query.upper() for kw in dangerous_keywords)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Register and use the tool:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.tool import ToolRegistry
|
|
|
|
|
|
|
|
|
|
registry = ToolRegistry()
|
|
|
|
|
registry.register(DatabaseQueryTool("data.db"))
|
|
|
|
|
|
|
|
|
|
# Use in an actor
|
|
|
|
|
tool = registry.get("database-query")
|
|
|
|
|
result = await tool.execute(
|
|
|
|
|
query="SELECT * FROM users WHERE age > 18",
|
|
|
|
|
database="default"
|
|
|
|
|
)
|
|
|
|
|
print(f"Found {result['row_count']} users")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Implement strict input validation
|
|
|
|
|
- Use safety profiles to restrict dangerous operations
|
|
|
|
|
- Log all tool invocations for audit trails
|
|
|
|
|
- Implement rate limiting for external API calls
|
|
|
|
|
- Handle errors gracefully with informative messages
|
|
|
|
|
- Document all parameters and return values
|
|
|
|
|
- Test tools with various inputs including edge cases
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **Safety validation failed:** Review the safety profile and input validation
|
|
|
|
|
- **External API error:** Check API credentials and connectivity
|
|
|
|
|
- **Timeout:** Implement retry logic with exponential backoff
|
|
|
|
|
- **Rate limit exceeded:** Implement caching or request queuing
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Managing Resources
|
|
|
|
|
|
|
|
|
|
### Recipe 7: Define and Use Resources
|
|
|
|
|
|
|
|
|
|
**Objective:** Create and manage resources that agents can interact with.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Define a resource type in `resources/document.yaml`:
|
|
|
|
|
```yaml
|
|
|
|
|
name: "document"
|
|
|
|
|
version: "1.0.0"
|
|
|
|
|
description: "A text document resource"
|
|
|
|
|
|
|
|
|
|
resource:
|
|
|
|
|
type: "document"
|
|
|
|
|
|
|
|
|
|
properties:
|
|
|
|
|
- name: "path"
|
|
|
|
|
type: "string"
|
|
|
|
|
description: "File path to the document"
|
|
|
|
|
required: true
|
|
|
|
|
|
|
|
|
|
- name: "format"
|
|
|
|
|
type: "string"
|
|
|
|
|
description: "Document format (txt, pdf, docx)"
|
|
|
|
|
enum: ["txt", "pdf", "docx"]
|
|
|
|
|
|
|
|
|
|
- name: "content"
|
|
|
|
|
type: "string"
|
|
|
|
|
description: "Document content"
|
|
|
|
|
|
|
|
|
|
- name: "metadata"
|
|
|
|
|
type: "object"
|
|
|
|
|
description: "Document metadata"
|
|
|
|
|
|
|
|
|
|
operations:
|
|
|
|
|
- name: "read"
|
|
|
|
|
description: "Read document content"
|
|
|
|
|
inputs:
|
|
|
|
|
- name: "path"
|
|
|
|
|
type: "string"
|
|
|
|
|
|
|
|
|
|
- name: "write"
|
|
|
|
|
description: "Write content to document"
|
|
|
|
|
inputs:
|
|
|
|
|
- name: "path"
|
|
|
|
|
type: "string"
|
|
|
|
|
- name: "content"
|
|
|
|
|
type: "string"
|
|
|
|
|
|
|
|
|
|
- name: "analyze"
|
|
|
|
|
description: "Analyze document content"
|
|
|
|
|
inputs:
|
|
|
|
|
- name: "path"
|
|
|
|
|
type: "string"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Implement the resource in Python:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.resource import Resource, ResourceOperation
|
|
|
|
|
from typing import Any
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
class DocumentResource(Resource):
|
|
|
|
|
name = "document"
|
|
|
|
|
version = "1.0.0"
|
|
|
|
|
|
|
|
|
|
def __init__(self, path: str):
|
|
|
|
|
self.path = Path(path)
|
|
|
|
|
|
|
|
|
|
async def read(self) -> str:
|
|
|
|
|
"""Read document content."""
|
|
|
|
|
if not self.path.exists():
|
|
|
|
|
raise FileNotFoundError(f"Document not found: {self.path}")
|
|
|
|
|
|
|
|
|
|
return self.path.read_text()
|
|
|
|
|
|
|
|
|
|
async def write(self, content: str) -> None:
|
|
|
|
|
"""Write content to document."""
|
|
|
|
|
self.path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
self.path.write_text(content)
|
|
|
|
|
|
|
|
|
|
async def analyze(self) -> dict[str, Any]:
|
|
|
|
|
"""Analyze document content."""
|
|
|
|
|
content = await self.read()
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
"word_count": len(content.split()),
|
|
|
|
|
"line_count": len(content.split('\n')),
|
|
|
|
|
"character_count": len(content),
|
|
|
|
|
"format": self.path.suffix[1:]
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Use resources in an actor:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.resource import ResourceManager
|
|
|
|
|
|
|
|
|
|
manager = ResourceManager()
|
|
|
|
|
|
|
|
|
|
# Create a resource
|
|
|
|
|
doc = DocumentResource("documents/report.txt")
|
|
|
|
|
manager.register("report", doc)
|
|
|
|
|
|
|
|
|
|
# Use in an actor
|
|
|
|
|
content = await doc.read()
|
|
|
|
|
analysis = await doc.analyze()
|
|
|
|
|
|
|
|
|
|
print(f"Document has {analysis['word_count']} words")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Define clear resource types with well-documented properties
|
|
|
|
|
- Implement proper error handling for resource operations
|
|
|
|
|
- Use resource validation to ensure data integrity
|
|
|
|
|
- Implement access control for sensitive resources
|
|
|
|
|
- Log all resource operations for audit trails
|
|
|
|
|
- Cache resource data when appropriate
|
|
|
|
|
- Document resource lifecycle and cleanup
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **Resource not found:** Verify the resource path and existence
|
|
|
|
|
- **Access denied:** Check file permissions and access control
|
|
|
|
|
- **Invalid format:** Validate resource format matches expected type
|
|
|
|
|
- **Concurrent access:** Implement locking for shared resources
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Using the Plan Lifecycle
|
|
|
|
|
|
|
|
|
|
### Recipe 8: Create and Execute a Plan (v3 Workflow)
|
|
|
|
|
|
|
|
|
|
**Objective:** Use the v3 plan lifecycle to create, execute, and apply plans.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Create a plan from an action template:
|
|
|
|
|
```bash
|
|
|
|
|
# List available actions
|
|
|
|
|
agents action list
|
|
|
|
|
|
|
|
|
|
# Create a plan from an action
|
|
|
|
|
agents plan use local/document-analyzer my-project
|
|
|
|
|
# Output: Plan ID: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Execute the plan (strategize and execute phases):
|
|
|
|
|
```bash
|
|
|
|
|
agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Review the plan:
|
|
|
|
|
```bash
|
|
|
|
|
agents plan show 01HXM8C2ZK4Q7C2B3F2R4VYV6J
|
|
|
|
|
agents plan diff 01HXM8C2ZK4Q7C2B3F2R4VYV6J
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4. Apply the plan:
|
|
|
|
|
```bash
|
|
|
|
|
agents plan apply 01HXM8C2ZK4Q7C2B3F2R4VYV6J
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
5. Check plan status:
|
|
|
|
|
```bash
|
|
|
|
|
agents plan status 01HXM8C2ZK4Q7C2B3F2R4VYV6J
|
|
|
|
|
agents plan list
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Always review the plan before applying
|
|
|
|
|
- Use meaningful action names that describe the intent
|
|
|
|
|
- Keep plans focused on a single objective
|
|
|
|
|
- Document the plan's purpose and expected outcomes
|
|
|
|
|
- Use version control for action templates
|
|
|
|
|
- Test plans in a safe environment first
|
|
|
|
|
- Monitor plan execution for errors
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **Plan not found:** Verify the ULID is correct
|
|
|
|
|
- **Action not found:** Check that the action exists with `agents action list`
|
|
|
|
|
- **Execution failed:** Review the plan logs with `agents plan logs <PLAN_ID>`
|
|
|
|
|
- **Invalid state:** Ensure the plan is in the correct state for the operation
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Configuration & Providers
|
|
|
|
|
|
|
|
|
|
### Recipe 9: Configure Multiple Providers
|
|
|
|
|
|
|
|
|
|
**Objective:** Set up multiple AI providers and switch between them.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Create a comprehensive configuration file:
|
|
|
|
|
```yaml
|
|
|
|
|
# ~/.cleveragents/config.yaml
|
|
|
|
|
|
|
|
|
|
providers:
|
|
|
|
|
openai:
|
|
|
|
|
api_key: ${OPENAI_API_KEY}
|
|
|
|
|
model: gpt-4
|
|
|
|
|
temperature: 0.7
|
|
|
|
|
max_tokens: 2000
|
|
|
|
|
timeout: 30
|
|
|
|
|
|
|
|
|
|
anthropic:
|
|
|
|
|
api_key: ${ANTHROPIC_API_KEY}
|
|
|
|
|
model: claude-3-sonnet-20240229
|
|
|
|
|
temperature: 0.5
|
|
|
|
|
max_tokens: 4000
|
|
|
|
|
timeout: 30
|
|
|
|
|
|
|
|
|
|
ollama:
|
|
|
|
|
base_url: "http://localhost:11434"
|
|
|
|
|
model: "llama2"
|
|
|
|
|
temperature: 0.7
|
|
|
|
|
timeout: 60
|
|
|
|
|
|
|
|
|
|
defaults:
|
|
|
|
|
provider: "openai"
|
|
|
|
|
model: "gpt-4"
|
|
|
|
|
|
|
|
|
|
logging:
|
|
|
|
|
level: "INFO"
|
|
|
|
|
format: "json"
|
|
|
|
|
|
|
|
|
|
cache:
|
|
|
|
|
enabled: true
|
|
|
|
|
ttl: 3600
|
|
|
|
|
|
|
|
|
|
security:
|
|
|
|
|
validate_ssl: true
|
|
|
|
|
rate_limit: 100
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Use different providers in actors:
|
|
|
|
|
```yaml
|
|
|
|
|
# Fast responses with Ollama
|
|
|
|
|
name: "local-assistant"
|
|
|
|
|
actor:
|
|
|
|
|
provider: "ollama"
|
|
|
|
|
model: "llama2"
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
# High quality with OpenAI
|
|
|
|
|
name: "premium-assistant"
|
|
|
|
|
actor:
|
|
|
|
|
provider: "openai"
|
|
|
|
|
model: "gpt-4"
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
# Cost-effective with Anthropic
|
|
|
|
|
name: "budget-assistant"
|
|
|
|
|
provider: "anthropic"
|
|
|
|
|
model: "claude-3-haiku-20240307"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Switch providers programmatically:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.config import ConfigManager
|
|
|
|
|
from cleveragents.providers import ProviderFactory
|
|
|
|
|
|
|
|
|
|
config = ConfigManager.load()
|
|
|
|
|
|
|
|
|
|
# Get a specific provider
|
|
|
|
|
openai_provider = ProviderFactory.create(
|
|
|
|
|
"openai",
|
|
|
|
|
config.providers["openai"]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Use the provider
|
|
|
|
|
response = await openai_provider.generate("Hello, world!")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Use environment variables for sensitive credentials
|
|
|
|
|
- Document provider-specific configuration options
|
|
|
|
|
- Test with multiple providers to understand differences
|
|
|
|
|
- Implement fallback providers for reliability
|
|
|
|
|
- Monitor provider usage and costs
|
|
|
|
|
- Use caching to reduce API calls
|
|
|
|
|
- Implement rate limiting awareness
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **Provider not found:** Verify provider name in configuration
|
|
|
|
|
- **Authentication failed:** Check API keys and credentials
|
|
|
|
|
- **Model not available:** Verify model name is correct for the provider
|
|
|
|
|
- **Rate limit exceeded:** Implement request queuing or caching
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Integration Patterns
|
|
|
|
|
|
|
|
|
|
### Recipe 10: Integrate with LangChain
|
|
|
|
|
|
|
|
|
|
**Objective:** Use CleverAgents with LangChain components.
|
|
|
|
|
|
|
|
|
|
**Steps:**
|
|
|
|
|
|
|
|
|
|
1. Create a LangChain-based actor:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.langgraph import LangGraphActorBuilder
|
|
|
|
|
from langchain.prompts import ChatPromptTemplate
|
|
|
|
|
from langchain.schema.runnable import RunnablePassthrough
|
|
|
|
|
from langchain_openai import ChatOpenAI
|
|
|
|
|
|
|
|
|
|
# Create LLM
|
|
|
|
|
llm = ChatOpenAI(model="gpt-4", temperature=0.7)
|
|
|
|
|
|
|
|
|
|
# Create prompt template
|
|
|
|
|
prompt = ChatPromptTemplate.from_template(
|
|
|
|
|
"You are a helpful assistant. Answer: {question}"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Create chain
|
|
|
|
|
chain = prompt | llm
|
|
|
|
|
|
|
|
|
|
# Use in CleverAgents
|
|
|
|
|
builder = LangGraphActorBuilder("langchain-assistant")
|
|
|
|
|
|
|
|
|
|
async def process_query(state):
|
|
|
|
|
response = await chain.ainvoke({"question": state["query"]})
|
|
|
|
|
return {"response": response.content}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Integrate with LangGraph workflows:
|
|
|
|
|
```python
|
|
|
|
|
from langgraph.graph import StateGraph
|
|
|
|
|
from typing import TypedDict
|
|
|
|
|
|
|
|
|
|
class QueryState(TypedDict):
|
|
|
|
|
query: str
|
|
|
|
|
context: str
|
|
|
|
|
response: str
|
|
|
|
|
|
|
|
|
|
graph = StateGraph(QueryState)
|
|
|
|
|
|
|
|
|
|
async def retrieve_context(state: QueryState):
|
|
|
|
|
# Retrieve relevant context
|
|
|
|
|
return {"context": "..."}
|
|
|
|
|
|
|
|
|
|
async def generate_response(state: QueryState):
|
|
|
|
|
# Generate response using LangChain
|
|
|
|
|
chain = prompt | llm
|
|
|
|
|
response = await chain.ainvoke({
|
|
|
|
|
"question": state["query"],
|
|
|
|
|
"context": state["context"]
|
|
|
|
|
})
|
|
|
|
|
return {"response": response.content}
|
|
|
|
|
|
|
|
|
|
graph.add_node("retrieve", retrieve_context)
|
|
|
|
|
graph.add_node("generate", generate_response)
|
|
|
|
|
graph.add_edge("retrieve", "generate")
|
|
|
|
|
graph.set_entry_point("retrieve")
|
|
|
|
|
graph.set_finish_point("generate")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Use LangChain's unified interfaces for provider abstraction
|
|
|
|
|
- Implement streaming for better UX
|
|
|
|
|
- Use memory classes for conversation history
|
|
|
|
|
- Implement proper error handling
|
|
|
|
|
- Test chains independently before integration
|
|
|
|
|
- Monitor token usage and costs
|
|
|
|
|
- Document chain behavior and expected outputs
|
|
|
|
|
|
|
|
|
|
**Troubleshooting:**
|
|
|
|
|
- **Import error:** Ensure LangChain is installed
|
|
|
|
|
- **Provider error:** Verify LangChain provider configuration
|
|
|
|
|
- **Chain error:** Check prompt template variables match inputs
|
|
|
|
|
- **Memory error:** Implement memory pruning for long conversations
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Troubleshooting
|
|
|
|
|
|
|
|
|
|
### Common Issues and Solutions
|
|
|
|
|
|
|
|
|
|
#### Issue: "Provider not configured"
|
|
|
|
|
|
|
|
|
|
**Symptoms:** Error message when trying to use an actor or skill.
|
|
|
|
|
|
|
|
|
|
**Solutions:**
|
|
|
|
|
1. Verify provider configuration:
|
|
|
|
|
```bash
|
|
|
|
|
agents config show
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Check environment variables:
|
|
|
|
|
```bash
|
|
|
|
|
echo $OPENAI_API_KEY
|
|
|
|
|
echo $ANTHROPIC_API_KEY
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Validate configuration file:
|
|
|
|
|
```bash
|
|
|
|
|
agents config validate
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4. Recreate configuration:
|
|
|
|
|
```bash
|
|
|
|
|
agents config init
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
#### Issue: "Skill/Tool not found"
|
|
|
|
|
|
|
|
|
|
**Symptoms:** Actor cannot find a registered skill or tool.
|
|
|
|
|
|
|
|
|
|
**Solutions:**
|
|
|
|
|
1. List available skills:
|
|
|
|
|
```bash
|
|
|
|
|
agents skill list
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. List available tools:
|
|
|
|
|
```bash
|
|
|
|
|
agents tool list
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Register the skill/tool:
|
|
|
|
|
```python
|
|
|
|
|
from cleveragents.skills import SkillRegistry
|
|
|
|
|
|
|
|
|
|
registry = SkillRegistry()
|
|
|
|
|
registry.register(MySkill())
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4. Check skill/tool names match exactly (case-sensitive)
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
#### Issue: "Plan execution failed"
|
|
|
|
|
|
|
|
|
|
**Symptoms:** Plan fails during execution with unclear error message.
|
|
|
|
|
|
|
|
|
|
**Solutions:**
|
|
|
|
|
1. Check plan logs:
|
|
|
|
|
```bash
|
|
|
|
|
agents plan logs <PLAN_ID>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Review plan details:
|
|
|
|
|
```bash
|
|
|
|
|
agents plan show <PLAN_ID>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. Check actor logs:
|
|
|
|
|
```bash
|
|
|
|
|
agents actor logs <ACTOR_NAME>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4. Verify all required skills and tools are available
|
|
|
|
|
|
|
|
|
|
5. Test individual components:
|
|
|
|
|
```bash
|
|
|
|
|
agents actor test <ACTOR_NAME> --input "test input"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### Getting Help
|
|
|
|
|
|
|
|
|
|
If you encounter issues not covered in this guide:
|
|
|
|
|
|
|
|
|
|
1. **Check the FAQ:** Review [FAQ](../faq.md) for common questions
|
|
|
|
|
2. **Review Architecture:** Understand core concepts in [Architecture](../architecture.md)
|
|
|
|
|
3. **Check API Reference:** Look up specific modules in [API Reference](../api/index.md)
|
|
|
|
|
4. **Review Examples:** Check `/examples/` directory for working examples
|
|
|
|
|
5. **Check ADRs:** Review [Architecture Decision Records](../adr/index.md) for design rationale
|
|
|
|
|
6. **Enable Debug Logging:** Set `logging.level: "DEBUG"` in configuration
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Related Documentation
|
|
|
|
|
|
|
|
|
|
- [Architecture](../architecture.md) - Core architectural concepts
|
|
|
|
|
- [API Reference](../api/index.md) - Detailed API documentation
|
|
|
|
|
- [Development Guide](../development/agent-system-specification.md) - Development best practices
|
|
|
|
|
- [Testing Guide](../development/testing.md) - Testing strategies and patterns
|
|
|
|
|
- [FAQ](../faq.md) - Frequently asked questions
|
|
|
|
|
- [Examples](../../examples/) - Working code examples
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
**Last Updated:** April 2026
|
|
|
|
|
|
|
|
|
|
For the latest updates and additional recipes, visit the [CleverAgents Documentation](https://docs.cleverthis.com/cleveragents).
|