656 lines
21 KiB
Python
656 lines
21 KiB
Python
"""API routes for the Agents plugin — /api/v1/agents.
|
|
|
|
Endpoints: agent definitions CRUD, execute, test-run, runs, versions, tools.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import uuid
|
|
from datetime import UTC
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.db import get_db
|
|
from app.deps import get_current_user, require_permission
|
|
from app.plugins.builtins.automation.models import (
|
|
AgentDefinition,
|
|
AgentRun,
|
|
AgentVersion,
|
|
)
|
|
from app.plugins.builtins.automation.schemas import (
|
|
AgentDefinitionCreate,
|
|
AgentDefinitionListResponse,
|
|
AgentDefinitionResponse,
|
|
AgentDefinitionUpdate,
|
|
AgentMessageRequest,
|
|
AgentRunListResponse,
|
|
AgentRunResponse,
|
|
AgentVersionListResponse,
|
|
AgentVersionResponse,
|
|
)
|
|
from app.plugins.builtins.automation.services import (
|
|
AgentService,
|
|
RunLogService,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/api/v1/agents", tags=["agents"])
|
|
|
|
|
|
# ─── Helper Functions ───
|
|
|
|
|
|
def _agent_to_response(a: AgentDefinition) -> AgentDefinitionResponse:
|
|
"""Convert AgentDefinition model to response schema."""
|
|
return AgentDefinitionResponse(
|
|
id=str(a.id),
|
|
name=a.name,
|
|
description=a.description or "",
|
|
llm_model=a.llm_model,
|
|
system_prompt=a.system_prompt or "",
|
|
tool_ids=[str(t) for t in (a.tool_ids or [])],
|
|
heartbeat_interval_seconds=a.heartbeat_interval_seconds,
|
|
mode=a.mode,
|
|
is_active=a.is_active,
|
|
max_executions_per_hour=a.max_executions_per_hour,
|
|
max_duration_seconds=a.max_duration_seconds,
|
|
budget_limit_usd=a.budget_limit_usd,
|
|
temperature=a.temperature,
|
|
max_tokens=a.max_tokens,
|
|
max_steps=a.max_steps,
|
|
trace_mode=a.trace_mode,
|
|
skill_ids=[str(s) for s in (a.skill_ids or [])],
|
|
trigger_config=a.trigger_config or {},
|
|
ai_use_case_metadata=a.ai_use_case_metadata or {},
|
|
created_by=str(a.created_by) if a.created_by else None,
|
|
created_at=a.created_at.isoformat() if a.created_at else None,
|
|
updated_at=a.updated_at.isoformat() if a.updated_at else None,
|
|
)
|
|
|
|
|
|
def _agent_run_to_response(r: AgentRun) -> AgentRunResponse:
|
|
"""Convert AgentRun model to response schema."""
|
|
return AgentRunResponse(
|
|
id=str(r.id),
|
|
agent_id=str(r.agent_id),
|
|
status=r.status,
|
|
started_at=r.started_at.isoformat() if r.started_at else "",
|
|
completed_at=r.completed_at.isoformat() if r.completed_at else None,
|
|
duration_seconds=r.duration_seconds,
|
|
result=r.result,
|
|
error=r.error,
|
|
cost_usd=r.cost_usd,
|
|
trigger_type=r.trigger_type,
|
|
trigger_data=r.trigger_data or {},
|
|
created_at=r.created_at.isoformat() if r.created_at else None,
|
|
)
|
|
|
|
|
|
def _agent_version_to_response(v: AgentVersion) -> AgentVersionResponse:
|
|
"""Convert AgentVersion model to response schema."""
|
|
return AgentVersionResponse(
|
|
id=str(v.id),
|
|
agent_id=str(v.agent_id),
|
|
version_number=v.version_number,
|
|
snapshot=v.snapshot or {},
|
|
changed_by=str(v.changed_by) if v.changed_by else None,
|
|
created_at=v.created_at.isoformat() if v.created_at else None,
|
|
)
|
|
|
|
|
|
# ─── CRUD Endpoints ───
|
|
|
|
|
|
@router.get(
|
|
"",
|
|
dependencies=[Depends(require_permission("agents:read"))],
|
|
response_model=AgentDefinitionListResponse,
|
|
)
|
|
async def list_agents(
|
|
is_active: bool | None = Query(None),
|
|
mode: str | None = Query(None),
|
|
limit: int = Query(50, ge=1, le=200),
|
|
offset: int = Query(0, ge=0),
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""List agent definitions with optional filters."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
user_id = uuid.UUID(current_user["user_id"])
|
|
is_system_admin = current_user.get("is_system_admin", False)
|
|
items, total = await AgentService.list(
|
|
db, tenant_id, is_active=is_active, mode=mode, limit=limit, offset=offset,
|
|
user_id=user_id, is_system_admin=is_system_admin,
|
|
)
|
|
return AgentDefinitionListResponse(
|
|
items=[_agent_to_response(a) for a in items],
|
|
total=total,
|
|
)
|
|
|
|
|
|
@router.post(
|
|
"/",
|
|
dependencies=[Depends(require_permission("agents:write"))],
|
|
response_model=AgentDefinitionResponse,
|
|
status_code=201,
|
|
)
|
|
async def create_agent(
|
|
data: AgentDefinitionCreate,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Create a new agent definition."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
user_id = uuid.UUID(current_user["user_id"])
|
|
agent = await AgentService.create(db, tenant_id, data.model_dump(), user_id=user_id)
|
|
return _agent_to_response(agent)
|
|
|
|
|
|
|
|
@router.get(
|
|
"/tools",
|
|
dependencies=[Depends(require_permission("agents:read"))],
|
|
)
|
|
async def list_tools(
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
):
|
|
"""List available tools from the tool registry."""
|
|
try:
|
|
from app.plugins.builtins.ai_assistant.contracts import (
|
|
get_tool_registry,
|
|
)
|
|
|
|
registry = get_tool_registry()
|
|
tools = registry.list_tools()
|
|
return {
|
|
"items": [
|
|
{
|
|
"id": t.get("id", t.get("name", "")),
|
|
"name": t.get("name", ""),
|
|
"description": t.get("description", ""),
|
|
"plugin": t.get("plugin", ""),
|
|
}
|
|
for t in tools
|
|
],
|
|
"total": len(tools),
|
|
}
|
|
except ImportError:
|
|
return {"items": [], "total": 0, "note": "Tool registry not available"}
|
|
except Exception as e:
|
|
logger.exception("Failed to list tools")
|
|
return {"items": [], "total": 0, "error": str(e)}
|
|
|
|
|
|
# ─── Recent Runs ───
|
|
|
|
|
|
@router.get(
|
|
"/runs/recent",
|
|
dependencies=[Depends(require_permission("agents:read"))],
|
|
response_model=AgentRunListResponse,
|
|
)
|
|
async def list_recent_agent_runs(
|
|
limit: int = Query(20, ge=1, le=100),
|
|
status: str | None = Query(None),
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""List recent agent runs across all agents (for dashboard)."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
items, total = await RunLogService.list_agent_runs(
|
|
db, tenant_id, agent_id=None, status=status, limit=limit, offset=0
|
|
)
|
|
return AgentRunListResponse(
|
|
items=[_agent_run_to_response(r) for r in items],
|
|
total=total,
|
|
)
|
|
@router.get(
|
|
"/{agent_id}",
|
|
dependencies=[Depends(require_permission("agents:read"))],
|
|
response_model=AgentDefinitionResponse,
|
|
)
|
|
async def get_agent(
|
|
agent_id: str,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Get a single agent definition by ID."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
agent = await AgentService.get_by_id(db, tenant_id, aid)
|
|
if agent is None:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
return _agent_to_response(agent)
|
|
|
|
|
|
@router.patch(
|
|
"/{agent_id}",
|
|
dependencies=[Depends(require_permission("agents:write"))],
|
|
response_model=AgentDefinitionResponse,
|
|
)
|
|
async def update_agent(
|
|
agent_id: str,
|
|
data: AgentDefinitionUpdate,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Update an existing agent definition."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
user_id = uuid.UUID(current_user["user_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
agent = await AgentService.update(
|
|
db, tenant_id, aid, data.model_dump(exclude_none=True), user_id=user_id
|
|
)
|
|
if agent is None:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
return _agent_to_response(agent)
|
|
|
|
|
|
# ─── AI Use-Case Metadata ───
|
|
|
|
|
|
class AIUseCaseMetadataUpdate(BaseModel):
|
|
"""Update AI use-case metadata for an agent."""
|
|
|
|
intended_purpose: str | None = None
|
|
owner: str | None = None
|
|
data_categories: list[str] | None = None
|
|
allowed_providers: list[str] | None = None
|
|
allowed_models: list[str] | None = None
|
|
allowed_actions: list[str] | None = None
|
|
oversight_policy: str | None = None
|
|
risk_class: str | None = None
|
|
human_review_required: bool | None = None
|
|
|
|
|
|
@router.get(
|
|
"/{agent_id}/ai-use-case",
|
|
dependencies=[Depends(require_permission("agents:read"))],
|
|
)
|
|
async def get_ai_use_case(
|
|
agent_id: str,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Get AI use-case metadata for an agent."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
agent = await AgentService.get_by_id(db, tenant_id, aid)
|
|
if agent is None:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
return {"agent_id": agent_id, "ai_use_case_metadata": agent.ai_use_case_metadata or {}}
|
|
|
|
|
|
@router.patch(
|
|
"/{agent_id}/ai-use-case",
|
|
dependencies=[Depends(require_permission("agents:write"))],
|
|
)
|
|
async def update_ai_use_case(
|
|
agent_id: str,
|
|
data: AIUseCaseMetadataUpdate,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Update AI use-case metadata for an agent."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
user_id = uuid.UUID(current_user["user_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
agent = await AgentService.get_by_id(db, tenant_id, aid)
|
|
if agent is None:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
|
|
# Merge with existing metadata (partial update).
|
|
current = dict(agent.ai_use_case_metadata or {})
|
|
updates = data.model_dump(exclude_none=True)
|
|
current.update(updates)
|
|
|
|
# Validate the merged metadata against the agent config.
|
|
from app.ai.ai_use_case import AIUseCaseMetadata, validate_ai_use_case
|
|
|
|
try:
|
|
metadata = AIUseCaseMetadata(**current)
|
|
except Exception as e:
|
|
raise HTTPException(status_code=400, detail=f"Invalid AI use-case metadata: {e}") from None
|
|
warnings = validate_ai_use_case(metadata, agent)
|
|
|
|
updated = await AgentService.update(
|
|
db, tenant_id, aid, {"ai_use_case_metadata": current}, user_id=user_id
|
|
)
|
|
if updated is None:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
return {
|
|
"agent_id": agent_id,
|
|
"ai_use_case_metadata": current,
|
|
"warnings": warnings,
|
|
}
|
|
|
|
|
|
@router.delete(
|
|
"/{agent_id}",
|
|
dependencies=[Depends(require_permission("agents:delete"))],
|
|
)
|
|
async def delete_agent(
|
|
agent_id: str,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Delete an agent definition."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
success = await AgentService.delete(db, tenant_id, aid)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
return {"status": "ok"}
|
|
|
|
|
|
# ─── Execute / Test-Run ───
|
|
|
|
|
|
@router.post(
|
|
"/{agent_id}/execute",
|
|
dependencies=[Depends(require_permission("agents:execute"))],
|
|
)
|
|
async def execute_agent(
|
|
agent_id: str,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Execute an agent definition."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
agent = await AgentService.get_by_id(db, tenant_id, aid)
|
|
if agent is None:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
if not agent.is_active:
|
|
raise HTTPException(status_code=400, detail="Agent is not active")
|
|
|
|
# Create run log entry
|
|
run = AgentRun(
|
|
tenant_id=tenant_id,
|
|
agent_id=aid,
|
|
status="running",
|
|
started_at=__import__("datetime").datetime.now(__import__("datetime").timezone.utc),
|
|
trigger_type="manual",
|
|
trigger_data={"triggered_by": str(uuid.UUID(current_user["user_id"]))},
|
|
)
|
|
db.add(run)
|
|
await db.flush()
|
|
|
|
# Execute agent via agent runner
|
|
from app.plugins.builtins.automation.agent_runner import run_agent
|
|
|
|
run_id = str(run.id)
|
|
await db.commit()
|
|
|
|
# Run agent
|
|
result = await run_agent(
|
|
ctx={"tenant_id": str(tenant_id), "user_id": current_user["user_id"]},
|
|
agent_id=str(aid),
|
|
trigger_type="manual",
|
|
trigger_data={"triggered_by": current_user["user_id"]},
|
|
)
|
|
|
|
# Update run with results
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import update as sa_update
|
|
now = datetime.now(UTC)
|
|
async with db.begin():
|
|
await db.execute(
|
|
sa_update(AgentRun)
|
|
.where(AgentRun.id == run.id)
|
|
.values(
|
|
status=result.get("status", "completed"),
|
|
completed_at=now,
|
|
duration_seconds=0.0,
|
|
result=result,
|
|
output_data=result,
|
|
)
|
|
)
|
|
|
|
return {"status": result.get("status", "ok"), "run_id": run_id, "result": result}
|
|
|
|
|
|
@router.post(
|
|
"/{agent_id}/test-run",
|
|
dependencies=[Depends(require_permission("agents:execute"))],
|
|
)
|
|
async def test_run_agent(
|
|
agent_id: str,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Test-run an agent definition (validates config without full execution)."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
agent = await AgentService.get_by_id(db, tenant_id, aid)
|
|
if agent is None:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
|
|
return {
|
|
"status": "ok",
|
|
"agent": _agent_to_response(agent),
|
|
"validation": {
|
|
"valid": True,
|
|
"llm_model": agent.llm_model,
|
|
"tool_count": len(agent.tool_ids or []),
|
|
"mode": agent.mode,
|
|
},
|
|
}
|
|
|
|
|
|
# ─── Runs ───
|
|
|
|
|
|
@router.get(
|
|
"/{agent_id}/runs",
|
|
dependencies=[Depends(require_permission("agents:read"))],
|
|
response_model=AgentRunListResponse,
|
|
)
|
|
async def list_agent_runs(
|
|
agent_id: str,
|
|
status: str | None = Query(None),
|
|
limit: int = Query(50, ge=1, le=200),
|
|
offset: int = Query(0, ge=0),
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""List run logs for an agent definition."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
items, total = await RunLogService.list_agent_runs(
|
|
db, tenant_id, agent_id=aid, status=status, limit=limit, offset=offset
|
|
)
|
|
return AgentRunListResponse(
|
|
items=[_agent_run_to_response(r) for r in items],
|
|
total=total,
|
|
)
|
|
|
|
|
|
# ─── Versions ───
|
|
|
|
|
|
@router.get(
|
|
"/{agent_id}/versions",
|
|
dependencies=[Depends(require_permission("agents:read"))],
|
|
response_model=AgentVersionListResponse,
|
|
)
|
|
async def list_agent_versions(
|
|
agent_id: str,
|
|
limit: int = Query(50, ge=1, le=200),
|
|
offset: int = Query(0, ge=0),
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""List version history for an agent definition."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
items, total = await AgentService.get_versions(
|
|
db, tenant_id, aid, limit=limit, offset=offset
|
|
)
|
|
return AgentVersionListResponse(
|
|
items=[_agent_version_to_response(v) for v in items],
|
|
total=total,
|
|
)
|
|
|
|
|
|
@router.post(
|
|
"/{agent_id}/versions/{version_id}/restore",
|
|
dependencies=[Depends(require_permission("agents:write"))],
|
|
response_model=AgentDefinitionResponse,
|
|
)
|
|
async def restore_agent_version(
|
|
agent_id: str,
|
|
version_id: str,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Restore an agent definition from a specific version."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
user_id = uuid.UUID(current_user["user_id"])
|
|
try:
|
|
aid = uuid.UUID(agent_id)
|
|
vid = uuid.UUID(version_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid ID") from None
|
|
|
|
agent = await AgentService.restore_version(
|
|
db, tenant_id, aid, vid, user_id=user_id
|
|
)
|
|
if agent is None:
|
|
raise HTTPException(status_code=404, detail="Agent or version not found")
|
|
return _agent_to_response(agent)
|
|
|
|
|
|
# ─── Tools ───
|
|
|
|
|
|
@router.post(
|
|
"/{id}/send-message",
|
|
dependencies=[Depends(require_permission("agents:execute"))],
|
|
)
|
|
async def send_agent_message_endpoint(
|
|
id: str,
|
|
body: AgentMessageRequest,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Send a message from one agent to another."""
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
try:
|
|
aid = uuid.UUID(id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
# Verify the source agent exists
|
|
agent = await AgentService.get_by_id(db, tenant_id, aid)
|
|
if agent is None:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
if not agent.is_active:
|
|
raise HTTPException(status_code=400, detail="Agent is not active")
|
|
|
|
from app.plugins.builtins.automation.agent_comm import send_agent_message
|
|
|
|
result = await send_agent_message(
|
|
from_agent_id=str(aid),
|
|
to_agent_name=body.to_agent_name,
|
|
message=body.message,
|
|
db=db,
|
|
tenant_id=tenant_id,
|
|
)
|
|
return result
|
|
|
|
|
|
|
|
# ─── Punkt 7: SSE Streaming Endpoint (agent_stream.py) ─────────────────────
|
|
|
|
|
|
@router.post("/{id}/stream")
|
|
async def stream_agent_run(
|
|
id: str,
|
|
body: AgentMessageRequest,
|
|
current_user: dict[str, Any] = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Stream an agent run via Server-Sent Events (SSE).
|
|
|
|
Uses ``app.ai.agent_stream.stream_react_loop`` to emit step events
|
|
in real-time as the agent processes.
|
|
"""
|
|
from fastapi.responses import StreamingResponse
|
|
from app.ai.agent_stream import stream_react_loop
|
|
from app.plugins.builtins.ai_assistant.contracts import get_tool_registry
|
|
|
|
tenant_id = uuid.UUID(current_user["tenant_id"])
|
|
user_id = uuid.UUID(current_user["user_id"])
|
|
try:
|
|
aid = uuid.UUID(id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid agent ID") from None
|
|
|
|
agent = await AgentService.get_by_id(db, tenant_id, aid)
|
|
if agent is None:
|
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
if not agent.is_active:
|
|
raise HTTPException(status_code=400, detail="Agent is not active")
|
|
|
|
registry = get_tool_registry()
|
|
tool_ids: list[str] = list(agent.tool_ids or [])
|
|
tools = registry.get_by_names(tool_ids) if tool_ids else []
|
|
tool_schemas = [t.to_openai_schema() for t in tools] if tools else []
|
|
|
|
return StreamingResponse(
|
|
stream_react_loop(
|
|
agent_definition=agent,
|
|
user_message=body.message,
|
|
tools=tool_schemas,
|
|
tool_registry=registry,
|
|
db=db,
|
|
tenant_id=tenant_id,
|
|
user_id=user_id,
|
|
agent_run_id=aid,
|
|
),
|
|
media_type="text/event-stream",
|
|
)
|