Initial commit
This commit is contained in:
12
.claude-plugin/plugin.json
Normal file
12
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "claude-agent-sdk",
|
||||
"description": "Build autonomous AI agents with Claude Agent SDK. Create multi-step reasoning workflows, orchestrate subagents, integrate MCP servers. Use when: building coding agents, SRE systems, security auditors, code review bots, or troubleshooting CLI not found, context length exceeded errors.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "Jeremy Dawes",
|
||||
"email": "jeremy@jezweb.net"
|
||||
},
|
||||
"skills": [
|
||||
"./"
|
||||
]
|
||||
}
|
||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# claude-agent-sdk
|
||||
|
||||
Build autonomous AI agents with Claude Agent SDK. Create multi-step reasoning workflows, orchestrate subagents, integrate MCP servers. Use when: building coding agents, SRE systems, security auditors, code review bots, or troubleshooting CLI not found, context length exceeded errors.
|
||||
595
SKILL.md
Normal file
595
SKILL.md
Normal file
@@ -0,0 +1,595 @@
|
||||
---
|
||||
name: claude-agent-sdk
|
||||
description: |
|
||||
Build autonomous AI agents with Claude Agent SDK. Structured outputs (v0.1.45, Nov 2025) guarantee JSON schema validation, plugins system, hooks for event-driven workflows. Use when: building coding agents with validated JSON responses, SRE systems, security auditors, or troubleshooting CLI not found, structured output validation, session forking errors.
|
||||
license: MIT
|
||||
metadata:
|
||||
version: 2.0.0
|
||||
last_verified: 2025-11-22
|
||||
package_version: 0.1.50
|
||||
token_savings: ~70%
|
||||
errors_prevented: 12
|
||||
breaking_changes: v0.1.45 - Structured outputs (Nov 2025), v0.1.0 - No default system prompt, settingSources required
|
||||
keywords:
|
||||
- claude agent sdk
|
||||
- "@anthropic-ai/claude-agent-sdk"
|
||||
- structured outputs
|
||||
- json schema validation
|
||||
- outputFormat
|
||||
- query()
|
||||
- createSdkMcpServer
|
||||
- AgentDefinition
|
||||
- tool()
|
||||
- claude subagents
|
||||
- mcp servers
|
||||
- autonomous agents
|
||||
- plugins system
|
||||
- hooks system
|
||||
- session management
|
||||
- session forking
|
||||
- permissionMode
|
||||
- canUseTool
|
||||
- multi-agent orchestration
|
||||
- settingSources
|
||||
- CLI not found
|
||||
- context length exceeded
|
||||
- structured output validation
|
||||
- zod schema
|
||||
---
|
||||
|
||||
# Claude Agent SDK - Structured Outputs & Error Prevention Guide
|
||||
|
||||
**Package**: @anthropic-ai/claude-agent-sdk@0.1.50 (Nov 21, 2025)
|
||||
**Breaking Changes**: v0.1.45 - Structured outputs (Nov 2025), v0.1.0 - No default system prompt, settingSources required
|
||||
|
||||
---
|
||||
|
||||
## What's New in v0.1.45+ (Nov 2025)
|
||||
|
||||
**Major Features:**
|
||||
|
||||
### 1. Structured Outputs (v0.1.45, Nov 14, 2025)
|
||||
- **JSON schema validation** - Guarantees responses match exact schemas
|
||||
- **`outputFormat` parameter** - Define output structure with JSON schema or Zod
|
||||
- **Access validated results** - Via `message.structured_output`
|
||||
- **Beta header required**: `structured-outputs-2025-11-13`
|
||||
- **Type safety** - Full TypeScript inference with Zod schemas
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
import { z } from "zod";
|
||||
|
||||
const schema = z.object({
|
||||
summary: z.string(),
|
||||
sentiment: z.enum(['positive', 'neutral', 'negative']),
|
||||
confidence: z.number().min(0).max(1)
|
||||
});
|
||||
|
||||
const response = query({
|
||||
prompt: "Analyze this code review feedback",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
outputFormat: {
|
||||
type: "json_schema",
|
||||
json_schema: {
|
||||
name: "AnalysisResult",
|
||||
strict: true,
|
||||
schema: zodToJsonSchema(schema)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'result' && message.structured_output) {
|
||||
// Guaranteed to match schema
|
||||
const validated = schema.parse(message.structured_output);
|
||||
console.log(`Sentiment: ${validated.sentiment}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Plugins System (v0.1.27)
|
||||
- **`plugins` array** - Load local plugin paths
|
||||
- **Custom plugin support** - Extend agent capabilities
|
||||
|
||||
### 3. Hooks System (v0.1.0+)
|
||||
- **Event-driven callbacks** - PreToolUse, PostToolUse, Notification, UserPromptSubmit
|
||||
- **Session event hooks** - Monitor and control agent behavior
|
||||
|
||||
### 4. Additional Options
|
||||
- **`fallbackModel`** - Automatic model fallback on failures
|
||||
- **`maxThinkingTokens`** - Control extended thinking budget
|
||||
- **`strictMcpConfig`** - Strict MCP configuration validation
|
||||
- **`continue`** - Resume with new prompt (differs from `resume`)
|
||||
- **`permissionMode: 'plan'`** - New permission mode for planning workflows
|
||||
|
||||
📚 **Docs**: https://platform.claude.com/docs/en/agent-sdk/structured-outputs
|
||||
|
||||
---
|
||||
|
||||
## The Complete Claude Agent SDK Reference
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Core Query API](#core-query-api)
|
||||
2. [Tool Integration](#tool-integration-built-in--custom)
|
||||
3. [MCP Servers](#mcp-servers-model-context-protocol)
|
||||
4. [Subagent Orchestration](#subagent-orchestration)
|
||||
5. [Session Management](#session-management)
|
||||
6. [Permission Control](#permission-control)
|
||||
7. [Filesystem Settings](#filesystem-settings)
|
||||
8. [Message Types & Streaming](#message-types--streaming)
|
||||
9. [Error Handling](#error-handling)
|
||||
10. [Known Issues](#known-issues-prevention)
|
||||
|
||||
---
|
||||
|
||||
## Core Query API
|
||||
|
||||
**Key signature:**
|
||||
```typescript
|
||||
query(prompt: string | AsyncIterable<SDKUserMessage>, options?: Options)
|
||||
-> AsyncGenerator<SDKMessage>
|
||||
```
|
||||
|
||||
**Critical Options:**
|
||||
- `outputFormat` - Structured JSON schema validation (v0.1.45+)
|
||||
- `settingSources` - Filesystem settings loading ('user'|'project'|'local')
|
||||
- `canUseTool` - Custom permission logic callback
|
||||
- `agents` - Programmatic subagent definitions
|
||||
- `mcpServers` - MCP server configuration
|
||||
- `permissionMode` - 'default'|'acceptEdits'|'bypassPermissions'|'plan'
|
||||
|
||||
---
|
||||
|
||||
## Tool Integration (Built-in + Custom)
|
||||
|
||||
**Tool Control:**
|
||||
- `allowedTools` - Whitelist (takes precedence)
|
||||
- `disallowedTools` - Blacklist
|
||||
- `canUseTool` - Custom permission callback (see Permission Control section)
|
||||
|
||||
**Built-in Tools:** Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch, Task, NotebookEdit, BashOutput, KillBash, ListMcpResources, ReadMcpResource
|
||||
|
||||
---
|
||||
|
||||
## MCP Servers (Model Context Protocol)
|
||||
|
||||
**Server Types:**
|
||||
- **In-process** - `createSdkMcpServer()` with `tool()` definitions
|
||||
- **External** - stdio, HTTP, SSE transport
|
||||
|
||||
**Tool Definition:**
|
||||
```typescript
|
||||
tool(name: string, description: string, zodSchema, handler)
|
||||
```
|
||||
|
||||
**Handler Return:**
|
||||
```typescript
|
||||
{ content: [{ type: "text", text: "..." }], isError?: boolean }
|
||||
```
|
||||
|
||||
### External MCP Servers (stdio)
|
||||
|
||||
```typescript
|
||||
const response = query({
|
||||
prompt: "List files and analyze Git history",
|
||||
options: {
|
||||
mcpServers: {
|
||||
// Filesystem server
|
||||
"filesystem": {
|
||||
command: "npx",
|
||||
args: ["@modelcontextprotocol/server-filesystem"],
|
||||
env: {
|
||||
ALLOWED_PATHS: "/Users/developer/projects:/tmp"
|
||||
}
|
||||
},
|
||||
// Git operations server
|
||||
"git": {
|
||||
command: "npx",
|
||||
args: ["@modelcontextprotocol/server-git"],
|
||||
env: {
|
||||
GIT_REPO_PATH: "/Users/developer/projects/my-repo"
|
||||
}
|
||||
}
|
||||
},
|
||||
allowedTools: [
|
||||
"mcp__filesystem__list_files",
|
||||
"mcp__filesystem__read_file",
|
||||
"mcp__git__log",
|
||||
"mcp__git__diff"
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### External MCP Servers (HTTP/SSE)
|
||||
|
||||
```typescript
|
||||
const response = query({
|
||||
prompt: "Analyze data from remote service",
|
||||
options: {
|
||||
mcpServers: {
|
||||
"remote-service": {
|
||||
url: "https://api.example.com/mcp",
|
||||
headers: {
|
||||
"Authorization": "Bearer your-token-here",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
}
|
||||
},
|
||||
allowedTools: ["mcp__remote-service__analyze"]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### MCP Tool Naming Convention
|
||||
|
||||
**Format**: `mcp__<server-name>__<tool-name>`
|
||||
|
||||
**CRITICAL:**
|
||||
- Server name and tool name MUST match configuration
|
||||
- Use double underscores (`__`) as separators
|
||||
- Include in `allowedTools` array
|
||||
|
||||
**Examples:** `mcp__weather-service__get_weather`, `mcp__filesystem__read_file`
|
||||
|
||||
---
|
||||
|
||||
## Subagent Orchestration
|
||||
|
||||
### AgentDefinition Type
|
||||
|
||||
```typescript
|
||||
type AgentDefinition = {
|
||||
description: string; // When to use this agent
|
||||
prompt: string; // System prompt for agent
|
||||
tools?: string[]; // Allowed tools (optional)
|
||||
model?: 'sonnet' | 'opus' | 'haiku' | 'inherit'; // Model (optional)
|
||||
}
|
||||
```
|
||||
|
||||
**Field Details:**
|
||||
|
||||
- **description**: When to use agent (used by main agent for delegation)
|
||||
- **prompt**: System prompt (defines role, inherits main context)
|
||||
- **tools**: Allowed tools (if omitted, inherits from main agent)
|
||||
- **model**: Model override (`haiku`/`sonnet`/`opus`/`inherit`)
|
||||
|
||||
**Usage:**
|
||||
```typescript
|
||||
agents: {
|
||||
"security-checker": {
|
||||
description: "Security audits and vulnerability scanning",
|
||||
prompt: "You check security. Scan for secrets, verify OWASP compliance.",
|
||||
tools: ["Read", "Grep", "Bash"],
|
||||
model: "sonnet"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Session Management
|
||||
|
||||
**Options:**
|
||||
- `resume: sessionId` - Continue previous session
|
||||
- `forkSession: true` - Create new branch from session
|
||||
- `continue: prompt` - Resume with new prompt (differs from `resume`)
|
||||
|
||||
**Session Forking Pattern (Unique Capability):**
|
||||
|
||||
```typescript
|
||||
// Explore alternative without modifying original
|
||||
const forked = query({
|
||||
prompt: "Try GraphQL instead of REST",
|
||||
options: {
|
||||
resume: sessionId,
|
||||
forkSession: true // Creates new branch, original session unchanged
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Capture Session ID:**
|
||||
```typescript
|
||||
for await (const message of response) {
|
||||
if (message.type === 'system' && message.subtype === 'init') {
|
||||
sessionId = message.session_id; // Save for later resume/fork
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Permission Control
|
||||
|
||||
**Permission Modes:**
|
||||
```typescript
|
||||
type PermissionMode = "default" | "acceptEdits" | "bypassPermissions" | "plan";
|
||||
```
|
||||
|
||||
- `default` - Standard permission checks
|
||||
- `acceptEdits` - Auto-approve file edits
|
||||
- `bypassPermissions` - Skip ALL checks (use in CI/CD only)
|
||||
- `plan` - Planning mode (v0.1.45+)
|
||||
|
||||
### Custom Permission Logic
|
||||
|
||||
```typescript
|
||||
const response = query({
|
||||
prompt: "Deploy application to production",
|
||||
options: {
|
||||
permissionMode: "default",
|
||||
canUseTool: async (toolName, input) => {
|
||||
// Allow read-only operations
|
||||
if (['Read', 'Grep', 'Glob'].includes(toolName)) {
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
|
||||
// Deny destructive bash commands
|
||||
if (toolName === 'Bash') {
|
||||
const dangerous = ['rm -rf', 'dd if=', 'mkfs', '> /dev/'];
|
||||
if (dangerous.some(pattern => input.command.includes(pattern))) {
|
||||
return {
|
||||
behavior: "deny",
|
||||
message: "Destructive command blocked for safety"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Require confirmation for deployments
|
||||
if (input.command?.includes('deploy') || input.command?.includes('kubectl apply')) {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: "Confirm deployment to production?"
|
||||
};
|
||||
}
|
||||
|
||||
// Allow by default
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### canUseTool Callback
|
||||
|
||||
```typescript
|
||||
type CanUseToolCallback = (
|
||||
toolName: string,
|
||||
input: any
|
||||
) => Promise<PermissionDecision>;
|
||||
|
||||
type PermissionDecision =
|
||||
| { behavior: "allow" }
|
||||
| { behavior: "deny"; message?: string }
|
||||
| { behavior: "ask"; message?: string };
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
|
||||
```typescript
|
||||
// Block all file writes
|
||||
canUseTool: async (toolName, input) => {
|
||||
if (toolName === 'Write' || toolName === 'Edit') {
|
||||
return { behavior: "deny", message: "No file modifications allowed" };
|
||||
}
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
|
||||
// Require confirmation for specific files
|
||||
canUseTool: async (toolName, input) => {
|
||||
const sensitivePaths = ['/etc/', '/root/', '.env', 'credentials.json'];
|
||||
if ((toolName === 'Write' || toolName === 'Edit') &&
|
||||
sensitivePaths.some(path => input.file_path?.includes(path))) {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `Modify sensitive file ${input.file_path}?`
|
||||
};
|
||||
}
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
|
||||
// Log all tool usage
|
||||
canUseTool: async (toolName, input) => {
|
||||
console.log(`Tool requested: ${toolName}`, input);
|
||||
await logToDatabase(toolName, input);
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Filesystem Settings
|
||||
|
||||
**Setting Sources:**
|
||||
```typescript
|
||||
type SettingSource = 'user' | 'project' | 'local';
|
||||
```
|
||||
|
||||
- `user` - `~/.claude/settings.json` (global)
|
||||
- `project` - `.claude/settings.json` (team-shared)
|
||||
- `local` - `.claude/settings.local.json` (gitignored overrides)
|
||||
|
||||
**Default:** NO settings loaded (`settingSources: []`)
|
||||
|
||||
### Settings Priority
|
||||
|
||||
When multiple sources loaded, settings merge in this order (highest priority first):
|
||||
|
||||
1. **Programmatic options** (passed to `query()`) - Always win
|
||||
2. **Local settings** (`.claude/settings.local.json`)
|
||||
3. **Project settings** (`.claude/settings.json`)
|
||||
4. **User settings** (`~/.claude/settings.json`)
|
||||
|
||||
**Example:**
|
||||
|
||||
```typescript
|
||||
// .claude/settings.json
|
||||
{
|
||||
"allowedTools": ["Read", "Write", "Edit"]
|
||||
}
|
||||
|
||||
// .claude/settings.local.json
|
||||
{
|
||||
"allowedTools": ["Read"] // Overrides project settings
|
||||
}
|
||||
|
||||
// Programmatic
|
||||
const response = query({
|
||||
options: {
|
||||
settingSources: ["project", "local"],
|
||||
allowedTools: ["Read", "Grep"] // ← This wins
|
||||
}
|
||||
});
|
||||
|
||||
// Actual allowedTools: ["Read", "Grep"]
|
||||
```
|
||||
|
||||
**Best Practice:** Use `settingSources: ["project"]` in CI/CD for consistent behavior.
|
||||
|
||||
---
|
||||
|
||||
## Message Types & Streaming
|
||||
|
||||
**Message Types:**
|
||||
- `system` - Session init/completion (includes `session_id`)
|
||||
- `assistant` - Agent responses
|
||||
- `tool_call` - Tool execution requests
|
||||
- `tool_result` - Tool execution results
|
||||
- `error` - Error messages
|
||||
- `result` - Final result (includes `structured_output` for v0.1.45+)
|
||||
|
||||
**Streaming Pattern:**
|
||||
```typescript
|
||||
for await (const message of response) {
|
||||
if (message.type === 'system' && message.subtype === 'init') {
|
||||
sessionId = message.session_id; // Capture for resume/fork
|
||||
}
|
||||
if (message.type === 'result' && message.structured_output) {
|
||||
// Structured output available (v0.1.45+)
|
||||
const validated = schema.parse(message.structured_output);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Error Codes:**
|
||||
|
||||
| Error Code | Cause | Solution |
|
||||
|------------|-------|----------|
|
||||
| `CLI_NOT_FOUND` | Claude Code not installed | Install: `npm install -g @anthropic-ai/claude-code` |
|
||||
| `AUTHENTICATION_FAILED` | Invalid API key | Check ANTHROPIC_API_KEY env var |
|
||||
| `RATE_LIMIT_EXCEEDED` | Too many requests | Implement retry with backoff |
|
||||
| `CONTEXT_LENGTH_EXCEEDED` | Prompt too long | Use session compaction, reduce context |
|
||||
| `PERMISSION_DENIED` | Tool blocked | Check permissionMode, canUseTool |
|
||||
| `TOOL_EXECUTION_FAILED` | Tool error | Check tool implementation |
|
||||
| `SESSION_NOT_FOUND` | Invalid session ID | Verify session ID |
|
||||
| `MCP_SERVER_FAILED` | Server error | Check server configuration |
|
||||
|
||||
---
|
||||
|
||||
## Known Issues Prevention
|
||||
|
||||
This skill prevents **12** documented issues:
|
||||
|
||||
### Issue #1: CLI Not Found Error
|
||||
**Error**: `"Claude Code CLI not installed"`
|
||||
**Source**: SDK requires Claude Code CLI
|
||||
**Why It Happens**: CLI not installed globally
|
||||
**Prevention**: Install before using SDK: `npm install -g @anthropic-ai/claude-code`
|
||||
|
||||
### Issue #2: Authentication Failed
|
||||
**Error**: `"Invalid API key"`
|
||||
**Source**: Missing or incorrect ANTHROPIC_API_KEY
|
||||
**Why It Happens**: Environment variable not set
|
||||
**Prevention**: Always set `export ANTHROPIC_API_KEY="sk-ant-..."`
|
||||
|
||||
### Issue #3: Permission Denied Errors
|
||||
**Error**: Tool execution blocked
|
||||
**Source**: `permissionMode` restrictions
|
||||
**Why It Happens**: Tool not allowed by permissions
|
||||
**Prevention**: Use `allowedTools` or custom `canUseTool` callback
|
||||
|
||||
### Issue #4: Context Length Exceeded
|
||||
**Error**: `"Prompt too long"`
|
||||
**Source**: Input exceeds model context window
|
||||
**Why It Happens**: Large codebase, long conversations
|
||||
**Prevention**: SDK auto-compacts, but reduce context if needed
|
||||
|
||||
### Issue #5: Tool Execution Timeout
|
||||
**Error**: Tool doesn't respond
|
||||
**Source**: Long-running tool execution
|
||||
**Why It Happens**: Tool takes too long (>5 minutes default)
|
||||
**Prevention**: Implement timeout handling in tool implementations
|
||||
|
||||
### Issue #6: Session Not Found
|
||||
**Error**: `"Invalid session ID"`
|
||||
**Source**: Session expired or invalid
|
||||
**Why It Happens**: Session ID incorrect or too old
|
||||
**Prevention**: Capture `session_id` from `system` init message
|
||||
|
||||
### Issue #7: MCP Server Connection Failed
|
||||
**Error**: Server not responding
|
||||
**Source**: Server not running or misconfigured
|
||||
**Why It Happens**: Command/URL incorrect, server crashed
|
||||
**Prevention**: Test MCP server independently, verify command/URL
|
||||
|
||||
### Issue #8: Subagent Definition Errors
|
||||
**Error**: Invalid AgentDefinition
|
||||
**Source**: Missing required fields
|
||||
**Why It Happens**: `description` or `prompt` missing
|
||||
**Prevention**: Always include `description` and `prompt` fields
|
||||
|
||||
### Issue #9: Settings File Not Found
|
||||
**Error**: `"Cannot read settings"`
|
||||
**Source**: Settings file doesn't exist
|
||||
**Why It Happens**: `settingSources` includes non-existent file
|
||||
**Prevention**: Check file exists before including in sources
|
||||
|
||||
### Issue #10: Tool Name Collision
|
||||
**Error**: Duplicate tool name
|
||||
**Source**: Multiple tools with same name
|
||||
**Why It Happens**: Two MCP servers define same tool name
|
||||
**Prevention**: Use unique tool names, prefix with server name
|
||||
|
||||
### Issue #11: Zod Schema Validation Error
|
||||
**Error**: Invalid tool input
|
||||
**Source**: Input doesn't match Zod schema
|
||||
**Why It Happens**: Agent provided wrong data type
|
||||
**Prevention**: Use descriptive Zod schemas with `.describe()`
|
||||
|
||||
### Issue #12: Filesystem Permission Denied
|
||||
**Error**: Cannot access path
|
||||
**Source**: Restricted filesystem access
|
||||
**Why It Happens**: Path outside `workingDirectory` or no permissions
|
||||
**Prevention**: Set correct `workingDirectory`, check file permissions
|
||||
|
||||
---
|
||||
|
||||
## Official Documentation
|
||||
|
||||
- **Agent SDK Overview**: https://platform.claude.com/docs/en/api/agent-sdk/overview
|
||||
- **TypeScript API**: https://platform.claude.com/docs/en/api/agent-sdk/typescript
|
||||
- **Structured Outputs**: https://platform.claude.com/docs/en/agent-sdk/structured-outputs
|
||||
- **GitHub (TypeScript)**: https://github.com/anthropics/claude-agent-sdk-typescript
|
||||
- **CHANGELOG**: https://github.com/anthropics/claude-agent-sdk-typescript/blob/main/CHANGELOG.md
|
||||
|
||||
---
|
||||
|
||||
**Token Efficiency**:
|
||||
- **Without skill**: ~12,000 tokens (MCP setup, permission patterns, session forking, structured outputs, error handling)
|
||||
- **With skill**: ~3,600 tokens (focused on v0.1.45+ features + error prevention + advanced patterns)
|
||||
- **Savings**: ~70% (~8,400 tokens)
|
||||
|
||||
**Errors prevented**: 12 documented issues with exact solutions
|
||||
**Key value**: Structured outputs (v0.1.45+), session forking, canUseTool patterns, settingSources priority, MCP naming, error codes
|
||||
|
||||
---
|
||||
|
||||
**Last verified**: 2025-11-22 | **Skill version**: 2.0.0 | **Changes**: Added v0.1.45 structured outputs, plugins, hooks, new options. Removed tutorial/basic examples (~750 lines). Focused on knowledge gaps + error prevention + advanced patterns.
|
||||
117
plugin.lock.json
Normal file
117
plugin.lock.json
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||
"pluginId": "gh:jezweb/claude-skills:skills/claude-agent-sdk",
|
||||
"normalized": {
|
||||
"repo": null,
|
||||
"ref": "refs/tags/v20251128.0",
|
||||
"commit": "315199601dfcaed916a0e54f31a1033dda9083c3",
|
||||
"treeHash": "9fccde519ca19cf105fbc6fad209544bb0c4fc39bab30eefd28c2eeb34a2428a",
|
||||
"generatedAt": "2025-11-28T10:19:02.433038Z",
|
||||
"toolVersion": "publish_plugins.py@0.2.0"
|
||||
},
|
||||
"origin": {
|
||||
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||
"branch": "master",
|
||||
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "claude-agent-sdk",
|
||||
"description": "Build autonomous AI agents with Claude Agent SDK. Create multi-step reasoning workflows, orchestrate subagents, integrate MCP servers. Use when: building coding agents, SRE systems, security auditors, code review bots, or troubleshooting CLI not found, context length exceeded errors.",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"content": {
|
||||
"files": [
|
||||
{
|
||||
"path": "README.md",
|
||||
"sha256": "4bb48906321c8bad9a94c37402fba317253a456069a9676db896af5a4c4ea9f8"
|
||||
},
|
||||
{
|
||||
"path": "SKILL.md",
|
||||
"sha256": "7c32c7ba4c1ad33e7cfe376c91583b1d736ac0e178dff83218c7c86fb33a7def"
|
||||
},
|
||||
{
|
||||
"path": "references/permissions-guide.md",
|
||||
"sha256": "5589e3eb8735bece774525ad1920d3872817c2220762ffbaaf9a323d301931d7"
|
||||
},
|
||||
{
|
||||
"path": "references/subagents-patterns.md",
|
||||
"sha256": "02da9234550f631981909e2215b6b75a2f143ce1a23f7900aca46b05d8105614"
|
||||
},
|
||||
{
|
||||
"path": "references/mcp-servers-guide.md",
|
||||
"sha256": "de51d6b2de83f28285c4ce9e026aaa82596d387635605b2d940fd3e01903fd74"
|
||||
},
|
||||
{
|
||||
"path": "references/top-errors.md",
|
||||
"sha256": "9851933034a5e6d7aabec4efcfec1376c13f4005779427acf143c7885c1e2ef1"
|
||||
},
|
||||
{
|
||||
"path": "references/query-api-reference.md",
|
||||
"sha256": "7d4fc6ecb314c35459b761b9d8dee4ed6400f88ed14a89b6fa07da3e647e8789"
|
||||
},
|
||||
{
|
||||
"path": "references/session-management.md",
|
||||
"sha256": "03aab36582a282c0287afa54e5d3b099b641ee7661c89565eb2342461a2d8c8e"
|
||||
},
|
||||
{
|
||||
"path": "scripts/check-versions.sh",
|
||||
"sha256": "aef12c3666dcf48dbd2ab9ab48ed0e6b3421f07c9b0b1ba8c8f86cce854b4333"
|
||||
},
|
||||
{
|
||||
"path": ".claude-plugin/plugin.json",
|
||||
"sha256": "2f4f11c881066e9935507f609cdd111d3ea4e4345a8ef1712c0d63ef0b2448f3"
|
||||
},
|
||||
{
|
||||
"path": "templates/query-with-tools.ts",
|
||||
"sha256": "f8b66826c6215495424d9bf531df8849d6f212337b8f87cfd426e45385a6a29a"
|
||||
},
|
||||
{
|
||||
"path": "templates/custom-mcp-server.ts",
|
||||
"sha256": "d0278f889dc636c29d93c5eee276e8df4b767040d5638fec0a749041f6ba9be4"
|
||||
},
|
||||
{
|
||||
"path": "templates/filesystem-settings.ts",
|
||||
"sha256": "978c605143ed6a21634e158db942ef058c77aa74d4888fc29369d97158599dce"
|
||||
},
|
||||
{
|
||||
"path": "templates/subagents-orchestration.ts",
|
||||
"sha256": "5fd7ba8aa4b8dc0c55751b42d93ba2683d97c24dfe342a3c979d88e256c168ba"
|
||||
},
|
||||
{
|
||||
"path": "templates/error-handling.ts",
|
||||
"sha256": "96e200d822d102291001c81988d7067c9617ad62dca4b69c784df3b0fa00a4e3"
|
||||
},
|
||||
{
|
||||
"path": "templates/package.json",
|
||||
"sha256": "f0f65eee92f660595f041990aef6f87399a66f31534cd84b87bcd7e353056f0b"
|
||||
},
|
||||
{
|
||||
"path": "templates/session-management.ts",
|
||||
"sha256": "a7694ad86949e55eff94ef0497fd57cade9df0e6c611eae4f05831590c7b73ac"
|
||||
},
|
||||
{
|
||||
"path": "templates/basic-query.ts",
|
||||
"sha256": "01bc97a086e10a3e154f8fb0f1b973c6b5ab06abe11267332120d278115a4f67"
|
||||
},
|
||||
{
|
||||
"path": "templates/tsconfig.json",
|
||||
"sha256": "ec2fcaa2f83c2321ae55023ef9c3b4deba02f391f77edd51f1427c31500af999"
|
||||
},
|
||||
{
|
||||
"path": "templates/permission-control.ts",
|
||||
"sha256": "7980eac42cee3af86354465963913b7ee35bd34cbc50b24d4ef9dba952905813"
|
||||
},
|
||||
{
|
||||
"path": "templates/multi-agent-workflow.ts",
|
||||
"sha256": "ca43932014e8cad916aeff24ea1b01a0f18b2ba9757a5a19fe7a7a0b64f8a85f"
|
||||
}
|
||||
],
|
||||
"dirSha256": "9fccde519ca19cf105fbc6fad209544bb0c4fc39bab30eefd28c2eeb34a2428a"
|
||||
},
|
||||
"security": {
|
||||
"scannedAt": null,
|
||||
"scannerVersion": null,
|
||||
"flags": []
|
||||
}
|
||||
}
|
||||
387
references/mcp-servers-guide.md
Normal file
387
references/mcp-servers-guide.md
Normal file
@@ -0,0 +1,387 @@
|
||||
# MCP Servers Guide
|
||||
|
||||
Complete guide to creating and using Model Context Protocol (MCP) servers with Claude Agent SDK.
|
||||
|
||||
---
|
||||
|
||||
## What Are MCP Servers?
|
||||
|
||||
MCP servers extend agent capabilities with custom tools. Think of them as plugins that give your agent new abilities.
|
||||
|
||||
**Use Cases**:
|
||||
- Database access
|
||||
- API integrations
|
||||
- Custom calculations
|
||||
- External service interactions
|
||||
- File system operations
|
||||
|
||||
---
|
||||
|
||||
## Creating In-Process MCP Servers
|
||||
|
||||
### Basic Server
|
||||
|
||||
```typescript
|
||||
import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
||||
import { z } from "zod";
|
||||
|
||||
const myServer = createSdkMcpServer({
|
||||
name: "my-service",
|
||||
version: "1.0.0",
|
||||
tools: [
|
||||
tool(
|
||||
"tool_name",
|
||||
"Tool description",
|
||||
{ /* Zod schema */ },
|
||||
async (args) => {
|
||||
// Implementation
|
||||
return {
|
||||
content: [{ type: "text", text: "Result" }]
|
||||
};
|
||||
}
|
||||
)
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
### Tool Definition Pattern
|
||||
|
||||
```typescript
|
||||
tool(
|
||||
name: string, // Tool identifier
|
||||
description: string, // What it does
|
||||
inputSchema: ZodSchema, // Input validation
|
||||
handler: Handler // Implementation
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zod Schemas
|
||||
|
||||
### Common Patterns
|
||||
|
||||
```typescript
|
||||
import { z } from "zod";
|
||||
|
||||
// String
|
||||
z.string()
|
||||
z.string().email()
|
||||
z.string().url()
|
||||
z.string().min(5).max(100)
|
||||
z.string().describe("Description for AI")
|
||||
|
||||
// Number
|
||||
z.number()
|
||||
z.number().int()
|
||||
z.number().positive()
|
||||
z.number().min(0).max(100)
|
||||
|
||||
// Boolean
|
||||
z.boolean()
|
||||
z.boolean().default(false)
|
||||
|
||||
// Enum
|
||||
z.enum(["option1", "option2", "option3"])
|
||||
z.union([z.literal("a"), z.literal("b")])
|
||||
|
||||
// Optional
|
||||
z.string().optional()
|
||||
z.number().default(10)
|
||||
|
||||
// Object
|
||||
z.object({
|
||||
name: z.string(),
|
||||
age: z.number(),
|
||||
email: z.string().email().optional()
|
||||
})
|
||||
|
||||
// Array
|
||||
z.array(z.string())
|
||||
z.array(z.number()).min(1).max(10)
|
||||
|
||||
// Complex nested
|
||||
z.object({
|
||||
user: z.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string(),
|
||||
roles: z.array(z.enum(["admin", "user", "guest"]))
|
||||
}),
|
||||
metadata: z.record(z.any()).optional()
|
||||
})
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
|
||||
```typescript
|
||||
// ✅ Good: Clear descriptions
|
||||
{
|
||||
location: z.string().describe("City name or coordinates (e.g., 'San Francisco, CA')"),
|
||||
radius: z.number().min(1).max(100).describe("Search radius in kilometers")
|
||||
}
|
||||
|
||||
// ❌ Bad: No descriptions
|
||||
{
|
||||
location: z.string(),
|
||||
radius: z.number()
|
||||
}
|
||||
|
||||
// ✅ Good: Validation constraints
|
||||
{
|
||||
email: z.string().email(),
|
||||
age: z.number().int().min(0).max(120),
|
||||
role: z.enum(["admin", "user", "guest"])
|
||||
}
|
||||
|
||||
// ❌ Bad: No validation
|
||||
{
|
||||
email: z.string(),
|
||||
age: z.number(),
|
||||
role: z.string()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Handler Implementation
|
||||
|
||||
### Success Response
|
||||
|
||||
```typescript
|
||||
async (args) => {
|
||||
const result = await performOperation(args);
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: JSON.stringify(result, null, 2)
|
||||
}]
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Error Response
|
||||
|
||||
```typescript
|
||||
async (args) => {
|
||||
try {
|
||||
const result = await riskyOperation(args);
|
||||
return {
|
||||
content: [{ type: "text", text: result }]
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Error: ${error.message}`
|
||||
}],
|
||||
isError: true // Mark as error
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Weather Service
|
||||
|
||||
```typescript
|
||||
const weatherServer = createSdkMcpServer({
|
||||
name: "weather",
|
||||
version: "1.0.0",
|
||||
tools: [
|
||||
tool(
|
||||
"get_weather",
|
||||
"Get current weather for a location",
|
||||
{
|
||||
location: z.string().describe("City name"),
|
||||
units: z.enum(["celsius", "fahrenheit"]).default("celsius")
|
||||
},
|
||||
async (args) => {
|
||||
const response = await fetch(
|
||||
`https://api.weather.com/v1/current?location=${args.location}&units=${args.units}`
|
||||
);
|
||||
const data = await response.json();
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Temp: ${data.temp}° ${args.units}\nConditions: ${data.conditions}`
|
||||
}]
|
||||
};
|
||||
}
|
||||
),
|
||||
tool(
|
||||
"get_forecast",
|
||||
"Get 7-day forecast",
|
||||
{
|
||||
location: z.string(),
|
||||
days: z.number().min(1).max(7).default(7)
|
||||
},
|
||||
async (args) => {
|
||||
const forecast = await fetchForecast(args.location, args.days);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(forecast, null, 2) }]
|
||||
};
|
||||
}
|
||||
)
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
### Database Service
|
||||
|
||||
```typescript
|
||||
const databaseServer = createSdkMcpServer({
|
||||
name: "database",
|
||||
version: "1.0.0",
|
||||
tools: [
|
||||
tool(
|
||||
"query",
|
||||
"Execute SQL query",
|
||||
{
|
||||
sql: z.string().describe("SQL query to execute"),
|
||||
params: z.array(z.any()).optional().describe("Query parameters")
|
||||
},
|
||||
async (args) => {
|
||||
try {
|
||||
const results = await db.query(args.sql, args.params);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
content: [{ type: "text", text: `SQL Error: ${error.message}` }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
}
|
||||
)
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Using MCP Servers
|
||||
|
||||
### In Query Options
|
||||
|
||||
```typescript
|
||||
const response = query({
|
||||
prompt: "What's the weather in NYC?",
|
||||
options: {
|
||||
mcpServers: {
|
||||
"weather": weatherServer,
|
||||
"database": databaseServer
|
||||
},
|
||||
allowedTools: [
|
||||
"mcp__weather__get_weather",
|
||||
"mcp__database__query"
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Tool Naming Convention
|
||||
|
||||
**Format**: `mcp__<server-name>__<tool-name>`
|
||||
|
||||
Examples:
|
||||
- `mcp__weather__get_weather`
|
||||
- `mcp__database__query`
|
||||
- `mcp__filesystem__read_file`
|
||||
|
||||
**CRITICAL**: Server and tool names must match exactly.
|
||||
|
||||
---
|
||||
|
||||
## External MCP Servers
|
||||
|
||||
### Stdio Servers
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
mcpServers: {
|
||||
"filesystem": {
|
||||
command: "npx",
|
||||
args: ["@modelcontextprotocol/server-filesystem"],
|
||||
env: {
|
||||
ALLOWED_PATHS: "/path/to/allowed/dir"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### HTTP/SSE Servers
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
mcpServers: {
|
||||
"remote": {
|
||||
url: "https://api.example.com/mcp",
|
||||
headers: {
|
||||
"Authorization": "Bearer token",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### ✅ Do
|
||||
|
||||
- Use clear tool names and descriptions
|
||||
- Add `.describe()` to all Zod fields
|
||||
- Implement error handling in handlers
|
||||
- Validate inputs with Zod constraints
|
||||
- Return clear, formatted responses
|
||||
- Test tools independently before integration
|
||||
- Use unique tool names across servers
|
||||
- Version your servers
|
||||
|
||||
### ❌ Don't
|
||||
|
||||
- Use generic names like "process" or "run"
|
||||
- Skip input validation
|
||||
- Return raw error objects
|
||||
- Forget `isError: true` on errors
|
||||
- Use duplicate tool names
|
||||
- Expose sensitive operations without checks
|
||||
- Skip testing in isolation
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Tool Not Found
|
||||
|
||||
**Problem**: `"Tool mcp__server__tool not found"`
|
||||
|
||||
**Solution**:
|
||||
1. Check server name matches
|
||||
2. Check tool name matches
|
||||
3. Include in `allowedTools` array
|
||||
4. Verify server added to `mcpServers`
|
||||
|
||||
### Tool Name Collision
|
||||
|
||||
**Problem**: Two tools with same name
|
||||
|
||||
**Solution**: Use unique names or prefix with server name
|
||||
|
||||
### Validation Errors
|
||||
|
||||
**Problem**: Invalid input to tool
|
||||
|
||||
**Solution**: Add descriptive Zod schemas with constraints
|
||||
|
||||
---
|
||||
|
||||
**For more details**: See SKILL.md
|
||||
**Official MCP docs**: https://modelcontextprotocol.io/
|
||||
429
references/permissions-guide.md
Normal file
429
references/permissions-guide.md
Normal file
@@ -0,0 +1,429 @@
|
||||
# Permissions Guide
|
||||
|
||||
Complete guide to permission control in Claude Agent SDK.
|
||||
|
||||
---
|
||||
|
||||
## Permission Modes
|
||||
|
||||
### Overview
|
||||
|
||||
Three built-in modes:
|
||||
|
||||
| Mode | Behavior | Use Case |
|
||||
|------|----------|----------|
|
||||
| `default` | Standard checks | General use, production |
|
||||
| `acceptEdits` | Auto-approve file edits | Trusted refactoring |
|
||||
| `bypassPermissions` | Skip ALL checks | CI/CD, sandboxed envs |
|
||||
|
||||
---
|
||||
|
||||
## Default Mode
|
||||
|
||||
Standard permission checks.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
permissionMode: "default"
|
||||
}
|
||||
```
|
||||
|
||||
**Prompts user for**:
|
||||
- File writes/edits
|
||||
- Potentially dangerous bash commands
|
||||
- Sensitive operations
|
||||
|
||||
**Auto-allows**:
|
||||
- Read operations (Read, Grep, Glob)
|
||||
- Safe bash commands
|
||||
|
||||
---
|
||||
|
||||
## Accept Edits Mode
|
||||
|
||||
Automatically approves file modifications.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
permissionMode: "acceptEdits"
|
||||
}
|
||||
```
|
||||
|
||||
**Auto-approves**:
|
||||
- File edits (Edit)
|
||||
- File writes (Write)
|
||||
|
||||
**Still prompts for**:
|
||||
- Dangerous bash commands
|
||||
- Sensitive operations
|
||||
|
||||
**Use when**: Refactoring, code generation workflows
|
||||
|
||||
---
|
||||
|
||||
## Bypass Permissions Mode
|
||||
|
||||
⚠️ **DANGER**: Skips ALL permission checks.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
permissionMode: "bypassPermissions"
|
||||
}
|
||||
```
|
||||
|
||||
**Auto-approves EVERYTHING**:
|
||||
- All file operations
|
||||
- All bash commands
|
||||
- All tools
|
||||
|
||||
**ONLY use in**:
|
||||
- CI/CD pipelines
|
||||
- Sandboxed containers
|
||||
- Docker environments
|
||||
- Trusted, isolated contexts
|
||||
|
||||
**NEVER use in**:
|
||||
- Production systems
|
||||
- User-facing environments
|
||||
- Untrusted inputs
|
||||
|
||||
---
|
||||
|
||||
## Custom Permission Logic
|
||||
|
||||
### canUseTool Callback
|
||||
|
||||
```typescript
|
||||
type CanUseTool = (
|
||||
toolName: string,
|
||||
input: any
|
||||
) => Promise<PermissionDecision>;
|
||||
|
||||
type PermissionDecision =
|
||||
| { behavior: "allow" }
|
||||
| { behavior: "deny"; message?: string }
|
||||
| { behavior: "ask"; message?: string };
|
||||
```
|
||||
|
||||
### Basic Example
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
canUseTool: async (toolName, input) => {
|
||||
// Allow read-only
|
||||
if (['Read', 'Grep', 'Glob'].includes(toolName)) {
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
|
||||
// Deny dangerous bash
|
||||
if (toolName === 'Bash' && input.command.includes('rm -rf')) {
|
||||
return {
|
||||
behavior: "deny",
|
||||
message: "Destructive command blocked"
|
||||
};
|
||||
}
|
||||
|
||||
// Ask for confirmation
|
||||
if (toolName === 'Write') {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `Create ${input.file_path}?`
|
||||
};
|
||||
}
|
||||
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern 1: Block Destructive Commands
|
||||
|
||||
```typescript
|
||||
canUseTool: async (toolName, input) => {
|
||||
if (toolName === 'Bash') {
|
||||
const dangerous = [
|
||||
'rm -rf',
|
||||
'dd if=',
|
||||
'mkfs',
|
||||
'> /dev/',
|
||||
'shutdown',
|
||||
'reboot',
|
||||
'kill -9',
|
||||
'pkill'
|
||||
];
|
||||
|
||||
for (const pattern of dangerous) {
|
||||
if (input.command.includes(pattern)) {
|
||||
return {
|
||||
behavior: "deny",
|
||||
message: `Blocked dangerous command: ${pattern}`
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 2: Protect Sensitive Files
|
||||
|
||||
```typescript
|
||||
canUseTool: async (toolName, input) => {
|
||||
if (toolName === 'Write' || toolName === 'Edit') {
|
||||
const sensitivePaths = [
|
||||
'/etc/',
|
||||
'/root/',
|
||||
'.env',
|
||||
'credentials',
|
||||
'secrets',
|
||||
'config/production',
|
||||
'.ssh/',
|
||||
'private_key'
|
||||
];
|
||||
|
||||
for (const path of sensitivePaths) {
|
||||
if (input.file_path?.includes(path)) {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `⚠️ Modify sensitive file: ${input.file_path}?`
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 3: Environment-Based Permissions
|
||||
|
||||
```typescript
|
||||
const environment = process.env.NODE_ENV; // 'development' | 'staging' | 'production'
|
||||
|
||||
canUseTool: async (toolName, input) => {
|
||||
// Production: require approval for everything
|
||||
if (environment === 'production') {
|
||||
if (toolName === 'Bash' || toolName === 'Write' || toolName === 'Edit') {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `PRODUCTION: Approve ${toolName}?`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Staging: auto-approve edits
|
||||
if (environment === 'staging') {
|
||||
if (toolName === 'Write' || toolName === 'Edit') {
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
|
||||
// Development: allow most things
|
||||
if (environment === 'development') {
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 4: Deployment Confirmation
|
||||
|
||||
```typescript
|
||||
canUseTool: async (toolName, input) => {
|
||||
if (toolName === 'Bash') {
|
||||
const deploymentPatterns = [
|
||||
'deploy',
|
||||
'kubectl apply',
|
||||
'terraform apply',
|
||||
'helm install',
|
||||
'docker push',
|
||||
'npm publish'
|
||||
];
|
||||
|
||||
for (const pattern of deploymentPatterns) {
|
||||
if (input.command.includes(pattern)) {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `🚀 DEPLOYMENT: ${input.command}\n\nProceed?`
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 5: Audit Logging
|
||||
|
||||
```typescript
|
||||
const auditLog: Array<{
|
||||
tool: string;
|
||||
input: any;
|
||||
decision: string;
|
||||
timestamp: Date;
|
||||
}> = [];
|
||||
|
||||
canUseTool: async (toolName, input) => {
|
||||
// Log everything
|
||||
console.log(`[${new Date().toISOString()}] ${toolName}`);
|
||||
|
||||
const decision = { behavior: "allow" as const };
|
||||
|
||||
// Store audit log
|
||||
auditLog.push({
|
||||
tool: toolName,
|
||||
input,
|
||||
decision: decision.behavior,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
// Could also send to external service
|
||||
// await logToDatadog(toolName, input, decision);
|
||||
|
||||
return decision;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Combining Modes with Custom Logic
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
permissionMode: "acceptEdits", // Auto-approve file edits
|
||||
canUseTool: async (toolName, input) => {
|
||||
// But still block dangerous bash
|
||||
if (toolName === 'Bash' && input.command.includes('rm -rf')) {
|
||||
return { behavior: "deny", message: "Blocked" };
|
||||
}
|
||||
|
||||
// Custom logic runs AFTER permission mode
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### ✅ Do
|
||||
|
||||
- Start with `"default"` mode
|
||||
- Use `canUseTool` for fine-grained control
|
||||
- Block known dangerous patterns
|
||||
- Require confirmation for sensitive ops
|
||||
- Log all tool usage for auditing
|
||||
- Test permission logic thoroughly
|
||||
- Use environment-based rules
|
||||
- Implement rate limiting if needed
|
||||
|
||||
### ❌ Don't
|
||||
|
||||
- Use `"bypassPermissions"` in production
|
||||
- Skip permission checks for "trusted" inputs
|
||||
- Allow arbitrary bash without filtering
|
||||
- Trust file paths without validation
|
||||
- Ignore audit logging
|
||||
- Assume AI won't make mistakes
|
||||
- Give blanket approvals
|
||||
|
||||
---
|
||||
|
||||
## Testing Permissions
|
||||
|
||||
```typescript
|
||||
async function testPermissions() {
|
||||
const tests = [
|
||||
{ tool: "Read", input: { file_path: "/etc/passwd" }, expectAllow: true },
|
||||
{ tool: "Bash", input: { command: "rm -rf /" }, expectDeny: true },
|
||||
{ tool: "Write", input: { file_path: ".env" }, expectAsk: true }
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
const decision = await canUseTool(test.tool, test.input);
|
||||
|
||||
if (test.expectAllow && decision.behavior !== 'allow') {
|
||||
console.error(`FAIL: Expected allow for ${test.tool}`);
|
||||
}
|
||||
if (test.expectDeny && decision.behavior !== 'deny') {
|
||||
console.error(`FAIL: Expected deny for ${test.tool}`);
|
||||
}
|
||||
if (test.expectAsk && decision.behavior !== 'ask') {
|
||||
console.error(`FAIL: Expected ask for ${test.tool}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Allow Read-Only
|
||||
|
||||
```typescript
|
||||
canUseTool: async (toolName, input) => {
|
||||
if (['Read', 'Grep', 'Glob'].includes(toolName)) {
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
return {
|
||||
behavior: "deny",
|
||||
message: "Read-only mode"
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Require Approval for All
|
||||
|
||||
```typescript
|
||||
canUseTool: async (toolName, input) => {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `Approve ${toolName}?`
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Block Bash Entirely
|
||||
|
||||
```typescript
|
||||
canUseTool: async (toolName, input) => {
|
||||
if (toolName === 'Bash') {
|
||||
return {
|
||||
behavior: "deny",
|
||||
message: "Bash execution disabled"
|
||||
};
|
||||
}
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
Handle permission errors gracefully:
|
||||
|
||||
```typescript
|
||||
for await (const message of response) {
|
||||
if (message.type === 'error') {
|
||||
if (message.error.type === 'permission_denied') {
|
||||
console.log('Permission denied for:', message.error.tool);
|
||||
// Continue with fallback or skip
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**For more details**: See SKILL.md
|
||||
**Template**: templates/permission-control.ts
|
||||
437
references/query-api-reference.md
Normal file
437
references/query-api-reference.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# Query API Reference
|
||||
|
||||
Complete reference for the `query()` function - the primary interface for Claude Agent SDK.
|
||||
|
||||
---
|
||||
|
||||
## Function Signature
|
||||
|
||||
```typescript
|
||||
function query(config: {
|
||||
prompt: string | AsyncIterable<SDKUserMessage>;
|
||||
options?: Options;
|
||||
}): AsyncGenerator<SDKMessage, void>;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Parameters
|
||||
|
||||
### prompt
|
||||
|
||||
**Type**: `string | AsyncIterable<SDKUserMessage>`
|
||||
**Required**: Yes
|
||||
|
||||
The task or question for the agent.
|
||||
|
||||
```typescript
|
||||
// Simple string prompt
|
||||
query({ prompt: "Analyze the codebase" })
|
||||
|
||||
// Streaming prompt (advanced)
|
||||
query({ prompt: streamingUserMessages() })
|
||||
```
|
||||
|
||||
### options
|
||||
|
||||
**Type**: `Options`
|
||||
**Required**: No
|
||||
|
||||
Configuration options for the query.
|
||||
|
||||
---
|
||||
|
||||
## Options Reference
|
||||
|
||||
### model
|
||||
|
||||
**Type**: `"sonnet" | "haiku" | "opus" | "claude-sonnet-4-5" | "inherit"`
|
||||
**Default**: `"sonnet"`
|
||||
|
||||
Model to use for the agent.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
model: "claude-sonnet-4-5" // Specific version
|
||||
model: "haiku" // Fast
|
||||
model: "opus" // Maximum capability
|
||||
model: "inherit" // Use parent model (subagents)
|
||||
}
|
||||
```
|
||||
|
||||
### workingDirectory
|
||||
|
||||
**Type**: `string`
|
||||
**Default**: Current working directory
|
||||
|
||||
Directory where agent operates.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
workingDirectory: "/path/to/project"
|
||||
}
|
||||
```
|
||||
|
||||
### systemPrompt
|
||||
|
||||
**Type**: `string | { type: 'preset', preset: 'claude_code' }`
|
||||
**Default**: None
|
||||
|
||||
System prompt that defines agent behavior.
|
||||
|
||||
```typescript
|
||||
// Custom prompt
|
||||
options: {
|
||||
systemPrompt: "You are a security-focused code reviewer."
|
||||
}
|
||||
|
||||
// Use CLAUDE.md from project
|
||||
options: {
|
||||
systemPrompt: { type: 'preset', preset: 'claude_code' },
|
||||
settingSources: ["project"] // Required to load CLAUDE.md
|
||||
}
|
||||
```
|
||||
|
||||
### allowedTools
|
||||
|
||||
**Type**: `string[]`
|
||||
**Default**: All tools
|
||||
|
||||
Whitelist of tools agent can use.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
allowedTools: ["Read", "Grep", "Glob"] // Read-only
|
||||
}
|
||||
```
|
||||
|
||||
### disallowedTools
|
||||
|
||||
**Type**: `string[]`
|
||||
**Default**: None
|
||||
|
||||
Blacklist of tools agent cannot use.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
disallowedTools: ["Bash", "Write", "Edit"] // No modifications
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: If both specified, `allowedTools` wins.
|
||||
|
||||
### permissionMode
|
||||
|
||||
**Type**: `"default" | "acceptEdits" | "bypassPermissions"`
|
||||
**Default**: `"default"`
|
||||
|
||||
Permission strategy.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
permissionMode: "default" // Standard checks
|
||||
permissionMode: "acceptEdits" // Auto-approve edits
|
||||
permissionMode: "bypassPermissions" // Skip all checks (caution!)
|
||||
}
|
||||
```
|
||||
|
||||
### canUseTool
|
||||
|
||||
**Type**: `(toolName: string, input: any) => Promise<PermissionDecision>`
|
||||
**Default**: None
|
||||
|
||||
Custom permission logic.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
canUseTool: async (toolName, input) => {
|
||||
if (toolName === 'Bash' && input.command.includes('rm -rf')) {
|
||||
return { behavior: "deny", message: "Blocked" };
|
||||
}
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**PermissionDecision**:
|
||||
- `{ behavior: "allow" }` - Allow execution
|
||||
- `{ behavior: "deny", message?: string }` - Block execution
|
||||
- `{ behavior: "ask", message?: string }` - Prompt user
|
||||
|
||||
### agents
|
||||
|
||||
**Type**: `Record<string, AgentDefinition>`
|
||||
**Default**: None
|
||||
|
||||
Subagent definitions.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
agents: {
|
||||
"test-runner": {
|
||||
description: "Run test suites",
|
||||
prompt: "You run tests. Fail if any test fails.",
|
||||
tools: ["Bash", "Read"],
|
||||
model: "haiku"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**AgentDefinition**:
|
||||
- `description` (string, required) - When to use agent
|
||||
- `prompt` (string, required) - Agent's system prompt
|
||||
- `tools` (string[], optional) - Allowed tools
|
||||
- `model` (string, optional) - Model override
|
||||
|
||||
### mcpServers
|
||||
|
||||
**Type**: `Record<string, McpServerConfig>`
|
||||
**Default**: None
|
||||
|
||||
MCP server configurations.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
mcpServers: {
|
||||
"custom-server": customServer, // In-process
|
||||
"filesystem": { // External (stdio)
|
||||
command: "npx",
|
||||
args: ["@modelcontextprotocol/server-filesystem"]
|
||||
},
|
||||
"remote": { // External (HTTP)
|
||||
url: "https://api.example.com/mcp",
|
||||
headers: { "Authorization": "Bearer token" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### settingSources
|
||||
|
||||
**Type**: `("user" | "project" | "local")[]`
|
||||
**Default**: `[]` (no filesystem settings)
|
||||
|
||||
Filesystem settings to load.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
settingSources: ["project"] // Project only (CI/CD)
|
||||
settingSources: ["user", "project", "local"] // All sources
|
||||
settingSources: [] // Isolated (no files)
|
||||
}
|
||||
```
|
||||
|
||||
**Files**:
|
||||
- `user` = `~/.claude/settings.json`
|
||||
- `project` = `.claude/settings.json`
|
||||
- `local` = `.claude/settings.local.json`
|
||||
|
||||
**Priority**: Programmatic > Local > Project > User
|
||||
|
||||
### resume
|
||||
|
||||
**Type**: `string`
|
||||
**Default**: None
|
||||
|
||||
Session ID to resume.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
resume: "session-id-here"
|
||||
}
|
||||
```
|
||||
|
||||
### forkSession
|
||||
|
||||
**Type**: `boolean`
|
||||
**Default**: `false`
|
||||
|
||||
Create new branch from resumed session.
|
||||
|
||||
```typescript
|
||||
options: {
|
||||
resume: "session-id-here",
|
||||
forkSession: true // New branch, original unchanged
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Return Value
|
||||
|
||||
**Type**: `AsyncGenerator<SDKMessage, void>`
|
||||
|
||||
Asynchronous generator yielding messages.
|
||||
|
||||
```typescript
|
||||
const response = query({ prompt: "..." });
|
||||
|
||||
for await (const message of response) {
|
||||
// Process message
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Message Types
|
||||
|
||||
See full details in SKILL.md. Summary:
|
||||
|
||||
| Type | When | Data |
|
||||
|------|------|------|
|
||||
| `system` | Session events | `session_id`, `model`, `tools` |
|
||||
| `assistant` | Agent response | `content` (string or blocks) |
|
||||
| `tool_call` | Tool requested | `tool_name`, `input` |
|
||||
| `tool_result` | Tool completed | `tool_name`, `result` |
|
||||
| `error` | Error occurred | `error` object |
|
||||
|
||||
---
|
||||
|
||||
## Usage Patterns
|
||||
|
||||
### Basic Query
|
||||
|
||||
```typescript
|
||||
const response = query({
|
||||
prompt: "Analyze code",
|
||||
options: { model: "sonnet" }
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### With Tools
|
||||
|
||||
```typescript
|
||||
const response = query({
|
||||
prompt: "Review and fix bugs",
|
||||
options: {
|
||||
model: "sonnet",
|
||||
allowedTools: ["Read", "Grep", "Edit"]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### With Subagents
|
||||
|
||||
```typescript
|
||||
const response = query({
|
||||
prompt: "Deploy to production",
|
||||
options: {
|
||||
agents: {
|
||||
"tester": { /* ... */ },
|
||||
"deployer": { /* ... */ }
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### With Custom Tools
|
||||
|
||||
```typescript
|
||||
const response = query({
|
||||
prompt: "Get weather and send notification",
|
||||
options: {
|
||||
mcpServers: { "weather": weatherServer },
|
||||
allowedTools: ["mcp__weather__get_weather"]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### With Session Management
|
||||
|
||||
```typescript
|
||||
// Start
|
||||
let session = await startSession("Build API");
|
||||
|
||||
// Resume
|
||||
await resumeSession(session, "Add auth");
|
||||
|
||||
// Fork
|
||||
await forkSession(session, "Try GraphQL instead");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### ✅ Do
|
||||
|
||||
- Set specific `allowedTools` for security
|
||||
- Use `canUseTool` for fine-grained control
|
||||
- Implement error handling for all queries
|
||||
- Capture `session_id` for resuming
|
||||
- Use `workingDirectory` for clarity
|
||||
- Test MCP servers independently
|
||||
- Monitor tool execution with `tool_call` messages
|
||||
|
||||
### ❌ Don't
|
||||
|
||||
- Use `bypassPermissions` in production (unless sandboxed)
|
||||
- Ignore error messages
|
||||
- Skip session ID capture if planning to resume
|
||||
- Allow unrestricted Bash without `canUseTool`
|
||||
- Load user settings in CI/CD
|
||||
- Use duplicate tool names
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const response = query({ prompt: "..." });
|
||||
for await (const message of response) {
|
||||
if (message.type === 'error') {
|
||||
console.error('Agent error:', message.error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code === 'CLI_NOT_FOUND') {
|
||||
console.error('Install Claude Code CLI');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TypeScript Types
|
||||
|
||||
```typescript
|
||||
type Options = {
|
||||
model?: "sonnet" | "haiku" | "opus" | string;
|
||||
workingDirectory?: string;
|
||||
systemPrompt?: string | { type: 'preset', preset: 'claude_code' };
|
||||
allowedTools?: string[];
|
||||
disallowedTools?: string[];
|
||||
permissionMode?: "default" | "acceptEdits" | "bypassPermissions";
|
||||
canUseTool?: (toolName: string, input: any) => Promise<PermissionDecision>;
|
||||
agents?: Record<string, AgentDefinition>;
|
||||
mcpServers?: Record<string, McpServerConfig>;
|
||||
settingSources?: ("user" | "project" | "local")[];
|
||||
resume?: string;
|
||||
forkSession?: boolean;
|
||||
};
|
||||
|
||||
type AgentDefinition = {
|
||||
description: string;
|
||||
prompt: string;
|
||||
tools?: string[];
|
||||
model?: "sonnet" | "opus" | "haiku" | "inherit";
|
||||
};
|
||||
|
||||
type PermissionDecision =
|
||||
| { behavior: "allow" }
|
||||
| { behavior: "deny"; message?: string }
|
||||
| { behavior: "ask"; message?: string };
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**For more details**: See SKILL.md
|
||||
**Official docs**: https://docs.claude.com/en/api/agent-sdk/typescript
|
||||
419
references/session-management.md
Normal file
419
references/session-management.md
Normal file
@@ -0,0 +1,419 @@
|
||||
# Session Management Guide
|
||||
|
||||
Complete guide to sessions, resuming, and forking in Claude Agent SDK.
|
||||
|
||||
---
|
||||
|
||||
## What Are Sessions?
|
||||
|
||||
Sessions enable:
|
||||
- **Persistent conversations** - Resume where you left off
|
||||
- **Context preservation** - Agent remembers everything
|
||||
- **Alternative paths** - Fork to explore different approaches
|
||||
|
||||
---
|
||||
|
||||
## Session Lifecycle
|
||||
|
||||
```
|
||||
Start → Capture Session ID → Resume → Resume → ... → End
|
||||
↓
|
||||
Fork (alternative path)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Starting a Session
|
||||
|
||||
Every `query()` call creates a session.
|
||||
|
||||
```typescript
|
||||
let sessionId: string | undefined;
|
||||
|
||||
const response = query({
|
||||
prompt: "Build a REST API",
|
||||
options: { model: "sonnet" }
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'system' && message.subtype === 'init') {
|
||||
sessionId = message.session_id;
|
||||
console.log(`Session started: ${sessionId}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**CRITICAL**: Capture `session_id` from `system` init message.
|
||||
|
||||
---
|
||||
|
||||
## Resuming a Session
|
||||
|
||||
Continue a previous conversation.
|
||||
|
||||
```typescript
|
||||
const resumed = query({
|
||||
prompt: "Now add authentication",
|
||||
options: {
|
||||
resume: sessionId, // Resume previous session
|
||||
model: "sonnet"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**What's preserved**:
|
||||
- All previous messages
|
||||
- Agent's understanding of context
|
||||
- Files created/modified
|
||||
- Decisions made
|
||||
|
||||
**What's NOT preserved**:
|
||||
- Environment variables
|
||||
- Tool availability (specify again)
|
||||
- Permission settings (specify again)
|
||||
|
||||
---
|
||||
|
||||
## Forking a Session
|
||||
|
||||
Create alternative path without modifying original.
|
||||
|
||||
```typescript
|
||||
const forked = query({
|
||||
prompt: "Actually, make it GraphQL instead",
|
||||
options: {
|
||||
resume: sessionId,
|
||||
forkSession: true, // Creates new branch
|
||||
model: "sonnet"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Result**:
|
||||
- New session created
|
||||
- Starts from same point as original
|
||||
- Original session unchanged
|
||||
- Can compare approaches
|
||||
|
||||
---
|
||||
|
||||
## Use Case Patterns
|
||||
|
||||
### Pattern 1: Sequential Development
|
||||
|
||||
Step-by-step feature building.
|
||||
|
||||
```typescript
|
||||
// Step 1: Initial implementation
|
||||
let session = await startSession("Create user authentication");
|
||||
|
||||
// Step 2: Add feature
|
||||
session = await resumeSession(session, "Add OAuth support");
|
||||
|
||||
// Step 3: Add tests
|
||||
session = await resumeSession(session, "Write integration tests");
|
||||
|
||||
// Step 4: Deploy
|
||||
session = await resumeSession(session, "Deploy to production");
|
||||
```
|
||||
|
||||
### Pattern 2: Exploration & Decision
|
||||
|
||||
Try multiple approaches, choose best.
|
||||
|
||||
```typescript
|
||||
// Start main conversation
|
||||
let mainSession = await startSession("Design payment system");
|
||||
|
||||
// Explore option A
|
||||
let optionA = await forkSession(mainSession, "Use Stripe");
|
||||
|
||||
// Explore option B
|
||||
let optionB = await forkSession(mainSession, "Use PayPal");
|
||||
|
||||
// Explore option C
|
||||
let optionC = await forkSession(mainSession, "Use Square");
|
||||
|
||||
// Choose winner
|
||||
let chosenSession = optionA; // Decision made
|
||||
await resumeSession(chosenSession, "Implement chosen approach");
|
||||
```
|
||||
|
||||
### Pattern 3: Multi-User Collaboration
|
||||
|
||||
Multiple developers, independent work.
|
||||
|
||||
```typescript
|
||||
// Developer A starts work
|
||||
let sessionA = await startSession("Implement user profile page");
|
||||
|
||||
// Developer B forks for different feature
|
||||
let sessionB = await forkSession(sessionA, "Add avatar upload");
|
||||
|
||||
// Developer C forks for another feature
|
||||
let sessionC = await forkSession(sessionA, "Implement search");
|
||||
|
||||
// All can work independently
|
||||
```
|
||||
|
||||
### Pattern 4: Error Recovery
|
||||
|
||||
Backup and restore points.
|
||||
|
||||
```typescript
|
||||
// Save checkpoint before risky operation
|
||||
let checkpoint = sessionId;
|
||||
|
||||
try {
|
||||
await resumeSession(checkpoint, "Refactor entire auth system");
|
||||
} catch (error) {
|
||||
console.log("Refactor failed, restoring from checkpoint");
|
||||
await forkSession(checkpoint, "Try safer incremental refactor");
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 5: A/B Testing
|
||||
|
||||
Test different implementations.
|
||||
|
||||
```typescript
|
||||
let baseline = await startSession("Implement feature X");
|
||||
|
||||
// Approach A
|
||||
let approachA = await forkSession(baseline, "Use algorithm A");
|
||||
const metricsA = await measurePerformance(approachA);
|
||||
|
||||
// Approach B
|
||||
let approachB = await forkSession(baseline, "Use algorithm B");
|
||||
const metricsB = await measurePerformance(approachB);
|
||||
|
||||
// Compare and choose
|
||||
const winner = metricsA.better(metricsB) ? approachA : approachB;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Session Best Practices
|
||||
|
||||
### ✅ Do
|
||||
|
||||
- Always capture `session_id` from init message
|
||||
- Store session IDs for later use
|
||||
- Use descriptive prompts when resuming
|
||||
- Fork for alternative approaches
|
||||
- Test resuming before deploying
|
||||
- Consider session lifetime limits
|
||||
|
||||
### ❌ Don't
|
||||
|
||||
- Forget to capture session ID
|
||||
- Assume sessions last forever
|
||||
- Resume with completely unrelated prompts
|
||||
- Fork excessively (creates many branches)
|
||||
- Rely on sessions for critical state
|
||||
- Skip testing resume functionality
|
||||
|
||||
---
|
||||
|
||||
## Helper Functions
|
||||
|
||||
```typescript
|
||||
async function startSession(prompt: string): Promise<string> {
|
||||
let sessionId: string | undefined;
|
||||
|
||||
const response = query({ prompt, options: { model: "sonnet" } });
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'system' && message.subtype === 'init') {
|
||||
sessionId = message.session_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sessionId) throw new Error('Failed to start session');
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
async function resumeSession(
|
||||
sessionId: string,
|
||||
prompt: string
|
||||
): Promise<void> {
|
||||
const response = query({
|
||||
prompt,
|
||||
options: { resume: sessionId, model: "sonnet" }
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function forkSession(
|
||||
sessionId: string,
|
||||
prompt: string
|
||||
): Promise<string> {
|
||||
let newSessionId: string | undefined;
|
||||
|
||||
const response = query({
|
||||
prompt,
|
||||
options: {
|
||||
resume: sessionId,
|
||||
forkSession: true,
|
||||
model: "sonnet"
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'system' && message.subtype === 'init') {
|
||||
newSessionId = message.session_id;
|
||||
} else if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
|
||||
if (!newSessionId) throw new Error('Failed to fork session');
|
||||
return newSessionId;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Session Storage
|
||||
|
||||
Store sessions for later use:
|
||||
|
||||
```typescript
|
||||
// In-memory storage
|
||||
const sessions = new Map<string, { id: string; created: Date }>();
|
||||
|
||||
async function saveSession(prompt: string) {
|
||||
const id = await startSession(prompt);
|
||||
sessions.set(id, { id, created: new Date() });
|
||||
return id;
|
||||
}
|
||||
|
||||
function getSession(id: string) {
|
||||
return sessions.get(id);
|
||||
}
|
||||
|
||||
// Database storage
|
||||
async function saveSessionToDb(sessionId: string, metadata: any) {
|
||||
await db.insert('sessions', {
|
||||
id: sessionId,
|
||||
created_at: new Date(),
|
||||
metadata
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Session Limits
|
||||
|
||||
### Context Window
|
||||
|
||||
Sessions have context window limits (200k tokens for Sonnet).
|
||||
|
||||
**Strategies**:
|
||||
- SDK auto-compacts context
|
||||
- Fork to start fresh from a point
|
||||
- Summarize and start new session
|
||||
|
||||
### Lifetime
|
||||
|
||||
Sessions may expire after inactivity.
|
||||
|
||||
**Strategies**:
|
||||
- Don't rely on sessions lasting indefinitely
|
||||
- Store important state separately
|
||||
- Test resume functionality
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Session Not Found
|
||||
|
||||
**Problem**: `"Invalid session ID"`
|
||||
|
||||
**Causes**:
|
||||
- Session expired
|
||||
- Invalid session ID
|
||||
- Session from different CLI instance
|
||||
|
||||
**Solution**: Start new session
|
||||
|
||||
### Context Preserved Incorrectly
|
||||
|
||||
**Problem**: Agent doesn't remember previous work
|
||||
|
||||
**Causes**:
|
||||
- Different settings/tools specified
|
||||
- Context window exceeded
|
||||
- Fork instead of resume
|
||||
|
||||
**Solution**: Verify using `resume` not `forkSession`
|
||||
|
||||
### Too Many Forks
|
||||
|
||||
**Problem**: Hard to track branches
|
||||
|
||||
**Solution**: Limit forking, clean up unused branches
|
||||
|
||||
---
|
||||
|
||||
## Complete Example
|
||||
|
||||
```typescript
|
||||
class SessionManager {
|
||||
private sessions = new Map<string, string>();
|
||||
|
||||
async start(name: string, prompt: string): Promise<string> {
|
||||
const id = await startSession(prompt);
|
||||
this.sessions.set(name, id);
|
||||
console.log(`✨ Started: ${name}`);
|
||||
return id;
|
||||
}
|
||||
|
||||
async resume(name: string, prompt: string): Promise<void> {
|
||||
const id = this.sessions.get(name);
|
||||
if (!id) throw new Error(`Session ${name} not found`);
|
||||
console.log(`↪️ Resuming: ${name}`);
|
||||
await resumeSession(id, prompt);
|
||||
}
|
||||
|
||||
async fork(
|
||||
fromName: string,
|
||||
newName: string,
|
||||
prompt: string
|
||||
): Promise<string> {
|
||||
const fromId = this.sessions.get(fromName);
|
||||
if (!fromId) throw new Error(`Session ${fromName} not found`);
|
||||
console.log(`🔀 Forking: ${fromName} → ${newName}`);
|
||||
const newId = await forkSession(fromId, prompt);
|
||||
this.sessions.set(newName, newId);
|
||||
return newId;
|
||||
}
|
||||
|
||||
list(): string[] {
|
||||
return Array.from(this.sessions.keys());
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
const manager = new SessionManager();
|
||||
|
||||
await manager.start("main", "Build a web app");
|
||||
await manager.resume("main", "Add authentication");
|
||||
await manager.fork("main", "option-a", "Use JWT tokens");
|
||||
await manager.fork("main", "option-b", "Use sessions");
|
||||
|
||||
console.log("Sessions:", manager.list());
|
||||
// ["main", "option-a", "option-b"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**For more details**: See SKILL.md
|
||||
**Template**: templates/session-management.ts
|
||||
464
references/subagents-patterns.md
Normal file
464
references/subagents-patterns.md
Normal file
@@ -0,0 +1,464 @@
|
||||
# Subagents Patterns
|
||||
|
||||
Guide to designing and orchestrating specialized subagents.
|
||||
|
||||
---
|
||||
|
||||
## What Are Subagents?
|
||||
|
||||
Specialized agents with:
|
||||
- **Specific expertise** - Focused domain knowledge
|
||||
- **Custom tools** - Only tools they need
|
||||
- **Different models** - Match capability to task cost
|
||||
- **Dedicated prompts** - Tailored instructions
|
||||
|
||||
---
|
||||
|
||||
## When to Use Subagents
|
||||
|
||||
### ✅ Use Subagents When:
|
||||
|
||||
- Task requires different expertise areas
|
||||
- Some subtasks need different models (cost optimization)
|
||||
- Tool access should be restricted per role
|
||||
- Clear separation of concerns needed
|
||||
- Multiple steps with specialized knowledge
|
||||
|
||||
### ❌ Don't Use Subagents When:
|
||||
|
||||
- Single straightforward task
|
||||
- All work can be done by one agent
|
||||
- Overhead of orchestration > benefit
|
||||
- Tools/permissions don't vary
|
||||
|
||||
---
|
||||
|
||||
## AgentDefinition Structure
|
||||
|
||||
```typescript
|
||||
type AgentDefinition = {
|
||||
description: string; // When to use this agent
|
||||
prompt: string; // System prompt for agent
|
||||
tools?: string[]; // Allowed tools (optional)
|
||||
model?: 'sonnet' | 'opus' | 'haiku' | 'inherit'; // Model (optional)
|
||||
}
|
||||
```
|
||||
|
||||
### Field Guidelines
|
||||
|
||||
**description**:
|
||||
- Clear, action-oriented
|
||||
- When to invoke this agent
|
||||
- 1-2 sentences
|
||||
- Examples: "Run test suites", "Deploy to production"
|
||||
|
||||
**prompt**:
|
||||
- Agent's role and behavior
|
||||
- Instructions and constraints
|
||||
- What to do and what not to do
|
||||
- Can be detailed (100-500 tokens)
|
||||
|
||||
**tools**:
|
||||
- If omitted, inherits all tools from main agent
|
||||
- Use to restrict agent to specific tools
|
||||
- Examples: `["Read", "Grep"]` for read-only
|
||||
|
||||
**model**:
|
||||
- `"haiku"` - Fast, cost-effective ($0.25/$1.25 per MTok)
|
||||
- `"sonnet"` - Balanced ($3/$15 per MTok)
|
||||
- `"opus"` - Maximum capability ($15/$75 per MTok)
|
||||
- `"inherit"` - Use main agent's model
|
||||
- If omitted, inherits main agent's model
|
||||
|
||||
---
|
||||
|
||||
## Design Patterns
|
||||
|
||||
### Pattern 1: DevOps Pipeline
|
||||
|
||||
```typescript
|
||||
agents: {
|
||||
"test-runner": {
|
||||
description: "Run automated test suites and verify coverage",
|
||||
prompt: `You run tests.
|
||||
|
||||
Execute:
|
||||
- Unit tests
|
||||
- Integration tests
|
||||
- End-to-end tests
|
||||
|
||||
FAIL if any tests fail. Report clear errors.`,
|
||||
tools: ["Bash", "Read"],
|
||||
model: "haiku" // Fast, cost-effective
|
||||
},
|
||||
|
||||
"security-checker": {
|
||||
description: "Security audits and vulnerability scanning",
|
||||
prompt: `You check security.
|
||||
|
||||
Scan for:
|
||||
- Exposed secrets
|
||||
- Dependency vulnerabilities
|
||||
- Permission issues
|
||||
- OWASP compliance
|
||||
|
||||
Block deployment if critical issues found.`,
|
||||
tools: ["Read", "Grep", "Bash"],
|
||||
model: "sonnet" // Balance for analysis
|
||||
},
|
||||
|
||||
"deployer": {
|
||||
description: "Application deployment and rollbacks",
|
||||
prompt: `You deploy applications.
|
||||
|
||||
Process:
|
||||
1. Deploy to staging
|
||||
2. Verify health checks
|
||||
3. Deploy to production
|
||||
4. Create rollback plan
|
||||
|
||||
ALWAYS have rollback ready.`,
|
||||
tools: ["Bash", "Read"],
|
||||
model: "sonnet" // Reliable for critical ops
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 2: Code Review Workflow
|
||||
|
||||
```typescript
|
||||
agents: {
|
||||
"syntax-checker": {
|
||||
description: "Check syntax, formatting, and linting",
|
||||
prompt: `You check syntax and formatting.
|
||||
|
||||
Run:
|
||||
- ESLint
|
||||
- Prettier
|
||||
- TypeScript type checking
|
||||
|
||||
Report all violations clearly.`,
|
||||
tools: ["Bash", "Read"],
|
||||
model: "haiku" // Fast checks
|
||||
},
|
||||
|
||||
"logic-reviewer": {
|
||||
description: "Review logic, algorithms, and architecture",
|
||||
prompt: `You review code logic.
|
||||
|
||||
Check:
|
||||
- Algorithmic correctness
|
||||
- Edge cases
|
||||
- Performance issues
|
||||
- Design patterns
|
||||
|
||||
Suggest improvements.`,
|
||||
tools: ["Read", "Grep"],
|
||||
model: "sonnet" // Complex analysis
|
||||
},
|
||||
|
||||
"security-reviewer": {
|
||||
description: "Review for security vulnerabilities",
|
||||
prompt: `You review security.
|
||||
|
||||
Check:
|
||||
- SQL injection
|
||||
- XSS vulnerabilities
|
||||
- Authentication bypass
|
||||
- Data exposure
|
||||
|
||||
FAIL on critical issues.`,
|
||||
tools: ["Read", "Grep"],
|
||||
model: "sonnet" // Security expertise
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 3: Content Generation
|
||||
|
||||
```typescript
|
||||
agents: {
|
||||
"researcher": {
|
||||
description: "Research topics and gather information",
|
||||
prompt: `You research topics.
|
||||
|
||||
Gather:
|
||||
- Relevant information
|
||||
- Latest trends
|
||||
- Best practices
|
||||
- Examples
|
||||
|
||||
Provide comprehensive research.`,
|
||||
tools: ["WebSearch", "WebFetch", "Read"],
|
||||
model: "haiku" // Fast research
|
||||
},
|
||||
|
||||
"writer": {
|
||||
description: "Write content based on research",
|
||||
prompt: `You write content.
|
||||
|
||||
Write:
|
||||
- Clear, engaging prose
|
||||
- Well-structured
|
||||
- Audience-appropriate
|
||||
- Fact-based
|
||||
|
||||
Use research provided.`,
|
||||
tools: ["Write", "Read"],
|
||||
model: "sonnet" // Quality writing
|
||||
},
|
||||
|
||||
"editor": {
|
||||
description: "Edit and polish content",
|
||||
prompt: `You edit content.
|
||||
|
||||
Check:
|
||||
- Grammar and spelling
|
||||
- Clarity and flow
|
||||
- Consistency
|
||||
- Formatting
|
||||
|
||||
Polish to perfection.`,
|
||||
tools: ["Read", "Edit"],
|
||||
model: "sonnet" // Quality editing
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 4: Incident Response
|
||||
|
||||
```typescript
|
||||
agents: {
|
||||
"incident-detector": {
|
||||
description: "Detect and triage incidents",
|
||||
prompt: `You detect incidents.
|
||||
|
||||
Monitor:
|
||||
- Error rates
|
||||
- Response times
|
||||
- System health
|
||||
- Alerts
|
||||
|
||||
Assess severity and impact.`,
|
||||
tools: ["Bash", "Read"],
|
||||
model: "haiku" // Fast detection
|
||||
},
|
||||
|
||||
"root-cause-analyzer": {
|
||||
description: "Analyze root cause of incidents",
|
||||
prompt: `You analyze root causes.
|
||||
|
||||
Investigate:
|
||||
- Logs
|
||||
- Metrics
|
||||
- Recent changes
|
||||
- Dependencies
|
||||
|
||||
Identify exact cause.`,
|
||||
tools: ["Bash", "Read", "Grep"],
|
||||
model: "sonnet" // Deep analysis
|
||||
},
|
||||
|
||||
"fix-implementer": {
|
||||
description: "Implement fixes for incidents",
|
||||
prompt: `You implement fixes.
|
||||
|
||||
Fix:
|
||||
- Apply patches
|
||||
- Rollback changes
|
||||
- Update config
|
||||
- Deploy hotfixes
|
||||
|
||||
Verify fix resolves issue.`,
|
||||
tools: ["Read", "Edit", "Bash"],
|
||||
model: "sonnet" // Careful fixes
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Orchestration Strategies
|
||||
|
||||
### Sequential Execution
|
||||
|
||||
Main agent coordinates agents in order:
|
||||
|
||||
```
|
||||
test-runner → security-checker → deployer
|
||||
```
|
||||
|
||||
**Use when**: Steps must happen in order
|
||||
|
||||
### Parallel Execution
|
||||
|
||||
Main agent delegates to multiple agents at once:
|
||||
|
||||
```
|
||||
test-runner
|
||||
security-checker } in parallel
|
||||
code-reviewer
|
||||
```
|
||||
|
||||
**Use when**: Steps are independent
|
||||
|
||||
### Conditional Execution
|
||||
|
||||
Main agent decides which agents to use based on context:
|
||||
|
||||
```
|
||||
if (tests fail) → test-fixer
|
||||
if (security issue) → security-fixer
|
||||
if (all pass) → deployer
|
||||
```
|
||||
|
||||
**Use when**: Different paths needed
|
||||
|
||||
---
|
||||
|
||||
## Model Selection Strategy
|
||||
|
||||
### Cost vs Capability
|
||||
|
||||
| Model | Cost (in/out) | Speed | Use For |
|
||||
|-------|---------------|-------|---------|
|
||||
| Haiku | $0.25/$1.25 | Fastest | Monitoring, simple checks |
|
||||
| Sonnet | $3/$15 | Medium | Code review, analysis |
|
||||
| Opus | $15/$75 | Slowest | Complex reasoning |
|
||||
|
||||
### Optimization Tips
|
||||
|
||||
```typescript
|
||||
// ✅ Good: Match model to task
|
||||
agents: {
|
||||
"monitor": { model: "haiku" }, // Simple checks
|
||||
"reviewer": { model: "sonnet" }, // Analysis
|
||||
"architect": { model: "opus" } // Complex design
|
||||
}
|
||||
|
||||
// ❌ Bad: Opus for everything
|
||||
agents: {
|
||||
"monitor": { model: "opus" }, // Wasteful
|
||||
"reviewer": { model: "opus" }, // Wasteful
|
||||
"simple-task": { model: "opus" } // Wasteful
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tool Restriction Patterns
|
||||
|
||||
### Read-Only Agent
|
||||
|
||||
```typescript
|
||||
{
|
||||
description: "Analyze code without modifications",
|
||||
tools: ["Read", "Grep", "Glob"],
|
||||
model: "haiku"
|
||||
}
|
||||
```
|
||||
|
||||
### Write-Only Agent
|
||||
|
||||
```typescript
|
||||
{
|
||||
description: "Generate new files",
|
||||
tools: ["Write"],
|
||||
model: "sonnet"
|
||||
}
|
||||
```
|
||||
|
||||
### Modify Agent
|
||||
|
||||
```typescript
|
||||
{
|
||||
description: "Edit existing files",
|
||||
tools: ["Read", "Edit"],
|
||||
model: "sonnet"
|
||||
}
|
||||
```
|
||||
|
||||
### Full Access Agent
|
||||
|
||||
```typescript
|
||||
{
|
||||
description: "Complete control",
|
||||
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"],
|
||||
model: "sonnet"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Communication Between Agents
|
||||
|
||||
Agents communicate through the main agent:
|
||||
|
||||
```
|
||||
Main Agent: "Run tests"
|
||||
↓
|
||||
Test Runner: "Tests passed"
|
||||
↓
|
||||
Main Agent: "Deploy to staging"
|
||||
↓
|
||||
Deployer: "Deployed to staging"
|
||||
↓
|
||||
Main Agent: "Verify health"
|
||||
↓
|
||||
Monitor: "Health checks passing"
|
||||
↓
|
||||
Main Agent: "Deploy to production"
|
||||
```
|
||||
|
||||
**No direct agent-to-agent communication**.
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### ✅ Do
|
||||
|
||||
- Give agents clear, specific roles
|
||||
- Match model to task complexity
|
||||
- Restrict tools per agent's needs
|
||||
- Write detailed prompts with constraints
|
||||
- Use descriptive agent names
|
||||
- Test agents independently
|
||||
- Monitor which agents are invoked
|
||||
|
||||
### ❌ Don't
|
||||
|
||||
- Create overlapping responsibilities
|
||||
- Use Opus for simple tasks
|
||||
- Give all agents all tools
|
||||
- Write vague prompts
|
||||
- Use generic names like "agent1"
|
||||
- Skip testing in isolation
|
||||
- Assume agents will coordinate perfectly
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Agent Not Invoked
|
||||
|
||||
**Problem**: Main agent doesn't call subagent
|
||||
|
||||
**Solution**: Improve `description` to be more specific
|
||||
|
||||
### Wrong Agent Invoked
|
||||
|
||||
**Problem**: Main agent calls incorrect subagent
|
||||
|
||||
**Solution**: Make descriptions more distinct
|
||||
|
||||
### Agent Lacks Capability
|
||||
|
||||
**Problem**: Agent can't complete task
|
||||
|
||||
**Solution**: Add required tools or upgrade model
|
||||
|
||||
---
|
||||
|
||||
**For more details**: See SKILL.md
|
||||
**Examples**: templates/subagents-orchestration.ts
|
||||
503
references/top-errors.md
Normal file
503
references/top-errors.md
Normal file
@@ -0,0 +1,503 @@
|
||||
# Top Errors & Solutions
|
||||
|
||||
Complete reference for common Claude Agent SDK errors and how to fix them.
|
||||
|
||||
---
|
||||
|
||||
## Error #1: CLI Not Found
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Claude Code CLI not installed"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
The SDK requires Claude Code CLI to be installed globally, but it's not found in PATH.
|
||||
|
||||
### Solution
|
||||
```bash
|
||||
npm install -g @anthropic-ai/claude-code
|
||||
```
|
||||
|
||||
Verify installation:
|
||||
```bash
|
||||
which claude-code
|
||||
# Should output: /usr/local/bin/claude-code or similar
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Install CLI before using SDK
|
||||
- Add to project setup documentation
|
||||
- Check CLI availability in CI/CD
|
||||
|
||||
---
|
||||
|
||||
## Error #2: Authentication Failed
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Invalid API key"
|
||||
"Authentication failed"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- ANTHROPIC_API_KEY environment variable not set
|
||||
- API key is invalid or expired
|
||||
- API key has wrong format
|
||||
|
||||
### Solution
|
||||
```bash
|
||||
# Set API key
|
||||
export ANTHROPIC_API_KEY="sk-ant-..."
|
||||
|
||||
# Verify it's set
|
||||
echo $ANTHROPIC_API_KEY
|
||||
```
|
||||
|
||||
Get API key:
|
||||
1. Visit https://console.anthropic.com/
|
||||
2. Navigate to API Keys section
|
||||
3. Create new key
|
||||
4. Copy and save securely
|
||||
|
||||
### Prevention
|
||||
- Use environment variables (never hardcode)
|
||||
- Check key before running
|
||||
- Add to .env.example template
|
||||
- Document setup process
|
||||
|
||||
---
|
||||
|
||||
## Error #3: Permission Denied
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Tool use blocked"
|
||||
"Permission denied for tool: Bash"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- Tool not in `allowedTools` array
|
||||
- `permissionMode` is too restrictive
|
||||
- Custom `canUseTool` callback denied execution
|
||||
|
||||
### Solution
|
||||
```typescript
|
||||
// Add tool to allowedTools
|
||||
options: {
|
||||
allowedTools: ["Read", "Write", "Edit", "Bash"] // Add needed tools
|
||||
}
|
||||
|
||||
// Or use less restrictive permission mode
|
||||
options: {
|
||||
permissionMode: "acceptEdits" // Auto-approve edits
|
||||
}
|
||||
|
||||
// Or check canUseTool logic
|
||||
options: {
|
||||
canUseTool: async (toolName, input) => {
|
||||
console.log("Tool requested:", toolName); // Debug
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Set appropriate `allowedTools` from start
|
||||
- Test permission logic thoroughly
|
||||
- Use `permissionMode: "bypassPermissions"` in CI/CD
|
||||
|
||||
---
|
||||
|
||||
## Error #4: Context Length Exceeded
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Prompt too long"
|
||||
"Context length exceeded"
|
||||
"Too many tokens"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- Input prompt exceeds model's context window (200k tokens)
|
||||
- Long conversation without pruning
|
||||
- Large files in context
|
||||
|
||||
### Solution
|
||||
SDK auto-compacts context, but you can:
|
||||
|
||||
```typescript
|
||||
// Fork session to start fresh from a point
|
||||
const forked = query({
|
||||
prompt: "Continue with fresh context",
|
||||
options: {
|
||||
resume: sessionId,
|
||||
forkSession: true // Start fresh
|
||||
}
|
||||
});
|
||||
|
||||
// Or reduce context
|
||||
options: {
|
||||
allowedTools: ["Read", "Grep"], // Limit tools
|
||||
systemPrompt: "Keep responses concise."
|
||||
}
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Use session forking for long tasks
|
||||
- Keep prompts focused
|
||||
- Don't load unnecessary files
|
||||
- Monitor context usage
|
||||
|
||||
---
|
||||
|
||||
## Error #5: Tool Execution Timeout
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Tool did not respond"
|
||||
"Tool execution timeout"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- Tool takes too long (>5 minutes default)
|
||||
- Infinite loop in tool implementation
|
||||
- Network timeout for external tools
|
||||
|
||||
### Solution
|
||||
|
||||
For custom tools:
|
||||
```typescript
|
||||
tool("long_task", "Description", schema, async (args) => {
|
||||
// Add timeout
|
||||
const timeout = 60000; // 1 minute
|
||||
const promise = performLongTask(args);
|
||||
const result = await Promise.race([
|
||||
promise,
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Timeout')), timeout)
|
||||
)
|
||||
]);
|
||||
return { content: [{ type: "text", text: result }] };
|
||||
})
|
||||
```
|
||||
|
||||
For bash commands:
|
||||
```typescript
|
||||
// Add timeout to bash command
|
||||
command: "timeout 60s long-running-command"
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Set reasonable timeouts
|
||||
- Optimize tool implementations
|
||||
- Use background jobs for long tasks
|
||||
- Test tools independently
|
||||
|
||||
---
|
||||
|
||||
## Error #6: Session Not Found
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Invalid session ID"
|
||||
"Session not found"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- Session ID is incorrect
|
||||
- Session expired (old)
|
||||
- Session from different CLI instance
|
||||
|
||||
### Solution
|
||||
```typescript
|
||||
// Ensure session ID captured correctly
|
||||
let sessionId: string | undefined;
|
||||
for await (const message of response) {
|
||||
if (message.type === 'system' && message.subtype === 'init') {
|
||||
sessionId = message.session_id; // Capture here
|
||||
console.log("Session:", sessionId); // Verify
|
||||
}
|
||||
}
|
||||
|
||||
// Use correct session ID
|
||||
query({
|
||||
prompt: "...",
|
||||
options: { resume: sessionId } // Must match exactly
|
||||
});
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Always capture session_id from system init
|
||||
- Store session IDs reliably
|
||||
- Don't rely on sessions lasting indefinitely
|
||||
- Handle session errors gracefully
|
||||
|
||||
---
|
||||
|
||||
## Error #7: MCP Server Connection Failed
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Server connection error"
|
||||
"MCP server not responding"
|
||||
"Failed to connect to MCP server"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- Server command/URL incorrect
|
||||
- Server crashed or not running
|
||||
- Network issues (HTTP/SSE servers)
|
||||
- Missing dependencies
|
||||
|
||||
### Solution
|
||||
|
||||
For stdio servers:
|
||||
```typescript
|
||||
// Verify command works independently
|
||||
// Test: npx @modelcontextprotocol/server-filesystem
|
||||
options: {
|
||||
mcpServers: {
|
||||
"filesystem": {
|
||||
command: "npx", // Verify npx is available
|
||||
args: ["@modelcontextprotocol/server-filesystem"],
|
||||
env: {
|
||||
ALLOWED_PATHS: "/path" // Verify path exists
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For HTTP servers:
|
||||
```typescript
|
||||
// Test URL separately
|
||||
const testResponse = await fetch("https://api.example.com/mcp");
|
||||
console.log(testResponse.status); // Should be 200
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Test MCP servers independently before integration
|
||||
- Verify command/URL works
|
||||
- Add error handling for server failures
|
||||
- Use health checks
|
||||
|
||||
---
|
||||
|
||||
## Error #8: Subagent Definition Error
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Invalid AgentDefinition"
|
||||
"Agent configuration error"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- Missing required fields (`description` or `prompt`)
|
||||
- Invalid `model` value
|
||||
- Invalid `tools` array
|
||||
|
||||
### Solution
|
||||
```typescript
|
||||
agents: {
|
||||
"my-agent": {
|
||||
description: "Clear description of when to use", // Required
|
||||
prompt: "Detailed system prompt", // Required
|
||||
tools: ["Read", "Write"], // Optional
|
||||
model: "sonnet" // Optional
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Always include `description` and `prompt`
|
||||
- Use TypeScript types
|
||||
- Test agent definitions
|
||||
- Follow examples in templates
|
||||
|
||||
---
|
||||
|
||||
## Error #9: Settings File Not Found
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Cannot read settings"
|
||||
"Settings file not found"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- `settingSources` includes non-existent file
|
||||
- File path incorrect
|
||||
- File permissions deny read
|
||||
|
||||
### Solution
|
||||
```typescript
|
||||
// Check file exists before loading
|
||||
import fs from 'fs';
|
||||
|
||||
const projectSettingsPath = '.claude/settings.json';
|
||||
const settingSources = [];
|
||||
|
||||
if (fs.existsSync(projectSettingsPath)) {
|
||||
settingSources.push('project');
|
||||
}
|
||||
|
||||
options: {
|
||||
settingSources // Only existing files
|
||||
}
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Check file exists before including in sources
|
||||
- Use empty array for isolated execution
|
||||
- Handle missing files gracefully
|
||||
|
||||
---
|
||||
|
||||
## Error #10: Tool Name Collision
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Duplicate tool name"
|
||||
"Tool already defined"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- Two MCP servers define same tool name
|
||||
- Tool name conflicts with built-in tool
|
||||
|
||||
### Solution
|
||||
```typescript
|
||||
// Use unique tool names
|
||||
const server1 = createSdkMcpServer({
|
||||
name: "service-a",
|
||||
tools: [
|
||||
tool("service_a_process", ...) // Prefix with server name
|
||||
]
|
||||
});
|
||||
|
||||
const server2 = createSdkMcpServer({
|
||||
name: "service-b",
|
||||
tools: [
|
||||
tool("service_b_process", ...) // Different name
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Use unique tool names
|
||||
- Prefix tools with server name
|
||||
- Test integration before deployment
|
||||
|
||||
---
|
||||
|
||||
## Error #11: Zod Schema Validation Error
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Invalid tool input"
|
||||
"Schema validation failed"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- Agent provided data that doesn't match Zod schema
|
||||
- Schema too restrictive
|
||||
- Missing `.describe()` on fields
|
||||
|
||||
### Solution
|
||||
```typescript
|
||||
// Add descriptive schemas
|
||||
{
|
||||
email: z.string().email().describe("User email address"),
|
||||
age: z.number().int().min(0).max(120).describe("Age in years"),
|
||||
role: z.enum(["admin", "user"]).describe("User role")
|
||||
}
|
||||
|
||||
// Make fields optional if appropriate
|
||||
{
|
||||
email: z.string().email(),
|
||||
phoneOptional: z.string().optional() // Not required
|
||||
}
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Use `.describe()` on all fields
|
||||
- Add validation constraints
|
||||
- Test with various inputs
|
||||
- Make optional fields explicit
|
||||
|
||||
---
|
||||
|
||||
## Error #12: Filesystem Permission Denied
|
||||
|
||||
### Error Message
|
||||
```
|
||||
"Access denied"
|
||||
"Cannot access path"
|
||||
"EACCES: permission denied"
|
||||
```
|
||||
|
||||
### Why It Happens
|
||||
- Path outside `workingDirectory`
|
||||
- No read/write permissions
|
||||
- Protected system directory
|
||||
|
||||
### Solution
|
||||
```typescript
|
||||
// Set correct working directory
|
||||
options: {
|
||||
workingDirectory: "/path/to/accessible/dir"
|
||||
}
|
||||
|
||||
// Or fix permissions
|
||||
// chmod +r file.txt (add read)
|
||||
// chmod +w file.txt (add write)
|
||||
```
|
||||
|
||||
### Prevention
|
||||
- Set appropriate `workingDirectory`
|
||||
- Verify file permissions
|
||||
- Don't access system directories
|
||||
- Use dedicated project directories
|
||||
|
||||
---
|
||||
|
||||
## General Error Handling Pattern
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const response = query({ prompt: "...", options: { ... } });
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'error') {
|
||||
console.error('Agent error:', message.error);
|
||||
// Handle non-fatal errors
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fatal error:', error);
|
||||
|
||||
// Handle specific errors
|
||||
switch (error.code) {
|
||||
case 'CLI_NOT_FOUND':
|
||||
console.error('Install: npm install -g @anthropic-ai/claude-code');
|
||||
break;
|
||||
case 'AUTHENTICATION_FAILED':
|
||||
console.error('Check ANTHROPIC_API_KEY');
|
||||
break;
|
||||
case 'RATE_LIMIT_EXCEEDED':
|
||||
console.error('Rate limited. Retry with backoff.');
|
||||
break;
|
||||
case 'CONTEXT_LENGTH_EXCEEDED':
|
||||
console.error('Reduce context or fork session');
|
||||
break;
|
||||
default:
|
||||
console.error('Unexpected error:', error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**For more details**: See SKILL.md
|
||||
**Template**: templates/error-handling.ts
|
||||
55
scripts/check-versions.sh
Executable file
55
scripts/check-versions.sh
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check package versions for Claude Agent SDK skill
|
||||
# Usage: ./scripts/check-versions.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔍 Checking Claude Agent SDK package versions..."
|
||||
echo ""
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Check if npm is available
|
||||
if ! command -v npm &> /dev/null; then
|
||||
echo -e "${RED}❌ npm not found. Please install Node.js.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to check package version
|
||||
check_package() {
|
||||
local package=$1
|
||||
local current_version=$2
|
||||
|
||||
echo -n "Checking $package... "
|
||||
|
||||
# Get latest version from npm
|
||||
latest_version=$(npm view $package version 2>/dev/null)
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}❌ Not found in npm registry${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$current_version" = "$latest_version" ]; then
|
||||
echo -e "${GREEN}✅ Up to date ($current_version)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Update available: $current_version → $latest_version${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "📦 Dependencies:"
|
||||
check_package "@anthropic-ai/claude-agent-sdk" "0.1.0"
|
||||
check_package "zod" "3.23.0"
|
||||
|
||||
echo ""
|
||||
echo "🛠️ Dev Dependencies:"
|
||||
check_package "@types/node" "20.0.0"
|
||||
check_package "typescript" "5.3.0"
|
||||
|
||||
echo ""
|
||||
echo "✨ Check complete!"
|
||||
55
templates/basic-query.ts
Normal file
55
templates/basic-query.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
/**
|
||||
* Basic Query Template
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Simple query execution
|
||||
* - Model selection
|
||||
* - Working directory
|
||||
* - Basic message handling
|
||||
*/
|
||||
|
||||
async function basicQuery() {
|
||||
const response = query({
|
||||
prompt: "Analyze the codebase and suggest improvements",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5", // or "haiku", "opus"
|
||||
workingDirectory: process.cwd(),
|
||||
allowedTools: ["Read", "Grep", "Glob"]
|
||||
}
|
||||
});
|
||||
|
||||
// Process streaming messages
|
||||
for await (const message of response) {
|
||||
switch (message.type) {
|
||||
case 'system':
|
||||
if (message.subtype === 'init') {
|
||||
console.log(`Session ID: ${message.session_id}`);
|
||||
console.log(`Model: ${message.model}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'assistant':
|
||||
if (typeof message.content === 'string') {
|
||||
console.log('Assistant:', message.content);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'tool_call':
|
||||
console.log(`Executing tool: ${message.tool_name}`);
|
||||
break;
|
||||
|
||||
case 'tool_result':
|
||||
console.log(`Tool ${message.tool_name} completed`);
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.error('Error:', message.error.message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run
|
||||
basicQuery().catch(console.error);
|
||||
161
templates/custom-mcp-server.ts
Normal file
161
templates/custom-mcp-server.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { query, createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* Custom MCP Server Template
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Creating in-process MCP server
|
||||
* - Defining tools with Zod schemas
|
||||
* - Multiple tools in one server
|
||||
* - Error handling in tools
|
||||
*/
|
||||
|
||||
// Define a custom MCP server with multiple tools
|
||||
const weatherServer = createSdkMcpServer({
|
||||
name: "weather-service",
|
||||
version: "1.0.0",
|
||||
tools: [
|
||||
tool(
|
||||
"get_weather",
|
||||
"Get current weather for a location",
|
||||
{
|
||||
location: z.string().describe("City name or coordinates"),
|
||||
units: z.enum(["celsius", "fahrenheit"]).default("celsius")
|
||||
},
|
||||
async (args) => {
|
||||
try {
|
||||
// Simulate API call
|
||||
const response = await fetch(
|
||||
`https://api.weather.com/v1/current?location=${args.location}&units=${args.units}`
|
||||
);
|
||||
const data = await response.json();
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Temperature: ${data.temp}° ${args.units}\nConditions: ${data.conditions}\nHumidity: ${data.humidity}%`
|
||||
}]
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Error fetching weather: ${error.message}`
|
||||
}],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
}
|
||||
),
|
||||
tool(
|
||||
"get_forecast",
|
||||
"Get weather forecast for next 7 days",
|
||||
{
|
||||
location: z.string(),
|
||||
days: z.number().min(1).max(7).default(7)
|
||||
},
|
||||
async (args) => {
|
||||
// Simulated forecast data
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `7-day forecast for ${args.location}: Mostly sunny with temperatures ranging from 15-25°C`
|
||||
}]
|
||||
};
|
||||
}
|
||||
)
|
||||
]
|
||||
});
|
||||
|
||||
// Database tools server
|
||||
const databaseServer = createSdkMcpServer({
|
||||
name: "database",
|
||||
version: "1.0.0",
|
||||
tools: [
|
||||
tool(
|
||||
"query_users",
|
||||
"Query user records from the database",
|
||||
{
|
||||
email: z.string().email().optional(),
|
||||
limit: z.number().min(1).max(100).default(10),
|
||||
offset: z.number().min(0).default(0)
|
||||
},
|
||||
async (args) => {
|
||||
// Simulated database query
|
||||
const results = [
|
||||
{ id: 1, email: "user1@example.com", name: "User 1" },
|
||||
{ id: 2, email: "user2@example.com", name: "User 2" }
|
||||
];
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: JSON.stringify(results, null, 2)
|
||||
}]
|
||||
};
|
||||
}
|
||||
),
|
||||
tool(
|
||||
"calculate",
|
||||
"Perform mathematical calculations",
|
||||
{
|
||||
expression: z.string().describe("Mathematical expression to evaluate"),
|
||||
precision: z.number().min(0).max(10).default(2)
|
||||
},
|
||||
async (args) => {
|
||||
try {
|
||||
// In production, use a proper math parser (e.g., mathjs)
|
||||
const result = eval(args.expression);
|
||||
const rounded = Number(result.toFixed(args.precision));
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Result: ${rounded}`
|
||||
}]
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Invalid expression: ${error.message}`
|
||||
}],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
}
|
||||
)
|
||||
]
|
||||
});
|
||||
|
||||
// Use custom tools in query
|
||||
async function useCustomTools() {
|
||||
const response = query({
|
||||
prompt: "What's the weather in San Francisco? Also query users with gmail addresses and calculate 15% tip on $85.50",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
mcpServers: {
|
||||
"weather-service": weatherServer,
|
||||
"database": databaseServer
|
||||
},
|
||||
allowedTools: [
|
||||
"mcp__weather-service__get_weather",
|
||||
"mcp__weather-service__get_forecast",
|
||||
"mcp__database__query_users",
|
||||
"mcp__database__calculate"
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log('Assistant:', message.content);
|
||||
} else if (message.type === 'tool_call') {
|
||||
console.log(`\n🔧 ${message.tool_name}:`, message.input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run
|
||||
useCustomTools().catch(console.error);
|
||||
283
templates/error-handling.ts
Normal file
283
templates/error-handling.ts
Normal file
@@ -0,0 +1,283 @@
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
/**
|
||||
* Error Handling Template
|
||||
*
|
||||
* Demonstrates:
|
||||
* - SDK error handling
|
||||
* - Message-level error handling
|
||||
* - Retry strategies
|
||||
* - Graceful degradation
|
||||
*/
|
||||
|
||||
// Example 1: Basic Error Handling
|
||||
async function basicErrorHandling() {
|
||||
try {
|
||||
const response = query({
|
||||
prompt: "Analyze and refactor code",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
workingDirectory: "/path/to/project"
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
switch (message.type) {
|
||||
case 'assistant':
|
||||
console.log('Assistant:', message.content);
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.error('Agent error:', message.error.message);
|
||||
if (message.error.type === 'permission_denied') {
|
||||
console.log('Permission denied for:', message.error.tool);
|
||||
// Handle permission errors gracefully
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fatal error:', error);
|
||||
|
||||
// Handle specific error codes
|
||||
if (error.code === 'CLI_NOT_FOUND') {
|
||||
console.error('Claude Code CLI not installed');
|
||||
console.error('Install: npm install -g @anthropic-ai/claude-code');
|
||||
} else if (error.code === 'AUTHENTICATION_FAILED') {
|
||||
console.error('Invalid API key. Check ANTHROPIC_API_KEY');
|
||||
} else if (error.code === 'RATE_LIMIT_EXCEEDED') {
|
||||
console.error('Rate limit exceeded. Retry after delay.');
|
||||
} else if (error.code === 'CONTEXT_LENGTH_EXCEEDED') {
|
||||
console.error('Context too large. Use session compaction.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 2: Retry with Exponential Backoff
|
||||
async function retryWithBackoff(
|
||||
prompt: string,
|
||||
maxRetries = 3,
|
||||
baseDelay = 1000
|
||||
): Promise<void> {
|
||||
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
||||
try {
|
||||
const response = query({
|
||||
prompt,
|
||||
options: {
|
||||
model: "claude-sonnet-4-5"
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
|
||||
return; // Success, exit
|
||||
} catch (error) {
|
||||
if (error.code === 'RATE_LIMIT_EXCEEDED' && attempt < maxRetries - 1) {
|
||||
const delay = baseDelay * Math.pow(2, attempt);
|
||||
console.log(`Rate limited. Retrying in ${delay}ms...`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
} else {
|
||||
throw error; // Re-throw if not rate limit or final attempt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 3: Graceful Degradation
|
||||
async function gracefulDegradation(prompt: string) {
|
||||
// Try with full capabilities first
|
||||
try {
|
||||
console.log('Attempting with Sonnet model...');
|
||||
const response = query({
|
||||
prompt,
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
allowedTools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Sonnet failed, falling back to Haiku...');
|
||||
|
||||
// Fallback to faster/cheaper model with limited tools
|
||||
try {
|
||||
const response = query({
|
||||
prompt,
|
||||
options: {
|
||||
model: "haiku",
|
||||
allowedTools: ["Read", "Grep", "Glob"] // Read-only
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
} catch (fallbackError) {
|
||||
console.error('All attempts failed:', fallbackError);
|
||||
throw fallbackError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 4: Comprehensive Error Handler
|
||||
async function comprehensiveErrorHandling() {
|
||||
const errors: Array<{ type: string; message: string; timestamp: Date }> = [];
|
||||
|
||||
try {
|
||||
const response = query({
|
||||
prompt: "Complex multi-step task",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
permissionMode: "default"
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
switch (message.type) {
|
||||
case 'assistant':
|
||||
console.log('✅ Assistant:', message.content);
|
||||
break;
|
||||
|
||||
case 'tool_call':
|
||||
console.log(`🔧 Executing: ${message.tool_name}`);
|
||||
break;
|
||||
|
||||
case 'tool_result':
|
||||
console.log(`✅ ${message.tool_name} completed`);
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.error('❌ Error:', message.error.message);
|
||||
errors.push({
|
||||
type: message.error.type,
|
||||
message: message.error.message,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
// Handle different error types
|
||||
if (message.error.type === 'permission_denied') {
|
||||
console.log('→ Permission was denied, continuing with limited access');
|
||||
} else if (message.error.type === 'tool_execution_failed') {
|
||||
console.log('→ Tool failed, attempting alternative approach');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('💥 Fatal error:', error);
|
||||
|
||||
// Log error details
|
||||
errors.push({
|
||||
type: error.code || 'UNKNOWN',
|
||||
message: error.message,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
// Specific handlers
|
||||
if (error.code === 'AUTHENTICATION_FAILED') {
|
||||
console.error('→ Check your ANTHROPIC_API_KEY environment variable');
|
||||
console.error('→ Visit https://console.anthropic.com/ for API keys');
|
||||
} else if (error.code === 'RATE_LIMIT_EXCEEDED') {
|
||||
console.error('→ Rate limit exceeded');
|
||||
console.error('→ Implement exponential backoff or reduce request frequency');
|
||||
} else if (error.code === 'CONTEXT_LENGTH_EXCEEDED') {
|
||||
console.error('→ Context too large');
|
||||
console.error('→ Consider using session management or reducing prompt size');
|
||||
} else if (error.code === 'CLI_NOT_FOUND') {
|
||||
console.error('→ Claude Code CLI not found');
|
||||
console.error('→ Install: npm install -g @anthropic-ai/claude-code');
|
||||
}
|
||||
|
||||
throw error;
|
||||
} finally {
|
||||
// Always log error summary
|
||||
if (errors.length > 0) {
|
||||
console.log('\n\n=== Error Summary ===');
|
||||
errors.forEach(err => {
|
||||
console.log(`${err.timestamp.toISOString()} - ${err.type}: ${err.message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 5: Circuit Breaker Pattern
|
||||
class CircuitBreaker {
|
||||
private failures = 0;
|
||||
private lastFailureTime?: Date;
|
||||
private readonly threshold = 3;
|
||||
private readonly resetTimeout = 60000; // 1 minute
|
||||
|
||||
async execute(fn: () => Promise<void>): Promise<void> {
|
||||
// Check if circuit is open
|
||||
if (this.isOpen()) {
|
||||
throw new Error('Circuit breaker is OPEN. Too many failures.');
|
||||
}
|
||||
|
||||
try {
|
||||
await fn();
|
||||
this.onSuccess();
|
||||
} catch (error) {
|
||||
this.onFailure();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private isOpen(): boolean {
|
||||
if (this.failures >= this.threshold) {
|
||||
const now = new Date();
|
||||
if (this.lastFailureTime &&
|
||||
now.getTime() - this.lastFailureTime.getTime() < this.resetTimeout) {
|
||||
return true;
|
||||
}
|
||||
// Reset after timeout
|
||||
this.failures = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private onSuccess() {
|
||||
this.failures = 0;
|
||||
this.lastFailureTime = undefined;
|
||||
}
|
||||
|
||||
private onFailure() {
|
||||
this.failures++;
|
||||
this.lastFailureTime = new Date();
|
||||
console.warn(`Circuit breaker: ${this.failures}/${this.threshold} failures`);
|
||||
}
|
||||
}
|
||||
|
||||
async function useCircuitBreaker() {
|
||||
const breaker = new CircuitBreaker();
|
||||
|
||||
try {
|
||||
await breaker.execute(async () => {
|
||||
const response = query({
|
||||
prompt: "Perform task",
|
||||
options: { model: "sonnet" }
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Circuit breaker prevented execution or task failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Run
|
||||
comprehensiveErrorHandling().catch(console.error);
|
||||
211
templates/filesystem-settings.ts
Normal file
211
templates/filesystem-settings.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
/**
|
||||
* Filesystem Settings Template
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Loading settings from user, project, local
|
||||
* - Settings priority and merging
|
||||
* - Isolated vs configured execution
|
||||
* - Loading CLAUDE.md project instructions
|
||||
*/
|
||||
|
||||
// Example 1: Load All Settings (Legacy Behavior)
|
||||
async function loadAllSettings() {
|
||||
const response = query({
|
||||
prompt: "Build a new feature following project conventions",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
settingSources: ["user", "project", "local"]
|
||||
// Loads:
|
||||
// 1. ~/.claude/settings.json (user)
|
||||
// 2. .claude/settings.json (project)
|
||||
// 3. .claude/settings.local.json (local overrides)
|
||||
//
|
||||
// Priority (highest first):
|
||||
// 1. Programmatic options (this config)
|
||||
// 2. Local settings
|
||||
// 3. Project settings
|
||||
// 4. User settings
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 2: Project Settings Only (CI/CD Pattern)
|
||||
async function projectSettingsOnly() {
|
||||
const response = query({
|
||||
prompt: "Run automated code review",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
settingSources: ["project"]
|
||||
// Only .claude/settings.json
|
||||
// Ignores user and local settings
|
||||
// Ensures consistent behavior in CI/CD
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 3: No Filesystem Settings (Fully Isolated)
|
||||
async function isolatedExecution() {
|
||||
const response = query({
|
||||
prompt: "Analyze this code snippet",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
settingSources: [], // Empty = no filesystem settings
|
||||
workingDirectory: "/tmp/sandbox",
|
||||
allowedTools: ["Read", "Grep", "Glob"],
|
||||
systemPrompt: "You are a code analyzer."
|
||||
// Fully isolated, no filesystem dependencies
|
||||
// Perfect for sandboxed/containerized environments
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 4: Hybrid Approach (Project + Programmatic)
|
||||
async function hybridConfiguration() {
|
||||
const response = query({
|
||||
prompt: "Implement user authentication system",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
settingSources: ["project"], // Load CLAUDE.md and project settings
|
||||
systemPrompt: "Follow security best practices and company coding standards.",
|
||||
agents: {
|
||||
"security-checker": {
|
||||
description: "Security validation specialist",
|
||||
prompt: "Validate all security implementations against OWASP guidelines.",
|
||||
tools: ["Read", "Grep"],
|
||||
model: "sonnet"
|
||||
}
|
||||
},
|
||||
allowedTools: ["Read", "Write", "Edit", "Grep", "Glob"]
|
||||
// Project settings + programmatic overrides
|
||||
// Programmatic settings always win
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 5: Loading CLAUDE.md Project Instructions
|
||||
async function loadProjectInstructions() {
|
||||
const response = query({
|
||||
prompt: "Implement new feature according to project guidelines",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
systemPrompt: {
|
||||
type: 'preset',
|
||||
preset: 'claude_code' // Required to use CLAUDE.md
|
||||
},
|
||||
settingSources: ["project"], // Reads CLAUDE.md from project directory
|
||||
workingDirectory: process.cwd()
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 6: Environment-Specific Settings
|
||||
async function environmentSpecificSettings(
|
||||
environment: 'development' | 'staging' | 'production'
|
||||
) {
|
||||
let settingSources: Array<'user' | 'project' | 'local'>;
|
||||
let permissionMode: 'default' | 'acceptEdits' | 'bypassPermissions';
|
||||
|
||||
switch (environment) {
|
||||
case 'development':
|
||||
settingSources = ["user", "project", "local"];
|
||||
permissionMode = "acceptEdits";
|
||||
break;
|
||||
|
||||
case 'staging':
|
||||
settingSources = ["project"];
|
||||
permissionMode = "default";
|
||||
break;
|
||||
|
||||
case 'production':
|
||||
settingSources = ["project"];
|
||||
permissionMode = "default";
|
||||
break;
|
||||
}
|
||||
|
||||
const response = query({
|
||||
prompt: "Deploy application",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
settingSources,
|
||||
permissionMode,
|
||||
workingDirectory: process.cwd()
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Settings File Examples:
|
||||
|
||||
/**
|
||||
* ~/.claude/settings.json (User Settings)
|
||||
* {
|
||||
* "model": "claude-sonnet-4-5",
|
||||
* "allowedTools": ["Read", "Write", "Edit", "Bash", "Grep", "Glob"],
|
||||
* "permissionMode": "default"
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* .claude/settings.json (Project Settings - version controlled)
|
||||
* {
|
||||
* "model": "claude-sonnet-4-5",
|
||||
* "allowedTools": ["Read", "Write", "Edit", "Grep", "Glob"],
|
||||
* "disallowedTools": ["Bash"],
|
||||
* "agents": {
|
||||
* "code-reviewer": {
|
||||
* "description": "Review code for quality",
|
||||
* "prompt": "You review code for best practices.",
|
||||
* "tools": ["Read", "Grep"],
|
||||
* "model": "haiku"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* .claude/settings.local.json (Local Overrides - gitignored)
|
||||
* {
|
||||
* "permissionMode": "acceptEdits",
|
||||
* "allowedTools": ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
|
||||
* }
|
||||
*/
|
||||
|
||||
// Run
|
||||
hybridConfiguration().catch(console.error);
|
||||
318
templates/multi-agent-workflow.ts
Normal file
318
templates/multi-agent-workflow.ts
Normal file
@@ -0,0 +1,318 @@
|
||||
import { query, createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* Complete Multi-Agent Workflow Template
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Complex multi-agent orchestration
|
||||
* - Custom tools for agents
|
||||
* - Environment-based configuration
|
||||
* - Production-ready error handling
|
||||
* - Comprehensive monitoring
|
||||
*/
|
||||
|
||||
// Custom tools for notification and logging
|
||||
const appTools = createSdkMcpServer({
|
||||
name: "app-services",
|
||||
version: "1.0.0",
|
||||
tools: [
|
||||
tool(
|
||||
"send_notification",
|
||||
"Send notification to users or teams",
|
||||
{
|
||||
userId: z.string().optional(),
|
||||
teamId: z.string().optional(),
|
||||
message: z.string(),
|
||||
priority: z.enum(["low", "medium", "high", "critical"]).default("medium")
|
||||
},
|
||||
async (args) => {
|
||||
// Simulate notification service
|
||||
console.log(`📧 Notification (${args.priority}): ${args.message}`);
|
||||
return {
|
||||
content: [{ type: "text", text: "Notification sent successfully" }]
|
||||
};
|
||||
}
|
||||
),
|
||||
tool(
|
||||
"log_event",
|
||||
"Log application events for monitoring",
|
||||
{
|
||||
event: z.string(),
|
||||
data: z.record(z.any()).optional(),
|
||||
severity: z.enum(["debug", "info", "warning", "error", "critical"]).default("info")
|
||||
},
|
||||
async (args) => {
|
||||
console.log(`📝 [${args.severity.toUpperCase()}] ${args.event}:`, args.data || '');
|
||||
return {
|
||||
content: [{ type: "text", text: "Event logged" }]
|
||||
};
|
||||
}
|
||||
),
|
||||
tool(
|
||||
"check_health",
|
||||
"Check system health metrics",
|
||||
{
|
||||
service: z.string(),
|
||||
metrics: z.array(z.enum(["cpu", "memory", "disk", "network"])).optional()
|
||||
},
|
||||
async (args) => {
|
||||
// Simulate health check
|
||||
const health = {
|
||||
service: args.service,
|
||||
status: "healthy",
|
||||
uptime: "99.9%",
|
||||
responseTime: "50ms"
|
||||
};
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(health, null, 2) }]
|
||||
};
|
||||
}
|
||||
)
|
||||
]
|
||||
});
|
||||
|
||||
// Main DevOps agent orchestrator
|
||||
async function runDevOpsAgent(task: string) {
|
||||
console.log(`🚀 Starting DevOps Agent for: ${task}\n`);
|
||||
|
||||
const response = query({
|
||||
prompt: task,
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
workingDirectory: process.cwd(),
|
||||
systemPrompt: `You are a DevOps automation expert and orchestrator.
|
||||
|
||||
Your responsibilities:
|
||||
- Monitor system health
|
||||
- Deploy applications safely
|
||||
- Handle incidents and alerts
|
||||
- Maintain infrastructure
|
||||
- Coordinate specialized agents
|
||||
|
||||
Always log your actions and notify relevant stakeholders.
|
||||
Follow the principle of least privilege for tool access.`,
|
||||
|
||||
// Custom tools
|
||||
mcpServers: {
|
||||
"app-services": appTools
|
||||
},
|
||||
|
||||
// Specialized agents for different tasks
|
||||
agents: {
|
||||
"deployment-agent": {
|
||||
description: "Handles application deployments, rollbacks, and release management",
|
||||
prompt: `You manage deployments.
|
||||
|
||||
Deployment checklist:
|
||||
1. Verify all tests pass
|
||||
2. Deploy to staging first
|
||||
3. Run smoke tests
|
||||
4. Deploy to production
|
||||
5. Create rollback plan
|
||||
6. Monitor for issues
|
||||
|
||||
Always notify stakeholders of deployment status.`,
|
||||
tools: [
|
||||
"Bash",
|
||||
"Read",
|
||||
"mcp__app-services__log_event",
|
||||
"mcp__app-services__send_notification",
|
||||
"mcp__app-services__check_health"
|
||||
],
|
||||
model: "sonnet"
|
||||
},
|
||||
|
||||
"incident-responder": {
|
||||
description: "Responds to production incidents, outages, and performance issues",
|
||||
prompt: `You handle incidents.
|
||||
|
||||
Incident response process:
|
||||
1. Assess impact (users affected, services down)
|
||||
2. Identify root cause
|
||||
3. Implement immediate fixes
|
||||
4. Communicate status updates
|
||||
5. Document incident for post-mortem
|
||||
|
||||
Work quickly but carefully. User experience is critical.`,
|
||||
tools: [
|
||||
"Bash",
|
||||
"Read",
|
||||
"Grep",
|
||||
"mcp__app-services__log_event",
|
||||
"mcp__app-services__send_notification",
|
||||
"mcp__app-services__check_health"
|
||||
],
|
||||
model: "sonnet"
|
||||
},
|
||||
|
||||
"monitoring-agent": {
|
||||
description: "Monitors system metrics, health checks, and alerts on issues",
|
||||
prompt: `You monitor systems.
|
||||
|
||||
Monitoring tasks:
|
||||
- Check application metrics
|
||||
- Analyze error rates
|
||||
- Monitor response times
|
||||
- Verify system health
|
||||
- Alert on anomalies
|
||||
|
||||
Report issues immediately.`,
|
||||
tools: [
|
||||
"Bash",
|
||||
"Read",
|
||||
"mcp__app-services__log_event",
|
||||
"mcp__app-services__send_notification",
|
||||
"mcp__app-services__check_health"
|
||||
],
|
||||
model: "haiku" // Fast, cost-effective for monitoring
|
||||
},
|
||||
|
||||
"security-agent": {
|
||||
description: "Performs security audits, vulnerability scanning, and compliance checks",
|
||||
prompt: `You ensure security.
|
||||
|
||||
Security checks:
|
||||
- Scan for exposed secrets
|
||||
- Check dependency vulnerabilities
|
||||
- Verify access controls
|
||||
- Validate compliance (OWASP, SOC2)
|
||||
- Audit infrastructure config
|
||||
|
||||
Block deployments if critical issues found.`,
|
||||
tools: [
|
||||
"Bash",
|
||||
"Read",
|
||||
"Grep",
|
||||
"mcp__app-services__log_event",
|
||||
"mcp__app-services__send_notification"
|
||||
],
|
||||
model: "sonnet"
|
||||
},
|
||||
|
||||
"performance-agent": {
|
||||
description: "Analyzes performance metrics, identifies bottlenecks, and suggests optimizations",
|
||||
prompt: `You optimize performance.
|
||||
|
||||
Performance analysis:
|
||||
- Database query times
|
||||
- API response times
|
||||
- Memory/CPU usage
|
||||
- Network latency
|
||||
- Caching effectiveness
|
||||
|
||||
Identify bottlenecks and optimization opportunities.`,
|
||||
tools: [
|
||||
"Bash",
|
||||
"Read",
|
||||
"Grep",
|
||||
"mcp__app-services__log_event",
|
||||
"mcp__app-services__check_health"
|
||||
],
|
||||
model: "sonnet"
|
||||
}
|
||||
},
|
||||
|
||||
// Permission control
|
||||
permissionMode: "default",
|
||||
canUseTool: async (toolName, input) => {
|
||||
// Log all tool usage
|
||||
console.log(`🔧 [${new Date().toISOString()}] ${toolName}`);
|
||||
|
||||
// Prevent destructive operations
|
||||
if (toolName === 'Bash') {
|
||||
const dangerous = ['rm -rf', 'dd if=', 'mkfs', '> /dev/', 'shutdown'];
|
||||
if (dangerous.some(pattern => input.command.includes(pattern))) {
|
||||
return {
|
||||
behavior: "deny",
|
||||
message: `Destructive command blocked: ${input.command}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Require confirmation for production deployments
|
||||
if (input.command?.includes('deploy --production') ||
|
||||
input.command?.includes('kubectl apply -n production')) {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `⚠️ PRODUCTION DEPLOYMENT: ${input.command}\n\nConfirm?`
|
||||
};
|
||||
}
|
||||
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Track execution
|
||||
const agentsUsed = new Set<string>();
|
||||
const toolsExecuted: string[] = [];
|
||||
let sessionId: string | undefined;
|
||||
|
||||
try {
|
||||
for await (const message of response) {
|
||||
switch (message.type) {
|
||||
case 'system':
|
||||
if (message.subtype === 'init') {
|
||||
sessionId = message.session_id;
|
||||
console.log(`✨ Session: ${sessionId}\n`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'assistant':
|
||||
console.log('📋 Orchestrator:', message.content);
|
||||
break;
|
||||
|
||||
case 'tool_call':
|
||||
console.log(`\n🔧 Executing: ${message.tool_name}`);
|
||||
toolsExecuted.push(message.tool_name);
|
||||
break;
|
||||
|
||||
case 'tool_result':
|
||||
console.log(`✅ ${message.tool_name} completed`);
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.error('❌ Error:', message.error.message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n\n✅ Task completed successfully`);
|
||||
console.log(`Session ID: ${sessionId}`);
|
||||
console.log(`Tools executed: ${toolsExecuted.length}`);
|
||||
} catch (error) {
|
||||
console.error('💥 Fatal error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Usage examples
|
||||
async function main() {
|
||||
try {
|
||||
// Example 1: Deployment
|
||||
await runDevOpsAgent(
|
||||
"Deploy version 2.5.0 to production with full validation and monitoring"
|
||||
);
|
||||
|
||||
// Example 2: Incident Response
|
||||
// await runDevOpsAgent(
|
||||
// "API response time increased by 300% in last hour. Investigate, identify root cause, and fix"
|
||||
// );
|
||||
|
||||
// Example 3: Security Audit
|
||||
// await runDevOpsAgent(
|
||||
// "Perform comprehensive security audit of the application and infrastructure"
|
||||
// );
|
||||
|
||||
// Example 4: Performance Optimization
|
||||
// await runDevOpsAgent(
|
||||
// "Analyze application performance and implement optimizations for the checkout flow"
|
||||
// );
|
||||
} catch (error) {
|
||||
console.error('Workflow failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
29
templates/package.json
Normal file
29
templates/package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "claude-agent-sdk-examples",
|
||||
"version": "1.0.0",
|
||||
"description": "Claude Agent SDK usage examples",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"basic-query": "tsx templates/basic-query.ts",
|
||||
"query-with-tools": "tsx templates/query-with-tools.ts",
|
||||
"custom-mcp-server": "tsx templates/custom-mcp-server.ts",
|
||||
"subagents": "tsx templates/subagents-orchestration.ts",
|
||||
"sessions": "tsx templates/session-management.ts",
|
||||
"permissions": "tsx templates/permission-control.ts",
|
||||
"settings": "tsx templates/filesystem-settings.ts",
|
||||
"errors": "tsx templates/error-handling.ts",
|
||||
"workflow": "tsx templates/multi-agent-workflow.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.1.0",
|
||||
"zod": "^3.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"tsx": "^4.0.0",
|
||||
"typescript": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
}
|
||||
211
templates/permission-control.ts
Normal file
211
templates/permission-control.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
/**
|
||||
* Permission Control Template
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Permission modes (default, acceptEdits, bypassPermissions)
|
||||
* - Custom canUseTool callback
|
||||
* - Safety controls for dangerous operations
|
||||
* - Conditional tool approval
|
||||
*/
|
||||
|
||||
// Example 1: Accept Edits Mode (auto-approve file edits)
|
||||
async function autoApproveEdits() {
|
||||
const response = query({
|
||||
prompt: "Refactor the user service to use async/await throughout",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
workingDirectory: "/path/to/project",
|
||||
permissionMode: "acceptEdits" // Auto-approve file edits
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 2: Bypass Permissions (use with caution!)
|
||||
async function bypassAllPermissions() {
|
||||
const response = query({
|
||||
prompt: "Run comprehensive test suite and fix all failures",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
permissionMode: "bypassPermissions"
|
||||
// ⚠️ CAUTION: Skips ALL permission checks
|
||||
// Use only in trusted, sandboxed environments
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 3: Custom Permission Logic
|
||||
async function customPermissions() {
|
||||
const response = query({
|
||||
prompt: "Deploy the application to production",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
permissionMode: "default",
|
||||
canUseTool: async (toolName, input) => {
|
||||
// Allow read-only operations
|
||||
if (['Read', 'Grep', 'Glob'].includes(toolName)) {
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
|
||||
// Deny destructive bash commands
|
||||
if (toolName === 'Bash') {
|
||||
const dangerous = [
|
||||
'rm -rf',
|
||||
'dd if=',
|
||||
'mkfs',
|
||||
'> /dev/',
|
||||
'shutdown',
|
||||
'reboot'
|
||||
];
|
||||
|
||||
if (dangerous.some(pattern => input.command.includes(pattern))) {
|
||||
return {
|
||||
behavior: "deny",
|
||||
message: `Destructive command blocked: ${input.command}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Require confirmation for deployments
|
||||
if (input.command?.includes('deploy') ||
|
||||
input.command?.includes('kubectl apply') ||
|
||||
input.command?.includes('terraform apply')) {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `Confirm deployment: ${input.command}?`
|
||||
};
|
||||
}
|
||||
|
||||
// Require confirmation for file writes to sensitive paths
|
||||
if (toolName === 'Write' || toolName === 'Edit') {
|
||||
const sensitivePaths = [
|
||||
'/etc/',
|
||||
'/root/',
|
||||
'.env',
|
||||
'credentials',
|
||||
'secrets',
|
||||
'config/production'
|
||||
];
|
||||
|
||||
if (sensitivePaths.some(path => input.file_path?.includes(path))) {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `Modify sensitive file ${input.file_path}?`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Allow by default
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 4: Environment-Based Permissions
|
||||
async function environmentBasedPermissions(environment: 'development' | 'staging' | 'production') {
|
||||
const response = query({
|
||||
prompt: "Deploy the latest changes",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
permissionMode: "default",
|
||||
canUseTool: async (toolName, input) => {
|
||||
// Production requires approval for everything
|
||||
if (environment === 'production') {
|
||||
if (toolName === 'Bash' || toolName === 'Write' || toolName === 'Edit') {
|
||||
return {
|
||||
behavior: "ask",
|
||||
message: `PRODUCTION: Approve ${toolName}?`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Staging auto-approves edits
|
||||
if (environment === 'staging') {
|
||||
if (toolName === 'Write' || toolName === 'Edit') {
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
|
||||
// Development bypasses most checks
|
||||
if (environment === 'development') {
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
|
||||
return { behavior: "allow" };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 5: Logging & Auditing
|
||||
async function loggingPermissions() {
|
||||
const toolLog: Array<{ tool: string; input: any; decision: string; timestamp: Date }> = [];
|
||||
|
||||
const response = query({
|
||||
prompt: "Implement new feature X",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
permissionMode: "default",
|
||||
canUseTool: async (toolName, input) => {
|
||||
// Log all tool usage
|
||||
console.log(`[${new Date().toISOString()}] Tool requested: ${toolName}`);
|
||||
|
||||
const decision = { behavior: "allow" as const };
|
||||
|
||||
// Audit log
|
||||
toolLog.push({
|
||||
tool: toolName,
|
||||
input,
|
||||
decision: decision.behavior,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
// Could also send to external logging service
|
||||
// await logToDatabase(toolName, input, decision);
|
||||
|
||||
return decision;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
|
||||
// Print audit log
|
||||
console.log('\n\n=== Audit Log ===');
|
||||
toolLog.forEach(entry => {
|
||||
console.log(`${entry.timestamp.toISOString()} - ${entry.tool} - ${entry.decision}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Run
|
||||
customPermissions().catch(console.error);
|
||||
54
templates/query-with-tools.ts
Normal file
54
templates/query-with-tools.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
/**
|
||||
* Query with Tool Control Template
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Allowing/disallowing tools
|
||||
* - System prompts
|
||||
* - Tool execution monitoring
|
||||
*/
|
||||
|
||||
async function queryWithTools() {
|
||||
const response = query({
|
||||
prompt: "Review the authentication module for security issues and fix any vulnerabilities",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
workingDirectory: "/path/to/project",
|
||||
systemPrompt: `You are a security-focused code reviewer.
|
||||
|
||||
Analyze code for:
|
||||
- SQL injection vulnerabilities
|
||||
- XSS vulnerabilities
|
||||
- Authentication bypass issues
|
||||
- Insecure direct object references
|
||||
- Security misconfiguration
|
||||
|
||||
Provide detailed recommendations and fix critical issues.`,
|
||||
|
||||
// Allow reading and modification, but not bash execution
|
||||
allowedTools: ["Read", "Grep", "Glob", "Write", "Edit"],
|
||||
disallowedTools: ["Bash"]
|
||||
}
|
||||
});
|
||||
|
||||
// Track tool usage
|
||||
const toolsUsed = new Set<string>();
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log('\nAssistant:', message.content);
|
||||
} else if (message.type === 'tool_call') {
|
||||
console.log(`\n🔧 Executing: ${message.tool_name}`);
|
||||
console.log(`Input:`, JSON.stringify(message.input, null, 2));
|
||||
toolsUsed.add(message.tool_name);
|
||||
} else if (message.type === 'tool_result') {
|
||||
console.log(`✅ ${message.tool_name} completed`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n\nTools used: ${Array.from(toolsUsed).join(', ')}`);
|
||||
}
|
||||
|
||||
// Run
|
||||
queryWithTools().catch(console.error);
|
||||
151
templates/session-management.ts
Normal file
151
templates/session-management.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
/**
|
||||
* Session Management Template
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Starting sessions
|
||||
* - Resuming sessions
|
||||
* - Forking sessions (alternative paths)
|
||||
* - Session lifecycle management
|
||||
*/
|
||||
|
||||
// Start a new session
|
||||
async function startSession(prompt: string): Promise<string> {
|
||||
let sessionId: string | undefined;
|
||||
|
||||
const response = query({
|
||||
prompt,
|
||||
options: {
|
||||
model: "claude-sonnet-4-5"
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'system' && message.subtype === 'init') {
|
||||
sessionId = message.session_id;
|
||||
console.log(`✨ Session started: ${sessionId}`);
|
||||
} else if (message.type === 'assistant') {
|
||||
console.log('Assistant:', message.content);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sessionId) {
|
||||
throw new Error('Failed to start session');
|
||||
}
|
||||
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
// Resume an existing session
|
||||
async function resumeSession(sessionId: string, prompt: string): Promise<void> {
|
||||
const response = query({
|
||||
prompt,
|
||||
options: {
|
||||
resume: sessionId,
|
||||
model: "claude-sonnet-4-5"
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`\n↪️ Resuming session: ${sessionId}`);
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log('Assistant:', message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fork a session (explore alternative path)
|
||||
async function forkSession(sessionId: string, prompt: string): Promise<void> {
|
||||
const response = query({
|
||||
prompt,
|
||||
options: {
|
||||
resume: sessionId,
|
||||
forkSession: true, // Creates new branch
|
||||
model: "claude-sonnet-4-5"
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`\n🔀 Forking session: ${sessionId}`);
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'system' && message.subtype === 'init') {
|
||||
console.log(`New session ID: ${message.session_id}`);
|
||||
} else if (message.type === 'assistant') {
|
||||
console.log('Assistant:', message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pattern 1: Sequential Development
|
||||
async function sequentialDevelopment() {
|
||||
console.log("🚀 Sequential Development Pattern\n");
|
||||
|
||||
// Step 1: Initial implementation
|
||||
let session = await startSession("Create a user authentication system with JWT");
|
||||
|
||||
// Step 2: Add feature
|
||||
await resumeSession(session, "Add OAuth 2.0 support (Google and GitHub)");
|
||||
|
||||
// Step 3: Add tests
|
||||
await resumeSession(session, "Write comprehensive integration tests");
|
||||
|
||||
// Step 4: Deploy
|
||||
await resumeSession(session, "Deploy to production with monitoring");
|
||||
|
||||
console.log("\n✅ Sequential development complete");
|
||||
}
|
||||
|
||||
// Pattern 2: Exploration & Decision
|
||||
async function explorationAndDecision() {
|
||||
console.log("🔍 Exploration & Decision Pattern\n");
|
||||
|
||||
// Start main conversation
|
||||
let mainSession = await startSession("Design a payment processing system");
|
||||
|
||||
// Explore option A
|
||||
console.log("\n--- Option A: Stripe ---");
|
||||
await forkSession(mainSession, "Implement using Stripe API");
|
||||
|
||||
// Explore option B
|
||||
console.log("\n--- Option B: PayPal ---");
|
||||
await forkSession(mainSession, "Implement using PayPal API");
|
||||
|
||||
// After decision, continue with chosen approach
|
||||
console.log("\n--- Chosen: Stripe ---");
|
||||
await resumeSession(mainSession, "Implement the Stripe integration with webhooks");
|
||||
|
||||
console.log("\n✅ Exploration complete");
|
||||
}
|
||||
|
||||
// Pattern 3: Multi-User Collaboration
|
||||
async function multiUserCollaboration() {
|
||||
console.log("👥 Multi-User Collaboration Pattern\n");
|
||||
|
||||
// Developer A starts work
|
||||
let sessionA = await startSession("Implement user profile page with avatar, bio, and settings");
|
||||
|
||||
// Developer B forks for different feature
|
||||
await forkSession(sessionA, "Add real-time notifications system with WebSockets");
|
||||
|
||||
// Developer C forks for another feature
|
||||
await forkSession(sessionA, "Implement search functionality with filters and sorting");
|
||||
|
||||
// All developers can work independently without interfering
|
||||
console.log("\n✅ Multi-user collaboration setup complete");
|
||||
}
|
||||
|
||||
// Run examples
|
||||
async function main() {
|
||||
try {
|
||||
// Choose one pattern to run
|
||||
await sequentialDevelopment();
|
||||
// await explorationAndDecision();
|
||||
// await multiUserCollaboration();
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
166
templates/subagents-orchestration.ts
Normal file
166
templates/subagents-orchestration.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
/**
|
||||
* Subagent Orchestration Template
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Defining specialized subagents
|
||||
* - Different models for different agents
|
||||
* - Tool restrictions per agent
|
||||
* - Multi-agent workflows
|
||||
*/
|
||||
|
||||
async function deployWithAgents(version: string) {
|
||||
const response = query({
|
||||
prompt: `Deploy version ${version} to production with full validation`,
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
workingDirectory: process.cwd(),
|
||||
systemPrompt: `You are a DevOps orchestrator.
|
||||
|
||||
Coordinate specialized agents to:
|
||||
1. Run tests (test-runner agent)
|
||||
2. Check security (security-checker agent)
|
||||
3. Deploy application (deployer agent)
|
||||
4. Monitor systems (monitoring-agent agent)
|
||||
|
||||
Ensure all validation passes before deployment.`,
|
||||
|
||||
agents: {
|
||||
"test-runner": {
|
||||
description: "Run automated test suites and verify coverage",
|
||||
prompt: `You run tests.
|
||||
|
||||
Execute test commands, parse results, report coverage.
|
||||
FAIL the deployment if any tests fail.
|
||||
Report clear error messages for failures.`,
|
||||
tools: ["Bash", "Read", "Grep"],
|
||||
model: "haiku" // Fast, cost-effective for testing
|
||||
},
|
||||
|
||||
"security-checker": {
|
||||
description: "Security audits and vulnerability scanning",
|
||||
prompt: `You check security.
|
||||
|
||||
Scan for:
|
||||
- Exposed secrets or API keys
|
||||
- Outdated dependencies
|
||||
- Incorrect file permissions
|
||||
- OWASP compliance issues
|
||||
|
||||
Verify all security checks pass before deployment.`,
|
||||
tools: ["Read", "Grep", "Bash"],
|
||||
model: "sonnet" // Balance for security analysis
|
||||
},
|
||||
|
||||
"deployer": {
|
||||
description: "Application deployment and rollbacks",
|
||||
prompt: `You deploy applications.
|
||||
|
||||
Deployment process:
|
||||
1. Deploy to staging environment
|
||||
2. Verify health checks pass
|
||||
3. Deploy to production
|
||||
4. Create rollback plan
|
||||
|
||||
ALWAYS have a rollback ready.`,
|
||||
tools: ["Bash", "Read"],
|
||||
model: "sonnet" // Reliable for critical operations
|
||||
},
|
||||
|
||||
"monitoring-agent": {
|
||||
description: "System monitoring and alerting",
|
||||
prompt: `You monitor systems.
|
||||
|
||||
Check:
|
||||
- Application metrics
|
||||
- Error rates
|
||||
- Response times
|
||||
- System health
|
||||
|
||||
Alert on issues immediately.`,
|
||||
tools: ["Bash", "Read"],
|
||||
model: "haiku" // Fast monitoring checks
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Track which agents were used
|
||||
const agentsUsed = new Set<string>();
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log('\n📋 Orchestrator:', message.content);
|
||||
} else if (message.type === 'tool_call') {
|
||||
console.log(`\n🔧 Tool: ${message.tool_name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example: Complex DevOps workflow
|
||||
async function complexWorkflow() {
|
||||
const response = query({
|
||||
prompt: "API response time increased by 300% in last hour. Investigate and fix",
|
||||
options: {
|
||||
model: "claude-sonnet-4-5",
|
||||
systemPrompt: "You coordinate incident response across specialized teams.",
|
||||
|
||||
agents: {
|
||||
"incident-responder": {
|
||||
description: "Diagnose and respond to production incidents",
|
||||
prompt: `You handle incidents.
|
||||
|
||||
Steps:
|
||||
1. Assess impact (users affected, services down)
|
||||
2. Identify root cause
|
||||
3. Implement immediate fixes
|
||||
4. Communicate status updates
|
||||
|
||||
Work with monitoring and deployment agents.`,
|
||||
tools: ["Bash", "Read", "Grep"],
|
||||
model: "sonnet"
|
||||
},
|
||||
|
||||
"performance-analyst": {
|
||||
description: "Analyze performance metrics and bottlenecks",
|
||||
prompt: `You analyze performance.
|
||||
|
||||
Investigate:
|
||||
- Database query times
|
||||
- API response times
|
||||
- Memory/CPU usage
|
||||
- Network latency
|
||||
|
||||
Identify bottlenecks and optimization opportunities.`,
|
||||
tools: ["Bash", "Read", "Grep"],
|
||||
model: "sonnet"
|
||||
},
|
||||
|
||||
"fix-implementer": {
|
||||
description: "Implement performance fixes and optimizations",
|
||||
prompt: `You implement fixes.
|
||||
|
||||
Apply optimizations:
|
||||
- Database query optimization
|
||||
- Caching improvements
|
||||
- Code refactoring
|
||||
- Infrastructure scaling
|
||||
|
||||
Test fixes before deploying.`,
|
||||
tools: ["Read", "Edit", "Bash"],
|
||||
model: "sonnet"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for await (const message of response) {
|
||||
if (message.type === 'assistant') {
|
||||
console.log(message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run
|
||||
deployWithAgents("2.5.0").catch(console.error);
|
||||
22
templates/tsconfig.json
Normal file
22
templates/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"lib": ["ES2022"],
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./",
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user