aiagents4pharma 1.14.0__py3-none-any.whl → 1.14.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. aiagents4pharma/configs/config.yaml +2 -1
  2. aiagents4pharma/configs/talk2biomodels/__init__.py +1 -0
  3. aiagents4pharma/configs/talk2biomodels/agents/t2b_agent/default.yaml +2 -3
  4. aiagents4pharma/configs/talk2biomodels/tools/__init__.py +4 -0
  5. aiagents4pharma/configs/talk2biomodels/tools/ask_question/__init__.py +3 -0
  6. aiagents4pharma/talk2biomodels/states/state_talk2biomodels.py +21 -7
  7. aiagents4pharma/talk2biomodels/tests/test_ask_question.py +44 -0
  8. aiagents4pharma/talk2biomodels/tests/test_get_annotation.py +67 -69
  9. aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py +26 -0
  10. aiagents4pharma/talk2biomodels/tests/test_integration.py +126 -0
  11. aiagents4pharma/talk2biomodels/tests/test_param_scan.py +68 -0
  12. aiagents4pharma/talk2biomodels/tests/test_search_models.py +28 -0
  13. aiagents4pharma/talk2biomodels/tests/test_simulate_model.py +39 -0
  14. aiagents4pharma/talk2biomodels/tests/test_steady_state.py +90 -0
  15. aiagents4pharma/talk2biomodels/tools/ask_question.py +29 -8
  16. aiagents4pharma/talk2biomodels/tools/get_annotation.py +24 -9
  17. aiagents4pharma/talk2biomodels/tools/load_arguments.py +114 -0
  18. aiagents4pharma/talk2biomodels/tools/parameter_scan.py +91 -96
  19. aiagents4pharma/talk2biomodels/tools/simulate_model.py +14 -81
  20. aiagents4pharma/talk2biomodels/tools/steady_state.py +48 -89
  21. {aiagents4pharma-1.14.0.dist-info → aiagents4pharma-1.14.1.dist-info}/METADATA +1 -1
  22. {aiagents4pharma-1.14.0.dist-info → aiagents4pharma-1.14.1.dist-info}/RECORD +25 -16
  23. aiagents4pharma/talk2biomodels/tests/test_langgraph.py +0 -384
  24. {aiagents4pharma-1.14.0.dist-info → aiagents4pharma-1.14.1.dist-info}/LICENSE +0 -0
  25. {aiagents4pharma-1.14.0.dist-info → aiagents4pharma-1.14.1.dist-info}/WHEEL +0 -0
  26. {aiagents4pharma-1.14.0.dist-info → aiagents4pharma-1.14.1.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
1
  defaults:
2
2
  - _self_
3
- - talk2biomodels/agents/t2b_agent: default
3
+ - talk2biomodels/agents/t2b_agent: default
4
+ - talk2biomodels/tools/ask_question: default
@@ -3,3 +3,4 @@ Import all the modules in the package
3
3
  '''
4
4
 
5
5
  from . import agents
6
+ from . import tools
@@ -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 value for the
8
- `simulation_name` or `steadystate_name`
9
- argument.
7
+ or param_scan or steady state, suggest a
8
+ value for the `experiment_name` argument.
@@ -0,0 +1,4 @@
1
+ '''
2
+ Import all the modules in the package
3
+ '''
4
+ from . import ask_question
@@ -0,0 +1,3 @@
1
+ '''
2
+ Import all the modules in the package
3
+ '''
@@ -8,19 +8,33 @@ from typing import Annotated
8
8
  import operator
9
9
  from langgraph.prebuilt.chat_agent_executor import AgentState
10
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
+
11
25
  class Talk2Biomodels(AgentState):
12
26
  """
13
27
  The state for the Talk2BioModels agent.
14
28
  """
15
29
  llm_model: str
16
30
  # A StateGraph may receive a concurrent updates
17
- # which is not supported by the StateGraph.
18
- # Therefore, we need to use Annotated to specify
19
- # the operator for the sbml_file_path field.
31
+ # which is not supported by the StateGraph. Hence,
32
+ # we need to add a reducer function to handle the
33
+ # concurrent updates.
20
34
  # https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE/
21
35
  model_id: Annotated[list, operator.add]
22
36
  sbml_file_path: Annotated[list, operator.add]
23
- dic_simulated_data: Annotated[list[dict], operator.add]
24
- dic_scanned_data: Annotated[list[dict], operator.add]
25
- dic_steady_state_data: Annotated[list[dict], operator.add]
26
- dic_annotations_data : Annotated[list[dict], 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 test_species_list(make_graph):
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 passing species names.
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 test_all_species(make_graph):
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
- model 12 contains species with no URL.
95
- model 20 contains species without description.
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
- # Test valid models
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
- if isinstance(msg, ToolMessage) and msg.name == "get_annotation":
116
- if model_id == 12:
117
- # For model 12:
118
- # Expect a successful extraction (artifact is True) and that the content
119
- # matches what is returned by prepare_content_msg for species ['lac'].
120
- if (msg.artifact is True and msg.content == prepare_content_msg(['lac'],[])
121
- and msg.status=="success"):
122
- test_condition = True
123
- break
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
- test_condition = False
164
- for msg in reversed_messages:
165
- # Assert that the one of the messages is a ToolMessage
166
- if isinstance(msg, ToolMessage) and msg.name == "get_annotation":
167
- if "Error:" in msg.content and msg.status == "error":
168
- test_condition = True
169
- break
170
- # Loop through the reversed messages until a
171
- # ToolMessage is found.
172
- # Ensure the system correctly informs the user to specify a model
173
- assert test_condition, "Expected error message when no model is specified was not found."
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']