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
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
run: completed
{
"Open_page_output": {
"url": "https://example.com"
},
"Read_heading_output": {
"heading": "Example Domain"
}
}
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.