mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-30 19:02:16 +00:00
- Rewrite .github/workflows/desktop.yml: 2-job pipeline (validate + build-and-release) with rolling desktop-latest pre-release on push to main and stable desktop-v* releases - Add UpdateChecker component: checks for updates on startup + every 30 min, background download with progress bar, one-click relaunch - Configure Tauri updater: endpoints pointing to desktop-latest release, pubkey placeholder - Add tauri-plugin-process for relaunch support (Cargo.toml, lib.rs, package.json) - Add macOS Entitlements.plist for notarization (network + file access, no sandbox) - Add scripts/bump-desktop-version.sh for atomic version bumps across 3 config files - Add desktop/README.md with dev setup, auto-update architecture, signing docs - Update .gitignore for desktop/node_modules, dist, target - Configure macOS minimumSystemVersion, Windows timestampUrl - Include all Phase 14-21 work: agent hardening, RBAC, taint tracking, workflows, skills, knowledge graph, sessions, A2A, MCP templates, WASM sandbox, TUI dashboard, production tools, CLI expansion, API expansion, learning productionization, Tauri desktop app, and 10 new channels Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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?"
|