fix(ui): exclude vector_store_ids from model edit JSON textarea

Fields with dedicated form inputs (vector_store_ids, guardrails, tags)
were included in the litellm_extra_params JSON textarea. On save, these
duplicated values from the JSON could override the dedicated form field
logic, injecting unwanted parameters into litellm_params for non-OpenAI
models.

Exclude these fields from the JSON textarea (matching the existing
litellm_credential_name exclusion) and delete them from parsed JSON on
submit.

Fixes #27117
This commit is contained in:
Jonathan Wrede 2026-05-10 18:10:50 +00:00
parent 0af33fbe70
commit ffb6942ac0
2 changed files with 44 additions and 1 deletions

View file

@ -579,6 +579,46 @@ describe("ModelInfoView", () => {
expect(updatePayload.litellm_params).not.toHaveProperty("vector_store_ids");
});
it("should not leak vector_store_ids from JSON textarea when model already has them", async () => {
const modelWithVectorStores = {
...defaultModelData,
litellm_params: {
...defaultModelData.litellm_params,
vector_store_ids: ["vs_abc123"],
},
};
mockUseModelsInfo.mockReturnValue({
data: {
data: [modelWithVectorStores],
},
isLoading: false,
error: null,
});
const user = userEvent.setup();
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
await waitFor(() => {
expect(screen.getByRole("button", { name: /edit settings/i })).toBeInTheDocument();
});
await user.click(screen.getByRole("button", { name: /edit settings/i }));
const litellmParamsInput = screen
.getAllByRole("textbox")
.find(
(input) =>
input.tagName === "TEXTAREA" &&
(input as HTMLTextAreaElement).value.includes('"custom_llm_provider"'),
);
expect(litellmParamsInput).toBeDefined();
if (!litellmParamsInput) {
return;
}
expect((litellmParamsInput as HTMLTextAreaElement).value).not.toContain("vector_store_ids");
});
it("should not include input_cost_per_token or output_cost_per_token in update payload when user does not touch cost fields", async () => {
// Regression: editing a model without touching cost fields used to inject
// input_cost_per_token: 0 and output_cost_per_token: 0 into litellm_params,

View file

@ -235,6 +235,9 @@ export default function ModelInfoView({
try {
parsedExtraParams = values.litellm_extra_params ? JSON.parse(values.litellm_extra_params) : {};
delete parsedExtraParams.litellm_credential_name;
delete parsedExtraParams.vector_store_ids;
delete parsedExtraParams.guardrails;
delete parsedExtraParams.tags;
} catch (e) {
NotificationsManager.fromBackend("Invalid JSON in LiteLLM Params");
setIsSaving(false);
@ -651,7 +654,7 @@ export default function ModelInfoView({
litellm_extra_params: JSON.stringify(
Object.fromEntries(
Object.entries(localModelData.litellm_params || {}).filter(
([key]) => key !== "litellm_credential_name",
([key]) => !["litellm_credential_name", "vector_store_ids", "guardrails", "tags"].includes(key),
),
),
null,