Source code for tooluniverse.iedb_tool

from __future__ import annotations

from typing import Any, Dict, Mapping

import requests

from .base_tool import BaseTool
from .http_utils import request_with_retry
from .tool_registry import register_tool


[docs] @register_tool("IEDBTool") class IEDBTool(BaseTool): """ Tool for interacting with the IEDB Query API (PostgREST). This tool is JSON-config driven: each tool config supplies `fields.endpoint` and (optionally) `fields.default_params` + `fields.shorthand_filters` to map friendly arguments into PostgREST filter expressions (e.g., `eq.123`, `ilike.*KVF*`). """ QUERY_API_URL = "https://query-api.iedb.org"
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: fields = self.tool_config.get("fields") or {} endpoint = fields.get("endpoint") if not endpoint or not isinstance(endpoint, str): return { "status": "error", "error": "Tool misconfigured: missing fields.endpoint", "detail": ( "Expected tool_config.fields.endpoint (string) like " "'/epitope_search'." ), } url = f"{self.QUERY_API_URL}{endpoint}" params: Dict[str, Any] = {} default_params = fields.get("default_params") or {} if isinstance(default_params, Mapping): params.update(default_params) # Common paging / projection knobs (PostgREST) if arguments.get("limit") is not None: params["limit"] = arguments.get("limit") if arguments.get("offset") is not None: params["offset"] = arguments.get("offset") if arguments.get("order"): params["order"] = arguments.get("order") select = arguments.get("select") if select: if isinstance(select, list): params["select"] = ",".join(str(x) for x in select if x) else: params["select"] = str(select) # Advanced filters: caller provides PostgREST expressions, e.g.: # {"linear_sequence": "ilike.*KVF*", "structure_type": "eq.Linear peptide"} raw_filters = arguments.get("filters") or {} if isinstance(raw_filters, Mapping): for k, v in raw_filters.items(): if k and v is not None: params[str(k)] = str(v) # Shorthand filters: map friendly args into PostgREST expressions. # Example in tool config: # "shorthand_filters": {"sequence_contains": {"column": "linear_sequence", # "op": "ilike_contains"}} shorthand = fields.get("shorthand_filters") or {} if isinstance(shorthand, Mapping): for arg_name, spec in shorthand.items(): if not arg_name: continue val = arguments.get(arg_name) if val is None: continue if not isinstance(spec, Mapping): continue column = spec.get("column") or arg_name op = spec.get("op") or "eq" if op == "eq": params[str(column)] = f"eq.{val}" elif op == "ilike_contains": params[str(column)] = f"ilike.*{val}*" elif op == "raw": params[str(column)] = str(val) timeout_s = fields.get("timeout", 30) try: resp = request_with_retry( requests, "GET", url, params=params, timeout=timeout_s, ) if not (200 <= resp.status_code < 300): detail: Any try: detail = resp.json() except Exception: detail = resp.text[:2000] return { "status": "error", "url": resp.url, "status_code": resp.status_code, "error": "HTTP request failed", "detail": detail, } try: data: Any = resp.json() except Exception: data = resp.text out: Dict[str, Any] = { "status": "success", "url": resp.url, "data": data, } if isinstance(data, list): out["count"] = len(data) return out except Exception as e: return {"status": "error", "url": url, "error": str(e)}