Skip to content

Commit e0df20b

Browse files
xydt-lcyclaudesteipete
authored
fix(media): normalizeMediaSource should handle uppercase FILE:// URI schemes (#103490)
* fix: normalizeMediaSource should handle uppercase FILE:// URI schemes URI schemes are case-insensitive per RFC 3986. normalizeMediaSource only matched lowercase 'file://', so MEDIA:FILE:///tmp/generated.png was left in assistant text instead of being extracted as a local media attachment. Replaced startsWith + replace with a case-insensitive regex to handle FILE://, file://, and any mixed-case variant. Fixes #103473 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * fix(media): handle spaced uppercase file URLs --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]> Co-authored-by: Peter Steinberger <[email protected]>
1 parent 9b4c7c0 commit e0df20b

2 files changed

Lines changed: 8 additions & 2 deletions

File tree

src/media/parse.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ describe("splitMediaFromOutput", () => {
6666
String.raw`MEDIA:/path/to/image.png\"}],\"details\":{\"provider\":\"openai\"}`,
6767
],
6868
["/tmp/render,final.png", "MEDIA:/tmp/render,final.png"],
69+
["/tmp/generated.png", "MEDIA:FILE:///tmp/generated.png"],
70+
["/tmp/generated.png", "MEDIA:file:///tmp/generated.png"],
71+
["/Users/pete/My File.png", "MEDIA:FILE:///Users/pete/My File.png"],
72+
["/Users/pete/My File.png", "MEDIA:file:///Users/pete/My File.png"],
6973
] as const)("accepts supported media path variant: %s", (expectedPath, input) => {
7074
expectAcceptedMediaPathCase(expectedPath, input);
7175
});

src/media/parse.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ export type SplitMediaFromOutputOptions = {
3333
extractMediaDirectives?: boolean;
3434
};
3535

36+
const FILE_URL_PREFIX_RE = /^file:\/\//i;
37+
3638
/** Converts file URLs into plain local paths before downstream media validation. */
3739
export function normalizeMediaSource(src: string): string {
38-
return src.startsWith("file://") ? src.replace("file://", "") : src;
40+
return src.replace(FILE_URL_PREFIX_RE, "");
3941
}
4042

4143
const TRAILING_SERIALIZED_JSON_AFTER_EXT_RE = /^(.*\.\w{1,10})\\?"(?=[\]},:]|$).*/s;
@@ -603,7 +605,7 @@ export function splitMediaFromOutput(
603605

604606
const trimmedPayload = payloadValue.trim();
605607
const looksLikeLocalPath =
606-
looksLikeLocalFilePath(trimmedPayload) || trimmedPayload.startsWith("file://");
608+
looksLikeLocalFilePath(trimmedPayload) || FILE_URL_PREFIX_RE.test(trimmedPayload);
607609
if (
608610
!unwrapped &&
609611
validCount === 1 &&

0 commit comments

Comments
 (0)