feat: init commint

This commit is contained in:
2026-09-18 15:26:19 +08:00
parent 3b61a767a0
commit 9f47dbb5cc
95 changed files with 7712 additions and 1137 deletions

View File

@@ -24,7 +24,7 @@ from apps.agents.schemas import (
AgentDraftUpdateIn,
AgentRunDetailOut,
AgentRunIn,
AgentRunSummaryOut,
AgentRunListOut,
AgentVersionOut,
)
from apps.agents.services import (
@@ -52,9 +52,12 @@ def serialize_step(step: AgentStepBinding) -> dict:
"skill_name": step.skill_version.definition.name,
"skill_version": step.skill_version.version,
"skill_status": step.skill_version.status,
"skill_output_enforcement": step.skill_version.output_enforcement,
"model_deployment_id": step.model_deployment_id,
"model_display_name": deployment.display_name,
"model_capability": deployment.capability,
"model_structured_output_mode": deployment.structured_output_mode,
"model_structured_output_test_status": deployment.structured_output_test_status,
"input_mapping": step.input_mapping,
}
@@ -151,7 +154,30 @@ def serialize_run(run: AgentRun, detailed: bool = False) -> dict:
"duration_ms": step.duration_ms,
"error_code": step.error_code,
"error_message": step.error_message,
"attempts": list(step.attempts.all()),
"attempts": [
{
"id": attempt.id,
"attempt_type": attempt.attempt_type,
"status": attempt.status,
"raw_output": attempt.raw_output,
"validation_error": attempt.validation_error,
"input_tokens": attempt.input_tokens,
"output_tokens": attempt.output_tokens,
"duration_ms": attempt.duration_ms,
"structured_output": (
attempt.model_invocation.model_snapshot.get(
"structured_output"
)
or {}
if attempt.model_invocation_id
else {}
),
"created_at": attempt.created_at,
}
for attempt in step.attempts.select_related(
"model_invocation"
)
],
}
for step in run.steps.all()
],
@@ -214,6 +240,12 @@ def audit(user, action: str, target_type: str, target_id: str, snapshot: dict) -
)
def validation_http_error(error: Exception) -> HttpError:
if isinstance(error, AgentValidationError) and error.code.startswith("structured_output_"):
return HttpError(400, f"{error.code}: {error}")
return HttpError(400, str(error))
@router.get("", response=list[AgentDefinitionOut])
def list_agents(request):
require_permission(request, "agent.manage")
@@ -246,7 +278,7 @@ def create_agent(request, payload: AgentCreateIn):
)
replace_agent_steps(version, [item.dict() for item in payload.steps])
except (AgentValidationError, SkillValidationError) as error:
raise HttpError(400, str(error)) from error
raise validation_http_error(error) from error
except IntegrityError as error:
raise HttpError(400, "Agent code or step configuration already exists") from error
audit(request.user, "create", "agent", str(definition.id), {"code": definition.code})
@@ -280,7 +312,7 @@ def create_agent_draft(request, agent_id: int):
try:
return serialize_version(ensure_agent_draft(definition, request.user))
except AgentValidationError as error:
raise HttpError(400, str(error)) from error
raise validation_http_error(error) from error
@router.get("/{agent_id}/draft", response=AgentVersionOut)
@@ -309,7 +341,7 @@ def update_agent_draft(request, agent_id: int, payload: AgentDraftUpdateIn):
else:
validate_agent_version(version)
except (AgentValidationError, SkillValidationError, IntegrityError) as error:
raise HttpError(400, str(error)) from error
raise validation_http_error(error) from error
audit(
request.user,
"update_draft",
@@ -341,7 +373,7 @@ def publish_agent(request, agent_id: int):
try:
validate_agent_version(version, publishing=True)
except (AgentValidationError, SkillValidationError) as error:
raise HttpError(400, str(error)) from error
raise validation_http_error(error) from error
version.status = "published"
version.published_by = request.user
version.published_at = timezone.now()
@@ -389,7 +421,7 @@ def start_agent_run(request, agent_id: int, payload: AgentRunIn):
sandbox=sandbox,
)
except (AgentValidationError, SkillValidationError) as error:
raise HttpError(400, str(error)) from error
raise validation_http_error(error) from error
audit(
request.user,
"run_started",
@@ -400,15 +432,32 @@ def start_agent_run(request, agent_id: int, payload: AgentRunIn):
return serialize_run(run, detailed=True)
@runs_router.get("", response=list[AgentRunSummaryOut])
def list_agent_runs(request, status: str | None = None, agent_id: int | None = None):
@runs_router.get("", response=AgentRunListOut)
def list_agent_runs(
request,
status: str | None = None,
agent_id: int | None = None,
page: int = 1,
page_size: int = 20,
):
require_permission(request, "agent.run.view")
queryset = AgentRun.objects.select_related("definition", "agent_version")
if status:
queryset = queryset.filter(status=status)
if agent_id:
queryset = queryset.filter(definition_id=agent_id)
return [serialize_run(run) for run in queryset[:100]]
page = max(page, 1)
page_size = min(max(page_size, 1), 100)
total = queryset.count()
total_pages = (total + page_size - 1) // page_size if total else 0
start = (page - 1) * page_size
return {
"items": [serialize_run(run) for run in queryset[start : start + page_size]],
"page": page,
"page_size": page_size,
"total": total,
"total_pages": total_pages,
}
@runs_router.get("/{public_id}", response=AgentRunDetailOut)