molecule-core/workspace-template/tests/test_agent.py
Hongming Wang 24fec62d7f initial commit — Molecule AI platform
Forked clean from public hackathon repo (Starfire-AgentTeam, BSL 1.1)
with full rebrand to Molecule AI under github.com/Molecule-AI/molecule-monorepo.

Brand: Starfire → Molecule AI.
Slug: starfire / agent-molecule → molecule.
Env vars: STARFIRE_* → MOLECULE_*.
Go module: github.com/agent-molecule/platform → github.com/Molecule-AI/molecule-monorepo/platform.
Python packages: starfire_plugin → molecule_plugin, starfire_agent → molecule_agent.
DB: agentmolecule → molecule.

History truncated; see public repo for prior commits and contributor
attribution. Verified green: go test -race ./... (platform), pytest
(workspace-template 1129 + sdk 132), vitest (canvas 352), build (mcp).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 11:55:37 -07:00

374 lines
16 KiB
Python

"""Tests for agent.py — LangGraph agent factory.
Uses importlib.util.spec_from_file_location to load the real module, bypassing
any conftest mocks that might interfere.
"""
import importlib.util
import sys
from pathlib import Path
from types import ModuleType
from unittest.mock import MagicMock, patch
import pytest
ROOT = Path(__file__).resolve().parents[1]
def _load_agent(monkeypatch, extra_sys_modules=None):
"""Load the real agent.py in isolation."""
spec = importlib.util.spec_from_file_location(
"_test_agent",
ROOT / "agent.py",
)
mod = importlib.util.module_from_spec(spec)
# Patch langgraph before exec
fake_langgraph = ModuleType("langgraph")
fake_prebuilt = ModuleType("langgraph.prebuilt")
fake_create = MagicMock(return_value=MagicMock(name="agent_instance"))
fake_prebuilt.create_react_agent = fake_create
fake_langgraph.prebuilt = fake_prebuilt
monkeypatch.setitem(sys.modules, "langgraph", fake_langgraph)
monkeypatch.setitem(sys.modules, "langgraph.prebuilt", fake_prebuilt)
if extra_sys_modules:
for k, v in extra_sys_modules.items():
monkeypatch.setitem(sys.modules, k, v)
spec.loader.exec_module(mod)
# Attach the create_react_agent mock to module for inspection
mod._fake_create_react_agent = fake_create
return mod
# ---------------------------------------------------------------------------
# create_agent — provider tests
# ---------------------------------------------------------------------------
class TestCreateAgent:
def test_anthropic_provider(self, monkeypatch):
"""anthropic: prefix uses ChatAnthropic."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_anthropic = ModuleType("langchain_anthropic")
fake_lc_anthropic.ChatAnthropic = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_anthropic": fake_lc_anthropic})
monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
agent = mod.create_agent("anthropic:claude-test", [], "sys prompt")
fake_llm_cls.assert_called_once_with(model="claude-test")
mod._fake_create_react_agent.assert_called_once()
assert agent is not None
def test_anthropic_with_base_url(self, monkeypatch):
"""anthropic: with ANTHROPIC_BASE_URL passes anthropic_api_url."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_anthropic = ModuleType("langchain_anthropic")
fake_lc_anthropic.ChatAnthropic = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_anthropic": fake_lc_anthropic})
monkeypatch.setenv("ANTHROPIC_BASE_URL", "http://proxy.test")
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
mod.create_agent("anthropic:claude-test", [], "sys prompt")
fake_llm_cls.assert_called_once_with(model="claude-test", anthropic_api_url="http://proxy.test")
def test_openai_provider(self, monkeypatch):
"""openai: prefix uses ChatOpenAI."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_openai = ModuleType("langchain_openai")
fake_lc_openai.ChatOpenAI = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_openai": fake_lc_openai})
monkeypatch.delenv("OPENAI_BASE_URL", raising=False)
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
mod.create_agent("openai:gpt-4o", [], "sys prompt")
fake_llm_cls.assert_called_once_with(model="gpt-4o")
def test_openai_with_base_url(self, monkeypatch):
"""openai: with OPENAI_BASE_URL passes openai_api_base."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_openai = ModuleType("langchain_openai")
fake_lc_openai.ChatOpenAI = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_openai": fake_lc_openai})
monkeypatch.setenv("OPENAI_BASE_URL", "http://openai-proxy.test")
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
mod.create_agent("openai:gpt-4o", [], "sys")
fake_llm_cls.assert_called_once_with(model="gpt-4o", openai_api_base="http://openai-proxy.test")
def test_openrouter_provider(self, monkeypatch):
"""openrouter: prefix uses ChatOpenAI with openrouter base URL."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_openai = ModuleType("langchain_openai")
fake_lc_openai.ChatOpenAI = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_openai": fake_lc_openai})
monkeypatch.setenv("OPENROUTER_API_KEY", "sk-router-test")
monkeypatch.setenv("MAX_TOKENS", "1024")
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
mod.create_agent("openrouter:mistral-7b", [], "sys")
fake_llm_cls.assert_called_once_with(
model="mistral-7b",
openai_api_key="sk-router-test",
openai_api_base="https://openrouter.ai/api/v1",
max_tokens=1024,
)
def test_openrouter_fallback_api_key(self, monkeypatch):
"""openrouter falls back to OPENAI_API_KEY when OPENROUTER_API_KEY absent."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_openai = ModuleType("langchain_openai")
fake_lc_openai.ChatOpenAI = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_openai": fake_lc_openai})
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
monkeypatch.setenv("OPENAI_API_KEY", "sk-openai-fallback")
monkeypatch.delenv("MAX_TOKENS", raising=False)
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
mod.create_agent("openrouter:mistral-7b", [], "sys")
call_kwargs = fake_llm_cls.call_args
assert call_kwargs.kwargs["openai_api_key"] == "sk-openai-fallback"
def test_groq_provider(self, monkeypatch):
"""groq: prefix uses ChatOpenAI with groq base URL."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_openai = ModuleType("langchain_openai")
fake_lc_openai.ChatOpenAI = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_openai": fake_lc_openai})
monkeypatch.setenv("GROQ_API_KEY", "gsk-test")
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
mod.create_agent("groq:llama3-70b", [], "sys")
fake_llm_cls.assert_called_once_with(
model="llama3-70b",
openai_api_key="gsk-test",
openai_api_base="https://api.groq.com/openai/v1",
)
def test_no_provider_prefix_defaults_to_anthropic(self, monkeypatch):
"""model string without colon defaults to anthropic provider."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_anthropic = ModuleType("langchain_anthropic")
fake_lc_anthropic.ChatAnthropic = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_anthropic": fake_lc_anthropic})
monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
mod.create_agent("claude-3-opus", [], "sys")
fake_llm_cls.assert_called_once_with(model="claude-3-opus")
def test_unsupported_provider_raises_value_error(self, monkeypatch):
"""Unknown provider raises ValueError."""
mod = _load_agent(monkeypatch)
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
with pytest.raises(ValueError, match="Unsupported model provider"):
mod.create_agent("bogus:some-model", [], "sys")
def test_google_genai_provider(self, monkeypatch):
"""google_genai: prefix uses ChatGoogleGenerativeAI."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_google = ModuleType("langchain_google_genai")
fake_lc_google.ChatGoogleGenerativeAI = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_google_genai": fake_lc_google})
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
mod.create_agent("google_genai:gemini-pro", [], "sys")
# google_genai falls into the else: llm = LLMClass(model=model_name) branch
fake_llm_cls.assert_called_once_with(model="gemini-pro")
def test_ollama_provider(self, monkeypatch):
"""ollama: prefix uses ChatOllama."""
fake_llm_cls = MagicMock(return_value=MagicMock(name="llm"))
fake_lc_ollama = ModuleType("langchain_ollama")
fake_lc_ollama.ChatOllama = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_ollama": fake_lc_ollama})
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
mod.create_agent("ollama:llama3", [], "sys")
fake_llm_cls.assert_called_once_with(model="llama3")
def test_import_error_raises_import_error(self, monkeypatch):
"""ImportError from provider package is re-raised as ImportError."""
# Remove langchain_anthropic from sys.modules so the import fails
monkeypatch.delitem(sys.modules, "langchain_anthropic", raising=False)
mod = _load_agent(monkeypatch)
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
# Patch builtins.__import__ to raise for langchain_anthropic
original_import = __builtins__.__import__ if hasattr(__builtins__, "__import__") else __import__
def fake_import(name, *args, **kwargs):
if name == "langchain_anthropic":
raise ImportError("no module named langchain_anthropic")
return original_import(name, *args, **kwargs)
import builtins
monkeypatch.setattr(builtins, "__import__", fake_import)
with pytest.raises(ImportError, match="langchain-anthropic"):
mod.create_agent("anthropic:claude-test", [], "sys")
# ---------------------------------------------------------------------------
# _setup_langfuse
# ---------------------------------------------------------------------------
class TestSetupLangfuse:
def test_no_env_vars_returns_empty_list(self, monkeypatch):
mod = _load_agent(monkeypatch)
monkeypatch.delenv("LANGFUSE_HOST", raising=False)
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
result = mod._setup_langfuse()
assert result == []
def test_partial_env_vars_returns_empty_list(self, monkeypatch):
"""Only some langfuse vars set — should return []."""
mod = _load_agent(monkeypatch)
monkeypatch.setenv("LANGFUSE_HOST", "http://langfuse.test")
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
result = mod._setup_langfuse()
assert result == []
def test_all_vars_langfuse_installed(self, monkeypatch):
"""All langfuse vars present and package available returns [handler]."""
mod = _load_agent(monkeypatch)
monkeypatch.setenv("LANGFUSE_HOST", "http://langfuse.test")
monkeypatch.setenv("LANGFUSE_PUBLIC_KEY", "pk-test")
monkeypatch.setenv("LANGFUSE_SECRET_KEY", "sk-test")
fake_handler = MagicMock(name="langfuse_handler")
fake_callback_mod = ModuleType("langfuse.callback")
fake_callback_mod.CallbackHandler = MagicMock(return_value=fake_handler)
fake_langfuse = ModuleType("langfuse")
fake_langfuse.callback = fake_callback_mod
monkeypatch.setitem(sys.modules, "langfuse", fake_langfuse)
monkeypatch.setitem(sys.modules, "langfuse.callback", fake_callback_mod)
result = mod._setup_langfuse()
assert len(result) == 1
assert result[0] is fake_handler
def test_langfuse_import_error_returns_empty_list(self, monkeypatch):
"""ImportError from langfuse package returns []."""
mod = _load_agent(monkeypatch)
monkeypatch.setenv("LANGFUSE_HOST", "http://langfuse.test")
monkeypatch.setenv("LANGFUSE_PUBLIC_KEY", "pk-test")
monkeypatch.setenv("LANGFUSE_SECRET_KEY", "sk-test")
# Make sure langfuse is NOT in sys.modules
monkeypatch.delitem(sys.modules, "langfuse", raising=False)
monkeypatch.delitem(sys.modules, "langfuse.callback", raising=False)
import builtins
original_import = builtins.__import__
def fake_import(name, *args, **kwargs):
if name == "langfuse.callback":
raise ImportError("no module named langfuse")
return original_import(name, *args, **kwargs)
monkeypatch.setattr(builtins, "__import__", fake_import)
result = mod._setup_langfuse()
assert result == []
def test_langfuse_exception_returns_empty_list(self, monkeypatch):
"""Exception during CallbackHandler construction returns []."""
mod = _load_agent(monkeypatch)
monkeypatch.setenv("LANGFUSE_HOST", "http://langfuse.test")
monkeypatch.setenv("LANGFUSE_PUBLIC_KEY", "pk-test")
monkeypatch.setenv("LANGFUSE_SECRET_KEY", "sk-test")
fake_callback_mod = ModuleType("langfuse.callback")
fake_callback_mod.CallbackHandler = MagicMock(side_effect=RuntimeError("connect failed"))
fake_langfuse = ModuleType("langfuse")
fake_langfuse.callback = fake_callback_mod
monkeypatch.setitem(sys.modules, "langfuse", fake_langfuse)
monkeypatch.setitem(sys.modules, "langfuse.callback", fake_callback_mod)
result = mod._setup_langfuse()
assert result == []
def test_langfuse_callbacks_attached_to_llm(self, monkeypatch):
"""When langfuse is configured, callbacks are attached to the LLM."""
fake_llm = MagicMock(name="llm")
fake_llm_cls = MagicMock(return_value=fake_llm)
fake_lc_anthropic = ModuleType("langchain_anthropic")
fake_lc_anthropic.ChatAnthropic = fake_llm_cls
mod = _load_agent(monkeypatch, {"langchain_anthropic": fake_lc_anthropic})
monkeypatch.setenv("LANGFUSE_HOST", "http://langfuse.test")
monkeypatch.setenv("LANGFUSE_PUBLIC_KEY", "pk-test")
monkeypatch.setenv("LANGFUSE_SECRET_KEY", "sk-test")
monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
fake_handler = MagicMock(name="handler")
fake_callback_mod = ModuleType("langfuse.callback")
fake_callback_mod.CallbackHandler = MagicMock(return_value=fake_handler)
fake_langfuse = ModuleType("langfuse")
fake_langfuse.callback = fake_callback_mod
monkeypatch.setitem(sys.modules, "langfuse", fake_langfuse)
monkeypatch.setitem(sys.modules, "langfuse.callback", fake_callback_mod)
mod.create_agent("anthropic:claude-test", [], "sys")
assert fake_llm.callbacks == [fake_handler]