Add 4 red tests for Phase 2: shared node pool + contextvar HUD
Tests that will pass once implemented: - pool_creates_shared_nodes: NodePool has shared stateless nodes - pool_excludes_stateful: sensor/memorizer/ui not shared - pool_reuses_instances: same pool returns same objects - contextvar_hud_isolation: concurrent tasks get isolated HUD Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b4031611e2
commit
d3350fd502
@ -526,6 +526,76 @@ def test_model_override_per_request():
|
|||||||
assert result["trace"]["path"] == "reflex"
|
assert result["trace"]["path"] == "reflex"
|
||||||
|
|
||||||
|
|
||||||
|
# --- Phase 2: Shared Node Pool (RED — will fail until implemented) ---
|
||||||
|
|
||||||
|
def test_pool_creates_shared_nodes():
|
||||||
|
"""NodePool creates shared instances for stateless nodes."""
|
||||||
|
from agent.node_pool import NodePool
|
||||||
|
pool = NodePool("v4-eras")
|
||||||
|
# Shared nodes should exist
|
||||||
|
assert "input" in pool.shared, "input should be shared"
|
||||||
|
assert "output" in pool.shared, "output should be shared"
|
||||||
|
assert "pa" in pool.shared, "pa should be shared"
|
||||||
|
assert "expert_eras" in pool.shared, "expert_eras should be shared"
|
||||||
|
assert "interpreter" in pool.shared, "interpreter should be shared"
|
||||||
|
|
||||||
|
|
||||||
|
def test_pool_excludes_stateful():
|
||||||
|
"""NodePool excludes stateful nodes (sensor, memorizer, ui)."""
|
||||||
|
from agent.node_pool import NodePool
|
||||||
|
pool = NodePool("v4-eras")
|
||||||
|
assert "sensor" not in pool.shared, "sensor should NOT be shared"
|
||||||
|
assert "memorizer" not in pool.shared, "memorizer should NOT be shared"
|
||||||
|
assert "ui" not in pool.shared, "ui should NOT be shared"
|
||||||
|
|
||||||
|
|
||||||
|
def test_pool_reuses_instances():
|
||||||
|
"""Two Runtimes using the same pool share node objects."""
|
||||||
|
from agent.node_pool import NodePool
|
||||||
|
pool = NodePool("v4-eras")
|
||||||
|
# Same pool → same node instances
|
||||||
|
input1 = pool.shared["input"]
|
||||||
|
input2 = pool.shared["input"]
|
||||||
|
assert input1 is input2, "pool should return same instance"
|
||||||
|
|
||||||
|
|
||||||
|
def test_contextvar_hud_isolation():
|
||||||
|
"""Contextvars isolate HUD events between concurrent tasks."""
|
||||||
|
from agent.nodes.base import _current_hud
|
||||||
|
|
||||||
|
results_a = []
|
||||||
|
results_b = []
|
||||||
|
|
||||||
|
async def hud_a(data):
|
||||||
|
results_a.append(data)
|
||||||
|
|
||||||
|
async def hud_b(data):
|
||||||
|
results_b.append(data)
|
||||||
|
|
||||||
|
async def task_a():
|
||||||
|
_current_hud.set(hud_a)
|
||||||
|
# Simulate work with a yield point
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
hud_fn = _current_hud.get()
|
||||||
|
await hud_fn({"from": "a"})
|
||||||
|
|
||||||
|
async def task_b():
|
||||||
|
_current_hud.set(hud_b)
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
hud_fn = _current_hud.get()
|
||||||
|
await hud_fn({"from": "b"})
|
||||||
|
|
||||||
|
async def run_both():
|
||||||
|
await asyncio.gather(task_a(), task_b())
|
||||||
|
|
||||||
|
asyncio.get_event_loop().run_until_complete(run_both())
|
||||||
|
|
||||||
|
assert len(results_a) == 1 and results_a[0]["from"] == "a", \
|
||||||
|
f"task_a HUD leaked: {results_a}"
|
||||||
|
assert len(results_b) == 1 and results_b[0]["from"] == "b", \
|
||||||
|
f"task_b HUD leaked: {results_b}"
|
||||||
|
|
||||||
|
|
||||||
# --- Test registry (for run_tests.py) ---
|
# --- Test registry (for run_tests.py) ---
|
||||||
|
|
||||||
TESTS = {
|
TESTS = {
|
||||||
@ -538,8 +608,13 @@ TESTS = {
|
|||||||
'frame_trace_reflex': test_frame_trace_reflex,
|
'frame_trace_reflex': test_frame_trace_reflex,
|
||||||
'frame_trace_expert': test_frame_trace_expert,
|
'frame_trace_expert': test_frame_trace_expert,
|
||||||
'frame_trace_expert_with_interpreter': test_frame_trace_expert_with_interpreter,
|
'frame_trace_expert_with_interpreter': test_frame_trace_expert_with_interpreter,
|
||||||
# Red — Phase 1: config-driven models
|
# Phase 1: config-driven models
|
||||||
'graph_has_models': test_graph_has_models,
|
'graph_has_models': test_graph_has_models,
|
||||||
'instantiate_applies_graph_models': test_instantiate_applies_graph_models,
|
'instantiate_applies_graph_models': test_instantiate_applies_graph_models,
|
||||||
'model_override_per_request': test_model_override_per_request,
|
'model_override_per_request': test_model_override_per_request,
|
||||||
|
# Phase 2: shared node pool
|
||||||
|
'pool_creates_shared_nodes': test_pool_creates_shared_nodes,
|
||||||
|
'pool_excludes_stateful': test_pool_excludes_stateful,
|
||||||
|
'pool_reuses_instances': test_pool_reuses_instances,
|
||||||
|
'contextvar_hud_isolation': test_contextvar_hud_isolation,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user