tooluniverse 0.2.0__py3-none-any.whl → 1.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.
Potentially problematic release.
This version of tooluniverse might be problematic. Click here for more details.
- tooluniverse/__init__.py +340 -4
- tooluniverse/admetai_tool.py +84 -0
- tooluniverse/agentic_tool.py +563 -0
- tooluniverse/alphafold_tool.py +96 -0
- tooluniverse/base_tool.py +129 -6
- tooluniverse/boltz_tool.py +207 -0
- tooluniverse/chem_tool.py +192 -0
- tooluniverse/compose_scripts/__init__.py +1 -0
- tooluniverse/compose_scripts/biomarker_discovery.py +293 -0
- tooluniverse/compose_scripts/comprehensive_drug_discovery.py +186 -0
- tooluniverse/compose_scripts/drug_safety_analyzer.py +89 -0
- tooluniverse/compose_scripts/literature_tool.py +34 -0
- tooluniverse/compose_scripts/output_summarizer.py +279 -0
- tooluniverse/compose_scripts/tool_description_optimizer.py +681 -0
- tooluniverse/compose_scripts/tool_discover.py +705 -0
- tooluniverse/compose_scripts/tool_graph_composer.py +448 -0
- tooluniverse/compose_tool.py +371 -0
- tooluniverse/ctg_tool.py +1002 -0
- tooluniverse/custom_tool.py +81 -0
- tooluniverse/dailymed_tool.py +108 -0
- tooluniverse/data/admetai_tools.json +155 -0
- tooluniverse/data/agentic_tools.json +1156 -0
- tooluniverse/data/alphafold_tools.json +87 -0
- tooluniverse/data/boltz_tools.json +9 -0
- tooluniverse/data/chembl_tools.json +16 -0
- tooluniverse/data/clait_tools.json +108 -0
- tooluniverse/data/clinicaltrials_gov_tools.json +326 -0
- tooluniverse/data/compose_tools.json +202 -0
- tooluniverse/data/dailymed_tools.json +70 -0
- tooluniverse/data/dataset_tools.json +646 -0
- tooluniverse/data/disease_target_score_tools.json +712 -0
- tooluniverse/data/efo_tools.json +17 -0
- tooluniverse/data/embedding_tools.json +319 -0
- tooluniverse/data/enrichr_tools.json +31 -0
- tooluniverse/data/europe_pmc_tools.json +22 -0
- tooluniverse/data/expert_feedback_tools.json +10 -0
- tooluniverse/data/fda_drug_adverse_event_tools.json +491 -0
- tooluniverse/data/fda_drug_labeling_tools.json +1 -1
- tooluniverse/data/fda_drugs_with_brand_generic_names_for_tool.py +76929 -148860
- tooluniverse/data/finder_tools.json +209 -0
- tooluniverse/data/gene_ontology_tools.json +113 -0
- tooluniverse/data/gwas_tools.json +1082 -0
- tooluniverse/data/hpa_tools.json +333 -0
- tooluniverse/data/humanbase_tools.json +47 -0
- tooluniverse/data/idmap_tools.json +74 -0
- tooluniverse/data/mcp_client_tools_example.json +113 -0
- tooluniverse/data/mcpautoloadertool_defaults.json +28 -0
- tooluniverse/data/medlineplus_tools.json +141 -0
- tooluniverse/data/monarch_tools.json +1 -1
- tooluniverse/data/openalex_tools.json +36 -0
- tooluniverse/data/opentarget_tools.json +1 -1
- tooluniverse/data/output_summarization_tools.json +101 -0
- tooluniverse/data/packages/bioinformatics_core_tools.json +1756 -0
- tooluniverse/data/packages/categorized_tools.txt +206 -0
- tooluniverse/data/packages/cheminformatics_tools.json +347 -0
- tooluniverse/data/packages/earth_sciences_tools.json +74 -0
- tooluniverse/data/packages/genomics_tools.json +776 -0
- tooluniverse/data/packages/image_processing_tools.json +38 -0
- tooluniverse/data/packages/machine_learning_tools.json +789 -0
- tooluniverse/data/packages/neuroscience_tools.json +62 -0
- tooluniverse/data/packages/original_tools.txt +0 -0
- tooluniverse/data/packages/physics_astronomy_tools.json +62 -0
- tooluniverse/data/packages/scientific_computing_tools.json +560 -0
- tooluniverse/data/packages/single_cell_tools.json +453 -0
- tooluniverse/data/packages/software_tools.json +4954 -0
- tooluniverse/data/packages/structural_biology_tools.json +396 -0
- tooluniverse/data/packages/visualization_tools.json +399 -0
- tooluniverse/data/pubchem_tools.json +215 -0
- tooluniverse/data/pubtator_tools.json +68 -0
- tooluniverse/data/rcsb_pdb_tools.json +1332 -0
- tooluniverse/data/reactome_tools.json +19 -0
- tooluniverse/data/semantic_scholar_tools.json +26 -0
- tooluniverse/data/special_tools.json +2 -25
- tooluniverse/data/tool_composition_tools.json +88 -0
- tooluniverse/data/toolfinderkeyword_defaults.json +34 -0
- tooluniverse/data/txagent_client_tools.json +9 -0
- tooluniverse/data/uniprot_tools.json +211 -0
- tooluniverse/data/url_fetch_tools.json +94 -0
- tooluniverse/data/uspto_downloader_tools.json +9 -0
- tooluniverse/data/uspto_tools.json +811 -0
- tooluniverse/data/xml_tools.json +3275 -0
- tooluniverse/dataset_tool.py +296 -0
- tooluniverse/default_config.py +165 -0
- tooluniverse/efo_tool.py +42 -0
- tooluniverse/embedding_database.py +630 -0
- tooluniverse/embedding_sync.py +396 -0
- tooluniverse/enrichr_tool.py +266 -0
- tooluniverse/europe_pmc_tool.py +52 -0
- tooluniverse/execute_function.py +1775 -95
- tooluniverse/extended_hooks.py +444 -0
- tooluniverse/gene_ontology_tool.py +194 -0
- tooluniverse/graphql_tool.py +158 -36
- tooluniverse/gwas_tool.py +358 -0
- tooluniverse/hpa_tool.py +1645 -0
- tooluniverse/humanbase_tool.py +389 -0
- tooluniverse/logging_config.py +254 -0
- tooluniverse/mcp_client_tool.py +764 -0
- tooluniverse/mcp_integration.py +413 -0
- tooluniverse/mcp_tool_registry.py +925 -0
- tooluniverse/medlineplus_tool.py +337 -0
- tooluniverse/openalex_tool.py +228 -0
- tooluniverse/openfda_adv_tool.py +283 -0
- tooluniverse/openfda_tool.py +393 -160
- tooluniverse/output_hook.py +1122 -0
- tooluniverse/package_tool.py +195 -0
- tooluniverse/pubchem_tool.py +158 -0
- tooluniverse/pubtator_tool.py +168 -0
- tooluniverse/rcsb_pdb_tool.py +38 -0
- tooluniverse/reactome_tool.py +108 -0
- tooluniverse/remote/boltz/boltz_mcp_server.py +50 -0
- tooluniverse/remote/depmap_24q2/depmap_24q2_mcp_tool.py +442 -0
- tooluniverse/remote/expert_feedback/human_expert_mcp_tools.py +2013 -0
- tooluniverse/remote/expert_feedback/simple_test.py +23 -0
- tooluniverse/remote/expert_feedback/start_web_interface.py +188 -0
- tooluniverse/remote/expert_feedback/web_only_interface.py +0 -0
- tooluniverse/remote/expert_feedback_mcp/human_expert_mcp_server.py +1611 -0
- tooluniverse/remote/expert_feedback_mcp/simple_test.py +34 -0
- tooluniverse/remote/expert_feedback_mcp/start_web_interface.py +91 -0
- tooluniverse/remote/immune_compass/compass_tool.py +327 -0
- tooluniverse/remote/pinnacle/pinnacle_tool.py +328 -0
- tooluniverse/remote/transcriptformer/transcriptformer_tool.py +586 -0
- tooluniverse/remote/uspto_downloader/uspto_downloader_mcp_server.py +61 -0
- tooluniverse/remote/uspto_downloader/uspto_downloader_tool.py +120 -0
- tooluniverse/remote_tool.py +99 -0
- tooluniverse/restful_tool.py +53 -30
- tooluniverse/scripts/generate_tool_graph.py +408 -0
- tooluniverse/scripts/visualize_tool_graph.py +829 -0
- tooluniverse/semantic_scholar_tool.py +62 -0
- tooluniverse/smcp.py +2452 -0
- tooluniverse/smcp_server.py +975 -0
- tooluniverse/test/mcp_server_test.py +0 -0
- tooluniverse/test/test_admetai_tool.py +370 -0
- tooluniverse/test/test_agentic_tool.py +129 -0
- tooluniverse/test/test_alphafold_tool.py +71 -0
- tooluniverse/test/test_chem_tool.py +37 -0
- tooluniverse/test/test_compose_lieraturereview.py +63 -0
- tooluniverse/test/test_compose_tool.py +448 -0
- tooluniverse/test/test_dailymed.py +69 -0
- tooluniverse/test/test_dataset_tool.py +200 -0
- tooluniverse/test/test_disease_target_score.py +56 -0
- tooluniverse/test/test_drugbank_filter_examples.py +179 -0
- tooluniverse/test/test_efo.py +31 -0
- tooluniverse/test/test_enrichr_tool.py +21 -0
- tooluniverse/test/test_europe_pmc_tool.py +20 -0
- tooluniverse/test/test_fda_adv.py +95 -0
- tooluniverse/test/test_fda_drug_labeling.py +91 -0
- tooluniverse/test/test_gene_ontology_tools.py +66 -0
- tooluniverse/test/test_gwas_tool.py +139 -0
- tooluniverse/test/test_hpa.py +625 -0
- tooluniverse/test/test_humanbase_tool.py +20 -0
- tooluniverse/test/test_idmap_tools.py +61 -0
- tooluniverse/test/test_mcp_server.py +211 -0
- tooluniverse/test/test_mcp_tool.py +247 -0
- tooluniverse/test/test_medlineplus.py +220 -0
- tooluniverse/test/test_openalex_tool.py +32 -0
- tooluniverse/test/test_opentargets.py +28 -0
- tooluniverse/test/test_pubchem_tool.py +116 -0
- tooluniverse/test/test_pubtator_tool.py +37 -0
- tooluniverse/test/test_rcsb_pdb_tool.py +86 -0
- tooluniverse/test/test_reactome.py +54 -0
- tooluniverse/test/test_semantic_scholar_tool.py +24 -0
- tooluniverse/test/test_software_tools.py +147 -0
- tooluniverse/test/test_tool_description_optimizer.py +49 -0
- tooluniverse/test/test_tool_finder.py +26 -0
- tooluniverse/test/test_tool_finder_llm.py +252 -0
- tooluniverse/test/test_tools_find.py +195 -0
- tooluniverse/test/test_uniprot_tools.py +74 -0
- tooluniverse/test/test_uspto_tool.py +72 -0
- tooluniverse/test/test_xml_tool.py +113 -0
- tooluniverse/tool_finder_embedding.py +267 -0
- tooluniverse/tool_finder_keyword.py +693 -0
- tooluniverse/tool_finder_llm.py +699 -0
- tooluniverse/tool_graph_web_ui.py +955 -0
- tooluniverse/tool_registry.py +416 -0
- tooluniverse/uniprot_tool.py +155 -0
- tooluniverse/url_tool.py +253 -0
- tooluniverse/uspto_tool.py +240 -0
- tooluniverse/utils.py +369 -41
- tooluniverse/xml_tool.py +369 -0
- tooluniverse-1.0.0.dist-info/METADATA +377 -0
- tooluniverse-1.0.0.dist-info/RECORD +186 -0
- tooluniverse-1.0.0.dist-info/entry_points.txt +9 -0
- tooluniverse/generate_mcp_tools.py +0 -113
- tooluniverse/mcp_server.py +0 -3340
- tooluniverse-0.2.0.dist-info/METADATA +0 -139
- tooluniverse-0.2.0.dist-info/RECORD +0 -21
- tooluniverse-0.2.0.dist-info/entry_points.txt +0 -4
- {tooluniverse-0.2.0.dist-info → tooluniverse-1.0.0.dist-info}/WHEEL +0 -0
- {tooluniverse-0.2.0.dist-info → tooluniverse-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {tooluniverse-0.2.0.dist-info → tooluniverse-1.0.0.dist-info}/top_level.txt +0 -0
tooluniverse/utils.py
CHANGED
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
import yaml
|
|
2
2
|
import json
|
|
3
|
+
import re
|
|
4
|
+
import hashlib
|
|
5
|
+
import os
|
|
6
|
+
from typing import Dict, Any, Union, List
|
|
7
|
+
from huggingface_hub import hf_hub_download
|
|
8
|
+
from pydantic._internal._model_construction import ModelMetaclass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def download_from_hf(tool_config):
|
|
12
|
+
# Extract dataset configuration
|
|
13
|
+
hf_parameters = tool_config.get("hf_dataset_path")
|
|
14
|
+
relative_local_path = hf_parameters.get("save_to_local_dir")
|
|
15
|
+
|
|
16
|
+
# Compute absolute path to save locally
|
|
17
|
+
if not os.path.isabs(relative_local_path):
|
|
18
|
+
project_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
|
19
|
+
absolute_local_dir = os.path.join(project_root, relative_local_path)
|
|
20
|
+
else:
|
|
21
|
+
absolute_local_dir = relative_local_path
|
|
22
|
+
|
|
23
|
+
# Ensure the directory exists
|
|
24
|
+
os.makedirs(absolute_local_dir, exist_ok=True)
|
|
25
|
+
|
|
26
|
+
# Download the CSV from Hugging Face Hub
|
|
27
|
+
try:
|
|
28
|
+
# Prepare download arguments
|
|
29
|
+
download_args = {
|
|
30
|
+
"repo_id": hf_parameters.get("repo_id"),
|
|
31
|
+
"filename": hf_parameters.get("path_in_repo"),
|
|
32
|
+
"repo_type": "dataset",
|
|
33
|
+
"local_dir": absolute_local_dir,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Only add token if it's not None and not empty
|
|
37
|
+
token = hf_parameters.get("token")
|
|
38
|
+
if token is not None and token.strip():
|
|
39
|
+
download_args["token"] = token
|
|
40
|
+
else:
|
|
41
|
+
download_args["token"] = False
|
|
42
|
+
|
|
43
|
+
downloaded_path = hf_hub_download(**download_args)
|
|
44
|
+
|
|
45
|
+
# The downloaded file path is returned by hf_hub_download
|
|
46
|
+
result = {"success": True, "local_path": downloaded_path}
|
|
47
|
+
except Exception as e:
|
|
48
|
+
result = {"success": False, "error": str(e)}
|
|
49
|
+
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_md5(input_str):
|
|
54
|
+
# Create an MD5 hash object
|
|
55
|
+
md5_hash = hashlib.md5()
|
|
56
|
+
|
|
57
|
+
# Encode the string and update the hash object
|
|
58
|
+
md5_hash.update(input_str.encode("utf-8"))
|
|
59
|
+
|
|
60
|
+
# Return the hexadecimal MD5 digest
|
|
61
|
+
return md5_hash.hexdigest()
|
|
3
62
|
|
|
4
63
|
|
|
5
64
|
def yaml_to_dict(yaml_file_path):
|
|
@@ -13,7 +72,7 @@ def yaml_to_dict(yaml_file_path):
|
|
|
13
72
|
dict: Dictionary representation of the YAML file content.
|
|
14
73
|
"""
|
|
15
74
|
try:
|
|
16
|
-
with open(yaml_file_path,
|
|
75
|
+
with open(yaml_file_path, "r") as file:
|
|
17
76
|
yaml_dict = yaml.safe_load(file)
|
|
18
77
|
return yaml_dict
|
|
19
78
|
except FileNotFoundError:
|
|
@@ -32,7 +91,7 @@ def read_json_list(file_path):
|
|
|
32
91
|
Returns:
|
|
33
92
|
list: A list of dictionaries containing the JSON objects.
|
|
34
93
|
"""
|
|
35
|
-
with open(file_path,
|
|
94
|
+
with open(file_path, "r") as file:
|
|
36
95
|
data = json.load(file)
|
|
37
96
|
return data
|
|
38
97
|
|
|
@@ -45,18 +104,30 @@ def evaluate_function_call(tool_definition, function_call):
|
|
|
45
104
|
"number": float,
|
|
46
105
|
"boolean": bool,
|
|
47
106
|
"array": list,
|
|
48
|
-
"object": dict
|
|
107
|
+
"object": dict,
|
|
108
|
+
"pydantic": ModelMetaclass,
|
|
49
109
|
}
|
|
50
110
|
|
|
51
111
|
# Check if the function name matches
|
|
52
112
|
if tool_definition["name"] != function_call["name"]:
|
|
53
113
|
return False, "Function name does not match."
|
|
54
114
|
|
|
115
|
+
# Handle the case where properties is None (no arguments expected)
|
|
116
|
+
if tool_definition["parameter"]["properties"] is None:
|
|
117
|
+
# If properties is None, the function should not have any arguments
|
|
118
|
+
if function_call.get("arguments") and len(function_call["arguments"]) > 0:
|
|
119
|
+
return False, "This function does not accept any arguments."
|
|
120
|
+
return True, "Function call is valid."
|
|
121
|
+
|
|
55
122
|
# Check if all required parameters are present
|
|
56
|
-
required_params = [
|
|
57
|
-
|
|
123
|
+
required_params = [
|
|
124
|
+
key
|
|
125
|
+
for key, value in tool_definition["parameter"]["properties"].items()
|
|
126
|
+
if value.get("required", False)
|
|
127
|
+
]
|
|
58
128
|
missing_params = [
|
|
59
|
-
param for param in required_params if param not in function_call["arguments"]
|
|
129
|
+
param for param in required_params if param not in function_call["arguments"]
|
|
130
|
+
]
|
|
60
131
|
if missing_params:
|
|
61
132
|
return False, f"Missing required parameters: {missing_params}"
|
|
62
133
|
|
|
@@ -69,12 +140,37 @@ def evaluate_function_call(tool_definition, function_call):
|
|
|
69
140
|
if param not in valid_params:
|
|
70
141
|
invalid_params.append(param)
|
|
71
142
|
else:
|
|
72
|
-
|
|
143
|
+
param_schema = valid_params[param]
|
|
144
|
+
|
|
145
|
+
# Handle both simple and complex parameter schemas
|
|
146
|
+
expected_type = None
|
|
147
|
+
|
|
148
|
+
# Case 1: Simple schema with direct "type" field
|
|
149
|
+
if "type" in param_schema:
|
|
150
|
+
expected_type = param_schema["type"]
|
|
151
|
+
|
|
152
|
+
# Case 2: Complex schema with "anyOf" (common in MCP tools)
|
|
153
|
+
elif "anyOf" in param_schema:
|
|
154
|
+
# Extract the primary type from anyOf, ignoring null types
|
|
155
|
+
for type_option in param_schema["anyOf"]:
|
|
156
|
+
if type_option.get("type") and type_option["type"] != "null":
|
|
157
|
+
expected_type = type_option["type"]
|
|
158
|
+
break
|
|
159
|
+
|
|
160
|
+
# If we still don't have a type, skip validation for this parameter
|
|
161
|
+
if not expected_type:
|
|
162
|
+
continue
|
|
163
|
+
|
|
73
164
|
if expected_type not in type_map:
|
|
74
165
|
return False, f"Unsupported parameter type: {expected_type}"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
166
|
+
|
|
167
|
+
# Special handling for 'number' type which should accept both int and float
|
|
168
|
+
if expected_type == "number":
|
|
169
|
+
if not isinstance(value, (int, float)):
|
|
170
|
+
type_mismatches.append((param, expected_type, type(value).__name__))
|
|
171
|
+
else:
|
|
172
|
+
if not isinstance(value, type_map[expected_type]):
|
|
173
|
+
type_mismatches.append((param, expected_type, type(value).__name__))
|
|
78
174
|
|
|
79
175
|
if invalid_params:
|
|
80
176
|
return False, f"Invalid parameters provided: {invalid_params}"
|
|
@@ -84,6 +180,7 @@ def evaluate_function_call(tool_definition, function_call):
|
|
|
84
180
|
|
|
85
181
|
return True, "Function call is valid."
|
|
86
182
|
|
|
183
|
+
|
|
87
184
|
def evaluate_function_call_from_toolbox(toolbox, function_call):
|
|
88
185
|
tool_name = function_call["name"]
|
|
89
186
|
this_tool_dec = toolbox.get_one_tool_by_one_name(tool_name)
|
|
@@ -91,9 +188,11 @@ def evaluate_function_call_from_toolbox(toolbox, function_call):
|
|
|
91
188
|
return False, "Tool not found."
|
|
92
189
|
results, results_message = evaluate_function_call(this_tool_dec, function_call)
|
|
93
190
|
return results, results_message
|
|
94
|
-
|
|
95
191
|
|
|
96
|
-
|
|
192
|
+
|
|
193
|
+
def compare_function_calls(
|
|
194
|
+
pred_function_call, gt_function_call, compare_arguments=True, compare_value=True
|
|
195
|
+
):
|
|
97
196
|
# Extracting the name and arguments from the predicted function call
|
|
98
197
|
pred_name = pred_function_call["name"]
|
|
99
198
|
pred_arguments = pred_function_call["arguments"]
|
|
@@ -111,7 +210,10 @@ def compare_function_calls(pred_function_call, gt_function_call, compare_argumen
|
|
|
111
210
|
if set(pred_arguments.keys()) != set(gt_arguments.keys()):
|
|
112
211
|
missing_in_pred = set(gt_arguments.keys()) - set(pred_arguments.keys())
|
|
113
212
|
missing_in_gt = set(pred_arguments.keys()) - set(gt_arguments.keys())
|
|
114
|
-
return
|
|
213
|
+
return (
|
|
214
|
+
False,
|
|
215
|
+
f"Argument keys do not match. Missing in predicted: {missing_in_pred}, Missing in ground truth: {missing_in_gt}",
|
|
216
|
+
)
|
|
115
217
|
if compare_value:
|
|
116
218
|
# Compare argument values
|
|
117
219
|
mismatched_values = []
|
|
@@ -125,12 +227,12 @@ def compare_function_calls(pred_function_call, gt_function_call, compare_argumen
|
|
|
125
227
|
return True, "Function calls match."
|
|
126
228
|
|
|
127
229
|
|
|
128
|
-
def extract_function_call_json(lst, return_message=False, verbose=True):
|
|
230
|
+
def extract_function_call_json(lst, return_message=False, verbose=True, format="llama"):
|
|
129
231
|
if type(lst) is dict:
|
|
130
232
|
if return_message:
|
|
131
233
|
return lst, ""
|
|
132
234
|
return lst
|
|
133
|
-
result_str =
|
|
235
|
+
result_str = "".join(lst)
|
|
134
236
|
if verbose:
|
|
135
237
|
print("\033[1;34mPossible LLM outputs for function call:\033[0m", result_str)
|
|
136
238
|
try:
|
|
@@ -140,33 +242,259 @@ def extract_function_call_json(lst, return_message=False, verbose=True):
|
|
|
140
242
|
return function_call_json
|
|
141
243
|
except json.JSONDecodeError:
|
|
142
244
|
try:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
245
|
+
if format == "llama":
|
|
246
|
+
index_start = result_str.find("[TOOL_CALLS]")
|
|
247
|
+
index_end = result_str.find("</s>")
|
|
248
|
+
if index_end == -1:
|
|
249
|
+
index_end = result_str.find("<|eom_id|>")
|
|
250
|
+
if index_end == -1:
|
|
251
|
+
function_call_str = result_str[index_start + len("[TOOL_CALLS]") :]
|
|
252
|
+
else:
|
|
253
|
+
function_call_str = result_str[
|
|
254
|
+
index_start + len("[TOOL_CALLS]") : index_end
|
|
255
|
+
]
|
|
256
|
+
# print("function_call_str", function_call_str)
|
|
257
|
+
function_call_json = json.loads(function_call_str.strip())
|
|
258
|
+
elif format == "qwen":
|
|
259
|
+
index_start = result_str.find("<tool_call>")
|
|
260
|
+
function_call_str = result_str[index_start:]
|
|
261
|
+
|
|
262
|
+
pattern = re.compile(r"<tool_call>(.*?)</tool_call>", re.DOTALL)
|
|
263
|
+
matches = pattern.findall(function_call_str)
|
|
264
|
+
function_call_json = []
|
|
265
|
+
|
|
266
|
+
for match in matches:
|
|
267
|
+
# Clean up the JSON string
|
|
268
|
+
json_str = match.strip()
|
|
269
|
+
data = json.loads(json_str)
|
|
270
|
+
function_call_json.append(data)
|
|
271
|
+
|
|
154
272
|
if return_message:
|
|
155
273
|
message = result_str[:index_start]
|
|
156
274
|
return function_call_json, message
|
|
157
275
|
return function_call_json
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
276
|
+
|
|
277
|
+
except json.JSONDecodeError as e:
|
|
278
|
+
print("Not a function call:", e)
|
|
279
|
+
if return_message:
|
|
280
|
+
return None, result_str
|
|
281
|
+
return None
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def validate_query(query: Dict[str, Any]) -> bool:
|
|
285
|
+
"""
|
|
286
|
+
Validate a query dictionary for required fields and structure.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
query (Dict[str, Any]): The query dictionary to validate
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
bool: True if query is valid, False otherwise
|
|
293
|
+
"""
|
|
294
|
+
if not isinstance(query, dict):
|
|
295
|
+
return False
|
|
296
|
+
|
|
297
|
+
# Check for basic required fields (customize based on your needs)
|
|
298
|
+
required_fields = ["query", "parameters"]
|
|
299
|
+
for field in required_fields:
|
|
300
|
+
if field not in query:
|
|
301
|
+
return False
|
|
302
|
+
|
|
303
|
+
# Additional validation logic can be added here
|
|
304
|
+
return True
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def normalize_gene_symbol(gene_symbol: str) -> str:
|
|
308
|
+
"""
|
|
309
|
+
Normalize a gene symbol to standard format.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
gene_symbol (str): The gene symbol to normalize
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
str: Normalized gene symbol
|
|
316
|
+
"""
|
|
317
|
+
if not isinstance(gene_symbol, str):
|
|
318
|
+
return str(gene_symbol)
|
|
319
|
+
|
|
320
|
+
# Convert to uppercase and strip whitespace
|
|
321
|
+
normalized = gene_symbol.strip().upper()
|
|
322
|
+
|
|
323
|
+
# Remove common prefixes/suffixes if needed
|
|
324
|
+
# This is a basic implementation - customize as needed
|
|
325
|
+
normalized = re.sub(r"^GENE[-_]?", "", normalized)
|
|
326
|
+
normalized = re.sub(r"[-_]?GENE$", "", normalized)
|
|
327
|
+
|
|
328
|
+
return normalized
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def format_api_response(
|
|
332
|
+
response_data: Any, format_type: str = "json"
|
|
333
|
+
) -> Union[str, Dict[str, Any], List[Any]]:
|
|
334
|
+
"""
|
|
335
|
+
Format API response data into a standardized format.
|
|
336
|
+
|
|
337
|
+
Args:
|
|
338
|
+
response_data (Any): The response data to format
|
|
339
|
+
format_type (str): The desired output format ('json', 'pretty', 'minimal')
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
Union[str, Dict[str, Any]]: Formatted response
|
|
343
|
+
"""
|
|
344
|
+
if format_type == "json":
|
|
345
|
+
if isinstance(response_data, (dict, list)):
|
|
346
|
+
return response_data
|
|
347
|
+
else:
|
|
348
|
+
return {"data": response_data, "status": "success"}
|
|
349
|
+
|
|
350
|
+
elif format_type == "pretty":
|
|
351
|
+
if isinstance(response_data, dict):
|
|
352
|
+
return json.dumps(response_data, indent=2, ensure_ascii=False)
|
|
353
|
+
else:
|
|
354
|
+
return json.dumps(
|
|
355
|
+
{"data": response_data, "status": "success"},
|
|
356
|
+
indent=2,
|
|
357
|
+
ensure_ascii=False,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
elif format_type == "minimal":
|
|
361
|
+
if isinstance(response_data, dict) and "data" in response_data:
|
|
362
|
+
return response_data["data"]
|
|
363
|
+
else:
|
|
364
|
+
return response_data
|
|
365
|
+
|
|
366
|
+
else:
|
|
367
|
+
return response_data
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def validate_hook_config(config: Dict[str, Any]) -> bool:
|
|
371
|
+
"""
|
|
372
|
+
Validate hook configuration for correctness and completeness.
|
|
373
|
+
|
|
374
|
+
This function checks that the hook configuration contains all required
|
|
375
|
+
fields and that the structure is valid for the hook system.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
config (Dict[str, Any]): Hook configuration to validate
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
bool: True if configuration is valid, False otherwise
|
|
382
|
+
"""
|
|
383
|
+
try:
|
|
384
|
+
# Check for required top-level fields
|
|
385
|
+
if not isinstance(config, dict):
|
|
386
|
+
return False
|
|
387
|
+
|
|
388
|
+
# Validate global settings if present
|
|
389
|
+
if "global_settings" in config:
|
|
390
|
+
global_settings = config["global_settings"]
|
|
391
|
+
if not isinstance(global_settings, dict):
|
|
392
|
+
return False
|
|
393
|
+
|
|
394
|
+
# Validate hooks array
|
|
395
|
+
if "hooks" in config:
|
|
396
|
+
hooks = config["hooks"]
|
|
397
|
+
if not isinstance(hooks, list):
|
|
398
|
+
return False
|
|
399
|
+
|
|
400
|
+
for hook in hooks:
|
|
401
|
+
if not validate_hook_conditions(hook.get("conditions", {})):
|
|
402
|
+
return False
|
|
403
|
+
|
|
404
|
+
# Validate tool-specific hooks
|
|
405
|
+
if "tool_specific_hooks" in config:
|
|
406
|
+
tool_hooks = config["tool_specific_hooks"]
|
|
407
|
+
if not isinstance(tool_hooks, dict):
|
|
408
|
+
return False
|
|
409
|
+
|
|
410
|
+
for _tool_name, tool_config in tool_hooks.items():
|
|
411
|
+
if not isinstance(tool_config, dict):
|
|
412
|
+
return False
|
|
413
|
+
if "hooks" in tool_config:
|
|
414
|
+
for hook in tool_config["hooks"]:
|
|
415
|
+
if not validate_hook_conditions(hook.get("conditions", {})):
|
|
416
|
+
return False
|
|
417
|
+
|
|
418
|
+
# Validate category hooks
|
|
419
|
+
if "category_hooks" in config:
|
|
420
|
+
category_hooks = config["category_hooks"]
|
|
421
|
+
if not isinstance(category_hooks, dict):
|
|
422
|
+
return False
|
|
423
|
+
|
|
424
|
+
for _category_name, category_config in category_hooks.items():
|
|
425
|
+
if not isinstance(category_config, dict):
|
|
426
|
+
return False
|
|
427
|
+
if "hooks" in category_config:
|
|
428
|
+
for hook in category_config["hooks"]:
|
|
429
|
+
if not validate_hook_conditions(hook.get("conditions", {})):
|
|
430
|
+
return False
|
|
431
|
+
|
|
432
|
+
return True
|
|
433
|
+
|
|
434
|
+
except Exception:
|
|
435
|
+
return False
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def validate_hook_conditions(conditions: Dict[str, Any]) -> bool:
|
|
439
|
+
"""
|
|
440
|
+
Validate hook trigger conditions.
|
|
441
|
+
|
|
442
|
+
This function checks that the hook conditions are properly structured
|
|
443
|
+
and contain valid operators and thresholds.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
conditions (Dict[str, Any]): Hook conditions to validate
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
bool: True if conditions are valid, False otherwise
|
|
450
|
+
"""
|
|
451
|
+
try:
|
|
452
|
+
if not isinstance(conditions, dict):
|
|
453
|
+
return False
|
|
454
|
+
|
|
455
|
+
# Validate output length conditions
|
|
456
|
+
if "output_length" in conditions:
|
|
457
|
+
length_condition = conditions["output_length"]
|
|
458
|
+
if not isinstance(length_condition, dict):
|
|
459
|
+
return False
|
|
460
|
+
|
|
461
|
+
# Check for required fields
|
|
462
|
+
if "threshold" not in length_condition:
|
|
463
|
+
return False
|
|
464
|
+
if "operator" not in length_condition:
|
|
465
|
+
return False
|
|
466
|
+
|
|
467
|
+
# Validate threshold is numeric
|
|
468
|
+
threshold = length_condition["threshold"]
|
|
469
|
+
if not isinstance(threshold, (int, float)) or threshold < 0:
|
|
470
|
+
return False
|
|
471
|
+
|
|
472
|
+
# Validate operator
|
|
473
|
+
operator = length_condition["operator"]
|
|
474
|
+
if operator not in [">", ">=", "<", "<="]:
|
|
475
|
+
return False
|
|
476
|
+
|
|
477
|
+
# Validate content type conditions
|
|
478
|
+
if "content_type" in conditions:
|
|
479
|
+
content_type = conditions["content_type"]
|
|
480
|
+
if not isinstance(content_type, str):
|
|
481
|
+
return False
|
|
482
|
+
if content_type not in ["json", "text", "xml", "csv"]:
|
|
483
|
+
return False
|
|
484
|
+
|
|
485
|
+
# Validate tool type conditions
|
|
486
|
+
if "tool_type" in conditions:
|
|
487
|
+
tool_type = conditions["tool_type"]
|
|
488
|
+
if not isinstance(tool_type, str):
|
|
489
|
+
return False
|
|
490
|
+
|
|
491
|
+
# Validate tool name conditions
|
|
492
|
+
if "tool_name" in conditions:
|
|
493
|
+
tool_name = conditions["tool_name"]
|
|
494
|
+
if not isinstance(tool_name, str):
|
|
495
|
+
return False
|
|
496
|
+
|
|
497
|
+
return True
|
|
498
|
+
|
|
499
|
+
except Exception:
|
|
500
|
+
return False
|