feat(chat): write API keys to OpenClaw and embed Control UI for chat

Part 1: API Key Integration
- Create electron/utils/openclaw-auth.ts to write keys to
  ~/.openclaw/agents/main/agent/auth-profiles.json
- Update provider:save and provider:setApiKey IPC handlers to
  persist keys to OpenClaw auth-profiles alongside ClawX storage
- Save API key to OpenClaw on successful validation in Setup wizard
- Pass provider API keys as environment variables when starting
  the Gateway process (ANTHROPIC_API_KEY, OPENROUTER_API_KEY, etc.)

Part 2: Embed OpenClaw Control UI for Chat
- Replace custom Chat UI with <webview> embedding the Gateway's
  built-in Control UI at http://127.0.0.1:{port}/?token={token}
- Add gateway:getControlUiUrl IPC handler to provide tokenized URL
- Enable webviewTag in Electron BrowserWindow preferences
- Override X-Frame-Options/CSP headers to allow webview embedding
- Suppress noisy control-ui token_mismatch stderr messages
- Add loading/error states for the embedded webview

This fixes the "No API key found for provider" error and replaces
the buggy custom chat implementation with OpenClaw's battle-tested
Control UI.
This commit is contained in:
Haze
2026-02-06 03:12:17 +08:00
Unverified
parent b01952fba7
commit 284861a0f5
7 changed files with 414 additions and 380 deletions

View File

@@ -2,7 +2,7 @@
* Electron Main Process Entry
* Manages window creation, system tray, and IPC handlers
*/
import { app, BrowserWindow, ipcMain, shell } from 'electron';
import { app, BrowserWindow, ipcMain, session, shell } from 'electron';
import { join } from 'path';
import { GatewayManager } from '../gateway/manager';
import { registerIpcHandlers } from './ipc-handlers';
@@ -32,6 +32,7 @@ function createWindow(): BrowserWindow {
nodeIntegration: false,
contextIsolation: true,
sandbox: false,
webviewTag: true, // Enable <webview> for embedding OpenClaw Control UI
},
titleBarStyle: process.platform === 'darwin' ? 'hiddenInset' : 'default',
trafficLightPosition: { x: 16, y: 16 },
@@ -74,6 +75,28 @@ async function initialize(): Promise<void> {
// Create system tray
createTray(mainWindow);
// Override security headers for the OpenClaw Control UI webview
// The Control UI sets X-Frame-Options: DENY and CSP frame-ancestors 'none'
// which prevents embedding in an Electron webview
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
const headers = { ...details.responseHeaders };
// Remove X-Frame-Options to allow embedding in webview
delete headers['X-Frame-Options'];
delete headers['x-frame-options'];
// Remove restrictive CSP frame-ancestors
if (headers['Content-Security-Policy']) {
headers['Content-Security-Policy'] = headers['Content-Security-Policy'].map(
(csp) => csp.replace(/frame-ancestors\s+'none'/g, "frame-ancestors 'self' *")
);
}
if (headers['content-security-policy']) {
headers['content-security-policy'] = headers['content-security-policy'].map(
(csp) => csp.replace(/frame-ancestors\s+'none'/g, "frame-ancestors 'self' *")
);
}
callback({ responseHeaders: headers });
});
// Register IPC handlers
registerIpcHandlers(gatewayManager, mainWindow);