Coverage for aipyapp/cli/cli_agent.py: 0%

150 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-08-11 12:02 +0200

1#!/usr/bin/env python 

2# -*- coding: utf-8 -*- 

3 

4from typing import Dict, Any, Optional 

5from datetime import datetime 

6 

7import uvicorn 

8from fastapi import FastAPI, HTTPException, BackgroundTasks 

9from pydantic import BaseModel, Field 

10 

11from loguru import logger 

12 

13from .. import T, __version__ 

14from ..aipy.agent_taskmgr import AgentTaskManager 

15from ..display import DisplayManager 

16 

17# API 数据模型 

18class TaskRequest(BaseModel): 

19 instruction: str = Field(..., description="任务指令") 

20 metadata: Optional[Dict[str, Any]] = Field(default=None, description="任务元数据") 

21 

22class TaskResponse(BaseModel): 

23 task_id: str = Field(..., description="任务ID") 

24 status: str = Field(..., description="任务状态") 

25 message: str = Field(..., description="响应消息") 

26 

27class TaskStatusResponse(BaseModel): 

28 task_id: str 

29 instruction: str 

30 status: str 

31 created_at: str 

32 started_at: Optional[str] 

33 completed_at: Optional[str] 

34 error: Optional[str] 

35 

36class TaskResultResponse(BaseModel): 

37 task_id: str 

38 instruction: str 

39 status: str 

40 created_at: str 

41 started_at: Optional[str] 

42 completed_at: Optional[str] 

43 error: Optional[str] 

44 output: Optional[Dict[str, Any]] 

45 

46# 全局变量 

47agent_manager: Optional[AgentTaskManager] = None 

48app = FastAPI( 

49 title="AIPython Agent API", 

50 description="HTTP API for n8n integration with AIPython", 

51 version=__version__ 

52) 

53 

54@app.on_event("startup") 

55async def startup_event(): 

56 """应用启动时初始化""" 

57 logger.info("Starting AIPython Agent API server...") 

58 

59@app.on_event("shutdown") 

60async def shutdown_event(): 

61 """应用关闭时清理""" 

62 logger.info("Shutting down AIPython Agent API server...") 

63 if agent_manager and hasattr(agent_manager, 'executor'): 

64 agent_manager.executor.shutdown(wait=True) 

65 

66@app.get("/", response_model=Dict[str, str]) 

67async def root(): 

68 """根路径 - API信息""" 

69 return { 

70 "name": "AIPython Agent API", 

71 "version": __version__, 

72 "status": "running", 

73 "timestamp": datetime.now().isoformat(), 

74 "endpoints": { 

75 "submit_task": "POST /tasks", 

76 "get_task_status": "GET /tasks/{task_id}", 

77 "get_task_result": "GET /tasks/{task_id}/result", 

78 "list_tasks": "GET /tasks", 

79 "cancel_task": "DELETE /tasks/{task_id}", 

80 "health": "GET /health" 

81 } 

82 } 

83 

84@app.get("/health") 

85async def health_check(): 

86 """健康检查""" 

87 return { 

88 "status": "healthy", 

89 "timestamp": datetime.now().isoformat(), 

90 "agent_manager": "initialized" if agent_manager else "not_initialized" 

91 } 

92 

93@app.post("/tasks", response_model=TaskResponse) 

94async def submit_task(task_request: TaskRequest, background_tasks: BackgroundTasks): 

95 """提交新任务""" 

96 if not agent_manager: 

97 raise HTTPException(status_code=500, detail="Agent manager not initialized") 

98 

99 try: 

100 # 提交任务 

101 task_id = await agent_manager.submit_task( 

102 instruction=task_request.instruction, 

103 metadata=task_request.metadata 

104 ) 

105 

106 # 在后台执行任务 

107 background_tasks.add_task(execute_task_background, task_id) 

108 

109 return TaskResponse( 

110 task_id=task_id, 

111 status="pending", 

112 message="Task submitted successfully" 

113 ) 

114 

115 except Exception as e: 

116 logger.error(f"Failed to submit task: {e}") 

117 raise HTTPException(status_code=500, detail=str(e)) 

118 

119async def execute_task_background(task_id: str): 

120 """后台执行任务""" 

121 try: 

122 await agent_manager.execute_task(task_id) 

123 logger.info(f"Task {task_id} completed") 

124 except Exception as e: 

125 logger.error(f"Task {task_id} failed: {e}") 

126 

127@app.get("/tasks/{task_id}", response_model=TaskStatusResponse) 

128async def get_task_status(task_id: str): 

129 """获取任务状态""" 

130 if not agent_manager: 

131 raise HTTPException(status_code=500, detail="Agent manager not initialized") 

132 

133 try: 

134 task_data = await agent_manager.get_task_status(task_id) 

135 return TaskStatusResponse(**task_data) 

136 except ValueError as e: 

137 raise HTTPException(status_code=404, detail=str(e)) 

138 except Exception as e: 

139 logger.error(f"Failed to get task status: {e}") 

140 raise HTTPException(status_code=500, detail=str(e)) 

141 

142@app.get("/tasks/{task_id}/result", response_model=TaskResultResponse) 

143async def get_task_result(task_id: str): 

144 """获取任务结果""" 

145 if not agent_manager: 

146 raise HTTPException(status_code=500, detail="Agent manager not initialized") 

147 

148 try: 

149 result = await agent_manager.get_task_result(task_id) 

150 return TaskResultResponse(**result) 

151 except ValueError as e: 

152 raise HTTPException(status_code=404, detail=str(e)) 

153 except Exception as e: 

154 logger.error(f"Failed to get task result: {e}") 

155 raise HTTPException(status_code=500, detail=str(e)) 

156 

157@app.get("/tasks") 

158async def list_tasks(): 

159 """列出所有任务""" 

160 if not agent_manager: 

161 raise HTTPException(status_code=500, detail="Agent manager not initialized") 

162 

163 try: 

164 tasks = await agent_manager.list_tasks() 

165 return {"tasks": tasks} 

166 except Exception as e: 

167 logger.error(f"Failed to list tasks: {e}") 

168 raise HTTPException(status_code=500, detail=str(e)) 

169 

170@app.delete("/tasks/{task_id}") 

171async def cancel_task(task_id: str): 

172 """取消任务""" 

173 if not agent_manager: 

174 raise HTTPException(status_code=500, detail="Agent manager not initialized") 

175 

176 try: 

177 success = await agent_manager.cancel_task(task_id) 

178 if success: 

179 return {"message": f"Task {task_id} cancelled"} 

180 else: 

181 raise HTTPException(status_code=400, detail="Task cannot be cancelled") 

182 except Exception as e: 

183 logger.error(f"Failed to cancel task: {e}") 

184 raise HTTPException(status_code=500, detail=str(e)) 

185 

186@app.post("/admin/cleanup") 

187async def cleanup_tasks(max_age_hours: int = 24): 

188 """清理完成的任务""" 

189 if not agent_manager: 

190 raise HTTPException(status_code=500, detail="Agent manager not initialized") 

191 

192 try: 

193 cleaned_count = agent_manager.cleanup_completed_tasks(max_age_hours) 

194 return {"message": f"Cleaned up {cleaned_count} tasks"} 

195 except Exception as e: 

196 logger.error(f"Failed to cleanup tasks: {e}") 

197 raise HTTPException(status_code=500, detail=str(e)) 

198 

199def init_agent_manager(settings): 

200 """初始化Agent管理器""" 

201 global agent_manager 

202 try: 

203 display_config = {'style': 'agent', 'quiet': True} 

204 display_manager = DisplayManager(display_config) 

205 agent_manager = AgentTaskManager(settings, display_manager=display_manager) 

206 logger.info("Agent manager initialized successfully") 

207 return True 

208 except Exception as e: 

209 logger.error(f"Failed to initialize agent manager: {e}") 

210 return False 

211 

212def main(settings): 

213 """Agent模式主函数""" 

214 global agent_manager 

215 

216 host = settings.get('host', '127.0.0.1') 

217 port = settings.get('port', 8848) 

218 print(f"🤖 AIPython Agent Mode ({__version__})") 

219 print(f"🚀 Starting HTTP API server on {host}:{port}") 

220 

221 # 初始化Agent管理器 

222 if not init_agent_manager(settings): 

223 print(f"{T('Failed to initialize agent manager')}") 

224 return 

225 

226 print(f"{T('Agent manager initialized')}") 

227 print(f"🔗 API Documentation: http://{host}:{port}/docs") 

228 print(f"📊 Health Check: http://{host}:{port}/health") 

229 

230 # 启动服务器 

231 try: 

232 uvicorn.run( 

233 app, 

234 host=host, 

235 port=port, 

236 log_level="info" if settings.get('debug', False) else "warning" 

237 ) 

238 except KeyboardInterrupt: 

239 print(f"\n⏹️ {T('Server stopped by user')}") 

240 except Exception as e: 

241 print(f"{T('Server error')}: {e}") 

242 logger.error(f"Server error: {e}")