


























@@ -13,9 +13,14 @@ import {
1313completeSimpleWithLiveTimeout,
1414computeCacheHitRate,
1515extractAssistantText,
16+type LiveResolvedModel,
1617logLiveCache,
1718resolveLiveDirectModel,
1819} from "./live-cache-test-support.js";
20+import {
21+isAuthErrorMessage,
22+isBillingErrorMessage,
23+} from "./pi-embedded-helpers/failover-matches.js";
19242025const OPENAI_TIMEOUT_MS = 120_000;
2126const ANTHROPIC_TIMEOUT_MS = 120_000;
@@ -31,7 +36,6 @@ const LIVE_TEST_PNG_URL = new URL(
3136import.meta.url,
3237);
333834-type LiveResolvedModel = Awaited<ReturnType<typeof resolveLiveDirectModel>>;
3539type ProviderKey = keyof typeof LIVE_CACHE_REGRESSION_BASELINE;
3640type CacheLane = "image" | "mcp" | "stable" | "tool";
3741type CacheUsage = {
@@ -595,9 +599,88 @@ function appendBaselineFindings(target: BaselineFindings, source: BaselineFindin
595599target.warnings.push(...source.warnings);
596600}
597601602+function isAnthropicAccountDrift(error: unknown): boolean {
603+const message = error instanceof Error ? error.message : String(error);
604+return isBillingErrorMessage(message) || isAuthErrorMessage(message);
605+}
606+607+function isAnthropicEmptyCacheProbe(error: unknown): boolean {
608+return error instanceof CacheProbeTextMismatchError && error.text.trim().length === 0;
609+}
610+611+function cloneFixtureWithKey(fixture: LiveResolvedModel, apiKey: string): LiveResolvedModel {
612+return { ...fixture, apiKey };
613+}
614+615+async function runAnthropicCacheLane(params: {
616+fixture: LiveResolvedModel;
617+lane: CacheLane;
618+pngBase64: string;
619+runToken: string;
620+warnings: string[];
621+}): Promise<{ attempt?: Awaited<ReturnType<typeof runRepeatedLaneWithBaselineRetry>> }> {
622+const keys =
623+params.fixture.apiKeys && params.fixture.apiKeys.length > 0
624+ ? params.fixture.apiKeys
625+ : [params.fixture.apiKey];
626+let lastError: unknown;
627+for (const [index, apiKey] of keys.entries()) {
628+try {
629+return {
630+attempt: await runRepeatedLaneWithBaselineRetry({
631+lane: params.lane,
632+providerTag: "anthropic",
633+fixture: cloneFixtureWithKey(params.fixture, apiKey),
634+runToken: params.runToken,
635+pngBase64: params.pngBase64,
636+}),
637+};
638+} catch (error) {
639+lastError = error;
640+if (isAnthropicAccountDrift(error) && index + 1 < keys.length) {
641+logLiveCache(`anthropic ${params.lane} account drift; retrying with next key`);
642+continue;
643+}
644+break;
645+}
646+}
647+648+if (isAnthropicAccountDrift(lastError) || isAnthropicEmptyCacheProbe(lastError)) {
649+const reason = isAnthropicEmptyCacheProbe(lastError) ? "empty response" : "account drift";
650+const warning = `anthropic ${params.lane} skipped: ${reason}`;
651+params.warnings.push(warning);
652+logLiveCache(warning);
653+return {};
654+}
655+throw lastError;
656+}
657+658+async function runAnthropicDisabledCacheLane(params: {
659+fixture: LiveResolvedModel;
660+runToken: string;
661+warnings: string[];
662+}): Promise<LaneResult | undefined> {
663+try {
664+return await runAnthropicDisabledLane({
665+fixture: params.fixture,
666+runToken: params.runToken,
667+sessionId: `live-cache-regression-${params.runToken}-anthropic-disabled`,
668+});
669+} catch (error) {
670+if (isAnthropicAccountDrift(error) || isAnthropicEmptyCacheProbe(error)) {
671+const warning = "anthropic disabled skipped: account drift";
672+params.warnings.push(warning);
673+logLiveCache(warning);
674+return undefined;
675+}
676+throw error;
677+}
678+}
679+598680export const __testing = {
599681 assertAgainstBaseline,
600682 evaluateAgainstBaseline,
683+ isAnthropicAccountDrift,
601684 resolveCacheProbeMaxTokens,
602685 shouldAcceptEmptyOpenAICacheProbe,
603686 shouldRetryCacheProbeText,
@@ -650,13 +733,17 @@ export async function runLiveCacheRegression(): Promise<LiveCacheRegressionResul
650733};
651734appendBaselineFindings({ regressions, warnings }, openaiAttempt.findings);
652735653-const anthropicAttempt = await runRepeatedLaneWithBaselineRetry({
736+const { attempt: anthropicAttempt } = await runAnthropicCacheLane({
654737 lane,
655-providerTag: "anthropic",
656738fixture: anthropic,
657739 runToken,
658740 pngBase64,
741+ warnings,
659742});
743+if (!anthropicAttempt) {
744+summary.anthropic[lane] = { skipped: true };
745+continue;
746+}
660747const anthropicResult = anthropicAttempt.result;
661748logLiveCache(
662749`anthropic ${lane} warmup ${formatUsage(anthropicResult.warmup?.usage ?? {})} rate=${anthropicResult.warmup?.hitRate.toFixed(3) ?? "0.000"}`,
@@ -673,22 +760,26 @@ export async function runLiveCacheRegression(): Promise<LiveCacheRegressionResul
673760appendBaselineFindings({ regressions, warnings }, anthropicAttempt.findings);
674761}
675762676-const disabled = await runAnthropicDisabledLane({
763+const disabled = await runAnthropicDisabledCacheLane({
677764fixture: anthropic,
678765 runToken,
679-sessionId: `live-cache-regression-${runToken}-anthropic-disabled`,
680-});
681-logLiveCache(`anthropic disabled ${formatUsage(disabled.disabled?.usage ?? {})}`);
682-summary.anthropic.disabled = {
683-disabled: disabled.disabled?.usage,
684-};
685-assertAgainstBaseline({
686-lane: "disabled",
687-provider: "anthropic",
688-result: disabled,
689- regressions,
690766 warnings,
691767});
768+if (disabled) {
769+logLiveCache(`anthropic disabled ${formatUsage(disabled.disabled?.usage ?? {})}`);
770+summary.anthropic.disabled = {
771+disabled: disabled.disabled?.usage,
772+};
773+assertAgainstBaseline({
774+lane: "disabled",
775+provider: "anthropic",
776+result: disabled,
777+ regressions,
778+ warnings,
779+});
780+} else {
781+summary.anthropic.disabled = { skipped: true };
782+}
692783693784logLiveCache(`cache regression summary ${JSON.stringify(summary)}`);
694785if (warnings.length > 0) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。