import{type TemplateResult,type PropertyValues}from'lit';import{LyraElement}from'../../../internal/lyra-element.js';import type{LyraFrame}from'../../../internal/variants.js';import type{LyraTranscriptMode}from'../../../internal/shared-unions.js'; /** Whether the panel is streaming a run live or replaying a finished one -- the library's shared * transcript-mode vocabulary, identical to ``'s `ActivityFeedMode`. */ export type ThinkingPanelMode=LyraTranscriptMode; /** Visual chrome for ``'s root — the library's shared container-frame vocabulary. */ export type ThinkingPanelAppearance=LyraFrame;export interface ThinkingPanelToggleDetail{expanded:boolean;}export interface LyraThinkingPanelEventMap{'lr-toggle-request':CustomEvent;'lr-toggle':CustomEvent;'lr-follow-change':CustomEvent<{following:boolean;}>;} /** * `` — a collapsible panel for an AI agent's * intermediate reasoning/"thinking" transcript, kept visually and * semantically distinct from its final response. Same collapsible * header-button-plus-region shape as ``; the default slot * is entirely free-form (a consumer-composed ``, * ``, or plain text) — this component has no dependency on * either and imposes no structure on what's slotted. * * `compact` tightens the header and transcript-body padding for dense * transcript rows. `frame="plain"` removes the outside card chrome when a * containing message or panel already supplies it; the header/body divider * and their layout remain, so the disclosure keeps its internal structure. * * `mode` (`'live'` while reasoning is actively streaming in, `'post-hoc'` * once it's complete and being reviewed after the fact) drives two concrete * behavior differences, not just a styling hook: * - **Header hint.** While `duration-ms` is unset, `'live'` shows a pulsing * "Thinking…" placeholder in `[part="duration"]`; `'post-hoc'` shows * nothing there instead (a finished review with no known duration has * nothing useful to say in that slot). Once `duration-ms` is set, both * modes show the same static `"Thought for …"` text — a `'post-hoc'` * consumer that captured a duration is free to supply it too. * - **Auto-scroll.** Only `'live'` mode auto-follows new content appended to * the default slot while `expanded` (see below); `'post-hoc'` never * scrolls on its own, since reviewing finished reasoning is expected to * start from the top like reading any other completed document. This * library otherwise defaults to *not* editorializing about a host's data * (see ``'s plain-`description` stance), but scroll position * is presentation, not data, so this one behavior difference earns its * keep rather than being left as a bare visual/semantic hint the host * would have to reimplement identically itself. * * Live-mode auto-scroll ("stick to bottom") is the classic chat-transcript * convention: while `mode="live"` and `expanded`, new content keeps the * panel scrolled to its latest line — *unless* the user has manually * scrolled up to (re-)read earlier content, in which case their position is * never yanked away from them. This is tracked continuously via a `scroll` * listener on `[part="body"]` (not recomputed from the mutation itself, * which necessarily observes the DOM only *after* it has already changed): * every user-driven scroll updates the public `follow` state to record whether the body was left within * `NEAR_BOTTOM_PX` of its own max scroll position, and only a mutation that * arrives while that's still true triggers a follow-up scroll-to-bottom. * Opening an already-`'live'` panel (or one that later becomes `'live'`) * always resets this to "anchored" and jumps to the latest content, the same * way a chat app's own transcript does when you re-open it. * * New content is detected two ways, both feeding the same coalesced scroll-to-bottom (a mutation * and a settle event landing in the same animation frame never double-scroll): * - A `MutationObserver` on this element's own light DOM (`childList`+`subtree`+`characterData`) * rather than the default slot's `slotchange` event, because `slotchange` only fires when the * set of top-level assigned nodes changes — never for a text node mutating *inside* an * already-slotted element, which is the shape a consumer literally appending chunks to a plain * light-DOM node produces. This cannot see a mutation entirely inside a slotted custom * element's own shadow root (e.g. `` re-rendering its shadow tree after a * `content` property change) — Shadow DOM encapsulation blocks that by design. * - A listener for `lr-content-settled`, a composed, bubbling, signal-only event * (`detail: null`) this library's own streaming renderers — ``, * ``, `` — emit at their own settle points. Being composed, it * crosses exactly the shadow boundary the `MutationObserver` above cannot, covering every * property- or attribute-driven producer that renders into its own shadow root instead of * mutating visible light-DOM text. * * A slotted element that is neither a plain light-DOM text producer nor one of this library's own * streaming renderers — a bespoke custom element that re-renders its own shadow tree from a * property change — needs to append/mutate visible light-DOM text itself, emit its own * `lr-content-settled`, or have the host call this panel's own `scrollToBottom()` directly. * * `aria-controls` linking the header to the body region uses `nextId()` * (`../../internal/a11y.js`) for a collision-safe id, the same convention * `` and `` already establish for every * toggle-controls-region pairing in this library. * * @customElement lr-thinking-panel * @slot - The reasoning/thinking content. * @event lr-toggle-request - Cancelable proposal emitted before a header activation changes * `expanded`. `detail: { expanded }` carries the requested next state. * @event lr-toggle - The accepted header request committed. `detail: { expanded }` carries the * new state and is never emitted for a vetoed proposal. * @event lr-follow-change - `detail: { following }`; emitted only when a user scroll releases or * re-engages tail following. Direct `follow` assignment and `scrollToBottom()` do not echo it. * @csspart base - The outer container. * @csspart header - The clickable header (`