mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 16:01:24 +00:00
* fix(cron): pass agent identity through delivery path Cron delivery messages now include agent identity (name, avatar) in outbound messages. Identity fields are passed best-effort for Slack (graceful fallback if chat:write.customize scope is missing). Fixes #16218 * fix: fix Slack cron delivery identity (#16242) (thanks @robbyczgw-cla) --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -33,8 +33,83 @@ type SlackSendOpts = {
|
||||
mediaUrl?: string;
|
||||
client?: WebClient;
|
||||
threadTs?: string;
|
||||
username?: string;
|
||||
icon_url?: string;
|
||||
icon_emoji?: string;
|
||||
};
|
||||
|
||||
function hasCustomIdentity(opts: SlackSendOpts): boolean {
|
||||
return Boolean(opts.username || opts.icon_url || opts.icon_emoji);
|
||||
}
|
||||
|
||||
function isSlackCustomizeScopeError(err: unknown): boolean {
|
||||
if (!(err instanceof Error)) {
|
||||
return false;
|
||||
}
|
||||
const maybeData = err as Error & {
|
||||
data?: {
|
||||
error?: string;
|
||||
needed?: string;
|
||||
response_metadata?: { scopes?: string[]; acceptedScopes?: string[] };
|
||||
};
|
||||
};
|
||||
const code = maybeData.data?.error?.toLowerCase();
|
||||
if (code !== "missing_scope") {
|
||||
return false;
|
||||
}
|
||||
const needed = maybeData.data?.needed?.toLowerCase();
|
||||
if (needed?.includes("chat:write.customize")) {
|
||||
return true;
|
||||
}
|
||||
const scopes = [
|
||||
...(maybeData.data?.response_metadata?.scopes ?? []),
|
||||
...(maybeData.data?.response_metadata?.acceptedScopes ?? []),
|
||||
].map((scope) => scope.toLowerCase());
|
||||
return scopes.includes("chat:write.customize");
|
||||
}
|
||||
|
||||
async function postSlackMessageBestEffort(params: {
|
||||
client: WebClient;
|
||||
channelId: string;
|
||||
text: string;
|
||||
threadTs?: string;
|
||||
opts: SlackSendOpts;
|
||||
}) {
|
||||
const basePayload = {
|
||||
channel: params.channelId,
|
||||
text: params.text,
|
||||
thread_ts: params.threadTs,
|
||||
};
|
||||
try {
|
||||
// Slack Web API types model icon_url and icon_emoji as mutually exclusive.
|
||||
// Build payloads in explicit branches so TS and runtime stay aligned.
|
||||
if (params.opts.icon_url) {
|
||||
return await params.client.chat.postMessage({
|
||||
...basePayload,
|
||||
...(params.opts.username ? { username: params.opts.username } : {}),
|
||||
icon_url: params.opts.icon_url,
|
||||
});
|
||||
}
|
||||
if (params.opts.icon_emoji) {
|
||||
return await params.client.chat.postMessage({
|
||||
...basePayload,
|
||||
...(params.opts.username ? { username: params.opts.username } : {}),
|
||||
icon_emoji: params.opts.icon_emoji,
|
||||
});
|
||||
}
|
||||
return await params.client.chat.postMessage({
|
||||
...basePayload,
|
||||
...(params.opts.username ? { username: params.opts.username } : {}),
|
||||
});
|
||||
} catch (err) {
|
||||
if (!hasCustomIdentity(params.opts) || !isSlackCustomizeScopeError(err)) {
|
||||
throw err;
|
||||
}
|
||||
logVerbose("slack send: missing chat:write.customize, retrying without custom identity");
|
||||
return params.client.chat.postMessage(basePayload);
|
||||
}
|
||||
}
|
||||
|
||||
export type SlackSendResult = {
|
||||
messageId: string;
|
||||
channelId: string;
|
||||
@@ -182,19 +257,23 @@ export async function sendMessageSlack(
|
||||
maxBytes: mediaMaxBytes,
|
||||
});
|
||||
for (const chunk of rest) {
|
||||
const response = await client.chat.postMessage({
|
||||
channel: channelId,
|
||||
const response = await postSlackMessageBestEffort({
|
||||
client,
|
||||
channelId,
|
||||
text: chunk,
|
||||
thread_ts: opts.threadTs,
|
||||
threadTs: opts.threadTs,
|
||||
opts,
|
||||
});
|
||||
lastMessageId = response.ts ?? lastMessageId;
|
||||
}
|
||||
} else {
|
||||
for (const chunk of chunks.length ? chunks : [""]) {
|
||||
const response = await client.chat.postMessage({
|
||||
channel: channelId,
|
||||
const response = await postSlackMessageBestEffort({
|
||||
client,
|
||||
channelId,
|
||||
text: chunk,
|
||||
thread_ts: opts.threadTs,
|
||||
threadTs: opts.threadTs,
|
||||
opts,
|
||||
});
|
||||
lastMessageId = response.ts ?? lastMessageId;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user