mirror of
https://github.com/mims-harvard/ToolUniverse.git
synced 2026-09-19 07:31:47 +08:00
08246bcd4d
* docs: expand redirect map with 15 additional legacy paths Adds redirects for paths uncovered in a second-pass audit against the live published site. Each destination verified to return HTTP 200 on https://zitniklab.hms.harvard.edu/ToolUniverse/. New /tutorials/ → /guide/, /tools/, /expand_tooluniverse/ redirects: - make_your_data_searchable, make_your_data_agent_searchable, build_search_and_share_datastores → guide/make_your_data_agent_searchable - skills → guide/skills_showcase - tool_finder → guide/finding_tools - overview → guide/index - remote_tools → tools/remote_tools - mcp_integration → expand_tooluniverse/remote_tools/mcp_integration Top-level legacy pages (404 at root, now redirected): - getting_started → guide/python_guide - deployment, contributing, changelog → about/<page> - faq → help/faq Local build confirms all 22 redirect stubs generate and that every destination file exists in the build output. * docs: fix broken sphinx-tabs, dead toctrees, orphan pages, missing image Build now produces 0 warnings/errors of these structural categories (down from ~280 such issues): - Re-enable sphinx_tabs.tabs extension (3.5.0 supports Sphinx 9.x); fixes 7 broken "Unknown directive type tabs" errors that made help/faq.html and help/troubleshooting.html render incomplete. - Drop 25+ dead toctree entries in api/modules.rst and api/tooluniverse.rst that referenced per-module pages never generated by sphinx-apidoc; modules.rst now points at the existing comprehensive tooluniverse autodoc page. - Wire 16 orphan pages into the master toctree so they're reachable from the navigation, including tooluniverse_case_study, visualization_tutorial, expert_feedback, literature_search_web_ui, euhealth, logging, openrouter, streaming, vllm, wechat_community, simbad_tools, the guide/index landing page, and the full expand_tooluniverse sub-tree. - Remove three stale ":doc:" links to old/{quickstart,installation, getting_started} from sitemap.rst (those directories are excluded from the build) and mark sitemap.rst as :orphan: since it's a parallel nav surface by design. - Mark MCP_TASKS_GUIDE.md as orphan and exclude the internal DOCUMENTATION_STRUCTURE.md meta-doc from the build. - Add the missing tools/remote/ui.jpg referenced by the remote expert_feedback page (previously: broken image). * docs: eliminate all 49 structural Sphinx ERRORs (broken tables, directives, headings) Round-3 build cleanup. Builds now finish with 0 structural ERRORs of any category (previous: 49 ERRORs spread across 20 files). Total warnings/errors dropped from 280 → 114; the remaining 114 are all in Python source-file docstrings (out of scope for a docs PR). Categories fixed: **Malformed tables** (8 files) Replace ASCII grid tables with mis-aligned pipes and inline-markdown pipe tables (which RST mis-parses as substitution references) with ``list-table`` directives that render correctly across all themes: - guide/literature_search_tools_tutorial.rst (two tables) - guide/cache_system.rst (env-var table whose first column overflowed) - guide/clinical_guidelines_tools.rst - guide/make_your_data_agent_searchable.rst - expand_tooluniverse/contributing/index.rst - expand_tooluniverse/contributing/remote_tools.rst - expand_tooluniverse/reference/index.rst **list-table indentation** (3 files) Option lines and list items were indented with 1 space (only valid for 3-space) so Sphinx silently dropped them and reported "exactly one bullet list expected": - guide/finding_tools.rst - guide/http_api.rst - guide/tools.rst **Code-block separators** (5 files, ~30 directives) Add the required blank line between an introductory paragraph and a following ``.. code-block::``. Without it, Sphinx treated the directive as a continuation of the paragraph and emitted "Unexpected indentation" for every line of the code: - guide/literature_search_tools_tutorial.rst - expand_tooluniverse/quick_start.rst - expand_tooluniverse/contributing/local_tools.rst - expand_tooluniverse/contributing/remote_tools.rst - guide/make_your_data_agent_searchable.rst **Heading-style + indentation** (3 files) - guide/building_ai_scientists/mcp_name_shortening.rst — strip stray leading spaces from two section titles + downgrade unknown ``.. critical::`` to ``.. important::`` - about/deployment.rst — remove rogue ``=========`` underline below numbered-list items that mis-led the parser into skipping heading levels - guide/make_your_data_agent_searchable.rst — extend four "title underline too short" underlines + convert four markdown ``` fences to RST literal blocks **Misc directive / target fixes** - guide/python_guide.rst — replace nonexistent ``.. success::`` with a tip-styled ``.. admonition::`` - guide/euhealth_tools_tutorial.rst — indent ``.. note::`` body so it is no longer an empty admonition - help/troubleshooting.rst — same fix + remove rogue ``=========`` line that was being read as a section overline - tools/cellosaurus_tools.rst — wrap ``CVCL_`` in literal backticks so the trailing underscore stops triggering missing-target lookups - expand_tooluniverse/index.rst — promote two leading-space bullet lists to standalone lists so the indentation is correct - expand_tooluniverse/reference/architecture.rst — switch ``.. graphviz::`` (extension not installed) to a plain ``.. code-block:: text``; the embedded content was Mermaid pseudo-code anyway - guide/tools.rst — strip leading space on a section title * docs: clear all remaining content warnings (lists, headings, refs, grids) Round-4 build cleanup. Builds now finish with 0 structural ERRORs and 0 content WARNINGs; the only remaining ~11 warnings are pre-existing autodoc infrastructure noise (duplicate object index entries from autosummary, and the ghost_tool / medrxiv_tool modules that genuinely fail to import) — none are in hand-written documentation. Fixes in this commit: **sphinx-design grids** (python_guide.rst) Re-indent two ``.. grid::`` blocks whose first card + options used 1-space indentation (Sphinx silently dropped them → "parent of grid-item should be grid-row"). Also fix a ``.. button-ref::`` whose content was indented 1 space, producing a broken ``:any:`` cross-reference, and point it at the absolute ``/api/modules``. **Numbered/bulleted sub-lists** (tool_composition, literature_search ×2, architecture, literature_search_web_ui, make_your_data, agentic_tools, finding_tools, euhealth) Insert the required blank line before nested lists and re-indent 1-space sub-bullets to align under their parent list marker. Clears ~80 "list ends without a blank line; unexpected unindent" warnings. **Title underlines** (logging, tool_caller, loading_tools, tool_composition, euhealth, make_your_data, contributing/local_tools, reference/index, remote_tools/tutorial, troubleshooting + bulk pass) Extend underlines shorter than their title text; strip stray leading spaces from section titles that Sphinx read as block quotes. **Stray markdown in RST** (make_your_data, local_tools) Convert leftover ``###`` headings and ``` ``` fences to proper RST directives; remove a rogue ``------`` separator that was being parsed as a section underline. **Duplicate autosectionlabel** (make_your_data) Rename the second "How it works" heading to "How sharing works". **uniprot_tools** (JSON + generated RST) Rephrase the ``min_length`` / ``max_length`` descriptions so the open-ended range syntax no longer contains a bare ``*`` that RST read as an unterminated emphasis marker. Fixed in the JSON source so it survives doc regeneration.
598 lines
23 KiB
ReStructuredText
598 lines
23 KiB
ReStructuredText
Tool Composition Tutorial
|
|
=========================
|
|
|
|
**Chain ToolUniverse's 1000+ tools into powerful scientific workflows**
|
|
|
|
Overview
|
|
--------
|
|
|
|
Tool composition is the art of combining individual scientific tools into sophisticated research workflows. ToolUniverse's Tool Composer enables the integration of tools with heterogeneous backends to build end-to-end workflows. By leveraging the Tool Caller for direct in-code execution, Tool Composer generates a container function that exposes both the Tool Caller and ToolUniverse as in-line, executable primitives.
|
|
|
|
.. code-block:: text
|
|
|
|
Individual Tools → Composed Workflows → Research Solutions
|
|
|
|
Example: Literature Search & Summary Tool
|
|
|
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
│EuropePMC │ │ Literature │ │ Research │
|
|
│OpenAlex │ → │ Search & │ → │ Summary │
|
|
│PubTator │ │ Summary │ │ Generated │
|
|
│AI Reviewer │ │ Tool │ │ │
|
|
└─────────────┘ └─────────────┘ └─────────────┘
|
|
|
|
**Benefits of Tool Composition**:
|
|
- **Complex Research**: Solve multi-step problems that no single tool can address
|
|
- **Workflow Reuse**: Create reusable research pipelines for common tasks
|
|
- **Automation**: Reduce manual coordination between different tools
|
|
- **Quality Control**: Build in validation and expert review at critical steps
|
|
- **Heterogeneous Integration**: Combine tools with different backends seamlessly
|
|
- **Agentic Loops**: Enable adaptive, multi-step experimental analysis
|
|
|
|
Tool Composer Architecture
|
|
---------------------------
|
|
|
|
The Tool Composer generates a container function that serves as the execution backbone for complex workflows. This container function, implemented as `compose(arguments, tooluniverse, call_tool)`, contains the logic for coordinating different types of tools so they work together in a single workflow.
|
|
|
|
**Container Function Components**:
|
|
|
|
1. **arguments**: Specifies the tool call arguments that follow the interaction protocol schema of ToolUniverse
|
|
2. **tooluniverse**: An instance of ToolUniverse that provides all available functions that ToolUniverse can support
|
|
3. **call_tool**: A callable interface of Tool Caller that abstracts the invocation of individual tools in ToolUniverse
|
|
|
|
**Execution Patterns**:
|
|
- **Chaining**: Chain the output of one tool into the input of the next
|
|
- **Broadcasting**: Call multiple tools with a single query
|
|
- **Agentic Loops**: Build agentic loops that use agentic tools to generate function calls, execute tools, and incorporate tool feedback for multi-step experimental analysis
|
|
|
|
How Tool Composition Works
|
|
---------------------------
|
|
|
|
ToolUniverse's ComposeTool system works through a configuration-driven approach:
|
|
|
|
1. **Configuration File**: Define compose tools in a JSON file like `compose_tools.json`
|
|
2. **Implementation Script**: Write Python scripts in the compose environment: `def compose(arguments, tooluniverse, call_tool): ...`
|
|
3. **Automatic Loading**: ComposeTool automatically loads dependencies and executes workflows
|
|
|
|
Creating Your First Compose Tool
|
|
---------------------------------
|
|
|
|
Let's create a literature search and summary tool as an example:
|
|
|
|
Step 1: Create the Implementation Script
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Create a file `src/tooluniverse/compose_scripts/literature_tool.py`:
|
|
|
|
.. code-block:: python
|
|
|
|
"""
|
|
Literature Search & Summary Tool
|
|
Minimal compose tool perfect for paper screenshots
|
|
"""
|
|
|
|
def compose(arguments, tooluniverse, call_tool):
|
|
"""Search literature and generate summary"""
|
|
topic = arguments['research_topic']
|
|
|
|
literature = {}
|
|
literature['pmc'] = call_tool('EuropePMC_search_articles', {'query': topic, 'limit': 5})
|
|
literature['openalex'] = call_tool('openalex_literature_search', {'search_keywords': topic, 'max_results': 5})
|
|
literature['pubtator'] = call_tool('PubTator3_LiteratureSearch', {'text': topic, 'page_size': 5})
|
|
|
|
summary = call_tool('MedicalLiteratureReviewer', {
|
|
'research_topic': topic, 'literature_content': str(literature),
|
|
'focus_area': 'key findings', 'study_types': 'all studies',
|
|
'quality_level': 'all evidence', 'review_scope': 'rapid review'
|
|
})
|
|
|
|
return summary
|
|
|
|
Step 2: Add Configuration to compose_tools.json
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Add this configuration to `src/tooluniverse/data/compose_tools.json`:
|
|
|
|
.. code-block:: json
|
|
|
|
{
|
|
"type": "ComposeTool",
|
|
"name": "LiteratureSearchTool",
|
|
"description": "Comprehensive literature search and summary tool that searches multiple databases (EuropePMC, OpenAlex, PubTator) and generates AI-powered summaries of research findings",
|
|
"parameter": {
|
|
"type": "object",
|
|
"properties": {
|
|
"research_topic": {
|
|
"type": "string",
|
|
"description": "The research topic or query to search for in the literature"
|
|
}
|
|
},
|
|
"required": ["research_topic"]
|
|
},
|
|
"auto_load_dependencies": true,
|
|
"fail_on_missing_tools": false,
|
|
"required_tools": [
|
|
"EuropePMC_search_articles",
|
|
"openalex_literature_search",
|
|
"PubTator3_LiteratureSearch",
|
|
"MedicalLiteratureReviewer"
|
|
],
|
|
"composition_file": "literature_tool.py",
|
|
"composition_function": "compose"
|
|
}
|
|
|
|
Step 3: Use Your Compose Tool
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Once configured, you can use your compose tool like any other ToolUniverse tool:
|
|
|
|
.. code-block:: python
|
|
|
|
from tooluniverse import ToolUniverse
|
|
|
|
# Initialize ToolUniverse
|
|
tu = ToolUniverse()
|
|
|
|
# Load compose tools
|
|
tu.load_tools(['compose_tools'])
|
|
|
|
# Use your literature search tool
|
|
result = tu.run({"name": "LiteratureSearchTool", "arguments": {'research_topic': 'COVID-19 vaccine efficacy'}})
|
|
|
|
print(result)
|
|
|
|
Compose Tool Configuration Reference
|
|
------------------------------------
|
|
|
|
Required Fields
|
|
~~~~~~~~~~~~~~~
|
|
|
|
- **type**: Must be "ComposeTool"
|
|
- **name**: Unique name for your compose tool
|
|
- **description**: Human-readable description of what the tool does
|
|
- **parameter**: JSON schema defining input parameters
|
|
- **composition_file**: Python file in `compose_scripts/` directory
|
|
- **composition_function**: Function name to call (usually "compose")
|
|
|
|
Optional Fields
|
|
~~~~~~~~~~~~~~~
|
|
|
|
- **auto_load_dependencies**: Whether to automatically load required tools (default: true)
|
|
- **fail_on_missing_tools**: Whether to fail if required tools are missing (default: false)
|
|
- **required_tools**: List of tool names that must be available
|
|
|
|
Compose Function Signature
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Your compose function must follow this exact signature:
|
|
|
|
.. code-block:: python
|
|
|
|
def compose(arguments, tooluniverse, call_tool):
|
|
"""
|
|
Compose function signature
|
|
|
|
Args:
|
|
arguments (dict): Input parameters from the tool call
|
|
tooluniverse (ToolUniverse): Reference to the ToolUniverse instance
|
|
call_tool (function): Function to call other tools
|
|
|
|
Returns:
|
|
Any: The result of your composition
|
|
"""
|
|
# Your composition logic here
|
|
pass
|
|
|
|
Heterogeneous Workflow Construction
|
|
------------------------------------
|
|
|
|
As illustrated in the ToolUniverse paper, a composed tool can run several literature search tools concurrently and then invoke a summarization agent to synthesize the findings, demonstrating heterogeneous workflow construction in which each step is driven by tool execution. This approach enables:
|
|
|
|
- **Multi-backend Integration**: Combine tools from different scientific databases and APIs
|
|
- **Concurrent Execution**: Run multiple tools simultaneously for efficiency
|
|
- **Intelligent Synthesis**: Use AI agents to synthesize results from heterogeneous sources
|
|
- **Adaptive Analysis**: Build workflows that can adapt based on intermediate results
|
|
|
|
Core Composition Patterns
|
|
--------------------------
|
|
|
|
1. Sequential Chaining
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
**Use Case**: Linear workflows where each step depends on the previous one
|
|
|
|
**Pattern**: Chain the output of one tool into the input of the next
|
|
|
|
.. code-block:: python
|
|
|
|
def compose(arguments, tooluniverse, call_tool):
|
|
"""Sequential pipeline: Disease → Targets → Drugs → Safety Assessment"""
|
|
|
|
disease_id = arguments['disease_efo_id']
|
|
|
|
# Step 1: Find disease-associated targets
|
|
targets_result = call_tool('OpenTargets_get_associated_targets_by_disease_efoId', {
|
|
'efoId': disease_id
|
|
})
|
|
|
|
top_targets = targets_result["data"]["disease"]["associatedTargets"]["rows"][:5]
|
|
|
|
# Step 2: Find known drugs for this disease
|
|
drugs_result = call_tool('OpenTargets_get_associated_drugs_by_disease_efoId', {
|
|
'efoId': disease_id,
|
|
'size': 20
|
|
})
|
|
|
|
drug_rows = drugs_result["data"]["disease"]["knownDrugs"]["rows"]
|
|
|
|
# Step 3: Extract SMILES and assess safety
|
|
safety_assessments = []
|
|
processed_drugs = set()
|
|
|
|
for drug in drug_rows[:5]: # Limit for demo
|
|
drug_name = drug["drug"]["name"]
|
|
if drug_name in processed_drugs:
|
|
continue
|
|
processed_drugs.add(drug_name)
|
|
|
|
# Get SMILES from drug name
|
|
cid_result = call_tool('PubChem_get_CID_by_compound_name', {
|
|
'name': drug_name
|
|
})
|
|
|
|
if cid_result and 'IdentifierList' in cid_result:
|
|
cids = cid_result['IdentifierList']['CID']
|
|
if cids:
|
|
smiles_result = call_tool('PubChem_get_compound_properties_by_CID', {
|
|
'cid': cids[0]
|
|
})
|
|
|
|
if smiles_result and 'PropertyTable' in smiles_result:
|
|
properties = smiles_result['PropertyTable']['Properties'][0]
|
|
smiles = properties.get('CanonicalSMILES') or properties.get('ConnectivitySMILES')
|
|
|
|
if smiles:
|
|
# Assess safety properties
|
|
bbb_result = call_tool('ADMETAI_predict_BBB_penetrance', {
|
|
'smiles': [smiles]
|
|
})
|
|
|
|
safety_assessments.append({
|
|
'drug_name': drug_name,
|
|
'smiles': smiles,
|
|
'bbb_penetrance': bbb_result
|
|
})
|
|
|
|
return {
|
|
'disease': disease_id,
|
|
'targets_found': len(top_targets),
|
|
'drugs_analyzed': len(safety_assessments),
|
|
'safety_results': safety_assessments
|
|
}
|
|
|
|
2. Broadcasting (Parallel Execution)
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
**Use Case**: Independent operations that can run simultaneously
|
|
|
|
**Pattern**: Call multiple tools with a single query (broadcasting)
|
|
|
|
.. code-block:: python
|
|
|
|
def compose(arguments, tooluniverse, call_tool):
|
|
"""Parallel search across multiple literature databases"""
|
|
|
|
research_topic = arguments['research_topic']
|
|
|
|
# Execute searches in parallel
|
|
literature = {}
|
|
literature['pmc'] = call_tool('EuropePMC_search_articles', {
|
|
'query': research_topic, 'limit': 50
|
|
})
|
|
literature['openalex'] = call_tool('openalex_literature_search', {
|
|
'search_keywords': research_topic, 'max_results': 50
|
|
})
|
|
literature['pubtator'] = call_tool('PubTator3_LiteratureSearch', {
|
|
'text': research_topic, 'page_size': 50
|
|
})
|
|
|
|
# Synthesize findings using AI agent
|
|
synthesis = call_tool('MedicalLiteratureReviewer', {
|
|
'research_topic': research_topic,
|
|
'literature_content': str(literature),
|
|
'focus_area': 'key findings',
|
|
'study_types': 'all studies',
|
|
'quality_level': 'all evidence',
|
|
'review_scope': 'comprehensive review'
|
|
})
|
|
|
|
return {
|
|
'topic': research_topic,
|
|
'sources_searched': len(literature),
|
|
'total_papers': sum(len(r.get('documents', r.get('papers', [])))
|
|
for r in literature.values()),
|
|
'synthesis': synthesis,
|
|
'detailed_results': literature
|
|
}
|
|
|
|
3. Agentic Loops
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
**Use Case**: Iterative optimization with AI guidance and tool feedback
|
|
|
|
**Pattern**: Build agentic loops that use agentic tools to generate function calls, execute tools, and incorporate tool feedback for multi-step experimental analysis
|
|
|
|
.. code-block:: python
|
|
|
|
def compose(arguments, tooluniverse, call_tool):
|
|
"""Iterative compound optimization with AI-guided feedback loops"""
|
|
|
|
initial_smiles = arguments['initial_smiles']
|
|
target_protein = arguments['target_protein']
|
|
|
|
current_compound = initial_smiles
|
|
optimization_history = []
|
|
max_iterations = 5
|
|
target_affinity = -8.0 # Strong binding threshold
|
|
|
|
for iteration in range(max_iterations):
|
|
# Step 1: Predict binding affinity using molecular docking
|
|
binding_result = call_tool('boltz2_docking', {
|
|
'protein_id': target_protein,
|
|
'ligand_smiles': current_compound
|
|
})
|
|
|
|
# Step 2: Predict ADMET properties
|
|
bbb_result = call_tool('ADMETAI_predict_BBB_penetrance', {
|
|
'smiles': [current_compound]
|
|
})
|
|
|
|
bio_result = call_tool('ADMETAI_predict_bioavailability', {
|
|
'smiles': [current_compound]
|
|
})
|
|
|
|
tox_result = call_tool('ADMETAI_predict_toxicity', {
|
|
'smiles': [current_compound]
|
|
})
|
|
|
|
# Step 3: Record iteration data
|
|
iteration_data = {
|
|
'iteration': iteration,
|
|
'compound': current_compound,
|
|
'binding_affinity': binding_result.get('binding_affinity'),
|
|
'binding_probability': binding_result.get('binding_probability'),
|
|
'bbb_penetrance': bbb_result,
|
|
'bioavailability': bio_result,
|
|
'toxicity': tox_result
|
|
}
|
|
optimization_history.append(iteration_data)
|
|
|
|
# Step 4: Check if target achieved
|
|
if binding_result.get('binding_affinity', 0) <= target_affinity:
|
|
break
|
|
|
|
# Step 5: AI-guided compound optimization
|
|
# Use an agentic tool to analyze current results and suggest improvements
|
|
optimization_suggestion = call_tool('ChemicalOptimizationAgent', {
|
|
'current_compound': current_compound,
|
|
'current_properties': iteration_data,
|
|
'optimization_goals': ['binding_affinity', 'oral_bioavailability'],
|
|
'target_protein': target_protein
|
|
})
|
|
|
|
# Step 6: Generate next compound based on AI feedback
|
|
next_compound = call_tool('CompoundGenerator', {
|
|
'base_compound': current_compound,
|
|
'optimization_suggestions': optimization_suggestion,
|
|
'modification_type': 'targeted_improvement'
|
|
})
|
|
|
|
current_compound = next_compound.get('new_compound', current_compound)
|
|
|
|
return {
|
|
'initial_compound': initial_smiles,
|
|
'final_compound': current_compound,
|
|
'iterations': len(optimization_history),
|
|
'optimization_history': optimization_history,
|
|
'target_achieved': binding_result.get('binding_affinity', 0) <= target_affinity
|
|
}
|
|
|
|
4. Error Handling and Fallbacks
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
**Use Case**: Robust workflows that handle failures gracefully
|
|
|
|
**Pattern**: Implement fallback mechanisms and graceful degradation
|
|
|
|
.. code-block:: python
|
|
|
|
def compose(arguments, tooluniverse, call_tool):
|
|
"""Workflow with comprehensive error handling and fallbacks"""
|
|
|
|
results = {"status": "running", "completed_steps": []}
|
|
|
|
try:
|
|
# Step 1: Critical initial step
|
|
step1_result = call_tool('critical_analysis_tool', arguments)
|
|
results["step1"] = step1_result
|
|
results["completed_steps"].append("step1")
|
|
|
|
except Exception as e:
|
|
results["status"] = "failed"
|
|
results["error"] = f"Step 1 failed: {str(e)}"
|
|
return results
|
|
|
|
try:
|
|
# Step 2: Optional enhancement step
|
|
step2_result = call_tool('enhancement_tool', {"data": step1_result})
|
|
results["step2"] = step2_result
|
|
results["completed_steps"].append("step2")
|
|
|
|
except Exception as e:
|
|
# Continue without this step
|
|
results["step2_warning"] = f"Enhancement step failed: {str(e)}"
|
|
|
|
# Step 3: Alternative approaches with fallback
|
|
try:
|
|
step3_result = call_tool('primary_validation_tool', {"data": step1_result})
|
|
results["validation"] = step3_result
|
|
|
|
except Exception:
|
|
# Fallback validation method
|
|
try:
|
|
fallback_result = call_tool('alternative_validation_tool', {"data": step1_result})
|
|
results["validation"] = fallback_result
|
|
results["validation_method"] = "fallback"
|
|
|
|
except Exception as e:
|
|
results["validation_error"] = str(e)
|
|
|
|
results["status"] = "completed"
|
|
return results
|
|
|
|
Real-World Composition Examples
|
|
-------------------------------
|
|
|
|
For comprehensive examples of compose tools in action, see the :doc:`scientific_workflows` Tutorial, which includes:
|
|
|
|
- **Comprehensive Drug Discovery Pipeline**: End-to-end workflow from target identification to safety assessment
|
|
- **Biomarker Discovery Workflow**: Multi-step biomarker validation using literature, expression data, and pathway analysis
|
|
- **Advanced Literature Review**: AI-powered systematic reviews with citation analysis
|
|
- **Agentic Research Workflows**: Adaptive workflows that use AI feedback for multi-step analysis
|
|
|
|
These examples demonstrate how compose tools can orchestrate complex scientific workflows, combining tools from different backends to solve real-world research problems.
|
|
|
|
Tool Caller Interface
|
|
-----------------------
|
|
|
|
The Tool Caller provides a callable interface that abstracts the invocation of individual tools in ToolUniverse. This abstraction enables:
|
|
|
|
- **Unified Tool Access**: All tools are accessed through the same `call_tool` interface
|
|
- **Protocol Compliance**: Tool calls follow the interaction protocol schema of ToolUniverse
|
|
- **Error Handling**: Consistent error handling across different tool types
|
|
- **Dependency Management**: Automatic loading and management of tool dependencies
|
|
|
|
**Tool Caller Usage Pattern**:
|
|
|
|
.. code-block:: python
|
|
|
|
def compose(arguments, tooluniverse, call_tool):
|
|
# Direct tool invocation through the Tool Caller interface
|
|
result = call_tool('tool_name', {'param1': 'value1', 'param2': 'value2'})
|
|
|
|
# The call_tool function handles:
|
|
# - Tool loading and instantiation
|
|
# - Parameter validation
|
|
# - Execution and error handling
|
|
# - Result formatting
|
|
|
|
return result
|
|
|
|
Troubleshooting
|
|
---------------
|
|
|
|
Common Issues and Solutions
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
1. **Tool Not Found Error**
|
|
|
|
- Check that the tool name is correct in your compose script
|
|
- Ensure the tool is loaded in ToolUniverse
|
|
- Verify the tool is in the `required_tools` list
|
|
- Use `auto_load_dependencies: true` to automatically load missing tools
|
|
|
|
2. **Import Errors**
|
|
|
|
- Make sure your compose script is in the `compose_scripts/` directory
|
|
- Check that the function name matches `composition_function`
|
|
- Verify the function signature is correct: `def compose(arguments, tooluniverse, call_tool):`
|
|
|
|
3. **Parameter Errors**
|
|
|
|
- Validate your parameter schema in the JSON configuration
|
|
- Check that required parameters are provided
|
|
- Ensure parameter types match the schema
|
|
- Follow the interaction protocol schema of ToolUniverse
|
|
|
|
4. **Performance Issues**
|
|
|
|
- Limit the number of tools called in sequence
|
|
- Use `auto_load_dependencies: true` for automatic loading
|
|
- Consider caching results for repeated calls
|
|
- Implement proper error handling to avoid cascading failures
|
|
|
|
5. **Heterogeneous Backend Issues**
|
|
|
|
- Ensure all required tools are available across different backends
|
|
- Use `fail_on_missing_tools: false` for graceful degradation
|
|
- Implement fallback mechanisms for critical workflow steps
|
|
|
|
Available Compose Tools
|
|
------------------------
|
|
|
|
ToolUniverse currently provides several pre-built compose tools that demonstrate different workflow patterns:
|
|
|
|
** Working Compose Tools**:
|
|
|
|
1. **LiteratureSearchTool** - Literature research and synthesis
|
|
|
|
- Searches EuropePMC, OpenAlex, and PubTator databases
|
|
- Uses AI agent for literature summarization
|
|
- Demonstrates broadcasting pattern
|
|
|
|
2. **ComprehensiveDrugDiscoveryPipeline** - End-to-end drug discovery
|
|
|
|
- Target identification using OpenTargets
|
|
- Lead discovery from known drugs
|
|
- Safety assessment using ADMETAI tools
|
|
- Literature validation
|
|
- Demonstrates sequential chaining with tool integration
|
|
|
|
3. **BiomarkerDiscoveryWorkflow** - Biomarker discovery and validation
|
|
|
|
- Literature-based biomarker discovery
|
|
- Multi-strategy gene search using HPA
|
|
- Comprehensive pathway analysis using HPA tools
|
|
- Clinical validation using FDA data
|
|
- Demonstrates multi-strategy fallbacks and error handling
|
|
|
|
4. **DrugSafetyAnalyzer** - Drug safety assessment
|
|
|
|
- PubChem compound information retrieval
|
|
- EuropePMC literature search
|
|
- Demonstrates safety-focused workflows
|
|
|
|
5. **ToolDescriptionOptimizer** - Tool optimization
|
|
|
|
- AI-powered tool description improvement
|
|
- Test case generation and quality evaluation
|
|
- Demonstrates agentic optimization loops
|
|
|
|
6. **ToolDiscover** - Tool discovery and generation
|
|
|
|
- AI-powered tool creation from descriptions
|
|
- Iterative code improvement
|
|
- Demonstrates advanced agentic workflows
|
|
|
|
**Key Features**:
|
|
- **All tools tested and working** with real data processing
|
|
- **Comprehensive error handling** with graceful fallbacks
|
|
- **Tool chaining** for complex multi-step workflows
|
|
- **Dynamic data extraction** (e.g., SMILES from drug names)
|
|
- **Multi-strategy approaches** for robust data retrieval
|
|
|
|
.. seealso::
|
|
|
|
- :doc:`../expand_tooluniverse/architecture` - ToolUniverse architecture
|
|
- :doc:`building_ai_scientists/index` - Connect to AI agents
|
|
- :doc:`scientific_workflows` - Real composition examples
|
|
|
|
.. tip::
|
|
**Start simple**: Begin with sequential workflows like the LiteratureSearchTool example, then progress to more complex patterns as you become comfortable with tool composition.
|
|
|
|
.. note::
|
|
**Compose Tool Location**: All compose scripts must be placed in `src/tooluniverse/compose_scripts/` directory and registered in `src/tooluniverse/data/compose_tools.json`.
|
|
|
|
.. important::
|
|
**Tool Composer Architecture**: The Tool Composer generates container functions that expose ToolUniverse and Tool Caller as in-line, executable primitives, enabling flexible multi-tool execution patterns for complex scientific workflows.
|