+
{agent.profiles[0]?.agent_display_name ?? agent.name}
diff --git a/apps/web/components/agent-logo.tsx b/apps/web/components/agent-logo.tsx
new file mode 100644
index 0000000000..4d6c3b1f4b
--- /dev/null
+++ b/apps/web/components/agent-logo.tsx
@@ -0,0 +1,44 @@
+'use client';
+
+import { useState, useSyncExternalStore } from 'react';
+import Image from 'next/image';
+import { useTheme } from 'next-themes';
+import { getBackendConfig } from '@/lib/config';
+
+interface AgentLogoProps {
+ agentName: string;
+ size?: number;
+ className?: string;
+}
+
+const emptySubscribe = () => () => {};
+
+/** Wrapper that re-mounts the inner image when agentName changes, resetting error state. */
+export function AgentLogo({ agentName, size = 16, className }: AgentLogoProps) {
+ return
;
+}
+
+function AgentLogoImage({ agentName, size = 16, className }: AgentLogoProps) {
+ const { resolvedTheme } = useTheme();
+ const mounted = useSyncExternalStore(emptySubscribe, () => true, () => false);
+ const [error, setError] = useState(false);
+
+ if (!mounted || error) {
+ return
;
+ }
+
+ const variant = resolvedTheme === 'dark' ? 'dark' : 'light';
+ const src = `${getBackendConfig().apiBaseUrl}/api/v1/agents/${encodeURIComponent(agentName)}/logo?variant=${variant}`;
+
+ return (
+
setError(true)}
+ />
+ );
+}
diff --git a/apps/web/components/settings/agent-profile-page.tsx b/apps/web/components/settings/agent-profile-page.tsx
index 3f7c208829..9cb896e344 100644
--- a/apps/web/components/settings/agent-profile-page.tsx
+++ b/apps/web/components/settings/agent-profile-page.tsx
@@ -14,6 +14,7 @@ import { ProfileFormFields } from '@/components/settings/profile-form-fields';
import { deleteAgentProfileAction, updateAgentProfileAction } from '@/app/actions/agents';
import type { Agent, AgentProfile, ModelConfig, PermissionSetting, PassthroughConfig } from '@/lib/types/http';
import { useAppStore } from '@/components/state-provider';
+import { AgentLogo } from '@/components/agent-logo';
import { ProfileMcpConfigCard } from '@/app/settings/agents/[agentId]/profile-mcp-config-card';
import { CommandPreviewCard } from '@/app/settings/agents/[agentId]/profiles/[profileId]/command-preview-card';
import type { AgentProfileMcpConfig } from '@/lib/types/http';
@@ -44,6 +45,7 @@ function ProfileEditor({ agent, profile, modelConfig, permissionSettings, passth
id: agentProfile.id,
label: `${agentProfile.agent_display_name} • ${agentProfile.name}`,
agent_id: agentItem.id,
+ agent_name: agentItem.name,
}))
)
);
@@ -137,7 +139,10 @@ function ProfileEditor({ agent, profile, modelConfig, permissionSettings, passth
-
{profile.agent_display_name} • {savedProfile.name}
+
+
+ {profile.agent_display_name} • {savedProfile.name}
+
{profile.agent_display_name} profile settings
diff --git a/apps/web/components/settings/settings-app-sidebar.tsx b/apps/web/components/settings/settings-app-sidebar.tsx
index 35347ae9d9..b6e81c3abb 100644
--- a/apps/web/components/settings/settings-app-sidebar.tsx
+++ b/apps/web/components/settings/settings-app-sidebar.tsx
@@ -30,8 +30,10 @@ import {
useSidebar,
} from '@kandev/ui/sidebar';
import { ScrollArea } from '@kandev/ui/scroll-area';
+import { ScrollOnOverflow } from '@kandev/ui/scroll-on-overflow';
import { useAppStore } from '@/components/state-provider';
import { useAvailableAgents } from '@/hooks/domains/settings/use-available-agents';
+import { AgentLogo } from '@/components/agent-logo';
import type { Workspace, Agent, AgentProfile, Environment, Executor } from '@/lib/types/http';
export function SettingsAppSidebar() {
@@ -66,7 +68,7 @@ export function SettingsAppSidebar() {
-
+
Settings
@@ -192,12 +194,13 @@ export function SettingsAppSidebar() {
const profilePath = `/settings/agents/${encodedAgent}/profiles/${profile.id}`;
const agentLabel = profile.agent_display_name || agent.name;
return (
-
+
-
-
+
+
+
{agentLabel} • {profile.name}
-
+
diff --git a/apps/web/components/task-create-dialog.tsx b/apps/web/components/task-create-dialog.tsx
index 5faceb1f91..5987184d2c 100644
--- a/apps/web/components/task-create-dialog.tsx
+++ b/apps/web/components/task-create-dialog.tsx
@@ -22,6 +22,7 @@ import { Textarea } from '@kandev/ui/textarea';
import { Button } from '@kandev/ui/button';
import { Combobox } from './combobox';
import { Badge } from '@kandev/ui/badge';
+import { ScrollOnOverflow } from '@kandev/ui/scroll-on-overflow';
import type { LocalRepository, Task, Workspace, Repository, Environment, Executor, Branch } from '@/lib/types/http';
import type { AgentProfileOption } from '@/lib/state/slices';
import {
@@ -46,6 +47,7 @@ import { getLocalStorage, setLocalStorage } from '@/lib/local-storage';
import { STORAGE_KEYS } from '@/lib/settings/constants';
import { linkToSession } from '@/lib/links';
import { getExecutorIcon } from '@/lib/executor-icons';
+import { AgentLogo } from '@/components/agent-logo';
import { useDockviewStore } from '@/lib/state/dockview-store';
import { useContextFilesStore } from '@/lib/state/context-files-store';
@@ -209,7 +211,7 @@ const AgentSelector = memo(function AgentSelector({
emptyMessage="No agent found."
disabled={disabled}
dropdownLabel="Agent profile"
- className={disabled ? undefined : 'cursor-pointer'}
+ className={`min-w-[380px]${disabled ? '' : ' cursor-pointer'}`}
triggerClassName={triggerClassName}
/>
);
@@ -642,11 +644,14 @@ export function TaskCreateDialog({
label: profile.label,
renderLabel: () => (
- {agentLabel}
+
+
+ {agentLabel}
+
{profileLabel ? (
-
+
{profileLabel}
-
+
) : null}
),
diff --git a/apps/web/hooks/domains/settings/use-settings-data.ts b/apps/web/hooks/domains/settings/use-settings-data.ts
index b30e2d10bb..fa5ce2d340 100644
--- a/apps/web/hooks/domains/settings/use-settings-data.ts
+++ b/apps/web/hooks/domains/settings/use-settings-data.ts
@@ -52,6 +52,7 @@ export function useSettingsData(enabled = true) {
id: profile.id,
label: `${profile.agent_display_name} • ${profile.name}`,
agent_id: agent.id,
+ agent_name: agent.name,
}))
)
);
diff --git a/apps/web/lib/state/slices/settings/types.ts b/apps/web/lib/state/slices/settings/types.ts
index 1fbeb1de5c..8d38dc6590 100644
--- a/apps/web/lib/state/slices/settings/types.ts
+++ b/apps/web/lib/state/slices/settings/types.ts
@@ -35,6 +35,7 @@ export type AgentProfileOption = {
id: string;
label: string;
agent_id: string;
+ agent_name: string;
};
export type AgentProfilesState = {
diff --git a/apps/web/lib/ws/handlers/agents.ts b/apps/web/lib/ws/handlers/agents.ts
index 591f4c09d7..dcacd252da 100644
--- a/apps/web/lib/ws/handlers/agents.ts
+++ b/apps/web/lib/ws/handlers/agents.ts
@@ -29,9 +29,10 @@ export function registerAgentsHandlers(store: StoreApi): WsHandlers {
'agent.profile.created': (message) => {
store.setState((state) => {
const label = `${message.payload.profile.agent_display_name} • ${message.payload.profile.name}`;
+ const agentName = state.settingsAgents.items.find((a) => a.id === message.payload.profile.agent_id)?.name ?? '';
const nextProfiles = [
...state.agentProfiles.items.filter((profile) => profile.id !== message.payload.profile.id),
- { id: message.payload.profile.id, label, agent_id: message.payload.profile.agent_id },
+ { id: message.payload.profile.id, label, agent_id: message.payload.profile.agent_id, agent_name: agentName },
];
const nextAgents = state.settingsAgents.items.map((item) =>
item.id === message.payload.profile.agent_id
@@ -67,9 +68,10 @@ export function registerAgentsHandlers(store: StoreApi): WsHandlers {
'agent.profile.updated': (message) => {
store.setState((state) => {
const label = `${message.payload.profile.agent_display_name} • ${message.payload.profile.name}`;
+ const agentName = state.settingsAgents.items.find((a) => a.id === message.payload.profile.agent_id)?.name ?? '';
const nextProfiles = state.agentProfiles.items.map((profile) =>
profile.id === message.payload.profile.id
- ? { ...profile, label, agent_id: message.payload.profile.agent_id }
+ ? { ...profile, label, agent_id: message.payload.profile.agent_id, agent_name: agentName }
: profile
);
const nextAgents = state.settingsAgents.items.map((item) =>