Skip to content

Commit 69484ff

Browse files
Merge pull request #34 from StevanFreeborn/stevanfreeborn/fix/add-cancellation-token-support
fix: add cancellation token support
2 parents 02e34bb + 16ee80a commit 69484ff

File tree

7 files changed

+95
-71
lines changed

7 files changed

+95
-71
lines changed

.github/workflows/publish.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313
with:
1414
fetch-depth: 0
1515
token: ${{ secrets.ACTIONS_PAT }}
16-
- name: Setup .NET 8
16+
- name: Setup .NET 9
1717
uses: actions/setup-dotnet@v4
1818
with:
19-
dotnet-version: 8.x
19+
dotnet-version: 9.x
2020
- name: Install versionize
2121
run: dotnet tool install --global Versionize
2222
- name: Setup git
@@ -53,10 +53,10 @@ jobs:
5353
fetch-depth: 0
5454
ref: ${{ github.ref }}
5555
token: ${{ secrets.ACTIONS_PAT }}
56-
- name: Setup .NET 8
56+
- name: Setup .NET 9
5757
uses: actions/setup-dotnet@v4
5858
with:
59-
dotnet-version: 8.x
59+
dotnet-version: 9.x
6060
- name: Get project version
6161
uses: kzrnm/get-net-sdk-project-versions-action@v1
6262
id: get-version
@@ -88,10 +88,10 @@ jobs:
8888
fetch-depth: 0
8989
ref: ${{ github.ref }}
9090
token: ${{ secrets.ACTIONS_PAT }}
91-
- name: Setup .NET 8
91+
- name: Setup .NET 9
9292
uses: actions/setup-dotnet@v4
9393
with:
94-
dotnet-version: 8.x
94+
dotnet-version: 9.x
9595
- name: Install Docfx
9696
run: dotnet tool install --global docfx
9797
- name: Get project version

.github/workflows/pull_request.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ jobs:
1515
steps:
1616
- name: Checkout repository
1717
uses: actions/checkout@v4
18-
- name: Setup .NET 8
18+
- name: Setup .NET 9
1919
uses: actions/setup-dotnet@v4
2020
with:
21-
dotnet-version: 8.x
21+
dotnet-version: 9.x
2222
- name: Restore dependencies
2323
run: dotnet restore
2424
- name: Format code
@@ -28,10 +28,10 @@ jobs:
2828
steps:
2929
- name: Checkout repository
3030
uses: actions/checkout@v4
31-
- name: Setup .NET 8
31+
- name: Setup .NET 9
3232
uses: actions/setup-dotnet@v4
3333
with:
34-
dotnet-version: 8.x
34+
dotnet-version: 9.x
3535
- name: Install report generator
3636
run: dotnet tool install --global dotnet-reportgenerator-globaltool --version 5.3.7
3737
- name: Restore dependencies

.vscode/settings.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,18 @@
33
"dotnet.defaultSolution": "AnthropicClient.sln",
44
"cSpell.words": [
55
"Browsable",
6+
"buildtransitive",
7+
"contentfiles",
8+
"Docfx",
9+
"globaltool",
610
"haikus",
11+
"Linq",
12+
"msbuild",
713
"nameof",
14+
"reportgenerator",
15+
"reporttypes",
816
"Szalay",
17+
"targetdir",
918
"typeof"
1019
],
1120
"dotnet.unitTests.runSettingsPath": "./tests/AnthropicClient.Tests/.runsettings"

src/AnthropicClient/AnthropicApiClient.cs

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Net.Http.Headers;
2+
using System.Runtime.CompilerServices;
23
using System.Text;
34
using System.Text.Json;
45

@@ -52,9 +53,9 @@ public AnthropicApiClient(string apiKey, HttpClient httpClient)
5253
}
5354

5455
/// <inheritdoc/>
55-
public async Task<AnthropicResult<MessageResponse>> CreateMessageAsync(MessageRequest request)
56+
public async Task<AnthropicResult<MessageResponse>> CreateMessageAsync(MessageRequest request, CancellationToken cancellationToken = default)
5657
{
57-
var response = await SendRequestAsync(MessagesEndpoint, request);
58+
var response = await SendRequestAsync(MessagesEndpoint, request, cancellationToken);
5859
var anthropicHeaders = new AnthropicHeaders(response.Headers);
5960
var responseContent = await response.Content.ReadAsStringAsync();
6061

@@ -75,13 +76,14 @@ public async Task<AnthropicResult<MessageResponse>> CreateMessageAsync(MessageRe
7576
}
7677

7778
/// <inheritdoc/>
78-
public async IAsyncEnumerable<AnthropicEvent> CreateMessageAsync(StreamMessageRequest request)
79+
public async IAsyncEnumerable<AnthropicEvent> CreateMessageAsync(StreamMessageRequest request, [EnumeratorCancellation] CancellationToken cancellationToken = default)
7980
{
80-
var response = await SendRequestAsync(MessagesEndpoint, request);
81+
var response = await SendRequestAsync(MessagesEndpoint, request, cancellationToken);
8182

8283
if (response.IsSuccessStatusCode is false)
8384
{
84-
var error = Deserialize<AnthropicError>(await response.Content.ReadAsStringAsync()) ?? new AnthropicError();
85+
var errorContent = await response.Content.ReadAsStringAsync();
86+
var error = Deserialize<AnthropicError>(errorContent) ?? new AnthropicError();
8587
yield return new AnthropicEvent(EventType.Error, new ErrorEventData(error.Error));
8688
yield break;
8789
}
@@ -239,57 +241,57 @@ msgResponse is not null
239241
}
240242

241243
/// <inheritdoc/>
242-
public async Task<AnthropicResult<MessageBatchResponse>> CreateMessageBatchAsync(MessageBatchRequest request)
244+
public async Task<AnthropicResult<MessageBatchResponse>> CreateMessageBatchAsync(MessageBatchRequest request, CancellationToken cancellationToken = default)
243245
{
244-
var response = await SendRequestAsync(MessageBatchesEndpoint, request);
246+
var response = await SendRequestAsync(MessageBatchesEndpoint, request, cancellationToken);
245247
return await CreateResultAsync<MessageBatchResponse>(response);
246248
}
247249

248250
/// <inheritdoc/>
249-
public async Task<AnthropicResult<MessageBatchResponse>> GetMessageBatchAsync(string batchId)
251+
public async Task<AnthropicResult<MessageBatchResponse>> GetMessageBatchAsync(string batchId, CancellationToken cancellationToken = default)
250252
{
251-
var response = await SendRequestAsync($"{MessageBatchesEndpoint}/{batchId}");
253+
var response = await SendRequestAsync($"{MessageBatchesEndpoint}/{batchId}", cancellationToken: cancellationToken);
252254
return await CreateResultAsync<MessageBatchResponse>(response);
253255
}
254256

255257
/// <inheritdoc/>
256-
public async Task<AnthropicResult<Page<MessageBatchResponse>>> ListMessageBatchesAsync(PagingRequest? request = null)
258+
public async Task<AnthropicResult<Page<MessageBatchResponse>>> ListMessageBatchesAsync(PagingRequest? request = null, CancellationToken cancellationToken = default)
257259
{
258260
var pagingRequest = request ?? new PagingRequest();
259261
var endpoint = $"{MessageBatchesEndpoint}?{pagingRequest.ToQueryParameters()}";
260-
var response = await SendRequestAsync(endpoint);
262+
var response = await SendRequestAsync(endpoint, cancellationToken: cancellationToken);
261263
return await CreateResultAsync<Page<MessageBatchResponse>>(response);
262264
}
263265

264266
/// <inheritdoc/>
265-
public async IAsyncEnumerable<AnthropicResult<Page<MessageBatchResponse>>> ListAllMessageBatchesAsync(int limit = 20)
267+
public async IAsyncEnumerable<AnthropicResult<Page<MessageBatchResponse>>> ListAllMessageBatchesAsync(int limit = 20, [EnumeratorCancellation] CancellationToken cancellationToken = default)
266268
{
267-
await foreach (var result in GetAllPagesAsync<MessageBatchResponse>(MessageBatchesEndpoint, limit))
269+
await foreach (var result in GetAllPagesAsync<MessageBatchResponse>(MessageBatchesEndpoint, limit, cancellationToken))
268270
{
269271
yield return result;
270272
}
271273
}
272274

273275
/// <inheritdoc/>
274-
public async Task<AnthropicResult<MessageBatchResponse>> CancelMessageBatchAsync(string batchId)
276+
public async Task<AnthropicResult<MessageBatchResponse>> CancelMessageBatchAsync(string batchId, CancellationToken cancellationToken = default)
275277
{
276278
var endpoint = $"{MessageBatchesEndpoint}/{batchId}/cancel";
277-
var response = await SendRequestAsync(endpoint, HttpMethod.Post);
279+
var response = await SendRequestAsync(endpoint, HttpMethod.Post, cancellationToken);
278280
return await CreateResultAsync<MessageBatchResponse>(response);
279281
}
280282

281283
/// <inheritdoc/>
282-
public async Task<AnthropicResult<MessageBatchDeleteResponse>> DeleteMessageBatchAsync(string batchId)
284+
public async Task<AnthropicResult<MessageBatchDeleteResponse>> DeleteMessageBatchAsync(string batchId, CancellationToken cancellationToken = default)
283285
{
284286
var endpoint = $"{MessageBatchesEndpoint}/{batchId}";
285-
var response = await SendRequestAsync(endpoint, HttpMethod.Delete);
287+
var response = await SendRequestAsync(endpoint, HttpMethod.Delete, cancellationToken);
286288
return await CreateResultAsync<MessageBatchDeleteResponse>(response);
287289
}
288290

289291
/// <inheritdoc/>
290-
public async Task<AnthropicResult<IAsyncEnumerable<MessageBatchResultItem>>> GetMessageBatchResultsAsync(string batchId)
292+
public async Task<AnthropicResult<IAsyncEnumerable<MessageBatchResultItem>>> GetMessageBatchResultsAsync(string batchId, CancellationToken cancellationToken = default)
291293
{
292-
var response = await SendRequestAsync($"{MessageBatchesEndpoint}/{batchId}/results");
294+
var response = await SendRequestAsync($"{MessageBatchesEndpoint}/{batchId}/results", cancellationToken: cancellationToken);
293295
var anthropicHeaders = new AnthropicHeaders(response.Headers);
294296

295297
if (response.IsSuccessStatusCode is false)
@@ -319,47 +321,47 @@ async IAsyncEnumerable<MessageBatchResultItem> ReadResultsAsync()
319321
}
320322

321323
/// <inheritdoc/>
322-
public async Task<AnthropicResult<TokenCountResponse>> CountMessageTokensAsync(CountMessageTokensRequest request)
324+
public async Task<AnthropicResult<TokenCountResponse>> CountMessageTokensAsync(CountMessageTokensRequest request, CancellationToken cancellationToken = default)
323325
{
324-
var response = await SendRequestAsync(CountTokensEndpoint, request);
326+
var response = await SendRequestAsync(CountTokensEndpoint, request, cancellationToken);
325327
return await CreateResultAsync<TokenCountResponse>(response);
326328
}
327329

328330
/// <inheritdoc/>
329-
public async Task<AnthropicResult<Page<AnthropicModel>>> ListModelsAsync(PagingRequest? request = null)
331+
public async Task<AnthropicResult<Page<AnthropicModel>>> ListModelsAsync(PagingRequest? request = null, CancellationToken cancellationToken = default)
330332
{
331333
var pagingRequest = request ?? new PagingRequest();
332334
var endpoint = $"{ModelsEndpoint}?{pagingRequest.ToQueryParameters()}";
333-
var response = await SendRequestAsync(endpoint);
335+
var response = await SendRequestAsync(endpoint, cancellationToken: cancellationToken);
334336
return await CreateResultAsync<Page<AnthropicModel>>(response);
335337
}
336338

337339
/// <inheritdoc/>
338-
public async IAsyncEnumerable<AnthropicResult<Page<AnthropicModel>>> ListAllModelsAsync(int limit = 20)
340+
public async IAsyncEnumerable<AnthropicResult<Page<AnthropicModel>>> ListAllModelsAsync(int limit = 20, [EnumeratorCancellation] CancellationToken cancellationToken = default)
339341
{
340-
await foreach (var result in GetAllPagesAsync<AnthropicModel>(ModelsEndpoint, limit))
342+
await foreach (var result in GetAllPagesAsync<AnthropicModel>(ModelsEndpoint, limit, cancellationToken))
341343
{
342344
yield return result;
343345
}
344346
}
345347

346348
/// <inheritdoc/>
347-
public async Task<AnthropicResult<AnthropicModel>> GetModelAsync(string modelId)
349+
public async Task<AnthropicResult<AnthropicModel>> GetModelAsync(string modelId, CancellationToken cancellationToken = default)
348350
{
349351
var endpoint = $"{ModelsEndpoint}/{modelId}";
350-
var response = await SendRequestAsync(endpoint);
352+
var response = await SendRequestAsync(endpoint, cancellationToken: cancellationToken);
351353
return await CreateResultAsync<AnthropicModel>(response);
352354
}
353355

354-
private async IAsyncEnumerable<AnthropicResult<Page<T>>> GetAllPagesAsync<T>(string endpoint, int limit = 20)
356+
private async IAsyncEnumerable<AnthropicResult<Page<T>>> GetAllPagesAsync<T>(string endpoint, int limit = 20, [EnumeratorCancellation] CancellationToken cancellationToken = default)
355357
{
356358
var pagingRequest = new PagingRequest(limit: limit);
357359
string Endpoint() => $"{endpoint}?{pagingRequest.ToQueryParameters()}";
358360
bool hasMore;
359361

360362
do
361363
{
362-
var response = await SendRequestAsync(Endpoint());
364+
var response = await SendRequestAsync(Endpoint(), cancellationToken: cancellationToken);
363365
var anthropicHeaders = new AnthropicHeaders(response.Headers);
364366
var responseContent = await response.Content.ReadAsStringAsync();
365367

@@ -420,17 +422,17 @@ private async IAsyncEnumerable<AnthropicResult<Page<T>>> GetAllPagesAsync<T>(str
420422
return AnthropicResult<T>.Success(model, anthropicHeaders);
421423
}
422424

423-
private async Task<HttpResponseMessage> SendRequestAsync(string endpoint, HttpMethod? method = null)
425+
private async Task<HttpResponseMessage> SendRequestAsync(string endpoint, HttpMethod? method = null, CancellationToken cancellationToken = default)
424426
{
425427
var request = new HttpRequestMessage(method ?? HttpMethod.Get, endpoint);
426-
return await _httpClient.SendAsync(request);
428+
return await _httpClient.SendAsync(request, cancellationToken);
427429
}
428430

429-
private async Task<HttpResponseMessage> SendRequestAsync<T>(string endpoint, T request)
431+
private async Task<HttpResponseMessage> SendRequestAsync<T>(string endpoint, T request, CancellationToken cancellationToken = default)
430432
{
431433
var requestJson = Serialize(request);
432434
var requestContent = new StringContent(requestJson, Encoding.UTF8, JsonContentType);
433-
return await _httpClient.PostAsync(endpoint, requestContent);
435+
return await _httpClient.PostAsync(endpoint, requestContent, cancellationToken);
434436
}
435437

436438
private string Serialize<T>(T obj) => JsonSerializer.Serialize(obj, JsonSerializationOptions.DefaultOptions);

src/AnthropicClient/AnthropicClient.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
</ItemGroup>
3535

3636
<ItemGroup>
37-
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
38-
<PackageReference Include="System.Text.Json" Version="8.0.5" />
37+
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.5" />
38+
<PackageReference Include="System.Text.Json" Version="9.0.5" />
3939
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
4040
</ItemGroup>
4141

0 commit comments

Comments
 (0)