Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/apps/desktop/src/api/browser_control_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,18 @@ fn default_cdp_port() -> u16 {
/// something asks for the browser. Reattaching here restores that connection
/// without the user having to click anything.
///
/// Opt-in, because the grant does not survive a browser restart: after one,
/// reattaching raises an approval dialog before the user has asked for the
/// browser at all.
///
/// This never starts a browser and never opens a settings page: when there is
/// no live endpoint to reattach to, it does nothing and leaves the on-demand
/// path to handle it.
pub fn init_on_startup() {
tokio::spawn(async {
if !auto_connect_on_startup_enabled().await {
return;
}
let Ok(kind) = selected_browser_kind().await else {
return;
};
Expand Down Expand Up @@ -64,6 +71,17 @@ pub fn init_on_startup() {
});
}

async fn auto_connect_on_startup_enabled() -> bool {
let Ok(service) = get_global_config_service().await else {
return false;
};
service
.get_config::<GlobalConfig>(None)
.await
.map(|config| config.ai.browser_control_auto_connect_on_startup)
.unwrap_or(false)
}

async fn selected_browser_kind() -> Result<BrowserKind, String> {
let config = get_global_config_service()
.await
Expand Down
8 changes: 8 additions & 0 deletions src/crates/assembly/core/src/service/config/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,13 @@ pub struct AIConfig {
#[serde(default)]
pub browser_control_preferred_browser: String,

/// Reattach to an already-running browser when BitFun starts. Off by
/// default: the browser forgets its approval when it restarts, so this can
/// put an approval dialog in front of the user before they asked for the
/// browser at all.
#[serde(default)]
pub browser_control_auto_connect_on_startup: bool,

/// Maximum number of rounds per dialog turn before soft-pausing.
#[serde(default = "default_max_rounds")]
pub max_rounds: usize,
Expand Down Expand Up @@ -1842,6 +1849,7 @@ impl Default for AIConfig {
debug_mode_config: DebugModeConfig::default(),
computer_use_enabled: false,
browser_control_preferred_browser: String::new(),
browser_control_auto_connect_on_startup: false,
max_rounds: default_max_rounds(),
}
}
Expand Down
34 changes: 34 additions & 0 deletions src/web-ui/src/infrastructure/config/components/SessionConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ const SessionSettingsPanels: React.FC<SessionSettingsPanelsProps> = ({ variant }
// ── Browser control state ───────────────────────────────────────────────
const [browserCdpAvailable, setBrowserCdpAvailable] = useState(false);
const [browserReady, setBrowserReady] = useState(false);
const [browserAutoConnectOnStartup, setBrowserAutoConnectOnStartup] = useState(false);
const [browserDefaultCdpSupported, setBrowserDefaultCdpSupported] = useState(false);
const [browserDefaultCdpEnabled, setBrowserDefaultCdpEnabled] = useState(false);
const [browserKind, setBrowserKind] = useState('');
Expand Down Expand Up @@ -244,6 +245,7 @@ const SessionSettingsPanels: React.FC<SessionSettingsPanelsProps> = ({ variant }
debugConfigData,
computerUseCfg,
browserControlPreferredBrowser,
browserControlAutoConnect,
loadedToolPermissionConfig,
loadedPermissionModeControlVisibility,
loadedCompanionPets,
Expand All @@ -256,6 +258,7 @@ const SessionSettingsPanels: React.FC<SessionSettingsPanelsProps> = ({ variant }
configManager.getConfig<DebugModeConfig>('ai.debug_mode_config'),
configManager.getConfig<boolean>('ai.computer_use_enabled'),
configManager.getConfig<string>('ai.browser_control_preferred_browser'),
configManager.getConfig<boolean>('ai.browser_control_auto_connect_on_startup'),
permissionConfigService.getConfig(),
configManager.getOptionalConfig<boolean>(SHOW_PERMISSION_MODE_CONTROL_CONFIG_PATH),
listAgentCompanionPets(),
Expand All @@ -271,6 +274,7 @@ const SessionSettingsPanels: React.FC<SessionSettingsPanelsProps> = ({ variant }
setSubagentBatchExecutionPolicy(normalizeSubagentBatchExecutionPolicy(loadedSubagentBatchExecutionPolicy));
if (debugConfigData) setDebugConfig(debugConfigData);
setPreferredBrowser(browserControlPreferredBrowser || DEFAULT_BROWSER_CONTROL_BROWSER);
setBrowserAutoConnectOnStartup(browserControlAutoConnect === true);
setToolPermissionConfig(normalizeToolPermissionConfig(loadedToolPermissionConfig));
setShowPermissionModeControl(loadedPermissionModeControlVisibility !== false);

Expand Down Expand Up @@ -649,6 +653,20 @@ const SessionSettingsPanels: React.FC<SessionSettingsPanelsProps> = ({ variant }
}
};

const handleBrowserAutoConnectChange = async (checked: boolean) => {
const previousValue = browserAutoConnectOnStartup;
setBrowserAutoConnectOnStartup(checked);
try {
await configManager.setConfig('ai.browser_control_auto_connect_on_startup', checked);
} catch (error) {
log.error('Failed to save browser_control_auto_connect_on_startup', error);
setBrowserAutoConnectOnStartup(previousValue);
notificationService.error(
`${tTools('messages.saveFailed')}: ` + (error instanceof Error ? error.message : String(error))
);
}
};

const presentBrowserControlLaunchResult = (result: BrowserControlLaunchResponse) => {
if (result.success) {
notificationService.success(
Expand Down Expand Up @@ -1530,6 +1548,22 @@ const SessionSettingsPanels: React.FC<SessionSettingsPanelsProps> = ({ variant }
</div>
</ConfigPageRow>
)}
{browserDefaultCdpSupported && (
<ConfigPageRow
label={t('browserControl.autoConnectOnStartup')}
description={t('browserControl.autoConnectOnStartupDesc')}
align="center"
balanced
>
<div className="bitfun-func-agent-config__row-control" data-bf-component="session-config" data-bf-part="control">
<Switch
checked={browserAutoConnectOnStartup}
onChange={(e) => void handleBrowserAutoConnectChange(e.target.checked)}
size="small"
/>
</div>
</ConfigPageRow>
)}
<ConfigPageRow
label={t('browserControl.status')}
description={t('browserControl.statusDesc') || undefined}
Expand Down
1 change: 1 addition & 0 deletions src/web-ui/src/infrastructure/config/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ export interface AIConfig {
subagent_batch_execution_policy?: 'safe_only' | 'force_parallel' | 'serial';
computer_use_enabled?: boolean;
browser_control_preferred_browser?: string;
browser_control_auto_connect_on_startup?: boolean;
}

export interface StoredAgentProfileConfigItem {
Expand Down
2 changes: 2 additions & 0 deletions src/web-ui/src/locales/en-US/settings/session-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@
"connect": "Connect",
"defaultCdp": "Default CDP",
"defaultCdpDesc": "Let BitFun use the Chrome or Edge you already have open, with your existing tabs and signed-in accounts, instead of starting a separate empty browser. You grant this once in the browser, and the browser still asks you to confirm each connection.",
"autoConnectOnStartup": "Connect on startup",
"autoConnectOnStartupDesc": "Attach as soon as BitFun starts, if the browser is already running with the setting above enabled. Note: the browser forgets its approval when it restarts, so after that you get an approval prompt right away — even if you weren't going to use the browser this session. When off, BitFun attaches the first time an agent needs the browser.",
"defaultCdpEnabled": "Enabled",
"defaultCdpDisabled": "Not enabled",
"enableDefaultCdp": "Enable default CDP",
Expand Down
2 changes: 2 additions & 0 deletions src/web-ui/src/locales/zh-CN/settings/session-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@
"connect": "连接浏览器",
"defaultCdp": "默认 CDP",
"defaultCdpDesc": "让 BitFun 直接使用你正在用的 Chrome 或 Edge,保留已打开的标签页和登录状态,不必另开一个空白浏览器。首次需要在浏览器中授权,之后每次连接也会由浏览器向你确认。",
"autoConnectOnStartup": "启动时自动连接",
"autoConnectOnStartupDesc": "BitFun 启动时,若浏览器正在运行且已启用上面的设置,就直接连上。注意:浏览器重启后会忘记之前的授权,这时会立刻弹出一次授权确认,即使你这次并不打算用浏览器。关闭时改为按需连接 —— Agent 第一次用到浏览器才连。",
"defaultCdpEnabled": "已启用",
"defaultCdpDisabled": "未启用",
"enableDefaultCdp": "启用默认 CDP",
Expand Down
2 changes: 2 additions & 0 deletions src/web-ui/src/locales/zh-TW/settings/session-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@
"connect": "連接瀏覽器",
"defaultCdp": "預設 CDP",
"defaultCdpDesc": "讓 BitFun 直接使用你正在用的 Chrome 或 Edge,保留已開啟的分頁和登入狀態,不必另外開一個空白瀏覽器。首次需要在瀏覽器中授權,之後每次連線也會由瀏覽器向你確認。",
"autoConnectOnStartup": "啟動時自動連接",
"autoConnectOnStartupDesc": "BitFun 啟動時,若瀏覽器正在執行且已啟用上面的設定,就直接連上。注意:瀏覽器重新啟動後會忘記先前的授權,這時會立刻跳出一次授權確認,即使你這次並不打算用瀏覽器。關閉時改為按需連接 —— Agent 第一次用到瀏覽器才連。",
"defaultCdpEnabled": "已啟用",
"defaultCdpDisabled": "未啟用",
"enableDefaultCdp": "啟用預設 CDP",
Expand Down