aiagents4pharma 1.43.0__py3-none-any.whl → 1.45.0__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 (290) hide show
  1. aiagents4pharma/__init__.py +2 -2
  2. aiagents4pharma/talk2aiagents4pharma/.dockerignore +13 -0
  3. aiagents4pharma/talk2aiagents4pharma/Dockerfile +105 -0
  4. aiagents4pharma/talk2aiagents4pharma/README.md +1 -0
  5. aiagents4pharma/talk2aiagents4pharma/__init__.py +4 -5
  6. aiagents4pharma/talk2aiagents4pharma/agents/__init__.py +3 -2
  7. aiagents4pharma/talk2aiagents4pharma/agents/main_agent.py +24 -23
  8. aiagents4pharma/talk2aiagents4pharma/configs/__init__.py +2 -2
  9. aiagents4pharma/talk2aiagents4pharma/configs/agents/__init__.py +2 -2
  10. aiagents4pharma/talk2aiagents4pharma/configs/agents/main_agent/default.yaml +2 -2
  11. aiagents4pharma/talk2aiagents4pharma/configs/config.yaml +1 -1
  12. aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/.env.example +23 -0
  13. aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/docker-compose.yml +93 -0
  14. aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/.env.example +23 -0
  15. aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/docker-compose.yml +108 -0
  16. aiagents4pharma/talk2aiagents4pharma/install.md +127 -0
  17. aiagents4pharma/talk2aiagents4pharma/states/__init__.py +3 -2
  18. aiagents4pharma/talk2aiagents4pharma/states/state_talk2aiagents4pharma.py +5 -3
  19. aiagents4pharma/talk2aiagents4pharma/tests/__init__.py +2 -2
  20. aiagents4pharma/talk2aiagents4pharma/tests/test_main_agent.py +72 -50
  21. aiagents4pharma/talk2biomodels/.dockerignore +13 -0
  22. aiagents4pharma/talk2biomodels/Dockerfile +104 -0
  23. aiagents4pharma/talk2biomodels/README.md +1 -0
  24. aiagents4pharma/talk2biomodels/__init__.py +4 -8
  25. aiagents4pharma/talk2biomodels/agents/__init__.py +3 -2
  26. aiagents4pharma/talk2biomodels/agents/t2b_agent.py +47 -42
  27. aiagents4pharma/talk2biomodels/api/__init__.py +4 -5
  28. aiagents4pharma/talk2biomodels/api/kegg.py +14 -10
  29. aiagents4pharma/talk2biomodels/api/ols.py +13 -10
  30. aiagents4pharma/talk2biomodels/api/uniprot.py +7 -6
  31. aiagents4pharma/talk2biomodels/configs/__init__.py +3 -4
  32. aiagents4pharma/talk2biomodels/configs/agents/__init__.py +2 -2
  33. aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/__init__.py +2 -2
  34. aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/default.yaml +1 -1
  35. aiagents4pharma/talk2biomodels/configs/config.yaml +1 -1
  36. aiagents4pharma/talk2biomodels/configs/tools/__init__.py +4 -5
  37. aiagents4pharma/talk2biomodels/configs/tools/ask_question/__init__.py +2 -2
  38. aiagents4pharma/talk2biomodels/configs/tools/ask_question/default.yaml +1 -2
  39. aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/__init__.py +2 -2
  40. aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/default.yaml +1 -1
  41. aiagents4pharma/talk2biomodels/configs/tools/get_annotation/__init__.py +2 -2
  42. aiagents4pharma/talk2biomodels/configs/tools/get_annotation/default.yaml +1 -1
  43. aiagents4pharma/talk2biomodels/install.md +63 -0
  44. aiagents4pharma/talk2biomodels/models/__init__.py +4 -4
  45. aiagents4pharma/talk2biomodels/models/basico_model.py +36 -28
  46. aiagents4pharma/talk2biomodels/models/sys_bio_model.py +13 -10
  47. aiagents4pharma/talk2biomodels/states/__init__.py +3 -2
  48. aiagents4pharma/talk2biomodels/states/state_talk2biomodels.py +12 -8
  49. aiagents4pharma/talk2biomodels/tests/BIOMD0000000449_url.xml +1585 -0
  50. aiagents4pharma/talk2biomodels/tests/__init__.py +2 -2
  51. aiagents4pharma/talk2biomodels/tests/article_on_model_537.pdf +0 -0
  52. aiagents4pharma/talk2biomodels/tests/test_api.py +18 -14
  53. aiagents4pharma/talk2biomodels/tests/test_ask_question.py +8 -9
  54. aiagents4pharma/talk2biomodels/tests/test_basico_model.py +15 -9
  55. aiagents4pharma/talk2biomodels/tests/test_get_annotation.py +54 -55
  56. aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py +28 -27
  57. aiagents4pharma/talk2biomodels/tests/test_integration.py +21 -33
  58. aiagents4pharma/talk2biomodels/tests/test_load_biomodel.py +14 -11
  59. aiagents4pharma/talk2biomodels/tests/test_param_scan.py +21 -20
  60. aiagents4pharma/talk2biomodels/tests/test_query_article.py +129 -29
  61. aiagents4pharma/talk2biomodels/tests/test_search_models.py +9 -13
  62. aiagents4pharma/talk2biomodels/tests/test_simulate_model.py +16 -15
  63. aiagents4pharma/talk2biomodels/tests/test_steady_state.py +12 -22
  64. aiagents4pharma/talk2biomodels/tests/test_sys_bio_model.py +33 -29
  65. aiagents4pharma/talk2biomodels/tools/__init__.py +15 -12
  66. aiagents4pharma/talk2biomodels/tools/ask_question.py +42 -32
  67. aiagents4pharma/talk2biomodels/tools/custom_plotter.py +51 -43
  68. aiagents4pharma/talk2biomodels/tools/get_annotation.py +99 -75
  69. aiagents4pharma/talk2biomodels/tools/get_modelinfo.py +57 -51
  70. aiagents4pharma/talk2biomodels/tools/load_arguments.py +52 -32
  71. aiagents4pharma/talk2biomodels/tools/load_biomodel.py +8 -2
  72. aiagents4pharma/talk2biomodels/tools/parameter_scan.py +107 -90
  73. aiagents4pharma/talk2biomodels/tools/query_article.py +14 -13
  74. aiagents4pharma/talk2biomodels/tools/search_models.py +37 -26
  75. aiagents4pharma/talk2biomodels/tools/simulate_model.py +47 -37
  76. aiagents4pharma/talk2biomodels/tools/steady_state.py +76 -58
  77. aiagents4pharma/talk2biomodels/tools/utils.py +4 -3
  78. aiagents4pharma/talk2cells/README.md +1 -0
  79. aiagents4pharma/talk2cells/__init__.py +4 -5
  80. aiagents4pharma/talk2cells/agents/__init__.py +3 -2
  81. aiagents4pharma/talk2cells/agents/scp_agent.py +21 -19
  82. aiagents4pharma/talk2cells/states/__init__.py +3 -2
  83. aiagents4pharma/talk2cells/states/state_talk2cells.py +4 -2
  84. aiagents4pharma/talk2cells/tests/scp_agent/test_scp_agent.py +8 -9
  85. aiagents4pharma/talk2cells/tools/__init__.py +3 -2
  86. aiagents4pharma/talk2cells/tools/scp_agent/__init__.py +4 -4
  87. aiagents4pharma/talk2cells/tools/scp_agent/display_studies.py +5 -3
  88. aiagents4pharma/talk2cells/tools/scp_agent/search_studies.py +21 -22
  89. aiagents4pharma/talk2knowledgegraphs/.dockerignore +13 -0
  90. aiagents4pharma/talk2knowledgegraphs/Dockerfile +103 -0
  91. aiagents4pharma/talk2knowledgegraphs/README.md +1 -0
  92. aiagents4pharma/talk2knowledgegraphs/__init__.py +4 -7
  93. aiagents4pharma/talk2knowledgegraphs/agents/__init__.py +3 -2
  94. aiagents4pharma/talk2knowledgegraphs/agents/t2kg_agent.py +40 -30
  95. aiagents4pharma/talk2knowledgegraphs/configs/__init__.py +3 -6
  96. aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/__init__.py +2 -2
  97. aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/default.yaml +8 -8
  98. aiagents4pharma/talk2knowledgegraphs/configs/app/__init__.py +3 -2
  99. aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/__init__.py +2 -2
  100. aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/default.yaml +1 -1
  101. aiagents4pharma/talk2knowledgegraphs/configs/config.yaml +1 -1
  102. aiagents4pharma/talk2knowledgegraphs/configs/tools/__init__.py +4 -5
  103. aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/__init__.py +2 -2
  104. aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/default.yaml +1 -1
  105. aiagents4pharma/talk2knowledgegraphs/configs/tools/multimodal_subgraph_extraction/default.yaml +17 -2
  106. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/__init__.py +2 -2
  107. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/default.yaml +1 -1
  108. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/__init__.py +2 -2
  109. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/default.yaml +1 -1
  110. aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/ols_terms/default.yaml +1 -1
  111. aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/reactome_pathways/default.yaml +1 -1
  112. aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/uniprot_proteins/default.yaml +1 -1
  113. aiagents4pharma/talk2knowledgegraphs/configs/utils/pubchem_utils/default.yaml +1 -1
  114. aiagents4pharma/talk2knowledgegraphs/datasets/__init__.py +4 -6
  115. aiagents4pharma/talk2knowledgegraphs/datasets/biobridge_primekg.py +115 -67
  116. aiagents4pharma/talk2knowledgegraphs/datasets/dataset.py +2 -0
  117. aiagents4pharma/talk2knowledgegraphs/datasets/primekg.py +35 -24
  118. aiagents4pharma/talk2knowledgegraphs/datasets/starkqa_primekg.py +29 -21
  119. aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/.env.example +23 -0
  120. aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/docker-compose.yml +93 -0
  121. aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/.env.example +23 -0
  122. aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/docker-compose.yml +108 -0
  123. aiagents4pharma/talk2knowledgegraphs/entrypoint.sh +190 -0
  124. aiagents4pharma/talk2knowledgegraphs/install.md +140 -0
  125. aiagents4pharma/talk2knowledgegraphs/milvus_data_dump.py +31 -65
  126. aiagents4pharma/talk2knowledgegraphs/states/__init__.py +3 -2
  127. aiagents4pharma/talk2knowledgegraphs/states/state_talk2knowledgegraphs.py +1 -0
  128. aiagents4pharma/talk2knowledgegraphs/tests/test_agents_t2kg_agent.py +65 -40
  129. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_biobridge_primekg.py +54 -48
  130. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_dataset.py +4 -0
  131. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_primekg.py +17 -4
  132. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_starkqa_primekg.py +33 -24
  133. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_graphrag_reasoning.py +116 -69
  134. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_milvus_multimodal_subgraph_extraction.py +736 -413
  135. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_multimodal_subgraph_extraction.py +22 -15
  136. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_extraction.py +19 -12
  137. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_summarization.py +95 -48
  138. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_embeddings.py +4 -0
  139. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_huggingface.py +5 -0
  140. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_nim_molmim.py +13 -18
  141. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_ollama.py +10 -3
  142. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_enrichments.py +4 -3
  143. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ollama.py +3 -2
  144. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ols.py +1 -0
  145. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_pubchem.py +9 -4
  146. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_reactome.py +6 -6
  147. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_uniprot.py +4 -0
  148. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_extractions_milvus_multimodal_pcst.py +442 -42
  149. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_kg_utils.py +3 -4
  150. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_pubchem_utils.py +10 -6
  151. aiagents4pharma/talk2knowledgegraphs/tools/__init__.py +10 -7
  152. aiagents4pharma/talk2knowledgegraphs/tools/graphrag_reasoning.py +15 -20
  153. aiagents4pharma/talk2knowledgegraphs/tools/milvus_multimodal_subgraph_extraction.py +245 -205
  154. aiagents4pharma/talk2knowledgegraphs/tools/multimodal_subgraph_extraction.py +92 -90
  155. aiagents4pharma/talk2knowledgegraphs/tools/subgraph_extraction.py +25 -37
  156. aiagents4pharma/talk2knowledgegraphs/tools/subgraph_summarization.py +10 -13
  157. aiagents4pharma/talk2knowledgegraphs/utils/__init__.py +4 -7
  158. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/__init__.py +4 -7
  159. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/embeddings.py +4 -0
  160. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/huggingface.py +11 -14
  161. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/nim_molmim.py +7 -7
  162. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/ollama.py +12 -6
  163. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/sentence_transformer.py +8 -6
  164. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/__init__.py +9 -6
  165. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/enrichments.py +1 -0
  166. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ollama.py +15 -9
  167. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ols_terms.py +23 -20
  168. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/pubchem_strings.py +12 -10
  169. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/reactome_pathways.py +16 -10
  170. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/uniprot_proteins.py +26 -18
  171. aiagents4pharma/talk2knowledgegraphs/utils/extractions/__init__.py +4 -5
  172. aiagents4pharma/talk2knowledgegraphs/utils/extractions/milvus_multimodal_pcst.py +218 -81
  173. aiagents4pharma/talk2knowledgegraphs/utils/extractions/multimodal_pcst.py +53 -47
  174. aiagents4pharma/talk2knowledgegraphs/utils/extractions/pcst.py +18 -14
  175. aiagents4pharma/talk2knowledgegraphs/utils/kg_utils.py +22 -23
  176. aiagents4pharma/talk2knowledgegraphs/utils/pubchem_utils.py +11 -10
  177. aiagents4pharma/talk2scholars/.dockerignore +13 -0
  178. aiagents4pharma/talk2scholars/Dockerfile +104 -0
  179. aiagents4pharma/talk2scholars/README.md +1 -0
  180. aiagents4pharma/talk2scholars/agents/__init__.py +1 -5
  181. aiagents4pharma/talk2scholars/agents/main_agent.py +6 -4
  182. aiagents4pharma/talk2scholars/agents/paper_download_agent.py +5 -4
  183. aiagents4pharma/talk2scholars/agents/pdf_agent.py +4 -2
  184. aiagents4pharma/talk2scholars/agents/s2_agent.py +2 -2
  185. aiagents4pharma/talk2scholars/agents/zotero_agent.py +10 -11
  186. aiagents4pharma/talk2scholars/configs/__init__.py +1 -3
  187. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/__init__.py +1 -4
  188. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/main_agent/default.yaml +1 -1
  189. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/pdf_agent/default.yaml +1 -1
  190. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/s2_agent/default.yaml +8 -8
  191. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/zotero_agent/default.yaml +7 -7
  192. aiagents4pharma/talk2scholars/configs/tools/__init__.py +8 -6
  193. aiagents4pharma/talk2scholars/docker-compose/cpu/.env.example +21 -0
  194. aiagents4pharma/talk2scholars/docker-compose/cpu/docker-compose.yml +90 -0
  195. aiagents4pharma/talk2scholars/docker-compose/gpu/.env.example +21 -0
  196. aiagents4pharma/talk2scholars/docker-compose/gpu/docker-compose.yml +105 -0
  197. aiagents4pharma/talk2scholars/install.md +122 -0
  198. aiagents4pharma/talk2scholars/state/state_talk2scholars.py +8 -8
  199. aiagents4pharma/talk2scholars/tests/{test_main_agent.py → test_agents_main_agent.py} +41 -23
  200. aiagents4pharma/talk2scholars/tests/{test_paper_download_agent.py → test_agents_paper_agents_download_agent.py} +10 -16
  201. aiagents4pharma/talk2scholars/tests/{test_pdf_agent.py → test_agents_pdf_agent.py} +6 -10
  202. aiagents4pharma/talk2scholars/tests/{test_s2_agent.py → test_agents_s2_agent.py} +8 -16
  203. aiagents4pharma/talk2scholars/tests/{test_zotero_agent.py → test_agents_zotero_agent.py} +5 -7
  204. aiagents4pharma/talk2scholars/tests/{test_s2_display_dataframe.py → test_s2_tools_display_dataframe.py} +6 -7
  205. aiagents4pharma/talk2scholars/tests/{test_s2_query_dataframe.py → test_s2_tools_query_dataframe.py} +5 -15
  206. aiagents4pharma/talk2scholars/tests/{test_paper_downloader.py → test_tools_paper_downloader.py} +25 -63
  207. aiagents4pharma/talk2scholars/tests/{test_question_and_answer_tool.py → test_tools_question_and_answer_tool.py} +2 -6
  208. aiagents4pharma/talk2scholars/tests/{test_s2_multi.py → test_tools_s2_multi.py} +5 -5
  209. aiagents4pharma/talk2scholars/tests/{test_s2_retrieve.py → test_tools_s2_retrieve.py} +2 -1
  210. aiagents4pharma/talk2scholars/tests/{test_s2_search.py → test_tools_s2_search.py} +5 -5
  211. aiagents4pharma/talk2scholars/tests/{test_s2_single.py → test_tools_s2_single.py} +5 -5
  212. aiagents4pharma/talk2scholars/tests/{test_arxiv_downloader.py → test_utils_arxiv_downloader.py} +16 -25
  213. aiagents4pharma/talk2scholars/tests/{test_base_paper_downloader.py → test_utils_base_paper_downloader.py} +25 -47
  214. aiagents4pharma/talk2scholars/tests/{test_biorxiv_downloader.py → test_utils_biorxiv_downloader.py} +14 -42
  215. aiagents4pharma/talk2scholars/tests/{test_medrxiv_downloader.py → test_utils_medrxiv_downloader.py} +15 -49
  216. aiagents4pharma/talk2scholars/tests/{test_nvidia_nim_reranker.py → test_utils_nvidia_nim_reranker.py} +6 -16
  217. aiagents4pharma/talk2scholars/tests/{test_pdf_answer_formatter.py → test_utils_pdf_answer_formatter.py} +1 -0
  218. aiagents4pharma/talk2scholars/tests/{test_pdf_batch_processor.py → test_utils_pdf_batch_processor.py} +6 -15
  219. aiagents4pharma/talk2scholars/tests/{test_pdf_collection_manager.py → test_utils_pdf_collection_manager.py} +34 -11
  220. aiagents4pharma/talk2scholars/tests/{test_pdf_document_processor.py → test_utils_pdf_document_processor.py} +2 -3
  221. aiagents4pharma/talk2scholars/tests/{test_pdf_generate_answer.py → test_utils_pdf_generate_answer.py} +3 -6
  222. aiagents4pharma/talk2scholars/tests/{test_pdf_gpu_detection.py → test_utils_pdf_gpu_detection.py} +5 -16
  223. aiagents4pharma/talk2scholars/tests/{test_pdf_rag_pipeline.py → test_utils_pdf_rag_pipeline.py} +7 -17
  224. aiagents4pharma/talk2scholars/tests/{test_pdf_retrieve_chunks.py → test_utils_pdf_retrieve_chunks.py} +4 -11
  225. aiagents4pharma/talk2scholars/tests/{test_pdf_singleton_manager.py → test_utils_pdf_singleton_manager.py} +26 -23
  226. aiagents4pharma/talk2scholars/tests/{test_pdf_vector_normalization.py → test_utils_pdf_vector_normalization.py} +1 -1
  227. aiagents4pharma/talk2scholars/tests/{test_pdf_vector_store.py → test_utils_pdf_vector_store.py} +27 -55
  228. aiagents4pharma/talk2scholars/tests/{test_pubmed_downloader.py → test_utils_pubmed_downloader.py} +31 -91
  229. aiagents4pharma/talk2scholars/tests/{test_read_helper_utils.py → test_utils_read_helper_utils.py} +2 -6
  230. aiagents4pharma/talk2scholars/tests/{test_s2_utils_ext_ids.py → test_utils_s2_utils_ext_ids.py} +5 -15
  231. aiagents4pharma/talk2scholars/tests/{test_zotero_human_in_the_loop.py → test_utils_zotero_human_in_the_loop.py} +6 -13
  232. aiagents4pharma/talk2scholars/tests/{test_zotero_path.py → test_utils_zotero_path.py} +53 -45
  233. aiagents4pharma/talk2scholars/tests/{test_zotero_read.py → test_utils_zotero_read.py} +30 -91
  234. aiagents4pharma/talk2scholars/tests/{test_zotero_write.py → test_utils_zotero_write.py} +6 -16
  235. aiagents4pharma/talk2scholars/tools/__init__.py +1 -4
  236. aiagents4pharma/talk2scholars/tools/paper_download/paper_downloader.py +20 -35
  237. aiagents4pharma/talk2scholars/tools/paper_download/utils/__init__.py +7 -5
  238. aiagents4pharma/talk2scholars/tools/paper_download/utils/arxiv_downloader.py +9 -11
  239. aiagents4pharma/talk2scholars/tools/paper_download/utils/base_paper_downloader.py +14 -21
  240. aiagents4pharma/talk2scholars/tools/paper_download/utils/biorxiv_downloader.py +14 -22
  241. aiagents4pharma/talk2scholars/tools/paper_download/utils/medrxiv_downloader.py +11 -13
  242. aiagents4pharma/talk2scholars/tools/paper_download/utils/pubmed_downloader.py +14 -28
  243. aiagents4pharma/talk2scholars/tools/pdf/question_and_answer.py +4 -8
  244. aiagents4pharma/talk2scholars/tools/pdf/utils/__init__.py +16 -14
  245. aiagents4pharma/talk2scholars/tools/pdf/utils/answer_formatter.py +4 -4
  246. aiagents4pharma/talk2scholars/tools/pdf/utils/batch_processor.py +15 -17
  247. aiagents4pharma/talk2scholars/tools/pdf/utils/collection_manager.py +2 -2
  248. aiagents4pharma/talk2scholars/tools/pdf/utils/document_processor.py +5 -5
  249. aiagents4pharma/talk2scholars/tools/pdf/utils/generate_answer.py +4 -4
  250. aiagents4pharma/talk2scholars/tools/pdf/utils/get_vectorstore.py +2 -6
  251. aiagents4pharma/talk2scholars/tools/pdf/utils/gpu_detection.py +5 -9
  252. aiagents4pharma/talk2scholars/tools/pdf/utils/nvidia_nim_reranker.py +4 -4
  253. aiagents4pharma/talk2scholars/tools/pdf/utils/paper_loader.py +2 -2
  254. aiagents4pharma/talk2scholars/tools/pdf/utils/rag_pipeline.py +6 -15
  255. aiagents4pharma/talk2scholars/tools/pdf/utils/retrieve_chunks.py +7 -15
  256. aiagents4pharma/talk2scholars/tools/pdf/utils/singleton_manager.py +2 -2
  257. aiagents4pharma/talk2scholars/tools/pdf/utils/tool_helper.py +3 -4
  258. aiagents4pharma/talk2scholars/tools/pdf/utils/vector_normalization.py +8 -17
  259. aiagents4pharma/talk2scholars/tools/pdf/utils/vector_store.py +17 -33
  260. aiagents4pharma/talk2scholars/tools/s2/__init__.py +8 -6
  261. aiagents4pharma/talk2scholars/tools/s2/display_dataframe.py +3 -7
  262. aiagents4pharma/talk2scholars/tools/s2/multi_paper_rec.py +7 -6
  263. aiagents4pharma/talk2scholars/tools/s2/query_dataframe.py +5 -12
  264. aiagents4pharma/talk2scholars/tools/s2/retrieve_semantic_scholar_paper_id.py +2 -4
  265. aiagents4pharma/talk2scholars/tools/s2/search.py +6 -6
  266. aiagents4pharma/talk2scholars/tools/s2/single_paper_rec.py +5 -3
  267. aiagents4pharma/talk2scholars/tools/s2/utils/__init__.py +1 -3
  268. aiagents4pharma/talk2scholars/tools/s2/utils/multi_helper.py +12 -18
  269. aiagents4pharma/talk2scholars/tools/s2/utils/search_helper.py +11 -18
  270. aiagents4pharma/talk2scholars/tools/s2/utils/single_helper.py +11 -16
  271. aiagents4pharma/talk2scholars/tools/zotero/__init__.py +1 -4
  272. aiagents4pharma/talk2scholars/tools/zotero/utils/__init__.py +1 -4
  273. aiagents4pharma/talk2scholars/tools/zotero/utils/read_helper.py +21 -39
  274. aiagents4pharma/talk2scholars/tools/zotero/utils/review_helper.py +2 -6
  275. aiagents4pharma/talk2scholars/tools/zotero/utils/write_helper.py +8 -11
  276. aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_path.py +4 -12
  277. aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_pdf_downloader.py +13 -27
  278. aiagents4pharma/talk2scholars/tools/zotero/zotero_read.py +4 -7
  279. aiagents4pharma/talk2scholars/tools/zotero/zotero_review.py +8 -10
  280. aiagents4pharma/talk2scholars/tools/zotero/zotero_write.py +3 -2
  281. {aiagents4pharma-1.43.0.dist-info → aiagents4pharma-1.45.0.dist-info}/METADATA +115 -50
  282. aiagents4pharma-1.45.0.dist-info/RECORD +324 -0
  283. {aiagents4pharma-1.43.0.dist-info → aiagents4pharma-1.45.0.dist-info}/WHEEL +1 -2
  284. aiagents4pharma-1.43.0.dist-info/RECORD +0 -293
  285. aiagents4pharma-1.43.0.dist-info/top_level.txt +0 -1
  286. /aiagents4pharma/talk2scholars/tests/{test_state.py → test_states_state.py} +0 -0
  287. /aiagents4pharma/talk2scholars/tests/{test_pdf_paper_loader.py → test_utils_pdf_paper_loader.py} +0 -0
  288. /aiagents4pharma/talk2scholars/tests/{test_tool_helper_utils.py → test_utils_tool_helper_utils.py} +0 -0
  289. /aiagents4pharma/talk2scholars/tests/{test_zotero_pdf_downloader_utils.py → test_utils_zotero_pdf_downloader_utils.py} +0 -0
  290. {aiagents4pharma-1.43.0.dist-info → aiagents4pharma-1.45.0.dist-info}/licenses/LICENSE +0 -0
@@ -3,9 +3,11 @@ Updated Unit Tests for the S2 agent (Semantic Scholar sub-agent).
3
3
  """
4
4
 
5
5
  from unittest import mock
6
+
6
7
  import pytest
7
- from langchain_core.messages import HumanMessage, AIMessage
8
+ from langchain_core.messages import AIMessage, HumanMessage
8
9
  from langchain_openai import ChatOpenAI
10
+
9
11
  from ..agents.s2_agent import get_app
10
12
  from ..state.state_talk2scholars import Talk2Scholars
11
13
 
@@ -27,9 +29,7 @@ def mock_hydra_fixture():
27
29
  def mock_tools_fixture():
28
30
  """Mock tools to prevent execution of real API calls."""
29
31
  with (
30
- mock.patch(
31
- "aiagents4pharma.talk2scholars.tools.s2.search.search_tool"
32
- ) as mock_s2_search,
32
+ mock.patch("aiagents4pharma.talk2scholars.tools.s2.search.search_tool") as mock_s2_search,
33
33
  mock.patch(
34
34
  "aiagents4pharma.talk2scholars.tools.s2.display_dataframe.display_dataframe"
35
35
  ) as mock_s2_display,
@@ -115,9 +115,7 @@ def test_s2_agent_tools_assignment(request):
115
115
  mock.patch(
116
116
  "aiagents4pharma.talk2scholars.agents.s2_agent.create_react_agent"
117
117
  ) as mock_create,
118
- mock.patch(
119
- "aiagents4pharma.talk2scholars.agents.s2_agent.ToolNode"
120
- ) as mock_toolnode,
118
+ mock.patch("aiagents4pharma.talk2scholars.agents.s2_agent.ToolNode") as mock_toolnode,
121
119
  ):
122
120
  mock_agent = mock.Mock()
123
121
  mock_create.return_value = mock_agent
@@ -132,9 +130,7 @@ def test_s2_agent_tools_assignment(request):
132
130
  def test_s2_query_dataframe_tool():
133
131
  """Test if the query_dataframe tool is correctly utilized by the agent."""
134
132
  thread_id = "test_thread"
135
- mock_state = Talk2Scholars(
136
- messages=[HumanMessage(content="Query results for AI papers")]
137
- )
133
+ mock_state = Talk2Scholars(messages=[HumanMessage(content="Query results for AI papers")])
138
134
  with mock.patch(
139
135
  "aiagents4pharma.talk2scholars.agents.s2_agent.create_react_agent"
140
136
  ) as mock_create:
@@ -166,9 +162,7 @@ def test_s2_query_dataframe_tool():
166
162
  def test_s2_retrieve_id_tool():
167
163
  """Test if the retrieve_semantic_scholar_paper_id tool is correctly utilized by the agent."""
168
164
  thread_id = "test_thread"
169
- mock_state = Talk2Scholars(
170
- messages=[HumanMessage(content="Retrieve paper ID for AI research")]
171
- )
165
+ mock_state = Talk2Scholars(messages=[HumanMessage(content="Retrieve paper ID for AI research")])
172
166
  with mock.patch(
173
167
  "aiagents4pharma.talk2scholars.agents.s2_agent.create_react_agent"
174
168
  ) as mock_create:
@@ -177,9 +171,7 @@ def test_s2_retrieve_id_tool():
177
171
  mock_agent.invoke.return_value = {
178
172
  "messages": [HumanMessage(content="Retrieve paper ID for AI research")],
179
173
  "last_displayed_papers": {},
180
- "papers": {
181
- "paper_id": "MockPaper123"
182
- }, # Ensure 'paper_id' is inside 'papers'
174
+ "papers": {"paper_id": "MockPaper123"}, # Ensure 'paper_id' is inside 'papers'
183
175
  "multi_papers": {},
184
176
  }
185
177
  app = get_app(thread_id, llm_model=LLM_MODEL)
@@ -3,9 +3,11 @@ Updated Unit Tests for the Zotero agent (Zotero Library Managent sub-agent).
3
3
  """
4
4
 
5
5
  from unittest import mock
6
+
6
7
  import pytest
7
- from langchain_core.messages import HumanMessage, AIMessage
8
+ from langchain_core.messages import AIMessage, HumanMessage
8
9
  from langchain_openai import ChatOpenAI
10
+
9
11
  from ..agents.zotero_agent import get_app
10
12
  from ..state.state_talk2scholars import Talk2Scholars
11
13
 
@@ -105,9 +107,7 @@ def test_zotero_agent_tools_assignment(request):
105
107
  mock.patch(
106
108
  "aiagents4pharma.talk2scholars.agents.zotero_agent.create_react_agent"
107
109
  ) as mock_create,
108
- mock.patch(
109
- "aiagents4pharma.talk2scholars.agents.zotero_agent.ToolNode"
110
- ) as mock_toolnode,
110
+ mock.patch("aiagents4pharma.talk2scholars.agents.zotero_agent.ToolNode") as mock_toolnode,
111
111
  ):
112
112
  mock_agent = mock.Mock()
113
113
  mock_create.return_value = mock_agent
@@ -122,9 +122,7 @@ def test_zotero_agent_tools_assignment(request):
122
122
  def test_s2_query_dataframe_tool():
123
123
  """Test if the query_dataframe tool is correctly utilized by the agent."""
124
124
  thread_id = "test_thread"
125
- mock_state = Talk2Scholars(
126
- messages=[HumanMessage(content="Query results for AI papers")]
127
- )
125
+ mock_state = Talk2Scholars(messages=[HumanMessage(content="Query results for AI papers")])
128
126
  with mock.patch(
129
127
  "aiagents4pharma.talk2scholars.agents.zotero_agent.create_react_agent"
130
128
  ) as mock_create:
@@ -4,10 +4,13 @@ Unit tests for S2 tools functionality.
4
4
 
5
5
  import pytest
6
6
  from langgraph.types import Command
7
+
7
8
  from ..tools.s2.display_dataframe import (
8
- display_dataframe,
9
9
  NoPapersFoundError as raised_error,
10
10
  )
11
+ from ..tools.s2.display_dataframe import (
12
+ display_dataframe,
13
+ )
11
14
 
12
15
 
13
16
  @pytest.fixture(name="initial_state")
@@ -51,9 +54,7 @@ class TestS2Tools:
51
54
  raised_error,
52
55
  match="No papers found. A search/rec needs to be performed first.",
53
56
  ):
54
- display_dataframe.invoke(
55
- {"state": initial_state, "tool_call_id": "test123"}
56
- )
57
+ display_dataframe.invoke({"state": initial_state, "tool_call_id": "test123"})
57
58
 
58
59
  def test_display_dataframe_shows_papers(self, initial_state):
59
60
  """Verifies display_dataframe tool correctly returns papers from state"""
@@ -61,9 +62,7 @@ class TestS2Tools:
61
62
  state["last_displayed_papers"] = "papers"
62
63
  state["papers"] = MOCK_STATE_PAPER
63
64
 
64
- result = display_dataframe.invoke(
65
- input={"state": state, "tool_call_id": "test123"}
66
- )
65
+ result = display_dataframe.invoke(input={"state": state, "tool_call_id": "test123"})
67
66
 
68
67
  assert isinstance(result, Command) # Expect a Command object
69
68
  assert isinstance(result.update, dict) # Ensure update is a dictionary
@@ -59,9 +59,7 @@ class TestS2Tools:
59
59
  ):
60
60
  query_dataframe.run(tool_input)
61
61
 
62
- @patch(
63
- "aiagents4pharma.talk2scholars.tools.s2.query_dataframe.create_pandas_dataframe_agent"
64
- )
62
+ @patch("aiagents4pharma.talk2scholars.tools.s2.query_dataframe.create_pandas_dataframe_agent")
65
63
  def test_query_dataframe_with_papers(self, mock_create_agent, initial_state):
66
64
  """Tests querying papers when data is available."""
67
65
  state = initial_state.copy()
@@ -72,9 +70,7 @@ class TestS2Tools:
72
70
  mock_agent = MagicMock()
73
71
  mock_agent.invoke.return_value = {"output": "Mocked response"}
74
72
 
75
- mock_create_agent.return_value = (
76
- mock_agent # Mock the function returning the agent
77
- )
73
+ mock_create_agent.return_value = mock_agent # Mock the function returning the agent
78
74
 
79
75
  # Ensure that the output of query_dataframe is correctly structured
80
76
  # Invoke the tool with a test tool_call_id
@@ -94,9 +90,7 @@ class TestS2Tools:
94
90
  assert isinstance(msg, ToolMessage)
95
91
  assert msg.content == "Mocked response"
96
92
 
97
- @patch(
98
- "aiagents4pharma.talk2scholars.tools.s2.query_dataframe.create_pandas_dataframe_agent"
99
- )
93
+ @patch("aiagents4pharma.talk2scholars.tools.s2.query_dataframe.create_pandas_dataframe_agent")
100
94
  def test_query_dataframe_direct_mapping(self, mock_create_agent, initial_state):
101
95
  """Tests query_dataframe when last_displayed_papers is a direct dict mapping."""
102
96
  # Prepare state with direct mapping
@@ -143,9 +137,7 @@ class TestS2Tools:
143
137
  query_dataframe.run(tool_input)
144
138
  assert "Could not resolve a valid metadata dictionary" in str(exc.value)
145
139
 
146
- @patch(
147
- "aiagents4pharma.talk2scholars.tools.s2.query_dataframe.create_pandas_dataframe_agent"
148
- )
140
+ @patch("aiagents4pharma.talk2scholars.tools.s2.query_dataframe.create_pandas_dataframe_agent")
149
141
  def test_query_dataframe_extract_ids(self, mock_create_agent):
150
142
  """Test extract_ids returns the raw list or single element correctly."""
151
143
  # Prepare state with fake paper_ids column
@@ -159,9 +151,7 @@ class TestS2Tools:
159
151
  state[state_key] = dic # simulate indirect mapping
160
152
  # Mock agent to echo the Python expression
161
153
  mock_agent = MagicMock()
162
- mock_agent.invoke.side_effect = lambda args, stream_mode=None: {
163
- "output": args["input"]
164
- }
154
+ mock_agent.invoke.side_effect = lambda args, stream_mode=None: {"output": args["input"]}
165
155
  mock_create_agent.return_value = mock_agent
166
156
  # Test full list
167
157
  tool_input = {
@@ -33,12 +33,14 @@ from aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader import
33
33
  # --- tiny helpers to manipulate factory state without protected-access lint ---
34
34
  def _set_cached_config(value):
35
35
  """set cached config in the factory for testing purposes."""
36
- setattr(PaperDownloaderFactory, "_cached_config", value)
36
+ attr_name = "_cached_config"
37
+ setattr(PaperDownloaderFactory, attr_name, value)
37
38
 
38
39
 
39
40
  def _set_config_lock(lock_obj):
40
41
  """set the config lock object in the factory for testing purposes."""
41
- setattr(PaperDownloaderFactory, "_config_lock", lock_obj)
42
+ attr_name = "_config_lock"
43
+ setattr(PaperDownloaderFactory, attr_name, lock_obj)
42
44
 
43
45
 
44
46
  class PaperDownloaderFactoryTestShim(PaperDownloaderFactory):
@@ -121,16 +123,10 @@ class TestPaperDownloaderFactory(unittest.TestCase):
121
123
  """tear down after each test."""
122
124
  PaperDownloaderFactory.clear_cache()
123
125
 
124
- @patch(
125
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.ArxivDownloader"
126
- )
126
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.ArxivDownloader")
127
127
  @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.hydra")
128
- @patch(
129
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra"
130
- )
131
- def test_create_arxiv_and_cached_config(
132
- self, mock_global_hydra, mock_hydra, mock_arxiv
133
- ):
128
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra")
129
+ def test_create_arxiv_and_cached_config(self, mock_global_hydra, mock_hydra, mock_arxiv):
134
130
  """First create loads config, second create returns cached config (no re-init)."""
135
131
  # First call: GlobalHydra not initialized
136
132
  mock_global_hydra.return_value.is_initialized.return_value = False
@@ -156,16 +152,10 @@ class TestPaperDownloaderFactory(unittest.TestCase):
156
152
  mock_hydra.initialize.assert_not_called()
157
153
  mock_hydra.compose.assert_not_called()
158
154
 
159
- @patch(
160
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.MedrxivDownloader"
161
- )
155
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.MedrxivDownloader")
162
156
  @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.hydra")
163
- @patch(
164
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra"
165
- )
166
- @patch(
167
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.OmegaConf"
168
- )
157
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra")
158
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.OmegaConf")
169
159
  def test_create_medrxiv_omegaconf_and_clear_existing(
170
160
  self, mock_omegaconf, mock_global_hydra, mock_hydra, mock_medrxiv
171
161
  ):
@@ -195,16 +185,10 @@ class TestPaperDownloaderFactory(unittest.TestCase):
195
185
  self.assertEqual(cfg_d["api_url"], "https://med")
196
186
  self.assertEqual(cfg_d["pdf_url_template"], "T")
197
187
 
198
- @patch(
199
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.BiorxivDownloader"
200
- )
188
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.BiorxivDownloader")
201
189
  @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.hydra")
202
- @patch(
203
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra"
204
- )
205
- def test_create_biorxiv_dir_fallback(
206
- self, mock_global_hydra, mock_hydra, mock_biorxiv
207
- ):
190
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra")
191
+ def test_create_biorxiv_dir_fallback(self, mock_global_hydra, mock_hydra, mock_biorxiv):
208
192
  """dir() fallback path with __slots__ object should populate public, skip private."""
209
193
  mock_global_hydra.return_value.is_initialized.return_value = False
210
194
  common_obj = _SlotsSource(public_val=30, private_val="hide")
@@ -221,13 +205,9 @@ class TestPaperDownloaderFactory(unittest.TestCase):
221
205
  # Ensure private key not present
222
206
  self.assertNotIn("_private", cfg_d)
223
207
 
224
- @patch(
225
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.PubmedDownloader"
226
- )
208
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.PubmedDownloader")
227
209
  @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.hydra")
228
- @patch(
229
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra"
230
- )
210
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra")
231
211
  def test_create_pubmed_apply_config_warning_path(
232
212
  self, mock_global_hydra, mock_hydra, mock_pubmed
233
213
  ):
@@ -236,9 +216,7 @@ class TestPaperDownloaderFactory(unittest.TestCase):
236
216
  # First (common) will raise inside _extract_from_items -> warning
237
217
  common_obj = _ExplodingItemsSlots()
238
218
  # Service path is sane to still build config
239
- svc_obj = SimpleNamespace(
240
- api_url="https://pubmed", request_timeout=55, chunk_size=1024
241
- )
219
+ svc_obj = SimpleNamespace(api_url="https://pubmed", request_timeout=55, chunk_size=1024)
242
220
  mock_hydra.compose.return_value = _cfg_obj(common_obj, {"pubmed": svc_obj})
243
221
 
244
222
  with patch(
@@ -255,26 +233,18 @@ class TestPaperDownloaderFactory(unittest.TestCase):
255
233
  self.assertEqual(cfg_d["chunk_size"], 1024)
256
234
 
257
235
  @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.hydra")
258
- @patch(
259
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra"
260
- )
236
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra")
261
237
  def test_create_missing_service_error_message(self, mock_global_hydra, mock_hydra):
262
238
  """Missing service should raise ValueError with 'Service ... not found' message."""
263
239
  mock_global_hydra.return_value.is_initialized.return_value = False
264
240
  mock_hydra.compose.return_value = _cfg_obj(SimpleNamespace(), {"arxiv": {}})
265
241
  with self.assertRaises(ValueError) as ctx:
266
242
  PaperDownloaderFactory.create("unsupported")
267
- self.assertIn(
268
- "Service 'unsupported' not found in configuration", str(ctx.exception)
269
- )
243
+ self.assertIn("Service 'unsupported' not found in configuration", str(ctx.exception))
270
244
 
271
245
  @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.hydra")
272
- @patch(
273
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra"
274
- )
275
- def test_get_unified_config_failure_raises_runtimeerror(
276
- self, mock_global_hydra, mock_hydra
277
- ):
246
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra")
247
+ def test_get_unified_config_failure_raises_runtimeerror(self, mock_global_hydra, mock_hydra):
278
248
  """Hydra initialize failure should surface as RuntimeError from create()."""
279
249
  PaperDownloaderFactory.clear_cache()
280
250
  mock_global_hydra.return_value.is_initialized.return_value = False
@@ -400,9 +370,7 @@ class TestDownloadPapersFunction(unittest.TestCase):
400
370
  self.assertTrue(result.update["ok"])
401
371
 
402
372
  @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.hydra")
403
- @patch(
404
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra"
405
- )
373
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra")
406
374
  def test_get_default_service_functionality(self, mock_global_hydra, mock_hydra):
407
375
  """Test get_default_service method with various configurations."""
408
376
  mock_global_hydra.return_value.is_initialized.return_value = False
@@ -411,14 +379,12 @@ class TestDownloadPapersFunction(unittest.TestCase):
411
379
  common_cfg = SimpleNamespace(request_timeout=30, chunk_size=8192)
412
380
  services = {
413
381
  "arxiv": SimpleNamespace(api_url="https://arxiv.org"),
414
- "pubmed": SimpleNamespace(id_converter_url="https://pmc.ncbi.nlm.nih.gov")
382
+ "pubmed": SimpleNamespace(id_converter_url="https://pmc.ncbi.nlm.nih.gov"),
415
383
  }
416
384
  tool_cfg = SimpleNamespace(default_service="arxiv")
417
385
  mock_hydra.compose.return_value = SimpleNamespace(
418
386
  tools=SimpleNamespace(
419
- paper_download=SimpleNamespace(
420
- tool=tool_cfg, common=common_cfg, services=services
421
- )
387
+ paper_download=SimpleNamespace(tool=tool_cfg, common=common_cfg, services=services)
422
388
  )
423
389
  )
424
390
 
@@ -449,9 +415,7 @@ class TestDownloadPapersFunction(unittest.TestCase):
449
415
  tool_cfg.default_service = "medrxiv"
450
416
  mock_hydra.compose.return_value = SimpleNamespace(
451
417
  tools=SimpleNamespace(
452
- paper_download=SimpleNamespace(
453
- tool=tool_cfg, common=common_cfg, services=services
454
- )
418
+ paper_download=SimpleNamespace(tool=tool_cfg, common=common_cfg, services=services)
455
419
  )
456
420
  )
457
421
  PaperDownloaderFactory.clear_cache()
@@ -469,9 +433,7 @@ class TestUnifiedConfigDoubleCheck(unittest.TestCase):
469
433
  """Covers the double-check return branch in _get_unified_config."""
470
434
 
471
435
  @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.hydra")
472
- @patch(
473
- "aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra"
474
- )
436
+ @patch("aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.GlobalHydra")
475
437
  def test_double_check_inside_lock(self, mock_global_hydra, _mock_hydra):
476
438
  """tests the double-check branch in _get_unified_config using public create()."""
477
439
  # avoid real hydra init path if we accidentally go there
@@ -73,9 +73,7 @@ def test_question_and_answer_success(dependencies_fixture, input_fixture):
73
73
  dependencies_fixture["mock_helper_cls"].return_value = mock_helper
74
74
  dependencies_fixture["mock_load_config"].return_value = {"config_key": "value"}
75
75
  dependencies_fixture["mock_get_vectorstore"].return_value = MagicMock()
76
- dependencies_fixture["mock_retrieve_rerank"].return_value = [
77
- {"chunk": "relevant content"}
78
- ]
76
+ dependencies_fixture["mock_retrieve_rerank"].return_value = [{"chunk": "relevant content"}]
79
77
  dependencies_fixture["mock_format_answer"].return_value = "Here is your answer."
80
78
 
81
79
  result = question_and_answer.invoke(input_fixture)
@@ -99,9 +97,7 @@ def test_question_and_answer_no_reranked_chunks(dependencies_fixture, input_fixt
99
97
  dependencies_fixture["mock_load_config"].return_value = {"config_key": "value"}
100
98
  dependencies_fixture["mock_get_vectorstore"].return_value = MagicMock()
101
99
  dependencies_fixture["mock_retrieve_rerank"].return_value = []
102
- dependencies_fixture["mock_format_answer"].return_value = (
103
- "No relevant information found."
104
- )
100
+ dependencies_fixture["mock_format_answer"].return_value = "No relevant information found."
105
101
 
106
102
  result = question_and_answer.invoke(input_fixture)
107
103
 
@@ -4,11 +4,13 @@ Unit tests for S2 tools functionality.
4
4
 
5
5
  import json
6
6
  from types import SimpleNamespace
7
+
8
+ import hydra
7
9
  import pytest
8
10
  import requests
9
- from langgraph.types import Command
10
11
  from langchain_core.messages import ToolMessage
11
- import hydra
12
+ from langgraph.types import Command
13
+
12
14
  from aiagents4pharma.talk2scholars.tools.s2.multi_paper_rec import (
13
15
  get_multi_paper_recommendations,
14
16
  )
@@ -162,9 +164,7 @@ def dummy_requests_post_exception(url, headers, params, data, timeout):
162
164
  def patch_hydra(monkeypatch):
163
165
  """Patch Hydra's initialize and compose functions to return dummy objects."""
164
166
  # Patch hydra.initialize to return our dummy context manager.
165
- monkeypatch.setattr(
166
- hydra, "initialize", lambda version_base, config_path: DummyHydraContext()
167
- )
167
+ monkeypatch.setattr(hydra, "initialize", lambda version_base, config_path: DummyHydraContext())
168
168
  # Patch hydra.compose to return our dummy config.
169
169
  monkeypatch.setattr(hydra, "compose", lambda config_name, overrides: dummy_config)
170
170
 
@@ -3,13 +3,14 @@ Unit tests for S2 tools functionality.
3
3
  """
4
4
 
5
5
  from unittest.mock import patch
6
+
6
7
  import pytest
7
8
  from langgraph.types import Command
9
+
8
10
  from ..tools.s2.retrieve_semantic_scholar_paper_id import (
9
11
  retrieve_semantic_scholar_paper_id,
10
12
  )
11
13
 
12
-
13
14
  # Fixed test data for deterministic results
14
15
  MOCK_SEARCH_RESPONSE = {
15
16
  "data": [
@@ -3,11 +3,13 @@ Unit tests for S2 tools functionality.
3
3
  """
4
4
 
5
5
  from types import SimpleNamespace
6
- import pytest
6
+
7
7
  import hydra
8
+ import pytest
8
9
  import requests
9
- from langgraph.types import Command
10
10
  from langchain_core.messages import ToolMessage
11
+ from langgraph.types import Command
12
+
11
13
  from aiagents4pharma.talk2scholars.tools.s2.search import search_tool
12
14
  from aiagents4pharma.talk2scholars.tools.s2.utils import search_helper
13
15
 
@@ -147,9 +149,7 @@ def dummy_requests_get_exception(url, params, timeout):
147
149
  def patch_hydra(monkeypatch):
148
150
  """hydra patch to mock initialize and compose functions."""
149
151
  # Patch hydra.initialize to return our dummy context manager.
150
- monkeypatch.setattr(
151
- hydra, "initialize", lambda version_base, config_path: DummyHydraContext()
152
- )
152
+ monkeypatch.setattr(hydra, "initialize", lambda version_base, config_path: DummyHydraContext())
153
153
  # Patch hydra.compose to return our dummy config.
154
154
  monkeypatch.setattr(hydra, "compose", lambda config_name, overrides: dummy_config)
155
155
 
@@ -3,11 +3,13 @@ Unit tests for S2 tools functionality.
3
3
  """
4
4
 
5
5
  from types import SimpleNamespace
6
+
7
+ import hydra
6
8
  import pytest
7
9
  import requests
8
- import hydra
9
- from langgraph.types import Command
10
10
  from langchain_core.messages import ToolMessage
11
+ from langgraph.types import Command
12
+
11
13
  from aiagents4pharma.talk2scholars.tools.s2.single_paper_rec import (
12
14
  get_single_paper_recommendations,
13
15
  )
@@ -156,9 +158,7 @@ def dummy_requests_get_exception(url, params, timeout):
156
158
  @pytest.fixture(autouse=True)
157
159
  def patch_hydra(monkeypatch):
158
160
  """Patch Hydra's initialize and compose functions with dummy implementations."""
159
- monkeypatch.setattr(
160
- hydra, "initialize", lambda version_base, config_path: DummyHydraContext()
161
- )
161
+ monkeypatch.setattr(hydra, "initialize", lambda version_base, config_path: DummyHydraContext())
162
162
  # Patch hydra.compose to return our dummy config.
163
163
  monkeypatch.setattr(hydra, "compose", lambda config_name, overrides: dummy_config)
164
164
 
@@ -81,7 +81,10 @@ class TestArxivDownloader(unittest.TestCase):
81
81
  <name>Jane Smith</name>
82
82
  </author>
83
83
  <link href="http://arxiv.org/abs/1234.5678v1" rel="alternate" type="text/html"/>
84
- <link href="http://arxiv.org/pdf/1234.5678v1.pdf" rel="related" type="application/pdf" title="pdf"/>
84
+ <link href="http://arxiv.org/pdf/1234.5678v1.pdf"
85
+ rel="related"
86
+ type="application/pdf"
87
+ title="pdf"/>
85
88
  </entry>
86
89
  </feed>"""
87
90
 
@@ -104,8 +107,7 @@ class TestArxivDownloader(unittest.TestCase):
104
107
 
105
108
  # Verify API call - it uses query string format, not params
106
109
  expected_url = (
107
- "http://export.arxiv.org/api/query?search_query="
108
- "id:1234.5678&start=0&max_results=1"
110
+ "http://export.arxiv.org/api/query?search_query=id:1234.5678&start=0&max_results=1"
109
111
  )
110
112
  mock_get.assert_called_once_with(expected_url, timeout=30)
111
113
  mock_response.raise_for_status.assert_called_once()
@@ -201,9 +203,7 @@ class TestArxivDownloader(unittest.TestCase):
201
203
  metadata = ET.fromstring(self.sample_xml)
202
204
  pdf_result = ("/tmp/test.pdf", "test_paper.pdf")
203
205
 
204
- result = self.downloader.extract_paper_metadata(
205
- metadata, "1234.5678", pdf_result
206
- )
206
+ result = self.downloader.extract_paper_metadata(metadata, "1234.5678", pdf_result)
207
207
 
208
208
  # Verify extracted metadata
209
209
  expected_metadata = {
@@ -226,9 +226,7 @@ class TestArxivDownloader(unittest.TestCase):
226
226
  """Test metadata extraction without PDF download."""
227
227
  metadata = ET.fromstring(self.sample_xml)
228
228
 
229
- with patch.object(
230
- self.downloader, "get_default_filename", return_value="1234.5678.pdf"
231
- ):
229
+ with patch.object(self.downloader, "get_default_filename", return_value="1234.5678.pdf"):
232
230
  result = self.downloader.extract_paper_metadata(metadata, "1234.5678", None)
233
231
 
234
232
  # Verify metadata without PDF
@@ -275,9 +273,7 @@ class TestArxivDownloader(unittest.TestCase):
275
273
  # Case 1: Title present
276
274
  metadata1 = ET.fromstring(self.sample_xml)
277
275
  entry1 = metadata1.find("atom:entry", ns)
278
- self.assertEqual(
279
- self.downloader.extract_title_public(entry1, ns), "Test Paper Title"
280
- )
276
+ self.assertEqual(self.downloader.extract_title_public(entry1, ns), "Test Paper Title")
281
277
 
282
278
  # Case 2: Title missing
283
279
  xml_no_title = """<?xml version="1.0" encoding="UTF-8"?>
@@ -346,9 +342,7 @@ class TestArxivDownloader(unittest.TestCase):
346
342
  )
347
343
 
348
344
  # Without result
349
- with patch.object(
350
- self.downloader, "get_default_filename", return_value="default.pdf"
351
- ):
345
+ with patch.object(self.downloader, "get_default_filename", return_value="default.pdf"):
352
346
  expected_without = {
353
347
  "URL": "",
354
348
  "pdf_url": "",
@@ -365,9 +359,7 @@ class TestArxivDownloader(unittest.TestCase):
365
359
  """Service name, identifier name, and default filename helpers."""
366
360
  self.assertEqual(self.downloader.get_service_name(), "arXiv")
367
361
  self.assertEqual(self.downloader.get_identifier_name(), "arXiv ID")
368
- self.assertEqual(
369
- self.downloader.get_default_filename("1234.5678"), "1234.5678.pdf"
370
- )
362
+ self.assertEqual(self.downloader.get_default_filename("1234.5678"), "1234.5678.pdf")
371
363
 
372
364
  def test_get_paper_identifier_info(self):
373
365
  """Test _get_paper_identifier_info method."""
@@ -411,7 +403,10 @@ class TestArxivDownloaderIntegration(unittest.TestCase):
411
403
  <author>
412
404
  <name>Test Author</name>
413
405
  </author>
414
- <link href="http://arxiv.org/pdf/1234.5678v1.pdf" rel="related" type="application/pdf" title="pdf"/>
406
+ <link href="http://arxiv.org/pdf/1234.5678v1.pdf"
407
+ rel="related"
408
+ type="application/pdf"
409
+ title="pdf"/>
415
410
  </entry>
416
411
  </feed>"""
417
412
 
@@ -446,9 +441,7 @@ class TestArxivDownloaderIntegration(unittest.TestCase):
446
441
  pdf_result = self.downloader.download_pdf_to_temp(pdf_url, identifier)
447
442
 
448
443
  # Step 4: Extract metadata
449
- paper_data = self.downloader.extract_paper_metadata(
450
- metadata, identifier, pdf_result
451
- )
444
+ paper_data = self.downloader.extract_paper_metadata(metadata, identifier, pdf_result)
452
445
 
453
446
  results[identifier] = paper_data
454
447
 
@@ -464,9 +457,7 @@ class TestArxivDownloaderIntegration(unittest.TestCase):
464
457
 
465
458
  # Verify method calls
466
459
  mock_get.assert_called_once()
467
- mock_download.assert_called_once_with(
468
- "http://arxiv.org/pdf/1234.5678v1.pdf", "1234.5678"
469
- )
460
+ mock_download.assert_called_once_with("http://arxiv.org/pdf/1234.5678v1.pdf", "1234.5678")
470
461
 
471
462
  @patch("requests.get")
472
463
  def test_error_handling_workflow(self, mock_get):