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,93 @@
|
|
|
1
|
+
from sqlalchemy import Column, String, DateTime, Text, JSON, Enum as SQLEnum, ForeignKey
|
|
2
|
+
from sqlalchemy.dialects.postgresql import UUID
|
|
3
|
+
from sqlalchemy.orm import relationship
|
|
4
|
+
from sqlalchemy.sql import func
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
import uuid
|
|
7
|
+
import enum
|
|
8
|
+
|
|
9
|
+
from control_plane_api.app.database import Base
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ExecutionStatus(str, enum.Enum):
|
|
13
|
+
PENDING = "pending"
|
|
14
|
+
RUNNING = "running"
|
|
15
|
+
WAITING_FOR_INPUT = "waiting_for_input"
|
|
16
|
+
COMPLETED = "completed"
|
|
17
|
+
FAILED = "failed"
|
|
18
|
+
CANCELLED = "cancelled"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ExecutionType(str, enum.Enum):
|
|
22
|
+
AGENT = "agent"
|
|
23
|
+
TEAM = "team"
|
|
24
|
+
WORKFLOW = "workflow"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ExecutionTriggerSource(str, enum.Enum):
|
|
28
|
+
"""How the execution was triggered"""
|
|
29
|
+
USER = "user" # Triggered by a user directly via UI/API
|
|
30
|
+
JOB_CRON = "job_cron" # Triggered by a scheduled job (cron)
|
|
31
|
+
JOB_WEBHOOK = "job_webhook" # Triggered by a webhook job
|
|
32
|
+
JOB_MANUAL = "job_manual" # Triggered manually through job trigger API
|
|
33
|
+
SYSTEM = "system" # Triggered by system/automation
|
|
34
|
+
API = "api" # Triggered directly via API
|
|
35
|
+
CHAT = "chat" # Triggered from chat interface
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Execution(Base):
|
|
39
|
+
"""Model for tracking agent/team/workflow executions with user attribution"""
|
|
40
|
+
|
|
41
|
+
__tablename__ = "executions"
|
|
42
|
+
|
|
43
|
+
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
44
|
+
|
|
45
|
+
# Organization
|
|
46
|
+
organization_id = Column(String, nullable=False, index=True)
|
|
47
|
+
|
|
48
|
+
# What is being executed
|
|
49
|
+
execution_type = Column(SQLEnum(ExecutionType, values_callable=lambda x: [e.value for e in x]), nullable=False)
|
|
50
|
+
entity_id = Column(String, nullable=False) # agent_id, team_id, or workflow_id
|
|
51
|
+
entity_name = Column(String) # Cached name for display
|
|
52
|
+
runner_name = Column(String, nullable=True) # Cached runner name for filtering
|
|
53
|
+
|
|
54
|
+
# User attribution - who initiated this execution
|
|
55
|
+
user_id = Column(String, nullable=True, index=True)
|
|
56
|
+
user_email = Column(String, nullable=True)
|
|
57
|
+
user_name = Column(String, nullable=True)
|
|
58
|
+
user_avatar = Column(String, nullable=True)
|
|
59
|
+
|
|
60
|
+
# Trigger source - how this execution was initiated
|
|
61
|
+
trigger_source = Column(
|
|
62
|
+
SQLEnum(ExecutionTriggerSource, values_callable=lambda x: [e.value for e in x]),
|
|
63
|
+
default=ExecutionTriggerSource.USER,
|
|
64
|
+
nullable=False,
|
|
65
|
+
index=True
|
|
66
|
+
)
|
|
67
|
+
trigger_metadata = Column(JSON, default={}) # Additional context about the trigger (job_id, webhook payload, etc.)
|
|
68
|
+
|
|
69
|
+
# Execution details
|
|
70
|
+
prompt = Column(Text, nullable=False)
|
|
71
|
+
system_prompt = Column(Text, nullable=True)
|
|
72
|
+
config = Column(JSON, default={})
|
|
73
|
+
|
|
74
|
+
# Status and results
|
|
75
|
+
status = Column(SQLEnum(ExecutionStatus, values_callable=lambda x: [e.value for e in x]), default=ExecutionStatus.PENDING, nullable=False)
|
|
76
|
+
response = Column(Text, nullable=True)
|
|
77
|
+
error_message = Column(Text, nullable=True)
|
|
78
|
+
|
|
79
|
+
# Metadata
|
|
80
|
+
usage = Column(JSON, default={}) # Token usage, cost, etc.
|
|
81
|
+
execution_metadata = Column(JSON, default={}) # Additional metadata
|
|
82
|
+
|
|
83
|
+
# Timestamps
|
|
84
|
+
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
|
85
|
+
started_at = Column(DateTime(timezone=True), nullable=True)
|
|
86
|
+
completed_at = Column(DateTime(timezone=True), nullable=True)
|
|
87
|
+
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
|
88
|
+
|
|
89
|
+
# Relationships
|
|
90
|
+
participants = relationship("ExecutionParticipant", back_populates="execution", cascade="all, delete-orphan", lazy="selectin")
|
|
91
|
+
|
|
92
|
+
def __repr__(self):
|
|
93
|
+
return f"<Execution {self.id} ({self.execution_type}:{self.entity_id}) - {self.status} by {self.user_email}>"
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
from sqlalchemy import Column, String, DateTime, Text, JSON, Enum as SQLEnum, Boolean, ForeignKey, Integer
|
|
2
|
+
from sqlalchemy.dialects.postgresql import UUID
|
|
3
|
+
from sqlalchemy.orm import relationship
|
|
4
|
+
from sqlalchemy.sql import func
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
import uuid
|
|
7
|
+
import enum
|
|
8
|
+
|
|
9
|
+
from control_plane_api.app.database import Base
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class JobStatus(str, enum.Enum):
|
|
13
|
+
"""Job status enumeration"""
|
|
14
|
+
ACTIVE = "active"
|
|
15
|
+
PAUSED = "paused"
|
|
16
|
+
FAILED = "failed"
|
|
17
|
+
DISABLED = "disabled"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class JobTriggerType(str, enum.Enum):
|
|
21
|
+
"""Job trigger type enumeration"""
|
|
22
|
+
CRON = "cron"
|
|
23
|
+
WEBHOOK = "webhook"
|
|
24
|
+
MANUAL = "manual"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ExecutorType(str, enum.Enum):
|
|
28
|
+
"""Job executor routing type"""
|
|
29
|
+
AUTO = "auto" # First available worker queue with active workers
|
|
30
|
+
SPECIFIC_QUEUE = "specific_queue" # Explicit worker queue selection
|
|
31
|
+
ENVIRONMENT = "environment" # Route to specific environment
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PlanningMode(str, enum.Enum):
|
|
35
|
+
"""Planning mode for job execution"""
|
|
36
|
+
ON_THE_FLY = "on_the_fly" # Use planner to determine execution
|
|
37
|
+
PREDEFINED_AGENT = "predefined_agent" # Execute specific agent
|
|
38
|
+
PREDEFINED_TEAM = "predefined_team" # Execute specific team
|
|
39
|
+
PREDEFINED_WORKFLOW = "predefined_workflow" # Execute specific workflow
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Job(Base):
|
|
43
|
+
"""
|
|
44
|
+
Model for scheduled and webhook-triggered jobs.
|
|
45
|
+
|
|
46
|
+
Jobs can be triggered via:
|
|
47
|
+
- Cron schedule (using Temporal Schedules)
|
|
48
|
+
- Webhook URL (with HMAC signature verification)
|
|
49
|
+
- Manual API trigger
|
|
50
|
+
|
|
51
|
+
Jobs execute agents, teams, or workflows with configurable routing.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
__tablename__ = "jobs"
|
|
55
|
+
|
|
56
|
+
id = Column(String, primary_key=True, default=lambda: f"job_{uuid.uuid4()}")
|
|
57
|
+
|
|
58
|
+
# Organization (multi-tenant isolation)
|
|
59
|
+
organization_id = Column(String, nullable=False, index=True)
|
|
60
|
+
|
|
61
|
+
# Job metadata
|
|
62
|
+
name = Column(String, nullable=False, index=True)
|
|
63
|
+
description = Column(Text, nullable=True)
|
|
64
|
+
enabled = Column(Boolean, default=True, nullable=False, index=True)
|
|
65
|
+
status = Column(
|
|
66
|
+
SQLEnum(JobStatus, values_callable=lambda x: [e.value for e in x]),
|
|
67
|
+
default=JobStatus.ACTIVE,
|
|
68
|
+
nullable=False,
|
|
69
|
+
index=True
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Trigger configuration
|
|
73
|
+
trigger_type = Column(
|
|
74
|
+
SQLEnum(JobTriggerType, values_callable=lambda x: [e.value for e in x]),
|
|
75
|
+
nullable=False,
|
|
76
|
+
index=True
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Cron configuration (for CRON trigger type)
|
|
80
|
+
cron_schedule = Column(String, nullable=True) # e.g., "0 17 * * *" (daily at 5pm)
|
|
81
|
+
cron_timezone = Column(String, default="UTC", nullable=True) # e.g., "America/New_York"
|
|
82
|
+
|
|
83
|
+
# Webhook configuration (for WEBHOOK trigger type)
|
|
84
|
+
webhook_url_path = Column(String, nullable=True, unique=True, index=True) # e.g., "/api/v1/jobs/webhook/abc123"
|
|
85
|
+
webhook_secret = Column(String, nullable=True) # HMAC secret for signature verification
|
|
86
|
+
|
|
87
|
+
# Temporal Schedule ID (managed by system)
|
|
88
|
+
temporal_schedule_id = Column(String, nullable=True, unique=True, index=True)
|
|
89
|
+
|
|
90
|
+
# Planning and execution configuration
|
|
91
|
+
planning_mode = Column(
|
|
92
|
+
SQLEnum(PlanningMode, values_callable=lambda x: [e.value for e in x]),
|
|
93
|
+
default=PlanningMode.PREDEFINED_AGENT,
|
|
94
|
+
nullable=False
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Entity to execute (based on planning_mode)
|
|
98
|
+
entity_type = Column(String, nullable=True) # "agent", "team", "workflow" (for predefined modes)
|
|
99
|
+
entity_id = Column(String, nullable=True) # agent_id, team_id, or workflow_id
|
|
100
|
+
entity_name = Column(String, nullable=True) # Cached name for display
|
|
101
|
+
|
|
102
|
+
# Prompt configuration
|
|
103
|
+
prompt_template = Column(Text, nullable=False) # Can include {{variables}} for dynamic params
|
|
104
|
+
system_prompt = Column(Text, nullable=True)
|
|
105
|
+
|
|
106
|
+
# Executor routing configuration
|
|
107
|
+
executor_type = Column(
|
|
108
|
+
SQLEnum(ExecutorType, values_callable=lambda x: [e.value for e in x]),
|
|
109
|
+
default=ExecutorType.AUTO,
|
|
110
|
+
nullable=False
|
|
111
|
+
)
|
|
112
|
+
worker_queue_name = Column(String, nullable=True) # For SPECIFIC_QUEUE executor type
|
|
113
|
+
environment_name = Column(String, nullable=True) # For ENVIRONMENT executor type
|
|
114
|
+
|
|
115
|
+
# Execution configuration
|
|
116
|
+
config = Column(JSON, default={}) # Additional execution config (timeout, retry, etc.)
|
|
117
|
+
execution_environment = Column(JSON, default={}) # Environment variables, secrets, etc.
|
|
118
|
+
|
|
119
|
+
# Execution tracking
|
|
120
|
+
last_execution_id = Column(UUID(as_uuid=True), ForeignKey("executions.id", ondelete="SET NULL"), nullable=True)
|
|
121
|
+
last_execution_at = Column(DateTime(timezone=True), nullable=True)
|
|
122
|
+
next_execution_at = Column(DateTime(timezone=True), nullable=True) # For cron jobs
|
|
123
|
+
total_executions = Column(Integer, default=0, nullable=False) # Total number of executions
|
|
124
|
+
successful_executions = Column(Integer, default=0, nullable=False) # Number of successful executions
|
|
125
|
+
failed_executions = Column(Integer, default=0, nullable=False) # Number of failed executions
|
|
126
|
+
|
|
127
|
+
# Execution history (last N runs)
|
|
128
|
+
execution_history = Column(JSON, default=list) # List of recent execution summaries
|
|
129
|
+
|
|
130
|
+
# Audit fields
|
|
131
|
+
created_by = Column(String, nullable=True) # User ID who created the job
|
|
132
|
+
updated_by = Column(String, nullable=True) # User ID who last updated the job
|
|
133
|
+
|
|
134
|
+
# Timestamps
|
|
135
|
+
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
|
136
|
+
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
|
137
|
+
last_triggered_at = Column(DateTime(timezone=True), nullable=True) # Last time job was triggered (manual or scheduled)
|
|
138
|
+
|
|
139
|
+
# Relationships
|
|
140
|
+
last_execution = relationship("Execution", foreign_keys=[last_execution_id], lazy="select")
|
|
141
|
+
|
|
142
|
+
def __repr__(self):
|
|
143
|
+
return f"<Job {self.id} ({self.name}) - {self.trigger_type}:{self.status}>"
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class JobExecution(Base):
|
|
147
|
+
"""
|
|
148
|
+
Junction table linking Jobs to Executions.
|
|
149
|
+
Tracks which executions were triggered by which jobs.
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
__tablename__ = "job_executions"
|
|
153
|
+
|
|
154
|
+
id = Column(String, primary_key=True, default=lambda: f"jobexec_{uuid.uuid4()}")
|
|
155
|
+
|
|
156
|
+
# Foreign keys
|
|
157
|
+
job_id = Column(String, ForeignKey("jobs.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
158
|
+
execution_id = Column(UUID(as_uuid=True), ForeignKey("executions.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
159
|
+
|
|
160
|
+
# Organization (for efficient querying)
|
|
161
|
+
organization_id = Column(String, nullable=False, index=True)
|
|
162
|
+
|
|
163
|
+
# Trigger context
|
|
164
|
+
trigger_type = Column(String, nullable=False) # "cron", "webhook", "manual"
|
|
165
|
+
trigger_metadata = Column(JSON, default={}) # Additional context (webhook payload, manual trigger user, etc.)
|
|
166
|
+
|
|
167
|
+
# Execution outcome (denormalized for quick queries)
|
|
168
|
+
execution_status = Column(String, nullable=True) # Cached from execution.status
|
|
169
|
+
execution_duration_ms = Column(Integer, nullable=True) # Duration in milliseconds
|
|
170
|
+
|
|
171
|
+
# Timestamps
|
|
172
|
+
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
|
173
|
+
|
|
174
|
+
# Relationships
|
|
175
|
+
job = relationship("Job", foreign_keys=[job_id], lazy="select")
|
|
176
|
+
execution = relationship("Execution", foreign_keys=[execution_id], lazy="select")
|
|
177
|
+
|
|
178
|
+
def __repr__(self):
|
|
179
|
+
return f"<JobExecution job={self.job_id} execution={self.execution_id}>"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""LLM Model database model"""
|
|
2
|
+
from sqlalchemy import Column, String, Boolean, Text, JSON, Integer
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from sqlalchemy import DateTime
|
|
5
|
+
import uuid as uuid_module
|
|
6
|
+
|
|
7
|
+
from control_plane_api.app.database import Base
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LLMModel(Base):
|
|
11
|
+
"""
|
|
12
|
+
LLM Model configuration for agent execution.
|
|
13
|
+
|
|
14
|
+
Stores available LLM models that can be used by agents and teams,
|
|
15
|
+
including provider information, compatibility, and UI metadata.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
__tablename__ = "llm_models"
|
|
19
|
+
|
|
20
|
+
id = Column(String, primary_key=True, default=lambda: str(uuid_module.uuid4()))
|
|
21
|
+
|
|
22
|
+
# Model identification
|
|
23
|
+
value = Column(String, unique=True, nullable=False, index=True)
|
|
24
|
+
label = Column(String, nullable=False)
|
|
25
|
+
provider = Column(String, nullable=False, index=True)
|
|
26
|
+
|
|
27
|
+
# UI metadata
|
|
28
|
+
logo = Column(String, nullable=True)
|
|
29
|
+
description = Column(Text, nullable=True)
|
|
30
|
+
|
|
31
|
+
# Status and flags
|
|
32
|
+
enabled = Column(Boolean, default=True, nullable=False, index=True)
|
|
33
|
+
recommended = Column(Boolean, default=False, nullable=False)
|
|
34
|
+
|
|
35
|
+
# Runtime compatibility
|
|
36
|
+
# Store list of compatible runtime types (e.g., ["default", "claude_code"])
|
|
37
|
+
compatible_runtimes = Column(JSON, default=list, nullable=False)
|
|
38
|
+
|
|
39
|
+
# Model capabilities and metadata
|
|
40
|
+
capabilities = Column(JSON, default=dict, nullable=False)
|
|
41
|
+
# Example: {"vision": true, "function_calling": true, "max_tokens": 4096}
|
|
42
|
+
|
|
43
|
+
# Pricing information (optional)
|
|
44
|
+
pricing = Column(JSON, default=dict, nullable=True)
|
|
45
|
+
# Example: {"input_cost_per_1k": 0.01, "output_cost_per_1k": 0.03}
|
|
46
|
+
|
|
47
|
+
# Display order (lower = shown first)
|
|
48
|
+
display_order = Column(Integer, default=1000, nullable=False)
|
|
49
|
+
|
|
50
|
+
# Metadata
|
|
51
|
+
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
|
52
|
+
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
|
53
|
+
created_by = Column(String, nullable=True) # User ID who created this model entry
|
|
54
|
+
|
|
55
|
+
def __repr__(self):
|
|
56
|
+
return f"<LLMModel(id={self.id}, value={self.value}, provider={self.provider})>"
|
|
57
|
+
|
|
58
|
+
def to_dict(self):
|
|
59
|
+
"""Convert to dictionary for API responses"""
|
|
60
|
+
return {
|
|
61
|
+
"id": self.id,
|
|
62
|
+
"value": self.value,
|
|
63
|
+
"label": self.label,
|
|
64
|
+
"provider": self.provider,
|
|
65
|
+
"logo": self.logo,
|
|
66
|
+
"description": self.description,
|
|
67
|
+
"enabled": self.enabled,
|
|
68
|
+
"recommended": self.recommended,
|
|
69
|
+
"compatible_runtimes": self.compatible_runtimes,
|
|
70
|
+
"capabilities": self.capabilities,
|
|
71
|
+
"pricing": self.pricing,
|
|
72
|
+
"display_order": self.display_order,
|
|
73
|
+
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|
74
|
+
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|
75
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from sqlalchemy import Column, String, DateTime, Boolean, Index
|
|
2
|
+
from sqlalchemy.sql import func
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
from control_plane_api.app.database import Base
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UserPresence(Base):
|
|
10
|
+
"""Model for tracking user presence on agents/tasks for real-time collaboration"""
|
|
11
|
+
|
|
12
|
+
__tablename__ = "user_presence"
|
|
13
|
+
|
|
14
|
+
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
|
|
15
|
+
|
|
16
|
+
# User information
|
|
17
|
+
user_id = Column(String, nullable=False, index=True)
|
|
18
|
+
user_email = Column(String, nullable=True)
|
|
19
|
+
user_name = Column(String, nullable=True)
|
|
20
|
+
user_avatar = Column(String, nullable=True)
|
|
21
|
+
|
|
22
|
+
# What the user is viewing/interacting with
|
|
23
|
+
agent_id = Column(String, nullable=True, index=True)
|
|
24
|
+
session_id = Column(String, nullable=True, index=True)
|
|
25
|
+
execution_id = Column(String, nullable=True, index=True)
|
|
26
|
+
|
|
27
|
+
# Presence state
|
|
28
|
+
is_active = Column(Boolean, default=True, nullable=False)
|
|
29
|
+
is_typing = Column(Boolean, default=False, nullable=False)
|
|
30
|
+
|
|
31
|
+
# Timestamps
|
|
32
|
+
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
|
33
|
+
last_active_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
|
34
|
+
|
|
35
|
+
# Create composite index for efficient queries
|
|
36
|
+
__table_args__ = (
|
|
37
|
+
Index('idx_presence_lookup', 'agent_id', 'is_active', 'last_active_at'),
|
|
38
|
+
Index('idx_presence_user', 'user_id', 'is_active'),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def __repr__(self):
|
|
42
|
+
return f"<UserPresence(user_id={self.user_id}, agent_id={self.agent_id}, is_active={self.is_active})>"
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def is_stale(self) -> bool:
|
|
46
|
+
"""Check if presence is stale (no activity in last 5 minutes)"""
|
|
47
|
+
if not self.last_active_at:
|
|
48
|
+
return True
|
|
49
|
+
return (datetime.utcnow() - self.last_active_at).total_seconds() > 300 # 5 minutes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from sqlalchemy import Column, String, DateTime, Text, JSON, Enum, Boolean
|
|
2
|
+
from sqlalchemy.orm import relationship
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
import enum
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
from control_plane_api.app.database import Base
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ProjectStatus(str, enum.Enum):
|
|
11
|
+
"""Project status enumeration"""
|
|
12
|
+
|
|
13
|
+
ACTIVE = "active"
|
|
14
|
+
ARCHIVED = "archived"
|
|
15
|
+
PAUSED = "paused"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Project(Base):
|
|
19
|
+
"""Project model for organizing agents, teams, and tasks"""
|
|
20
|
+
|
|
21
|
+
__tablename__ = "projects"
|
|
22
|
+
|
|
23
|
+
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
|
|
24
|
+
organization_id = Column(String, nullable=False, index=True)
|
|
25
|
+
name = Column(String, nullable=False, index=True)
|
|
26
|
+
description = Column(Text, nullable=True)
|
|
27
|
+
goals = Column(Text, nullable=True)
|
|
28
|
+
status = Column(Enum(ProjectStatus, values_callable=lambda x: [e.value for e in x]), default=ProjectStatus.ACTIVE, nullable=False)
|
|
29
|
+
|
|
30
|
+
# Environment and runner configuration
|
|
31
|
+
restrict_to_environment = Column(Boolean, default=False, nullable=False)
|
|
32
|
+
# Note: policy_ids are stored in settings JSON field, not as separate column
|
|
33
|
+
|
|
34
|
+
# Default settings for project
|
|
35
|
+
default_model = Column(String, nullable=True) # Default LLM model for this project
|
|
36
|
+
default_settings = Column(JSON, default=dict, nullable=False) # Additional project-wide settings
|
|
37
|
+
|
|
38
|
+
# Metadata
|
|
39
|
+
is_default = Column(Boolean, default=False, nullable=False) # Flag for the default project
|
|
40
|
+
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
|
41
|
+
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
|
42
|
+
|
|
43
|
+
# Note: Project associations are managed through junction tables (project_agents, project_teams)
|
|
44
|
+
# in Supabase, not through direct foreign keys in the SQLAlchemy models
|
|
45
|
+
|
|
46
|
+
def __repr__(self):
|
|
47
|
+
return f"<Project(id={self.id}, name={self.name}, status={self.status})>"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from sqlalchemy import Column, String, DateTime, Text, JSON, ForeignKey
|
|
2
|
+
from sqlalchemy.orm import relationship
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
from control_plane_api.app.database import Base
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Session(Base):
|
|
10
|
+
"""Session model for storing agent session information with multi-user support"""
|
|
11
|
+
|
|
12
|
+
__tablename__ = "sessions"
|
|
13
|
+
|
|
14
|
+
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
|
|
15
|
+
agent_id = Column(String, ForeignKey("agents.id"), nullable=False)
|
|
16
|
+
|
|
17
|
+
# Multi-user support - inspired by Agno's multi-user pattern
|
|
18
|
+
user_id = Column(String, nullable=True, index=True) # User who owns this session
|
|
19
|
+
user_email = Column(String, nullable=True)
|
|
20
|
+
user_name = Column(String, nullable=True)
|
|
21
|
+
user_avatar = Column(String, nullable=True)
|
|
22
|
+
|
|
23
|
+
# Session data
|
|
24
|
+
messages = Column(JSON, default=list, nullable=False)
|
|
25
|
+
context = Column(JSON, default=dict, nullable=False)
|
|
26
|
+
session_metadata = Column(JSON, default=dict, nullable=False)
|
|
27
|
+
|
|
28
|
+
# Timestamps
|
|
29
|
+
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
|
30
|
+
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
|
31
|
+
expires_at = Column(DateTime, nullable=True)
|
|
32
|
+
last_active_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
|
33
|
+
|
|
34
|
+
# Relationships
|
|
35
|
+
agent = relationship("Agent", back_populates="sessions")
|
|
36
|
+
|
|
37
|
+
def __repr__(self):
|
|
38
|
+
return f"<Session(id={self.id}, agent_id={self.agent_id}, user_id={self.user_id})>"
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from sqlalchemy import Column, String, DateTime, Text, JSON, Enum, ForeignKey, UniqueConstraint, ARRAY
|
|
2
|
+
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
|
|
3
|
+
from sqlalchemy.orm import relationship
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
import enum
|
|
6
|
+
import uuid as uuid_module
|
|
7
|
+
|
|
8
|
+
from control_plane_api.app.database import Base
|
|
9
|
+
from control_plane_api.app.models.agent import RuntimeType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TeamStatus(str, enum.Enum):
|
|
13
|
+
"""Team status enumeration"""
|
|
14
|
+
|
|
15
|
+
ACTIVE = "active"
|
|
16
|
+
INACTIVE = "inactive"
|
|
17
|
+
ARCHIVED = "archived"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Team(Base):
|
|
21
|
+
"""Team model for storing team information"""
|
|
22
|
+
|
|
23
|
+
__tablename__ = "teams"
|
|
24
|
+
__table_args__ = (
|
|
25
|
+
UniqueConstraint('organization_id', 'name', name='uq_team_org_name'),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
id = Column(String, primary_key=True, default=lambda: str(uuid_module.uuid4()))
|
|
29
|
+
organization_id = Column(String, nullable=False, index=True)
|
|
30
|
+
name = Column(String, nullable=False, index=True)
|
|
31
|
+
description = Column(Text, nullable=True)
|
|
32
|
+
status = Column(Enum(TeamStatus, values_callable=lambda x: [e.value for e in x]), default=TeamStatus.ACTIVE, nullable=False)
|
|
33
|
+
|
|
34
|
+
# Configuration
|
|
35
|
+
configuration = Column(JSON, default=dict, nullable=False)
|
|
36
|
+
# Use PostgreSQL UUID array - SQLAlchemy will handle the conversion
|
|
37
|
+
skill_ids = Column(ARRAY(PG_UUID(as_uuid=False)), default=list, nullable=False)
|
|
38
|
+
execution_environment = Column(JSON, default=dict, nullable=False)
|
|
39
|
+
|
|
40
|
+
# Runtime configuration
|
|
41
|
+
runtime = Column(
|
|
42
|
+
Enum(RuntimeType, values_callable=lambda x: [e.value for e in x]),
|
|
43
|
+
default=RuntimeType.DEFAULT,
|
|
44
|
+
server_default="default",
|
|
45
|
+
nullable=False,
|
|
46
|
+
index=True
|
|
47
|
+
) # Runtime type for team execution (default: Agno, claude_code: Claude Code SDK)
|
|
48
|
+
|
|
49
|
+
# Metadata
|
|
50
|
+
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
|
51
|
+
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
|
52
|
+
|
|
53
|
+
# Relationships
|
|
54
|
+
agents = relationship("Agent", back_populates="team")
|
|
55
|
+
workflows = relationship("Workflow", back_populates="team", cascade="all, delete-orphan")
|
|
56
|
+
|
|
57
|
+
# Many-to-many relationship with environments
|
|
58
|
+
environment_associations = relationship(
|
|
59
|
+
"TeamEnvironment",
|
|
60
|
+
foreign_keys="TeamEnvironment.team_id",
|
|
61
|
+
cascade="all, delete-orphan",
|
|
62
|
+
lazy="select"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def __repr__(self):
|
|
66
|
+
return f"<Team(id={self.id}, name={self.name}, status={self.status})>"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from sqlalchemy import Column, String, DateTime, Text, JSON, ForeignKey, Enum
|
|
2
|
+
from sqlalchemy.orm import relationship
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
import enum
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
from control_plane_api.app.database import Base
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class WorkflowStatus(str, enum.Enum):
|
|
11
|
+
"""Workflow status enumeration"""
|
|
12
|
+
|
|
13
|
+
PENDING = "pending"
|
|
14
|
+
RUNNING = "running"
|
|
15
|
+
PAUSED = "paused"
|
|
16
|
+
COMPLETED = "completed"
|
|
17
|
+
FAILED = "failed"
|
|
18
|
+
CANCELLED = "cancelled"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Workflow(Base):
|
|
22
|
+
"""Workflow model for storing workflow information"""
|
|
23
|
+
|
|
24
|
+
__tablename__ = "workflows"
|
|
25
|
+
|
|
26
|
+
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
|
|
27
|
+
name = Column(String, nullable=False, index=True)
|
|
28
|
+
description = Column(Text, nullable=True)
|
|
29
|
+
status = Column(Enum(WorkflowStatus, values_callable=lambda x: [e.value for e in x]), default=WorkflowStatus.PENDING, nullable=False)
|
|
30
|
+
|
|
31
|
+
# Workflow definition
|
|
32
|
+
steps = Column(JSON, default=list, nullable=False)
|
|
33
|
+
current_step = Column(String, nullable=True)
|
|
34
|
+
|
|
35
|
+
# Configuration
|
|
36
|
+
configuration = Column(JSON, default=dict, nullable=False)
|
|
37
|
+
|
|
38
|
+
# Relationships
|
|
39
|
+
team_id = Column(String, ForeignKey("teams.id"), nullable=True)
|
|
40
|
+
|
|
41
|
+
# Metadata
|
|
42
|
+
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
|
43
|
+
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
|
44
|
+
started_at = Column(DateTime, nullable=True)
|
|
45
|
+
completed_at = Column(DateTime, nullable=True)
|
|
46
|
+
|
|
47
|
+
# State management
|
|
48
|
+
state = Column(JSON, default=dict, nullable=False)
|
|
49
|
+
error_message = Column(Text, nullable=True)
|
|
50
|
+
|
|
51
|
+
# Relationships
|
|
52
|
+
team = relationship("Team", back_populates="workflows")
|
|
53
|
+
|
|
54
|
+
def __repr__(self):
|
|
55
|
+
return f"<Workflow(id={self.id}, name={self.name}, status={self.status})>"
|