
























@@ -57,7 +57,10 @@ type MessagePresentationButton = {
5757 value?: string;
5858 url?: string;
5959 webApp?: { url: string };
60+/** @deprecated Use webApp. Accepted for legacy JSON payloads only. */
6061 web_app?: { url: string };
62+ priority?: number;
63+ disabled?: boolean;
6164 style?: "primary" | "secondary" | "success" | "danger";
6265};
6366@@ -82,11 +85,19 @@ Button semantics:
8285- `value` is an application action value routed back through the channel's
8386 existing interaction path when the channel supports clickable controls.
8487- `url` is a link button. It can exist without `value`.
85-- `webApp` and `web_app` describe a channel-native web app button. Telegram
86- renders this as `web_app` and only supports it in private chats.
88+- `webApp` describes a channel-native web app button. Telegram renders this
89+ as `web_app` and only supports it in private chats. `web_app` is still
90+ accepted in loose JSON payloads for compatibility, but TypeScript producers
91+ should use `webApp`.
8792- `label` is required and is also used in text fallback.
8893- `style` is advisory. Renderers should map unsupported styles to a safe
8994 default, not fail the send.
95+- `priority` is optional. When a channel advertises action limits and controls
96+ must be dropped, core keeps higher-priority buttons first and preserves
97+ original order among equal priority buttons. When all controls fit, authored
98+ order is preserved.
99+- `disabled` is optional. Channels must opt in with `supportsDisabled`; otherwise
100+ core degrades the disabled control to non-interactive fallback text.
9010191102Select semantics:
92103@@ -205,6 +216,27 @@ const adapter: ChannelOutboundAdapter = {
205216 selects: true,
206217 context: true,
207218 divider: true,
219+ limits: {
220+ actions: {
221+ maxActions: 25,
222+ maxActionsPerRow: 5,
223+ maxRows: 5,
224+ maxLabelLength: 80,
225+ maxValueBytes: 100,
226+ supportsStyles: true,
227+ supportsDisabled: false,
228+ },
229+ selects: {
230+ maxOptions: 25,
231+ maxLabelLength: 100,
232+ maxValueBytes: 100,
233+ },
234+ text: {
235+ maxLength: 2000,
236+ encoding: "characters",
237+ markdownDialect: "discord-markdown",
238+ },
239+ },
208240 },
209241 deliveryCapabilities: {
210242 pin: true,
@@ -218,10 +250,49 @@ const adapter: ChannelOutboundAdapter = {
218250};
219251```
220252221-Capability fields are intentionally simple booleans. They describe what the
222-renderer can make interactive, not every native platform limit. Renderers still
223-own platform-specific limits such as maximum button count, block count, and
224-card size.
253+Capability booleans describe what the renderer can make interactive. Optional
254+`limits` describe the generic envelope core can adapt before calling the
255+renderer:
256+257+```ts
258+type ChannelPresentationCapabilities = {
259+ supported?: boolean;
260+ buttons?: boolean;
261+ selects?: boolean;
262+ context?: boolean;
263+ divider?: boolean;
264+ limits?: {
265+ actions?: {
266+ maxActions?: number;
267+ maxActionsPerRow?: number;
268+ maxRows?: number;
269+ maxLabelLength?: number;
270+ maxValueBytes?: number;
271+ supportsStyles?: boolean;
272+ supportsDisabled?: boolean;
273+ supportsLayoutHints?: boolean;
274+ };
275+ selects?: {
276+ maxOptions?: number;
277+ maxLabelLength?: number;
278+ maxValueBytes?: number;
279+ };
280+ text?: {
281+ maxLength?: number;
282+ encoding?: "characters" | "utf8-bytes" | "utf16-units";
283+ markdownDialect?: "plain" | "markdown" | "html" | "slack-mrkdwn" | "discord-markdown";
284+ supportsEdit?: boolean;
285+ };
286+ };
287+};
288+```
289+290+Core applies generic limits to semantic controls before rendering. Renderers
291+still own final provider-specific validation and clipping for native block
292+count, card size, URL limits, and provider quirks that cannot be expressed in
293+the generic contract. If limits remove every control from a block, core keeps
294+the labels as non-interactive context text so the delivered message still has a
295+visible fallback.
225296226297## Core render flow
227298@@ -230,10 +301,12 @@ When a `ReplyPayload` or message action includes `presentation`, core:
2303011. Normalizes the presentation payload.
2313022. Resolves the target channel's outbound adapter.
2323033. Reads `presentationCapabilities`.
233-4. Calls `renderPresentation` when the adapter can render the payload.
234-5. Falls back to conservative text when the adapter is absent or cannot render.
235-6. Sends the resulting payload through the normal channel delivery path.
236-7. Applies delivery metadata such as `delivery.pin` after the first successful
304+4. Applies generic capability limits such as action count, label length, and
305+ select option count when the adapter advertises them.
306+5. Calls `renderPresentation` when the adapter can render the payload.
307+6. Falls back to conservative text when the adapter is absent or cannot render.
308+7. Sends the resulting payload through the normal channel delivery path.
309+8. Applies delivery metadata such as `delivery.pin` after the first successful
237310 sent message.
238311239312Core owns fallback behavior so producers can stay channel-agnostic. Channel
@@ -303,15 +376,20 @@ code:
303376304377```ts
305378import {
379+adaptMessagePresentationForChannel,
380+applyPresentationActionLimits,
306381interactiveReplyToPresentation,
307382normalizeMessagePresentation,
383+presentationPageSize,
308384presentationToInteractiveControlsReply,
309385presentationToInteractiveReply,
310386renderMessagePresentationFallbackText,
311387} from "openclaw/plugin-sdk/interactive-runtime";
312388```
313389314-New code should accept or produce `MessagePresentation` directly.
390+New code should accept or produce `MessagePresentation` directly. Existing
391+`interactive` payloads are a deprecated subset of `presentation`; runtime
392+support remains for older producers.
315393316394`presentationToInteractiveReply(...)` preserves visible presentation text by
317395mapping the title, text, context, buttons, and selects into the older
@@ -351,7 +429,9 @@ messages where the provider supports those operations.
351429- Implement `renderPresentation` in runtime code, not control-plane plugin
352430 setup code.
353431- Keep native UI libraries out of hot setup/catalog paths.
354-- Preserve platform limits in the renderer and tests.
432+- Declare generic capability limits on `presentationCapabilities.limits` when
433+ they are known.
434+- Preserve final platform limits in the renderer and tests.
355435- Add fallback tests for unsupported buttons, selects, URL buttons, title/text
356436 duplication, and mixed `message` plus `presentation` sends.
357437- Add delivery pin support through `deliveryCapabilities.pin` and
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。