mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-08-14 08:52:06 +00:00
206 lines
6.9 KiB
Python
206 lines
6.9 KiB
Python
"""Tests for the new ICLUpdaterPolicy versioned example database features."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from openjarvis.learning.icl_updater import ICLUpdaterPolicy
|
|
|
|
|
|
class TestICLUpdaterAddExample:
|
|
def test_add_example_quality_gate(self):
|
|
"""Examples below the quality threshold should be rejected."""
|
|
policy = ICLUpdaterPolicy(min_score=0.7)
|
|
accepted = policy.add_example(
|
|
query="low quality",
|
|
response="bad answer",
|
|
outcome=0.3,
|
|
)
|
|
assert accepted is False
|
|
assert len(policy.example_db) == 0
|
|
assert policy.version == 0
|
|
|
|
def test_add_example_stores(self):
|
|
"""Examples above the threshold should be stored."""
|
|
policy = ICLUpdaterPolicy(min_score=0.5)
|
|
accepted = policy.add_example(
|
|
query="What is 2+2?",
|
|
response="4",
|
|
outcome=0.9,
|
|
metadata={"source": "test"},
|
|
)
|
|
assert accepted is True
|
|
assert len(policy.example_db) == 1
|
|
ex = policy.example_db[0]
|
|
assert ex["query"] == "What is 2+2?"
|
|
assert ex["response"] == "4"
|
|
assert ex["outcome"] == 0.9
|
|
assert ex["metadata"] == {"source": "test"}
|
|
assert ex["version"] == 1
|
|
|
|
def test_add_example_at_threshold(self):
|
|
"""An example exactly at the threshold should be accepted."""
|
|
policy = ICLUpdaterPolicy(min_score=0.7)
|
|
accepted = policy.add_example(
|
|
query="borderline",
|
|
response="ok",
|
|
outcome=0.7,
|
|
)
|
|
assert accepted is True
|
|
assert len(policy.example_db) == 1
|
|
|
|
|
|
class TestICLUpdaterRollback:
|
|
def test_rollback(self):
|
|
"""Rollback should remove examples added after the given version."""
|
|
policy = ICLUpdaterPolicy(min_score=0.5)
|
|
policy.add_example("q1", "r1", 0.8)
|
|
policy.add_example("q2", "r2", 0.9)
|
|
v2 = policy.version
|
|
assert v2 == 2
|
|
|
|
policy.add_example("q3", "r3", 0.85)
|
|
policy.add_example("q4", "r4", 0.95)
|
|
assert len(policy.example_db) == 4
|
|
assert policy.version == 4
|
|
|
|
policy.rollback(v2)
|
|
assert policy.version == 2
|
|
assert len(policy.example_db) == 2
|
|
queries = [ex["query"] for ex in policy.example_db]
|
|
assert "q1" in queries
|
|
assert "q2" in queries
|
|
assert "q3" not in queries
|
|
assert "q4" not in queries
|
|
|
|
def test_rollback_to_zero(self):
|
|
"""Rollback to version 0 should remove all examples."""
|
|
policy = ICLUpdaterPolicy(min_score=0.5)
|
|
policy.add_example("q1", "r1", 0.8)
|
|
policy.add_example("q2", "r2", 0.9)
|
|
policy.rollback(0)
|
|
assert policy.version == 0
|
|
assert len(policy.example_db) == 0
|
|
|
|
|
|
class TestICLUpdaterGetExamples:
|
|
def test_get_examples(self):
|
|
"""Should return examples sorted by outcome."""
|
|
policy = ICLUpdaterPolicy(min_score=0.5)
|
|
policy.add_example("math q1", "r1", 0.7)
|
|
policy.add_example("math q2", "r2", 0.95)
|
|
policy.add_example("math q3", "r3", 0.8)
|
|
|
|
results = policy.get_examples(top_k=2)
|
|
assert len(results) == 2
|
|
assert results[0]["outcome"] >= results[1]["outcome"]
|
|
assert results[0]["outcome"] == 0.95
|
|
|
|
def test_get_examples_with_query_class(self):
|
|
"""Filtering by query_class should narrow results."""
|
|
policy = ICLUpdaterPolicy(min_score=0.5)
|
|
policy.add_example("math problem", "42", 0.9)
|
|
policy.add_example("code review", "looks good", 0.85)
|
|
policy.add_example("math equation", "x=5", 0.8)
|
|
|
|
results = policy.get_examples(query_class="math", top_k=10)
|
|
assert len(results) == 2
|
|
assert all("math" in ex["query"].lower() for ex in results)
|
|
|
|
def test_get_examples_empty(self):
|
|
"""No examples should return empty list."""
|
|
policy = ICLUpdaterPolicy(min_score=0.5)
|
|
results = policy.get_examples(top_k=5)
|
|
assert results == []
|
|
|
|
|
|
class TestICLUpdaterVersioning:
|
|
def test_version_increments(self):
|
|
"""Each successful add should increment the version."""
|
|
policy = ICLUpdaterPolicy(min_score=0.5)
|
|
assert policy.version == 0
|
|
|
|
policy.add_example("q1", "r1", 0.8)
|
|
assert policy.version == 1
|
|
|
|
policy.add_example("q2", "r2", 0.9)
|
|
assert policy.version == 2
|
|
|
|
# Rejected add should NOT increment version
|
|
policy.add_example("q3", "r3", 0.1)
|
|
assert policy.version == 2
|
|
|
|
def test_max_examples_limit(self):
|
|
"""Adding beyond max_examples should trim the oldest entries."""
|
|
policy = ICLUpdaterPolicy(min_score=0.5, max_examples=3)
|
|
|
|
policy.add_example("q1", "r1", 0.8)
|
|
policy.add_example("q2", "r2", 0.85)
|
|
policy.add_example("q3", "r3", 0.9)
|
|
assert len(policy.example_db) == 3
|
|
|
|
# Adding a 4th should trim q1 (the oldest)
|
|
policy.add_example("q4", "r4", 0.95)
|
|
assert len(policy.example_db) == 3
|
|
queries = [ex["query"] for ex in policy.example_db]
|
|
assert "q1" not in queries
|
|
assert "q4" in queries
|
|
assert "q2" in queries
|
|
assert "q3" in queries
|
|
|
|
|
|
class TestICLUpdaterAutoApply:
|
|
def test_auto_apply_default_false(self):
|
|
"""auto_apply should default to False."""
|
|
policy = ICLUpdaterPolicy()
|
|
assert policy._auto_apply is False
|
|
|
|
def test_auto_apply_configurable(self):
|
|
"""auto_apply can be set via constructor."""
|
|
policy = ICLUpdaterPolicy(auto_apply=True)
|
|
assert policy._auto_apply is True
|
|
|
|
|
|
class TestICLUpdaterBackwardCompat:
|
|
def test_existing_update_still_works(self):
|
|
"""The original update() method must still function."""
|
|
from dataclasses import dataclass, field
|
|
from typing import Optional
|
|
|
|
from openjarvis.core.types import StepType, TraceStep
|
|
|
|
@dataclass
|
|
class _MockTrace:
|
|
query: str = ""
|
|
model: str = "model-a"
|
|
outcome: str = "success"
|
|
feedback: Optional[float] = 0.8
|
|
steps: list = field(default_factory=list)
|
|
total_latency_seconds: float = 1.0
|
|
|
|
class _MockTraceStore:
|
|
def __init__(self, traces):
|
|
self._traces = traces
|
|
|
|
def list_traces(self):
|
|
return self._traces
|
|
|
|
step = TraceStep(
|
|
step_type=StepType.TOOL_CALL,
|
|
timestamp=0.0,
|
|
input={"tool": "calculator"},
|
|
output={"result": "ok"},
|
|
metadata={"tool_name": "calculator"},
|
|
)
|
|
traces = [
|
|
_MockTrace(
|
|
query="What is 2+2?",
|
|
outcome="success",
|
|
feedback=0.9,
|
|
steps=[step],
|
|
),
|
|
]
|
|
policy = ICLUpdaterPolicy(min_score=0.5)
|
|
store = _MockTraceStore(traces)
|
|
result = policy.update(store)
|
|
assert len(result["examples"]) == 1
|
|
assert result["examples"][0]["query"] == "What is 2+2?"
|