mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-28 05:12:26 +00:00
439 lines
13 KiB
Python
439 lines
13 KiB
Python
"""Tests for the composition layer."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from openjarvis.core.config import JarvisConfig
|
|
from openjarvis.core.events import EventBus
|
|
from openjarvis.system import JarvisSystem, SystemBuilder
|
|
|
|
|
|
class TestJarvisSystem:
|
|
def test_ask_direct_mode(self):
|
|
engine = MagicMock()
|
|
engine.generate.return_value = {
|
|
"content": "Hello!",
|
|
"usage": {"prompt_tokens": 5, "completion_tokens": 3},
|
|
}
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test-model",
|
|
)
|
|
result = system.ask("Hi")
|
|
assert result["content"] == "Hello!"
|
|
assert result["model"] == "test-model"
|
|
assert result["engine"] == "mock"
|
|
|
|
def test_ask_returns_usage(self):
|
|
engine = MagicMock()
|
|
engine.generate.return_value = {
|
|
"content": "OK",
|
|
"usage": {"prompt_tokens": 10, "completion_tokens": 5},
|
|
}
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
)
|
|
result = system.ask("Hi")
|
|
assert result["usage"]["prompt_tokens"] == 10
|
|
|
|
def test_ask_no_agent_direct_mode(self):
|
|
"""When agent_name is empty and no agent param, use direct engine mode."""
|
|
engine = MagicMock()
|
|
engine.generate.return_value = {
|
|
"content": "Direct response",
|
|
"usage": {},
|
|
}
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
agent_name="",
|
|
)
|
|
result = system.ask("Hi")
|
|
assert result["content"] == "Direct response"
|
|
engine.generate.assert_called_once()
|
|
|
|
def test_ask_with_agent_none_uses_direct(self):
|
|
"""Passing agent_name='none' should use direct engine mode."""
|
|
engine = MagicMock()
|
|
engine.generate.return_value = {
|
|
"content": "Direct response",
|
|
"usage": {},
|
|
}
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
agent_name="none",
|
|
)
|
|
result = system.ask("Hi")
|
|
assert result["content"] == "Direct response"
|
|
|
|
def test_ask_with_agent_override(self):
|
|
"""Passing agent= param should use that agent even if system has a default."""
|
|
from openjarvis.agents._stubs import AgentResult
|
|
from openjarvis.core.registry import AgentRegistry
|
|
|
|
class TestAgent:
|
|
agent_id = "test-system-agent"
|
|
|
|
def __init__(self, eng, model, **kwargs):
|
|
pass
|
|
|
|
def run(self, input, context=None, **kwargs):
|
|
return AgentResult(content="From test agent", turns=1)
|
|
|
|
# Register (or re-register) the agent
|
|
if not AgentRegistry.contains("test-system-agent"):
|
|
AgentRegistry.register_value("test-system-agent", TestAgent)
|
|
|
|
engine = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
agent_name="",
|
|
)
|
|
result = system.ask("Hi", agent="test-system-agent")
|
|
assert result["content"] == "From test agent"
|
|
|
|
def test_ask_unknown_agent(self):
|
|
"""Unknown agent should return an error dict."""
|
|
engine = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
)
|
|
result = system.ask("Hi", agent="nonexistent-agent-xyz")
|
|
assert "Unknown agent" in result["content"]
|
|
assert result.get("error") is True
|
|
|
|
def test_ask_passes_temperature_and_max_tokens(self):
|
|
engine = MagicMock()
|
|
engine.generate.return_value = {"content": "OK", "usage": {}}
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
)
|
|
system.ask("Hi", temperature=0.3, max_tokens=512)
|
|
call_kwargs = engine.generate.call_args
|
|
assert call_kwargs[1]["temperature"] == 0.3
|
|
assert call_kwargs[1]["max_tokens"] == 512
|
|
|
|
def test_close(self):
|
|
engine = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
)
|
|
system.close() # Should not raise
|
|
|
|
def test_close_with_telemetry(self):
|
|
engine = MagicMock()
|
|
telem = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
telemetry_store=telem,
|
|
)
|
|
system.close()
|
|
telem.close.assert_called_once()
|
|
|
|
def test_close_with_trace_store(self):
|
|
engine = MagicMock()
|
|
trace = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
trace_store=trace,
|
|
)
|
|
system.close()
|
|
trace.close.assert_called_once()
|
|
|
|
def test_build_tools_empty(self):
|
|
engine = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
)
|
|
tools = system._build_tools([])
|
|
assert tools == []
|
|
|
|
def test_build_tools_unknown_tool(self):
|
|
engine = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
)
|
|
tools = system._build_tools(["nonexistent_tool_xyz"])
|
|
assert tools == []
|
|
|
|
|
|
class TestSystemBuilder:
|
|
def test_builder_fluent_api(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
result = builder.engine("ollama").model("test").agent("simple")
|
|
assert result is builder # fluent
|
|
|
|
def test_builder_stores_config(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
assert builder._config is config
|
|
|
|
def test_builder_engine_setter(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
builder.engine("vllm")
|
|
assert builder._engine_key == "vllm"
|
|
|
|
def test_builder_model_setter(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
builder.model("my-model")
|
|
assert builder._model == "my-model"
|
|
|
|
def test_builder_agent_setter(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
builder.agent("orchestrator")
|
|
assert builder._agent_name == "orchestrator"
|
|
|
|
def test_builder_tools_setter(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
builder.tools(["calculator", "think"])
|
|
assert builder._tool_names == ["calculator", "think"]
|
|
|
|
def test_builder_telemetry_setter(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
builder.telemetry(False)
|
|
assert builder._telemetry is False
|
|
|
|
def test_builder_traces_setter(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
builder.traces(True)
|
|
assert builder._traces is True
|
|
|
|
def test_builder_event_bus_setter(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
bus = EventBus()
|
|
builder.event_bus(bus)
|
|
assert builder._bus is bus
|
|
|
|
def test_builder_chaining(self):
|
|
config = JarvisConfig()
|
|
builder = (
|
|
SystemBuilder(config)
|
|
.engine("ollama")
|
|
.model("test-model")
|
|
.agent("simple")
|
|
.tools(["calculator"])
|
|
.telemetry(True)
|
|
.traces(False)
|
|
)
|
|
assert builder._engine_key == "ollama"
|
|
assert builder._model == "test-model"
|
|
assert builder._agent_name == "simple"
|
|
assert builder._tool_names == ["calculator"]
|
|
assert builder._telemetry is True
|
|
assert builder._traces is False
|
|
|
|
def test_import_works(self):
|
|
from openjarvis.system import JarvisSystem, SystemBuilder
|
|
|
|
assert JarvisSystem is not None
|
|
assert SystemBuilder is not None
|
|
|
|
def test_builder_default_config(self):
|
|
"""SystemBuilder with no config should load defaults."""
|
|
builder = SystemBuilder()
|
|
assert builder._config is not None
|
|
assert isinstance(builder._config, JarvisConfig)
|
|
|
|
def test_builder_build_raises_without_engine(self):
|
|
"""build() should raise RuntimeError when no engine is available."""
|
|
config = JarvisConfig()
|
|
# Use a nonsense engine key to ensure no engine is found
|
|
builder = SystemBuilder(config).engine("nonexistent_engine_xyz_123")
|
|
with pytest.raises(RuntimeError, match="No inference engine"):
|
|
builder.build()
|
|
|
|
def test_builder_sandbox_setter(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
result = builder.sandbox(True)
|
|
assert result is builder # fluent
|
|
assert builder._sandbox is True
|
|
|
|
def test_builder_scheduler_setter(self):
|
|
config = JarvisConfig()
|
|
builder = SystemBuilder(config)
|
|
result = builder.scheduler(True)
|
|
assert result is builder # fluent
|
|
assert builder._scheduler is True
|
|
|
|
def test_builder_sandbox_scheduler_chaining(self):
|
|
config = JarvisConfig()
|
|
builder = (
|
|
SystemBuilder(config)
|
|
.engine("ollama")
|
|
.model("test")
|
|
.sandbox(True)
|
|
.scheduler(True)
|
|
)
|
|
assert builder._sandbox is True
|
|
assert builder._scheduler is True
|
|
assert builder._engine_key == "ollama"
|
|
|
|
|
|
class TestJarvisSystemClose:
|
|
def test_close_with_scheduler_store(self):
|
|
engine = MagicMock()
|
|
sched_store = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
scheduler_store=sched_store,
|
|
)
|
|
system.close()
|
|
sched_store.close.assert_called_once()
|
|
|
|
def test_close_with_scheduler(self):
|
|
engine = MagicMock()
|
|
scheduler = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
scheduler=scheduler,
|
|
)
|
|
system.close()
|
|
scheduler.stop.assert_called_once()
|
|
|
|
def test_close_with_memory_backend(self):
|
|
engine = MagicMock()
|
|
mem = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
memory_backend=mem,
|
|
)
|
|
system.close()
|
|
mem.close.assert_called_once()
|
|
|
|
def test_close_with_session_store(self):
|
|
engine = MagicMock()
|
|
sess = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
session_store=sess,
|
|
)
|
|
system.close()
|
|
sess.close.assert_called_once()
|
|
|
|
def test_close_with_workflow_engine(self):
|
|
engine = MagicMock()
|
|
wf = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
workflow_engine=wf,
|
|
)
|
|
system.close()
|
|
wf.close.assert_called_once()
|
|
|
|
def test_system_fields_default_none(self):
|
|
engine = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
)
|
|
assert system.scheduler_store is None
|
|
assert system.scheduler is None
|
|
assert system.container_runner is None
|
|
|
|
def test_close_with_agent_scheduler(self):
|
|
engine = MagicMock()
|
|
agent_scheduler = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
agent_scheduler=agent_scheduler,
|
|
)
|
|
system.close()
|
|
agent_scheduler.stop.assert_called_once()
|
|
|
|
def test_system_agent_fields_default_none(self):
|
|
engine = MagicMock()
|
|
system = JarvisSystem(
|
|
config=JarvisConfig(),
|
|
bus=EventBus(),
|
|
engine=engine,
|
|
engine_key="mock",
|
|
model="test",
|
|
)
|
|
assert system.agent_scheduler is None
|
|
assert system.agent_executor is None
|