Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug fix]: Human evaluation UI breaks when a variant has been deleted #1872

13 changes: 9 additions & 4 deletions agenta-backend/agenta_backend/models/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,17 @@ async def human_evaluation_db_to_pydantic(
variant_name = (
evaluation_variant.variant.variant_name
if isinstance(evaluation_variant.variant_id, uuid.UUID)
else str(evaluation_variant.variant.variant_id)
else str(evaluation_variant.variant_id)
)
variants_names.append(str(variant_name))
variants_ids.append(str(evaluation_variant.variant.id))
revisions.append(str(evaluation_variant.variant_revision.revision))
variants_revision_ids.append(str(evaluation_variant.variant_revision.id))
variants_ids.append(str(evaluation_variant.variant_id))
variant_revision = (
str(evaluation_variant.variant_revision.revision)
if isinstance(evaluation_variant.variant_revision_id, uuid.UUID)
else " None"
)
revisions.append(variant_revision)
variants_revision_ids.append(str(evaluation_variant.variant_revision_id))

return HumanEvaluation(
id=str(evaluation_db.id),
Expand Down
15 changes: 14 additions & 1 deletion agenta-backend/agenta_backend/routers/container_router.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import uuid
import logging

from typing import List, Optional, Union
Expand Down Expand Up @@ -163,8 +164,20 @@ async def construct_app_container_url(

if base_id:
object_db = await db_manager.fetch_base_by_id(base_id)
elif variant_id:
elif variant_id and variant_id != "None":
# NOTE: Backward Compatibility
# ---------------------------
# When a user creates a human evaluation with a variant and later deletes the variant,
# the human evaluation page becomes inaccessible due to the backend raising a
# "'NoneType' object has no attribute 'variant_id'" error. To suppress this error,
# we will return the string "None" as the ID of the variant.
# This change ensures that users can still view their evaluations; however,
# they will no longer be able to access a deployment URL for the deleted variant.
# Therefore, we ensure that variant_id is not "None".
object_db = await db_manager.fetch_app_variant_by_id(variant_id)
else:
# NOTE: required for backward compatibility
object_db = None

# Check app access
if isCloudEE():
Expand Down
50 changes: 38 additions & 12 deletions agenta-backend/agenta_backend/services/db_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2737,24 +2737,50 @@ async def fetch_evaluations_by_resource(resource_type: str, resource_ids: List[s

async with db_engine.get_session() as session:
if resource_type == "variant":
query = select(EvaluationDB).filter(EvaluationDB.variant_id.in_(ids))
elif resource_type == "testset":
query = select(EvaluationDB).filter(EvaluationDB.testset_id.in_(ids))
elif resource_type == "evaluator_config":
result_evaluations = await session.execute(
select(EvaluationDB)
.filter(EvaluationDB.variant_id.in_(ids))
.options(load_only(EvaluationDB.id)) # type: ignore
)
result_human_evaluations = await session.execute(
select(HumanEvaluationDB)
.join(HumanEvaluationVariantDB)
.filter(HumanEvaluationVariantDB.variant_id.in_(ids))
.options(load_only(HumanEvaluationDB.id)) # type: ignore
)
res_evaluations = result_evaluations.scalars().all()
res_human_evaluations = result_human_evaluations.scalars().all()
return res_evaluations + res_human_evaluations

if resource_type == "testset":
result_evaluations = await session.execute(
select(EvaluationDB)
.filter(EvaluationDB.testset_id.in_(ids))
.options(load_only(EvaluationDB.id)) # type: ignore
)
result_human_evaluations = await session.execute(
select(HumanEvaluationDB)
.filter(HumanEvaluationDB.testset_id.in_(ids))
.options(load_only(HumanEvaluationDB.id)) # type: ignore
)
res_evaluations = result_evaluations.scalars().all()
res_human_evaluations = result_human_evaluations.scalars().all()
return res_evaluations + res_human_evaluations

if resource_type == "evaluator_config":
query = (
select(EvaluationDB)
.join(EvaluationDB.evaluator_configs)
.filter(EvaluationEvaluatorConfigDB.evaluator_config_id.in_(ids))
)
else:
raise HTTPException(
status_code=400,
detail=f"resource_type {resource_type} is not supported",
)
result = await session.execute(query)
res = result.scalars().all()
return res

result = await session.execute(query)
res = result.scalars().all()
return res
raise HTTPException(
status_code=400,
detail=f"resource_type {resource_type} is not supported",
)


async def delete_evaluations(evaluation_ids: List[str]) -> None:
Expand Down
27 changes: 19 additions & 8 deletions agenta-web/src/components/Playground/Views/ParametersView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {usePostHogAg} from "@/hooks/usePostHogAg"
import {isDemo} from "@/lib/helpers/utils"
import {useQueryParam} from "@/hooks/useQuery"
import {dynamicComponent, dynamicService} from "@/lib/helpers/dynamic"
import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate"

const PromptVersioningDrawer: any = dynamicComponent(
`PromptVersioningDrawer/PromptVersioningDrawer`,
Expand Down Expand Up @@ -131,14 +132,24 @@ const ParametersView: React.FC<Props> = ({
})
}

const handleDelete = () => {
deleteVariant(() => {
if (variant.persistent) {
return deleteSingleVariant(variant.variantId).then(() => {
onStateChange(false)
})
}
})
const handleDelete = async () => {
try {
if (
!(await checkIfResourceValidForDeletion({
resourceType: "variant",
resourceIds: [variant.variantId],
}))
)
return

deleteVariant(() => {
if (variant.persistent) {
return deleteSingleVariant(variant.variantId).then(() => {
onStateChange(false)
})
}
})
} catch {}
}

useEffect(() => {
Expand Down
Loading