aiagents4pharma 0.0.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 (336) hide show
  1. aiagents4pharma/__init__.py +11 -0
  2. aiagents4pharma/talk2aiagents4pharma/.dockerignore +13 -0
  3. aiagents4pharma/talk2aiagents4pharma/Dockerfile +133 -0
  4. aiagents4pharma/talk2aiagents4pharma/README.md +1 -0
  5. aiagents4pharma/talk2aiagents4pharma/__init__.py +5 -0
  6. aiagents4pharma/talk2aiagents4pharma/agents/__init__.py +6 -0
  7. aiagents4pharma/talk2aiagents4pharma/agents/main_agent.py +70 -0
  8. aiagents4pharma/talk2aiagents4pharma/configs/__init__.py +5 -0
  9. aiagents4pharma/talk2aiagents4pharma/configs/agents/__init__.py +5 -0
  10. aiagents4pharma/talk2aiagents4pharma/configs/agents/main_agent/default.yaml +29 -0
  11. aiagents4pharma/talk2aiagents4pharma/configs/app/__init__.py +0 -0
  12. aiagents4pharma/talk2aiagents4pharma/configs/app/frontend/__init__.py +0 -0
  13. aiagents4pharma/talk2aiagents4pharma/configs/app/frontend/default.yaml +102 -0
  14. aiagents4pharma/talk2aiagents4pharma/configs/config.yaml +4 -0
  15. aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/.env.example +23 -0
  16. aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/docker-compose.yml +93 -0
  17. aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/.env.example +23 -0
  18. aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/docker-compose.yml +108 -0
  19. aiagents4pharma/talk2aiagents4pharma/install.md +154 -0
  20. aiagents4pharma/talk2aiagents4pharma/states/__init__.py +5 -0
  21. aiagents4pharma/talk2aiagents4pharma/states/state_talk2aiagents4pharma.py +18 -0
  22. aiagents4pharma/talk2aiagents4pharma/tests/__init__.py +3 -0
  23. aiagents4pharma/talk2aiagents4pharma/tests/test_main_agent.py +312 -0
  24. aiagents4pharma/talk2biomodels/.dockerignore +13 -0
  25. aiagents4pharma/talk2biomodels/Dockerfile +104 -0
  26. aiagents4pharma/talk2biomodels/README.md +1 -0
  27. aiagents4pharma/talk2biomodels/__init__.py +5 -0
  28. aiagents4pharma/talk2biomodels/agents/__init__.py +6 -0
  29. aiagents4pharma/talk2biomodels/agents/t2b_agent.py +104 -0
  30. aiagents4pharma/talk2biomodels/api/__init__.py +5 -0
  31. aiagents4pharma/talk2biomodels/api/ols.py +75 -0
  32. aiagents4pharma/talk2biomodels/api/uniprot.py +36 -0
  33. aiagents4pharma/talk2biomodels/configs/__init__.py +5 -0
  34. aiagents4pharma/talk2biomodels/configs/agents/__init__.py +5 -0
  35. aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/__init__.py +3 -0
  36. aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/default.yaml +14 -0
  37. aiagents4pharma/talk2biomodels/configs/app/__init__.py +0 -0
  38. aiagents4pharma/talk2biomodels/configs/app/frontend/__init__.py +0 -0
  39. aiagents4pharma/talk2biomodels/configs/app/frontend/default.yaml +72 -0
  40. aiagents4pharma/talk2biomodels/configs/config.yaml +7 -0
  41. aiagents4pharma/talk2biomodels/configs/tools/__init__.py +5 -0
  42. aiagents4pharma/talk2biomodels/configs/tools/ask_question/__init__.py +3 -0
  43. aiagents4pharma/talk2biomodels/configs/tools/ask_question/default.yaml +30 -0
  44. aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/__init__.py +3 -0
  45. aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/default.yaml +8 -0
  46. aiagents4pharma/talk2biomodels/configs/tools/get_annotation/__init__.py +3 -0
  47. aiagents4pharma/talk2biomodels/configs/tools/get_annotation/default.yaml +8 -0
  48. aiagents4pharma/talk2biomodels/install.md +63 -0
  49. aiagents4pharma/talk2biomodels/models/__init__.py +5 -0
  50. aiagents4pharma/talk2biomodels/models/basico_model.py +125 -0
  51. aiagents4pharma/talk2biomodels/models/sys_bio_model.py +60 -0
  52. aiagents4pharma/talk2biomodels/states/__init__.py +6 -0
  53. aiagents4pharma/talk2biomodels/states/state_talk2biomodels.py +49 -0
  54. aiagents4pharma/talk2biomodels/tests/BIOMD0000000449_url.xml +1585 -0
  55. aiagents4pharma/talk2biomodels/tests/__init__.py +3 -0
  56. aiagents4pharma/talk2biomodels/tests/article_on_model_537.pdf +0 -0
  57. aiagents4pharma/talk2biomodels/tests/test_api.py +31 -0
  58. aiagents4pharma/talk2biomodels/tests/test_ask_question.py +42 -0
  59. aiagents4pharma/talk2biomodels/tests/test_basico_model.py +67 -0
  60. aiagents4pharma/talk2biomodels/tests/test_get_annotation.py +190 -0
  61. aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py +92 -0
  62. aiagents4pharma/talk2biomodels/tests/test_integration.py +116 -0
  63. aiagents4pharma/talk2biomodels/tests/test_load_biomodel.py +35 -0
  64. aiagents4pharma/talk2biomodels/tests/test_param_scan.py +71 -0
  65. aiagents4pharma/talk2biomodels/tests/test_query_article.py +184 -0
  66. aiagents4pharma/talk2biomodels/tests/test_save_model.py +47 -0
  67. aiagents4pharma/talk2biomodels/tests/test_search_models.py +35 -0
  68. aiagents4pharma/talk2biomodels/tests/test_simulate_model.py +44 -0
  69. aiagents4pharma/talk2biomodels/tests/test_steady_state.py +86 -0
  70. aiagents4pharma/talk2biomodels/tests/test_sys_bio_model.py +67 -0
  71. aiagents4pharma/talk2biomodels/tools/__init__.py +17 -0
  72. aiagents4pharma/talk2biomodels/tools/ask_question.py +125 -0
  73. aiagents4pharma/talk2biomodels/tools/custom_plotter.py +165 -0
  74. aiagents4pharma/talk2biomodels/tools/get_annotation.py +342 -0
  75. aiagents4pharma/talk2biomodels/tools/get_modelinfo.py +159 -0
  76. aiagents4pharma/talk2biomodels/tools/load_arguments.py +134 -0
  77. aiagents4pharma/talk2biomodels/tools/load_biomodel.py +44 -0
  78. aiagents4pharma/talk2biomodels/tools/parameter_scan.py +310 -0
  79. aiagents4pharma/talk2biomodels/tools/query_article.py +64 -0
  80. aiagents4pharma/talk2biomodels/tools/save_model.py +98 -0
  81. aiagents4pharma/talk2biomodels/tools/search_models.py +96 -0
  82. aiagents4pharma/talk2biomodels/tools/simulate_model.py +137 -0
  83. aiagents4pharma/talk2biomodels/tools/steady_state.py +187 -0
  84. aiagents4pharma/talk2biomodels/tools/utils.py +23 -0
  85. aiagents4pharma/talk2cells/README.md +1 -0
  86. aiagents4pharma/talk2cells/__init__.py +5 -0
  87. aiagents4pharma/talk2cells/agents/__init__.py +6 -0
  88. aiagents4pharma/talk2cells/agents/scp_agent.py +87 -0
  89. aiagents4pharma/talk2cells/states/__init__.py +6 -0
  90. aiagents4pharma/talk2cells/states/state_talk2cells.py +15 -0
  91. aiagents4pharma/talk2cells/tests/scp_agent/test_scp_agent.py +22 -0
  92. aiagents4pharma/talk2cells/tools/__init__.py +6 -0
  93. aiagents4pharma/talk2cells/tools/scp_agent/__init__.py +6 -0
  94. aiagents4pharma/talk2cells/tools/scp_agent/display_studies.py +27 -0
  95. aiagents4pharma/talk2cells/tools/scp_agent/search_studies.py +78 -0
  96. aiagents4pharma/talk2knowledgegraphs/.dockerignore +13 -0
  97. aiagents4pharma/talk2knowledgegraphs/Dockerfile +131 -0
  98. aiagents4pharma/talk2knowledgegraphs/README.md +1 -0
  99. aiagents4pharma/talk2knowledgegraphs/__init__.py +5 -0
  100. aiagents4pharma/talk2knowledgegraphs/agents/__init__.py +5 -0
  101. aiagents4pharma/talk2knowledgegraphs/agents/t2kg_agent.py +99 -0
  102. aiagents4pharma/talk2knowledgegraphs/configs/__init__.py +5 -0
  103. aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/__init__.py +3 -0
  104. aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/default.yaml +62 -0
  105. aiagents4pharma/talk2knowledgegraphs/configs/app/__init__.py +5 -0
  106. aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/__init__.py +3 -0
  107. aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/default.yaml +79 -0
  108. aiagents4pharma/talk2knowledgegraphs/configs/config.yaml +13 -0
  109. aiagents4pharma/talk2knowledgegraphs/configs/tools/__init__.py +5 -0
  110. aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/__init__.py +3 -0
  111. aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/default.yaml +24 -0
  112. aiagents4pharma/talk2knowledgegraphs/configs/tools/multimodal_subgraph_extraction/__init__.py +0 -0
  113. aiagents4pharma/talk2knowledgegraphs/configs/tools/multimodal_subgraph_extraction/default.yaml +33 -0
  114. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/__init__.py +3 -0
  115. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/default.yaml +43 -0
  116. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/__init__.py +3 -0
  117. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/default.yaml +9 -0
  118. aiagents4pharma/talk2knowledgegraphs/configs/utils/database/milvus/__init__.py +3 -0
  119. aiagents4pharma/talk2knowledgegraphs/configs/utils/database/milvus/default.yaml +61 -0
  120. aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/ols_terms/default.yaml +3 -0
  121. aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/reactome_pathways/default.yaml +3 -0
  122. aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/uniprot_proteins/default.yaml +6 -0
  123. aiagents4pharma/talk2knowledgegraphs/configs/utils/pubchem_utils/default.yaml +5 -0
  124. aiagents4pharma/talk2knowledgegraphs/datasets/__init__.py +5 -0
  125. aiagents4pharma/talk2knowledgegraphs/datasets/biobridge_primekg.py +607 -0
  126. aiagents4pharma/talk2knowledgegraphs/datasets/dataset.py +25 -0
  127. aiagents4pharma/talk2knowledgegraphs/datasets/primekg.py +212 -0
  128. aiagents4pharma/talk2knowledgegraphs/datasets/starkqa_primekg.py +210 -0
  129. aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/.env.example +23 -0
  130. aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/docker-compose.yml +93 -0
  131. aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/.env.example +23 -0
  132. aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/docker-compose.yml +108 -0
  133. aiagents4pharma/talk2knowledgegraphs/entrypoint.sh +180 -0
  134. aiagents4pharma/talk2knowledgegraphs/install.md +165 -0
  135. aiagents4pharma/talk2knowledgegraphs/milvus_data_dump.py +886 -0
  136. aiagents4pharma/talk2knowledgegraphs/states/__init__.py +5 -0
  137. aiagents4pharma/talk2knowledgegraphs/states/state_talk2knowledgegraphs.py +40 -0
  138. aiagents4pharma/talk2knowledgegraphs/tests/__init__.py +0 -0
  139. aiagents4pharma/talk2knowledgegraphs/tests/test_agents_t2kg_agent.py +318 -0
  140. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_biobridge_primekg.py +248 -0
  141. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_dataset.py +33 -0
  142. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_primekg.py +86 -0
  143. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_starkqa_primekg.py +125 -0
  144. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_graphrag_reasoning.py +257 -0
  145. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_milvus_multimodal_subgraph_extraction.py +1444 -0
  146. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_multimodal_subgraph_extraction.py +159 -0
  147. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_extraction.py +152 -0
  148. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_summarization.py +201 -0
  149. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_database_milvus_connection_manager.py +812 -0
  150. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_embeddings.py +51 -0
  151. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_huggingface.py +49 -0
  152. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_nim_molmim.py +59 -0
  153. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_ollama.py +63 -0
  154. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_sentencetransformer.py +47 -0
  155. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_enrichments.py +40 -0
  156. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ollama.py +94 -0
  157. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ols.py +70 -0
  158. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_pubchem.py +45 -0
  159. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_reactome.py +44 -0
  160. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_uniprot.py +48 -0
  161. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_extractions_milvus_multimodal_pcst.py +759 -0
  162. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_kg_utils.py +78 -0
  163. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_pubchem_utils.py +123 -0
  164. aiagents4pharma/talk2knowledgegraphs/tools/__init__.py +11 -0
  165. aiagents4pharma/talk2knowledgegraphs/tools/graphrag_reasoning.py +138 -0
  166. aiagents4pharma/talk2knowledgegraphs/tools/load_arguments.py +22 -0
  167. aiagents4pharma/talk2knowledgegraphs/tools/milvus_multimodal_subgraph_extraction.py +965 -0
  168. aiagents4pharma/talk2knowledgegraphs/tools/multimodal_subgraph_extraction.py +374 -0
  169. aiagents4pharma/talk2knowledgegraphs/tools/subgraph_extraction.py +291 -0
  170. aiagents4pharma/talk2knowledgegraphs/tools/subgraph_summarization.py +123 -0
  171. aiagents4pharma/talk2knowledgegraphs/utils/__init__.py +5 -0
  172. aiagents4pharma/talk2knowledgegraphs/utils/database/__init__.py +5 -0
  173. aiagents4pharma/talk2knowledgegraphs/utils/database/milvus_connection_manager.py +586 -0
  174. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/__init__.py +5 -0
  175. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/embeddings.py +81 -0
  176. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/huggingface.py +111 -0
  177. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/nim_molmim.py +54 -0
  178. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/ollama.py +87 -0
  179. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/sentence_transformer.py +73 -0
  180. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/__init__.py +12 -0
  181. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/enrichments.py +37 -0
  182. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ollama.py +129 -0
  183. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ols_terms.py +89 -0
  184. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/pubchem_strings.py +78 -0
  185. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/reactome_pathways.py +71 -0
  186. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/uniprot_proteins.py +98 -0
  187. aiagents4pharma/talk2knowledgegraphs/utils/extractions/__init__.py +5 -0
  188. aiagents4pharma/talk2knowledgegraphs/utils/extractions/milvus_multimodal_pcst.py +762 -0
  189. aiagents4pharma/talk2knowledgegraphs/utils/extractions/multimodal_pcst.py +298 -0
  190. aiagents4pharma/talk2knowledgegraphs/utils/extractions/pcst.py +229 -0
  191. aiagents4pharma/talk2knowledgegraphs/utils/kg_utils.py +67 -0
  192. aiagents4pharma/talk2knowledgegraphs/utils/pubchem_utils.py +104 -0
  193. aiagents4pharma/talk2scholars/.dockerignore +13 -0
  194. aiagents4pharma/talk2scholars/Dockerfile +104 -0
  195. aiagents4pharma/talk2scholars/README.md +1 -0
  196. aiagents4pharma/talk2scholars/__init__.py +7 -0
  197. aiagents4pharma/talk2scholars/agents/__init__.py +13 -0
  198. aiagents4pharma/talk2scholars/agents/main_agent.py +89 -0
  199. aiagents4pharma/talk2scholars/agents/paper_download_agent.py +96 -0
  200. aiagents4pharma/talk2scholars/agents/pdf_agent.py +101 -0
  201. aiagents4pharma/talk2scholars/agents/s2_agent.py +135 -0
  202. aiagents4pharma/talk2scholars/agents/zotero_agent.py +127 -0
  203. aiagents4pharma/talk2scholars/configs/__init__.py +7 -0
  204. aiagents4pharma/talk2scholars/configs/agents/__init__.py +7 -0
  205. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/__init__.py +7 -0
  206. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/main_agent/__init__.py +3 -0
  207. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/main_agent/default.yaml +52 -0
  208. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/paper_download_agent/__init__.py +3 -0
  209. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/paper_download_agent/default.yaml +19 -0
  210. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/pdf_agent/__init__.py +3 -0
  211. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/pdf_agent/default.yaml +19 -0
  212. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/s2_agent/__init__.py +3 -0
  213. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/s2_agent/default.yaml +44 -0
  214. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/zotero_agent/__init__.py +3 -0
  215. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/zotero_agent/default.yaml +19 -0
  216. aiagents4pharma/talk2scholars/configs/app/__init__.py +7 -0
  217. aiagents4pharma/talk2scholars/configs/app/frontend/__init__.py +3 -0
  218. aiagents4pharma/talk2scholars/configs/app/frontend/default.yaml +72 -0
  219. aiagents4pharma/talk2scholars/configs/config.yaml +16 -0
  220. aiagents4pharma/talk2scholars/configs/tools/__init__.py +21 -0
  221. aiagents4pharma/talk2scholars/configs/tools/multi_paper_recommendation/__init__.py +3 -0
  222. aiagents4pharma/talk2scholars/configs/tools/multi_paper_recommendation/default.yaml +26 -0
  223. aiagents4pharma/talk2scholars/configs/tools/paper_download/__init__.py +3 -0
  224. aiagents4pharma/talk2scholars/configs/tools/paper_download/default.yaml +124 -0
  225. aiagents4pharma/talk2scholars/configs/tools/question_and_answer/__init__.py +3 -0
  226. aiagents4pharma/talk2scholars/configs/tools/question_and_answer/default.yaml +62 -0
  227. aiagents4pharma/talk2scholars/configs/tools/retrieve_semantic_scholar_paper_id/__init__.py +3 -0
  228. aiagents4pharma/talk2scholars/configs/tools/retrieve_semantic_scholar_paper_id/default.yaml +12 -0
  229. aiagents4pharma/talk2scholars/configs/tools/search/__init__.py +3 -0
  230. aiagents4pharma/talk2scholars/configs/tools/search/default.yaml +26 -0
  231. aiagents4pharma/talk2scholars/configs/tools/single_paper_recommendation/__init__.py +3 -0
  232. aiagents4pharma/talk2scholars/configs/tools/single_paper_recommendation/default.yaml +26 -0
  233. aiagents4pharma/talk2scholars/configs/tools/zotero_read/__init__.py +3 -0
  234. aiagents4pharma/talk2scholars/configs/tools/zotero_read/default.yaml +57 -0
  235. aiagents4pharma/talk2scholars/configs/tools/zotero_write/__inti__.py +3 -0
  236. aiagents4pharma/talk2scholars/configs/tools/zotero_write/default.yaml +55 -0
  237. aiagents4pharma/talk2scholars/docker-compose/cpu/.env.example +21 -0
  238. aiagents4pharma/talk2scholars/docker-compose/cpu/docker-compose.yml +90 -0
  239. aiagents4pharma/talk2scholars/docker-compose/gpu/.env.example +21 -0
  240. aiagents4pharma/talk2scholars/docker-compose/gpu/docker-compose.yml +105 -0
  241. aiagents4pharma/talk2scholars/install.md +122 -0
  242. aiagents4pharma/talk2scholars/state/__init__.py +7 -0
  243. aiagents4pharma/talk2scholars/state/state_talk2scholars.py +98 -0
  244. aiagents4pharma/talk2scholars/tests/__init__.py +3 -0
  245. aiagents4pharma/talk2scholars/tests/test_agents_main_agent.py +256 -0
  246. aiagents4pharma/talk2scholars/tests/test_agents_paper_agents_download_agent.py +139 -0
  247. aiagents4pharma/talk2scholars/tests/test_agents_pdf_agent.py +114 -0
  248. aiagents4pharma/talk2scholars/tests/test_agents_s2_agent.py +198 -0
  249. aiagents4pharma/talk2scholars/tests/test_agents_zotero_agent.py +160 -0
  250. aiagents4pharma/talk2scholars/tests/test_s2_tools_display_dataframe.py +91 -0
  251. aiagents4pharma/talk2scholars/tests/test_s2_tools_query_dataframe.py +191 -0
  252. aiagents4pharma/talk2scholars/tests/test_states_state.py +38 -0
  253. aiagents4pharma/talk2scholars/tests/test_tools_paper_downloader.py +507 -0
  254. aiagents4pharma/talk2scholars/tests/test_tools_question_and_answer_tool.py +105 -0
  255. aiagents4pharma/talk2scholars/tests/test_tools_s2_multi.py +307 -0
  256. aiagents4pharma/talk2scholars/tests/test_tools_s2_retrieve.py +67 -0
  257. aiagents4pharma/talk2scholars/tests/test_tools_s2_search.py +286 -0
  258. aiagents4pharma/talk2scholars/tests/test_tools_s2_single.py +298 -0
  259. aiagents4pharma/talk2scholars/tests/test_utils_arxiv_downloader.py +469 -0
  260. aiagents4pharma/talk2scholars/tests/test_utils_base_paper_downloader.py +598 -0
  261. aiagents4pharma/talk2scholars/tests/test_utils_biorxiv_downloader.py +669 -0
  262. aiagents4pharma/talk2scholars/tests/test_utils_medrxiv_downloader.py +500 -0
  263. aiagents4pharma/talk2scholars/tests/test_utils_nvidia_nim_reranker.py +117 -0
  264. aiagents4pharma/talk2scholars/tests/test_utils_pdf_answer_formatter.py +67 -0
  265. aiagents4pharma/talk2scholars/tests/test_utils_pdf_batch_processor.py +92 -0
  266. aiagents4pharma/talk2scholars/tests/test_utils_pdf_collection_manager.py +173 -0
  267. aiagents4pharma/talk2scholars/tests/test_utils_pdf_document_processor.py +68 -0
  268. aiagents4pharma/talk2scholars/tests/test_utils_pdf_generate_answer.py +72 -0
  269. aiagents4pharma/talk2scholars/tests/test_utils_pdf_gpu_detection.py +129 -0
  270. aiagents4pharma/talk2scholars/tests/test_utils_pdf_paper_loader.py +116 -0
  271. aiagents4pharma/talk2scholars/tests/test_utils_pdf_rag_pipeline.py +88 -0
  272. aiagents4pharma/talk2scholars/tests/test_utils_pdf_retrieve_chunks.py +190 -0
  273. aiagents4pharma/talk2scholars/tests/test_utils_pdf_singleton_manager.py +159 -0
  274. aiagents4pharma/talk2scholars/tests/test_utils_pdf_vector_normalization.py +121 -0
  275. aiagents4pharma/talk2scholars/tests/test_utils_pdf_vector_store.py +406 -0
  276. aiagents4pharma/talk2scholars/tests/test_utils_pubmed_downloader.py +1007 -0
  277. aiagents4pharma/talk2scholars/tests/test_utils_read_helper_utils.py +106 -0
  278. aiagents4pharma/talk2scholars/tests/test_utils_s2_utils_ext_ids.py +403 -0
  279. aiagents4pharma/talk2scholars/tests/test_utils_tool_helper_utils.py +85 -0
  280. aiagents4pharma/talk2scholars/tests/test_utils_zotero_human_in_the_loop.py +266 -0
  281. aiagents4pharma/talk2scholars/tests/test_utils_zotero_path.py +496 -0
  282. aiagents4pharma/talk2scholars/tests/test_utils_zotero_pdf_downloader_utils.py +46 -0
  283. aiagents4pharma/talk2scholars/tests/test_utils_zotero_read.py +743 -0
  284. aiagents4pharma/talk2scholars/tests/test_utils_zotero_write.py +151 -0
  285. aiagents4pharma/talk2scholars/tools/__init__.py +9 -0
  286. aiagents4pharma/talk2scholars/tools/paper_download/__init__.py +12 -0
  287. aiagents4pharma/talk2scholars/tools/paper_download/paper_downloader.py +442 -0
  288. aiagents4pharma/talk2scholars/tools/paper_download/utils/__init__.py +22 -0
  289. aiagents4pharma/talk2scholars/tools/paper_download/utils/arxiv_downloader.py +207 -0
  290. aiagents4pharma/talk2scholars/tools/paper_download/utils/base_paper_downloader.py +336 -0
  291. aiagents4pharma/talk2scholars/tools/paper_download/utils/biorxiv_downloader.py +313 -0
  292. aiagents4pharma/talk2scholars/tools/paper_download/utils/medrxiv_downloader.py +196 -0
  293. aiagents4pharma/talk2scholars/tools/paper_download/utils/pubmed_downloader.py +323 -0
  294. aiagents4pharma/talk2scholars/tools/pdf/__init__.py +7 -0
  295. aiagents4pharma/talk2scholars/tools/pdf/question_and_answer.py +170 -0
  296. aiagents4pharma/talk2scholars/tools/pdf/utils/__init__.py +37 -0
  297. aiagents4pharma/talk2scholars/tools/pdf/utils/answer_formatter.py +62 -0
  298. aiagents4pharma/talk2scholars/tools/pdf/utils/batch_processor.py +198 -0
  299. aiagents4pharma/talk2scholars/tools/pdf/utils/collection_manager.py +172 -0
  300. aiagents4pharma/talk2scholars/tools/pdf/utils/document_processor.py +76 -0
  301. aiagents4pharma/talk2scholars/tools/pdf/utils/generate_answer.py +97 -0
  302. aiagents4pharma/talk2scholars/tools/pdf/utils/get_vectorstore.py +59 -0
  303. aiagents4pharma/talk2scholars/tools/pdf/utils/gpu_detection.py +150 -0
  304. aiagents4pharma/talk2scholars/tools/pdf/utils/nvidia_nim_reranker.py +97 -0
  305. aiagents4pharma/talk2scholars/tools/pdf/utils/paper_loader.py +123 -0
  306. aiagents4pharma/talk2scholars/tools/pdf/utils/rag_pipeline.py +113 -0
  307. aiagents4pharma/talk2scholars/tools/pdf/utils/retrieve_chunks.py +197 -0
  308. aiagents4pharma/talk2scholars/tools/pdf/utils/singleton_manager.py +140 -0
  309. aiagents4pharma/talk2scholars/tools/pdf/utils/tool_helper.py +86 -0
  310. aiagents4pharma/talk2scholars/tools/pdf/utils/vector_normalization.py +150 -0
  311. aiagents4pharma/talk2scholars/tools/pdf/utils/vector_store.py +327 -0
  312. aiagents4pharma/talk2scholars/tools/s2/__init__.py +21 -0
  313. aiagents4pharma/talk2scholars/tools/s2/display_dataframe.py +110 -0
  314. aiagents4pharma/talk2scholars/tools/s2/multi_paper_rec.py +111 -0
  315. aiagents4pharma/talk2scholars/tools/s2/query_dataframe.py +233 -0
  316. aiagents4pharma/talk2scholars/tools/s2/retrieve_semantic_scholar_paper_id.py +128 -0
  317. aiagents4pharma/talk2scholars/tools/s2/search.py +101 -0
  318. aiagents4pharma/talk2scholars/tools/s2/single_paper_rec.py +102 -0
  319. aiagents4pharma/talk2scholars/tools/s2/utils/__init__.py +5 -0
  320. aiagents4pharma/talk2scholars/tools/s2/utils/multi_helper.py +223 -0
  321. aiagents4pharma/talk2scholars/tools/s2/utils/search_helper.py +205 -0
  322. aiagents4pharma/talk2scholars/tools/s2/utils/single_helper.py +216 -0
  323. aiagents4pharma/talk2scholars/tools/zotero/__init__.py +7 -0
  324. aiagents4pharma/talk2scholars/tools/zotero/utils/__init__.py +7 -0
  325. aiagents4pharma/talk2scholars/tools/zotero/utils/read_helper.py +270 -0
  326. aiagents4pharma/talk2scholars/tools/zotero/utils/review_helper.py +74 -0
  327. aiagents4pharma/talk2scholars/tools/zotero/utils/write_helper.py +194 -0
  328. aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_path.py +180 -0
  329. aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_pdf_downloader.py +133 -0
  330. aiagents4pharma/talk2scholars/tools/zotero/zotero_read.py +105 -0
  331. aiagents4pharma/talk2scholars/tools/zotero/zotero_review.py +162 -0
  332. aiagents4pharma/talk2scholars/tools/zotero/zotero_write.py +91 -0
  333. aiagents4pharma-0.0.0.dist-info/METADATA +335 -0
  334. aiagents4pharma-0.0.0.dist-info/RECORD +336 -0
  335. aiagents4pharma-0.0.0.dist-info/WHEEL +4 -0
  336. aiagents4pharma-0.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,198 @@
1
+ """
2
+ Updated Unit Tests for the S2 agent (Semantic Scholar sub-agent).
3
+ """
4
+
5
+ from unittest import mock
6
+
7
+ import pytest
8
+ from langchain_core.messages import AIMessage, HumanMessage
9
+ from langchain_openai import ChatOpenAI
10
+
11
+ from ..agents.s2_agent import get_app
12
+ from ..state.state_talk2scholars import Talk2Scholars
13
+
14
+ LLM_MODEL = ChatOpenAI(model="gpt-4o-mini", temperature=0)
15
+
16
+
17
+ @pytest.fixture(autouse=True)
18
+ def mock_hydra_fixture():
19
+ """Mock Hydra configuration to prevent external dependencies."""
20
+ with mock.patch("hydra.initialize"), mock.patch("hydra.compose") as mock_compose:
21
+ cfg_mock = mock.MagicMock()
22
+ cfg_mock.agents.talk2scholars.s2_agent.temperature = 0
23
+ cfg_mock.agents.talk2scholars.s2_agent.s2_agent = "Test prompt"
24
+ mock_compose.return_value = cfg_mock
25
+ yield mock_compose
26
+
27
+
28
+ @pytest.fixture
29
+ def mock_tools_fixture():
30
+ """Mock tools to prevent execution of real API calls."""
31
+ with (
32
+ mock.patch("aiagents4pharma.talk2scholars.tools.s2.search.search_tool") as mock_s2_search,
33
+ mock.patch(
34
+ "aiagents4pharma.talk2scholars.tools.s2.display_dataframe.display_dataframe"
35
+ ) as mock_s2_display,
36
+ mock.patch(
37
+ "aiagents4pharma.talk2scholars.tools.s2.single_paper_rec."
38
+ "get_single_paper_recommendations"
39
+ ) as mock_s2_single_rec,
40
+ mock.patch(
41
+ "aiagents4pharma.talk2scholars.tools.s2.multi_paper_rec.get_multi_paper_recommendations"
42
+ ) as mock_s2_multi_rec,
43
+ mock.patch(
44
+ "aiagents4pharma.talk2scholars.tools.s2.query_dataframe.query_dataframe"
45
+ ) as mock_s2_query_dataframe,
46
+ mock.patch(
47
+ "aiagents4pharma.talk2scholars.tools.s2.retrieve_semantic_scholar_paper_id."
48
+ "retrieve_semantic_scholar_paper_id"
49
+ ) as mock_s2_retrieve_id,
50
+ ):
51
+ mock_s2_search.return_value = {"result": "Mock Search Result"}
52
+ mock_s2_display.return_value = {"result": "Mock Display Result"}
53
+ mock_s2_single_rec.return_value = {"result": "Mock Single Rec"}
54
+ mock_s2_multi_rec.return_value = {"result": "Mock Multi Rec"}
55
+ mock_s2_query_dataframe.return_value = {"result": "Mock Query Result"}
56
+ mock_s2_retrieve_id.return_value = {"paper_id": "MockPaper123"}
57
+
58
+ yield [
59
+ mock_s2_search,
60
+ mock_s2_display,
61
+ mock_s2_single_rec,
62
+ mock_s2_multi_rec,
63
+ mock_s2_query_dataframe,
64
+ mock_s2_retrieve_id,
65
+ ]
66
+
67
+
68
+ @pytest.mark.usefixtures("mock_hydra_fixture")
69
+ def test_s2_agent_initialization():
70
+ """Test that S2 agent initializes correctly with mock configuration."""
71
+ thread_id = "test_thread"
72
+ with mock.patch(
73
+ "aiagents4pharma.talk2scholars.agents.s2_agent.create_react_agent"
74
+ ) as mock_create:
75
+ mock_create.return_value = mock.Mock()
76
+ app = get_app(thread_id, llm_model=LLM_MODEL)
77
+ assert app is not None
78
+ assert mock_create.called
79
+
80
+
81
+ def test_s2_agent_invocation():
82
+ """Test that the S2 agent processes user input and returns a valid response."""
83
+ thread_id = "test_thread"
84
+ mock_state = Talk2Scholars(messages=[HumanMessage(content="Find AI papers")])
85
+ with mock.patch(
86
+ "aiagents4pharma.talk2scholars.agents.s2_agent.create_react_agent"
87
+ ) as mock_create:
88
+ mock_agent = mock.Mock()
89
+ mock_create.return_value = mock_agent
90
+ mock_agent.invoke.return_value = {
91
+ "messages": [AIMessage(content="Here are some AI papers")],
92
+ "papers": {"id123": "AI Research Paper"},
93
+ }
94
+ app = get_app(thread_id, llm_model=LLM_MODEL)
95
+ result = app.invoke(
96
+ mock_state,
97
+ config={
98
+ "configurable": {
99
+ "thread_id": thread_id,
100
+ "checkpoint_ns": "test_ns",
101
+ "checkpoint_id": "test_checkpoint",
102
+ }
103
+ },
104
+ )
105
+ assert "messages" in result
106
+ assert "papers" in result
107
+ assert result["papers"]["id123"] == "AI Research Paper"
108
+
109
+
110
+ def test_s2_agent_tools_assignment(request):
111
+ """Ensure that the correct tools are assigned to the agent."""
112
+ thread_id = "test_thread"
113
+ mock_tools = request.getfixturevalue("mock_tools_fixture")
114
+ with (
115
+ mock.patch(
116
+ "aiagents4pharma.talk2scholars.agents.s2_agent.create_react_agent"
117
+ ) as mock_create,
118
+ mock.patch("aiagents4pharma.talk2scholars.agents.s2_agent.ToolNode") as mock_toolnode,
119
+ ):
120
+ mock_agent = mock.Mock()
121
+ mock_create.return_value = mock_agent
122
+ mock_tool_instance = mock.Mock()
123
+ mock_tool_instance.tools = mock_tools
124
+ mock_toolnode.return_value = mock_tool_instance
125
+ get_app(thread_id, llm_model=LLM_MODEL)
126
+ assert mock_toolnode.called
127
+ assert len(mock_tool_instance.tools) == 6
128
+
129
+
130
+ def test_s2_query_dataframe_tool():
131
+ """Test if the query_dataframe tool is correctly utilized by the agent."""
132
+ thread_id = "test_thread"
133
+ mock_state = Talk2Scholars(messages=[HumanMessage(content="Query results for AI papers")])
134
+ with mock.patch(
135
+ "aiagents4pharma.talk2scholars.agents.s2_agent.create_react_agent"
136
+ ) as mock_create:
137
+ mock_agent = mock.Mock()
138
+ mock_create.return_value = mock_agent
139
+ mock_agent.invoke.return_value = {
140
+ "messages": [HumanMessage(content="Query results for AI papers")],
141
+ "last_displayed_papers": {},
142
+ "papers": {
143
+ "query_dataframe": "Mock Query Result"
144
+ }, # Ensure the expected key is inside 'papers'
145
+ "multi_papers": {},
146
+ }
147
+ app = get_app(thread_id, llm_model=LLM_MODEL)
148
+ result = app.invoke(
149
+ mock_state,
150
+ config={
151
+ "configurable": {
152
+ "thread_id": thread_id,
153
+ "checkpoint_ns": "test_ns",
154
+ "checkpoint_id": "test_checkpoint",
155
+ }
156
+ },
157
+ )
158
+ assert "query_dataframe" in result["papers"]
159
+ assert mock_agent.invoke.called
160
+
161
+
162
+ def test_s2_retrieve_id_tool():
163
+ """Test if the retrieve_semantic_scholar_paper_id tool is correctly utilized by the agent."""
164
+ thread_id = "test_thread"
165
+ mock_state = Talk2Scholars(messages=[HumanMessage(content="Retrieve paper ID for AI research")])
166
+ with mock.patch(
167
+ "aiagents4pharma.talk2scholars.agents.s2_agent.create_react_agent"
168
+ ) as mock_create:
169
+ mock_agent = mock.Mock()
170
+ mock_create.return_value = mock_agent
171
+ mock_agent.invoke.return_value = {
172
+ "messages": [HumanMessage(content="Retrieve paper ID for AI research")],
173
+ "last_displayed_papers": {},
174
+ "papers": {"paper_id": "MockPaper123"}, # Ensure 'paper_id' is inside 'papers'
175
+ "multi_papers": {},
176
+ }
177
+ app = get_app(thread_id, llm_model=LLM_MODEL)
178
+ result = app.invoke(
179
+ mock_state,
180
+ config={
181
+ "configurable": {
182
+ "thread_id": thread_id,
183
+ "checkpoint_ns": "test_ns",
184
+ "checkpoint_id": "test_checkpoint",
185
+ }
186
+ },
187
+ )
188
+ assert "paper_id" in result["papers"]
189
+ assert mock_agent.invoke.called
190
+
191
+
192
+ def test_s2_agent_hydra_failure():
193
+ """Test exception handling when Hydra fails to load config."""
194
+ thread_id = "test_thread"
195
+ with mock.patch("hydra.initialize", side_effect=Exception("Hydra error")):
196
+ with pytest.raises(Exception) as exc_info:
197
+ get_app(thread_id, llm_model=LLM_MODEL)
198
+ assert "Hydra error" in str(exc_info.value)
@@ -0,0 +1,160 @@
1
+ """
2
+ Updated Unit Tests for the Zotero agent (Zotero Library Managent sub-agent).
3
+ """
4
+
5
+ from unittest import mock
6
+
7
+ import pytest
8
+ from langchain_core.messages import AIMessage, HumanMessage
9
+ from langchain_openai import ChatOpenAI
10
+
11
+ from ..agents.zotero_agent import get_app
12
+ from ..state.state_talk2scholars import Talk2Scholars
13
+
14
+ LLM_MODEL = ChatOpenAI(model="gpt-4o-mini", temperature=0)
15
+
16
+
17
+ @pytest.fixture(autouse=True)
18
+ def mock_hydra_fixture():
19
+ """Mock Hydra configuration to prevent external dependencies."""
20
+ with mock.patch("hydra.initialize"), mock.patch("hydra.compose") as mock_compose:
21
+ cfg_mock = mock.MagicMock()
22
+ cfg_mock.agents.talk2scholars.zotero_agent.temperature = 0
23
+ cfg_mock.agents.talk2scholars.zotero_agent.zotero_agent = "Test prompt"
24
+ mock_compose.return_value = cfg_mock
25
+ yield mock_compose
26
+
27
+
28
+ @pytest.fixture
29
+ def mock_tools_fixture():
30
+ """Mock tools to prevent execution of real API calls."""
31
+ with (
32
+ mock.patch(
33
+ "aiagents4pharma.talk2scholars.tools.s2.display_dataframe.display_dataframe"
34
+ ) as mock_s2_display,
35
+ mock.patch(
36
+ "aiagents4pharma.talk2scholars.tools.s2.query_dataframe.query_dataframe"
37
+ ) as mock_s2_query_dataframe,
38
+ mock.patch(
39
+ "aiagents4pharma.talk2scholars.tools.s2."
40
+ "retrieve_semantic_scholar_paper_id."
41
+ "retrieve_semantic_scholar_paper_id"
42
+ ) as mock_s2_retrieve_id,
43
+ mock.patch(
44
+ "aiagents4pharma.talk2scholars.tools.zotero.zotero_read.zotero_read"
45
+ ) as mock_zotero_query_dataframe,
46
+ ):
47
+ mock_s2_display.return_value = {"result": "Mock Display Result"}
48
+ mock_s2_query_dataframe.return_value = {"result": "Mock Query Result"}
49
+ mock_s2_retrieve_id.return_value = {"paper_id": "MockPaper123"}
50
+ mock_zotero_query_dataframe.return_value = {"result": "Mock Search Result"}
51
+
52
+ yield [
53
+ mock_s2_display,
54
+ mock_s2_query_dataframe,
55
+ mock_s2_retrieve_id,
56
+ mock_zotero_query_dataframe,
57
+ ]
58
+
59
+
60
+ @pytest.mark.usefixtures("mock_hydra_fixture")
61
+ def test_zotero_agent_initialization():
62
+ """Test that S2 agent initializes correctly with mock configuration."""
63
+ thread_id = "test_thread"
64
+ with mock.patch(
65
+ "aiagents4pharma.talk2scholars.agents.zotero_agent.create_react_agent"
66
+ ) as mock_create:
67
+ mock_create.return_value = mock.Mock()
68
+ app = get_app(thread_id, llm_model=LLM_MODEL)
69
+ assert app is not None
70
+ assert mock_create.called
71
+
72
+
73
+ def test_zotero_agent_invocation():
74
+ """Test that the S2 agent processes user input and returns a valid response."""
75
+ thread_id = "test_thread"
76
+ mock_state = Talk2Scholars(messages=[HumanMessage(content="Find AI papers")])
77
+ with mock.patch(
78
+ "aiagents4pharma.talk2scholars.agents.zotero_agent.create_react_agent"
79
+ ) as mock_create:
80
+ mock_agent = mock.Mock()
81
+ mock_create.return_value = mock_agent
82
+ mock_agent.invoke.return_value = {
83
+ "messages": [AIMessage(content="Here are some AI papers")],
84
+ "papers": {"id123": "AI Research Paper"},
85
+ }
86
+ app = get_app(thread_id, llm_model=LLM_MODEL)
87
+ result = app.invoke(
88
+ mock_state,
89
+ config={
90
+ "configurable": {
91
+ "thread_id": thread_id,
92
+ "checkpoint_ns": "test_ns",
93
+ "checkpoint_id": "test_checkpoint",
94
+ }
95
+ },
96
+ )
97
+ assert "messages" in result
98
+ assert "papers" in result
99
+ assert result["papers"]["id123"] == "AI Research Paper"
100
+
101
+
102
+ def test_zotero_agent_tools_assignment(request):
103
+ """Ensure that the correct tools are assigned to the agent."""
104
+ thread_id = "test_thread"
105
+ mock_tools = request.getfixturevalue("mock_tools_fixture")
106
+ with (
107
+ mock.patch(
108
+ "aiagents4pharma.talk2scholars.agents.zotero_agent.create_react_agent"
109
+ ) as mock_create,
110
+ mock.patch("aiagents4pharma.talk2scholars.agents.zotero_agent.ToolNode") as mock_toolnode,
111
+ ):
112
+ mock_agent = mock.Mock()
113
+ mock_create.return_value = mock_agent
114
+ mock_tool_instance = mock.Mock()
115
+ mock_tool_instance.tools = mock_tools
116
+ mock_toolnode.return_value = mock_tool_instance
117
+ get_app(thread_id, llm_model=LLM_MODEL)
118
+ assert mock_toolnode.called
119
+ assert len(mock_tool_instance.tools) == 4
120
+
121
+
122
+ def test_s2_query_dataframe_tool():
123
+ """Test if the query_dataframe tool is correctly utilized by the agent."""
124
+ thread_id = "test_thread"
125
+ mock_state = Talk2Scholars(messages=[HumanMessage(content="Query results for AI papers")])
126
+ with mock.patch(
127
+ "aiagents4pharma.talk2scholars.agents.zotero_agent.create_react_agent"
128
+ ) as mock_create:
129
+ mock_agent = mock.Mock()
130
+ mock_create.return_value = mock_agent
131
+ mock_agent.invoke.return_value = {
132
+ "messages": [HumanMessage(content="Query results for AI papers")],
133
+ "last_displayed_papers": {},
134
+ "papers": {
135
+ "query_dataframe": "Mock Query Result"
136
+ }, # Ensure the expected key is inside 'papers'
137
+ "multi_papers": {},
138
+ }
139
+ app = get_app(thread_id, llm_model=LLM_MODEL)
140
+ result = app.invoke(
141
+ mock_state,
142
+ config={
143
+ "configurable": {
144
+ "thread_id": thread_id,
145
+ "checkpoint_ns": "test_ns",
146
+ "checkpoint_id": "test_checkpoint",
147
+ }
148
+ },
149
+ )
150
+ assert "query_dataframe" in result["papers"]
151
+ assert mock_agent.invoke.called
152
+
153
+
154
+ def test_zotero_agent_hydra_failure():
155
+ """Test exception handling when Hydra fails to load config."""
156
+ thread_id = "test_thread"
157
+ with mock.patch("hydra.initialize", side_effect=Exception("Hydra error")):
158
+ with pytest.raises(Exception) as exc_info:
159
+ get_app(thread_id, llm_model=LLM_MODEL)
160
+ assert "Hydra error" in str(exc_info.value)
@@ -0,0 +1,91 @@
1
+ """
2
+ Unit tests for S2 tools functionality.
3
+ """
4
+
5
+ import pytest
6
+ from langgraph.types import Command
7
+
8
+ from ..tools.s2.display_dataframe import (
9
+ NoPapersFoundError as raised_error,
10
+ )
11
+ from ..tools.s2.display_dataframe import (
12
+ display_dataframe,
13
+ )
14
+
15
+
16
+ @pytest.fixture(name="initial_state")
17
+ def initial_state_fixture():
18
+ """Provides an empty initial state for tests."""
19
+ return {"papers": {}, "multi_papers": {}}
20
+
21
+
22
+ # Fixed test data for deterministic results
23
+ MOCK_SEARCH_RESPONSE = {
24
+ "data": [
25
+ {
26
+ "paperId": "123",
27
+ "title": "Machine Learning Basics",
28
+ "abstract": "An introduction to ML",
29
+ "year": 2023,
30
+ "citationCount": 100,
31
+ "url": "https://example.com/paper1",
32
+ "authors": [{"name": "Test Author"}],
33
+ }
34
+ ]
35
+ }
36
+
37
+ MOCK_STATE_PAPER = {
38
+ "123": {
39
+ "Title": "Machine Learning Basics",
40
+ "Abstract": "An introduction to ML",
41
+ "Year": 2023,
42
+ "Citation Count": 100,
43
+ "URL": "https://example.com/paper1",
44
+ }
45
+ }
46
+
47
+
48
+ class TestS2Tools:
49
+ """Unit tests for individual S2 tools"""
50
+
51
+ def test_display_dataframe_empty_state(self, initial_state):
52
+ """Verifies display_dataframe tool behavior when state is empty and raises an exception"""
53
+ with pytest.raises(
54
+ raised_error,
55
+ match="No papers found. A search/rec needs to be performed first.",
56
+ ):
57
+ display_dataframe.invoke({"state": initial_state, "tool_call_id": "test123"})
58
+
59
+ def test_display_dataframe_shows_papers(self, initial_state):
60
+ """Verifies display_dataframe tool correctly returns papers from state"""
61
+ state = initial_state.copy()
62
+ state["last_displayed_papers"] = "papers"
63
+ state["papers"] = MOCK_STATE_PAPER
64
+
65
+ result = display_dataframe.invoke(input={"state": state, "tool_call_id": "test123"})
66
+
67
+ assert isinstance(result, Command) # Expect a Command object
68
+ assert isinstance(result.update, dict) # Ensure update is a dictionary
69
+ assert "messages" in result.update
70
+ assert len(result.update["messages"]) == 1
71
+ assert (
72
+ "1 papers found. Papers are attached as an artifact."
73
+ in result.update["messages"][0].content
74
+ )
75
+
76
+ def test_display_dataframe_direct_mapping(self, initial_state):
77
+ """Verifies display_dataframe handles direct dict mapping in last_displayed_papers."""
78
+ # Prepare state with direct mapping of papers
79
+ state = initial_state.copy()
80
+ state["last_displayed_papers"] = MOCK_STATE_PAPER
81
+ # Invoke display tool
82
+ result = display_dataframe.invoke({"state": state, "tool_call_id": "test123"})
83
+ assert isinstance(result, Command)
84
+ update = result.update
85
+ # Artifact should be the direct mapping
86
+ messages = update.get("messages", [])
87
+ assert len(messages) == 1
88
+ artifact = messages[0].artifact
89
+ assert artifact == MOCK_STATE_PAPER
90
+ # Content count should match mapping length
91
+ assert "1 papers found" in messages[0].content
@@ -0,0 +1,191 @@
1
+ """
2
+ Unit tests for S2 tools functionality.
3
+ """
4
+
5
+ from unittest.mock import MagicMock, patch
6
+
7
+ import pytest
8
+ from langchain_core.messages import ToolMessage
9
+
10
+ from ..tools.s2.query_dataframe import NoPapersFoundError, query_dataframe
11
+
12
+
13
+ @pytest.fixture(name="initial_state")
14
+ def initial_state_fixture():
15
+ """Provides an empty initial state for tests with a dummy llm_model."""
16
+ return {"papers": {}, "multi_papers": {}, "llm_model": MagicMock()}
17
+
18
+
19
+ # Fixed test data for deterministic results
20
+ MOCK_SEARCH_RESPONSE = {
21
+ "data": [
22
+ {
23
+ "paperId": "123",
24
+ "title": "Machine Learning Basics",
25
+ "abstract": "An introduction to ML",
26
+ "year": 2023,
27
+ "citationCount": 100,
28
+ "url": "https://example.com/paper1",
29
+ "authors": [{"name": "Test Author"}],
30
+ }
31
+ ]
32
+ }
33
+
34
+ MOCK_STATE_PAPER = {
35
+ "123": {
36
+ "Title": "Machine Learning Basics",
37
+ "Abstract": "An introduction to ML",
38
+ "Year": 2023,
39
+ "Citation Count": 100,
40
+ "URL": "https://example.com/paper1",
41
+ }
42
+ }
43
+
44
+
45
+ class TestS2Tools:
46
+ """Unit tests for individual S2 tools"""
47
+
48
+ def test_query_dataframe_empty_state(self, initial_state):
49
+ """Tests query_dataframe tool behavior when no papers are found."""
50
+ # Calling without any papers should raise NoPapersFoundError
51
+ tool_input = {
52
+ "question": "List all papers",
53
+ "state": initial_state,
54
+ "tool_call_id": "test_id",
55
+ }
56
+ with pytest.raises(
57
+ NoPapersFoundError,
58
+ match="No papers found. A search needs to be performed first.",
59
+ ):
60
+ query_dataframe.run(tool_input)
61
+
62
+ @patch("aiagents4pharma.talk2scholars.tools.s2.query_dataframe.create_pandas_dataframe_agent")
63
+ def test_query_dataframe_with_papers(self, mock_create_agent, initial_state):
64
+ """Tests querying papers when data is available."""
65
+ state = initial_state.copy()
66
+ state["last_displayed_papers"] = "papers"
67
+ state["papers"] = MOCK_STATE_PAPER
68
+
69
+ # Mock the dataframe agent instead of the LLM
70
+ mock_agent = MagicMock()
71
+ mock_agent.invoke.return_value = {"output": "Mocked response"}
72
+
73
+ mock_create_agent.return_value = mock_agent # Mock the function returning the agent
74
+
75
+ # Ensure that the output of query_dataframe is correctly structured
76
+ # Invoke the tool with a test tool_call_id
77
+ tool_input = {
78
+ "question": "List all papers",
79
+ "state": state,
80
+ "tool_call_id": "test_id",
81
+ }
82
+ result = query_dataframe.run(tool_input)
83
+ # The tool returns a Command with messages
84
+ assert hasattr(result, "update")
85
+ update = result.update
86
+ assert "messages" in update
87
+ msgs = update["messages"]
88
+ assert len(msgs) == 1
89
+ msg = msgs[0]
90
+ assert isinstance(msg, ToolMessage)
91
+ assert msg.content == "Mocked response"
92
+
93
+ @patch("aiagents4pharma.talk2scholars.tools.s2.query_dataframe.create_pandas_dataframe_agent")
94
+ def test_query_dataframe_direct_mapping(self, mock_create_agent, initial_state):
95
+ """Tests query_dataframe when last_displayed_papers is a direct dict mapping."""
96
+ # Prepare state with direct mapping
97
+ state = initial_state.copy()
98
+ state["last_displayed_papers"] = MOCK_STATE_PAPER
99
+ # Mock the dataframe agent
100
+ mock_agent = MagicMock()
101
+ mock_agent.invoke.return_value = {"output": "Direct mapping response"}
102
+ mock_create_agent.return_value = mock_agent
103
+ # Invoke tool
104
+ # Invoke the tool with direct mapping and test tool_call_id
105
+ tool_input = {
106
+ "question": "Filter papers",
107
+ "state": state,
108
+ "tool_call_id": "test_id",
109
+ }
110
+ result = query_dataframe.run(tool_input)
111
+ update = result.update
112
+ assert "messages" in update
113
+ msgs = update["messages"]
114
+ assert len(msgs) == 1
115
+ msg = msgs[0]
116
+ assert isinstance(msg, ToolMessage)
117
+ assert msg.content == "Direct mapping response"
118
+
119
+ def test_query_dataframe_missing_llm(self, initial_state):
120
+ """Test that missing llm_model raises ValueError."""
121
+ # Remove llm_model
122
+ state = {k: v for k, v in initial_state.items() if k != "llm_model"}
123
+ state["last_displayed_papers"] = MOCK_STATE_PAPER
124
+ tool_input = {"question": "Test", "state": state, "tool_call_id": "test_id"}
125
+ with pytest.raises(ValueError) as exc:
126
+ query_dataframe.run(tool_input)
127
+ assert "Missing 'llm_model' in state." in str(exc.value)
128
+
129
+ def test_query_dataframe_invalid_mapping(self, initial_state):
130
+ """Test that invalid last_displayed_papers mapping raises ValueError."""
131
+ # Provide invalid mapping key
132
+ state = initial_state.copy()
133
+ state["last_displayed_papers"] = "nonexistent_key"
134
+ # llm_model present
135
+ tool_input = {"question": "Test", "state": state, "tool_call_id": "test_id"}
136
+ with pytest.raises(ValueError) as exc:
137
+ query_dataframe.run(tool_input)
138
+ assert "Could not resolve a valid metadata dictionary" in str(exc.value)
139
+
140
+ @patch("aiagents4pharma.talk2scholars.tools.s2.query_dataframe.create_pandas_dataframe_agent")
141
+ def test_query_dataframe_extract_ids(self, mock_create_agent):
142
+ """Test extract_ids returns the raw list or single element correctly."""
143
+ # Prepare state with fake paper_ids column
144
+ state = {"llm_model": MagicMock()}
145
+ state_key = "papers"
146
+ dic = {
147
+ "p1": {"paper_ids": ["id1", "id2"]},
148
+ "p2": {"paper_ids": ["id3"]},
149
+ }
150
+ state["last_displayed_papers"] = dic
151
+ state[state_key] = dic # simulate indirect mapping
152
+ # Mock agent to echo the Python expression
153
+ mock_agent = MagicMock()
154
+ mock_agent.invoke.side_effect = lambda args, stream_mode=None: {"output": args["input"]}
155
+ mock_create_agent.return_value = mock_agent
156
+ # Test full list
157
+ tool_input = {
158
+ "question": "",
159
+ "state": state,
160
+ "tool_call_id": "tid",
161
+ "extract_ids": True,
162
+ "id_column": "paper_ids",
163
+ }
164
+ result = query_dataframe.run(tool_input)
165
+ output = result.update["messages"][0].content
166
+ # Should be the base list expression
167
+ expected = "df['paper_ids'].dropna().str[0].tolist()"
168
+ assert output == expected
169
+ # Test single element
170
+ tool_input["row_number"] = 2
171
+ result2 = query_dataframe.run(tool_input)
172
+ output2 = result2.update["messages"][0].content
173
+ expected2 = "df['paper_ids'].dropna().str[0].tolist()[1]"
174
+ assert output2 == expected2
175
+
176
+ def test_query_dataframe_extract_ids_missing_column(self, initial_state):
177
+ """Test that missing id_column raises ValueError when extract_ids=True."""
178
+ state = initial_state.copy()
179
+ state["last_displayed_papers"] = {"p1": {"paper_ids": ["id1"]}}
180
+ state["papers"] = state["last_displayed_papers"]
181
+ with pytest.raises(ValueError) as exc:
182
+ query_dataframe.run(
183
+ {
184
+ "question": "",
185
+ "state": state,
186
+ "tool_call_id": "tid",
187
+ "extract_ids": True,
188
+ "id_column": "",
189
+ }
190
+ )
191
+ assert "Must specify 'id_column' when extract_ids=True." in str(exc.value)
@@ -0,0 +1,38 @@
1
+ """
2
+ Tests for state management functionality.
3
+ """
4
+
5
+ from ..state.state_talk2scholars import merge_dict, replace_dict
6
+
7
+
8
+ def test_state_replace_dict():
9
+ """Verifies state dictionary replacement works correctly"""
10
+ existing = {"key1": "value1", "key2": "value2"}
11
+ new = {"key3": "value3"}
12
+ result = replace_dict(existing, new)
13
+ assert result == new
14
+ assert isinstance(result, dict)
15
+
16
+
17
+ def test_state_merge_dict():
18
+ """Verifies state dictionary merging works correctly"""
19
+ existing = {"a": 1, "b": 2}
20
+ new = {"b": 3, "c": 4}
21
+ result = merge_dict(existing, new)
22
+ # result should contain merged keys, with new values overriding existing ones
23
+ assert result == {"a": 1, "b": 3, "c": 4}
24
+ assert isinstance(result, dict)
25
+ # original existing dict should be unchanged
26
+ assert existing == {"a": 1, "b": 2}
27
+
28
+
29
+ def test_replace_dict_non_mapping():
30
+ """Verifies replace_dict returns non-mapping values directly"""
31
+
32
+ existing = {"key": "value"}
33
+ # When new is not a dict, replace_dict should return new value unchanged
34
+ new_value = "not_a_dict"
35
+ result = replace_dict(existing, new_value)
36
+ assert result == new_value
37
+ # existing should remain unmodified when returning new directly
38
+ assert existing == {"key": "value"}