From 2fcfdfa5ddd29fcc7457bb1dae9b57efe5acb475 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Tue, 30 Dec 2025 21:12:58 +0600 Subject: [PATCH 01/12] added provider model metrics --- sdk/agenta/sdk/assets.py | 65 ++++++++++--- sdk/agenta/sdk/types.py | 8 +- .../components/SelectLLMProvider/index.tsx | 96 +++++++++++++++---- .../components/SessionsTable/index.tsx | 1 + .../genericTransformer/helpers/metadata.ts | 43 +++++++-- .../genericTransformer/types/schema.d.ts | 1 + 6 files changed, 173 insertions(+), 41 deletions(-) diff --git a/sdk/agenta/sdk/assets.py b/sdk/agenta/sdk/assets.py index 4457ab357b..b0ee836285 100644 --- a/sdk/agenta/sdk/assets.py +++ b/sdk/agenta/sdk/assets.py @@ -1,19 +1,19 @@ supported_llm_models = { "anthropic": [ - "anthropic/claude-sonnet-4-5", - "anthropic/claude-haiku-4-5", - "anthropic/claude-opus-4-1", - "anthropic/claude-sonnet-4-20250514", - "anthropic/claude-opus-4-20250514", - "anthropic/claude-3-7-sonnet-20250219", - "anthropic/claude-3-5-sonnet-20241022", - "anthropic/claude-3-5-sonnet-20240620", - "anthropic/claude-3-5-haiku-20241022", - "anthropic/claude-3-opus-20240229", - "anthropic/claude-3-sonnet-20240229", - "anthropic/claude-3-haiku-20240307", - "anthropic/claude-2.1", - "anthropic/claude-2", + "claude-sonnet-4-5", + "claude-haiku-4-5", + "claude-opus-4-1", + "claude-sonnet-4-20250514", + "claude-opus-4-20250514", + "claude-3-7-sonnet-20250219", + "claude-3-5-sonnet-20241022", + "claude-3-5-sonnet-20240620", + "claude-3-5-haiku-20241022", + "claude-3-opus-20240229", + "claude-3-sonnet-20240229", + "claude-3-haiku-20240307", + "claude-2.1", + "claude-2", ], "cohere": [ "cohere/command-light", @@ -206,6 +206,43 @@ providers_list = list(supported_llm_models.keys()) + +from typing import TypedDict, Dict +import litellm + + +class ModelMetadata(TypedDict): + input: float + output: float + + +model_metadata: Dict[str, Dict[str, ModelMetadata]] = {} + +for provider, models in supported_llm_models.items(): + model_metadata[provider] = {} + for model in models: + cost_info = None + + # 1. Check for exact match + if model in litellm.model_cost: + cost_info = litellm.model_cost[model] + + # 2. Check for match without provider prefix + if not cost_info and "/" in model: + short_name = model.split("/", 1)[1] + if short_name in litellm.model_cost: + cost_info = litellm.model_cost[short_name] + + if cost_info: + input_cost = cost_info.get("input_cost_per_token", 0) * 1_000_000 + output_cost = cost_info.get("output_cost_per_token", 0) * 1_000_000 + + if input_cost > 0 or output_cost > 0: + model_metadata[provider][model] = { + "input": input_cost, + "output": output_cost, + } + model_to_provider_mapping = { model: provider for provider, models in supported_llm_models.items() diff --git a/sdk/agenta/sdk/types.py b/sdk/agenta/sdk/types.py index f5953a142f..243886ac31 100644 --- a/sdk/agenta/sdk/types.py +++ b/sdk/agenta/sdk/types.py @@ -8,7 +8,7 @@ from starlette.responses import StreamingResponse -from agenta.sdk.assets import supported_llm_models +from agenta.sdk.assets import supported_llm_models, model_metadata from agenta.client.backend.types import AgentaNodesResponse, AgentaNodeDto @@ -23,7 +23,11 @@ def MCField( # pylint: disable=invalid-name ) -> Field: # Pydantic 2.12+ no longer allows post-creation mutation of field properties if isinstance(choices, dict): - json_extra = {"choices": choices, "x-parameter": "grouped_choice"} + json_extra = { + "choices": choices, + "x-parameter": "grouped_choice", + "x-model-metadata": model_metadata, + } elif isinstance(choices, list): json_extra = {"choices": choices, "x-parameter": "choice"} else: diff --git a/web/oss/src/components/SelectLLMProvider/index.tsx b/web/oss/src/components/SelectLLMProvider/index.tsx index 15bbb04df7..42d1fabe4d 100644 --- a/web/oss/src/components/SelectLLMProvider/index.tsx +++ b/web/oss/src/components/SelectLLMProvider/index.tsx @@ -1,13 +1,13 @@ import {useMemo, useRef, useState} from "react" import {CaretRight, Plus, X} from "@phosphor-icons/react" -import {Select, Input, Button, Divider, InputRef, Popover} from "antd" +import {Button, Divider, Input, InputRef, Popover, Select, Typography} from "antd" 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, PROVIDER_LABELS} from "@/oss/lib/Types" +import {PROVIDER_LABELS, SecretDTOProvider} from "@/oss/lib/Types" import LLMIcons from "../LLMIcons" import Anthropic from "../LLMIcons/assets/Anthropic" @@ -25,6 +25,7 @@ interface ProviderOption { label: string value: string key?: string + metadata?: Record } interface ProviderGroup { @@ -169,6 +170,7 @@ const SelectLLMProvider = ({ label: resolvedLabel, value: resolvedValue, key: option?.key ?? resolvedValue, + metadata: option?.metadata, } }) .filter(Boolean) as ProviderOption[]) ?? [], @@ -208,6 +210,65 @@ const SelectLLMProvider = ({ setTimeout(() => setOpen(false), 0) } + const renderTooltipContent = (metadata: Record) => ( +
+ {(metadata.input !== undefined || metadata.output !== undefined) && ( + <> +
+ + Input: + + + ${metadata.input} / 1M + +
+
+ + Output:{" "} + + + ${metadata.output} / 1M + +
+ + )} +
+ ) + + const renderOptionContent = (option: ProviderOption) => { + const Icon = getProviderIcon(option.value) || LLMIcons[option.label] + return ( +
+
+ {Icon && } + {option.label} +
+
+ ) + } + + const renderOption = (option: ProviderOption) => { + const content = renderOptionContent(option) + + if (option.metadata) { + return ( +
e.stopPropagation()}> + + {content} + +
+ ) + } + + return content + } + return ( <>