feat: add NORTH_STAR.md and MVP core loop (Telegram bot + LLM + proposal generator)
This commit is contained in:
committed by
GitHub
parent
c071fe6bf7
commit
6862c7d0b8
@@ -0,0 +1,119 @@
|
||||
"""Tests for steward.bot.telegram (handler logic)."""
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
from telegram import Message, Update, User
|
||||
from telegram.ext import CallbackContext
|
||||
|
||||
from steward.bot.telegram import (
|
||||
_history,
|
||||
_is_allowed,
|
||||
clear_handler,
|
||||
message_handler,
|
||||
start_handler,
|
||||
)
|
||||
from steward.config import Settings
|
||||
from steward.llm.client import LLMClient
|
||||
|
||||
|
||||
def _make_settings(**kwargs) -> Settings:
|
||||
defaults = dict(
|
||||
telegram_bot_token="test-token",
|
||||
openai_api_key="test-key",
|
||||
)
|
||||
defaults.update(kwargs)
|
||||
return Settings(**defaults)
|
||||
|
||||
|
||||
def _make_update(user_id: int = 12345, text: str = "hello") -> Update:
|
||||
user = MagicMock(spec=User)
|
||||
user.id = user_id
|
||||
|
||||
message = MagicMock(spec=Message)
|
||||
message.text = text
|
||||
message.reply_text = AsyncMock()
|
||||
|
||||
update = MagicMock(spec=Update)
|
||||
update.effective_user = user
|
||||
update.message = message
|
||||
return update
|
||||
|
||||
|
||||
def _make_context(settings: Settings, llm: LLMClient | None = None) -> CallbackContext: # type: ignore[type-arg]
|
||||
ctx = MagicMock(spec=CallbackContext)
|
||||
ctx.bot_data = {"settings": settings, "llm": llm}
|
||||
return ctx
|
||||
|
||||
|
||||
class TestIsAllowed:
|
||||
def test_no_allowlist_allows_everyone(self):
|
||||
settings = _make_settings(telegram_allowed_user_ids=[])
|
||||
assert _is_allowed(999, settings) is True
|
||||
|
||||
def test_allowlist_accepts_known_user(self):
|
||||
settings = _make_settings(telegram_allowed_user_ids=[1, 2, 3])
|
||||
assert _is_allowed(2, settings) is True
|
||||
|
||||
def test_allowlist_rejects_unknown_user(self):
|
||||
settings = _make_settings(telegram_allowed_user_ids=[1, 2, 3])
|
||||
assert _is_allowed(999, settings) is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_handler_replies(monkeypatch):
|
||||
settings = _make_settings()
|
||||
update = _make_update()
|
||||
ctx = _make_context(settings)
|
||||
|
||||
await start_handler(update, ctx)
|
||||
|
||||
update.message.reply_text.assert_awaited_once()
|
||||
text = update.message.reply_text.call_args.args[0]
|
||||
assert "Steward" in text
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_handler_ignores_disallowed_user():
|
||||
settings = _make_settings(telegram_allowed_user_ids=[9999])
|
||||
update = _make_update(user_id=1111)
|
||||
ctx = _make_context(settings)
|
||||
|
||||
await start_handler(update, ctx)
|
||||
|
||||
update.message.reply_text.assert_not_awaited()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clear_handler_clears_history():
|
||||
settings = _make_settings()
|
||||
user_id = 42
|
||||
_history[user_id] = [{"role": "user", "content": "old msg"}]
|
||||
|
||||
update = _make_update(user_id=user_id)
|
||||
ctx = _make_context(settings)
|
||||
|
||||
await clear_handler(update, ctx)
|
||||
|
||||
assert _history[user_id] == []
|
||||
update.message.reply_text.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_message_handler_calls_llm_and_replies():
|
||||
settings = _make_settings()
|
||||
mock_llm = MagicMock(spec=LLMClient)
|
||||
mock_llm.chat = AsyncMock(return_value="LLM response")
|
||||
|
||||
update = _make_update(user_id=77, text="What is the weather?")
|
||||
ctx = _make_context(settings, llm=mock_llm)
|
||||
|
||||
_history[77].clear()
|
||||
await message_handler(update, ctx)
|
||||
|
||||
mock_llm.chat.assert_awaited_once()
|
||||
update.message.reply_text.assert_awaited_once()
|
||||
# History should now contain the user/assistant turn
|
||||
assert len(_history[77]) == 2
|
||||
assert _history[77][0]["role"] == "user"
|
||||
assert _history[77][1]["role"] == "assistant"
|
||||
Reference in New Issue
Block a user