feat: RSO observation system, child safety, Discord adapter, Telegram watchdog, email attachments
Core agent improvements: - RSO (Relevance Scoring & Observation) system: interaction_logger, memory_scorer, signal_detector - Memory access logging (memory_access_log table) for relevance scoring; high-signal turn detection - Rich conversation storage for notable turns; compact_conversation truncates long user messages - Task-type classifier (query/action/analysis/creative) for observation tagging - Nested sub-agent visibility: deep delegations now register against the main agent's manager Child safety (Gabriel profile): - child_safety.py: filtering, audit logging, prompt constants for restricted sessions - .kiro/specs/child-safety-profile: requirements, design, tasks specs - GABRIEL_BOT_PROPOSAL.md: initial proposal doc - Reduced context window (10 msgs) and tutor-mode identity for restricted users Telegram adapter: - Polling watchdog: auto-restarts updater if polling drops unexpectedly - get_me() with exponential-backoff retry on NetworkError at startup - Correct stop() ordering: signal watchdog before cancelling tasks Email / Gmail: - send_email: supports file attachments (attachments list param) - get_email: surfaces attachment metadata in response Scheduled tasks / weather: - Remove OpenWeatherMap API calls from morning-weather task; use wttr.in exclusively - New scheduled tasks and scheduler state persistence Discord: - adapters/discord/__init__.py scaffold - discord-plugin: MCP plugin for Claude Code Discord integration (server.ts, skills, config) Infrastructure: - n8n workflow exports (garvis_webhook, content_pipeline variants) - memory_workspace: context, homelab-repo-updates, weekly observation summaries, error logs - UCS C240 migration plan doc - requirements.txt: new deps - .claude/settings.json, fix_hooks.py: hook/permission tuning
This commit is contained in:
@@ -112,6 +112,13 @@ class SlackAdapter(BaseAdapter):
|
||||
self.is_running = False
|
||||
print("[Slack] Disconnected")
|
||||
|
||||
def _is_user_allowed(self, user_id: str) -> bool:
|
||||
"""Return False if an allow-list is configured and this user is not on it."""
|
||||
allowed = self.config.settings.get("allowed_users", [])
|
||||
if not allowed:
|
||||
return True # open if unconfigured — preserves existing behaviour
|
||||
return str(user_id) in [str(u) for u in allowed]
|
||||
|
||||
def _register_handlers(self) -> None:
|
||||
"""Register Slack event handlers."""
|
||||
|
||||
@@ -121,8 +128,19 @@ class SlackAdapter(BaseAdapter):
|
||||
if event.get("subtype") in ["bot_message", "message_changed"]:
|
||||
return
|
||||
|
||||
# Suppress Slack system notifications (channel privacy changes, etc.)
|
||||
raw_text = event.get("text", "")
|
||||
_SUPPRESSED_PATTERNS = [
|
||||
"made this channel *private*",
|
||||
"has joined the channel",
|
||||
]
|
||||
if any(p in raw_text for p in _SUPPRESSED_PATTERNS):
|
||||
return
|
||||
|
||||
user_id = event.get("user")
|
||||
text = event.get("text", "")
|
||||
if not self._is_user_allowed(user_id):
|
||||
return
|
||||
text = raw_text
|
||||
channel = event.get("channel")
|
||||
thread_ts = event.get("thread_ts")
|
||||
ts = event.get("ts")
|
||||
@@ -184,6 +202,8 @@ class SlackAdapter(BaseAdapter):
|
||||
async def handle_app_mentions(event, say):
|
||||
"""Handle @mentions of the bot."""
|
||||
user_id = event.get("user")
|
||||
if not self._is_user_allowed(user_id):
|
||||
return
|
||||
text = self._strip_mention(event.get("text", ""))
|
||||
channel = event.get("channel")
|
||||
thread_ts = event.get("thread_ts")
|
||||
|
||||
Reference in New Issue
Block a user