mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-28 15:01:41 +03:00
refactor(media): normalize inbound media type defaults (#16228)
This commit is contained in:
committed by
GitHub
parent
e53a221e5c
commit
4b1cadaecb
@@ -116,6 +116,43 @@ describe("finalizeInboundContext", () => {
|
||||
finalizeInboundContext(ctx, { forceBodyForCommands: true });
|
||||
expect(ctx.BodyForCommands).toBe("say hi");
|
||||
});
|
||||
|
||||
it("fills MediaType/MediaTypes defaults only when media exists", () => {
|
||||
const withMedia: MsgContext = {
|
||||
Body: "hi",
|
||||
MediaPath: "/tmp/file.bin",
|
||||
};
|
||||
const outWithMedia = finalizeInboundContext(withMedia);
|
||||
expect(outWithMedia.MediaType).toBe("application/octet-stream");
|
||||
expect(outWithMedia.MediaTypes).toEqual(["application/octet-stream"]);
|
||||
|
||||
const withoutMedia: MsgContext = { Body: "hi" };
|
||||
const outWithoutMedia = finalizeInboundContext(withoutMedia);
|
||||
expect(outWithoutMedia.MediaType).toBeUndefined();
|
||||
expect(outWithoutMedia.MediaTypes).toBeUndefined();
|
||||
});
|
||||
|
||||
it("pads MediaTypes to match MediaPaths/MediaUrls length", () => {
|
||||
const ctx: MsgContext = {
|
||||
Body: "hi",
|
||||
MediaPaths: ["/tmp/a", "/tmp/b"],
|
||||
MediaTypes: ["image/png"],
|
||||
};
|
||||
const out = finalizeInboundContext(ctx);
|
||||
expect(out.MediaType).toBe("image/png");
|
||||
expect(out.MediaTypes).toEqual(["image/png", "application/octet-stream"]);
|
||||
});
|
||||
|
||||
it("derives MediaType from MediaTypes when missing", () => {
|
||||
const ctx: MsgContext = {
|
||||
Body: "hi",
|
||||
MediaPath: "/tmp/a",
|
||||
MediaTypes: ["image/jpeg"],
|
||||
};
|
||||
const out = finalizeInboundContext(ctx);
|
||||
expect(out.MediaType).toBe("image/jpeg");
|
||||
expect(out.MediaTypes).toEqual(["image/jpeg"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("inbound dedupe", () => {
|
||||
|
||||
@@ -10,6 +10,8 @@ export type FinalizeInboundContextOptions = {
|
||||
forceConversationLabel?: boolean;
|
||||
};
|
||||
|
||||
const DEFAULT_MEDIA_TYPE = "application/octet-stream";
|
||||
|
||||
function normalizeTextField(value: unknown): string | undefined {
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
@@ -17,6 +19,21 @@ function normalizeTextField(value: unknown): string | undefined {
|
||||
return normalizeInboundTextNewlines(value);
|
||||
}
|
||||
|
||||
function normalizeMediaType(value: unknown): string | undefined {
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
return trimmed.length > 0 ? trimmed : undefined;
|
||||
}
|
||||
|
||||
function countMediaEntries(ctx: MsgContext): number {
|
||||
const pathCount = Array.isArray(ctx.MediaPaths) ? ctx.MediaPaths.length : 0;
|
||||
const urlCount = Array.isArray(ctx.MediaUrls) ? ctx.MediaUrls.length : 0;
|
||||
const single = ctx.MediaPath || ctx.MediaUrl ? 1 : 0;
|
||||
return Math.max(pathCount, urlCount, single);
|
||||
}
|
||||
|
||||
export function finalizeInboundContext<T extends Record<string, unknown>>(
|
||||
ctx: T,
|
||||
opts: FinalizeInboundContextOptions = {},
|
||||
@@ -73,5 +90,35 @@ export function finalizeInboundContext<T extends Record<string, unknown>>(
|
||||
// Always set. Default-deny when upstream forgets to populate it.
|
||||
normalized.CommandAuthorized = normalized.CommandAuthorized === true;
|
||||
|
||||
// MediaType/MediaTypes alignment:
|
||||
// - No media: do not inject defaults.
|
||||
// - Media present: ensure MediaType is always set, and MediaTypes is padded to match
|
||||
// MediaPaths/MediaUrls length when possible.
|
||||
const mediaCount = countMediaEntries(normalized);
|
||||
if (mediaCount > 0) {
|
||||
const mediaType = normalizeMediaType(normalized.MediaType);
|
||||
const rawMediaTypes = Array.isArray(normalized.MediaTypes) ? normalized.MediaTypes : undefined;
|
||||
const normalizedMediaTypes = rawMediaTypes?.map((entry) => normalizeMediaType(entry));
|
||||
|
||||
let mediaTypesFinal: string[] | undefined;
|
||||
if (normalizedMediaTypes && normalizedMediaTypes.length > 0) {
|
||||
const filled = normalizedMediaTypes.slice();
|
||||
while (filled.length < mediaCount) {
|
||||
filled.push(undefined);
|
||||
}
|
||||
mediaTypesFinal = filled.map((entry) => entry ?? DEFAULT_MEDIA_TYPE);
|
||||
} else if (mediaType) {
|
||||
mediaTypesFinal = [mediaType];
|
||||
while (mediaTypesFinal.length < mediaCount) {
|
||||
mediaTypesFinal.push(DEFAULT_MEDIA_TYPE);
|
||||
}
|
||||
} else {
|
||||
mediaTypesFinal = Array.from({ length: mediaCount }, () => DEFAULT_MEDIA_TYPE);
|
||||
}
|
||||
|
||||
normalized.MediaTypes = mediaTypesFinal;
|
||||
normalized.MediaType = mediaType ?? mediaTypesFinal[0] ?? DEFAULT_MEDIA_TYPE;
|
||||
}
|
||||
|
||||
return normalized as T & FinalizedMsgContext;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user