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,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
State management for the Talk2Scholars agent.
|
|
3
|
+
|
|
4
|
+
This module defines the state class `Talk2Scholars`, which maintains the conversation
|
|
5
|
+
context, retrieved papers, and other relevant metadata. The state ensures consistency
|
|
6
|
+
across agent interactions.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from collections.abc import Mapping
|
|
11
|
+
from typing import Annotated, Any
|
|
12
|
+
|
|
13
|
+
from langchain_core.embeddings import Embeddings
|
|
14
|
+
from langchain_core.language_models import BaseChatModel
|
|
15
|
+
from langgraph.prebuilt.chat_agent_executor import AgentState
|
|
16
|
+
|
|
17
|
+
# Configure logging
|
|
18
|
+
logging.basicConfig(level=logging.INFO)
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def merge_dict(existing: dict[str, Any], new: dict[str, Any]) -> dict[str, Any]:
|
|
23
|
+
"""
|
|
24
|
+
Merges the existing dictionary with a new dictionary.
|
|
25
|
+
|
|
26
|
+
This function logs the state merge and ensures that the new values
|
|
27
|
+
are appended to the existing state without overwriting other entries.
|
|
28
|
+
Args:
|
|
29
|
+
existing (Dict[str, Any]): The current dictionary state.
|
|
30
|
+
new (Dict[str, Any]): The new dictionary state to merge.
|
|
31
|
+
Returns:
|
|
32
|
+
Dict[str, Any]: The merged dictionary state.
|
|
33
|
+
"""
|
|
34
|
+
merged = dict(existing) if existing else {}
|
|
35
|
+
merged.update(new or {})
|
|
36
|
+
return merged
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def replace_dict(existing: dict[str, Any], new: Any) -> Any:
|
|
40
|
+
"""
|
|
41
|
+
Replaces the existing dictionary with a new dictionary.
|
|
42
|
+
|
|
43
|
+
This function logs the state update and ensures that the old state is replaced
|
|
44
|
+
with the new one.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
existing (Dict[str, Any]): The current dictionary state.
|
|
48
|
+
new (Dict[str, Any]): The new dictionary state to replace the existing one.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Dict[str, Any]: The updated dictionary state.
|
|
52
|
+
|
|
53
|
+
Example:
|
|
54
|
+
>>> old_state = {"papers": {"id1": "Paper 1"}}
|
|
55
|
+
>>> new_state = {"papers": {"id2": "Paper 2"}}
|
|
56
|
+
>>> updated_state = replace_dict(old_state, new_state)
|
|
57
|
+
>>> print(updated_state)
|
|
58
|
+
{"papers": {"id2": "Paper 2"}}
|
|
59
|
+
"""
|
|
60
|
+
# If new is not a mapping, just replace existing value outright
|
|
61
|
+
if not isinstance(new, Mapping):
|
|
62
|
+
return new
|
|
63
|
+
# In-place replace: clear existing mapping and update with new entries
|
|
64
|
+
existing.clear()
|
|
65
|
+
existing.update(new)
|
|
66
|
+
return existing
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Talk2Scholars(AgentState):
|
|
70
|
+
"""
|
|
71
|
+
Represents the state of the Talk2Scholars agent.
|
|
72
|
+
This class extends `AgentState` to maintain conversation history, retrieved papers,
|
|
73
|
+
and interactions with the language model.
|
|
74
|
+
Attributes:
|
|
75
|
+
last_displayed_papers (Dict[str, Any]): Stores the most recently displayed papers.
|
|
76
|
+
papers (Dict[str, Any]): Stores the research papers retrieved from the agent's queries.
|
|
77
|
+
multi_papers (Dict[str, Any]): Stores multiple recommended papers from various sources.
|
|
78
|
+
article_data (Dict[str, Any]): Stores the papers retrieved from Zotero and the pdf
|
|
79
|
+
download agent with their metadata.
|
|
80
|
+
zotero_write_approval_status (Dict[str, Any]): Stores the approval status and collection
|
|
81
|
+
path for Zotero save operations.
|
|
82
|
+
llm_model (BaseChatModel): The language model instance used for generating responses.
|
|
83
|
+
text_embedding_model (Embeddings): The text embedding model used for
|
|
84
|
+
similarity calculations.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
# Agent state fields
|
|
88
|
+
# Key controlling UI display: always replace to reference latest output
|
|
89
|
+
# Stores the most recently displayed papers metadata
|
|
90
|
+
last_displayed_papers: Annotated[dict[str, Any], replace_dict]
|
|
91
|
+
# Accumulative keys: merge new entries into existing state
|
|
92
|
+
papers: Annotated[dict[str, Any], merge_dict]
|
|
93
|
+
multi_papers: Annotated[dict[str, Any], merge_dict]
|
|
94
|
+
article_data: Annotated[dict[str, Any], merge_dict]
|
|
95
|
+
# Approval status: always replace to reflect latest operation
|
|
96
|
+
zotero_write_approval_status: Annotated[dict[str, Any], replace_dict]
|
|
97
|
+
llm_model: BaseChatModel
|
|
98
|
+
text_embedding_model: Embeddings
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for main agent functionality.
|
|
3
|
+
Tests the supervisor agent's routing logic and state management.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from types import SimpleNamespace
|
|
7
|
+
|
|
8
|
+
import hydra
|
|
9
|
+
import pytest
|
|
10
|
+
from langchain_core.language_models.chat_models import BaseChatModel
|
|
11
|
+
from langchain_core.messages import AIMessage, HumanMessage
|
|
12
|
+
from langchain_core.outputs import ChatGeneration, ChatResult
|
|
13
|
+
from langchain_openai import ChatOpenAI
|
|
14
|
+
from pydantic import Field
|
|
15
|
+
|
|
16
|
+
from aiagents4pharma.talk2scholars.agents.main_agent import get_app
|
|
17
|
+
|
|
18
|
+
# --- Dummy LLM Implementation ---
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DummyLLM(BaseChatModel):
|
|
22
|
+
"""A dummy language model implementation for testing purposes."""
|
|
23
|
+
|
|
24
|
+
model_name: str = Field(...)
|
|
25
|
+
|
|
26
|
+
def _generate(self, messages, stop=None, run_manager=None, **kwargs):
|
|
27
|
+
"""generate a dummy response based on the input messages."""
|
|
28
|
+
DummyLLM.called_prompt = messages[0].content
|
|
29
|
+
message = AIMessage(content="dummy output")
|
|
30
|
+
generation = ChatGeneration(message=message)
|
|
31
|
+
return ChatResult(generations=[generation])
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def _llm_type(self):
|
|
35
|
+
"""Return the type of the language model."""
|
|
36
|
+
return "dummy"
|
|
37
|
+
|
|
38
|
+
# NEW: public shim to avoid protected access in tests
|
|
39
|
+
def public_llm_type(self) -> str:
|
|
40
|
+
"""public method to access the LLM type."""
|
|
41
|
+
return self._llm_type
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# --- Dummy Workflow and Sub-agent Functions ---
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class DummyWorkflow:
|
|
48
|
+
"""A dummy workflow class that records arguments for verification."""
|
|
49
|
+
|
|
50
|
+
def __init__(self, supervisor_args=None):
|
|
51
|
+
"""Initialize the workflow with the given supervisor arguments."""
|
|
52
|
+
self.supervisor_args = supervisor_args or {}
|
|
53
|
+
self.checkpointer = None
|
|
54
|
+
self.name = None
|
|
55
|
+
|
|
56
|
+
def compile(self, checkpointer, name):
|
|
57
|
+
"""Compile the workflow with the given checkpointer and name."""
|
|
58
|
+
self.checkpointer = checkpointer
|
|
59
|
+
self.name = name
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
def get_supervisor_args(self):
|
|
63
|
+
"""Return the supervisor arguments stored in this workflow."""
|
|
64
|
+
return self.supervisor_args
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def dummy_s2_agent(uniq_id, llm_model):
|
|
68
|
+
"""Return a DummyWorkflow for the S2 agent."""
|
|
69
|
+
dummy_s2_agent.called_uniq_id = uniq_id
|
|
70
|
+
dummy_s2_agent.called_llm_model = llm_model
|
|
71
|
+
return DummyWorkflow(supervisor_args={"agent": "s2", "uniq_id": uniq_id})
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def dummy_zotero_agent(uniq_id, llm_model):
|
|
75
|
+
"""Return a DummyWorkflow for the Zotero agent."""
|
|
76
|
+
dummy_zotero_agent.called_uniq_id = uniq_id
|
|
77
|
+
dummy_zotero_agent.called_llm_model = llm_model
|
|
78
|
+
return DummyWorkflow(supervisor_args={"agent": "zotero", "uniq_id": uniq_id})
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def dummy_question_and_answer_agent(uniq_id, llm_model):
|
|
82
|
+
"""Return a DummyWorkflow for the PDF agent."""
|
|
83
|
+
dummy_question_and_answer_agent.called_uniq_id = uniq_id
|
|
84
|
+
dummy_question_and_answer_agent.called_llm_model = llm_model
|
|
85
|
+
return DummyWorkflow(supervisor_args={"agent": "pdf", "uniq_id": uniq_id})
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def dummy_create_supervisor(apps, model, state_schema, **kwargs):
|
|
89
|
+
"""Return a DummyWorkflow for the supervisor."""
|
|
90
|
+
dummy_create_supervisor.called_kwargs = kwargs
|
|
91
|
+
return DummyWorkflow(
|
|
92
|
+
supervisor_args={
|
|
93
|
+
"apps": apps,
|
|
94
|
+
"model": model,
|
|
95
|
+
"state_schema": state_schema,
|
|
96
|
+
**kwargs,
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# --- Dummy Hydra Configuration Setup ---
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class DummyHydraContext:
|
|
105
|
+
"""A dummy context manager for mocking Hydra's initialize and compose functions."""
|
|
106
|
+
|
|
107
|
+
def __enter__(self):
|
|
108
|
+
"""Return None when entering the context."""
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
def __exit__(self, exc_type, exc_val, traceback):
|
|
112
|
+
"""Exit function that does nothing."""
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def dict_to_namespace(d):
|
|
117
|
+
"""Convert a dictionary to a SimpleNamespace object."""
|
|
118
|
+
return SimpleNamespace(
|
|
119
|
+
**{key: dict_to_namespace(val) if isinstance(val, dict) else val for key, val in d.items()}
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
dummy_config = {
|
|
124
|
+
"agents": {"talk2scholars": {"main_agent": {"system_prompt": "Dummy system prompt"}}}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class DummyHydraCompose:
|
|
129
|
+
"""A dummy class that returns a namespace from a dummy config dictionary."""
|
|
130
|
+
|
|
131
|
+
def __init__(self, config):
|
|
132
|
+
"""Constructor that stores the dummy config."""
|
|
133
|
+
self.config = config
|
|
134
|
+
|
|
135
|
+
def __getattr__(self, item):
|
|
136
|
+
"""Return a namespace from the dummy config."""
|
|
137
|
+
return dict_to_namespace(self.config.get(item, {}))
|
|
138
|
+
|
|
139
|
+
def get_config(self):
|
|
140
|
+
"""Get the raw dummy configuration dictionary."""
|
|
141
|
+
return self.config
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# --- Pytest Fixtures to Patch Dependencies ---
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@pytest.fixture(autouse=True)
|
|
148
|
+
def patch_hydra(monkeypatch):
|
|
149
|
+
"""Patch the hydra.initialize and hydra.compose functions to return dummy objects."""
|
|
150
|
+
monkeypatch.setattr(hydra, "initialize", lambda version_base, config_path: DummyHydraContext())
|
|
151
|
+
monkeypatch.setattr(
|
|
152
|
+
hydra, "compose", lambda config_name, overrides: DummyHydraCompose(dummy_config)
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def dummy_paper_download_agent(uniq_id, llm_model):
|
|
157
|
+
"""Return a DummyWorkflow for the paper download agent."""
|
|
158
|
+
dummy_paper_download_agent.called_uniq_id = uniq_id
|
|
159
|
+
dummy_paper_download_agent.called_llm_model = llm_model
|
|
160
|
+
return DummyWorkflow(supervisor_args={"agent": "paper_download", "uniq_id": uniq_id})
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@pytest.fixture(autouse=True)
|
|
164
|
+
def patch_sub_agents_and_supervisor(monkeypatch):
|
|
165
|
+
"""Patch the sub-agents and supervisor creation functions."""
|
|
166
|
+
monkeypatch.setattr(
|
|
167
|
+
"aiagents4pharma.talk2scholars.agents.main_agent.get_app_s2", dummy_s2_agent
|
|
168
|
+
)
|
|
169
|
+
monkeypatch.setattr(
|
|
170
|
+
"aiagents4pharma.talk2scholars.agents.main_agent.get_app_zotero",
|
|
171
|
+
dummy_zotero_agent,
|
|
172
|
+
)
|
|
173
|
+
monkeypatch.setattr(
|
|
174
|
+
"aiagents4pharma.talk2scholars.agents.main_agent.get_app_pdf",
|
|
175
|
+
dummy_question_and_answer_agent,
|
|
176
|
+
)
|
|
177
|
+
monkeypatch.setattr(
|
|
178
|
+
"aiagents4pharma.talk2scholars.agents.main_agent.get_app_paper_download",
|
|
179
|
+
dummy_paper_download_agent,
|
|
180
|
+
)
|
|
181
|
+
monkeypatch.setattr(
|
|
182
|
+
"aiagents4pharma.talk2scholars.agents.main_agent.create_supervisor",
|
|
183
|
+
dummy_create_supervisor,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# --- Test Cases ---
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_dummy_llm_generate():
|
|
191
|
+
"""Test the dummy LLM's generate function through public interface."""
|
|
192
|
+
dummy = DummyLLM(model_name="test-model")
|
|
193
|
+
# Test that the dummy LLM can be used (testing the class works)
|
|
194
|
+
assert dummy.model_name == "test-model"
|
|
195
|
+
# Test through public interface that internally calls _generate (covers lines 26-27)
|
|
196
|
+
# Use invoke which internally calls _generate
|
|
197
|
+
messages = [HumanMessage(content="test prompt")]
|
|
198
|
+
result = dummy.invoke(messages)
|
|
199
|
+
# Verify the internal state was set
|
|
200
|
+
assert hasattr(DummyLLM, "called_prompt")
|
|
201
|
+
assert result is not None
|
|
202
|
+
assert DummyLLM.called_prompt == "test prompt"
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def test_dummy_llm_llm_type():
|
|
206
|
+
"""Test the dummy LLM's type identification."""
|
|
207
|
+
dummy = DummyLLM(model_name="test-model")
|
|
208
|
+
|
|
209
|
+
# Use public shim instead of protected attribute access
|
|
210
|
+
llm_type = dummy.public_llm_type()
|
|
211
|
+
assert llm_type == "dummy"
|
|
212
|
+
|
|
213
|
+
# Also test the public string representation
|
|
214
|
+
assert "DummyLLM" in str(dummy.__class__.__name__)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def test_get_app_with_gpt4o_mini():
|
|
218
|
+
"""
|
|
219
|
+
Test that get_app replaces a 'gpt-4o-mini' LLM with a new ChatOpenAI instance.
|
|
220
|
+
"""
|
|
221
|
+
uniq_id = "test_thread"
|
|
222
|
+
dummy_llm = DummyLLM(model_name="gpt-4o-mini")
|
|
223
|
+
app = get_app(uniq_id, dummy_llm)
|
|
224
|
+
|
|
225
|
+
supervisor_args = getattr(app, "supervisor_args", {})
|
|
226
|
+
assert isinstance(supervisor_args.get("model"), ChatOpenAI)
|
|
227
|
+
assert supervisor_args.get("prompt") == "Dummy system prompt"
|
|
228
|
+
assert getattr(app, "name", "") == "Talk2Scholars_MainAgent"
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def test_get_app_with_other_model():
|
|
232
|
+
"""
|
|
233
|
+
Test that get_app does not replace the LLM if its model_name is not 'gpt-4o-mini'.
|
|
234
|
+
"""
|
|
235
|
+
uniq_id = "test_thread_2"
|
|
236
|
+
dummy_llm = DummyLLM(model_name="other-model")
|
|
237
|
+
app = get_app(uniq_id, dummy_llm)
|
|
238
|
+
|
|
239
|
+
supervisor_args = getattr(app, "supervisor_args", {})
|
|
240
|
+
assert supervisor_args.get("model") is dummy_llm
|
|
241
|
+
assert supervisor_args.get("prompt") == "Dummy system prompt"
|
|
242
|
+
assert getattr(app, "name", "") == "Talk2Scholars_MainAgent"
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def test_dummy_workflow_get_supervisor_args():
|
|
246
|
+
"""Test that DummyWorkflow.get_supervisor_args returns the stored args."""
|
|
247
|
+
dummy_args = {"agent": "test", "uniq_id": "id123"}
|
|
248
|
+
wf = DummyWorkflow(supervisor_args=dummy_args)
|
|
249
|
+
assert wf.get_supervisor_args() is dummy_args
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def test_dummy_hydra_compose_get_config():
|
|
253
|
+
"""Test that DummyHydraCompose.get_config returns the raw config."""
|
|
254
|
+
config_dict = {"agents": {"test": {"key": "value"}}}
|
|
255
|
+
compose = DummyHydraCompose(config_dict)
|
|
256
|
+
assert compose.get_config() is config_dict
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Unit tests for the paper download agent in Talk2Scholars."""
|
|
2
|
+
|
|
3
|
+
from unittest import mock
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from langchain_core.language_models.chat_models import BaseChatModel
|
|
7
|
+
from langchain_core.messages import AIMessage, HumanMessage
|
|
8
|
+
|
|
9
|
+
from ..agents.paper_download_agent import get_app
|
|
10
|
+
from ..state.state_talk2scholars import Talk2Scholars
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.fixture(autouse=True)
|
|
14
|
+
def mock_hydra_fixture():
|
|
15
|
+
"""Mocks Hydra configuration for tests."""
|
|
16
|
+
with mock.patch("hydra.initialize"), mock.patch("hydra.compose") as mock_compose:
|
|
17
|
+
cfg_mock = mock.MagicMock()
|
|
18
|
+
cfg_mock.agents.talk2scholars.paper_download_agent.paper_download_agent = "Test prompt"
|
|
19
|
+
mock_compose.return_value = cfg_mock
|
|
20
|
+
yield mock_compose
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def mock_tools_fixture():
|
|
25
|
+
"""Mocks paper download tools to prevent real HTTP calls."""
|
|
26
|
+
with mock.patch(
|
|
27
|
+
"aiagents4pharma.talk2scholars.tools.paper_download.paper_downloader.download_papers"
|
|
28
|
+
) as mock_download_papers:
|
|
29
|
+
mock_download_papers.return_value = {"article_data": {"dummy_key": "dummy_value"}}
|
|
30
|
+
yield [mock_download_papers]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.mark.usefixtures("mock_hydra_fixture")
|
|
34
|
+
def test_paper_download_agent_initialization():
|
|
35
|
+
"""Ensures the paper download agent initializes properly with a prompt."""
|
|
36
|
+
thread_id = "test_thread_paper_dl"
|
|
37
|
+
llm_mock = mock.Mock(spec=BaseChatModel) # Mock LLM
|
|
38
|
+
|
|
39
|
+
with mock.patch(
|
|
40
|
+
"aiagents4pharma.talk2scholars.agents.paper_download_agent.create_react_agent"
|
|
41
|
+
) as mock_create_agent:
|
|
42
|
+
mock_create_agent.return_value = mock.Mock()
|
|
43
|
+
|
|
44
|
+
app = get_app(thread_id, llm_mock)
|
|
45
|
+
assert app is not None, "The agent app should be successfully created."
|
|
46
|
+
assert mock_create_agent.called
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_paper_download_agent_invocation():
|
|
50
|
+
"""Verifies agent processes queries and updates state correctly."""
|
|
51
|
+
_ = mock_tools_fixture # Prevents unused-argument warning
|
|
52
|
+
thread_id = "test_thread_paper_dl"
|
|
53
|
+
mock_state = Talk2Scholars(messages=[HumanMessage(content="Download paper 1234.5678")])
|
|
54
|
+
llm_mock = mock.Mock(spec=BaseChatModel)
|
|
55
|
+
|
|
56
|
+
with mock.patch(
|
|
57
|
+
"aiagents4pharma.talk2scholars.agents.paper_download_agent.create_react_agent"
|
|
58
|
+
) as mock_create_agent:
|
|
59
|
+
mock_agent = mock.Mock()
|
|
60
|
+
mock_create_agent.return_value = mock_agent
|
|
61
|
+
mock_agent.invoke.return_value = {
|
|
62
|
+
"messages": [AIMessage(content="Here is the paper")],
|
|
63
|
+
"article_data": {"file_bytes": b"FAKE_PDF_CONTENTS"},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
app = get_app(thread_id, llm_mock)
|
|
67
|
+
result = app.invoke(
|
|
68
|
+
mock_state,
|
|
69
|
+
config={
|
|
70
|
+
"configurable": {
|
|
71
|
+
"thread_id": thread_id,
|
|
72
|
+
"checkpoint_ns": "test_ns",
|
|
73
|
+
"checkpoint_id": "test_checkpoint",
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
assert "messages" in result
|
|
79
|
+
assert "article_data" in result
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_paper_download_agent_tools_assignment(
|
|
83
|
+
request,
|
|
84
|
+
):
|
|
85
|
+
"""Checks correct tool assignment (download_papers tool)."""
|
|
86
|
+
thread_id = "test_thread_paper_dl"
|
|
87
|
+
request.getfixturevalue("mock_tools_fixture")
|
|
88
|
+
llm_mock = mock.Mock(spec=BaseChatModel)
|
|
89
|
+
|
|
90
|
+
with (
|
|
91
|
+
mock.patch(
|
|
92
|
+
"aiagents4pharma.talk2scholars.agents.paper_download_agent.create_react_agent"
|
|
93
|
+
) as mock_create_agent,
|
|
94
|
+
mock.patch(
|
|
95
|
+
"aiagents4pharma.talk2scholars.agents.paper_download_agent.ToolNode"
|
|
96
|
+
) as mock_toolnode,
|
|
97
|
+
):
|
|
98
|
+
mock_agent = mock.Mock()
|
|
99
|
+
mock_create_agent.return_value = mock_agent
|
|
100
|
+
mock_tool_instance = mock.Mock()
|
|
101
|
+
mock_toolnode.return_value = mock_tool_instance
|
|
102
|
+
|
|
103
|
+
get_app(thread_id, llm_mock)
|
|
104
|
+
# Verify ToolNode was called with download_papers function
|
|
105
|
+
assert mock_toolnode.called
|
|
106
|
+
# Check that ToolNode was called with a list containing the download_papers tool
|
|
107
|
+
call_args = mock_toolnode.call_args[0][0] # Get first positional argument (the tools list)
|
|
108
|
+
assert len(call_args) == 1
|
|
109
|
+
# The tool should be a StructuredTool with name 'download_papers'
|
|
110
|
+
tool = call_args[0]
|
|
111
|
+
assert hasattr(tool, "name")
|
|
112
|
+
assert tool.name == "download_papers"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_paper_download_agent_hydra_failure():
|
|
116
|
+
"""Confirms the agent gracefully handles exceptions if Hydra fails."""
|
|
117
|
+
thread_id = "test_thread_paper_dl"
|
|
118
|
+
llm_mock = mock.Mock(spec=BaseChatModel)
|
|
119
|
+
|
|
120
|
+
with mock.patch("hydra.initialize", side_effect=Exception("Mock Hydra failure")):
|
|
121
|
+
with pytest.raises(Exception) as exc_info:
|
|
122
|
+
get_app(thread_id, llm_mock)
|
|
123
|
+
assert "Mock Hydra failure" in str(exc_info.value)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_paper_download_agent_model_failure():
|
|
127
|
+
"""Ensures agent handles model-related failures gracefully."""
|
|
128
|
+
thread_id = "test_thread_paper_dl"
|
|
129
|
+
llm_mock = mock.Mock(spec=BaseChatModel)
|
|
130
|
+
|
|
131
|
+
with mock.patch(
|
|
132
|
+
"aiagents4pharma.talk2scholars.agents.paper_download_agent.create_react_agent",
|
|
133
|
+
side_effect=Exception("Mock model failure"),
|
|
134
|
+
):
|
|
135
|
+
with pytest.raises(Exception) as exc_info:
|
|
136
|
+
get_app(thread_id, llm_mock)
|
|
137
|
+
assert "Mock model failure" in str(exc_info.value), (
|
|
138
|
+
"Model initialization failure should raise an exception."
|
|
139
|
+
)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit Tests for the PDF agent.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from unittest import mock
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
from langchain_core.messages import AIMessage, HumanMessage
|
|
9
|
+
|
|
10
|
+
from ..agents.pdf_agent import get_app
|
|
11
|
+
from ..state.state_talk2scholars import Talk2Scholars
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture(autouse=True)
|
|
15
|
+
def mock_hydra_fixture():
|
|
16
|
+
"""Mock Hydra configuration to prevent external dependencies."""
|
|
17
|
+
with mock.patch("hydra.initialize"), mock.patch("hydra.compose") as mock_compose:
|
|
18
|
+
# Create a mock configuration with a pdf_agent section.
|
|
19
|
+
cfg_mock = mock.MagicMock()
|
|
20
|
+
# The pdf_agent config will be accessed as cfg.agents.talk2scholars.pdf_agent in get_app.
|
|
21
|
+
cfg_mock.agents.talk2scholars.pdf_agent.some_property = "Test prompt"
|
|
22
|
+
mock_compose.return_value = cfg_mock
|
|
23
|
+
yield mock_compose
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.fixture
|
|
27
|
+
def mock_tools_fixture():
|
|
28
|
+
"""Mock PDF agent tools to prevent execution of real API calls."""
|
|
29
|
+
with (
|
|
30
|
+
mock.patch(
|
|
31
|
+
"aiagents4pharma.talk2scholars.agents.pdf_agent.question_and_answer"
|
|
32
|
+
) as mock_question_and_answer,
|
|
33
|
+
):
|
|
34
|
+
mock_question_and_answer.return_value = {"result": "Mock Question and Answer Result"}
|
|
35
|
+
yield [mock_question_and_answer]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.fixture(name="mock_llm")
|
|
39
|
+
def llm_fixture():
|
|
40
|
+
"""Provide a dummy language model to pass into get_app."""
|
|
41
|
+
return mock.Mock()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.mark.usefixtures("mock_hydra_fixture")
|
|
45
|
+
def test_pdf_agent_initialization(mock_llm):
|
|
46
|
+
"""Test that PDF agent initializes correctly with mock configuration."""
|
|
47
|
+
thread_id = "test_thread"
|
|
48
|
+
with mock.patch(
|
|
49
|
+
"aiagents4pharma.talk2scholars.agents.pdf_agent.create_react_agent"
|
|
50
|
+
) as mock_create:
|
|
51
|
+
mock_create.return_value = mock.Mock()
|
|
52
|
+
app = get_app(thread_id, mock_llm)
|
|
53
|
+
assert app is not None
|
|
54
|
+
assert mock_create.called
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_pdf_agent_invocation(mock_llm):
|
|
58
|
+
"""Test that the PDF agent processes user input and returns a valid response."""
|
|
59
|
+
thread_id = "test_thread"
|
|
60
|
+
# Create a sample state with a human message.
|
|
61
|
+
mock_state = Talk2Scholars(messages=[HumanMessage(content="Extract key data from PDF")])
|
|
62
|
+
with mock.patch(
|
|
63
|
+
"aiagents4pharma.talk2scholars.agents.pdf_agent.create_react_agent"
|
|
64
|
+
) as mock_create:
|
|
65
|
+
mock_agent = mock.Mock()
|
|
66
|
+
mock_create.return_value = mock_agent
|
|
67
|
+
# Simulate a response from the PDF agent.
|
|
68
|
+
mock_agent.invoke.return_value = {
|
|
69
|
+
"messages": [AIMessage(content="PDF content extracted successfully")],
|
|
70
|
+
"article_data": {"page": 1, "text": "Sample PDF text"},
|
|
71
|
+
}
|
|
72
|
+
app = get_app(thread_id, mock_llm)
|
|
73
|
+
result = app.invoke(
|
|
74
|
+
mock_state,
|
|
75
|
+
config={
|
|
76
|
+
"configurable": {
|
|
77
|
+
"thread_id": thread_id,
|
|
78
|
+
"checkpoint_ns": "test_ns",
|
|
79
|
+
"checkpoint_id": "test_checkpoint",
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
assert "messages" in result
|
|
84
|
+
assert "article_data" in result
|
|
85
|
+
assert result["article_data"]["page"] == 1
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_pdf_agent_tools_assignment(request, mock_llm):
|
|
89
|
+
"""Ensure that the correct tools are assigned to the PDF agent."""
|
|
90
|
+
thread_id = "test_thread"
|
|
91
|
+
mock_tools = request.getfixturevalue("mock_tools_fixture")
|
|
92
|
+
with (
|
|
93
|
+
mock.patch(
|
|
94
|
+
"aiagents4pharma.talk2scholars.agents.pdf_agent.create_react_agent"
|
|
95
|
+
) as mock_create,
|
|
96
|
+
mock.patch("aiagents4pharma.talk2scholars.agents.pdf_agent.ToolNode") as mock_toolnode,
|
|
97
|
+
):
|
|
98
|
+
mock_agent = mock.Mock()
|
|
99
|
+
mock_create.return_value = mock_agent
|
|
100
|
+
mock_tool_instance = mock.Mock()
|
|
101
|
+
mock_tool_instance.tools = mock_tools
|
|
102
|
+
mock_toolnode.return_value = mock_tool_instance
|
|
103
|
+
get_app(thread_id, mock_llm)
|
|
104
|
+
assert mock_toolnode.called
|
|
105
|
+
assert len(mock_tool_instance.tools) == 1
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_pdf_agent_hydra_failure(mock_llm):
|
|
109
|
+
"""Test exception handling when Hydra fails to load config for PDF agent."""
|
|
110
|
+
thread_id = "test_thread"
|
|
111
|
+
with mock.patch("hydra.initialize", side_effect=Exception("Hydra error")):
|
|
112
|
+
with pytest.raises(Exception) as exc_info:
|
|
113
|
+
get_app(thread_id, mock_llm)
|
|
114
|
+
assert "Hydra error" in str(exc_info.value)
|