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,463 @@
1
+ """
2
+ Agent-Driven Migration Flow.
3
+
4
+ Uses AgentFlow with specialized agents to migrate code from various
5
+ agent frameworks to PraisonAI format.
6
+
7
+ Architecture:
8
+ 1. Analyzer Agent - Scans all files, understands relationships
9
+ 2. Converter Agent - Transforms code using migration spec
10
+ 3. Evaluator Agent - Uses LLM-as-Judge to validate conversion
11
+ 4. Error Agent - Analyzes failures and suggests fixes
12
+
13
+ The flow includes a retry loop (max 3 iterations) for error recovery.
14
+ """
15
+
16
+ import os
17
+ import logging
18
+ from dataclasses import dataclass, field
19
+ from typing import Dict, List, Optional
20
+ from pathlib import Path
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ @dataclass
26
+ class FileContext:
27
+ """Context for a single file in the migration."""
28
+ path: str
29
+ content: str
30
+ patterns_found: List[str] = field(default_factory=list)
31
+ converted_content: Optional[str] = None
32
+ errors: List[str] = field(default_factory=list)
33
+
34
+
35
+ @dataclass
36
+ class MigrationContext:
37
+ """Complete context for multi-file migration."""
38
+ source_path: str
39
+ files: Dict[str, FileContext] = field(default_factory=dict)
40
+ all_imports: List[str] = field(default_factory=list)
41
+ all_classes: List[str] = field(default_factory=list)
42
+ all_functions: List[str] = field(default_factory=list)
43
+ cross_file_deps: Dict[str, List[str]] = field(default_factory=dict)
44
+
45
+ def to_prompt(self) -> str:
46
+ """Convert context to a prompt for LLM agents."""
47
+ lines = [
48
+ f"# Project Analysis: {self.source_path}",
49
+ f"Total files: {len(self.files)}",
50
+ "",
51
+ "## Files:",
52
+ ]
53
+ for path, ctx in self.files.items():
54
+ lines.append(f"- {path}: {len(ctx.content)} chars, patterns: {ctx.patterns_found}")
55
+
56
+ if self.cross_file_deps:
57
+ lines.append("")
58
+ lines.append("## Cross-file Dependencies:")
59
+ for file, deps in self.cross_file_deps.items():
60
+ lines.append(f"- {file} imports from: {deps}")
61
+
62
+ return "\n".join(lines)
63
+
64
+
65
+ @dataclass
66
+ class MigrationResult:
67
+ """Result of the migration flow."""
68
+ success: bool
69
+ files_converted: int = 0
70
+ files_failed: int = 0
71
+ iterations: int = 0
72
+ evaluation_score: float = 0.0
73
+ converted_files: Dict[str, str] = field(default_factory=dict)
74
+ errors: List[str] = field(default_factory=list)
75
+ warnings: List[str] = field(default_factory=list)
76
+
77
+
78
+ class MigrationFlow:
79
+ """
80
+ Agent-driven migration flow using AgentFlow.
81
+
82
+ Uses specialized agents to analyze, convert, evaluate, and fix
83
+ code migration from various agent frameworks to PraisonAI.
84
+
85
+ Example:
86
+ flow = MigrationFlow(
87
+ source_path="./my-project",
88
+ output_path="./converted",
89
+ max_retries=3
90
+ )
91
+ result = flow.run()
92
+ """
93
+
94
+ def __init__(
95
+ self,
96
+ source_path: str,
97
+ output_path: Optional[str] = None,
98
+ max_retries: int = 3,
99
+ llm: str = "gpt-4o-mini",
100
+ dry_run: bool = True,
101
+ ):
102
+ self.source_path = source_path
103
+ self.output_path = output_path or f"{source_path}_converted"
104
+ self.max_retries = max_retries
105
+ self.llm = llm
106
+ self.dry_run = dry_run
107
+ self._context: Optional[MigrationContext] = None
108
+ self._spec = None
109
+
110
+ def _gather_files(self) -> MigrationContext:
111
+ """Gather all Python files and build context."""
112
+ context = MigrationContext(source_path=self.source_path)
113
+
114
+ source = Path(self.source_path)
115
+
116
+ if source.is_file():
117
+ # Single file
118
+ with open(source, 'r', encoding='utf-8') as f:
119
+ content = f.read()
120
+ context.files[str(source)] = FileContext(
121
+ path=str(source),
122
+ content=content
123
+ )
124
+ else:
125
+ # Directory - scan for Python files
126
+ exclude_dirs = {'venv', '.venv', '__pycache__', '.git', 'node_modules', '.tox', 'dist', 'build'}
127
+
128
+ for root, dirs, files in os.walk(source):
129
+ # Filter out excluded directories
130
+ dirs[:] = [d for d in dirs if d not in exclude_dirs]
131
+
132
+ for filename in files:
133
+ if filename.endswith('.py'):
134
+ filepath = os.path.join(root, filename)
135
+ try:
136
+ with open(filepath, 'r', encoding='utf-8') as f:
137
+ content = f.read()
138
+ rel_path = os.path.relpath(filepath, source)
139
+ context.files[rel_path] = FileContext(
140
+ path=rel_path,
141
+ content=content
142
+ )
143
+ except Exception as e:
144
+ logger.warning(f"Could not read {filepath}: {e}")
145
+
146
+ # Analyze cross-file dependencies
147
+ self._analyze_dependencies(context)
148
+
149
+ return context
150
+
151
+ def _analyze_dependencies(self, context: MigrationContext) -> None:
152
+ """Analyze imports and cross-file dependencies."""
153
+ import re
154
+
155
+ for path, file_ctx in context.files.items():
156
+ # Extract imports
157
+ import_pattern = r'^(?:from\s+(\S+)\s+)?import\s+(.+)$'
158
+ for line in file_ctx.content.split('\n'):
159
+ match = re.match(import_pattern, line.strip())
160
+ if match:
161
+ module = match.group(1) or match.group(2).split(',')[0].strip()
162
+ context.all_imports.append(module)
163
+
164
+ # Check if it's a local import
165
+ for other_path in context.files:
166
+ other_module = other_path.replace('/', '.').replace('.py', '')
167
+ if module.startswith(other_module) or other_module.endswith(module):
168
+ if path not in context.cross_file_deps:
169
+ context.cross_file_deps[path] = []
170
+ context.cross_file_deps[path].append(other_path)
171
+
172
+ # Extract class and function names
173
+ class_pattern = r'^class\s+(\w+)'
174
+ func_pattern = r'^def\s+(\w+)'
175
+ for line in file_ctx.content.split('\n'):
176
+ match = re.match(class_pattern, line)
177
+ if match:
178
+ context.all_classes.append(match.group(1))
179
+ match = re.match(func_pattern, line)
180
+ if match:
181
+ context.all_functions.append(match.group(1))
182
+
183
+ def _create_agents(self):
184
+ """Create the specialized migration agents."""
185
+ # Lazy import to avoid circular dependencies
186
+ from praisonaiagents import Agent
187
+ from .migration_spec import get_default_spec, PRAISONAI_REFERENCE
188
+
189
+ self._spec = get_default_spec()
190
+ spec_prompt = self._spec.to_prompt()
191
+
192
+ # Analyzer Agent
193
+ analyzer = Agent(
194
+ name="Analyzer",
195
+ role="Code Analyzer",
196
+ goal="Analyze source code to identify agent patterns and dependencies",
197
+ instructions=f"""You are a code analysis expert. Analyze the provided source code to:
198
+ 1. Identify all agent-related patterns (Agent, Task, Team, Workflow definitions)
199
+ 2. Map dependencies between files
200
+ 3. Identify import patterns that need conversion
201
+ 4. List all classes and functions that are part of the agent system
202
+
203
+ Use this specification to identify patterns:
204
+ {spec_prompt}
205
+
206
+ Output a structured analysis with:
207
+ - List of detected patterns per file
208
+ - Cross-file dependencies
209
+ - Recommended conversion order
210
+ """,
211
+ llm=self.llm,
212
+ )
213
+
214
+ # Converter Agent
215
+ converter = Agent(
216
+ name="Converter",
217
+ role="Code Converter",
218
+ goal="Convert source code to PraisonAI format",
219
+ instructions=f"""You are a code conversion expert. Convert the provided source code to PraisonAI format.
220
+
221
+ Use this specification for conversion:
222
+ {spec_prompt}
223
+
224
+ Reference for PraisonAI code:
225
+ {PRAISONAI_REFERENCE}
226
+
227
+ Rules:
228
+ 1. Preserve all logic and behavior
229
+ 2. Convert imports to praisonaiagents
230
+ 3. Map parameters according to the spec
231
+ 4. Handle cross-file dependencies correctly
232
+ 5. Ensure the converted code is syntactically valid Python
233
+ 6. Do NOT include any framework names in comments
234
+
235
+ Output the complete converted code for each file.
236
+ """,
237
+ llm=self.llm,
238
+ )
239
+
240
+ # Evaluator Agent (LLM-as-Judge)
241
+ evaluator = Agent(
242
+ name="Evaluator",
243
+ role="Migration Evaluator",
244
+ goal="Evaluate the quality of code migration",
245
+ instructions="""You are a code quality evaluator using LLM-as-Judge methodology.
246
+
247
+ Evaluate the converted code on these criteria (score 1-10 each):
248
+ 1. **Syntax Correctness**: Is the code valid Python?
249
+ 2. **Import Completeness**: Are all necessary imports present?
250
+ 3. **Functional Equivalence**: Does it preserve the original behavior?
251
+ 4. **Pattern Accuracy**: Are agent patterns correctly converted?
252
+ 5. **Dependency Handling**: Are cross-file dependencies handled?
253
+
254
+ Output format:
255
+ ```json
256
+ {
257
+ "scores": {
258
+ "syntax": 8,
259
+ "imports": 9,
260
+ "equivalence": 7,
261
+ "patterns": 8,
262
+ "dependencies": 9
263
+ },
264
+ "overall_score": 8.2,
265
+ "passed": true,
266
+ "issues": ["list of specific issues if any"],
267
+ "suggestions": ["list of improvements if any"]
268
+ }
269
+ ```
270
+
271
+ A score of 8.0 or higher means PASSED.
272
+ """,
273
+ llm=self.llm,
274
+ )
275
+
276
+ # Error Agent
277
+ error_agent = Agent(
278
+ name="ErrorAnalyzer",
279
+ role="Error Analyzer",
280
+ goal="Analyze migration errors and suggest fixes",
281
+ instructions="""You are an error analysis expert. When migration evaluation fails:
282
+
283
+ 1. Analyze the specific errors reported
284
+ 2. Identify the root cause
285
+ 3. Suggest specific fixes
286
+ 4. Provide corrected code snippets
287
+
288
+ Output format:
289
+ ```json
290
+ {
291
+ "root_cause": "description of the main issue",
292
+ "affected_files": ["list of files with issues"],
293
+ "fixes": [
294
+ {
295
+ "file": "filename",
296
+ "issue": "what's wrong",
297
+ "fix": "how to fix it",
298
+ "corrected_code": "the fixed code snippet"
299
+ }
300
+ ],
301
+ "retry_recommended": true
302
+ }
303
+ ```
304
+ """,
305
+ llm=self.llm,
306
+ )
307
+
308
+ return analyzer, converter, evaluator, error_agent
309
+
310
+ def run(self) -> MigrationResult:
311
+ """Run the migration flow."""
312
+ result = MigrationResult(success=False)
313
+
314
+ # Gather all files
315
+ logger.info(f"Gathering files from {self.source_path}")
316
+ self._context = self._gather_files()
317
+
318
+ if not self._context.files:
319
+ result.errors.append("No Python files found")
320
+ return result
321
+
322
+ logger.info(f"Found {len(self._context.files)} files to analyze")
323
+
324
+ # Create agents
325
+ analyzer, converter, evaluator, error_agent = self._create_agents()
326
+
327
+ # Build the combined context for all files
328
+ all_code = []
329
+ for path, file_ctx in self._context.files.items():
330
+ all_code.append(f"# File: {path}\n{file_ctx.content}")
331
+ combined_code = "\n\n---\n\n".join(all_code)
332
+
333
+ # Retry loop
334
+ for iteration in range(self.max_retries):
335
+ result.iterations = iteration + 1
336
+ logger.info(f"Migration iteration {iteration + 1}/{self.max_retries}")
337
+
338
+ try:
339
+ # Step 1: Analyze
340
+ analysis_prompt = f"""Analyze this codebase for migration:
341
+
342
+ {self._context.to_prompt()}
343
+
344
+ Full code:
345
+ {combined_code}
346
+ """
347
+ analysis = analyzer.start(analysis_prompt)
348
+ logger.info("Analysis complete")
349
+
350
+ # Step 2: Convert
351
+ convert_prompt = f"""Convert this code to PraisonAI format.
352
+
353
+ Analysis results:
354
+ {analysis}
355
+
356
+ Original code:
357
+ {combined_code}
358
+
359
+ Convert ALL files and output the complete converted code for each file.
360
+ Format: Start each file with "# FILE: filename.py" followed by the converted code.
361
+ """
362
+ converted = converter.start(convert_prompt)
363
+ logger.info("Conversion complete")
364
+
365
+ # Parse converted files
366
+ self._parse_converted_output(converted, result)
367
+
368
+ # Step 3: Evaluate
369
+ eval_prompt = f"""Evaluate this migration:
370
+
371
+ Original code:
372
+ {combined_code}
373
+
374
+ Converted code:
375
+ {converted}
376
+
377
+ Evaluate and score the migration quality.
378
+ """
379
+ evaluation = evaluator.start(eval_prompt)
380
+ logger.info("Evaluation complete")
381
+
382
+ # Parse evaluation result
383
+ import json
384
+ import re
385
+
386
+ # Try to extract JSON from evaluation
387
+ json_match = re.search(r'\{[\s\S]*\}', evaluation)
388
+ if json_match:
389
+ try:
390
+ eval_result = json.loads(json_match.group())
391
+ result.evaluation_score = eval_result.get('overall_score', 0)
392
+
393
+ if eval_result.get('passed', False) or result.evaluation_score >= 8.0:
394
+ result.success = True
395
+ result.files_converted = len(result.converted_files)
396
+ logger.info(f"Migration PASSED with score {result.evaluation_score}")
397
+ break
398
+ else:
399
+ # Evaluation failed, run error analysis
400
+ issues = eval_result.get('issues', [])
401
+ result.warnings.extend(issues)
402
+
403
+ if iteration < self.max_retries - 1:
404
+ error_prompt = f"""Migration evaluation failed.
405
+
406
+ Issues found:
407
+ {issues}
408
+
409
+ Converted code:
410
+ {converted}
411
+
412
+ Analyze the errors and suggest fixes.
413
+ """
414
+ _ = error_agent.start(error_prompt)
415
+ logger.info("Error analysis complete, retrying...")
416
+ # The next iteration will use the error analysis context
417
+ except json.JSONDecodeError:
418
+ result.warnings.append("Could not parse evaluation result")
419
+ else:
420
+ result.warnings.append("No evaluation JSON found")
421
+
422
+ except Exception as e:
423
+ result.errors.append(f"Iteration {iteration + 1} failed: {str(e)}")
424
+ logger.error(f"Migration error: {e}")
425
+
426
+ if not result.success:
427
+ result.errors.append(f"Migration failed after {self.max_retries} attempts")
428
+
429
+ # Save converted files if not dry run
430
+ if not self.dry_run and result.success:
431
+ self._save_converted_files(result)
432
+
433
+ return result
434
+
435
+ def _parse_converted_output(self, converted: str, result: MigrationResult) -> None:
436
+ """Parse the converted output into individual files."""
437
+ import re
438
+
439
+ # Split by file markers
440
+ file_pattern = r'#\s*FILE:\s*(\S+\.py)'
441
+ parts = re.split(file_pattern, converted)
442
+
443
+ # parts[0] is before first file, then alternating filename, content
444
+ for i in range(1, len(parts), 2):
445
+ if i + 1 < len(parts):
446
+ filename = parts[i].strip()
447
+ content = parts[i + 1].strip()
448
+ # Clean up code blocks
449
+ content = re.sub(r'^```python\s*', '', content)
450
+ content = re.sub(r'\s*```$', '', content)
451
+ result.converted_files[filename] = content
452
+
453
+ def _save_converted_files(self, result: MigrationResult) -> None:
454
+ """Save converted files to output directory."""
455
+ output_dir = Path(self.output_path)
456
+ output_dir.mkdir(parents=True, exist_ok=True)
457
+
458
+ for filename, content in result.converted_files.items():
459
+ filepath = output_dir / filename
460
+ filepath.parent.mkdir(parents=True, exist_ok=True)
461
+ with open(filepath, 'w', encoding='utf-8') as f:
462
+ f.write(content)
463
+ logger.info(f"Saved: {filepath}")