@nodetool-ai/agents 0.8.4-a24.3 → 0.8.4

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 (135) hide show
  1. package/dist/.nodetool-build-stamp +1 -1
  2. package/dist/_skills/LICENSE-iart-motion-design-skills +21 -0
  3. package/dist/_skills/README.md +211 -0
  4. package/dist/_skills/api-agents/SKILL.md +58 -0
  5. package/dist/_skills/api-apps/SKILL.md +54 -0
  6. package/dist/_skills/api-assets/SKILL.md +66 -0
  7. package/dist/_skills/api-collections/SKILL.md +33 -0
  8. package/dist/_skills/api-games/SKILL.md +81 -0
  9. package/dist/_skills/api-media/SKILL.md +131 -0
  10. package/dist/_skills/api-memory/SKILL.md +72 -0
  11. package/dist/_skills/api-models/SKILL.md +78 -0
  12. package/dist/_skills/api-scripts/SKILL.md +79 -0
  13. package/dist/_skills/api-settings/SKILL.md +49 -0
  14. package/dist/_skills/api-sketches/SKILL.md +61 -0
  15. package/dist/_skills/api-storyboards/SKILL.md +94 -0
  16. package/dist/_skills/api-timelines/SKILL.md +151 -0
  17. package/dist/_skills/api-web/SKILL.md +57 -0
  18. package/dist/_skills/api-workflows/SKILL.md +123 -0
  19. package/dist/_skills/beat-sync-editing/SKILL.md +208 -0
  20. package/dist/_skills/caption-titles/SKILL.md +94 -0
  21. package/dist/_skills/color-motion/SKILL.md +185 -0
  22. package/dist/_skills/commercial-beat-sheet/SKILL.md +338 -0
  23. package/dist/_skills/elevenlabs-audio-prompting/SKILL.md +163 -0
  24. package/dist/_skills/explainer-storyboard/SKILL.md +63 -0
  25. package/dist/_skills/flux-2-klein-prompting/SKILL.md +107 -0
  26. package/dist/_skills/frame-composition/SKILL.md +291 -0
  27. package/dist/_skills/game-direction/SKILL.md +99 -0
  28. package/dist/_skills/gpt-image-2-prompting/SKILL.md +161 -0
  29. package/dist/_skills/hailuo-prompting/SKILL.md +107 -0
  30. package/dist/_skills/kling-video-prompting/SKILL.md +188 -0
  31. package/dist/_skills/launch-commercial/SKILL.md +267 -0
  32. package/dist/_skills/launch-kit/SKILL.md +120 -0
  33. package/dist/_skills/logo-reveal/SKILL.md +225 -0
  34. package/dist/_skills/manimgx/SKILL.md +123 -0
  35. package/dist/_skills/minimax-h3-prompting/SKILL.md +134 -0
  36. package/dist/_skills/motion-ad/SKILL.md +281 -0
  37. package/dist/_skills/motion-background/SKILL.md +145 -0
  38. package/dist/_skills/motion-curves/SKILL.md +302 -0
  39. package/dist/_skills/motion-direction/SKILL.md +259 -0
  40. package/dist/_skills/motion-graphics/SKILL.md +217 -0
  41. package/dist/_skills/motion-principles/SKILL.md +255 -0
  42. package/dist/_skills/music-video-treatment/SKILL.md +40 -0
  43. package/dist/_skills/nano-banana-pro-prompting/SKILL.md +133 -0
  44. package/dist/_skills/native-game/SKILL.md +310 -0
  45. package/dist/_skills/native-game-reference/SKILL.md +879 -0
  46. package/dist/_skills/nodetool-3d-scene/SKILL.md +110 -0
  47. package/dist/_skills/nodetool-api-reference/SKILL.md +338 -0
  48. package/dist/_skills/nodetool-app-builder/SKILL.md +291 -0
  49. package/dist/_skills/nodetool-browser-agent/SKILL.md +119 -0
  50. package/dist/_skills/nodetool-chat-cli/SKILL.md +184 -0
  51. package/dist/_skills/nodetool-custom-node-developer/SKILL.md +294 -0
  52. package/dist/_skills/nodetool-deployment/SKILL.md +195 -0
  53. package/dist/_skills/nodetool-js-scripting/SKILL.md +223 -0
  54. package/dist/_skills/nodetool-model-provider-config/SKILL.md +348 -0
  55. package/dist/_skills/nodetool-rag-indexing/SKILL.md +153 -0
  56. package/dist/_skills/nodetool-sketch/SKILL.md +138 -0
  57. package/dist/_skills/nodetool-skill-author/SKILL.md +125 -0
  58. package/dist/_skills/nodetool-troubleshooter/SKILL.md +370 -0
  59. package/dist/_skills/nodetool-video-post/SKILL.md +149 -0
  60. package/dist/_skills/nodetool-workflow-builder/SKILL.md +295 -0
  61. package/dist/_skills/product-commercial/SKILL.md +132 -0
  62. package/dist/_skills/qwen-image-prompting/SKILL.md +122 -0
  63. package/dist/_skills/script-video/SKILL.md +106 -0
  64. package/dist/_skills/seedance-2-prompting/SKILL.md +194 -0
  65. package/dist/_skills/seedream-prompting/SKILL.md +117 -0
  66. package/dist/_skills/short-film/SKILL.md +123 -0
  67. package/dist/_skills/stable-audio-prompting/SKILL.md +130 -0
  68. package/dist/_skills/storyboard-core/SKILL.md +716 -0
  69. package/dist/_skills/timeline-edit-ops/SKILL.md +736 -0
  70. package/dist/_skills/trailer-template/SKILL.md +291 -0
  71. package/dist/_skills/ugc-video/SKILL.md +186 -0
  72. package/dist/_skills/veo-3-prompting/SKILL.md +140 -0
  73. package/dist/_skills/video-audio-continuity/SKILL.md +90 -0
  74. package/dist/_skills/video-clone/SKILL.md +96 -0
  75. package/dist/_skills/video-workflow/SKILL.md +119 -0
  76. package/dist/_skills/wan-2-6-prompting/SKILL.md +107 -0
  77. package/dist/app-build/bridge.d.ts.map +1 -1
  78. package/dist/app-build/bridge.js +44 -17
  79. package/dist/app-build/bridge.js.map +1 -1
  80. package/dist/capabilities/apps.d.ts.map +1 -1
  81. package/dist/capabilities/apps.js +55 -13
  82. package/dist/capabilities/apps.js.map +1 -1
  83. package/dist/capabilities/apps.specs.d.ts.map +1 -1
  84. package/dist/capabilities/apps.specs.js +5 -3
  85. package/dist/capabilities/apps.specs.js.map +1 -1
  86. package/dist/capabilities/game-asset-browser.d.ts.map +1 -1
  87. package/dist/capabilities/game-asset-browser.js +6 -1
  88. package/dist/capabilities/game-asset-browser.js.map +1 -1
  89. package/dist/capabilities/game.d.ts +1 -1
  90. package/dist/capabilities/game.d.ts.map +1 -1
  91. package/dist/capabilities/game.js +71 -56
  92. package/dist/capabilities/game.js.map +1 -1
  93. package/dist/capabilities/game.specs.js +1 -1
  94. package/dist/capabilities/game.specs.js.map +1 -1
  95. package/dist/capabilities/game3d.d.ts.map +1 -1
  96. package/dist/capabilities/game3d.js +14 -19
  97. package/dist/capabilities/game3d.js.map +1 -1
  98. package/dist/capabilities/gameAssertions.d.ts +52 -0
  99. package/dist/capabilities/gameAssertions.d.ts.map +1 -0
  100. package/dist/capabilities/gameAssertions.js +32 -0
  101. package/dist/capabilities/gameAssertions.js.map +1 -0
  102. package/dist/capabilities/models.d.ts.map +1 -1
  103. package/dist/capabilities/models.js +9 -0
  104. package/dist/capabilities/models.js.map +1 -1
  105. package/dist/capabilities/storyboards.d.ts.map +1 -1
  106. package/dist/capabilities/storyboards.js +36 -11
  107. package/dist/capabilities/storyboards.js.map +1 -1
  108. package/dist/capabilities/storyboards.specs.d.ts.map +1 -1
  109. package/dist/capabilities/storyboards.specs.js +11 -1
  110. package/dist/capabilities/storyboards.specs.js.map +1 -1
  111. package/dist/capabilities/workflows.d.ts.map +1 -1
  112. package/dist/capabilities/workflows.js +1 -0
  113. package/dist/capabilities/workflows.js.map +1 -1
  114. package/dist/capabilities/workflows.specs.d.ts.map +1 -1
  115. package/dist/capabilities/workflows.specs.js +4 -3
  116. package/dist/capabilities/workflows.specs.js.map +1 -1
  117. package/dist/evals/surfaces/game.d.ts.map +1 -1
  118. package/dist/evals/surfaces/game.js +29 -1
  119. package/dist/evals/surfaces/game.js.map +1 -1
  120. package/dist/game-authoring.d.ts +120 -0
  121. package/dist/game-authoring.d.ts.map +1 -1
  122. package/dist/game-build-integrity.d.ts +12 -0
  123. package/dist/game-build-integrity.d.ts.map +1 -0
  124. package/dist/game-build-integrity.js +78 -0
  125. package/dist/game-build-integrity.js.map +1 -0
  126. package/dist/game-examples.d.ts +44 -3
  127. package/dist/game-examples.d.ts.map +1 -1
  128. package/dist/game-examples.js +60 -10
  129. package/dist/game-examples.js.map +1 -1
  130. package/dist/system-skills.d.ts +1 -1
  131. package/dist/system-skills.js +1 -1
  132. package/dist/tools/builtin-tools.d.ts.map +1 -1
  133. package/dist/tools/builtin-tools.js +2 -0
  134. package/dist/tools/builtin-tools.js.map +1 -1
  135. package/package.json +19 -19
@@ -0,0 +1,131 @@
1
+ ---
2
+ name: api-media
3
+ description: "Call nodetool.media or nodetool.generations from a code action: generate or edit images, video, speech and music with a picked model, transcribe and embed, judge images with a vision model, read a video, run ffmpeg or ffprobe, download a video, and read the status and cost of a generation. Load before the first call into these namespaces."
4
+ ---
5
+
6
+ # nodetool.media and nodetool.generations
7
+
8
+ `nodetool.media` makes one result with one picked model and saves it as an
9
+ asset. No workflow is needed. `nodetool.generations` is the record of every
10
+ media generation: status, cost, and the assets it made. The model comes from
11
+ `nodetool.models.pick` (see `api-models`). How to word a prompt for one model
12
+ line is the `*-prompting` skill that `find_model` names in `prompting_skill`.
13
+
14
+ ## Generation calls
15
+
16
+ Each call takes `model` as a `pick`/`find` result, `{provider, model_id}`, or
17
+ a `"provider/model_id"` string.
18
+
19
+ | Call | Options | Capability to pick |
20
+ | :--- | :--- | :--- |
21
+ | `generateImage(prompt, model, opts)` | `width`, `height`, `quality`, `negative_prompt`, `output_file`, `background` | `text_to_image` |
22
+ | `editImage(inputFile, prompt, model, opts)` | `reference_files`, `strength`, `target_width`, `target_height`, `negative_prompt`, `output_file`, `background` | `image_to_image` |
23
+ | `generateVideo(prompt, model, opts)` | `duration_seconds`, `aspect_ratio`, `resolution`, `num_frames`, `negative_prompt`, `output_file`, `background` | `text_to_video` |
24
+ | `animateImage(inputFile, model, opts)` | `prompt`, `duration_seconds`, `aspect_ratio`, `resolution`, `num_frames`, `output_file`, `background` | `image_to_video` |
25
+ | `videoFromReferences(referenceFiles, model, opts)` | `prompt`, `use_reference_video_audio`, `negative_prompt`, `num_frames`, `duration_seconds`, `aspect_ratio`, `resolution`, `output_file`, `background` | `reference_to_video` |
26
+ | `speak(text, model, opts)` | `voice`, `speed`, `output_file`, `background` | `text_to_speech` |
27
+ | `generateMusic(prompt, model, opts)` | `lyrics`, `duration_seconds`, `output_file`, `background` | `text_to_music` |
28
+ | `transcribe(inputFile, model, opts)` | `language`, `prompt` | `automatic_speech_recognition` |
29
+ | `embed(text, model, opts)` | `dimensions`. `text` is a string or an array. | `generate_embedding` |
30
+
31
+ A generation answers with `asset_id`, `asset_uri` (`asset://…`),
32
+ `generation_id`, `mime_type` and `bytes`, plus `path` when you passed
33
+ `output_file`. An input file (`inputFile`, `reference_files`) is an
34
+ `asset://` URI or a workspace path.
35
+
36
+ - `editImage` is the call for "make it like this". Pass the attached image or
37
+ an approved earlier result as `inputFile`, and further images to match in
38
+ `reference_files`.
39
+ - `videoFromReferences` is for a shot that more than one reference defines: a
40
+ character plus a garment, a product plus a location. The prompt then says
41
+ the action and the camera, not the subjects.
42
+ - Models honour `duration_seconds` loosely. Measure the result with
43
+ `ffprobe` before you cut to it.
44
+ - To put words on a picture, draw them yourself with `createCanvas` and
45
+ `fillText`, or with `renderText` from
46
+ `@nodetool-ai/sandbox-flow/lib.image.draw`.
47
+
48
+ ### Background generations
49
+
50
+ `background` is the async flag on every generation call, not a transparent
51
+ background. `background: true` returns at once with
52
+ `{generation_id, status: "running", background: true}`. Collect the result
53
+ with `nodetool.generations.wait(receipt)`. A run can have 16 open at most.
54
+ Each one is billed, so confirm the count and the cost with the user before
55
+ you fan out paid video. Start several, then wait for all of them in the same
56
+ action:
57
+
58
+ ```js
59
+ const model = await nodetool.models.pick("text_to_video");
60
+ const receipts = await Promise.all(prompts.map((p) =>
61
+ nodetool.media.generateVideo(p, model, { background: true })));
62
+ const done = await Promise.all(receipts.map((r) =>
63
+ nodetool.generations.wait(r, { timeout_seconds: 480 })));
64
+ ```
65
+
66
+ A code action stops after 600 s. Keep each wait under that budget. A wait
67
+ that times out answers the current record, so wait again in the next action
68
+ for any that are still `running`.
69
+
70
+ ## Handles and saving
71
+
72
+ `image.*`, `audio.*` and `video.*` (guest globals, no `nodetool.` prefix) take
73
+ a generation result, its `asset_uri` or an asset id, and answer run-local
74
+ handles. `video.addAudio(videoHandle, audioHandle)` combines media, for
75
+ example. Save a finished handle with `nodetool.media.toImage(handle)`,
76
+ `toAudio(handle)` or `toVideo(handle)` before the action ends. A handle is dead
77
+ in the next action. Do not pull bytes into the guest.
78
+
79
+ Hold each result in a local variable and feed it straight into the next call.
80
+ Record the uris a later action or turn will need with `nodetool.memory.save`,
81
+ and never re-run generation for something already saved.
82
+
83
+ ## Judging
84
+
85
+ The judge is a chat model that reads images (`pick("generate_message")` on a
86
+ vision model), not the model that made the picture.
87
+
88
+ | Call | Answers |
89
+ | :--- | :--- |
90
+ | `critique(image, brief, visionModel, {taste_profile})` | A pass/revise verdict and concrete defects with locations and fixes. Feed the fixes into the next prompt. When it names no defect, make fresh variations. |
91
+ | `compare(images, brief, visionModel, {taste_profile})` | The winner of 2–8 candidates by a pairwise knockout, each match judged twice with the order swapped, plus every verdict |
92
+ | `scoreAdherence(image, brief, visionModel, {questions})` | Yes/no answers to up to 12 checks made from the brief, and the fraction that passed |
93
+ | `understandVideo(video, prompt, videoModel, {max_tokens})` | `{text, truncated}`. Gemini reads the whole clip with audio. Other models get still frames with no audio. A `truncated` answer is half an answer: raise `max_tokens` or use a model that does not reason. |
94
+
95
+ ## Host binaries
96
+
97
+ | Call | Does |
98
+ | :--- | :--- |
99
+ | `ffmpeg(args, {inputs, output_file, timeout_seconds})` | Runs ffmpeg in the workspace with no shell. `args` is the argv after the binary. Paths are workspace-relative, and URLs are refused. `inputs` stages assets first as `{"a.mp4": "asset://…"}` (8 files at most). `output_file` is saved as an asset. The default timeout is 180 s, the maximum 600 s. |
100
+ | `ffprobe(path, {inputs, timeout_seconds})` | Reads the format and streams. `path` may be an `asset://` URI. The answer has a `summary` with `duration_seconds`, `width`, `height` and `has_audio` as real numbers and booleans. The default timeout is 30 s, the maximum 120 s. |
101
+ | `downloadVideo(url, outputFile, {format, timeout_seconds})` | Downloads a public video with yt-dlp, up to 2 GiB. The default timeout is 300 s. |
102
+
103
+ ```js
104
+ // Concatenate two assets in one call.
105
+ await nodetool.media.ffmpeg(
106
+ ["-i", "a.mp4", "-i", "b.mp4", "-filter_complex",
107
+ "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]", "-map", "[v]", "-map", "[a]",
108
+ "out.mp4"],
109
+ { inputs: { "a.mp4": uriA, "b.mp4": uriB }, output_file: "out.mp4" }
110
+ );
111
+ ```
112
+
113
+ ## nodetool.generations
114
+
115
+ Every generation result carries `generation_id`. Read the cost with `get`
116
+ instead of guessing it.
117
+
118
+ | Call | Answers |
119
+ | :--- | :--- |
120
+ | `list({status, provider, capability, thread_id, job_id, since, limit, start_key})` | Generations, newest first, with status, cost, errors and assets |
121
+ | `get(idOrResult)` | One generation in full: request parameters, cost and how it was priced, the provider request id, the assets |
122
+ | `wait(idOrResult, {timeout_seconds})` | Waits for a background generation. The default is 300 s. A timeout answers the current record; call again to keep waiting. |
123
+ | `cancel(idOrResult)` | Stops a running generation. It answers `cancelled: false` when the generation already settled. |
124
+ | `reconcile(idOrResult)` | Asks the provider what it billed and replaces the estimate |
125
+ | `fromProvider(provider, {model, status, since, until, limit, cursor})` | The provider's own history, from any machine. `fal_ai` answers. |
126
+ | `getFromProvider(provider, requestId, {model})` | One provider-side generation, with the output urls it still hosts. This recovers a lost asset. |
127
+
128
+ Statuses are `pending`, `running`, `recovering`, `completed`, `failed`,
129
+ `cancelled`, `needs_attention` and `interrupted`. `completed` means the
130
+ output is durable. A failed, cancelled or interrupted generation can still be
131
+ billed.
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: api-memory
3
+ description: "Call nodetool.memory, nodetool.shared or nodetool.threads from a code action: save and recall durable notes and resources across conversations, pass results between steps and sub-agents in one run, and read past chat threads. Load before the first call into these namespaces."
4
+ ---
5
+
6
+ # nodetool.memory, nodetool.shared, nodetool.threads
7
+
8
+ Nothing carries over between code actions except what a tool saved. These
9
+ three namespaces are where state lives, at three lifetimes:
10
+
11
+ | Namespace | Lifetime | Use it for |
12
+ | :--- | :--- | :--- |
13
+ | `nodetool.memory` | Every conversation, until deleted | Facts, decisions, preferences, and the assets and documents you made |
14
+ | `nodetool.shared` | This run only | Handing results between steps, tasks and sub-agents |
15
+ | `nodetool.threads` | Read-only chat history | "What did we decide last time?" |
16
+
17
+ ## nodetool.memory
18
+
19
+ | Call | Does |
20
+ | :--- | :--- |
21
+ | `save(content, {title, kind, resources})` | Saves a note. |
22
+ | `search(query, {limit, thread, kinds})` | Finds notes by keyword. Every word must appear in the title or the content, so fewer words find more. `limit` defaults to 25. |
23
+ | `list({limit, thread, kinds})` | Lists notes, newest first. `limit` defaults to 100, max 200. |
24
+ | `update(memoryId, {content, title, kind, resources})` | Changes the fields you pass. `resources` replaces the list. |
25
+ | `remove(memoryId)` | Deletes one note. |
26
+
27
+ - `kind` is `note` (default), `fact`, `preference`, `decision` or `resource`.
28
+ - `thread` is `"all"` (default) or `"current"`.
29
+ - `resources` is a list of `{type, id, uri?, label?}`. `type` is `asset`,
30
+ `workflow`, `collection`, `node`, `job`, `timeline`, `script`, `storyboard`,
31
+ `image_document`, `thread`, `url` or `other`. Asset references are checked
32
+ and come back with a live `asset://` uri.
33
+ - The notes of the current conversation are shown to you at the start of each
34
+ turn. Search for the rest.
35
+
36
+ Record what you make in the same action that makes it:
37
+
38
+ ```js
39
+ const shot = await nodetool.media.generateImage(prompt, model);
40
+ await nodetool.memory.save("Hero still for the launch film", {
41
+ title: "Hero still",
42
+ kind: "resource",
43
+ resources: [{ type: "asset", id: shot.asset_id }]
44
+ });
45
+ ```
46
+
47
+ Before you generate, search memory for a result that already exists. Never
48
+ generate again what a note already records.
49
+
50
+ ## nodetool.shared
51
+
52
+ The scratchpad of this run. It is gone when the run ends.
53
+
54
+ | Call | Does |
55
+ | :--- | :--- |
56
+ | `list({kind, key_prefix, sources})` | Metadata only: keys, titles, kinds, sizes. `kind` filters to `task_result`, `step_result`, `input` or `shared`. |
57
+ | `read(keys)` | Full values for the keys you name. Misses come back in `missing`. A key with no `<namespace>:` prefix is also looked up under `shared:`. |
58
+ | `publish(key, value, {title, description})` | Stores any JSON value under `shared:<key>`. |
59
+
60
+ The results of earlier steps and tasks land here. Read them instead of asking
61
+ for them again. List first, then read only the keys you need.
62
+
63
+ ## nodetool.threads
64
+
65
+ | Call | Does |
66
+ | :--- | :--- |
67
+ | `list({limit, workflow_id, cursor, preview})` | Past conversations, newest first, each with its last message unless `preview: false`. `limit` defaults to 20. |
68
+ | `get(threadId, {limit, newest_first, cursor, max_chars})` | A page of messages, oldest first. Text is cut at `max_chars` (default 2000, `0` for no cut). |
69
+ | `last(threadId)` | The newest message, or `undefined` |
70
+ | `message(messageId)` | One message in full: every tool call with its arguments, files, cost |
71
+
72
+ Page with the `next` cursor of the previous answer.
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: api-models
3
+ description: "Call nodetool.models from a code action: pick the best configured model for a capability, search for a model the user named, browse a provider's catalog, set a node's model property, or make one language-model call. Load before the first call into nodetool.models."
4
+ ---
5
+
6
+ # nodetool.models
7
+
8
+ Model discovery for this install. It knows which providers have credentials
9
+ and which local models are downloaded. Never guess a model id: pick one here,
10
+ then pass it on. Credentials and provider setup are
11
+ `nodetool-model-provider-config`.
12
+
13
+ ## Calls
14
+
15
+ | Call | Does | Answers |
16
+ | :--- | :--- | :--- |
17
+ | `pick(capability, {query, provider_hint, model_hint, prefer_local})` | Resolves ONE model. | The top result: `{provider, model_id, ref, …}` |
18
+ | `find(capability, {query, task, provider_hint, model_hint, prefer_local, limit})` | Ranks candidates. `limit` defaults to 5. | `{results, ref, note?, query_matched?}` |
19
+ | `list({provider, model_type, downloaded_only, limit})` | Browses every configured model. | `{results}` |
20
+ | `forProvider(provider)` | Lists one provider's language models. | The provider catalog |
21
+ | `generate(prompt, model, {system, images, max_tokens, temperature})` | One language-model call, with optional images. No asset is made. | `{provider, model, text}` |
22
+
23
+ `capability` is one of `text_to_image`, `image_to_image`, `segment_image`,
24
+ `text_to_video`, `image_to_video`, `reference_to_video`, `text_to_speech`,
25
+ `text_to_music`, `audio_to_audio`, `automatic_speech_recognition`,
26
+ `generate_embedding` and `generate_message`.
27
+
28
+ `model_type` for `list` is one of `language`, `image`, `video`, `tts`,
29
+ `music`, `audio_to_audio`, `asr` and `embedding`.
30
+
31
+ ## What a result carries
32
+
33
+ - `provider` and `model_id` — the route. Every `nodetool.media.*` call takes
34
+ the whole result, `{provider, model_id}`, or a `"provider/model_id"` string.
35
+ - `ref` — the typed value `{type, provider, id, name}`. Assign it **verbatim**
36
+ to a node's `*_model` property. The flat `model_id` field does not fit that
37
+ property.
38
+ - For ranked media models: `canonical`, `ranked_task`, `rank` and `of`, and
39
+ `alternate_routes` for other providers that serve the same model. One model
40
+ is one row, not one row for each route.
41
+ - `prompting_skill` — the name of the shipped guide for that model line. Load
42
+ it with `load_skill` before you write the prompt.
43
+
44
+ ## Rules
45
+
46
+ - `pick` with no options is the good default. For image, video, speech and
47
+ music, the order comes from a quality leaderboard for the task. Do not shop
48
+ around.
49
+ - When the user named a model, search in the same call:
50
+ `pick("text_to_image", {query: "flux schnell"})`. `query` is free text over
51
+ the model id and name. All words must appear, and separators do not matter.
52
+ - `pick` throws when no configured provider offers the capability, and when a
53
+ `query` matches nothing. It never answers with an unrelated model. Report
54
+ the miss or call `find` to see what is configured.
55
+ - `task` is a hint against the supported tasks of a model. It is not a search
56
+ box. Use `query` to search by name.
57
+ - A judge for `nodetool.media.critique`, `compare`, `scoreAdherence` and
58
+ `understandVideo` is a chat model that reads images or video:
59
+ `pick("generate_message", {query: "gemini"})`, for example. It is not the
60
+ model that made the picture.
61
+
62
+ ## Examples
63
+
64
+ ```js
65
+ // The best image model, straight into a generation.
66
+ const model = await nodetool.models.pick("text_to_image");
67
+ const shot = await nodetool.media.generateImage("a red fox in snow", model);
68
+
69
+ // A node property wants the typed ref. wf = await nodetool.workflows.open(id).
70
+ const tts = await nodetool.models.pick("text_to_speech");
71
+ wf.node("speech_1").set({ model: tts.ref });
72
+
73
+ // One text call with an image.
74
+ const llm = await nodetool.models.pick("generate_message");
75
+ const { text } = await nodetool.models.generate(
76
+ "Name the dominant colour in one word.", llm, { images: [shot.asset_uri] }
77
+ );
78
+ ```
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: api-scripts
3
+ description: "Call nodetool.scripts from a code action: create a voice script (spoken lines, not JavaScript), add speakers with voices and spoken lines, voice the lines as audio takes, and assemble the takes into a voiceover timeline with word timings. Load before the first call into nodetool.scripts."
4
+ ---
5
+
6
+ # nodetool.scripts
7
+
8
+ A script (a voice script) is a cast of speakers, each with a voice, and the
9
+ lines they speak in reading order. Voicing a line makes an audio take.
10
+ Assembling lays the takes into a timeline. A JavaScript script is a different
11
+ document (`nodetool-js-scripting`). A video timed to a written voiceover is
12
+ `script-video`.
13
+
14
+ | Call | Does | Answers |
15
+ | :--- | :--- | :--- |
16
+ | `list({limit})` | Lists scripts, newest first, with cast size, line count, voiced count and the timeline it was assembled into. | Script rows |
17
+ | `create(name, {project_id, id})` | Creates an empty script. An existing `id` is returned as it is, so a retry makes no copy. | `{script_id, …}` |
18
+ | `get(id)` | Reads the cast and every line with its id, index, speaker, text, direction, pause, effective voice and voicing status. | The script |
19
+ | `edit(id, ops)` | Applies ops in order and saves. An open editor picks the change up live. | The result of each op |
20
+ | `voice(id, opts)` | Calls the TTS provider for the lines. | The takes it made |
21
+ | `assembleTimeline(id, {name, fps})` | Lays the voiced takes end to end into a timeline. | The timeline id, and the lines it skipped |
22
+
23
+ Line status is `draft` (never voiced), `stale` (the text or voice changed
24
+ since the take), `voiced` or `no_voice` (the speaker has no voice).
25
+
26
+ ## Ops
27
+
28
+ A line `target` is its id, its 0-based index in the whole script, or its exact
29
+ text. A speaker `target` is its id or name. An argument an op does not take is
30
+ refused.
31
+
32
+ | Op | Arguments |
33
+ | :--- | :--- |
34
+ | `set_setup` | `stage?`, `brief?`, `format?`, `length_seconds?`, `pace?`, `language?` |
35
+ | `add_speaker` | `name`, `color?`, `provider?`, `model?`, `voice?`, `entityId?` |
36
+ | `set_speaker` | `target`, `name?`, `color?`, `entityId?` — renames or recolours a speaker |
37
+ | `set_speaker_voice` | `target`, `provider`, `model`, `voice`, `settings?` |
38
+ | `remove_speaker` | `target` |
39
+ | `add_section` | `title?` |
40
+ | `add_line` | `text`, `speaker?`, `section?`, `direction?`, `pause_after_ms?`, `index?` |
41
+ | `set_line_text` | `target`, `text` |
42
+ | `set_line_speaker` | `target`, `speaker` — the op that gives a line its speaker |
43
+ | `remove_line` | `target` |
44
+
45
+ - `format` is `voiceover`, `dialogue`, `interview`, `ad-read` or `tutorial`.
46
+ - `entityId` makes the speaker a cast character from the entity library, so
47
+ storyboard renders can use it.
48
+ - A rewritten line keeps its takes as `stale`, so the next `voice()` records
49
+ exactly those again.
50
+
51
+ ## voice
52
+
53
+ - Omit `targets` to voice every line that is unvoiced or stale. A whole script
54
+ is one call. Each line is a paid TTS call plus a transcription call, so
55
+ confirm the scope with the user before you voice a long script.
56
+ - `targets` takes line ids, indexes or exact texts.
57
+ - Each line uses its own voice, else its speaker's. `provider`, `model` and
58
+ `voice` together override every line. Pick the model with
59
+ `nodetool.models.pick("text_to_speech")`.
60
+ - `speed`, `concurrency` (default 3, max 8).
61
+ - Word timings are transcribed for captions (`transcribe`, default true;
62
+ `asr_provider` and `asr_model` default to `openai` and `whisper-1`).
63
+ - Earlier takes are kept, and the new take becomes current.
64
+
65
+ ```js
66
+ const { script_id: id } = await nodetool.scripts.create("Launch VO");
67
+ await nodetool.scripts.edit(id, [
68
+ { op: "add_speaker", name: "Narrator" },
69
+ { op: "set_speaker_voice", target: "Narrator", provider, model, voice },
70
+ { op: "add_line", text: "Meet the lamp that listens.", speaker: "Narrator" }
71
+ ]);
72
+ await nodetool.scripts.voice(id);
73
+ const cut = await nodetool.scripts.assembleTimeline(id);
74
+ ```
75
+
76
+ Each assembled clip carries its word timings, the speaker label and a link to
77
+ its line, so a re-voiced line can round-trip into the cut. Running the
78
+ assembly again rebuilds the same timeline in place. Validate it with
79
+ `nodetool.timelines.validate` before a render.
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: api-settings
3
+ description: "Call nodetool.settings or nodetool.secrets from a code action: read or change a NodeTool setting, find out which credentials are configured, ask the user to enter a missing API key, or read a secret in a script. Load before the first call into these namespaces."
4
+ ---
5
+
6
+ # nodetool.settings and nodetool.secrets
7
+
8
+ `nodetool.settings` is the configuration of this install. `nodetool.secrets`
9
+ reads credentials inside a run. A secret value never passes through the agent:
10
+ the user types it in a dialog.
11
+
12
+ ## nodetool.settings
13
+
14
+ | Call | Does | Answers |
15
+ | :--- | :--- | :--- |
16
+ | `list({group})` | Lists every setting, or one group (`"Folders"`, for example), with its description, allowed values and current value. Secrets are not in this list. | `{settings, groups}` |
17
+ | `get(key)` | Reads one setting, from the user's saved settings and then the environment. Refuses a secret. | The setting with its `value` and `source` (`user`, `env` or `unset`) |
18
+ | `set(key, value)` | Changes one setting for this user. Only a declared setting can be set, and a setting with allowed values takes only those. `value` is a string. | — |
19
+ | `secrets()` | Lists the known credentials and whether each one is configured. | Names and a configured flag. Never values. |
20
+ | `requestSecret(key, {reason, help_url})` | Opens a dialog in the user's client where they type the value. | Only whether they saved one |
21
+
22
+ `key` is the environment-variable name: `"AUTOSAVE_INTERVAL_MINUTES"`,
23
+ `"STRIPE_API_KEY"`.
24
+
25
+ ### Asking for a credential
26
+
27
+ 1. Call `secrets()` to see what is missing, and use the name the service is
28
+ registered under.
29
+ 2. Call `requestSecret(key, {reason, help_url})`. Write `reason` for the user,
30
+ in one sentence. `help_url` is where they get the key.
31
+ 3. Continue when the answer says it was saved.
32
+
33
+ A run with no interactive client refuses the request. Then tell the user
34
+ which credential is missing and where to add it (Settings > Secrets). Do not
35
+ ask again in a loop, and never ask the user to paste a key into the chat.
36
+
37
+ ## nodetool.secrets
38
+
39
+ For code that needs a credential value, such as a Code node or a script:
40
+
41
+ | Call | Does |
42
+ | :--- | :--- |
43
+ | `get(name)` | The value. It throws and names the secret when it is not set. |
44
+ | `tryGet(name)` | The value, or `undefined` for a credential that is optional |
45
+ | `list()` | The names this node declared in its secret scope, or `null` when it declared none |
46
+
47
+ A read works only for a name inside the secret scope of the run. A chat
48
+ action has no secret store, so `nodetool.secrets.get` throws there. Use the
49
+ tools that hold the credential on the host instead of reading it.
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: api-sketches
3
+ description: "Call nodetool.sketches from a code action: create a sketch (layered image document), read it, add, arrange and restyle layers, place images on layers, resize the canvas, validate it, and manage its versions. Load before the first call into nodetool.sketches."
4
+ ---
5
+
6
+ # nodetool.sketches
7
+
8
+ A sketch is an image document: a canvas, a stack of layers, and the bindings
9
+ that say where the picture of a layer comes from. How to compose one is
10
+ `nodetool-sketch`. This is the call reference. One finished image with no
11
+ layers to keep is `nodetool.media.generateImage`, not a sketch.
12
+
13
+ | Call | Does | Answers |
14
+ | :--- | :--- | :--- |
15
+ | `list({query, limit})` | Lists sketches, newest first. | Rows with id, name and canvas size |
16
+ | `create(name, {width, height, background_color, project_id, id})` | Creates a blank canvas. The defaults are 1024×1024 on `#ffffff`. An existing `id` you own is returned instead of a copy. | `{image_document_id, …}` |
17
+ | `get(id)` | Reads the document: canvas, background, layers, bindings. Layer bitmaps stay opaque. | The document |
18
+ | `edit(id, ops)` | Applies layer ops in order and saves. An open editor picks the change up live. | The result of each op |
19
+ | `validate(idOrDocument, {width, height, background_color})` | Checks the structure without a render. For an inline document, pass the canvas it is stored against so a mismatch is reported. | `{ok, issues}` |
20
+ | `versions(id, {save_type, limit})`, `getVersion(id, n)` | Lists and reads whole-document snapshots. | Version rows, newest first |
21
+ | `snapshot(id, {name})` | Saves a manual version. | The version number |
22
+ | `restore(id, n)` | Rolls back. The state it replaces is snapshotted first. | The findings of the validation after the restore |
23
+ | `deleteVersion(id, n)` | Deletes one snapshot. This cannot be undone. | — |
24
+
25
+ ## Ops
26
+
27
+ `target` is a layer id, its name, or `"active"`. Layer index 0 is the
28
+ **bottom** layer.
29
+
30
+ | Op | Arguments |
31
+ | :--- | :--- |
32
+ | `add_layer` | `name?`, `type?` (`"raster"` or `"mask"`), `index?`, `image?`, `x?`, `y?`, `width?`, `height?` |
33
+ | `remove_layer` | `target` |
34
+ | `rename_layer` | `target`, `name` |
35
+ | `set_layer_props` | `target`, `visible?`, `locked?`, `opacity?`, `blendMode?` |
36
+ | `set_layer_image` | `target`, `image`, `x?`, `y?`, `width?`, `height?` |
37
+ | `reorder_layer` | `target`, `index` |
38
+ | `duplicate_layer` | `target` |
39
+ | `select_layer` | `target` |
40
+ | `resize_canvas` | `width`, `height` |
41
+ | `set_setup` | `brief?`, `use_case?`, `variations?`, `stage?` — the state of the guided image flow. It renders nothing. |
42
+
43
+ - `image` is an asset id, an `asset://` locator, a `data:` URL or an http(s)
44
+ URL. The layer points at it and the editor draws it at its natural size from
45
+ the top-left of `{x, y, width, height}`, which defaults to the whole canvas.
46
+ Pass the dimensions of the image when you know them.
47
+ - `use_case` is `product`, `portrait`, `key-art`, `social`, `logo`, `concept`
48
+ or `texture`, and it also sets the canvas size.
49
+ - Pixels are never read or written here. Painting and generation happen in an
50
+ open editor or a workflow run.
51
+
52
+ ```js
53
+ const { image_document_id: id } = await nodetool.sketches.create("Poster",
54
+ { width: 1080, height: 1350 });
55
+ await nodetool.sketches.edit(id, [
56
+ { op: "add_layer", name: "Backdrop", image: bgUri },
57
+ { op: "add_layer", name: "Product", image: productUri, x: 240, y: 300, width: 600, height: 600 },
58
+ { op: "set_layer_props", target: "Product", blendMode: "normal", opacity: 1 }
59
+ ]);
60
+ const check = await nodetool.sketches.validate(id);
61
+ ```
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: api-storyboards
3
+ description: "Call nodetool.storyboards from a code action: create a storyboard, write and reorder its shots, set the board's style, entities and models, render stills and clips, revise a clip, and assemble the board into a timeline. Load before the first call into nodetool.storyboards."
4
+ ---
5
+
6
+ # nodetool.storyboards
7
+
8
+ A storyboard turns a brief into shots: an action, a camera, a motion and a
9
+ duration for each, with cast entities. Stills are the cheap step, clips the
10
+ expensive one, and the board assembles into a timeline. The directing
11
+ contract is `storyboard-core`. The brief shapes are the board skills
12
+ (`commercial-beat-sheet`, `explainer-storyboard`, `music-video-treatment`,
13
+ `trailer-template`, and the job skills such as `product-commercial` and
14
+ `short-film`). Search for them with `list_skills`.
15
+
16
+ | Call | Does | Answers |
17
+ | :--- | :--- | :--- |
18
+ | `list({limit})` | Lists boards, newest first, with shot, still and clip counts. | Board rows |
19
+ | `create(name, {brief, style, aspect_ratio, project_id, id})` | Creates a blank board. `aspect_ratio` defaults to `"16:9"`. `style` is added to every shot prompt. | `{id, storyboard_id, …}` |
20
+ | `get(id)` | Reads the brief, style, aspect ratio, models, `revision`, and every shot with its id, index, slug, action, camera, motion, duration, status, `has_still`, `has_clip` and `covered_by`. | The board |
21
+ | `edit(id, ops, {expected_revision})` | Applies ops in order and saves. It spends nothing. `expected_revision` refuses the edit when the board changed after you read it. | The result of each op |
22
+ | `renderStills(id, {targets, provider, model, style, stale_only, concurrency})` | Makes keyframe stills with the image model. | The stills it made |
23
+ | `renderClips(id, {targets, provider, model, resolution, mode, stale_only, concurrency})` | Makes clips with the video model. This is the expensive step. | The clips it made, and the shots it skipped |
24
+ | `reviseClip(id, target, instruction, {provider, model})` | Changes one clip with a video-to-video edit: "make it darker, add rain". | The new take |
25
+ | `assembleTimeline(id, {name, fps})` | Lays the rendered clips end to end into a timeline. | The timeline id, and what it skipped |
26
+ | `previewDesign({storyboardId, expectedStoryboardRevision})` | Reads the board's design as an inline editable timeline preview. No generation and no save. | The preview |
27
+ | `finish({storyboardId, expectedStoryboardRevision, strategy, model, timelineId, expectedTimelineRevision})` | Turns the board's graphics into editable timeline layers with no media generation. `strategy` is `deterministic` (default, no provider, an unreviewed draft) or `agentic` (a model composes and reviews rendered frames). | The status, the timeline and the new revisions |
28
+
29
+ `targets` and `target` take a shot id, a 0-based index or a slug. Omit
30
+ `targets` to render every shot that needs the step. `previewDesign` and
31
+ `finish` take one argument object with camelCase keys.
32
+
33
+ ## Ops
34
+
35
+ | Op | Arguments |
36
+ | :--- | :--- |
37
+ | `add_shot` | `action`, `slug?`, `camera?`, `motion?`, `dialogue?`, `narration?`, `duration_seconds?`, `duration_source?`, `render_mode?`, `entity_ids?`, `location_id?`, `covered_by?`, `notes?`, `end_state?`, `sound?`, `index?` |
38
+ | `update_shot` | `target` and the same fields |
39
+ | `remove_shot`, `duplicate_shot` | `target` |
40
+ | `reorder_shot` | `target`, `index` |
41
+ | `move_shot` | `target`, `scene_id?`, `position` (0-based inside the scene) |
42
+ | `set_board` | `brief?`, `style?`, `aspect_ratio?`, `entity_ids?`, `image_model?`, `video_model?`, `narration?`, `music_prompt?`, `motion_design?` |
43
+ | `set_setup` | `brief?`, `genre?`, `stage?` |
44
+ | `set_style` | `entity_id` (a style entity becomes the board preset) or `style` (the descriptor alone) |
45
+ | `create_scene`, `update_scene`, `merge_scene` | `after_scene_id?`; `scene_id`, `slugline?`, `lighting?`; `scene_id` |
46
+ | `select_version`, `delete_version` | `target`, `kind`, `version` (0-based, oldest first) |
47
+ | `add_keyframe_version` | `target`, `asset_id`, `flip_of?` |
48
+
49
+ - `image_model` and `video_model` take a model object from
50
+ `nodetool.models.pick` and become the render defaults of the board.
51
+ - `covered_by: {shot_id, start_seconds?, end_seconds?}` says that this shot's
52
+ picture is a window into another shot's clip, for one generation whose
53
+ length covers several beats. The covered shot counts as rendered. Pass
54
+ `null` to undo it.
55
+ - `set_board` `narration` and `music_prompt` are board-level voiceover and
56
+ score direction. An empty string clears one. `motion_design` is
57
+ `{direction?, transitions?, continuities?}`, and `null` clears it.
58
+
59
+ ## Render modes
60
+
61
+ A shot renders the way its `render_mode` says, or the way `mode` says for one
62
+ call:
63
+
64
+ - `keyframe` (default) animates the selected still with `image_to_video`. A
65
+ shot with no still is reported, not rendered. Render its still first.
66
+ - `direct` makes the clip from the prompt with `text_to_video`. No still is
67
+ needed.
68
+ - `reference` uses the reference images of the cast entities with
69
+ `reference_to_video`.
70
+
71
+ Earlier stills and clips are kept as versions. `stale_only: true` renders
72
+ only shots whose current version was made against a style, model, aspect
73
+ ratio or prompt they no longer have.
74
+
75
+ ## The loop
76
+
77
+ ```js
78
+ const { id } = await nodetool.storyboards.create("Lamp launch", { brief, style });
79
+ await nodetool.storyboards.edit(id, [
80
+ { op: "set_board", image_model: await nodetool.models.pick("text_to_image"),
81
+ video_model: await nodetool.models.pick("image_to_video") },
82
+ { op: "add_shot", action: "Wide of the lamp on a desk at dusk", duration_seconds: 4 },
83
+ { op: "add_shot", action: "Close on the switch as a hand reaches in", duration_seconds: 3 }
84
+ ]);
85
+ await nodetool.storyboards.renderStills(id); // cheap: look at them first
86
+ // … view the stills, fix shots with update_shot, render again with stale_only …
87
+ // Confirm the shot count and the clip cost with the user before this call.
88
+ await nodetool.storyboards.renderClips(id); // expensive: every shot that needs a clip
89
+ const cut = await nodetool.storyboards.assembleTimeline(id);
90
+ ```
91
+
92
+ When the board links a script, assembly times each shot to the takes it
93
+ covers and adds a voiceover clip for each voiced line. Validate the timeline
94
+ with `nodetool.timelines.validate` before a render.