fix(ai): excluded copilot urls from interleaved http beta
- Excluded effective github-copilot URLs from the interleaved beta path so custom-provider and rerouted Copilot hosts don't send the rejected header. - Covered a custom provider on a Copilot host omitting the beta. Fixes #6717
This commit is contained in:
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
|
||||
import { scheduler } from "node:timers/promises";
|
||||
import * as tls from "node:tls";
|
||||
import { isAnthropicSigningProxyUrl, isOfficialAnthropicApiUrl } from "@oh-my-pi/pi-catalog/compat/anthropic";
|
||||
import { isVertexRawPredictUrl } from "@oh-my-pi/pi-catalog/hosts";
|
||||
import { hostMatchesUrl, isVertexRawPredictUrl } from "@oh-my-pi/pi-catalog/hosts";
|
||||
import { mapEffortToAnthropicAdaptiveEffort } from "@oh-my-pi/pi-catalog/model-thinking";
|
||||
import { calculateCost, getBundledModel } from "@oh-my-pi/pi-catalog/models";
|
||||
import { isAnthropicOAuthToken } from "@oh-my-pi/pi-catalog/utils";
|
||||
@@ -2856,15 +2856,20 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
|
||||
// official API, so only known non-official signing routes need the beta
|
||||
// (#6717). Classify the effective URL: Foundry and provider overrides can
|
||||
// reroute a model without rebuilding its materialized compat.
|
||||
// Vertex rawPredict is excluded like every other HTTP-beta path here: it can
|
||||
// only accept betas in the JSON body (`anthropic_beta`), never as this
|
||||
// `anthropic-beta` HTTP header, so advertising it there earns a 400 (#5614).
|
||||
// Two signing routes still can't take the beta as this `anthropic-beta` HTTP
|
||||
// header, so they're excluded: Vertex rawPredict accepts betas only in the
|
||||
// JSON body (`anthropic_beta`) and 400s on the header (#5614), and GitHub
|
||||
// Copilot rejects Anthropic betas outright — the `github-copilot` provider
|
||||
// branch below strips them, but a custom provider id or a canonical model
|
||||
// rerouted to `api.githubcopilot.com` / `copilot-api.*` reaches the generic
|
||||
// header builder instead, so exclude those effective URLs here too.
|
||||
const needsInterleavedBeta =
|
||||
interleavedThinking &&
|
||||
(!model.thinking?.supportsDisplay ||
|
||||
(!isOfficialAnthropicApiUrl(baseUrl) &&
|
||||
isAnthropicSigningProxyUrl(baseUrl) &&
|
||||
!isVertexRawPredictUrl(baseUrl ?? "")));
|
||||
!isVertexRawPredictUrl(baseUrl ?? "") &&
|
||||
!hostMatchesUrl(baseUrl, "githubCopilot")));
|
||||
const oauthToken = isOAuth ?? isAnthropicOAuthToken(apiKey);
|
||||
const supportsEagerToolInputStreaming = resolveEagerToolInputStreamingSupport(model, baseUrl);
|
||||
const needsFineGrainedToolStreamingBeta =
|
||||
|
||||
@@ -1852,11 +1852,23 @@ describe("Anthropic request fingerprint alignment", () => {
|
||||
apiKey: "vertex-adc",
|
||||
interleavedThinking: true,
|
||||
});
|
||||
// A custom provider on a Copilot host is signing, but the proxy rejects
|
||||
// Anthropic betas outright and this path bypasses the provider branch.
|
||||
const copilotUrlProxy = buildAnthropicClientOptions({
|
||||
model: buildModel({
|
||||
...adaptiveProxySpec,
|
||||
provider: "custom-copilot",
|
||||
baseUrl: "https://api.githubcopilot.com",
|
||||
}),
|
||||
apiKey: "ghu_test",
|
||||
interleavedThinking: true,
|
||||
});
|
||||
|
||||
expect(signingProxy.defaultHeaders["anthropic-beta"]).toContain("interleaved-thinking-2025-05-14");
|
||||
expect(reroutedSigningProxy.defaultHeaders["anthropic-beta"]).toContain("interleaved-thinking-2025-05-14");
|
||||
expect(nonSigningProxy.defaultHeaders["anthropic-beta"] ?? "").not.toContain("interleaved-thinking-2025-05-14");
|
||||
expect(vertexRawPredict.defaultHeaders["anthropic-beta"] ?? "").not.toContain("interleaved-thinking-2025-05-14");
|
||||
expect(copilotUrlProxy.defaultHeaders["anthropic-beta"] ?? "").not.toContain("interleaved-thinking-2025-05-14");
|
||||
});
|
||||
|
||||
it("adds legacy fine-grained tool-streaming beta only for tool requests on incompatible models", () => {
|
||||
|
||||
Reference in New Issue
Block a user