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
9 changes: 6 additions & 3 deletions lib/features/holding_news.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from .. import config
from ..ask import ask
from ..context import Ctx
from ..llm.base import is_busy
from ..llm.base import BUSY_REPLY, is_busy
from ..llm.gate import Route
from ..mcp.results import table_records
from ..prompts import HOLDING_NEWS_PROMPT
Expand Down Expand Up @@ -233,11 +233,14 @@ async def on_command(ctx: Ctx, msg: Message) -> None:
return
draft = Draft(ctx.bot, msg.chat_id)
await draft.start()
busy: list[str] = []
try:
result = (await run_holding_news(ctx, only_username=username)).get(username)
result = (await run_holding_news(ctx, only_username=username, busy=busy)).get(username)
finally:
draft.stop()
if result:
if busy:
await asyncio.to_thread(save, await msg.reply_text(BUSY_REPLY))
elif result:
await send_holding_news(ctx, msg.chat_id, *result)
else:
await asyncio.to_thread(
Expand Down
1 change: 1 addition & 0 deletions lib/llm/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ..mcp.schema import ToolDef

BUSY_STATUSES = (429, 503, 529)
BUSY_REPLY = "The AI provider is at capacity right now. Please try again in a few minutes."


class Overloaded(RuntimeError):
Expand Down
3 changes: 1 addition & 2 deletions lib/telegram/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from ..context import Ctx
from ..features import dm_buttons, holding_news, movers, periods, post
from ..history import compact, format_rows
from ..llm.base import is_busy
from ..llm.base import BUSY_REPLY, is_busy
from ..llm.gate import Route, is_portfolio_question, route
from ..msgtext import describe, sender_name
from ..prompts import MOVERS_EXPLAIN, PRESET_PROMPT, chat_prompt, down_note
Expand All @@ -30,7 +30,6 @@

log = logging.getLogger("bot")
PORTFOLIO_ADMINS_ONLY = "Portfolio data is for admins only."
BUSY_REPLY = "The AI provider is at capacity right now. Please try again in a few minutes."
FOLLOW_UP_WORDS = 12 # a message this short right after the bot's reply may be a follow-up to it
FOLLOW_UP_SECONDS = 30 * 60
FOLLOW_UP_CHARS = 400 # of the bot's reply that the tool gate also reads
Expand Down
2 changes: 1 addition & 1 deletion mcp_servers.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"sharesight": {
"description": "Sharesight portfolios. Never ask the user for portfolio IDs or holdings: call list_portfolios first (it names every portfolio and its owner), then get_performance_report for the ones involved. A report's holdings list is exactly their current positions, with quantity, value and gains. When comparing portfolios or explaining a result, write 2-3 short paragraphs: each portfolio's return, then its tailwinds (biggest contributors, with numbers) and headwinds (biggest detractors), and what explains the gap.",
"command": "npx",
"args": ["-y", "github:sryburn/sharesight-mcp"],
"args": ["-y", "github:robdevops/sharesight-mcp"],
"env": {
"SHARESIGHT_CLIENT_ID": "${SHARESIGHT_CLIENT_ID}",
"SHARESIGHT_CLIENT_SECRET": "${SHARESIGHT_CLIENT_SECRET}"
Expand Down
8 changes: 8 additions & 0 deletions tests/test_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,11 @@ async def test_flushcache_command_is_admin_only_and_flushes_by_portfolio_and_per
every = user_msg(ctx.bot, "/flushcache", user_id=5, mid=5)
await commands.flush_cache(ctx, update_for(every), N(args=[]))
assert "Flushed 4 cached periods (all portfolios)" in every.replies[0]["text"]


async def test_holdingnews_command_says_when_the_provider_is_busy(env, store):
ctx = holding_ctx(env, store, [Overloaded("at capacity")])
m = user_msg(ctx.bot, "/holdingnews", chat_id=5, user_id=5)
m.from_user.username = "bob_llama"
await holding_news.on_command(ctx, m)
assert "at capacity" in m.replies[-1]["text"] and "No major news" not in m.replies[-1]["text"]
Loading