fix: move client to top level namespace

This commit is contained in:
Stevan Freeborn
2024-06-28 10:53:36 -05:00
parent 8c0c60faea
commit 422719f509
@@ -4,8 +4,9 @@ using System.Text.Json;
using AnthropicClient.Json;
using AnthropicClient.Utils;
using AnthropicClient.Models;
namespace AnthropicClient.Models;
namespace AnthropicClient;
/// <summary>
/// Represents a client for interacting with the Anthropic API.
@@ -18,6 +19,13 @@ public interface IClient
/// <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);
/// <summary>
/// Creates a chat message asynchronously and streams the response.
/// </summary>
/// <param name="request">The chat message request to create.</param>
/// <returns>An asynchronous enumerable that yields the chat response line by line.</returns>
IAsyncEnumerable<AnthropicEvent> CreateChatMessageAsync(StreamChatMessageRequest request);
}
/// <inheritdoc cref="IClient"/>
@@ -62,8 +70,7 @@ public class Client : IClient
/// <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 response = await SendRequestAsync(request);
var requestId = GetRequestId(response);
var responseContent = await response.Content.ReadAsStringAsync();
@@ -77,6 +84,70 @@ public class Client : IClient
return AnthropicResult<ChatResponse>.Success(chatResponse, requestId);
}
/// <inheritdoc />
public async IAsyncEnumerable<AnthropicEvent> CreateChatMessageAsync(StreamChatMessageRequest request)
{
var response = await SendRequestAsync(request);
var requestId = GetRequestId(response);
using var responseContent = await response.Content.ReadAsStreamAsync();
using var streamReader = new StreamReader(responseContent);
var currentEvent = new AnthropicEvent();
// TODO: I'd like to emit custom events unique to this client
// - "content_block_complete"
// - provides the complete content block that was streamed
// - useful for streaming in text, but then handling tool calls with their entire input
// will need to keep track of current content so that we can build it up as relevant
// deltas are streamed in
// will want to capture the content block start event
// then continue to build this up until we get to the content block stop event
// at that point we should have the complete block and we should be able to yield
// return the complete block and reset the current content block
// event: content_block_start
// data: {"type":"content_block_start","index":1,"content_block":{"type":"tool_use","id":"toolu_01T1x1fJ34qAmk2tNTrN7Up6","name":"get_weather","input":{}}}
do
{
var line = await streamReader.ReadLineAsync();
if (line is null)
{
break;
}
if (line.StartsWith("event:"))
{
var eventType = line.Substring("event:".Length).Trim();
currentEvent = currentEvent with { Type = eventType };
}
if (line.StartsWith("data:"))
{
var eventData = line.Substring("data:".Length).Trim();
var eventDataJson = JsonSerializer.Deserialize<EventData>(eventData, JsonSerializationOptions.DefaultOptions);
currentEvent = currentEvent with { Data = eventDataJson! };
}
if (line == string.Empty)
{
yield return currentEvent;
currentEvent = new AnthropicEvent();
}
} while (true);
}
private async Task<HttpResponseMessage> SendRequestAsync(MessageRequest request)
{
var requestContent = new StringContent(Serialize(request), Encoding.UTF8, JsonContentType);
return await _httpClient.PostAsync(MessagesEndpoint, requestContent);
}
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;