feat: implement GetMessageBatchResultsAsync method

This commit is contained in:
Stevan Freeborn
2025-01-09 23:17:41 -06:00
parent 0a6d89bd77
commit c56adf394c
16 changed files with 294 additions and 23 deletions
@@ -1,10 +1,9 @@
using AnthropicClient.Tests.Files;
namespace AnthropicClient.Tests.EndToEnd;
public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(configFixture)
{
private string GetTestFilePath(string fileName) =>
Path.Combine(Directory.GetCurrentDirectory(), "Files", fileName);
[Fact]
public async Task CreateMessageAsync_WhenCalled_ItShouldReturnResponse()
{
@@ -63,7 +62,7 @@ public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(conf
[Fact]
public async Task CreateMessageAsync_WhenImageIsSent_ItShouldReturnResponse()
{
var imagePath = GetTestFilePath("elephant.jpg");
var imagePath = TestFileHelper.GetTestFilePath("elephant.jpg");
var mediaType = "image/jpeg";
var bytes = await File.ReadAllBytesAsync(imagePath);
var base64Data = Convert.ToBase64String(bytes);
@@ -102,7 +101,7 @@ public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(conf
{
var client = CreateClient(new HttpClient());
var storyPath = GetTestFilePath("story.txt");
var storyPath = TestFileHelper.GetTestFilePath("story.txt");
var storyText = await File.ReadAllTextAsync(storyPath);
var request = new MessageRequest(
@@ -141,7 +140,7 @@ public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(conf
{
var client = CreateClient(new HttpClient());
var storyPath = GetTestFilePath("story.txt");
var storyPath = TestFileHelper.GetTestFilePath("story.txt");
var storyText = await File.ReadAllTextAsync(storyPath);
var request = new MessageRequest(
@@ -217,7 +216,7 @@ public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(conf
[Fact]
public async Task CreateMessageAsync_WhenProvidedWithPDF_ItShouldReturnResponse()
{
var pdfPath = GetTestFilePath("addendum.pdf");
var pdfPath = TestFileHelper.GetTestFilePath("addendum.pdf");
var bytes = await File.ReadAllBytesAsync(pdfPath);
var base64Data = Convert.ToBase64String(bytes);
@@ -253,7 +252,7 @@ public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(conf
[Fact]
public async Task CreateMessageAsync_WhenProvidedWithPDFWithCacheControl_ItShouldUseCache()
{
var pdfPath = GetTestFilePath("addendum.pdf");
var pdfPath = TestFileHelper.GetTestFilePath("addendum.pdf");
var bytes = await File.ReadAllBytesAsync(pdfPath);
var base64Data = Convert.ToBase64String(bytes);
@@ -354,9 +353,9 @@ public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(conf
)
),
]);
var result = await _client.CreateMessageBatchAsync(request);
result.IsSuccess.Should().BeTrue();
result.Value.Should().BeOfType<MessageBatchResponse>();
result.Value.Id.Should().NotBeNullOrEmpty();
@@ -374,7 +373,7 @@ public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(conf
)
),
]);
var createResult = await _client.CreateMessageBatchAsync(request);
var getResult = await _client.GetMessageBatchAsync(createResult.Value.Id);
@@ -0,0 +1,7 @@
namespace AnthropicClient.Tests.Files;
static class TestFileHelper
{
public static string GetTestFilePath(string fileName) =>
Path.Combine(Directory.GetCurrentDirectory(), "Files", fileName);
}
@@ -0,0 +1,5 @@
{"custom_id":"my-fifth-request","result":{"type":"errored","error":{"type":"error","error":{"type":"not_found_error","message":"The requested resource could not be found."}}}}
{"custom_id":"my-fourth-request","result":{"type":"expired"}}
{"custom_id":"my-third-request","result":{"type":"canceled"}}
{"custom_id":"my-second-request","result":{"type":"succeeded","message":{"id":"msg_014VwiXbi91y3JMjcpyGBHX5","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"Hello again! It's nice to see you. How can I assist you today? Is there anything specific you'd like to chat about or any questions you have?"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":11,"output_tokens":36}}}}
{"custom_id":"my-first-request","result":{"type":"succeeded","message":{"id":"msg_01FqfsLoHwgeFbguDgpz48m7","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"Hello! How can I assist you today? Feel free to ask me any questions or let me know if there's anything you'd like to chat about."}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":10,"output_tokens":34}}}}
@@ -1,3 +1,6 @@
using AnthropicClient.Tests.Files;
using AnthropicClient.Tests.Unit;
namespace AnthropicClient.Tests.Integration;
public class AnthropicApiClientTests : IntegrationTest
@@ -1032,7 +1035,7 @@ public class AnthropicApiClientTests : IntegrationTest
result.Value.CancelInitiatedAt.Should().Be(DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"));
result.Value.ResultsUrl.Should().Be("https://api.anthropic.com/v1/messages/batches/msgbatch_013Zva2CMHLNnXjNJJKqJ2EF/results");
}
[Fact]
public async Task CreateMessageBatchAsync_WhenCalledAndErrorReturned_ItShouldHandleError()
{
@@ -1058,7 +1061,7 @@ public class AnthropicApiClientTests : IntegrationTest
result.Error.Should().BeOfType<AnthropicError>();
result.Error.Error.Should().BeOfType<InvalidRequestError>();
}
[Fact]
public async Task CreateMessageBatchAsync_WhenCalledRequestFailsAndErrorCanNotBeDeserialized_ItShouldReturnUnknownError()
{
@@ -1078,7 +1081,7 @@ public class AnthropicApiClientTests : IntegrationTest
result.Error.Should().BeOfType<AnthropicError>();
result.Error.Error.Should().BeOfType<ApiError>();
}
[Fact]
public async Task CreateMessageBatchAsync_WhenCalledRequestSucceedsAndCanNotDeserializeResponse_ItShouldReturnEmptyResponse()
{
@@ -1153,7 +1156,7 @@ public class AnthropicApiClientTests : IntegrationTest
result.Value.ResultsUrl.Should()
.Be("https://api.anthropic.com/v1/messages/batches/msgbatch_013Zva2CMHLNnXjNJJKqJ2EF/results");
}
[Fact]
public async Task GetMessageBatchAsync_WhenCalledAndErrorReturned_ItShouldHandleError()
{
@@ -1179,7 +1182,7 @@ public class AnthropicApiClientTests : IntegrationTest
result.Error.Should().BeOfType<AnthropicError>();
result.Error.Error.Should().BeOfType<InvalidRequestError>();
}
[Fact]
public async Task GetMessageBatchAsync_WhenCalledRequestFailsAndErrorCanNotBeDeserialized_ItShouldReturnUnknownError()
{
@@ -1199,7 +1202,7 @@ public class AnthropicApiClientTests : IntegrationTest
result.Error.Should().BeOfType<AnthropicError>();
result.Error.Error.Should().BeOfType<ApiError>();
}
[Fact]
public async Task GetMessageBatchAsync_WhenCalledAndCanNotDeserializeResponse_ItShouldReturnEmptyResponse()
{
@@ -1218,4 +1221,30 @@ public class AnthropicApiClientTests : IntegrationTest
result.IsSuccess.Should().BeTrue();
result.Value.Should().BeOfType<MessageBatchResponse>();
}
[Fact]
public async Task GetMessageBatchResultsAsync_WhenCalledAndSuccessful_ItShouldReturnAllBatchResults()
{
var batchId = "msgbatch_013Zva2CMHLNnXjNJJKqJ2EF";
var batchResultsPath = TestFileHelper.GetTestFilePath("batch_results.jsonl");
var batchResultsText = await File.ReadAllTextAsync(batchResultsPath);
var batchResults = batchResultsText.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
var expectedResults = batchResults.Select(Deserialize<MessageBatchResultItem>);
_mockHttpMessageHandler
.WhenGetMessageBatchResultsRequest(batchId)
.Respond(
HttpStatusCode.OK,
"application/x-jsonl",
batchResultsText
);
var result = await Client.GetMessageBatchResultsAsync(batchId);
result.IsSuccess.Should().BeTrue();
var actualResults = await result.Value.ToListAsync();
actualResults.Should().BeEquivalentTo(expectedResults);
}
}
@@ -1,6 +1,8 @@
using AnthropicClient.Tests.Unit;
namespace AnthropicClient.Tests.Integration;
public class IntegrationTest
public class IntegrationTest : SerializationTest
{
protected readonly MockHttpMessageHandler _mockHttpMessageHandler = new();
protected AnthropicApiClient Client => CreateClient();
@@ -71,10 +73,16 @@ public static class MockHttpMessageHandlerExtensions
return mockHttpMessageHandler
.SetupBaseRequest(HttpMethod.Post, MessageBatchesEndpoint);
}
public static MockedRequest WhenGetMessageBatchRequest(this MockHttpMessageHandler mockHttpMessageHandler, string batchId)
{
return mockHttpMessageHandler
.SetupBaseRequest(HttpMethod.Get, $"{MessageBatchesEndpoint}/{batchId}");
}
public static MockedRequest WhenGetMessageBatchResultsRequest(this MockHttpMessageHandler mockHttpMessageHandler, string batchId)
{
return mockHttpMessageHandler
.SetupBaseRequest(HttpMethod.Get, $"{MessageBatchesEndpoint}/{batchId}/results");
}
}
@@ -0,0 +1,14 @@
namespace AnthropicClient.Tests.Unit.Models;
public class MessageBatchResultItemTests
{
[Fact]
public void Constructor_WhenCalled_ItShouldReturnInstanceWithPropertiesSet()
{
var result = new MessageBatchResultItem();
result.Should().BeOfType<MessageBatchResultItem>();
result.CustomId.Should().BeEmpty();
result.Result.Should().Be(default);
}
}