kubiya-control-plane-api 0.1.0__py3-none-any.whl → 0.3.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kubiya-control-plane-api might be problematic. Click here for more details.
- control_plane_api/README.md +266 -0
- control_plane_api/__init__.py +0 -0
- control_plane_api/__version__.py +1 -0
- control_plane_api/alembic/README +1 -0
- control_plane_api/alembic/env.py +98 -0
- control_plane_api/alembic/script.py.mako +28 -0
- control_plane_api/alembic/versions/1382bec74309_initial_migration_with_all_models.py +251 -0
- control_plane_api/alembic/versions/1f54bc2a37e3_add_analytics_tables.py +162 -0
- control_plane_api/alembic/versions/2e4cb136dc10_rename_toolset_ids_to_skill_ids_in_teams.py +30 -0
- control_plane_api/alembic/versions/31cd69a644ce_add_skill_templates_table.py +28 -0
- control_plane_api/alembic/versions/89e127caa47d_add_jobs_and_job_executions_tables.py +161 -0
- control_plane_api/alembic/versions/add_llm_models_table.py +51 -0
- control_plane_api/alembic/versions/b0e10697f212_add_runtime_column_to_teams_simple.py +42 -0
- control_plane_api/alembic/versions/ce43b24b63bf_add_execution_trigger_source_and_fix_.py +155 -0
- control_plane_api/alembic/versions/d4eaf16e3f8d_rename_toolsets_to_skills.py +84 -0
- control_plane_api/alembic/versions/efa2dc427da1_rename_metadata_to_custom_metadata.py +32 -0
- control_plane_api/alembic/versions/f973b431d1ce_add_workflow_executor_to_skill_types.py +44 -0
- control_plane_api/alembic.ini +148 -0
- control_plane_api/api/index.py +12 -0
- control_plane_api/app/__init__.py +11 -0
- control_plane_api/app/activities/__init__.py +20 -0
- control_plane_api/app/activities/agent_activities.py +379 -0
- control_plane_api/app/activities/team_activities.py +410 -0
- control_plane_api/app/activities/temporal_cloud_activities.py +577 -0
- control_plane_api/app/config/__init__.py +35 -0
- control_plane_api/app/config/api_config.py +354 -0
- control_plane_api/app/config/model_pricing.py +318 -0
- control_plane_api/app/config.py +95 -0
- control_plane_api/app/database.py +135 -0
- control_plane_api/app/exceptions.py +408 -0
- control_plane_api/app/lib/__init__.py +11 -0
- control_plane_api/app/lib/job_executor.py +312 -0
- control_plane_api/app/lib/kubiya_client.py +235 -0
- control_plane_api/app/lib/litellm_pricing.py +166 -0
- control_plane_api/app/lib/planning_tools/__init__.py +22 -0
- control_plane_api/app/lib/planning_tools/agents.py +155 -0
- control_plane_api/app/lib/planning_tools/base.py +189 -0
- control_plane_api/app/lib/planning_tools/environments.py +214 -0
- control_plane_api/app/lib/planning_tools/resources.py +240 -0
- control_plane_api/app/lib/planning_tools/teams.py +198 -0
- control_plane_api/app/lib/policy_enforcer_client.py +939 -0
- control_plane_api/app/lib/redis_client.py +436 -0
- control_plane_api/app/lib/supabase.py +71 -0
- control_plane_api/app/lib/temporal_client.py +138 -0
- control_plane_api/app/lib/validation/__init__.py +20 -0
- control_plane_api/app/lib/validation/runtime_validation.py +287 -0
- control_plane_api/app/main.py +128 -0
- control_plane_api/app/middleware/__init__.py +8 -0
- control_plane_api/app/middleware/auth.py +513 -0
- control_plane_api/app/middleware/exception_handler.py +267 -0
- control_plane_api/app/middleware/rate_limiting.py +384 -0
- control_plane_api/app/middleware/request_id.py +202 -0
- control_plane_api/app/models/__init__.py +27 -0
- control_plane_api/app/models/agent.py +79 -0
- control_plane_api/app/models/analytics.py +206 -0
- control_plane_api/app/models/associations.py +81 -0
- control_plane_api/app/models/environment.py +63 -0
- control_plane_api/app/models/execution.py +93 -0
- control_plane_api/app/models/job.py +179 -0
- control_plane_api/app/models/llm_model.py +75 -0
- control_plane_api/app/models/presence.py +49 -0
- control_plane_api/app/models/project.py +47 -0
- control_plane_api/app/models/session.py +38 -0
- control_plane_api/app/models/team.py +66 -0
- control_plane_api/app/models/workflow.py +55 -0
- control_plane_api/app/policies/README.md +121 -0
- control_plane_api/app/policies/approved_users.rego +62 -0
- control_plane_api/app/policies/business_hours.rego +51 -0
- control_plane_api/app/policies/rate_limiting.rego +100 -0
- control_plane_api/app/policies/tool_restrictions.rego +86 -0
- control_plane_api/app/routers/__init__.py +4 -0
- control_plane_api/app/routers/agents.py +364 -0
- control_plane_api/app/routers/agents_v2.py +1260 -0
- control_plane_api/app/routers/analytics.py +1014 -0
- control_plane_api/app/routers/context_manager.py +562 -0
- control_plane_api/app/routers/environment_context.py +270 -0
- control_plane_api/app/routers/environments.py +715 -0
- control_plane_api/app/routers/execution_environment.py +517 -0
- control_plane_api/app/routers/executions.py +1911 -0
- control_plane_api/app/routers/health.py +92 -0
- control_plane_api/app/routers/health_v2.py +326 -0
- control_plane_api/app/routers/integrations.py +274 -0
- control_plane_api/app/routers/jobs.py +1344 -0
- control_plane_api/app/routers/models.py +82 -0
- control_plane_api/app/routers/models_v2.py +361 -0
- control_plane_api/app/routers/policies.py +639 -0
- control_plane_api/app/routers/presence.py +234 -0
- control_plane_api/app/routers/projects.py +902 -0
- control_plane_api/app/routers/runners.py +379 -0
- control_plane_api/app/routers/runtimes.py +172 -0
- control_plane_api/app/routers/secrets.py +155 -0
- control_plane_api/app/routers/skills.py +1001 -0
- control_plane_api/app/routers/skills_definitions.py +140 -0
- control_plane_api/app/routers/task_planning.py +1256 -0
- control_plane_api/app/routers/task_queues.py +654 -0
- control_plane_api/app/routers/team_context.py +270 -0
- control_plane_api/app/routers/teams.py +1400 -0
- control_plane_api/app/routers/worker_queues.py +1545 -0
- control_plane_api/app/routers/workers.py +935 -0
- control_plane_api/app/routers/workflows.py +204 -0
- control_plane_api/app/runtimes/__init__.py +6 -0
- control_plane_api/app/runtimes/validation.py +344 -0
- control_plane_api/app/schemas/job_schemas.py +295 -0
- control_plane_api/app/services/__init__.py +1 -0
- control_plane_api/app/services/agno_service.py +619 -0
- control_plane_api/app/services/litellm_service.py +190 -0
- control_plane_api/app/services/policy_service.py +525 -0
- control_plane_api/app/services/temporal_cloud_provisioning.py +150 -0
- control_plane_api/app/skills/__init__.py +44 -0
- control_plane_api/app/skills/base.py +229 -0
- control_plane_api/app/skills/business_intelligence.py +189 -0
- control_plane_api/app/skills/data_visualization.py +154 -0
- control_plane_api/app/skills/docker.py +104 -0
- control_plane_api/app/skills/file_generation.py +94 -0
- control_plane_api/app/skills/file_system.py +110 -0
- control_plane_api/app/skills/python.py +92 -0
- control_plane_api/app/skills/registry.py +65 -0
- control_plane_api/app/skills/shell.py +102 -0
- control_plane_api/app/skills/workflow_executor.py +469 -0
- control_plane_api/app/utils/workflow_executor.py +354 -0
- control_plane_api/app/workflows/__init__.py +11 -0
- control_plane_api/app/workflows/agent_execution.py +507 -0
- control_plane_api/app/workflows/agent_execution_with_skills.py +222 -0
- control_plane_api/app/workflows/namespace_provisioning.py +326 -0
- control_plane_api/app/workflows/team_execution.py +399 -0
- control_plane_api/scripts/seed_models.py +239 -0
- control_plane_api/worker/__init__.py +0 -0
- control_plane_api/worker/activities/__init__.py +0 -0
- control_plane_api/worker/activities/agent_activities.py +1241 -0
- control_plane_api/worker/activities/approval_activities.py +234 -0
- control_plane_api/worker/activities/runtime_activities.py +388 -0
- control_plane_api/worker/activities/skill_activities.py +267 -0
- control_plane_api/worker/activities/team_activities.py +1217 -0
- control_plane_api/worker/config/__init__.py +31 -0
- control_plane_api/worker/config/worker_config.py +275 -0
- control_plane_api/worker/control_plane_client.py +529 -0
- control_plane_api/worker/examples/analytics_integration_example.py +362 -0
- control_plane_api/worker/models/__init__.py +1 -0
- control_plane_api/worker/models/inputs.py +89 -0
- control_plane_api/worker/runtimes/__init__.py +31 -0
- control_plane_api/worker/runtimes/base.py +789 -0
- control_plane_api/worker/runtimes/claude_code_runtime.py +1443 -0
- control_plane_api/worker/runtimes/default_runtime.py +617 -0
- control_plane_api/worker/runtimes/factory.py +173 -0
- control_plane_api/worker/runtimes/validation.py +93 -0
- control_plane_api/worker/services/__init__.py +1 -0
- control_plane_api/worker/services/agent_executor.py +422 -0
- control_plane_api/worker/services/agent_executor_v2.py +383 -0
- control_plane_api/worker/services/analytics_collector.py +457 -0
- control_plane_api/worker/services/analytics_service.py +464 -0
- control_plane_api/worker/services/approval_tools.py +310 -0
- control_plane_api/worker/services/approval_tools_agno.py +207 -0
- control_plane_api/worker/services/cancellation_manager.py +177 -0
- control_plane_api/worker/services/data_visualization.py +827 -0
- control_plane_api/worker/services/jira_tools.py +257 -0
- control_plane_api/worker/services/runtime_analytics.py +328 -0
- control_plane_api/worker/services/session_service.py +194 -0
- control_plane_api/worker/services/skill_factory.py +175 -0
- control_plane_api/worker/services/team_executor.py +574 -0
- control_plane_api/worker/services/team_executor_v2.py +465 -0
- control_plane_api/worker/services/workflow_executor_tools.py +1418 -0
- control_plane_api/worker/tests/__init__.py +1 -0
- control_plane_api/worker/tests/e2e/__init__.py +0 -0
- control_plane_api/worker/tests/e2e/test_execution_flow.py +571 -0
- control_plane_api/worker/tests/integration/__init__.py +0 -0
- control_plane_api/worker/tests/integration/test_control_plane_integration.py +308 -0
- control_plane_api/worker/tests/unit/__init__.py +0 -0
- control_plane_api/worker/tests/unit/test_control_plane_client.py +401 -0
- control_plane_api/worker/utils/__init__.py +1 -0
- control_plane_api/worker/utils/chunk_batcher.py +305 -0
- control_plane_api/worker/utils/retry_utils.py +60 -0
- control_plane_api/worker/utils/streaming_utils.py +373 -0
- control_plane_api/worker/worker.py +753 -0
- control_plane_api/worker/workflows/__init__.py +0 -0
- control_plane_api/worker/workflows/agent_execution.py +589 -0
- control_plane_api/worker/workflows/team_execution.py +429 -0
- kubiya_control_plane_api-0.3.4.dist-info/METADATA +229 -0
- kubiya_control_plane_api-0.3.4.dist-info/RECORD +182 -0
- kubiya_control_plane_api-0.3.4.dist-info/entry_points.txt +2 -0
- kubiya_control_plane_api-0.3.4.dist-info/top_level.txt +1 -0
- kubiya_control_plane_api-0.1.0.dist-info/METADATA +0 -66
- kubiya_control_plane_api-0.1.0.dist-info/RECORD +0 -5
- kubiya_control_plane_api-0.1.0.dist-info/top_level.txt +0 -1
- {kubiya_control_plane_api-0.1.0.dist-info/licenses → control_plane_api}/LICENSE +0 -0
- {kubiya_control_plane_api-0.1.0.dist-info → kubiya_control_plane_api-0.3.4.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
from fastapi import APIRouter, Depends, HTTPException, status
|
|
2
|
+
from fastapi.responses import StreamingResponse
|
|
3
|
+
from sqlalchemy.orm import Session
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
from control_plane_api.app.database import get_db
|
|
8
|
+
from control_plane_api.app.models.agent import Agent, AgentStatus
|
|
9
|
+
from control_plane_api.app.models.execution import Execution, ExecutionStatus, ExecutionType
|
|
10
|
+
from control_plane_api.app.services.litellm_service import litellm_service
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
|
|
13
|
+
router = APIRouter()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def agent_to_response(agent: Agent) -> dict:
|
|
17
|
+
"""Convert Agent model to response dict, mapping model_config to llm_config"""
|
|
18
|
+
return {
|
|
19
|
+
"id": agent.id,
|
|
20
|
+
"name": agent.name,
|
|
21
|
+
"description": agent.description,
|
|
22
|
+
"status": agent.status,
|
|
23
|
+
"capabilities": agent.capabilities,
|
|
24
|
+
"configuration": agent.configuration,
|
|
25
|
+
"model_id": agent.model_id,
|
|
26
|
+
"llm_config": agent.model_config,
|
|
27
|
+
"team_id": agent.team_id,
|
|
28
|
+
"created_at": agent.created_at,
|
|
29
|
+
"updated_at": agent.updated_at,
|
|
30
|
+
"last_active_at": agent.last_active_at,
|
|
31
|
+
"state": agent.state,
|
|
32
|
+
"error_message": agent.error_message,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Pydantic schemas
|
|
37
|
+
class AgentCreate(BaseModel):
|
|
38
|
+
name: str = Field(..., description="Agent name")
|
|
39
|
+
description: str | None = Field(None, description="Agent description")
|
|
40
|
+
capabilities: list = Field(default_factory=list, description="Agent capabilities")
|
|
41
|
+
configuration: dict = Field(default_factory=dict, description="Agent configuration")
|
|
42
|
+
model_id: str | None = Field(None, description="LiteLLM model identifier")
|
|
43
|
+
llm_config: dict = Field(default_factory=dict, description="Model-specific configuration")
|
|
44
|
+
team_id: str | None = Field(None, description="Team ID to assign this agent to")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class AgentUpdate(BaseModel):
|
|
48
|
+
name: str | None = None
|
|
49
|
+
description: str | None = None
|
|
50
|
+
status: AgentStatus | None = None
|
|
51
|
+
capabilities: list | None = None
|
|
52
|
+
configuration: dict | None = None
|
|
53
|
+
state: dict | None = None
|
|
54
|
+
model_id: str | None = None
|
|
55
|
+
llm_config: dict | None = None
|
|
56
|
+
team_id: str | None = None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class AgentResponse(BaseModel):
|
|
60
|
+
id: str
|
|
61
|
+
name: str
|
|
62
|
+
description: str | None
|
|
63
|
+
status: AgentStatus
|
|
64
|
+
capabilities: list
|
|
65
|
+
configuration: dict
|
|
66
|
+
model_id: str | None
|
|
67
|
+
llm_config: dict
|
|
68
|
+
team_id: str | None
|
|
69
|
+
created_at: datetime
|
|
70
|
+
updated_at: datetime
|
|
71
|
+
last_active_at: datetime | None
|
|
72
|
+
state: dict
|
|
73
|
+
error_message: str | None
|
|
74
|
+
|
|
75
|
+
class Config:
|
|
76
|
+
from_attributes = True
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class AgentExecutionRequest(BaseModel):
|
|
80
|
+
prompt: str = Field(..., description="The prompt to execute")
|
|
81
|
+
system_prompt: str | None = Field(None, description="Optional system prompt")
|
|
82
|
+
stream: bool = Field(False, description="Whether to stream the response")
|
|
83
|
+
config: dict | None = Field(None, description="Optional configuration including user metadata")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class AgentExecutionResponse(BaseModel):
|
|
87
|
+
execution_id: str
|
|
88
|
+
success: bool
|
|
89
|
+
response: str | None = None
|
|
90
|
+
error: str | None = None
|
|
91
|
+
model: str
|
|
92
|
+
usage: dict | None = None
|
|
93
|
+
finish_reason: str | None = None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@router.post("", response_model=AgentResponse, status_code=status.HTTP_201_CREATED)
|
|
97
|
+
def create_agent(agent_data: AgentCreate, db: Session = Depends(get_db)):
|
|
98
|
+
"""Create a new agent"""
|
|
99
|
+
agent = Agent(
|
|
100
|
+
name=agent_data.name,
|
|
101
|
+
description=agent_data.description,
|
|
102
|
+
capabilities=agent_data.capabilities,
|
|
103
|
+
configuration=agent_data.configuration,
|
|
104
|
+
model_id=agent_data.model_id,
|
|
105
|
+
model_config=agent_data.llm_config,
|
|
106
|
+
team_id=agent_data.team_id,
|
|
107
|
+
)
|
|
108
|
+
db.add(agent)
|
|
109
|
+
db.commit()
|
|
110
|
+
db.refresh(agent)
|
|
111
|
+
return agent_to_response(agent)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@router.get("", response_model=List[AgentResponse])
|
|
115
|
+
def list_agents(
|
|
116
|
+
skip: int = 0,
|
|
117
|
+
limit: int = 100,
|
|
118
|
+
status_filter: AgentStatus | None = None,
|
|
119
|
+
db: Session = Depends(get_db),
|
|
120
|
+
):
|
|
121
|
+
"""List all agents"""
|
|
122
|
+
query = db.query(Agent)
|
|
123
|
+
if status_filter:
|
|
124
|
+
query = query.filter(Agent.status == status_filter)
|
|
125
|
+
agents = query.offset(skip).limit(limit).all()
|
|
126
|
+
return [agent_to_response(agent) for agent in agents]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@router.get("/{agent_id}", response_model=AgentResponse)
|
|
130
|
+
def get_agent(agent_id: str, db: Session = Depends(get_db)):
|
|
131
|
+
"""Get a specific agent by ID"""
|
|
132
|
+
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
|
133
|
+
if not agent:
|
|
134
|
+
raise HTTPException(status_code=404, detail="Agent not found")
|
|
135
|
+
return agent_to_response(agent)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@router.patch("/{agent_id}", response_model=AgentResponse)
|
|
139
|
+
def update_agent(agent_id: str, agent_data: AgentUpdate, db: Session = Depends(get_db)):
|
|
140
|
+
"""Update an agent"""
|
|
141
|
+
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
|
142
|
+
if not agent:
|
|
143
|
+
raise HTTPException(status_code=404, detail="Agent not found")
|
|
144
|
+
|
|
145
|
+
update_data = agent_data.model_dump(exclude_unset=True)
|
|
146
|
+
for field, value in update_data.items():
|
|
147
|
+
setattr(agent, field, value)
|
|
148
|
+
|
|
149
|
+
agent.updated_at = datetime.utcnow()
|
|
150
|
+
db.commit()
|
|
151
|
+
db.refresh(agent)
|
|
152
|
+
return agent_to_response(agent)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@router.delete("/{agent_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
156
|
+
def delete_agent(agent_id: str, db: Session = Depends(get_db)):
|
|
157
|
+
"""Delete an agent"""
|
|
158
|
+
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
|
159
|
+
if not agent:
|
|
160
|
+
raise HTTPException(status_code=404, detail="Agent not found")
|
|
161
|
+
|
|
162
|
+
db.delete(agent)
|
|
163
|
+
db.commit()
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@router.post("/{agent_id}/start", response_model=AgentResponse)
|
|
168
|
+
def start_agent(agent_id: str, db: Session = Depends(get_db)):
|
|
169
|
+
"""Start an agent"""
|
|
170
|
+
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
|
171
|
+
if not agent:
|
|
172
|
+
raise HTTPException(status_code=404, detail="Agent not found")
|
|
173
|
+
|
|
174
|
+
if agent.status == AgentStatus.RUNNING:
|
|
175
|
+
raise HTTPException(status_code=400, detail="Agent is already running")
|
|
176
|
+
|
|
177
|
+
agent.status = AgentStatus.RUNNING
|
|
178
|
+
agent.last_active_at = datetime.utcnow()
|
|
179
|
+
agent.error_message = None
|
|
180
|
+
db.commit()
|
|
181
|
+
db.refresh(agent)
|
|
182
|
+
return agent_to_response(agent)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@router.post("/{agent_id}/stop", response_model=AgentResponse)
|
|
186
|
+
def stop_agent(agent_id: str, db: Session = Depends(get_db)):
|
|
187
|
+
"""Stop an agent"""
|
|
188
|
+
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
|
189
|
+
if not agent:
|
|
190
|
+
raise HTTPException(status_code=404, detail="Agent not found")
|
|
191
|
+
|
|
192
|
+
agent.status = AgentStatus.STOPPED
|
|
193
|
+
agent.last_active_at = datetime.utcnow()
|
|
194
|
+
db.commit()
|
|
195
|
+
db.refresh(agent)
|
|
196
|
+
return agent_to_response(agent)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@router.post("/{agent_id}/pause", response_model=AgentResponse)
|
|
200
|
+
def pause_agent(agent_id: str, db: Session = Depends(get_db)):
|
|
201
|
+
"""Pause an agent"""
|
|
202
|
+
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
|
203
|
+
if not agent:
|
|
204
|
+
raise HTTPException(status_code=404, detail="Agent not found")
|
|
205
|
+
|
|
206
|
+
if agent.status != AgentStatus.RUNNING:
|
|
207
|
+
raise HTTPException(status_code=400, detail="Can only pause running agents")
|
|
208
|
+
|
|
209
|
+
agent.status = AgentStatus.PAUSED
|
|
210
|
+
agent.last_active_at = datetime.utcnow()
|
|
211
|
+
db.commit()
|
|
212
|
+
db.refresh(agent)
|
|
213
|
+
return agent_to_response(agent)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@router.post("/{agent_id}/resume", response_model=AgentResponse)
|
|
217
|
+
def resume_agent(agent_id: str, db: Session = Depends(get_db)):
|
|
218
|
+
"""Resume a paused agent"""
|
|
219
|
+
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
|
220
|
+
if not agent:
|
|
221
|
+
raise HTTPException(status_code=404, detail="Agent not found")
|
|
222
|
+
|
|
223
|
+
if agent.status != AgentStatus.PAUSED:
|
|
224
|
+
raise HTTPException(status_code=400, detail="Can only resume paused agents")
|
|
225
|
+
|
|
226
|
+
agent.status = AgentStatus.RUNNING
|
|
227
|
+
agent.last_active_at = datetime.utcnow()
|
|
228
|
+
db.commit()
|
|
229
|
+
db.refresh(agent)
|
|
230
|
+
return agent_to_response(agent)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@router.post("/{agent_id}/execute", response_model=AgentExecutionResponse)
|
|
234
|
+
def execute_agent(
|
|
235
|
+
agent_id: str,
|
|
236
|
+
execution_request: AgentExecutionRequest,
|
|
237
|
+
db: Session = Depends(get_db),
|
|
238
|
+
):
|
|
239
|
+
"""Execute an agent with a prompt using LiteLLM"""
|
|
240
|
+
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
|
241
|
+
if not agent:
|
|
242
|
+
raise HTTPException(status_code=404, detail="Agent not found")
|
|
243
|
+
|
|
244
|
+
# Extract user metadata from config if provided
|
|
245
|
+
user_metadata = {}
|
|
246
|
+
if execution_request.config and "user_metadata" in execution_request.config:
|
|
247
|
+
user_metadata = execution_request.config["user_metadata"]
|
|
248
|
+
|
|
249
|
+
# Create execution record
|
|
250
|
+
execution = Execution(
|
|
251
|
+
execution_type=ExecutionType.AGENT,
|
|
252
|
+
entity_id=agent.id,
|
|
253
|
+
entity_name=agent.name,
|
|
254
|
+
prompt=execution_request.prompt,
|
|
255
|
+
system_prompt=execution_request.system_prompt,
|
|
256
|
+
status=ExecutionStatus.RUNNING,
|
|
257
|
+
execution_metadata={
|
|
258
|
+
"user_id": user_metadata.get("user_id"),
|
|
259
|
+
"user_name": user_metadata.get("user_name"),
|
|
260
|
+
"user_email": user_metadata.get("user_email"),
|
|
261
|
+
"user_avatar": user_metadata.get("user_avatar"),
|
|
262
|
+
},
|
|
263
|
+
)
|
|
264
|
+
db.add(execution)
|
|
265
|
+
db.flush() # Get execution ID without committing
|
|
266
|
+
execution.started_at = datetime.utcnow()
|
|
267
|
+
|
|
268
|
+
# Extract model configuration
|
|
269
|
+
model = agent.model_id
|
|
270
|
+
model_config = agent.model_config or {}
|
|
271
|
+
|
|
272
|
+
# Get system prompt from configuration if not provided
|
|
273
|
+
system_prompt = execution_request.system_prompt
|
|
274
|
+
if not system_prompt and "system_prompt" in agent.configuration:
|
|
275
|
+
system_prompt = agent.configuration["system_prompt"]
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
# Execute using LiteLLM service
|
|
279
|
+
result = litellm_service.execute_agent(
|
|
280
|
+
prompt=execution_request.prompt,
|
|
281
|
+
model=model,
|
|
282
|
+
system_prompt=system_prompt,
|
|
283
|
+
**model_config,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Update execution record with results
|
|
287
|
+
execution.response = result.get("response")
|
|
288
|
+
execution.usage = result.get("usage", {})
|
|
289
|
+
execution.execution_metadata = {
|
|
290
|
+
"model": result.get("model"),
|
|
291
|
+
"finish_reason": result.get("finish_reason"),
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if result.get("success"):
|
|
295
|
+
execution.status = ExecutionStatus.COMPLETED
|
|
296
|
+
agent.status = AgentStatus.COMPLETED
|
|
297
|
+
else:
|
|
298
|
+
execution.status = ExecutionStatus.FAILED
|
|
299
|
+
execution.error_message = result.get("error")
|
|
300
|
+
agent.status = AgentStatus.FAILED
|
|
301
|
+
agent.error_message = result.get("error")
|
|
302
|
+
|
|
303
|
+
execution.completed_at = datetime.utcnow()
|
|
304
|
+
|
|
305
|
+
except Exception as e:
|
|
306
|
+
# Handle execution errors
|
|
307
|
+
execution.status = ExecutionStatus.FAILED
|
|
308
|
+
execution.error_message = str(e)
|
|
309
|
+
execution.completed_at = datetime.utcnow()
|
|
310
|
+
agent.status = AgentStatus.FAILED
|
|
311
|
+
agent.error_message = str(e)
|
|
312
|
+
result = {
|
|
313
|
+
"success": False,
|
|
314
|
+
"error": str(e),
|
|
315
|
+
"model": model,
|
|
316
|
+
"usage": None,
|
|
317
|
+
"finish_reason": None,
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
# Update agent state
|
|
321
|
+
agent.last_active_at = datetime.utcnow()
|
|
322
|
+
db.commit()
|
|
323
|
+
|
|
324
|
+
return AgentExecutionResponse(
|
|
325
|
+
execution_id=execution.id,
|
|
326
|
+
**result
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
@router.post("/{agent_id}/execute/stream")
|
|
331
|
+
def execute_agent_stream(
|
|
332
|
+
agent_id: str,
|
|
333
|
+
execution_request: AgentExecutionRequest,
|
|
334
|
+
db: Session = Depends(get_db),
|
|
335
|
+
):
|
|
336
|
+
"""Execute an agent with a prompt using LiteLLM (streaming response)"""
|
|
337
|
+
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
|
338
|
+
if not agent:
|
|
339
|
+
raise HTTPException(status_code=404, detail="Agent not found")
|
|
340
|
+
|
|
341
|
+
# Extract model configuration
|
|
342
|
+
model = agent.model_id
|
|
343
|
+
model_config = agent.model_config or {}
|
|
344
|
+
|
|
345
|
+
# Get system prompt from configuration if not provided
|
|
346
|
+
system_prompt = execution_request.system_prompt
|
|
347
|
+
if not system_prompt and "system_prompt" in agent.configuration:
|
|
348
|
+
system_prompt = agent.configuration["system_prompt"]
|
|
349
|
+
|
|
350
|
+
# Update agent state
|
|
351
|
+
agent.last_active_at = datetime.utcnow()
|
|
352
|
+
agent.status = AgentStatus.RUNNING
|
|
353
|
+
db.commit()
|
|
354
|
+
|
|
355
|
+
# Execute using LiteLLM service (streaming)
|
|
356
|
+
return StreamingResponse(
|
|
357
|
+
litellm_service.execute_agent_stream(
|
|
358
|
+
prompt=execution_request.prompt,
|
|
359
|
+
model=model,
|
|
360
|
+
system_prompt=system_prompt,
|
|
361
|
+
**model_config,
|
|
362
|
+
),
|
|
363
|
+
media_type="text/event-stream",
|
|
364
|
+
)
|