diff --git a/api/ee/src/services/commoners.py b/api/ee/src/services/commoners.py index 45e5643d78..961857b942 100644 --- a/api/ee/src/services/commoners.py +++ b/api/ee/src/services/commoners.py @@ -133,7 +133,7 @@ async def create_accounts(payload: dict): # Prepare payload to create organization create_org_payload = CreateOrganization( name=user_dict["username"], - description="My Default Organization", + description="Default Organization", owner=str(user.id), type="default", ) diff --git a/api/ee/src/services/db_manager_ee.py b/api/ee/src/services/db_manager_ee.py index c8ebffece7..86d144cc62 100644 --- a/api/ee/src/services/db_manager_ee.py +++ b/api/ee/src/services/db_manager_ee.py @@ -227,7 +227,7 @@ async def create_default_project( """ project_db = await create_project( - "Default", + "Default Project", workspace_id=workspace_id, organization_id=organization_id, session=session, @@ -836,7 +836,7 @@ async def create_organization( name=payload.name, type=payload.type if payload.type else "", description=( - "My Default Workspace" + "Default Workspace" if payload.type == "default" else payload.description if payload.description diff --git a/api/oss/src/core/services/v0.py b/api/oss/src/core/services/v0.py index 06597bd632..7b7aac8eeb 100644 --- a/api/oss/src/core/services/v0.py +++ b/api/oss/src/core/services/v0.py @@ -518,7 +518,6 @@ async def auto_custom_code_run_v0( ) except Exception as e: raise CustomCodeServerV0Error( - code=500, message=str(e), stacktrace=traceback.format_exc(), ) from e diff --git a/api/oss/src/services/admin_manager.py b/api/oss/src/services/admin_manager.py index b8117ee23d..88a042b710 100644 --- a/api/oss/src/services/admin_manager.py +++ b/api/oss/src/services/admin_manager.py @@ -182,7 +182,7 @@ async def legacy_create_organization( name=payload.name, type=payload.type if payload.type else "", description=( - "My Default Workspace" + "Default Workspace" if payload.type == "default" else payload.description if payload.description diff --git a/api/oss/src/services/db_manager.py b/api/oss/src/services/db_manager.py index 2eae87f25c..deb84b651e 100644 --- a/api/oss/src/services/db_manager.py +++ b/api/oss/src/services/db_manager.py @@ -1214,7 +1214,7 @@ async def create_workspace(name: str, organization_id: str): workspace_db = WorkspaceDB( name=name, organization_id=uuid.UUID(organization_id), - description="My Default Workspace", + description="Default Workspace", type="default", ) diff --git a/api/oss/tests/legacy/old_tests/variants_main_router/conftest.py b/api/oss/tests/legacy/old_tests/variants_main_router/conftest.py index e363aec1a7..be33f4fb2e 100644 --- a/api/oss/tests/legacy/old_tests/variants_main_router/conftest.py +++ b/api/oss/tests/legacy/old_tests/variants_main_router/conftest.py @@ -65,11 +65,11 @@ async def get_second_user_object(): async def get_or_create_project_from_db(): async with engine.core_session() as session: result = await session.execute( - select(ProjectDB).filter_by(project_name="default", is_default=True) + select(ProjectDB).filter_by(project_name="Default Project", is_default=True) ) project = result.scalars().first() if project is None: - create_project = ProjectDB(project_name="default", is_default=True) + create_project = ProjectDB(project_name="Default Project", is_default=True) session.add(create_project) await session.commit() await session.refresh(create_project) diff --git a/api/pyproject.toml b/api/pyproject.toml index c1bd003b24..8a726c2e5b 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "api" -version = "0.59.7" +version = "0.59.8" description = "Agenta API" authors = [ { name = "Mahmoud Mabrouk", email = "mahmoud@agenta.ai" }, diff --git a/docs/docs/prompt-engineering/playground/02-adding-custom-providers.mdx b/docs/docs/prompt-engineering/playground/02-adding-custom-providers.mdx index 22ea3e3b6f..bbb65252e8 100644 --- a/docs/docs/prompt-engineering/playground/02-adding-custom-providers.mdx +++ b/docs/docs/prompt-engineering/playground/02-adding-custom-providers.mdx @@ -16,6 +16,7 @@ You can integrate self-hosted models into Agenta by adding custom providers such - [Azure OpenAI](#configuring-azure-openai) - [AWS Bedrock](#configuring-aws-bedrock) +- [Vertex AI](#configuring-vertex-ai) - [OpenAI-compatible endpoints](#configuring-openai-compatible-endpoints-eg-ollama) (including self-hosted models, OpenAI finetuned models, [Ollama](#configuring-openai-compatible-endpoints-eg-ollama), etc.) diff --git a/sdk/agenta/sdk/managers/secrets.py b/sdk/agenta/sdk/managers/secrets.py index 9a5722f899..8cab332968 100644 --- a/sdk/agenta/sdk/managers/secrets.py +++ b/sdk/agenta/sdk/managers/secrets.py @@ -119,11 +119,16 @@ def _get_compatible_model(*, model: str, provider_slug: str): # The reason is that custom providers are in fact openai compatible providers # They need to be passed in litellm as openai/modelname - if "custom" in model: - modified_model = model.replace(f"{provider_slug}/custom/", "openai/") - return modified_model.replace(f"{provider_slug}/", "") + modified_model = model - return model.replace(f"{provider_slug}/", "") + if "custom" in modified_model: + modified_model = modified_model.replace( + f"{provider_slug}/custom/", "openai/" + ) + + modified_model = modified_model.replace(f"{provider_slug}/", "") + + return modified_model @staticmethod def get_provider_settings(model: str) -> Optional[Dict]: @@ -137,6 +142,8 @@ def get_provider_settings(model: str) -> Optional[Dict]: Dict: A dictionary containing all parameters needed for litellm.completion """ + request_provider_model = model + # STEP 1: get vault secrets from route context and transform it secrets = SecretsManager.get_from_route() if not secrets: @@ -146,11 +153,11 @@ def get_provider_settings(model: str) -> Optional[Dict]: secrets = SecretsManager._parse_secrets(secrets=secrets) # STEP 2: check model exists in supported standard models - provider = _standard_providers.get(model) + provider = _standard_providers.get(request_provider_model) if not provider: # check and get provider kind if model exists in custom provider models provider = SecretsManager._custom_providers_get( - model=model, + model=request_provider_model, secrets=secrets, ) @@ -159,16 +166,19 @@ def get_provider_settings(model: str) -> Optional[Dict]: return None # STEP 2c: get litellm compatible model - provider_slug = SecretsManager._custom_provider_slug_get( - model=model, secrets=secrets + request_provider_slug = ( + SecretsManager._custom_provider_slug_get( + model=request_provider_model, secrets=secrets + ) + or "" ) - model = SecretsManager._get_compatible_model( - model=model, provider_slug=provider_slug + compatible_provider_model = SecretsManager._get_compatible_model( + model=request_provider_model, provider_slug=request_provider_slug ) # STEP 3: initialize provider settings and simplify provider name - provider_settings = {"model": model} - provider_name = re.sub( + provider_settings = dict(model=compatible_provider_model) + request_provider_kind = re.sub( r"[\s-]+", "", provider.lower() ) # normalizing other special characters too (azure-openai) @@ -180,9 +190,9 @@ def get_provider_settings(model: str) -> Optional[Dict]: # i). Extract API key if present # (for standard models -- openai/anthropic/gemini, etc) if secret.get("kind") == "provider_key": - provider_kind = secret_data.get("kind", "") + secret_provider_kind = secret_data.get("kind", "") - if provider_kind == provider_name: + if request_provider_kind == secret_provider_kind: if "key" in provider_info: provider_settings["api_key"] = provider_info["key"] continue @@ -190,13 +200,20 @@ def get_provider_settings(model: str) -> Optional[Dict]: # ii). Extract Credentials if present # (for custom providers -- aws bedrock/sagemaker, vertex_ai, etc) elif secret.get("kind") == "custom_provider": - provider_kind = provider_info.get("kind", "").lower().replace(" ", "") - provider_slug = secret_data.get("provider_slug", "") - provider_extras = provider_info.get("extras", {}) - - if provider_kind == provider_name or provider_slug == provider_name: - if provider_extras: - provider_settings.update(provider_extras) + secret_provider_kind = ( + provider_info.get("kind", "").lower().replace(" ", "") + ) + secret_provider_slug = secret_data.get("provider_slug", "") + secret_provider_models = secret_data.get("models", "") + secret_provider_extras = provider_info.get("extras", {}) + + if ( + request_provider_kind == secret_provider_kind + and request_provider_slug == secret_provider_slug + and request_provider_model in secret_provider_models + ): + if secret_provider_extras: + provider_settings.update(secret_provider_extras) continue return provider_settings diff --git a/sdk/pyproject.toml b/sdk/pyproject.toml index 72a0c1303a..249002fb60 100644 --- a/sdk/pyproject.toml +++ b/sdk/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "agenta" -version = "0.59.7" +version = "0.59.8" description = "The SDK for agenta is an open-source LLMOps platform." readme = "README.md" authors = [ diff --git a/web/ee/package.json b/web/ee/package.json index 39f418661f..bb8404cb91 100644 --- a/web/ee/package.json +++ b/web/ee/package.json @@ -1,6 +1,6 @@ { "name": "@agenta/ee", - "version": "0.59.7", + "version": "0.59.8", "private": true, "engines": { "node": ">=18" diff --git a/web/ee/src/components/EvalRunDetails/AutoEvalRun/components/EvalRunTestCaseViewUtilityOptions/index.tsx b/web/ee/src/components/EvalRunDetails/AutoEvalRun/components/EvalRunTestCaseViewUtilityOptions/index.tsx index 35f0777096..18e7fb2897 100644 --- a/web/ee/src/components/EvalRunDetails/AutoEvalRun/components/EvalRunTestCaseViewUtilityOptions/index.tsx +++ b/web/ee/src/components/EvalRunDetails/AutoEvalRun/components/EvalRunTestCaseViewUtilityOptions/index.tsx @@ -30,6 +30,62 @@ interface ScenarioCsvRow { record: Record } +const extractPrimitiveMetricValue = (input: any): any => { + if (input === null || input === undefined) return input + if (typeof input !== "object") return input + if (Array.isArray(input)) { + for (const item of input) { + const value = extractPrimitiveMetricValue(item) + if (value !== undefined) return value + } + return undefined + } + if (typeof (input as any).mean !== "undefined") return (input as any).mean + if (typeof (input as any).value !== "undefined") return (input as any).value + if (Array.isArray((input as any).frequency) && (input as any).frequency.length) { + const sorted = [...(input as any).frequency].sort( + (a, b) => (b?.count ?? 0) - (a?.count ?? 0), + ) + const candidate = sorted.find((entry) => entry?.value !== undefined) + if (candidate) return candidate.value + } + if (Array.isArray((input as any).rank) && (input as any).rank.length) { + const candidate = (input as any).rank.find((entry: any) => entry?.value !== undefined) + if (candidate) return candidate.value + } + if (Array.isArray((input as any).unique) && (input as any).unique.length) { + return (input as any).unique.find((item: any) => item !== undefined) + } + for (const value of Object.values(input)) { + const extracted = extractPrimitiveMetricValue(value) + if (extracted !== undefined) return extracted + } + return undefined +} + +const parseAnnotationMetricKey = ( + key: string, +): null | {slug: string; metric: string; source: "direct" | "analytics"} => { + if (!key.includes(".")) return null + if (key.startsWith("attributes.ag.")) return null + const analyticsOutputMatch = key.match(/^([^\.]+)\.attributes\.ag\.data\.outputs\.(.+)$/) + if (analyticsOutputMatch) { + return {slug: analyticsOutputMatch[1], metric: analyticsOutputMatch[2], source: "analytics"} + } + const analyticsMetricMatch = key.match(/^([^\.]+)\.attributes\.ag\.metrics\.(.+)$/) + if (analyticsMetricMatch) { + return { + slug: analyticsMetricMatch[1], + metric: analyticsMetricMatch[2], + source: "analytics", + } + } + const [slug, ...rest] = key.split(".") + const metric = rest.join(".") + if (!slug || !metric) return null + return {slug, metric, source: "direct"} +} + const EvalRunTestCaseViewUtilityOptions = ({ columns, setEditColumns, @@ -69,6 +125,10 @@ const EvalRunTestCaseViewUtilityOptions = ({ ? (evaluatorsRaw as any[]) : Object.values(evaluatorsRaw as any) const evaluatorSlugs = evaluatorList.map((e: any) => e.slug) + const baseEvaluatorMap = new Map() + evaluatorList.forEach((evaluator: any) => { + if (evaluator?.slug) baseEvaluatorMap.set(evaluator.slug, evaluator) + }) // 2) Resolve steps and metrics for this run const [scenarioMetricsMap, ...allScenarios] = await Promise.all([ @@ -85,9 +145,30 @@ const EvalRunTestCaseViewUtilityOptions = ({ allScenarios.forEach((scenario) => { if (!scenario) return - const sid = scenario.steps?.[0]?.scenarioId + const sid = scenario.scenarioId || scenario.id || scenario.steps?.[0]?.scenarioId const scenarioId = sid ? String(sid) : undefined + const scenarioEvaluatorMap = new Map(baseEvaluatorMap) + const registerEvaluator = (candidate?: any) => { + if (!candidate?.slug) return + const existing = scenarioEvaluatorMap.get(candidate.slug) + if (existing && existing.name) return + scenarioEvaluatorMap.set(candidate.slug, {...existing, ...candidate}) + } + ;(scenario.steps || []).forEach((step: any) => { + registerEvaluator(step?.evaluator) + registerEvaluator(step?.annotation?.references?.evaluator) + }) + ;(scenario.annSteps || []).forEach((step: any) => { + registerEvaluator(step?.evaluator) + registerEvaluator(step?.annotation?.references?.evaluator) + }) + const resolveEvaluatorLabel = (slug?: string) => { + if (!slug) return undefined + const evaluator = scenarioEvaluatorMap.get(slug) + return evaluator?.name || evaluator?.displayName || evaluator?.slug || slug + } + const primaryInput = scenario.inputSteps?.find((s: any) => s.inputs) || {} const {inputs = {}, groundTruth = {}, status: inputStatus} = primaryInput as any @@ -158,13 +239,14 @@ const EvalRunTestCaseViewUtilityOptions = ({ const evalMetricsDefs = store.get(metricsFromEvaluatorsFamily(rId)) as any if (evalMetricsDefs && typeof evalMetricsDefs === "object") { Object.entries(evalMetricsDefs).forEach(([slug, defs]: [string, any[]]) => { - const evaluator = evaluatorList?.find((e) => e?.slug === slug) + const label = resolveEvaluatorLabel(slug) + if (!label) return if (!Array.isArray(defs)) return defs.forEach((metricDef) => { Object.keys(metricDef || {}) .filter((k) => k !== "evaluatorSlug") .forEach((metricName) => { - const key = `${evaluator?.name || slug}.${metricName}` + const key = `${label}.${metricName}` if (!(key in record)) record[key] = "" }) }) @@ -181,19 +263,15 @@ const EvalRunTestCaseViewUtilityOptions = ({ Object.entries(evalMetrics || {}).forEach(([k, v]) => { if (Array.isArray(v)) { v.forEach((metric) => { - const evaluator = (evaluatorList as any[])?.find( - (e) => e?.slug === metric?.evaluatorSlug, - ) const {evaluatorSlug, ...rest} = metric + const label = + resolveEvaluatorLabel(evaluatorSlug) || + evaluatorSlug || + "unknown" Object.keys(rest || {}).forEach((metricKey) => { - if (evaluator) { - record[`${evaluator?.name}.${metricKey}`] = - convertToStringOrJson(errorMessage) - } else { - record[`${metric?.evaluatorSlug}.${metricKey}`] = - convertToStringOrJson(errorMessage) - } + record[`${label}.${metricKey}`] = + convertToStringOrJson(errorMessage) }) }) } @@ -203,29 +281,32 @@ const EvalRunTestCaseViewUtilityOptions = ({ if (annotation) { Object.entries(annotation || {}).forEach(([k, v]) => { - if (!k.includes(".")) return - const [evalSlug, metricName] = k.split(".") - if (["error", "errors"].includes(metricName)) return - const evaluator = (evaluatorList as any[])?.find( - (e) => e?.slug === evalSlug, - ) - - if ((v as any).mean) { - record[`${evaluator?.name}.${metricName}`] = (v as any)?.mean - } else if ((v as any).unique) { - const mostFrequent = (v as any).frequency.reduce( - (max: any, current: any) => - current.count > max.count ? current : max, - ).value - record[`${evaluator?.name}.${metricName}`] = String(mostFrequent) - } else if (v && typeof v !== "object") { - record[`${evaluator?.name}.${metricName}`] = - typeof v === "number" - ? String(v).includes(".") - ? (v as number).toFixed(3) - : v - : convertToStringOrJson(v) + const parsed = parseAnnotationMetricKey(k) + if (!parsed) return + if (["error", "errors"].includes(parsed.metric)) return + const label = resolveEvaluatorLabel(parsed.slug) + if (!label) return + + const primitive = extractPrimitiveMetricValue(v) + if (primitive === undefined) return + + const recordKey = `${label}.${parsed.metric}` + const existingValue = record[recordKey] + if ( + parsed.source === "direct" && + existingValue !== undefined && + existingValue !== null && + existingValue !== "" + ) { + return } + + record[recordKey] = + typeof primitive === "number" + ? Number.isFinite(primitive) && !Number.isInteger(primitive) + ? primitive.toFixed(3) + : primitive + : convertToStringOrJson(primitive) }) } rowsForRun.push({record, scenarioId}) diff --git a/web/ee/src/lib/workers/evalRunner/scenarioListWorker.ts b/web/ee/src/lib/workers/evalRunner/scenarioListWorker.ts index fce789f9a5..bfc3f21f13 100644 --- a/web/ee/src/lib/workers/evalRunner/scenarioListWorker.ts +++ b/web/ee/src/lib/workers/evalRunner/scenarioListWorker.ts @@ -77,7 +77,12 @@ async function fetchPage({ }) if (!res.ok) throw new Error(`fetch ${res.status}`) const json = (await res.json()) as {scenarios?: IScenario[]; next?: string} - return {scenarios: json.scenarios ?? [], next: json.next} + + const scenarios = json.scenarios ?? [] + const nextCursor = + json.next ?? + (scenarios.length === limit ? (scenarios[scenarios.length - 1]?.id ?? null) : null) + return {scenarios, next: nextCursor} } self.onmessage = async (e: MessageEvent) => { diff --git a/web/oss/package.json b/web/oss/package.json index aabe09effa..24b9cfbf7b 100644 --- a/web/oss/package.json +++ b/web/oss/package.json @@ -1,6 +1,6 @@ { "name": "@agenta/oss", - "version": "0.59.7", + "version": "0.59.8", "private": true, "engines": { "node": ">=18" diff --git a/web/oss/src/components/LLMIcons/assets/AnyScale.tsx b/web/oss/src/components/LLMIcons/assets/AnyScale.tsx index 009362e8a6..bad783082c 100644 --- a/web/oss/src/components/LLMIcons/assets/AnyScale.tsx +++ b/web/oss/src/components/LLMIcons/assets/AnyScale.tsx @@ -1,6 +1,6 @@ import {IconProps} from "./types" -const AnyScale = ({...props}: IconProps) => { +const Anyscale = ({...props}: IconProps) => { return ( { ) } -export default AnyScale +export default Anyscale diff --git a/web/oss/src/components/LLMIcons/index.tsx b/web/oss/src/components/LLMIcons/index.tsx index 478b707a9c..7d4315b862 100644 --- a/web/oss/src/components/LLMIcons/index.tsx +++ b/web/oss/src/components/LLMIcons/index.tsx @@ -1,5 +1,3 @@ -import {SecretDTOProvider} from "@/oss/lib/Types" - import AlephAlpha from "./assets/AlephAlpha" import Anthropic from "./assets/Anthropic" import AnyScale from "./assets/AnyScale" @@ -22,26 +20,22 @@ import Vertex from "./assets/Vertex" import XAI from "./assets/XAI" const IconMap: Record> = { - [SecretDTOProvider.OPENAI]: OpenAi, - [SecretDTOProvider.MISTRALAI]: Mistral, - [SecretDTOProvider.COHERE]: Cerebus, - [SecretDTOProvider.ANTHROPIC]: Anthropic, - [SecretDTOProvider.PERPLEXITYAI]: Perplexity, - [SecretDTOProvider.TOGETHERAI]: Together, - [SecretDTOProvider.GROQ]: Groq, - [SecretDTOProvider.GEMINI]: Gemini, - [SecretDTOProvider.OPENROUTER]: OpenRouter, - replicate: Replicate, - lepton: Lepton, - xai: XAI, - fireworks: Fireworks, - alephalpha: AlephAlpha, - anyscale: AnyScale, - azure: Azure, - bedrock: Bedrock, - deepinfra: DeepInfra, - sagemaker: Sagemaker, - vertex_ai: Vertex, + OpenAI: OpenAi, + Cohere: Cerebus, + Anyscale: AnyScale, + DeepInfra: DeepInfra, + "Aleph Alpha": AlephAlpha, + Groq: Groq, + "Mistral AI": Mistral, + Anthropic: Anthropic, + "Perplexity AI": Perplexity, + "Together AI": Together, + OpenRouter: OpenRouter, + "Google Gemini": Gemini, + "Google Vertex AI": Vertex, + "AWS Bedrock": Bedrock, + // "AWS SageMaker": Sagemaker, + "Azure OpenAI": Azure, } export default IconMap diff --git a/web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/ConfigureProviderDrawerTitle.tsx b/web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/ConfigureProviderDrawerTitle.tsx index ac73d25902..4d5f5985b8 100644 --- a/web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/ConfigureProviderDrawerTitle.tsx +++ b/web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/ConfigureProviderDrawerTitle.tsx @@ -1,6 +1,6 @@ import {memo} from "react" -import {Play} from "@phosphor-icons/react" +import {LinkSimple} from "@phosphor-icons/react" import {Button, Typography} from "antd" const ConfigureProviderDrawerTitle = () => { @@ -8,9 +8,11 @@ const ConfigureProviderDrawerTitle = () => {
Configure provider diff --git a/web/oss/src/components/SelectLLMProvider/index.tsx b/web/oss/src/components/SelectLLMProvider/index.tsx index e9176c42b5..784bda6ac0 100644 --- a/web/oss/src/components/SelectLLMProvider/index.tsx +++ b/web/oss/src/components/SelectLLMProvider/index.tsx @@ -7,7 +7,7 @@ import clsx from "clsx" import useLazyEffect from "@/oss/hooks/useLazyEffect" import {useVaultSecret} from "@/oss/hooks/useVaultSecret" import {capitalize} from "@/oss/lib/helpers/utils" -import {SecretDTOProvider} from "@/oss/lib/Types" +import {SecretDTOProvider, PROVIDER_LABELS} from "@/oss/lib/Types" import LLMIcons from "../LLMIcons" import Anthropic from "../LLMIcons/assets/Anthropic" @@ -50,21 +50,36 @@ const SelectLLMProvider = ({ const icons = useMemo(() => [OpenAi, Gemini, Anthropic, Mistral, Together], []) const extendedProviders = useMemo( - () => [...Object.values(SecretDTOProvider), "bedrock", "azure", "vertex_ai", "custom"], + () => [ + ...Object.values(SecretDTOProvider), + "vertex_ai", + "bedrock", + // "sagemaker", + "azure", + "custom", + ], [], ) - const providers = useMemo( + const labeledProviders = useMemo( () => - extendedProviders.map((provider) => { - return { - label: capitalize(provider), - options: [capitalize(provider)], - } - }), + extendedProviders.map((provider) => ({ + key: provider, + label: PROVIDER_LABELS[provider] ?? provider, + })), [extendedProviders], ) + const providers = useMemo( + () => + labeledProviders.map(({ key, label }) => ({ + label, + options: [label], + value: key, + })), + [labeledProviders], + ) + const filteredProviders = useMemo(() => { if (options) { const groupOptions = options.map((group) => ({ @@ -161,7 +176,7 @@ const SelectLLMProvider = ({ > {/* Map out filtered groups and their options */} {filteredProviders.map((group, idx) => { - const GroupIcon = group.label ? LLMIcons[group.label.toLowerCase()] : null + const GroupIcon = group.label ? LLMIcons[group.label] : null return showGroup ? ( ) : ( group.options?.map((option: string) => { - const Icon = LLMIcons[option.toLowerCase()] + const Icon = LLMIcons[option] return (