Skip to content

Conversation

@kapetr
Copy link
Contributor

@kapetr kapetr commented Dec 2, 2025

Summary

Adds initial Canvas functionality to the UI

Linked Issues

Refs #168

Documentation

  • No Docs Needed:

Breaking changes

TS SDK

  • handleInputRequired -> resolveUserMetadata
  • InputRequiredResponses -> UserMetadataInputs

@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Dec 2, 2025
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @kapetr, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers the initial implementation of Canvas functionality, a significant new feature that allows for interactive content within the user interface. It encompasses updates across the Python and TypeScript SDKs to integrate the Canvas extension, alongside the development of new UI components for rendering, managing, and interacting with Canvas-based artifacts. Users can now select text within a Canvas and submit edit requests to the agent, enhancing the interactive experience.

Highlights

  • Initial Canvas Functionality: Introduced the foundational Canvas feature to the UI, enabling agents to interact with and modify rich content directly within the chat interface.
  • SDK Updates: Updated both Python and TypeScript SDKs to support the new Canvas extension, including new examples for code and recipe agents.
  • UI Components and Interaction: Added new UI components for displaying Canvas artifacts, managing their state, and allowing user interaction through text selection and editing requests.
  • Markdown Enhancements: Implemented markdown rendering enhancements to track source positions of content and enable a floating toolbar for selected text within Canvas artifacts.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request introduces initial Canvas functionality to the UI, which involves significant changes across both Python SDK examples and the TypeScript UI. Key updates include new UI components for displaying and interacting with canvas artifacts, a mechanism to map DOM selections back to markdown source for editing, and integration of canvas-specific message parts and API extensions. The changes are generally well-structured and introduce a powerful new feature. However, there are a few areas that require attention regarding robustness, consistency, and potential breaking changes in the TypeScript SDK.

@kapetr kapetr requested a review from PetrBulanek December 2, 2025 15:21
@kapetr kapetr force-pushed the feat/168-open-canvas-functionality branch from 5220d2f to b2ab5ef Compare December 3, 2025 10:47
@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Dec 3, 2025

const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/canvas/v1';

const schema = z.null();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels weird to me. Shouldn't we rather put an empty object there? Maybe there will be some demands in the future, so let's prepare for that right away?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and it would simplify things on the UI. What do you think @tomkis ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change? :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So a demand with empty parameters can be distinguished from a non-existent demand. But I completely agree with your concern - we should rethink how this is handled.

Comment on lines 105 to 112
if (canvasDemands !== undefined) {
const canvasEditRequest = fulfillments.canvasEditRequest();
if (canvasEditRequest) {
fulfilledMetadata = fulfillCanvasDemand(fulfilledMetadata, canvasEditRequest);
}
}

const oauthRedirectUri = fulfillments.oauthRedirectUri();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you checking undefined directly here? I would probably try to make it all as similar as possible to the other functions (with regard to parameters, return values, etc.). Maybe in the future some mechanism will be created so that all this doesn't have to be called manually. :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same reason as the previous comment.

Comment on lines 121 to 143
const parts = handleArtifactUpdate(event);
const parts = handleArtifactUpdate(event, demands.canvasDemands !== undefined);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a good solution? Theoretically, it could just be a matter of returning the file and not the canvas itself. Shouldn't this be differentiated more at the metadata level? I'd be happy to talk about it some more. This seems fragile to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above comments. Not sure i understand the comment with the file (it can still return FilePart). This essentially checks if the agent can handle canvas edit requests, meaning it will add ArtifactPart and render Canvas UI.
But I'll be happy to discuss this, it's really an initial version!

import { findWithIndex } from '#utils/helpers.ts';
import { toMarkdownArtifact } from '#utils/markdown.ts';

export function processMessageArtifactPart(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it would be better if the function returned parts and the array mutation took place outside the function. This is how it is handled in other cases in addMessagePart fn. I don't see any actual problem there, but it seems a little clearer to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would basically mean removing this function and copying contents into the addMessagePart. I'd prefer that as well, but it would clutter addMessagePart quite a bit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. I just found the function a little difficult to read. Maybe it's primarily because of the long if conditions. But I guess it's not such a big deal. So let's leave it as it is. :-)

Signed-off-by: Petr Kadlec <[email protected]>

feat(ui): finalize canvas, improve selection mapping

Signed-off-by: Petr Kadlec <[email protected]>

Signed-off-by: Petr Kadlec <[email protected]>

Signed-off-by: Petr Kadlec <[email protected]>

Signed-off-by: Petr Kadlec <[email protected]>
Signed-off-by: Petr Kadlec <[email protected]>
@kapetr kapetr force-pushed the feat/168-open-canvas-functionality branch from b2ab5ef to c568163 Compare December 8, 2025 15:45
@kapetr kapetr requested a review from tomkis December 9, 2025 13:25
@kapetr
Copy link
Contributor Author

kapetr commented Dec 9, 2025

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces initial Canvas functionality to the UI, enabling users to interact with artifacts displayed in a canvas-like view. Key changes include new Python SDK examples for canvas agents, TypeScript SDK updates for canvas extensions, and significant UI components for rendering and interacting with canvas artifacts. The UI now supports selecting text within markdown content to initiate edit requests, and a new context (CanvasProvider) manages active artifacts. Overall, the changes are well-structured and integrate the new feature effectively. However, there are a few areas that could be improved for robustness and clarity, particularly regarding state management and selection logic.

Comment on lines +41 to +42
if message.metadata and self.spec.URI in message.metadata and message.parts:
message.parts = [part for part in message.parts if not isinstance(part.root, TextPart)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Modifying message.parts in place within handle_incoming_message can lead to unexpected side effects if the A2AMessage object is intended to be immutable or if other parts of the system rely on its original state. It's generally safer to create a new list of parts rather than mutating the incoming message directly.

Suggested change
if message.metadata and self.spec.URI in message.metadata and message.parts:
message.parts = [part for part in message.parts if not isinstance(part.root, TextPart)]
if message.metadata and self.spec.URI in message.metadata and message.parts:
# Create a new list of parts to avoid mutating the original message object
message.parts = [part for part in message.parts if not isinstance(part.root, TextPart)]

@kapetr kapetr requested a review from PetrBulanek December 10, 2025 07:48
artifact_id: z.string(),
});

export type CanvasFulfillments = z.infer<typeof responseSchema>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets rename this, it's no longer fullfilment.

};
}

const canvasEditRequest = fulfillments.canvasEditRequest();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong. Canvas Edit Request is not fullfilemnt.

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Dec 10, 2025
@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels Dec 10, 2025
const inputRequiredMetadata = await resolveInputRequiredMetadata(responses);
const uiExtensionMetadata = await resolveUiExtensionMetadata(uiExtensionInputs);

console.log({ uiExtensionInputs, uiExtensionMetadata });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgotten console.log

@dosubot dosubot bot removed the lgtm This PR has been approved by a maintainer label Dec 10, 2025
Signed-off-by: Petr Kadlec <[email protected]>
@kapetr
Copy link
Contributor Author

kapetr commented Dec 11, 2025

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces initial canvas functionality, a significant new feature enabling users to interact with agent-generated artifacts like code or recipes in a dedicated UI panel. The implementation spans the Python and TypeScript SDKs and the UI application, featuring artifact streaming, an editing interface with text selection, and markdown-to-DOM position mapping. The changes are extensive and well-structured. I've identified a high-severity bug in the UI's artifact streaming logic that could cause data duplication, and two medium-severity issues in the Python example files related to unsafe array access that could lead to crashes. Addressing these points will enhance the feature's robustness.

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Dec 11, 2025
@kapetr
Copy link
Contributor Author

kapetr commented Dec 11, 2025

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new functionality for a 'Canvas' UI, allowing users to select and request edits on artifacts generated by an agent. The changes span across the Python SDK, the TypeScript SDK, and the UI application, including new components, hooks, and context providers. The implementation is quite comprehensive, covering everything from the backend agent extension to the frontend selection mechanism with a floating toolbar.

My review focuses on improving robustness, performance, and correctness in the new example files and core logic. I've identified a few areas for improvement:

  • In the Python example agents, there are opportunities to make artifact part access safer and to optimize regex compilation.
  • In the Python canvas extension, a type check appears to be incorrect, which could lead to bugs.
  • In the UI, there's a minor bug in how artifact content is constructed and an accessibility issue in a new form.
  • The new documentation for the canvas feature contains a couple of errors in its code examples that could mislead developers.

Overall, this is a well-executed feature addition. The use of modern browser APIs like CSS Custom Highlights is a nice touch. Addressing the feedback will make the implementation more robust and the documentation more accurate.

Signed-off-by: Petr Kadlec <[email protected]>
@kapetr kapetr merged commit 965df7f into main Dec 11, 2025
10 checks passed
@kapetr kapetr deleted the feat/168-open-canvas-functionality branch December 11, 2025 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change lgtm This PR has been approved by a maintainer size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants