Add CIViC (Clinical Interpretation of Variants in Cancer) tools integration

- Add CIViCTool class with GraphQL API support
- Implement 12 CIViC tools:
  - civic_search_genes: Search genes in CIViC database
  - civic_get_variants_by_gene: Get variants by gene ID
  - civic_get_variant: Get variant details by ID
  - civic_search_variants: Search variants
  - civic_get_evidence_item: Get evidence item by ID
  - civic_search_evidence_items: Search evidence items
  - civic_get_assertion: Get assertion by ID
  - civic_search_assertions: Search assertions
  - civic_get_molecular_profile: Get molecular profile by ID
  - civic_search_molecular_profiles: Search molecular profiles
  - civic_search_diseases: Browse/search diseases
  - civic_search_therapies: Browse/search therapies
- Add example script demonstrating all CIViC tools
- Update tool_implementation_guide.md with reminder about auto-generated wrapper files
- Register civic category in default_config.py
This commit is contained in:
Shanghua
2026-01-17 19:15:44 -05:00
parent eef9337c60
commit f0079c5866
22 changed files with 2195 additions and 2 deletions
+287
View File
@@ -0,0 +1,287 @@
#!/usr/bin/env python3
"""
Example script for CIViC (Clinical Interpretation of Variants in Cancer) Tools.
This example demonstrates how to use all CIViC tools to:
- Search for genes, variants, evidence items, assertions, molecular profiles
- Get detailed information by ID
- Browse diseases and therapies
- Explore cancer variant interpretations
CIViC is a community knowledgebase for expert-curated interpretations of variants in cancer.
"""
import os
import sys
import json
# Ensure src is in path to import tooluniverse
sys.path.append(os.path.join(os.path.dirname(__file__), '../src'))
from tooluniverse import ToolUniverse
def print_result(tool_name, result):
"""Print formatted result."""
print(f"\n{'='*80}")
print(f"Results for {tool_name}")
print(f"{'='*80}")
if result and "error" not in result:
# Print summary
data = result.get("data", {})
if data:
print(f"✅ Success!")
print(f"Response keys: {list(data.keys())}")
# Print a sample of the data
result_str = json.dumps(result, indent=2)
if len(result_str) > 1000:
print(f"\nResponse preview (first 1000 chars):")
print(result_str[:1000] + "...")
else:
print(f"\nFull response:")
print(result_str)
else:
print("⚠️ No data returned")
elif "error" in result:
print(f"❌ Error: {result.get('error')}")
if "errors" in result:
print(f" Details: {result.get('errors')}")
else:
print("❌ No result found or error occurred.")
print("-" * 80)
def main():
print("="*80)
print("CIViC Tools Example")
print("="*80)
print("\nInitializing ToolUniverse...")
tu = ToolUniverse()
tu.load_tools(tool_type=["civic"])
# Example 1: Search for genes
print("\n" + "="*80)
print("Example 1: Search for genes in CIViC")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_search_genes",
"arguments": {"limit": 5}
})
print_result("civic_search_genes", result)
# Extract gene IDs for later examples
gene_id = None
if result and "data" in result:
genes = result["data"].get("genes", {}).get("nodes", [])
if genes:
gene_id = genes[0].get("id")
print(f"\n📋 Found {len(genes)} genes:")
for i, gene in enumerate(genes[:5], 1):
print(f" {i}. {gene.get('name')} (ID: {gene.get('id')}) - {gene.get('description', 'No description')[:50]}")
except Exception as e:
print(f"❌ Error: {e}")
import traceback
traceback.print_exc()
# Example 2: Get variants by gene
if gene_id:
print("\n" + "="*80)
print(f"Example 2: Get variants for gene ID {gene_id}")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_get_variants_by_gene",
"arguments": {"gene_id": gene_id, "limit": 5}
})
print_result("civic_get_variants_by_gene", result)
if result and "data" in result:
gene_data = result["data"].get("gene", {})
variants = gene_data.get("variants", {}).get("nodes", [])
print(f"\n🧬 Gene: {gene_data.get('name')}")
print(f" Found {len(variants)} variants:")
for i, variant in enumerate(variants[:5], 1):
print(f" {i}. {variant.get('name')} (ID: {variant.get('id')})")
except Exception as e:
print(f"❌ Error: {e}")
# Example 3: Search for variants
print("\n" + "="*80)
print("Example 3: Search for variants")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_search_variants",
"arguments": {"limit": 5}
})
print_result("civic_search_variants", result)
variant_id = None
if result and "data" in result:
variants = result["data"].get("variants", {}).get("nodes", [])
if variants:
variant_id = variants[0].get("id")
print(f"\n🔬 Found {len(variants)} variants:")
for i, variant in enumerate(variants[:5], 1):
print(f" {i}. {variant.get('name')} (ID: {variant.get('id')})")
except Exception as e:
print(f"❌ Error: {e}")
# Example 4: Get variant by ID
if variant_id:
print("\n" + "="*80)
print(f"Example 4: Get variant details for variant ID {variant_id}")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_get_variant",
"arguments": {"variant_id": variant_id}
})
print_result("civic_get_variant", result)
except Exception as e:
print(f"❌ Error: {e}")
# Example 5: Search for evidence items
print("\n" + "="*80)
print("Example 5: Search for evidence items")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_search_evidence_items",
"arguments": {"limit": 5}
})
print_result("civic_search_evidence_items", result)
evidence_id = None
if result and "data" in result:
evidence_items = result["data"].get("evidenceItems", {}).get("nodes", [])
if evidence_items:
evidence_id = evidence_items[0].get("id")
print(f"\n📚 Found {len(evidence_items)} evidence items:")
for i, item in enumerate(evidence_items[:5], 1):
desc = item.get("description", "")[:80]
level = item.get("evidenceLevel", "N/A")
etype = item.get("evidenceType", "N/A")
print(f" {i}. [{level}] {etype}: {desc}...")
except Exception as e:
print(f"❌ Error: {e}")
# Example 6: Get evidence item by ID
if evidence_id:
print("\n" + "="*80)
print(f"Example 6: Get evidence item details for ID {evidence_id}")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_get_evidence_item",
"arguments": {"evidence_id": evidence_id}
})
print_result("civic_get_evidence_item", result)
except Exception as e:
print(f"❌ Error: {e}")
# Example 7: Search for assertions
print("\n" + "="*80)
print("Example 7: Search for assertions")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_search_assertions",
"arguments": {"limit": 5}
})
print_result("civic_search_assertions", result)
if result and "data" in result:
assertions = result["data"].get("assertions", {}).get("nodes", [])
print(f"\n📋 Found {len(assertions)} assertions")
except Exception as e:
print(f"❌ Error: {e}")
# Example 8: Search for molecular profiles
print("\n" + "="*80)
print("Example 8: Search for molecular profiles")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_search_molecular_profiles",
"arguments": {"limit": 5}
})
print_result("civic_search_molecular_profiles", result)
profile_id = None
if result and "data" in result:
profiles = result["data"].get("molecularProfiles", {}).get("nodes", [])
if profiles:
profile_id = profiles[0].get("id")
print(f"\n🧪 Found {len(profiles)} molecular profiles:")
for i, profile in enumerate(profiles[:5], 1):
print(f" {i}. {profile.get('name', 'Unknown')} (ID: {profile.get('id')})")
except Exception as e:
print(f"❌ Error: {e}")
# Example 9: Get molecular profile by ID
if profile_id:
print("\n" + "="*80)
print(f"Example 9: Get molecular profile details for ID {profile_id}")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_get_molecular_profile",
"arguments": {"molecular_profile_id": profile_id}
})
print_result("civic_get_molecular_profile", result)
except Exception as e:
print(f"❌ Error: {e}")
# Example 10: Search for diseases
print("\n" + "="*80)
print("Example 10: Search for diseases")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_search_diseases",
"arguments": {"limit": 5}
})
print_result("civic_search_diseases", result)
if result and "data" in result:
diseases = result["data"].get("browseDiseases", {}).get("nodes", [])
print(f"\n🏥 Found {len(diseases)} diseases:")
for i, disease in enumerate(diseases[:5], 1):
print(f" {i}. {disease.get('name')} (ID: {disease.get('id')})")
except Exception as e:
print(f"❌ Error: {e}")
# Example 11: Search for therapies
print("\n" + "="*80)
print("Example 11: Search for therapies")
print("="*80)
try:
result = tu.run_one_function({
"name": "civic_search_therapies",
"arguments": {"limit": 5}
})
print_result("civic_search_therapies", result)
if result and "data" in result:
therapies = result["data"].get("browseTherapies", {}).get("nodes", [])
print(f"\n💊 Found {len(therapies)} therapies:")
for i, therapy in enumerate(therapies[:5], 1):
print(f" {i}. {therapy.get('name')} (ID: {therapy.get('id')})")
except Exception as e:
print(f"❌ Error: {e}")
print("\n" + "="*80)
print("CIViC Tools Example Complete!")
print("="*80)
print("\n💡 Tips:")
print(" - Start with civic_search_genes to find genes of interest")
print(" - Use civic_get_variants_by_gene to explore variants for a gene")
print(" - Evidence items link variants to clinical outcomes")
print(" - Assertions integrate multiple evidence items")
print(" - Molecular profiles represent biomarker combinations")
print(" - Use browse tools (diseases, therapies) to explore available entities")
print(" - All tools support limit parameter for pagination")
if __name__ == "__main__":
main()
+2 -1
View File
@@ -110,7 +110,8 @@ def run_tests(tu: ToolUniverse, configs: List[Tuple[Path, List[Dict]]], args) ->
for tool in tools:
name = tool.get("name")
if not name: continue
if not name:
continue
# Name filter logic (if pattern matches tool name directly)
if args.pattern and args.pattern.lower() not in name.lower() and args.pattern.lower() not in file_path.name.lower():
+4
View File
@@ -182,7 +182,11 @@ class BaseTool:
try:
import jsonschema
except ImportError:
# jsonschema not available, skip validation
return None
try:
# Filter out internal control parameters before validation
# Only filter known internal parameters, not all underscore-prefixed params
# to allow optional streaming parameter _tooluniverse_stream
+113
View File
@@ -0,0 +1,113 @@
"""
CIViC (Clinical Interpretation of Variants in Cancer) API tool for ToolUniverse.
CIViC is a community knowledgebase for expert-curated interpretations of variants
in cancer. It provides clinical evidence levels and interpretations.
API Documentation: https://civicdb.org/api
GraphQL Endpoint: https://civicdb.org/api/graphql
"""
import requests
from typing import Dict, Any, Optional
from .base_tool import BaseTool
from .tool_registry import register_tool
# Base URL for CIViC
CIVIC_BASE_URL = "https://civicdb.org/api"
CIVIC_GRAPHQL_URL = f"{CIVIC_BASE_URL}/graphql"
@register_tool("CIViCTool")
class CIViCTool(BaseTool):
"""
Tool for querying CIViC (Clinical Interpretation of Variants in Cancer).
CIViC provides:
- Expert-curated cancer variant interpretations
- Clinical evidence levels
- Drug-variant associations
- Disease-variant associations
Uses GraphQL API. No authentication required. Free for academic/research use.
"""
def __init__(self, tool_config: Dict[str, Any]):
super().__init__(tool_config)
fields = tool_config.get("fields", {})
self.query_template: str = fields.get("query", "")
self.operation_name: Optional[str] = fields.get("operation_name")
self.timeout: int = tool_config.get("timeout", 30)
def _build_graphql_query(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Build GraphQL query from template and arguments."""
query = self.query_template
# GraphQL queries use variables, not string replacement
# Extract variable names from query (e.g., $limit, $gene_id)
import re
var_matches = re.findall(r"\$(\w+)", query)
# Map arguments to GraphQL variables
# GraphQL variable names match argument names in our config
variables = {}
for var_name in var_matches:
# Check if argument exists (variable name matches argument name)
if var_name in arguments:
variables[var_name] = arguments[var_name]
payload = {"query": query}
if self.operation_name:
payload["operationName"] = self.operation_name
if variables:
payload["variables"] = variables
return payload
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Execute the CIViC GraphQL API call."""
try:
# Build GraphQL query
payload = self._build_graphql_query(arguments)
# Make GraphQL request
response = requests.post(
CIVIC_GRAPHQL_URL,
json=payload,
timeout=self.timeout,
headers={
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "ToolUniverse/CIViC",
},
)
response.raise_for_status()
data = response.json()
# Check for GraphQL errors
if "errors" in data:
return {
"error": "GraphQL query errors",
"errors": data["errors"],
"query": arguments,
}
return {
"data": data.get("data", {}),
"metadata": {
"source": "CIViC (Clinical Interpretation of Variants in Cancer)",
"format": "GraphQL",
"endpoint": CIVIC_GRAPHQL_URL,
},
}
except requests.RequestException as e:
return {"error": f"CIViC API request failed: {str(e)}", "query": arguments}
except ValueError as e:
return {"error": str(e), "query": arguments}
except Exception as e:
return {"error": f"Unexpected error: {str(e)}", "query": arguments}
+705
View File
@@ -0,0 +1,705 @@
[
{
"name": "civic_search_genes",
"description": "Search for genes in CIViC (Clinical Interpretation of Variants in Cancer) database. CIViC is a community knowledgebase for expert-curated interpretations of variants in cancer. Returns genes with their IDs, names, and descriptions. Use this to find genes of interest before querying variants or evidence.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Optional search query to filter genes by name or description. If not provided, returns all genes up to the limit."
},
"limit": {
"type": "integer",
"description": "Maximum number of genes to return (default: 10, recommended max: 100)",
"default": 10
}
},
"required": []
},
"fields": {
"query": "query GetGenes($limit: Int) { genes(first: $limit) { nodes { id name description entrezId } } }",
"operation_name": "GetGenes"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"genes": {
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "CIViC gene ID"
},
"name": {
"type": "string",
"description": "Gene symbol/name"
},
"description": {
"type": "string",
"description": "Gene description"
},
"entrezId": {
"type": "string",
"description": "Entrez Gene ID"
}
}
}
}
}
}
}
},
"metadata": {
"type": "object",
"properties": {
"source": {
"type": "string"
},
"format": {
"type": "string"
}
}
}
}
},
"test_examples": [
{
"limit": 5
},
{
"query": "BRCA",
"limit": 10
}
]
},
{
"name": "civic_get_variants_by_gene",
"description": "Get all variants associated with a specific gene in CIViC database. Returns variant information including names, coordinates, and associated evidence. Use this after finding a gene ID with civic_search_genes to explore all cancer variants for that gene.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"gene_id": {
"type": "integer",
"description": "CIViC gene ID (e.g., 4244 for ABCB1). Find gene IDs using civic_search_genes."
},
"limit": {
"type": "integer",
"description": "Maximum number of variants to return (default: 50, recommended max: 200)",
"default": 50
}
},
"required": [
"gene_id"
]
},
"fields": {
"query": "query GetVariantsByGene($gene_id: Int!, $limit: Int) { gene(id: $gene_id) { id name variants(first: $limit) { nodes { id name } } } }",
"operation_name": "GetVariantsByGene"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"gene": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"variants": {
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "CIViC variant ID"
},
"name": {
"type": "string",
"description": "Variant name"
}
}
}
}
}
}
}
}
}
},
"metadata": {
"type": "object",
"properties": {
"source": {
"type": "string"
},
"format": {
"type": "string"
}
}
}
}
},
"test_examples": [
{
"gene_id": 4244,
"limit": 10
}
]
},
{
"name": "civic_get_variant",
"description": "Get detailed information about a specific variant in CIViC database by variant ID. Variants represent specific genetic alterations (SNVs, indels, structural variants, etc.) with clinical significance in cancer. Returns variant name, coordinates, gene association, and related information.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"variant_id": {
"type": "integer",
"description": "CIViC variant ID (e.g., 4170)"
}
},
"required": [
"variant_id"
]
},
"fields": {
"query": "query GetVariant($variant_id: Int!) { variant(id: $variant_id) { id name } }",
"operation_name": "GetVariant"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"variant": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "CIViC variant ID"
},
"name": {
"type": "string",
"description": "Variant name"
}
}
}
}
}
}
},
"test_examples": [
{
"variant_id": 4170
}
]
},
{
"name": "civic_search_variants",
"description": "Search for variants in CIViC database. Returns a list of variants with their IDs and names. Variants represent specific genetic alterations with clinical significance in cancer.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Maximum number of variants to return (default: 20, recommended max: 100)",
"default": 20
}
},
"required": []
},
"fields": {
"query": "query SearchVariants($limit: Int) { variants(first: $limit) { nodes { id name } } }",
"operation_name": "SearchVariants"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"variants": {
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"test_examples": [
{
"limit": 10
}
]
},
{
"name": "civic_get_evidence_item",
"description": "Get detailed information about a specific evidence item in CIViC database by evidence ID. Evidence items link molecular profiles or variants to clinical outcomes, therapies, or disease states with curated literature support. Returns evidence description, level (A-E), type (PREDICTIVE, DIAGNOSTIC, PROGNOSTIC), and associated information.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"evidence_id": {
"type": "integer",
"description": "CIViC evidence item ID (e.g., 116)"
}
},
"required": [
"evidence_id"
]
},
"fields": {
"query": "query GetEvidenceItem($evidence_id: Int!) { evidenceItem(id: $evidence_id) { id description evidenceLevel evidenceType } }",
"operation_name": "GetEvidenceItem"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"evidenceItem": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"description": {
"type": "string"
},
"evidenceLevel": {
"type": "string",
"description": "Evidence level (A, B, C, D, E)"
},
"evidenceType": {
"type": "string",
"description": "Evidence type (PREDICTIVE, DIAGNOSTIC, PROGNOSTIC, etc.)"
}
}
}
}
}
}
},
"test_examples": [
{
"evidence_id": 116
}
]
},
{
"name": "civic_search_evidence_items",
"description": "Search for evidence items in CIViC database. Evidence items are curated statements linking variants or molecular profiles to clinical outcomes, therapies, or disease states. Returns a list of evidence items with descriptions, evidence levels (A-E), and evidence types (PREDICTIVE, DIAGNOSTIC, PROGNOSTIC).",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Maximum number of evidence items to return (default: 20, recommended max: 100)",
"default": 20
}
},
"required": []
},
"fields": {
"query": "query SearchEvidenceItems($limit: Int) { evidenceItems(first: $limit) { nodes { id description evidenceLevel evidenceType } } }",
"operation_name": "SearchEvidenceItems"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"evidenceItems": {
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"description": {
"type": "string"
},
"evidenceLevel": {
"type": "string"
},
"evidenceType": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"test_examples": [
{
"limit": 10
}
]
},
{
"name": "civic_get_assertion",
"description": "Get detailed information about a specific assertion in CIViC database by assertion ID. Assertions are higher-level clinical interpretations that integrate multiple evidence items into formal statements about clinical actionability. Returns assertion description, evidence summary, and associated molecular profile or variant information.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"assertion_id": {
"type": "integer",
"description": "CIViC assertion ID (e.g., 101)"
}
},
"required": [
"assertion_id"
]
},
"fields": {
"query": "query GetAssertion($assertion_id: Int!) { assertion(id: $assertion_id) { id description status } }",
"operation_name": "GetAssertion"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"assertion": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"description": {
"type": "string"
},
"status": {
"type": "string",
"description": "Assertion status (ACCEPTED, SUBMITTED, etc.)"
}
}
}
}
}
}
},
"test_examples": [
{
"assertion_id": 101
}
]
},
{
"name": "civic_search_assertions",
"description": "Search for assertions in CIViC database. Assertions are higher-level clinical interpretations that integrate multiple evidence items into formal statements about clinical actionability. Returns a list of assertions with descriptions and associated molecular profiles or variants.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Maximum number of assertions to return (default: 20, recommended max: 100)",
"default": 20
}
},
"required": []
},
"fields": {
"query": "query SearchAssertions($limit: Int) { assertions(first: $limit) { nodes { id description status } } }",
"operation_name": "SearchAssertions"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"assertions": {
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"description": {
"type": "string"
},
"status": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"test_examples": [
{
"limit": 10
}
]
},
{
"name": "civic_get_molecular_profile",
"description": "Get detailed information about a specific molecular profile in CIViC database by molecular profile ID. Molecular profiles represent combinations of variants or features (e.g., 'BRAF V600E') that serve as biomarkers for clinical interpretation. Returns profile name, description, and associated variants.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"molecular_profile_id": {
"type": "integer",
"description": "CIViC molecular profile ID (e.g., 12 for BRAF V600E)"
}
},
"required": [
"molecular_profile_id"
]
},
"fields": {
"query": "query GetMolecularProfile($molecular_profile_id: Int!) { molecularProfile(id: $molecular_profile_id) { id name } }",
"operation_name": "GetMolecularProfile"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"molecularProfile": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
}
}
}
},
"test_examples": [
{
"molecular_profile_id": 12
}
]
},
{
"name": "civic_search_molecular_profiles",
"description": "Search for molecular profiles in CIViC database. Molecular profiles represent combinations of variants or features (e.g., 'BRAF V600E', 'EGFR T790M') that serve as biomarkers for clinical interpretation. Returns a list of molecular profiles with IDs, names, and descriptions.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Maximum number of molecular profiles to return (default: 20, recommended max: 100)",
"default": 20
}
},
"required": []
},
"fields": {
"query": "query SearchMolecularProfiles($limit: Int) { molecularProfiles(first: $limit) { nodes { id name } } }",
"operation_name": "SearchMolecularProfiles"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"molecularProfiles": {
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"test_examples": [
{
"limit": 10
}
]
},
{
"name": "civic_search_diseases",
"description": "Search for diseases in CIViC database. Returns a list of cancer diseases and conditions (with IDs and names) that are associated with variants and evidence in CIViC. Use this to browse available disease entities before querying variants or evidence by disease.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Maximum number of diseases to return (default: 20, recommended max: 100)",
"default": 20
}
},
"required": []
},
"fields": {
"query": "query SearchDiseases($limit: Int) { browseDiseases(first: $limit) { nodes { id name } } }",
"operation_name": "SearchDiseases"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"browseDiseases": {
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"test_examples": [
{
"limit": 10
}
]
},
{
"name": "civic_search_therapies",
"description": "Search for therapies (drugs/treatments) in CIViC database. Returns a list of cancer therapies and drugs (with IDs and names) that are associated with variants and evidence in CIViC. Use this to browse available therapies before querying evidence items or assertions by therapy.",
"type": "CIViCTool",
"parameter": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Maximum number of therapies to return (default: 20, recommended max: 100)",
"default": 20
}
},
"required": []
},
"fields": {
"query": "query SearchTherapies($limit: Int) { browseTherapies(first: $limit) { nodes { id name } } }",
"operation_name": "SearchTherapies"
},
"return_schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"browseTherapies": {
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"test_examples": [
{
"limit": 10
}
]
}
]
+10
View File
@@ -123,6 +123,14 @@ default_tool_files = {
),
# New database tools
"interpro": os.path.join(current_dir, "data", "interpro_tools.json"),
"ebi_search": os.path.join(current_dir, "data", "ebi_search_tools.json"),
"intact": os.path.join(current_dir, "data", "intact_tools.json"),
"metabolights": os.path.join(current_dir, "data", "metabolights_tools.json"),
"proteins_api": os.path.join(current_dir, "data", "proteins_api_tools.json"),
"arrayexpress": os.path.join(current_dir, "data", "arrayexpress_tools.json"),
"dbfetch": os.path.join(current_dir, "data", "dbfetch_tools.json"),
"pdbe_api": os.path.join(current_dir, "data", "pdbe_api_tools.json"),
"ena_browser": os.path.join(current_dir, "data", "ena_browser_tools.json"),
"blast": os.path.join(current_dir, "data", "blast_tools.json"),
"cbioportal": os.path.join(current_dir, "data", "cbioportal_tools.json"),
"regulomedb": os.path.join(current_dir, "data", "regulomedb_tools.json"),
@@ -239,6 +247,8 @@ default_tool_files = {
"dgidb": os.path.join(current_dir, "data", "dgidb_tools.json"),
# STITCH - Chemical-Protein Interactions
"stitch": os.path.join(current_dir, "data", "stitch_tools.json"),
# CIViC - Clinical Interpretation of Variants in Cancer
"civic": os.path.join(current_dir, "data", "civic_tools.json"),
}
# Auto-load any user-provided tools from ~/.tooluniverse/user_tools/
+31
View File
@@ -60,6 +60,37 @@ def prop_to_python_type(prop: Dict[str, Any]) -> str:
# Fall back to regular type handling
json_type = prop.get("type", "string")
# Handle when type is a list (e.g., ["string", "array"])
if isinstance(json_type, list):
types = []
for item_type in json_type:
if item_type == "string":
types.append("str")
elif item_type == "array":
# Check if it's an array of strings
items = prop.get("items", {})
if items.get("type") == "string":
types.append("list[str]")
else:
types.append("list[Any]")
elif item_type:
types.append(json_type_to_python(item_type))
if len(types) == 1:
return types[0]
elif len(types) > 1:
# Remove duplicates while preserving order
seen = set()
unique_types = []
for t in types:
if t not in seen:
seen.add(t)
unique_types.append(t)
return " | ".join(unique_types)
else:
return "Any"
if json_type == "array":
# Check if it's an array of a specific type
items = prop.get("items", {})
@@ -453,6 +453,10 @@
"alphafold_get_annotations": "137c9fc43c08b637767dd714f4149bf6",
"alphafold_get_prediction": "596321f421d924f323fcb3c2ce37ba7d",
"alphafold_get_summary": "00da8b8a6ab1b0458d331150b517a291",
"arrayexpress_get_experiment": "3041e209269d45b508fbd944532bce8c",
"arrayexpress_get_experiment_files": "01f0d763ee721a1b6b30e4dbf83e17b7",
"arrayexpress_get_experiment_samples": "4600ddbae62565198d583524dbb1d4b5",
"arrayexpress_search_experiments": "21fb2b38684f3718662a6f3bb48086a7",
"biomodels_get_files": "313ddc6e15c5d7d9eaf997f6f3b229f1",
"biomodels_search": "3830b1d3b2ebd8f7fb9442466ae3b9de",
"cBioPortal_get_cancer_studies": "94d3086b9f812f5cf508757a0f8a49cc",
@@ -464,12 +468,28 @@
"cellosaurus_query_converter": "aa2e9051c5d4670b88c33d7f17a72425",
"cellosaurus_search_cell_lines": "f83daa78d3be1999e1db7572bc99775b",
"chembl_disease_target_score": "04ece0d7462525b462af63a3e741d369",
"civic_get_assertion": "72139323a5f5d72f8bc0a7efc0a76d1b",
"civic_get_evidence_item": "6f1a581fcc34b20f265b86ffeba8cc1a",
"civic_get_molecular_profile": "7a916b73e75410a529979229f92a05e7",
"civic_get_variant": "e89f1bc7ec2fb90d343054b5ea88adfc",
"civic_get_variants_by_gene": "7111963288ce13f1e3af8093008fe20e",
"civic_search_assertions": "a54942472e6c544823b7a88cc0b3107d",
"civic_search_diseases": "fa98b6fac27ea6f5475a0c880cf89bc4",
"civic_search_evidence_items": "a8c5611e76bb9ddc9f480185e1fd0aab",
"civic_search_genes": "602e63606610214f7a004494e91656f1",
"civic_search_molecular_profiles": "8086537be81d8302bdd4281a01dcec0e",
"civic_search_therapies": "314a40f86b8cda574d5c073e2c6782e6",
"civic_search_variants": "1b5dc14997578f88f2ea7ceae4d460d0",
"clinical_trials_get_details": "fa2c61295fcd790982f0fd922b6b8b5c",
"clinical_trials_search": "49f7b2bcd77d8c88632a0afad69cbe69",
"clinvar_get_clinical_significance": "8a9e5fb7b68139c5ade908562a464299",
"clinvar_get_variant_details": "5e8041f1945968c422d677bcfd683fbb",
"clinvar_search_variants": "de79e63606363c6e5b9ffafa20277c2d",
"convert_to_markdown": "b11d1deb6abe98a376f741f1b413fbfb",
"dbfetch_fetch_batch": "33a44deffeb4ee63c78be26c39792a82",
"dbfetch_fetch_entry": "fc6df1051183b59c81c3568d3cd7ed34",
"dbfetch_list_databases": "370818c1f833cd89b7559dce8905ef42",
"dbfetch_list_formats": "6e3acadd36aefb7eea71b892b83afa1a",
"dbsnp_get_frequencies": "75e339002f89c4e33f55defa3c68be9d",
"dbsnp_get_variant_by_rsid": "d36d4e64fbcbb26231f8dbc479cd5aff",
"dbsnp_search_by_gene": "a9db6f9d650ff5a6314032b046adf00f",
@@ -500,11 +520,23 @@
"drugbank_vocab_filter": "60d4b64685861395b5b5c6a7db38d91e",
"drugbank_vocab_search": "726d5418564d63e51d944c3dad20ea6a",
"dynamic_package_discovery": "8fbd6c7eb3d8b827109f94833598b8b9",
"ebi_cross_reference_search": "1dad98b6eaa1b33968f054b36e9d9d90",
"ebi_get_domain_fields": "45bba9d6e49e39500be9f3c705ddc359",
"ebi_get_domain_info": "d4f009d0f5dfece9254ad438535e4517",
"ebi_get_entry": "fcc8dec1ef463a1d0c2ec02fac11c6c2",
"ebi_list_domains": "0b9201043af02dcb72182725f01d0dd2",
"ebi_search_domain": "fb7e82ee5649992fa9126cdbdd65dcbf",
"ebi_search_with_facets": "aa9d640290fa3fbe5d76097745beb724",
"embedding_database_add": "a51d21c2d84ca0b0a91c5212ab2c4dcf",
"embedding_database_create": "6af3a740796ae3067fbef98194b66fe9",
"embedding_database_search": "214e75ca0ad0e6d78d56e84f93c9df6e",
"embedding_sync_download": "e20f7d6780a428201171ec3bd01d707d",
"embedding_sync_upload": "915d3a5f60cbb827f9565ea245c28a1d",
"ena_get_entry": "686bdc6dfbe2c149e29097eb9d9767cf",
"ena_get_entry_history": "411756caf773c3ec16386411a0d24b43",
"ena_get_sequence_embl": "a7531a7bbfd0bd5463163f1b82498964",
"ena_get_sequence_fasta": "af5369206dbc5dc85a42dace8733e38f",
"ena_get_sequence_xml": "8f38d8c5a287d4a59b13ffae122d644c",
"enrichr_gene_enrichment_analysis": "38f2c27c7f4ec82558c36e7a43860db1",
"ensembl_get_sequence": "d5ac3d209844f6a5fd9ff7ae4b760397",
"ensembl_get_variants": "14cab74e7147a129f189cb42d954df7d",
@@ -776,6 +808,11 @@
"humanbase_ppi_analysis": "fadb85460bc9f84e5c9e59e6e6f0d2d6",
"icd_search_codes": "08ae65c82276312dbbfa8fb4f5f703ae",
"iedb_search_epitopes": "ef670fdc7909116e1dd23d78fc676a90",
"intact_get_interaction_details": "4ec4c2186399edce788aff89626e6ff0",
"intact_get_interaction_network": "387672718390f74081ddcabf77cd44a7",
"intact_get_interactions": "800b8e0f4107ec925acaf66fc5acf9a0",
"intact_get_interactor": "d4a1ffe2488c981a22d268f45b9c53c3",
"intact_search_interactions": "08d3d9cfa6270667b160f6530ed0ebe1",
"kegg_find_genes": "296e17dd4d59125ba7e562e96b074253",
"kegg_get_gene_info": "24f7f52c2e9bddbaba1b1b6ac3039804",
"kegg_get_pathway_info": "650705af0b041f1223c215536753220b",
@@ -787,6 +824,12 @@
"mesh_get_subjects_by_subject_id": "d391c3abf4e61db66a21ecaf4907a20c",
"mesh_get_subjects_by_subject_name": "5bb262ecbea7535cbaf34e39812bb905",
"mesh_get_subjects_by_subject_scope_or_definition": "f30f82d4fa18f53dfc0b97583abd99a2",
"metabolights_get_study": "5f8ab3ecaa4079517bc773c54ca1d7ea",
"metabolights_get_study_assays": "fd8f5f121d3d875c950b481679064438",
"metabolights_get_study_files": "74c77ca5c07661aa8dc5f324c3419df7",
"metabolights_get_study_samples": "00198d53a10a65db5c00aa9f48bd91e0",
"metabolights_list_studies": "aca6d688d04bd79e1a68bd05d32b4009",
"metabolights_search_studies": "c095c77c5c1afe9242ed2acae2b072fc",
"odphp_itemlist": "59211a801c987b5dcfd54956632a3a36",
"odphp_myhealthfinder": "aa875b4813498cc3a7940ff33796093f",
"odphp_outlink_fetch": "cee04b3a8cb40243a9216c49b116e2ec",
@@ -802,6 +845,16 @@
"openalex_literature_search": "7416ef2448df0b6e44ea21cc5a69a2f6",
"pc_get_interactions": "302a566634c428781950818b93b96d5a",
"pc_search_pathways": "e40405f131698e52d47bfc6a015b5aee",
"pdbe_get_entry_assemblies": "7481c655089f3f407641118d2516d3ed",
"pdbe_get_entry_publications": "64a3976c3840adefea5ebf43218d8026",
"pdbe_get_entry_quality": "ca959215fd834a430ca10ebbdf4715d4",
"pdbe_get_entry_secondary_structure": "415f96947a6d85c230765a612a20eb0d",
"pdbe_get_entry_summary": "3e158cdcc6706e54af2655b1a56edd63",
"proteins_api_get_epitopes": "462b411219badbef28fcf5eb0b066262",
"proteins_api_get_protein": "9b7f02ded471f831b32f6c4efe4f3520",
"proteins_api_get_proteomics": "dac590c0c0dcbc7d476c2c9f59069ba0",
"proteins_api_get_variants": "f465e68efd133838bde39c9a47bb3d59",
"proteins_api_search": "6c2683369ae9fe5096662c6c6662bed6",
"python_code_executor": "b20a3dd34a7fc9cef8a8f29c31176d60",
"python_script_runner": "75d575b58092eda727deb7c16b0ae505",
"reactome_disease_target_score": "bc653cc38d09c6f71f06844e83b76e84",
+107 -1
View File
@@ -1,7 +1,7 @@
"""
ToolUniverse Tools
Type-safe Python interface to 817 scientific tools.
Type-safe Python interface to 870 scientific tools.
Each tool is in its own module for minimal import overhead.
Usage:
@@ -849,6 +849,10 @@ from .advanced_literature_search_agent import advanced_literature_search_agent
from .alphafold_get_annotations import alphafold_get_annotations
from .alphafold_get_prediction import alphafold_get_prediction
from .alphafold_get_summary import alphafold_get_summary
from .arrayexpress_get_experiment import arrayexpress_get_experiment
from .arrayexpress_get_experiment_files import arrayexpress_get_experiment_files
from .arrayexpress_get_experiment_samples import arrayexpress_get_experiment_samples
from .arrayexpress_search_experiments import arrayexpress_search_experiments
from .biomodels_get_files import biomodels_get_files
from .biomodels_search import biomodels_search
from .cBioPortal_get_cancer_studies import cBioPortal_get_cancer_studies
@@ -864,12 +868,28 @@ from .cellosaurus_get_cell_line_info import cellosaurus_get_cell_line_info
from .cellosaurus_query_converter import cellosaurus_query_converter
from .cellosaurus_search_cell_lines import cellosaurus_search_cell_lines
from .chembl_disease_target_score import chembl_disease_target_score
from .civic_get_assertion import civic_get_assertion
from .civic_get_evidence_item import civic_get_evidence_item
from .civic_get_molecular_profile import civic_get_molecular_profile
from .civic_get_variant import civic_get_variant
from .civic_get_variants_by_gene import civic_get_variants_by_gene
from .civic_search_assertions import civic_search_assertions
from .civic_search_diseases import civic_search_diseases
from .civic_search_evidence_items import civic_search_evidence_items
from .civic_search_genes import civic_search_genes
from .civic_search_molecular_profiles import civic_search_molecular_profiles
from .civic_search_therapies import civic_search_therapies
from .civic_search_variants import civic_search_variants
from .clinical_trials_get_details import clinical_trials_get_details
from .clinical_trials_search import clinical_trials_search
from .clinvar_get_clinical_significance import clinvar_get_clinical_significance
from .clinvar_get_variant_details import clinvar_get_variant_details
from .clinvar_search_variants import clinvar_search_variants
from .convert_to_markdown import convert_to_markdown
from .dbfetch_fetch_batch import dbfetch_fetch_batch
from .dbfetch_fetch_entry import dbfetch_fetch_entry
from .dbfetch_list_databases import dbfetch_list_databases
from .dbfetch_list_formats import dbfetch_list_formats
from .dbsnp_get_frequencies import dbsnp_get_frequencies
from .dbsnp_get_variant_by_rsid import dbsnp_get_variant_by_rsid
from .dbsnp_search_by_gene import dbsnp_search_by_gene
@@ -928,11 +948,23 @@ from .drugbank_links_search import drugbank_links_search
from .drugbank_vocab_filter import drugbank_vocab_filter
from .drugbank_vocab_search import drugbank_vocab_search
from .dynamic_package_discovery import dynamic_package_discovery
from .ebi_cross_reference_search import ebi_cross_reference_search
from .ebi_get_domain_fields import ebi_get_domain_fields
from .ebi_get_domain_info import ebi_get_domain_info
from .ebi_get_entry import ebi_get_entry
from .ebi_list_domains import ebi_list_domains
from .ebi_search_domain import ebi_search_domain
from .ebi_search_with_facets import ebi_search_with_facets
from .embedding_database_add import embedding_database_add
from .embedding_database_create import embedding_database_create
from .embedding_database_search import embedding_database_search
from .embedding_sync_download import embedding_sync_download
from .embedding_sync_upload import embedding_sync_upload
from .ena_get_entry import ena_get_entry
from .ena_get_entry_history import ena_get_entry_history
from .ena_get_sequence_embl import ena_get_sequence_embl
from .ena_get_sequence_fasta import ena_get_sequence_fasta
from .ena_get_sequence_xml import ena_get_sequence_xml
from .enrichr_gene_enrichment_analysis import enrichr_gene_enrichment_analysis
from .ensembl_get_sequence import ensembl_get_sequence
from .ensembl_get_variants import ensembl_get_variants
@@ -1244,6 +1276,11 @@ from .hca_search_projects import hca_search_projects
from .humanbase_ppi_analysis import humanbase_ppi_analysis
from .icd_search_codes import icd_search_codes
from .iedb_search_epitopes import iedb_search_epitopes
from .intact_get_interaction_details import intact_get_interaction_details
from .intact_get_interaction_network import intact_get_interaction_network
from .intact_get_interactions import intact_get_interactions
from .intact_get_interactor import intact_get_interactor
from .intact_search_interactions import intact_search_interactions
from .kegg_find_genes import kegg_find_genes
from .kegg_get_gene_info import kegg_get_gene_info
from .kegg_get_pathway_info import kegg_get_pathway_info
@@ -1259,6 +1296,12 @@ from .mesh_get_subjects_by_subject_name import mesh_get_subjects_by_subject_name
from .mesh_get_subjects_by_subject_scope_or_definition import (
mesh_get_subjects_by_subject_scope_or_definition,
)
from .metabolights_get_study import metabolights_get_study
from .metabolights_get_study_assays import metabolights_get_study_assays
from .metabolights_get_study_files import metabolights_get_study_files
from .metabolights_get_study_samples import metabolights_get_study_samples
from .metabolights_list_studies import metabolights_list_studies
from .metabolights_search_studies import metabolights_search_studies
from .odphp_itemlist import odphp_itemlist
from .odphp_myhealthfinder import odphp_myhealthfinder
from .odphp_outlink_fetch import odphp_outlink_fetch
@@ -1274,6 +1317,16 @@ from .open_deep_research_agent import open_deep_research_agent
from .openalex_literature_search import openalex_literature_search
from .pc_get_interactions import pc_get_interactions
from .pc_search_pathways import pc_search_pathways
from .pdbe_get_entry_assemblies import pdbe_get_entry_assemblies
from .pdbe_get_entry_publications import pdbe_get_entry_publications
from .pdbe_get_entry_quality import pdbe_get_entry_quality
from .pdbe_get_entry_secondary_structure import pdbe_get_entry_secondary_structure
from .pdbe_get_entry_summary import pdbe_get_entry_summary
from .proteins_api_get_epitopes import proteins_api_get_epitopes
from .proteins_api_get_protein import proteins_api_get_protein
from .proteins_api_get_proteomics import proteins_api_get_proteomics
from .proteins_api_get_variants import proteins_api_get_variants
from .proteins_api_search import proteins_api_search
from .python_code_executor import python_code_executor
from .python_script_runner import python_script_runner
from .reactome_disease_target_score import reactome_disease_target_score
@@ -1746,6 +1799,10 @@ __all__ = [
"alphafold_get_annotations",
"alphafold_get_prediction",
"alphafold_get_summary",
"arrayexpress_get_experiment",
"arrayexpress_get_experiment_files",
"arrayexpress_get_experiment_samples",
"arrayexpress_search_experiments",
"biomodels_get_files",
"biomodels_search",
"cBioPortal_get_cancer_studies",
@@ -1757,12 +1814,28 @@ __all__ = [
"cellosaurus_query_converter",
"cellosaurus_search_cell_lines",
"chembl_disease_target_score",
"civic_get_assertion",
"civic_get_evidence_item",
"civic_get_molecular_profile",
"civic_get_variant",
"civic_get_variants_by_gene",
"civic_search_assertions",
"civic_search_diseases",
"civic_search_evidence_items",
"civic_search_genes",
"civic_search_molecular_profiles",
"civic_search_therapies",
"civic_search_variants",
"clinical_trials_get_details",
"clinical_trials_search",
"clinvar_get_clinical_significance",
"clinvar_get_variant_details",
"clinvar_search_variants",
"convert_to_markdown",
"dbfetch_fetch_batch",
"dbfetch_fetch_entry",
"dbfetch_list_databases",
"dbfetch_list_formats",
"dbsnp_get_frequencies",
"dbsnp_get_variant_by_rsid",
"dbsnp_search_by_gene",
@@ -1793,11 +1866,23 @@ __all__ = [
"drugbank_vocab_filter",
"drugbank_vocab_search",
"dynamic_package_discovery",
"ebi_cross_reference_search",
"ebi_get_domain_fields",
"ebi_get_domain_info",
"ebi_get_entry",
"ebi_list_domains",
"ebi_search_domain",
"ebi_search_with_facets",
"embedding_database_add",
"embedding_database_create",
"embedding_database_search",
"embedding_sync_download",
"embedding_sync_upload",
"ena_get_entry",
"ena_get_entry_history",
"ena_get_sequence_embl",
"ena_get_sequence_fasta",
"ena_get_sequence_xml",
"enrichr_gene_enrichment_analysis",
"ensembl_get_sequence",
"ensembl_get_variants",
@@ -2069,6 +2154,11 @@ __all__ = [
"humanbase_ppi_analysis",
"icd_search_codes",
"iedb_search_epitopes",
"intact_get_interaction_details",
"intact_get_interaction_network",
"intact_get_interactions",
"intact_get_interactor",
"intact_search_interactions",
"kegg_find_genes",
"kegg_get_gene_info",
"kegg_get_pathway_info",
@@ -2080,6 +2170,12 @@ __all__ = [
"mesh_get_subjects_by_subject_id",
"mesh_get_subjects_by_subject_name",
"mesh_get_subjects_by_subject_scope_or_definition",
"metabolights_get_study",
"metabolights_get_study_assays",
"metabolights_get_study_files",
"metabolights_get_study_samples",
"metabolights_list_studies",
"metabolights_search_studies",
"odphp_itemlist",
"odphp_myhealthfinder",
"odphp_outlink_fetch",
@@ -2095,6 +2191,16 @@ __all__ = [
"openalex_literature_search",
"pc_get_interactions",
"pc_search_pathways",
"pdbe_get_entry_assemblies",
"pdbe_get_entry_publications",
"pdbe_get_entry_quality",
"pdbe_get_entry_secondary_structure",
"pdbe_get_entry_summary",
"proteins_api_get_epitopes",
"proteins_api_get_protein",
"proteins_api_get_proteomics",
"proteins_api_get_variants",
"proteins_api_search",
"python_code_executor",
"python_script_runner",
"reactome_disease_target_score",
@@ -0,0 +1,46 @@
"""
civic_get_assertion
Get detailed information about a specific assertion in CIViC database by assertion ID. Assertions...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_get_assertion(
assertion_id: int,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Get detailed information about a specific assertion in CIViC database by assertion ID. Assertions...
Parameters
----------
assertion_id : int
CIViC assertion ID (e.g., 101)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_get_assertion", "arguments": {"assertion_id": assertion_id}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_get_assertion"]
@@ -0,0 +1,46 @@
"""
civic_get_evidence_item
Get detailed information about a specific evidence item in CIViC database by evidence ID. Evidenc...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_get_evidence_item(
evidence_id: int,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Get detailed information about a specific evidence item in CIViC database by evidence ID. Evidenc...
Parameters
----------
evidence_id : int
CIViC evidence item ID (e.g., 116)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_get_evidence_item", "arguments": {"evidence_id": evidence_id}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_get_evidence_item"]
@@ -0,0 +1,49 @@
"""
civic_get_molecular_profile
Get detailed information about a specific molecular profile in CIViC database by molecular profil...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_get_molecular_profile(
molecular_profile_id: int,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Get detailed information about a specific molecular profile in CIViC database by molecular profil...
Parameters
----------
molecular_profile_id : int
CIViC molecular profile ID (e.g., 12 for BRAF V600E)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{
"name": "civic_get_molecular_profile",
"arguments": {"molecular_profile_id": molecular_profile_id},
},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_get_molecular_profile"]
@@ -0,0 +1,46 @@
"""
civic_get_variant
Get detailed information about a specific variant in CIViC database by variant ID. Variants repre...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_get_variant(
variant_id: int,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Get detailed information about a specific variant in CIViC database by variant ID. Variants repre...
Parameters
----------
variant_id : int
CIViC variant ID (e.g., 4170)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_get_variant", "arguments": {"variant_id": variant_id}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_get_variant"]
@@ -0,0 +1,52 @@
"""
civic_get_variants_by_gene
Get all variants associated with a specific gene in CIViC database. Returns variant information i...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_get_variants_by_gene(
gene_id: int,
limit: Optional[int] = 50,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Get all variants associated with a specific gene in CIViC database. Returns variant information i...
Parameters
----------
gene_id : int
CIViC gene ID (e.g., 4244 for ABCB1). Find gene IDs using civic_search_genes.
limit : int
Maximum number of variants to return (default: 50, recommended max: 200)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{
"name": "civic_get_variants_by_gene",
"arguments": {"gene_id": gene_id, "limit": limit},
},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_get_variants_by_gene"]
@@ -0,0 +1,46 @@
"""
civic_search_assertions
Search for assertions in CIViC database. Assertions are higher-level clinical interpretations tha...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_search_assertions(
limit: Optional[int] = 20,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Search for assertions in CIViC database. Assertions are higher-level clinical interpretations tha...
Parameters
----------
limit : int
Maximum number of assertions to return (default: 20, recommended max: 100)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_search_assertions", "arguments": {"limit": limit}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_search_assertions"]
@@ -0,0 +1,46 @@
"""
civic_search_diseases
Search for diseases in CIViC database. Returns a list of cancer diseases and conditions (with IDs...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_search_diseases(
limit: Optional[int] = 20,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Search for diseases in CIViC database. Returns a list of cancer diseases and conditions (with IDs...
Parameters
----------
limit : int
Maximum number of diseases to return (default: 20, recommended max: 100)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_search_diseases", "arguments": {"limit": limit}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_search_diseases"]
@@ -0,0 +1,46 @@
"""
civic_search_evidence_items
Search for evidence items in CIViC database. Evidence items are curated statements linking varian...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_search_evidence_items(
limit: Optional[int] = 20,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Search for evidence items in CIViC database. Evidence items are curated statements linking varian...
Parameters
----------
limit : int
Maximum number of evidence items to return (default: 20, recommended max: 100)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_search_evidence_items", "arguments": {"limit": limit}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_search_evidence_items"]
@@ -0,0 +1,49 @@
"""
civic_search_genes
Search for genes in CIViC (Clinical Interpretation of Variants in Cancer) database. CIViC is a co...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_search_genes(
query: Optional[str] = None,
limit: Optional[int] = 10,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Search for genes in CIViC (Clinical Interpretation of Variants in Cancer) database. CIViC is a co...
Parameters
----------
query : str
Optional search query to filter genes by name or description. If not provided...
limit : int
Maximum number of genes to return (default: 10, recommended max: 100)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_search_genes", "arguments": {"query": query, "limit": limit}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_search_genes"]
@@ -0,0 +1,46 @@
"""
civic_search_molecular_profiles
Search for molecular profiles in CIViC database. Molecular profiles represent combinations of var...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_search_molecular_profiles(
limit: Optional[int] = 20,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Search for molecular profiles in CIViC database. Molecular profiles represent combinations of var...
Parameters
----------
limit : int
Maximum number of molecular profiles to return (default: 20, recommended max:...
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_search_molecular_profiles", "arguments": {"limit": limit}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_search_molecular_profiles"]
@@ -0,0 +1,46 @@
"""
civic_search_therapies
Search for therapies (drugs/treatments) in CIViC database. Returns a list of cancer therapies and...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_search_therapies(
limit: Optional[int] = 20,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Search for therapies (drugs/treatments) in CIViC database. Returns a list of cancer therapies and...
Parameters
----------
limit : int
Maximum number of therapies to return (default: 20, recommended max: 100)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_search_therapies", "arguments": {"limit": limit}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_search_therapies"]
@@ -0,0 +1,46 @@
"""
civic_search_variants
Search for variants in CIViC database. Returns a list of variants with their IDs and names. Varia...
"""
from typing import Any, Optional, Callable
from ._shared_client import get_shared_client
def civic_search_variants(
limit: Optional[int] = 20,
*,
stream_callback: Optional[Callable[[str], None]] = None,
use_cache: bool = False,
validate: bool = True,
) -> dict[str, Any]:
"""
Search for variants in CIViC database. Returns a list of variants with their IDs and names. Varia...
Parameters
----------
limit : int
Maximum number of variants to return (default: 20, recommended max: 100)
stream_callback : Callable, optional
Callback for streaming output
use_cache : bool, default False
Enable caching
validate : bool, default True
Validate parameters
Returns
-------
dict[str, Any]
"""
# Handle mutable defaults to avoid B006 linting error
return get_shared_client().run_one_function(
{"name": "civic_search_variants", "arguments": {"limit": limit}},
stream_callback=stream_callback,
use_cache=use_cache,
validate=validate,
)
__all__ = ["civic_search_variants"]
+319
View File
@@ -0,0 +1,319 @@
# Life Science Tool Implementation Plan
This document outlines the strategy for implementing new life science tools into `ToolUniverse`. It begins with a guideline for adding tools based on the project's best practices and then details the implementation plan for each specific data source.
## 1. Guidelines for Adding Tools to ToolUniverse
Based on `docs/expand_tooluniverse/contributing/local_tools.rst` and the current codebase structure:
### A. File Structure & Location
* **Source Code**: Create a new Python file `src/tooluniverse/xxx_tool.py`.
* **Configuration**: Create a corresponding JSON config file `src/tooluniverse/data/xxx_tools.json`.
* **Tests**: Create a unit test file `tests/unit/test_xxx_tool.py`.
* **⚠️ IMPORTANT**: **Do NOT** manually create files in `src/tooluniverse/tools/`. Files in this folder are automatically generated wrapper functions. They will be created automatically by ToolUniverse based on your JSON configuration.
### B. Implementation Pattern
1. **Inheritance**: Your tool class must inherit from `BaseTool`.
2. **Registration**: Use the `@register_tool` decorator with the class name.
**Example `src/tooluniverse/my_new_tool.py`**:
```python
from typing import Dict, Any
from .base_tool import BaseTool
from .tool_registry import register_tool
@register_tool("MyNewTool")
class MyNewTool(BaseTool):
"""
My new tool description.
"""
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
# Implementation logic here
return {"result": "success"}
```
3. **Configuration**:
* **Do NOT** embed large configs in the decorator based on current best practices for contributed tools. Use the external JSON file.
* The configuration file must define the tool's `name` (snake_case), `type` (matching the class name), `description`, `parameter` schema (JSON Schema), **`return_schema`** (output structure), and `test_examples`.
**Example `src/tooluniverse/data/my_new_tools.json`**:
```json
[
{
"name": "my_new_tool",
"type": "MyNewTool",
"description": "Convert text to uppercase",
"parameter": {
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "Text to convert"
}
},
"required": ["input"]
},
"return_schema": {
"type": "object",
"properties": {
"result": {
"type": "string",
"description": "The converted text"
}
}
},
"test_examples": [
{
"input": "hello"
}
]
}
]
```
4. **Auto-Discovery**:
* Modern `ToolUniverse` uses automated discovery. You generally **do not** need to modify `src/tooluniverse/__init__.py` if you place your file correctly in `src/tooluniverse/`.
### C. Development Checklist
1. [ ] Create `src/tooluniverse/xxx_tool.py` with `@register_tool`.
2. [ ] Create `src/tooluniverse/data/xxx_tools.json` including `returns` schema.
3. [ ] Implement `run(arguments)` method.
4. [ ] Implement `validate_parameters` (optional but recommended).
5. [ ] Write unit tests in `tests/unit/`.
6. [ ] Verify tool load with `tu.load_tools()`.
---
## 2. Tool Improvement and Maintenance Checklist
**Purpose**: This checklist guides LLMs through systematically improving and maintaining existing tools in ToolUniverse.
### Phase 1: Initial Assessment
#### Step 1.1: Identify Tool Files
- [ ] Locate tool class file: `src/tooluniverse/{category}_tool.py`
- [ ] Locate JSON config file: `src/tooluniverse/data/{category}_tools.json`
- [ ] List all tool function files: `src/tooluniverse/tools/{category}_*.py` (⚠️ Note: These are auto-generated wrappers)
- [ ] Check `default_config.py` for category registration
- [ ] Check `tools/__init__.py` for imports (⚠️ Note: Imports are auto-generated)
#### Step 1.2: Verify Basic Structure
- [ ] Tool class registration exists (`@register_tool`)
- [ ] Class name matches JSON config `"type"` field
- [ ] JSON file is valid
- [ ] Tool loads without errors
- [ ] Python syntax is valid
### Phase 2: Functionality Testing
#### Step 2.1: Test Tool Execution
- [ ] Load tools and test each tool with sample arguments
- [ ] Verify results contain data (not empty)
- [ ] Check response structure matches return_schema
- [ ] Test error handling with invalid inputs
#### Step 2.2: Test API Endpoints Directly
- [ ] Test REST/GraphQL endpoints respond correctly
- [ ] Verify status codes are 200 OK (not 404/502/503)
- [ ] Check response format matches tool expectations
### Phase 3: Description Improvement
#### Step 3.1: Review Tool Descriptions
- [ ] Check each tool's description field
- [ ] Description includes: purpose, input, output, use cases
- [ ] Description is clear to users unfamiliar with API
- [ ] Add examples if missing
#### Step 3.2: Review Parameter Descriptions
For each parameter:
- [ ] Has clear description with examples
- [ ] Has default value if optional
- [ ] Has constraints (min/max/enum) if applicable
- [ ] Type is correct
#### Step 3.3: Review Return Schema
- [ ] return_schema field exists
- [ ] Schema matches actual tool output
- [ ] All important fields documented
- [ ] Nested structures fully documented
### Phase 4: Error Handling Improvement
#### Step 4.1: Review Current Error Handling
- [ ] Test error messages with invalid inputs
- [ ] Test HTTP error handling (404, 502, 503)
- [ ] Verify try/except blocks exist
- [ ] Errors return dict with "error" key
#### Step 4.2: Improve Error Messages
- [ ] Error messages are specific (not generic)
- [ ] Errors suggest actionable solutions
- [ ] Errors include context (status_code, endpoint)
- [ ] Errors are user-friendly
#### Step 4.3: Add Retry Logic (if needed)
- [ ] Identify transient failures (ConnectionError, Timeout)
- [ ] Implement retry with exponential backoff
- [ ] Set max retries (typically 2-3)
- [ ] Handle final failure appropriately
### Phase 5: Finding Missing Tools
#### Step 5.1: Research API Capabilities
- [ ] **Read API Docs**: Check official documentation for all endpoints/operations
- [ ] **GraphQL Introspection**: Use schema introspection to find all queries
- [ ] **Test Endpoints**: Try different endpoint patterns
- [ ] **Check Related Packages**: Look at R/Bioconductor or Python packages
- [ ] **Web Search**: Search for "{API_NAME} API documentation"
#### Step 5.2: Create Gap Analysis Matrix
- [ ] List current tools from JSON config
- [ ] List all API capabilities
- [ ] Create comparison table (implemented vs available)
- [ ] Prioritize missing tools (HIGH/MEDIUM/LOW)
- [ ] Document findings
#### Step 5.3: Identify Subset Extraction Opportunities
- [ ] **Check Data Size**: If full response is large/complex
- [ ] **Identify Subsets**: Common fields users need (diseases, pathways, etc.)
- [ ] **Add Subset Tools**: Create tools that extract specific data types
- [ ] **Implement Method**: Create `_extract_subset()` helper if needed
### Phase 6: Fix Common Issues
#### Issue 6.1: Tool Class Name Mismatch
**Symptoms**: Tool doesn't load, registration errors
**Check**:
- [ ] Python class name matches `@register_tool("ClassName")`
- [ ] JSON config `"type"` field matches class name exactly
- [ ] No typos or case mismatches
**Fix**: Ensure Python class name matches JSON `"type"` field exactly
#### Issue 6.2: Response Format Mismatch
**Symptoms**: `'list' object has no attribute 'get'` or similar errors
**Check**:
- [ ] Test API response format directly
- [ ] Check if API returns list vs dict
- [ ] Verify tool expects correct format
**Fix**: Check API response format and convert if needed (list → dict or vice versa)
#### Issue 6.3: Endpoint URL Issues
**Symptoms**: 404 errors, "Not Found" responses
**Check**:
- [ ] Test endpoint directly
- [ ] Verify URL pattern in API documentation
- [ ] Check placeholder replacement logic
- [ ] Verify base URL is correct
**Fix**: Verify URL building logic and placeholder replacement
#### Issue 6.4: Missing Error Handling
**Symptoms**: Tool crashes on API errors, unhandled exceptions
**Check**:
- [ ] Test with invalid inputs
- [ ] Test with network failures
- [ ] Check for try/except blocks
**Fix**: Add try/except blocks with specific error handling for HTTP errors
### Phase 7: Final Verification
#### Step 7.1: Comprehensive Testing
- [ ] Test all tools with valid inputs
- [ ] Test error cases with invalid inputs
- [ ] Test edge cases (empty results, null values)
- [ ] Verify results contain meaningful data
- [ ] Check performance is reasonable
#### Step 7.2: Validation Checks
- [ ] JSON files are valid
- [ ] Python syntax is valid
- [ ] No linting errors
- [ ] All tools load without errors
- [ ] Tool functions imported in `tools/__init__.py` (⚠️ Auto-generated, verify they exist)
- [ ] Category registered in `default_config.py`
**Validation Commands**:
```bash
python3 -m json.tool src/tooluniverse/data/{category}_tools.json # Validate JSON
python3 -m py_compile src/tooluniverse/{category}_tool.py # Check syntax
```
#### Step 7.3: Documentation
- [ ] Tool descriptions are clear and complete
- [ ] Parameter descriptions include examples
- [ ] Return schemas match actual output
- [ ] Create example script in `examples/`
- [ ] Document findings and fixes
### Complete Tool Improvement Checklist Summary
**Quick Reference - Run through all phases**:
**Phase 1: Initial Assessment**
- [ ] Identify all tool files
- [ ] Verify basic structure (class names, JSON validity, loading)
**Phase 2: Functionality Testing**
- [ ] Test tool execution with sample inputs
- [ ] Test API endpoints directly
- [ ] Verify meaningful content returned
**Phase 3: Description Improvement**
- [ ] Review and improve tool descriptions
- [ ] Review and improve parameter descriptions
- [ ] Review and improve return schemas
**Phase 4: Error Handling**
- [ ] Review current error handling
- [ ] Improve error messages (specific, actionable)
- [ ] Add retry logic if needed
**Phase 5: Finding Missing Tools**
- [ ] Research API capabilities
- [ ] Create gap analysis matrix
- [ ] Identify subset extraction opportunities
**Phase 6: Fix Common Issues**
- [ ] Fix tool class name mismatches
- [ ] Fix response format mismatches
- [ ] Fix endpoint URL issues
- [ ] Add missing error handling
**Phase 7: Final Verification**
- [ ] Comprehensive testing
- [ ] Validation checks
- [ ] Documentation updates
---
## 3. Quick Reference: Common Commands
### Validation
```bash
python3 -m json.tool src/tooluniverse/data/{category}_tools.json # Validate JSON
python3 -m py_compile src/tooluniverse/{category}_tool.py # Check syntax
```
### Testing
```bash
python3 examples/{category}_tools_example.py # Test tool execution
```
### Finding Tools
```bash
ls src/tooluniverse/tools/{category}_*.py # List tool files
grep -c "\"name\":" src/tooluniverse/data/{category}_tools.json # Count tools
grep "@register_tool" src/tooluniverse/{category}_tool.py # Check registration
```
---