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.
- control_plane_api/LICENSE +676 -0
- control_plane_api/README.md +350 -0
- control_plane_api/__init__.py +4 -0
- control_plane_api/__version__.py +8 -0
- control_plane_api/alembic/README +1 -0
- control_plane_api/alembic/env.py +121 -0
- control_plane_api/alembic/script.py.mako +28 -0
- control_plane_api/alembic/versions/2613c65c3dbe_initial_database_setup.py +32 -0
- control_plane_api/alembic/versions/2df520d4927d_merge_heads.py +28 -0
- control_plane_api/alembic/versions/43abf98d6a01_add_paused_status_to_executions.py +73 -0
- control_plane_api/alembic/versions/6289854264cb_merge_multiple_heads.py +28 -0
- control_plane_api/alembic/versions/6a4d4dc3d8dc_generate_execution_transitions.py +50 -0
- control_plane_api/alembic/versions/87d11cf0a783_add_disconnected_status_to_worker_.py +44 -0
- control_plane_api/alembic/versions/add_ephemeral_queue_support.py +85 -0
- control_plane_api/alembic/versions/add_model_type_to_llm_models.py +31 -0
- control_plane_api/alembic/versions/add_plan_executions_table.py +114 -0
- control_plane_api/alembic/versions/add_trace_span_tables.py +154 -0
- control_plane_api/alembic/versions/add_user_info_to_traces.py +36 -0
- control_plane_api/alembic/versions/adjusting_foreign_keys.py +32 -0
- control_plane_api/alembic/versions/b4983d976db2_initial_tables.py +1128 -0
- control_plane_api/alembic/versions/d181a3b40e71_rename_custom_metadata_to_metadata_in_.py +50 -0
- control_plane_api/alembic/versions/df9117888e82_add_missing_columns.py +82 -0
- control_plane_api/alembic/versions/f25de6ad895a_missing_migrations.py +34 -0
- control_plane_api/alembic/versions/f71305fb69b9_fix_ephemeral_queue_deletion_foreign_key.py +54 -0
- control_plane_api/alembic/versions/mark_local_exec_queues_as_ephemeral.py +68 -0
- control_plane_api/alembic.ini +148 -0
- control_plane_api/api/index.py +12 -0
- control_plane_api/app/__init__.py +11 -0
- control_plane_api/app/activities/__init__.py +20 -0
- control_plane_api/app/activities/agent_activities.py +384 -0
- control_plane_api/app/activities/plan_generation_activities.py +499 -0
- control_plane_api/app/activities/team_activities.py +424 -0
- control_plane_api/app/activities/temporal_cloud_activities.py +588 -0
- control_plane_api/app/config/__init__.py +35 -0
- control_plane_api/app/config/api_config.py +469 -0
- control_plane_api/app/config/config_loader.py +224 -0
- control_plane_api/app/config/model_pricing.py +323 -0
- control_plane_api/app/config/storage_config.py +159 -0
- control_plane_api/app/config.py +115 -0
- control_plane_api/app/controllers/__init__.py +0 -0
- control_plane_api/app/controllers/execution_environment_controller.py +1315 -0
- control_plane_api/app/database.py +135 -0
- control_plane_api/app/exceptions.py +408 -0
- control_plane_api/app/lib/__init__.py +11 -0
- control_plane_api/app/lib/environment.py +65 -0
- control_plane_api/app/lib/event_bus/__init__.py +17 -0
- control_plane_api/app/lib/event_bus/base.py +136 -0
- control_plane_api/app/lib/event_bus/manager.py +335 -0
- control_plane_api/app/lib/event_bus/providers/__init__.py +6 -0
- control_plane_api/app/lib/event_bus/providers/http_provider.py +166 -0
- control_plane_api/app/lib/event_bus/providers/nats_provider.py +324 -0
- control_plane_api/app/lib/event_bus/providers/redis_provider.py +233 -0
- control_plane_api/app/lib/event_bus/providers/websocket_provider.py +497 -0
- control_plane_api/app/lib/job_executor.py +330 -0
- control_plane_api/app/lib/kubiya_client.py +293 -0
- control_plane_api/app/lib/litellm_pricing.py +166 -0
- control_plane_api/app/lib/mcp_validation.py +163 -0
- control_plane_api/app/lib/nats/__init__.py +13 -0
- control_plane_api/app/lib/nats/credentials_manager.py +288 -0
- control_plane_api/app/lib/nats/listener.py +374 -0
- control_plane_api/app/lib/planning_prompt_builder.py +153 -0
- control_plane_api/app/lib/planning_tools/__init__.py +41 -0
- control_plane_api/app/lib/planning_tools/agents.py +409 -0
- control_plane_api/app/lib/planning_tools/agno_toolkit.py +836 -0
- control_plane_api/app/lib/planning_tools/base.py +119 -0
- control_plane_api/app/lib/planning_tools/cognitive_memory_tools.py +403 -0
- control_plane_api/app/lib/planning_tools/context_graph_tools.py +545 -0
- control_plane_api/app/lib/planning_tools/environments.py +218 -0
- control_plane_api/app/lib/planning_tools/knowledge.py +204 -0
- control_plane_api/app/lib/planning_tools/models.py +93 -0
- control_plane_api/app/lib/planning_tools/planning_service.py +646 -0
- control_plane_api/app/lib/planning_tools/resources.py +242 -0
- control_plane_api/app/lib/planning_tools/teams.py +334 -0
- control_plane_api/app/lib/policy_enforcer_client.py +1016 -0
- control_plane_api/app/lib/redis_client.py +803 -0
- control_plane_api/app/lib/sqlalchemy_utils.py +486 -0
- control_plane_api/app/lib/state_transition_tools/__init__.py +7 -0
- control_plane_api/app/lib/state_transition_tools/execution_context.py +388 -0
- control_plane_api/app/lib/storage/__init__.py +20 -0
- control_plane_api/app/lib/storage/base_provider.py +274 -0
- control_plane_api/app/lib/storage/provider_factory.py +157 -0
- control_plane_api/app/lib/storage/vercel_blob_provider.py +468 -0
- control_plane_api/app/lib/supabase.py +71 -0
- control_plane_api/app/lib/supabase_utils.py +138 -0
- control_plane_api/app/lib/task_planning/__init__.py +138 -0
- control_plane_api/app/lib/task_planning/agent_factory.py +308 -0
- control_plane_api/app/lib/task_planning/agents.py +389 -0
- control_plane_api/app/lib/task_planning/cache.py +218 -0
- control_plane_api/app/lib/task_planning/entity_resolver.py +273 -0
- control_plane_api/app/lib/task_planning/helpers.py +293 -0
- control_plane_api/app/lib/task_planning/hooks.py +474 -0
- control_plane_api/app/lib/task_planning/models.py +503 -0
- control_plane_api/app/lib/task_planning/plan_validator.py +166 -0
- control_plane_api/app/lib/task_planning/planning_workflow.py +2911 -0
- control_plane_api/app/lib/task_planning/runner.py +656 -0
- control_plane_api/app/lib/task_planning/streaming_hook.py +213 -0
- control_plane_api/app/lib/task_planning/workflow.py +424 -0
- control_plane_api/app/lib/templating/__init__.py +88 -0
- control_plane_api/app/lib/templating/compiler.py +278 -0
- control_plane_api/app/lib/templating/engine.py +178 -0
- control_plane_api/app/lib/templating/parsers/__init__.py +29 -0
- control_plane_api/app/lib/templating/parsers/base.py +96 -0
- control_plane_api/app/lib/templating/parsers/env.py +85 -0
- control_plane_api/app/lib/templating/parsers/graph.py +112 -0
- control_plane_api/app/lib/templating/parsers/secret.py +87 -0
- control_plane_api/app/lib/templating/parsers/simple.py +81 -0
- control_plane_api/app/lib/templating/resolver.py +366 -0
- control_plane_api/app/lib/templating/types.py +214 -0
- control_plane_api/app/lib/templating/validator.py +201 -0
- control_plane_api/app/lib/temporal_client.py +232 -0
- control_plane_api/app/lib/temporal_credentials_cache.py +178 -0
- control_plane_api/app/lib/temporal_credentials_service.py +203 -0
- control_plane_api/app/lib/validation/__init__.py +24 -0
- control_plane_api/app/lib/validation/runtime_validation.py +388 -0
- control_plane_api/app/main.py +531 -0
- control_plane_api/app/middleware/__init__.py +10 -0
- control_plane_api/app/middleware/auth.py +645 -0
- control_plane_api/app/middleware/exception_handler.py +267 -0
- control_plane_api/app/middleware/prometheus_middleware.py +173 -0
- control_plane_api/app/middleware/rate_limiting.py +384 -0
- control_plane_api/app/middleware/request_id.py +202 -0
- control_plane_api/app/models/__init__.py +40 -0
- control_plane_api/app/models/agent.py +90 -0
- control_plane_api/app/models/analytics.py +206 -0
- control_plane_api/app/models/associations.py +107 -0
- control_plane_api/app/models/auth_user.py +73 -0
- control_plane_api/app/models/context.py +161 -0
- control_plane_api/app/models/custom_integration.py +99 -0
- control_plane_api/app/models/environment.py +64 -0
- control_plane_api/app/models/execution.py +125 -0
- control_plane_api/app/models/execution_transition.py +50 -0
- control_plane_api/app/models/job.py +159 -0
- control_plane_api/app/models/llm_model.py +78 -0
- control_plane_api/app/models/orchestration.py +66 -0
- control_plane_api/app/models/plan_execution.py +102 -0
- control_plane_api/app/models/presence.py +49 -0
- control_plane_api/app/models/project.py +61 -0
- control_plane_api/app/models/project_management.py +85 -0
- control_plane_api/app/models/session.py +29 -0
- control_plane_api/app/models/skill.py +155 -0
- control_plane_api/app/models/system_tables.py +43 -0
- control_plane_api/app/models/task_planning.py +372 -0
- control_plane_api/app/models/team.py +86 -0
- control_plane_api/app/models/trace.py +257 -0
- control_plane_api/app/models/user_profile.py +54 -0
- control_plane_api/app/models/worker.py +221 -0
- control_plane_api/app/models/workflow.py +161 -0
- control_plane_api/app/models/workspace.py +50 -0
- control_plane_api/app/observability/__init__.py +177 -0
- control_plane_api/app/observability/context_logging.py +475 -0
- control_plane_api/app/observability/decorators.py +337 -0
- control_plane_api/app/observability/local_span_processor.py +702 -0
- control_plane_api/app/observability/metrics.py +303 -0
- control_plane_api/app/observability/middleware.py +246 -0
- control_plane_api/app/observability/optional.py +115 -0
- control_plane_api/app/observability/tracing.py +382 -0
- control_plane_api/app/policies/README.md +149 -0
- control_plane_api/app/policies/approved_users.rego +62 -0
- control_plane_api/app/policies/business_hours.rego +51 -0
- control_plane_api/app/policies/rate_limiting.rego +100 -0
- control_plane_api/app/policies/tool_enforcement/README.md +336 -0
- control_plane_api/app/policies/tool_enforcement/bash_command_validation.rego +71 -0
- control_plane_api/app/policies/tool_enforcement/business_hours_enforcement.rego +82 -0
- control_plane_api/app/policies/tool_enforcement/mcp_tool_allowlist.rego +58 -0
- control_plane_api/app/policies/tool_enforcement/production_safeguards.rego +80 -0
- control_plane_api/app/policies/tool_enforcement/role_based_tool_access.rego +44 -0
- control_plane_api/app/policies/tool_restrictions.rego +86 -0
- control_plane_api/app/routers/__init__.py +4 -0
- control_plane_api/app/routers/agents.py +382 -0
- control_plane_api/app/routers/agents_v2.py +1598 -0
- control_plane_api/app/routers/analytics.py +1310 -0
- control_plane_api/app/routers/auth.py +59 -0
- control_plane_api/app/routers/client_config.py +57 -0
- control_plane_api/app/routers/context_graph.py +561 -0
- control_plane_api/app/routers/context_manager.py +577 -0
- control_plane_api/app/routers/custom_integrations.py +490 -0
- control_plane_api/app/routers/enforcer.py +132 -0
- control_plane_api/app/routers/environment_context.py +252 -0
- control_plane_api/app/routers/environments.py +761 -0
- control_plane_api/app/routers/execution_environment.py +847 -0
- control_plane_api/app/routers/executions/__init__.py +28 -0
- control_plane_api/app/routers/executions/router.py +286 -0
- control_plane_api/app/routers/executions/services/__init__.py +22 -0
- control_plane_api/app/routers/executions/services/demo_worker_health.py +156 -0
- control_plane_api/app/routers/executions/services/status_service.py +420 -0
- control_plane_api/app/routers/executions/services/test_worker_health.py +480 -0
- control_plane_api/app/routers/executions/services/worker_health.py +514 -0
- control_plane_api/app/routers/executions/streaming/__init__.py +22 -0
- control_plane_api/app/routers/executions/streaming/deduplication.py +352 -0
- control_plane_api/app/routers/executions/streaming/event_buffer.py +353 -0
- control_plane_api/app/routers/executions/streaming/event_formatter.py +964 -0
- control_plane_api/app/routers/executions/streaming/history_loader.py +588 -0
- control_plane_api/app/routers/executions/streaming/live_source.py +693 -0
- control_plane_api/app/routers/executions/streaming/streamer.py +849 -0
- control_plane_api/app/routers/executions.py +4888 -0
- control_plane_api/app/routers/health.py +165 -0
- control_plane_api/app/routers/health_v2.py +394 -0
- control_plane_api/app/routers/integration_templates.py +496 -0
- control_plane_api/app/routers/integrations.py +287 -0
- control_plane_api/app/routers/jobs.py +1809 -0
- control_plane_api/app/routers/metrics.py +517 -0
- control_plane_api/app/routers/models.py +82 -0
- control_plane_api/app/routers/models_v2.py +628 -0
- control_plane_api/app/routers/plan_executions.py +1481 -0
- control_plane_api/app/routers/plan_generation_async.py +304 -0
- control_plane_api/app/routers/policies.py +669 -0
- control_plane_api/app/routers/presence.py +234 -0
- control_plane_api/app/routers/projects.py +987 -0
- control_plane_api/app/routers/runners.py +379 -0
- control_plane_api/app/routers/runtimes.py +172 -0
- control_plane_api/app/routers/secrets.py +171 -0
- control_plane_api/app/routers/skills.py +1010 -0
- control_plane_api/app/routers/skills_definitions.py +140 -0
- control_plane_api/app/routers/storage.py +456 -0
- control_plane_api/app/routers/task_planning.py +611 -0
- control_plane_api/app/routers/task_queues.py +650 -0
- control_plane_api/app/routers/team_context.py +274 -0
- control_plane_api/app/routers/teams.py +1747 -0
- control_plane_api/app/routers/templates.py +248 -0
- control_plane_api/app/routers/traces.py +571 -0
- control_plane_api/app/routers/websocket_client.py +479 -0
- control_plane_api/app/routers/websocket_executions_status.py +437 -0
- control_plane_api/app/routers/websocket_gateway.py +323 -0
- control_plane_api/app/routers/websocket_traces.py +576 -0
- control_plane_api/app/routers/worker_queues.py +2555 -0
- control_plane_api/app/routers/worker_websocket.py +419 -0
- control_plane_api/app/routers/workers.py +1004 -0
- control_plane_api/app/routers/workflows.py +204 -0
- control_plane_api/app/runtimes/__init__.py +6 -0
- control_plane_api/app/runtimes/validation.py +344 -0
- control_plane_api/app/schemas/__init__.py +1 -0
- control_plane_api/app/schemas/job_schemas.py +302 -0
- control_plane_api/app/schemas/mcp_schemas.py +311 -0
- control_plane_api/app/schemas/template_schemas.py +133 -0
- control_plane_api/app/schemas/trace_schemas.py +168 -0
- control_plane_api/app/schemas/worker_queue_observability_schemas.py +165 -0
- control_plane_api/app/services/__init__.py +1 -0
- control_plane_api/app/services/agno_planning_strategy.py +233 -0
- control_plane_api/app/services/agno_service.py +838 -0
- control_plane_api/app/services/claude_code_planning_service.py +203 -0
- control_plane_api/app/services/context_graph_client.py +224 -0
- control_plane_api/app/services/custom_integration_service.py +415 -0
- control_plane_api/app/services/integration_resolution_service.py +345 -0
- control_plane_api/app/services/litellm_service.py +394 -0
- control_plane_api/app/services/plan_generator.py +79 -0
- control_plane_api/app/services/planning_strategy.py +66 -0
- control_plane_api/app/services/planning_strategy_factory.py +118 -0
- control_plane_api/app/services/policy_service.py +615 -0
- control_plane_api/app/services/state_transition_service.py +755 -0
- control_plane_api/app/services/storage_service.py +593 -0
- control_plane_api/app/services/temporal_cloud_provisioning.py +150 -0
- control_plane_api/app/services/toolsets/context_graph_skill.py +432 -0
- control_plane_api/app/services/trace_retention.py +354 -0
- control_plane_api/app/services/worker_queue_metrics_service.py +190 -0
- control_plane_api/app/services/workflow_cancellation_manager.py +135 -0
- control_plane_api/app/services/workflow_operations_service.py +611 -0
- control_plane_api/app/skills/__init__.py +100 -0
- control_plane_api/app/skills/base.py +239 -0
- control_plane_api/app/skills/builtin/__init__.py +37 -0
- control_plane_api/app/skills/builtin/agent_communication/__init__.py +8 -0
- control_plane_api/app/skills/builtin/agent_communication/skill.py +246 -0
- control_plane_api/app/skills/builtin/code_ingestion/__init__.py +4 -0
- control_plane_api/app/skills/builtin/code_ingestion/skill.py +267 -0
- control_plane_api/app/skills/builtin/cognitive_memory/__init__.py +4 -0
- control_plane_api/app/skills/builtin/cognitive_memory/skill.py +174 -0
- control_plane_api/app/skills/builtin/contextual_awareness/__init__.py +4 -0
- control_plane_api/app/skills/builtin/contextual_awareness/skill.py +387 -0
- control_plane_api/app/skills/builtin/data_visualization/__init__.py +4 -0
- control_plane_api/app/skills/builtin/data_visualization/skill.py +154 -0
- control_plane_api/app/skills/builtin/docker/__init__.py +4 -0
- control_plane_api/app/skills/builtin/docker/skill.py +104 -0
- control_plane_api/app/skills/builtin/file_generation/__init__.py +4 -0
- control_plane_api/app/skills/builtin/file_generation/skill.py +94 -0
- control_plane_api/app/skills/builtin/file_system/__init__.py +4 -0
- control_plane_api/app/skills/builtin/file_system/skill.py +110 -0
- control_plane_api/app/skills/builtin/knowledge_api/__init__.py +5 -0
- control_plane_api/app/skills/builtin/knowledge_api/skill.py +124 -0
- control_plane_api/app/skills/builtin/python/__init__.py +4 -0
- control_plane_api/app/skills/builtin/python/skill.py +92 -0
- control_plane_api/app/skills/builtin/remote_filesystem/__init__.py +5 -0
- control_plane_api/app/skills/builtin/remote_filesystem/skill.py +170 -0
- control_plane_api/app/skills/builtin/shell/__init__.py +4 -0
- control_plane_api/app/skills/builtin/shell/skill.py +161 -0
- control_plane_api/app/skills/builtin/slack/__init__.py +3 -0
- control_plane_api/app/skills/builtin/slack/skill.py +302 -0
- control_plane_api/app/skills/builtin/workflow_executor/__init__.py +4 -0
- control_plane_api/app/skills/builtin/workflow_executor/skill.py +469 -0
- control_plane_api/app/skills/business_intelligence.py +189 -0
- control_plane_api/app/skills/config.py +63 -0
- control_plane_api/app/skills/loaders/__init__.py +14 -0
- control_plane_api/app/skills/loaders/base.py +73 -0
- control_plane_api/app/skills/loaders/filesystem_loader.py +199 -0
- control_plane_api/app/skills/registry.py +125 -0
- control_plane_api/app/utils/helpers.py +12 -0
- control_plane_api/app/utils/workflow_executor.py +354 -0
- control_plane_api/app/workflows/__init__.py +11 -0
- control_plane_api/app/workflows/agent_execution.py +520 -0
- control_plane_api/app/workflows/agent_execution_with_skills.py +223 -0
- control_plane_api/app/workflows/namespace_provisioning.py +326 -0
- control_plane_api/app/workflows/plan_generation.py +254 -0
- control_plane_api/app/workflows/team_execution.py +442 -0
- control_plane_api/scripts/seed_models.py +240 -0
- control_plane_api/scripts/validate_existing_tool_names.py +492 -0
- control_plane_api/shared/__init__.py +8 -0
- control_plane_api/shared/version.py +17 -0
- control_plane_api/test_deduplication.py +274 -0
- control_plane_api/test_executor_deduplication_e2e.py +309 -0
- control_plane_api/test_job_execution_e2e.py +283 -0
- control_plane_api/test_real_integration.py +193 -0
- control_plane_api/version.py +38 -0
- control_plane_api/worker/__init__.py +0 -0
- control_plane_api/worker/activities/__init__.py +0 -0
- control_plane_api/worker/activities/agent_activities.py +1585 -0
- control_plane_api/worker/activities/approval_activities.py +234 -0
- control_plane_api/worker/activities/job_activities.py +199 -0
- control_plane_api/worker/activities/runtime_activities.py +1167 -0
- control_plane_api/worker/activities/skill_activities.py +282 -0
- control_plane_api/worker/activities/team_activities.py +479 -0
- control_plane_api/worker/agent_runtime_server.py +370 -0
- control_plane_api/worker/binary_manager.py +333 -0
- control_plane_api/worker/config/__init__.py +31 -0
- control_plane_api/worker/config/worker_config.py +273 -0
- control_plane_api/worker/control_plane_client.py +1491 -0
- control_plane_api/worker/examples/analytics_integration_example.py +362 -0
- control_plane_api/worker/health_monitor.py +159 -0
- control_plane_api/worker/metrics.py +237 -0
- control_plane_api/worker/models/__init__.py +1 -0
- control_plane_api/worker/models/error_events.py +105 -0
- control_plane_api/worker/models/inputs.py +89 -0
- control_plane_api/worker/runtimes/__init__.py +35 -0
- control_plane_api/worker/runtimes/agent_runtime/runtime.py +485 -0
- control_plane_api/worker/runtimes/agno/__init__.py +34 -0
- control_plane_api/worker/runtimes/agno/config.py +248 -0
- control_plane_api/worker/runtimes/agno/hooks.py +385 -0
- control_plane_api/worker/runtimes/agno/mcp_builder.py +195 -0
- control_plane_api/worker/runtimes/agno/runtime.py +1063 -0
- control_plane_api/worker/runtimes/agno/utils.py +163 -0
- control_plane_api/worker/runtimes/base.py +979 -0
- control_plane_api/worker/runtimes/claude_code/__init__.py +38 -0
- control_plane_api/worker/runtimes/claude_code/cleanup.py +184 -0
- control_plane_api/worker/runtimes/claude_code/client_pool.py +529 -0
- control_plane_api/worker/runtimes/claude_code/config.py +829 -0
- control_plane_api/worker/runtimes/claude_code/hooks.py +482 -0
- control_plane_api/worker/runtimes/claude_code/litellm_proxy.py +1702 -0
- control_plane_api/worker/runtimes/claude_code/mcp_builder.py +467 -0
- control_plane_api/worker/runtimes/claude_code/mcp_discovery.py +558 -0
- control_plane_api/worker/runtimes/claude_code/runtime.py +1546 -0
- control_plane_api/worker/runtimes/claude_code/tool_mapper.py +403 -0
- control_plane_api/worker/runtimes/claude_code/utils.py +149 -0
- control_plane_api/worker/runtimes/factory.py +173 -0
- control_plane_api/worker/runtimes/model_utils.py +107 -0
- control_plane_api/worker/runtimes/validation.py +93 -0
- control_plane_api/worker/services/__init__.py +1 -0
- control_plane_api/worker/services/agent_communication_tools.py +908 -0
- control_plane_api/worker/services/agent_executor.py +485 -0
- control_plane_api/worker/services/agent_executor_v2.py +793 -0
- control_plane_api/worker/services/analytics_collector.py +457 -0
- control_plane_api/worker/services/analytics_service.py +464 -0
- control_plane_api/worker/services/approval_tools.py +310 -0
- control_plane_api/worker/services/approval_tools_agno.py +207 -0
- control_plane_api/worker/services/cancellation_manager.py +177 -0
- control_plane_api/worker/services/code_ingestion_tools.py +465 -0
- control_plane_api/worker/services/contextual_awareness_tools.py +405 -0
- control_plane_api/worker/services/data_visualization.py +834 -0
- control_plane_api/worker/services/event_publisher.py +531 -0
- control_plane_api/worker/services/jira_tools.py +257 -0
- control_plane_api/worker/services/remote_filesystem_tools.py +498 -0
- control_plane_api/worker/services/runtime_analytics.py +328 -0
- control_plane_api/worker/services/session_service.py +365 -0
- control_plane_api/worker/services/skill_context_enhancement.py +181 -0
- control_plane_api/worker/services/skill_factory.py +471 -0
- control_plane_api/worker/services/system_prompt_enhancement.py +410 -0
- control_plane_api/worker/services/team_executor.py +715 -0
- control_plane_api/worker/services/team_executor_v2.py +1866 -0
- control_plane_api/worker/services/tool_enforcement.py +254 -0
- control_plane_api/worker/services/workflow_executor/__init__.py +52 -0
- control_plane_api/worker/services/workflow_executor/event_processor.py +287 -0
- control_plane_api/worker/services/workflow_executor/event_publisher.py +210 -0
- control_plane_api/worker/services/workflow_executor/executors/__init__.py +15 -0
- control_plane_api/worker/services/workflow_executor/executors/base.py +270 -0
- control_plane_api/worker/services/workflow_executor/executors/json_executor.py +50 -0
- control_plane_api/worker/services/workflow_executor/executors/python_executor.py +50 -0
- control_plane_api/worker/services/workflow_executor/models.py +142 -0
- control_plane_api/worker/services/workflow_executor_tools.py +1748 -0
- control_plane_api/worker/skills/__init__.py +12 -0
- control_plane_api/worker/skills/builtin/context_graph_search/README.md +213 -0
- control_plane_api/worker/skills/builtin/context_graph_search/__init__.py +5 -0
- control_plane_api/worker/skills/builtin/context_graph_search/agno_impl.py +808 -0
- control_plane_api/worker/skills/builtin/context_graph_search/skill.yaml +67 -0
- control_plane_api/worker/skills/builtin/contextual_awareness/__init__.py +4 -0
- control_plane_api/worker/skills/builtin/contextual_awareness/agno_impl.py +62 -0
- control_plane_api/worker/skills/builtin/data_visualization/agno_impl.py +18 -0
- control_plane_api/worker/skills/builtin/data_visualization/skill.yaml +84 -0
- control_plane_api/worker/skills/builtin/docker/agno_impl.py +65 -0
- control_plane_api/worker/skills/builtin/docker/skill.yaml +60 -0
- control_plane_api/worker/skills/builtin/file_generation/agno_impl.py +47 -0
- control_plane_api/worker/skills/builtin/file_generation/skill.yaml +64 -0
- control_plane_api/worker/skills/builtin/file_system/agno_impl.py +32 -0
- control_plane_api/worker/skills/builtin/file_system/skill.yaml +54 -0
- control_plane_api/worker/skills/builtin/knowledge_api/__init__.py +4 -0
- control_plane_api/worker/skills/builtin/knowledge_api/agno_impl.py +50 -0
- control_plane_api/worker/skills/builtin/knowledge_api/skill.yaml +66 -0
- control_plane_api/worker/skills/builtin/python/agno_impl.py +25 -0
- control_plane_api/worker/skills/builtin/python/skill.yaml +60 -0
- control_plane_api/worker/skills/builtin/schema_fix_mixin.py +260 -0
- control_plane_api/worker/skills/builtin/shell/agno_impl.py +31 -0
- control_plane_api/worker/skills/builtin/shell/skill.yaml +60 -0
- control_plane_api/worker/skills/builtin/slack/__init__.py +3 -0
- control_plane_api/worker/skills/builtin/slack/agno_impl.py +1282 -0
- control_plane_api/worker/skills/builtin/slack/skill.yaml +276 -0
- control_plane_api/worker/skills/builtin/workflow_executor/agno_impl.py +62 -0
- control_plane_api/worker/skills/builtin/workflow_executor/skill.yaml +79 -0
- control_plane_api/worker/skills/loaders/__init__.py +5 -0
- control_plane_api/worker/skills/loaders/base.py +23 -0
- control_plane_api/worker/skills/loaders/filesystem_loader.py +357 -0
- control_plane_api/worker/skills/registry.py +208 -0
- control_plane_api/worker/tests/__init__.py +1 -0
- control_plane_api/worker/tests/conftest.py +12 -0
- control_plane_api/worker/tests/e2e/__init__.py +0 -0
- control_plane_api/worker/tests/e2e/test_context_graph_real_api.py +338 -0
- control_plane_api/worker/tests/e2e/test_context_graph_templates_e2e.py +523 -0
- control_plane_api/worker/tests/e2e/test_enforcement_e2e.py +344 -0
- control_plane_api/worker/tests/e2e/test_execution_flow.py +571 -0
- control_plane_api/worker/tests/e2e/test_single_execution_mode.py +656 -0
- control_plane_api/worker/tests/integration/__init__.py +0 -0
- control_plane_api/worker/tests/integration/test_builtin_skills_fixes.py +245 -0
- control_plane_api/worker/tests/integration/test_context_graph_search_integration.py +365 -0
- control_plane_api/worker/tests/integration/test_control_plane_integration.py +308 -0
- control_plane_api/worker/tests/integration/test_hook_enforcement_integration.py +579 -0
- control_plane_api/worker/tests/integration/test_scheduled_job_workflow.py +237 -0
- control_plane_api/worker/tests/integration/test_system_prompt_enhancement_integration.py +343 -0
- control_plane_api/worker/tests/unit/__init__.py +0 -0
- control_plane_api/worker/tests/unit/test_builtin_skill_autoload.py +396 -0
- control_plane_api/worker/tests/unit/test_context_graph_search.py +450 -0
- control_plane_api/worker/tests/unit/test_context_graph_templates.py +403 -0
- control_plane_api/worker/tests/unit/test_control_plane_client.py +401 -0
- control_plane_api/worker/tests/unit/test_control_plane_client_jobs.py +345 -0
- control_plane_api/worker/tests/unit/test_job_activities.py +353 -0
- control_plane_api/worker/tests/unit/test_skill_context_enhancement.py +321 -0
- control_plane_api/worker/tests/unit/test_system_prompt_enhancement.py +415 -0
- control_plane_api/worker/tests/unit/test_tool_enforcement.py +324 -0
- control_plane_api/worker/utils/__init__.py +1 -0
- control_plane_api/worker/utils/chunk_batcher.py +330 -0
- control_plane_api/worker/utils/environment.py +65 -0
- control_plane_api/worker/utils/error_publisher.py +260 -0
- control_plane_api/worker/utils/event_batcher.py +256 -0
- control_plane_api/worker/utils/logging_config.py +335 -0
- control_plane_api/worker/utils/logging_helper.py +326 -0
- control_plane_api/worker/utils/parameter_validator.py +120 -0
- control_plane_api/worker/utils/retry_utils.py +60 -0
- control_plane_api/worker/utils/streaming_utils.py +665 -0
- control_plane_api/worker/utils/tool_validation.py +332 -0
- control_plane_api/worker/utils/workspace_manager.py +163 -0
- control_plane_api/worker/websocket_client.py +393 -0
- control_plane_api/worker/worker.py +1297 -0
- control_plane_api/worker/workflows/__init__.py +0 -0
- control_plane_api/worker/workflows/agent_execution.py +909 -0
- control_plane_api/worker/workflows/scheduled_job_wrapper.py +332 -0
- control_plane_api/worker/workflows/team_execution.py +611 -0
- kubiya_control_plane_api-0.9.15.dist-info/METADATA +354 -0
- kubiya_control_plane_api-0.9.15.dist-info/RECORD +479 -0
- kubiya_control_plane_api-0.9.15.dist-info/WHEEL +5 -0
- kubiya_control_plane_api-0.9.15.dist-info/entry_points.txt +5 -0
- kubiya_control_plane_api-0.9.15.dist-info/licenses/LICENSE +676 -0
- kubiya_control_plane_api-0.9.15.dist-info/top_level.txt +3 -0
- scripts/__init__.py +1 -0
- scripts/migrations.py +39 -0
- scripts/seed_worker_queues.py +128 -0
- scripts/setup_agent_runtime.py +142 -0
- worker_internal/__init__.py +1 -0
- worker_internal/planner/__init__.py +1 -0
- worker_internal/planner/activities.py +1499 -0
- worker_internal/planner/agent_tools.py +197 -0
- worker_internal/planner/event_models.py +148 -0
- worker_internal/planner/event_publisher.py +67 -0
- worker_internal/planner/models.py +199 -0
- worker_internal/planner/retry_logic.py +134 -0
- worker_internal/planner/worker.py +300 -0
- worker_internal/planner/workflows.py +970 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Temporal Cloud Provisioning Service
|
|
3
|
+
|
|
4
|
+
This service handles provisioning Temporal Cloud namespaces via the
|
|
5
|
+
Vercel serverless function (api/provision-namespace.go).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import httpx
|
|
10
|
+
import structlog
|
|
11
|
+
from typing import Dict, Any
|
|
12
|
+
|
|
13
|
+
logger = structlog.get_logger()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TemporalCloudProvisioningService:
|
|
17
|
+
"""Service for provisioning Temporal Cloud namespaces"""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
# Get the Vercel function URL from environment
|
|
21
|
+
self.proxy_url = os.getenv("TEMPORAL_CLOUD_PROXY_URL")
|
|
22
|
+
if not self.proxy_url:
|
|
23
|
+
# If not set, use the Vercel production URL
|
|
24
|
+
self.proxy_url = "https://temporal-cloud-proxy.vercel.app/api/provision-namespace"
|
|
25
|
+
|
|
26
|
+
# Get the admin token for authorization (will be checked when actually used)
|
|
27
|
+
self.admin_token = os.getenv("TEMPORAL_CLOUD_ADMIN_TOKEN")
|
|
28
|
+
|
|
29
|
+
async def provision_namespace_for_organization(
|
|
30
|
+
self,
|
|
31
|
+
organization_id: str,
|
|
32
|
+
organization_name: str,
|
|
33
|
+
region: str = "aws-us-east-1",
|
|
34
|
+
retention_days: int = 7,
|
|
35
|
+
) -> Dict[str, Any]:
|
|
36
|
+
"""
|
|
37
|
+
Provision a Temporal Cloud namespace for an organization.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
organization_id: The organization ID
|
|
41
|
+
organization_name: The organization name
|
|
42
|
+
region: The Temporal Cloud region (default: aws-us-east-1)
|
|
43
|
+
retention_days: Number of days to retain workflow history (default: 7)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Dictionary with:
|
|
47
|
+
- success: Boolean indicating if provisioning succeeded
|
|
48
|
+
- namespace_name: The provisioned namespace name
|
|
49
|
+
- namespace: Dictionary with namespace details
|
|
50
|
+
- already_exists: Boolean indicating if namespace already existed
|
|
51
|
+
- error: Error message if failed
|
|
52
|
+
- timeout: Boolean indicating if operation timed out
|
|
53
|
+
"""
|
|
54
|
+
logger.info(
|
|
55
|
+
"provisioning_temporal_namespace",
|
|
56
|
+
organization_id=organization_id,
|
|
57
|
+
organization_name=organization_name,
|
|
58
|
+
region=region,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Check if token is available
|
|
62
|
+
if not self.admin_token:
|
|
63
|
+
error_msg = "TEMPORAL_CLOUD_ADMIN_TOKEN environment variable is required but not set"
|
|
64
|
+
logger.error("temporal_cloud_token_missing", organization_id=organization_id)
|
|
65
|
+
return {
|
|
66
|
+
"success": False,
|
|
67
|
+
"error": error_msg,
|
|
68
|
+
"timeout": False,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
# Prepare the request
|
|
73
|
+
payload = {
|
|
74
|
+
"organization_id": organization_id,
|
|
75
|
+
"organization_name": organization_name,
|
|
76
|
+
"region": region,
|
|
77
|
+
"retention_days": retention_days,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
headers = {
|
|
81
|
+
"Authorization": f"Bearer {self.admin_token}",
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# Call the Vercel function
|
|
86
|
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
|
87
|
+
response = await client.post(
|
|
88
|
+
self.proxy_url,
|
|
89
|
+
json=payload,
|
|
90
|
+
headers=headers,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Check response status
|
|
94
|
+
if response.status_code == 200:
|
|
95
|
+
result = response.json()
|
|
96
|
+
logger.info(
|
|
97
|
+
"namespace_provisioned_successfully",
|
|
98
|
+
organization_id=organization_id,
|
|
99
|
+
namespace_name=result.get("namespace_name"),
|
|
100
|
+
already_exists=result.get("already_exists", False),
|
|
101
|
+
)
|
|
102
|
+
return result
|
|
103
|
+
else:
|
|
104
|
+
error_msg = response.text
|
|
105
|
+
logger.error(
|
|
106
|
+
"namespace_provisioning_failed",
|
|
107
|
+
organization_id=organization_id,
|
|
108
|
+
status_code=response.status_code,
|
|
109
|
+
error=error_msg,
|
|
110
|
+
)
|
|
111
|
+
return {
|
|
112
|
+
"success": False,
|
|
113
|
+
"error": f"HTTP {response.status_code}: {error_msg}",
|
|
114
|
+
"timeout": False,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
except httpx.TimeoutException as e:
|
|
118
|
+
logger.warning(
|
|
119
|
+
"namespace_provisioning_timeout",
|
|
120
|
+
organization_id=organization_id,
|
|
121
|
+
error=str(e),
|
|
122
|
+
)
|
|
123
|
+
return {
|
|
124
|
+
"success": False,
|
|
125
|
+
"error": "Provisioning timed out",
|
|
126
|
+
"timeout": True,
|
|
127
|
+
}
|
|
128
|
+
except Exception as e:
|
|
129
|
+
logger.error(
|
|
130
|
+
"namespace_provisioning_exception",
|
|
131
|
+
organization_id=organization_id,
|
|
132
|
+
error=str(e),
|
|
133
|
+
)
|
|
134
|
+
return {
|
|
135
|
+
"success": False,
|
|
136
|
+
"error": str(e),
|
|
137
|
+
"timeout": False,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Global instance
|
|
142
|
+
_provisioning_service = None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_provisioning_service() -> TemporalCloudProvisioningService:
|
|
146
|
+
"""Get the provisioning service singleton"""
|
|
147
|
+
global _provisioning_service
|
|
148
|
+
if _provisioning_service is None:
|
|
149
|
+
_provisioning_service = TemporalCloudProvisioningService()
|
|
150
|
+
return _provisioning_service
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Context Graph Skill - Memory and Knowledge Graph Tools
|
|
3
|
+
|
|
4
|
+
Provides agents with persistent memory capabilities using async job polling.
|
|
5
|
+
All operations are automatically scoped to environment-specific datasets.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Optional, Dict, Any
|
|
9
|
+
import httpx
|
|
10
|
+
import logging
|
|
11
|
+
import asyncio
|
|
12
|
+
import time
|
|
13
|
+
from agno.tools import Toolkit
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
# Configuration
|
|
18
|
+
MAX_RETRIES = 3
|
|
19
|
+
INITIAL_RETRY_DELAY = 1.0
|
|
20
|
+
MAX_RETRY_DELAY = 10.0
|
|
21
|
+
POLL_INTERVAL = 2.0 # seconds between job status checks
|
|
22
|
+
MAX_POLL_TIME = 300.0 # 5 minutes max wait
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _is_retryable_error(response: httpx.Response | None, exception: Exception | None) -> bool:
|
|
26
|
+
"""Determine if error is retryable (network/5xx) or permanent (4xx)."""
|
|
27
|
+
if exception and isinstance(exception, (httpx.ConnectError, httpx.TimeoutException, httpx.NetworkError)):
|
|
28
|
+
return True
|
|
29
|
+
if response and response.status_code >= 500:
|
|
30
|
+
return True
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
async def _retry_with_backoff(func, max_retries: int = MAX_RETRIES):
|
|
35
|
+
"""Retry with exponential backoff for transient failures only."""
|
|
36
|
+
last_exception = None
|
|
37
|
+
delay = INITIAL_RETRY_DELAY
|
|
38
|
+
|
|
39
|
+
for attempt in range(max_retries):
|
|
40
|
+
try:
|
|
41
|
+
result = await func()
|
|
42
|
+
if isinstance(result, httpx.Response) and not _is_retryable_error(result, None):
|
|
43
|
+
return result
|
|
44
|
+
return result
|
|
45
|
+
except Exception as e:
|
|
46
|
+
last_exception = e
|
|
47
|
+
if not _is_retryable_error(None, e):
|
|
48
|
+
logger.error(f"Non-retryable error", extra={"error": str(e)})
|
|
49
|
+
raise
|
|
50
|
+
if attempt < max_retries - 1:
|
|
51
|
+
logger.warning(f"Retry {attempt + 1}/{max_retries} in {delay}s", extra={"error": str(e)})
|
|
52
|
+
await asyncio.sleep(delay)
|
|
53
|
+
delay = min(delay * 2, MAX_RETRY_DELAY)
|
|
54
|
+
else:
|
|
55
|
+
logger.error(f"All retries failed", extra={"error": str(e)})
|
|
56
|
+
|
|
57
|
+
if last_exception:
|
|
58
|
+
raise last_exception
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ContextGraphSkill(Toolkit):
|
|
62
|
+
"""
|
|
63
|
+
Context graph skill with async job polling and progress indicators.
|
|
64
|
+
|
|
65
|
+
Tools:
|
|
66
|
+
- store_memory: Store information (can wait for completion or return immediately)
|
|
67
|
+
- poll_job_status: Poll job status until complete
|
|
68
|
+
- recall_memory: Search stored memories
|
|
69
|
+
- semantic_search: Search knowledge graph
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(
|
|
73
|
+
self,
|
|
74
|
+
graph_api_url: str,
|
|
75
|
+
api_key: str,
|
|
76
|
+
organization_id: str,
|
|
77
|
+
dataset_name: str,
|
|
78
|
+
auto_create_dataset: bool = True,
|
|
79
|
+
):
|
|
80
|
+
super().__init__(name="context-graph-memory")
|
|
81
|
+
|
|
82
|
+
self.graph_api_url = graph_api_url.rstrip('/')
|
|
83
|
+
self.api_key = api_key
|
|
84
|
+
self.organization_id = organization_id
|
|
85
|
+
self.dataset_name = dataset_name
|
|
86
|
+
self.auto_create_dataset = auto_create_dataset
|
|
87
|
+
self._dataset_id = None
|
|
88
|
+
|
|
89
|
+
self.register(self.store_memory)
|
|
90
|
+
self.register(self.poll_job_status)
|
|
91
|
+
self.register(self.recall_memory)
|
|
92
|
+
self.register(self.semantic_search)
|
|
93
|
+
|
|
94
|
+
logger.info("Initialized ContextGraphSkill", extra={"dataset_name": dataset_name})
|
|
95
|
+
|
|
96
|
+
async def _get_or_create_dataset(self) -> str:
|
|
97
|
+
"""Get or create dataset ID (cached)."""
|
|
98
|
+
if self._dataset_id:
|
|
99
|
+
return self._dataset_id
|
|
100
|
+
|
|
101
|
+
headers = {
|
|
102
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
103
|
+
"X-Organization-ID": self.organization_id,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
|
107
|
+
response = await client.get(
|
|
108
|
+
f"{self.graph_api_url}/api/v1/graph/datasets",
|
|
109
|
+
headers=headers,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if response.status_code == 200:
|
|
113
|
+
response_data = response.json()
|
|
114
|
+
# Handle both list response (old API) and dict response (new API)
|
|
115
|
+
if isinstance(response_data, dict):
|
|
116
|
+
datasets = response_data.get("datasets", [])
|
|
117
|
+
else:
|
|
118
|
+
datasets = response_data
|
|
119
|
+
|
|
120
|
+
for ds in datasets:
|
|
121
|
+
if ds.get("name") == self.dataset_name:
|
|
122
|
+
self._dataset_id = ds["id"]
|
|
123
|
+
return self._dataset_id
|
|
124
|
+
|
|
125
|
+
if self.auto_create_dataset:
|
|
126
|
+
create_response = await client.post(
|
|
127
|
+
f"{self.graph_api_url}/api/v1/graph/datasets",
|
|
128
|
+
headers=headers,
|
|
129
|
+
json={
|
|
130
|
+
"name": self.dataset_name,
|
|
131
|
+
"description": f"Auto-created for: {self.dataset_name}",
|
|
132
|
+
"scope": "org",
|
|
133
|
+
},
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if create_response.status_code in [200, 201]:
|
|
137
|
+
self._dataset_id = create_response.json()["id"]
|
|
138
|
+
return self._dataset_id
|
|
139
|
+
else:
|
|
140
|
+
raise Exception(f"Failed to create dataset: {create_response.status_code}")
|
|
141
|
+
else:
|
|
142
|
+
raise Exception(f"Dataset '{self.dataset_name}' not found")
|
|
143
|
+
|
|
144
|
+
async def _poll_job_status(
|
|
145
|
+
self,
|
|
146
|
+
job_id: str,
|
|
147
|
+
dataset_id: str,
|
|
148
|
+
headers: Dict[str, str],
|
|
149
|
+
) -> tuple[Dict[str, Any], str]:
|
|
150
|
+
"""
|
|
151
|
+
Poll job status until complete, building progress log.
|
|
152
|
+
|
|
153
|
+
Returns (final_job_status, progress_log) or raises exception on timeout/failure.
|
|
154
|
+
"""
|
|
155
|
+
start_time = time.time()
|
|
156
|
+
last_progress = -1
|
|
157
|
+
progress_log = []
|
|
158
|
+
poll_count = 0
|
|
159
|
+
|
|
160
|
+
progress_log.append(f"⏳ Submitting memory job...")
|
|
161
|
+
logger.info("Starting job polling", extra={"job_id": job_id})
|
|
162
|
+
|
|
163
|
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
164
|
+
while True:
|
|
165
|
+
elapsed = time.time() - start_time
|
|
166
|
+
poll_count += 1
|
|
167
|
+
|
|
168
|
+
if elapsed > MAX_POLL_TIME:
|
|
169
|
+
progress_log.append(f"✗ Timeout after {MAX_POLL_TIME}s ({poll_count} polls)")
|
|
170
|
+
raise Exception(f"Job timed out after {MAX_POLL_TIME}s")
|
|
171
|
+
|
|
172
|
+
# Poll job status
|
|
173
|
+
try:
|
|
174
|
+
response = await client.get(
|
|
175
|
+
f"{self.graph_api_url}/api/v1/graph/jobs/{job_id}",
|
|
176
|
+
headers=headers,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
if response.status_code != 200:
|
|
180
|
+
# Fallback to memory/status endpoint
|
|
181
|
+
response = await client.get(
|
|
182
|
+
f"{self.graph_api_url}/api/v1/graph/memory/status/{job_id}",
|
|
183
|
+
headers=headers,
|
|
184
|
+
params={"dataset_id": dataset_id},
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if response.status_code == 200:
|
|
188
|
+
job_status = response.json()
|
|
189
|
+
status = job_status.get("status", "unknown")
|
|
190
|
+
progress = job_status.get("progress", 0)
|
|
191
|
+
|
|
192
|
+
# Log progress changes
|
|
193
|
+
if progress != last_progress and progress > 0:
|
|
194
|
+
progress_log.append(f" ⚙️ Progress: {progress}%")
|
|
195
|
+
last_progress = progress
|
|
196
|
+
elif poll_count == 1:
|
|
197
|
+
progress_log.append(f" 🔄 Job submitted, polling for completion...")
|
|
198
|
+
|
|
199
|
+
# Check completion
|
|
200
|
+
if status == "completed":
|
|
201
|
+
progress_log.append(f"✅ Complete in {elapsed:.1f}s ({poll_count} polls)")
|
|
202
|
+
logger.info("Job completed", extra={"job_id": job_id, "elapsed": elapsed})
|
|
203
|
+
return job_status, "\n".join(progress_log)
|
|
204
|
+
elif status == "failed":
|
|
205
|
+
error = job_status.get("error", "Unknown error")
|
|
206
|
+
progress_log.append(f"✗ Job failed: {error}")
|
|
207
|
+
raise Exception(f"Job failed: {error}")
|
|
208
|
+
|
|
209
|
+
# Log occasional status updates
|
|
210
|
+
if poll_count % 5 == 0:
|
|
211
|
+
progress_log.append(f" ⏱️ Still processing... ({elapsed:.0f}s elapsed)")
|
|
212
|
+
|
|
213
|
+
except httpx.HTTPError as e:
|
|
214
|
+
logger.warning("Poll error", extra={"error": str(e), "poll_count": poll_count})
|
|
215
|
+
if poll_count == 1:
|
|
216
|
+
progress_log.append(f" ⚠️ Connection issue, retrying...")
|
|
217
|
+
|
|
218
|
+
# Wait before next poll
|
|
219
|
+
await asyncio.sleep(POLL_INTERVAL)
|
|
220
|
+
|
|
221
|
+
async def store_memory(
|
|
222
|
+
self,
|
|
223
|
+
context: str,
|
|
224
|
+
wait: bool = True,
|
|
225
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
226
|
+
) -> str:
|
|
227
|
+
"""
|
|
228
|
+
Store context in persistent memory.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
context: Information to remember
|
|
232
|
+
wait: If True, wait for job to complete. If False, return immediately with job_id
|
|
233
|
+
metadata: Optional metadata
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
If wait=True: Success message with memory ID (only after job completes)
|
|
237
|
+
If wait=False: Job ID for manual polling with poll_job_status tool
|
|
238
|
+
"""
|
|
239
|
+
try:
|
|
240
|
+
dataset_id = await self._get_or_create_dataset()
|
|
241
|
+
|
|
242
|
+
headers = {
|
|
243
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
244
|
+
"X-Organization-ID": self.organization_id,
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
context_dict = {"content": context}
|
|
248
|
+
if metadata:
|
|
249
|
+
context_dict["metadata"] = metadata
|
|
250
|
+
|
|
251
|
+
# Submit job (async mode - returns immediately)
|
|
252
|
+
async def _do_store():
|
|
253
|
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
254
|
+
return await client.post(
|
|
255
|
+
f"{self.graph_api_url}/api/v1/graph/memory/store",
|
|
256
|
+
headers=headers,
|
|
257
|
+
json={
|
|
258
|
+
"context": context_dict,
|
|
259
|
+
"dataset_id": dataset_id,
|
|
260
|
+
"metadata": metadata,
|
|
261
|
+
"sync": False, # Async mode
|
|
262
|
+
},
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
response = await _retry_with_backoff(_do_store)
|
|
266
|
+
|
|
267
|
+
if response.status_code != 200:
|
|
268
|
+
error_msg = f"Failed to submit memory job: HTTP {response.status_code}"
|
|
269
|
+
logger.error(error_msg, extra={"response": response.text[:500]})
|
|
270
|
+
return f"✗ Error: {error_msg}"
|
|
271
|
+
|
|
272
|
+
result = response.json()
|
|
273
|
+
job_id = result.get("job_id")
|
|
274
|
+
memory_id = result.get("memory_id", "unknown")
|
|
275
|
+
|
|
276
|
+
if not job_id:
|
|
277
|
+
# Sync response (shouldn't happen with sync=False, but handle it)
|
|
278
|
+
return f"✓ Memory stored. Memory ID: {memory_id}"
|
|
279
|
+
|
|
280
|
+
# If wait=False, return job_id immediately for manual polling
|
|
281
|
+
if not wait:
|
|
282
|
+
return f"⏳ Memory storage job submitted.\n\nJob ID: {job_id}\nMemory ID: {memory_id}\n\n" \
|
|
283
|
+
f"Use poll_job_status(job_id=\"{job_id}\") to check progress."
|
|
284
|
+
|
|
285
|
+
# If wait=True, poll until complete (backend waits for Cognee pipeline)
|
|
286
|
+
try:
|
|
287
|
+
final_status, progress_log = await self._poll_job_status(job_id, dataset_id, headers)
|
|
288
|
+
|
|
289
|
+
logger.info("Memory stored and indexed", extra={"memory_id": memory_id, "job_id": job_id})
|
|
290
|
+
|
|
291
|
+
# Return detailed progress log with final status
|
|
292
|
+
return f"{progress_log}\n\n✅ Memory stored and indexed successfully!\nMemory ID: {memory_id}\n\n" \
|
|
293
|
+
f"The memory is now searchable and can be recalled."
|
|
294
|
+
except Exception as poll_error:
|
|
295
|
+
logger.error("Polling failed", extra={"error": str(poll_error), "job_id": job_id})
|
|
296
|
+
return f"✗ Job submitted (ID: {job_id[:8]}...) but polling failed: {str(poll_error)}\n" \
|
|
297
|
+
f"Use poll_job_status(job_id=\"{job_id}\") to check manually."
|
|
298
|
+
|
|
299
|
+
except Exception as e:
|
|
300
|
+
error_msg = f"Failed to store memory: {str(e)}"
|
|
301
|
+
logger.error(error_msg, extra={"error_type": type(e).__name__})
|
|
302
|
+
return f"✗ Error: {error_msg}"
|
|
303
|
+
|
|
304
|
+
async def poll_job_status(
|
|
305
|
+
self,
|
|
306
|
+
job_id: str,
|
|
307
|
+
) -> str:
|
|
308
|
+
"""
|
|
309
|
+
Poll a memory storage job until complete.
|
|
310
|
+
|
|
311
|
+
Use this after calling store_memory with wait=False to monitor job progress.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
job_id: Job ID returned from store_memory
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
Progress log and final status
|
|
318
|
+
"""
|
|
319
|
+
try:
|
|
320
|
+
dataset_id = await self._get_or_create_dataset()
|
|
321
|
+
|
|
322
|
+
headers = {
|
|
323
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
324
|
+
"X-Organization-ID": self.organization_id,
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
final_status, progress_log = await self._poll_job_status(job_id, dataset_id, headers)
|
|
328
|
+
memory_id = final_status.get("job_metadata", {}).get("memory_id", "unknown")
|
|
329
|
+
|
|
330
|
+
logger.info("Job polling complete", extra={"memory_id": memory_id, "job_id": job_id})
|
|
331
|
+
|
|
332
|
+
return f"{progress_log}\n\n✅ Job completed successfully!\nMemory ID: {memory_id}"
|
|
333
|
+
|
|
334
|
+
except Exception as e:
|
|
335
|
+
error_msg = f"Failed to poll job status: {str(e)}"
|
|
336
|
+
logger.error(error_msg, extra={"error_type": type(e).__name__, "job_id": job_id})
|
|
337
|
+
return f"✗ Error: {error_msg}"
|
|
338
|
+
|
|
339
|
+
async def recall_memory(
|
|
340
|
+
self,
|
|
341
|
+
query: str,
|
|
342
|
+
limit: int = 5,
|
|
343
|
+
) -> str:
|
|
344
|
+
"""Recall memories using semantic search."""
|
|
345
|
+
try:
|
|
346
|
+
dataset_id = await self._get_or_create_dataset()
|
|
347
|
+
|
|
348
|
+
headers = {
|
|
349
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
350
|
+
"X-Organization-ID": self.organization_id,
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async def _do_recall():
|
|
354
|
+
# Increased timeout to 300s for large datasets/slow Cognee queries
|
|
355
|
+
async with httpx.AsyncClient(timeout=300.0) as client:
|
|
356
|
+
return await client.post(
|
|
357
|
+
f"{self.graph_api_url}/api/v1/graph/memory/recall",
|
|
358
|
+
headers=headers,
|
|
359
|
+
json={"query": query, "dataset_id": dataset_id, "limit": limit},
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
response = await _retry_with_backoff(_do_recall)
|
|
363
|
+
|
|
364
|
+
if response.status_code == 200:
|
|
365
|
+
response_data = response.json()
|
|
366
|
+
|
|
367
|
+
# Handle both response formats
|
|
368
|
+
if isinstance(response_data, dict) and 'memories' in response_data:
|
|
369
|
+
results = response_data['memories']
|
|
370
|
+
elif isinstance(response_data, list):
|
|
371
|
+
results = response_data
|
|
372
|
+
else:
|
|
373
|
+
results = []
|
|
374
|
+
|
|
375
|
+
if not results:
|
|
376
|
+
return f"No memories found for: '{query}'"
|
|
377
|
+
|
|
378
|
+
formatted = f"Found {len(results)} memories:\n\n"
|
|
379
|
+
for i, item in enumerate(results, 1):
|
|
380
|
+
content = item.get('content', item.get('text', 'N/A'))
|
|
381
|
+
formatted += f"{i}. {content}\n"
|
|
382
|
+
if item.get('metadata'):
|
|
383
|
+
formatted += f" Metadata: {item['metadata']}\n"
|
|
384
|
+
if item.get('similarity_score'):
|
|
385
|
+
formatted += f" Relevance: {item['similarity_score']:.2f}\n"
|
|
386
|
+
formatted += "\n"
|
|
387
|
+
|
|
388
|
+
return formatted
|
|
389
|
+
else:
|
|
390
|
+
return f"✗ Error: HTTP {response.status_code}"
|
|
391
|
+
|
|
392
|
+
except Exception as e:
|
|
393
|
+
return f"✗ Error: {str(e)}"
|
|
394
|
+
|
|
395
|
+
async def semantic_search(self, query: str, limit: int = 10) -> str:
|
|
396
|
+
"""Perform semantic search across knowledge graph."""
|
|
397
|
+
try:
|
|
398
|
+
dataset_id = await self._get_or_create_dataset()
|
|
399
|
+
|
|
400
|
+
headers = {
|
|
401
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
402
|
+
"X-Organization-ID": self.organization_id,
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async with httpx.AsyncClient(timeout=120.0) as client:
|
|
406
|
+
response = await client.post(
|
|
407
|
+
f"{self.graph_api_url}/api/v1/graph/nodes/search/semantic",
|
|
408
|
+
headers=headers,
|
|
409
|
+
json={"query": query, "filters": {"dataset_ids": [dataset_id]}, "limit": limit},
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
if response.status_code == 200:
|
|
413
|
+
results = response.json()
|
|
414
|
+
if not results:
|
|
415
|
+
return f"No results for: '{query}'"
|
|
416
|
+
|
|
417
|
+
formatted = f"Search results for '{query}':\n\n"
|
|
418
|
+
for i, item in enumerate(results, 1):
|
|
419
|
+
content = item.get('content', item.get('text', 'N/A'))
|
|
420
|
+
formatted += f"{i}. {content}\n"
|
|
421
|
+
if item.get('similarity_score'):
|
|
422
|
+
formatted += f" Relevance: {item['similarity_score']:.2f}\n"
|
|
423
|
+
if item.get('metadata'):
|
|
424
|
+
formatted += f" Metadata: {item['metadata']}\n"
|
|
425
|
+
formatted += "\n"
|
|
426
|
+
|
|
427
|
+
return formatted
|
|
428
|
+
else:
|
|
429
|
+
return f"✗ Error: HTTP {response.status_code}"
|
|
430
|
+
|
|
431
|
+
except Exception as e:
|
|
432
|
+
return f"✗ Error: {str(e)}"
|