Skip to content

finding(plugin-chatbot): per-message avatar / avatarFallback work end to end but no authoring-facing type declares them — #4424's RuntimeOnlyMessageKeys picked only three keys #7295

Description

@yinlianghui

Found while covering content/docs/plugins/plugin-chatbot.mdx for #5174 batch 5 (PR #7294). Filed unassigned and not fixed there — that PR's surface is the UNGATED_DOCS ledger plus three doc pages, and this is a package type.

What

Authoring a chatbot node with a per-message avatar override works, all the way through:

  • Chatbot resolves it: message.avatarFallback || userAvatarFallback and message.avatar || userAvatarUrlpackages/plugin-chatbot/src/index.tsx:177-178.
  • The authoring-to-runtime seam carries it: authoredToRuntimeMessage destructures only role / timestamp / toolInvocations and spreads the rest (...passthrough) — packages/plugin-chatbot/src/chatMessageAdapter.ts:256-262.
  • The SDUI renderer feeds it: toRuntimeMessages(messages) into Chatbotpackages/plugin-chatbot/src/renderer.tsx.

But no type an author can name declares those two keys.

type declares avatar / avatarFallback?
ChatMessage from @object-ui/types (what ChatbotSchema.messages is typed as) no
SeamChatMessage from @object-ui/plugin-chatbot noRuntimeOnlyMessageKeys is Pick(RuntimeChatMessage, 'buildProgress' or 'blueprintProgress' or 'charts')
ChatMessage from @object-ui/plugin-chatbot (the runtime shape) yes

So ChatbotSchema.messages is ChatMessage[] from @object-ui/types, and that interface has no index signature — an author who annotates their schema gets TS2353: 'avatarFallback' does not exist in type 'ChatMessage' on a value that renders correctly.

Measured

With the four example schemas on content/docs/plugins/plugin-chatbot.mdx annotated ChatbotSchema, the doc-snippet gate reports exactly five of these, one per documented per-message avatar:

plugin-chatbot.mdx:326:7  TS2353: Object literal may only specify known properties, and 'avatarFallback' does not exist in type 'ChatMessage'.
plugin-chatbot.mdx:350:7  TS2353: ... 'avatarFallback' ...
plugin-chatbot.mdx:376:7  TS2353: ... 'avatarFallback' ...
plugin-chatbot.mdx:382:7  TS2353: ... 'avatarFallback' ...
plugin-chatbot.mdx:393:7  TS2353: ... 'avatarFallback' ...

PR #7294 therefore leaves those three example blocks unannotated rather than deleting working, documented behaviour to satisfy a checker. That is a deliberate hole in that page's gate coverage, and it closes when this is decided.

Why it is worth a card rather than a shrug

This is the residue of #4424, which is the card that introduced SeamChatMessage and named the render-only keys. It picked buildProgress, blueprintProgress and charts — the keys API mode lifts out of the stream — and did not consider the two keys a human author writes by hand. The seam is otherwise exactly the mechanism that is supposed to make this expressible.

Related: #4383 (the barrel used to export two different ChatMessage types), #4399 (the as any this seam replaced), #6169 (the chatbot authoring surface becoming one named type).

Two readings, not resolved here

  1. The authoring contract should carry them. Add avatar?: string and avatarFallback?: string to @object-ui/types' ChatMessage, since a metadata author demonstrably writes them and the runtime honours them. Cheapest, and makes declared = enforced true again for this key pair.
  2. They are render-only and the seam should carry them. Widen RuntimeOnlyMessageKeys to include them, leaving the pure authoring contract narrow. This keeps @object-ui/types minimal but does not help the ChatbotSchema.messages author, who never names SeamChatMessage — so on its own it does not close the hole above.

Reading 1 is what the measured usage argues for; reading 2 is what the existing seam vocabulary argues for. Someone who owns the authoring contract should pick.

Reachability

Nothing breaks at runtime — the keys work today. The cost is type-level: a TypeScript author annotating their chatbot metadata is told a correct value is wrong, and a documentation page cannot be fully gate-covered.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanefindingpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions