Skip to content

feat(chatbot): add page-aware context, dynamic suggestions, and sessi…#464

Merged
paigerube14 merged 2 commits into
krkn-chaos:mainfrom
vipulpandey21:feat/chatbot-page-context-and-session
May 18, 2026
Merged

feat(chatbot): add page-aware context, dynamic suggestions, and sessi…#464
paigerube14 merged 2 commits into
krkn-chaos:mainfrom
vipulpandey21:feat/chatbot-page-context-and-session

Conversation

@vipulpandey21

Copy link
Copy Markdown
Contributor

What this PR does

Closes #463

The Krkn chatbot is useful, but it had no idea what page you were reading.
Every page showed the same generic quick buttons, and your conversation
disappeared the moment you navigated away. This PR fixes all three of those
problems.

Changes

1. Page-aware context pill

When you open the chatbot on a doc page, it now detects where you are and
shows a small "Asking about: Pod Scenarios" pill above the input. This also
gets sent to the backend so the LLM can prioritise results from the section
you are already reading — no backend code changes needed.

2. Dynamic quick suggestion buttons

The three hardcoded buttons (Getting Started, Available Scenarios,
Installation) are now replaced with page-specific questions. There are 13
different sets covering every scenario page, Krkn AI, krknctl, Cerberus,
Installation, and Getting Started. On pages outside the docs, the original
default buttons still show.

3. Session persistence + Clear button

Conversation history is now saved to sessionStorage so your messages
survive when you navigate between pages in the same tab. A Clear button lets
you reset the session whenever you want a fresh start. History is capped at
the last 20 messages to keep storage clean.

Files changed

  • static/js/chatbot.js
  • static/css/chatbot.css

No backend changes. No Hugo templates touched. No SCSS changes.

Testing

  1. Go to any scenario page (e.g. /docs/scenarios/pod-scenario/)
  2. Open the chatbot — pill shows "Asking about: Pod Scenarios" and buttons
    are pod-specific
  3. Navigate to /docs/getting-started/ — pill and buttons update automatically
  4. Go to the homepage — no pill, default buttons shown
  5. Send a message, navigate away, come back — conversation is still there
  6. Click Clear — session resets to welcome message

…on persistence

- Detect current doc section from URL and show 'Asking about: X' pill
  above the input so users know the chatbot is contextualised to the
  page they are reading
- Pass page context in the request body so the backend can prioritise
  relevant documentation sections in its search results
- Replace hardcoded quick buttons with 13 sets of page-specific
  suggested questions covering all scenario pages, Krkn AI, krknctl,
  Cerberus, Installation, and Getting Started
- Persist conversation history in sessionStorage so messages survive
  page navigation within the same browser tab (capped at 20 messages)
- Add Clear button to reset the session and start fresh

Closes krkn-chaos#463

Signed-off-by: vipulpandey21 <vipulpandey7917@gmail.com>
@netlify

netlify Bot commented May 16, 2026

Copy link
Copy Markdown

Deploy Preview for krkn-chaos ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 39641d2
🔍 Latest deploy log https://app.netlify.com/projects/krkn-chaos/deploys/6a089ae1f0e37c0008008492
😎 Deploy Preview https://deploy-preview-464--krkn-chaos.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Add page-aware context, dynamic suggestions, and session persistence

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add page-aware context detection showing "Asking about: X" pill above input
• Replace hardcoded quick buttons with 13 sets of page-specific suggestions
• Persist conversation history to sessionStorage across page navigations
• Add Clear button to reset session and start fresh conversation
• Pass detected page context to backend for improved search prioritization
Diagram
flowchart LR
  A["User opens chatbot"] --> B["Detect current doc page"]
  B --> C["Show context pill"]
  B --> D["Load page-specific buttons"]
  B --> E["Restore session messages"]
  C --> F["Send context to backend"]
  D --> G["User sends message"]
  G --> H["Save to sessionStorage"]
  H --> I["Navigate to new page"]
  I --> J["Restore conversation history"]
Loading

Grey Divider

File Changes

1. static/js/chatbot.js ✨ Enhancement +316/-5

Page context detection and session persistence implementation

• Add detectPageContext() method mapping 30+ URL patterns to doc section labels
• Implement saveSession() and loadSession() for sessionStorage persistence (capped at 20
 messages)
• Add clearSession() method to reset conversation and show welcome message
• Implement getPageSuggestions() returning 13 page-specific question sets with emojis
• Add updateQuickButtons() to dynamically replace buttons based on current page
• Add updatePageContextPill() to show/hide context bar based on URL
• Modify sendMessage() to include detected page context in API request body
• Update addMessage() with skipSave parameter to avoid double-persisting during session restore
• Initialize session storage key and max persisted messages in constructor
• Add Clear button event listener in createChatbot()
• Restore saved messages on initialization before showing welcome message

static/js/chatbot.js


2. static/css/chatbot.css Styling +57/-0

Add styles for context pill and clear button

• Add .krkn-page-context-bar styles for the context pill container with flexbox layout
• Style .krkn-page-context-label for "Asking about:" text with subtle color
• Style .krkn-page-context-name for doc section name with primary color and ellipsis
• Add .krkn-chat-clear button styles with hover and focus states
• Implement smooth transitions for Clear button interactions

static/css/chatbot.css


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented May 16, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Incorrect doc path regexes ✓ Resolved 🐞 Bug ≡ Correctness
Description
detectPageContext() / getPageSuggestions() use URL regexes that don’t match multiple existing docs
routes (e.g. "network-chaos-scenario", "zone-outage-scenarios", "cpu-hog-scenario"), so the context
pill and page-specific quick buttons won’t appear on those pages.
Code

static/js/chatbot.js[R20-56]

+    detectPageContext() {
+        const path = window.location.pathname;
+
+        // Map URL path segments to human-readable doc section labels
+        const contextMap = [
+            { pattern: /\/docs\/scenarios\/pod-scenario/,          label: 'Pod Scenarios' },
+            { pattern: /\/docs\/scenarios\/container-scenario/,    label: 'Container Scenarios' },
+            { pattern: /\/docs\/scenarios\/node-scenarios/,        label: 'Node Scenarios' },
+            { pattern: /\/docs\/scenarios\/network-chaos/,         label: 'Network Chaos' },
+            { pattern: /\/docs\/scenarios\/pod-network-scenario/,  label: 'Pod Network Chaos' },
+            { pattern: /\/docs\/scenarios\/application-outage/,    label: 'Application Outage' },
+            { pattern: /\/docs\/scenarios\/service-disruption/,    label: 'Service Disruption' },
+            { pattern: /\/docs\/scenarios\/service-hijacking/,     label: 'Service Hijacking' },
+            { pattern: /\/docs\/scenarios\/zone-outage/,           label: 'Zone Outage Scenarios' },
+            { pattern: /\/docs\/scenarios\/power-outage/,          label: 'Power Outage Scenarios' },
+            { pattern: /\/docs\/scenarios\/hog-scenarios\/cpu/,    label: 'CPU Hog Scenario' },
+            { pattern: /\/docs\/scenarios\/hog-scenarios\/memory/, label: 'Memory Hog Scenario' },
+            { pattern: /\/docs\/scenarios\/hog-scenarios\/io/,     label: 'IO Hog Scenario' },
+            { pattern: /\/docs\/scenarios\/pvc-scenario/,          label: 'PVC Disk Fill Scenario' },
+            { pattern: /\/docs\/scenarios\/time-scenarios/,        label: 'Time Skew Scenarios' },
+            { pattern: /\/docs\/scenarios\/dns-outage/,            label: 'DNS Outage Scenario' },
+            { pattern: /\/docs\/scenarios\/etcd-split-brain/,      label: 'ETCD Split Brain' },
+            { pattern: /\/docs\/scenarios\/aurora-disruption/,     label: 'Aurora Disruption' },
+            { pattern: /\/docs\/scenarios\/efs-disruption/,        label: 'EFS Disruption' },
+            { pattern: /\/docs\/scenarios\/syn-flood/,             label: 'Syn Flood Scenario' },
+            { pattern: /\/docs\/scenarios\/http-load/,             label: 'HTTP Load Scenario' },
+            { pattern: /\/docs\/scenarios\/kubevirt/,              label: 'KubeVirt VM Outage' },
+            { pattern: /\/docs\/scenarios\/network-chaos-ng/,      label: 'Network Chaos NG' },
+            { pattern: /\/docs\/scenarios/,                        label: 'Chaos Scenarios' },
+            { pattern: /\/docs\/krkn_ai/,                          label: 'Krkn AI' },
+            { pattern: /\/docs\/krkn-operator/,                    label: 'Krkn Operator' },
+            { pattern: /\/docs\/cerberus/,                         label: 'Cerberus' },
+            { pattern: /\/docs\/krknctl/,                          label: 'krknctl CLI' },
+            { pattern: /\/docs\/installation/,                     label: 'Installation' },
+            { pattern: /\/docs\/getting-started/,                  label: 'Getting Started' },
+            { pattern: /\/docs\/krkn/,                             label: 'Krkn Core' },
+        ];
Evidence
The JS maps look for slugs like /docs/scenarios/network-chaos and
/docs/scenarios/hog-scenarios/cpu, but the actual documentation folders (and thus routes) include
different segments such as network-chaos-scenario and hog-scenarios/cpu-hog-scenario, so these
regex checks will never match on those pages.

static/js/chatbot.js[20-56]
static/js/chatbot.js[116-231]
content/en/docs/scenarios/network-chaos-scenario/_index.md[1-6]
content/en/docs/scenarios/zone-outage-scenarios/_index.md[1-6]
content/en/docs/scenarios/hog-scenarios/cpu-hog-scenario/_index.md[1-6]
content/en/docs/scenarios/service-disruption-scenarios/_index.md[1-6]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`detectPageContext()` and `getPageSuggestions()` rely on regexes that do not match several documentation route segments used by the site. As a result, the feature silently fails (no context pill + default suggestions) on those pages.

### Issue Context
Docs routes are derived from the content directory names (e.g. `content/en/docs/scenarios/network-chaos-scenario/` => `/docs/scenarios/network-chaos-scenario/`). Several patterns in the new maps omit the `-scenario` / `-scenarios` suffixes or use different subpaths than the actual folders.

### Fix Focus Areas
- static/js/chatbot.js[20-66]
- static/js/chatbot.js[116-246]

### What to change
- Update regex patterns to match the actual route segments (e.g. `network-chaos-scenario`, `zone-outage-scenarios`, `power-outage-scenarios`, `service-disruption-scenarios`, `service-hijacking-scenario`, `syn-flood-scenario`, `http-load-scenario`, `kubevirt-vm-outage-scenario`, `network-chaos-ng-scenarios`, and `hog-scenarios/(cpu-hog-scenario|memory-hog-scenario|io-hog-scenario)`).
- Prefer exact segment matching (e.g. include trailing `/` or boundary) to avoid accidental partial matches.
- Consider extracting a single source of truth for slugs to avoid divergence between contextMap and suggestionMap.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Persistent XSS via messages ✓ Resolved 🐞 Bug ⛨ Security
Description
saveSession()/loadSession() persist and replay message text, but addMessage() renders message text
via insertAdjacentHTML after formatMessage() without escaping or sanitizing HTML/URLs; this makes
any injected payload persist across page navigations within the session.
Code

static/js/chatbot.js[R72-83]

+    saveSession() {
+        try {
+            const toSave = this.messages.slice(-this.maxPersistedMessages).map(msg => ({
+                text: msg.text,
+                sender: msg.sender,
+                timestamp: msg.timestamp
+            }));
+            sessionStorage.setItem(this.sessionKey, JSON.stringify(toSave));
+        } catch (e) {
+            // sessionStorage may be unavailable (private browsing restrictions) — fail silently
+        }
+    }
Evidence
Session persistence stores raw msg.text and restores it on load, while message rendering injects
formatted output directly into the DOM as HTML. Since formatMessage() does not escape HTML and
builds <a href="..."> from user-controlled text, stored payloads can be re-executed/rendered
automatically during restore.

static/js/chatbot.js[72-83]
static/js/chatbot.js[384-393]
static/js/chatbot.js[526-567]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Messages are rendered as HTML (`insertAdjacentHTML`) using the output of `formatMessage()`, which performs markdown-like substitutions but does not escape HTML metacharacters or validate link URLs. With session persistence, malicious content is stored and then automatically re-rendered on subsequent pages.

### Issue Context
This affects both user-provided input and bot responses (from the backend), and is amplified by the new session persistence/restore flow.

### Fix Focus Areas
- static/js/chatbot.js[72-93]
- static/js/chatbot.js[384-393]
- static/js/chatbot.js[526-567]

### What to change
- Prefer DOM construction with `textContent` for plain text and a safe markdown renderer for formatting.
- If keeping `formatMessage()`, first HTML-escape the raw text (`&`, `<`, `>`, `"`, `'`) before applying formatting.
- Sanitize the final HTML with a strict allowlist (tags: `p`, `strong`, `em`, `code`, `a`; attributes: `href`, `target`, `rel`) and **reject** `javascript:`/`data:` URLs.
- Consider storing a structured message model (text + formatting tokens) rather than raw HTML-capable strings.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Clear hidden without context ✓ Resolved 🐞 Bug ≡ Correctness
Description
updatePageContextPill() hides the entire context bar when no doc context is detected, and the Clear
button is inside that bar, so users on non-doc pages lose the UI affordance to clear the persisted
conversation.
Code

static/js/chatbot.js[R270-283]

+    // Show or hide the page context pill based on current URL
+    updatePageContextPill() {
+        const bar = document.getElementById('krkn-page-context-bar');
+        const nameEl = document.getElementById('krkn-page-context-name');
+        const pageContext = this.detectPageContext();
+
+        if (bar && nameEl) {
+            if (pageContext) {
+                nameEl.textContent = pageContext;
+                bar.hidden = false;
+            } else {
+                bar.hidden = true;
+            }
+        }
Evidence
The Clear control is rendered inside the context bar, and the logic explicitly hides the whole bar
when no context is detected; therefore the Clear button is not shown on pages where
detectPageContext() returns null.

static/js/chatbot.js[270-284]
static/js/chatbot.js[312-320]
static/js/chatbot.js[20-66]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The Clear button is nested inside `#krkn-page-context-bar`, and the bar is hidden whenever no doc context is detected. This removes the visible Clear control on non-doc pages even though session persistence still applies there.

### Issue Context
`updatePageContextPill()` toggles `bar.hidden` based solely on `detectPageContext()`. Since `Clear` is inside that bar, it disappears together with the pill.

### Fix Focus Areas
- static/js/chatbot.js[270-284]
- static/js/chatbot.js[312-320]

### What to change
- Keep the Clear button visible regardless of page context (e.g., move it to the chat header, or render a separate always-visible control).
- Alternatively, hide only the context label/name portion while leaving a smaller action row visible when `pageContext` is null.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Session restore lacks validation ✓ Resolved 🐞 Bug ☼ Reliability
Description
createChatbot() assumes loadSession() returns an array and calls savedMessages.forEach(); if
sessionStorage contains valid JSON of a non-array type, this throws and prevents chatbot
initialization.
Code

static/js/chatbot.js[R384-389]

+        // Restore previous session messages (if any) before showing welcome message
+        const savedMessages = this.loadSession();
+        if (savedMessages.length > 0) {
+            savedMessages.forEach(msg => {
+                this.addMessage(msg.text, msg.sender, /* skipSave */ true);
+            });
Evidence
loadSession() returns the raw result of JSON.parse() with no type validation, and
createChatbot() immediately calls .forEach() on the returned value when length > 0, which will
throw for non-array JSON values.

static/js/chatbot.js[85-93]
static/js/chatbot.js[384-393]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Session restore is not defensive against corrupted/unexpected `sessionStorage` contents. `JSON.parse()` can return any JSON type, but initialization treats it as an array and calls `.forEach()`.

### Issue Context
This can happen if the key was written by an older version, a browser extension, manual debugging, or partial writes.

### Fix Focus Areas
- static/js/chatbot.js[85-93]
- static/js/chatbot.js[384-393]

### What to change
- In `loadSession()`, parse into a local variable and return `Array.isArray(parsed) ? parsed : []`.
- Optionally validate each entry shape (`{text: string, sender: 'user'|'bot'}`) and drop invalid items.
- Consider clearing the storage key if invalid to avoid repeated crashes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread static/js/chatbot.js
Comment thread static/js/chatbot.js
- Fix URL patterns to match exact Hugo directory names
  (e.g. network-chaos-scenario, zone-outage-scenarios,
  cpu-hog-scenario, kubevirt-vm-outage-scenario)
- Fix persistent XSS: sanitize message text via textContent
  before saving to sessionStorage and validate shape on load
- Move Clear button into input wrapper so it is always
  accessible, not hidden behind the context pill
- Add sender validation in loadSession to reject malformed data

Signed-off-by: vipulpandey21 <vipulpandey7917@gmail.com>
@vipulpandey21

vipulpandey21 commented May 16, 2026

Copy link
Copy Markdown
Contributor Author

Hey Maintainers @paigerube14 @shahsahil264 @chaitanyaenr

I've addressed all the review feedback from Qodo and fixed the URL patterns to match exact Hugo directory names, added XSS sanitization for session storage, moved the Clear button so it's always accessible, and added shape validation on session restore.
Would love to get your eyes on this when you have a moment free from you works!
A quick preview of what the feature looks like in action:

Pod Scenarios page --- context pill + page-specific buttons:
![pod-scenarios](paste screenshot here)

Getting Started page --- different buttons auto-loaded:
![getting-started](paste screenshot here)

Homepage --- no pill, default buttons shown:
![homepage](paste screenshot here)

Happy to make any changes based on your feedback. Thanks!

@paigerube14

Copy link
Copy Markdown
Contributor

this change looks good to me, I like how each page has its own suggestions of search and the chatbot stays open /keeps history between pages

@paigerube14 paigerube14 merged commit 8297329 into krkn-chaos:main May 18, 2026
7 checks passed
@vipulpandey21

vipulpandey21 commented May 19, 2026

Copy link
Copy Markdown
Contributor Author

Thank you Mrs. Paige! Really glad this approach worked well in practice.

The main issue was that the chatbot had no awareness of which documentation page the user was on, so suggestions stayed generic and conversations reset across navigation. I fixed that by passing the current page context into the chat session and persisting session state with sessionStorage, so the chatbot keeps continuity between pages.
The dynamic suggestions came from the same idea, tailoring prompts to the current page/topic instead of showing the same static suggestions everywhere makes the chatbot feel much more relevant and useful.

While working on this, I also found that the chatbot search index hadn’t been updating properly because the CI workflow never regenerated the static index file. Opened #472 for that fix so the index can rebuild automatically and stay up to date with docs changes.
Thank you for you time, Mrs. Paige.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature(chatbot): page-aware context, dynamic suggestions, and session persistence.

2 participants