Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
# Required: Anthropic API Key for Claude models
ANTHROPIC_API_KEY=your_anthropic_api_key_here

# Required if DISGENET API use:
DISGENET_API_KEY=
DISGENET_API_SERVER_HOST=https://api.disgenet.com

# Optional: OpenAI API Key (if using OpenAI models)
OPENAI_API_KEY=your_openai_api_key_here

Expand Down
27 changes: 0 additions & 27 deletions MANIFEST.in

This file was deleted.

55 changes: 51 additions & 4 deletions biomni/agent/a1.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
import inspect
import os
import re
import sys
from collections.abc import Generator
from datetime import datetime
from pathlib import Path
from typing import Any, Literal, TypedDict

import pandas as pd
from dotenv import load_dotenv

if os.path.exists(".env"):
load_dotenv(".env", override=False)
print("Loaded environment variables from .env")

from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage
from langchain_core.prompts import ChatPromptTemplate
from langgraph.checkpoint.memory import MemorySaver
Expand Down Expand Up @@ -43,10 +49,6 @@
textify_api_dict,
)

if os.path.exists(".env"):
load_dotenv(".env", override=False)
print("Loaded environment variables from .env")


class AgentState(TypedDict):
messages: list[BaseMessage]
Expand Down Expand Up @@ -79,6 +81,10 @@ def __init__(
commercial_mode: If True, excludes datasets that require commercial licenses or are non-commercial only

"""
# --- DISGENET API key preflight (warn early, before the agent tries to select DISGENET tools) ---
# Note: We never prompt in non-interactive contexts (e.g., Flask/gunicorn); we only warn.
self.disgenet_api_available = self._disgenet_api_key_check()

# Use default_config values for unspecified parameters
if path is None:
path = default_config.path
Expand Down Expand Up @@ -222,6 +228,47 @@ def __init__(
self.timeout_seconds = timeout_seconds # 10 minutes default timeout
self.configure()

_DISGENET_KEY_WARNED: bool = False
_DISGENET_KEY_PROMPTED: bool = False

def _disgenet_api_key_check(self) -> bool:
"""One-time DISGENET_API_KEY check.

- If missing, prints a warning early during agent init.
- If stdin is a TTY, prompts once per process for a key (press Enter to skip).
"""
existing = os.getenv("DISGENET_API_KEY")
if existing:
return True

if not A1._DISGENET_KEY_WARNED:
print(
"⚠️ DISGENET_API_KEY is not set. Please provide the DISGENET API KEY in the environment in order to get full access to DISGENET tools."
)
A1._DISGENET_KEY_WARNED = True

# Never block in non-interactive contexts (e.g., Flask/gunicorn, CI).
if not sys.stdin.isatty():
return False

# Avoid repeatedly prompting if the agent is re-initialized in a loop.
if A1._DISGENET_KEY_PROMPTED:
return False
A1._DISGENET_KEY_PROMPTED = True

try:
from getpass import getpass

entered = getpass("Enter DISGENET_API_KEY (leave blank to skip): ").strip()
if not entered:
return False
os.environ["DISGENET_API_KEY"] = entered
print("✅ DISGENET_API_KEY set for this process.")
return True
except Exception:
# If prompting fails for any reason, just keep going with the warning-only behavior.
return False

def add_tool(self, api):
"""Add a new tool to the agent's tool registry and make it available for retrieval.

Expand Down
10 changes: 5 additions & 5 deletions biomni/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ class BiomniConfig:
"""

# Data and execution settings
path: str = "./data"
timeout_seconds: int = 600
path: str = os.getenv("BIOMNI_PATH", "./data")

# LLM settings (API keys still from environment)
llm: str = "claude-sonnet-4-5"
temperature: float = 0.7
# LLM settings (API keys still from environment): claude-3-5-sonnet-20241022 || gpt-4o-mini-2024-07-18
llm: str = os.getenv("BIOMNI_LLM", "gpt-5-mini-2025-08-07")
temperature: float = float(os.getenv("BIOMNI_TEMPERATURE", "1")) # 0.7

timeout_seconds: int = 600
# Tool settings
use_tool_retriever: bool = True

Expand Down
1 change: 0 additions & 1 deletion biomni/env_desc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"ddinter_hormonal.csv": "Drug-drug interactions for systemic hormonal preparations from DDInter 2.0 database.",
"ddinter_respiratory.csv": "Drug-drug interactions for respiratory system drugs from DDInter 2.0 database.",
"ddinter_various.csv": "Drug-drug interactions for various drugs from DDInter 2.0 database.",
"DisGeNET.parquet": "Gene-disease associations from multiple sources.",
"dosage_growth_defect.parquet": "Gene dosage changes affecting growth.",
"enamine_cloud_library_smiles.pkl": "Compounds from Enamine REAL library with SMILES annotations.",
"evebio_assay_table.csv": "Assay metadata with one row per assay from EveBio pharmome mapping.",
Expand Down
1 change: 0 additions & 1 deletion biomni/env_desc_cm.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
# "ddinter_hormonal.csv": "Drug-drug interactions for systemic hormonal preparations from DDInter 2.0 database.", # CC BY-NC-SA 4.0 - Non-commercial only
# "ddinter_respiratory.csv": "Drug-drug interactions for respiratory system drugs from DDInter 2.0 database.", # CC BY-NC-SA 4.0 - Non-commercial only
# "ddinter_various.csv": "Drug-drug interactions for various drugs from DDInter 2.0 database.", # CC BY-NC-SA 4.0 - Non-commercial only
# "DisGeNET.parquet": "Gene-disease associations from multiple sources.", # CC BY-NC-SA 4.0 - Non-commercial only
"dosage_growth_defect.parquet": "Gene dosage changes affecting growth.",
# "enamine_cloud_library_smiles.pkl": "Compounds from Enamine REAL library with SMILES annotations.", # Proprietary - Requires license
# "evebio_assay_table.csv": "Assay metadata with one row per assay from EveBio pharmome mapping.", # Proprietary - Requires permission
Expand Down
2 changes: 1 addition & 1 deletion biomni/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def get_llm(
# Use config values for any unspecified parameters
if config is not None:
if model is None:
model = config.llm_model
model = config.llm
if temperature is None:
temperature = config.temperature
if source is None:
Expand Down
Loading