Files
hermes-agent/tests/skills/test_optional_skill_scripts.py

85 lines
3.8 KiB
Python

"""Execute optional research helpers offline; upstream/SDK doubles are boundary spies.
This covers importability and client routing, not the paid evolution loop or a
live vector service. Document policy belongs to test_skill_document_contracts.
"""
import pickle
from pathlib import Path
import runpy
import sys
from types import ModuleType, SimpleNamespace
from unittest.mock import Mock
import pytest
RESEARCH = Path(__file__).resolve().parents[2] / "optional-skills/research"
@pytest.mark.parametrize("script", ["rag_pipeline.py", "memory_manager.py"])
def test_pinecone_client_uses_key_and_rejects_missing_key(script, monkeypatch, capsys):
sdk = ModuleType("pinecone")
constructor = Mock()
monkeypatch.setattr(sdk, "Pinecone", constructor, raising=False)
monkeypatch.setitem(sys.modules, "pinecone", sdk)
get_client = runpy.run_path(str(RESEARCH / "pinecone-research/scripts" / script))["get_pinecone_client"]
monkeypatch.setenv("PINECONE_API_KEY", "test-only-key")
assert get_client() is constructor.return_value
constructor.assert_called_once_with(api_key="test-only-key")
monkeypatch.delenv("PINECONE_API_KEY")
with pytest.raises(SystemExit, match="1"):
get_client()
assert "PINECONE_API_KEY" in capsys.readouterr().err
assert constructor.call_count == 1
@pytest.mark.parametrize("relative", [
"scripts/parrot_openrouter.py", "templates/custom_problem_template.py",
])
def test_evolver_provider_routing(relative, monkeypatch):
# The upstream package is optional/AGPL; only its imported types are needed
# to load these scripts and exercise their own provider client functions.
class UpstreamType:
def __class_getitem__(cls, _):
return cls
for module, names in {
"cli_common": "build_hyperparameter_config_from_args register_hyperparameter_args parse_learning_log_view_type",
"evolve_problem_loop": "EvolveProblemLoop",
"learning_log": "LearningLogEntry",
"problem": "EvaluationFailureCase EvaluationResult Evaluator Mutator Organism Problem",
}.items():
stub = ModuleType(f"darwinian_evolver.{module}")
for name in names.split():
setattr(stub, name, UpstreamType)
monkeypatch.setitem(sys.modules, stub.__name__, stub)
import openai
constructor = Mock()
monkeypatch.setattr(openai, "OpenAI", constructor)
monkeypatch.setenv("OPENROUTER_API_KEY", "test-only-key")
monkeypatch.setenv("EVOLVER_MODEL", "test/provider-model")
script = runpy.run_path(str(RESEARCH / "darwinian-evolver" / relative))
create = constructor.return_value.chat.completions.create
create.return_value = SimpleNamespace(choices=[SimpleNamespace(message=SimpleNamespace(content="reply"))])
assert script["_prompt_llm"]("question") == "reply"
constructor.assert_called_once_with(api_key="test-only-key", base_url="https://openrouter.ai/api/v1")
assert create.call_args.kwargs["model"] == "test/provider-model"
assert create.call_args.kwargs["messages"] == [{"role": "user", "content": "question"}]
monkeypatch.delenv("OPENROUTER_API_KEY")
with pytest.raises(SystemExit, match="OPENROUTER_API_KEY"):
script["_client"]()
assert constructor.call_count == 1
def test_snapshot_requires_trust_before_unpickling(tmp_path, monkeypatch, capsys):
snapshot = tmp_path / "snapshot.pkl"
snapshot.write_bytes(pickle.dumps({"population_snapshot": pickle.dumps({"organisms": []})}))
script = RESEARCH / "darwinian-evolver/scripts/show_snapshot.py"
main = runpy.run_path(str(script))["main"]
monkeypatch.setattr(sys, "argv", [str(script), str(snapshot)])
with pytest.raises(SystemExit, match="refusing to unpickle"):
main()
monkeypatch.setattr(sys, "argv", [str(script), str(snapshot), "--i-trust-this-file"])
assert main() == 0
assert "# organisms: 0" in capsys.readouterr().out