Skip to content

Commit 769f9da

Browse files
feat(api): add claude 4 models, files API, code execution tool, MCP connector and more
1 parent 2ed236d commit 769f9da

File tree

23 files changed

+1211
-70
lines changed

23 files changed

+1211
-70
lines changed

.stats.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 21
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic%2Fanthropic-087f1149681ef9bc1074184df28ed4b4b9cc37b86cba50eb18e6c18452864446.yml
3-
openapi_spec_hash: 2007ff815a3f39af8cebe1976d50f17d
4-
config_hash: 7b88da171a1b1bdb963ec2311e417cbe
1+
configured_endpoints: 26
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic%2Fanthropic-1fdf23e8226430012c21819427e8d1ed16c08c0fb2d4abf69b8e318a42e99552.yml
3+
openapi_spec_hash: 836bbb4ab7c33c37456d1842876d7aba
4+
config_hash: 7b17fe2f10f5942177ff51b0a13506fa

MIGRATION.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ This affects the following methods:
7777
- `client.beta.messages.batches.delete()`
7878
- `client.beta.messages.batches.cancel()`
7979
- `client.beta.messages.batches.results()`
80+
- `client.beta.files.list()`
81+
- `client.beta.files.delete()`
82+
- `client.beta.files.download()`
83+
- `client.beta.files.retrieveMetadata()`
8084

8185
### Removed `httpAgent` in favor of `fetchOptions`
8286

README.md

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,51 @@ This SDK provides support for tool use, aka function calling. More details can b
184184

185185
We provide support for the [Anthropic Bedrock API](https://aws.amazon.com/bedrock/claude/) through a [separate package](https://github.com/anthropics/anthropic-sdk-typescript/tree/main/packages/bedrock-sdk).
186186

187+
## File uploads
188+
189+
Request parameters that correspond to file uploads can be passed in many different forms:
190+
191+
- `File` (or an object with the same structure)
192+
- a `fetch` `Response` (or an object with the same structure)
193+
- an `fs.ReadStream`
194+
- the return value of our `toFile` helper
195+
196+
Note that we recommend you set the content-type explicitly as the files API will not infer it for you:
197+
198+
```ts
199+
import fs from 'fs';
200+
import Anthropic, { toFile } from '@anthropic-ai/sdk';
201+
202+
const client = new Anthropic();
203+
204+
// If you have access to Node `fs` we recommend using `fs.createReadStream()`:
205+
await client.beta.files.upload({
206+
file: await toFile(fs.createReadStream('/path/to/file'), undefined, { type: 'application/json' }),
207+
betas: ['files-api-2025-04-14'],
208+
});
209+
210+
// Or if you have the web `File` API you can pass a `File` instance:
211+
await client.beta.files.upload({
212+
file: new File(['my bytes'], 'file.txt', { type: 'text/plain' }),
213+
betas: ['files-api-2025-04-14'],
214+
});
215+
// You can also pass a `fetch` `Response`:
216+
await client.beta.files.upload({
217+
file: await fetch('https://somesite/file'),
218+
betas: ['files-api-2025-04-14'],
219+
});
220+
221+
// Or a `Buffer` / `Uint8Array`
222+
await client.beta.files.upload({
223+
file: await toFile(Buffer.from('my bytes'), 'file', { type: 'text/plain' }),
224+
betas: ['files-api-2025-04-14'],
225+
});
226+
await client.beta.files.upload({
227+
file: await toFile(new Uint8Array([0, 1, 2]), 'file', { type: 'text/plain' }),
228+
betas: ['files-api-2025-04-14'],
229+
});
230+
```
231+
187232
## Handling errors
188233

189234
When the library is unable to connect to the API,
@@ -309,8 +354,9 @@ Passing `stream: true` or [overriding](#timeouts) the `timeout` option at the cl
309354
An expected request latency longer than the [timeout](#timeouts) for a non-streaming request
310355
will result in the client terminating the connection and retrying without receiving a response.
311356

312-
When supported by the `fetch` implementation, we set a [TCP socket keep-alive](https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html)
313-
option in order to reduce the impact of idle connection timeouts on some networks.
357+
When supported by the `fetch` implementation, we set a [TCP socket keep-alive](https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html) option in order
358+
to reduce the impact of idle connection timeouts on some networks.
359+
This can be [overriden](#configuring-an-https-agent-eg-for-proxies) by configuring a custom proxy.
314360

315361
## Auto-pagination
316362

api.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ Types:
185185
- <code><a href="./src/resources/beta/messages/messages.ts">BetaBase64PDFBlock</a></code>
186186
- <code><a href="./src/resources/beta/messages/messages.ts">BetaBase64PDFSource</a></code>
187187
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCacheControlEphemeral</a></code>
188+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCacheCreation</a></code>
188189
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCitationCharLocation</a></code>
189190
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCitationCharLocationParam</a></code>
190191
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCitationContentBlockLocation</a></code>
@@ -195,12 +196,32 @@ Types:
195196
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCitationsConfigParam</a></code>
196197
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCitationsDelta</a></code>
197198
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCitationsWebSearchResultLocation</a></code>
199+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionOutputBlock</a></code>
200+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionOutputBlockParam</a></code>
201+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionResultBlock</a></code>
202+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionResultBlockParam</a></code>
203+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionTool20250522</a></code>
204+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionToolResultBlock</a></code>
205+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionToolResultBlockContent</a></code>
206+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionToolResultBlockParam</a></code>
207+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionToolResultBlockParamContent</a></code>
208+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionToolResultError</a></code>
209+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionToolResultErrorCode</a></code>
210+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaCodeExecutionToolResultErrorParam</a></code>
211+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaContainer</a></code>
212+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaContainerUploadBlock</a></code>
213+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaContainerUploadBlockParam</a></code>
198214
- <code><a href="./src/resources/beta/messages/messages.ts">BetaContentBlock</a></code>
199215
- <code><a href="./src/resources/beta/messages/messages.ts">BetaContentBlockParam</a></code>
200216
- <code><a href="./src/resources/beta/messages/messages.ts">BetaContentBlockSource</a></code>
201217
- <code><a href="./src/resources/beta/messages/messages.ts">BetaContentBlockSourceContent</a></code>
218+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaFileDocumentSource</a></code>
219+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaFileImageSource</a></code>
202220
- <code><a href="./src/resources/beta/messages/messages.ts">BetaImageBlockParam</a></code>
203221
- <code><a href="./src/resources/beta/messages/messages.ts">BetaInputJSONDelta</a></code>
222+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaMCPToolResultBlock</a></code>
223+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaMCPToolUseBlock</a></code>
224+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaMCPToolUseBlockParam</a></code>
204225
- <code><a href="./src/resources/beta/messages/messages.ts">BetaMessage</a></code>
205226
- <code><a href="./src/resources/beta/messages/messages.ts">BetaMessageDeltaUsage</a></code>
206227
- <code><a href="./src/resources/beta/messages/messages.ts">BetaMessageParam</a></code>
@@ -217,6 +238,9 @@ Types:
217238
- <code><a href="./src/resources/beta/messages/messages.ts">BetaRawMessageStreamEvent</a></code>
218239
- <code><a href="./src/resources/beta/messages/messages.ts">BetaRedactedThinkingBlock</a></code>
219240
- <code><a href="./src/resources/beta/messages/messages.ts">BetaRedactedThinkingBlockParam</a></code>
241+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaRequestMCPServerToolConfiguration</a></code>
242+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaRequestMCPServerURLDefinition</a></code>
243+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaRequestMCPToolResultBlockParam</a></code>
220244
- <code><a href="./src/resources/beta/messages/messages.ts">BetaServerToolUsage</a></code>
221245
- <code><a href="./src/resources/beta/messages/messages.ts">BetaServerToolUseBlock</a></code>
222246
- <code><a href="./src/resources/beta/messages/messages.ts">BetaServerToolUseBlockParam</a></code>
@@ -246,6 +270,7 @@ Types:
246270
- <code><a href="./src/resources/beta/messages/messages.ts">BetaToolResultBlockParam</a></code>
247271
- <code><a href="./src/resources/beta/messages/messages.ts">BetaToolTextEditor20241022</a></code>
248272
- <code><a href="./src/resources/beta/messages/messages.ts">BetaToolTextEditor20250124</a></code>
273+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaToolTextEditor20250429</a></code>
249274
- <code><a href="./src/resources/beta/messages/messages.ts">BetaToolUnion</a></code>
250275
- <code><a href="./src/resources/beta/messages/messages.ts">BetaToolUseBlock</a></code>
251276
- <code><a href="./src/resources/beta/messages/messages.ts">BetaToolUseBlockParam</a></code>
@@ -261,6 +286,7 @@ Types:
261286
- <code><a href="./src/resources/beta/messages/messages.ts">BetaWebSearchToolResultBlockParam</a></code>
262287
- <code><a href="./src/resources/beta/messages/messages.ts">BetaWebSearchToolResultBlockParamContent</a></code>
263288
- <code><a href="./src/resources/beta/messages/messages.ts">BetaWebSearchToolResultError</a></code>
289+
- <code><a href="./src/resources/beta/messages/messages.ts">BetaWebSearchToolResultErrorCode</a></code>
264290

265291
Methods:
266292

@@ -289,3 +315,18 @@ Methods:
289315
- <code title="delete /v1/messages/batches/{message_batch_id}?beta=true">client.beta.messages.batches.<a href="./src/resources/beta/messages/batches.ts">delete</a>(messageBatchID, { ...params }) -> BetaDeletedMessageBatch</code>
290316
- <code title="post /v1/messages/batches/{message_batch_id}/cancel?beta=true">client.beta.messages.batches.<a href="./src/resources/beta/messages/batches.ts">cancel</a>(messageBatchID, { ...params }) -> BetaMessageBatch</code>
291317
- <code title="get /v1/messages/batches/{message_batch_id}/results?beta=true">client.beta.messages.batches.<a href="./src/resources/beta/messages/batches.ts">results</a>(messageBatchID, { ...params }) -> BetaMessageBatchIndividualResponse</code>
318+
319+
## Files
320+
321+
Types:
322+
323+
- <code><a href="./src/resources/beta/files.ts">DeletedFile</a></code>
324+
- <code><a href="./src/resources/beta/files.ts">FileMetadata</a></code>
325+
326+
Methods:
327+
328+
- <code title="get /v1/files?beta=true">client.beta.files.<a href="./src/resources/beta/files.ts">list</a>({ ...params }) -> FileMetadataPage</code>
329+
- <code title="delete /v1/files/{file_id}?beta=true">client.beta.files.<a href="./src/resources/beta/files.ts">delete</a>(fileID, { ...params }) -> DeletedFile</code>
330+
- <code title="get /v1/files/{file_id}/content?beta=true">client.beta.files.<a href="./src/resources/beta/files.ts">download</a>(fileID, { ...params }) -> Response</code>
331+
- <code title="get /v1/files/{file_id}?beta=true">client.beta.files.<a href="./src/resources/beta/files.ts">retrieveMetadata</a>(fileID, { ...params }) -> FileMetadata</code>
332+
- <code title="post /v1/files?beta=true">client.beta.files.<a href="./src/resources/beta/files.ts">upload</a>({ ...params }) -> FileMetadata</code>

examples/mcp.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env -S npm run tsn -T
2+
3+
import Anthropic from '@anthropic-ai/sdk';
4+
5+
const anthropic = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY
6+
7+
const main = async () => {
8+
const stream = anthropic.beta.messages.stream(
9+
{
10+
model: 'claude-3-7-sonnet-20250219',
11+
max_tokens: 1000,
12+
mcp_servers: [
13+
{
14+
type: 'url',
15+
url: 'http://example-server.modelcontextprotocol.io/sse',
16+
name: 'example',
17+
tool_configuration: {
18+
// Optional, defaults to allowing all tools
19+
enabled: true, // Optional
20+
allowed_tools: ['echo', 'add'], // Optional
21+
},
22+
},
23+
],
24+
messages: [
25+
{
26+
role: 'user',
27+
content: 'Calculate 1+2',
28+
},
29+
],
30+
},
31+
{
32+
headers: {
33+
'anthropic-beta': 'mcp-client-2025-04-04',
34+
},
35+
},
36+
);
37+
for await (const event of stream) {
38+
if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
39+
process.stdout.write(event.delta.text);
40+
}
41+
}
42+
process.stdout.write('\n');
43+
};
44+
main();

src/client.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,20 @@ export class BaseAnthropic {
769769
return sleepSeconds * jitter * 1000;
770770
}
771771

772+
public calculateNonstreamingTimeout(maxTokens: number, maxNonstreamingTokens?: number): number {
773+
const maxTime = 60 * 60 * 1000; // 10 minutes
774+
const defaultTime = 60 * 10 * 1000; // 10 minutes
775+
776+
const expectedTime = (maxTime * maxTokens) / 128000;
777+
if (expectedTime > defaultTime || (maxNonstreamingTokens != null && maxTokens > maxNonstreamingTokens)) {
778+
throw new Errors.AnthropicError(
779+
'Streaming is strongly recommended for operations that may token longer than 10 minutes. See https://github.com/anthropics/anthropic-sdk-typescript#long-requests for more details',
780+
);
781+
}
782+
783+
return defaultTime;
784+
}
785+
772786
buildRequest(
773787
inputOptions: FinalRequestOptions,
774788
{ retryCount = 0 }: { retryCount?: number } = {},

src/internal/constants.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// File containing shared constants
2+
3+
/**
4+
* Model-specific timeout constraints for non-streaming requests
5+
*/
6+
export const MODEL_NONSTREAMING_TOKENS: Record<string, number> = {
7+
'claude-opus-4-20250514': 8192,
8+
'claude-opus-4-0': 8192,
9+
'claude-4-opus-20250514': 8192,
10+
'anthropic.claude-opus-4-20250514-v1:0': 8192,
11+
'claude-opus-4@20250514': 8192,
12+
};

src/internal/to-file.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,19 @@ export async function toFile(
9090
// If it's a promise, resolve it.
9191
value = await value;
9292

93-
// If we've been given a `File` we don't need to do anything
93+
name ||= getName(value);
94+
95+
// If we've been given a `File` we don't need to do anything if the name / options
96+
// have not been customised.
9497
if (isFileLike(value)) {
95-
if (value instanceof File) {
98+
if (value instanceof File && name == null && options == null) {
9699
return value;
97100
}
98-
return makeFile([await value.arrayBuffer()], value.name);
101+
return makeFile([await value.arrayBuffer()], name ?? value.name, {
102+
type: value.type,
103+
lastModified: value.lastModified,
104+
...options,
105+
});
99106
}
100107

101108
if (isResponseLike(value)) {
@@ -107,8 +114,6 @@ export async function toFile(
107114

108115
const parts = await getBytes(value);
109116

110-
name ||= getName(value);
111-
112117
if (!options?.type) {
113118
const type = parts.find((part) => typeof part === 'object' && 'type' in part && part.type);
114119
if (typeof type === 'string') {

src/internal/uploads.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export const createForm = async <T = Record<string, unknown>>(
138138

139139
// We check for Blob not File because Bun.File doesn't inherit from File,
140140
// but they both inherit from Blob and have a `name` property at runtime.
141-
const isNamedBlob = (value: object) => value instanceof Blob && 'name' in value;
141+
const isNamedBlob = (value: object): value is Blob => value instanceof Blob && 'name' in value;
142142

143143
const isUploadable = (value: unknown) =>
144144
typeof value === 'object' &&
@@ -168,11 +168,17 @@ const addFormValue = async (form: FormData, key: string, value: unknown): Promis
168168
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
169169
form.append(key, String(value));
170170
} else if (value instanceof Response) {
171-
form.append(key, makeFile([await value.blob()], getName(value)));
171+
let options = {} as FilePropertyBag;
172+
const contentType = value.headers.get('Content-Type');
173+
if (contentType) {
174+
options = { type: contentType };
175+
}
176+
177+
form.append(key, makeFile([await value.blob()], getName(value), options));
172178
} else if (isAsyncIterable(value)) {
173179
form.append(key, makeFile([await new Response(ReadableStreamFrom(value)).blob()], getName(value)));
174180
} else if (isNamedBlob(value)) {
175-
form.append(key, value, getName(value));
181+
form.append(key, makeFile([value], getName(value), { type: value.type }));
176182
} else if (Array.isArray(value)) {
177183
await Promise.all(value.map((entry) => addFormValue(form, key + '[]', entry)));
178184
} else if (typeof value === 'object') {

src/lib/BetaMessageStream.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
432432
break;
433433
}
434434
case 'input_json_delta': {
435-
if (content.type === 'tool_use' && content.input) {
435+
if ((content.type === 'tool_use' || content.type === 'mcp_tool_use') && content.input) {
436436
this._emit('inputJson', event.delta.partial_json, content.input);
437437
}
438438
break;
@@ -528,6 +528,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
528528
case 'message_stop':
529529
return snapshot;
530530
case 'message_delta':
531+
snapshot.container = event.delta.container;
531532
snapshot.stop_reason = event.delta.stop_reason;
532533
snapshot.stop_sequence = event.delta.stop_sequence;
533534
snapshot.usage.output_tokens = event.usage.output_tokens;
@@ -570,7 +571,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
570571
break;
571572
}
572573
case 'input_json_delta': {
573-
if (snapshotContent?.type === 'tool_use') {
574+
if (snapshotContent?.type === 'tool_use' || snapshotContent?.type === 'mcp_tool_use') {
574575
// we need to keep track of the raw JSON string as well so that we can
575576
// re-parse it for each delta, for now we just store it as an untyped
576577
// non-enumerable property on the snapshot

0 commit comments

Comments
 (0)