fix(send_message): resolve Slack user IDs to DM channel IDs

The _SLACK_TARGET_RE regex only matched IDs starting with C (channel),
G (group), or D (direct message). Slack user IDs start with U, causing
'Could not resolve' errors when trying to send DMs to specific users.

Changes:
- Expand _SLACK_TARGET_RE to accept U-prefixed IDs (user IDs)
- Add conversations.open fallback to resolve user IDs to DM channel
  IDs before sending, since chat.postMessage requires a conversation ID

Fixes #ISSUE_NUMBER
This commit is contained in:
jvinals 2026-05-18 20:07:09 -07:00 committed by Teknium
parent 756900723a
commit 09b6dcc4f3

View file

@ -27,7 +27,7 @@ _FEISHU_TARGET_RE = re.compile(r"^\s*((?:oc|ou|on|chat|open)_[-A-Za-z0-9]+)(?::(
# because the API requires a conversation ID. To DM a user you must first call
# conversations.open to obtain a D... ID. Without this gate, Slack IDs fall
# through to channel-name resolution, which only matches by name and fails.
_SLACK_TARGET_RE = re.compile(r"^\s*([CGD][A-Z0-9]{8,})\s*$")
_SLACK_TARGET_RE = re.compile(r"^\s*([CGDU][A-Z0-9]{8,})\s*$")
# Session-derived Slack thread targets use "<conversation_id>:<thread_ts>".
_SLACK_THREAD_TARGET_RE = re.compile(r"^\s*([CGD][A-Z0-9]{8,}):([^\s:]+)\s*$")
_WEIXIN_TARGET_RE = re.compile(r"^\s*((?:wxid|gh|v\d+|wm|wb)_[A-Za-z0-9_-]+|[A-Za-z0-9._-]+@chatroom|filehelper)\s*$")
@ -275,6 +275,28 @@ def _handle_send(args):
if duplicate_skip:
return json.dumps(duplicate_skip)
# Slack: resolve user IDs (U...) to DM channel IDs via conversations.open
if platform_name == "slack" and chat_id and chat_id.startswith("U"):
try:
import aiohttp
async def _open_slack_dm(token, user_id):
url = "https://slack.com/api/conversations.open"
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
async with session.post(url, headers=headers, json={"users": [user_id]}) as resp:
data = await resp.json()
if data.get("ok"):
return data["channel"]["id"]
return None
from model_tools import _run_async
dm_channel = _run_async(_open_slack_dm(pconfig.token, chat_id))
if dm_channel:
chat_id = dm_channel
else:
return json.dumps({"error": f"Could not open DM with Slack user {chat_id}. Check bot permissions (im:write)."})
except Exception as e:
return json.dumps({"error": f"Failed to open Slack DM: {e}"})
try:
from model_tools import _run_async
result = _run_async(