frox-nano-v2 / src /tests /test_conductor.py
Hritik045678's picture
Upload folder using huggingface_hub
296a506 verified
Raw
History Blame Contribute Delete
6 kB
"""
Frox AI — Conductor Tests
Run with: pytest tests/test_conductor.py -v
Covers the pure-logic pieces (plan parsing, worker validation) that
don't need torch or a loaded model — the orchestrator/engine-calling
parts are integration-level and better tested against a real server.
"""
from __future__ import annotations
import sys
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from orchestration.conductor import MorphConductor, WorkerSpec, WorkflowStep
class FakeOrchestrator:
"""Stands in for MorphInferenceEngine — returns a canned response per call."""
def __init__(self, responses):
self.responses = list(responses)
self.calls = []
def generate(self, messages, **kwargs):
self.calls.append((messages, kwargs))
return self.responses.pop(0) if self.responses else ""
@pytest.fixture
def conductor_with_workers():
orch = FakeOrchestrator([])
workers = [
WorkerSpec("code", "Coding specialist"),
WorkerSpec("pro", "Hard reasoning specialist"),
]
return MorphConductor(orchestrator=orch, workers=workers), orch
class TestPlanParsing:
def test_valid_plan_parses(self, conductor_with_workers):
conductor, _ = conductor_with_workers
raw = '{"steps": [{"subtask": "write code", "worker": "code", "access": []}]}'
plan = conductor._parse_plan(raw)
assert plan.valid
assert len(plan.steps) == 1
assert plan.steps[0].worker == "code"
def test_plan_wrapped_in_prose_still_parses(self, conductor_with_workers):
"""Models often add commentary around the JSON despite instructions — must still extract it."""
conductor, _ = conductor_with_workers
raw = 'Here is my plan:\n{"steps": [{"subtask": "x", "worker": "pro", "access": []}]}\nHope that helps!'
plan = conductor._parse_plan(raw)
assert plan.valid
assert plan.steps[0].worker == "pro"
def test_multi_step_plan_with_access_list(self, conductor_with_workers):
conductor, _ = conductor_with_workers
raw = ('{"steps": ['
'{"subtask": "draft code", "worker": "code", "access": []},'
'{"subtask": "verify correctness", "worker": "pro", "access": [0]}'
']}')
plan = conductor._parse_plan(raw)
assert plan.valid
assert len(plan.steps) == 2
assert plan.steps[1].access == [0]
def test_unparseable_json_is_invalid(self, conductor_with_workers):
conductor, _ = conductor_with_workers
plan = conductor._parse_plan("I don't want to make a plan.")
assert not plan.valid
assert plan.error is not None
def test_empty_steps_is_invalid(self, conductor_with_workers):
conductor, _ = conductor_with_workers
plan = conductor._parse_plan('{"steps": []}')
assert not plan.valid
def test_unknown_worker_is_invalid(self, conductor_with_workers):
conductor, _ = conductor_with_workers
raw = '{"steps": [{"subtask": "x", "worker": "nonexistent_worker", "access": []}]}'
plan = conductor._parse_plan(raw)
assert not plan.valid
assert "nonexistent_worker" in plan.error
def test_self_worker_is_valid(self, conductor_with_workers):
"""'self' (the orchestrator reviewing/refining its own work) is always a valid worker name."""
conductor, _ = conductor_with_workers
raw = '{"steps": [{"subtask": "x", "worker": "self", "access": []}]}'
plan = conductor._parse_plan(raw)
assert plan.valid
def test_max_steps_truncates(self, conductor_with_workers):
conductor, _ = conductor_with_workers
conductor.max_steps = 2
raw = json_steps = (
'{"steps": ['
'{"subtask": "a", "worker": "code", "access": []},'
'{"subtask": "b", "worker": "pro", "access": []},'
'{"subtask": "c", "worker": "code", "access": []}'
']}'
)
plan = conductor._parse_plan(raw)
assert plan.valid
assert len(plan.steps) == 2
class TestFastModeFallback:
def test_fast_mode_picks_a_configured_worker(self, conductor_with_workers):
conductor, orch = conductor_with_workers
orch.responses = ["code"] # orchestrator's routing decision
# Patch the worker to avoid actually invoking a model
conductor.workers["code"].engine = FakeOrchestrator(["worker response"])
result = conductor.run([{"role": "user", "content": "write a function"}], mode="fast")
assert result.mode == "fast"
assert result.trace[0]["worker"] == "code"
def test_invalid_plan_falls_back_gracefully(self, conductor_with_workers):
conductor, orch = conductor_with_workers
# First call: _plan() -> garbage (invalid). Second call: _select_single_worker() -> "pro".
orch.responses = ["not json at all", "pro"]
conductor.workers["pro"].engine = FakeOrchestrator(["fallback response"])
result = conductor.run([{"role": "user", "content": "hard task"}], mode="deep")
assert result.mode == "fallback"
assert "note" in result.trace[0]
class TestWorkerSpec:
def test_invoke_requires_engine_or_call_fn(self):
worker = WorkerSpec("orphan", "no backend configured")
with pytest.raises(RuntimeError):
worker.invoke("do something")
def test_invoke_uses_call_fn_when_present(self):
calls = []
def fake_call(system_prompt, content):
calls.append((system_prompt, content))
return "remote response"
worker = WorkerSpec("remote", "a remote worker", call_fn=fake_call, role_prompt="be helpful")
result = worker.invoke("do the thing", context="prior context")
assert result == "remote response"
assert calls[0][0] == "be helpful"
assert "prior context" in calls[0][1]
assert "do the thing" in calls[0][1]