Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions coordination/PROJECT_CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@

## Где закончили

**2026-08-19 (Arena.ai, фикс кнопки «Трейдинг»):** текстовая кнопка «📈 Трейдинг»
вела на старый treasury-отчёт (ключевое слово «трейдинг» в treasury-intent).
Исправлено: единый хелпер send_full_report; перехват текста «трейдинг» ДО
treasury в tg_bot/accounts.py; inline nav_trading на том же хелпере. Живая
симуляция текстового пути подтверждена; отчёт отправлен владельцу (3/3).
Коммит на ветке `agent/20260819-trading-button-fix`.
Журнал: `coordination/sessions/20260819T010000Z-aios-arena-tg-trading-report.md`.

## Где закончили

**2026-08-19 (Arena.ai, отчёт «по-человечески»):** кнопка «Трейдинг» теперь
выдаёт отчёт на языке обывателя: «Главное за 30 секунд», «Что это» к каждому
портфелю, человеческие названия причин сделок, блок «Простыми словами» и
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,18 @@ claim: "coordination/claims/tg-trading-report--20260819T010000Z-aios-arena.md (
- Отчёт отправлен владельцу в TG (3 сообщения: 2 данных + LLM-аналитика).
- Бот перезапущен; тесты test_trading_report.py 8/8; полный pytest зелёный
(кроме регенерируемого inventory).

## Дополнение 2 (2026-08-19, фикс кнопки)

- Владелец сообщил: кнопка «📈 Трейдинг» (текстовая клавиатура) присылала СТАРЫЙ
treasury-отчёт («Мультибиржевой Paper Trading», 10 бирж) — текст попадал в
_handle_treasury_intent по ключевому слову «трейдинг».
- Фикс: единый хелпер send_full_report в tg_bot/trading_report.py; в
tg_bot/accounts.py (_handle_account_intent) перехват нормализованного текста
«трейдинг»/«📈 трейдинг» ДО treasury-интента; inline-callback nav_trading
переведён на тот же хелпер (дублирование убрано).
- Живая симуляция текстового пути: handled=True, отправляется человеческий
отчёт, старый treasury НЕ вызывается. Бот перезапущен; отчёт отправлен
владельцу в TG (3/3 сообщений).
- Тесты: test_trading_button_path.py (3) + обновлённый test_trading_report.py —
11/11 зелёные.
49 changes: 49 additions & 0 deletions tests/test_trading_button_path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Tests: кнопка «Трейдинг» (текст) ведёт на человеческий отчёт."""

from __future__ import annotations

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

from tg_bot.trading_report import send_full_report # noqa: E402


class FakeApi:
def __init__(self):
self.messages = []

def send_message(self, chat_id, text, **kwargs):
self.messages.append(text)


def test_send_full_report_sends_data_and_llm_placeholder():
api = FakeApi()
# LLM-секция реально вызовет балансер — для теста это не нужно,
# поэтому проверяем только структуру с патчем llm_section
import tg_bot.trading_report as mod

orig_llm = mod.llm_section
mod.llm_section = lambda snap: ["🤖 тестовая аналитика"]
try:
send_full_report(api, 123)
finally:
mod.llm_section = orig_llm
assert api.messages, "сообщения не отправлены"
assert any("Главное за 30 секунд" in m for m in api.messages)
assert "⏳ LLM-аналитика готовится…" in api.messages


def test_accounts_routes_trading_text_before_treasury():
src = (Path(__file__).resolve().parents[1] / "tg_bot" / "accounts.py").read_text(encoding="utf-8")
# перехват стоит ДО treasury-интента
pos_trading = src.index('_t_norm in ("трейдинг"')
pos_treasury = src.index("_handle_treasury_intent(api, chat_id, text)")
assert pos_trading < pos_treasury
assert "send_full_report" in src


def test_callbacks_use_shared_helper():
src = (Path(__file__).resolve().parents[1] / "tg_bot" / "callbacks.py").read_text(encoding="utf-8")
assert "from tg_bot.trading_report import send_full_report" in src
3 changes: 1 addition & 2 deletions tests/test_trading_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,4 @@ def test_nav_trading_wired_to_report():

src = _P("/root/AIOS/tg_bot/callbacks.py").read_text(encoding="utf-8")
assert 'data == "nav_trading"' in src
assert "tg_bot.trading_report" in src
assert "llm_section" in src
assert "from tg_bot.trading_report import send_full_report" in src
11 changes: 11 additions & 0 deletions tg_bot/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,17 @@ def _handle_account_intent(api, chat_id: int, text: str) -> bool:
except Exception:
pass

# Кнопка текстовой клавиатуры «📈 Трейдинг» — новый человеческий отчёт
# (до treasury-intent, у которого «трейдинг» числится ключевым словом).
_t_norm = " ".join(str(text or "").casefold().split())
if _t_norm in ("трейдинг", "📈 трейдинг", "трейдинг отчёт", "трейдинг отчет"):
try:
from tg_bot.trading_report import send_full_report
send_full_report(api, chat_id)
except Exception as _e_tr:
api.send_message(chat_id, f"⚠️ Трейдинг-отчёт: {_e_tr}")
return True

# Workflow readiness, jobs, inventory, metrics, bank monitor, recovery, reports and leads precede broad CRM words.
if _m()._handle_treasury_intent(api, chat_id, text):
return True
Expand Down
19 changes: 2 additions & 17 deletions tg_bot/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1170,26 +1170,11 @@ def _handle_nav_callback(api, chat_id: int, cb_id: str, data: str) -> None:
from tg_bot.treasury import _handle_treasury_intent as _hti
_hti(api, chat_id, "казначейство и резервы")
elif data == "nav_trading":
from tg_bot.trading_report import build_snapshot, format_report, llm_section

try:
snap = build_snapshot()
for msg in format_report(snap):
api.send_message(chat_id, msg)
from tg_bot.trading_report import send_full_report
send_full_report(api, chat_id)
except Exception as _e_tr:
api.send_message(chat_id, f"⚠️ Трейдинг-отчёт: {_e_tr}")
return
api.send_message(chat_id, "⏳ LLM-аналитика готовится…")
import threading

def _bg_llm(a, cid, snap_):
try:
for msg in llm_section(snap_):
a.send_message(cid, msg)
except Exception as _e_llm:
a.send_message(cid, f"🤖 LLM-аналитика: ошибка ({_e_llm})")

threading.Thread(target=_bg_llm, args=(api, chat_id, snap), daemon=True).start()
elif data == "crypto_refresh":
from tg_bot.treasury import _handle_treasury_intent as _hti
_hti(api, chat_id, "крипто заработок")
Expand Down
23 changes: 23 additions & 0 deletions tg_bot/trading_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,29 @@ def full_report() -> list[str]:
return format_report(snap) + llm_section(snap)


def send_full_report(api, chat_id) -> None:
"""Отправка отчёта в чат: данные сразу, LLM-аналитика в фоновом потоке.

Используется кнопкой «Трейдинг» (и inline-callback nav_trading, и
текстовой клавиатурой MAIN_MENU_KEYBOARD) — единая точка сборки.
"""

snap = build_snapshot()
for msg in format_report(snap):
api.send_message(chat_id, msg)
api.send_message(chat_id, "⏳ LLM-аналитика готовится…")
import threading

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥 The Roast: import threading внутри функции send_full_report — это как хранить запасной ключ в сейфе, ключ от которого у тебя в кармане. Работает, но каждый вызов тащит повторный импорт, и PEP 8 уже подписала petition на развод.

🩹 The Fix: Перенеси import threading в начало файла. Модули из stdlib не должны импортироваться внутри функции без веской причины.

📏 Severity: nitpick


Reply with @kilocode-bot fix it to have Kilo Code address this issue.


def _bg():
try:
for msg in llm_section(snap):
api.send_message(chat_id, msg)
except Exception as _e:
api.send_message(chat_id, f"🤖 LLM-аналитика: ошибка ({_e})")

threading.Thread(target=_bg, daemon=True).start()


if __name__ == "__main__":
for msg in full_report():
print("=" * 60)
Expand Down
Loading