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,856 @@
1
+ """
2
+ Step2v2 Extractor Module - Refactored for compatibility with ChatAgent
3
+
4
+ This module provides functions to extract structured information from academic papers.
5
+ It can be used with the project's ChatAgent via batch_remote_chat_with_retry.
6
+
7
+ Usage:
8
+ 1. Call extract_paper_info_batch() to extract info for multiple papers
9
+ 2. The function handles prompt building, API calls, and result aggregation internally
10
+ """
11
+
12
+ import os
13
+ import json
14
+ import re
15
+ from typing import Dict, List, Optional, Tuple, Any
16
+
17
+ from utils.utils import extract_json
18
+
19
+ # ================= CONSTANTS =================
20
+
21
+ ARXIV_DOMAINS = [
22
+ "cs.CV", "cs.CL", "cs.LG", "cs.AI", "cs.RO", "cs.NE", "stat.ML", "cs.MA",
23
+ "cs.DC", "cs.OS", "cs.AR", "cs.NI", "cs.PL", "cs.SE", "cs.DB", "cs.PF",
24
+ "cs.CC", "cs.DS", "cs.LO", "cs.IT", "cs.CR", "cs.GT",
25
+ "cs.HC", "cs.SI", "cs.CY", "cs.IR", "cs.MM", "cs.DL",
26
+ "cs.CE", "cs.CG", "cs.DM", "cs.ET", "cs.FL", "cs.GL",
27
+ "cs.GR", "cs.MS", "cs.NA", "cs.OH", "cs.SC", "cs.SD", "cs.SY",
28
+ "Hybrid", "Others"
29
+ ]
30
+
31
+ PAPER_TYPES = [
32
+ "Methodology", "System Design", "Benchmark/Dataset",
33
+ "Theoretical Proof", "Empirical Study", "Survey/Review",
34
+ "Application", "Position Paper", "Hybrid",
35
+ "Resource Paper", "Reproducibility Study", "Negative Results",
36
+ "Tutorial/Educational", "Others"
37
+ ]
38
+
39
+ METRIC_BLACKLIST = {
40
+ "accuracy", "precision", "recall", "f1", "auc", "roc", "map", "iou", "psnr", "ssim",
41
+ "fid", "inception score", "bleu", "rouge", "meteor", "cider", "fps", "latency",
42
+ "throughput", "flops", "parameters", "training time", "convergence", "error rate",
43
+ "speed", "cost", "memory", "loss", "perplexity", "top-1", "top-5", "mae", "rmse",
44
+ "validity", "novelty", "uniqueness", "diversity", "baseline", "sota", "method",
45
+ "model", "algorithm", "previous work", "prior art", "ablation", "variant", "proposed"
46
+ }
47
+
48
+
49
+ # ================= UTILITY FUNCTIONS =================
50
+
51
+ def clean_title_latex(title: str) -> str:
52
+ """Clean LaTeX special characters from title."""
53
+ if not title: return "Unknown Title"
54
+ t = re.sub(r'^\d+(\.\d+)*\s+', '', title)
55
+ t = re.sub(r'[$\\{}"]', '', t)
56
+ t = re.sub(r'\s+', ' ', t).strip()
57
+ return t
58
+
59
+ def extract_regex_candidates(full_text: str) -> Dict[str, List[str]]:
60
+ """Extract candidate methods and baselines using regex patterns."""
61
+ candidates = {"methods": set(), "baselines": set()}
62
+
63
+ method_pattern = re.compile(
64
+ r"(?:proposed|our|new|introduce|present)\s+(?:method|framework|algorithm|network|model)?\s*([A-Z][A-Za-z0-9\-]{2,15})",
65
+ re.MULTILINE
66
+ )
67
+
68
+ baseline_pattern = re.compile(
69
+ r"(?:compare(?:s|d)?\s+(?:with|to|against)|outperform(?:s|ed)|surpass(?:es|ed)|superior\s+to|better\s+than|following|adopted\s+from|baseline|built\s+upon|extends?|evaluates?|analyzes?|prior\s+work|existing\s+method)\s+([A-Z][A-Za-z0-9\-]{2,15})",
70
+ re.IGNORECASE | re.MULTILINE
71
+ )
72
+
73
+ for m in method_pattern.findall(full_text):
74
+ if len(m) > 2 and m.lower() not in METRIC_BLACKLIST:
75
+ candidates["methods"].add(m)
76
+ for b in baseline_pattern.findall(full_text):
77
+ if len(b) > 2 and b.lower() not in METRIC_BLACKLIST:
78
+ candidates["baselines"].add(b)
79
+
80
+ return {"methods": list(candidates["methods"]), "baselines": list(candidates["baselines"])}
81
+
82
+ def mark_entities_in_text(full_text: str, entity_list: List[str], marker_prefix: str) -> str:
83
+ """Mark entities in text with special markers."""
84
+ marked_text = full_text
85
+ for entity in entity_list:
86
+ if not entity or len(entity) < 3:
87
+ continue
88
+ escaped = re.escape(entity)
89
+ pattern = r'\b' + escaped + r'\b'
90
+ replacement = f"[{marker_prefix}:{entity}]"
91
+ marked_text = re.sub(pattern, replacement, marked_text, count=1, flags=re.IGNORECASE)
92
+ return marked_text
93
+
94
+
95
+ # ================= PROMPT BUILDERS =================
96
+
97
+ def build_main_extraction_prompt(
98
+ markdown_text: str,
99
+ title: str,
100
+ regex_candidates: dict,
101
+ *,
102
+ section_context: dict | None = None,
103
+ ) -> Tuple[str, str]:
104
+ """
105
+ Build main extraction prompt for a single paper.
106
+
107
+ Returns:
108
+ Tuple of (system_prompt, user_prompt)
109
+ """
110
+ domain_str = ", ".join(ARXIV_DOMAINS)
111
+ type_str = ", ".join(PAPER_TYPES)
112
+
113
+ marked_text = mark_entities_in_text(markdown_text, regex_candidates['methods'], "HINT_METHOD")
114
+
115
+ core_type_reference = """
116
+ Core Contribution Type Reference (Choose ONE single word):
117
+ 1. Methodological: Algorithm, Architecture, Framework, TrainingMethod, InferenceMethod, LossFunction, OptimizationTechnique
118
+ 2. System/Tool: System, Infrastructure, Tool, Library, Platform
119
+ 3. Data/Evaluation: Dataset, Benchmark, DataAugmentation, AnnotationScheme, EvaluationMetric, EvaluationProtocol
120
+ 4. Theoretical: TheoreticalFramework, TheoreticalProof, MathematicalFormulation, ComplexityAnalysis
121
+ 5. Analytical: EmpiricalAnalysis, ComparativeAnalysis, AblationAnalysis, ErrorAnalysis, Survey, Taxonomy
122
+ 6. Application: Application, CaseStudy, DomainAdaptation
123
+ 7. Others: Hybrid, Others
124
+
125
+ OUTPUT FORMAT: Single word only (e.g., Algorithm, NOT Type: Algorithm)
126
+ """
127
+
128
+ system = f"""You are a Senior Research Analyst extracting structured metadata from academic papers.
129
+
130
+ CRITICAL GROUNDING RULES:
131
+ 1. Insight: Must provide INDEPENDENT ANALYSIS beyond summary. Describe prerequisites, trade-offs, design choices, or potential defects. DO NOT copy summary or quote.
132
+ 2. Quote: Must be VERBATIM text from the original paper. Use ... for exact excerpts. DO NOT paraphrase or fabricate.
133
+ 3. Summary: Concise factual description in natural sentence form.
134
+ 4. Keywords: Concept words used for COARSE-GRAINED RETRIEVAL and filtering. Choose representative terms that capture the essence for search/matching.
135
+
136
+ PRIORITY: RECALL - Extract ALL relevant entities (cores, components, problems, innovations, limitations, future work). Do not omit items due to uncertainty.
137
+
138
+ Core vs Component Granularity Rules:
139
+ - Core Contribution: The LARGEST, TOP-LEVEL contribution that is NOT contained by any other entity. This is the root method/system/dataset proposed.
140
+ Example: Swin Transformer (the overall architecture)
141
+ Characteristics: Has unique name, explicitly claimed as main contribution, can stand alone
142
+
143
+ - Component: ALL sub-elements, modules, techniques, or building blocks that are PART OF a Core Contribution.
144
+ Example: Shifted Window Mechanism, Patch Merging Layer (parts of Swin Transformer)
145
+ Characteristics: Cannot exist independently without the Core, implements specific functionality
146
+
147
+ If unsure: Ask Can this exist independently, or is it always part of something bigger?
148
+ - Independent -> Core
149
+ - Part of bigger system -> Component
150
+
151
+ Text Marking System:
152
+ You will see markers like [HINT_METHOD:MethodName] in the text. These are SUGGESTIONS from pattern matching.
153
+ - They may contain false positives or miss important entities
154
+ - Use them to guide attention but read the FULL paper independently
155
+ - Extract ALL relevant entities regardless of whether they have markers
156
+
157
+ Few-Shot Examples:
158
+
159
+ Example 1: Clear Core-Component Hierarchy
160
+ Paper: Swin Transformer: Hierarchical Vision Transformer using Shifted Windows
161
+
162
+ Core Contribution:
163
+ name: Swin Transformer
164
+ acronym: SwinT
165
+ type: Architecture
166
+ keywords: [hierarchical transformer, shifted windows, vision backbone]
167
+ summary: Hierarchical vision transformer using shifted windows for efficient attention
168
+ insight: Trade-off: Achieves O(n) complexity via window-based computation but sacrifices some long-range modeling capability compared to full self-attention
169
+ quote: We propose Swin Transformer, a hierarchical Transformer whose representation is computed with shifted windows
170
+
171
+ Components (ALL parts of Swin Transformer):
172
+ 1. name: Shifted Window Mechanism
173
+ acronym: null
174
+ related_to_core: Swin Transformer
175
+ keywords: [window attention, cross-window connection]
176
+ summary: Window-based self-attention with shifting for cross-window connections
177
+ insight: Design choice: 7x7 window balances efficiency and receptive field. Potential defect: Window boundaries may cause artifacts for objects spanning multiple windows
178
+ quote: The shifted windowing scheme bridges the windows of the preceding layer
179
+
180
+ 2. name: Patch Merging Layer
181
+ acronym: null
182
+ related_to_core: Swin Transformer
183
+ keywords: [downsampling, hierarchical features]
184
+ summary: Downsampling layer that concatenates neighboring patch features
185
+ insight: Design choice: 2x2 merging reduces resolution while doubling channels. Potential defect: Loses fine-grained spatial information needed for dense prediction
186
+ quote: The patch merging layer concatenates the features of each group of 2x2 neighboring patches
187
+
188
+ Example 2: Multiple Cores
189
+ Paper proposes BOTH a new method AND a new dataset:
190
+
191
+ Core 1:
192
+ name: RainNet
193
+ acronym: null
194
+ type: Algorithm
195
+ keywords: [rain removal, weather robustness]
196
+
197
+ Core 2:
198
+ name: RainCityscapes
199
+ acronym: null
200
+ type: Dataset
201
+ keywords: [rainy driving, synthetic weather]
202
+
203
+ Component of Core 1:
204
+ name: Weather Augmentation Module
205
+ acronym: WAM
206
+ related_to_core: RainNet
207
+ keywords: [data augmentation, rain synthesis]
208
+ """
209
+
210
+ section_context = section_context or {}
211
+ included_headings = str(section_context.get("included_headings") or "")
212
+ omitted_headings = str(section_context.get("omitted_headings") or "")
213
+ packet_notice = ""
214
+ source_label = "FULL PAPER TEXT"
215
+ if included_headings:
216
+ source_label = "COMPLETE SECTIONS FROM THE PAPER"
217
+ packet_notice = f"""
218
+ IMPORTANT SECTION-PACKET BOUNDARY:
219
+ The source text contains only the following complete sections:
220
+ {included_headings}
221
+
222
+ The following body sections are not in this request:
223
+ {omitted_headings or '- (none)'}
224
+
225
+ Do not infer results, limitations, or entities from omitted sections. Extract only
226
+ evidence explicitly present in the complete sections supplied below.
227
+ """
228
+
229
+ user = f"""
230
+ {core_type_reference}
231
+
232
+ {packet_notice}
233
+ {source_label} (Some entities marked with [HINT_METHOD:...] as suggestions only):
234
+ {marked_text}
235
+
236
+ Task: Extract structured information for paper titled "{title}"
237
+
238
+ Output JSON Schema (FOLLOW THIS EXACT ATTRIBUTE ORDER):
239
+ {{
240
+ "metadata": {{
241
+ "title": "str (paper title, use EXACT title provided in the task)",
242
+ "domain": "str (from: {domain_str})",
243
+ "paper_type": "str (from: {type_str})",
244
+ "structured_summary": {{
245
+ "background": "str",
246
+ "method": "str",
247
+ "result": "str"
248
+ }},
249
+ "code_url": "str or null"
250
+ }},
251
+ "problems": [
252
+ {{
253
+ "keywords": ["str"],
254
+ "summary": "str",
255
+ "insight": "str (MUST be independent analysis)",
256
+ "quote": "str (MUST be verbatim)",
257
+ "related_to_core": "str"
258
+ }}
259
+ ],
260
+ "core_contributions": [
261
+ {{
262
+ "name": "str (TOP-LEVEL entity)",
263
+ "acronym": "str or null",
264
+ "type": "str (SINGLE WORD)",
265
+ "keywords": ["str"],
266
+ "summary": "str",
267
+ "insight": "str (prerequisites, trade-offs, design rationale)",
268
+ "quote": "str"
269
+ }}
270
+ ],
271
+ "core_relations": [
272
+ {{
273
+ "source": "str (core name)",
274
+ "target": "str (core name)",
275
+ "keywords": ["str"],
276
+ "summary": "str (natural sentence)",
277
+ "insight": "str (why relationship exists)",
278
+ "quote": "str"
279
+ }}
280
+ ],
281
+ "components": [
282
+ {{
283
+ "name": "str (MUST NOT be same as core name)",
284
+ "acronym": "str or null",
285
+ "related_to_core": "str (MUST link to parent Core)",
286
+ "keywords": ["str"],
287
+ "summary": "str",
288
+ "insight": "str (MUST include design choices AND potential defects)",
289
+ "quote": "str"
290
+ }}
291
+ ],
292
+ "innovations": [
293
+ {{
294
+ "keywords": ["str"],
295
+ "summary": "str",
296
+ "insight": "str",
297
+ "quote": "str",
298
+ "related_to_core": "str"
299
+ }}
300
+ ],
301
+ "limitations": [
302
+ {{
303
+ "keywords": ["str"],
304
+ "summary": "str",
305
+ "insight": "str",
306
+ "quote": "str",
307
+ "related_to_core": "str"
308
+ }}
309
+ ],
310
+ "future_work": [
311
+ {{
312
+ "keywords": ["str"],
313
+ "summary": "str",
314
+ "insight": "str",
315
+ "quote": "str",
316
+ "related_to_core": "str"
317
+ }}
318
+ ]
319
+ }}
320
+
321
+ CRITICAL REMINDERS:
322
+ 1. PRIORITY: RECALL - Extract ALL entities, even if uncertain
323
+ 2. Core vs Component: Use hierarchy rules above
324
+ 3. Type field: Single word only
325
+ 4. Insight: Independent analysis, not copy of summary/quote
326
+ 5. Quote: Verbatim text with ... markers
327
+ 6. Components: MUST discuss potential defects
328
+ 7. Keywords: Choose terms for RETRIEVAL and FILTERING purposes
329
+ 8. Attribute order: MUST follow schema order exactly (keywords first, then summary, insight, quote)
330
+ 9. Ignore [HINT_METHOD:...] markers in your output
331
+
332
+ Return JSON only:"""
333
+
334
+ return system, user
335
+
336
+
337
+ def build_baseline_extraction_prompt(markdown_text: str, core_names: List[str], regex_candidates: dict) -> Tuple[str, str]:
338
+ """
339
+ Build baseline/dataset extraction prompt for a single paper.
340
+
341
+ Returns:
342
+ Tuple of (system_prompt, user_prompt)
343
+ """
344
+ marked_text = mark_entities_in_text(markdown_text, regex_candidates['baselines'], "HINT_BASELINE")
345
+
346
+ system = """You are a Research Graph Builder focusing on relationship extraction.
347
+
348
+ CRITICAL: For Baselines and Datasets, the summary/insight/quote fields describe THE RELATIONSHIP/COMPARISON, NOT the entity itself.
349
+
350
+ PRIORITY: RECALL > PRECISION
351
+ Your PRIMARY GOAL is to extract ALL baselines and datasets mentioned, especially from:
352
+ - Experimental results (tables, figures)
353
+ - Related Work section
354
+ - Appendix (supplementary experiments)
355
+ - Theoretical comparisons (complexity analysis)
356
+
357
+ It is BETTER to include a questionable baseline than to miss a real one.
358
+
359
+ Text Marking System:
360
+ You will see markers like [HINT_BASELINE:MethodName] - these are SUGGESTIONS only.
361
+ Read Experiments, Related Work, and Appendix thoroughly to find ALL baselines.
362
+
363
+ Keywords Usage:
364
+ Keywords should capture key concepts for COARSE-GRAINED RETRIEVAL. Choose representative terms for filtering and search.
365
+
366
+ Example Baseline Entry:
367
+ {
368
+ "name": "ResNet-50",
369
+ "acronym": null,
370
+ "related_to_core": "Swin Transformer",
371
+ "keywords": ["residual network", "image classification"],
372
+ "summary": "Our SwinT outperforms this baseline by 3.2 percent on ImageNet top-1 accuracy",
373
+ "metrics": ["Top-1 Accuracy", "Top-5 Accuracy"],
374
+ "insight": "Performance gap stems from ResNet lack of long-range modeling vs attention mechanisms",
375
+ "quote": "Our method achieves 82.1 percent top-1 accuracy, surpassing ResNet-50 78.9 percent"
376
+ }
377
+
378
+ Example Dataset Entry:
379
+ {
380
+ "name": "ImageNet-1K",
381
+ "acronym": "IN-1K",
382
+ "related_to_core": "Swin Transformer",
383
+ "keywords": ["image classification", "large-scale benchmark"],
384
+ "summary": "Primary benchmark used to evaluate classification performance",
385
+ "metrics": ["Top-1 Accuracy", "Top-5 Accuracy"],
386
+ "insight": "ImageNet diversity makes it the de facto standard, though class distribution may not reflect real-world scenarios",
387
+ "quote": "We evaluate on ImageNet-1K ILSVRC2012 validation set"
388
+ }"""
389
+
390
+ user = f"""
391
+ Core Methods Proposed in THIS Paper (DO NOT include as baselines): {json.dumps(core_names)}
392
+
393
+ FULL PAPER TEXT (Some baselines marked with [HINT_BASELINE:...] as suggestions):
394
+ Focus especially on:
395
+ - Experimental Results sections
396
+ - Related Work section
397
+ - Appendix / Supplementary Material
398
+ - Theoretical Comparisons
399
+
400
+ {marked_text}
401
+
402
+ Task: Extract ALL baselines and datasets with MAXIMUM RECALL.
403
+
404
+ PRIORITY: RECALL - When in doubt, INCLUDE the baseline. Missing a baseline is worse than false positive.
405
+
406
+ What is a Baseline (Expanded):
407
+ 1. Competitors: Methods explicitly compared in result tables
408
+ 2. Predecessors: Methods this work builds upon, improves, or fixes
409
+ 3. Related Work: Methods discussed as alternatives or inspiration
410
+ 4. Theoretical Comparisons: Methods compared in complexity analysis
411
+ 5. Appendix Comparisons: Additional baselines in supplementary experiments
412
+ 6. For Dataset Papers: Previous datasets compared OR models evaluated on new benchmark
413
+ 7. For Analysis Papers: Systems/methods being analyzed
414
+ 8. Ablation Variants: Simplified versions of proposed method (e.g., Ours w/o attention)
415
+
416
+ Naming Convention:
417
+ - Prioritize Method Name (e.g., SimCLR, Faster R-CNN, ImageNet-1K)
418
+ - Only use Author Name (e.g., He et al.) IF method has no specific name
419
+ - For ablations: Use descriptive name (e.g., SwinT w/o shifted windows)
420
+
421
+ CONSTRAINT:
422
+ Baselines must ONLY contain PREVIOUS EXISTING ENTITIES or ABLATION VARIANTS.
423
+ NEVER include full Core Contributions from THIS paper ({core_names}).
424
+
425
+ Output JSON Schema (FOLLOW THIS EXACT ATTRIBUTE ORDER):
426
+ {{
427
+ "baselines": [
428
+ {{
429
+ "name": "str",
430
+ "acronym": "str or null",
431
+ "related_to_core": "str (which core compared to)",
432
+ "keywords": ["str"],
433
+ "summary": "str (natural sentence about relationship)",
434
+ "metrics": ["str"] or null,
435
+ "insight": "str (WHY performance gap or relationship exists)",
436
+ "quote": "str (evidence)"
437
+ }}
438
+ ],
439
+ "datasets": [
440
+ {{
441
+ "name": "str",
442
+ "acronym": "str or null",
443
+ "related_to_core": "str",
444
+ "keywords": ["str"],
445
+ "summary": "str (how dataset is used)",
446
+ "metrics": ["str"] or null,
447
+ "insight": "str (why chosen, what reveals)",
448
+ "quote": "str"
449
+ }}
450
+ ]
451
+ }}
452
+
453
+ CRITICAL REMINDERS:
454
+ 1. PRIORITY: RECALL - Extract ALL from experiments, related work, appendix, theory
455
+ 2. summary/insight/quote: Describe THE EDGE (relationship), not node (entity)
456
+ 3. metrics: List of metric NAMES only (e.g., [Accuracy, F1]), OR null if not applicable
457
+ 4. Attribute order: MUST follow schema (name, acronym, related_to_core, keywords, summary, metrics, insight, quote)
458
+ 5. Keywords: Choose terms for RETRIEVAL purposes
459
+ 6. Verify entities appear in paper (no hallucination)
460
+ 7. When uncertain, INCLUDE IT
461
+ 8. Ignore [HINT_BASELINE:...] markers in output
462
+
463
+ Return JSON only:"""
464
+
465
+ return system, user
466
+
467
+
468
+ # ================= VALIDATION & PARSING (COMBINED) =================
469
+
470
+ def validate_and_parse_main(response: str, info_dict: dict = None) -> Tuple[bool, dict]:
471
+ """
472
+ Validate and parse main extraction response.
473
+
474
+ This function combines validation and parsing - the second return value
475
+ is the parsed result for use in aggregation.
476
+
477
+ Args:
478
+ response: LLM response string
479
+ info_dict: Optional dict with 'node_id' and 'title' (original title from markdown)
480
+
481
+ Returns:
482
+ Tuple of (is_valid, parsed_result_or_response)
483
+ - If valid: (True, parsed dict with node_id and result)
484
+ - If invalid: raises ValueError
485
+ """
486
+ if not response:
487
+ raise ValueError("Empty response")
488
+
489
+ parsed = extract_json(response)
490
+
491
+ if not isinstance(parsed, dict):
492
+ raise ValueError("Response is not a JSON object")
493
+
494
+ # Check required top-level keys
495
+ if 'metadata' not in parsed:
496
+ raise ValueError("Missing required key: metadata")
497
+
498
+ # Extract core names for baseline extraction
499
+ core_contributions = parsed.get("core_contributions", [])
500
+ core_names = [c.get("name") for c in core_contributions if c.get("name")]
501
+
502
+ # Extract original title from info_dict for fallback (info_dict contains the extracted title from markdown)
503
+ original_title = None
504
+ if info_dict:
505
+ original_title = info_dict.get('title')
506
+
507
+ result = {
508
+ 'node_id': info_dict.get('node_id') if info_dict else None,
509
+ 'result': parsed,
510
+ 'core_names': core_names,
511
+ 'original_title': original_title
512
+ }
513
+
514
+ return True, result
515
+
516
+
517
+ def validate_and_parse_baseline(response: str, info_dict: dict = None) -> Tuple[bool, dict]:
518
+ """
519
+ Validate and parse baseline extraction response.
520
+
521
+ This function combines validation and parsing - the second return value
522
+ is the parsed result for use in aggregation.
523
+
524
+ Args:
525
+ response: LLM response string
526
+ info_dict: Optional dict with 'node_id' and 'core_names'
527
+
528
+ Returns:
529
+ Tuple of (is_valid, parsed_result_or_response)
530
+ - If valid: (True, parsed dict with node_id and result)
531
+ - If invalid: raises ValueError
532
+ """
533
+ if not response:
534
+ raise ValueError("Empty response")
535
+
536
+ parsed = extract_json(response)
537
+
538
+ if not isinstance(parsed, dict):
539
+ raise ValueError("Response is not a JSON object")
540
+
541
+ # Check required top-level keys
542
+ if 'baselines' not in parsed and 'datasets' not in parsed:
543
+ raise ValueError("Missing required keys: baselines or datasets")
544
+
545
+ result = {
546
+ 'node_id': info_dict.get('node_id') if info_dict else None,
547
+ 'result': parsed,
548
+ 'core_names': info_dict.get('core_names', []) if info_dict else []
549
+ }
550
+
551
+ return True, result
552
+
553
+
554
+ # ================= RESULT AGGREGATOR =================
555
+
556
+ def aggregate_results(
557
+ main_results: List[dict],
558
+ baseline_results: List[dict],
559
+ source_info: Dict[str, dict]
560
+ ) -> List[dict]:
561
+ """Aggregate main and baseline results into final output."""
562
+ main_by_paper = {r['node_id']: r for r in main_results if r}
563
+ baseline_by_paper = {r['node_id']: r for r in (baseline_results or []) if r}
564
+
565
+ aggregated = []
566
+ for node_id in main_by_paper:
567
+ main_res = main_by_paper[node_id]
568
+ baseline_res = baseline_by_paper.get(node_id, {})
569
+ info = source_info.get(node_id, {})
570
+
571
+ result = main_res['result']
572
+ core_contributions = result.get("core_contributions", [])
573
+ core_names = main_res.get('core_names', [])
574
+
575
+ meta_info = result.get("metadata", {})
576
+ # Use LLM's title if available, otherwise use original_title from extraction
577
+ official_title = meta_info.get('title', 'Unknown')
578
+ if official_title == 'Unknown' or not official_title:
579
+ # Fallback to original title extracted from markdown
580
+ original_title = main_res.get('original_title')
581
+ if original_title and original_title != 'Unknown Title':
582
+ official_title = original_title
583
+
584
+ # Build self-reference set
585
+ self_names = {official_title.lower(), "ours", "proposed", "method", "model", "framework", "this work"}
586
+ for c in core_contributions:
587
+ if c.get("name"): self_names.add(c.get("name").lower())
588
+ if c.get("acronym"): self_names.add(c.get("acronym").lower())
589
+
590
+ # Filter components
591
+ valid_components = []
592
+ for comp in result.get("components", []):
593
+ c_name = comp.get("name", "").strip()
594
+ if not c_name or c_name.lower() in self_names:
595
+ continue
596
+ if any(c_name.lower() == cn.lower() for cn in core_names):
597
+ continue
598
+ related = comp.get("related_to_core")
599
+ if related not in core_names and len(core_names) == 1:
600
+ comp["related_to_core"] = core_names[0]
601
+ valid_components.append(comp)
602
+
603
+ # Filter baselines
604
+ valid_baselines = []
605
+ graph_data = baseline_res.get('result', {})
606
+ for item in graph_data.get("baselines", []):
607
+ name = item.get("name", "").strip()
608
+ if not name or name.lower() in self_names:
609
+ continue
610
+ related = item.get("related_to_core")
611
+ if related not in core_names and len(core_names) >= 1:
612
+ item["related_to_core"] = core_names[0]
613
+ if "keywords" in item:
614
+ item["keywords"] = [k for k in item["keywords"] if k.lower() not in METRIC_BLACKLIST]
615
+ valid_baselines.append(item)
616
+
617
+ # Filter datasets
618
+ valid_datasets = []
619
+ for ds in graph_data.get("datasets", []):
620
+ name = ds.get("name", "").strip()
621
+ if not name:
622
+ continue
623
+ related = ds.get("related_to_core")
624
+ if related not in core_names and len(core_names) >= 1:
625
+ ds["related_to_core"] = core_names[0]
626
+ valid_datasets.append(ds)
627
+
628
+ final_output = {
629
+ "node_id": node_id,
630
+ "source_venue": info.get("source_venue", "Unknown"),
631
+ "pub_year": info.get("pub_year", "2024"),
632
+ "metadata": {
633
+ "title": official_title,
634
+ "domain": meta_info.get("domain", "Others"),
635
+ "paper_type": meta_info.get("paper_type", "Others"),
636
+ "structured_summary": meta_info.get("structured_summary", {}),
637
+ "code_url": meta_info.get("code_url")
638
+ },
639
+ "ideation_resource": {
640
+ "problems": result.get("problems", []),
641
+ "core_contributions": core_contributions,
642
+ "core_relations": result.get("core_relations", []),
643
+ "components": valid_components,
644
+ "innovations": result.get("innovations", []),
645
+ "limitations": result.get("limitations", []),
646
+ "future_work": result.get("future_work", [])
647
+ },
648
+ "graph_data": {
649
+ "baselines": valid_baselines,
650
+ "datasets": valid_datasets
651
+ }
652
+ }
653
+ aggregated.append(final_output)
654
+
655
+ return aggregated
656
+
657
+
658
+ # ================= MAIN PIPELINE FUNCTION =================
659
+
660
+ def extract_paper_info_batch(
661
+ papers: Dict[str, str],
662
+ chat_agent,
663
+ source_info: Dict[str, str] = None,
664
+ temperature: float = 0.05,
665
+ max_retry: int = 3,
666
+ ) -> List[dict]:
667
+ """
668
+ Extract paper information using ChatAgent with retry.
669
+
670
+ Args:
671
+ papers: Dict mapping paper_id -> markdown_text
672
+ chat_agent: ChatAgent instance with batch_remote_chat_with_retry method
673
+ source_info: Optional dict mapping paper_id -> {source_venue, pub_year}
674
+ temperature: LLM temperature
675
+ max_retry: Max retry attempts per prompt
676
+
677
+ Returns:
678
+ List of extraction results
679
+ """
680
+ if source_info is None:
681
+ source_info = {}
682
+
683
+ paper_ids = list(papers.keys())
684
+ markdowns = list(papers.values())
685
+
686
+ # ===== Step 1: Main Extraction =====
687
+ main_prompts = []
688
+ main_metadata = []
689
+
690
+ for paper_id, markdown in zip(paper_ids, markdowns):
691
+ # Extract title from markdown
692
+ title = "Unknown Title"
693
+ for line in markdown.split('\n')[:20]:
694
+ match = re.match(r'^#\s+(.+)$', line.strip())
695
+ if match:
696
+ title = clean_title_latex(match.group(1))
697
+ break
698
+
699
+ regex_candidates = extract_regex_candidates(markdown)
700
+ system, user = build_main_extraction_prompt(markdown, title, regex_candidates)
701
+
702
+ # Combine system + user for the prompt
703
+ full_prompt = f"{system}\n\n{user}"
704
+ main_prompts.append(full_prompt)
705
+ main_metadata.append({
706
+ 'paper_id': paper_id,
707
+ 'title': title,
708
+ 'regex_candidates': regex_candidates
709
+ })
710
+
711
+ # Call with retry and validation - info_dict contains paper_id for later aggregation
712
+ main_responses = chat_agent.batch_remote_chat_with_retry(
713
+ main_prompts,
714
+ validate_fn=validate_and_parse_main,
715
+ max_retry=max_retry,
716
+ desc="Main extraction",
717
+ temperature=temperature,
718
+ info_dict={'metadata': main_metadata} # Pass metadata for aggregation
719
+ )
720
+
721
+ # main_responses are already parsed results from validate_and_parse_main
722
+ main_results = main_responses
723
+
724
+ # Build core names map for baseline extraction
725
+ core_names_map = {}
726
+ for res in main_results:
727
+ if res:
728
+ core_names_map[res['node_id']] = res.get('core_names', [])
729
+
730
+ # ===== Step 2: Baseline Extraction =====
731
+ baseline_prompts = []
732
+ baseline_metadata = []
733
+
734
+ for paper_id, markdown in zip(paper_ids, markdowns):
735
+ core_names = core_names_map.get(paper_id, [])
736
+ regex_candidates = extract_regex_candidates(markdown)
737
+ system, user = build_baseline_extraction_prompt(markdown, core_names, regex_candidates)
738
+
739
+ full_prompt = f"{system}\n\n{user}"
740
+ baseline_prompts.append(full_prompt)
741
+ baseline_metadata.append({
742
+ 'paper_id': paper_id,
743
+ 'core_names': core_names
744
+ })
745
+
746
+ # Call with retry and validation
747
+ baseline_responses = chat_agent.batch_remote_chat_with_retry(
748
+ baseline_prompts,
749
+ validate_fn=validate_and_parse_baseline,
750
+ max_retry=max_retry,
751
+ desc="Baseline extraction",
752
+ temperature=temperature,
753
+ info_dict={'metadata': baseline_metadata}
754
+ )
755
+
756
+ # baseline_responses are already parsed results from validate_and_parse_baseline
757
+ baseline_results = baseline_responses
758
+
759
+ # ===== Step 3: Aggregate =====
760
+ return aggregate_results(main_results, baseline_results, source_info)
761
+
762
+
763
+ def format_extraction_result(result: dict) -> str:
764
+ """Format extraction result into readable keynote string."""
765
+ if not result:
766
+ return "No details found."
767
+
768
+ meta = result.get('metadata', {})
769
+ structured_summary = meta.get('structured_summary', {})
770
+
771
+ formatted = f"Paper Title: {meta.get('title', 'N/A')}\n"
772
+ formatted += f"Paper Type: {meta.get('paper_type', 'N/A')}\n"
773
+ formatted += f"Domain: {meta.get('domain', 'N/A')}\n"
774
+ formatted += f"Summary (Background): {structured_summary.get('background', 'N/A')}\n"
775
+ formatted += f"Summary (Method): {structured_summary.get('method', 'N/A')}\n"
776
+ formatted += f"Summary (Result): {structured_summary.get('result', 'N/A')}\n"
777
+
778
+ ideation = result.get('ideation_resource', {})
779
+ cores = ideation.get('core_contributions', [])
780
+ if cores:
781
+ formatted += f"\nCore Contributions:\n"
782
+ for core in cores:
783
+ formatted += f" - {core.get('name', 'N/A')}: {core.get('summary', 'N/A')}\n"
784
+ formatted += f" Insight: {core.get('insight', 'N/A')}\n"
785
+
786
+ # Add Components section
787
+ components = ideation.get('components', [])
788
+ if components:
789
+ formatted += f"\nComponents:\n"
790
+ for comp in components:
791
+ related_to_core = comp.get('related_to_core', 'N/A')
792
+ formatted += f" - {comp.get('name', 'N/A')} (Part of: {related_to_core})\n"
793
+ formatted += f" Summary: {comp.get('summary', 'N/A')}\n"
794
+ formatted += f" Insight: {comp.get('insight', 'N/A')}\n"
795
+
796
+ all_keywords = []
797
+ for core in cores:
798
+ all_keywords.extend(core.get('keywords', []))
799
+ for comp in components:
800
+ all_keywords.extend(comp.get('keywords', []))
801
+ if all_keywords:
802
+ formatted += f"\nKeywords: {', '.join(all_keywords[:15])}\n"
803
+
804
+ return formatted
805
+
806
+
807
+ # ================= WRAPPER FUNCTIONS FOR COMPATIBILITY =================
808
+
809
+ def build_main_extraction_prompts(papers: Dict[str, str]) -> List[tuple]:
810
+ """
811
+ Build main extraction prompts for multiple papers.
812
+ Returns list of (full_prompt, paper_id, metadata_dict)
813
+ """
814
+ results = []
815
+ for paper_id, markdown in papers.items():
816
+ # Extract title from markdown
817
+ title = "Unknown Title"
818
+ for line in markdown.split('\n')[:20]:
819
+ match = re.match(r'^#\s+(.+)$', line.strip())
820
+ if match:
821
+ title = clean_title_latex(match.group(1))
822
+ break
823
+
824
+ regex_candidates = extract_regex_candidates(markdown)
825
+ system, user = build_main_extraction_prompt(markdown, title, regex_candidates)
826
+ full_prompt = f"{system}\n\n{user}"
827
+
828
+ results.append((full_prompt, paper_id, {'title': title, 'regex_candidates': regex_candidates}))
829
+
830
+ return results
831
+
832
+
833
+ def build_baseline_extraction_prompts(papers: Dict[str, str], core_names_map: Dict[str, List[str]]) -> List[tuple]:
834
+ """
835
+ Build baseline extraction prompts for multiple papers.
836
+ Returns list of (full_prompt, paper_id, metadata_dict)
837
+ """
838
+ results = []
839
+ for paper_id, markdown in papers.items():
840
+ core_names = core_names_map.get(paper_id, [])
841
+ regex_candidates = extract_regex_candidates(markdown)
842
+ system, user = build_baseline_extraction_prompt(markdown, core_names, regex_candidates)
843
+ full_prompt = f"{system}\n\n{user}"
844
+
845
+ results.append((full_prompt, paper_id, {'core_names': core_names}))
846
+
847
+ return results
848
+
849
+
850
+ def aggregate_extraction_results(
851
+ main_results: List[dict],
852
+ baseline_results: List[dict],
853
+ source_info: Dict[str, dict]
854
+ ) -> List[dict]:
855
+ """Wrapper for aggregate_results for compatibility."""
856
+ return aggregate_results(main_results, baseline_results, source_info)