czty's picture
Add files using upload-large-folder tool
b2c86fd verified
Raw
History Blame Contribute Delete
5.29 kB
import os
import uuid
from dataclasses import dataclass, field
from threading import Lock
from dotenv import load_dotenv
load_dotenv()
from biomni_agent import BiomniWebAgent
DEFAULT_LLM_PROVIDER = os.getenv("BIOMNI_LLM_PROVIDER", "deepseek").strip().lower()
@dataclass
class SessionState:
agent: BiomniWebAgent | None = None
uploaded_files: list[str] = field(default_factory=list)
metabolomics_enabled: bool = False
metabolomics_tools: list[str] = field(default_factory=list)
paper_repro_enabled: bool = False
paper_profile: str = "foxj1"
stop_requested: bool = False
llm_provider: str = field(default_factory=lambda: DEFAULT_LLM_PROVIDER)
def _create_agent(
session_id: str,
expected_files: list[str] | None = None,
llm_provider: str = DEFAULT_LLM_PROVIDER,
) -> BiomniWebAgent:
return BiomniWebAgent(
session_id=session_id,
expected_data_lake_files=expected_files or [],
llm_provider=llm_provider,
)
class SessionManager:
def __init__(self):
self._sessions: dict[str, SessionState] = {}
self._lock = Lock()
def create_session(self, llm_provider: str = DEFAULT_LLM_PROVIDER) -> str:
sid = str(uuid.uuid4())
with self._lock:
# Lazy init agent to avoid blocking /session/new.
self._sessions[sid] = SessionState(
llm_provider=(llm_provider or DEFAULT_LLM_PROVIDER).strip().lower()
)
return sid
def has_session(self, sid: str) -> bool:
return sid in self._sessions
def get_agent(self, sid: str) -> BiomniWebAgent:
# Fast path: already initialized
with self._lock:
state = self._sessions[sid]
if state.agent is not None:
return state.agent
expected_files = list(state.uploaded_files)
llm_provider = state.llm_provider
# Slow path: initialize outside lock
new_agent = _create_agent(sid, expected_files=expected_files, llm_provider=llm_provider)
if expected_files:
new_agent.set_uploaded_files(expected_files)
new_agent.set_metabolomics_settings(state.metabolomics_enabled, state.metabolomics_tools)
new_agent.set_paper_reproduction_settings(state.paper_repro_enabled, state.paper_profile)
# Publish initialized agent
with self._lock:
state = self._sessions.get(sid)
if state is None:
raise KeyError(f"Session not found: {sid}")
if state.agent is None:
state.agent = new_agent
return state.agent
def add_uploaded_file(self, sid: str, relative_path: str):
with self._lock:
state = self._sessions[sid]
if relative_path not in state.uploaded_files:
state.uploaded_files.append(relative_path)
if state.agent is not None:
state.agent.set_uploaded_files(state.uploaded_files)
def set_metabolomics_settings(self, sid: str, enabled: bool, tools: list[str]):
with self._lock:
state = self._sessions[sid]
state.metabolomics_enabled = bool(enabled)
state.metabolomics_tools = sorted(set(tools))
if state.agent is not None:
state.agent.set_metabolomics_settings(state.metabolomics_enabled, state.metabolomics_tools)
def set_llm_provider(self, sid: str, llm_provider: str):
normalized = (llm_provider or DEFAULT_LLM_PROVIDER).strip().lower()
with self._lock:
state = self._sessions[sid]
if state.llm_provider == normalized:
return
state.llm_provider = normalized
# Recreate the agent on next access so the new backend takes effect.
state.agent = None
def request_stop(self, sid: str) -> None:
with self._lock:
state = self._sessions[sid]
state.stop_requested = True
if state.agent is not None:
state.agent.request_cancel()
def clear_stop(self, sid: str) -> None:
with self._lock:
state = self._sessions[sid]
state.stop_requested = False
if state.agent is not None:
state.agent.clear_cancel_request()
def is_stop_requested(self, sid: str) -> bool:
with self._lock:
state = self._sessions[sid]
return bool(state.stop_requested)
def set_paper_reproduction_settings(self, sid: str, enabled: bool, profile: str = "foxj1"):
normalized_profile = (profile or "foxj1").strip().lower()
with self._lock:
state = self._sessions[sid]
state.paper_repro_enabled = bool(enabled)
state.paper_profile = normalized_profile
if state.agent is not None:
state.agent.set_paper_reproduction_settings(state.paper_repro_enabled, state.paper_profile)
def get_uploaded_files(self, sid: str) -> list[str]:
with self._lock:
return list(self._sessions[sid].uploaded_files)
def delete_session(self, sid: str):
with self._lock:
self._sessions.pop(sid, None)
def cleanup_all(self):
with self._lock:
self._sessions.clear()