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.
- aiagents4pharma/__init__.py +11 -0
- aiagents4pharma/talk2aiagents4pharma/.dockerignore +13 -0
- aiagents4pharma/talk2aiagents4pharma/Dockerfile +133 -0
- aiagents4pharma/talk2aiagents4pharma/README.md +1 -0
- aiagents4pharma/talk2aiagents4pharma/__init__.py +5 -0
- aiagents4pharma/talk2aiagents4pharma/agents/__init__.py +6 -0
- aiagents4pharma/talk2aiagents4pharma/agents/main_agent.py +70 -0
- aiagents4pharma/talk2aiagents4pharma/configs/__init__.py +5 -0
- aiagents4pharma/talk2aiagents4pharma/configs/agents/__init__.py +5 -0
- aiagents4pharma/talk2aiagents4pharma/configs/agents/main_agent/default.yaml +29 -0
- aiagents4pharma/talk2aiagents4pharma/configs/app/__init__.py +0 -0
- aiagents4pharma/talk2aiagents4pharma/configs/app/frontend/__init__.py +0 -0
- aiagents4pharma/talk2aiagents4pharma/configs/app/frontend/default.yaml +102 -0
- aiagents4pharma/talk2aiagents4pharma/configs/config.yaml +4 -0
- aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/.env.example +23 -0
- aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/docker-compose.yml +93 -0
- aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/.env.example +23 -0
- aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/docker-compose.yml +108 -0
- aiagents4pharma/talk2aiagents4pharma/install.md +154 -0
- aiagents4pharma/talk2aiagents4pharma/states/__init__.py +5 -0
- aiagents4pharma/talk2aiagents4pharma/states/state_talk2aiagents4pharma.py +18 -0
- aiagents4pharma/talk2aiagents4pharma/tests/__init__.py +3 -0
- aiagents4pharma/talk2aiagents4pharma/tests/test_main_agent.py +312 -0
- aiagents4pharma/talk2biomodels/.dockerignore +13 -0
- aiagents4pharma/talk2biomodels/Dockerfile +104 -0
- aiagents4pharma/talk2biomodels/README.md +1 -0
- aiagents4pharma/talk2biomodels/__init__.py +5 -0
- aiagents4pharma/talk2biomodels/agents/__init__.py +6 -0
- aiagents4pharma/talk2biomodels/agents/t2b_agent.py +104 -0
- aiagents4pharma/talk2biomodels/api/__init__.py +5 -0
- aiagents4pharma/talk2biomodels/api/ols.py +75 -0
- aiagents4pharma/talk2biomodels/api/uniprot.py +36 -0
- aiagents4pharma/talk2biomodels/configs/__init__.py +5 -0
- aiagents4pharma/talk2biomodels/configs/agents/__init__.py +5 -0
- aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/__init__.py +3 -0
- aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/default.yaml +14 -0
- aiagents4pharma/talk2biomodels/configs/app/__init__.py +0 -0
- aiagents4pharma/talk2biomodels/configs/app/frontend/__init__.py +0 -0
- aiagents4pharma/talk2biomodels/configs/app/frontend/default.yaml +72 -0
- aiagents4pharma/talk2biomodels/configs/config.yaml +7 -0
- aiagents4pharma/talk2biomodels/configs/tools/__init__.py +5 -0
- aiagents4pharma/talk2biomodels/configs/tools/ask_question/__init__.py +3 -0
- aiagents4pharma/talk2biomodels/configs/tools/ask_question/default.yaml +30 -0
- aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/__init__.py +3 -0
- aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/default.yaml +8 -0
- aiagents4pharma/talk2biomodels/configs/tools/get_annotation/__init__.py +3 -0
- aiagents4pharma/talk2biomodels/configs/tools/get_annotation/default.yaml +8 -0
- aiagents4pharma/talk2biomodels/install.md +63 -0
- aiagents4pharma/talk2biomodels/models/__init__.py +5 -0
- aiagents4pharma/talk2biomodels/models/basico_model.py +125 -0
- aiagents4pharma/talk2biomodels/models/sys_bio_model.py +60 -0
- aiagents4pharma/talk2biomodels/states/__init__.py +6 -0
- aiagents4pharma/talk2biomodels/states/state_talk2biomodels.py +49 -0
- aiagents4pharma/talk2biomodels/tests/BIOMD0000000449_url.xml +1585 -0
- aiagents4pharma/talk2biomodels/tests/__init__.py +3 -0
- aiagents4pharma/talk2biomodels/tests/article_on_model_537.pdf +0 -0
- aiagents4pharma/talk2biomodels/tests/test_api.py +31 -0
- aiagents4pharma/talk2biomodels/tests/test_ask_question.py +42 -0
- aiagents4pharma/talk2biomodels/tests/test_basico_model.py +67 -0
- aiagents4pharma/talk2biomodels/tests/test_get_annotation.py +190 -0
- aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py +92 -0
- aiagents4pharma/talk2biomodels/tests/test_integration.py +116 -0
- aiagents4pharma/talk2biomodels/tests/test_load_biomodel.py +35 -0
- aiagents4pharma/talk2biomodels/tests/test_param_scan.py +71 -0
- aiagents4pharma/talk2biomodels/tests/test_query_article.py +184 -0
- aiagents4pharma/talk2biomodels/tests/test_save_model.py +47 -0
- aiagents4pharma/talk2biomodels/tests/test_search_models.py +35 -0
- aiagents4pharma/talk2biomodels/tests/test_simulate_model.py +44 -0
- aiagents4pharma/talk2biomodels/tests/test_steady_state.py +86 -0
- aiagents4pharma/talk2biomodels/tests/test_sys_bio_model.py +67 -0
- aiagents4pharma/talk2biomodels/tools/__init__.py +17 -0
- aiagents4pharma/talk2biomodels/tools/ask_question.py +125 -0
- aiagents4pharma/talk2biomodels/tools/custom_plotter.py +165 -0
- aiagents4pharma/talk2biomodels/tools/get_annotation.py +342 -0
- aiagents4pharma/talk2biomodels/tools/get_modelinfo.py +159 -0
- aiagents4pharma/talk2biomodels/tools/load_arguments.py +134 -0
- aiagents4pharma/talk2biomodels/tools/load_biomodel.py +44 -0
- aiagents4pharma/talk2biomodels/tools/parameter_scan.py +310 -0
- aiagents4pharma/talk2biomodels/tools/query_article.py +64 -0
- aiagents4pharma/talk2biomodels/tools/save_model.py +98 -0
- aiagents4pharma/talk2biomodels/tools/search_models.py +96 -0
- aiagents4pharma/talk2biomodels/tools/simulate_model.py +137 -0
- aiagents4pharma/talk2biomodels/tools/steady_state.py +187 -0
- aiagents4pharma/talk2biomodels/tools/utils.py +23 -0
- aiagents4pharma/talk2cells/README.md +1 -0
- aiagents4pharma/talk2cells/__init__.py +5 -0
- aiagents4pharma/talk2cells/agents/__init__.py +6 -0
- aiagents4pharma/talk2cells/agents/scp_agent.py +87 -0
- aiagents4pharma/talk2cells/states/__init__.py +6 -0
- aiagents4pharma/talk2cells/states/state_talk2cells.py +15 -0
- aiagents4pharma/talk2cells/tests/scp_agent/test_scp_agent.py +22 -0
- aiagents4pharma/talk2cells/tools/__init__.py +6 -0
- aiagents4pharma/talk2cells/tools/scp_agent/__init__.py +6 -0
- aiagents4pharma/talk2cells/tools/scp_agent/display_studies.py +27 -0
- aiagents4pharma/talk2cells/tools/scp_agent/search_studies.py +78 -0
- aiagents4pharma/talk2knowledgegraphs/.dockerignore +13 -0
- aiagents4pharma/talk2knowledgegraphs/Dockerfile +131 -0
- aiagents4pharma/talk2knowledgegraphs/README.md +1 -0
- aiagents4pharma/talk2knowledgegraphs/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/agents/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/agents/t2kg_agent.py +99 -0
- aiagents4pharma/talk2knowledgegraphs/configs/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/__init__.py +3 -0
- aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/default.yaml +62 -0
- aiagents4pharma/talk2knowledgegraphs/configs/app/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/__init__.py +3 -0
- aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/default.yaml +79 -0
- aiagents4pharma/talk2knowledgegraphs/configs/config.yaml +13 -0
- aiagents4pharma/talk2knowledgegraphs/configs/tools/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/__init__.py +3 -0
- aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/default.yaml +24 -0
- aiagents4pharma/talk2knowledgegraphs/configs/tools/multimodal_subgraph_extraction/__init__.py +0 -0
- aiagents4pharma/talk2knowledgegraphs/configs/tools/multimodal_subgraph_extraction/default.yaml +33 -0
- aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/__init__.py +3 -0
- aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/default.yaml +43 -0
- aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/__init__.py +3 -0
- aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/default.yaml +9 -0
- aiagents4pharma/talk2knowledgegraphs/configs/utils/database/milvus/__init__.py +3 -0
- aiagents4pharma/talk2knowledgegraphs/configs/utils/database/milvus/default.yaml +61 -0
- aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/ols_terms/default.yaml +3 -0
- aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/reactome_pathways/default.yaml +3 -0
- aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/uniprot_proteins/default.yaml +6 -0
- aiagents4pharma/talk2knowledgegraphs/configs/utils/pubchem_utils/default.yaml +5 -0
- aiagents4pharma/talk2knowledgegraphs/datasets/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/datasets/biobridge_primekg.py +607 -0
- aiagents4pharma/talk2knowledgegraphs/datasets/dataset.py +25 -0
- aiagents4pharma/talk2knowledgegraphs/datasets/primekg.py +212 -0
- aiagents4pharma/talk2knowledgegraphs/datasets/starkqa_primekg.py +210 -0
- aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/.env.example +23 -0
- aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/docker-compose.yml +93 -0
- aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/.env.example +23 -0
- aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/docker-compose.yml +108 -0
- aiagents4pharma/talk2knowledgegraphs/entrypoint.sh +180 -0
- aiagents4pharma/talk2knowledgegraphs/install.md +165 -0
- aiagents4pharma/talk2knowledgegraphs/milvus_data_dump.py +886 -0
- aiagents4pharma/talk2knowledgegraphs/states/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/states/state_talk2knowledgegraphs.py +40 -0
- aiagents4pharma/talk2knowledgegraphs/tests/__init__.py +0 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_agents_t2kg_agent.py +318 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_biobridge_primekg.py +248 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_dataset.py +33 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_primekg.py +86 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_starkqa_primekg.py +125 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_graphrag_reasoning.py +257 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_milvus_multimodal_subgraph_extraction.py +1444 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_multimodal_subgraph_extraction.py +159 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_extraction.py +152 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_summarization.py +201 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_database_milvus_connection_manager.py +812 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_embeddings.py +51 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_huggingface.py +49 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_nim_molmim.py +59 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_ollama.py +63 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_sentencetransformer.py +47 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_enrichments.py +40 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ollama.py +94 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ols.py +70 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_pubchem.py +45 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_reactome.py +44 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_uniprot.py +48 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_extractions_milvus_multimodal_pcst.py +759 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_kg_utils.py +78 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_pubchem_utils.py +123 -0
- aiagents4pharma/talk2knowledgegraphs/tools/__init__.py +11 -0
- aiagents4pharma/talk2knowledgegraphs/tools/graphrag_reasoning.py +138 -0
- aiagents4pharma/talk2knowledgegraphs/tools/load_arguments.py +22 -0
- aiagents4pharma/talk2knowledgegraphs/tools/milvus_multimodal_subgraph_extraction.py +965 -0
- aiagents4pharma/talk2knowledgegraphs/tools/multimodal_subgraph_extraction.py +374 -0
- aiagents4pharma/talk2knowledgegraphs/tools/subgraph_extraction.py +291 -0
- aiagents4pharma/talk2knowledgegraphs/tools/subgraph_summarization.py +123 -0
- aiagents4pharma/talk2knowledgegraphs/utils/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/utils/database/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/utils/database/milvus_connection_manager.py +586 -0
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/embeddings.py +81 -0
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/huggingface.py +111 -0
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/nim_molmim.py +54 -0
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/ollama.py +87 -0
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/sentence_transformer.py +73 -0
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/__init__.py +12 -0
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/enrichments.py +37 -0
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ollama.py +129 -0
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ols_terms.py +89 -0
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/pubchem_strings.py +78 -0
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/reactome_pathways.py +71 -0
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/uniprot_proteins.py +98 -0
- aiagents4pharma/talk2knowledgegraphs/utils/extractions/__init__.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/utils/extractions/milvus_multimodal_pcst.py +762 -0
- aiagents4pharma/talk2knowledgegraphs/utils/extractions/multimodal_pcst.py +298 -0
- aiagents4pharma/talk2knowledgegraphs/utils/extractions/pcst.py +229 -0
- aiagents4pharma/talk2knowledgegraphs/utils/kg_utils.py +67 -0
- aiagents4pharma/talk2knowledgegraphs/utils/pubchem_utils.py +104 -0
- aiagents4pharma/talk2scholars/.dockerignore +13 -0
- aiagents4pharma/talk2scholars/Dockerfile +104 -0
- aiagents4pharma/talk2scholars/README.md +1 -0
- aiagents4pharma/talk2scholars/__init__.py +7 -0
- aiagents4pharma/talk2scholars/agents/__init__.py +13 -0
- aiagents4pharma/talk2scholars/agents/main_agent.py +89 -0
- aiagents4pharma/talk2scholars/agents/paper_download_agent.py +96 -0
- aiagents4pharma/talk2scholars/agents/pdf_agent.py +101 -0
- aiagents4pharma/talk2scholars/agents/s2_agent.py +135 -0
- aiagents4pharma/talk2scholars/agents/zotero_agent.py +127 -0
- aiagents4pharma/talk2scholars/configs/__init__.py +7 -0
- aiagents4pharma/talk2scholars/configs/agents/__init__.py +7 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/__init__.py +7 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/main_agent/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/main_agent/default.yaml +52 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/paper_download_agent/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/paper_download_agent/default.yaml +19 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/pdf_agent/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/pdf_agent/default.yaml +19 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/s2_agent/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/s2_agent/default.yaml +44 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/zotero_agent/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/zotero_agent/default.yaml +19 -0
- aiagents4pharma/talk2scholars/configs/app/__init__.py +7 -0
- aiagents4pharma/talk2scholars/configs/app/frontend/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/app/frontend/default.yaml +72 -0
- aiagents4pharma/talk2scholars/configs/config.yaml +16 -0
- aiagents4pharma/talk2scholars/configs/tools/__init__.py +21 -0
- aiagents4pharma/talk2scholars/configs/tools/multi_paper_recommendation/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/tools/multi_paper_recommendation/default.yaml +26 -0
- aiagents4pharma/talk2scholars/configs/tools/paper_download/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/tools/paper_download/default.yaml +124 -0
- aiagents4pharma/talk2scholars/configs/tools/question_and_answer/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/tools/question_and_answer/default.yaml +62 -0
- aiagents4pharma/talk2scholars/configs/tools/retrieve_semantic_scholar_paper_id/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/tools/retrieve_semantic_scholar_paper_id/default.yaml +12 -0
- aiagents4pharma/talk2scholars/configs/tools/search/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/tools/search/default.yaml +26 -0
- aiagents4pharma/talk2scholars/configs/tools/single_paper_recommendation/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/tools/single_paper_recommendation/default.yaml +26 -0
- aiagents4pharma/talk2scholars/configs/tools/zotero_read/__init__.py +3 -0
- aiagents4pharma/talk2scholars/configs/tools/zotero_read/default.yaml +57 -0
- aiagents4pharma/talk2scholars/configs/tools/zotero_write/__inti__.py +3 -0
- aiagents4pharma/talk2scholars/configs/tools/zotero_write/default.yaml +55 -0
- aiagents4pharma/talk2scholars/docker-compose/cpu/.env.example +21 -0
- aiagents4pharma/talk2scholars/docker-compose/cpu/docker-compose.yml +90 -0
- aiagents4pharma/talk2scholars/docker-compose/gpu/.env.example +21 -0
- aiagents4pharma/talk2scholars/docker-compose/gpu/docker-compose.yml +105 -0
- aiagents4pharma/talk2scholars/install.md +122 -0
- aiagents4pharma/talk2scholars/state/__init__.py +7 -0
- aiagents4pharma/talk2scholars/state/state_talk2scholars.py +98 -0
- aiagents4pharma/talk2scholars/tests/__init__.py +3 -0
- aiagents4pharma/talk2scholars/tests/test_agents_main_agent.py +256 -0
- aiagents4pharma/talk2scholars/tests/test_agents_paper_agents_download_agent.py +139 -0
- aiagents4pharma/talk2scholars/tests/test_agents_pdf_agent.py +114 -0
- aiagents4pharma/talk2scholars/tests/test_agents_s2_agent.py +198 -0
- aiagents4pharma/talk2scholars/tests/test_agents_zotero_agent.py +160 -0
- aiagents4pharma/talk2scholars/tests/test_s2_tools_display_dataframe.py +91 -0
- aiagents4pharma/talk2scholars/tests/test_s2_tools_query_dataframe.py +191 -0
- aiagents4pharma/talk2scholars/tests/test_states_state.py +38 -0
- aiagents4pharma/talk2scholars/tests/test_tools_paper_downloader.py +507 -0
- aiagents4pharma/talk2scholars/tests/test_tools_question_and_answer_tool.py +105 -0
- aiagents4pharma/talk2scholars/tests/test_tools_s2_multi.py +307 -0
- aiagents4pharma/talk2scholars/tests/test_tools_s2_retrieve.py +67 -0
- aiagents4pharma/talk2scholars/tests/test_tools_s2_search.py +286 -0
- aiagents4pharma/talk2scholars/tests/test_tools_s2_single.py +298 -0
- aiagents4pharma/talk2scholars/tests/test_utils_arxiv_downloader.py +469 -0
- aiagents4pharma/talk2scholars/tests/test_utils_base_paper_downloader.py +598 -0
- aiagents4pharma/talk2scholars/tests/test_utils_biorxiv_downloader.py +669 -0
- aiagents4pharma/talk2scholars/tests/test_utils_medrxiv_downloader.py +500 -0
- aiagents4pharma/talk2scholars/tests/test_utils_nvidia_nim_reranker.py +117 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_answer_formatter.py +67 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_batch_processor.py +92 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_collection_manager.py +173 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_document_processor.py +68 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_generate_answer.py +72 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_gpu_detection.py +129 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_paper_loader.py +116 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_rag_pipeline.py +88 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_retrieve_chunks.py +190 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_singleton_manager.py +159 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_vector_normalization.py +121 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pdf_vector_store.py +406 -0
- aiagents4pharma/talk2scholars/tests/test_utils_pubmed_downloader.py +1007 -0
- aiagents4pharma/talk2scholars/tests/test_utils_read_helper_utils.py +106 -0
- aiagents4pharma/talk2scholars/tests/test_utils_s2_utils_ext_ids.py +403 -0
- aiagents4pharma/talk2scholars/tests/test_utils_tool_helper_utils.py +85 -0
- aiagents4pharma/talk2scholars/tests/test_utils_zotero_human_in_the_loop.py +266 -0
- aiagents4pharma/talk2scholars/tests/test_utils_zotero_path.py +496 -0
- aiagents4pharma/talk2scholars/tests/test_utils_zotero_pdf_downloader_utils.py +46 -0
- aiagents4pharma/talk2scholars/tests/test_utils_zotero_read.py +743 -0
- aiagents4pharma/talk2scholars/tests/test_utils_zotero_write.py +151 -0
- aiagents4pharma/talk2scholars/tools/__init__.py +9 -0
- aiagents4pharma/talk2scholars/tools/paper_download/__init__.py +12 -0
- aiagents4pharma/talk2scholars/tools/paper_download/paper_downloader.py +442 -0
- aiagents4pharma/talk2scholars/tools/paper_download/utils/__init__.py +22 -0
- aiagents4pharma/talk2scholars/tools/paper_download/utils/arxiv_downloader.py +207 -0
- aiagents4pharma/talk2scholars/tools/paper_download/utils/base_paper_downloader.py +336 -0
- aiagents4pharma/talk2scholars/tools/paper_download/utils/biorxiv_downloader.py +313 -0
- aiagents4pharma/talk2scholars/tools/paper_download/utils/medrxiv_downloader.py +196 -0
- aiagents4pharma/talk2scholars/tools/paper_download/utils/pubmed_downloader.py +323 -0
- aiagents4pharma/talk2scholars/tools/pdf/__init__.py +7 -0
- aiagents4pharma/talk2scholars/tools/pdf/question_and_answer.py +170 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/__init__.py +37 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/answer_formatter.py +62 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/batch_processor.py +198 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/collection_manager.py +172 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/document_processor.py +76 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/generate_answer.py +97 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/get_vectorstore.py +59 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/gpu_detection.py +150 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/nvidia_nim_reranker.py +97 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/paper_loader.py +123 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/rag_pipeline.py +113 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/retrieve_chunks.py +197 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/singleton_manager.py +140 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/tool_helper.py +86 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/vector_normalization.py +150 -0
- aiagents4pharma/talk2scholars/tools/pdf/utils/vector_store.py +327 -0
- aiagents4pharma/talk2scholars/tools/s2/__init__.py +21 -0
- aiagents4pharma/talk2scholars/tools/s2/display_dataframe.py +110 -0
- aiagents4pharma/talk2scholars/tools/s2/multi_paper_rec.py +111 -0
- aiagents4pharma/talk2scholars/tools/s2/query_dataframe.py +233 -0
- aiagents4pharma/talk2scholars/tools/s2/retrieve_semantic_scholar_paper_id.py +128 -0
- aiagents4pharma/talk2scholars/tools/s2/search.py +101 -0
- aiagents4pharma/talk2scholars/tools/s2/single_paper_rec.py +102 -0
- aiagents4pharma/talk2scholars/tools/s2/utils/__init__.py +5 -0
- aiagents4pharma/talk2scholars/tools/s2/utils/multi_helper.py +223 -0
- aiagents4pharma/talk2scholars/tools/s2/utils/search_helper.py +205 -0
- aiagents4pharma/talk2scholars/tools/s2/utils/single_helper.py +216 -0
- aiagents4pharma/talk2scholars/tools/zotero/__init__.py +7 -0
- aiagents4pharma/talk2scholars/tools/zotero/utils/__init__.py +7 -0
- aiagents4pharma/talk2scholars/tools/zotero/utils/read_helper.py +270 -0
- aiagents4pharma/talk2scholars/tools/zotero/utils/review_helper.py +74 -0
- aiagents4pharma/talk2scholars/tools/zotero/utils/write_helper.py +194 -0
- aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_path.py +180 -0
- aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_pdf_downloader.py +133 -0
- aiagents4pharma/talk2scholars/tools/zotero/zotero_read.py +105 -0
- aiagents4pharma/talk2scholars/tools/zotero/zotero_review.py +162 -0
- aiagents4pharma/talk2scholars/tools/zotero/zotero_write.py +91 -0
- aiagents4pharma-0.0.0.dist-info/METADATA +335 -0
- aiagents4pharma-0.0.0.dist-info/RECORD +336 -0
- aiagents4pharma-0.0.0.dist-info/WHEEL +4 -0
- 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"}
|