mirror of
https://github.com/tiennm99/litellm.git
synced 2026-07-16 04:18:49 +00:00
[UI] - Add ability to set model alias per key/team (#13276)
* update model alias on keys * team model aliases * fix model aliases * fixes for teams
This commit is contained in:
@@ -0,0 +1,342 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { message } from "antd";
|
||||
import { PlusCircleIcon, PencilIcon, TrashIcon } from "@heroicons/react/outline";
|
||||
import {
|
||||
Card,
|
||||
Title,
|
||||
Text,
|
||||
Table,
|
||||
TableHead,
|
||||
TableHeaderCell,
|
||||
TableBody,
|
||||
TableRow,
|
||||
TableCell
|
||||
} from "@tremor/react";
|
||||
import ModelSelector from "./ModelSelector";
|
||||
|
||||
interface ModelAliasManagerProps {
|
||||
accessToken: string;
|
||||
initialModelAliases?: { [key: string]: string };
|
||||
onAliasUpdate?: (updatedAliases: { [key: string]: string }) => void;
|
||||
showExampleConfig?: boolean;
|
||||
}
|
||||
|
||||
interface AliasItem {
|
||||
id: string;
|
||||
aliasName: string;
|
||||
targetModel: string;
|
||||
}
|
||||
|
||||
const ModelAliasManager: React.FC<ModelAliasManagerProps> = ({
|
||||
accessToken,
|
||||
initialModelAliases = {},
|
||||
onAliasUpdate,
|
||||
showExampleConfig = true,
|
||||
}) => {
|
||||
const [aliases, setAliases] = useState<AliasItem[]>([]);
|
||||
const [newAlias, setNewAlias] = useState({ aliasName: "", targetModel: "" });
|
||||
const [editingAlias, setEditingAlias] = useState<AliasItem | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Convert object to array for display
|
||||
const aliasArray = Object.entries(initialModelAliases).map(([aliasName, targetModel], index) => ({
|
||||
id: `${index}-${aliasName}`,
|
||||
aliasName,
|
||||
targetModel,
|
||||
}));
|
||||
setAliases(aliasArray);
|
||||
}, [initialModelAliases]);
|
||||
|
||||
const handleAddAlias = () => {
|
||||
if (!newAlias.aliasName || !newAlias.targetModel) {
|
||||
message.error("Please provide both alias name and target model");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for duplicate alias names
|
||||
if (aliases.some(alias => alias.aliasName === newAlias.aliasName)) {
|
||||
message.error("An alias with this name already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
const newAliasObj: AliasItem = {
|
||||
id: `${Date.now()}-${newAlias.aliasName}`,
|
||||
aliasName: newAlias.aliasName,
|
||||
targetModel: newAlias.targetModel,
|
||||
};
|
||||
|
||||
const updatedAliases = [...aliases, newAliasObj];
|
||||
setAliases(updatedAliases);
|
||||
setNewAlias({ aliasName: "", targetModel: "" });
|
||||
|
||||
// Convert array back to object format and notify parent
|
||||
const aliasObject: { [key: string]: string } = {};
|
||||
updatedAliases.forEach(alias => {
|
||||
aliasObject[alias.aliasName] = alias.targetModel;
|
||||
});
|
||||
|
||||
if (onAliasUpdate) {
|
||||
onAliasUpdate(aliasObject);
|
||||
}
|
||||
|
||||
message.success("Alias added successfully");
|
||||
};
|
||||
|
||||
const handleEditAlias = (alias: AliasItem) => {
|
||||
setEditingAlias({ ...alias });
|
||||
};
|
||||
|
||||
const handleUpdateAlias = () => {
|
||||
if (!editingAlias) return;
|
||||
|
||||
if (!editingAlias.aliasName || !editingAlias.targetModel) {
|
||||
message.error("Please provide both alias name and target model");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for duplicate alias names (excluding current alias)
|
||||
if (aliases.some(alias => alias.id !== editingAlias.id && alias.aliasName === editingAlias.aliasName)) {
|
||||
message.error("An alias with this name already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedAliases = aliases.map(alias =>
|
||||
alias.id === editingAlias.id ? editingAlias : alias
|
||||
);
|
||||
|
||||
setAliases(updatedAliases);
|
||||
setEditingAlias(null);
|
||||
|
||||
// Convert array back to object format and notify parent
|
||||
const aliasObject: { [key: string]: string } = {};
|
||||
updatedAliases.forEach(alias => {
|
||||
aliasObject[alias.aliasName] = alias.targetModel;
|
||||
});
|
||||
|
||||
if (onAliasUpdate) {
|
||||
onAliasUpdate(aliasObject);
|
||||
}
|
||||
|
||||
message.success("Alias updated successfully");
|
||||
};
|
||||
|
||||
const handleCancelEdit = () => {
|
||||
setEditingAlias(null);
|
||||
};
|
||||
|
||||
const deleteAlias = (aliasId: string) => {
|
||||
const updatedAliases = aliases.filter(alias => alias.id !== aliasId);
|
||||
setAliases(updatedAliases);
|
||||
|
||||
// Convert array back to object format and notify parent
|
||||
const aliasObject: { [key: string]: string } = {};
|
||||
updatedAliases.forEach(alias => {
|
||||
aliasObject[alias.aliasName] = alias.targetModel;
|
||||
});
|
||||
|
||||
if (onAliasUpdate) {
|
||||
onAliasUpdate(aliasObject);
|
||||
}
|
||||
|
||||
message.success("Alias deleted successfully");
|
||||
};
|
||||
|
||||
// Convert current aliases to object for config example
|
||||
const aliasObject = aliases.reduce((acc, alias) => {
|
||||
acc[alias.aliasName] = alias.targetModel;
|
||||
return acc;
|
||||
}, {} as { [key: string]: string });
|
||||
|
||||
return (
|
||||
<div className="mt-4">
|
||||
<div className="mb-6">
|
||||
<Text className="text-sm font-medium text-gray-700 mb-2">Add New Alias</Text>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-xs text-gray-500 mb-1">Alias Name</label>
|
||||
<input
|
||||
type="text"
|
||||
value={newAlias.aliasName}
|
||||
onChange={(e) =>
|
||||
setNewAlias({
|
||||
...newAlias,
|
||||
aliasName: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="e.g., gpt-4o"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs text-gray-500 mb-1">
|
||||
Target Model
|
||||
</label>
|
||||
<ModelSelector
|
||||
accessToken={accessToken}
|
||||
value={newAlias.targetModel}
|
||||
placeholder="Select target model"
|
||||
onChange={(value) =>
|
||||
setNewAlias({
|
||||
...newAlias,
|
||||
targetModel: value,
|
||||
})
|
||||
}
|
||||
showLabel={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-end">
|
||||
<button
|
||||
onClick={handleAddAlias}
|
||||
disabled={!newAlias.aliasName || !newAlias.targetModel}
|
||||
className={`flex items-center px-4 py-2 rounded-md text-sm ${!newAlias.aliasName || !newAlias.targetModel ? 'bg-gray-300 text-gray-500 cursor-not-allowed' : 'bg-green-600 text-white hover:bg-green-700'}`}
|
||||
>
|
||||
<PlusCircleIcon className="w-4 h-4 mr-1" />
|
||||
Add Alias
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Text className="text-sm font-medium text-gray-700 mb-2">
|
||||
Manage Existing Aliases
|
||||
</Text>
|
||||
<div className="rounded-lg custom-border relative mb-6">
|
||||
<div className="overflow-x-auto">
|
||||
<Table className="[&_td]:py-0.5 [&_th]:py-1">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableHeaderCell className="py-1 h-8">
|
||||
Alias Name
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">
|
||||
Target Model
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">
|
||||
Actions
|
||||
</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{aliases.map((alias) => (
|
||||
<TableRow key={alias.id} className="h-8">
|
||||
{editingAlias && editingAlias.id === alias.id ? (
|
||||
<>
|
||||
<TableCell className="py-0.5">
|
||||
<input
|
||||
type="text"
|
||||
value={editingAlias.aliasName}
|
||||
onChange={(e) =>
|
||||
setEditingAlias({
|
||||
...editingAlias,
|
||||
aliasName: e.target.value,
|
||||
})
|
||||
}
|
||||
className="w-full px-2 py-1 border border-gray-300 rounded-md text-sm"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="py-0.5">
|
||||
<ModelSelector
|
||||
accessToken={accessToken}
|
||||
value={editingAlias.targetModel}
|
||||
onChange={(value) =>
|
||||
setEditingAlias({
|
||||
...editingAlias,
|
||||
targetModel: value,
|
||||
})
|
||||
}
|
||||
showLabel={false}
|
||||
style={{ height: '32px' }}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="py-0.5 whitespace-nowrap">
|
||||
<div className="flex space-x-2">
|
||||
<button
|
||||
onClick={handleUpdateAlias}
|
||||
className="text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded hover:bg-blue-100"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
onClick={handleCancelEdit}
|
||||
className="text-xs bg-gray-50 text-gray-600 px-2 py-1 rounded hover:bg-gray-100"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<TableCell className="py-0.5 text-sm text-gray-900">
|
||||
{alias.aliasName}
|
||||
</TableCell>
|
||||
<TableCell className="py-0.5 text-sm text-gray-500">
|
||||
{alias.targetModel}
|
||||
</TableCell>
|
||||
<TableCell className="py-0.5 whitespace-nowrap">
|
||||
<div className="flex space-x-2">
|
||||
<button
|
||||
onClick={() => handleEditAlias(alias)}
|
||||
className="text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded hover:bg-blue-100"
|
||||
>
|
||||
<PencilIcon className="w-3 h-3" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => deleteAlias(alias.id)}
|
||||
className="text-xs bg-red-50 text-red-600 px-2 py-1 rounded hover:bg-red-100"
|
||||
>
|
||||
<TrashIcon className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</>
|
||||
)}
|
||||
</TableRow>
|
||||
))}
|
||||
{aliases.length === 0 && (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={3}
|
||||
className="py-0.5 text-sm text-gray-500 text-center"
|
||||
>
|
||||
No aliases added yet. Add a new alias above.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Configuration Example */}
|
||||
{showExampleConfig && (
|
||||
<Card>
|
||||
<Title className="mb-4">Configuration Example</Title>
|
||||
<Text className="text-gray-600 mb-4">
|
||||
Here's how your current aliases would look in the config:
|
||||
</Text>
|
||||
<div className="bg-gray-100 rounded-lg p-4 font-mono text-sm">
|
||||
<div className="text-gray-700">
|
||||
model_aliases:
|
||||
{Object.keys(aliasObject).length === 0 ? (
|
||||
<span className="text-gray-500">
|
||||
<br />
|
||||
# No aliases configured yet
|
||||
</span>
|
||||
) : (
|
||||
Object.entries(aliasObject).map(([key, value]) => (
|
||||
<span key={key}>
|
||||
<br />
|
||||
"{key}": "{value}"
|
||||
</span>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModelAliasManager;
|
||||
@@ -0,0 +1,122 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { TextInput, Text } from "@tremor/react";
|
||||
import { Select } from "antd";
|
||||
import { RobotOutlined } from "@ant-design/icons";
|
||||
import { fetchAvailableModels, ModelGroup } from "../chat_ui/llm_calls/fetch_models";
|
||||
|
||||
interface ModelSelectorProps {
|
||||
accessToken: string;
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
onChange?: (value: string) => void;
|
||||
disabled?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
showLabel?: boolean;
|
||||
labelText?: string;
|
||||
}
|
||||
|
||||
const ModelSelector: React.FC<ModelSelectorProps> = ({
|
||||
accessToken,
|
||||
value,
|
||||
placeholder = "Select a Model",
|
||||
onChange,
|
||||
disabled = false,
|
||||
style,
|
||||
className,
|
||||
showLabel = true,
|
||||
labelText = "Select Model"
|
||||
}) => {
|
||||
const [selectedModel, setSelectedModel] = useState<string | undefined>(value);
|
||||
const [showCustomModelInput, setShowCustomModelInput] = useState<boolean>(false);
|
||||
const [modelInfo, setModelInfo] = useState<ModelGroup[]>([]);
|
||||
const customModelTimeout = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedModel(value);
|
||||
}, [value]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!accessToken) return;
|
||||
|
||||
const loadModels = async () => {
|
||||
try {
|
||||
const uniqueModels = await fetchAvailableModels(accessToken);
|
||||
console.log("Fetched models for selector:", uniqueModels);
|
||||
|
||||
if (uniqueModels.length > 0) {
|
||||
setModelInfo(uniqueModels);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching model info:", error);
|
||||
}
|
||||
};
|
||||
|
||||
loadModels();
|
||||
}, [accessToken]);
|
||||
|
||||
const onModelChange = (value: string) => {
|
||||
if (value === 'custom') {
|
||||
setShowCustomModelInput(true);
|
||||
setSelectedModel(undefined);
|
||||
} else {
|
||||
setShowCustomModelInput(false);
|
||||
setSelectedModel(value);
|
||||
if (onChange) {
|
||||
onChange(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleCustomModelChange = (value: string) => {
|
||||
// Using setTimeout to create a simple debounce effect
|
||||
if (customModelTimeout.current) {
|
||||
clearTimeout(customModelTimeout.current);
|
||||
}
|
||||
|
||||
customModelTimeout.current = setTimeout(() => {
|
||||
setSelectedModel(value);
|
||||
if (onChange) {
|
||||
onChange(value);
|
||||
}
|
||||
}, 500); // 500ms delay after typing stops
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{showLabel && (
|
||||
<Text className="font-medium block mb-2 text-gray-700 flex items-center">
|
||||
<RobotOutlined className="mr-2" /> {labelText}
|
||||
</Text>
|
||||
)}
|
||||
<Select
|
||||
value={selectedModel}
|
||||
placeholder={placeholder}
|
||||
onChange={onModelChange}
|
||||
options={[
|
||||
...Array.from(new Set(modelInfo.map(option => option.model_group)))
|
||||
.map((model_group, index) => ({
|
||||
value: model_group,
|
||||
label: model_group,
|
||||
key: index
|
||||
})),
|
||||
{ value: 'custom', label: 'Enter custom model', key: 'custom' }
|
||||
]}
|
||||
style={{ width: "100%", ...style }}
|
||||
showSearch={true}
|
||||
className={`rounded-md ${className || ''}`}
|
||||
disabled={disabled}
|
||||
/>
|
||||
{showCustomModelInput && (
|
||||
<TextInput
|
||||
className="mt-2"
|
||||
placeholder="Enter custom model name"
|
||||
onValueChange={handleCustomModelChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModelSelector;
|
||||
@@ -49,6 +49,7 @@ import BudgetDurationDropdown from "./common_components/budget_duration_dropdown
|
||||
import { formatNumberWithCommas } from "@/utils/dataUtils";
|
||||
import { callback_map, mapDisplayToInternalNames } from "./callback_info_helpers";
|
||||
import MCPServerSelector from "./mcp_server_management/MCPServerSelector";
|
||||
import ModelAliasManager from "./common_components/ModelAliasManager";
|
||||
|
||||
|
||||
const { Option } = Select;
|
||||
@@ -184,6 +185,7 @@ const CreateKey: React.FC<CreateKeyProps> = ({
|
||||
const [mcpAccessGroupsLoaded, setMcpAccessGroupsLoaded] = useState(false);
|
||||
const [disabledCallbacks, setDisabledCallbacks] = useState<string[]>([]);
|
||||
const [keyType, setKeyType] = useState<string>("default");
|
||||
const [modelAliases, setModelAliases] = useState<{ [key: string]: string }>({});
|
||||
|
||||
const handleOk = () => {
|
||||
setIsModalVisible(false);
|
||||
@@ -191,6 +193,7 @@ const CreateKey: React.FC<CreateKeyProps> = ({
|
||||
setLoggingSettings([]);
|
||||
setDisabledCallbacks([]);
|
||||
setKeyType("default");
|
||||
setModelAliases({});
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@@ -201,6 +204,7 @@ const CreateKey: React.FC<CreateKeyProps> = ({
|
||||
setLoggingSettings([]);
|
||||
setDisabledCallbacks([]);
|
||||
setKeyType("default");
|
||||
setModelAliases({});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -371,6 +375,12 @@ const CreateKey: React.FC<CreateKeyProps> = ({
|
||||
// Remove the original field as it's now part of object_permission
|
||||
delete formValues.allowed_mcp_access_groups;
|
||||
}
|
||||
|
||||
// Add model_aliases if any are defined
|
||||
if (Object.keys(modelAliases).length > 0) {
|
||||
formValues.aliases = JSON.stringify(modelAliases);
|
||||
}
|
||||
|
||||
let response;
|
||||
if (keyOwner === "service_account") {
|
||||
response = await keyCreateServiceAccountCall(accessToken, formValues);
|
||||
@@ -1008,6 +1018,25 @@ const CreateKey: React.FC<CreateKeyProps> = ({
|
||||
</div>
|
||||
</AccordionBody>
|
||||
</Accordion>
|
||||
|
||||
<Accordion className="mt-4 mb-4">
|
||||
<AccordionHeader>
|
||||
<b>Model Aliases</b>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<div className="mt-4">
|
||||
<Text className="text-sm text-gray-600 mb-4">
|
||||
Create custom aliases for models that can be used in API calls. This allows you to create shortcuts for specific models.
|
||||
</Text>
|
||||
<ModelAliasManager
|
||||
accessToken={accessToken}
|
||||
initialModelAliases={modelAliases}
|
||||
onAliasUpdate={setModelAliases}
|
||||
showExampleConfig={false}
|
||||
/>
|
||||
</div>
|
||||
</AccordionBody>
|
||||
</Accordion>
|
||||
<Accordion className="mt-4 mb-4">
|
||||
<AccordionHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
@@ -74,6 +74,7 @@ import type { KeyResponse, Team } from "./key_team_helpers/key_list";
|
||||
import { formatNumberWithCommas } from "../utils/dataUtils";
|
||||
import { AlertTriangleIcon, XIcon } from 'lucide-react';
|
||||
import MCPServerSelector from "./mcp_server_management/MCPServerSelector";
|
||||
import ModelAliasManager from "./common_components/ModelAliasManager";
|
||||
|
||||
interface TeamProps {
|
||||
teams: Team[] | null;
|
||||
@@ -205,6 +206,7 @@ const Teams: React.FC<TeamProps> = ({
|
||||
const [mcpAccessGroups, setMcpAccessGroups] = useState<string[]>([]);
|
||||
const [mcpAccessGroupsLoaded, setMcpAccessGroupsLoaded] = useState(false);
|
||||
const [deleteConfirmInput, setDeleteConfirmInput] = useState("");
|
||||
const [modelAliases, setModelAliases] = useState<{ [key: string]: string }>({});
|
||||
|
||||
useEffect(() => {
|
||||
console.log(`currentOrgForCreateTeam: ${currentOrgForCreateTeam}`);
|
||||
@@ -278,6 +280,7 @@ const Teams: React.FC<TeamProps> = ({
|
||||
setIsTeamModalVisible(false);
|
||||
form.resetFields();
|
||||
setLoggingSettings([]);
|
||||
setModelAliases({});
|
||||
};
|
||||
|
||||
const handleMemberOk = () => {
|
||||
@@ -290,6 +293,7 @@ const Teams: React.FC<TeamProps> = ({
|
||||
setIsTeamModalVisible(false);
|
||||
form.resetFields();
|
||||
setLoggingSettings([]);
|
||||
setModelAliases({});
|
||||
};
|
||||
|
||||
const handleMemberCancel = () => {
|
||||
@@ -439,6 +443,12 @@ const Teams: React.FC<TeamProps> = ({
|
||||
formValues.allowed_mcp_access_groups;
|
||||
delete formValues.allowed_mcp_access_groups;
|
||||
}
|
||||
|
||||
// Add model_aliases if any are defined
|
||||
if (Object.keys(modelAliases).length > 0) {
|
||||
formValues.model_aliases = modelAliases;
|
||||
}
|
||||
|
||||
const response: any = await teamCreateCall(accessToken, formValues);
|
||||
if (teams !== null) {
|
||||
setTeams([...teams, response]);
|
||||
@@ -449,6 +459,7 @@ const Teams: React.FC<TeamProps> = ({
|
||||
message.success("Team created");
|
||||
form.resetFields();
|
||||
setLoggingSettings([]);
|
||||
setModelAliases({});
|
||||
setIsTeamModalVisible(false);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -1466,6 +1477,7 @@ const Teams: React.FC<TeamProps> = ({
|
||||
placeholder="Select MCP servers or access groups (optional)"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
</AccordionBody>
|
||||
</Accordion>
|
||||
|
||||
@@ -1483,6 +1495,26 @@ const Teams: React.FC<TeamProps> = ({
|
||||
</div>
|
||||
</AccordionBody>
|
||||
</Accordion>
|
||||
|
||||
|
||||
<Accordion className="mt-8 mb-8">
|
||||
<AccordionHeader>
|
||||
<b>Model Aliases</b>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<div className="mt-4">
|
||||
<Text className="text-sm text-gray-600 mb-4">
|
||||
Create custom aliases for models that can be used by team members in API calls. This allows you to create shortcuts for specific models.
|
||||
</Text>
|
||||
<ModelAliasManager
|
||||
accessToken={accessToken || ""}
|
||||
initialModelAliases={modelAliases}
|
||||
onAliasUpdate={setModelAliases}
|
||||
showExampleConfig={false}
|
||||
/>
|
||||
</div>
|
||||
</AccordionBody>
|
||||
</Accordion>
|
||||
</>
|
||||
<div style={{ textAlign: "right", marginTop: "10px" }}>
|
||||
<Button2 htmlType="submit">Create Team</Button2>
|
||||
|
||||
Reference in New Issue
Block a user