fix(slack): pass recipient_team_id and recipient_user_id to streaming API calls

The Slack Agents & AI Apps streaming API (chat.startStream / chat.stopStream)
requires recipient_team_id and recipient_user_id parameters. Without them,
stopStream fails with 'missing_recipient_team_id' (all contexts) or
'missing_recipient_user_id' (DM contexts), causing streamed messages to
disappear after generation completes.

This passes:
- team_id (from auth.test at provider startup, stored in monitor context)
- user_id (from the incoming message sender, for DM recipient identification)

through to the ChatStreamer via recipient_team_id and recipient_user_id options.

Fixes #19839, #20847, #20299, #19791, #20337

AI-assisted: Written with Claude (Opus 4.6) via OpenClaw. Lightly tested
(unit tests pass, live workspace verification in progress).
This commit is contained in:
David Szarzynski
2026-02-19 08:30:26 -06:00
parent 26c9b37f5b
commit f0bf3be56d
2 changed files with 20 additions and 2 deletions

View File

@@ -199,6 +199,8 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
channel: message.channel,
threadTs: streamThreadTs,
text,
teamId: ctx.teamId,
userId: message.user,
});
replyPlan.markSent();
return;

View File

@@ -36,6 +36,18 @@ export type StartSlackStreamParams = {
threadTs: string;
/** Optional initial markdown text to include in the stream start. */
text?: string;
/**
* The team ID of the workspace this stream belongs to.
* Required by the Slack API for `chat.startStream` / `chat.stopStream`.
* Obtain from `auth.test` response (`team_id`).
*/
teamId?: string;
/**
* The user ID of the message recipient (required for DM streaming).
* Without this, `chat.stopStream` fails with `missing_recipient_user_id`
* in direct message conversations.
*/
userId?: string;
};
export type AppendSlackStreamParams = {
@@ -64,13 +76,17 @@ export type StopSlackStreamParams = {
export async function startSlackStream(
params: StartSlackStreamParams,
): Promise<SlackStreamSession> {
const { client, channel, threadTs, text } = params;
const { client, channel, threadTs, text, teamId, userId } = params;
logVerbose(`slack-stream: starting stream in ${channel} thread=${threadTs}`);
logVerbose(
`slack-stream: starting stream in ${channel} thread=${threadTs}${teamId ? ` team=${teamId}` : ""}${userId ? ` user=${userId}` : ""}`,
);
const streamer = client.chatStream({
channel,
thread_ts: threadTs,
...(teamId ? { recipient_team_id: teamId } : {}),
...(userId ? { recipient_user_id: userId } : {}),
});
const session: SlackStreamSession = {