Skip to content

[feat] Let each agent carry its own icon and colour - #6062

Open
ashrafchowdury wants to merge 8 commits into
release/v0.112.2from
feat/agent-icon-picker
Open

[feat] Let each agent carry its own icon and colour#6062
ashrafchowdury wants to merge 8 commits into
release/v0.112.2from
feat/agent-icon-picker

Conversation

@ashrafchowdury

@ashrafchowdury ashrafchowdury commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Context

Every agent renders the same Robot glyph. The sidebar, the playground header, the agent cards and the chat empty state all draw it, so once a workspace holds more than a handful of agents there is nothing to tell them apart at a glance. The only per-agent mark today is the initials tile on the cards, coloured by a hash of the id, which the other four surfaces do not use.

What this adds

Click the chip beside the agent name in the playground header and a picker opens. Pick an icon, pick a colour from the palette or mix a custom one, and it saves as you pick. There is no save button. The sidebar rows, the sidebar workflow switcher, the agent cards and the chat empty state then display the choice; the header is the only place that edits it.

An agent nobody has customised looks exactly as it does today, because each surface keeps its own existing fallback rather than being forced onto a shared default.

The choice lives in localStorage for now, keyed by workflow id:

agenta:agent-icon:1  ->  { "<workflowId>": {icon, color, path} }

The backend home is the workflow artifact's meta. Moving it there needs the update guard in workflow/api/api.ts fixed first, since it checks name || description || flags || tags and ignores a meta-only change. Only the atom family behind agentIconAtomFamily has to change when that lands. No call site does.

How the icons get here

Importing the Phosphor React barrel would put 4.8 MB in the entry chunk, and a variable dynamic import would emit roughly 1512 tiny chunks with the grid firing one request per visible icon. So pnpm --filter @agenta/ui generate:icons reads @phosphor-icons/core and emits one module of raw SVG path data. The root pnpm generate:phosphor-catalog still delegates to it.

It generates the regular weight and nothing else, which is what enforces the outline-only rule. No other weight exists in the file to reach for.

The set is curated, not complete: 160 icons listed in scripts/curated-icons.ts and grouped by what someone naming an agent actually reaches for. The full 1512 are 12k lines of generated path data, and a picker whose first screen is aircraft and alignment glyphs helps nobody. Adding one is a line in that file plus a regenerate. The generator throws on a name @phosphor-icons/core does not have, so a Phosphor rename breaks the build instead of silently dropping an icon somebody already chose.

The catalog is 105 KB raw, 32 KB gzipped, and it is a lazy chunk. It is referenced exactly twice: a type-only import that the compiler erases, and an import() inside the picker. The picker itself sits behind next/dynamic, so the sidebar, which draws agent icons on every route, never pays for the picker or the virtualizer. Nothing loads until the picker opens for the first time.

The generated file is committed, which is why there is no prepare hook and nothing for the Docker images to copy early. Commit 4 tried generating it on install instead; commit 6 undoes that, so reviewers reading commit-by-commit will pass through a prepare script and a .gitignore entry the tip no longer has.

Tests / notes

  • 29 unit tests in agentIconColors.test.ts cover the colour maths: hex parsing including junk input, HSV round-trip across every palette colour, palette-pair versus derived tint, the dark-mode derivations, and the palette invariants.
  • Full lint and type-check pass across @agenta/ui, @agenta/entities, @agenta/entity-ui and @agenta/oss. 361 @agenta/entity-ui tests pass.
  • Verified in the running app, light and dark.
  • Dark mode is derived, not designed. The source design is light-only, so the tile takes a 16 percent wash of the colour lifted toward white, following the construction palette.ts already uses for tag surfaces. Worth an eye from design before this ships.
  • The nine palette colours are hardcoded in colors.ts rather than sourced from palette.ts. They are user-chosen data rather than theme roles, but the default #113955 does duplicate the agent tag token. Routing them through the token generator is a follow-up, not this PR.
  • The grid opens on the curated order rather than alphabetically, so the first row is the icons an agent is most likely to want. The catalog still carries categories, so a category rail is an addition rather than a rewrite.
  • Second commit is a regression this PR introduced and then fixed. AgentGlyph returned a fragment when an agent had no icon of its own, and a fragment swallows the className antd clones onto a menu icon, so every agent row in the sidebar lost its 10px icon-to-label gap. It now always renders one real element and forwards the className.

What to QA

  • Open an agent in the playground. Click the chip to the left of the agent name. The picker opens with the current icon previewed, nine swatches, a search box and an icon grid.
  • Search for robot, git and chart. Matching works on tag names too, not just the icon name. A query with no matches shows the empty message.
  • Narrow the search until only two or three icons match. The grid holds its height instead of collapsing, so the panel does not jump under the cursor.
  • Pick an icon, then pick a colour. Both apply immediately, with no save step.
  • Click the rainbow swatch to open custom colour. Type a hex, then drag the square and the hue strip. The chip, the grid's selected cell and the hex field all track the drag.
  • Reload the page. The icon persists and paints on the first frame, with no flash of the old Robot.
  • Check the sidebar agent rows, the sidebar workflow switcher, the Agents page cards, the home rail and the chat empty state. All show the same icon and colour, and none of them is clickable.
  • Check dark mode on every one of those surfaces.
  • Regression: an agent you never customised still shows the Robot, and the cards still show initials on the hashed colour.
  • Regression: sidebar agent rows keep a 10px gap between the icon and the name, matching Home, Prompts and Show all.

Preview

This demo is created programmatically

agent-icon.mp4

@vercel

vercel Bot commented Aug 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview Aug 18, 2026 3:06pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: ef6345bd-0144-4a34-a05b-6530012f8ba6

📥 Commits

Reviewing files that changed from the base of the PR and between 4233c41 and 10dce76.

📒 Files selected for processing (1)
  • web/oss/src/components/Playground/Components/AgentCommitNotice.tsx

Included review availability: Your plan includes up to 8 reviews per rolling hour; 7 remain after this review.


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added customizable icons and colors for persisted agents, saved locally.
    • Added an icon picker with search, categories, preset colors, custom hex colors, and reset support.
    • Updated agent cards, headers, chat empty states, commit notices, and sidebars to display selected icons.
    • Preserved robot and initials fallbacks for temporary workflows or agents without custom icons.
  • Bug Fixes

    • Draft and temporary workflows no longer use persisted icon settings.
  • Tests

    • Added coverage for icon colors, validation, persistence, bounded storage, and fallback behavior.

Walkthrough

The PR adds workflow-specific agent icons with persisted icon and color selections. It introduces a generated Phosphor catalog, shared rendering utilities, an icon picker, bounded local-storage persistence, and integrations across chat, playground, sidebar, commit notices, and agent cards.

Changes

Agent icon customization

Layer / File(s) Summary
Icon catalog and rendering foundation
web/packages/agenta-ui/src/agent-icon/*, web/packages/agenta-ui/scripts/*, web/packages/agenta-ui/tests/unit/agentIconColors.test.ts, web/packages/agenta-ui/package.json, web/package.json
The UI package generates a curated Phosphor catalog, provides color utilities and SVG icon rendering, exposes shared icon chrome, and adds color utility tests and generation scripts.
Persisted icon state and shared agent UI
web/packages/agenta-entities/src/workflow/*, web/packages/agenta-entity-ui/src/agent/*
Workflow icon records are validated and persisted in a bounded local-storage map. Shared hooks and AgentGlyph resolve stored icons with caller-provided fallbacks.
Icon picker and editing trigger
web/packages/agenta-ui/src/agent-icon/AgentIconPicker.tsx, web/oss/src/components/AgentIconChip/index.tsx
The picker supports catalog search, virtualized icon results, preset or custom colors, and immediate selection commits. AgentIconTrigger loads the picker client-side for persisted workflows and keeps a fallback for ephemeral agents.
Workflow surface integration
web/oss/src/components/AgentChatSlice/components/AgentChatEmptyState.tsx, web/oss/src/components/Playground/Components/PlaygroundHeader/index.tsx, web/oss/src/components/Sidebar/components/WorkflowIdentity.tsx, web/oss/src/components/Sidebar/dynamic/registry.ts, web/oss/src/components/Playground/Components/AgentCommitNotice.tsx, web/packages/agenta-entity-ui/src/agent/AgentCard.tsx
Agent icons use resolved workflow IDs and shared icon chrome across chat empty states, playground headers, sidebar identities, sidebar entries, commit notices, and agent cards. Draft workflow IDs retain fallback behavior.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: 🟡 Moderate · up to 10dce

This PR adds persisted per-agent icons and colors across the product, but malformed stored icon data can reach SVG rendering and malformed storage can break agent surfaces during rendering; cancelled color drags may also leave page-level listeners attached. Merge should wait for sanitization/validation and drag-cleanup fixes.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AgentIconTrigger
  participant AgentIconPicker
  participant agentIconAtomFamily
  participant AgentSurface
  User->>AgentIconTrigger: open workflow icon control
  AgentIconTrigger->>AgentIconPicker: load picker for persisted workflow
  AgentIconPicker->>agentIconAtomFamily: save icon, color, and SVG path
  agentIconAtomFamily-->>AgentSurface: provide persisted icon record
  AgentSurface->>AgentSurface: render workflow-specific icon chrome
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 75.00% which is sufficient. The required threshold is 60.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: per-agent icon and colour customization.
Description check ✅ Passed The description directly explains the per-agent icon and colour customization, affected surfaces, storage, implementation, and testing.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-icon-picker

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ashrafchowdury
ashrafchowdury marked this pull request as ready for review August 17, 2026 05:16
@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. enhancement New feature or request frontend labels Aug 17, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
web/packages/agenta-ui/src/agent-icon/AgentIconPicker.tsx (1)

69-89: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Handle pointercancel and unmount so the drag listeners cannot outlive the picker.

stop is only bound to pointerup. If the browser cancels the pointer, which happens on touch when a scroll or a system gesture takes over, no pointerup fires. The pointermove listener then stays attached to window for the rest of the page session and keeps calling onPreview on a picker the user has already closed.

Bind pointercancel to the same stop, and clear the listeners if the picker unmounts first.

♻️ Proposed fix: also stop on `pointercancel` and expose a cleanup
 const trackDrag = (
     event: PointerEvent<HTMLDivElement>,
     onMove: (x: number, y: number) => void,
     onCommit: () => void,
-) => {
+): (() => void) => {
     const rect = event.currentTarget.getBoundingClientRect()
     const track = (e: {clientX: number; clientY: number}) =>
         onMove(
             clamp((e.clientX - rect.left) / rect.width, 0, 1),
             clamp((e.clientY - rect.top) / rect.height, 0, 1),
         )
 
     track(event)
     const stop = () => {
         window.removeEventListener("pointermove", track)
         window.removeEventListener("pointerup", stop)
+        window.removeEventListener("pointercancel", stop)
         onCommit()
     }
     window.addEventListener("pointermove", track)
     window.addEventListener("pointerup", stop)
+    window.addEventListener("pointercancel", stop)
+    return stop
 }

In CustomColorArea, keep the returned stopper in a ref and call it from an unmount effect:

const stopRef = useRef<(() => void) | null>(null)
useEffect(() => () => stopRef.current?.(), [])
// ...
onPointerDown={(e) => {
    stopRef.current = trackDrag(e, (x, y) => onPreview(hsvToHex(hsv.h, x, 1 - y)), onCommit)
}}
web/oss/src/components/Sidebar/components/WorkflowIdentity.tsx (1)

96-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Do not use chrome.style as the "customised" discriminator.

Line 105 infers "the user picked an icon" from the presence of chrome.style. That reads an implementation detail of agentIconChrome, which only attaches a style in the record branch. AgentIcon.tsx states the intent is the opposite: the customised-or-not branch should live in the helper, not at the call site.

The coupling is load-bearing here. fallbackGlyph is null on line 98, so if agentIconChrome ever attaches a style to the fallback branch, this row renders an empty glyph box and loses the prompt/agent icon class from WORKFLOW_DISPLAY_META.

Expose an explicit flag from the helper, for example customised: boolean, and gate on that instead.

Line 97 also restates the glyph size that WorkflowIdentityView already computes on line 52. Two sources for one number can drift, and the glyph would then stop matching the box. Consider passing the resolved size down, or exporting it as a shared constant.

web/packages/agenta-ui/src/agent-icon/index.ts (1)

1-9: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Split the picker into a separate package entry.

agentIcon.tsx imports agentIconChrome from @agenta/ui/agent-icon, while AgentIconChip dynamically imports AgentIconPicker from the same entry. The barrel synchronously re-exports AgentIconPicker, so the picker and virtualizer enter the synchronous bundle. Expose the picker through a separate subpath and update the dynamic import.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 890b6b23-0911-46c4-b9c4-98b0615c4fad

📥 Commits

Reviewing files that changed from the base of the PR and between 0af145e and f6bc4ea.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • web/.gitignore
  • web/oss/src/components/AgentChatSlice/components/AgentChatEmptyState.tsx
  • web/oss/src/components/AgentIconChip/index.tsx
  • web/oss/src/components/Playground/Components/PlaygroundHeader/index.tsx
  • web/oss/src/components/Sidebar/components/WorkflowIdentity.tsx
  • web/oss/src/components/Sidebar/dynamic/registry.ts
  • web/package.json
  • web/packages/agenta-entities/src/workflow/index.ts
  • web/packages/agenta-entities/src/workflow/state/agentIcon.ts
  • web/packages/agenta-entities/src/workflow/state/boundedMap.ts
  • web/packages/agenta-entities/src/workflow/state/index.ts
  • web/packages/agenta-entities/src/workflow/state/persistedAgentType.ts
  • web/packages/agenta-entity-ui/src/agent/AgentCard.tsx
  • web/packages/agenta-entity-ui/src/agent/agentIcon.tsx
  • web/packages/agenta-entity-ui/src/agent/index.ts
  • web/packages/agenta-ui/package.json
  • web/packages/agenta-ui/scripts/generate-catalog.ts
  • web/packages/agenta-ui/src/agent-icon/AgentIcon.tsx
  • web/packages/agenta-ui/src/agent-icon/AgentIconPicker.tsx
  • web/packages/agenta-ui/src/agent-icon/colors.ts
  • web/packages/agenta-ui/src/agent-icon/index.ts
  • web/packages/agenta-ui/tests/unit/agentIconColors.test.ts

Included review availability: Your plan includes up to 8 reviews per rolling hour; 7 remain after this review.

Comment thread web/packages/agenta-entities/src/workflow/state/agentIcon.ts Outdated
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-pr-6062.up.railway.app/w
Project agenta-oss-clone-spike
Image tag pr-6062-d42a09c
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-08-18T15:08:32.387Z

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: bb16fe66-e77a-4735-8e92-0ff5ce00e4c4

📥 Commits

Reviewing files that changed from the base of the PR and between b9db11e and d30eaa8.

⛔ Files ignored due to path filters (1)
  • web/packages/agenta-ui/src/agent-icon/catalog.generated.ts is excluded by !**/*.generated.*
📒 Files selected for processing (3)
  • web/packages/agenta-ui/package.json
  • web/packages/agenta-ui/scripts/curated-icons.ts
  • web/packages/agenta-ui/scripts/generate-catalog.ts
💤 Files with no reviewable changes (1)
  • web/packages/agenta-ui/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/packages/agenta-ui/scripts/generate-catalog.ts

Included review availability: Your plan includes up to 8 reviews per rolling hour; 7 remain after this review.

Comment thread web/packages/agenta-ui/scripts/curated-icons.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 207552cb-ec52-4926-ba71-5b75a29a2025

📥 Commits

Reviewing files that changed from the base of the PR and between d30eaa8 and 4233c41.

⛔ Files ignored due to path filters (1)
  • web/packages/agenta-ui/src/agent-icon/catalog.generated.ts is excluded by !**/*.generated.*
📒 Files selected for processing (9)
  • web/oss/src/components/Sidebar/components/WorkflowIdentity.tsx
  • web/packages/agenta-entities/src/workflow/state/agentIcon.ts
  • web/packages/agenta-entities/tests/unit/agent-icon-record.test.ts
  • web/packages/agenta-entities/tests/unit/bounded-map.test.ts
  • web/packages/agenta-entity-ui/src/agent/agentIcon.tsx
  • web/packages/agenta-ui/scripts/generate-catalog.ts
  • web/packages/agenta-ui/src/agent-icon/AgentIcon.tsx
  • web/packages/agenta-ui/src/agent-icon/AgentIconPicker.tsx
  • web/packages/agenta-ui/src/agent-icon/colors.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • web/packages/agenta-ui/scripts/generate-catalog.ts
  • web/packages/agenta-ui/src/agent-icon/AgentIconPicker.tsx
  • web/packages/agenta-ui/src/agent-icon/AgentIcon.tsx
  • web/packages/agenta-ui/src/agent-icon/colors.ts
  • web/oss/src/components/Sidebar/components/WorkflowIdentity.tsx
  • web/packages/agenta-entity-ui/src/agent/agentIcon.tsx

Included review availability: Your plan includes up to 8 reviews per rolling hour; 4 remain after this review.

Comment thread web/packages/agenta-entities/src/workflow/state/agentIcon.ts
@ashrafchowdury
ashrafchowdury changed the base branch from main to release/v0.112.2 August 17, 2026 11:41
@ashrafchowdury

Copy link
Copy Markdown
Contributor Author

@mmabrouk request you for a product review

mmabrouk commented Aug 17, 2026

Copy link
Copy Markdown
Member

@ashrafchowdury The custom icon appears in these agent identity surfaces:

  • Playground header
  • Sidebar agent rows
  • Sidebar workflow switcher
  • Agent cards
  • Chat empty state

It does not appear in two other surfaces that represent the current agent:

  • Assistant-message avatars in AgentMessage.tsx
  • The “Agent updated this configuration” notice in AgentCommitNotice.tsx

I recommend that we use the custom icon in these two surfaces.

The loading shell also shows the default robot. I think that is acceptable because the workflow data may not be available when the shell renders.

The Agents navigation item, the empty Agents page, and app-type icons should keep the default robot. They represent the agent type, not one agent.

Copy link
Copy Markdown
Member

Backend persistence is tracked in #6082.

The issue moves the icon name and color to the workflow artifact under tags.@ag.icon. It also covers tag merging, optimistic updates, browser-value migration, and SVG lookup without storing SVG markup in the backend. I added it to the product issue queue.

@ashrafchowdury
ashrafchowdury changed the base branch from release/v0.112.2 to main August 18, 2026 10:33
@ashrafchowdury
ashrafchowdury changed the base branch from main to release/v0.112.2 August 18, 2026 10:34
@ashrafchowdury
ashrafchowdury changed the base branch from release/v0.112.2 to main August 18, 2026 10:35
@ashrafchowdury
ashrafchowdury changed the base branch from main to release/v0.112.2 August 18, 2026 10:36
Every agent rendered the same fixed Robot glyph, so a workspace with many
agents gave you nothing to tell them apart at a glance. Clicking the chip in
the playground header now opens a picker — any Phosphor icon, a palette or
custom colour, saved as you pick. The sidebar, the agent cards and the chat
empty state display the choice; only the header edits it.

Stored in localStorage for now, keyed by workflow id. The backend home is the
workflow artifact's `meta`, which needs its meta-only update guard fixed first.

Icons come from a generated catalog (`pnpm generate:phosphor-catalog`) that
holds only the regular weight — that is what enforces outline-only. It loads
as a lazy chunk when the picker opens: importing the Phosphor React barrel
would put 4.8 MB in the entry chunk, and a per-icon dynamic import would emit
~1512 chunks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ashrafchowdury and others added 7 commits August 18, 2026 17:33
AgentGlyph returned a fragment whenever an agent had no icon of its own, and a
fragment swallows the className antd clones onto a menu icon. Without
`ant-menu-item-icon` the `.ant-menu-item-icon + .ant-menu-title-content` rule
never matched, so every agent row lost its 10px gap — not only the ones with a
custom icon. The fixed Robot glyph's own ~1.3px of ink padding was all that had
been standing in for it, which is why it read as fine until the glyph changed.

Always render one real element, and forward the className onto it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Searching down to two or three icons shrank the results area, which pulled the
rest of the popover up under the pointer. The no-match case collapsed it
further, to a single line of muted text that was easy to miss.

The grid and the empty state now share one fixed height, so the panel is the
same size from the moment it opens. The empty state also says what happened: a
magnifier, "No icons found", and the query that missed, truncated so a long
search cannot widen the panel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…king it

The Phosphor catalog is 12k lines of generated path data, which made it 91% of
this PR's diff and would do the same on every Phosphor bump. Nobody reviews it.

@agenta/ui now owns the artifact: the generator, the @phosphor-icons/core dep,
and a `prepare` script that regenerates it on every `pnpm install`. Same pattern
@agentaai/api-client already uses to build its dist/. The root script delegates.

The file is gitignored, so a fresh checkout gets it from install rather than
from git. If it is somehow missing, the generator says to run `pnpm install`
rather than failing on a missing module.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous commit moved the dep from the workspace root into @agenta/ui and
added tsx there, but left pnpm-lock.yaml behind. CI installs with
--frozen-lockfile, so every web job failed at the install step before its real
work ran: "1 dependencies were removed: @phosphor-icons/core@2.1.1".

No format or lint problem. Those steps were skipped, not failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The full Phosphor set was 1512 icons, 12k generated lines and 222 KB gzipped,
and the picker opened on a screen of aircraft and alignment glyphs. Curating to
160 icons someone would actually pick for an agent cuts the file to 1349 lines
and 32 KB, and lets it be committed like any other source file.

That removes the machinery the untracked version needed: no `prepare`, so
nothing runs during install, so the Docker images need no early copy of the
generator. Both CI failures we hit came from that machinery, and they are gone
rather than patched.

The list lives in scripts/curated-icons.ts, grouped by category; adding an icon
is one line plus a regenerate. The generator now fails on a name Phosphor does
not have instead of quietly shipping fewer icons, which caught `bracket` and
`telescope` on the first run. Icons emit in curated order, so the picker opens
on robot, brain, sparkle rather than alphabetically.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Correctness:
- Do not cache a rejected catalog import. A chunk that 404s after a deploy left the
  picker spinning for the rest of the session with no retry; it now clears the cached
  promise and offers Try again.
- Hold hue/saturation/value as state and derive the hex from it, not the reverse.
  Re-deriving HSV from the hex lost the hue at both achromatic edges, so any drag to
  white or black collapsed to red with no way back.
- Give trackDrag a teardown and run it on unmount, so a drag interrupted by closing
  the popover no longer commits its colour.
- Stop treating the default colour as selected. No swatch ring and no grid highlight
  until a record exists, so clicking the first swatch is a real change rather than a
  no-op that shifted the sidebar row in dark mode.

Reachability:
- Add a Reset control and widen onChange to accept null, making the atom's documented
  clear path reachable.

Simplification:
- Drop the useMemo in useAgentIconChrome; fallbackGlyph is a fresh element at most
  call sites, so the dependency array never compared equal.
- Carry an explicit customised flag on AgentIconChrome instead of inferring it from
  the presence of style.
- Decide the rail's 17/14 glyph size in one helper instead of two expressions.
- Derive the loading and error heights from the grid height rather than hardcoding.

Tests and docs:
- Cover writeBounded's delete-before-insert ordering rule and the isAgentIconRecord
  guard on path, the two invariants with no coverage.
- Point the generated catalog's banner at the real script path and command.
Review feedback: the 'Agent updated this configuration' notice still drew the shared
robot for every agent. It now wears the agent's own mark, resolved from the signal's
revision through the same workflowId selector the chat empty state uses, and guarded on
isLocalDraftId. An uncustomised agent keeps its existing agent-tag chip untouched.
@ashrafchowdury
ashrafchowdury changed the base branch from release/v0.112.2 to main August 18, 2026 15:03
@ashrafchowdury
ashrafchowdury force-pushed the feat/agent-icon-picker branch from 10dce76 to 7c48f5e Compare August 18, 2026 15:04
@ashrafchowdury
ashrafchowdury changed the base branch from main to release/v0.112.2 August 19, 2026 05:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request frontend size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants