From 8e0443a6bb4736207d5ddf173f8ec966d03cec46 Mon Sep 17 00:00:00 2001
From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com>
Date: Sun, 5 Jan 2025 21:20:27 -0600
Subject: [PATCH] feat: implement ListAllModelsAsync and ListModelsAsync
---
src/AnthropicClient/AnthropicApiClient.cs | 81 +++-
src/AnthropicClient/Models/Page.cs | 4 +-
src/AnthropicClient/Models/PagingRequest.cs | 5 +-
.../EndToEnd/AnthropicApiClientTests.cs | 28 ++
.../Integration/AnthropicApiClientTests.cs | 419 +++++++++++++++++-
.../Integration/IntegrationTest.cs | 7 +
.../Unit/Models/PagingRequestTests.cs | 6 +-
7 files changed, 507 insertions(+), 43 deletions(-)
diff --git a/src/AnthropicClient/AnthropicApiClient.cs b/src/AnthropicClient/AnthropicApiClient.cs
index 9a92093..836a6bd 100644
--- a/src/AnthropicClient/AnthropicApiClient.cs
+++ b/src/AnthropicClient/AnthropicApiClient.cs
@@ -1,6 +1,7 @@
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
+using System.Threading.Tasks;
using AnthropicClient.Json;
using AnthropicClient.Models;
@@ -39,15 +40,15 @@ public interface IAnthropicApiClient
///
/// The paging request to use for listing the models.
/// 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);
+ Task>> ListModelsAsync(PagingRequest? request = null);
///
- /// Lists the models asynchronously.
+ /// Lists the models asynchronously
///
/// The maximum number of models to return in each page.
/// An asynchronous enumerable that yields the response as an where T is where T is .
///
- IAsyncEnumerable>> ListModelsAsync(int limit = 20);
+ IAsyncEnumerable>> ListAllModelsAsync(int limit = 20);
}
///
@@ -57,6 +58,7 @@ public class AnthropicApiClient : IAnthropicApiClient
private const string ApiKeyHeader = "x-api-key";
private const string MessagesEndpoint = "messages";
private const string CountTokensEndpoint = "messages/count_tokens";
+ private const string ModelsEndpoint = "models";
private const string JsonContentType = "application/json";
private const string EventPrefix = "event:";
private const string DataPrefix = "data:";
@@ -292,10 +294,64 @@ public class AnthropicApiClient : IAnthropicApiClient
}
var msgResponse = Deserialize(responseContent) ?? new TokenCountResponse();
-
return AnthropicResult.Success(msgResponse, anthropicHeaders);
}
+ ///
+ public async Task>> ListModelsAsync(PagingRequest? request = null)
+ {
+ var pagingRequest = request ?? new PagingRequest();
+ var endpoint = $"{ModelsEndpoint}?{pagingRequest.ToQueryParameters()}";
+ var response = await SendRequestAsync(endpoint);
+ var anthropicHeaders = new AnthropicHeaders(response.Headers);
+ var responseContent = await response.Content.ReadAsStringAsync();
+
+ if (response.IsSuccessStatusCode is false)
+ {
+ var error = Deserialize(responseContent) ?? new AnthropicError();
+ return AnthropicResult>.Failure(error, anthropicHeaders);
+ }
+
+ var page = Deserialize>(responseContent) ?? new Page();
+ return AnthropicResult>.Success(page, anthropicHeaders);
+ }
+
+ ///
+ public async IAsyncEnumerable>> ListAllModelsAsync(int limit = 20)
+ {
+ var pagingRequest = new PagingRequest(limit: limit);
+ string Endpoint() => $"{ModelsEndpoint}?{pagingRequest.ToQueryParameters()}";
+ bool hasMore;
+
+ do
+ {
+ var response = await SendRequestAsync(Endpoint());
+ var anthropicHeaders = new AnthropicHeaders(response.Headers);
+ var responseContent = await response.Content.ReadAsStringAsync();
+
+ if (response.IsSuccessStatusCode is false)
+ {
+ var error = Deserialize(responseContent) ?? new AnthropicError();
+ yield return AnthropicResult>.Failure(error, anthropicHeaders);
+ yield break;
+ }
+
+ var page = Deserialize>(responseContent) ?? new Page();
+
+ if (page.HasMore && page.LastId is not null)
+ {
+ hasMore = true;
+ pagingRequest = new PagingRequest(limit: limit, afterId: page.LastId);
+ }
+ else
+ {
+ hasMore = false;
+ }
+
+ yield return AnthropicResult>.Success(page, anthropicHeaders);
+ } while (hasMore);
+ }
+
private ToolCall? GetToolCall(MessageResponse response, List tools)
{
var toolUse = response.Content.OfType().FirstOrDefault();
@@ -315,6 +371,11 @@ public class AnthropicApiClient : IAnthropicApiClient
return new ToolCall(tool, toolUse);
}
+ private async Task SendRequestAsync(string endpoint)
+ {
+ return await _httpClient.GetAsync(endpoint);
+ }
+
private async Task SendRequestAsync(string endpoint, T request)
{
var requestJson = Serialize(request);
@@ -324,16 +385,4 @@ public class AnthropicApiClient : IAnthropicApiClient
private string Serialize(T obj) => JsonSerializer.Serialize(obj, JsonSerializationOptions.DefaultOptions);
private T? Deserialize(string json) => JsonSerializer.Deserialize(json, JsonSerializationOptions.DefaultOptions);
-
- ///
- public Task>> ListModelsAsync(PagingRequest request)
- {
- throw new NotImplementedException();
- }
-
- ///
- public IAsyncEnumerable>> ListModelsAsync(int limit = 20)
- {
- throw new NotImplementedException();
- }
}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/Page.cs b/src/AnthropicClient/Models/Page.cs
index e0ec5a8..729d90b 100644
--- a/src/AnthropicClient/Models/Page.cs
+++ b/src/AnthropicClient/Models/Page.cs
@@ -11,13 +11,13 @@ public class Page
/// The id of the first item in the page.
///
[JsonPropertyName("first_id")]
- public string FirstId { get; init; } = string.Empty;
+ public string? FirstId { get; init; } = string.Empty;
///
/// The id of the last item in the page.
///
[JsonPropertyName("last_id")]
- public string LastId { get; init; } = string.Empty;
+ public string? LastId { get; init; } = string.Empty;
///
/// Indicates whether there is more data to be retrieved.
diff --git a/src/AnthropicClient/Models/PagingRequest.cs b/src/AnthropicClient/Models/PagingRequest.cs
index b7aad83..f8b415a 100644
--- a/src/AnthropicClient/Models/PagingRequest.cs
+++ b/src/AnthropicClient/Models/PagingRequest.cs
@@ -70,10 +70,7 @@ public class PagingRequest
parameters.Add($"after_id={AfterId}");
}
- if (Limit is not DefaultLimit)
- {
- parameters.Add($"limit={Limit}");
- }
+ parameters.Add($"limit={Limit}");
return string.Join("&", parameters);
}
diff --git a/tests/AnthropicClient.Tests/EndToEnd/AnthropicApiClientTests.cs b/tests/AnthropicClient.Tests/EndToEnd/AnthropicApiClientTests.cs
index 50dab64..e64893a 100644
--- a/tests/AnthropicClient.Tests/EndToEnd/AnthropicApiClientTests.cs
+++ b/tests/AnthropicClient.Tests/EndToEnd/AnthropicApiClientTests.cs
@@ -303,4 +303,32 @@ public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(conf
result.Value.Should().BeOfType();
result.Value.InputTokens.Should().BeGreaterThan(0);
}
+
+ [Fact]
+ public async Task ListModelsAsync_WhenCalled_ItShouldReturnResponse()
+ {
+ var result = await _client.ListModelsAsync();
+
+ result.IsSuccess.Should().BeTrue();
+ result.Value.Should().BeOfType>();
+ result.Value.Data.Should().HaveCountGreaterThan(0);
+ }
+
+ [Fact]
+ public async Task ListModelsAsync_WhenCalledWithPagination_ItShouldReturnResponse()
+ {
+ var result = await _client.ListModelsAsync(new PagingRequest(limit: 1));
+
+ result.IsSuccess.Should().BeTrue();
+ result.Value.Should().BeOfType>();
+ result.Value.Data.Should().HaveCount(1);
+ }
+
+ [Fact]
+ public async Task ListAllModelsAsync_WhenCalled_ItShouldReturnResponse()
+ {
+ var responses = await _client.ListAllModelsAsync(limit: 1).ToListAsync();
+
+ responses.Should().HaveCountGreaterThan(0);
+ }
}
\ No newline at end of file
diff --git a/tests/AnthropicClient.Tests/Integration/AnthropicApiClientTests.cs b/tests/AnthropicClient.Tests/Integration/AnthropicApiClientTests.cs
index f874a31..795b132 100644
--- a/tests/AnthropicClient.Tests/Integration/AnthropicApiClientTests.cs
+++ b/tests/AnthropicClient.Tests/Integration/AnthropicApiClientTests.cs
@@ -57,7 +57,7 @@ public class AnthropicApiClientTests : IntegrationTest
""input_tokens"": 10,
""output_tokens"": 25
}
- }"
+ }"
);
var request = new MessageRequest(
@@ -115,7 +115,7 @@ public class AnthropicApiClientTests : IntegrationTest
""input_tokens"": 10,
""output_tokens"": 25
}
- }"
+ }"
);
var func = (string ticker) => ticker;
@@ -191,7 +191,7 @@ public class AnthropicApiClientTests : IntegrationTest
""input_tokens"": 10,
""output_tokens"": 25
}
- }"
+ }"
);
var request = new MessageRequest(
@@ -331,12 +331,12 @@ public class AnthropicApiClientTests : IntegrationTest
HttpStatusCode.BadRequest,
"application/json",
@"{
- ""type"": ""error"",
- ""error"": {
- ""type"": ""invalid_request_error"",
- ""message"": ""messages: roles must alternate between user and assistant, but found multiple user roles in a row""
- }
- }"
+ ""type"": ""error"",
+ ""error"": {
+ ""type"": ""invalid_request_error"",
+ ""message"": ""messages: roles must alternate between user and assistant, but found multiple user roles in a row""
+ }
+ }"
);
var request = new StreamMessageRequest(
@@ -385,7 +385,7 @@ public class AnthropicApiClientTests : IntegrationTest
""input_tokens"": 10,
""output_tokens"": 25
}
- }"
+ }"
);
var request = new MessageRequest(
@@ -428,8 +428,8 @@ public class AnthropicApiClientTests : IntegrationTest
HttpStatusCode.OK,
"application/json",
@"{
- ""input_tokens"": 10
- }"
+ ""input_tokens"": 10
+ }"
);
var request = new CountMessageTokensRequest(
@@ -455,12 +455,12 @@ public class AnthropicApiClientTests : IntegrationTest
HttpStatusCode.BadRequest,
"application/json",
@"{
- ""type"": ""error"",
- ""error"": {
- ""type"": ""invalid_request_error"",
- ""message"": ""messages: roles must alternate between user and assistant, but found multiple user roles in a row""
- }
- }"
+ ""type"": ""error"",
+ ""error"": {
+ ""type"": ""invalid_request_error"",
+ ""message"": ""messages: roles must alternate between user and assistant, but found multiple user roles in a row""
+ }
+ }"
);
var request = new CountMessageTokensRequest(
@@ -503,4 +503,387 @@ public class AnthropicApiClientTests : IntegrationTest
result.Error.Should().BeOfType();
result.Error.Error.Should().BeOfType();
}
+
+ [Fact]
+ public async Task ListModelsAsync_WhenCalledWithPagingRequestUsingDefaultValues_ItShouldReturnListOfModels()
+ {
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .Respond(
+ HttpStatusCode.OK,
+ "application/json",
+ @"{
+ ""data"": [
+ {
+ ""type"": ""model"",
+ ""id"": ""claude-3-5-sonnet-20241022"",
+ ""display_name"": ""Claude 3.5 Sonnet (New)"",
+ ""created_at"": ""2024-10-22T00:00:00Z""
+ }
+ ],
+ ""has_more"": true,
+ ""first_id"": ""first_id"",
+ ""last_id"": ""last_id""
+ }"
+ );
+
+ var result = await Client.ListModelsAsync();
+
+ result.IsSuccess.Should().BeTrue();
+ result.Value.Should().BeOfType>();
+ result.Value.HasMore.Should().BeTrue();
+ result.Value.FirstId.Should().Be("first_id");
+ result.Value.LastId.Should().Be("last_id");
+ result.Value.Data.Should().BeEquivalentTo(new AnthropicModel[]
+ {
+ new()
+ {
+ Type = "model",
+ Id = "claude-3-5-sonnet-20241022",
+ DisplayName = "Claude 3.5 Sonnet (New)",
+ CreatedAt = DateTimeOffset.Parse("2024-10-22T00:00:00Z")
+ }
+ });
+ }
+
+ [Fact]
+ public async Task ListModelsAsync_WhenCalledWithPagingRequestUsingCustomValues_ItShouldReturnListOfModels()
+ {
+ var pagingRequest = new PagingRequest("prev_id", "next_id", 10);
+
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .WithQueryString(new Dictionary
+ {
+ { "before_id", pagingRequest.BeforeId },
+ { "after_id", pagingRequest.AfterId },
+ { "limit", pagingRequest.Limit.ToString() },
+ })
+ .Respond(
+ HttpStatusCode.OK,
+ "application/json",
+ @"{
+ ""data"": [
+ {
+ ""type"": ""model"",
+ ""id"": ""claude-3-5-sonnet-20241022"",
+ ""display_name"": ""Claude 3.5 Sonnet (New)"",
+ ""created_at"": ""2024-10-22T00:00:00Z""
+ }
+ ],
+ ""has_more"": true,
+ ""first_id"": ""first_id"",
+ ""last_id"": ""last_id""
+ }"
+ );
+
+ var result = await Client.ListModelsAsync(pagingRequest);
+
+ result.IsSuccess.Should().BeTrue();
+ result.Value.Should().BeOfType>();
+ result.Value.HasMore.Should().BeTrue();
+ result.Value.FirstId.Should().Be("first_id");
+ result.Value.LastId.Should().Be("last_id");
+ result.Value.Data.Should().BeEquivalentTo(new AnthropicModel[]
+ {
+ new()
+ {
+ Type = "model",
+ Id = "claude-3-5-sonnet-20241022",
+ DisplayName = "Claude 3.5 Sonnet (New)",
+ CreatedAt = DateTimeOffset.Parse("2024-10-22T00:00:00Z")
+ }
+ });
+ }
+
+ [Fact]
+ public async Task ListModelsAsync_WhenCalledAndNoModelsReturned_ItShouldReturnEmptyList()
+ {
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .Respond(
+ HttpStatusCode.OK,
+ "application/json",
+ @"{
+ ""data"": [],
+ ""has_more"": false,
+ ""first_id"": null,
+ ""last_id"": null
+ }"
+ );
+
+ var result = await Client.ListModelsAsync();
+
+ result.IsSuccess.Should().BeTrue();
+ result.Value.Should().BeOfType>();
+ result.Value.HasMore.Should().BeFalse();
+ result.Value.FirstId.Should().BeNull();
+ result.Value.LastId.Should().BeNull();
+ result.Value.Data.Should().BeEmpty();
+ }
+
+ [Fact]
+ public async Task ListModelsAsync_WhenCalledAndErrorReturned_ItShouldHandleError()
+ {
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .Respond(
+ HttpStatusCode.BadRequest,
+ "application/json",
+ @"{
+ ""type"": ""error"",
+ ""error"": {
+ ""type"": ""invalid_request_error"",
+ ""message"": ""messages: roles must alternate between user and assistant, but found multiple user roles in a row""
+ }
+ }"
+ );
+
+ var result = await Client.ListModelsAsync();
+
+ result.IsSuccess.Should().BeFalse();
+ result.Error.Should().BeOfType();
+ result.Error.Error.Should().BeOfType();
+ }
+
+ [Fact]
+ public async Task ListModelsAsync_WhenCalledRequestFailsAndCanNotSerializeError_ItShouldReturnUnknownError()
+ {
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .Respond(
+ HttpStatusCode.BadRequest,
+ "application/json",
+ @"{}"
+ );
+
+ var result = await Client.ListModelsAsync();
+
+ result.IsSuccess.Should().BeFalse();
+ result.Error.Should().BeOfType();
+ result.Error.Error.Should().BeOfType();
+ }
+
+ [Fact]
+ public async Task ListAllModelsAsync_WhenCalled_ItShouldReturnAllModels()
+ {
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .WithExactQueryString(new Dictionary()
+ {
+ { "limit", "20" },
+ })
+ .Respond(
+ HttpStatusCode.OK,
+ "application/json",
+ @"{
+ ""data"": [
+ {
+ ""type"": ""model"",
+ ""id"": ""claude-3-5-sonnet-20241022"",
+ ""display_name"": ""Claude 3.5 Sonnet (New)"",
+ ""created_at"": ""2024-10-22T00:00:00Z""
+ }
+ ],
+ ""has_more"": true,
+ ""first_id"": ""1"",
+ ""last_id"": ""1""
+ }"
+ );
+
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .WithExactQueryString(new Dictionary()
+ {
+ { "after_id", "1" },
+ { "limit", "20" },
+ })
+ .Respond(
+ HttpStatusCode.OK,
+ "application/json",
+ @"{
+ ""data"": [
+ {
+ ""type"": ""model"",
+ ""id"": ""claude-3-5-sonnet-20241023"",
+ ""display_name"": ""Claude 3.5 Sonnet (New)"",
+ ""created_at"": ""2024-10-23T00:00:00Z""
+ }
+ ],
+ ""has_more"": false,
+ ""first_id"": ""2"",
+ ""last_id"": ""2""
+ }"
+ );
+
+ var pageResponses = Client.ListAllModelsAsync();
+ var collectedPages = new List>();
+
+ await foreach (var response in pageResponses)
+ {
+ response.IsSuccess.Should().BeTrue();
+ response.Value.Should().BeOfType>();
+ collectedPages.Add(response.Value);
+ }
+
+ collectedPages.Should().HaveCount(2);
+ collectedPages.Should().BeEquivalentTo(new Page[]
+ {
+ new()
+ {
+ HasMore = true,
+ FirstId = "1",
+ LastId = "1",
+ Data = [
+ new()
+ {
+ Type = "model",
+ Id = "claude-3-5-sonnet-20241022",
+ DisplayName = "Claude 3.5 Sonnet (New)",
+ CreatedAt = DateTimeOffset.Parse("2024-10-22T00:00:00Z")
+ }
+ ]
+ },
+ new()
+ {
+ HasMore = false,
+ FirstId = "2",
+ LastId = "2",
+ Data = [
+ new()
+ {
+ Type = "model",
+ Id = "claude-3-5-sonnet-20241023",
+ DisplayName = "Claude 3.5 Sonnet (New)",
+ CreatedAt = DateTimeOffset.Parse("2024-10-23T00:00:00Z")
+ }
+ ]
+ }
+ });
+ }
+
+ [Fact]
+ public async Task ListAllModelsAsync_WhenCalledAndErrorReturned_ItShouldHandleError()
+ {
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .Respond(
+ HttpStatusCode.BadRequest,
+ "application/json",
+ @"{
+ ""type"": ""error"",
+ ""error"": {
+ ""type"": ""invalid_request_error"",
+ ""message"": ""messages: roles must alternate between user and assistant, but found multiple user roles in a row""
+ }
+ }"
+ );
+
+ var responses = Client.ListAllModelsAsync();
+ var count = 0;
+
+ await foreach (var page in responses)
+ {
+ count++;
+ page.IsSuccess.Should().BeFalse();
+ page.Error.Should().BeOfType();
+ page.Error.Error.Should().BeOfType();
+ }
+
+ count.Should().Be(1);
+ }
+
+ [Fact]
+ public async Task ListAllModelsAsync_WhenCalledRequestFailsAndCanNotSerializeError_ItShouldReturnUnknownError()
+ {
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .Respond(
+ HttpStatusCode.BadRequest,
+ "application/json",
+ @"{}"
+ );
+
+ var responses = Client.ListAllModelsAsync();
+ var count = 0;
+
+ await foreach (var page in responses)
+ {
+ count++;
+ page.IsSuccess.Should().BeFalse();
+ page.Error.Should().BeOfType();
+ page.Error.Error.Should().BeOfType();
+ }
+
+ count.Should().Be(1);
+ }
+
+ [Fact]
+ public async Task ListAllModelsAsync_WhenFirstPageSucceedsAndSecondPageFails_ItShouldReturnFirstPageAndError()
+ {
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .WithExactQueryString(new Dictionary
+ {
+ { "limit", "20" },
+ })
+ .Respond(
+ HttpStatusCode.OK,
+ "application/json",
+ @"{
+ ""data"": [
+ {
+ ""type"": ""model"",
+ ""id"": ""claude-3-5-sonnet-20241022"",
+ ""display_name"": ""Claude 3.5 Sonnet (New)"",
+ ""created_at"": ""2024-10-22T00:00:00Z""
+ }
+ ],
+ ""has_more"": true,
+ ""first_id"": ""1"",
+ ""last_id"": ""1""
+ }"
+ );
+
+ _mockHttpMessageHandler
+ .WhenListModelsRequest()
+ .WithExactQueryString(new Dictionary
+ {
+ { "after_id", "1" },
+ { "limit", "20" },
+ })
+ .Respond(
+ HttpStatusCode.BadRequest,
+ "application/json",
+ @"{
+ ""type"": ""error"",
+ ""error"": {
+ ""type"": ""invalid_request_error"",
+ ""message"": ""messages: roles must alternate between user and assistant, but found multiple user roles in a row""
+ }
+ }"
+ );
+
+ var responses = Client.ListAllModelsAsync();
+ var count = 0;
+
+ await foreach (var page in responses)
+ {
+ count++;
+
+ if (count == 1)
+ {
+ page.IsSuccess.Should().BeTrue();
+ page.Value.Should().BeOfType>();
+ }
+ else
+ {
+ page.IsSuccess.Should().BeFalse();
+ page.Error.Should().BeOfType();
+ page.Error.Error.Should().BeOfType();
+ }
+ }
+
+ count.Should().Be(2);
+ }
}
\ No newline at end of file
diff --git a/tests/AnthropicClient.Tests/Integration/IntegrationTest.cs b/tests/AnthropicClient.Tests/Integration/IntegrationTest.cs
index fd04cec..1d5b77a 100644
--- a/tests/AnthropicClient.Tests/Integration/IntegrationTest.cs
+++ b/tests/AnthropicClient.Tests/Integration/IntegrationTest.cs
@@ -16,6 +16,7 @@ public static class MockHttpMessageHandlerExtensions
private const string BaseUrl = "https://api.anthropic.com/v1";
private static readonly string MessagesEndpoint = $"{BaseUrl}/messages";
private static readonly string CountTokensEndpoint = $"{BaseUrl}/messages/count_tokens";
+ private static readonly string ModelsEndpoint = $"{BaseUrl}/models";
private static MockedRequest SetupBaseRequest(
this MockHttpMessageHandler mockHttpMessageHandler,
@@ -51,4 +52,10 @@ public static class MockHttpMessageHandlerExtensions
return mockHttpMessageHandler
.SetupBaseRequest(HttpMethod.Post, CountTokensEndpoint);
}
+
+ public static MockedRequest WhenListModelsRequest(this MockHttpMessageHandler mockHttpMessageHandler)
+ {
+ return mockHttpMessageHandler
+ .SetupBaseRequest(HttpMethod.Get, ModelsEndpoint);
+ }
}
\ No newline at end of file
diff --git a/tests/AnthropicClient.Tests/Unit/Models/PagingRequestTests.cs b/tests/AnthropicClient.Tests/Unit/Models/PagingRequestTests.cs
index 54e6c8f..069120c 100644
--- a/tests/AnthropicClient.Tests/Unit/Models/PagingRequestTests.cs
+++ b/tests/AnthropicClient.Tests/Unit/Models/PagingRequestTests.cs
@@ -25,7 +25,7 @@ public class PagingRequestTests : SerializationTest
var result = pagingRequest.ToQueryParameters();
- result.Should().BeEmpty();
+ result.Should().Be("limit=20");
}
[Fact]
@@ -35,7 +35,7 @@ public class PagingRequestTests : SerializationTest
var result = pagingRequest.ToQueryParameters();
- result.Should().Be("before_id=before-id");
+ result.Should().Be("before_id=before-id&limit=20");
}
[Fact]
@@ -45,7 +45,7 @@ public class PagingRequestTests : SerializationTest
var result = pagingRequest.ToQueryParameters();
- result.Should().Be("after_id=after-id");
+ result.Should().Be("after_id=after-id&limit=20");
}
[Fact]