Skip to content

Chat modality in the shared Rust core: coverage vs. the native hosts (follow-up to #326) #428

Description

@filvecchiato

cc @TarikGul @decrypto21

Not sure if this can help you checking implementation. Feel free to ignore.

Follow-up review of #326 ("feat: integrate the Chat modality with the shared Rust core"), answering one question: does the shared core now implement the chat modality the hosts serve natively today?

Verdict: yes, with two exceptionsregister_bot is not implemented, and the native adapter accepts only 2 of the 7 message content types.

Reference for "natively available": triangle-js-sdks/packages/host-api-wrapper/src/chat.ts (what chat products call today), the slots the iOS host fills (Packages/Products/.../Resources/container.js:3757-3770), and ProductsNativeApiProtocol (ProductsNativeApi.swift:25-27).

Method-by-method

Legacy native call In the core after #326
registerRoomchat_create_room ChatPlatform::create_room → native createRoom; New/Exists idempotency, refreshes the room list on New (native.rs, ChatCallbackPlatform)
subscribeChatListchat_list_subscribe subscribe_rooms + notifyChatRoomsChanged push
sendMessagechat_post_message ⚠️ implemented, but the adapter maps only Text and Custom. RichText / Actions / File / Reaction / ReactionRemoved return Unknown { reason: "native Chat adapter supports text and custom messages" }. This is the existing native ceiling — iOS's ProductBotMessage is .text/.custom only — so it is parity, but now expressed as a runtime error rather than a type-level absence.
subscribeActionchat_action_subscribe ✅ connection-scoped stream, 64-item pre-subscribe buffer, FIFO drain, per-connection isolation (runtime/chat.rs); native pushes via publishChatAction. All three payloads (MessagePosted, ActionTriggered, Command) are representable; the committed iOS diagnosis exercises MessagePosted plus !diagnose as a command through the worker.
onCustomMessageRenderingRequest ✅ reshaped into a typed host-initiated request/response stream (#[wire(host_initiated, start_id = 52)]), driven natively by renderCustomMessage + NativeCustomRendererObserver. Wire ids and SCALE encoding preserved, with fixture tests asserting byte-identical legacy encoding in both directions, including the Component<P> → inline-variant flattening of CustomRendererNode.
registerBotchat_register_bot not implemented. No ChatPlatform / NativeChatCallbacks hook; only the generated dispatcher references it, so it falls through to the trait default CallError::unavailable() (still true at HEAD). Not a regression — iOS's container already left host_chat_register_bot as a not-implemented slot — but a product using the legacy wrapper's registerBot() still gets an error.

Beyond parity the PR adds ProductExecutionKind::{Spa,Chat} with generated dispatcher filtering (SPA connections get Denied on every Chat method), uniffi derives across the whole chat + custom-renderer type set so renderer trees cross into Swift/Kotlin as typed values, a chat-only playground worker, and a committed iOS diagnosis at 5 success / 0 failed (explorer/diagnosis-reports/chat/ios.md).

Where it is actually reachable

  • iOS — complete: ChatHostBridge + openProductExecution(bridge:chat:), publishChatAction, renderCustomMessage, notifyChatRoomsChanged; diagnosis green. The host half (paritytech/polkadot-app-ios-v2#1310) is still open, so the path is not live in the app yet.
  • Android — plumbing only: TrUAPIHost.kt gained the ProductExecutionKind enum and a RuntimeConfig.executionKind field. No chat callback surface in the Kotlin wrapper (still NativeTrUApiCore), no Android chat diagnosis report. Android's native chat cannot be driven through the core.
  • Desktop / web / dotli — plumbing only: executionKind on ProductRuntimeConfig in @parity/truapi-host. There is no chat code in js/packages/truapi-host/src, so Chat resolves to Unsupported.

Out of scope entirely

The richer native chat surface documented in the hosts — attachments/upload with BlurHash thumbnails, WebRTC calls, reactions, contacts, chat requests, drafts, message history/pagination — has no core representation.

Worth flagging separately: a product still has no way to read messages. There is a room-list subscription but no message-history method, so a product only sees actions from the moment it subscribes, plus the 64-item buffer.

Suggested follow-ups

  1. Decide register_bot's fate — either add a ChatPlatform hook and implement it natively, or drop it from the trait so it stops advertising a method no host serves.
  2. Android chat callback surface in TrUAPIHost.kt + a chat/android.md diagnosis report.
  3. Decide whether desktop/web get Chat at all; if not, say so explicitly in the docs rather than leaving executionKind: Chat acceptable but non-functional.
  4. Either widen the native adapter to the remaining ChatMessageContent variants or narrow what the protocol advertises for the native path.
  5. Message history / pagination as its own protocol design discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions