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

1#!/usr/bin/env python

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

3

4 from typing import Dict, Any, Optional

5 from datetime import datetime

6

7 import uvicorn

8 from fastapi import FastAPI, HTTPException, BackgroundTasks

9 from pydantic import BaseModel, Field

10

11 from loguru import logger

12

13 from .. import T, __version__

14 from ..aipy.agent_taskmgr import AgentTaskManager

15 from ..display import DisplayManager

16

17# API 数据模型

18 class TaskRequest(BaseModel):

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

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

21

22 class TaskResponse(BaseModel):

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

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

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

26

27 class 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

36 class 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# 全局变量

47 agent_manager: Optional[AgentTaskManager] = None

48 app = 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")

55 async def startup_event():

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

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

58

59@app.on_event("shutdown")

60 async 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])

67 async 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")

85 async 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)

94 async 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

119 async 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)

128 async 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)

143 async 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")

158 async 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}")

171 async 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")

187 async 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

199 def 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

212 def 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}")