fix: stop inferring file extraction from Body/RawBody mismatch (#46454)
This commit is contained in:
parent
e8fd176cf4
commit
1b6c43baa4
@ -292,27 +292,21 @@ export async function applyDeferredMediaUnderstandingToQueuedRun(
|
||||
return;
|
||||
}
|
||||
|
||||
const referenceBody = mediaContext.RawBody ?? mediaContext.Body;
|
||||
// Prefer RawBody-vs-Body comparison when RawBody exists. If RawBody is
|
||||
// missing, any real <file>...</file> block plus file-like attachments means
|
||||
// extraction already ran, even if the stored name came from Content-Disposition
|
||||
// instead of the attachment path/url basename.
|
||||
if (!mediaContext.DeferredFileBlocksExtracted && hasAnyFileAttachments(mediaContext)) {
|
||||
const rawBodyMissing = typeof mediaContext.RawBody !== "string";
|
||||
if (mediaContext.Body !== referenceBody) {
|
||||
mediaContext.DeferredFileBlocksExtracted = true;
|
||||
} else if (
|
||||
rawBodyMissing &&
|
||||
(Boolean(mediaContext.MediaUnderstanding?.length) ||
|
||||
bodyContainsExtractedFileBlock(mediaContext.Body))
|
||||
) {
|
||||
mediaContext.DeferredFileBlocksExtracted = true;
|
||||
}
|
||||
}
|
||||
if (mediaContext.MediaUnderstanding?.length) {
|
||||
mediaContext.DeferredMediaApplied = true;
|
||||
return;
|
||||
}
|
||||
// Treat followup file extraction as already applied only when we have explicit
|
||||
// evidence: the queue snapshot already flagged it or Body already contains a
|
||||
// real extracted <file>...</file> block. Body/RawBody mismatches are not
|
||||
// reliable because some channels wrap Body with envelope metadata.
|
||||
if (
|
||||
!mediaContext.DeferredFileBlocksExtracted &&
|
||||
hasAnyFileAttachments(mediaContext) &&
|
||||
bodyContainsExtractedFileBlock(mediaContext.Body)
|
||||
) {
|
||||
mediaContext.DeferredFileBlocksExtracted = true;
|
||||
}
|
||||
|
||||
if (mediaContext.DeferredFileBlocksExtracted && hasOnlyFileLikeAttachments(mediaContext)) {
|
||||
mediaContext.DeferredMediaApplied = true;
|
||||
|
||||
@ -1231,6 +1231,54 @@ describe("createFollowupRunner media understanding", () => {
|
||||
expect(agentCall?.prompt?.match(/<file\b/g)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("does not infer file extraction from wrapped Body/RawBody mismatches", async () => {
|
||||
const fileBlock = '<file name="report.pdf" mime="application/pdf">\nreport content\n</file>';
|
||||
applyMediaUnderstandingMock.mockImplementationOnce(
|
||||
async (params: { ctx: Record<string, unknown> }) => {
|
||||
params.ctx.Body = `summarize this\n\n${fileBlock}`;
|
||||
return {
|
||||
outputs: [],
|
||||
decisions: [],
|
||||
appliedImage: false,
|
||||
appliedAudio: false,
|
||||
appliedVideo: false,
|
||||
appliedFile: true,
|
||||
};
|
||||
},
|
||||
);
|
||||
runEmbeddedPiAgentMock.mockResolvedValueOnce({
|
||||
payloads: [{ text: "file processed" }],
|
||||
meta: {},
|
||||
});
|
||||
|
||||
const runner = createFollowupRunner({
|
||||
opts: { onBlockReply: vi.fn(async () => {}) },
|
||||
typing: createMockTypingController(),
|
||||
typingMode: "instant",
|
||||
defaultModel: "anthropic/claude-opus-4-5",
|
||||
});
|
||||
|
||||
await runner(
|
||||
createQueuedRun({
|
||||
prompt: "[media attached: /tmp/report.pdf]\nLine: Alice\nsummarize this",
|
||||
mediaContext: {
|
||||
Body: "Line: Alice\nsummarize this",
|
||||
RawBody: "summarize this",
|
||||
MediaPaths: ["/tmp/report.pdf"],
|
||||
MediaTypes: ["application/pdf"],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(applyMediaUnderstandingMock).toHaveBeenCalledTimes(1);
|
||||
const agentCall = runEmbeddedPiAgentMock.mock.calls.at(-1)?.[0] as {
|
||||
prompt?: string;
|
||||
};
|
||||
expect(agentCall?.prompt).toContain("Line: Alice");
|
||||
expect(agentCall?.prompt).toContain(fileBlock);
|
||||
expect(agentCall?.prompt?.match(/<file\s+name="report\.pdf"/g)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("preserves non-audio media lines when only audio is transcribed", async () => {
|
||||
applyMediaUnderstandingMock.mockImplementationOnce(
|
||||
async (params: { ctx: Record<string, unknown> }) => {
|
||||
|
||||
@ -52,9 +52,9 @@ export type FollowupMediaContext = {
|
||||
DeferredMediaApplied?: boolean;
|
||||
/**
|
||||
* Set when file extraction has already been applied to Body (either in the
|
||||
* primary path or by a previous deferred-media run). Checked instead of
|
||||
* scanning body text for `<file` patterns to avoid false-positives on user
|
||||
* messages that contain literal XML-like text.
|
||||
* primary path or by a previous deferred-media run). This avoids re-running
|
||||
* file extraction when Body already contains real extracted `<file>...</file>`
|
||||
* blocks.
|
||||
*/
|
||||
DeferredFileBlocksExtracted?: boolean;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user