From 268b34774cba2832bff831fe6e72f8fd71ad2a3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B9=E9=9B=AA?= <2b@yorha.xyz> Date: Thu, 11 Jun 2026 02:32:38 +0900 Subject: [PATCH] feat(ui): i18n for agents config and info views --- .../agents/agent_card_discovery.tsx | 62 +++++--- .../src/components/agents/agent_config.ts | 124 +++++++-------- .../src/components/agents/agent_cost_view.tsx | 16 +- .../components/agents/agent_form_fields.tsx | 77 +++++---- .../src/components/agents/agent_info.tsx | 148 +++++++++++------- .../components/agents/cost_config_fields.tsx | 6 +- .../agents/dynamic_agent_form_fields.tsx | 6 +- ui/litellm-dashboard/src/locales/en.json | 138 ++++++++++++++++ ui/litellm-dashboard/src/locales/zh-CN.json | 138 ++++++++++++++++ 9 files changed, 530 insertions(+), 185 deletions(-) diff --git a/ui/litellm-dashboard/src/components/agents/agent_card_discovery.tsx b/ui/litellm-dashboard/src/components/agents/agent_card_discovery.tsx index 3fa35419fde..82b89e200de 100644 --- a/ui/litellm-dashboard/src/components/agents/agent_card_discovery.tsx +++ b/ui/litellm-dashboard/src/components/agents/agent_card_discovery.tsx @@ -1,6 +1,7 @@ "use client"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; import { Alert, Button, Checkbox, Collapse, Empty, Input, Space, Spin, Switch, Tag, Tooltip, Typography } from "antd"; // Empty is used in the skills panel below. import { @@ -61,6 +62,7 @@ const AgentCardDiscovery: React.FC = ({ discoveryRequest, savedAgentCard, }) => { + const { t } = useTranslation(); // When the parent drives discovery, ``manualUrl`` is unused — the URL // comes from ``discoveryRequest.url`` directly. When the parent hasn't // supplied a plan, the admin types into this field manually. @@ -115,14 +117,16 @@ const AgentCardDiscovery: React.FC = ({ const handleDiscover = useCallback(async () => { if (!accessToken) { - setError("No access token available"); + setError(t("agentsPage.agentCardDiscovery.noAccessToken")); onApplyRef.current(null); return; } const trimmed = effectiveUrl.trim(); if (!trimmed) { setError( - isParentDriven ? "Fill in the agent's connection details above first" : "Enter the agent's base URL first", + isParentDriven + ? t("agentsPage.agentCardDiscovery.fillConnectionDetails") + : t("agentsPage.agentCardDiscovery.enterBaseUrl"), ); setCard(null); onApplyRef.current(null); @@ -150,7 +154,7 @@ const AgentCardDiscovery: React.FC = ({ resetSelections(response.agent_card); } catch (e: any) { if (requestId !== discoverRequestIdRef.current) return; - setError(e?.message ? String(e.message) : "Failed to discover agent card"); + setError(e?.message ? String(e.message) : t("agentsPage.agentCardDiscovery.failedToDiscover")); setCard(null); lastSyncedSelectionRef.current = null; onApplyRef.current(null); @@ -169,7 +173,7 @@ const AgentCardDiscovery: React.FC = ({ // during editing), which would re-fire the auto-discover effect and // wipe in-progress user selections. // eslint-disable-next-line react-hooks/exhaustive-deps - }, [accessToken, effectiveUrl, isParentDriven, discoveryMode, discoveryParamsKey]); + }, [accessToken, effectiveUrl, isParentDriven, discoveryMode, discoveryParamsKey, t]); // Auto-discover when the URL (or parent plan) becomes available. Debounce // is applied uniformly so rapid changes from a watched parent form (e.g. @@ -239,19 +243,19 @@ const AgentCardDiscovery: React.FC = ({
- Discover from agent URL - + {t("agentsPage.agentCardDiscovery.discoverFromUrl")} +
{isParentDriven ? ( <> - Using the connection details you entered above. We'll fetch: + {t("agentsPage.agentCardDiscovery.usingConnectionDetails")}
{discoveryRequest!.display_url || effectiveUrl || ( - Fill in the fields above first + {t("agentsPage.agentCardDiscovery.fillFieldsAbove")} )}
@@ -262,15 +266,14 @@ const AgentCardDiscovery: React.FC = ({ onClick={handleDiscover} disabled={!effectiveUrl.trim()} > - {card ? "Re-discover" : "Discover"} + {card ? t("agentsPage.agentCardDiscovery.rediscover") : t("agentsPage.agentCardDiscovery.discover")}
) : ( <> - Paste the upstream agent's base URL. We'll try /.well-known/agent-card.json,{" "} - /.well-known/agent.json, and /agent.json in order. + {t("agentsPage.agentCardDiscovery.pasteUrlHint")} @@ -288,7 +291,7 @@ const AgentCardDiscovery: React.FC = ({ loading={loading} onClick={handleDiscover} > - {card ? "Re-discover" : "Discover"} + {card ? t("agentsPage.agentCardDiscovery.rediscover") : t("agentsPage.agentCardDiscovery.discover")} @@ -298,7 +301,7 @@ const AgentCardDiscovery: React.FC = ({ = ({
- Upstream card loaded + {t("agentsPage.agentCardDiscovery.upstreamCardLoaded")} {card.version && v{card.version}} {card.provider?.organization && {card.provider.organization}} @@ -325,16 +328,22 @@ const AgentCardDiscovery: React.FC = ({
- - setEditedName(e.target.value)} placeholder="Agent name" /> + + setEditedName(e.target.value)} + placeholder={t("agentsPage.agentCardDiscovery.namePlaceholder")} + />
- + setEditedDescription(e.target.value)} rows={2} - placeholder="What this agent does" + placeholder={t("agentsPage.agentCardDiscovery.descriptionPlaceholder")} />
@@ -344,15 +353,18 @@ const AgentCardDiscovery: React.FC = ({ key="skills" header={ - Skills + {t("agentsPage.agentCardDiscovery.skillsTitle")} - {selectedSkillCount} / {skillCount} selected + {t("agentsPage.agentCardDiscovery.skillsSelected", { + selected: selectedSkillCount, + total: skillCount, + })} } > {skillCount === 0 ? ( - + ) : (
{(card.skills ?? []).map((skill, idx) => { @@ -379,7 +391,7 @@ const AgentCardDiscovery: React.FC = ({ {skill.description && ( {skill.description} @@ -396,8 +408,8 @@ const AgentCardDiscovery: React.FC = ({ key="capabilities" header={ - Capabilities - + {t("agentsPage.agentCardDiscovery.capabilitiesTitle")} + @@ -417,7 +429,7 @@ const AgentCardDiscovery: React.FC = ({ {!upstreamHas && ( - not advertised upstream + {t("agentsPage.agentCardDiscovery.notAdvertisedUpstream")} )}
diff --git a/ui/litellm-dashboard/src/components/agents/agent_config.ts b/ui/litellm-dashboard/src/components/agents/agent_config.ts index 14b6729bf93..77807d92f04 100644 --- a/ui/litellm-dashboard/src/components/agents/agent_config.ts +++ b/ui/litellm-dashboard/src/components/agents/agent_config.ts @@ -2,6 +2,7 @@ * Shared configuration for agent form fields * Used across create, view, and update operations */ +import type { TFunction } from "i18next"; export interface FieldConfig { name: string; @@ -22,7 +23,9 @@ export interface SectionConfig { defaultExpanded?: boolean; } -export const AGENT_FORM_CONFIG: { +export const getAgentFormConfig = ( + t: TFunction, +): { basic: SectionConfig; skills: SectionConfig; capabilities: SectionConfig; @@ -30,45 +33,45 @@ export const AGENT_FORM_CONFIG: { litellm: SectionConfig; cost: SectionConfig; tracing: SectionConfig; -} = { +} => ({ basic: { key: "basic", - title: "Basic Information", + title: t("agentsPage.agentConfig.basicTitle"), defaultExpanded: true, fields: [ { name: "name", - label: "Display Name", + label: t("agentsPage.agentConfig.displayNameLabel"), type: "text", required: true, - placeholder: "e.g., Customer Support Agent", + placeholder: t("agentsPage.agentConfig.displayNamePlaceholder"), }, { name: "description", - label: "Description", + label: t("common.description"), type: "textarea", required: true, - placeholder: "Describe what this agent does...", + placeholder: t("agentsPage.agentConfig.descriptionPlaceholder"), rows: 3, }, { name: "url", - label: "URL", + label: t("agentsPage.agentConfig.urlLabel"), type: "url", required: false, - placeholder: "http://localhost:9999/", - tooltip: "Base URL where the agent is hosted (optional)", + placeholder: t("agentsPage.agentConfig.urlPlaceholder"), + tooltip: t("agentsPage.agentConfig.urlTooltip"), }, { name: "version", - label: "Version", + label: t("agentsPage.agentConfig.versionLabel"), type: "text", placeholder: "1.0.0", defaultValue: "1.0.0", }, { name: "protocolVersion", - label: "Protocol Version", + label: t("agentsPage.agentConfig.protocolVersionLabel"), type: "text", placeholder: "1.0", defaultValue: "1.0", @@ -77,11 +80,11 @@ export const AGENT_FORM_CONFIG: { }, skills: { key: "skills", - title: "Skills", + title: t("agentsPage.agentConfig.skillsTitle"), fields: [ { name: "skills", - label: "Skills", + label: t("agentsPage.agentConfig.skillsTitle"), type: "list", defaultValue: [], }, @@ -89,159 +92,152 @@ export const AGENT_FORM_CONFIG: { }, capabilities: { key: "capabilities", - title: "Capabilities", + title: t("agentsPage.agentConfig.capabilitiesTitle"), fields: [ { name: "streaming", - label: "Streaming", + label: t("agentsPage.agentConfig.streamingLabel"), type: "switch", defaultValue: false, }, { name: "pushNotifications", - label: "Push Notifications", + label: t("agentsPage.agentConfig.pushNotificationsLabel"), type: "switch", }, { name: "stateTransitionHistory", - label: "State Transition History", + label: t("agentsPage.agentConfig.stateTransitionHistoryLabel"), type: "switch", }, ], }, optional: { key: "optional", - title: "Optional Settings", + title: t("agentsPage.agentConfig.optionalTitle"), fields: [ { name: "iconUrl", - label: "Icon URL", + label: t("agentsPage.agentConfig.iconUrlLabel"), type: "url", placeholder: "https://example.com/icon.png", }, { name: "documentationUrl", - label: "Documentation URL", + label: t("agentsPage.agentConfig.documentationUrlLabel"), type: "url", placeholder: "https://docs.example.com", }, { name: "supportsAuthenticatedExtendedCard", - label: "Supports Authenticated Extended Card", + label: t("agentsPage.agentConfig.supportsAuthCardLabel"), type: "switch", }, ], }, litellm: { key: "litellm", - title: "LiteLLM Parameters", + title: t("agentsPage.agentConfig.litellmTitle"), fields: [ { name: "model", - label: "Model (Optional)", + label: t("agentsPage.agentConfig.modelOptionalLabel"), type: "text", }, { name: "make_public", - label: "Make Public", + label: t("agentsPage.agentConfig.makePublicLabel"), type: "switch", }, ], }, cost: { key: "cost", - title: "Cost Configuration", + title: t("agentsPage.agentConfig.costTitle"), fields: [ { name: "cost_per_query", - label: "Cost Per Query ($)", + label: t("agentsPage.agentConfig.costPerQueryLabel"), type: "text", placeholder: "0.0", - tooltip: "Fixed cost per query", + tooltip: t("agentsPage.agentConfig.costPerQueryTooltip"), }, { name: "input_cost_per_token", - label: "Input Cost Per Token ($)", + label: t("agentsPage.agentConfig.inputCostPerTokenLabel"), type: "text", placeholder: "0.000001", - tooltip: "Cost per input token", + tooltip: t("agentsPage.agentConfig.inputCostPerTokenTooltip"), }, { name: "output_cost_per_token", - label: "Output Cost Per Token ($)", + label: t("agentsPage.agentConfig.outputCostPerTokenLabel"), type: "text", placeholder: "0.000002", - tooltip: "Cost per output token", + tooltip: t("agentsPage.agentConfig.outputCostPerTokenTooltip"), }, ], }, tracing: { key: "tracing", - title: "Tracing", + title: t("agentsPage.agentConfig.tracingTitle"), fields: [ { name: "enable_tracing", - label: "Enable Tracing", + label: t("agentsPage.agentConfig.enableTracingLabel"), type: "switch", defaultValue: false, - tooltip: "Enable request tracing for this agent", + tooltip: t("agentsPage.agentConfig.enableTracingTooltip"), }, ], }, -}; +}); -export const SKILL_FIELD_CONFIG = { +export const getSkillFieldConfig = (t: TFunction) => ({ id: { name: "id", - label: "Skill ID", + label: t("agentsPage.agentConfig.skillIdLabel"), required: true, - placeholder: "e.g., hello_world", + placeholder: t("agentsPage.agentConfig.skillIdPlaceholder"), }, name: { name: "name", - label: "Skill Name", + label: t("agentsPage.agentConfig.skillNameLabel"), required: true, - placeholder: "e.g., Returns hello world", + placeholder: t("agentsPage.agentConfig.skillNamePlaceholder"), }, description: { name: "description", - label: "Description", + label: t("common.description"), required: true, - placeholder: "What this skill does", + placeholder: t("agentsPage.agentConfig.skillDescriptionPlaceholder"), rows: 2, }, tags: { name: "tags", - label: "Tags", + label: t("agentsPage.agentConfig.skillTagsLabel"), required: true, - placeholder: "Type a tag and press Enter", + placeholder: t("agentsPage.agentConfig.skillTagsPlaceholder"), }, examples: { name: "examples", - label: "Examples", - placeholder: "Type an example and press Enter", + label: t("agentsPage.agentConfig.skillExamplesLabel"), + placeholder: t("agentsPage.agentConfig.skillExamplesPlaceholder"), }, -}; +}); /** * Get default form values from configuration */ -export const getDefaultFormValues = () => { - const defaults: any = { - defaultInputModes: ["text"], - defaultOutputModes: ["text"], - }; - - Object.values(AGENT_FORM_CONFIG).forEach((section) => { - section.fields.forEach((field) => { - if (field.defaultValue !== undefined) { - defaults[field.name] = field.defaultValue; - } - }); - }); - - return defaults; -}; +export const getDefaultFormValues = () => ({ + defaultInputModes: ["text"], + defaultOutputModes: ["text"], + version: "1.0.0", + protocolVersion: "1.0", + streaming: false, + skills: [], + enable_tracing: false, +}); /** * Build agent data from form values according to AgentConfig spec diff --git a/ui/litellm-dashboard/src/components/agents/agent_cost_view.tsx b/ui/litellm-dashboard/src/components/agents/agent_cost_view.tsx index 04837fe823f..253f7de779c 100644 --- a/ui/litellm-dashboard/src/components/agents/agent_cost_view.tsx +++ b/ui/litellm-dashboard/src/components/agents/agent_cost_view.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useTranslation } from "react-i18next"; import { Title } from "@tremor/react"; import { Descriptions } from "antd"; import { Agent } from "./types"; @@ -8,6 +9,7 @@ interface AgentCostViewProps { } const AgentCostView: React.FC = ({ agent }) => { + const { t } = useTranslation(); const params = agent.litellm_params; if ( @@ -20,16 +22,22 @@ const AgentCostView: React.FC = ({ agent }) => { return (
- Cost Configuration + {t("agentsPage.agentCostView.title")} {params.cost_per_query !== undefined && ( - ${params.cost_per_query} + + ${params.cost_per_query} + )} {params.input_cost_per_token !== undefined && ( - ${params.input_cost_per_token} + + ${params.input_cost_per_token} + )} {params.output_cost_per_token !== undefined && ( - ${params.output_cost_per_token} + + ${params.output_cost_per_token} + )}
diff --git a/ui/litellm-dashboard/src/components/agents/agent_form_fields.tsx b/ui/litellm-dashboard/src/components/agents/agent_form_fields.tsx index 7965af6322d..1278ef72e38 100644 --- a/ui/litellm-dashboard/src/components/agents/agent_form_fields.tsx +++ b/ui/litellm-dashboard/src/components/agents/agent_form_fields.tsx @@ -1,8 +1,9 @@ -import React from "react"; +import React, { useMemo } from "react"; +import { useTranslation } from "react-i18next"; import { Form, Input, Switch, Collapse, Select, Space, Tooltip } from "antd"; import { Button as AntButton } from "antd"; import { PlusOutlined, MinusCircleOutlined, InfoCircleOutlined } from "@ant-design/icons"; -import { AGENT_FORM_CONFIG, SKILL_FIELD_CONFIG } from "./agent_config"; +import { getAgentFormConfig, getSkillFieldConfig } from "./agent_config"; import CostConfigFields from "./cost_config_fields"; @@ -13,29 +14,32 @@ interface AgentFormFieldsProps { visiblePanels?: string[]; } -/** - * Reusable form fields component for agent forms - * Uses shared configuration from agent_config.ts - */ const AgentFormFields: React.FC = ({ showAgentName = true, visiblePanels }) => { + const { t } = useTranslation(); + const AGENT_FORM_CONFIG = useMemo(() => getAgentFormConfig(t), [t]); + const SKILL_FIELD_CONFIG = useMemo(() => getSkillFieldConfig(t), [t]); + const shouldShow = (key: string) => !visiblePanels || visiblePanels.includes(key); return ( <> {showAgentName && ( - + )} {/* Basic Information */} {shouldShow(AGENT_FORM_CONFIG.basic.key) && ( - + {AGENT_FORM_CONFIG.basic.fields.map((field) => ( = ({ showAgentName = true, name={field.name} rules={ field.required - ? [{ required: true, message: `Please enter ${field.label.toLowerCase()}` }] + ? [ + { + required: true, + message: t("agentsPage.agentFormFields.pleaseEnterField", { + field: field.label.toLowerCase(), + }), + }, + ] : undefined } tooltip={field.tooltip} @@ -60,7 +71,7 @@ const AgentFormFields: React.FC = ({ showAgentName = true, {/* Skills */} {shouldShow(AGENT_FORM_CONFIG.skills.key) && ( - + {(fields, { add, remove }) => ( <> @@ -73,7 +84,7 @@ const AgentFormFields: React.FC = ({ showAgentName = true, {...field} label={SKILL_FIELD_CONFIG.id.label} name={[field.name, "id"]} - rules={[{ required: SKILL_FIELD_CONFIG.id.required, message: "Required" }]} + rules={[{ required: SKILL_FIELD_CONFIG.id.required, message: t("common.required") }]} > @@ -82,7 +93,7 @@ const AgentFormFields: React.FC = ({ showAgentName = true, {...field} label={SKILL_FIELD_CONFIG.name.label} name={[field.name, "name"]} - rules={[{ required: SKILL_FIELD_CONFIG.name.required, message: "Required" }]} + rules={[{ required: SKILL_FIELD_CONFIG.name.required, message: t("common.required") }]} > @@ -91,7 +102,7 @@ const AgentFormFields: React.FC = ({ showAgentName = true, {...field} label={SKILL_FIELD_CONFIG.description.label} name={[field.name, "description"]} - rules={[{ required: SKILL_FIELD_CONFIG.description.required, message: "Required" }]} + rules={[{ required: SKILL_FIELD_CONFIG.description.required, message: t("common.required") }]} > = ({ showAgentName = true, {...field} label={SKILL_FIELD_CONFIG.tags.label} name={[field.name, "tags"]} - rules={[{ required: SKILL_FIELD_CONFIG.tags.required, message: "Required" }]} + rules={[{ required: SKILL_FIELD_CONFIG.tags.required, message: t("common.required") }]} > + - + remove(name)} style={{ color: "#ff4d4f" }} /> ))} add()} icon={} style={{ width: "100%" }}> - Add Static Header + {t("agentsPage.agentFormFields.addStaticHeader")} )} @@ -234,8 +251,8 @@ const AgentFormFields: React.FC = ({ showAgentName = true, - Forward Client Headers{" "} - + {t("agentsPage.agentFormFields.forwardClientHeadersLabel")}{" "} + @@ -245,7 +262,7 @@ const AgentFormFields: React.FC = ({ showAgentName = true, @@ -369,21 +401,21 @@ const AgentInfoView: React.FC = ({ agentId, onClose, accessT )} - Rate Limits + {t("agentsPage.agentInfo.rateLimitsTitle")}
- - + + - - + +
- - + + - - + +
@@ -395,13 +427,13 @@ const AgentInfoView: React.FC = ({ agentId, onClose, accessT fetchAgentInfo(); }} > - Cancel + {t("common.cancel")} - Save Changes + {t("agentsPage.agentInfo.saveChanges")}
) : ( - Click "Edit Settings" to modify agent configuration. + {t("agentsPage.agentInfo.editSettingsHint")} )} diff --git a/ui/litellm-dashboard/src/components/agents/cost_config_fields.tsx b/ui/litellm-dashboard/src/components/agents/cost_config_fields.tsx index 6f31aac6530..00bf6d0aa2b 100644 --- a/ui/litellm-dashboard/src/components/agents/cost_config_fields.tsx +++ b/ui/litellm-dashboard/src/components/agents/cost_config_fields.tsx @@ -1,11 +1,13 @@ import React from "react"; import { Form, Input } from "antd"; -import { AGENT_FORM_CONFIG } from "./agent_config"; +import { useTranslation } from "react-i18next"; +import { getAgentFormConfig } from "./agent_config"; const CostConfigFields: React.FC = () => { + const { t } = useTranslation(); return ( <> - {AGENT_FORM_CONFIG.cost.fields.map((field) => ( + {getAgentFormConfig(t).cost.fields.map((field) => ( diff --git a/ui/litellm-dashboard/src/components/agents/dynamic_agent_form_fields.tsx b/ui/litellm-dashboard/src/components/agents/dynamic_agent_form_fields.tsx index 3edea4362c9..df9430f89e6 100644 --- a/ui/litellm-dashboard/src/components/agents/dynamic_agent_form_fields.tsx +++ b/ui/litellm-dashboard/src/components/agents/dynamic_agent_form_fields.tsx @@ -1,7 +1,8 @@ import React from "react"; import { Form, Input, Select, Collapse } from "antd"; +import { useTranslation } from "react-i18next"; import { AgentCreateInfo, AgentCredentialFieldMetadata } from "../networking"; -import { AGENT_FORM_CONFIG } from "./agent_config"; +import { getAgentFormConfig } from "./agent_config"; import CostConfigFields from "./cost_config_fields"; const { Panel } = Collapse; @@ -16,6 +17,7 @@ interface DynamicAgentFormFieldsProps { * credential fields defined by the agent type metadata. */ const DynamicAgentFormFields: React.FC = ({ agentTypeInfo }) => { + const { t } = useTranslation(); return ( <> = ({ agentTy ))} - + diff --git a/ui/litellm-dashboard/src/locales/en.json b/ui/litellm-dashboard/src/locales/en.json index bf20de6a462..2a5203992a5 100644 --- a/ui/litellm-dashboard/src/locales/en.json +++ b/ui/litellm-dashboard/src/locales/en.json @@ -6033,6 +6033,144 @@ "noKeyAssigned": "No key assigned", "statusActive": "Active", "statusNeedsSetup": "Needs Setup" + }, + "agentConfig": { + "basicTitle": "Basic Information", + "displayNameLabel": "Display Name", + "displayNamePlaceholder": "e.g., Customer Support Agent", + "descriptionPlaceholder": "Describe what this agent does...", + "urlLabel": "URL", + "urlPlaceholder": "http://localhost:9999/", + "urlTooltip": "Base URL where the agent is hosted (optional)", + "versionLabel": "Version", + "protocolVersionLabel": "Protocol Version", + "skillsTitle": "Skills", + "capabilitiesTitle": "Capabilities", + "streamingLabel": "Streaming", + "pushNotificationsLabel": "Push Notifications", + "stateTransitionHistoryLabel": "State Transition History", + "optionalTitle": "Optional Settings", + "iconUrlLabel": "Icon URL", + "documentationUrlLabel": "Documentation URL", + "supportsAuthCardLabel": "Supports Authenticated Extended Card", + "litellmTitle": "LiteLLM Parameters", + "modelOptionalLabel": "Model (Optional)", + "makePublicLabel": "Make Public", + "costTitle": "Cost Configuration", + "costPerQueryLabel": "Cost Per Query ($)", + "costPerQueryTooltip": "Fixed cost per query", + "inputCostPerTokenLabel": "Input Cost Per Token ($)", + "inputCostPerTokenTooltip": "Cost per input token", + "outputCostPerTokenLabel": "Output Cost Per Token ($)", + "outputCostPerTokenTooltip": "Cost per output token", + "tracingTitle": "Tracing", + "enableTracingLabel": "Enable Tracing", + "enableTracingTooltip": "Enable request tracing for this agent", + "skillIdLabel": "Skill ID", + "skillIdPlaceholder": "e.g., hello_world", + "skillNameLabel": "Skill Name", + "skillNamePlaceholder": "e.g., Returns hello world", + "skillDescriptionPlaceholder": "What this skill does", + "skillTagsLabel": "Tags", + "skillTagsPlaceholder": "Type a tag and press Enter", + "skillExamplesLabel": "Examples", + "skillExamplesPlaceholder": "Type an example and press Enter" + }, + "agentFormFields": { + "agentNameLabel": "Agent Name", + "agentNameRequired": "Please enter a unique agent name", + "agentNameTooltip": "Unique identifier for the agent", + "agentNamePlaceholder": "e.g., customer-support-agent", + "pleaseEnterField": "Please enter {{field}}", + "removeSkill": "Remove Skill", + "addSkill": "Add Skill", + "authHeadersTitle": "Authentication Headers", + "staticHeadersLabel": "Static Headers", + "staticHeadersTooltip": "Headers always sent to the backend agent, regardless of the client request. Admin-configured, static wins on conflict.", + "headerNameRequired": "Header name required", + "headerNamePlaceholder": "Header name (e.g. Authorization)", + "headerValueRequired": "Value required", + "headerValuePlaceholder": "Value (e.g. Bearer token123)", + "addStaticHeader": "Add Static Header", + "forwardClientHeadersLabel": "Forward Client Headers", + "forwardClientHeadersTooltip": "Header names to extract from the client's request and forward to the agent. Type a name and press Enter.", + "forwardClientHeadersPlaceholder": "e.g. x-api-key, Authorization" + }, + "agentCostView": { + "title": "Cost Configuration", + "costPerQuery": "Cost Per Query", + "inputCostPerToken": "Input Cost Per Token", + "outputCostPerToken": "Output Cost Per Token" + }, + "agentCardDiscovery": { + "noAccessToken": "No access token available", + "fillConnectionDetails": "Fill in the agent's connection details above first", + "enterBaseUrl": "Enter the agent's base URL first", + "failedToDiscover": "Failed to discover agent card", + "discoverFromUrl": "Discover from agent URL", + "discoverTooltip": "LiteLLM will fetch /.well-known/agent-card.json from this URL and let you pick which skills and capabilities to expose through the proxy.", + "usingConnectionDetails": "Using the connection details you entered above. We'll fetch:", + "fillFieldsAbove": "Fill in the fields above first", + "rediscover": "Re-discover", + "discover": "Discover", + "pasteUrlHint": "Paste the upstream agent's base URL. We'll try /.well-known/agent-card.json, /.well-known/agent.json, and /agent.json in order.", + "discoveryFailed": "Discovery failed", + "upstreamCardLoaded": "Upstream card loaded", + "nameLabel": "Name (shown to API clients)", + "namePlaceholder": "Agent name", + "descriptionPlaceholder": "What this agent does", + "skillsTitle": "Skills", + "skillsSelected": "{{selected}} / {{total}} selected", + "noSkills": "Upstream card has no skills", + "more": "more", + "capabilitiesTitle": "Capabilities", + "capabilitiesTooltip": "Only capabilities LiteLLM can faithfully proxy today are listed. Others (push notifications, extensions) are coming soon.", + "notAdvertisedUpstream": "not advertised upstream" + }, + "agentInfo": { + "failedToLoad": "Failed to load agent information", + "updateSuccess": "Agent updated successfully", + "updateFailed": "Failed to update agent", + "agentNotFound": "Agent not found", + "backToList": "Back to Agents List", + "backToAgents": "Back to Agents", + "unnamedAgent": "Unnamed Agent", + "overviewTab": "Overview", + "settingsTab": "Settings", + "agentIdLabel": "Agent ID", + "agentNameLabel": "Agent Name", + "displayNameLabel": "Display Name", + "urlLabel": "URL", + "versionLabel": "Version", + "protocolVersionLabel": "Protocol Version", + "streamingLabel": "Streaming", + "pushNotificationsLabel": "Push Notifications", + "stateTransitionHistoryLabel": "State Transition History", + "skillsLabel": "Skills", + "skillsConfigured": "{{count}} configured", + "modelLabel": "Model", + "makePublicLabel": "Make Public", + "iconUrlLabel": "Icon URL", + "documentationUrlLabel": "Documentation URL", + "tpmLimitLabel": "TPM Limit", + "rpmLimitLabel": "RPM Limit", + "sessionTpmLimitLabel": "Session TPM Limit", + "sessionRpmLimitLabel": "Session RPM Limit", + "unlimited": "Unlimited", + "mcpToolPermissionsTitle": "MCP Tool Permissions", + "mcpServersLabel": "MCP Servers", + "mcpAccessGroupsLabel": "MCP Access Groups", + "toolPermissionsPerServerLabel": "Tool permissions per server", + "skillsSectionTitle": "Skills", + "skillFallbackLabel": "Skill {{index}}", + "skillIdField": "ID", + "skillTagsField": "Tags", + "skillExamplesField": "Examples", + "agentSettingsTitle": "Agent Settings", + "editSettings": "Edit Settings", + "editSettingsHint": "Click \"Edit Settings\" to modify agent configuration.", + "rateLimitsTitle": "Rate Limits", + "saveChanges": "Save Changes" } } } diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json index b68cac4b86c..c210de32d64 100644 --- a/ui/litellm-dashboard/src/locales/zh-CN.json +++ b/ui/litellm-dashboard/src/locales/zh-CN.json @@ -6033,6 +6033,144 @@ "noKeyAssigned": "未分配密钥", "statusActive": "活跃", "statusNeedsSetup": "待配置" + }, + "agentConfig": { + "basicTitle": "基本信息", + "displayNameLabel": "显示名称", + "displayNamePlaceholder": "例如:客服 Agent", + "descriptionPlaceholder": "描述此 Agent 的功能...", + "urlLabel": "URL", + "urlPlaceholder": "http://localhost:9999/", + "urlTooltip": "Agent 所在的基础 URL(可选)", + "versionLabel": "版本", + "protocolVersionLabel": "协议版本", + "skillsTitle": "工具", + "capabilitiesTitle": "能力", + "streamingLabel": "流式输出", + "pushNotificationsLabel": "推送通知", + "stateTransitionHistoryLabel": "状态转换历史", + "optionalTitle": "可选设置", + "iconUrlLabel": "图标 URL", + "documentationUrlLabel": "文档 URL", + "supportsAuthCardLabel": "支持认证扩展卡片", + "litellmTitle": "LiteLLM 参数", + "modelOptionalLabel": "模型(可选)", + "makePublicLabel": "公开", + "costTitle": "花费配置", + "costPerQueryLabel": "每次查询花费($)", + "costPerQueryTooltip": "每次查询的固定花费", + "inputCostPerTokenLabel": "输入 Token 花费($)", + "inputCostPerTokenTooltip": "每个输入 Token 的花费", + "outputCostPerTokenLabel": "输出 Token 花费($)", + "outputCostPerTokenTooltip": "每个输出 Token 的花费", + "tracingTitle": "追踪", + "enableTracingLabel": "启用追踪", + "enableTracingTooltip": "为此 Agent 启用请求追踪", + "skillIdLabel": "工具 ID", + "skillIdPlaceholder": "例如:hello_world", + "skillNameLabel": "工具名称", + "skillNamePlaceholder": "例如:返回 hello world", + "skillDescriptionPlaceholder": "此工具的功能", + "skillTagsLabel": "标签", + "skillTagsPlaceholder": "输入标签后按 Enter", + "skillExamplesLabel": "示例", + "skillExamplesPlaceholder": "输入示例后按 Enter" + }, + "agentFormFields": { + "agentNameLabel": "Agent 名称", + "agentNameRequired": "请输入唯一的 Agent 名称", + "agentNameTooltip": "Agent 的唯一标识符", + "agentNamePlaceholder": "例如:customer-support-agent", + "pleaseEnterField": "请输入{{field}}", + "removeSkill": "移除工具", + "addSkill": "添加工具", + "authHeadersTitle": "认证请求头", + "staticHeadersLabel": "静态请求头", + "staticHeadersTooltip": "始终发送给后端 Agent 的请求头,与客户端请求无关。管理员配置,冲突时静态配置优先。", + "headerNameRequired": "请求头名称不能为空", + "headerNamePlaceholder": "请求头名称(例如 Authorization)", + "headerValueRequired": "值不能为空", + "headerValuePlaceholder": "值(例如 Bearer token123)", + "addStaticHeader": "添加静态请求头", + "forwardClientHeadersLabel": "转发客户端请求头", + "forwardClientHeadersTooltip": "从客户端请求中提取并转发给 Agent 的请求头名称。输入名称后按 Enter。", + "forwardClientHeadersPlaceholder": "例如:x-api-key、Authorization" + }, + "agentCostView": { + "title": "花费配置", + "costPerQuery": "每次查询花费", + "inputCostPerToken": "输入 Token 花费", + "outputCostPerToken": "输出 Token 花费" + }, + "agentCardDiscovery": { + "noAccessToken": "无可用访问令牌", + "fillConnectionDetails": "请先填写上方的 Agent 连接详情", + "enterBaseUrl": "请先输入 Agent 的基础 URL", + "failedToDiscover": "发现 Agent 卡片失败", + "discoverFromUrl": "从 Agent URL 发现", + "discoverTooltip": "LiteLLM 将从此 URL 获取 /.well-known/agent-card.json,并让您选择通过代理开放的工具和能力。", + "usingConnectionDetails": "使用上方填写的连接详情,将获取:", + "fillFieldsAbove": "请先填写上方字段", + "rediscover": "重新发现", + "discover": "发现", + "pasteUrlHint": "粘贴上游 Agent 的基础 URL,将依次尝试 /.well-known/agent-card.json、/.well-known/agent.json 和 /agent.json。", + "discoveryFailed": "发现失败", + "upstreamCardLoaded": "已加载上游卡片", + "nameLabel": "名称(对 API 客户端显示)", + "namePlaceholder": "Agent 名称", + "descriptionPlaceholder": "此 Agent 的功能", + "skillsTitle": "工具", + "skillsSelected": "{{selected}} / {{total}} 已选", + "noSkills": "上游卡片无工具", + "more": "展开", + "capabilitiesTitle": "能力", + "capabilitiesTooltip": "仅列出 LiteLLM 当前可以忠实代理的能力,其他能力(推送通知、扩展)即将推出。", + "notAdvertisedUpstream": "上游未声明" + }, + "agentInfo": { + "failedToLoad": "加载 Agent 信息失败", + "updateSuccess": "Agent 更新成功", + "updateFailed": "更新 Agent 失败", + "agentNotFound": "未找到 Agent", + "backToList": "返回 Agent 列表", + "backToAgents": "返回 Agent 列表", + "unnamedAgent": "未命名 Agent", + "overviewTab": "概览", + "settingsTab": "设置", + "agentIdLabel": "Agent ID", + "agentNameLabel": "Agent 名称", + "displayNameLabel": "显示名称", + "urlLabel": "URL", + "versionLabel": "版本", + "protocolVersionLabel": "协议版本", + "streamingLabel": "流式输出", + "pushNotificationsLabel": "推送通知", + "stateTransitionHistoryLabel": "状态转换历史", + "skillsLabel": "工具", + "skillsConfigured": "已配置 {{count}} 个", + "modelLabel": "模型", + "makePublicLabel": "公开", + "iconUrlLabel": "图标 URL", + "documentationUrlLabel": "文档 URL", + "tpmLimitLabel": "TPM 限制", + "rpmLimitLabel": "RPM 限制", + "sessionTpmLimitLabel": "会话 TPM 限制", + "sessionRpmLimitLabel": "会话 RPM 限制", + "unlimited": "无限制", + "mcpToolPermissionsTitle": "MCP 工具权限", + "mcpServersLabel": "MCP 服务器", + "mcpAccessGroupsLabel": "MCP 访问组", + "toolPermissionsPerServerLabel": "每服务器工具权限", + "skillsSectionTitle": "工具", + "skillFallbackLabel": "工具 {{index}}", + "skillIdField": "ID", + "skillTagsField": "标签", + "skillExamplesField": "示例", + "agentSettingsTitle": "Agent 设置", + "editSettings": "编辑设置", + "editSettingsHint": "点击「编辑设置」修改 Agent 配置。", + "rateLimitsTitle": "速率限制", + "saveChanges": "保存更改" } } }