apex-core 0.9.0__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 (335) hide show
  1. apex_core/__init__.py +23 -0
  2. apex_core/agents/__init__.py +13 -0
  3. apex_core/agents/agent_config.py +293 -0
  4. apex_core/agents/agent_factory.py +240 -0
  5. apex_core/agents/domain_agent.py +109 -0
  6. apex_core/agents/interaction_logger.py +429 -0
  7. apex_core/agents/llm_factory.py +272 -0
  8. apex_core/agents/swarm_orchestrator.py +419 -0
  9. apex_core/agents/tool_wrapper.py +222 -0
  10. apex_core/config/agents/compute.yaml +72 -0
  11. apex_core/config/agents/containers.yaml +58 -0
  12. apex_core/config/agents/identity.yaml +63 -0
  13. apex_core/config/agents/init.yaml +76 -0
  14. apex_core/config/agents/mlops.yaml +70 -0
  15. apex_core/config/agents/networking.yaml +78 -0
  16. apex_core/config/agents/observability.yaml +59 -0
  17. apex_core/config/agents/platform.yaml +60 -0
  18. apex_core/config/aws_acm.yaml +131 -0
  19. apex_core/config/aws_alb.yaml +663 -0
  20. apex_core/config/aws_apigateway.yaml +361 -0
  21. apex_core/config/aws_cloudformation.yaml +263 -0
  22. apex_core/config/aws_cloudwatch_logs.yaml +239 -0
  23. apex_core/config/aws_ec2.yaml +63 -0
  24. apex_core/config/aws_ecr.yaml +367 -0
  25. apex_core/config/aws_ecs.yaml +701 -0
  26. apex_core/config/aws_ecs_app_workflow.yaml +223 -0
  27. apex_core/config/aws_efs.yaml +219 -0
  28. apex_core/config/aws_iam.yaml +339 -0
  29. apex_core/config/aws_nlb.yaml +318 -0
  30. apex_core/config/aws_operations.yaml +169 -0
  31. apex_core/config/aws_route53.yaml +183 -0
  32. apex_core/config/aws_s3.yaml +271 -0
  33. apex_core/config/aws_secrets_manager.yaml +237 -0
  34. apex_core/config/aws_service_discovery.yaml +200 -0
  35. apex_core/config/aws_sts.yaml +107 -0
  36. apex_core/config/aws_vpc.yaml +860 -0
  37. apex_core/config/aws_vpc_link.yaml +139 -0
  38. apex_core/config/aws_vpc_stack_workflow.yaml +186 -0
  39. apex_core/config/ci_runs.yaml +179 -0
  40. apex_core/config/code_quality.yaml +178 -0
  41. apex_core/config/databricks_operations.yaml +171 -0
  42. apex_core/config/docker_operations.yaml +366 -0
  43. apex_core/config/gcp_artifact_registry.yaml +382 -0
  44. apex_core/config/gcp_bigquery.yaml +186 -0
  45. apex_core/config/gcp_cloud_run.yaml +757 -0
  46. apex_core/config/gcp_cloud_sql.yaml +292 -0
  47. apex_core/config/gcp_firebase.yaml +635 -0
  48. apex_core/config/gcp_iam.yaml +520 -0
  49. apex_core/config/gcp_identity_platform.yaml +163 -0
  50. apex_core/config/gcp_inventory.yaml +141 -0
  51. apex_core/config/gcp_networking.yaml +553 -0
  52. apex_core/config/gcp_observability.yaml +107 -0
  53. apex_core/config/gcp_org_policy.yaml +146 -0
  54. apex_core/config/gcp_project.yaml +316 -0
  55. apex_core/config/gcp_pubsub.yaml +308 -0
  56. apex_core/config/gcp_redis.yaml +172 -0
  57. apex_core/config/gcp_secret_manager.yaml +304 -0
  58. apex_core/config/gcp_storage.yaml +309 -0
  59. apex_core/config/github_repo.yaml +773 -0
  60. apex_core/config/health_check.yaml +147 -0
  61. apex_core/config/iam/README.md +128 -0
  62. apex_core/config/iam/iam-admin-policy.json +293 -0
  63. apex_core/config/mlflow_operations.yaml +348 -0
  64. apex_core/config/penpot.yaml +321 -0
  65. apex_core/config/platform_control.yaml +64 -0
  66. apex_core/config/platform_workflows.yaml +314 -0
  67. apex_core/config/project_setup.yaml +179 -0
  68. apex_core/config/projects.yaml +99 -0
  69. apex_core/config/release_ops.yaml +163 -0
  70. apex_core/config/security.yaml +164 -0
  71. apex_core/config/skills.yaml +98 -0
  72. apex_core/config/templates/config_template.yaml +142 -0
  73. apex_core/config/templates/vpc_with_internet_access.yaml +91 -0
  74. apex_core/config/terraform_operations.yaml +302 -0
  75. apex_core/config/test_runner.yaml +253 -0
  76. apex_core/config/validation.yaml +168 -0
  77. apex_core/config/workflow_engine.yaml +156 -0
  78. apex_core/config/workflow_planning.yaml +91 -0
  79. apex_core/config/workflow_planning_resource_server.yaml +136 -0
  80. apex_core/core/__init__.py +12 -0
  81. apex_core/core/apex_settings.py +701 -0
  82. apex_core/core/capability_digest.py +56 -0
  83. apex_core/core/capability_resolver.py +815 -0
  84. apex_core/core/capability_shadows.py +195 -0
  85. apex_core/core/capability_sync.py +534 -0
  86. apex_core/core/diagnostics.py +49 -0
  87. apex_core/core/dsl_engine.py +630 -0
  88. apex_core/core/dsl_models.py +418 -0
  89. apex_core/core/execution_nodes.py +125 -0
  90. apex_core/core/flow_loader.py +165 -0
  91. apex_core/core/flow_models.py +279 -0
  92. apex_core/core/instance_manager.py +604 -0
  93. apex_core/core/langgraph_compiler.py +1452 -0
  94. apex_core/core/mcp_integration.py +245 -0
  95. apex_core/core/mode_manager.py +483 -0
  96. apex_core/core/operator_abstraction.py +326 -0
  97. apex_core/core/permission_models.py +44 -0
  98. apex_core/core/plan_store.py +187 -0
  99. apex_core/core/platform.py +608 -0
  100. apex_core/core/platform_config.py +292 -0
  101. apex_core/core/platform_models.py +529 -0
  102. apex_core/core/provenance.py +495 -0
  103. apex_core/core/requirements_checker.py +284 -0
  104. apex_core/core/resource_graph.py +258 -0
  105. apex_core/core/response_models.py +176 -0
  106. apex_core/core/review_passes.py +126 -0
  107. apex_core/core/server_factory.py +144 -0
  108. apex_core/core/skills_placement.py +237 -0
  109. apex_core/core/state_lifecycle.py +194 -0
  110. apex_core/core/validators/__init__.py +22 -0
  111. apex_core/core/validators/flow_validator.py +217 -0
  112. apex_core/core/validators/resource_server_validator.py +203 -0
  113. apex_core/core/validators/workflow_validator.py +127 -0
  114. apex_core/core/workflow_config.py +64 -0
  115. apex_core/core/workflow_planning_server.py +249 -0
  116. apex_core/core/workflow_resolver.py +213 -0
  117. apex_core/core/workflow_status.py +263 -0
  118. apex_core/llm/__init__.py +21 -0
  119. apex_core/llm/model_providers.py +451 -0
  120. apex_core/middleware/__init__.py +19 -0
  121. apex_core/middleware/audit_middleware.py +102 -0
  122. apex_core/middleware/execution_mode_middleware.py +47 -0
  123. apex_core/middleware/otel_export.py +335 -0
  124. apex_core/middleware/permission_middleware.py +65 -0
  125. apex_core/middleware/provenance_middleware.py +108 -0
  126. apex_core/middleware/tag_injection_middleware.py +156 -0
  127. apex_core/providers/__init__.py +89 -0
  128. apex_core/providers/aws/__init__.py +73 -0
  129. apex_core/providers/aws/aws_acm.py +156 -0
  130. apex_core/providers/aws/aws_alb.py +576 -0
  131. apex_core/providers/aws/aws_apigateway.py +418 -0
  132. apex_core/providers/aws/aws_base.py +84 -0
  133. apex_core/providers/aws/aws_cloudformation.py +328 -0
  134. apex_core/providers/aws/aws_cloudwatch_logs.py +297 -0
  135. apex_core/providers/aws/aws_ec2.py +110 -0
  136. apex_core/providers/aws/aws_ecr.py +387 -0
  137. apex_core/providers/aws/aws_ecs.py +627 -0
  138. apex_core/providers/aws/aws_efs.py +332 -0
  139. apex_core/providers/aws/aws_iam.py +308 -0
  140. apex_core/providers/aws/aws_nlb.py +338 -0
  141. apex_core/providers/aws/aws_response_models.py +161 -0
  142. apex_core/providers/aws/aws_route53.py +209 -0
  143. apex_core/providers/aws/aws_s3.py +281 -0
  144. apex_core/providers/aws/aws_secrets_manager.py +246 -0
  145. apex_core/providers/aws/aws_service_discovery.py +273 -0
  146. apex_core/providers/aws/aws_sts.py +122 -0
  147. apex_core/providers/aws/aws_vpc.py +1061 -0
  148. apex_core/providers/aws/aws_vpc_link.py +134 -0
  149. apex_core/providers/databricks/__init__.py +5 -0
  150. apex_core/providers/databricks/databricks_resource_server.py +381 -0
  151. apex_core/providers/devtools/__init__.py +22 -0
  152. apex_core/providers/devtools/ci_runs_resource_server.py +446 -0
  153. apex_core/providers/devtools/code_quality_resource_server.py +190 -0
  154. apex_core/providers/devtools/health_check_resource_server.py +203 -0
  155. apex_core/providers/devtools/release_ops_resource_server.py +342 -0
  156. apex_core/providers/devtools/test_runner_resource_server.py +273 -0
  157. apex_core/providers/devtools/validation_resource_server.py +256 -0
  158. apex_core/providers/docker/__init__.py +5 -0
  159. apex_core/providers/docker/docker_resource_server.py +696 -0
  160. apex_core/providers/gcp/__init__.py +80 -0
  161. apex_core/providers/gcp/gcp_artifact_registry.py +703 -0
  162. apex_core/providers/gcp/gcp_base.py +284 -0
  163. apex_core/providers/gcp/gcp_bigquery.py +383 -0
  164. apex_core/providers/gcp/gcp_cloud_run.py +1287 -0
  165. apex_core/providers/gcp/gcp_cloud_sql.py +447 -0
  166. apex_core/providers/gcp/gcp_firebase.py +1363 -0
  167. apex_core/providers/gcp/gcp_iam.py +901 -0
  168. apex_core/providers/gcp/gcp_identity_platform.py +450 -0
  169. apex_core/providers/gcp/gcp_inventory.py +840 -0
  170. apex_core/providers/gcp/gcp_networking.py +1057 -0
  171. apex_core/providers/gcp/gcp_observability.py +197 -0
  172. apex_core/providers/gcp/gcp_org_policy.py +294 -0
  173. apex_core/providers/gcp/gcp_project.py +571 -0
  174. apex_core/providers/gcp/gcp_pubsub.py +368 -0
  175. apex_core/providers/gcp/gcp_redis.py +268 -0
  176. apex_core/providers/gcp/gcp_secret_manager.py +528 -0
  177. apex_core/providers/gcp/gcp_security_validator.py +262 -0
  178. apex_core/providers/gcp/gcp_storage.py +525 -0
  179. apex_core/providers/github/__init__.py +48 -0
  180. apex_core/providers/github/github_base.py +169 -0
  181. apex_core/providers/github/github_repo.py +1356 -0
  182. apex_core/providers/internal/__init__.py +5 -0
  183. apex_core/providers/internal/platform_control.py +269 -0
  184. apex_core/providers/internal/project_setup_resource_server.py +991 -0
  185. apex_core/providers/internal/projects_resource_server.py +389 -0
  186. apex_core/providers/internal/skills_resource_server.py +409 -0
  187. apex_core/providers/internal/templates/aws-data-pipeline/AGENT.md +50 -0
  188. apex_core/providers/internal/templates/aws-data-pipeline/CONSTITUTION.md +25 -0
  189. apex_core/providers/internal/templates/aws-full-stack/AGENT.md +49 -0
  190. apex_core/providers/internal/templates/aws-full-stack/CONSTITUTION.md +25 -0
  191. apex_core/providers/internal/templates/aws-infrastructure/AGENT.md +47 -0
  192. apex_core/providers/internal/templates/aws-infrastructure/CONSTITUTION.md +25 -0
  193. apex_core/providers/internal/templates/aws-microservice/AGENT.md +61 -0
  194. apex_core/providers/internal/templates/aws-microservice/CONSTITUTION.md +25 -0
  195. apex_core/providers/internal/templates/aws-ml-platform/AGENT.md +47 -0
  196. apex_core/providers/internal/templates/aws-ml-platform/CONSTITUTION.md +25 -0
  197. apex_core/providers/internal/templates/common/AGENT.md +29 -0
  198. apex_core/providers/internal/templates/databricks-ml/AGENT.md +44 -0
  199. apex_core/providers/internal/templates/databricks-ml/CONSTITUTION.md +25 -0
  200. apex_core/providers/internal/templates/docker-local/AGENT.md +50 -0
  201. apex_core/providers/internal/templates/docker-local/CONSTITUTION.md +23 -0
  202. apex_core/providers/internal/workflow_engine.py +896 -0
  203. apex_core/providers/internal/workflow_planning_resource_server.py +724 -0
  204. apex_core/providers/mlflow/__init__.py +5 -0
  205. apex_core/providers/mlflow/mlflow_resource_server.py +596 -0
  206. apex_core/providers/penpot/__init__.py +49 -0
  207. apex_core/providers/penpot/penpot_base.py +354 -0
  208. apex_core/providers/penpot/penpot_geometry.py +204 -0
  209. apex_core/providers/penpot/penpot_operations.py +512 -0
  210. apex_core/providers/security/__init__.py +5 -0
  211. apex_core/providers/security/gitleaks.toml +81 -0
  212. apex_core/providers/security/security_scan_resource_server.py +461 -0
  213. apex_core/providers/terraform/__init__.py +5 -0
  214. apex_core/providers/terraform/terraform_resource_server.py +836 -0
  215. apex_core/providers/workflows/__init__.py +38 -0
  216. apex_core/skills/ci/SKILL.md +96 -0
  217. apex_core/skills/ci-triage/SKILL.md +88 -0
  218. apex_core/skills/containers/SKILL.md +152 -0
  219. apex_core/skills/data-quality/SKILL.md +140 -0
  220. apex_core/skills/gcp/SKILL.md +204 -0
  221. apex_core/skills/iac/SKILL.md +139 -0
  222. apex_core/skills/observability/SKILL.md +154 -0
  223. apex_core/skills/security/SKILL.md +130 -0
  224. apex_core/tools/__init__.py +10 -0
  225. apex_core/tools/apex_capabilities.py +280 -0
  226. apex_core/tools/apex_chat.py +219 -0
  227. apex_core/tools/apex_cli.py +511 -0
  228. apex_core/tools/apex_flows.py +162 -0
  229. apex_core/tools/apex_llm_models.py +314 -0
  230. apex_core/tools/apex_mcp_server.py +54 -0
  231. apex_core/tools/apex_plan.py +202 -0
  232. apex_core/tools/apex_state.py +1635 -0
  233. apex_core/tools/apex_ui.py +73 -0
  234. apex_core/tools/apex_validate.py +360 -0
  235. apex_core/tools/apex_workflows.py +294 -0
  236. apex_core/tools/cli_generator_agent.py +335 -0
  237. apex_core/tools/provenance_hooks.py +114 -0
  238. apex_core/tools/resource_mapper.py +1192 -0
  239. apex_core/tools/streamlit/__init__.py +0 -0
  240. apex_core/tools/streamlit/_helpers.py +131 -0
  241. apex_core/tools/streamlit/chat_app.py +114 -0
  242. apex_core/tools/streamlit/dashboard_app.py +165 -0
  243. apex_core/tools/streamlit/portal/__init__.py +1 -0
  244. apex_core/tools/streamlit/portal/audit_store.py +289 -0
  245. apex_core/tools/streamlit/portal/auth.py +154 -0
  246. apex_core/tools/streamlit/portal/catalog_store.py +340 -0
  247. apex_core/tools/streamlit/portal/components/__init__.py +0 -0
  248. apex_core/tools/streamlit/portal/components/execution_runner.py +194 -0
  249. apex_core/tools/streamlit/portal/components/param_form.py +157 -0
  250. apex_core/tools/streamlit/portal/components/workflow_dag.py +108 -0
  251. apex_core/tools/streamlit/portal/db.py +121 -0
  252. apex_core/tools/streamlit/portal/migrations/__init__.py +0 -0
  253. apex_core/tools/streamlit/portal/migrations/alembic.ini +37 -0
  254. apex_core/tools/streamlit/portal/migrations/env.py +63 -0
  255. apex_core/tools/streamlit/portal/migrations/versions/0001_create_executions_table.py +46 -0
  256. apex_core/tools/streamlit/portal/pages/__init__.py +0 -0
  257. apex_core/tools/streamlit/portal/pages/audit.py +122 -0
  258. apex_core/tools/streamlit/portal/pages/author.py +286 -0
  259. apex_core/tools/streamlit/portal/pages/catalog.py +154 -0
  260. apex_core/tools/streamlit/portal/pages/history.py +98 -0
  261. apex_core/tools/streamlit/portal/pages/metrics.py +107 -0
  262. apex_core/tools/streamlit/portal/pages/registry.py +134 -0
  263. apex_core/tools/streamlit/portal/portal_app.py +154 -0
  264. apex_core/tools/toolnode_agent.py +444 -0
  265. apex_core/workflows/apex/apex-release.yml +150 -0
  266. apex_core/workflows/aws/deploy_ecs_service_pipeline.yaml +131 -0
  267. apex_core/workflows/aws/deploy_vpc_stack.yaml +87 -0
  268. apex_core/workflows/aws/full_stack_deployment.yaml +62 -0
  269. apex_core/workflows/ci/deploy-pipeline.yml +118 -0
  270. apex_core/workflows/ci/full-pipeline.yml +108 -0
  271. apex_core/workflows/ci/gcp-deploy-pipeline.yml +156 -0
  272. apex_core/workflows/ci/terraform-deploy-pipeline.yml +73 -0
  273. apex_core/workflows/examples/deploy-test-ui-complete.dev.config.yml +22 -0
  274. apex_core/workflows/examples/deploy-test-ui-complete.prod.config.yml +23 -0
  275. apex_core/workflows/examples/deploy-test-ui-complete.yml +402 -0
  276. apex_core/workflows/examples/internet-facing-alb.yml +268 -0
  277. apex_core/workflows/gcp/apex-ci-setup.yml +138 -0
  278. apex_core/workflows/gcp/artifact-registry-push.yml +68 -0
  279. apex_core/workflows/gcp/cloud-run-deploy-image.yml +184 -0
  280. apex_core/workflows/gcp/cloud-run-deploy.yml +111 -0
  281. apex_core/workflows/gcp/cloud-run-zero-downtime.yml +110 -0
  282. apex_core/workflows/gcp/firebase-hosting-deploy.yml +49 -0
  283. apex_core/workflows/gcp/gcp-admin-bootstrap.yml +89 -0
  284. apex_core/workflows/gcp/gcp-database-setup.yml +145 -0
  285. apex_core/workflows/gcp/gcp-deploy-sa-wif-bind.yml +119 -0
  286. apex_core/workflows/gcp/gcp-firebase-init.yml +78 -0
  287. apex_core/workflows/gcp/gcp-org-bootstrap.yml +125 -0
  288. apex_core/workflows/gcp/gcp-product-env-bootstrap.yml +238 -0
  289. apex_core/workflows/gcp/gcp-project-bootstrap.yml +101 -0
  290. apex_core/workflows/gcp/gcp-secrets-provision.yml +46 -0
  291. apex_core/workflows/gcp/gcp-service-account-setup.yml +61 -0
  292. apex_core/workflows/gcp/gcp-storage-setup.yml +67 -0
  293. apex_core/workflows/gcp/gcp-wif-org-provider.yml +106 -0
  294. apex_core/workflows/gcp/gcp-wif-setup.yml +123 -0
  295. apex_core/workflows/gcp/publish-python-package.yml +100 -0
  296. apex_core/workflows/generated/deployment/deploy-apex-demo-api-deployment.yaml +244 -0
  297. apex_core/workflows/generated/infrastructure/deploy-apex-demo-api-infrastructure.yaml +364 -0
  298. apex_core/workflows/github/design-pr-merge.yml +53 -0
  299. apex_core/workflows/github/github-repo-bootstrap.yml +93 -0
  300. apex_core/workflows/modules/alb-with-target-group.yml +136 -0
  301. apex_core/workflows/modules/ci-quality-gate-python.yml +75 -0
  302. apex_core/workflows/modules/ci-quality-gate-typescript.yml +85 -0
  303. apex_core/workflows/modules/create-networking.yml +95 -0
  304. apex_core/workflows/modules/create-secret.yml +61 -0
  305. apex_core/workflows/modules/deploy-container-registry.yml +75 -0
  306. apex_core/workflows/modules/deploy-container-service.yml +97 -0
  307. apex_core/workflows/modules/deploy-static-site.yml +80 -0
  308. apex_core/workflows/modules/docker-build-and-push.yml +55 -0
  309. apex_core/workflows/modules/ecr-repository.yml +70 -0
  310. apex_core/workflows/modules/ecs-fargate-cluster.yml +45 -0
  311. apex_core/workflows/modules/ecs-service-with-alb.yml +244 -0
  312. apex_core/workflows/modules/health-check-services.yml +49 -0
  313. apex_core/workflows/modules/run-e2e-tests.yml +52 -0
  314. apex_core/workflows/modules/run-linting.yml +51 -0
  315. apex_core/workflows/modules/run-type-check.yml +43 -0
  316. apex_core/workflows/modules/run-unit-tests.yml +55 -0
  317. apex_core/workflows/modules/simple-test.yml +26 -0
  318. apex_core/workflows/modules/sync-secrets-to-gcp.yml +224 -0
  319. apex_core/workflows/modules/terraform-capture-outputs.yml +70 -0
  320. apex_core/workflows/modules/terraform-import-resources.yml +96 -0
  321. apex_core/workflows/modules/terraform-init-plan-apply.yml +48 -0
  322. apex_core/workflows/modules/terraform-validate-only.yml +82 -0
  323. apex_core/workflows/modules/terraform-workspace-deploy.yml +58 -0
  324. apex_core/workflows/modules/validate-deployment.yml +75 -0
  325. apex_core/workflows/modules/validate-infrastructure.yml +66 -0
  326. apex_core/workflows/modules/vpc-with-subnets.yml +158 -0
  327. apex_core/workflows/ops/cleanup_vpc.yml +46 -0
  328. apex_core/workflows/platform/simple_web_stack.yaml +75 -0
  329. apex_core/workflows/platform/vpc_internet_access.yaml +277 -0
  330. apex_core/workflows/platform/web_app_stack.yaml +123 -0
  331. apex_core-0.9.0.dist-info/METADATA +361 -0
  332. apex_core-0.9.0.dist-info/RECORD +335 -0
  333. apex_core-0.9.0.dist-info/WHEEL +4 -0
  334. apex_core-0.9.0.dist-info/entry_points.txt +3 -0
  335. apex_core-0.9.0.dist-info/licenses/LICENSE +124 -0
apex_core/__init__.py ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ APEX Platform - Multi-Cloud Infrastructure Orchestration Library
4
+
5
+ A provider-agnostic platform for orchestrating cloud infrastructure operations
6
+ with state management, execution planning, and conditional workflows.
7
+
8
+ Key Features:
9
+ - Multi-provider support (AWS, Azure, GCP, Kubernetes)
10
+ - State-aware execution with variable interpolation
11
+ - Execution planning with validation and rollback
12
+ - Dynamic class loading from YAML configuration
13
+ - MCP (Model Context Protocol) integration
14
+ """
15
+
16
+ from .core.platform import APEXPlatform
17
+
18
+ __version__ = "1.0.0"
19
+ __author__ = "APEX Platform Team"
20
+
21
+ __all__ = [
22
+ "APEXPlatform"
23
+ ]
@@ -0,0 +1,13 @@
1
+ """
2
+ APEX Platform Agents
3
+
4
+ Config-driven, factory-based multi-domain agent system built on LangGraph Swarm.
5
+
6
+ Architecture:
7
+ SwarmOrchestrator — routes queries to domain agents, manages multi-turn state
8
+ AgentFactory — creates domain agents from YAML config definitions
9
+ AgentConfigLoader — discovers and validates agent YAML configs
10
+ DomainAgent — wraps a compiled LangGraph ReAct agent for one domain
11
+ tool_wrapper — builds middleware-compliant LangChain StructuredTools
12
+ InteractionLogger — logs routing decisions + tool calls to interactions.jsonl
13
+ """
@@ -0,0 +1,293 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Agent configuration models and config context detection.
4
+
5
+ Contains:
6
+ ConfigContext — project vs global context detection
7
+ AgentDomainConfig — Pydantic model for agent YAML configs
8
+ ModelConfig — nested LLM model configuration
9
+ QueryExample — training/test example in agent config
10
+ AgentConfigLoader — discovers and validates agent YAML configs
11
+ AgentConfigError — raised on config validation failures
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import logging
17
+ from dataclasses import dataclass, field
18
+ from pathlib import Path
19
+ from typing import Any, Dict, List, Optional
20
+
21
+ import yaml
22
+ from pydantic import BaseModel, Field, field_validator
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ # ---------------------------------------------------------------------------
28
+ # Config Context
29
+ # ---------------------------------------------------------------------------
30
+
31
+
32
+ @dataclass
33
+ class ConfigContext:
34
+ """Determines which configs/skills/tools are available based on context.
35
+
36
+ Project context: .apex/settings.yaml exists in cwd or a parent directory.
37
+ Global context: no project config found; uses ~/.apex/ defaults.
38
+ """
39
+
40
+ mode: str # "project" | "global"
41
+ project_dir: Optional[Path] # Project root (where .apex/ lives)
42
+ global_dir: Path # Always ~/.apex/
43
+ allowed_skills: Optional[List[str]] = field(default=None) # None = all
44
+ allowed_agents: Optional[List[str]] = field(default=None) # None = all
45
+ skills_repo: Optional[str] = field(default=None)
46
+ projects_repo: Optional[str] = field(default=None)
47
+
48
+ @classmethod
49
+ def detect(cls, cwd: Path = None) -> "ConfigContext":
50
+ """Auto-detect context by walking up from cwd looking for .apex/settings.yaml.
51
+
52
+ Args:
53
+ cwd: Starting directory. Defaults to Path.cwd().
54
+
55
+ Returns:
56
+ ConfigContext with mode="project" if found, else mode="global".
57
+ """
58
+ cwd = cwd or Path.cwd()
59
+ global_dir = Path.home() / ".apex"
60
+
61
+ # Walk up the directory tree looking for .apex/settings.yaml
62
+ current = cwd
63
+ while True:
64
+ candidate = current / ".apex" / "settings.yaml"
65
+ if candidate.exists():
66
+ # Found project context — load project-level overrides
67
+ allowed_skills = None
68
+ allowed_agents = None
69
+ skills_repo = None
70
+ projects_repo = None
71
+
72
+ try:
73
+ with open(candidate) as f:
74
+ data = yaml.safe_load(f) or {}
75
+ agents_cfg = data.get("agents", {})
76
+ skills_cfg = data.get("skills", {})
77
+ allowed_skills = agents_cfg.get("allowed_skills") or skills_cfg.get("allowed_skills")
78
+ allowed_agents = agents_cfg.get("allowed_agents")
79
+ skills_repo = skills_cfg.get("skills_repo")
80
+ projects_repo = skills_cfg.get("projects_repo")
81
+ except Exception as e:
82
+ logger.warning("Failed to read project settings at %s: %s", candidate, e)
83
+
84
+ return cls(
85
+ mode="project",
86
+ project_dir=current,
87
+ global_dir=global_dir,
88
+ allowed_skills=allowed_skills,
89
+ allowed_agents=allowed_agents,
90
+ skills_repo=skills_repo,
91
+ projects_repo=projects_repo,
92
+ )
93
+
94
+ parent = current.parent
95
+ if parent == current:
96
+ break # Reached filesystem root
97
+ current = parent
98
+
99
+ # No project config found — global context
100
+ return cls(
101
+ mode="global",
102
+ project_dir=None,
103
+ global_dir=global_dir,
104
+ )
105
+
106
+ @property
107
+ def settings_path(self) -> Path:
108
+ """Return the active settings.yaml path."""
109
+ if self.project_dir:
110
+ return self.project_dir / ".apex" / "settings.yaml"
111
+ return self.global_dir / "settings.yaml"
112
+
113
+ @property
114
+ def skills_dir(self) -> Path:
115
+ """Return ~/.apex/skills/ directory."""
116
+ return self.global_dir / "skills"
117
+
118
+ @property
119
+ def conversations_db(self) -> Path:
120
+ """Return path to shared conversations database."""
121
+ return self.global_dir / "conversations.db"
122
+
123
+
124
+ # ---------------------------------------------------------------------------
125
+ # Pydantic models for agent YAML configs
126
+ # ---------------------------------------------------------------------------
127
+
128
+
129
+ class QueryExample(BaseModel):
130
+ """A single training/test example embedded in the agent config."""
131
+
132
+ query: str = Field(description="Natural language user query")
133
+ tool: str = Field(description="Expected tool name (e.g., 'create_vpc')")
134
+ server: str = Field(description="Expected server name (e.g., 'aws_vpc')")
135
+ parameters: Dict[str, Any] = Field(default_factory=dict, description="Expected tool parameters")
136
+
137
+
138
+ class AgentDomainConfig(BaseModel):
139
+ """Configuration for a domain agent, loaded from YAML.
140
+
141
+ One YAML file per domain in config/agents/*.yaml.
142
+ """
143
+
144
+ name: str = Field(description="Unique domain identifier (e.g., 'infrastructure')")
145
+ description: str = Field(description="Domain description — used for FAISS domain search")
146
+ skill: Optional[str] = Field(default=None, description="SKILL.md name reference")
147
+ memory_mode: str = Field(default="persistent", description="'persistent' or 'stateless'")
148
+ resource_servers: List[str] = Field(description="ResourceServer names (e.g., ['aws_vpc', 'aws_subnet'])")
149
+ handoff_targets: List[str] = Field(default_factory=list, description="Sibling domain names for routing")
150
+ routing_keywords: List[str] = Field(default_factory=list, description="Keywords for fast-path routing")
151
+ system_prompt: Optional[str] = Field(default=None, description="Custom system prompt (overrides skill)")
152
+ examples: List[QueryExample] = Field(default_factory=list, description="Baseline training/test examples")
153
+
154
+ @field_validator("memory_mode")
155
+ @classmethod
156
+ def validate_memory_mode(cls, v: str) -> str:
157
+ allowed = {"persistent", "stateless"}
158
+ if v not in allowed:
159
+ raise ValueError(f"memory_mode must be one of {allowed}, got '{v}'")
160
+ return v
161
+
162
+ @field_validator("resource_servers")
163
+ @classmethod
164
+ def validate_resource_servers_not_empty(cls, v: List[str]) -> List[str]:
165
+ if not v:
166
+ raise ValueError("resource_servers must contain at least one server name")
167
+ return v
168
+
169
+
170
+ # ---------------------------------------------------------------------------
171
+ # Config loading error
172
+ # ---------------------------------------------------------------------------
173
+
174
+
175
+ class AgentConfigError(Exception):
176
+ """Raised when agent config is invalid or cannot be loaded."""
177
+
178
+
179
+ # ---------------------------------------------------------------------------
180
+ # AgentConfigLoader
181
+ # ---------------------------------------------------------------------------
182
+
183
+
184
+ class AgentConfigLoader:
185
+ """Discovers and validates agent domain configs from YAML files.
186
+
187
+ Loads all YAML files from config_dir matching *.yaml and parses them
188
+ into AgentDomainConfig instances.
189
+ """
190
+
191
+ def __init__(self, config_dir: Path = None):
192
+ """
193
+ Args:
194
+ config_dir: Path to agents config directory.
195
+ Default: auto-discovers config/agents/ relative to this file.
196
+ """
197
+ if config_dir is None:
198
+ # Auto-discover: walk up from this file to find config/agents/
199
+ pkg_root = Path(__file__).parent.parent.parent.parent # src/../.. = repo root
200
+ config_dir = pkg_root / "config" / "agents"
201
+
202
+ self.config_dir = config_dir
203
+
204
+ def load_all(self) -> Dict[str, AgentDomainConfig]:
205
+ """Load all agent configs from config_dir.
206
+
207
+ Returns:
208
+ Dict mapping domain name to validated AgentDomainConfig.
209
+
210
+ Raises:
211
+ AgentConfigError: If any config file is invalid.
212
+ """
213
+ if not self.config_dir.exists():
214
+ logger.warning("Agent config directory not found: %s", self.config_dir)
215
+ return {}
216
+
217
+ configs: Dict[str, AgentDomainConfig] = {}
218
+
219
+ for yaml_file in sorted(self.config_dir.glob("*.yaml")):
220
+ try:
221
+ config = self._load_file(yaml_file)
222
+ configs[config.name] = config
223
+ logger.debug("Loaded agent config: %s from %s", config.name, yaml_file.name)
224
+ except Exception as e:
225
+ raise AgentConfigError(
226
+ f"Failed to load agent config from {yaml_file.name}: {e}"
227
+ ) from e
228
+
229
+ logger.info("Loaded %d agent configs from %s", len(configs), self.config_dir)
230
+ return configs
231
+
232
+ def load_one(self, name: str) -> AgentDomainConfig:
233
+ """Load a single agent config by domain name.
234
+
235
+ Args:
236
+ name: Domain name (matches the 'name' field in YAML, not filename).
237
+
238
+ Raises:
239
+ AgentConfigError: If the config is not found or invalid.
240
+ """
241
+ yaml_file = self.config_dir / f"{name}.yaml"
242
+ if not yaml_file.exists():
243
+ raise AgentConfigError(f"Agent config not found: {yaml_file}")
244
+ return self._load_file(yaml_file)
245
+
246
+ def _load_file(self, path: Path) -> AgentDomainConfig:
247
+ """Parse a single YAML file into AgentDomainConfig."""
248
+ with open(path) as f:
249
+ data = yaml.safe_load(f) or {}
250
+ try:
251
+ return AgentDomainConfig(**data)
252
+ except Exception as e:
253
+ raise AgentConfigError(f"Invalid config in {path.name}: {e}") from e
254
+
255
+ def validate(
256
+ self,
257
+ config: AgentDomainConfig,
258
+ all_configs: Dict[str, AgentDomainConfig],
259
+ known_servers: Optional[List[str]] = None,
260
+ ) -> List[str]:
261
+ """Validate config against known servers and sibling configs.
262
+
263
+ Args:
264
+ config: Config to validate.
265
+ all_configs: All other configs (for handoff target validation).
266
+ known_servers: List of known ResourceServer names from platform.
267
+ If None, server validation is skipped.
268
+
269
+ Returns:
270
+ List of validation error messages (empty if valid).
271
+ """
272
+ errors: List[str] = []
273
+
274
+ # Validate resource_servers against known platform servers
275
+ if known_servers is not None:
276
+ for server in config.resource_servers:
277
+ if server not in known_servers:
278
+ errors.append(
279
+ f"resource_server '{server}' not found in platform. "
280
+ f"Available: {known_servers}"
281
+ )
282
+
283
+ # Validate handoff_targets reference real agent configs
284
+ for target in config.handoff_targets:
285
+ if target == config.name:
286
+ errors.append(f"handoff_target '{target}' cannot reference itself")
287
+ elif target not in all_configs:
288
+ errors.append(
289
+ f"handoff_target '{target}' not found in loaded agent configs. "
290
+ f"Available: {list(all_configs.keys())}"
291
+ )
292
+
293
+ return errors
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ AgentFactory — creates DomainAgent instances from AgentDomainConfig.
4
+
5
+ One factory per platform session. Receives the platform instance and a single
6
+ shared LLM (from llm_factory.resolve_llm). All domain agents share the same
7
+ LLM — model choice is a user-level concern, not per-agent.
8
+
9
+ Persistent agents share one AsyncSqliteSaver at ~/.apex/conversations.db,
10
+ with thread isolation via domain-prefixed thread IDs.
11
+ Stateless agents get no checkpointer — fresh context each session.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import logging
17
+ from pathlib import Path
18
+ from typing import TYPE_CHECKING, Dict, Optional
19
+
20
+ from langgraph.prebuilt import create_react_agent
21
+
22
+ from apex_core.agents.agent_config import AgentDomainConfig
23
+ from apex_core.agents.domain_agent import DomainAgent
24
+ from apex_core.agents.tool_wrapper import build_domain_tools
25
+
26
+ if TYPE_CHECKING:
27
+ from langchain_core.language_models import BaseChatModel
28
+ from apex_core.core.platform import APEXPlatform
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+ _GENERIC_SYSTEM_PROMPT = """You are an APEX Platform domain agent for the {domain} domain.
33
+
34
+ You help users manage {description}.
35
+
36
+ Available tools cover: {servers}.
37
+
38
+ Guidelines:
39
+ - Always confirm intent before executing destructive operations
40
+ - Default to dry-run (plan) mode unless user explicitly requests apply/execute
41
+ - Be concise and precise — infrastructure tasks need accuracy
42
+ - If a request is outside your domain, say so clearly
43
+ """
44
+
45
+
46
+ class AgentFactory:
47
+ """Creates DomainAgent instances from YAML config definitions.
48
+
49
+ Args:
50
+ platform: Initialized APEXPlatform with resource servers loaded.
51
+ llm: Shared LangChain chat model (from llm_factory.resolve_llm()).
52
+ checkpointer: Optional pre-initialized AsyncSqliteSaver.
53
+ If None, created lazily at ~/.apex/conversations.db
54
+ when the first persistent agent is requested.
55
+ """
56
+
57
+ def __init__(
58
+ self,
59
+ platform: "APEXPlatform",
60
+ llm: "BaseChatModel",
61
+ checkpointer=None,
62
+ ):
63
+ self.platform = platform
64
+ self.llm = llm
65
+ self._checkpointer = checkpointer # shared, lazily initialized
66
+
67
+ # ------------------------------------------------------------------
68
+ # Public API
69
+ # ------------------------------------------------------------------
70
+
71
+ async def create_agent(self, config: AgentDomainConfig) -> DomainAgent:
72
+ """Create a single domain agent from config.
73
+
74
+ Steps:
75
+ 1. Build middleware-compliant tool wrappers for all resource servers
76
+ 2. Load SKILL.md content (if configured)
77
+ 3. Build system prompt
78
+ 4. Create LangGraph ReAct agent with checkpointer
79
+ 5. Return DomainAgent wrapper
80
+
81
+ Raises:
82
+ AgentConfigError: If required resource servers are missing.
83
+ """
84
+ # 1. Build tools — validates server availability
85
+ tools = build_domain_tools(config, self.platform)
86
+ if not tools:
87
+ logger.warning(
88
+ "Agent '%s' has no tools — resource servers %s may not be loaded",
89
+ config.name,
90
+ config.resource_servers,
91
+ )
92
+
93
+ # 2. Load skill content
94
+ skill_content = self._load_skill_content(config.skill)
95
+
96
+ # 3. Build system prompt
97
+ system_prompt = self._build_system_prompt(config, skill_content)
98
+
99
+ # 4. Get checkpointer (shared for persistent, None for stateless)
100
+ checkpointer = await self._get_checkpointer(config)
101
+
102
+ # 5. Create LangGraph ReAct agent
103
+ graph = create_react_agent(
104
+ model=self.llm,
105
+ tools=tools,
106
+ state_modifier=system_prompt,
107
+ checkpointer=checkpointer,
108
+ )
109
+
110
+ logger.info(
111
+ "Created domain agent '%s': %d tools, memory=%s, skill=%s",
112
+ config.name,
113
+ len(tools),
114
+ config.memory_mode,
115
+ config.skill or "none",
116
+ )
117
+
118
+ return DomainAgent(
119
+ config=config,
120
+ compiled_agent=graph,
121
+ tools=tools,
122
+ skill_prompt=skill_content or system_prompt,
123
+ active=True,
124
+ checkpointer=checkpointer,
125
+ )
126
+
127
+ async def create_all(
128
+ self, configs: Dict[str, AgentDomainConfig]
129
+ ) -> Dict[str, DomainAgent]:
130
+ """Create all domain agents from configs.
131
+
132
+ Persistent agents are early-loaded at startup.
133
+ Stateless agents are created but marked inactive — they'll be
134
+ re-created per session when needed (lazy loading).
135
+
136
+ Returns:
137
+ Dict mapping domain name → DomainAgent.
138
+ """
139
+ agents: Dict[str, DomainAgent] = {}
140
+
141
+ for name, config in configs.items():
142
+ try:
143
+ agent = await self.create_agent(config)
144
+ agents[name] = agent
145
+ logger.info("Loaded agent: %s (%s)", name, config.memory_mode)
146
+ except Exception as e:
147
+ logger.error("Failed to create agent '%s': %s", name, e)
148
+ # Continue loading other agents — partial startup is better than full failure
149
+
150
+ logger.info("AgentFactory: loaded %d/%d agents", len(agents), len(configs))
151
+ return agents
152
+
153
+ # ------------------------------------------------------------------
154
+ # Internal helpers
155
+ # ------------------------------------------------------------------
156
+
157
+ def _build_system_prompt(
158
+ self, config: AgentDomainConfig, skill_content: Optional[str]
159
+ ) -> str:
160
+ """Build the system prompt for a domain agent.
161
+
162
+ Priority:
163
+ 1. config.system_prompt (explicit YAML override)
164
+ 2. SKILL.md content (if skill configured and file exists)
165
+ 3. Generic domain prompt template
166
+ """
167
+ if config.system_prompt:
168
+ return config.system_prompt
169
+
170
+ if skill_content:
171
+ return (
172
+ f"You are an APEX Platform domain agent for the {config.name} domain.\n\n"
173
+ f"Domain expertise (from SKILL.md):\n{skill_content}\n\n"
174
+ f"Available resource servers: {', '.join(config.resource_servers)}"
175
+ )
176
+
177
+ return _GENERIC_SYSTEM_PROMPT.format(
178
+ domain=config.name,
179
+ description=config.description,
180
+ servers=", ".join(config.resource_servers),
181
+ )
182
+
183
+ def _load_skill_content(self, skill_name: Optional[str]) -> Optional[str]:
184
+ """Load SKILL.md content from ~/.apex/skills/{skill_name}/SKILL.md.
185
+
186
+ Returns None if skill is not configured or file is missing.
187
+ Logs a warning if configured but missing (user should install it).
188
+ """
189
+ if not skill_name:
190
+ return None
191
+
192
+ skill_path = Path.home() / ".apex" / "skills" / skill_name / "SKILL.md"
193
+ if skill_path.exists():
194
+ try:
195
+ content = skill_path.read_text(encoding="utf-8")
196
+ logger.info("Loaded SKILL.md for '%s' from %s", skill_name, skill_path)
197
+ return content
198
+ except Exception as e:
199
+ logger.warning("Failed to read SKILL.md at %s: %s", skill_path, e)
200
+ return None
201
+
202
+ logger.warning(
203
+ "SKILL.md not found for skill '%s' at %s. "
204
+ "Install with: apex skills install %s",
205
+ skill_name,
206
+ skill_path,
207
+ skill_name,
208
+ )
209
+ return None
210
+
211
+ async def _get_checkpointer(self, config: AgentDomainConfig):
212
+ """Return the shared checkpointer for persistent agents, None for stateless.
213
+
214
+ All persistent agents share one AsyncSqliteSaver at ~/.apex/conversations.db.
215
+ Conversation isolation is via thread_id = "{domain}_{session_id}".
216
+ """
217
+ if config.memory_mode != "persistent":
218
+ return None
219
+
220
+ if self._checkpointer is None:
221
+ self._checkpointer = await self._init_checkpointer()
222
+
223
+ return self._checkpointer
224
+
225
+ async def _init_checkpointer(self):
226
+ """Initialize shared AsyncSqliteSaver at ~/.apex/conversations.db."""
227
+ try:
228
+ from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
229
+
230
+ db_path = Path.home() / ".apex" / "conversations.db"
231
+ db_path.parent.mkdir(parents=True, exist_ok=True)
232
+
233
+ checkpointer = AsyncSqliteSaver.from_conn_string(str(db_path))
234
+ logger.info("Initialized shared checkpointer at %s", db_path)
235
+ return checkpointer
236
+
237
+ except Exception as e:
238
+ logger.error("Failed to initialize checkpointer: %s", e)
239
+ logger.warning("Persistent agents will run without memory this session")
240
+ return None
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ DomainAgent — wraps a compiled LangGraph ReAct agent for a single domain.
4
+
5
+ Each domain agent:
6
+ - Owns a scoped set of tools (only its resource servers' tools)
7
+ - Has persistent or stateless memory (via SqliteSaver checkpointer)
8
+ - Uses domain-prefixed thread IDs for conversation isolation:
9
+ thread_id = "{domain}_{session_id}"
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import logging
15
+ from dataclasses import dataclass, field
16
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
17
+
18
+ from langchain_core.messages import HumanMessage
19
+
20
+ if TYPE_CHECKING:
21
+ from langchain_core.tools import StructuredTool
22
+ from langgraph.graph.state import CompiledStateGraph
23
+
24
+ from apex_core.agents.agent_config import AgentDomainConfig
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ @dataclass
30
+ class DomainAgent:
31
+ """Runtime wrapper for a compiled LangGraph ReAct agent serving one domain.
32
+
33
+ Created by AgentFactory. Not persisted — rebuilt from config at startup.
34
+ """
35
+
36
+ config: "AgentDomainConfig"
37
+ compiled_agent: "CompiledStateGraph"
38
+ tools: List["StructuredTool"]
39
+ skill_prompt: str
40
+ active: bool = True
41
+ checkpointer: Optional[Any] = field(default=None, repr=False)
42
+
43
+ @property
44
+ def name(self) -> str:
45
+ return self.config.name
46
+
47
+ @property
48
+ def description(self) -> str:
49
+ return self.config.description
50
+
51
+ @property
52
+ def memory_mode(self) -> str:
53
+ return self.config.memory_mode
54
+
55
+ @property
56
+ def is_persistent(self) -> bool:
57
+ return self.config.memory_mode == "persistent"
58
+
59
+ def thread_id(self, session_id: str) -> str:
60
+ """Construct domain-scoped thread ID for checkpoint isolation.
61
+
62
+ All conversations with this domain agent under the same session
63
+ share one checkpoint thread, keeping conversation context across turns.
64
+ """
65
+ return f"{self.name}_{session_id}"
66
+
67
+ async def invoke(self, user_input: str, session_id: str) -> str:
68
+ """Process a single user message and return the agent's response.
69
+
70
+ Args:
71
+ user_input: Natural language query from the user.
72
+ session_id: Session identifier for multi-turn memory.
73
+
74
+ Returns:
75
+ Agent response as a plain string.
76
+ """
77
+ config = {"configurable": {"thread_id": self.thread_id(session_id)}}
78
+
79
+ try:
80
+ result = await self.compiled_agent.ainvoke(
81
+ {"messages": [HumanMessage(content=user_input)]},
82
+ config=config,
83
+ )
84
+ # Extract last AI message content
85
+ messages = result.get("messages", [])
86
+ if messages:
87
+ last = messages[-1]
88
+ content = last.content if hasattr(last, "content") else str(last)
89
+ return content if isinstance(content, str) else str(content)
90
+ return "No response from agent."
91
+
92
+ except Exception as e:
93
+ logger.error("DomainAgent '%s' invocation failed: %s", self.name, e)
94
+ return f"Error: {e}"
95
+
96
+ def get_info(self) -> Dict[str, Any]:
97
+ """Return agent metadata for display / info commands."""
98
+ return {
99
+ "name": self.name,
100
+ "description": self.description,
101
+ "memory_mode": self.memory_mode,
102
+ "resource_servers": self.config.resource_servers,
103
+ "tool_count": len(self.tools),
104
+ "tool_names": [t.name for t in self.tools],
105
+ "routing_keywords": self.config.routing_keywords,
106
+ "handoff_targets": self.config.handoff_targets,
107
+ "skill": self.config.skill,
108
+ "active": self.active,
109
+ }