Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix markdown request renderer #14211

Merged
merged 6 commits into from
Sep 30, 2024

Conversation

eneufeld
Copy link
Contributor

What it does

Currently requests in the ai chat view use a markdown renderer which parses html input and tries to render this. This leads to unexpected behavior when using html in the query.
By deactivating html support there, an alternative is needed as the markdown renderer just renders an empty paragraph if html is now passed to it. So to render the actual text, a span is created and filled with the text content.

fixes #14208

How to test

Use a string like <img src="../../enter-openai-key.png" alt="Theia IDE Screenshot" style="max-width: 525px"> in you query.

Follow-ups

Review checklist

Reminder for reviewers

Comment on lines 42 to 56
// // eslint-disable-next-line no-null/no-null
// const ref: React.MutableRefObject<HTMLDivElement | null> = useRef(null);

// useEffect(() => {
// const host = document.createElement('div');
// const html = this.markdownIt.render(response.content);
// host.innerHTML = DOMPurify.sanitize(html, {
// ALLOW_UNKNOWN_PROTOCOLS: true // DOMPurify usually strips non http(s) links from hrefs
// });
// while (ref?.current?.firstChild) {
// ref.current.removeChild(ref.current.firstChild);
// }

// ref?.current?.appendChild(host);
// }, [response.content]);
Copy link
Member

Choose a reason for hiding this comment

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

should be removed

Comment on lines 383 to 396
useEffect(() => {
const markdownIt = markdownit();
const text = node.request.request.displayText ?? node.request.request.text;
const host = document.createElement('div');
const html = markdownIt.render(text);
host.innerHTML = DOMPurify.sanitize(html, {
ALLOW_UNKNOWN_PROTOCOLS: true // DOMPurify usually strips non http(s) links from hrefs
});
while (ref?.current?.firstChild) {
ref.current.removeChild(ref.current.firstChild);
}

ref?.current?.appendChild(host);
}, [node.request]);
Copy link
Member

Choose a reason for hiding this comment

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

This is almost the same content as in the response renderer. I would like to suggest a custom hook useMarkDownRendering(markDownText) so we can reuse this logic in both.

The hook could then also be documented on why it exists and why it uses markdownit directly.

@@ -411,35 +410,35 @@ export class TextChatResponseContentImpl implements TextChatResponseContent {

export class MarkdownChatResponseContentImpl implements MarkdownChatResponseContent {
kind: 'markdownContent' = 'markdownContent';
protected _content: MarkdownStringImpl = new MarkdownStringImpl();
protected _content: string;
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we keep the markdown string content? depending on its attributes we could then hand over different options to markdownit. Thereby we could allow html embeddings if someone wants to have that.

Change the rendering off all markdown renderers to use markdown-it directly.
Also no MarkdownString class is used anymore.

fixes eclipse-theia#14208
- revert model changes
- create custom hook for rendering
Copy link
Member

@sdirix sdirix left a comment

Choose a reason for hiding this comment

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

Works for me!

I tested requests like:

Hi <span> there </span>

And I executed prompts like:

Paste me an html template. Do not wrap in code block

These requests and answers were shown correctly 👍


I only have minor comments

Comment on lines +73 to +74
// eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLDivElement | null>(null);
Copy link
Member

Choose a reason for hiding this comment

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

Is there a benefit of using null over undefined?

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 ref paramerter wants null, can't be used with undefined

useEffect(() => {
const markdownIt = markdownit();
const host = document.createElement('div');
const html = markdownIt.render(markdown);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const html = markdownIt.render(markdown);
// TODO: accept MarkdownString objects and set options accordingly
const html = markdownIt.render(markdown);

Copy link
Member

@sdirix sdirix left a comment

Choose a reason for hiding this comment

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

Works great

@sdirix sdirix merged commit 363865f into eclipse-theia:master Sep 30, 2024
11 checks passed
@sdirix sdirix deleted the fix/request-rendering branch September 30, 2024 11:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

[Theia AI] HTML is not escaped in the Chat View
2 participants