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,162 @@
|
|
|
1
|
+
"""add comprehensive analytics tables for execution tracking
|
|
2
|
+
|
|
3
|
+
Revision ID: 1f54bc2a37e3
|
|
4
|
+
Revises: add_llm_models_table
|
|
5
|
+
Create Date: 2025-01-08 14:00:00.000000
|
|
6
|
+
|
|
7
|
+
This migration adds production-grade analytics tables to track:
|
|
8
|
+
- Per-turn LLM metrics (tokens, duration, cost)
|
|
9
|
+
- Tool execution details (success/failure, timing)
|
|
10
|
+
- Task completion tracking
|
|
11
|
+
"""
|
|
12
|
+
from alembic import op
|
|
13
|
+
import sqlalchemy as sa
|
|
14
|
+
from sqlalchemy.dialects import postgresql
|
|
15
|
+
|
|
16
|
+
# revision identifiers, used by Alembic.
|
|
17
|
+
revision = '1f54bc2a37e3'
|
|
18
|
+
down_revision = 'add_llm_models_table'
|
|
19
|
+
branch_labels = None
|
|
20
|
+
depends_on = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def upgrade():
|
|
24
|
+
# Create execution_turns table
|
|
25
|
+
op.create_table(
|
|
26
|
+
'execution_turns',
|
|
27
|
+
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
|
|
28
|
+
sa.Column('organization_id', sa.String(), nullable=False),
|
|
29
|
+
sa.Column('execution_id', postgresql.UUID(as_uuid=True), nullable=False),
|
|
30
|
+
sa.Column('turn_number', sa.Integer(), nullable=False),
|
|
31
|
+
sa.Column('turn_id', sa.String(), nullable=True),
|
|
32
|
+
sa.Column('model', sa.String(), nullable=False),
|
|
33
|
+
sa.Column('model_provider', sa.String(), nullable=True),
|
|
34
|
+
sa.Column('started_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
|
|
35
|
+
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
|
|
36
|
+
sa.Column('duration_ms', sa.Integer(), nullable=True),
|
|
37
|
+
sa.Column('input_tokens', sa.Integer(), nullable=True, server_default='0'),
|
|
38
|
+
sa.Column('output_tokens', sa.Integer(), nullable=True, server_default='0'),
|
|
39
|
+
sa.Column('cache_read_tokens', sa.Integer(), nullable=True, server_default='0'),
|
|
40
|
+
sa.Column('cache_creation_tokens', sa.Integer(), nullable=True, server_default='0'),
|
|
41
|
+
sa.Column('total_tokens', sa.Integer(), nullable=True, server_default='0'),
|
|
42
|
+
sa.Column('input_cost', sa.Float(), nullable=True, server_default='0.0'),
|
|
43
|
+
sa.Column('output_cost', sa.Float(), nullable=True, server_default='0.0'),
|
|
44
|
+
sa.Column('cache_read_cost', sa.Float(), nullable=True, server_default='0.0'),
|
|
45
|
+
sa.Column('cache_creation_cost', sa.Float(), nullable=True, server_default='0.0'),
|
|
46
|
+
sa.Column('total_cost', sa.Float(), nullable=True, server_default='0.0'),
|
|
47
|
+
sa.Column('finish_reason', sa.String(), nullable=True),
|
|
48
|
+
sa.Column('response_preview', sa.Text(), nullable=True),
|
|
49
|
+
sa.Column('tools_called_count', sa.Integer(), nullable=False, server_default='0'),
|
|
50
|
+
sa.Column('tools_called_names', postgresql.JSON(astext_type=sa.Text()), nullable=False, server_default='[]'),
|
|
51
|
+
sa.Column('error_message', sa.Text(), nullable=True),
|
|
52
|
+
sa.Column('metrics', postgresql.JSON(astext_type=sa.Text()), nullable=False, server_default='{}'),
|
|
53
|
+
sa.Column('runtime_minutes', sa.Float(), nullable=True, server_default='0.0'),
|
|
54
|
+
sa.Column('model_weight', sa.Float(), nullable=True, server_default='1.0'),
|
|
55
|
+
sa.Column('tool_calls_weight', sa.Float(), nullable=True, server_default='1.0'),
|
|
56
|
+
sa.Column('aem_value', sa.Float(), nullable=True, server_default='0.0'),
|
|
57
|
+
sa.Column('aem_cost', sa.Float(), nullable=True, server_default='0.0'),
|
|
58
|
+
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
|
|
59
|
+
sa.PrimaryKeyConstraint('id'),
|
|
60
|
+
sa.ForeignKeyConstraint(['execution_id'], ['executions.id'], ondelete='CASCADE')
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Create indexes for execution_turns
|
|
64
|
+
op.create_index('ix_execution_turns_organization_id', 'execution_turns', ['organization_id'])
|
|
65
|
+
op.create_index('ix_execution_turns_execution_id', 'execution_turns', ['execution_id'])
|
|
66
|
+
op.create_index('ix_execution_turns_org_execution', 'execution_turns', ['organization_id', 'execution_id'])
|
|
67
|
+
op.create_index('ix_execution_turns_org_model', 'execution_turns', ['organization_id', 'model'])
|
|
68
|
+
op.create_index('ix_execution_turns_org_created', 'execution_turns', ['organization_id', 'created_at'])
|
|
69
|
+
op.create_index('ix_execution_turns_org_cost', 'execution_turns', ['organization_id', 'total_cost'])
|
|
70
|
+
|
|
71
|
+
# Create execution_tool_calls table
|
|
72
|
+
op.create_table(
|
|
73
|
+
'execution_tool_calls',
|
|
74
|
+
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
|
|
75
|
+
sa.Column('organization_id', sa.String(), nullable=False),
|
|
76
|
+
sa.Column('execution_id', postgresql.UUID(as_uuid=True), nullable=False),
|
|
77
|
+
sa.Column('turn_id', postgresql.UUID(as_uuid=True), nullable=True),
|
|
78
|
+
sa.Column('tool_name', sa.String(), nullable=False),
|
|
79
|
+
sa.Column('tool_use_id', sa.String(), nullable=True),
|
|
80
|
+
sa.Column('started_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
|
|
81
|
+
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
|
|
82
|
+
sa.Column('duration_ms', sa.Integer(), nullable=True),
|
|
83
|
+
sa.Column('tool_input', postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
|
84
|
+
sa.Column('tool_output', sa.Text(), nullable=True),
|
|
85
|
+
sa.Column('tool_output_size', sa.Integer(), nullable=True),
|
|
86
|
+
sa.Column('success', sa.Boolean(), nullable=False, server_default='true'),
|
|
87
|
+
sa.Column('error_message', sa.Text(), nullable=True),
|
|
88
|
+
sa.Column('error_type', sa.String(), nullable=True),
|
|
89
|
+
sa.Column('metadata', postgresql.JSON(astext_type=sa.Text()), nullable=False, server_default='{}'),
|
|
90
|
+
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
|
|
91
|
+
sa.PrimaryKeyConstraint('id'),
|
|
92
|
+
sa.ForeignKeyConstraint(['execution_id'], ['executions.id'], ondelete='CASCADE'),
|
|
93
|
+
sa.ForeignKeyConstraint(['turn_id'], ['execution_turns.id'], ondelete='CASCADE')
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Create indexes for execution_tool_calls
|
|
97
|
+
op.create_index('ix_execution_tool_calls_organization_id', 'execution_tool_calls', ['organization_id'])
|
|
98
|
+
op.create_index('ix_execution_tool_calls_execution_id', 'execution_tool_calls', ['execution_id'])
|
|
99
|
+
op.create_index('ix_execution_tool_calls_turn_id', 'execution_tool_calls', ['turn_id'])
|
|
100
|
+
op.create_index('ix_execution_tool_calls_tool_name', 'execution_tool_calls', ['tool_name'])
|
|
101
|
+
op.create_index('ix_execution_tool_calls_org_execution', 'execution_tool_calls', ['organization_id', 'execution_id'])
|
|
102
|
+
op.create_index('ix_execution_tool_calls_org_tool', 'execution_tool_calls', ['organization_id', 'tool_name'])
|
|
103
|
+
op.create_index('ix_execution_tool_calls_org_success', 'execution_tool_calls', ['organization_id', 'success'])
|
|
104
|
+
op.create_index('ix_execution_tool_calls_org_created', 'execution_tool_calls', ['organization_id', 'created_at'])
|
|
105
|
+
|
|
106
|
+
# Create execution_tasks table
|
|
107
|
+
op.create_table(
|
|
108
|
+
'execution_tasks',
|
|
109
|
+
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
|
|
110
|
+
sa.Column('organization_id', sa.String(), nullable=False),
|
|
111
|
+
sa.Column('execution_id', postgresql.UUID(as_uuid=True), nullable=False),
|
|
112
|
+
sa.Column('task_number', sa.Integer(), nullable=True),
|
|
113
|
+
sa.Column('task_id', sa.String(), nullable=True),
|
|
114
|
+
sa.Column('task_description', sa.Text(), nullable=False),
|
|
115
|
+
sa.Column('task_type', sa.String(), nullable=True),
|
|
116
|
+
sa.Column('status', sa.String(), nullable=False, server_default='pending'),
|
|
117
|
+
sa.Column('started_at', sa.DateTime(timezone=True), nullable=True),
|
|
118
|
+
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
|
|
119
|
+
sa.Column('duration_ms', sa.Integer(), nullable=True),
|
|
120
|
+
sa.Column('result', sa.Text(), nullable=True),
|
|
121
|
+
sa.Column('error_message', sa.Text(), nullable=True),
|
|
122
|
+
sa.Column('metadata', postgresql.JSON(astext_type=sa.Text()), nullable=False, server_default='{}'),
|
|
123
|
+
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
|
|
124
|
+
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
|
|
125
|
+
sa.PrimaryKeyConstraint('id'),
|
|
126
|
+
sa.ForeignKeyConstraint(['execution_id'], ['executions.id'], ondelete='CASCADE')
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Create indexes for execution_tasks
|
|
130
|
+
op.create_index('ix_execution_tasks_organization_id', 'execution_tasks', ['organization_id'])
|
|
131
|
+
op.create_index('ix_execution_tasks_execution_id', 'execution_tasks', ['execution_id'])
|
|
132
|
+
op.create_index('ix_execution_tasks_org_execution', 'execution_tasks', ['organization_id', 'execution_id'])
|
|
133
|
+
op.create_index('ix_execution_tasks_org_status', 'execution_tasks', ['organization_id', 'status'])
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def downgrade():
|
|
137
|
+
# Drop execution_tasks table and indexes
|
|
138
|
+
op.drop_index('ix_execution_tasks_org_status', table_name='execution_tasks')
|
|
139
|
+
op.drop_index('ix_execution_tasks_org_execution', table_name='execution_tasks')
|
|
140
|
+
op.drop_index('ix_execution_tasks_execution_id', table_name='execution_tasks')
|
|
141
|
+
op.drop_index('ix_execution_tasks_organization_id', table_name='execution_tasks')
|
|
142
|
+
op.drop_table('execution_tasks')
|
|
143
|
+
|
|
144
|
+
# Drop execution_tool_calls table and indexes
|
|
145
|
+
op.drop_index('ix_execution_tool_calls_org_created', table_name='execution_tool_calls')
|
|
146
|
+
op.drop_index('ix_execution_tool_calls_org_success', table_name='execution_tool_calls')
|
|
147
|
+
op.drop_index('ix_execution_tool_calls_org_tool', table_name='execution_tool_calls')
|
|
148
|
+
op.drop_index('ix_execution_tool_calls_org_execution', table_name='execution_tool_calls')
|
|
149
|
+
op.drop_index('ix_execution_tool_calls_tool_name', table_name='execution_tool_calls')
|
|
150
|
+
op.drop_index('ix_execution_tool_calls_turn_id', table_name='execution_tool_calls')
|
|
151
|
+
op.drop_index('ix_execution_tool_calls_execution_id', table_name='execution_tool_calls')
|
|
152
|
+
op.drop_index('ix_execution_tool_calls_organization_id', table_name='execution_tool_calls')
|
|
153
|
+
op.drop_table('execution_tool_calls')
|
|
154
|
+
|
|
155
|
+
# Drop execution_turns table and indexes
|
|
156
|
+
op.drop_index('ix_execution_turns_org_cost', table_name='execution_turns')
|
|
157
|
+
op.drop_index('ix_execution_turns_org_created', table_name='execution_turns')
|
|
158
|
+
op.drop_index('ix_execution_turns_org_model', table_name='execution_turns')
|
|
159
|
+
op.drop_index('ix_execution_turns_org_execution', table_name='execution_turns')
|
|
160
|
+
op.drop_index('ix_execution_turns_execution_id', table_name='execution_turns')
|
|
161
|
+
op.drop_index('ix_execution_turns_organization_id', table_name='execution_turns')
|
|
162
|
+
op.drop_table('execution_turns')
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""rename_toolset_ids_to_skill_ids_in_teams
|
|
2
|
+
|
|
3
|
+
Revision ID: 2e4cb136dc10
|
|
4
|
+
Revises: d4eaf16e3f8d
|
|
5
|
+
Create Date: 2025-11-06 21:31:20.981166
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from typing import Sequence, Union
|
|
9
|
+
|
|
10
|
+
from alembic import op
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = '2e4cb136dc10'
|
|
16
|
+
down_revision: Union[str, Sequence[str], None] = 'd4eaf16e3f8d'
|
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
18
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
"""Rename toolset_ids to skill_ids in teams table."""
|
|
23
|
+
# Rename toolset_ids column to skill_ids
|
|
24
|
+
op.alter_column('teams', 'toolset_ids', new_column_name='skill_ids')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def downgrade() -> None:
|
|
28
|
+
"""Rename skill_ids back to toolset_ids in teams table."""
|
|
29
|
+
# Reverse the column rename
|
|
30
|
+
op.alter_column('teams', 'skill_ids', new_column_name='toolset_ids')
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""add_skill_templates_table
|
|
2
|
+
|
|
3
|
+
Revision ID: 31cd69a644ce
|
|
4
|
+
Revises: f973b431d1ce
|
|
5
|
+
Create Date: 2025-11-08 10:35:32.991694
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from typing import Sequence, Union
|
|
9
|
+
|
|
10
|
+
from alembic import op
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = '31cd69a644ce'
|
|
16
|
+
down_revision: Union[str, Sequence[str], None] = 'f973b431d1ce'
|
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
18
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
"""Upgrade schema."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def downgrade() -> None:
|
|
27
|
+
"""Downgrade schema."""
|
|
28
|
+
pass
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""add_jobs_and_job_executions_tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 89e127caa47d
|
|
4
|
+
Revises: b0e10697f212
|
|
5
|
+
Create Date: 2025-11-06 20:11:04.561446
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from typing import Sequence, Union
|
|
9
|
+
|
|
10
|
+
from alembic import op
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = '89e127caa47d'
|
|
16
|
+
down_revision: Union[str, Sequence[str], None] = 'b0e10697f212'
|
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
18
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
"""Upgrade schema."""
|
|
23
|
+
# Create jobs table
|
|
24
|
+
op.create_table(
|
|
25
|
+
'jobs',
|
|
26
|
+
sa.Column('id', sa.String(255), primary_key=True),
|
|
27
|
+
sa.Column('organization_id', sa.String(255), nullable=False),
|
|
28
|
+
sa.Column('name', sa.String(255), nullable=False),
|
|
29
|
+
sa.Column('description', sa.Text(), nullable=True),
|
|
30
|
+
sa.Column('enabled', sa.Boolean(), nullable=False, server_default='true'),
|
|
31
|
+
sa.Column('status', sa.String(50), nullable=False, server_default='active'),
|
|
32
|
+
sa.Column('trigger_type', sa.String(50), nullable=False),
|
|
33
|
+
sa.Column('cron_schedule', sa.String(255), nullable=True),
|
|
34
|
+
sa.Column('cron_timezone', sa.String(100), server_default='UTC'),
|
|
35
|
+
sa.Column('webhook_url_path', sa.String(500), nullable=True),
|
|
36
|
+
sa.Column('webhook_secret', sa.String(500), nullable=True),
|
|
37
|
+
sa.Column('temporal_schedule_id', sa.String(255), nullable=True),
|
|
38
|
+
sa.Column('planning_mode', sa.String(50), nullable=False, server_default='predefined_agent'),
|
|
39
|
+
sa.Column('entity_type', sa.String(50), nullable=True),
|
|
40
|
+
sa.Column('entity_id', sa.String(255), nullable=True),
|
|
41
|
+
sa.Column('entity_name', sa.String(255), nullable=True),
|
|
42
|
+
sa.Column('prompt_template', sa.Text(), nullable=False),
|
|
43
|
+
sa.Column('system_prompt', sa.Text(), nullable=True),
|
|
44
|
+
sa.Column('executor_type', sa.String(50), nullable=False, server_default='auto'),
|
|
45
|
+
sa.Column('worker_queue_name', sa.String(255), nullable=True),
|
|
46
|
+
sa.Column('environment_name', sa.String(255), nullable=True),
|
|
47
|
+
sa.Column('config', sa.JSON(), server_default='{}'),
|
|
48
|
+
sa.Column('execution_environment', sa.JSON(), server_default='{}'),
|
|
49
|
+
sa.Column('last_execution_id', sa.String(255), nullable=True),
|
|
50
|
+
sa.Column('last_execution_at', sa.DateTime(timezone=True), nullable=True),
|
|
51
|
+
sa.Column('next_execution_at', sa.DateTime(timezone=True), nullable=True),
|
|
52
|
+
sa.Column('total_executions', sa.Integer(), server_default='0'),
|
|
53
|
+
sa.Column('successful_executions', sa.Integer(), server_default='0'),
|
|
54
|
+
sa.Column('failed_executions', sa.Integer(), server_default='0'),
|
|
55
|
+
sa.Column('execution_history', sa.JSON(), server_default='[]'),
|
|
56
|
+
sa.Column('created_by', sa.String(255), nullable=True),
|
|
57
|
+
sa.Column('updated_by', sa.String(255), nullable=True),
|
|
58
|
+
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
|
|
59
|
+
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
|
|
60
|
+
sa.Column('last_triggered_at', sa.DateTime(timezone=True), nullable=True),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Note: Skipping foreign key constraint for last_execution_id due to type mismatch
|
|
64
|
+
# The executions.id is stored as UUID in the database but defined as String in models
|
|
65
|
+
# We can add this constraint later after resolving the type discrepancy
|
|
66
|
+
|
|
67
|
+
# Add unique constraints
|
|
68
|
+
op.create_unique_constraint('uq_jobs_webhook_url_path', 'jobs', ['webhook_url_path'])
|
|
69
|
+
op.create_unique_constraint('uq_jobs_temporal_schedule_id', 'jobs', ['temporal_schedule_id'])
|
|
70
|
+
|
|
71
|
+
# Create indexes for jobs table
|
|
72
|
+
op.create_index('idx_jobs_organization_id', 'jobs', ['organization_id'])
|
|
73
|
+
op.create_index('idx_jobs_name', 'jobs', ['organization_id', 'name'])
|
|
74
|
+
op.create_index('idx_jobs_enabled', 'jobs', ['enabled'])
|
|
75
|
+
op.create_index('idx_jobs_status', 'jobs', ['status'])
|
|
76
|
+
op.create_index('idx_jobs_trigger_type', 'jobs', ['trigger_type'])
|
|
77
|
+
op.create_index('idx_jobs_webhook_url_path', 'jobs', ['webhook_url_path'])
|
|
78
|
+
op.create_index('idx_jobs_temporal_schedule_id', 'jobs', ['temporal_schedule_id'])
|
|
79
|
+
op.create_index('idx_jobs_created_at', 'jobs', ['created_at'])
|
|
80
|
+
op.create_index('idx_jobs_next_execution_at', 'jobs', ['next_execution_at'])
|
|
81
|
+
|
|
82
|
+
# Create job_executions table
|
|
83
|
+
op.create_table(
|
|
84
|
+
'job_executions',
|
|
85
|
+
sa.Column('id', sa.String(255), primary_key=True),
|
|
86
|
+
sa.Column('job_id', sa.String(255), nullable=False),
|
|
87
|
+
sa.Column('execution_id', sa.String(255), nullable=False),
|
|
88
|
+
sa.Column('organization_id', sa.String(255), nullable=False),
|
|
89
|
+
sa.Column('trigger_type', sa.String(50), nullable=False),
|
|
90
|
+
sa.Column('trigger_metadata', sa.JSON(), server_default='{}'),
|
|
91
|
+
sa.Column('execution_status', sa.String(50), nullable=True),
|
|
92
|
+
sa.Column('execution_duration_ms', sa.Integer(), nullable=True),
|
|
93
|
+
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Add foreign key constraints for job_executions
|
|
97
|
+
op.create_foreign_key(
|
|
98
|
+
'fk_job_executions_job',
|
|
99
|
+
'job_executions', 'jobs',
|
|
100
|
+
['job_id'], ['id'],
|
|
101
|
+
ondelete='CASCADE'
|
|
102
|
+
)
|
|
103
|
+
# Note: Skipping foreign key for execution_id due to type mismatch with executions.id
|
|
104
|
+
|
|
105
|
+
# Create indexes for job_executions table
|
|
106
|
+
op.create_index('idx_job_executions_job_id', 'job_executions', ['job_id'])
|
|
107
|
+
op.create_index('idx_job_executions_execution_id', 'job_executions', ['execution_id'])
|
|
108
|
+
op.create_index('idx_job_executions_organization_id', 'job_executions', ['organization_id'])
|
|
109
|
+
op.create_index('idx_job_executions_created_at', 'job_executions', ['created_at'])
|
|
110
|
+
op.create_index('idx_job_executions_trigger_type', 'job_executions', ['trigger_type'])
|
|
111
|
+
op.create_index('idx_job_executions_execution_status', 'job_executions', ['execution_status'])
|
|
112
|
+
|
|
113
|
+
# Create trigger function for updated_at
|
|
114
|
+
op.execute("""
|
|
115
|
+
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
116
|
+
RETURNS TRIGGER AS $$
|
|
117
|
+
BEGIN
|
|
118
|
+
NEW.updated_at = NOW();
|
|
119
|
+
RETURN NEW;
|
|
120
|
+
END;
|
|
121
|
+
$$ LANGUAGE plpgsql;
|
|
122
|
+
""")
|
|
123
|
+
|
|
124
|
+
# Create trigger for jobs table
|
|
125
|
+
op.execute("""
|
|
126
|
+
DROP TRIGGER IF EXISTS update_jobs_updated_at ON jobs;
|
|
127
|
+
CREATE TRIGGER update_jobs_updated_at
|
|
128
|
+
BEFORE UPDATE ON jobs
|
|
129
|
+
FOR EACH ROW
|
|
130
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
131
|
+
""")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def downgrade() -> None:
|
|
135
|
+
"""Downgrade schema."""
|
|
136
|
+
# Drop triggers
|
|
137
|
+
op.execute("DROP TRIGGER IF EXISTS update_jobs_updated_at ON jobs;")
|
|
138
|
+
op.execute("DROP FUNCTION IF EXISTS update_updated_at_column CASCADE;")
|
|
139
|
+
|
|
140
|
+
# Drop indexes for job_executions
|
|
141
|
+
op.drop_index('idx_job_executions_execution_status', 'job_executions')
|
|
142
|
+
op.drop_index('idx_job_executions_trigger_type', 'job_executions')
|
|
143
|
+
op.drop_index('idx_job_executions_created_at', 'job_executions')
|
|
144
|
+
op.drop_index('idx_job_executions_organization_id', 'job_executions')
|
|
145
|
+
op.drop_index('idx_job_executions_execution_id', 'job_executions')
|
|
146
|
+
op.drop_index('idx_job_executions_job_id', 'job_executions')
|
|
147
|
+
|
|
148
|
+
# Drop indexes for jobs
|
|
149
|
+
op.drop_index('idx_jobs_next_execution_at', 'jobs')
|
|
150
|
+
op.drop_index('idx_jobs_created_at', 'jobs')
|
|
151
|
+
op.drop_index('idx_jobs_temporal_schedule_id', 'jobs')
|
|
152
|
+
op.drop_index('idx_jobs_webhook_url_path', 'jobs')
|
|
153
|
+
op.drop_index('idx_jobs_trigger_type', 'jobs')
|
|
154
|
+
op.drop_index('idx_jobs_status', 'jobs')
|
|
155
|
+
op.drop_index('idx_jobs_enabled', 'jobs')
|
|
156
|
+
op.drop_index('idx_jobs_name', 'jobs')
|
|
157
|
+
op.drop_index('idx_jobs_organization_id', 'jobs')
|
|
158
|
+
|
|
159
|
+
# Drop tables
|
|
160
|
+
op.drop_table('job_executions')
|
|
161
|
+
op.drop_table('jobs')
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""add llm_models table
|
|
2
|
+
|
|
3
|
+
Revision ID: add_llm_models_table
|
|
4
|
+
Revises: f973b431d1ce
|
|
5
|
+
Create Date: 2025-01-08 13:25:00.000000
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
from sqlalchemy.dialects import postgresql
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = 'add_llm_models_table'
|
|
14
|
+
down_revision = 'f973b431d1ce'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
# Create llm_models table
|
|
21
|
+
op.create_table(
|
|
22
|
+
'llm_models',
|
|
23
|
+
sa.Column('id', sa.String(), nullable=False),
|
|
24
|
+
sa.Column('value', sa.String(), nullable=False),
|
|
25
|
+
sa.Column('label', sa.String(), nullable=False),
|
|
26
|
+
sa.Column('provider', sa.String(), nullable=False),
|
|
27
|
+
sa.Column('logo', sa.String(), nullable=True),
|
|
28
|
+
sa.Column('description', sa.Text(), nullable=True),
|
|
29
|
+
sa.Column('enabled', sa.Boolean(), nullable=False, server_default='true'),
|
|
30
|
+
sa.Column('recommended', sa.Boolean(), nullable=False, server_default='false'),
|
|
31
|
+
sa.Column('compatible_runtimes', postgresql.JSON(astext_type=sa.Text()), nullable=False, server_default='[]'),
|
|
32
|
+
sa.Column('capabilities', postgresql.JSON(astext_type=sa.Text()), nullable=False, server_default='{}'),
|
|
33
|
+
sa.Column('pricing', postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
|
34
|
+
sa.Column('display_order', sa.Integer(), nullable=False, server_default='1000'),
|
|
35
|
+
sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.text('now()')),
|
|
36
|
+
sa.Column('updated_at', sa.DateTime(), nullable=False, server_default=sa.text('now()')),
|
|
37
|
+
sa.Column('created_by', sa.String(), nullable=True),
|
|
38
|
+
sa.PrimaryKeyConstraint('id')
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Create indexes
|
|
42
|
+
op.create_index(op.f('ix_llm_models_value'), 'llm_models', ['value'], unique=True)
|
|
43
|
+
op.create_index(op.f('ix_llm_models_provider'), 'llm_models', ['provider'], unique=False)
|
|
44
|
+
op.create_index(op.f('ix_llm_models_enabled'), 'llm_models', ['enabled'], unique=False)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def downgrade():
|
|
48
|
+
op.drop_index(op.f('ix_llm_models_enabled'), table_name='llm_models')
|
|
49
|
+
op.drop_index(op.f('ix_llm_models_provider'), table_name='llm_models')
|
|
50
|
+
op.drop_index(op.f('ix_llm_models_value'), table_name='llm_models')
|
|
51
|
+
op.drop_table('llm_models')
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""add_runtime_column_to_teams_simple
|
|
2
|
+
|
|
3
|
+
Revision ID: b0e10697f212
|
|
4
|
+
Revises: 1382bec74309
|
|
5
|
+
Create Date: 2025-11-06 11:48:06.515460
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from typing import Sequence, Union
|
|
9
|
+
|
|
10
|
+
from alembic import op
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = 'b0e10697f212'
|
|
16
|
+
down_revision: Union[str, Sequence[str], None] = '1382bec74309'
|
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
18
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
"""Upgrade schema: Add runtime column to teams table."""
|
|
23
|
+
# Create the RuntimeType enum if it doesn't exist
|
|
24
|
+
op.execute("CREATE TYPE runtimetype AS ENUM ('default', 'claude_code')")
|
|
25
|
+
|
|
26
|
+
# Add runtime column to teams table
|
|
27
|
+
op.add_column('teams', sa.Column('runtime', sa.Enum('default', 'claude_code', name='runtimetype'), server_default='default', nullable=False))
|
|
28
|
+
|
|
29
|
+
# Create index on runtime column
|
|
30
|
+
op.create_index(op.f('ix_teams_runtime'), 'teams', ['runtime'], unique=False)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def downgrade() -> None:
|
|
34
|
+
"""Downgrade schema: Remove runtime column from teams table."""
|
|
35
|
+
# Drop index
|
|
36
|
+
op.drop_index(op.f('ix_teams_runtime'), table_name='teams')
|
|
37
|
+
|
|
38
|
+
# Drop column
|
|
39
|
+
op.drop_column('teams', 'runtime')
|
|
40
|
+
|
|
41
|
+
# Drop enum type
|
|
42
|
+
op.execute("DROP TYPE runtimetype")
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""add_execution_trigger_source_and_fix_types
|
|
2
|
+
|
|
3
|
+
Revision ID: ce43b24b63bf
|
|
4
|
+
Revises: 89e127caa47d
|
|
5
|
+
Create Date: 2025-11-06 20:15:09.289858
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from typing import Sequence, Union
|
|
9
|
+
|
|
10
|
+
from alembic import op
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = 'ce43b24b63bf'
|
|
16
|
+
down_revision: Union[str, Sequence[str], None] = '89e127caa47d'
|
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
18
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
"""Upgrade schema."""
|
|
23
|
+
# 1. Add trigger_source enum type
|
|
24
|
+
op.execute("""
|
|
25
|
+
CREATE TYPE executiontriggersource AS ENUM (
|
|
26
|
+
'user', 'job_cron', 'job_webhook', 'job_manual', 'system', 'api', 'chat'
|
|
27
|
+
)
|
|
28
|
+
""")
|
|
29
|
+
|
|
30
|
+
# 2. Add trigger_source and trigger_metadata columns to executions table
|
|
31
|
+
op.add_column('executions',
|
|
32
|
+
sa.Column('trigger_source', sa.Enum(
|
|
33
|
+
'user', 'job_cron', 'job_webhook', 'job_manual', 'system', 'api', 'chat',
|
|
34
|
+
name='executiontriggersource'
|
|
35
|
+
), nullable=False, server_default='user')
|
|
36
|
+
)
|
|
37
|
+
op.add_column('executions',
|
|
38
|
+
sa.Column('trigger_metadata', sa.JSON(), server_default='{}', nullable=True)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# 3. Create index on trigger_source
|
|
42
|
+
op.create_index('ix_executions_trigger_source', 'executions', ['trigger_source'])
|
|
43
|
+
|
|
44
|
+
# 4. Fix jobs table column types (total_executions, successful_executions, failed_executions from JSON to INTEGER)
|
|
45
|
+
# First, convert any existing data
|
|
46
|
+
op.execute("UPDATE jobs SET total_executions = COALESCE((total_executions::text)::integer, 0) WHERE total_executions IS NOT NULL")
|
|
47
|
+
op.execute("UPDATE jobs SET successful_executions = COALESCE((successful_executions::text)::integer, 0) WHERE successful_executions IS NOT NULL")
|
|
48
|
+
op.execute("UPDATE jobs SET failed_executions = COALESCE((failed_executions::text)::integer, 0) WHERE failed_executions IS NOT NULL")
|
|
49
|
+
|
|
50
|
+
# Then alter column types
|
|
51
|
+
op.alter_column('jobs', 'total_executions',
|
|
52
|
+
type_=sa.Integer(),
|
|
53
|
+
existing_type=sa.JSON(),
|
|
54
|
+
server_default='0',
|
|
55
|
+
nullable=False
|
|
56
|
+
)
|
|
57
|
+
op.alter_column('jobs', 'successful_executions',
|
|
58
|
+
type_=sa.Integer(),
|
|
59
|
+
existing_type=sa.JSON(),
|
|
60
|
+
server_default='0',
|
|
61
|
+
nullable=False
|
|
62
|
+
)
|
|
63
|
+
op.alter_column('jobs', 'failed_executions',
|
|
64
|
+
type_=sa.Integer(),
|
|
65
|
+
existing_type=sa.JSON(),
|
|
66
|
+
server_default='0',
|
|
67
|
+
nullable=False
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# 5. Fix job_executions.execution_duration_ms from JSON to INTEGER
|
|
71
|
+
op.execute("UPDATE job_executions SET execution_duration_ms = COALESCE((execution_duration_ms::text)::integer, NULL) WHERE execution_duration_ms IS NOT NULL")
|
|
72
|
+
op.alter_column('job_executions', 'execution_duration_ms',
|
|
73
|
+
type_=sa.Integer(),
|
|
74
|
+
existing_type=sa.JSON(),
|
|
75
|
+
nullable=True
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# 6. Update last_execution_id in jobs to be UUID type instead of VARCHAR
|
|
79
|
+
# First drop the existing column (safe since we're still setting up)
|
|
80
|
+
op.drop_column('jobs', 'last_execution_id')
|
|
81
|
+
|
|
82
|
+
# Add it back with correct UUID type
|
|
83
|
+
op.add_column('jobs',
|
|
84
|
+
sa.Column('last_execution_id', sa.dialects.postgresql.UUID(as_uuid=True), nullable=True)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# 7. Update execution_id in job_executions to be UUID type
|
|
88
|
+
op.drop_column('job_executions', 'execution_id')
|
|
89
|
+
op.add_column('job_executions',
|
|
90
|
+
sa.Column('execution_id', sa.dialects.postgresql.UUID(as_uuid=True), nullable=False)
|
|
91
|
+
)
|
|
92
|
+
op.create_index('idx_job_executions_execution_id', 'job_executions', ['execution_id'])
|
|
93
|
+
|
|
94
|
+
# 8. Now add the foreign key constraints with proper types
|
|
95
|
+
op.create_foreign_key(
|
|
96
|
+
'fk_jobs_last_execution',
|
|
97
|
+
'jobs', 'executions',
|
|
98
|
+
['last_execution_id'], ['id'],
|
|
99
|
+
ondelete='SET NULL'
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
op.create_foreign_key(
|
|
103
|
+
'fk_job_executions_execution',
|
|
104
|
+
'job_executions', 'executions',
|
|
105
|
+
['execution_id'], ['id'],
|
|
106
|
+
ondelete='CASCADE'
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def downgrade() -> None:
|
|
111
|
+
"""Downgrade schema."""
|
|
112
|
+
# Drop foreign keys
|
|
113
|
+
op.drop_constraint('fk_job_executions_execution', 'job_executions', type_='foreignkey')
|
|
114
|
+
op.drop_constraint('fk_jobs_last_execution', 'jobs', type_='foreignkey')
|
|
115
|
+
|
|
116
|
+
# Revert execution_id in job_executions back to VARCHAR
|
|
117
|
+
op.drop_index('idx_job_executions_execution_id', 'job_executions')
|
|
118
|
+
op.drop_column('job_executions', 'execution_id')
|
|
119
|
+
op.add_column('job_executions',
|
|
120
|
+
sa.Column('execution_id', sa.String(255), nullable=False)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Revert last_execution_id in jobs back to VARCHAR
|
|
124
|
+
op.drop_column('jobs', 'last_execution_id')
|
|
125
|
+
op.add_column('jobs',
|
|
126
|
+
sa.Column('last_execution_id', sa.String(255), nullable=True)
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Revert execution_duration_ms back to JSON
|
|
130
|
+
op.alter_column('job_executions', 'execution_duration_ms',
|
|
131
|
+
type_=sa.JSON(),
|
|
132
|
+
existing_type=sa.Integer()
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Revert job execution counters back to JSON
|
|
136
|
+
op.alter_column('jobs', 'failed_executions',
|
|
137
|
+
type_=sa.JSON(),
|
|
138
|
+
existing_type=sa.Integer()
|
|
139
|
+
)
|
|
140
|
+
op.alter_column('jobs', 'successful_executions',
|
|
141
|
+
type_=sa.JSON(),
|
|
142
|
+
existing_type=sa.Integer()
|
|
143
|
+
)
|
|
144
|
+
op.alter_column('jobs', 'total_executions',
|
|
145
|
+
type_=sa.JSON(),
|
|
146
|
+
existing_type=sa.Integer()
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Drop trigger_source index and columns
|
|
150
|
+
op.drop_index('ix_executions_trigger_source', 'executions')
|
|
151
|
+
op.drop_column('executions', 'trigger_metadata')
|
|
152
|
+
op.drop_column('executions', 'trigger_source')
|
|
153
|
+
|
|
154
|
+
# Drop enum type
|
|
155
|
+
op.execute("DROP TYPE executiontriggersource")
|