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 || userAvatarUrl — packages/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 Chatbot — packages/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 | no — RuntimeOnlyMessageKeys 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
- 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. - 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.
Found while covering
content/docs/plugins/plugin-chatbot.mdxfor #5174 batch 5 (PR #7294). Filed unassigned and not fixed there — that PR's surface is theUNGATED_DOCSledger plus three doc pages, and this is a package type.What
Authoring a
chatbotnode with a per-message avatar override works, all the way through:Chatbotresolves it:message.avatarFallback || userAvatarFallbackandmessage.avatar || userAvatarUrl—packages/plugin-chatbot/src/index.tsx:177-178.authoredToRuntimeMessagedestructures onlyrole/timestamp/toolInvocationsand spreads the rest (...passthrough) —packages/plugin-chatbot/src/chatMessageAdapter.ts:256-262.toRuntimeMessages(messages)intoChatbot—packages/plugin-chatbot/src/renderer.tsx.But no type an author can name declares those two keys.
avatar/avatarFallback?ChatMessagefrom@object-ui/types(whatChatbotSchema.messagesis typed as)SeamChatMessagefrom@object-ui/plugin-chatbotRuntimeOnlyMessageKeysisPick(RuntimeChatMessage, 'buildProgress' or 'blueprintProgress' or 'charts')ChatMessagefrom@object-ui/plugin-chatbot(the runtime shape)So
ChatbotSchema.messagesisChatMessage[]from@object-ui/types, and that interface has no index signature — an author who annotates their schema getsTS2353: '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.mdxannotatedChatbotSchema, the doc-snippet gate reports exactly five of these, one per documented per-message avatar: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
SeamChatMessageand named the render-only keys. It pickedbuildProgress,blueprintProgressandcharts— 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
ChatMessagetypes), #4399 (theas anythis seam replaced), #6169 (thechatbotauthoring surface becoming one named type).Two readings, not resolved here
avatar?: stringandavatarFallback?: stringto@object-ui/types'ChatMessage, since a metadata author demonstrably writes them and the runtime honours them. Cheapest, and makesdeclared = enforcedtrue again for this key pair.RuntimeOnlyMessageKeysto include them, leaving the pure authoring contract narrow. This keeps@object-ui/typesminimal but does not help theChatbotSchema.messagesauthor, who never namesSeamChatMessage— 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.