This commit is contained in:
team3
2026-07-13 12:31:25 +02:00
parent 32d7ad9ea1
commit 9cd8e02e22
34 changed files with 747 additions and 606 deletions

View File

@@ -184,3 +184,101 @@ async def test_inhaltsfehler_kein_laufabbruch(monkeypatch):
res = await llm.call(ctx, stage="soll", template="Korpus-Soll",
werte={"topic": topic, "quelle": "q", "text": "x"}, erwartet=list)
assert res is None # begrenzte Restarts, dann None — kein Absturz, keine Pause
async def test_stop_cancelt_verwaisten_haupt_task(monkeypatch):
"""Stop cancelt den Wartenden — der ensure_future-Haupt-Task muss MIT
sterben, sonst hält er Slot + Tokens bis zum Timeout (aak: 10 Waisen)."""
import asyncio
import agents
import llm
from conftest import run_anlegen, topic_anlegen
topic = topic_anlegen("orphan")
ctx = llm.Kontext(run_anlegen(topic), topic, "minimax")
ctx.ebene = "inventar"
gestartet = asyncio.Event()
gecancelt = asyncio.Event()
async def langsamer_agent(key, prompt, timeout, **kw):
gestartet.set()
try:
await asyncio.sleep(60)
except asyncio.CancelledError:
gecancelt.set()
raise
return agents.AgentErgebnis(0, "nie", "")
monkeypatch.setattr(agents, "run_agent", langsamer_agent)
monkeypatch.setattr(llm, "HEDGE_NACH_S", 0) # Pfad: return await haupt
task = asyncio.ensure_future(llm._roher_call("k", "p", 10, ctx, "judge", "none"))
await gestartet.wait()
task.cancel()
try:
await task
except asyncio.CancelledError:
pass
await asyncio.wait_for(gecancelt.wait(), timeout=2) # Waise wurde mitgecancelt
async def test_pause_drainiert_statt_zu_canceln(monkeypatch):
"""ManuellePause in llm.alle: Laufende laufen zu Ende (Ergebnis zählt),
nichts wird gecancelt."""
import asyncio
import llm
fertig = {"langsam": False}
async def schnell_pausiert():
raise llm.ManuellePause("manuell pausiert")
async def langsam():
await asyncio.sleep(0.05)
fertig["langsam"] = True
import pytest
with pytest.raises(llm.ManuellePause):
await llm.alle([schnell_pausiert(), langsam()])
assert fertig["langsam"] is True # NICHT gecancelt — ausgelaufen
async def test_pause_beendet_lauf_als_paused():
"""Pause-Flag → nächster Agent liefert „pausiert" → Lauf endet 'paused';
Start setzt normal fort (Flag wird aufgehoben)."""
import db
import pipeline
from conftest import topic_anlegen
topic = topic_anlegen("pausetest")
run_id = pipeline.lauf_starten(topic)
pipeline.lauf_pausieren(topic) # vor dem ersten Call — deterministisch
await pipeline._laeufe[topic]
run = db.one("SELECT * FROM runs WHERE id=?", (run_id,))
assert run["status"] == "paused" and "pausiert" in run["grund"]
# Resume: Start hebt die Pause auf, Lauf läuft durch
pipeline.lauf_starten(topic)
await pipeline._laeufe[topic]
assert db.one("SELECT status FROM topics WHERE name=?", (topic,))["status"] == "fertig"
async def test_output_cap_ohne_neuversuch(monkeypatch):
"""stop=max_tokens ist deterministisch — sofort None statt 2 Neuversuche
(der Aufrufer halbiert den Chunk)."""
import agents
import db
import llm
from conftest import run_anlegen, topic_anlegen
topic = topic_anlegen("cap")
ctx = llm.Kontext(run_anlegen(topic), topic, "minimax")
ctx.ebene = "inventar"
aufrufe = {"n": 0}
async def cap_agent(key, prompt, timeout, **kw):
aufrufe["n"] += 1
return agents.AgentErgebnis(1, "", "leere Antwort (stop=max_tokens)",
{"input": 100, "output": 32000})
monkeypatch.setattr(agents, "run_agent", cap_agent)
monkeypatch.setattr(llm, "HEDGE_NACH_S", 0)
res = await llm.call(ctx, stage="extraktion", template="Atom-Extraktion",
werte={"topic": topic, "quelle": "q", "text": "x"}, erwartet=list)
assert res is None and aufrufe["n"] == 1 # genau EIN Versuch
ev = db.one("SELECT status, tok_out FROM events WHERE run_id=? AND stage='extraktion'",
(ctx.run_id,))
assert ev["status"] == "cap" and ev["tok_out"] == 32000