mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 12:26:38 -06:00
fix(slack): preserve actual multipart delivery receipt kinds (#129089)
This commit is contained in:
committed by
GitHub
parent
0415c403a7
commit
d2ac0e3b6f
@@ -429,6 +429,19 @@ describe("sendMessageSlack blocks", () => {
|
||||
expect(
|
||||
delivered.some((result) => result.receipt.parts[0]?.kind === "card" && !result.meta),
|
||||
).toBe(true);
|
||||
expect(
|
||||
aggregateResult.receipt.parts.map(({ platformMessageId, kind, index }) => ({
|
||||
platformMessageId,
|
||||
kind,
|
||||
index,
|
||||
})),
|
||||
).toEqual(
|
||||
delivered.map((result, index) => ({
|
||||
platformMessageId: result.messageId,
|
||||
kind: result.receipt.parts[0]?.kind,
|
||||
index,
|
||||
})),
|
||||
);
|
||||
const questionDelivery = delivered.find((delivery) => delivery.meta);
|
||||
expect(questionDelivery?.messageId).not.toBe(aggregateResult.messageId);
|
||||
expect(JSON.stringify(aggregateResult.meta)).toBe(
|
||||
|
||||
@@ -339,6 +339,18 @@ function createSlackSendReceipt(params: {
|
||||
});
|
||||
}
|
||||
|
||||
function createSlackSendReceiptFromResults(
|
||||
results: readonly SlackSendResult[],
|
||||
threadTs?: string,
|
||||
): MessageReceipt {
|
||||
const receipt = createMessageReceiptFromOutboundResults({ results, threadId: threadTs });
|
||||
const thread = threadTs ? { threadId: threadTs } : {};
|
||||
for (const [index, part] of receipt.parts.entries()) {
|
||||
Object.assign(part, { index, ...thread });
|
||||
}
|
||||
return Object.assign(receipt, thread);
|
||||
}
|
||||
|
||||
function resolveToken(params: {
|
||||
explicit?: string;
|
||||
accountId: string;
|
||||
@@ -1134,6 +1146,7 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
accountId: account.accountId,
|
||||
token: delivery.credential,
|
||||
});
|
||||
const deliveredResults: SlackSendResult[] = [];
|
||||
const reportDelivery = async (
|
||||
result: SlackSendResult,
|
||||
deliveredBlocks?: (Block | KnownBlock)[],
|
||||
@@ -1154,6 +1167,7 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
},
|
||||
}
|
||||
: result;
|
||||
deliveredResults.push(deliveryResult);
|
||||
await opts.onDeliveryResult?.(deliveryResult);
|
||||
return deliveryResult;
|
||||
};
|
||||
@@ -1213,7 +1227,6 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
orderedBlockDeliveryPlan?.skipOriginalBlocks
|
||||
? orderedBlockDeliveryPlan
|
||||
: undefined;
|
||||
const sentMessageIds: string[] = [];
|
||||
let lastMessageId = "";
|
||||
let deliveredChannelId = channelId;
|
||||
let canonicalDeliveredThreadTs: string | undefined;
|
||||
@@ -1310,7 +1323,6 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
lastMessageId = response.ts;
|
||||
deliveredChannelId = resolvePostedMessageChannelId(response, deliveredChannelId);
|
||||
canonicalDeliveredThreadTs ??= resolvePostedMessageThreadTs(response);
|
||||
sentMessageIds.push(response.ts);
|
||||
const deliveredThreadTs =
|
||||
resolvePostedMessageThreadTs(response) ?? normalizeSlackThreadTsCandidate(opts.threadTs);
|
||||
const fallbackDelivery = await reportDelivery(
|
||||
@@ -1331,11 +1343,10 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
questionDelivery = fallbackDelivery;
|
||||
}
|
||||
}
|
||||
const messageId = lastMessageId;
|
||||
const deliveredThreadTs =
|
||||
canonicalDeliveredThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs);
|
||||
return {
|
||||
messageId,
|
||||
messageId: lastMessageId,
|
||||
channelId: deliveredChannelId,
|
||||
threadTs: deliveredThreadTs,
|
||||
// Core replaces per-card progress with this aggregate; retain the
|
||||
@@ -1348,12 +1359,7 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
receipt: createSlackSendReceipt({
|
||||
platformMessageIds: sentMessageIds,
|
||||
channelId: deliveredChannelId,
|
||||
kind: fallbackMessages.some((message) => message.blocks) ? "card" : "text",
|
||||
threadTs: deliveredThreadTs,
|
||||
}),
|
||||
receipt: createSlackSendReceiptFromResults(deliveredResults, deliveredThreadTs),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1391,7 +1397,6 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
onPlatformSendDispatch: dispatchOnce,
|
||||
...(delivery.upload ? { auditContext: delivery.upload.auditContext } : {}),
|
||||
});
|
||||
sentMessageIds.push(lastMessageId);
|
||||
await reportDelivery({
|
||||
messageId: lastMessageId,
|
||||
channelId,
|
||||
@@ -1409,8 +1414,7 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
}
|
||||
|
||||
for (const [partIndex, chunk] of chunksToPost.entries()) {
|
||||
const carriesPrimaryMessageOptions =
|
||||
partIndex === 0 && !opts.mediaUrl && sentMessageIds.length === 0;
|
||||
const carriesPrimaryMessageOptions = partIndex === 0 && !opts.mediaUrl;
|
||||
const baseMetadata = carriesPrimaryMessageOptions ? opts.metadata : undefined;
|
||||
// Every post carries its index/count so reconciliation proves the complete
|
||||
// logical text send and never mistakes a partial chunk fanout for success.
|
||||
@@ -1442,7 +1446,6 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
lastMessageId = response.ts;
|
||||
deliveredChannelId = resolvePostedMessageChannelId(response, deliveredChannelId);
|
||||
canonicalDeliveredThreadTs ??= resolvePostedMessageThreadTs(response);
|
||||
sentMessageIds.push(response.ts);
|
||||
await reportDelivery({
|
||||
messageId: response.ts,
|
||||
channelId: deliveredChannelId,
|
||||
@@ -1458,19 +1461,13 @@ async function sendMessageSlackQueuedInner(params: {
|
||||
});
|
||||
}
|
||||
|
||||
const messageId = lastMessageId;
|
||||
const deliveredThreadTs =
|
||||
canonicalDeliveredThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs);
|
||||
return {
|
||||
messageId,
|
||||
messageId: lastMessageId,
|
||||
channelId: deliveredChannelId,
|
||||
threadTs: deliveredThreadTs,
|
||||
receipt: createSlackSendReceipt({
|
||||
platformMessageIds: sentMessageIds,
|
||||
channelId: deliveredChannelId,
|
||||
kind: opts.mediaUrl ? "media" : "text",
|
||||
threadTs: deliveredThreadTs,
|
||||
}),
|
||||
receipt: createSlackSendReceiptFromResults(deliveredResults, deliveredThreadTs),
|
||||
};
|
||||
}
|
||||
/* oxlint-disable max-lines -- TODO: split this grandfathered oversized file. */
|
||||
|
||||
@@ -579,6 +579,7 @@ describe("sendMessageSlack file upload with user IDs", () => {
|
||||
vi.stubEnv("NO_PROXY", "127.0.0.1,localhost");
|
||||
vi.stubEnv("no_proxy", "127.0.0.1,localhost");
|
||||
const alternateClient = createUploadTestClient(`${baseUrl}/api/`);
|
||||
const onDeliveryResult = vi.fn();
|
||||
mockUploadDestination(alternateClient, `${baseUrl}/upload/v1/capability`);
|
||||
fetchWithSsrFGuard.mockImplementationOnce(async (params) => {
|
||||
const mockedFetch = globalThis.fetch;
|
||||
@@ -590,9 +591,30 @@ describe("sendMessageSlack file upload with user IDs", () => {
|
||||
}
|
||||
});
|
||||
|
||||
await sendUpload(alternateClient, { mediaUrl: "/tmp/alternate-root.png" });
|
||||
const result = await sendUpload(alternateClient, {
|
||||
mediaUrl: "/tmp/alternate-root.png",
|
||||
message: "a".repeat(8_500),
|
||||
threadTs: "171.222",
|
||||
onDeliveryResult,
|
||||
});
|
||||
|
||||
expectCompletedUpload({ client: alternateClient, expected: { channel_id: "C123CHAN" } });
|
||||
expect(alternateClient.chat.postMessage).toHaveBeenCalledOnce();
|
||||
expect(
|
||||
onDeliveryResult.mock.calls.map(([delivery]) => delivery.receipt.parts[0]?.kind),
|
||||
).toEqual(["media", "text"]);
|
||||
expect(
|
||||
result.receipt.parts.map(({ platformMessageId, kind, index, threadId }) => ({
|
||||
platformMessageId,
|
||||
kind,
|
||||
index,
|
||||
threadId,
|
||||
})),
|
||||
).toEqual([
|
||||
{ platformMessageId: "F001", kind: "media", index: 0, threadId: "171.222" },
|
||||
{ platformMessageId: "171234.567", kind: "text", index: 1, threadId: "171.222" },
|
||||
]);
|
||||
expect(result.receipt.threadId).toBe("171.222");
|
||||
expect(cleanupUploadTimeout).toHaveBeenCalledOnce();
|
||||
expect(uploadTimeoutControllers).toHaveLength(0);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user