Files
Claude Agent a89cf201ab fix(discord-bridge): zgomot in bot.log si doua tipuri de stream necunoscute
Trei lucruri observate in logurile de productie dupa restartul precedent.

1. Ecoul propriilor mesaje umplea bot.log cu WARNING. Propriile mesaje au si
   ele `author.bot == True`, iar verificarea generica de bot venea INAINTEA
   celei pe `self_id` — deci raspunsurile botului se jurnalizau ca "bot
   strain", la fiecare mesaj. Verificarea pe `self_id` trece prima (motivul e
   acum precis), iar refuzurile de rutina — propriile mesaje si ceilalti boti —
   merg la DEBUG. Guild / canal / utilizator strain si webhook raman WARNING:
   alea chiar sunt semnal de securitate si erau inecate in zgomot.

2. `tool_progress` (heartbeat la 30s cat timp o unealta ruleaza) devine
   eveniment `ToolProgress`. Mesajul live arata acum "⏳ ruleaza de 2m30s" sub
   unealta curenta — singurul semn ca un tur lung lucreaza si nu a inghetat.

3. `rate_limit_event` devine eveniment `RateLimit` si apare in `/status` la
   randul `utilizare`. Cum nu exista plafon de cost (abonament, nu API),
   fereastra de utilizare e singura limita reala; se avertizeaza in log o data
   per schimbare de stare, nu la fiecare eveniment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
2026-08-31 07:46:51 +00:00

174 lines
6.0 KiB
Python

"""T6: parser tolerant."""
from __future__ import annotations
import json
import pytest
import stream
def P(**kw):
return stream.StreamParser(**kw)
def test_system_init_aduce_session_id():
p = P()
(ev,) = p.feed_line(json.dumps({"type": "system", "subtype": "init",
"session_id": "s1", "model": "sonnet", "cwd": "/workspace",
"tools": ["Bash"]}))
assert isinstance(ev, stream.SystemInit)
assert ev.session_id == "s1" and ev.model == "sonnet" and ev.tools == ("Bash",)
def test_assistant_text_si_tool_use():
p = P()
evs = p.feed_line(json.dumps({"type": "assistant", "session_id": "s1", "message": {"content": [
{"type": "text", "text": "salut"},
{"type": "tool_use", "id": "tu1", "name": "Bash", "input": {"command": "ls"}}]}}))
assert [type(e) for e in evs] == [stream.AssistantText, stream.ToolUse]
assert evs[0].text == "salut"
assert evs[1].name == "Bash" and evs[1].input["command"] == "ls"
def test_tool_result_din_user():
p = P()
(ev,) = p.feed_line(json.dumps({"type": "user", "message": {"content": [
{"type": "tool_result", "tool_use_id": "tu1", "content": [{"type": "text", "text": "out"}]}]}}))
assert isinstance(ev, stream.ToolResult) and ev.text == "out" and ev.is_error is False
def test_result_aduce_cost_si_durata():
p = P()
(ev,) = p.feed_line(json.dumps({"type": "result", "subtype": "success", "is_error": False,
"total_cost_usd": 0.1547, "duration_ms": 34500,
"num_turns": 3, "result": "gata"}))
assert (ev.total_cost_usd, ev.duration_ms, ev.num_turns, ev.text) == (0.1547, 34500, 3, "gata")
assert ev.is_error is False and p.saw_result
def test_result_cu_campuri_stricate_nu_crapa():
p = P()
(ev,) = p.feed_line(json.dumps({"type": "result", "total_cost_usd": "nu-i numar",
"duration_ms": None, "num_turns": "x"}))
assert ev.total_cost_usd == 0.0 and ev.duration_ms == 0 and ev.num_turns == 0
def test_result_de_eroare_marcat():
p = P()
(ev,) = p.feed_line(json.dumps({"type": "result", "subtype": "error_during_execution"}))
assert ev.is_error is True
def test_tip_necunoscut_logat_o_singura_data():
calls = []
p = P(version_fn=lambda: (calls.append(1), "2.1.251")[1])
line = json.dumps({"type": "tip_care_nu_exista", "detail": "x"})
assert p.feed_line(line) == []
assert p.feed_line(line) == []
assert p.feed_line(json.dumps({"type": "alt_tip_nou"})) == []
assert p.unknown_types == {"tip_care_nu_exista", "alt_tip_nou"}
assert len(calls) == 2 # o data per tip, nu per linie
def test_linie_non_json_ignorata(caplog):
p = P()
with caplog.at_level("WARNING"):
assert p.feed_line("Error: something went wrong") == []
assert p.feed_line("[1, 2, 3]") == []
assert p.bad_lines == 2
assert any("non-JSON" in r.message or "nu e obiect" in r.message for r in caplog.records)
def test_linii_goale_ignorate():
p = P()
assert p.feed_line("") == [] and p.feed_line(" \n") == []
async def _aiter(lines):
for x in lines:
yield x
async def test_eof_inainte_de_result_da_eroare_explicita():
p = P()
got = []
with pytest.raises(stream.StreamEOFError):
async for ev in p.aiter_events(_aiter([
json.dumps({"type": "system", "subtype": "init", "session_id": "s1"}),
json.dumps({"type": "assistant", "message": {"content": [{"type": "text", "text": "hm"}]}}),
])):
got.append(ev)
assert len(got) == 2
async def test_aiter_se_opreste_la_result():
p = P()
evs = [e async for e in p.aiter_events(_aiter([
json.dumps({"type": "system", "subtype": "init", "session_id": "s1"}),
json.dumps({"type": "result", "total_cost_usd": 1.0}),
json.dumps({"type": "assistant", "message": {"content": [{"type": "text", "text": "dupa"}]}}),
]))]
assert [type(e) for e in evs] == [stream.SystemInit, stream.Result]
async def test_aiter_accepta_bytes_si_gunoi():
p = P()
evs = [e async for e in p.aiter_events(_aiter([
b"gunoi binar\n",
b'{"type":"result","total_cost_usd":0.5}\n',
]))]
assert len(evs) == 1 and evs[0].total_cost_usd == 0.5
# ------------------------------------------ tool_progress si rate_limit_event
# Ambele apareau in bot.log ca "tip necunoscut ignorat" (claude 2.1.251).
def test_tool_progress_devine_eveniment():
p = P()
ev = p.feed_line(json.dumps({
"type": "tool_progress",
"tool_use_id": "toolu_01-heartbeat-0",
"tool_name": "Bash",
"parent_tool_use_id": "toolu_01",
"elapsed_time_seconds": 30,
"heartbeat": True,
}))[0]
assert isinstance(ev, stream.ToolProgress)
assert (ev.tool_name, ev.elapsed_s, ev.heartbeat) == ("Bash", 30, True)
assert p.unknown_types == set()
def test_tool_progress_cu_campuri_aiurea_nu_arunca():
p = P()
ev = p.feed_line(json.dumps({"type": "tool_progress", "elapsed_time_seconds": "x"}))[0]
assert (ev.tool_name, ev.elapsed_s, ev.heartbeat) == ("?", 0, False)
def test_rate_limit_event_devine_eveniment():
p = P()
ev = p.feed_line(json.dumps({
"type": "rate_limit_event",
"rate_limit_info": {
"status": "allowed", "resetsAt": 1788171600,
"rateLimitType": "five_hour", "overageStatus": "rejected",
},
}))[0]
assert isinstance(ev, stream.RateLimit)
assert ev.ok and ev.limit_type == "five_hour" and ev.resets_at == 1788171600
assert p.unknown_types == set()
def test_rate_limit_event_franat_nu_e_ok():
p = P()
ev = p.feed_line(json.dumps(
{"type": "rate_limit_event", "rate_limit_info": {"status": "rejected"}}))[0]
assert not ev.ok and ev.status == "rejected"
def test_rate_limit_event_fara_info_nu_arunca():
p = P()
ev = p.feed_line(json.dumps({"type": "rate_limit_event"}))[0]
assert not ev.ok and ev.status == "necunoscut" and ev.resets_at == 0