2024-07-01 23:59:24 -05:00
|
|
|
namespace AnthropicClient.Tests.Integration;
|
|
|
|
|
|
|
|
|
|
public class AnthropicApiClientTests : IntegrationTest
|
|
|
|
|
{
|
|
|
|
|
[Theory]
|
|
|
|
|
[ClassData(typeof(ErrorTestData))]
|
2024-07-03 16:57:27 -05:00
|
|
|
public async Task CreateMessageAsync_WhenCalledAndErrorReturned_ItShouldHandleError(
|
2024-07-01 23:59:24 -05:00
|
|
|
HttpStatusCode statusCode,
|
|
|
|
|
string content,
|
|
|
|
|
Type errorType
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
_mockHttpMessageHandler
|
|
|
|
|
.WhenCreateMessageRequest()
|
|
|
|
|
.Respond(
|
|
|
|
|
statusCode,
|
|
|
|
|
"application/json",
|
|
|
|
|
content
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var request = new MessageRequest(
|
2024-07-01 23:59:24 -05:00
|
|
|
model: AnthropicModels.Claude3Haiku,
|
|
|
|
|
messages: [new(MessageRole.User, [new TextContent("Hello!")])]
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var result = await Client.CreateMessageAsync(request);
|
2024-07-01 23:59:24 -05:00
|
|
|
|
|
|
|
|
result.IsSuccess.Should().BeFalse();
|
|
|
|
|
result.Error.Should().BeOfType<AnthropicError>();
|
2024-07-07 16:21:23 -05:00
|
|
|
|
2024-07-01 23:59:24 -05:00
|
|
|
var actualErrorType = result.Error.Error!.GetType();
|
|
|
|
|
actualErrorType.Should().Be(errorType);
|
|
|
|
|
}
|
2024-07-03 00:11:48 -05:00
|
|
|
|
|
|
|
|
[Fact]
|
2024-07-03 16:57:27 -05:00
|
|
|
public async Task CreateMessageAsync_WhenCalledAndMessageCreatedWithTextContent_ItShouldReturnMessage()
|
2024-07-03 00:11:48 -05:00
|
|
|
{
|
|
|
|
|
_mockHttpMessageHandler
|
|
|
|
|
.WhenCreateMessageRequest()
|
|
|
|
|
.Respond(
|
|
|
|
|
HttpStatusCode.OK,
|
|
|
|
|
"application/json",
|
|
|
|
|
@"{
|
|
|
|
|
""content"": [
|
|
|
|
|
{
|
|
|
|
|
""text"": ""Hi! My name is Claude."",
|
|
|
|
|
""type"": ""text""
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
""id"": ""msg_013Zva2CMHLNnXjNJJKqJ2EF"",
|
|
|
|
|
""model"": ""claude-3-5-sonnet-20240620"",
|
|
|
|
|
""role"": ""assistant"",
|
|
|
|
|
""stop_reason"": ""end_turn"",
|
|
|
|
|
""stop_sequence"": null,
|
|
|
|
|
""type"": ""message"",
|
|
|
|
|
""usage"": {
|
|
|
|
|
""input_tokens"": 10,
|
|
|
|
|
""output_tokens"": 25
|
|
|
|
|
}
|
|
|
|
|
}"
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var request = new MessageRequest(
|
2024-07-03 00:11:48 -05:00
|
|
|
model: AnthropicModels.Claude35Sonnet,
|
|
|
|
|
messages: [new(MessageRole.User, [new TextContent("Hello!")])]
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var result = await Client.CreateMessageAsync(request);
|
2024-07-03 00:11:48 -05:00
|
|
|
|
|
|
|
|
result.IsSuccess.Should().BeTrue();
|
2024-07-03 16:57:27 -05:00
|
|
|
result.Value.Should().BeOfType<MessageResponse>();
|
2024-07-03 00:11:48 -05:00
|
|
|
|
|
|
|
|
var message = result.Value;
|
|
|
|
|
message.Id.Should().Be("msg_013Zva2CMHLNnXjNJJKqJ2EF");
|
|
|
|
|
message.Model.Should().Be("claude-3-5-sonnet-20240620");
|
|
|
|
|
message.Role.Should().Be("assistant");
|
|
|
|
|
message.StopReason.Should().Be("end_turn");
|
|
|
|
|
message.StopSequence.Should().BeNull();
|
|
|
|
|
message.Type.Should().Be("message");
|
|
|
|
|
message.Usage.InputTokens.Should().Be(10);
|
|
|
|
|
message.Usage.OutputTokens.Should().Be(25);
|
|
|
|
|
message.Content.Should().HaveCount(1);
|
|
|
|
|
message.ToolCall.Should().BeNull();
|
2024-07-07 16:21:23 -05:00
|
|
|
|
2024-07-03 00:11:48 -05:00
|
|
|
var textContent = message.Content[0];
|
|
|
|
|
textContent.Should().BeOfType<TextContent>();
|
|
|
|
|
textContent.As<TextContent>().Text.Should().Be("Hi! My name is Claude.");
|
|
|
|
|
textContent.As<TextContent>().Type.Should().Be("text");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
2024-07-03 16:57:27 -05:00
|
|
|
public async Task CreateMessageAsync_WhenCalledAndMessageCreatedWithToolUseContentAndToolIsProvided_ItShouldReturnMessageWithToolCall()
|
2024-07-03 00:11:48 -05:00
|
|
|
{
|
|
|
|
|
_mockHttpMessageHandler
|
|
|
|
|
.WhenCreateMessageRequest()
|
|
|
|
|
.Respond(
|
|
|
|
|
HttpStatusCode.OK,
|
|
|
|
|
"application/json",
|
|
|
|
|
@"{
|
|
|
|
|
""content"": [
|
|
|
|
|
{
|
|
|
|
|
""id"": ""toolu_01D7FLrfh4GYq7yT1ULFeyMV"",
|
|
|
|
|
""name"": ""get_stock_price"",
|
|
|
|
|
""input"": { ""ticker"": ""^GSPC"" },
|
|
|
|
|
""type"": ""tool_use""
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
""id"": ""msg_01D7FLrfh4GYq7yT1ULFeyMV"",
|
|
|
|
|
""model"": ""claude-3-5-sonnet-20240620"",
|
|
|
|
|
""role"": ""assistant"",
|
|
|
|
|
""stop_reason"": ""end_turn"",
|
|
|
|
|
""stop_sequence"": null,
|
|
|
|
|
""type"": ""message"",
|
|
|
|
|
""usage"": {
|
|
|
|
|
""input_tokens"": 10,
|
|
|
|
|
""output_tokens"": 25
|
|
|
|
|
}
|
|
|
|
|
}"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var func = (string ticker) => ticker;
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var request = new MessageRequest(
|
2024-07-03 00:11:48 -05:00
|
|
|
model: AnthropicModels.Claude35Sonnet,
|
|
|
|
|
messages: [
|
|
|
|
|
new(MessageRole.User, [new TextContent("Hello!")]),
|
|
|
|
|
],
|
|
|
|
|
tools: [
|
|
|
|
|
Tool.CreateFromFunction("get_stock_price", "Gets the stock price for a given ticker", func)
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var result = await Client.CreateMessageAsync(request);
|
2024-07-03 00:11:48 -05:00
|
|
|
|
|
|
|
|
result.IsSuccess.Should().BeTrue();
|
2024-07-03 16:57:27 -05:00
|
|
|
result.Value.Should().BeOfType<MessageResponse>();
|
2024-07-03 00:11:48 -05:00
|
|
|
|
|
|
|
|
var message = result.Value;
|
|
|
|
|
message.Id.Should().Be("msg_01D7FLrfh4GYq7yT1ULFeyMV");
|
|
|
|
|
message.Model.Should().Be("claude-3-5-sonnet-20240620");
|
|
|
|
|
message.Role.Should().Be("assistant");
|
|
|
|
|
message.StopReason.Should().Be("end_turn");
|
|
|
|
|
message.StopSequence.Should().BeNull();
|
|
|
|
|
message.Type.Should().Be("message");
|
|
|
|
|
message.Usage.InputTokens.Should().Be(10);
|
|
|
|
|
message.Usage.OutputTokens.Should().Be(25);
|
|
|
|
|
message.Content.Should().HaveCount(1);
|
|
|
|
|
message.ToolCall.Should().NotBeNull();
|
|
|
|
|
|
|
|
|
|
var toolUseContent = message.Content[0];
|
|
|
|
|
toolUseContent.Should().BeOfType<ToolUseContent>();
|
|
|
|
|
|
|
|
|
|
toolUseContent.As<ToolUseContent>().Id.Should().Be("toolu_01D7FLrfh4GYq7yT1ULFeyMV");
|
|
|
|
|
toolUseContent.As<ToolUseContent>().Name.Should().Be("get_stock_price");
|
|
|
|
|
toolUseContent.As<ToolUseContent>().Type.Should().Be("tool_use");
|
|
|
|
|
|
|
|
|
|
var input = toolUseContent.As<ToolUseContent>().Input;
|
|
|
|
|
var ticker = input.GetValueOrDefault("ticker");
|
|
|
|
|
ticker!.ToString().Should().Be("^GSPC");
|
|
|
|
|
|
|
|
|
|
var toolCallResult = await message.ToolCall!.InvokeAsync();
|
|
|
|
|
toolCallResult.IsSuccess.Should().BeTrue();
|
|
|
|
|
toolCallResult.Value!.ToString().Should().Be("^GSPC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[Fact]
|
2024-07-03 16:57:27 -05:00
|
|
|
public async Task CreateMessageAsync_WhenCalledAndMessageCreatedWithToolUseButNoToolProvided_ItShouldReturnMessageWithoutToolCall()
|
2024-07-03 00:11:48 -05:00
|
|
|
{
|
|
|
|
|
_mockHttpMessageHandler
|
|
|
|
|
.WhenCreateMessageRequest()
|
|
|
|
|
.Respond(
|
|
|
|
|
HttpStatusCode.OK,
|
|
|
|
|
"application/json",
|
|
|
|
|
@"{
|
|
|
|
|
""content"": [
|
|
|
|
|
{
|
|
|
|
|
""id"": ""toolu_01D7FLrfh4GYq7yT1ULFeyMV"",
|
|
|
|
|
""name"": ""get_stock_price"",
|
|
|
|
|
""input"": { ""ticker"": ""^GSPC"" },
|
|
|
|
|
""type"": ""tool_use""
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
""id"": ""msg_01D7FLrfh4GYq7yT1ULFeyMV"",
|
|
|
|
|
""model"": ""claude-3-5-sonnet-20240620"",
|
|
|
|
|
""role"": ""assistant"",
|
|
|
|
|
""stop_reason"": ""end_turn"",
|
|
|
|
|
""stop_sequence"": null,
|
|
|
|
|
""type"": ""message"",
|
|
|
|
|
""usage"": {
|
|
|
|
|
""input_tokens"": 10,
|
|
|
|
|
""output_tokens"": 25
|
|
|
|
|
}
|
|
|
|
|
}"
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var request = new MessageRequest(
|
2024-07-03 00:11:48 -05:00
|
|
|
model: AnthropicModels.Claude35Sonnet,
|
|
|
|
|
messages: [
|
|
|
|
|
new(MessageRole.User, [new TextContent("Hello!")]),
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var result = await Client.CreateMessageAsync(request);
|
2024-07-03 00:11:48 -05:00
|
|
|
|
|
|
|
|
result.IsSuccess.Should().BeTrue();
|
2024-07-03 16:57:27 -05:00
|
|
|
result.Value.Should().BeOfType<MessageResponse>();
|
2024-07-03 00:11:48 -05:00
|
|
|
|
|
|
|
|
var message = result.Value;
|
|
|
|
|
message.Id.Should().Be("msg_01D7FLrfh4GYq7yT1ULFeyMV");
|
|
|
|
|
message.Model.Should().Be("claude-3-5-sonnet-20240620");
|
|
|
|
|
message.Role.Should().Be("assistant");
|
|
|
|
|
message.StopReason.Should().Be("end_turn");
|
|
|
|
|
message.StopSequence.Should().BeNull();
|
|
|
|
|
message.Type.Should().Be("message");
|
|
|
|
|
message.Usage.InputTokens.Should().Be(10);
|
|
|
|
|
message.Usage.OutputTokens.Should().Be(25);
|
|
|
|
|
message.Content.Should().HaveCount(1);
|
|
|
|
|
message.ToolCall.Should().BeNull();
|
|
|
|
|
|
|
|
|
|
var toolUseContent = message.Content[0];
|
|
|
|
|
toolUseContent.Should().BeOfType<ToolUseContent>();
|
|
|
|
|
|
|
|
|
|
toolUseContent.As<ToolUseContent>().Id.Should().Be("toolu_01D7FLrfh4GYq7yT1ULFeyMV");
|
|
|
|
|
toolUseContent.As<ToolUseContent>().Name.Should().Be("get_stock_price");
|
|
|
|
|
toolUseContent.As<ToolUseContent>().Type.Should().Be("tool_use");
|
|
|
|
|
|
|
|
|
|
var input = toolUseContent.As<ToolUseContent>().Input;
|
|
|
|
|
var ticker = input.GetValueOrDefault("ticker");
|
|
|
|
|
ticker!.ToString().Should().Be("^GSPC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Theory]
|
|
|
|
|
[ClassData(typeof(EventTestData))]
|
2024-07-03 16:57:27 -05:00
|
|
|
public async Task CreateMessageAsync_WhenCalledAndMessageIsStreamed_ItShouldHandleAllEventTypes(string eventString, AnthropicEvent anthropicEvent)
|
2024-07-03 00:11:48 -05:00
|
|
|
{
|
|
|
|
|
_mockHttpMessageHandler
|
|
|
|
|
.WhenCreateStreamMessageRequest()
|
|
|
|
|
.Respond(
|
|
|
|
|
HttpStatusCode.OK,
|
|
|
|
|
"text/event-stream",
|
|
|
|
|
new MemoryStream(Encoding.UTF8.GetBytes(eventString))
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var request = new StreamMessageRequest(
|
2024-07-03 00:11:48 -05:00
|
|
|
model: AnthropicModels.Claude35Sonnet,
|
|
|
|
|
messages: [
|
|
|
|
|
new(MessageRole.User, [new TextContent("Hello!")]),
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var result = Client.CreateMessageAsync(request);
|
2024-07-03 00:11:48 -05:00
|
|
|
var e = await result.FirstOrDefaultAsync();
|
|
|
|
|
|
|
|
|
|
e.Should().BeEquivalentTo(anthropicEvent);
|
|
|
|
|
}
|
2024-07-03 13:58:58 -05:00
|
|
|
|
|
|
|
|
[Fact]
|
2024-07-03 16:57:27 -05:00
|
|
|
public async Task CreateMessageAsync_WhenCalledAndMessageIsStreamed_ItShouldReturnAllExpectedEvents()
|
2024-07-03 13:58:58 -05:00
|
|
|
{
|
|
|
|
|
var eventStream = EventTestData.GetEventStream();
|
|
|
|
|
var events = EventTestData.GetAllEvents();
|
|
|
|
|
|
|
|
|
|
_mockHttpMessageHandler
|
|
|
|
|
.WhenCreateStreamMessageRequest()
|
|
|
|
|
.Respond(
|
|
|
|
|
HttpStatusCode.OK,
|
|
|
|
|
"text/event-stream",
|
|
|
|
|
eventStream
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var request = new StreamMessageRequest(
|
2024-07-03 13:58:58 -05:00
|
|
|
model: AnthropicModels.Claude35Sonnet,
|
|
|
|
|
messages: [
|
|
|
|
|
new(MessageRole.User, [new TextContent("Hello!")]),
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var result = Client.CreateMessageAsync(request);
|
2024-07-03 13:58:58 -05:00
|
|
|
|
|
|
|
|
var actualEvents = await result.ToListAsync();
|
|
|
|
|
|
|
|
|
|
actualEvents.Should().BeEquivalentTo(events);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
2024-07-03 16:57:27 -05:00
|
|
|
public async Task CreateMessageAsync_WhenCalledMessageIsStreamedAndToolProvide_ItShouldReturnToolCall()
|
2024-07-03 13:58:58 -05:00
|
|
|
{
|
|
|
|
|
var eventStream = EventTestData.GetEventStream();
|
|
|
|
|
|
|
|
|
|
_mockHttpMessageHandler
|
|
|
|
|
.WhenCreateStreamMessageRequest()
|
|
|
|
|
.Respond(
|
|
|
|
|
HttpStatusCode.OK,
|
|
|
|
|
"text/event-stream",
|
|
|
|
|
eventStream
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var getWeather = (string location, string unit) => $"The weather in {location} is 72°{unit}";
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var request = new StreamMessageRequest(
|
2024-07-03 13:58:58 -05:00
|
|
|
model: AnthropicModels.Claude35Sonnet,
|
|
|
|
|
messages: [
|
|
|
|
|
new(MessageRole.User, [new TextContent("Hello!")]),
|
|
|
|
|
],
|
|
|
|
|
tools: [
|
|
|
|
|
Tool.CreateFromFunction("get_weather", "Gets the weather for a location", getWeather)
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-03 16:57:27 -05:00
|
|
|
var result = Client.CreateMessageAsync(request);
|
2024-07-03 13:58:58 -05:00
|
|
|
var msgCompleteEvent = await result
|
|
|
|
|
.Where(e => e.Type is EventType.MessageComplete)
|
|
|
|
|
.FirstAsync();
|
2024-07-07 16:21:23 -05:00
|
|
|
|
2024-07-03 13:58:58 -05:00
|
|
|
msgCompleteEvent.Data.Should().BeOfType<MessageCompleteEventData>();
|
2024-07-07 16:21:23 -05:00
|
|
|
|
2024-07-03 13:58:58 -05:00
|
|
|
var toolCall = msgCompleteEvent.Data.As<MessageCompleteEventData>().Message.ToolCall;
|
|
|
|
|
var toolCallResult = await toolCall!.InvokeAsync<string>();
|
|
|
|
|
|
|
|
|
|
toolCallResult.IsSuccess.Should().BeTrue();
|
2024-07-07 16:21:23 -05:00
|
|
|
toolCallResult.Value.Should().Be(getWeather("San Francisco, CA", "fahrenheit"));
|
2024-07-03 13:58:58 -05:00
|
|
|
}
|
2024-07-19 21:15:59 -05:00
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task CreateMessageAsync_WhenCalledMessageIsStreamAndRequestFails_ItShouldReturnErrorEvent()
|
|
|
|
|
{
|
|
|
|
|
_mockHttpMessageHandler
|
|
|
|
|
.WhenCreateStreamMessageRequest()
|
|
|
|
|
.Respond(
|
|
|
|
|
HttpStatusCode.BadRequest,
|
|
|
|
|
"application/json",
|
|
|
|
|
@"{
|
|
|
|
|
""type"": ""error"",
|
|
|
|
|
""error"": {
|
|
|
|
|
""type"": ""invalid_request_error"",
|
|
|
|
|
""message"": ""messages: roles must alternate between user and assistant, but found multiple user roles in a row""
|
|
|
|
|
}
|
|
|
|
|
}"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var request = new StreamMessageRequest(
|
|
|
|
|
model: AnthropicModels.Claude35Sonnet,
|
|
|
|
|
messages: [
|
|
|
|
|
new(MessageRole.User, [new TextContent("Hello!")]),
|
|
|
|
|
new(MessageRole.User, [new TextContent("Hello!")])
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var result = Client.CreateMessageAsync(request);
|
|
|
|
|
var events = await result.ToListAsync();
|
|
|
|
|
|
|
|
|
|
events.Should().HaveCount(1);
|
|
|
|
|
events[0].Type.Should().Be(EventType.Error);
|
|
|
|
|
events[0].Data.Should().BeOfType<ErrorEventData>();
|
|
|
|
|
events[0].Data.Should().BeEquivalentTo(new ErrorEventData(
|
|
|
|
|
new InvalidRequestError(
|
|
|
|
|
"messages: roles must alternate between user and assistant, but found multiple user roles in a row"
|
|
|
|
|
)
|
|
|
|
|
));
|
|
|
|
|
}
|
2024-11-21 13:55:56 -06:00
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task CreateMessageAsync_WhenCalledAndMessageCreatedWithDocumentContent_ItShouldReturnMessage()
|
|
|
|
|
{
|
|
|
|
|
_mockHttpMessageHandler
|
|
|
|
|
.WhenCreateMessageRequest()
|
|
|
|
|
.Respond(
|
|
|
|
|
HttpStatusCode.OK,
|
|
|
|
|
"application/json",
|
|
|
|
|
@"{
|
|
|
|
|
""content"": [
|
|
|
|
|
{
|
|
|
|
|
""text"": ""It is a PDF"",
|
|
|
|
|
""type"": ""text""
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
""id"": ""msg_013Zva2CMHLNnXjNJJKqJ2EF"",
|
|
|
|
|
""model"": ""claude-3-5-sonnet-20240620"",
|
|
|
|
|
""role"": ""assistant"",
|
|
|
|
|
""stop_reason"": ""end_turn"",
|
|
|
|
|
""stop_sequence"": null,
|
|
|
|
|
""type"": ""message"",
|
|
|
|
|
""usage"": {
|
|
|
|
|
""input_tokens"": 10,
|
|
|
|
|
""output_tokens"": 25
|
|
|
|
|
}
|
|
|
|
|
}"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var request = new MessageRequest(
|
|
|
|
|
model: AnthropicModels.Claude35Sonnet,
|
|
|
|
|
messages: [
|
|
|
|
|
new(MessageRole.User, [new TextContent("What is this?")]),
|
|
|
|
|
new(MessageRole.User, [new DocumentContent("application/pdf", "data")])
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var result = await Client.CreateMessageAsync(request);
|
|
|
|
|
|
|
|
|
|
result.IsSuccess.Should().BeTrue();
|
|
|
|
|
result.Value.Should().BeOfType<MessageResponse>();
|
|
|
|
|
|
|
|
|
|
var message = result.Value;
|
|
|
|
|
message.Id.Should().Be("msg_013Zva2CMHLNnXjNJJKqJ2EF");
|
|
|
|
|
message.Model.Should().Be("claude-3-5-sonnet-20240620");
|
|
|
|
|
message.Role.Should().Be("assistant");
|
|
|
|
|
message.StopReason.Should().Be("end_turn");
|
|
|
|
|
message.StopSequence.Should().BeNull();
|
|
|
|
|
message.Type.Should().Be("message");
|
|
|
|
|
message.Usage.InputTokens.Should().Be(10);
|
|
|
|
|
message.Usage.OutputTokens.Should().Be(25);
|
|
|
|
|
message.Content.Should().HaveCount(1);
|
|
|
|
|
message.ToolCall.Should().BeNull();
|
|
|
|
|
|
|
|
|
|
var textContent = message.Content[0];
|
|
|
|
|
textContent.Should().BeOfType<TextContent>();
|
|
|
|
|
textContent.As<TextContent>().Text.Should().Be("It is a PDF");
|
|
|
|
|
textContent.As<TextContent>().Type.Should().Be("text");
|
|
|
|
|
}
|
2024-07-01 23:59:24 -05:00
|
|
|
}
|