fix: validate pixverse video seed metadata

This commit is contained in:
Peter Steinberger
2026-05-28 17:49:58 -04:00
parent 4dbe2a3d2b
commit 1fd73947d1
2 changed files with 55 additions and 4 deletions

View File

@@ -182,6 +182,48 @@ describe("pixverse video generation provider", () => {
expect(firstPostJsonRequest().body).not.toHaveProperty("seed");
});
it("drops malformed response seed metadata", async () => {
postJsonRequestMock.mockResolvedValue({
response: {
json: async () => ({
ErrCode: 0,
ErrMsg: "success",
Resp: { video_id: 123 },
}),
},
release: vi.fn(async () => {}),
});
fetchWithTimeoutMock.mockResolvedValueOnce({
json: async () => ({
ErrCode: 0,
ErrMsg: "success",
Resp: {
id: 123,
status: 1,
url: "https://media.pixverse.ai/out.mp4",
seed: 1.5,
},
}),
headers: new Headers(),
});
const provider = buildPixVerseVideoGenerationProvider();
const result = await provider.generateVideo({
provider: "pixverse",
model: "pixverse/v6",
prompt: "a quiet city street at sunrise",
cfg: {},
});
expect(result.metadata).toEqual({
endpoint: "/video/text/generate",
videoId: 123,
status: 1,
seed: undefined,
size: undefined,
});
});
it("uploads local image input before submitting image-to-video", async () => {
postMultipartRequestMock.mockResolvedValue({
response: {

View File

@@ -13,7 +13,11 @@ import {
sanitizeConfiguredModelProviderRequest,
type ProviderOperationDeadline,
} from "openclaw/plugin-sdk/provider-http";
import { asFiniteNumber, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
import {
asFiniteNumber,
asSafeIntegerInRange,
normalizeOptionalString,
} from "openclaw/plugin-sdk/string-coerce-runtime";
import type {
GeneratedVideoAsset,
VideoGenerationProvider,
@@ -34,6 +38,7 @@ const DEFAULT_TIMEOUT_MS = 300_000;
const POLL_INTERVAL_MS = 5_000;
const MAX_POLL_ATTEMPTS = 180;
const MAX_DURATION_SECONDS = 15;
const PIXVERSE_SEED_MAX = 2_147_483_647;
const PIXVERSE_VIDEO_MODELS = ["v6", "c1"] as const;
const PIXVERSE_TEXT_ASPECT_RATIOS = [
"16:9",
@@ -134,12 +139,16 @@ function appendOptionalNumber(body: Record<string, unknown>, key: string, value:
}
function appendOptionalInt32Seed(body: Record<string, unknown>, value: unknown): void {
const seed = asFiniteNumber(value);
if (seed != null && Number.isSafeInteger(seed) && seed >= 0 && seed <= 2_147_483_647) {
const seed = asSafeIntegerInRange(value, { min: 0, max: PIXVERSE_SEED_MAX });
if (seed !== undefined) {
body.seed = seed;
}
}
function readPixVerseSeed(value: unknown): number | undefined {
return asSafeIntegerInRange(value, { min: 0, max: PIXVERSE_SEED_MAX });
}
function appendOptionalString(body: Record<string, unknown>, key: string, value: unknown): void {
const stringValue = normalizeOptionalString(value);
if (stringValue) {
@@ -498,7 +507,7 @@ export function buildPixVerseVideoGenerationProvider(): VideoGenerationProvider
endpoint,
videoId,
status: readPixVerseStatus(completed),
seed: asFiniteNumber(completed.seed),
seed: readPixVerseSeed(completed.seed),
size: asFiniteNumber(completed.size),
},
};