Get started
برنامه بازآرایی ارائه کانال
وضعیت
برای عامل مشترک، CLI، قابلیت Plugin و سطوح تحویل خروجی پیادهسازی شده است:
ReplyPayload.presentationرابط کاربری معنایی پیام را حمل میکند.ReplyPayload.delivery.pinدرخواستهای سنجاقکردن پیام ارسالشده را حمل میکند.- کنشهای مشترک پیام بهجای
components،blocks،buttonsیاcardبومی ارائهدهنده،presentation،deliveryوpinرا آشکار میکنند. - هسته ارائه را از طریق قابلیتهای خروجی اعلامشده توسط Plugin رندر میکند یا بهصورت خودکار تنزل میدهد.
- رندرکنندههای Discord، Slack، Telegram، Mattermost، Microsoft Teams و Feishu قرارداد عمومی را مصرف میکنند.
- کد صفحه کنترل کانال Discord دیگر کانتینرهای رابط کاربری مبتنی بر Carbon را import نمیکند.
مستندات مرجع اکنون در ارائه پیام قرار دارند. این طرح را بهعنوان زمینه تاریخی پیادهسازی نگه دارید؛ برای تغییرات قرارداد، رندرکننده یا رفتار جایگزین، راهنمای مرجع را بهروزرسانی کنید.
مسئله
رابط کاربری کانال در حال حاضر میان چند سطح ناسازگار تقسیم شده است:
- هسته از طریق
buildCrossContextComponentsمالک یک hook رندرکننده میانزمینهای با شکل Discord است. channel.tsمربوط به Discord میتواند از طریقDiscordUiContainerرابط کاربری بومی Carbon را import کند، که وابستگیهای رابط کاربری زمان اجرا را وارد صفحه کنترل Plugin کانال میکند.- عامل و CLI راههای فرار payload بومی مانند
componentsدر Discord،blocksدر Slack،buttonsدر Telegram یا Mattermost، وcardدر Microsoft Teams یا Feishu را آشکار میکنند. ReplyPayload.channelDataهم راهنماییهای انتقال و هم پوششهای رابط کاربری بومی را حمل میکند.- مدل عمومی
interactiveوجود دارد، اما از چیدمانهای غنیتری که هماکنون توسط Discord، Slack، Microsoft Teams، Feishu، LINE، Telegram و Mattermost استفاده میشوند محدودتر است.
این وضعیت باعث میشود هسته از شکلهای رابط کاربری بومی آگاه باشد، تنبلی زمان اجرای Plugin را تضعیف میکند، و به عاملها راههای بیش از حد ارائهدهندهمحور برای بیان نیت یکسان پیام میدهد.
اهداف
- هسته بهترین ارائه معنایی را برای یک پیام بر اساس قابلیتهای اعلامشده تصمیمگیری میکند.
- افزونهها قابلیتها را اعلام میکنند و ارائه معنایی را به payloadهای انتقال بومی رندر میکنند.
- رابط کاربری کنترل وب از رابط کاربری بومی چت جدا میماند.
- payloadهای بومی کانال از طریق سطح پیام مشترک عامل یا CLI آشکار نمیشوند.
- ویژگیهای ارائه پشتیبانینشده بهصورت خودکار به بهترین نمایش متنی تنزل مییابند.
- رفتار تحویل مانند سنجاقکردن یک پیام ارسالشده، فراداده عمومی تحویل است، نه ارائه.
غیرهدفها
- هیچ shim سازگاری عقبرو برای
buildCrossContextComponentsوجود ندارد. - هیچ راه فرار بومی عمومی برای
components،blocks،buttonsیاcardوجود ندارد. - هیچ import هستهای از کتابخانههای رابط کاربری بومی کانال وجود ندارد.
- هیچ سطح SDK ویژه ارائهدهنده برای کانالهای بستهبندیشده وجود ندارد.
مدل هدف
یک فیلد 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/rendering قدیمی داخلی برای تولیدکنندگان پاسخ موجود باقی میماند.
API عمومی روبهروی تولیدکننده، interactive را منسوخشده تلقی میکند. پشتیبانی زمان اجرا
باقی میماند تا کمکگیرندههای تأیید موجود و Pluginهای قدیمیتر همچنان کار کنند،
در حالی که کد جدید presentation منتشر میکند.
فراداده تحویل
یک فیلد delivery تحت مالکیت هسته برای رفتار ارسال که رابط کاربری نیست اضافه کنید.
type ReplyPayloadDelivery = { pin?: | boolean | { enabled: boolean; notify?: boolean; required?: boolean; };};معناشناسی:
delivery.pin = trueیعنی نخستین پیام با تحویل موفق سنجاق شود.- مقدار پیشفرض
notifyبرابرfalseاست. - مقدار پیشفرض
requiredبرابرfalseاست؛ کانالهای پشتیبانینشده یا شکست در سنجاقکردن با ادامه تحویل بهصورت خودکار تنزل مییابند. - کنشهای پیام دستی
pin،unpinوlist-pinsبرای پیامهای موجود باقی میمانند.
اتصال topic فعلی ACP در Telegram باید از channelData.telegram.pin = true به delivery.pin = true منتقل شود.
قرارداد قابلیت زمان اجرا
hookهای رندر ارائه و تحویل را به سازگارگر خروجی زمان اجرا اضافه کنید، نه به Plugin کانال صفحه کنترل.
type ChannelPresentationCapabilities = { supported: boolean; buttons?: boolean; selects?: boolean; context?: boolean; divider?: boolean; tones?: MessagePresentationTone[]; limits?: { actions?: { maxActions?: number; maxActionsPerRow?: number; maxRows?: number; maxLabelLength?: number; maxValueBytes?: number; supportsStyles?: boolean; supportsDisabled?: boolean; supportsLayoutHints?: boolean; }; selects?: { maxOptions?: number; maxLabelLength?: number; maxValueBytes?: number; }; text?: { maxLength?: number; encoding?: "characters" | "utf8-bytes" | "utf16-units"; markdownDialect?: "plain" | "markdown" | "html" | "slack-mrkdwn" | "discord-markdown"; supportsEdit?: boolean; }; };}; 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>;};رفتار هسته:
- کانال هدف و سازگارگر زمان اجرا را resolve کنید.
- قابلیتهای ارائه را درخواست کنید.
- پیش از رندر، بلوکهای پشتیبانینشده را تنزل دهید و محدودیتهای عمومی قابلیت را اعمال کنید.
renderPresentationرا فراخوانی کنید.- اگر رندرکنندهای وجود ندارد، ارائه را به متن جایگزین تبدیل کنید.
- پس از ارسال موفق، وقتی
delivery.pinدرخواست شده و پشتیبانی میشود،pinDeliveredMessageرا فراخوانی کنید.
نگاشت کانال
Discord:
presentationرا به components v2 و کانتینرهای Carbon در ماژولهای فقط زمان اجرا رندر کنید.- کمکگیرندههای رنگ accent را در ماژولهای سبک نگه دارید.
- importهای
DiscordUiContainerرا از کد صفحه کنترل Plugin کانال حذف کنید.
Slack:
presentationرا به Block Kit رندر کنید.- ورودی
blocksعامل و CLI را حذف کنید.
Telegram:
- متن، زمینه و جداکنندهها را بهصورت متن رندر کنید.
- وقتی برای سطح هدف پیکربندی و مجاز شده باشد، کنشها و انتخاب را بهصورت صفحهکلیدهای inline رندر کنید.
- وقتی دکمههای inline غیرفعال هستند، از متن جایگزین استفاده کنید.
- سنجاقکردن topic مربوط به ACP را به
delivery.pinمنتقل کنید.
Mattermost:
- کنشها را در صورت پیکربندی، بهصورت دکمههای تعاملی رندر کنید.
- بلوکهای دیگر را بهصورت متن جایگزین رندر کنید.
Microsoft Teams:
presentationرا به Adaptive Cards رندر کنید.- کنشهای دستی pin/unpin/list-pins را نگه دارید.
- اگر پشتیبانی Graph برای گفتوگوی هدف قابل اتکا است، بهصورت اختیاری
pinDeliveredMessageرا پیادهسازی کنید.
Feishu:
presentationرا به کارتهای تعاملی رندر کنید.- کنشهای دستی pin/unpin/list-pins را نگه دارید.
- اگر رفتار API قابل اتکا است، بهصورت اختیاری
pinDeliveredMessageرا برای سنجاقکردن پیام ارسالشده پیادهسازی کنید.
LINE:
- در صورت امکان،
presentationرا به پیامهای Flex یا template رندر کنید. - برای بلوکهای پشتیبانینشده به متن بازگردید.
- payloadهای رابط کاربری LINE را از
channelDataحذف کنید.
کانالهای ساده یا محدود:
- ارائه را با قالببندی محافظهکارانه به متن تبدیل کنید.
مراحل بازآرایی
- اصلاح انتشار Discord را دوباره اعمال کنید که
ui-colors.tsرا از رابط کاربری مبتنی بر Carbon جدا میکند وDiscordUiContainerرا ازextensions/discord/src/channel.tsحذف میکند. presentationوdeliveryرا بهReplyPayload، عادیسازی payload خروجی، خلاصههای تحویل و payloadهای hook اضافه کنید.- schema و کمکگیرندههای parser مربوط به
MessagePresentationرا در یک زیرمسیر محدود SDK/زمان اجرا اضافه کنید. - قابلیتهای پیام
buttons،cards،componentsوblocksرا با قابلیتهای ارائه معنایی جایگزین کنید. - hookهای سازگارگر خروجی زمان اجرا را برای رندر ارائه و سنجاقکردن تحویل اضافه کنید.
- ساخت مؤلفه میانزمینهای را با
buildCrossContextPresentationجایگزین کنید. src/infra/outbound/channel-adapters.tsرا حذف کنید وbuildCrossContextComponentsرا از types مربوط به Plugin کانال بردارید.maybeApplyCrossContextMarkerرا تغییر دهید تا بهجای پارامترهای بومی،presentationرا الصاق کند.- مسیرهای ارسال plugin-dispatch را بهروزرسانی کنید تا فقط ارائه معنایی و فراداده تحویل را مصرف کنند.
- پارامترهای payload بومی عامل و CLI را حذف کنید:
components،blocks،buttonsوcard. - کمکگیرندههای SDK را که schemaهای ابزار پیام بومی میسازند حذف کنید و آنها را با کمکگیرندههای schema ارائه جایگزین کنید.
- پوششهای رابط کاربری/بومی را از
channelDataحذف کنید؛ فقط فراداده انتقال را تا زمان بازبینی هر فیلد باقیمانده نگه دارید. - رندرکنندههای Discord، Slack، Telegram، Mattermost، Microsoft Teams، Feishu و LINE را مهاجرت دهید.
- مستندات CLI پیام، صفحههای کانال، SDK مربوط به Plugin و cookbook قابلیت را بهروزرسانی کنید.
- برای Discord و entrypointهای کانال تحت تأثیر، پروفایلگیری fanout مربوط به import را اجرا کنید.
مراحل 1 تا 11 و 13 تا 14 در این بازآرایی برای عامل مشترک، CLI، قابلیت Plugin و قراردادهای سازگارگر خروجی پیادهسازی شدهاند. مرحله 12 همچنان یک گذر پاکسازی داخلی عمیقتر برای پوششهای انتقال channelData خصوصی ارائهدهنده باقی میماند. مرحله 15 اگر بخواهیم فراتر از gate نوع/تست، عددهای کمّی import-fanout داشته باشیم، اعتبارسنجی پیگیری محسوب میشود.
تستها
اضافه یا بهروزرسانی کنید:
- تستهای عادیسازی ارائه.
- تستهای تنزل خودکار ارائه برای بلوکهای پشتیبانینشده.
- تستهای نشانگر میانزمینهای برای plugin dispatch و مسیرهای تحویل هسته.
- تستهای ماتریس رندر کانال برای Discord، Slack، Telegram، Mattermost، Microsoft Teams، Feishu، LINE و متن جایگزین.
- تستهای schema ابزار پیام که ثابت میکنند فیلدهای بومی حذف شدهاند.
- تستهای CLI که ثابت میکنند flagهای بومی حذف شدهاند.
- رگرسیون تنبلی import مربوط به entrypoint در Discord که Carbon را پوشش میدهد.
- تستهای سنجاقکردن تحویل که Telegram و جایگزین عمومی را پوشش میدهند.
پرسشهای باز
- آیا
delivery.pinباید در گذر اول برای Discord، Slack، Microsoft Teams و Feishu پیادهسازی شود، یا ابتدا فقط Telegram؟ - آیا
deliveryدر نهایت باید فیلدهای موجود مانندreplyToId،replyToCurrent،silentوaudioAsVoiceرا جذب کند، یا روی رفتارهای پس از ارسال متمرکز بماند؟ - آیا ارائه باید مستقیماً از تصویرها یا ارجاعهای فایل پشتیبانی کند، یا فعلاً رسانه باید جدا از چیدمان رابط کاربری باقی بماند؟