Get started
طرح بازآرایی نمایش کانال
وضعیت
برای عامل مشترک، CLI، قابلیت Plugin، و سطوح تحویل خروجی پیادهسازی شده است:
ReplyPayload.presentationرابط کاربری معنایی پیام را حمل میکند.ReplyPayload.delivery.pinدرخواستهای سنجاقکردن پیام ارسالشده را حمل میکند.- کنشهای پیام مشترک بهجای
components،blocks،buttonsیاcardبومی ارائهدهنده،presentation،deliveryوpinرا ارائه میکنند. - هسته، ارائه را از طریق قابلیتهای خروجی اعلامشده توسط Plugin رندر میکند یا بهصورت خودکار تنزل میدهد.
- رندرکنندههای Discord، Slack، Telegram، Mattermost، MS Teams و Feishu قرارداد عمومی را مصرف میکنند.
- کد صفحه کنترل کانال Discord دیگر کانتینرهای رابط کاربری مبتنی بر Carbon را import نمیکند.
مستندات مرجع اکنون در ارائه پیام قرار دارند. این طرح را بهعنوان زمینه تاریخی پیادهسازی نگه دارید؛ برای تغییرات قرارداد، رندرکننده یا رفتار fallback، راهنمای مرجع را بهروزرسانی کنید.
مسئله
رابط کاربری کانال در حال حاضر میان چند سطح ناسازگار تقسیم شده است:
- هسته از طریق
buildCrossContextComponentsمالک یک hook رندرکننده میانبافتی با شکل Discord است. channel.tsمربوط به Discord میتواند رابط کاربری بومی Carbon را از طریقDiscordUiContainerimport کند، که وابستگیهای رابط کاربری زمان اجرا را وارد صفحه کنترل Plugin کانال میکند.- عامل و CLI راههای خروج اضطراری payload بومی مانند
componentsدر Discord،blocksدر Slack،buttonsدر Telegram یا Mattermost، وcardدر Teams یا Feishu را ارائه میکنند. ReplyPayload.channelDataهم نکتههای transport و هم envelopeهای رابط کاربری بومی را حمل میکند.- مدل عمومی
interactiveوجود دارد، اما از layoutهای غنیتری که هماکنون توسط Discord، Slack، Teams، Feishu، LINE، Telegram و Mattermost استفاده میشوند محدودتر است.
این موضوع باعث میشود هسته از شکلهای رابط کاربری بومی آگاه باشد، تنبلی زمان اجرای Plugin را تضعیف میکند، و به عاملها راههای بیشازحد وابسته به ارائهدهنده میدهد تا یک intent پیام واحد را بیان کنند.
اهداف
- هسته بهترین ارائه معنایی را برای یک پیام، براساس قابلیتهای اعلامشده، انتخاب میکند.
- افزونهها قابلیتها را اعلام میکنند و ارائه معنایی را به payloadهای transport بومی رندر میکنند.
- رابط کاربری کنترل وب از رابط کاربری بومی چت جدا میماند.
- payloadهای کانال بومی از طریق سطح پیام عامل مشترک یا CLI در معرض قرار نمیگیرند.
- ویژگیهای پشتیبانینشده ارائه بهصورت خودکار به بهترین نمایش متنی تنزل میکنند.
- رفتار تحویل مانند سنجاقکردن یک پیام ارسالشده، metadata عمومی تحویل است، نه ارائه.
غیرهدفها
- هیچ shim سازگاری عقبرو برای
buildCrossContextComponentsوجود ندارد. - هیچ راه خروج اضطراری بومی عمومی برای
components،blocks،buttonsیاcardوجود ندارد. - هیچ import از کتابخانههای رابط کاربری بومی کانال در هسته وجود ندارد.
- هیچ seam مخصوص ارائهدهنده در SDK برای کانالهای bundled وجود ندارد.
مدل هدف
یک فیلد presentation متعلق به هسته به ReplyPayload اضافه کنید.
type MessagePresentationTone = "neutral" | "info" | "success" | "warning" | "danger";
type MessagePresentation = {
tone?: MessagePresentationTone;
title?: string;
blocks: MessagePresentationBlock[];
};
type MessagePresentationBlock =
| { type: "text"; text: string }
| { type: "context"; text: string }
| { type: "divider" }
| { type: "buttons"; buttons: MessagePresentationButton[] }
| { type: "select"; placeholder?: string; options: MessagePresentationOption[] };
type MessagePresentationButton = {
label: string;
value?: string;
url?: string;
style?: "primary" | "secondary" | "success" | "danger";
};
type MessagePresentationOption = {
label: string;
value: string;
};
interactive در طول مهاجرت به زیرمجموعهای از presentation تبدیل میشود:
- بلوک متنی
interactiveبهpresentation.blocks[].type = "text"نگاشت میشود. - بلوک دکمههای
interactiveبهpresentation.blocks[].type = "buttons"نگاشت میشود. - بلوک انتخاب
interactiveبهpresentation.blocks[].type = "select"نگاشت میشود.
schemaهای عامل خارجی و CLI اکنون از presentation استفاده میکنند؛ interactive بهعنوان parser/helper رندر legacy داخلی برای تولیدکنندگان پاسخ موجود باقی میماند.
metadata تحویل
یک فیلد delivery متعلق به هسته برای رفتار ارسال که رابط کاربری نیست اضافه کنید.
type ReplyPayloadDelivery = {
pin?:
| boolean
| {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
};
معناشناسی:
delivery.pin = trueیعنی نخستین پیام با تحویل موفق سنجاق شود.- مقدار پیشفرض
notifyبرابرfalseاست. - مقدار پیشفرض
requiredبرابرfalseاست؛ کانالهای پشتیبانینشده یا شکست در سنجاقکردن با ادامه تحویل بهصورت خودکار تنزل میکنند. - کنشهای پیام دستی
pin،unpinوlist-pinsبرای پیامهای موجود باقی میمانند.
binding فعلی topic در Telegram ACP باید از channelData.telegram.pin = true به delivery.pin = true منتقل شود.
قرارداد قابلیت زمان اجرا
hookهای رندر ارائه و تحویل را به adapter خروجی زمان اجرا اضافه کنید، نه به Plugin کانال صفحه کنترل.
type ChannelPresentationCapabilities = {
supported: boolean;
buttons?: boolean;
selects?: boolean;
context?: boolean;
divider?: boolean;
tones?: MessagePresentationTone[];
};
type ChannelDeliveryCapabilities = {
pinSentMessage?: boolean;
};
type ChannelOutboundAdapter = {
presentationCapabilities?: ChannelPresentationCapabilities;
renderPresentation?: (params: {
payload: ReplyPayload;
presentation: MessagePresentation;
ctx: ChannelOutboundSendContext;
}) => ReplyPayload | null;
deliveryCapabilities?: ChannelDeliveryCapabilities;
pinDeliveredMessage?: (params: {
cfg: OpenClawConfig;
accountId?: string | null;
to: string;
threadId?: string | number | null;
messageId: string;
notify: boolean;
}) => Promise<void>;
};
رفتار هسته:
- کانال هدف و adapter زمان اجرا را resolve کند.
- قابلیتهای ارائه را درخواست کند.
- بلوکهای پشتیبانینشده را پیش از رندر تنزل دهد.
renderPresentationرا فراخوانی کند.- اگر رندرکنندهای وجود ندارد، ارائه را به fallback متنی تبدیل کند.
- پس از ارسال موفق، وقتی
delivery.pinدرخواست شده و پشتیبانی میشود،pinDeliveredMessageرا فراخوانی کند.
نگاشت کانال
Discord:
presentationرا در ماژولهای فقط زمان اجرا به components v2 و کانتینرهای Carbon رندر کنید.- helperهای رنگ accent را در ماژولهای سبک نگه دارید.
- importهای
DiscordUiContainerرا از کد صفحه کنترل Plugin کانال حذف کنید.
Slack:
presentationرا به Block Kit رندر کنید.- ورودی
blocksعامل و CLI را حذف کنید.
Telegram:
- متن، context و dividerها را بهصورت متن رندر کنید.
- کنشها و select را وقتی برای سطح هدف پیکربندی و مجاز شدهاند، بهصورت صفحهکلیدهای inline رندر کنید.
- وقتی دکمههای inline غیرفعال هستند، از fallback متنی استفاده کنید.
- سنجاقکردن topic در ACP را به
delivery.pinمنتقل کنید.
Mattermost:
- کنشها را در جایی که پیکربندی شدهاند بهصورت دکمههای تعاملی رندر کنید.
- سایر بلوکها را بهصورت fallback متنی رندر کنید.
MS Teams:
presentationرا به Adaptive Cards رندر کنید.- کنشهای دستی pin/unpin/list-pins را نگه دارید.
- در صورت قابلاعتمادبودن پشتیبانی Graph برای گفتوگوی هدف، در صورت نیاز
pinDeliveredMessageرا پیادهسازی کنید.
Feishu:
presentationرا به کارتهای تعاملی رندر کنید.- کنشهای دستی pin/unpin/list-pins را نگه دارید.
- اگر رفتار API قابلاعتماد است، در صورت نیاز
pinDeliveredMessageرا برای سنجاقکردن پیام ارسالشده پیادهسازی کنید.
LINE:
presentationرا در صورت امکان به پیامهای Flex یا template رندر کنید.- برای بلوکهای پشتیبانینشده به متن fallback کنید.
- payloadهای رابط کاربری LINE را از
channelDataحذف کنید.
کانالهای ساده یا محدود:
- ارائه را با قالببندی محافظهکارانه به متن تبدیل کنید.
مراحل refactor
- fix انتشار Discord را دوباره اعمال کنید که
ui-colors.tsرا از رابط کاربری مبتنی بر Carbon جدا میکند وDiscordUiContainerرا ازextensions/discord/src/channel.tsحذف میکند. presentationوdeliveryرا بهReplyPayload، نرمالسازی payload خروجی، خلاصههای تحویل، و payloadهای hook اضافه کنید.- schema و helperهای parser مربوط به
MessagePresentationرا در یک subpath محدود SDK/runtime اضافه کنید. - قابلیتهای پیام
buttons،cards،componentsوblocksرا با قابلیتهای ارائه معنایی جایگزین کنید. - hookهای adapter خروجی زمان اجرا را برای رندر ارائه و سنجاقکردن تحویل اضافه کنید.
- ساخت component میانبافتی را با
buildCrossContextPresentationجایگزین کنید. src/infra/outbound/channel-adapters.tsرا حذف کنید وbuildCrossContextComponentsرا از نوعهای Plugin کانال بردارید.maybeApplyCrossContextMarkerرا تغییر دهید تا بهجای پارامترهای بومی،presentationرا attach کند.- مسیرهای ارسال plugin-dispatch را بهروزرسانی کنید تا فقط ارائه معنایی و metadata تحویل را مصرف کنند.
- پارامترهای payload بومی عامل و CLI را حذف کنید:
components،blocks،buttonsوcard. - helperهای SDK را که schemaهای ابزار پیام بومی میسازند حذف کنید و آنها را با helperهای schema ارائه جایگزین کنید.
- envelopeهای رابط کاربری/بومی را از
channelDataحذف کنید؛ تا زمانی که هر فیلد باقیمانده بررسی شود، فقط metadata مربوط به transport را نگه دارید. - رندرکنندههای Discord، Slack، Telegram، Mattermost، MS Teams، Feishu و LINE را مهاجرت دهید.
- مستندات CLI پیام، صفحههای کانال، Plugin SDK و cookbook قابلیت را بهروزرسانی کنید.
- برای Discord و entrypointهای کانالهای تحتتأثیر، profiling مربوط به fanout import را اجرا کنید.
مراحل 1 تا 11 و 13 تا 14 در این refactor برای قراردادهای عامل مشترک، CLI، قابلیت Plugin و adapter خروجی پیادهسازی شدهاند. مرحله 12 همچنان یک pass پاکسازی داخلی عمیقتر برای envelopeهای transport خصوصی ارائهدهنده در channelData باقی میماند. مرحله 15 اگر فراتر از gate نوع/تست، عددهای کمی fanout import بخواهیم، بهعنوان اعتبارسنجی بعدی باقی میماند.
تستها
اضافه یا بهروزرسانی کنید:
- تستهای نرمالسازی ارائه.
- تستهای تنزل خودکار ارائه برای بلوکهای پشتیبانینشده.
- تستهای marker میانبافتی برای مسیرهای plugin dispatch و تحویل هسته.
- تستهای ماتریس رندر کانال برای Discord، Slack، Telegram، Mattermost، MS Teams، Feishu، LINE و fallback متنی.
- تستهای schema ابزار پیام که ثابت میکنند فیلدهای بومی حذف شدهاند.
- تستهای CLI که ثابت میکنند flagهای بومی حذف شدهاند.
- regression مربوط به تنبلی import در entrypoint Discord که Carbon را پوشش میدهد.
- تستهای سنجاقکردن تحویل که Telegram و fallback عمومی را پوشش میدهند.
پرسشهای باز
- آیا
delivery.pinباید در گذر نخست برای Discord، Slack، MS Teams و Feishu پیادهسازی شود، یا ابتدا فقط برای Telegram؟ - آیا
deliveryدر نهایت باید فیلدهای موجود مانندreplyToId،replyToCurrent،silentوaudioAsVoiceرا هم جذب کند، یا روی رفتارهای پس از ارسال متمرکز بماند؟ - آیا ارائه باید مستقیما از تصویرها یا ارجاعهای فایل پشتیبانی کند، یا رسانه فعلا باید جدا از layout رابط کاربری باقی بماند؟