From 640f78bdfda1d4c01626f1b868f93558a28915dc Mon Sep 17 00:00:00 2001 From: JeremyFunk Date: Thu, 27 Aug 2026 15:53:28 +0200 Subject: [PATCH 1/3] feat(web): framework icons for agent sessions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The list rows and the session header named the emitting framework in words only. Put its brand mark beside the name, from a vendor id -> icon map next to the existing label map. Only frameworks whose logo can be drawn faithfully get a mark; the rest fall back to the generic glyph on purpose — an approximated logo names the wrong company, the fallback just declines to name one. --- .../agent-sessions/agent-sessions-list.tsx | 7 +++- apps/web/src/components/icons/anthropic.tsx | 20 +++++++++++ apps/web/src/components/icons/index.ts | 4 +++ apps/web/src/components/icons/microsoft.tsx | 20 +++++++++++ apps/web/src/components/icons/openai.tsx | 19 +++++++++++ apps/web/src/components/icons/vercel.tsx | 19 +++++++++++ apps/web/src/lab/agent-session-fixture.ts | 10 ++++-- .../lib/agent-sessions/vendor-icon.test.ts | 19 +++++++++++ .../web/src/lib/agent-sessions/vendor-icon.ts | 34 +++++++++++++++++++ .../src/routes/agent-sessions/$sessionId.tsx | 4 +++ 10 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 apps/web/src/components/icons/anthropic.tsx create mode 100644 apps/web/src/components/icons/microsoft.tsx create mode 100644 apps/web/src/components/icons/openai.tsx create mode 100644 apps/web/src/components/icons/vercel.tsx create mode 100644 apps/web/src/lib/agent-sessions/vendor-icon.test.ts create mode 100644 apps/web/src/lib/agent-sessions/vendor-icon.ts diff --git a/apps/web/src/components/agent-sessions/agent-sessions-list.tsx b/apps/web/src/components/agent-sessions/agent-sessions-list.tsx index 28fbaceff..77d96dac5 100644 --- a/apps/web/src/components/agent-sessions/agent-sessions-list.tsx +++ b/apps/web/src/components/agent-sessions/agent-sessions-list.tsx @@ -4,6 +4,7 @@ import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@m import { formatRelativeTimeOrDate, toEpochMs } from "@maple/ui/lib/time-format" import { formatSessionDuration } from "@maple/ui/lib/replay-format" import { ChatBubbleSparkleIcon } from "@/components/icons" +import { vendorIcon } from "@/lib/agent-sessions/vendor-icon" import { vendorLabel } from "@/lib/agent-sessions/vendor-label" /** The wire row from `listAiSessions` — one AI agent session, newest first. */ @@ -58,6 +59,7 @@ export function AgentSessionsList({ sessions, limit }: AgentSessionsListProps) {
{sessions.map((session) => { const hasErrors = session.errorSpanCount > 0 + const VendorIcon = vendorIcon(session.vendorId) const vendor = vendorLabel(session.vendorId) const secondary = session.vendorVersion && session.vendorVersion !== "0" @@ -95,7 +97,10 @@ export function AgentSessionsList({ sessions, limit }: AgentSessionsListProps) { {formatRelativeTimeOrDate(session.startTime)}
-
{secondary}
+
+ + {secondary} +
{hasErrors && (
diff --git a/apps/web/src/components/icons/anthropic.tsx b/apps/web/src/components/icons/anthropic.tsx new file mode 100644 index 000000000..8309c0c8e --- /dev/null +++ b/apps/web/src/components/icons/anthropic.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The Anthropic mark — the "A\" glyph, used for Claude-branded frameworks too. */ +function AnthropicIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { AnthropicIcon } diff --git a/apps/web/src/components/icons/index.ts b/apps/web/src/components/icons/index.ts index a4aa9e638..222257ae5 100644 --- a/apps/web/src/components/icons/index.ts +++ b/apps/web/src/components/icons/index.ts @@ -55,6 +55,7 @@ export { } from "@maple/ui/components/icons" // App-specific icons (not part of the core library). +export { AnthropicIcon } from "./anthropic" export { ArrowPathIcon } from "./arrow-path" export { ArrowRightFromLineIcon } from "./arrow-right-from-line" export { ArrowThroughLineRightIcon } from "./arrow-through-line-right" @@ -118,12 +119,14 @@ export { LogoutIcon } from "./logout" export { MaximizeIcon } from "./maximize" export { MediaPauseIcon } from "./media-pause" export { MediaPlayIcon } from "./media-play" +export { MicrosoftIcon } from "./microsoft" export { MinimizeIcon } from "./minimize" export { MongodbIcon } from "./mongodb" export { MoonIcon } from "./moon" export { MysqlIcon } from "./mysql" export { NatsIcon } from "./nats" export { NodejsIcon } from "./nodejs" +export { OpenAiIcon } from "./openai" export { OpenjdkIcon } from "./openjdk" export { OperaIcon } from "./opera" export { PaletteIcon } from "./palette" @@ -160,6 +163,7 @@ export { SunIcon } from "./sun" export { TelegramIcon, TelegramMonoIcon } from "./telegram" export { TranscriptIcon } from "./transcript" export { TruckIcon } from "./truck" +export { VercelIcon } from "./vercel" export { WarpStreamIcon } from "./warpstream" export { UploadIcon } from "./upload" export { WorkflowRingIcon, WORKFLOW_LABEL, WORKFLOW_COLOR } from "./workflow-ring" diff --git a/apps/web/src/components/icons/microsoft.tsx b/apps/web/src/components/icons/microsoft.tsx new file mode 100644 index 000000000..89851817f --- /dev/null +++ b/apps/web/src/components/icons/microsoft.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The Microsoft four-square mark, flattened to one colour. */ +function MicrosoftIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { MicrosoftIcon } diff --git a/apps/web/src/components/icons/openai.tsx b/apps/web/src/components/icons/openai.tsx new file mode 100644 index 000000000..ebbafba8a --- /dev/null +++ b/apps/web/src/components/icons/openai.tsx @@ -0,0 +1,19 @@ +import type { IconProps } from "./icon" + +function OpenAiIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { OpenAiIcon } diff --git a/apps/web/src/components/icons/vercel.tsx b/apps/web/src/components/icons/vercel.tsx new file mode 100644 index 000000000..d411d0646 --- /dev/null +++ b/apps/web/src/components/icons/vercel.tsx @@ -0,0 +1,19 @@ +import type { IconProps } from "./icon" + +function VercelIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { VercelIcon } diff --git a/apps/web/src/lab/agent-session-fixture.ts b/apps/web/src/lab/agent-session-fixture.ts index 44ad9990f..fec60dcdd 100644 --- a/apps/web/src/lab/agent-session-fixture.ts +++ b/apps/web/src/lab/agent-session-fixture.ts @@ -256,12 +256,16 @@ function toolResult(tool: string): string | undefined { } } +/** The gateway stamps a vendor on every AI span, so the fixture carries one too + * — it is what puts a framework mark beside the label in the header and rows. */ +const VENDOR_ID = "claude_agent_sdk" + export function buildAgentSessionFixture(): readonly AiSessionSpan[] { const base = buildBaseTurns() const baseEndMs = Math.max(...base.map((span) => spanStartMs(span) + span.durationMs)) - T0 - return [...base, ...buildTranscriptTurns(baseEndMs + 2 * MINUTE)].sort( - (a, b) => spanStartMs(a) - spanStartMs(b), - ) + return [...base, ...buildTranscriptTurns(baseEndMs + 2 * MINUTE)] + .sort((a, b) => spanStartMs(a) - spanStartMs(b)) + .map((span) => ({ ...span, vendorId: VENDOR_ID })) } /** diff --git a/apps/web/src/lib/agent-sessions/vendor-icon.test.ts b/apps/web/src/lib/agent-sessions/vendor-icon.test.ts new file mode 100644 index 000000000..52e6ede19 --- /dev/null +++ b/apps/web/src/lib/agent-sessions/vendor-icon.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from "vitest" + +import { AnthropicIcon, ChatBubbleSparkleIcon, OpenAiIcon } from "@/components/icons" +import { vendorIcon } from "./vendor-icon" + +describe("vendorIcon", () => { + it("gives a recognised framework its brand mark", () => { + expect(vendorIcon("claude_agent_sdk")).toBe(AnthropicIcon) + // Two ids, one framework: the OpenInference instrumentation is still OpenAI. + expect(vendorIcon("openai_agents_sdk")).toBe(OpenAiIcon) + expect(vendorIcon("openinference-openai")).toBe(OpenAiIcon) + }) + + it("falls back for frameworks without a mark, and for no vendor at all", () => { + expect(vendorIcon("crewai")).toBe(ChatBubbleSparkleIcon) + expect(vendorIcon("unknown:genai")).toBe(ChatBubbleSparkleIcon) + expect(vendorIcon("")).toBe(ChatBubbleSparkleIcon) + }) +}) diff --git a/apps/web/src/lib/agent-sessions/vendor-icon.ts b/apps/web/src/lib/agent-sessions/vendor-icon.ts new file mode 100644 index 000000000..145d23a4a --- /dev/null +++ b/apps/web/src/lib/agent-sessions/vendor-icon.ts @@ -0,0 +1,34 @@ +import { MapleMark } from "@maple/ui/components/icons" + +import { + AnthropicIcon, + ChatBubbleSparkleIcon, + GoogleIcon, + type IconComponent, + MicrosoftIcon, + OpenAiIcon, + VercelIcon, +} from "@/components/icons" + +/** + * Brand marks for the vendor ids the ingest gateway stamps. A framework is + * listed only when its logo is one we can draw faithfully — the rest fall back + * to the generic mark on purpose. An approximated logo names the wrong company; + * the fallback merely declines to name one, and `vendorLabel` says it in words + * either way. + */ +const VENDOR_ICONS: Record = { + claude_agent_sdk: AnthropicIcon, + google_adk: GoogleIcon, + maple: MapleMark, + microsoft_agent_framework: MicrosoftIcon, + openai_agents_sdk: OpenAiIcon, + "openinference-openai": OpenAiIcon, + semantic_kernel: MicrosoftIcon, + vercel_ai_sdk: VercelIcon, +} satisfies Record + +/** The mark that belongs beside `vendorLabel(vendorId)`. */ +export function vendorIcon(vendorId: string): IconComponent { + return VENDOR_ICONS[vendorId] ?? ChatBubbleSparkleIcon +} diff --git a/apps/web/src/routes/agent-sessions/$sessionId.tsx b/apps/web/src/routes/agent-sessions/$sessionId.tsx index 4f7337d25..26b6e7fd3 100644 --- a/apps/web/src/routes/agent-sessions/$sessionId.tsx +++ b/apps/web/src/routes/agent-sessions/$sessionId.tsx @@ -29,6 +29,7 @@ import { } from "@/lib/agent-sessions/session-window" import { buildSessionSummary, type SessionSummary } from "@/lib/agent-sessions/session-summary" import { buildSessionTurns } from "@/lib/agent-sessions/session-turns" +import { vendorIcon } from "@/lib/agent-sessions/vendor-icon" import { vendorLabel } from "@/lib/agent-sessions/vendor-label" import { Result, useAtomValue } from "@/lib/effect-atom" import { displayError } from "@/lib/error-messages" @@ -225,6 +226,8 @@ function SessionDetailBody({ // Message content is opt-in and off by default, so most sessions have no // opening user message to title the page with. const title = summary.title ?? breadcrumbSessionId(sessionId) + // The framework that emitted the session, as its mark — the subtitle names it. + const VendorIcon = vendorIcon(summary.vendorIds[0] ?? "") return ( @@ -233,6 +236,7 @@ function SessionDetailBody({ + {summary.title === undefined ? ( // The id fallback title copies the full session id. From b1b4e07d55d23af625b40f18afbf817ebabcf95b Mon Sep 17 00:00:00 2001 From: JeremyFunk Date: Thu, 27 Aug 2026 16:57:42 +0200 Subject: [PATCH 2/3] feat(web): extend framework icon coverage to every vendor with verifiable geometry --- apps/web/src/components/icons/anthropic.tsx | 20 ------------------- apps/web/src/components/icons/claude.tsx | 20 +++++++++++++++++++ apps/web/src/components/icons/crewai.tsx | 20 +++++++++++++++++++ apps/web/src/components/icons/effect.tsx | 20 +++++++++++++++++++ apps/web/src/components/icons/haystack.tsx | 20 +++++++++++++++++++ apps/web/src/components/icons/huggingface.tsx | 20 +++++++++++++++++++ apps/web/src/components/icons/index.ts | 9 ++++++++- apps/web/src/components/icons/langchain.tsx | 20 +++++++++++++++++++ apps/web/src/components/icons/pydantic.tsx | 20 +++++++++++++++++++ apps/web/src/components/icons/spring.tsx | 20 +++++++++++++++++++ .../lib/agent-sessions/vendor-icon.test.ts | 7 ++++--- .../web/src/lib/agent-sessions/vendor-icon.ts | 18 +++++++++++++++-- 12 files changed, 188 insertions(+), 26 deletions(-) delete mode 100644 apps/web/src/components/icons/anthropic.tsx create mode 100644 apps/web/src/components/icons/claude.tsx create mode 100644 apps/web/src/components/icons/crewai.tsx create mode 100644 apps/web/src/components/icons/effect.tsx create mode 100644 apps/web/src/components/icons/haystack.tsx create mode 100644 apps/web/src/components/icons/huggingface.tsx create mode 100644 apps/web/src/components/icons/langchain.tsx create mode 100644 apps/web/src/components/icons/pydantic.tsx create mode 100644 apps/web/src/components/icons/spring.tsx diff --git a/apps/web/src/components/icons/anthropic.tsx b/apps/web/src/components/icons/anthropic.tsx deleted file mode 100644 index 8309c0c8e..000000000 --- a/apps/web/src/components/icons/anthropic.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { IconProps } from "./icon" - -/** The Anthropic mark — the "A\" glyph, used for Claude-branded frameworks too. */ -function AnthropicIcon({ size = 24, className, ...props }: IconProps) { - return ( - - ) -} -export { AnthropicIcon } diff --git a/apps/web/src/components/icons/claude.tsx b/apps/web/src/components/icons/claude.tsx new file mode 100644 index 000000000..5f03fa9a6 --- /dev/null +++ b/apps/web/src/components/icons/claude.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The Claude spark mark — Claude-branded agent frameworks. */ +function ClaudeIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { ClaudeIcon } diff --git a/apps/web/src/components/icons/crewai.tsx b/apps/web/src/components/icons/crewai.tsx new file mode 100644 index 000000000..c8717deb1 --- /dev/null +++ b/apps/web/src/components/icons/crewai.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The CrewAI mark. */ +function CrewAiIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { CrewAiIcon } diff --git a/apps/web/src/components/icons/effect.tsx b/apps/web/src/components/icons/effect.tsx new file mode 100644 index 000000000..17c704f9f --- /dev/null +++ b/apps/web/src/components/icons/effect.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The Effect mark, for Effect AI. */ +function EffectIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { EffectIcon } diff --git a/apps/web/src/components/icons/haystack.tsx b/apps/web/src/components/icons/haystack.tsx new file mode 100644 index 000000000..69417320c --- /dev/null +++ b/apps/web/src/components/icons/haystack.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The Haystack mark. */ +function HaystackIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { HaystackIcon } diff --git a/apps/web/src/components/icons/huggingface.tsx b/apps/web/src/components/icons/huggingface.tsx new file mode 100644 index 000000000..43cf20ed2 --- /dev/null +++ b/apps/web/src/components/icons/huggingface.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The Hugging Face mark, for smolagents. */ +function HuggingFaceIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { HuggingFaceIcon } diff --git a/apps/web/src/components/icons/index.ts b/apps/web/src/components/icons/index.ts index 222257ae5..5085cd809 100644 --- a/apps/web/src/components/icons/index.ts +++ b/apps/web/src/components/icons/index.ts @@ -55,7 +55,6 @@ export { } from "@maple/ui/components/icons" // App-specific icons (not part of the core library). -export { AnthropicIcon } from "./anthropic" export { ArrowPathIcon } from "./arrow-path" export { ArrowRightFromLineIcon } from "./arrow-right-from-line" export { ArrowThroughLineRightIcon } from "./arrow-through-line-right" @@ -74,8 +73,10 @@ export { ChartBarTrendUpIcon } from "./chart-bar-trend-up" export { ChartLineIcon } from "./chart-line" export { CirclePercentageIcon } from "./circle-percentage" export { CircleQuestionIcon } from "./circle-question" +export { ClaudeIcon } from "./claude" export { ClickhouseIcon } from "./clickhouse" export { CloudflareIcon, CloudflareMonoIcon } from "./cloudflare" +export { CrewAiIcon } from "./crewai" export { ChromeIcon } from "./chrome" export { CompactLinesIcon } from "./compact-lines" export { CornerDownLeftIcon } from "./corner-down-left" @@ -84,6 +85,7 @@ export { CursorPointerIcon } from "./cursor-pointer" export { CreditCardIcon } from "./credit-card" export { CubeIcon } from "./cube" export { DiscordIcon } from "./discord" +export { EffectIcon } from "./effect" export { DotsVerticalIcon } from "./dots-vertical" export { DownloadIcon } from "./download" export { EdgeIcon } from "./edge" @@ -97,6 +99,8 @@ export { FolderIcon } from "./folder" export { GearIcon } from "./gear" export { GithubIcon } from "./github" export { GoogleIcon } from "./google" +export { HaystackIcon } from "./haystack" +export { HuggingFaceIcon } from "./huggingface" export { GridIcon } from "./grid" export { GridSquareCirclePlusIcon } from "./grid-square-circle-plus" export { GripDotsIcon } from "./grip-dots" @@ -108,6 +112,7 @@ export { HouseIcon } from "./house" export { IdBadgeIcon } from "./id-badge" export { ImageIcon } from "./image" export { KafkaIcon } from "./kafka" +export { LangchainIcon } from "./langchain" export { KeyIcon } from "./key" export { KeyboardIcon } from "./keyboard" export { KubernetesIcon } from "./kubernetes" @@ -133,6 +138,7 @@ export { PaletteIcon } from "./palette" export { PaperPlaneIcon } from "./paper-plane" export { PencilIcon } from "./pencil" export { PlanetScaleIcon } from "./planetscale" +export { PydanticIcon } from "./pydantic" // Nucleo Pixel Essential — a deliberately separate family, used where a row // needs a type marker rather than an action affordance (the session replay // event rail). Don't mix them with the outline icons inside one control. @@ -154,6 +160,7 @@ export { SafariIcon } from "./safari" export { ServerIcon } from "./server" export { ShieldIcon } from "./shield" export { SlackIcon, SlackMonoIcon } from "./slack" +export { SpringIcon } from "./spring" export { SlidersIcon } from "./sliders" export { SpinnerIcon } from "./spinner" export { SquareIcon } from "./square" diff --git a/apps/web/src/components/icons/langchain.tsx b/apps/web/src/components/icons/langchain.tsx new file mode 100644 index 000000000..9473b3eeb --- /dev/null +++ b/apps/web/src/components/icons/langchain.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The LangChain chain-link mark. */ +function LangchainIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { LangchainIcon } diff --git a/apps/web/src/components/icons/pydantic.tsx b/apps/web/src/components/icons/pydantic.tsx new file mode 100644 index 000000000..761213a5a --- /dev/null +++ b/apps/web/src/components/icons/pydantic.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The Pydantic mark, for Pydantic AI. */ +function PydanticIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { PydanticIcon } diff --git a/apps/web/src/components/icons/spring.tsx b/apps/web/src/components/icons/spring.tsx new file mode 100644 index 000000000..bf3a43753 --- /dev/null +++ b/apps/web/src/components/icons/spring.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from "./icon" + +/** The Spring mark, for Spring AI. */ +function SpringIcon({ size = 24, className, ...props }: IconProps) { + return ( + + ) +} +export { SpringIcon } diff --git a/apps/web/src/lib/agent-sessions/vendor-icon.test.ts b/apps/web/src/lib/agent-sessions/vendor-icon.test.ts index 52e6ede19..c35c1e6bb 100644 --- a/apps/web/src/lib/agent-sessions/vendor-icon.test.ts +++ b/apps/web/src/lib/agent-sessions/vendor-icon.test.ts @@ -1,18 +1,19 @@ import { describe, expect, it } from "vitest" -import { AnthropicIcon, ChatBubbleSparkleIcon, OpenAiIcon } from "@/components/icons" +import { ChatBubbleSparkleIcon, ClaudeIcon, LangchainIcon, OpenAiIcon } from "@/components/icons" import { vendorIcon } from "./vendor-icon" describe("vendorIcon", () => { it("gives a recognised framework its brand mark", () => { - expect(vendorIcon("claude_agent_sdk")).toBe(AnthropicIcon) + expect(vendorIcon("claude_agent_sdk")).toBe(ClaudeIcon) + expect(vendorIcon("langchain")).toBe(LangchainIcon) // Two ids, one framework: the OpenInference instrumentation is still OpenAI. expect(vendorIcon("openai_agents_sdk")).toBe(OpenAiIcon) expect(vendorIcon("openinference-openai")).toBe(OpenAiIcon) }) it("falls back for frameworks without a mark, and for no vendor at all", () => { - expect(vendorIcon("crewai")).toBe(ChatBubbleSparkleIcon) + expect(vendorIcon("litellm")).toBe(ChatBubbleSparkleIcon) expect(vendorIcon("unknown:genai")).toBe(ChatBubbleSparkleIcon) expect(vendorIcon("")).toBe(ChatBubbleSparkleIcon) }) diff --git a/apps/web/src/lib/agent-sessions/vendor-icon.ts b/apps/web/src/lib/agent-sessions/vendor-icon.ts index 145d23a4a..b8e6bcddd 100644 --- a/apps/web/src/lib/agent-sessions/vendor-icon.ts +++ b/apps/web/src/lib/agent-sessions/vendor-icon.ts @@ -1,12 +1,19 @@ import { MapleMark } from "@maple/ui/components/icons" import { - AnthropicIcon, ChatBubbleSparkleIcon, + ClaudeIcon, + CrewAiIcon, + EffectIcon, GoogleIcon, + HaystackIcon, + HuggingFaceIcon, type IconComponent, + LangchainIcon, MicrosoftIcon, OpenAiIcon, + PydanticIcon, + SpringIcon, VercelIcon, } from "@/components/icons" @@ -18,13 +25,20 @@ import { * either way. */ const VENDOR_ICONS: Record = { - claude_agent_sdk: AnthropicIcon, + claude_agent_sdk: ClaudeIcon, + crewai: CrewAiIcon, + effect_ai: EffectIcon, google_adk: GoogleIcon, + haystack: HaystackIcon, + langchain: LangchainIcon, maple: MapleMark, microsoft_agent_framework: MicrosoftIcon, openai_agents_sdk: OpenAiIcon, "openinference-openai": OpenAiIcon, + pydantic_ai: PydanticIcon, semantic_kernel: MicrosoftIcon, + smolagents: HuggingFaceIcon, + spring_ai: SpringIcon, vercel_ai_sdk: VercelIcon, } satisfies Record From dfacbe7032495cc9d33baf6e985b9d13d28345fe Mon Sep 17 00:00:00 2001 From: JeremyFunk Date: Thu, 27 Aug 2026 20:14:02 +0200 Subject: [PATCH 3/3] feat(web): eve sessions carry the Vercel mark --- apps/web/src/lib/agent-sessions/vendor-icon.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/web/src/lib/agent-sessions/vendor-icon.ts b/apps/web/src/lib/agent-sessions/vendor-icon.ts index b8e6bcddd..eb621fc67 100644 --- a/apps/web/src/lib/agent-sessions/vendor-icon.ts +++ b/apps/web/src/lib/agent-sessions/vendor-icon.ts @@ -28,6 +28,8 @@ const VENDOR_ICONS: Record = { claude_agent_sdk: ClaudeIcon, crewai: CrewAiIcon, effect_ai: EffectIcon, + // eve is Vercel's agent framework and has no mark of its own. + eve: VercelIcon, google_adk: GoogleIcon, haystack: HaystackIcon, langchain: LangchainIcon,