mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
feat(frontend): Wire LLM picker to live registry
- Extract useLlmModelField hook that fetches live model list from /api/v2/llm/models and merges is_enabled/is_recommended flags - Registry is sole source of truth: models absent or disabled are hidden - recommended model driven by is_recommended flag, falls back to schema.default - Simplify LlmModelField.tsx to thin render component
This commit is contained in:
@@ -7,45 +7,16 @@ import {
|
||||
RJSFSchema,
|
||||
titleId,
|
||||
} from "@rjsf/utils";
|
||||
import { useMemo } from "react";
|
||||
import { LlmModelPicker } from "./components/LlmModelPicker";
|
||||
import { LlmModelMetadataMap } from "./types";
|
||||
import { updateUiOption } from "../../helpers";
|
||||
|
||||
type LlmModelSchema = RJSFSchema & {
|
||||
llm_model_metadata?: LlmModelMetadataMap;
|
||||
};
|
||||
import { useLlmModelField } from "./useLlmModelField";
|
||||
|
||||
export function LlmModelField(props: FieldProps) {
|
||||
const { schema, formData, onChange, disabled, readonly, fieldPathId } = props;
|
||||
|
||||
const metadata = useMemo(() => {
|
||||
return (schema as LlmModelSchema)?.llm_model_metadata ?? {};
|
||||
}, [schema]);
|
||||
|
||||
const models = useMemo(() => {
|
||||
return Object.values(metadata);
|
||||
}, [metadata]);
|
||||
|
||||
const selectedName =
|
||||
typeof formData === "string"
|
||||
? formData
|
||||
: typeof schema.default === "string"
|
||||
? schema.default
|
||||
: "";
|
||||
|
||||
const selectedModel = selectedName
|
||||
? (metadata[selectedName] ??
|
||||
models.find((model) => model.name === selectedName))
|
||||
: undefined;
|
||||
|
||||
const recommendedName =
|
||||
typeof schema.default === "string" ? schema.default : models[0]?.name;
|
||||
|
||||
const recommendedModel =
|
||||
recommendedName && metadata[recommendedName]
|
||||
? metadata[recommendedName]
|
||||
: undefined;
|
||||
const { models, selectedModel, recommendedModel } = useLlmModelField(
|
||||
schema as RJSFSchema,
|
||||
formData,
|
||||
);
|
||||
|
||||
if (models.length === 0) {
|
||||
return null;
|
||||
@@ -56,7 +27,6 @@ export function LlmModelField(props: FieldProps) {
|
||||
"DescriptionFieldTemplate",
|
||||
props.registry,
|
||||
);
|
||||
|
||||
const updatedUiSchema = updateUiOption(props.uiSchema, {
|
||||
showHandles: false,
|
||||
});
|
||||
|
||||
@@ -6,6 +6,8 @@ export type LlmModelMetadata = {
|
||||
provider_name: string;
|
||||
name: string;
|
||||
price_tier?: number;
|
||||
is_recommended?: boolean;
|
||||
is_enabled?: boolean;
|
||||
};
|
||||
|
||||
export type LlmModelMetadataMap = Record<string, LlmModelMetadata>;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { useMemo } from "react";
|
||||
import { RJSFSchema } from "@rjsf/utils";
|
||||
import { useGetV2ListModels } from "@/app/api/__generated__/endpoints/llm/llm";
|
||||
import type { LlmModelsResponse } from "@/app/api/__generated__/models/llmModelsResponse";
|
||||
import { LlmModelMetadata, LlmModelMetadataMap } from "./types";
|
||||
|
||||
type LlmModelSchema = RJSFSchema & {
|
||||
llm_model_metadata?: LlmModelMetadataMap;
|
||||
};
|
||||
|
||||
export function useLlmModelField(schema: RJSFSchema, formData: unknown) {
|
||||
const { data: registryData } = useGetV2ListModels(
|
||||
{ enabled_only: false },
|
||||
{ query: { staleTime: 60_000 } },
|
||||
);
|
||||
|
||||
const schemaMetadata = useMemo(
|
||||
() => (schema as LlmModelSchema)?.llm_model_metadata ?? {},
|
||||
[schema],
|
||||
);
|
||||
|
||||
// Merge live is_enabled / is_recommended flags from the registry into the
|
||||
// static schema metadata so the picker reflects admin changes without a
|
||||
// server restart. Models absent from the registry are hidden.
|
||||
const models = useMemo<LlmModelMetadata[]>(() => {
|
||||
const responseData = registryData?.data;
|
||||
const registryModels: LlmModelsResponse["models"] =
|
||||
responseData && "models" in responseData ? responseData.models : [];
|
||||
const bySlug = new Map(registryModels.map((m) => [m.slug, m]));
|
||||
|
||||
return Object.values(schemaMetadata)
|
||||
.map((m) => {
|
||||
const live = bySlug.get(m.name);
|
||||
return {
|
||||
...m,
|
||||
// Registry is the sole source of truth; absent = not shown.
|
||||
is_enabled: live?.is_enabled ?? false,
|
||||
is_recommended: live?.is_recommended ?? false,
|
||||
};
|
||||
})
|
||||
.filter((m) => m.is_enabled !== false);
|
||||
}, [schemaMetadata, registryData]);
|
||||
|
||||
const selectedName =
|
||||
typeof formData === "string"
|
||||
? formData
|
||||
: typeof schema.default === "string"
|
||||
? schema.default
|
||||
: "";
|
||||
|
||||
const selectedModel = selectedName
|
||||
? models.find((m) => m.name === selectedName)
|
||||
: undefined;
|
||||
|
||||
// Registry flag takes priority; schema.default is the static fallback.
|
||||
const recommendedModel =
|
||||
models.find((m) => m.is_recommended) ??
|
||||
models.find(
|
||||
(m) => typeof schema.default === "string" && m.name === schema.default,
|
||||
);
|
||||
|
||||
return { models, selectedModel, recommendedModel };
|
||||
}
|
||||
Reference in New Issue
Block a user