Skip to content

feat(notifications): custom test-notification text in web (#563)#630

Open
axisrow wants to merge 1 commit into
mainfrom
fix/web-test-notification-text-563
Open

feat(notifications): custom test-notification text in web (#563)#630
axisrow wants to merge 1 commit into
mainfrom
fix/web-test-notification-text-563

Conversation

@axisrow
Copy link
Copy Markdown
Owner

@axisrow axisrow commented May 29, 2026

Addresses the «Тест уведомлений» parity gap from #563.

Проблема

Одно и то же действие вело себя по-разному: CLI notification test --message "..." позволяет задать свой текст, а кнопка «Тест» в вебе всегда слала фиксированную строку.

Решение

  • dispatcher _handle_notifications_test: использует payload["text"], если задан и непустой; иначе — дефолтное сообщение.
  • web handle_test_notification: читает необязательное поле формы text и прокидывает его в payload только если оно непустое (пустое → дефолт диспетчера).
  • шаблон settings/_notifications.html: добавлено необязательное текстовое поле рядом с кнопкой «Тест».

CLI уже поддерживал --message, поэтому правок там не требуется — теперь поведение совпадает.

Примечание: остальные пункты #563 (collect через слой-посредник, интерактивный agent chat, context rebuild, окно dry-run) — отдельные расхождения уровня архитектуры; этот PR закрывает изолированный и безопасный пункт про тест уведомлений.

Проверка

  • ruff чисто; dispatcher + web notifications + CLI notification тесты — 191 passed (включая новые: кастомный текст в payload, пустой текст → пустой payload, дефолт диспетчера).

🤖 Generated with Claude Code

CLI `notification test` accepts `--message`, but the web "Тест" button sent
a fixed string — same action, different behaviour. Bring web to parity:

- dispatcher `_handle_notifications_test` honours payload["text"] when present,
  falling back to the default message otherwise;
- web handle_test_notification reads an optional `text` form field and only
  forwards it when non-blank;
- settings notifications form gains an optional text input.

Addresses the "Тест уведомлений" parity gap from #563.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@etopro
Copy link
Copy Markdown
Collaborator

etopro commented May 29, 2026

PR review

I read the full diff plus the wrapper/CLI/agent code that surrounds it.

Overall: 👍 solid PR, correctly scoped and tested

The core fix is right:

  • Dispatcher (telegram_command_dispatcher.py:858): str(payload.get("text") or "").strip() or "<default>" correctly handles None, missing key, empty string, and whitespace-only — all fall back to the default. ✓
  • Web handler: reads text, strips, passes payload={"text": text} only when non-empty. ✓
  • Template: adds optional input alongside the button. ✓
  • Tests: 3 new + 1 reinforced assertion (the existing dispatcher test now also asserts the default message is sent). ✓

Issues worth flagging

1. Incomplete parity claim (medium)

The PR description says "CLI уже поддерживал --message, поэтому правок там не требуется — теперь поведение совпадает." That's true for CLI ↔ Web, but there's a third codepath that's still hardcoded:

src/agent/tools/notifications.py:101–117

@tool("test_notification", "Send a test notification message via the bot", {})
async def test_notification(args):
    ...
    await svc.send_notification("🔔 Тестовое уведомление от агента")

So:

  • CLI notification test --message ... → custom text ✓
  • Web button → custom text (after this PR) ✓
  • Agent test_notification → still hardcoded string ✗

This is a tiny addition (a text annotated arg + pass to send_notification) and would actually complete the parity. The PR could either close it here or call it out explicitly as a follow-up. The current PR text leaves a reader thinking parity is done.

Also worth noting: the CLI uses NotificationService.send_notification() directly, while the web button goes through the notifications.test dispatcher command. Two paths reach the same notifier — fine, but the dispatcher fix only benefits the web/agent route. Not a bug, just an observation.

2. Test name is mildly misleading (low)

test_test_notification_blank_text_omits_payload asserts kwargs["payload"] == {}, but the handler passes payload=None. The empty-dict comes from _enqueue_notification_command's payload or {} normalization (handlers.py:112). The test name says "omits" but what's tested is "normalized to empty". Either rename to ..._falls_back_to_empty_payload or assert payload=None was the value the handler passed. Not a blocker — passes today, behaves correctly.

3. Dispatcher one-liner is dense but correct (low/nit)

text = str(payload.get("text") or "").strip() or "✅ Тест уведомлений: соединение установлено"

The or-chain works because of Python falsy semantics; if a future caller passes a non-string (e.g., a list), str() would stringify it into the notification. None of the current callers do that, so it's theoretical. If you want to be strict:

raw = payload.get("text")
text = (raw.strip() if isinstance(raw, str) else "") or "✅ Тест уведомлений: соединение установлено"

Optional cleanup.

4. Template — inline style (nit)

style="max-width:20rem" on the input — fine but slightly out of step with utility-class patterns. Skim other settings templates; if they use inline styles, keep as is. Cosmetic.

Verdict

Ship it after deciding on #1 (close the agent gap in this PR, or amend the PR description to call it a known remaining gap). Items 2–4 are nits — none block merge.

🤖 Review generated with Claude Code

@axisrow
Copy link
Copy Markdown
Owner Author

axisrow commented May 29, 2026

@claude review

@claude
Copy link
Copy Markdown

claude Bot commented May 29, 2026

Claude encountered an error after 52s —— View job


PR Review in Progress

  • Gather context and understand request
  • Read changed files
  • Review code changes
  • Post final review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants