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,220 @@
1
+ """
2
+ Runtime configuration migration checks.
3
+
4
+ Checks for legacy cli_backend configuration and provides migration to
5
+ the new model-scoped runtime configuration.
6
+ """
7
+
8
+ import os
9
+ import yaml
10
+ import json
11
+ import shutil
12
+ import copy
13
+ from pathlib import Path
14
+ from typing import Dict, List, Optional, Union
15
+ from datetime import datetime
16
+
17
+ from ..models import CheckCategory, CheckResult, CheckStatus, CheckSeverity, DoctorConfig
18
+ from ..registry import register_check
19
+
20
+
21
+ def _find_config_file(config_file: Optional[str] = None) -> Optional[Path]:
22
+ """Find the configuration file to check."""
23
+ if config_file:
24
+ path = Path(config_file)
25
+ return path if path.exists() else None
26
+
27
+ # Search for common config files
28
+ current_dir = Path.cwd()
29
+ for filename in ["agents.yaml", "agents.yml", "config.yaml", "config.yml"]:
30
+ path = current_dir / filename
31
+ if path.exists():
32
+ return path
33
+
34
+ return None
35
+
36
+
37
+ def _load_config(config_path: Path) -> Dict:
38
+ """Load configuration from YAML file."""
39
+ try:
40
+ with open(config_path, 'r', encoding='utf-8') as f:
41
+ return yaml.safe_load(f) or {}
42
+ except Exception as e:
43
+ raise ValueError(f"Failed to load config file: {e}")
44
+
45
+
46
+ def _save_config(config_path: Path, config: Dict, create_backup: bool = True) -> str:
47
+ """Save configuration to YAML file with optional backup."""
48
+ backup_info = ""
49
+
50
+ # Serialize first to ensure it's valid YAML
51
+ try:
52
+ yaml_content = yaml.dump(config, default_flow_style=False, sort_keys=False, indent=2)
53
+ except Exception as e:
54
+ raise ValueError(f"Failed to serialize configuration to YAML: {e}")
55
+
56
+ if create_backup:
57
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
58
+ backup_path = config_path.with_name(f"{config_path.stem}.backup.{timestamp}.yaml")
59
+ shutil.copy2(config_path, backup_path)
60
+ backup_info = f" (backup: {backup_path.name})"
61
+
62
+ with open(config_path, 'w', encoding='utf-8') as f:
63
+ f.write(yaml_content)
64
+
65
+ return backup_info
66
+
67
+
68
+ @register_check(
69
+ id="runtime.config_migration",
70
+ title="Runtime Configuration Migration",
71
+ description="Check for legacy cli_backend configuration and migrate to model-scoped runtime",
72
+ category=CheckCategory.RUNTIME
73
+ )
74
+ def check_runtime_config_migration(config: DoctorConfig) -> CheckResult:
75
+ """
76
+ Check for legacy cli_backend configuration and provide migration path.
77
+
78
+ Args:
79
+ config: DoctorConfig instance with fix and execute flags
80
+ """
81
+ try:
82
+ config_path = _find_config_file(config.config_file)
83
+
84
+ # If user specified a file and it doesn't exist, return ERROR
85
+ if config.config_file and not config_path:
86
+ return CheckResult(
87
+ id="runtime.config_file_found",
88
+ title="Configuration File Check",
89
+ category=CheckCategory.RUNTIME,
90
+ status=CheckStatus.ERROR,
91
+ message=f"Specified configuration file not found: {config.config_file}",
92
+ severity=CheckSeverity.HIGH
93
+ )
94
+ elif not config_path:
95
+ return CheckResult(
96
+ id="runtime.config_file_found",
97
+ title="Configuration File Check",
98
+ category=CheckCategory.RUNTIME,
99
+ status=CheckStatus.SKIP,
100
+ message="No configuration file found to check",
101
+ details="Searched for: agents.yaml, agents.yml, config.yaml, config.yml in current directory",
102
+ severity=CheckSeverity.INFO
103
+ )
104
+
105
+ # Load configuration
106
+ try:
107
+ yaml_config = _load_config(config_path)
108
+ except ValueError as e:
109
+ return CheckResult(
110
+ id="runtime.config_load",
111
+ title="Configuration Load",
112
+ category=CheckCategory.RUNTIME,
113
+ status=CheckStatus.ERROR,
114
+ message=f"Failed to load configuration file: {e}",
115
+ severity=CheckSeverity.HIGH
116
+ )
117
+
118
+ # Import the migration functionality from praisonaiagents
119
+ try:
120
+ from praisonaiagents.runtime import collect_findings, apply_fixes
121
+ except ImportError as e:
122
+ return CheckResult(
123
+ id="runtime.config_migration",
124
+ title="Runtime Configuration Migration",
125
+ category=CheckCategory.RUNTIME,
126
+ status=CheckStatus.ERROR,
127
+ message=f"Could not import migration tools: {e}",
128
+ details="Ensure praisonaiagents is installed: pip install praisonaiagents",
129
+ severity=CheckSeverity.HIGH
130
+ )
131
+
132
+ # Collect findings from all registered rules
133
+ findings = collect_findings(yaml_config)
134
+
135
+ if not findings:
136
+ return CheckResult(
137
+ id="runtime.config_migration",
138
+ title="Runtime Configuration Migration",
139
+ category=CheckCategory.RUNTIME,
140
+ status=CheckStatus.PASS,
141
+ message=f"Configuration is up to date: {config_path.name}",
142
+ details="No legacy cli_backend fields found",
143
+ severity=CheckSeverity.INFO
144
+ )
145
+
146
+ # Prepare details about findings
147
+ details = []
148
+ for finding in findings:
149
+ details.append(f"• {finding.description}")
150
+ if finding.details:
151
+ details.append(f" {finding.details}")
152
+
153
+ # If not fixing, just report findings
154
+ if not config.fix:
155
+ return CheckResult(
156
+ id="runtime.config_migration",
157
+ title="Runtime Configuration Migration",
158
+ category=CheckCategory.RUNTIME,
159
+ status=CheckStatus.WARN,
160
+ message=f"Found {len(findings)} legacy configuration(s) in {config_path.name}",
161
+ details="\n".join(details),
162
+ severity=CheckSeverity.MEDIUM,
163
+ fix_suggestion="Run 'praisonai doctor runtime --fix' to migrate automatically"
164
+ )
165
+
166
+ # Apply fixes (dry-run or execute)
167
+ try:
168
+ migrated_config = apply_fixes(yaml_config)
169
+
170
+ # Show what would be changed
171
+ if config.fix and not config.execute:
172
+ # Dry-run mode
173
+ preview = []
174
+ preview.append(f"Would migrate {len(findings)} legacy configuration(s):")
175
+ preview.extend(details)
176
+ preview.append("\nTo apply changes, run with --fix --execute")
177
+
178
+ return CheckResult(
179
+ id="runtime.config_migration",
180
+ title="Runtime Configuration Migration (Dry-Run)",
181
+ category=CheckCategory.RUNTIME,
182
+ status=CheckStatus.INFO,
183
+ message=f"Preview of changes for {config_path.name}",
184
+ details="\n".join(preview),
185
+ severity=CheckSeverity.INFO
186
+ )
187
+
188
+ # Execute the migration
189
+ if config.fix and config.execute:
190
+ backup_info = _save_config(config_path, migrated_config)
191
+
192
+ return CheckResult(
193
+ id="runtime.config_migration",
194
+ title="Runtime Configuration Migration",
195
+ category=CheckCategory.RUNTIME,
196
+ status=CheckStatus.PASS,
197
+ message=f"Successfully migrated {len(findings)} legacy configuration(s)",
198
+ details=f"Updated: {config_path.name}{backup_info}",
199
+ severity=CheckSeverity.INFO
200
+ )
201
+
202
+ except Exception as e:
203
+ return CheckResult(
204
+ id="runtime.config_migration",
205
+ title="Runtime Configuration Migration",
206
+ category=CheckCategory.RUNTIME,
207
+ status=CheckStatus.ERROR,
208
+ message=f"Failed to apply migration: {e}",
209
+ severity=CheckSeverity.HIGH
210
+ )
211
+
212
+ except Exception as e:
213
+ return CheckResult(
214
+ id="runtime.config_migration",
215
+ title="Runtime Configuration Migration",
216
+ category=CheckCategory.RUNTIME,
217
+ status=CheckStatus.ERROR,
218
+ message=f"Runtime migration check failed: {e}",
219
+ severity=CheckSeverity.HIGH
220
+ )
@@ -0,0 +1,322 @@
1
+ """
2
+ Selftest checks for the Doctor CLI module.
3
+
4
+ Performs minimal agent dry-run to validate the system.
5
+ """
6
+
7
+ import os
8
+
9
+ from ..models import (
10
+ CheckCategory,
11
+ CheckResult,
12
+ CheckStatus,
13
+ CheckSeverity,
14
+ DoctorConfig,
15
+ )
16
+ from ..registry import register_check
17
+
18
+
19
+ @register_check(
20
+ id="selftest_agent_import",
21
+ title="Agent Import",
22
+ description="Check Agent class can be imported",
23
+ category=CheckCategory.SELFTEST,
24
+ severity=CheckSeverity.HIGH,
25
+ )
26
+ def check_selftest_agent_import(config: DoctorConfig) -> CheckResult:
27
+ """Check Agent class can be imported."""
28
+ try:
29
+ from praisonaiagents import Agent
30
+ return CheckResult(
31
+ id="selftest_agent_import",
32
+ title="Agent Import",
33
+ category=CheckCategory.SELFTEST,
34
+ status=CheckStatus.PASS,
35
+ message="Agent class imported successfully",
36
+ )
37
+ except ImportError as e:
38
+ return CheckResult(
39
+ id="selftest_agent_import",
40
+ title="Agent Import",
41
+ category=CheckCategory.SELFTEST,
42
+ status=CheckStatus.FAIL,
43
+ message=f"Cannot import Agent: {e}",
44
+ remediation="Ensure praisonaiagents is properly installed",
45
+ severity=CheckSeverity.CRITICAL,
46
+ )
47
+
48
+
49
+ @register_check(
50
+ id="selftest_agent_create",
51
+ title="Agent Creation",
52
+ description="Check Agent can be instantiated",
53
+ category=CheckCategory.SELFTEST,
54
+ severity=CheckSeverity.HIGH,
55
+ dependencies=["selftest_agent_import"],
56
+ )
57
+ def check_selftest_agent_create(config: DoctorConfig) -> CheckResult:
58
+ """Check Agent can be instantiated."""
59
+ try:
60
+ from praisonaiagents import Agent
61
+
62
+ # Create a minimal agent without making API calls
63
+ agent = Agent(
64
+ name="DoctorTestAgent",
65
+ instructions="You are a test agent.",
66
+ llm="gpt-4o-mini", # Default model
67
+ output="minimal",
68
+ )
69
+
70
+ return CheckResult(
71
+ id="selftest_agent_create",
72
+ title="Agent Creation",
73
+ category=CheckCategory.SELFTEST,
74
+ status=CheckStatus.PASS,
75
+ message="Agent instantiated successfully",
76
+ metadata={"agent_name": agent.name},
77
+ )
78
+ except Exception as e:
79
+ return CheckResult(
80
+ id="selftest_agent_create",
81
+ title="Agent Creation",
82
+ category=CheckCategory.SELFTEST,
83
+ status=CheckStatus.FAIL,
84
+ message=f"Agent creation failed: {type(e).__name__}",
85
+ details=str(e)[:200],
86
+ remediation="Check configuration and dependencies",
87
+ severity=CheckSeverity.HIGH,
88
+ )
89
+
90
+
91
+ @register_check(
92
+ id="selftest_llm_config",
93
+ title="LLM Configuration",
94
+ description="Check LLM configuration is valid",
95
+ category=CheckCategory.SELFTEST,
96
+ severity=CheckSeverity.MEDIUM,
97
+ )
98
+ def check_selftest_llm_config(config: DoctorConfig) -> CheckResult:
99
+ """Check LLM configuration is valid."""
100
+ # Check for API key
101
+ openai_key = os.environ.get("OPENAI_API_KEY")
102
+ anthropic_key = os.environ.get("ANTHROPIC_API_KEY")
103
+ google_key = os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY")
104
+ ollama_host = os.environ.get("OLLAMA_HOST")
105
+
106
+ providers = []
107
+ if openai_key:
108
+ providers.append("OpenAI")
109
+ if anthropic_key:
110
+ providers.append("Anthropic")
111
+ if google_key:
112
+ providers.append("Google")
113
+ if ollama_host:
114
+ providers.append("Ollama")
115
+
116
+ if providers:
117
+ return CheckResult(
118
+ id="selftest_llm_config",
119
+ title="LLM Configuration",
120
+ category=CheckCategory.SELFTEST,
121
+ status=CheckStatus.PASS,
122
+ message=f"LLM provider(s) configured: {', '.join(providers)}",
123
+ metadata={"providers": providers},
124
+ )
125
+ else:
126
+ return CheckResult(
127
+ id="selftest_llm_config",
128
+ title="LLM Configuration",
129
+ category=CheckCategory.SELFTEST,
130
+ status=CheckStatus.FAIL,
131
+ message="No LLM provider configured",
132
+ remediation="Set OPENAI_API_KEY or another provider's API key",
133
+ severity=CheckSeverity.HIGH,
134
+ )
135
+
136
+
137
+ @register_check(
138
+ id="selftest_mock_chat",
139
+ title="Mock Chat Test",
140
+ description="Test agent chat with mock response",
141
+ category=CheckCategory.SELFTEST,
142
+ severity=CheckSeverity.MEDIUM,
143
+ requires_deep=True,
144
+ )
145
+ def check_selftest_mock_chat(config: DoctorConfig) -> CheckResult:
146
+ """Test agent chat with mock response (no API call)."""
147
+ if not config.mock and not config.live:
148
+ # Default to mock in deep mode
149
+ config.mock = True
150
+
151
+ if config.live:
152
+ return CheckResult(
153
+ id="selftest_mock_chat",
154
+ title="Mock Chat Test",
155
+ category=CheckCategory.SELFTEST,
156
+ status=CheckStatus.SKIP,
157
+ message="Skipped (--live mode uses live API)",
158
+ )
159
+
160
+ try:
161
+ # Test basic agent functionality without making API calls
162
+ from praisonaiagents import Agent
163
+
164
+ agent = Agent(
165
+ name="MockTestAgent",
166
+ instructions="You are a test agent. Always respond with 'OK'.",
167
+ llm="gpt-4o-mini",
168
+ output="minimal",
169
+ )
170
+
171
+ # Verify agent is properly configured
172
+ if hasattr(agent, 'name') and hasattr(agent, 'instructions'):
173
+ return CheckResult(
174
+ id="selftest_mock_chat",
175
+ title="Mock Chat Test",
176
+ category=CheckCategory.SELFTEST,
177
+ status=CheckStatus.PASS,
178
+ message="Agent mock test passed",
179
+ )
180
+ else:
181
+ return CheckResult(
182
+ id="selftest_mock_chat",
183
+ title="Mock Chat Test",
184
+ category=CheckCategory.SELFTEST,
185
+ status=CheckStatus.FAIL,
186
+ message="Agent missing expected attributes",
187
+ )
188
+ except Exception as e:
189
+ return CheckResult(
190
+ id="selftest_mock_chat",
191
+ title="Mock Chat Test",
192
+ category=CheckCategory.SELFTEST,
193
+ status=CheckStatus.FAIL,
194
+ message=f"Mock test failed: {type(e).__name__}",
195
+ details=str(e)[:200],
196
+ )
197
+
198
+
199
+ @register_check(
200
+ id="selftest_live_chat",
201
+ title="Live Chat Test",
202
+ description="Test agent chat with live API call",
203
+ category=CheckCategory.SELFTEST,
204
+ severity=CheckSeverity.LOW,
205
+ requires_deep=True,
206
+ )
207
+ def check_selftest_live_chat(config: DoctorConfig) -> CheckResult:
208
+ """Test agent chat with live API call."""
209
+ if not config.live:
210
+ return CheckResult(
211
+ id="selftest_live_chat",
212
+ title="Live Chat Test",
213
+ category=CheckCategory.SELFTEST,
214
+ status=CheckStatus.SKIP,
215
+ message="Skipped (use --live to enable)",
216
+ )
217
+
218
+ # Check for API key first
219
+ if not os.environ.get("OPENAI_API_KEY"):
220
+ return CheckResult(
221
+ id="selftest_live_chat",
222
+ title="Live Chat Test",
223
+ category=CheckCategory.SELFTEST,
224
+ status=CheckStatus.SKIP,
225
+ message="Skipped (OPENAI_API_KEY not set)",
226
+ )
227
+
228
+ try:
229
+ from praisonaiagents import Agent
230
+
231
+ model = config.model or "gpt-4o-mini"
232
+
233
+ agent = Agent(
234
+ name="LiveTestAgent",
235
+ instructions="You are a test agent. Respond with exactly: 'Doctor test OK'",
236
+ llm=model,
237
+ output="minimal",
238
+ )
239
+
240
+ # Make a simple API call
241
+ response = agent.chat("Say hello")
242
+
243
+ if response:
244
+ return CheckResult(
245
+ id="selftest_live_chat",
246
+ title="Live Chat Test",
247
+ category=CheckCategory.SELFTEST,
248
+ status=CheckStatus.PASS,
249
+ message=f"Live API call successful (model: {model})",
250
+ metadata={"model": model, "response_length": len(str(response))},
251
+ )
252
+ else:
253
+ return CheckResult(
254
+ id="selftest_live_chat",
255
+ title="Live Chat Test",
256
+ category=CheckCategory.SELFTEST,
257
+ status=CheckStatus.FAIL,
258
+ message="Live API call returned empty response",
259
+ )
260
+ except Exception as e:
261
+ return CheckResult(
262
+ id="selftest_live_chat",
263
+ title="Live Chat Test",
264
+ category=CheckCategory.SELFTEST,
265
+ status=CheckStatus.FAIL,
266
+ message=f"Live API call failed: {type(e).__name__}",
267
+ details=str(e)[:200],
268
+ remediation="Check API key and network connectivity",
269
+ )
270
+
271
+
272
+ @register_check(
273
+ id="selftest_tools_wiring",
274
+ title="Tools Wiring",
275
+ description="Check tools can be wired to agent",
276
+ category=CheckCategory.SELFTEST,
277
+ severity=CheckSeverity.LOW,
278
+ )
279
+ def check_selftest_tools_wiring(config: DoctorConfig) -> CheckResult:
280
+ """Check tools can be wired to agent."""
281
+ try:
282
+ from praisonaiagents import Agent
283
+
284
+ # Define a simple test tool
285
+ def test_tool(x: str) -> str:
286
+ """A test tool that echoes input."""
287
+ return f"Echo: {x}"
288
+
289
+ agent = Agent(
290
+ name="ToolTestAgent",
291
+ instructions="You are a test agent with tools.",
292
+ tools=[test_tool],
293
+ llm="gpt-4o-mini",
294
+ output="minimal",
295
+ )
296
+
297
+ # Check tools are registered
298
+ if hasattr(agent, 'tools') or hasattr(agent, '_tools'):
299
+ return CheckResult(
300
+ id="selftest_tools_wiring",
301
+ title="Tools Wiring",
302
+ category=CheckCategory.SELFTEST,
303
+ status=CheckStatus.PASS,
304
+ message="Tools wired to agent successfully",
305
+ )
306
+ else:
307
+ return CheckResult(
308
+ id="selftest_tools_wiring",
309
+ title="Tools Wiring",
310
+ category=CheckCategory.SELFTEST,
311
+ status=CheckStatus.WARN,
312
+ message="Tools wiring could not be verified",
313
+ )
314
+ except Exception as e:
315
+ return CheckResult(
316
+ id="selftest_tools_wiring",
317
+ title="Tools Wiring",
318
+ category=CheckCategory.SELFTEST,
319
+ status=CheckStatus.FAIL,
320
+ message=f"Tools wiring failed: {type(e).__name__}",
321
+ details=str(e)[:200],
322
+ )