Fix admin LLM API routes and improve model migration

Removes redundant route prefix in backend admin LLM API, updates OpenAPI paths to match, and improves parameterization for batch node updates in model migration and revert logic. Also adds stricter validation for replacement model slug in frontend actions and sets button type in EditModelModal.
This commit is contained in:
Bentlybro
2026-01-16 12:51:06 +00:00
parent eab93aba2b
commit 963b8090cc
5 changed files with 28 additions and 22 deletions

View File

@@ -11,7 +11,6 @@ from backend.server.v2.llm import model as llm_model
logger = logging.getLogger(__name__)
router = fastapi.APIRouter(
prefix="/admin/llm",
tags=["llm", "admin"],
dependencies=[fastapi.Security(autogpt_libs.auth.requires_admin_user)],
)

View File

@@ -355,7 +355,8 @@ async def toggle_model(
if nodes_migrated > 0:
# Update by IDs to ensure we only update the exact nodes we queried
node_ids_pg_array = "{" + ",".join(migrated_node_ids) + "}"
# Use JSON array and jsonb_array_elements_text for safe parameterization
node_ids_json = json.dumps(migrated_node_ids)
await tx.execute_raw(
"""
UPDATE "AgentNode"
@@ -364,10 +365,12 @@ async def toggle_model(
'{model}',
to_jsonb($1::text)
)
WHERE id::text = ANY($2::text[])
WHERE id::text IN (
SELECT jsonb_array_elements_text($2::jsonb)
)
""",
migrate_to_slug,
node_ids_pg_array,
node_ids_json,
)
record = await tx.llmmodel.update(
@@ -636,8 +639,8 @@ async def revert_migration(
# Update only the specific nodes that were migrated
# We need to check that they still have the target model (haven't been changed since)
# Use a single batch update for efficiency
# Format node IDs as PostgreSQL text array literal for comparison
node_ids_pg_array = "{" + ",".join(migrated_node_ids) + "}"
# Use JSON array and jsonb_array_elements_text for safe parameterization
node_ids_json = json.dumps(migrated_node_ids)
result = await tx.execute_raw(
"""
UPDATE "AgentNode"
@@ -646,11 +649,13 @@ async def revert_migration(
'{model}',
to_jsonb($1::text)
)
WHERE id::text = ANY($2::text[])
WHERE id::text IN (
SELECT jsonb_array_elements_text($2::jsonb)
)
AND "constantInput"::jsonb->>'model' = $3
""",
migration.sourceModelSlug,
node_ids_pg_array,
node_ids_json,
migration.targetModelSlug,
)
nodes_reverted = result if result else 0

View File

@@ -211,11 +211,12 @@ export async function toggleLlmModelAction(formData: FormData): Promise<void> {
export async function deleteLlmModelAction(formData: FormData): Promise<void> {
const modelId = String(formData.get("model_id"));
const replacementModelSlug = String(formData.get("replacement_model_slug"));
const rawReplacement = formData.get("replacement_model_slug");
if (!replacementModelSlug) {
if (rawReplacement == null || String(rawReplacement).trim() === "") {
throw new Error("Replacement model is required");
}
const replacementModelSlug = String(rawReplacement).trim();
const response = await deleteV2DeleteLlmModelAndMigrateWorkflows(modelId, {
replacement_model_slug: replacementModelSlug,

View File

@@ -190,6 +190,7 @@ export function EditModelModal({
<Dialog.Footer>
<Button
type="button"
variant="ghost"
size="small"
onClick={() => setOpen(false)}

View File

@@ -4085,7 +4085,7 @@
}
}
},
"/api/llm/admin/admin/llm/creators": {
"/api/llm/admin/creators": {
"get": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "List model creators",
@@ -4145,7 +4145,7 @@
"security": [{ "HTTPBearerJWT": [] }]
}
},
"/api/llm/admin/admin/llm/creators/{creator_id}": {
"/api/llm/admin/creators/{creator_id}": {
"delete": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "Delete model creator",
@@ -4269,7 +4269,7 @@
}
}
},
"/api/llm/admin/admin/llm/migrations": {
"/api/llm/admin/migrations": {
"get": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "List model migrations",
@@ -4315,7 +4315,7 @@
}
}
},
"/api/llm/admin/admin/llm/migrations/{migration_id}": {
"/api/llm/admin/migrations/{migration_id}": {
"get": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "Get migration details",
@@ -4353,7 +4353,7 @@
}
}
},
"/api/llm/admin/admin/llm/migrations/{migration_id}/revert": {
"/api/llm/admin/migrations/{migration_id}/revert": {
"post": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "Revert a model migration",
@@ -4406,7 +4406,7 @@
}
}
},
"/api/llm/admin/admin/llm/models": {
"/api/llm/admin/models": {
"get": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "List LLM models",
@@ -4481,7 +4481,7 @@
}
}
},
"/api/llm/admin/admin/llm/models/{model_id}": {
"/api/llm/admin/models/{model_id}": {
"delete": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "Delete LLM model and migrate workflows",
@@ -4575,7 +4575,7 @@
}
}
},
"/api/llm/admin/admin/llm/models/{model_id}/toggle": {
"/api/llm/admin/models/{model_id}/toggle": {
"patch": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "Toggle LLM model availability",
@@ -4623,7 +4623,7 @@
}
}
},
"/api/llm/admin/admin/llm/models/{model_id}/usage": {
"/api/llm/admin/models/{model_id}/usage": {
"get": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "Get model usage count",
@@ -4663,7 +4663,7 @@
}
}
},
"/api/llm/admin/admin/llm/providers": {
"/api/llm/admin/providers": {
"get": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "List LLM providers",
@@ -4743,7 +4743,7 @@
}
}
},
"/api/llm/admin/admin/llm/providers/{provider_id}": {
"/api/llm/admin/providers/{provider_id}": {
"patch": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "Update LLM provider",
@@ -4790,7 +4790,7 @@
}
}
},
"/api/llm/admin/admin/llm/recommended-model": {
"/api/llm/admin/recommended-model": {
"get": {
"tags": ["v2", "admin", "llm", "llm", "admin"],
"summary": "Get recommended model",