SWIRLS_
Language

Node Types

Configuration reference for every node type available in .swirls files.

Nodes are the building blocks of a graph. Each node has a type field that determines its behavior. This page documents all available node types, their fields, and examples.

For how nodes connect to each other, see Graphs. For type-safe access to node outputs, see Context.

code

Run TypeScript in an isolated sandbox.

FieldTypeRequiredDescription
code@ts { } blockNoTypeScript to execute. Access context.nodes for input. Return value becomes output.
schema@json { } blockNoOutput schema (JSON Schema).
node normalize {
  type: code
  label: "Normalize email"
  outputSchema: @json {
    { "type": "object", "required": ["email"], "properties": { "email": { "type": "string" } }, "additionalProperties": false }
  }
  code: @ts {
    const email = context.nodes.root.input.email ?? ""
    return { email: email.toLowerCase().trim() }
  }
}

ai

Invoke an AI model. Supports multiple kinds: text, object, image, video, and embed.

FieldTypeRequiredDescription
kindstringYesOne of: text, object, image, video, embed.
modelstringYesModel identifier (e.g. "anthropic/claude-3.5-sonnet", "openai/dall-e-3").
prompt@ts { } blockYesTypeScript expression returning the prompt string.
temperaturenumberNoSampling temperature.
maxTokensnumberNoMax output tokens.
optionsobjectNoKind-specific options (e.g. { n: 1, size: "1024x1024" } for image).
schema@json { } blockNoOutput schema. Required for the object kind.

Example (object kind):

node classify {
  type: ai
  label: "Classify intent"
  kind: object
  model: "anthropic/claude-3.5-sonnet"
  prompt: @ts {
    return `Classify this message: ${context.nodes.root.input.message}`
  }
  schema: @json {
    {
      "type": "object",
      "required": ["intent", "confidence"],
      "properties": {
        "intent": { "type": "string" },
        "confidence": { "type": "number" }
      }
    }
  }
}

Example (image kind):

node generate_image {
  type: ai
  label: "Generate image"
  kind: image
  model: "openai/dall-e-3"
  prompt: @ts {
    return `A professional illustration of: ${context.nodes.root.input.topic}`
  }
  options: {
    n: 1
    size: "1024x1024"
  }
}

switch

Conditional routing. Returns a case name to determine which branch executes.

FieldTypeRequiredDescription
casesstring arrayYesList of case names.
router@ts { } blockYesTypeScript expression returning one of the case names.

Use labeled edges in the flow block: route -["case_name"]-> target.

node route {
  type: switch
  label: "Route by priority"
  cases: ["high", "medium", "low"]
  router: @ts {
    const score = context.nodes.root.output.score ?? 0
    if (score > 80) return "high"
    if (score > 40) return "medium"
    return "low"
  }
}

http

Make HTTP requests to external APIs.

FieldTypeRequiredDescription
url@ts { } block or stringYesRequest URL.
methodstringNoHTTP method. Defaults to GET.
headersobjectNoRequest headers.
body@ts { } blockNoRequest body.
schema@json { } blockNoOutput schema.
node fetch_data {
  type: http
  label: "Fetch from API"
  method: "POST"
  url: @ts {
    return `https://api.example.com/data/${context.nodes.root.input.id}`
  }
  headers: {
    "Content-Type": "application/json"
    "Authorization": @ts {
      return `Bearer ${context.secrets.API_KEY}`
    }
  }
  body: @ts {
    return JSON.stringify({ query: context.nodes.root.input.query })
  }
  schema: @json {
    { "type": "object", "properties": { "results": { "type": "array" } } }
  }
}

email

Send emails with dynamic content.

FieldTypeRequiredDescription
from@ts { } block or stringYesSender address.
to@ts { } block or stringYesRecipient address.
subject@ts { } block or stringYesSubject line.
text@ts { } block or stringNoPlain text body.
html@ts { } block or stringNoHTML body.
schema@json { } blockNoOutput schema.
node send_email {
  type: email
  label: "Send notification"
  from: @ts { return "[email protected]" }
  to: @ts { return context.nodes.root.output.email }
  subject: @ts { return "Your request has been processed" }
  text: @ts {
    return `Hello ${context.nodes.root.output.name}, your request is complete.`
  }
}

stream

Query persisted data from a graph's stream.

FieldTypeRequiredDescription
streamstringYesStream name (from a graph's persistence block).
query@sql { } blockNoSQL query with {{table}} placeholder.
schema@json { } blockNoOutput schema.
node recent_submissions {
  type: stream
  label: "Recent submissions"
  stream: "submissions"
  outputSchema: @json {
    {
      "type": "object",
      "required": ["results", "pageInfo"],
      "properties": {
        "results": { "type": "array", "items": { "type": "object" } },
        "pageInfo": { "type": "object" }
      },
      "additionalProperties": false
    }
  }
  query: @sql {
    SELECT * FROM {{table}} ORDER BY created_at DESC LIMIT 10
  }
}

graph

Execute another graph as a subgraph.

FieldTypeRequiredDescription
graphstringYesName of the graph to execute.
input@ts { } blockYesTypeScript expression mapping input for the subgraph.
node run_enrichment {
  type: graph
  label: "Run enrichment"
  graph: "enrich_contact"
  input: @ts {
    return { email: context.nodes.root.input.email, name: context.nodes.root.input.name }
  }
}

scrape

Fetch and extract content from web pages.

FieldTypeRequiredDescription
url@ts { } blockYesURL to scrape.
selectorstringNoCSS selector to extract.
schema@json { } blockNoOutput schema.

wait

Pause execution for a duration.

FieldTypeRequiredDescription
durationnumberNoSeconds to wait.

bucket

Storage operations: get, put, and delete.

FieldTypeRequiredDescription
operationstringYesOne of: get, put, delete.
bucketstringNoBucket name.
keystringNoObject key.
schema@json { } blockNoOutput schema.

document

Document processing node.

FieldTypeRequiredDescription
schema@json { } blockNoOutput schema.

On this page