diff --git a/src/web-ui/src/infrastructure/config/components/AIFeaturesConfig.scss b/src/web-ui/src/infrastructure/config/components/AIFeaturesConfig.scss index c2af710016..5cbb2dd555 100644 --- a/src/web-ui/src/infrastructure/config/components/AIFeaturesConfig.scss +++ b/src/web-ui/src/infrastructure/config/components/AIFeaturesConfig.scss @@ -110,288 +110,6 @@ background: transparent; } - &__pet-picker { - width: 100%; - display: block; - } - - &__pet-row-heading { - width: 100%; - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: $size-gap-3; - } - - &__pet-row-copy { - min-width: 0; - display: flex; - flex-direction: column; - gap: 4px; - } - - &__pet-row-title { - color: var(--color-text-primary); - font-size: var(--font-size-sm); - font-weight: var(--font-weight-medium); - line-height: var(--line-height-base); - } - - &__pet-row-description { - color: var(--color-text-secondary); - font-size: var(--font-size-xs); - font-weight: var(--font-weight-normal); - line-height: var(--line-height-relaxed); - } - - &__pet-select { - min-width: 0; - } - - &__pet-select .select__trigger { - min-height: 38px; - } - - &__pet-select .select__dropdown { - max-height: 320px; - } - - &__pet-actions { - display: flex; - align-items: center; - gap: $size-gap-2; - white-space: nowrap; - } - - &__pet-chooser { - min-width: 0; - display: flex; - flex-direction: column; - gap: $size-gap-2; - } - - &__pet-expand-button { - width: 100%; - min-width: 0; - min-height: 48px; - display: flex; - align-items: center; - justify-content: space-between; - gap: $size-gap-3; - padding: 5px 10px 5px 8px; - border: 1px solid var(--border-subtle); - border-radius: var(--size-radius-sm); - color: var(--color-text-primary); - background: var(--element-bg-subtle); - cursor: pointer; - transition: - border-color 0.16s ease, - background 0.16s ease, - box-shadow 0.16s ease; - } - - &__pet-expand-button:hover { - border-color: var(--border-medium); - background: var(--element-bg-soft); - } - - &__pet-expand-button:focus-visible { - outline: 2px solid var(--color-accent-500); - outline-offset: 2px; - } - - &__pet-expand-button svg { - flex-shrink: 0; - transition: transform 0.16s ease; - } - - &__pet-expand-chevron--open { - transform: rotate(180deg); - } - - &__pet-expand-current { - min-width: 0; - display: flex; - align-items: center; - gap: $size-gap-3; - } - - &__pet-list { - max-height: min(360px, 52vh); - overflow-y: auto; - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: $size-gap-2; - padding: 12px; - border: 1px solid var(--border-subtle); - border-radius: var(--size-radius-sm); - background: color-mix(in srgb, var(--element-bg-subtle) 52%, transparent); - } - - &__pet-list-group { - grid-column: 1 / -1; - padding: 6px 2px 2px; - color: var(--color-text-muted); - font-size: var(--font-size-xs); - font-weight: var(--font-weight-medium); - line-height: var(--line-height-tight); - letter-spacing: 0; - } - - &__pet-select-option { - min-width: 0; - width: 100%; - min-height: 64px; - display: grid; - grid-template-columns: minmax(0, 1fr) max-content; - align-items: center; - gap: $size-gap-2; - padding: 9px 10px; - border: 1px solid var(--border-subtle); - border-radius: var(--size-radius-sm); - color: var(--color-text-primary); - text-align: left; - background: color-mix(in srgb, var(--element-bg-base) 74%, transparent); - cursor: pointer; - transition: - border-color 0.16s ease, - background 0.16s ease, - box-shadow 0.16s ease; - } - - &__pet-select-option:hover, - &__pet-select-option:focus-visible { - border-color: var(--border-medium); - background: color-mix(in srgb, var(--element-bg-soft) 84%, transparent); - outline: none; - } - - &__pet-select-option:focus-visible { - box-shadow: 0 0 0 2px var(--color-accent-500); - } - - &__pet-select-option--selected { - border-color: color-mix(in srgb, var(--color-accent-500) 58%, var(--border-subtle)); - background: color-mix(in srgb, var(--color-accent-500) 10%, var(--element-bg-base)); - } - - &__pet-select-option-main { - min-width: 0; - flex: 1; - display: flex; - align-items: center; - gap: $size-gap-3; - } - - &__pet-select-delete { - flex-shrink: 0; - } - - &__pet-select-actions { - min-width: 28px; - height: 28px; - display: flex; - align-items: center; - justify-content: flex-end; - position: relative; - } - - &__pet-select-check { - flex-shrink: 0; - color: var(--color-accent-500); - transition: opacity 0.14s ease; - } - - &__pet-select-delete { - position: absolute; - inset: 0; - opacity: 0; - pointer-events: none; - transition: opacity 0.14s ease; - } - - &__pet-select-option:hover &__pet-select-delete, - &__pet-select-option:focus-within &__pet-select-delete { - opacity: 1; - pointer-events: auto; - } - - &__pet-select-option:hover &__pet-select-actions--deletable &__pet-select-check, - &__pet-select-option:focus-within &__pet-select-actions--deletable &__pet-select-check { - opacity: 0; - } - - &__pet-select-thumb { - width: 36px; - height: 36px; - display: flex; - align-items: center; - justify-content: center; - overflow: visible; - flex-shrink: 0; - } - - &__pet-select-panda { - transform: scale(0.62); - } - - &__pet-select-text { - min-width: 0; - display: flex; - flex-direction: column; - gap: 3px; - } - - &__pet-select-label, - &__pet-select-value { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - &__pet-select-description { - color: var(--color-text-muted); - font-size: var(--font-size-xs); - line-height: $line-height-tight; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - &__pet-preview-sprite { - width: 34px; - height: 38px; - background-image: var(--bitfun-pet-preview-src); - background-repeat: no-repeat; - background-size: 800% 900%; - background-position: 0 0; - image-rendering: pixelated; - animation: bitfun-config-pet-preview 1.2s steps(6) infinite; - } - -} - -@media (prefers-reduced-motion: reduce) { - .bitfun-func-agent-config { - &__pet-expand-button, - &__pet-expand-button svg, - &__pet-select-option, - &__pet-preview-sprite { - animation: none; - transition: none; - } - } -} - -@keyframes bitfun-config-pet-preview { - from { - background-position-x: 0; - } - - to { - background-position-x: 85.7142857%; - } } @container config-panel (max-width: 520px) { @@ -399,22 +117,5 @@ &__row-control { align-items: flex-start; } - - &__pet-picker { - display: block; - } - - &__pet-row-heading { - flex-direction: column; - gap: $size-gap-2; - } - - &__pet-actions { - justify-content: flex-start; - } - - &__pet-list { - grid-template-columns: minmax(0, 1fr); - } } } diff --git a/src/web-ui/src/infrastructure/config/components/SessionConfig.tsx b/src/web-ui/src/infrastructure/config/components/SessionConfig.tsx index a78499193e..03d05974a1 100644 --- a/src/web-ui/src/infrastructure/config/components/SessionConfig.tsx +++ b/src/web-ui/src/infrastructure/config/components/SessionConfig.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { FolderOpen, RefreshCw, ChevronDown, Plus, Trash2, Check, Info } from 'lucide-react'; +import { FolderOpen, RefreshCw, ChevronDown, Info } from 'lucide-react'; import { Switch, NumberInput, @@ -18,14 +18,6 @@ import { } from '@/component-library'; import { ConfigPageHeader, ConfigPageLayout, ConfigPageContent, ConfigPageSection, ConfigPageRow } from './common'; import { aiExperienceConfigService, type AIExperienceSettings } from '../services/AIExperienceConfigService'; -import { - DEFAULT_AGENT_COMPANION_PET, - deleteAgentCompanionPetPackage, - importAgentCompanionPetPackage, - listAgentCompanionPets, - releaseAgentCompanionPetPreviewBlobs, - type AgentCompanionPetPackage, -} from '../services/AgentCompanionPetService'; import { configManager } from '../services/ConfigManager'; import { systemAPI } from '@/infrastructure/api/service-api/SystemAPI'; import { useNotification, notificationService } from '@/shared/notification-system'; @@ -37,8 +29,7 @@ import { DEFAULT_LANGUAGE_TEMPLATES, } from '../types'; import { ModelSelectionRadio } from './ModelSelectionRadio'; -import { ChatInputPixelPet } from '@/flow_chat/components/ChatInputPixelPet'; -import { ask, open } from '@tauri-apps/plugin-dialog'; +import { open } from '@tauri-apps/plugin-dialog'; import { createLogger } from '@/shared/utils/logger'; import './AIFeaturesConfig.scss'; import './DebugConfig.scss'; @@ -98,11 +89,6 @@ const SessionSettingsPanels: React.FC = ({ variant } // ── Session config state ───────────────────────────────────────────────── const [isLoading, setIsLoading] = useState(true); const [settings, setSettings] = useState(null); - const [companionPets, setCompanionPets] = useState([]); - const [companionPetsLoading, setCompanionPetsLoading] = useState(false); - const [companionPetImporting, setCompanionPetImporting] = useState(false); - const [companionPetDeletingPath, setCompanionPetDeletingPath] = useState(null); - const [companionPetListExpanded, setCompanionPetListExpanded] = useState(false); const [models, setModels] = useState([]); const [funcAgentModels, setFuncAgentModels] = useState>({}); const [skipToolConfirmation, setSkipToolConfirmation] = useState(true); @@ -217,7 +203,6 @@ const SessionSettingsPanels: React.FC = ({ variant } debugConfigData, computerUseCfg, browserControlPreferredBrowser, - loadedCompanionPets, ] = await Promise.all([ aiExperienceConfigService.getSettingsAsync(), configManager.getConfig('ai.models') || [], @@ -230,11 +215,9 @@ const SessionSettingsPanels: React.FC = ({ variant } configManager.getConfig('ai.debug_mode_config'), configManager.getConfig('ai.computer_use_enabled'), configManager.getConfig('ai.browser_control_preferred_browser'), - listAgentCompanionPets(), ]); setSettings(loadedSettings); - setCompanionPets(loadedCompanionPets); setModels(allModels as AIModelConfig[]); setFuncAgentModels(funcAgentModelsData as Record); setSkipToolConfirmation(skipConfirm ?? true); @@ -279,97 +262,6 @@ const SessionSettingsPanels: React.FC = ({ variant } } }; - const handleRefreshCompanionPets = async () => { - setCompanionPetsLoading(true); - try { - setCompanionPets(await listAgentCompanionPets()); - } finally { - setCompanionPetsLoading(false); - } - }; - - const handleImportCompanionPet = async () => { - if (!IS_TAURI_DESKTOP) return; - setCompanionPetImporting(true); - try { - const selected = await open({ - directory: false, - multiple: false, - title: t('features.agentCompanion.importDialogTitle'), - filters: [{ name: 'Petdex', extensions: ['zip'] }], - }); - if (!selected || Array.isArray(selected)) return; - const imported = await importAgentCompanionPetPackage(selected); - const refreshed = await listAgentCompanionPets(); - setCompanionPets(refreshed); - await updateSetting('agent_companion_pet', { - id: imported.id, - displayName: imported.displayName, - description: imported.description, - source: imported.source, - packagePath: imported.packagePath, - spritesheetPath: imported.spritesheetPath, - spritesheetMimeType: imported.spritesheetMimeType, - }); - } catch (error) { - log.error('Failed to import Agent companion pet', error); - notification.error(t('features.agentCompanion.importFailed')); - } finally { - setCompanionPetImporting(false); - } - }; - - const handleDeleteCompanionPet = async (event: React.MouseEvent, pet: AgentCompanionPetPackage) => { - event.preventDefault(); - event.stopPropagation(); - if (!IS_TAURI_DESKTOP || pet.source !== 'user' || !settings) return; - const confirmed = await ask(t('features.agentCompanion.deleteConfirmBody'), { - title: t('features.agentCompanion.deleteConfirmTitle'), - kind: 'warning', - }); - if (!confirmed) return; - setCompanionPetDeletingPath(pet.packagePath); - try { - await deleteAgentCompanionPetPackage(pet.packagePath); - releaseAgentCompanionPetPreviewBlobs(pet.packagePath, pet.spritesheetPath); - const refreshed = await listAgentCompanionPets(); - setCompanionPets(refreshed); - if (settings.agent_companion_pet?.packagePath === pet.packagePath) { - const next = { ...settings, agent_companion_pet: DEFAULT_AGENT_COMPANION_PET }; - setSettings(next); - await aiExperienceConfigService.saveSettings(next); - } - notification.success(t('features.agentCompanion.deleteSuccess')); - } catch (error) { - log.error('Failed to delete Agent companion pet', error); - notification.error(t('features.agentCompanion.deleteFailed')); - } finally { - setCompanionPetDeletingPath(null); - } - }; - - const companionPetOptions: SelectOption[] = companionPets.map(pet => ({ - value: pet.packagePath, - label: pet.displayName, - description: pet.description ?? undefined, - group: pet.source === 'preset' - ? t('features.agentCompanion.groupPreset') - : t('features.agentCompanion.groupImported'), - })); - - const companionDisplayModeOptions: SelectOption[] = [ - { - value: 'desktop', - label: t('features.agentCompanion.displayDesktop'), - description: t('features.agentCompanion.displayDesktopDesc'), - }, - { - value: 'input', - label: t('features.agentCompanion.displayInput'), - description: t('features.agentCompanion.displayInputDesc'), - }, - ]; - const subagentBatchExecutionPolicyOptions: SelectOption[] = [ { value: 'safe_only', @@ -402,30 +294,6 @@ const SessionSettingsPanels: React.FC = ({ variant } ); - const selectedCompanionPetPackage = settings?.agent_companion_pet - ? companionPets.find(pet => pet.packagePath === settings.agent_companion_pet?.packagePath) ?? null - : null; - const selectedCompanionPet = selectedCompanionPetPackage ?? settings?.agent_companion_pet ?? DEFAULT_AGENT_COMPANION_PET; - const selectedCompanionPetValue = selectedCompanionPet.packagePath; - const selectedCompanionPetOption = companionPetOptions.find(option => option.value === selectedCompanionPetValue) - ?? companionPetOptions[0]; - - const handleCompanionPetChange = async (value: string | number | (string | number)[]) => { - const selectedValue = String(Array.isArray(value) ? value[0] : value); - const pet = companionPets.find(item => item.packagePath === selectedValue); - if (!pet) return; - await updateSetting('agent_companion_pet', { - id: pet.id, - displayName: pet.displayName, - description: pet.description, - source: pet.source, - packagePath: pet.packagePath, - spritesheetPath: pet.spritesheetPath, - spritesheetMimeType: pet.spritesheetMimeType, - }); - setCompanionPetListExpanded(false); - }; - const getModelName = useCallback((modelId: string | null | undefined): string | undefined => { if (!modelId) return undefined; return models.find(m => m.id === modelId)?.name; @@ -866,193 +734,6 @@ const SessionSettingsPanels: React.FC = ({ variant } - {/* ── Agent companion (collapsed input) ─────────────────── */} - - -
- updateSetting('enable_agent_companion', e.target.checked)} - size="small" - /> -
-
- -