mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-05-17 04:01:13 +00:00
Default Bring Your Own Browser mode to the existing browser profile while exposing a clean Agent profile option in Browser settings with a clear warning for existing-profile access. Forward the selected profile mode through the connector browser runtime, tolerate legacy config modules and old saved configs, and update regression coverage for the new payload shape.
490 lines
16 KiB
HTML
490 lines
16 KiB
HTML
<html>
|
|
<head>
|
|
<title>Browser Settings</title>
|
|
<script type="module">
|
|
import { store } from "/plugins/_browser/webui/browser-config-store.js";
|
|
</script>
|
|
</head>
|
|
|
|
<body>
|
|
<div x-data>
|
|
<template x-if="$store.browserConfig && config">
|
|
<div
|
|
class="browser-config-sections"
|
|
x-init="$store.browserConfig.init(config)"
|
|
x-effect="$store.browserConfig.bindConfig(config)"
|
|
x-destroy="$store.browserConfig.cleanup()"
|
|
>
|
|
<div class="browser-config-card">
|
|
<div class="section-title">Host Browser</div>
|
|
<div class="section-description">
|
|
Use Chrome, Edge, or Chromium on this computer. Keep A0 CLI connected; the browser opens when the agent first needs it.
|
|
</div>
|
|
|
|
<label class="browser-config-field">
|
|
<span class="browser-config-field-label">Browser location</span>
|
|
<select x-model="$store.browserConfig.config.runtime_backend">
|
|
<option value="container">Docker browser</option>
|
|
<option value="host_required">Bring Your Own Browser</option>
|
|
</select>
|
|
<span
|
|
class="browser-config-field-help"
|
|
x-show="$store.browserConfig.config.runtime_backend === 'host_required'"
|
|
>
|
|
Use Google Chrome or a Chromium family browser. Visit chrome://inspect#remote-debugging and enable "Allow remote debugging".
|
|
</span>
|
|
</label>
|
|
|
|
<label
|
|
class="browser-config-field"
|
|
x-show="$store.browserConfig.config.runtime_backend === 'host_required'"
|
|
>
|
|
<span class="browser-config-field-label">Host browser profile</span>
|
|
<select x-model="$store.browserConfig.config.host_browser_profile_mode">
|
|
<option value="existing">Existing browser profile</option>
|
|
<option value="agent">Clean Agent profile</option>
|
|
</select>
|
|
<span
|
|
class="browser-config-field-help"
|
|
x-show="$store.browserConfig.config.host_browser_profile_mode === 'agent'"
|
|
>
|
|
Uses a separate A0-controlled local profile on this computer.
|
|
</span>
|
|
</label>
|
|
|
|
<div
|
|
class="browser-config-warning"
|
|
x-show="$store.browserConfig.config.runtime_backend === 'host_required' && $store.browserConfig.config.host_browser_profile_mode !== 'agent'"
|
|
>
|
|
<span class="material-symbols-outlined">warning</span>
|
|
<span>
|
|
Existing profile lets the agent interact with the browser instance you authorize,
|
|
including signed-in sites, cookies, tabs, downloads, and page content.
|
|
</span>
|
|
</div>
|
|
|
|
<label class="browser-config-field">
|
|
<span class="browser-config-field-label">Page content access</span>
|
|
<select x-model="$store.browserConfig.config.host_browser_privacy_policy">
|
|
<option value="enforce_local">Local models only</option>
|
|
<option value="warn">Warn when using cloud</option>
|
|
<option value="allow">Allow</option>
|
|
</select>
|
|
<span class="browser-config-field-help">Controls page text and screenshots from the host browser.</span>
|
|
</label>
|
|
|
|
<div class="browser-config-note">
|
|
<span class="material-symbols-outlined" :class="{ spinning: $store.browserConfig.hostBrowserStatusLoading }" x-text="$store.browserConfig.hostBrowserStatusLoading ? 'progress_activity' : 'captive_portal'"></span>
|
|
<span x-text="$store.browserConfig.hostBrowserConnectorLabel()"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="browser-config-card">
|
|
<div class="section-title">Browsing</div>
|
|
<div class="section-description">
|
|
Set how new Browser sessions start and how an already-open Browser surface follows agent activity.
|
|
</div>
|
|
|
|
<label class="browser-config-field">
|
|
<span class="browser-config-field-label">Starting page</span>
|
|
<input
|
|
type="text"
|
|
x-model="$store.browserConfig.config.default_homepage"
|
|
placeholder="about:blank or https://example.com"
|
|
autocomplete="off"
|
|
/>
|
|
</label>
|
|
|
|
<label class="browser-config-switch-row">
|
|
<span class="browser-config-switch-copy">
|
|
<span class="browser-config-field-label">Autofocus active page</span>
|
|
<span class="browser-config-field-help">Update the visible Browser surface for pages opened or changed by Browser tool results.</span>
|
|
</span>
|
|
<span class="browser-config-toggle-with-label">
|
|
<span class="browser-config-toggle-label" x-text="$store.browserConfig.autofocusLabel()"></span>
|
|
<span class="browser-config-toggle">
|
|
<input
|
|
type="checkbox"
|
|
:checked="$store.browserConfig.config.autofocus_active_page !== false"
|
|
@change="$store.browserConfig.setAutofocusActivePage($event.target.checked)"
|
|
/>
|
|
<span class="browser-config-switch"></span>
|
|
</span>
|
|
</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="browser-config-card">
|
|
<div class="section-title">Extensions</div>
|
|
<div class="section-description">
|
|
Choose which installed Chrome extensions Browser loads.
|
|
</div>
|
|
|
|
<div class="browser-config-warning">
|
|
<span class="material-symbols-outlined">warning</span>
|
|
<span>
|
|
Extensions run inside the Docker browser sandbox, but malicious or buggy extensions can
|
|
still damage that environment. Keep only the extensions you trust enabled.
|
|
</span>
|
|
</div>
|
|
|
|
<div class="browser-config-extension-list">
|
|
<div class="browser-config-subtitle">
|
|
<span>Installed extensions</span>
|
|
<span class="material-symbols-outlined spinning" x-show="$store.browserConfig.extensionsLoading">progress_activity</span>
|
|
</div>
|
|
<template x-if="!$store.browserConfig.extensionsLoading && !$store.browserConfig.extensionsList.length">
|
|
<div class="browser-config-empty">No installed extensions found.</div>
|
|
</template>
|
|
<template x-for="extension in $store.browserConfig.extensionsList" :key="extension.path">
|
|
<div class="browser-config-extension-row" :title="extension.path">
|
|
<span class="browser-config-extension-text">
|
|
<span class="browser-config-extension-name" x-text="extension.name || 'Unnamed extension'"></span>
|
|
<span class="browser-config-extension-meta" x-text="$store.browserConfig.extensionVersionLabel(extension)"></span>
|
|
</span>
|
|
<span class="browser-config-extension-actions">
|
|
<label class="browser-config-toggle">
|
|
<input
|
|
type="checkbox"
|
|
:checked="$store.browserConfig.extensionEnabled(extension)"
|
|
:disabled="$store.browserConfig.extensionDeleteLoadingPath === extension.path"
|
|
@change="$store.browserConfig.setExtensionEnabled(extension, $event.target.checked)"
|
|
/>
|
|
<span class="browser-config-switch"></span>
|
|
</label>
|
|
<button
|
|
type="button"
|
|
class="browser-config-extension-delete"
|
|
:disabled="!$store.browserConfig.extensionCanDelete(extension) || $store.browserConfig.extensionDeleteLoadingPath === extension.path"
|
|
:title="$store.browserConfig.extensionDeleteTitle(extension)"
|
|
:aria-label="'Delete ' + (extension.name || 'extension')"
|
|
@click.stop="$store.browserConfig.deleteExtension(extension)"
|
|
>
|
|
<span
|
|
class="material-symbols-outlined"
|
|
:class="{ spinning: $store.browserConfig.extensionDeleteLoadingPath === extension.path }"
|
|
x-text="$store.browserConfig.extensionDeleteLoadingPath === extension.path ? 'progress_activity' : 'delete'"
|
|
></span>
|
|
</button>
|
|
</span>
|
|
</div>
|
|
</template>
|
|
<div class="browser-config-note browser-config-success" x-show="$store.browserConfig.extensionsMessage">
|
|
<span class="material-symbols-outlined">check_circle</span>
|
|
<span x-text="$store.browserConfig.extensionsMessage"></span>
|
|
</div>
|
|
<div class="browser-config-note" x-show="$store.browserConfig.extensionsError">
|
|
<span class="material-symbols-outlined">error</span>
|
|
<span x-text="$store.browserConfig.extensionsError"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="browser-config-pill-row">
|
|
<span class="browser-config-pill" x-text="$store.browserConfig.pathCountLabel()"></span>
|
|
<span class="browser-config-pill tone-active" x-show="$store.browserConfig.extensionModeReady()">
|
|
Ready
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
|
|
<style>
|
|
.browser-config-sections {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
}
|
|
|
|
.browser-config-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
padding: 16px;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.browser-config-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
|
|
.browser-config-field-label {
|
|
color: var(--color-text);
|
|
font-size: 0.84rem;
|
|
font-weight: 650;
|
|
}
|
|
|
|
.browser-config-field-help {
|
|
color: var(--color-text-secondary);
|
|
font-size: 0.78rem;
|
|
line-height: 1.35;
|
|
}
|
|
|
|
.browser-config-field input[type="text"],
|
|
.browser-config-field select {
|
|
width: 100%;
|
|
min-height: 36px;
|
|
padding: 7px 10px;
|
|
border: 1px solid color-mix(in srgb, var(--color-border) 74%, transparent);
|
|
border-radius: 8px;
|
|
background: var(--color-input);
|
|
color: var(--color-text);
|
|
font: inherit;
|
|
}
|
|
|
|
.browser-config-switch-row {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
align-items: center;
|
|
gap: 16px;
|
|
min-height: 46px;
|
|
padding-top: 2px;
|
|
}
|
|
|
|
.browser-config-switch-copy {
|
|
display: flex;
|
|
min-width: 0;
|
|
flex-direction: column;
|
|
gap: 3px;
|
|
}
|
|
|
|
.browser-config-toggle-with-label {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.browser-config-toggle-label {
|
|
min-width: 24px;
|
|
color: var(--color-text-secondary);
|
|
font-size: 0.78rem;
|
|
font-weight: 650;
|
|
text-align: right;
|
|
}
|
|
|
|
.browser-config-extension-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
padding: 12px;
|
|
border: 1px solid color-mix(in srgb, var(--color-border) 72%, transparent);
|
|
border-radius: 8px;
|
|
background: color-mix(in srgb, var(--color-panel) 78%, transparent);
|
|
}
|
|
|
|
.browser-config-subtitle {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 8px;
|
|
color: var(--color-text-secondary);
|
|
font-size: 0.82rem;
|
|
font-weight: 650;
|
|
}
|
|
|
|
.browser-config-subtitle .material-symbols-outlined {
|
|
font-size: 18px;
|
|
}
|
|
|
|
.browser-config-empty,
|
|
.browser-config-extension-meta {
|
|
color: var(--color-text-secondary);
|
|
font-size: 0.78rem;
|
|
}
|
|
|
|
.browser-config-extension-row {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
align-items: center;
|
|
gap: 14px;
|
|
min-height: 42px;
|
|
padding: 8px 0;
|
|
}
|
|
|
|
.browser-config-extension-row + .browser-config-extension-row {
|
|
border-top: 1px solid color-mix(in srgb, var(--color-border) 52%, transparent);
|
|
}
|
|
|
|
.browser-config-extension-text {
|
|
display: flex;
|
|
min-width: 0;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
}
|
|
|
|
.browser-config-extension-name {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
color: var(--color-text);
|
|
font-weight: 650;
|
|
}
|
|
|
|
.browser-config-extension-actions {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.browser-config-toggle {
|
|
position: relative;
|
|
display: inline-flex;
|
|
flex: 0 0 auto;
|
|
align-items: center;
|
|
width: 42px;
|
|
height: 24px;
|
|
}
|
|
|
|
.browser-config-toggle input {
|
|
position: absolute;
|
|
inset: 0;
|
|
margin: 0;
|
|
opacity: 0;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.browser-config-toggle input:disabled {
|
|
cursor: wait;
|
|
}
|
|
|
|
.browser-config-switch {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 999px;
|
|
background: color-mix(in srgb, var(--color-border) 78%, transparent);
|
|
pointer-events: none;
|
|
transition: background-color 0.18s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
.browser-config-switch::after {
|
|
content: "";
|
|
position: absolute;
|
|
top: 3px;
|
|
left: 3px;
|
|
width: 18px;
|
|
height: 18px;
|
|
border-radius: 50%;
|
|
background: var(--color-background);
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.24);
|
|
transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
.browser-config-toggle input:checked + .browser-config-switch {
|
|
background: color-mix(in srgb, var(--color-primary) 76%, #16a34a);
|
|
}
|
|
|
|
.browser-config-toggle input:checked + .browser-config-switch::after {
|
|
transform: translateX(18px);
|
|
}
|
|
|
|
.browser-config-toggle input:disabled + .browser-config-switch {
|
|
opacity: 0.58;
|
|
}
|
|
|
|
.browser-config-extension-delete {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 28px;
|
|
min-width: 28px;
|
|
height: 28px;
|
|
min-height: 28px;
|
|
padding: 0;
|
|
border: 1px solid color-mix(in srgb, #be123c 30%, var(--color-border));
|
|
border-radius: 7px;
|
|
background: transparent;
|
|
color: color-mix(in srgb, #be123c 78%, var(--color-text));
|
|
cursor: pointer;
|
|
}
|
|
|
|
.browser-config-extension-delete:hover:not(:disabled) {
|
|
background: color-mix(in srgb, #be123c 12%, var(--color-background));
|
|
color: #be123c;
|
|
}
|
|
|
|
.browser-config-extension-delete:disabled {
|
|
cursor: not-allowed;
|
|
opacity: 0.48;
|
|
}
|
|
|
|
.browser-config-extension-delete .material-symbols-outlined {
|
|
font-size: 17px;
|
|
}
|
|
|
|
.browser-config-note {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 8px;
|
|
padding: 10px 12px;
|
|
border-radius: 8px;
|
|
background: color-mix(in srgb, var(--color-panel) 82%, transparent);
|
|
color: var(--color-text-secondary);
|
|
font-size: var(--font-size-small);
|
|
}
|
|
|
|
.browser-config-note.browser-config-success {
|
|
background: color-mix(in srgb, #15803d 12%, var(--color-background));
|
|
color: color-mix(in srgb, var(--color-text) 88%, #166534);
|
|
}
|
|
|
|
.browser-config-warning {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 9px;
|
|
padding: 11px 12px;
|
|
border: 1px solid color-mix(in srgb, #d97706 44%, var(--color-border));
|
|
border-radius: 8px;
|
|
background: color-mix(in srgb, #d97706 14%, var(--color-background));
|
|
color: color-mix(in srgb, var(--color-text) 86%, #92400e);
|
|
font-size: var(--font-size-small);
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.browser-config-warning .material-symbols-outlined {
|
|
color: #b45309;
|
|
font-size: 20px;
|
|
}
|
|
|
|
.browser-config-sections .spinning {
|
|
display: inline-block;
|
|
transform-origin: center;
|
|
animation: browser-config-spin 0.8s linear infinite;
|
|
}
|
|
|
|
@keyframes browser-config-spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
.browser-config-pill-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
}
|
|
|
|
.browser-config-pill {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
min-height: 28px;
|
|
padding: 0 10px;
|
|
border-radius: 999px;
|
|
border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
|
|
background: color-mix(in srgb, var(--color-panel) 88%, transparent);
|
|
font-size: 0.78rem;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
.browser-config-pill.tone-active {
|
|
color: #1b5e20;
|
|
border-color: rgba(27, 94, 32, 0.18);
|
|
background: rgba(46, 125, 50, 0.12);
|
|
}
|
|
</style>
|
|
</body>
|
|
</html>
|