| """Tool functions for Magentic agents. |
| |
| These functions are decorated with @ai_function to be callable by the ChatAgent's internal LLM. |
| They also interact with the thread-safe MagenticState to persist evidence. |
| """ |
|
|
| from agent_framework import ai_function |
|
|
| from src.agents.state import get_magentic_state |
| from src.tools.clinicaltrials import ClinicalTrialsTool |
| from src.tools.europepmc import EuropePMCTool |
| from src.tools.pubmed import PubMedTool |
|
|
| |
| _pubmed = PubMedTool() |
| _clinicaltrials = ClinicalTrialsTool() |
| _europepmc = EuropePMCTool() |
|
|
|
|
| @ai_function |
| async def search_pubmed(query: str, max_results: int = 10) -> str: |
| """Search PubMed for biomedical research papers. |
| |
| Use this tool to find peer-reviewed scientific literature about |
| drugs, diseases, mechanisms of action, and clinical studies. |
| |
| Args: |
| query: Search keywords (e.g., "metformin alzheimer mechanism") |
| max_results: Maximum results to return (default 10) |
| |
| Returns: |
| Formatted list of papers with titles, abstracts, and citations |
| """ |
| state = get_magentic_state() |
|
|
| |
| results = await _pubmed.search(query, max_results) |
| if not results: |
| return f"No PubMed results found for: {query}" |
|
|
| |
| display_results = results |
| if state.embedding_service: |
| |
| unique_results = await state.embedding_service.deduplicate(results) |
|
|
| |
| related = await state.search_related(query, n_results=3) |
|
|
| |
| display_results = unique_results + related |
|
|
| |
| |
| new_count = state.add_evidence(results) |
|
|
| |
| output = [f"Found {len(results)} results ({new_count} new stored):\n"] |
|
|
| |
| limit = min(len(display_results), max_results) |
|
|
| for i, r in enumerate(display_results[:limit], 1): |
| title = r.citation.title |
| date = r.citation.date |
| source = r.citation.source |
| content_clean = r.content[:300].replace("\n", " ") |
| url = r.citation.url |
|
|
| output.append(f"{i}. **{title}** ({date})") |
| output.append(f" Source: {source} | {url}") |
| output.append(f" {content_clean}...") |
| output.append("") |
|
|
| return "\n".join(output) |
|
|
|
|
| @ai_function |
| async def search_clinical_trials(query: str, max_results: int = 10) -> str: |
| """Search ClinicalTrials.gov for clinical studies. |
| |
| Use this tool to find ongoing and completed clinical trials |
| for drug repurposing candidates. |
| |
| Args: |
| query: Search terms (e.g., "metformin cancer phase 3") |
| max_results: Maximum results to return (default 10) |
| |
| Returns: |
| Formatted list of clinical trials with status and details |
| """ |
| state = get_magentic_state() |
|
|
| results = await _clinicaltrials.search(query, max_results) |
| if not results: |
| return f"No clinical trials found for: {query}" |
|
|
| |
| new_count = state.add_evidence(results) |
|
|
| output = [f"Found {len(results)} clinical trials ({new_count} new stored):\n"] |
| for i, r in enumerate(results[:max_results], 1): |
| title = r.citation.title |
| date = r.citation.date |
| source = r.citation.source |
| content_clean = r.content[:300].replace("\n", " ") |
| url = r.citation.url |
|
|
| output.append(f"{i}. **{title}**") |
| output.append(f" Status: {source} | Date: {date}") |
| output.append(f" {content_clean}...") |
| output.append(f" URL: {url}\n") |
|
|
| return "\n".join(output) |
|
|
|
|
| @ai_function |
| async def search_preprints(query: str, max_results: int = 10) -> str: |
| """Search Europe PMC for preprints and papers. |
| |
| Use this tool to find the latest research including preprints |
| from bioRxiv, medRxiv, and peer-reviewed papers. |
| |
| Args: |
| query: Search terms (e.g., "long covid treatment") |
| max_results: Maximum results to return (default 10) |
| |
| Returns: |
| Formatted list of papers with abstracts and links |
| """ |
| state = get_magentic_state() |
|
|
| results = await _europepmc.search(query, max_results) |
| if not results: |
| return f"No papers found for: {query}" |
|
|
| |
| new_count = state.add_evidence(results) |
|
|
| output = [f"Found {len(results)} papers ({new_count} new stored):\n"] |
| for i, r in enumerate(results[:max_results], 1): |
| title = r.citation.title |
| date = r.citation.date |
| source = r.citation.source |
| content_clean = r.content[:300].replace("\n", " ") |
| url = r.citation.url |
|
|
| output.append(f"{i}. **{title}**") |
| output.append(f" Source: {source} | Date: {date}") |
| output.append(f" {content_clean}...") |
| output.append(f" URL: {url}\n") |
|
|
| return "\n".join(output) |
|
|
|
|
| @ai_function |
| async def get_bibliography() -> str: |
| """Get the full list of collected evidence for the bibliography. |
| |
| Use this tool when generating the final report to get the complete |
| list of references. |
| |
| Returns: |
| Formatted bibliography string. |
| """ |
| state = get_magentic_state() |
| if not state.evidence: |
| return "No evidence collected." |
|
|
| output = ["## References"] |
| for i, ev in enumerate(state.evidence, 1): |
| output.append(f"{i}. {ev.citation.formatted}") |
| output.append(f" URL: {ev.citation.url}") |
|
|
| return "\n".join(output) |
|
|