BrowserToolHandler: Puppeteer-Browserautomatisierung
Verantwortung
BrowserToolHandler ist der Einstiegspunkt, über den Cline den Browser bedient, und entspricht dem Werkzeugnamen ClineDefaultTool.BROWSER. Das Modell wählt über den Parameter action die konkrete Operation: launch (URL öffnen), click (Koordinatenklick), type (Text in den aktuellen Fokus eingeben), scroll_up/scroll_down (Seite scrollen), close (Browser schließen) (class declaration:12-13). Nach jeder Aktion wird ein Screenshot sowie die in diesem Fenster angefallenen console logs zurückgegeben, damit das Modell den Seitenzustand visuell erfasst.
Der Handler selbst ist nur eine „Fassade": Er übernimmt nach einem tool_use die Parametervalidierung, Approval und den Hook und reicht die Aktion dann an die BrowserSession-Instanz config.services.browserSession weiter. Der echte Browser-Prozess, die Puppeteer-API, die Screenshot-Codierung und die Remote-Browser-Verbindung liegen alle in der BrowserSession (class BrowserSession:38). Die BrowserSession nutzt puppeteer-core, um sich mit einem lokalen Chrome oder einem Remote-Browser zu verbinden, und erhält über connect/launch die Browser/Page-Objekte.
Die Positionierung dieses Werkzeugs in Cline ist die einer „Capability Tool" (Fähigkeits-Werkzeug) auf gleicher Ebene wie file ops und web fetch: eine vom ToolExecutor angestoßene einmalige Ausführungseinheit. Die Besonderheit ist, dass es zustandsbehaftet ist: Innerhalb einer Task gibt es nur eine Browsersitzung, nach launch verwenden alle nachfolgenden click/type/scroll-Aktionen dieselbe Page, bis close oder ein Fehler auftritt. Deshalb ruft der Handler in jedem Fehlerzweig closeBrowser() auf — ein Browser-Prozess darf nicht zurückbleiben.
Entwurfsmotivation
- Sitzungs-Wiederverwendung: Nach launch wird die Page bis close weiterverwendet, damit nicht bei jedem click neu geöffnet wird; außerdem kann das Modell über mehrere Aktionen hinweg Login-Status und Scroll-Position halten (
launchBrowser:155). - Screenshot + Console-Logs dual: Nach jeder Aktion wartet
doAction500 ms auf Console-Stille und liefert dann Screenshot + Logs zusammen an das Modell zurück, um die Lücke rein visueller Erfassung (keine JS-Fehler sichtbar) zu schließen (doAction:378). - Launch mit eigenem Approval: Einen Browser zu öffnen ist eine hochriskante Aktion; launch läuft über den eigenen ask-Typ
browser_action_launch, während andere Aktionen (click/type/scroll) nach erfolgter launch-Freigabe standardmäßig durchgehen (launch flow:81). - Remote-Browser-Fallback: Schlägt die Remote-Browser-Verbindung fehl, wird auf den lokalen Modus herabgestuft, damit das Werkzeug als Ganzes nicht abstürzt (
remote fallback:181-198). - Nach click auf Navigation warten: Ein Klick kann eine Seitennavigation auslösen; doAction lauscht bei click auf
request-Ereignisse, um Netzwerkaktivität zu erkennen, und ruft ggf.waitForNavigationauf (click:528-561). - Browser zwingend schließen vor Werkzeugwechsel: Im Ergebnis wird der Hinweis „REMEMBER ... non-browser_action tools erst nach close des Browsers verwenden" angefügt, damit das Modell nicht bei offenem Browser zu Dateiänderungen wechselt (
result reminder:190-194).
Schlüsseldateien
class declaration:12—export class BrowserToolHandler implements IFullyManagedTool,name = ClineDefaultTool.BROWSER.handlePartialBlock:19— Streaming-Zweig: launch geht über den ask-Typbrowser_action_launch, andere Aktionen sagen direkt die aktuelle Koordinate/den Text.execute:62— Hauptfluss: action validieren → launch-Zweig oder click/type/scroll/close-Zweig → Screenshot + Logs zurückgeben.launch flow:81-127— Vollständiger launch-Ablauf: url validieren, approval, PreToolUse hook,applyLatestBrowserSettingsaktualisiert die Session,launchBrowser+navigateToUrl.click/type param check:130-145— Bei click fehlt coordinate oder bei type fehlt text: jeweils Fehlermeldung und closeBrowser.action dispatch:163-179— switch verteilt aufbrowserSession.click/type/scrollDown/scrollUp/closeBrowser.result format:184-203— launch/click/type/scroll liefern Screenshot + Logs, close liefert reinen Text-Hinweis.error close:205-208— Jede Ausnahme führtcloseBrowseraus, kein Browser-Prozess bleibt zurück.launchBrowser:155— Remote-Vorrang, bei Misserfolg Fallback auf lokal, dannbrowser.newPage()für neuen Tab.doAction:378— console/pageerror-Listener anhängen, Aktion ausführen, 500 ms auf Stille warten, Screenshot, Listener aufräumen.navigateToUrl:481—page.gotomitdomcontentloaded + networkidle2, danachwaitTillHTMLStablepollt die HTML-Größe.click:528— Koordinaten zerlegen,page.mouse.click, auf request lauschen und entscheiden, ob auf Navigation gewartet wird.screenshot:441— webp bevorzugt, bei Misserfolg Fallback auf png; schlagen beide fehl, wird geworfen und screenshot_error-Telemetrie gesendet.
Datenfluss
Der launch-Zweig ist der vollständigste Ablauf des BrowserToolHandler: url validieren → approval → hook → browserSession aktualisieren → Browser öffnen → navigieren → Screenshot und Logs zurückgeben. Der Schlüsselcode:
// apps/vscode/src/core/task/tools/handlers/BrowserToolHandler.ts
if (action === "launch") {
if (!url) {
config.taskState.consecutiveMistakeCount++
const errorResult = await config.callbacks.sayAndCreateMissingParamError(this.name, "url")
await config.services.browserSession.closeBrowser()
return errorResult
}
config.taskState.consecutiveMistakeCount = 0
// ... approval + PreToolUse hook ...
await config.callbacks.say("browser_action_result", "")
config.services.browserSession = await config.callbacks.applyLatestBrowserSettings()
await config.services.browserSession.launchBrowser()
browserActionResult = await config.services.browserSession.navigateToUrl(url)
}Beachten Sie die Zeile config.services.browserSession = await config.callbacks.applyLatestBrowserSettings(): Sie aktualisiert nicht nur die Einstellungen, sondern ersetzt auch die von ToolExecutor gehaltene browserSession-Referenz, sodass nachfolgende Browser-Tool-Aufrufe dieselbe neue Session erhalten (applyLatestBrowserSettings:125).
navigateToUrl läuft intern über doAction, und alle Nicht-launch-Aktionen gehen ebenfalls über doAction. doAction setzt Screenshot + console-Logs zu einem BrowserActionResult zusammen:
// apps/vscode/src/services/browser/BrowserSession.ts
const screenshotType = this.useWebp ? "webp" : "png"
let screenshotBase64 = await this.page.screenshot({ ...options, type: screenshotType })
let screenshot = `data:image/${screenshotType};base64,${screenshotBase64}`
if (!screenshotBase64) {
screenshotBase64 = await this.page.screenshot({ ...options, type: "png" })
screenshot = `data:image/png;base64,${screenshotBase64}`
}
return {
screenshot,
logs: logs.join("\n"),
currentUrl: this.page.url(),
currentMousePosition: this.currentMousePosition,
}Der Handler verpackt dieses Resultat als formatResponse.toolResult und fügt die starke Erinnerung „Browser erst schließen, dann zu anderen Werkzeugen wechseln" an.
Grenzen und Fehler
- Ungültige action: Beim Abschluss des Blocks ist die action nicht in der Liste
browserActions,consecutiveMistakeCount+++sayAndCreateMissingParamError+closeBrowser(invalid action:69-75). - launch ohne url: launch muss url mitbringen; fehlt sie, erfolgt ebenfalls mistake++ und closeBrowser (
missing url:82-87). - click ohne coordinate / type ohne text: Bei fehlendem Parameter wird ein Fehler gemeldet und closeBrowser aufgerufen, damit keine Session zurückbleibt (
param checks:131-145). - Remote-Browser-Verbindung fehlgeschlagen: Wenn
launchRemoteBrowserwirft, wird nach catch auflaunchLocalBrowserherabgestuft und remote_browser_launch_error per Telemetrie aufgezeichnet (remote fallback:181-198). - Screenshot fehlgeschlagen: Schlägt webp fehl, wird auf png retry gewechselt; schlagen beide fehl, wird "Failed to take screenshot." geworfen und screenshot_error-Telemetrie gesendet (
screenshot retry:448-466). - page nicht gestartet:
doActionprüftthis.pageund wirft, falls nicht vorhanden, mit dem Hinweis „Browser is not launched"; das passiert typischerweise bei Nicht-browser_action-Werkzeugen (die eigentlich keine Berechtigung haben) oder nach einem vorherigen close (page check:379-383). - Jede Ausnahme schließt den Browser: Der try/catch-Fallback des Handlers ist
browserSession.closeBrowser(), um sicherzustellen, dass kein Chrome-Prozess Ressourcen blockiert (error close:205-208).
Zusammenfassung
BrowserToolHandler ist eine dünne Hülle; die eigentliche Arbeit macht die BrowserSession. Das Modell wählt über den action-Parameter launch/click/type/scroll/close; der Handler übernimmt Parameter-Validierung und Approval und reicht die Aktion an die Puppeteer-Aufrufe der BrowserSession weiter, um dann Screenshot und console-Logs an das Modell zurückzugeben. launch hat ein eigenes Approval, die anderen Aktionen verwenden die bereits geöffnete Sitzung; bei jedem Fehler wird der Browser zwangsgeschlossen.
Wer tiefer einsteigen will, kann weiterlesen bei:
- Datei- und Befehls-Werkzeuge:
/cap-tools/file-ops - Web fetch/search:
/cap-tools/web - Werkzeug-Dispatch-Pfad:
/agent-loop/task-class
Siehe offizielle Dokumentation: Cline-Dokumentation · README