feat: create chat message
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Models;
|
||||
|
||||
namespace AnthropicClient.Json;
|
||||
|
||||
class ContentConverter : JsonConverter<Content>
|
||||
{
|
||||
public override Content Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
using var jsonDocument = JsonDocument.ParseValue(ref reader);
|
||||
var root = jsonDocument.RootElement;
|
||||
var type = root.GetProperty("type").GetString();
|
||||
return type switch
|
||||
{
|
||||
ContentType.Text => JsonSerializer.Deserialize<TextContent>(root.GetRawText(), options)!,
|
||||
ContentType.Image => JsonSerializer.Deserialize<ImageContent>(root.GetRawText(), options)!,
|
||||
ContentType.ToolUse => JsonSerializer.Deserialize<ToolUseContent>(root.GetRawText(), options)!,
|
||||
ContentType.ToolResult => JsonSerializer.Deserialize<ToolResultContent>(root.GetRawText(), options)!,
|
||||
_ => throw new JsonException($"Unknown content type: {type}")
|
||||
};
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, Content value, JsonSerializerOptions options)
|
||||
{
|
||||
JsonSerializer.Serialize(writer, value, value.GetType(), options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Models;
|
||||
|
||||
namespace AnthropicClient.Json;
|
||||
|
||||
class ErrorConverter : JsonConverter<Error>
|
||||
{
|
||||
public override Error Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
using var jsonDocument = JsonDocument.ParseValue(ref reader);
|
||||
var root = jsonDocument.RootElement;
|
||||
var type = root.GetProperty("type").GetString();
|
||||
|
||||
return type switch
|
||||
{
|
||||
ErrorType.InvalidRequestError => JsonSerializer.Deserialize<InvalidRequestError>(root.GetRawText(), options)!,
|
||||
ErrorType.AuthenticationError => JsonSerializer.Deserialize<AuthenticationError>(root.GetRawText(), options)!,
|
||||
ErrorType.PermissionError => JsonSerializer.Deserialize<PermissionError>(root.GetRawText(), options)!,
|
||||
ErrorType.NotFoundError => JsonSerializer.Deserialize<NotFoundError>(root.GetRawText(), options)!,
|
||||
ErrorType.RateLimitError => JsonSerializer.Deserialize<RateLimitError>(root.GetRawText(), options)!,
|
||||
ErrorType.ApiError => JsonSerializer.Deserialize<ApiError>(root.GetRawText(), options)!,
|
||||
ErrorType.OverloadedError => JsonSerializer.Deserialize<OverloadedError>(root.GetRawText(), options)!,
|
||||
_ => throw new JsonException($"Unknown error type: {type}")
|
||||
};
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, Error value, JsonSerializerOptions options)
|
||||
{
|
||||
JsonSerializer.Serialize(writer, value, value.GetType(), options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Json;
|
||||
|
||||
static class JsonSerializationOptions
|
||||
{
|
||||
public static JsonSerializerOptions DefaultOptions => new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
Converters =
|
||||
{
|
||||
new ContentConverter(),
|
||||
new ToolChoiceConverter(),
|
||||
new ErrorConverter(),
|
||||
},
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Models;
|
||||
|
||||
namespace AnthropicClient.Json;
|
||||
|
||||
class ToolChoiceConverter : JsonConverter<ToolChoice>
|
||||
{
|
||||
public override ToolChoice Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
using var jsonDocument = JsonDocument.ParseValue(ref reader);
|
||||
var root = jsonDocument.RootElement;
|
||||
var type = root.GetProperty("type").GetString();
|
||||
return type switch
|
||||
{
|
||||
ToolChoiceType.Auto => JsonSerializer.Deserialize<AutoToolChoice>(root.GetRawText(), options)!,
|
||||
ToolChoiceType.Any => JsonSerializer.Deserialize<AnyToolChoice>(root.GetRawText(), options)!,
|
||||
ToolChoiceType.Tool => JsonSerializer.Deserialize<SpecificToolChoice>(root.GetRawText(), options)!,
|
||||
_ => throw new JsonException($"Unknown tool choice type: {type}")
|
||||
};
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, ToolChoice value, JsonSerializerOptions options)
|
||||
{
|
||||
JsonSerializer.Serialize(writer, value, value.GetType(), options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an error response from the Anthropic API.
|
||||
/// </summary>
|
||||
public class AnthropicError
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of the error.
|
||||
/// </summary>
|
||||
public string Type { get; init; } = "error";
|
||||
|
||||
/// <summary>
|
||||
/// The error object.
|
||||
/// </summary>
|
||||
public Error? Error { get; init; } = null;
|
||||
|
||||
[JsonConstructor]
|
||||
internal AnthropicError()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AnthropicError"/> class.
|
||||
/// </summary>
|
||||
/// <param name="error">The error as an <see cref="Error"/> object.</param>
|
||||
/// <returns>A new instance of the <see cref="AnthropicError"/> class.</returns>
|
||||
public AnthropicError(Error error)
|
||||
{
|
||||
Error = error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Provides constants for the Anthropic models.
|
||||
/// </summary>
|
||||
public static class AnthropicModels
|
||||
{
|
||||
/// <summary>
|
||||
/// The Claude-3 Opus model.
|
||||
/// </summary>
|
||||
public const string Claude3Opus = "claude-3-opus-20240229";
|
||||
|
||||
/// <summary>
|
||||
/// The Claude-3 Sonnet model.
|
||||
/// </summary>
|
||||
public const string Claude3Sonnet = "claude-3-sonnet-20240229";
|
||||
|
||||
/// <summary>
|
||||
/// The Claude-3.5 Sonnet model.
|
||||
/// </summary>
|
||||
public const string Claude35Sonnet = "claude-3-5-sonnet-20240620";
|
||||
|
||||
/// <summary>
|
||||
/// The Claude-3 Haiku model.
|
||||
/// </summary>
|
||||
public const string Claude3Haiku = "claude-3-haiku-20240307";
|
||||
|
||||
internal static bool IsValidModel(string modelId) => modelId is Claude3Opus or Claude3Sonnet or Claude35Sonnet or Claude3Haiku;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result of an Anthropic API operation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the result value.</typeparam>
|
||||
public class AnthropicResult<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// The value of the result.
|
||||
/// </summary>
|
||||
public T Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The error of the result.
|
||||
/// </summary>
|
||||
public AnthropicError Error { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the operation was successful.
|
||||
/// </summary>
|
||||
public bool IsSuccess { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The request ID of the operation.
|
||||
/// </summary>
|
||||
public string RequestId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AnthropicResult{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the result.</param>
|
||||
/// <param name="error">The error of the result.</param>
|
||||
/// <param name="isSuccess">Indicates whether the operation was successful.</param>
|
||||
/// <param name="requestId">The request ID of the operation.</param>
|
||||
/// <returns>A new instance of the <see cref="AnthropicResult{T}"/> class.</returns>
|
||||
protected AnthropicResult(T value, AnthropicError error, bool isSuccess, string requestId)
|
||||
{
|
||||
Value = value;
|
||||
Error = error;
|
||||
IsSuccess = isSuccess;
|
||||
RequestId = requestId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful result.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the result.</param>
|
||||
/// <param name="requestId">The request ID of the operation.</param>
|
||||
/// <returns>A new instance of the <see cref="AnthropicResult{T}"/> class.</returns>
|
||||
public static AnthropicResult<T> Success(T value, string requestId)
|
||||
{
|
||||
return new AnthropicResult<T>(value, null!, true, requestId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed result.
|
||||
/// </summary>
|
||||
/// <param name="error">The error of the result.</param>
|
||||
/// <param name="requestId">The request ID of the operation.</param>
|
||||
/// <returns>A new instance of the <see cref="AnthropicResult{T}"/> class.</returns>
|
||||
public static AnthropicResult<T> Failure(AnthropicError error, string requestId)
|
||||
{
|
||||
return new AnthropicResult<T>(default!, error, false, requestId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the any tool choice mode.
|
||||
/// </summary>
|
||||
public class AnyToolChoice : ToolChoice
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AnyToolChoice"/> class.
|
||||
/// </summary>
|
||||
/// <returns>A new instance of the <see cref="AnyToolChoice"/> class.</returns>
|
||||
public AnyToolChoice() : base(ToolChoiceType.Any) { }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an api_error response from the Anthropic API.
|
||||
/// </summary>
|
||||
public class ApiError : Error
|
||||
{
|
||||
[JsonConstructor]
|
||||
internal ApiError() : base(ErrorType.ApiError)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiError"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message.</param>
|
||||
/// <returns>A new instance of the <see cref="ApiError"/> class.</returns>
|
||||
public ApiError(string message) : base(ErrorType.ApiError)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an authentication_error response from the Anthropic API.
|
||||
/// </summary>
|
||||
public class AuthenticationError : Error
|
||||
{
|
||||
[JsonConstructor]
|
||||
internal AuthenticationError() : base(ErrorType.AuthenticationError)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthenticationError"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message.</param>
|
||||
/// <returns>A new instance of the <see cref="AuthenticationError"/> class.</returns>
|
||||
public AuthenticationError(string message) : base(ErrorType.AuthenticationError)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the auto tool choice mode.
|
||||
/// </summary>
|
||||
public class AutoToolChoice : ToolChoice
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AutoToolChoice"/> class.
|
||||
/// </summary>
|
||||
/// <returns>A new instance of the <see cref="AutoToolChoice"/> class.</returns>
|
||||
public AutoToolChoice() : base(ToolChoiceType.Auto) { }
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a chat message.
|
||||
/// </summary>
|
||||
public class ChatMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the role of the message.
|
||||
/// </summary>
|
||||
public string Role { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contents of the message.
|
||||
/// </summary>
|
||||
public List<Content> Content { get; init; } = [];
|
||||
|
||||
[JsonConstructor]
|
||||
internal ChatMessage()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ChatMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="role">The role of the message.</param>
|
||||
/// <param name="content">The contents of the message.</param>
|
||||
/// <exception cref="ArgumentException">Thrown when the role is invalid.</exception>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the role or content is null.</exception>
|
||||
/// <returns>A new instance of the <see cref="ChatMessage"/> class.</returns>
|
||||
public ChatMessage(string role, List<Content> content)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(role, nameof(role));
|
||||
ArgumentValidator.ThrowIfNull(content, nameof(content));
|
||||
|
||||
if (MessageRole.IsValidRole(role) is false)
|
||||
{
|
||||
throw new ArgumentException($"Invalid role: {role}");
|
||||
}
|
||||
|
||||
Role = role;
|
||||
Content = content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a chat message request.
|
||||
/// </summary>
|
||||
public class ChatMessageRequest : MessageRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the model ID to use for the request.
|
||||
/// </summary>
|
||||
public string Model { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system ID to use for the request.
|
||||
/// </summary>
|
||||
public string? System { get; init; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the messages to send to the model.
|
||||
/// </summary>
|
||||
public List<ChatMessage> Messages { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum number of tokens to generate.
|
||||
/// </summary>
|
||||
[JsonPropertyName("max_tokens")]
|
||||
public int MaxTokens { get; init; } = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the metadata to include with the request.
|
||||
/// </summary>
|
||||
public Dictionary<string, object>? Metadata { get; init; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the prompt stop sequences.
|
||||
/// </summary>
|
||||
[JsonPropertyName("stop_sequences")]
|
||||
public List<string> StopSequences { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the temperature to use for the request.
|
||||
/// </summary>
|
||||
public decimal Temperature { get; init; } = 0.0m;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top-K value to use for the request.
|
||||
/// </summary>
|
||||
public int? TopK { get; init; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top-P value to use for the request.
|
||||
/// </summary>
|
||||
public decimal? TopP { get; init; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tool choice mode to use for the request.
|
||||
/// </summary>
|
||||
[JsonPropertyName("tool_choice")]
|
||||
public ToolChoice? ToolChoice { get; init; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tools to use for the request.
|
||||
/// </summary>
|
||||
public List<Tool>? Tools { get; init; } = null;
|
||||
|
||||
[JsonConstructor]
|
||||
internal ChatMessageRequest() : base(false) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ChatMessageRequest"/> class.
|
||||
/// </summary>
|
||||
/// <param name="model">The model ID to use for the request.</param>
|
||||
/// <param name="messages">The messages to send to the model.</param>
|
||||
/// <param name="maxTokens">The maximum number of tokens to generate.</param>
|
||||
/// <param name="system">The system ID to use for the request.</param>
|
||||
/// <param name="metadata">The metadata to include with the request.</param>
|
||||
/// <param name="temperature">The temperature to use for the request.</param>
|
||||
/// <param name="topK">The top-K value to use for the request.</param>
|
||||
/// <param name="topP">The top-P value to use for the request.</param>
|
||||
/// <param name="toolChoice">The tool choice mode to use for the request.</param>
|
||||
/// <param name="tools">The tools to use for the request.</param>
|
||||
/// <exception cref="ArgumentException">Thrown when the model ID is invalid.</exception>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the model or messages is null.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when the messages contain no messages.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when the max tokens is less than one.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when the temperature is less than zero or greater than one.</exception>
|
||||
/// <returns>A new instance of the <see cref="ChatMessageRequest"/> class.</returns>
|
||||
public ChatMessageRequest(
|
||||
string model,
|
||||
List<ChatMessage> messages,
|
||||
int maxTokens = 1024,
|
||||
string? system = null,
|
||||
Dictionary<string, object>? metadata = null,
|
||||
decimal temperature = 0.0m,
|
||||
int? topK = null,
|
||||
decimal? topP = null,
|
||||
ToolChoice? toolChoice = null,
|
||||
List<Tool>? tools = null
|
||||
) : base(false)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(model, nameof(model));
|
||||
ArgumentValidator.ThrowIfNull(messages, nameof(messages));
|
||||
|
||||
if (AnthropicModels.IsValidModel(model) is false)
|
||||
{
|
||||
throw new ArgumentException($"Invalid model ID: {model}");
|
||||
}
|
||||
|
||||
if (messages.Count < 1)
|
||||
{
|
||||
throw new ArgumentException("Messages must contain at least one message");
|
||||
}
|
||||
|
||||
if (maxTokens < 1)
|
||||
{
|
||||
throw new ArgumentException($"Invalid max tokens: {maxTokens}");
|
||||
}
|
||||
|
||||
if (temperature < 0.0m || temperature > 1.0m)
|
||||
{
|
||||
throw new ArgumentException($"Invalid temperature: {temperature}");
|
||||
}
|
||||
|
||||
Model = model;
|
||||
Messages = messages;
|
||||
MaxTokens = maxTokens;
|
||||
System = system;
|
||||
Metadata = metadata;
|
||||
Temperature = temperature;
|
||||
TopK = topK;
|
||||
TopP = topP;
|
||||
ToolChoice = toolChoice;
|
||||
Tools = tools;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a chat response.
|
||||
/// </summary>
|
||||
public class ChatResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the ID of the chat response.
|
||||
/// </summary>
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model used for the chat response.
|
||||
/// </summary>
|
||||
public string Model { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the role of the chat response.
|
||||
/// </summary>
|
||||
public string Role { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stop reason of the chat response.
|
||||
/// </summary>
|
||||
[JsonPropertyName("stop_reason")]
|
||||
public string StopReason { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stop sequence of the chat response.
|
||||
/// </summary>
|
||||
[JsonPropertyName("stop_sequence")]
|
||||
public string StopSequence { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the chat response.
|
||||
/// </summary>
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the usage of the chat response.
|
||||
/// </summary>
|
||||
public ChatUsage Usage { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contents of the chat response.
|
||||
/// </summary>
|
||||
public List<Content> Content { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the usage of a chat response.
|
||||
/// </summary>
|
||||
public class ChatUsage
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the number of input tokens used.
|
||||
/// </summary>
|
||||
[JsonPropertyName("input_tokens")]
|
||||
public int InputTokens { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of output tokens used.
|
||||
/// </summary>
|
||||
[JsonPropertyName("output_tokens")]
|
||||
public int OutputTokens { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using AnthropicClient.Json;
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for interacting with the Anthropic API.
|
||||
/// </summary>
|
||||
public interface IClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a chat message asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="request">The chat message request to create.</param>
|
||||
/// <returns>A task that represents the asynchronous operation. The task result contains the chat response as an <see cref="AnthropicResult{T}"/>.</returns>
|
||||
Task<AnthropicResult<ChatResponse>> CreateChatMessageAsync(ChatMessageRequest request);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IClient"/>
|
||||
public class Client : IClient
|
||||
{
|
||||
private const string BaseUrl = "https://api.anthropic.com/v1/";
|
||||
private const string ApiKeyHeader = "x-api-key";
|
||||
private const string MessagesEndpoint = "messages";
|
||||
private const string JsonContentType = "application/json";
|
||||
private const string RequestIdHeader = "request-id";
|
||||
private readonly Dictionary<string, string> _defaultHeaders = new()
|
||||
{
|
||||
{ "anthropic-version", "2023-06-01" },
|
||||
};
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Client"/> class.
|
||||
/// </summary>
|
||||
/// <param name="apiKey">The API key to use for the client.</param>
|
||||
/// <param name="httpClient">The HTTP client to use for the client.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the API key or HTTP client is null.</exception>
|
||||
/// <returns>A new instance of the <see cref="Client"/> class.</returns>
|
||||
public Client(string apiKey, HttpClient httpClient)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(apiKey, nameof(apiKey));
|
||||
ArgumentValidator.ThrowIfNull(httpClient, nameof(httpClient));
|
||||
|
||||
_httpClient = httpClient;
|
||||
_httpClient.BaseAddress = new Uri(BaseUrl);
|
||||
_httpClient.DefaultRequestHeaders.Add(ApiKeyHeader, apiKey);
|
||||
_httpClient.DefaultRequestHeaders
|
||||
.Accept
|
||||
.Add(new MediaTypeWithQualityHeaderValue(JsonContentType));
|
||||
|
||||
foreach (var pair in _defaultHeaders)
|
||||
{
|
||||
_httpClient.DefaultRequestHeaders.Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<AnthropicResult<ChatResponse>> CreateChatMessageAsync(ChatMessageRequest request)
|
||||
{
|
||||
var requestContent = new StringContent(Serialize(request), Encoding.UTF8, JsonContentType);
|
||||
var response = await _httpClient.PostAsync(MessagesEndpoint, requestContent);
|
||||
var requestId = GetRequestId(response);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
if (response.IsSuccessStatusCode is false)
|
||||
{
|
||||
var error = Deserialize<AnthropicError>(responseContent) ?? new AnthropicError();
|
||||
return AnthropicResult<ChatResponse>.Failure(error, requestId);
|
||||
}
|
||||
|
||||
var chatResponse = Deserialize<ChatResponse>(responseContent) ?? new ChatResponse();
|
||||
return AnthropicResult<ChatResponse>.Success(chatResponse, requestId);
|
||||
}
|
||||
|
||||
private string Serialize<T>(T obj) => JsonSerializer.Serialize(obj, JsonSerializationOptions.DefaultOptions);
|
||||
private T? Deserialize<T>(string json) => JsonSerializer.Deserialize<T>(json, JsonSerializationOptions.DefaultOptions);
|
||||
private string GetRequestId(HttpResponseMessage response) => response.Headers.GetValues(RequestIdHeader).FirstOrDefault() ?? string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents part of the content of a chat message.
|
||||
/// </summary>
|
||||
public abstract class Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type of the content.
|
||||
/// </summary>
|
||||
public string Type { get; init; } = string.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
internal Content()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Content"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of the content.</param>
|
||||
/// <returns>A new instance of the <see cref="Content"/> class.</returns>
|
||||
protected Content(string type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the content type.
|
||||
/// </summary>
|
||||
public static class ContentType
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the text content type.
|
||||
/// </summary>
|
||||
public const string Text = "text";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the image content type.
|
||||
/// </summary>
|
||||
public const string Image = "image";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the tool use content type.
|
||||
/// </summary>
|
||||
public const string ToolUse = "tool_use";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the tool result content type.
|
||||
/// </summary>
|
||||
public const string ToolResult = "tool_result";
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an error.
|
||||
/// </summary>
|
||||
public abstract class Error
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type of the error.
|
||||
/// </summary>
|
||||
public string Type { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message of the error.
|
||||
/// </summary>
|
||||
public string Message { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Error"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of the error.</param>
|
||||
/// <returns>A new instance of the <see cref="Error"/> class.</returns>
|
||||
protected Error(string type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the error type.
|
||||
/// </summary>
|
||||
public class ErrorType
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the invalid_request error type.
|
||||
/// </summary>
|
||||
public const string InvalidRequestError = "invalid_request_error";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the authentication_error type.
|
||||
/// </summary>
|
||||
public const string AuthenticationError = "authentication_error";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the permission_error type.
|
||||
/// </summary>
|
||||
public const string PermissionError = "permission_error";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the not_found_error type.
|
||||
/// </summary>
|
||||
public const string NotFoundError = "not_found_error";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the rate_limit_error type.
|
||||
/// </summary>
|
||||
public const string RateLimitError = "rate_limit_error";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the api_error type.
|
||||
/// </summary>
|
||||
public const string ApiError = "api_error";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the overloaded_error type.
|
||||
/// </summary>
|
||||
public const string OverloadedError = "overloaded_error";
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents image content that is part of a chat message.
|
||||
/// </summary>
|
||||
public class ImageContent : Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the source of the image.
|
||||
/// </summary>
|
||||
public ImageSource Source { get; init; } = new();
|
||||
|
||||
[JsonConstructor]
|
||||
internal ImageContent()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageContent"/> class.
|
||||
/// </summary>
|
||||
/// <param name="mediaType">The media type of the image.</param>
|
||||
/// <param name="data">The data of the image.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the media type or data is null.</exception>
|
||||
/// <returns>A new instance of the <see cref="ImageContent"/> class.</returns>
|
||||
public ImageContent(string mediaType, string data) : base(ContentType.Image)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(mediaType, nameof(mediaType));
|
||||
ArgumentValidator.ThrowIfNull(data, nameof(data));
|
||||
|
||||
Source = new(mediaType, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an image source.
|
||||
/// </summary>
|
||||
public class ImageSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the media type of the image.
|
||||
/// </summary>
|
||||
[JsonPropertyName("media_type")]
|
||||
public string MediaType { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data of the image.
|
||||
/// </summary>
|
||||
public string Data { get; init; } = string.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
internal ImageSource()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageSource"/> class.
|
||||
/// </summary>
|
||||
/// <param name="mediaType">The media type of the image.</param>
|
||||
/// <param name="data">The data of the image.</param>
|
||||
/// <exception cref="ArgumentException">Thrown when the media type is invalid.</exception>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the media type or data is null.</exception>
|
||||
/// <returns>A new instance of the <see cref="ImageSource"/> class.</returns>
|
||||
public ImageSource(string mediaType, string data)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(mediaType, nameof(mediaType));
|
||||
|
||||
if (ImageType.IsValidImageType(mediaType) is false)
|
||||
{
|
||||
throw new ArgumentException($"Invalid media type: {mediaType}");
|
||||
}
|
||||
|
||||
ArgumentValidator.ThrowIfNull(data, nameof(data));
|
||||
|
||||
MediaType = mediaType;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the image type.
|
||||
/// </summary>
|
||||
public static class ImageType
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the JPEG image type.
|
||||
/// </summary>
|
||||
public const string Jpg = "image/jpeg";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the PNG image type.
|
||||
/// </summary>
|
||||
public const string Png = "image/png";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the GIF image type.
|
||||
/// </summary>
|
||||
public const string Gif = "image/gif";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the WebP image type.
|
||||
/// </summary>
|
||||
public const string Webp = "image/webp";
|
||||
|
||||
internal static bool IsValidImageType(string imageType) => imageType is Jpg or Png or Gif or Webp;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an input property.
|
||||
/// </summary>
|
||||
public class InputProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type of the input property.
|
||||
/// </summary>
|
||||
public string Type { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description of the input property.
|
||||
/// </summary>
|
||||
public string Description { get; init; } = string.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
internal InputProperty()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InputProperty"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of the input property.</param>
|
||||
/// <param name="description">The description of the input property.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the type or description is null.</exception>
|
||||
/// <returns>A new instance of the <see cref="InputProperty"/> class.</returns>
|
||||
public InputProperty(string type, string description)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(type, nameof(type));
|
||||
ArgumentValidator.ThrowIfNull(description, nameof(description));
|
||||
|
||||
Type = type;
|
||||
Description = description;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an input schema.
|
||||
/// </summary>
|
||||
public class InputSchema
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type of the input schema.
|
||||
/// </summary>
|
||||
public string Type { get; init; } = "object";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the properties of the input schema.
|
||||
/// </summary>
|
||||
public Dictionary<string, InputProperty> Properties { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the required properties of the input schema.
|
||||
/// </summary>
|
||||
public List<string> Required { get; init; } = [];
|
||||
|
||||
[JsonConstructor]
|
||||
internal InputSchema()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InputSchema"/> class.
|
||||
/// </summary>
|
||||
/// <param name="properties">The properties of the input schema.</param>
|
||||
/// <param name="required">The required properties of the input schema.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the properties or required is null.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when the required properties are not present in the properties dictionary.</exception>
|
||||
/// <returns>A new instance of the <see cref="InputSchema"/> class.</returns>
|
||||
public InputSchema(Dictionary<string, InputProperty> properties, List<string> required)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(properties, nameof(properties));
|
||||
ArgumentValidator.ThrowIfNull(required, nameof(required));
|
||||
|
||||
if (required.Any(r => properties.ContainsKey(r) is false))
|
||||
{
|
||||
throw new ArgumentException("Required properties must be present in the properties dictionary.");
|
||||
}
|
||||
|
||||
Properties = properties;
|
||||
Required = required;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an invalid_request error.
|
||||
/// </summary>
|
||||
public class InvalidRequestError : Error
|
||||
{
|
||||
[JsonConstructor]
|
||||
internal InvalidRequestError() : base(ErrorType.InvalidRequestError)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InvalidRequestError"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message of the error.</param>
|
||||
/// <returns>A new instance of the <see cref="InvalidRequestError"/> class.</returns>
|
||||
public InvalidRequestError(string message) : base(ErrorType.InvalidRequestError)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
class IsExternalInit { }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a message request.
|
||||
/// </summary>
|
||||
public abstract class MessageRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the message should be streamed.
|
||||
/// </summary>
|
||||
public bool Stream { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MessageRequest"/> class.
|
||||
/// </summary>
|
||||
/// <param name="stream">A value indicating whether the message should be streamed.</param>
|
||||
/// <returns>A new instance of the <see cref="MessageRequest"/> class.</returns>
|
||||
public MessageRequest(bool stream = false)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the message role.
|
||||
/// </summary>
|
||||
public static class MessageRole
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the user role.
|
||||
/// </summary>
|
||||
public const string User = "user";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the assistant role.
|
||||
/// </summary>
|
||||
public const string Assistant = "assistant";
|
||||
|
||||
internal static bool IsValidRole(string role) => role is User or Assistant;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a not_found error.
|
||||
/// </summary>
|
||||
public class NotFoundError : Error
|
||||
{
|
||||
[JsonConstructor]
|
||||
internal NotFoundError() : base(ErrorType.NotFoundError)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NotFoundError"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message of the error.</param>
|
||||
/// <returns>A new instance of the <see cref="NotFoundError"/> class.</returns>
|
||||
public NotFoundError(string message) : base(ErrorType.NotFoundError)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an overloaded error.
|
||||
/// </summary>
|
||||
public class OverloadedError : Error
|
||||
{
|
||||
[JsonConstructor]
|
||||
internal OverloadedError() : base(ErrorType.OverloadedError)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OverloadedError"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message of the error.</param>
|
||||
/// <returns>A new instance of the <see cref="OverloadedError"/> class.</returns>
|
||||
public OverloadedError(string message) : base(ErrorType.OverloadedError)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a permission error.
|
||||
/// </summary>
|
||||
public class PermissionError : Error
|
||||
{
|
||||
[JsonConstructor]
|
||||
internal PermissionError() : base(ErrorType.PermissionError)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PermissionError"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message of the error.</param>
|
||||
/// <returns>A new instance of the <see cref="PermissionError"/> class.</returns>
|
||||
public PermissionError(string message) : base(ErrorType.PermissionError)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a rate_limit error.
|
||||
/// </summary>
|
||||
public class RateLimitError : Error
|
||||
{
|
||||
[JsonConstructor]
|
||||
internal RateLimitError() : base(ErrorType.RateLimitError)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RateLimitError"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message of the error.</param>
|
||||
/// <returns>A new instance of the <see cref="RateLimitError"/> class.</returns>
|
||||
public RateLimitError(string message) : base(ErrorType.RateLimitError)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the specific tool choice mode.
|
||||
/// </summary>
|
||||
public class SpecificToolChoice : ToolChoice
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the tool.
|
||||
/// </summary>
|
||||
public string Name { get; init; } = string.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
internal SpecificToolChoice() : base(ToolChoiceType.Tool)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SpecificToolChoice"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the tool.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the name is null.</exception>
|
||||
/// <returns>A new instance of the <see cref="SpecificToolChoice"/> class.</returns>
|
||||
public SpecificToolChoice(string name) : base(ToolChoiceType.Tool)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(name, nameof(name));
|
||||
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the stop reason type.
|
||||
/// </summary>
|
||||
public static class StopReasonType
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the end_turn stop reason.
|
||||
/// </summary>
|
||||
public const string EndTurn = "end_turn";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the max_tokens stop reason.
|
||||
/// </summary>
|
||||
public const string MaxTokens = "max_tokens";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the stop_sequence stop reason.
|
||||
/// </summary>
|
||||
public const string StopSequence = "stop_sequence";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the tool_use stop reason.
|
||||
/// </summary>
|
||||
public const string ToolUse = "tool_use";
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents text content that is part of a chat message.
|
||||
/// </summary>
|
||||
public class TextContent : Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the text of the content.
|
||||
/// </summary>
|
||||
public string Text { get; init; } = string.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
internal TextContent() : base(ContentType.Text)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TextContent"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The text of the content.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the text is null.</exception>
|
||||
/// <returns>A new instance of the <see cref="TextContent"/> class.</returns>
|
||||
public TextContent(string text) : base(ContentType.Text)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(text, nameof(text));
|
||||
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a tool that can be used in the chat.
|
||||
/// </summary>
|
||||
public class Tool
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the tool.
|
||||
/// </summary>
|
||||
public string Name { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description of the tool.
|
||||
/// </summary>
|
||||
public string Description { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the input schema of the tool.
|
||||
/// </summary>
|
||||
[JsonPropertyName("input_schema")]
|
||||
public InputSchema InputSchema { get; init; } = new();
|
||||
|
||||
[JsonConstructor]
|
||||
internal Tool()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Tool"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the tool.</param>
|
||||
/// <param name="description">The description of the tool.</param>
|
||||
/// <param name="inputSchema">The input schema of the tool.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the name, description, or input schema is null.</exception>
|
||||
/// <returns>A new instance of the <see cref="Tool"/> class.</returns>
|
||||
public Tool(string name, string description, InputSchema inputSchema)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(name, nameof(name));
|
||||
ArgumentValidator.ThrowIfNull(description, nameof(description));
|
||||
ArgumentValidator.ThrowIfNull(inputSchema, nameof(inputSchema));
|
||||
|
||||
Name = name;
|
||||
Description = description;
|
||||
InputSchema = inputSchema;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a tool choice mode.
|
||||
/// </summary>
|
||||
public abstract class ToolChoice
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type of the tool choice.
|
||||
/// </summary>
|
||||
public string Type { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ToolChoice"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of the tool choice.</param>
|
||||
/// <returns>A new instance of the <see cref="ToolChoice"/> class.</returns>
|
||||
protected ToolChoice(string type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the tool choice type.
|
||||
/// </summary>
|
||||
public class ToolChoiceType
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the auto tool choice type.
|
||||
/// </summary>
|
||||
public const string Auto = "auto";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the any tool choice type.
|
||||
/// </summary>
|
||||
public const string Any = "any";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the specific tool choice type.
|
||||
/// </summary>
|
||||
public const string Tool = "tool";
|
||||
|
||||
internal static bool IsValidType(string type) => type is Auto or Any or Tool;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AnthropicClient.Utils;
|
||||
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents tool result content that is part of a chat message.
|
||||
/// </summary>
|
||||
public class ToolResultContent : Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the tool use ID of the content.
|
||||
/// </summary>
|
||||
[JsonPropertyName("tool_use_id")]
|
||||
public string ToolUseId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of the tool result.
|
||||
/// </summary>
|
||||
public string Content { get; set; } = string.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
internal ToolResultContent() : base(ContentType.ToolResult) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ToolResultContent"/> class.
|
||||
/// </summary>
|
||||
/// <param name="toolUseId">The tool use ID of the content.</param>
|
||||
/// <param name="content">The content of the tool result.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the tool use ID or content is null.</exception>
|
||||
/// <returns>A new instance of the <see cref="ToolResultContent"/> class.</returns>
|
||||
public ToolResultContent(string toolUseId, string content) : base(ContentType.ToolResult)
|
||||
{
|
||||
ArgumentValidator.ThrowIfNull(toolUseId, nameof(toolUseId));
|
||||
ArgumentValidator.ThrowIfNull(content, nameof(content));
|
||||
|
||||
ToolUseId = toolUseId;
|
||||
Content = content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace AnthropicClient.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents tool use content that is part of a message.
|
||||
/// </summary>
|
||||
public class ToolUseContent : Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the ID of the tool use.
|
||||
/// </summary>
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the tool.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the input of the tool.
|
||||
/// </summary>
|
||||
public Dictionary<string, object?> Input { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ToolUseContent"/> class.
|
||||
/// </summary>
|
||||
/// <returns>A new instance of the <see cref="ToolUseContent"/> class.</returns>
|
||||
public ToolUseContent() : base(ContentType.ToolUse)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace AnthropicClient.Utils;
|
||||
|
||||
/// <summary>
|
||||
/// Provides methods to validate arguments.
|
||||
/// </summary>
|
||||
public static class ArgumentValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Throws an <see cref="ArgumentNullException"/> if the value is null.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="value">The value to check.</param>
|
||||
/// <param name="name">The name of the value.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when the value is null.</exception>
|
||||
/// <returns>Nothing.</returns>
|
||||
public static void ThrowIfNull<T>(T? value, string name)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user