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
11 changes: 10 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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; \
Comment on lines +50 to +56

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Automated build never toggles automated mode

The README claims automated mode is the default build (docker build -f docker/Dockerfile -t browser-operator-automated .), but the Dockerfile declares ARG AUTOMATED_MODE=false and only flips the flag when the arg is explicitly true. With the documented command the sed step is skipped, leaving BUILD_CONFIG.AUTOMATED_MODE false so OAuth is still shown and evaluation stays manual. Builders will never get the advertised automated behavior unless they pass --build-arg AUTOMATED_MODE=true. Consider changing the default to true or update the instructions to pass the arg when automated mode is desired.

Useful? React with 👍 / 👎.

fi

# Build Browser Operator version with current changes
RUN npm run build
Comment on lines +59 to 60
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

“with current changes” is misleading; build ignores PR workspace unless you COPY it.

This stage checks out upstream/main and never copies the PR’s tree, so local changes won’t be in the build. If the intent is to build this PR, COPY the needed paths (or the entire repo) before running npm run build.

Minimal overlay to include PR edits in the output:

-# Build Browser Operator version with current changes
-RUN npm run build
+# Build Browser Operator version with current changes
+# (already added above) COPY front_end /workspace/devtools/devtools-frontend/front_end
+RUN npm run build

If you intentionally build a remote ref, consider making it explicit:

- RUN git fetch upstream
- RUN git checkout upstream/main
+ ARG SOURCE_REF=main
+ RUN git fetch upstream ${SOURCE_REF} && git checkout FETCH_HEAD

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "PWD: $(pwd)"
echo "Listing repo root:"
ls -la

echo
echo "Find Dockerfile(s) (using fd if available, fallback to find):"
if command -v fd >/dev/null 2>&1; then
  fd -HI -t f 'Dockerfile' || true
else
  find . -maxdepth 6 -type f -name 'Dockerfile' || true
fi

echo
echo "Search for 'RUN npm run build' across repo:"
rg -n --hidden -S "RUN npm run build" -g '!*node_modules/**' || true

echo
# Prefer docker/Dockerfile if present
if [ -f docker/Dockerfile ]; then
  echo "---- docker/Dockerfile (with line numbers) ----"
  nl -ba docker/Dockerfile | sed -n '1,240p'
  echo "---- Relevant matches in docker/Dockerfile ----"
  rg -n -C3 "git fetch|checkout upstream|checkout|upstream/main|COPY|WORKDIR|ARG SOURCE_REF|RUN npm run build" docker/Dockerfile || true
else
  echo "docker/Dockerfile not found — printing every Dockerfile that contains 'npm run build'."
  files=$(rg --no-line-number --hidden -S "RUN npm run build" --glob '!*node_modules/**' --files || true)
  if [ -z "$files" ]; then
    echo "No Dockerfile with 'npm run build' found."
  else
    for f in $files; do
      echo
      echo "---- $f (with line numbers) ----"
      nl -ba "$f" | sed -n '1,240p'
      echo "---- Relevant matches in $f ----"
      rg -n -C3 "git fetch|checkout upstream|checkout|upstream/main|COPY|WORKDIR|ARG SOURCE_REF|RUN npm run build" "$f" || true
    done
  fi
fi

echo
echo "Also search repository for 'git fetch upstream' or 'checkout upstream' to confirm behavior:"
rg -n --hidden -S "git fetch upstream|checkout upstream|checkout FETCH_HEAD|checkout upstream/main" || true

Length of output: 3814


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "PWD: $(pwd)"
echo
echo "---- docker/Dockerfile (full) ----"
sed -n '1,400p' docker/Dockerfile || true

echo
echo "---- Repo-wide searches ----"
echo "RUN npm run build occurrences:"
grep -nR --line-number --binary-files=without-match "RUN npm run build" || true

echo
echo "git fetch / checkout upstream occurrences:"
grep -nR --line-number --binary-files=without-match -E "git fetch|checkout upstream|checkout FETCH_HEAD|upstream/main" || true

echo
echo "COPY of front_end / repo files occurrences:"
grep -nR --line-number --binary-files=without-match -E "COPY .*front_end|COPY .*front-end|COPY \.|COPY .* /workspace" || true

echo
echo "---- Context around 'RUN npm run build' in docker/Dockerfile ----"
grep -n -C3 --line-number "RUN npm run build" docker/Dockerfile || true

Length of output: 3481


Build ignores local PR edits — Dockerfile checks out upstream/main before the final build.

docker/Dockerfile adds an upstream remote and runs git fetch && git checkout upstream/main before the second RUN npm run build and never COPYs the repo into the image, so “current changes” won’t be included. Location: docker/Dockerfile lines 46–60.

Minimal overlay to include PR edits in the output:

-# Build Browser Operator version with current changes
-RUN npm run build
+# Build Browser Operator version with current changes
+# (already added above) COPY front_end /workspace/devtools/devtools-frontend/front_end
+RUN npm run build

If you intentionally build a remote ref, make that explicit:

- RUN git fetch upstream
- RUN git checkout upstream/main
+ ARG SOURCE_REF=main
+ RUN git fetch upstream ${SOURCE_REF} && git checkout FETCH_HEAD

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In docker/Dockerfile around lines 46–60 the Docker build adds an upstream remote
and checks out upstream/main before the final RUN npm run build, and the
repository contents are not copied into the image, so local PR edits are never
included; fix by removing the git fetch/checkout of upstream/main (or make the
remote ref explicit via a build ARG) and ensure the workspace is COPYed into the
image before running npm run build (i.e., add COPY . /app (or appropriate path)
and set WORKDIR before the build step) so the build uses current changes, or
alternatively make the Dockerfile accept a build-time ref/ARG and document that
it intentionally builds a remote ref.


# Production stage
Expand Down
37 changes: 33 additions & 4 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions front_end/panels/ai_chat/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
8 changes: 8 additions & 0 deletions front_end/panels/ai_chat/common/EvaluationConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand Down Expand Up @@ -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') || '';
Expand Down
20 changes: 20 additions & 0 deletions front_end/panels/ai_chat/core/BuildConfig.ts
Original file line number Diff line number Diff line change
@@ -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;
19 changes: 6 additions & 13 deletions front_end/panels/ai_chat/ui/AIChatPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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'];
Expand All @@ -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;
}

Expand Down Expand Up @@ -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),
};
Expand Down
Loading