@nodetool-ai/agents 0.8.2 → 0.8.3
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/dist/.nodetool-build-stamp +1 -1
- package/dist/apify/assets.d.ts.map +1 -1
- package/dist/apify/assets.js +4 -0
- package/dist/apify/assets.js.map +1 -1
- package/dist/capabilities/agent-activity.js +1 -1
- package/dist/capabilities/assets.d.ts.map +1 -1
- package/dist/capabilities/assets.js +40 -10
- package/dist/capabilities/assets.js.map +1 -1
- package/dist/capabilities/collections.d.ts +4 -6
- package/dist/capabilities/collections.d.ts.map +1 -1
- package/dist/capabilities/collections.js +16 -11
- package/dist/capabilities/collections.js.map +1 -1
- package/dist/capabilities/derive-shot.d.ts +45 -0
- package/dist/capabilities/derive-shot.d.ts.map +1 -0
- package/dist/capabilities/derive-shot.js +82 -0
- package/dist/capabilities/derive-shot.js.map +1 -0
- package/dist/capabilities/documents.d.ts +2 -1
- package/dist/capabilities/documents.d.ts.map +1 -1
- package/dist/capabilities/documents.js +12 -6
- package/dist/capabilities/documents.js.map +1 -1
- package/dist/capabilities/email.d.ts +2 -1
- package/dist/capabilities/email.d.ts.map +1 -1
- package/dist/capabilities/email.js +5 -3
- package/dist/capabilities/email.js.map +1 -1
- package/dist/capabilities/game-asset-browser.d.ts +11 -0
- package/dist/capabilities/game-asset-browser.d.ts.map +1 -0
- package/dist/capabilities/game-asset-browser.js +152 -0
- package/dist/capabilities/game-asset-browser.js.map +1 -0
- package/dist/capabilities/game.d.ts +30 -0
- package/dist/capabilities/game.d.ts.map +1 -1
- package/dist/capabilities/game.js +215 -137
- package/dist/capabilities/game.js.map +1 -1
- package/dist/capabilities/game.specs.d.ts +2 -0
- package/dist/capabilities/game.specs.d.ts.map +1 -1
- package/dist/capabilities/game.specs.js +20 -5
- package/dist/capabilities/game.specs.js.map +1 -1
- package/dist/capabilities/game3d.d.ts.map +1 -1
- package/dist/capabilities/game3d.js +4 -3
- package/dist/capabilities/game3d.js.map +1 -1
- package/dist/capabilities/generations.d.ts.map +1 -1
- package/dist/capabilities/generations.js +7 -21
- package/dist/capabilities/generations.js.map +1 -1
- package/dist/capabilities/lazy-tool-core.d.ts +23 -0
- package/dist/capabilities/lazy-tool-core.d.ts.map +1 -0
- package/dist/capabilities/lazy-tool-core.js +56 -0
- package/dist/capabilities/lazy-tool-core.js.map +1 -0
- package/dist/capabilities/lazy-tool.d.ts +2 -21
- package/dist/capabilities/lazy-tool.d.ts.map +1 -1
- package/dist/capabilities/lazy-tool.js +3 -55
- package/dist/capabilities/lazy-tool.js.map +1 -1
- package/dist/capabilities/legacy-tools.js +1 -1
- package/dist/capabilities/legacy-tools.js.map +1 -1
- package/dist/capabilities/media.d.ts.map +1 -1
- package/dist/capabilities/media.js +13 -1
- package/dist/capabilities/media.js.map +1 -1
- package/dist/capabilities/media.specs.d.ts.map +1 -1
- package/dist/capabilities/media.specs.js +17 -0
- package/dist/capabilities/media.specs.js.map +1 -1
- package/dist/capabilities/metadata.d.ts +62 -0
- package/dist/capabilities/metadata.d.ts.map +1 -0
- package/dist/capabilities/metadata.js +114 -0
- package/dist/capabilities/metadata.js.map +1 -0
- package/dist/capabilities/model3d.d.ts.map +1 -1
- package/dist/capabilities/model3d.js +4 -0
- package/dist/capabilities/model3d.js.map +1 -1
- package/dist/capabilities/registry.d.ts +4 -19
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js +48 -117
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/capabilities/run-agent.js +1 -1
- package/dist/capabilities/settings.d.ts.map +1 -1
- package/dist/capabilities/settings.js +4 -2
- package/dist/capabilities/settings.js.map +1 -1
- package/dist/capabilities/storyboards.d.ts +11 -1
- package/dist/capabilities/storyboards.d.ts.map +1 -1
- package/dist/capabilities/storyboards.js +466 -4
- package/dist/capabilities/storyboards.js.map +1 -1
- package/dist/capabilities/storyboards.specs.d.ts +6 -0
- package/dist/capabilities/storyboards.specs.d.ts.map +1 -1
- package/dist/capabilities/storyboards.specs.js +131 -2
- package/dist/capabilities/storyboards.specs.js.map +1 -1
- package/dist/capabilities/threads.js +1 -1
- package/dist/capabilities/threads.js.map +1 -1
- package/dist/capabilities/timeline-bridge.d.ts +9 -0
- package/dist/capabilities/timeline-bridge.d.ts.map +1 -1
- package/dist/capabilities/timeline-bridge.js +60 -68
- package/dist/capabilities/timeline-bridge.js.map +1 -1
- package/dist/capabilities/timeline-operations.d.ts +52 -0
- package/dist/capabilities/timeline-operations.d.ts.map +1 -0
- package/dist/capabilities/timeline-operations.js +413 -0
- package/dist/capabilities/timeline-operations.js.map +1 -0
- package/dist/capabilities/timelines.d.ts +3 -38
- package/dist/capabilities/timelines.d.ts.map +1 -1
- package/dist/capabilities/timelines.js +30 -413
- package/dist/capabilities/timelines.js.map +1 -1
- package/dist/capabilities/timelines.specs.d.ts.map +1 -1
- package/dist/capabilities/timelines.specs.js +5 -1
- package/dist/capabilities/timelines.specs.js.map +1 -1
- package/dist/capabilities/web.d.ts.map +1 -1
- package/dist/capabilities/web.js +4 -0
- package/dist/capabilities/web.js.map +1 -1
- package/dist/capabilities/workflows.d.ts +3 -1
- package/dist/capabilities/workflows.d.ts.map +1 -1
- package/dist/capabilities/workflows.js +192 -14
- package/dist/capabilities/workflows.js.map +1 -1
- package/dist/capabilities/workflows.specs.d.ts +2 -0
- package/dist/capabilities/workflows.specs.d.ts.map +1 -1
- package/dist/capabilities/workflows.specs.js +65 -1
- package/dist/capabilities/workflows.specs.js.map +1 -1
- package/dist/codeact/sandbox-packages.d.ts +0 -7
- package/dist/codeact/sandbox-packages.d.ts.map +1 -1
- package/dist/codeact/sandbox-packages.js +1 -10
- package/dist/codeact/sandbox-packages.js.map +1 -1
- package/dist/evals/surfaces/game.d.ts +8 -2
- package/dist/evals/surfaces/game.d.ts.map +1 -1
- package/dist/evals/surfaces/game.js +460 -2
- package/dist/evals/surfaces/game.js.map +1 -1
- package/dist/game-authoring.d.ts +4895 -59
- package/dist/game-authoring.d.ts.map +1 -1
- package/dist/game-build.d.ts +3 -0
- package/dist/game-build.d.ts.map +1 -0
- package/dist/game-build.js +3 -0
- package/dist/game-build.js.map +1 -0
- package/dist/game-examples.d.ts +1355 -2
- package/dist/game-examples.d.ts.map +1 -1
- package/dist/generation-cancel.d.ts +31 -0
- package/dist/generation-cancel.d.ts.map +1 -0
- package/dist/generation-cancel.js +28 -0
- package/dist/generation-cancel.js.map +1 -0
- package/dist/host-access-gate.d.ts +29 -0
- package/dist/host-access-gate.d.ts.map +1 -0
- package/dist/host-access-gate.js +39 -0
- package/dist/host-access-gate.js.map +1 -0
- package/dist/host-modules/dispatcher.d.ts +7 -1
- package/dist/host-modules/dispatcher.d.ts.map +1 -1
- package/dist/host-modules/dispatcher.js +13 -2
- package/dist/host-modules/dispatcher.js.map +1 -1
- package/dist/host-modules/docx.d.ts.map +1 -1
- package/dist/host-modules/docx.js +2 -2
- package/dist/host-modules/docx.js.map +1 -1
- package/dist/host-modules/epub.d.ts.map +1 -1
- package/dist/host-modules/epub.js +2 -2
- package/dist/host-modules/epub.js.map +1 -1
- package/dist/host-modules/fabric.d.ts.map +1 -1
- package/dist/host-modules/fabric.js +1 -1
- package/dist/host-modules/fabric.js.map +1 -1
- package/dist/host-modules/limits.d.ts +10 -8
- package/dist/host-modules/limits.d.ts.map +1 -1
- package/dist/host-modules/limits.js +14 -9
- package/dist/host-modules/limits.js.map +1 -1
- package/dist/host-modules/mammoth.d.ts.map +1 -1
- package/dist/host-modules/mammoth.js +2 -2
- package/dist/host-modules/mammoth.js.map +1 -1
- package/dist/host-modules/ocr.d.ts.map +1 -1
- package/dist/host-modules/ocr.js +1 -1
- package/dist/host-modules/ocr.js.map +1 -1
- package/dist/host-modules/pdf.d.ts.map +1 -1
- package/dist/host-modules/pdf.js +2 -2
- package/dist/host-modules/pdf.js.map +1 -1
- package/dist/host-modules/pdflib.d.ts.map +1 -1
- package/dist/host-modules/pdflib.js +2 -2
- package/dist/host-modules/pdflib.js.map +1 -1
- package/dist/host-modules/pptx.d.ts.map +1 -1
- package/dist/host-modules/pptx.js +2 -2
- package/dist/host-modules/pptx.js.map +1 -1
- package/dist/host-modules/pptxgen.d.ts.map +1 -1
- package/dist/host-modules/pptxgen.js +2 -2
- package/dist/host-modules/pptxgen.js.map +1 -1
- package/dist/host-modules/tfjs.d.ts.map +1 -1
- package/dist/host-modules/tfjs.js +4 -4
- package/dist/host-modules/tfjs.js.map +1 -1
- package/dist/host-modules/xlsx.d.ts.map +1 -1
- package/dist/host-modules/xlsx.js +2 -2
- package/dist/host-modules/xlsx.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/js-sandbox.d.ts +7 -1
- package/dist/js-sandbox.d.ts.map +1 -1
- package/dist/js-sandbox.js +20 -4
- package/dist/js-sandbox.js.map +1 -1
- package/dist/timeline-code-bake.js +2 -2
- package/dist/timeline-code-bake.js.map +1 -1
- package/dist/tools/builtin-tools.d.ts +4 -3
- package/dist/tools/builtin-tools.d.ts.map +1 -1
- package/dist/tools/builtin-tools.js +11 -3
- package/dist/tools/builtin-tools.js.map +1 -1
- package/package.json +122 -41
|
@@ -20,9 +20,9 @@ import { z } from "zod";
|
|
|
20
20
|
import { SpanStatusCode } from "@opentelemetry/api";
|
|
21
21
|
import { mp4DurationSeconds, withSpan } from "@nodetool-ai/runtime";
|
|
22
22
|
import { storyboardMotionDesign, storyboardShotGraphics } from "@nodetool-ai/protocol/api-schemas/storyboards.js";
|
|
23
|
-
import { assertProductionGenerationAllowed, isFullResourceId, isShortResourceId, productionRequirement } from "@nodetool-ai/protocol";
|
|
23
|
+
import { assertProductionGenerationAllowed, compileOneTake, isFullResourceId, isShortResourceId, productionRequirement } from "@nodetool-ai/protocol";
|
|
24
24
|
import { stampScriptStoryboardId } from "./script-link.js";
|
|
25
|
-
import { listStoryboardsSpec, createStoryboardSpec, getStoryboardSpec, renderStoryboardStillsSpec, renderStoryboardClipsSpec, reviseStoryboardClipSpec, assembleStoryboardTimelineSpec, editStoryboardSpec, directStoryboardSpec, extractScriptFromStoryboardSpec, deleteStoryboardSpec } from "./storyboards.specs.js";
|
|
25
|
+
import { listStoryboardsSpec, createStoryboardSpec, getStoryboardSpec, renderStoryboardStillsSpec, renderStoryboardClipsSpec, reviseStoryboardClipSpec, assembleStoryboardTimelineSpec, deriveShotFromClipSpec, editStoryboardSpec, directStoryboardSpec, extractScriptFromStoryboardSpec, deleteStoryboardSpec, getStoryboardOneTakeSpec, updateStoryboardOneTakeSpec } from "./storyboards.specs.js";
|
|
26
26
|
import { measureStoryboardSources } from "./storyboard-measured-sources.js";
|
|
27
27
|
import { clampConcurrency } from "./concurrency.js";
|
|
28
28
|
import { isNonBlankString, isNumber, isRecord, isString } from "../utils/type-guards.js";
|
|
@@ -439,6 +439,8 @@ const getStoryboard = {
|
|
|
439
439
|
action: shot.action,
|
|
440
440
|
camera: shot.camera,
|
|
441
441
|
motion: shot.motion,
|
|
442
|
+
end_state: shot.end_state,
|
|
443
|
+
sound: shot.sound,
|
|
442
444
|
graphics: shot.graphics,
|
|
443
445
|
production: shot.production,
|
|
444
446
|
duration_seconds: shot.duration_seconds,
|
|
@@ -1291,6 +1293,8 @@ const SHOT_EDIT_FIELDS = new Set([
|
|
|
1291
1293
|
"slug",
|
|
1292
1294
|
"camera",
|
|
1293
1295
|
"motion",
|
|
1296
|
+
"end_state",
|
|
1297
|
+
"sound",
|
|
1294
1298
|
"graphics",
|
|
1295
1299
|
"production",
|
|
1296
1300
|
"dialogue",
|
|
@@ -1436,6 +1440,17 @@ function applyShotFields(shot, args, shots = []) {
|
|
|
1436
1440
|
next.camera = args["camera"];
|
|
1437
1441
|
if (args["motion"] !== undefined)
|
|
1438
1442
|
next.motion = String(args["motion"]);
|
|
1443
|
+
for (const field of ["end_state", "sound"]) {
|
|
1444
|
+
const value = args[field];
|
|
1445
|
+
if (value === undefined)
|
|
1446
|
+
continue;
|
|
1447
|
+
if (value === null || String(value).trim() === "") {
|
|
1448
|
+
delete next[field];
|
|
1449
|
+
}
|
|
1450
|
+
else {
|
|
1451
|
+
next[field] = String(value);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1439
1454
|
if (args["graphics"] !== undefined) {
|
|
1440
1455
|
if (args["graphics"] === null) {
|
|
1441
1456
|
delete next.graphics;
|
|
@@ -2131,6 +2146,212 @@ const editStoryboard = {
|
|
|
2131
2146
|
}
|
|
2132
2147
|
};
|
|
2133
2148
|
// ---------------------------------------------------------------------------
|
|
2149
|
+
// derive_shot_from_clip
|
|
2150
|
+
// ---------------------------------------------------------------------------
|
|
2151
|
+
const DEFAULT_DERIVED_FRAMES = 3;
|
|
2152
|
+
const formatSeconds = (ms) => `${(ms / 1000).toFixed(1)}s`;
|
|
2153
|
+
/**
|
|
2154
|
+
* The headless twin of the editor's Derived shot section
|
|
2155
|
+
* (`useDeriveShotFromClip`): frames → assets → a shot after the source shot
|
|
2156
|
+
* → a clip following it on a new track above the source clip. The board is
|
|
2157
|
+
* written before the timeline, so a timeline conflict leaves the shot on the
|
|
2158
|
+
* board and says so.
|
|
2159
|
+
*/
|
|
2160
|
+
const deriveShotFromClip = {
|
|
2161
|
+
spec: deriveShotFromClipSpec,
|
|
2162
|
+
impl: async (run, params) => {
|
|
2163
|
+
const timelineId = params["timeline_id"];
|
|
2164
|
+
if (!isNonBlankString(timelineId)) {
|
|
2165
|
+
return {
|
|
2166
|
+
error: "timeline_id is required (use list_timelines to find one)."
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
if (!isNonBlankString(params["clip_id"])) {
|
|
2170
|
+
return { error: "clip_id is required (a clip id or name)." };
|
|
2171
|
+
}
|
|
2172
|
+
const { MAX_DERIVED_FRAMES } = await import("@nodetool-ai/timeline");
|
|
2173
|
+
const frameCount = params["frame_count"] === undefined
|
|
2174
|
+
? DEFAULT_DERIVED_FRAMES
|
|
2175
|
+
: params["frame_count"];
|
|
2176
|
+
if (!isNumber(frameCount) ||
|
|
2177
|
+
!Number.isInteger(frameCount) ||
|
|
2178
|
+
frameCount < 1 ||
|
|
2179
|
+
frameCount > MAX_DERIVED_FRAMES) {
|
|
2180
|
+
return {
|
|
2181
|
+
error: `frame_count must be a whole number from 1 to ${MAX_DERIVED_FRAMES}.`
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
const actionParam = params["action"];
|
|
2185
|
+
if (actionParam !== undefined && !isString(actionParam)) {
|
|
2186
|
+
return { error: "action must be a string." };
|
|
2187
|
+
}
|
|
2188
|
+
const { TimelineSequence, Storyboard } = await import("@nodetool-ai/models");
|
|
2189
|
+
const sequence = await TimelineSequence.findById(timelineId);
|
|
2190
|
+
if (!sequence || sequence.user_id !== run.context.userId) {
|
|
2191
|
+
return { error: `Timeline ${timelineId} was not found.` };
|
|
2192
|
+
}
|
|
2193
|
+
const { findDocumentClip, captureDerivedFrames, placeDerivedShotClip } = await import("./derive-shot.js");
|
|
2194
|
+
const source = findDocumentClip(sequence.toDocument().clips, params["clip_id"]);
|
|
2195
|
+
if (!source) {
|
|
2196
|
+
return {
|
|
2197
|
+
error: `No clip matching "${params["clip_id"]}" in timeline ${timelineId}.`
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
const boardId = source.storyboardBoardId;
|
|
2201
|
+
const sourceShotId = source.storyboardShotId;
|
|
2202
|
+
if (!boardId || !sourceShotId) {
|
|
2203
|
+
return {
|
|
2204
|
+
error: `Clip "${source.name}" is not linked to a storyboard shot.`
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
if (source.mediaType !== "video" || !source.currentAssetId) {
|
|
2208
|
+
return {
|
|
2209
|
+
error: "Reference frames come from a video clip with footage."
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
const board = await loadBoard(run, boardId);
|
|
2213
|
+
if (isError(board))
|
|
2214
|
+
return board;
|
|
2215
|
+
const sourceShot = board.doc.shots.find((shot) => shot.id === sourceShotId);
|
|
2216
|
+
if (!sourceShot) {
|
|
2217
|
+
return {
|
|
2218
|
+
error: `The shot clip "${source.name}" follows is no longer on its board.`
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
const label = sourceShot.slug ?? `Shot ${sourceShot.index + 1}`;
|
|
2222
|
+
let frames;
|
|
2223
|
+
try {
|
|
2224
|
+
frames = await captureDerivedFrames(run.context, source, frameCount);
|
|
2225
|
+
}
|
|
2226
|
+
catch (error) {
|
|
2227
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
2228
|
+
}
|
|
2229
|
+
const bindings = [];
|
|
2230
|
+
for (const [index, frame] of frames.entries()) {
|
|
2231
|
+
const created = await run.context.createAsset({
|
|
2232
|
+
name: `${label}-frame-${index + 1}.png`,
|
|
2233
|
+
contentType: "image/png",
|
|
2234
|
+
content: frame.png
|
|
2235
|
+
});
|
|
2236
|
+
const assetId = isRecord(created) && isString(created["id"]) ? created["id"] : null;
|
|
2237
|
+
if (!assetId) {
|
|
2238
|
+
return { error: "A reference frame was saved without an asset id." };
|
|
2239
|
+
}
|
|
2240
|
+
bindings.push({
|
|
2241
|
+
kind: "style",
|
|
2242
|
+
asset_id: assetId,
|
|
2243
|
+
label: `${label} at ${formatSeconds(frame.sourceTimeMs)}`
|
|
2244
|
+
});
|
|
2245
|
+
}
|
|
2246
|
+
const action = actionParam?.trim() || sourceShot.action;
|
|
2247
|
+
const shotArgs = {
|
|
2248
|
+
after_shot_id: sourceShot.id,
|
|
2249
|
+
action,
|
|
2250
|
+
slug: `${label} (derived)`,
|
|
2251
|
+
duration_seconds: source.durationMs / 1000,
|
|
2252
|
+
duration_source: "manual",
|
|
2253
|
+
render_mode: "reference",
|
|
2254
|
+
production: {
|
|
2255
|
+
schema_version: 1,
|
|
2256
|
+
speech_mode: "none",
|
|
2257
|
+
requested_take_count: 1,
|
|
2258
|
+
reference_bindings: bindings
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
2261
|
+
if (sourceShot.camera !== undefined)
|
|
2262
|
+
shotArgs["camera"] = sourceShot.camera;
|
|
2263
|
+
if (sourceShot.motion !== undefined)
|
|
2264
|
+
shotArgs["motion"] = sourceShot.motion;
|
|
2265
|
+
if (sourceShot.entity_ids !== undefined) {
|
|
2266
|
+
shotArgs["entity_ids"] = sourceShot.entity_ids;
|
|
2267
|
+
}
|
|
2268
|
+
if (sourceShot.location_id !== undefined) {
|
|
2269
|
+
shotArgs["location_id"] = sourceShot.location_id;
|
|
2270
|
+
}
|
|
2271
|
+
let shot;
|
|
2272
|
+
for (let attempt = 0; attempt < CAS_ATTEMPTS && !shot; attempt++) {
|
|
2273
|
+
const current = await loadBoard(run, boardId);
|
|
2274
|
+
if (isError(current))
|
|
2275
|
+
return current;
|
|
2276
|
+
const { row, doc } = current;
|
|
2277
|
+
let shotId;
|
|
2278
|
+
try {
|
|
2279
|
+
const added = applyBoardOp(doc, { op: "add_shot", args: shotArgs });
|
|
2280
|
+
shotId = added.id;
|
|
2281
|
+
}
|
|
2282
|
+
catch (error) {
|
|
2283
|
+
return {
|
|
2284
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
const index = doc.shots.findIndex((candidate) => candidate.id === shotId);
|
|
2288
|
+
if (sourceShot.clip_model !== undefined) {
|
|
2289
|
+
doc.shots[index] = {
|
|
2290
|
+
...doc.shots[index],
|
|
2291
|
+
clip_model: sourceShot.clip_model
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
if (doc.screenplay) {
|
|
2295
|
+
doc.screenplay.shots = doc.shots;
|
|
2296
|
+
}
|
|
2297
|
+
const saved = await Storyboard.updateFieldsIfUnchanged(row.id, row.updated_at, { document: JSON.stringify(doc) }, { ops: [{ tool: "add_shot", input: { ...shotArgs, id: shotId } }] });
|
|
2298
|
+
if (saved)
|
|
2299
|
+
shot = doc.shots[index];
|
|
2300
|
+
}
|
|
2301
|
+
if (!shot) {
|
|
2302
|
+
return {
|
|
2303
|
+
error: `Storyboard ${boardId} is being modified concurrently; nothing was saved. Retry the call.`
|
|
2304
|
+
};
|
|
2305
|
+
}
|
|
2306
|
+
for (let attempt = 0; attempt < CAS_ATTEMPTS; attempt++) {
|
|
2307
|
+
const current = await TimelineSequence.findById(timelineId);
|
|
2308
|
+
if (!current)
|
|
2309
|
+
break;
|
|
2310
|
+
const document = current.toDocument();
|
|
2311
|
+
const latest = document.clips.find((clip) => clip.id === source.id);
|
|
2312
|
+
if (!latest)
|
|
2313
|
+
break;
|
|
2314
|
+
const placed = placeDerivedShotClip(document, latest, {
|
|
2315
|
+
boardId,
|
|
2316
|
+
shotId: shot.id,
|
|
2317
|
+
name: shot.slug ?? "Derived shot"
|
|
2318
|
+
});
|
|
2319
|
+
const saved = await TimelineSequence.updateDocumentIfUnchanged(current.id, current.updated_at, { ...document, tracks: placed.tracks, clips: placed.clips }, {
|
|
2320
|
+
ops: [
|
|
2321
|
+
{
|
|
2322
|
+
tool: "ui_timeline_add_track",
|
|
2323
|
+
input: { id: placed.trackId, type: "video" }
|
|
2324
|
+
},
|
|
2325
|
+
{
|
|
2326
|
+
tool: "ui_timeline_add_media_clip",
|
|
2327
|
+
input: { id: placed.clipId, track_id: placed.trackId }
|
|
2328
|
+
}
|
|
2329
|
+
]
|
|
2330
|
+
});
|
|
2331
|
+
if (saved) {
|
|
2332
|
+
return {
|
|
2333
|
+
storyboard_id: boardId,
|
|
2334
|
+
shot_id: shot.id,
|
|
2335
|
+
shot_index: shot.index,
|
|
2336
|
+
slug: shot.slug,
|
|
2337
|
+
reference_asset_ids: bindings.map((binding) => binding.asset_id),
|
|
2338
|
+
timeline_id: timelineId,
|
|
2339
|
+
track_id: placed.trackId,
|
|
2340
|
+
clip_id: placed.clipId,
|
|
2341
|
+
next: "Render the shot with render_storyboard_clips, targets " +
|
|
2342
|
+
`["${shot.id}"]. The clip plays the take once it lands.`
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
return {
|
|
2347
|
+
error: `Shot ${shot.id} was added to storyboard ${boardId}, but timeline ` +
|
|
2348
|
+
`${timelineId} changed or its source clip was removed, so no clip ` +
|
|
2349
|
+
"was placed. Add a clip for the shot with edit_timeline, or remove " +
|
|
2350
|
+
"the shot with edit_storyboard."
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
};
|
|
2354
|
+
// ---------------------------------------------------------------------------
|
|
2134
2355
|
// direct_storyboard
|
|
2135
2356
|
// ---------------------------------------------------------------------------
|
|
2136
2357
|
const DEFAULT_DIRECTED_SHOTS = 6;
|
|
@@ -2443,6 +2664,244 @@ const deleteStoryboard = {
|
|
|
2443
2664
|
: { error: `Storyboard ${id} was not found, or it is not yours.` };
|
|
2444
2665
|
}
|
|
2445
2666
|
};
|
|
2667
|
+
// ---------------------------------------------------------------------------
|
|
2668
|
+
// get_storyboard_one_take / update_storyboard_one_take
|
|
2669
|
+
// ---------------------------------------------------------------------------
|
|
2670
|
+
/** Above this the providers that take one continuous clip refuse or truncate. */
|
|
2671
|
+
const ONE_TAKE_MAX_SECONDS = 30;
|
|
2672
|
+
/** The most reference images a one-take provider accepts. */
|
|
2673
|
+
const ONE_TAKE_MAX_IMAGES = 9;
|
|
2674
|
+
const oneTakeUpdateInput = z.object({
|
|
2675
|
+
prompt: z.string().optional(),
|
|
2676
|
+
duration_seconds: z.number().positive().nullable().optional(),
|
|
2677
|
+
aspect_ratio: z.string().trim().min(1).nullable().optional(),
|
|
2678
|
+
resolution: z.string().trim().min(1).nullable().optional(),
|
|
2679
|
+
model: z
|
|
2680
|
+
.object({
|
|
2681
|
+
provider: z.string().trim().min(1),
|
|
2682
|
+
id: z.string().trim().min(1),
|
|
2683
|
+
name: z.string().optional()
|
|
2684
|
+
})
|
|
2685
|
+
.nullable()
|
|
2686
|
+
.optional(),
|
|
2687
|
+
shots: z
|
|
2688
|
+
.array(z.object({
|
|
2689
|
+
shot_id: z.string().trim().min(1),
|
|
2690
|
+
end_state: z.string().nullable().optional(),
|
|
2691
|
+
sound: z.string().nullable().optional()
|
|
2692
|
+
}))
|
|
2693
|
+
.optional()
|
|
2694
|
+
});
|
|
2695
|
+
/** The one-take render settings a call may set; null clears one. */
|
|
2696
|
+
const ONE_TAKE_SETTINGS = [
|
|
2697
|
+
"duration_seconds",
|
|
2698
|
+
"aspect_ratio",
|
|
2699
|
+
"resolution",
|
|
2700
|
+
"model"
|
|
2701
|
+
];
|
|
2702
|
+
/** The board's `videoModel` as a model ref, or null when it names none. */
|
|
2703
|
+
function boardVideoModel(value) {
|
|
2704
|
+
if (!value || typeof value !== "object")
|
|
2705
|
+
return null;
|
|
2706
|
+
const record = value;
|
|
2707
|
+
const id = record["id"];
|
|
2708
|
+
const provider = record["provider"];
|
|
2709
|
+
if (typeof id !== "string" || id === "" || typeof provider !== "string" || provider === "") {
|
|
2710
|
+
return null;
|
|
2711
|
+
}
|
|
2712
|
+
const model = {
|
|
2713
|
+
id,
|
|
2714
|
+
provider: provider
|
|
2715
|
+
};
|
|
2716
|
+
const name = record["name"];
|
|
2717
|
+
if (typeof name === "string") {
|
|
2718
|
+
model.name = name;
|
|
2719
|
+
}
|
|
2720
|
+
return model;
|
|
2721
|
+
}
|
|
2722
|
+
/** The shape both one-take capabilities return. */
|
|
2723
|
+
function oneTakeSummary(row, doc) {
|
|
2724
|
+
const compiled = compileOneTake({
|
|
2725
|
+
shots: doc.shots,
|
|
2726
|
+
oneTake: doc.one_take
|
|
2727
|
+
});
|
|
2728
|
+
const direction = doc.one_take;
|
|
2729
|
+
const settings = {
|
|
2730
|
+
duration_seconds: direction?.duration_seconds ?? null,
|
|
2731
|
+
aspect_ratio: direction?.aspect_ratio ?? null,
|
|
2732
|
+
resolution: direction?.resolution ?? null,
|
|
2733
|
+
model: direction?.model ?? null
|
|
2734
|
+
};
|
|
2735
|
+
const effective = {
|
|
2736
|
+
duration_seconds: compiled.duration_seconds,
|
|
2737
|
+
shot_total_seconds: compiled.shot_total_seconds,
|
|
2738
|
+
aspect_ratio: settings.aspect_ratio ?? doc.aspectRatio ?? null,
|
|
2739
|
+
resolution: settings.resolution,
|
|
2740
|
+
model: settings.model ?? boardVideoModel(doc.videoModel)
|
|
2741
|
+
};
|
|
2742
|
+
const warnings = [];
|
|
2743
|
+
if (!effective.model) {
|
|
2744
|
+
warnings.push("No video model is chosen: set `model` here or the board's video model.");
|
|
2745
|
+
}
|
|
2746
|
+
if (compiled.duration_seconds > ONE_TAKE_MAX_SECONDS) {
|
|
2747
|
+
warnings.push(`The take runs ${compiled.duration_seconds}s, over the ${ONE_TAKE_MAX_SECONDS}s one-take limit.`);
|
|
2748
|
+
}
|
|
2749
|
+
if (compiled.references.length > ONE_TAKE_MAX_IMAGES) {
|
|
2750
|
+
warnings.push(`${compiled.references.length} reference images; one-take models accept at most ${ONE_TAKE_MAX_IMAGES}.`);
|
|
2751
|
+
}
|
|
2752
|
+
const byId = new Map(doc.shots.map((shot) => [shot.id, shot]));
|
|
2753
|
+
const withoutStill = compiled.steps
|
|
2754
|
+
.map((step) => byId.get(step.shot_id))
|
|
2755
|
+
.filter((shot) => !!shot && !shot.keyframe?.asset_id);
|
|
2756
|
+
if (withoutStill.length > 0) {
|
|
2757
|
+
warnings.push(`Shots without a still send no image: ${withoutStill
|
|
2758
|
+
.map((shot) => shot.slug?.trim() || shot.id)
|
|
2759
|
+
.join(", ")}.`);
|
|
2760
|
+
}
|
|
2761
|
+
return {
|
|
2762
|
+
storyboard_id: row.id,
|
|
2763
|
+
revision: row.revision,
|
|
2764
|
+
updated_at: row.updated_at,
|
|
2765
|
+
stored: doc.one_take !== undefined,
|
|
2766
|
+
prompt: doc.one_take?.prompt ?? "",
|
|
2767
|
+
compiled: compiled.compiled,
|
|
2768
|
+
full_prompt: compiled.prompt,
|
|
2769
|
+
references: compiled.references.map((reference, index) => ({
|
|
2770
|
+
image_number: index + 1,
|
|
2771
|
+
marker: `[Image ${index + 1}]`,
|
|
2772
|
+
...reference
|
|
2773
|
+
})),
|
|
2774
|
+
steps: compiled.steps.map((step) => {
|
|
2775
|
+
const shot = byId.get(step.shot_id);
|
|
2776
|
+
return {
|
|
2777
|
+
shot_id: step.shot_id,
|
|
2778
|
+
index: shot?.index,
|
|
2779
|
+
slug: shot?.slug,
|
|
2780
|
+
start_seconds: step.start_seconds,
|
|
2781
|
+
end_seconds: step.end_seconds,
|
|
2782
|
+
end_state: shot?.end_state ?? null,
|
|
2783
|
+
sound: shot?.sound ?? null
|
|
2784
|
+
};
|
|
2785
|
+
}),
|
|
2786
|
+
duration_seconds: compiled.duration_seconds,
|
|
2787
|
+
settings,
|
|
2788
|
+
effective,
|
|
2789
|
+
warnings
|
|
2790
|
+
};
|
|
2791
|
+
}
|
|
2792
|
+
const getStoryboardOneTake = {
|
|
2793
|
+
spec: getStoryboardOneTakeSpec,
|
|
2794
|
+
impl: async (run, params) => {
|
|
2795
|
+
const board = await loadBoard(run, params["storyboard_id"]);
|
|
2796
|
+
if (isError(board))
|
|
2797
|
+
return board;
|
|
2798
|
+
return oneTakeSummary(board.row, board.doc);
|
|
2799
|
+
}
|
|
2800
|
+
};
|
|
2801
|
+
const updateStoryboardOneTake = {
|
|
2802
|
+
spec: updateStoryboardOneTakeSpec,
|
|
2803
|
+
impl: async (run, params) => {
|
|
2804
|
+
const parsed = oneTakeUpdateInput.safeParse({
|
|
2805
|
+
prompt: params["prompt"],
|
|
2806
|
+
duration_seconds: params["duration_seconds"],
|
|
2807
|
+
aspect_ratio: params["aspect_ratio"],
|
|
2808
|
+
resolution: params["resolution"],
|
|
2809
|
+
model: params["model"],
|
|
2810
|
+
shots: params["shots"]
|
|
2811
|
+
});
|
|
2812
|
+
if (!parsed.success) {
|
|
2813
|
+
return {
|
|
2814
|
+
error: parsed.error.issues
|
|
2815
|
+
.map((issue) => `${issue.path.join(".") || "input"}: ${issue.message}`)
|
|
2816
|
+
.join("; ")
|
|
2817
|
+
};
|
|
2818
|
+
}
|
|
2819
|
+
const { prompt, shots: shotPatches } = parsed.data;
|
|
2820
|
+
const settingsGiven = ONE_TAKE_SETTINGS.filter((key) => parsed.data[key] !== undefined);
|
|
2821
|
+
if (prompt === undefined && settingsGiven.length === 0 && !shotPatches) {
|
|
2822
|
+
return {
|
|
2823
|
+
error: "Pass prompt, duration_seconds, aspect_ratio, resolution, model or shots to update."
|
|
2824
|
+
};
|
|
2825
|
+
}
|
|
2826
|
+
const { Storyboard } = await import("@nodetool-ai/models");
|
|
2827
|
+
for (let attempt = 0; attempt < CAS_ATTEMPTS; attempt++) {
|
|
2828
|
+
const board = await loadBoard(run, params["storyboard_id"]);
|
|
2829
|
+
if (isError(board))
|
|
2830
|
+
return board;
|
|
2831
|
+
const { row } = board;
|
|
2832
|
+
const doc = board.doc;
|
|
2833
|
+
if (params["expected_revision"] !== undefined &&
|
|
2834
|
+
params["expected_revision"] !== row.revision) {
|
|
2835
|
+
return {
|
|
2836
|
+
error: "Storyboard revision conflict. Refresh the board before editing."
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
const ops = [];
|
|
2840
|
+
if (prompt !== undefined || settingsGiven.length > 0) {
|
|
2841
|
+
const next = {
|
|
2842
|
+
...doc.one_take,
|
|
2843
|
+
prompt: prompt ?? doc.one_take?.prompt ?? ""
|
|
2844
|
+
};
|
|
2845
|
+
const { duration_seconds, aspect_ratio, resolution, model } = parsed.data;
|
|
2846
|
+
if (duration_seconds !== undefined)
|
|
2847
|
+
next.duration_seconds = duration_seconds;
|
|
2848
|
+
if (aspect_ratio !== undefined)
|
|
2849
|
+
next.aspect_ratio = aspect_ratio;
|
|
2850
|
+
if (resolution !== undefined)
|
|
2851
|
+
next.resolution = resolution;
|
|
2852
|
+
if (model !== undefined) {
|
|
2853
|
+
next.model = model && {
|
|
2854
|
+
...model,
|
|
2855
|
+
provider: model.provider
|
|
2856
|
+
};
|
|
2857
|
+
}
|
|
2858
|
+
// A null clears the setting: store it absent, not null.
|
|
2859
|
+
for (const key of ONE_TAKE_SETTINGS) {
|
|
2860
|
+
if (next[key] === null)
|
|
2861
|
+
delete next[key];
|
|
2862
|
+
}
|
|
2863
|
+
doc.one_take = next;
|
|
2864
|
+
// Field-level, the way set_board is: an open editor takes the
|
|
2865
|
+
// direction whole.
|
|
2866
|
+
ops.push({ tool: "set_board", input: { one_take: doc.one_take } });
|
|
2867
|
+
}
|
|
2868
|
+
for (const patch of shotPatches ?? []) {
|
|
2869
|
+
const shot = findShot(doc.shots, patch.shot_id);
|
|
2870
|
+
if (!shot) {
|
|
2871
|
+
return {
|
|
2872
|
+
error: `No shot matches "${patch.shot_id}". Call get_storyboard for shot ids.`
|
|
2873
|
+
};
|
|
2874
|
+
}
|
|
2875
|
+
const next = { ...shot };
|
|
2876
|
+
for (const field of ["end_state", "sound"]) {
|
|
2877
|
+
const value = patch[field];
|
|
2878
|
+
if (value === undefined)
|
|
2879
|
+
continue;
|
|
2880
|
+
if (value === null || value.trim() === "") {
|
|
2881
|
+
delete next[field];
|
|
2882
|
+
}
|
|
2883
|
+
else {
|
|
2884
|
+
next[field] = value;
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
doc.shots = doc.shots.map((s) => (s.id === shot.id ? next : s));
|
|
2888
|
+
ops.push({
|
|
2889
|
+
tool: "update_shot",
|
|
2890
|
+
input: { id: shot.id, target: shot.id }
|
|
2891
|
+
});
|
|
2892
|
+
}
|
|
2893
|
+
if (doc.screenplay)
|
|
2894
|
+
doc.screenplay.shots = doc.shots;
|
|
2895
|
+
const saved = await Storyboard.updateFieldsIfUnchanged(row.id, row.updated_at, { document: JSON.stringify(doc) }, { ops });
|
|
2896
|
+
if (!saved)
|
|
2897
|
+
continue;
|
|
2898
|
+
return oneTakeSummary(saved, doc);
|
|
2899
|
+
}
|
|
2900
|
+
return {
|
|
2901
|
+
error: `Storyboard ${String(params["storyboard_id"])} is being modified concurrently; nothing was saved. Retry the call.`
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
};
|
|
2446
2905
|
export const STORYBOARD_CAPABILITIES = [
|
|
2447
2906
|
finishStoryboard,
|
|
2448
2907
|
layoutStoryboard,
|
|
@@ -2454,14 +2913,17 @@ export const STORYBOARD_CAPABILITIES = [
|
|
|
2454
2913
|
renderStoryboardClips,
|
|
2455
2914
|
reviseStoryboardClip,
|
|
2456
2915
|
assembleStoryboardTimeline,
|
|
2916
|
+
deriveShotFromClip,
|
|
2457
2917
|
editStoryboard,
|
|
2458
2918
|
directStoryboard,
|
|
2459
2919
|
extractScriptFromStoryboard,
|
|
2460
|
-
deleteStoryboard
|
|
2920
|
+
deleteStoryboard,
|
|
2921
|
+
getStoryboardOneTake,
|
|
2922
|
+
updateStoryboardOneTake
|
|
2461
2923
|
];
|
|
2462
2924
|
export const module = {
|
|
2463
2925
|
module: "storyboards",
|
|
2464
2926
|
exports: STORYBOARD_CAPABILITIES
|
|
2465
2927
|
};
|
|
2466
|
-
export { finishStoryboard, layoutStoryboard, previewStoryboardDesign, listStoryboards, createStoryboard, getStoryboard, renderStoryboardStills, renderStoryboardClips, reviseStoryboardClip, assembleStoryboardTimeline, editStoryboard, directStoryboard, extractScriptFromStoryboard, deleteStoryboard };
|
|
2928
|
+
export { finishStoryboard, layoutStoryboard, previewStoryboardDesign, listStoryboards, createStoryboard, getStoryboard, renderStoryboardStills, renderStoryboardClips, reviseStoryboardClip, assembleStoryboardTimeline, deriveShotFromClip, editStoryboard, directStoryboard, extractScriptFromStoryboard, deleteStoryboard, getStoryboardOneTake, updateStoryboardOneTake };
|
|
2467
2929
|
//# sourceMappingURL=storyboards.js.map
|