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,335 @@
1
+ """
2
+ Centralized logging configuration for the worker process.
3
+
4
+ This module provides:
5
+ - Dynamic log level configuration via KUBIYA_CLI_LOG_LEVEL environment variable
6
+ - Multiple log format support (pretty, json, text) via KUBIYA_LOG_FORMAT
7
+ - Backward compatibility with CLAUDE_CODE_DEBUG
8
+ - Sensitive data sanitization helpers
9
+ - Unified structlog configuration
10
+ """
11
+
12
+ import os
13
+ import logging
14
+ import time
15
+ import structlog
16
+ from typing import Any, Dict
17
+
18
+
19
+ def get_log_level() -> int:
20
+ """
21
+ Get log level from environment variables with fallback hierarchy.
22
+
23
+ Priority:
24
+ 1. KUBIYA_CLI_LOG_LEVEL (new, preferred)
25
+ 2. LOG_LEVEL (generic fallback)
26
+ 3. CLAUDE_CODE_DEBUG=true → DEBUG (deprecated, with warning)
27
+ 4. Default: INFO
28
+
29
+ Returns:
30
+ int: Python logging level constant (logging.DEBUG, logging.INFO, etc.)
31
+ """
32
+ logger = structlog.get_logger(__name__)
33
+
34
+ # Check KUBIYA_CLI_LOG_LEVEL first (preferred)
35
+ kubiya_log_level = os.getenv("KUBIYA_CLI_LOG_LEVEL", "").upper()
36
+ if kubiya_log_level:
37
+ level_map = {
38
+ "DEBUG": logging.DEBUG,
39
+ "INFO": logging.INFO,
40
+ "WARNING": logging.WARNING,
41
+ "ERROR": logging.ERROR,
42
+ "CRITICAL": logging.CRITICAL,
43
+ }
44
+ if kubiya_log_level in level_map:
45
+ return level_map[kubiya_log_level]
46
+
47
+ # Check generic LOG_LEVEL
48
+ log_level = os.getenv("LOG_LEVEL", "").upper()
49
+ if log_level:
50
+ level_map = {
51
+ "DEBUG": logging.DEBUG,
52
+ "INFO": logging.INFO,
53
+ "WARNING": logging.WARNING,
54
+ "ERROR": logging.ERROR,
55
+ "CRITICAL": logging.CRITICAL,
56
+ }
57
+ if log_level in level_map:
58
+ return level_map[log_level]
59
+
60
+ # Check deprecated CLAUDE_CODE_DEBUG
61
+ if os.getenv("CLAUDE_CODE_DEBUG", "false").lower() == "true":
62
+ # Show deprecation warning (but only once, using a module-level flag)
63
+ if not hasattr(get_log_level, "_warned"):
64
+ logger.warning(
65
+ "deprecated_env_var",
66
+ old_var="CLAUDE_CODE_DEBUG",
67
+ new_var="KUBIYA_CLI_LOG_LEVEL",
68
+ message="CLAUDE_CODE_DEBUG is deprecated. Please use KUBIYA_CLI_LOG_LEVEL=DEBUG instead."
69
+ )
70
+ get_log_level._warned = True
71
+ return logging.DEBUG
72
+
73
+ # Default to INFO
74
+ return logging.INFO
75
+
76
+
77
+ def get_log_format() -> str:
78
+ """
79
+ Get log format from environment variable.
80
+
81
+ Priority:
82
+ 1. KUBIYA_LOG_FORMAT
83
+ 2. Default: "pretty"
84
+
85
+ Supported formats:
86
+ - pretty: Human-readable colored output with emojis (default)
87
+ - json: JSON-formatted for log aggregation
88
+ - text: Simple text without colors
89
+
90
+ Returns:
91
+ str: Log format ("pretty", "json", or "text")
92
+ """
93
+ log_format = os.getenv("KUBIYA_LOG_FORMAT", "pretty").lower()
94
+ if log_format not in ["pretty", "json", "text"]:
95
+ # Invalid format, default to pretty
96
+ return "pretty"
97
+ return log_format
98
+
99
+
100
+ def sanitize_value(key: str, value: Any) -> str:
101
+ """
102
+ Sanitize sensitive values based on key name.
103
+
104
+ Keys containing TOKEN, SECRET, PASSWORD, KEY, or CREDENTIAL will be masked.
105
+ Shows first 10 and last 5 characters for values longer than 15 chars,
106
+ otherwise shows "***".
107
+
108
+ Args:
109
+ key: The key/variable name
110
+ value: The value to potentially sanitize
111
+
112
+ Returns:
113
+ str: Sanitized value if key is sensitive, otherwise original value as string
114
+ """
115
+ sensitive_keywords = ["TOKEN", "SECRET", "PASSWORD", "KEY", "CREDENTIAL"]
116
+
117
+ # Check if key contains any sensitive keyword
118
+ is_sensitive = any(keyword in key.upper() for keyword in sensitive_keywords)
119
+
120
+ if not is_sensitive:
121
+ return str(value)
122
+
123
+ # Sanitize sensitive value
124
+ value_str = str(value)
125
+ if len(value_str) > 15:
126
+ return f"{value_str[:10]}...{value_str[-5:]}"
127
+ else:
128
+ return "***"
129
+
130
+
131
+ def pretty_console_renderer(logger, name, event_dict):
132
+ """
133
+ Render logs in a pretty, human-readable format instead of JSON.
134
+ Uses colors and emojis for better readability.
135
+
136
+ Args:
137
+ logger: The logger instance
138
+ name: The logger name
139
+ event_dict: Dictionary containing log event data
140
+
141
+ Returns:
142
+ str: Formatted log message
143
+ """
144
+ level = event_dict.get("level", "info").upper()
145
+ event = event_dict.get("event", "")
146
+ timestamp = event_dict.get("timestamp", "")
147
+
148
+ # Extract timestamp (just time part)
149
+ if timestamp:
150
+ try:
151
+ time_part = timestamp.split("T")[1].split(".")[0] # HH:MM:SS
152
+ except:
153
+ time_part = timestamp
154
+ else:
155
+ time_part = time.strftime("%H:%M:%S")
156
+
157
+ # Color codes
158
+ RESET = "\033[0m"
159
+ GRAY = "\033[90m"
160
+ GREEN = "\033[92m"
161
+ YELLOW = "\033[93m"
162
+ RED = "\033[91m"
163
+ CYAN = "\033[96m"
164
+ BOLD = "\033[1m"
165
+
166
+ # Level icons and colors
167
+ level_config = {
168
+ "INFO": ("ℹ️", CYAN),
169
+ "WARNING": ("⚠️", YELLOW),
170
+ "ERROR": ("❌", RED),
171
+ "DEBUG": ("🔍", GRAY),
172
+ }
173
+
174
+ icon, color = level_config.get(level, ("•", RESET))
175
+
176
+ # Format the main message
177
+ message = f"{GRAY}[{time_part}]{RESET} {icon} {event}"
178
+
179
+ # Add relevant context (skip internal keys)
180
+ skip_keys = {"level", "event", "timestamp", "logger"}
181
+ context_parts = []
182
+
183
+ for key, value in event_dict.items():
184
+ if key in skip_keys:
185
+ continue
186
+ # Format value nicely
187
+ if isinstance(value, bool):
188
+ value_str = "✓" if value else "✗"
189
+ elif isinstance(value, str) and len(value) > 60:
190
+ value_str = value[:57] + "..."
191
+ else:
192
+ value_str = str(value)
193
+
194
+ context_parts.append(f"{GRAY}{key}={RESET}{value_str}")
195
+
196
+ if context_parts:
197
+ message += f" {GRAY}({', '.join(context_parts)}){RESET}"
198
+
199
+ return message
200
+
201
+
202
+ def json_renderer(logger, name, event_dict):
203
+ """
204
+ Render logs in JSON format for log aggregation systems.
205
+
206
+ Args:
207
+ logger: The logger instance
208
+ name: The logger name
209
+ event_dict: Dictionary containing log event data
210
+
211
+ Returns:
212
+ str: JSON-formatted log message
213
+ """
214
+ import json
215
+ return json.dumps(event_dict)
216
+
217
+
218
+ def text_renderer(logger, name, event_dict):
219
+ """
220
+ Render logs in simple text format without colors.
221
+
222
+ Args:
223
+ logger: The logger instance
224
+ name: The logger name
225
+ event_dict: Dictionary containing log event data
226
+
227
+ Returns:
228
+ str: Simple text log message
229
+ """
230
+ level = event_dict.get("level", "info").upper()
231
+ event = event_dict.get("event", "")
232
+ timestamp = event_dict.get("timestamp", "")
233
+
234
+ # Extract timestamp (just time part)
235
+ if timestamp:
236
+ try:
237
+ time_part = timestamp.split("T")[1].split(".")[0] # HH:MM:SS
238
+ except:
239
+ time_part = timestamp
240
+ else:
241
+ time_part = time.strftime("%H:%M:%S")
242
+
243
+ # Format the main message
244
+ message = f"[{time_part}] {level:8} {event}"
245
+
246
+ # Add relevant context (skip internal keys)
247
+ skip_keys = {"level", "event", "timestamp", "logger"}
248
+ context_parts = []
249
+
250
+ for key, value in event_dict.items():
251
+ if key in skip_keys:
252
+ continue
253
+ context_parts.append(f"{key}={value}")
254
+
255
+ if context_parts:
256
+ message += f" ({', '.join(context_parts)})"
257
+
258
+ return message
259
+
260
+
261
+ def add_trace_context(logger, method_name, event_dict):
262
+ """
263
+ Processor that automatically adds OpenTelemetry trace context to all logs.
264
+
265
+ This enables trace-log correlation by including:
266
+ - trace_id: The current trace ID (32-character hex)
267
+ - span_id: The current span ID (16-character hex)
268
+
269
+ These IDs allow you to:
270
+ 1. Copy trace_id from logs → Search in Jaeger UI
271
+ 2. See which logs belong to which trace
272
+ 3. Correlate application logs with distributed traces
273
+
274
+ Args:
275
+ logger: The logger instance
276
+ method_name: The method being called (info, warning, etc.)
277
+ event_dict: Dictionary containing log event data
278
+
279
+ Returns:
280
+ dict: Updated event_dict with trace context
281
+ """
282
+ try:
283
+ from control_plane_api.app.observability.optional import get_current_span
284
+
285
+ span = get_current_span()
286
+ if span and span.is_recording():
287
+ span_context = span.get_span_context()
288
+ if span_context and span_context.is_valid:
289
+ # Add trace context to every log message
290
+ event_dict["trace_id"] = format(span_context.trace_id, '032x')
291
+ event_dict["span_id"] = format(span_context.span_id, '016x')
292
+ except Exception:
293
+ # If OTEL not available or error, silently continue
294
+ # (graceful degradation - logs still work without tracing)
295
+ pass
296
+
297
+ return event_dict
298
+
299
+
300
+ def configure_logging() -> None:
301
+ """
302
+ Configure structlog with dynamic settings from environment variables.
303
+
304
+ This function sets up structlog with:
305
+ - Dynamic log level from KUBIYA_CLI_LOG_LEVEL (or fallback)
306
+ - Dynamic log format from KUBIYA_LOG_FORMAT
307
+ - Appropriate renderer based on format
308
+ - Standard processors for context and timestamps
309
+ - Automatic trace context injection (trace_id, span_id)
310
+
311
+ Should be called once at application startup before any logging occurs.
312
+ """
313
+ log_level = get_log_level()
314
+ log_format = get_log_format()
315
+
316
+ # Select renderer based on format
317
+ if log_format == "json":
318
+ renderer = json_renderer
319
+ elif log_format == "text":
320
+ renderer = text_renderer
321
+ else: # "pretty" (default)
322
+ renderer = pretty_console_renderer
323
+
324
+ # Configure structlog with trace context processor
325
+ structlog.configure(
326
+ processors=[
327
+ structlog.contextvars.merge_contextvars,
328
+ structlog.processors.add_log_level,
329
+ add_trace_context, # ← Automatically adds trace_id and span_id to all logs
330
+ structlog.processors.TimeStamper(fmt="iso"),
331
+ renderer,
332
+ ],
333
+ wrapper_class=structlog.make_filtering_bound_logger(log_level),
334
+ logger_factory=structlog.PrintLoggerFactory(),
335
+ )
@@ -0,0 +1,326 @@
1
+ """Unified logging helper for clear and structured logs across the worker.
2
+
3
+ This module provides consistent logging utilities to make logs easy to read and understand.
4
+ """
5
+
6
+ import structlog
7
+ from typing import Optional, Dict, Any
8
+ from datetime import datetime
9
+
10
+
11
+ class ExecutionLogger:
12
+ """Unified logger for execution workflows with clear, human-readable output."""
13
+
14
+ def __init__(self, logger_name: str = "worker"):
15
+ self.logger = structlog.get_logger(logger_name)
16
+
17
+ @staticmethod
18
+ def _format_execution_id(execution_id: str) -> str:
19
+ """Format execution ID for display (show first 8 chars)."""
20
+ if not execution_id:
21
+ return "unknown"
22
+ return execution_id[:8] if len(execution_id) > 8 else execution_id
23
+
24
+ @staticmethod
25
+ def _get_emoji(status: str) -> str:
26
+ """Get emoji for status."""
27
+ emoji_map = {
28
+ "started": "🚀",
29
+ "running": "⚙️",
30
+ "streaming": "📡",
31
+ "waiting": "⏳",
32
+ "completed": "✅",
33
+ "failed": "❌",
34
+ "cancelled": "🛑",
35
+ "retry": "🔄",
36
+ "warning": "⚠️",
37
+ "info": "ℹ️",
38
+ }
39
+ return emoji_map.get(status.lower(), "•")
40
+
41
+ def execution_started(
42
+ self,
43
+ execution_id: str,
44
+ agent_id: Optional[str] = None,
45
+ model: Optional[str] = None,
46
+ runtime: Optional[str] = None,
47
+ ):
48
+ """Log execution start."""
49
+ exec_short = self._format_execution_id(execution_id)
50
+ msg = f"🚀 Execution Started: {exec_short}"
51
+
52
+ details = []
53
+ if agent_id:
54
+ details.append(f"agent={agent_id[:8]}")
55
+ if model:
56
+ details.append(f"model={model}")
57
+ if runtime:
58
+ details.append(f"runtime={runtime}")
59
+
60
+ if details:
61
+ msg += f" ({', '.join(details)})"
62
+
63
+ self.logger.info(msg, execution_id=execution_id)
64
+
65
+ # Print clear separator to distinguish between executions
66
+ print(f"\n{'─' * 80}")
67
+ print(f"🚀 Execution Started: {exec_short}")
68
+ if details:
69
+ print(f" {' | '.join(details)}")
70
+ print(f"{'─' * 80}")
71
+
72
+ def execution_completed(self, execution_id: str, duration_ms: Optional[int] = None):
73
+ """Log execution completion."""
74
+ exec_short = self._format_execution_id(execution_id)
75
+ msg = f"✅ Execution Completed: {exec_short}"
76
+
77
+ if duration_ms:
78
+ duration_sec = duration_ms / 1000
79
+ msg += f" (took {duration_sec:.2f}s)"
80
+
81
+ self.logger.info(msg, execution_id=execution_id)
82
+
83
+ # Print clear end separator
84
+ print(f"\n{'─' * 80}")
85
+ print(msg)
86
+ print(f"{'─' * 80}\n")
87
+
88
+ def execution_failed(
89
+ self,
90
+ execution_id: str,
91
+ error: str,
92
+ error_type: Optional[str] = None,
93
+ recoverable: bool = False,
94
+ ):
95
+ """Log execution failure."""
96
+ exec_short = self._format_execution_id(execution_id)
97
+
98
+ if recoverable:
99
+ msg = f"⚠️ Execution Error (Recoverable): {exec_short}"
100
+ else:
101
+ msg = f"❌ Execution Failed: {exec_short}"
102
+
103
+ self.logger.error(
104
+ msg,
105
+ execution_id=execution_id,
106
+ error=error,
107
+ error_type=error_type,
108
+ )
109
+
110
+ # Print clear failure separator
111
+ print(f"\n{'─' * 80}")
112
+ print(msg)
113
+ if error_type:
114
+ print(f" Error Type: {error_type}")
115
+ print(f" Error: {error}")
116
+ print(f"{'─' * 80}\n")
117
+
118
+ def activity_started(
119
+ self,
120
+ activity_name: str,
121
+ execution_id: str,
122
+ details: Optional[Dict[str, Any]] = None,
123
+ ):
124
+ """Log activity start."""
125
+ exec_short = self._format_execution_id(execution_id)
126
+ msg = f"⚙️ {activity_name}: {exec_short}"
127
+
128
+ if details:
129
+ detail_str = ", ".join([f"{k}={v}" for k, v in details.items()])
130
+ msg += f" ({detail_str})"
131
+
132
+ self.logger.info(msg, execution_id=execution_id, activity=activity_name)
133
+ print(f" → {msg}")
134
+
135
+ def activity_completed(
136
+ self,
137
+ activity_name: str,
138
+ execution_id: str,
139
+ result: Optional[str] = None,
140
+ ):
141
+ """Log activity completion."""
142
+ exec_short = self._format_execution_id(execution_id)
143
+ msg = f"✅ {activity_name}: {exec_short}"
144
+
145
+ if result:
146
+ msg += f" - {result}"
147
+
148
+ self.logger.info(msg, execution_id=execution_id, activity=activity_name)
149
+ print(f" ✓ {msg}")
150
+
151
+ def activity_failed(
152
+ self,
153
+ activity_name: str,
154
+ execution_id: str,
155
+ error: str,
156
+ will_retry: bool = False,
157
+ ):
158
+ """Log activity failure."""
159
+ exec_short = self._format_execution_id(execution_id)
160
+
161
+ if will_retry:
162
+ msg = f"🔄 {activity_name} Failed (Retrying): {exec_short}"
163
+ else:
164
+ msg = f"❌ {activity_name} Failed: {exec_short}"
165
+
166
+ self.logger.error(
167
+ msg,
168
+ execution_id=execution_id,
169
+ activity=activity_name,
170
+ error=error,
171
+ )
172
+ print(f" ✗ {msg}")
173
+ print(f" Error: {error}")
174
+
175
+ def streaming_started(self, execution_id: str):
176
+ """Log streaming start."""
177
+ exec_short = self._format_execution_id(execution_id)
178
+ msg = f"📡 Streaming Response: {exec_short}"
179
+ self.logger.info(msg, execution_id=execution_id)
180
+ print(f" → {msg}")
181
+
182
+ def streaming_progress(
183
+ self,
184
+ execution_id: str,
185
+ chunks_received: int,
186
+ response_length: int,
187
+ ):
188
+ """Log streaming progress (only at milestones)."""
189
+ exec_short = self._format_execution_id(execution_id)
190
+
191
+ # Only log at milestones to avoid spam
192
+ if chunks_received % 50 == 0 or chunks_received < 5:
193
+ msg = f"📡 Streaming: {exec_short} - {chunks_received} chunks, {response_length} chars"
194
+ self.logger.debug(msg, execution_id=execution_id)
195
+ # Only print for first few chunks or milestones
196
+ if chunks_received < 5:
197
+ print(f" {msg}")
198
+
199
+ def status_update(
200
+ self,
201
+ execution_id: str,
202
+ old_status: Optional[str],
203
+ new_status: str,
204
+ reason: Optional[str] = None,
205
+ ):
206
+ """Log status update."""
207
+ exec_short = self._format_execution_id(execution_id)
208
+ emoji = self._get_emoji(new_status)
209
+
210
+ if old_status:
211
+ msg = f"{emoji} Status Change: {exec_short} ({old_status} → {new_status})"
212
+ else:
213
+ msg = f"{emoji} Status: {exec_short} ({new_status})"
214
+
215
+ if reason:
216
+ msg += f" - {reason}"
217
+
218
+ self.logger.info(msg, execution_id=execution_id, status=new_status)
219
+ print(f" {msg}")
220
+
221
+ def workflow_signal(
222
+ self,
223
+ execution_id: str,
224
+ signal_name: str,
225
+ details: Optional[str] = None,
226
+ ):
227
+ """Log workflow signal received."""
228
+ exec_short = self._format_execution_id(execution_id)
229
+ msg = f"📨 Signal Received: {exec_short} ({signal_name})"
230
+
231
+ if details:
232
+ msg += f" - {details}"
233
+
234
+ self.logger.info(msg, execution_id=execution_id, signal=signal_name)
235
+ print(f" {msg}")
236
+
237
+ def turn_started(self, execution_id: str, turn_number: int):
238
+ """Log conversation turn start."""
239
+ exec_short = self._format_execution_id(execution_id)
240
+ msg = f"💬 Turn {turn_number} Started: {exec_short}"
241
+ self.logger.info(msg, execution_id=execution_id, turn=turn_number)
242
+ print(f"\n {msg}")
243
+
244
+ def turn_completed(
245
+ self,
246
+ execution_id: str,
247
+ turn_number: int,
248
+ tokens_used: Optional[int] = None,
249
+ ):
250
+ """Log conversation turn completion."""
251
+ exec_short = self._format_execution_id(execution_id)
252
+ msg = f"💬 Turn {turn_number} Completed: {exec_short}"
253
+
254
+ if tokens_used:
255
+ msg += f" ({tokens_used} tokens)"
256
+
257
+ self.logger.info(msg, execution_id=execution_id, turn=turn_number)
258
+ print(f" {msg}")
259
+
260
+ def tool_call_started(
261
+ self,
262
+ execution_id: str,
263
+ tool_name: str,
264
+ tool_id: Optional[str] = None,
265
+ ):
266
+ """Log tool call start."""
267
+ exec_short = self._format_execution_id(execution_id)
268
+ msg = f"🔧 Tool Called: {tool_name}"
269
+
270
+ if tool_id:
271
+ msg += f" (id: {tool_id[:8]})"
272
+
273
+ self.logger.info(
274
+ msg,
275
+ execution_id=execution_id,
276
+ tool_name=tool_name,
277
+ tool_id=tool_id,
278
+ )
279
+ print(f" → {msg}")
280
+
281
+ def tool_call_completed(
282
+ self,
283
+ execution_id: str,
284
+ tool_name: str,
285
+ success: bool,
286
+ duration_ms: Optional[int] = None,
287
+ ):
288
+ """Log tool call completion."""
289
+ exec_short = self._format_execution_id(execution_id)
290
+
291
+ if success:
292
+ emoji = "✅"
293
+ status = "completed"
294
+ else:
295
+ emoji = "❌"
296
+ status = "failed"
297
+
298
+ msg = f"{emoji} Tool {status}: {tool_name}"
299
+
300
+ if duration_ms:
301
+ msg += f" (took {duration_ms}ms)"
302
+
303
+ self.logger.info(
304
+ msg,
305
+ execution_id=execution_id,
306
+ tool_name=tool_name,
307
+ success=success,
308
+ )
309
+ print(f" {msg}")
310
+
311
+ def warning(self, execution_id: str, message: str, details: Optional[Dict] = None):
312
+ """Log warning."""
313
+ exec_short = self._format_execution_id(execution_id)
314
+ msg = f"⚠️ Warning: {exec_short} - {message}"
315
+
316
+ self.logger.warning(msg, execution_id=execution_id, **(details or {}))
317
+ print(f" {msg}")
318
+
319
+ def debug(self, execution_id: str, message: str):
320
+ """Log debug message (only in debug mode)."""
321
+ exec_short = self._format_execution_id(execution_id)
322
+ self.logger.debug(message, execution_id=execution_id)
323
+
324
+
325
+ # Global logger instance
326
+ execution_logger = ExecutionLogger()