Agent Icon Data Model#
Agent icons in Dify use a three-field model: icon_type, icon, and icon_url. The meaning of icon varies by icon_type, making type checks essential before use.
Core Fields#
Defined on App in web/types/app.ts:
| Field | Type | Meaning |
|---|---|---|
icon_type | 'emoji' | 'image' | 'link' | null | Rendering strategy |
icon | string | Emoji character or file ID (when icon_type === 'image') |
icon_background | string | null | Background color β only used for emoji/null types |
icon_url | string | null | Resolved image URL β only populated when icon_type === 'image' |
AppIconType is defined as :
export type AppIconType = 'image' | 'emoji' | 'link'
Rendering via AppIcon#
The AppIcon component (web/app/components/base/app-icon/index.tsx) accepts imageUrl (not icon_url) as a separate prop. It renders :
- An
<img>tag fromimageUrlonly wheniconType === 'image' && imageUrlis truthy - Otherwise, an emoji (defaulting to π€) or the
innerIconslot
The background color is suppressed for image icons .
Inconsistencies in Agent API Types#
The auto-generated contracts in packages/contracts/generated/api/console/agent/types.gen.ts reveal a split between agent response types:
Types that include icon_url (read-only computed field, server-resolved URL):
AgentAppPartialβreadonly icon_url: string | null(line 513)AgentAppDetailWithSiteβreadonly icon_url: string | null(line 44)AppDetailSiteResponseβreadonly icon_url: string | null(line 585)
Types that do NOT include icon_url:
AgentInviteOptionResponseβ hasicon,icon_background,icon_type, but noicon_urlAgentComposerAgentResponseβ same omissionAgentLogSourceResponseβ usesapp_icon*field names, no URL fieldAgentReferencingWorkflowResponseβ usesapp_icon*field names, no URL
There are also two separate enum definitions for the icon type with identical values:
IconTypeβ'emoji' | 'image' | 'link'(used in payload types likeAgentAppCreatePayload)AgentIconTypeβ'emoji' | 'image' | 'link'(used inAgentInviteOptionResponseandComposerSavePayload)
These are structurally identical but separate declarations, creating an inconsistency that could cause type errors when passing one where the other is expected.
Workaround in Agent Selector#
Because AgentInviteOptionResponse lacks icon_url, the agent selector passes agent.icon as both the icon and imageUrl props to AppIcon:
// agent-selector.tsx lines 225β232
<AppIcon
size="small"
iconType={agent.icon_type}
icon={agent.icon ?? undefined}
background={agent.icon_background}
imageUrl={agent.icon ?? undefined} // β passes file ID, not a URL
/>
The same pattern is used in agent-roster-field.tsx. This means image-type agent icons in these components attempt to render a file ID as a direct image URL rather than the resolved icon_url, which can result in broken images.
The toAgentRosterNodeData mapping also propagates this gap β icon_url is never copied into AgentRosterNodeData because it doesn't exist on the source type.
Writable vs Readonly Variants#
The contracts file also generates parallel *Writable types (e.g., AgentAppDetailWithSiteWritable, AgentAppPartialWritable) that omit icon_url entirely. This is intentional β icon_url is a server-computed field and should never be submitted in write payloads.
Key Files#
| File | Purpose |
|---|---|
packages/contracts/generated/api/console/agent/types.gen.ts | Auto-generated API types β source of truth for field availability per response type |
web/types/app.ts | AppIconType and App type with documented field semantics |
web/app/components/base/app-icon/index.tsx | AppIcon renderer β imageUrl prop is the required URL, not icon |
web/app/components/workflow/block-selector/agent-selector.tsx | Shows the icon-as-imageUrl workaround |
web/app/components/workflow/nodes/agent-v2/components/agent-roster-field.tsx | Same pattern, local AgentRosterDisplayData type without icon_url |