import { useCallback, useEffect, useState } from 'react'; import { Download, Loader2 } from 'lucide-react'; import { Button } from '../../../../../shared/view/ui'; import { authenticatedFetch } from '../../../../../utils/api'; import SettingsCard from '../../SettingsCard'; import SettingsRow from '../../SettingsRow'; import SettingsSection from '../../SettingsSection'; import SettingsToggle from '../../SettingsToggle'; type ComputerUseSettings = { enabled: boolean; agentToolsEnabled: boolean; }; type ComputerUseStatus = { enabled: boolean; runtime: 'cloud' | 'local'; available: boolean; nutInstalled: boolean; screenshotInstalled: boolean; installInProgress: boolean; agentToolsEnabled: boolean; message: string; }; async function readJson(response: Response): Promise { const data = await response.json(); if (!response.ok || data.success === false) { throw new Error(data.error || data.details || `Request failed (${response.status})`); } return data as T; } export default function ComputerUseSettingsTab() { const [settings, setSettings] = useState({ enabled: false, agentToolsEnabled: false }); const [status, setStatus] = useState(null); const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); const [isInstalling, setIsInstalling] = useState(false); const [error, setError] = useState(null); const loadState = useCallback(async () => { setError(null); const [settingsResponse, statusResponse] = await Promise.all([ authenticatedFetch('/api/computer-use/settings'), authenticatedFetch('/api/computer-use/status'), ]); const settingsData = await readJson<{ data: { settings: ComputerUseSettings } }>(settingsResponse); const statusData = await readJson<{ data: ComputerUseStatus }>(statusResponse); setSettings(settingsData.data.settings); setStatus(statusData.data); }, []); useEffect(() => { setIsLoading(true); void loadState() .catch((err) => setError(err instanceof Error ? err.message : 'Failed to load Computer Use settings')) .finally(() => setIsLoading(false)); }, [loadState]); const updateSettings = async (nextSettings: Partial) => { setIsSaving(true); setError(null); try { const response = await authenticatedFetch('/api/computer-use/settings', { method: 'PUT', body: JSON.stringify(nextSettings), }); const data = await readJson<{ data: { settings: ComputerUseSettings } }>(response); setSettings(data.data.settings); window.dispatchEvent(new Event('computerUseSettingsChanged')); await loadState(); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to save Computer Use settings'); } finally { setIsSaving(false); } }; const installRuntime = async () => { setIsInstalling(true); setError(null); try { const response = await authenticatedFetch('/api/computer-use/runtime/install', { method: 'POST' }); await readJson(response); await loadState(); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to install Computer Use runtime'); } finally { setIsInstalling(false); } }; const isCloud = status?.runtime === 'cloud'; const needsRuntime = Boolean(settings.enabled && !isCloud && status && (!status.nutInstalled || !status.screenshotInstalled)); return (
Computer Use can control your entire desktop. Agents act only while you grant control from the Computer panel, and any action stops the moment you press Stop.
void updateSettings({ enabled: value })} ariaLabel="Enable Computer Use" disabled={isLoading || isSaving} /> void updateSettings({ agentToolsEnabled: value })} ariaLabel="Enable Computer Tools for Agents" disabled={isLoading || isSaving || !settings.enabled} /> {(needsRuntime || isCloud || error) && (
{isCloud && (
{status?.message || 'Cloud Computer Use requires a linked CloudCLI Desktop Agent on the user machine.'}
)} {needsRuntime && (
Desktop runtime required

{status?.message || 'Install the desktop control runtime needed to capture the screen and drive input.'}

Control lib: {status?.nutInstalled ? 'installed' : 'missing'} Screen capture: {status?.screenshotInstalled ? 'installed' : 'missing'}
)} {error && (
{error}
)}
)}
); }