feat: implement CreateMessageBatchAsync method
This commit is contained in:
@@ -978,4 +978,58 @@ public class AnthropicApiClientTests : IntegrationTest
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value.Should().BeOfType<AnthropicModel>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateMessageBatchAsync_WhenCalled_ItShouldReturnBatch()
|
||||
{
|
||||
_mockHttpMessageHandler
|
||||
.WhenCreateMessageBatchRequest()
|
||||
.Respond(
|
||||
HttpStatusCode.OK,
|
||||
"application/json",
|
||||
@"{
|
||||
""id"": ""msgbatch_013Zva2CMHLNnXjNJJKqJ2EF"",
|
||||
""type"": ""message_batch"",
|
||||
""processing_status"": ""in_progress"",
|
||||
""request_counts"": {
|
||||
""processing"": 100,
|
||||
""succeeded"": 50,
|
||||
""errored"": 30,
|
||||
""canceled"": 10,
|
||||
""expired"": 10
|
||||
},
|
||||
""ended_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""created_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""expires_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""archived_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""cancel_initiated_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""results_url"": ""https://api.anthropic.com/v1/messages/batches/msgbatch_013Zva2CMHLNnXjNJJKqJ2EF/results""
|
||||
}"
|
||||
);
|
||||
|
||||
var request = new MessageBatchRequest([new("custom_id", new())]);
|
||||
|
||||
var result = await Client.CreateMessageBatchAsync(request);
|
||||
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
result.Value.Should().BeOfType<MessageBatchResponse>();
|
||||
result.Value.Id.Should().Be("msgbatch_013Zva2CMHLNnXjNJJKqJ2EF");
|
||||
result.Value.Type.Should().Be("message_batch");
|
||||
result.Value.ProcessingStatus.Should().Be("in_progress");
|
||||
result.Value.RequestCounts.Should().BeEquivalentTo(new MessageBatchRequestCounts
|
||||
{
|
||||
Processing = 100,
|
||||
Succeeded = 50,
|
||||
Errored = 30,
|
||||
Canceled = 10,
|
||||
Expired = 10
|
||||
});
|
||||
|
||||
result.Value.EndedAt.Should().Be(DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"));
|
||||
result.Value.CreatedAt.Should().Be(DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"));
|
||||
result.Value.ExpiresAt.Should().Be(DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"));
|
||||
result.Value.ArchivedAt.Should().Be(DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"));
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -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 MessageBatchesEndpoint = $"{BaseUrl}/messages/batches";
|
||||
private static readonly string ModelsEndpoint = $"{BaseUrl}/models";
|
||||
|
||||
private static MockedRequest SetupBaseRequest(
|
||||
@@ -64,4 +65,10 @@ public static class MockHttpMessageHandlerExtensions
|
||||
return mockHttpMessageHandler
|
||||
.SetupBaseRequest(HttpMethod.Get, $"{ModelsEndpoint}/{modelId}");
|
||||
}
|
||||
|
||||
public static MockedRequest WhenCreateMessageBatchRequest(this MockHttpMessageHandler mockHttpMessageHandler)
|
||||
{
|
||||
return mockHttpMessageHandler
|
||||
.SetupBaseRequest(HttpMethod.Post, MessageBatchesEndpoint);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
namespace AnthropicClient.Tests.Unit.Models;
|
||||
|
||||
public class MessageBatchRequestItemTests : SerializationTest
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_WhenCalled_ItShouldReturnInstanceWithPropertiesSet()
|
||||
{
|
||||
var customId = "custom_id";
|
||||
var messageRequest = new MessageRequest();
|
||||
|
||||
var result = new MessageBatchRequestItem(customId, messageRequest);
|
||||
|
||||
result.Should().BeOfType<MessageBatchRequestItem>();
|
||||
result.CustomId.Should().Be(customId);
|
||||
result.Params.Should().BeSameAs(messageRequest);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
[InlineData(null)]
|
||||
public void Constructor_WhenCalledAndCustomIdIsInvalid_ItShouldThrowException(string? customId)
|
||||
{
|
||||
var act = () => new MessageBatchRequestItem(customId!, new MessageRequest());
|
||||
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WhenCalledAndMessageRequestIsNull_ItShouldThrowException()
|
||||
{
|
||||
var act = () => new MessageBatchRequestItem("custom_id", null!);
|
||||
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
namespace AnthropicClient.Tests.Unit.Models;
|
||||
|
||||
public class MessageBatchRequestTests : SerializationTest
|
||||
{
|
||||
private const string SampleJson = @"{
|
||||
""requests"": [
|
||||
{
|
||||
""custom_id"": ""my-first-request"",
|
||||
""params"": {
|
||||
""model"": ""claude-3-5-sonnet-20241022"",
|
||||
""messages"": [
|
||||
{""role"": ""user"", ""content"": [{ ""text"": ""Hello, world"", ""type"": ""text"" }]}
|
||||
],
|
||||
""max_tokens"": 1024,
|
||||
""stop_sequences"": [],
|
||||
""temperature"": 0.0,
|
||||
""stream"": false
|
||||
}
|
||||
},
|
||||
{
|
||||
""custom_id"": ""my-second-request"",
|
||||
""params"": {
|
||||
""model"": ""claude-3-5-sonnet-20241022"",
|
||||
""messages"": [
|
||||
{""role"": ""user"", ""content"": [{ ""text"": ""Hi again, friend"", ""type"": ""text"" }]}
|
||||
],
|
||||
""max_tokens"": 1024,
|
||||
""stop_sequences"": [],
|
||||
""temperature"": 0.0,
|
||||
""stream"": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WhenCalled_ItShouldReturnInstanceWithPropertiesSet()
|
||||
{
|
||||
var requests = new List<MessageBatchRequestItem> { new("custom_id", new()) };
|
||||
|
||||
var result = new MessageBatchRequest(requests);
|
||||
|
||||
result.Should().BeOfType<MessageBatchRequest>();
|
||||
result.Requests.Should().BeSameAs(requests);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WhenCalledWithEmptyRequests_ItShouldThrowException()
|
||||
{
|
||||
var act = () => new MessageBatchRequest([]);
|
||||
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonSerialization_WhenSerialized_ItShouldHaveExpectedShape()
|
||||
{
|
||||
var requests = new List<MessageBatchRequestItem>
|
||||
{
|
||||
new("my-first-request", new()
|
||||
{
|
||||
Model = "claude-3-5-sonnet-20241022",
|
||||
MaxTokens = 1024,
|
||||
Messages = [
|
||||
new() { Role = "user", Content = [new TextContent("Hello, world")] }
|
||||
]
|
||||
}),
|
||||
new("my-second-request", new()
|
||||
{
|
||||
Model = "claude-3-5-sonnet-20241022",
|
||||
MaxTokens = 1024,
|
||||
Messages = [
|
||||
new() { Role = "user", Content = [new TextContent("Hi again, friend")] }
|
||||
]
|
||||
})
|
||||
};
|
||||
|
||||
var result = new MessageBatchRequest(requests);
|
||||
|
||||
var json = Serialize(result);
|
||||
|
||||
JsonAssert.Equal(SampleJson, json);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
namespace AnthropicClient.Tests.Unit.Models;
|
||||
|
||||
public class MessageBatchResponseTests : SerializationTest
|
||||
{
|
||||
private const string SampleJson = @"{
|
||||
""id"": ""msgbatch_013Zva2CMHLNnXjNJJKqJ2EF"",
|
||||
""type"": ""message_batch"",
|
||||
""processing_status"": ""in_progress"",
|
||||
""request_counts"": {
|
||||
""processing"": 100,
|
||||
""succeeded"": 50,
|
||||
""errored"": 30,
|
||||
""canceled"": 10,
|
||||
""expired"": 10
|
||||
},
|
||||
""ended_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""created_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""expires_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""archived_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""cancel_initiated_at"": ""2024-08-20T18:37:24.100435Z"",
|
||||
""results_url"": ""https://api.anthropic.com/v1/messages/batches/msgbatch_013Zva2CMHLNnXjNJJKqJ2EF/results""
|
||||
}";
|
||||
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WhenCalled_ItShouldReturnInstanceWithPropertiesSet()
|
||||
{
|
||||
var result = new MessageBatchResponse();
|
||||
|
||||
result.Should().BeOfType<MessageBatchResponse>();
|
||||
result.Id.Should().BeEmpty();
|
||||
result.Type.Should().BeEmpty();
|
||||
result.ProcessingStatus.Should().BeEmpty();
|
||||
result.RequestCounts.Should().BeEquivalentTo(new MessageBatchRequestCounts());
|
||||
result.EndedAt.Should().Be(DateTimeOffset.MinValue);
|
||||
result.CreatedAt.Should().Be(DateTimeOffset.MinValue);
|
||||
result.ExpiresAt.Should().Be(DateTimeOffset.MinValue);
|
||||
result.ArchivedAt.Should().Be(DateTimeOffset.MinValue);
|
||||
result.CancelInitiatedAt.Should().Be(DateTimeOffset.MinValue);
|
||||
result.ResultsUrl.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonSerialization_WhenDeserialized_ItShouldHaveExpectedValues()
|
||||
{
|
||||
var result = Deserialize<MessageBatchResponse>(SampleJson);
|
||||
|
||||
result.Should().BeEquivalentTo(new MessageBatchResponse
|
||||
{
|
||||
Id = "msgbatch_013Zva2CMHLNnXjNJJKqJ2EF",
|
||||
Type = "message_batch",
|
||||
ProcessingStatus = "in_progress",
|
||||
RequestCounts = new MessageBatchRequestCounts
|
||||
{
|
||||
Processing = 100,
|
||||
Succeeded = 50,
|
||||
Errored = 30,
|
||||
Canceled = 10,
|
||||
Expired = 10
|
||||
},
|
||||
EndedAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
CreatedAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
ExpiresAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
ArchivedAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
CancelInitiatedAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
ResultsUrl = "https://api.anthropic.com/v1/messages/batches/msgbatch_013Zva2CMHLNnXjNJJKqJ2EF/results"
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonSerialization_WhenSerialized_ItShouldHaveExpectedShape()
|
||||
{
|
||||
var expectedJson = @"{
|
||||
""id"": ""msgbatch_013Zva2CMHLNnXjNJJKqJ2EF"",
|
||||
""type"": ""message_batch"",
|
||||
""processing_status"": ""in_progress"",
|
||||
""request_counts"": {
|
||||
""processing"": 100,
|
||||
""succeeded"": 50,
|
||||
""errored"": 30,
|
||||
""canceled"": 10,
|
||||
""expired"": 10
|
||||
},
|
||||
""ended_at"": ""2024-08-20T18:37:24.100435+00:00"",
|
||||
""created_at"": ""2024-08-20T18:37:24.100435+00:00"",
|
||||
""expires_at"": ""2024-08-20T18:37:24.100435+00:00"",
|
||||
""archived_at"": ""2024-08-20T18:37:24.100435+00:00"",
|
||||
""cancel_initiated_at"": ""2024-08-20T18:37:24.100435+00:00"",
|
||||
""results_url"": ""https://api.anthropic.com/v1/messages/batches/msgbatch_013Zva2CMHLNnXjNJJKqJ2EF/results""
|
||||
}";
|
||||
|
||||
var result = Serialize(new MessageBatchResponse
|
||||
{
|
||||
Id = "msgbatch_013Zva2CMHLNnXjNJJKqJ2EF",
|
||||
Type = "message_batch",
|
||||
ProcessingStatus = "in_progress",
|
||||
RequestCounts = new MessageBatchRequestCounts
|
||||
{
|
||||
Processing = 100,
|
||||
Succeeded = 50,
|
||||
Errored = 30,
|
||||
Canceled = 10,
|
||||
Expired = 10
|
||||
},
|
||||
EndedAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
CreatedAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
ExpiresAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
ArchivedAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
CancelInitiatedAt = DateTimeOffset.Parse("2024-08-20T18:37:24.100435Z"),
|
||||
ResultsUrl = "https://api.anthropic.com/v1/messages/batches/msgbatch_013Zva2CMHLNnXjNJJKqJ2EF/results"
|
||||
});
|
||||
|
||||
JsonAssert.Equal(expectedJson, result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user