Wer einen KI-Agenten wie die DeepSeek Harness bedient, bekommt als blinder Nutzer ein Problem, das Sehende gar nicht erst bemerken: Der Agent arbeitet unsichtbar im Hintergrund. Er ruft Tools auf, bekommt Ergebnisse, und schreibt eine Antwort. Aber was passiert eigentlich gerade? Das blieb mir lange verborgen - bis ich ein kleines Accessibility-Plugin dafür gebaut habe.
Das Ergebnis ist dsh-a11y-focus,
ein Plugin für die DeepSeek-Harness-WebUI. Es kündigt an, was der Agent gerade
tut, und zwar direkt über eine aria-live-Region. NVDA, JAWS und VoiceOver
lesen diese Region automatisch vor - ohne dass ich meinen Fokus verschieben
muss.
Was das Plugin ansagt
Das Herzstück sind zwei Signale, die für mich den Unterschied machen:
Tool-Aufrufe sofort. Sobald der Agent ein Tool aufruft, wird das sofort angesagt (“Tool: Name und Inhalt”). Entscheidend ist der Moment des Starts, nicht das Ende. Bei einer Such-Anfrage oder einem Datei-Zugriff höre ich also direkt, was gerade passiert, statt ins Leere zu warten.
Fertige Antworten. Die letzte abgeschlossene Antwort des Agents wird mit dem vollen Text über die Live-Region vorgelesen - aber erst, wenn sie wirklich fertig ist, nicht während sie noch schreibt. Die Erkennung läuft über Textstabilität: Erst wenn der Text 900 Millisekunden unverändert bleibt, gilt er als abgeschlossen.
Wie es funktioniert
Technisch ist es ein Client-Plugin, das über ein MutationObserver auf den
Chat-Container der Harness-WebUI schaut. Neue Elemente und Textänderungen
werden erfasst. Für die Ansage gibt es ein verstecktes, aber für Screenreader
sichtbares div mit aria-live="polite" und role="status".
Zwei Details haben mich beim Bauen beschäftigt:
- Das Plugin arbeitet mit
textContentstattinnerText. So werden auch eingeklappte oder ausgeblendete Tool-Call-Inhalte erfasst, dieinnerText(nur sichtbares DOM) unterschlagen würde. - Es gibt keinen zuverlässigen DOM-Attribut für “Streaming fertig”, weil React
das
streaming-Prop nicht ins DOM schreibt. Deshalb die Lösung über die Textstabilität mit Debounce - sie funktioniert unabhängig vom Framework.
Was bewusst nicht passiert
Das Plugin bewegt meinen Fokus nicht. Kein element.focus(), das die Nutzung
stören würde. Und es spielt beim Laden einer alten Session nichts nach: Nur
neue Ereignisse ab jetzt werden angesagt, keine schon vorhandenen Nachrichten.
Deep-Diving-Status
Während der “Deep diving…”-Status des Agents aktiv ist (also der Agent
arbeitet), wird das alle fünf Sekunden wiederholt angesagt, solange der
Zustand besteht. Die Erkennung läuft über ein role="status"-Element, dessen
Text “Deep diving” enthält - wichtig, weil die Harness zusätzlich ein leeres
role="status"-Element rendern kann. Deshalb wird über den Textinhalt
geprüft, nicht über das erste role="status".
Kontext
Das Plugin ist der Laufzeit-Unterbau meiner Arbeit mit Coding-Agenten. Wenn Tool-Aufrufe und Zwischenschritte nicht angesagt werden, ist man als blinder Nutzer auf Vermutungen angewiesen oder muss mühsam nachfragen. Mit dsh-a11y-focus höre ich einfach zu, was der Agent tut - wie jeder andere auch auf den Bildschirm schaut.
Der Quellcode liegt auf GitHub: slohmaier/dsh-a11y-focus. Dort findet sich auch die Installationsbeschreibung für die Harness. Wer mit den ungewohnten Abkürzungen dsh, cordis und den verschiedenen Bundle-Profilen starten will, findet im README die konkreten Schritte.