Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Anthropic.SDK/Anthropic.SDK.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
<PackageTags>Claude, AI, ML, API, Anthropic</PackageTags>
<Title>Claude API</Title>
<PackageReleaseNotes>
Update to latest version of Microsoft.Extensions.AI.Abstractions
Fixes a critical bug that causes the library to make double requests, increasing latency and cost.
</PackageReleaseNotes>
<PackageId>Anthropic.SDK</PackageId>
<Version>5.2.1</Version>
<AssemblyVersion>5.2.1.0</AssemblyVersion>
<FileVersion>5.2.1.0</FileVersion>
<Version>5.2.2</Version>
<AssemblyVersion>5.2.2.0</AssemblyVersion>
<FileVersion>5.2.2.0</FileVersion>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>icon.png</PackageIcon>
Expand Down
30 changes: 29 additions & 1 deletion Anthropic.SDK/BaseEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Threading;
using System.Threading.Tasks;
using Anthropic.SDK.Messaging;
using System.Linq;

namespace Anthropic.SDK
{
Expand Down Expand Up @@ -57,10 +58,37 @@ protected async Task<TResponse> HttpRequestMessages<TResponse>(string url = null

using var ms = new MemoryStream(Encoding.UTF8.GetBytes(resultAsString));
var res = await JsonSerializer.DeserializeAsync<TResponse>(ms, options, cancellationToken: ctx).ConfigureAwait(false);

if (res is MessageResponse messageResponse)
{
messageResponse.RateLimits = GetRateLimits(response);
}
return res;
}

protected RateLimits GetRateLimits(HttpResponseMessage message)
{
var rateLimits = new RateLimits();

TryParseHeaderValue(message, "anthropic-ratelimit-requests-limit", long.Parse, value => rateLimits.RequestsLimit = value);
TryParseHeaderValue(message, "anthropic-ratelimit-requests-remaining", long.Parse, value => rateLimits.RequestsRemaining = value);
TryParseHeaderValue(message, "anthropic-ratelimit-requests-reset", DateTime.Parse, value => rateLimits.RequestsReset = value);
TryParseHeaderValue(message, "anthropic-ratelimit-tokens-limit", long.Parse, value => rateLimits.TokensLimit = value);
TryParseHeaderValue(message, "anthropic-ratelimit-tokens-remaining", long.Parse, value => rateLimits.TokensRemaining = value);
TryParseHeaderValue(message, "anthropic-ratelimit-tokens-reset", DateTime.Parse, value => rateLimits.TokensReset = value);

return rateLimits;
}

private static void TryParseHeaderValue<T>(HttpResponseMessage message, string headerName, Func<string, T> parser, Action<T> setter)
{
if (message.Headers.TryGetValues(headerName, out var values) &&
values.FirstOrDefault() is string value &&
parser(value) is T parsedValue)
{
setter(parsedValue);
}
}

/// <summary>
/// Makes an HTTP request and deserializes the response to the specified type without custom converters.
/// </summary>
Expand Down
41 changes: 2 additions & 39 deletions Anthropic.SDK/EndpointBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,22 +102,7 @@
return $"{resultAsString ?? "<no content>"}";
}

/// <summary>
/// Override the base HttpRequestMessages to add rate limits
/// </summary>
protected new async Task<TResponse> HttpRequestMessages<TResponse>(string url = null, HttpMethod verb = null,
object postData = null, CancellationToken ctx = default)
{
var response = await base.HttpRequestMessages<TResponse>(url, verb, postData, ctx).ConfigureAwait(false);

if (response is MessageResponse messageResponse)
{
messageResponse.RateLimits = GetRateLimits(await HttpRequestRaw(url, verb, postData, false, ctx));
}

return response;
}


protected async IAsyncEnumerable<BatchLine> HttpStreamingRequestBatches(string url = null,
HttpMethod verb = null,
object postData = null, [EnumeratorCancellation] CancellationToken ctx = default)
Expand Down Expand Up @@ -168,34 +153,12 @@
}
}

private static RateLimits GetRateLimits(HttpResponseMessage message)
{
var rateLimits = new RateLimits();

TryParseHeaderValue(message, "anthropic-ratelimit-requests-limit", long.Parse, value => rateLimits.RequestsLimit = value);
TryParseHeaderValue(message, "anthropic-ratelimit-requests-remaining", long.Parse, value => rateLimits.RequestsRemaining = value);
TryParseHeaderValue(message, "anthropic-ratelimit-requests-reset", DateTime.Parse, value => rateLimits.RequestsReset = value);
TryParseHeaderValue(message, "anthropic-ratelimit-tokens-limit", long.Parse, value => rateLimits.TokensLimit = value);
TryParseHeaderValue(message, "anthropic-ratelimit-tokens-remaining", long.Parse, value => rateLimits.TokensRemaining = value);
TryParseHeaderValue(message, "anthropic-ratelimit-tokens-reset", DateTime.Parse, value => rateLimits.TokensReset = value);

return rateLimits;
}

private static void TryParseHeaderValue<T>(HttpResponseMessage message, string headerName, Func<string, T> parser, Action<T> setter)
{
if (message.Headers.TryGetValues(headerName, out var values) &&
values.FirstOrDefault() is string value &&
parser(value) is T parsedValue)
{
setter(parsedValue);
}
}


/// <summary>
/// Handle error responses from the API
/// </summary>
protected override async Task<Exception> HandleErrorResponseAsync(HttpResponseMessage response, string resultAsString, string url)

Check warning on line 161 in Anthropic.SDK/EndpointBase.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
#if NET6_0_OR_GREATER
if (response.StatusCode == HttpStatusCode.TooManyRequests)
Expand Down
Loading