diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 2825527..8668753 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -13,10 +13,10 @@ jobs:
with:
fetch-depth: 0
token: ${{ secrets.ACTIONS_PAT }}
- - name: Setup .NET 8
+ - name: Setup .NET 9
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
- name: Install versionize
run: dotnet tool install --global Versionize
- name: Setup git
@@ -53,10 +53,10 @@ jobs:
fetch-depth: 0
ref: ${{ github.ref }}
token: ${{ secrets.ACTIONS_PAT }}
- - name: Setup .NET 8
+ - name: Setup .NET 9
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
- name: Get project version
uses: kzrnm/get-net-sdk-project-versions-action@v1
id: get-version
@@ -88,10 +88,10 @@ jobs:
fetch-depth: 0
ref: ${{ github.ref }}
token: ${{ secrets.ACTIONS_PAT }}
- - name: Setup .NET 8
+ - name: Setup .NET 9
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
- name: Install Docfx
run: dotnet tool install --global docfx
- name: Get project version
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index b6a83cd..f12943b 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -15,10 +15,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- - name: Setup .NET 8
+ - name: Setup .NET 9
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
- name: Restore dependencies
run: dotnet restore
- name: Format code
@@ -28,10 +28,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- - name: Setup .NET 8
+ - name: Setup .NET 9
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.x
+ dotnet-version: 9.x
- name: Install report generator
run: dotnet tool install --global dotnet-reportgenerator-globaltool --version 5.3.7
- name: Restore dependencies
diff --git a/.vscode/settings.json b/.vscode/settings.json
index b2f391d..11a990d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -3,9 +3,18 @@
"dotnet.defaultSolution": "AnthropicClient.sln",
"cSpell.words": [
"Browsable",
+ "buildtransitive",
+ "contentfiles",
+ "Docfx",
+ "globaltool",
"haikus",
+ "Linq",
+ "msbuild",
"nameof",
+ "reportgenerator",
+ "reporttypes",
"Szalay",
+ "targetdir",
"typeof"
],
"dotnet.unitTests.runSettingsPath": "./tests/AnthropicClient.Tests/.runsettings"
diff --git a/src/AnthropicClient/AnthropicApiClient.cs b/src/AnthropicClient/AnthropicApiClient.cs
index 826b735..f05f3e6 100644
--- a/src/AnthropicClient/AnthropicApiClient.cs
+++ b/src/AnthropicClient/AnthropicApiClient.cs
@@ -1,4 +1,5 @@
using System.Net.Http.Headers;
+using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
@@ -52,9 +53,9 @@ public AnthropicApiClient(string apiKey, HttpClient httpClient)
}
///
- public async Task> CreateMessageAsync(MessageRequest request)
+ public async Task> CreateMessageAsync(MessageRequest request, CancellationToken cancellationToken = default)
{
- var response = await SendRequestAsync(MessagesEndpoint, request);
+ var response = await SendRequestAsync(MessagesEndpoint, request, cancellationToken);
var anthropicHeaders = new AnthropicHeaders(response.Headers);
var responseContent = await response.Content.ReadAsStringAsync();
@@ -75,13 +76,14 @@ public async Task> CreateMessageAsync(MessageRe
}
///
- public async IAsyncEnumerable CreateMessageAsync(StreamMessageRequest request)
+ public async IAsyncEnumerable CreateMessageAsync(StreamMessageRequest request, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
- var response = await SendRequestAsync(MessagesEndpoint, request);
+ var response = await SendRequestAsync(MessagesEndpoint, request, cancellationToken);
if (response.IsSuccessStatusCode is false)
{
- var error = Deserialize(await response.Content.ReadAsStringAsync()) ?? new AnthropicError();
+ var errorContent = await response.Content.ReadAsStringAsync();
+ var error = Deserialize(errorContent) ?? new AnthropicError();
yield return new AnthropicEvent(EventType.Error, new ErrorEventData(error.Error));
yield break;
}
@@ -239,57 +241,57 @@ msgResponse is not null
}
///
- public async Task> CreateMessageBatchAsync(MessageBatchRequest request)
+ public async Task> CreateMessageBatchAsync(MessageBatchRequest request, CancellationToken cancellationToken = default)
{
- var response = await SendRequestAsync(MessageBatchesEndpoint, request);
+ var response = await SendRequestAsync(MessageBatchesEndpoint, request, cancellationToken);
return await CreateResultAsync(response);
}
///
- public async Task> GetMessageBatchAsync(string batchId)
+ public async Task> GetMessageBatchAsync(string batchId, CancellationToken cancellationToken = default)
{
- var response = await SendRequestAsync($"{MessageBatchesEndpoint}/{batchId}");
+ var response = await SendRequestAsync($"{MessageBatchesEndpoint}/{batchId}", cancellationToken: cancellationToken);
return await CreateResultAsync(response);
}
///
- public async Task>> ListMessageBatchesAsync(PagingRequest? request = null)
+ public async Task>> ListMessageBatchesAsync(PagingRequest? request = null, CancellationToken cancellationToken = default)
{
var pagingRequest = request ?? new PagingRequest();
var endpoint = $"{MessageBatchesEndpoint}?{pagingRequest.ToQueryParameters()}";
- var response = await SendRequestAsync(endpoint);
+ var response = await SendRequestAsync(endpoint, cancellationToken: cancellationToken);
return await CreateResultAsync>(response);
}
///
- public async IAsyncEnumerable>> ListAllMessageBatchesAsync(int limit = 20)
+ public async IAsyncEnumerable>> ListAllMessageBatchesAsync(int limit = 20, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
- await foreach (var result in GetAllPagesAsync(MessageBatchesEndpoint, limit))
+ await foreach (var result in GetAllPagesAsync(MessageBatchesEndpoint, limit, cancellationToken))
{
yield return result;
}
}
///
- public async Task> CancelMessageBatchAsync(string batchId)
+ public async Task> CancelMessageBatchAsync(string batchId, CancellationToken cancellationToken = default)
{
var endpoint = $"{MessageBatchesEndpoint}/{batchId}/cancel";
- var response = await SendRequestAsync(endpoint, HttpMethod.Post);
+ var response = await SendRequestAsync(endpoint, HttpMethod.Post, cancellationToken);
return await CreateResultAsync(response);
}
///
- public async Task> DeleteMessageBatchAsync(string batchId)
+ public async Task> DeleteMessageBatchAsync(string batchId, CancellationToken cancellationToken = default)
{
var endpoint = $"{MessageBatchesEndpoint}/{batchId}";
- var response = await SendRequestAsync(endpoint, HttpMethod.Delete);
+ var response = await SendRequestAsync(endpoint, HttpMethod.Delete, cancellationToken);
return await CreateResultAsync(response);
}
///
- public async Task>> GetMessageBatchResultsAsync(string batchId)
+ public async Task>> GetMessageBatchResultsAsync(string batchId, CancellationToken cancellationToken = default)
{
- var response = await SendRequestAsync($"{MessageBatchesEndpoint}/{batchId}/results");
+ var response = await SendRequestAsync($"{MessageBatchesEndpoint}/{batchId}/results", cancellationToken: cancellationToken);
var anthropicHeaders = new AnthropicHeaders(response.Headers);
if (response.IsSuccessStatusCode is false)
@@ -319,39 +321,39 @@ async IAsyncEnumerable ReadResultsAsync()
}
///
- public async Task> CountMessageTokensAsync(CountMessageTokensRequest request)
+ public async Task> CountMessageTokensAsync(CountMessageTokensRequest request, CancellationToken cancellationToken = default)
{
- var response = await SendRequestAsync(CountTokensEndpoint, request);
+ var response = await SendRequestAsync(CountTokensEndpoint, request, cancellationToken);
return await CreateResultAsync(response);
}
///
- public async Task>> ListModelsAsync(PagingRequest? request = null)
+ public async Task>> ListModelsAsync(PagingRequest? request = null, CancellationToken cancellationToken = default)
{
var pagingRequest = request ?? new PagingRequest();
var endpoint = $"{ModelsEndpoint}?{pagingRequest.ToQueryParameters()}";
- var response = await SendRequestAsync(endpoint);
+ var response = await SendRequestAsync(endpoint, cancellationToken: cancellationToken);
return await CreateResultAsync>(response);
}
///
- public async IAsyncEnumerable>> ListAllModelsAsync(int limit = 20)
+ public async IAsyncEnumerable>> ListAllModelsAsync(int limit = 20, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
- await foreach (var result in GetAllPagesAsync(ModelsEndpoint, limit))
+ await foreach (var result in GetAllPagesAsync(ModelsEndpoint, limit, cancellationToken))
{
yield return result;
}
}
///
- public async Task> GetModelAsync(string modelId)
+ public async Task> GetModelAsync(string modelId, CancellationToken cancellationToken = default)
{
var endpoint = $"{ModelsEndpoint}/{modelId}";
- var response = await SendRequestAsync(endpoint);
+ var response = await SendRequestAsync(endpoint, cancellationToken: cancellationToken);
return await CreateResultAsync(response);
}
- private async IAsyncEnumerable>> GetAllPagesAsync(string endpoint, int limit = 20)
+ private async IAsyncEnumerable>> GetAllPagesAsync(string endpoint, int limit = 20, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var pagingRequest = new PagingRequest(limit: limit);
string Endpoint() => $"{endpoint}?{pagingRequest.ToQueryParameters()}";
@@ -359,7 +361,7 @@ private async IAsyncEnumerable>> GetAllPagesAsync(str
do
{
- var response = await SendRequestAsync(Endpoint());
+ var response = await SendRequestAsync(Endpoint(), cancellationToken: cancellationToken);
var anthropicHeaders = new AnthropicHeaders(response.Headers);
var responseContent = await response.Content.ReadAsStringAsync();
@@ -420,17 +422,17 @@ private async IAsyncEnumerable>> GetAllPagesAsync(str
return AnthropicResult.Success(model, anthropicHeaders);
}
- private async Task SendRequestAsync(string endpoint, HttpMethod? method = null)
+ private async Task SendRequestAsync(string endpoint, HttpMethod? method = null, CancellationToken cancellationToken = default)
{
var request = new HttpRequestMessage(method ?? HttpMethod.Get, endpoint);
- return await _httpClient.SendAsync(request);
+ return await _httpClient.SendAsync(request, cancellationToken);
}
- private async Task SendRequestAsync(string endpoint, T request)
+ private async Task SendRequestAsync(string endpoint, T request, CancellationToken cancellationToken = default)
{
var requestJson = Serialize(request);
var requestContent = new StringContent(requestJson, Encoding.UTF8, JsonContentType);
- return await _httpClient.PostAsync(endpoint, requestContent);
+ return await _httpClient.PostAsync(endpoint, requestContent, cancellationToken);
}
private string Serialize(T obj) => JsonSerializer.Serialize(obj, JsonSerializationOptions.DefaultOptions);
diff --git a/src/AnthropicClient/AnthropicClient.csproj b/src/AnthropicClient/AnthropicClient.csproj
index 8f16d24..0a58e81 100644
--- a/src/AnthropicClient/AnthropicClient.csproj
+++ b/src/AnthropicClient/AnthropicClient.csproj
@@ -34,8 +34,8 @@
-
-
+
+
diff --git a/src/AnthropicClient/IAnthropicApiClient.cs b/src/AnthropicClient/IAnthropicApiClient.cs
index 27c7e00..e4f63b9 100644
--- a/src/AnthropicClient/IAnthropicApiClient.cs
+++ b/src/AnthropicClient/IAnthropicApiClient.cs
@@ -11,91 +11,104 @@ public interface IAnthropicApiClient
/// Creates a message asynchronously.
///
/// The message request to create.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an .
- Task> CreateMessageAsync(MessageRequest request);
+ Task> CreateMessageAsync(MessageRequest request, CancellationToken cancellationToken = default);
///
/// Creates a message asynchronously and streams the response.
///
/// The message request to create.
+ /// A token to cancel the asynchronous operation.
/// An asynchronous enumerable that yields the response event by event.
- IAsyncEnumerable CreateMessageAsync(StreamMessageRequest request);
+ IAsyncEnumerable CreateMessageAsync(StreamMessageRequest request, CancellationToken cancellationToken = default);
///
/// Creates a batch of messages asynchronously.
///
/// The message batch request to create.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an where T is .
- Task> CreateMessageBatchAsync(MessageBatchRequest request);
+ Task> CreateMessageBatchAsync(MessageBatchRequest request, CancellationToken cancellationToken = default);
///
/// Gets a message batch asynchronously.
///
/// The ID of the message batch to get.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an where T is .
- Task> GetMessageBatchAsync(string batchId);
+ Task> GetMessageBatchAsync(string batchId, CancellationToken cancellationToken = default);
///
/// Lists the message batches asynchronously.
///
/// The paging request to use for listing the message batches.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an where T is where T is .
- Task>> ListMessageBatchesAsync(PagingRequest? request = null);
+ Task>> ListMessageBatchesAsync(PagingRequest? request = null, CancellationToken cancellationToken = default);
///
/// Lists all message batches asynchronously.
///
/// The maximum number of message batches to return in each page.
+ /// A token to cancel the asynchronous operation.
/// An asynchronous enumerable that yields the response as an where T is where T is .
- IAsyncEnumerable>> ListAllMessageBatchesAsync(int limit = 20);
+ IAsyncEnumerable>> ListAllMessageBatchesAsync(int limit = 20, CancellationToken cancellationToken = default);
///
/// Cancels a message batch asynchronously.
///
/// The ID of the message batch to cancel.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an where T is .
- Task> CancelMessageBatchAsync(string batchId);
+ Task> CancelMessageBatchAsync(string batchId, CancellationToken cancellationToken = default);
///
/// Deletes a message batch asynchronously.
///
/// The ID of the message batch to delete.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an where T is .
- Task> DeleteMessageBatchAsync(string batchId);
+ Task> DeleteMessageBatchAsync(string batchId, CancellationToken cancellationToken = default);
///
/// Gets the results of a message batch asynchronously.
///
/// The ID of the message batch to get the results for.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an where T is where T is .
- Task>> GetMessageBatchResultsAsync(string batchId);
+ Task>> GetMessageBatchResultsAsync(string batchId, CancellationToken cancellationToken = default);
///
/// Counts the tokens in a message asynchronously.
///
/// The count message tokens request.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an where T is .
- Task> CountMessageTokensAsync(CountMessageTokensRequest request);
+ Task> CountMessageTokensAsync(CountMessageTokensRequest request, CancellationToken cancellationToken = default);
///
- /// Lists the models asynchronously.
+ /// Lists models asynchronously, returning a single page of results.
///
/// The paging request to use for listing the models.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an where T is where T is .
- Task>> ListModelsAsync(PagingRequest? request = null);
+ Task>> ListModelsAsync(PagingRequest? request = null, CancellationToken cancellationToken = default);
///
- /// Lists the models asynchronously
+ /// Lists all models asynchronously, returning every page of results.
///
/// The maximum number of models to return in each page.
+ /// A token to cancel the asynchronous operation.
/// An asynchronous enumerable that yields the response as an where T is where T is .
///
- IAsyncEnumerable>> ListAllModelsAsync(int limit = 20);
+ IAsyncEnumerable>> ListAllModelsAsync(int limit = 20, CancellationToken cancellationToken = default);
///
/// Gets a model by its ID asynchronously.
///
/// The ID of the model to get.
+ /// A token to cancel the asynchronous operation.
/// A task that represents the asynchronous operation. The task result contains the response as an where T is .
- Task> GetModelAsync(string modelId);
+ Task> GetModelAsync(string modelId, CancellationToken cancellationToken = default);
}
\ No newline at end of file
diff --git a/tests/AnthropicClient.Tests/AnthropicClient.Tests.csproj b/tests/AnthropicClient.Tests/AnthropicClient.Tests.csproj
index 0a5f3db..1962db3 100644
--- a/tests/AnthropicClient.Tests/AnthropicClient.Tests.csproj
+++ b/tests/AnthropicClient.Tests/AnthropicClient.Tests.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net9.0
enable
enable
false
@@ -10,21 +10,21 @@
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
@@ -54,7 +54,7 @@
PreserveNewest
-
+
PreserveNewest