mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-10 07:46:02 +00:00
feat(models): persist context metadata
This commit is contained in:
@@ -64,6 +64,17 @@ function convertExtraArgsToObject(
|
||||
return obj;
|
||||
}
|
||||
|
||||
function parseContextLength(
|
||||
value: number | null | undefined,
|
||||
invalidMessage: string,
|
||||
): number | null {
|
||||
if (value === undefined || value === null) return null;
|
||||
if (!Number.isInteger(value) || value <= 0) {
|
||||
throw new Error(invalidMessage);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export default function ModelsDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
@@ -254,6 +265,7 @@ export default function ModelsDialog({
|
||||
name: string,
|
||||
abilities: string[],
|
||||
extraArgs: ExtraArg[],
|
||||
contextLength?: number | null,
|
||||
) {
|
||||
if (!name.trim()) {
|
||||
toast.error(t('models.modelNameRequired'));
|
||||
@@ -268,6 +280,10 @@ export default function ModelsDialog({
|
||||
name,
|
||||
provider_uuid: providerUuid,
|
||||
abilities,
|
||||
context_length: parseContextLength(
|
||||
contextLength,
|
||||
t('models.contextLengthInvalid'),
|
||||
),
|
||||
extra_args: extraArgsObj,
|
||||
} as never);
|
||||
} else if (modelType === 'embedding') {
|
||||
@@ -325,6 +341,7 @@ export default function ModelsDialog({
|
||||
name: item.model.name,
|
||||
provider_uuid: providerUuid,
|
||||
abilities: item.abilities,
|
||||
context_length: item.model.context_length ?? null,
|
||||
extra_args: {},
|
||||
} as never);
|
||||
} else if (effectiveType === 'embedding') {
|
||||
@@ -361,6 +378,7 @@ export default function ModelsDialog({
|
||||
name: string,
|
||||
abilities: string[],
|
||||
extraArgs: ExtraArg[],
|
||||
contextLength?: number | null,
|
||||
) {
|
||||
if (!name.trim()) {
|
||||
toast.error(t('models.modelNameRequired'));
|
||||
@@ -375,6 +393,10 @@ export default function ModelsDialog({
|
||||
name,
|
||||
provider_uuid: providerUuid,
|
||||
abilities,
|
||||
context_length: parseContextLength(
|
||||
contextLength,
|
||||
t('models.contextLengthInvalid'),
|
||||
),
|
||||
extra_args: extraArgsObj,
|
||||
} as never);
|
||||
} else if (modelType === 'embedding') {
|
||||
@@ -509,8 +531,15 @@ export default function ModelsDialog({
|
||||
onSpaceLogin={handleSpaceLogin}
|
||||
onOpenAddModel={() => setAddModelPopoverOpen(provider.uuid)}
|
||||
onCloseAddModel={() => setAddModelPopoverOpen(null)}
|
||||
onAddModel={(modelType, name, abilities, extraArgs) =>
|
||||
handleAddModel(provider.uuid, modelType, name, abilities, extraArgs)
|
||||
onAddModel={(modelType, name, abilities, extraArgs, contextLength) =>
|
||||
handleAddModel(
|
||||
provider.uuid,
|
||||
modelType,
|
||||
name,
|
||||
abilities,
|
||||
extraArgs,
|
||||
contextLength,
|
||||
)
|
||||
}
|
||||
onScanModels={(modelType) => handleScanModels(provider.uuid, modelType)}
|
||||
onAddScannedModels={(modelType, models) =>
|
||||
@@ -518,7 +547,14 @@ export default function ModelsDialog({
|
||||
}
|
||||
onOpenEditModel={(modelId) => setEditModelPopoverOpen(modelId)}
|
||||
onCloseEditModel={() => setEditModelPopoverOpen(null)}
|
||||
onUpdateModel={(modelId, modelType, name, abilities, extraArgs) =>
|
||||
onUpdateModel={(
|
||||
modelId,
|
||||
modelType,
|
||||
name,
|
||||
abilities,
|
||||
extraArgs,
|
||||
contextLength,
|
||||
) =>
|
||||
handleUpdateModel(
|
||||
provider.uuid,
|
||||
modelId,
|
||||
@@ -526,6 +562,7 @@ export default function ModelsDialog({
|
||||
name,
|
||||
abilities,
|
||||
extraArgs,
|
||||
contextLength,
|
||||
)
|
||||
}
|
||||
onOpenDeleteConfirm={(modelId) => setDeleteConfirmOpen(modelId)}
|
||||
|
||||
@@ -41,6 +41,7 @@ interface AddModelPopoverProps {
|
||||
name: string,
|
||||
abilities: string[],
|
||||
extraArgs: ExtraArg[],
|
||||
contextLength?: number | null,
|
||||
) => Promise<void>;
|
||||
onScanModels: (modelType?: ModelType) => Promise<ScanModelsResult>;
|
||||
onAddScannedModels: (
|
||||
@@ -81,6 +82,7 @@ export default function AddModelPopover({
|
||||
const [mode, setMode] = useState<'manual' | 'scan'>('manual');
|
||||
const [name, setName] = useState('');
|
||||
const [abilities, setAbilities] = useState<string[]>([]);
|
||||
const [contextLength, setContextLength] = useState('');
|
||||
const [extraArgs, setExtraArgs] = useState<ExtraArg[]>([]);
|
||||
const [scanLoading, setScanLoading] = useState(false);
|
||||
const [scannedModels, setScannedModels] = useState<ScannedProviderModel[]>(
|
||||
@@ -98,6 +100,7 @@ export default function AddModelPopover({
|
||||
setMode(initialMode);
|
||||
setName('');
|
||||
setAbilities([]);
|
||||
setContextLength('');
|
||||
setExtraArgs([]);
|
||||
setScanLoading(false);
|
||||
setScannedModels([]);
|
||||
@@ -119,7 +122,11 @@ export default function AddModelPopover({
|
||||
}, [tab, mode]);
|
||||
|
||||
const handleAdd = async () => {
|
||||
await onAddModel(tab, name, abilities, extraArgs);
|
||||
const parsedContextLength =
|
||||
tab === 'llm' && contextLength.trim()
|
||||
? Number(contextLength.trim())
|
||||
: null;
|
||||
await onAddModel(tab, name, abilities, extraArgs, parsedContextLength);
|
||||
};
|
||||
|
||||
const handleTest = async () => {
|
||||
@@ -318,6 +325,24 @@ export default function AddModelPopover({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tab === 'llm' && (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="add-context-length">
|
||||
{t('models.contextLength')}
|
||||
</Label>
|
||||
<Input
|
||||
id="add-context-length"
|
||||
type="number"
|
||||
min={1}
|
||||
step={1}
|
||||
inputMode="numeric"
|
||||
placeholder={t('models.contextLengthPlaceholder')}
|
||||
value={contextLength}
|
||||
onChange={(e) => setContextLength(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ExtraArgsEditor
|
||||
args={extraArgs}
|
||||
onChange={setExtraArgs}
|
||||
|
||||
@@ -31,6 +31,7 @@ interface ModelItemProps {
|
||||
name: string,
|
||||
abilities: string[],
|
||||
extraArgs: ExtraArg[],
|
||||
contextLength?: number | null,
|
||||
) => Promise<void>;
|
||||
onTestModel: (
|
||||
name: string,
|
||||
@@ -92,6 +93,11 @@ export default function ModelItem({
|
||||
const [editAbilities, setEditAbilities] = useState<string[]>(
|
||||
modelType === 'llm' ? (model as LLMModel).abilities || [] : [],
|
||||
);
|
||||
const [editContextLength, setEditContextLength] = useState(
|
||||
modelType === 'llm' && (model as LLMModel).context_length
|
||||
? String((model as LLMModel).context_length)
|
||||
: '',
|
||||
);
|
||||
const [editExtraArgs, setEditExtraArgs] = useState<ExtraArg[]>(
|
||||
convertExtraArgsToArray(model.extra_args),
|
||||
);
|
||||
@@ -106,13 +112,27 @@ export default function ModelItem({
|
||||
setEditAbilities(
|
||||
modelType === 'llm' ? (model as LLMModel).abilities || [] : [],
|
||||
);
|
||||
setEditContextLength(
|
||||
modelType === 'llm' && (model as LLMModel).context_length
|
||||
? String((model as LLMModel).context_length)
|
||||
: '',
|
||||
);
|
||||
setEditExtraArgs(convertExtraArgsToArray(model.extra_args));
|
||||
onResetTestResult();
|
||||
}
|
||||
}, [isEditOpen]);
|
||||
|
||||
const handleSave = async () => {
|
||||
await onUpdateModel(editName, editAbilities, editExtraArgs);
|
||||
const parsedContextLength =
|
||||
modelType === 'llm' && editContextLength.trim()
|
||||
? Number(editContextLength.trim())
|
||||
: null;
|
||||
await onUpdateModel(
|
||||
editName,
|
||||
editAbilities,
|
||||
editExtraArgs,
|
||||
parsedContextLength,
|
||||
);
|
||||
};
|
||||
|
||||
const handleTest = async () => {
|
||||
@@ -287,6 +307,25 @@ export default function ModelItem({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{modelType === 'llm' && (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor={`edit-context-length-${model.uuid}`}>
|
||||
{t('models.contextLength')}
|
||||
</Label>
|
||||
<Input
|
||||
id={`edit-context-length-${model.uuid}`}
|
||||
type="number"
|
||||
min={1}
|
||||
step={1}
|
||||
inputMode="numeric"
|
||||
placeholder={t('models.contextLengthPlaceholder')}
|
||||
value={editContextLength}
|
||||
disabled={isLangBotModels}
|
||||
onChange={(e) => setEditContextLength(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ExtraArgsEditor
|
||||
args={editExtraArgs}
|
||||
onChange={setEditExtraArgs}
|
||||
|
||||
@@ -60,6 +60,7 @@ interface ProviderCardProps {
|
||||
name: string,
|
||||
abilities: string[],
|
||||
extraArgs: ExtraArg[],
|
||||
contextLength?: number | null,
|
||||
) => Promise<void>;
|
||||
onScanModels: (modelType?: ModelType) => Promise<ScanModelsResult>;
|
||||
onAddScannedModels: (
|
||||
@@ -74,6 +75,7 @@ interface ProviderCardProps {
|
||||
name: string,
|
||||
abilities: string[],
|
||||
extraArgs: ExtraArg[],
|
||||
contextLength?: number | null,
|
||||
) => Promise<void>;
|
||||
onOpenDeleteConfirm: (modelId: string) => void;
|
||||
onCloseDeleteConfirm: () => void;
|
||||
@@ -405,13 +407,19 @@ export default function ProviderCard({
|
||||
onOpenDeleteConfirm={onOpenDeleteConfirm}
|
||||
onCloseDeleteConfirm={onCloseDeleteConfirm}
|
||||
onDeleteModel={() => onDeleteModel(model.uuid, 'llm')}
|
||||
onUpdateModel={(name, abilities, extraArgs) =>
|
||||
onUpdateModel={(
|
||||
name,
|
||||
abilities,
|
||||
extraArgs,
|
||||
contextLength,
|
||||
) =>
|
||||
onUpdateModel(
|
||||
model.uuid,
|
||||
'llm',
|
||||
name,
|
||||
abilities,
|
||||
extraArgs,
|
||||
contextLength,
|
||||
)
|
||||
}
|
||||
onTestModel={(name, abilities, extraArgs) =>
|
||||
|
||||
@@ -53,6 +53,7 @@ export interface ModelItemProps {
|
||||
name: string,
|
||||
abilities: string[],
|
||||
extraArgs: ExtraArg[],
|
||||
contextLength?: number | null,
|
||||
) => Promise<void>;
|
||||
onTest: (
|
||||
name: string,
|
||||
@@ -89,6 +90,7 @@ export interface ProviderCardProps {
|
||||
name: string,
|
||||
abilities: string[],
|
||||
extraArgs: ExtraArg[],
|
||||
contextLength?: number | null,
|
||||
) => Promise<void>;
|
||||
onScanModels: (modelType?: ModelType) => Promise<ScanModelsResult>;
|
||||
onAddScannedModels: (
|
||||
@@ -103,6 +105,7 @@ export interface ProviderCardProps {
|
||||
name: string,
|
||||
abilities: string[],
|
||||
extraArgs: ExtraArg[],
|
||||
contextLength?: number | null,
|
||||
) => Promise<void>;
|
||||
onOpenDeleteConfirm: (modelId: string) => void;
|
||||
onCloseDeleteConfirm: () => void;
|
||||
|
||||
@@ -96,6 +96,7 @@ export interface LLMModel {
|
||||
provider_uuid: string;
|
||||
provider?: ModelProvider;
|
||||
abilities?: string[];
|
||||
context_length?: number | null;
|
||||
extra_args?: object;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,6 +201,9 @@ const enUS = {
|
||||
selectModelAbilities: 'Select model abilities',
|
||||
visionAbility: 'Vision Ability',
|
||||
functionCallAbility: 'Function Call',
|
||||
contextLength: 'Context Window',
|
||||
contextLengthPlaceholder: 'Unknown',
|
||||
contextLengthInvalid: 'Context window must be a positive integer',
|
||||
extraParameters: 'Extra Parameters',
|
||||
addParameter: 'Add Parameter',
|
||||
keyName: 'Key Name',
|
||||
|
||||
@@ -206,6 +206,9 @@ const esES = {
|
||||
selectModelAbilities: 'Seleccionar capacidades del modelo',
|
||||
visionAbility: 'Capacidad de visión',
|
||||
functionCallAbility: 'Llamada a funciones',
|
||||
contextLength: 'Ventana de contexto',
|
||||
contextLengthPlaceholder: 'Desconocido',
|
||||
contextLengthInvalid: 'La ventana de contexto debe ser un entero positivo',
|
||||
extraParameters: 'Parámetros adicionales',
|
||||
addParameter: 'Añadir parámetro',
|
||||
keyName: 'Nombre de la clave',
|
||||
|
||||
@@ -204,6 +204,10 @@ const jaJP = {
|
||||
selectModelAbilities: 'モデル機能を選択',
|
||||
visionAbility: '視覚機能',
|
||||
functionCallAbility: '関数呼び出し',
|
||||
contextLength: 'コンテキストウィンドウ',
|
||||
contextLengthPlaceholder: '不明',
|
||||
contextLengthInvalid:
|
||||
'コンテキストウィンドウは正の整数である必要があります',
|
||||
extraParameters: '追加パラメータ',
|
||||
addParameter: 'パラメータを追加',
|
||||
keyName: 'キー名',
|
||||
|
||||
@@ -203,6 +203,10 @@ const ruRU = {
|
||||
selectModelAbilities: 'Выберите возможности модели',
|
||||
visionAbility: 'Распознавание изображений',
|
||||
functionCallAbility: 'Вызов функций',
|
||||
contextLength: 'Контекстное окно',
|
||||
contextLengthPlaceholder: 'Неизвестно',
|
||||
contextLengthInvalid:
|
||||
'Контекстное окно должно быть положительным целым числом',
|
||||
extraParameters: 'Дополнительные параметры',
|
||||
addParameter: 'Добавить параметр',
|
||||
keyName: 'Имя ключа',
|
||||
|
||||
@@ -199,6 +199,9 @@ const thTH = {
|
||||
selectModelAbilities: 'เลือกความสามารถของโมเดล',
|
||||
visionAbility: 'ความสามารถด้านภาพ',
|
||||
functionCallAbility: 'การเรียกฟังก์ชัน',
|
||||
contextLength: 'หน้าต่างบริบท',
|
||||
contextLengthPlaceholder: 'ไม่ทราบ',
|
||||
contextLengthInvalid: 'หน้าต่างบริบทต้องเป็นจำนวนเต็มบวก',
|
||||
extraParameters: 'พารามิเตอร์เพิ่มเติม',
|
||||
addParameter: 'เพิ่มพารามิเตอร์',
|
||||
keyName: 'ชื่อคีย์',
|
||||
|
||||
@@ -203,6 +203,9 @@ const viVN = {
|
||||
selectModelAbilities: 'Chọn khả năng mô hình',
|
||||
visionAbility: 'Khả năng thị giác',
|
||||
functionCallAbility: 'Gọi hàm',
|
||||
contextLength: 'Cửa sổ ngữ cảnh',
|
||||
contextLengthPlaceholder: 'Không rõ',
|
||||
contextLengthInvalid: 'Cửa sổ ngữ cảnh phải là số nguyên dương',
|
||||
extraParameters: 'Tham số bổ sung',
|
||||
addParameter: 'Thêm tham số',
|
||||
keyName: 'Tên khóa',
|
||||
|
||||
@@ -193,6 +193,9 @@ const zhHans = {
|
||||
selectModelAbilities: '选择模型能力',
|
||||
visionAbility: '视觉能力',
|
||||
functionCallAbility: '函数调用',
|
||||
contextLength: '上下文窗口',
|
||||
contextLengthPlaceholder: '未知',
|
||||
contextLengthInvalid: '上下文窗口必须是正整数',
|
||||
extraParameters: '额外参数',
|
||||
addParameter: '添加参数',
|
||||
keyName: '键名',
|
||||
|
||||
@@ -193,6 +193,9 @@ const zhHant = {
|
||||
selectModelAbilities: '選擇模型能力',
|
||||
visionAbility: '視覺能力',
|
||||
functionCallAbility: '函數呼叫',
|
||||
contextLength: '上下文視窗',
|
||||
contextLengthPlaceholder: '未知',
|
||||
contextLengthInvalid: '上下文視窗必須是正整數',
|
||||
extraParameters: '額外參數',
|
||||
addParameter: '新增參數',
|
||||
keyName: '鍵名',
|
||||
|
||||
Reference in New Issue
Block a user