"""Budget-Stopp (hart) und Infra-Fail-closed (Lauf-Pause statt Teilergebnis).""" import asyncio import agents import ledger import llm import pytest from conftest import run_anlegen, topic_anlegen async def test_budget_stoppt_hart(monkeypatch): topic = topic_anlegen() run = run_anlegen(topic, budget=120) # Fake-Call kostet 150 Tokens ctx = llm.Kontext(run, topic, "minimax") ctx.ebene = "test" with pytest.raises(ledger.BudgetErschoepft): await llm.call(ctx, stage="soll", template="Korpus-Soll", werte={"topic": topic, "quelle": "q", "text": "x"}, erwartet=list) assert ledger.verbraucht(run) >= 120 # der Verbrauch bleibt sichtbar async def test_infra_pause_statt_fail_open(monkeypatch): topic = topic_anlegen() run = run_anlegen(topic) ctx = llm.Kontext(run, topic, "minimax") ctx.ebene = "test" async def immer_429(key, prompt, timeout, **kw): return agents.AgentErgebnis(1, "", "HTTP 429: rate limited") monkeypatch.setattr(agents, "run_agent", immer_429) monkeypatch.setattr(llm, "INFRA_BACKOFF_BASE", 0.01) with pytest.raises(llm.LaufPause): await llm.call(ctx, stage="soll", template="Korpus-Soll", werte={"topic": topic, "quelle": "q", "text": "x"}, erwartet=list) stati = [e["status"] for e in __import__("db").query("SELECT status FROM events WHERE run_id=?", (run,))] assert stati and all(s == "infra" for s in stati) # jeder Versuch im Ledger async def test_inhaltsfehler_kein_laufabbruch(monkeypatch): topic = topic_anlegen() run = run_anlegen(topic) ctx = llm.Kontext(run, topic, "minimax") ctx.ebene = "test" async def unsinn(key, prompt, timeout, **kw): return agents.AgentErgebnis(0, "kein json", "") monkeypatch.setattr(agents, "run_agent", unsinn) 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