PMFlow/backend/app/api/ai_steward_api/routes_reply_iteration.py

264 lines
9.4 KiB
Python

from __future__ import annotations
from fastapi import Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from ...core.response import success_response
from ...dependencies.permissions import require_manager_user
from ...dependencies.tenant import get_tenant_id
from ...models import User
from ...schemas.reply_iteration import (
FeedbackAssetPromoteRequest,
PromptReleaseCreateRequest,
PromptTrialCreateRequest,
PromptTrialDecisionRequest,
ReplyIterationCandidateCreateRequest,
ReplyIterationJudgeRunCreateRequest,
)
from ...services.prompt_release import PromptReleaseService
from ...services.reply_iteration import ReplyIterationService
from .shared import *
@router.post("/feedback-center/items/{record_id}/promote")
async def promote_feedback_center_item_to_asset(
record_id: int,
request: FeedbackAssetPromoteRequest,
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
try:
data = await ReplyIterationService(db).promote_feedback_record(
tenant_id=effective_tenant_id,
record_id=record_id,
actor_id=int(current_user.id),
asset_type=request.asset_type,
prompt_key=request.prompt_key,
workflow_type=request.workflow_type,
notes=request.notes,
pair_with_asset_id=request.pair_with_asset_id,
pair_role=request.pair_role,
pair_reason=request.pair_reason,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return success_response(data)
@router.get("/reply-iteration/assets")
async def list_reply_iteration_assets(
asset_type: str | None = Query(default=None),
prompt_key: str | None = Query(default=None),
limit: int = Query(default=20, ge=1, le=100),
offset: int = Query(default=0, ge=0),
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
data = await ReplyIterationService(db).list_assets(
tenant_id=effective_tenant_id,
asset_type=asset_type,
prompt_key=prompt_key,
limit=limit,
offset=offset,
)
return success_response(data)
@router.post("/reply-iteration/judge-runs")
async def create_reply_iteration_judge_run(
request: ReplyIterationJudgeRunCreateRequest,
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
try:
data = await ReplyIterationService(db).create_judge_run(
tenant_id=effective_tenant_id,
asset_id=request.asset_id,
actor_id=int(current_user.id),
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return success_response(data)
@router.get("/reply-iteration/judge-runs")
async def list_reply_iteration_judge_runs(
limit: int = Query(default=20, ge=1, le=100),
offset: int = Query(default=0, ge=0),
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
return success_response(
await ReplyIterationService(db).list_judge_runs(
tenant_id=effective_tenant_id,
limit=limit,
offset=offset,
)
)
@router.post("/reply-iteration/candidates")
async def create_reply_iteration_candidate(
request: ReplyIterationCandidateCreateRequest,
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
try:
data = await ReplyIterationService(db).create_optimizer_candidate(
tenant_id=effective_tenant_id,
judge_run_id=request.judge_run_id,
actor_id=int(current_user.id),
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return success_response(data)
@router.get("/reply-iteration/candidates")
async def list_reply_iteration_candidates(
limit: int = Query(default=20, ge=1, le=100),
offset: int = Query(default=0, ge=0),
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
return success_response(
await ReplyIterationService(db).list_candidates(
tenant_id=effective_tenant_id,
limit=limit,
offset=offset,
)
)
@router.post("/reply-iteration/prompt-releases")
async def create_prompt_release(
request: PromptReleaseCreateRequest,
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
try:
data = await PromptReleaseService(db).create_release(
tenant_id=effective_tenant_id,
prompt_key=request.prompt_key,
body_snapshot=request.body_snapshot,
created_by=int(current_user.id),
notes=request.notes,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return success_response(data)
@router.get("/reply-iteration/prompt-releases")
async def list_prompt_releases(
prompt_key: str | None = Query(default=None),
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
return success_response(
await PromptReleaseService(db).list_releases(
tenant_id=effective_tenant_id,
prompt_key=prompt_key,
)
)
@router.post("/reply-iteration/prompt-releases/{release_id}/activate")
async def activate_prompt_release(
release_id: int,
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
try:
data = await PromptReleaseService(db).activate_release(
tenant_id=effective_tenant_id,
release_id=release_id,
actor_id=int(current_user.id),
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return success_response(data)
@router.get("/reply-iteration/trials")
async def list_prompt_release_trials(
limit: int = Query(default=20, ge=1, le=100),
offset: int = Query(default=0, ge=0),
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
return success_response(
await ReplyIterationService(db).list_trials(
tenant_id=effective_tenant_id,
limit=limit,
offset=offset,
)
)
@router.post("/reply-iteration/trials")
async def create_prompt_release_trial(
request: PromptTrialCreateRequest,
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
try:
data = await ReplyIterationService(db).create_trial(
tenant_id=effective_tenant_id,
actor_id=int(current_user.id),
title=request.title,
hypothesis=request.hypothesis,
target_metric=request.target_metric,
prompt_key=request.prompt_key,
baseline_release_id=request.baseline_release_id,
candidate_release_id=request.candidate_release_id,
scope_json=request.scope_json,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return success_response(data)
@router.post("/reply-iteration/trials/{trial_id}/decision")
async def decide_prompt_release_trial(
trial_id: int,
request: PromptTrialDecisionRequest,
current_user: User = Depends(require_manager_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
try:
data = await ReplyIterationService(db).decide_trial(
tenant_id=effective_tenant_id,
trial_id=trial_id,
actor_id=int(current_user.id),
decision=request.decision,
result_summary=request.result_summary,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return success_response(data)