claude-agent-sdk
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseClaude Agent SDK - Structured Outputs & Error Prevention Guide
Claude Agent SDK - 结构化输出与错误预防指南
Package: @anthropic-ai/claude-agent-sdk@0.2.12
Breaking Changes: v0.1.45 - Structured outputs (Nov 2025), v0.1.0 - No default system prompt, settingSources required
Package: @anthropic-ai/claude-agent-sdk@0.2.12
重大变更: v0.1.45 - 新增结构化输出(2025年11月),v0.1.0 - 无默认系统提示,需指定settingSources
What's New in v0.1.45+ (Nov 2025)
v0.1.45+版本新特性(2025年11月)
—
1. 结构化输出(v0.1.45,2025年11月14日)
Major Features:
- JSON schema验证 - 确保响应与指定的精确 schema 匹配
- 参数 - 使用JSON schema或Zod定义输出结构
outputFormat - 访问验证后的结果 - 通过获取
message.structured_output - 需添加Beta头:
structured-outputs-2025-11-13 - 类型安全 - 结合Zod schema实现完整TypeScript类型推断
示例:
typescript
import { query } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
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) {
// 保证匹配schema
const validated = schema.parse(message.structured_output);
console.log(`Sentiment: ${validated.sentiment}`);
}
}Zod兼容性(v0.1.71+): SDK支持Zod v3.24.1+和Zod v4.0.0+作为对等依赖。无论使用哪个版本,导入方式均为。
import { z } from "zod"1. Structured Outputs (v0.1.45, Nov 14, 2025)
2. 插件系统(v0.1.27)
- JSON schema validation - Guarantees responses match exact schemas
- parameter - Define output structure with JSON schema or Zod
outputFormat - 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";
import { zodToJsonSchema } from "zod-to-json-schema";
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}`);
}
}Zod Compatibility (v0.1.71+): SDK supports both Zod v3.24.1+ and Zod v4.0.0+ as peer dependencies. Import remains for either version.
import { z } from "zod"- 数组 - 加载本地插件路径
plugins - 自定义插件支持 - 扩展代理能力
2. Plugins System (v0.1.27)
3. 钩子系统(v0.1.0+)
- array - Load local plugin paths
plugins - Custom plugin support - Extend agent capabilities
全部12种钩子事件:
| 钩子 | 触发时机 | 适用场景 |
|---|---|---|
| 工具执行前 | 验证、修改或阻止工具调用 |
| 工具执行后 | 记录结果、触发副作用 |
| 代理发送通知时 | 显示状态更新 |
| 收到用户提示时 | 预处理或验证输入 |
| 子代理启动时 | 跟踪任务委托、记录上下文 |
| 子代理完成时 | 汇总结果、清理资源 |
| 上下文压缩前 | 保存截断前的状态 |
| 需要权限时 | 自定义审批工作流 |
| 代理停止时 | 清理资源、最终日志记录 |
| 会话开始时 | 初始化状态 |
| 会话结束时 | 持久化状态、清理资源 |
| 发生错误时 | 自定义错误处理 |
钩子配置:
typescript
const response = query({
prompt: "...",
options: {
hooks: {
PreToolUse: async (input) => {
console.log(`Tool: ${input.toolName}`);
return { allow: true }; // 或 { allow: false, message: "..." }
},
PostToolUse: async (input) => {
await logToolUsage(input.toolName, input.result);
}
}
}
});3. Hooks System (v0.1.0+)
4. 其他选项
All 12 Hook Events:
| Hook | When Fired | Use Case |
|---|---|---|
| Before tool execution | Validate, modify, or block tool calls |
| After tool execution | Log results, trigger side effects |
| Agent notifications | Display status updates |
| User prompt received | Pre-process or validate input |
| Subagent spawned | Track delegation, log context |
| Subagent completed | Aggregate results, cleanup |
| Before context compaction | Save state before truncation |
| Permission needed | Custom approval workflows |
| Agent stopping | Cleanup, final logging |
| Session begins | Initialize state |
| Session ends | Persist state, cleanup |
| Error occurred | Custom error handling |
Hook Configuration:
typescript
const response = query({
prompt: "...",
options: {
hooks: {
PreToolUse: async (input) => {
console.log(`Tool: ${input.toolName}`);
return { allow: true }; // or { allow: false, message: "..." }
},
PostToolUse: async (input) => {
await logToolUsage(input.toolName, input.result);
}
}
}
});- - 失败时自动切换备用模型
fallbackModel - - 控制扩展思考预算
maxThinkingTokens - - 严格的MCP配置验证
strictMcpConfig - - 使用新提示恢复会话(与
continue不同)resume - - 用于规划工作流的新权限模式
permissionMode: 'plan'
4. Additional Options
Claude Agent SDK完整参考
—
目录
- - Automatic model fallback on failures
fallbackModel - - Control extended thinking budget
maxThinkingTokens - - Strict MCP configuration validation
strictMcpConfig - - Resume with new prompt (differs from
continue)resume - - New permission mode for planning workflows
permissionMode: 'plan'
The Complete Claude Agent SDK Reference
核心Query API
Table of Contents
—
- Core Query API
- Tool Integration
- MCP Servers
- Subagent Orchestration
- Session Management
- Permission Control
- Sandbox Settings
- File Checkpointing
- Filesystem Settings
- Query Object Methods
- Message Types & Streaming
- Error Handling
- Known Issues
关键签名:
typescript
query(prompt: string | AsyncIterable<SDKUserMessage>, options?: Options)
-> AsyncGenerator<SDKMessage>重要选项:
- - 结构化JSON schema验证(v0.1.45+)
outputFormat - - 文件系统设置加载来源('user'|'project'|'local')
settingSources - - 自定义权限逻辑回调
canUseTool - - 程序化子代理定义
agents - - MCP服务器配置
mcpServers - - 'default'|'acceptEdits'|'bypassPermissions'|'plan'
permissionMode - - 启用Beta功能(如1M上下文窗口)
betas - - 用于安全执行的沙箱设置
sandbox - - 启用文件状态快照
enableFileCheckpointing - - 系统提示(字符串或预设对象)
systemPrompt
Core Query API
扩展上下文(1M令牌)
Key signature:
typescript
query(prompt: string | AsyncIterable<SDKUserMessage>, options?: Options)
-> AsyncGenerator<SDKMessage>Critical Options:
- - Structured JSON schema validation (v0.1.45+)
outputFormat - - Filesystem settings loading ('user'|'project'|'local')
settingSources - - Custom permission logic callback
canUseTool - - Programmatic subagent definitions
agents - - MCP server configuration
mcpServers - - 'default'|'acceptEdits'|'bypassPermissions'|'plan'
permissionMode - - Enable beta features (e.g., 1M context window)
betas - - Sandbox settings for secure execution
sandbox - - Enable file state snapshots
enableFileCheckpointing - - System prompt (string or preset object)
systemPrompt
启用100万令牌上下文窗口:
typescript
const response = query({
prompt: "Analyze this large codebase",
options: {
betas: ['context-1m-2025-08-07'], // 启用1M上下文
model: "claude-sonnet-4-5"
}
});Extended Context (1M Tokens)
系统提示配置
Enable 1 million token context window:
typescript
const response = query({
prompt: "Analyze this large codebase",
options: {
betas: ['context-1m-2025-08-07'], // Enable 1M context
model: "claude-sonnet-4-5"
}
});两种systemPrompt形式:
typescript
// 1. 简单字符串
systemPrompt: "You are a helpful coding assistant."
// 2. 预设形式(保留Claude Code默认行为并添加自定义内容)
systemPrompt: {
type: 'preset',
preset: 'claude_code',
append: "\n\nAdditional context: Focus on security."
}推荐使用预设形式,这样既能保留Claude Code的默认行为,又能添加自定义内容。
System Prompt Configuration
工具集成(内置+自定义)
Two forms of systemPrompt:
typescript
// 1. Simple string
systemPrompt: "You are a helpful coding assistant."
// 2. Preset with optional append (preserves Claude Code defaults)
systemPrompt: {
type: 'preset',
preset: 'claude_code',
append: "\n\nAdditional context: Focus on security."
}Use preset form when you want Claude Code's default behaviors plus custom additions.
工具控制:
- - 白名单(优先级最高)
allowedTools - - 黑名单
disallowedTools - - 自定义权限回调(见权限控制章节)
canUseTool
内置工具: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch, Task, NotebookEdit, BashOutput, KillBash, ListMcpResources, ReadMcpResource, AskUserQuestion
Tool Integration (Built-in + Custom)
AskUserQuestion工具(v0.1.71+)
Tool Control:
- - Whitelist (takes precedence)
allowedTools - - Blacklist
disallowedTools - - Custom permission callback (see Permission Control section)
canUseTool
Built-in Tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch, Task, NotebookEdit, BashOutput, KillBash, ListMcpResources, ReadMcpResource, AskUserQuestion
允许代理执行过程中与用户交互:
typescript
const response = query({
prompt: "Review and refactor the codebase",
options: {
allowedTools: ["Read", "Write", "Edit", "AskUserQuestion"]
}
});
// 代理现在可以提出澄清问题
// 问题会以tool_call形式出现在消息流中,名称为"AskUserQuestion"适用场景:
- 任务执行中澄清模糊需求
- 执行破坏性操作前获取用户批准
- 提供选项并获取用户选择
AskUserQuestion Tool (v0.1.71+)
工具配置(v0.1.57+)
Enable user interaction during agent execution:
typescript
const response = query({
prompt: "Review and refactor the codebase",
options: {
allowedTools: ["Read", "Write", "Edit", "AskUserQuestion"]
}
});
// Agent can now ask clarifying questions
// Questions appear in message stream as tool_call with name "AskUserQuestion"Use cases:
- Clarify ambiguous requirements mid-task
- Get user approval before destructive operations
- Present options and get selection
三种工具配置形式:
typescript
// 1. 精确白名单(字符串数组)
tools: ["Read", "Write", "Grep"]
// 2. 禁用所有工具(空数组)
tools: []
// 3. 预设默认值(对象形式)
tools: { type: 'preset', preset: 'claude_code' }注意: 和仍然可用,但提供了更大的灵活性。
allowedToolsdisallowedToolstoolsTools Configuration (v0.1.57+)
MCP服务器(模型上下文协议)
Three forms of tool configuration:
typescript
// 1. Exact allowlist (string array)
tools: ["Read", "Write", "Grep"]
// 2. Disable all tools (empty array)
tools: []
// 3. Preset with defaults (object form)
tools: { type: 'preset', preset: 'claude_code' }Note: and still work but provides more flexibility.
allowedToolsdisallowedToolstools服务器类型:
- 进程内 - 使用和
createSdkMcpServer()定义tool() - 外部 - stdio、HTTP、SSE传输
工具定义:
typescript
tool(name: string, description: string, zodSchema, handler)处理器返回值:
typescript
{ content: [{ type: "text", text: "..." }], isError?: boolean }MCP Servers (Model Context Protocol)
外部MCP服务器(stdio)
Server Types:
- In-process - with
createSdkMcpServer()definitionstool() - External - stdio, HTTP, SSE transport
Tool Definition:
typescript
tool(name: string, description: string, zodSchema, handler)Handler Return:
typescript
{ content: [{ type: "text", text: "..." }], isError?: boolean }typescript
const response = query({
prompt: "List files and analyze Git history",
options: {
mcpServers: {
// 文件系统服务器
"filesystem": {
command: "npx",
args: ["@modelcontextprotocol/server-filesystem"],
env: {
ALLOWED_PATHS: "/Users/developer/projects:/tmp"
}
},
// Git操作服务器
"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 (stdio)
外部MCP服务器(HTTP/SSE)
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"
]
}
});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"]
}
});External MCP Servers (HTTP/SSE)
MCP工具命名规范
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__<server-name>__<tool-name>关键注意事项:
- 服务器名称和工具名称必须与配置匹配
- 使用双下划线()作为分隔符
__ - 需添加到数组中
allowedTools
示例: ,
mcp__weather-service__get_weathermcp__filesystem__read_fileMCP Tool Naming Convention
子代理编排
—
AgentDefinition类型
Format:
mcp__<server-name>__<tool-name>CRITICAL:
- Server name and tool name MUST match configuration
- Use double underscores () as separators
__ - Include in array
allowedTools
Examples: ,
mcp__weather-service__get_weathermcp__filesystem__read_filetypescript
type AgentDefinition = {
description: string; // 该代理的适用场景
prompt: string; // 代理的系统提示
tools?: string[]; // 允许使用的工具(可选)
model?: 'sonnet' | 'opus' | 'haiku' | 'inherit'; // 模型(可选)
skills?: string[]; // 加载的技能(v0.2.10+)
maxTurns?: number; // 停止前的最大轮次(v0.2.10+)
}字段详情:
- description: 代理的适用场景(主代理用于任务委托)
- prompt: 系统提示(定义角色,继承主上下文)
- tools: 允许使用的工具(若省略,继承自主代理)
- model: 模型覆盖选项(/
haiku/sonnet/opus)inherit - skills: 为代理加载的技能(v0.2.10+)
- maxTurns: 代理返回控制权前的最大轮次(v0.2.10+)
用法:
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",
skills: ["security-best-practices"], // 加载特定技能
maxTurns: 10 // 限制为10轮
}
}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)
skills?: string[]; // Skills to load (v0.2.10+)
maxTurns?: number; // Maximum turns before stopping (v0.2.10+)
}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 - skills: Skills to load for agent (v0.2.10+)
- maxTurns: Limit agent to N turns before returning control (v0.2.10+)
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",
skills: ["security-best-practices"], // Load specific skills
maxTurns: 10 // Limit to 10 turns
}
}已知问题: 父代理停止时,子代理不会自动停止(Issue #132)
当父代理停止(通过取消或错误)时,已生成的子代理会作为孤立进程继续运行,可能导致:
- 资源泄漏
- 父代理停止后工具仍继续执行
- 递归场景下内存不足(Claude Code Issue #4850)
解决方法: 在Stop钩子中实现清理逻辑:
typescript
const response = query({
prompt: "Deploy to production",
options: {
agents: {
"deployer": {
description: "Handle deployments",
prompt: "Deploy the application",
tools: ["Bash"]
}
},
hooks: {
Stop: async (input) => {
// 手动清理生成的进程
console.log("Parent stopped - cleaning up subagents");
// 实现进程跟踪和终止逻辑
}
}
}
});增强功能跟踪: Issue #142 提出了自动终止的建议
⚠️ Subagent Cleanup Warning
会话管理
Known Issue: Subagents don't stop when parent agent stops (Issue #132)
When a parent agent is stopped (via cancellation or error), spawned subagents continue running as orphaned processes. This can lead to:
- Resource leaks
- Continued tool execution after parent stopped
- RAM out-of-memory in recursive scenarios (Claude Code Issue #4850)
Workaround: Implement cleanup in Stop hooks:
typescript
const response = query({
prompt: "Deploy to production",
options: {
agents: {
"deployer": {
description: "Handle deployments",
prompt: "Deploy the application",
tools: ["Bash"]
}
},
hooks: {
Stop: async (input) => {
// Manual cleanup of spawned processes
console.log("Parent stopped - cleaning up subagents");
// Implement process tracking and termination
}
}
}
});Enhancement Tracking: Issue #142 proposes auto-termination
选项:
- - 继续之前的会话
resume: sessionId - - 从会话创建新分支
forkSession: true - - 使用新提示恢复会话(与
continue: prompt不同)resume
会话分支模式(独特功能):
typescript
// 在不修改原始会话的情况下探索替代方案
const forked = query({
prompt: "Try GraphQL instead of REST",
options: {
resume: sessionId,
forkSession: true // 创建新分支,原始会话保持不变
}
});捕获会话ID:
typescript
for await (const message of response) {
if (message.type === 'system' && message.subtype === 'init') {
sessionId = message.session_id; // 保存以便后续恢复/分支
}
}Session Management
V2会话API(预览版 - v0.1.54+)
Options:
- - Continue previous session
resume: sessionId - - Create new branch from session
forkSession: true - - Resume with new prompt (differs from
continue: prompt)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
}
}更简洁的多轮对话模式:
typescript
import {
unstable_v2_createSession,
unstable_v2_resumeSession,
unstable_v2_prompt
} from "@anthropic-ai/claude-agent-sdk";
// 创建新会话
const session = await unstable_v2_createSession({
model: "claude-sonnet-4-5",
workingDirectory: process.cwd(),
allowedTools: ["Read", "Grep", "Glob"]
});
// 发送提示并流式接收响应
const stream = unstable_v2_prompt(session, "Analyze the codebase structure");
for await (const message of stream) {
console.log(message);
}
// 在同一会话中继续对话
const stream2 = unstable_v2_prompt(session, "Now suggest improvements");
for await (const message of stream2) {
console.log(message);
}
// 恢复之前的会话
const resumedSession = await unstable_v2_resumeSession(session.sessionId);注意: V2 API处于预览阶段(带有前缀)。在v0.1.72版本中,方法已重命名为。
unstable_.receive().stream()V2 Session APIs (Preview - v0.1.54+)
权限控制
Simpler multi-turn conversation pattern:
typescript
import {
unstable_v2_createSession,
unstable_v2_resumeSession,
unstable_v2_prompt
} from "@anthropic-ai/claude-agent-sdk";
// Create a new session
const session = await unstable_v2_createSession({
model: "claude-sonnet-4-5",
workingDirectory: process.cwd(),
allowedTools: ["Read", "Grep", "Glob"]
});
// Send prompts and stream responses
const stream = unstable_v2_prompt(session, "Analyze the codebase structure");
for await (const message of stream) {
console.log(message);
}
// Continue conversation in same session
const stream2 = unstable_v2_prompt(session, "Now suggest improvements");
for await (const message of stream2) {
console.log(message);
}
// Resume a previous session
const resumedSession = await unstable_v2_resumeSession(session.sessionId);Note: V2 APIs are in preview ( prefix). The method was renamed to in v0.1.72.
unstable_.receive().stream()权限模式:
typescript
type PermissionMode = "default" | "acceptEdits" | "bypassPermissions" | "plan";- - 标准权限检查
default - - 自动批准文件编辑
acceptEdits - - 跳过所有检查(仅在CI/CD中使用)
bypassPermissions - - 规划模式(v0.1.45+)
plan
Permission Control
自定义权限逻辑
Permission Modes:
typescript
type PermissionMode = "default" | "acceptEdits" | "bypassPermissions" | "plan";- - Standard permission checks
default - - Auto-approve file edits
acceptEdits - - Skip ALL checks (use in CI/CD only)
bypassPermissions - - Planning mode (v0.1.45+)
plan
typescript
const response = query({
prompt: "Deploy application to production",
options: {
permissionMode: "default",
canUseTool: async (toolName, input) => {
// 允许只读操作
if (['Read', 'Grep', 'Glob'].includes(toolName)) {
return { behavior: "allow" };
}
// 阻止破坏性bash命令
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"
};
}
}
// 部署操作需要确认
if (input.command?.includes('deploy') || input.command?.includes('kubectl apply')) {
return {
behavior: "ask",
message: "Confirm deployment to production?"
};
}
// 默认允许
return { behavior: "allow" };
}
}
});Custom Permission Logic
canUseTool回调
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" };
}
}
});typescript
type CanUseToolCallback = (
toolName: string,
input: any
) => Promise<PermissionDecision>;
type PermissionDecision =
| { behavior: "allow" }
| { behavior: "deny"; message?: string }
| { behavior: "ask"; message?: string };示例:
typescript
// 阻止所有文件写入操作
canUseTool: async (toolName, input) => {
if (toolName === 'Write' || toolName === 'Edit') {
return { behavior: "deny", message: "No file modifications allowed" };
}
return { behavior: "allow" };
}
// 特定文件需要确认
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" };
}
// 记录所有工具使用情况
canUseTool: async (toolName, input) => {
console.log(`Tool requested: ${toolName}`, input);
await logToDatabase(toolName, input);
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" };
}为Bash命令启用沙箱执行:
typescript
const response = query({
prompt: "Run system diagnostics",
options: {
sandbox: {
enabled: true,
autoAllowBashIfSandboxed: true, // 沙箱中自动批准bash命令
excludedCommands: ["rm", "dd", "mkfs"], // 永远需要权限的命令
allowUnsandboxedCommands: false // 拒绝无法沙箱化的命令
}
}
});Sandbox Settings (Security-Critical)
SandboxSettings类型
Enable sandboxed execution for Bash commands:
typescript
const response = query({
prompt: "Run system diagnostics",
options: {
sandbox: {
enabled: true,
autoAllowBashIfSandboxed: true, // Auto-approve bash in sandbox
excludedCommands: ["rm", "dd", "mkfs"], // Never auto-approve these
allowUnsandboxedCommands: false // Deny unsandboxable commands
}
}
});typescript
type SandboxSettings = {
enabled: boolean;
autoAllowBashIfSandboxed?: boolean; // 默认值: false
excludedCommands?: string[];
allowUnsandboxedCommands?: boolean; // 默认值: false
network?: NetworkSandboxSettings;
ignoreViolations?: SandboxIgnoreViolations;
};
type NetworkSandboxSettings = {
enabled: boolean;
proxyUrl?: string; // 网络请求的HTTP代理
};关键选项:
- - 激活沙箱隔离
enabled - - 跳过安全bash命令的权限提示
autoAllowBashIfSandboxed - - 始终需要权限的命令
excludedCommands - - 允许无法沙箱化的命令(有风险)
allowUnsandboxedCommands - - 通过代理路由网络请求以进行监控
network.proxyUrl
最佳实践: 在处理不受信任输入的生产代理中始终使用沙箱。
SandboxSettings Type
文件检查点
typescript
type SandboxSettings = {
enabled: boolean;
autoAllowBashIfSandboxed?: boolean; // Default: false
excludedCommands?: string[];
allowUnsandboxedCommands?: boolean; // Default: false
network?: NetworkSandboxSettings;
ignoreViolations?: SandboxIgnoreViolations;
};
type NetworkSandboxSettings = {
enabled: boolean;
proxyUrl?: string; // HTTP proxy for network requests
};Key Options:
- - Activate sandbox isolation
enabled - - Skip permission prompts for safe bash commands
autoAllowBashIfSandboxed - - Commands that always require permission
excludedCommands - - Allow commands that can't be sandboxed (risky)
allowUnsandboxedCommands - - Route network through proxy for monitoring
network.proxyUrl
Best Practice: Always use sandbox in production agents handling untrusted input.
启用文件状态快照以支持回滚功能:
typescript
const response = query({
prompt: "Refactor the authentication module",
options: {
enableFileCheckpointing: true // 启用文件快照
}
});
// 后续: 将文件更改回滚到特定点
for await (const message of response) {
if (message.type === 'user' && message.uuid) {
// 后续可以回滚到该点
const userMessageUuid = message.uuid;
// 回滚操作(调用Query对象的方法)
await response.rewindFiles(userMessageUuid);
}
}适用场景:
- 撤销失败的重构尝试
- A/B测试代码变更
- 安全探索替代方案
File Checkpointing
文件系统设置
Enable file state snapshots for rollback capability:
typescript
const response = query({
prompt: "Refactor the authentication module",
options: {
enableFileCheckpointing: true // Enable file snapshots
}
});
// Later: rewind file changes to a specific point
for await (const message of response) {
if (message.type === 'user' && message.uuid) {
// Can rewind to this point later
const userMessageUuid = message.uuid;
// To rewind (call on Query object)
await response.rewindFiles(userMessageUuid);
}
}Use cases:
- Undo failed refactoring attempts
- A/B test code changes
- Safe exploration of alternatives
设置来源:
typescript
type SettingSource = 'user' | 'project' | 'local';- -
user(全局)~/.claude/settings.json - -
project(团队共享).claude/settings.json - -
local(Git忽略的本地覆盖配置).claude/settings.local.json
默认值: 不加载任何设置()
settingSources: []Filesystem Settings
设置优先级
Setting Sources:
typescript
type SettingSource = 'user' | 'project' | 'local';- -
user(global)~/.claude/settings.json - -
project(team-shared).claude/settings.json - -
local(gitignored overrides).claude/settings.local.json
Default: NO settings loaded ()
settingSources: []当加载多个来源时,设置按以下顺序合并(优先级从高到低):
- 程序化选项(传递给)- 优先级最高
query() - 本地设置()
.claude/settings.local.json - 项目设置()
.claude/settings.json - 用户设置()
~/.claude/settings.json
示例:
typescript
// .claude/settings.json
{
"allowedTools": ["Read", "Write", "Edit"]
}
// .claude/settings.local.json
{
"allowedTools": ["Read"] // 覆盖项目设置
}
// 程序化配置
const response = query({
options: {
settingSources: ["project", "local"],
allowedTools: ["Read", "Grep"] // ← 此配置优先级最高
}
});
// 实际生效的allowedTools: ["Read", "Grep"]最佳实践: 在CI/CD中使用以确保行为一致。
settingSources: ["project"]Settings Priority
Query对象方法
When multiple sources loaded, settings merge in this order (highest priority first):
- Programmatic options (passed to ) - Always win
query() - Local settings ()
.claude/settings.local.json - Project settings ()
.claude/settings.json - 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 in CI/CD for consistent behavior.
settingSources: ["project"]query()Querytypescript
const q = query({ prompt: "..." });
// 异步迭代(主要用法)
for await (const message of q) { ... }
// 运行时模型控制
await q.setModel("claude-opus-4-5"); // 会话中切换模型
await q.setMaxThinkingTokens(4096); // 设置思考预算
// 内省
const models = await q.supportedModels(); // 列出可用模型
const commands = await q.supportedCommands(); // 列出可用命令
const account = await q.accountInfo(); // 获取账户详情
// MCP状态
const status = await q.mcpServerStatus(); // 检查MCP服务器状态
// 返回值: { [serverName]: { status: 'connected' | 'failed', error?: string } }
// 文件操作(需要启用enableFileCheckpointing)
await q.rewindFiles(userMessageUuid); // 回滚到检查点适用场景:
- 根据任务复杂度动态切换模型
- 监控MCP服务器健康状态
- 为推理任务调整思考预算
Query Object Methods
消息类型与流式传输
The function returns a object with these methods:
query()Querytypescript
const q = query({ prompt: "..." });
// Async iteration (primary usage)
for await (const message of q) { ... }
// Runtime model control
await q.setModel("claude-opus-4-5"); // Change model mid-session
await q.setMaxThinkingTokens(4096); // Set thinking budget
// Introspection
const models = await q.supportedModels(); // List available models
const commands = await q.supportedCommands(); // List available commands
const account = await q.accountInfo(); // Get account details
// MCP status
const status = await q.mcpServerStatus(); // Check MCP server status
// Returns: { [serverName]: { status: 'connected' | 'failed', error?: string } }
// File operations (requires enableFileCheckpointing)
await q.rewindFiles(userMessageUuid); // Rewind to checkpointUse cases:
- Dynamic model switching based on task complexity
- Monitoring MCP server health
- Adjusting thinking budget for reasoning tasks
消息类型:
- - 会话初始化/完成(包含
system)session_id - - 代理响应
assistant - - 工具执行请求
tool_call - - 工具执行结果
tool_result - - 错误消息
error - - 最终结果(v0.1.45+包含
result)structured_output
流式传输模式:
typescript
for await (const message of response) {
if (message.type === 'system' && message.subtype === 'init') {
sessionId = message.session_id; // 捕获以便后续恢复/分支
}
if (message.type === 'result' && message.structured_output) {
// 结构化输出可用(v0.1.45+)
const validated = schema.parse(message.structured_output);
}
}Message Types & Streaming
错误处理
Message Types:
- - Session init/completion (includes
system)session_id - - Agent responses
assistant - - Tool execution requests
tool_call - - Tool execution results
tool_result - - Error messages
error - - Final result (includes
resultfor v0.1.45+)structured_output
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);
}
}错误代码:
| 错误代码 | 原因 | 解决方案 |
|---|---|---|
| 未安装Claude Code | 安装: |
| API密钥无效 | 检查ANTHROPIC_API_KEY环境变量 |
| 请求过多 | 实现带退避的重试机制 |
| 提示过长 | 使用会话压缩,减少上下文 |
| 工具被阻止 | 检查permissionMode和canUseTool配置 |
| 工具执行错误 | 检查工具实现 |
| 会话ID无效 | 验证会话ID |
| 服务器错误 | 检查服务器配置 |
Error Handling
已知问题与预防
Error Codes:
| Error Code | Cause | Solution |
|---|---|---|
| Claude Code not installed | Install: |
| Invalid API key | Check ANTHROPIC_API_KEY env var |
| Too many requests | Implement retry with backoff |
| Prompt too long | Use session compaction, reduce context |
| Tool blocked | Check permissionMode, canUseTool |
| Tool error | Check tool implementation |
| Invalid session ID | Verify session ID |
| Server error | Check server configuration |
本技能可预防14种已记录的问题:
Known Issues Prevention
问题#1: CLI未找到错误
This skill prevents 14 documented issues:
错误:
来源: SDK需要Claude Code CLI
原因: 未全局安装CLI
预防: 使用SDK前先安装:
"Claude Code CLI not installed"npm install -g @anthropic-ai/claude-codeIssue #1: CLI Not Found Error
问题#2: 认证失败
Error:
Source: SDK requires Claude Code CLI
Why It Happens: CLI not installed globally
Prevention: Install before using SDK:
"Claude Code CLI not installed"npm install -g @anthropic-ai/claude-code错误:
来源: 缺少或错误的ANTHROPIC_API_KEY
原因: 未设置环境变量
预防: 始终设置
"Invalid API key"export ANTHROPIC_API_KEY="sk-ant-..."Issue #2: Authentication Failed
问题#3: 权限拒绝错误
Error:
Source: Missing or incorrect ANTHROPIC_API_KEY
Why It Happens: Environment variable not set
Prevention: Always set
"Invalid API key"export ANTHROPIC_API_KEY="sk-ant-..."错误: 工具执行被阻止
来源: 限制
原因: 权限配置不允许使用该工具
预防: 使用或自定义回调
permissionModeallowedToolscanUseToolIssue #3: Permission Denied Errors
问题#4: 上下文长度超出(会话中断)
Error: Tool execution blocked
Source: restrictions
Why It Happens: Tool not allowed by permissions
Prevention: Use or custom callback
permissionModeallowedToolscanUseTool错误:
来源: 输入超出模型上下文窗口(Issue #138)
原因: 代码库过大、对话过长
"Prompt too long"⚠️ 关键行为: 一旦会话达到上下文限制:
- 该会话的所有后续请求都会返回"Prompt too long"
- 命令也会返回相同错误
/compact - 会话永久损坏,必须放弃
预防策略:
typescript
// 1. 主动创建会话分支(在达到限制前创建检查点)
const checkpoint = query({
prompt: "Checkpoint current state",
options: {
resume: sessionId,
forkSession: true // 在达到限制前创建分支
}
});
// 2. 监控时间并主动轮换会话
const MAX_SESSION_TIME = 80 * 60 * 1000; // 80分钟(在90分钟崩溃前)
let sessionStartTime = Date.now();
function shouldRotateSession() {
return Date.now() - sessionStartTime > MAX_SESSION_TIME;
}
// 3. 在达到上下文限制前启动新会话
if (shouldRotateSession()) {
const summary = await getSummary(currentSession);
const newSession = query({
prompt: `Continue with context: ${summary}`
});
sessionStartTime = Date.now();
}注意: SDK会自动压缩上下文,但如果达到限制,会话将无法恢复
Issue #4: Context Length Exceeded (Session-Breaking)
问题#5: 工具执行超时
Error:
Source: Input exceeds model context window (Issue #138)
Why It Happens: Large codebase, long conversations
"Prompt too long"⚠️ Critical Behavior: Once a session hits context limit:
- All subsequent requests to that session return "Prompt too long"
- command fails with same error
/compact - Session is permanently broken and must be abandoned
Prevention Strategies:
typescript
// 1. Proactive session forking (create checkpoints before hitting limit)
const checkpoint = query({
prompt: "Checkpoint current state",
options: {
resume: sessionId,
forkSession: true // Create branch before hitting limit
}
});
// 2. Monitor time and rotate sessions proactively
const MAX_SESSION_TIME = 80 * 60 * 1000; // 80 minutes (before 90-min crash)
let sessionStartTime = Date.now();
function shouldRotateSession() {
return Date.now() - sessionStartTime > MAX_SESSION_TIME;
}
// 3. Start new sessions before hitting context limits
if (shouldRotateSession()) {
const summary = await getSummary(currentSession);
const newSession = query({
prompt: `Continue with context: ${summary}`
});
sessionStartTime = Date.now();
}Note: SDK auto-compacts, but if limit is reached, session becomes unrecoverable
错误: 工具无响应
来源: 工具执行时间过长
原因: 工具执行时间超过默认5分钟限制
预防: 在工具实现中添加超时处理
Issue #5: Tool Execution Timeout
问题#6: 会话未找到
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
错误:
来源: 会话过期或无效
原因: 会话ID不正确或过旧
预防: 从初始化消息中捕获
"Invalid session ID"systemsession_idIssue #6: Session Not Found
问题#7: MCP服务器连接失败
Error:
Source: Session expired or invalid
Why It Happens: Session ID incorrect or too old
Prevention: Capture from init message
"Invalid session ID"session_idsystem错误: 服务器无响应
来源: 服务器未运行或配置错误
原因: 命令/URL不正确、服务器崩溃
预防: 独立测试MCP服务器,验证命令/URL
Issue #7: MCP Server Connection Failed
问题#8: 子代理定义错误
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
错误: 无效的AgentDefinition
来源: 缺少必填字段
原因: 缺少或字段
预防: 始终包含和字段
descriptionpromptdescriptionpromptIssue #8: Subagent Definition Errors
问题#9: 设置文件未找到
Error: Invalid AgentDefinition
Source: Missing required fields
Why It Happens: or missing
Prevention: Always include and fields
descriptionpromptdescriptionprompt错误:
来源: 设置文件不存在
原因: 包含不存在的文件
预防: 在添加到来源前检查文件是否存在
"Cannot read settings"settingSourcesIssue #9: Settings File Not Found
问题#10: 工具名称冲突
Error:
Source: Settings file doesn't exist
Why It Happens: includes non-existent file
Prevention: Check file exists before including in sources
"Cannot read settings"settingSources错误: 工具名称重复
来源: 多个工具使用相同名称
原因: 两个MCP服务器定义了相同的工具名称
预防: 使用唯一的工具名称,以服务器名称为前缀
Issue #10: Tool Name Collision
问题#11: Zod Schema验证错误
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
错误: 工具输入无效
来源: 输入不匹配Zod schema
原因: 代理提供了错误的数据类型
预防: 使用带的描述性Zod schema
.describe()Issue #11: Zod Schema Validation Error
问题#12: 文件系统权限拒绝
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()错误: 无法访问路径
来源: 文件系统访问受限
原因: 路径超出或无权限
预防: 设置正确的,检查文件权限
workingDirectoryworkingDirectoryIssue #12: Filesystem Permission Denied
问题#13: MCP服务器配置缺少type
字段
typeError: Cannot access path
Source: Restricted filesystem access
Why It Happens: Path outside or no permissions
Prevention: Set correct , check file permissions
workingDirectoryworkingDirectory错误: (信息模糊,无上下文)
来源: GitHub Issue #131
原因: 基于URL的MCP服务器需要显式的或字段
预防: 始终为基于URL的MCP服务器指定传输类型
"Claude Code process exited with code 1"type: "http"type: "sse"typescript
// ❌ 错误 - 缺少type字段(导致模糊的退出代码1)
mcpServers: {
"my-server": {
url: "https://api.example.com/mcp"
}
}
// ✅ 正确 - 基于URL的服务器需要type字段
mcpServers: {
"my-server": {
url: "https://api.example.com/mcp",
type: "http" // 或"sse"用于服务器发送事件
}
}诊断线索: 如果看到"process exited with code 1"且无其他上下文,请检查MCP服务器配置是否缺少字段。
typeIssue #13: MCP Server Config Missing type
Field
type问题#14: MCP工具结果包含Unicode行分隔符
Error: (cryptic, no context)
Source: GitHub Issue #131
Why It Happens: URL-based MCP servers require explicit or field
Prevention: Always specify transport type for URL-based MCP servers
"Claude Code process exited with code 1"type: "http"type: "sse"typescript
// ❌ Wrong - missing type field (causes cryptic exit code 1)
mcpServers: {
"my-server": {
url: "https://api.example.com/mcp"
}
}
// ✅ Correct - type field required for URL-based servers
mcpServers: {
"my-server": {
url: "https://api.example.com/mcp",
type: "http" // or "sse" for Server-Sent Events
}
}Diagnostic Clue: If you see "process exited with code 1" with no other context, check your MCP server configuration for missing fields.
type错误: JSON解析错误,代理挂起
来源: GitHub Issue #137
原因: Unicode U+2028(行分隔符)和U+2029(段落分隔符)在JSON中是合法的,但会破坏JavaScript解析
预防: 在MCP工具结果中转义这些字符
typescript
// MCP工具处理器 - 清理外部数据
tool("fetch_content", "Fetch text content", {}, async (args) => {
const content = await fetchExternalData();
// ✅ 清理Unicode行/段落分隔符
const sanitized = content
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
return {
content: [{ type: "text", text: sanitized }]
};
});适用场景: 外部数据源(API、网页抓取、用户输入)可能包含这些字符
Issue #14: MCP Tool Result with Unicode Line Separators
官方文档
Error: JSON parse error, agent hangs
Source: GitHub Issue #137
Why It Happens: Unicode U+2028 (line separator) and U+2029 (paragraph separator) are valid in JSON but break JavaScript parsing
Prevention: Escape these characters in MCP tool results
typescript
// MCP tool handler - sanitize external data
tool("fetch_content", "Fetch text content", {}, async (args) => {
const content = await fetchExternalData();
// ✅ Sanitize Unicode line/paragraph separators
const sanitized = content
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
return {
content: [{ type: "text", text: sanitized }]
};
});When This Matters: External data sources (APIs, web scraping, user input) that may contain these characters
Related: MCP Python SDK Issue #1356
- Agent SDK概述: https://platform.claude.com/docs/en/api/agent-sdk/overview
- TypeScript API: https://platform.claude.com/docs/en/api/agent-sdk/typescript
- 结构化输出: https://platform.claude.com/docs/en/agent-sdk/structured-outputs
- GitHub (TypeScript): https://github.com/anthropics/claude-agent-sdk-typescript
- 变更日志: https://github.com/anthropics/claude-agent-sdk-typescript/blob/main/CHANGELOG.md
令牌效率:
- 不使用本技能: ~15,000令牌(MCP设置、权限模式、会话API、沙箱配置、钩子、结构化输出、错误处理)
- 使用本技能: ~4,500令牌(全面覆盖v0.2.12版本 + 错误预防 + 高级模式)
- 节省: ~70%(约10,500令牌)
预防的错误: 14种已记录的问题及确切解决方案(包括2个社区发现的陷阱)
核心价值: V2会话API、沙箱设置、文件检查点、Query方法、AskUserQuestion工具、结构化输出(v0.1.45+)、会话分支、canUseTool模式、完整钩子系统(12种事件)、Zod v4支持、子代理清理模式
最后验证: 2026-01-20 | 技能版本: 3.1.0 | 变更: 添加问题#13(MCP type字段)、问题#14(Unicode U+2028/U+2029)、扩展问题#4(会话中断)、添加带Stop钩子模式的子代理清理警告
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: ~15,000 tokens (MCP setup, permission patterns, session APIs, sandbox config, hooks, structured outputs, error handling)
- With skill: ~4,500 tokens (comprehensive v0.2.12 coverage + error prevention + advanced patterns)
- Savings: ~70% (~10,500 tokens)
Errors prevented: 14 documented issues with exact solutions (including 2 community-sourced gotchas)
Key value: V2 Session APIs, Sandbox Settings, File Checkpointing, Query methods, AskUserQuestion tool, structured outputs (v0.1.45+), session forking, canUseTool patterns, complete hooks system (12 events), Zod v4 support, subagent cleanup patterns
Last verified: 2026-01-20 | Skill version: 3.1.0 | Changes: Added Issue #13 (MCP type field), Issue #14 (Unicode U+2028/U+2029), expanded Issue #4 (session-breaking), added subagent cleanup warning with Stop hook pattern
—