diff --git a/docker/Dockerfile b/docker/Dockerfile index 41f08a1b465..2a6cb50340b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -47,7 +47,16 @@ RUN git remote add upstream https://github.com/BrowserOperator/browser-operator- RUN git fetch upstream RUN git checkout upstream/main -# Build Browser Operator version +# Allow configurable automated mode +ARG AUTOMATED_MODE=false + +# Set build-time flags based on Docker arg +RUN if [ "$AUTOMATED_MODE" = "true" ]; then \ + sed -i 's/AUTOMATED_MODE: false/AUTOMATED_MODE: true/' \ + front_end/panels/ai_chat/core/BuildConfig.ts; \ + fi + +# Build Browser Operator version with current changes RUN npm run build # Production stage diff --git a/docker/README.md b/docker/README.md index 379527aceb5..ece2c08ebf0 100644 --- a/docker/README.md +++ b/docker/README.md @@ -22,8 +22,11 @@ The Docker setup uses a multi-stage build process: From the repository root directory: ```bash -# Build the Docker image -docker build -f docker/Dockerfile -t devtools-frontend . +# Build with automated mode (default - bypasses OAuth, auto-enables evaluation) +docker build -f docker/Dockerfile -t browser-operator-automated . + +# Build with normal mode (requires manual authentication) +docker build -f docker/Dockerfile --build-arg AUTOMATED_MODE=false -t browser-operator-manual . # Or use docker-compose (recommended) docker-compose -f docker/docker-compose.yml build @@ -32,8 +35,11 @@ docker-compose -f docker/docker-compose.yml build ### Running the Container ```bash -# Using docker run -docker run -d -p 8000:8000 --name devtools-frontend devtools-frontend +# Automated mode (no authentication required, evaluation auto-enabled) +docker run -d -p 8000:8000 --name browser-operator-automated browser-operator-automated + +# Manual mode (requires OAuth/API key setup) +docker run -d -p 8000:8000 --name browser-operator-manual browser-operator-manual # Or using docker-compose (recommended) docker-compose -f docker/docker-compose.yml up -d @@ -67,6 +73,29 @@ docker/ └── README.md # This file ``` +## Automated Mode vs Manual Mode + +### Automated Mode (Default) +- **Purpose**: Optimized for Docker/CI environments and automated workflows +- **Authentication**: Bypasses OAuth panel - no manual setup required +- **Evaluation**: Automatically enables evaluation mode for API wrapper connectivity +- **Use cases**: Production deployments, CI/CD, headless automation, API integration + +### Manual Mode +- **Purpose**: Standard interactive usage +- **Authentication**: Requires OAuth setup or API key configuration +- **Evaluation**: Manual enable/disable in settings +- **Use cases**: Development, interactive testing, manual usage + +```bash +# Example automated mode workflow +docker build -f docker/Dockerfile -t browser-operator-automated . +docker run -d -p 8000:8000 --name browser-operator browser-operator-automated + +# Ready to use immediately - no authentication required! +# Evaluation server can connect automatically via WebSocket (ws://localhost:8080) +``` + ## Advanced Usage ### Development Mode diff --git a/front_end/panels/ai_chat/BUILD.gn b/front_end/panels/ai_chat/BUILD.gn index 1fea191b0c1..5e364879389 100644 --- a/front_end/panels/ai_chat/BUILD.gn +++ b/front_end/panels/ai_chat/BUILD.gn @@ -48,6 +48,7 @@ devtools_module("ai_chat") { "core/Types.ts", "core/AgentService.ts", "core/Constants.ts", + "core/BuildConfig.ts", "core/structured_response.ts", "core/GraphConfigs.ts", "core/ConfigurableGraph.ts", @@ -176,6 +177,7 @@ _ai_chat_sources = [ "core/Types.ts", "core/AgentService.ts", "core/Constants.ts", + "core/BuildConfig.ts", "core/structured_response.ts", "core/GraphConfigs.ts", "core/ConfigurableGraph.ts", diff --git a/front_end/panels/ai_chat/common/EvaluationConfig.ts b/front_end/panels/ai_chat/common/EvaluationConfig.ts index 66ea9134ec3..be5169fe6cb 100644 --- a/front_end/panels/ai_chat/common/EvaluationConfig.ts +++ b/front_end/panels/ai_chat/common/EvaluationConfig.ts @@ -4,6 +4,7 @@ import { createLogger } from '../core/Logger.js'; import { WebSocketRPCClient } from './WebSocketRPCClient.js'; +import { BUILD_CONFIG } from '../core/BuildConfig.js'; const logger = createLogger('EvaluationConfig'); @@ -49,6 +50,13 @@ class EvaluationConfigStore { private loadFromLocalStorage(): void { try { + // In automated mode, set default to enabled if not already set + if (BUILD_CONFIG.AUTOMATED_MODE && + localStorage.getItem('ai_chat_evaluation_enabled') === null) { + localStorage.setItem('ai_chat_evaluation_enabled', 'true'); + logger.info('Automated mode: defaulted evaluation to enabled'); + } + const enabled = localStorage.getItem('ai_chat_evaluation_enabled') === 'true'; const endpoint = localStorage.getItem('ai_chat_evaluation_endpoint') || 'ws://localhost:8080'; const secretKey = localStorage.getItem('ai_chat_evaluation_secret_key') || ''; diff --git a/front_end/panels/ai_chat/core/BuildConfig.ts b/front_end/panels/ai_chat/core/BuildConfig.ts new file mode 100644 index 00000000000..91d89fec191 --- /dev/null +++ b/front_end/panels/ai_chat/core/BuildConfig.ts @@ -0,0 +1,20 @@ +// Copyright 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * Build-time configuration for automated deployments and Docker environments. + * + * This file contains constants that are set during the build process to configure + * behavior for different deployment scenarios. + */ +export const BUILD_CONFIG = { + /** + * Automated mode flag for Docker/CI deployments. + * When true: + * - Bypasses OAuth authentication panel + * - Automatically enables evaluation mode + * - Optimized for headless/automated usage + */ + AUTOMATED_MODE: false, // Will be set to true during Docker build +} as const; \ No newline at end of file diff --git a/front_end/panels/ai_chat/ui/AIChatPanel.ts b/front_end/panels/ai_chat/ui/AIChatPanel.ts index ec1a673f090..6dd9055451a 100644 --- a/front_end/panels/ai_chat/ui/AIChatPanel.ts +++ b/front_end/panels/ai_chat/ui/AIChatPanel.ts @@ -20,6 +20,7 @@ import { OpenRouterProvider } from '../LLM/OpenRouterProvider.js'; import { createLogger } from '../core/Logger.js'; import { isEvaluationEnabled, getEvaluationConfig } from '../common/EvaluationConfig.js'; import { EvaluationAgent } from '../evaluation/remote/EvaluationAgent.js'; +import { BUILD_CONFIG } from '../core/BuildConfig.js'; // Import of LiveAgentSessionComponent is not required here; the element is // registered by ChatView where it is used. @@ -1395,9 +1396,8 @@ export class AIChatPanel extends UI.Panel.Panel { * @returns true if at least one provider has valid credentials */ #hasAnyProviderCredentials(): boolean { - logger.info('=== CHECKING ALL PROVIDER CREDENTIALS ==='); + const selectedProvider = localStorage.getItem(PROVIDER_SELECTION_KEY) || 'openai'; - logger.info('Currently selected provider:', selectedProvider); // Check all providers except LiteLLM (unless LiteLLM is selected) const providers = ['openai', 'groq', 'openrouter']; @@ -1407,19 +1407,13 @@ export class AIChatPanel extends UI.Panel.Panel { providers.push('litellm'); } - logger.info('Providers to check:', providers); - for (const provider of providers) { - logger.info(`Checking provider: ${provider}`); const validation = LLMClient.validateProviderCredentials(provider); - logger.info(`Provider ${provider} validation result:`, validation); if (validation.isValid) { - logger.info(`✅ Found valid credentials for provider: ${provider}`); return true; } } - logger.info('❌ No valid credentials found for any provider'); return false; } @@ -1997,12 +1991,11 @@ export class AIChatPanel extends UI.Panel.Panel { inputPlaceholder: this.#getInputPlaceholderText(), // Add OAuth login state showOAuthLogin: (() => { + if (BUILD_CONFIG.AUTOMATED_MODE) { + return false; + } const hasCredentials = this.#hasAnyProviderCredentials(); - const showOAuth = !hasCredentials; - logger.info('=== OAUTH LOGIN UI DECISION ==='); - logger.info('hasAnyProviderCredentials:', hasCredentials); - logger.info('showOAuthLogin will be set to:', showOAuth); - return showOAuth; + return !hasCredentials; })(), onOAuthLogin: this.#handleOAuthLogin.bind(this), };