Add index-free MiniCPM scout, local QLoRA training, and measured evaluation
Tests / core (push) Canceled after 0s
Tests / core (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from micro_scout.agent import search_live
|
||||
from micro_scout.local_policy import OllamaPolicy
|
||||
|
||||
|
||||
class ScriptedPolicy:
|
||||
model = "test-policy"
|
||||
context = 8192
|
||||
max_tokens = 512
|
||||
|
||||
def __init__(self, actions):
|
||||
self.actions = iter(actions)
|
||||
self.messages = []
|
||||
|
||||
def prompt_tokens(self, messages):
|
||||
return 100
|
||||
|
||||
def generate(self, messages, **kwargs):
|
||||
self.messages.append(messages)
|
||||
return {
|
||||
"response": json.dumps(next(self.actions)),
|
||||
"prompt_eval_count": 20,
|
||||
"eval_count": 10,
|
||||
"done_reason": "stop",
|
||||
}
|
||||
|
||||
|
||||
def test_search_loop_collects_verified_evidence_and_optional_trace(tmp_path):
|
||||
(tmp_path / "a.py").write_text("def add(a, b):\n return a + b\n")
|
||||
ref = {"path": "a.py", "start_line": 1, "end_line": 2}
|
||||
policy = ScriptedPolicy(
|
||||
[
|
||||
{"calls": [{"tool": "grep", "pattern": "add"}], "results": []},
|
||||
{"calls": [{"tool": "read", **ref}], "results": []},
|
||||
{"calls": [], "results": [ref]},
|
||||
]
|
||||
)
|
||||
trace = tmp_path / "trace.json"
|
||||
result = search_live(tmp_path, "add two values", policy, trace=trace)
|
||||
assert result["status"] == "completed"
|
||||
assert result["tool_calls"] == 3
|
||||
assert result["input_tokens"] == 60
|
||||
assert result["results"][0]["content"] == "def add(a, b):\n return a + b"
|
||||
assert len(json.loads(trace.read_text())["history"]) == 3
|
||||
|
||||
|
||||
def test_unread_references_are_rejected_and_model_can_recover(tmp_path):
|
||||
(tmp_path / "a.py").write_text("answer = 42\n")
|
||||
ref = {"path": "a.py", "start_line": 1, "end_line": 1}
|
||||
policy = ScriptedPolicy(
|
||||
[
|
||||
{"calls": [], "results": [ref]},
|
||||
{"calls": [{"tool": "read", **ref}], "results": []},
|
||||
{"calls": [], "results": [ref]},
|
||||
]
|
||||
)
|
||||
result = search_live(tmp_path, "find answer", policy)
|
||||
assert result["invalid_actions"] == 1
|
||||
assert result["status"] == "completed"
|
||||
assert "Read the complete range" in policy.messages[1][-1]["content"]
|
||||
|
||||
|
||||
def test_exhaustion_and_abstention_are_distinct(tmp_path):
|
||||
policy = ScriptedPolicy([{"calls": [{"tool": "files"}], "results": []}])
|
||||
result = search_live(tmp_path, "unknown code", policy, max_rounds=1)
|
||||
assert result["status"] == "budget_exhausted"
|
||||
assert result["results"] == []
|
||||
policy = ScriptedPolicy([{"calls": [], "results": []}])
|
||||
assert search_live(tmp_path, "unknown code", policy)["status"] == "abstained"
|
||||
|
||||
|
||||
def test_malformed_actions_and_tool_errors_counted(tmp_path):
|
||||
policy = ScriptedPolicy(
|
||||
[
|
||||
{"something": "else"},
|
||||
{"calls": [{"tool": "shell"}], "results": []},
|
||||
{"calls": [], "results": []},
|
||||
]
|
||||
)
|
||||
result = search_live(tmp_path, "look around", policy)
|
||||
assert result["invalid_actions"] == 1
|
||||
assert result["tool_errors"] == 1
|
||||
assert result["status"] == "abstained"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"endpoint",
|
||||
[
|
||||
"https://example.org",
|
||||
"http://user@localhost",
|
||||
"http://127.0.0.1/elsewhere",
|
||||
"http://127.0.0.1?x=1",
|
||||
],
|
||||
)
|
||||
def test_only_local_model_endpoints_are_supported(endpoint):
|
||||
with pytest.raises(ValueError):
|
||||
OllamaPolicy(endpoint=endpoint)
|
||||
Reference in New Issue
Block a user