mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): i18n for agents config and info views
This commit is contained in:
parent
a65632e342
commit
268b34774c
9 changed files with 530 additions and 185 deletions
|
|
@ -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<AgentCardDiscoveryProps> = ({
|
|||
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<AgentCardDiscoveryProps> = ({
|
|||
|
||||
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<AgentCardDiscoveryProps> = ({
|
|||
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<AgentCardDiscoveryProps> = ({
|
|||
// 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<AgentCardDiscoveryProps> = ({
|
|||
<div className="border border-gray-200 rounded-lg p-4 bg-gray-50 mb-4">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<LinkOutlined className="text-indigo-600" />
|
||||
<Text strong>Discover from agent URL</Text>
|
||||
<Tooltip title="LiteLLM will fetch /.well-known/agent-card.json from this URL and let you pick which skills and capabilities to expose through the proxy.">
|
||||
<Text strong>{t("agentsPage.agentCardDiscovery.discoverFromUrl")}</Text>
|
||||
<Tooltip title={t("agentsPage.agentCardDiscovery.discoverTooltip")}>
|
||||
<InfoCircleOutlined className="text-gray-400" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
{isParentDriven ? (
|
||||
<>
|
||||
<Paragraph className="text-xs text-gray-500 mb-2">
|
||||
Using the connection details you entered above. We'll fetch:
|
||||
{t("agentsPage.agentCardDiscovery.usingConnectionDetails")}
|
||||
</Paragraph>
|
||||
<div className="bg-white border border-gray-200 rounded px-3 py-2 mb-3 font-mono text-xs text-gray-700 break-all">
|
||||
{discoveryRequest!.display_url || effectiveUrl || (
|
||||
<span className="text-gray-400 italic">Fill in the fields above first</span>
|
||||
<span className="text-gray-400 italic">{t("agentsPage.agentCardDiscovery.fillFieldsAbove")}</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
|
|
@ -262,15 +266,14 @@ const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
|||
onClick={handleDiscover}
|
||||
disabled={!effectiveUrl.trim()}
|
||||
>
|
||||
{card ? "Re-discover" : "Discover"}
|
||||
{card ? t("agentsPage.agentCardDiscovery.rediscover") : t("agentsPage.agentCardDiscovery.discover")}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Paragraph className="text-xs text-gray-500 mb-3">
|
||||
Paste the upstream agent's base URL. We'll try <code>/.well-known/agent-card.json</code>,{" "}
|
||||
<code>/.well-known/agent.json</code>, and <code>/agent.json</code> in order.
|
||||
{t("agentsPage.agentCardDiscovery.pasteUrlHint")}
|
||||
</Paragraph>
|
||||
|
||||
<Space.Compact style={{ width: "100%" }}>
|
||||
|
|
@ -288,7 +291,7 @@ const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
|||
loading={loading}
|
||||
onClick={handleDiscover}
|
||||
>
|
||||
{card ? "Re-discover" : "Discover"}
|
||||
{card ? t("agentsPage.agentCardDiscovery.rediscover") : t("agentsPage.agentCardDiscovery.discover")}
|
||||
</Button>
|
||||
</Space.Compact>
|
||||
</>
|
||||
|
|
@ -298,7 +301,7 @@ const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
|||
<Alert
|
||||
className="mt-3"
|
||||
type="error"
|
||||
message="Discovery failed"
|
||||
message={t("agentsPage.agentCardDiscovery.discoveryFailed")}
|
||||
description={error}
|
||||
showIcon
|
||||
closable
|
||||
|
|
@ -317,7 +320,7 @@ const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
|||
<div className="flex items-center justify-between mb-3">
|
||||
<Space>
|
||||
<CheckCircleTwoTone twoToneColor="#52c41a" />
|
||||
<Text strong>Upstream card loaded</Text>
|
||||
<Text strong>{t("agentsPage.agentCardDiscovery.upstreamCardLoaded")}</Text>
|
||||
{card.version && <Tag color="blue">v{card.version}</Tag>}
|
||||
{card.provider?.organization && <Tag color="purple">{card.provider.organization}</Tag>}
|
||||
</Space>
|
||||
|
|
@ -325,16 +328,22 @@ const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
|||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
||||
<div>
|
||||
<label className="text-xs font-medium text-gray-600 block mb-1">Name (shown to API clients)</label>
|
||||
<Input value={editedName} onChange={(e) => setEditedName(e.target.value)} placeholder="Agent name" />
|
||||
<label className="text-xs font-medium text-gray-600 block mb-1">
|
||||
{t("agentsPage.agentCardDiscovery.nameLabel")}
|
||||
</label>
|
||||
<Input
|
||||
value={editedName}
|
||||
onChange={(e) => setEditedName(e.target.value)}
|
||||
placeholder={t("agentsPage.agentCardDiscovery.namePlaceholder")}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-medium text-gray-600 block mb-1">Description</label>
|
||||
<label className="text-xs font-medium text-gray-600 block mb-1">{t("common.description")}</label>
|
||||
<Input.TextArea
|
||||
value={editedDescription}
|
||||
onChange={(e) => setEditedDescription(e.target.value)}
|
||||
rows={2}
|
||||
placeholder="What this agent does"
|
||||
placeholder={t("agentsPage.agentCardDiscovery.descriptionPlaceholder")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -344,15 +353,18 @@ const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
|||
key="skills"
|
||||
header={
|
||||
<Space>
|
||||
<Text strong>Skills</Text>
|
||||
<Text strong>{t("agentsPage.agentCardDiscovery.skillsTitle")}</Text>
|
||||
<Tag>
|
||||
{selectedSkillCount} / {skillCount} selected
|
||||
{t("agentsPage.agentCardDiscovery.skillsSelected", {
|
||||
selected: selectedSkillCount,
|
||||
total: skillCount,
|
||||
})}
|
||||
</Tag>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
{skillCount === 0 ? (
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="Upstream card has no skills" />
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t("agentsPage.agentCardDiscovery.noSkills")} />
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{(card.skills ?? []).map((skill, idx) => {
|
||||
|
|
@ -379,7 +391,7 @@ const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
|||
{skill.description && (
|
||||
<Paragraph
|
||||
className="text-xs text-gray-500 mt-1 mb-0"
|
||||
ellipsis={{ rows: 2, expandable: true, symbol: "more" }}
|
||||
ellipsis={{ rows: 2, expandable: true, symbol: t("agentsPage.agentCardDiscovery.more") }}
|
||||
>
|
||||
{skill.description}
|
||||
</Paragraph>
|
||||
|
|
@ -396,8 +408,8 @@ const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
|||
key="capabilities"
|
||||
header={
|
||||
<Space>
|
||||
<Text strong>Capabilities</Text>
|
||||
<Tooltip title="Only capabilities LiteLLM can faithfully proxy today are listed. Others (push notifications, extensions) are coming soon.">
|
||||
<Text strong>{t("agentsPage.agentCardDiscovery.capabilitiesTitle")}</Text>
|
||||
<Tooltip title={t("agentsPage.agentCardDiscovery.capabilitiesTooltip")}>
|
||||
<InfoCircleOutlined className="text-gray-400" />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
|
|
@ -417,7 +429,7 @@ const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
|||
</Text>
|
||||
{!upstreamHas && (
|
||||
<Tag className="ml-2" color="default">
|
||||
not advertised upstream
|
||||
{t("agentsPage.agentCardDiscovery.notAdvertisedUpstream")}
|
||||
</Tag>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<AgentCostViewProps> = ({ agent }) => {
|
||||
const { t } = useTranslation();
|
||||
const params = agent.litellm_params;
|
||||
|
||||
if (
|
||||
|
|
@ -20,16 +22,22 @@ const AgentCostView: React.FC<AgentCostViewProps> = ({ agent }) => {
|
|||
|
||||
return (
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<Title>Cost Configuration</Title>
|
||||
<Title>{t("agentsPage.agentCostView.title")}</Title>
|
||||
<Descriptions bordered column={1} style={{ marginTop: 16 }}>
|
||||
{params.cost_per_query !== undefined && (
|
||||
<Descriptions.Item label="Cost Per Query">${params.cost_per_query}</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentCostView.costPerQuery")}>
|
||||
${params.cost_per_query}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{params.input_cost_per_token !== undefined && (
|
||||
<Descriptions.Item label="Input Cost Per Token">${params.input_cost_per_token}</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentCostView.inputCostPerToken")}>
|
||||
${params.input_cost_per_token}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{params.output_cost_per_token !== undefined && (
|
||||
<Descriptions.Item label="Output Cost Per Token">${params.output_cost_per_token}</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentCostView.outputCostPerToken")}>
|
||||
${params.output_cost_per_token}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
</Descriptions>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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<AgentFormFieldsProps> = ({ 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 && (
|
||||
<Form.Item
|
||||
label="Agent Name"
|
||||
label={t("agentsPage.agentFormFields.agentNameLabel")}
|
||||
name="agent_name"
|
||||
rules={[{ required: true, message: "Please enter a unique agent name" }]}
|
||||
tooltip="Unique identifier for the agent"
|
||||
rules={[{ required: true, message: t("agentsPage.agentFormFields.agentNameRequired") }]}
|
||||
tooltip={t("agentsPage.agentFormFields.agentNameTooltip")}
|
||||
>
|
||||
<Input placeholder="e.g., customer-support-agent" />
|
||||
<Input placeholder={t("agentsPage.agentFormFields.agentNamePlaceholder")} />
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
<Collapse defaultActiveKey={["basic"]} style={{ marginBottom: 16 }}>
|
||||
{/* Basic Information */}
|
||||
{shouldShow(AGENT_FORM_CONFIG.basic.key) && (
|
||||
<Panel header={`${AGENT_FORM_CONFIG.basic.title} (Required)`} key={AGENT_FORM_CONFIG.basic.key}>
|
||||
<Panel
|
||||
header={`${AGENT_FORM_CONFIG.basic.title} (${t("common.required")})`}
|
||||
key={AGENT_FORM_CONFIG.basic.key}
|
||||
>
|
||||
{AGENT_FORM_CONFIG.basic.fields.map((field) => (
|
||||
<Form.Item
|
||||
key={field.name}
|
||||
|
|
@ -43,7 +47,14 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ 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<AgentFormFieldsProps> = ({ showAgentName = true,
|
|||
|
||||
{/* Skills */}
|
||||
{shouldShow(AGENT_FORM_CONFIG.skills.key) && (
|
||||
<Panel header={`${AGENT_FORM_CONFIG.skills.title}`} key={AGENT_FORM_CONFIG.skills.key}>
|
||||
<Panel header={AGENT_FORM_CONFIG.skills.title} key={AGENT_FORM_CONFIG.skills.key}>
|
||||
<Form.List name="skills">
|
||||
{(fields, { add, remove }) => (
|
||||
<>
|
||||
|
|
@ -73,7 +84,7 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ 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") }]}
|
||||
>
|
||||
<Input placeholder={SKILL_FIELD_CONFIG.id.placeholder} />
|
||||
</Form.Item>
|
||||
|
|
@ -82,7 +93,7 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ 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") }]}
|
||||
>
|
||||
<Input placeholder={SKILL_FIELD_CONFIG.name.placeholder} />
|
||||
</Form.Item>
|
||||
|
|
@ -91,7 +102,7 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ 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") }]}
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={SKILL_FIELD_CONFIG.description.rows}
|
||||
|
|
@ -103,7 +114,7 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ 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") }]}
|
||||
>
|
||||
<Select
|
||||
mode="tags"
|
||||
|
|
@ -123,12 +134,12 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ showAgentName = true,
|
|||
</Form.Item>
|
||||
|
||||
<AntButton type="link" danger onClick={() => remove(field.name)} icon={<MinusCircleOutlined />}>
|
||||
Remove Skill
|
||||
{t("agentsPage.agentFormFields.removeSkill")}
|
||||
</AntButton>
|
||||
</div>
|
||||
))}
|
||||
<AntButton type="dashed" onClick={() => add()} icon={<PlusOutlined />} style={{ width: "100%" }}>
|
||||
Add Skill
|
||||
{t("agentsPage.agentFormFields.addSkill")}
|
||||
</AntButton>
|
||||
</>
|
||||
)}
|
||||
|
|
@ -188,13 +199,13 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ showAgentName = true,
|
|||
|
||||
{/* Authentication Headers */}
|
||||
{shouldShow("auth_headers") && (
|
||||
<Panel header="Authentication Headers" key="auth_headers">
|
||||
<Panel header={t("agentsPage.agentFormFields.authHeadersTitle")} key="auth_headers">
|
||||
{/* Static Headers */}
|
||||
<Form.Item
|
||||
label={
|
||||
<span>
|
||||
Static Headers{" "}
|
||||
<Tooltip title="Headers always sent to the backend agent, regardless of the client request. Admin-configured, static wins on conflict.">
|
||||
{t("agentsPage.agentFormFields.staticHeadersLabel")}{" "}
|
||||
<Tooltip title={t("agentsPage.agentFormFields.staticHeadersTooltip")}>
|
||||
<InfoCircleOutlined style={{ color: "#8c8c8c" }} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -208,22 +219,28 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ showAgentName = true,
|
|||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, "header"]}
|
||||
rules={[{ required: true, message: "Header name required" }]}
|
||||
rules={[{ required: true, message: t("agentsPage.agentFormFields.headerNameRequired") }]}
|
||||
>
|
||||
<Input placeholder="Header name (e.g. Authorization)" style={{ width: 220 }} />
|
||||
<Input
|
||||
placeholder={t("agentsPage.agentFormFields.headerNamePlaceholder")}
|
||||
style={{ width: 220 }}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, "value"]}
|
||||
rules={[{ required: true, message: "Value required" }]}
|
||||
rules={[{ required: true, message: t("agentsPage.agentFormFields.headerValueRequired") }]}
|
||||
>
|
||||
<Input placeholder="Value (e.g. Bearer token123)" style={{ width: 260 }} />
|
||||
<Input
|
||||
placeholder={t("agentsPage.agentFormFields.headerValuePlaceholder")}
|
||||
style={{ width: 260 }}
|
||||
/>
|
||||
</Form.Item>
|
||||
<MinusCircleOutlined onClick={() => remove(name)} style={{ color: "#ff4d4f" }} />
|
||||
</Space>
|
||||
))}
|
||||
<AntButton type="dashed" onClick={() => add()} icon={<PlusOutlined />} style={{ width: "100%" }}>
|
||||
Add Static Header
|
||||
{t("agentsPage.agentFormFields.addStaticHeader")}
|
||||
</AntButton>
|
||||
</>
|
||||
)}
|
||||
|
|
@ -234,8 +251,8 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ showAgentName = true,
|
|||
<Form.Item
|
||||
label={
|
||||
<span>
|
||||
Forward Client Headers{" "}
|
||||
<Tooltip title="Header names to extract from the client's request and forward to the agent. Type a name and press Enter.">
|
||||
{t("agentsPage.agentFormFields.forwardClientHeadersLabel")}{" "}
|
||||
<Tooltip title={t("agentsPage.agentFormFields.forwardClientHeadersTooltip")}>
|
||||
<InfoCircleOutlined style={{ color: "#8c8c8c" }} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -245,7 +262,7 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ showAgentName = true,
|
|||
<Select
|
||||
mode="tags"
|
||||
style={{ width: "100%" }}
|
||||
placeholder="e.g. x-api-key, Authorization"
|
||||
placeholder={t("agentsPage.agentFormFields.forwardClientHeadersPlaceholder")}
|
||||
tokenSeparators={[","]}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, Title, Text, Button as TremorButton, Tab, TabGroup, TabList, TabPanel, TabPanels } from "@tremor/react";
|
||||
import { Form, Input, InputNumber, Button as AntButton, Spin, Descriptions, Divider } from "antd";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
|
|
@ -21,6 +22,7 @@ interface AgentInfoViewProps {
|
|||
}
|
||||
|
||||
const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessToken, isAdmin }) => {
|
||||
const { t } = useTranslation();
|
||||
const [agent, setAgent] = useState<Agent | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
|
|
@ -73,7 +75,7 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching agent info:", error);
|
||||
MessageManager.error("Failed to load agent information");
|
||||
MessageManager.error(t("agentsPage.agentInfo.failedToLoad"));
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
@ -153,12 +155,12 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
}
|
||||
|
||||
await patchAgentCall(accessToken, agentId, updateData);
|
||||
MessageManager.success("Agent updated successfully");
|
||||
MessageManager.success(t("agentsPage.agentInfo.updateSuccess"));
|
||||
setIsEditing(false);
|
||||
fetchAgentInfo();
|
||||
} catch (error) {
|
||||
console.error("Error updating agent:", error);
|
||||
MessageManager.error("Failed to update agent");
|
||||
MessageManager.error(t("agentsPage.agentInfo.updateFailed"));
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
|
@ -177,9 +179,9 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
if (!agent) {
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div className="text-center">Agent not found</div>
|
||||
<div className="text-center">{t("agentsPage.agentInfo.agentNotFound")}</div>
|
||||
<TremorButton onClick={onClose} className="mt-4">
|
||||
Back to Agents List
|
||||
{t("agentsPage.agentInfo.backToList")}
|
||||
</TremorButton>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -196,65 +198,91 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
<div className="p-4">
|
||||
<div>
|
||||
<TremorButton icon={ArrowLeftIcon} variant="light" onClick={onClose} className="mb-4">
|
||||
Back to Agents
|
||||
{t("agentsPage.agentInfo.backToAgents")}
|
||||
</TremorButton>
|
||||
<Title>{agent.agent_name || "Unnamed Agent"}</Title>
|
||||
<Title>{agent.agent_name || t("agentsPage.agentInfo.unnamedAgent")}</Title>
|
||||
<Text className="text-gray-500 font-mono">{agent.agent_id}</Text>
|
||||
</div>
|
||||
|
||||
<TabGroup>
|
||||
<TabList className="mb-4">
|
||||
<Tab key="overview">Overview</Tab>
|
||||
{isAdmin ? <Tab key="settings">Settings</Tab> : <></>}
|
||||
<Tab key="overview">{t("agentsPage.agentInfo.overviewTab")}</Tab>
|
||||
{isAdmin ? <Tab key="settings">{t("agentsPage.agentInfo.settingsTab")}</Tab> : <></>}
|
||||
</TabList>
|
||||
|
||||
<TabPanels>
|
||||
{/* Overview Panel */}
|
||||
<TabPanel>
|
||||
<Descriptions bordered column={1}>
|
||||
<Descriptions.Item label="Agent ID">{agent.agent_id}</Descriptions.Item>
|
||||
<Descriptions.Item label="Agent Name">{agent.agent_name}</Descriptions.Item>
|
||||
<Descriptions.Item label="Display Name">{agent.agent_card_params?.name || "-"}</Descriptions.Item>
|
||||
<Descriptions.Item label="Description">{agent.agent_card_params?.description || "-"}</Descriptions.Item>
|
||||
<Descriptions.Item label="URL">{agent.agent_card_params?.url || "-"}</Descriptions.Item>
|
||||
<Descriptions.Item label="Version">{agent.agent_card_params?.version || "-"}</Descriptions.Item>
|
||||
<Descriptions.Item label="Protocol Version">
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.agentIdLabel")}>{agent.agent_id}</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.agentNameLabel")}>{agent.agent_name}</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.displayNameLabel")}>
|
||||
{agent.agent_card_params?.name || "-"}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("common.description")}>
|
||||
{agent.agent_card_params?.description || "-"}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.urlLabel")}>
|
||||
{agent.agent_card_params?.url || "-"}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.versionLabel")}>
|
||||
{agent.agent_card_params?.version || "-"}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.protocolVersionLabel")}>
|
||||
{agent.agent_card_params?.protocolVersion || "-"}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Streaming">
|
||||
{agent.agent_card_params?.capabilities?.streaming ? "Yes" : "No"}
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.streamingLabel")}>
|
||||
{agent.agent_card_params?.capabilities?.streaming ? t("common.yes") : t("common.no")}
|
||||
</Descriptions.Item>
|
||||
{agent.agent_card_params?.capabilities?.pushNotifications && (
|
||||
<Descriptions.Item label="Push Notifications">Yes</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.pushNotificationsLabel")}>
|
||||
{t("common.yes")}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{agent.agent_card_params?.capabilities?.stateTransitionHistory && (
|
||||
<Descriptions.Item label="State Transition History">Yes</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.stateTransitionHistoryLabel")}>
|
||||
{t("common.yes")}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
<Descriptions.Item label="Skills">
|
||||
{agent.agent_card_params?.skills?.length || 0} configured
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.skillsLabel")}>
|
||||
{t("agentsPage.agentInfo.skillsConfigured", {
|
||||
count: agent.agent_card_params?.skills?.length || 0,
|
||||
})}
|
||||
</Descriptions.Item>
|
||||
{agent.litellm_params?.model && (
|
||||
<Descriptions.Item label="Model">{agent.litellm_params.model}</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.modelLabel")}>
|
||||
{agent.litellm_params.model}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{agent.litellm_params?.make_public !== undefined && (
|
||||
<Descriptions.Item label="Make Public">
|
||||
{agent.litellm_params.make_public ? "Yes" : "No"}
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.makePublicLabel")}>
|
||||
{agent.litellm_params.make_public ? t("common.yes") : t("common.no")}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{agent.agent_card_params?.iconUrl && (
|
||||
<Descriptions.Item label="Icon URL">{agent.agent_card_params.iconUrl}</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.iconUrlLabel")}>
|
||||
{agent.agent_card_params.iconUrl}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{agent.agent_card_params?.documentationUrl && (
|
||||
<Descriptions.Item label="Documentation URL">
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.documentationUrlLabel")}>
|
||||
{agent.agent_card_params.documentationUrl}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
<Descriptions.Item label="TPM Limit">{agent.tpm_limit ?? "Unlimited"}</Descriptions.Item>
|
||||
<Descriptions.Item label="RPM Limit">{agent.rpm_limit ?? "Unlimited"}</Descriptions.Item>
|
||||
<Descriptions.Item label="Session TPM Limit">{agent.session_tpm_limit ?? "Unlimited"}</Descriptions.Item>
|
||||
<Descriptions.Item label="Session RPM Limit">{agent.session_rpm_limit ?? "Unlimited"}</Descriptions.Item>
|
||||
<Descriptions.Item label="Created At">{formatDate(agent.created_at)}</Descriptions.Item>
|
||||
<Descriptions.Item label="Updated At">{formatDate(agent.updated_at)}</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.tpmLimitLabel")}>
|
||||
{agent.tpm_limit ?? t("agentsPage.agentInfo.unlimited")}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.rpmLimitLabel")}>
|
||||
{agent.rpm_limit ?? t("agentsPage.agentInfo.unlimited")}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.sessionTpmLimitLabel")}>
|
||||
{agent.session_tpm_limit ?? t("agentsPage.agentInfo.unlimited")}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.sessionRpmLimitLabel")}>
|
||||
{agent.session_rpm_limit ?? t("agentsPage.agentInfo.unlimited")}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("common.createdAt")}>{formatDate(agent.created_at)}</Descriptions.Item>
|
||||
<Descriptions.Item label={t("common.updatedAt")}>{formatDate(agent.updated_at)}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{agent.object_permission &&
|
||||
|
|
@ -263,22 +291,22 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
(agent.object_permission.mcp_tool_permissions &&
|
||||
Object.keys(agent.object_permission.mcp_tool_permissions).length > 0)) && (
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<Title>MCP Tool Permissions</Title>
|
||||
<Title>{t("agentsPage.agentInfo.mcpToolPermissionsTitle")}</Title>
|
||||
<Descriptions bordered column={1} style={{ marginTop: 16 }}>
|
||||
{agent.object_permission.mcp_servers && agent.object_permission.mcp_servers.length > 0 && (
|
||||
<Descriptions.Item label="MCP Servers">
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.mcpServersLabel")}>
|
||||
{agent.object_permission.mcp_servers.join(", ")}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{agent.object_permission.mcp_access_groups &&
|
||||
agent.object_permission.mcp_access_groups.length > 0 && (
|
||||
<Descriptions.Item label="MCP Access Groups">
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.mcpAccessGroupsLabel")}>
|
||||
{agent.object_permission.mcp_access_groups.join(", ")}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{agent.object_permission.mcp_tool_permissions &&
|
||||
Object.keys(agent.object_permission.mcp_tool_permissions).length > 0 && (
|
||||
<Descriptions.Item label="Tool permissions per server">
|
||||
<Descriptions.Item label={t("agentsPage.agentInfo.toolPermissionsPerServerLabel")}>
|
||||
<div className="space-y-1">
|
||||
{Object.entries(agent.object_permission.mcp_tool_permissions).map(([serverId, tools]) => (
|
||||
<div key={serverId}>
|
||||
|
|
@ -297,23 +325,27 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
|
||||
{agent.agent_card_params?.skills && agent.agent_card_params.skills.length > 0 && (
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<Title>Skills</Title>
|
||||
<Title>{t("agentsPage.agentInfo.skillsSectionTitle")}</Title>
|
||||
<Descriptions bordered column={1} style={{ marginTop: 16 }}>
|
||||
{agent.agent_card_params.skills.map((skill: any, index: number) => (
|
||||
<Descriptions.Item label={skill.name || `Skill ${index + 1}`} key={index}>
|
||||
<Descriptions.Item
|
||||
label={skill.name || t("agentsPage.agentInfo.skillFallbackLabel", { index: index + 1 })}
|
||||
key={index}
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
<strong>ID:</strong> {skill.id}
|
||||
<strong>{t("agentsPage.agentInfo.skillIdField")}:</strong> {skill.id}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Description:</strong> {skill.description}
|
||||
<strong>{t("common.description")}:</strong> {skill.description}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Tags:</strong> {Array.isArray(skill.tags) ? skill.tags.join(", ") : skill.tags}
|
||||
<strong>{t("agentsPage.agentInfo.skillTagsField")}:</strong>{" "}
|
||||
{Array.isArray(skill.tags) ? skill.tags.join(", ") : skill.tags}
|
||||
</div>
|
||||
{skill.examples && skill.examples.length > 0 && (
|
||||
<div>
|
||||
<strong>Examples:</strong>{" "}
|
||||
<strong>{t("agentsPage.agentInfo.skillExamplesField")}:</strong>{" "}
|
||||
{Array.isArray(skill.examples) ? skill.examples.join(", ") : skill.examples}
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -330,7 +362,7 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
<TabPanel>
|
||||
<Card>
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<Title>Agent Settings</Title>
|
||||
<Title>{t("agentsPage.agentInfo.agentSettingsTitle")}</Title>
|
||||
{!isEditing && (
|
||||
<TremorButton
|
||||
onClick={() => {
|
||||
|
|
@ -338,14 +370,14 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
setIsEditing(true);
|
||||
}}
|
||||
>
|
||||
Edit Settings
|
||||
{t("agentsPage.agentInfo.editSettings")}
|
||||
</TremorButton>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isEditing ? (
|
||||
<Form form={form} layout="vertical" onFinish={handleUpdate}>
|
||||
<Form.Item label="Agent ID">
|
||||
<Form.Item label={t("agentsPage.agentInfo.agentIdLabel")}>
|
||||
<Input value={agent.agent_id} disabled />
|
||||
</Form.Item>
|
||||
|
||||
|
|
@ -369,21 +401,21 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
)}
|
||||
|
||||
<Divider />
|
||||
<Title className="mb-4">Rate Limits</Title>
|
||||
<Title className="mb-4">{t("agentsPage.agentInfo.rateLimitsTitle")}</Title>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Form.Item label="TPM Limit" name="tpm_limit">
|
||||
<InputNumber className="w-full" min={0} placeholder="Unlimited" />
|
||||
<Form.Item label={t("agentsPage.agentInfo.tpmLimitLabel")} name="tpm_limit">
|
||||
<InputNumber className="w-full" min={0} placeholder={t("agentsPage.agentInfo.unlimited")} />
|
||||
</Form.Item>
|
||||
<Form.Item label="RPM Limit" name="rpm_limit">
|
||||
<InputNumber className="w-full" min={0} placeholder="Unlimited" />
|
||||
<Form.Item label={t("agentsPage.agentInfo.rpmLimitLabel")} name="rpm_limit">
|
||||
<InputNumber className="w-full" min={0} placeholder={t("agentsPage.agentInfo.unlimited")} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Form.Item label="Session TPM Limit" name="session_tpm_limit">
|
||||
<InputNumber className="w-full" min={0} placeholder="Unlimited" />
|
||||
<Form.Item label={t("agentsPage.agentInfo.sessionTpmLimitLabel")} name="session_tpm_limit">
|
||||
<InputNumber className="w-full" min={0} placeholder={t("agentsPage.agentInfo.unlimited")} />
|
||||
</Form.Item>
|
||||
<Form.Item label="Session RPM Limit" name="session_rpm_limit">
|
||||
<InputNumber className="w-full" min={0} placeholder="Unlimited" />
|
||||
<Form.Item label={t("agentsPage.agentInfo.sessionRpmLimitLabel")} name="session_rpm_limit">
|
||||
<InputNumber className="w-full" min={0} placeholder={t("agentsPage.agentInfo.unlimited")} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
|
|
@ -395,13 +427,13 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
fetchAgentInfo();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
{t("common.cancel")}
|
||||
</AntButton>
|
||||
<TremorButton loading={isSaving}>Save Changes</TremorButton>
|
||||
<TremorButton loading={isSaving}>{t("agentsPage.agentInfo.saveChanges")}</TremorButton>
|
||||
</div>
|
||||
</Form>
|
||||
) : (
|
||||
<Text>Click "Edit Settings" to modify agent configuration.</Text>
|
||||
<Text>{t("agentsPage.agentInfo.editSettingsHint")}</Text>
|
||||
)}
|
||||
</Card>
|
||||
</TabPanel>
|
||||
|
|
|
|||
|
|
@ -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) => (
|
||||
<Form.Item key={field.name} label={field.label} name={field.name} tooltip={field.tooltip}>
|
||||
<Input placeholder={field.placeholder} type="number" step="0.000001" />
|
||||
</Form.Item>
|
||||
|
|
|
|||
|
|
@ -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<DynamicAgentFormFieldsProps> = ({ agentTypeInfo }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
|
|
@ -59,7 +61,7 @@ const DynamicAgentFormFields: React.FC<DynamicAgentFormFieldsProps> = ({ agentTy
|
|||
))}
|
||||
|
||||
<Collapse style={{ marginBottom: 16 }}>
|
||||
<Panel header={AGENT_FORM_CONFIG.cost.title} key={AGENT_FORM_CONFIG.cost.key}>
|
||||
<Panel header={getAgentFormConfig(t).cost.title} key={getAgentFormConfig(t).cost.key}>
|
||||
<CostConfigFields />
|
||||
</Panel>
|
||||
</Collapse>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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": "保存更改"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue