from fastapi import APIRouter from fastapi import HTTPException, Depends ,Security from fastapi_sqlalchemy import db from pydantic import BaseModel from superagi.worker import execute_agent from superagi.helper.auth import validate_api_key,get_organisation_from_api_key from superagi.models.agent import Agent from superagi.models.agent_execution_config import AgentExecutionConfiguration from superagi.models.agent_config import AgentConfiguration from superagi.models.agent_schedule import AgentSchedule from superagi.models.project import Project from superagi.models.workflows.agent_workflow import AgentWorkflow from superagi.models.agent_execution import AgentExecution from superagi.models.organisation import Organisation from superagi.models.knowledges import Knowledges from superagi.models.resource import Resource from superagi.controllers.types.agent_with_config import AgentConfigExtInput,AgentConfigUpdateExtInput from superagi.models.workflows.iteration_workflow import IterationWorkflow from superagi.helper.s3_helper import S3Helper from datetime import datetime from typing import Optional,List from superagi.models.toolkit import Toolkit from superagi.apm.event_handler import EventHandler from superagi.config.config import get_config router = APIRouter() class AgentExecutionIn(BaseModel): name: Optional[str] goal: Optional[List[str]] instruction: Optional[List[str]] class Config: orm_mode = True class RunFilterConfigIn(BaseModel): run_ids:Optional[List[int]] run_status_filter:Optional[str] class Config: orm_mode = True class ExecutionStateChangeConfigIn(BaseModel): run_ids:Optional[List[int]] class Config: orm_mode = True class RunIDConfig(BaseModel): run_ids:List[int] class Config: orm_mode = True @router.post("", status_code=200) def create_agent_with_config(agent_with_config: AgentConfigExtInput, api_key: str = Security(validate_api_key), organisation:Organisation = Depends(get_organisation_from_api_key)): project=Project.find_by_org_id(db.session, organisation.id) try: tools_arr=Toolkit.get_tool_and_toolkit_arr(db.session,organisation.id,agent_with_config.tools) except Exception as e: raise HTTPException(status_code=404, detail=str(e)) agent_with_config.tools=tools_arr agent_with_config.project_id=project.id agent_with_config.exit="No exit criterion" agent_with_config.permission_type="God Mode" agent_with_config.LTM_DB=None db_agent = Agent.create_agent_with_config(db, agent_with_config) if agent_with_config.schedule is not None: agent_schedule = AgentSchedule.save_schedule_from_config(db.session, db_agent, agent_with_config.schedule) if agent_schedule is None: raise HTTPException(status_code=500, detail="Failed to schedule agent") EventHandler(session=db.session).create_event('agent_created', {'agent_name': agent_with_config.name, 'model': agent_with_config.model}, db_agent.id, organisation.id if organisation else 0) db.session.commit() return { "agent_id": db_agent.id } start_step = AgentWorkflow.fetch_trigger_step_id(db.session, db_agent.agent_workflow_id) iteration_step_id = IterationWorkflow.fetch_trigger_step_id(db.session, start_step.action_reference_id).id if start_step.action_type == "ITERATION_WORKFLOW" else -1 # Creating an execution with RUNNING status execution = AgentExecution(status='CREATED', last_execution_time=datetime.now(), agent_id=db_agent.id, name="New Run", current_agent_step_id=start_step.id, iteration_workflow_step_id=iteration_step_id) agent_execution_configs = { "goal": agent_with_config.goal, "instruction": agent_with_config.instruction, "constraints": agent_with_config.constraints, "exit": agent_with_config.exit, "tools": agent_with_config.tools, "iteration_interval": agent_with_config.iteration_interval, "model": agent_with_config.model, "permission_type": agent_with_config.permission_type, "LTM_DB": agent_with_config.LTM_DB, "max_iterations": agent_with_config.max_iterations, "user_timezone": agent_with_config.user_timezone, "knowledge": agent_with_config.knowledge } db.session.add(execution) db.session.commit() db.session.flush() AgentExecutionConfiguration.add_or_update_agent_execution_config(session=db.session, execution=execution, agent_execution_configs=agent_execution_configs) organisation = db_agent.get_agent_organisation(db.session) EventHandler(session=db.session).create_event('agent_created', {'agent_name': agent_with_config.name, 'model': agent_with_config.model}, db_agent.id, organisation.id if organisation else 0) # execute_agent.delay(execution.id, datetime.now()) db.session.commit() return { "agent_id": db_agent.id } @router.post("/{agent_id}/run",status_code=200) def create_run(agent_id:int,agent_execution: AgentExecutionIn,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)): agent=Agent.get_agent_from_id(db.session,agent_id) if not agent: raise HTTPException(status_code=404, detail="Agent not found") project=Project.find_by_id(db.session, agent.project_id) if project.organisation_id!=organisation.id: raise HTTPException(status_code=404, detail="Agent not found") db_schedule=AgentSchedule.find_by_agent_id(db.session, agent_id) if db_schedule is not None: raise HTTPException(status_code=409, detail="Agent is already scheduled,cannot run") start_step = AgentWorkflow.fetch_trigger_step_id(db.session, agent.agent_workflow_id) db_agent_execution=AgentExecution.get_execution_by_agent_id_and_status(db.session, agent_id, "CREATED") if db_agent_execution is None: db_agent_execution = AgentExecution(status="RUNNING", last_execution_time=datetime.now(), agent_id=agent_id, name=agent_execution.name, num_of_calls=0, num_of_tokens=0, current_agent_step_id=start_step.id) db.session.add(db_agent_execution) else: db_agent_execution.status = "RUNNING" db.session.commit() db.session.flush() agent_execution_configs = {} if agent_execution.goal is not None: agent_execution_configs = { "goal": agent_execution.goal, } if agent_execution.instruction is not None: agent_execution_configs["instructions"] = agent_execution.instruction, if agent_execution_configs != {}: AgentExecutionConfiguration.add_or_update_agent_execution_config(session=db.session, execution=db_agent_execution, agent_execution_configs=agent_execution_configs) EventHandler(session=db.session).create_event('run_created', {'agent_execution_id': db_agent_execution.id, 'agent_execution_name':db_agent_execution.name }, agent_id, organisation.id if organisation else 0) agent_execution_knowledge = AgentConfiguration.get_agent_config_by_key_and_agent_id(session= db.session, key= 'knowledge', agent_id= agent_id) if agent_execution_knowledge and agent_execution_knowledge.value != 'None': knowledge_name = Knowledges.get_knowledge_from_id(db.session, int(agent_execution_knowledge.value)).name if knowledge_name is not None: EventHandler(session=db.session).create_event('knowledge_picked', {'knowledge_name': knowledge_name, 'agent_execution_id': db_agent_execution.id}, agent_id, organisation.id if organisation else 0 ) if db_agent_execution.status == "RUNNING": execute_agent.delay(db_agent_execution.id, datetime.now()) return { "run_id":db_agent_execution.id } @router.put("/{agent_id}",status_code=200) def update_agent(agent_id: int, agent_with_config: AgentConfigUpdateExtInput,api_key: str = Security(validate_api_key), organisation:Organisation = Depends(get_organisation_from_api_key)): db_agent= Agent.get_active_agent_by_id(db.session, agent_id) if not db_agent: raise HTTPException(status_code=404, detail="agent not found") project=Project.find_by_id(db.session, db_agent.project_id) if project is None: raise HTTPException(status_code=404, detail="Project not found") if project.organisation_id!=organisation.id: raise HTTPException(status_code=404, detail="Agent not found") # db_execution=AgentExecution.get_execution_by_agent_id_and_status(db.session, agent_id, "RUNNING") # if db_execution is not None: # raise HTTPException(status_code=409, detail="Agent is already running,please pause and then update") db_schedule=AgentSchedule.find_by_agent_id(db.session, agent_id) if db_schedule is not None: raise HTTPException(status_code=409, detail="Agent is already scheduled,cannot update") try: tools_arr=Toolkit.get_tool_and_toolkit_arr(db.session,organisation.id,agent_with_config.tools) except Exception as e: raise HTTPException(status_code=404,detail=str(e)) if agent_with_config.schedule is not None: raise HTTPException(status_code=400,detail="Cannot schedule an existing agent") agent_with_config.tools=tools_arr agent_with_config.project_id=project.id agent_with_config.exit="No exit criterion" agent_with_config.permission_type="God Mode" agent_with_config.LTM_DB=None for key,value in agent_with_config.dict().items(): if hasattr(db_agent,key) and value is not None: setattr(db_agent,key,value) db.session.commit() db.session.flush() start_step = AgentWorkflow.fetch_trigger_step_id(db.session, db_agent.agent_workflow_id) iteration_step_id = IterationWorkflow.fetch_trigger_step_id(db.session, start_step.action_reference_id).id if start_step.action_type == "ITERATION_WORKFLOW" else -1 execution = AgentExecution(status='CREATED', last_execution_time=datetime.now(), agent_id=db_agent.id, name="New Run", current_agent_step_id=start_step.id, iteration_workflow_step_id=iteration_step_id) agent_execution_configs = { "goal": agent_with_config.goal, "instruction": agent_with_config.instruction, "tools":agent_with_config.tools, "constraints": agent_with_config.constraints, "iteration_interval": agent_with_config.iteration_interval, "model": agent_with_config.model, "max_iterations": agent_with_config.max_iterations, "agent_workflow": agent_with_config.agent_workflow, } agent_configurations = [ AgentConfiguration(agent_id=db_agent.id, key=key, value=str(value)) for key, value in agent_execution_configs.items() ] db.session.add_all(agent_configurations) db.session.add(execution) db.session.commit() db.session.flush() AgentExecutionConfiguration.add_or_update_agent_execution_config(session=db.session, execution=execution, agent_execution_configs=agent_execution_configs) db.session.commit() return { "agent_id":db_agent.id } @router.post("/{agent_id}/run-status") def get_agent_runs(agent_id:int,filter_config:RunFilterConfigIn,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)): agent= Agent.get_active_agent_by_id(db.session, agent_id) if not agent: raise HTTPException(status_code=404, detail="Agent not found") project=Project.find_by_id(db.session, agent.project_id) if project.organisation_id!=organisation.id: raise HTTPException(status_code=404, detail="Agent not found") db_execution_arr=[] if filter_config.run_status_filter is not None: filter_config.run_status_filter=filter_config.run_status_filter.upper() db_execution_arr=AgentExecution.get_all_executions_by_filter_config(db.session, agent.id, filter_config) response_arr=[] for ind_execution in db_execution_arr: response_arr.append({"run_id":ind_execution.id, "status":ind_execution.status}) return response_arr @router.post("/{agent_id}/pause",status_code=200) def pause_agent_runs(agent_id:int,execution_state_change_input:ExecutionStateChangeConfigIn,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)): agent= Agent.get_active_agent_by_id(db.session, agent_id) if not agent: raise HTTPException(status_code=404, detail="Agent not found") project=Project.find_by_id(db.session, agent.project_id) if project.organisation_id!=organisation.id: raise HTTPException(status_code=404, detail="Agent not found") #Checking if the run_ids whose output files are requested belong to the organisation if execution_state_change_input.run_ids is not None: try: AgentExecution.validate_run_ids(db.session,execution_state_change_input.run_ids,organisation.id) except Exception as e: raise HTTPException(status_code=404, detail="One or more run id(s) not found") db_execution_arr=AgentExecution.get_all_executions_by_status_and_agent_id(db.session, agent.id, execution_state_change_input, "RUNNING") if db_execution_arr is not None and execution_state_change_input.run_ids is not None \ and len(db_execution_arr) != len(execution_state_change_input.run_ids): raise HTTPException(status_code=404, detail="One or more run id(s) not found") for ind_execution in db_execution_arr: ind_execution.status="PAUSED" db.session.commit() db.session.flush() return { "result":"success" } @router.post("/{agent_id}/resume",status_code=200) def resume_agent_runs(agent_id:int,execution_state_change_input:ExecutionStateChangeConfigIn,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)): agent= Agent.get_active_agent_by_id(db.session, agent_id) if not agent: raise HTTPException(status_code=404, detail="Agent not found") project=Project.find_by_id(db.session, agent.project_id) if project.organisation_id!=organisation.id: raise HTTPException(status_code=404, detail="Agent not found") if execution_state_change_input.run_ids is not None: try: AgentExecution.validate_run_ids(db.session,execution_state_change_input.run_ids,organisation.id) except Exception as e: raise HTTPException(status_code=404, detail="One or more run id(s) not found") db_execution_arr=AgentExecution.get_all_executions_by_status_and_agent_id(db.session, agent.id, execution_state_change_input, "PAUSED") if db_execution_arr is not None and execution_state_change_input.run_ids is not None\ and len(db_execution_arr) != len(execution_state_change_input.run_ids): raise HTTPException(status_code=404, detail="One or more run id(s) not found") for ind_execution in db_execution_arr: ind_execution.status="RUNNING" execute_agent.delay(ind_execution.id, datetime.now()) db.session.commit() db.session.flush() return { "result":"success" } @router.post("/resources/output",status_code=200) def get_run_resources(run_id_config:RunIDConfig,api_key: str = Security(validate_api_key),organisation:Organisation = Depends(get_organisation_from_api_key)): if get_config('STORAGE_TYPE') != "S3": raise HTTPException(status_code=400,detail="This endpoint only works when S3 is configured") run_ids_arr=run_id_config.run_ids if len(run_ids_arr)==0: raise HTTPException(status_code=404, detail=f"No execution_id found") #Checking if the run_ids whose output files are requested belong to the organisation try: AgentExecution.validate_run_ids(db.session, run_ids_arr, organisation.id) except Exception as e: raise HTTPException(status_code=404, detail="One or more run id(s) not found") db_resources_arr=Resource.find_by_run_ids(db.session, run_ids_arr) try: response_obj=S3Helper().get_download_url_of_resources(db_resources_arr) except: raise HTTPException(status_code=401,detail="Invalid S3 credentials") return response_obj