zebflow 0.11.14

Reactive web automation platform — pipelines, templates, and real-time collaboration in a single binary.
Documentation
{
  "apiVersion": "zebflow.com/v1",
  "kind": "Pipeline",
  "metadata": {
    "name": "openai-embed"
  },
  "spec": {
    "id": "openai-embed",
    "nodes": [
      {
        "id": "trigger",
        "kind": "trigger.function",
        "config": {
          "description": "Embeds one text or a list of texts with the chosen provider's embedding model."
        },
        "input_pins": [],
        "output_pins": [
          "out"
        ]
      },
      {
        "id": "prepare",
        "kind": "javascript.script.run",
        "config": {
          "source": "var a = input.function; var p = ctx.placeholder || {}; var text = [].concat(a.text === undefined || a.text === null ? [] : a.text); text = [].concat.apply([], text).map(function (t) { return t === null || t === undefined ? '' : String(t); }); if (text.length === 0 || text.some(function (t) { return t.trim() === ''; })) throw new Error('--text is empty; it needs the text to embed'); if (text.length > 2048) throw new Error('--text gives ' + text.length + ' texts; at most 2048 are embedded at once'); var model = a.model || p.MODEL || (a.provider === 'openrouter' ? 'openai/text-embedding-3-small' : 'text-embedding-3-small'); return { model: String(model), input: text };"
        },
        "input_pins": [
          "in"
        ],
        "output_pins": [
          "out"
        ]
      },
      {
        "id": "call",
        "kind": "http.response.fetch",
        "config": {
          "method": "POST",
          "url": "{{ ($placeholder.BASE_URL || (input.function.provider === 'openrouter' ? 'https://openrouter.ai/api/v1' : 'https://api.openai.com/v1')).replace(/\\/$/, '') }}{{ $placeholder.EMBEDDING_PATH || '/embeddings' }}",
          "headers": {
            "Authorization": "Bearer {{ $placeholder.API_KEY }}",
            "Content-Type": "application/json"
          },
          "body": "{{ input.script }}",
          "timeout": "2m"
        },
        "input_pins": [
          "in"
        ],
        "output_pins": [
          "out"
        ]
      },
      {
        "id": "answer",
        "kind": "javascript.script.run",
        "config": {
          "source": "var r = input.response || {}; var b = r.body || {}; if (!r.ok || !Array.isArray(b.data)) throw new Error('the provider answered no embeddings: ' + (b.error ? (b.error.message || JSON.stringify(b.error)) : ('HTTP ' + r.status))); var vectors = b.data.slice().sort(function (x, y) { return (x.index || 0) - (y.index || 0); }).map(function (d) { return d.embedding; }); return { vectors: vectors, model: b.model, dims: vectors.length ? vectors[0].length : 0, usage: b.usage || null };"
        },
        "input_pins": [
          "in"
        ],
        "output_pins": [
          "out"
        ]
      }
    ],
    "edges": [
      {
        "from_node": "trigger",
        "from_pin": "out",
        "to_node": "prepare",
        "to_pin": "in"
      },
      {
        "from_node": "prepare",
        "from_pin": "out",
        "to_node": "call",
        "to_pin": "in"
      },
      {
        "from_node": "call",
        "from_pin": "out",
        "to_node": "answer",
        "to_pin": "in"
      }
    ]
  }
}