@openclaw/novita-provider 2026.11.3 → 2026.11.5-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"entries":[{"output":"index.js","source":"extensions/novita/index.ts"},{"output":"video-generation-provider.js","source":"extensions/novita/video-generation-provider.ts"}],"chunks":[{"output":"index.js","sha256":"e96c2caf023d52b0d2aae8f343a3528c2d1bc2239450d733187376127bd63f1b","facadeSource":"extensions/novita/index.ts","sources":["extensions/novita/index.ts","extensions/novita/openclaw.plugin.json"]},{"output":"video-generation-provider.js","sha256":"28831dd0b6a0a2ae3b4572c3bb30de2ee81fe91255eaa0871844a3041d3793f9","facadeSource":"extensions/novita/video-generation-provider.ts","sources":["extensions/novita/video-generation-provider.ts"]}],"unrenderedSources":[]}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveImageSourceUrl } from "openclaw/plugin-sdk/image-generation";
|
|
2
2
|
import { downloadGeneratedVideoAsset, resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
|
|
3
3
|
import { isProviderApiKeyConfiguredAsync } from "openclaw/plugin-sdk/provider-auth";
|
|
4
|
-
import {
|
|
5
|
-
import { assertOkOrThrowHttpError, createProviderOperationDeadline, createProviderOperationTimeoutResolver, pollProviderOperationJson, postJsonRequest, readProviderJsonObjectResponse, resolveProviderHttpRequestConfig, sanitizeConfiguredModelProviderRequest } from "openclaw/plugin-sdk/provider-http";
|
|
4
|
+
import { createProviderOperationDeadline, createProviderOperationTimeoutResolver, pollProviderOperationJson, postJsonResponse, resolveProviderApiKeyHttpRequestConfig, sanitizeConfiguredModelProviderRequest } from "openclaw/plugin-sdk/provider-http";
|
|
6
5
|
import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
7
6
|
//#region extensions/novita/video-generation-provider.ts
|
|
8
7
|
const DEFAULT_BASE_URL = "https://api.novita.ai";
|
|
@@ -121,10 +120,6 @@ const MODEL_CATALOG = {
|
|
|
121
120
|
}
|
|
122
121
|
}
|
|
123
122
|
};
|
|
124
|
-
function nearestDuration(value, allowed) {
|
|
125
|
-
const requested = typeof value === "number" && Number.isFinite(value) ? value : allowed[0];
|
|
126
|
-
return allowed.reduce((best, current) => Math.abs(current - requested) < Math.abs(best - requested) ? current : best);
|
|
127
|
-
}
|
|
128
123
|
function resolveModel(req) {
|
|
129
124
|
const model = normalizeOptionalString(req.model) ?? DEFAULT_MODEL;
|
|
130
125
|
if (!Object.hasOwn(MODEL_CATALOG, model)) throw new Error(`Novita video generation does not support model ${model}.`);
|
|
@@ -135,18 +130,6 @@ function resolveModel(req) {
|
|
|
135
130
|
if (images[0]?.role && images[0].role !== "first_frame") throw new Error("Novita image-to-video supports only an ordinary or first_frame image.");
|
|
136
131
|
return images.length > 0 ? model.replace(/-t2v$/, "-i2v") : model;
|
|
137
132
|
}
|
|
138
|
-
function resolveImage(req) {
|
|
139
|
-
const image = req.inputImages?.[0];
|
|
140
|
-
if (!image) return;
|
|
141
|
-
const url = normalizeOptionalString(image.url);
|
|
142
|
-
if (url) return url;
|
|
143
|
-
if (!image.buffer) throw new Error("Novita image-to-video input is missing image data.");
|
|
144
|
-
return toImageDataUrl({
|
|
145
|
-
...image,
|
|
146
|
-
buffer: image.buffer,
|
|
147
|
-
defaultMimeType: "image/png"
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
133
|
function resolveResolution(req, wan) {
|
|
151
134
|
return normalizeOptionalString(req.resolution)?.toUpperCase() === "1080P" ? "1080P" : wan ? "720P" : "768P";
|
|
152
135
|
}
|
|
@@ -160,18 +143,14 @@ function resolveWanSize(req) {
|
|
|
160
143
|
}
|
|
161
144
|
function buildBody(req, model) {
|
|
162
145
|
const wan = model.startsWith("wan");
|
|
163
|
-
const image =
|
|
146
|
+
const image = resolveImageSourceUrl(req.inputImages?.[0], "Novita image-to-video input is missing image data.");
|
|
164
147
|
const options = req.providerOptions ?? {};
|
|
165
148
|
const mode = image ? "imageToVideo" : "generate";
|
|
166
149
|
const schema = MODEL_CATALOG[model]?.capabilities?.[mode]?.providerOptions ?? {};
|
|
167
150
|
for (const [key, value] of Object.entries(options)) if (typeof value !== schema[key]) throw new Error(`Novita ${model} does not support provider option ${key} with this value.`);
|
|
168
151
|
const audioInputs = req.inputAudios ?? [];
|
|
169
152
|
if (audioInputs.length > (wan ? 1 : 0)) throw new Error(`Novita ${model} supports ${wan ? "at most one" : "no"} audio reference input.`);
|
|
170
|
-
const duration =
|
|
171
|
-
5,
|
|
172
|
-
10,
|
|
173
|
-
15
|
|
174
|
-
] : [6, 10]);
|
|
153
|
+
const duration = req.durationSeconds ?? (wan ? 5 : 6);
|
|
175
154
|
const resolution = resolveResolution(req, wan);
|
|
176
155
|
if (!wan) {
|
|
177
156
|
if (duration === 10 && resolution === "1080P") throw new Error("Novita Hailuo 1080P requires a 6-second duration; use 768P for 10 seconds.");
|
|
@@ -240,13 +219,17 @@ function buildNovitaVideoGenerationProvider() {
|
|
|
240
219
|
async generateVideo(req) {
|
|
241
220
|
const model = resolveModel(req);
|
|
242
221
|
const body = buildBody(req, model);
|
|
243
|
-
const
|
|
222
|
+
const providerConfig = req.cfg.models?.providers?.novita;
|
|
223
|
+
const configuredBase = normalizeOptionalString(providerConfig?.baseUrl)?.replace(/\/+$/, "").replace(/\/openai\/v1$/, "");
|
|
224
|
+
const { baseUrl, headers, allowPrivateNetwork, dispatcherPolicy } = await resolveProviderApiKeyHttpRequestConfig({
|
|
225
|
+
req,
|
|
226
|
+
missingApiKeyMessage: "Novita API key missing",
|
|
227
|
+
baseUrl: configuredBase ?? DEFAULT_BASE_URL,
|
|
228
|
+
defaultBaseUrl: DEFAULT_BASE_URL,
|
|
244
229
|
provider: "novita",
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
store: req.authStore
|
|
230
|
+
capability: "video",
|
|
231
|
+
request: sanitizeConfiguredModelProviderRequest(providerConfig?.request)
|
|
248
232
|
});
|
|
249
|
-
if (!auth.apiKey) throw new Error("Novita API key missing");
|
|
250
233
|
const deadline = createProviderOperationDeadline({
|
|
251
234
|
timeoutMs: req.timeoutMs ?? DEFAULT_OPERATION_TIMEOUT_MS,
|
|
252
235
|
label: "Novita video generation"
|
|
@@ -255,43 +238,25 @@ function buildNovitaVideoGenerationProvider() {
|
|
|
255
238
|
deadline,
|
|
256
239
|
defaultTimeoutMs: DEFAULT_TIMEOUT_MS
|
|
257
240
|
});
|
|
258
|
-
const providerConfig = req.cfg.models?.providers?.novita;
|
|
259
|
-
const configuredBase = normalizeOptionalString(providerConfig?.baseUrl)?.replace(/\/+$/, "").replace(/\/openai\/v1$/, "");
|
|
260
|
-
const { baseUrl, headers, allowPrivateNetwork, dispatcherPolicy } = resolveProviderHttpRequestConfig({
|
|
261
|
-
baseUrl: configuredBase ?? DEFAULT_BASE_URL,
|
|
262
|
-
defaultBaseUrl: DEFAULT_BASE_URL,
|
|
263
|
-
defaultHeaders: {
|
|
264
|
-
Authorization: `Bearer ${auth.apiKey}`,
|
|
265
|
-
"Content-Type": "application/json"
|
|
266
|
-
},
|
|
267
|
-
provider: "novita",
|
|
268
|
-
capability: "video",
|
|
269
|
-
transport: "http",
|
|
270
|
-
request: sanitizeConfiguredModelProviderRequest(providerConfig?.request)
|
|
271
|
-
});
|
|
272
241
|
const endpoint = `/v3/async/${model}`;
|
|
273
|
-
const
|
|
242
|
+
const submitted = await postJsonResponse({
|
|
274
243
|
url: `${baseUrl}${endpoint}`,
|
|
275
244
|
headers,
|
|
276
245
|
body,
|
|
277
246
|
timeoutMs: timeoutMs(),
|
|
278
247
|
fetchFn: fetch,
|
|
279
248
|
allowPrivateNetwork,
|
|
280
|
-
dispatcherPolicy
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
try {
|
|
284
|
-
await assertOkOrThrowHttpError(response, "Novita video generation failed", {
|
|
249
|
+
dispatcherPolicy,
|
|
250
|
+
errorLabel: "Novita video generation failed",
|
|
251
|
+
errorOptions: {
|
|
285
252
|
bodyTimeoutMs: timeoutMs,
|
|
286
253
|
requestHeaders: headers
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
await release();
|
|
294
|
-
}
|
|
254
|
+
},
|
|
255
|
+
readOptions: { timeoutMs },
|
|
256
|
+
objectResponse: true
|
|
257
|
+
});
|
|
258
|
+
const taskId = normalizeOptionalString(submitted.task_id);
|
|
259
|
+
if (!taskId) throw new Error("Novita video generation response missing task_id");
|
|
295
260
|
const pollUrl = new URL(`${baseUrl}/v3/async/task-result`);
|
|
296
261
|
pollUrl.searchParams.set("task_id", taskId);
|
|
297
262
|
const completed = await pollProviderOperationJson({
|
|
@@ -300,7 +265,7 @@ function buildNovitaVideoGenerationProvider() {
|
|
|
300
265
|
deadline,
|
|
301
266
|
defaultTimeoutMs: DEFAULT_TIMEOUT_MS,
|
|
302
267
|
fetchFn: fetch,
|
|
303
|
-
allowPrivateNetwork,
|
|
268
|
+
ssrfPolicy: { allowPrivateNetwork },
|
|
304
269
|
dispatcherPolicy,
|
|
305
270
|
maxAttempts: 120,
|
|
306
271
|
pollIntervalMs: 5e3,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/novita-provider",
|
|
3
|
-
"version": "2026.11.
|
|
3
|
+
"version": "2026.11.5-beta.2",
|
|
4
4
|
"description": "OpenClaw NovitaAI provider plugin",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"minHostVersion": ">=2026.7.2"
|
|
19
19
|
},
|
|
20
20
|
"compat": {
|
|
21
|
-
"pluginApi": ">=2026.11.
|
|
21
|
+
"pluginApi": ">=2026.11.5-beta.2"
|
|
22
22
|
},
|
|
23
23
|
"build": {
|
|
24
|
-
"openclawVersion": "2026.11.
|
|
24
|
+
"openclawVersion": "2026.11.5-beta.2",
|
|
25
25
|
"bundledDist": false
|
|
26
26
|
},
|
|
27
27
|
"release": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"assets/activity.svg"
|
|
41
41
|
],
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"openclaw": ">=2026.11.
|
|
43
|
+
"openclaw": ">=2026.11.5-beta.2"
|
|
44
44
|
},
|
|
45
45
|
"peerDependenciesMeta": {
|
|
46
46
|
"openclaw": {
|