Source code for tooluniverse.scicrunch_rrid_tool

# scicrunch_rrid_tool.py
"""
SciCrunch RRID resolver tool for ToolUniverse.

RRIDs (Research Resource Identifiers) are the citation standard journals
increasingly require for antibodies, cell lines, model organisms,
plasmids, and software/tools, so a paper's methods section can be resolved
to exactly which resource was used. ToolUniverse already has a dedicated,
richer Antibody Registry tool for the AB_ prefix (the majority of RRIDs);
this tool resolves any RRID prefix through SciCrunch's own registry,
covering the categories that tool does not: SCR_ (software/tools),
cell lines, organisms, and plasmids, plus serving as a general fallback.

API: https://scicrunch.org/resolver
No authentication required.
"""

from typing import Any, Dict, List

import requests

from .base_tool import BaseTool
from .tool_registry import register_tool

RESOLVER_URL = "https://scicrunch.org/resolver"


def _names(entries: Any) -> List[str]:
    """Flatten SciCrunch's list-of-{name:...} fields to plain strings."""
    if not isinstance(entries, list):
        return []
    return [e.get("name") for e in entries if isinstance(e, dict) and e.get("name")]


[docs] @register_tool("SciCrunchRRIDTool") class SciCrunchRRIDTool(BaseTool): """ Tool for resolving Research Resource Identifiers (RRIDs) via SciCrunch. Supports any RRID prefix (antibodies, software/tools, cell lines, organisms, plasmids), returning the resource's name, description, category, and citation. No authentication required. """
[docs] def __init__(self, tool_config: Dict[str, Any]): super().__init__(tool_config) self.timeout = tool_config.get("timeout", 30) self.operation = tool_config.get("fields", {}).get( "operation", "resolve_rrid" )
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Execute the RRID resolution.""" try: if self.operation == "resolve_rrid": return self._resolve_rrid(arguments) return { "status": "error", "error": f"Unknown operation: {self.operation}", } except requests.exceptions.Timeout: return { "status": "error", "error": f"SciCrunch request timed out after {self.timeout}s", } except requests.exceptions.ConnectionError: return { "status": "error", "error": "Failed to connect to SciCrunch. Check network.", } except requests.exceptions.HTTPError as e: code = e.response.status_code if e.response is not None else "unknown" return {"status": "error", "error": f"SciCrunch returned HTTP {code}"} except ValueError: return { "status": "error", "error": "SciCrunch returned a non-JSON response", } except Exception as e: return { "status": "error", "error": f"Error querying SciCrunch: {str(e)}", }
[docs] def _resolve_rrid(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Resolve one RRID to its resource record.""" rrid = (arguments.get("rrid") or "").strip() if not rrid: return { "status": "error", "error": "rrid is required, e.g. 'RRID:SCR_002526' or " "'SCR_002526'. Prefix is optional.", } identifier = rrid if rrid.upper().startswith("RRID:") else f"RRID:{rrid}" response = requests.get( f"{RESOLVER_URL}/{identifier}.json", timeout=self.timeout ) if response.status_code == 404: return { "status": "error", "error": f"No SciCrunch record for '{rrid}'.", } response.raise_for_status() payload = response.json() hits = (payload.get("hits") or {}).get("hits") or [] if not hits: return { "status": "error", "error": f"No SciCrunch record for '{rrid}'.", } source = hits[0].get("_source") or {} item = source.get("item") or {} rrid_info = source.get("rrid") or {} current_urls = [ d.get("uri") for d in (source.get("distributions") or {}).get("current") or [] if d.get("uri") ] return { "status": "success", "data": { "rrid": rrid_info.get("curie") or identifier, "name": item.get("name"), "description": item.get("description"), "categories": _names(item.get("types")), "keywords": [ k.get("keyword") for k in item.get("keywords") or [] if isinstance(k, dict) and k.get("keyword") ], "synonyms": _names(item.get("synonyms")), "proper_citation": rrid_info.get("properCitation"), "landing_page_urls": current_urls, }, "metadata": { "rrid": rrid, "note": "For antibody RRIDs (AB_ prefix), " "AntibodyRegistry_resolve_rrid returns richer " "antibody-specific fields (target, clonality, host).", "source": "SciCrunch Registry", }, }