Repository navigation
feat(sidekick): Gleap.openSidekick, an agent in a side panel next to the page - #193
Draft
boehlerlukas wants to merge 5 commits into
Draft
boehlerlukas wants to merge 5 commits into
boehlerlukas wants to merge 5 commits into
Conversation
…tive guards) What the page tells the agent (origin + path only: query and fragment never leave the page; title, onboarding step, the app's data, bounded like the server's sanitiser) as one envelope with Kai Copilot (surface 'sidekick'), overlay / push / sheet by viewport, and when a proactive open may show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t to the page The widget frame gets a 'sidekick' app mode: a full-height panel on the right edge (400 px; a full-screen sheet on phones) over a dim layer that blocks the page (overlay, default) or with the page pushed aside by a margin on <html> (push). Closes by its x, Escape, a click on the dimmed page or closeSidekick(); the page comes back exactly (inline styles, scroll, focus, launcher). The page's context follows SPA navigation. A messenger build without the sidekick falls back to startAgent. API: openSidekick, setSidekickContext, closeSidekick, isSidekickOpen, setSidekickProactive; events sidekick-opened/-closed/-proactive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The socket announces the 'sidekick' cap (the server sends proactive opens only to SDKs that do) and hands 'sidekick' messages to the manager, which shows one at most once per page view, never over something else, never while the person types, and not again for a day after a dismissal. The page poll keeps the open panel's context current. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- openSidekick pushes the page aside by default (no dim, page usable, aria-modal false,
Escape in the page stays the page's). It overlays a dimmed page instead when asked
(mode 'overlay'), when the page would get narrower than 720 px, or when a push could
break it: a page in a frame, RTL, a margin on <html>, a 100vw layout or a body with its
own width, a full-width fixed header/footer. A one-layout probe (margin applied, never
painted, put back) decides; sidekick-opened says why (pushFallback). Phones keep the
full-screen sheet, now clear of the notch and home indicator.
- Gleap.showSidekickMessage({ agentId, message, sender? }) / hideSidekickMessage(): a card
in the notification stack (avatar, 3 lines, "<agent> · now", its own dismiss button).
Clicking it opens the sidekick with the message as the agent's first message. Dismissed
= gone for a day in every tab (BroadcastChannel + gleap cache); a route change, the
widget opening or another identity take it away. Built with DOM nodes (no markup from
the message), a real button, Escape dismisses, a polite live region announces it,
reduced motion respected.
- Proactive socket messages carry display 'card' | 'open' (none = open, the old protocol);
cards wait for nothing, respect setSidekickProactive(false) and disabled in-app
notifications. The socket announces the new `sidekick-card` cap.
- Opening the sidekick no longer clears the other unread notifications; they hide while
it is open and come back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hrink along - Every position: fixed element that spans the viewport (left ≈ 0 and right ≈ the edge, or ≥ 90vw wide) gets inline left/width (!important) on the panel's side while pushed, slides with the page, and gets its previous inline values back exactly on close (an element without a style attribute gets none). A throttled MutationObserver adjusts fixed elements added (or turned fixed) while open; resizes re-measure. Gleap's own elements and the backdrop are skipped; transform-centered bars are left alone. - The push probe and its fallbacks (fixed bar, 100vw, html margin, RTL) are gone. Overlay only when asked, when the page would get narrower than 720 px, and by default inside an iframe (mode 'push' forces it there). Phones keep the sheet. A right-to-left widget pushes from the left. <html>'s own margin is kept (ours adds to it). - Pushed, the panel has a hairline edge instead of the overlay shadow. - Sidekick card: in a collapsed notification stack only the stack's × shows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sidekick mode: an agent in a side panel next to the page
Gleap.openSidekick()opens Kai Support or one of the workspace's customer agents in a full-height panel on the right edge (400 px), with the page's context. By default it pushes the page aside like Intercom's Fin side panel: the page stays visible and usable, no dim. Phones get a full-screen sheet. Agents can also reach out first with a message card above the launcher that opens the panel with their message in the thread. Plan: decision 13 of the Kai re-release (contract in.handover/kai-build/sidekick.md).API
All of it is additive: nothing changes for a page that never calls the sidekick and gets no sidekick trigger.
Layout
<html>on the panel's side (never a transform), no backdrop,aria-modal="false", Escape inside a page field stays the page's. Fixed headers and footers shrink along: everyposition: fixedelement spanning the viewport (left ≈ 0 and right ≈ the edge, or ≥ 90vw) gets inlineleft/widthon the panel's side while pushed, slides with the page, and gets its previous inline values back exactly on close. A throttled MutationObserver handles fixed elements added (or turned fixed) while open; resizes re-measure. Gleap's own elements and the backdrop are skipped.mode: 'overlay'), when the page would get narrower than 720 px, and by default on a page inside an iframe (mode: 'push'forces the push there).sidekick-openedsays why (pushFallback: 'iframe').<html>inline styles, the fixed bars' inline styles, scroll position, focus, launcher. Other unread notifications hide while the panel is open and come back afterwards.Message cards
<button>, a polite live region announces it, reduced motion is respected. CSS goes through the SDK's existing injected stylesheet (CSP nonce); runtime styles only via CSSOM.operatorName/operatorAvatarImage), as the classic chat notification shows AI messages.Proactive messages from the socket
The socket announces
sidekickand the newsidekick-card. Asidekickmessage carriesdisplay: 'card' | 'open'(no display = open, the earlier protocol). Cards wait for nothing; opens keep the typing / hidden-tab waits. Both: at most one per page view, never over something else, quiet for a day after a dismissal, respectsetSidekickProactive(false); cards also respect disabled in-app notifications. The server sends cards / opens only to sockets that announced them; every other client gets the classic in-app conversation instead (Serverfeat/redesign-rerelease).Backwards compatible
startAgentand the AI bar are untouched; a Messenger build without the sidekick cap in its ping makesopenSidekick(and a card click) fall back tostartAgent.Verified
npm test: 35 suites, 598 tests (GleapSidekickRules.test.js: envelope, push-risk decisions, card parsing, proactive guards).npm run buildpasses (build outputs not committed)..handover/kai-build/shots/sidekick/.<html>inline style, scroll), a fixed bar added while open adjusted and restored, overlay at ~1000 px, a card on a 375/390 px phone opening the full-screen sheet with the message in the thread. Screenshots:.handover/kai-build/shots/sidekick/r3-*.Not in this PR
No version bump or release. Needs GleapSDK/Messenger-App#268 deployed first (older Messenger builds fall back to
startAgent) and the Server side (infeat/redesign-rerelease) for context, cards and proactive messages.🤖 Generated with Claude Code