aiagents4pharma 1.14.0__tar.gz → 1.14.1__tar.gz
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-1.14.0 → aiagents4pharma-1.14.1}/PKG-INFO +1 -1
- aiagents4pharma-1.14.1/aiagents4pharma/configs/config.yaml +4 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/configs/talk2biomodels/__init__.py +1 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/configs/talk2biomodels/agents/t2b_agent/default.yaml +2 -3
- aiagents4pharma-1.14.1/aiagents4pharma/configs/talk2biomodels/tools/__init__.py +4 -0
- aiagents4pharma-1.14.1/aiagents4pharma/configs/talk2biomodels/tools/ask_question/__init__.py +3 -0
- aiagents4pharma-1.14.1/aiagents4pharma/talk2biomodels/states/state_talk2biomodels.py +40 -0
- aiagents4pharma-1.14.1/aiagents4pharma/talk2biomodels/tests/test_ask_question.py +44 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tests/test_get_annotation.py +67 -69
- aiagents4pharma-1.14.1/aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py +26 -0
- aiagents4pharma-1.14.1/aiagents4pharma/talk2biomodels/tests/test_integration.py +126 -0
- aiagents4pharma-1.14.1/aiagents4pharma/talk2biomodels/tests/test_param_scan.py +68 -0
- aiagents4pharma-1.14.1/aiagents4pharma/talk2biomodels/tests/test_search_models.py +28 -0
- aiagents4pharma-1.14.1/aiagents4pharma/talk2biomodels/tests/test_simulate_model.py +39 -0
- aiagents4pharma-1.14.1/aiagents4pharma/talk2biomodels/tests/test_steady_state.py +90 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/ask_question.py +29 -8
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/get_annotation.py +24 -9
- aiagents4pharma-1.14.1/aiagents4pharma/talk2biomodels/tools/load_arguments.py +114 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/parameter_scan.py +91 -96
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/simulate_model.py +14 -81
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/steady_state.py +48 -89
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma.egg-info/PKG-INFO +1 -1
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma.egg-info/SOURCES.txt +10 -1
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/pyproject.toml +3 -0
- aiagents4pharma-1.14.1/release_version.txt +1 -0
- aiagents4pharma-1.14.0/aiagents4pharma/configs/config.yaml +0 -3
- aiagents4pharma-1.14.0/aiagents4pharma/talk2biomodels/states/state_talk2biomodels.py +0 -26
- aiagents4pharma-1.14.0/aiagents4pharma/talk2biomodels/tests/test_langgraph.py +0 -384
- aiagents4pharma-1.14.0/release_version.txt +0 -1
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/LICENSE +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/README.md +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/configs/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/configs/talk2biomodels/agents/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/configs/talk2biomodels/agents/t2b_agent/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/agents/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/agents/t2b_agent.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/api/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/api/kegg.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/api/ols.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/api/uniprot.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/models/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/models/basico_model.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/models/sys_bio_model.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/states/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tests/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tests/test_api.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tests/test_basico_model.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tests/test_sys_bio_model.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/custom_plotter.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/get_modelinfo.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/load_biomodel.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2biomodels/tools/search_models.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/agents/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/agents/scp_agent.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/states/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/states/state_talk2cells.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/tests/scp_agent/test_scp_agent.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/tools/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/tools/scp_agent/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/tools/scp_agent/display_studies.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2cells/tools/scp_agent/search_studies.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/agents/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/agents/main_agent.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/agents/s2_agent.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/config/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/config/config.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/state/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/state/state_talk2competitors.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/tests/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/tests/test_langgraph.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/tools/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/tools/s2/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/tools/s2/display_results.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/tools/s2/multi_paper_rec.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/tools/s2/search.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2competitors/tools/s2/single_paper_rec.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/datasets/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/datasets/biobridge_primekg.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/datasets/dataset.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/datasets/primekg.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/datasets/starkqa_primekg.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_biobridge_primekg.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_dataset.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_primekg.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_starkqa_primekg.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_embeddings.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_huggingface.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_sentencetransformer.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_enrichments.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ollama.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/utils/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/utils/embeddings/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/utils/embeddings/embeddings.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/utils/embeddings/huggingface.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/utils/embeddings/sentence_transformer.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/utils/enrichments/__init__.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/utils/enrichments/enrichments.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ollama.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma/talk2knowledgegraphs/utils/kg_utils.py +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma.egg-info/dependency_links.txt +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma.egg-info/requires.txt +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/aiagents4pharma.egg-info/top_level.txt +0 -0
- {aiagents4pharma-1.14.0 → aiagents4pharma-1.14.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: aiagents4pharma
|
3
|
-
Version: 1.14.
|
3
|
+
Version: 1.14.1
|
4
4
|
Summary: AI Agents for drug discovery, drug development, and other pharmaceutical R&D
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -4,6 +4,5 @@ state_modifier: >
|
|
4
4
|
If the user asks for the uploaded model,
|
5
5
|
then pass the use_uploaded_model argument
|
6
6
|
as True. If the user asks for simulation
|
7
|
-
or steady state, suggest a
|
8
|
-
|
9
|
-
argument.
|
7
|
+
or param_scan or steady state, suggest a
|
8
|
+
value for the `experiment_name` argument.
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
|
3
|
+
'''
|
4
|
+
This is the state file for the Talk2BioModels agent.
|
5
|
+
'''
|
6
|
+
|
7
|
+
from typing import Annotated
|
8
|
+
import operator
|
9
|
+
from langgraph.prebuilt.chat_agent_executor import AgentState
|
10
|
+
|
11
|
+
def add_data(data1: dict, data2: dict) -> dict:
|
12
|
+
"""
|
13
|
+
A reducer function to merge two dictionaries.
|
14
|
+
"""
|
15
|
+
left_idx_by_name = {data['name']: idx for idx, data in enumerate(data1)}
|
16
|
+
merged = data1.copy()
|
17
|
+
for data in data2:
|
18
|
+
idx = left_idx_by_name.get(data['name'])
|
19
|
+
if idx is not None:
|
20
|
+
merged[idx] = data
|
21
|
+
else:
|
22
|
+
merged.append(data)
|
23
|
+
return merged
|
24
|
+
|
25
|
+
class Talk2Biomodels(AgentState):
|
26
|
+
"""
|
27
|
+
The state for the Talk2BioModels agent.
|
28
|
+
"""
|
29
|
+
llm_model: str
|
30
|
+
# A StateGraph may receive a concurrent updates
|
31
|
+
# which is not supported by the StateGraph. Hence,
|
32
|
+
# we need to add a reducer function to handle the
|
33
|
+
# concurrent updates.
|
34
|
+
# https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE/
|
35
|
+
model_id: Annotated[list, operator.add]
|
36
|
+
sbml_file_path: Annotated[list, operator.add]
|
37
|
+
dic_simulated_data: Annotated[list[dict], add_data]
|
38
|
+
dic_scanned_data: Annotated[list[dict], add_data]
|
39
|
+
dic_steady_state_data: Annotated[list[dict], add_data]
|
40
|
+
dic_annotations_data : Annotated[list[dict], add_data]
|
@@ -0,0 +1,44 @@
|
|
1
|
+
'''
|
2
|
+
Test cases for Talk2Biomodels.
|
3
|
+
'''
|
4
|
+
|
5
|
+
from langchain_core.messages import HumanMessage, ToolMessage
|
6
|
+
from ..agents.t2b_agent import get_app
|
7
|
+
|
8
|
+
def test_ask_question_tool():
|
9
|
+
'''
|
10
|
+
Test the ask_question tool without the simulation results.
|
11
|
+
'''
|
12
|
+
unique_id = 12345
|
13
|
+
app = get_app(unique_id, llm_model='gpt-4o-mini')
|
14
|
+
config = {"configurable": {"thread_id": unique_id}}
|
15
|
+
|
16
|
+
##########################################
|
17
|
+
# Test ask_question tool when simulation
|
18
|
+
# results are not available i.e. the
|
19
|
+
# simulation has not been run. In this
|
20
|
+
# case, the tool should return an error
|
21
|
+
##########################################
|
22
|
+
# Update state
|
23
|
+
app.update_state(config, {"llm_model": "gpt-4o-mini"})
|
24
|
+
# Define the prompt
|
25
|
+
prompt = "Call the ask_question tool to answer the "
|
26
|
+
prompt += "question: What is the concentration of CRP "
|
27
|
+
prompt += "in serum at 1000 hours? The simulation name "
|
28
|
+
prompt += "is `simulation_name`."
|
29
|
+
# Invoke the tool
|
30
|
+
app.invoke(
|
31
|
+
{"messages": [HumanMessage(content=prompt)]},
|
32
|
+
config=config
|
33
|
+
)
|
34
|
+
# Get the messages from the current state
|
35
|
+
# and reverse the order
|
36
|
+
current_state = app.get_state(config)
|
37
|
+
reversed_messages = current_state.values["messages"][::-1]
|
38
|
+
# Loop through the reversed messages until a
|
39
|
+
# ToolMessage is found.
|
40
|
+
for msg in reversed_messages:
|
41
|
+
# Assert that the message is a ToolMessage
|
42
|
+
# and its status is "error"
|
43
|
+
if isinstance(msg, ToolMessage):
|
44
|
+
assert msg.status == "error"
|
@@ -1,6 +1,7 @@
|
|
1
1
|
'''
|
2
|
-
Test cases for Talk2Biomodels.
|
2
|
+
Test cases for Talk2Biomodels get_annotation tool.
|
3
3
|
'''
|
4
|
+
|
4
5
|
import random
|
5
6
|
import pytest
|
6
7
|
from langchain_core.messages import HumanMessage, ToolMessage
|
@@ -17,9 +18,27 @@ def make_graph_fixture():
|
|
17
18
|
config = {"configurable": {"thread_id": unique_id}}
|
18
19
|
return graph, config
|
19
20
|
|
20
|
-
def
|
21
|
+
def test_no_model_provided(make_graph):
|
22
|
+
'''
|
23
|
+
Test the tool by not specifying any model.
|
24
|
+
We are testing a condition where the user
|
25
|
+
asks for annotations of all species without
|
26
|
+
specifying a model.
|
27
|
+
'''
|
28
|
+
app, config = make_graph
|
29
|
+
prompt = "Extract annotations of all species. Call the tool get_annotation."
|
30
|
+
app.invoke({"messages": [HumanMessage(content=prompt)]},
|
31
|
+
config=config
|
32
|
+
)
|
33
|
+
current_state = app.get_state(config)
|
34
|
+
# Assert that the state key model_id is empty.
|
35
|
+
assert current_state.values["model_id"] == []
|
36
|
+
|
37
|
+
def test_specific_species_provided(make_graph):
|
21
38
|
'''
|
22
|
-
Test the tool by
|
39
|
+
Test the tool by providing a specific species name.
|
40
|
+
We are testing a condition where the user asks for annotations
|
41
|
+
of a specific species in a specific model.
|
23
42
|
'''
|
24
43
|
# Test with a valid species name
|
25
44
|
app, config = make_graph
|
@@ -87,15 +106,19 @@ def test_species_list(make_graph):
|
|
87
106
|
break
|
88
107
|
assert artifact_was_none
|
89
108
|
|
90
|
-
def
|
109
|
+
def test_all_species_annotations(make_graph):
|
91
110
|
'''
|
92
111
|
Test the tool by asking for annotations of all species is specific models.
|
112
|
+
Here, we test the tool with three models since they have different use cases:
|
113
|
+
- model 12 contains a species with no URL provided.
|
114
|
+
- model 20 contains a species without description.
|
115
|
+
- model 56 contains a species with database outside of KEGG, UniProt, and OLS.
|
93
116
|
|
94
|
-
|
95
|
-
|
96
|
-
model 56 contains species with database outside of KEGG, UniProt, and OLS.
|
117
|
+
We are testing a condition where the user asks for annotations
|
118
|
+
of all species in a specific model.
|
97
119
|
'''
|
98
|
-
#
|
120
|
+
# Loop through the models and test the tool
|
121
|
+
# for each model's unique use case.
|
99
122
|
for model_id in [12, 20, 56]:
|
100
123
|
app, config = make_graph
|
101
124
|
prompt = f"Extract annotations of all species model {model_id}."
|
@@ -103,71 +126,46 @@ def test_all_species(make_graph):
|
|
103
126
|
app.invoke({"messages": [HumanMessage(content=prompt)]},
|
104
127
|
config=config
|
105
128
|
)
|
106
|
-
#print(response["messages"])
|
107
|
-
# assistant_msg = response["messages"][-1].content
|
108
|
-
|
109
129
|
current_state = app.get_state(config)
|
110
130
|
|
111
131
|
reversed_messages = current_state.values["messages"][::-1]
|
112
132
|
# Coveres all of the use cases for the expecetd sting on all the species
|
113
133
|
test_condition = False
|
114
134
|
for msg in reversed_messages:
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
if model_id == 20:
|
126
|
-
# For model 20:
|
127
|
-
# Expect an error message containing a note that species extraction failed.
|
128
|
-
if ("Unable to extract species from the model"
|
129
|
-
in msg.content and msg.status == "error"):
|
130
|
-
test_condition = True
|
131
|
-
break
|
132
|
-
|
133
|
-
if model_id == 56:
|
134
|
-
# For model 56:
|
135
|
-
# Expect a successful extraction (artifact is True) and that the content
|
136
|
-
# matches for for missing description ['ORI'].
|
137
|
-
if (msg.artifact is True and
|
138
|
-
msg.content == prepare_content_msg([],['ORI'])
|
139
|
-
and msg.status == "success"):
|
140
|
-
test_condition = True
|
141
|
-
break
|
142
|
-
|
143
|
-
# Retrieve the dictionary that holds all the annotation data from the app's state
|
144
|
-
dic_annotations_data = current_state.values["dic_annotations_data"]
|
145
|
-
|
146
|
-
assert isinstance(dic_annotations_data, list),\
|
147
|
-
f"Expected a list for model {model_id}, got {type(dic_annotations_data)}"
|
148
|
-
assert len(dic_annotations_data) > 0,\
|
149
|
-
f"Expected species data for model {model_id}, but got empty list"
|
150
|
-
assert test_condition # Expected output is validated
|
151
|
-
|
152
|
-
# Test case where no model is specified
|
153
|
-
app, config = make_graph
|
154
|
-
prompt = "Extract annotations of all species."
|
155
|
-
app.invoke({"messages": [HumanMessage(content=prompt)]},
|
156
|
-
config=config
|
157
|
-
)
|
158
|
-
current_state = app.get_state(config)
|
159
|
-
# dic_annotations_data = current_state.values["dic_annotations_data"]
|
160
|
-
reversed_messages = current_state.values["messages"][::-1]
|
161
|
-
print(reversed_messages)
|
135
|
+
# Skip messages that are not ToolMessages and those that are not
|
136
|
+
# from the get_annotation tool.
|
137
|
+
if not isinstance(msg, ToolMessage) or msg.name != "get_annotation":
|
138
|
+
continue
|
139
|
+
if model_id == 12:
|
140
|
+
# Extact the first and second description of the LacI protein
|
141
|
+
# We already know that the first or second description is missing ('-')
|
142
|
+
dic_annotations_data = current_state.values["dic_annotations_data"][0]
|
143
|
+
first_descp_laci_protein = dic_annotations_data['data']['Description'][0]
|
144
|
+
second_descp_laci_protein = dic_annotations_data['data']['Description'][1]
|
162
145
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
146
|
+
# Expect a successful extraction (artifact is True) and that the content
|
147
|
+
# matches what is returned by prepare_content_msg for species.
|
148
|
+
# And that the first or second description of the LacI protein is missing.
|
149
|
+
if (msg.artifact is True and msg.content == prepare_content_msg([],[])
|
150
|
+
and msg.status=="success" and (first_descp_laci_protein == '-' or
|
151
|
+
second_descp_laci_protein == '-')):
|
152
|
+
test_condition = True
|
153
|
+
break
|
154
|
+
|
155
|
+
if model_id == 20:
|
156
|
+
# Expect an error message containing a note
|
157
|
+
# that species extraction failed.
|
158
|
+
if ("Unable to extract species from the model"
|
159
|
+
in msg.content and msg.status == "error"):
|
160
|
+
test_condition = True
|
161
|
+
break
|
162
|
+
|
163
|
+
if model_id == 56:
|
164
|
+
# Expect a successful extraction (artifact is True) and that the content
|
165
|
+
# matches for for missing description ['ORI'].
|
166
|
+
if (msg.artifact is True and
|
167
|
+
msg.content == prepare_content_msg([],['ORI'])
|
168
|
+
and msg.status == "success"):
|
169
|
+
test_condition = True
|
170
|
+
break
|
171
|
+
assert test_condition # Expected output is validated
|
@@ -0,0 +1,26 @@
|
|
1
|
+
'''
|
2
|
+
Test cases for Talk2Biomodels get_modelinfo tool.
|
3
|
+
'''
|
4
|
+
|
5
|
+
from langchain_core.messages import HumanMessage
|
6
|
+
from ..agents.t2b_agent import get_app
|
7
|
+
|
8
|
+
def test_get_modelinfo_tool():
|
9
|
+
'''
|
10
|
+
Test the get_modelinfo tool.
|
11
|
+
'''
|
12
|
+
unique_id = 12345
|
13
|
+
app = get_app(unique_id)
|
14
|
+
config = {"configurable": {"thread_id": unique_id}}
|
15
|
+
# Update state
|
16
|
+
app.update_state(config,
|
17
|
+
{"sbml_file_path": ["aiagents4pharma/talk2biomodels/tests/BIOMD0000000449_url.xml"]})
|
18
|
+
prompt = "Extract all relevant information from the uploaded model."
|
19
|
+
# Test the tool get_modelinfo
|
20
|
+
response = app.invoke(
|
21
|
+
{"messages": [HumanMessage(content=prompt)]},
|
22
|
+
config=config
|
23
|
+
)
|
24
|
+
assistant_msg = response["messages"][-1].content
|
25
|
+
# Check if the assistant message is a string
|
26
|
+
assert isinstance(assistant_msg, str)
|
@@ -0,0 +1,126 @@
|
|
1
|
+
'''
|
2
|
+
Test cases for Talk2Biomodels.
|
3
|
+
'''
|
4
|
+
|
5
|
+
import pandas as pd
|
6
|
+
from langchain_core.messages import HumanMessage, ToolMessage
|
7
|
+
from ..agents.t2b_agent import get_app
|
8
|
+
|
9
|
+
def test_integration():
|
10
|
+
'''
|
11
|
+
Test the integration of the tools.
|
12
|
+
'''
|
13
|
+
unique_id = 1234567
|
14
|
+
app = get_app(unique_id)
|
15
|
+
config = {"configurable": {"thread_id": unique_id}}
|
16
|
+
app.update_state(config, {"llm_model": "gpt-4o-mini"})
|
17
|
+
# ##########################################
|
18
|
+
# ## Test simulate_model tool
|
19
|
+
# ##########################################
|
20
|
+
prompt = '''Simulate the model 537 for 100 hours and intervals
|
21
|
+
100 with an initial concentration of `DoseQ2W`
|
22
|
+
set to 300 and `Dose` set to 0. Reset the concentration
|
23
|
+
of `Ab{serum}` to 100 every 25 hours.'''
|
24
|
+
# Test the tool get_modelinfo
|
25
|
+
response = app.invoke(
|
26
|
+
{"messages": [HumanMessage(content=prompt)]},
|
27
|
+
config=config
|
28
|
+
)
|
29
|
+
assistant_msg = response["messages"][-1].content
|
30
|
+
print (assistant_msg)
|
31
|
+
# Check if the assistant message is a string
|
32
|
+
assert isinstance(assistant_msg, str)
|
33
|
+
##########################################
|
34
|
+
# Test ask_question tool when simulation
|
35
|
+
# results are available
|
36
|
+
##########################################
|
37
|
+
# Update state
|
38
|
+
app.update_state(config, {"llm_model": "gpt-4o-mini"})
|
39
|
+
prompt = """What is the concentration of CRP in serum after 100 hours?
|
40
|
+
Round off the value to 2 decimal places."""
|
41
|
+
# Test the tool get_modelinfo
|
42
|
+
response = app.invoke(
|
43
|
+
{"messages": [HumanMessage(content=prompt)]},
|
44
|
+
config=config
|
45
|
+
)
|
46
|
+
assistant_msg = response["messages"][-1].content
|
47
|
+
# print (assistant_msg)
|
48
|
+
# Check if the assistant message is a string
|
49
|
+
assert '211' in assistant_msg
|
50
|
+
|
51
|
+
##########################################
|
52
|
+
# Test custom_plotter tool when the
|
53
|
+
# simulation results are available
|
54
|
+
##########################################
|
55
|
+
prompt = "Plot only CRP related species."
|
56
|
+
|
57
|
+
# Update state
|
58
|
+
app.update_state(config, {"llm_model": "gpt-4o-mini"}
|
59
|
+
)
|
60
|
+
# Test the tool get_modelinfo
|
61
|
+
response = app.invoke(
|
62
|
+
{"messages": [HumanMessage(content=prompt)]},
|
63
|
+
config=config
|
64
|
+
)
|
65
|
+
assistant_msg = response["messages"][-1].content
|
66
|
+
current_state = app.get_state(config)
|
67
|
+
# Get the messages from the current state
|
68
|
+
# and reverse the order
|
69
|
+
reversed_messages = current_state.values["messages"][::-1]
|
70
|
+
# Loop through the reversed messages
|
71
|
+
# until a ToolMessage is found.
|
72
|
+
expected_header = ['Time', 'CRP{serum}', 'CRPExtracellular']
|
73
|
+
expected_header += ['CRP Suppression (%)', 'CRP (% of baseline)']
|
74
|
+
expected_header += ['CRP{liver}']
|
75
|
+
predicted_artifact = []
|
76
|
+
for msg in reversed_messages:
|
77
|
+
if isinstance(msg, ToolMessage):
|
78
|
+
# Work on the message if it is a ToolMessage
|
79
|
+
# These may contain additional visuals that
|
80
|
+
# need to be displayed to the user.
|
81
|
+
if msg.name == "custom_plotter":
|
82
|
+
predicted_artifact = msg.artifact
|
83
|
+
break
|
84
|
+
# Convert the artifact into a pandas dataframe
|
85
|
+
# for easy comparison
|
86
|
+
df = pd.DataFrame(predicted_artifact)
|
87
|
+
# Extract the headers from the dataframe
|
88
|
+
predicted_header = df.columns.tolist()
|
89
|
+
# Check if the header is in the expected_header
|
90
|
+
# assert expected_header in predicted_artifact
|
91
|
+
assert set(expected_header).issubset(set(predicted_header))
|
92
|
+
##########################################
|
93
|
+
# Test custom_plotter tool when the
|
94
|
+
# simulation results are available but
|
95
|
+
# the species is not available
|
96
|
+
##########################################
|
97
|
+
prompt = """Make a custom plot showing the
|
98
|
+
concentration of the species `TP53` over
|
99
|
+
time. Do not show any other species."""
|
100
|
+
# Update state
|
101
|
+
app.update_state(config, {"llm_model": "gpt-4o-mini"}
|
102
|
+
)
|
103
|
+
# Test the tool get_modelinfo
|
104
|
+
response = app.invoke(
|
105
|
+
{"messages": [HumanMessage(content=prompt)]},
|
106
|
+
config=config
|
107
|
+
)
|
108
|
+
assistant_msg = response["messages"][-1].content
|
109
|
+
# print (response["messages"])
|
110
|
+
current_state = app.get_state(config)
|
111
|
+
# Get the messages from the current state
|
112
|
+
# and reverse the order
|
113
|
+
reversed_messages = current_state.values["messages"][::-1]
|
114
|
+
# Loop through the reversed messages until a
|
115
|
+
# ToolMessage is found.
|
116
|
+
predicted_artifact = []
|
117
|
+
for msg in reversed_messages:
|
118
|
+
if isinstance(msg, ToolMessage):
|
119
|
+
# Work on the message if it is a ToolMessage
|
120
|
+
# These may contain additional visuals that
|
121
|
+
# need to be displayed to the user.
|
122
|
+
if msg.name == "custom_plotter":
|
123
|
+
predicted_artifact = msg.artifact
|
124
|
+
break
|
125
|
+
# Check if the the predicted artifact is `None`
|
126
|
+
assert predicted_artifact is None
|
@@ -0,0 +1,68 @@
|
|
1
|
+
'''
|
2
|
+
Test cases for Talk2Biomodels parameter scan tool.
|
3
|
+
'''
|
4
|
+
|
5
|
+
import pandas as pd
|
6
|
+
from langchain_core.messages import HumanMessage, ToolMessage
|
7
|
+
from ..agents.t2b_agent import get_app
|
8
|
+
|
9
|
+
def test_param_scan_tool():
|
10
|
+
'''
|
11
|
+
In this test, we will test the parameter_scan tool.
|
12
|
+
We will prompt it to scan the parameter `kIL6RBind`
|
13
|
+
from 1 to 100 in steps of 10, record the changes
|
14
|
+
in the concentration of the species `Ab{serum}` in
|
15
|
+
model 537.
|
16
|
+
|
17
|
+
We will pass the inaccuarate parameter (`KIL6Rbind`)
|
18
|
+
and species names (just `Ab`) to the tool to test
|
19
|
+
if it can deal with it.
|
20
|
+
|
21
|
+
We expect the agent to first invoke the parameter_scan
|
22
|
+
tool and raise an error. It will then invoke another
|
23
|
+
tool get_modelinfo to get the correct parameter
|
24
|
+
and species names. Finally, the agent will reinvoke
|
25
|
+
the parameter_scan tool with the correct parameter
|
26
|
+
and species names.
|
27
|
+
|
28
|
+
'''
|
29
|
+
unique_id = 1234
|
30
|
+
app = get_app(unique_id)
|
31
|
+
config = {"configurable": {"thread_id": unique_id}}
|
32
|
+
app.update_state(config, {"llm_model": "gpt-4o-mini"})
|
33
|
+
prompt = """How will the value of Ab in serum in model 537 change
|
34
|
+
if the param kIL6Rbind is varied from 1 to 100 in steps of 10?
|
35
|
+
Set the initial `DoseQ2W` concentration to 300. Assume
|
36
|
+
that the model is simulated for 2016 hours with an interval of 50."""
|
37
|
+
# Invoke the agent
|
38
|
+
app.invoke(
|
39
|
+
{"messages": [HumanMessage(content=prompt)]},
|
40
|
+
config=config
|
41
|
+
)
|
42
|
+
current_state = app.get_state(config)
|
43
|
+
reversed_messages = current_state.values["messages"][::-1]
|
44
|
+
# Loop through the reversed messages until a
|
45
|
+
# ToolMessage is found.
|
46
|
+
df = pd.DataFrame(columns=['name', 'status', 'content'])
|
47
|
+
names = []
|
48
|
+
statuses = []
|
49
|
+
contents = []
|
50
|
+
for msg in reversed_messages:
|
51
|
+
# Assert that the message is a ToolMessage
|
52
|
+
# and its status is "error"
|
53
|
+
if not isinstance(msg, ToolMessage):
|
54
|
+
continue
|
55
|
+
names.append(msg.name)
|
56
|
+
statuses.append(msg.status)
|
57
|
+
contents.append(msg.content)
|
58
|
+
df = pd.DataFrame({'name': names, 'status': statuses, 'content': contents})
|
59
|
+
# print (df)
|
60
|
+
assert any((df["status"] == "error") &
|
61
|
+
(df["name"] == "parameter_scan") &
|
62
|
+
(df["content"].str.startswith(
|
63
|
+
"Error: ValueError('Invalid species or parameter name:")))
|
64
|
+
assert any((df["status"] == "success") &
|
65
|
+
(df["name"] == "parameter_scan") &
|
66
|
+
(df["content"].str.startswith("Parameter scan results of")))
|
67
|
+
assert any((df["status"] == "success") &
|
68
|
+
(df["name"] == "get_modelinfo"))
|
@@ -0,0 +1,28 @@
|
|
1
|
+
'''
|
2
|
+
Test cases for Talk2Biomodels search models tool.
|
3
|
+
'''
|
4
|
+
|
5
|
+
from langchain_core.messages import HumanMessage
|
6
|
+
from ..agents.t2b_agent import get_app
|
7
|
+
|
8
|
+
def test_search_models_tool():
|
9
|
+
'''
|
10
|
+
Test the search_models tool.
|
11
|
+
'''
|
12
|
+
unique_id = 12345
|
13
|
+
app = get_app(unique_id)
|
14
|
+
config = {"configurable": {"thread_id": unique_id}}
|
15
|
+
# Update state
|
16
|
+
app.update_state(config, {"llm_model": "gpt-4o-mini"})
|
17
|
+
prompt = "Search for models on Crohn's disease."
|
18
|
+
# Test the tool get_modelinfo
|
19
|
+
response = app.invoke(
|
20
|
+
{"messages": [HumanMessage(content=prompt)]},
|
21
|
+
config=config
|
22
|
+
)
|
23
|
+
assistant_msg = response["messages"][-1].content
|
24
|
+
# Check if the assistant message is a string
|
25
|
+
assert isinstance(assistant_msg, str)
|
26
|
+
# Check if the assistant message contains the
|
27
|
+
# biomodel id BIO0000000537
|
28
|
+
assert "BIOMD0000000537" in assistant_msg
|
@@ -0,0 +1,39 @@
|
|
1
|
+
'''
|
2
|
+
Test cases for Talk2Biomodels.
|
3
|
+
'''
|
4
|
+
|
5
|
+
from langchain_core.messages import HumanMessage
|
6
|
+
from ..agents.t2b_agent import get_app
|
7
|
+
|
8
|
+
def test_simulate_model_tool():
|
9
|
+
'''
|
10
|
+
Test the simulate_model tool when simulating
|
11
|
+
multiple models.
|
12
|
+
'''
|
13
|
+
unique_id = 123
|
14
|
+
app = get_app(unique_id)
|
15
|
+
config = {"configurable": {"thread_id": unique_id}}
|
16
|
+
app.update_state(config, {"llm_model": "gpt-4o-mini"})
|
17
|
+
# Upload a model to the state
|
18
|
+
app.update_state(config,
|
19
|
+
{"sbml_file_path": ["aiagents4pharma/talk2biomodels/tests/BIOMD0000000449_url.xml"]})
|
20
|
+
prompt = "Simulate model 64 and the uploaded model"
|
21
|
+
# Invoke the agent
|
22
|
+
app.invoke(
|
23
|
+
{"messages": [HumanMessage(content=prompt)]},
|
24
|
+
config=config
|
25
|
+
)
|
26
|
+
current_state = app.get_state(config)
|
27
|
+
dic_simulated_data = current_state.values["dic_simulated_data"]
|
28
|
+
# Check if the dic_simulated_data is a list
|
29
|
+
assert isinstance(dic_simulated_data, list)
|
30
|
+
# Check if the length of the dic_simulated_data is 2
|
31
|
+
assert len(dic_simulated_data) == 2
|
32
|
+
# Check if the source of the first model is 64
|
33
|
+
assert dic_simulated_data[0]['source'] == 64
|
34
|
+
# Check if the source of the second model is upload
|
35
|
+
assert dic_simulated_data[1]['source'] == "upload"
|
36
|
+
# Check if the data of the first model contains
|
37
|
+
assert '1,3-bisphosphoglycerate' in dic_simulated_data[0]['data']
|
38
|
+
# Check if the data of the second model contains
|
39
|
+
assert 'mTORC2' in dic_simulated_data[1]['data']
|