12 KiB
AI Agents Configuration: [Project Name]
AI Provider: [OpenAI / Claude / Gemini / Cloudflare AI] Framework: [Vercel AI SDK / Custom / Cloudflare Workers AI] Agent Architecture: [Single agent / Multi-agent / Agentic workflows] Last Updated: [Date]
Overview
This document defines AI agents, their capabilities, tools, and workflows for this project.
Agent Philosophy:
- Purpose-built agents - Each agent has a specific, well-defined role
- Tool-equipped - Agents have access to functions they need
- Conversational - Agents can ask clarifying questions
- Stateful when needed - Use Durable Objects for long-running conversations
- Fail gracefully - Always have fallback responses
AI Provider Configuration
Primary Provider: [Provider Name]
Model: [e.g., gpt-5, claude-sonnet-4-5, gemini-2.5-pro]
API Key: Stored in environment variable [KEY_NAME]
Base URL: [API endpoint]
Configuration:
// src/lib/ai-config.ts
export const aiConfig = {
provider: '[provider]',
model: '[model-name]',
apiKey: process.env.[KEY_NAME],
temperature: 0.7,
maxTokens: 2000,
topP: 1.0
}
Fallback Provider (optional): [Secondary provider if primary fails]
Agents
Agent 1: [Agent Name]
Purpose: [What this agent does] Model: [Specific model if different from default] Context Window: [Token limit for this agent]
Capabilities:
- [Capability 1]
- [Capability 2]
- [Capability 3]
System Prompt:
You are [agent role]. Your goal is to [agent purpose].
Guidelines:
- [Guideline 1]
- [Guideline 2]
- [Guideline 3]
When you need information you don't have:
- Use available tools
- Ask the user clarifying questions
- Provide your best answer with caveats
Response format:
- Be concise and actionable
- Use markdown for formatting
- Include code examples when helpful
Available Tools:
[tool_name]- [Description][tool_name]- [Description]
Example Conversation:
User: [Example input]
Agent: [Example response]
User: [Follow-up]
Agent: [Agent uses tool and responds]
Endpoint: POST /api/agents/[agent-name]
Request:
{
"message": "User message",
"conversationId": "optional-conversation-id",
"context": { "optional": "context" }
}
Response (streaming):
data: {"type":"text","content":"Agent response..."}
data: {"type":"tool_call","name":"search","args":{"query":"..."}}
data: {"type":"tool_result","result":{...}}
data: {"type":"done"}
Agent 2: [Agent Name]
Purpose: [What this agent does]
[... repeat structure from Agent 1 ...]
Tools (Functions)
AI agents can call these functions to perform actions or retrieve information.
Tool: [tool_name]
Purpose: [What this tool does]
Parameters:
{
param1: string, // Description
param2: number, // Description
param3?: boolean // Optional description
}
Implementation:
// src/lib/ai-tools.ts
export async function [tool_name](params: ToolParams, context: Context) {
// Tool logic
const result = await performAction(params)
return result
}
Example:
// Agent calls tool
const result = await [tool_name]({
param1: "value",
param2: 42
})
// Tool returns
{
success: true,
data: { /* result */ }
}
Failure Handling: [How tool handles errors]
Tool: search_database
Purpose: Search the database for user-specific information
Parameters:
{
query: string, // Natural language search query
table: string, // Which table to search
limit?: number // Max results (default 5)
}
Implementation:
export async function search_database(
{ query, table, limit = 5 }: SearchParams,
context: Context
) {
const userId = context.get('userId')
// Convert natural language to SQL (simplified example)
const results = await context.env.DB.prepare(
`SELECT * FROM ${table} WHERE user_id = ? LIMIT ?`
).bind(userId, limit).all()
return {
success: true,
data: results.results
}
}
Agent Workflows
Workflow: [Workflow Name]
Purpose: [What this workflow accomplishes]
Agents Involved:
- [Agent 1] - [Role in workflow]
- [Agent 2] - [Role in workflow]
Flow:
1. User submits [input]
↓
2. [Agent 1] analyzes input
↓
3. [Agent 1] calls tool: [tool_name]
↓
4. Tool returns data
↓
5. [Agent 1] generates response
↓
6. If needed: Hand off to [Agent 2]
↓
7. [Agent 2] completes task
↓
8. Return final result to user
Example:
User: "Find all high-priority tasks and create a summary report"
[Planner Agent] → Calls search_database(query="high priority tasks")
→ Receives 5 tasks
→ Hands off to [Writer Agent] with task data
[Writer Agent] → Generates formatted report
→ Returns markdown report to user
Conversation State
Stateless Agents (Default)
When to use: Single-turn interactions, no context needed
Implementation: Each request is independent
Example: Simple Q&A, content generation
Stateful Agents (Durable Objects)
When to use: Multi-turn conversations, context retention
Implementation: Store conversation history in Durable Object
Setup:
// src/durable-objects/conversation.ts
export class Conversation implements DurableObject {
private messages: Message[] = []
async fetch(request: Request) {
const { message } = await request.json()
// Add user message to history
this.messages.push({ role: 'user', content: message })
// Call AI with full conversation history
const response = await callAI({
messages: this.messages,
tools: availableTools
})
// Add assistant response to history
this.messages.push({ role: 'assistant', content: response })
return new Response(JSON.stringify({ response }))
}
}
Wrangler Config:
{
"durable_objects": {
"bindings": [
{
"name": "CONVERSATIONS",
"class_name": "Conversation",
"script_name": "app"
}
]
}
}
Usage:
// Create/get conversation
const conversationId = crypto.randomUUID()
const durableObjectId = env.CONVERSATIONS.idFromName(conversationId)
const stub = env.CONVERSATIONS.get(durableObjectId)
// Send message to conversation
const response = await stub.fetch(request)
Streaming Responses
Why stream: Better UX, appears faster, shows progress
Implementation (Server-Sent Events):
// src/routes/agents.ts
app.post('/api/agents/:agentName', async (c) => {
const { message } = await c.req.json()
const stream = await streamAIResponse({
message,
agent: c.req.param('agentName')
})
return c.newResponse(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
}
})
})
Client (Vercel AI SDK):
import { useChat } from '@ai-sdk/react'
export function ChatInterface() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
api: '/api/agents/chat'
})
return (
<div>
{messages.map(m => (
<div key={m.id}>{m.content}</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
</form>
</div>
)
}
Prompt Engineering
System Prompt Best Practices
Structure:
- Role definition - "You are a [role]"
- Capabilities - What the agent can do
- Constraints - What the agent cannot do
- Tone/style - How the agent should respond
- Output format - Markdown, JSON, etc
Example:
You are a helpful task management assistant.
Your capabilities:
- Search user's tasks
- Create, update, delete tasks
- Generate task summaries and reports
- Set reminders and priorities
Your constraints:
- Never access other users' data
- Always confirm before deleting tasks
- Ask for clarification if user intent is unclear
Response style:
- Be concise and actionable
- Use bullet points for lists
- Include task IDs for reference
Output format:
- Use markdown formatting
- Bold important information
- Use code blocks for task IDs
Token Management
Cost Optimization:
- Use smaller models for simple tasks (gpt-5-mini, claude-haiku-4-5)
- Use larger models only when needed (gpt-5, claude-sonnet-4-5)
- Limit conversation history (keep last N messages)
- Summarize long conversations to reduce tokens
Token Budgets:
const TOKEN_BUDGETS = {
'simple-qa': {
model: 'gpt-5-mini',
maxInputTokens: 500,
maxOutputTokens: 500
},
'complex-analysis': {
model: 'gpt-5',
maxInputTokens: 4000,
maxOutputTokens: 2000
}
}
Error Handling
AI Provider Failures
Handle:
- Rate limits (retry with backoff)
- API errors (fallback provider or error message)
- Timeout (abort and inform user)
Example:
try {
const response = await callAI({ message, tools })
return response
} catch (error) {
if (error.code === 'rate_limit') {
// Retry with exponential backoff
await sleep(2000)
return await callAI({ message, tools })
} else {
// Return graceful error
return {
error: true,
message: "I'm having trouble processing that right now. Please try again."
}
}
}
Testing AI Agents
Unit Tests (Tool Functions)
Test each tool independently:
describe('search_database tool', () => {
it('returns user-specific results', async () => {
const result = await search_database({
query: 'high priority',
table: 'tasks'
}, mockContext)
expect(result.success).toBe(true)
expect(result.data.length).toBeGreaterThan(0)
})
})
Integration Tests (Agent Endpoints)
Test agent responses:
describe('POST /api/agents/assistant', () => {
it('responds to simple query', async () => {
const res = await app.request('/api/agents/assistant', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
},
body: JSON.stringify({
message: 'List my tasks'
})
})
expect(res.status).toBe(200)
const data = await res.json()
expect(data.response).toContain('task')
})
})
Manual Testing
Test Prompts:
- Simple queries: "What tasks do I have?"
- Tool usage: "Create a new task called 'Review PR'"
- Edge cases: "Delete all my tasks" (should confirm first)
- Unclear input: "Do the thing" (should ask for clarification)
- Multi-step: "Find high-priority tasks and summarize them"
Monitoring and Observability
Metrics to track:
- Agent invocations per day
- Average response time
- Token usage (input + output)
- Tool call frequency
- Error rate
Logging:
console.log('[Agent]', {
agent: 'assistant',
userId: context.get('userId'),
message: message.substring(0, 50),
tokensUsed: response.usage.total_tokens,
toolsCalled: toolCalls.map(t => t.name),
responseTime: Date.now() - startTime
})
Cloudflare Workers Analytics Engine (optional):
await env.ANALYTICS.writeDataPoint({
indexes: [userId],
doubles: [responseTime, tokensUsed],
blobs: [agentName, toolsCalled]
})
Future Agent Enhancements
- Add [agent name] for [purpose]
- Integrate [tool name] for [capability]
- Implement [workflow name]
- Add voice input/output
- Multi-modal support (images, files)
Revision History
v1.0 ([Date]): Initial agent configuration v1.1 ([Date]): [Changes made]