Agent Skillsnodetool-ai/nodetool › sandbox-flow

sandbox-flow

GitHub

提供在沙箱环境中以类型安全异步函数方式调用 NodeTool 节点的能力,支持流式处理、标准控制流及错误管理。

packages/sandbox-packs/sandbox-flow/SKILL.md nodetool-ai/nodetool

Trigger Scenarios

需要在代码中动态调用 AI 节点或工具 实现基于 Promise 的异步节点编排

Install

npx skills add nodetool-ai/nodetool --skill sandbox-flow -g -y
More Options

Non-standard path

npx skills add https://github.com/nodetool-ai/nodetool/tree/main/packages/sandbox-packs/sandbox-flow -g -y

Use without installing

npx skills use nodetool-ai/nodetool@sandbox-flow

指定 Agent (Claude Code)

npx skills add nodetool-ai/nodetool --skill sandbox-flow -a claude-code -g -y

安装 repo 全部 skill

npx skills add nodetool-ai/nodetool --all -g -y

预览 repo 内 skill

npx skills add nodetool-ai/nodetool --list

SKILL.md

Frontmatter
{
    "name": "sandbox-flow",
    "description": "Call NodeTool nodes as typed async functions from sandbox code, one importable module per node namespace, with streaming and plain JavaScript control flow"
}

Calling nodes from the sandbox

Specifier: @nodetool-ai/sandbox-flow. Each node namespace is its own module — @nodetool-ai/sandbox-flow/nodetool.text, @nodetool-ai/sandbox-flow/lib.audio, and so on for all 69. Every node type is a generated async function whose name and inputs come from the node's own metadata, so a type this pack does not export has no import to resolve.

This is not the graph DSL. Nothing is built, saved, or scheduled: the call runs the node and resolves to its outputs. await is the edge, a variable is the wire, Promise.all is the fan-out, and if/for/try are themselves.

import { concat } from "@nodetool-ai/sandbox-flow/nodetool.text";

const r = await concat({ a: "hello ", b: "world" });
return r.output;

Two imports, both required

  1. import { … } from "@nodetool-ai/sandbox-flow/<namespace>"; — the nodes.
  2. import "@nodetool-ai/sandbox-nodetool/flow"; — the capability module.

The second one is not decoration. The host mounts a capability module by reading the body's static imports, and this pack's guest code calls into @nodetool-ai/sandbox-nodetool/flow. Without the body-side import the facade is never mounted and the pack's own import of it is refused by name.

import "@nodetool-ai/sandbox-nodetool/flow";
import { concat } from "@nodetool-ai/sandbox-flow/nodetool.text";

Streaming

A node that streams its output carries a .stream member; a one-shot node does not, so the surface tells you which is which. Awaiting the plain call on a streaming node still works — it drains the node and returns the last value per slot.

import "@nodetool-ai/sandbox-nodetool/flow";
import { agent } from "@nodetool-ai/sandbox-flow/nodetool.agents";

let text = "";
for await (const chunk of agent.stream({ objective: "Summarize the file" })) {
  text += chunk.chunk ?? "";
  if (text.length > 2000) break; // closes the stream; the node stops
}
return text;

Breaking early releases the stream on the host. Read it to the end, or break — both are fine; abandoning the loop object without either is what leaks.

A node written against the streaming-input contract streams {slot, value} instead of partial outputs, one item per emission, and its inputs accept an array wherever a single value goes:

import { take } from "@nodetool-ai/sandbox-flow/nodetool.control";

const kept = [];
for await (const { slot, value } of take.stream({ input_item: [1, 2, 3], n: 2 })) {
  if (slot === "output") kept.push(value);
}

Arrays are the whole of streaming input in this version. An async iterable on an input handle is not accepted.

Errors

A node that fails rejects the call with its own error. There is no verdict machinery and no per-node error stream — your try/catch is the supervisor, and retry, fallback, and timeout are yours to write:

import "@nodetool-ai/sandbox-nodetool/flow";
import { textToSpeech } from "@nodetool-ai/sandbox-flow/gemini.audio";

try {
  return await textToSpeech({ text: draft });
} catch (error) {
  return { error: String(error) };
}

Fan-out

Concurrency is Promise.all, and it is real: the calls run at once.

const summaries = await Promise.all(
  documents.map((document) => summarizer({ text: document }))
);

Nothing throttles this. A hundred items is a hundred concurrent model calls — batch them yourself when that matters.

The untyped root

import { callNode } from "@nodetool-ai/sandbox-flow" takes a node type as a string and checks nothing until the host answers. Use it when the type is decided at run time; otherwise import the namespace, where a wrong name is an import error rather than a failed call.

Gotchas

  • Inputs are values, not handles. There is nothing to wire and no .output() — the call returns the outputs record.
  • No graph comes out of this. Nothing opens in the editor, validates, or replays. When the artifact matters, build a graph with @nodetool-ai/sandbox-dsl instead.
  • A missing property is the node's default, exactly as in a graph run.
  • Names follow the node class: nodetool.text.Concat is concat, nodetool.constant.Integer is integer. Reserved words take a trailing underscore (if_).

Version History

  • a6a7e57 Current 2026-08-20 09:52

Same Skill Collection

.claude/skills/ask-matt/SKILL.md
.claude/skills/ast-grep-outline/SKILL.md
.claude/skills/ast-grep/SKILL.md
.claude/skills/codebase-design/SKILL.md
.claude/skills/companion-clis/SKILL.md
.claude/skills/diagnosing-bugs/SKILL.md
.claude/skills/domain-modeling/SKILL.md
.claude/skills/flash/SKILL.md
.claude/skills/implement/SKILL.md
.claude/skills/improve-codebase-architecture/SKILL.md
.claude/skills/nodetool-api-reference/SKILL.md
.claude/skills/nodetool-browser-agent/SKILL.md
.claude/skills/nodetool-chat-cli/SKILL.md
.claude/skills/nodetool-custom-node-developer/SKILL.md
.claude/skills/nodetool-deployment/SKILL.md
.claude/skills/nodetool-model-provider-config/SKILL.md
.claude/skills/nodetool-rag-indexing/SKILL.md
.claude/skills/nodetool-troubleshooter/SKILL.md
.claude/skills/nodetool-workflow-builder/SKILL.md
.claude/skills/prototype/SKILL.md
.claude/skills/research/SKILL.md
.claude/skills/resolving-merge-conflicts/SKILL.md
.claude/skills/setup-matt-pocock-skills/SKILL.md
.claude/skills/tdd/SKILL.md
.claude/skills/to-spec/SKILL.md
.claude/skills/to-tickets/SKILL.md
.claude/skills/triage/SKILL.md
.claude/skills/wayfinder/SKILL.md
.claude/skills/wizard/SKILL.md
.claude/skills/yts806379-everything-claude-code-e2e-testing/SKILL.md
packages/sandbox-packs/sandbox-aws/SKILL.md
packages/sandbox-packs/sandbox-chrono/SKILL.md
packages/sandbox-packs/sandbox-color/SKILL.md
packages/sandbox-packs/sandbox-csv/SKILL.md
packages/sandbox-packs/sandbox-dates/SKILL.md
packages/sandbox-packs/sandbox-decimal/SKILL.md
packages/sandbox-packs/sandbox-diff/SKILL.md
packages/sandbox-packs/sandbox-docx/SKILL.md
packages/sandbox-packs/sandbox-dsl/SKILL.md
packages/sandbox-packs/sandbox-epub/SKILL.md
packages/sandbox-packs/sandbox-exif/SKILL.md
packages/sandbox-packs/sandbox-expr/SKILL.md
packages/sandbox-packs/sandbox-fabric/SKILL.md
packages/sandbox-packs/sandbox-gif/SKILL.md
packages/sandbox-packs/sandbox-html/SKILL.md
packages/sandbox-packs/sandbox-ics/SKILL.md
packages/sandbox-packs/sandbox-jmespath/SKILL.md
packages/sandbox-packs/sandbox-mammoth/SKILL.md
packages/sandbox-packs/sandbox-markdown/SKILL.md

Metadata

Files
0
Version
a6a7e57
Hash
f1f79215
Indexed
2026-08-20 09:52

- 위키
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-25 05:50
浙ICP备14020137号-1 $방문자$