상태
공유 에이전트, CLI, Plugin capability, 아웃바운드 전달 표면에 대해 구현 완료:ReplyPayload.presentation이 시맨틱 메시지 UI를 전달합니다.ReplyPayload.delivery.pin이 전송된 메시지 pin 요청을 전달합니다.- 공유 메시지 action은 provider 네이티브
components,blocks,buttons,card대신presentation,delivery,pin을 노출합니다. - 코어는 Plugin이 선언한 아웃바운드 capability를 통해 presentation을 렌더링하거나 자동으로 degrade합니다.
- Discord, Slack, Telegram, Mattermost, MS Teams, Feishu 렌더러가 일반 계약을 소비합니다.
- Discord 채널 control-plane 코드는 더 이상 Carbon 기반 UI 컨테이너를 import하지 않습니다.
문제
채널 UI는 현재 서로 호환되지 않는 여러 표면으로 나뉘어 있습니다.- 코어는
buildCrossContextComponents를 통해 Discord 형태의 교차 컨텍스트 렌더러 Hook을 소유합니다. - Discord
channel.ts는DiscordUiContainer를 통해 네이티브 Carbon UI를 import할 수 있어, 채널 Plugin control plane으로 런타임 UI 의존성을 끌어옵니다. - 에이전트와 CLI는 Discord
components, Slackblocks, Telegram 또는 Mattermostbuttons, Teams 또는 Feishucard같은 네이티브 페이로드 escape hatch를 노출합니다. ReplyPayload.channelData는 전송 힌트와 네이티브 UI envelope를 모두 담고 있습니다.- 일반
interactive모델은 존재하지만, Discord, Slack, Teams, Feishu, LINE, Telegram, Mattermost에서 이미 사용 중인 더 풍부한 레이아웃보다는 범위가 좁습니다.
목표
- 코어가 선언된 capability로부터 메시지에 대한 최적의 시맨틱 프레젠테이션을 결정합니다.
- extension은 capability를 선언하고 시맨틱 프레젠테이션을 네이티브 전송 페이로드로 렌더링합니다.
- 웹 Control UI는 채팅 네이티브 UI와 분리된 상태를 유지합니다.
- 네이티브 채널 페이로드는 공유 에이전트나 CLI 메시지 표면을 통해 노출되지 않습니다.
- 지원되지 않는 presentation 기능은 자동으로 최적의 텍스트 표현으로 degrade됩니다.
- 전송된 메시지 pinning 같은 전달 동작은 presentation이 아니라 일반적인 전달 메타데이터입니다.
비목표
buildCrossContextComponents에 대한 하위 호환 shim 없음.components,blocks,buttons,card에 대한 공개 네이티브 escape hatch 없음.- 코어에서 채널 네이티브 UI 라이브러리 import 없음.
- 번들 채널에 대한 provider별 SDK seam 없음.
목표 모델
코어 소유presentation 필드를 ReplyPayload에 추가합니다.
interactive는 presentation의 하위 집합이 됩니다.
interactive텍스트 블록은presentation.blocks[].type = "text"로 매핑됩니다.interactive버튼 블록은presentation.blocks[].type = "buttons"로 매핑됩니다.interactiveselect 블록은presentation.blocks[].type = "select"로 매핑됩니다.
presentation을 사용합니다. interactive는 기존 reply producer를 위한 내부 레거시 parser/rendering helper로 남습니다.
전달 메타데이터
UI가 아닌 전송 동작을 위한 코어 소유delivery 필드를 추가합니다.
delivery.pin = true는 첫 번째로 성공적으로 전달된 메시지를 pin하라는 뜻입니다.notify의 기본값은false입니다.required의 기본값은false이며, 지원되지 않는 채널 또는 pinning 실패는 전달을 계속하면서 자동으로 degrade됩니다.- 수동
pin,unpin,list-pins메시지 action은 기존 메시지에 대해 그대로 유지됩니다.
channelData.telegram.pin = true에서 delivery.pin = true로 이동해야 합니다.
런타임 capability 계약
presentation 및 delivery 렌더 Hook을 control-plane 채널 Plugin이 아니라 런타임 아웃바운드 어댑터에 추가합니다.- 대상 채널과 런타임 어댑터를 확인합니다.
- presentation capability를 요청합니다.
- 지원되지 않는 블록을 렌더링 전에 degrade합니다.
renderPresentation을 호출합니다.- 렌더러가 없으면 presentation을 텍스트 fallback으로 변환합니다.
- 전송 성공 후
delivery.pin이 요청되고 지원되면pinDeliveredMessage를 호출합니다.
채널 매핑
Discord:presentation을 런타임 전용 모듈에서 components v2와 Carbon 컨테이너로 렌더링합니다.- accent color helper는 가벼운 모듈에 유지합니다.
- 채널 Plugin control-plane 코드에서
DiscordUiContainerimport를 제거합니다.
presentation을 Block Kit으로 렌더링합니다.- 에이전트와 CLI의
blocks입력을 제거합니다.
- 텍스트, context, divider를 텍스트로 렌더링합니다.
- action과 select는 대상 표면에서 구성 및 허용된 경우 inline keyboard로 렌더링합니다.
- inline button이 비활성화되어 있으면 텍스트 fallback을 사용합니다.
- ACP topic pinning을
delivery.pin으로 이동합니다.
- action을 구성된 경우 대화형 버튼으로 렌더링합니다.
- 다른 블록은 텍스트 fallback으로 렌더링합니다.
presentation을 Adaptive Cards로 렌더링합니다.- 수동 pin/unpin/list-pins action은 유지합니다.
- 대상 대화에서 Graph 지원이 신뢰할 수 있다면
pinDeliveredMessage를 선택적으로 구현합니다.
presentation을 interactive cards로 렌더링합니다.- 수동 pin/unpin/list-pins action은 유지합니다.
- API 동작이 신뢰할 수 있다면 전송된 메시지 pinning용
pinDeliveredMessage를 선택적으로 구현합니다.
- 가능한 경우
presentation을 Flex 또는 template message로 렌더링합니다. - 지원되지 않는 블록은 텍스트로 fallback합니다.
- LINE UI 페이로드를
channelData에서 제거합니다.
- presentation을 보수적인 서식의 텍스트로 변환합니다.
리팩터링 단계
ui-colors.ts를 Carbon 기반 UI에서 분리하고extensions/discord/src/channel.ts에서DiscordUiContainer를 제거하는 Discord 릴리스 수정을 다시 적용합니다.ReplyPayload, 아웃바운드 페이로드 정규화, 전달 요약, Hook 페이로드에presentation과delivery를 추가합니다.- 좁은 SDK/런타임 하위 경로에
MessagePresentation스키마와 parser helper를 추가합니다. - 메시지 capability
buttons,cards,components,blocks를 시맨틱 presentation capability로 대체합니다. - presentation 렌더와 delivery pinning을 위한 런타임 아웃바운드 어댑터 Hook을 추가합니다.
- 교차 컨텍스트 component 구성을
buildCrossContextPresentation으로 대체합니다. src/infra/outbound/channel-adapters.ts를 삭제하고 채널 Plugin 타입에서buildCrossContextComponents를 제거합니다.maybeApplyCrossContextMarker가 네이티브 params 대신presentation을 첨부하도록 변경합니다.- Plugin-dispatch send 경로가 시맨틱 presentation과 delivery 메타데이터만 소비하도록 업데이트합니다.
- 에이전트와 CLI의 네이티브 페이로드 params
components,blocks,buttons,card를 제거합니다. - 네이티브 message-tool 스키마를 생성하던 SDK helper를 제거하고, 이를 presentation 스키마 helper로 대체합니다.
channelData에서 UI/네이티브 envelope를 제거하고, 남은 각 필드가 검토될 때까지 전송 메타데이터만 유지합니다.- Discord, Slack, Telegram, Mattermost, MS Teams, Feishu, LINE 렌더러를 마이그레이션합니다.
- 메시지 CLI, 채널 페이지, Plugin SDK, capability cookbook 문서를 업데이트합니다.
- Discord 및 영향받는 채널 entrypoint에 대한 import fanout profiling을 실행합니다.
channelData 전송 envelope에 대한 더 깊은 내부 정리 작업으로 남아 있습니다. 15단계는 타입/테스트 게이트를 넘어 import-fanout 수치를 정량화하고 싶을 때의 후속 검증으로 남아 있습니다.
테스트
다음을 추가하거나 업데이트합니다.- Presentation 정규화 테스트
- 지원되지 않는 블록에 대한 presentation 자동 degrade 테스트
- Plugin dispatch 및 코어 전달 경로에 대한 교차 컨텍스트 마커 테스트
- Discord, Slack, Telegram, Mattermost, MS Teams, Feishu, LINE, 텍스트 fallback에 대한 채널 렌더 매트릭스 테스트
- 네이티브 필드가 제거되었음을 증명하는 메시지 도구 스키마 테스트
- 네이티브 플래그가 제거되었음을 증명하는 CLI 테스트
- Carbon을 다루는 Discord entrypoint import 지연성 회귀 테스트
- Telegram 및 일반 fallback을 다루는 delivery pin 테스트
열린 질문
- 첫 번째 단계에서
delivery.pin을 Discord, Slack, MS Teams, Feishu에 구현해야 할까요, 아니면 Telegram만 먼저 해야 할까요? delivery가 결국replyToId,replyToCurrent,silent,audioAsVoice같은 기존 필드도 흡수해야 할까요, 아니면 post-send 동작에만 집중해야 할까요?- presentation이 이미지나 파일 참조를 직접 지원해야 할까요, 아니면 지금은 미디어를 UI 레이아웃과 분리된 상태로 유지해야 할까요?