import type { WebClient } from "@slack/web-api"; import type { ChatStreamer } from "@slack/web-api/dist/chat-stream.js"; import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
export type SlackStreamSession = { /** The SDK ChatStreamer instance managing this stream. */
streamer: ChatStreamer; /** Channel this stream lives in. */
channel: string; /** Thread timestamp (required for streaming). */
threadTs: string; /** True once stop() has been called. */
stopped: boolean; /** *TrueonceanySlackAPIcall(startStream/appendStream)hassucceeded. *TheSDKbuffersappendedtextlocallyuntilthebufferexceeds *`buffer_size`(default256chars);onlythendoesitissueanetwork *call.Until`delivered`flips,nothinghasactuallyreachedSlack.
*/
delivered: boolean; /** Text accepted by the SDK but not yet acknowledged by Slack. */
pendingText: string;
};
export type StartSlackStreamParams = {
client: WebClient;
channel: string;
threadTs: string; /** Optional initial markdown text to include in the stream start. */
text?: string; /** *TheteamIDoftheworkspacethisstreambelongsto. *RequiredbytheSlackAPIfor`chat.startStream`/`chat.stopStream`. *Obtainfrom`auth.test`response(`team_id`).
*/
teamId?: string; /** *TheuserIDofthemessagerecipient(requiredforDMstreaming). *Withoutthis,`chat.stopStream`failswith`missing_recipient_user_id` *indirectmessageconversations.
*/
userId?: string;
};
export type AppendSlackStreamParams = {
session: SlackStreamSession;
text: string;
};
export type StopSlackStreamParams = {
session: SlackStreamSession; /** Optional final markdown text to append before stopping. */
text?: string;
};
session.stopped = true; if (text) {
session.pendingText += text;
}
logVerbose(
`slack-stream: stopping stream in ${session.channel} thread=${session.threadTs}${
text ? ` (final text: ${text.length} chars)` : ""
}`,
);
try {
await session.streamer.stop(text ? { markdown_text: text } : undefined);
session.delivered = true;
session.pendingText = "";
} catch (err) { if (isBenignSlackFinalizeError(err)) { const code = extractSlackErrorCode(err) ?? "unknown"; if (session.pendingText) { // stop() can be the first network call for short replies. If Slack // Connect rejects it, the user has not seen the SDK-buffered text yet. thrownew SlackStreamNotDeliveredError(session.pendingText, code);
} if (session.delivered) {
logVerbose(
`slack-stream: finalize rejected by Slack (${code}); prior appends delivered, treating stream as stopped`,
); return;
}
} throw err;
}
/** *SlackAPIerrorcodesthatindicate`chat.stopStream`(orthe *`chat.startStream`calltheSDKissuesinside`stop()`whenthebuffer *neverflushed)cannotfinalizethestreamforthecurrentrecipientor *team.Eitherthecallerfallsbacktoanormalmessage(see *{@linkSlackStreamNotDeliveredError})or,ifpriorappendsalready *deliveredtext,theerrorisloggedverboselyandswallowed.
*/ const BENIGN_SLACK_FINALIZE_ERROR_CODES = new Set<string>([ // Slack Connect recipients: finalize fails because the external user id // is not resolvable in the host workspace (#70295). "user_not_found", // Slack Connect team mismatch in shared channels. "team_not_found", // DMs that closed between stream start and stop. "missing_recipient_user_id",
]);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.