From 41d77486e0399b493f577cc207750f13ccf24558 Mon Sep 17 00:00:00 2001
From: Nikhil Sonti <nikhilsv92@gmail.com>
Date: Thu, 24 Jul 2025 16:14:27 -0700
Subject: [PATCH] BrowserOS settings page

---
 .../api/settings_private/prefs_util.cc        |   4 +
 chrome/browser/prefs/browser_prefs.cc         |   6 +
 chrome/browser/resources/settings/BUILD.gn    |   1 +
 .../browseros_prefs_page.html                 | 336 ++++++++++++++++++
 .../browseros_prefs_page.ts                   | 250 +++++++++++++
 chrome/browser/resources/settings/route.ts    |   1 +
 chrome/browser/resources/settings/router.ts   |   1 +
 chrome/browser/resources/settings/settings.ts |   1 +
 .../settings/settings_main/settings_main.html |   6 +
 .../settings/settings_main/settings_main.ts   |  10 +-
 .../settings/settings_menu/settings_menu.html |   6 +
 .../toolbar/pinned_action_toolbar_button.cc   |  24 +-
 .../toolbar/pinned_action_toolbar_button.h    |   1 +
 chrome/common/pref_names.h                    |  12 +
 14 files changed, 652 insertions(+), 7 deletions(-)
 create mode 100644 chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.html
 create mode 100644 chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.ts

diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 1869a54c5b4e4..0ffbb43806598 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -606,6 +606,10 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
   (*s_allowlist)["nxtscape.ollama_base_url"] = settings_api::PrefType::kString;
   (*s_allowlist)["nxtscape.ollama_model"] = settings_api::PrefType::kString;
 
+  // BrowserOS preferences
+  (*s_allowlist)[prefs::kBrowserOSShowToolbarLabels] = settings_api::PrefType::kBoolean;
+  (*s_allowlist)[prefs::kBrowserOSCustomProviders] = settings_api::PrefType::kString;
+
 #if BUILDFLAG(IS_CHROMEOS)
   // Accounts / Users / People.
   (*s_allowlist)[ash::kAccountsPrefAllowGuest] =
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 5a5b278252383..cf120aacb58d3 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -2349,6 +2349,12 @@ void RegisterNxtscapePrefs(user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterStringPref("nxtscape.ollama_api_key", "");
   registry->RegisterStringPref("nxtscape.ollama_base_url", "http://localhost:11434");
   registry->RegisterStringPref("nxtscape.ollama_model", "");
+  
+  // BrowserOS toolbar settings
+  registry->RegisterBooleanPref(prefs::kBrowserOSShowToolbarLabels, true);
+  
+  // Custom providers list - stored as a JSON string
+  registry->RegisterStringPref(prefs::kBrowserOSCustomProviders, "[]");
 }
 
 #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index 1a8cd69860514..c7a1069d49c2b 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -57,6 +57,7 @@ build_webui("build") {
     "a11y_page/a11y_page.ts",
     "about_page/about_page.ts",
     "nxtscape_page/nxtscape_page.ts",
+    "browseros_prefs_page/browseros_prefs_page.ts",
     "ai_page/ai_compare_subpage.ts",
     "ai_page/ai_info_card.ts",
     "ai_page/ai_logging_info_bullet.ts",
diff --git a/chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.html b/chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.html
new file mode 100644
index 0000000000000..f7766f378ba0a
--- /dev/null
+++ b/chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.html
@@ -0,0 +1,336 @@
+    <link rel="import" href="../controls/settings_toggle_button.html">
+    <style include="cr-shared-style settings-shared md-select">
+      .page-header {
+        display: flex;
+        align-items: center;
+        gap: 16px;
+        padding: 20px 20px 16px;
+        border-bottom: var(--cr-separator-line);
+      }
+      
+      .page-icon {
+        width: 32px;
+        height: 32px;
+        border-radius: 50%;
+        background: var(--google-orange-500);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        color: white;
+        font-size: 18px;
+      }
+      
+      .page-title {
+        font-size: 20px;
+        font-weight: 400;
+        color: var(--cr-primary-text-color);
+        margin: 0;
+      }
+      
+      .page-subtitle {
+        font-size: 14px;
+        color: var(--cr-secondary-text-color);
+        margin: 4px 0 0 0;
+      }
+      
+      .prefs-container {
+        max-width: 680px;
+        margin: 20px auto;
+        padding: 0 20px 20px;
+      }
+      
+      .prefs-section {
+        background: var(--cr-card-background-color);
+        border: 1px solid var(--cr-separator-color);
+        border-radius: 8px;
+        padding: 20px;
+        margin-bottom: 16px;
+      }
+      
+      .prefs-section-header {
+        margin-bottom: 16px;
+        padding-bottom: 16px;
+        border-bottom: 1px solid var(--cr-separator-color);
+      }
+      
+      .prefs-section-title {
+        font-size: 16px;
+        font-weight: 500;
+        color: var(--cr-primary-text-color);
+        margin: 0;
+      }
+      
+      .prefs-toggle-row {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        padding: 12px 0;
+      }
+      
+      .prefs-toggle-label {
+        font-size: 14px;
+        color: var(--cr-primary-text-color);
+      }
+      
+      .prefs-toggle-sublabel {
+        font-size: 12px;
+        color: var(--cr-secondary-text-color);
+        margin-top: 4px;
+      }
+      
+      .custom-providers-list {
+        margin-top: 16px;
+      }
+      
+      .custom-provider-item {
+        display: flex;
+        align-items: center;
+        gap: 12px;
+        padding: 12px;
+        background: var(--cr-hover-background-color);
+        border-radius: 6px;
+        margin-bottom: 8px;
+      }
+      
+      .custom-provider-info {
+        flex: 1;
+      }
+      
+      .custom-provider-name {
+        font-size: 14px;
+        font-weight: 500;
+        color: var(--cr-primary-text-color);
+      }
+      
+      .custom-provider-url {
+        font-size: 12px;
+        color: var(--cr-secondary-text-color);
+        margin-top: 2px;
+      }
+      
+      .add-provider-button {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        padding: 8px 16px;
+        margin-top: 12px;
+        border: 1px dashed var(--cr-separator-color);
+        border-radius: 6px;
+        background: transparent;
+        color: var(--cr-focus-outline-color);
+        cursor: pointer;
+        transition: all 0.2s ease;
+      }
+      
+      .add-provider-button:hover {
+        background: var(--cr-hover-background-color);
+        border-color: var(--cr-focus-outline-color);
+      }
+      
+      .provider-dialog {
+        --cr-dialog-width: 600px;
+        --cr-dialog-max-height: none;
+      }
+      
+      .provider-dialog::part(dialog) {
+        max-width: 600px;
+        width: 600px;
+      }
+      
+      .provider-dialog [slot="body"] {
+        overflow: visible !important;
+        min-height: 220px;
+        padding: 20px 24px;
+      }
+      
+      .provider-dialog .form-group {
+        margin-bottom: 24px;
+      }
+      
+      .provider-dialog .form-group:last-child {
+        margin-bottom: 0;
+      }
+      
+      .delete-button {
+        padding: 6px;
+        border-radius: 4px;
+        background: transparent;
+        border: none;
+        cursor: pointer;
+        color: var(--google-red-600);
+        transition: background 0.2s ease;
+      }
+      
+      .delete-button:hover {
+        background: var(--cr-hover-background-color);
+      }
+      
+      .form-group {
+        margin-bottom: 16px;
+      }
+      
+      .form-label {
+        display: block;
+        font-size: 13px;
+        font-weight: 500;
+        color: var(--cr-primary-text-color);
+        margin-bottom: 8px;
+      }
+      
+      .form-field {
+        width: 100%;
+        height: 40px;
+        padding: 0 12px;
+        border: 1px solid var(--cr-separator-color);
+        border-radius: 4px;
+        font-size: 14px;
+        background: var(--cr-input-background-color);
+        color: var(--cr-primary-text-color);
+        transition: border-color 0.2s ease;
+        box-sizing: border-box;
+      }
+      
+      .form-field:hover {
+        border-color: var(--cr-hover-border-color);
+      }
+      
+      .form-field:focus {
+        outline: none;
+        border-color: var(--cr-focus-outline-color);
+      }
+      
+      .form-helper {
+        font-size: 12px;
+        color: var(--cr-secondary-text-color);
+        margin-top: 4px;
+      }
+      
+      .status-toast {
+        position: fixed;
+        bottom: 24px;
+        left: 50%;
+        transform: translateX(-50%) translateY(100px);
+        padding: 12px 24px;
+        border-radius: 4px;
+        background: var(--google-grey-900);
+        color: white;
+        font-size: 14px;
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        opacity: 0;
+        transition: all 0.3s ease;
+        z-index: 1000;
+      }
+      
+      .status-toast.show {
+        transform: translateX(-50%) translateY(0);
+        opacity: 1;
+      }
+      
+      @media (prefers-color-scheme: dark) {
+        .status-toast {
+          background: var(--google-grey-800);
+        }
+      }
+    </style>
+    
+    <div class="page-header">
+      <div class="page-icon">
+        <cr-icon icon="settings:settings"></cr-icon>
+      </div>
+      <div>
+        <h1 class="page-title">BrowserOS Preferences</h1>
+        <div class="page-subtitle">Configure BrowserOS-specific settings</div>
+      </div>
+    </div>
+    
+    <div class="prefs-container">
+      <!-- Toolbar Settings -->
+      <div class="prefs-section">
+        <div class="prefs-section-header">
+          <h3 class="prefs-section-title">Toolbar Settings</h3>
+        </div>
+        <div class="prefs-toggle-row">
+          <div>
+            <div class="prefs-toggle-label">Show labels in toolbar</div>
+            <div class="prefs-toggle-sublabel">Display text labels next to BrowserOS toolbar icons</div>
+            <div class="prefs-toggle-sublabel" style="color: var(--google-orange-600); font-weight: 500; margin-top: 4px;">
+              NOTE: Needs browser restart
+            </div>
+          </div>
+          <settings-toggle-button
+              id="showToolbarLabels"
+              pref="{{prefs.browseros.show_toolbar_labels}}">
+          </settings-toggle-button>
+        </div>
+      </div>
+      
+      <!-- Custom Providers -->
+      <div class="prefs-section" style="display: none;">
+        <div class="prefs-section-header">
+          <h3 class="prefs-section-title">Custom AI Providers</h3>
+        </div>
+        <div class="prefs-toggle-sublabel" style="margin-bottom: 16px;">
+          Add custom AI providers to use in LLM Chat and LLM Hub
+        </div>
+        
+        <div class="custom-providers-list" id="customProvidersList">
+          <template is="dom-repeat" items="[[customProviders]]">
+            <div class="custom-provider-item">
+              <div class="custom-provider-info">
+                <div class="custom-provider-name">[[item.name]]</div>
+                <div class="custom-provider-url">[[item.url]]</div>
+              </div>
+              <button class="delete-button" on-click="deleteCustomProvider_" data-index$="[[index]]">
+                <cr-icon icon="cr:delete"></cr-icon>
+              </button>
+            </div>
+          </template>
+        </div>
+        
+        <button class="add-provider-button" on-click="showAddProviderDialog_">
+          <cr-icon icon="cr:add"></cr-icon>
+          Add Provider
+        </button>
+      </div>
+    </div>
+    
+    <!-- Add Provider Dialog -->
+    <cr-dialog id="addProviderDialog" class="provider-dialog">
+      <div slot="title">Add Custom AI Provider</div>
+      <div slot="body">
+        <div class="form-group">
+          <label class="form-label" for="newProviderName">Provider Name</label>
+          <input type="text" 
+                 id="newProviderName"
+                 class="form-field"
+                 placeholder="e.g., My Custom AI"
+                 value="{{newProviderName_::input}}">
+          <div class="form-helper">Display name for the provider</div>
+        </div>
+        <div class="form-group">
+          <label class="form-label" for="newProviderUrl">Provider URL</label>
+          <input type="url" 
+                 id="newProviderUrl"
+                 class="form-field"
+                 placeholder="https://example.com/ai-chat"
+                 value="{{newProviderUrl_::input}}">
+          <div class="form-helper">Full URL to the AI provider interface</div>
+        </div>
+      </div>
+      <div slot="button-container">
+        <cr-button class="cancel-button" on-click="cancelAddProvider_">
+          Cancel
+        </cr-button>
+        <cr-button class="action-button" on-click="addCustomProvider_">
+          Add
+        </cr-button>
+      </div>
+    </cr-dialog>
+    
+    <!-- Status message toast -->
+    <div id="statusMessage" class="status-toast">
+      <cr-icon icon="cr:check-circle"></cr-icon>
+      Settings saved successfully
+    </div>
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.ts b/chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.ts
new file mode 100644
index 0000000000000..2616c77cc001b
--- /dev/null
+++ b/chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.ts
@@ -0,0 +1,250 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview 'settings-browseros-prefs-page' contains BrowserOS-specific settings.
+ */
+
+import '../settings_page/settings_section.js';
+import '../settings_page_styles.css.js';
+import '../settings_shared.css.js';
+import '../controls/settings_toggle_button.js';
+import 'chrome://resources/cr_elements/cr_button/cr_button.js';
+import 'chrome://resources/cr_elements/cr_icon/cr_icon.js';
+import 'chrome://resources/cr_elements/icons.html.js';
+import 'chrome://resources/cr_elements/cr_shared_style.css.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
+
+import {PrefsMixin} from '/shared/settings/prefs/prefs_mixin.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './browseros_prefs_page.html.js';
+
+interface CustomProvider {
+  name: string;
+  url: string;
+}
+
+export interface SettingsBrowserOSPrefsPageElement {
+  $: {
+    addProviderDialog: HTMLElement;
+  };
+}
+
+const SettingsBrowserOSPrefsPageElementBase = PrefsMixin(PolymerElement);
+
+export class SettingsBrowserOSPrefsPageElement extends SettingsBrowserOSPrefsPageElementBase {
+  static get is() {
+    return 'settings-browseros-prefs-page';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      /**
+       * Preferences state.
+       */
+      prefs: {
+        type: Object,
+        notify: true,
+      },
+      
+      /**
+       * List of custom providers
+       */
+      customProviders: {
+        type: Array,
+        value: () => [],
+      },
+      
+      /**
+       * New provider name for dialog
+       */
+      newProviderName_: {
+        type: String,
+        value: '',
+      },
+      
+      /**
+       * New provider URL for dialog
+       */
+      newProviderUrl_: {
+        type: String,
+        value: '',
+      },
+    };
+  }
+
+  // Declare properties
+  declare prefs: any;
+  declare customProviders: CustomProvider[];
+  declare newProviderName_: string;
+  declare newProviderUrl_: string;
+
+  /**
+   * Initialize when attached to DOM
+   */
+  override connectedCallback() {
+    super.connectedCallback();
+    // Wait for prefs to be ready before loading
+    this.addEventListener('prefs-changed', () => {
+      if (this.prefs && !this.customProviders) {
+        this.loadCustomProviders_();
+      }
+    });
+    // Try loading immediately in case prefs are already available
+    if (this.prefs) {
+      this.loadCustomProviders_();
+    }
+  }
+  
+  /**
+   * Load custom providers from preference
+   */
+  private loadCustomProviders_() {
+    try {
+      const pref = this.getPref('browseros.custom_providers');
+      if (pref && pref.value) {
+        this.customProviders = JSON.parse(pref.value);
+      } else {
+        this.customProviders = [];
+      }
+    } catch (e) {
+      console.warn('Failed to load custom providers:', e);
+      this.customProviders = [];
+    }
+  }
+  
+  /**
+   * Save custom providers to preference
+   */
+  private saveCustomProviders_() {
+    const customProvidersJson = JSON.stringify(this.customProviders);
+    // @ts-ignore: setPrefValue exists at runtime from PrefsMixin
+    this.setPrefValue('browseros.custom_providers', customProvidersJson);
+  }
+  
+  /**
+   * Show add provider dialog
+   */
+  private showAddProviderDialog_() {
+    this.newProviderName_ = '';
+    this.newProviderUrl_ = '';
+    const dialog = this.$.addProviderDialog as any;
+    dialog.showModal();
+  }
+  
+  /**
+   * Cancel add provider dialog
+   */
+  private cancelAddProvider_() {
+    const dialog = this.$.addProviderDialog as any;
+    dialog.close();
+  }
+  
+  /**
+   * Add custom provider
+   */
+  private async addCustomProvider_() {
+    if (!this.newProviderName_ || !this.newProviderUrl_) {
+      return;
+    }
+    
+    // Validate URL
+    try {
+      const url = new URL(this.newProviderUrl_);
+      if (!url.protocol.startsWith('http')) {
+        alert('Please enter a valid HTTP or HTTPS URL');
+        return;
+      }
+    } catch (e) {
+      alert('Please enter a valid URL');
+      return;
+    }
+    
+    // Add the new provider
+    this.push('customProviders', {
+      name: this.newProviderName_,
+      url: this.newProviderUrl_
+    });
+    
+    // Save to preferences
+    this.saveCustomProviders_();
+    
+    // Clear input fields
+    this.newProviderName_ = '';
+    this.newProviderUrl_ = '';
+    
+    // Close dialog with small delay
+    await new Promise(resolve => setTimeout(resolve, 50));
+    this.cancelAddProvider_();
+    
+    // Show status message after dialog closes
+    await new Promise(resolve => setTimeout(resolve, 100));
+    this.showStatusMessage_();
+  }
+  
+  /**
+   * Delete custom provider
+   */
+  private deleteCustomProvider_(e: Event) {
+    const button = e.currentTarget as HTMLElement;
+    const index = parseInt(button.dataset['index'] || '0');
+    
+    // Remove the provider
+    this.splice('customProviders', index, 1);
+    
+    // Save to preferences
+    this.saveCustomProviders_();
+    
+    // Show status message
+    this.showStatusMessage_();
+  }
+  
+  /**
+   * Handle toolbar label toggle change
+   */
+  override ready() {
+    super.ready();
+    
+    // Listen for toggle changes
+    const toggleButton = this.shadowRoot!.querySelector('#showToolbarLabels');
+    if (toggleButton) {
+      toggleButton.addEventListener('change', () => {
+        // The toggle button will automatically update the pref through PrefsMixin
+        this.showStatusMessage_();
+      });
+    }
+  }
+  
+  /**
+   * Show status message briefly
+   */
+  private showStatusMessage_() {
+    const statusMessage = this.shadowRoot!.querySelector('#statusMessage') as HTMLElement;
+    if (statusMessage) {
+      // Remove class first to reset animation if called multiple times
+      statusMessage.classList.remove('show');
+      // Force reflow
+      void statusMessage.offsetWidth;
+      // Add class to show
+      statusMessage.classList.add('show');
+      setTimeout(() => {
+        statusMessage.classList.remove('show');
+      }, 2000);
+    }
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'settings-browseros-prefs-page': SettingsBrowserOSPrefsPageElement;
+  }
+}
+
+customElements.define(
+    SettingsBrowserOSPrefsPageElement.is, SettingsBrowserOSPrefsPageElement);
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts
index e8dd01dc3e7b6..c8996cc719973 100644
--- a/chrome/browser/resources/settings/route.ts
+++ b/chrome/browser/resources/settings/route.ts
@@ -184,6 +184,7 @@ function createRoutes(): SettingsRoutes {
   r.BASIC = new Route('/');
   r.ABOUT = new Route('/help', loadTimeData.getString('aboutPageTitle'));
   r.NXTSCAPE = new Route('/browseros-ai', 'BrowserOS AI Settings');
+  r.BROWSEROS_PREFS = new Route('/browseros-settings', 'BrowserOS Settings');
 
   r.SEARCH = r.BASIC.createSection(
       '/search', 'search', loadTimeData.getString('searchPageTitle'));
diff --git a/chrome/browser/resources/settings/router.ts b/chrome/browser/resources/settings/router.ts
index 46c2093278ceb..393a3c259c2e1 100644
--- a/chrome/browser/resources/settings/router.ts
+++ b/chrome/browser/resources/settings/router.ts
@@ -15,6 +15,7 @@ export interface SettingsRoutes {
   ABOUT: Route;
   ACCESSIBILITY: Route;
   NXTSCAPE: Route;
+  BROWSEROS_PREFS: Route;
   ADDRESSES: Route;
   ADVANCED: Route;
   AI: Route;
diff --git a/chrome/browser/resources/settings/settings.ts b/chrome/browser/resources/settings/settings.ts
index dbd5e82c285f9..35c91e53c07dc 100644
--- a/chrome/browser/resources/settings/settings.ts
+++ b/chrome/browser/resources/settings/settings.ts
@@ -33,6 +33,7 @@ export {PluralStringProxyImpl as SettingsPluralStringProxyImpl} from 'chrome://r
 export {getTrustedHTML} from 'chrome://resources/js/static_types.js';
 export {SettingsAboutPageElement} from './about_page/about_page.js';
 export {SettingsNxtscapePageElement} from './nxtscape_page/nxtscape_page.js';
+export {SettingsBrowserOSPrefsPageElement} from './browseros_prefs_page/browseros_prefs_page.js';
 export {ControlledRadioButtonElement} from './controls/controlled_radio_button.js';
 export {SettingsDropdownMenuElement} from './controls/settings_dropdown_menu.js';
 export {SettingsToggleButtonElement} from './controls/settings_toggle_button.js';
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index 403f2f2258fb8..b0c5e71a428ad 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -55,3 +55,9 @@
           prefs="{{prefs}}">
       </settings-nxtscape-page>
     </template>
+    <template is="dom-if" if="[[showPages_.browserosPrefs]]">
+      <settings-browseros-prefs-page role="main"
+          class="cr-centered-card-container"
+          prefs="{{prefs}}">
+      </settings-browseros-prefs-page>
+    </template>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.ts b/chrome/browser/resources/settings/settings_main/settings_main.ts
index 433afef3be384..2da0ef8a114fa 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.ts
+++ b/chrome/browser/resources/settings/settings_main/settings_main.ts
@@ -15,6 +15,7 @@ import 'chrome://resources/js/search_highlight_utils.js';
 import 'chrome://resources/cr_elements/cr_icon/cr_icon.js';
 import '../about_page/about_page.js';
 import '../nxtscape_page/nxtscape_page.js';
+import '../browseros_prefs_page/browseros_prefs_page.js';
 import '../basic_page/basic_page.js';
 import '../search_settings.js';
 import '../settings_shared.css.js';
@@ -34,6 +35,7 @@ interface MainPageVisibility {
   about: boolean;
   settings: boolean;
   nxtscape: boolean;
+  browserosPrefs: boolean;
 }
 
 export interface SettingsMainElement {
@@ -70,7 +72,7 @@ export class SettingsMainElement extends SettingsMainElementBase {
       showPages_: {
         type: Object,
         value() {
-          return {about: false, settings: false, nxtscape: false};
+          return {about: false, settings: false, nxtscape: false, browserosPrefs: false};
         },
       },
 
@@ -119,10 +121,12 @@ export class SettingsMainElement extends SettingsMainElementBase {
     const currentRoute = Router.getInstance().getCurrentRoute();
     const inAbout = routes.ABOUT.contains(currentRoute);
     const inNxtscape = routes.NXTSCAPE.contains(currentRoute);
+    const inBrowserOSPrefs = routes.BROWSEROS_PREFS.contains(currentRoute);
     this.showPages_ = {
       about: inAbout,
-      settings: !inAbout && !inNxtscape,
-      nxtscape: inNxtscape
+      settings: !inAbout && !inNxtscape && !inBrowserOSPrefs,
+      nxtscape: inNxtscape,
+      browserosPrefs: inBrowserOSPrefs
     };
   }
 
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index 8f123acf9b322..a1f1454c2bf2a 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -63,6 +63,12 @@
           BrowserOS AI
           <cr-ripple></cr-ripple>
         </a>
+        <a role="menuitem" id="browseros-prefs-menu" href="/browseros-settings"
+            class="cr-nav-menu-item">
+          <cr-icon icon="settings:system"></cr-icon>
+          BrowserOS Settings
+          <cr-ripple></cr-ripple>
+        </a>
         <a role="menuitem" id="autofill" href="/autofill"
             hidden="[[!pageVisibility.autofill]]"
             class="cr-nav-menu-item">
diff --git a/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc b/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
index 06259d2817b4e..6d54a267d75b0 100644
--- a/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
@@ -45,6 +45,8 @@
 #include "ui/views/controls/button/button_controller.h"
 #include "ui/views/view_class_properties.h"
 #include "ui/views/view_utils.h"
+#include "components/prefs/pref_service.h"
+#include "chrome/common/pref_names.h"
 
 DEFINE_UI_CLASS_PROPERTY_TYPE(PinnedToolbarActionFlexPriority)
 DEFINE_UI_CLASS_PROPERTY_KEY(
@@ -87,6 +89,8 @@ PinnedActionToolbarButton::PinnedActionToolbarButton(
         show_labels = browser_->profile()->GetPrefs()->GetBoolean(
             prefs::kBrowserOSShowToolbarLabels);
       }
+      else {
+      }
       
       if (show_labels) {
         // Use LabelButton::SetText directly to set permanent text
@@ -361,10 +365,22 @@ void PinnedActionToolbarButtonActionViewInterface::ActionItemChangedImpl(
 
   // Update the text from the action item for BrowserOS actions
   if (browseros::IsBrowserOSAction(action_view_->GetActionId())) {
-    // Use LabelButton::SetText directly to set permanent text
-    action_view_->views::LabelButton::SetText(action_item->GetText());
-    // Ensure the text is visible
-    action_view_->SetTextSubpixelRenderingEnabled(false);
+    // Check if labels should be shown
+    bool show_labels = true;
+    if (action_view_->GetBrowser() && action_view_->GetBrowser()->profile()) {
+      show_labels = action_view_->GetBrowser()->profile()->GetPrefs()->GetBoolean(
+          prefs::kBrowserOSShowToolbarLabels);
+    }
+    
+    if (show_labels) {
+      // Use LabelButton::SetText directly to set permanent text
+      action_view_->views::LabelButton::SetText(action_item->GetText());
+      // Ensure the text is visible
+      action_view_->SetTextSubpixelRenderingEnabled(false);
+    } else {
+      // Clear the text if labels are disabled
+      action_view_->views::LabelButton::SetText(std::u16string());
+    }
   }
 
   // Update whether the action is engaged before updating the view.
diff --git a/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h b/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h
index e1557abfda184..df7f5c078211a 100644
--- a/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h
+++ b/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h
@@ -56,6 +56,7 @@ class PinnedActionToolbarButton : public ToolbarButton {
   bool IsPinned() { return pinned_; }
   bool IsPermanent() { return permanent_; }
   views::View* GetImageContainerView() { return image_container_view(); }
+  Browser* GetBrowser() { return browser_; }
 
   bool ShouldSkipExecutionForTesting() { return skip_execution_; }
 
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 12f83b0cc1ab5..10c867a0660de 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -4273,6 +4273,18 @@ inline constexpr char kServiceWorkerToControlSrcdocIframeEnabled[] =
 // is set as a SharedWorker script URL.
 inline constexpr char kSharedWorkerBlobURLFixEnabled[] =
     "worker.shared_worker_blob_url_fix_enabled";
+
+// *************** BROWSEROS PREFS ***************
+// These are BrowserOS-specific preferences
+
+// Boolean that controls whether toolbar labels are shown for BrowserOS actions
+inline constexpr char kBrowserOSShowToolbarLabels[] =
+    "browseros.show_toolbar_labels";
+
+// JSON string containing custom AI providers for BrowserOS
+inline constexpr char kBrowserOSCustomProviders[] = 
+    "browseros.custom_providers";
+
 }  // namespace prefs
 
 #endif  // CHROME_COMMON_PREF_NAMES_H_
-- 
2.49.0

