Skip to content

Commit 8dfbf54

Browse files
committed
Fix the browser operator provider settings
1 parent 612e49d commit 8dfbf54

File tree

6 files changed

+138
-10
lines changed

6 files changed

+138
-10
lines changed

front_end/panels/ai_chat/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ devtools_module("ai_chat") {
5555
"ui/settings/providers/LiteLLMSettings.ts",
5656
"ui/settings/providers/GroqSettings.ts",
5757
"ui/settings/providers/OpenRouterSettings.ts",
58+
"ui/settings/providers/BrowserOperatorSettings.ts",
5859
"ui/settings/advanced/MCPSettings.ts",
5960
"ui/settings/advanced/BrowsingHistorySettings.ts",
6061
"ui/settings/advanced/VectorDBSettings.ts",
@@ -248,6 +249,7 @@ _ai_chat_sources = [
248249
"ui/settings/providers/LiteLLMSettings.ts",
249250
"ui/settings/providers/GroqSettings.ts",
250251
"ui/settings/providers/OpenRouterSettings.ts",
252+
"ui/settings/providers/BrowserOperatorSettings.ts",
251253
"ui/settings/advanced/MCPSettings.ts",
252254
"ui/settings/advanced/BrowsingHistorySettings.ts",
253255
"ui/settings/advanced/VectorDBSettings.ts",

front_end/panels/ai_chat/ui/SettingsDialog.ts

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { OpenAISettings } from './settings/providers/OpenAISettings.js';
2121
import { LiteLLMSettings } from './settings/providers/LiteLLMSettings.js';
2222
import { GroqSettings } from './settings/providers/GroqSettings.js';
2323
import { OpenRouterSettings } from './settings/providers/OpenRouterSettings.js';
24+
import { BrowserOperatorSettings } from './settings/providers/BrowserOperatorSettings.js';
2425

2526
// Import advanced feature settings classes
2627
import { MCPSettings } from './settings/advanced/MCPSettings.js';
@@ -193,18 +194,27 @@ export class SettingsDialog {
193194
() => dialog.hide()
194195
);
195196

197+
const browseroperatorSettings = new BrowserOperatorSettings(
198+
browseroperatorContent,
199+
getModelOptions,
200+
addCustomModelOption,
201+
removeCustomModelOption
202+
);
203+
196204
// Render all providers (only visible one will be shown)
197205
openaiSettings.render();
198206
litellmSettings.render();
199207
groqSettings.render();
200208
openrouterSettings.render();
209+
browseroperatorSettings.render();
201210

202211
// Store provider settings for later access
203212
const providerSettings = new Map<ProviderType, any>([
204213
['openai', openaiSettings],
205214
['litellm', litellmSettings],
206215
['groq', groqSettings],
207216
['openrouter', openrouterSettings],
217+
['browseroperator', browseroperatorSettings],
208218
]);
209219

210220
// Event listener for provider change
@@ -296,19 +306,19 @@ export class SettingsDialog {
296306

297307
// Add Advanced Settings Toggle
298308
const advancedToggleContainer = document.createElement('div');
299-
advancedToggleContainer.className = 'advanced-toggle-container';
309+
advancedToggleContainer.className = 'advanced-settings-toggle-container';
300310
contentDiv.appendChild(advancedToggleContainer);
301311

302312
const advancedToggleCheckbox = document.createElement('input');
303313
advancedToggleCheckbox.type = 'checkbox';
304314
advancedToggleCheckbox.id = 'advanced-settings-toggle';
305-
advancedToggleCheckbox.className = 'advanced-toggle-checkbox';
315+
advancedToggleCheckbox.className = 'advanced-settings-checkbox';
306316
advancedToggleCheckbox.checked = localStorage.getItem(ADVANCED_SETTINGS_ENABLED_KEY) === 'true';
307317
advancedToggleContainer.appendChild(advancedToggleCheckbox);
308318

309319
const advancedToggleLabel = document.createElement('label');
310320
advancedToggleLabel.htmlFor = 'advanced-settings-toggle';
311-
advancedToggleLabel.className = 'advanced-toggle-label';
321+
advancedToggleLabel.className = 'advanced-settings-label';
312322
advancedToggleLabel.textContent = '⚙️ Advanced Settings';
313323
advancedToggleContainer.appendChild(advancedToggleLabel);
314324

@@ -370,11 +380,33 @@ export class SettingsDialog {
370380
toggleAdvancedSections(advancedToggleCheckbox.checked);
371381
});
372382

373-
// Create disclaimer
374-
const disclaimer = document.createElement('div');
375-
disclaimer.className = 'settings-disclaimer';
376-
disclaimer.textContent = i18nString(UIStrings.disclaimer);
377-
contentDiv.appendChild(disclaimer);
383+
// Add disclaimer section
384+
const disclaimerSection = document.createElement('div');
385+
disclaimerSection.classList.add('settings-section', 'disclaimer-section');
386+
contentDiv.appendChild(disclaimerSection);
387+
388+
const disclaimerTitle = document.createElement('h3');
389+
disclaimerTitle.textContent = i18nString(UIStrings.importantNotice);
390+
disclaimerTitle.classList.add('settings-subtitle');
391+
disclaimerSection.appendChild(disclaimerTitle);
392+
393+
const disclaimerText = document.createElement('div');
394+
disclaimerText.classList.add('settings-disclaimer');
395+
disclaimerText.innerHTML = `
396+
<p class="disclaimer-warning">
397+
<strong>Beta Version:</strong> This is a beta version of the Browser Operator - AI Assistant feature.
398+
</p>
399+
<p class="disclaimer-note">
400+
<strong>Data Sharing:</strong> When using this feature, your browser data and conversation content will be sent to the AI model for processing.
401+
</p>
402+
<p class="disclaimer-note">
403+
<strong>Provider Support:</strong> We currently support OpenAI, Groq and OpenRouter providers directly. And we support LiteLLM as a proxy to access 100+ other models.
404+
</p>
405+
<p class="disclaimer-footer">
406+
By using this feature, you acknowledge that your data will be processed according to Model Provider's privacy policy and terms of service.
407+
</p>
408+
`;
409+
disclaimerSection.appendChild(disclaimerText);
378410

379411
// Create footer with buttons
380412
const footer = document.createElement('div');
@@ -422,6 +454,7 @@ export class SettingsDialog {
422454
litellmSettings.save();
423455
groqSettings.save();
424456
openrouterSettings.save();
457+
browseroperatorSettings.save();
425458

426459
// Save mini/nano model selections from current provider
427460
const currentProviderSettings = providerSettings.get(selectedProvider as ProviderType);

front_end/panels/ai_chat/ui/settings/i18n-strings.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ export const UIStrings = {
3636
*@description OpenRouter provider option
3737
*/
3838
openrouterProvider: 'OpenRouter',
39+
/**
40+
*@description BrowserOperator provider option
41+
*/
42+
browseroperatorProvider: 'BrowserOperator',
3943
/**
4044
*@description LiteLLM API Key label
4145
*/
@@ -84,6 +88,14 @@ export const UIStrings = {
8488
*@description OpenAI API Key hint
8589
*/
8690
apiKeyHint: 'An OpenAI API key is required for OpenAI models (GPT-4.1, O4 Mini, etc.)',
91+
/**
92+
*@description BrowserOperator API Key label
93+
*/
94+
browseroperatorApiKeyLabel: 'BrowserOperator API Key (Optional)',
95+
/**
96+
*@description BrowserOperator API Key hint
97+
*/
98+
browseroperatorApiKeyHint: 'Optional API key for BrowserOperator managed service. Authentication is not required.',
8799
/**
88100
*@description Test button text
89101
*/
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2025 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import { BaseProviderSettings } from './BaseProviderSettings.js';
6+
import { i18nString, UIStrings } from '../i18n-strings.js';
7+
import { getStorageItem, setStorageItem } from '../utils/storage.js';
8+
import type { GetModelOptionsFunction, AddCustomModelOptionFunction, RemoveCustomModelOptionFunction } from '../types.js';
9+
10+
// Storage key for BrowserOperator API key (defined in LLMConfigurationManager.ts)
11+
const BROWSEROPERATOR_API_KEY_STORAGE_KEY = 'ai_chat_browseroperator_api_key';
12+
13+
/**
14+
* BrowserOperator provider settings
15+
*
16+
* BrowserOperator is a managed hosted service with agent-based routing.
17+
* - API key is optional
18+
* - Endpoint is hardcoded to https://api.browseroperator.io/v1
19+
* - Models are static aliases (main, mini, nano) not real model names
20+
*/
21+
export class BrowserOperatorSettings extends BaseProviderSettings {
22+
private apiKeyInput: HTMLInputElement | null = null;
23+
private settingsSection: HTMLElement | null = null;
24+
25+
constructor(
26+
container: HTMLElement,
27+
getModelOptions: GetModelOptionsFunction,
28+
addCustomModelOption: AddCustomModelOptionFunction,
29+
removeCustomModelOption: RemoveCustomModelOptionFunction
30+
) {
31+
super(container, 'browseroperator', getModelOptions, addCustomModelOption, removeCustomModelOption);
32+
}
33+
34+
render(): void {
35+
// Clear any existing content
36+
this.container.innerHTML = '';
37+
38+
// Setup BrowserOperator content
39+
this.settingsSection = document.createElement('div');
40+
this.settingsSection.className = 'settings-section';
41+
this.container.appendChild(this.settingsSection);
42+
43+
// Optional API key section
44+
const apiKeyLabel = document.createElement('div');
45+
apiKeyLabel.className = 'settings-label';
46+
apiKeyLabel.textContent = i18nString(UIStrings.browseroperatorApiKeyLabel);
47+
this.settingsSection.appendChild(apiKeyLabel);
48+
49+
const apiKeyHint = document.createElement('div');
50+
apiKeyHint.className = 'settings-hint';
51+
apiKeyHint.textContent = i18nString(UIStrings.browseroperatorApiKeyHint);
52+
this.settingsSection.appendChild(apiKeyHint);
53+
54+
const settingsSavedApiKey = getStorageItem(BROWSEROPERATOR_API_KEY_STORAGE_KEY, '');
55+
this.apiKeyInput = document.createElement('input');
56+
this.apiKeyInput.className = 'settings-input';
57+
this.apiKeyInput.type = 'password';
58+
this.apiKeyInput.placeholder = 'Enter your BrowserOperator API key (optional)';
59+
this.apiKeyInput.value = settingsSavedApiKey;
60+
this.settingsSection.appendChild(this.apiKeyInput);
61+
}
62+
63+
updateModelSelectors(): void {
64+
// BrowserOperator doesn't need model selectors - models are managed automatically
65+
return;
66+
}
67+
68+
save(): void {
69+
// Save BrowserOperator API key (optional)
70+
if (this.apiKeyInput) {
71+
const newApiKey = this.apiKeyInput.value.trim();
72+
if (newApiKey) {
73+
setStorageItem(BROWSEROPERATOR_API_KEY_STORAGE_KEY, newApiKey);
74+
} else {
75+
// Remove from storage if empty (API key is optional)
76+
localStorage.removeItem(BROWSEROPERATOR_API_KEY_STORAGE_KEY);
77+
}
78+
}
79+
}
80+
}

front_end/panels/ai_chat/ui/settings/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
export interface ModelOption {
99
value: string;
1010
label: string;
11-
type: 'openai' | 'litellm' | 'groq' | 'openrouter';
11+
type: 'openai' | 'litellm' | 'groq' | 'openrouter' | 'browseroperator';
1212
}
1313

1414
/**
@@ -22,7 +22,7 @@ export interface ValidationResult {
2222
/**
2323
* Provider type
2424
*/
25-
export type ProviderType = 'openai' | 'litellm' | 'groq' | 'openrouter';
25+
export type ProviderType = 'openai' | 'litellm' | 'groq' | 'openrouter' | 'browseroperator';
2626

2727
/**
2828
* Model tier type

front_end/panels/ai_chat/ui/settings/utils/styles.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ export function getSettingsStyles(): string {
447447
align-items: center;
448448
gap: 8px;
449449
margin-bottom: 8px;
450+
padding-left: 20px;
450451
}
451452
452453
.advanced-settings-checkbox {

0 commit comments

Comments
 (0)