Files
openclaw/extensions/msteams/src/presentation.ts
Peter Steinberger d641126c1d feat(plugin-sdk): add typed presentation command actions (#88721)
* feat(plugin-sdk): add typed presentation command actions

* test: use shared env helper in telegram bot tests

* test: expect typed approval actions

* test: expect typed sdk approval actions
2026-05-31 18:48:45 +01:00

96 lines
2.6 KiB
TypeScript

import {
adaptMessagePresentationForChannel,
resolveMessagePresentationControlValue,
type MessagePresentation,
} from "openclaw/plugin-sdk/interactive-runtime";
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
import type { ChannelOutboundAdapter } from "../runtime-api.js";
export const MSTEAMS_PRESENTATION_CAPABILITIES = {
supported: true,
buttons: true,
selects: false,
context: true,
divider: true,
limits: {
actions: {
supportsStyles: false,
supportsDisabled: false,
},
text: {
markdownDialect: "markdown",
},
},
} satisfies ChannelOutboundAdapter["presentationCapabilities"];
export function buildMSTeamsPresentationCard(params: {
presentation: MessagePresentation;
text?: string | null;
}) {
const body: Record<string, unknown>[] = [];
const text = normalizeOptionalString(params.text);
if (text) {
body.push({
type: "TextBlock",
text,
wrap: true,
});
}
const presentation = adaptMessagePresentationForChannel({
presentation: params.presentation,
capabilities: MSTEAMS_PRESENTATION_CAPABILITIES,
});
if (presentation.title) {
body.push({
type: "TextBlock",
text: presentation.title,
weight: "Bolder",
size: "Medium",
wrap: true,
});
}
const actions: Record<string, unknown>[] = [];
for (const block of presentation.blocks) {
if (block.type === "text" || block.type === "context") {
body.push({
type: "TextBlock",
text: block.text,
wrap: true,
...(block.type === "context" ? { isSubtle: true, size: "Small" } : {}),
});
continue;
}
if (block.type === "divider") {
body.push({ type: "TextBlock", text: "---", wrap: true, isSubtle: true });
continue;
}
if (block.type === "buttons") {
for (const button of block.buttons) {
const targetUrl = button.url ?? button.webApp?.url ?? button.web_app?.url;
if (targetUrl) {
actions.push({
type: "Action.OpenUrl",
title: button.label,
url: targetUrl,
});
continue;
}
const value = resolveMessagePresentationControlValue(button);
if (value) {
actions.push({
type: "Action.Submit",
title: button.label,
data: button.action?.type === "command" ? value : { value, label: button.label },
});
}
}
}
}
return {
type: "AdaptiveCard",
version: "1.4",
body,
...(actions.length ? { actions } : {}),
};
}