kubiya-control-plane-api 0.9.15__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.
Files changed (479) hide show
  1. control_plane_api/LICENSE +676 -0
  2. control_plane_api/README.md +350 -0
  3. control_plane_api/__init__.py +4 -0
  4. control_plane_api/__version__.py +8 -0
  5. control_plane_api/alembic/README +1 -0
  6. control_plane_api/alembic/env.py +121 -0
  7. control_plane_api/alembic/script.py.mako +28 -0
  8. control_plane_api/alembic/versions/2613c65c3dbe_initial_database_setup.py +32 -0
  9. control_plane_api/alembic/versions/2df520d4927d_merge_heads.py +28 -0
  10. control_plane_api/alembic/versions/43abf98d6a01_add_paused_status_to_executions.py +73 -0
  11. control_plane_api/alembic/versions/6289854264cb_merge_multiple_heads.py +28 -0
  12. control_plane_api/alembic/versions/6a4d4dc3d8dc_generate_execution_transitions.py +50 -0
  13. control_plane_api/alembic/versions/87d11cf0a783_add_disconnected_status_to_worker_.py +44 -0
  14. control_plane_api/alembic/versions/add_ephemeral_queue_support.py +85 -0
  15. control_plane_api/alembic/versions/add_model_type_to_llm_models.py +31 -0
  16. control_plane_api/alembic/versions/add_plan_executions_table.py +114 -0
  17. control_plane_api/alembic/versions/add_trace_span_tables.py +154 -0
  18. control_plane_api/alembic/versions/add_user_info_to_traces.py +36 -0
  19. control_plane_api/alembic/versions/adjusting_foreign_keys.py +32 -0
  20. control_plane_api/alembic/versions/b4983d976db2_initial_tables.py +1128 -0
  21. control_plane_api/alembic/versions/d181a3b40e71_rename_custom_metadata_to_metadata_in_.py +50 -0
  22. control_plane_api/alembic/versions/df9117888e82_add_missing_columns.py +82 -0
  23. control_plane_api/alembic/versions/f25de6ad895a_missing_migrations.py +34 -0
  24. control_plane_api/alembic/versions/f71305fb69b9_fix_ephemeral_queue_deletion_foreign_key.py +54 -0
  25. control_plane_api/alembic/versions/mark_local_exec_queues_as_ephemeral.py +68 -0
  26. control_plane_api/alembic.ini +148 -0
  27. control_plane_api/api/index.py +12 -0
  28. control_plane_api/app/__init__.py +11 -0
  29. control_plane_api/app/activities/__init__.py +20 -0
  30. control_plane_api/app/activities/agent_activities.py +384 -0
  31. control_plane_api/app/activities/plan_generation_activities.py +499 -0
  32. control_plane_api/app/activities/team_activities.py +424 -0
  33. control_plane_api/app/activities/temporal_cloud_activities.py +588 -0
  34. control_plane_api/app/config/__init__.py +35 -0
  35. control_plane_api/app/config/api_config.py +469 -0
  36. control_plane_api/app/config/config_loader.py +224 -0
  37. control_plane_api/app/config/model_pricing.py +323 -0
  38. control_plane_api/app/config/storage_config.py +159 -0
  39. control_plane_api/app/config.py +115 -0
  40. control_plane_api/app/controllers/__init__.py +0 -0
  41. control_plane_api/app/controllers/execution_environment_controller.py +1315 -0
  42. control_plane_api/app/database.py +135 -0
  43. control_plane_api/app/exceptions.py +408 -0
  44. control_plane_api/app/lib/__init__.py +11 -0
  45. control_plane_api/app/lib/environment.py +65 -0
  46. control_plane_api/app/lib/event_bus/__init__.py +17 -0
  47. control_plane_api/app/lib/event_bus/base.py +136 -0
  48. control_plane_api/app/lib/event_bus/manager.py +335 -0
  49. control_plane_api/app/lib/event_bus/providers/__init__.py +6 -0
  50. control_plane_api/app/lib/event_bus/providers/http_provider.py +166 -0
  51. control_plane_api/app/lib/event_bus/providers/nats_provider.py +324 -0
  52. control_plane_api/app/lib/event_bus/providers/redis_provider.py +233 -0
  53. control_plane_api/app/lib/event_bus/providers/websocket_provider.py +497 -0
  54. control_plane_api/app/lib/job_executor.py +330 -0
  55. control_plane_api/app/lib/kubiya_client.py +293 -0
  56. control_plane_api/app/lib/litellm_pricing.py +166 -0
  57. control_plane_api/app/lib/mcp_validation.py +163 -0
  58. control_plane_api/app/lib/nats/__init__.py +13 -0
  59. control_plane_api/app/lib/nats/credentials_manager.py +288 -0
  60. control_plane_api/app/lib/nats/listener.py +374 -0
  61. control_plane_api/app/lib/planning_prompt_builder.py +153 -0
  62. control_plane_api/app/lib/planning_tools/__init__.py +41 -0
  63. control_plane_api/app/lib/planning_tools/agents.py +409 -0
  64. control_plane_api/app/lib/planning_tools/agno_toolkit.py +836 -0
  65. control_plane_api/app/lib/planning_tools/base.py +119 -0
  66. control_plane_api/app/lib/planning_tools/cognitive_memory_tools.py +403 -0
  67. control_plane_api/app/lib/planning_tools/context_graph_tools.py +545 -0
  68. control_plane_api/app/lib/planning_tools/environments.py +218 -0
  69. control_plane_api/app/lib/planning_tools/knowledge.py +204 -0
  70. control_plane_api/app/lib/planning_tools/models.py +93 -0
  71. control_plane_api/app/lib/planning_tools/planning_service.py +646 -0
  72. control_plane_api/app/lib/planning_tools/resources.py +242 -0
  73. control_plane_api/app/lib/planning_tools/teams.py +334 -0
  74. control_plane_api/app/lib/policy_enforcer_client.py +1016 -0
  75. control_plane_api/app/lib/redis_client.py +803 -0
  76. control_plane_api/app/lib/sqlalchemy_utils.py +486 -0
  77. control_plane_api/app/lib/state_transition_tools/__init__.py +7 -0
  78. control_plane_api/app/lib/state_transition_tools/execution_context.py +388 -0
  79. control_plane_api/app/lib/storage/__init__.py +20 -0
  80. control_plane_api/app/lib/storage/base_provider.py +274 -0
  81. control_plane_api/app/lib/storage/provider_factory.py +157 -0
  82. control_plane_api/app/lib/storage/vercel_blob_provider.py +468 -0
  83. control_plane_api/app/lib/supabase.py +71 -0
  84. control_plane_api/app/lib/supabase_utils.py +138 -0
  85. control_plane_api/app/lib/task_planning/__init__.py +138 -0
  86. control_plane_api/app/lib/task_planning/agent_factory.py +308 -0
  87. control_plane_api/app/lib/task_planning/agents.py +389 -0
  88. control_plane_api/app/lib/task_planning/cache.py +218 -0
  89. control_plane_api/app/lib/task_planning/entity_resolver.py +273 -0
  90. control_plane_api/app/lib/task_planning/helpers.py +293 -0
  91. control_plane_api/app/lib/task_planning/hooks.py +474 -0
  92. control_plane_api/app/lib/task_planning/models.py +503 -0
  93. control_plane_api/app/lib/task_planning/plan_validator.py +166 -0
  94. control_plane_api/app/lib/task_planning/planning_workflow.py +2911 -0
  95. control_plane_api/app/lib/task_planning/runner.py +656 -0
  96. control_plane_api/app/lib/task_planning/streaming_hook.py +213 -0
  97. control_plane_api/app/lib/task_planning/workflow.py +424 -0
  98. control_plane_api/app/lib/templating/__init__.py +88 -0
  99. control_plane_api/app/lib/templating/compiler.py +278 -0
  100. control_plane_api/app/lib/templating/engine.py +178 -0
  101. control_plane_api/app/lib/templating/parsers/__init__.py +29 -0
  102. control_plane_api/app/lib/templating/parsers/base.py +96 -0
  103. control_plane_api/app/lib/templating/parsers/env.py +85 -0
  104. control_plane_api/app/lib/templating/parsers/graph.py +112 -0
  105. control_plane_api/app/lib/templating/parsers/secret.py +87 -0
  106. control_plane_api/app/lib/templating/parsers/simple.py +81 -0
  107. control_plane_api/app/lib/templating/resolver.py +366 -0
  108. control_plane_api/app/lib/templating/types.py +214 -0
  109. control_plane_api/app/lib/templating/validator.py +201 -0
  110. control_plane_api/app/lib/temporal_client.py +232 -0
  111. control_plane_api/app/lib/temporal_credentials_cache.py +178 -0
  112. control_plane_api/app/lib/temporal_credentials_service.py +203 -0
  113. control_plane_api/app/lib/validation/__init__.py +24 -0
  114. control_plane_api/app/lib/validation/runtime_validation.py +388 -0
  115. control_plane_api/app/main.py +531 -0
  116. control_plane_api/app/middleware/__init__.py +10 -0
  117. control_plane_api/app/middleware/auth.py +645 -0
  118. control_plane_api/app/middleware/exception_handler.py +267 -0
  119. control_plane_api/app/middleware/prometheus_middleware.py +173 -0
  120. control_plane_api/app/middleware/rate_limiting.py +384 -0
  121. control_plane_api/app/middleware/request_id.py +202 -0
  122. control_plane_api/app/models/__init__.py +40 -0
  123. control_plane_api/app/models/agent.py +90 -0
  124. control_plane_api/app/models/analytics.py +206 -0
  125. control_plane_api/app/models/associations.py +107 -0
  126. control_plane_api/app/models/auth_user.py +73 -0
  127. control_plane_api/app/models/context.py +161 -0
  128. control_plane_api/app/models/custom_integration.py +99 -0
  129. control_plane_api/app/models/environment.py +64 -0
  130. control_plane_api/app/models/execution.py +125 -0
  131. control_plane_api/app/models/execution_transition.py +50 -0
  132. control_plane_api/app/models/job.py +159 -0
  133. control_plane_api/app/models/llm_model.py +78 -0
  134. control_plane_api/app/models/orchestration.py +66 -0
  135. control_plane_api/app/models/plan_execution.py +102 -0
  136. control_plane_api/app/models/presence.py +49 -0
  137. control_plane_api/app/models/project.py +61 -0
  138. control_plane_api/app/models/project_management.py +85 -0
  139. control_plane_api/app/models/session.py +29 -0
  140. control_plane_api/app/models/skill.py +155 -0
  141. control_plane_api/app/models/system_tables.py +43 -0
  142. control_plane_api/app/models/task_planning.py +372 -0
  143. control_plane_api/app/models/team.py +86 -0
  144. control_plane_api/app/models/trace.py +257 -0
  145. control_plane_api/app/models/user_profile.py +54 -0
  146. control_plane_api/app/models/worker.py +221 -0
  147. control_plane_api/app/models/workflow.py +161 -0
  148. control_plane_api/app/models/workspace.py +50 -0
  149. control_plane_api/app/observability/__init__.py +177 -0
  150. control_plane_api/app/observability/context_logging.py +475 -0
  151. control_plane_api/app/observability/decorators.py +337 -0
  152. control_plane_api/app/observability/local_span_processor.py +702 -0
  153. control_plane_api/app/observability/metrics.py +303 -0
  154. control_plane_api/app/observability/middleware.py +246 -0
  155. control_plane_api/app/observability/optional.py +115 -0
  156. control_plane_api/app/observability/tracing.py +382 -0
  157. control_plane_api/app/policies/README.md +149 -0
  158. control_plane_api/app/policies/approved_users.rego +62 -0
  159. control_plane_api/app/policies/business_hours.rego +51 -0
  160. control_plane_api/app/policies/rate_limiting.rego +100 -0
  161. control_plane_api/app/policies/tool_enforcement/README.md +336 -0
  162. control_plane_api/app/policies/tool_enforcement/bash_command_validation.rego +71 -0
  163. control_plane_api/app/policies/tool_enforcement/business_hours_enforcement.rego +82 -0
  164. control_plane_api/app/policies/tool_enforcement/mcp_tool_allowlist.rego +58 -0
  165. control_plane_api/app/policies/tool_enforcement/production_safeguards.rego +80 -0
  166. control_plane_api/app/policies/tool_enforcement/role_based_tool_access.rego +44 -0
  167. control_plane_api/app/policies/tool_restrictions.rego +86 -0
  168. control_plane_api/app/routers/__init__.py +4 -0
  169. control_plane_api/app/routers/agents.py +382 -0
  170. control_plane_api/app/routers/agents_v2.py +1598 -0
  171. control_plane_api/app/routers/analytics.py +1310 -0
  172. control_plane_api/app/routers/auth.py +59 -0
  173. control_plane_api/app/routers/client_config.py +57 -0
  174. control_plane_api/app/routers/context_graph.py +561 -0
  175. control_plane_api/app/routers/context_manager.py +577 -0
  176. control_plane_api/app/routers/custom_integrations.py +490 -0
  177. control_plane_api/app/routers/enforcer.py +132 -0
  178. control_plane_api/app/routers/environment_context.py +252 -0
  179. control_plane_api/app/routers/environments.py +761 -0
  180. control_plane_api/app/routers/execution_environment.py +847 -0
  181. control_plane_api/app/routers/executions/__init__.py +28 -0
  182. control_plane_api/app/routers/executions/router.py +286 -0
  183. control_plane_api/app/routers/executions/services/__init__.py +22 -0
  184. control_plane_api/app/routers/executions/services/demo_worker_health.py +156 -0
  185. control_plane_api/app/routers/executions/services/status_service.py +420 -0
  186. control_plane_api/app/routers/executions/services/test_worker_health.py +480 -0
  187. control_plane_api/app/routers/executions/services/worker_health.py +514 -0
  188. control_plane_api/app/routers/executions/streaming/__init__.py +22 -0
  189. control_plane_api/app/routers/executions/streaming/deduplication.py +352 -0
  190. control_plane_api/app/routers/executions/streaming/event_buffer.py +353 -0
  191. control_plane_api/app/routers/executions/streaming/event_formatter.py +964 -0
  192. control_plane_api/app/routers/executions/streaming/history_loader.py +588 -0
  193. control_plane_api/app/routers/executions/streaming/live_source.py +693 -0
  194. control_plane_api/app/routers/executions/streaming/streamer.py +849 -0
  195. control_plane_api/app/routers/executions.py +4888 -0
  196. control_plane_api/app/routers/health.py +165 -0
  197. control_plane_api/app/routers/health_v2.py +394 -0
  198. control_plane_api/app/routers/integration_templates.py +496 -0
  199. control_plane_api/app/routers/integrations.py +287 -0
  200. control_plane_api/app/routers/jobs.py +1809 -0
  201. control_plane_api/app/routers/metrics.py +517 -0
  202. control_plane_api/app/routers/models.py +82 -0
  203. control_plane_api/app/routers/models_v2.py +628 -0
  204. control_plane_api/app/routers/plan_executions.py +1481 -0
  205. control_plane_api/app/routers/plan_generation_async.py +304 -0
  206. control_plane_api/app/routers/policies.py +669 -0
  207. control_plane_api/app/routers/presence.py +234 -0
  208. control_plane_api/app/routers/projects.py +987 -0
  209. control_plane_api/app/routers/runners.py +379 -0
  210. control_plane_api/app/routers/runtimes.py +172 -0
  211. control_plane_api/app/routers/secrets.py +171 -0
  212. control_plane_api/app/routers/skills.py +1010 -0
  213. control_plane_api/app/routers/skills_definitions.py +140 -0
  214. control_plane_api/app/routers/storage.py +456 -0
  215. control_plane_api/app/routers/task_planning.py +611 -0
  216. control_plane_api/app/routers/task_queues.py +650 -0
  217. control_plane_api/app/routers/team_context.py +274 -0
  218. control_plane_api/app/routers/teams.py +1747 -0
  219. control_plane_api/app/routers/templates.py +248 -0
  220. control_plane_api/app/routers/traces.py +571 -0
  221. control_plane_api/app/routers/websocket_client.py +479 -0
  222. control_plane_api/app/routers/websocket_executions_status.py +437 -0
  223. control_plane_api/app/routers/websocket_gateway.py +323 -0
  224. control_plane_api/app/routers/websocket_traces.py +576 -0
  225. control_plane_api/app/routers/worker_queues.py +2555 -0
  226. control_plane_api/app/routers/worker_websocket.py +419 -0
  227. control_plane_api/app/routers/workers.py +1004 -0
  228. control_plane_api/app/routers/workflows.py +204 -0
  229. control_plane_api/app/runtimes/__init__.py +6 -0
  230. control_plane_api/app/runtimes/validation.py +344 -0
  231. control_plane_api/app/schemas/__init__.py +1 -0
  232. control_plane_api/app/schemas/job_schemas.py +302 -0
  233. control_plane_api/app/schemas/mcp_schemas.py +311 -0
  234. control_plane_api/app/schemas/template_schemas.py +133 -0
  235. control_plane_api/app/schemas/trace_schemas.py +168 -0
  236. control_plane_api/app/schemas/worker_queue_observability_schemas.py +165 -0
  237. control_plane_api/app/services/__init__.py +1 -0
  238. control_plane_api/app/services/agno_planning_strategy.py +233 -0
  239. control_plane_api/app/services/agno_service.py +838 -0
  240. control_plane_api/app/services/claude_code_planning_service.py +203 -0
  241. control_plane_api/app/services/context_graph_client.py +224 -0
  242. control_plane_api/app/services/custom_integration_service.py +415 -0
  243. control_plane_api/app/services/integration_resolution_service.py +345 -0
  244. control_plane_api/app/services/litellm_service.py +394 -0
  245. control_plane_api/app/services/plan_generator.py +79 -0
  246. control_plane_api/app/services/planning_strategy.py +66 -0
  247. control_plane_api/app/services/planning_strategy_factory.py +118 -0
  248. control_plane_api/app/services/policy_service.py +615 -0
  249. control_plane_api/app/services/state_transition_service.py +755 -0
  250. control_plane_api/app/services/storage_service.py +593 -0
  251. control_plane_api/app/services/temporal_cloud_provisioning.py +150 -0
  252. control_plane_api/app/services/toolsets/context_graph_skill.py +432 -0
  253. control_plane_api/app/services/trace_retention.py +354 -0
  254. control_plane_api/app/services/worker_queue_metrics_service.py +190 -0
  255. control_plane_api/app/services/workflow_cancellation_manager.py +135 -0
  256. control_plane_api/app/services/workflow_operations_service.py +611 -0
  257. control_plane_api/app/skills/__init__.py +100 -0
  258. control_plane_api/app/skills/base.py +239 -0
  259. control_plane_api/app/skills/builtin/__init__.py +37 -0
  260. control_plane_api/app/skills/builtin/agent_communication/__init__.py +8 -0
  261. control_plane_api/app/skills/builtin/agent_communication/skill.py +246 -0
  262. control_plane_api/app/skills/builtin/code_ingestion/__init__.py +4 -0
  263. control_plane_api/app/skills/builtin/code_ingestion/skill.py +267 -0
  264. control_plane_api/app/skills/builtin/cognitive_memory/__init__.py +4 -0
  265. control_plane_api/app/skills/builtin/cognitive_memory/skill.py +174 -0
  266. control_plane_api/app/skills/builtin/contextual_awareness/__init__.py +4 -0
  267. control_plane_api/app/skills/builtin/contextual_awareness/skill.py +387 -0
  268. control_plane_api/app/skills/builtin/data_visualization/__init__.py +4 -0
  269. control_plane_api/app/skills/builtin/data_visualization/skill.py +154 -0
  270. control_plane_api/app/skills/builtin/docker/__init__.py +4 -0
  271. control_plane_api/app/skills/builtin/docker/skill.py +104 -0
  272. control_plane_api/app/skills/builtin/file_generation/__init__.py +4 -0
  273. control_plane_api/app/skills/builtin/file_generation/skill.py +94 -0
  274. control_plane_api/app/skills/builtin/file_system/__init__.py +4 -0
  275. control_plane_api/app/skills/builtin/file_system/skill.py +110 -0
  276. control_plane_api/app/skills/builtin/knowledge_api/__init__.py +5 -0
  277. control_plane_api/app/skills/builtin/knowledge_api/skill.py +124 -0
  278. control_plane_api/app/skills/builtin/python/__init__.py +4 -0
  279. control_plane_api/app/skills/builtin/python/skill.py +92 -0
  280. control_plane_api/app/skills/builtin/remote_filesystem/__init__.py +5 -0
  281. control_plane_api/app/skills/builtin/remote_filesystem/skill.py +170 -0
  282. control_plane_api/app/skills/builtin/shell/__init__.py +4 -0
  283. control_plane_api/app/skills/builtin/shell/skill.py +161 -0
  284. control_plane_api/app/skills/builtin/slack/__init__.py +3 -0
  285. control_plane_api/app/skills/builtin/slack/skill.py +302 -0
  286. control_plane_api/app/skills/builtin/workflow_executor/__init__.py +4 -0
  287. control_plane_api/app/skills/builtin/workflow_executor/skill.py +469 -0
  288. control_plane_api/app/skills/business_intelligence.py +189 -0
  289. control_plane_api/app/skills/config.py +63 -0
  290. control_plane_api/app/skills/loaders/__init__.py +14 -0
  291. control_plane_api/app/skills/loaders/base.py +73 -0
  292. control_plane_api/app/skills/loaders/filesystem_loader.py +199 -0
  293. control_plane_api/app/skills/registry.py +125 -0
  294. control_plane_api/app/utils/helpers.py +12 -0
  295. control_plane_api/app/utils/workflow_executor.py +354 -0
  296. control_plane_api/app/workflows/__init__.py +11 -0
  297. control_plane_api/app/workflows/agent_execution.py +520 -0
  298. control_plane_api/app/workflows/agent_execution_with_skills.py +223 -0
  299. control_plane_api/app/workflows/namespace_provisioning.py +326 -0
  300. control_plane_api/app/workflows/plan_generation.py +254 -0
  301. control_plane_api/app/workflows/team_execution.py +442 -0
  302. control_plane_api/scripts/seed_models.py +240 -0
  303. control_plane_api/scripts/validate_existing_tool_names.py +492 -0
  304. control_plane_api/shared/__init__.py +8 -0
  305. control_plane_api/shared/version.py +17 -0
  306. control_plane_api/test_deduplication.py +274 -0
  307. control_plane_api/test_executor_deduplication_e2e.py +309 -0
  308. control_plane_api/test_job_execution_e2e.py +283 -0
  309. control_plane_api/test_real_integration.py +193 -0
  310. control_plane_api/version.py +38 -0
  311. control_plane_api/worker/__init__.py +0 -0
  312. control_plane_api/worker/activities/__init__.py +0 -0
  313. control_plane_api/worker/activities/agent_activities.py +1585 -0
  314. control_plane_api/worker/activities/approval_activities.py +234 -0
  315. control_plane_api/worker/activities/job_activities.py +199 -0
  316. control_plane_api/worker/activities/runtime_activities.py +1167 -0
  317. control_plane_api/worker/activities/skill_activities.py +282 -0
  318. control_plane_api/worker/activities/team_activities.py +479 -0
  319. control_plane_api/worker/agent_runtime_server.py +370 -0
  320. control_plane_api/worker/binary_manager.py +333 -0
  321. control_plane_api/worker/config/__init__.py +31 -0
  322. control_plane_api/worker/config/worker_config.py +273 -0
  323. control_plane_api/worker/control_plane_client.py +1491 -0
  324. control_plane_api/worker/examples/analytics_integration_example.py +362 -0
  325. control_plane_api/worker/health_monitor.py +159 -0
  326. control_plane_api/worker/metrics.py +237 -0
  327. control_plane_api/worker/models/__init__.py +1 -0
  328. control_plane_api/worker/models/error_events.py +105 -0
  329. control_plane_api/worker/models/inputs.py +89 -0
  330. control_plane_api/worker/runtimes/__init__.py +35 -0
  331. control_plane_api/worker/runtimes/agent_runtime/runtime.py +485 -0
  332. control_plane_api/worker/runtimes/agno/__init__.py +34 -0
  333. control_plane_api/worker/runtimes/agno/config.py +248 -0
  334. control_plane_api/worker/runtimes/agno/hooks.py +385 -0
  335. control_plane_api/worker/runtimes/agno/mcp_builder.py +195 -0
  336. control_plane_api/worker/runtimes/agno/runtime.py +1063 -0
  337. control_plane_api/worker/runtimes/agno/utils.py +163 -0
  338. control_plane_api/worker/runtimes/base.py +979 -0
  339. control_plane_api/worker/runtimes/claude_code/__init__.py +38 -0
  340. control_plane_api/worker/runtimes/claude_code/cleanup.py +184 -0
  341. control_plane_api/worker/runtimes/claude_code/client_pool.py +529 -0
  342. control_plane_api/worker/runtimes/claude_code/config.py +829 -0
  343. control_plane_api/worker/runtimes/claude_code/hooks.py +482 -0
  344. control_plane_api/worker/runtimes/claude_code/litellm_proxy.py +1702 -0
  345. control_plane_api/worker/runtimes/claude_code/mcp_builder.py +467 -0
  346. control_plane_api/worker/runtimes/claude_code/mcp_discovery.py +558 -0
  347. control_plane_api/worker/runtimes/claude_code/runtime.py +1546 -0
  348. control_plane_api/worker/runtimes/claude_code/tool_mapper.py +403 -0
  349. control_plane_api/worker/runtimes/claude_code/utils.py +149 -0
  350. control_plane_api/worker/runtimes/factory.py +173 -0
  351. control_plane_api/worker/runtimes/model_utils.py +107 -0
  352. control_plane_api/worker/runtimes/validation.py +93 -0
  353. control_plane_api/worker/services/__init__.py +1 -0
  354. control_plane_api/worker/services/agent_communication_tools.py +908 -0
  355. control_plane_api/worker/services/agent_executor.py +485 -0
  356. control_plane_api/worker/services/agent_executor_v2.py +793 -0
  357. control_plane_api/worker/services/analytics_collector.py +457 -0
  358. control_plane_api/worker/services/analytics_service.py +464 -0
  359. control_plane_api/worker/services/approval_tools.py +310 -0
  360. control_plane_api/worker/services/approval_tools_agno.py +207 -0
  361. control_plane_api/worker/services/cancellation_manager.py +177 -0
  362. control_plane_api/worker/services/code_ingestion_tools.py +465 -0
  363. control_plane_api/worker/services/contextual_awareness_tools.py +405 -0
  364. control_plane_api/worker/services/data_visualization.py +834 -0
  365. control_plane_api/worker/services/event_publisher.py +531 -0
  366. control_plane_api/worker/services/jira_tools.py +257 -0
  367. control_plane_api/worker/services/remote_filesystem_tools.py +498 -0
  368. control_plane_api/worker/services/runtime_analytics.py +328 -0
  369. control_plane_api/worker/services/session_service.py +365 -0
  370. control_plane_api/worker/services/skill_context_enhancement.py +181 -0
  371. control_plane_api/worker/services/skill_factory.py +471 -0
  372. control_plane_api/worker/services/system_prompt_enhancement.py +410 -0
  373. control_plane_api/worker/services/team_executor.py +715 -0
  374. control_plane_api/worker/services/team_executor_v2.py +1866 -0
  375. control_plane_api/worker/services/tool_enforcement.py +254 -0
  376. control_plane_api/worker/services/workflow_executor/__init__.py +52 -0
  377. control_plane_api/worker/services/workflow_executor/event_processor.py +287 -0
  378. control_plane_api/worker/services/workflow_executor/event_publisher.py +210 -0
  379. control_plane_api/worker/services/workflow_executor/executors/__init__.py +15 -0
  380. control_plane_api/worker/services/workflow_executor/executors/base.py +270 -0
  381. control_plane_api/worker/services/workflow_executor/executors/json_executor.py +50 -0
  382. control_plane_api/worker/services/workflow_executor/executors/python_executor.py +50 -0
  383. control_plane_api/worker/services/workflow_executor/models.py +142 -0
  384. control_plane_api/worker/services/workflow_executor_tools.py +1748 -0
  385. control_plane_api/worker/skills/__init__.py +12 -0
  386. control_plane_api/worker/skills/builtin/context_graph_search/README.md +213 -0
  387. control_plane_api/worker/skills/builtin/context_graph_search/__init__.py +5 -0
  388. control_plane_api/worker/skills/builtin/context_graph_search/agno_impl.py +808 -0
  389. control_plane_api/worker/skills/builtin/context_graph_search/skill.yaml +67 -0
  390. control_plane_api/worker/skills/builtin/contextual_awareness/__init__.py +4 -0
  391. control_plane_api/worker/skills/builtin/contextual_awareness/agno_impl.py +62 -0
  392. control_plane_api/worker/skills/builtin/data_visualization/agno_impl.py +18 -0
  393. control_plane_api/worker/skills/builtin/data_visualization/skill.yaml +84 -0
  394. control_plane_api/worker/skills/builtin/docker/agno_impl.py +65 -0
  395. control_plane_api/worker/skills/builtin/docker/skill.yaml +60 -0
  396. control_plane_api/worker/skills/builtin/file_generation/agno_impl.py +47 -0
  397. control_plane_api/worker/skills/builtin/file_generation/skill.yaml +64 -0
  398. control_plane_api/worker/skills/builtin/file_system/agno_impl.py +32 -0
  399. control_plane_api/worker/skills/builtin/file_system/skill.yaml +54 -0
  400. control_plane_api/worker/skills/builtin/knowledge_api/__init__.py +4 -0
  401. control_plane_api/worker/skills/builtin/knowledge_api/agno_impl.py +50 -0
  402. control_plane_api/worker/skills/builtin/knowledge_api/skill.yaml +66 -0
  403. control_plane_api/worker/skills/builtin/python/agno_impl.py +25 -0
  404. control_plane_api/worker/skills/builtin/python/skill.yaml +60 -0
  405. control_plane_api/worker/skills/builtin/schema_fix_mixin.py +260 -0
  406. control_plane_api/worker/skills/builtin/shell/agno_impl.py +31 -0
  407. control_plane_api/worker/skills/builtin/shell/skill.yaml +60 -0
  408. control_plane_api/worker/skills/builtin/slack/__init__.py +3 -0
  409. control_plane_api/worker/skills/builtin/slack/agno_impl.py +1282 -0
  410. control_plane_api/worker/skills/builtin/slack/skill.yaml +276 -0
  411. control_plane_api/worker/skills/builtin/workflow_executor/agno_impl.py +62 -0
  412. control_plane_api/worker/skills/builtin/workflow_executor/skill.yaml +79 -0
  413. control_plane_api/worker/skills/loaders/__init__.py +5 -0
  414. control_plane_api/worker/skills/loaders/base.py +23 -0
  415. control_plane_api/worker/skills/loaders/filesystem_loader.py +357 -0
  416. control_plane_api/worker/skills/registry.py +208 -0
  417. control_plane_api/worker/tests/__init__.py +1 -0
  418. control_plane_api/worker/tests/conftest.py +12 -0
  419. control_plane_api/worker/tests/e2e/__init__.py +0 -0
  420. control_plane_api/worker/tests/e2e/test_context_graph_real_api.py +338 -0
  421. control_plane_api/worker/tests/e2e/test_context_graph_templates_e2e.py +523 -0
  422. control_plane_api/worker/tests/e2e/test_enforcement_e2e.py +344 -0
  423. control_plane_api/worker/tests/e2e/test_execution_flow.py +571 -0
  424. control_plane_api/worker/tests/e2e/test_single_execution_mode.py +656 -0
  425. control_plane_api/worker/tests/integration/__init__.py +0 -0
  426. control_plane_api/worker/tests/integration/test_builtin_skills_fixes.py +245 -0
  427. control_plane_api/worker/tests/integration/test_context_graph_search_integration.py +365 -0
  428. control_plane_api/worker/tests/integration/test_control_plane_integration.py +308 -0
  429. control_plane_api/worker/tests/integration/test_hook_enforcement_integration.py +579 -0
  430. control_plane_api/worker/tests/integration/test_scheduled_job_workflow.py +237 -0
  431. control_plane_api/worker/tests/integration/test_system_prompt_enhancement_integration.py +343 -0
  432. control_plane_api/worker/tests/unit/__init__.py +0 -0
  433. control_plane_api/worker/tests/unit/test_builtin_skill_autoload.py +396 -0
  434. control_plane_api/worker/tests/unit/test_context_graph_search.py +450 -0
  435. control_plane_api/worker/tests/unit/test_context_graph_templates.py +403 -0
  436. control_plane_api/worker/tests/unit/test_control_plane_client.py +401 -0
  437. control_plane_api/worker/tests/unit/test_control_plane_client_jobs.py +345 -0
  438. control_plane_api/worker/tests/unit/test_job_activities.py +353 -0
  439. control_plane_api/worker/tests/unit/test_skill_context_enhancement.py +321 -0
  440. control_plane_api/worker/tests/unit/test_system_prompt_enhancement.py +415 -0
  441. control_plane_api/worker/tests/unit/test_tool_enforcement.py +324 -0
  442. control_plane_api/worker/utils/__init__.py +1 -0
  443. control_plane_api/worker/utils/chunk_batcher.py +330 -0
  444. control_plane_api/worker/utils/environment.py +65 -0
  445. control_plane_api/worker/utils/error_publisher.py +260 -0
  446. control_plane_api/worker/utils/event_batcher.py +256 -0
  447. control_plane_api/worker/utils/logging_config.py +335 -0
  448. control_plane_api/worker/utils/logging_helper.py +326 -0
  449. control_plane_api/worker/utils/parameter_validator.py +120 -0
  450. control_plane_api/worker/utils/retry_utils.py +60 -0
  451. control_plane_api/worker/utils/streaming_utils.py +665 -0
  452. control_plane_api/worker/utils/tool_validation.py +332 -0
  453. control_plane_api/worker/utils/workspace_manager.py +163 -0
  454. control_plane_api/worker/websocket_client.py +393 -0
  455. control_plane_api/worker/worker.py +1297 -0
  456. control_plane_api/worker/workflows/__init__.py +0 -0
  457. control_plane_api/worker/workflows/agent_execution.py +909 -0
  458. control_plane_api/worker/workflows/scheduled_job_wrapper.py +332 -0
  459. control_plane_api/worker/workflows/team_execution.py +611 -0
  460. kubiya_control_plane_api-0.9.15.dist-info/METADATA +354 -0
  461. kubiya_control_plane_api-0.9.15.dist-info/RECORD +479 -0
  462. kubiya_control_plane_api-0.9.15.dist-info/WHEEL +5 -0
  463. kubiya_control_plane_api-0.9.15.dist-info/entry_points.txt +5 -0
  464. kubiya_control_plane_api-0.9.15.dist-info/licenses/LICENSE +676 -0
  465. kubiya_control_plane_api-0.9.15.dist-info/top_level.txt +3 -0
  466. scripts/__init__.py +1 -0
  467. scripts/migrations.py +39 -0
  468. scripts/seed_worker_queues.py +128 -0
  469. scripts/setup_agent_runtime.py +142 -0
  470. worker_internal/__init__.py +1 -0
  471. worker_internal/planner/__init__.py +1 -0
  472. worker_internal/planner/activities.py +1499 -0
  473. worker_internal/planner/agent_tools.py +197 -0
  474. worker_internal/planner/event_models.py +148 -0
  475. worker_internal/planner/event_publisher.py +67 -0
  476. worker_internal/planner/models.py +199 -0
  477. worker_internal/planner/retry_logic.py +134 -0
  478. worker_internal/planner/worker.py +300 -0
  479. worker_internal/planner/workflows.py +970 -0
@@ -0,0 +1,88 @@
1
+ """
2
+ Template engine package for variable substitution in MCP configurations.
3
+
4
+ This package provides a flexible, extensible template engine that supports
5
+ multiple template syntaxes through a plugin-based parser system.
6
+
7
+ Supported template syntaxes:
8
+ - {{variable}} - Simple variable substitution
9
+ - {{.secret.name}} - Secret from vault
10
+ - {{.env.VAR}} - Environment variable
11
+
12
+ Example usage:
13
+ from control_plane_api.app.lib.templating import TemplateEngine, TemplateContext, TemplateCompiler
14
+
15
+ # Parse and compile a template
16
+ engine = TemplateEngine()
17
+ context = TemplateContext(
18
+ secrets={"api_key": "secret-value"},
19
+ env_vars={"PORT": "8080"}
20
+ )
21
+
22
+ compiler = TemplateCompiler(engine)
23
+ result = compiler.compile("http://api.example.com:{{.env.PORT}}/{{.secret.api_key}}", context)
24
+ print(result.compiled) # "http://api.example.com:8080/secret-value"
25
+ """
26
+
27
+ # Core types
28
+ from control_plane_api.app.lib.templating.types import (
29
+ TemplateVariableType,
30
+ TemplateVariable,
31
+ ValidationError,
32
+ ParseResult,
33
+ TemplateContext,
34
+ ValidationResult,
35
+ CompileResult,
36
+ )
37
+
38
+ # Main engine components
39
+ from control_plane_api.app.lib.templating.engine import TemplateEngine, get_default_engine
40
+ from control_plane_api.app.lib.templating.validator import TemplateValidator
41
+ from control_plane_api.app.lib.templating.compiler import TemplateCompiler
42
+ from control_plane_api.app.lib.templating.resolver import (
43
+ TemplateResolver,
44
+ TemplateResolutionError,
45
+ resolve_templates,
46
+ has_templates,
47
+ extract_all_variables,
48
+ )
49
+
50
+ # Parser infrastructure (for advanced usage)
51
+ from control_plane_api.app.lib.templating.parsers import (
52
+ BaseParser,
53
+ SimpleVariableParser,
54
+ SecretVariableParser,
55
+ EnvVariableParser,
56
+ DEFAULT_PARSERS,
57
+ )
58
+
59
+ __all__ = [
60
+ # Types
61
+ "TemplateVariableType",
62
+ "TemplateVariable",
63
+ "ValidationError",
64
+ "ParseResult",
65
+ "TemplateContext",
66
+ "ValidationResult",
67
+ "CompileResult",
68
+ # Main components
69
+ "TemplateEngine",
70
+ "get_default_engine",
71
+ "TemplateValidator",
72
+ "TemplateCompiler",
73
+ "TemplateResolver",
74
+ "TemplateResolutionError",
75
+ # Convenience functions
76
+ "resolve_templates",
77
+ "has_templates",
78
+ "extract_all_variables",
79
+ # Parsers (advanced)
80
+ "BaseParser",
81
+ "SimpleVariableParser",
82
+ "SecretVariableParser",
83
+ "EnvVariableParser",
84
+ "DEFAULT_PARSERS",
85
+ ]
86
+
87
+ # Version
88
+ __version__ = "1.0.0"
@@ -0,0 +1,278 @@
1
+ """
2
+ Template compilation logic.
3
+
4
+ Compiles templates by substituting variables with their values from a context.
5
+ """
6
+
7
+ import json
8
+ import os
9
+ import structlog
10
+ import httpx
11
+ from typing import Any, Dict, Optional
12
+ from control_plane_api.app.lib.templating.types import (
13
+ TemplateContext,
14
+ TemplateVariableType,
15
+ CompileResult,
16
+ )
17
+ from control_plane_api.app.lib.templating.engine import TemplateEngine, get_default_engine
18
+ from control_plane_api.app.lib.templating.validator import TemplateValidator
19
+
20
+ logger = structlog.get_logger()
21
+
22
+
23
+ class TemplateCompiler:
24
+ """
25
+ Compiles templates by substituting variables with values from a context.
26
+
27
+ The compiler:
28
+ 1. Validates the template
29
+ 2. Substitutes variables with their values
30
+ 3. Returns the compiled string
31
+ """
32
+
33
+ def __init__(self, engine: TemplateEngine = None):
34
+ """
35
+ Initialize the compiler with a template engine.
36
+
37
+ Args:
38
+ engine: Template engine to use. If None, uses default engine.
39
+ """
40
+ self.engine = engine if engine is not None else get_default_engine()
41
+ self.validator = TemplateValidator(self.engine)
42
+
43
+ def compile(self, template: str, context: TemplateContext) -> CompileResult:
44
+ """
45
+ Compile a template by substituting all variables with their values.
46
+
47
+ Process:
48
+ 1. Parse the template to extract variables
49
+ 2. Validate that all variables exist in context
50
+ 3. Substitute variables with their values (in reverse order to preserve positions)
51
+
52
+ Args:
53
+ template: Template string to compile
54
+ context: Template context with variable values
55
+
56
+ Returns:
57
+ CompileResult with compiled string or error
58
+ """
59
+ try:
60
+ # Parse the template
61
+ parse_result = self.engine.parse(template)
62
+
63
+ # Check for syntax errors
64
+ if not parse_result.is_valid:
65
+ error_messages = [err.message for err in parse_result.errors]
66
+ error_str = "; ".join(error_messages)
67
+ logger.warning("template_syntax_errors", errors=error_messages)
68
+ return CompileResult(
69
+ compiled="",
70
+ success=False,
71
+ error=f"Template syntax errors: {error_str}"
72
+ )
73
+
74
+ # Validate against context
75
+ validation_result = self.validator.validate(template, context)
76
+ if not validation_result.valid:
77
+ error_messages = [err.message for err in validation_result.errors]
78
+ error_str = "; ".join(error_messages)
79
+ logger.warning("template_validation_errors", errors=error_messages)
80
+ return CompileResult(
81
+ compiled="",
82
+ success=False,
83
+ error=f"Template validation errors: {error_str}"
84
+ )
85
+
86
+ # Substitute variables (process in reverse order to preserve positions)
87
+ result = template
88
+ for var in sorted(parse_result.variables, key=lambda v: v.start, reverse=True):
89
+ try:
90
+ # Get the value based on variable type
91
+ value = self._get_variable_value(var.type, var, context)
92
+
93
+ # Convert to string
94
+ value_str = str(value) if value is not None else ""
95
+
96
+ # Substitute
97
+ result = result[:var.start] + value_str + result[var.end:]
98
+
99
+ logger.debug(
100
+ "variable_substituted",
101
+ variable_name=var.name,
102
+ variable_type=var.type.value,
103
+ has_value=bool(value),
104
+ value_length=len(value_str)
105
+ )
106
+
107
+ except KeyError as e:
108
+ # This shouldn't happen if validation passed, but handle it gracefully
109
+ logger.error(
110
+ "variable_not_found_during_compilation",
111
+ variable_name=var.name,
112
+ error=str(e)
113
+ )
114
+ # Preserve the original error message (especially for graph node API errors)
115
+ error_msg = str(e) if str(e) else f"Variable '{var.name}' not found in context"
116
+ return CompileResult(
117
+ compiled="",
118
+ success=False,
119
+ error=error_msg
120
+ )
121
+
122
+ logger.info(
123
+ "template_compiled_successfully",
124
+ original_length=len(template),
125
+ compiled_length=len(result),
126
+ variable_count=len(parse_result.variables)
127
+ )
128
+
129
+ return CompileResult(
130
+ compiled=result,
131
+ success=True
132
+ )
133
+
134
+ except Exception as e:
135
+ logger.error("template_compilation_failed", error=str(e), exc_info=True)
136
+ return CompileResult(
137
+ compiled="",
138
+ success=False,
139
+ error=f"Compilation failed: {str(e)}"
140
+ )
141
+
142
+ def _get_variable_value(
143
+ self,
144
+ var_type: TemplateVariableType,
145
+ var,
146
+ context: TemplateContext
147
+ ) -> Any:
148
+ """
149
+ Get the value for a variable from the context.
150
+
151
+ Args:
152
+ var_type: Type of variable
153
+ var: TemplateVariable object
154
+ context: Template context
155
+
156
+ Returns:
157
+ Variable value
158
+
159
+ Raises:
160
+ KeyError: If variable not found in context
161
+ """
162
+ if var_type == TemplateVariableType.SECRET:
163
+ return context.secrets[var.display_name]
164
+ elif var_type == TemplateVariableType.ENV:
165
+ return context.env_vars[var.display_name]
166
+ elif var_type == TemplateVariableType.GRAPH:
167
+ return self._get_graph_node_value(var.display_name, context)
168
+ else: # SIMPLE
169
+ return context.variables[var.name]
170
+
171
+ def _get_graph_node_value(
172
+ self,
173
+ node_id: str,
174
+ context: TemplateContext
175
+ ) -> str:
176
+ """
177
+ Get graph node data from context or fetch from API.
178
+
179
+ Args:
180
+ node_id: The node ID to fetch
181
+ context: Template context with graph configuration
182
+
183
+ Returns:
184
+ Formatted node data as JSON string
185
+
186
+ Raises:
187
+ KeyError: If node not found or API configuration missing
188
+ """
189
+ # Check if node is already in context
190
+ if context.graph_nodes and node_id in context.graph_nodes:
191
+ node_data = context.graph_nodes[node_id]
192
+ return json.dumps(node_data, indent=2)
193
+
194
+ # Need to fetch from API - validate configuration
195
+ if not context.graph_api_base:
196
+ raise KeyError(
197
+ f"Context graph API base URL not configured for node '{node_id}'"
198
+ )
199
+ if not context.graph_api_key:
200
+ raise KeyError(
201
+ f"Context graph API key not configured for node '{node_id}'"
202
+ )
203
+
204
+ # Fetch node from API
205
+ try:
206
+ node_data = self._fetch_graph_node(
207
+ node_id=node_id,
208
+ api_base=context.graph_api_base,
209
+ api_key=context.graph_api_key,
210
+ org_id=context.graph_org_id
211
+ )
212
+
213
+ # Cache in context for subsequent requests
214
+ if context.graph_nodes is None:
215
+ context.graph_nodes = {}
216
+ context.graph_nodes[node_id] = node_data
217
+
218
+ return json.dumps(node_data, indent=2)
219
+
220
+ except httpx.HTTPStatusError as e:
221
+ if e.response.status_code == 404:
222
+ raise KeyError(f"Graph node '{node_id}' not found")
223
+ else:
224
+ raise KeyError(
225
+ f"Failed to fetch graph node '{node_id}': "
226
+ f"HTTP {e.response.status_code}"
227
+ )
228
+ except Exception as e:
229
+ raise KeyError(f"Failed to fetch graph node '{node_id}': {str(e)}")
230
+
231
+ def _fetch_graph_node(
232
+ self,
233
+ node_id: str,
234
+ api_base: str,
235
+ api_key: str,
236
+ org_id: Optional[str] = None,
237
+ timeout: int = 30
238
+ ) -> Dict[str, Any]:
239
+ """
240
+ Fetch a node from the context graph API.
241
+
242
+ Args:
243
+ node_id: The node ID to fetch
244
+ api_base: Context graph API base URL
245
+ api_key: API key for authentication
246
+ org_id: Optional organization ID
247
+ timeout: Request timeout in seconds
248
+
249
+ Returns:
250
+ Node data dictionary
251
+
252
+ Raises:
253
+ httpx.HTTPStatusError: If request fails (including 404)
254
+ Exception: If request fails for other reasons
255
+ """
256
+ url = f"{api_base.rstrip('/')}/api/v1/graph/nodes/{node_id}"
257
+
258
+ headers = {
259
+ "Authorization": f"UserKey {api_key}",
260
+ "Accept": "application/json",
261
+ "Content-Type": "application/json",
262
+ "X-Kubiya-Client": "agent-runtime-template-compiler",
263
+ }
264
+
265
+ if org_id:
266
+ headers["X-Organization-ID"] = org_id
267
+
268
+ logger.debug(
269
+ "fetching_graph_node",
270
+ node_id=node_id,
271
+ api_base=api_base,
272
+ has_org_id=bool(org_id)
273
+ )
274
+
275
+ with httpx.Client(timeout=timeout) as client:
276
+ response = client.get(url, headers=headers)
277
+ response.raise_for_status()
278
+ return response.json()
@@ -0,0 +1,178 @@
1
+ """
2
+ Main template engine orchestrator.
3
+
4
+ Coordinates multiple parsers to extract, validate, and compile templates.
5
+ """
6
+
7
+ import structlog
8
+ from typing import List, Set
9
+ from control_plane_api.app.lib.templating.types import (
10
+ TemplateVariable,
11
+ ParseResult,
12
+ ValidationError,
13
+ )
14
+ from control_plane_api.app.lib.templating.parsers import BaseParser, DEFAULT_PARSERS
15
+
16
+ logger = structlog.get_logger()
17
+
18
+
19
+ class TemplateEngine:
20
+ """
21
+ Main template engine that coordinates multiple parsers.
22
+
23
+ This engine uses a plugin-based architecture where different parsers
24
+ can be registered to handle different template syntaxes.
25
+ """
26
+
27
+ def __init__(self, parsers: List[BaseParser] = None):
28
+ """
29
+ Initialize the template engine with a list of parsers.
30
+
31
+ Args:
32
+ parsers: List of parsers to use. If None, uses DEFAULT_PARSERS.
33
+ """
34
+ self.parsers = parsers if parsers is not None else DEFAULT_PARSERS.copy()
35
+ logger.debug("template_engine_initialized", parser_count=len(self.parsers))
36
+
37
+ def parse(self, template: str) -> ParseResult:
38
+ """
39
+ Parse a template string using all registered parsers.
40
+
41
+ Args:
42
+ template: Template string to parse
43
+
44
+ Returns:
45
+ ParseResult with all variables found and any syntax errors
46
+ """
47
+ if not template:
48
+ return ParseResult(template="", variables=[], errors=[])
49
+
50
+ variables: List[TemplateVariable] = []
51
+ errors: List[ValidationError] = []
52
+ processed_positions: Set[int] = set()
53
+
54
+ # Run each parser
55
+ for parser in self.parsers:
56
+ try:
57
+ parser_variables = parser.parse(template)
58
+
59
+ # Filter out variables at already-processed positions
60
+ # This prevents conflicts between parsers (e.g., {{var}} matching as both simple and secret)
61
+ for var in parser_variables:
62
+ if var.start not in processed_positions:
63
+ variables.append(var)
64
+ processed_positions.add(var.start)
65
+ logger.debug(
66
+ "variable_parsed",
67
+ variable_name=var.name,
68
+ variable_type=var.type.value,
69
+ position=var.start
70
+ )
71
+
72
+ except Exception as e:
73
+ logger.error(
74
+ "parser_error",
75
+ parser=parser.__class__.__name__,
76
+ error=str(e)
77
+ )
78
+ errors.append(ValidationError(
79
+ message=f"Parser error ({parser.__class__.__name__}): {str(e)}",
80
+ code="PARSER_ERROR"
81
+ ))
82
+
83
+ # Check for unrecognized template patterns
84
+ # Find all {{ }} that weren't matched by any parser
85
+ import re
86
+ all_braces = re.finditer(r"\{\{([^}]+)\}\}", template)
87
+ for match in all_braces:
88
+ start = match.start()
89
+ if start not in processed_positions:
90
+ raw = match.group(0)
91
+ errors.append(ValidationError(
92
+ message=f"Unrecognized template syntax: '{raw}'. Expected {{{{variable}}}}, {{{{.secret.name}}}}, or {{{{.env.VAR}}}}",
93
+ position=start,
94
+ code="INVALID_SYNTAX"
95
+ ))
96
+ logger.warning(
97
+ "unrecognized_template_syntax",
98
+ raw=raw,
99
+ position=start
100
+ )
101
+
102
+ # Sort variables by position for consistent ordering
103
+ variables.sort(key=lambda v: v.start)
104
+
105
+ return ParseResult(
106
+ template=template,
107
+ variables=variables,
108
+ errors=errors
109
+ )
110
+
111
+ def extract_variables(self, template: str) -> List[TemplateVariable]:
112
+ """
113
+ Extract all variables from a template without full parsing.
114
+
115
+ Args:
116
+ template: Template string
117
+
118
+ Returns:
119
+ List of TemplateVariable objects
120
+ """
121
+ parse_result = self.parse(template)
122
+ return parse_result.variables
123
+
124
+ def get_required_secrets(self, template: str) -> List[str]:
125
+ """
126
+ Get list of required secret names from a template.
127
+
128
+ Args:
129
+ template: Template string
130
+
131
+ Returns:
132
+ List of secret names (without .secret prefix)
133
+ """
134
+ parse_result = self.parse(template)
135
+ return [var.display_name for var in parse_result.secret_variables]
136
+
137
+ def get_required_env_vars(self, template: str) -> List[str]:
138
+ """
139
+ Get list of required environment variable names from a template.
140
+
141
+ Args:
142
+ template: Template string
143
+
144
+ Returns:
145
+ List of environment variable names (without .env prefix)
146
+ """
147
+ parse_result = self.parse(template)
148
+ return [var.display_name for var in parse_result.env_variables]
149
+
150
+ def get_required_simple_vars(self, template: str) -> List[str]:
151
+ """
152
+ Get list of required simple variable names from a template.
153
+
154
+ Args:
155
+ template: Template string
156
+
157
+ Returns:
158
+ List of simple variable names
159
+ """
160
+ parse_result = self.parse(template)
161
+ return [var.name for var in parse_result.simple_variables]
162
+
163
+
164
+ # Global default engine instance
165
+ _default_engine = None
166
+
167
+
168
+ def get_default_engine() -> TemplateEngine:
169
+ """
170
+ Get the default global template engine instance.
171
+
172
+ Returns:
173
+ TemplateEngine instance
174
+ """
175
+ global _default_engine
176
+ if _default_engine is None:
177
+ _default_engine = TemplateEngine()
178
+ return _default_engine
@@ -0,0 +1,29 @@
1
+ """
2
+ Template parsers package.
3
+
4
+ Exports all available template variable parsers.
5
+ """
6
+
7
+ from control_plane_api.app.lib.templating.parsers.base import BaseParser
8
+ from control_plane_api.app.lib.templating.parsers.simple import SimpleVariableParser
9
+ from control_plane_api.app.lib.templating.parsers.secret import SecretVariableParser
10
+ from control_plane_api.app.lib.templating.parsers.env import EnvVariableParser
11
+ from control_plane_api.app.lib.templating.parsers.graph import GraphNodeParser
12
+
13
+ # Default list of parsers to use in the template engine
14
+ # Order matters: more specific patterns should come first to avoid conflicts
15
+ DEFAULT_PARSERS = [
16
+ SecretVariableParser(), # {{.secret.name}} - most specific
17
+ EnvVariableParser(), # {{.env.VAR}} - specific
18
+ GraphNodeParser(), # {{.graph.node-id}} - specific
19
+ SimpleVariableParser(), # {{variable}} - most general (must be last)
20
+ ]
21
+
22
+ __all__ = [
23
+ "BaseParser",
24
+ "SimpleVariableParser",
25
+ "SecretVariableParser",
26
+ "EnvVariableParser",
27
+ "GraphNodeParser",
28
+ "DEFAULT_PARSERS",
29
+ ]
@@ -0,0 +1,96 @@
1
+ """
2
+ Base parser interface for template variable parsers.
3
+
4
+ This module defines the abstract base class that all template parsers must implement.
5
+ """
6
+
7
+ import re
8
+ from abc import ABC, abstractmethod
9
+ from typing import List, Optional
10
+ from control_plane_api.app.lib.templating.types import TemplateVariable, TemplateVariableType
11
+
12
+
13
+ class BaseParser(ABC):
14
+ """
15
+ Abstract base class for template variable parsers.
16
+
17
+ Each parser is responsible for:
18
+ - Defining a regex pattern to match its template syntax
19
+ - Parsing matches into TemplateVariable objects
20
+ - Validating variable names according to its rules
21
+ """
22
+
23
+ @property
24
+ @abstractmethod
25
+ def pattern(self) -> re.Pattern:
26
+ """
27
+ Regular expression pattern to match this parser's template syntax.
28
+
29
+ Returns:
30
+ Compiled regex pattern
31
+ """
32
+ pass
33
+
34
+ @property
35
+ @abstractmethod
36
+ def variable_type(self) -> TemplateVariableType:
37
+ """
38
+ Type of variables this parser handles.
39
+
40
+ Returns:
41
+ TemplateVariableType enum value
42
+ """
43
+ pass
44
+
45
+ @abstractmethod
46
+ def parse_match(self, match: re.Match, template: str) -> Optional[TemplateVariable]:
47
+ """
48
+ Parse a regex match into a TemplateVariable.
49
+
50
+ Args:
51
+ match: Regex match object
52
+ template: Full template string (for context)
53
+
54
+ Returns:
55
+ TemplateVariable if valid, None if invalid
56
+ """
57
+ pass
58
+
59
+ @abstractmethod
60
+ def validate_name(self, name: str) -> bool:
61
+ """
62
+ Validate that a variable name follows this parser's rules.
63
+
64
+ Args:
65
+ name: Variable name to validate
66
+
67
+ Returns:
68
+ True if valid, False otherwise
69
+ """
70
+ pass
71
+
72
+ def parse(self, template: str) -> List[TemplateVariable]:
73
+ """
74
+ Parse a template string and extract all variables of this parser's type.
75
+
76
+ Args:
77
+ template: Template string to parse
78
+
79
+ Returns:
80
+ List of TemplateVariable objects found
81
+ """
82
+ if not template:
83
+ return []
84
+
85
+ variables: List[TemplateVariable] = []
86
+
87
+ for match in self.pattern.finditer(template):
88
+ variable = self.parse_match(match, template)
89
+ if variable:
90
+ variables.append(variable)
91
+
92
+ return variables
93
+
94
+ def __repr__(self) -> str:
95
+ """String representation for debugging."""
96
+ return f"{self.__class__.__name__}(type={self.variable_type.value})"