[Obs AI Assistant] Add custom plugin for highlighting user and assistant responses when they have redacted entities#224605
Conversation
|
Pinging @elastic/obs-ai-assistant (Team:Obs AI Assistant) |
🤖 GitHub commentsExpand to view the GitHub comments
Just comment with:
|
| } | ||
|
|
||
| // helper using detected entity positions to transform user messages into react node to add text highlighting | ||
| function highlightContent( |
There was a problem hiding this comment.
I suspect we can simplify quite a bit here. If you wrap in <anonymized entityClass="....">${content}</anonymized>, I assume you can either just use CSS or add anonymized as a component to processingPlugins. Perhaps the CSS option is simpler. Also, I wouldn't worry about how it renders in a code block or code tag - that's something we can fix later.
There was a problem hiding this comment.
Thanks for the feedback @dgieselaar and I like the suggested - I'm happy to try this out and see where it lands. My current understanding is that if we want to keep the existing UX for messages we may need to go down the path of the plugins as the content was previously wrapped in EuiMarkdownFormat since we want to utilize the existing plugins (perhaps wrapping with anonymized and processingPlugins could work). If we can go with CSS altogether, that would be ideal.
There was a problem hiding this comment.
@dgieselaar After trying a few things out I found that wrapping into <anonymized> doesn't work without implementing a parsing plugin as, otherwise, all of the markup gets processed and removed by the default plugins. Let me know if you know of a way to override this behaviour for certain elements and make easier - I searched across the codebase and didn't find solutions that do so without a parsing plugin (for example, I found security assistant's plugin).
I'm happy to make this a markup parser, but from my current understanding the approach wouldn't change much (other than a simplified regex). Happy to hear your thoughts.
I'm happy to look into this before Monday again (currently on PTO).
cc: @arturoliduena
There was a problem hiding this comment.
So, I had another pass at this and found that remark-parse strips out common and custom tags without implemented parser. I also found that most of other custom parsers across the codebase (based on my search) follow the custom plugin approach outlined in EUI docs.
I updated the PR to follow the parsing approach outlined in the EUI docs that's used elsewehere and adapted from your suggestion so the format is now:
!{anonymized{"entityClass": "<entity class>", "content": "<content>"}}
Let me know what you think about those changes.
There was a problem hiding this comment.
TIL about that being recommended syntax. So the reason I was hoping we can use HTML elements is because it's more readable, it doesn't break anything if people e.g. copy/paste the prompt or the assistant response. But what I get from you is that remark-parse strips any tags it doesn't understand? And what about something like <em> with a custom classname and or attributes? We don't have to spend a lot of time on it, so feel free to move forward with this approach if the other is not feasible.
There was a problem hiding this comment.
But what I get from you is that remark-parse strips any tags it doesn't understand?
That's correct. The default parsing plugins (getDefaultEuiMarkdownParsingPlugins()) also seems to strip standard tags, unless you implement a custom parser. I tried with <span>, <div> and <em> and all get stripped with children (content) being show that ends up like other standard text in the markdown.
Thanks for calling it out, it was good to dive and understand the constraints. I will update in case I do find a simpler take on this, but will leave as is for now.
…they have anonymized entities
44ad28a to
c325fc7
Compare
| * Markdown parser for anonymized inline syntax. | ||
| * Matches `!{anonymized{...}}` and passes the JSON configuration on the node. | ||
| */ | ||
| export const anonymizedHighlightPlugin: Plugin = function () { |
There was a problem hiding this comment.
The parser logic was taken from the EUI documentation: https://eui.elastic.co/docs/components/editors-and-syntax/markdown/plugins/#putting-it-all-together-a-simple-chart-plugin
I previously implemented with regex, but thought I'd adhere to what's recommended and used across the codebase.
💛 Build succeeded, but was flaky
Failed CI StepsTest Failures
Metrics [docs]Module Count
Async chunks
Page load bundle
History
|
|
Starting backport for target branches: 8.19 https://github.com/elastic/kibana/actions/runs/15878011783 |
💔 All backports failed
Manual backportTo create the backport manually run: Questions ?Please refer to the Backport tool documentation |
💚 All backports created successfully
Note: Successful backport PRs will be merged automatically after passing CI. Questions ?Please refer to the Backport tool documentation |
…ant responses when they have redacted entities (elastic#224605) Closes: elastic/obs-ai-team#264 ## Summary Add custom plugin for highlighting user and assistant responses when they have redacted entities: - Custom plugin for `EuiMarkdownFormat` that highlights all content wrapped inside anonymized node. The parsing plugin follows the approach from [EUI docs](https://eui.elastic.co/docs/components/editors-and-syntax/markdown/plugins/#putting-it-all-together-a-simple-chart-plugin) and is used as follows: ``` !{anonymized{"entityClass":"<entity class>", "content": "<content"}} ``` - Highlighted content is currently rendered as `EuiCode`, but it can be more sophisticated (i.e highlight differently depending on the entity class). - Allows using the same highlighting logic for messages from both `user` and `assistant` roles. - Currently **skipping highlighting inside the code blocks** - may require customising the default plugins further. Manually tested: - Function calling seems to work as expected. - Search results with PII are highlighted in the table. - Custom regex matches are highlighted correctly. ### Testing instructions: 1. Used setup from elastic#216352 to set up NER model locally. 2. Added to `kibana.dev.yml`: ``` uiSettings: overrides: 'observability:aiAssistantAnonymizationRules': | [ { "type": "regex", "pattern": "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[A-Za-z]{2,}", "enabled": true, "entityClass": "EMAIL" }, { "type": "regex", "pattern": "https?://[^\\s]+", "enabled": true, "entityClass": "URL" }, { "type": "regex", "pattern": "\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b", "enabled": true, "entityClass": "IP" }, { "type": "ner", "enabled": true } ] ``` 3. Used the assistant (see screenshots below) ### Screenshots <img width="689" alt="image" src="https://github.com/user-attachments/assets/d1f9bd57-7e76-43dc-88a6-d0be5fb15092" /> <img width="689" alt="image" src="https://github.com/user-attachments/assets/ed63626b-b32d-45f8-9cf4-c575320d0dfc" /> <img width="689" alt="image" src="https://github.com/user-attachments/assets/0b591158-9186-406a-aab3-e3be538216dc" /> ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) (cherry picked from commit 05b4fdd) # Conflicts: # x-pack/platform/packages/shared/kbn-ai-assistant/src/chat/chat_timeline.tsx
… assistant responses when they have redacted entities (#224605) (#225305) # Backport This will backport the following commits from `main` to `8.19`: - [[Obs AI Assistant] Add custom plugin for highlighting user and assistant responses when they have redacted entities (#224605)](#224605) <!--- Backport version: 10.0.1 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Srdjan Lulic","email":"srdjan.lulic@elastic.co"},"sourceCommit":{"committedDate":"2025-06-25T13:41:19Z","message":"[Obs AI Assistant] Add custom plugin for highlighting user and assistant responses when they have redacted entities (#224605)\n\nCloses: https://github.com/elastic/obs-ai-assistant-team/issues/264\n\n## Summary\n\nAdd custom plugin for highlighting user and assistant responses when\nthey have redacted entities:\n\n- Custom plugin for `EuiMarkdownFormat` that highlights all content\nwrapped inside anonymized node. The parsing plugin follows the approach\nfrom [EUI\ndocs](https://eui.elastic.co/docs/components/editors-and-syntax/markdown/plugins/#putting-it-all-together-a-simple-chart-plugin)\nand is used as follows:\n ```\n!{anonymized{\"entityClass\":\"<entity class>\", \"content\": \"<content\"}}\n ``` \n- Highlighted content is currently rendered as `EuiCode`, but it can be\nmore sophisticated (i.e highlight differently depending on the entity\nclass).\n- Allows using the same highlighting logic for messages from both `user`\nand `assistant` roles.\n- Currently **skipping highlighting inside the code blocks** - may\nrequire customising the default plugins further.\n\nManually tested: \n- Function calling seems to work as expected.\n- Search results with PII are highlighted in the table.\n- Custom regex matches are highlighted correctly.\n\n### Testing instructions:\n1. Used setup from #216352 to set\nup NER model locally.\n2. Added to `kibana.dev.yml`:\n```\nuiSettings:\n overrides:\n 'observability:aiAssistantAnonymizationRules': |\n [\n {\n \"type\": \"regex\",\n \"pattern\": \"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[A-Za-z]{2,}\",\n \"enabled\": true,\n \"entityClass\": \"EMAIL\"\n },\n {\n \"type\": \"regex\",\n \"pattern\": \"https?://[^\\\\s]+\",\n \"enabled\": true,\n \"entityClass\": \"URL\"\n },\n {\n \"type\": \"regex\",\n \"pattern\": \"\\\\b(?:\\\\d{1,3}\\\\.){3}\\\\d{1,3}\\\\b\",\n \"enabled\": true,\n \"entityClass\": \"IP\"\n },\n {\n \"type\": \"ner\",\n \"enabled\": true\n }\n ]\n```\n3. Used the assistant (see screenshots below)\n\n### Screenshots\n<img width=\"689\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/d1f9bd57-7e76-43dc-88a6-d0be5fb15092\"\n/>\n\n<img width=\"689\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/ed63626b-b32d-45f8-9cf4-c575320d0dfc\"\n/>\n\n\n<img width=\"689\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/0b591158-9186-406a-aab3-e3be538216dc\"\n/>\n\n\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [x] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [x]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"05b4fdd854e62b761b480a2d64b76ba4cd13511e","branchLabelMapping":{"^v9.1.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Obs AI Assistant","ci:project-deploy-observability","backport:version","v9.1.0","v8.19.0"],"title":"[Obs AI Assistant] Add custom plugin for highlighting user and assistant responses when they have redacted entities","number":224605,"url":"https://github.com/elastic/kibana/pull/224605","mergeCommit":{"message":"[Obs AI Assistant] Add custom plugin for highlighting user and assistant responses when they have redacted entities (#224605)\n\nCloses: https://github.com/elastic/obs-ai-assistant-team/issues/264\n\n## Summary\n\nAdd custom plugin for highlighting user and assistant responses when\nthey have redacted entities:\n\n- Custom plugin for `EuiMarkdownFormat` that highlights all content\nwrapped inside anonymized node. The parsing plugin follows the approach\nfrom [EUI\ndocs](https://eui.elastic.co/docs/components/editors-and-syntax/markdown/plugins/#putting-it-all-together-a-simple-chart-plugin)\nand is used as follows:\n ```\n!{anonymized{\"entityClass\":\"<entity class>\", \"content\": \"<content\"}}\n ``` \n- Highlighted content is currently rendered as `EuiCode`, but it can be\nmore sophisticated (i.e highlight differently depending on the entity\nclass).\n- Allows using the same highlighting logic for messages from both `user`\nand `assistant` roles.\n- Currently **skipping highlighting inside the code blocks** - may\nrequire customising the default plugins further.\n\nManually tested: \n- Function calling seems to work as expected.\n- Search results with PII are highlighted in the table.\n- Custom regex matches are highlighted correctly.\n\n### Testing instructions:\n1. Used setup from #216352 to set\nup NER model locally.\n2. Added to `kibana.dev.yml`:\n```\nuiSettings:\n overrides:\n 'observability:aiAssistantAnonymizationRules': |\n [\n {\n \"type\": \"regex\",\n \"pattern\": \"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[A-Za-z]{2,}\",\n \"enabled\": true,\n \"entityClass\": \"EMAIL\"\n },\n {\n \"type\": \"regex\",\n \"pattern\": \"https?://[^\\\\s]+\",\n \"enabled\": true,\n \"entityClass\": \"URL\"\n },\n {\n \"type\": \"regex\",\n \"pattern\": \"\\\\b(?:\\\\d{1,3}\\\\.){3}\\\\d{1,3}\\\\b\",\n \"enabled\": true,\n \"entityClass\": \"IP\"\n },\n {\n \"type\": \"ner\",\n \"enabled\": true\n }\n ]\n```\n3. Used the assistant (see screenshots below)\n\n### Screenshots\n<img width=\"689\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/d1f9bd57-7e76-43dc-88a6-d0be5fb15092\"\n/>\n\n<img width=\"689\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/ed63626b-b32d-45f8-9cf4-c575320d0dfc\"\n/>\n\n\n<img width=\"689\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/0b591158-9186-406a-aab3-e3be538216dc\"\n/>\n\n\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [x] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [x]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"05b4fdd854e62b761b480a2d64b76ba4cd13511e"}},"sourceBranch":"main","suggestedTargetBranches":["8.19"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/224605","number":224605,"mergeCommit":{"message":"[Obs AI Assistant] Add custom plugin for highlighting user and assistant responses when they have redacted entities (#224605)\n\nCloses: https://github.com/elastic/obs-ai-assistant-team/issues/264\n\n## Summary\n\nAdd custom plugin for highlighting user and assistant responses when\nthey have redacted entities:\n\n- Custom plugin for `EuiMarkdownFormat` that highlights all content\nwrapped inside anonymized node. The parsing plugin follows the approach\nfrom [EUI\ndocs](https://eui.elastic.co/docs/components/editors-and-syntax/markdown/plugins/#putting-it-all-together-a-simple-chart-plugin)\nand is used as follows:\n ```\n!{anonymized{\"entityClass\":\"<entity class>\", \"content\": \"<content\"}}\n ``` \n- Highlighted content is currently rendered as `EuiCode`, but it can be\nmore sophisticated (i.e highlight differently depending on the entity\nclass).\n- Allows using the same highlighting logic for messages from both `user`\nand `assistant` roles.\n- Currently **skipping highlighting inside the code blocks** - may\nrequire customising the default plugins further.\n\nManually tested: \n- Function calling seems to work as expected.\n- Search results with PII are highlighted in the table.\n- Custom regex matches are highlighted correctly.\n\n### Testing instructions:\n1. Used setup from #216352 to set\nup NER model locally.\n2. Added to `kibana.dev.yml`:\n```\nuiSettings:\n overrides:\n 'observability:aiAssistantAnonymizationRules': |\n [\n {\n \"type\": \"regex\",\n \"pattern\": \"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[A-Za-z]{2,}\",\n \"enabled\": true,\n \"entityClass\": \"EMAIL\"\n },\n {\n \"type\": \"regex\",\n \"pattern\": \"https?://[^\\\\s]+\",\n \"enabled\": true,\n \"entityClass\": \"URL\"\n },\n {\n \"type\": \"regex\",\n \"pattern\": \"\\\\b(?:\\\\d{1,3}\\\\.){3}\\\\d{1,3}\\\\b\",\n \"enabled\": true,\n \"entityClass\": \"IP\"\n },\n {\n \"type\": \"ner\",\n \"enabled\": true\n }\n ]\n```\n3. Used the assistant (see screenshots below)\n\n### Screenshots\n<img width=\"689\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/d1f9bd57-7e76-43dc-88a6-d0be5fb15092\"\n/>\n\n<img width=\"689\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/ed63626b-b32d-45f8-9cf4-c575320d0dfc\"\n/>\n\n\n<img width=\"689\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/0b591158-9186-406a-aab3-e3be538216dc\"\n/>\n\n\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [x] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [x]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"05b4fdd854e62b761b480a2d64b76ba4cd13511e"}},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
Closes: https://github.com/elastic/obs-ai-assistant-team/issues/264
Summary
Add custom plugin for highlighting user and assistant responses when they have redacted entities:
EuiMarkdownFormatthat highlights all content wrapped inside anonymized node. The parsing plugin follows the approach from EUI docs and is used as follows:EuiCode, but it can be more sophisticated (i.e highlight differently depending on the entity class).userandassistantroles.Manually tested:
Testing instructions:
kibana.dev.yml:Screenshots
Checklist
Check the PR satisfies following conditions.
Reviewers should verify this PR satisfies this list as well.
release_note:*label is applied per the guidelines