Skip to content

Commit 49f43fb

Browse files
Add diagnostic logging to proxy snapshot mismatch errors
When the replaying proxy can't find a matching conversation on CI, log the request message count, each stored conversation's message count, and the exact mismatch point (message index + content diff). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e98a2c7 commit 49f43fb

File tree

1 file changed

+34
-9
lines changed

1 file changed

+34
-9
lines changed

test/harness/replayingCapiProxy.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ export class ReplayingCapiProxy extends CapturingHttpProxy {
341341
state.testInfo,
342342
state.workDir,
343343
state.toolResultNormalizers,
344+
state.storedData,
344345
);
345346
return;
346347
}
@@ -380,30 +381,54 @@ async function exitWithNoMatchingRequestError(
380381
testInfo: { file: string; line?: number } | undefined,
381382
workDir: string,
382383
toolResultNormalizers: ToolResultNormalizer[],
384+
storedData?: NormalizedData,
383385
) {
384386
const parts: string[] = [];
385387
if (testInfo?.file) parts.push(`file=${testInfo.file}`);
386388
if (typeof testInfo?.line === "number") parts.push(`line=${testInfo.line}`);
387389
const header = parts.length ? ` ${parts.join(",")}` : "";
388390

389-
let finalMessageInfo: string;
391+
let diagnostics = "";
390392
try {
391393
const normalized = await parseAndNormalizeRequest(
392394
options.body,
393395
workDir,
394396
toolResultNormalizers,
395397
);
396-
const normalizedMessages = normalized.conversations[0]?.messages ?? [];
397-
finalMessageInfo = JSON.stringify(
398-
normalizedMessages[normalizedMessages.length - 1],
399-
);
400-
} catch {
401-
finalMessageInfo = `(unable to parse request body: ${options.body?.slice(0, 200) ?? "empty"})`;
398+
const requestMessages = normalized.conversations[0]?.messages ?? [];
399+
400+
diagnostics += `Request has ${requestMessages.length} messages.\n`;
401+
402+
if (storedData) {
403+
for (let c = 0; c < storedData.conversations.length; c++) {
404+
const saved = storedData.conversations[c].messages;
405+
diagnostics += `Conversation ${c} has ${saved.length} messages. `;
406+
if (requestMessages.length >= saved.length) {
407+
diagnostics += `Skipped: request (${requestMessages.length}) >= saved (${saved.length}).\n`;
408+
continue;
409+
}
410+
let mismatchAt = -1;
411+
for (let i = 0; i < requestMessages.length; i++) {
412+
const reqMsg = JSON.stringify(requestMessages[i]);
413+
const savedMsg = JSON.stringify(saved[i]);
414+
if (reqMsg !== savedMsg) {
415+
mismatchAt = i;
416+
diagnostics += `Mismatch at message ${i}:\n request: ${reqMsg.slice(0, 200)}\n saved: ${savedMsg.slice(0, 200)}\n`;
417+
break;
418+
}
419+
}
420+
if (mismatchAt === -1) {
421+
const nextRole = saved[requestMessages.length]?.role;
422+
diagnostics += `Prefix matched but next message role is "${nextRole}" (need "assistant").\n`;
423+
}
424+
}
425+
}
426+
} catch (e) {
427+
diagnostics = `(unable to parse request: ${e})`;
402428
}
403429

404430
const errorMessage =
405-
`No cached response found for ${options.requestOptions.method} ${options.requestOptions.path}. ` +
406-
`Final message: ${finalMessageInfo}`;
431+
`No cached response found for ${options.requestOptions.method} ${options.requestOptions.path}.\n${diagnostics}`;
407432
process.stderr.write(`::error${header}::${errorMessage}\n`);
408433
options.onError(new Error(errorMessage));
409434
}

0 commit comments

Comments
 (0)