@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.
Files changed (189) hide show
  1. package/dist/.nodetool-build-stamp +1 -1
  2. package/dist/apify/assets.d.ts.map +1 -1
  3. package/dist/apify/assets.js +4 -0
  4. package/dist/apify/assets.js.map +1 -1
  5. package/dist/capabilities/agent-activity.js +1 -1
  6. package/dist/capabilities/assets.d.ts.map +1 -1
  7. package/dist/capabilities/assets.js +40 -10
  8. package/dist/capabilities/assets.js.map +1 -1
  9. package/dist/capabilities/collections.d.ts +4 -6
  10. package/dist/capabilities/collections.d.ts.map +1 -1
  11. package/dist/capabilities/collections.js +16 -11
  12. package/dist/capabilities/collections.js.map +1 -1
  13. package/dist/capabilities/derive-shot.d.ts +45 -0
  14. package/dist/capabilities/derive-shot.d.ts.map +1 -0
  15. package/dist/capabilities/derive-shot.js +82 -0
  16. package/dist/capabilities/derive-shot.js.map +1 -0
  17. package/dist/capabilities/documents.d.ts +2 -1
  18. package/dist/capabilities/documents.d.ts.map +1 -1
  19. package/dist/capabilities/documents.js +12 -6
  20. package/dist/capabilities/documents.js.map +1 -1
  21. package/dist/capabilities/email.d.ts +2 -1
  22. package/dist/capabilities/email.d.ts.map +1 -1
  23. package/dist/capabilities/email.js +5 -3
  24. package/dist/capabilities/email.js.map +1 -1
  25. package/dist/capabilities/game-asset-browser.d.ts +11 -0
  26. package/dist/capabilities/game-asset-browser.d.ts.map +1 -0
  27. package/dist/capabilities/game-asset-browser.js +152 -0
  28. package/dist/capabilities/game-asset-browser.js.map +1 -0
  29. package/dist/capabilities/game.d.ts +30 -0
  30. package/dist/capabilities/game.d.ts.map +1 -1
  31. package/dist/capabilities/game.js +215 -137
  32. package/dist/capabilities/game.js.map +1 -1
  33. package/dist/capabilities/game.specs.d.ts +2 -0
  34. package/dist/capabilities/game.specs.d.ts.map +1 -1
  35. package/dist/capabilities/game.specs.js +20 -5
  36. package/dist/capabilities/game.specs.js.map +1 -1
  37. package/dist/capabilities/game3d.d.ts.map +1 -1
  38. package/dist/capabilities/game3d.js +4 -3
  39. package/dist/capabilities/game3d.js.map +1 -1
  40. package/dist/capabilities/generations.d.ts.map +1 -1
  41. package/dist/capabilities/generations.js +7 -21
  42. package/dist/capabilities/generations.js.map +1 -1
  43. package/dist/capabilities/lazy-tool-core.d.ts +23 -0
  44. package/dist/capabilities/lazy-tool-core.d.ts.map +1 -0
  45. package/dist/capabilities/lazy-tool-core.js +56 -0
  46. package/dist/capabilities/lazy-tool-core.js.map +1 -0
  47. package/dist/capabilities/lazy-tool.d.ts +2 -21
  48. package/dist/capabilities/lazy-tool.d.ts.map +1 -1
  49. package/dist/capabilities/lazy-tool.js +3 -55
  50. package/dist/capabilities/lazy-tool.js.map +1 -1
  51. package/dist/capabilities/legacy-tools.js +1 -1
  52. package/dist/capabilities/legacy-tools.js.map +1 -1
  53. package/dist/capabilities/media.d.ts.map +1 -1
  54. package/dist/capabilities/media.js +13 -1
  55. package/dist/capabilities/media.js.map +1 -1
  56. package/dist/capabilities/media.specs.d.ts.map +1 -1
  57. package/dist/capabilities/media.specs.js +17 -0
  58. package/dist/capabilities/media.specs.js.map +1 -1
  59. package/dist/capabilities/metadata.d.ts +62 -0
  60. package/dist/capabilities/metadata.d.ts.map +1 -0
  61. package/dist/capabilities/metadata.js +114 -0
  62. package/dist/capabilities/metadata.js.map +1 -0
  63. package/dist/capabilities/model3d.d.ts.map +1 -1
  64. package/dist/capabilities/model3d.js +4 -0
  65. package/dist/capabilities/model3d.js.map +1 -1
  66. package/dist/capabilities/registry.d.ts +4 -19
  67. package/dist/capabilities/registry.d.ts.map +1 -1
  68. package/dist/capabilities/registry.js +48 -117
  69. package/dist/capabilities/registry.js.map +1 -1
  70. package/dist/capabilities/run-agent.js +1 -1
  71. package/dist/capabilities/settings.d.ts.map +1 -1
  72. package/dist/capabilities/settings.js +4 -2
  73. package/dist/capabilities/settings.js.map +1 -1
  74. package/dist/capabilities/storyboards.d.ts +11 -1
  75. package/dist/capabilities/storyboards.d.ts.map +1 -1
  76. package/dist/capabilities/storyboards.js +466 -4
  77. package/dist/capabilities/storyboards.js.map +1 -1
  78. package/dist/capabilities/storyboards.specs.d.ts +6 -0
  79. package/dist/capabilities/storyboards.specs.d.ts.map +1 -1
  80. package/dist/capabilities/storyboards.specs.js +131 -2
  81. package/dist/capabilities/storyboards.specs.js.map +1 -1
  82. package/dist/capabilities/threads.js +1 -1
  83. package/dist/capabilities/threads.js.map +1 -1
  84. package/dist/capabilities/timeline-bridge.d.ts +9 -0
  85. package/dist/capabilities/timeline-bridge.d.ts.map +1 -1
  86. package/dist/capabilities/timeline-bridge.js +60 -68
  87. package/dist/capabilities/timeline-bridge.js.map +1 -1
  88. package/dist/capabilities/timeline-operations.d.ts +52 -0
  89. package/dist/capabilities/timeline-operations.d.ts.map +1 -0
  90. package/dist/capabilities/timeline-operations.js +413 -0
  91. package/dist/capabilities/timeline-operations.js.map +1 -0
  92. package/dist/capabilities/timelines.d.ts +3 -38
  93. package/dist/capabilities/timelines.d.ts.map +1 -1
  94. package/dist/capabilities/timelines.js +30 -413
  95. package/dist/capabilities/timelines.js.map +1 -1
  96. package/dist/capabilities/timelines.specs.d.ts.map +1 -1
  97. package/dist/capabilities/timelines.specs.js +5 -1
  98. package/dist/capabilities/timelines.specs.js.map +1 -1
  99. package/dist/capabilities/web.d.ts.map +1 -1
  100. package/dist/capabilities/web.js +4 -0
  101. package/dist/capabilities/web.js.map +1 -1
  102. package/dist/capabilities/workflows.d.ts +3 -1
  103. package/dist/capabilities/workflows.d.ts.map +1 -1
  104. package/dist/capabilities/workflows.js +192 -14
  105. package/dist/capabilities/workflows.js.map +1 -1
  106. package/dist/capabilities/workflows.specs.d.ts +2 -0
  107. package/dist/capabilities/workflows.specs.d.ts.map +1 -1
  108. package/dist/capabilities/workflows.specs.js +65 -1
  109. package/dist/capabilities/workflows.specs.js.map +1 -1
  110. package/dist/codeact/sandbox-packages.d.ts +0 -7
  111. package/dist/codeact/sandbox-packages.d.ts.map +1 -1
  112. package/dist/codeact/sandbox-packages.js +1 -10
  113. package/dist/codeact/sandbox-packages.js.map +1 -1
  114. package/dist/evals/surfaces/game.d.ts +8 -2
  115. package/dist/evals/surfaces/game.d.ts.map +1 -1
  116. package/dist/evals/surfaces/game.js +460 -2
  117. package/dist/evals/surfaces/game.js.map +1 -1
  118. package/dist/game-authoring.d.ts +4895 -59
  119. package/dist/game-authoring.d.ts.map +1 -1
  120. package/dist/game-build.d.ts +3 -0
  121. package/dist/game-build.d.ts.map +1 -0
  122. package/dist/game-build.js +3 -0
  123. package/dist/game-build.js.map +1 -0
  124. package/dist/game-examples.d.ts +1355 -2
  125. package/dist/game-examples.d.ts.map +1 -1
  126. package/dist/generation-cancel.d.ts +31 -0
  127. package/dist/generation-cancel.d.ts.map +1 -0
  128. package/dist/generation-cancel.js +28 -0
  129. package/dist/generation-cancel.js.map +1 -0
  130. package/dist/host-access-gate.d.ts +29 -0
  131. package/dist/host-access-gate.d.ts.map +1 -0
  132. package/dist/host-access-gate.js +39 -0
  133. package/dist/host-access-gate.js.map +1 -0
  134. package/dist/host-modules/dispatcher.d.ts +7 -1
  135. package/dist/host-modules/dispatcher.d.ts.map +1 -1
  136. package/dist/host-modules/dispatcher.js +13 -2
  137. package/dist/host-modules/dispatcher.js.map +1 -1
  138. package/dist/host-modules/docx.d.ts.map +1 -1
  139. package/dist/host-modules/docx.js +2 -2
  140. package/dist/host-modules/docx.js.map +1 -1
  141. package/dist/host-modules/epub.d.ts.map +1 -1
  142. package/dist/host-modules/epub.js +2 -2
  143. package/dist/host-modules/epub.js.map +1 -1
  144. package/dist/host-modules/fabric.d.ts.map +1 -1
  145. package/dist/host-modules/fabric.js +1 -1
  146. package/dist/host-modules/fabric.js.map +1 -1
  147. package/dist/host-modules/limits.d.ts +10 -8
  148. package/dist/host-modules/limits.d.ts.map +1 -1
  149. package/dist/host-modules/limits.js +14 -9
  150. package/dist/host-modules/limits.js.map +1 -1
  151. package/dist/host-modules/mammoth.d.ts.map +1 -1
  152. package/dist/host-modules/mammoth.js +2 -2
  153. package/dist/host-modules/mammoth.js.map +1 -1
  154. package/dist/host-modules/ocr.d.ts.map +1 -1
  155. package/dist/host-modules/ocr.js +1 -1
  156. package/dist/host-modules/ocr.js.map +1 -1
  157. package/dist/host-modules/pdf.d.ts.map +1 -1
  158. package/dist/host-modules/pdf.js +2 -2
  159. package/dist/host-modules/pdf.js.map +1 -1
  160. package/dist/host-modules/pdflib.d.ts.map +1 -1
  161. package/dist/host-modules/pdflib.js +2 -2
  162. package/dist/host-modules/pdflib.js.map +1 -1
  163. package/dist/host-modules/pptx.d.ts.map +1 -1
  164. package/dist/host-modules/pptx.js +2 -2
  165. package/dist/host-modules/pptx.js.map +1 -1
  166. package/dist/host-modules/pptxgen.d.ts.map +1 -1
  167. package/dist/host-modules/pptxgen.js +2 -2
  168. package/dist/host-modules/pptxgen.js.map +1 -1
  169. package/dist/host-modules/tfjs.d.ts.map +1 -1
  170. package/dist/host-modules/tfjs.js +4 -4
  171. package/dist/host-modules/tfjs.js.map +1 -1
  172. package/dist/host-modules/xlsx.d.ts.map +1 -1
  173. package/dist/host-modules/xlsx.js +2 -2
  174. package/dist/host-modules/xlsx.js.map +1 -1
  175. package/dist/index.d.ts +3 -0
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +4 -0
  178. package/dist/index.js.map +1 -1
  179. package/dist/js-sandbox.d.ts +7 -1
  180. package/dist/js-sandbox.d.ts.map +1 -1
  181. package/dist/js-sandbox.js +20 -4
  182. package/dist/js-sandbox.js.map +1 -1
  183. package/dist/timeline-code-bake.js +2 -2
  184. package/dist/timeline-code-bake.js.map +1 -1
  185. package/dist/tools/builtin-tools.d.ts +4 -3
  186. package/dist/tools/builtin-tools.d.ts.map +1 -1
  187. package/dist/tools/builtin-tools.js +11 -3
  188. package/dist/tools/builtin-tools.js.map +1 -1
  189. 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