routes.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. from core_domain import ServiceHealth
  2. from fastapi import APIRouter, Depends, HTTPException, Query
  3. from sqlalchemy import text
  4. from sqlalchemy.orm import Session
  5. from app.application.services import AgentApplicationService, build_agent_application_service
  6. from app.bootstrap.settings import AgentServiceSettings
  7. from app.db.session import get_db
  8. from app.schemas.agent import (
  9. AgentCreateRequest,
  10. AgentResponse,
  11. AgentRunCreateRequest,
  12. AgentRunExecuteRequest,
  13. AgentRunExecuteResponse,
  14. AgentRunResponse,
  15. AgentRunStatusUpdateRequest,
  16. AgentStatusUpdateRequest,
  17. AgentToolInvocationResponse,
  18. AgentVersionCreateRequest,
  19. AgentVersionResponse,
  20. AgentWorkerExecuteNextRequest,
  21. AgentWorkerExecuteNextResponse,
  22. )
  23. router = APIRouter()
  24. def get_agent_service_settings() -> AgentServiceSettings:
  25. return AgentServiceSettings()
  26. def get_agent_application_service(
  27. db: Session = Depends(get_db),
  28. settings: AgentServiceSettings = Depends(get_agent_service_settings)) -> AgentApplicationService:
  29. return build_agent_application_service(db=db, settings=settings)
  30. @router.get("/health", response_model=ServiceHealth)
  31. def health_check(db: Session = Depends(get_db)) -> ServiceHealth:
  32. db.execute(text("SELECT 1"))
  33. return ServiceHealth(service="agent-service", status="ok", database="ok")
  34. @router.post("", response_model=AgentResponse)
  35. def create_agent(
  36. payload: AgentCreateRequest,
  37. service: AgentApplicationService = Depends(get_agent_application_service)) -> AgentResponse:
  38. entity = service.create_agent(payload)
  39. return AgentResponse.from_entity(entity)
  40. @router.get("", response_model=list[AgentResponse])
  41. def list_agents(
  42. service: AgentApplicationService = Depends(get_agent_application_service)) -> list[AgentResponse]:
  43. return [AgentResponse.from_entity(item) for item in service.list_agents()]
  44. @router.patch("/{agent_id}/status", response_model=AgentResponse)
  45. def update_agent_status(
  46. agent_id: str,
  47. payload: AgentStatusUpdateRequest,
  48. service: AgentApplicationService = Depends(get_agent_application_service)) -> AgentResponse:
  49. entity = service.update_agent_status(agent_id=agent_id, payload=payload)
  50. if entity is None:
  51. raise HTTPException(status_code=404, detail=f"agent not found: {agent_id}")
  52. return AgentResponse.from_entity(entity)
  53. @router.post("/versions", response_model=AgentVersionResponse)
  54. def create_agent_version(
  55. payload: AgentVersionCreateRequest,
  56. service: AgentApplicationService = Depends(get_agent_application_service)) -> AgentVersionResponse:
  57. try:
  58. entity = service.create_agent_version(payload)
  59. except ValueError as exc:
  60. raise HTTPException(status_code=422, detail=str(exc)) from exc
  61. return AgentVersionResponse.from_entity(entity)
  62. @router.get("/versions", response_model=list[AgentVersionResponse])
  63. def list_agent_versions(
  64. agent_id: str = Query(...),
  65. service: AgentApplicationService = Depends(get_agent_application_service)) -> list[AgentVersionResponse]:
  66. return [
  67. AgentVersionResponse.from_entity(item)
  68. for item in service.list_agent_versions(agent_id=agent_id)
  69. ]
  70. @router.post("/runs", response_model=AgentRunResponse)
  71. def create_agent_run(
  72. payload: AgentRunCreateRequest,
  73. service: AgentApplicationService = Depends(get_agent_application_service)) -> AgentRunResponse:
  74. try:
  75. entity = service.create_agent_run(payload)
  76. except ValueError as exc:
  77. raise HTTPException(status_code=422, detail=str(exc)) from exc
  78. return AgentRunResponse.from_entity(entity)
  79. @router.get("/runs", response_model=list[AgentRunResponse])
  80. def list_agent_runs(
  81. agent_id: str | None = Query(default=None),
  82. session_id: str | None = Query(default=None),
  83. service: AgentApplicationService = Depends(get_agent_application_service)) -> list[AgentRunResponse]:
  84. return [
  85. AgentRunResponse.from_entity(item)
  86. for item in service.list_agent_runs(
  87. agent_id=agent_id,
  88. session_id=session_id)
  89. ]
  90. @router.get(
  91. "/runs/{agent_run_id}/tool-invocations",
  92. response_model=list[AgentToolInvocationResponse])
  93. def list_agent_tool_invocations(
  94. agent_run_id: str,
  95. service: AgentApplicationService = Depends(get_agent_application_service)) -> list[AgentToolInvocationResponse]:
  96. return [
  97. AgentToolInvocationResponse.from_entity(item)
  98. for item in service.list_agent_tool_invocations(
  99. agent_run_id=agent_run_id)
  100. ]
  101. @router.post("/runs/{agent_run_id}/status", response_model=AgentRunResponse)
  102. def update_agent_run_status(
  103. agent_run_id: str,
  104. payload: AgentRunStatusUpdateRequest,
  105. service: AgentApplicationService = Depends(get_agent_application_service)) -> AgentRunResponse:
  106. entity = service.update_agent_run_status(agent_run_id=agent_run_id, payload=payload)
  107. if entity is None:
  108. raise HTTPException(status_code=404, detail=f"agent_run not found: {agent_run_id}")
  109. return AgentRunResponse.from_entity(entity)
  110. @router.post("/runs/{agent_run_id}/execute", response_model=AgentRunExecuteResponse)
  111. def execute_agent_run(
  112. agent_run_id: str,
  113. payload: AgentRunExecuteRequest,
  114. service: AgentApplicationService = Depends(get_agent_application_service)) -> AgentRunExecuteResponse:
  115. entity = service.execute_agent_run(agent_run_id=agent_run_id, payload=payload)
  116. if entity is None:
  117. raise HTTPException(status_code=404, detail=f"agent_run not found: {agent_run_id}")
  118. output_json = entity.output_json or {}
  119. model_value = output_json.get("model")
  120. dry_run_value = output_json.get("dry_run")
  121. return AgentRunExecuteResponse(
  122. run=AgentRunResponse.from_entity(entity),
  123. model=model_value if isinstance(model_value, str) else None,
  124. dry_run=dry_run_value if isinstance(dry_run_value, bool) else False)
  125. @router.post("/workers/execute-next", response_model=AgentWorkerExecuteNextResponse)
  126. def execute_next_worker_task(
  127. payload: AgentWorkerExecuteNextRequest,
  128. settings: AgentServiceSettings = Depends(get_agent_service_settings),
  129. service: AgentApplicationService = Depends(get_agent_application_service)) -> AgentWorkerExecuteNextResponse:
  130. result = service.execute_next_claimed_agent_run(
  131. worker_key=payload.worker_key,
  132. lease_seconds=payload.lease_seconds or settings.worker_lease_seconds,
  133. dry_run=payload.dry_run if payload.dry_run is not None else settings.worker_dry_run)
  134. if result is None:
  135. raise HTTPException(status_code=404, detail="queued agent_run not found")
  136. entity, released_lease_count = result
  137. output_json = entity.output_json or {}
  138. model_value = output_json.get("model")
  139. dry_run_value = output_json.get("dry_run")
  140. return AgentWorkerExecuteNextResponse(
  141. run=AgentRunResponse.from_entity(entity),
  142. model=model_value if isinstance(model_value, str) else None,
  143. dry_run=dry_run_value if isinstance(dry_run_value, bool) else False,
  144. released_lease_count=released_lease_count)