update
This commit is contained in:
@@ -57,7 +57,7 @@ def _mk_race(finder_by_agent):
|
||||
prompts = []
|
||||
|
||||
async def fake_race(topic, label, slots, quorum, timeout, provider, on_update=None,
|
||||
cancelled=None, *, grace=None, min_runtime=None, max_runtime=None):
|
||||
cancelled=None, *, grace=None, min_runtime=None, max_runtime=None, late=None):
|
||||
outs = []
|
||||
for slot in slots:
|
||||
key, prompt = slot["key"], slot["prompt"]
|
||||
@@ -372,6 +372,47 @@ async def test_clarify_inline_evidence_no_tools(sub_env, monkeypatch, tmp_path):
|
||||
assert list(tmp_path.glob("subblock-final-*-j*.md")) # Engine persistiert die Judge-Antwort
|
||||
|
||||
|
||||
async def test_panel_2of3_kehrt_bei_einigkeit_zurueck(tmp_path):
|
||||
"""Zwei übereinstimmende Verdicts → Rückkehr ohne den langsamen Dritten; sein
|
||||
Ergebnis wird detached nachpersistiert (Resume)."""
|
||||
import asyncio as aio
|
||||
gesunken = {}
|
||||
|
||||
async def judge(j, delay, antwort):
|
||||
await aio.sleep(delay)
|
||||
return (0, antwort, "")
|
||||
|
||||
tasks = {aio.create_task(judge(1, 0.01, "a")): 1,
|
||||
aio.create_task(judge(2, 0.02, "a")): 2,
|
||||
aio.create_task(judge(3, 5.0, "b")): 3}
|
||||
|
||||
def sink(j, r):
|
||||
gesunken[j] = r[1]
|
||||
|
||||
import time
|
||||
t0 = time.monotonic()
|
||||
await blx._panel_2of3(tasks, sink, lambda: list(gesunken.values()), lambda s: s)
|
||||
assert time.monotonic() - t0 < 1.0 # nicht auf j3 gewartet
|
||||
assert gesunken == {1: "a", 2: "a"}
|
||||
|
||||
|
||||
async def test_panel_2of3_dissens_wartet_auf_dritten():
|
||||
"""Uneinige erste zwei → der dritte wird abgewartet (Mehrheit braucht ihn)."""
|
||||
import asyncio as aio
|
||||
gesunken = {}
|
||||
|
||||
async def judge(j, delay, antwort):
|
||||
await aio.sleep(delay)
|
||||
return (0, antwort, "")
|
||||
|
||||
tasks = {aio.create_task(judge(1, 0.01, "a")): 1,
|
||||
aio.create_task(judge(2, 0.02, "b")): 2,
|
||||
aio.create_task(judge(3, 0.1, "a")): 3}
|
||||
await blx._panel_2of3(tasks, lambda j, r: gesunken.__setitem__(j, r[1]),
|
||||
lambda: list(gesunken.values()), lambda s: s)
|
||||
assert gesunken == {1: "a", 2: "b", 3: "a"}
|
||||
|
||||
|
||||
async def test_facts_check_inline_cited_evidence(sub_env, monkeypatch, tmp_path):
|
||||
"""Facts-Check: zitierte Zeilenbereiche gehen inline mit, Judge läuft ohne Tools,
|
||||
die Check-Datei schreibt die Engine aus der Text-Antwort."""
|
||||
@@ -409,6 +450,35 @@ async def test_facts_check_inline_cited_evidence(sub_env, monkeypatch, tmp_path)
|
||||
assert (tmp_path / f"facts-check-{sh}-c0-j1.json").exists() # Engine persistiert die Antwort
|
||||
|
||||
|
||||
async def test_facts_find_inline_evidence_no_tools(sub_env, monkeypatch, tmp_path):
|
||||
"""Facts find/erg mit Korpus: Auszüge inline, Agent ohne Tools — Tool-Agenten
|
||||
verloren sich in Reasoning-Schleifen und endeten mit leerem Turn (Retry-Wellen)."""
|
||||
db, ctx, files = sub_env
|
||||
d = _corpus(tmp_path)
|
||||
seen = []
|
||||
facts = {"facts": [{"block": "Alpha", "subblock": "Sub Eins", "key_points": ["k"],
|
||||
"prerequisites": "", "hurdles": "",
|
||||
"cited_facts": [{"text": "T", "source": "Skript.txt, Z.2"}],
|
||||
"example_idea": ""}]}
|
||||
|
||||
async def fake_slot(ctx2, label, *, key, prompt, role, capabilities, payload, timeout, on_line=None):
|
||||
seen.append((key, capabilities, prompt))
|
||||
return blx.OK, payload((0, json.dumps(facts), ""))
|
||||
|
||||
async def fake_agent(key, prompt, timeout, **kw): # Check-Panel
|
||||
return (0, '{"ok": true}', "")
|
||||
|
||||
monkeypatch.setattr(blx, "run_single_slot", fake_slot)
|
||||
monkeypatch.setattr(blx, "run_agent", fake_agent)
|
||||
res = await blx._facts_block(ctx, lambda *a, **k: None, {"arbeit": tmp_path},
|
||||
{"Alpha": ["Sub Eins"]}, {"type": "uni"}, d, "", ns="x-")
|
||||
assert res is not None
|
||||
finder = [s for s in seen if "-facts-c0" in s[0] or "-facts-erg-" in s[0]]
|
||||
assert finder and all(caps == "none" for _, caps, _ in finder)
|
||||
assert all("── Skript.txt" in prompt for _, _, prompt in finder) # Auszüge inline
|
||||
assert all("ls/find" not in prompt for _, _, prompt in finder)
|
||||
|
||||
|
||||
def test_sub_key_resolves_short_titles():
|
||||
"""Artefakt-Agenten echoen den Kurztitel; der Sub-Key heißt 'kurztitel: beschreibung'.
|
||||
Eindeutiger Präfix wird aufgelöst, Mehrdeutiges und Fehlendes bleibt unverändert."""
|
||||
|
||||
Reference in New Issue
Block a user