Zum Inhalt springen

Workflows aus Blöcken bauen

Setze Navigation, Aktionen, Extraktion und Kontrollfluss zu einem versionierten Workflow zusammen: neun Blocktypen, unveränderliche Versionen, Label als Variablen.

Zuletzt aktualisiert:

Eine Linie ist schon ein Graph

login credentialId navigation fällt durch conditional erster Treffer gewinnt extraction Schema → Run-Ergebnis action nextBlockLabel: navigation Treffer otherwise finallyBlockLabel läuft immer zuletzt -- außer bei Cancel ein Block ohne nextBlockLabel fällt in Deklarationsreihenfolge durch -- eine gerade Linie ist der Graph, in dem jede Kante die offensichtliche ist
Blöcke ohne nextBlockLabel fallen in Deklarationsreihenfolge durch; explizite Kanten gibt es nur dort, wo der Fluss verzweigt.

Blöcke, Versionen und Label

Ein Workflow ist eine Liste von Blöcken. Hat ein Block kein nextBlockLabel, fällt die Ausführung zum nächsten Block in Deklarationsreihenfolge durch — eine einfache Sequenz ist also der Graph, in dem jede Kante die offensichtliche ist, und eine Kante zeichnest du nur, wenn du eine Verzweigung meinst.

Jedes Veröffentlichen erzeugt eine neue, unveränderliche Version, und ein Run führt die Version aus, mit der er gestartet ist; ein Publish mitten im Run ändert nichts, was schon läuft. Block-Label müssen gültige Bezeichner sein (Read_heading, keine Phrase mit Leerzeichen), denn ein Label wird zur Template-Variablen: Ein späterer Block kann {{Read_heading_output.heading}} referenzieren.

Die neun Blocktypen

Die Typ-Spalte nennt das Feld, um das sich der jeweilige Block dreht.

Name Typ Beschreibung
navigation url Öffnet eine URL. Die einfachste Kante des Graphen.
action instruction Eine Anweisung, optional mit zusammengesetztem XPath-Selektor. aiFallback bestimmt, ob das Modell proaktiv handelt oder erst, wenn der Selektor scheitert (proactive|fallback).
extraction instruction Zieht strukturierte Daten aus der Seite, optional gegen ein JSON-Schema.
login credentialId Meldet sich mit einem Tresor-Datensatz an. Der Block trägt eine Credential-Id, nie ein Geheimnis.
validation criterion Prüft ein Kriterium gegen die Seite und lässt den Run scheitern, wenn es nicht gilt.
code code Kunden-JavaScript. Es läuft im Session-Container, nie im Plattform-Prozess.
http_request method, url Ruft eine externe API auf und reicht die Antwort an spätere Blöcke weiter.
loop over Wiederholt verschachtelte Blöcke über eine Liste, begrenzt durch maxIterations.
conditional branches Verzweigt anhand von Kriterien. Alle Kriterien werden in einem einzigen Modellaufruf gegen einen Snapshot beantwortet; der erste zutreffende Zweig gewinnt.

Veröffentlichen, starten, pollen

Voraussetzungen: api-key inference

BASE="https://browserberg.com"
AUTH="Authorization: Bearer $BROWSERBERG_API_KEY"
JSON="Content-Type: application/json"

# Publish. Every publish is a new immutable version; labels must be valid
# identifiers because they become template variables.
WFID=$(curl -s -X POST "$BASE/v1/workflows" -H "$AUTH" -H "$JSON" -d '{
  "title": "Read the example heading",
  "blocks": [
    { "blockType": "navigation", "label": "Open_page", "url": "https://example.com" },
    { "blockType": "extraction", "label": "Read_heading",
      "instruction": "the page heading",
      "schema": { "type": "object", "properties": { "heading": { "type": "string" } } } }
  ]
}' | python3 -c 'import json,sys; print(json.load(sys.stdin)["workflow"]["workflowId"])')

SID=$(curl -s -X POST "$BASE/v1/sessions" -H "$AUTH" -H "$JSON" -d '{"ttlSeconds": 300}' \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["session"]["id"])')

RUNID=$(curl -s -X POST "$BASE/v1/workflows/$WFID/runs" -H "$AUTH" -H "$JSON" \
  -d "{\"sessionId\": \"$SID\"}" \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["run"]["runId"])')

# Poll until terminal.
for i in $(seq 1 90); do
  STATUS=$(curl -s "$BASE/v1/workflow-runs/$RUNID" -H "$AUTH" \
    | python3 -c 'import json,sys; print(json.load(sys.stdin)["run"]["status"])')
  if [ "$STATUS" != "running" ]; then break; fi
  sleep 2
done

echo "run: $STATUS"
curl -s "$BASE/v1/workflow-runs/$RUNID" -H "$AUTH" \
  | python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["run"]["outputs"], indent=2))'

curl -s -X DELETE "$BASE/v1/sessions/$SID" -H "$AUTH" > /dev/null

Reihenfolge, Aufräumen, Validierung

Für Portale, die pro Login nur eine Sitzung erlauben, setze runSequentially mit einem sequentialKey: Runs mit demselben Schlüssel stellen sich an, statt sich gegenseitig die Anmeldung zu kappen. finallyBlockLabel benennt einen Block, der bei jedem abgeschlossenen oder gescheiterten Run zuletzt läuft — mit einer bewussten Ausnahme: Bei einem Abbruch läuft er nicht, denn Abbruch heißt sofort stoppen, nicht erst nach weiteren Schritten.

Veröffentlichst du etwas Ungültiges, liefert die API alle Validierungsfehler auf einmal, jeden mit Code und Position — eine Runde, um die ganze Definition zu reparieren, nicht eine pro Fehler.

Stilisierte Ansicht eines Browserberg-Workflows mit sequenziell verbundenen Blöcken und einer Verzweigung
Versionen sind unveränderlich; ein laufender Workflow endet auf der Version, mit der er begonnen hat.

Weiterbauen

  • Workflow-Heilung Wenn sich das Portal unter einem laufenden Workflow ändert
  • Zeitplan-Trigger Den Workflow jede Nacht um 02:30 laufen lassen
  • Referenz Workflows Jedes Blockfeld im Detail