praisonai-code 0.0.1__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 (309) hide show
  1. praisonai_code/__init__.py +17 -0
  2. praisonai_code/cli/__init__.py +12 -0
  3. praisonai_code/cli/_forward_shim.py +10 -0
  4. praisonai_code/cli/_paths.py +88 -0
  5. praisonai_code/cli/_warnings.py +58 -0
  6. praisonai_code/cli/app.py +757 -0
  7. praisonai_code/cli/approval_backend.py +272 -0
  8. praisonai_code/cli/branding.py +94 -0
  9. praisonai_code/cli/commands/__init__.py +114 -0
  10. praisonai_code/cli/commands/acp.py +80 -0
  11. praisonai_code/cli/commands/agent.py +116 -0
  12. praisonai_code/cli/commands/agents.py +80 -0
  13. praisonai_code/cli/commands/app.py +139 -0
  14. praisonai_code/cli/commands/attach.py +95 -0
  15. praisonai_code/cli/commands/audit.py +102 -0
  16. praisonai_code/cli/commands/auth.py +508 -0
  17. praisonai_code/cli/commands/batch.py +848 -0
  18. praisonai_code/cli/commands/benchmark.py +286 -0
  19. praisonai_code/cli/commands/browser.py +299 -0
  20. praisonai_code/cli/commands/call.py +45 -0
  21. praisonai_code/cli/commands/chat.py +332 -0
  22. praisonai_code/cli/commands/checkpoint.py +170 -0
  23. praisonai_code/cli/commands/code.py +276 -0
  24. praisonai_code/cli/commands/command.py +114 -0
  25. praisonai_code/cli/commands/commit.py +47 -0
  26. praisonai_code/cli/commands/completion.py +333 -0
  27. praisonai_code/cli/commands/config.py +681 -0
  28. praisonai_code/cli/commands/context.py +414 -0
  29. praisonai_code/cli/commands/daemon.py +203 -0
  30. praisonai_code/cli/commands/debug.py +142 -0
  31. praisonai_code/cli/commands/deploy.py +71 -0
  32. praisonai_code/cli/commands/diag.py +55 -0
  33. praisonai_code/cli/commands/docs.py +1575 -0
  34. praisonai_code/cli/commands/doctor.py +332 -0
  35. praisonai_code/cli/commands/endpoints.py +51 -0
  36. praisonai_code/cli/commands/environment.py +179 -0
  37. praisonai_code/cli/commands/eval.py +131 -0
  38. praisonai_code/cli/commands/examples.py +953 -0
  39. praisonai_code/cli/commands/flow.py +436 -0
  40. praisonai_code/cli/commands/github.py +752 -0
  41. praisonai_code/cli/commands/hooks.py +74 -0
  42. praisonai_code/cli/commands/init.py +174 -0
  43. praisonai_code/cli/commands/knowledge.py +440 -0
  44. praisonai_code/cli/commands/langextract.py +120 -0
  45. praisonai_code/cli/commands/langfuse.py +984 -0
  46. praisonai_code/cli/commands/loop.py +211 -0
  47. praisonai_code/cli/commands/lsp.py +112 -0
  48. praisonai_code/cli/commands/managed.py +659 -0
  49. praisonai_code/cli/commands/mcp.py +763 -0
  50. praisonai_code/cli/commands/memory.py +298 -0
  51. praisonai_code/cli/commands/models.py +264 -0
  52. praisonai_code/cli/commands/n8n.py +326 -0
  53. praisonai_code/cli/commands/obs.py +19 -0
  54. praisonai_code/cli/commands/package.py +76 -0
  55. praisonai_code/cli/commands/paths.py +106 -0
  56. praisonai_code/cli/commands/permissions.py +272 -0
  57. praisonai_code/cli/commands/plugins.py +609 -0
  58. praisonai_code/cli/commands/port.py +530 -0
  59. praisonai_code/cli/commands/profile.py +466 -0
  60. praisonai_code/cli/commands/publish.py +193 -0
  61. praisonai_code/cli/commands/rag.py +913 -0
  62. praisonai_code/cli/commands/realtime.py +52 -0
  63. praisonai_code/cli/commands/recipe.py +684 -0
  64. praisonai_code/cli/commands/registry.py +59 -0
  65. praisonai_code/cli/commands/replay.py +830 -0
  66. praisonai_code/cli/commands/research.py +49 -0
  67. praisonai_code/cli/commands/retrieval.py +377 -0
  68. praisonai_code/cli/commands/rules.py +71 -0
  69. praisonai_code/cli/commands/run.py +1573 -0
  70. praisonai_code/cli/commands/sandbox.py +371 -0
  71. praisonai_code/cli/commands/schedule.py +529 -0
  72. praisonai_code/cli/commands/serve.py +690 -0
  73. praisonai_code/cli/commands/session.py +450 -0
  74. praisonai_code/cli/commands/setup.py +174 -0
  75. praisonai_code/cli/commands/skills.py +545 -0
  76. praisonai_code/cli/commands/standardise.py +711 -0
  77. praisonai_code/cli/commands/templates.py +54 -0
  78. praisonai_code/cli/commands/test.py +558 -0
  79. praisonai_code/cli/commands/todo.py +74 -0
  80. praisonai_code/cli/commands/tools.py +205 -0
  81. praisonai_code/cli/commands/traces.py +145 -0
  82. praisonai_code/cli/commands/tracker.py +852 -0
  83. praisonai_code/cli/commands/train.py +613 -0
  84. praisonai_code/cli/commands/ui.py +172 -0
  85. praisonai_code/cli/commands/up.py +354 -0
  86. praisonai_code/cli/commands/validate.py +291 -0
  87. praisonai_code/cli/commands/version.py +101 -0
  88. praisonai_code/cli/commands/workflow.py +97 -0
  89. praisonai_code/cli/config_loader.py +437 -0
  90. praisonai_code/cli/configuration/__init__.py +27 -0
  91. praisonai_code/cli/configuration/config.schema.json +57 -0
  92. praisonai_code/cli/configuration/credentials.py +446 -0
  93. praisonai_code/cli/configuration/loader.py +364 -0
  94. praisonai_code/cli/configuration/model_resolver.py +161 -0
  95. praisonai_code/cli/configuration/oauth.py +389 -0
  96. praisonai_code/cli/configuration/paths.py +224 -0
  97. praisonai_code/cli/configuration/resolver.py +687 -0
  98. praisonai_code/cli/configuration/schema.py +317 -0
  99. praisonai_code/cli/execution/__init__.py +99 -0
  100. praisonai_code/cli/execution/core.py +208 -0
  101. praisonai_code/cli/execution/profiler.py +898 -0
  102. praisonai_code/cli/execution/request.py +85 -0
  103. praisonai_code/cli/execution/result.py +74 -0
  104. praisonai_code/cli/fallback_schema.py +416 -0
  105. praisonai_code/cli/features/__init__.py +278 -0
  106. praisonai_code/cli/features/_endpoint_registry.py +64 -0
  107. praisonai_code/cli/features/_search_registry.py +43 -0
  108. praisonai_code/cli/features/acp.py +236 -0
  109. praisonai_code/cli/features/action_orchestrator.py +576 -0
  110. praisonai_code/cli/features/agent_scheduler.py +773 -0
  111. praisonai_code/cli/features/agent_tools.py +603 -0
  112. praisonai_code/cli/features/agents.py +397 -0
  113. praisonai_code/cli/features/at_mentions.py +471 -0
  114. praisonai_code/cli/features/audit_cli.py +270 -0
  115. praisonai_code/cli/features/auto_memory.py +182 -0
  116. praisonai_code/cli/features/auto_mode.py +552 -0
  117. praisonai_code/cli/features/autonomy_mode.py +546 -0
  118. praisonai_code/cli/features/background.py +356 -0
  119. praisonai_code/cli/features/base.py +168 -0
  120. praisonai_code/cli/features/benchmark.py +1462 -0
  121. praisonai_code/cli/features/capabilities.py +1326 -0
  122. praisonai_code/cli/features/checkpoints.py +345 -0
  123. praisonai_code/cli/features/cli_profiler.py +335 -0
  124. praisonai_code/cli/features/code_intelligence.py +666 -0
  125. praisonai_code/cli/features/compaction.py +294 -0
  126. praisonai_code/cli/features/compare.py +534 -0
  127. praisonai_code/cli/features/config_hierarchy.py +366 -0
  128. praisonai_code/cli/features/context_manager.py +597 -0
  129. praisonai_code/cli/features/cost_tracker.py +514 -0
  130. praisonai_code/cli/features/csv_test_runner.py +736 -0
  131. praisonai_code/cli/features/custom_definitions.py +790 -0
  132. praisonai_code/cli/features/debug.py +810 -0
  133. praisonai_code/cli/features/deploy.py +605 -0
  134. praisonai_code/cli/features/diag.py +289 -0
  135. praisonai_code/cli/features/display_jsonl.py +173 -0
  136. praisonai_code/cli/features/doctor/__init__.py +63 -0
  137. praisonai_code/cli/features/doctor/checks/__init__.py +29 -0
  138. praisonai_code/cli/features/doctor/checks/acp_checks.py +220 -0
  139. praisonai_code/cli/features/doctor/checks/bot_checks.py +340 -0
  140. praisonai_code/cli/features/doctor/checks/config_checks.py +373 -0
  141. praisonai_code/cli/features/doctor/checks/db_checks.py +366 -0
  142. praisonai_code/cli/features/doctor/checks/env_checks.py +637 -0
  143. praisonai_code/cli/features/doctor/checks/gateway_checks.py +387 -0
  144. praisonai_code/cli/features/doctor/checks/lsp_checks.py +231 -0
  145. praisonai_code/cli/features/doctor/checks/mcp_checks.py +367 -0
  146. praisonai_code/cli/features/doctor/checks/memory_checks.py +268 -0
  147. praisonai_code/cli/features/doctor/checks/network_checks.py +251 -0
  148. praisonai_code/cli/features/doctor/checks/obs_checks.py +328 -0
  149. praisonai_code/cli/features/doctor/checks/packaging_checks.py +422 -0
  150. praisonai_code/cli/features/doctor/checks/performance_checks.py +235 -0
  151. praisonai_code/cli/features/doctor/checks/permissions_checks.py +259 -0
  152. praisonai_code/cli/features/doctor/checks/runtime_checks.py +650 -0
  153. praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +220 -0
  154. praisonai_code/cli/features/doctor/checks/selftest_checks.py +322 -0
  155. praisonai_code/cli/features/doctor/checks/serve_checks.py +426 -0
  156. praisonai_code/cli/features/doctor/checks/skills_checks.py +327 -0
  157. praisonai_code/cli/features/doctor/checks/tools_checks.py +371 -0
  158. praisonai_code/cli/features/doctor/engine.py +266 -0
  159. praisonai_code/cli/features/doctor/formatters.py +377 -0
  160. praisonai_code/cli/features/doctor/handler.py +564 -0
  161. praisonai_code/cli/features/doctor/models.py +276 -0
  162. praisonai_code/cli/features/doctor/registry.py +239 -0
  163. praisonai_code/cli/features/endpoints.py +1016 -0
  164. praisonai_code/cli/features/eval.py +559 -0
  165. praisonai_code/cli/features/examples.py +707 -0
  166. praisonai_code/cli/features/external_agents.py +231 -0
  167. praisonai_code/cli/features/fast_context.py +410 -0
  168. praisonai_code/cli/features/file_history.py +320 -0
  169. praisonai_code/cli/features/flow_display.py +566 -0
  170. praisonai_code/cli/features/git_attribution.py +159 -0
  171. praisonai_code/cli/features/git_integration.py +651 -0
  172. praisonai_code/cli/features/guardrail.py +171 -0
  173. praisonai_code/cli/features/handoff.py +252 -0
  174. praisonai_code/cli/features/hooks.py +583 -0
  175. praisonai_code/cli/features/hybrid_workflow.py +391 -0
  176. praisonai_code/cli/features/image.py +384 -0
  177. praisonai_code/cli/features/interactive_core_headless.py +450 -0
  178. praisonai_code/cli/features/interactive_runtime.py +600 -0
  179. praisonai_code/cli/features/interactive_test_harness.py +537 -0
  180. praisonai_code/cli/features/interactive_tools.py +428 -0
  181. praisonai_code/cli/features/interactive_tui.py +603 -0
  182. praisonai_code/cli/features/job_workflow.py +906 -0
  183. praisonai_code/cli/features/jobs.py +632 -0
  184. praisonai_code/cli/features/knowledge.py +531 -0
  185. praisonai_code/cli/features/knowledge_cli.py +438 -0
  186. praisonai_code/cli/features/lite.py +244 -0
  187. praisonai_code/cli/features/logs.py +200 -0
  188. praisonai_code/cli/features/lsp_cli.py +225 -0
  189. praisonai_code/cli/features/lsp_diagnostics.py +185 -0
  190. praisonai_code/cli/features/mcp.py +344 -0
  191. praisonai_code/cli/features/message_queue.py +587 -0
  192. praisonai_code/cli/features/metrics.py +210 -0
  193. praisonai_code/cli/features/migrate.py +1329 -0
  194. praisonai_code/cli/features/migration_flow.py +463 -0
  195. praisonai_code/cli/features/migration_spec.py +276 -0
  196. praisonai_code/cli/features/n8n.py +703 -0
  197. praisonai_code/cli/features/observability.py +293 -0
  198. praisonai_code/cli/features/ollama.py +361 -0
  199. praisonai_code/cli/features/output_modes.py +155 -0
  200. praisonai_code/cli/features/output_style.py +273 -0
  201. praisonai_code/cli/features/package.py +631 -0
  202. praisonai_code/cli/features/performance.py +308 -0
  203. praisonai_code/cli/features/persistence.py +636 -0
  204. praisonai_code/cli/features/profiler/__init__.py +81 -0
  205. praisonai_code/cli/features/profiler/core.py +558 -0
  206. praisonai_code/cli/features/profiler/optimizations.py +652 -0
  207. praisonai_code/cli/features/profiler/suite.py +386 -0
  208. praisonai_code/cli/features/queue/__init__.py +73 -0
  209. praisonai_code/cli/features/queue/manager.py +435 -0
  210. praisonai_code/cli/features/queue/models.py +289 -0
  211. praisonai_code/cli/features/queue/persistence.py +564 -0
  212. praisonai_code/cli/features/queue/scheduler.py +529 -0
  213. praisonai_code/cli/features/queue/worker.py +400 -0
  214. praisonai_code/cli/features/recipe.py +2187 -0
  215. praisonai_code/cli/features/recipe_creator.py +996 -0
  216. praisonai_code/cli/features/recipe_optimizer.py +1364 -0
  217. praisonai_code/cli/features/recipe_prompts.py +226 -0
  218. praisonai_code/cli/features/registry.py +229 -0
  219. praisonai_code/cli/features/repo_map.py +860 -0
  220. praisonai_code/cli/features/router.py +466 -0
  221. praisonai_code/cli/features/safe_shell.py +427 -0
  222. praisonai_code/cli/features/sandbox_cli.py +283 -0
  223. praisonai_code/cli/features/sandbox_executor.py +536 -0
  224. praisonai_code/cli/features/sdk_knowledge.py +500 -0
  225. praisonai_code/cli/features/session.py +222 -0
  226. praisonai_code/cli/features/session_checkpoints.py +208 -0
  227. praisonai_code/cli/features/setup/__init__.py +9 -0
  228. praisonai_code/cli/features/setup/handler.py +355 -0
  229. praisonai_code/cli/features/setup/templates.py +62 -0
  230. praisonai_code/cli/features/skills.py +940 -0
  231. praisonai_code/cli/features/slash_commands.py +692 -0
  232. praisonai_code/cli/features/telemetry.py +179 -0
  233. praisonai_code/cli/features/templates.py +1390 -0
  234. praisonai_code/cli/features/thinking.py +343 -0
  235. praisonai_code/cli/features/todo.py +334 -0
  236. praisonai_code/cli/features/tools.py +680 -0
  237. praisonai_code/cli/features/tui/__init__.py +83 -0
  238. praisonai_code/cli/features/tui/app.py +871 -0
  239. praisonai_code/cli/features/tui/cli.py +580 -0
  240. praisonai_code/cli/features/tui/config.py +150 -0
  241. praisonai_code/cli/features/tui/debug.py +526 -0
  242. praisonai_code/cli/features/tui/events.py +99 -0
  243. praisonai_code/cli/features/tui/mock_provider.py +328 -0
  244. praisonai_code/cli/features/tui/orchestrator.py +652 -0
  245. praisonai_code/cli/features/tui/screens/__init__.py +50 -0
  246. praisonai_code/cli/features/tui/screens/help.py +157 -0
  247. praisonai_code/cli/features/tui/screens/main.py +568 -0
  248. praisonai_code/cli/features/tui/screens/queue.py +174 -0
  249. praisonai_code/cli/features/tui/screens/session.py +124 -0
  250. praisonai_code/cli/features/tui/screens/settings.py +148 -0
  251. praisonai_code/cli/features/tui/session_store.py +198 -0
  252. praisonai_code/cli/features/tui/widgets/__init__.py +56 -0
  253. praisonai_code/cli/features/tui/widgets/chat.py +263 -0
  254. praisonai_code/cli/features/tui/widgets/command_popup.py +258 -0
  255. praisonai_code/cli/features/tui/widgets/composer.py +292 -0
  256. praisonai_code/cli/features/tui/widgets/file_popup.py +207 -0
  257. praisonai_code/cli/features/tui/widgets/queue_panel.py +223 -0
  258. praisonai_code/cli/features/tui/widgets/status.py +181 -0
  259. praisonai_code/cli/features/tui/widgets/tool_panel.py +307 -0
  260. praisonai_code/cli/features/wizard.py +289 -0
  261. praisonai_code/cli/features/workflow.py +802 -0
  262. praisonai_code/cli/features/yaml_utils.py +321 -0
  263. praisonai_code/cli/interactive/__init__.py +48 -0
  264. praisonai_code/cli/interactive/async_tui.py +1218 -0
  265. praisonai_code/cli/interactive/config.py +139 -0
  266. praisonai_code/cli/interactive/core.py +618 -0
  267. praisonai_code/cli/interactive/events.py +131 -0
  268. praisonai_code/cli/interactive/frontends/__init__.py +31 -0
  269. praisonai_code/cli/interactive/frontends/rich_frontend.py +462 -0
  270. praisonai_code/cli/interactive/frontends/textual_frontend.py +157 -0
  271. praisonai_code/cli/interactive/praison_io.py +502 -0
  272. praisonai_code/cli/interactive/repl.py +297 -0
  273. praisonai_code/cli/interactive/split_tui.py +456 -0
  274. praisonai_code/cli/interactive/tui_app.py +457 -0
  275. praisonai_code/cli/langfuse_client.py +360 -0
  276. praisonai_code/cli/main.py +7421 -0
  277. praisonai_code/cli/output/__init__.py +25 -0
  278. praisonai_code/cli/output/console.py +456 -0
  279. praisonai_code/cli/output/event_bridge.py +191 -0
  280. praisonai_code/cli/schedule_cli.py +54 -0
  281. praisonai_code/cli/schema_provider.py +23 -0
  282. praisonai_code/cli/session/__init__.py +16 -0
  283. praisonai_code/cli/session/resume.py +148 -0
  284. praisonai_code/cli/session/unified.py +548 -0
  285. praisonai_code/cli/state/__init__.py +31 -0
  286. praisonai_code/cli/state/identifiers.py +161 -0
  287. praisonai_code/cli/state/project_sessions.py +383 -0
  288. praisonai_code/cli/state/sessions.py +390 -0
  289. praisonai_code/cli/ui/__init__.py +160 -0
  290. praisonai_code/cli/ui/config.py +46 -0
  291. praisonai_code/cli/ui/events.py +61 -0
  292. praisonai_code/cli/ui/mg_backend.py +342 -0
  293. praisonai_code/cli/ui/plain.py +133 -0
  294. praisonai_code/cli/ui/rich_backend.py +162 -0
  295. praisonai_code/cli/unified_schema.py +655 -0
  296. praisonai_code/cli/utils/env_utils.py +126 -0
  297. praisonai_code/cli/utils/project.py +131 -0
  298. praisonai_code/cli_backends/__init__.py +73 -0
  299. praisonai_code/cli_backends/claude.py +373 -0
  300. praisonai_code/cli_backends/registry.py +113 -0
  301. praisonai_code/runtime/__init__.py +36 -0
  302. praisonai_code/runtime/__main__.py +81 -0
  303. praisonai_code/runtime/client.py +131 -0
  304. praisonai_code/runtime/descriptor.py +209 -0
  305. praisonai_code/runtime/server.py +356 -0
  306. praisonai_code-0.0.1.dist-info/METADATA +80 -0
  307. praisonai_code-0.0.1.dist-info/RECORD +309 -0
  308. praisonai_code-0.0.1.dist-info/WHEEL +5 -0
  309. praisonai_code-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,650 @@
1
+ """
2
+ Runtime compatibility checks for multi-agent setups.
3
+
4
+ Provides preflight validation for team YAML configurations to detect
5
+ runtime conflicts, missing capabilities, and handoff compatibility issues.
6
+ """
7
+
8
+ import yaml
9
+ import os
10
+ from typing import Any, Dict, List, Optional, Set, Iterator
11
+ from dataclasses import dataclass
12
+
13
+ from ..models import CheckResult, CheckStatus, CheckCategory, CheckSeverity
14
+ from ..registry import CheckRegistry
15
+
16
+
17
+ @dataclass
18
+ class RuntimeCapability:
19
+ """Represents a runtime capability requirement."""
20
+ name: str
21
+ description: str
22
+ required: bool = True
23
+
24
+
25
+ @dataclass
26
+ class RuntimeInfo:
27
+ """Information about a specific runtime."""
28
+ id: str
29
+ name: str
30
+ available: bool
31
+ capabilities: List[RuntimeCapability]
32
+ supports_handoff: bool = False
33
+ supports_tool_loop: bool = False
34
+
35
+
36
+ @dataclass
37
+ class AgentRuntimeConfig:
38
+ """Runtime configuration for a specific agent."""
39
+ role_name: str
40
+ runtime_id: Optional[str]
41
+ resolved_runtime: Optional[str]
42
+ capabilities_needed: Set[str]
43
+ handoff_targets: List[str]
44
+ has_tools: bool
45
+
46
+
47
+ class RuntimeCompatibilityChecker:
48
+ """Checks runtime compatibility for multi-agent setups."""
49
+
50
+ def __init__(self):
51
+ self.known_runtimes = self._get_known_runtimes()
52
+
53
+ def _get_known_runtimes(self) -> Dict[str, RuntimeInfo]:
54
+ """Get information about known runtimes."""
55
+ runtimes = {}
56
+
57
+ # Check framework availability using the same pattern as agents_generator
58
+ try:
59
+ from praisonai._framework_availability import is_available
60
+ except ImportError:
61
+ is_available = lambda x: False
62
+
63
+ # Adapter-aware availability: a runtime is only "usable" if its adapter
64
+ # is both installed AND implemented/registered. This keeps `doctor` in
65
+ # sync with the registry-backed `--framework` choices so it never
66
+ # reports a runtime as available when the matching framework cannot run
67
+ # (e.g. unimplemented AutoGen v0.4 / AG2 entry-point placeholders).
68
+ def _runtime_usable(framework_name: str, package_name: str) -> bool:
69
+ try:
70
+ from praisonai.framework_adapters.registry import get_default_registry
71
+ except ImportError:
72
+ # Fallback to raw package probe only when the registry module
73
+ # itself cannot be imported (e.g. partial install).
74
+ return is_available(package_name)
75
+
76
+ registry = get_default_registry()
77
+ # When the registry is the source of truth, an unregistered
78
+ # framework is not runnable even if its packages are installed,
79
+ # so doctor stays consistent with the `--framework` choices.
80
+ if framework_name not in registry.list_names():
81
+ return False
82
+ return registry.is_available(framework_name)
83
+
84
+ # PraisonAI Agents runtime
85
+ runtimes['praisonai'] = RuntimeInfo(
86
+ id='praisonai',
87
+ name='PraisonAI Agents',
88
+ available=is_available('praisonaiagents'),
89
+ capabilities=[
90
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
91
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
92
+ RuntimeCapability('handoff_support', 'Agent-to-agent handoffs'),
93
+ RuntimeCapability('context_sharing', 'Share conversation context'),
94
+ RuntimeCapability('cli_backend', 'CLI backend integration'),
95
+ ],
96
+ supports_handoff=True,
97
+ supports_tool_loop=True
98
+ )
99
+
100
+ # CrewAI runtime
101
+ runtimes['crewai'] = RuntimeInfo(
102
+ id='crewai',
103
+ name='CrewAI',
104
+ available=is_available('crewai'),
105
+ capabilities=[
106
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
107
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
108
+ RuntimeCapability('sequential_execution', 'Sequential task execution'),
109
+ RuntimeCapability('hierarchical_execution', 'Hierarchical task execution'),
110
+ ],
111
+ supports_handoff=False,
112
+ supports_tool_loop=True
113
+ )
114
+
115
+ # AutoGen v0.2 runtime
116
+ runtimes['autogen'] = RuntimeInfo(
117
+ id='autogen',
118
+ name='AutoGen v0.2',
119
+ available=is_available('autogen'),
120
+ capabilities=[
121
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
122
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
123
+ RuntimeCapability('group_chat', 'Multi-agent conversations'),
124
+ ],
125
+ supports_handoff=False,
126
+ supports_tool_loop=True
127
+ )
128
+
129
+ # AutoGen v0.4 runtime (optional entry-point adapter)
130
+ runtimes['autogen_v4'] = RuntimeInfo(
131
+ id='autogen_v4',
132
+ name='AutoGen v0.4',
133
+ available=_runtime_usable('autogen_v4', 'autogen_v4'),
134
+ capabilities=[
135
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
136
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
137
+ RuntimeCapability('handoff_support', 'Agent-to-agent handoffs', required=False),
138
+ ],
139
+ supports_handoff=True,
140
+ supports_tool_loop=True
141
+ )
142
+
143
+ # AG2 runtime (optional entry-point adapter)
144
+ runtimes['ag2'] = RuntimeInfo(
145
+ id='ag2',
146
+ name='AG2 (AutoGen Next)',
147
+ available=_runtime_usable('ag2', 'ag2'),
148
+ capabilities=[
149
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
150
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
151
+ ],
152
+ supports_handoff=False,
153
+ supports_tool_loop=True
154
+ )
155
+
156
+ runtimes['langgraph'] = RuntimeInfo(
157
+ id='langgraph',
158
+ name='LangGraph',
159
+ available=_runtime_usable('langgraph', 'langgraph'),
160
+ capabilities=[
161
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
162
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
163
+ RuntimeCapability('sequential_execution', 'Sequential task execution'),
164
+ ],
165
+ supports_handoff=False,
166
+ supports_tool_loop=True
167
+ )
168
+
169
+ runtimes['openai_agents'] = RuntimeInfo(
170
+ id='openai_agents',
171
+ name='OpenAI Agents SDK',
172
+ available=_runtime_usable('openai_agents', 'openai_agents'),
173
+ capabilities=[
174
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
175
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
176
+ RuntimeCapability('handoff_support', 'Agent-to-agent handoffs', required=False),
177
+ ],
178
+ supports_handoff=True,
179
+ supports_tool_loop=True
180
+ )
181
+
182
+ runtimes['agno'] = RuntimeInfo(
183
+ id='agno',
184
+ name='Agno',
185
+ available=_runtime_usable('agno', 'agno'),
186
+ capabilities=[
187
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
188
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
189
+ RuntimeCapability('sequential_execution', 'Sequential task execution'),
190
+ RuntimeCapability('handoff_support', 'Agent-to-agent handoffs via Team route', required=False),
191
+ ],
192
+ supports_handoff=True,
193
+ supports_tool_loop=True
194
+ )
195
+
196
+ runtimes['google_adk'] = RuntimeInfo(
197
+ id='google_adk',
198
+ name='Google ADK',
199
+ available=_runtime_usable('google_adk', 'google_adk'),
200
+ capabilities=[
201
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
202
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
203
+ RuntimeCapability('sequential_execution', 'Sequential task execution'),
204
+ RuntimeCapability('handoff_support', 'Agent-to-agent handoffs via sub_agents', required=False),
205
+ ],
206
+ supports_handoff=True,
207
+ supports_tool_loop=True
208
+ )
209
+
210
+ runtimes['pydantic_ai'] = RuntimeInfo(
211
+ id='pydantic_ai',
212
+ name='Pydantic AI',
213
+ available=_runtime_usable('pydantic_ai', 'pydantic_ai'),
214
+ capabilities=[
215
+ RuntimeCapability('agent_creation', 'Create and manage agents'),
216
+ RuntimeCapability('tool_execution', 'Execute tools and functions'),
217
+ RuntimeCapability('sequential_execution', 'Sequential task execution'),
218
+ RuntimeCapability('handoff_support', 'Agent-to-agent handoffs via delegation tools', required=False),
219
+ ],
220
+ supports_handoff=True,
221
+ supports_tool_loop=True
222
+ )
223
+
224
+ return runtimes
225
+
226
+ def _check_autogen_v4(self) -> bool:
227
+ """Check if AutoGen v0.4+ packages are installed."""
228
+ try:
229
+ from praisonai._framework_availability import is_available as fw_available
230
+ return fw_available('autogen_v4')
231
+ except ImportError:
232
+ return False
233
+
234
+ def _parse_yaml_config(self, yaml_path: str) -> Dict[str, Any]:
235
+ """Parse team YAML configuration."""
236
+ try:
237
+ with open(yaml_path, 'r') as f:
238
+ return yaml.safe_load(f)
239
+ except Exception as e:
240
+ raise ValueError(f"Failed to parse YAML file: {e}")
241
+
242
+ def _extract_agent_configs(self, config: Dict[str, Any]) -> List[AgentRuntimeConfig]:
243
+ """Extract agent runtime configurations from YAML."""
244
+ agents = []
245
+
246
+ # Handle both 'roles' (canonical) and 'agents' (legacy) sections
247
+ entities = {}
248
+ entities.update(config.get('roles', {}))
249
+ entities.update(config.get('agents', {}))
250
+
251
+ for role_name, role_config in entities.items():
252
+ if not isinstance(role_config, dict):
253
+ continue
254
+
255
+ # Extract runtime information
256
+ runtime_id = role_config.get('runtime')
257
+ capabilities_needed = set()
258
+ handoff_targets = []
259
+ has_tools = bool(role_config.get('tools', []))
260
+
261
+ # Check for handoff configuration
262
+ handoff_config = role_config.get('handoff', {})
263
+ if handoff_config:
264
+ if isinstance(handoff_config, dict):
265
+ raw_targets = handoff_config.get('to', [])
266
+ if isinstance(raw_targets, str):
267
+ handoff_targets = [raw_targets]
268
+ elif isinstance(raw_targets, list):
269
+ handoff_targets = raw_targets
270
+ else:
271
+ handoff_targets = []
272
+ elif isinstance(handoff_config, str):
273
+ handoff_targets = [handoff_config]
274
+ elif isinstance(handoff_config, list):
275
+ handoff_targets = handoff_config
276
+
277
+ if handoff_targets:
278
+ capabilities_needed.add('handoff_support')
279
+
280
+ # Check for CLI backend usage
281
+ if role_config.get('cli_backend'):
282
+ capabilities_needed.add('cli_backend')
283
+
284
+ # Check for tool requirements
285
+ if has_tools:
286
+ capabilities_needed.add('tool_execution')
287
+
288
+ # Resolve runtime using framework selection logic
289
+ resolved_runtime = self._resolve_runtime_for_agent(
290
+ config, runtime_id, role_config
291
+ )
292
+
293
+ agents.append(AgentRuntimeConfig(
294
+ role_name=role_name,
295
+ runtime_id=runtime_id,
296
+ resolved_runtime=resolved_runtime,
297
+ capabilities_needed=capabilities_needed,
298
+ handoff_targets=handoff_targets,
299
+ has_tools=has_tools
300
+ ))
301
+
302
+ return agents
303
+
304
+ def _resolve_runtime_for_agent(self, config: Dict[str, Any],
305
+ agent_runtime: Optional[str],
306
+ agent_config: Dict[str, Any]) -> str:
307
+ """Resolve the actual runtime that will be used for an agent."""
308
+ # Agent-level runtime takes priority
309
+ if agent_runtime:
310
+ return agent_runtime
311
+
312
+ # Fall back to global framework
313
+ framework = config.get('framework', 'praisonai')
314
+
315
+ # Handle AutoGen version selection logic
316
+ if framework == 'autogen':
317
+ autogen_version = str(
318
+ config.get('autogen_version', os.environ.get('AUTOGEN_VERSION', 'auto'))
319
+ ).lower()
320
+
321
+ autogen_v4_runtime = self.known_runtimes.get('autogen_v4')
322
+ autogen_runtime = self.known_runtimes.get('autogen')
323
+
324
+ if autogen_version == 'v0.4' and autogen_v4_runtime and autogen_v4_runtime.available:
325
+ return 'autogen_v4'
326
+ elif autogen_version == 'v0.2' and autogen_runtime and autogen_runtime.available:
327
+ return 'autogen'
328
+ elif autogen_version == 'auto':
329
+ if autogen_v4_runtime and autogen_v4_runtime.available:
330
+ return 'autogen_v4'
331
+ elif autogen_runtime and autogen_runtime.available:
332
+ return 'autogen'
333
+
334
+ return framework
335
+
336
+ def validate_team_yaml(self, yaml_path: str) -> Iterator[CheckResult]:
337
+ """Validate a team YAML file for runtime compatibility."""
338
+ try:
339
+ config = self._parse_yaml_config(yaml_path)
340
+ except Exception as e:
341
+ yield CheckResult(
342
+ id="runtime.yaml_parse",
343
+ title="YAML Parsing",
344
+ category=CheckCategory.CONFIG,
345
+ status=CheckStatus.ERROR,
346
+ message=f"Failed to parse YAML: {e}",
347
+ severity=CheckSeverity.CRITICAL
348
+ )
349
+ return
350
+
351
+ # Extract agent configurations
352
+ try:
353
+ agents = self._extract_agent_configs(config)
354
+ except Exception as e:
355
+ yield CheckResult(
356
+ id="runtime.config_extract",
357
+ title="Configuration Extraction",
358
+ category=CheckCategory.CONFIG,
359
+ status=CheckStatus.ERROR,
360
+ message=f"Failed to extract agent configs: {e}",
361
+ severity=CheckSeverity.HIGH
362
+ )
363
+ return
364
+
365
+ if not agents:
366
+ yield CheckResult(
367
+ id="runtime.no_agents",
368
+ title="Agent Presence",
369
+ category=CheckCategory.CONFIG,
370
+ status=CheckStatus.WARN,
371
+ message="No agents found in configuration",
372
+ severity=CheckSeverity.LOW
373
+ )
374
+ return
375
+
376
+ # Validate each agent's runtime
377
+ yield from self._validate_agent_runtimes(agents)
378
+
379
+ # Validate cross-agent compatibility
380
+ yield from self._validate_handoff_compatibility(agents)
381
+
382
+ # Validate mixed-runtime scenarios
383
+ yield from self._validate_mixed_runtime_setup(agents)
384
+
385
+ def _validate_agent_runtimes(self, agents: List[AgentRuntimeConfig]) -> Iterator[CheckResult]:
386
+ """Validate individual agent runtime configurations."""
387
+ for agent in agents:
388
+ runtime_info = self.known_runtimes.get(agent.resolved_runtime)
389
+
390
+ if not runtime_info:
391
+ yield CheckResult(
392
+ id=f"runtime.unknown_runtime.{agent.role_name}",
393
+ title=f"Unknown Runtime ({agent.role_name})",
394
+ category=CheckCategory.CONFIG,
395
+ status=CheckStatus.FAIL,
396
+ message=f"Unknown runtime '{agent.resolved_runtime}' for agent '{agent.role_name}'",
397
+ details=f"Known runtimes: {', '.join(self.known_runtimes.keys())}",
398
+ severity=CheckSeverity.HIGH
399
+ )
400
+ continue
401
+
402
+ if not runtime_info.available:
403
+ yield CheckResult(
404
+ id=f"runtime.unavailable.{agent.role_name}",
405
+ title=f"Runtime Unavailable ({agent.role_name})",
406
+ category=CheckCategory.ENVIRONMENT,
407
+ status=CheckStatus.FAIL,
408
+ message=f"Runtime '{runtime_info.name}' is not available for agent '{agent.role_name}'",
409
+ details="Install required packages or check dependencies",
410
+ remediation=f"Install packages for {runtime_info.name}",
411
+ severity=CheckSeverity.HIGH
412
+ )
413
+ continue
414
+
415
+ # Check capability requirements
416
+ runtime_capabilities = {cap.name for cap in runtime_info.capabilities}
417
+ missing_capabilities = agent.capabilities_needed - runtime_capabilities
418
+
419
+ if missing_capabilities:
420
+ yield CheckResult(
421
+ id=f"runtime.missing_capabilities.{agent.role_name}",
422
+ title=f"Missing Capabilities ({agent.role_name})",
423
+ category=CheckCategory.CONFIG,
424
+ status=CheckStatus.FAIL,
425
+ message=f"Runtime '{runtime_info.name}' missing required capabilities: {', '.join(missing_capabilities)}",
426
+ details=f"Agent '{agent.role_name}' requires: {', '.join(agent.capabilities_needed)}",
427
+ remediation="Use a compatible runtime or remove unsupported features",
428
+ severity=CheckSeverity.HIGH
429
+ )
430
+
431
+ def _validate_handoff_compatibility(self, agents: List[AgentRuntimeConfig]) -> Iterator[CheckResult]:
432
+ """Validate handoff compatibility between agents."""
433
+ agent_map = {agent.role_name: agent for agent in agents}
434
+
435
+ for agent in agents:
436
+ if not agent.handoff_targets:
437
+ continue
438
+
439
+ runtime_info = self.known_runtimes.get(agent.resolved_runtime)
440
+ if not runtime_info or not runtime_info.supports_handoff:
441
+ yield CheckResult(
442
+ id=f"runtime.handoff_unsupported.{agent.role_name}",
443
+ title=f"Handoff Unsupported ({agent.role_name})",
444
+ category=CheckCategory.CONFIG,
445
+ status=CheckStatus.FAIL,
446
+ message=f"Agent '{agent.role_name}' configured for handoffs but runtime '{runtime_info.name if runtime_info else agent.resolved_runtime}' doesn't support handoffs",
447
+ details=f"Handoff targets: {', '.join(agent.handoff_targets)}",
448
+ remediation="Use praisonai, autogen_v4, or openai_agents framework for handoff support",
449
+ severity=CheckSeverity.HIGH
450
+ )
451
+ continue
452
+
453
+ # Check if handoff targets exist and are compatible
454
+ for target in agent.handoff_targets:
455
+ target_agent = agent_map.get(target)
456
+ if not target_agent:
457
+ yield CheckResult(
458
+ id=f"runtime.handoff_target_missing.{agent.role_name}",
459
+ title=f"Handoff Target Missing ({agent.role_name})",
460
+ category=CheckCategory.CONFIG,
461
+ status=CheckStatus.FAIL,
462
+ message=f"Agent '{agent.role_name}' has handoff target '{target}' that doesn't exist",
463
+ severity=CheckSeverity.HIGH
464
+ )
465
+ continue
466
+
467
+ target_runtime_info = self.known_runtimes.get(target_agent.resolved_runtime)
468
+ if target_runtime_info and not target_runtime_info.supports_tool_loop:
469
+ yield CheckResult(
470
+ id=f"runtime.handoff_target_incompatible.{agent.role_name}",
471
+ title=f"Handoff Target Incompatible ({agent.role_name})",
472
+ category=CheckCategory.CONFIG,
473
+ status=CheckStatus.WARN,
474
+ message=f"Handoff target '{target}' uses runtime that may not support tool loops",
475
+ details=f"Target runtime: {target_runtime_info.name}",
476
+ severity=CheckSeverity.MEDIUM
477
+ )
478
+
479
+ def _validate_mixed_runtime_setup(self, agents: List[AgentRuntimeConfig]) -> Iterator[CheckResult]:
480
+ """Validate mixed-runtime scenario compatibility."""
481
+ runtimes_used = {agent.resolved_runtime for agent in agents}
482
+
483
+ if len(runtimes_used) <= 1:
484
+ return # Single runtime setup, no mixed-runtime issues
485
+
486
+ yield CheckResult(
487
+ id="runtime.mixed_runtimes",
488
+ title="Mixed Runtime Setup",
489
+ category=CheckCategory.CONFIG,
490
+ status=CheckStatus.WARN,
491
+ message=f"Multiple runtimes detected: {', '.join(runtimes_used)}",
492
+ details="Mixed runtimes may have compatibility issues",
493
+ remediation="Consider using a single runtime for consistency",
494
+ severity=CheckSeverity.MEDIUM
495
+ )
496
+
497
+ # Check for specific problematic combinations
498
+ handoff_agents = [a for a in agents if a.handoff_targets]
499
+ if handoff_agents:
500
+ handoff_runtimes = {a.resolved_runtime for a in handoff_agents}
501
+ incompatible_handoff_runtimes = handoff_runtimes - {
502
+ 'praisonai',
503
+ 'autogen_v4',
504
+ 'openai_agents',
505
+ 'agno',
506
+ 'google_adk',
507
+ 'pydantic_ai',
508
+ }
509
+
510
+ if incompatible_handoff_runtimes:
511
+ yield CheckResult(
512
+ id="runtime.mixed_handoff_incompatible",
513
+ title="Mixed Runtime Handoff Issues",
514
+ category=CheckCategory.CONFIG,
515
+ status=CheckStatus.FAIL,
516
+ message=f"Handoffs configured with incompatible runtimes: {', '.join(incompatible_handoff_runtimes)}",
517
+ details="Only praisonai, autogen_v4, openai_agents, agno, google_adk, and pydantic_ai runtimes support handoffs",
518
+ remediation="Use praisonai, autogen_v4, openai_agents, agno, google_adk, or pydantic_ai for agents that need handoff capabilities",
519
+ severity=CheckSeverity.HIGH
520
+ )
521
+
522
+
523
+ def lint_runtime_team(yaml_path: str) -> List[CheckResult]:
524
+ """
525
+ Public API for programmatic runtime linting.
526
+
527
+ Args:
528
+ yaml_path: Path to the team YAML file
529
+
530
+ Returns:
531
+ List of check results
532
+ """
533
+ checker = RuntimeCompatibilityChecker()
534
+ return list(checker.validate_team_yaml(yaml_path))
535
+
536
+
537
+ # Register the runtime checks with the doctor framework
538
+
539
+
540
+ def runtime_team_check(config):
541
+ """Runtime team compatibility check for the doctor framework."""
542
+ team_file = getattr(config, 'team_file', None)
543
+
544
+ if not team_file:
545
+ return CheckResult(
546
+ id="runtime.no_team_file",
547
+ title="No Team File Specified",
548
+ category=CheckCategory.RUNTIME,
549
+ status=CheckStatus.SKIP,
550
+ message="Use --team to specify a team YAML file for runtime validation"
551
+ )
552
+
553
+ if not os.path.exists(team_file):
554
+ return CheckResult(
555
+ id="runtime.team_file_not_found",
556
+ title="Team File Not Found",
557
+ category=CheckCategory.RUNTIME,
558
+ status=CheckStatus.FAIL,
559
+ message=f"Team YAML file not found: {team_file}",
560
+ severity=CheckSeverity.HIGH
561
+ )
562
+
563
+ checker = RuntimeCompatibilityChecker()
564
+ results = list(checker.validate_team_yaml(team_file))
565
+
566
+ if not results:
567
+ return CheckResult(
568
+ id="runtime.team_validation_success",
569
+ title="Runtime Team Compatibility",
570
+ category=CheckCategory.RUNTIME,
571
+ status=CheckStatus.PASS,
572
+ message=f"No runtime compatibility issues found in {team_file}"
573
+ )
574
+
575
+ # Aggregate results into a single CheckResult as expected by the doctor engine
576
+ has_failures = any(r.status in (CheckStatus.FAIL, CheckStatus.ERROR) for r in results)
577
+ has_warnings = any(r.status == CheckStatus.WARN for r in results)
578
+
579
+ if has_failures:
580
+ status = CheckStatus.FAIL
581
+ severity = CheckSeverity.HIGH
582
+ elif has_warnings:
583
+ status = CheckStatus.WARN
584
+ severity = CheckSeverity.MEDIUM
585
+ else:
586
+ status = CheckStatus.PASS
587
+ severity = CheckSeverity.LOW
588
+
589
+ return CheckResult(
590
+ id="runtime.team_validation_aggregate",
591
+ title="Runtime Team Compatibility",
592
+ category=CheckCategory.RUNTIME,
593
+ status=status,
594
+ message=f"Found {len(results)} runtime compatibility issue(s) in {team_file}",
595
+ details="\n".join(f"- {r.id}: {r.message}" for r in results) if results else "No issues found",
596
+ severity=severity,
597
+ metadata={"findings": [r.to_dict() for r in results]}
598
+ )
599
+
600
+
601
+ def workflow_runtime_check(config):
602
+ """Workflow runtime compatibility check (placeholder for future implementation)."""
603
+ workflow_file = getattr(config, 'workflow_file', None)
604
+
605
+ if not workflow_file:
606
+ return CheckResult(
607
+ id="runtime.workflow_not_implemented",
608
+ title="Workflow Runtime Validation",
609
+ category=CheckCategory.RUNTIME,
610
+ status=CheckStatus.SKIP,
611
+ message="Workflow runtime validation not yet implemented"
612
+ )
613
+
614
+ return CheckResult(
615
+ id="runtime.workflow_placeholder",
616
+ title="Workflow Runtime Validation",
617
+ category=CheckCategory.RUNTIME,
618
+ status=CheckStatus.SKIP,
619
+ message="Workflow runtime validation will be implemented in future versions"
620
+ )
621
+
622
+
623
+ # Register checks when module is imported
624
+ try:
625
+ registry = CheckRegistry()
626
+
627
+ # Register team runtime check
628
+ registry.register(
629
+ id='runtime.team',
630
+ title='Runtime Team Compatibility',
631
+ description='Validate runtime compatibility for team YAML configurations',
632
+ category=CheckCategory.RUNTIME,
633
+ implementation=runtime_team_check,
634
+ requires_deep=False
635
+ )
636
+
637
+ # Register workflow runtime check (placeholder)
638
+ registry.register(
639
+ id='runtime.workflow',
640
+ title='Workflow Runtime Compatibility',
641
+ description='Validate runtime compatibility for workflow YAML configurations',
642
+ category=CheckCategory.RUNTIME,
643
+ implementation=workflow_runtime_check,
644
+ requires_deep=False
645
+ )
646
+
647
+ except Exception as e:
648
+ # Log registration failure but don't crash the module
649
+ import logging
650
+ logging.getLogger(__name__).warning(f"Failed to register runtime checks: {e}")