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.
- qwen_sci-0.2.2.dist-info/METADATA +492 -0
- qwen_sci-0.2.2.dist-info/RECORD +549 -0
- qwen_sci-0.2.2.dist-info/WHEEL +4 -0
- qwen_sci-0.2.2.dist-info/entry_points.txt +6 -0
- qwen_sci-0.2.2.dist-info/licenses/LICENSE +21 -0
- src/1.txt +1 -0
- src/__init__.py +1 -0
- src/__main__.py +5 -0
- src/agents/__init__.py +1 -0
- src/agents/experiment_design_agent/__init__.py +268 -0
- src/agents/experiment_design_agent/artifacts.py +747 -0
- src/agents/experiment_design_agent/cache.py +319 -0
- src/agents/experiment_design_agent/completeness.py +130 -0
- src/agents/experiment_design_agent/contracts.py +771 -0
- src/agents/experiment_design_agent/counterexample_analyzer.py +187 -0
- src/agents/experiment_design_agent/design_evidence_paper_screener.py +470 -0
- src/agents/experiment_design_agent/discipline_catalog.py +178 -0
- src/agents/experiment_design_agent/evidence_cards.py +338 -0
- src/agents/experiment_design_agent/evidence_planner.py +452 -0
- src/agents/experiment_design_agent/formal_reasoning_planner.py +884 -0
- src/agents/experiment_design_agent/fulltext_acquisition.py +863 -0
- src/agents/experiment_design_agent/idea_adapter.py +100 -0
- src/agents/experiment_design_agent/idea_intake.py +87 -0
- src/agents/experiment_design_agent/llm_json.py +328 -0
- src/agents/experiment_design_agent/orchestrator.py +1220 -0
- src/agents/experiment_design_agent/reasoning_context.py +183 -0
- src/agents/experiment_design_agent/reasoning_validation.py +546 -0
- src/agents/experiment_design_agent/run.py +481 -0
- src/agents/experiment_design_agent/run_logging.py +292 -0
- src/agents/experiment_design_agent/scope_gate.py +198 -0
- src/agents/experiment_design_agent/study_type_composer.py +1360 -0
- src/agents/experiment_design_agent/survey_evidence.py +1381 -0
- src/agents/experiment_design_agent/template_router.py +195 -0
- src/agents/experiment_design_agent/variable_claim_extractor.py +93 -0
- src/agents/idea_agent/__init__.py +1 -0
- src/agents/idea_agent/agent/__init__.py +6 -0
- src/agents/idea_agent/agent/artifacts.py +308 -0
- src/agents/idea_agent/agent/base.py +122 -0
- src/agents/idea_agent/agent/ligagent.py +488 -0
- src/agents/idea_agent/agent/mcts.py +2060 -0
- src/agents/idea_agent/agent/prompts/__init__.py +48 -0
- src/agents/idea_agent/agent/prompts/advanced_analysis.py +235 -0
- src/agents/idea_agent/agent/prompts/algorithm_alignment.py +55 -0
- src/agents/idea_agent/agent/prompts/algorithm_structuring.py +48 -0
- src/agents/idea_agent/agent/prompts/component_extraction.py +62 -0
- src/agents/idea_agent/agent/prompts/component_novelty_evaluation.py +54 -0
- src/agents/idea_agent/agent/prompts/experiment_findings_extraction.py +39 -0
- src/agents/idea_agent/agent/prompts/idea_fusion.py +295 -0
- src/agents/idea_agent/agent/prompts/idea_introduction.py +30 -0
- src/agents/idea_agent/agent/prompts/idea_result_alignment.py +39 -0
- src/agents/idea_agent/agent/prompts/input_interpreter.py +52 -0
- src/agents/idea_agent/agent/prompts/keynote_ops.py +78 -0
- src/agents/idea_agent/agent/prompts/mcts_evaluation.py +235 -0
- src/agents/idea_agent/agent/prompts/mcts_generation.py +140 -0
- src/agents/idea_agent/agent/prompts/mechanism_commit_query.py +99 -0
- src/agents/idea_agent/agent/prompts/memory_selection.py +0 -0
- src/agents/idea_agent/agent/prompts/prompt_modes.py +16 -0
- src/agents/idea_agent/agent/prompts/rag_query.py +34 -0
- src/agents/idea_agent/agent/prompts/re_analysis_replan.py +48 -0
- src/agents/idea_agent/agent/prompts/reference_grounding.py +34 -0
- src/agents/idea_agent/agent/prompts/root_domain_classification.py +32 -0
- src/agents/idea_agent/agent/prompts/scientific_debate.py +88 -0
- src/agents/idea_agent/agent/prompts/scientific_materialization.py +45 -0
- src/agents/idea_agent/agent/prompts/skill_instantiation.py +193 -0
- src/agents/idea_agent/agent/prompts/theory_transfer_query.py +93 -0
- src/agents/idea_agent/agent/prompts/topic_background.py +15 -0
- src/agents/idea_agent/agent/skills/DEFAULT_SKILL_TEMPLATES.json +263 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/alternative-path-contrast/SKILL.md +40 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/alternative-path-contrast/references/contrast_patterns.md +22 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/feedback-closed-loop/SKILL.md +40 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/feedback-closed-loop/references/mechanism_cards.md +24 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/hierarchical-decomposition/SKILL.md +39 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/hierarchical-decomposition/references/hierarchy_patterns.md +22 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/mechanism-commit-innovation/SKILL.md +39 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/mechanism-commit-innovation/references/mechanism_commit_patterns.md +24 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/multi-scale-coordinator/SKILL.md +39 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/multi-scale-coordinator/references/coordination_patterns.md +22 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/speculative-execution-with-repair/SKILL.md +41 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/speculative-execution-with-repair/references/speculation_patterns.md +22 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/surgical-modularity/SKILL.md +39 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/surgical-modularity/references/modularity_patterns.md +22 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/theory-transfer-injection/SKILL.md +40 -0
- src/agents/idea_agent/agent/skills/edit_operator_skills/theory-transfer-injection/references/transfer_patterns.md +24 -0
- src/agents/idea_agent/example/idea_result.json +900 -0
- src/agents/idea_agent/run.py +276 -0
- src/agents/idea_agent/tests/test_advanced_analysis_contract.py +90 -0
- src/agents/idea_agent/tests/test_gap_hypothesis_bridge.py +166 -0
- src/agents/idea_agent/tests/test_idea_debate.py +480 -0
- src/agents/idea_agent/tests/test_idea_result_v5.py +99 -0
- src/agents/idea_agent/tests/test_idea_synthesis.py +92 -0
- src/agents/idea_agent/tests/test_mature_idea_sources.py +27 -0
- src/agents/idea_agent/tests/test_multimodal_idea_integration.py +386 -0
- src/agents/idea_agent/tests/test_profile_materialization_and_scoring.py +219 -0
- src/agents/idea_agent/tests/test_profile_native_skill_rendering.py +122 -0
- src/agents/idea_agent/tests/test_result_persistence.py +183 -0
- src/agents/idea_agent/tests/test_scientific_intervention_profiles.py +241 -0
- src/agents/idea_agent/tests/test_scientific_rubric_and_prompts.py +559 -0
- src/agents/idea_agent/tests/test_strict_json_object_responses.py +48 -0
- src/agents/idea_agent/utils/core/__init__.py +1 -0
- src/agents/idea_agent/utils/core/ablation_inputs.py +60 -0
- src/agents/idea_agent/utils/core/chat_errors.py +95 -0
- src/agents/idea_agent/utils/core/chat_router.py +130 -0
- src/agents/idea_agent/utils/core/chat_transport.py +188 -0
- src/agents/idea_agent/utils/core/config_loader.py +166 -0
- src/agents/idea_agent/utils/core/json_utils.py +28 -0
- src/agents/idea_agent/utils/core/logger.py +287 -0
- src/agents/idea_agent/utils/core/progress.py +58 -0
- src/agents/idea_agent/utils/core/response_parsing.py +57 -0
- src/agents/idea_agent/utils/core/run_inputs.py +198 -0
- src/agents/idea_agent/utils/mcts/__init__.py +1 -0
- src/agents/idea_agent/utils/mcts/component_novelty.py +342 -0
- src/agents/idea_agent/utils/mcts/defect_registry.py +302 -0
- src/agents/idea_agent/utils/mcts/idea_routes.py +61 -0
- src/agents/idea_agent/utils/mcts/idea_taste_presets.py +312 -0
- src/agents/idea_agent/utils/mcts/mcts_helpers.py +738 -0
- src/agents/idea_agent/utils/mcts/mcts_runtime.py +3000 -0
- src/agents/idea_agent/utils/mcts/scientific_intervention_ontology.py +1561 -0
- src/agents/idea_agent/utils/mcts/scientific_rubric.py +211 -0
- src/agents/idea_agent/utils/mcts/skill_parsing.py +92 -0
- src/agents/idea_agent/utils/papers/__init__.py +1 -0
- src/agents/idea_agent/utils/papers/paper_graph_vector_store.py +499 -0
- src/agents/idea_agent/utils/papers/paper_repository.py +372 -0
- src/agents/idea_agent/utils/prompting/__init__.py +1 -0
- src/agents/idea_agent/utils/prompting/prompt_views.py +637 -0
- src/agents/idea_agent/utils/workflow/__init__.py +1 -0
- src/agents/idea_agent/utils/workflow/advanced_analysis_contract.py +244 -0
- src/agents/idea_agent/utils/workflow/gap_hypothesis_bridge.py +461 -0
- src/agents/idea_agent/utils/workflow/idea_contract.py +426 -0
- src/agents/idea_agent/utils/workflow/idea_debate.py +1238 -0
- src/agents/idea_agent/utils/workflow/idea_diversity.py +163 -0
- src/agents/idea_agent/utils/workflow/idea_fusion.py +889 -0
- src/agents/idea_agent/utils/workflow/idea_helpers.py +478 -0
- src/agents/idea_agent/utils/workflow/idea_portfolio.py +422 -0
- src/agents/idea_agent/utils/workflow/idea_synthesis.py +482 -0
- src/agents/idea_agent/utils/workflow/ligagent_flow.py +581 -0
- src/agents/idea_agent/utils/workflow/ligagent_handlers.py +1836 -0
- src/agents/idea_agent/utils/workflow/ligagent_helpers.py +1331 -0
- src/agents/idea_agent/utils/workflow/ligagent_utils.py +322 -0
- src/agents/idea_agent/utils/workflow/mature_idea_sources.py +648 -0
- src/agents/idea_agent/utils/workflow/multimodal_data_anchoring.py +578 -0
- src/agents/idea_agent/utils/workflow/result_persistence.py +774 -0
- src/agents/idea_agent/utils/workflow/stage_contract.py +76 -0
- src/agents/idea_agent/utils/workflow/workflow_runtime.py +288 -0
- src/agents/research_plan_author/__init__.py +50 -0
- src/agents/research_plan_author/artifacts.py +270 -0
- src/agents/research_plan_author/authoring_blueprint.py +1246 -0
- src/agents/research_plan_author/bibtex_renderer.py +252 -0
- src/agents/research_plan_author/contract_repair.py +131 -0
- src/agents/research_plan_author/contracts.py +745 -0
- src/agents/research_plan_author/cross_section_editor.py +232 -0
- src/agents/research_plan_author/document_quality.py +987 -0
- src/agents/research_plan_author/idea_evolution.py +223 -0
- src/agents/research_plan_author/input_loader.py +76 -0
- src/agents/research_plan_author/latex_compiler.py +260 -0
- src/agents/research_plan_author/latex_safety.py +159 -0
- src/agents/research_plan_author/llm_json.py +74 -0
- src/agents/research_plan_author/markdown_renderer.py +275 -0
- src/agents/research_plan_author/pdf_validator.py +149 -0
- src/agents/research_plan_author/render.py +166 -0
- src/agents/research_plan_author/render_artifacts.py +187 -0
- src/agents/research_plan_author/run.py +765 -0
- src/agents/research_plan_author/run_logging.py +209 -0
- src/agents/research_plan_author/section_cache.py +184 -0
- src/agents/research_plan_author/section_composer.py +1764 -0
- src/agents/research_plan_author/section_router.py +209 -0
- src/agents/research_plan_author/semantic_validator.py +254 -0
- src/agents/research_plan_author/source_bundle.py +46 -0
- src/agents/research_plan_author/source_registry.py +208 -0
- src/agents/research_plan_author/survey_source_loader.py +137 -0
- src/agents/research_plan_author/template_adapter.py +173 -0
- src/agents/research_plan_author/template_profile.py +204 -0
- src/agents/research_plan_author/tex_renderer.py +496 -0
- src/agents/research_plan_author/theory_presentation.py +134 -0
- src/agents/research_plan_author/theory_spine.py +703 -0
- src/agents/survey_agent/Dockerfile +54 -0
- src/agents/survey_agent/README.md +350 -0
- src/agents/survey_agent/config/deep_survey.yaml +217 -0
- src/agents/survey_agent/config/deep_survey_batch.yaml +176 -0
- src/agents/survey_agent/config/deep_survey_fast.yaml +183 -0
- src/agents/survey_agent/config/evaluate_baseline.yaml +197 -0
- src/agents/survey_agent/config/outcomeRAG.yaml +159 -0
- src/agents/survey_agent/env_report.md +348 -0
- src/agents/survey_agent/modules/__init__.py +0 -0
- src/agents/survey_agent/modules/code_collector.py +2194 -0
- src/agents/survey_agent/modules/code_report_generator.py +1282 -0
- src/agents/survey_agent/modules/data_manager.py +1713 -0
- src/agents/survey_agent/modules/database.py +167 -0
- src/agents/survey_agent/modules/fulltext_download_cache.py +462 -0
- src/agents/survey_agent/modules/fulltext_http.py +134 -0
- src/agents/survey_agent/modules/fulltext_resolution.py +749 -0
- src/agents/survey_agent/modules/judge.py +434 -0
- src/agents/survey_agent/modules/outcome_RAG.py +236 -0
- src/agents/survey_agent/modules/paper_graph_retriever.py +1075 -0
- src/agents/survey_agent/modules/pe.py +1729 -0
- src/agents/survey_agent/modules/pseudo_creator.py +782 -0
- src/agents/survey_agent/modules/pseudo_reviser.py +537 -0
- src/agents/survey_agent/modules/refine_agent.py +1952 -0
- src/agents/survey_agent/modules/survey_generator.py +5691 -0
- src/agents/survey_agent/modules/survey_visualizer.py +1817 -0
- src/agents/survey_agent/modules/visual_prompts.py +327 -0
- src/agents/survey_agent/modules/work_analyzer.py +2750 -0
- src/agents/survey_agent/modules/work_collector.py +5649 -0
- src/agents/survey_agent/scripts/baseline_evaluation.py +411 -0
- src/agents/survey_agent/scripts/run_deep_survey.py +224 -0
- src/agents/survey_agent/scripts/run_deep_survey_adapter.py +407 -0
- src/agents/survey_agent/scripts/run_deep_survey_adapter_with_input.py +409 -0
- src/agents/survey_agent/scripts/run_deep_survey_batch.py +228 -0
- src/agents/survey_agent/scripts/run_deep_survey_batch_arg.py +243 -0
- src/agents/survey_agent/scripts/run_deep_survey_batch_settings.py +218 -0
- src/agents/survey_agent/scripts/run_keynotes_gen.py +128 -0
- src/agents/survey_agent/scripts/run_work_clusters.py +140 -0
- src/agents/survey_agent/utils/__init__.py +0 -0
- src/agents/survey_agent/utils/ablation_utils.py +317 -0
- src/agents/survey_agent/utils/api_call.py +2518 -0
- src/agents/survey_agent/utils/chat_utils.py +82 -0
- src/agents/survey_agent/utils/config_utils.py +70 -0
- src/agents/survey_agent/utils/convert_to_md.py +29 -0
- src/agents/survey_agent/utils/err_info.py +24 -0
- src/agents/survey_agent/utils/file_utils.py +176 -0
- src/agents/survey_agent/utils/gpu_utils.py +145 -0
- src/agents/survey_agent/utils/graph_visualizer.py +279 -0
- src/agents/survey_agent/utils/html_utils.py +181 -0
- src/agents/survey_agent/utils/latex_generator_intra_cluster.py +529 -0
- src/agents/survey_agent/utils/latex_generator_relation_table.py +193 -0
- src/agents/survey_agent/utils/mineru_section_packer.py +334 -0
- src/agents/survey_agent/utils/mineru_utils.py +396 -0
- src/agents/survey_agent/utils/paper.py +144 -0
- src/agents/survey_agent/utils/read_yaml.py +15 -0
- src/agents/survey_agent/utils/repo_utils.py +167 -0
- src/agents/survey_agent/utils/rich_logger.py +77 -0
- src/agents/survey_agent/utils/step2v2.py +874 -0
- src/agents/survey_agent/utils/step2v2_extractor.py +856 -0
- src/agents/survey_agent/utils/topic_survey_storage.py +309 -0
- src/agents/survey_agent/utils/utils.py +118 -0
- src/agents/survey_agent/utils/work.py +2 -0
- src/cli.py +1611 -0
- src/config/__init__.py +213 -0
- src/config/default.yaml +1122 -0
- src/harness/LICENSE +21 -0
- src/harness/VENDORED.md +14 -0
- src/harness/src/__init__.py +0 -0
- src/harness/src/openharness/__init__.py +0 -0
- src/harness/src/openharness/__main__.py +6 -0
- src/harness/src/openharness/api/__init__.py +21 -0
- src/harness/src/openharness/api/client.py +281 -0
- src/harness/src/openharness/api/codex_client.py +407 -0
- src/harness/src/openharness/api/copilot_auth.py +240 -0
- src/harness/src/openharness/api/copilot_client.py +134 -0
- src/harness/src/openharness/api/errors.py +19 -0
- src/harness/src/openharness/api/openai_client.py +577 -0
- src/harness/src/openharness/api/provider.py +186 -0
- src/harness/src/openharness/api/registry.py +437 -0
- src/harness/src/openharness/api/usage.py +17 -0
- src/harness/src/openharness/auth/__init__.py +29 -0
- src/harness/src/openharness/auth/external.py +610 -0
- src/harness/src/openharness/auth/flows.py +189 -0
- src/harness/src/openharness/auth/manager.py +482 -0
- src/harness/src/openharness/auth/storage.py +269 -0
- src/harness/src/openharness/autopilot/__init__.py +23 -0
- src/harness/src/openharness/autopilot/service.py +2239 -0
- src/harness/src/openharness/autopilot/types.py +91 -0
- src/harness/src/openharness/bridge/__init__.py +20 -0
- src/harness/src/openharness/bridge/manager.py +106 -0
- src/harness/src/openharness/bridge/session_runner.py +46 -0
- src/harness/src/openharness/bridge/types.py +37 -0
- src/harness/src/openharness/bridge/work_secret.py +41 -0
- src/harness/src/openharness/channels/UPSTREAM +6 -0
- src/harness/src/openharness/channels/__init__.py +22 -0
- src/harness/src/openharness/channels/adapter.py +131 -0
- src/harness/src/openharness/channels/bus/__init__.py +6 -0
- src/harness/src/openharness/channels/bus/events.py +38 -0
- src/harness/src/openharness/channels/bus/queue.py +44 -0
- src/harness/src/openharness/channels/impl/__init__.py +6 -0
- src/harness/src/openharness/channels/impl/base.py +141 -0
- src/harness/src/openharness/channels/impl/dingtalk.py +445 -0
- src/harness/src/openharness/channels/impl/discord.py +311 -0
- src/harness/src/openharness/channels/impl/email.py +410 -0
- src/harness/src/openharness/channels/impl/feishu.py +1342 -0
- src/harness/src/openharness/channels/impl/manager.py +257 -0
- src/harness/src/openharness/channels/impl/matrix.py +700 -0
- src/harness/src/openharness/channels/impl/mochat.py +897 -0
- src/harness/src/openharness/channels/impl/qq.py +141 -0
- src/harness/src/openharness/channels/impl/slack.py +284 -0
- src/harness/src/openharness/channels/impl/telegram.py +525 -0
- src/harness/src/openharness/channels/impl/whatsapp.py +159 -0
- src/harness/src/openharness/cli.py +2551 -0
- src/harness/src/openharness/commands/__init__.py +21 -0
- src/harness/src/openharness/commands/registry.py +2783 -0
- src/harness/src/openharness/config/__init__.py +34 -0
- src/harness/src/openharness/config/paths.py +160 -0
- src/harness/src/openharness/config/schema.py +119 -0
- src/harness/src/openharness/config/settings.py +1104 -0
- src/harness/src/openharness/coordinator/__init__.py +12 -0
- src/harness/src/openharness/coordinator/agent_definitions.py +975 -0
- src/harness/src/openharness/coordinator/coordinator_mode.py +520 -0
- src/harness/src/openharness/engine/__init__.py +80 -0
- src/harness/src/openharness/engine/cost_tracker.py +24 -0
- src/harness/src/openharness/engine/messages.py +222 -0
- src/harness/src/openharness/engine/query.py +1188 -0
- src/harness/src/openharness/engine/query_engine.py +313 -0
- src/harness/src/openharness/engine/stream_events.py +90 -0
- src/harness/src/openharness/hooks/__init__.py +50 -0
- src/harness/src/openharness/hooks/events.py +20 -0
- src/harness/src/openharness/hooks/executor.py +242 -0
- src/harness/src/openharness/hooks/hot_reload.py +31 -0
- src/harness/src/openharness/hooks/loader.py +68 -0
- src/harness/src/openharness/hooks/schemas.py +66 -0
- src/harness/src/openharness/hooks/types.py +38 -0
- src/harness/src/openharness/keybindings/__init__.py +14 -0
- src/harness/src/openharness/keybindings/default_bindings.py +11 -0
- src/harness/src/openharness/keybindings/loader.py +22 -0
- src/harness/src/openharness/keybindings/parser.py +18 -0
- src/harness/src/openharness/keybindings/resolver.py +13 -0
- src/harness/src/openharness/mcp/__init__.py +79 -0
- src/harness/src/openharness/mcp/client.py +298 -0
- src/harness/src/openharness/mcp/config.py +16 -0
- src/harness/src/openharness/mcp/types.py +76 -0
- src/harness/src/openharness/memory/__init__.py +25 -0
- src/harness/src/openharness/memory/agent.py +91 -0
- src/harness/src/openharness/memory/manager.py +183 -0
- src/harness/src/openharness/memory/memdir.py +52 -0
- src/harness/src/openharness/memory/migrate.py +137 -0
- src/harness/src/openharness/memory/paths.py +22 -0
- src/harness/src/openharness/memory/relevance.py +145 -0
- src/harness/src/openharness/memory/scan.py +116 -0
- src/harness/src/openharness/memory/schema.py +443 -0
- src/harness/src/openharness/memory/search.py +71 -0
- src/harness/src/openharness/memory/team.py +90 -0
- src/harness/src/openharness/memory/types.py +33 -0
- src/harness/src/openharness/memory/usage.py +153 -0
- src/harness/src/openharness/output_styles/__init__.py +5 -0
- src/harness/src/openharness/output_styles/loader.py +42 -0
- src/harness/src/openharness/permissions/__init__.py +26 -0
- src/harness/src/openharness/permissions/checker.py +200 -0
- src/harness/src/openharness/permissions/modes.py +13 -0
- src/harness/src/openharness/personalization/__init__.py +6 -0
- src/harness/src/openharness/personalization/extractor.py +138 -0
- src/harness/src/openharness/personalization/rules.py +64 -0
- src/harness/src/openharness/personalization/session_hook.py +65 -0
- src/harness/src/openharness/platforms.py +86 -0
- src/harness/src/openharness/plugins/__init__.py +53 -0
- src/harness/src/openharness/plugins/bundled/__init__.py +0 -0
- src/harness/src/openharness/plugins/installer.py +39 -0
- src/harness/src/openharness/plugins/loader.py +730 -0
- src/harness/src/openharness/plugins/schemas.py +24 -0
- src/harness/src/openharness/plugins/types.py +59 -0
- src/harness/src/openharness/prompts/__init__.py +14 -0
- src/harness/src/openharness/prompts/claudemd.py +48 -0
- src/harness/src/openharness/prompts/context.py +187 -0
- src/harness/src/openharness/prompts/environment.py +135 -0
- src/harness/src/openharness/prompts/system_prompt.py +109 -0
- src/harness/src/openharness/sandbox/Dockerfile +6 -0
- src/harness/src/openharness/sandbox/__init__.py +33 -0
- src/harness/src/openharness/sandbox/adapter.py +148 -0
- src/harness/src/openharness/sandbox/docker_backend.py +232 -0
- src/harness/src/openharness/sandbox/docker_image.py +103 -0
- src/harness/src/openharness/sandbox/path_validator.py +37 -0
- src/harness/src/openharness/sandbox/session.py +63 -0
- src/harness/src/openharness/services/__init__.py +30 -0
- src/harness/src/openharness/services/autodream/__init__.py +34 -0
- src/harness/src/openharness/services/autodream/backup.py +104 -0
- src/harness/src/openharness/services/autodream/lock.py +138 -0
- src/harness/src/openharness/services/autodream/prompt.py +128 -0
- src/harness/src/openharness/services/autodream/service.py +313 -0
- src/harness/src/openharness/services/compact/__init__.py +1725 -0
- src/harness/src/openharness/services/cron.py +137 -0
- src/harness/src/openharness/services/cron_scheduler.py +595 -0
- src/harness/src/openharness/services/lsp/__init__.py +216 -0
- src/harness/src/openharness/services/memory_extract/__init__.py +261 -0
- src/harness/src/openharness/services/oauth/__init__.py +0 -0
- src/harness/src/openharness/services/session_backend.py +97 -0
- src/harness/src/openharness/services/session_memory/__init__.py +139 -0
- src/harness/src/openharness/services/session_storage.py +230 -0
- src/harness/src/openharness/services/token_estimation.py +15 -0
- src/harness/src/openharness/services/tool_outputs.py +55 -0
- src/harness/src/openharness/skills/__init__.py +44 -0
- src/harness/src/openharness/skills/_frontmatter.py +97 -0
- src/harness/src/openharness/skills/bundled/__init__.py +75 -0
- src/harness/src/openharness/skills/bundled/content/commit.md +25 -0
- src/harness/src/openharness/skills/bundled/content/debug.md +25 -0
- src/harness/src/openharness/skills/bundled/content/diagnose.md +35 -0
- src/harness/src/openharness/skills/bundled/content/plan.md +39 -0
- src/harness/src/openharness/skills/bundled/content/review.md +33 -0
- src/harness/src/openharness/skills/bundled/content/simplify.md +26 -0
- src/harness/src/openharness/skills/bundled/content/skill-creator.md +175 -0
- src/harness/src/openharness/skills/bundled/content/test.md +38 -0
- src/harness/src/openharness/skills/loader.py +229 -0
- src/harness/src/openharness/skills/registry.py +29 -0
- src/harness/src/openharness/skills/types.py +24 -0
- src/harness/src/openharness/state/__init__.py +6 -0
- src/harness/src/openharness/state/app_state.py +30 -0
- src/harness/src/openharness/state/store.py +40 -0
- src/harness/src/openharness/swarm/__init__.py +70 -0
- src/harness/src/openharness/swarm/in_process.py +693 -0
- src/harness/src/openharness/swarm/lockfile.py +24 -0
- src/harness/src/openharness/swarm/mailbox.py +522 -0
- src/harness/src/openharness/swarm/permission_sync.py +1168 -0
- src/harness/src/openharness/swarm/registry.py +410 -0
- src/harness/src/openharness/swarm/spawn_utils.py +229 -0
- src/harness/src/openharness/swarm/subprocess_backend.py +171 -0
- src/harness/src/openharness/swarm/team_lifecycle.py +910 -0
- src/harness/src/openharness/swarm/types.py +398 -0
- src/harness/src/openharness/swarm/worktree.py +315 -0
- src/harness/src/openharness/tasks/__init__.py +18 -0
- src/harness/src/openharness/tasks/local_agent_task.py +28 -0
- src/harness/src/openharness/tasks/local_shell_task.py +17 -0
- src/harness/src/openharness/tasks/manager.py +475 -0
- src/harness/src/openharness/tasks/stop_task.py +11 -0
- src/harness/src/openharness/tasks/types.py +32 -0
- src/harness/src/openharness/themes/__init__.py +21 -0
- src/harness/src/openharness/themes/builtin.py +89 -0
- src/harness/src/openharness/themes/loader.py +55 -0
- src/harness/src/openharness/themes/schema.py +54 -0
- src/harness/src/openharness/tools/__init__.py +107 -0
- src/harness/src/openharness/tools/agent_tool.py +141 -0
- src/harness/src/openharness/tools/ask_user_question_tool.py +46 -0
- src/harness/src/openharness/tools/base.py +80 -0
- src/harness/src/openharness/tools/bash_tool.py +259 -0
- src/harness/src/openharness/tools/brief_tool.py +33 -0
- src/harness/src/openharness/tools/config_tool.py +54 -0
- src/harness/src/openharness/tools/cron_create_tool.py +105 -0
- src/harness/src/openharness/tools/cron_delete_tool.py +32 -0
- src/harness/src/openharness/tools/cron_list_tool.py +69 -0
- src/harness/src/openharness/tools/cron_toggle_tool.py +37 -0
- src/harness/src/openharness/tools/enter_plan_mode_tool.py +28 -0
- src/harness/src/openharness/tools/enter_worktree_tool.py +80 -0
- src/harness/src/openharness/tools/exit_plan_mode_tool.py +28 -0
- src/harness/src/openharness/tools/exit_worktree_tool.py +42 -0
- src/harness/src/openharness/tools/file_edit_tool.py +95 -0
- src/harness/src/openharness/tools/file_read_tool.py +72 -0
- src/harness/src/openharness/tools/file_write_tool.py +87 -0
- src/harness/src/openharness/tools/glob_tool.py +175 -0
- src/harness/src/openharness/tools/grep_tool.py +374 -0
- src/harness/src/openharness/tools/image_generation_tool.py +447 -0
- src/harness/src/openharness/tools/image_to_text_tool.py +237 -0
- src/harness/src/openharness/tools/list_mcp_resources_tool.py +36 -0
- src/harness/src/openharness/tools/lsp_tool.py +154 -0
- src/harness/src/openharness/tools/mcp_auth_tool.py +71 -0
- src/harness/src/openharness/tools/mcp_tool.py +72 -0
- src/harness/src/openharness/tools/notebook_edit_tool.py +97 -0
- src/harness/src/openharness/tools/read_mcp_resource_tool.py +38 -0
- src/harness/src/openharness/tools/remote_trigger_tool.py +74 -0
- src/harness/src/openharness/tools/send_message_tool.py +58 -0
- src/harness/src/openharness/tools/skill_tool.py +43 -0
- src/harness/src/openharness/tools/sleep_tool.py +32 -0
- src/harness/src/openharness/tools/task_create_tool.py +56 -0
- src/harness/src/openharness/tools/task_get_tool.py +33 -0
- src/harness/src/openharness/tools/task_list_tool.py +35 -0
- src/harness/src/openharness/tools/task_output_tool.py +35 -0
- src/harness/src/openharness/tools/task_stop_tool.py +30 -0
- src/harness/src/openharness/tools/task_update_tool.py +50 -0
- src/harness/src/openharness/tools/team_create_tool.py +31 -0
- src/harness/src/openharness/tools/team_delete_tool.py +30 -0
- src/harness/src/openharness/tools/todo_write_tool.py +46 -0
- src/harness/src/openharness/tools/tool_search_tool.py +38 -0
- src/harness/src/openharness/tools/web_fetch_tool.py +117 -0
- src/harness/src/openharness/tools/web_search_tool.py +119 -0
- src/harness/src/openharness/ui/__init__.py +5 -0
- src/harness/src/openharness/ui/app.py +320 -0
- src/harness/src/openharness/ui/backend_host.py +941 -0
- src/harness/src/openharness/ui/coordinator_drain.py +198 -0
- src/harness/src/openharness/ui/input.py +32 -0
- src/harness/src/openharness/ui/output.py +265 -0
- src/harness/src/openharness/ui/permission_dialog.py +14 -0
- src/harness/src/openharness/ui/protocol.py +247 -0
- src/harness/src/openharness/ui/react_launcher.py +179 -0
- src/harness/src/openharness/ui/runtime.py +799 -0
- src/harness/src/openharness/ui/textual_app.py +495 -0
- src/harness/src/openharness/utils/__init__.py +0 -0
- src/harness/src/openharness/utils/file_lock.py +86 -0
- src/harness/src/openharness/utils/fs.py +98 -0
- src/harness/src/openharness/utils/helpers.py +77 -0
- src/harness/src/openharness/utils/network_guard.py +340 -0
- src/harness/src/openharness/utils/shell.py +147 -0
- src/harness/src/openharness/vim/__init__.py +5 -0
- src/harness/src/openharness/vim/transitions.py +8 -0
- src/harness/src/openharness/voice/__init__.py +7 -0
- src/harness/src/openharness/voice/keyterms.py +10 -0
- src/harness/src/openharness/voice/stream_stt.py +8 -0
- src/harness/src/openharness/voice/voice_mode.py +44 -0
- src/llm/__init__.py +29 -0
- src/llm/image_generation.py +402 -0
- src/llm/provider_registry.py +419 -0
- src/llm/runtime_env.py +64 -0
- src/llm/structured_output.py +131 -0
- src/llm/vision.py +198 -0
- src/memory/__init__.py +2 -0
- src/memory/api/__init__.py +1 -0
- src/memory/api/base_memory_system_api.py +98 -0
- src/memory/api/base_symbolic_memory_system_api.py +190 -0
- src/memory/api/base_vector_memory_system_api.py +116 -0
- src/memory/api/faiss_memory_system_api.py +228 -0
- src/memory/api/slot_process_api.py +827 -0
- src/memory/api/symbolic_memory_system_api.py +572 -0
- src/memory/memory_system/__init__.py +48 -0
- src/memory/memory_system/component_taxonomy.py +430 -0
- src/memory/memory_system/llm.py +437 -0
- src/memory/memory_system/models.py +168 -0
- src/memory/memory_system/user_prompt.py +418 -0
- src/memory/memory_system/utils.py +282 -0
- src/memory/memory_system/vectorstore.py +311 -0
- src/memory/memory_system/working_slot.py +99 -0
- src/pipeline/__init__.py +129 -0
- src/pipeline/contracts.py +531 -0
- src/pipeline/discipline_taxonomy.py +916 -0
- src/pipeline/evidence_coverage_ledger.py +1150 -0
- src/pipeline/evidence_refinement.py +620 -0
- src/pipeline/experiment_to_symbolic.py +137 -0
- src/pipeline/multimodal_evidence/__init__.py +28 -0
- src/pipeline/multimodal_evidence/capabilities.py +107 -0
- src/pipeline/multimodal_evidence/claims.py +135 -0
- src/pipeline/multimodal_evidence/contract.py +291 -0
- src/pipeline/multimodal_evidence/data_sh_compiler.py +505 -0
- src/pipeline/multimodal_evidence/handoff_binding.py +135 -0
- src/pipeline/multimodal_evidence/manifest.py +254 -0
- src/pipeline/multimodal_evidence/native_analysis.py +479 -0
- src/pipeline/multimodal_evidence/perception.py +277 -0
- src/pipeline/multimodal_evidence/query_binding.py +65 -0
- src/pipeline/multimodal_evidence/rendering.py +120 -0
- src/pipeline/multimodal_evidence/safety.py +42 -0
- src/pipeline/multimodal_evidence/sampling.py +69 -0
- src/pipeline/multimodal_evidence/service.py +148 -0
- src/pipeline/multimodal_evidence/survey_integration.py +460 -0
- src/pipeline/paper_identity.py +52 -0
- src/pipeline/research_design_inventory.py +338 -0
- src/pipeline/research_domain_resolution.py +669 -0
- src/pipeline/research_identity.py +548 -0
- src/pipeline/research_question_contract.py +646 -0
- src/pipeline/retrieval_lanes.py +889 -0
- src/pipeline/run_loop.py +862 -0
- src/pipeline/science_events.py +30 -0
- src/pipeline/science_manifests.py +602 -0
- src/pipeline/science_run.py +918 -0
- src/pipeline/science_stages.py +709 -0
- src/pipeline/science_workflow.py +807 -0
- src/pipeline/sh_cluster_projection.py +306 -0
- src/pipeline/sh_graph_provenance.py +648 -0
- src/pipeline/subhypothesis_decomposition.py +392 -0
- src/pipeline/subhypothesis_evidence.py +856 -0
- src/pipeline/survey_evidence_plan.py +858 -0
- src/pipeline/survey_gap_adjudication.py +647 -0
- src/pipeline/survey_gap_candidates.py +840 -0
- src/pipeline/survey_gap_ledger.py +683 -0
- src/pipeline/survey_gap_triage.py +401 -0
- src/pipeline/survey_handoff_persistence.py +481 -0
- src/pipeline/survey_handoff_projection.py +457 -0
- src/pipeline/survey_idea_handoff.py +1112 -0
- src/pipeline/survey_idea_loader.py +289 -0
- 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
|