Skip to content

Commit ec96afb

Browse files
Merge pull request #13 from anthropics/justin/cancellation
Add cancellation support using AbortController/AbortSignal
2 parents 493075d + 607afa5 commit ec96afb

File tree

3 files changed

+75
-5
lines changed

3 files changed

+75
-5
lines changed

examples/cancellation.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import "dotenv/config";
2+
import { AI_PROMPT, Client, HUMAN_PROMPT } from "../src";
3+
4+
const apiKey = process.env.ANTHROPIC_API_KEY;
5+
if (!apiKey) {
6+
throw new Error("The ANTHROPIC_API_KEY environment variable must be set");
7+
}
8+
9+
const client = new Client(apiKey);
10+
const abortController = new AbortController();
11+
12+
client
13+
.complete(
14+
{
15+
prompt: `${HUMAN_PROMPT} How many toes do dogs have?${AI_PROMPT}`,
16+
stop_sequences: [HUMAN_PROMPT],
17+
max_tokens_to_sample: 200,
18+
model: "claude-v1",
19+
},
20+
{ signal: abortController.signal }
21+
)
22+
.catch((error) => {
23+
if (error.name === "AbortError") {
24+
console.log("Cancelled complete()");
25+
}
26+
});
27+
28+
client
29+
.completeStream(
30+
{
31+
prompt: `${HUMAN_PROMPT} How many toes do dogs have?${AI_PROMPT}`,
32+
stop_sequences: [HUMAN_PROMPT],
33+
max_tokens_to_sample: 200,
34+
model: "claude-v1",
35+
},
36+
{
37+
onOpen: (response) => {
38+
console.log("Opened stream, HTTP status code", response.status);
39+
},
40+
onUpdate: (completion) => {
41+
console.log(completion.completion);
42+
},
43+
signal: abortController.signal,
44+
}
45+
)
46+
.catch((error) => {
47+
if (error.name === "AbortError") {
48+
console.log("Cancelled completeStream()");
49+
}
50+
});
51+
52+
abortController.abort();

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@anthropic-ai/sdk",
3-
"version": "0.4.2",
3+
"version": "0.4.3",
44
"description": "Library for accessing the Anthropic API",
55
"repository": "https://github.com/anthropics/anthropic-sdk-typescript",
66
"license": "MIT",
@@ -15,7 +15,8 @@
1515
"lint": "eslint src && prettier --check .",
1616
"format": "prettier --write .",
1717
"example:basic_stream": "tsc --build && node ./build/examples/basic_stream.js",
18-
"example:basic_sync": "tsc --build && node ./build/examples/basic_sync.js"
18+
"example:basic_sync": "tsc --build && node ./build/examples/basic_sync.js",
19+
"example:cancellation": "tsc --build && node ./build/examples/cancellation.js"
1920
},
2021
"dependencies": {
2122
"@fortaine/fetch-event-source": "^3.0.6",

src/index.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export type OnUpdate = (completion: CompletionResponse) => void | Promise<void>;
1818
export const HUMAN_PROMPT = "\n\nHuman:";
1919
export const AI_PROMPT = "\n\nAssistant:";
2020

21-
const CLIENT_ID = "anthropic-typescript/0.4.2";
21+
const CLIENT_ID = "anthropic-typescript/0.4.3";
2222
const DEFAULT_API_URL = "https://api.anthropic.com";
2323

2424
enum Event {
@@ -43,7 +43,10 @@ export class Client {
4343
this.apiUrl = options?.apiUrl ?? DEFAULT_API_URL;
4444
}
4545

46-
async complete(params: SamplingParameters): Promise<CompletionResponse> {
46+
async complete(
47+
params: SamplingParameters,
48+
options?: { signal?: AbortSignal }
49+
): Promise<CompletionResponse> {
4750
const response = await fetch(`${this.apiUrl}/v1/complete`, {
4851
method: "POST",
4952
headers: {
@@ -53,6 +56,7 @@ export class Client {
5356
"X-API-Key": this.apiKey,
5457
},
5558
body: JSON.stringify({ ...params, stream: false }),
59+
signal: options?.signal,
5660
});
5761

5862
if (!response.ok) {
@@ -69,10 +73,23 @@ export class Client {
6973

7074
completeStream(
7175
params: SamplingParameters,
72-
{ onOpen, onUpdate }: { onOpen?: OnOpen; onUpdate?: OnUpdate }
76+
{
77+
onOpen,
78+
onUpdate,
79+
signal,
80+
}: { onOpen?: OnOpen; onUpdate?: OnUpdate; signal?: AbortSignal }
7381
): Promise<CompletionResponse> {
7482
const abortController = new AbortController();
83+
7584
return new Promise((resolve, reject) => {
85+
signal?.addEventListener("abort", (event) => {
86+
abortController.abort(event);
87+
reject({
88+
name: "AbortError",
89+
message: "Caller aborted completeStream",
90+
});
91+
});
92+
7693
fetchEventSource(`${this.apiUrl}/v1/complete`, {
7794
method: "POST",
7895
headers: {

0 commit comments

Comments
 (0)