Merge PR #8795: fix(tests): stop ANTHROPIC_BASE_URL from failing the Anthropic suites (@Huang-404-Q)

This commit is contained in:
can1357
2026-08-19 01:36:58 +02:00
8 changed files with 72 additions and 2 deletions
+3 -1
View File
@@ -32,7 +32,7 @@ import type {
} from "@oh-my-pi/pi-ai/types";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import { removeSyncWithRetries } from "@oh-my-pi/pi-utils";
import { withEnv } from "./helpers";
import { withEnv, withOfficialAnthropicEndpoint } from "./helpers";
const ANTHROPIC_MODEL_SPEC: ModelSpec<"anthropic-messages"> = {
id: "claude-sonnet-4-5",
@@ -152,6 +152,8 @@ function expectClaudeMetadataUserId(userId: string | undefined, expectedSessionI
}
}
withOfficialAnthropicEndpoint();
describe("Anthropic request fingerprint alignment", () => {
it("maps Stainless arch values from explicit inputs", () => {
expect(mapStainlessArch("x64")).toBe("x64");
@@ -3,6 +3,7 @@ import { streamSimple } from "@oh-my-pi/pi-ai";
import type { CacheControlEphemeral, MessageCreateParams } from "@oh-my-pi/pi-ai/providers/anthropic-wire";
import type { CacheRetention, Context, FetchImpl, Model, ProviderSessionState } from "@oh-my-pi/pi-ai/types";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import { withOfficialAnthropicEndpoint } from "./helpers";
const CACHE_REFRESH_DELAY_MS = 5 * 60_000 - 15_000;
const CACHE_TOKENS = 1_200;
@@ -211,6 +212,8 @@ afterEach(() => {
vi.restoreAllMocks();
});
withOfficialAnthropicEndpoint();
describe("Anthropic prompt-cache refresh", () => {
it("replays max_tokens=0 once per interval and stops after three refreshes", async () => {
vi.useFakeTimers();
@@ -7,6 +7,7 @@ import {
} from "@oh-my-pi/pi-ai/providers/anthropic";
import type { Context, Model, ProviderSessionState, ServiceTier } from "@oh-my-pi/pi-ai/types";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import { withOfficialAnthropicEndpoint } from "./helpers";
function makeAnthropicModel(id: string): Model<"anthropic-messages"> {
return buildModel({
@@ -52,6 +53,8 @@ function capturePayload(model: Model<"anthropic-messages">, opts: CaptureOptions
return promise;
}
withOfficialAnthropicEndpoint();
describe("Anthropic priority service tier → speed='fast'", () => {
it("sets speed='fast' for Claude Opus 4.7 when serviceTier='priority'", async () => {
const payload = (await capturePayload(makeAnthropicModel("claude-opus-4-7"), {
@@ -13,7 +13,7 @@ import type {
import type { AssistantMessageEvent, Context, Model, ModelSpec, ProviderSessionState } from "@oh-my-pi/pi-ai/types";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import { structuredCloneJSON } from "@oh-my-pi/pi-utils";
import { withEnv } from "./helpers";
import { withEnv, withOfficialAnthropicEndpoint } from "./helpers";
const model: Model<"anthropic-messages"> = buildModel({
id: "claude-sonnet-4-5",
@@ -351,6 +351,8 @@ afterEach(() => {
vi.restoreAllMocks();
});
withOfficialAnthropicEndpoint();
describe("anthropic stream envelope handling", () => {
it("ignores duplicate message_start envelopes without resetting streamed text", async () => {
vi.spyOn(AnthropicMessages.prototype, "create").mockImplementation(
+27
View File
@@ -1,3 +1,4 @@
import { afterEach, beforeEach } from "bun:test";
import * as os from "node:os";
import * as path from "node:path";
import type { Model } from "@oh-my-pi/pi-ai/types";
@@ -114,3 +115,29 @@ async function readAuthGatewayE2EStatus(): Promise<AuthGatewayE2EStatus> {
}
return { ok: true, token };
}
/**
* Neutralize `ANTHROPIC_BASE_URL` for the calling test file.
*
* The variable reroutes the effective Anthropic endpoint, and every
* "official endpoint" behavior — eager tool-input streaming, long cache
* retention, the Cowork TLS profile, the Claude Code session header — switches
* off once it points elsewhere. A contributor running a gateway, or running the
* suite from inside another agent, otherwise sees these tests fail on a clean
* checkout. Tests that exercise gateway routing set the variable explicitly
* with `withEnv` inside the test body, which still wins over this reset.
*/
export function withOfficialAnthropicEndpoint(): void {
let previous: string | undefined;
beforeEach(() => {
previous = Bun.env.ANTHROPIC_BASE_URL;
delete Bun.env.ANTHROPIC_BASE_URL;
});
afterEach(() => {
if (previous === undefined) {
delete Bun.env.ANTHROPIC_BASE_URL;
} else {
Bun.env.ANTHROPIC_BASE_URL = previous;
}
});
}
@@ -15,6 +15,7 @@ import { getStreamingPartialJson, setStreamingPartialJson } from "@oh-my-pi/pi-a
import { AssistantMessageEventStream } from "@oh-my-pi/pi-ai/utils/event-stream";
import { wrapLeakedThinkingStream } from "@oh-my-pi/pi-ai/utils/leaked-thinking-stream";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import { withOfficialAnthropicEndpoint } from "./helpers";
/** Minimal assistant message; `content`/`stopReason` overridden per event. */
function msg(overrides: Partial<AssistantMessage> = {}): AssistantMessage {
@@ -92,6 +93,8 @@ async function nextToolSnapshot(iterator: AsyncIterator<AssistantMessageEvent>):
}
}
withOfficialAnthropicEndpoint();
describe("wrapLeakedThinkingStream", () => {
async function runLeakedText(chunks: readonly string[]): Promise<{
events: AssistantMessageEvent[];
@@ -10,6 +10,9 @@ import { AgentSession } from "@oh-my-pi/pi-coding-agent/session/agent-session";
import { AuthStorage } from "@oh-my-pi/pi-coding-agent/session/auth-storage";
import { SessionManager } from "@oh-my-pi/pi-coding-agent/session/session-manager";
import { TempDir } from "@oh-my-pi/pi-utils";
import { withOfficialAnthropicEndpoint } from "./helpers/anthropic-endpoint";
withOfficialAnthropicEndpoint();
describe("/fast targets the current model's service-tier family", () => {
let tempDir: TempDir;
@@ -0,0 +1,27 @@
import { afterEach, beforeEach } from "bun:test";
/**
* Neutralize `ANTHROPIC_BASE_URL` for the calling test file.
*
* The variable reroutes the effective Anthropic endpoint, and every
* "official endpoint" behavior — eager tool-input streaming, long cache
* retention, the Cowork TLS profile, the Claude Code session header — switches
* off once it points elsewhere. A contributor running a gateway, or running the
* suite from inside another agent, otherwise sees these tests fail on a clean
* checkout. Tests that exercise gateway routing set the variable explicitly
* with `withEnv` inside the test body, which still wins over this reset.
*/
export function withOfficialAnthropicEndpoint(): void {
let previous: string | undefined;
beforeEach(() => {
previous = Bun.env.ANTHROPIC_BASE_URL;
delete Bun.env.ANTHROPIC_BASE_URL;
});
afterEach(() => {
if (previous === undefined) {
delete Bun.env.ANTHROPIC_BASE_URL;
} else {
Bun.env.ANTHROPIC_BASE_URL = previous;
}
});
}