Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
58ae575
feat(desktop): AgentTeam management + TeamRunConsole interactive + te…
Jun 2, 2026
9ca99d5
Merge dev/delicious233 into dev/trump — resolve 7 conflicts
Jun 2, 2026
6dd28ae
Merge dev/delicious233 (cb94c81) into dev/trump — resolve i18n conflicts
Jun 2, 2026
3a9c6bc
fix(desktop): update hubClient test to expect DEV-mode HUB_URL default
Jun 2, 2026
edb3d04
chore: remove leftover i18n merge temp files
Jun 2, 2026
8e3e3e1
ci: fix frontend-web missing pnpm and E2E smoke missing playwright co…
Jun 2, 2026
6d0edc9
ci: fix frontend-web cache-dependency-path to app/pnpm-lock.yaml
Jun 2, 2026
52a37e9
ci: make frontend-web lint debt-visibility only like desktop
Jun 2, 2026
b780665
fix(web): add missing closing brace in AgentList.module.css
Jun 2, 2026
a791883
fix(edge-server): remove BOM from opencode.go and fix cross-platform …
Jun 2, 2026
32a65da
fix: resolve go-edge pipe race and web vitest emoji-mart JSON import
Jun 2, 2026
4891e92
fix(e2e): align playwright webServer port with Vite dev server (5173 …
Jun 2, 2026
4bf6d83
fix(ci): resolve remaining 3 CI failures - go-edge BOM, web emoji-mar…
Jun 2, 2026
5b426ee
fix(ci): lower security coverage threshold, use vite preview for E2E,…
Jun 2, 2026
cc4b0aa
fix(ci): mock @emoji-mart/data in vitest, fix E2E preview port
Jun 2, 2026
8debe7d
fix(ci): stub @emoji-mart/data via resolve.alias, simplify E2E webServer
Jun 2, 2026
821421f
fix(ci): use Vite plugin resolveId for @emoji-mart/data, start E2E se…
Jun 2, 2026
cc3fb55
fix(ci): use Node.js ESM loader to mock @emoji-mart/data, fix E2E pre…
Jun 2, 2026
0819ee4
fix(ci): use Node.js ESM loader to mock @emoji-mart/data, fix E2E pre…
Jun 2, 2026
4357824
fix(ci): run vitest directly via node --import instead of NODE_OPTIONS
Jun 2, 2026
cc4c95d
fix(e2e): use python http.server for more reliable static serving
Jun 2, 2026
11f7420
fix(ci): run vitest via shell wrapper with inline NODE_OPTIONS instea…
Jun 2, 2026
859e20c
fix(ci): catch ERR_MODULE_NOT_FOUND for @lobehub subpath imports in E…
Jun 2, 2026
86091d0
fix(ci): catch all resolution errors in @lobehub subtree, not just ER…
Jun 2, 2026
bbcb4a0
fix(ci): catch all node_modules resolution errors, not just @lobehub …
Jun 2, 2026
f0a2374
fix(ci): actively fix ESM resolution instead of stubbing
Jun 2, 2026
da6f495
fix(ci): intercept all .json imports in ESM hook, not just @emoji-mar…
Jun 2, 2026
6601b11
fix(ci): intercept JSON URLs post-resolution, not just .json specifiers
Jun 2, 2026
60c5c9f
fix(test): add window.matchMedia mock to test-setup
Jun 2, 2026
c0fea1b
fix(test): import vi from vitest explicitly in test-setup
Jun 2, 2026
3542665
fix(ci): add continue-on-error to govulncheck, exclude stale mockConv…
Jun 3, 2026
154cea0
merge: sync dev/delicious233 into dev/trump — 62 commits
Jun 3, 2026
88749ae
feat: upgrade Go to 1.25.11, fix mockConvergence tests, add govulnche…
Jun 3, 2026
d1aa0ba
fix(desktop): update PromptInput and WelcomeScreen tests for merge-in…
Jun 3, 2026
d630332
fix(ci): regenerate lockfile, lower coverage to 70, fix process_execu…
Jun 3, 2026
e73cb6b
reset: align dev/trump with origin/master
Jun 4, 2026
7b3e6f3
fix(desktop): clean up Agent Profiles settings UI
Jun 4, 2026
4e7841f
fix(desktop): 调整 Agent Profile 设置界面
Jun 5, 2026
d5db7e5
fix(ci): 修复 dev/trump 基线检查
Jun 5, 2026
6b5d0d7
test(edge): 补充基线 CI 覆盖率用例
Jun 5, 2026
c393a1e
test(edge): 补充 security 覆盖率用例
Jun 5, 2026
b5ebb27
Merge pull request #277 from TokenDanceLab/fix/base-ci-green-dev-trump
Xavier-Trump Jun 5, 2026
b84047e
merge: 同步 dev delicious233 到 dev trump
Jun 5, 2026
c8fa2d9
fix(desktop): 让账号页设备 ID 可展开
Jun 5, 2026
9980096
Merge pull request #280 from TokenDanceLab/fix/desktop-account-device…
Xavier-Trump Jun 5, 2026
54fbda5
fix(desktop): 调整设备 ID 展开排版
Jun 5, 2026
fc82462
fix(desktop): 修复快捷键自定义态布局
Jun 5, 2026
58f97d7
Merge pull request #282 from TokenDanceLab/fix/desktop-keyboard-short…
Xavier-Trump Jun 6, 2026
06ecd83
fix(desktop): 补齐设置页 i18n 文案
Jun 6, 2026
b019231
Merge pull request #281 from TokenDanceLab/fix/desktop-account-device…
Xavier-Trump Jun 6, 2026
547797b
fix(desktop): 统一设置页卡片间距
Jun 6, 2026
e58f892
Merge pull request #283 from TokenDanceLab/fix/desktop-settings-i18n-…
Xavier-Trump Jun 6, 2026
aad5379
fix(desktop): 移除外观页重复密度设置
Jun 6, 2026
a63ba2b
Merge pull request #284 from TokenDanceLab/fix/desktop-settings-remov…
Xavier-Trump Jun 6, 2026
a6b42a2
fix(desktop): 修复默认 Agent 配置生效
Jun 6, 2026
d150e66
fix(desktop): 修复配置路由下拉显示
Jun 6, 2026
f85c98a
Merge pull request #285 from TokenDanceLab/fix/desktop-config-default…
Xavier-Trump Jun 6, 2026
7c87e64
fix(desktop): 将快捷键操作移入面板标题区
Jun 6, 2026
133f62e
fix(desktop): 稳定快捷键编辑态列表位置
Jun 6, 2026
cb400f0
Merge pull request #288 from TokenDanceLab/fix/desktop-keyboard-toolb…
Xavier-Trump Jun 6, 2026
d0c4625
fix(desktop): 同步默认 Agent 配置清理
Jun 6, 2026
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
34 changes: 24 additions & 10 deletions app/desktop/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
import { useTopMenuConfig } from '@/hooks/useTopMenuConfig';
import { ToastContainer } from '@/components/Toast';
import type { SectionId as SettingsSectionId } from '@/components/SettingsPage';
import { useStoredValueState } from '@/components/settings/utils';
import {
DEFAULT_AGENT_AUTO,
resolveAvailableDefaultAgentId,
} from '@/utils/defaultAgent';

// Lazy-loaded non-critical components
const AuthPage = lazy(() => import('@/components/AuthPage'));
Expand Down Expand Up @@ -178,7 +183,7 @@
const activeThreadId = resolveThreadSelectionId(selectedThreadId as ThreadSelectionInput);
const { messages, isConnected, currentRun, permissionRequests, decidePermission } = useChatMessages(online, activeThreadId);
const { data: agentData } = useAgentList(online);
const agents = agentData?.items ?? [];
const agents = useMemo(() => agentData?.items ?? [], [agentData?.items]);
const modelCatalogQuery = useModelCatalog(online);
const modelsDevDisplayNamesQuery = useModelsDevDisplayNames(true);
const agentTeamSummary = useMemo(
Expand All @@ -197,6 +202,7 @@
const [workspaceExpanded, setWorkspaceExpanded] = useState(false);
const [settingsOpen, setSettingsOpen] = useState(false);
const [settingsInitialSection, setSettingsInitialSection] = useState<SettingsSectionId>('general');
const [defaultAgent, setDefaultAgent] = useStoredValueState<string>('defaultAgent', DEFAULT_AGENT_AUTO);
const [pendingComposerDraft, setPendingComposerDraft] = useState('');
const {
leftSidebarCollapsed,
Expand Down Expand Up @@ -257,7 +263,7 @@
}
}
prevThreadIdsRef.current = currentIds;
}, [threads, online, addToast, t]);

Check warning on line 266 in app/desktop/src/App.tsx

View workflow job for this annotation

GitHub Actions / frontend-desktop

React Hook useEffect has a missing dependency: 'silentCreatedThreadToastIdsRef'. Either include it or remove the dependency array

Check warning on line 266 in app/desktop/src/App.tsx

View workflow job for this annotation

GitHub Actions / frontend-desktop

React Hook useEffect has a missing dependency: 'silentCreatedThreadToastIdsRef'. Either include it or remove the dependency array

useEffect(() => {
if (!threadData?.items) return;
Expand All @@ -268,12 +274,18 @@
if (liveThreadIds.has(threadId)) pendingCreatedThreadIdsRef.current.delete(threadId);
}
useThreadStore.getState().pruneMissingThreads([...knownThreadIds]);
}, [threadData?.items, threads]);

Check warning on line 277 in app/desktop/src/App.tsx

View workflow job for this annotation

GitHub Actions / frontend-desktop

React Hook useEffect has a missing dependency: 'pendingCreatedThreadIdsRef'. Either include it or remove the dependency array

Check warning on line 277 in app/desktop/src/App.tsx

View workflow job for this annotation

GitHub Actions / frontend-desktop

React Hook useEffect has a missing dependency: 'pendingCreatedThreadIdsRef'. Either include it or remove the dependency array

const selectedThread = threads.find((th) => th.threadId === activeThreadId);
const { data: threadItemData } = useThreadMessages(activeThreadId);
const { data: allRunsData } = useRuns(undefined, undefined, { enabled: online });
const selectedAgent = agents.find((a) => a.id === selectedAgentId);
const validDefaultAgentId = useMemo(
() => resolveAvailableDefaultAgentId(defaultAgent, agents),
[agents, defaultAgent],
);
const effectiveSelectedAgentId = selectedAgentId ?? validDefaultAgentId;
const selectedAgent = agents.find((a) => a.id === effectiveSelectedAgentId);
const manuallySelectedAgent = selectedAgentId ? agents.find((a) => a.id === selectedAgentId) : undefined;
const displayedRun = currentRun ?? optimisticRun;
const runIsActive = isRunActiveStatus(displayedRun?.status);
const runCardConstrained = workspaceWidth > 0 && workspaceWidth < RUN_CARD_MIN_WORKSPACE_WIDTH;
Expand Down Expand Up @@ -352,7 +364,7 @@
activeThreadId,
threads,
agents,
selectedAgentId,
selectedAgentId: effectiveSelectedAgentId,
optimisticRun,
currentRun,
allMessages,
Expand Down Expand Up @@ -395,7 +407,7 @@
openGlobalSearch,
} = useThreadNavigation({
allMessages,
selectedAgentName: selectedAgent?.name,
selectedAgentName: manuallySelectedAgent?.name,
selectedAgentId: selectedAgentId ?? null,
selectedThreadId: selectedThread?.threadId,
selectedThreadTitle: selectedThread?.title,
Expand Down Expand Up @@ -663,6 +675,8 @@
initialSection={settingsInitialSection}
onBack={() => setSettingsOpen(false)}
onOpenAuth={handleOpenAuth}
defaultAgent={defaultAgent}
setDefaultAgent={setDefaultAgent}
/>
</Suspense>
) : (
Expand Down Expand Up @@ -698,7 +712,7 @@
<div className={styles.mobileNavPanel}>
<div className={styles.sidebarSection}>
<div className={styles.sidebarScroll}>
<Slot name="agent-list" agents={agents} online={online} selectedId={selectedAgentId} onSelect={handleSelectAgent} />
<Slot name="agent-list" agents={agents} online={online} selectedId={effectiveSelectedAgentId} onSelect={handleSelectAgent} />
</div>
</div>
<div className={`${styles.sidebarSection} ${styles.threadSection}`}>
Expand Down Expand Up @@ -806,7 +820,7 @@
{/* Agents section */}
<div className={styles.sidebarSection}>
<div className={styles.sidebarScroll}>
<Slot name="agent-list" agents={agents} online={online} selectedId={selectedAgentId} onSelect={handleSelectAgent} />
<Slot name="agent-list" agents={agents} online={online} selectedId={effectiveSelectedAgentId} onSelect={handleSelectAgent} />
</div>
</div>

Expand Down Expand Up @@ -918,7 +932,7 @@
const thread = await createThread(title ?? undefined);
addThreadToCache(thread);
handleSelectThread(thread.threadId);
await handleSend(prompt, selectedAgentId ?? undefined, {
await handleSend(prompt, effectiveSelectedAgentId ?? undefined, {
threadId: thread.threadId,
threadInfo: thread,
createdEmptyThread: true,
Expand All @@ -937,7 +951,7 @@
agentTeamsLoading={agentTeamsQuery.isLoading || agentTeamsQuery.isFetching}
agentTeamsSignedIn={hubInventoryEnabled}
agents={agents}
selectedAgentId={selectedAgentId ?? undefined}
selectedAgentId={effectiveSelectedAgentId ?? undefined}
onSelectAgent={handleSelectAgent}
onStartLocalOrchestration={handleStartLocalOrchestration}
/>
Expand All @@ -955,7 +969,7 @@
isStreaming={composerLocked}
isConnected={isConnected}
agents={agents}
selectedAgentId={selectedAgentId}
selectedAgentId={effectiveSelectedAgentId ?? undefined}
onSelectAgent={handleSelectAgent}
onRetry={handleRetry}
onFork={handleForkThread}
Expand All @@ -968,7 +982,7 @@
{/* Input area — only for agent chat */}
{activeRailView === 'agents' && (
<div className={styles.inputArea}>
<Slot name="prompt-input" agents={agents} threads={threads} executionTargets={executionTargetsQuery.data?.items ?? []} modelCatalog={modelCatalogQuery.data} modelDisplayNames={modelsDevDisplayNamesQuery.data} selectedAgentId={selectedAgentId ?? undefined} onSelectAgent={handleSelectAgent} onSend={handleSend} isStreaming={runIsActive} isStarting={runStartPending} onCancel={handleCancel} disabled={!online} threadId={activeThreadId ?? undefined} onRetryLast={handleRetry} onForkThread={handleForkThread} />
<Slot name="prompt-input" agents={agents} threads={threads} executionTargets={executionTargetsQuery.data?.items ?? []} modelCatalog={modelCatalogQuery.data} modelDisplayNames={modelsDevDisplayNamesQuery.data} selectedAgentId={effectiveSelectedAgentId ?? undefined} onSelectAgent={handleSelectAgent} onSend={handleSend} isStreaming={runIsActive} isStarting={runStartPending} onCancel={handleCancel} disabled={!online} threadId={activeThreadId ?? undefined} onRetryLast={handleRetry} onForkThread={handleForkThread} />
</div>
)}
</div>
Expand Down
42 changes: 29 additions & 13 deletions app/desktop/src/components/SettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,12 @@ import { useHealth } from '@/hooks/useHealth';
import { useAuth } from '@/hooks/useAuth';
import { useTaskBridgeStore } from '@/stores/taskBridgeStore';
import { preferredProfileAlias } from '@/utils/agentProfile';

import { useModelSettingsStore } from '@/stores/modelSettingsStore';
import {
useModelSettingsStore,
type ResolvedRunModelSettings,
} from '@/stores/modelSettingsStore';
DEFAULT_AGENT_AUTO,
buildDefaultAgentOptions,
resolveAvailableDefaultAgentId,
} from '@/utils/defaultAgent';
import styles from './SettingsPage.module.css';
import {
useStoredBooleanState,
Expand Down Expand Up @@ -129,6 +130,8 @@ interface Props {
onBack: () => void;
onOpenAuth: () => void;
initialSection?: SectionId;
defaultAgent: string;
setDefaultAgent: (value: string) => void;
}

interface NavItem {
Expand All @@ -138,7 +141,13 @@ interface NavItem {
group: 'workspace' | 'automation' | 'system';
}

export default function SettingsPage({ onBack, onOpenAuth, initialSection = 'general' }: Props) {
export default function SettingsPage({
onBack,
onOpenAuth,
initialSection = 'general',
defaultAgent,
setDefaultAgent,
}: Props) {
const { t } = useTranslation();
const { themeMode, setThemeMode, themePreset, setThemePreset } = useTheme();
const hubAuth = useAuth();
Expand Down Expand Up @@ -232,7 +241,16 @@ export default function SettingsPage({ onBack, onOpenAuth, initialSection = 'gen
const updateCcSwitchProvider = useModelSettingsStore((s) => s.updateProvider);
const resolveRunRequestOptions = useModelSettingsStore((s) => s.resolveRunRequestOptions);

const agents = agentData?.items ?? [];
const agents = useMemo(() => agentData?.items ?? [], [agentData?.items]);
const defaultAgentAutoLabel = t('settings.defaultAgent.auto');
const defaultAgentOptions = useMemo(
() => buildDefaultAgentOptions(agents, defaultAgentAutoLabel),
[agents, defaultAgentAutoLabel],
);
const defaultAgentValue = useMemo(
() => resolveAvailableDefaultAgentId(defaultAgent, agents) ?? DEFAULT_AGENT_AUTO,
[agents, defaultAgent],
);
const localAgentProfiles = useMemo(
() => agents.map((agent) => ({
agent,
Expand Down Expand Up @@ -452,22 +470,20 @@ export default function SettingsPage({ onBack, onOpenAuth, initialSection = 'gen
<AppearanceSection
themeMode={themeMode}
setThemeMode={setThemeMode}
compactMode={compactMode}
setCompactMode={setCompactMode}
themePreset={themePreset}
setThemePreset={setThemePreset}
/>
)}

{active === 'configuration' && (
<ConfigurationSection
defaultAgent="Auto"
setDefaultAgent={NOOP}
routing={t('settings.routingAuto')}
defaultAgent={defaultAgentValue}
setDefaultAgent={setDefaultAgent}
routing="auto"
setRouting={NOOP}
approvalMode={approvalMode}
setApprovalMode={setApprovalMode}
defaultAgentOptions={[['Auto', 'Auto']]}
defaultAgentOptions={defaultAgentOptions}
routingOptions={[['auto', t('settings.routingAuto')]]}
/>
)}
Expand Down Expand Up @@ -710,7 +726,7 @@ export default function SettingsPage({ onBack, onOpenAuth, initialSection = 'gen
{active === 'data' && (
<DataSection
t={t}
addToast={(input) => { return ''; }}
addToast={(_input) => { return ''; }}
resetModelSettings={() => {
setDefaultModel('auto');
setDefaultProvider('tokendance-gateway');
Expand Down
60 changes: 46 additions & 14 deletions app/desktop/src/components/settings/cards/LocalAgentProfileCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useMemo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { Bot, ChevronDown, ChevronUp, Globe, Wrench } from 'lucide-react';
import { Bot, ChevronDown, ChevronUp } from 'lucide-react';
import type { AgentInfo } from '@shared/types';
import type { ResolvedRunModelSettings } from '@/stores/modelSettingsStore';
import {
Expand Down Expand Up @@ -45,6 +45,8 @@ interface LocalAgentProfileCardProps {
edgeOnline: boolean;
}

type SelectOption = readonly [string, string];

// ── Tool catalog ────────────────────────────────────

const TOOL_CATALOG: Array<{ name: string; descriptionKey: string }> = [
Expand Down Expand Up @@ -158,6 +160,21 @@ function estimateTokens(text: string): number {
return Math.max(1, Math.round(cjk + ascii / 4));
}

function withCurrentOptions(options: readonly SelectOption[], currentValues: Array<string | undefined>): SelectOption[] {
const next = [...options];
for (const value of currentValues) {
const trimmed = value?.trim();
if (trimmed && !next.some(([optionValue]) => optionValue === trimmed)) {
next.unshift([trimmed, trimmed]);
}
}
return next;
}

function labelForOption(options: readonly SelectOption[], value: string): string {
return options.find(([optionValue]) => optionValue === value)?.[1] ?? value;
}

// ── Component ───────────────────────────────────────

export default function LocalAgentProfileCard({
Expand Down Expand Up @@ -245,6 +262,24 @@ export default function LocalAgentProfileCard({
}, []);

const enabledToolCount = profile.tools.filter((t) => t.enabled).length;
const modelOptions = useMemo(
() => withCurrentOptions(MODEL_OPTIONS.filter(([value]) => value !== 'auto'), [profile.modelOverride, route.model]),
[profile.modelOverride, route.model],
);
const providerOptions = useMemo(
() => withCurrentOptions(PROVIDER_OPTIONS, [profile.providerOverride, route.provider]),
[profile.providerOverride, route.provider],
);
const reasoningOptions = useMemo(
() => withCurrentOptions(REASONING_OPTIONS, [profile.reasoningOverride, route.reasoningEffort]),
[profile.reasoningOverride, route.reasoningEffort],
);
const activeModel = profile.modelOverride || route.model || '';
const activeProvider = profile.providerOverride || route.provider || '';
const hasProfileModelChoice = Boolean(profile.modelOverride || profile.providerOverride || profile.reasoningOverride);
const autoLabel = t('prompt.routeAuto');
const modelLabel = activeModel ? labelForOption(modelOptions, activeModel) : autoLabel;
const providerLabel = activeProvider ? labelForOption(providerOptions, activeProvider) : autoLabel;

return (
<div className={styles.profileCard}>
Expand Down Expand Up @@ -272,13 +307,10 @@ export default function LocalAgentProfileCard({
</em>
</div>
<div className={styles.profileMeta}>
<span>{t('settings.profileRuntime')}: {agent.id}</span>
<span>{t('settings.profileModel')}: {route.model ?? t('prompt.routeAuto')}</span>
<span>{t('settings.modelAliasProvider')}: {route.provider ?? t('prompt.routeAuto')}</span>
<span>{t('settings.modelAliasReasoning')}: {route.reasoningEffort ?? t('prompt.routeAuto')}</span>
{alias ? <span>{t('settings.profileAlias')}: {alias}</span> : null}
<span>{t('settings.executionTargets')}: {t('settings.targetLocalEdge')}</span>
<span>{t('settings.profileConfigSource')}: AGENTS.md / memory / skills</span>
<span>{t('settings.agentProfileSummaryModel', { model: modelLabel })}</span>
<span>{t('settings.agentProfileSummaryProvider', { provider: providerLabel })}</span>
<span>{hasProfileModelChoice ? t('settings.agentProfileSummaryCustom') : t('settings.agentProfileSummaryDefault')}</span>
<span>{t('settings.agentProfileSummaryTarget')}</span>
</div>
<div className={styles.profileExpandArrow}>
{expanded ? <ChevronUp size={15} /> : <ChevronDown size={15} />}
Expand Down Expand Up @@ -374,33 +406,33 @@ export default function LocalAgentProfileCard({
onChange={(e) => setProfile((prev) => ({ ...prev, modelOverride: e.target.value }))}
>
<option value="">{t('settings.agentProfileUseDefault', { defaultValue: 'Use default' })}</option>
{MODEL_OPTIONS.filter(([v]) => v !== 'auto').map(([value, label]) => (
{modelOptions.map(([value, label]) => (
<option key={value} value={value}>{label}</option>
))}
</select>
</label>
<label className={styles.profileEditorMiniLabel}>
<span>{t('settings.modelAliasProvider')}</span>
<span>{t('settings.agentProfileProvider')}</span>
<select
className={styles.select}
value={profile.providerOverride}
onChange={(e) => setProfile((prev) => ({ ...prev, providerOverride: e.target.value }))}
>
<option value="">{t('settings.agentProfileUseDefault', { defaultValue: 'Use default' })}</option>
{PROVIDER_OPTIONS.map(([value, label]) => (
{providerOptions.map(([value, label]) => (
<option key={value} value={value}>{label}</option>
))}
</select>
</label>
<label className={styles.profileEditorMiniLabel}>
<span>{t('settings.modelAliasReasoning')}</span>
<span>{t('settings.agentProfileReasoning')}</span>
<select
className={styles.select}
value={profile.reasoningOverride}
onChange={(e) => setProfile((prev) => ({ ...prev, reasoningOverride: e.target.value }))}
>
<option value="">{t('settings.agentProfileUseDefault', { defaultValue: 'Use default' })}</option>
{REASONING_OPTIONS.map(([value, label]) => (
{reasoningOptions.map(([value, label]) => (
<option key={value} value={value}>{label}</option>
))}
</select>
Expand Down Expand Up @@ -557,7 +589,7 @@ export default function LocalAgentProfileCard({
<div className={styles.profileEditorActions}>
<div className={styles.profileEditorActionsLeft}>
<span className={styles.profileEditorSource}>
{t('settings.agentProfileStorage', { defaultValue: 'Saved to localStorage' })}: {agentProfileKey(agent.id)}
{t('settings.agentProfileStorage', { defaultValue: 'Saved on this device' })}
</span>
<button
type="button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ export default function RuntimeInventoryCard({ agent }: { agent: AgentInfo }) {
</div>
<div className={styles.profileMeta}>
<span>{t('settings.runtimeAdapter')}: {agent.id}</span>
<span>{t('settings.profileRuntime')}: {t('settings.statusReady')}</span>
<span>{t('settings.profileModel')}: {t('settings.statusPlanned')}</span>
<span>{t('settings.profileConfig')}: {t('settings.statusPlanned')}</span>
</div>
</div>
);
Expand Down
10 changes: 7 additions & 3 deletions app/desktop/src/components/settings/primitives/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@ import styles from './primitives.module.css';
interface PanelProps {
title: string;
description?: string;
actions?: ReactNode;
children: ReactNode;
}

export default function Panel({ title, description, children }: PanelProps) {
export default function Panel({ title, description, actions, children }: PanelProps) {
return (
<section className={styles.panel}>
<div className={styles.panelHeader}>
<h2>{title}</h2>
{description ? <p>{description}</p> : null}
<div className={styles.panelHeaderCopy}>
<h2>{title}</h2>
{description ? <p>{description}</p> : null}
</div>
{actions ? <div className={styles.panelHeaderActions}>{actions}</div> : null}
</div>
<div className={styles.panelBody}>{children}</div>
</section>
Expand Down
Loading
Loading