Zum Inhalt springen

UIAP Action Runtime

FeldWert
StatusDraft
Version0.1
Datum2026-03-27
Abhängigkeiten[UIAP-CORE], [UIAP-CAP]
EditorenPatrick

UIAP Action Runtime v0.1 definiert, wie eine UIAP-Gegenstelle eine angeforderte Action annimmt, das Ziel auflöst, Actionability prüft, die Ausführung wählt, den Erfolg verifiziert und strukturierte Ergebnisse zurückmeldet.

Die Runtime ist nicht auf Web beschränkt, enthält hier aber eine normative Web-Bindung über [email protected].

Die Schlüsselwörter MUSS, DARF NICHT, SOLLTE, KANN in diesem Dokument sind normativ gemäss RFC 2119 und BCP 14 zu interpretieren, wenn und nur wenn sie in GROSSBUCHSTABEN erscheinen.

Der Executor nimmt action.request entgegen und führt aus.

Der Controller sendet action.request, action.cancel und Confirmation-Antworten.

Optional. Zeigt Ghost Cursor, Highlights, Fokusrahmen oder Narration an.


  1. Eine Action MUSS einen klaren Lifecycle haben.
  2. Nicht-idempotente Actions DÜRFEN nicht blind wiederholt werden.
  3. Zielauflösung MUSS deterministisch und prüfbar sein.
  4. Erfolg MUSS über beobachtbare Signale verifiziert werden.
  5. User-Activation- und Trusted-Event-Grenzen MÜSSEN explizit modelliert werden.
  6. Presentation ist optional und darf die Ausführung nicht fälschen.

Eine Action hat genau einen dieser Zustände:

  • RECEIVED
  • RESOLVING_TARGET
  • CHECKING_PRECONDITIONS
  • AWAITING_CONFIRMATION
  • EXECUTING
  • VERIFYING
  • WAITING_FOR_USER
  • RECOVERING
  • SUCCEEDED
  • FAILED
  • CANCELLED

interface ActionRequestPayload {
actionId: ActionId;
target?: ActionTarget;
args?: Record<string, unknown>;
preferredExecutionModes?: ExecutionMode[];
verification?: VerificationSpec;
presentation?: PresentationHints;
timeoutMs?: number;
idempotencyKey?: string;
metadata?: Record<string, unknown>;
}
interface ActionTarget {
ref?: TargetRef;
expectedRole?: UIRole;
expectedName?: string;
expectedScopeId?: ScopeId;
expectedDocumentId?: DocumentId;
allowAmbiguous?: false; // default false
}
interface PresentationHints {
ghostCursor?: boolean;
highlight?: "none" | "outline" | "spotlight";
narration?: string;
pace?: "instant" | "humanized";
}
interface ActionAcceptedPayload {
actionHandle: string;
actionId: ActionId;
status: "accepted";
}
  • Eine gültige action.request MUSS mit action.accepted oder error beantwortet werden.
  • actionHandle MUSS innerhalb der Session eindeutig sein.

interface ActionProgressPayload {
actionHandle: string;
stage:
| "resolving_target"
| "checking_preconditions"
| "awaiting_confirmation"
| "executing"
| "verifying"
| "waiting_for_user"
| "recovering";
chosenExecutionMode?: ExecutionMode;
resolvedTarget?: ResolvedTarget;
note?: string;
detail?: Record<string, unknown>;
}

interface ActionConfirmationRequestPayload {
actionHandle: string;
actionId: ActionId;
risk: RiskDescriptor;
preview?: {
summary?: string;
target?: ResolvedTarget;
args?: Record<string, unknown>;
};
}
interface ActionConfirmationGrantPayload {
actionHandle: string;
}
interface ActionConfirmationDenyPayload {
actionHandle: string;
reason?: string;
}
  • Wenn risk.level="confirm" oder Policy dies verlangt, MUSS der Executor action.confirmation.request senden und anhalten.
  • Ohne action.confirmation.grant DARF die Action nicht fortgesetzt werden.
  • Eine Verweigerung MUSS mit action.result.status="cancelled" enden.

interface ActionCancelPayload {
actionHandle: string;
reason?: string;
}
interface ActionCancelledPayload {
actionHandle: string;
status: "cancelled";
reason?: string;
}

interface ActionResultPayload {
actionHandle: string;
actionId: ActionId;
status: "succeeded" | "failed" | "cancelled";
chosenExecutionMode?: ExecutionMode;
resolvedTarget?: ResolvedTarget;
verification: VerificationOutcome;
sideEffectState?: "none" | "applied" | "unknown";
stateRevision?: RevisionId;
returnValue?: Record<string, unknown>;
error?: RuntimeErrorDescriptor;
metadata?: Record<string, unknown>;
}

interface ResolvedTarget {
by: "stableId" | "instanceId" | "semantic" | "annotation" | "runtimeHint";
instanceId: ElementInstanceId;
stableId?: StableId;
documentId: DocumentId;
scopeId?: ScopeId;
role: UIRole;
name?: string;
bbox?: DOMRectLike;
}

interface VerificationSpec {
policy?: "capability-default" | "any" | "all" | "none";
signals?: SuccessSignal[];
timeoutMs?: number;
requireRevisionAdvance?: boolean;
}

interface VerificationOutcome {
passed: boolean;
policy: "capability-default" | "any" | "all" | "none";
observed: SuccessSignal[];
missing?: SuccessSignal[];
timeoutMs?: number;
}

type RuntimeErrorCode =
| "action_unsupported"
| "target_required"
| "target_not_found"
| "target_ambiguous"
| "stale_target"
| "target_not_interactable"
| "confirmation_denied"
| "user_activation_required"
| "cross_origin_unavailable"
| "closed_shadow_unavailable"
| "execution_mode_unavailable"
| "verification_failed"
| "unsafe_retry_refused"
| "cancelled"
| "internal_runtime_error";
interface RuntimeErrorDescriptor {
code: RuntimeErrorCode;
message: string;
retryable?: boolean;
detail?: Record<string, unknown>;
}

Die Runtime SOLLTE standardmäßig diesen Modus-Fallback verwenden:

  1. appAction
  2. semanticUi
  3. externalDriver
  4. inputSynthesis
  5. visionAssist
  • appAction ist fachlich am stabilsten.
  • semanticUi nutzt die vorhandene Web-Semantik.
  • externalDriver kann echte Browsersteuerung leisten.
  • inputSynthesis im Seitenkontext ist oft nur begrenzt vertrauenswürdig.
  • visionAssist ist teuer und fragiler.

Die konkrete Reihenfolge DARF pro App oder Policy angepasst werden.


Ein Executor MUSS Targets in dieser Reihenfolge auflösen:

  1. TargetRef.by = "stableId"
  2. TargetRef.by = "semantic" innerhalb erwarteter Scopes/Dokumente
  3. app-spezifische Annotationen wie meaning oder defaultAction
  4. lokale Runtime-Hints (css, xpath) nur als letzter technischer Fallback

Wenn mehrere Kandidaten gefunden werden, MUSS der Executor einen Score bilden aus:

  • Scope-Match
  • Role-Match
  • Name-Match
  • StableId-Match
  • sichtbarer Nähe zum aktuellen Fokus
  • deklarierter Default-Action

Wenn danach kein eindeutiger Sieger vorliegt, MUSS target_ambiguous geliefert werden.

Wenn ein bereits aufgelöstes Ziel vor der Ausführung nicht mehr attached oder nicht mehr konsistent ist, MUSS die Runtime einmal neu auflösen. Wenn auch das fehlschlägt, MUSS stale_target oder target_not_found geliefert werden.


Playwright behandelt robuste Interaktion nicht als „einfach draufklicken“, sondern prüft vor Aktionen Zustände wie Sichtbarkeit, Stabilität, Event-Empfang und Enabled-Status. UIAP übernimmt dieses Denkmodell ausdrücklich, weil Browser-UIs sonst bei jedem Re-Render anfangen, sich wie beleidigte Primadonnen aufzuführen. scrollIntoView() ist das Standardmittel, um Ziele sichtbar zu machen. ([Playwright][4])

Vor einer Ausführung MUSS der Executor mindestens prüfen:

  • Session ist aktiv
  • Action wird unterstützt
  • Policy erlaubt die Action
  • Ziel ist vorhanden
  • Ziel gehört nicht zu einem opaque Bereich

9.2 Für pointer-ähnliche Actions (ui.activate, ui.toggle, ui.choose)

Abschnitt betitelt „9.2 Für pointer-ähnliche Actions (ui.activate, ui.toggle, ui.choose)“
  • attached = true
  • visible = true
  • enabled != false
  • blocked != true
  • stable != false
  • obscured != true oder es gibt eine sichere Recovery
  • Ziel ist im Viewport oder kann dorthin gescrollt werden

9.3 Für Texteingabe (ui.enterText, ui.clearText, ui.setValue)

Abschnitt betitelt „9.3 Für Texteingabe (ui.enterText, ui.clearText, ui.setValue)“
  • editable = true oder Rolle ist textuell editierbar
  • readonly != true
  • enabled != false
  • Ziel kann fokussiert werden oder ist bereits fokussiert
  • Zielroute oder Link muss vorhanden oder direkt ausführbar sein

Wenn eine Prüfung scheitert, MUSS entweder Recovery versucht oder ein Fehler resultiert werden.


Direkte fachliche Ausführung über eine App-Registry.

  • SOLLTE bevorzugt werden, wenn verfügbar.
  • MUSS die fachliche Bedeutung der Action respektieren.
  • DARF ohne konkretes DOM-Ziel ausgeführt werden, wenn die Action dies zulässt.

Semantische Ausführung im Web-Kontext.

  • SOLLTE Plattformmethoden wie focus(), click(), scrollIntoView() oder kontrollspezifische Setter bevorzugen.
  • SOLLTE nur synthetische Eventsequenzen erzeugen, wenn keine semantisch reichere Methode existiert.
  • DARF sich nicht auf rohe dispatchEvent()-Tricks als Standard verlassen.

HTMLElement.click() simuliert einen Klick und feuert das Click-Event, sofern das Element nicht disabled ist. Per dispatchEvent() erzeugte Events sind dagegen nicht isTrusted, und Features mit Aktivierungszwang verlangen laut Plattform trusted triggering input events. Deshalb MUSS die Runtime user_activation_required als erstklassigen Fall behandeln, statt so zu tun, als würde JavaScript allein eine echte Nutzerinteraktion herbeizaubern. ([MDN Web Docs][5])


Ausführung über externe Browsersteuerung.

  • DARF verwendet werden, wenn ein Out-of-Process-Driver verfügbar ist.
  • MUSS denselben Action-Lifecycle und dieselben Verification-Regeln einhalten.
  • WebDriver BiDi oder äquivalente Mechanismen SIND zulässige Implementierungen.

Low-Level-Eingabesynthese.

  • DARF verwendet werden, wenn semanticUi nicht ausreicht.
  • Ein In-Page-Executor MUSS diesen Modus als nicht user-activation-sicher behandeln.
  • Dieser Modus SOLLTE nicht für sicherheitskritische oder browsergated Flows verwendet werden.

Visueller Fallback.

  • DARF nur verwendet werden, wenn die anderen Modi nicht verfügbar oder erfolglos sind.
  • MUSS den gewählten Zielpunkt und die nachgelagerte Verifikation dokumentieren.

Liest Zustand, Text, Value oder Beschreibung eines Targets.

  • returnValue SOLLTE den gelesenen Zustand oder Inhalt tragen.

Fokussiert das Ziel.

  • focus.target == instanceId

Reine Präsentationsaction.

  • Muss nicht den Web-State ändern.
  • verification.policy="none" ist zulässig.

Aktiviert ein Ziel.

  • Bevorzugt appAction
  • sonst semanticUi mit scrollIntoView() und Aktivierung
  • nur wenn nötig andere Modi
  • capability-default oder angeforderte Success Signals

Schreibt Text in ein editierbares Feld.

  • Ziel fokussieren
  • optional bestehenden Wert löschen
  • Wert setzen
  • app-kompatible Eingabesemantik auslösen
  • Ergebniswert verifizieren
  • value.equals oder element.state.textValue

Setzt textuellen Inhalt auf leer.

Wählt eine Option in combobox, listbox, select oder ähnlichen Kontrollen.

Ändert einen binären oder tri-state Zustand.

Öffnet bzw. schließt expandierbare Ziele.

Öffnet oder schließt modale oder temporäre Oberflächen.

Bringt ein Ziel in den sichtbaren Bereich.

Scrollt ein Element oder den Viewport.

Schließt eine formularähnliche Interaktion ab.

Wechselt Route oder URL.

Führt eine deklarierte Domain Action aus.


Wenn verification nicht gesetzt ist, MUSS die Runtime folgendes verwenden:

  1. success-Signale aus dem ActionDescriptor, falls vorhanden
  2. sonst success-Signale des Ziels, falls vorhanden
  3. sonst eine profiltypische Minimalverifikation

Für Web SOLLTE Minimalverifikation so aussehen:

  • bei ui.focus: Fokus ist auf dem Ziel
  • bei ui.enterText: Zielwert entspricht erwartetem Wert
  • bei ui.activate: mindestens eine plausible Zustandsänderung, z. B. Route-Wechsel, Dialogwechsel, Toast, Zustandsdelta
  • bei nav.navigate: Route oder URL hat gewechselt
  • bei ui.highlight: keine State-Verifikation nötig
  • none: keine formale Verifikation
  • any: mindestens ein Signal muss eintreten
  • all: alle Signale müssen eintreten
  • capability-default: app- oder zielseitige Defaults

Wenn requireRevisionAdvance=true, MUSS mindestens eine neue PageGraph-Revision beobachtet werden, bevor Erfolg erklärt wird.


Die Runtime DARF Recovery-Versuche machen, MUSS aber vorsichtig bleiben.

  • erneut auflösen bei stale target
  • scrollIntoView bei offscreen target
  • kurze Re-Waits bei vorübergehendem Busy-/Loading-Zustand
  • erneute Verifikation nach dokumentierter UI-Aktualisierung
  • erneutes Auslösen nicht-idempotenter Actions ohne sichere Kenntnis des Side-Effect-Status
  • Überspringen nötiger Bestätigungen
  • Zugriff in opaque Cross-Origin- oder Closed-Shadow-Bereiche

Bei Fehlschlag MUSS sideEffectState gesetzt werden auf:

  • none
  • applied
  • unknown

Für nicht-idempotente Actions MUSS unknown als hartes Warnsignal behandelt werden.


Das Web begrenzt bewusst APIs, die schlechte Nutzererfahrungen oder Missbrauch verursachen könnten; einige Features funktionieren nur bei aktiver oder bereits erfolgter User Activation, und die auslösenden Input-Events müssen trusted sein. Deshalb MUSS UIAP eine Action sauber anhalten und waiting_for_user oder user_activation_required melden können, statt Browser-Sicherheitsgrenzen mit Script-Zauberei wegzudiskutieren. ([MDN Web Docs][2])

Wenn eine Action daran scheitert, MUSS der Executor:

  1. action.progress mit stage="waiting_for_user" senden,
  2. einen verständlichen note-Text publizieren,
  3. nach tatsächlicher Nutzerinteraktion FORTSETZEN oder sauber FEHLSCHLAGEN.

Kein passendes Ziel gefunden.

Mehrere plausible Ziele, kein eindeutiger Sieger.

Ziel existiert, ist aber nicht ausführbar.

Ausführung benötigt echte Nutzerinteraktion.

Ziel liegt in einem opaque Cross-Origin-Bereich.

Ziel liegt in einem geschlossenen Shadow Root ohne Bridge.

Ausführung lief, aber erwartete Signale blieben aus.

Retry wäre fachlich oder sicherheitstechnisch unzulässig.


Ein konformer Runtime Executor MUSS:

  • action.request annehmen,
  • Zielauflösung aus stableId und semantischen Targets unterstützen,
  • Precondition Checks ausführen,
  • mindestens appAction oder semanticUi unterstützen,
  • Confirmation Flows unterstützen,
  • Success Signals verifizieren,
  • action.result mit verification und optional error senden.

{
"uiap": "0.1",
"kind": "request",
"type": "action.request",
"id": "msg_77",
"sessionId": "sess_123",
"ts": "2026-03-26T14:03:00.000Z",
"source": { "role": "agent", "id": "onboarding-agent" },
"payload": {
"actionId": "ui.activate",
"target": {
"ref": { "by": "stableId", "value": "video.submit" },
"expectedRole": "button",
"expectedName": "Video erstellen"
},
"verification": {
"policy": "all",
"signals": [
{ "kind": "route.changed", "pattern": "/videos/:id" },
{ "kind": "toast.contains", "text": "erstellt" }
],
"timeoutMs": 8000,
"requireRevisionAdvance": true
},
"presentation": {
"ghostCursor": true,
"highlight": "spotlight",
"pace": "humanized"
},
"timeoutMs": 12000
}
}
{
"uiap": "0.1",
"kind": "response",
"type": "action.accepted",
"id": "msg_78",
"correlationId": "msg_77",
"sessionId": "sess_123",
"ts": "2026-03-26T14:03:00.015Z",
"source": { "role": "bridge", "id": "web-runtime" },
"payload": {
"actionHandle": "act_991",
"actionId": "ui.activate",
"status": "accepted"
}
}
{
"uiap": "0.1",
"kind": "event",
"type": "action.progress",
"id": "msg_79",
"sessionId": "sess_123",
"ts": "2026-03-26T14:03:00.020Z",
"source": { "role": "bridge", "id": "web-runtime" },
"payload": {
"actionHandle": "act_991",
"stage": "resolving_target",
"resolvedTarget": {
"by": "stableId",
"instanceId": "el_submit",
"stableId": "video.submit",
"documentId": "doc_root",
"scopeId": "scope_form",
"role": "button",
"name": "Video erstellen",
"bbox": { "x": 120, "y": 420, "width": 180, "height": 40 }
}
}
}
{
"uiap": "0.1",
"kind": "event",
"type": "action.result",
"id": "msg_80",
"sessionId": "sess_123",
"ts": "2026-03-26T14:03:01.220Z",
"source": { "role": "bridge", "id": "web-runtime" },
"payload": {
"actionHandle": "act_991",
"actionId": "ui.activate",
"status": "succeeded",
"chosenExecutionMode": "semanticUi",
"resolvedTarget": {
"by": "stableId",
"instanceId": "el_submit",
"stableId": "video.submit",
"documentId": "doc_root",
"scopeId": "scope_form",
"role": "button",
"name": "Video erstellen"
},
"verification": {
"passed": true,
"policy": "all",
"observed": [
{ "kind": "route.changed", "pattern": "/videos/:id" },
{ "kind": "toast.contains", "text": "erstellt" }
],
"timeoutMs": 8000
},
"sideEffectState": "applied",
"stateRevision": "rev_20"
}
}

  • [UIAP-CORE] UIAP Core v0.1
  • [UIAP-CAP] UIAP Capability Model v0.1
  • [RFC2119] Key words for use in RFCs to Indicate Requirement Levels, BCP 14
  • Action-Handler MÜSSEN Eingabeparameter validieren, bevor sie fachliche Operationen ausführen.
  • sideEffectState MUSS korrekt gemeldet werden, um unbeabsichtigte Zustandsänderungen nachvollziehbar zu machen.
  • Nicht-idempotente Actions SOLLTEN keine automatischen Retries ausführen.
  • Der Confirmation-Flow MUSS manipulationssicher sein; eine granted-Antwort DARF nur von einer autorisierten Quelle stammen.
VersionDatumÄnderungen
0.12026-03-27Initialer Entwurf