qwen-sci 0.2.2__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 (549) hide show
  1. qwen_sci-0.2.2.dist-info/METADATA +492 -0
  2. qwen_sci-0.2.2.dist-info/RECORD +549 -0
  3. qwen_sci-0.2.2.dist-info/WHEEL +4 -0
  4. qwen_sci-0.2.2.dist-info/entry_points.txt +6 -0
  5. qwen_sci-0.2.2.dist-info/licenses/LICENSE +21 -0
  6. src/1.txt +1 -0
  7. src/__init__.py +1 -0
  8. src/__main__.py +5 -0
  9. src/agents/__init__.py +1 -0
  10. src/agents/experiment_design_agent/__init__.py +268 -0
  11. src/agents/experiment_design_agent/artifacts.py +747 -0
  12. src/agents/experiment_design_agent/cache.py +319 -0
  13. src/agents/experiment_design_agent/completeness.py +130 -0
  14. src/agents/experiment_design_agent/contracts.py +771 -0
  15. src/agents/experiment_design_agent/counterexample_analyzer.py +187 -0
  16. src/agents/experiment_design_agent/design_evidence_paper_screener.py +470 -0
  17. src/agents/experiment_design_agent/discipline_catalog.py +178 -0
  18. src/agents/experiment_design_agent/evidence_cards.py +338 -0
  19. src/agents/experiment_design_agent/evidence_planner.py +452 -0
  20. src/agents/experiment_design_agent/formal_reasoning_planner.py +884 -0
  21. src/agents/experiment_design_agent/fulltext_acquisition.py +863 -0
  22. src/agents/experiment_design_agent/idea_adapter.py +100 -0
  23. src/agents/experiment_design_agent/idea_intake.py +87 -0
  24. src/agents/experiment_design_agent/llm_json.py +328 -0
  25. src/agents/experiment_design_agent/orchestrator.py +1220 -0
  26. src/agents/experiment_design_agent/reasoning_context.py +183 -0
  27. src/agents/experiment_design_agent/reasoning_validation.py +546 -0
  28. src/agents/experiment_design_agent/run.py +481 -0
  29. src/agents/experiment_design_agent/run_logging.py +292 -0
  30. src/agents/experiment_design_agent/scope_gate.py +198 -0
  31. src/agents/experiment_design_agent/study_type_composer.py +1360 -0
  32. src/agents/experiment_design_agent/survey_evidence.py +1381 -0
  33. src/agents/experiment_design_agent/template_router.py +195 -0
  34. src/agents/experiment_design_agent/variable_claim_extractor.py +93 -0
  35. src/agents/idea_agent/__init__.py +1 -0
  36. src/agents/idea_agent/agent/__init__.py +6 -0
  37. src/agents/idea_agent/agent/artifacts.py +308 -0
  38. src/agents/idea_agent/agent/base.py +122 -0
  39. src/agents/idea_agent/agent/ligagent.py +488 -0
  40. src/agents/idea_agent/agent/mcts.py +2060 -0
  41. src/agents/idea_agent/agent/prompts/__init__.py +48 -0
  42. src/agents/idea_agent/agent/prompts/advanced_analysis.py +235 -0
  43. src/agents/idea_agent/agent/prompts/algorithm_alignment.py +55 -0
  44. src/agents/idea_agent/agent/prompts/algorithm_structuring.py +48 -0
  45. src/agents/idea_agent/agent/prompts/component_extraction.py +62 -0
  46. src/agents/idea_agent/agent/prompts/component_novelty_evaluation.py +54 -0
  47. src/agents/idea_agent/agent/prompts/experiment_findings_extraction.py +39 -0
  48. src/agents/idea_agent/agent/prompts/idea_fusion.py +295 -0
  49. src/agents/idea_agent/agent/prompts/idea_introduction.py +30 -0
  50. src/agents/idea_agent/agent/prompts/idea_result_alignment.py +39 -0
  51. src/agents/idea_agent/agent/prompts/input_interpreter.py +52 -0
  52. src/agents/idea_agent/agent/prompts/keynote_ops.py +78 -0
  53. src/agents/idea_agent/agent/prompts/mcts_evaluation.py +235 -0
  54. src/agents/idea_agent/agent/prompts/mcts_generation.py +140 -0
  55. src/agents/idea_agent/agent/prompts/mechanism_commit_query.py +99 -0
  56. src/agents/idea_agent/agent/prompts/memory_selection.py +0 -0
  57. src/agents/idea_agent/agent/prompts/prompt_modes.py +16 -0
  58. src/agents/idea_agent/agent/prompts/rag_query.py +34 -0
  59. src/agents/idea_agent/agent/prompts/re_analysis_replan.py +48 -0
  60. src/agents/idea_agent/agent/prompts/reference_grounding.py +34 -0
  61. src/agents/idea_agent/agent/prompts/root_domain_classification.py +32 -0
  62. src/agents/idea_agent/agent/prompts/scientific_debate.py +88 -0
  63. src/agents/idea_agent/agent/prompts/scientific_materialization.py +45 -0
  64. src/agents/idea_agent/agent/prompts/skill_instantiation.py +193 -0
  65. src/agents/idea_agent/agent/prompts/theory_transfer_query.py +93 -0
  66. src/agents/idea_agent/agent/prompts/topic_background.py +15 -0
  67. src/agents/idea_agent/agent/skills/DEFAULT_SKILL_TEMPLATES.json +263 -0
  68. src/agents/idea_agent/agent/skills/edit_operator_skills/alternative-path-contrast/SKILL.md +40 -0
  69. src/agents/idea_agent/agent/skills/edit_operator_skills/alternative-path-contrast/references/contrast_patterns.md +22 -0
  70. src/agents/idea_agent/agent/skills/edit_operator_skills/feedback-closed-loop/SKILL.md +40 -0
  71. src/agents/idea_agent/agent/skills/edit_operator_skills/feedback-closed-loop/references/mechanism_cards.md +24 -0
  72. src/agents/idea_agent/agent/skills/edit_operator_skills/hierarchical-decomposition/SKILL.md +39 -0
  73. src/agents/idea_agent/agent/skills/edit_operator_skills/hierarchical-decomposition/references/hierarchy_patterns.md +22 -0
  74. src/agents/idea_agent/agent/skills/edit_operator_skills/mechanism-commit-innovation/SKILL.md +39 -0
  75. src/agents/idea_agent/agent/skills/edit_operator_skills/mechanism-commit-innovation/references/mechanism_commit_patterns.md +24 -0
  76. src/agents/idea_agent/agent/skills/edit_operator_skills/multi-scale-coordinator/SKILL.md +39 -0
  77. src/agents/idea_agent/agent/skills/edit_operator_skills/multi-scale-coordinator/references/coordination_patterns.md +22 -0
  78. src/agents/idea_agent/agent/skills/edit_operator_skills/speculative-execution-with-repair/SKILL.md +41 -0
  79. src/agents/idea_agent/agent/skills/edit_operator_skills/speculative-execution-with-repair/references/speculation_patterns.md +22 -0
  80. src/agents/idea_agent/agent/skills/edit_operator_skills/surgical-modularity/SKILL.md +39 -0
  81. src/agents/idea_agent/agent/skills/edit_operator_skills/surgical-modularity/references/modularity_patterns.md +22 -0
  82. src/agents/idea_agent/agent/skills/edit_operator_skills/theory-transfer-injection/SKILL.md +40 -0
  83. src/agents/idea_agent/agent/skills/edit_operator_skills/theory-transfer-injection/references/transfer_patterns.md +24 -0
  84. src/agents/idea_agent/example/idea_result.json +900 -0
  85. src/agents/idea_agent/run.py +276 -0
  86. src/agents/idea_agent/tests/test_advanced_analysis_contract.py +90 -0
  87. src/agents/idea_agent/tests/test_gap_hypothesis_bridge.py +166 -0
  88. src/agents/idea_agent/tests/test_idea_debate.py +480 -0
  89. src/agents/idea_agent/tests/test_idea_result_v5.py +99 -0
  90. src/agents/idea_agent/tests/test_idea_synthesis.py +92 -0
  91. src/agents/idea_agent/tests/test_mature_idea_sources.py +27 -0
  92. src/agents/idea_agent/tests/test_multimodal_idea_integration.py +386 -0
  93. src/agents/idea_agent/tests/test_profile_materialization_and_scoring.py +219 -0
  94. src/agents/idea_agent/tests/test_profile_native_skill_rendering.py +122 -0
  95. src/agents/idea_agent/tests/test_result_persistence.py +183 -0
  96. src/agents/idea_agent/tests/test_scientific_intervention_profiles.py +241 -0
  97. src/agents/idea_agent/tests/test_scientific_rubric_and_prompts.py +559 -0
  98. src/agents/idea_agent/tests/test_strict_json_object_responses.py +48 -0
  99. src/agents/idea_agent/utils/core/__init__.py +1 -0
  100. src/agents/idea_agent/utils/core/ablation_inputs.py +60 -0
  101. src/agents/idea_agent/utils/core/chat_errors.py +95 -0
  102. src/agents/idea_agent/utils/core/chat_router.py +130 -0
  103. src/agents/idea_agent/utils/core/chat_transport.py +188 -0
  104. src/agents/idea_agent/utils/core/config_loader.py +166 -0
  105. src/agents/idea_agent/utils/core/json_utils.py +28 -0
  106. src/agents/idea_agent/utils/core/logger.py +287 -0
  107. src/agents/idea_agent/utils/core/progress.py +58 -0
  108. src/agents/idea_agent/utils/core/response_parsing.py +57 -0
  109. src/agents/idea_agent/utils/core/run_inputs.py +198 -0
  110. src/agents/idea_agent/utils/mcts/__init__.py +1 -0
  111. src/agents/idea_agent/utils/mcts/component_novelty.py +342 -0
  112. src/agents/idea_agent/utils/mcts/defect_registry.py +302 -0
  113. src/agents/idea_agent/utils/mcts/idea_routes.py +61 -0
  114. src/agents/idea_agent/utils/mcts/idea_taste_presets.py +312 -0
  115. src/agents/idea_agent/utils/mcts/mcts_helpers.py +738 -0
  116. src/agents/idea_agent/utils/mcts/mcts_runtime.py +3000 -0
  117. src/agents/idea_agent/utils/mcts/scientific_intervention_ontology.py +1561 -0
  118. src/agents/idea_agent/utils/mcts/scientific_rubric.py +211 -0
  119. src/agents/idea_agent/utils/mcts/skill_parsing.py +92 -0
  120. src/agents/idea_agent/utils/papers/__init__.py +1 -0
  121. src/agents/idea_agent/utils/papers/paper_graph_vector_store.py +499 -0
  122. src/agents/idea_agent/utils/papers/paper_repository.py +372 -0
  123. src/agents/idea_agent/utils/prompting/__init__.py +1 -0
  124. src/agents/idea_agent/utils/prompting/prompt_views.py +637 -0
  125. src/agents/idea_agent/utils/workflow/__init__.py +1 -0
  126. src/agents/idea_agent/utils/workflow/advanced_analysis_contract.py +244 -0
  127. src/agents/idea_agent/utils/workflow/gap_hypothesis_bridge.py +461 -0
  128. src/agents/idea_agent/utils/workflow/idea_contract.py +426 -0
  129. src/agents/idea_agent/utils/workflow/idea_debate.py +1238 -0
  130. src/agents/idea_agent/utils/workflow/idea_diversity.py +163 -0
  131. src/agents/idea_agent/utils/workflow/idea_fusion.py +889 -0
  132. src/agents/idea_agent/utils/workflow/idea_helpers.py +478 -0
  133. src/agents/idea_agent/utils/workflow/idea_portfolio.py +422 -0
  134. src/agents/idea_agent/utils/workflow/idea_synthesis.py +482 -0
  135. src/agents/idea_agent/utils/workflow/ligagent_flow.py +581 -0
  136. src/agents/idea_agent/utils/workflow/ligagent_handlers.py +1836 -0
  137. src/agents/idea_agent/utils/workflow/ligagent_helpers.py +1331 -0
  138. src/agents/idea_agent/utils/workflow/ligagent_utils.py +322 -0
  139. src/agents/idea_agent/utils/workflow/mature_idea_sources.py +648 -0
  140. src/agents/idea_agent/utils/workflow/multimodal_data_anchoring.py +578 -0
  141. src/agents/idea_agent/utils/workflow/result_persistence.py +774 -0
  142. src/agents/idea_agent/utils/workflow/stage_contract.py +76 -0
  143. src/agents/idea_agent/utils/workflow/workflow_runtime.py +288 -0
  144. src/agents/research_plan_author/__init__.py +50 -0
  145. src/agents/research_plan_author/artifacts.py +270 -0
  146. src/agents/research_plan_author/authoring_blueprint.py +1246 -0
  147. src/agents/research_plan_author/bibtex_renderer.py +252 -0
  148. src/agents/research_plan_author/contract_repair.py +131 -0
  149. src/agents/research_plan_author/contracts.py +745 -0
  150. src/agents/research_plan_author/cross_section_editor.py +232 -0
  151. src/agents/research_plan_author/document_quality.py +987 -0
  152. src/agents/research_plan_author/idea_evolution.py +223 -0
  153. src/agents/research_plan_author/input_loader.py +76 -0
  154. src/agents/research_plan_author/latex_compiler.py +260 -0
  155. src/agents/research_plan_author/latex_safety.py +159 -0
  156. src/agents/research_plan_author/llm_json.py +74 -0
  157. src/agents/research_plan_author/markdown_renderer.py +275 -0
  158. src/agents/research_plan_author/pdf_validator.py +149 -0
  159. src/agents/research_plan_author/render.py +166 -0
  160. src/agents/research_plan_author/render_artifacts.py +187 -0
  161. src/agents/research_plan_author/run.py +765 -0
  162. src/agents/research_plan_author/run_logging.py +209 -0
  163. src/agents/research_plan_author/section_cache.py +184 -0
  164. src/agents/research_plan_author/section_composer.py +1764 -0
  165. src/agents/research_plan_author/section_router.py +209 -0
  166. src/agents/research_plan_author/semantic_validator.py +254 -0
  167. src/agents/research_plan_author/source_bundle.py +46 -0
  168. src/agents/research_plan_author/source_registry.py +208 -0
  169. src/agents/research_plan_author/survey_source_loader.py +137 -0
  170. src/agents/research_plan_author/template_adapter.py +173 -0
  171. src/agents/research_plan_author/template_profile.py +204 -0
  172. src/agents/research_plan_author/tex_renderer.py +496 -0
  173. src/agents/research_plan_author/theory_presentation.py +134 -0
  174. src/agents/research_plan_author/theory_spine.py +703 -0
  175. src/agents/survey_agent/Dockerfile +54 -0
  176. src/agents/survey_agent/README.md +350 -0
  177. src/agents/survey_agent/config/deep_survey.yaml +217 -0
  178. src/agents/survey_agent/config/deep_survey_batch.yaml +176 -0
  179. src/agents/survey_agent/config/deep_survey_fast.yaml +183 -0
  180. src/agents/survey_agent/config/evaluate_baseline.yaml +197 -0
  181. src/agents/survey_agent/config/outcomeRAG.yaml +159 -0
  182. src/agents/survey_agent/env_report.md +348 -0
  183. src/agents/survey_agent/modules/__init__.py +0 -0
  184. src/agents/survey_agent/modules/code_collector.py +2194 -0
  185. src/agents/survey_agent/modules/code_report_generator.py +1282 -0
  186. src/agents/survey_agent/modules/data_manager.py +1713 -0
  187. src/agents/survey_agent/modules/database.py +167 -0
  188. src/agents/survey_agent/modules/fulltext_download_cache.py +462 -0
  189. src/agents/survey_agent/modules/fulltext_http.py +134 -0
  190. src/agents/survey_agent/modules/fulltext_resolution.py +749 -0
  191. src/agents/survey_agent/modules/judge.py +434 -0
  192. src/agents/survey_agent/modules/outcome_RAG.py +236 -0
  193. src/agents/survey_agent/modules/paper_graph_retriever.py +1075 -0
  194. src/agents/survey_agent/modules/pe.py +1729 -0
  195. src/agents/survey_agent/modules/pseudo_creator.py +782 -0
  196. src/agents/survey_agent/modules/pseudo_reviser.py +537 -0
  197. src/agents/survey_agent/modules/refine_agent.py +1952 -0
  198. src/agents/survey_agent/modules/survey_generator.py +5691 -0
  199. src/agents/survey_agent/modules/survey_visualizer.py +1817 -0
  200. src/agents/survey_agent/modules/visual_prompts.py +327 -0
  201. src/agents/survey_agent/modules/work_analyzer.py +2750 -0
  202. src/agents/survey_agent/modules/work_collector.py +5649 -0
  203. src/agents/survey_agent/scripts/baseline_evaluation.py +411 -0
  204. src/agents/survey_agent/scripts/run_deep_survey.py +224 -0
  205. src/agents/survey_agent/scripts/run_deep_survey_adapter.py +407 -0
  206. src/agents/survey_agent/scripts/run_deep_survey_adapter_with_input.py +409 -0
  207. src/agents/survey_agent/scripts/run_deep_survey_batch.py +228 -0
  208. src/agents/survey_agent/scripts/run_deep_survey_batch_arg.py +243 -0
  209. src/agents/survey_agent/scripts/run_deep_survey_batch_settings.py +218 -0
  210. src/agents/survey_agent/scripts/run_keynotes_gen.py +128 -0
  211. src/agents/survey_agent/scripts/run_work_clusters.py +140 -0
  212. src/agents/survey_agent/utils/__init__.py +0 -0
  213. src/agents/survey_agent/utils/ablation_utils.py +317 -0
  214. src/agents/survey_agent/utils/api_call.py +2518 -0
  215. src/agents/survey_agent/utils/chat_utils.py +82 -0
  216. src/agents/survey_agent/utils/config_utils.py +70 -0
  217. src/agents/survey_agent/utils/convert_to_md.py +29 -0
  218. src/agents/survey_agent/utils/err_info.py +24 -0
  219. src/agents/survey_agent/utils/file_utils.py +176 -0
  220. src/agents/survey_agent/utils/gpu_utils.py +145 -0
  221. src/agents/survey_agent/utils/graph_visualizer.py +279 -0
  222. src/agents/survey_agent/utils/html_utils.py +181 -0
  223. src/agents/survey_agent/utils/latex_generator_intra_cluster.py +529 -0
  224. src/agents/survey_agent/utils/latex_generator_relation_table.py +193 -0
  225. src/agents/survey_agent/utils/mineru_section_packer.py +334 -0
  226. src/agents/survey_agent/utils/mineru_utils.py +396 -0
  227. src/agents/survey_agent/utils/paper.py +144 -0
  228. src/agents/survey_agent/utils/read_yaml.py +15 -0
  229. src/agents/survey_agent/utils/repo_utils.py +167 -0
  230. src/agents/survey_agent/utils/rich_logger.py +77 -0
  231. src/agents/survey_agent/utils/step2v2.py +874 -0
  232. src/agents/survey_agent/utils/step2v2_extractor.py +856 -0
  233. src/agents/survey_agent/utils/topic_survey_storage.py +309 -0
  234. src/agents/survey_agent/utils/utils.py +118 -0
  235. src/agents/survey_agent/utils/work.py +2 -0
  236. src/cli.py +1611 -0
  237. src/config/__init__.py +213 -0
  238. src/config/default.yaml +1122 -0
  239. src/harness/LICENSE +21 -0
  240. src/harness/VENDORED.md +14 -0
  241. src/harness/src/__init__.py +0 -0
  242. src/harness/src/openharness/__init__.py +0 -0
  243. src/harness/src/openharness/__main__.py +6 -0
  244. src/harness/src/openharness/api/__init__.py +21 -0
  245. src/harness/src/openharness/api/client.py +281 -0
  246. src/harness/src/openharness/api/codex_client.py +407 -0
  247. src/harness/src/openharness/api/copilot_auth.py +240 -0
  248. src/harness/src/openharness/api/copilot_client.py +134 -0
  249. src/harness/src/openharness/api/errors.py +19 -0
  250. src/harness/src/openharness/api/openai_client.py +577 -0
  251. src/harness/src/openharness/api/provider.py +186 -0
  252. src/harness/src/openharness/api/registry.py +437 -0
  253. src/harness/src/openharness/api/usage.py +17 -0
  254. src/harness/src/openharness/auth/__init__.py +29 -0
  255. src/harness/src/openharness/auth/external.py +610 -0
  256. src/harness/src/openharness/auth/flows.py +189 -0
  257. src/harness/src/openharness/auth/manager.py +482 -0
  258. src/harness/src/openharness/auth/storage.py +269 -0
  259. src/harness/src/openharness/autopilot/__init__.py +23 -0
  260. src/harness/src/openharness/autopilot/service.py +2239 -0
  261. src/harness/src/openharness/autopilot/types.py +91 -0
  262. src/harness/src/openharness/bridge/__init__.py +20 -0
  263. src/harness/src/openharness/bridge/manager.py +106 -0
  264. src/harness/src/openharness/bridge/session_runner.py +46 -0
  265. src/harness/src/openharness/bridge/types.py +37 -0
  266. src/harness/src/openharness/bridge/work_secret.py +41 -0
  267. src/harness/src/openharness/channels/UPSTREAM +6 -0
  268. src/harness/src/openharness/channels/__init__.py +22 -0
  269. src/harness/src/openharness/channels/adapter.py +131 -0
  270. src/harness/src/openharness/channels/bus/__init__.py +6 -0
  271. src/harness/src/openharness/channels/bus/events.py +38 -0
  272. src/harness/src/openharness/channels/bus/queue.py +44 -0
  273. src/harness/src/openharness/channels/impl/__init__.py +6 -0
  274. src/harness/src/openharness/channels/impl/base.py +141 -0
  275. src/harness/src/openharness/channels/impl/dingtalk.py +445 -0
  276. src/harness/src/openharness/channels/impl/discord.py +311 -0
  277. src/harness/src/openharness/channels/impl/email.py +410 -0
  278. src/harness/src/openharness/channels/impl/feishu.py +1342 -0
  279. src/harness/src/openharness/channels/impl/manager.py +257 -0
  280. src/harness/src/openharness/channels/impl/matrix.py +700 -0
  281. src/harness/src/openharness/channels/impl/mochat.py +897 -0
  282. src/harness/src/openharness/channels/impl/qq.py +141 -0
  283. src/harness/src/openharness/channels/impl/slack.py +284 -0
  284. src/harness/src/openharness/channels/impl/telegram.py +525 -0
  285. src/harness/src/openharness/channels/impl/whatsapp.py +159 -0
  286. src/harness/src/openharness/cli.py +2551 -0
  287. src/harness/src/openharness/commands/__init__.py +21 -0
  288. src/harness/src/openharness/commands/registry.py +2783 -0
  289. src/harness/src/openharness/config/__init__.py +34 -0
  290. src/harness/src/openharness/config/paths.py +160 -0
  291. src/harness/src/openharness/config/schema.py +119 -0
  292. src/harness/src/openharness/config/settings.py +1104 -0
  293. src/harness/src/openharness/coordinator/__init__.py +12 -0
  294. src/harness/src/openharness/coordinator/agent_definitions.py +975 -0
  295. src/harness/src/openharness/coordinator/coordinator_mode.py +520 -0
  296. src/harness/src/openharness/engine/__init__.py +80 -0
  297. src/harness/src/openharness/engine/cost_tracker.py +24 -0
  298. src/harness/src/openharness/engine/messages.py +222 -0
  299. src/harness/src/openharness/engine/query.py +1188 -0
  300. src/harness/src/openharness/engine/query_engine.py +313 -0
  301. src/harness/src/openharness/engine/stream_events.py +90 -0
  302. src/harness/src/openharness/hooks/__init__.py +50 -0
  303. src/harness/src/openharness/hooks/events.py +20 -0
  304. src/harness/src/openharness/hooks/executor.py +242 -0
  305. src/harness/src/openharness/hooks/hot_reload.py +31 -0
  306. src/harness/src/openharness/hooks/loader.py +68 -0
  307. src/harness/src/openharness/hooks/schemas.py +66 -0
  308. src/harness/src/openharness/hooks/types.py +38 -0
  309. src/harness/src/openharness/keybindings/__init__.py +14 -0
  310. src/harness/src/openharness/keybindings/default_bindings.py +11 -0
  311. src/harness/src/openharness/keybindings/loader.py +22 -0
  312. src/harness/src/openharness/keybindings/parser.py +18 -0
  313. src/harness/src/openharness/keybindings/resolver.py +13 -0
  314. src/harness/src/openharness/mcp/__init__.py +79 -0
  315. src/harness/src/openharness/mcp/client.py +298 -0
  316. src/harness/src/openharness/mcp/config.py +16 -0
  317. src/harness/src/openharness/mcp/types.py +76 -0
  318. src/harness/src/openharness/memory/__init__.py +25 -0
  319. src/harness/src/openharness/memory/agent.py +91 -0
  320. src/harness/src/openharness/memory/manager.py +183 -0
  321. src/harness/src/openharness/memory/memdir.py +52 -0
  322. src/harness/src/openharness/memory/migrate.py +137 -0
  323. src/harness/src/openharness/memory/paths.py +22 -0
  324. src/harness/src/openharness/memory/relevance.py +145 -0
  325. src/harness/src/openharness/memory/scan.py +116 -0
  326. src/harness/src/openharness/memory/schema.py +443 -0
  327. src/harness/src/openharness/memory/search.py +71 -0
  328. src/harness/src/openharness/memory/team.py +90 -0
  329. src/harness/src/openharness/memory/types.py +33 -0
  330. src/harness/src/openharness/memory/usage.py +153 -0
  331. src/harness/src/openharness/output_styles/__init__.py +5 -0
  332. src/harness/src/openharness/output_styles/loader.py +42 -0
  333. src/harness/src/openharness/permissions/__init__.py +26 -0
  334. src/harness/src/openharness/permissions/checker.py +200 -0
  335. src/harness/src/openharness/permissions/modes.py +13 -0
  336. src/harness/src/openharness/personalization/__init__.py +6 -0
  337. src/harness/src/openharness/personalization/extractor.py +138 -0
  338. src/harness/src/openharness/personalization/rules.py +64 -0
  339. src/harness/src/openharness/personalization/session_hook.py +65 -0
  340. src/harness/src/openharness/platforms.py +86 -0
  341. src/harness/src/openharness/plugins/__init__.py +53 -0
  342. src/harness/src/openharness/plugins/bundled/__init__.py +0 -0
  343. src/harness/src/openharness/plugins/installer.py +39 -0
  344. src/harness/src/openharness/plugins/loader.py +730 -0
  345. src/harness/src/openharness/plugins/schemas.py +24 -0
  346. src/harness/src/openharness/plugins/types.py +59 -0
  347. src/harness/src/openharness/prompts/__init__.py +14 -0
  348. src/harness/src/openharness/prompts/claudemd.py +48 -0
  349. src/harness/src/openharness/prompts/context.py +187 -0
  350. src/harness/src/openharness/prompts/environment.py +135 -0
  351. src/harness/src/openharness/prompts/system_prompt.py +109 -0
  352. src/harness/src/openharness/sandbox/Dockerfile +6 -0
  353. src/harness/src/openharness/sandbox/__init__.py +33 -0
  354. src/harness/src/openharness/sandbox/adapter.py +148 -0
  355. src/harness/src/openharness/sandbox/docker_backend.py +232 -0
  356. src/harness/src/openharness/sandbox/docker_image.py +103 -0
  357. src/harness/src/openharness/sandbox/path_validator.py +37 -0
  358. src/harness/src/openharness/sandbox/session.py +63 -0
  359. src/harness/src/openharness/services/__init__.py +30 -0
  360. src/harness/src/openharness/services/autodream/__init__.py +34 -0
  361. src/harness/src/openharness/services/autodream/backup.py +104 -0
  362. src/harness/src/openharness/services/autodream/lock.py +138 -0
  363. src/harness/src/openharness/services/autodream/prompt.py +128 -0
  364. src/harness/src/openharness/services/autodream/service.py +313 -0
  365. src/harness/src/openharness/services/compact/__init__.py +1725 -0
  366. src/harness/src/openharness/services/cron.py +137 -0
  367. src/harness/src/openharness/services/cron_scheduler.py +595 -0
  368. src/harness/src/openharness/services/lsp/__init__.py +216 -0
  369. src/harness/src/openharness/services/memory_extract/__init__.py +261 -0
  370. src/harness/src/openharness/services/oauth/__init__.py +0 -0
  371. src/harness/src/openharness/services/session_backend.py +97 -0
  372. src/harness/src/openharness/services/session_memory/__init__.py +139 -0
  373. src/harness/src/openharness/services/session_storage.py +230 -0
  374. src/harness/src/openharness/services/token_estimation.py +15 -0
  375. src/harness/src/openharness/services/tool_outputs.py +55 -0
  376. src/harness/src/openharness/skills/__init__.py +44 -0
  377. src/harness/src/openharness/skills/_frontmatter.py +97 -0
  378. src/harness/src/openharness/skills/bundled/__init__.py +75 -0
  379. src/harness/src/openharness/skills/bundled/content/commit.md +25 -0
  380. src/harness/src/openharness/skills/bundled/content/debug.md +25 -0
  381. src/harness/src/openharness/skills/bundled/content/diagnose.md +35 -0
  382. src/harness/src/openharness/skills/bundled/content/plan.md +39 -0
  383. src/harness/src/openharness/skills/bundled/content/review.md +33 -0
  384. src/harness/src/openharness/skills/bundled/content/simplify.md +26 -0
  385. src/harness/src/openharness/skills/bundled/content/skill-creator.md +175 -0
  386. src/harness/src/openharness/skills/bundled/content/test.md +38 -0
  387. src/harness/src/openharness/skills/loader.py +229 -0
  388. src/harness/src/openharness/skills/registry.py +29 -0
  389. src/harness/src/openharness/skills/types.py +24 -0
  390. src/harness/src/openharness/state/__init__.py +6 -0
  391. src/harness/src/openharness/state/app_state.py +30 -0
  392. src/harness/src/openharness/state/store.py +40 -0
  393. src/harness/src/openharness/swarm/__init__.py +70 -0
  394. src/harness/src/openharness/swarm/in_process.py +693 -0
  395. src/harness/src/openharness/swarm/lockfile.py +24 -0
  396. src/harness/src/openharness/swarm/mailbox.py +522 -0
  397. src/harness/src/openharness/swarm/permission_sync.py +1168 -0
  398. src/harness/src/openharness/swarm/registry.py +410 -0
  399. src/harness/src/openharness/swarm/spawn_utils.py +229 -0
  400. src/harness/src/openharness/swarm/subprocess_backend.py +171 -0
  401. src/harness/src/openharness/swarm/team_lifecycle.py +910 -0
  402. src/harness/src/openharness/swarm/types.py +398 -0
  403. src/harness/src/openharness/swarm/worktree.py +315 -0
  404. src/harness/src/openharness/tasks/__init__.py +18 -0
  405. src/harness/src/openharness/tasks/local_agent_task.py +28 -0
  406. src/harness/src/openharness/tasks/local_shell_task.py +17 -0
  407. src/harness/src/openharness/tasks/manager.py +475 -0
  408. src/harness/src/openharness/tasks/stop_task.py +11 -0
  409. src/harness/src/openharness/tasks/types.py +32 -0
  410. src/harness/src/openharness/themes/__init__.py +21 -0
  411. src/harness/src/openharness/themes/builtin.py +89 -0
  412. src/harness/src/openharness/themes/loader.py +55 -0
  413. src/harness/src/openharness/themes/schema.py +54 -0
  414. src/harness/src/openharness/tools/__init__.py +107 -0
  415. src/harness/src/openharness/tools/agent_tool.py +141 -0
  416. src/harness/src/openharness/tools/ask_user_question_tool.py +46 -0
  417. src/harness/src/openharness/tools/base.py +80 -0
  418. src/harness/src/openharness/tools/bash_tool.py +259 -0
  419. src/harness/src/openharness/tools/brief_tool.py +33 -0
  420. src/harness/src/openharness/tools/config_tool.py +54 -0
  421. src/harness/src/openharness/tools/cron_create_tool.py +105 -0
  422. src/harness/src/openharness/tools/cron_delete_tool.py +32 -0
  423. src/harness/src/openharness/tools/cron_list_tool.py +69 -0
  424. src/harness/src/openharness/tools/cron_toggle_tool.py +37 -0
  425. src/harness/src/openharness/tools/enter_plan_mode_tool.py +28 -0
  426. src/harness/src/openharness/tools/enter_worktree_tool.py +80 -0
  427. src/harness/src/openharness/tools/exit_plan_mode_tool.py +28 -0
  428. src/harness/src/openharness/tools/exit_worktree_tool.py +42 -0
  429. src/harness/src/openharness/tools/file_edit_tool.py +95 -0
  430. src/harness/src/openharness/tools/file_read_tool.py +72 -0
  431. src/harness/src/openharness/tools/file_write_tool.py +87 -0
  432. src/harness/src/openharness/tools/glob_tool.py +175 -0
  433. src/harness/src/openharness/tools/grep_tool.py +374 -0
  434. src/harness/src/openharness/tools/image_generation_tool.py +447 -0
  435. src/harness/src/openharness/tools/image_to_text_tool.py +237 -0
  436. src/harness/src/openharness/tools/list_mcp_resources_tool.py +36 -0
  437. src/harness/src/openharness/tools/lsp_tool.py +154 -0
  438. src/harness/src/openharness/tools/mcp_auth_tool.py +71 -0
  439. src/harness/src/openharness/tools/mcp_tool.py +72 -0
  440. src/harness/src/openharness/tools/notebook_edit_tool.py +97 -0
  441. src/harness/src/openharness/tools/read_mcp_resource_tool.py +38 -0
  442. src/harness/src/openharness/tools/remote_trigger_tool.py +74 -0
  443. src/harness/src/openharness/tools/send_message_tool.py +58 -0
  444. src/harness/src/openharness/tools/skill_tool.py +43 -0
  445. src/harness/src/openharness/tools/sleep_tool.py +32 -0
  446. src/harness/src/openharness/tools/task_create_tool.py +56 -0
  447. src/harness/src/openharness/tools/task_get_tool.py +33 -0
  448. src/harness/src/openharness/tools/task_list_tool.py +35 -0
  449. src/harness/src/openharness/tools/task_output_tool.py +35 -0
  450. src/harness/src/openharness/tools/task_stop_tool.py +30 -0
  451. src/harness/src/openharness/tools/task_update_tool.py +50 -0
  452. src/harness/src/openharness/tools/team_create_tool.py +31 -0
  453. src/harness/src/openharness/tools/team_delete_tool.py +30 -0
  454. src/harness/src/openharness/tools/todo_write_tool.py +46 -0
  455. src/harness/src/openharness/tools/tool_search_tool.py +38 -0
  456. src/harness/src/openharness/tools/web_fetch_tool.py +117 -0
  457. src/harness/src/openharness/tools/web_search_tool.py +119 -0
  458. src/harness/src/openharness/ui/__init__.py +5 -0
  459. src/harness/src/openharness/ui/app.py +320 -0
  460. src/harness/src/openharness/ui/backend_host.py +941 -0
  461. src/harness/src/openharness/ui/coordinator_drain.py +198 -0
  462. src/harness/src/openharness/ui/input.py +32 -0
  463. src/harness/src/openharness/ui/output.py +265 -0
  464. src/harness/src/openharness/ui/permission_dialog.py +14 -0
  465. src/harness/src/openharness/ui/protocol.py +247 -0
  466. src/harness/src/openharness/ui/react_launcher.py +179 -0
  467. src/harness/src/openharness/ui/runtime.py +799 -0
  468. src/harness/src/openharness/ui/textual_app.py +495 -0
  469. src/harness/src/openharness/utils/__init__.py +0 -0
  470. src/harness/src/openharness/utils/file_lock.py +86 -0
  471. src/harness/src/openharness/utils/fs.py +98 -0
  472. src/harness/src/openharness/utils/helpers.py +77 -0
  473. src/harness/src/openharness/utils/network_guard.py +340 -0
  474. src/harness/src/openharness/utils/shell.py +147 -0
  475. src/harness/src/openharness/vim/__init__.py +5 -0
  476. src/harness/src/openharness/vim/transitions.py +8 -0
  477. src/harness/src/openharness/voice/__init__.py +7 -0
  478. src/harness/src/openharness/voice/keyterms.py +10 -0
  479. src/harness/src/openharness/voice/stream_stt.py +8 -0
  480. src/harness/src/openharness/voice/voice_mode.py +44 -0
  481. src/llm/__init__.py +29 -0
  482. src/llm/image_generation.py +402 -0
  483. src/llm/provider_registry.py +419 -0
  484. src/llm/runtime_env.py +64 -0
  485. src/llm/structured_output.py +131 -0
  486. src/llm/vision.py +198 -0
  487. src/memory/__init__.py +2 -0
  488. src/memory/api/__init__.py +1 -0
  489. src/memory/api/base_memory_system_api.py +98 -0
  490. src/memory/api/base_symbolic_memory_system_api.py +190 -0
  491. src/memory/api/base_vector_memory_system_api.py +116 -0
  492. src/memory/api/faiss_memory_system_api.py +228 -0
  493. src/memory/api/slot_process_api.py +827 -0
  494. src/memory/api/symbolic_memory_system_api.py +572 -0
  495. src/memory/memory_system/__init__.py +48 -0
  496. src/memory/memory_system/component_taxonomy.py +430 -0
  497. src/memory/memory_system/llm.py +437 -0
  498. src/memory/memory_system/models.py +168 -0
  499. src/memory/memory_system/user_prompt.py +418 -0
  500. src/memory/memory_system/utils.py +282 -0
  501. src/memory/memory_system/vectorstore.py +311 -0
  502. src/memory/memory_system/working_slot.py +99 -0
  503. src/pipeline/__init__.py +129 -0
  504. src/pipeline/contracts.py +531 -0
  505. src/pipeline/discipline_taxonomy.py +916 -0
  506. src/pipeline/evidence_coverage_ledger.py +1150 -0
  507. src/pipeline/evidence_refinement.py +620 -0
  508. src/pipeline/experiment_to_symbolic.py +137 -0
  509. src/pipeline/multimodal_evidence/__init__.py +28 -0
  510. src/pipeline/multimodal_evidence/capabilities.py +107 -0
  511. src/pipeline/multimodal_evidence/claims.py +135 -0
  512. src/pipeline/multimodal_evidence/contract.py +291 -0
  513. src/pipeline/multimodal_evidence/data_sh_compiler.py +505 -0
  514. src/pipeline/multimodal_evidence/handoff_binding.py +135 -0
  515. src/pipeline/multimodal_evidence/manifest.py +254 -0
  516. src/pipeline/multimodal_evidence/native_analysis.py +479 -0
  517. src/pipeline/multimodal_evidence/perception.py +277 -0
  518. src/pipeline/multimodal_evidence/query_binding.py +65 -0
  519. src/pipeline/multimodal_evidence/rendering.py +120 -0
  520. src/pipeline/multimodal_evidence/safety.py +42 -0
  521. src/pipeline/multimodal_evidence/sampling.py +69 -0
  522. src/pipeline/multimodal_evidence/service.py +148 -0
  523. src/pipeline/multimodal_evidence/survey_integration.py +460 -0
  524. src/pipeline/paper_identity.py +52 -0
  525. src/pipeline/research_design_inventory.py +338 -0
  526. src/pipeline/research_domain_resolution.py +669 -0
  527. src/pipeline/research_identity.py +548 -0
  528. src/pipeline/research_question_contract.py +646 -0
  529. src/pipeline/retrieval_lanes.py +889 -0
  530. src/pipeline/run_loop.py +862 -0
  531. src/pipeline/science_events.py +30 -0
  532. src/pipeline/science_manifests.py +602 -0
  533. src/pipeline/science_run.py +918 -0
  534. src/pipeline/science_stages.py +709 -0
  535. src/pipeline/science_workflow.py +807 -0
  536. src/pipeline/sh_cluster_projection.py +306 -0
  537. src/pipeline/sh_graph_provenance.py +648 -0
  538. src/pipeline/subhypothesis_decomposition.py +392 -0
  539. src/pipeline/subhypothesis_evidence.py +856 -0
  540. src/pipeline/survey_evidence_plan.py +858 -0
  541. src/pipeline/survey_gap_adjudication.py +647 -0
  542. src/pipeline/survey_gap_candidates.py +840 -0
  543. src/pipeline/survey_gap_ledger.py +683 -0
  544. src/pipeline/survey_gap_triage.py +401 -0
  545. src/pipeline/survey_handoff_persistence.py +481 -0
  546. src/pipeline/survey_handoff_projection.py +457 -0
  547. src/pipeline/survey_idea_handoff.py +1112 -0
  548. src/pipeline/survey_idea_loader.py +289 -0
  549. src/research_run_ids.py +11 -0
@@ -0,0 +1,1282 @@
1
+ """
2
+ Code Report Generator Module
3
+
4
+ This module provides functionality to generate comprehensive code analysis reports
5
+ from multiple papers' pseudocode, organized by different dimensions.
6
+
7
+ Input format: List[dict] where each dict contains:
8
+ - "paper_id": str - the paper identifier
9
+ - "pseudocode_report": str - the pseudocode report for that paper
10
+ """
11
+
12
+ import os
13
+ import sys
14
+ import json
15
+ from typing import List, Dict, Optional, Tuple
16
+
17
+ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
18
+ from utils.config_utils import merge_with_default_survey_config
19
+ from utils.rich_logger import get_logger
20
+ from utils.api_call import ChatAgent
21
+ # from modules.work_collector import WorkCollector
22
+ # from modules.code_collector import CodeCollector, CodeAnalyzer
23
+
24
+
25
+ # Prompt template for batch code report generation
26
+ # All prompts are in English as requested
27
+ BATCH_CODE_REPORT_PROMPT = """
28
+ You are an expert at analyzing research paper code implementations and generating comprehensive reports with forward-looking guidance.
29
+
30
+ Your task is to analyze a batch of papers on the topic: "{topic}"
31
+
32
+ For each paper, you have basic paper information and code pseudocode reports:
33
+
34
+ {pseudocode_reports}
35
+
36
+ ---
37
+
38
+ TASK: Generate a comprehensive code analysis report for this batch of papers, with emphasis on identifying gaps and future research directions.
39
+
40
+ IMPORTANT: Go beyond surface-level descriptions. Analyze the ACTUAL IMPLEMENTATION DETAILS from the pseudocode.
41
+
42
+ ## Report Structure Requirements:
43
+
44
+ ### 1. Executive Summary
45
+ - What are the dominant implementation patterns?
46
+ - What are the major gaps and underexplored opportunities?
47
+ - What are the most promising future research directions?
48
+
49
+ ### 2. Data Structure Classification and Problem Modeling
50
+ - Analyze how different papers model the problem and what data structures they use
51
+ - Categorize them into meaningful groups
52
+ - For each data structure: WHY it was chosen, WHAT trade-offs it involves
53
+
54
+ ### 3. Core Algorithm Classification
55
+ - Identify patterns in core algorithms across papers
56
+ - For each algorithm provide:
57
+ * Specific function/class names from the pseudocode
58
+ * Step-by-step logic flow (input → processing → output)
59
+ * Key hyperparameters and their purposes
60
+ * Concrete implementation details (e.g., HOW attention is computed, not just "uses attention")
61
+
62
+ ### 4. Optimization and Acceleration Strategy Classification
63
+ - Computational optimizations (vectorization, batching, caching)
64
+ - Memory optimizations (gradient checkpointing, mixed precision)
65
+ - Training tricks and convergence improvements
66
+ - For each optimization: explain the MECHANISM and EXPECTED IMPACT
67
+
68
+ ### 5. Custom Dimensions (Topic-Specific)
69
+ - For LLM topics: workflow management, context window handling, agent architectures
70
+ - For RL topics: reward shaping, exploration mechanisms, credit assignment
71
+ - For CV topics: data augmentation pipelines, architecture patterns
72
+ - Add other meaningful dimensions based on code patterns observed
73
+
74
+ ### 6. Critical Gap Analysis
75
+ For each gap identified:
76
+ - Specific description of what's missing or underexplored
77
+ - Evidence from the code implementations supporting this gap
78
+ - Why this gap matters for the field
79
+
80
+ ### 7. Future Research Directions
81
+ Based on gap analysis, provide concrete future directions:
82
+ - Specific research problems to tackle
83
+ - Potential approaches to address each gap
84
+ - Expected challenges and how to overcome them
85
+ - Connections to implementation patterns observed in the code
86
+
87
+ ## General Requirements:
88
+ - Each claim should be traceable to specific parts of the pseudocode(Most important)
89
+ - Compare approaches with SPECIFIC technical differences
90
+ - Include actual code details: variable names, function names, class names
91
+
92
+ Output format:
93
+ Provide a structured report with clear sections for each dimension.
94
+ Emphasize the Future Research Directions section.
95
+ """
96
+ INTEGRATED_REPORT_PROMPT = """
97
+ You are an expert at synthesizing multiple batch reports into a comprehensive integrated report.
98
+
99
+ You have already generated reports for several batches of papers on the topic: "{topic}"
100
+
101
+ Here are the batch reports:
102
+ {combined_reports}
103
+
104
+ ---
105
+
106
+ TASK: Integrate all batch reports into a single comprehensive report
107
+
108
+ IMPORTANT: Maintain the depth and specificity from individual batch reports. Do NOT simplify or generalize the implementation details.
109
+
110
+ ## Required Report Structure:
111
+
112
+ ### 1. Executive Summary
113
+ - Dominant implementation patterns across all papers
114
+ - Major gaps and underexplored opportunities
115
+ - Most promising future research directions
116
+
117
+ ### 2. Problem Modeling and Data Structure Classification
118
+ - Unified view of problem modeling approaches
119
+ - Data structure categories with specific examples
120
+ - Trade-offs analysis preserved from original reports
121
+
122
+ ### 3. Core Algorithm Classification
123
+ - Algorithm patterns across all papers
124
+ - Specific function/class names, logic flows, hyperparameters
125
+ - Implementation details with code-level examples
126
+
127
+ ### 4. Optimization and Acceleration Strategy Classification
128
+ - Optimization techniques identified
129
+ - Specific mechanisms and expected impacts
130
+ - Computational and memory optimizations
131
+
132
+ ### 5. Custom Dimensions (Topic-Specific)
133
+ - Workflow patterns (for LLM topics)
134
+ - Agent architectures and context handling
135
+ - Other topic-relevant dimensions
136
+
137
+ ### 6. Critical Gap Analysis (IMPORTANT)
138
+ For each gap identified:
139
+ - Specific description of what's missing
140
+ - Evidence from implementation patterns
141
+ - Why this gap matters
142
+
143
+ ### 7. Future Research Directions (MOST IMPORTANT)
144
+ Based on gap analysis, provide:
145
+ - Specific research problems to tackle
146
+ - Potential approaches to address gaps
147
+ - Expected challenges and solutions
148
+ - Connections to observed implementation patterns
149
+
150
+ ### 8. Conclusion
151
+ - Key takeaways from the synthesis
152
+ - Forward-looking insights
153
+
154
+ The final report should be:
155
+ - Comprehensive: Cover all important aspects from all batches
156
+ - Coherent: Flow logically from section to section
157
+ - Non-redundant: Avoid repeating same points when merging batches
158
+ - Specific: Provide meaningful synthesis with actual implementation details when necessary
159
+ - Actionable: Emphasize future research directions
160
+ - Concise: Avoid keeping trivial parts when intergrating batches
161
+ - Deep: Integrate with analysis rather than simple enumeration
162
+
163
+ Output format:
164
+ Provide a well-structured comprehensive report with clear sections.
165
+ The report should be at most 6000 words and 700 lines
166
+ Emphasize the Future Research Directions section.
167
+ """
168
+
169
+
170
+ BATCH_FRAMEWORK_ENV_PROMPT = """
171
+ You are an expert at analyzing research paper code implementations and providing guidance on framework selection and environment configuration.
172
+
173
+ Your task is to analyze a batch of repositories to generate guidance on framework selection and environment setup.
174
+
175
+ For each repository, you have:
176
+ 1. Paper general information: repository name, paper title, paper abstract, paper pseudocode report
177
+ 2. Paper environment information: requirements content, README content:
178
+ {combined_content}
179
+ ---
180
+
181
+ TASK: Generate framework selection and environment configuration guidance for this batch
182
+
183
+ Required Content:
184
+
185
+ 1. **Framework Analysis**:
186
+ - Identify frameworks used (PyTorch, TensorFlow, JAX, etc.)
187
+ - Analyze version requirements and compatibility
188
+ - Assess framework suitability for different scenarios
189
+
190
+ 2. **Environment Configuration**:
191
+ - Key dependencies and their versions
192
+ - Special requirements (GPU, CUDA, etc.)
193
+ - Setup best practices
194
+
195
+ 3. **Base Framework Assessment**:
196
+ - Code quality and documentation quality
197
+ - Extensibility and maintainability
198
+ - Suitability for different research directions
199
+
200
+ Requirements:
201
+ - Comprehensive: Cover all important aspects mentioned above
202
+ - Coherent: Flow logically from section to section
203
+ - Specific: Provide concrete examples from the repositories
204
+ - Concise: Avoid keeping trivial parts when intergrating batches
205
+
206
+ Output format:
207
+ Provide a structured report with clear sections.
208
+ """
209
+
210
+ INTEGRATED_FRAMEWORK_ENV_PROMPT = """
211
+ You are an expert at synthesizing multiple batch reports into a comprehensive framework and environment guidance report.
212
+
213
+ You have already generated reports for several batches of repositories on the topic: "{topic}"
214
+
215
+ Here are the batch reports:
216
+ {combined_reports}
217
+
218
+ ---
219
+
220
+ TASK: Integrate all batch reports into a comprehensive framework selection and environment configuration guide
221
+
222
+ Requirements:
223
+ 1. Synthesize information from all batches into a unified report
224
+ 2. Remove duplicates and consolidate similar findings
225
+ 3. Ensure all key insights from each batch are preserved
226
+ 4. Structure the report with the following sections:
227
+ - Framework Selection Analysis
228
+ - Environment Configuration Guidance
229
+ - Base Framework Recommendations
230
+ - Sub-direction Analysis
231
+ 5. Add a summary section at the beginning
232
+ 6. Add a conclusion section with actionable recommendations
233
+
234
+ The final report should be:
235
+ - Practical: Provide actionable recommendations
236
+ - Comprehensive: Cover all important aspects
237
+ - Well-organized: Clear headings and structured sections
238
+ - Non-redundant: Avoid repeating the same points
239
+ - Coherent: Flow logically from section to section
240
+ - Actionable: Emphasize future research directions
241
+ - Concise: Avoid keeping trivial parts when intergrating batches
242
+ - Deep: Integrate with analysis rather than simple enumeration
243
+
244
+ Output format:
245
+ Provide a well-structured comprehensive report with clear sections.
246
+ The report should be at most 5000 words and 700 lines
247
+ """
248
+
249
+ class CodeReportGenerator:
250
+ """
251
+ A class to generate comprehensive code analysis reports from multiple papers.
252
+
253
+ This generator:
254
+ 1. Takes input as List[dict] with paper_id and pseudocode_report
255
+ 2. Processes them in batches
256
+ 3. Generates dimension-specific analysis for each batch directly from pseudocode reports
257
+ 4. Integrates all batch reports into a final comprehensive report
258
+ """
259
+
260
+ def __init__(self, config,
261
+ work_collector = None,
262
+ code_collector = None,
263
+ code_analyzer = None):
264
+ """
265
+ Initialize the CodeReportGenerator.
266
+
267
+ Args:
268
+ config: Configuration object containing API settings
269
+ work_collector: Optional WorkCollector instance (will create if not provided)
270
+ code_collector: Optional CodeCollector instance
271
+ code_analyzer: Optional CodeAnalyzer instance
272
+ """
273
+ self.config = config
274
+ self.logger = get_logger("CodeReportGenerator")
275
+ self.chat_agent = ChatAgent(config)
276
+ self.work_collector = work_collector
277
+ self.max_context_chars_for_integrate = int(self.config.APIInfo.llm_max_context_length * 2.5)
278
+
279
+ # Code collector and analyzer (optional, for backwards compatibility)
280
+ self.code_collector = code_collector
281
+ self.code_analyzer = code_analyzer
282
+
283
+ # Cache path for pseudocode (if needed)
284
+ if self.code_collector:
285
+ self.repo_cache_path = self.code_collector.repo_cache_path
286
+ else:
287
+ raise ValueError("codereporter lack valid code_collector to initialize")
288
+
289
+ # Batch size for processing papers
290
+ self.batch_size = 5
291
+
292
+ # Common file names for requirements and readme
293
+ self.requirement_files = ['requirements.txt', 'requirements.txt', 'setup.py', 'pyproject.toml', 'setup.cfg']
294
+ self.readme_files = ['README.md', 'README.rst', 'README.txt', 'README', "readme.txt", "readme.md", "readme.rst", "readme"]
295
+
296
+ def read_repo_files(self, repo_name: str) -> Dict[str, Dict[str, str]]:
297
+ """
298
+ Read requirement and README files from a cloned repository.
299
+
300
+ Args:
301
+ repo_name: The name of the repository (folder name in cache)
302
+
303
+ Returns:
304
+ Dict containing 'requirements' and 'readme' content:
305
+ {
306
+ 'requirements': {'file_name': 'content' or 'NOT_FOUND'},
307
+ 'readme': {'file_name': 'content' or 'NOT_FOUND'}
308
+ }
309
+ """
310
+ repo_path = os.path.join(self.repo_cache_path, repo_name)
311
+
312
+ if not os.path.exists(repo_path):
313
+ self.logger.error(f"Repository not found in cache: {repo_path}")
314
+ return {
315
+ 'requirements': {'NOT_FOUND': 'Repository not found'},
316
+ 'readme': {'NOT_FOUND': 'Repository not found'}
317
+ }
318
+
319
+ result = {
320
+ 'requirements': {},
321
+ 'readme': {}
322
+ }
323
+
324
+ # Search for requirements files
325
+ for req_file in self.requirement_files:
326
+ req_path = os.path.join(repo_path, req_file)
327
+ if os.path.exists(req_path):
328
+ try:
329
+ with open(req_path, 'r', encoding='utf-8', errors='ignore') as f:
330
+ content = f.read()
331
+ result['requirements'][req_file] = content
332
+ self.logger.info(f"Found requirements file: {req_file}")
333
+ except Exception as e:
334
+ self.logger.warning(f"Failed to read {req_file}: {e}")
335
+ result['requirements'][req_file] = f"Error reading file: {str(e)}"
336
+
337
+ # If no requirements file found, search for any file containing 'requirements'
338
+ if not result['requirements']:
339
+ try:
340
+ for fname in os.listdir(repo_path):
341
+ if 'requirements' in fname.lower() and not fname.startswith('.'):
342
+ req_path = os.path.join(repo_path, fname)
343
+ if os.path.isfile(req_path):
344
+ try:
345
+ with open(req_path, 'r', encoding='utf-8', errors='ignore') as f:
346
+ content = f.read()
347
+ result['requirements'][fname] = content
348
+ self.logger.info(f"Found requirements file: {fname}")
349
+ except Exception as e:
350
+ self.logger.warning(f"Failed to read {fname}: {e}")
351
+ except Exception as e:
352
+ self.logger.warning(f"Failed to list directory: {e}")
353
+
354
+ # If still no requirements found, mark as NOT_FOUND
355
+ if not result['requirements']:
356
+ result['requirements']['NOT_FOUND'] = "No requirements file found"
357
+
358
+ # Search for README files
359
+ for readme_file in self.readme_files:
360
+ readme_path = os.path.join(repo_path, readme_file)
361
+ if os.path.exists(readme_path):
362
+ try:
363
+ with open(readme_path, 'r', encoding='utf-8', errors='ignore') as f:
364
+ content = f.read()
365
+ # Limit README content to first 15000 chars to avoid too long input
366
+ if len(content) > 15000:
367
+ content = content[:15000] + "\n\n... (truncated)"
368
+ result['readme'][readme_file] = content
369
+ self.logger.info(f"Found README file: {readme_file}")
370
+ except Exception as e:
371
+ self.logger.warning(f"Failed to read {readme_file}: {e}")
372
+ result['readme'][readme_file] = f"Error reading file: {str(e)}"
373
+
374
+ # If no README found, search for any file starting with 'README'
375
+ if not result['readme']:
376
+ try:
377
+ for fname in os.listdir(repo_path):
378
+ if fname.lower().startswith('readme') and not fname.startswith('.'):
379
+ readme_path = os.path.join(repo_path, fname)
380
+ if os.path.isfile(readme_path):
381
+ try:
382
+ with open(readme_path, 'r', encoding='utf-8', errors='ignore') as f:
383
+ content = f.read()
384
+ if len(content) > 15000:
385
+ content = content[:15000] + "\n\n... (truncated)"
386
+ result['readme'][fname] = content
387
+ self.logger.info(f"Found README file: {fname}")
388
+ except Exception as e:
389
+ self.logger.warning(f"Failed to read {fname}: {e}")
390
+ except Exception as e:
391
+ self.logger.warning(f"Failed to list directory: {e}")
392
+
393
+ # If still no README found, mark as NOT_FOUND
394
+ if not result['readme']:
395
+ result['readme']['NOT_FOUND'] = "No README file found"
396
+
397
+ return result
398
+
399
+ def _generate_batch_framework_env_report(self,
400
+ topic: str,
401
+ repo_data_batches: List[List[Dict]],
402
+ max_readme: int = 1,
403
+ max_requirements: int = 2,
404
+ max_batches: int = 20) -> List[str]:
405
+ """
406
+ Generate framework and environment guidance reports for multiple batches of repositories.
407
+
408
+ Args:
409
+ topic: The research topic
410
+ repo_data_batches: List of batches, where each batch is a list of repo data dictionaries
411
+
412
+ Returns:
413
+ List of generated batch report strings
414
+ """
415
+ if not repo_data_batches:
416
+ self.logger.warning("No repository data batches provided")
417
+ return []
418
+
419
+ self.logger.info(f"Processing {len(repo_data_batches)} batches of repositories")
420
+
421
+ # Build prompts for each batch
422
+ prompts = []
423
+ batch_info = [] # Track info for logging
424
+
425
+ for batch_idx, repo_data in enumerate(repo_data_batches):
426
+ if not repo_data:
427
+ self.logger.warning(f"Empty batch at index {batch_idx}, skipping")
428
+ continue
429
+
430
+ # Build the content for this batch
431
+ repos_content = []
432
+
433
+ for i, repo in enumerate(repo_data):
434
+ repo_name = repo.get('repo_name', f'Repo_{i+1}')
435
+ requirements = repo.get('requirements', {})
436
+ readme = repo.get('readme', {})
437
+ paper_abstract = repo.get('paper_abstract', "")
438
+ paper_title = repo.get('paper_title', "")
439
+ pseudocode = repo.get('pseudocode', 'pseudocode not found')
440
+
441
+ # Format requirements content
442
+ req_content = ""
443
+ req_num = 0
444
+ for fname, content in requirements.items():
445
+ if fname != 'NOT_FOUND':
446
+ req_content += f"\n--- {fname} ---\n{content}\n"
447
+ req_num += 1
448
+ if req_num >= max_requirements:
449
+ break
450
+ if not req_content:
451
+ req_content = requirements.get('NOT_FOUND', 'No requirements found')
452
+
453
+ # Format README content
454
+ readme_content = ""
455
+ readme_num = 0
456
+ for fname, content in readme.items():
457
+ if fname != 'NOT_FOUND':
458
+ readme_content += f"\n--- {fname} ---\n{content}\n"
459
+ readme_num += 1
460
+ if readme_num >= max_readme:
461
+ break
462
+ if not readme_content:
463
+ readme_content = readme.get('NOT_FOUND', 'No README found')
464
+
465
+ content = f"=== Repository {i+1}: {repo_name} ===\n"
466
+ content += f"[Repository Information]:(for reference and understanding the repo)\n"
467
+ content += f"Paper_title: {paper_title}\nPaper abstract: {paper_abstract}\n"
468
+ content += f"Paper_Pseudocode: {pseudocode}\n"
469
+ content += f"[Readme and Requiremnets]:(report core contents source)\n"
470
+ content += f"Requirements:\n{req_content}\n\n"
471
+ content += f"README:\n{readme_content}"
472
+ repos_content.append(content)
473
+
474
+ combined_content = "\n\n".join(repos_content)
475
+
476
+ prompt = BATCH_FRAMEWORK_ENV_PROMPT.format(
477
+ combined_content = combined_content
478
+ )
479
+ prompts.append(prompt)
480
+ batch_info.append({
481
+ 'batch_idx': batch_idx,
482
+ 'num_repos': len(repo_data),
483
+ 'repo_names': [r.get('repo_name', f'Repo_{i}') for i, r in enumerate(repo_data)]
484
+ })
485
+
486
+ self.logger.info(f"Prepared batch {batch_idx + 1}/{len(repo_data_batches)} with {len(repo_data)} repositories")
487
+
488
+ if not prompts:
489
+ self.logger.error("No valid prompts generated from batches")
490
+ return []
491
+
492
+ self.logger.info(f"Generating {len(prompts)} framework/env batch reports via API...")
493
+
494
+ def _env_report_validate_fn(result, info_dict = None):
495
+ if not isinstance(result, str):
496
+ raise TypeError("batch env_report result not string")
497
+ if len(result) < 100:
498
+ raise ValueError("batch env_report result too short")
499
+ return True, result
500
+
501
+ try:
502
+ results = self.chat_agent.batch_remote_chat_with_retry(
503
+ prompts=prompts,
504
+ validate_fn=_env_report_validate_fn,
505
+ max_retry=6,
506
+ desc="Generating batch env reports",
507
+ temperature=0.3,
508
+ )
509
+
510
+ # Log success info
511
+ if isinstance(results, list):
512
+ self.logger.info(f"Successfully generated {len(results)} framework/env batch reports")
513
+ for i, result in enumerate(results):
514
+ if result:
515
+ self.logger.info(f"Framework batch {i+1} report length: {len(result)} chars")
516
+ else:
517
+ self.logger.warning(f"Framework batch {i+1} returned empty result")
518
+ else:
519
+ self.logger.warning(f"Unexpected result type from batch_remote_chat_with_retry: {type(results)}")
520
+
521
+ return results if isinstance(results, list) else []
522
+
523
+ except Exception as e:
524
+ self.logger.error(f"Failed to generate framework/env reports: {e}")
525
+ return []
526
+
527
+ def _integrate_framework_env_reports(self, topic: str, batch_reports: List[str], max_context_chars: int = None) -> str:
528
+ """
529
+ Integrate multiple batch reports into a final comprehensive framework/env report.
530
+ Uses multi-round fallback when combined reports exceed context window.
531
+
532
+ Args:
533
+ topic: The research topic
534
+ batch_reports: List of batch report strings
535
+ max_context_chars: Maximum characters per integration call (default: 150000)
536
+
537
+ Returns:
538
+ The integrated report
539
+ """
540
+ if max_context_chars is None:
541
+ max_context_chars = self.max_context_chars_for_integrate
542
+
543
+ if not batch_reports:
544
+ return "No reports to integrate."
545
+
546
+ if len(batch_reports) == 1:
547
+ # Only one batch, no integration needed
548
+ return batch_reports[0]
549
+
550
+ # First attempt: try integrating all reports at once
551
+ combined_reports = "\n\n==== BATCH SEPARATOR ====\n\n".join(
552
+ f"=== Batch {i+1} ===\n{report}"
553
+ for i, report in enumerate(batch_reports)
554
+ )
555
+
556
+ # Check if combined content fits in context
557
+ prompt_length = len(INTEGRATED_FRAMEWORK_ENV_PROMPT.format(topic=topic, combined_reports=combined_reports))
558
+
559
+ if prompt_length <= max_context_chars:
560
+ self.logger.info("Integrating framework/env batch reports into final report...")
561
+ try:
562
+ result = self.chat_agent.remote_chat(
563
+ text_content=INTEGRATED_FRAMEWORK_ENV_PROMPT.format(topic=topic, combined_reports=combined_reports),
564
+ temperature=0.3
565
+ )
566
+ return result
567
+ except Exception as e:
568
+ self.logger.warning(f"Failed to integrate all reports at once: {e}")
569
+ # Fall through to multi-round fallback
570
+ else:
571
+ self.logger.info(f"Combined reports exceed context ({prompt_length} chars), using multi-round fallback...")
572
+
573
+ # Multi-round fallback: integrate in smaller groups
574
+ return self._multi_round_integrate_framework_env(topic, batch_reports, max_context_chars)
575
+
576
+ def _multi_round_integrate_framework_env(self, topic: str, batch_reports: List[str], max_context_chars: int = None) -> str:
577
+ """
578
+ Multi-round integration when all batch reports don't fit in context.
579
+ Integrates reports in pairs/groups, then recursively integrates results.
580
+
581
+ Args:
582
+ topic: The research topic
583
+ batch_reports: List of batch report strings
584
+ max_context_chars: Maximum characters per integration call
585
+
586
+ Returns:
587
+ The integrated report
588
+ """
589
+ self.logger.info(f"Starting multi-round integration for {len(batch_reports)} batch reports...")
590
+
591
+ # Base case: if only one or two reports, integrate directly
592
+ if len(batch_reports) <= 2:
593
+ combined = "\n\n==== BATCH SEPARATOR ====\n\n".join(
594
+ f"=== Batch {i+1} ===\n{report}"
595
+ for i, report in enumerate(batch_reports)
596
+ )
597
+ try:
598
+ result = self.chat_agent.remote_chat(
599
+ text_content=INTEGRATED_FRAMEWORK_ENV_PROMPT.format(topic=topic, combined_reports=combined),
600
+ temperature=0.3
601
+ )
602
+ return result
603
+ except Exception as e:
604
+ self.logger.error(f"Failed to integrate: {e}")
605
+ return "\n\n".join(batch_reports)
606
+
607
+ # Group reports into pairs that fit within context
608
+ groups = []
609
+ current_group = []
610
+ current_group_size = 0
611
+
612
+ for i, report in enumerate(batch_reports):
613
+ report_size = len(report)
614
+ separator_size = len(f"\n\n==== BATCH SEPARATOR ====\n\n=== Batch {len(current_group) + 1} ===\n")
615
+
616
+ # Check if adding this report would exceed context
617
+ # Reserve space for prompt template (~500 chars)
618
+ if current_group_size + report_size + separator_size > int(max_context_chars*0.9):
619
+ if current_group:
620
+ groups.append(current_group)
621
+ current_group = [report]
622
+ current_group_size = report_size
623
+ else:
624
+ current_group.append(report)
625
+ current_group_size += report_size + separator_size
626
+
627
+ if current_group:
628
+ groups.append(current_group)
629
+
630
+ self.logger.info(f"Grouped {len(batch_reports)} reports into {len(groups)} integration groups")
631
+
632
+ # Integrate each group
633
+ integrated_groups = []
634
+ for i, group in enumerate(groups):
635
+ if len(group) == 1:
636
+ integrated_groups.append(group[0])
637
+ self.logger.info(f"Group {i+1}: single report, no integration needed")
638
+ else:
639
+ combined = "\n\n==== BATCH SEPARATOR ====\n\n".join(
640
+ f"=== Batch {j+1} ===\n{report}"
641
+ for j, report in enumerate(group)
642
+ )
643
+ try:
644
+ result = self.chat_agent.remote_chat(
645
+ text_content=INTEGRATED_FRAMEWORK_ENV_PROMPT.format(topic=topic, combined_reports=combined),
646
+ temperature=0.3
647
+ )
648
+ integrated_groups.append(result)
649
+ self.logger.info(f"Group {i+1}: integrated {len(group)} reports into {len(result)} chars")
650
+ except Exception as e:
651
+ self.logger.error(f"Failed to integrate group {i+1}: {e}")
652
+ integrated_groups.append("\n\n".join(group))
653
+
654
+ # If only one group, return it
655
+ if len(integrated_groups) == 1:
656
+ return integrated_groups[0]
657
+
658
+ # Recursively integrate the integrated groups
659
+ self.logger.info(f"Recursively integrating {len(integrated_groups)} integrated groups...")
660
+ return self._multi_round_integrate_framework_env(topic, integrated_groups, max_context_chars)
661
+
662
+ def generate_framework_env_report(
663
+ self,
664
+ paper_mainfests: List[Dict],
665
+ topic: str,
666
+ batch_size: int = None,
667
+ verbose: bool = True,
668
+ use_concise_pseudocode: bool = True
669
+ ) -> str:
670
+ """
671
+ Generate a comprehensive framework selection and environment configuration guidance report.
672
+
673
+ This function:
674
+ 1. Takes input as List[dict] with repo information (repo_name, paper_id, etc.)
675
+ 2. Reads requirement.txt and README files for each repository
676
+ 3. Processes repositories in batches
677
+ 4. Generates framework/env guidance for each batch
678
+ 5. Integrates all batch reports into a final comprehensive report
679
+
680
+ Args:
681
+ repos: List of dictionaries, each containing:
682
+ - "repo_name": str - the repository name
683
+ - "paper_id": str (optional) - the paper identifier
684
+ - Other keys are ignored
685
+ topic: The research topic
686
+ batch_size: Number of repos per batch (default: self.batch_size)
687
+ verbose: Whether to print progress information
688
+
689
+ Returns:
690
+ The final integrated report string
691
+ """
692
+ if batch_size is None:
693
+ batch_size = self.batch_size
694
+
695
+ repo_data = []
696
+ for paper_mainfest in paper_mainfests:
697
+ # Validate input format
698
+ if not paper_mainfest:
699
+ return "Error: No paper_mainfest provided."
700
+
701
+ paper_title = paper_mainfest.get("paper_title", "")
702
+ paper_abstract = paper_mainfest.get("paper_abstract", "")
703
+ paper_id = paper_mainfest.get("paper_id", "")
704
+ repo_num = len(paper_mainfest.get("repo_names", []))
705
+
706
+ if len(paper_mainfest.get("pseudocodes", [])) != repo_num or len(paper_mainfest.get("concise_pseudocodes", [])) != repo_num:
707
+ raise ValueError(f"Mismatch in number of repos and (concise) pseudocodes for paper {paper_mainfest.get('paper_id', 'unknown')}")
708
+
709
+ for idx in range(repo_num):
710
+ repo_name = paper_mainfest.get("repo_names", [])[idx]
711
+ if use_concise_pseudocode:
712
+ pseudocode = paper_mainfest.get("concise_pseudocodes", [])[idx]
713
+ else:
714
+ pseudocode = paper_mainfest.get("pseudocode", [])[idx]
715
+ files_content = self.read_repo_files(repo_name)
716
+ repo_data.append({
717
+ 'repo_name': repo_name,
718
+ 'paper_id': paper_id,
719
+ 'paper_abstract': paper_abstract,
720
+ 'pseudocode': pseudocode,
721
+ 'paper_title': paper_title,
722
+ 'requirements': files_content.get('requirements', {}),
723
+ 'readme': files_content.get('readme', {})
724
+ })
725
+
726
+ # Split repos into batches
727
+ batches = []
728
+ for i in range(0, len(repo_data), batch_size):
729
+ batches.append(repo_data[i:i + batch_size])
730
+
731
+ if verbose:
732
+ self.logger.info(f"Processing {len(batches)} batches...")
733
+
734
+ batch_reports = self._generate_batch_framework_env_report(topic, batches)
735
+
736
+
737
+ if not batch_reports:
738
+ self.logger.error("No reports generated")
739
+ return "Error: No reports could be generated for the given repositories."
740
+
741
+ # Integrate all batch reports
742
+ final_report = self._integrate_framework_env_reports(topic, batch_reports)
743
+
744
+ if verbose:
745
+ self.logger.info(f"Final framework/env report generated ({len(final_report)} chars)")
746
+
747
+ return final_report
748
+
749
+ def _generate_batch_report(self, topic: str, paper_batches: List[List[Dict]]) -> List[str]:
750
+ """
751
+ Generate code reports for multiple batches of papers directly from pseudocode reports.
752
+
753
+ Args:
754
+ topic: The research topic
755
+ paper_batches: List of batches, where each batch is a list of paper data dictionaries
756
+
757
+ Returns:
758
+ List of generated batch report strings
759
+ """
760
+ if not paper_batches:
761
+ self.logger.warning("No paper batches provided to _generate_batch_report")
762
+ return []
763
+
764
+ self.logger.info(f"Processing {len(paper_batches)} batches of papers")
765
+
766
+ # Validate and build prompts for each batch
767
+ prompts = []
768
+ batch_info = [] # Track info for logging
769
+
770
+ for batch_idx, papers_data in enumerate(paper_batches):
771
+ if not papers_data:
772
+ self.logger.warning(f"Empty batch at index {batch_idx}, skipping")
773
+ continue
774
+
775
+ # Build the prompt with all papers in the batch
776
+ papers_content = []
777
+
778
+ for i, paper in enumerate(papers_data):
779
+ paper_id = paper.get('paper_id', f'Paper_{i+1}')
780
+ pseudocode_report = paper.get('pseudocode_report', '')
781
+ paper_title = paper.get('paper_title', f'Paper {i+1}')
782
+ paper_abstract = paper.get('paper_abstract', 'No abstract available')
783
+
784
+ content = f"=== Paper {i+1} (ID: {paper_id})\n paper title: {paper_title}\n paper abstract: {paper_abstract}\n ===Pseudocode Report:\n{pseudocode_report}"
785
+ papers_content.append(content)
786
+
787
+ combined_content = "\n\n".join(papers_content)
788
+
789
+ prompt = BATCH_CODE_REPORT_PROMPT.format(
790
+ topic=topic,
791
+ pseudocode_reports=combined_content
792
+ )
793
+ prompts.append(prompt)
794
+ batch_info.append({
795
+ 'batch_idx': batch_idx,
796
+ 'num_papers': len(papers_data),
797
+ 'paper_ids': [p.get('paper_id', f'Paper_{i}') for i, p in enumerate(papers_data)]
798
+ })
799
+
800
+ self.logger.info(f"Prepared batch {batch_idx + 1}/{len(paper_batches)} with {len(papers_data)} papers")
801
+
802
+ if not prompts:
803
+ self.logger.error("No valid prompts generated from batches")
804
+ return []
805
+
806
+ # Validate function for batch report
807
+ def _validate_batch_report(result, info_dict = None):
808
+ if not isinstance(result, str):
809
+ raise ValueError(f"Generated batch code report is not a string type: {type(result)}.")
810
+ if not result or len(result) < 100:
811
+ raise ValueError(f"Generated batch code report is too short: {len(result)}, likely an error occurred, raw: {result}")
812
+ return True, result
813
+
814
+ self.logger.info(f"Generating {len(prompts)} batch reports via API...")
815
+
816
+ try:
817
+ results = self.chat_agent.batch_remote_chat_with_retry(
818
+ prompts=prompts,
819
+ validate_fn=_validate_batch_report,
820
+ max_retry=6,
821
+ desc="Generating batch code reports",
822
+ temperature=0.3,
823
+ )
824
+
825
+ # Log success info
826
+ if isinstance(results, list):
827
+ self.logger.info(f"Successfully generated {len(results)} batch reports")
828
+ for i, result in enumerate(results):
829
+ if result:
830
+ self.logger.info(f"Batch {i+1} report length: {len(result)} chars")
831
+ else:
832
+ self.logger.warning(f"Batch {i+1} returned empty result")
833
+ else:
834
+ self.logger.warning(f"Unexpected result type: {type(results)}")
835
+
836
+ return results if isinstance(results, list) else []
837
+
838
+ except Exception as e:
839
+ self.logger.error(f"Failed to generate batch reports: {e}")
840
+ return []
841
+
842
+ def _integrate_reports(self, topic: str, batch_reports: List[str], max_context_chars: int = None) -> str:
843
+ """
844
+ Integrate multiple batch reports into a final comprehensive report.
845
+ Uses multi-round fallback when combined reports exceed context window.
846
+
847
+ Args:
848
+ topic: The research topic
849
+ batch_reports: List of batch report strings
850
+ max_context_chars: Maximum characters per integration call
851
+
852
+ Returns:
853
+ The integrated report
854
+ """
855
+ if not batch_reports:
856
+ return "No reports to integrate."
857
+
858
+ if max_context_chars is None:
859
+ max_context_chars = self.max_context_chars_for_integrate
860
+
861
+ if len(batch_reports) == 1:
862
+ # Only one batch, no integration needed
863
+ return batch_reports[0]
864
+
865
+ # First attempt: try integrating all reports at once
866
+ combined_reports = "\n\n==== BATCH SEPARATOR ====\n\n".join(
867
+ f"=== Batch {i+1} ===\n{report}"
868
+ for i, report in enumerate(batch_reports)
869
+ )
870
+
871
+ # Check if combined content fits in context
872
+ prompt_length = len(INTEGRATED_REPORT_PROMPT.format(topic=topic, combined_reports=combined_reports))
873
+
874
+ if prompt_length <= max_context_chars:
875
+ self.logger.info("Integrating batch reports into final report...")
876
+ try:
877
+ result = self.chat_agent.remote_chat_with_retry(
878
+ prompt=INTEGRATED_REPORT_PROMPT.format(topic=topic, combined_reports=combined_reports),
879
+ temperature=0.3,
880
+ max_retry=6,
881
+ )
882
+ return result
883
+ except Exception as e:
884
+ self.logger.warning(f"Failed to integrate all reports at once: {e}")
885
+ # Fall through to multi-round fallback
886
+ else:
887
+ self.logger.info(f"Combined reports exceed context ({prompt_length} chars), using multi-round fallback...")
888
+
889
+ # Multi-round fallback: integrate in smaller groups
890
+ return self._multi_round_integrate_reports(topic, batch_reports, max_context_chars)
891
+
892
+ def _multi_round_integrate_reports(self, topic: str, batch_reports: List[str], max_context_chars: int = None) -> str:
893
+ """
894
+ Multi-round integration when all batch reports don't fit in context.
895
+ Integrates reports in pairs/groups, then recursively integrates results.
896
+
897
+ Args:
898
+ topic: The research topic
899
+ batch_reports: List of batch report strings
900
+ max_context_chars: Maximum characters per integration call
901
+
902
+ Returns:
903
+ The integrated report
904
+ """
905
+ self.logger.info(f"Starting multi-round integration for {len(batch_reports)} batch reports...")
906
+
907
+ # Base case: if only one or two reports, integrate directly
908
+ if len(batch_reports) <= 2:
909
+ combined = "\n\n==== BATCH SEPARATOR ====\n\n".join(
910
+ f"=== Batch {i+1} ===\n{report}"
911
+ for i, report in enumerate(batch_reports)
912
+ )
913
+ try:
914
+ result = self.chat_agent.remote_chat_with_retry(
915
+ prompt=INTEGRATED_REPORT_PROMPT.format(topic=topic, combined_reports=combined),
916
+ temperature=0.3,
917
+ max_retry=6,
918
+ )
919
+ return result
920
+ except Exception as e:
921
+ self.logger.error(f"Failed to integrate: {e}")
922
+ return "\n\n".join(batch_reports)
923
+
924
+ # Group reports into pairs that fit within context
925
+ groups = []
926
+ current_group = []
927
+ current_group_size = 0
928
+
929
+ for i, report in enumerate(batch_reports):
930
+ report_size = len(report)
931
+ separator_size = len(f"\n\n==== BATCH SEPARATOR ====\n\n=== Batch {len(current_group) + 1} ===\n")
932
+
933
+ # Check if adding this report would exceed context
934
+ # Reserve space for prompt template (~1500 chars)
935
+ if current_group_size + report_size + separator_size > int(max_context_chars*0.9):
936
+ if current_group:
937
+ groups.append(current_group)
938
+ current_group = [report]
939
+ current_group_size = report_size
940
+ else:
941
+ current_group.append(report)
942
+ current_group_size += report_size + separator_size
943
+
944
+ if current_group:
945
+ groups.append(current_group)
946
+
947
+ self.logger.info(f"Grouped {len(batch_reports)} reports into {len(groups)} integration groups")
948
+
949
+ # Integrate each group
950
+ integrated_groups = []
951
+ for i, group in enumerate(groups):
952
+ if len(group) == 1:
953
+ integrated_groups.append(group[0])
954
+ self.logger.info(f"Group {i+1}: single report, no integration needed")
955
+ else:
956
+ combined = "\n\n==== BATCH SEPARATOR ====\n\n".join(
957
+ f"=== Batch {j+1} ===\n{report}"
958
+ for j, report in enumerate(group)
959
+ )
960
+ try:
961
+ result = self.chat_agent.remote_chat_with_retry(
962
+ prompt=INTEGRATED_REPORT_PROMPT.format(topic=topic, combined_reports=combined),
963
+ temperature=0.3,
964
+ max_retry=6,
965
+ )
966
+ integrated_groups.append(result)
967
+ self.logger.info(f"Group {i+1}: integrated {len(group)} reports into {len(result)} chars")
968
+ except Exception as e:
969
+ self.logger.error(f"Failed to integrate group {i+1}: {e}")
970
+ integrated_groups.append("\n\n".join(group))
971
+
972
+ # If only one group, return it
973
+ if len(integrated_groups) == 1:
974
+ return integrated_groups[0]
975
+
976
+ # Recursively integrate the integrated groups
977
+ self.logger.info(f"Recursively integrating {len(integrated_groups)} integrated groups...")
978
+ return self._multi_round_integrate_reports(topic, integrated_groups, max_context_chars)
979
+
980
+ def generate_report(
981
+ self,
982
+ papers: List[Dict],
983
+ topic: str = None,
984
+ batch_size: int = None,
985
+ verbose: bool = True
986
+ ) -> str:
987
+ """
988
+ Generate a comprehensive code analysis report for a list of papers.
989
+
990
+ This function:
991
+ 1. Takes input as List[dict] with paper_id and pseudocode_report
992
+ 2. Processes papers in batches
993
+ 3. Generates a dimension-specific report for each batch directly from pseudocode reports
994
+ 4. Integrates all batch reports into a final comprehensive report
995
+
996
+ Args:
997
+ papers: List of dictionaries, each containing:
998
+ - "paper_id": str - the paper identifier
999
+ - "pseudocode_report": str - the pseudocode report for that paper
1000
+ topic: The research topic
1001
+ batch_size: Number of papers per batch (default: self.batch_size)
1002
+ verbose: Whether to print progress information
1003
+
1004
+ Returns:
1005
+ The final integrated report string
1006
+ """
1007
+ if topic is None:
1008
+ topic = self.config.BasicInfo.topic
1009
+ if batch_size is None:
1010
+ batch_size = self.batch_size
1011
+
1012
+ # Validate input format
1013
+ if not papers:
1014
+ return "Error: No papers provided."
1015
+
1016
+ for i, paper in enumerate(papers):
1017
+ if not isinstance(paper, dict):
1018
+ return f"Error: Expected dict at index {i}, got {type(paper)}"
1019
+ if 'pseudocodes' not in paper:
1020
+ return f"Error: Missing 'pseudocodes' key in paper at index {i}"
1021
+
1022
+ if verbose:
1023
+ self.logger.info(f"Generating code report for topic: {topic}")
1024
+ self.logger.info(f"Total papers: {len(papers)}, batch size: {batch_size}")
1025
+
1026
+ # Split papers into batches
1027
+ batches = []
1028
+ for i in range(0, len(papers), batch_size):
1029
+ batches.append(papers[i:i + batch_size])
1030
+
1031
+ if verbose:
1032
+ self.logger.info(f"Processing {len(batches)} batches...")
1033
+
1034
+
1035
+ batch_reports = self._generate_batch_report(topic, batches)
1036
+
1037
+ if not batch_reports:
1038
+ self.logger.error("No reports generated")
1039
+ return "Error: No reports could be generated for the given papers."
1040
+
1041
+ # Integrate all batch reports
1042
+ final_report = self._integrate_reports(topic, batch_reports)
1043
+
1044
+ # Build repository name index from input papers (code-generated, not LLM-generated)
1045
+ # This avoids LLM hallucination by using the actual input data
1046
+ repo_names_set = set()
1047
+ repo_paper_mapping = {} # repo_name -> paper_id
1048
+
1049
+ for paper in papers:
1050
+ paper_id = paper.get('paper_id', '')
1051
+ # Try to get repo_names from various possible keys
1052
+ repo_names = paper.get('repo_names', [])
1053
+ if not repo_names:
1054
+ # Try alternative keys that might contain repo info
1055
+ repo_names = paper.get('repos', [])
1056
+ if not repo_names and 'pseudocodes' in paper:
1057
+ # If no explicit repo_names, try to infer from paper structure
1058
+ # Some papers may store repo info differently
1059
+ pass
1060
+ for repo_name in repo_names:
1061
+ if repo_name and repo_name not in ['NOT_FOUND', None, '']:
1062
+ repo_names_set.add(repo_name)
1063
+ if repo_name not in repo_paper_mapping:
1064
+ repo_paper_mapping[repo_name] = []
1065
+ if paper_id not in repo_paper_mapping[repo_name]:
1066
+ repo_paper_mapping[repo_name].append(paper_id)
1067
+
1068
+ # Append repository index to the report if we found any repos
1069
+ if repo_names_set:
1070
+ repo_index_header = "\n\n---\n\n## Repository Index\n\n"
1071
+ repo_index_content = "The following repositories were analyzed in this report:\n\n"
1072
+
1073
+ # Sort repo names for consistent output
1074
+ sorted_repo_names = sorted(repo_names_set)
1075
+ for idx, repo_name in enumerate(sorted_repo_names, 1):
1076
+ paper_ids = repo_paper_mapping.get(repo_name, [])
1077
+ if paper_ids:
1078
+ repo_index_content += f"{idx}. **{repo_name}** (Paper: {', '.join(paper_ids)})\n"
1079
+ else:
1080
+ repo_index_content += f"{idx}. **{repo_name}**\n"
1081
+
1082
+ final_report += repo_index_header + repo_index_content
1083
+ if verbose:
1084
+ self.logger.info(f"Appended repository index with {len(repo_names_set)} repos")
1085
+
1086
+ if verbose:
1087
+ self.logger.info(f"Final report generated ({len(final_report)} chars)")
1088
+
1089
+ return final_report
1090
+
1091
+ def save_report(self, code_report: str, env_report: str, output_path: str = None):
1092
+ """
1093
+ Save the report to a file.
1094
+
1095
+ Args:
1096
+ code_report: The code report string
1097
+ env_report: The environment report string
1098
+ output_path: Path to save the report
1099
+ """
1100
+ topic = getattr(self.config.BasicInfo, 'topic', 'survey')
1101
+
1102
+ # Determine save directory
1103
+ if output_path and output_path.strip():
1104
+ save_dir = os.path.dirname(output_path)
1105
+ else:
1106
+ # Fallback to output_base_dir if save_path is empty
1107
+ output_base_dir = getattr(self.config.BasicInfo, 'save_path', None)
1108
+ if output_base_dir and output_base_dir.strip():
1109
+ save_dir = output_base_dir
1110
+ else:
1111
+ # Last resort: use current directory
1112
+ save_dir = os.getcwd()
1113
+ self.logger.warning(f"Both output_path and output_base_dir are empty, using current directory: {save_dir}")
1114
+
1115
+ save_dir = os.path.join(save_dir, "analysis")
1116
+
1117
+ os.makedirs(save_dir, exist_ok=True)
1118
+
1119
+ # Create md and json paths with topic name
1120
+ if self.config.BasicInfo.adapter_mode:
1121
+ save_env_path = os.path.join(save_dir, "survey_env_report.md")
1122
+ save_report_path = os.path.join(save_dir, "survey_code_report.md")
1123
+ else:
1124
+ save_env_path = os.path.join(save_dir, f"{topic}_env_report.md")
1125
+ save_report_path = os.path.join(save_dir, f"{topic}_code_report.md")
1126
+
1127
+ with open(save_env_path, "w", encoding="utf-8") as f:
1128
+ f.write(env_report)
1129
+ with open(save_report_path, "w", encoding="utf-8") as f:
1130
+ f.write(code_report)
1131
+
1132
+ self.logger.info(f"Code report saved to {save_report_path}\nEnv report saved to {save_env_path}")
1133
+
1134
+
1135
+ def generate_code_report(
1136
+ papers: List[Dict],
1137
+ topic: str,
1138
+ config = None,
1139
+ output_path: str = None,
1140
+ batch_size: int = 5,
1141
+ verbose: bool = True
1142
+ ) -> str:
1143
+ """
1144
+ Convenience function to generate a code report for a list of papers.
1145
+
1146
+ Args:
1147
+ papers: List of dictionaries, each containing:
1148
+ - "paper_id": str - the paper identifier
1149
+ - "pseudocode_report": str - the pseudocode report for that paper
1150
+ topic: The research topic
1151
+ config: Configuration object (will use default if not provided)
1152
+ output_path: Optional path to save the report
1153
+ batch_size: Number of papers per batch
1154
+ verbose: Whether to print progress
1155
+
1156
+ Returns:
1157
+ The generated report string
1158
+ """
1159
+ # Create config if not provided (will use defaults from environment)
1160
+ if config is None:
1161
+ # Try to get config from environment or use a dummy one
1162
+ try:
1163
+ import hydra
1164
+ from omegaconf import OmegaConf
1165
+
1166
+ # Try to load default config
1167
+ config_path = os.path.join(
1168
+ os.path.dirname(os.path.dirname(__file__)),
1169
+ "config",
1170
+ "deep_survey_batch.yaml"
1171
+ )
1172
+ if os.path.exists(config_path):
1173
+ config = merge_with_default_survey_config(OmegaConf.load(config_path))
1174
+ else:
1175
+ config = OmegaConf.create({})
1176
+ except:
1177
+ config = OmegaConf.create({})
1178
+
1179
+ # Create generator and generate report
1180
+ generator = CodeReportGenerator(config)
1181
+ report = generator.generate_report(
1182
+ papers=papers,
1183
+ topic=topic,
1184
+ batch_size=batch_size,
1185
+ verbose=verbose
1186
+ )
1187
+
1188
+ # Save if output path provided
1189
+ if output_path:
1190
+ generator.save_report(report, output_path)
1191
+
1192
+ return report
1193
+
1194
+
1195
+ def generate_framework_env_guidance(
1196
+ repos: List[Dict],
1197
+ topic: str,
1198
+ config = None,
1199
+ output_path: str = None,
1200
+ batch_size: int = 5,
1201
+ verbose: bool = True
1202
+ ) -> str:
1203
+ """
1204
+ Convenience function to generate framework selection and environment configuration guidance.
1205
+
1206
+ This function analyzes requirements.txt and README files from multiple repositories
1207
+ to generate comprehensive guidance on framework selection and environment setup.
1208
+
1209
+ Input format: List[dict] where each dict contains:
1210
+ - "repo_name": str - the repository name (folder name in cache)
1211
+ - "paper_id": str (optional) - the paper identifier
1212
+ - Other keys are ignored but can be included
1213
+
1214
+ Args:
1215
+ repos: List of dictionaries with repository information
1216
+ topic: The research topic
1217
+ config: Configuration object (will use default if not provided)
1218
+ output_path: Optional path to save the report
1219
+ batch_size: Number of repos per batch (default: 5)
1220
+ verbose: Whether to print progress
1221
+
1222
+ Returns:
1223
+ The generated framework/env guidance report string
1224
+
1225
+ Example:
1226
+ repos = [
1227
+ {"paper_id": "2601.12345", "repo_name": "some-repo"},
1228
+ {"paper_id": "2601.23456", "repo_name": "another-repo"},
1229
+ {"paper_id": "2601.34567", "repo_name": "third-repo"}
1230
+ ]
1231
+ topic = "LLM-based Agents"
1232
+ report = generate_framework_env_guidance(repos, topic, output_path="./outputs/framework_env_guide.txt")
1233
+ print(report)
1234
+ """
1235
+ # Create config if not provided (will use defaults from environment)
1236
+ if config is None:
1237
+ # Try to get config from environment or use a dummy one
1238
+ try:
1239
+ import hydra
1240
+ from omegaconf import OmegaConf
1241
+
1242
+ # Try to load default config
1243
+ config_path = os.path.join(
1244
+ os.path.dirname(os.path.dirname(__file__)),
1245
+ "config",
1246
+ "deep_survey_batch.yaml"
1247
+ )
1248
+ if os.path.exists(config_path):
1249
+ config = merge_with_default_survey_config(OmegaConf.load(config_path))
1250
+ else:
1251
+ config = OmegaConf.create({})
1252
+ except:
1253
+ config = OmegaConf.create({})
1254
+
1255
+ # Create generator and generate framework/env report
1256
+ generator = CodeReportGenerator(config)
1257
+ report = generator.generate_framework_env_report(
1258
+ repos=repos,
1259
+ topic=topic,
1260
+ batch_size=batch_size,
1261
+ verbose=verbose
1262
+ )
1263
+
1264
+ # Save if output path provided
1265
+ if output_path:
1266
+ generator.save_report(report, output_path)
1267
+
1268
+ return report
1269
+
1270
+
1271
+ # Example usage
1272
+ if __name__ == "__main__":
1273
+ # Example: Generate a report for a list of papers with pseudocode reports
1274
+ # papers = [
1275
+ # {"paper_id": "2601.12345", "pseudocode_report": "..."},
1276
+ # {"paper_id": "2601.23456", "pseudocode_report": "..."},
1277
+ # {"paper_id": "2601.34567", "pseudocode_report": "..."}
1278
+ # ]
1279
+ # topic = "LLM-based Agents"
1280
+ # report = generate_code_report(papers, topic, output_path="./outputs/code_report.txt")
1281
+ # print(report)
1282
+ pass