@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.
- package/AGENTS.md +21 -41
- package/README.md +73 -139
- package/extensions/agents.ts +205 -0
- package/extensions/ask-question.ts +54 -95
- package/extensions/recommended-tools.ts +62 -0
- package/extensions/ui.ts +204 -58
- package/lib/agent-config.ts +55 -0
- package/lib/agents.ts +208 -0
- package/lib/question-model.ts +98 -0
- package/lib/question-ui.ts +214 -0
- package/lib/recommended-tools.ts +119 -0
- package/lib/subagent-runner.ts +146 -0
- package/lib/ui-tips.json +41 -0
- package/package.json +5 -13
- package/prompts/init.md +10 -2
- package/prompts/summary.md +7 -6
- package/schemas/agent.schema.json +48 -0
- package/skills/{claude-api/LICENSE.txt → caveman/LICENSE} +2 -2
- package/skills/caveman/LICENSE-MIT +21 -0
- package/skills/caveman/NOTICE +10 -0
- package/skills/caveman/SKILL.md +89 -0
- package/skills/find-skills/SKILL.md +141 -0
- package/skills/ponytail/LICENSE +21 -0
- package/skills/ponytail/NOTICE +9 -0
- package/skills/ponytail/SKILL.md +52 -0
- package/skills-lock.json +6 -0
- package/tests/agents.test.mjs +605 -0
- package/tests/ask-question-pty.test.mjs +16 -0
- package/tests/ask-question.test.mjs +269 -0
- package/tests/fixtures/agents-provider.ts +55 -0
- package/tests/fixtures/ask-question-pty.py +91 -0
- package/tests/fixtures/ask-question-terminal.mjs +69 -0
- package/tests/fixtures/recommended-tools-terminal.mjs +103 -0
- package/tests/init-workflow.test.mjs +31 -0
- package/tests/recommended-tools-pty.test.mjs +16 -0
- package/tests/recommended-tools.test.mjs +423 -0
- package/tests/resources.test.mjs +66 -0
- package/tests/skills-routing.test.mjs +7 -4
- package/tests/ui-tip-reload.test.mjs +70 -0
- package/tests/ui.test.mjs +450 -0
- package/tsconfig.json +1 -0
- package/eval/README.md +0 -72
- package/eval/permission-cases.json +0 -28
- package/eval/permissions.mjs +0 -103
- package/extensions/background-tasks.ts +0 -433
- package/extensions/background-worker.ts +0 -50
- package/extensions/glob.ts +0 -32
- package/extensions/mode.ts +0 -397
- package/lib/bash-approvals.ts +0 -113
- package/lib/bash-policy.ts +0 -164
- package/lib/mode-policy.ts +0 -174
- package/lib/path-policy.ts +0 -182
- package/lib/permission-classifier.ts +0 -128
- package/lib/permission-config.ts +0 -91
- package/lib/permission-denials.ts +0 -32
- package/lib/permission-intent.ts +0 -128
- package/lib/permission-taxonomy.ts +0 -15
- package/lib/task-broker.ts +0 -65
- package/lib/task-checkout.ts +0 -39
- package/lib/task-git.ts +0 -44
- package/lib/task-patch.ts +0 -106
- package/lib/task-permissions.ts +0 -51
- package/lib/task-report.ts +0 -62
- package/lib/task-worktree-policy.ts +0 -56
- package/skills/claude-api/SKILL.md +0 -572
- package/skills/claude-api/csharp/claude-api/README.md +0 -362
- package/skills/claude-api/csharp/claude-api/batches.md +0 -14
- package/skills/claude-api/csharp/claude-api/files-api.md +0 -25
- package/skills/claude-api/csharp/claude-api/streaming.md +0 -28
- package/skills/claude-api/csharp/claude-api/tool-use.md +0 -164
- package/skills/claude-api/curl/examples.md +0 -256
- package/skills/claude-api/curl/managed-agents.md +0 -371
- package/skills/claude-api/go/claude-api/README.md +0 -188
- package/skills/claude-api/go/claude-api/files-api.md +0 -23
- package/skills/claude-api/go/claude-api/streaming.md +0 -43
- package/skills/claude-api/go/claude-api/tool-use.md +0 -220
- package/skills/claude-api/go/managed-agents/README.md +0 -564
- package/skills/claude-api/java/claude-api/README.md +0 -238
- package/skills/claude-api/java/claude-api/files-api.md +0 -27
- package/skills/claude-api/java/claude-api/streaming.md +0 -24
- package/skills/claude-api/java/claude-api/tool-use.md +0 -228
- package/skills/claude-api/java/managed-agents/README.md +0 -443
- package/skills/claude-api/php/claude-api/README.md +0 -174
- package/skills/claude-api/php/claude-api/batches.md +0 -15
- package/skills/claude-api/php/claude-api/files-api.md +0 -13
- package/skills/claude-api/php/claude-api/streaming.md +0 -27
- package/skills/claude-api/php/claude-api/tool-use.md +0 -253
- package/skills/claude-api/php/managed-agents/README.md +0 -443
- package/skills/claude-api/python/claude-api/README.md +0 -565
- package/skills/claude-api/python/claude-api/batches.md +0 -198
- package/skills/claude-api/python/claude-api/files-api.md +0 -170
- package/skills/claude-api/python/claude-api/sdk-upgrade.md +0 -286
- package/skills/claude-api/python/claude-api/streaming.md +0 -179
- package/skills/claude-api/python/claude-api/tool-use.md +0 -627
- package/skills/claude-api/python/managed-agents/README.md +0 -335
- package/skills/claude-api/ruby/claude-api/README.md +0 -134
- package/skills/claude-api/ruby/claude-api/streaming.md +0 -16
- package/skills/claude-api/ruby/claude-api/tool-use.md +0 -41
- package/skills/claude-api/ruby/managed-agents/README.md +0 -394
- package/skills/claude-api/shared/admin-api.md +0 -179
- package/skills/claude-api/shared/agent-design.md +0 -101
- package/skills/claude-api/shared/anthropic-cli.md +0 -269
- package/skills/claude-api/shared/claude-platform-on-aws.md +0 -59
- package/skills/claude-api/shared/cost-optimization.md +0 -233
- package/skills/claude-api/shared/error-codes.md +0 -262
- package/skills/claude-api/shared/live-sources.md +0 -166
- package/skills/claude-api/shared/managed-agents-api-reference.md +0 -455
- package/skills/claude-api/shared/managed-agents-client-patterns.md +0 -220
- package/skills/claude-api/shared/managed-agents-core.md +0 -359
- package/skills/claude-api/shared/managed-agents-environments.md +0 -226
- package/skills/claude-api/shared/managed-agents-events.md +0 -290
- package/skills/claude-api/shared/managed-agents-memory.md +0 -201
- package/skills/claude-api/shared/managed-agents-multiagent.md +0 -260
- package/skills/claude-api/shared/managed-agents-onboarding.md +0 -82
- package/skills/claude-api/shared/managed-agents-outcomes.md +0 -108
- package/skills/claude-api/shared/managed-agents-overview.md +0 -77
- package/skills/claude-api/shared/managed-agents-scheduled-deployments.md +0 -156
- package/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +0 -282
- package/skills/claude-api/shared/managed-agents-tools.md +0 -504
- package/skills/claude-api/shared/managed-agents-webhooks.md +0 -143
- package/skills/claude-api/shared/model-migration.md +0 -1872
- package/skills/claude-api/shared/models.md +0 -142
- package/skills/claude-api/shared/platform-availability.md +0 -53
- package/skills/claude-api/shared/prompt-audit.md +0 -223
- package/skills/claude-api/shared/prompt-caching.md +0 -292
- package/skills/claude-api/shared/token-counting.md +0 -56
- package/skills/claude-api/shared/tool-use-concepts.md +0 -526
- package/skills/claude-api/typescript/claude-api/README.md +0 -405
- package/skills/claude-api/typescript/claude-api/batches.md +0 -106
- package/skills/claude-api/typescript/claude-api/files-api.md +0 -98
- package/skills/claude-api/typescript/claude-api/streaming.md +0 -178
- package/skills/claude-api/typescript/claude-api/tool-use.md +0 -586
- package/skills/claude-api/typescript/managed-agents/README.md +0 -359
- package/tests/auto-permissions.test.mjs +0 -315
- package/tests/background-tasks.test.mjs +0 -27
- package/tests/background-worker.test.mjs +0 -60
- package/tests/bash-permissions.test.mjs +0 -276
- package/tests/glob.test.mjs +0 -31
- package/tests/mode.test.mjs +0 -62
- package/tests/permission-evaluation.test.mjs +0 -70
- package/tests/permission-foundation.test.mjs +0 -194
- package/tests/permission-policy.test.mjs +0 -158
- package/tests/runtime/README.md +0 -51
- package/tests/runtime/harness.mjs +0 -190
- package/tests/runtime/permissions.test.mjs +0 -192
- package/tests/runtime/tui.test.mjs +0 -60
- package/tests/task-integration.test.mjs +0 -324
- package/tests/task-permissions.test.mjs +0 -178
- package/tests/task-worktree-policy.test.mjs +0 -53
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
# Message Batches API - Python
|
|
2
|
-
|
|
3
|
-
The Batches API (`POST /v1/messages/batches`) processes Messages API requests asynchronously at 50% of standard prices.
|
|
4
|
-
|
|
5
|
-
## Key Facts
|
|
6
|
-
|
|
7
|
-
- Up to 100,000 requests or 256 MB per batch
|
|
8
|
-
- Most batches complete within 1 hour; maximum 24 hours
|
|
9
|
-
- Results available for 29 days after creation
|
|
10
|
-
- 50% cost reduction on all token usage
|
|
11
|
-
- All Messages API features supported (vision, tools, caching, etc.)
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Create a Batch
|
|
16
|
-
|
|
17
|
-
```python
|
|
18
|
-
import anthropic
|
|
19
|
-
from anthropic.types.message_create_params import MessageCreateParamsNonStreaming
|
|
20
|
-
from anthropic.types.messages.batch_create_params import Request
|
|
21
|
-
|
|
22
|
-
client = anthropic.Anthropic()
|
|
23
|
-
|
|
24
|
-
message_batch = client.messages.batches.create(
|
|
25
|
-
requests=[
|
|
26
|
-
Request(
|
|
27
|
-
custom_id="request-1",
|
|
28
|
-
params=MessageCreateParamsNonStreaming(
|
|
29
|
-
model="claude-opus-5",
|
|
30
|
-
max_tokens=16000,
|
|
31
|
-
messages=[{"role": "user", "content": "Summarize climate change impacts"}]
|
|
32
|
-
)
|
|
33
|
-
),
|
|
34
|
-
Request(
|
|
35
|
-
custom_id="request-2",
|
|
36
|
-
params=MessageCreateParamsNonStreaming(
|
|
37
|
-
model="claude-opus-5",
|
|
38
|
-
max_tokens=16000,
|
|
39
|
-
messages=[{"role": "user", "content": "Explain quantum computing basics"}]
|
|
40
|
-
)
|
|
41
|
-
),
|
|
42
|
-
]
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
print(f"Batch ID: {message_batch.id}")
|
|
46
|
-
print(f"Status: {message_batch.processing_status}")
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Poll for Completion
|
|
52
|
-
|
|
53
|
-
```python
|
|
54
|
-
import time
|
|
55
|
-
|
|
56
|
-
while True:
|
|
57
|
-
batch = client.messages.batches.retrieve(message_batch.id)
|
|
58
|
-
if batch.processing_status == "ended":
|
|
59
|
-
break
|
|
60
|
-
print(f"Status: {batch.processing_status}, processing: {batch.request_counts.processing}")
|
|
61
|
-
time.sleep(60)
|
|
62
|
-
|
|
63
|
-
print("Batch complete!")
|
|
64
|
-
print(f"Succeeded: {batch.request_counts.succeeded}")
|
|
65
|
-
print(f"Errored: {batch.request_counts.errored}")
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## Retrieve Results
|
|
71
|
-
|
|
72
|
-
> **Note:** Examples below use `match/case` syntax, requiring Python 3.10+. For earlier versions, use `if/elif` chains instead.
|
|
73
|
-
|
|
74
|
-
```python
|
|
75
|
-
for result in client.messages.batches.results(message_batch.id):
|
|
76
|
-
match result.result.type:
|
|
77
|
-
case "succeeded":
|
|
78
|
-
msg = result.result.message
|
|
79
|
-
text = next((b.text for b in msg.content if b.type == "text"), "")
|
|
80
|
-
print(f"[{result.custom_id}] {text[:100]}")
|
|
81
|
-
case "errored":
|
|
82
|
-
if result.result.error.type == "invalid_request":
|
|
83
|
-
print(f"[{result.custom_id}] Validation error - fix request and retry")
|
|
84
|
-
else:
|
|
85
|
-
print(f"[{result.custom_id}] Server error - safe to retry")
|
|
86
|
-
case "canceled":
|
|
87
|
-
print(f"[{result.custom_id}] Canceled")
|
|
88
|
-
case "expired":
|
|
89
|
-
print(f"[{result.custom_id}] Expired - resubmit")
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## Cancel a Batch
|
|
95
|
-
|
|
96
|
-
```python
|
|
97
|
-
cancelled = client.messages.batches.cancel(message_batch.id)
|
|
98
|
-
print(f"Status: {cancelled.processing_status}") # "canceling"
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## List Batches (auto-pagination)
|
|
104
|
-
|
|
105
|
-
Iterating the return value of any `list()` call auto-paginates across all pages - do not index into `.data` if you want the full set:
|
|
106
|
-
|
|
107
|
-
```python
|
|
108
|
-
for batch in client.messages.batches.list(limit=20):
|
|
109
|
-
print(batch.id, batch.processing_status)
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
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.
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## Batch with Prompt Caching
|
|
117
|
-
|
|
118
|
-
```python
|
|
119
|
-
shared_system = [
|
|
120
|
-
{"type": "text", "text": "You are a literary analyst."},
|
|
121
|
-
{
|
|
122
|
-
"type": "text",
|
|
123
|
-
"text": large_document_text, # Shared across all requests
|
|
124
|
-
"cache_control": {"type": "ephemeral"}
|
|
125
|
-
}
|
|
126
|
-
]
|
|
127
|
-
|
|
128
|
-
message_batch = client.messages.batches.create(
|
|
129
|
-
requests=[
|
|
130
|
-
Request(
|
|
131
|
-
custom_id=f"analysis-{i}",
|
|
132
|
-
params=MessageCreateParamsNonStreaming(
|
|
133
|
-
model="claude-opus-5",
|
|
134
|
-
max_tokens=16000,
|
|
135
|
-
system=shared_system,
|
|
136
|
-
messages=[{"role": "user", "content": question}]
|
|
137
|
-
)
|
|
138
|
-
)
|
|
139
|
-
for i, question in enumerate(questions)
|
|
140
|
-
]
|
|
141
|
-
)
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## Full End-to-End Example
|
|
147
|
-
|
|
148
|
-
```python
|
|
149
|
-
import anthropic
|
|
150
|
-
import time
|
|
151
|
-
from anthropic.types.message_create_params import MessageCreateParamsNonStreaming
|
|
152
|
-
from anthropic.types.messages.batch_create_params import Request
|
|
153
|
-
|
|
154
|
-
client = anthropic.Anthropic()
|
|
155
|
-
|
|
156
|
-
# 1. Prepare requests
|
|
157
|
-
items_to_classify = [
|
|
158
|
-
"The product quality is excellent!",
|
|
159
|
-
"Terrible customer service, never again.",
|
|
160
|
-
"It's okay, nothing special.",
|
|
161
|
-
]
|
|
162
|
-
|
|
163
|
-
requests = [
|
|
164
|
-
Request(
|
|
165
|
-
custom_id=f"classify-{i}",
|
|
166
|
-
params=MessageCreateParamsNonStreaming(
|
|
167
|
-
model="claude-haiku-4-5",
|
|
168
|
-
max_tokens=50,
|
|
169
|
-
messages=[{
|
|
170
|
-
"role": "user",
|
|
171
|
-
"content": f"Classify as positive/negative/neutral (one word): {text}"
|
|
172
|
-
}]
|
|
173
|
-
)
|
|
174
|
-
)
|
|
175
|
-
for i, text in enumerate(items_to_classify)
|
|
176
|
-
]
|
|
177
|
-
|
|
178
|
-
# 2. Create batch
|
|
179
|
-
batch = client.messages.batches.create(requests=requests)
|
|
180
|
-
print(f"Created batch: {batch.id}")
|
|
181
|
-
|
|
182
|
-
# 3. Wait for completion
|
|
183
|
-
while True:
|
|
184
|
-
batch = client.messages.batches.retrieve(batch.id)
|
|
185
|
-
if batch.processing_status == "ended":
|
|
186
|
-
break
|
|
187
|
-
time.sleep(10)
|
|
188
|
-
|
|
189
|
-
# 4. Collect results
|
|
190
|
-
results = {}
|
|
191
|
-
for result in client.messages.batches.results(batch.id):
|
|
192
|
-
if result.result.type == "succeeded":
|
|
193
|
-
msg = result.result.message
|
|
194
|
-
results[result.custom_id] = next((b.text for b in msg.content if b.type == "text"), "")
|
|
195
|
-
|
|
196
|
-
for custom_id, classification in sorted(results.items()):
|
|
197
|
-
print(f"{custom_id}: {classification}")
|
|
198
|
-
```
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
# Files API - Python
|
|
2
|
-
|
|
3
|
-
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.
|
|
4
|
-
|
|
5
|
-
The Files API is out of beta. In current SDKs `client.beta.files` has breaking shape changes from previous versions, matching the stable `client.files` - migrate per the Files API row in `shared/live-sources.md`. Examples below predate this.
|
|
6
|
-
|
|
7
|
-
## Key Facts
|
|
8
|
-
|
|
9
|
-
- Maximum file size: 500 MB
|
|
10
|
-
- Total storage: 100 GB per organization
|
|
11
|
-
- Files persist until deleted
|
|
12
|
-
- File operations (upload, list, delete) are free; content used in messages is billed as input tokens
|
|
13
|
-
- Not available on Amazon Bedrock or Google Vertex AI
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Upload a File
|
|
18
|
-
|
|
19
|
-
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.
|
|
20
|
-
|
|
21
|
-
```python
|
|
22
|
-
import anthropic
|
|
23
|
-
from pathlib import Path
|
|
24
|
-
|
|
25
|
-
client = anthropic.Anthropic()
|
|
26
|
-
|
|
27
|
-
uploaded = client.beta.files.upload(
|
|
28
|
-
file=("report.pdf", open("report.pdf", "rb"), "application/pdf"),
|
|
29
|
-
)
|
|
30
|
-
# or: client.beta.files.upload(file=Path("report.pdf"))
|
|
31
|
-
print(f"File ID: {uploaded.id}")
|
|
32
|
-
print(f"Size: {uploaded.size_bytes} bytes")
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## Use a File in Messages
|
|
38
|
-
|
|
39
|
-
### PDF / Text Document
|
|
40
|
-
|
|
41
|
-
```python
|
|
42
|
-
response = client.beta.messages.create(
|
|
43
|
-
model="claude-opus-5",
|
|
44
|
-
max_tokens=16000,
|
|
45
|
-
messages=[{
|
|
46
|
-
"role": "user",
|
|
47
|
-
"content": [
|
|
48
|
-
{"type": "text", "text": "Summarize the key findings in this report."},
|
|
49
|
-
{
|
|
50
|
-
"type": "document",
|
|
51
|
-
"source": {"type": "file", "file_id": uploaded.id},
|
|
52
|
-
"title": "Q4 Report", # optional
|
|
53
|
-
"citations": {"enabled": True} # optional, enables citations
|
|
54
|
-
}
|
|
55
|
-
]
|
|
56
|
-
}],
|
|
57
|
-
betas=["files-api-2025-04-14"],
|
|
58
|
-
)
|
|
59
|
-
for block in response.content:
|
|
60
|
-
if block.type == "text":
|
|
61
|
-
print(block.text)
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Image
|
|
65
|
-
|
|
66
|
-
```python
|
|
67
|
-
image_file = client.beta.files.upload(
|
|
68
|
-
file=("photo.png", open("photo.png", "rb"), "image/png"),
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
response = client.beta.messages.create(
|
|
72
|
-
model="claude-opus-5",
|
|
73
|
-
max_tokens=16000,
|
|
74
|
-
messages=[{
|
|
75
|
-
"role": "user",
|
|
76
|
-
"content": [
|
|
77
|
-
{"type": "text", "text": "What's in this image?"},
|
|
78
|
-
{
|
|
79
|
-
"type": "image",
|
|
80
|
-
"source": {"type": "file", "file_id": image_file.id}
|
|
81
|
-
}
|
|
82
|
-
]
|
|
83
|
-
}],
|
|
84
|
-
betas=["files-api-2025-04-14"],
|
|
85
|
-
)
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## Manage Files
|
|
91
|
-
|
|
92
|
-
### List Files
|
|
93
|
-
|
|
94
|
-
Iterate the list result directly - the SDK auto-paginates across all pages. Only use `.data` if you want the first page only.
|
|
95
|
-
|
|
96
|
-
```python
|
|
97
|
-
for f in client.beta.files.list():
|
|
98
|
-
print(f"{f.id}: {f.filename} ({f.size_bytes} bytes)")
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Get File Metadata
|
|
102
|
-
|
|
103
|
-
```python
|
|
104
|
-
file_info = client.beta.files.retrieve_metadata("file_011CNha8iCJcU1wXNR6q4V8w")
|
|
105
|
-
print(f"Filename: {file_info.filename}")
|
|
106
|
-
print(f"MIME type: {file_info.mime_type}")
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Delete a File
|
|
110
|
-
|
|
111
|
-
```python
|
|
112
|
-
client.beta.files.delete("file_011CNha8iCJcU1wXNR6q4V8w")
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Download a File
|
|
116
|
-
|
|
117
|
-
Only files created by the code execution tool or skills can be downloaded (not user-uploaded files).
|
|
118
|
-
|
|
119
|
-
```python
|
|
120
|
-
file_content = client.beta.files.download("file_011CNha8iCJcU1wXNR6q4V8w")
|
|
121
|
-
file_content.write_to_file("output.txt")
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## Full End-to-End Example
|
|
127
|
-
|
|
128
|
-
Upload a document once, ask multiple questions about it:
|
|
129
|
-
|
|
130
|
-
```python
|
|
131
|
-
import anthropic
|
|
132
|
-
|
|
133
|
-
client = anthropic.Anthropic()
|
|
134
|
-
|
|
135
|
-
# 1. Upload once
|
|
136
|
-
uploaded = client.beta.files.upload(
|
|
137
|
-
file=("contract.pdf", open("contract.pdf", "rb"), "application/pdf"),
|
|
138
|
-
)
|
|
139
|
-
print(f"Uploaded: {uploaded.id}")
|
|
140
|
-
|
|
141
|
-
# 2. Ask multiple questions using the same file_id
|
|
142
|
-
questions = [
|
|
143
|
-
"What are the key terms and conditions?",
|
|
144
|
-
"What is the termination clause?",
|
|
145
|
-
"Summarize the payment schedule.",
|
|
146
|
-
]
|
|
147
|
-
|
|
148
|
-
for question in questions:
|
|
149
|
-
response = client.beta.messages.create(
|
|
150
|
-
model="claude-opus-5",
|
|
151
|
-
max_tokens=16000,
|
|
152
|
-
messages=[{
|
|
153
|
-
"role": "user",
|
|
154
|
-
"content": [
|
|
155
|
-
{"type": "text", "text": question},
|
|
156
|
-
{
|
|
157
|
-
"type": "document",
|
|
158
|
-
"source": {"type": "file", "file_id": uploaded.id}
|
|
159
|
-
}
|
|
160
|
-
]
|
|
161
|
-
}],
|
|
162
|
-
betas=["files-api-2025-04-14"],
|
|
163
|
-
)
|
|
164
|
-
print(f"\nQ: {question}")
|
|
165
|
-
text = next((b.text for b in response.content if b.type == "text"), "")
|
|
166
|
-
print(f"A: {text[:200]}")
|
|
167
|
-
|
|
168
|
-
# 3. Clean up when done
|
|
169
|
-
client.beta.files.delete(uploaded.id)
|
|
170
|
-
```
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
# Upgrading the `anthropic` Python SDK: 0.x -> 1.x
|
|
2
|
-
|
|
3
|
-
> **If you arrived via `/claude-api upgrade`:** this is the right file. Execute the steps below in order - do not summarize them back to the user. Start with Step 0 before touching any file.
|
|
4
|
-
|
|
5
|
-
`anthropic` 1.x is deliberately a small step from the last 0.x release: no method was restructured and no new pattern is required. Long-deprecated surface was removed, the HTTP layer moved from `httpx` to its maintained fork `httpx2`, and the minimum Python version is now 3.10. Almost every required edit is mechanical, and a type checker flags nearly all of them once 1.x is installed - which makes `pyright` / `mypy` output a good cross-check for the inventory below.
|
|
6
|
-
|
|
7
|
-
The SDK repository's `MIGRATION.md` is the authoritative change list - WebFetch it (URL in `shared/live-sources.md` -> SDK major-version upgrade guides) when you can, and if it disagrees with this file, follow `MIGRATION.md` and say so in your report. The other Python files in this skill may still show 0.x-era details; for a project on 1.x, this file takes precedence.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Step 0: Confirm scope, current version, and target
|
|
13
|
-
|
|
14
|
-
**Scope - ask before editing unless it is already unambiguous.** Same rule as model migration: if the request does not name an exact file, a specific directory, or an explicit file list, ask one question offering (1) the whole working directory, (2) a specific subdirectory, (3) specific files - and wait. `upgrade`, `upgrade python`, "move my project to anthropic v1" are all scope-ambiguous. A trailing path in the subcommand (`upgrade python src/`) is a scope. Dependency manifests and lockfiles at the project root (`pyproject.toml`, `requirements*.txt`, `setup.py`/`setup.cfg`, `Pipfile`, `uv.lock`, `poetry.lock`) count as in scope whenever any code under them is - say so when you confirm the scope.
|
|
15
|
-
|
|
16
|
-
**Current version.** Read the declared requirement (`anthropic...` in the manifests above) and, if a project environment is available, the installed one (`python -c "import anthropic; print(anthropic.__version__)"`). If the project is already on 1.x, skip the dependency bump and treat this as a call-site cleanup. If nothing in scope declares the dependency (a bare scripts directory, or `anthropic` arrives transitively), don't invent a manifest - upgrade the code and put the install command in the report.
|
|
17
|
-
|
|
18
|
-
**Target version.** Before writing any pin, confirm a 1.x release is actually published: `pip index versions anthropic` (or `curl -s https://pypi.org/pypi/anthropic/json` and read `info.version`). Use the newest 1.x you find. If no 1.x release exists yet, stop and tell the user - do not write an uninstallable requirement. If you cannot check (no network), proceed with `>=1,<2` and list the unverified pin in your report.
|
|
19
|
-
|
|
20
|
-
If the scope is under git, check `git status` before editing - unexpected modifications mean a concurrent process; stop and investigate before proceeding.
|
|
21
|
-
|
|
22
|
-
## Step 1: Inventory the call sites
|
|
23
|
-
|
|
24
|
-
Search the scope for each signal below (`rg -n -F` for the literal strings; exclude virtualenvs, `.git`, build output and vendored code) and keep the hit list - it is your checklist and, re-run at the end, your verification.
|
|
25
|
-
|
|
26
|
-
| Signal | What it finds | Section |
|
|
27
|
-
|---|---|---|
|
|
28
|
-
| `requires-python`, `python_requires`, `python-version`, `py39`, `3.9` in manifests, CI config, `tox.ini`, `noxfile.py`, `.python-version`, `Dockerfile` | a Python 3.9 floor | Step 2 |
|
|
29
|
-
| `anthropic` entries in manifests / lockfiles; `httpx-aiohttp`, `httpx_aiohttp` | the pins to change | Step 2 |
|
|
30
|
-
| `import httpx`, `from httpx` | modules that may hand `httpx` objects to the SDK | Step 3 |
|
|
31
|
-
| `respx`, `pytest_httpx` / `httpx_mock`, `vcr`, `MockTransport`; `HTTPXClientInstrumentor` / `opentelemetry.instrumentation.httpx`, `HttpxIntegration` (Sentry) | HTTP mocking and tracing / APM instrumentation that patch `httpx` and silently stop seeing SDK traffic | Step 3 |
|
|
32
|
-
| `with_raw_response` | raw-response call sites | Step 4 |
|
|
33
|
-
| `LegacyAPIResponse`, `_legacy_response` | annotations / imports of the removed class | Step 4 |
|
|
34
|
-
| `completions.create`, `HUMAN_PROMPT`, `AI_PROMPT`, `max_tokens_to_sample` | the removed Text Completions API | Step 5 |
|
|
35
|
-
| `temperature`, `top_p`, `top_k` (keyword arguments and quoted dict keys) | removed sampling parameters - only hits that feed Anthropic SDK calls count | Step 6 |
|
|
36
|
-
| `output_format` | raw `output_format={...}` dicts vs the unchanged `output_format=Model` helper argument | Step 6 |
|
|
37
|
-
| `BetaBase64PDFBlockParam`, `READ_MAX_BYTES`, `ProxiesTypes` / `Transport` imported from `anthropic`, `AsyncTransport` / `ProxiesDict` imported from `anthropic._types` | renamed / removed exports | Step 7 |
|
|
38
|
-
| `.parse(` calls that pass `stream=` | `messages.parse(stream=...)` | Step 8 |
|
|
39
|
-
| `compaction_control` | client-side tool-runner compaction | Step 8 |
|
|
40
|
-
| `body=` on `client.get` / `post` / `put` / `patch` / `delete` calls whose value is `bytes` (`b"..."`, `.encode()`, a bytes variable) | raw bytes passed as `body=` | Step 8 |
|
|
41
|
-
| `isinstance(` checks against `Stream` / `AsyncStream` | checks aimed at message streams | Step 8 |
|
|
42
|
-
| `default_headers`, `extra_headers`, `ANTHROPIC_CUSTOM_HEADERS` | header maps to check for duplicate casings / `bytes` values | Step 9 |
|
|
43
|
-
| `AnthropicBedrock(`, `AsyncAnthropicBedrock(` | Bedrock clients that may rely on the old region fallback | Step 10 |
|
|
44
|
-
|
|
45
|
-
Classify each hit before editing: **SDK call site** (edit), **unrelated use of the same name** (leave - e.g. `httpx` calls to other services, `urllib.parse`, a pydantic `.parse_obj`, a `temperature` variable for a thermostat), **test** (edit, and keep the test meaningful), **docs / README snippet or notebook inside the scope** (edit - for `.ipynb`, the greps match inside the JSON cell sources; edit the source strings, `%pip install` lines included, and keep the JSON valid). Never touch installed packages or vendored third-party code.
|
|
46
|
-
|
|
47
|
-
## Step 2: Environment - Python >= 3.10 and the dependency pins
|
|
48
|
-
|
|
49
|
-
- **[DECIDE] Python floor.** 1.x requires Python 3.10+. If the project still declares or tests 3.9 (`requires-python = ">=3.9"`, trove classifiers, a `3.9` CI matrix entry, tox/nox envs, a `python:3.9` base image), that is the user's decision, not a silent edit: propose the floor bump and the CI-matrix change as their own hunk and call it out in the report. On 3.9, `pip` simply keeps resolving the last 0.x release, so nothing breaks until they move.
|
|
50
|
-
- **[BREAKS] The `anthropic` requirement.** Rewrite it in the file's existing style - `anthropic>=1,<2` for a range, `anthropic~=1.0` / Poetry `^1.0` for compatible-release styles, `anthropic==<latest 1.x from Step 0>` where the project pins exactly. Extras (`anthropic[bedrock]`, `[vertex]`, `[aiohttp]`) are unchanged. Regenerate the lockfile with the project's own tool (`uv lock`, `poetry lock`, `pip-compile`, `pipenv lock`) if you can run it; otherwise give the user the exact command.
|
|
51
|
-
- **`httpx-aiohttp`.** If it is pinned only so `DefaultAioHttpClient()` works, remove it - the aiohttp transport now ships inside the SDK and the `aiohttp` extra installs only `aiohttp`.
|
|
52
|
-
- **`httpx2` / `httpx`.** After Step 3, if any project module imports `httpx2` directly, add `httpx2` to the declared dependencies (it arrives transitively with `anthropic`, but direct imports should be declared). `httpx2` has its own version line starting at 2.0 - write `httpx2>=2.0` (or match what `anthropic` resolved: `pip index versions httpx2`), never a specifier copied from the old `httpx` pin such as `>=0.27`. Keep `httpx` declared only if the project still uses it for something other than the SDK.
|
|
53
|
-
|
|
54
|
-
Pydantic v1 and v2 both remain supported; nothing else about the environment changes.
|
|
55
|
-
|
|
56
|
-
## Step 3: `httpx` -> `httpx2`, only where objects cross the SDK boundary
|
|
57
|
-
|
|
58
|
-
`httpx2` is the API-compatible, maintained fork of `httpx` (same classes, same behaviour). The change only matters for `httpx` objects handed **to** the SDK or received **from** it; plain values (`timeout=30.0`, `max_retries=3`) need nothing.
|
|
59
|
-
|
|
60
|
-
- **[BREAKS] Objects passed in.** `httpx.Timeout`, `httpx.Limits`, transports (`httpx.HTTPTransport(...)`, `AsyncHTTPTransport`, `MockTransport`), and whole clients (`httpx.Client` / `AsyncClient` as `http_client=`) must come from `httpx2`. An old-`httpx` client passed as `http_client=` raises `TypeError` at construction. This includes the project's own middleware, not just the outermost object handed to `Anthropic(...)`: a `class TracingTransport(httpx.BaseTransport)` subclass, the inner `httpx.HTTPTransport()` a wrapper delegates to, an `httpx.Auth` flow, and the annotations on `event_hooks` callables all re-base onto `httpx2` - a wrapper left delegating to an old-`httpx` transport hands the SDK `httpx.Response` objects. If the module uses `httpx` only for the SDK, alias the import (`import httpx2 as httpx`) and nothing else changes; if it also talks to other services with `httpx`, import both and switch only the SDK-bound objects to `httpx2`. Prefer the SDK's own re-exports where they let you drop the import entirely: `anthropic.Timeout`, `anthropic.DefaultHttpxClient`, `anthropic.DefaultAsyncHttpxClient`, `anthropic.DefaultAioHttpClient` (all already `httpx2`-based, all unchanged).
|
|
61
|
-
|
|
62
|
-
```python
|
|
63
|
-
# Before
|
|
64
|
-
import httpx
|
|
65
|
-
from anthropic import Anthropic, DefaultHttpxClient
|
|
66
|
-
|
|
67
|
-
client = Anthropic(
|
|
68
|
-
timeout=httpx.Timeout(60.0, connect=5.0),
|
|
69
|
-
http_client=DefaultHttpxClient(proxy="http://proxy.example", transport=httpx.HTTPTransport(retries=1)),
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
# After
|
|
73
|
-
import httpx2 as httpx
|
|
74
|
-
from anthropic import Anthropic, DefaultHttpxClient
|
|
75
|
-
|
|
76
|
-
client = Anthropic(
|
|
77
|
-
timeout=httpx.Timeout(60.0, connect=5.0),
|
|
78
|
-
http_client=DefaultHttpxClient(proxy="http://proxy.example", transport=httpx.HTTPTransport(retries=1)),
|
|
79
|
-
)
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
- **[DECIDE] Or alias process-wide, for applications.** `httpx2.alias_httpx()` makes `import httpx` / `import httpcore` resolve to `httpx2` / `httpcore2` for the whole process, so nothing else needs editing. Reach for it instead of the import edits when the scope is an **application** that shares clients, transports or exception types between the SDK and other `httpx` code, or that relies on tooling which patches `httpx` itself (tracing / APM instrumentation, HTTP mocking - see **Instrumentation and tests** below). Two hard rules: it must run before anything imports `httpx` or `httpcore` (otherwise it raises `RuntimeError`; calling it twice is a no-op), so it goes at the very top of the entry point; and it is for applications only - never add it to a **library's** import path on behalf of that library's users (edit the imports there instead). Say which you chose and why in the report.
|
|
83
|
-
|
|
84
|
-
```python
|
|
85
|
-
# the very first lines of the application's entry point
|
|
86
|
-
import httpx2
|
|
87
|
-
|
|
88
|
-
httpx2.alias_httpx()
|
|
89
|
-
|
|
90
|
-
import httpx # now the httpx2 module: httpx.Client is httpx2.Client
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
- **[BREAKS] Objects coming out.** `APIStatusError.response`, `APIConnectionError.request`, `.http_response` / `.headers` / `.url` on raw and streaming responses, the `request` / `response` arguments your `http_client` event hooks receive, and `cast_to=httpx.Response` on the low-level `client.get/post/...` methods are now `httpx2` types with identical attributes. Only `isinstance` checks and annotations naming `httpx.Response` / `httpx.Request` / `httpx.Headers` / `httpx.URL` change (`httpx2.Response`, ...).
|
|
94
|
-
- **Removed re-exports.** `anthropic.Transport` and `anthropic.ProxiesTypes` (and `AsyncTransport` / `ProxiesDict` from `anthropic._types`) are gone; use `httpx2.BaseTransport`, `httpx2.AsyncBaseTransport`, `httpx2.Proxy` (or a proxy URL string).
|
|
95
|
-
- **Instrumentation and tests.** Libraries that observe or stub HTTP by patching `httpx` - OpenTelemetry's `HTTPXClientInstrumentor`, Sentry's `httpx` integration, `respx`, `pytest-httpx`, `vcrpy` - keep importing fine but silently stop seeing the SDK's requests, so nothing fails loudly. The fix is the same `httpx2.alias_httpx()` call - not swapping in some `*-httpx2` instrumentation package (verify any such name is a real, populated release before depending on it) - made before any of them (or `httpx`) is imported: at the top of the application entry point for instrumentation, and under pytest as an early plugin so it runs before `respx` / `pytest-httpx` and the test modules load:
|
|
96
|
-
|
|
97
|
-
```python
|
|
98
|
-
# tests/_alias_httpx.py
|
|
99
|
-
import httpx2
|
|
100
|
-
|
|
101
|
-
httpx2.alias_httpx() # `import httpx` / `import httpcore` now resolve to httpx2 / httpcore2
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
```toml
|
|
105
|
-
# pyproject.toml
|
|
106
|
-
[tool.pytest.ini_options]
|
|
107
|
-
addopts = "-p tests._alias_httpx"
|
|
108
|
-
pythonpath = ["."]
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Merge into an existing `addopts` rather than replacing it (`pytest.ini` / `setup.cfg` / `tox.ini` equivalents work the same way). Transport-level fakes (`httpx2.Client(transport=httpx2.MockTransport(handler))`, a handler typed `httpx2.Request -> httpx2.Response`) only need the import swap.
|
|
112
|
-
|
|
113
|
-
## Step 4: `.with_raw_response` returns `APIResponse` / `AsyncAPIResponse`
|
|
114
|
-
|
|
115
|
-
`.with_raw_response` used to return `LegacyAPIResponse` on both clients; it now returns the same classes `.with_streaming_response` already used. Two consequences:
|
|
116
|
-
|
|
117
|
-
- **[BREAKS] On async clients, reading the body is awaited** - `parse()`, `json()`, `text()`, `read()` are coroutines. Decide sync vs async from the client the accessor hangs off (`AsyncAnthropic` and the other `Async*` platform clients) or an `await` on the `.with_raw_response...(...)` call itself - not from the enclosing function alone.
|
|
118
|
-
- **[BREAKS] `.text` and `.content` are methods now, on the sync client too:** `.text` -> `.text()`, `.content` -> `.read()`. The new classes also expose `json()` and the `iter_bytes()` / `iter_text()` / `iter_lines()` iterators directly; 0.x code reached those through `r.http_response`, which still works and need not be rewritten.
|
|
119
|
-
|
|
120
|
-
| 0.x (`LegacyAPIResponse`) | 1.x sync (`APIResponse`) | 1.x async (`AsyncAPIResponse`) |
|
|
121
|
-
|---|---|---|
|
|
122
|
-
| `r.parse()` | `r.parse()` | `await r.parse()` |
|
|
123
|
-
| `r.text` | `r.text()` | `await r.text()` |
|
|
124
|
-
| `r.content` | `r.read()` | `await r.read()` |
|
|
125
|
-
| - (only `r.http_response.json()`) | `r.json()` | `await r.json()` |
|
|
126
|
-
| - (only `r.http_response.iter_bytes()` ...) | `r.iter_bytes()` / `.iter_text()` / `.iter_lines()` | `async for chunk in r.iter_bytes():` ... |
|
|
127
|
-
| `.headers`, `.status_code`, `.url`, `.request_id`, `.retries_taken`, `.http_response`, `.elapsed` | unchanged | unchanged (plain attributes - never awaited) |
|
|
128
|
-
|
|
129
|
-
```python
|
|
130
|
-
# Before (async client)
|
|
131
|
-
raw = await client.messages.with_raw_response.create(...)
|
|
132
|
-
print(raw.headers["request-id"], raw.text)
|
|
133
|
-
message = raw.parse()
|
|
134
|
-
|
|
135
|
-
# After
|
|
136
|
-
raw = await client.messages.with_raw_response.create(...)
|
|
137
|
-
print(raw.headers["request-id"], await raw.text())
|
|
138
|
-
message = await raw.parse()
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Anchor every edit on a value that demonstrably comes from a `.with_raw_response.` call (follow it through variables, return values and fixtures); do not touch `.parse()` / `.text` on unrelated objects, and do not double-await. Annotations and imports of `anthropic._legacy_response.LegacyAPIResponse` become `anthropic.APIResponse` / `anthropic.AsyncAPIResponse`. `.with_streaming_response` code is unchanged.
|
|
142
|
-
|
|
143
|
-
## Step 5: Text Completions -> Messages (the one non-mechanical change)
|
|
144
|
-
|
|
145
|
-
**[BREAKS]** `client.completions.create()` (`/v1/complete`), the `Completion` types, and the `anthropic.HUMAN_PROMPT` / `anthropic.AI_PROMPT` constants are removed (also from `AnthropicBedrock`). Port each call to `client.messages.create()`:
|
|
146
|
-
|
|
147
|
-
- the `f"{HUMAN_PROMPT} ...{AI_PROMPT}"` prompt string becomes `messages=[{"role": "user", "content": "..."}]`; text that preceded the first `HUMAN_PROMPT` as instructions becomes `system=`; alternating `HUMAN_PROMPT`/`AI_PROMPT` turns become alternating `user`/`assistant` messages;
|
|
148
|
-
- `max_tokens_to_sample=` -> `max_tokens=`; `stop_sequences=` carries over; drop `temperature`/`top_p`/`top_k` (Step 6);
|
|
149
|
-
- `completion.completion` -> the text blocks of `message.content` (`"".join(b.text for b in message.content if b.type == "text")`); `stop_reason` values carry over (`"stop_sequence"`, `"max_tokens"`), with `"end_turn"` as the new normal-completion value;
|
|
150
|
-
- `stream=True` completions -> `client.messages.stream(...)` and its `text_stream`.
|
|
151
|
-
|
|
152
|
-
```python
|
|
153
|
-
# Before
|
|
154
|
-
from anthropic import AI_PROMPT, HUMAN_PROMPT
|
|
155
|
-
|
|
156
|
-
completion = client.completions.create(
|
|
157
|
-
model="claude-2.1",
|
|
158
|
-
max_tokens_to_sample=256,
|
|
159
|
-
prompt=f"{HUMAN_PROMPT} Why is the sky blue?{AI_PROMPT}",
|
|
160
|
-
)
|
|
161
|
-
print(completion.completion)
|
|
162
|
-
|
|
163
|
-
# After
|
|
164
|
-
message = client.messages.create(
|
|
165
|
-
model="claude-opus-5",
|
|
166
|
-
max_tokens=256,
|
|
167
|
-
messages=[{"role": "user", "content": "Why is the sky blue?"}],
|
|
168
|
-
)
|
|
169
|
-
print("".join(block.text for block in message.content if block.type == "text"))
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
**[DECIDE] The model.** Code still on Text Completions usually pins a retired model (`claude-2.x`, `claude-instant-*`), which 404s regardless of SDK version. Keep a model that is still served; otherwise switch to `claude-opus-5` so the code runs, say so prominently in the report, and point the user at `/claude-api migrate` for validating prompts against the new model - a completions-era prompt is exactly what `shared/prompt-audit.md` exists for.
|
|
173
|
-
|
|
174
|
-
## Step 6: Removed request parameters
|
|
175
|
-
|
|
176
|
-
- **[BREAKS] `temperature`, `top_p`, `top_k`** are no longer accepted by `messages.create()` / `.stream()` / `.parse()`, their `beta.messages` counterparts, or `beta.messages.tool_runner()` (passing them is a `TypeError`), and are gone from the per-request `params` TypedDict of `messages.batches.create()` (a type checker flags the key; at runtime the SDK still forwards it). Delete them - they are gone from the 1.x signatures, not from the API, and whether a model still honours them is a model question (`shared/model-migration.md`): Opus 4.7 and later return a 400 for any request that carries one (the default value included), Claude Sonnet 5 rejects non-default values, and every still-served model before those accepts them - the Claude 4.6 / 4.5 line (Opus 4.6, Sonnet 4.6, Opus 4.5, Sonnet 4.5, Haiku 4.5) and the deprecated-but-still-served Claude 4 models (`shared/models.md` -> Deprecated Models). So **[DECIDE]** when the call pins one of those accepting models and visibly depends on the setting (a documented determinism requirement, an A/B on temperature), move it into `extra_body` instead of deleting it - `extra_body={"temperature": 0.2}` is merged into the request JSON as-is - and for a `messages.batches.create()` request leave the key in that request's `params` dict (it is forwarded, see above). A call that pins a retired model (`shared/models.md` -> Retired Models) is the `migrate` flow's problem first: it needs a replacement model, and the replacement decides whether the setting survives. Say which calls kept a setting this way in the report. When a test existed only to assert that these parameters pass through, keep it meaningful by asserting on parameters that still exist (`stop_sequences`, `metadata`, `service_tier`, `max_tokens`) rather than deleting it.
|
|
177
|
-
|
|
178
|
-
```python
|
|
179
|
-
# Before
|
|
180
|
-
client.messages.create(..., model="claude-sonnet-4-6", temperature=0.2)
|
|
181
|
-
|
|
182
|
-
# After (only when the pinned model accepts it and the code depends on it)
|
|
183
|
-
client.messages.create(..., model="claude-sonnet-4-6", extra_body={"temperature": 0.2})
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
- **[BREAKS] `output_format={...}` as a raw dict/TypedDict** - on `beta.messages.create()`, `beta.messages.count_tokens()` and batch params (where the parameter is gone) and on the `messages.stream()` / `messages.count_tokens()` / `beta.messages.stream()` helpers (which used to accept a dict as well and now raise `TypeError` for one) -> `output_config={"format": {...}}` (merge into an existing `output_config` if one is already passed, e.g. alongside `effort`). **Leave `output_format=SomeModel` alone** when the value is a *type* (a Pydantic model / class passed to the `parse()`, `stream()` or `tool_runner()` helpers, or to the non-beta `messages.count_tokens()`) - that is the one form the helpers still take (`beta.messages.count_tokens()` only ever took the dict form, and has no `output_format` at all now). Tell them apart by the value: dict literal / `{"type": "json_schema", ...}` -> migrate; a class name -> keep.
|
|
187
|
-
|
|
188
|
-
```python
|
|
189
|
-
# Before
|
|
190
|
-
client.beta.messages.create(..., temperature=0.2, output_format={"type": "json_schema", "schema": Order.model_json_schema()})
|
|
191
|
-
|
|
192
|
-
# After
|
|
193
|
-
client.beta.messages.create(..., output_config={"format": {"type": "json_schema", "schema": Order.model_json_schema()}})
|
|
194
|
-
# or, usually better: client.beta.messages.parse(..., output_format=Order)
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## Step 7: Renamed and removed names (pure renames)
|
|
198
|
-
|
|
199
|
-
**[BREAKS]** Replace imports and every reference; the replacement types are identical.
|
|
200
|
-
|
|
201
|
-
| Removed | Replacement |
|
|
202
|
-
|---|---|
|
|
203
|
-
| `anthropic.types.beta.BetaBase64PDFBlockParam` | `anthropic.types.beta.BetaRequestDocumentBlockParam` |
|
|
204
|
-
| `anthropic.Transport` / `anthropic.ProxiesTypes` (and `anthropic._types.AsyncTransport` / `ProxiesDict`) | `httpx2.BaseTransport` / `httpx2.Proxy` (`httpx2.AsyncBaseTransport`) |
|
|
205
|
-
| `anthropic.HUMAN_PROMPT` / `anthropic.AI_PROMPT` | none - Step 5 |
|
|
206
|
-
| `anthropic.lib.tools.agent_toolset.READ_MAX_BYTES` | `anthropic.lib.tools.agent_toolset.DEFAULT_MAX_FILE_BYTES` |
|
|
207
|
-
|
|
208
|
-
## Step 8: Removed helper arguments and behaviour
|
|
209
|
-
|
|
210
|
-
- **[BREAKS] `messages.parse(..., stream=True)`** (and `beta.messages.parse`): the argument is gone (it never streamed). Use the streaming helper, which supports the same structured-output types:
|
|
211
|
-
|
|
212
|
-
```python
|
|
213
|
-
# Before
|
|
214
|
-
result = client.messages.parse(..., output_format=Order, stream=True)
|
|
215
|
-
|
|
216
|
-
# After
|
|
217
|
-
with client.messages.stream(..., output_format=Order) as stream:
|
|
218
|
-
order = stream.get_final_message().parsed_output
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
A `parse(..., stream=False)` just loses the argument.
|
|
222
|
-
- **[BREAKS] `tool_runner(compaction_control=...)`** - client-side compaction is removed in favour of server-side compaction. Carry the old `context_token_threshold` over as the trigger value (the API minimum is 50,000; raise smaller values to that and mention it):
|
|
223
|
-
|
|
224
|
-
```python
|
|
225
|
-
# Before
|
|
226
|
-
runner = client.beta.messages.tool_runner(..., compaction_control={"enabled": True, "context_token_threshold": 100_000})
|
|
227
|
-
|
|
228
|
-
# After
|
|
229
|
-
runner = client.beta.messages.tool_runner(
|
|
230
|
-
...,
|
|
231
|
-
betas=["compact-2026-01-12"],
|
|
232
|
-
context_management={"edits": [{"type": "compact_20260112", "trigger": {"type": "input_tokens", "value": 100_000}}]},
|
|
233
|
-
)
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
If the loop around the runner rebuilds `messages` itself, make sure it appends the full `message.content` (compaction blocks included) - see the Compaction section of `python/claude-api/README.md`.
|
|
237
|
-
- **[BREAKS] Raw `bytes` as `body=`** on `client.get/post/put/patch/delete`: `body=` is always JSON-serialised now; raw payloads (and iterators, for streaming uploads) go through `content=`:
|
|
238
|
-
|
|
239
|
-
```python
|
|
240
|
-
# Before
|
|
241
|
-
client.post("/v1/example", body=b"raw payload", cast_to=httpx.Response)
|
|
242
|
-
|
|
243
|
-
# After
|
|
244
|
-
client.post("/v1/example", content=b"raw payload", cast_to=httpx2.Response)
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
- **[BREAKS] `isinstance(x, anthropic.Stream)` / `AsyncStream` meant to match `client.messages.stream()` objects** now returns `False` (the compatibility shim and its `DeprecationWarning` are gone). Check for `anthropic.lib.streaming.MessageStream` / `AsyncMessageStream` instead; keep `Stream` only where the value really is a raw `create(stream=True)` stream.
|
|
248
|
-
|
|
249
|
-
## Step 9: Header names are matched case-insensitively
|
|
250
|
-
|
|
251
|
-
Usually nothing to edit. The SDK now merges `default_headers`, `extra_headers`, `with_options(default_headers=...)` and `ANTHROPIC_CUSTOM_HEADERS` case-insensitively: a later entry replaces an earlier header of the same name whatever its casing (including headers the SDK sets itself), and `omit` removes one the same way. Scan the Step 1 hits for two things and fix only those: **[DECIDE]** the same header name spelled with two casings where the code relied on both lines being sent (send one comma-joined value instead), and **[BREAKS]** `bytes` header values, which now raise - `.decode()` them.
|
|
252
|
-
|
|
253
|
-
## Step 10: Bedrock - a region is required
|
|
254
|
-
|
|
255
|
-
**[DECIDE]** `AnthropicBedrock()` / `AsyncAnthropicBedrock()` used to warn and fall back to `us-east-1` when no region was configured; they now raise `ValueError` at construction. Resolution order: `aws_region=` -> `AWS_REGION` / `AWS_DEFAULT_REGION` -> the region configured for the boto3 session / `aws_profile` (the profile is now honoured for region lookup). For each construction without `aws_region=`, check whether the deployment provides a region (env files, Dockerfiles, deployment manifests, AWS profile config in the repo). If it demonstrably does, nothing to do; if you cannot tell, do **not** invent a region - list the call site in the report as needing `aws_region=` or `AWS_REGION`, and only hardcode `"us-east-1"` if the user confirms that the old implicit default is what they were actually using.
|
|
256
|
-
|
|
257
|
-
Streaming from Bedrock also changes: event types the SDK does not know are now skipped instead of yielded - the only known case is the `amazon-bedrock-invocationMetrics` frame. Code that filtered those frames out can be deleted; code that *consumed* invocation metrics loses them on 1.x - **[DECIDE]** list it in the report (the SDK asks such users to open an issue).
|
|
258
|
-
|
|
259
|
-
## Step 11: Verify
|
|
260
|
-
|
|
261
|
-
1. Re-run the Step 1 greps over the scope. Every remaining hit needs a reason (unrelated `httpx` use, `Raw*` names, helper `output_format=Model`, ...) - put the reasons in the report.
|
|
262
|
-
2. `python -m compileall -q <scope>` must pass. If the project has a type checker configured, run it - nearly every missed call site is a type error on 1.x. Run the test suite if it is runnable without credentials.
|
|
263
|
-
3. If 1.x is installed in the environment: `python -c "import anthropic, httpx2; print(anthropic.__version__)"`.
|
|
264
|
-
|
|
265
|
-
## Step 12: Report
|
|
266
|
-
|
|
267
|
-
Lead with the outcome, then:
|
|
268
|
-
|
|
269
|
-
- what changed, grouped by the steps above, with file counts and the notable files;
|
|
270
|
-
- **decisions the user owns** - Python floor / CI matrix (Step 2), import edits vs `alias_httpx()` (Step 3), sampling-parameter reliance (Step 6), the model chosen for ported completions calls (Step 5), duplicate-casing headers (Step 9), Bedrock regions and invocation metrics (Step 10);
|
|
271
|
-
- if you introduced `httpx2` anywhere, one provenance line, because reviewers and supply-chain scanners flag unfamiliar package names as possible typosquats: it is the SDK's own HTTP dependency, the maintained fork of `httpx` by its original author, published by Pydantic (`github.com/pydantic/httpx2`), version line 2.x;
|
|
272
|
-
- what you could not verify (offline PyPI check, no type checker, tests not runnable, pre-commit hooks that need the new packages installed) and the exact commands to finish: the install / lock command and, if relevant, `pip uninstall httpx-aiohttp`.
|
|
273
|
-
|
|
274
|
-
## Checklist
|
|
275
|
-
|
|
276
|
-
- [ ] **[BREAKS]** `anthropic` requirement moved to 1.x in the project's pin style; lockfile regenerated or command given
|
|
277
|
-
- [ ] **[DECIDE]** Python >= 3.10 floor and CI matrix proposed as a separate hunk
|
|
278
|
-
- [ ] **[BREAKS]** `httpx` objects passed to / received from the SDK (custom transports, auth flows and event hooks included) come from `httpx2` - or **[DECIDE]** `httpx2.alias_httpx()` at the top of an application entry point; `httpx`-patching instrumentation / mocking (`respx`, `pytest-httpx`, `vcrpy`, OpenTelemetry, Sentry) covered by the alias; `httpx-aiohttp` dropped; `httpx2>=2.0` declared if imported
|
|
279
|
-
- [ ] **[BREAKS]** async `.with_raw_response`: `await` on `parse()/json()/text()/read()`; `.text` -> `.text()`, `.content` -> `.read()` everywhere; `LegacyAPIResponse` annotations replaced
|
|
280
|
-
- [ ] **[BREAKS]** `completions.create` / `HUMAN_PROMPT` / `AI_PROMPT` ported to Messages; **[DECIDE]** model choice surfaced
|
|
281
|
-
- [ ] **[BREAKS]** `temperature` / `top_p` / `top_k` removed from SDK calls - or, **[DECIDE]**, moved to `extra_body` only where the call pins an older model *and* visibly depends on the setting; raw `output_format={...}` -> `output_config={"format": ...}` everywhere (helpers included); helper `output_format=Model` untouched
|
|
282
|
-
- [ ] **[BREAKS]** `BetaBase64PDFBlockParam` -> `BetaRequestDocumentBlockParam`; `Transport`/`AsyncTransport`/`ProxiesTypes` -> `httpx2` names; `READ_MAX_BYTES` -> `DEFAULT_MAX_FILE_BYTES`
|
|
283
|
-
- [ ] **[BREAKS]** `parse(stream=)` -> `messages.stream()`; `compaction_control` -> server-side compaction; `body=bytes` -> `content=`; `Stream` isinstance checks retargeted
|
|
284
|
-
- [ ] **[DECIDE]** duplicate-casing headers joined; **[BREAKS]** `bytes` header values decoded
|
|
285
|
-
- [ ] **[DECIDE]** Bedrock constructions without a discoverable region listed, not guessed; invocation-metrics consumers flagged
|
|
286
|
-
- [ ] Step 11 verification run and Step 12 report written
|