79 lines
2.8 KiB
Python
79 lines
2.8 KiB
Python
"""Administrator task projections and controls, backed by native Jobs."""
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from pydantic import Field
|
|
from schemas import CamelModel
|
|
from db.session import get_session
|
|
from services.auth import require_admin
|
|
from services.background_tasks.service import task_service
|
|
from services.config_resolver import resolve_runtime_config
|
|
|
|
router = APIRouter(prefix="/api/background-tasks", tags=["background-tasks"], dependencies=[Depends(require_admin)])
|
|
|
|
|
|
class SubmitTask(CamelModel):
|
|
assistant_id: str
|
|
tool_id: str
|
|
instruction: str = Field(min_length=1, max_length=12000)
|
|
request_id: str = Field(min_length=1, max_length=80)
|
|
|
|
|
|
class TaskInput(CamelModel):
|
|
reply: str | None = None
|
|
answers: list[list[str]] | None = None
|
|
|
|
|
|
@router.get("")
|
|
async def list_tasks(assistant_id: str):
|
|
return [record.public() for record in await task_service.repository.list(assistant_id)]
|
|
|
|
|
|
@router.post("")
|
|
async def submit_task(body: SubmitTask, db=Depends(get_session)):
|
|
cfg = await resolve_runtime_config(db, body.assistant_id)
|
|
if cfg.type != "prompt" or cfg.runtimeMode != "pipeline":
|
|
raise HTTPException(400, "后台任务仅支持提示词 Pipeline")
|
|
bound = {binding.tool_id for binding in cfg.tool_bindings}
|
|
tool = next((tool for tool in cfg.tools if tool.id == body.tool_id and tool.id in bound and tool.type == "task"), None)
|
|
if not tool:
|
|
raise HTTPException(400, "助手未绑定该任务工具")
|
|
try:
|
|
return await task_service.submit(assistant_id=body.assistant_id, conversation_id="web_" + body.assistant_id, tool=tool, instruction=body.instruction, invocation_id=body.request_id)
|
|
except ValueError as exc:
|
|
raise HTTPException(400, str(exc)) from exc
|
|
|
|
|
|
@router.get("/{task_id}")
|
|
async def get_task(task_id: str):
|
|
try:
|
|
return (await task_service.get(task_id)).public()
|
|
except ValueError as exc:
|
|
raise HTTPException(404, str(exc)) from exc
|
|
|
|
|
|
@router.post("/{task_id}/cancel")
|
|
async def cancel_task(task_id: str):
|
|
try:
|
|
return await task_service.cancel(task_id)
|
|
except ValueError as exc:
|
|
raise HTTPException(404, str(exc)) from exc
|
|
|
|
|
|
@router.post("/{task_id}/input")
|
|
async def send_input(task_id: str, body: TaskInput):
|
|
try:
|
|
return await task_service.send_input(task_id, body.model_dump(exclude_none=True))
|
|
except ValueError as exc:
|
|
raise HTTPException(400, str(exc)) from exc
|
|
except Exception as exc:
|
|
raise HTTPException(502, "远端暂未接受回复,请稍后重试") from exc
|
|
|
|
|
|
@router.post("/{task_id}/refresh")
|
|
async def refresh_task(task_id: str):
|
|
try:
|
|
return await task_service.reconcile(task_id)
|
|
except ValueError as exc:
|
|
raise HTTPException(404, str(exc)) from exc
|
|
except Exception as exc:
|
|
raise HTTPException(502, "暂时无法核查远端状态") from exc
|