gateway.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. from datetime import datetime
  2. from typing import TYPE_CHECKING, Literal
  3. from pydantic import BaseModel
  4. if TYPE_CHECKING:
  5. from app.db.models import ApiKey, AppApiKey, AppDefinition, AppInvocationAudit, GatewayRequestAudit
  6. class DownstreamServiceHealth(BaseModel):
  7. service: str
  8. status: str
  9. url: str
  10. status_code: int | None = None
  11. error_message: str | None = None
  12. class GatewayServicesHealthResponse(BaseModel):
  13. service: str = "api-gateway"
  14. status: str
  15. downstream_services: list[DownstreamServiceHealth]
  16. class GatewayRequestAuditResponse(BaseModel):
  17. id: str
  18. request_id: str
  19. method: str
  20. path: str
  21. query_string: str | None = None
  22. target_service: str | None = None
  23. target_url: str | None = None
  24. status_code: int | None = None
  25. duration_ms: int
  26. client_host: str | None = None
  27. user_agent: str | None = None
  28. error_message: str | None = None
  29. created_time: datetime
  30. @classmethod
  31. def from_entity(cls, entity: "GatewayRequestAudit") -> "GatewayRequestAuditResponse":
  32. return cls.model_validate(entity, from_attributes=True)
  33. class GatewayAuditServiceStats(BaseModel):
  34. target_service: str
  35. request_count: int
  36. error_count: int
  37. average_duration_ms: float
  38. class GatewayAuditStatsResponse(BaseModel):
  39. total_request_count: int
  40. total_error_count: int
  41. services: list[GatewayAuditServiceStats]
  42. class ApiKeyCreateRequest(BaseModel):
  43. name: str
  44. scopes: str | None = None
  45. expires_time: datetime | None = None
  46. class ApiKeyListRequest(BaseModel):
  47. pass
  48. class ApiKeyCreateResponse(BaseModel):
  49. id: str
  50. name: str
  51. key_prefix: str
  52. api_key: str
  53. status: str
  54. scopes: str | None = None
  55. expires_time: datetime | None = None
  56. created_time: datetime
  57. class ApiKeyResponse(BaseModel):
  58. id: str
  59. name: str
  60. key_prefix: str
  61. status: str
  62. scopes: str | None = None
  63. expires_time: datetime | None = None
  64. last_used_time: datetime | None = None
  65. created_time: datetime
  66. @classmethod
  67. def from_entity(cls, entity: "ApiKey") -> "ApiKeyResponse":
  68. return cls.model_validate(entity, from_attributes=True)
  69. ApiKeyStatus = Literal["active", "disabled", "revoked"]
  70. class ApiKeyStatusUpdateRequest(BaseModel):
  71. status: ApiKeyStatus
  72. class ApiKeyStatusPostRequest(ApiKeyStatusUpdateRequest):
  73. api_key_id: str
  74. # ── Application ──────────────────────────────────────────────────────────────
  75. AppStatus = Literal["draft", "published", "disabled"]
  76. AppTargetType = Literal["agent", "team"]
  77. class AppCreateRequest(BaseModel):
  78. code: str
  79. name: str
  80. description: str | None = None
  81. target_type: AppTargetType
  82. target_id: str
  83. owner_user_id: str | None = None
  84. settings_json: str | None = None
  85. class AppListRequest(BaseModel):
  86. pass
  87. class AppDetailRequest(BaseModel):
  88. app_id: str
  89. class AppUpdateRequest(BaseModel):
  90. app_id: str
  91. name: str | None = None
  92. description: str | None = None
  93. target_type: AppTargetType | None = None
  94. target_id: str | None = None
  95. settings_json: str | None = None
  96. class AppStatusUpdateRequest(BaseModel):
  97. app_id: str
  98. status: AppStatus
  99. class AppResponse(BaseModel):
  100. id: str
  101. code: str
  102. name: str
  103. description: str | None = None
  104. status: str
  105. target_type: str
  106. target_id: str
  107. owner_user_id: str | None = None
  108. settings_json: str | None = None
  109. created_time: datetime
  110. updated_time: datetime
  111. @classmethod
  112. def from_entity(cls, entity: "AppDefinition") -> "AppResponse":
  113. return cls.model_validate(entity, from_attributes=True)
  114. # ── App API Key ──────────────────────────────────────────────────────────────
  115. AppApiKeyStatus = Literal["active", "disabled", "revoked"]
  116. class AppApiKeyCreateRequest(BaseModel):
  117. name: str
  118. scopes: str | None = None
  119. expires_time: datetime | None = None
  120. class AppApiKeyCreateResponse(BaseModel):
  121. id: str
  122. app_id: str
  123. name: str
  124. key_prefix: str
  125. api_key: str
  126. status: str
  127. scopes: str | None = None
  128. expires_time: datetime | None = None
  129. created_time: datetime
  130. class AppApiKeyListRequest(BaseModel):
  131. pass
  132. class AppApiKeyResponse(BaseModel):
  133. id: str
  134. app_id: str
  135. name: str
  136. key_prefix: str
  137. status: str
  138. scopes: str | None = None
  139. expires_time: datetime | None = None
  140. last_used_time: datetime | None = None
  141. created_time: datetime
  142. @classmethod
  143. def from_entity(cls, entity: "AppApiKey") -> "AppApiKeyResponse":
  144. return cls.model_validate(entity, from_attributes=True)
  145. class AppApiKeyStatusUpdateRequest(BaseModel):
  146. api_key_id: str
  147. status: AppApiKeyStatus
  148. # ── App Invocation Audit ─────────────────────────────────────────────────────
  149. class AppAuditListRequest(BaseModel):
  150. limit: int = 100
  151. class AppInvocationAuditResponse(BaseModel):
  152. id: str
  153. app_id: str
  154. api_key_prefix: str | None = None
  155. request_id: str
  156. session_id: str | None = None
  157. run_request_id: str | None = None
  158. target_type: str
  159. target_id: str
  160. invoke_type: str
  161. status: str
  162. duration_ms: int
  163. error_code: str | None = None
  164. error_message: str | None = None
  165. client_metadata_json: str | None = None
  166. created_time: datetime
  167. @classmethod
  168. def from_entity(cls, entity: "AppInvocationAudit") -> "AppInvocationAuditResponse":
  169. return cls.model_validate(entity, from_attributes=True)
  170. # ── OpenAPI External Invocation ──────────────────────────────────────────────
  171. class OpenApiChatRequest(BaseModel):
  172. user_id: str | None = None
  173. session_id: str | None = None
  174. message: str
  175. inputs: dict[str, object] | None = None
  176. metadata: dict[str, object] | None = None
  177. class OpenApiChatResponse(BaseModel):
  178. request_id: str
  179. app_code: str
  180. session_id: str
  181. run_request_id: str
  182. target_type: str
  183. target_id: str
  184. status: str
  185. output_text: str | None = None
  186. output_json: dict[str, object] | None = None
  187. error: str | None = None