Get started
Plan refaktoryzacji prezentacji kanałów
Status
Zaimplementowane dla współdzielonego agenta, CLI, możliwości Plugin oraz powierzchni dostarczania wychodzącego:
ReplyPayload.presentationprzenosi semantyczny interfejs wiadomości.ReplyPayload.delivery.pinprzenosi żądania przypięcia wysłanej wiadomości.- Współdzielone akcje wiadomości udostępniają
presentation,deliveryipinzamiast natywnych dla dostawcycomponents,blocks,buttonslubcard. - Rdzeń renderuje albo automatycznie degraduje prezentację przez zadeklarowane przez Plugin możliwości wychodzące.
- Renderery Discord, Slack, Telegram, Mattermost, MS Teams i Feishu używają ogólnego kontraktu.
- Kod płaszczyzny sterowania kanału Discord nie importuje już kontenerów UI opartych na Carbon.
Kanoniczna dokumentacja znajduje się teraz w Prezentacji wiadomości. Zachowaj ten plan jako historyczny kontekst implementacji; w przypadku zmian kontraktu, renderera lub zachowania awaryjnego aktualizuj kanoniczny przewodnik.
Problem
Interfejs kanałów jest obecnie podzielony między kilka niezgodnych powierzchni:
- Rdzeń posiada hak renderera międzykontekstowego o kształcie Discord przez
buildCrossContextComponents. - Discord
channel.tsmoże importować natywny UI Carbon przezDiscordUiContainer, co wciąga zależności UI czasu wykonania do płaszczyzny sterowania Plugin kanału. - Agent i CLI udostępniają natywne obejścia ładunku, takie jak Discord
components, Slackblocks, Telegram lub Mattermostbuttonsoraz Teams lub Feishucard. ReplyPayload.channelDataprzenosi zarówno wskazówki transportowe, jak i natywne koperty UI.- Ogólny model
interactiveistnieje, ale jest węższy niż bogatsze układy używane już przez Discord, Slack, Teams, Feishu, LINE, Telegram i Mattermost.
To sprawia, że rdzeń zna natywne kształty UI, osłabia leniwe ładowanie czasu wykonania Plugin i daje agentom zbyt wiele specyficznych dla dostawcy sposobów wyrażenia tego samego zamiaru wiadomości.
Cele
- Rdzeń wybiera najlepszą semantyczną prezentację wiadomości na podstawie zadeklarowanych możliwości.
- Rozszerzenia deklarują możliwości i renderują semantyczną prezentację do natywnych ładunków transportowych.
- Web Control UI pozostaje oddzielony od natywnego UI czatu.
- Natywne ładunki kanału nie są udostępniane przez współdzieloną powierzchnię wiadomości agenta ani CLI.
- Nieobsługiwane funkcje prezentacji automatycznie degradują do najlepszej reprezentacji tekstowej.
- Zachowanie dostarczania, takie jak przypięcie wysłanej wiadomości, jest ogólnymi metadanymi dostarczania, a nie prezentacją.
Poza zakresem
- Brak podkładki zgodności wstecznej dla
buildCrossContextComponents. - Brak publicznych natywnych obejść dla
components,blocks,buttonslubcard. - Brak importów natywnych bibliotek UI kanałów w rdzeniu.
- Brak specyficznych dla dostawcy szwów SDK dla dołączonych kanałów.
Model docelowy
Dodaj należące do rdzenia pole presentation do 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 staje się podzbiorem presentation podczas migracji:
- Blok tekstowy
interactivemapuje się napresentation.blocks[].type = "text". - Blok przycisków
interactivemapuje się napresentation.blocks[].type = "buttons". - Blok wyboru
interactivemapuje się napresentation.blocks[].type = "select".
Zewnętrzne schematy agenta i CLI używają teraz presentation; interactive pozostaje wewnętrznym starszym pomocnikiem parsowania/renderowania dla istniejących producentów odpowiedzi.
Metadane dostarczania
Dodaj należące do rdzenia pole delivery dla zachowania wysyłania, które nie jest UI.
type ReplyPayloadDelivery = {
pin?:
| boolean
| {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
};
Semantyka:
delivery.pin = trueoznacza przypięcie pierwszej pomyślnie dostarczonej wiadomości.notifydomyślnie ma wartośćfalse.requireddomyślnie ma wartośćfalse; nieobsługiwane kanały lub nieudane przypięcie automatycznie degradują przez kontynuowanie dostarczania.- Ręczne akcje wiadomości
pin,unpinilist-pinspozostają dla istniejących wiadomości.
Bieżące wiązanie tematu ACP Telegram powinno zostać przeniesione z channelData.telegram.pin = true do delivery.pin = true.
Kontrakt możliwości czasu wykonania
Dodaj haki renderowania prezentacji i dostarczania do adaptera wychodzącego czasu wykonania, a nie do Plugin kanału płaszczyzny sterowania.
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>;
};
Zachowanie rdzenia:
- Rozwiąż docelowy kanał i adapter czasu wykonania.
- Poproś o możliwości prezentacji.
- Zdegraduj nieobsługiwane bloki przed renderowaniem.
- Wywołaj
renderPresentation. - Jeśli renderer nie istnieje, przekonwertuj prezentację na tekst awaryjny.
- Po pomyślnym wysłaniu wywołaj
pinDeliveredMessage, gdydelivery.pinjest żądane i obsługiwane.
Mapowanie kanałów
Discord:
- Renderuj
presentationdo komponentów v2 i kontenerów Carbon w modułach wyłącznie czasu wykonania. - Zachowaj pomocniki kolorów akcentu w lekkich modułach.
- Usuń importy
DiscordUiContainerz kodu płaszczyzny sterowania Plugin kanału.
Slack:
- Renderuj
presentationdo Block Kit. - Usuń wejście agenta i CLI
blocks.
Telegram:
- Renderuj tekst, kontekst i dzielniki jako tekst.
- Renderuj akcje i wybór jako klawiatury inline, gdy są skonfigurowane i dozwolone dla docelowej powierzchni.
- Używaj tekstu awaryjnego, gdy przyciski inline są wyłączone.
- Przenieś przypinanie tematu ACP do
delivery.pin.
Mattermost:
- Renderuj akcje jako interaktywne przyciski, gdy są skonfigurowane.
- Renderuj inne bloki jako tekst awaryjny.
MS Teams:
- Renderuj
presentationdo Adaptive Cards. - Zachowaj ręczne akcje pin/unpin/list-pins.
- Opcjonalnie zaimplementuj
pinDeliveredMessage, jeśli obsługa Graph jest niezawodna dla docelowej konwersacji.
Feishu:
- Renderuj
presentationdo kart interaktywnych. - Zachowaj ręczne akcje pin/unpin/list-pins.
- Opcjonalnie zaimplementuj
pinDeliveredMessagedla przypinania wysłanych wiadomości, jeśli zachowanie API jest niezawodne.
LINE:
- Renderuj
presentationdo wiadomości Flex lub szablonowych tam, gdzie to możliwe. - Wróć do tekstu dla nieobsługiwanych bloków.
- Usuń ładunki UI LINE z
channelData.
Kanały zwykłe lub ograniczone:
- Konwertuj prezentację na tekst z zachowawczym formatowaniem.
Kroki refaktoryzacji
- Ponownie zastosuj poprawkę wydania Discord, która oddziela
ui-colors.tsod UI opartego na Carbon i usuwaDiscordUiContainerzextensions/discord/src/channel.ts. - Dodaj
presentationideliverydoReplyPayload, normalizacji ładunku wychodzącego, podsumowań dostarczania i ładunków haków. - Dodaj schemat
MessagePresentationi pomocniki parsera w wąskiej podścieżce SDK/czasu wykonania. - Zastąp możliwości wiadomości
buttons,cards,componentsiblockssemantycznymi możliwościami prezentacji. - Dodaj haki adaptera wychodzącego czasu wykonania dla renderowania prezentacji i przypinania dostarczania.
- Zastąp konstrukcję komponentów międzykontekstowych przez
buildCrossContextPresentation. - Usuń
src/infra/outbound/channel-adapters.tsi usuńbuildCrossContextComponentsz typów Plugin kanału. - Zmień
maybeApplyCrossContextMarker, aby dołączałpresentationzamiast natywnych parametrów. - Zaktualizuj ścieżki wysyłania plugin-dispatch, aby używały wyłącznie semantycznej prezentacji i metadanych dostarczania.
- Usuń natywne parametry ładunku agenta i CLI:
components,blocks,buttonsicard. - Usuń pomocniki SDK tworzące natywne schematy narzędzi wiadomości, zastępując je pomocnikami schematu prezentacji.
- Usuń koperty UI/natywne z
channelData; zachowaj wyłącznie metadane transportowe, dopóki każde pozostałe pole nie zostanie przejrzane. - Zmigruj renderery Discord, Slack, Telegram, Mattermost, MS Teams, Feishu i LINE.
- Zaktualizuj dokumentację dla CLI wiadomości, stron kanałów, SDK Plugin i cookbooka możliwości.
- Uruchom profilowanie fanoutu importów dla Discord i dotkniętych punktów wejścia kanałów.
Kroki 1-11 i 13-14 są zaimplementowane w tej refaktoryzacji dla kontraktów współdzielonego agenta, CLI, możliwości Plugin i adaptera wychodzącego. Krok 12 pozostaje głębszym wewnętrznym przebiegiem czyszczenia dla prywatnych dla dostawcy kopert transportowych channelData. Krok 15 pozostaje walidacją następczą, jeśli chcemy ilościowych danych o fanoucie importów wykraczających poza bramkę typów/testów.
Testy
Dodaj lub zaktualizuj:
- Testy normalizacji prezentacji.
- Testy automatycznej degradacji prezentacji dla nieobsługiwanych bloków.
- Testy znaczników międzykontekstowych dla ścieżek plugin dispatch i dostarczania rdzenia.
- Testy macierzy renderowania kanałów dla Discord, Slack, Telegram, Mattermost, MS Teams, Feishu, LINE i tekstu awaryjnego.
- Testy schematu narzędzia wiadomości dowodzące, że natywne pola zostały usunięte.
- Testy CLI dowodzące, że natywne flagi zostały usunięte.
- Regresja leniwości importu punktu wejścia Discord obejmująca Carbon.
- Testy przypinania dostarczania obejmujące Telegram i ogólny tryb awaryjny.
Otwarte pytania
- Czy
delivery.pinpowinno zostać zaimplementowane dla Discord, Slack, MS Teams i Feishu w pierwszym przebiegu, czy najpierw tylko dla Telegram? - Czy
deliverypowinno ostatecznie wchłonąć istniejące pola, takie jakreplyToId,replyToCurrent,silentiaudioAsVoice, czy pozostać skupione na zachowaniach po wysłaniu? - Czy prezentacja powinna obsługiwać bezpośrednio obrazy lub odwołania do plików, czy media powinny na razie pozostać oddzielone od układu UI?