From ecfbc866766b04eff2d4d3e87bb6e4b6e832e5c5 Mon Sep 17 00:00:00 2001 From: Nico Date: Fri, 3 Apr 2026 18:03:56 +0200 Subject: [PATCH] Add 3 red tests for Phase 1: config-driven models Tests that will pass once implemented: - graph_has_models: graph definition includes MODELS dict - instantiate_applies_graph_models: node.model set from graph config - model_override_per_request: process_message accepts model_overrides Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/test_engine.py | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/test_engine.py b/tests/test_engine.py index d1cfc70..ce5f96d 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -477,9 +477,60 @@ def test_frame_trace_expert_with_interpreter(): assert trace["total_frames"] >= 5, f"expected >=5 frames, got {trace['total_frames']}" +# --- Phase 1: Config-driven models (RED — will fail until implemented) --- + +def test_graph_has_models(): + """Graph definition includes a MODELS dict mapping role → model.""" + g = load_graph("v4-eras") + assert "models" in g, "graph should have a 'models' key" + models = g["models"] + assert isinstance(models, dict), "models should be a dict" + # Every LLM-using node should have a model entry + llm_nodes = {"input", "pa", "expert_eras", "interpreter", "output", "memorizer"} + for role in llm_nodes: + assert role in models, f"models should include '{role}'" + assert isinstance(models[role], str) and "/" in models[role], \ + f"model for '{role}' should be a provider/model string, got {models.get(role)}" + + +def test_instantiate_applies_graph_models(): + """instantiate_nodes applies model from graph config, overriding class default.""" + hud = MockHud() + g = load_graph("v4-eras") + # Override a model in graph config + g["models"] = g.get("models", {}) + g["models"]["input"] = "test/override-model" + nodes = instantiate_nodes(g, hud) + assert nodes["input"].model == "test/override-model", \ + f"input node model should be 'test/override-model', got {nodes['input'].model}" + + +def test_model_override_per_request(): + """Engine accepts model overrides that are applied to nodes for one request.""" + nodes = { + "input": MockInputNode(intent="social", complexity="trivial"), + "output": MockOutputNode(), + "pa": MockPANode(), + "expert_eras": MockExpertNode(), + "interpreter": MockInterpreterNode(), + "memorizer": MockMemorizer(), + "sensor": MockSensor(), + "ui": MockUINode(), + } + engine, sink, hud = make_frame_engine(nodes, "v4-eras") + + # process_message should accept model_overrides param + result = asyncio.get_event_loop().run_until_complete( + engine.process_message("hello", model_overrides={"input": "test/fast-model"}) + ) + # Should complete without error (overrides applied internally) + assert result["trace"]["path"] == "reflex" + + # --- Test registry (for run_tests.py) --- TESTS = { + # Green — engine mechanics 'graph_load': test_graph_load, 'node_instantiation': test_node_instantiation, 'edge_types_complete': test_edge_types_complete, @@ -488,4 +539,8 @@ TESTS = { 'frame_trace_reflex': test_frame_trace_reflex, 'frame_trace_expert': test_frame_trace_expert, 'frame_trace_expert_with_interpreter': test_frame_trace_expert_with_interpreter, + # Red — Phase 1: config-driven models + 'graph_has_models': test_graph_has_models, + 'instantiate_applies_graph_models': test_instantiate_applies_graph_models, + 'model_override_per_request': test_model_override_per_request, }