fix(automation): reorder routes — static paths before dynamic {id} to prevent 400 errors

This commit is contained in:
Agent Zero
2026-07-24 10:42:08 +02:00
parent 7dd4865638
commit 992d4b79d4
2 changed files with 186 additions and 186 deletions
+58 -58
View File
@@ -139,6 +139,64 @@ async def create_agent(
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.tool_registry 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"))],
@@ -419,61 +477,3 @@ async def send_agent_message_endpoint(
)
return result
@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.tool_registry 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,
)
+128 -128
View File
@@ -142,6 +142,134 @@ async def create_automation(
return _automation_to_response(automation)
# ─── Recent Runs ───
@router.get(
"/runs/recent",
dependencies=[Depends(require_permission("automation:read"))],
response_model=AutomationRunListResponse,
)
async def list_recent_automation_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 automation runs across all automations (for dashboard)."""
tenant_id = uuid.UUID(current_user["tenant_id"])
items, total = await RunLogService.list_automation_runs(
db, tenant_id, automation_id=None, status=status, limit=limit, offset=0
)
return AutomationRunListResponse(
items=[_run_to_response(r) for r in items],
total=total,
)
# ─── MiniApps ───
@router.get(
"/miniapps",
dependencies=[Depends(require_permission("automation:read"))],
response_model=list[MiniAppResponse],
)
async def list_miniapps(
current_user: dict[str, Any] = Depends(get_current_user),
):
"""List custom MiniApps from plugin config."""
from app.plugins.builtins.kommunikation.miniapp_registry import MiniAppRegistry
registry = MiniAppRegistry()
return registry.list_apps()
@router.post(
"/miniapps",
dependencies=[Depends(require_permission("automation:write"))],
response_model=MiniAppResponse,
status_code=201,
)
async def create_miniapp(
data: MiniAppCreate,
current_user: dict[str, Any] = Depends(get_current_user),
):
"""Create a custom MiniApp definition."""
from app.plugins.builtins.kommunikation.miniapp_registry import MiniAppRegistry
registry = MiniAppRegistry()
registry.register(
app_id=data.app_id,
name=data.name,
icon=data.icon,
description=data.description,
plugin_name="automation",
render_schema=data.render_schema,
)
return MiniAppResponse(
app_id=data.app_id,
name=data.name,
icon=data.icon,
description=data.description,
plugin_name="automation",
render_schema=data.render_schema,
)
@router.delete(
"/miniapps/{app_id}",
dependencies=[Depends(require_permission("automation:delete"))],
)
async def delete_miniapp(
app_id: str,
current_user: dict[str, Any] = Depends(get_current_user),
):
"""Delete a custom MiniApp definition."""
from app.plugins.builtins.kommunikation.miniapp_registry import MiniAppRegistry
registry = MiniAppRegistry()
registry.unregister(app_id)
return {"status": "ok"}
# ─── Settings ───
@router.get(
"/settings",
dependencies=[Depends(require_permission("automation:configure"))],
response_model=AutomationSettingsResponse,
)
async def get_automation_settings(
current_user: dict[str, Any] = Depends(get_current_user),
):
"""Get automation default settings."""
# Return default settings (could be stored in plugin config in the future)
return AutomationSettingsResponse(
default_llm_model="ollama/deepseek-v4-flash",
heartbeat_default_interval=300,
max_concurrent_agents=5,
log_level="INFO",
)
@router.patch(
"/settings",
dependencies=[Depends(require_permission("automation:configure"))],
response_model=AutomationSettingsResponse,
)
async def update_automation_settings(
data: AutomationSettingsUpdate,
current_user: dict[str, Any] = Depends(get_current_user),
):
"""Update automation settings (stored in plugin config)."""
# TODO: Persist settings to plugin config table
# For now, return the updated values as a preview
settings = AutomationSettingsResponse(
default_llm_model=data.default_llm_model or "ollama/deepseek-v4-flash",
heartbeat_default_interval=data.heartbeat_default_interval or 300,
max_concurrent_agents=data.max_concurrent_agents or 5,
log_level=data.log_level or "INFO",
)
return settings
@router.get(
"/{automation_id}",
dependencies=[Depends(require_permission("automation:read"))],
@@ -415,131 +543,3 @@ async def restore_automation_version(
return _automation_to_response(automation)
# ─── Recent Runs ───
@router.get(
"/runs/recent",
dependencies=[Depends(require_permission("automation:read"))],
response_model=AutomationRunListResponse,
)
async def list_recent_automation_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 automation runs across all automations (for dashboard)."""
tenant_id = uuid.UUID(current_user["tenant_id"])
items, total = await RunLogService.list_automation_runs(
db, tenant_id, automation_id=None, status=status, limit=limit, offset=0
)
return AutomationRunListResponse(
items=[_run_to_response(r) for r in items],
total=total,
)
# ─── MiniApps ───
@router.get(
"/miniapps",
dependencies=[Depends(require_permission("automation:read"))],
response_model=list[MiniAppResponse],
)
async def list_miniapps(
current_user: dict[str, Any] = Depends(get_current_user),
):
"""List custom MiniApps from plugin config."""
from app.plugins.builtins.kommunikation.miniapp_registry import MiniAppRegistry
registry = MiniAppRegistry()
return registry.list_apps()
@router.post(
"/miniapps",
dependencies=[Depends(require_permission("automation:write"))],
response_model=MiniAppResponse,
status_code=201,
)
async def create_miniapp(
data: MiniAppCreate,
current_user: dict[str, Any] = Depends(get_current_user),
):
"""Create a custom MiniApp definition."""
from app.plugins.builtins.kommunikation.miniapp_registry import MiniAppRegistry
registry = MiniAppRegistry()
registry.register(
app_id=data.app_id,
name=data.name,
icon=data.icon,
description=data.description,
plugin_name="automation",
render_schema=data.render_schema,
)
return MiniAppResponse(
app_id=data.app_id,
name=data.name,
icon=data.icon,
description=data.description,
plugin_name="automation",
render_schema=data.render_schema,
)
@router.delete(
"/miniapps/{app_id}",
dependencies=[Depends(require_permission("automation:delete"))],
)
async def delete_miniapp(
app_id: str,
current_user: dict[str, Any] = Depends(get_current_user),
):
"""Delete a custom MiniApp definition."""
from app.plugins.builtins.kommunikation.miniapp_registry import MiniAppRegistry
registry = MiniAppRegistry()
registry.unregister(app_id)
return {"status": "ok"}
# ─── Settings ───
@router.get(
"/settings",
dependencies=[Depends(require_permission("automation:configure"))],
response_model=AutomationSettingsResponse,
)
async def get_automation_settings(
current_user: dict[str, Any] = Depends(get_current_user),
):
"""Get automation default settings."""
# Return default settings (could be stored in plugin config in the future)
return AutomationSettingsResponse(
default_llm_model="ollama/deepseek-v4-flash",
heartbeat_default_interval=300,
max_concurrent_agents=5,
log_level="INFO",
)
@router.patch(
"/settings",
dependencies=[Depends(require_permission("automation:configure"))],
response_model=AutomationSettingsResponse,
)
async def update_automation_settings(
data: AutomationSettingsUpdate,
current_user: dict[str, Any] = Depends(get_current_user),
):
"""Update automation settings (stored in plugin config)."""
# TODO: Persist settings to plugin config table
# For now, return the updated values as a preview
settings = AutomationSettingsResponse(
default_llm_model=data.default_llm_model or "ollama/deepseek-v4-flash",
heartbeat_default_interval=data.heartbeat_default_interval or 300,
max_concurrent_agents=data.max_concurrent_agents or 5,
log_level=data.log_level or "INFO",
)
return settings