feat: implement CreateMessageBatchAsync method

This commit is contained in:
Stevan Freeborn
2025-01-08 20:37:58 -06:00
parent fe39f10382
commit 9548754d6c
9 changed files with 487 additions and 1 deletions
+26 -1
View File
@@ -28,6 +28,13 @@ public interface IAnthropicApiClient
/// <returns>An asynchronous enumerable that yields the response event by event.</returns>
IAsyncEnumerable<AnthropicEvent> CreateMessageAsync(StreamMessageRequest request);
/// <summary>
/// Creates a batch of messages asynchronously.
/// </summary>
/// <param name="request">The message batch request to create.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the response as an <see cref="AnthropicResult{T}"/> where T is <see cref="MessageBatchResponse"/>.</returns>
Task<AnthropicResult<MessageBatchResponse>> CreateMessageBatchAsync(MessageBatchRequest request);
/// <summary>
/// Counts the tokens in a message asynchronously.
/// </summary>
@@ -64,7 +71,8 @@ public class AnthropicApiClient : IAnthropicApiClient
private const string BaseUrl = "https://api.anthropic.com/v1/";
private const string ApiKeyHeader = "x-api-key";
private const string MessagesEndpoint = "messages";
private const string CountTokensEndpoint = "messages/count_tokens";
private string CountTokensEndpoint => $"{MessagesEndpoint}/count-tokens";
private string MessageBatchesEndpoint => $"{MessagesEndpoint}/batches";
private const string ModelsEndpoint = "models";
private const string JsonContentType = "application/json";
private const string EventPrefix = "event:";
@@ -287,6 +295,23 @@ public class AnthropicApiClient : IAnthropicApiClient
} while (true);
}
/// <inheritdoc/>
public async Task<AnthropicResult<MessageBatchResponse>> CreateMessageBatchAsync(MessageBatchRequest request)
{
var response = await SendRequestAsync(MessageBatchesEndpoint, request);
var anthropicHeaders = new AnthropicHeaders(response.Headers);
var responseContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode is false)
{
var error = Deserialize<AnthropicError>(responseContent) ?? new AnthropicError();
return AnthropicResult<MessageBatchResponse>.Failure(error, anthropicHeaders);
}
var msgBatchResponse = Deserialize<MessageBatchResponse>(responseContent) ?? new MessageBatchResponse();
return AnthropicResult<MessageBatchResponse>.Success(msgBatchResponse, anthropicHeaders);
}
/// <inheritdoc/>
public async Task<AnthropicResult<TokenCountResponse>> CountMessageTokensAsync(CountMessageTokensRequest request)
{
@@ -0,0 +1,28 @@
namespace AnthropicClient.Models;
/// <summary>
/// Represents a request to create a batch of messages.
/// </summary>
public class MessageBatchRequest
{
/// <summary>
/// Gets the requests to create messages.
/// </summary>
public List<MessageBatchRequestItem> Requests { get; init; } = [];
/// <summary>
/// Initializes a new instance of the <see cref="MessageBatchRequest"/> class.
/// </summary>
/// <param name="requests">The requests to create messages.</param>
/// <exception cref="ArgumentException">Thrown when <paramref name="requests"/> is empty.</exception>
/// <returns>An instance of the <see cref="MessageBatchRequest"/> class.</returns>
public MessageBatchRequest(List<MessageBatchRequestItem> requests)
{
if (requests.Count == 0)
{
throw new ArgumentException($"{nameof(requests)} must not be empty.", nameof(requests));
}
Requests = requests;
}
}
@@ -0,0 +1,39 @@
using System.Text.Json.Serialization;
using AnthropicClient.Utils;
namespace AnthropicClient.Models;
/// <summary>
/// Represents an item in a batch of messages.
/// </summary>
public class MessageBatchRequestItem
{
/// <summary>
/// Gets the custom identifier for the message.
/// </summary>
[JsonPropertyName("custom_id")]
public string CustomId { get; init; }
/// <summary>
/// Gets the message request parameters.
/// </summary>
public MessageRequest Params { get; init; }
/// <summary>
/// Initializes a new instance of the <see cref="MessageBatchRequestItem"/> class.
/// </summary>
/// <param name="customId">The custom identifier for the message.</param>
/// <param name="messageRequest">The message request parameters.</param>
/// <exception cref="ArgumentException">Thrown when <paramref name="customId"/> is null or whitespace.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="messageRequest"/> is null.</exception>
/// <returns>An instance of the <see cref="MessageBatchRequestItem"/> class.</returns>
public MessageBatchRequestItem(string customId, MessageRequest messageRequest)
{
ArgumentValidator.ThrowIfNullOrWhitespace(customId, nameof(customId));
ArgumentValidator.ThrowIfNull(messageRequest, nameof(messageRequest));
CustomId = customId;
Params = messageRequest;
}
}
@@ -0,0 +1,98 @@
using System.Text.Json.Serialization;
namespace AnthropicClient.Models;
/// <summary>
/// Represents a response to a batch of messages.
/// </summary>
public class MessageBatchResponse
{
/// <summary>
/// Gets the identifier of the batch.
/// </summary>
public string Id { get; init; } = string.Empty;
/// <summary>
/// Gets the type of the batch.
/// </summary>
public string Type { get; init; } = string.Empty;
/// <summary>
/// Gets the processing status of the batch.
/// </summary>
[JsonPropertyName("processing_status")]
public string ProcessingStatus { get; init; } = string.Empty;
/// <summary>
/// Gets the counts of requests in the batch.
/// </summary>
[JsonPropertyName("request_counts")]
public MessageBatchRequestCounts RequestCounts { get; init; } = new MessageBatchRequestCounts();
/// <summary>
/// Gets the date and time when the batch ended.
/// </summary>
[JsonPropertyName("ended_at")]
public DateTimeOffset EndedAt { get; init; }
/// <summary>
/// Gets the date and time when the batch was created.
/// </summary>
[JsonPropertyName("created_at")]
public DateTimeOffset CreatedAt { get; init; }
/// <summary>
/// Gets the date and time when the batch expires.
/// </summary>
[JsonPropertyName("expires_at")]
public DateTimeOffset ExpiresAt { get; init; }
/// <summary>
/// Gets the date and time when the batch was archived.
/// </summary>
[JsonPropertyName("archived_at")]
public DateTimeOffset ArchivedAt { get; init; }
/// <summary>
/// Gets the date and time when the batch cancellation was initiated.
/// </summary>
[JsonPropertyName("cancel_initiated_at")]
public DateTimeOffset CancelInitiatedAt { get; init; }
/// <summary>
/// Gets the URL to the results of the batch.
/// </summary>
[JsonPropertyName("results_url")]
public string ResultsUrl { get; init; } = string.Empty;
}
/// <summary>
/// Represents the counts of requests in a batch of messages.
/// </summary>
public class MessageBatchRequestCounts
{
/// <summary>
/// Gets the number of requests in the batch that are processing.
/// </summary>
public int Processing { get; init; }
/// <summary>
/// Gets the number of requests in the batch that succeeded.
/// </summary>
public int Succeeded { get; init; }
/// <summary>
/// Gets the number of requests in the batch that errored.
/// </summary>
public int Errored { get; init; }
/// <summary>
/// Gets the number of requests in the batch that were cancelled.
/// </summary>
public int Canceled { get; init; }
/// <summary>
/// Gets the number of requests in the batch that expired.
/// </summary>
public int Expired { get; init; }
}