File size: 4,642 Bytes
5f74407
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"""Research Agent - Simple version using langchain create_agent directly."""

from datetime import datetime

from dotenv import load_dotenv
load_dotenv(".env", override=True)

from langchain_ollama import ChatOllama
from langchain.agents import create_agent
from langchain_core.tools import tool

import httpx
from markdownify import markdownify
from tavily import TavilyClient

tavily_client = TavilyClient()

def fetch_webpage_content(url: str, timeout: float = 10.0) -> str:
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    }
    try:
        response = httpx.get(url, headers=headers, timeout=timeout, follow_redirects=True)
        response.raise_for_status()
        if response.headers.get('content-type', '').startswith('application/pdf'):
            return f"[PDF content not displayed - URL: {url}]"
        content = markdownify(response.text)
        if len(content) > 3000:
            content = content[:3000] + "\n\n[Content truncated]"
        return content
    except Exception as e:
        return f"Error fetching content from {url}: {str(e)}"

@tool
def tavily_search(query: str, max_results: int = 3) -> str:
    """Search the web for information on a given query.

    Args:
        query: Search query to execute
        max_results: Maximum number of results to return (default: 3)

    Returns:
        Formatted search results with webpage content
    """
    search_results = tavily_client.search(query, max_results=max_results)
    result_texts = []
    for result in search_results.get("results", []):
        url = result["url"]
        title = result["title"]
        content = fetch_webpage_content(url)
        result_text = f"""## {title}
**URL:** {url}

{content}

---
"""
        result_texts.append(result_text)
    response = f"🔍 Found {len(result_texts)} result(s) for '{query}':\n\n" + "\n".join(result_texts)
    return response

@tool
def think_tool(reflection: str) -> str:
    """Tool for strategic reflection on research progress."""
    return f"Reflection recorded: {reflection}"

@tool
def write_file(file_path: str, content: str) -> str:
    """Write content to a file."""
    with open(file_path, 'w', encoding='utf-8') as f:
        f.write(content)
    return f"File written: {file_path}"

current_date = datetime.now().strftime("%Y-%m-%d")

RESEARCHER_INSTRUCTIONS = f"""You are an expert research assistant with a strict workflow. Today's date is {current_date}.

**YOUR MISSION:** Design a comprehensive 50-gene panel for human prostate cancer research. YOU MUST COMPLETE ALL STEPS.

**TOOLS AVAILABLE:**
1. tavily_search(query, max_results): Search the web for academic papers and research
2. think_tool(reflection): Record analysis and plan next steps
3. write_file(file_path, content): Write final report when ALL research is done

**WORKFLOW - FOLLOW EXACTLY IN ORDER:**

STEP 1: Search for prostate cancer driver genes. Use tavily_search with query about oncogenes, tumor suppressors, and key mutations in prostate cancer.

STEP 2: Search for immune microenvironment markers. Use tavily_search with query about PD-1, PD-L1, CTLA-4, CD4, CD8, and tumor immune infiltration markers.

STEP 3: Search for tissue and stromal markers. Use tavily_search with query about angiogenesis (VEGF), extracellular matrix (collagen), and stromal fibroblasts in prostate cancer.

STEP 4: Search for commercial gene panels. Use tavily_search with query about FDA-approved or commercially available prostate cancer gene tests like Oncotype DX, Prolaris, Decipher.

STEP 5: Use think_tool to analyze all findings and create the 50-gene list.

STEP 6: Use write_file to save the complete report to 'final_report.md'.

**FINAL REPORT FORMAT:**
# Prostate Cancer 50-Gene Panel Design

## Executive Summary
Overview of the panel design and its clinical significance.

## Tumor Status Markers (20 genes)
- Gene: Description and relevance

## Immune Microenvironment Markers (15 genes)
- Gene: Description and relevance

## Tissue Context Markers (15 genes)
- Gene: Description and relevance

## References
List of sources with URLs.

**CRITICAL INSTRUCTION:** Do NOT summarize or ask questions. EXECUTE THE STEPS ONE BY ONE. After each tool call, immediately proceed to the next step. Continue until all 6 steps are complete. YOU MUST use write_file at the end to save the report."""

model = ChatOllama(model="qwen3.5:9b", temperature=0.0)

tools = [tavily_search, think_tool, write_file]

agent = create_agent(
    model=model,
    tools=tools,
    system_prompt=RESEARCHER_INSTRUCTIONS,
)