@nodetool-ai/agents 0.8.4-a24.2 → 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,223 @@
1
+ ---
2
+ name: nodetool-js-scripting
3
+ description: "Write JavaScript that runs in NodeTool's QuickJS sandbox: Code node bodies, saved JS script documents, sandbox package imports, and calling nodes from code."
4
+ featured: true
5
+ ---
6
+
7
+ # Write NodeTool sandbox JavaScript
8
+
9
+ Three places take the same guest JavaScript, with the same globals, the same
10
+ imports and the same limits.
11
+
12
+ | Where | What it is | Reach it with |
13
+ |---|---|---|
14
+ | **Code node** | A body inside a workflow graph | `validate_code`, `run_code`, `test_code` |
15
+ | **JS script document** | A named, versioned script with declared ports, secrets, a timeout and saved tests | `list_js_scripts`, `get_js_script`, `save_js_script`, `edit_js_script`, `validate_js_script`, `run_js_script`, `test_js_script` |
16
+ | **Native flow** | Guest code calling nodes as async functions, no graph | `import "@nodetool-ai/sandbox-nodetool/flow"` |
17
+
18
+ Pick a Code node when the logic belongs to one graph. Pick a script document
19
+ when the same logic is called from several places, needs its own tests, or needs
20
+ version history. Pick native flow when the control flow is easier to write than
21
+ to wire.
22
+
23
+ ## The body contract
24
+
25
+ ```js
26
+ // inputs: { rows: [...], threshold: 10 }
27
+ const kept = inputs.rows.filter((r) => r.score > inputs.threshold);
28
+ progress(50, `kept ${kept.length}`);
29
+ for (const row of kept) await emit("row", row); // streams as it goes
30
+ await output("count", kept.length); // final, posted at the end
31
+ ```
32
+
33
+ - **Inputs arrive on the `inputs` object**, never as globals of their own name.
34
+ Values are deep-copied through JSON before entering the guest.
35
+ - **Outputs leave through `await output(name, value)` and `await emit(name,
36
+ value)`, and nothing else.** `name` must be a declared output handle. A second
37
+ `output` on the same handle throws. `return` is ordinary control flow and its
38
+ value is ignored. For a script document this is enforced: a body that declares
39
+ outputs and returns them instead of emitting them is an **error**, because a
40
+ script has no legacy return contract. A Code node still accepts the old
41
+ return/yield contract for one more release, with a deprecation warning.
42
+ - **Media inputs arrive as refs.** Read one with `media.bytes` / `media.text` /
43
+ `media.info`, and build one with `media.toDocument` / `toImage` / `toAudio` /
44
+ `toVideo`. Pass the whole input object, not its `uri`, so the ref's own type
45
+ travels with it. Every `media.*` call is async.
46
+ - **`stream` is the input side of `emit`.** A body that mentions `stream` runs
47
+ **once** over the whole stream and pulls its own items. A body that never
48
+ mentions it runs once per incoming item. Nothing is configured: deleting the
49
+ last `stream` call flips the node back.
50
+
51
+ ```js
52
+ for await (const item of stream(name)) // one handle, in order, until EOS
53
+ for await (const [handle, item] of stream.any()) // every handle, arrival order
54
+ const item = await stream.first(name) // next value, undefined at EOS
55
+ stream.open(name) // could more still arrive?
56
+ ```
57
+
58
+ - **`state`** survives across streaming invocations and resets at each run.
59
+ - **`progress(percent, message)`** drives the node's progress bar.
60
+
61
+ ## Capabilities are globals, libraries are imports
62
+
63
+ Globals need no declaration: `console`, `fetch`, `workspace`, `getSecret`,
64
+ `nodetool.secrets.*`, `sleep`, `crypto`, `format`, `image`, `audio`, `video`,
65
+ `media`, `canvas`, `assetToSandbox` / `sandboxToAsset`, `progress`, `emit` /
66
+ `output`, and the pure helpers `toBase64` / `fromBase64` / `toHex` / `fromHex` /
67
+ `parallelMap`. `media.*` and `workspace.*` need a `ProcessingContext`, so they
68
+ throw in a bare sandbox call with no run behind it.
69
+
70
+ Everything else is a **sandbox package** the body imports:
71
+
72
+ ```js
73
+ import yaml from "@nodetool-ai/sandbox-yaml";
74
+ ```
75
+
76
+ Discover them with `list_sandbox_packages` and read one's API with
77
+ `get_sandbox_package_docs`. Do not guess a specifier: a pack this host does not
78
+ carry fails validation with "Install `<pack>`". `nodetool packs
79
+ compile` builds one for a dependency that is not shipped.
80
+
81
+ `image.*`, `audio.*` and `video.*` transforms return a `sandbox://media/<id>`
82
+ handle, not bytes. Chain the calls, then `<type>.toAsset(handle)` before the run
83
+ ends. A handle does not survive into a later run.
84
+
85
+ ## Running an agent from code
86
+
87
+ Use `run_agent` when the work needs more than one model call: look something
88
+ up, act, read the result, correct.
89
+
90
+ ```js
91
+ import { run_agent } from "@nodetool-ai/sandbox-nodetool/agents";
92
+
93
+ const answer = await run_agent({
94
+ prompt: "Read storyboard " + inputs.storyboardId + " and list its shot titles.",
95
+ model: inputs.model, // {provider, id} from a model selector
96
+ tools: ["get_storyboard"], // capability wire names, nothing else
97
+ output_schema: { type: "object", properties: { titles: { type: "array", items: { type: "string" } } } }
98
+ });
99
+ await output("titles", answer.result.titles);
100
+ ```
101
+
102
+ Without `output_schema`, `answer.text` is the agent's final message. The agent
103
+ reports its text and tool calls while it runs. A mini app shows them in an
104
+ Agent Activity widget bound to `op:<id>/exec#transcript`. `generate_text` stays
105
+ the right call for one prompt with no tools.
106
+
107
+ ## Calling nodes from code
108
+
109
+ ```js
110
+ import "@nodetool-ai/sandbox-nodetool/flow"; // mounts the bridge, required
111
+ import { concat } from "@nodetool-ai/sandbox-flow/nodetool.text";
112
+
113
+ const r = await concat({ a: inputs.left, b: inputs.right });
114
+ await output("joined", r.output);
115
+ ```
116
+
117
+ `await` is the edge, a variable is the wire, `Promise.all` is the fan-out. Both
118
+ imports are required: the facade does not mount without the capability module.
119
+ Streaming-output nodes carry `.stream(inputs)`, an async iterable where an early
120
+ `break` closes the stream and runs node cleanup. Every call passes the per-call
121
+ permission gate and bills through the invoking run, bounded by a recursion depth
122
+ cap of 4 and 16 concurrently open streams per run. Streaming *inputs* accept
123
+ arrays only in v1.
124
+
125
+ A program that must open in the editor, be validated, or run on the server still
126
+ builds a graph. Use `nodetool-workflow-builder`
127
+ for that.
128
+
129
+ ## Building a timeline from code
130
+
131
+ ```js
132
+ import { video } from "@nodetool-ai/sandbox-timeline";
133
+
134
+ const v = video({ width: 1920, height: 1080, fps: 30 });
135
+ const title = v.scene("title", 3, (s) => {
136
+ const t = s.text("Hello", { size: 120, weight: 600, color: "#ffffff" });
137
+ t.enter({ from: { opacity: 0 }, at: 0, dur: 0.5 });
138
+ });
139
+ v.series([title]);
140
+ const saved = await v.save(nodetool.timelines, { name: "Hello" });
141
+ await output("timeline_id", saved.timeline_id);
142
+ ```
143
+
144
+ The pack authors a whole motion-graphics cut in seconds, local to each scene,
145
+ and saves it with one `set_timeline_document`, instead of one `edit_timeline`
146
+ op per clip. Pass the body's `nodetool.timelines` to `v.save`: a module cannot
147
+ see the belt. `get_sandbox_package_docs` on the specifier returns the full
148
+ authoring API.
149
+
150
+ Save the build script itself as a JS script document and it links to the
151
+ timeline it makes automatically: `v.save(nodetool.timelines, {name})` with no
152
+ `timeline_id` the first time creates the timeline and links this script to
153
+ it; every later run of the same script updates that timeline in place
154
+ instead of making another. Revise with `edit_js_script`'s string-replacement
155
+ ops (below) rather than resending the whole body.
156
+
157
+ ## The loop
158
+
159
+ 1. **Write or read the body.** `get_js_script` for a saved script.
160
+ 2. **`validate_code` / `validate_js_script` after every edit.** It catches
161
+ syntax, imports against the installed catalog, undefined names, undeclared
162
+ `inputs.*` reads, outputs no `emit`/`output` call reaches, duplicate or
163
+ non-identifier port names, and tests naming ports the script does not
164
+ declare. It is far cheaper than running.
165
+ 3. **`run_code` / `run_js_script`** with real inputs. `output` values come back
166
+ as `outputs`, `emit` values as `streamed`, an ordered list of `{name, value}`.
167
+ Stage a streamed input with `input_streams`, keyed by handle.
168
+ 4. **`test_code` / `test_js_script`** as the regression check. A case supplies
169
+ `inputs` (or `input_streams`) and optionally `expect` — final values per
170
+ handle, compared structurally, with unnamed outputs ignored, and
171
+ `expected_streamed`, the full ordered emit list. A case with neither passes
172
+ when the body runs without error.
173
+ 5. **Save.** `save_js_script` validates first and is CAS on update. For a
174
+ small revision, `edit_js_script(js_script_id, ops)` is cheaper: each op is
175
+ `{old, new}`, and `old` must match exactly once in the current code — like
176
+ a code editor's find/replace, refused by name on zero or on an ambiguous
177
+ match. It validates the result the same way `save_js_script` does.
178
+
179
+ Script documents get the same version family as the other documents:
180
+ `list_js_script_versions`, `get_js_script_version`, `create_js_script_version`,
181
+ `restore_js_script_version`, `delete_js_script_version`.
182
+
183
+ ## Secrets and limits
184
+
185
+ Read a credential with `nodetool.secrets.get(name)` — never inline one, and
186
+ never write one into a body or a test case. A script's declared secrets are
187
+ intersected with whatever allowance the invoking context carries. There is no
188
+ `set_secret`: `request_secret` asks the user's own client for one and the value
189
+ never enters the guest, the transcript, or the model's context. A headless run
190
+ carries no secret prompt, so the call is refused by name rather than quietly
191
+ writing something nobody approved.
192
+
193
+ Script composition is bounded like sub-agents: depth cap 4 with a script id
194
+ chain, so a cycle fails the call naming it. Execution time defaults to 30s and
195
+ every limit is overridable per invocation and clamped to a ceiling.
196
+
197
+ ## Verify from a shell
198
+
199
+ These are the `nodetool` CLI. From a NodeTool checkout the same commands run
200
+ as `npm run dev:nodetool -- <command>`.
201
+
202
+ ```bash
203
+ nodetool jsscript validate <id|file.json> --json
204
+ nodetool jsscript run <id|file.json> --inputs '{"numbers":[1,2,3]}'
205
+ nodetool jsscript run <id|file.json> --input-streams '{"numbers":[1,2,3]}'
206
+ nodetool jsscript test <id|file.json> --json
207
+ nodetool jsscript versions list|show|create|restore|delete <id>
208
+ ```
209
+
210
+ A path that exists on disk wins over an id, and a file target needs no database.
211
+ `jsscript test` exits non-zero on any failure and is the keyless selfcheck the
212
+ harness gate runs.
213
+
214
+ ## Reference
215
+
216
+ In a NodeTool checkout, these repository sources go further:
217
+
218
+ - `docs/javascript-sandbox.md` — the guest surface, marshaling, limits,
219
+ concurrency and the security model.
220
+ - `docs/js-script-document-design.md` — document shape, storage, invocation
221
+ from agents, Code nodes and mini apps.
222
+ - `docs/harnesses.md` § nodetool jsscript
223
+ - `packages/sandbox-packs/README.md`
@@ -0,0 +1,348 @@
1
+ ---
2
+ name: nodetool-model-provider-config
3
+ description: "Configure NodeTool model providers and API keys (list_secrets, request_secret), pick a model with find_model, or set up local Ollama, llama.cpp and Hugging Face models."
4
+ featured: true
5
+ ---
6
+
7
+ You help users configure AI model providers and select the right models for their tasks.
8
+
9
+ # In the product
10
+
11
+ The agent has no shell. Configure keys and pick models with these tools:
12
+
13
+ 1. `list_secrets` shows which credentials are configured. It never returns a
14
+ value.
15
+ 2. `request_secret {key, reason, help_url}` opens a dialog where the user types
16
+ a missing key. The value is saved from the dialog and never passes through
17
+ the agent. Never ask the user to paste a key into chat. When the run has no
18
+ interactive client, name the missing key and point the user to
19
+ Settings > Secrets.
20
+ 3. `find_model {capability}` returns a real `{provider, model_id}` and a `ref`
21
+ to assign verbatim to a node's model property. Call it before adding any
22
+ generic AI node. Never write a model id from memory, including the examples
23
+ below.
24
+ 4. `list_provider_models {provider}` lists one provider's language models.
25
+
26
+ Inside a code action the same calls are `nodetool.secrets` /
27
+ `nodetool.settings` (load `api-settings`) and `nodetool.models` (load
28
+ `api-models`).
29
+
30
+ The `nodetool` provider is NodeTool's managed service. Its models run on
31
+ platform keys and draw from the user's credit balance, so it needs no key of
32
+ the user's own. Every other provider bills the user's own account.
33
+
34
+ # Provider Overview
35
+
36
+ | Provider | Type | Key Env Var | Models |
37
+ |----------|------|-------------|--------|
38
+ | **OpenAI** | Cloud | `OPENAI_API_KEY` | GPT, GPT-Image, TTS, Whisper |
39
+ | **Anthropic** | Cloud | `ANTHROPIC_API_KEY` | Claude Opus, Sonnet, Haiku |
40
+ | **Gemini (Google)** | Cloud | `GEMINI_API_KEY` | Gemini, Veo, Nano Banana |
41
+ | **xAI** | Cloud | `XAI_API_KEY` | Grok |
42
+ | **Ollama** | Local | `OLLAMA_API_URL` | Qwen, Llama 3, Mistral, any GGUF. Separate install, must be running |
43
+ | **HuggingFace** | Cloud | `HF_TOKEN` | Hosted Inference Providers |
44
+ | **HuggingFace local** (`huggingface-local`) | Local | — | Diffusers/Transformers models via the HuggingFace Python pack |
45
+ | **NodeTool** (`nodetool`) | Cloud, managed | — (credits) | Curated models |
46
+ | **FAL** (`fal_ai`) | Cloud | `FAL_API_KEY` | Fast image/video generation |
47
+ | **KIE** (`kie`) | Cloud | `KIE_API_KEY` | Image, video and music models from many vendors |
48
+ | **ElevenLabs** (`elevenlabs`) | Cloud | `ELEVENLABS_API_KEY` | TTS, voice, sound effects |
49
+ | **Replicate** | Cloud | `REPLICATE_API_TOKEN` | Community models |
50
+ | **Comfy Cloud** | Cloud | `COMFY_API_KEY` | No model list; runs a ComfyUI workflow on Comfy's GPUs via `lib.comfy.RunWorkflowOnCloud` |
51
+ | **vLLM** | Local | `VLLM_BASE_URL` (required) | Self-hosted, OpenAI-compatible |
52
+ | **LM Studio** | Local | `LMSTUDIO_API_URL` | Models loaded in LM Studio's local server |
53
+ | **llama.cpp server** (`llama_cpp`) | Local | `LLAMA_CPP_URL` (required) | A `llama-server` you run |
54
+ | **llama.cpp local** (`node_llama_cpp`) | Local | — | GGUF files in-process; runtime from Package Manager → Engines & tools |
55
+ | **MLX** | Local | — | MLX Python pack, Apple Silicon only |
56
+
57
+ Other registered chat providers (any of these is valid for the CLI's `-p/--provider`):
58
+ `groq`, `mistral`, `deepseek`, `moonshot`, `minimax`, `cerebras`, `alibaba`
59
+ (`DASHSCOPE_API_KEY`, Qwen via Alibaba Cloud Model Studio), `together`,
60
+ `openrouter`, `requesty`, `opper`, `api_route`, `codex`, `claude_agent_sdk`, `lmstudio`,
61
+ `azure_openai` (`AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_ENDPOINT`, models from
62
+ `AZURE_OPENAI_DEPLOYMENTS`), `bedrock` (`BEDROCK_ACCESS_KEY_ID`,
63
+ `BEDROCK_SECRET_ACCESS_KEY`, `BEDROCK_REGION`).
64
+
65
+ # From a shell (self-host)
66
+
67
+ These run in the user's terminal, not in the product. `nodetool models
68
+ providers` shows configured providers, `nodetool models recommended` the curated
69
+ list, and `nodetool models by-provider <provider>` one provider's ids.
70
+
71
+ ```bash
72
+ # Via CLI (encrypted storage)
73
+ nodetool secrets store OPENAI_API_KEY
74
+ nodetool secrets store ANTHROPIC_API_KEY
75
+ nodetool secrets store GEMINI_API_KEY
76
+ nodetool secrets store HF_TOKEN
77
+ nodetool secrets store FAL_API_KEY
78
+ nodetool secrets store REPLICATE_API_TOKEN
79
+ nodetool secrets store COMFY_API_KEY
80
+
81
+ # Via environment variables
82
+ export OPENAI_API_KEY=sk-...
83
+ export ANTHROPIC_API_KEY=sk-ant-...
84
+ export GEMINI_API_KEY=AI...
85
+ export HF_TOKEN=hf_...
86
+ export FAL_API_KEY=...
87
+ export REPLICATE_API_TOKEN=r8_...
88
+ export COMFY_API_KEY=comfyui-...
89
+ export OLLAMA_API_URL=http://localhost:11434
90
+ ```
91
+
92
+ # Model Selection by Task
93
+
94
+ The tables name model families as starting points. `find_model` ranks what is
95
+ actually available on this install and returns the exact id.
96
+
97
+ ## whisper.cpp speech recognition
98
+
99
+ Both providers are local-only and unavailable on the cloud profile.
100
+ `whisper_cpp` runs speech recognition in the backend through the optional
101
+ `@fugood/whisper.node@1.1.3` runtime package. Install **whisper.cpp** from the
102
+ Package Manager, then download a GGML model from Models. It serves
103
+ `nodetool.text.AutomaticSpeechRecognition` and `whisper_cpp.LiveTranscription`.
104
+ Use the absolute model path returned by discovery unchanged as the ASR model id.
105
+
106
+ Models use the Hugging Face hub cache (see HuggingFace models below for how its
107
+ location resolves). `WHISPER_CPP_MODELS_DIR` adds another directory.
108
+ `WHISPER_CPP_GPU_BACKEND` accepts `auto`, `metal`, `cuda`, `vulkan`, or `cpu`.
109
+ `auto` uses Metal on macOS. On Windows and Linux it tries the CUDA build, then
110
+ the Vulkan build, then the default CPU build. Restart the backend after
111
+ changing the backend setting. Live transcription accepts base64 PCM16
112
+ mono chunks with an optional `content_metadata.sample_rate` and uses Silero
113
+ VAD when installed, otherwise fixed windows.
114
+
115
+ `whisper_cpp_server` calls a user-run `whisper-server`. Set
116
+ `WHISPER_CPP_SERVER_URL` to its base URL. The model id is `default`, representing
117
+ the model loaded by that server. It requires no native runtime package.
118
+
119
+ ## Language / Chat
120
+
121
+ | Need | Family | Provider | Notes |
122
+ |------|--------|----------|-------|
123
+ | Best quality | GPT flagship, Claude Opus or Sonnet | OpenAI, Anthropic | Highest capability |
124
+ | Good balance | GPT mini, Gemini Flash | OpenAI, Gemini | Fast + cheap |
125
+ | Local/private | Llama, Qwen | Ollama | No data leaves machine |
126
+ | Lightweight local | Small Llama, Mistral 7B | Ollama | Low memory |
127
+ | Code | Claude Sonnet, GPT flagship | Anthropic, OpenAI | Best for coding |
128
+
129
+ ## Image Generation
130
+
131
+ | Need | Model | Provider | Notes |
132
+ |------|-------|----------|-------|
133
+ | Best quality | FLUX.2 Dev | HuggingFace, FAL | State-of-art |
134
+ | Fast | FLUX Schnell | HuggingFace | Quick iterations |
135
+ | Versatile | SDXL | HuggingFace | Many LoRAs available |
136
+ | API-based | GPT Image 2, Nano Banana | OpenAI, Gemini/KIE | No local GPU needed |
137
+
138
+ ## Video Generation
139
+
140
+ | Need | Model | Provider |
141
+ |------|-------|----------|
142
+ | Best quality | Sora 2 Pro | OpenAI (KIE) |
143
+ | Fast | Wan 2.6 | KIE |
144
+ | Image-to-video | Kling 2.6 | KIE |
145
+ | Talking avatar | Kling AI Avatar | KIE |
146
+
147
+ ## Speech & Audio
148
+
149
+ | Need | Model | Provider |
150
+ |------|-------|----------|
151
+ | TTS (quality) | ElevenLabs | ElevenLabs |
152
+ | TTS (fast/free) | Kokoro | HuggingFace pack, MLX pack, Transformers.js |
153
+ | ASR (accuracy) | Whisper Large V3 | HuggingFace pack, whisper.cpp |
154
+ | ASR (fast) | Whisper Turbo | HuggingFace pack, MLX pack, whisper.cpp |
155
+
156
+ ## Embeddings
157
+
158
+ | Need | Model | Provider |
159
+ |------|-------|----------|
160
+ | General text | text-embedding-3-small | OpenAI |
161
+ | Best quality | text-embedding-3-large | OpenAI |
162
+ | Local/free | sentence-transformers | HuggingFace |
163
+
164
+ # Local Model Setup
165
+
166
+ ## Ollama (Easiest)
167
+
168
+ Ollama is a separate program. NodeTool does not ship or start it, so it must be
169
+ running before its models appear. On macOS and Windows, download it from
170
+ ollama.com. On Linux:
171
+
172
+ ```bash
173
+ # Install
174
+ curl -fsSL https://ollama.com/install.sh | sh
175
+
176
+ # Pull models
177
+ ollama pull llama3
178
+ ollama pull mistral
179
+ ollama pull qwen2
180
+
181
+ # Verify
182
+ ollama list
183
+
184
+ # NodeTool finds Ollama at 127.0.0.1:11434
185
+ # Override: OLLAMA_API_URL in Settings → Integrations → Local Model Servers,
186
+ # or export OLLAMA_API_URL=http://host:11434
187
+ ```
188
+
189
+ `OLLAMA_CONTEXT_LENGTH` sets the context window sent with each request.
190
+ Unset, NodeTool uses the model's own value, capped at 32768.
191
+
192
+ ## Python packs (HuggingFace local, MLX, Wan2GP)
193
+
194
+ Local Diffusers/Transformers models, MLX models and Wan2GP video run in the
195
+ Python worker, and each needs its pack.
196
+
197
+ - Desktop app: **Tools → Package Manager → Python nodes**. Installing a pack
198
+ sets up Python first if it is missing. The HuggingFace pack pulls a PyTorch
199
+ 2.14 build matched to the GPU. MLX is offered only on Apple Silicon Macs.
200
+ On a Mac, both packs need Apple Silicon and macOS 14 or newer.
201
+ - Without the desktop app: a Python 3.11+ env with
202
+ `pip install nodetool-core nodetool-huggingface` (plus `nodetool-mlx` on
203
+ Apple Silicon), then start the server with `NODETOOL_PYTHON` pointing at that
204
+ env's `python`. `curl -fsSL https://raw.githubusercontent.com/nodetool-ai/nodetool/main/install.sh | bash -s -- -y --pack huggingface`
205
+ builds that env on Linux and macOS. `--pack` takes `huggingface`, `mlx`, or
206
+ `wan2gp`. On macOS, always set `NODETOOL_PYTHON` to the env it prints.
207
+ - `NODETOOL_TORCH_DEVICE` (`cuda`, `cuda:1`, `mps`, `cpu`) picks the device.
208
+ - Wan2GP nodes call a Wan2GP server the user runs. `WAN2GP_MCP_URL` (default
209
+ `http://127.0.0.1:7866/mcp`) or the node's `server_url` points at it.
210
+
211
+ ## HuggingFace models
212
+
213
+ Download local models in the Model Manager before running the workflow. A node
214
+ that downloads on first use can fail on a gated repo or stall a run.
215
+
216
+ For gated models:
217
+ 1. Accept the license on the model page at huggingface.co
218
+ 2. Store `HF_TOKEN` in Settings (or `nodetool secrets store HF_TOKEN`). Model
219
+ Manager downloads use it
220
+ 3. Download the model in the Model Manager
221
+
222
+ Models go to the Hugging Face hub cache: `HF_HUB_CACHE`, else
223
+ `HUGGINGFACE_HUB_CACHE`, else `$HF_HOME/hub`, else
224
+ `$XDG_CACHE_HOME/huggingface/hub`, else `~/.cache/huggingface/hub`. The
225
+ server and the Python worker (through `huggingface_hub`) apply this one order.
226
+ The desktop app keeps `~/.cache/huggingface` when `XDG_CACHE_HOME` is set (as
227
+ in Flatpak) but that cache already holds models.
228
+
229
+ ## llama.cpp
230
+
231
+ Two providers. `node_llama_cpp` loads GGUF files in-process after the runtime
232
+ is installed from Package Manager → Engines & tools. `llama_cpp` calls a
233
+ `llama-server` the user runs, at `LLAMA_CPP_URL`. Best for CPU inference and
234
+ quantized models.
235
+
236
+ ## whisper.cpp and Transformers.js
237
+
238
+ whisper.cpp is speech recognition only (see above). Transformers.js runs small
239
+ ONNX models in-process after its runtime is installed from Package Manager →
240
+ Software. Its cache is `TRANSFORMERS_JS_CACHE_DIR`.
241
+
242
+ ## MLX (Apple Silicon only)
243
+
244
+ Needs the MLX pack and macOS 14 or newer. Lower memory usage than standard
245
+ PyTorch.
246
+
247
+ # Local Inference Performance
248
+
249
+ | Framework | Throughput | Memory | Hardware |
250
+ |-----------|-----------|--------|----------|
251
+ | **llama.cpp** | Medium | Excellent | CPU, GPU |
252
+ | **MLX** | Good | Excellent | Apple Silicon |
253
+ | **Transformers** | Medium | Good | Any |
254
+
255
+ # Provider-Agnostic Nodes
256
+
257
+ These nodes work with any provider — just select the model:
258
+
259
+ | Node | Purpose |
260
+ |------|---------|
261
+ | `nodetool.agents.Agent` | Any LLM for chat/reasoning |
262
+ | `nodetool.image.TextToImage` | Any image generation model |
263
+ | `nodetool.image.ImageToImage` | Any image transformation model |
264
+ | `nodetool.video.TextToVideo` | Any video generation model |
265
+ | `nodetool.video.ImageToVideo` | Any image-to-video model |
266
+ | `nodetool.audio.TextToSpeech` | Any TTS model |
267
+ | `nodetool.text.AutomaticSpeechRecognition` | Any ASR model |
268
+
269
+ # Provider Capabilities
270
+
271
+ | Capability | OpenAI | Anthropic | Google | Ollama | HF |
272
+ |-----------|--------|-----------|--------|--------|-----|
273
+ | Chat/Text | yes | yes | yes | yes | yes |
274
+ | Vision | yes | yes | yes | some | yes |
275
+ | Image Gen | yes (GPT-Image) | no | no | no | yes |
276
+ | Video Gen | no | no | yes (Veo) | no | some |
277
+ | TTS | yes | no | no | no | yes |
278
+ | ASR | yes (Whisper) | no | no | no | yes |
279
+ | Embeddings | yes | no | yes | yes | yes |
280
+ | Tool Calling | yes | yes | yes | some | no |
281
+
282
+ # Common Pitfalls
283
+
284
+ - **Wrong key env var name**: Each provider has a specific name (see table above)
285
+ - **Ollama not running**: NodeTool does not start it. Start the Ollama app or `ollama serve`
286
+ - **Gated HF models**: Must accept terms on huggingface.co first
287
+ - **GPU memory**: Large models need 8-24GB VRAM; use quantized versions
288
+ - **PyTorch on the CPU despite a GPU**: the desktop app installs CUDA 12.8 for Turing (RTX 20xx) and newer (driver 570+), CUDA 12.6 for Maxwell to Volta, and CPU for Kepler, pre-RDNA 2 AMD and AMD on Windows. It also falls back to CPU, with a warning, when no GPU build resolves. A manual `pip install torch` on Linux gets CUDA 13.0, which needs driver 580+ and Turing or newer, as does the Docker worker image
289
+ - **No local provider in the model menu**: the Python pack is missing, or `NODETOOL_PYTHON_ON_DEMAND=true` and no workflow has started the worker yet
290
+ - **Rate limits**: Cloud providers have rate limits; implement retries or use local
291
+ - **Model ID mismatch**: Take ids from `find_model` or `list_provider_models`, never from memory. From a shell, `nodetool models by-provider <provider>` lists them
292
+ - **Key pasted into chat**: Use `request_secret`. A key in a chat message is stored in the thread
293
+
294
+ # Repository only: custom provider
295
+
296
+ This is TypeScript for contributors working in a NodeTool checkout. The
297
+ in-product agent cannot add a provider. Providers extend `BaseProvider` from `@nodetool-ai/runtime` (not `@nodetool-ai/core`).
298
+ Both `generateMessage` and `generateMessages` take a single **args object**.
299
+
300
+ ```typescript
301
+ import {
302
+ BaseProvider,
303
+ type ProviderId,
304
+ type Message,
305
+ type ProviderStreamItem,
306
+ type ProviderTool,
307
+ type LanguageModel,
308
+ } from "@nodetool-ai/runtime";
309
+
310
+ export class MyProvider extends BaseProvider {
311
+ private apiKey: string;
312
+
313
+ constructor(kwargs: Record<string, unknown> = {}) {
314
+ super("my_provider" as ProviderId);
315
+ this.apiKey = String(kwargs["MY_API_KEY"] ?? process.env.MY_API_KEY ?? "");
316
+ }
317
+
318
+ static override requiredSecrets(): string[] {
319
+ return ["MY_API_KEY"];
320
+ }
321
+
322
+ // Non-streaming: return a single assistant Message.
323
+ async generateMessage(args: {
324
+ messages: Message[];
325
+ model: string;
326
+ tools?: ProviderTool[];
327
+ }): Promise<Message> {
328
+ // Call your API with args.messages / args.model …
329
+ return { role: "assistant", content: "response text" };
330
+ }
331
+
332
+ // Streaming: yield ProviderStreamItem chunks.
333
+ async *generateMessages(args: {
334
+ messages: Message[];
335
+ model: string;
336
+ tools?: ProviderTool[];
337
+ }): AsyncGenerator<ProviderStreamItem> {
338
+ yield { type: "chunk", content: "response text", done: false };
339
+ }
340
+
341
+ override async getAvailableLanguageModels(): Promise<LanguageModel[]> {
342
+ return [{ id: "my-model", name: "My Model", provider: "my_provider" }];
343
+ }
344
+ }
345
+ ```
346
+
347
+ Register it with `registerProvider("my_provider", MyProvider)` from
348
+ `@nodetool-ai/runtime`.