




















@@ -20,6 +20,7 @@ import {
2020const OPENAI_TIMEOUT_MS = 120_000;
2121const ANTHROPIC_TIMEOUT_MS = 120_000;
2222const LIVE_CACHE_LANE_RETRIES = 1;
23+const LIVE_CACHE_RESPONSE_RETRIES = 1;
2324const OPENAI_PREFIX = buildStableCachePrefix("openai");
2425const OPENAI_MCP_PREFIX = buildStableCachePrefix("openai-mcp-style");
2526const ANTHROPIC_PREFIX = buildStableCachePrefix("anthropic");
@@ -128,6 +129,16 @@ function assert(condition: unknown, message: string): asserts condition {
128129}
129130}
130131132+function shouldRetryCacheProbeText(params: {
133+attempt: number;
134+suffix: string;
135+text: string;
136+}): boolean {
137+const responseTextLower = normalizeLowercaseStringOrEmpty(params.text);
138+const suffixLower = normalizeLowercaseStringOrEmpty(params.suffix);
139+return !responseTextLower.includes(suffixLower) && params.attempt <= LIVE_CACHE_RESPONSE_RETRIES;
140+}
141+131142async function runToolOnlyTurn(params: {
132143apiKey: string;
133144cacheRetention: "none" | "short" | "long";
@@ -205,38 +216,47 @@ async function completeCacheProbe(params: {
205216maxTokens?: number;
206217}): Promise<CacheRun> {
207218const timeoutMs = params.providerTag === "openai" ? OPENAI_TIMEOUT_MS : ANTHROPIC_TIMEOUT_MS;
208-const response = await completeSimpleWithLiveTimeout(
209-params.model,
210-{
211-systemPrompt: params.systemPrompt,
212-messages: params.messages,
213- ...(params.tools ? { tools: params.tools } : {}),
214-},
215-{
216-apiKey: params.apiKey,
217-cacheRetention: params.cacheRetention,
218-sessionId: params.sessionId,
219-maxTokens: params.maxTokens ?? 64,
220-temperature: 0,
221- ...(params.providerTag === "openai" ? { reasoning: "none" as unknown as never } : {}),
222-},
223-`${params.providerTag} cache lane ${params.suffix}`,
224-timeoutMs,
225-);
226-const text = extractAssistantText(response);
227-const responseTextLower = normalizeLowercaseStringOrEmpty(text);
228-const suffixLower = normalizeLowercaseStringOrEmpty(params.suffix);
229-assert(
230-responseTextLower.includes(suffixLower),
231-`expected response to contain ${params.suffix}, got ${JSON.stringify(text)}`,
232-);
233-const usage = normalizeCacheUsage(response.usage);
234-return {
235-suffix: params.suffix,
236- text,
237- usage,
238-hitRate: computeCacheHitRate(usage),
239-};
219+for (let attempt = 1; attempt <= 1 + LIVE_CACHE_RESPONSE_RETRIES; attempt += 1) {
220+const response = await completeSimpleWithLiveTimeout(
221+params.model,
222+{
223+systemPrompt: params.systemPrompt,
224+messages: params.messages,
225+ ...(params.tools ? { tools: params.tools } : {}),
226+},
227+{
228+apiKey: params.apiKey,
229+cacheRetention: params.cacheRetention,
230+sessionId: params.sessionId,
231+maxTokens: params.maxTokens ?? 64,
232+temperature: 0,
233+ ...(params.providerTag === "openai" ? { reasoning: "none" as unknown as never } : {}),
234+},
235+`${params.providerTag} cache lane ${params.suffix}`,
236+timeoutMs,
237+);
238+const text = extractAssistantText(response);
239+if (shouldRetryCacheProbeText({ attempt, suffix: params.suffix, text })) {
240+logLiveCache(
241+`${params.providerTag} cache lane ${params.suffix} response mismatch; retrying once: ${JSON.stringify(text)}`,
242+);
243+continue;
244+}
245+const responseTextLower = normalizeLowercaseStringOrEmpty(text);
246+const suffixLower = normalizeLowercaseStringOrEmpty(params.suffix);
247+assert(
248+responseTextLower.includes(suffixLower),
249+`expected response to contain ${params.suffix}, got ${JSON.stringify(text)}`,
250+);
251+const usage = normalizeCacheUsage(response.usage);
252+return {
253+suffix: params.suffix,
254+ text,
255+ usage,
256+hitRate: computeCacheHitRate(usage),
257+};
258+}
259+throw new Error(`expected response to contain ${params.suffix}`);
240260}
241261242262async function runRepeatedLane(params: {
@@ -507,6 +527,7 @@ function appendBaselineFindings(target: BaselineFindings, source: BaselineFindin
507527export const __testing = {
508528 assertAgainstBaseline,
509529 evaluateAgainstBaseline,
530+ shouldRetryCacheProbeText,
510531 shouldRetryBaselineFindings,
511532};
512533此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。