diff --git a/src/AnthropicClient/AnthropicClient.csproj b/src/AnthropicClient/AnthropicClient.csproj
index 9c4fd50..6e2b388 100644
--- a/src/AnthropicClient/AnthropicClient.csproj
+++ b/src/AnthropicClient/AnthropicClient.csproj
@@ -19,6 +19,7 @@
+
diff --git a/src/AnthropicClient/Json/ContentDeltaConverter.cs b/src/AnthropicClient/Json/ContentDeltaConverter.cs
new file mode 100644
index 0000000..e384b8a
--- /dev/null
+++ b/src/AnthropicClient/Json/ContentDeltaConverter.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+using AnthropicClient.Models;
+
+namespace AnthropicClient.Json;
+
+class ContentDeltaConverter : JsonConverter
+{
+ public override ContentDelta 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
+ {
+ ContentDeltaType.TextDelta => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ ContentDeltaType.JsonDelta => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ _ => throw new JsonException($"Unknown content type: {type}")
+ };
+ }
+
+ public override void Write(Utf8JsonWriter writer, ContentDelta value, JsonSerializerOptions options)
+ {
+ JsonSerializer.Serialize(writer, value, value.GetType(), options);
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Json/EventDataConverter.cs b/src/AnthropicClient/Json/EventDataConverter.cs
new file mode 100644
index 0000000..d11855b
--- /dev/null
+++ b/src/AnthropicClient/Json/EventDataConverter.cs
@@ -0,0 +1,34 @@
+using System.Diagnostics;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+using AnthropicClient.Models;
+
+namespace AnthropicClient.Json;
+
+class EventDataConverter : JsonConverter
+{
+ public override EventData 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
+ {
+ EventType.Ping => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ EventType.Error => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ EventType.MessageStart => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ EventType.MessageDelta => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ EventType.MessageStop => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ EventType.ContentBlockStart => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ EventType.ContentBlockDelta => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ EventType.ContentBlockStop => JsonSerializer.Deserialize(root.GetRawText(), options)!,
+ _ => throw new JsonException($"Unknown content type: {type}")
+ };
+ }
+
+ public override void Write(Utf8JsonWriter writer, EventData value, JsonSerializerOptions options)
+ {
+ JsonSerializer.Serialize(writer, value, value.GetType(), options);
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Json/JsonSerializationOptions.cs b/src/AnthropicClient/Json/JsonSerializationOptions.cs
index 15214b0..fd90328 100644
--- a/src/AnthropicClient/Json/JsonSerializationOptions.cs
+++ b/src/AnthropicClient/Json/JsonSerializationOptions.cs
@@ -14,6 +14,8 @@ static class JsonSerializationOptions
new ContentConverter(),
new ToolChoiceConverter(),
new ErrorConverter(),
+ new EventDataConverter(),
+ new ContentDeltaConverter(),
},
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};
diff --git a/src/AnthropicClient/Models/AnthropicEvent.cs b/src/AnthropicClient/Models/AnthropicEvent.cs
new file mode 100644
index 0000000..91bab77
--- /dev/null
+++ b/src/AnthropicClient/Models/AnthropicEvent.cs
@@ -0,0 +1,20 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public record AnthropicEvent
+{
+ public string Type { get; init; } = string.Empty;
+ public EventData Data { get; init; } = default!;
+
+ [JsonConstructor]
+ internal AnthropicEvent()
+ {
+ }
+
+ public AnthropicEvent(string type, EventData data)
+ {
+ Type = type;
+ Data = data;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ChatMessageRequest.cs b/src/AnthropicClient/Models/ChatMessageRequest.cs
index 6a54b95..895565a 100644
--- a/src/AnthropicClient/Models/ChatMessageRequest.cs
+++ b/src/AnthropicClient/Models/ChatMessageRequest.cs
@@ -1,7 +1,5 @@
using System.Text.Json.Serialization;
-using AnthropicClient.Utils;
-
namespace AnthropicClient.Models;
///
@@ -9,66 +7,8 @@ namespace AnthropicClient.Models;
///
public class ChatMessageRequest : MessageRequest
{
- ///
- /// Gets the model ID to use for the request.
- ///
- public string Model { get; init; } = string.Empty;
-
- ///
- /// Gets the system ID to use for the request.
- ///
- public string? System { get; init; } = null;
-
- ///
- /// Gets the messages to send to the model.
- ///
- public List Messages { get; init; } = [];
-
- ///
- /// Gets the maximum number of tokens to generate.
- ///
- [JsonPropertyName("max_tokens")]
- public int MaxTokens { get; init; } = 1024;
-
- ///
- /// Gets the metadata to include with the request.
- ///
- public Dictionary? Metadata { get; init; } = null;
-
- ///
- /// Gets the prompt stop sequences.
- ///
- [JsonPropertyName("stop_sequences")]
- public List StopSequences { get; init; } = [];
-
- ///
- /// Gets the temperature to use for the request.
- ///
- public decimal Temperature { get; init; } = 0.0m;
-
- ///
- /// Gets the top-K value to use for the request.
- ///
- public int? TopK { get; init; } = null;
-
- ///
- /// Gets the top-P value to use for the request.
- ///
- public decimal? TopP { get; init; } = null;
-
- ///
- /// Gets the tool choice mode to use for the request.
- ///
- [JsonPropertyName("tool_choice")]
- public ToolChoice? ToolChoice { get; init; } = null;
-
- ///
- /// Gets the tools to use for the request.
- ///
- public List? Tools { get; init; } = null;
-
[JsonConstructor]
- internal ChatMessageRequest() : base(false) { }
+ internal ChatMessageRequest() : base() { }
///
/// Initializes a new instance of the class.
@@ -100,40 +40,19 @@ public class ChatMessageRequest : MessageRequest
decimal? topP = null,
ToolChoice? toolChoice = null,
List? tools = null
- ) : base(false)
+ ) : base(
+ model,
+ messages,
+ maxTokens,
+ system,
+ metadata,
+ temperature,
+ topK,
+ topP,
+ toolChoice,
+ tools,
+ 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;
}
}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ChatResponse.cs b/src/AnthropicClient/Models/ChatResponse.cs
index b95e461..aa33a1b 100644
--- a/src/AnthropicClient/Models/ChatResponse.cs
+++ b/src/AnthropicClient/Models/ChatResponse.cs
@@ -10,42 +10,42 @@ public class ChatResponse
///
/// Gets the ID of the chat response.
///
- public string Id { get; set; } = string.Empty;
+ public string Id { get; init; } = string.Empty;
///
/// Gets the model used for the chat response.
///
- public string Model { get; set; } = string.Empty;
+ public string Model { get; init; } = string.Empty;
///
/// Gets the role of the chat response.
///
- public string Role { get; set; } = string.Empty;
+ public string Role { get; init; } = string.Empty;
///
/// Gets the stop reason of the chat response.
///
[JsonPropertyName("stop_reason")]
- public string StopReason { get; set; } = string.Empty;
+ public string StopReason { get; init; } = string.Empty;
///
/// Gets the stop sequence of the chat response.
///
[JsonPropertyName("stop_sequence")]
- public string StopSequence { get; set; } = string.Empty;
+ public string StopSequence { get; init; } = string.Empty;
///
/// Gets the type of the chat response.
///
- public string Type { get; set; } = string.Empty;
+ public string Type { get; init; } = string.Empty;
///
/// Gets the usage of the chat response.
///
- public ChatUsage Usage { get; set; } = new();
+ public ChatUsage Usage { get; init; } = new();
///
/// Gets the contents of the chat response.
///
- public List Content { get; set; } = [];
+ public List Content { get; init; } = [];
}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ChatUsage.cs b/src/AnthropicClient/Models/ChatUsage.cs
index 73312ee..1dd7749 100644
--- a/src/AnthropicClient/Models/ChatUsage.cs
+++ b/src/AnthropicClient/Models/ChatUsage.cs
@@ -11,11 +11,11 @@ public class ChatUsage
/// Gets the number of input tokens used.
///
[JsonPropertyName("input_tokens")]
- public int InputTokens { get; set; }
+ public int InputTokens { get; init; }
///
/// Gets the number of output tokens used.
///
[JsonPropertyName("output_tokens")]
- public int OutputTokens { get; set; }
+ public int OutputTokens { get; init; }
}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ContentDelta.cs b/src/AnthropicClient/Models/ContentDelta.cs
new file mode 100644
index 0000000..fbc0484
--- /dev/null
+++ b/src/AnthropicClient/Models/ContentDelta.cs
@@ -0,0 +1,11 @@
+namespace AnthropicClient.Models;
+
+public abstract class ContentDelta
+{
+ public string Type { get; init; }
+
+ protected ContentDelta(string type)
+ {
+ Type = type;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ContentDeltaEventData.cs b/src/AnthropicClient/Models/ContentDeltaEventData.cs
new file mode 100644
index 0000000..4439a8e
--- /dev/null
+++ b/src/AnthropicClient/Models/ContentDeltaEventData.cs
@@ -0,0 +1,20 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public class ContentDeltaEventData : EventData
+{
+ public int Index { get; init; }
+ public ContentDelta Delta { get; init; } = default!;
+
+ [JsonConstructor]
+ internal ContentDeltaEventData() : base(EventType.ContentBlockDelta)
+ {
+ }
+
+ public ContentDeltaEventData(int index, ContentDelta delta) : base(EventType.ContentBlockDelta)
+ {
+ Index = index;
+ Delta = delta;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ContentDeltaType.cs b/src/AnthropicClient/Models/ContentDeltaType.cs
new file mode 100644
index 0000000..b5096f3
--- /dev/null
+++ b/src/AnthropicClient/Models/ContentDeltaType.cs
@@ -0,0 +1,7 @@
+namespace AnthropicClient.Models;
+
+public static class ContentDeltaType
+{
+ public const string TextDelta = "text_delta";
+ public const string JsonDelta = "input_json_delta";
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ContentStartEventData.cs b/src/AnthropicClient/Models/ContentStartEventData.cs
new file mode 100644
index 0000000..1edfa2e
--- /dev/null
+++ b/src/AnthropicClient/Models/ContentStartEventData.cs
@@ -0,0 +1,22 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public class ContentStartEventData : EventData
+{
+ public int Index { get; init; }
+
+ [JsonPropertyName("content_block")]
+ public Content ContentBlock { get; init; }
+
+ [JsonConstructor]
+ internal ContentStartEventData() : base(EventType.ContentBlockStart)
+ {
+ }
+
+ public ContentStartEventData(int index, Content contentBlock) : base(EventType.ContentBlockStart)
+ {
+ Index = index;
+ ContentBlock = contentBlock;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ContentStopEventData.cs b/src/AnthropicClient/Models/ContentStopEventData.cs
new file mode 100644
index 0000000..b0ac609
--- /dev/null
+++ b/src/AnthropicClient/Models/ContentStopEventData.cs
@@ -0,0 +1,18 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public class ContentStopEventData : EventData
+{
+ public int Index { get; init; }
+
+ [JsonConstructor]
+ internal ContentStopEventData() : base(EventType.ContentBlockStop)
+ {
+ }
+
+ public ContentStopEventData(int index) : base(EventType.ContentBlockStop)
+ {
+ Index = index;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ErrorEventData.cs b/src/AnthropicClient/Models/ErrorEventData.cs
new file mode 100644
index 0000000..a0b0af2
--- /dev/null
+++ b/src/AnthropicClient/Models/ErrorEventData.cs
@@ -0,0 +1,18 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public class ErrorEventData : EventData
+{
+ public Error Error { get; init; } = default!;
+
+ [JsonConstructor]
+ internal ErrorEventData() : base(EventType.Error)
+ {
+ }
+
+ public ErrorEventData(Error error) : base(EventType.Error)
+ {
+ Error = error;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/EventData.cs b/src/AnthropicClient/Models/EventData.cs
new file mode 100644
index 0000000..e73d531
--- /dev/null
+++ b/src/AnthropicClient/Models/EventData.cs
@@ -0,0 +1,13 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public abstract class EventData
+{
+ public string Type { get; init; }
+
+ protected EventData(string type)
+ {
+ Type = type;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/EventType.cs b/src/AnthropicClient/Models/EventType.cs
new file mode 100644
index 0000000..a652168
--- /dev/null
+++ b/src/AnthropicClient/Models/EventType.cs
@@ -0,0 +1,13 @@
+namespace AnthropicClient.Models;
+
+public static class EventType
+{
+ public const string Error = "error";
+ public const string Ping = "ping";
+ public const string MessageStart = "message_start";
+ public const string MessageDelta = "message_delta";
+ public const string MessageStop = "message_stop";
+ public const string ContentBlockStart = "content_block_start";
+ public const string ContentBlockDelta = "content_block_delta";
+ public const string ContentBlockStop = "content_block_stop";
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/JsonDelta.cs b/src/AnthropicClient/Models/JsonDelta.cs
new file mode 100644
index 0000000..80c8b00
--- /dev/null
+++ b/src/AnthropicClient/Models/JsonDelta.cs
@@ -0,0 +1,19 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public class JsonDelta : ContentDelta
+{
+ [JsonPropertyName("partial_json")]
+ public string PartialJson { get; init; } = string.Empty;
+
+ [JsonConstructor]
+ internal JsonDelta() : base(ContentDeltaType.JsonDelta)
+ {
+ }
+
+ public JsonDelta(string partialJson) : base(ContentDeltaType.JsonDelta)
+ {
+ PartialJson = partialJson;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/MessageDeltaEventData.cs b/src/AnthropicClient/Models/MessageDeltaEventData.cs
new file mode 100644
index 0000000..240e307
--- /dev/null
+++ b/src/AnthropicClient/Models/MessageDeltaEventData.cs
@@ -0,0 +1,40 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public class MessageDeltaEventData : EventData
+{
+ public MessageDelta Delta { get; init; }
+ public ChatUsage Usage { get; init; }
+
+ [JsonConstructor]
+ internal MessageDeltaEventData() : base(EventType.MessageDelta)
+ {
+ }
+
+ public MessageDeltaEventData(MessageDelta delta, ChatUsage usage) : base(EventType.MessageDelta)
+ {
+ Delta = delta;
+ Usage = usage;
+ }
+}
+
+public class MessageDelta
+{
+ [JsonPropertyName("stop_reason")]
+ public string StopReason { get; init; } = string.Empty;
+
+ [JsonPropertyName("stop_sequence")]
+ public string StopSequence { get; init; } = string.Empty;
+
+ [JsonConstructor]
+ internal MessageDelta()
+ {
+ }
+
+ public MessageDelta(string stopReason, string stopSequence)
+ {
+ StopReason = stopReason;
+ StopSequence = stopSequence;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/MessageRequest.cs b/src/AnthropicClient/Models/MessageRequest.cs
index a676c4e..7beeeaa 100644
--- a/src/AnthropicClient/Models/MessageRequest.cs
+++ b/src/AnthropicClient/Models/MessageRequest.cs
@@ -1,3 +1,7 @@
+using System.Text.Json.Serialization;
+
+using AnthropicClient.Utils;
+
namespace AnthropicClient.Models;
///
@@ -5,18 +9,139 @@ namespace AnthropicClient.Models;
///
public abstract class MessageRequest
{
+ ///
+ /// Gets the model ID to use for the request.
+ ///
+ public string Model { get; init; } = string.Empty;
+
+ ///
+ /// Gets the system ID to use for the request.
+ ///
+ public string? System { get; init; } = null;
+
+ ///
+ /// Gets the messages to send to the model.
+ ///
+ public List Messages { get; init; } = [];
+
+ ///
+ /// Gets the maximum number of tokens to generate.
+ ///
+ [JsonPropertyName("max_tokens")]
+ public int MaxTokens { get; init; } = 1024;
+
+ ///
+ /// Gets the metadata to include with the request.
+ ///
+ public Dictionary? Metadata { get; init; } = null;
+
+ ///
+ /// Gets the prompt stop sequences.
+ ///
+ [JsonPropertyName("stop_sequences")]
+ public List StopSequences { get; init; } = [];
+
+ ///
+ /// Gets the temperature to use for the request.
+ ///
+ public decimal Temperature { get; init; } = 0.0m;
+
+ ///
+ /// Gets the top-K value to use for the request.
+ ///
+ public int? TopK { get; init; } = null;
+
+ ///
+ /// Gets the top-P value to use for the request.
+ ///
+ public decimal? TopP { get; init; } = null;
+
+ ///
+ /// Gets the tool choice mode to use for the request.
+ ///
+ [JsonPropertyName("tool_choice")]
+ public ToolChoice? ToolChoice { get; init; } = null;
+
+ ///
+ /// Gets the tools to use for the request.
+ ///
+ public List? Tools { get; init; } = null;
+
///
/// Gets a value indicating whether the message should be streamed.
///
public bool Stream { get; init; }
+ [JsonConstructor]
+ internal MessageRequest() { }
+
///
/// Initializes a new instance of the class.
///
+ /// The model ID to use for the request.
+ /// The messages to send to the model.
+ /// The maximum number of tokens to generate.
+ /// The system ID to use for the request.
+ /// The metadata to include with the request.
+ /// The temperature to use for the request.
+ /// The top-K value to use for the request.
+ /// The top-P value to use for the request.
+ /// The tool choice mode to use for the request.
+ /// The tools to use for the request.
/// A value indicating whether the message should be streamed.
+ /// Thrown when the model ID is invalid.
+ /// Thrown when the model or messages is null.
+ /// Thrown when the messages contain no messages.
+ /// Thrown when the max tokens is less than one.
+ /// Thrown when the temperature is less than zero or greater than one.
/// A new instance of the class.
- public MessageRequest(bool stream = false)
+ protected MessageRequest(
+ string model,
+ List messages,
+ int maxTokens = 1024,
+ string? system = null,
+ Dictionary? metadata = null,
+ decimal temperature = 0.0m,
+ int? topK = null,
+ decimal? topP = null,
+ ToolChoice? toolChoice = null,
+ List? tools = null,
+ bool stream = 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;
Stream = stream;
}
}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/MessageStartEventData.cs b/src/AnthropicClient/Models/MessageStartEventData.cs
new file mode 100644
index 0000000..16b4451
--- /dev/null
+++ b/src/AnthropicClient/Models/MessageStartEventData.cs
@@ -0,0 +1,18 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public class MessageStartEventData : EventData
+{
+ public ChatMessage Message { get; init; } = new();
+
+ [JsonConstructor]
+ internal MessageStartEventData() : base(EventType.MessageStart)
+ {
+ }
+
+ public MessageStartEventData(ChatMessage message) : base(EventType.MessageStart)
+ {
+ Message = message;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/MessageStopEventData.cs b/src/AnthropicClient/Models/MessageStopEventData.cs
new file mode 100644
index 0000000..ed781e6
--- /dev/null
+++ b/src/AnthropicClient/Models/MessageStopEventData.cs
@@ -0,0 +1,8 @@
+namespace AnthropicClient.Models;
+
+public class MessageStopEventData : EventData
+{
+ public MessageStopEventData() : base(EventType.MessageStop)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/PingEventData.cs b/src/AnthropicClient/Models/PingEventData.cs
new file mode 100644
index 0000000..e288154
--- /dev/null
+++ b/src/AnthropicClient/Models/PingEventData.cs
@@ -0,0 +1,8 @@
+namespace AnthropicClient.Models;
+
+public class PingEventData : EventData
+{
+ public PingEventData() : base(EventType.Ping)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/StreamChatMessageRequest.cs b/src/AnthropicClient/Models/StreamChatMessageRequest.cs
new file mode 100644
index 0000000..bcf50fb
--- /dev/null
+++ b/src/AnthropicClient/Models/StreamChatMessageRequest.cs
@@ -0,0 +1,58 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+///
+/// Represents a chat message request.
+///
+public class StreamChatMessageRequest : MessageRequest
+{
+ [JsonConstructor]
+ internal StreamChatMessageRequest() : base() { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The model ID to use for the request.
+ /// The messages to send to the model.
+ /// The maximum number of tokens to generate.
+ /// The system ID to use for the request.
+ /// The metadata to include with the request.
+ /// The temperature to use for the request.
+ /// The top-K value to use for the request.
+ /// The top-P value to use for the request.
+ /// The tool choice mode to use for the request.
+ /// The tools to use for the request.
+ /// Thrown when the model ID is invalid.
+ /// Thrown when the model or messages is null.
+ /// Thrown when the messages contain no messages.
+ /// Thrown when the max tokens is less than one.
+ /// Thrown when the temperature is less than zero or greater than one.
+ /// A new instance of the class.
+ public StreamChatMessageRequest(
+ string model,
+ List messages,
+ int maxTokens = 1024,
+ string? system = null,
+ Dictionary? metadata = null,
+ decimal temperature = 0.0m,
+ int? topK = null,
+ decimal? topP = null,
+ ToolChoice? toolChoice = null,
+ List? tools = null
+ ) : base(
+ model,
+ messages,
+ maxTokens,
+ system,
+ metadata,
+ temperature,
+ topK,
+ topP,
+ toolChoice,
+ tools,
+ true
+ )
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/TextDelta.cs b/src/AnthropicClient/Models/TextDelta.cs
new file mode 100644
index 0000000..0768ca2
--- /dev/null
+++ b/src/AnthropicClient/Models/TextDelta.cs
@@ -0,0 +1,18 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+public class TextDelta : ContentDelta
+{
+ public string Text { get; set; } = string.Empty;
+
+ [JsonConstructor]
+ internal TextDelta() : base(ContentDeltaType.TextDelta)
+ {
+ }
+
+ public TextDelta(string text) : base(ContentDeltaType.TextDelta)
+ {
+ Text = text;
+ }
+}
\ No newline at end of file
diff --git a/src/AnthropicClient/Models/ToolResultContent.cs b/src/AnthropicClient/Models/ToolResultContent.cs
index f8b8f82..b49f918 100644
--- a/src/AnthropicClient/Models/ToolResultContent.cs
+++ b/src/AnthropicClient/Models/ToolResultContent.cs
@@ -13,12 +13,12 @@ public class ToolResultContent : Content
/// Gets the tool use ID of the content.
///
[JsonPropertyName("tool_use_id")]
- public string ToolUseId { get; set; } = string.Empty;
+ public string ToolUseId { get; init; } = string.Empty;
///
/// Gets the content of the tool result.
///
- public string Content { get; set; } = string.Empty;
+ public string Content { get; init; } = string.Empty;
[JsonConstructor]
internal ToolResultContent() : base(ContentType.ToolResult) { }
diff --git a/src/AnthropicClient/Models/ToolUseContent.cs b/src/AnthropicClient/Models/ToolUseContent.cs
index aef8668..b09dcd7 100644
--- a/src/AnthropicClient/Models/ToolUseContent.cs
+++ b/src/AnthropicClient/Models/ToolUseContent.cs
@@ -8,17 +8,17 @@ public class ToolUseContent : Content
///
/// Gets the ID of the tool use.
///
- public string Id { get; set; } = string.Empty;
+ public string Id { get; init; } = string.Empty;
///
/// Gets the name of the tool.
///
- public string Name { get; set; } = string.Empty;
+ public string Name { get; init; } = string.Empty;
///
/// Gets the input of the tool.
///
- public Dictionary Input { get; set; } = [];
+ public Dictionary Input { get; init; } = [];
///
/// Initializes a new instance of the class.
diff --git a/tests/AnthropicClient.Tests/EndToEnd/ClientTests.cs b/tests/AnthropicClient.Tests/EndToEnd/ClientTests.cs
index d51f0ba..aee03d6 100644
--- a/tests/AnthropicClient.Tests/EndToEnd/ClientTests.cs
+++ b/tests/AnthropicClient.Tests/EndToEnd/ClientTests.cs
@@ -18,4 +18,24 @@ public class ClientTests(
result.IsSuccess.Should().BeTrue();
result.Value.Should().BeOfType();
}
+
+ [Fact]
+ public async Task CreateChatMessage_WhenCalledWithStreamRequest_IteratesOverChatResponse()
+ {
+ var request = new StreamChatMessageRequest(
+ model: AnthropicModels.Claude3Haiku,
+ messages: [new(MessageRole.User, [new TextContent("Hello!")])]
+ );
+
+ var response = _client.CreateChatMessageAsync(request);
+
+ var events = new List();
+
+ await foreach (var e in response)
+ {
+ events.Add(e);
+ }
+
+ events.Should().NotBeEmpty();
+ }
}
\ No newline at end of file