feat: implement GetModelAsync method
This commit is contained in:
@@ -49,6 +49,13 @@ public interface IAnthropicApiClient
|
|||||||
/// <returns>An asynchronous enumerable that yields the response as an <see cref="AnthropicResult{T}"/> where T is <see cref="Page{T}"/> where T is <see cref="AnthropicModel"/>.</returns>
|
/// <returns>An asynchronous enumerable that yields the response as an <see cref="AnthropicResult{T}"/> where T is <see cref="Page{T}"/> where T is <see cref="AnthropicModel"/>.</returns>
|
||||||
///
|
///
|
||||||
IAsyncEnumerable<AnthropicResult<Page<AnthropicModel>>> ListAllModelsAsync(int limit = 20);
|
IAsyncEnumerable<AnthropicResult<Page<AnthropicModel>>> ListAllModelsAsync(int limit = 20);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a model by its ID asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="modelId">The ID of the model to get.</param>
|
||||||
|
/// <returns>A task that represents the asynchronous operation. The task result contains the response as an <see cref="AnthropicResult{T}"/> where T is <see cref="AnthropicModel"/>.</returns>
|
||||||
|
Task<AnthropicResult<AnthropicModel>> GetModelAsync(string modelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IAnthropicApiClient"/>
|
/// <inheritdoc cref="IAnthropicApiClient"/>
|
||||||
@@ -352,6 +359,24 @@ public class AnthropicApiClient : IAnthropicApiClient
|
|||||||
} while (hasMore);
|
} while (hasMore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<AnthropicResult<AnthropicModel>> GetModelAsync(string modelId)
|
||||||
|
{
|
||||||
|
var endpoint = $"{ModelsEndpoint}/{modelId}";
|
||||||
|
var response = await SendRequestAsync(endpoint);
|
||||||
|
var anthropicHeaders = new AnthropicHeaders(response.Headers);
|
||||||
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode is false)
|
||||||
|
{
|
||||||
|
var error = Deserialize<AnthropicError>(responseContent) ?? new AnthropicError();
|
||||||
|
return AnthropicResult<AnthropicModel>.Failure(error, anthropicHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = Deserialize<AnthropicModel>(responseContent) ?? new AnthropicModel();
|
||||||
|
return AnthropicResult<AnthropicModel>.Success(model, anthropicHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
private ToolCall? GetToolCall(MessageResponse response, List<Tool> tools)
|
private ToolCall? GetToolCall(MessageResponse response, List<Tool> tools)
|
||||||
{
|
{
|
||||||
var toolUse = response.Content.OfType<ToolUseContent>().FirstOrDefault();
|
var toolUse = response.Content.OfType<ToolUseContent>().FirstOrDefault();
|
||||||
|
|||||||
@@ -331,4 +331,14 @@ public class ClientTests(ConfigurationFixture configFixture) : EndToEndTest(conf
|
|||||||
|
|
||||||
responses.Should().HaveCountGreaterThan(0);
|
responses.Should().HaveCountGreaterThan(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetModelAsync_WhenCalled_ItShouldReturnResponse()
|
||||||
|
{
|
||||||
|
var result = await _client.GetModelAsync(AnthropicModels.Claude3Haiku);
|
||||||
|
|
||||||
|
result.IsSuccess.Should().BeTrue();
|
||||||
|
result.Value.Should().BeOfType<AnthropicModel>();
|
||||||
|
result.Value.Id.Should().Be(AnthropicModels.Claude3Haiku);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -479,7 +479,7 @@ public class AnthropicApiClientTests : IntegrationTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CountMessageTokensAsync_WhenCalledRequestFailsAndCanNotSerializeError_ItShouldReturnUnknownError()
|
public async Task CountMessageTokensAsync_WhenCalledRequestFailsAndCanNotDeserializeError_ItShouldReturnUnknownError()
|
||||||
{
|
{
|
||||||
_mockHttpMessageHandler
|
_mockHttpMessageHandler
|
||||||
.WhenCountMessageTokensRequest()
|
.WhenCountMessageTokensRequest()
|
||||||
@@ -647,7 +647,7 @@ public class AnthropicApiClientTests : IntegrationTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ListModelsAsync_WhenCalledRequestFailsAndCanNotSerializeError_ItShouldReturnUnknownError()
|
public async Task ListModelsAsync_WhenCalledRequestFailsAndCanNotDeserializeError_ItShouldReturnUnknownError()
|
||||||
{
|
{
|
||||||
_mockHttpMessageHandler
|
_mockHttpMessageHandler
|
||||||
.WhenListModelsRequest()
|
.WhenListModelsRequest()
|
||||||
@@ -794,7 +794,7 @@ public class AnthropicApiClientTests : IntegrationTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ListAllModelsAsync_WhenCalledRequestFailsAndCanNotSerializeError_ItShouldReturnUnknownError()
|
public async Task ListAllModelsAsync_WhenCalledRequestFailsAndCanNotDeserializeError_ItShouldReturnUnknownError()
|
||||||
{
|
{
|
||||||
_mockHttpMessageHandler
|
_mockHttpMessageHandler
|
||||||
.WhenListModelsRequest()
|
.WhenListModelsRequest()
|
||||||
@@ -886,4 +886,97 @@ public class AnthropicApiClientTests : IntegrationTest
|
|||||||
|
|
||||||
count.Should().Be(2);
|
count.Should().Be(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetModelAsync_WhenCalled_ItShouldReturnModel()
|
||||||
|
{
|
||||||
|
var modelId = "claude-3-5-sonnet-20241022";
|
||||||
|
|
||||||
|
_mockHttpMessageHandler
|
||||||
|
.WhenGetModelRequest(modelId)
|
||||||
|
.Respond(
|
||||||
|
HttpStatusCode.OK,
|
||||||
|
"application/json",
|
||||||
|
@"{
|
||||||
|
""type"": ""model"",
|
||||||
|
""id"": ""claude-3-5-sonnet-20241022"",
|
||||||
|
""display_name"": ""Claude 3.5 Sonnet (New)"",
|
||||||
|
""created_at"": ""2024-10-22T00:00:00Z""
|
||||||
|
}"
|
||||||
|
);
|
||||||
|
|
||||||
|
var result = await Client.GetModelAsync(modelId);
|
||||||
|
|
||||||
|
result.IsSuccess.Should().BeTrue();
|
||||||
|
result.Value.Should().BeOfType<AnthropicModel>();
|
||||||
|
result.Value.Type.Should().Be("model");
|
||||||
|
result.Value.Id.Should().Be("claude-3-5-sonnet-20241022");
|
||||||
|
result.Value.DisplayName.Should().Be("Claude 3.5 Sonnet (New)");
|
||||||
|
result.Value.CreatedAt.Should().Be(DateTimeOffset.Parse("2024-10-22T00:00:00Z"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetModelAsync_WhenCalledAndErrorReturned_ItShouldHandleError()
|
||||||
|
{
|
||||||
|
var modelId = "claude-3-5-sonnet-20241022";
|
||||||
|
|
||||||
|
_mockHttpMessageHandler
|
||||||
|
.WhenGetModelRequest(modelId)
|
||||||
|
.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 result = await Client.GetModelAsync(modelId);
|
||||||
|
|
||||||
|
result.IsSuccess.Should().BeFalse();
|
||||||
|
result.Error.Should().BeOfType<AnthropicError>();
|
||||||
|
result.Error.Error.Should().BeOfType<InvalidRequestError>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetModelAsync_WhenCalledRequestFailsAndCanNotDeserializeError_ItShouldReturnUnknownError()
|
||||||
|
{
|
||||||
|
var modelId = "claude-3-5-sonnet-20241022";
|
||||||
|
|
||||||
|
_mockHttpMessageHandler
|
||||||
|
.WhenGetModelRequest(modelId)
|
||||||
|
.Respond(
|
||||||
|
HttpStatusCode.BadRequest,
|
||||||
|
"application/json",
|
||||||
|
@"{}"
|
||||||
|
);
|
||||||
|
|
||||||
|
var result = await Client.GetModelAsync(modelId);
|
||||||
|
|
||||||
|
result.IsSuccess.Should().BeFalse();
|
||||||
|
result.Error.Should().BeOfType<AnthropicError>();
|
||||||
|
result.Error.Error.Should().BeOfType<ApiError>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetModelAsync_WhenCalledAndCanNotDeserializeModel_ItShouldReturnEmptyModel()
|
||||||
|
{
|
||||||
|
var modelId = "claude-3-5-sonnet-20241022";
|
||||||
|
|
||||||
|
_mockHttpMessageHandler
|
||||||
|
.WhenGetModelRequest(modelId)
|
||||||
|
.Respond(
|
||||||
|
HttpStatusCode.OK,
|
||||||
|
"application/json",
|
||||||
|
@"{}"
|
||||||
|
);
|
||||||
|
|
||||||
|
var result = await Client.GetModelAsync(modelId);
|
||||||
|
|
||||||
|
result.IsSuccess.Should().BeFalse();
|
||||||
|
result.Error.Should().BeOfType<AnthropicModel>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -58,4 +58,10 @@ public static class MockHttpMessageHandlerExtensions
|
|||||||
return mockHttpMessageHandler
|
return mockHttpMessageHandler
|
||||||
.SetupBaseRequest(HttpMethod.Get, ModelsEndpoint);
|
.SetupBaseRequest(HttpMethod.Get, ModelsEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MockedRequest WhenGetModelRequest(this MockHttpMessageHandler mockHttpMessageHandler, string modelId)
|
||||||
|
{
|
||||||
|
return mockHttpMessageHandler
|
||||||
|
.SetupBaseRequest(HttpMethod.Get, $"{ModelsEndpoint}/{modelId}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user