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,559 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib
4
+ from types import SimpleNamespace
5
+
6
+ import pytest
7
+
8
+ from src.agents.idea_agent.agent.prompts.component_extraction import (
9
+ COMPONENT_EXTRACTION_PROMPT,
10
+ )
11
+ from src.agents.idea_agent.agent.prompts.advanced_analysis import (
12
+ ADVANCED_ANALYSIS_PROMPT,
13
+ render_advanced_analysis_prompt,
14
+ )
15
+ from src.agents.idea_agent.agent.prompts.idea_fusion import (
16
+ IDEA_FUSION_PROMPT,
17
+ render_idea_fusion_prompt,
18
+ )
19
+ from src.agents.idea_agent.agent.prompts.mcts_evaluation import (
20
+ MCTS_IDEA_EVALUATION_PROMPT,
21
+ )
22
+ from src.agents.idea_agent.agent.prompts.mcts_generation import (
23
+ MCTS_IDEA_GENERATION_PROMPT,
24
+ )
25
+ from src.agents.idea_agent.agent.prompts.skill_instantiation import (
26
+ SKILL_INSTANTIATION_PROMPT,
27
+ )
28
+ from src.agents.idea_agent.utils.mcts.defect_registry import format_defect_registry
29
+ from src.agents.idea_agent.utils.mcts.defect_registry import profile_skill_defect_tags
30
+ from src.agents.idea_agent.utils.mcts.idea_taste_presets import (
31
+ SCORE_WEIGHT_FIELDS,
32
+ get_idea_taste_preset,
33
+ )
34
+ from src.agents.idea_agent.utils.mcts.mcts_runtime import (
35
+ _contract_from_instantiation,
36
+ _direction_prompt_context,
37
+ _route_contract_incomplete_fields,
38
+ _route_contract_noop_fields,
39
+ EditPlan,
40
+ evaluation_prompt_cache_key,
41
+ materialize_child_state,
42
+ merge_hypothesis_contract,
43
+ ValidationProtocol,
44
+ )
45
+ from src.agents.idea_agent.utils.mcts.scientific_intervention_ontology import (
46
+ format_scientific_intervention_profile_for_prompt,
47
+ get_scientific_intervention_profile,
48
+ )
49
+ from src.agents.idea_agent.utils.mcts.scientific_rubric import (
50
+ format_scientific_rubric_for_prompt,
51
+ )
52
+ from src.agents.idea_agent.utils.workflow.idea_contract import normalize_idea_contract
53
+
54
+
55
+ def _profile_payload(profile_id: str) -> dict[str, object]:
56
+ profile = get_scientific_intervention_profile(profile_id)
57
+ assert profile is not None
58
+ payload = profile.to_payload()
59
+ payload["contribution_mode"] = profile.contribution_modes[0].mode_id
60
+ return payload
61
+
62
+
63
+ def test_profile_text_is_injected_into_generation_and_extraction_prompts() -> None:
64
+ profile_text = format_scientific_intervention_profile_for_prompt(
65
+ _profile_payload("physical_materials_chemical")
66
+ )
67
+ assert "physical_materials_chemical" in profile_text
68
+ assert "structure_property_mechanism" in profile_text
69
+ generation = MCTS_IDEA_GENERATION_PROMPT.format(
70
+ topic="battery degradation",
71
+ direction_mode="evidence_first",
72
+ direction_summary="Prefer defensible evidence.",
73
+ taste_guidance="Use a narrow mechanism.",
74
+ target_gap_ids="gap-1",
75
+ profile_id="physical_materials_chemical",
76
+ scientific_intervention_profile=profile_text,
77
+ profile_native_object_schema="{}",
78
+ gap_seed_context="seed-1",
79
+ current_summary="parent",
80
+ paper_context="papers",
81
+ memory_bundle="memory",
82
+ edit_operators="ops",
83
+ constraints="constraints",
84
+ max_children=2,
85
+ )
86
+ extraction = COMPONENT_EXTRACTION_PROMPT.format(
87
+ mature_idea="materials idea",
88
+ topic="battery degradation",
89
+ scientific_intervention_profile=profile_text,
90
+ prior_components="[]",
91
+ component_decisions="[]",
92
+ )
93
+ assert "physical_materials_chemical" in generation
94
+ assert "physical_materials_chemical" in extraction
95
+ assert "Training signals and model objectives are primary only" in generation
96
+ assert "flow_matching_generator" not in COMPONENT_EXTRACTION_PROMPT
97
+ assert "controllability_gramian" not in COMPONENT_EXTRACTION_PROMPT
98
+ assert "proof_obligation" in COMPONENT_EXTRACTION_PROMPT
99
+
100
+
101
+ def test_skill_prompt_accepts_profile_native_objects_and_roles() -> None:
102
+ profile_text = format_scientific_intervention_profile_for_prompt(
103
+ _profile_payload("formal_theoretical")
104
+ )
105
+ prompt = SKILL_INSTANTIATION_PROMPT.format(
106
+ topic="mathematical dynamics",
107
+ root_domains="mathematics",
108
+ scientific_intervention_profile=profile_text,
109
+ refinement_scope="theorem assumptions",
110
+ taste_guidance="none",
111
+ mature_idea="theorem",
112
+ parent_summary="parent",
113
+ parent_components="proof_object",
114
+ paper_context="papers",
115
+ memory_bundle="memory",
116
+ skill_references="references",
117
+ additional_retrieval_context="",
118
+ skill_name="mechanism-commit-innovation",
119
+ plan_objective="repair proof gap",
120
+ target_defects="proof_gap",
121
+ component_edits="[]",
122
+ validation_protocols="counterexample",
123
+ guardrails="none",
124
+ )
125
+ assert "formal_theoretical" in prompt
126
+ assert "scientific object, role, mechanism, process, relation" in prompt
127
+
128
+
129
+ def test_profiles_expose_native_contribution_modes() -> None:
130
+ for profile_id in (
131
+ "physical_materials_chemical",
132
+ "clinical_health",
133
+ "formal_theoretical",
134
+ "computational_algorithmic",
135
+ ):
136
+ profile = get_scientific_intervention_profile(profile_id)
137
+ assert profile is not None
138
+ assert profile.contribution_modes
139
+ assert all(mode.mode_id for mode in profile.contribution_modes)
140
+
141
+
142
+ def test_non_cs_rubric_does_not_require_training_signal() -> None:
143
+ rubric = format_scientific_rubric_for_prompt(
144
+ _profile_payload("clinical_health")
145
+ )
146
+ assert "not universal quality requirements" not in rubric
147
+ assert "training signal" not in rubric
148
+ assert "native objects" in rubric
149
+ assert "causal" in rubric.lower()
150
+
151
+
152
+ def test_non_cs_early_prompts_use_profile_neutral_vocabulary() -> None:
153
+ advanced = render_advanced_analysis_prompt(
154
+ ADVANCED_ANALYSIS_PROMPT.format(
155
+ topic="clinical endpoint",
156
+ mature_idea="",
157
+ mature_idea_source="empty",
158
+ refinement_scope="",
159
+ refinement_scope_source="empty",
160
+ survey_contents="",
161
+ papers="",
162
+ experiment_findings="None",
163
+ ),
164
+ "clinical_health",
165
+ ).lower()
166
+ fusion = render_idea_fusion_prompt(
167
+ IDEA_FUSION_PROMPT.format(
168
+ topic="clinical endpoint",
169
+ mature_idea="",
170
+ refinement_scope="",
171
+ root_domains="medicine",
172
+ scientific_intervention_profile="clinical_health",
173
+ scientific_object_schema="{}",
174
+ analysis="",
175
+ mode_count=2,
176
+ candidate_ideas_json="[]",
177
+ ),
178
+ "clinical_health",
179
+ ).lower()
180
+ for prompt in (advanced, fusion):
181
+ assert "training signals" not in prompt
182
+ assert "task-solving mechanism" not in prompt
183
+ assert "gate/router/controller" not in prompt
184
+ assert "specific computational role" not in prompt
185
+
186
+
187
+ def test_evaluation_prompt_accepts_profile_and_rubric_blocks() -> None:
188
+ rendered = MCTS_IDEA_EVALUATION_PROMPT.format(
189
+ topic="clinical endpoint",
190
+ direction_mode="evidence_first",
191
+ direction_summary="Prefer defensible evidence.",
192
+ taste_guidance="Use a narrow mechanism.",
193
+ target_gap_ids="gap-1",
194
+ profile_id="clinical_health",
195
+ gap_seed_context="seed-1",
196
+ root_domains="medicine",
197
+ mature_idea="causal intervention",
198
+ refinement_scope="mediator identification",
199
+ edit_plan="plan",
200
+ idea="candidate",
201
+ scientific_intervention_profile=format_scientific_intervention_profile_for_prompt(
202
+ _profile_payload("clinical_health")
203
+ ),
204
+ profile_native_object_schema="{}",
205
+ scientific_rubric=format_scientific_rubric_for_prompt(
206
+ _profile_payload("clinical_health")
207
+ ),
208
+ defect_registry=format_defect_registry("clinical_health"),
209
+ symbolic_memory_hints="none",
210
+ )
211
+ assert '"explanatory_power": 0-5' in rendered
212
+ assert "clinical_health" in rendered
213
+
214
+
215
+ def test_direction_context_exposes_mode_profile_and_gap_seeds() -> None:
216
+ preset = get_idea_taste_preset("evidence_first")
217
+ assert preset is not None
218
+ mcts = SimpleNamespace(
219
+ idea_taste_preset=preset,
220
+ scientific_intervention_profile={
221
+ "profile_id": "physical_materials_chemical",
222
+ "scientific_object_schema": {"object_types": ["material_process"]},
223
+ },
224
+ gap_hypothesis_seeds=[{"gap_id": "gap-1"}],
225
+ gap_seed_context="seed-1",
226
+ )
227
+ state = SimpleNamespace(scientific_intervention={})
228
+
229
+ context = _direction_prompt_context(mcts, state)
230
+
231
+ assert context["direction_mode"] == "evidence_first"
232
+ assert context["profile_id"] == "physical_materials_chemical"
233
+ assert context["target_gap_ids"] == "gap-1"
234
+ assert "seed-1" in context["gap_seed_context"]
235
+ assert "material_process" in context["profile_native_object_schema"]
236
+
237
+
238
+ def test_optional_scientific_contract_fields_are_preserved_without_new_required_fields() -> None:
239
+ normalized = normalize_idea_contract(
240
+ {
241
+ "title": "A hypothesis",
242
+ "abstract": "A concise abstract.",
243
+ "core_contribution": "A scientific claim.",
244
+ "method": "A profile-native method.",
245
+ "direction_mode": "bridge_builder",
246
+ "central_hypothesis": "The relation changes under the condition.",
247
+ "scientific_object": {"object_type": "process"},
248
+ "target_gap_ids": ["gap-1"],
249
+ "gap_alignment": [{"gap_id": "gap-1", "alignment": "direct"}],
250
+ "evidence_basis": ["SURVEY_ANCHOR: mechanism remains unresolved"],
251
+ "experiment_design": "must be discarded",
252
+ }
253
+ )
254
+
255
+ assert normalized["direction_mode"] == "bridge_builder"
256
+ assert normalized["central_hypothesis"] == "The relation changes under the condition."
257
+ assert normalized["scientific_object"] == {"object_type": "process"}
258
+ assert normalized["target_gap_ids"] == ["gap-1"]
259
+ assert normalized["gap_alignment"] == [{"gap_id": "gap-1", "alignment": "direct"}]
260
+ assert normalized["evidence_basis"] == ["SURVEY_ANCHOR: mechanism remains unresolved"]
261
+ assert "experiment_design" not in normalized
262
+
263
+
264
+ def test_instantiation_contract_collects_top_level_scientific_fields() -> None:
265
+ contract = _contract_from_instantiation(
266
+ {
267
+ "central_hypothesis": "A claim",
268
+ "target_gap_ids": ["gap-1"],
269
+ "evidence_basis": ["anchor-1"],
270
+ "scientific_contract": {"direction_mode": "moonshot_inventor"},
271
+ }
272
+ )
273
+
274
+ assert contract == {
275
+ "direction_mode": "moonshot_inventor",
276
+ "central_hypothesis": "A claim",
277
+ "target_gap_ids": ["gap-1"],
278
+ "evidence_basis": ["anchor-1"],
279
+ }
280
+
281
+
282
+ def test_child_contract_inherits_parent_fields_without_treating_blanks_as_clears() -> None:
283
+ parent_contract = {
284
+ "central_hypothesis": "The relation changes under a bounded condition.",
285
+ "mechanism_or_relation": "A native mediator links the intervention to the outcome.",
286
+ "target_gap_ids": ["gap-1"],
287
+ "claim_scope": "The measured operating regime.",
288
+ }
289
+ child_contract = {
290
+ "central_hypothesis": "",
291
+ "claim_scope": "A narrower operating regime.",
292
+ }
293
+
294
+ merged = merge_hypothesis_contract(parent_contract, child_contract)
295
+
296
+ assert merged["central_hypothesis"] == parent_contract["central_hypothesis"]
297
+ assert merged["mechanism_or_relation"] == parent_contract["mechanism_or_relation"]
298
+ assert merged["target_gap_ids"] == ["gap-1"]
299
+ assert merged["claim_scope"] == "A narrower operating regime."
300
+
301
+
302
+ def test_route_specific_omission_is_marked_instead_of_being_silently_inherited() -> None:
303
+ parent_contract = {
304
+ "scientific_object": {"object_type": "parent_object"},
305
+ "mechanism_or_relation": "parent mechanism",
306
+ "expected_mechanism": "parent expectation",
307
+ }
308
+
309
+ assert _route_contract_incomplete_fields(
310
+ "mechanism_replacement",
311
+ parent_contract,
312
+ {},
313
+ ) == ["mechanism_or_relation"]
314
+ assert _route_contract_incomplete_fields(
315
+ "object_substitution",
316
+ parent_contract,
317
+ {"scientific_object": {"object_type": "child_object"}},
318
+ ) == []
319
+ assert _route_contract_noop_fields(
320
+ "mechanism_replacement",
321
+ parent_contract,
322
+ {"mechanism_or_relation": "parent mechanism"},
323
+ ) == ["mechanism_or_relation"]
324
+ assert _route_contract_noop_fields(
325
+ "object_substitution",
326
+ parent_contract,
327
+ {"scientific_object": {"object_type": "parent_object"}},
328
+ ) == ["scientific_object"]
329
+
330
+
331
+ def test_materialized_child_preserves_parent_contract_and_marks_missing_route_change() -> None:
332
+ parent = SimpleNamespace(
333
+ title="Parent hypothesis",
334
+ abstract="Parent abstract",
335
+ core_contribution="Parent contribution",
336
+ method="Parent method",
337
+ risks="Parent risks",
338
+ tags=["parent"],
339
+ target_defects=["unexplored_gap"],
340
+ components=[],
341
+ component_explanations={},
342
+ root_domains=["physics"],
343
+ discipline_resolution={},
344
+ paper_graph_context="",
345
+ scientific_intervention={
346
+ "hypothesis_contract": {
347
+ "central_hypothesis": "Parent hypothesis remains available.",
348
+ "mechanism_or_relation": "Parent mechanism must not disappear.",
349
+ "target_gap_ids": ["gap-1"],
350
+ }
351
+ },
352
+ )
353
+ plan = EditPlan(
354
+ skill_name="route-test",
355
+ objective="Refine the mechanism.",
356
+ target_defects=["unexplored_gap"],
357
+ component_edits=[],
358
+ validation=ValidationProtocol(),
359
+ guardrails=[],
360
+ memory_refs=[],
361
+ compile_notes="test plan",
362
+ )
363
+ mcts = SimpleNamespace(
364
+ route_id="mechanism_replacement",
365
+ idea_taste_preset=None,
366
+ _skill_prior_for_prompt=lambda _skill_name: 0.0,
367
+ )
368
+
369
+ child = materialize_child_state(
370
+ mcts,
371
+ parent,
372
+ plan,
373
+ {"claim_scope": "A narrower scope."},
374
+ idea_state_cls=lambda **payload: SimpleNamespace(**payload),
375
+ )
376
+
377
+ contract = child.scientific_intervention["hypothesis_contract"]
378
+ assert contract["central_hypothesis"] == "Parent hypothesis remains available."
379
+ assert contract["mechanism_or_relation"] == "Parent mechanism must not disappear."
380
+ assert contract["claim_scope"] == "A narrower scope."
381
+ assert child.scientific_intervention["route_contract_incomplete_fields"] == [
382
+ "mechanism_or_relation"
383
+ ]
384
+
385
+
386
+ def test_materialized_child_marks_parent_mechanism_restatement_as_route_noop() -> None:
387
+ parent = SimpleNamespace(
388
+ title="Parent hypothesis",
389
+ abstract="Parent abstract",
390
+ core_contribution="Parent contribution",
391
+ method="Parent method",
392
+ risks="Parent risks",
393
+ tags=["parent"],
394
+ target_defects=["unexplored_gap"],
395
+ components=[],
396
+ component_explanations={},
397
+ root_domains=["physics"],
398
+ discipline_resolution={},
399
+ paper_graph_context="",
400
+ scientific_intervention={
401
+ "hypothesis_contract": {
402
+ "mechanism_or_relation": "Parent mechanism.",
403
+ "target_gap_ids": ["gap-1"],
404
+ }
405
+ },
406
+ )
407
+ plan = EditPlan(
408
+ skill_name="route-test",
409
+ objective="Replace the mechanism.",
410
+ target_defects=["unexplored_gap"],
411
+ component_edits=[],
412
+ validation=ValidationProtocol(),
413
+ guardrails=[],
414
+ memory_refs=[],
415
+ compile_notes="test plan",
416
+ )
417
+ mcts = SimpleNamespace(
418
+ route_id="mechanism_replacement",
419
+ idea_taste_preset=None,
420
+ _skill_prior_for_prompt=lambda _skill_name: 0.0,
421
+ )
422
+
423
+ child = materialize_child_state(
424
+ mcts,
425
+ parent,
426
+ plan,
427
+ {"mechanism_or_relation": "Parent mechanism."},
428
+ idea_state_cls=lambda **payload: SimpleNamespace(**payload),
429
+ )
430
+
431
+ assert "route_contract_incomplete_fields" not in child.scientific_intervention
432
+ assert child.scientific_intervention["route_contract_noop_fields"] == [
433
+ "mechanism_or_relation"
434
+ ]
435
+ assert child.scientific_intervention["route_contract_parent_values"] == {
436
+ "mechanism_or_relation": "Parent mechanism."
437
+ }
438
+
439
+
440
+ def test_profile_priority_defects_are_visible() -> None:
441
+ registry = format_defect_registry("formal_theoretical")
442
+ assert "Profile priority: formal_theoretical" in registry
443
+ assert "missing_assumption [profile-priority]" in registry
444
+ assert "proof_gap [profile-priority]" in registry
445
+
446
+
447
+ def test_profile_priority_defects_drive_skill_overlap() -> None:
448
+ assert "missing_boundary_condition" in profile_skill_defect_tags(
449
+ "clinical_health",
450
+ "alternative-path-contrast",
451
+ )
452
+ assert "proof_gap" in profile_skill_defect_tags(
453
+ "formal_theoretical",
454
+ "theory-transfer-injection",
455
+ )
456
+
457
+
458
+ def test_taste_presets_include_scientific_weights_and_normalize() -> None:
459
+ for mode in ("moonshot_inventor", "bridge_builder", "steady_engineer", "ambitious_realist"):
460
+ preset = get_idea_taste_preset(mode)
461
+ assert preset is not None
462
+ assert set(SCORE_WEIGHT_FIELDS).issubset(preset.weights)
463
+ assert sum(preset.weights[field] for field in SCORE_WEIGHT_FIELDS) == pytest.approx(1.0)
464
+
465
+
466
+ def test_cache_key_changes_with_profile_and_rubric_versions() -> None:
467
+ base = evaluation_prompt_cache_key("candidate")
468
+ other_profile = evaluation_prompt_cache_key("candidate", profile_id="clinical_health")
469
+ other_rubric = evaluation_prompt_cache_key("candidate", rubric_version="scientific_rubric_v2")
470
+ assert base != other_profile
471
+ assert base != other_rubric
472
+
473
+
474
+ def _mcts_module():
475
+ pytest.importorskip("faiss")
476
+ return importlib.import_module("src.agents.idea_agent.agent.mcts")
477
+
478
+
479
+ def test_idea_evaluation_scientific_dimensions_are_backward_compatible() -> None:
480
+ mcts = _mcts_module()
481
+ legacy = mcts.IdeaEvaluation.from_payload(
482
+ {
483
+ "novelty": 4,
484
+ "surprise": 3,
485
+ "feasibility": 4,
486
+ "clarity": 3,
487
+ "impact": 4,
488
+ "risk": 1,
489
+ "conciseness": 3,
490
+ "alignment_score": 4,
491
+ "complexity_penalty": 1,
492
+ "protocol_score": 3,
493
+ }
494
+ )
495
+ assert legacy.explanatory_power == 0
496
+ assert "claim_overreach_penalty" in legacy.to_dict()
497
+ low_overreach = mcts.IdeaEvaluation.from_payload(
498
+ {**legacy.to_dict(), "claim_overreach_penalty": 0}
499
+ )
500
+ high_overreach = mcts.IdeaEvaluation.from_payload(
501
+ {**legacy.to_dict(), "claim_overreach_penalty": 5}
502
+ )
503
+ assert low_overreach.composite > high_overreach.composite
504
+
505
+
506
+ def test_fixed_scientific_candidate_fixtures_do_not_lose_to_benchmark_only_cs() -> None:
507
+ mcts = _mcts_module()
508
+
509
+ common = {
510
+ "surprise": 3,
511
+ "feasibility": 4,
512
+ "clarity": 4,
513
+ "impact": 4,
514
+ "risk": 1,
515
+ "conciseness": 3,
516
+ "alignment_score": 4,
517
+ "complexity_penalty": 1,
518
+ "protocol_score": 4,
519
+ "confidence": 0.9,
520
+ }
521
+ benchmark_only_cs = mcts.IdeaEvaluation.from_payload(
522
+ {
523
+ **common,
524
+ "novelty": 5,
525
+ "feasibility": 5,
526
+ "clarity": 3,
527
+ "impact": 3,
528
+ "protocol_score": 2,
529
+ "explanatory_power": 1,
530
+ "identifiability": 1,
531
+ "boundary_calibration": 1,
532
+ "claim_overreach_penalty": 3,
533
+ },
534
+ profile_id="computational_algorithmic",
535
+ )
536
+ fixture_scores = {}
537
+ for name, (profile_id, values) in {
538
+ "materials_mechanism": ("physical_materials_chemical", (4, 5, 5, 4, 1)),
539
+ "medicine_causal": ("clinical_health", (4, 5, 4, 4, 1)),
540
+ "math_counterexample": ("formal_theoretical", (4, 5, 5, 5, 0)),
541
+ "cs_typical": ("computational_algorithmic", (5, 4, 4, 4, 1)),
542
+ }.items():
543
+ novelty, explanatory, identifiability, boundary, overreach = values
544
+ fixture_scores[name] = mcts.IdeaEvaluation.from_payload(
545
+ {
546
+ **common,
547
+ "novelty": novelty,
548
+ "explanatory_power": explanatory,
549
+ "identifiability": identifiability,
550
+ "boundary_calibration": boundary,
551
+ "claim_overreach_penalty": overreach,
552
+ },
553
+ profile_id=profile_id,
554
+ ).composite
555
+
556
+ assert fixture_scores["materials_mechanism"] >= benchmark_only_cs.composite
557
+ assert fixture_scores["medicine_causal"] >= benchmark_only_cs.composite
558
+ assert fixture_scores["math_counterexample"] >= benchmark_only_cs.composite
559
+ assert fixture_scores["cs_typical"] >= benchmark_only_cs.composite
@@ -0,0 +1,48 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+
5
+ from src.agents.idea_agent.utils.core.response_parsing import (
6
+ JsonObjectResponseError,
7
+ parse_json_object_response,
8
+ )
9
+ from src.agents.idea_agent.utils.workflow.ligagent_utils import LigRuntime
10
+
11
+
12
+ class _CapturingAgent:
13
+ model = "mock-model"
14
+
15
+ def __init__(self) -> None:
16
+ self.request_kwargs: dict = {}
17
+
18
+ def chat(self, prompt: str, **kwargs):
19
+ del prompt
20
+ self.request_kwargs = kwargs
21
+ return '{"status": "ok"}'
22
+
23
+
24
+ def test_strict_json_object_parser_accepts_only_one_top_level_object() -> None:
25
+ assert parse_json_object_response('{"status": "ok"}') == {"status": "ok"}
26
+
27
+ with pytest.raises(JsonObjectResponseError):
28
+ parse_json_object_response('["not", "an object"]')
29
+ with pytest.raises(JsonObjectResponseError):
30
+ parse_json_object_response('Preamble\n["fragment"]\n{"status": "ok"}')
31
+
32
+
33
+ def test_runtime_forwards_json_object_mode_without_leaking_internal_flag() -> None:
34
+ agent = _CapturingAgent()
35
+ runtime = LigRuntime(agent)
36
+
37
+ result = runtime.llm_json(
38
+ session=None,
39
+ stage="advanced_analysis",
40
+ op_name="test",
41
+ prompt="Return an object.",
42
+ require_json_object=True,
43
+ response_format={"type": "json_object"},
44
+ )
45
+
46
+ assert result == {"status": "ok"}
47
+ assert agent.request_kwargs["response_format"] == {"type": "json_object"}
48
+ assert "require_json_object" not in agent.request_kwargs
@@ -0,0 +1 @@
1
+ """Core utilities shared across Idea Agent modules."""
@@ -0,0 +1,60 @@
1
+ """Helpers for optional ablation-results ingestion into LigAgent runs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Any, Mapping, Optional
8
+
9
+
10
+ def _resolve_ablation_results_file(raw_path: Any) -> Optional[Path]:
11
+ path_text = str(raw_path).strip() if raw_path is not None else ""
12
+ if not path_text:
13
+ return None
14
+
15
+ path = Path(path_text).expanduser()
16
+ if not path.exists():
17
+ return None
18
+
19
+ if path.is_file():
20
+ return path if path.suffix.lower() == ".json" else None
21
+
22
+ json_files = sorted(
23
+ candidate for candidate in path.iterdir() if candidate.is_file() and candidate.suffix.lower() == ".json"
24
+ )
25
+ if not json_files:
26
+ return None
27
+ if len(json_files) > 1:
28
+ raise ValueError(
29
+ f"Expected exactly one JSON file under ablation_results_path={path}, found {len(json_files)}."
30
+ )
31
+ return json_files[0]
32
+
33
+
34
+ def load_ablation_results_payload(run_inputs: Mapping[str, Any]) -> Any:
35
+ """Resolve ablation results from an optional JSON directory or JSON file path."""
36
+ resolved_file = _resolve_ablation_results_file(run_inputs.get("ablation_results_path"))
37
+ if resolved_file is None:
38
+ return None
39
+
40
+ with resolved_file.open("r", encoding="utf-8") as f:
41
+ payload = json.load(f)
42
+ return payload if payload else None
43
+
44
+
45
+ def ingest_ablation_results_if_available(
46
+ agent: Any,
47
+ run_inputs: Mapping[str, Any],
48
+ logger: Optional[Any] = None,
49
+ ) -> bool:
50
+ """Inject ablation results when a non-empty payload is available."""
51
+ payload = load_ablation_results_payload(run_inputs)
52
+ if not payload:
53
+ if logger is not None:
54
+ logger.info("[LigAgent] No ablation results provided; skipping ingestion.")
55
+ return False
56
+
57
+ agent.ingest_ablation_results(payload)
58
+ if logger is not None:
59
+ logger.info("[LigAgent] Injected ablation results into artifact state.")
60
+ return True