hive-skills 0.1.0

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.
Files changed (238) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +235 -0
  3. package/assets/LICENSE +32 -0
  4. package/assets/THIRD_PARTY_NOTICES.md +72 -0
  5. package/assets/manifest.json +1290 -0
  6. package/assets/skills/authored/code-review/composable/BUNDLE.md +192 -0
  7. package/assets/skills/authored/code-review/composable/INDEX.md +13 -0
  8. package/assets/skills/authored/code-review/composable/VERSION +1 -0
  9. package/assets/skills/authored/code-review/composable/mini/01-review-method.md +34 -0
  10. package/assets/skills/authored/code-review/composable/mini/02-security-review.md +20 -0
  11. package/assets/skills/authored/code-review/composable/mini/03-correctness-bugs.md +19 -0
  12. package/assets/skills/authored/code-review/composable/mini/04-concurrency.md +16 -0
  13. package/assets/skills/authored/code-review/composable/mini/05-error-handling.md +12 -0
  14. package/assets/skills/authored/code-review/composable/mini/06-performance.md +11 -0
  15. package/assets/skills/authored/code-review/composable/mini/07-api-design.md +20 -0
  16. package/assets/skills/authored/code-review/composable/mini/08-missing-tests.md +25 -0
  17. package/assets/skills/authored/code-review/composable/mini/09-refactoring-and-communication.md +32 -0
  18. package/assets/skills/authored/data-analysis/composable/BUNDLE.md +186 -0
  19. package/assets/skills/authored/data-analysis/composable/INDEX.md +13 -0
  20. package/assets/skills/authored/data-analysis/composable/VERSION +1 -0
  21. package/assets/skills/authored/data-analysis/composable/mini/01-data-quality-profiling.md +26 -0
  22. package/assets/skills/authored/data-analysis/composable/mini/02-aggregation-pitfalls.md +21 -0
  23. package/assets/skills/authored/data-analysis/composable/mini/03-time-series.md +19 -0
  24. package/assets/skills/authored/data-analysis/composable/mini/04-segmentation.md +23 -0
  25. package/assets/skills/authored/data-analysis/composable/mini/05-discount-pricing.md +17 -0
  26. package/assets/skills/authored/data-analysis/composable/mini/06-insight-generation.md +25 -0
  27. package/assets/skills/authored/data-analysis/composable/mini/07-executive-writing.md +26 -0
  28. package/assets/skills/authored/data-analysis/composable/mini/08-recommendations.md +20 -0
  29. package/assets/skills/authored/data-analysis/composable/mini/09-reproducibility-assumptions.md +20 -0
  30. package/assets/skills/authored/financial-analysis/composable/BUNDLE.md +1293 -0
  31. package/assets/skills/authored/financial-analysis/composable/INDEX.md +17 -0
  32. package/assets/skills/authored/financial-analysis/composable/VERSION +1 -0
  33. package/assets/skills/authored/financial-analysis/composable/mini/00-core.md +69 -0
  34. package/assets/skills/authored/financial-analysis/composable/mini/01-profitability-efficiency-ratios.md +173 -0
  35. package/assets/skills/authored/financial-analysis/composable/mini/02-liquidity-leverage-ratios.md +120 -0
  36. package/assets/skills/authored/financial-analysis/composable/mini/03-valuation-ratios-interpretation.md +107 -0
  37. package/assets/skills/authored/financial-analysis/composable/mini/04-dcf-projection-wacc.md +122 -0
  38. package/assets/skills/authored/financial-analysis/composable/mini/05-dcf-terminal-value-sensitivity.md +75 -0
  39. package/assets/skills/authored/financial-analysis/composable/mini/06-comparables-precedents.md +78 -0
  40. package/assets/skills/authored/financial-analysis/composable/mini/07-budget-variance-analysis.md +47 -0
  41. package/assets/skills/authored/financial-analysis/composable/mini/08-driver-based-forecasting-scenarios.md +111 -0
  42. package/assets/skills/authored/financial-analysis/composable/mini/09-rolling-forecasts-accuracy.md +114 -0
  43. package/assets/skills/authored/financial-analysis/composable/mini/10-reporting-exec-summary.md +58 -0
  44. package/assets/skills/authored/financial-analysis/composable/mini/11-industry-adaptations.md +130 -0
  45. package/assets/skills/authored/financial-analysis/composable/mini/12-toolkit-scripts-io.md +102 -0
  46. package/assets/skills/authored/python-api/composable/BUNDLE.md +389 -0
  47. package/assets/skills/authored/python-api/composable/INDEX.md +13 -0
  48. package/assets/skills/authored/python-api/composable/VERSION +1 -0
  49. package/assets/skills/authored/python-api/composable/mini/01-project-structure.md +44 -0
  50. package/assets/skills/authored/python-api/composable/mini/02-routing-and-app.md +38 -0
  51. package/assets/skills/authored/python-api/composable/mini/03-pydantic-models.md +45 -0
  52. package/assets/skills/authored/python-api/composable/mini/04-validation-and-errors.md +59 -0
  53. package/assets/skills/authored/python-api/composable/mini/05-dependencies-and-auth.md +60 -0
  54. package/assets/skills/authored/python-api/composable/mini/06-pagination-filtering.md +44 -0
  55. package/assets/skills/authored/python-api/composable/mini/07-async-performance.md +30 -0
  56. package/assets/skills/authored/python-api/composable/mini/08-testing.md +45 -0
  57. package/assets/skills/authored/python-api/composable/mini/09-middleware-observability.md +29 -0
  58. package/assets/skills/authored/tech-writing/composable/BUNDLE.md +220 -0
  59. package/assets/skills/authored/tech-writing/composable/INDEX.md +12 -0
  60. package/assets/skills/authored/tech-writing/composable/VERSION +1 -0
  61. package/assets/skills/authored/tech-writing/composable/mini/01-audience-analysis.md +26 -0
  62. package/assets/skills/authored/tech-writing/composable/mini/02-document-types.md +27 -0
  63. package/assets/skills/authored/tech-writing/composable/mini/03-readme-quickstart-changelog.md +22 -0
  64. package/assets/skills/authored/tech-writing/composable/mini/04-information-architecture.md +21 -0
  65. package/assets/skills/authored/tech-writing/composable/mini/05-style-clarity.md +29 -0
  66. package/assets/skills/authored/tech-writing/composable/mini/06-breaking-changes-migrations.md +33 -0
  67. package/assets/skills/authored/tech-writing/composable/mini/07-troubleshooting-security.md +30 -0
  68. package/assets/skills/authored/tech-writing/composable/mini/08-faq-voice-tone.md +32 -0
  69. package/assets/skills/converted/claude-api/composable/BUNDLE.md +14996 -0
  70. package/assets/skills/converted/claude-api/composable/INDEX.md +98 -0
  71. package/assets/skills/converted/claude-api/composable/VERSION +1 -0
  72. package/assets/skills/converted/claude-api/composable/mini/00-core.md +235 -0
  73. package/assets/skills/converted/claude-api/composable/mini/01-model-api-quick-reference.md +258 -0
  74. package/assets/skills/converted/claude-api/composable/mini/02-common-pitfalls.md +42 -0
  75. package/assets/skills/converted/claude-api/composable/mini/10-models.md +135 -0
  76. package/assets/skills/converted/claude-api/composable/mini/11-platform-availability.md +96 -0
  77. package/assets/skills/converted/claude-api/composable/mini/12-claude-platform-on-aws.md +59 -0
  78. package/assets/skills/converted/claude-api/composable/mini/13-live-sources.md +143 -0
  79. package/assets/skills/converted/claude-api/composable/mini/14-error-codes.md +256 -0
  80. package/assets/skills/converted/claude-api/composable/mini/15-prompt-caching.md +223 -0
  81. package/assets/skills/converted/claude-api/composable/mini/16-token-counting.md +56 -0
  82. package/assets/skills/converted/claude-api/composable/mini/17-tool-use-concepts.md +444 -0
  83. package/assets/skills/converted/claude-api/composable/mini/18-agent-design.md +101 -0
  84. package/assets/skills/converted/claude-api/composable/mini/19-anthropic-cli.md +246 -0
  85. package/assets/skills/converted/claude-api/composable/mini/20-model-migration.md +1301 -0
  86. package/assets/skills/converted/claude-api/composable/mini/30-managed-agents-overview.md +71 -0
  87. package/assets/skills/converted/claude-api/composable/mini/31-managed-agents-core.md +278 -0
  88. package/assets/skills/converted/claude-api/composable/mini/32-managed-agents-environments.md +219 -0
  89. package/assets/skills/converted/claude-api/composable/mini/33-managed-agents-tools.md +366 -0
  90. package/assets/skills/converted/claude-api/composable/mini/34-managed-agents-events.md +252 -0
  91. package/assets/skills/converted/claude-api/composable/mini/35-managed-agents-outcomes.md +106 -0
  92. package/assets/skills/converted/claude-api/composable/mini/36-managed-agents-multiagent.md +101 -0
  93. package/assets/skills/converted/claude-api/composable/mini/37-managed-agents-webhooks.md +123 -0
  94. package/assets/skills/converted/claude-api/composable/mini/38-managed-agents-memory.md +197 -0
  95. package/assets/skills/converted/claude-api/composable/mini/39-managed-agents-scheduled-deployments.md +146 -0
  96. package/assets/skills/converted/claude-api/composable/mini/40-managed-agents-client-patterns.md +211 -0
  97. package/assets/skills/converted/claude-api/composable/mini/41-managed-agents-onboarding.md +82 -0
  98. package/assets/skills/converted/claude-api/composable/mini/42-managed-agents-api-reference.md +441 -0
  99. package/assets/skills/converted/claude-api/composable/mini/43-managed-agents-self-hosted-sandboxes.md +174 -0
  100. package/assets/skills/converted/claude-api/composable/mini/50-python-readme.md +564 -0
  101. package/assets/skills/converted/claude-api/composable/mini/51-python-tool-use.md +590 -0
  102. package/assets/skills/converted/claude-api/composable/mini/52-python-streaming-batches-files.md +549 -0
  103. package/assets/skills/converted/claude-api/composable/mini/53-python-managed-agents.md +335 -0
  104. package/assets/skills/converted/claude-api/composable/mini/55-typescript-readme.md +404 -0
  105. package/assets/skills/converted/claude-api/composable/mini/56-typescript-tool-use.md +548 -0
  106. package/assets/skills/converted/claude-api/composable/mini/57-typescript-streaming-batches-files.md +384 -0
  107. package/assets/skills/converted/claude-api/composable/mini/58-typescript-managed-agents.md +358 -0
  108. package/assets/skills/converted/claude-api/composable/mini/60-csharp-readme.md +361 -0
  109. package/assets/skills/converted/claude-api/composable/mini/61-csharp-tool-use.md +163 -0
  110. package/assets/skills/converted/claude-api/composable/mini/62-csharp-streaming-batches-files.md +64 -0
  111. package/assets/skills/converted/claude-api/composable/mini/65-go-readme.md +185 -0
  112. package/assets/skills/converted/claude-api/composable/mini/66-go-tool-use.md +219 -0
  113. package/assets/skills/converted/claude-api/composable/mini/67-go-streaming-files.md +63 -0
  114. package/assets/skills/converted/claude-api/composable/mini/68-go-managed-agents.md +564 -0
  115. package/assets/skills/converted/claude-api/composable/mini/70-java-readme.md +237 -0
  116. package/assets/skills/converted/claude-api/composable/mini/71-java-tool-use.md +227 -0
  117. package/assets/skills/converted/claude-api/composable/mini/72-java-streaming-files.md +49 -0
  118. package/assets/skills/converted/claude-api/composable/mini/73-java-managed-agents.md +443 -0
  119. package/assets/skills/converted/claude-api/composable/mini/75-php-readme.md +173 -0
  120. package/assets/skills/converted/claude-api/composable/mini/76-php-tool-use.md +252 -0
  121. package/assets/skills/converted/claude-api/composable/mini/77-php-streaming-batches-files.md +53 -0
  122. package/assets/skills/converted/claude-api/composable/mini/78-php-managed-agents.md +443 -0
  123. package/assets/skills/converted/claude-api/composable/mini/80-ruby-readme.md +133 -0
  124. package/assets/skills/converted/claude-api/composable/mini/81-ruby-tool-use-streaming.md +56 -0
  125. package/assets/skills/converted/claude-api/composable/mini/82-ruby-managed-agents.md +394 -0
  126. package/assets/skills/converted/claude-api/composable/mini/85-curl-examples.md +255 -0
  127. package/assets/skills/converted/claude-api/composable/mini/86-curl-managed-agents.md +340 -0
  128. package/assets/skills/converted/claude-api/composable/presets/csharp.md +1151 -0
  129. package/assets/skills/converted/claude-api/composable/presets/curl.md +1154 -0
  130. package/assets/skills/converted/claude-api/composable/presets/go.md +1598 -0
  131. package/assets/skills/converted/claude-api/composable/presets/java.md +1523 -0
  132. package/assets/skills/converted/claude-api/composable/presets/php.md +1488 -0
  133. package/assets/skills/converted/claude-api/composable/presets/python.md +2605 -0
  134. package/assets/skills/converted/claude-api/composable/presets/ruby.md +1146 -0
  135. package/assets/skills/converted/claude-api/composable/presets/shared.md +6478 -0
  136. package/assets/skills/converted/claude-api/composable/presets/typescript.md +2261 -0
  137. package/assets/skills/converted/docx/composable/BUNDLE.md +617 -0
  138. package/assets/skills/converted/docx/composable/INDEX.md +12 -0
  139. package/assets/skills/converted/docx/composable/VERSION +1 -0
  140. package/assets/skills/converted/docx/composable/mini/00-core.md +26 -0
  141. package/assets/skills/converted/docx/composable/mini/01-reading-converting.md +36 -0
  142. package/assets/skills/converted/docx/composable/mini/02-creating-setup-layout.md +85 -0
  143. package/assets/skills/converted/docx/composable/mini/03-creating-elements.md +257 -0
  144. package/assets/skills/converted/docx/composable/mini/04-editing-existing.md +57 -0
  145. package/assets/skills/converted/docx/composable/mini/05-xml-reference.md +128 -0
  146. package/assets/skills/converted/internal-comms/composable/BUNDLE.md +220 -0
  147. package/assets/skills/converted/internal-comms/composable/INDEX.md +11 -0
  148. package/assets/skills/converted/internal-comms/composable/VERSION +1 -0
  149. package/assets/skills/converted/internal-comms/composable/mini/00-core.md +30 -0
  150. package/assets/skills/converted/internal-comms/composable/mini/01-3p-updates.md +49 -0
  151. package/assets/skills/converted/internal-comms/composable/mini/02-company-newsletter.md +67 -0
  152. package/assets/skills/converted/internal-comms/composable/mini/03-faq-answers.md +32 -0
  153. package/assets/skills/converted/internal-comms/composable/mini/04-general-comms.md +18 -0
  154. package/assets/skills/converted/mcp-builder/composable/BUNDLE.md +2460 -0
  155. package/assets/skills/converted/mcp-builder/composable/INDEX.md +23 -0
  156. package/assets/skills/converted/mcp-builder/composable/VERSION +1 -0
  157. package/assets/skills/converted/mcp-builder/composable/mini/00-core.md +43 -0
  158. package/assets/skills/converted/mcp-builder/composable/mini/01-workflow-research-planning.md +54 -0
  159. package/assets/skills/converted/mcp-builder/composable/mini/02-implementation-process.md +78 -0
  160. package/assets/skills/converted/mcp-builder/composable/mini/03-naming-conventions.md +33 -0
  161. package/assets/skills/converted/mcp-builder/composable/mini/04-response-formats.md +21 -0
  162. package/assets/skills/converted/mcp-builder/composable/mini/05-pagination.md +24 -0
  163. package/assets/skills/converted/mcp-builder/composable/mini/06-transport.md +47 -0
  164. package/assets/skills/converted/mcp-builder/composable/mini/07-annotations.md +20 -0
  165. package/assets/skills/converted/mcp-builder/composable/mini/08-security.md +35 -0
  166. package/assets/skills/converted/mcp-builder/composable/mini/09-error-handling.md +32 -0
  167. package/assets/skills/converted/mcp-builder/composable/mini/10-testing-and-documentation.md +21 -0
  168. package/assets/skills/converted/mcp-builder/composable/mini/11-python-implementation.md +432 -0
  169. package/assets/skills/converted/mcp-builder/composable/mini/12-python-advanced-and-checklist.md +233 -0
  170. package/assets/skills/converted/mcp-builder/composable/mini/13-node-implementation.md +717 -0
  171. package/assets/skills/converted/mcp-builder/composable/mini/14-node-advanced-and-checklist.md +200 -0
  172. package/assets/skills/converted/mcp-builder/composable/mini/15-evaluation-design.md +200 -0
  173. package/assets/skills/converted/mcp-builder/composable/mini/16-evaluation-running.md +198 -0
  174. package/assets/skills/converted/mcp-builder/composable/presets/node-server.md +1381 -0
  175. package/assets/skills/converted/mcp-builder/composable/presets/python-server.md +1129 -0
  176. package/assets/skills/converted/pdf/composable/BUNDLE.md +1284 -0
  177. package/assets/skills/converted/pdf/composable/INDEX.md +14 -0
  178. package/assets/skills/converted/pdf/composable/VERSION +1 -0
  179. package/assets/skills/converted/pdf/composable/mini/00-core.md +46 -0
  180. package/assets/skills/converted/pdf/composable/mini/01-creation.md +176 -0
  181. package/assets/skills/converted/pdf/composable/mini/02-extraction.md +178 -0
  182. package/assets/skills/converted/pdf/composable/mini/03-merge-split-manipulate.md +240 -0
  183. package/assets/skills/converted/pdf/composable/mini/04-images-ocr.md +168 -0
  184. package/assets/skills/converted/pdf/composable/mini/05-encryption.md +51 -0
  185. package/assets/skills/converted/pdf/composable/mini/06-forms.md +300 -0
  186. package/assets/skills/converted/pdf/composable/mini/07-libraries-reference.md +89 -0
  187. package/assets/skills/converted/pptx/composable/BUNDLE.md +911 -0
  188. package/assets/skills/converted/pptx/composable/INDEX.md +12 -0
  189. package/assets/skills/converted/pptx/composable/VERSION +1 -0
  190. package/assets/skills/converted/pptx/composable/mini/00-core.md +37 -0
  191. package/assets/skills/converted/pptx/composable/mini/01-reading.md +37 -0
  192. package/assets/skills/converted/pptx/composable/mini/02-creating-from-scratch.md +422 -0
  193. package/assets/skills/converted/pptx/composable/mini/03-editing-templates.md +207 -0
  194. package/assets/skills/converted/pptx/composable/mini/04-design.md +89 -0
  195. package/assets/skills/converted/pptx/composable/mini/05-qa-and-rendering.md +91 -0
  196. package/assets/skills/converted/pptx/composable/presets/creating.md +659 -0
  197. package/assets/skills/converted/pptx/composable/presets/editing.md +485 -0
  198. package/assets/skills/converted/skill-creator/composable/BUNDLE.md +1681 -0
  199. package/assets/skills/converted/skill-creator/composable/INDEX.md +21 -0
  200. package/assets/skills/converted/skill-creator/composable/VERSION +1 -0
  201. package/assets/skills/converted/skill-creator/composable/mini/00-core.md +59 -0
  202. package/assets/skills/converted/skill-creator/composable/mini/01-creating-a-skill.md +27 -0
  203. package/assets/skills/converted/skill-creator/composable/mini/02-skill-writing-guide.md +71 -0
  204. package/assets/skills/converted/skill-creator/composable/mini/03-test-cases.md +21 -0
  205. package/assets/skills/converted/skill-creator/composable/mini/04-running-and-evaluating.md +128 -0
  206. package/assets/skills/converted/skill-creator/composable/mini/05-improving-the-skill.md +30 -0
  207. package/assets/skills/converted/skill-creator/composable/mini/06-blind-comparison.md +5 -0
  208. package/assets/skills/converted/skill-creator/composable/mini/07-description-optimization.md +74 -0
  209. package/assets/skills/converted/skill-creator/composable/mini/08-packaging.md +11 -0
  210. package/assets/skills/converted/skill-creator/composable/mini/09-environment-specific.md +38 -0
  211. package/assets/skills/converted/skill-creator/composable/mini/10-scripts-and-references.md +34 -0
  212. package/assets/skills/converted/skill-creator/composable/mini/11-json-schemas.md +414 -0
  213. package/assets/skills/converted/skill-creator/composable/mini/12-agent-grader.md +225 -0
  214. package/assets/skills/converted/skill-creator/composable/mini/13-agent-comparator.md +204 -0
  215. package/assets/skills/converted/skill-creator/composable/mini/14-agent-analyzer.md +276 -0
  216. package/assets/skills/converted/skill-creator/composable/presets/authoring.md +198 -0
  217. package/assets/skills/converted/skill-creator/composable/presets/evaluating.md +1334 -0
  218. package/assets/skills/converted/skill-creator/composable/presets/optimizing.md +160 -0
  219. package/assets/skills/converted/skill-creator/composable/presets.json +5 -0
  220. package/assets/skills/meta/ccs-skill-creator/composable/BUNDLE.md +465 -0
  221. package/assets/skills/meta/ccs-skill-creator/composable/INDEX.md +8 -0
  222. package/assets/skills/meta/ccs-skill-creator/composable/VERSION +1 -0
  223. package/assets/skills/meta/ccs-skill-creator/composable/mini/00-core.md +46 -0
  224. package/assets/skills/meta/ccs-skill-creator/composable/mini/01-create-new-skill.md +167 -0
  225. package/assets/skills/meta/ccs-skill-creator/composable/mini/02-convert-existing-skill.md +120 -0
  226. package/assets/skills/meta/ccs-skill-creator/composable/mini/03-review-and-maintain.md +112 -0
  227. package/assets/skills/sources/anthropic/PROVENANCE.md +3 -0
  228. package/assets/skills/sources/anthropic/claude-api/LICENSE.txt +202 -0
  229. package/assets/skills/sources/anthropic/docx/LICENSE.txt +30 -0
  230. package/assets/skills/sources/anthropic/internal-comms/LICENSE.txt +202 -0
  231. package/assets/skills/sources/anthropic/mcp-builder/LICENSE.txt +202 -0
  232. package/assets/skills/sources/anthropic/pdf/LICENSE.txt +30 -0
  233. package/assets/skills/sources/anthropic/pptx/LICENSE.txt +30 -0
  234. package/assets/skills/sources/anthropic/skill-creator/LICENSE.txt +202 -0
  235. package/assets/skills/sources/financial-analyst/PROVENANCE.md +1 -0
  236. package/assets/tools/hive.py +728 -0
  237. package/dist/cli.js +7494 -0
  238. package/package.json +40 -0
@@ -0,0 +1,2605 @@
1
+ <!-- GENERATED by tools/hive.py compile — do not hand-edit. -->
2
+ # claude-api — Compiled Skill Bundle — Preset: python (v1.0.0)
3
+
4
+ All composable mini-skills for `claude-api` concatenated in index order, frontmatter stripped. Regenerate with `tools/hive.py compile <skill-dir>` — do not edit by hand.
5
+
6
+ ---
7
+ <!-- module: 00-core.md -->
8
+
9
+ # Building LLM-Powered Applications with Claude
10
+
11
+ This skill helps you build LLM-powered applications with Claude. Choose the right surface based on your needs, detect the project language, then read the relevant language-specific documentation.
12
+
13
+ ## Before You Start
14
+
15
+ Scan the target file (or, if no target file, the prompt and project) for non-Anthropic provider markers — `import openai`, `from openai`, `langchain_openai`, `OpenAI(`, `gpt-4`, `gpt-5`, file names like `agent-openai.py` or `*-generic.py`, or any explicit instruction to keep the code provider-neutral. If you find any, stop and tell the user that this skill produces Claude/Anthropic SDK code; ask whether they want to switch the file to Claude or want a non-Claude implementation. Do not edit a non-Anthropic file with Anthropic SDK calls.
16
+
17
+ ## Output Requirement
18
+
19
+ When the user asks you to add, modify, or implement a Claude feature, your code must call Claude through one of:
20
+
21
+ 1. **The official Anthropic SDK** for the project's language (`anthropic`, `@anthropic-ai/sdk`, `com.anthropic.*`, etc.). This is the default whenever a supported SDK exists for the project.
22
+ 2. **Raw HTTP** (`curl`, `requests`, `fetch`, `httpx`, etc.) — only when the user explicitly asks for cURL/REST/raw HTTP, the project is a shell/cURL project, or the language has no official SDK.
23
+
24
+ Never mix the two — don't reach for `requests`/`fetch` in a Python or TypeScript project just because it feels lighter. Never fall back to OpenAI-compatible shims.
25
+
26
+ **Never guess SDK usage.** Function names, class names, namespaces, method signatures, and import paths must come from explicit documentation — either the `{lang}/` files in this skill or the official SDK repositories or documentation links listed in `shared/live-sources.md`. If the binding you need is not explicitly documented in the skill files, WebFetch the relevant SDK repo from `shared/live-sources.md` before writing code. Do not infer Ruby/Java/Go/PHP/C# APIs from cURL shapes or from another language's SDK.
27
+
28
+ **If WebFetch or repository access fails** (network restricted, timeouts, clone blocked): do not keep retrying — write code from the patterns and namespace/package tables in the `{lang}/` file, run the compiler or interpreter on it, and iterate on the error output. For statically-typed SDKs (C#, Java, Go) a compile-fix loop against local errors reaches working code faster than blocked network research.
29
+
30
+ ## Defaults
31
+
32
+ Unless the user requests otherwise:
33
+
34
+ For the Claude model version, please use Claude Opus 4.8, which you can access via the exact model string `claude-opus-4-8`. Please default to using adaptive thinking (`thinking: {type: "adaptive"}`) for anything remotely complicated. And finally, please default to streaming for any request that may involve long input, long output, or high `max_tokens` — it prevents hitting request timeouts. Use the SDK's `.get_final_message()` / `.finalMessage()` helper to get the complete response if you don't need to handle individual stream events
35
+
36
+ ## ⚠️ API Drift — Your Training Prior May Be Stale
37
+
38
+ Several common Claude API shapes changed in 2025–2026. If you recall a pattern from training, verify it against the `{lang}/` files in this skill before writing — the rows below are the most frequent drift points:
39
+
40
+ | Area | Stale prior | Current API |
41
+ |---|---|---|
42
+ | Extended thinking | `thinking: {type: "enabled", budget_tokens: N}` | On Claude 4.6+ models: `thinking: {type: "adaptive"}`. `budget_tokens` is deprecated on Opus 4.6 / Sonnet 4.6 and **rejected with a 400** on Fable 5 / Sonnet 5 / Opus 4.8 / 4.7. Pre-4.6 models still use `budget_tokens`. |
43
+ | Web search / web fetch tool type | `web_search_20250305`, `web_fetch_20250910` | `web_search_20260209`, `web_fetch_20260209` (dynamic filtering) on Opus 4.8/4.7/4.6, Sonnet 5, and Sonnet 4.6. Older models keep the basic variants; on Vertex AI only basic `web_search_20250305` is available (web fetch is not on Vertex) — see the Server Tools QR below. |
44
+ | PHP parameter names | snake_case wire names as named args (`max_tokens`) | Top-level named args are camelCase (`maxTokens`). Nested array keys vary by feature (e.g. `'taskBudget'`, `'skillID'`, `'mcp_server_name'`) — copy the exact key from the documented example; do not bulk-convert. |
45
+
46
+ The `{lang}/` files in this skill are authoritative over recalled patterns.
47
+
48
+ ## Subcommands
49
+
50
+ If the User Request at the bottom of this prompt is a bare subcommand string (no prose), search every **Subcommands** table in this document — including any in sections appended below — and follow the matching Action column directly. This lets users invoke specific flows via `/claude-api <subcommand>`. If no table in the document matches, treat the request as normal prose.
51
+
52
+ | Subcommand | Action |
53
+ |---|---|
54
+ | `migrate` | Migrate existing Claude API code to a newer model. **Read `shared/model-migration.md` immediately** and follow it in order: Step 0 (confirm scope — ask which files/directories before any edit), Step 1 (classify each file), then the per-target breaking-changes section. Do not summarize the guide — execute it. If the user did not name a target model, ask which model to migrate to in the same turn as the scope question. |
55
+
56
+ ## Language Detection
57
+
58
+ Before reading code examples, determine which language the user is working in:
59
+
60
+ 1. **Look at project files** to infer the language:
61
+
62
+ - `*.py`, `requirements.txt`, `pyproject.toml`, `setup.py`, `Pipfile` → **Python** — read from `python/`
63
+ - `*.ts`, `*.tsx`, `package.json`, `tsconfig.json` → **TypeScript** — read from `typescript/`
64
+ - `*.js`, `*.jsx` (no `.ts` files present) → **TypeScript** — JS uses the same SDK, read from `typescript/`
65
+ - `*.java`, `pom.xml`, `build.gradle` → **Java** — read from `java/`
66
+ - `*.kt`, `*.kts`, `build.gradle.kts` → **Java** — Kotlin uses the Java SDK, read from `java/`
67
+ - `*.scala`, `build.sbt` → **Java** — Scala uses the Java SDK, read from `java/`
68
+ - `*.go`, `go.mod` → **Go** — read from `go/`
69
+ - `*.rb`, `Gemfile` → **Ruby** — read from `ruby/`
70
+ - `*.cs`, `*.csproj` → **C#** — read from `csharp/`
71
+ - `*.php`, `composer.json` → **PHP** — read from `php/`
72
+
73
+ 2. **If multiple languages detected** (e.g., both Python and TypeScript files):
74
+
75
+ - Check which language the user's current file or question relates to
76
+ - If still ambiguous, ask: "I detected both Python and TypeScript files. Which language are you using for the Claude API integration?"
77
+
78
+ 3. **If language can't be inferred** (empty project, no source files, or unsupported language):
79
+
80
+ - Use AskUserQuestion with options: Python, TypeScript, Java, Go, Ruby, cURL/raw HTTP, C#, PHP
81
+ - If AskUserQuestion is unavailable, default to Python examples and note: "Showing Python examples. Let me know if you need a different language."
82
+
83
+ 4. **If unsupported language detected** (Rust, Swift, C++, Elixir, etc.):
84
+
85
+ - Suggest cURL/raw HTTP examples from `curl/` and note that community SDKs may exist
86
+ - Offer to show Python or TypeScript examples as reference implementations
87
+
88
+ 5. **If user needs cURL/raw HTTP examples**, read from `curl/`.
89
+
90
+ ### Language-Specific Feature Support
91
+
92
+ | Language | Tool Runner | Managed Agents | Notes |
93
+ | ---------- | ----------- | -------------- | ------------------------------------- |
94
+ | Python | Yes (beta) | Yes (beta) | Full support — `@beta_tool` decorator |
95
+ | TypeScript | Yes (beta) | Yes (beta) | Full support — `betaZodTool` + Zod |
96
+ | Java | Yes (beta) | Yes (beta) | Beta tool use with annotated classes |
97
+ | Go | Yes (beta) | Yes (beta) | `BetaToolRunner` in `toolrunner` pkg |
98
+ | Ruby | Yes (beta) | Yes (beta) | `BaseTool` + `tool_runner` in beta |
99
+ | C# | Yes (beta) | Yes (beta) | `BetaToolRunner` + raw JSON schema |
100
+ | PHP | Yes (beta) | Yes (beta) | `BetaRunnableTool` + `toolRunner()` |
101
+ | cURL | N/A | Yes (beta) | Raw HTTP, no SDK features |
102
+
103
+ > **Managed Agents code examples**: dedicated language-specific READMEs are provided for Python, TypeScript, Go, Ruby, PHP, Java, and cURL (`{lang}/managed-agents/README.md`, `curl/managed-agents.md`). Read your language's README plus the language-agnostic `shared/managed-agents-*.md` concept files. **Agents are persistent — create once, reference by ID.** Store the agent ID returned by `agents.create` and pass it to every subsequent `sessions.create`; do not call `agents.create` in the request path. The Anthropic CLI (`ant`) is one convenient way to create agents and environments from version-controlled YAML — see `shared/anthropic-cli.md`. If a binding you need isn't shown in the README, WebFetch the relevant entry from `shared/live-sources.md` rather than guess. C# has beta Managed Agents support via `client.Beta.Agents` and related namespaces.
104
+
105
+ ## Which Surface Should I Use?
106
+
107
+ > **Start simple.** Default to the simplest tier that meets your needs. Single API calls and workflows handle most use cases — only reach for agents when the task genuinely requires open-ended, model-driven exploration.
108
+
109
+ | Use Case | Tier | Recommended Surface | Why |
110
+ | ----------------------------------------------- | --------------- | ------------------------- | ------------------------------------------------------------ |
111
+ | Classification, summarization, extraction, Q&A | Single LLM call | **Claude API** | One request, one response |
112
+ | Batch processing or embeddings | Single LLM call | **Claude API** | Specialized endpoints |
113
+ | Multi-step pipelines with code-controlled logic | Workflow | **Claude API + tool use** | You orchestrate the loop |
114
+ | Custom agent with your own tools | Agent | **Claude API + tool use** | Maximum flexibility |
115
+ | Server-managed stateful agent with workspace | Agent | **Managed Agents** | Anthropic runs the loop and hosts the tool-execution sandbox |
116
+ | Persisted, versioned agent configs | Agent | **Managed Agents** | Agents are stored objects; sessions pin to a version |
117
+ | Long-running multi-turn agent with file mounts | Agent | **Managed Agents** | Per-session containers, SSE event stream, Skills + MCP |
118
+
119
+ > **Note:** Managed Agents is the right choice when you want Anthropic to run the agent loop *and* host the container where tools execute — file ops, bash, code execution all run in the per-session workspace. If you want to host the compute yourself or run your own custom tool runtime, Claude API + tool use is the right choice — use the tool runner for automatic loop handling, or the manual loop for fine-grained control (approval gates, custom logging, conditional execution).
120
+
121
+ > **Cloud-provider access.** **Claude Platform on AWS** is Anthropic-operated with same-day API parity — see `shared/claude-platform-on-aws.md` for client setup. For per-feature availability on **Claude Platform on AWS**, **Amazon Bedrock**, **Google Vertex AI**, and **Microsoft Foundry**, see `shared/platform-availability.md` — that table is the single source of truth in this skill; do not infer availability from anywhere else.
122
+
123
+ ### Decision Tree
124
+
125
+ ```
126
+ What does your application need?
127
+
128
+ 0. Which provider?
129
+ ├── First-party API or Claude Platform on AWS → continue (full surface available; per-feature exceptions in shared/platform-availability.md).
130
+ └── Amazon Bedrock, Google Vertex AI, or Microsoft Foundry → Claude API (+ tool use for agents); see shared/platform-availability.md for per-feature support.
131
+
132
+ 1. Single LLM call (classification, summarization, extraction, Q&A)
133
+ └── Claude API — one request, one response
134
+
135
+ 2. Do you want Anthropic to run the agent loop and host a per-session
136
+ container where Claude executes tools (bash, file ops, code)?
137
+ └── Yes → Managed Agents — server-managed sessions, persisted agent configs,
138
+ SSE event stream, Skills + MCP, file mounts.
139
+ Examples: "stateful coding agent with a workspace per task",
140
+ "long-running research agent that streams events to a UI",
141
+ "agent with persisted, versioned config used across many sessions"
142
+
143
+ 3. Workflow (multi-step, code-orchestrated, with your own tools)
144
+ └── Claude API with tool use — you control the loop
145
+
146
+ 4. Open-ended agent (model decides its own trajectory, your own tools, you host the compute)
147
+ └── Claude API agentic loop (maximum flexibility)
148
+ ```
149
+
150
+ ### Should I Build an Agent?
151
+
152
+ Before choosing the agent tier, check all four criteria:
153
+
154
+ - **Complexity** — Is the task multi-step and hard to fully specify in advance? (e.g., "turn this design doc into a PR" vs. "extract the title from this PDF")
155
+ - **Value** — Does the outcome justify higher cost and latency?
156
+ - **Viability** — Is Claude capable at this task type?
157
+ - **Cost of error** — Can errors be caught and recovered from? (tests, review, rollback)
158
+
159
+ If the answer is "no" to any of these, stay at a simpler tier (single call or workflow).
160
+
161
+ ## Architecture
162
+
163
+ Everything goes through `POST /v1/messages`. Tools and output constraints are features of this single endpoint — not separate APIs.
164
+
165
+ **User-defined tools** — You define tools (via decorators, Zod schemas, or raw JSON), and the SDK's tool runner handles calling the API, executing your functions, and looping until Claude is done. For full control, you can write the loop manually.
166
+
167
+ **Server-side tools** — Anthropic-hosted tools that run on Anthropic's infrastructure. Code execution is fully server-side (declare it in `tools`, Claude runs code automatically). Computer use can be server-hosted or self-hosted.
168
+
169
+ **Structured outputs** — Constrains the Messages API response format (`output_config.format`) and/or tool parameter validation (`strict: true`). The recommended approach is `client.messages.parse()` which validates responses against your schema automatically. Note: the old `output_format` parameter is deprecated; use `output_config: {format: {...}}` on `messages.create()`.
170
+
171
+ **Supporting endpoints** — Batches (`POST /v1/messages/batches`), Files (`POST /v1/files`), Token Counting (`POST /v1/messages/count_tokens` — see `shared/token-counting.md`), and Models (`GET /v1/models`, `GET /v1/models/{id}` — live capability/context-window discovery) feed into or support Messages API requests.
172
+
173
+ ## Reading Guide
174
+
175
+ After detecting the language, read the relevant files based on what the user needs.
176
+
177
+ **All SDK languages use the same multi-file layout** — directory `{lang}/claude-api/` containing `README.md` (install, client init, basic request, thinking, caching, stop details, misc), `tool-use.md` (tool definitions, agentic loop, Anthropic-defined tools, structured outputs), `streaming.md`, `batches.md`, `files-api.md`. Not every language has every file (e.g., Ruby has no `batches.md`); if a file is absent, that feature's example is not yet documented for that language — fall back to the cURL shape or WebFetch the SDK repo from `shared/live-sources.md`. **cURL** → `curl/examples.md`.
178
+
179
+ The Quick Task Reference below uses the `{lang}/claude-api/FILE.md` path notation for all languages.
180
+
181
+ ### Quick Task Reference
182
+
183
+ **Single text classification/summarization/extraction/Q&A:**
184
+ → Read only `{lang}/claude-api/README.md`
185
+
186
+ **Chat UI or real-time response display:**
187
+ → Read `{lang}/claude-api/README.md` + `{lang}/claude-api/streaming.md`
188
+
189
+ **Long-running conversations (may exceed context window):**
190
+ → Read `{lang}/claude-api/README.md` — see Compaction section
191
+ **Migrating to a newer model (Fable 5 / Opus 4.8 / Opus 4.7 / Opus 4.6 / Sonnet 5 / Sonnet 4.6) or replacing a retired model:**
192
+ → Read `shared/model-migration.md`
193
+ **Prompting or tuning Fable 5 (long turns, effort, verbosity, autonomous runs, sub-agents):**
194
+ → Read `shared/model-migration.md` → Migrating to Fable 5 → Behavioral shifts (prompt-tunable) + Long-running agent recommendations
195
+ **Prompt caching / optimize caching / "why is my cache hit rate low":**
196
+ → Read `shared/prompt-caching.md` + `{lang}/claude-api/README.md` (Prompt Caching section)
197
+ **Count tokens in a file / prompt / diff ("how many tokens is X"):**
198
+ → Read `shared/token-counting.md` — use `messages.count_tokens`, never `tiktoken`
199
+
200
+ **Function calling / tool use / agents:**
201
+ → Read `{lang}/claude-api/README.md` + `shared/tool-use-concepts.md` + `{lang}/claude-api/tool-use.md`
202
+
203
+ **Agent design (tool surface, context management, caching strategy):**
204
+ → Read `shared/agent-design.md`
205
+
206
+ **Batch processing (non-latency-sensitive):**
207
+ → Read `{lang}/claude-api/README.md` + `{lang}/claude-api/batches.md`
208
+
209
+ **File uploads across multiple requests:**
210
+ → Read `{lang}/claude-api/README.md` + `{lang}/claude-api/files-api.md`
211
+
212
+ **Managed Agents (server-managed stateful agents with workspace):**
213
+ → Read `shared/managed-agents-overview.md` + the rest of the `shared/managed-agents-*.md` files. For Python, TypeScript, Go, Ruby, PHP, and Java, read `{lang}/managed-agents/README.md` for code examples. For cURL, read `curl/managed-agents.md`. **Agents are persistent — create once, reference by ID.** Store the agent ID returned by `agents.create` and pass it to every subsequent `sessions.create`; do not call `agents.create` in the request path. The Anthropic CLI (`ant`) is one convenient way to create agents and environments from version-controlled YAML — see `shared/anthropic-cli.md`. If a binding you need isn't shown in the language README, WebFetch the relevant entry from `shared/live-sources.md` rather than guess. C# has beta Managed Agents support — see `csharp/claude-api/README.md` for details, or `curl/managed-agents.md` for raw HTTP reference.
214
+
215
+ ### Claude API (Full File Reference)
216
+
217
+ Read the **language-specific Claude API source** — `{language}/claude-api/` for every SDK language, `curl/examples.md` for cURL:
218
+
219
+ 1. **`{language}/claude-api/README.md`** — **Read this first.** Installation, quick start, common patterns, error handling.
220
+ 2. **`shared/tool-use-concepts.md`** — Read when the user needs function calling, code execution, memory, or structured outputs. Covers conceptual foundations.
221
+ 3. **`shared/agent-design.md`** — Read when designing an agent: bash vs. dedicated tools, programmatic tool calling, tool search/skills, context editing vs. compaction vs. memory, caching principles.
222
+ 4. **`{language}/claude-api/tool-use.md`** — Read for language-specific tool use code examples (tool runner, manual loop, code execution, memory, structured outputs).
223
+ 5. **`{language}/claude-api/streaming.md`** — Read when building chat UIs or interfaces that display responses incrementally.
224
+ 6. **`{language}/claude-api/batches.md`** — Read when processing many requests offline (not latency-sensitive). Runs asynchronously at 50% cost.
225
+ 7. **`{language}/claude-api/files-api.md`** — Read when sending the same file across multiple requests without re-uploading.
226
+ 8. **`shared/prompt-caching.md`** — Read when adding or optimizing prompt caching. Covers prefix-stability design, breakpoint placement, and anti-patterns that silently invalidate cache.
227
+ 9. **`shared/error-codes.md`** — Read when debugging HTTP errors or implementing error handling. Includes the per-SDK typed exception class table and the Go `errors.As` pattern.
228
+ 10. **`shared/model-migration.md`** — Read when upgrading to newer models, replacing retired models, or translating `budget_tokens` / prefill patterns to the current API.
229
+ 11. **`shared/live-sources.md`** — WebFetch URLs for fetching the latest official documentation.
230
+
231
+ Not every language has every file (e.g., Ruby has no `batches.md`); if a file is absent, that feature's example is not yet documented for that language.
232
+
233
+ > **Note:** For the Managed Agents file reference, see the `## Managed Agents (Beta)` section above — it lists every `shared/managed-agents-*.md` file and the language-specific READMEs.
234
+
235
+ ## When to Use WebFetch
236
+
237
+ Use WebFetch to get the latest documentation when:
238
+
239
+ - User asks for "latest" or "current" information
240
+ - Cached data seems incorrect
241
+ - User asks about features not covered here
242
+
243
+ Live documentation URLs are in `shared/live-sources.md`.
244
+
245
+ ---
246
+ <!-- module: 01-model-api-quick-reference.md -->
247
+
248
+ # Claude API Quick Reference (Models, Auth, Params, Surfaces)
249
+
250
+ ## Current Models (cached: 2026-06-24)
251
+
252
+ | Model | Model ID | Context | Input $/1M | Output $/1M |
253
+ | ----------------- | ------------------- | -------------- | ---------- | ----------- |
254
+ | Claude Fable 5 | `claude-fable-5` | 1M | $10.00 | $50.00 |
255
+ | Claude Mythos 5 (Project Glasswing only) | `claude-mythos-5` | 1M | $10.00 | $50.00 |
256
+ | Claude Opus 4.8 | `claude-opus-4-8` | 1M | $5.00 | $25.00 |
257
+ | Claude Opus 4.7 | `claude-opus-4-7` | 1M | $5.00 | $25.00 |
258
+ | Claude Opus 4.6 | `claude-opus-4-6` | 1M | $5.00 | $25.00 |
259
+ | Claude Sonnet 5 | `claude-sonnet-5` | 1M | $3.00 ($2.00 intro through 2026-08-31) | $15.00 ($10.00 intro) |
260
+ | Claude Sonnet 4.6 | `claude-sonnet-4-6` | 1M | $3.00 | $15.00 |
261
+ | Claude Haiku 4.5 | `claude-haiku-4-5` | 200K | $1.00 | $5.00 |
262
+
263
+ **ALWAYS use `claude-opus-4-8` unless the user explicitly names a different model.** This is non-negotiable. Do not use `claude-sonnet-5`, `claude-sonnet-4-6`, or any other model unless the user literally says "use sonnet" or "use haiku". Never downgrade for cost — that's the user's decision, not yours. Use `claude-fable-5` only when the user explicitly asks for Claude Fable 5, "fable", or Anthropic's most capable model — it has different API behavior than the Opus family (see below) and pricing that exceeds Opus-tier.
264
+
265
+ ### Claude Fable 5 (`claude-fable-5`) — most capable widely released model
266
+
267
+ Claude Fable 5 is Anthropic's most capable widely released model, for the most demanding reasoning and long-horizon agentic work. **Claude Mythos 5** (`claude-mythos-5`) offers the same capabilities, pricing, and API surface through Project Glasswing (participation is the only way to access it), succeeding the invitation-only Claude Mythos Preview (`claude-mythos-preview`) — everything below applies to both models. 1M context window (the maximum is also the default), 128K max output. Key API differences from Opus-tier — see `shared/model-migration.md` → Migrating to Claude Fable 5 for details:
268
+
269
+ - **Thinking is always on** — omit the `thinking` parameter entirely (or send `{type: "adaptive"}`). Any other explicit configuration is rejected: `{type: "disabled"}` and `{type: "enabled", budget_tokens: N}` both return a 400. Control depth with `output_config.effort` (supports `low` through `xhigh` and `max`).
270
+ - **The raw chain of thought is never returned** — responses carry regular `thinking` blocks (not `redacted_thinking`): `display: "summarized"` returns a readable summary, `"omitted"` (the default) leaves the `thinking` field as an empty string. Replay rules: pass thinking blocks back exactly as received on the same model (including empty-text blocks — the API rejects *modified* blocks, not read ones); a **different** model **drops** them from the prompt (typically silently — not an error; the drop happens before pricing, so dropped blocks aren't billed and there's nothing to strip). Regular thinking blocks from other models replay across models freely.
271
+ - **Tokenizer** — same tokenizer as Opus 4.8 (introduced with Opus 4.7). Token counts are roughly unchanged when migrating from Opus 4.7/4.8; per-token pricing differs. Coming from Opus 4.6, Sonnet, Haiku, or older, re-baseline with `count_tokens`.
272
+ - **`refusal` stop reason — handle it, and opt into fallbacks by default** — safety classifiers may decline a request (HTTP 200, `stop_reason: "refusal"`, with a `stop_details` category). A pre-output refusal has an empty `content` array and is not billed at all; a mid-stream refusal bills the already-streamed output — discard the partial output. Always check `stop_reason` before reading `content`. Recovery is **opt-in on the API**: most Claude consumer surfaces ship with built-in Claude Opus 4.8 fallbacks, but an API request that doesn't opt in simply stops on a refusal — and false positives on benign adjacent work (security tooling, life-sciences tasks) do happen. **When you write `claude-fable-5` code, include the server-side `fallbacks` parameter by default** (`betas: ["server-side-fallback-2026-06-01"]` + `fallbacks: [{"model": "claude-opus-4-8"}]`; Claude API and Claude Platform on AWS): a declined request is transparently re-served by the fallback model inside the same call, with credit-style repricing applied automatically (a decline before any output isn't billed; the rescue bills at the fallback model's own rates). Tell the user you've enabled it; drop it only if they decline. The GA SDKs' client-side `BetaRefusalFallbackMiddleware` + `BetaFallbackState` handle retry everywhere server-side fallbacks aren't supported (incl. Amazon Bedrock, Vertex AI, Microsoft Foundry); fallback credit refunds the cache-switch cost of client-side retries. Code examples: the Refusal Fallbacks section of your language's claude-api doc; full semantics in the migration guide's refusal section.
273
+ - **No assistant prefill** — same as the rest of the 4.6+ family.
274
+ - **30-day data retention required** — Claude Fable 5 is not available under zero data retention; requests from an org whose retention configuration doesn't meet the requirement return `400 invalid_request_error`.
275
+ - **Longer turns, different prompting** — single requests on hard tasks can run many minutes (plan timeouts/streaming/progress UX); effort sweeps should include low/medium for routine work; prompts written for prior models are often too prescriptive and reduce output quality. See `shared/model-migration.md` → Migrating to Claude Fable 5 → Behavioral shifts (prompt-tunable) for the recommended prompt snippets (anti-overplanning, no-tidying, grounded progress claims, boundaries, async sub-agents, memory, `send_to_user`).
276
+
277
+ **CRITICAL: Use only the exact model ID strings from the table above — they are complete as-is. Do not append date suffixes.** For example, use `claude-sonnet-4-6`, never `claude-sonnet-4-6-20251114` or any other date-suffixed variant you might recall from training data. If the user requests an older model not in the table (e.g., "opus 4.5", "sonnet 3.7"), read `shared/models.md` for the exact ID — do not construct one yourself.
278
+
279
+ A note: if any of the model strings above look unfamiliar to you, that's to be expected — that just means they were released after your training data cutoff. Rest assured they are real models; we wouldn't mess with you like that.
280
+
281
+ **Live capability lookup:** The table above is cached. When the user asks "what's the context window for X", "does X support vision/thinking/effort", or "which models support Y", query the Models API (`client.models.retrieve(id)` / `client.models.list()`) — see `shared/models.md` for the field reference and capability-filter examples.
282
+
283
+ ## Authentication (Quick Reference)
284
+
285
+ **An unset `ANTHROPIC_API_KEY` does NOT mean there are no credentials.** The SDKs and the `ant` CLI resolve credentials in this order (first match wins): `ANTHROPIC_API_KEY` → `ANTHROPIC_AUTH_TOKEN` → the `ANTHROPIC_PROFILE`-selected or active OAuth profile from `ant auth login` → Workload Identity Federation env vars → the default profile on disk. A bare `Anthropic()` / `new Anthropic()` / `anthropic.NewClient()` works after `ant auth login` with no env var set.
286
+
287
+ **When you need to call the API and `ANTHROPIC_API_KEY` is unset, don't ask the user for a key.** First run `ant auth status` — it shows which credential source and profile is active. If it reports an active profile:
288
+
289
+ - **SDK code or `ant` CLI:** just run it. The zero-arg client constructor and every `ant …` subcommand pick up the profile automatically — no env var needed.
290
+ - **Raw `curl` / HTTP:** get a short-lived token with `ant auth print-credentials --access-token` and send it as `Authorization: Bearer <token>` **plus** the header `anthropic-beta: oauth-2025-04-20` (OAuth tokens go on `Authorization: Bearer`, not `x-api-key:` — converting a curl from an API key is a header change, not a key swap). Always pass `--access-token`; the no-flag form prints JSON, not a bare token.
291
+
292
+ Only ask the user for a key if `ant auth status` reports no active credential source (or `ant` itself isn't installed). Suggest `ant auth login` as the first option — it stores a profile under `~/.config/anthropic/` that the SDKs read automatically — and an exported `ANTHROPIC_API_KEY` as the alternative.
293
+
294
+ Full auth details (named profiles, scopes, the API-key-shadows-profile trap, refresh-token expiry): `shared/anthropic-cli.md`.
295
+
296
+ ## Thinking & Effort (Quick Reference)
297
+
298
+ **Fable 5 / Opus 4.8 / 4.7 / Sonnet 5 — Adaptive thinking only:** Use `thinking: {type: "adaptive"}`. `thinking: {type: "enabled", budget_tokens: N}` returns a 400 — adaptive is the only on-mode. On Opus 4.8, Opus 4.7, and Sonnet 5, `{type: "disabled"}` and omitting `thinking` both work (on Sonnet 5, omitting runs adaptive; on Opus 4.7/4.8, omitting runs without thinking — set `{type: "adaptive"}` explicitly); on Fable 5, an explicit `{type: "disabled"}` returns a 400 — omit the `thinking` param entirely instead. Sampling parameters (`temperature`, `top_p`, `top_k`) are also removed and will 400. Opus 4.8 keeps the same request surface as 4.7 (no new breaking changes) — see `shared/model-migration.md` → Migrating to Opus 4.8 for the behavioral re-tuning, and → Migrating to Opus 4.7 for the full breaking-change list when coming from 4.6 or earlier. Note: with `thinking` disabled, Opus 4.8 may write longer reasoning into the visible response — leave adaptive thinking on, or add a final-answer-only instruction (see the migration guide).
299
+ **Opus 4.6 — Adaptive thinking (recommended):** Use `thinking: {type: "adaptive"}`. Claude dynamically decides when and how much to think. No `budget_tokens` needed — `budget_tokens` is deprecated on Opus 4.6 and Sonnet 4.6 and should not be used for new code. Adaptive thinking also automatically enables interleaved thinking (no beta header needed). **When the user asks for "extended thinking", a "thinking budget", or `budget_tokens`: always use Fable 5, Opus 4.8, 4.7, or 4.6 with `thinking: {type: "adaptive"}`. The concept of a fixed token budget for thinking is deprecated — adaptive thinking replaces it. Do NOT use `budget_tokens` for new 4.6/4.7/4.8 code and do NOT switch to an older model.** *Gradual-migration carve-out:* `budget_tokens` is still functional on Opus 4.6 and Sonnet 4.6 as a transitional escape hatch — if you're migrating existing code and need a hard token ceiling before you've tuned `effort`, see `shared/model-migration.md` → Transitional escape hatch. Note: this carve-out does **not** apply to Fable 5, Opus 4.7 or 4.8 — `budget_tokens` is fully removed there.
300
+ **Effort parameter (GA, no beta header):** Controls thinking depth and overall token spend via `output_config: {effort: "low"|"medium"|"high"|"max"}` (inside `output_config`, not top-level). Default is `high` (equivalent to omitting it). `max` is supported on Fable 5, Opus 4.6 and later, Sonnet 5, and Sonnet 4.6 (not Haiku or earlier Sonnets). Opus 4.7 added `"xhigh"` (between `high` and `max`) — the best setting for most coding and agentic use cases on Fable 5 / Opus 4.7/4.8 / Sonnet 5, and the default in Claude Code; use a minimum of `high` for most intelligence-sensitive work. Works on Fable 5, Opus 4.5, Opus 4.6, Opus 4.7, Opus 4.8, Sonnet 5, and Sonnet 4.6. Will error on Sonnet 4.5 / Haiku 4.5. On Fable 5, Opus 4.7/4.8, and Sonnet 5, effort matters more than on any prior model in their tier — re-tune it when migrating, and run long-horizon/agentic tasks at `high`/`xhigh` with the full task spec given up front. Combine with adaptive thinking for the best cost-quality tradeoffs. Lower effort means fewer and more-consolidated tool calls, less preamble, and terser confirmations — `high` is often the sweet spot balancing quality and token efficiency; use `max` when correctness matters more than cost; use `low` for subagents or simple tasks.
301
+
302
+ **Thinking display — `"omitted"` by default on Fable 5 / Mythos 5 / Opus 4.8 / 4.7 / Sonnet 5:** `display: "summarized"` returns a readable summary of the reasoning; `"omitted"` (the default on all five — a silent change from Opus 4.6 and Sonnet 4.6, where it was `"summarized"`) streams `thinking` blocks with empty text. `display` controls visibility only — thinking happens and is billed the same under every setting; the raw chain of thought is never exposed on any model. If you stream reasoning to users, the default looks like a long pause before output — set `thinking: {type: "adaptive", display: "summarized"}` explicitly. (Independent of display, echo thinking blocks back unchanged when continuing on the same model; other models silently ignore them — see the migration guide.)
303
+
304
+ **Task Budgets (beta, Fable 5 / Opus 4.7 / 4.8 / Sonnet 5):** `output_config: {task_budget: {type: "tokens", total: N}}` tells the model how many tokens it has for a full agentic loop — it sees a running countdown and self-moderates (minimum 20,000; beta header `task-budgets-2026-03-13`). Distinct from `max_tokens`, which is an enforced per-response ceiling the model is not aware of. See `shared/model-migration.md` → Task Budgets.
305
+
306
+ **Sonnet 4.6:** Supports adaptive thinking (`thinking: {type: "adaptive"}`). `budget_tokens` is deprecated on Sonnet 4.6 — use adaptive thinking instead.
307
+
308
+ **Older models (only if explicitly requested):** If the user specifically asks for Sonnet 4.5 or another older model, use `thinking: {type: "enabled", budget_tokens: N}`. `budget_tokens` must be less than `max_tokens` (minimum 1024). Never choose an older model just because the user mentions `budget_tokens` — use Opus 4.8 with adaptive thinking instead.
309
+
310
+ ## Compaction (Quick Reference)
311
+
312
+ **Beta, Fable 5, Opus 4.8, Opus 4.7, Opus 4.6, Sonnet 5, and Sonnet 4.6.** For long-running conversations that may exceed the 1M context window, enable server-side compaction. The API automatically summarizes earlier context when it approaches the trigger threshold (default: 150K tokens). Requires beta header `compact-2026-01-12`.
313
+
314
+ **Critical:** Append `response.content` (not just the text) back to your messages on every turn. Compaction blocks in the response must be preserved — the API uses them to replace the compacted history on the next request. Extracting only the text string and appending that will silently lose the compaction state.
315
+
316
+ See `{lang}/claude-api/README.md` (Compaction section) for code examples. Full docs via WebFetch in `shared/live-sources.md`.
317
+
318
+ ## Prompt Caching (Quick Reference)
319
+
320
+ **Prefix match.** Any byte change anywhere in the prefix invalidates everything after it. Render order is `tools` → `system` → `messages`. Keep stable content first (frozen system prompt, deterministic tool list), put volatile content (timestamps, per-request IDs, varying questions) after the last `cache_control` breakpoint.
321
+
322
+ **Mid-conversation operator instructions** (Claude Opus 4.8 only; no beta header): append `{"role": "system", ...}` to `messages[]` instead of editing top-level `system`. Preserves the cached history prefix and is the prompt-injection-safe operator channel. See `shared/prompt-caching.md` § Mid-conversation system messages.
323
+
324
+ **Top-level auto-caching** (`cache_control: {type: "ephemeral"}` on `messages.create()`) is the simplest option when you don't need fine-grained placement. Max 4 breakpoints per request. Minimum cacheable prefix is ~1024 tokens — shorter prefixes silently won't cache.
325
+
326
+ **Verify with `usage.cache_read_input_tokens`** — if it's zero across repeated requests, a silent invalidator is at work (`datetime.now()` in system prompt, unsorted JSON, varying tool set).
327
+
328
+ For placement patterns, architectural guidance, and the silent-invalidator audit checklist: read `shared/prompt-caching.md`. Language-specific syntax: `{lang}/claude-api/README.md` (Prompt Caching section).
329
+
330
+ ## Fast Mode (Quick Reference)
331
+
332
+ **Research preview, Opus 4.8 / 4.7 only.** Opus 4.7 fast mode is deprecated — after removal, `speed: "fast"` on 4.7 returns an error. Opus 4.8 is the durable fast-capable tier. Fast mode runs the same model at up to 2.5x higher output tokens per second, at premium pricing. Three things are required on every request: use the **beta** messages endpoint (`client.beta.messages.…`), pass the beta flag `fast-mode-2026-02-01`, and set `speed: "fast"` as a top-level request parameter (not a header, not in `extra_body`).
333
+
334
+ ```python
335
+ client.beta.messages.create(
336
+ model="claude-opus-4-8", max_tokens=4096,
337
+ speed="fast", betas=["fast-mode-2026-02-01"],
338
+ messages=[...],
339
+ )
340
+ ```
341
+
342
+ | Language | Beta flag | Speed parameter |
343
+ |---|---|---|
344
+ | Python | `betas=["fast-mode-2026-02-01"]` | `speed="fast"` |
345
+ | TypeScript / Ruby | `betas: ["fast-mode-2026-02-01"]` | `speed: "fast"` |
346
+ | Go | `[]anthropic.AnthropicBeta{anthropic.AnthropicBetaFastMode2026_02_01}` | `Speed: anthropic.BetaMessageNewParamsSpeedFast` |
347
+ | Java | `.addBeta(AnthropicBeta.FAST_MODE_2026_02_01)` | `.speed(MessageCreateParams.Speed.FAST)` |
348
+ | C# | `Betas = ["fast-mode-2026-02-01"]` | `Speed = Speed.Fast` (`Anthropic.Models.Beta.Messages`) |
349
+ | PHP | `betas: ['fast-mode-2026-02-01']` | `speed: 'fast'` |
350
+ | cURL | `anthropic-beta: fast-mode-2026-02-01` header | `"speed": "fast"` in body |
351
+
352
+ `response.usage.speed` reports which speed was used. Fast mode has its own rate limit separate from standard Opus; on 429, either retry after the `retry-after` delay or drop `speed` and fall back to standard (note: switching speed invalidates prompt cache). Not available with Batch API, Priority Tier, Claude Platform on AWS, or third-party platforms.
353
+
354
+ ## Task Budgets (Quick Reference)
355
+
356
+ **Beta, Fable 5 / Sonnet 5 / Opus 4.8 / 4.7.** A task budget gives Claude a token ceiling for an agentic loop so it paces itself and finishes gracefully instead of being cut off. Set `task_budget` inside `output_config` on `client.beta.messages.stream(...)` with beta flag `task-budgets-2026-03-13` — use streaming so the large `max_tokens` doesn't hit HTTP timeouts:
357
+
358
+ ```python
359
+ with client.beta.messages.stream(
360
+ model="claude-opus-4-8", max_tokens=128000,
361
+ output_config={"effort": "high", "task_budget": {"type": "tokens", "total": 64000}},
362
+ betas=["task-budgets-2026-03-13"],
363
+ messages=[...], tools=[...],
364
+ ) as stream:
365
+ response = stream.get_final_message()
366
+ ```
367
+
368
+ `task_budget` fields: `type` (always `"tokens"`), `total`, and optional `remaining` (defaults to `total`). The server injects a countdown marker Claude sees during generation; the budget counts what Claude generates and the tool results it reads this turn — **not** the full history you resend each request.
369
+
370
+ **Observing spend:** accumulate `response.usage.output_tokens` (plus the token count of the tool-result blocks you append) across loop iterations if you want to display progress. Leave `remaining` unset in the normal loop — the server tracks the countdown itself, and passing a client-computed `remaining` while also resending full history under-reports the budget. **Only pass `remaining`** when you compact or rewrite history between requests and the server can no longer derive prior spend.
371
+
372
+ ## Provider Clients (Quick Reference)
373
+
374
+ When targeting Claude on a third-party platform, use that platform's dedicated client class — not the first-party `Anthropic()` client with a `base_url` override. After construction the client exposes the same `messages.create` / `.stream` surface as the first-party SDK.
375
+
376
+ ### Amazon Bedrock
377
+
378
+ Use the **Mantle** client (Messages-API Bedrock endpoint). Bedrock model IDs take an `anthropic.` prefix (e.g. `"anthropic.claude-opus-4-8"`). Region is required.
379
+
380
+ | Language | Client |
381
+ |---|---|
382
+ | Python | `from anthropic import AnthropicBedrockMantle` → `AnthropicBedrockMantle(aws_region="…")` |
383
+ | TypeScript | `import { AnthropicBedrockMantle } from "@anthropic-ai/bedrock-sdk"` → `new AnthropicBedrockMantle({ awsRegion: "…" })` |
384
+ | Go | `bedrock.NewMantleClient(ctx, bedrock.MantleClientConfig{ AWSRegion: "…" })` |
385
+ | Java | `AnthropicOkHttpClient.builder().backend(BedrockMantleBackend.fromEnv()).build()` (from `com.anthropic.bedrock.backends`) |
386
+ | C# | `new AnthropicBedrockMantleClient(new() { AwsRegion = "…" })` (package `Anthropic.Bedrock`) |
387
+ | PHP | `use Anthropic\Bedrock\MantleClient;` → `new MantleClient(awsRegion: '…')` |
388
+ | Ruby | `Anthropic::BedrockMantleClient.new(aws_region: "…")` |
389
+
390
+ `AnthropicBedrock` / `BedrockClient` / `BedrockBackend` (without `Mantle`) are the legacy `bedrock-runtime` InvokeModel path — prefer the Mantle client for new code.
391
+
392
+ ### Microsoft Foundry
393
+
394
+ | Language | Client |
395
+ |---|---|
396
+ | Python | `from anthropic import AnthropicFoundry` → `AnthropicFoundry(api_key=…, resource="…")` |
397
+ | TypeScript | `import AnthropicFoundry from "@anthropic-ai/foundry-sdk"` → `new AnthropicFoundry({ … })` |
398
+ | Java | `AnthropicOkHttpClient.builder().backend(FoundryBackend.fromEnv()).build()` (from `com.anthropic.foundry.backends`) |
399
+ | C# | `new AnthropicFoundryClient(new AnthropicFoundryApiKeyCredentials(…))` (package `Anthropic.Foundry`) |
400
+ | PHP | `Foundry\Client::withCredentials(…)` |
401
+
402
+ The Go and Ruby SDKs do not currently support Foundry. For Ruby, use the standard `Anthropic::Client.new(base_url: "<foundry endpoint>")` as a fallback (Entra ID auth is not built in). For Claude Platform on AWS, see `shared/claude-platform-on-aws.md`.
403
+
404
+ ### Google Cloud Vertex AI
405
+
406
+ Two required constructor args: GCP `project_id` and `region`. Vertex model IDs take **no prefix** — current-generation models (Opus 4.8/4.7/4.6, Sonnet 5, Sonnet 4.6) use the bare first-party ID (e.g. `"claude-opus-4-8"`); dated-snapshot models use an `@` version separator (e.g. `claude-opus-4-5@20251101`, **not** `claude-opus-4-5-20251101`). Auth is GCP ADC (`gcloud auth application-default login`); no Anthropic API key. `region` can be `"global"` (recommended), a multi-region (`"us"`/`"eu"`), or a specific region. After construction, use the same `messages.create` / `.stream` surface.
407
+
408
+ | Language | Client |
409
+ |---|---|
410
+ | Python | `from anthropic import AnthropicVertex` → `AnthropicVertex(project_id="…", region="…")` (install `"anthropic[vertex]"`) |
411
+ | TypeScript | `import { AnthropicVertex } from "@anthropic-ai/vertex-sdk"` → `new AnthropicVertex({ projectId, region })` |
412
+ | Go | `import "github.com/anthropics/anthropic-sdk-go/vertex"` → `anthropic.NewClient(vertex.WithGoogleAuth(ctx, region, projectID))` |
413
+ | Java | `AnthropicOkHttpClient.builder().backend(VertexBackend.builder().region("…").project("…").build()).build()` (from `com.anthropic.vertex.backends`) |
414
+ | C# | `new AnthropicClient { Backend = new VertexBackend(projectId, region) }` (package `Anthropic.Vertex`) |
415
+ | PHP | `use Anthropic\Vertex;` → `Vertex\Client::fromEnvironment(location: '…', projectId: '…')` — note `location`, not `region` |
416
+ | Ruby | `Anthropic::VertexClient.new(region: "…", project_id: "…")` |
417
+
418
+ ## Context Editing (Quick Reference)
419
+
420
+ **Beta.** Context editing **clears** old tool results or thinking blocks from the conversation before the model sees it; it is **not compaction** (which summarizes). On `client.beta.messages.*` with beta `context-management-2025-06-27`, pass `context_management.edits` with a strategy type:
421
+
422
+ ```python
423
+ client.beta.messages.create(
424
+ model="claude-opus-4-8", max_tokens=4096,
425
+ betas=["context-management-2025-06-27"],
426
+ context_management={"edits": [{"type": "clear_tool_uses_20250919"}]},
427
+ tools=[...], messages=[...],
428
+ )
429
+ ```
430
+
431
+ Strategy types: `clear_tool_uses_20250919` (clears old tool results; optional `clear_tool_inputs: true` also clears the tool_use params) and `clear_thinking_20251015` (clears thinking blocks). Do **not** use `compact_20260112` or beta `compact-2026-01-12` — those are the separate compaction feature.
432
+
433
+ ## Mid-Conversation System Messages (Quick Reference)
434
+
435
+ **Claude Opus 4.8 only; no beta header.** Append `{"role": "system", "content": "…"}` to the `messages` array (not the top-level `system` field) to add an operator instruction mid-conversation without invalidating the cached prefix. Use the regular `client.messages.create` — there is no beta. A mid-conversation system message must follow a `user` message (or an `assistant` message ending in server-tool use), and must be either the last entry in `messages` or be followed by an `assistant` turn — it cannot be `messages[0]`. Availability: `shared/platform-availability.md`. See `shared/prompt-caching.md` § Mid-conversation system messages.
436
+
437
+ ## Managed Agents (Beta)
438
+
439
+ **Managed Agents** is a third surface: server-managed stateful agents with Anthropic-hosted tool execution. You create a persisted, versioned Agent config (`POST /v1/agents`), then start Sessions that reference it. Each session provisions a container as the agent's workspace — bash, file ops, and code execution run there; the agent loop itself runs on Anthropic's orchestration layer and acts on the container via tools. The session streams events; you send messages and tool results back.
440
+
441
+ Availability: `shared/platform-availability.md`. For agents on Bedrock / Vertex / Foundry (where Managed Agents is unsupported), use Claude API + tool use.
442
+
443
+ **Mandatory flow:** Agent (once) → Session (every run). `model`/`system`/`tools` live on the agent, never the session. See `shared/managed-agents-overview.md` for the full reading guide, beta headers, and pitfalls.
444
+
445
+ **Beta headers:** `managed-agents-2026-04-01` — the SDK sets this automatically for all `client.beta.{agents,environments,sessions,vaults,memory_stores,deployments,deployment_runs}.*` calls. Skills API uses `skills-2025-10-02` and Files API uses `files-api-2025-04-14`, but you don't need to explicitly pass those in for endpoints other than `/v1/skills` and `/v1/files`.
446
+
447
+ **Subcommands** — invoke directly with `/claude-api <subcommand>`:
448
+
449
+ | Subcommand | Action |
450
+ |---|---|
451
+ | `managed-agents-onboard` | Walk the user through setting up a Managed Agent from scratch. **Read `shared/managed-agents-onboarding.md` immediately** and follow its interview script: **describe → configure the agent (propose, don't interrogate) → environment → session** (same arc as the Console quickstart, auth deferred to the session step) — defaults and inline suggestions do the work, with a silent viability gate (job vs tools/credentials/data) before any code is emitted. Do not summarize — run the interview. |
452
+
453
+ **Reading guide:** Start with `shared/managed-agents-overview.md`, then the topical `shared/managed-agents-*.md` files (core, environments, tools, events, outcomes, multiagent, webhooks, memory, scheduled-deployments, client-patterns, onboarding, api-reference). For Python, TypeScript, Go, Ruby, PHP, and Java, read `{lang}/managed-agents/README.md` for code examples. For cURL, read `curl/managed-agents.md`. **Agents are persistent — create once, reference by ID.** Store the agent ID returned by `agents.create` and pass it to every subsequent `sessions.create`; do not call `agents.create` in the request path. The Anthropic CLI (`ant`) is one convenient way to create agents and environments from version-controlled YAML — see `shared/anthropic-cli.md`. If a binding you need isn't shown in the language README, WebFetch the relevant entry from `shared/live-sources.md` rather than guess. C# has beta Managed Agents support via `client.Beta.Agents` and related namespaces.
454
+
455
+ **When the user wants to set up a Managed Agent from scratch** (e.g. "how do I get started", "walk me through creating one", "set up a new agent"): read `shared/managed-agents-onboarding.md` and run its interview — same flow as the `managed-agents-onboard` subcommand.
456
+
457
+ **When the user asks "how do I write the client code for X":** reach for `shared/managed-agents-client-patterns.md` — covers lossless stream reconnect, `processed_at` queued/processed gate, interrupt, `tool_confirmation` round-trip, the correct idle/terminated break gate, post-idle status race, stream-first ordering, file-mount gotchas, keeping credentials host-side via custom tools, etc.
458
+
459
+ **When the user wants the agent to run on a schedule** (cron, "every night", "weekly report"): read `shared/managed-agents-scheduled-deployments.md` — deployments fire sessions autonomously on a cron cadence, with per-firing run records and lifecycle controls (pause/unpause/archive).
460
+
461
+ ## Server Tools (Quick Reference)
462
+
463
+ Server-side tools run on Anthropic's infrastructure — no client-side execution loop. Declare in `tools`; results arrive as content blocks in the same response. **No beta header** unless noted. **Prefer the latest type variant your model supports.** The `_20260209` web search / web fetch variants below (dynamic filtering) require Opus 4.8/4.7/4.6, Sonnet 5, or Sonnet 4.6; the basic variants for older models are listed after the table.
464
+
465
+ | Tool | `type` | `name` | Key optional params | Result block type |
466
+ |---|---|---|---|---|
467
+ | Web search | `web_search_20260209` | `web_search` | `max_uses`, `allowed_domains`/`blocked_domains`, `user_location` | `web_search_tool_result` → `.content` is a list of `web_search_result` |
468
+ | Web fetch | `web_fetch_20260209` | `web_fetch` | `max_uses`, `allowed_domains`/`blocked_domains`, `citations`, `max_content_tokens` | `web_fetch_tool_result` → `.content` is a `web_fetch_result` with a `document` block |
469
+ | Code execution | `code_execution_20260521` | `code_execution` | none | `bash_code_execution_tool_result` → `.content.stdout` / `.stderr` / `.return_code` |
470
+ | Tool search (regex) | `tool_search_tool_regex_20251119` | `tool_search_tool_regex` | mark other tools `defer_loading: true` | `tool_search_tool_result` |
471
+ | Tool search (BM25) | `tool_search_tool_bm25_20251119` | `tool_search_tool_bm25` | mark other tools `defer_loading: true` | `tool_search_tool_result` |
472
+
473
+ `web_search_20260209` / `web_fetch_20260209` have built-in dynamic filtering — code execution runs under the hood, so do **not** separately declare `code_execution` in `tools` (a second execution environment confuses the model). For models older than Opus 4.6 / Sonnet 4.6, use the basic variants `web_search_20250305` / `web_fetch_20250910` instead; on Vertex AI only basic `web_search_20250305` is available. `code_execution_20260120` (REPL persistence + programmatic tool calling) runs on Opus 4.5+ / Sonnet 4.5+. **Go SDK only**: `code_execution_20260521` lives under `client.Beta.Messages.New` with `Betas: []anthropic.AnthropicBeta{"code-execution-2025-08-25"}` (other languages use plain `client.messages.create`); `code_execution_20260120` uses the non-beta `client.Messages.New` in Go like everywhere else. Web fetch only fetches URLs already present in the conversation. Provider availability varies by tool — see `shared/platform-availability.md`. See `shared/tool-use-concepts.md` for `pause_turn` handling.
474
+
475
+ ## Document & File Input (Quick Reference)
476
+
477
+ **PDF (base64, no beta):** `{"type": "document", "source": {"type": "base64", "media_type": "application/pdf", "data": <b64 string>}}` in user content, placed before the text block. Base64 string must have no newlines. Limits: 32 MB request, 600 pages (100 for 200k-context models). Java: `ContentBlockParam.ofDocument(DocumentBlockParam... Base64PdfSource.builder().data(...))`.
478
+
479
+ **Files API (beta `files-api-2025-04-14`):** upload via `client.beta.files.upload(...)` → response `id` is the `file_id`. Reference it as `{"type": "document", "source": {"type": "file", "file_id": "..."}}` for PDF/text, or `{"type": "image", ...}` for images — the content-block type must match the file's MIME type. The beta header is required on **both** the upload and the `messages.create` that references the file. Availability: `shared/platform-availability.md`.
480
+
481
+ **Citations (no beta):** set `citations: {enabled: true}` on each `document` content block (all or none). Response splits into multiple `text` blocks; cited blocks carry a `citations` array. Each citation has `cited_text`, `document_index`, `document_title`, and a location by `type`: `char_location` (`start_char_index`/`end_char_index`) for plain text, `page_location` (`start_page_number`/`end_page_number`, 1-indexed) for PDF, `content_block_location` for custom content. Incompatible with `output_config.format`.
482
+
483
+ ## Tool Use Patterns (Quick Reference)
484
+
485
+ **Strict tool use (no beta):** set `strict: true` as a top-level field on the tool definition (alongside `name`/`description`/`input_schema`), **not** on `tool_choice`. Schema must have `additionalProperties: false` + `required`. Guarantees `tool_use.input` validates exactly. Go: `Strict: anthropic.Bool(true)` + `additionalProperties` via `InputSchema.ExtraFields`; Java: `.strict(true)` + `.putAdditionalProperty("additionalProperties", JsonValue.from(false))`.
486
+
487
+ **Parallel tool use (default on):** one assistant message may contain multiple `tool_use` blocks. Execute them concurrently, then return **all** `tool_result` blocks in a **single** user message (don't split across multiple messages). For a failed tool, return `tool_result` with `is_error: true` — don't drop it.
488
+
489
+ **Tool Runner (SDK beta helper):** drives the tool-call loop for you via `client.beta.messages.*`. Python: `@beta_tool` decorator + `client.beta.messages.tool_runner(...)` → `runner.until_done()`. TypeScript: `betaZodTool({...})` from `@anthropic-ai/sdk/helpers/beta/zod` + `client.beta.messages.toolRunner(...)` → `await runner`. Go: `toolrunner.NewBetaToolFromJSONSchema(...)` + `client.Beta.Messages.NewToolRunner(...)` → `.RunToCompletion(ctx)`. Java requires `.addBeta("structured-outputs-2025-11-13")`. Ruby: `Anthropic::BaseTool` subclass + `client.beta.messages.tool_runner(...)`. PHP: `BetaRunnableTool` + `->toolRunner(...)`. C#: raw JSON-schema tools + `BetaToolRunner` via `client.Beta.Messages.ToolRunner(...)`.
490
+
491
+ **Programmatic tool calling (no beta header):** Claude calls your custom tool from inside code execution. Add `{"type": "code_execution_20260120", "name": "code_execution"}` **and** set `"allowed_callers": ["code_execution_20260120"]` on your custom tool. Opus 4.5+ / Sonnet 4.5+ (availability: `shared/platform-availability.md`). When responding to a pending programmatic call, the user message must contain **only** `tool_result` blocks (no text). Not compatible with `strict: true`, `disable_parallel_tool_use`, forced `tool_choice`, or MCP tools.
492
+
493
+ ## Other API Surfaces (Quick Reference)
494
+
495
+ **Message Batches (no beta; availability: `shared/platform-availability.md`):** `client.messages.batches.create(requests=[{custom_id, params}, ...])` → poll `client.messages.batches.retrieve(id).processing_status` until `"ended"` → stream `client.messages.batches.results(id)`. Each result has `.custom_id` + `.result.type` (`succeeded`/`errored`/`canceled`/`expired`); on success read `.result.message.content`. Python wraps requests as `Request(custom_id=..., params=MessageCreateParamsNonStreaming(...))`. Results arrive in **any order** — key by `custom_id`, never by position.
496
+
497
+ **Models API (no beta; availability: `shared/platform-availability.md`):** `client.models.list()` (auto-paginates) and `client.models.retrieve("claude-opus-4-8")`. Each model object has `id`, `display_name`, `created_at`, and — since Mar 2026 — `max_input_tokens` (the context window), `max_tokens` (the output cap), and `capabilities`. There is no `context_window` field.
498
+
499
+ **Stop details (GA, Opus 4.7+):** `response.stop_details` is populated **only when `stop_reason == "refusal"`** (fields: `type: "refusal"`, `category: "cyber"|"bio"|null`, `explanation`). It is `null` for every other `stop_reason` (`end_turn`, `max_tokens`, `tool_use`, `pause_turn`, …) — always guard before reading.
500
+
501
+ **Client config (no beta):** `timeout` default 10 min; **units differ by SDK** — Python/Ruby: seconds; TypeScript: **milliseconds**; Go `option.WithRequestTimeout(time.Duration)`; Java `Duration`; C# `TimeSpan`. TS scales the default up to 60 min for large `max_tokens` on non-streaming requests; Java does so for streaming requests (Java non-streaming scales 30s–10 min). `max_retries`/`maxRetries` default 2 (retries 408/409/429/5xx + connection errors). `base_url` (or `ANTHROPIC_BASE_URL` env). Per-request override: Python `client.with_options(timeout=5.0).messages.create(...)`; TS `client.messages.create({...}, {timeout: 5_000})`; Ruby `request_options: {timeout: 5}`. Timeouts are retried — wall-clock can reach `timeout × (max_retries+1)`.
502
+
503
+ ## Workload Identity Federation (Quick Reference)
504
+
505
+ **GA, no beta header.** Construct the normal zero-arg client (`Anthropic()` / `new Anthropic()` / `anthropic.NewClient()` / `AnthropicOkHttpClient.fromEnv()`); the SDK auto-detects WIF when **all** of `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID`, and `ANTHROPIC_IDENTITY_TOKEN_FILE` (or `ANTHROPIC_IDENTITY_TOKEN`) are set, exchanges the JWT at `/v1/oauth/token`, and auto-refreshes. `ANTHROPIC_WORKSPACE_ID` does not gate activation — required only when the federation rule spans multiple workspaces (else 400 `workspace_id_required`), optional for single-workspace rules. `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN` (even empty) outrank WIF, and a set `ANTHROPIC_PROFILE` also wins over the federation env vars (a missing named profile is an error, not a fall-through) — unset all three.
506
+
507
+ ---
508
+ <!-- module: 02-common-pitfalls.md -->
509
+
510
+ # Common Pitfalls
511
+
512
+ ## Common Pitfalls
513
+
514
+ - **No `ANTHROPIC_API_KEY` ≠ no credentials.** Don't bail or ask the user for a key just because the env var is unset — run `ant auth status` first. After `ant auth login`, a bare `Anthropic()` client and `ant …` work with no env var; for raw curl, use `Authorization: Bearer $(ant auth print-credentials --access-token)` plus header `anthropic-beta: oauth-2025-04-20`. See the Authentication quick reference above and `shared/anthropic-cli.md`.
515
+ - Don't truncate inputs when passing files or content to the API. If the content is too long to fit in the context window, notify the user and discuss options (chunking, summarization, etc.) rather than silently truncating.
516
+ - **Fable 5 / Sonnet 5 / Opus 4.8 / 4.7 thinking:** Adaptive only. `thinking: {type: "enabled", budget_tokens: N}` returns 400 — `budget_tokens` is fully removed (along with `temperature`, `top_p`, `top_k`). Use `thinking: {type: "adaptive"}`. Opus 4.8 inherits this surface from 4.7 with no new breaking changes; Fable 5 adds one — an explicit `thinking: {type: "disabled"}` returns a 400 (accepted on Sonnet 5 / 4.7 / 4.8); omit the param instead.
517
+ - **Opus 4.6 / Sonnet 4.6 thinking:** Use `thinking: {type: "adaptive"}` — do NOT use `budget_tokens` for new 4.6 code (deprecated on both Opus 4.6 and Sonnet 4.6; for gradual migration of existing code, see the transitional escape hatch in `shared/model-migration.md` — note this carve-out does not apply to Fable 5, Opus 4.7 or 4.8). For older models, `budget_tokens` must be less than `max_tokens` (minimum 1024). This will throw an error if you get it wrong.
518
+ - **Prefill removed (Fable 5 and the 4.6/4.7/4.8 family):** Assistant message prefills (last-assistant-turn prefills) return a 400 error on Fable 5, Opus 4.6, Opus 4.7, Opus 4.8, and Sonnet 4.6. Use structured outputs (`output_config.format`) or system prompt instructions to control response format instead. (One exception: the fallback-credit prefill claim — when redeeming a credit with `fallback_has_prefill_claim: true`, the server accepts the echoed assistant message; see the migration guide's refusal section.)
519
+ - **Fable 5 `refusal` stop reason:** Safety classifiers may decline a request — a successful HTTP 200 with `stop_reason: "refusal"` (pre-output: empty `content`, nothing billed; mid-stream: partial output billed — discard it). Check `stop_reason` before reading `response.content[0]`, or you'll hit index errors on refused requests. To retry on another model, replay the history as-is — other models drop the refused model's thinking blocks from the prompt, unbilled; no stripping needed (and a fallback-credit redemption must echo the refused body exactly anyway, thinking blocks included). Fallbacks are **opt-in** — new `claude-fable-5` code should include the server-side `fallbacks` parameter by default so a refusal doesn't fail the request outright; see the Claude Fable 5 section above.
520
+ - **Fable 5 tokenizer:** Same tokenizer as Opus 4.8 — token counts are roughly unchanged when migrating from Opus 4.7/4.8. Coming from Opus 4.6, Sonnet, Haiku, or older, token counts differ (the Opus 4.7 tokenizer uses ~1×–1.35× as many tokens) — re-measure by calling `count_tokens` once with each model and comparing `input_tokens`.
521
+ - **Confirm migration scope before editing:** When a user asks to migrate code to a newer Claude model without naming a specific file, directory, or file list, **ask which scope to apply first** — the entire working directory, a specific subdirectory, or a specific set of files. Do not start editing until the user confirms. Imperative phrasings like "migrate my codebase", "move my project to X", "upgrade to Sonnet 4.6", or bare "migrate to Opus 4.8" are **still ambiguous** — they tell you what to do but not where, so ask. Proceed without asking only when the prompt names an exact file, a specific directory, or an explicit file list ("migrate `app.py`", "migrate everything under `services/`", "update `a.py` and `b.py`"). See `shared/model-migration.md` Step 0.
522
+ - **`max_tokens` defaults:** Don't lowball `max_tokens` — hitting the cap truncates output mid-thought and requires a retry. For non-streaming requests, default to `~16000` (keeps responses under SDK HTTP timeouts). For streaming requests, default to `~64000` (timeouts aren't a concern, so give the model room). Only go lower when you have a hard reason: classification (`~256`), cost caps, deliberately short outputs, or **`max_tokens: 0`** for cache pre-warming (see `shared/prompt-caching.md` → Pre-warming).
523
+ - **128K output tokens:** Fable 5, Opus 4.6, Opus 4.7, Opus 4.8, Sonnet 5, and Sonnet 4.6 support up to 128K `max_tokens`, but the SDKs require streaming for values that large to avoid HTTP timeouts. Use `.stream()` with `.get_final_message()` / `.finalMessage()`.
524
+ - **Tool call JSON parsing (Fable 5 and the 4.6/4.7/4.8 family):** Fable 5, Opus 4.6, Opus 4.7, Opus 4.8, and Sonnet 4.6 may produce different JSON string escaping in tool call `input` fields (e.g., Unicode or forward-slash escaping). Always parse tool inputs with `json.loads()` / `JSON.parse()` — never do raw string matching on the serialized input.
525
+ - **Structured outputs (all models):** Use `output_config: {format: {...}}` instead of the deprecated `output_format` parameter on `messages.create()`. This is a general API change, not 4.6-specific.
526
+ - **Don't reimplement SDK functionality:** The SDK provides high-level helpers — use them instead of building from scratch. Specifically: use `stream.finalMessage()` instead of wrapping `.on()` events in `new Promise()`; use typed exception classes (`Anthropic.RateLimitError`, etc.) instead of string-matching error messages; use SDK types (`Anthropic.MessageParam`, `Anthropic.Tool`, `Anthropic.Message`, etc.) instead of redefining equivalent interfaces.
527
+ - **Error handling — catch a chain, not one broad class.** A single `except APIStatusError` / `catch (AnthropicServiceException)` / `rescue APIError` loses the distinction between retryable (429, ≥500, network) and non-retryable (400/404) failures. Write a most-specific-first chain — e.g. `NotFoundError` → `RateLimitError` → `APIStatusError` → `APIConnectionError` (or the Go equivalent: `errors.As` into `*anthropic.Error` then `switch apierr.StatusCode { case 404: …; case 429: …; default: … }`). Per-language class names and namespaces are in `shared/error-codes.md`.
528
+ - **Don't research SDK types — write first.** If a type name isn't shown in the documentation included in this skill, write the code file from the namespace/package tables in the language-specific doc and let the compiler's error point you to the right name. Do not spend turns on WebFetch, SDK-repo clones, or compiling-and-running a separate reflection program to discover type names before writing — produce the source file first, then fix what the compiler reports. A quick `strings` / `jar tf` / `javap` against the installed SDK is acceptable for locating names (it returns in seconds), but don't escalate beyond that. A file with a wrong type name is recoverable; a session spent on discovery with no file written is not.
529
+ - **Bash and text editor tools are Anthropic-defined, schema-less.** Declare `{"type": "bash_20250124", "name": "bash"}` / `{"type": "text_editor_20250728", "name": "str_replace_based_edit_tool"}` — no `input_schema`. A custom tool with your own schema named `"bash"` is a different tool. Handler paths and security checks are in `shared/tool-use-concepts.md` § Client-Side Tools.
530
+ - **Advisor tool model pairing.** The advisor tool's `model` must be at least as capable as the request's top-level `model` — e.g. executor `claude-sonnet-5` → advisor `claude-opus-4-8` or `claude-opus-4-7`. An invalid pair returns 400. Pairing table in `shared/tool-use-concepts.md` § Advisor. Availability: `shared/platform-availability.md`.
531
+ - **Agent Skills ≠ Managed Agents.** To have Claude generate a `.pptx`/`.xlsx`/etc. via Agent Skills, call `client.beta.messages.create` with `container={"skills": [...]}`, the `code_execution_20260521` tool, and both `code-execution-2025-08-25` + `skills-2025-10-02` betas. Do not use `client.beta.agents` / `sessions` / `environments` here — those are the Managed Agents surface, not Agent Skills.
532
+ - **MCP connector needs both halves.** `mcp_servers=[{type:"url", url, name}]` alone is rejected as a validation error — also add `tools=[{type:"mcp_toolset", mcp_server_name:<same name>}]` with beta `mcp-client-2025-11-20`. Availability: `shared/platform-availability.md`.
533
+ - **Context editing ≠ compaction.** Context editing *clears* tool results and thinking blocks; compaction *summarizes* history. For context editing, use `context_management.edits` with type `clear_tool_uses_20250919` (or `clear_thinking_20251015`) on `client.beta.messages.*` with beta `context-management-2025-06-27` — not the `compact_20260112` type or `compact-2026-01-12` beta, which are compaction.
534
+ - **`inference_geo` is a direct top-level request parameter** — `client.messages.create(..., inference_geo="us")` / `.inferenceGeo("us")`. Do not put it in `extra_body` / `putAdditionalBodyProperty`. Supported on Opus 4.6 / Sonnet 4.6 and later; availability: `shared/platform-availability.md`. `response.usage.inference_geo` reports where inference ran.
535
+ - **Fine-grained tool streaming is not a beta feature.** Set `eager_input_streaming: true` on the tool definition and call the regular `client.messages.stream(...)`. There is no beta header and no `client.beta.*` path.
536
+ - **Cache diagnostics is beta.** Use `client.beta.messages.*` with beta `cache-diagnosis-2026-04-07`. Pass `diagnostics: {previous_message_id: null}` on the first turn and `diagnostics: {previous_message_id: <previous response id>}` on subsequent turns; the result is on `response.diagnostics`. Availability: `shared/platform-availability.md`.
537
+ - **Memory tool type is `memory_20250818`.** Declare `{"type": "memory_20250818", "name": "memory"}`. Go uses the beta-namespace type `{OfMemoryTool20250818: &anthropic.BetaMemoryTool20250818Param{}}` on `client.Beta.Messages.New`; Python/TypeScript/Ruby/PHP/C# use the non-beta `client.messages.create`; Java has both a non-beta `MemoryTool20250818` and a beta tool-runner path. Python/TypeScript provide `BetaAbstractMemoryTool` / `betaMemoryTool` helpers for implementing the backend.
538
+ - **Use a model the feature actually supports.** Some features are restricted to specific model tiers — fast mode is Opus 4.8 / 4.7 only, task budgets are Fable 5 / Sonnet 5 / Opus 4.8 / 4.7 only, and the advisor tool requires a valid executor↔advisor pair. If the user's prompt names a model that the feature doesn't support, use a supported model instead and note the substitution in the output.
539
+ - **Bedrock / Foundry: use the platform client class.** For Bedrock use the `…BedrockMantle…` client (e.g. Python `AnthropicBedrockMantle`, Java `BedrockMantleBackend`) with `anthropic.`-prefixed model IDs; `AnthropicBedrock`/`BedrockBackend` without `Mantle` is the legacy path. For Foundry use `AnthropicFoundry` / `FoundryBackend` / `AnthropicFoundryClient` where the SDK supports it (C#, Java, PHP, Python, TypeScript); Go and Ruby have no Foundry client — Ruby's documented fallback is the first-party client with a custom `base_url`. Per-language table above.
540
+ - **Don't define custom types for SDK data structures:** The SDK exports types for all API objects. Use `Anthropic.MessageParam` for messages, `Anthropic.Tool` for tool definitions, `Anthropic.ToolUseBlock` / `Anthropic.ToolResultBlockParam` for tool results, `Anthropic.Message` for responses. Defining your own `interface ChatMessage { role: string; content: unknown }` duplicates what the SDK already provides and loses type safety.
541
+ - **Report and document output:** For tasks that produce reports, documents, or visualizations, the code execution sandbox has `python-docx`, `python-pptx`, `matplotlib`, `pillow`, and `pypdf` pre-installed. Claude can generate formatted files (DOCX, PDF, charts) and return them via the Files API — consider this for "report" or "document" type requests instead of plain stdout text.
542
+ - **Server-tool errors don't raise.** Web search and web fetch errors return HTTP 200 with a `web_search_tool_result` / `web_fetch_tool_result` block whose `content` is a single error object (e.g. `{error_code: "max_uses_exceeded"}`) — not a raised exception. For web search, a success `content` is a *list*; an error `content` is an *object* — branch on that before indexing.
543
+ - **Code execution output block type:** `code_execution_20260521` returns `bash_code_execution_tool_result` (with `.content.stdout`), **not** the legacy bare `code_execution_tool_result`. Iterate `response.content` and match on the correct type.
544
+ - **Tool search: never defer everything.** The search tool itself must not have `defer_loading: true`, and at least one tool in `tools` must be non-deferred, or the API returns 400 `All tools have defer_loading set`.
545
+ - **`strict: true` goes on the tool, not `tool_choice`.** Putting `strict` on `tool_choice` does nothing; it's a sibling of `name`/`description`/`input_schema` on the tool definition itself.
546
+ - **Parallel tool results go in ONE user message.** Splitting `tool_result` blocks across multiple user messages silently trains Claude to stop making parallel calls. One assistant message of `tool_use` blocks → one user message of `tool_result` blocks.
547
+ - **Citations + structured outputs are incompatible.** Enabling `citations: {enabled: true}` on a document while also setting `output_config.format` returns a 400.
548
+ - **Batch results are unordered.** Match by `custom_id`, never by position in the results stream.
549
+ - **Vertex model IDs have no prefix.** Unlike Bedrock's `anthropic.`-prefixed IDs, Vertex takes the bare first-party ID for current-generation models (e.g. `"claude-opus-4-8"`); dated-snapshot models use an `@` separator (e.g. `claude-haiku-4-5@20251001`).
550
+ - **`stop_details` is `null` unless `stop_reason == "refusal"`.** For `max_tokens`, `end_turn`, etc., `stop_details` is `null` — guard before reading `.category`.
551
+ - **WIF auth: unset `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and `ANTHROPIC_PROFILE`.** `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` (even set to `""`) outrank Workload Identity Federation in the SDK's precedence chain and silently win; a set `ANTHROPIC_PROFILE` also wins (a missing named profile is an error, not a fall-through). `unset` them, don't blank them.
552
+
553
+ ---
554
+ <!-- module: 50-python-readme.md -->
555
+
556
+ # Claude API — Python
557
+
558
+ ## Installation
559
+
560
+ ```bash
561
+ pip install anthropic
562
+ ```
563
+
564
+ ## Client Initialization
565
+
566
+ ```python
567
+ import anthropic
568
+
569
+ # Default — resolves credentials from the environment:
570
+ # ANTHROPIC_API_KEY, or ANTHROPIC_AUTH_TOKEN, or an `ant auth login` profile.
571
+ # Prefer this for local dev; don't hardcode a key.
572
+ client = anthropic.Anthropic()
573
+
574
+ # Explicit API key (only when you must inject a specific key)
575
+ client = anthropic.Anthropic(api_key="your-api-key")
576
+
577
+ # Async client
578
+ async_client = anthropic.AsyncAnthropic()
579
+ ```
580
+
581
+ ---
582
+
583
+ ## Client Configuration
584
+
585
+ ### Per-request overrides
586
+
587
+ Use `with_options()` to override client settings for a single call without mutating the client:
588
+
589
+ ```python
590
+ client.with_options(timeout=5.0, max_retries=5).messages.create(
591
+ model="claude-opus-4-8",
592
+ max_tokens=1024,
593
+ messages=[{"role": "user", "content": "Hello"}],
594
+ )
595
+ ```
596
+
597
+ ### Timeouts
598
+
599
+ Default request timeout is 10 minutes. Pass a float (seconds) or an `httpx.Timeout` for granular control. On timeout the SDK raises `anthropic.APITimeoutError` (and retries per `max_retries`).
600
+
601
+ ```python
602
+ import httpx
603
+
604
+ client = anthropic.Anthropic(timeout=20.0)
605
+ client = anthropic.Anthropic(
606
+ timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
607
+ )
608
+ ```
609
+
610
+ ### Retries
611
+
612
+ The SDK auto-retries connection errors, 408, 409, 429, and ≥500 with exponential backoff (default 2 retries). Set `max_retries` on the client or via `with_options()`; `max_retries=0` disables.
613
+
614
+ ### Async performance (aiohttp backend)
615
+
616
+ For high-concurrency async workloads, install `anthropic[aiohttp]` and pass `DefaultAioHttpClient` instead of the default httpx backend:
617
+
618
+ ```python
619
+ from anthropic import AsyncAnthropic, DefaultAioHttpClient
620
+
621
+ async with AsyncAnthropic(http_client=DefaultAioHttpClient()) as client:
622
+ ...
623
+ ```
624
+
625
+ ### Custom HTTP client (proxy, base URL)
626
+
627
+ Use `DefaultHttpxClient` / `DefaultAsyncHttpxClient` — not raw `httpx.Client` — so the SDK's default timeouts and connection limits are preserved:
628
+
629
+ ```python
630
+ from anthropic import Anthropic, DefaultHttpxClient
631
+
632
+ client = Anthropic(
633
+ base_url="http://my.test.server.example.com:8083", # or ANTHROPIC_BASE_URL env var
634
+ http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com"),
635
+ )
636
+ ```
637
+
638
+ ### Logging
639
+
640
+ Set `ANTHROPIC_LOG=debug` (or `info`) to enable SDK logging via the standard `logging` module.
641
+
642
+ ---
643
+
644
+ ## Basic Message Request
645
+
646
+ ```python
647
+ response = client.messages.create(
648
+ model="claude-opus-4-8",
649
+ max_tokens=16000,
650
+ messages=[
651
+ {"role": "user", "content": "What is the capital of France?"}
652
+ ]
653
+ )
654
+ # response.content is a list of content block objects (TextBlock, ThinkingBlock,
655
+ # ToolUseBlock, ...). Check .type before accessing .text.
656
+ for block in response.content:
657
+ if block.type == "text":
658
+ print(block.text)
659
+ ```
660
+
661
+ ---
662
+
663
+ ## System Prompts
664
+
665
+ ```python
666
+ response = client.messages.create(
667
+ model="claude-opus-4-8",
668
+ max_tokens=16000,
669
+ system="You are a helpful coding assistant. Always provide examples in Python.",
670
+ messages=[{"role": "user", "content": "How do I read a JSON file?"}]
671
+ )
672
+ ```
673
+
674
+ ### Mid-conversation system messages (model-gated)
675
+
676
+ For operator instructions that arrive mid-conversation (mode switches, injected state), append `{"role": "system", ...}` to `messages` instead of editing top-level `system` — this preserves the cached prefix and carries operator authority. Must follow a user message (or an `assistant` message ending in server-tool use), and must be either the last entry in `messages` or be followed by an `assistant` turn; cannot be `messages[0]`. Unsupported models return a 400 (`role 'system' is not supported on this model`). See `shared/prompt-caching.md` for when to use this vs. top-level `system`.
677
+
678
+ ```python
679
+ response = client.messages.create(
680
+ model=MODEL_ID, # must support mid-conversation system messages
681
+ max_tokens=16000,
682
+ system=[{"type": "text", "text": STABLE_SYSTEM, "cache_control": {"type": "ephemeral"}}],
683
+ messages=history + [
684
+ {"role": "user", "content": user_message},
685
+ {"role": "system", "content": "Terse mode enabled — keep responses under 40 words."},
686
+ ],
687
+ ) # No beta header needed — use regular client.messages.create
688
+ ```
689
+
690
+ ---
691
+
692
+ ## Vision (Images)
693
+
694
+ ### Base64
695
+
696
+ ```python
697
+ import base64
698
+
699
+ with open("image.png", "rb") as f:
700
+ image_data = base64.standard_b64encode(f.read()).decode("utf-8")
701
+
702
+ response = client.messages.create(
703
+ model="claude-opus-4-8",
704
+ max_tokens=16000,
705
+ messages=[{
706
+ "role": "user",
707
+ "content": [
708
+ {
709
+ "type": "image",
710
+ "source": {
711
+ "type": "base64",
712
+ "media_type": "image/png",
713
+ "data": image_data
714
+ }
715
+ },
716
+ {"type": "text", "text": "What's in this image?"}
717
+ ]
718
+ }]
719
+ )
720
+ ```
721
+
722
+ ### URL
723
+
724
+ ```python
725
+ response = client.messages.create(
726
+ model="claude-opus-4-8",
727
+ max_tokens=16000,
728
+ messages=[{
729
+ "role": "user",
730
+ "content": [
731
+ {
732
+ "type": "image",
733
+ "source": {
734
+ "type": "url",
735
+ "url": "https://example.com/image.png"
736
+ }
737
+ },
738
+ {"type": "text", "text": "Describe this image"}
739
+ ]
740
+ }]
741
+ )
742
+ ```
743
+
744
+ ---
745
+
746
+ ## Prompt Caching
747
+
748
+ Cache large context to reduce costs (up to 90% savings). **Caching is a prefix match** — any byte change anywhere in the prefix invalidates everything after it. For placement patterns, architectural guidance (frozen system prompt, deterministic tool order, where to put volatile content), and the silent-invalidator audit checklist, read `shared/prompt-caching.md`.
749
+
750
+ ### Automatic Caching (Recommended)
751
+
752
+ Use top-level `cache_control` to automatically cache the last cacheable block in the request — no need to annotate individual content blocks:
753
+
754
+ ```python
755
+ response = client.messages.create(
756
+ model="claude-opus-4-8",
757
+ max_tokens=16000,
758
+ cache_control={"type": "ephemeral"}, # auto-caches the last cacheable block
759
+ system="You are an expert on this large document...",
760
+ messages=[{"role": "user", "content": "Summarize the key points"}]
761
+ )
762
+ ```
763
+
764
+ ### Manual Cache Control
765
+
766
+ For fine-grained control, add `cache_control` to specific content blocks:
767
+
768
+ ```python
769
+ response = client.messages.create(
770
+ model="claude-opus-4-8",
771
+ max_tokens=16000,
772
+ system=[{
773
+ "type": "text",
774
+ "text": "You are an expert on this large document...",
775
+ "cache_control": {"type": "ephemeral"} # default TTL is 5 minutes
776
+ }],
777
+ messages=[{"role": "user", "content": "Summarize the key points"}]
778
+ )
779
+
780
+ # With explicit TTL (time-to-live)
781
+ response = client.messages.create(
782
+ model="claude-opus-4-8",
783
+ max_tokens=16000,
784
+ system=[{
785
+ "type": "text",
786
+ "text": "You are an expert on this large document...",
787
+ "cache_control": {"type": "ephemeral", "ttl": "1h"} # 1 hour TTL
788
+ }],
789
+ messages=[{"role": "user", "content": "Summarize the key points"}]
790
+ )
791
+ ```
792
+
793
+ ### Verifying Cache Hits
794
+
795
+ ```python
796
+ print(response.usage.cache_creation_input_tokens) # tokens written to cache (~1.25x cost)
797
+ print(response.usage.cache_read_input_tokens) # tokens served from cache (~0.1x cost)
798
+ print(response.usage.input_tokens) # uncached tokens (full cost)
799
+ ```
800
+
801
+ If `cache_read_input_tokens` is zero across repeated identical-prefix requests, a silent invalidator is at work — `datetime.now()` or a UUID in the system prompt, unsorted `json.dumps()`, or a varying tool set. See `shared/prompt-caching.md` for the full audit table.
802
+
803
+ ---
804
+
805
+ ## Extended Thinking
806
+
807
+ > **Fable 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6:** Use adaptive thinking. `budget_tokens` is removed on Fable 5, Opus 4.8, and 4.7 (400 if sent); deprecated on Opus 4.6 and Sonnet 4.6.
808
+ > **Older models:** Use `thinking: {type: "enabled", budget_tokens: N}` (must be < `max_tokens`, min 1024).
809
+
810
+ ```python
811
+ # Fable 5 / Opus 4.8 / 4.7 / 4.6: adaptive thinking (recommended)
812
+ response = client.messages.create(
813
+ model="claude-opus-4-8",
814
+ max_tokens=16000,
815
+ thinking={"type": "adaptive", "display": "summarized"}, # display opt-in: default is omitted (empty thinking text) on Fable 5 / Mythos 5 / Opus 4.8 / 4.7
816
+ output_config={"effort": "high"}, # low | medium | high | max
817
+ messages=[{"role": "user", "content": "Solve this step by step..."}]
818
+ )
819
+
820
+ # Access thinking and response
821
+ for block in response.content:
822
+ if block.type == "thinking":
823
+ print(f"Thinking: {block.thinking}")
824
+ elif block.type == "text":
825
+ print(f"Response: {block.text}")
826
+ ```
827
+
828
+ ---
829
+
830
+ ## Error Handling
831
+
832
+ ```python
833
+ import anthropic
834
+
835
+ try:
836
+ response = client.messages.create(...)
837
+ except anthropic.BadRequestError as e:
838
+ print(f"Bad request: {e.message}")
839
+ except anthropic.AuthenticationError:
840
+ print("Invalid API key")
841
+ except anthropic.PermissionDeniedError:
842
+ print("API key lacks required permissions")
843
+ except anthropic.NotFoundError:
844
+ print("Invalid model or endpoint")
845
+ except anthropic.RateLimitError as e:
846
+ retry_after = int(e.response.headers.get("retry-after", "60"))
847
+ print(f"Rate limited. Retry after {retry_after}s.")
848
+ except anthropic.APIStatusError as e:
849
+ if e.status_code >= 500:
850
+ print(f"Server error ({e.status_code}). Retry later.")
851
+ else:
852
+ print(f"API error: {e.message}")
853
+ except anthropic.APIConnectionError:
854
+ print("Network error. Check internet connection.")
855
+ ```
856
+
857
+ ---
858
+
859
+ ## Response Helpers
860
+
861
+ Every response object exposes `_request_id` (populated from the `request-id` header) — log it when reporting failures to Anthropic. Despite the underscore prefix, this property is public.
862
+
863
+ ```python
864
+ message = client.messages.create(...)
865
+ print(message._request_id) # req_018EeWyXxfu5pfWkrYcMdjWG
866
+ print(message.to_json()) # serialize the Pydantic model
867
+ print(message.to_dict()) # plain dict
868
+ ```
869
+
870
+ To access raw headers or other response metadata, use `.with_raw_response`:
871
+
872
+ ```python
873
+ raw = client.messages.with_raw_response.create(
874
+ model="claude-opus-4-8",
875
+ max_tokens=1024,
876
+ messages=[{"role": "user", "content": "Hello"}],
877
+ )
878
+ print(raw.headers.get("request-id"))
879
+ message = raw.parse() # the Message object messages.create() would have returned
880
+ ```
881
+
882
+ ---
883
+
884
+ ## Multi-Turn Conversations
885
+
886
+ The API is stateless — send the full conversation history each time.
887
+
888
+ ```python
889
+ class ConversationManager:
890
+ """Manage multi-turn conversations with the Claude API."""
891
+
892
+ def __init__(self, client: anthropic.Anthropic, model: str, system: str = None):
893
+ self.client = client
894
+ self.model = model
895
+ self.system = system
896
+ self.messages = []
897
+
898
+ def send(self, user_message: str, **kwargs) -> str:
899
+ """Send a message and get a response."""
900
+ self.messages.append({"role": "user", "content": user_message})
901
+
902
+ response = self.client.messages.create(
903
+ model=self.model,
904
+ max_tokens=kwargs.get("max_tokens", 16000),
905
+ system=self.system,
906
+ messages=self.messages,
907
+ **kwargs
908
+ )
909
+
910
+ assistant_message = next(
911
+ (b.text for b in response.content if b.type == "text"), ""
912
+ )
913
+ self.messages.append({"role": "assistant", "content": assistant_message})
914
+
915
+ return assistant_message
916
+
917
+ # Usage
918
+ conversation = ConversationManager(
919
+ client=anthropic.Anthropic(),
920
+ model="claude-opus-4-8",
921
+ system="You are a helpful assistant."
922
+ )
923
+
924
+ response1 = conversation.send("My name is Alice.")
925
+ response2 = conversation.send("What's my name?") # Claude remembers "Alice"
926
+ ```
927
+
928
+ **Rules:**
929
+
930
+ - Consecutive same-role messages are allowed — the API combines them into a single turn
931
+ - First message must be `user`
932
+ - `role: "system"` messages are allowed mid-conversation on supporting models (no beta header needed) — see § Mid-conversation system messages above
933
+
934
+ ---
935
+
936
+ ### Compaction (long conversations)
937
+
938
+ > **Beta, Fable 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6.** 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.
939
+
940
+ ```python
941
+ import anthropic
942
+
943
+ client = anthropic.Anthropic()
944
+ messages = []
945
+
946
+ def chat(user_message: str) -> str:
947
+ messages.append({"role": "user", "content": user_message})
948
+
949
+ response = client.beta.messages.create(
950
+ betas=["compact-2026-01-12"],
951
+ model="claude-opus-4-8",
952
+ max_tokens=16000,
953
+ messages=messages,
954
+ context_management={
955
+ "edits": [{"type": "compact_20260112"}]
956
+ }
957
+ )
958
+
959
+ # Append full content — compaction blocks must be preserved
960
+ messages.append({"role": "assistant", "content": response.content})
961
+
962
+ return next(block.text for block in response.content if block.type == "text")
963
+
964
+ # Compaction triggers automatically when context grows large
965
+ print(chat("Help me build a Python web scraper"))
966
+ print(chat("Add support for JavaScript-rendered pages"))
967
+ print(chat("Now add rate limiting and error handling"))
968
+ ```
969
+
970
+ ---
971
+
972
+ ## Stop Reasons
973
+
974
+ The `stop_reason` field in the response indicates why the model stopped generating:
975
+
976
+ | Value | Meaning |
977
+ |-------|---------|
978
+ | `end_turn` | Claude finished its response naturally |
979
+ | `max_tokens` | Hit the `max_tokens` limit — increase it or use streaming |
980
+ | `stop_sequence` | Hit a custom stop sequence |
981
+ | `tool_use` | Claude wants to call a tool — execute it and continue |
982
+ | `pause_turn` | Model paused and can be resumed (agentic flows) |
983
+ | `refusal` | Claude refused for safety reasons — check `stop_details` |
984
+
985
+ ### Structured Stop Details
986
+
987
+ When `stop_reason` is `"refusal"`, the response includes a `stop_details` object with structured information about the refusal:
988
+
989
+ ```python
990
+ if response.stop_reason == "refusal" and response.stop_details:
991
+ print(f"Category: {response.stop_details.category}") # e.g. "cyber", "bio", "reasoning_extraction", "frontier_llm", or None — see docs for the full set
992
+ print(f"Explanation: {response.stop_details.explanation}")
993
+ ```
994
+
995
+ ### Refusal Fallbacks (Claude Fable 5) — opt in by default
996
+
997
+ Fallbacks are **opt-in**: without them a refused request simply stops. Include the server-side `fallbacks` parameter in `claude-fable-5` code by default — on a policy decline the API re-runs the same request on the fallback model inside the same call. A decline before any output isn't billed (a mid-stream decline bills the streamed partial); the rescue bills at the fallback model's own rates, with cache repricing applied automatically.
998
+
999
+ ```python
1000
+ response = client.beta.messages.create(
1001
+ model="claude-fable-5",
1002
+ max_tokens=16000,
1003
+ betas=["server-side-fallback-2026-06-01"],
1004
+ fallbacks=[{"model": "claude-opus-4-8"}],
1005
+ messages=[{"role": "user", "content": "..."}],
1006
+ )
1007
+
1008
+ # Switch points: one fallback block per model that ran and declined this turn
1009
+ for block in response.content:
1010
+ if block.type == "fallback":
1011
+ print(f"{block.from_.model} declined; {block.to.model} continued")
1012
+
1013
+ # Served-by signal — covers sticky turns, which carry no fallback block.
1014
+ # Pair with stop_reason: the fallback model can itself refuse.
1015
+ fallback_ran = any(
1016
+ entry.type == "fallback_message" for entry in response.usage.iterations or []
1017
+ )
1018
+ if fallback_ran and response.stop_reason != "refusal":
1019
+ print(f"Served by {response.model}")
1020
+ ```
1021
+
1022
+ A `stop_reason: "refusal"` on the final response means the whole chain refused. The header must be exactly `server-side-fallback-2026-06-01`; the parameter is rejected on the Batches API and unavailable on Amazon Bedrock, Vertex AI, and Microsoft Foundry — register the client-side `BetaRefusalFallbackMiddleware` on the client there instead. Full semantics (sticky routing, billing, streaming, echoing fallback turns back): `shared/model-migration.md` → Migrating to Claude Fable 5 → `refusal` stop reason.
1023
+
1024
+ ---
1025
+
1026
+ ## Cost Optimization Strategies
1027
+
1028
+ ### 1. Use Prompt Caching for Repeated Context
1029
+
1030
+ ```python
1031
+ # Automatic caching (simplest — caches the last cacheable block)
1032
+ response = client.messages.create(
1033
+ model="claude-opus-4-8",
1034
+ max_tokens=16000,
1035
+ cache_control={"type": "ephemeral"},
1036
+ system=large_document_text, # e.g., 50KB of context
1037
+ messages=[{"role": "user", "content": "Summarize the key points"}]
1038
+ )
1039
+
1040
+ # First request: full cost
1041
+ # Subsequent requests: ~90% cheaper for cached portion
1042
+ ```
1043
+
1044
+ ### 2. Choose the Right Model
1045
+
1046
+ ```python
1047
+ # Default to Opus for most tasks
1048
+ response = client.messages.create(
1049
+ model="claude-opus-4-8", # $5.00/$25.00 per 1M tokens
1050
+ max_tokens=16000,
1051
+ messages=[{"role": "user", "content": "Explain quantum computing"}]
1052
+ )
1053
+
1054
+ # Use Sonnet for high-volume production workloads
1055
+ standard_response = client.messages.create(
1056
+ model="claude-sonnet-5", # $3.00/$15.00 per 1M tokens
1057
+ max_tokens=16000,
1058
+ messages=[{"role": "user", "content": "Summarize this document"}]
1059
+ )
1060
+
1061
+ # Use Haiku only for simple, speed-critical tasks
1062
+ simple_response = client.messages.create(
1063
+ model="claude-haiku-4-5", # $1.00/$5.00 per 1M tokens
1064
+ max_tokens=256,
1065
+ messages=[{"role": "user", "content": "Classify this as positive or negative"}]
1066
+ )
1067
+ ```
1068
+
1069
+ ### 3. Use Token Counting Before Requests
1070
+
1071
+ ```python
1072
+ count_response = client.messages.count_tokens(
1073
+ model="claude-opus-4-8",
1074
+ messages=messages,
1075
+ system=system
1076
+ )
1077
+
1078
+ estimated_input_cost = count_response.input_tokens * 0.000005 # $5/1M tokens
1079
+ print(f"Estimated input cost: ${estimated_input_cost:.4f}")
1080
+ ```
1081
+
1082
+ ---
1083
+
1084
+ ## Retry with Exponential Backoff
1085
+
1086
+ > **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.
1087
+
1088
+ ```python
1089
+ import time
1090
+ import random
1091
+ import anthropic
1092
+
1093
+ def call_with_retry(
1094
+ client: anthropic.Anthropic,
1095
+ max_retries: int = 5,
1096
+ base_delay: float = 1.0,
1097
+ max_delay: float = 60.0,
1098
+ **kwargs
1099
+ ):
1100
+ """Call the API with exponential backoff retry."""
1101
+ last_exception = None
1102
+
1103
+ for attempt in range(max_retries):
1104
+ try:
1105
+ return client.messages.create(**kwargs)
1106
+ except anthropic.RateLimitError as e:
1107
+ last_exception = e
1108
+ except anthropic.APIStatusError as e:
1109
+ if e.status_code >= 500:
1110
+ last_exception = e
1111
+ else:
1112
+ raise # Client errors (4xx except 429) should not be retried
1113
+
1114
+ delay = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
1115
+ print(f"Retry {attempt + 1}/{max_retries} after {delay:.1f}s")
1116
+ time.sleep(delay)
1117
+
1118
+ raise last_exception
1119
+ ```
1120
+
1121
+ ---
1122
+ <!-- module: 51-python-tool-use.md -->
1123
+
1124
+ # Tool Use — Python
1125
+
1126
+ For conceptual overview (tool definitions, tool choice, tips), see [shared/tool-use-concepts.md](../../shared/tool-use-concepts.md).
1127
+
1128
+ ## Tool Runner (Recommended)
1129
+
1130
+ **Beta:** The tool runner is in beta in the Python SDK.
1131
+
1132
+ Use the `@beta_tool` decorator to define tools as typed functions, then pass them to `client.beta.messages.tool_runner()`:
1133
+
1134
+ ```python
1135
+ import anthropic
1136
+ from anthropic import beta_tool
1137
+
1138
+ client = anthropic.Anthropic()
1139
+
1140
+ @beta_tool
1141
+ def get_weather(location: str, unit: str = "celsius") -> str:
1142
+ """Get current weather for a location.
1143
+
1144
+ Args:
1145
+ location: City and state, e.g., San Francisco, CA.
1146
+ unit: Temperature unit, either "celsius" or "fahrenheit".
1147
+ """
1148
+ # Your implementation here
1149
+ return f"72°F and sunny in {location}"
1150
+
1151
+ # The tool runner handles the agentic loop automatically
1152
+ runner = client.beta.messages.tool_runner(
1153
+ model="claude-opus-4-8",
1154
+ max_tokens=16000,
1155
+ tools=[get_weather],
1156
+ messages=[{"role": "user", "content": "What's the weather in Paris?"}],
1157
+ )
1158
+
1159
+ # Each iteration yields a BetaMessage; iteration stops when Claude is done
1160
+ for message in runner:
1161
+ print(message)
1162
+ ```
1163
+
1164
+ For async usage, use `@beta_async_tool` with `async def` functions.
1165
+
1166
+ **Key benefits of the tool runner:**
1167
+
1168
+ - No manual loop — the SDK handles calling tools and feeding results back
1169
+ - Type-safe tool inputs via decorators
1170
+ - Tool schemas are generated automatically from function signatures
1171
+ - Iteration stops automatically when Claude has no more tool calls
1172
+
1173
+ ---
1174
+
1175
+ ## MCP Tool Conversion Helpers
1176
+
1177
+ **Beta.** Convert [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) tools, prompts, and resources to Anthropic API types for use with the tool runner. Requires `pip install anthropic[mcp]` (Python 3.10+).
1178
+
1179
+ > **Note:** The Claude API also supports an `mcp_servers` parameter that lets Claude connect directly to remote MCP servers. Use these helpers instead when you need local MCP servers, prompts, resources, or more control over the MCP connection.
1180
+
1181
+ ### MCP Tools with Tool Runner
1182
+
1183
+ ```python
1184
+ from anthropic import AsyncAnthropic
1185
+ from anthropic.lib.tools.mcp import async_mcp_tool
1186
+ from mcp import ClientSession
1187
+ from mcp.client.stdio import stdio_client, StdioServerParameters
1188
+
1189
+ client = AsyncAnthropic()
1190
+
1191
+ async with stdio_client(StdioServerParameters(command="mcp-server")) as (read, write):
1192
+ async with ClientSession(read, write) as mcp_client:
1193
+ await mcp_client.initialize()
1194
+
1195
+ tools_result = await mcp_client.list_tools()
1196
+ # tool_runner is sync — returns the runner, not a coroutine
1197
+ runner = client.beta.messages.tool_runner(
1198
+ model="claude-opus-4-8",
1199
+ max_tokens=16000,
1200
+ messages=[{"role": "user", "content": "Use the available tools"}],
1201
+ tools=[async_mcp_tool(t, mcp_client) for t in tools_result.tools],
1202
+ )
1203
+ async for message in runner:
1204
+ print(message)
1205
+ ```
1206
+
1207
+ For sync usage, use `mcp_tool` instead of `async_mcp_tool`.
1208
+
1209
+ ### MCP Prompts
1210
+
1211
+ ```python
1212
+ from anthropic.lib.tools.mcp import mcp_message
1213
+
1214
+ prompt = await mcp_client.get_prompt(name="my-prompt")
1215
+ response = await client.beta.messages.create(
1216
+ model="claude-opus-4-8",
1217
+ max_tokens=16000,
1218
+ messages=[mcp_message(m) for m in prompt.messages],
1219
+ )
1220
+ ```
1221
+
1222
+ ### MCP Resources as Content
1223
+
1224
+ ```python
1225
+ from anthropic.lib.tools.mcp import mcp_resource_to_content
1226
+
1227
+ resource = await mcp_client.read_resource(uri="file:///path/to/doc.txt")
1228
+ response = await client.beta.messages.create(
1229
+ model="claude-opus-4-8",
1230
+ max_tokens=16000,
1231
+ messages=[{
1232
+ "role": "user",
1233
+ "content": [
1234
+ mcp_resource_to_content(resource),
1235
+ {"type": "text", "text": "Summarize this document"},
1236
+ ],
1237
+ }],
1238
+ )
1239
+ ```
1240
+
1241
+ ### Upload MCP Resources as Files
1242
+
1243
+ ```python
1244
+ from anthropic.lib.tools.mcp import mcp_resource_to_file
1245
+
1246
+ resource = await mcp_client.read_resource(uri="file:///path/to/data.json")
1247
+ uploaded = await client.beta.files.upload(file=mcp_resource_to_file(resource))
1248
+ ```
1249
+
1250
+ Conversion functions raise `UnsupportedMCPValueError` if an MCP value cannot be converted (e.g., unsupported content types like audio, unsupported MIME types).
1251
+
1252
+ ---
1253
+
1254
+ ## Manual Agentic Loop
1255
+
1256
+ Use this when you need fine-grained control over the loop (e.g., custom logging, conditional tool execution, human-in-the-loop approval):
1257
+
1258
+ ```python
1259
+ import anthropic
1260
+
1261
+ client = anthropic.Anthropic()
1262
+ tools = [...] # Your tool definitions
1263
+ messages = [{"role": "user", "content": user_input}]
1264
+
1265
+ # Agentic loop: keep going until Claude stops calling tools
1266
+ while True:
1267
+ response = client.messages.create(
1268
+ model="claude-opus-4-8",
1269
+ max_tokens=16000,
1270
+ tools=tools,
1271
+ messages=messages
1272
+ )
1273
+
1274
+ # If Claude is done (no more tool calls), break
1275
+ if response.stop_reason == "end_turn":
1276
+ break
1277
+
1278
+ # Server-side tool hit iteration limit; re-send to continue
1279
+ if response.stop_reason == "pause_turn":
1280
+ messages = [
1281
+ {"role": "user", "content": user_input},
1282
+ {"role": "assistant", "content": response.content},
1283
+ ]
1284
+ continue
1285
+
1286
+ # Extract tool use blocks from the response
1287
+ tool_use_blocks = [b for b in response.content if b.type == "tool_use"]
1288
+
1289
+ # Append assistant's response (including tool_use blocks)
1290
+ messages.append({"role": "assistant", "content": response.content})
1291
+
1292
+ # Execute each tool and collect results
1293
+ tool_results = []
1294
+ for tool in tool_use_blocks:
1295
+ result = execute_tool(tool.name, tool.input) # Your implementation
1296
+ tool_results.append({
1297
+ "type": "tool_result",
1298
+ "tool_use_id": tool.id, # Must match the tool_use block's id
1299
+ "content": result
1300
+ })
1301
+
1302
+ # Append tool results as a user message
1303
+ messages.append({"role": "user", "content": tool_results})
1304
+
1305
+ # Final response text
1306
+ final_text = next(b.text for b in response.content if b.type == "text")
1307
+ ```
1308
+
1309
+ ---
1310
+
1311
+ ## Handling Tool Results
1312
+
1313
+ ```python
1314
+ response = client.messages.create(
1315
+ model="claude-opus-4-8",
1316
+ max_tokens=16000,
1317
+ tools=tools,
1318
+ messages=[{"role": "user", "content": "What's the weather in Paris?"}]
1319
+ )
1320
+
1321
+ for block in response.content:
1322
+ if block.type == "tool_use":
1323
+ tool_name = block.name
1324
+ tool_input = block.input
1325
+ tool_use_id = block.id
1326
+
1327
+ result = execute_tool(tool_name, tool_input)
1328
+
1329
+ followup = client.messages.create(
1330
+ model="claude-opus-4-8",
1331
+ max_tokens=16000,
1332
+ tools=tools,
1333
+ messages=[
1334
+ {"role": "user", "content": "What's the weather in Paris?"},
1335
+ {"role": "assistant", "content": response.content},
1336
+ {
1337
+ "role": "user",
1338
+ "content": [{
1339
+ "type": "tool_result",
1340
+ "tool_use_id": tool_use_id,
1341
+ "content": result
1342
+ }]
1343
+ }
1344
+ ]
1345
+ )
1346
+ ```
1347
+
1348
+ ---
1349
+
1350
+ ## Multiple Tool Calls
1351
+
1352
+ ```python
1353
+ tool_results = []
1354
+
1355
+ for block in response.content:
1356
+ if block.type == "tool_use":
1357
+ result = execute_tool(block.name, block.input)
1358
+ tool_results.append({
1359
+ "type": "tool_result",
1360
+ "tool_use_id": block.id,
1361
+ "content": result
1362
+ })
1363
+
1364
+ # Send all results back at once
1365
+ if tool_results:
1366
+ followup = client.messages.create(
1367
+ model="claude-opus-4-8",
1368
+ max_tokens=16000,
1369
+ tools=tools,
1370
+ messages=[
1371
+ *previous_messages,
1372
+ {"role": "assistant", "content": response.content},
1373
+ {"role": "user", "content": tool_results}
1374
+ ]
1375
+ )
1376
+ ```
1377
+
1378
+ ---
1379
+
1380
+ ## Error Handling in Tool Results
1381
+
1382
+ ```python
1383
+ tool_result = {
1384
+ "type": "tool_result",
1385
+ "tool_use_id": tool_use_id,
1386
+ "content": "Error: Location 'xyz' not found. Please provide a valid city name.",
1387
+ "is_error": True
1388
+ }
1389
+ ```
1390
+
1391
+ ---
1392
+
1393
+ ## Tool Choice
1394
+
1395
+ ```python
1396
+ response = client.messages.create(
1397
+ model="claude-opus-4-8",
1398
+ max_tokens=16000,
1399
+ tools=tools,
1400
+ tool_choice={"type": "tool", "name": "get_weather"}, # Force specific tool
1401
+ messages=[{"role": "user", "content": "What's the weather in Paris?"}]
1402
+ )
1403
+ ```
1404
+
1405
+ ---
1406
+
1407
+ ## Code Execution
1408
+
1409
+ ### Basic Usage
1410
+
1411
+ ```python
1412
+ import anthropic
1413
+
1414
+ client = anthropic.Anthropic()
1415
+
1416
+ response = client.messages.create(
1417
+ model="claude-opus-4-8",
1418
+ max_tokens=16000,
1419
+ messages=[{
1420
+ "role": "user",
1421
+ "content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
1422
+ }],
1423
+ tools=[{
1424
+ "type": "code_execution_20260120",
1425
+ "name": "code_execution"
1426
+ }]
1427
+ )
1428
+
1429
+ for block in response.content:
1430
+ if block.type == "text":
1431
+ print(block.text)
1432
+ elif block.type == "bash_code_execution_tool_result":
1433
+ print(f"stdout: {block.content.stdout}")
1434
+ ```
1435
+
1436
+ ### Upload Files for Analysis
1437
+
1438
+ ```python
1439
+ # 1. Upload a file
1440
+ uploaded = client.beta.files.upload(file=open("sales_data.csv", "rb"))
1441
+
1442
+ # 2. Pass to code execution via container_upload block
1443
+ # Code execution is GA; Files API is still beta (pass via extra_headers)
1444
+ response = client.messages.create(
1445
+ model="claude-opus-4-8",
1446
+ max_tokens=16000,
1447
+ extra_headers={"anthropic-beta": "files-api-2025-04-14"},
1448
+ messages=[{
1449
+ "role": "user",
1450
+ "content": [
1451
+ {"type": "text", "text": "Analyze this sales data. Show trends and create a visualization."},
1452
+ {"type": "container_upload", "file_id": uploaded.id}
1453
+ ]
1454
+ }],
1455
+ tools=[{"type": "code_execution_20260120", "name": "code_execution"}]
1456
+ )
1457
+ ```
1458
+
1459
+ ### Retrieve Generated Files
1460
+
1461
+ ```python
1462
+ import os
1463
+
1464
+ OUTPUT_DIR = "./claude_outputs"
1465
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
1466
+
1467
+ for block in response.content:
1468
+ if block.type == "bash_code_execution_tool_result":
1469
+ result = block.content
1470
+ if result.type == "bash_code_execution_result" and result.content:
1471
+ for file_ref in result.content:
1472
+ if file_ref.type == "bash_code_execution_output":
1473
+ metadata = client.beta.files.retrieve_metadata(file_ref.file_id)
1474
+ file_content = client.beta.files.download(file_ref.file_id)
1475
+ # Use basename to prevent path traversal; validate result
1476
+ safe_name = os.path.basename(metadata.filename)
1477
+ if not safe_name or safe_name in (".", ".."):
1478
+ print(f"Skipping invalid filename: {metadata.filename}")
1479
+ continue
1480
+ output_path = os.path.join(OUTPUT_DIR, safe_name)
1481
+ file_content.write_to_file(output_path)
1482
+ print(f"Saved: {output_path}")
1483
+ ```
1484
+
1485
+ ### Container Reuse
1486
+
1487
+ ```python
1488
+ # First request: set up environment
1489
+ response1 = client.messages.create(
1490
+ model="claude-opus-4-8",
1491
+ max_tokens=16000,
1492
+ messages=[{"role": "user", "content": "Install tabulate and create data.json with sample data"}],
1493
+ tools=[{"type": "code_execution_20260120", "name": "code_execution"}]
1494
+ )
1495
+
1496
+ # Get container ID from response
1497
+ container_id = response1.container.id
1498
+
1499
+ # Second request: reuse the same container
1500
+ response2 = client.messages.create(
1501
+ container=container_id,
1502
+ model="claude-opus-4-8",
1503
+ max_tokens=16000,
1504
+ messages=[{"role": "user", "content": "Read data.json and display as a formatted table"}],
1505
+ tools=[{"type": "code_execution_20260120", "name": "code_execution"}]
1506
+ )
1507
+ ```
1508
+
1509
+ ### Response Structure
1510
+
1511
+ ```python
1512
+ for block in response.content:
1513
+ if block.type == "text":
1514
+ print(block.text) # Claude's explanation
1515
+ elif block.type == "server_tool_use":
1516
+ print(f"Running: {block.name} - {block.input}") # What Claude is doing
1517
+ elif block.type == "bash_code_execution_tool_result":
1518
+ result = block.content
1519
+ if result.type == "bash_code_execution_result":
1520
+ if result.return_code == 0:
1521
+ print(f"Output: {result.stdout}")
1522
+ else:
1523
+ print(f"Error: {result.stderr}")
1524
+ else:
1525
+ print(f"Tool error: {result.error_code}")
1526
+ elif block.type == "text_editor_code_execution_tool_result":
1527
+ print(f"File operation: {block.content}")
1528
+ ```
1529
+
1530
+ ---
1531
+
1532
+ ## Memory Tool
1533
+
1534
+ ### Basic Usage
1535
+
1536
+ ```python
1537
+ import anthropic
1538
+
1539
+ client = anthropic.Anthropic()
1540
+
1541
+ response = client.messages.create(
1542
+ model="claude-opus-4-8",
1543
+ max_tokens=16000,
1544
+ messages=[{"role": "user", "content": "Remember that my preferred language is Python."}],
1545
+ tools=[{"type": "memory_20250818", "name": "memory"}],
1546
+ )
1547
+ ```
1548
+
1549
+ ### SDK Memory Helper
1550
+
1551
+ Subclass `BetaAbstractMemoryTool`:
1552
+
1553
+ ```python
1554
+ from anthropic.lib.tools import BetaAbstractMemoryTool
1555
+
1556
+ class MyMemoryTool(BetaAbstractMemoryTool):
1557
+ def view(self, command): ...
1558
+ def create(self, command): ...
1559
+ def str_replace(self, command): ...
1560
+ def insert(self, command): ...
1561
+ def delete(self, command): ...
1562
+ def rename(self, command): ...
1563
+
1564
+ memory = MyMemoryTool()
1565
+
1566
+ # Use with tool runner
1567
+ runner = client.beta.messages.tool_runner(
1568
+ model="claude-opus-4-8",
1569
+ max_tokens=16000,
1570
+ tools=[memory],
1571
+ messages=[{"role": "user", "content": "Remember my preferences"}],
1572
+ )
1573
+
1574
+ for message in runner:
1575
+ print(message)
1576
+ ```
1577
+
1578
+ For full implementation examples, use WebFetch:
1579
+
1580
+ - `https://github.com/anthropics/anthropic-sdk-python/blob/main/examples/memory/basic.py`
1581
+
1582
+ ---
1583
+
1584
+ ## Structured Outputs
1585
+
1586
+ ### JSON Outputs (Pydantic — Recommended)
1587
+
1588
+ ```python
1589
+ from pydantic import BaseModel
1590
+ from typing import List
1591
+ import anthropic
1592
+
1593
+ class ContactInfo(BaseModel):
1594
+ name: str
1595
+ email: str
1596
+ plan: str
1597
+ interests: List[str]
1598
+ demo_requested: bool
1599
+
1600
+ client = anthropic.Anthropic()
1601
+
1602
+ response = client.messages.parse(
1603
+ model="claude-opus-4-8",
1604
+ max_tokens=16000,
1605
+ messages=[{
1606
+ "role": "user",
1607
+ "content": "Extract: Jane Doe (jane@co.com) wants Enterprise, interested in API and SDKs, wants a demo."
1608
+ }],
1609
+ output_format=ContactInfo,
1610
+ )
1611
+
1612
+ # response.parsed_output is a validated ContactInfo instance
1613
+ contact = response.parsed_output
1614
+ print(contact.name) # "Jane Doe"
1615
+ print(contact.interests) # ["API", "SDKs"]
1616
+ ```
1617
+
1618
+ ### Raw Schema
1619
+
1620
+ ```python
1621
+ response = client.messages.create(
1622
+ model="claude-opus-4-8",
1623
+ max_tokens=16000,
1624
+ messages=[{
1625
+ "role": "user",
1626
+ "content": "Extract info: John Smith (john@example.com) wants the Enterprise plan."
1627
+ }],
1628
+ output_config={
1629
+ "format": {
1630
+ "type": "json_schema",
1631
+ "schema": {
1632
+ "type": "object",
1633
+ "properties": {
1634
+ "name": {"type": "string"},
1635
+ "email": {"type": "string"},
1636
+ "plan": {"type": "string"},
1637
+ "demo_requested": {"type": "boolean"}
1638
+ },
1639
+ "required": ["name", "email", "plan", "demo_requested"],
1640
+ "additionalProperties": False
1641
+ }
1642
+ }
1643
+ }
1644
+ )
1645
+
1646
+ import json
1647
+ # output_config.format guarantees the first block is text with valid JSON
1648
+ text = next(b.text for b in response.content if b.type == "text")
1649
+ data = json.loads(text)
1650
+ ```
1651
+
1652
+ ### Strict Tool Use
1653
+
1654
+ ```python
1655
+ response = client.messages.create(
1656
+ model="claude-opus-4-8",
1657
+ max_tokens=16000,
1658
+ messages=[{"role": "user", "content": "Book a flight to Tokyo for 2 passengers on March 15"}],
1659
+ tools=[{
1660
+ "name": "book_flight",
1661
+ "description": "Book a flight to a destination",
1662
+ "strict": True,
1663
+ "input_schema": {
1664
+ "type": "object",
1665
+ "properties": {
1666
+ "destination": {"type": "string"},
1667
+ "date": {"type": "string", "format": "date"},
1668
+ "passengers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6, 7, 8]}
1669
+ },
1670
+ "required": ["destination", "date", "passengers"],
1671
+ "additionalProperties": False
1672
+ }
1673
+ }]
1674
+ )
1675
+ ```
1676
+
1677
+ ### Using Both Together
1678
+
1679
+ ```python
1680
+ response = client.messages.create(
1681
+ model="claude-opus-4-8",
1682
+ max_tokens=16000,
1683
+ messages=[{"role": "user", "content": "Plan a trip to Paris next month"}],
1684
+ output_config={
1685
+ "format": {
1686
+ "type": "json_schema",
1687
+ "schema": {
1688
+ "type": "object",
1689
+ "properties": {
1690
+ "summary": {"type": "string"},
1691
+ "next_steps": {"type": "array", "items": {"type": "string"}}
1692
+ },
1693
+ "required": ["summary", "next_steps"],
1694
+ "additionalProperties": False
1695
+ }
1696
+ }
1697
+ },
1698
+ tools=[{
1699
+ "name": "search_flights",
1700
+ "description": "Search for available flights",
1701
+ "strict": True,
1702
+ "input_schema": {
1703
+ "type": "object",
1704
+ "properties": {
1705
+ "destination": {"type": "string"},
1706
+ "date": {"type": "string", "format": "date"}
1707
+ },
1708
+ "required": ["destination", "date"],
1709
+ "additionalProperties": False
1710
+ }
1711
+ }]
1712
+ )
1713
+ ```
1714
+
1715
+ ---
1716
+ <!-- module: 52-python-streaming-batches-files.md -->
1717
+
1718
+ # Streaming — Python
1719
+
1720
+ ## Quick Start
1721
+
1722
+ ```python
1723
+ with client.messages.stream(
1724
+ model="claude-opus-4-8",
1725
+ max_tokens=64000,
1726
+ messages=[{"role": "user", "content": "Write a story"}]
1727
+ ) as stream:
1728
+ for text in stream.text_stream:
1729
+ print(text, end="", flush=True)
1730
+ ```
1731
+
1732
+ ### Async
1733
+
1734
+ ```python
1735
+ async with async_client.messages.stream(
1736
+ model="claude-opus-4-8",
1737
+ max_tokens=64000,
1738
+ messages=[{"role": "user", "content": "Write a story"}]
1739
+ ) as stream:
1740
+ async for text in stream.text_stream:
1741
+ print(text, end="", flush=True)
1742
+ ```
1743
+
1744
+ ### Low-level: `stream=True`
1745
+
1746
+ `messages.stream()` (above) is the recommended helper — it accumulates state and exposes `text_stream` / `get_final_message()`. If you only need the raw event iterator and want lower memory use, pass `stream=True` to `messages.create()` instead:
1747
+
1748
+ ```python
1749
+ for event in client.messages.create(
1750
+ model="claude-opus-4-8",
1751
+ max_tokens=64000,
1752
+ messages=[{"role": "user", "content": "Write a story"}],
1753
+ stream=True,
1754
+ ):
1755
+ print(event.type)
1756
+ ```
1757
+
1758
+ No final-message accumulation is done for you in this form.
1759
+
1760
+ ---
1761
+
1762
+ ## Handling Different Content Types
1763
+
1764
+ Claude may return text, thinking blocks, or tool use. Handle each appropriately:
1765
+
1766
+ > **Fable 5 / Opus 4.8 / Opus 4.7 / Opus 4.6:** Use `thinking: {type: "adaptive"}`. On older models, use `thinking: {type: "enabled", budget_tokens: N}` instead.
1767
+
1768
+ ```python
1769
+ with client.messages.stream(
1770
+ model="claude-opus-4-8",
1771
+ max_tokens=64000,
1772
+ thinking={"type": "adaptive", "display": "summarized"}, # display opt-in: default is omitted (empty thinking text) on Fable 5 / Mythos 5 / Opus 4.8 / 4.7
1773
+ messages=[{"role": "user", "content": "Analyze this problem"}]
1774
+ ) as stream:
1775
+ for event in stream:
1776
+ if event.type == "content_block_start":
1777
+ if event.content_block.type == "thinking":
1778
+ print("\n[Thinking...]")
1779
+ elif event.content_block.type == "text":
1780
+ print("\n[Response:]")
1781
+
1782
+ elif event.type == "content_block_delta":
1783
+ if event.delta.type == "thinking_delta":
1784
+ print(event.delta.thinking, end="", flush=True)
1785
+ elif event.delta.type == "text_delta":
1786
+ print(event.delta.text, end="", flush=True)
1787
+ ```
1788
+
1789
+ ---
1790
+
1791
+ ## Streaming with Tool Use
1792
+
1793
+ The Python tool runner currently returns complete messages. Use streaming for individual API calls within a manual loop if you need per-token streaming with tools:
1794
+
1795
+ ```python
1796
+ with client.messages.stream(
1797
+ model="claude-opus-4-8",
1798
+ max_tokens=64000,
1799
+ tools=tools,
1800
+ messages=messages
1801
+ ) as stream:
1802
+ for text in stream.text_stream:
1803
+ print(text, end="", flush=True)
1804
+
1805
+ response = stream.get_final_message()
1806
+ # Continue with tool execution if response.stop_reason == "tool_use"
1807
+ ```
1808
+
1809
+ ---
1810
+
1811
+ ## Getting the Final Message
1812
+
1813
+ ```python
1814
+ with client.messages.stream(
1815
+ model="claude-opus-4-8",
1816
+ max_tokens=64000,
1817
+ messages=[{"role": "user", "content": "Hello"}]
1818
+ ) as stream:
1819
+ for text in stream.text_stream:
1820
+ print(text, end="", flush=True)
1821
+
1822
+ # Get full message after streaming
1823
+ final_message = stream.get_final_message()
1824
+ print(f"\n\nTokens used: {final_message.usage.output_tokens}")
1825
+ ```
1826
+
1827
+ ---
1828
+
1829
+ ## Streaming with Progress Updates
1830
+
1831
+ ```python
1832
+ def stream_with_progress(client, **kwargs):
1833
+ """Stream a response with progress updates."""
1834
+ total_tokens = 0
1835
+ content_parts = []
1836
+
1837
+ with client.messages.stream(**kwargs) as stream:
1838
+ for event in stream:
1839
+ if event.type == "content_block_delta":
1840
+ if event.delta.type == "text_delta":
1841
+ text = event.delta.text
1842
+ content_parts.append(text)
1843
+ print(text, end="", flush=True)
1844
+
1845
+ elif event.type == "message_delta":
1846
+ if event.usage and event.usage.output_tokens is not None:
1847
+ total_tokens = event.usage.output_tokens
1848
+
1849
+ final_message = stream.get_final_message()
1850
+
1851
+ print(f"\n\n[Tokens used: {total_tokens}]")
1852
+ return "".join(content_parts)
1853
+ ```
1854
+
1855
+ ---
1856
+
1857
+ ## Error Handling in Streams
1858
+
1859
+ ```python
1860
+ try:
1861
+ with client.messages.stream(
1862
+ model="claude-opus-4-8",
1863
+ max_tokens=64000,
1864
+ messages=[{"role": "user", "content": "Write a story"}]
1865
+ ) as stream:
1866
+ for text in stream.text_stream:
1867
+ print(text, end="", flush=True)
1868
+ except anthropic.APIConnectionError:
1869
+ print("\nConnection lost. Please retry.")
1870
+ except anthropic.RateLimitError:
1871
+ print("\nRate limited. Please wait and retry.")
1872
+ except anthropic.APIStatusError as e:
1873
+ print(f"\nAPI error: {e.status_code}")
1874
+ ```
1875
+
1876
+ ---
1877
+
1878
+ ## Stream Event Types
1879
+
1880
+ | Event Type | Description | When it fires |
1881
+ | --------------------- | --------------------------- | --------------------------------- |
1882
+ | `message_start` | Contains message metadata | Once at the beginning |
1883
+ | `content_block_start` | New content block beginning | When a text/tool_use block starts |
1884
+ | `content_block_delta` | Incremental content update | For each token/chunk |
1885
+ | `content_block_stop` | Content block complete | When a block finishes |
1886
+ | `message_delta` | Message-level updates | Contains `stop_reason`, usage |
1887
+ | `message_stop` | Message complete | Once at the end |
1888
+
1889
+ ## Best Practices
1890
+
1891
+ 1. **Always flush output** — Use `flush=True` to show tokens immediately
1892
+ 2. **Handle partial responses** — If the stream is interrupted, you may have incomplete content
1893
+ 3. **Track token usage** — The `message_delta` event contains usage information
1894
+ 4. **Use timeouts** — Set appropriate timeouts for your application
1895
+ 5. **Default to streaming** — Use `.get_final_message()` to get the complete response even when streaming, giving you timeout protection without needing to handle individual events
1896
+ 6. **Large `max_tokens` without streaming raises `ValueError`** — The SDK refuses non-streaming requests it estimates will exceed ~10 minutes (idle connections drop). Pass `stream=True` / use `messages.stream()`, or explicitly override `timeout`, to suppress the guard.
1897
+
1898
+ # Message Batches API — Python
1899
+
1900
+ The Batches API (`POST /v1/messages/batches`) processes Messages API requests asynchronously at 50% of standard prices.
1901
+
1902
+ ## Key Facts
1903
+
1904
+ - Up to 100,000 requests or 256 MB per batch
1905
+ - Most batches complete within 1 hour; maximum 24 hours
1906
+ - Results available for 29 days after creation
1907
+ - 50% cost reduction on all token usage
1908
+ - All Messages API features supported (vision, tools, caching, etc.)
1909
+
1910
+ ---
1911
+
1912
+ ## Create a Batch
1913
+
1914
+ ```python
1915
+ import anthropic
1916
+ from anthropic.types.message_create_params import MessageCreateParamsNonStreaming
1917
+ from anthropic.types.messages.batch_create_params import Request
1918
+
1919
+ client = anthropic.Anthropic()
1920
+
1921
+ message_batch = client.messages.batches.create(
1922
+ requests=[
1923
+ Request(
1924
+ custom_id="request-1",
1925
+ params=MessageCreateParamsNonStreaming(
1926
+ model="claude-opus-4-8",
1927
+ max_tokens=16000,
1928
+ messages=[{"role": "user", "content": "Summarize climate change impacts"}]
1929
+ )
1930
+ ),
1931
+ Request(
1932
+ custom_id="request-2",
1933
+ params=MessageCreateParamsNonStreaming(
1934
+ model="claude-opus-4-8",
1935
+ max_tokens=16000,
1936
+ messages=[{"role": "user", "content": "Explain quantum computing basics"}]
1937
+ )
1938
+ ),
1939
+ ]
1940
+ )
1941
+
1942
+ print(f"Batch ID: {message_batch.id}")
1943
+ print(f"Status: {message_batch.processing_status}")
1944
+ ```
1945
+
1946
+ ---
1947
+
1948
+ ## Poll for Completion
1949
+
1950
+ ```python
1951
+ import time
1952
+
1953
+ while True:
1954
+ batch = client.messages.batches.retrieve(message_batch.id)
1955
+ if batch.processing_status == "ended":
1956
+ break
1957
+ print(f"Status: {batch.processing_status}, processing: {batch.request_counts.processing}")
1958
+ time.sleep(60)
1959
+
1960
+ print("Batch complete!")
1961
+ print(f"Succeeded: {batch.request_counts.succeeded}")
1962
+ print(f"Errored: {batch.request_counts.errored}")
1963
+ ```
1964
+
1965
+ ---
1966
+
1967
+ ## Retrieve Results
1968
+
1969
+ > **Note:** Examples below use `match/case` syntax, requiring Python 3.10+. For earlier versions, use `if/elif` chains instead.
1970
+
1971
+ ```python
1972
+ for result in client.messages.batches.results(message_batch.id):
1973
+ match result.result.type:
1974
+ case "succeeded":
1975
+ msg = result.result.message
1976
+ text = next((b.text for b in msg.content if b.type == "text"), "")
1977
+ print(f"[{result.custom_id}] {text[:100]}")
1978
+ case "errored":
1979
+ if result.result.error.type == "invalid_request":
1980
+ print(f"[{result.custom_id}] Validation error - fix request and retry")
1981
+ else:
1982
+ print(f"[{result.custom_id}] Server error - safe to retry")
1983
+ case "canceled":
1984
+ print(f"[{result.custom_id}] Canceled")
1985
+ case "expired":
1986
+ print(f"[{result.custom_id}] Expired - resubmit")
1987
+ ```
1988
+
1989
+ ---
1990
+
1991
+ ## Cancel a Batch
1992
+
1993
+ ```python
1994
+ cancelled = client.messages.batches.cancel(message_batch.id)
1995
+ print(f"Status: {cancelled.processing_status}") # "canceling"
1996
+ ```
1997
+
1998
+ ---
1999
+
2000
+ ## List Batches (auto-pagination)
2001
+
2002
+ Iterating the return value of any `list()` call auto-paginates across all pages — do not index into `.data` if you want the full set:
2003
+
2004
+ ```python
2005
+ for batch in client.messages.batches.list(limit=20):
2006
+ print(batch.id, batch.processing_status)
2007
+ ```
2008
+
2009
+ For manual control, use `first_page.has_next_page()` / `first_page.get_next_page()` / `first_page.next_page_info()`; `first_page.data` holds the current page's items and `first_page.last_id` is the cursor.
2010
+
2011
+ ---
2012
+
2013
+ ## Batch with Prompt Caching
2014
+
2015
+ ```python
2016
+ shared_system = [
2017
+ {"type": "text", "text": "You are a literary analyst."},
2018
+ {
2019
+ "type": "text",
2020
+ "text": large_document_text, # Shared across all requests
2021
+ "cache_control": {"type": "ephemeral"}
2022
+ }
2023
+ ]
2024
+
2025
+ message_batch = client.messages.batches.create(
2026
+ requests=[
2027
+ Request(
2028
+ custom_id=f"analysis-{i}",
2029
+ params=MessageCreateParamsNonStreaming(
2030
+ model="claude-opus-4-8",
2031
+ max_tokens=16000,
2032
+ system=shared_system,
2033
+ messages=[{"role": "user", "content": question}]
2034
+ )
2035
+ )
2036
+ for i, question in enumerate(questions)
2037
+ ]
2038
+ )
2039
+ ```
2040
+
2041
+ ---
2042
+
2043
+ ## Full End-to-End Example
2044
+
2045
+ ```python
2046
+ import anthropic
2047
+ import time
2048
+ from anthropic.types.message_create_params import MessageCreateParamsNonStreaming
2049
+ from anthropic.types.messages.batch_create_params import Request
2050
+
2051
+ client = anthropic.Anthropic()
2052
+
2053
+ # 1. Prepare requests
2054
+ items_to_classify = [
2055
+ "The product quality is excellent!",
2056
+ "Terrible customer service, never again.",
2057
+ "It's okay, nothing special.",
2058
+ ]
2059
+
2060
+ requests = [
2061
+ Request(
2062
+ custom_id=f"classify-{i}",
2063
+ params=MessageCreateParamsNonStreaming(
2064
+ model="claude-haiku-4-5",
2065
+ max_tokens=50,
2066
+ messages=[{
2067
+ "role": "user",
2068
+ "content": f"Classify as positive/negative/neutral (one word): {text}"
2069
+ }]
2070
+ )
2071
+ )
2072
+ for i, text in enumerate(items_to_classify)
2073
+ ]
2074
+
2075
+ # 2. Create batch
2076
+ batch = client.messages.batches.create(requests=requests)
2077
+ print(f"Created batch: {batch.id}")
2078
+
2079
+ # 3. Wait for completion
2080
+ while True:
2081
+ batch = client.messages.batches.retrieve(batch.id)
2082
+ if batch.processing_status == "ended":
2083
+ break
2084
+ time.sleep(10)
2085
+
2086
+ # 4. Collect results
2087
+ results = {}
2088
+ for result in client.messages.batches.results(batch.id):
2089
+ if result.result.type == "succeeded":
2090
+ msg = result.result.message
2091
+ results[result.custom_id] = next((b.text for b in msg.content if b.type == "text"), "")
2092
+
2093
+ for custom_id, classification in sorted(results.items()):
2094
+ print(f"{custom_id}: {classification}")
2095
+ ```
2096
+
2097
+ # Files API — Python
2098
+
2099
+ The Files API uploads files for use in Messages API requests. Reference files via `file_id` in content blocks, avoiding re-uploads across multiple API calls.
2100
+
2101
+ **Beta:** Pass `betas=["files-api-2025-04-14"]` in your API calls (the SDK sets the required header automatically).
2102
+
2103
+ ## Key Facts
2104
+
2105
+ - Maximum file size: 500 MB
2106
+ - Total storage: 100 GB per organization
2107
+ - Files persist until deleted
2108
+ - File operations (upload, list, delete) are free; content used in messages is billed as input tokens
2109
+ - Not available on Amazon Bedrock or Google Vertex AI
2110
+
2111
+ ---
2112
+
2113
+ ## Upload a File
2114
+
2115
+ The `file` argument accepts a `(filename, content, content_type)` tuple, a `pathlib.Path` (or any `PathLike` — read for you, async-safe with `AsyncAnthropic`), or an open binary file object.
2116
+
2117
+ ```python
2118
+ import anthropic
2119
+ from pathlib import Path
2120
+
2121
+ client = anthropic.Anthropic()
2122
+
2123
+ uploaded = client.beta.files.upload(
2124
+ file=("report.pdf", open("report.pdf", "rb"), "application/pdf"),
2125
+ )
2126
+ # or: client.beta.files.upload(file=Path("report.pdf"))
2127
+ print(f"File ID: {uploaded.id}")
2128
+ print(f"Size: {uploaded.size_bytes} bytes")
2129
+ ```
2130
+
2131
+ ---
2132
+
2133
+ ## Use a File in Messages
2134
+
2135
+ ### PDF / Text Document
2136
+
2137
+ ```python
2138
+ response = client.beta.messages.create(
2139
+ model="claude-opus-4-8",
2140
+ max_tokens=16000,
2141
+ messages=[{
2142
+ "role": "user",
2143
+ "content": [
2144
+ {"type": "text", "text": "Summarize the key findings in this report."},
2145
+ {
2146
+ "type": "document",
2147
+ "source": {"type": "file", "file_id": uploaded.id},
2148
+ "title": "Q4 Report", # optional
2149
+ "citations": {"enabled": True} # optional, enables citations
2150
+ }
2151
+ ]
2152
+ }],
2153
+ betas=["files-api-2025-04-14"],
2154
+ )
2155
+ for block in response.content:
2156
+ if block.type == "text":
2157
+ print(block.text)
2158
+ ```
2159
+
2160
+ ### Image
2161
+
2162
+ ```python
2163
+ image_file = client.beta.files.upload(
2164
+ file=("photo.png", open("photo.png", "rb"), "image/png"),
2165
+ )
2166
+
2167
+ response = client.beta.messages.create(
2168
+ model="claude-opus-4-8",
2169
+ max_tokens=16000,
2170
+ messages=[{
2171
+ "role": "user",
2172
+ "content": [
2173
+ {"type": "text", "text": "What's in this image?"},
2174
+ {
2175
+ "type": "image",
2176
+ "source": {"type": "file", "file_id": image_file.id}
2177
+ }
2178
+ ]
2179
+ }],
2180
+ betas=["files-api-2025-04-14"],
2181
+ )
2182
+ ```
2183
+
2184
+ ---
2185
+
2186
+ ## Manage Files
2187
+
2188
+ ### List Files
2189
+
2190
+ Iterate the list result directly — the SDK auto-paginates across all pages. Only use `.data` if you want the first page only.
2191
+
2192
+ ```python
2193
+ for f in client.beta.files.list():
2194
+ print(f"{f.id}: {f.filename} ({f.size_bytes} bytes)")
2195
+ ```
2196
+
2197
+ ### Get File Metadata
2198
+
2199
+ ```python
2200
+ file_info = client.beta.files.retrieve_metadata("file_011CNha8iCJcU1wXNR6q4V8w")
2201
+ print(f"Filename: {file_info.filename}")
2202
+ print(f"MIME type: {file_info.mime_type}")
2203
+ ```
2204
+
2205
+ ### Delete a File
2206
+
2207
+ ```python
2208
+ client.beta.files.delete("file_011CNha8iCJcU1wXNR6q4V8w")
2209
+ ```
2210
+
2211
+ ### Download a File
2212
+
2213
+ Only files created by the code execution tool or skills can be downloaded (not user-uploaded files).
2214
+
2215
+ ```python
2216
+ file_content = client.beta.files.download("file_011CNha8iCJcU1wXNR6q4V8w")
2217
+ file_content.write_to_file("output.txt")
2218
+ ```
2219
+
2220
+ ---
2221
+
2222
+ ## Full End-to-End Example
2223
+
2224
+ Upload a document once, ask multiple questions about it:
2225
+
2226
+ ```python
2227
+ import anthropic
2228
+
2229
+ client = anthropic.Anthropic()
2230
+
2231
+ # 1. Upload once
2232
+ uploaded = client.beta.files.upload(
2233
+ file=("contract.pdf", open("contract.pdf", "rb"), "application/pdf"),
2234
+ )
2235
+ print(f"Uploaded: {uploaded.id}")
2236
+
2237
+ # 2. Ask multiple questions using the same file_id
2238
+ questions = [
2239
+ "What are the key terms and conditions?",
2240
+ "What is the termination clause?",
2241
+ "Summarize the payment schedule.",
2242
+ ]
2243
+
2244
+ for question in questions:
2245
+ response = client.beta.messages.create(
2246
+ model="claude-opus-4-8",
2247
+ max_tokens=16000,
2248
+ messages=[{
2249
+ "role": "user",
2250
+ "content": [
2251
+ {"type": "text", "text": question},
2252
+ {
2253
+ "type": "document",
2254
+ "source": {"type": "file", "file_id": uploaded.id}
2255
+ }
2256
+ ]
2257
+ }],
2258
+ betas=["files-api-2025-04-14"],
2259
+ )
2260
+ print(f"\nQ: {question}")
2261
+ text = next((b.text for b in response.content if b.type == "text"), "")
2262
+ print(f"A: {text[:200]}")
2263
+
2264
+ # 3. Clean up when done
2265
+ client.beta.files.delete(uploaded.id)
2266
+ ```
2267
+
2268
+ ---
2269
+ <!-- module: 53-python-managed-agents.md -->
2270
+
2271
+ # Managed Agents — Python
2272
+
2273
+ > **Bindings not shown here:** This README covers the most common managed-agents flows for Python. If you need a class, method, namespace, field, or behavior that isn't shown, WebFetch the Python SDK repo **or the relevant docs page** from `shared/live-sources.md` rather than guess. Do not extrapolate from cURL shapes or another language's SDK.
2274
+
2275
+ > **Agents are persistent — create once, reference by ID.** Store the agent ID returned by `agents.create` and pass it to every subsequent `sessions.create`; do not call `agents.create` in the request path. The Anthropic CLI is one convenient way to create agents and environments from version-controlled YAML — its URL is in `shared/live-sources.md`. The examples below show in-code creation for completeness; in production the create call belongs in setup, not in the request path.
2276
+
2277
+ ## Installation
2278
+
2279
+ ```bash
2280
+ pip install anthropic
2281
+ ```
2282
+
2283
+ ## Client Initialization
2284
+
2285
+ ```python
2286
+ import anthropic
2287
+
2288
+ # Default — resolves credentials from the environment:
2289
+ # ANTHROPIC_API_KEY, or ANTHROPIC_AUTH_TOKEN, or an `ant auth login` profile.
2290
+ # Prefer this for local dev; don't hardcode a key.
2291
+ client = anthropic.Anthropic()
2292
+
2293
+ # Explicit API key (only when you must inject a specific key)
2294
+ client = anthropic.Anthropic(api_key="your-api-key")
2295
+ ```
2296
+
2297
+ ---
2298
+
2299
+ ## Create an Environment
2300
+
2301
+ ```python
2302
+ environment = client.beta.environments.create(
2303
+ name="my-dev-env",
2304
+ config={
2305
+ "type": "cloud",
2306
+ "networking": {"type": "unrestricted"},
2307
+ },
2308
+ )
2309
+ print(environment.id) # env_...
2310
+ ```
2311
+
2312
+ ---
2313
+
2314
+ ## Create an Agent (required first step)
2315
+
2316
+ > ⚠️ **There is no inline agent config.** `model`/`system`/`tools` live on the agent object, not the session. Always start with `agents.create()` — the session only takes `agent={"type": "agent", "id": agent.id}`.
2317
+
2318
+ ### Minimal
2319
+
2320
+ ```python
2321
+ # 1. Create the agent (reusable, versioned)
2322
+ agent = client.beta.agents.create(
2323
+ name="Coding Assistant",
2324
+ model="claude-opus-4-8",
2325
+ tools=[{"type": "agent_toolset_20260401", "default_config": {"enabled": True}}],
2326
+ )
2327
+
2328
+ # 2. Start a session
2329
+ session = client.beta.sessions.create(
2330
+ agent={"type": "agent", "id": agent.id, "version": agent.version},
2331
+ environment_id=environment.id,
2332
+ )
2333
+ print(session.id, session.status)
2334
+ print(f"Trace: https://platform.claude.com/workspaces/default/sessions/{session.id}")
2335
+ ```
2336
+
2337
+ ### With system prompt and custom tools
2338
+
2339
+ ```python
2340
+ import os
2341
+
2342
+ agent = client.beta.agents.create(
2343
+ name="Code Reviewer",
2344
+ model="claude-opus-4-8",
2345
+ system="You are a senior code reviewer.",
2346
+ tools=[
2347
+ {"type": "agent_toolset_20260401"},
2348
+ {
2349
+ "type": "custom",
2350
+ "name": "run_tests",
2351
+ "description": "Run the test suite",
2352
+ "input_schema": {
2353
+ "type": "object",
2354
+ "properties": {
2355
+ "test_path": {"type": "string", "description": "Path to test file"}
2356
+ },
2357
+ "required": ["test_path"],
2358
+ },
2359
+ },
2360
+ ],
2361
+ )
2362
+
2363
+ session = client.beta.sessions.create(
2364
+ agent={"type": "agent", "id": agent.id, "version": agent.version},
2365
+ environment_id=environment.id,
2366
+ title="Code review session",
2367
+ resources=[
2368
+ {
2369
+ "type": "github_repository",
2370
+ "url": "https://github.com/owner/repo",
2371
+ "mount_path": "/workspace/repo",
2372
+ "authorization_token": os.environ["GITHUB_TOKEN"],
2373
+ "branch": "main",
2374
+ }
2375
+ ],
2376
+ )
2377
+ ```
2378
+
2379
+ ---
2380
+
2381
+ ## Send a User Message
2382
+
2383
+ ```python
2384
+ client.beta.sessions.events.send(
2385
+ session_id=session.id,
2386
+ events=[
2387
+ {
2388
+ "type": "user.message",
2389
+ "content": [{"type": "text", "text": "Review the auth module"}],
2390
+ }
2391
+ ],
2392
+ )
2393
+ ```
2394
+
2395
+ > 💡 **Stream-first:** Open the stream *before* (or concurrently with) sending the message. The stream only delivers events that occur after it opens — stream-after-send means early events arrive buffered in one batch. See [Steering Patterns](../../shared/managed-agents-events.md#steering-patterns).
2396
+
2397
+ ---
2398
+
2399
+ ## Stream Events (SSE)
2400
+
2401
+ ```python
2402
+ import json
2403
+
2404
+ # Stream-first: open stream, then send while stream is live
2405
+ with client.beta.sessions.events.stream(
2406
+ session_id=session.id,
2407
+ ) as stream:
2408
+ client.beta.sessions.events.send(
2409
+ session_id=session.id,
2410
+ events=[{"type": "user.message", "content": [{"type": "text", "text": "..."}]}],
2411
+ )
2412
+ for event in stream:
2413
+ ... # process events
2414
+
2415
+ # Standalone stream iteration:
2416
+ with client.beta.sessions.events.stream(
2417
+ session_id=session.id,
2418
+ ) as stream:
2419
+ for event in stream:
2420
+ if event.type == "agent.message":
2421
+ for block in event.content:
2422
+ if block.type == "text":
2423
+ print(block.text, end="", flush=True)
2424
+ elif event.type == "agent.custom_tool_use":
2425
+ # Custom tool invocation — session is now idle
2426
+ print(f"\nCustom tool call: {event.name}")
2427
+ print(f"Input: {json.dumps(event.input)}")
2428
+ # Send result back (see below)
2429
+ elif event.type == "session.status_idle":
2430
+ print("\n--- Agent idle ---")
2431
+ elif event.type == "session.status_terminated":
2432
+ print("\n--- Session terminated ---")
2433
+ break
2434
+ ```
2435
+
2436
+ ---
2437
+
2438
+ ## Provide Custom Tool Result
2439
+
2440
+ ```python
2441
+ client.beta.sessions.events.send(
2442
+ session_id=session.id,
2443
+ events=[
2444
+ {
2445
+ "type": "user.custom_tool_result",
2446
+ "custom_tool_use_id": "sevt_abc123",
2447
+ "content": [{"type": "text", "text": "All 42 tests passed."}],
2448
+ }
2449
+ ],
2450
+ )
2451
+ ```
2452
+
2453
+ ---
2454
+
2455
+ ## Poll Events
2456
+
2457
+ ```python
2458
+ events = client.beta.sessions.events.list(
2459
+ session_id=session.id,
2460
+ )
2461
+ for event in events.data:
2462
+ print(f"{event.type}: {event.id}")
2463
+ ```
2464
+
2465
+ > ⚠️ **Prefer the SDK over raw `requests`/`httpx`.** If you hand-roll a poll loop, don't assume `timeout=(5, 60)` or `httpx.Timeout(120)` caps total call duration — both are **per-chunk** read timeouts (reset on every byte), so a trickling response can block forever. For a hard wall-clock deadline, track `time.monotonic()` at the loop level and bail explicitly, or wrap with `asyncio.wait_for()`. See [Receiving Events](../../shared/managed-agents-events.md#receiving-events).
2466
+
2467
+ ---
2468
+
2469
+ ## Full Streaming Loop with Custom Tools
2470
+
2471
+ ```python
2472
+ import json
2473
+
2474
+
2475
+ def run_custom_tool(tool_name: str, tool_input: dict) -> str:
2476
+ """Execute a custom tool and return the result."""
2477
+ if tool_name == "run_tests":
2478
+ # Your tool implementation here
2479
+ return "All tests passed."
2480
+ return f"Unknown tool: {tool_name}"
2481
+
2482
+
2483
+ def run_session(client, session_id: str):
2484
+ """Stream events and handle custom tool calls."""
2485
+ while True:
2486
+ with client.beta.sessions.events.stream(
2487
+ session_id=session_id,
2488
+ ) as stream:
2489
+ tool_calls = []
2490
+ for event in stream:
2491
+ if event.type == "agent.message":
2492
+ for block in event.content:
2493
+ if block.type == "text":
2494
+ print(block.text, end="", flush=True)
2495
+ elif event.type == "agent.custom_tool_use":
2496
+ tool_calls.append(event)
2497
+ elif event.type == "session.status_idle":
2498
+ break
2499
+ elif event.type == "session.status_terminated":
2500
+ return
2501
+
2502
+ if not tool_calls:
2503
+ break
2504
+
2505
+ # Process custom tool calls
2506
+ results = []
2507
+ for call in tool_calls:
2508
+ result = run_custom_tool(call.name, call.input)
2509
+ results.append({
2510
+ "type": "user.custom_tool_result",
2511
+ "custom_tool_use_id": call.id,
2512
+ "content": [{"type": "text", "text": result}],
2513
+ })
2514
+
2515
+ client.beta.sessions.events.send(
2516
+ session_id=session_id,
2517
+ events=results,
2518
+ )
2519
+ ```
2520
+
2521
+ ---
2522
+
2523
+ ## Upload a File
2524
+
2525
+ ```python
2526
+ with open("data.csv", "rb") as f:
2527
+ file = client.beta.files.upload(
2528
+ file=f,
2529
+ )
2530
+
2531
+ # Use in a session
2532
+ session = client.beta.sessions.create(
2533
+ agent={"type": "agent", "id": agent.id, "version": agent.version},
2534
+ environment_id=environment.id,
2535
+ resources=[{"type": "file", "file_id": file.id, "mount_path": "/workspace/data.csv"}],
2536
+ )
2537
+ ```
2538
+
2539
+ ---
2540
+
2541
+ ## List and Download Session Files
2542
+
2543
+ List files the agent wrote to `/mnt/session/outputs/` during a session, then download them.
2544
+
2545
+ ```python
2546
+ # List files associated with a session
2547
+ files = client.beta.files.list(
2548
+ scope_id=session.id,
2549
+ betas=["managed-agents-2026-04-01"],
2550
+ )
2551
+ for f in files.data:
2552
+ print(f.filename, f.size_bytes)
2553
+ # Download each file and save to disk
2554
+ file_content = client.beta.files.download(f.id)
2555
+ file_content.write_to_file(f.filename)
2556
+ ```
2557
+
2558
+ > 💡 There's a brief indexing lag (~1–3s) between `session.status_idle` and output files appearing in `files.list`. Retry once or twice if the list is empty.
2559
+
2560
+ ---
2561
+
2562
+ ## Session Management
2563
+
2564
+ ```python
2565
+ # Get session details
2566
+ session = client.beta.sessions.retrieve(session_id="sesn_011CZxAbc123Def456")
2567
+ print(session.status, session.usage)
2568
+
2569
+ # List sessions
2570
+ sessions = client.beta.sessions.list()
2571
+
2572
+ # Delete a session
2573
+ client.beta.sessions.delete(session_id="sesn_011CZxAbc123Def456")
2574
+
2575
+ # Archive a session
2576
+ client.beta.sessions.archive(session_id="sesn_011CZxAbc123Def456")
2577
+ ```
2578
+
2579
+ ---
2580
+
2581
+ ## MCP Server Integration
2582
+
2583
+ ```python
2584
+ # Agent declares MCP server (no auth here — auth goes in a vault)
2585
+ agent = client.beta.agents.create(
2586
+ name="MCP Agent",
2587
+ model="claude-opus-4-8",
2588
+ mcp_servers=[
2589
+ {"type": "url", "name": "my-tools", "url": "https://my-mcp-server.example.com/sse"},
2590
+ ],
2591
+ tools=[
2592
+ {"type": "agent_toolset_20260401", "default_config": {"enabled": True}},
2593
+ {"type": "mcp_toolset", "mcp_server_name": "my-tools"},
2594
+ ],
2595
+ )
2596
+
2597
+ # Session attaches vault(s) containing credentials for those MCP server URLs
2598
+ session = client.beta.sessions.create(
2599
+ agent=agent.id,
2600
+ environment_id=environment.id,
2601
+ vault_ids=[vault.id],
2602
+ )
2603
+ ```
2604
+
2605
+ See `shared/managed-agents-tools.md` §Vaults for creating vaults and adding credentials.