@syntrologie/adapt-chatbot 2.44.0 → 2.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AdaptiveChatBar.d.ts.map +1 -1
- package/dist/AdaptiveChatBar.js +3 -3
- package/dist/AdaptiveChatTrail.d.ts +17 -2
- package/dist/AdaptiveChatTrail.d.ts.map +1 -1
- package/dist/AdaptiveChatTrail.js +2 -2
- package/dist/AdaptiveChatTrail.live-region.test.d.ts +2 -0
- package/dist/AdaptiveChatTrail.live-region.test.d.ts.map +1 -0
- package/dist/ChatAssistantLit.js +2 -2
- package/dist/ChatTransport.d.ts.map +1 -1
- package/dist/LeaveAMessageLit.d.ts +40 -0
- package/dist/LeaveAMessageLit.d.ts.map +1 -1
- package/dist/{chunk-3JCJDTHS.js → chunk-3ZF4VCPX.js} +2 -1
- package/dist/{chunk-3JCJDTHS.js.map → chunk-3ZF4VCPX.js.map} +2 -2
- package/dist/{chunk-EKGGGUI2.js → chunk-7TT7YYML.js} +143 -78
- package/dist/chunk-7TT7YYML.js.map +7 -0
- package/dist/{chunk-FXHYE6FY.js → chunk-MRHETSTW.js} +22 -3
- package/dist/{chunk-FXHYE6FY.js.map → chunk-MRHETSTW.js.map} +2 -2
- package/dist/{chunk-VZIUXXAM.js → chunk-TZA7572J.js} +93 -30
- package/dist/chunk-TZA7572J.js.map +7 -0
- package/dist/runtime.js +82 -4
- package/dist/runtime.js.map +2 -2
- package/package.json +1 -1
- package/dist/chunk-EKGGGUI2.js.map +0 -7
- package/dist/chunk-VZIUXXAM.js.map +0 -7
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
renderMarkdown
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TZA7572J.js";
|
|
4
4
|
|
|
5
5
|
// src/AdaptiveChatTrail.ts
|
|
6
6
|
import { css, html, LitElement, nothing } from "lit";
|
|
7
|
+
import { repeat } from "lit/directives/repeat.js";
|
|
7
8
|
import { styleMap } from "lit/directives/style-map.js";
|
|
8
9
|
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
9
10
|
var DEFAULT_VISIBLE = 3;
|
|
@@ -301,6 +302,7 @@ var _AdaptiveChatTrail = class _AdaptiveChatTrail extends LitElement {
|
|
|
301
302
|
data-trail-thinking
|
|
302
303
|
data-role="assistant"
|
|
303
304
|
data-status="thinking"
|
|
305
|
+
aria-live="off"
|
|
304
306
|
aria-label=${// The accessible name is the sentence on screen. When the dots are the
|
|
305
307
|
// only visual there is no sentence to mirror, so name the state with
|
|
306
308
|
// the SAME verb the visible copy uses ("typing", not "thinking").
|
|
@@ -624,9 +626,31 @@ var _AdaptiveChatTrail = class _AdaptiveChatTrail extends LitElement {
|
|
|
624
626
|
>
|
|
625
627
|
</button>`;
|
|
626
628
|
}
|
|
629
|
+
/**
|
|
630
|
+
* The conversation live region.
|
|
631
|
+
*
|
|
632
|
+
* Always rendered, in EVERY branch of `render()` — including the ones that
|
|
633
|
+
* paint no transcript at all. A live region must already be in the DOM when
|
|
634
|
+
* its first child arrives; one created in the same mutation as its content
|
|
635
|
+
* is not reliably announced by NVDA or JAWS (adversarial review I3), and the
|
|
636
|
+
* content that would be lost is the assistant's first reply of the session.
|
|
637
|
+
*
|
|
638
|
+
* `display: contents` means it contributes no box and no layout anywhere it
|
|
639
|
+
* is mounted, so it is safe to place in an empty-state hero or in the flex
|
|
640
|
+
* scroll container alike. In the empty states it is rendered LAST so it can
|
|
641
|
+
* never become the `:first-child` any layout rule targets.
|
|
642
|
+
*/
|
|
643
|
+
_renderConversationLog(children) {
|
|
644
|
+
return html`<div
|
|
645
|
+
data-syntro-chat-log
|
|
646
|
+
role="log"
|
|
647
|
+
aria-label="Conversation"
|
|
648
|
+
style="display:contents"
|
|
649
|
+
>${children}</div>`;
|
|
650
|
+
}
|
|
627
651
|
render() {
|
|
628
652
|
if (this.messages.length === 0 && !this.greeting && !this.introSuggestion && this.tileReceipts.length === 0 && this.inlineWidgets.length === 0)
|
|
629
|
-
return nothing;
|
|
653
|
+
return this._renderConversationLog(nothing);
|
|
630
654
|
if (this.messages.length === 0 && (this.greeting || this.introSuggestion)) {
|
|
631
655
|
return html`<div data-syntro-chat-trail data-state="empty" style=${styleMap({
|
|
632
656
|
display: "flex",
|
|
@@ -660,6 +684,7 @@ var _AdaptiveChatTrail = class _AdaptiveChatTrail extends LitElement {
|
|
|
660
684
|
>${this.introSuggestion.label}</button>` : nothing}
|
|
661
685
|
${this._renderReceiptStrip(this.tileReceipts)}
|
|
662
686
|
${this._renderInlineWidgetStrip(this.inlineWidgets)}
|
|
687
|
+
${this._renderConversationLog(nothing)}
|
|
663
688
|
</div>`;
|
|
664
689
|
}
|
|
665
690
|
if (this.messages.length === 0 && (this.tileReceipts.length > 0 || this.inlineWidgets.length > 0)) {
|
|
@@ -674,6 +699,7 @@ var _AdaptiveChatTrail = class _AdaptiveChatTrail extends LitElement {
|
|
|
674
699
|
})}>
|
|
675
700
|
${this._renderReceiptStrip(this.tileReceipts)}
|
|
676
701
|
${this._renderInlineWidgetStrip(this.inlineWidgets)}
|
|
702
|
+
${this._renderConversationLog(nothing)}
|
|
677
703
|
</div>`;
|
|
678
704
|
}
|
|
679
705
|
let turnReplies = [];
|
|
@@ -809,39 +835,11 @@ var _AdaptiveChatTrail = class _AdaptiveChatTrail extends LitElement {
|
|
|
809
835
|
position: "relative",
|
|
810
836
|
width: "100%"
|
|
811
837
|
};
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
// z-index:2 inside the frame) doesn't cover it. Shown whenever
|
|
818
|
-
// there's anything in the trail — the user expects this affordance
|
|
819
|
-
// available regardless of how many chips are on screen.
|
|
820
|
-
// When ``forceExpanded`` is set by the host (full-screen panel,
|
|
821
|
-
// etc.), there's nowhere to collapse INTO and the affordance
|
|
822
|
-
// would just confuse the user — suppress it entirely.
|
|
823
|
-
this.messages.length === 0 || this.forceExpanded ? nothing : this.expanded ? html`<button
|
|
824
|
-
type="button"
|
|
825
|
-
data-trail-toggle
|
|
826
|
-
data-trail-collapse
|
|
827
|
-
@click=${this._onCollapse}
|
|
828
|
-
style=${styleMap(moreStyles())}
|
|
829
|
-
>⌄ minimize</button>` : html`<button
|
|
830
|
-
type="button"
|
|
831
|
-
data-trail-toggle
|
|
832
|
-
data-trail-more
|
|
833
|
-
@click=${this._onExpand}
|
|
834
|
-
style=${styleMap(moreStyles())}
|
|
835
|
-
>${hidden > 0 ? html`↑ ${hidden} more · expand` : html`↑ expand`}</button>`}
|
|
836
|
-
<div data-syntro-chat-trail-frame style=${styleMap(frameStyles)}>
|
|
837
|
-
<div
|
|
838
|
-
data-syntro-chat-trail
|
|
839
|
-
style=${styleMap(containerStyles)}
|
|
840
|
-
@scroll=${this._onTrailScroll}
|
|
841
|
-
@wheel=${this._markUserScrollIntent}
|
|
842
|
-
@touchmove=${this._markUserScrollIntent}
|
|
843
|
-
>
|
|
844
|
-
${visible.map((m, i) => {
|
|
838
|
+
const isStreamingMsg = (m) => m.role === "assistant" && m.status === "streaming";
|
|
839
|
+
const lastVisible = visible[visible.length - 1];
|
|
840
|
+
const streamingTail = lastVisible !== void 0 && isStreamingMsg(lastVisible);
|
|
841
|
+
const strandedStreaming = (m, i) => isStreamingMsg(m) && !(streamingTail && i === visible.length - 1);
|
|
842
|
+
const renderChip = (m, i) => {
|
|
845
843
|
const pos = this.expanded || this.forceExpanded ? 0 : visible.length - 1 - i;
|
|
846
844
|
const state = chipVisualState(m);
|
|
847
845
|
const isStreaming = state.kind === "streaming";
|
|
@@ -861,61 +859,112 @@ var _AdaptiveChatTrail = class _AdaptiveChatTrail extends LitElement {
|
|
|
861
859
|
animation: "syntro-trail-chip-enter 220ms cubic-bezier(0.22, 1, 0.36, 1) both"
|
|
862
860
|
} : chipStyles(state, pos);
|
|
863
861
|
const personaByline = this.personaName && this._isAssistantTurnStart(m) ? html`<div data-trail-persona-byline style=${styleMap(personaBylineStyles())}>
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
862
|
+
${this.personaAvatarSm ? html`<img
|
|
863
|
+
data-trail-persona-avatar
|
|
864
|
+
src=${this.personaAvatarSm}
|
|
865
|
+
alt=""
|
|
866
|
+
style=${styleMap(personaAvatarStyles())}
|
|
867
|
+
/>` : nothing}<span>${this.personaName}</span>
|
|
868
|
+
</div>` : nothing;
|
|
871
869
|
return html`<div
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
870
|
+
data-trail-chip
|
|
871
|
+
data-trail-chip-id=${String(m.id)}
|
|
872
|
+
data-role=${m.role}
|
|
873
|
+
data-status=${m.status ?? "complete"}
|
|
874
|
+
aria-hidden=${strandedStreaming(m, i) ? "true" : nothing}
|
|
875
|
+
?inert=${strandedStreaming(m, i)}
|
|
876
|
+
style=${styleMap(chipStyle)}
|
|
877
|
+
>${personaByline}${renderedText}${isStreaming ? html`<span
|
|
878
|
+
data-trail-caret
|
|
879
|
+
aria-hidden="true"
|
|
880
|
+
style=${styleMap(caretStyles())}
|
|
881
|
+
></span>` : nothing}${toolCalls.length > 0 ? html`<div data-trail-toolcalls style=${styleMap(toolCallStripStyles())}>
|
|
882
|
+
${toolCalls.map(
|
|
883
883
|
(tc) => html`<button
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
884
|
+
type="button"
|
|
885
|
+
data-trail-toolcall
|
|
886
|
+
data-tool-id=${tc.id}
|
|
887
|
+
data-tool-status=${tc.status}
|
|
888
|
+
@click=${() => this._onToolCallClick(tc)}
|
|
889
|
+
style=${styleMap(pendingToolCallChipStyles())}
|
|
890
|
+
title="${tc.name} · ${tc.status}"
|
|
891
|
+
>? ${tc.name}</button>`
|
|
892
892
|
)}
|
|
893
|
-
|
|
894
|
-
|
|
893
|
+
</div>` : nothing}${receipts.length > 0 ? html`<div data-trail-receipts style=${styleMap(receiptStripStyles())}>
|
|
894
|
+
${receipts.map(
|
|
895
895
|
(r) => html`<div
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
896
|
+
data-trail-receipt
|
|
897
|
+
data-receipt-type=${r.type}
|
|
898
|
+
style=${styleMap(receiptStyles())}
|
|
899
|
+
><span aria-hidden="true" style=${styleMap(receiptIconStyles())}>✓</span
|
|
900
|
+
><span>${receiptText(r)}</span></div>`
|
|
901
901
|
)}
|
|
902
|
-
|
|
903
|
-
|
|
902
|
+
</div>` : nothing}${replyChips.length > 0 ? html`<div data-trail-reply-chips style=${styleMap(replyChipStripStyles())}>
|
|
903
|
+
${replyChips.map(
|
|
904
904
|
(reply) => html`<button
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
905
|
+
type="button"
|
|
906
|
+
data-trail-reply-chip
|
|
907
|
+
@click=${() => this._onSuggestedReplyClick(reply)}
|
|
908
|
+
style=${styleMap(replyChipStyles())}
|
|
909
|
+
>${reply}</button>`
|
|
910
910
|
)}
|
|
911
|
-
|
|
911
|
+
</div>` : nothing}</div>${// Receipt chips that mounted while THIS message was newest render
|
|
912
912
|
// inline right here, so they read as part of the flow and drift up
|
|
913
913
|
// as later messages append below them.
|
|
914
914
|
this._renderReceiptStrip(receiptsByAnchor.get(m.id) ?? [])}${// Inline widgets (reco carousel) anchored to this message render
|
|
915
915
|
// right here in the conversation flow — the whole point of the
|
|
916
916
|
// chat-inline slot: visible in the trail, not behind the panel.
|
|
917
917
|
this._renderInlineWidgetStrip(inlineByAnchor.get(m.id) ?? [])}`;
|
|
918
|
-
}
|
|
918
|
+
};
|
|
919
|
+
const committed = streamingTail ? visible.slice(0, -1) : visible;
|
|
920
|
+
const committedChips = repeat(
|
|
921
|
+
committed,
|
|
922
|
+
(m) => m.id,
|
|
923
|
+
(m, i) => renderChip(m, i)
|
|
924
|
+
);
|
|
925
|
+
const streamingChip = streamingTail ? renderChip(lastVisible, visible.length - 1) : nothing;
|
|
926
|
+
return html`
|
|
927
|
+
${// Single toggle button above the frame. Same DOM node morphs:
|
|
928
|
+
// collapsed → "↑ N more · expand" / "↑ expand" (calls _onExpand)
|
|
929
|
+
// expanded → "⌄ minimize" (calls _onCollapse)
|
|
930
|
+
// Lives OUTSIDE the frame so the absolute blur veil (top:0,
|
|
931
|
+
// z-index:2 inside the frame) doesn't cover it. Shown whenever
|
|
932
|
+
// there's anything in the trail — the user expects this affordance
|
|
933
|
+
// available regardless of how many chips are on screen.
|
|
934
|
+
// When ``forceExpanded`` is set by the host (full-screen panel,
|
|
935
|
+
// etc.), there's nowhere to collapse INTO and the affordance
|
|
936
|
+
// would just confuse the user — suppress it entirely.
|
|
937
|
+
this.messages.length === 0 || this.forceExpanded ? nothing : this.expanded ? html`<button
|
|
938
|
+
type="button"
|
|
939
|
+
data-trail-toggle
|
|
940
|
+
data-trail-collapse
|
|
941
|
+
@click=${this._onCollapse}
|
|
942
|
+
style=${styleMap(moreStyles())}
|
|
943
|
+
>⌄ minimize</button>` : html`<button
|
|
944
|
+
type="button"
|
|
945
|
+
data-trail-toggle
|
|
946
|
+
data-trail-more
|
|
947
|
+
@click=${this._onExpand}
|
|
948
|
+
style=${styleMap(moreStyles())}
|
|
949
|
+
>${hidden > 0 ? html`↑ ${hidden} more · expand` : html`↑ expand`}</button>`}
|
|
950
|
+
<div data-syntro-chat-trail-frame style=${styleMap(frameStyles)}>
|
|
951
|
+
<div
|
|
952
|
+
data-syntro-chat-trail
|
|
953
|
+
style=${styleMap(containerStyles)}
|
|
954
|
+
@scroll=${this._onTrailScroll}
|
|
955
|
+
@wheel=${this._markUserScrollIntent}
|
|
956
|
+
@touchmove=${this._markUserScrollIntent}
|
|
957
|
+
>
|
|
958
|
+
<!-- Committed transcript. Rendered UNCONDITIONALLY, even empty: a live
|
|
959
|
+
region has to be in the DOM before its first child arrives or the
|
|
960
|
+
announcement is dropped (review I3), and the first assistant reply
|
|
961
|
+
of a session is exactly the one that matters. display:contents
|
|
962
|
+
keeps the scroll container's flex layout byte-identical — the
|
|
963
|
+
wrapper is a semantic node only, which is why the bottom-anchor
|
|
964
|
+
rule reaches through it, and past it while it is still empty. -->
|
|
965
|
+
${this._renderConversationLog(committedChips)}
|
|
966
|
+
${// The in-flight reply: same slot on screen, outside the log.
|
|
967
|
+
streamingChip}
|
|
919
968
|
${// Thinking indicator — fills the gap between the user's
|
|
920
969
|
// most recent message and the assistant's first token.
|
|
921
970
|
// Shows when chatSession.inFlight is true AND the last
|
|
@@ -992,6 +1041,22 @@ _AdaptiveChatTrail.styles = css`
|
|
|
992
1041
|
[data-syntro-chat-trail]:not([data-state="empty"]) > :first-child {
|
|
993
1042
|
margin-top: auto;
|
|
994
1043
|
}
|
|
1044
|
+
/* …and THROUGH the conversation-log wrapper. That wrapper is
|
|
1045
|
+
display: contents (a semantic node carrying role=log, see render), so
|
|
1046
|
+
margin on it does nothing — the auto margin has to land on the first
|
|
1047
|
+
real chip inside it or a short thread floats to the top of a tall
|
|
1048
|
+
panel instead of hugging the composer. */
|
|
1049
|
+
[data-syntro-chat-trail]:not([data-state="empty"]) > [data-syntro-chat-log] > :first-child {
|
|
1050
|
+
margin-top: auto;
|
|
1051
|
+
}
|
|
1052
|
+
/* …and PAST it while it is still empty. The wrapper is always rendered (it
|
|
1053
|
+
is a live region, which must pre-exist its content), so with only an
|
|
1054
|
+
in-flight reply on screen the wrapper IS the :first-child and has no box
|
|
1055
|
+
to carry the margin. :empty ignores comment nodes, so Lit's own markers
|
|
1056
|
+
inside the wrapper do not defeat it. */
|
|
1057
|
+
[data-syntro-chat-trail]:not([data-state="empty"]) > [data-syntro-chat-log]:empty + * {
|
|
1058
|
+
margin-top: auto;
|
|
1059
|
+
}
|
|
995
1060
|
[data-trail-chip] > p:first-child {
|
|
996
1061
|
margin-top: 0;
|
|
997
1062
|
}
|
|
@@ -1766,4 +1831,4 @@ export {
|
|
|
1766
1831
|
AdaptiveChatTrail,
|
|
1767
1832
|
looksLikeSerializedModelResponse
|
|
1768
1833
|
};
|
|
1769
|
-
//# sourceMappingURL=chunk-
|
|
1834
|
+
//# sourceMappingURL=chunk-7TT7YYML.js.map
|