Mattermost: add interactive model picker (#38767)

Merged via squash.

Prepared head SHA: 0883654e88
Co-authored-by: mukhtharcm <56378562+mukhtharcm@users.noreply.github.com>
Co-authored-by: mukhtharcm <56378562+mukhtharcm@users.noreply.github.com>
Reviewed-by: @mukhtharcm
This commit is contained in:
Muhammed Mukhthar CM
2026-03-07 21:45:29 +05:30
committed by GitHub
parent 33e7394861
commit 4f08dcccfd
23 changed files with 1867 additions and 290 deletions

View File

@@ -26,21 +26,14 @@ import {
listMattermostDirectoryGroups,
listMattermostDirectoryPeers,
} from "./mattermost/directory.js";
import {
buildButtonAttachments,
resolveInteractionCallbackUrl,
setInteractionSecret,
} from "./mattermost/interactions.js";
import { monitorMattermostProvider } from "./mattermost/monitor.js";
import { probeMattermost } from "./mattermost/probe.js";
import { addMattermostReaction, removeMattermostReaction } from "./mattermost/reactions.js";
import { resolveMattermostSendChannelId, sendMessageMattermost } from "./mattermost/send.js";
import { sendMessageMattermost } from "./mattermost/send.js";
import { looksLikeMattermostTargetId, normalizeMattermostMessagingTarget } from "./normalize.js";
import { mattermostOnboardingAdapter } from "./onboarding.js";
import { getMattermostRuntime } from "./runtime.js";
const SIGNED_CHANNEL_ID_CONTEXT_KEY = "__openclaw_channel_id";
const mattermostMessageActions: ChannelMessageActionAdapter = {
listActions: ({ cfg }) => {
const enabledAccounts = listMattermostAccountIds(cfg)
@@ -162,61 +155,14 @@ const mattermostMessageActions: ChannelMessageActionAdapter = {
const replyToId = typeof params.replyToId === "string" ? params.replyToId : undefined;
const resolvedAccountId = accountId || undefined;
// Build props with button attachments if buttons are provided
let props: Record<string, unknown> | undefined;
if (params.buttons && Array.isArray(params.buttons)) {
const account = resolveMattermostAccount({ cfg, accountId: resolvedAccountId });
if (account.botToken) setInteractionSecret(account.accountId, account.botToken);
const channelId = await resolveMattermostSendChannelId(to, {
cfg,
accountId: account.accountId,
});
const callbackUrl = resolveInteractionCallbackUrl(account.accountId, {
gateway: cfg.gateway,
interactions: account.config.interactions,
});
// Flatten 2D array (rows of buttons) to 1D — core schema sends Array<Array<Button>>
// but Mattermost doesn't have row layout, so we flatten all rows into a single list.
// Also supports 1D arrays for backward compatibility.
const rawButtons = (params.buttons as Array<unknown>).flatMap((item) =>
Array.isArray(item) ? item : [item],
) as Array<Record<string, unknown>>;
const buttons = rawButtons
.map((btn) => ({
id: String(btn.id ?? btn.callback_data ?? ""),
name: String(btn.text ?? btn.name ?? btn.label ?? ""),
style: (btn.style as "default" | "primary" | "danger") ?? "default",
context:
typeof btn.context === "object" && btn.context !== null
? {
...(btn.context as Record<string, unknown>),
[SIGNED_CHANNEL_ID_CONTEXT_KEY]: channelId,
}
: { [SIGNED_CHANNEL_ID_CONTEXT_KEY]: channelId },
}))
.filter((btn) => btn.id && btn.name);
const attachmentText =
typeof params.attachmentText === "string" ? params.attachmentText : undefined;
props = {
attachments: buildButtonAttachments({
callbackUrl,
accountId: account.accountId,
buttons,
text: attachmentText,
}),
};
}
const mediaUrl =
typeof params.media === "string" ? params.media.trim() || undefined : undefined;
const result = await sendMessageMattermost(to, message, {
accountId: resolvedAccountId,
replyToId,
props,
buttons: Array.isArray(params.buttons) ? params.buttons : undefined,
attachmentText: typeof params.attachmentText === "string" ? params.attachmentText : undefined,
mediaUrl,
});