@preapexis/piexis 0.2.2 → 0.2.4

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 (149) hide show
  1. package/AGENTS.md +21 -41
  2. package/README.md +73 -139
  3. package/extensions/agents.ts +205 -0
  4. package/extensions/ask-question.ts +54 -95
  5. package/extensions/recommended-tools.ts +62 -0
  6. package/extensions/ui.ts +204 -58
  7. package/lib/agent-config.ts +55 -0
  8. package/lib/agents.ts +208 -0
  9. package/lib/question-model.ts +98 -0
  10. package/lib/question-ui.ts +214 -0
  11. package/lib/recommended-tools.ts +119 -0
  12. package/lib/subagent-runner.ts +146 -0
  13. package/lib/ui-tips.json +41 -0
  14. package/package.json +5 -13
  15. package/prompts/init.md +10 -2
  16. package/prompts/summary.md +7 -6
  17. package/schemas/agent.schema.json +48 -0
  18. package/skills/{claude-api/LICENSE.txt → caveman/LICENSE} +2 -2
  19. package/skills/caveman/LICENSE-MIT +21 -0
  20. package/skills/caveman/NOTICE +10 -0
  21. package/skills/caveman/SKILL.md +89 -0
  22. package/skills/find-skills/SKILL.md +141 -0
  23. package/skills/ponytail/LICENSE +21 -0
  24. package/skills/ponytail/NOTICE +9 -0
  25. package/skills/ponytail/SKILL.md +52 -0
  26. package/skills-lock.json +6 -0
  27. package/tests/agents.test.mjs +605 -0
  28. package/tests/ask-question-pty.test.mjs +16 -0
  29. package/tests/ask-question.test.mjs +269 -0
  30. package/tests/fixtures/agents-provider.ts +55 -0
  31. package/tests/fixtures/ask-question-pty.py +91 -0
  32. package/tests/fixtures/ask-question-terminal.mjs +69 -0
  33. package/tests/fixtures/recommended-tools-terminal.mjs +103 -0
  34. package/tests/init-workflow.test.mjs +31 -0
  35. package/tests/recommended-tools-pty.test.mjs +16 -0
  36. package/tests/recommended-tools.test.mjs +423 -0
  37. package/tests/resources.test.mjs +66 -0
  38. package/tests/skills-routing.test.mjs +7 -4
  39. package/tests/ui-tip-reload.test.mjs +70 -0
  40. package/tests/ui.test.mjs +450 -0
  41. package/tsconfig.json +1 -0
  42. package/eval/README.md +0 -72
  43. package/eval/permission-cases.json +0 -28
  44. package/eval/permissions.mjs +0 -103
  45. package/extensions/background-tasks.ts +0 -433
  46. package/extensions/background-worker.ts +0 -50
  47. package/extensions/glob.ts +0 -32
  48. package/extensions/mode.ts +0 -397
  49. package/lib/bash-approvals.ts +0 -113
  50. package/lib/bash-policy.ts +0 -164
  51. package/lib/mode-policy.ts +0 -174
  52. package/lib/path-policy.ts +0 -182
  53. package/lib/permission-classifier.ts +0 -128
  54. package/lib/permission-config.ts +0 -91
  55. package/lib/permission-denials.ts +0 -32
  56. package/lib/permission-intent.ts +0 -128
  57. package/lib/permission-taxonomy.ts +0 -15
  58. package/lib/task-broker.ts +0 -65
  59. package/lib/task-checkout.ts +0 -39
  60. package/lib/task-git.ts +0 -44
  61. package/lib/task-patch.ts +0 -106
  62. package/lib/task-permissions.ts +0 -51
  63. package/lib/task-report.ts +0 -62
  64. package/lib/task-worktree-policy.ts +0 -56
  65. package/skills/claude-api/SKILL.md +0 -572
  66. package/skills/claude-api/csharp/claude-api/README.md +0 -362
  67. package/skills/claude-api/csharp/claude-api/batches.md +0 -14
  68. package/skills/claude-api/csharp/claude-api/files-api.md +0 -25
  69. package/skills/claude-api/csharp/claude-api/streaming.md +0 -28
  70. package/skills/claude-api/csharp/claude-api/tool-use.md +0 -164
  71. package/skills/claude-api/curl/examples.md +0 -256
  72. package/skills/claude-api/curl/managed-agents.md +0 -371
  73. package/skills/claude-api/go/claude-api/README.md +0 -188
  74. package/skills/claude-api/go/claude-api/files-api.md +0 -23
  75. package/skills/claude-api/go/claude-api/streaming.md +0 -43
  76. package/skills/claude-api/go/claude-api/tool-use.md +0 -220
  77. package/skills/claude-api/go/managed-agents/README.md +0 -564
  78. package/skills/claude-api/java/claude-api/README.md +0 -238
  79. package/skills/claude-api/java/claude-api/files-api.md +0 -27
  80. package/skills/claude-api/java/claude-api/streaming.md +0 -24
  81. package/skills/claude-api/java/claude-api/tool-use.md +0 -228
  82. package/skills/claude-api/java/managed-agents/README.md +0 -443
  83. package/skills/claude-api/php/claude-api/README.md +0 -174
  84. package/skills/claude-api/php/claude-api/batches.md +0 -15
  85. package/skills/claude-api/php/claude-api/files-api.md +0 -13
  86. package/skills/claude-api/php/claude-api/streaming.md +0 -27
  87. package/skills/claude-api/php/claude-api/tool-use.md +0 -253
  88. package/skills/claude-api/php/managed-agents/README.md +0 -443
  89. package/skills/claude-api/python/claude-api/README.md +0 -565
  90. package/skills/claude-api/python/claude-api/batches.md +0 -198
  91. package/skills/claude-api/python/claude-api/files-api.md +0 -170
  92. package/skills/claude-api/python/claude-api/sdk-upgrade.md +0 -286
  93. package/skills/claude-api/python/claude-api/streaming.md +0 -179
  94. package/skills/claude-api/python/claude-api/tool-use.md +0 -627
  95. package/skills/claude-api/python/managed-agents/README.md +0 -335
  96. package/skills/claude-api/ruby/claude-api/README.md +0 -134
  97. package/skills/claude-api/ruby/claude-api/streaming.md +0 -16
  98. package/skills/claude-api/ruby/claude-api/tool-use.md +0 -41
  99. package/skills/claude-api/ruby/managed-agents/README.md +0 -394
  100. package/skills/claude-api/shared/admin-api.md +0 -179
  101. package/skills/claude-api/shared/agent-design.md +0 -101
  102. package/skills/claude-api/shared/anthropic-cli.md +0 -269
  103. package/skills/claude-api/shared/claude-platform-on-aws.md +0 -59
  104. package/skills/claude-api/shared/cost-optimization.md +0 -233
  105. package/skills/claude-api/shared/error-codes.md +0 -262
  106. package/skills/claude-api/shared/live-sources.md +0 -166
  107. package/skills/claude-api/shared/managed-agents-api-reference.md +0 -455
  108. package/skills/claude-api/shared/managed-agents-client-patterns.md +0 -220
  109. package/skills/claude-api/shared/managed-agents-core.md +0 -359
  110. package/skills/claude-api/shared/managed-agents-environments.md +0 -226
  111. package/skills/claude-api/shared/managed-agents-events.md +0 -290
  112. package/skills/claude-api/shared/managed-agents-memory.md +0 -201
  113. package/skills/claude-api/shared/managed-agents-multiagent.md +0 -260
  114. package/skills/claude-api/shared/managed-agents-onboarding.md +0 -82
  115. package/skills/claude-api/shared/managed-agents-outcomes.md +0 -108
  116. package/skills/claude-api/shared/managed-agents-overview.md +0 -77
  117. package/skills/claude-api/shared/managed-agents-scheduled-deployments.md +0 -156
  118. package/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +0 -282
  119. package/skills/claude-api/shared/managed-agents-tools.md +0 -504
  120. package/skills/claude-api/shared/managed-agents-webhooks.md +0 -143
  121. package/skills/claude-api/shared/model-migration.md +0 -1872
  122. package/skills/claude-api/shared/models.md +0 -142
  123. package/skills/claude-api/shared/platform-availability.md +0 -53
  124. package/skills/claude-api/shared/prompt-audit.md +0 -223
  125. package/skills/claude-api/shared/prompt-caching.md +0 -292
  126. package/skills/claude-api/shared/token-counting.md +0 -56
  127. package/skills/claude-api/shared/tool-use-concepts.md +0 -526
  128. package/skills/claude-api/typescript/claude-api/README.md +0 -405
  129. package/skills/claude-api/typescript/claude-api/batches.md +0 -106
  130. package/skills/claude-api/typescript/claude-api/files-api.md +0 -98
  131. package/skills/claude-api/typescript/claude-api/streaming.md +0 -178
  132. package/skills/claude-api/typescript/claude-api/tool-use.md +0 -586
  133. package/skills/claude-api/typescript/managed-agents/README.md +0 -359
  134. package/tests/auto-permissions.test.mjs +0 -315
  135. package/tests/background-tasks.test.mjs +0 -27
  136. package/tests/background-worker.test.mjs +0 -60
  137. package/tests/bash-permissions.test.mjs +0 -276
  138. package/tests/glob.test.mjs +0 -31
  139. package/tests/mode.test.mjs +0 -62
  140. package/tests/permission-evaluation.test.mjs +0 -70
  141. package/tests/permission-foundation.test.mjs +0 -194
  142. package/tests/permission-policy.test.mjs +0 -158
  143. package/tests/runtime/README.md +0 -51
  144. package/tests/runtime/harness.mjs +0 -190
  145. package/tests/runtime/permissions.test.mjs +0 -192
  146. package/tests/runtime/tui.test.mjs +0 -60
  147. package/tests/task-integration.test.mjs +0 -324
  148. package/tests/task-permissions.test.mjs +0 -178
  149. package/tests/task-worktree-policy.test.mjs +0 -53
@@ -1,627 +0,0 @@
1
- # Tool Use - Python
2
-
3
- For conceptual overview (tool definitions, tool choice, tips), see [shared/tool-use-concepts.md](../../shared/tool-use-concepts.md).
4
-
5
- ## Tool Runner (Recommended)
6
-
7
- **Beta:** The tool runner is in beta in the Python SDK.
8
-
9
- Use the `@beta_tool` decorator to define tools as typed functions, then pass them to `client.beta.messages.tool_runner()`:
10
-
11
- ```python
12
- import anthropic
13
- from anthropic import beta_tool
14
-
15
- client = anthropic.Anthropic()
16
-
17
- @beta_tool
18
- def get_weather(location: str, unit: str = "celsius") -> str:
19
- """Get current weather for a location.
20
-
21
- Args:
22
- location: City and state, e.g., San Francisco, CA.
23
- unit: Temperature unit, either "celsius" or "fahrenheit".
24
- """
25
- # Your implementation here
26
- return f"72°F and sunny in {location}"
27
-
28
- # The tool runner handles the agentic loop automatically
29
- runner = client.beta.messages.tool_runner(
30
- model="claude-opus-5",
31
- max_tokens=16000,
32
- tools=[get_weather],
33
- messages=[{"role": "user", "content": "What's the weather in Paris?"}],
34
- )
35
-
36
- # Each iteration yields a BetaMessage; iteration stops when Claude is done
37
- for message in runner:
38
- print(message)
39
- ```
40
-
41
- For async usage, use `@beta_async_tool` with `async def` functions.
42
-
43
- **Key benefits of the tool runner:**
44
-
45
- - No manual loop - the SDK handles calling tools and feeding results back
46
- - Type-safe tool inputs via decorators
47
- - Tool schemas are generated automatically from function signatures
48
- - Iteration stops automatically when Claude has no more tool calls
49
-
50
- ### Server tools with the tool runner
51
-
52
- The runner's `tools` list accepts raw server-tool definitions (`web_search_20260209`, `web_fetch_20260209`, code execution) alongside decorated tools - pass the literal tool dict; server tools run on Anthropic's servers, so there is no function to implement.
53
-
54
- **Caution - the runner does not auto-resume `pause_turn` (as of `anthropic` 0.116.0).** A long-running server-tool turn can stop with `stop_reason: "pause_turn"`. The runner only continues after a client tool produces a result, so a paused turn ends the loop and is returned as the final message - no error, no warning, just a silently truncated answer. Unlike the TypeScript runner, the Python runner cannot be resumed mid-loop: it exits unconditionally when no client tool ran, and `runner.append_messages(...)` does not prevent the exit. To handle `pause_turn`, mirror the conversation history as you iterate, then restart the runner with the paused turn appended:
55
-
56
- ```python
57
- messages = [{"role": "user", "content": user_input}]
58
-
59
- max_restarts = 5 # cap pause_turn restarts, mirroring max_continuations advice
60
- restarts = 0
61
- while True:
62
- runner = client.beta.messages.tool_runner(
63
- model="claude-opus-5",
64
- max_tokens=16000,
65
- tools=tools, # may mix @beta_tool functions and server-tool definitions
66
- messages=messages,
67
- )
68
- last = None
69
- for message in runner:
70
- last = message
71
- # Mirror the history - the runner keeps its own copy and does not expose it
72
- messages.append({"role": "assistant", "content": message.content})
73
- tool_response = runner.generate_tool_call_response() # cached; tools still run once
74
- if tool_response is not None:
75
- messages.append(tool_response)
76
- if last is None or last.stop_reason != "pause_turn":
77
- break
78
- restarts += 1
79
- if restarts > max_restarts:
80
- raise RuntimeError("giving up: turn still paused after max_restarts")
81
- # Paused mid-turn: `messages` already ends with the paused assistant
82
- # turn, so the next runner resumes it
83
- ```
84
-
85
- Alternatively, use the manual loop below, which handles `pause_turn` explicitly.
86
-
87
- ---
88
-
89
- ## MCP Tool Conversion Helpers
90
-
91
- **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+).
92
-
93
- > **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.
94
-
95
- ### MCP Tools with Tool Runner
96
-
97
- ```python
98
- from anthropic import AsyncAnthropic
99
- from anthropic.lib.tools.mcp import async_mcp_tool
100
- from mcp import ClientSession
101
- from mcp.client.stdio import stdio_client, StdioServerParameters
102
-
103
- client = AsyncAnthropic()
104
-
105
- async with stdio_client(StdioServerParameters(command="mcp-server")) as (read, write):
106
- async with ClientSession(read, write) as mcp_client:
107
- await mcp_client.initialize()
108
-
109
- tools_result = await mcp_client.list_tools()
110
- # tool_runner is sync - returns the runner, not a coroutine
111
- runner = client.beta.messages.tool_runner(
112
- model="claude-opus-5",
113
- max_tokens=16000,
114
- messages=[{"role": "user", "content": "Use the available tools"}],
115
- tools=[async_mcp_tool(t, mcp_client) for t in tools_result.tools],
116
- )
117
- async for message in runner:
118
- print(message)
119
- ```
120
-
121
- For sync usage, use `mcp_tool` instead of `async_mcp_tool`.
122
-
123
- ### MCP Prompts
124
-
125
- ```python
126
- from anthropic.lib.tools.mcp import mcp_message
127
-
128
- prompt = await mcp_client.get_prompt(name="my-prompt")
129
- response = await client.beta.messages.create(
130
- model="claude-opus-5",
131
- max_tokens=16000,
132
- messages=[mcp_message(m) for m in prompt.messages],
133
- )
134
- ```
135
-
136
- ### MCP Resources as Content
137
-
138
- ```python
139
- from anthropic.lib.tools.mcp import mcp_resource_to_content
140
-
141
- resource = await mcp_client.read_resource(uri="file:///path/to/doc.txt")
142
- response = await client.beta.messages.create(
143
- model="claude-opus-5",
144
- max_tokens=16000,
145
- messages=[{
146
- "role": "user",
147
- "content": [
148
- mcp_resource_to_content(resource),
149
- {"type": "text", "text": "Summarize this document"},
150
- ],
151
- }],
152
- )
153
- ```
154
-
155
- ### Upload MCP Resources as Files
156
-
157
- ```python
158
- from anthropic.lib.tools.mcp import mcp_resource_to_file
159
-
160
- resource = await mcp_client.read_resource(uri="file:///path/to/data.json")
161
- uploaded = await client.beta.files.upload(file=mcp_resource_to_file(resource))
162
- ```
163
-
164
- Conversion functions raise `UnsupportedMCPValueError` if an MCP value cannot be converted (e.g., unsupported content types like audio, unsupported MIME types).
165
-
166
- ---
167
-
168
- ## Manual Agentic Loop
169
-
170
- Prefer the tool runner above. Drop to a manual loop only when you need control the runner does not expose (e.g., a custom transport, request shapes the SDK cannot build, or avoiding a beta dependency - the runner is beta). Human-in-the-loop approval does *not* require a manual loop - gate inside the tool function (return a "user declined" result) or inspect pending `tool_use` blocks in the `for message in runner:` body and call `runner.set_messages_params()`.
171
-
172
- If you do need a manual loop:
173
-
174
- ```python
175
- import anthropic
176
-
177
- client = anthropic.Anthropic()
178
- tools = [...] # Your tool definitions
179
- messages = [{"role": "user", "content": user_input}]
180
-
181
- # Agentic loop: keep going until Claude stops calling tools
182
- while True:
183
- response = client.messages.create(
184
- model="claude-opus-5",
185
- max_tokens=16000,
186
- tools=tools,
187
- messages=messages
188
- )
189
-
190
- # If Claude is done (no more tool calls), break
191
- if response.stop_reason == "end_turn":
192
- break
193
-
194
- # Server-side tool hit iteration limit; re-send to continue
195
- if response.stop_reason == "pause_turn":
196
- messages = [
197
- {"role": "user", "content": user_input},
198
- {"role": "assistant", "content": response.content},
199
- ]
200
- continue
201
-
202
- # Extract tool use blocks from the response
203
- tool_use_blocks = [b for b in response.content if b.type == "tool_use"]
204
-
205
- # Append assistant's response (including tool_use blocks)
206
- messages.append({"role": "assistant", "content": response.content})
207
-
208
- # Execute each tool and collect results
209
- tool_results = []
210
- for tool in tool_use_blocks:
211
- result = execute_tool(tool.name, tool.input) # Your implementation
212
- tool_results.append({
213
- "type": "tool_result",
214
- "tool_use_id": tool.id, # Must match the tool_use block's id
215
- "content": result
216
- })
217
-
218
- # Append tool results as a user message
219
- messages.append({"role": "user", "content": tool_results})
220
-
221
- # Final response text
222
- final_text = next(b.text for b in response.content if b.type == "text")
223
- ```
224
-
225
- ---
226
-
227
- ## Handling Tool Results
228
-
229
- ```python
230
- response = client.messages.create(
231
- model="claude-opus-5",
232
- max_tokens=16000,
233
- tools=tools,
234
- messages=[{"role": "user", "content": "What's the weather in Paris?"}]
235
- )
236
-
237
- for block in response.content:
238
- if block.type == "tool_use":
239
- tool_name = block.name
240
- tool_input = block.input
241
- tool_use_id = block.id
242
-
243
- result = execute_tool(tool_name, tool_input)
244
-
245
- followup = client.messages.create(
246
- model="claude-opus-5",
247
- max_tokens=16000,
248
- tools=tools,
249
- messages=[
250
- {"role": "user", "content": "What's the weather in Paris?"},
251
- {"role": "assistant", "content": response.content},
252
- {
253
- "role": "user",
254
- "content": [{
255
- "type": "tool_result",
256
- "tool_use_id": tool_use_id,
257
- "content": result
258
- }]
259
- }
260
- ]
261
- )
262
- ```
263
-
264
- ---
265
-
266
- ## Multiple Tool Calls
267
-
268
- ```python
269
- tool_results = []
270
-
271
- for block in response.content:
272
- if block.type == "tool_use":
273
- result = execute_tool(block.name, block.input)
274
- tool_results.append({
275
- "type": "tool_result",
276
- "tool_use_id": block.id,
277
- "content": result
278
- })
279
-
280
- # Send all results back at once
281
- if tool_results:
282
- followup = client.messages.create(
283
- model="claude-opus-5",
284
- max_tokens=16000,
285
- tools=tools,
286
- messages=[
287
- *previous_messages,
288
- {"role": "assistant", "content": response.content},
289
- {"role": "user", "content": tool_results}
290
- ]
291
- )
292
- ```
293
-
294
- ---
295
-
296
- ## Error Handling in Tool Results
297
-
298
- ```python
299
- tool_result = {
300
- "type": "tool_result",
301
- "tool_use_id": tool_use_id,
302
- "content": "Error: Location 'xyz' not found. Please provide a valid city name.",
303
- "is_error": True
304
- }
305
- ```
306
-
307
- ---
308
-
309
- ## Tool Choice
310
-
311
- ```python
312
- response = client.messages.create(
313
- model="claude-opus-5",
314
- max_tokens=16000,
315
- tools=tools,
316
- tool_choice={"type": "tool", "name": "get_weather"}, # Force specific tool
317
- messages=[{"role": "user", "content": "What's the weather in Paris?"}]
318
- )
319
- ```
320
-
321
- ---
322
-
323
- ## Code Execution
324
-
325
- ### Basic Usage
326
-
327
- ```python
328
- import anthropic
329
-
330
- client = anthropic.Anthropic()
331
-
332
- response = client.messages.create(
333
- model="claude-opus-5",
334
- max_tokens=16000,
335
- messages=[{
336
- "role": "user",
337
- "content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
338
- }],
339
- tools=[{
340
- "type": "code_execution_20260120",
341
- "name": "code_execution"
342
- }]
343
- )
344
-
345
- for block in response.content:
346
- if block.type == "text":
347
- print(block.text)
348
- elif block.type == "bash_code_execution_tool_result":
349
- print(f"stdout: {block.content.stdout}")
350
- ```
351
-
352
- ### Upload Files for Analysis
353
-
354
- ```python
355
- # 1. Upload a file
356
- uploaded = client.beta.files.upload(file=open("sales_data.csv", "rb"))
357
-
358
- # 2. Pass to code execution via container_upload block
359
- response = client.messages.create(
360
- model="claude-opus-5",
361
- max_tokens=16000,
362
- messages=[{
363
- "role": "user",
364
- "content": [
365
- {"type": "text", "text": "Analyze this sales data. Show trends and create a visualization."},
366
- {"type": "container_upload", "file_id": uploaded.id}
367
- ]
368
- }],
369
- tools=[{"type": "code_execution_20260120", "name": "code_execution"}]
370
- )
371
- ```
372
-
373
- ### Retrieve Generated Files
374
-
375
- ```python
376
- import os
377
-
378
- OUTPUT_DIR = "./claude_outputs"
379
- os.makedirs(OUTPUT_DIR, exist_ok=True)
380
-
381
- for block in response.content:
382
- if block.type == "bash_code_execution_tool_result":
383
- result = block.content
384
- if result.type == "bash_code_execution_result" and result.content:
385
- for file_ref in result.content:
386
- if file_ref.type == "bash_code_execution_output":
387
- metadata = client.beta.files.retrieve_metadata(file_ref.file_id)
388
- file_content = client.beta.files.download(file_ref.file_id)
389
- # Use basename to prevent path traversal; validate result
390
- safe_name = os.path.basename(metadata.filename)
391
- if not safe_name or safe_name in (".", ".."):
392
- print(f"Skipping invalid filename: {metadata.filename}")
393
- continue
394
- output_path = os.path.join(OUTPUT_DIR, safe_name)
395
- file_content.write_to_file(output_path)
396
- print(f"Saved: {output_path}")
397
- ```
398
-
399
- ### Container Reuse
400
-
401
- ```python
402
- # First request: set up environment
403
- response1 = client.messages.create(
404
- model="claude-opus-5",
405
- max_tokens=16000,
406
- messages=[{"role": "user", "content": "Install tabulate and create data.json with sample data"}],
407
- tools=[{"type": "code_execution_20260120", "name": "code_execution"}]
408
- )
409
-
410
- # Get container ID from response
411
- container_id = response1.container.id
412
-
413
- # Second request: reuse the same container
414
- response2 = client.messages.create(
415
- container=container_id,
416
- model="claude-opus-5",
417
- max_tokens=16000,
418
- messages=[{"role": "user", "content": "Read data.json and display as a formatted table"}],
419
- tools=[{"type": "code_execution_20260120", "name": "code_execution"}]
420
- )
421
- ```
422
-
423
- ### Response Structure
424
-
425
- ```python
426
- for block in response.content:
427
- if block.type == "text":
428
- print(block.text) # Claude's explanation
429
- elif block.type == "server_tool_use":
430
- print(f"Running: {block.name} - {block.input}") # What Claude is doing
431
- elif block.type == "bash_code_execution_tool_result":
432
- result = block.content
433
- if result.type == "bash_code_execution_result":
434
- if result.return_code == 0:
435
- print(f"Output: {result.stdout}")
436
- else:
437
- print(f"Error: {result.stderr}")
438
- else:
439
- print(f"Tool error: {result.error_code}")
440
- elif block.type == "text_editor_code_execution_tool_result":
441
- print(f"File operation: {block.content}")
442
- ```
443
-
444
- ---
445
-
446
- ## Memory Tool
447
-
448
- ### Basic Usage
449
-
450
- ```python
451
- import anthropic
452
-
453
- client = anthropic.Anthropic()
454
-
455
- response = client.messages.create(
456
- model="claude-opus-5",
457
- max_tokens=16000,
458
- messages=[{"role": "user", "content": "Remember that my preferred language is Python."}],
459
- tools=[{"type": "memory_20250818", "name": "memory"}],
460
- )
461
- ```
462
-
463
- ### SDK Memory Helper
464
-
465
- Subclass `BetaAbstractMemoryTool`:
466
-
467
- ```python
468
- from anthropic.lib.tools import BetaAbstractMemoryTool
469
-
470
- class MyMemoryTool(BetaAbstractMemoryTool):
471
- def view(self, command): ...
472
- def create(self, command): ...
473
- def str_replace(self, command): ...
474
- def insert(self, command): ...
475
- def delete(self, command): ...
476
- def rename(self, command): ...
477
-
478
- memory = MyMemoryTool()
479
-
480
- # Use with tool runner
481
- runner = client.beta.messages.tool_runner(
482
- model="claude-opus-5",
483
- max_tokens=16000,
484
- tools=[memory],
485
- messages=[{"role": "user", "content": "Remember my preferences"}],
486
- )
487
-
488
- for message in runner:
489
- print(message)
490
- ```
491
-
492
- For full implementation examples, use WebFetch:
493
-
494
- - `https://github.com/anthropics/anthropic-sdk-python/blob/main/examples/memory/basic.py`
495
-
496
- ---
497
-
498
- ## Structured Outputs
499
-
500
- ### JSON Outputs (Pydantic - Recommended)
501
-
502
- ```python
503
- from pydantic import BaseModel
504
- from typing import List
505
- import anthropic
506
-
507
- class ContactInfo(BaseModel):
508
- name: str
509
- email: str
510
- plan: str
511
- interests: List[str]
512
- demo_requested: bool
513
-
514
- client = anthropic.Anthropic()
515
-
516
- response = client.messages.parse(
517
- model="claude-opus-5",
518
- max_tokens=16000,
519
- messages=[{
520
- "role": "user",
521
- "content": "Extract: Jane Doe (jane@co.com) wants Enterprise, interested in API and SDKs, wants a demo."
522
- }],
523
- output_format=ContactInfo,
524
- )
525
-
526
- # response.parsed_output is a validated ContactInfo instance
527
- contact = response.parsed_output
528
- print(contact.name) # "Jane Doe"
529
- print(contact.interests) # ["API", "SDKs"]
530
- ```
531
-
532
- ### Raw Schema
533
-
534
- ```python
535
- response = client.messages.create(
536
- model="claude-opus-5",
537
- max_tokens=16000,
538
- messages=[{
539
- "role": "user",
540
- "content": "Extract info: John Smith (john@example.com) wants the Enterprise plan."
541
- }],
542
- output_config={
543
- "format": {
544
- "type": "json_schema",
545
- "schema": {
546
- "type": "object",
547
- "properties": {
548
- "name": {"type": "string"},
549
- "email": {"type": "string"},
550
- "plan": {"type": "string"},
551
- "demo_requested": {"type": "boolean"}
552
- },
553
- "required": ["name", "email", "plan", "demo_requested"],
554
- "additionalProperties": False
555
- }
556
- }
557
- }
558
- )
559
-
560
- import json
561
- # output_config.format guarantees the first block is text with valid JSON
562
- text = next(b.text for b in response.content if b.type == "text")
563
- data = json.loads(text)
564
- ```
565
-
566
- ### Strict Tool Use
567
-
568
- ```python
569
- response = client.messages.create(
570
- model="claude-opus-5",
571
- max_tokens=16000,
572
- messages=[{"role": "user", "content": "Book a flight to Tokyo for 2 passengers on March 15"}],
573
- tools=[{
574
- "name": "book_flight",
575
- "description": "Book a flight to a destination",
576
- "strict": True,
577
- "input_schema": {
578
- "type": "object",
579
- "properties": {
580
- "destination": {"type": "string"},
581
- "date": {"type": "string", "format": "date"},
582
- "passengers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6, 7, 8]}
583
- },
584
- "required": ["destination", "date", "passengers"],
585
- "additionalProperties": False
586
- }
587
- }]
588
- )
589
- ```
590
-
591
- ### Using Both Together
592
-
593
- ```python
594
- response = client.messages.create(
595
- model="claude-opus-5",
596
- max_tokens=16000,
597
- messages=[{"role": "user", "content": "Plan a trip to Paris next month"}],
598
- output_config={
599
- "format": {
600
- "type": "json_schema",
601
- "schema": {
602
- "type": "object",
603
- "properties": {
604
- "summary": {"type": "string"},
605
- "next_steps": {"type": "array", "items": {"type": "string"}}
606
- },
607
- "required": ["summary", "next_steps"],
608
- "additionalProperties": False
609
- }
610
- }
611
- },
612
- tools=[{
613
- "name": "search_flights",
614
- "description": "Search for available flights",
615
- "strict": True,
616
- "input_schema": {
617
- "type": "object",
618
- "properties": {
619
- "destination": {"type": "string"},
620
- "date": {"type": "string", "format": "date"}
621
- },
622
- "required": ["destination", "date"],
623
- "additionalProperties": False
624
- }
625
- }]
626
- )
627
- ```