opencode-skills-antigravity 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-skills/ad-creative/SKILL.md +371 -0
- package/bundled-skills/ad-creative/evals/evals.json +90 -0
- package/bundled-skills/ad-creative/references/generative-tools.md +637 -0
- package/bundled-skills/ad-creative/references/platform-specs.md +213 -0
- package/bundled-skills/ai-seo/SKILL.md +407 -0
- package/bundled-skills/ai-seo/evals/evals.json +90 -0
- package/bundled-skills/ai-seo/references/content-patterns.md +285 -0
- package/bundled-skills/ai-seo/references/platform-ranking-factors.md +152 -0
- package/bundled-skills/backend-dev-guidelines/SKILL.md +1 -1
- package/bundled-skills/cc-skill-security-review/SKILL.md +1 -1
- package/bundled-skills/churn-prevention/SKILL.md +433 -0
- package/bundled-skills/churn-prevention/evals/evals.json +93 -0
- package/bundled-skills/churn-prevention/references/cancel-flow-patterns.md +316 -0
- package/bundled-skills/churn-prevention/references/dunning-playbook.md +408 -0
- package/bundled-skills/claude-api/LICENSE.txt +202 -0
- package/bundled-skills/claude-api/SKILL.md +252 -0
- package/bundled-skills/claude-api/csharp/claude-api.md +70 -0
- package/bundled-skills/claude-api/curl/examples.md +164 -0
- package/bundled-skills/claude-api/go/claude-api.md +146 -0
- package/bundled-skills/claude-api/java/claude-api.md +128 -0
- package/bundled-skills/claude-api/php/claude-api.md +88 -0
- package/bundled-skills/claude-api/python/agent-sdk/README.md +269 -0
- package/bundled-skills/claude-api/python/agent-sdk/patterns.md +319 -0
- package/bundled-skills/claude-api/python/claude-api/README.md +404 -0
- package/bundled-skills/claude-api/python/claude-api/batches.md +182 -0
- package/bundled-skills/claude-api/python/claude-api/files-api.md +162 -0
- package/bundled-skills/claude-api/python/claude-api/streaming.md +162 -0
- package/bundled-skills/claude-api/python/claude-api/tool-use.md +587 -0
- package/bundled-skills/claude-api/ruby/claude-api.md +87 -0
- package/bundled-skills/claude-api/shared/error-codes.md +205 -0
- package/bundled-skills/claude-api/shared/live-sources.md +121 -0
- package/bundled-skills/claude-api/shared/models.md +68 -0
- package/bundled-skills/claude-api/shared/tool-use-concepts.md +305 -0
- package/bundled-skills/claude-api/typescript/agent-sdk/README.md +220 -0
- package/bundled-skills/claude-api/typescript/agent-sdk/patterns.md +150 -0
- package/bundled-skills/claude-api/typescript/claude-api/README.md +313 -0
- package/bundled-skills/claude-api/typescript/claude-api/batches.md +106 -0
- package/bundled-skills/claude-api/typescript/claude-api/files-api.md +98 -0
- package/bundled-skills/claude-api/typescript/claude-api/streaming.md +178 -0
- package/bundled-skills/claude-api/typescript/claude-api/tool-use.md +477 -0
- package/bundled-skills/codex-review/SKILL.md +1 -1
- package/bundled-skills/cold-email/SKILL.md +167 -0
- package/bundled-skills/cold-email/evals/evals.json +94 -0
- package/bundled-skills/cold-email/references/benchmarks.md +83 -0
- package/bundled-skills/cold-email/references/follow-up-sequences.md +81 -0
- package/bundled-skills/cold-email/references/frameworks.md +90 -0
- package/bundled-skills/cold-email/references/personalization.md +79 -0
- package/bundled-skills/cold-email/references/subject-lines.md +53 -0
- package/bundled-skills/content-strategy/SKILL.md +374 -0
- package/bundled-skills/content-strategy/evals/evals.json +90 -0
- package/bundled-skills/content-strategy/references/headless-cms.md +194 -0
- package/bundled-skills/context7-auto-research/SKILL.md +1 -1
- package/bundled-skills/dbos-golang/SKILL.md +1 -1
- package/bundled-skills/dbos-python/SKILL.md +1 -1
- package/bundled-skills/dbos-typescript/SKILL.md +1 -1
- package/bundled-skills/debug-buttercup/SKILL.md +1 -1
- package/bundled-skills/defuddle/SKILL.md +50 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/integrations/jetski-gemini-loader/package.json +1 -0
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-import-2026-03-21.md +81 -0
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/evaluation/SKILL.md +1 -1
- package/bundled-skills/exa-search/SKILL.md +1 -1
- package/bundled-skills/firecrawl-scraper/SKILL.md +1 -1
- package/bundled-skills/frontend-dev-guidelines/SKILL.md +1 -1
- package/bundled-skills/gha-security-review/SKILL.md +2 -1
- package/bundled-skills/git-pushing/SKILL.md +1 -1
- package/bundled-skills/internal-comms/LICENSE.txt +202 -0
- package/bundled-skills/internal-comms/SKILL.md +35 -0
- package/bundled-skills/internal-comms/examples/3p-updates.md +47 -0
- package/bundled-skills/internal-comms/examples/company-newsletter.md +65 -0
- package/bundled-skills/internal-comms/examples/faq-answers.md +30 -0
- package/bundled-skills/internal-comms/examples/general-comms.md +16 -0
- package/bundled-skills/json-canvas/SKILL.md +253 -0
- package/bundled-skills/json-canvas/references/EXAMPLES.md +329 -0
- package/bundled-skills/lead-magnets/SKILL.md +319 -0
- package/bundled-skills/lead-magnets/references/benchmarks.md +129 -0
- package/bundled-skills/lead-magnets/references/format-guide.md +196 -0
- package/bundled-skills/memory-systems/SKILL.md +1 -1
- package/bundled-skills/obsidian-bases/SKILL.md +506 -0
- package/bundled-skills/obsidian-bases/references/FUNCTIONS_REFERENCE.md +173 -0
- package/bundled-skills/obsidian-cli/SKILL.md +115 -0
- package/bundled-skills/obsidian-markdown/SKILL.md +205 -0
- package/bundled-skills/obsidian-markdown/references/CALLOUTS.md +58 -0
- package/bundled-skills/obsidian-markdown/references/EMBEDS.md +63 -0
- package/bundled-skills/obsidian-markdown/references/PROPERTIES.md +61 -0
- package/bundled-skills/product-marketing-context/SKILL.md +250 -0
- package/bundled-skills/product-marketing-context/evals/evals.json +85 -0
- package/bundled-skills/react-best-practices/SKILL.md +1 -1
- package/bundled-skills/revops/SKILL.md +352 -0
- package/bundled-skills/revops/evals/evals.json +91 -0
- package/bundled-skills/revops/references/automation-playbooks.md +290 -0
- package/bundled-skills/revops/references/lifecycle-definitions.md +278 -0
- package/bundled-skills/revops/references/routing-rules.md +203 -0
- package/bundled-skills/revops/references/scoring-models.md +247 -0
- package/bundled-skills/sales-enablement/SKILL.md +358 -0
- package/bundled-skills/sales-enablement/evals/evals.json +91 -0
- package/bundled-skills/sales-enablement/references/deck-frameworks.md +263 -0
- package/bundled-skills/sales-enablement/references/demo-scripts.md +355 -0
- package/bundled-skills/sales-enablement/references/objection-library.md +270 -0
- package/bundled-skills/sales-enablement/references/one-pager-templates.md +208 -0
- package/bundled-skills/seo/SKILL.md +139 -0
- package/bundled-skills/seo/references/cwv-thresholds.md +108 -0
- package/bundled-skills/seo/references/eeat-framework.md +214 -0
- package/bundled-skills/seo/references/quality-gates.md +155 -0
- package/bundled-skills/seo/references/schema-types.md +118 -0
- package/bundled-skills/seo-competitor-pages/SKILL.md +229 -0
- package/bundled-skills/seo-content/SKILL.md +186 -0
- package/bundled-skills/seo-dataforseo/SKILL.md +395 -0
- package/bundled-skills/seo-geo/SKILL.md +254 -0
- package/bundled-skills/seo-hreflang/SKILL.md +209 -0
- package/bundled-skills/seo-image-gen/SKILL.md +183 -0
- package/bundled-skills/seo-images/SKILL.md +193 -0
- package/bundled-skills/seo-page/SKILL.md +103 -0
- package/bundled-skills/seo-plan/SKILL.md +136 -0
- package/bundled-skills/seo-plan/assets/agency.md +175 -0
- package/bundled-skills/seo-plan/assets/ecommerce.md +167 -0
- package/bundled-skills/seo-plan/assets/generic.md +144 -0
- package/bundled-skills/seo-plan/assets/local-service.md +160 -0
- package/bundled-skills/seo-plan/assets/publisher.md +153 -0
- package/bundled-skills/seo-plan/assets/saas.md +135 -0
- package/bundled-skills/seo-programmatic/SKILL.md +184 -0
- package/bundled-skills/seo-schema/SKILL.md +178 -0
- package/bundled-skills/seo-sitemap/SKILL.md +129 -0
- package/bundled-skills/seo-technical/SKILL.md +175 -0
- package/bundled-skills/site-architecture/SKILL.md +366 -0
- package/bundled-skills/site-architecture/evals/evals.json +88 -0
- package/bundled-skills/site-architecture/references/mermaid-templates.md +216 -0
- package/bundled-skills/site-architecture/references/navigation-patterns.md +305 -0
- package/bundled-skills/site-architecture/references/site-type-templates.md +293 -0
- package/bundled-skills/skill-improver/SKILL.md +1 -1
- package/bundled-skills/tavily-web/SKILL.md +1 -1
- package/bundled-skills/test-fixing/SKILL.md +1 -1
- package/bundled-skills/tool-design/SKILL.md +1 -1
- package/bundled-skills/ui-ux-pro-max/SKILL.md +1 -1
- package/bundled-skills/verification-before-completion/SKILL.md +1 -1
- package/bundled-skills/wiki-changelog/SKILL.md +1 -1
- package/bundled-skills/wiki-onboarding/SKILL.md +1 -1
- package/bundled-skills/wiki-qa/SKILL.md +1 -1
- package/bundled-skills/wiki-researcher/SKILL.md +1 -1
- package/bundled-skills/wiki-vitepress/SKILL.md +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# Agent SDK Patterns — Python
|
|
2
|
+
|
|
3
|
+
## Basic Agent
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
import anyio
|
|
7
|
+
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
|
|
8
|
+
|
|
9
|
+
async def main():
|
|
10
|
+
async for message in query(
|
|
11
|
+
prompt="Explain what this repository does",
|
|
12
|
+
options=ClaudeAgentOptions(
|
|
13
|
+
cwd="/path/to/project",
|
|
14
|
+
allowed_tools=["Read", "Glob", "Grep"]
|
|
15
|
+
)
|
|
16
|
+
):
|
|
17
|
+
if isinstance(message, ResultMessage):
|
|
18
|
+
print(message.result)
|
|
19
|
+
|
|
20
|
+
anyio.run(main)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Custom Tools
|
|
26
|
+
|
|
27
|
+
Custom tools require an MCP server. Use `ClaudeSDKClient` for full control, or pass the server to `query()` via `mcp_servers`.
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import anyio
|
|
31
|
+
from claude_agent_sdk import (
|
|
32
|
+
tool,
|
|
33
|
+
create_sdk_mcp_server,
|
|
34
|
+
ClaudeSDKClient,
|
|
35
|
+
ClaudeAgentOptions,
|
|
36
|
+
AssistantMessage,
|
|
37
|
+
TextBlock,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
@tool("get_weather", "Get the current weather for a location", {"location": str})
|
|
41
|
+
async def get_weather(args):
|
|
42
|
+
location = args["location"]
|
|
43
|
+
return {"content": [{"type": "text", "text": f"The weather in {location} is sunny and 72°F."}]}
|
|
44
|
+
|
|
45
|
+
server = create_sdk_mcp_server("weather-tools", tools=[get_weather])
|
|
46
|
+
|
|
47
|
+
async def main():
|
|
48
|
+
options = ClaudeAgentOptions(mcp_servers={"weather": server})
|
|
49
|
+
async with ClaudeSDKClient(options=options) as client:
|
|
50
|
+
await client.query("What's the weather in Paris?")
|
|
51
|
+
async for message in client.receive_response():
|
|
52
|
+
if isinstance(message, AssistantMessage):
|
|
53
|
+
for block in message.content:
|
|
54
|
+
if isinstance(block, TextBlock):
|
|
55
|
+
print(block.text)
|
|
56
|
+
|
|
57
|
+
anyio.run(main)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Hooks
|
|
63
|
+
|
|
64
|
+
### After Tool Use Hook
|
|
65
|
+
|
|
66
|
+
Log file changes after any edit:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import anyio
|
|
70
|
+
from datetime import datetime
|
|
71
|
+
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, ResultMessage
|
|
72
|
+
|
|
73
|
+
async def log_file_change(input_data, tool_use_id, context):
|
|
74
|
+
file_path = input_data.get('tool_input', {}).get('file_path', 'unknown')
|
|
75
|
+
with open('./audit.log', 'a') as f:
|
|
76
|
+
f.write(f"{datetime.now()}: modified {file_path}\n")
|
|
77
|
+
return {}
|
|
78
|
+
|
|
79
|
+
async def main():
|
|
80
|
+
async for message in query(
|
|
81
|
+
prompt="Refactor utils.py to improve readability",
|
|
82
|
+
options=ClaudeAgentOptions(
|
|
83
|
+
allowed_tools=["Read", "Edit", "Write"],
|
|
84
|
+
permission_mode="acceptEdits",
|
|
85
|
+
hooks={
|
|
86
|
+
"PostToolUse": [HookMatcher(matcher="Edit|Write", hooks=[log_file_change])]
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
):
|
|
90
|
+
if isinstance(message, ResultMessage):
|
|
91
|
+
print(message.result)
|
|
92
|
+
|
|
93
|
+
anyio.run(main)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Subagents
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import anyio
|
|
102
|
+
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, ResultMessage
|
|
103
|
+
|
|
104
|
+
async def main():
|
|
105
|
+
async for message in query(
|
|
106
|
+
prompt="Use the code-reviewer agent to review this codebase",
|
|
107
|
+
options=ClaudeAgentOptions(
|
|
108
|
+
allowed_tools=["Read", "Glob", "Grep", "Agent"],
|
|
109
|
+
agents={
|
|
110
|
+
"code-reviewer": AgentDefinition(
|
|
111
|
+
description="Expert code reviewer for quality and security reviews.",
|
|
112
|
+
prompt="Analyze code quality and suggest improvements.",
|
|
113
|
+
tools=["Read", "Glob", "Grep"]
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
):
|
|
118
|
+
if isinstance(message, ResultMessage):
|
|
119
|
+
print(message.result)
|
|
120
|
+
|
|
121
|
+
anyio.run(main)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## MCP Server Integration
|
|
127
|
+
|
|
128
|
+
### Browser Automation (Playwright)
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import anyio
|
|
132
|
+
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
|
|
133
|
+
|
|
134
|
+
async def main():
|
|
135
|
+
async for message in query(
|
|
136
|
+
prompt="Open example.com and describe what you see",
|
|
137
|
+
options=ClaudeAgentOptions(
|
|
138
|
+
mcp_servers={
|
|
139
|
+
"playwright": {"command": "npx", "args": ["@playwright/mcp@latest"]}
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
):
|
|
143
|
+
if isinstance(message, ResultMessage):
|
|
144
|
+
print(message.result)
|
|
145
|
+
|
|
146
|
+
anyio.run(main)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Database Access (PostgreSQL)
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
import os
|
|
153
|
+
import anyio
|
|
154
|
+
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
|
|
155
|
+
|
|
156
|
+
async def main():
|
|
157
|
+
async for message in query(
|
|
158
|
+
prompt="Show me the top 10 users by order count",
|
|
159
|
+
options=ClaudeAgentOptions(
|
|
160
|
+
mcp_servers={
|
|
161
|
+
"postgres": {
|
|
162
|
+
"command": "npx",
|
|
163
|
+
"args": ["-y", "@modelcontextprotocol/server-postgres"],
|
|
164
|
+
"env": {"DATABASE_URL": os.environ["DATABASE_URL"]}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
):
|
|
169
|
+
if isinstance(message, ResultMessage):
|
|
170
|
+
print(message.result)
|
|
171
|
+
|
|
172
|
+
anyio.run(main)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Permission Modes
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
import anyio
|
|
181
|
+
from claude_agent_sdk import query, ClaudeAgentOptions
|
|
182
|
+
|
|
183
|
+
async def main():
|
|
184
|
+
# Default: prompt for dangerous operations
|
|
185
|
+
async for message in query(
|
|
186
|
+
prompt="Delete all test files",
|
|
187
|
+
options=ClaudeAgentOptions(
|
|
188
|
+
allowed_tools=["Bash"],
|
|
189
|
+
permission_mode="default" # Will prompt before deleting
|
|
190
|
+
)
|
|
191
|
+
):
|
|
192
|
+
pass
|
|
193
|
+
|
|
194
|
+
# Plan: agent creates a plan before making changes
|
|
195
|
+
async for message in query(
|
|
196
|
+
prompt="Refactor the auth system",
|
|
197
|
+
options=ClaudeAgentOptions(
|
|
198
|
+
allowed_tools=["Read", "Edit"],
|
|
199
|
+
permission_mode="plan"
|
|
200
|
+
)
|
|
201
|
+
):
|
|
202
|
+
pass
|
|
203
|
+
|
|
204
|
+
# Accept edits: auto-accept file edits
|
|
205
|
+
async for message in query(
|
|
206
|
+
prompt="Refactor this module",
|
|
207
|
+
options=ClaudeAgentOptions(
|
|
208
|
+
allowed_tools=["Read", "Edit"],
|
|
209
|
+
permission_mode="acceptEdits"
|
|
210
|
+
)
|
|
211
|
+
):
|
|
212
|
+
pass
|
|
213
|
+
|
|
214
|
+
# Bypass: skip all prompts (use with caution)
|
|
215
|
+
async for message in query(
|
|
216
|
+
prompt="Set up the development environment",
|
|
217
|
+
options=ClaudeAgentOptions(
|
|
218
|
+
allowed_tools=["Bash", "Write"],
|
|
219
|
+
permission_mode="bypassPermissions",
|
|
220
|
+
allow_dangerously_skip_permissions=True
|
|
221
|
+
)
|
|
222
|
+
):
|
|
223
|
+
pass
|
|
224
|
+
|
|
225
|
+
anyio.run(main)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Error Recovery
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
import anyio
|
|
234
|
+
from claude_agent_sdk import (
|
|
235
|
+
query,
|
|
236
|
+
ClaudeAgentOptions,
|
|
237
|
+
CLINotFoundError,
|
|
238
|
+
CLIConnectionError,
|
|
239
|
+
ProcessError,
|
|
240
|
+
ResultMessage,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
async def run_with_recovery():
|
|
244
|
+
try:
|
|
245
|
+
async for message in query(
|
|
246
|
+
prompt="Fix the failing tests",
|
|
247
|
+
options=ClaudeAgentOptions(
|
|
248
|
+
allowed_tools=["Read", "Edit", "Bash"],
|
|
249
|
+
max_turns=10
|
|
250
|
+
)
|
|
251
|
+
):
|
|
252
|
+
if isinstance(message, ResultMessage):
|
|
253
|
+
print(message.result)
|
|
254
|
+
except CLINotFoundError:
|
|
255
|
+
print("Claude Code CLI not found. Install with: pip install claude-agent-sdk")
|
|
256
|
+
except CLIConnectionError as e:
|
|
257
|
+
print(f"Connection error: {e}")
|
|
258
|
+
except ProcessError as e:
|
|
259
|
+
print(f"Process error: {e}")
|
|
260
|
+
|
|
261
|
+
anyio.run(run_with_recovery)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Session Resumption
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
import anyio
|
|
270
|
+
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage, SystemMessage
|
|
271
|
+
|
|
272
|
+
async def main():
|
|
273
|
+
session_id = None
|
|
274
|
+
|
|
275
|
+
# First query: capture the session ID
|
|
276
|
+
async for message in query(
|
|
277
|
+
prompt="Read the authentication module",
|
|
278
|
+
options=ClaudeAgentOptions(allowed_tools=["Read", "Glob"])
|
|
279
|
+
):
|
|
280
|
+
if isinstance(message, SystemMessage) and message.subtype == "init":
|
|
281
|
+
session_id = message.session_id
|
|
282
|
+
|
|
283
|
+
# Resume with full context from the first query
|
|
284
|
+
async for message in query(
|
|
285
|
+
prompt="Now find all places that call it", # "it" = auth module
|
|
286
|
+
options=ClaudeAgentOptions(resume=session_id)
|
|
287
|
+
):
|
|
288
|
+
if isinstance(message, ResultMessage):
|
|
289
|
+
print(message.result)
|
|
290
|
+
|
|
291
|
+
anyio.run(main)
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Custom System Prompt
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
import anyio
|
|
300
|
+
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
|
|
301
|
+
|
|
302
|
+
async def main():
|
|
303
|
+
async for message in query(
|
|
304
|
+
prompt="Review this code",
|
|
305
|
+
options=ClaudeAgentOptions(
|
|
306
|
+
allowed_tools=["Read", "Glob", "Grep"],
|
|
307
|
+
system_prompt="""You are a senior code reviewer focused on:
|
|
308
|
+
1. Security vulnerabilities
|
|
309
|
+
2. Performance issues
|
|
310
|
+
3. Code maintainability
|
|
311
|
+
|
|
312
|
+
Always provide specific line numbers and suggestions for improvement."""
|
|
313
|
+
)
|
|
314
|
+
):
|
|
315
|
+
if isinstance(message, ResultMessage):
|
|
316
|
+
print(message.result)
|
|
317
|
+
|
|
318
|
+
anyio.run(main)
|
|
319
|
+
```
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
# Claude API — Python
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install anthropic
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Client Initialization
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
import anthropic
|
|
13
|
+
|
|
14
|
+
# Default (uses ANTHROPIC_API_KEY env var)
|
|
15
|
+
client = anthropic.Anthropic()
|
|
16
|
+
|
|
17
|
+
# Explicit API key
|
|
18
|
+
client = anthropic.Anthropic(api_key="your-api-key")
|
|
19
|
+
|
|
20
|
+
# Async client
|
|
21
|
+
async_client = anthropic.AsyncAnthropic()
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Basic Message Request
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
response = client.messages.create(
|
|
30
|
+
model="claude-opus-4-6",
|
|
31
|
+
max_tokens=1024,
|
|
32
|
+
messages=[
|
|
33
|
+
{"role": "user", "content": "What is the capital of France?"}
|
|
34
|
+
]
|
|
35
|
+
)
|
|
36
|
+
print(response.content[0].text)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## System Prompts
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
response = client.messages.create(
|
|
45
|
+
model="claude-opus-4-6",
|
|
46
|
+
max_tokens=1024,
|
|
47
|
+
system="You are a helpful coding assistant. Always provide examples in Python.",
|
|
48
|
+
messages=[{"role": "user", "content": "How do I read a JSON file?"}]
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Vision (Images)
|
|
55
|
+
|
|
56
|
+
### Base64
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import base64
|
|
60
|
+
|
|
61
|
+
with open("image.png", "rb") as f:
|
|
62
|
+
image_data = base64.standard_b64encode(f.read()).decode("utf-8")
|
|
63
|
+
|
|
64
|
+
response = client.messages.create(
|
|
65
|
+
model="claude-opus-4-6",
|
|
66
|
+
max_tokens=1024,
|
|
67
|
+
messages=[{
|
|
68
|
+
"role": "user",
|
|
69
|
+
"content": [
|
|
70
|
+
{
|
|
71
|
+
"type": "image",
|
|
72
|
+
"source": {
|
|
73
|
+
"type": "base64",
|
|
74
|
+
"media_type": "image/png",
|
|
75
|
+
"data": image_data
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{"type": "text", "text": "What's in this image?"}
|
|
79
|
+
]
|
|
80
|
+
}]
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### URL
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
response = client.messages.create(
|
|
88
|
+
model="claude-opus-4-6",
|
|
89
|
+
max_tokens=1024,
|
|
90
|
+
messages=[{
|
|
91
|
+
"role": "user",
|
|
92
|
+
"content": [
|
|
93
|
+
{
|
|
94
|
+
"type": "image",
|
|
95
|
+
"source": {
|
|
96
|
+
"type": "url",
|
|
97
|
+
"url": "https://example.com/image.png"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{"type": "text", "text": "Describe this image"}
|
|
101
|
+
]
|
|
102
|
+
}]
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Prompt Caching
|
|
109
|
+
|
|
110
|
+
Cache large context to reduce costs (up to 90% savings).
|
|
111
|
+
|
|
112
|
+
### Automatic Caching (Recommended)
|
|
113
|
+
|
|
114
|
+
Use top-level `cache_control` to automatically cache the last cacheable block in the request — no need to annotate individual content blocks:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
response = client.messages.create(
|
|
118
|
+
model="claude-opus-4-6",
|
|
119
|
+
max_tokens=1024,
|
|
120
|
+
cache_control={"type": "ephemeral"}, # auto-caches the last cacheable block
|
|
121
|
+
system="You are an expert on this large document...",
|
|
122
|
+
messages=[{"role": "user", "content": "Summarize the key points"}]
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Manual Cache Control
|
|
127
|
+
|
|
128
|
+
For fine-grained control, add `cache_control` to specific content blocks:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
response = client.messages.create(
|
|
132
|
+
model="claude-opus-4-6",
|
|
133
|
+
max_tokens=1024,
|
|
134
|
+
system=[{
|
|
135
|
+
"type": "text",
|
|
136
|
+
"text": "You are an expert on this large document...",
|
|
137
|
+
"cache_control": {"type": "ephemeral"} # default TTL is 5 minutes
|
|
138
|
+
}],
|
|
139
|
+
messages=[{"role": "user", "content": "Summarize the key points"}]
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# With explicit TTL (time-to-live)
|
|
143
|
+
response = client.messages.create(
|
|
144
|
+
model="claude-opus-4-6",
|
|
145
|
+
max_tokens=1024,
|
|
146
|
+
system=[{
|
|
147
|
+
"type": "text",
|
|
148
|
+
"text": "You are an expert on this large document...",
|
|
149
|
+
"cache_control": {"type": "ephemeral", "ttl": "1h"} # 1 hour TTL
|
|
150
|
+
}],
|
|
151
|
+
messages=[{"role": "user", "content": "Summarize the key points"}]
|
|
152
|
+
)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Extended Thinking
|
|
158
|
+
|
|
159
|
+
> **Opus 4.6 and Sonnet 4.6:** Use adaptive thinking. `budget_tokens` is deprecated on both Opus 4.6 and Sonnet 4.6.
|
|
160
|
+
> **Older models:** Use `thinking: {type: "enabled", budget_tokens: N}` (must be < `max_tokens`, min 1024).
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# Opus 4.6: adaptive thinking (recommended)
|
|
164
|
+
response = client.messages.create(
|
|
165
|
+
model="claude-opus-4-6",
|
|
166
|
+
max_tokens=16000,
|
|
167
|
+
thinking={"type": "adaptive"},
|
|
168
|
+
output_config={"effort": "high"}, # low | medium | high | max
|
|
169
|
+
messages=[{"role": "user", "content": "Solve this step by step..."}]
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Access thinking and response
|
|
173
|
+
for block in response.content:
|
|
174
|
+
if block.type == "thinking":
|
|
175
|
+
print(f"Thinking: {block.thinking}")
|
|
176
|
+
elif block.type == "text":
|
|
177
|
+
print(f"Response: {block.text}")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Error Handling
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
import anthropic
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
response = client.messages.create(...)
|
|
189
|
+
except anthropic.BadRequestError as e:
|
|
190
|
+
print(f"Bad request: {e.message}")
|
|
191
|
+
except anthropic.AuthenticationError:
|
|
192
|
+
print("Invalid API key")
|
|
193
|
+
except anthropic.PermissionDeniedError:
|
|
194
|
+
print("API key lacks required permissions")
|
|
195
|
+
except anthropic.NotFoundError:
|
|
196
|
+
print("Invalid model or endpoint")
|
|
197
|
+
except anthropic.RateLimitError as e:
|
|
198
|
+
retry_after = int(e.response.headers.get("retry-after", "60"))
|
|
199
|
+
print(f"Rate limited. Retry after {retry_after}s.")
|
|
200
|
+
except anthropic.APIStatusError as e:
|
|
201
|
+
if e.status_code >= 500:
|
|
202
|
+
print(f"Server error ({e.status_code}). Retry later.")
|
|
203
|
+
else:
|
|
204
|
+
print(f"API error: {e.message}")
|
|
205
|
+
except anthropic.APIConnectionError:
|
|
206
|
+
print("Network error. Check internet connection.")
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Multi-Turn Conversations
|
|
212
|
+
|
|
213
|
+
The API is stateless — send the full conversation history each time.
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
class ConversationManager:
|
|
217
|
+
"""Manage multi-turn conversations with the Claude API."""
|
|
218
|
+
|
|
219
|
+
def __init__(self, client: anthropic.Anthropic, model: str, system: str = None):
|
|
220
|
+
self.client = client
|
|
221
|
+
self.model = model
|
|
222
|
+
self.system = system
|
|
223
|
+
self.messages = []
|
|
224
|
+
|
|
225
|
+
def send(self, user_message: str, **kwargs) -> str:
|
|
226
|
+
"""Send a message and get a response."""
|
|
227
|
+
self.messages.append({"role": "user", "content": user_message})
|
|
228
|
+
|
|
229
|
+
response = self.client.messages.create(
|
|
230
|
+
model=self.model,
|
|
231
|
+
max_tokens=kwargs.get("max_tokens", 1024),
|
|
232
|
+
system=self.system,
|
|
233
|
+
messages=self.messages,
|
|
234
|
+
**kwargs
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
assistant_message = response.content[0].text
|
|
238
|
+
self.messages.append({"role": "assistant", "content": assistant_message})
|
|
239
|
+
|
|
240
|
+
return assistant_message
|
|
241
|
+
|
|
242
|
+
# Usage
|
|
243
|
+
conversation = ConversationManager(
|
|
244
|
+
client=anthropic.Anthropic(),
|
|
245
|
+
model="claude-opus-4-6",
|
|
246
|
+
system="You are a helpful assistant."
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
response1 = conversation.send("My name is Alice.")
|
|
250
|
+
response2 = conversation.send("What's my name?") # Claude remembers "Alice"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**Rules:**
|
|
254
|
+
|
|
255
|
+
- Messages must alternate between `user` and `assistant`
|
|
256
|
+
- First message must be `user`
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
### Compaction (long conversations)
|
|
261
|
+
|
|
262
|
+
> **Beta, Opus 4.6 only.** When conversations approach the 200K context window, compaction automatically summarizes earlier context server-side. The API returns a `compaction` block; you must pass it back on subsequent requests — append `response.content`, not just the text.
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
import anthropic
|
|
266
|
+
|
|
267
|
+
client = anthropic.Anthropic()
|
|
268
|
+
messages = []
|
|
269
|
+
|
|
270
|
+
def chat(user_message: str) -> str:
|
|
271
|
+
messages.append({"role": "user", "content": user_message})
|
|
272
|
+
|
|
273
|
+
response = client.beta.messages.create(
|
|
274
|
+
betas=["compact-2026-01-12"],
|
|
275
|
+
model="claude-opus-4-6",
|
|
276
|
+
max_tokens=4096,
|
|
277
|
+
messages=messages,
|
|
278
|
+
context_management={
|
|
279
|
+
"edits": [{"type": "compact_20260112"}]
|
|
280
|
+
}
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Append full content — compaction blocks must be preserved
|
|
284
|
+
messages.append({"role": "assistant", "content": response.content})
|
|
285
|
+
|
|
286
|
+
return next(block.text for block in response.content if block.type == "text")
|
|
287
|
+
|
|
288
|
+
# Compaction triggers automatically when context grows large
|
|
289
|
+
print(chat("Help me build a Python web scraper"))
|
|
290
|
+
print(chat("Add support for JavaScript-rendered pages"))
|
|
291
|
+
print(chat("Now add rate limiting and error handling"))
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Stop Reasons
|
|
297
|
+
|
|
298
|
+
The `stop_reason` field in the response indicates why the model stopped generating:
|
|
299
|
+
|
|
300
|
+
| Value | Meaning |
|
|
301
|
+
|-------|---------|
|
|
302
|
+
| `end_turn` | Claude finished its response naturally |
|
|
303
|
+
| `max_tokens` | Hit the `max_tokens` limit — increase it or use streaming |
|
|
304
|
+
| `stop_sequence` | Hit a custom stop sequence |
|
|
305
|
+
| `tool_use` | Claude wants to call a tool — execute it and continue |
|
|
306
|
+
| `pause_turn` | Model paused and can be resumed (agentic flows) |
|
|
307
|
+
| `refusal` | Claude refused for safety reasons — output may not match your schema |
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Cost Optimization Strategies
|
|
312
|
+
|
|
313
|
+
### 1. Use Prompt Caching for Repeated Context
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
# Automatic caching (simplest — caches the last cacheable block)
|
|
317
|
+
response = client.messages.create(
|
|
318
|
+
model="claude-opus-4-6",
|
|
319
|
+
max_tokens=1024,
|
|
320
|
+
cache_control={"type": "ephemeral"},
|
|
321
|
+
system=large_document_text, # e.g., 50KB of context
|
|
322
|
+
messages=[{"role": "user", "content": "Summarize the key points"}]
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# First request: full cost
|
|
326
|
+
# Subsequent requests: ~90% cheaper for cached portion
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### 2. Choose the Right Model
|
|
330
|
+
|
|
331
|
+
```python
|
|
332
|
+
# Default to Opus for most tasks
|
|
333
|
+
response = client.messages.create(
|
|
334
|
+
model="claude-opus-4-6", # $5.00/$25.00 per 1M tokens
|
|
335
|
+
max_tokens=1024,
|
|
336
|
+
messages=[{"role": "user", "content": "Explain quantum computing"}]
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
# Use Sonnet for high-volume production workloads
|
|
340
|
+
standard_response = client.messages.create(
|
|
341
|
+
model="claude-sonnet-4-6", # $3.00/$15.00 per 1M tokens
|
|
342
|
+
max_tokens=1024,
|
|
343
|
+
messages=[{"role": "user", "content": "Summarize this document"}]
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
# Use Haiku only for simple, speed-critical tasks
|
|
347
|
+
simple_response = client.messages.create(
|
|
348
|
+
model="claude-haiku-4-5", # $1.00/$5.00 per 1M tokens
|
|
349
|
+
max_tokens=256,
|
|
350
|
+
messages=[{"role": "user", "content": "Classify this as positive or negative"}]
|
|
351
|
+
)
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### 3. Use Token Counting Before Requests
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
count_response = client.messages.count_tokens(
|
|
358
|
+
model="claude-opus-4-6",
|
|
359
|
+
messages=messages,
|
|
360
|
+
system=system
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
estimated_input_cost = count_response.input_tokens * 0.000005 # $5/1M tokens
|
|
364
|
+
print(f"Estimated input cost: ${estimated_input_cost:.4f}")
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Retry with Exponential Backoff
|
|
370
|
+
|
|
371
|
+
> **Note:** The Anthropic SDK automatically retries rate limit (429) and server errors (5xx) with exponential backoff. You can configure this with `max_retries` (default: 2). Only implement custom retry logic if you need behavior beyond what the SDK provides.
|
|
372
|
+
|
|
373
|
+
```python
|
|
374
|
+
import time
|
|
375
|
+
import random
|
|
376
|
+
import anthropic
|
|
377
|
+
|
|
378
|
+
def call_with_retry(
|
|
379
|
+
client: anthropic.Anthropic,
|
|
380
|
+
max_retries: int = 5,
|
|
381
|
+
base_delay: float = 1.0,
|
|
382
|
+
max_delay: float = 60.0,
|
|
383
|
+
**kwargs
|
|
384
|
+
):
|
|
385
|
+
"""Call the API with exponential backoff retry."""
|
|
386
|
+
last_exception = None
|
|
387
|
+
|
|
388
|
+
for attempt in range(max_retries):
|
|
389
|
+
try:
|
|
390
|
+
return client.messages.create(**kwargs)
|
|
391
|
+
except anthropic.RateLimitError as e:
|
|
392
|
+
last_exception = e
|
|
393
|
+
except anthropic.APIStatusError as e:
|
|
394
|
+
if e.status_code >= 500:
|
|
395
|
+
last_exception = e
|
|
396
|
+
else:
|
|
397
|
+
raise # Client errors (4xx except 429) should not be retried
|
|
398
|
+
|
|
399
|
+
delay = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
|
|
400
|
+
print(f"Retry {attempt + 1}/{max_retries} after {delay:.1f}s")
|
|
401
|
+
time.sleep(delay)
|
|
402
|
+
|
|
403
|
+
raise last_exception
|
|
404
|
+
```
|