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,648 @@
1
+ """Build mature-idea portfolios from heterogeneous sources and scoped evidence."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from copy import deepcopy
6
+ from itertools import combinations
7
+ from typing import Any, Dict, Iterable, List, Mapping, Sequence
8
+
9
+ from src.agents.idea_agent.utils.workflow.idea_contract import (
10
+ normalize_mature_ideas,
11
+ )
12
+ from src.agents.idea_agent.utils.workflow.idea_diversity import (
13
+ filter_independent_mature_ideas,
14
+ )
15
+ from src.agents.idea_agent.utils.workflow.multimodal_data_anchoring import (
16
+ annotate_data_anchored_mature_idea,
17
+ scoped_multimodal_evidence_for_idea,
18
+ )
19
+
20
+
21
+ MATURE_IDEA_SOURCES = (
22
+ "user_input",
23
+ "survey_gap",
24
+ "prior_candidate",
25
+ "experiment_feedback",
26
+ "problem_reframing",
27
+ "adversarial_generation",
28
+ "cross_domain_transfer",
29
+ )
30
+
31
+ _SOURCE_ALIASES = {
32
+ "survey": "survey_gap",
33
+ "survey_gap": "survey_gap",
34
+ "history": "prior_candidate",
35
+ "prior": "prior_candidate",
36
+ "prior_candidate": "prior_candidate",
37
+ "experiment": "experiment_feedback",
38
+ "experiment_feedback": "experiment_feedback",
39
+ "generated": "problem_reframing",
40
+ "problem_reframing": "problem_reframing",
41
+ "adversarial": "adversarial_generation",
42
+ "adversarial_generation": "adversarial_generation",
43
+ "cross_domain": "cross_domain_transfer",
44
+ "cross_domain_transfer": "cross_domain_transfer",
45
+ "user": "user_input",
46
+ "user_input": "user_input",
47
+ }
48
+
49
+ _ACTIVE_GAP_ROUTES = {
50
+ "core_hypothesis",
51
+ "provisional_hypothesis",
52
+ "exploratory_frontier",
53
+ "future_work_seed",
54
+ }
55
+
56
+
57
+ def _text(value: Any) -> str:
58
+ return str(value or "").strip()
59
+
60
+
61
+ def _mapping(value: Any) -> Dict[str, Any]:
62
+ return dict(value) if isinstance(value, Mapping) else {}
63
+
64
+
65
+ def _list(value: Any) -> List[Any]:
66
+ if value is None:
67
+ return []
68
+ if isinstance(value, (list, tuple, set)):
69
+ return list(value)
70
+ return [value]
71
+
72
+
73
+ def _unique(values: Iterable[Any]) -> List[str]:
74
+ result: List[str] = []
75
+ seen = set()
76
+ for value in _list(values):
77
+ item = _text(value)
78
+ if not item or item.casefold() in seen:
79
+ continue
80
+ seen.add(item.casefold())
81
+ result.append(item)
82
+ return result
83
+
84
+
85
+ def _canonical_source(value: Any, default: str = "user_input") -> str:
86
+ source = _text(value).casefold()
87
+ return _SOURCE_ALIASES.get(source, _text(default) or "user_input")
88
+
89
+
90
+ def _source_record(raw: Any, source: str, *, index: int = 0, lineage: Any = None) -> Dict[str, Any]:
91
+ if isinstance(raw, Mapping):
92
+ record = dict(raw)
93
+ else:
94
+ record = {"title": _text(raw), "hypothesis": _text(raw)}
95
+ source = _canonical_source(source)
96
+ lineage = lineage if lineage is not None else source
97
+ record["idea_source"] = source
98
+ record["lineage"] = lineage
99
+ if not record.get("source_lineage"):
100
+ record["source_lineage"] = [{"idea_source": source, "lineage": deepcopy(lineage)}]
101
+ if not _text(record.get("maturity_status")):
102
+ record["maturity_status"] = "provisional" if source in {"survey_gap", "experiment_feedback"} else "mature"
103
+ if not _text(record.get("idea_id")):
104
+ record["idea_id"] = f"{source}-{index + 1:02d}"
105
+ return record
106
+
107
+
108
+ def _gap_rows(survey_handoff: Any, gap_triage: Any = None) -> List[Dict[str, Any]]:
109
+ handoff = survey_handoff if isinstance(survey_handoff, Mapping) else {}
110
+ triage_candidate = gap_triage if isinstance(gap_triage, Mapping) else handoff.get("gap_triage")
111
+ triage = dict(triage_candidate) if isinstance(triage_candidate, Mapping) else {}
112
+ triage_by_id = {
113
+ _text(row.get("gap_id")): row
114
+ for row in _list(triage.get("gaps"))
115
+ if isinstance(row, Mapping) and _text(row.get("gap_id"))
116
+ }
117
+ rows: List[Dict[str, Any]] = []
118
+ for row in _list(handoff.get("gaps")):
119
+ if not isinstance(row, Mapping):
120
+ continue
121
+ gap_id = _text(row.get("gap_id"))
122
+ triage_row = triage_by_id.get(gap_id, {})
123
+ route = _text(triage_row.get("eligibility_route") or row.get("eligibility_route"))
124
+ if route and route not in _ACTIVE_GAP_ROUTES:
125
+ continue
126
+ rows.append({**dict(row), **dict(triage_row)})
127
+ if rows:
128
+ return rows
129
+ return [dict(row) for row in triage_by_id.values()]
130
+
131
+
132
+ def _survey_gap_ideas(survey_handoff: Any, gap_triage: Any = None, *, limit: int = 4) -> List[Dict[str, Any]]:
133
+ ideas: List[Dict[str, Any]] = []
134
+ gap_rows = _gap_rows(survey_handoff, gap_triage)[:limit]
135
+ for index, gap in enumerate(gap_rows):
136
+ gap_id = _text(gap.get("gap_id"))
137
+ statement = _text(gap.get("statement") or gap.get("gap") or gap.get("description"))
138
+ target_object = gap.get("target_object") or gap.get("scientific_object") or gap.get("object")
139
+ mechanism = _text(gap.get("mechanism") or gap.get("missing_mechanism") or gap.get("target_slot"))
140
+ evidence = gap.get("evidence_basis") or gap.get("source_anchors") or gap.get("evidence_roles") or []
141
+ ideas.append(
142
+ _source_record(
143
+ {
144
+ "idea_id": f"survey-gap-{gap_id or index + 1}",
145
+ "title": _text(gap.get("title")) or f"Gap route: {gap_id or index + 1}",
146
+ "abstract": statement,
147
+ "hypothesis": statement or f"The unresolved relation associated with {gap_id} is testable.",
148
+ "scientific_object": target_object or {},
149
+ "mechanism": mechanism,
150
+ "mechanism_or_relation": mechanism,
151
+ "target_gap_ids": [gap_id] if gap_id else [],
152
+ "gap_alignment": [{"gap_id": gap_id, "alignment": "survey_gap"}] if gap_id else [],
153
+ "evidence_basis": evidence,
154
+ "refinement_scope": _text(gap.get("target_slot") or gap.get("refinement_scope")),
155
+ "falsifier": _text(gap.get("falsifier") or gap.get("discriminating_observation"))
156
+ or "A result showing the stated gap is resolved without this hypothesis.",
157
+ },
158
+ "survey_gap",
159
+ index=index,
160
+ lineage={"source": "survey", "gap_id": gap_id},
161
+ )
162
+ )
163
+ if len(gap_rows) >= 2:
164
+ for index, pair in enumerate(combinations(gap_rows[:3], 2)):
165
+ gap_ids = [_text(item.get("gap_id")) for item in pair if _text(item.get("gap_id"))]
166
+ statements = [
167
+ _text(item.get("statement") or item.get("gap") or item.get("description"))
168
+ for item in pair
169
+ ]
170
+ ideas.append(
171
+ _source_record(
172
+ {
173
+ "idea_id": "survey-gap-combination-" + "-".join(gap_ids),
174
+ "title": "Combined gap route: " + " + ".join(gap_ids),
175
+ "abstract": " | ".join(item for item in statements if item),
176
+ "hypothesis": "The joint constraints represented by " + ", ".join(gap_ids) + " admit a shared mechanism.",
177
+ "scientific_object": [
178
+ _text(item.get("target_object") or item.get("scientific_object"))
179
+ for item in pair
180
+ ],
181
+ "mechanism": "Joint mechanism linking the selected gap constraints.",
182
+ "target_gap_ids": gap_ids,
183
+ "gap_alignment": [
184
+ {"gap_id": gap_id, "alignment": "combined_survey_gaps"}
185
+ for gap_id in gap_ids
186
+ ],
187
+ "evidence_basis": [
188
+ item.get("evidence_basis") or item.get("source_anchors") or []
189
+ for item in pair
190
+ ],
191
+ "falsifier": "Evidence that the selected gaps require mutually incompatible mechanisms.",
192
+ },
193
+ "survey_gap",
194
+ index=limit + index,
195
+ lineage={"source": "survey", "gap_ids": gap_ids, "combination": True},
196
+ )
197
+ )
198
+ return ideas
199
+
200
+
201
+ def _survey_subhypothesis_ideas(survey_handoff: Any, *, limit: int = 6) -> List[Dict[str, Any]]:
202
+ """Promote independent Survey sub-hypotheses into source records."""
203
+
204
+ handoff = survey_handoff if isinstance(survey_handoff, Mapping) else {}
205
+ raw_rows: List[Any] = []
206
+ for key in ("subhypotheses", "sub_hypotheses", "hypothesis_seeds", "subhypothesis_candidates"):
207
+ value = handoff.get(key)
208
+ if isinstance(value, Mapping):
209
+ value = value.get("items") or value.get("records") or value.get("seeds") or []
210
+ raw_rows.extend(_list(value))
211
+ ideas: List[Dict[str, Any]] = []
212
+ for index, raw in enumerate(raw_rows[:limit]):
213
+ if not isinstance(raw, Mapping):
214
+ continue
215
+ gap_ids = _unique(raw.get("target_gap_ids") or raw.get("gap_ids") or raw.get("gap_id"))
216
+ hypothesis = _text(raw.get("hypothesis") or raw.get("central_hypothesis") or raw.get("statement"))
217
+ if not hypothesis and not _text(raw.get("title")):
218
+ continue
219
+ ideas.append(
220
+ _source_record(
221
+ {
222
+ **dict(raw),
223
+ "idea_id": _text(raw.get("idea_id")) or f"survey-subhypothesis-{index + 1:02d}",
224
+ "title": _text(raw.get("title")) or f"Survey sub-hypothesis {index + 1}",
225
+ "hypothesis": hypothesis,
226
+ "target_gap_ids": gap_ids,
227
+ "evidence_basis": raw.get("evidence_basis") or raw.get("source_anchors") or [],
228
+ },
229
+ "survey_gap",
230
+ index=index,
231
+ lineage={"source": "survey", "subhypothesis_id": _text(raw.get("subhypothesis_id") or raw.get("idea_id"))},
232
+ )
233
+ )
234
+ return ideas
235
+
236
+
237
+ def _prior_candidate_ideas(candidate: Any) -> List[Dict[str, Any]]:
238
+ if isinstance(candidate, Mapping):
239
+ candidates = candidate.get("candidates") or candidate.get("history") or [candidate]
240
+ else:
241
+ candidates = candidate
242
+ ideas: List[Dict[str, Any]] = []
243
+ for index, item in enumerate(_list(candidates)):
244
+ if not isinstance(item, Mapping) or not item:
245
+ continue
246
+ ideas.append(
247
+ _source_record(
248
+ deepcopy(item),
249
+ "prior_candidate",
250
+ index=index,
251
+ lineage={"source": "history", "candidate_id": _text(item.get("idea_id") or item.get("seed_id"))},
252
+ )
253
+ )
254
+ return ideas
255
+
256
+
257
+ def _experiment_feedback_ideas(results: Any, *, limit: int = 4) -> List[Dict[str, Any]]:
258
+ ideas: List[Dict[str, Any]] = []
259
+ if isinstance(results, Mapping):
260
+ results = results.get("results") or results.get("ablations") or results.get("experiments") or []
261
+ for index, item in enumerate(_list(results)[:limit]):
262
+ if not isinstance(item, Mapping):
263
+ continue
264
+ component = _text(item.get("component") or item.get("name"))
265
+ outcome = _text(item.get("result") or item.get("status") or item.get("hypothesis_status"))
266
+ analysis = _text(item.get("analysis") or item.get("finding") or item.get("summary"))
267
+ if not component and not analysis:
268
+ continue
269
+ ideas.append(
270
+ _source_record(
271
+ {
272
+ "idea_id": f"experiment-feedback-{index + 1:02d}",
273
+ "title": f"Experiment feedback: {component or index + 1}",
274
+ "abstract": analysis or outcome,
275
+ "hypothesis": f"The observed feedback for {component or 'the candidate'} identifies a mechanism-level refinement.",
276
+ "scientific_object": component,
277
+ "mechanism": analysis,
278
+ "mechanism_or_relation": analysis,
279
+ "evidence_basis": [analysis, outcome],
280
+ "falsifier": "A repeated controlled result that removes the reported effect.",
281
+ },
282
+ "experiment_feedback",
283
+ index=index,
284
+ lineage={"source": "ablation_results", "component": component, "outcome": outcome},
285
+ )
286
+ )
287
+ return ideas
288
+
289
+
290
+ def _analysis_source_ideas(analysis: Any) -> List[Dict[str, Any]]:
291
+ if not isinstance(analysis, Mapping):
292
+ return []
293
+ ideas: List[Dict[str, Any]] = []
294
+ groups = (
295
+ ("problem_reframing", "problem_reframing_ideas"),
296
+ ("problem_reframing", "reframed_ideas"),
297
+ ("adversarial_generation", "adversarial_idea_seeds"),
298
+ ("adversarial_generation", "divergent_idea_seeds"),
299
+ ("cross_domain_transfer", "cross_domain_inspiration"),
300
+ )
301
+ counters: Dict[str, int] = {}
302
+ for source, key in groups:
303
+ for raw in _list(analysis.get(key)):
304
+ if not isinstance(raw, Mapping):
305
+ continue
306
+ mapped = dict(raw)
307
+ if source == "cross_domain_transfer":
308
+ mapped.setdefault("title", _text(raw.get("source_field")) or "Cross-domain transfer")
309
+ mapped.setdefault("hypothesis", raw.get("application_hook"))
310
+ mapped.setdefault("mechanism", raw.get("transferable_mechanism"))
311
+ mapped.setdefault("mechanism_or_relation", raw.get("transferable_mechanism"))
312
+ mapped.setdefault("scientific_object", raw.get("source_field"))
313
+ elif source == "adversarial_generation":
314
+ mapped.setdefault("mechanism", raw.get("method_sketch") or raw.get("method"))
315
+ mapped.setdefault("mechanism_or_relation", raw.get("method_sketch") or raw.get("method"))
316
+ mapped.setdefault("falsifier", raw.get("evaluation_plan"))
317
+ elif source == "problem_reframing":
318
+ mapped.setdefault("title", raw.get("reframed_problem") or raw.get("new_question"))
319
+ mapped.setdefault("hypothesis", raw.get("reframed_problem") or raw.get("new_question"))
320
+ mapped.setdefault("mechanism", raw.get("mechanism") or raw.get("mechanism_sketch"))
321
+ mapped.setdefault("mechanism_or_relation", raw.get("mechanism") or raw.get("mechanism_sketch"))
322
+ counters[source] = counters.get(source, 0) + 1
323
+ ideas.append(
324
+ _source_record(
325
+ mapped,
326
+ source,
327
+ index=counters[source] - 1,
328
+ lineage={"source": "advanced_analysis", "field": key},
329
+ )
330
+ )
331
+ return ideas
332
+
333
+
334
+ def collect_mature_idea_sources(
335
+ *,
336
+ existing: Any = None,
337
+ survey_handoff: Any = None,
338
+ gap_triage: Any = None,
339
+ prior_candidate: Any = None,
340
+ experiment_results: Any = None,
341
+ analysis: Any = None,
342
+ max_ideas: int = 12,
343
+ allow_problem_reframing: bool = True,
344
+ allow_unanchored_seed: bool = True,
345
+ allow_high_risk_seed: bool = True,
346
+ multimodal_evidence_projection: Mapping[str, Any] | None = None,
347
+ ) -> List[Dict[str, Any]]:
348
+ """Collect, structurally deduplicate, and annotate mature ideas by lineage."""
349
+
350
+ records: List[Dict[str, Any]] = []
351
+ for raw in normalize_mature_ideas(existing, default_source="user_input"):
352
+ records.append(
353
+ _source_record(
354
+ raw,
355
+ _canonical_source(raw.get("idea_source"), "user_input"),
356
+ lineage=raw.get("lineage") or "user_input",
357
+ )
358
+ )
359
+ records.extend(_survey_gap_ideas(survey_handoff, gap_triage))
360
+ records.extend(_survey_subhypothesis_ideas(survey_handoff))
361
+ records.extend(_prior_candidate_ideas(prior_candidate))
362
+ records.extend(_experiment_feedback_ideas(experiment_results))
363
+ records.extend(_analysis_source_ideas(analysis))
364
+ records = [
365
+ annotate_data_anchored_mature_idea(
366
+ record,
367
+ survey_idea_handoff=survey_handoff if isinstance(survey_handoff, Mapping) else {},
368
+ multimodal_evidence_projection=multimodal_evidence_projection,
369
+ )
370
+ for record in records
371
+ ]
372
+
373
+ independent = filter_independent_mature_ideas(records)
374
+ enriched: List[Dict[str, Any]] = []
375
+ for record in independent:
376
+ maturity = assess_mature_idea_maturity(record, independent=True)
377
+ record["maturity"] = maturity
378
+ record["maturity_status"] = maturity["maturity_status"]
379
+ record["maturity_is_not_rank"] = True
380
+ source = _canonical_source(record.get("idea_source"), "user_input")
381
+ if not allow_problem_reframing and source == "problem_reframing":
382
+ continue
383
+ if not allow_unanchored_seed and (
384
+ bool(record.get("anti_anchor")) or source in {"problem_reframing", "adversarial_generation"}
385
+ ):
386
+ continue
387
+ if not allow_high_risk_seed and (
388
+ maturity.get("maturity_status") in {"exploratory", "needs_grounding"}
389
+ or _text(record.get("risk")).casefold() in {"high", "major"}
390
+ ):
391
+ continue
392
+ enriched.append(record)
393
+ limit = max(1, int(max_ideas or 12))
394
+ if len(enriched) <= limit:
395
+ return enriched
396
+ selected: List[Dict[str, Any]] = []
397
+ selected_ids = set()
398
+ for source in MATURE_IDEA_SOURCES:
399
+ item = next((record for record in enriched if record.get("idea_source") == source), None)
400
+ if item is not None:
401
+ selected.append(item)
402
+ selected_ids.add(id(item))
403
+ if len(selected) >= limit:
404
+ return selected[:limit]
405
+ for item in enriched:
406
+ if id(item) in selected_ids:
407
+ continue
408
+ selected.append(item)
409
+ if len(selected) >= limit:
410
+ break
411
+ return selected
412
+
413
+
414
+ def assess_mature_idea_maturity(
415
+ idea: Mapping[str, Any],
416
+ *,
417
+ evidence_context: Mapping[str, Any] | None = None,
418
+ independent: bool = True,
419
+ ) -> Dict[str, Any]:
420
+ """Score maturity dimensions independently; no single winner is selected."""
421
+
422
+ evidence_context = evidence_context if isinstance(evidence_context, Mapping) else {}
423
+ specificity = sum(
424
+ bool(idea.get(field))
425
+ for field in ("title", "hypothesis", "scientific_object", "target_gap_ids")
426
+ ) / 4.0
427
+ mechanism_complete = sum(
428
+ bool(idea.get(field))
429
+ for field in ("mechanism", "mechanism_or_relation", "intervention_or_transformation", "assumptions")
430
+ ) / 4.0
431
+ evidence_support = 1.0 if idea.get("evidence_basis") or evidence_context.get("evidence_subset") else 0.0
432
+ falsifiability = 1.0 if idea.get("falsifier") or idea.get("discriminating_observation") else 0.0
433
+ scope_clarity = 1.0 if idea.get("refinement_scope") or idea.get("claim_scope") else 0.0
434
+ executability = 1.0 if evidence_context.get("validation_targets") or (evidence_support and falsifiability) else 0.0
435
+ independence_score = 1.0 if independent else 0.0
436
+ dimensions = {
437
+ "specificity": round(specificity, 3),
438
+ "mechanism_completeness": round(mechanism_complete, 3),
439
+ "evidence_support": round(evidence_support, 3),
440
+ "falsifiability": round(falsifiability, 3),
441
+ "scope_clarity": round(scope_clarity, 3),
442
+ "executability": round(executability, 3),
443
+ "independence": round(independence_score, 3),
444
+ }
445
+ average = sum(dimensions.values()) / len(dimensions)
446
+ minimum = min(dimensions.values())
447
+ source_status = _text(idea.get("maturity_status")).lower()
448
+ if source_status == "rejected":
449
+ status = "rejected"
450
+ elif average >= 0.68 and minimum >= 0.45:
451
+ status = "mature"
452
+ elif average >= 0.42:
453
+ status = "provisional"
454
+ elif evidence_support == 0.0:
455
+ status = "needs_grounding"
456
+ else:
457
+ status = "exploratory"
458
+ return {
459
+ "dimensions": dimensions,
460
+ "aggregate": round(average, 3),
461
+ "maturity_status": status,
462
+ "maturity_is_not_rank": True,
463
+ }
464
+
465
+
466
+ def build_mature_idea_evidence_context(
467
+ idea: Mapping[str, Any],
468
+ *,
469
+ topic: str = "",
470
+ survey_handoff: Any = None,
471
+ references: Sequence[Mapping[str, Any]] | None = None,
472
+ ablation_results: Any = None,
473
+ public_facts: Any = None,
474
+ multimodal_evidence_projection: Mapping[str, Any] | None = None,
475
+ ) -> Dict[str, Any]:
476
+ """Create public, idea-specific, and anti-anchor evidence layers."""
477
+
478
+ handoff = dict(survey_handoff) if isinstance(survey_handoff, Mapping) else {}
479
+ source = _canonical_source(idea.get("idea_source"), "user_input")
480
+ anti_anchor = source in {"problem_reframing", "adversarial_generation"} or _text(idea.get("anchor_policy")) == "reframe_without_default_problem_anchor"
481
+ gap_ids = set(_text(item) for item in _list(idea.get("target_gap_ids")))
482
+ gaps = [
483
+ dict(row)
484
+ for row in _gap_rows(handoff)
485
+ if gap_ids and _text(row.get("gap_id")) in gap_ids
486
+ ]
487
+ data_evidence = scoped_multimodal_evidence_for_idea(
488
+ idea,
489
+ survey_idea_handoff=handoff,
490
+ multimodal_evidence_projection=multimodal_evidence_projection,
491
+ )
492
+ keywords = set(
493
+ _text(value).casefold()
494
+ for value in (
495
+ idea.get("title"),
496
+ idea.get("hypothesis"),
497
+ idea.get("mechanism"),
498
+ idea.get("mechanism_or_relation"),
499
+ )
500
+ if _text(value)
501
+ )
502
+ evidence_subset: List[Dict[str, Any]] = []
503
+ target_anchor_ids = {
504
+ _text(anchor_id)
505
+ for gap in gaps
506
+ for anchor_id in _list(gap.get("anchor_ids"))
507
+ if _text(anchor_id)
508
+ }
509
+ scoped_anchors = [
510
+ anchor
511
+ for anchor in _list(handoff.get("anchors"))
512
+ if isinstance(anchor, Mapping)
513
+ and (
514
+ _text(anchor.get("anchor_id")) in target_anchor_ids
515
+ or anchor in data_evidence.get("source_anchors", [])
516
+ )
517
+ ]
518
+ scoped_paper_ids = {
519
+ _text(_mapping(anchor.get("source_pointer")).get("paper_id"))
520
+ for anchor in scoped_anchors
521
+ if _text(_mapping(anchor.get("source_pointer")).get("paper_id"))
522
+ }
523
+ target_subhypotheses_for_papers = {_text(gap.get("subhypothesis_id")) for gap in gaps}
524
+ for role in _list(handoff.get("evidence_roles")):
525
+ if not isinstance(role, Mapping) or _text(role.get("subhypothesis_id")) not in target_subhypotheses_for_papers:
526
+ continue
527
+ scoped_paper_ids.update(
528
+ paper_id
529
+ for paper_id in _unique(
530
+ [
531
+ role.get("paper_id"),
532
+ *_list(role.get("paper_ids")),
533
+ *_list(role.get("qualified_paper_ids")),
534
+ *_list(role.get("background_paper_ids")),
535
+ ]
536
+ )
537
+ if paper_id
538
+ )
539
+ scoped_paper_ids.update(
540
+ _text(assessment.get("paper_id"))
541
+ for assessment in _list(data_evidence.get("paper_assessments"))
542
+ if isinstance(assessment, Mapping) and _text(assessment.get("paper_id"))
543
+ )
544
+ for reference in references or []:
545
+ if not isinstance(reference, Mapping):
546
+ continue
547
+ ref_text = " ".join(_text(reference.get(field)) for field in ("title", "abstract", "summary", "tldr")).casefold()
548
+ if _text(reference.get("paper_id")) in scoped_paper_ids or any(
549
+ gap_id.casefold() in ref_text for gap_id in gap_ids
550
+ ) or any(
551
+ keyword and keyword in ref_text for keyword in keywords
552
+ ):
553
+ evidence_subset.append(dict(reference))
554
+ evidence_subset = evidence_subset[:8]
555
+ ablation_subset = [
556
+ dict(item)
557
+ for item in _list(ablation_results)
558
+ if isinstance(item, Mapping)
559
+ and idea.get("scientific_object")
560
+ and _text(item.get("component") or item.get("name")).casefold()
561
+ in _text(idea.get("scientific_object")).casefold()
562
+ ][:6]
563
+ scoped_handoff = {
564
+ key: deepcopy(value)
565
+ for key, value in handoff.items()
566
+ if key not in {"gaps", "gap_triage", "source_anchors", "evidence_roles"}
567
+ }
568
+ scoped_handoff["gaps"] = gaps
569
+ raw_gap_triage = handoff.get("gap_triage")
570
+ raw_gap_triage_rows = (
571
+ raw_gap_triage.get("gaps")
572
+ if isinstance(raw_gap_triage, Mapping)
573
+ else raw_gap_triage
574
+ )
575
+ scoped_handoff["gap_triage"] = {
576
+ "gaps": [
577
+ row
578
+ for row in _list(raw_gap_triage_rows)
579
+ if isinstance(row, Mapping)
580
+ and (
581
+ gap_ids and _text(row.get("gap_id")) in gap_ids
582
+ )
583
+ ]
584
+ }
585
+ target_subhypotheses = {_text(gap.get("subhypothesis_id")) for gap in gaps}
586
+ scoped_handoff["anchors"] = [
587
+ deepcopy(anchor)
588
+ for anchor in scoped_anchors
589
+ ]
590
+ scoped_handoff["evidence_roles"] = [
591
+ deepcopy(role)
592
+ for role in _list(handoff.get("evidence_roles"))
593
+ if isinstance(role, Mapping)
594
+ and (
595
+ _text(role.get("subhypothesis_id")) in target_subhypotheses
596
+ or bool(
597
+ set(_unique(role.get("anchor_ids")))
598
+ & {_text(anchor.get("anchor_id")) for anchor in scoped_anchors}
599
+ )
600
+ )
601
+ ]
602
+ result = {
603
+ "public_facts": deepcopy(public_facts) if isinstance(public_facts, (Mapping, list, str)) else {},
604
+ "idea_id": _text(idea.get("idea_id")),
605
+ "idea_source": source,
606
+ "gap_explanation": gaps,
607
+ "evidence_subset": evidence_subset,
608
+ "retrieval_queries": _unique(
609
+ [topic, idea.get("title"), idea.get("hypothesis"), idea.get("mechanism_or_relation")]
610
+ ),
611
+ "counterexamples": _list(idea.get("counterexamples") or idea.get("negative_evidence")) + ablation_subset,
612
+ "mechanism_chain": _unique(
613
+ [idea.get("scientific_object"), idea.get("hypothesis"), idea.get("mechanism_or_relation"), idea.get("falsifier")]
614
+ ),
615
+ "validation_targets": _unique(
616
+ [idea.get("falsifier"), idea.get("discriminating_observation"), idea.get("refinement_scope")]
617
+ ),
618
+ "survey_handoff": scoped_handoff,
619
+ "anchor_policy": "reframe_without_default_problem_anchor" if anti_anchor else "scoped_survey_anchor",
620
+ "anti_anchor": anti_anchor,
621
+ "anti_anchor_reason": (
622
+ "This idea challenges the default problem definition and therefore receives public facts only; "
623
+ "Survey gaps and evidence are included only when explicitly targeted."
624
+ if anti_anchor
625
+ else "Evidence is scoped to the idea's selected gaps and mechanism."
626
+ ),
627
+ }
628
+ if data_evidence:
629
+ result["multimodal_evidence_context"] = data_evidence
630
+ result["counterexamples"] = _list(result["counterexamples"]) + [
631
+ *data_evidence.get("competing_explanations", []),
632
+ *data_evidence.get("claim_limits", []),
633
+ ]
634
+ result["validation_targets"] = _unique(
635
+ [
636
+ *result["validation_targets"],
637
+ *data_evidence.get("measurement_needs", []),
638
+ ]
639
+ )
640
+ return result
641
+
642
+
643
+ __all__ = [
644
+ "MATURE_IDEA_SOURCES",
645
+ "collect_mature_idea_sources",
646
+ "assess_mature_idea_maturity",
647
+ "build_mature_idea_evidence_context",
648
+ ]