@@ -76,11 +76,12 @@ function recordNotice(notice: string): void {
7676}
7777
7878/**
79- * Takeover state lives here (session-level, not in the page) so the panel's
80- * takeover strip survives navigations and tab switches. The reason rides
81- * every page-state push; the panel's Done chip sends `takeover-done`.
79+ * True while browser_request_takeover waits on the user. The Done chip on the
80+ * chat's takeover tool row completes it via the `takeover-done` panel action;
81+ * the state lives here (session-level, not in the page) so it survives
82+ * navigations and tab switches.
8283 */
83- let takeoverReason : string | null = null
84+ let takeoverActive = false
8485let takeoverDone = false
8586
8687function pageStateFor ( contents : WebContents ) : BrowserPageState {
@@ -90,7 +91,6 @@ function pageStateFor(contents: WebContents): BrowserPageState {
9091 loading : contents . isLoading ( ) ,
9192 canGoBack : contents . navigationHistory . canGoBack ( ) ,
9293 canGoForward : contents . navigationHistory . canGoForward ( ) ,
93- ...( takeoverReason !== null ? { takeoverReason } : { } ) ,
9494 }
9595}
9696
@@ -449,19 +449,17 @@ async function activeElementState(contents: WebContents): Promise<Record<string,
449449// ---------------------------------------------------------------------------
450450
451451/**
452- * Hands control to the user IN THE PANEL: the page is already natively
453- * interactive there, so the panel chrome shows a takeover strip (driven by
454- * `takeoverReason` on page-state pushes) with the Done chip; the tool
455- * resolves when that chip sends the `takeover-done` panel action. Nothing is
456- * injected into the page, so the strip never covers page content and
457- * survives navigations.
452+ * Hands control to the user: the page is already natively interactive in the
453+ * panel, and the chat's takeover tool row shows the reason with a Done chip.
454+ * The tool resolves when that chip sends the `takeover-done` panel action.
455+ * Nothing is injected into the page, so nothing covers page content and the
456+ * pending state survives navigations.
458457 */
459- async function runTakeover ( reason : string ) : Promise < unknown > {
458+ async function runTakeover ( ) : Promise < unknown > {
460459 const tab = session . ensureTab ( )
461460 const contents = tab . view . webContents
462- takeoverReason = reason
461+ takeoverActive = true
463462 takeoverDone = false
464- pushPageState ( contents )
465463
466464 const startedAt = Date . now ( )
467465 try {
@@ -478,9 +476,8 @@ async function runTakeover(reason: string): Promise<unknown> {
478476 }
479477 throw new ToolError ( 'Takeover timed out after 12 hours without the user finishing.' )
480478 } finally {
481- takeoverReason = null
479+ takeoverActive = false
482480 takeoverDone = false
483- if ( ! contents . isDestroyed ( ) ) pushPageState ( contents )
484481 }
485482}
486483
@@ -698,7 +695,10 @@ async function executeToolInner(
698695 }
699696
700697 case 'browser_request_takeover' : {
701- return await runTakeover ( requireStr ( params , 'reason' ) )
698+ // The reason renders in the chat's tool row, not here — but require it
699+ // so the model always tells the user why control was handed over.
700+ requireStr ( params , 'reason' )
701+ return await runTakeover ( )
702702 }
703703
704704 default : {
@@ -764,10 +764,10 @@ export async function executeTool(
764764
765765/** Browser-chrome commands from the panel header; fire-and-forget. */
766766export async function handlePanelAction ( action : BrowserPanelAction ) : Promise < void > {
767- // The Done chip on the panel 's takeover strip : hands control back to the
767+ // The Done chip on the chat 's takeover tool row : hands control back to the
768768 // agent. Meaningful only while a takeover is actually waiting.
769769 if ( action . action === 'takeover-done' ) {
770- if ( takeoverReason !== null ) takeoverDone = true
770+ if ( takeoverActive ) takeoverDone = true
771771 return
772772 }
773773 // Navigate bootstraps the session: the user can open the panel manually
0 commit comments