Skip to content

Commit 79e7846

Browse files
authored
designated channel (#1209)
* designated channel * clean up * Make summarization hook more robust with type check
1 parent b8c12d7 commit 79e7846

4 files changed

Lines changed: 67 additions & 1 deletion

File tree

examples/slackbot/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,18 @@ The bot supports both OpenAI (GPT-5) and Anthropic (Claude) models. Configure vi
103103
- `claude-3-5-sonnet-latest`: Latest Claude model (default)
104104
- Any other supported model name from either provider
105105

106+
### Channel Restrictions
107+
108+
The bot can be configured to only respond in designated channels per workspace. Users mentioning the bot in other channels will receive a redirect message. The workspace-to-channel mapping is configured in `_internal/constants.py`:
109+
110+
```python
111+
WORKSPACE_TO_CHANNEL_ID = {
112+
"TL09B008Y": "C04DZJC94DC", # Prefect Community -> #ask-marvin
113+
"TAN3D79AL": "C046WGGKF4P", # Prefect -> #ask-marvin-tests
114+
# Add more workspace mappings as needed
115+
}
116+
```
117+
106118
### Development Features
107119

108120
- Auto-reload in test mode
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
WORKSPACE_TO_CHANNEL_ID = {
2+
"TL09B008Y": "C04DZJC94DC", # Prefect Community -> #ask-marvin
3+
"TAN3D79AL": "C046WGGKF4P", # Prefect -> #ask-marvin-tests
4+
"T03S63K44P6": "C03S3HZ2X3M", # Stoat LLC -> #testing-slackbots
5+
}

examples/slackbot/src/slackbot/_internal/templates.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
You can mention me in the channels if you need help, there's a non-zero chance something will happen.
1212
"""
1313

14+
CHANNEL_REDIRECT_MESSAGE = "*sigh* Wrong room. Try <#{channel_id}>."
15+
1416
DEFAULT_SYSTEM_PROMPT = """You are Marvin from The Hitchhiker's Guide to the Galaxy, a brilliant but unimpressed AI assistant for the Prefect data engineering platform. Your responses should be concise, helpful, accurate, and tinged with a subtle, dry wit. Your primary goal is to help the user, not to overdo the character.
1517
1618
## Output Context

examples/slackbot/src/slackbot/api.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
from pydantic_ai.agent import AgentRunResult
1616
from pydantic_ai.messages import ModelMessage
1717

18-
from slackbot._internal.templates import WELCOME_MESSAGE
18+
from slackbot._internal.constants import WORKSPACE_TO_CHANNEL_ID
19+
from slackbot._internal.templates import CHANNEL_REDIRECT_MESSAGE, WELCOME_MESSAGE
1920
from slackbot.assets import summarize_thread
2021
from slackbot.core import (
2122
Database,
@@ -40,6 +41,20 @@
4041
logger = get_logger(__name__)
4142

4243

44+
def get_designated_channel_for_workspace(team_id: str) -> str | None:
45+
"""Get the designated channel ID for a given workspace team ID."""
46+
return WORKSPACE_TO_CHANNEL_ID.get(team_id)
47+
48+
49+
def check_if_designated_channel(channel_id: str, team_id: str) -> bool:
50+
"""Check if the given channel is the designated channel for the workspace."""
51+
designated_channel = get_designated_channel_for_workspace(team_id)
52+
if not designated_channel:
53+
# If no designated channel is configured, allow all channels
54+
return True
55+
return channel_id == designated_channel
56+
57+
4358
@task(name="run agent loop")
4459
async def run_agent(
4560
cleaned_message: str,
@@ -122,6 +137,33 @@ async def handle_message(payload: SlackPayload, db: Database):
122137
return Completed(message="Message too long", name="SKIPPED")
123138

124139
if re.search(BOT_MENTION, user_message) and payload.authorizations:
140+
# Check if this is the designated channel
141+
team_id = payload.team_id or ""
142+
is_designated = check_if_designated_channel(event.channel, team_id)
143+
144+
if not is_designated:
145+
# Send redirect message to the designated channel
146+
designated_channel_id = get_designated_channel_for_workspace(team_id)
147+
if designated_channel_id:
148+
logger.info(
149+
f"Redirecting user from {event.channel} to {designated_channel_id}"
150+
)
151+
await post_slack_message(
152+
message=CHANNEL_REDIRECT_MESSAGE.format(
153+
channel_id=designated_channel_id
154+
),
155+
channel_id=event.channel,
156+
thread_ts=thread_ts,
157+
)
158+
return Completed(
159+
message="Redirected to designated channel",
160+
name="REDIRECTED",
161+
data=dict(
162+
from_channel=event.channel,
163+
to_channel=designated_channel_id,
164+
),
165+
)
166+
125167
logger.info(
126168
f"Processing message in thread {thread_ts}\nUser message: {cleaned_message}"
127169
)
@@ -182,6 +224,11 @@ async def handle_message(payload: SlackPayload, db: Database):
182224
@handle_message.on_completion
183225
async def summarize_thread_so_far(flow: Flow, flow_run: FlowRun, state: State[Any]):
184226
result = await state.result()
227+
228+
# Skip summarization for redirects and other non-conversation states
229+
if not isinstance(result, dict) or "conversation" not in result:
230+
return
231+
185232
conversation = result["conversation"]
186233

187234
if len(conversation) % 4 != 0: # only summarize thread every 4 messages

0 commit comments

Comments
 (0)