@@ -12,7 +12,10 @@ import {
|
12 | 12 | resolveProviderHttpRequestConfig, |
13 | 13 | type ProviderOperationTimeoutMs, |
14 | 14 | } from "openclaw/plugin-sdk/provider-http"; |
15 | | -import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; |
| 15 | +import { |
| 16 | +asSafeIntegerInRange, |
| 17 | +normalizeOptionalString, |
| 18 | +} from "openclaw/plugin-sdk/string-coerce-runtime"; |
16 | 19 | import type { |
17 | 20 | GeneratedVideoAsset, |
18 | 21 | VideoGenerationProvider, |
@@ -26,6 +29,8 @@ const TOGETHER_VIDEO_BASE_URL = "https://api.together.xyz/v2";
|
26 | 29 | const DEFAULT_TIMEOUT_MS = 120_000; |
27 | 30 | const POLL_INTERVAL_MS = 5_000; |
28 | 31 | const MAX_POLL_ATTEMPTS = 120; |
| 32 | +const TOGETHER_MIN_DURATION_SECONDS = 1; |
| 33 | +const TOGETHER_MAX_DURATION_SECONDS = 10; |
29 | 34 | |
30 | 35 | type TogetherVideoResponse = { |
31 | 36 | id?: string; |
@@ -81,6 +86,17 @@ function extractTogetherVideoUrl(payload: TogetherVideoResponse): string | undef
|
81 | 86 | ); |
82 | 87 | } |
83 | 88 | |
| 89 | +function resolveTogetherDurationSeconds(value: unknown): string | undefined { |
| 90 | +if (typeof value !== "number" || !Number.isFinite(value)) { |
| 91 | +return undefined; |
| 92 | +} |
| 93 | +const duration = asSafeIntegerInRange(Math.round(value), { |
| 94 | +min: TOGETHER_MIN_DURATION_SECONDS, |
| 95 | +max: TOGETHER_MAX_DURATION_SECONDS, |
| 96 | +}); |
| 97 | +return duration === undefined ? undefined : String(duration); |
| 98 | +} |
| 99 | + |
84 | 100 | async function pollTogetherVideo(params: { |
85 | 101 | videoId: string; |
86 | 102 | headers: Headers; |
@@ -151,15 +167,15 @@ export function buildTogetherVideoGenerationProvider(): VideoGenerationProvider
|
151 | 167 | capabilities: { |
152 | 168 | generate: { |
153 | 169 | maxVideos: 1, |
154 | | -maxDurationSeconds: 12, |
| 170 | +maxDurationSeconds: TOGETHER_MAX_DURATION_SECONDS, |
155 | 171 | supportsSize: true, |
156 | 172 | }, |
157 | 173 | imageToVideo: { |
158 | 174 | enabled: true, |
159 | 175 | maxInputImagesByModel: { |
160 | 176 | "Wan-AI/Wan2.2-I2V-A14B": 1, |
161 | 177 | }, |
162 | | -maxDurationSeconds: 12, |
| 178 | +maxDurationSeconds: TOGETHER_MAX_DURATION_SECONDS, |
163 | 179 | supportsSize: true, |
164 | 180 | }, |
165 | 181 | videoToVideo: { |
@@ -203,8 +219,9 @@ export function buildTogetherVideoGenerationProvider(): VideoGenerationProvider
|
203 | 219 | prompt: req.prompt, |
204 | 220 | }; |
205 | 221 | const model = String(body.model); |
206 | | -if (typeof req.durationSeconds === "number" && Number.isFinite(req.durationSeconds)) { |
207 | | -body.seconds = String(Math.max(1, Math.round(req.durationSeconds))); |
| 222 | +const duration = resolveTogetherDurationSeconds(req.durationSeconds); |
| 223 | +if (duration !== undefined) { |
| 224 | +body.seconds = duration; |
208 | 225 | } |
209 | 226 | const size = normalizeOptionalString(req.size); |
210 | 227 | if (size) { |
|