Add IMessagePreambleRegistry extension point and IMessageMetadata interface#363
Conversation
|
Hi @brichet, other maintainers. Could you please give this a look? |
9a579c3 to
a88058c
Compare
… getter to Message class and subscribe preamble to changed signal
|
@jtpio updated the PR description with GIF showing multiple agents using Tool Call UI from jupyter-ai-contrib/jupyter-ai-acp-client#12 at the same time (also below). As you can see, each agent response gets its own message, so multiple concurrent agents maintain fully independent tool call timelines — each message's preamble re-renders only when its own tool_calls field changes. Tool call state is stored directly on each chat message ( |
There was a problem hiding this comment.
These changes look good to me. The message preamble makes a lot of sense since we already have a message footer. My only minor nitpick is that the naming convention is a bit awkward, but it makes sense given that the username & avatar is already the "header", so we should call this component the "preamble".
If I understand correctly, I think the main area of discussion concerns the addition of the tool_calls field to the message model. IMO, there are a few good reasons for us to add this:
-
Jupyter Chat's de facto purpose is to serve as a chat library for our AI extensions, i.e. Jupyter AI & JupyterLite AI. We should feel free to add general AI-relevant fields to the message model to make it easier for our extensions to append metadata to AI response messages. It may go unused by consumers, which is fine because empty keys occupy minimal memory/disk relative to the message contents.
-
The tool call object schema is well standardized now so we're not locking consumers into any specific implementation by adding the
tool_callsfield here. The required components of the schema are being used in LangChain and other AI libraries/providers. -
While we could add some extension point for making the message model configurable, this introduces several new design questions to work through. What happens if two different extensions need to each add fields to the message model? How can we still preserve type safety without just making the message an arbitrary dictionary? What happens if a user uninstalls an extension that adds a custom field, then opens an old chat file containing that custom field in its messages? IMO, the proposed approach of adding universally helpful but optional fields makes more sense pragmatically. We can update this in the future before the v1.0 release if needed.
packages/jupyter-chat/src/types.ts
Outdated
| export interface IToolCall { | ||
| tool_call_id: string; | ||
| title: string; | ||
| kind?: string; | ||
| status?: string; | ||
| raw_output?: unknown; | ||
| } |
There was a problem hiding this comment.
It may be good to add docstrings here to clarify the purpose of these fields. For example, title is the string shown to the user, kind helps indicate the type of action allowing consumers to switch icons, status is a string indicating the state of the tool call (i.e. success/failure), and raw_output is the output of the command.
packages/jupyter-chat/src/types.ts
Outdated
| export interface IToolCall { | ||
| tool_call_id: string; | ||
| title: string; | ||
| kind?: string; | ||
| status?: string; | ||
| raw_output?: unknown; | ||
| } |
There was a problem hiding this comment.
Also, right now, we're just showing the raw output, but eventually we may want to add an optional content field that provides a more human-friendly tool call UI for the user: https://agentclientprotocol.com/protocol/schema#toolcallcontent
|
Thanks @andrii-i for this PR, and for updating the screen cast. This looks good overall. I agree that the chat is currently mainly used for AI extensions, and that tool call is somewhat standardized (de facto, I don't think there is any official standard yet). Would there be any drawback to adding a generic |
|
Thanks for the thoughtful feedback, @brichet! To directly answer your question, there are a few drawbacks to
Potentially both approaches can coexist: typed fields for well-standardized concepts - which I believe tool calls to be - and metadata for everything else. |
Indeed, |
|
@andrii-i in jupyter-ai-contrib/jupyter-ai-acp-client#12 (which would consume this API), do you think it would be possible to quickly check what it would take to add support for more UI components than just tool calls? Since the screencasts show the Claude Agent is being used and Claude supports tasks lists (among others), maybe the task list component could be a good candidate? This would allow checking the API covers everything needed to allow further iterations in downstream implementations like |
|
Thanks @brichet and @SylvainCorlay. Updated the PR to follow the proposed generic metadata approach. Please give it another look now. |
|
@jtpio With the metadata update, extension authors only need to augment |
|
@jtpio For a working example of an extension adding a UI component, see the tool call UI component in jupyter-ai-contrib/jupyter-ai-acp-client#12 |
IToolCall type supportIMessagePreambleRegistry extension point and IMessageMetadata interface
There was a problem hiding this comment.
Tested and verified locally. Thanks for adding the metadata object & making the changes on the ACP client side Andrii.
@brichet Can you help merge & release this when you're back on Monday? Is there anything else to do before cutting another official v0.x release? Pre-release is fine if there are things pending.
|
I will cut a pre-release today. Also, as it may be related to this change, I started https://github.com/brichet/jupyter-chat-components, which currently includes a new mimetype that display tool call component, with approval/reject buttons. |
|
Thank you @brichet. |
|
TYSM! |

Description
Adds a message preamble registry (
IMessagePreambleRegistry) andIToolCalltype support tojupyter-chat.The preamble registry is an extension point that allows JupyterLab extensions to register React components rendered above the message body, after the header. It follows the same pattern as the existing footer registry (Token + interface + implementation + plugin), including the same
IMessageContent-based props signature. Components render vertically in insertion order. This enables downstream packages to plug UI into chat messages above the message body — for example, jupyter-ai-acp-client#12 uses it to display real-time tool call status for AI agent actions.Adds
IToolCallinterface andtool_calls?: IToolCall[]field onIMessageContent(TypeScript) andMessage(Python), providing first-class support for tool call metadata on chat messages.Tool Call UI (implementation) Preview
Preview from jupyter-ai-contrib/jupyter-ai-acp-client#12 that uses the message preamble registry:
Tests
Unit tests for the preamble registry covering: empty initialization, component addition, insertion order preservation, and defensive copy (mutating the returned array does not affect internal state).
Reviewer instructions
jlpm build, ensure compiles cleanjlpm test, ensure preamble registry tests passMessagePreambleComponentrenders between header and body inmessages.tsx. To test end-to-end, install jupyter-ai-acp-client#12 alongside this branch. jupyter-ai-devrepo can simplify the multi-repo setup.