Enable bot responses to ourselves

This commit is contained in:
Jack Kingsman
2026-01-29 12:15:30 -08:00
parent bcde4dd12e
commit 302973cc44
10 changed files with 36 additions and 28 deletions

View File

@@ -225,7 +225,7 @@ async def run_bot_for_message(
is_outgoing: bool = False,
) -> None:
"""
Run all enabled bots for an incoming message.
Run all enabled bots for a message (incoming or outgoing).
This is the main entry point called by message handlers after
a message is successfully decrypted and stored. Bots run serially,
@@ -240,12 +240,8 @@ async def run_bot_for_message(
channel_name: Channel name (e.g. "#general"), None for DMs
sender_timestamp: Sender's timestamp from the message
path: Hex-encoded routing path
is_outgoing: Whether this is our own outgoing message (skip bot)
is_outgoing: Whether this is our own outgoing message
"""
# Don't respond to our own outgoing messages
if is_outgoing:
return
# Early check if any bots are enabled (will re-check after sleep)
from app.repository import AppSettingsRepository

View File

@@ -322,8 +322,8 @@ async def create_dm_message_from_decrypted(
# Update contact's last_contacted timestamp (for sorting)
await ContactRepository.update_last_contacted(conversation_key, received)
# Run bot if enabled (for incoming DMs only, not historical decryption or outgoing)
if trigger_bot and not outgoing:
# Run bot if enabled (for all real-time DMs, including our own outgoing messages)
if trigger_bot:
from app.bot import run_bot_for_message
# Get contact name for the bot
@@ -339,7 +339,7 @@ async def create_dm_message_from_decrypted(
channel_name=None,
sender_timestamp=decrypted.timestamp,
path=path,
is_outgoing=False,
is_outgoing=outgoing,
)
return msg_id

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="manifest" href="/site.webmanifest" />
<script type="module" crossorigin src="/assets/index-BtBXI4sW.js"></script>
<script type="module" crossorigin src="/assets/index-DIU0_HcJ.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DiCOP9Mw.css">
</head>
<body>

View File

@@ -871,7 +871,15 @@ export function SettingsModal({
<div className="p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-md">
<p className="text-sm text-yellow-500">
<strong>Security Warning:</strong> This feature executes arbitrary Python code on
the server. Only enable if you understand the security implications.
the server. Only run trusted code, and be cautious of arbitrary usage of message
parameters.
</p>
</div>
<div className="p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-md">
<p className="text-sm text-yellow-500">
<strong>Don&apos;t wreck the mesh!</strong> Bots process ALL messages, including
their own. Be careful of creating infinite loops!
</p>
</div>

View File

@@ -344,9 +344,13 @@ class TestRunBotForMessage:
yield
@pytest.mark.asyncio
async def test_skips_outgoing_messages(self):
"""Bot is not triggered for outgoing messages."""
async def test_runs_for_outgoing_messages(self):
"""Bot is triggered for outgoing messages (user can trigger their own bots)."""
with patch("app.repository.AppSettingsRepository") as mock_repo:
mock_settings = MagicMock()
mock_settings.bots = [] # No enabled bots, but settings ARE checked
mock_repo.get = AsyncMock(return_value=mock_settings)
await run_bot_for_message(
sender_name="Me",
sender_key="abc123",
@@ -356,8 +360,8 @@ class TestRunBotForMessage:
is_outgoing=True,
)
# Should not even check settings
mock_repo.get.assert_not_called()
# Should check settings (outgoing no longer skipped)
mock_repo.get.assert_called_once()
@pytest.mark.asyncio
async def test_skips_when_no_enabled_bots(self):