From 8e9638c7500f48eccaabc11b027c838aeb1ab833 Mon Sep 17 00:00:00 2001 From: Susana Ferreira Date: Wed, 11 Feb 2026 14:32:13 +0000 Subject: [PATCH] feat(site): infer model family icon from model name in AI Bridge logs (#22022) ## Problem Previously, the AI Bridge model column icon was derived from the provider field. This worked because each provider only served its own models: OpenAI interceptions always used OpenAI models, and Anthropic interceptions always used Anthropic models. With the introduction of the Copilot provider, this assumption no longer holds. Copilot can forward requests to both OpenAI and Anthropic models, so the provider field alone is not enough to determine the correct model icon. This caused Copilot interceptions to display a fallback question mark icon for the model. Screenshot 2026-02-10 at 09 10 34 ## Changes * Added `AIBridgeModelIcon` component that infers the model family (Claude, OpenAI) from the model name string and renders the appropriate icon. * Updated `RequestLogsRow` to use `AIBridgeModelIcon` instead of `AIBridgeProviderIcon` in both the table row and the expanded detail view. --- .../RequestLogsPage/AIBridgeModelIcon.tsx | 65 +++++++++++++++++++ .../RequestLogsRow/RequestLogsRow.tsx | 10 +-- 2 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 site/src/pages/AIBridgePage/RequestLogsPage/AIBridgeModelIcon.tsx diff --git a/site/src/pages/AIBridgePage/RequestLogsPage/AIBridgeModelIcon.tsx b/site/src/pages/AIBridgePage/RequestLogsPage/AIBridgeModelIcon.tsx new file mode 100644 index 0000000000..2a3b4aef29 --- /dev/null +++ b/site/src/pages/AIBridgePage/RequestLogsPage/AIBridgeModelIcon.tsx @@ -0,0 +1,65 @@ +import { ExternalImage } from "components/ExternalImage/ExternalImage"; +import { CircleQuestionMarkIcon } from "lucide-react"; +import { cn } from "utils/cn"; + +// Infers the model family from a model name string. +// See official model naming docs: +// - Anthropic: https://docs.anthropic.com/en/docs/about-claude/models/all-models +// - OpenAI: https://platform.openai.com/docs/models +function inferModelFamily(model: string): string { + const modelFamily = model.toLowerCase(); + // Anthropic model families + if ( + modelFamily.includes("claude") || + modelFamily.includes("opus") || + modelFamily.includes("sonnet") || + modelFamily.includes("haiku") + ) { + return "claude"; + } + // OpenAI model families (gpt-*, o1/o3/o4-*, codex, whisper) + if ( + modelFamily.includes("gpt") || + modelFamily.startsWith("o1") || + modelFamily.startsWith("o3") || + modelFamily.startsWith("o4") || + modelFamily.includes("codex") || + modelFamily.includes("whisper") + ) { + return "openai"; + } + return "unknown"; +} + +export const AIBridgeModelIcon = ({ + model, + ...props +}: { + model: string; +} & React.ComponentProps<"svg">) => { + const iconClassName = "flex-shrink-0"; + const family = inferModelFamily(model); + switch (family) { + case "claude": + return ( + + ); + case "openai": + return ( + + ); + default: + return ( + + ); + } +}; diff --git a/site/src/pages/AIBridgePage/RequestLogsPage/RequestLogsRow/RequestLogsRow.tsx b/site/src/pages/AIBridgePage/RequestLogsPage/RequestLogsRow/RequestLogsRow.tsx index feeba6d71c..a60462614e 100644 --- a/site/src/pages/AIBridgePage/RequestLogsPage/RequestLogsRow/RequestLogsRow.tsx +++ b/site/src/pages/AIBridgePage/RequestLogsPage/RequestLogsRow/RequestLogsRow.tsx @@ -17,7 +17,7 @@ import { import { type FC, Fragment, useState } from "react"; import { cn } from "utils/cn"; import { formatDate, humanDuration } from "utils/time"; -import { AIBridgeProviderIcon } from "../AIBridgeProviderIcon"; +import { AIBridgeModelIcon } from "../AIBridgeModelIcon"; type RequestLogsRowProps = { interception: AIBridgeInterception; @@ -204,8 +204,8 @@ export const RequestLogsRow: FC = ({ interception }) => {
-
@@ -279,8 +279,8 @@ export const RequestLogsRow: FC = ({ interception }) => {
-