@helpai/elements 0.12.3 → 0.13.1
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/configurator.mjs +171 -87
- package/elements-web-component.esm.js +27 -27
- package/elements-web-component.esm.js.map +4 -4
- package/elements.cjs.js +27 -27
- package/elements.cjs.js.map +4 -4
- package/elements.esm.js +27 -27
- package/elements.esm.js.map +4 -4
- package/elements.js +28 -28
- package/elements.js.map +4 -4
- package/index.d.ts +143 -2
- package/index.mjs +1469 -502
- package/package.json +1 -1
- package/schema.d.ts +155 -30
- package/schema.json +476 -3
- package/schema.mjs +178 -89
- package/style.css +1 -1
- package/web-component.mjs +1486 -523
package/web-component.mjs
CHANGED
|
@@ -6,8 +6,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6
6
|
import { h as h2, render as render2 } from "preact";
|
|
7
7
|
|
|
8
8
|
// src/ui/app.tsx
|
|
9
|
-
import { useCallback as useCallback6, useEffect as useEffect17, useMemo as useMemo3, useRef as useRef8, useState as
|
|
10
|
-
import { useSignal } from "@preact/signals";
|
|
9
|
+
import { useCallback as useCallback6, useEffect as useEffect17, useMemo as useMemo3, useRef as useRef8, useState as useState13 } from "preact/hooks";
|
|
10
|
+
import { useSignal as useSignal2 } from "@preact/signals";
|
|
11
11
|
|
|
12
12
|
// src/core/brand.ts
|
|
13
13
|
var BRAND = {
|
|
@@ -105,15 +105,154 @@ var STRINGS_EN = {
|
|
|
105
105
|
newsEmpty: "No news yet",
|
|
106
106
|
newsLoading: "Loading news\u2026",
|
|
107
107
|
newsBack: "Back to news",
|
|
108
|
-
newsPublishedAt: "Published {date}"
|
|
108
|
+
newsPublishedAt: "Published {date}",
|
|
109
|
+
// ── Forms + human-in-the-loop (intake / ask-input / approval) ───
|
|
110
|
+
intakeSubmit: "Start chat",
|
|
111
|
+
intakeSkip: "Skip for now",
|
|
112
|
+
formRequired: "This field is required",
|
|
113
|
+
formInvalidEmail: "Enter a valid email address",
|
|
114
|
+
formInvalidTel: "Enter a valid phone number",
|
|
115
|
+
formInvalidUrl: "Enter a valid URL",
|
|
116
|
+
formInvalidNumber: "Enter a valid number",
|
|
117
|
+
formTooShort: "Too short (min {min} characters)",
|
|
118
|
+
formTooLong: "Too long (max {max} characters)",
|
|
119
|
+
formNumberTooSmall: "Must be at least {min}",
|
|
120
|
+
formNumberTooLarge: "Must be at most {max}",
|
|
121
|
+
formPatternMismatch: "Please match the requested format",
|
|
122
|
+
formChooseAtLeast: "Choose at least {min}",
|
|
123
|
+
formChooseAtMost: "Choose at most {max}",
|
|
124
|
+
formOther: "Other",
|
|
125
|
+
formOtherPlaceholder: "Type your answer\u2026",
|
|
126
|
+
inputRequired: "Input required",
|
|
127
|
+
inputSubmit: "Submit",
|
|
128
|
+
inputSkip: "Skip",
|
|
129
|
+
inputSubmitted: "Answer submitted",
|
|
130
|
+
approvalRequired: "Approval required",
|
|
131
|
+
approve: "Approve",
|
|
132
|
+
reject: "Reject",
|
|
133
|
+
approved: "Approved",
|
|
134
|
+
rejected: "Rejected",
|
|
135
|
+
approvalReason: "Add a reason (optional)",
|
|
136
|
+
stepNoLongerActive: "This request is no longer active."
|
|
137
|
+
};
|
|
138
|
+
var STRINGS_FR = {
|
|
139
|
+
attach: "Joindre des fichiers",
|
|
140
|
+
attachmentMimeRejected: "Type de fichier non pris en charge",
|
|
141
|
+
attachmentTooLarge: "Le fichier est trop volumineux",
|
|
142
|
+
attachmentTooMany: "Limite de pi\xE8ces jointes atteinte",
|
|
143
|
+
chatClosed: "Cette conversation est ferm\xE9e",
|
|
144
|
+
close: "Fermer",
|
|
145
|
+
collapse: "R\xE9duire",
|
|
146
|
+
collapseSidebar: "R\xE9duire la barre lat\xE9rale",
|
|
147
|
+
composerPlaceholder: "\xC9crivez un message\u2026",
|
|
148
|
+
dateLastWeek: "7 derniers jours",
|
|
149
|
+
dateOlder: "Plus ancien",
|
|
150
|
+
dateToday: "Aujourd'hui",
|
|
151
|
+
dateYesterday: "Hier",
|
|
152
|
+
dropZone: "D\xE9posez les fichiers \xE0 joindre",
|
|
153
|
+
errorGeneric: "Une erreur s'est produite",
|
|
154
|
+
errorRateLimited: "Trop de requ\xEAtes \u2014 veuillez r\xE9essayer dans un instant.",
|
|
155
|
+
errorRetry: "R\xE9essayer",
|
|
156
|
+
expand: "Agrandir",
|
|
157
|
+
expandSidebar: "D\xE9velopper la barre lat\xE9rale",
|
|
158
|
+
exitFullscreen: "Quitter le plein \xE9cran",
|
|
159
|
+
fullscreen: "Plein \xE9cran",
|
|
160
|
+
history: "Historique",
|
|
161
|
+
historyBack: "Retour au chat",
|
|
162
|
+
historyEmpty: "Aucune conversation pour le moment",
|
|
163
|
+
historyLoading: "Chargement de vos conversations\u2026",
|
|
164
|
+
historyNewChat: "Nouvelle conversation",
|
|
165
|
+
historyTitle: "Historique des conversations",
|
|
166
|
+
language: "Langue",
|
|
167
|
+
launcherOpen: "Ouvrir le chat",
|
|
168
|
+
messagesLoading: "Chargement de la conversation\u2026",
|
|
169
|
+
micStart: "D\xE9marrer la saisie vocale",
|
|
170
|
+
micStop: "Arr\xEAter la saisie vocale",
|
|
171
|
+
micUnsupported: "La saisie vocale n'est pas prise en charge par ce navigateur",
|
|
172
|
+
moreActions: "Plus d'actions",
|
|
173
|
+
newConversation: "Nouvelle conversation",
|
|
174
|
+
panelTitle: "Chat",
|
|
175
|
+
popOut: "Ouvrir dans un nouvel onglet",
|
|
176
|
+
resizeHandle: "Glisser pour redimensionner",
|
|
177
|
+
scrollToBottom: "Aller au plus r\xE9cent",
|
|
178
|
+
send: "Envoyer",
|
|
179
|
+
soundOff: "Son d\xE9sactiv\xE9",
|
|
180
|
+
soundOn: "Son activ\xE9",
|
|
181
|
+
startNewConversation: "D\xE9marrer une nouvelle conversation",
|
|
182
|
+
stop: "Arr\xEAter",
|
|
183
|
+
theme: "Th\xE8me",
|
|
184
|
+
themeAuto: "Auto (syst\xE8me)",
|
|
185
|
+
themeDark: "Sombre",
|
|
186
|
+
themeLight: "Clair",
|
|
187
|
+
loading: "Chargement\u2026",
|
|
188
|
+
thinking: "R\xE9flexion\u2026",
|
|
189
|
+
thoughts: "R\xE9flexions",
|
|
190
|
+
usedTool: "Outil utilis\xE9",
|
|
191
|
+
// ── Messenger modules ──────────────────────────────────────────
|
|
192
|
+
tabHome: "Accueil",
|
|
193
|
+
tabMessages: "Messages",
|
|
194
|
+
tabHelp: "Aide",
|
|
195
|
+
tabNews: "Actualit\xE9s",
|
|
196
|
+
modulesEmpty: "Rien pour le moment",
|
|
197
|
+
moduleBack: "Retour",
|
|
198
|
+
contentLoading: "Chargement\u2026",
|
|
199
|
+
homeGreeting: "Comment pouvons-nous vous aider ?",
|
|
200
|
+
homeGreetingNamed: "Bonjour {name} \u{1F44B}",
|
|
201
|
+
homeGreetingLead: "Comment pouvons-nous vous aider ?",
|
|
202
|
+
homeSearchPlaceholder: "Rechercher de l'aide",
|
|
203
|
+
homeContentTitle: "Articles populaires",
|
|
204
|
+
helpTitle: "Aide",
|
|
205
|
+
helpSearchPlaceholder: "Rechercher de l'aide",
|
|
206
|
+
helpEmpty: "Aucun article d'aide pour le moment",
|
|
207
|
+
helpLoading: "Chargement de l'aide\u2026",
|
|
208
|
+
helpSearchEmpty: "Aucun r\xE9sultat trouv\xE9",
|
|
209
|
+
newsTitle: "Actualit\xE9s",
|
|
210
|
+
newsEmpty: "Aucune actualit\xE9 pour le moment",
|
|
211
|
+
newsLoading: "Chargement des actualit\xE9s\u2026",
|
|
212
|
+
newsBack: "Retour aux actualit\xE9s",
|
|
213
|
+
newsPublishedAt: "Publi\xE9 le {date}",
|
|
214
|
+
// ── Forms + human-in-the-loop (intake / ask-input / approval) ───
|
|
215
|
+
intakeSubmit: "D\xE9marrer le chat",
|
|
216
|
+
intakeSkip: "Ignorer pour l'instant",
|
|
217
|
+
formRequired: "Ce champ est obligatoire",
|
|
218
|
+
formInvalidEmail: "Saisissez une adresse e-mail valide",
|
|
219
|
+
formInvalidTel: "Saisissez un num\xE9ro de t\xE9l\xE9phone valide",
|
|
220
|
+
formInvalidUrl: "Saisissez une URL valide",
|
|
221
|
+
formInvalidNumber: "Saisissez un nombre valide",
|
|
222
|
+
formTooShort: "Trop court (min. {min} caract\xE8res)",
|
|
223
|
+
formTooLong: "Trop long (max. {max} caract\xE8res)",
|
|
224
|
+
formNumberTooSmall: "Doit \xEAtre au moins {min}",
|
|
225
|
+
formNumberTooLarge: "Doit \xEAtre au plus {max}",
|
|
226
|
+
formPatternMismatch: "Veuillez respecter le format demand\xE9",
|
|
227
|
+
formChooseAtLeast: "Choisissez au moins {min}",
|
|
228
|
+
formChooseAtMost: "Choisissez au plus {max}",
|
|
229
|
+
formOther: "Autre",
|
|
230
|
+
formOtherPlaceholder: "Saisissez votre r\xE9ponse\u2026",
|
|
231
|
+
inputRequired: "Saisie requise",
|
|
232
|
+
inputSubmit: "Envoyer",
|
|
233
|
+
inputSkip: "Ignorer",
|
|
234
|
+
inputSubmitted: "R\xE9ponse envoy\xE9e",
|
|
235
|
+
approvalRequired: "Approbation requise",
|
|
236
|
+
approve: "Approuver",
|
|
237
|
+
reject: "Refuser",
|
|
238
|
+
approved: "Approuv\xE9",
|
|
239
|
+
rejected: "Refus\xE9",
|
|
240
|
+
approvalReason: "Ajouter une raison (facultatif)",
|
|
241
|
+
stepNoLongerActive: "Cette demande n'est plus active."
|
|
242
|
+
};
|
|
243
|
+
var BUILTIN_STRINGS = {
|
|
244
|
+
en: STRINGS_EN,
|
|
245
|
+
fr: STRINGS_FR
|
|
109
246
|
};
|
|
110
247
|
function resolveStrings(locale, override) {
|
|
111
248
|
const tag = primaryTag(locale);
|
|
112
249
|
const isNested = isNestedShape(override);
|
|
250
|
+
const builtinLocale = tag === "en" ? {} : BUILTIN_STRINGS[tag] ?? {};
|
|
113
251
|
const localeOverride = isNested ? override[tag] ?? {} : override ?? {};
|
|
114
252
|
const enOverride = isNested ? override.en ?? {} : {};
|
|
115
253
|
return {
|
|
116
254
|
...STRINGS_EN,
|
|
255
|
+
...builtinLocale,
|
|
117
256
|
...enOverride,
|
|
118
257
|
...localeOverride
|
|
119
258
|
};
|
|
@@ -293,11 +432,14 @@ var DEFAULT_ATTACHMENTS = {
|
|
|
293
432
|
var DEFAULT_WELCOME = { animation: "typewriter", speed: 60 };
|
|
294
433
|
var DEFAULT_FEATURES = {
|
|
295
434
|
files: true,
|
|
296
|
-
voice: "local"
|
|
435
|
+
voice: "local",
|
|
436
|
+
humanInLoop: true
|
|
297
437
|
};
|
|
438
|
+
var DEFAULT_INTAKE = { enabled: false, fields: [], skippable: false };
|
|
298
439
|
var DEFAULT_ENDPOINTS = {
|
|
299
440
|
upload: "/ai/agent/upload-file",
|
|
300
|
-
transcribe: "/ai/agent/transcribe-audio"
|
|
441
|
+
transcribe: "/ai/agent/transcribe-audio",
|
|
442
|
+
intake: "/ai/agent/intake"
|
|
301
443
|
};
|
|
302
444
|
var DEFAULT_LAUNCHER = {
|
|
303
445
|
variant: "circle",
|
|
@@ -359,11 +501,14 @@ function resolveOptions(rawOpts) {
|
|
|
359
501
|
features: {
|
|
360
502
|
files: opts.features?.files ?? DEFAULT_FEATURES.files,
|
|
361
503
|
voice: opts.features?.voice ?? DEFAULT_FEATURES.voice,
|
|
504
|
+
humanInLoop: opts.features?.humanInLoop ?? DEFAULT_FEATURES.humanInLoop,
|
|
362
505
|
tools: opts.features?.tools
|
|
363
506
|
},
|
|
507
|
+
intake: resolveIntake(opts.intake),
|
|
364
508
|
endpoints: {
|
|
365
509
|
upload: opts.endpoints?.upload ?? DEFAULT_ENDPOINTS.upload,
|
|
366
|
-
transcribe: opts.endpoints?.transcribe ?? DEFAULT_ENDPOINTS.transcribe
|
|
510
|
+
transcribe: opts.endpoints?.transcribe ?? DEFAULT_ENDPOINTS.transcribe,
|
|
511
|
+
intake: opts.endpoints?.intake ?? DEFAULT_ENDPOINTS.intake
|
|
367
512
|
},
|
|
368
513
|
attachments: {
|
|
369
514
|
accept: opts.composer?.attachments?.accept ?? DEFAULT_ATTACHMENTS.accept,
|
|
@@ -462,6 +607,18 @@ function resolveModules(overrides) {
|
|
|
462
607
|
const byId = Object.fromEntries(list.map((m) => [m.id, m]));
|
|
463
608
|
return { list, byId };
|
|
464
609
|
}
|
|
610
|
+
function resolveIntake(overrides) {
|
|
611
|
+
const fields = (overrides?.fields ?? []).filter((f) => Boolean(f && f.name && f.label && f.type));
|
|
612
|
+
if (fields.length === 0) return DEFAULT_INTAKE;
|
|
613
|
+
return {
|
|
614
|
+
enabled: overrides?.enabled ?? false,
|
|
615
|
+
title: overrides?.title,
|
|
616
|
+
description: overrides?.description,
|
|
617
|
+
fields,
|
|
618
|
+
submitLabel: overrides?.submitLabel,
|
|
619
|
+
skippable: overrides?.skippable ?? false
|
|
620
|
+
};
|
|
621
|
+
}
|
|
465
622
|
function resolveLauncher(overrides) {
|
|
466
623
|
const callout = overrides?.callout?.text ? {
|
|
467
624
|
shape: "pill",
|
|
@@ -507,6 +664,7 @@ var SECTION_KEYS = [
|
|
|
507
664
|
"i18n",
|
|
508
665
|
"footer",
|
|
509
666
|
"features",
|
|
667
|
+
"intake",
|
|
510
668
|
"endpoints"
|
|
511
669
|
];
|
|
512
670
|
function mergeServerConfig(user, server) {
|
|
@@ -658,55 +816,55 @@ var REACTIVE_ATTRS = [
|
|
|
658
816
|
];
|
|
659
817
|
function parseAttributes(get) {
|
|
660
818
|
const opts = {};
|
|
661
|
-
const
|
|
819
|
+
const str2 = (name) => {
|
|
662
820
|
const v = get(name);
|
|
663
821
|
return v === null || v === "" ? void 0 : v;
|
|
664
822
|
};
|
|
665
823
|
for (const [attr, key, cast] of EMBED_SCALAR_ATTRS) {
|
|
666
|
-
const raw =
|
|
824
|
+
const raw = str2(attr);
|
|
667
825
|
if (raw === void 0) continue;
|
|
668
826
|
opts[key] = cast ? cast(raw) : raw;
|
|
669
827
|
}
|
|
670
|
-
const presentationFlat = collectSubset(
|
|
671
|
-
const size = collectSubset(
|
|
828
|
+
const presentationFlat = collectSubset(str2, PRESENTATION_ATTRS);
|
|
829
|
+
const size = collectSubset(str2, PRESENTATION_SIZE_ATTRS);
|
|
672
830
|
if (presentationFlat || size) {
|
|
673
831
|
opts.presentation = { ...presentationFlat, ...size ? { size } : {} };
|
|
674
832
|
}
|
|
675
|
-
const behavior = collectSubset(
|
|
833
|
+
const behavior = collectSubset(str2, BEHAVIOR_ATTRS);
|
|
676
834
|
if (behavior) opts.behavior = behavior;
|
|
677
|
-
const i18n = collectSubset(
|
|
835
|
+
const i18n = collectSubset(str2, I18N_ATTRS);
|
|
678
836
|
if (i18n) opts.i18n = i18n;
|
|
679
|
-
const launcher = parseLauncher(get,
|
|
837
|
+
const launcher = parseLauncher(get, str2);
|
|
680
838
|
if (launcher) opts.launcher = launcher;
|
|
681
|
-
const features = collectSubset(
|
|
839
|
+
const features = collectSubset(str2, FEATURE_ATTRS);
|
|
682
840
|
if (features) opts.features = features;
|
|
683
|
-
const endpoints = collectSubset(
|
|
841
|
+
const endpoints = collectSubset(str2, ENDPOINT_ATTRS);
|
|
684
842
|
if (endpoints) opts.endpoints = endpoints;
|
|
685
|
-
const userContext = collectContext(
|
|
843
|
+
const userContext = collectContext(str2, USER_CONTEXT_ATTRS, "user-context");
|
|
686
844
|
if (userContext) opts.userContext = userContext;
|
|
687
|
-
const pageContext = collectContext(
|
|
845
|
+
const pageContext = collectContext(str2, PAGE_CONTEXT_ATTRS, "page-context");
|
|
688
846
|
if (pageContext) opts.pageContext = pageContext;
|
|
689
|
-
const actionsRaw =
|
|
847
|
+
const actionsRaw = str2("actions");
|
|
690
848
|
if (actionsRaw !== void 0) opts.header = { actions: onlyValidActions(actionsRaw) };
|
|
691
849
|
return opts;
|
|
692
850
|
}
|
|
693
|
-
function collectSubset(
|
|
851
|
+
function collectSubset(str2, table) {
|
|
694
852
|
const out = {};
|
|
695
853
|
for (const [attr, key, cast] of table) {
|
|
696
|
-
const raw =
|
|
854
|
+
const raw = str2(attr);
|
|
697
855
|
if (raw === void 0) continue;
|
|
698
856
|
out[key] = cast ? cast(raw) : raw;
|
|
699
857
|
}
|
|
700
858
|
return Object.keys(out).length > 0 ? out : null;
|
|
701
859
|
}
|
|
702
|
-
function collectContext(
|
|
860
|
+
function collectContext(str2, table, jsonAttr) {
|
|
703
861
|
const scalars = {};
|
|
704
862
|
for (const [attr, key] of table) {
|
|
705
|
-
const raw =
|
|
863
|
+
const raw = str2(attr);
|
|
706
864
|
if (raw !== void 0) scalars[key] = raw;
|
|
707
865
|
}
|
|
708
866
|
let fromJson = {};
|
|
709
|
-
const jsonRaw =
|
|
867
|
+
const jsonRaw = str2(jsonAttr);
|
|
710
868
|
if (jsonRaw) {
|
|
711
869
|
try {
|
|
712
870
|
const parsed = JSON.parse(jsonRaw);
|
|
@@ -717,13 +875,13 @@ function collectContext(str, table, jsonAttr) {
|
|
|
717
875
|
const out = { ...fromJson, ...scalars };
|
|
718
876
|
return Object.keys(out).length > 0 ? out : null;
|
|
719
877
|
}
|
|
720
|
-
function parseLauncher(get,
|
|
721
|
-
const base = collectSubset(
|
|
878
|
+
function parseLauncher(get, str2) {
|
|
879
|
+
const base = collectSubset(str2, LAUNCHER_ATTRS) ?? {};
|
|
722
880
|
const label = get("launcher-label");
|
|
723
881
|
if (label !== null) base.label = label;
|
|
724
|
-
const text =
|
|
882
|
+
const text = str2("callout-text");
|
|
725
883
|
if (text) {
|
|
726
|
-
const delay = Number.parseInt(
|
|
884
|
+
const delay = Number.parseInt(str2("callout-delay") ?? "", 10);
|
|
727
885
|
base.callout = { text, ...Number.isFinite(delay) ? { delayMs: delay } : {} };
|
|
728
886
|
}
|
|
729
887
|
return Object.keys(base).length > 0 ? base : null;
|
|
@@ -767,7 +925,7 @@ var tokens_default = ':host{--__P__-accent: __BRAND_ACCENT__;--__P__-accent-text
|
|
|
767
925
|
var reset_default = '*,*:before,*:after{box-sizing:border-box;margin:0;padding:0;border:0}button{font:inherit;color:inherit;background:none;cursor:pointer;-webkit-appearance:none;appearance:none;line-height:1}button:focus-visible,[tabindex]:focus-visible,textarea:focus-visible,input:focus-visible{outline:2px solid var(--__P__-accent);outline-offset:2px}textarea,input{font:inherit;color:inherit;background:none;border:0;outline:0;resize:none}a{color:var(--__P__-accent);text-decoration:underline;text-underline-offset:2px}img,svg{display:block;max-width:100%}ul,ol{list-style:none}.__P__-app{display:block;width:100%;height:100%;font-family:var(--__P__-font);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-feature-settings:"cv11","ss01","ss03"}.__P__-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n';
|
|
768
926
|
|
|
769
927
|
// src/styles/panel.css
|
|
770
|
-
var panel_default = '.__P__-anchor{right:16px;bottom:16px}:host([data-position="bottom-left"]) .__P__-anchor,:host([data-position="top-left"]) .__P__-anchor{right:auto;left:16px}:host([data-position="top-right"]) .__P__-anchor,:host([data-position="top-left"]) .__P__-anchor{bottom:auto;top:16px}.__P__-anchor{position:fixed;display:flex;flex-direction:column;align-items:flex-end;gap:var(--__P__-space-3);pointer-events:none}.__P__-anchor{--__P__-fab-size: 56px}.__P__-anchor[data-launcher-size=sm]{--__P__-fab-size: 44px}.__P__-anchor[data-launcher-size=md]{--__P__-fab-size: 56px}.__P__-anchor[data-launcher-size=lg]{--__P__-fab-size: 68px}.__P__-anchor>*{pointer-events:auto}.__P__-fab[data-size=sm]{--__P__-fab-size: 44px;font-size:var(--__P__-text-sm)}.__P__-fab[data-size=md]{--__P__-fab-size: 56px;font-size:14px}.__P__-fab[data-size=lg]{--__P__-fab-size: 68px;font-size:var(--__P__-text-base)}.__P__-fab{display:inline-flex;align-items:center;justify-content:center;gap:var(--__P__-space-2);color:var(--__P__-accent-text);background:var(--__P__-accent);box-shadow:var(--__P__-shadow-fab);font-weight:600;line-height:1;transform-origin:bottom right;animation:__P__-fab-in var(--__P__-dur-base) var(--__P__-ease) both;transition:transform var(--__P__-dur-base) var(--__P__-ease),opacity var(--__P__-dur-base) var(--__P__-ease),box-shadow var(--__P__-dur-base) var(--__P__-ease)}.__P__-fab:hover{transform:translateY(-2px)}.__P__-fab:active{transform:translateY(0)}.__P__-fab:focus-visible{outline:2px solid var(--__P__-on-accent);outline-offset:3px}.__P__-fab svg{width:24px;height:24px;flex-shrink:0}@keyframes __P__-fab-in{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:none}}.__P__-fab[data-leaving]{position:absolute;right:0;bottom:0;animation:__P__-fab-out var(--__P__-dur-quick) var(--__P__-ease) forwards;pointer-events:none}:host([data-position^="top-"]) .__P__-fab[data-leaving]{bottom:auto;top:0}:host([data-position$="-left"]) .__P__-fab[data-leaving]{right:auto;left:0}@keyframes __P__-fab-out{0%{opacity:1;transform:none}to{opacity:0;transform:scale(.85)}}.__P__-fab[data-variant=circle]{width:var(--__P__-fab-size);height:var(--__P__-fab-size);border-radius:999px}.__P__-fab[data-variant=circle] .__P__-fab-label{display:none}.__P__-fab[data-variant=pill]{height:var(--__P__-fab-size);padding:0 18px 0 16px;border-radius:999px}.__P__-fab[data-variant=bar]{height:var(--__P__-fab-size);padding:0 22px;border-radius:var(--__P__-radius)}.__P__-fab[data-variant=minimal]{height:var(--__P__-fab-size);padding:0 var(--__P__-space-4);border-radius:999px;background:transparent;color:var(--__P__-accent);box-shadow:none;border:1px solid currentColor}.__P__-fab[data-variant=minimal]:hover{background:color-mix(in srgb,var(--__P__-accent) 12%,transparent)}.__P__-callout{--__P__-callout-fab-h: var(--__P__-fab-size, 56px);--__P__-callout-gap: clamp(12px, calc(var(--__P__-callout-fab-h) * .25), 22px);--__P__-callout-nudge-direction: -1;position:absolute;display:inline-flex;align-items:center;gap:var(--__P__-space-2);padding:10px 14px;background:var(--__P__-fg);color:var(--__P__-bg);border-radius:999px;font-size:var(--__P__-text-sm);font-weight:600;line-height:1.2;box-shadow:0 10px 30px -8px #00000059;pointer-events:auto;animation:__P__-callout-in var(--__P__-dur-slow) var(--__P__-ease);z-index:1;max-width:240px;white-space:nowrap}.__P__-callout[data-position=left]{right:calc(100% + var(--__P__-callout-gap));bottom:calc(var(--__P__-callout-fab-h) / 2);transform:translateY(50%)}.__P__-callout[data-position=right]{left:calc(100% + var(--__P__-callout-gap));bottom:calc(var(--__P__-callout-fab-h) / 2);transform:translateY(50%);--__P__-callout-nudge-direction: 1}.__P__-callout[data-position=top]{bottom:calc(100% + var(--__P__-callout-gap));right:0;max-width:min(280px,calc(100vw - 32px))}.__P__-callout[data-position=bottom]{top:calc(100% + var(--__P__-callout-gap));right:0;max-width:min(280px,calc(100vw - 32px))}:host([data-position$="-left"]) .__P__-callout[data-position=top],:host([data-position$="-left"]) .__P__-callout[data-position=bottom]{right:auto;left:0}.__P__-callout[data-shape=bubble]{border-radius:var(--__P__-radius-md);white-space:normal;width:max-content;max-width:min(280px,calc(100vw - 32px))}.__P__-callout[data-shape=callout]{padding:12px 18px;font-size:14px;background:var(--__P__-accent);color:var(--__P__-accent-text)}.__P__-callout:after{content:"";position:absolute;width:12px;height:12px;background:inherit;border-radius:2px;transform:rotate(45deg)}.__P__-callout[data-position=left]:after{right:-5px;top:50%;margin-top:-6px}.__P__-callout[data-position=right]:after{left:-5px;top:50%;margin-top:-6px}.__P__-callout[data-position=top]:after{bottom:-5px;right:calc(var(--__P__-fab-size, 56px) / 2 - 6px)}.__P__-callout[data-position=bottom]:after{top:-5px;right:calc(var(--__P__-fab-size, 56px) / 2 - 6px)}:host([data-position$="-left"]) .__P__-callout[data-position=top]:after,:host([data-position$="-left"]) .__P__-callout[data-position=bottom]:after{right:auto;left:calc(var(--__P__-fab-size, 56px) / 2 - 6px)}.__P__-callout[data-animated]{animation:__P__-callout-in var(--__P__-dur-slow) var(--__P__-ease),__P__-callout-nudge 1.6s var(--__P__-ease-in-out) var(--__P__-dur-slow) infinite}@keyframes __P__-callout-in{0%{opacity:0}to{opacity:1}}@keyframes __P__-callout-nudge{0%,to{margin-left:0;margin-right:0}50%{margin-left:calc(6px * var(--__P__-callout-nudge-direction));margin-right:calc(-6px * var(--__P__-callout-nudge-direction))}}@media(prefers-reduced-motion:reduce){.__P__-callout[data-animated]{animation:__P__-callout-in 1ms var(--__P__-ease)}.__P__-icon-btn[data-recording=true],.__P__-typing span{animation:none}}.__P__-callout-close{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:999px;color:inherit;opacity:.7;cursor:pointer}.__P__-callout-close:hover{opacity:1;background:#ffffff26}.__P__-callout-close svg{width:12px;height:12px}.__P__-panel{width:var(--__P__-panel-w);height:var(--__P__-panel-h);max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);background:var(--__P__-bg);color:var(--__P__-fg);border-radius:var(--__P__-radius-lg);box-shadow:var(--__P__-shadow-panel);display:flex;flex-direction:column;overflow:hidden;transform-origin:bottom right;animation:__P__-panel-in var(--__P__-dur-slow) var(--__P__-ease);border:1px solid var(--__P__-border)}:host([data-mode="open"]) .__P__-panel{width:var(--__P__-widget-w, var(--__P__-panel-w));height:var(--__P__-widget-h, var(--__P__-panel-h));min-width:var(--__P__-resize-min-w, auto);min-height:var(--__P__-resize-min-h, auto);max-width:var(--__P__-resize-max-w, calc(100vw - 32px) );max-height:var(--__P__-resize-max-h, calc(100dvh - 32px) )}@keyframes __P__-panel-in{0%{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}:host([data-mode="expanded"]) .__P__-panel{width:var(--__P__-expanded-w, 640px);height:var(--__P__-expanded-h, 820px);max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px)}:host([data-mode="fullscreen"]){z-index:var(--__P__-z-panel)!important}:host([data-mode="fullscreen"]) .__P__-anchor{inset:0;align-items:stretch;padding:0}:host([data-mode="fullscreen"]) .__P__-panel{width:100vw;height:100dvh;max-width:none;max-height:none;border-radius:0;border:0}:host([data-mode="fullscreen"]) .__P__-fab{display:none}:host([data-mode="inline"]) .__P__-anchor,:host([data-mode="standalone"]) .__P__-anchor{position:static;inset:auto;padding:0;align-items:stretch;width:100%;height:100%;min-height:0}:host([data-mode="inline"]) .__P__-panel,:host([data-mode="standalone"]) .__P__-panel{width:100%;height:100%;min-width:0;min-height:0;max-width:none;max-height:none;animation:none}:host([data-mode="inline"]) .__P__-fab,:host([data-mode="standalone"]) .__P__-fab{display:none}:host([data-mode="inline"]){min-height:320px}:host([data-mode="inline"]) .__P__-panel{border-radius:var(--__P__-radius)}:host([data-mode="standalone"]) .__P__-panel{border-radius:0;border:0;box-shadow:none}:host([data-mode="modal"]){position:fixed!important;inset:0!important;z-index:var(--__P__-z-panel)!important;display:block!important;width:100vw;height:100dvh;background:var(--__P__-modal-backdrop, var(--__P__-backdrop));animation:__P__-backdrop-in var(--__P__-dur-base) var(--__P__-ease) both;--__P__-panel-w: min(960px, 92vw);--__P__-panel-h: min(720px, 88dvh)}:host([data-mode="modal"]) .__P__-anchor{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:var(--__P__-space-6);pointer-events:none}:host([data-mode="modal"]) .__P__-panel{pointer-events:auto;width:var(--__P__-widget-w, var(--__P__-panel-w));height:var(--__P__-widget-h, var(--__P__-panel-h));max-width:calc(100vw - 48px);max-height:calc(100dvh - 48px);min-width:0;min-height:0;border-radius:var(--__P__-radius);box-shadow:var(--__P__-shadow-panel);animation:__P__-modal-in var(--__P__-dur-base) var(--__P__-ease);translate:var(--__P__-modal-dx, 0px) var(--__P__-modal-dy, 0px)}:host([data-mode="modal"]) .__P__-header,:host([data-mode="modal"]) .__P__-back-header,:host([data-mode="modal"]) .__P__-home-hero{cursor:grab;touch-action:none}:host([data-mode="modal"]) .__P__-panel[data-dragging]{cursor:grabbing;user-select:none}:host([data-mode="modal"]) .__P__-panel[data-dragging] *{cursor:grabbing}:host([data-mode="modal"]) .__P__-fab{display:none}@keyframes __P__-backdrop-in{0%{background:#0000}to{background:var(--__P__-modal-backdrop, var(--__P__-backdrop))}}@keyframes __P__-modal-in{0%{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}:host([data-mode="drawer"]){--__P__-panel-w: min(440px, calc(100vw - 32px) );--__P__-panel-h: 100dvh}:host([data-mode="drawer"]) .__P__-anchor{position:fixed;--__P__-inset-x: var(--__P__-panel-inset, 12px);--__P__-inset-y: var(--__P__-panel-inset, 3dvh);top:var(--__P__-inset-y);bottom:auto;right:var(--__P__-inset-x);left:auto;width:min(var(--__P__-widget-w, var(--__P__-panel-w)),calc(100vw - var(--__P__-inset-x) * 2));height:min(var(--__P__-widget-h, var(--__P__-panel-h)),calc(100dvh - var(--__P__-inset-y) * 2));padding:0;display:block;pointer-events:auto}:host([data-mode="drawer"][data-position$="-left"]) .__P__-anchor{right:auto;left:var(--__P__-inset-x)}:host([data-mode="drawer"][data-position^="bottom-"]) .__P__-anchor{top:auto;bottom:var(--__P__-inset-y)}:host([data-mode="drawer"]) .__P__-panel{width:100%;height:100%;max-width:none;max-height:none;min-width:0;min-height:0;border-radius:var(--__P__-radius, 12px);border:1px solid var(--__P__-border);box-shadow:-8px 16px 32px -12px #00000038;animation:__P__-drawer-in var(--__P__-dur-base) var(--__P__-ease)}:host([data-mode="drawer"][data-position$="-left"]) .__P__-panel{box-shadow:8px 16px 32px -12px #00000038;animation:__P__-drawer-in-left var(--__P__-dur-base) var(--__P__-ease)}.__P__-fab[data-edge-tab]{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--__P__-space-2);position:fixed;top:50%;height:140px;width:auto;min-width:0;padding:10px 8px;writing-mode:vertical-rl;text-orientation:mixed;transform:translateY(-50%);transform-origin:center;animation:__P__-edge-tab-in var(--__P__-dur-base) var(--__P__-ease) both}.__P__-fab[data-edge-tab] svg{writing-mode:horizontal-tb}.__P__-fab[data-edge-tab]:hover{transform:translateY(-50%) scale(1.03)}.__P__-fab[data-edge-tab]:active{transform:translateY(-50%) scale(.97)}:host([data-position$="-right"]) .__P__-fab[data-edge-tab]{right:0;left:auto;border-radius:12px 0 0 12px;box-shadow:-6px 0 18px -8px #0000004d}:host([data-position$="-left"]) .__P__-fab[data-edge-tab]{left:0;right:auto;border-radius:0 12px 12px 0;box-shadow:6px 0 18px -8px #0000004d}.__P__-fab[data-edge-tab][data-leaving]{position:fixed;top:50%;bottom:auto;animation:__P__-edge-tab-out var(--__P__-dur-quick) var(--__P__-ease) forwards}@keyframes __P__-edge-tab-in{0%{opacity:0;transform:translateY(-50%) scale(.9)}to{opacity:1;transform:translateY(-50%) scale(1)}}@keyframes __P__-edge-tab-out{0%{opacity:1;transform:translateY(-50%) scale(1)}to{opacity:0;transform:translateY(-50%) scale(.85)}}@keyframes __P__-drawer-in{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes __P__-drawer-in-left{0%{transform:translate(-100%)}to{transform:translate(0)}}@media(prefers-reduced-motion:reduce){:host([data-mode="drawer"]) .__P__-panel,.__P__-fab[data-edge-tab]{animation:none}}.__P__-header{display:flex;align-items:center;gap:var(--__P__-space-2);padding:10px 12px;border-bottom:1px solid var(--__P__-border);background:var(--__P__-bg)}.__P__-header h1{font-size:14px;font-weight:600;flex:1;letter-spacing:-.01em}.__P__-header-actions{margin-left:auto;display:flex;align-items:center;gap:var(--__P__-space-1);flex-shrink:0}.__P__-agent{flex:1;display:inline-flex;align-items:center;gap:10px;min-width:0}.__P__-agent-avatar{position:relative;width:32px;height:32px;border-radius:999px;background:var(--__P__-bg-elevated);color:var(--__P__-fg-muted);display:inline-flex;align-items:center;justify-content:center;font-weight:700;font-size:var(--__P__-text-xs);overflow:hidden;flex-shrink:0}.__P__-agent-avatar img{width:100%;height:100%;object-fit:cover}.__P__-agent-avatar:after{content:"";position:absolute;right:-1px;bottom:-1px;width:10px;height:10px;border-radius:999px;border:2px solid var(--__P__-bg);background:var(--__P__-neutral)}.__P__-agent-avatar[data-status=online]:after{background:var(--__P__-success)}.__P__-agent-avatar[data-status=away]:after{background:var(--__P__-warning)}.__P__-agent-avatar[data-status=offline]:after{background:var(--__P__-neutral)}.__P__-agent-meta{display:flex;flex-direction:column;line-height:1.15;min-width:0}.__P__-agent-meta strong{font-size:14px;font-weight:600;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-agent-meta span{font-size:var(--__P__-text-xs);color:var(--__P__-fg-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-suggestions{display:flex;flex-wrap:nowrap;gap:var(--__P__-space-2);padding:6px 14px 10px;overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth;scroll-snap-type:x proximity;scrollbar-width:none;-ms-overflow-style:none;min-width:0}.__P__-suggestions::-webkit-scrollbar{display:none}.__P__-suggestions:before,.__P__-suggestions:after{content:"";flex:1 1 0;min-width:0}.__P__-suggestion{flex:0 0 auto;scroll-snap-align:center;padding:7px 14px;border-radius:999px;background:var(--__P__-bg-elevated);border:1px solid var(--__P__-border);color:var(--__P__-fg);font-size:var(--__P__-text-sm);font-weight:500;white-space:nowrap;transition:background var(--__P__-dur-quick) var(--__P__-ease),border-color var(--__P__-dur-quick) var(--__P__-ease),transform var(--__P__-dur-quick) var(--__P__-ease)}.__P__-suggestion:hover{border-color:var(--__P__-accent);color:var(--__P__-accent);transform:translateY(-1px)}.__P__-suggestion:focus-visible{outline:2px solid var(--__P__-accent);outline-offset:2px;border-color:var(--__P__-accent)}.__P__-suggestion:active{transform:translateY(0)}.__P__-icon-btn{width:32px;height:32px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;color:var(--__P__-fg-muted);transition:background var(--__P__-dur-quick) var(--__P__-ease),color var(--__P__-dur-quick) var(--__P__-ease)}.__P__-icon-btn:hover{background:var(--__P__-bg-elevated);color:var(--__P__-fg)}.__P__-icon-btn:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-icon-btn:active{background:var(--__P__-border)}.__P__-icon-btn:disabled{opacity:.45;cursor:not-allowed}.__P__-icon-btn:before{content:"";position:absolute;inset:-6px}.__P__-icon-btn{position:relative}.__P__-icon-btn svg{width:18px;height:18px}.__P__-icon-btn[data-recording=true]{color:var(--__P__-accent);background:color-mix(in srgb,var(--__P__-accent) 12%,transparent);animation:__P__-pulse 1.2s var(--__P__-ease) infinite}@keyframes __P__-pulse{0%,to{box-shadow:0 0 color-mix(in srgb,var(--__P__-accent) 40%,transparent)}50%{box-shadow:0 0 0 6px color-mix(in srgb,var(--__P__-accent) 0%,transparent)}}.__P__-list-wrap{position:relative;flex:1;min-height:0;display:flex;flex-direction:column}.__P__-jump{position:absolute;right:14px;bottom:14px;z-index:2;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:999px;border:1px solid var(--__P__-border);background:var(--__P__-bg-elevated);color:var(--__P__-fg);box-shadow:var(--__P__-shadow-panel);cursor:pointer;opacity:.85;transition:opacity var(--__P__-dur-quick) var(--__P__-ease),transform var(--__P__-dur-quick) var(--__P__-ease);animation:__P__-bubble-in var(--__P__-dur-base) var(--__P__-ease)}.__P__-jump:hover{opacity:1}.__P__-jump:active{transform:translateY(1px)}.__P__-jump svg{width:18px;height:18px}.__P__-list{flex:1;min-height:0;overflow-y:auto;padding:var(--__P__-space-4);padding-bottom:var(--__P__-space-8);display:flex;flex-direction:column;gap:14px;scrollbar-width:thin;scrollbar-color:var(--__P__-border-strong) transparent;scrollbar-gutter:stable}.__P__-list::-webkit-scrollbar{width:8px}.__P__-list::-webkit-scrollbar-thumb{background:var(--__P__-border-strong);border-radius:8px}.__P__-date-divider{position:sticky;top:var(--__P__-space-2);z-index:2;display:flex;justify-content:center;margin:var(--__P__-space-1) 0;pointer-events:none}.__P__-date-pill{padding:3px 10px;border-radius:999px;font-size:11px;font-weight:600;color:var(--__P__-fg-muted);background:var(--__P__-bg-elevated);border:1px solid var(--__P__-border);box-shadow:var(--__P__-shadow-card);opacity:0;pointer-events:none;transition:opacity var(--__P__-dur-base) var(--__P__-ease)}.__P__-list[data-scrolling=true] .__P__-date-pill{opacity:1;pointer-events:auto}@media(prefers-reduced-motion:reduce){.__P__-date-pill{transition:none}}.__P__-bubble-row{display:flex}.__P__-bubble-row[data-role=user]{justify-content:flex-end}.__P__-bubble-row[data-role=assistant]{justify-content:flex-start}.__P__-bubble{max-width:100%;padding:var(--__P__-space-3) var(--__P__-space-4);border-radius:var(--__P__-radius);line-height:1.6;font-size:14px;word-wrap:break-word;overflow-wrap:anywhere;box-shadow:0 1px 2px #0000000a,0 1px 8px -4px #0000000f;animation:__P__-bubble-in var(--__P__-dur-base) var(--__P__-ease)}.__P__-bubble ::selection{background:color-mix(in srgb,var(--__P__-accent) 30%,transparent)}.__P__-bubble-row[data-role=user] .__P__-bubble ::selection{background:#fff6;color:var(--__P__-bubble-user-text)}@keyframes __P__-bubble-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.__P__-bubble-row[data-role=user] .__P__-bubble{background:var(--__P__-bubble-user);color:var(--__P__-bubble-user-text);border-bottom-right-radius:5px}.__P__-bubble-row[data-role=assistant] .__P__-bubble{background:var(--__P__-bubble-assistant);color:var(--__P__-bubble-assistant-text);border-bottom-left-radius:5px}.__P__-bubble-col{display:flex;flex-direction:column;max-width:85%;min-width:0}.__P__-bubble-row[data-role=user] .__P__-bubble-col{align-items:flex-end}.__P__-bubble-row[data-role=assistant] .__P__-bubble-col{align-items:flex-start}.__P__-bubble-time{margin-top:3px;padding:0 4px;font-size:11px;line-height:1;color:var(--__P__-fg-muted);user-select:none}.__P__-md>*:first-child{margin-top:0}.__P__-md>*:last-child{margin-bottom:0}.__P__-md p{margin:10px 0}.__P__-md h1,.__P__-md h2,.__P__-md h3,.__P__-md h4,.__P__-md h5,.__P__-md h6{margin:18px 0 8px;line-height:1.3;letter-spacing:-.01em;font-weight:700}.__P__-md h1{font-size:1.4em}.__P__-md h2{font-size:1.22em}.__P__-md h3{font-size:1.08em}.__P__-md h4,.__P__-md h5,.__P__-md h6{font-size:1em}.__P__-md>h1:first-child,.__P__-md>h2:first-child,.__P__-md>h3:first-child,.__P__-md>h4:first-child,.__P__-md>h5:first-child,.__P__-md>h6:first-child{margin-top:0}.__P__-md ul,.__P__-md ol{padding-left:1.5em;margin:10px 0}.__P__-md ul{list-style:disc}.__P__-md ol{list-style:decimal}.__P__-md li{margin:6px 0;padding-left:2px}.__P__-md li::marker{color:var(--__P__-fg-muted)}.__P__-md li>p{margin:6px 0}.__P__-md li>ul,.__P__-md li>ol{margin:6px 0}.__P__-md strong,.__P__-md b{font-weight:650;letter-spacing:-.005em}.__P__-md em,.__P__-md i{font-style:italic}.__P__-md code{font-family:var(--__P__-font-mono);font-size:.86em;padding:1px 6px;border-radius:5px;background:color-mix(in srgb,var(--__P__-accent) 10%,transparent);color:var(--__P__-fg);border:1px solid color-mix(in srgb,var(--__P__-accent) 16%,transparent)}.__P__-md pre{font-family:var(--__P__-font-mono);font-size:12.5px;padding:12px 14px;border-radius:var(--__P__-radius-sm);background:#7f7f7f1f;overflow-x:auto;margin:var(--__P__-space-3) 0;line-height:1.5}.__P__-md pre code{padding:0;background:none}.__P__-md a{color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}.__P__-md a:hover{text-decoration-thickness:2px}.__P__-md blockquote{margin:14px 0;padding:6px 14px;border-left:3px solid color-mix(in srgb,var(--__P__-accent) 50%,transparent);background:color-mix(in srgb,var(--__P__-accent) 5%,transparent);border-radius:0 var(--__P__-radius-sm) var(--__P__-radius-sm) 0;color:var(--__P__-fg-muted)}.__P__-md blockquote>:first-child{margin-top:0}.__P__-md blockquote>:last-child{margin-bottom:0}.__P__-md hr{border:0;height:1px;background:color-mix(in srgb,currentColor 18%,transparent);margin:var(--__P__-space-4) 0}.__P__-md table{border-collapse:collapse;margin:var(--__P__-space-3) 0;font-size:.95em;display:block;overflow-x:auto;max-width:100%;font-variant-numeric:tabular-nums}.__P__-md th,.__P__-md td{padding:6px 10px;border-bottom:1px solid color-mix(in srgb,currentColor 12%,transparent);text-align:left}.__P__-md th{font-weight:700;background:color-mix(in srgb,currentColor 6%,transparent)}.__P__-md h1+ul,.__P__-md h1+ol,.__P__-md h2+ul,.__P__-md h2+ol,.__P__-md h3+ul,.__P__-md h3+ol,.__P__-md h4+ul,.__P__-md h4+ol{margin-top:var(--__P__-space-1)}.__P__-loading{display:inline-flex;align-items:center;gap:var(--__P__-space-2);color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm)}.__P__-loading-spinner{width:14px;height:14px;border-radius:999px;border:2px solid currentColor;border-top-color:transparent;animation:__P__-spin .8s linear infinite}@keyframes __P__-spin{to{transform:rotate(1turn)}}.__P__-typing{display:inline-flex;gap:var(--__P__-space-1);padding:var(--__P__-space-1) 0}.__P__-typing span{width:5px;height:5px;border-radius:999px;background:currentColor;opacity:.4;animation:__P__-blink 1.2s var(--__P__-ease) infinite}.__P__-typing span:nth-child(2){animation-delay:.2s}.__P__-typing span:nth-child(3){animation-delay:.4s}@keyframes __P__-blink{0%,80%,to{opacity:.3;transform:translateY(0)}40%{opacity:1;transform:translateY(-2px)}}.__P__-reasoning{margin:var(--__P__-space-1) 0 var(--__P__-space-2);padding-left:var(--__P__-space-3);border-left:2px solid var(--__P__-border-strong)}.__P__-reasoning-summary{display:inline-flex;align-items:center;gap:var(--__P__-space-1);cursor:pointer;list-style:none;user-select:none;color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs);font-weight:600}.__P__-reasoning-summary::-webkit-details-marker{display:none}.__P__-reasoning-summary:before{content:"";width:5px;height:5px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(-45deg);opacity:.7;transition:transform var(--__P__-dur-quick) var(--__P__-ease)}.__P__-reasoning[open] .__P__-reasoning-summary:before{transform:rotate(45deg)}.__P__-reasoning[data-active=true] .__P__-reasoning-label{animation:__P__-reasoning-pulse 1.4s var(--__P__-ease) infinite}@keyframes __P__-reasoning-pulse{0%,to{opacity:.5}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.__P__-reasoning[data-active=true] .__P__-reasoning-label{animation:none}}.__P__-reasoning-body{margin-top:var(--__P__-space-1);color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm)}.__P__-reasoning-body>:first-child{margin-top:0}.__P__-reasoning-body>:last-child{margin-bottom:0}.__P__-tool-chip{display:inline-flex;align-items:center;gap:6px;padding:var(--__P__-space-1) var(--__P__-space-2);margin-top:6px;border-radius:999px;background:var(--__P__-bg-elevated);border:1px solid var(--__P__-border);color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs)}.__P__-composer{border-top:1px solid var(--__P__-border);padding:10px 12px;background:var(--__P__-bg);display:flex;flex-direction:column;gap:var(--__P__-space-2)}.__P__-composer-row{display:flex;align-items:flex-end;gap:6px}.__P__-textarea{flex:1;height:40px;max-height:160px;padding:10px 12px;border-radius:var(--__P__-radius);background:var(--__P__-bg-elevated);border:1px solid transparent;font-size:14px;line-height:1.4;transition:height var(--__P__-dur-quick) var(--__P__-ease),border-color var(--__P__-dur-quick) var(--__P__-ease),box-shadow var(--__P__-dur-quick) var(--__P__-ease)}.__P__-textarea:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:1px;border-color:var(--__P__-focus)}@media(pointer:coarse){.__P__-textarea,.__P__-home-search-input{font-size:16px}.__P__-textarea{height:44px}}.__P__-send{width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;transition:opacity var(--__P__-dur-quick) var(--__P__-ease),transform var(--__P__-dur-quick) var(--__P__-ease),background var(--__P__-dur-quick) var(--__P__-ease)}.__P__-send[data-shape=circle]{border-radius:999px}.__P__-send[data-shape=square]{border-radius:var(--__P__-radius-sm)}.__P__-send[data-shape=pill]{width:auto;padding:0 18px;border-radius:999px}.__P__-send[data-variant=filled]{background:var(--__P__-accent);color:var(--__P__-accent-text)}.__P__-send[data-variant=outline]{background:transparent;color:var(--__P__-accent);border-color:var(--__P__-accent)}.__P__-send[data-variant=outline]:not(:disabled):hover{background:color-mix(in srgb,var(--__P__-accent) 10%,transparent)}.__P__-send[data-variant=ghost]{background:transparent;color:var(--__P__-accent)}.__P__-send[data-variant=ghost]:not(:disabled):hover{background:color-mix(in srgb,var(--__P__-accent) 8%,transparent)}.__P__-send:disabled{opacity:.4;cursor:not-allowed}.__P__-send:not(:disabled):hover{transform:translateY(-1px)}.__P__-send:not(:disabled):active{transform:translateY(0)}.__P__-send:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-send svg{width:18px;height:18px}.__P__-composer-actions{display:flex;gap:var(--__P__-space-1);flex-wrap:wrap}.__P__-attachments{display:flex;flex-wrap:wrap;gap:6px}.__P__-attachment-chip{display:inline-flex;align-items:center;gap:6px;padding:var(--__P__-space-1) var(--__P__-space-2) var(--__P__-space-1) var(--__P__-space-1);border-radius:999px;background:var(--__P__-bg-elevated);border:1px solid var(--__P__-border);font-size:var(--__P__-text-xs);max-width:200px}.__P__-attachment-thumb{width:24px;height:24px;border-radius:999px;object-fit:cover;background:var(--__P__-border)}.__P__-attachment-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.__P__-attachment-remove{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;color:var(--__P__-fg-muted)}.__P__-attachment-remove:hover{background:var(--__P__-border);color:var(--__P__-fg)}.__P__-dropzone{position:absolute;inset:8px;border:2px dashed var(--__P__-accent);border-radius:var(--__P__-radius);background:color-mix(in srgb,var(--__P__-accent) 8%,transparent);display:flex;align-items:center;justify-content:center;font-weight:600;color:var(--__P__-accent);pointer-events:none;z-index:10;animation:__P__-fade-in var(--__P__-dur-quick) var(--__P__-ease)}@keyframes __P__-fade-in{0%{opacity:0}to{opacity:1}}.__P__-error{margin-top:var(--__P__-space-1);padding:8px 10px;border-radius:var(--__P__-radius-sm);background:var(--__P__-danger-bg);color:var(--__P__-danger-text);font-size:var(--__P__-text-sm);display:flex;align-items:center;gap:var(--__P__-space-2)}.__P__-error button{color:inherit;text-decoration:underline;font-size:var(--__P__-text-sm)}.__P__-history{flex:1;overflow-y:auto;padding:var(--__P__-space-2) var(--__P__-space-1) var(--__P__-space-3)}.__P__-history-footer{flex:none;padding:var(--__P__-space-2) var(--__P__-space-3) var(--__P__-space-3);border-top:1px solid var(--__P__-border);background:var(--__P__-surface)}.__P__-history-new{width:100%;display:flex;align-items:center;justify-content:center;gap:var(--__P__-space-2);padding:var(--__P__-space-2) var(--__P__-space-3);border:none;border-radius:var(--__P__-radius-md);background:var(--__P__-accent);color:var(--__P__-on-accent);cursor:pointer;font-size:var(--__P__-text-sm);font-weight:600;transition:filter var(--__P__-dur-quick) var(--__P__-ease-out),transform var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-history-new svg{width:16px;height:16px}.__P__-history-new:hover{filter:brightness(1.08)}.__P__-history-new:active{transform:translateY(1px)}.__P__-history-new:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-history-empty{flex:1;display:flex;align-items:center;justify-content:center;padding:40px 16px;color:var(--__P__-fg-muted);font-size:14px;text-align:center}.__P__-history-group{display:flex;flex-direction:column;padding:0 var(--__P__-space-2)}.__P__-history-heading{font-size:var(--__P__-text-xs);font-weight:600;color:var(--__P__-fg-muted);padding:12px 8px 6px;text-transform:uppercase;letter-spacing:.04em}.__P__-history-item{all:unset;display:flex;flex-direction:column;gap:3px;padding:10px 12px;border-radius:var(--__P__-radius-md);cursor:pointer;transition:background var(--__P__-dur-base) var(--__P__-ease)}.__P__-history-item:hover{background:var(--__P__-bg-elevated)}.__P__-history-item:focus-visible{background:var(--__P__-bg-elevated);outline:2px solid var(--__P__-focus);outline-offset:-2px}.__P__-history-title{font-size:14px;font-weight:500;color:var(--__P__-fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-history-preview{font-size:var(--__P__-text-xs);color:var(--__P__-fg-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-history-item[data-closed=true] .__P__-history-title:after{content:"\\2022";margin-left:var(--__P__-space-2);opacity:.5}.__P__-list-loading{margin:auto;padding:var(--__P__-space-6) var(--__P__-space-4);color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm);text-align:center}.__P__-readonly-banner{display:flex;flex-direction:column;align-items:center;gap:10px;padding:14px 12px;margin:0 var(--__P__-space-3) var(--__P__-space-3);border-radius:var(--__P__-radius-md);background:var(--__P__-bg-elevated);color:var(--__P__-fg-muted);text-align:center;font-size:var(--__P__-text-sm)}.__P__-readonly-label{line-height:1.4}.__P__-readonly-cta{appearance:none;border:0;cursor:pointer;padding:var(--__P__-space-2) var(--__P__-space-4);border-radius:999px;background:var(--__P__-accent);color:var(--__P__-accent-text, #fff);font:inherit;font-weight:600;font-size:var(--__P__-text-sm);transition:filter var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-readonly-cta:hover,.__P__-readonly-cta:focus-visible{filter:brightness(1.1)}.__P__-readonly-cta:focus-visible{outline:2px solid var(--__P__-accent);outline-offset:2px}.__P__-composer-footer{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;padding:10px 16px;margin:0 var(--__P__-space-3);border-top:1px solid var(--__P__-border);text-align:center;font-size:11px;line-height:1.4;color:var(--__P__-fg-muted)}.__P__-disclaimer{max-width:320px;margin:0 auto;opacity:.9;letter-spacing:.01em}.__P__-poweredby{display:inline-flex;align-items:center;justify-content:center;gap:6px;color:inherit;text-decoration:none;opacity:.7;transition:opacity var(--__P__-dur-base) var(--__P__-ease);font-size:11px;letter-spacing:.02em}.__P__-poweredby:hover{opacity:1}.__P__-poweredby-logo{height:12px;width:auto;display:inline-block;vertical-align:middle}.__P__-poweredby-bar{flex:none;display:flex;align-items:center;justify-content:center;padding:6px 16px;border-top:1px solid var(--__P__-border);background:var(--__P__-bg-elevated)}.__P__-menu-wrap{position:relative;display:inline-flex}.__P__-menu{position:absolute;top:100%;right:0;margin-top:6px;min-width:200px;padding:6px;background:var(--__P__-bg);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius-md);box-shadow:var(--__P__-shadow-panel);z-index:10;display:flex;flex-direction:column;gap:2px;animation:__P__-menu-in var(--__P__-dur-base) var(--__P__-ease)}@media(prefers-reduced-motion:reduce){.__P__-menu{animation:none}}@keyframes __P__-menu-in{0%{opacity:0;transform:translateY(-4px) scale(.98);transform-origin:top right}to{opacity:1;transform:none}}.__P__-menu-item{all:unset;display:flex;align-items:center;gap:10px;padding:8px 10px;font-size:var(--__P__-text-sm);color:var(--__P__-fg);border-radius:var(--__P__-radius-sm);cursor:pointer;user-select:none}.__P__-menu-item:hover{background:var(--__P__-bg-elevated)}.__P__-menu-item:focus-visible{background:var(--__P__-bg-elevated);outline:2px solid var(--__P__-focus);outline-offset:-2px}.__P__-menu-item[disabled]{opacity:.45;cursor:not-allowed}.__P__-menu-icon{display:inline-flex;width:16px;height:16px;color:var(--__P__-fg-muted)}.__P__-menu-icon svg{width:16px;height:16px}.__P__-menu-label{flex:1}.__P__-menu-check{display:inline-flex;color:var(--__P__-accent)}.__P__-menu-check svg{width:14px;height:14px}.__P__-resize-grip{position:absolute;width:18px;height:18px;display:flex;align-items:center;justify-content:center;color:var(--__P__-fg-muted);opacity:.45;transition:opacity var(--__P__-dur-base) var(--__P__-ease);z-index:2;touch-action:none;user-select:none}.__P__-resize-grip:hover,.__P__-resize-grip:focus-visible{opacity:1}.__P__-resize-grip svg{width:10px;height:10px}.__P__-resize-grip--bottom-left{bottom:2px;left:2px;cursor:nesw-resize;transform:scaleX(-1)}.__P__-resize-grip--bottom-right{bottom:2px;right:2px;cursor:nwse-resize}.__P__-resize-grip--top-left{top:2px;left:2px;cursor:nwse-resize;transform:rotate(180deg)}.__P__-resize-grip--top-right{top:2px;right:2px;cursor:nesw-resize;transform:scaleY(-1)}:host(:not([data-mode="open"])) .__P__-resize-grip{display:none}.__P__-messenger{display:flex;flex-direction:column;overflow:hidden}.__P__-messenger-body{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.__P__-module{display:flex;flex-direction:column;height:100%;min-height:0}.__P__-module-scroll{flex:1;min-height:0;overflow-y:auto;padding:var(--__P__-space-3);display:flex;flex-direction:column;gap:var(--__P__-space-3)}.__P__-home{background:radial-gradient(125% 65% at 88% 0%,color-mix(in srgb,#fff 16%,transparent),transparent 55%),linear-gradient(180deg,var(--__P__-accent) 0%,var(--__P__-accent) 22%,color-mix(in srgb,var(--__P__-accent) 28%,var(--__P__-surface)) 44%,var(--__P__-surface) 70%);border-radius:var(--__P__-radius-lg) var(--__P__-radius-lg) 0 0}.__P__-home-scroll{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;background:transparent}.__P__-home-cards{display:flex;flex-direction:column;gap:var(--__P__-space-3);padding:4px 14px 16px}.__P__-module-pad{padding:var(--__P__-space-3) var(--__P__-space-3) 0}.__P__-module-empty{display:flex;flex-direction:column;align-items:center;gap:var(--__P__-space-3);padding:var(--__P__-space-8) var(--__P__-space-4);text-align:center;color:var(--__P__-fg-muted);font-size:var(--__P__-text-base)}.__P__-module-retry{padding:var(--__P__-space-2) var(--__P__-space-4);border:1px solid var(--__P__-border-strong);border-radius:var(--__P__-radius-sm);color:var(--__P__-fg);font-weight:600;cursor:pointer;transition:background var(--__P__-dur-quick) var(--__P__-ease-out),border-color var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-module-retry:hover{background:var(--__P__-hover);border-color:var(--__P__-accent)}.__P__-module-retry:active{background:var(--__P__-border)}.__P__-module-retry:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-help-list{flex:1;min-height:0;overflow-y:auto;padding-bottom:var(--__P__-space-3)}.__P__-help-group{display:flex;flex-direction:column}.__P__-help-section-title{position:sticky;top:0;z-index:1;margin:0;padding:var(--__P__-space-3) var(--__P__-space-5) var(--__P__-space-2);font-size:var(--__P__-text-xs);font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--__P__-fg-muted);background:var(--__P__-bg)}.__P__-help-card{margin:0 var(--__P__-space-3) var(--__P__-space-3);background:var(--__P__-surface);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius);overflow:hidden}.__P__-help-card .__P__-list-row{border-bottom:0;border-radius:0}.__P__-help-card .__P__-list-row+.__P__-list-row{border-top:1px solid var(--__P__-border)}.__P__-help-card .__P__-list-row:hover{background:var(--__P__-hover)}.__P__-module-cta{padding:var(--__P__-space-3);border-top:1px solid var(--__P__-border)}.__P__-tabbar{display:flex;border-top:1px solid var(--__P__-border);background:var(--__P__-bg-elevated);flex-shrink:0}.__P__-tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--__P__-space-1);min-height:48px;padding:var(--__P__-space-2) var(--__P__-space-1);color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs);font-weight:600;transition:color var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-tab:hover{color:var(--__P__-fg)}.__P__-tab[aria-selected=true]{color:var(--__P__-accent)}.__P__-tab:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:-2px}.__P__-tab:active{background:var(--__P__-hover)}.__P__-tab-icon{position:relative;display:inline-flex}.__P__-tab-icon svg{width:22px;height:22px}.__P__-tab-badge{position:absolute;top:-4px;left:calc(50% + 6px);min-width:16px;height:16px;padding:0 4px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;background:var(--__P__-accent);color:var(--__P__-on-accent);font-size:10px;font-weight:600;line-height:1}.__P__-home-hero{flex-shrink:0;padding:var(--__P__-space-5) var(--__P__-space-5) var(--__P__-space-3);color:var(--__P__-on-accent);--__P__-focus: var(--__P__-on-accent)}.__P__-home-hero-top{display:flex;align-items:center;justify-content:space-between;gap:var(--__P__-space-3);min-height:32px}.__P__-home-brand{font-size:14px;font-weight:600;letter-spacing:.01em;color:color-mix(in srgb,#fff 82%,transparent);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.__P__-home-brand-spacer{flex:1}.__P__-home-hero-actions{display:flex;align-items:center;gap:var(--__P__-space-2);flex-shrink:0}.__P__-home-hero-actions .__P__-icon-btn{color:#fff}.__P__-home-greeting{margin:28px 0 0;font-family:var(--__P__-font-display);font-size:var(--__P__-text-2xl);font-weight:800;line-height:1.18;letter-spacing:-.01em;overflow-wrap:anywhere}.__P__-home-lead{margin:2px 0 0;font-family:var(--__P__-font-display);font-size:var(--__P__-text-2xl);font-weight:800;line-height:1.18;letter-spacing:-.01em;color:color-mix(in srgb,var(--__P__-on-accent) 88%,transparent);overflow-wrap:anywhere}.__P__-home-avatars{display:flex}.__P__-home-avatar{width:30px;height:30px;border-radius:999px;overflow:hidden;margin-left:-10px;border:2px solid color-mix(in srgb,#fff 92%,transparent);box-shadow:0 1px 3px #0000002e;background:var(--__P__-surface);display:inline-flex;align-items:center;justify-content:center;font-size:var(--__P__-text-xs);font-weight:700;color:var(--__P__-fg)}.__P__-home-avatar:first-child{margin-left:0}.__P__-home-avatar img{width:100%;height:100%;object-fit:cover}.__P__-home-content{background:var(--__P__-surface);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius);box-shadow:var(--__P__-shadow-card);overflow:hidden}.__P__-home-content-title{padding:var(--__P__-space-4) var(--__P__-space-4) var(--__P__-space-3);font-size:var(--__P__-text-sm);font-weight:700}.__P__-home-content-list{display:flex;flex-direction:column;padding:0 var(--__P__-space-2) var(--__P__-space-2)}.__P__-home-content-list .__P__-list-row+.__P__-list-row{border-top:1px solid var(--__P__-border)}.__P__-home-card{display:block;width:100%;text-align:left;background:var(--__P__-surface);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius);padding:var(--__P__-space-4);box-shadow:var(--__P__-shadow-card)}.__P__-home-card[data-interactive=true]{cursor:pointer;transition:background var(--__P__-dur-quick) var(--__P__-ease-out),transform var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-home-card[data-interactive=true]:hover{background:var(--__P__-bg-elevated)}.__P__-home-card[data-interactive=true]:active{transform:translateY(1px)}.__P__-home-card[data-interactive=true]:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-home-recent-row{display:flex;align-items:center;gap:var(--__P__-space-3)}.__P__-home-recent-avatar{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;flex-shrink:0;border-radius:999px;background:color-mix(in oklch,var(--__P__-accent) 14%,transparent);color:var(--__P__-accent)}.__P__-home-recent-avatar svg{width:20px;height:20px}.__P__-home-recent-body{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}.__P__-home-recent-title{font-weight:600;font-size:14px}.__P__-home-recent-preview{color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.__P__-home-recent-at{color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs);flex-shrink:0}.__P__-home-recent-dot{width:8px;height:8px;border-radius:999px;background:var(--__P__-accent);flex-shrink:0}.__P__-home-recent-row[data-unread=true] .__P__-home-recent-title{font-weight:700}.__P__-home-status{display:flex;align-items:center;gap:var(--__P__-space-3)}.__P__-home-status-icon svg{width:22px;height:22px;color:var(--__P__-success)}.__P__-home-status[data-level=degraded] .__P__-home-status-icon svg{color:var(--__P__-warning)}.__P__-home-status[data-level=down] .__P__-home-status-icon svg{color:var(--__P__-danger)}.__P__-home-status-text{font-weight:600;font-size:14px}.__P__-home-search{display:flex;align-items:center;gap:var(--__P__-space-2);width:100%;padding:var(--__P__-space-3) var(--__P__-space-4);border-radius:var(--__P__-radius);border:1px solid var(--__P__-border);background:var(--__P__-surface);text-align:left}.__P__-home-search[data-input=true]{background:var(--__P__-bg-elevated)}.__P__-home-search:hover{border-color:var(--__P__-border-strong)}.__P__-home-search:focus-visible,.__P__-home-search:focus-within{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-home-search-text{flex:1;color:var(--__P__-fg-muted);font-size:14px}.__P__-home-search-input{flex:1;border:0;background:transparent;font-size:14px;color:var(--__P__-fg);outline:none}.__P__-home-search-icon svg{width:18px;height:18px;color:var(--__P__-accent)}.__P__-list-row{display:flex;align-items:center;gap:var(--__P__-space-3);width:100%;min-height:44px;text-align:left;padding:var(--__P__-space-3) var(--__P__-space-2);border-radius:var(--__P__-radius-sm)}.__P__-list-row:hover{background:var(--__P__-bg-elevated)}.__P__-list-row:active{background:var(--__P__-border)}.__P__-list-row:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:-2px}.__P__-list-row-body{display:flex;flex-direction:column;min-width:0;flex:1}.__P__-list-row-title{font-weight:600;font-size:var(--__P__-text-md);line-height:1.35}.__P__-list-row-sub{color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm);margin-top:var(--__P__-space-1);line-height:1.45;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.__P__-list-row-chevron svg{width:18px;height:18px;color:var(--__P__-accent);flex-shrink:0}.__P__-back-header{display:flex;align-items:center;gap:var(--__P__-space-2);padding:10px 12px;border-bottom:1px solid var(--__P__-border);flex-shrink:0}.__P__-back-title{flex:1;text-align:center;font-size:var(--__P__-text-md);font-weight:700;margin:0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-back-spacer{width:32px;height:1px}.__P__-content{display:flex;flex-direction:column;gap:14px;width:100%;max-width:68ch;margin:0 auto}.__P__-content-hero{width:100%;border-radius:var(--__P__-radius)}.__P__-content-subtitle{color:var(--__P__-fg-muted);margin:0}.__P__-content-frame{flex:1;min-height:0;width:100%;border:0;background:#fff}.__P__-news-list{display:flex;flex-direction:column;gap:var(--__P__-space-3)}.__P__-news-card{display:block;width:100%;text-align:left;border:1px solid var(--__P__-border);border-radius:var(--__P__-radius);overflow:hidden;background:var(--__P__-surface)}.__P__-news-card{transition:background var(--__P__-dur-quick) var(--__P__-ease-out),transform var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-news-card:hover{background:var(--__P__-bg-elevated)}.__P__-news-card:active{transform:translateY(1px)}.__P__-news-card:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-news-hero{width:100%;display:block}.__P__-news-body{display:flex;flex-direction:column;gap:6px;padding:14px 16px}.__P__-news-tags{display:flex;gap:6px;flex-wrap:wrap}.__P__-news-tag{font-size:var(--__P__-text-xs);font-weight:600;color:var(--__P__-accent);background:color-mix(in srgb,var(--__P__-accent) 12%,transparent);padding:2px 8px;border-radius:999px}.__P__-news-title{font-weight:700;font-size:var(--__P__-text-md)}.__P__-news-summary{color:var(--__P__-fg-muted);font-size:14px;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.__P__-modules-empty{display:flex;align-items:center;justify-content:center;position:relative}.__P__-modules-empty-close{position:absolute;top:12px;right:12px}.__P__-modules-empty-text{color:var(--__P__-fg-muted);font-size:var(--__P__-text-base)}\n';
|
|
928
|
+
var panel_default = '.__P__-anchor{right:16px;bottom:16px}:host([data-position="bottom-left"]) .__P__-anchor,:host([data-position="top-left"]) .__P__-anchor{right:auto;left:16px}:host([data-position="top-right"]) .__P__-anchor,:host([data-position="top-left"]) .__P__-anchor{bottom:auto;top:16px}.__P__-anchor{position:fixed;display:flex;flex-direction:column;align-items:flex-end;gap:var(--__P__-space-3);pointer-events:none}.__P__-anchor{--__P__-fab-size: 56px}.__P__-anchor[data-launcher-size=sm]{--__P__-fab-size: 44px}.__P__-anchor[data-launcher-size=md]{--__P__-fab-size: 56px}.__P__-anchor[data-launcher-size=lg]{--__P__-fab-size: 68px}.__P__-anchor>*{pointer-events:auto}.__P__-fab[data-size=sm]{--__P__-fab-size: 44px;font-size:var(--__P__-text-sm)}.__P__-fab[data-size=md]{--__P__-fab-size: 56px;font-size:14px}.__P__-fab[data-size=lg]{--__P__-fab-size: 68px;font-size:var(--__P__-text-base)}.__P__-fab{display:inline-flex;align-items:center;justify-content:center;gap:var(--__P__-space-2);color:var(--__P__-accent-text);background:var(--__P__-accent);box-shadow:var(--__P__-shadow-fab);font-weight:600;line-height:1;transform-origin:bottom right;animation:__P__-fab-in var(--__P__-dur-base) var(--__P__-ease) both;transition:transform var(--__P__-dur-base) var(--__P__-ease),opacity var(--__P__-dur-base) var(--__P__-ease),box-shadow var(--__P__-dur-base) var(--__P__-ease)}.__P__-fab:hover{transform:translateY(-2px)}.__P__-fab:active{transform:translateY(0)}.__P__-fab:focus-visible{outline:2px solid var(--__P__-on-accent);outline-offset:3px}.__P__-fab svg{width:24px;height:24px;flex-shrink:0}@keyframes __P__-fab-in{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:none}}.__P__-fab[data-leaving]{position:absolute;right:0;bottom:0;animation:__P__-fab-out var(--__P__-dur-quick) var(--__P__-ease) forwards;pointer-events:none}:host([data-position^="top-"]) .__P__-fab[data-leaving]{bottom:auto;top:0}:host([data-position$="-left"]) .__P__-fab[data-leaving]{right:auto;left:0}@keyframes __P__-fab-out{0%{opacity:1;transform:none}to{opacity:0;transform:scale(.85)}}.__P__-fab[data-variant=circle]{width:var(--__P__-fab-size);height:var(--__P__-fab-size);border-radius:999px}.__P__-fab[data-variant=circle] .__P__-fab-label{display:none}.__P__-fab[data-variant=pill]{height:var(--__P__-fab-size);padding:0 18px 0 16px;border-radius:999px}.__P__-fab[data-variant=bar]{height:var(--__P__-fab-size);padding:0 22px;border-radius:var(--__P__-radius)}.__P__-fab[data-variant=minimal]{height:var(--__P__-fab-size);padding:0 var(--__P__-space-4);border-radius:999px;background:transparent;color:var(--__P__-accent);box-shadow:none;border:1px solid currentColor}.__P__-fab[data-variant=minimal]:hover{background:color-mix(in srgb,var(--__P__-accent) 12%,transparent)}.__P__-callout{--__P__-callout-fab-h: var(--__P__-fab-size, 56px);--__P__-callout-gap: clamp(12px, calc(var(--__P__-callout-fab-h) * .25), 22px);--__P__-callout-nudge-direction: -1;position:absolute;display:inline-flex;align-items:center;gap:var(--__P__-space-2);padding:10px 14px;background:var(--__P__-fg);color:var(--__P__-bg);border-radius:999px;font-size:var(--__P__-text-sm);font-weight:600;line-height:1.2;box-shadow:0 10px 30px -8px #00000059;pointer-events:auto;animation:__P__-callout-in var(--__P__-dur-slow) var(--__P__-ease);z-index:1;max-width:240px;white-space:nowrap}.__P__-callout[data-position=left]{right:calc(100% + var(--__P__-callout-gap));bottom:calc(var(--__P__-callout-fab-h) / 2);transform:translateY(50%)}.__P__-callout[data-position=right]{left:calc(100% + var(--__P__-callout-gap));bottom:calc(var(--__P__-callout-fab-h) / 2);transform:translateY(50%);--__P__-callout-nudge-direction: 1}.__P__-callout[data-position=top]{bottom:calc(100% + var(--__P__-callout-gap));right:0;max-width:min(280px,calc(100vw - 32px))}.__P__-callout[data-position=bottom]{top:calc(100% + var(--__P__-callout-gap));right:0;max-width:min(280px,calc(100vw - 32px))}:host([data-position$="-left"]) .__P__-callout[data-position=top],:host([data-position$="-left"]) .__P__-callout[data-position=bottom]{right:auto;left:0}.__P__-callout[data-shape=bubble]{border-radius:var(--__P__-radius-md);white-space:normal;width:max-content;max-width:min(280px,calc(100vw - 32px))}.__P__-callout[data-shape=callout]{padding:12px 18px;font-size:14px;background:var(--__P__-accent);color:var(--__P__-accent-text)}.__P__-callout:after{content:"";position:absolute;width:12px;height:12px;background:inherit;border-radius:2px;transform:rotate(45deg)}.__P__-callout[data-position=left]:after{right:-5px;top:50%;margin-top:-6px}.__P__-callout[data-position=right]:after{left:-5px;top:50%;margin-top:-6px}.__P__-callout[data-position=top]:after{bottom:-5px;right:calc(var(--__P__-fab-size, 56px) / 2 - 6px)}.__P__-callout[data-position=bottom]:after{top:-5px;right:calc(var(--__P__-fab-size, 56px) / 2 - 6px)}:host([data-position$="-left"]) .__P__-callout[data-position=top]:after,:host([data-position$="-left"]) .__P__-callout[data-position=bottom]:after{right:auto;left:calc(var(--__P__-fab-size, 56px) / 2 - 6px)}.__P__-callout[data-animated]{animation:__P__-callout-in var(--__P__-dur-slow) var(--__P__-ease),__P__-callout-nudge 1.6s var(--__P__-ease-in-out) var(--__P__-dur-slow) infinite}@keyframes __P__-callout-in{0%{opacity:0}to{opacity:1}}@keyframes __P__-callout-nudge{0%,to{margin-left:0;margin-right:0}50%{margin-left:calc(6px * var(--__P__-callout-nudge-direction));margin-right:calc(-6px * var(--__P__-callout-nudge-direction))}}@media(prefers-reduced-motion:reduce){.__P__-callout[data-animated]{animation:__P__-callout-in 1ms var(--__P__-ease)}.__P__-icon-btn[data-recording=true],.__P__-typing span{animation:none}}.__P__-callout-close{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:999px;color:inherit;opacity:.7;cursor:pointer}.__P__-callout-close:hover{opacity:1;background:#ffffff26}.__P__-callout-close svg{width:12px;height:12px}.__P__-panel{width:var(--__P__-panel-w);height:var(--__P__-panel-h);max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);background:var(--__P__-bg);color:var(--__P__-fg);border-radius:var(--__P__-radius-lg);box-shadow:var(--__P__-shadow-panel);display:flex;flex-direction:column;overflow:hidden;transform-origin:bottom right;animation:__P__-panel-in var(--__P__-dur-slow) var(--__P__-ease);border:1px solid var(--__P__-border)}:host([data-mode="open"]) .__P__-panel{width:var(--__P__-widget-w, var(--__P__-panel-w));height:var(--__P__-widget-h, var(--__P__-panel-h));min-width:var(--__P__-resize-min-w, auto);min-height:var(--__P__-resize-min-h, auto);max-width:var(--__P__-resize-max-w, calc(100vw - 32px) );max-height:var(--__P__-resize-max-h, calc(100dvh - 32px) )}@keyframes __P__-panel-in{0%{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}:host([data-mode="expanded"]) .__P__-panel{width:var(--__P__-expanded-w, 640px);height:var(--__P__-expanded-h, 820px);max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px)}:host([data-mode="fullscreen"]){z-index:var(--__P__-z-panel)!important}:host([data-mode="fullscreen"]) .__P__-anchor{inset:0;align-items:stretch;padding:0}:host([data-mode="fullscreen"]) .__P__-panel{width:100vw;height:100dvh;max-width:none;max-height:none;border-radius:0;border:0}:host([data-mode="fullscreen"]) .__P__-fab{display:none}:host([data-mode="inline"]) .__P__-anchor,:host([data-mode="standalone"]) .__P__-anchor{position:static;inset:auto;padding:0;align-items:stretch;width:100%;height:100%;min-height:0}:host([data-mode="inline"]) .__P__-panel,:host([data-mode="standalone"]) .__P__-panel{width:100%;height:100%;min-width:0;min-height:0;max-width:none;max-height:none;animation:none}:host([data-mode="inline"]) .__P__-fab,:host([data-mode="standalone"]) .__P__-fab{display:none}:host([data-mode="inline"]){min-height:320px}:host([data-mode="inline"]) .__P__-panel{border-radius:var(--__P__-radius)}:host([data-mode="standalone"]) .__P__-panel{border-radius:0;border:0;box-shadow:none}:host([data-mode="modal"]){position:fixed!important;inset:0!important;z-index:var(--__P__-z-panel)!important;display:block!important;width:100vw;height:100dvh;background:var(--__P__-modal-backdrop, var(--__P__-backdrop));animation:__P__-backdrop-in var(--__P__-dur-base) var(--__P__-ease) both;--__P__-panel-w: min(960px, 92vw);--__P__-panel-h: min(720px, 88dvh)}:host([data-mode="modal"]) .__P__-anchor{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:var(--__P__-space-6);pointer-events:none}:host([data-mode="modal"]) .__P__-panel{pointer-events:auto;width:var(--__P__-widget-w, var(--__P__-panel-w));height:var(--__P__-widget-h, var(--__P__-panel-h));max-width:calc(100vw - 48px);max-height:calc(100dvh - 48px);min-width:0;min-height:0;border-radius:var(--__P__-radius);box-shadow:var(--__P__-shadow-panel);animation:__P__-modal-in var(--__P__-dur-base) var(--__P__-ease);translate:var(--__P__-modal-dx, 0px) var(--__P__-modal-dy, 0px)}:host([data-mode="modal"]) .__P__-header,:host([data-mode="modal"]) .__P__-back-header,:host([data-mode="modal"]) .__P__-home-hero{cursor:grab;touch-action:none}:host([data-mode="modal"]) .__P__-panel[data-dragging]{cursor:grabbing;user-select:none}:host([data-mode="modal"]) .__P__-panel[data-dragging] *{cursor:grabbing}:host([data-mode="modal"]) .__P__-fab{display:none}@keyframes __P__-backdrop-in{0%{background:#0000}to{background:var(--__P__-modal-backdrop, var(--__P__-backdrop))}}@keyframes __P__-modal-in{0%{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}:host([data-mode="drawer"]){--__P__-panel-w: min(440px, calc(100vw - 32px) );--__P__-panel-h: 100dvh}:host([data-mode="drawer"]) .__P__-anchor{position:fixed;--__P__-inset-x: var(--__P__-panel-inset, 12px);--__P__-inset-y: var(--__P__-panel-inset, 3dvh);top:var(--__P__-inset-y);bottom:auto;right:var(--__P__-inset-x);left:auto;width:min(var(--__P__-widget-w, var(--__P__-panel-w)),calc(100vw - var(--__P__-inset-x) * 2));height:min(var(--__P__-widget-h, var(--__P__-panel-h)),calc(100dvh - var(--__P__-inset-y) * 2));padding:0;display:block;pointer-events:auto}:host([data-mode="drawer"][data-position$="-left"]) .__P__-anchor{right:auto;left:var(--__P__-inset-x)}:host([data-mode="drawer"][data-position^="bottom-"]) .__P__-anchor{top:auto;bottom:var(--__P__-inset-y)}:host([data-mode="drawer"]) .__P__-panel{width:100%;height:100%;max-width:none;max-height:none;min-width:0;min-height:0;border-radius:var(--__P__-radius, 12px);border:1px solid var(--__P__-border);box-shadow:-8px 16px 32px -12px #00000038;animation:__P__-drawer-in var(--__P__-dur-base) var(--__P__-ease)}:host([data-mode="drawer"][data-position$="-left"]) .__P__-panel{box-shadow:8px 16px 32px -12px #00000038;animation:__P__-drawer-in-left var(--__P__-dur-base) var(--__P__-ease)}.__P__-fab[data-edge-tab]{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--__P__-space-2);position:fixed;top:50%;height:140px;width:auto;min-width:0;padding:10px 8px;writing-mode:vertical-rl;text-orientation:mixed;transform:translateY(-50%);transform-origin:center;animation:__P__-edge-tab-in var(--__P__-dur-base) var(--__P__-ease) both}.__P__-fab[data-edge-tab] svg{writing-mode:horizontal-tb}.__P__-fab[data-edge-tab]:hover{transform:translateY(-50%) scale(1.03)}.__P__-fab[data-edge-tab]:active{transform:translateY(-50%) scale(.97)}:host([data-position$="-right"]) .__P__-fab[data-edge-tab]{right:0;left:auto;border-radius:12px 0 0 12px;box-shadow:-6px 0 18px -8px #0000004d}:host([data-position$="-left"]) .__P__-fab[data-edge-tab]{left:0;right:auto;border-radius:0 12px 12px 0;box-shadow:6px 0 18px -8px #0000004d}.__P__-fab[data-edge-tab][data-leaving]{position:fixed;top:50%;bottom:auto;animation:__P__-edge-tab-out var(--__P__-dur-quick) var(--__P__-ease) forwards}@keyframes __P__-edge-tab-in{0%{opacity:0;transform:translateY(-50%) scale(.9)}to{opacity:1;transform:translateY(-50%) scale(1)}}@keyframes __P__-edge-tab-out{0%{opacity:1;transform:translateY(-50%) scale(1)}to{opacity:0;transform:translateY(-50%) scale(.85)}}@keyframes __P__-drawer-in{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes __P__-drawer-in-left{0%{transform:translate(-100%)}to{transform:translate(0)}}@media(prefers-reduced-motion:reduce){:host([data-mode="drawer"]) .__P__-panel,.__P__-fab[data-edge-tab]{animation:none}}.__P__-header{display:flex;align-items:center;gap:var(--__P__-space-2);padding:10px 12px;border-bottom:1px solid var(--__P__-border);background:var(--__P__-bg)}.__P__-header h1{font-size:14px;font-weight:600;flex:1;letter-spacing:-.01em}.__P__-header-actions{margin-left:auto;display:flex;align-items:center;gap:var(--__P__-space-1);flex-shrink:0}.__P__-agent{flex:1;display:inline-flex;align-items:center;gap:10px;min-width:0}.__P__-agent-avatar{position:relative;width:32px;height:32px;border-radius:999px;background:var(--__P__-bg-elevated);color:var(--__P__-fg-muted);display:inline-flex;align-items:center;justify-content:center;font-weight:700;font-size:var(--__P__-text-xs);overflow:hidden;flex-shrink:0}.__P__-agent-avatar img{width:100%;height:100%;object-fit:cover}.__P__-agent-avatar:after{content:"";position:absolute;right:-1px;bottom:-1px;width:10px;height:10px;border-radius:999px;border:2px solid var(--__P__-bg);background:var(--__P__-neutral)}.__P__-agent-avatar[data-status=online]:after{background:var(--__P__-success)}.__P__-agent-avatar[data-status=away]:after{background:var(--__P__-warning)}.__P__-agent-avatar[data-status=offline]:after{background:var(--__P__-neutral)}.__P__-agent-meta{display:flex;flex-direction:column;line-height:1.15;min-width:0}.__P__-agent-meta strong{font-size:14px;font-weight:600;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-agent-meta span{font-size:var(--__P__-text-xs);color:var(--__P__-fg-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-suggestions{display:flex;flex-wrap:nowrap;gap:var(--__P__-space-2);padding:6px 14px 10px;overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth;scroll-snap-type:x proximity;scrollbar-width:none;-ms-overflow-style:none;min-width:0}.__P__-suggestions::-webkit-scrollbar{display:none}.__P__-suggestions:before,.__P__-suggestions:after{content:"";flex:1 1 0;min-width:0}.__P__-suggestion{flex:0 0 auto;scroll-snap-align:center;padding:7px 14px;border-radius:999px;background:var(--__P__-bg-elevated);border:1px solid var(--__P__-border);color:var(--__P__-fg);font-size:var(--__P__-text-sm);font-weight:500;white-space:nowrap;transition:background var(--__P__-dur-quick) var(--__P__-ease),border-color var(--__P__-dur-quick) var(--__P__-ease),transform var(--__P__-dur-quick) var(--__P__-ease)}.__P__-suggestion:hover{border-color:var(--__P__-accent);color:var(--__P__-accent);transform:translateY(-1px)}.__P__-suggestion:focus-visible{outline:2px solid var(--__P__-accent);outline-offset:2px;border-color:var(--__P__-accent)}.__P__-suggestion:active{transform:translateY(0)}.__P__-icon-btn{width:32px;height:32px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;color:var(--__P__-fg-muted);transition:background var(--__P__-dur-quick) var(--__P__-ease),color var(--__P__-dur-quick) var(--__P__-ease)}.__P__-icon-btn:hover{background:var(--__P__-bg-elevated);color:var(--__P__-fg)}.__P__-icon-btn:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-icon-btn:active{background:var(--__P__-border)}.__P__-icon-btn:disabled{opacity:.45;cursor:not-allowed}.__P__-icon-btn:before{content:"";position:absolute;inset:-6px}.__P__-icon-btn{position:relative}.__P__-icon-btn svg{width:18px;height:18px}.__P__-icon-btn[data-recording=true]{color:var(--__P__-accent);background:color-mix(in srgb,var(--__P__-accent) 12%,transparent);animation:__P__-pulse 1.2s var(--__P__-ease) infinite}@keyframes __P__-pulse{0%,to{box-shadow:0 0 color-mix(in srgb,var(--__P__-accent) 40%,transparent)}50%{box-shadow:0 0 0 6px color-mix(in srgb,var(--__P__-accent) 0%,transparent)}}.__P__-list-wrap{position:relative;flex:1;min-height:0;display:flex;flex-direction:column}.__P__-jump{position:absolute;right:14px;bottom:14px;z-index:2;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:999px;border:1px solid var(--__P__-border);background:var(--__P__-bg-elevated);color:var(--__P__-fg);box-shadow:var(--__P__-shadow-panel);cursor:pointer;opacity:.85;transition:opacity var(--__P__-dur-quick) var(--__P__-ease),transform var(--__P__-dur-quick) var(--__P__-ease);animation:__P__-bubble-in var(--__P__-dur-base) var(--__P__-ease)}.__P__-jump:hover{opacity:1}.__P__-jump:active{transform:translateY(1px)}.__P__-jump svg{width:18px;height:18px}.__P__-list{flex:1;min-height:0;overflow-y:auto;padding:var(--__P__-space-4);padding-bottom:var(--__P__-space-8);display:flex;flex-direction:column;gap:14px;scrollbar-width:thin;scrollbar-color:var(--__P__-border-strong) transparent;scrollbar-gutter:stable}.__P__-list::-webkit-scrollbar{width:8px}.__P__-list::-webkit-scrollbar-thumb{background:var(--__P__-border-strong);border-radius:8px}.__P__-date-divider{position:sticky;top:var(--__P__-space-2);z-index:2;display:flex;justify-content:center;margin:var(--__P__-space-1) 0;pointer-events:none}.__P__-date-pill{padding:3px 10px;border-radius:999px;font-size:11px;font-weight:600;color:var(--__P__-fg-muted);background:var(--__P__-bg-elevated);border:1px solid var(--__P__-border);box-shadow:var(--__P__-shadow-card);opacity:0;pointer-events:none;transition:opacity var(--__P__-dur-base) var(--__P__-ease)}.__P__-list[data-scrolling=true] .__P__-date-pill{opacity:1;pointer-events:auto}@media(prefers-reduced-motion:reduce){.__P__-date-pill{transition:none}}.__P__-bubble-row{display:flex}.__P__-bubble-row[data-role=user]{justify-content:flex-end}.__P__-bubble-row[data-role=assistant]{justify-content:flex-start}.__P__-bubble{max-width:100%;padding:var(--__P__-space-3) var(--__P__-space-4);border-radius:var(--__P__-radius);line-height:1.6;font-size:14px;word-wrap:break-word;overflow-wrap:anywhere;box-shadow:0 1px 2px #0000000a,0 1px 8px -4px #0000000f;animation:__P__-bubble-in var(--__P__-dur-base) var(--__P__-ease)}.__P__-bubble ::selection{background:color-mix(in srgb,var(--__P__-accent) 30%,transparent)}.__P__-bubble-row[data-role=user] .__P__-bubble ::selection{background:#fff6;color:var(--__P__-bubble-user-text)}@keyframes __P__-bubble-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.__P__-bubble-row[data-role=user] .__P__-bubble{background:var(--__P__-bubble-user);color:var(--__P__-bubble-user-text);border-bottom-right-radius:5px}.__P__-bubble-row[data-role=assistant] .__P__-bubble{background:var(--__P__-bubble-assistant);color:var(--__P__-bubble-assistant-text);border-bottom-left-radius:5px}.__P__-bubble-col{display:flex;flex-direction:column;max-width:85%;min-width:0}.__P__-bubble-row[data-role=user] .__P__-bubble-col{align-items:flex-end}.__P__-bubble-row[data-role=assistant] .__P__-bubble-col{align-items:flex-start}.__P__-bubble-time{margin-top:3px;padding:0 4px;font-size:11px;line-height:1;color:var(--__P__-fg-muted);user-select:none}.__P__-md>*:first-child{margin-top:0}.__P__-md>*:last-child{margin-bottom:0}.__P__-md p{margin:10px 0}.__P__-md h1,.__P__-md h2,.__P__-md h3,.__P__-md h4,.__P__-md h5,.__P__-md h6{margin:18px 0 8px;line-height:1.3;letter-spacing:-.01em;font-weight:700}.__P__-md h1{font-size:1.4em}.__P__-md h2{font-size:1.22em}.__P__-md h3{font-size:1.08em}.__P__-md h4,.__P__-md h5,.__P__-md h6{font-size:1em}.__P__-md>h1:first-child,.__P__-md>h2:first-child,.__P__-md>h3:first-child,.__P__-md>h4:first-child,.__P__-md>h5:first-child,.__P__-md>h6:first-child{margin-top:0}.__P__-md ul,.__P__-md ol{padding-left:1.5em;margin:10px 0}.__P__-md ul{list-style:disc}.__P__-md ol{list-style:decimal}.__P__-md li{margin:6px 0;padding-left:2px}.__P__-md li::marker{color:var(--__P__-fg-muted)}.__P__-md li>p{margin:6px 0}.__P__-md li>ul,.__P__-md li>ol{margin:6px 0}.__P__-md strong,.__P__-md b{font-weight:650;letter-spacing:-.005em}.__P__-md em,.__P__-md i{font-style:italic}.__P__-md code{font-family:var(--__P__-font-mono);font-size:.86em;padding:1px 6px;border-radius:5px;background:color-mix(in srgb,var(--__P__-accent) 10%,transparent);color:var(--__P__-fg);border:1px solid color-mix(in srgb,var(--__P__-accent) 16%,transparent)}.__P__-md pre{font-family:var(--__P__-font-mono);font-size:12.5px;padding:12px 14px;border-radius:var(--__P__-radius-sm);background:#7f7f7f1f;overflow-x:auto;margin:var(--__P__-space-3) 0;line-height:1.5}.__P__-md pre code{padding:0;background:none}.__P__-md a{color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}.__P__-md a:hover{text-decoration-thickness:2px}.__P__-md blockquote{margin:14px 0;padding:6px 14px;border-left:3px solid color-mix(in srgb,var(--__P__-accent) 50%,transparent);background:color-mix(in srgb,var(--__P__-accent) 5%,transparent);border-radius:0 var(--__P__-radius-sm) var(--__P__-radius-sm) 0;color:var(--__P__-fg-muted)}.__P__-md blockquote>:first-child{margin-top:0}.__P__-md blockquote>:last-child{margin-bottom:0}.__P__-md hr{border:0;height:1px;background:color-mix(in srgb,currentColor 18%,transparent);margin:var(--__P__-space-4) 0}.__P__-md table{border-collapse:collapse;margin:var(--__P__-space-3) 0;font-size:.95em;display:block;overflow-x:auto;max-width:100%;font-variant-numeric:tabular-nums}.__P__-md th,.__P__-md td{padding:6px 10px;border-bottom:1px solid color-mix(in srgb,currentColor 12%,transparent);text-align:left}.__P__-md th{font-weight:700;background:color-mix(in srgb,currentColor 6%,transparent)}.__P__-md h1+ul,.__P__-md h1+ol,.__P__-md h2+ul,.__P__-md h2+ol,.__P__-md h3+ul,.__P__-md h3+ol,.__P__-md h4+ul,.__P__-md h4+ol{margin-top:var(--__P__-space-1)}.__P__-loading{display:inline-flex;align-items:center;gap:var(--__P__-space-2);color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm)}.__P__-loading-spinner{width:14px;height:14px;border-radius:999px;border:2px solid currentColor;border-top-color:transparent;animation:__P__-spin .8s linear infinite}@keyframes __P__-spin{to{transform:rotate(1turn)}}.__P__-typing{display:inline-flex;gap:var(--__P__-space-1);padding:var(--__P__-space-1) 0}.__P__-typing span{width:5px;height:5px;border-radius:999px;background:currentColor;opacity:.4;animation:__P__-blink 1.2s var(--__P__-ease) infinite}.__P__-typing span:nth-child(2){animation-delay:.2s}.__P__-typing span:nth-child(3){animation-delay:.4s}@keyframes __P__-blink{0%,80%,to{opacity:.3;transform:translateY(0)}40%{opacity:1;transform:translateY(-2px)}}.__P__-reasoning{margin:var(--__P__-space-1) 0 var(--__P__-space-2);padding-left:var(--__P__-space-3);border-left:2px solid var(--__P__-border-strong)}.__P__-reasoning-summary{display:inline-flex;align-items:center;gap:var(--__P__-space-1);cursor:pointer;list-style:none;user-select:none;color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs);font-weight:600}.__P__-reasoning-summary::-webkit-details-marker{display:none}.__P__-reasoning-summary:before{content:"";width:5px;height:5px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(-45deg);opacity:.7;transition:transform var(--__P__-dur-quick) var(--__P__-ease)}.__P__-reasoning[open] .__P__-reasoning-summary:before{transform:rotate(45deg)}.__P__-reasoning[data-active=true] .__P__-reasoning-label{animation:__P__-reasoning-pulse 1.4s var(--__P__-ease) infinite}@keyframes __P__-reasoning-pulse{0%,to{opacity:.5}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.__P__-reasoning[data-active=true] .__P__-reasoning-label{animation:none}}.__P__-reasoning-body{margin-top:var(--__P__-space-1);color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm)}.__P__-reasoning-body>:first-child{margin-top:0}.__P__-reasoning-body>:last-child{margin-bottom:0}.__P__-tool-chip{display:inline-flex;align-items:center;gap:6px;padding:var(--__P__-space-1) var(--__P__-space-2);margin-top:6px;border-radius:999px;background:var(--__P__-bg-elevated);border:1px solid var(--__P__-border);color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs)}.__P__-composer{border-top:1px solid var(--__P__-border);padding:10px 12px;background:var(--__P__-bg);display:flex;flex-direction:column;gap:var(--__P__-space-2)}.__P__-composer-row{display:flex;align-items:flex-end;gap:6px}.__P__-textarea{flex:1;height:40px;max-height:160px;padding:10px 12px;border-radius:var(--__P__-radius);background:var(--__P__-bg-elevated);border:1px solid transparent;font-size:14px;line-height:1.4;transition:height var(--__P__-dur-quick) var(--__P__-ease),border-color var(--__P__-dur-quick) var(--__P__-ease),box-shadow var(--__P__-dur-quick) var(--__P__-ease)}.__P__-textarea:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:1px;border-color:var(--__P__-focus)}@media(pointer:coarse){.__P__-textarea,.__P__-home-search-input{font-size:16px}.__P__-textarea{height:44px}}.__P__-send{width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;transition:opacity var(--__P__-dur-quick) var(--__P__-ease),transform var(--__P__-dur-quick) var(--__P__-ease),background var(--__P__-dur-quick) var(--__P__-ease)}.__P__-send[data-shape=circle]{border-radius:999px}.__P__-send[data-shape=square]{border-radius:var(--__P__-radius-sm)}.__P__-send[data-shape=pill]{width:auto;padding:0 18px;border-radius:999px}.__P__-send[data-variant=filled]{background:var(--__P__-accent);color:var(--__P__-accent-text)}.__P__-send[data-variant=outline]{background:transparent;color:var(--__P__-accent);border-color:var(--__P__-accent)}.__P__-send[data-variant=outline]:not(:disabled):hover{background:color-mix(in srgb,var(--__P__-accent) 10%,transparent)}.__P__-send[data-variant=ghost]{background:transparent;color:var(--__P__-accent)}.__P__-send[data-variant=ghost]:not(:disabled):hover{background:color-mix(in srgb,var(--__P__-accent) 8%,transparent)}.__P__-send:disabled{opacity:.4;cursor:not-allowed}.__P__-send:not(:disabled):hover{transform:translateY(-1px)}.__P__-send:not(:disabled):active{transform:translateY(0)}.__P__-send:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-send svg{width:18px;height:18px}.__P__-composer-actions{display:flex;gap:var(--__P__-space-1);flex-wrap:wrap}.__P__-attachments{display:flex;flex-wrap:wrap;gap:6px}.__P__-attachment-chip{display:inline-flex;align-items:center;gap:6px;padding:var(--__P__-space-1) var(--__P__-space-2) var(--__P__-space-1) var(--__P__-space-1);border-radius:999px;background:var(--__P__-bg-elevated);border:1px solid var(--__P__-border);font-size:var(--__P__-text-xs);max-width:200px}.__P__-attachment-thumb{width:24px;height:24px;border-radius:999px;object-fit:cover;background:var(--__P__-border)}.__P__-attachment-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.__P__-attachment-remove{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;color:var(--__P__-fg-muted)}.__P__-attachment-remove:hover{background:var(--__P__-border);color:var(--__P__-fg)}.__P__-dropzone{position:absolute;inset:8px;border:2px dashed var(--__P__-accent);border-radius:var(--__P__-radius);background:color-mix(in srgb,var(--__P__-accent) 8%,transparent);display:flex;align-items:center;justify-content:center;font-weight:600;color:var(--__P__-accent);pointer-events:none;z-index:10;animation:__P__-fade-in var(--__P__-dur-quick) var(--__P__-ease)}@keyframes __P__-fade-in{0%{opacity:0}to{opacity:1}}.__P__-error{margin-top:var(--__P__-space-1);padding:8px 10px;border-radius:var(--__P__-radius-sm);background:var(--__P__-danger-bg);color:var(--__P__-danger-text);font-size:var(--__P__-text-sm);display:flex;align-items:center;gap:var(--__P__-space-2)}.__P__-error button{color:inherit;text-decoration:underline;font-size:var(--__P__-text-sm)}.__P__-history{flex:1;overflow-y:auto;padding:var(--__P__-space-2) var(--__P__-space-1) var(--__P__-space-3)}.__P__-history-footer{flex:none;padding:var(--__P__-space-2) var(--__P__-space-3) var(--__P__-space-3);border-top:1px solid var(--__P__-border);background:var(--__P__-surface)}.__P__-history-new{width:100%;display:flex;align-items:center;justify-content:center;gap:var(--__P__-space-2);padding:var(--__P__-space-2) var(--__P__-space-3);border:none;border-radius:var(--__P__-radius-md);background:var(--__P__-accent);color:var(--__P__-on-accent);cursor:pointer;font-size:var(--__P__-text-sm);font-weight:600;transition:filter var(--__P__-dur-quick) var(--__P__-ease-out),transform var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-history-new svg{width:16px;height:16px}.__P__-history-new:hover{filter:brightness(1.08)}.__P__-history-new:active{transform:translateY(1px)}.__P__-history-new:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-history-empty{flex:1;display:flex;align-items:center;justify-content:center;padding:40px 16px;color:var(--__P__-fg-muted);font-size:14px;text-align:center}.__P__-history-group{display:flex;flex-direction:column;padding:0 var(--__P__-space-2)}.__P__-history-heading{font-size:var(--__P__-text-xs);font-weight:600;color:var(--__P__-fg-muted);padding:12px 8px 6px;text-transform:uppercase;letter-spacing:.04em}.__P__-history-item{all:unset;display:flex;flex-direction:column;gap:3px;padding:10px 12px;border-radius:var(--__P__-radius-md);cursor:pointer;transition:background var(--__P__-dur-base) var(--__P__-ease)}.__P__-history-item:hover{background:var(--__P__-bg-elevated)}.__P__-history-item:focus-visible{background:var(--__P__-bg-elevated);outline:2px solid var(--__P__-focus);outline-offset:-2px}.__P__-history-title{font-size:14px;font-weight:500;color:var(--__P__-fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-history-preview{font-size:var(--__P__-text-xs);color:var(--__P__-fg-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-history-item[data-closed=true] .__P__-history-title:after{content:"\\2022";margin-left:var(--__P__-space-2);opacity:.5}.__P__-list-loading{margin:auto;padding:var(--__P__-space-6) var(--__P__-space-4);color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm);text-align:center}.__P__-readonly-banner{display:flex;flex-direction:column;align-items:center;gap:10px;padding:14px 12px;margin:0 var(--__P__-space-3) var(--__P__-space-3);border-radius:var(--__P__-radius-md);background:var(--__P__-bg-elevated);color:var(--__P__-fg-muted);text-align:center;font-size:var(--__P__-text-sm)}.__P__-readonly-label{line-height:1.4}.__P__-readonly-cta{appearance:none;border:0;cursor:pointer;padding:var(--__P__-space-2) var(--__P__-space-4);border-radius:999px;background:var(--__P__-accent);color:var(--__P__-accent-text, #fff);font:inherit;font-weight:600;font-size:var(--__P__-text-sm);transition:filter var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-readonly-cta:hover,.__P__-readonly-cta:focus-visible{filter:brightness(1.1)}.__P__-readonly-cta:focus-visible{outline:2px solid var(--__P__-accent);outline-offset:2px}.__P__-composer-footer{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;padding:10px 16px;margin:0 var(--__P__-space-3);border-top:1px solid var(--__P__-border);text-align:center;font-size:11px;line-height:1.4;color:var(--__P__-fg-muted)}.__P__-disclaimer{max-width:320px;margin:0 auto;opacity:.9;letter-spacing:.01em}.__P__-poweredby{display:inline-flex;align-items:center;justify-content:center;gap:6px;color:inherit;text-decoration:none;opacity:.7;transition:opacity var(--__P__-dur-base) var(--__P__-ease);font-size:11px;letter-spacing:.02em}.__P__-poweredby:hover{opacity:1}.__P__-poweredby-logo{height:12px;width:auto;display:inline-block;vertical-align:middle}.__P__-poweredby-bar{flex:none;display:flex;align-items:center;justify-content:center;padding:6px 16px;border-top:1px solid var(--__P__-border);background:var(--__P__-bg-elevated)}.__P__-menu-wrap{position:relative;display:inline-flex}.__P__-menu{position:absolute;top:100%;right:0;margin-top:6px;min-width:200px;padding:6px;background:var(--__P__-bg);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius-md);box-shadow:var(--__P__-shadow-panel);z-index:10;display:flex;flex-direction:column;gap:2px;animation:__P__-menu-in var(--__P__-dur-base) var(--__P__-ease)}@media(prefers-reduced-motion:reduce){.__P__-menu{animation:none}}@keyframes __P__-menu-in{0%{opacity:0;transform:translateY(-4px) scale(.98);transform-origin:top right}to{opacity:1;transform:none}}.__P__-menu-item{all:unset;display:flex;align-items:center;gap:10px;padding:8px 10px;font-size:var(--__P__-text-sm);color:var(--__P__-fg);border-radius:var(--__P__-radius-sm);cursor:pointer;user-select:none}.__P__-menu-item:hover{background:var(--__P__-bg-elevated)}.__P__-menu-item:focus-visible{background:var(--__P__-bg-elevated);outline:2px solid var(--__P__-focus);outline-offset:-2px}.__P__-menu-item[disabled]{opacity:.45;cursor:not-allowed}.__P__-menu-icon{display:inline-flex;width:16px;height:16px;color:var(--__P__-fg-muted)}.__P__-menu-icon svg{width:16px;height:16px}.__P__-menu-label{flex:1}.__P__-menu-check{display:inline-flex;color:var(--__P__-accent)}.__P__-menu-check svg{width:14px;height:14px}.__P__-resize-grip{position:absolute;width:18px;height:18px;display:flex;align-items:center;justify-content:center;color:var(--__P__-fg-muted);opacity:.45;transition:opacity var(--__P__-dur-base) var(--__P__-ease);z-index:2;touch-action:none;user-select:none}.__P__-resize-grip:hover,.__P__-resize-grip:focus-visible{opacity:1}.__P__-resize-grip svg{width:10px;height:10px}.__P__-resize-grip--bottom-left{bottom:2px;left:2px;cursor:nesw-resize;transform:scaleX(-1)}.__P__-resize-grip--bottom-right{bottom:2px;right:2px;cursor:nwse-resize}.__P__-resize-grip--top-left{top:2px;left:2px;cursor:nwse-resize;transform:rotate(180deg)}.__P__-resize-grip--top-right{top:2px;right:2px;cursor:nesw-resize;transform:scaleY(-1)}:host(:not([data-mode="open"])) .__P__-resize-grip{display:none}.__P__-messenger{display:flex;flex-direction:column;overflow:hidden}.__P__-messenger-body{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.__P__-module{display:flex;flex-direction:column;height:100%;min-height:0}.__P__-module-scroll{flex:1;min-height:0;overflow-y:auto;padding:var(--__P__-space-3);display:flex;flex-direction:column;gap:var(--__P__-space-3)}.__P__-home{background:radial-gradient(125% 65% at 88% 0%,color-mix(in srgb,#fff 16%,transparent),transparent 55%),linear-gradient(180deg,var(--__P__-accent) 0%,var(--__P__-accent) 22%,color-mix(in srgb,var(--__P__-accent) 28%,var(--__P__-surface)) 44%,var(--__P__-surface) 70%);border-radius:var(--__P__-radius-lg) var(--__P__-radius-lg) 0 0}.__P__-home-scroll{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;background:transparent}.__P__-home-cards{display:flex;flex-direction:column;gap:var(--__P__-space-3);padding:4px 14px 16px}.__P__-module-pad{padding:var(--__P__-space-3) var(--__P__-space-3) 0}.__P__-module-empty{display:flex;flex-direction:column;align-items:center;gap:var(--__P__-space-3);padding:var(--__P__-space-8) var(--__P__-space-4);text-align:center;color:var(--__P__-fg-muted);font-size:var(--__P__-text-base)}.__P__-module-retry{padding:var(--__P__-space-2) var(--__P__-space-4);border:1px solid var(--__P__-border-strong);border-radius:var(--__P__-radius-sm);color:var(--__P__-fg);font-weight:600;cursor:pointer;transition:background var(--__P__-dur-quick) var(--__P__-ease-out),border-color var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-module-retry:hover{background:var(--__P__-hover);border-color:var(--__P__-accent)}.__P__-module-retry:active{background:var(--__P__-border)}.__P__-module-retry:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-help-list{flex:1;min-height:0;overflow-y:auto;padding-bottom:var(--__P__-space-3)}.__P__-help-group{display:flex;flex-direction:column}.__P__-help-section-title{position:sticky;top:0;z-index:1;margin:0;padding:var(--__P__-space-3) var(--__P__-space-5) var(--__P__-space-2);font-size:var(--__P__-text-xs);font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--__P__-fg-muted);background:var(--__P__-bg)}.__P__-help-card{margin:0 var(--__P__-space-3) var(--__P__-space-3);background:var(--__P__-surface);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius);overflow:hidden}.__P__-help-card .__P__-list-row{border-bottom:0;border-radius:0}.__P__-help-card .__P__-list-row+.__P__-list-row{border-top:1px solid var(--__P__-border)}.__P__-help-card .__P__-list-row:hover{background:var(--__P__-hover)}.__P__-module-cta{padding:var(--__P__-space-3);border-top:1px solid var(--__P__-border)}.__P__-tabbar{display:flex;border-top:1px solid var(--__P__-border);background:var(--__P__-bg-elevated);flex-shrink:0}.__P__-tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--__P__-space-1);min-height:48px;padding:var(--__P__-space-2) var(--__P__-space-1);color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs);font-weight:600;transition:color var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-tab:hover{color:var(--__P__-fg)}.__P__-tab[aria-selected=true]{color:var(--__P__-accent)}.__P__-tab:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:-2px}.__P__-tab:active{background:var(--__P__-hover)}.__P__-tab-icon{position:relative;display:inline-flex}.__P__-tab-icon svg{width:22px;height:22px}.__P__-tab-badge{position:absolute;top:-4px;left:calc(50% + 6px);min-width:16px;height:16px;padding:0 4px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;background:var(--__P__-accent);color:var(--__P__-on-accent);font-size:10px;font-weight:600;line-height:1}.__P__-home-hero{flex-shrink:0;padding:var(--__P__-space-5) var(--__P__-space-5) var(--__P__-space-3);color:var(--__P__-on-accent);--__P__-focus: var(--__P__-on-accent)}.__P__-home-hero-top{display:flex;align-items:center;justify-content:space-between;gap:var(--__P__-space-3);min-height:32px}.__P__-home-brand{font-size:14px;font-weight:600;letter-spacing:.01em;color:color-mix(in srgb,#fff 82%,transparent);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.__P__-home-brand-spacer{flex:1}.__P__-home-hero-actions{display:flex;align-items:center;gap:var(--__P__-space-2);flex-shrink:0}.__P__-home-hero-actions .__P__-icon-btn{color:#fff}.__P__-home-greeting{margin:28px 0 0;font-family:var(--__P__-font-display);font-size:var(--__P__-text-2xl);font-weight:800;line-height:1.18;letter-spacing:-.01em;overflow-wrap:anywhere}.__P__-home-lead{margin:2px 0 0;font-family:var(--__P__-font-display);font-size:var(--__P__-text-2xl);font-weight:800;line-height:1.18;letter-spacing:-.01em;color:color-mix(in srgb,var(--__P__-on-accent) 88%,transparent);overflow-wrap:anywhere}.__P__-home-avatars{display:flex}.__P__-home-avatar{width:30px;height:30px;border-radius:999px;overflow:hidden;margin-left:-10px;border:2px solid color-mix(in srgb,#fff 92%,transparent);box-shadow:0 1px 3px #0000002e;background:var(--__P__-surface);display:inline-flex;align-items:center;justify-content:center;font-size:var(--__P__-text-xs);font-weight:700;color:var(--__P__-fg)}.__P__-home-avatar:first-child{margin-left:0}.__P__-home-avatar img{width:100%;height:100%;object-fit:cover}.__P__-home-content{background:var(--__P__-surface);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius);box-shadow:var(--__P__-shadow-card);overflow:hidden}.__P__-home-content-title{padding:var(--__P__-space-4) var(--__P__-space-4) var(--__P__-space-3);font-size:var(--__P__-text-sm);font-weight:700}.__P__-home-content-list{display:flex;flex-direction:column;padding:0 var(--__P__-space-2) var(--__P__-space-2)}.__P__-home-content-list .__P__-list-row+.__P__-list-row{border-top:1px solid var(--__P__-border)}.__P__-home-card{display:block;width:100%;text-align:left;background:var(--__P__-surface);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius);padding:var(--__P__-space-4);box-shadow:var(--__P__-shadow-card)}.__P__-home-card[data-interactive=true]{cursor:pointer;transition:background var(--__P__-dur-quick) var(--__P__-ease-out),transform var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-home-card[data-interactive=true]:hover{background:var(--__P__-bg-elevated)}.__P__-home-card[data-interactive=true]:active{transform:translateY(1px)}.__P__-home-card[data-interactive=true]:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-home-recent-row{display:flex;align-items:center;gap:var(--__P__-space-3)}.__P__-home-recent-avatar{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;flex-shrink:0;border-radius:999px;background:color-mix(in oklch,var(--__P__-accent) 14%,transparent);color:var(--__P__-accent)}.__P__-home-recent-avatar svg{width:20px;height:20px}.__P__-home-recent-body{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}.__P__-home-recent-title{font-weight:600;font-size:14px}.__P__-home-recent-preview{color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.__P__-home-recent-at{color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs);flex-shrink:0}.__P__-home-recent-dot{width:8px;height:8px;border-radius:999px;background:var(--__P__-accent);flex-shrink:0}.__P__-home-recent-row[data-unread=true] .__P__-home-recent-title{font-weight:700}.__P__-home-status{display:flex;align-items:center;gap:var(--__P__-space-3)}.__P__-home-status-icon svg{width:22px;height:22px;color:var(--__P__-success)}.__P__-home-status[data-level=degraded] .__P__-home-status-icon svg{color:var(--__P__-warning)}.__P__-home-status[data-level=down] .__P__-home-status-icon svg{color:var(--__P__-danger)}.__P__-home-status-text{font-weight:600;font-size:14px}.__P__-home-search{display:flex;align-items:center;gap:var(--__P__-space-2);width:100%;padding:var(--__P__-space-3) var(--__P__-space-4);border-radius:var(--__P__-radius);border:1px solid var(--__P__-border);background:var(--__P__-surface);text-align:left}.__P__-home-search[data-input=true]{background:var(--__P__-bg-elevated)}.__P__-home-search:hover{border-color:var(--__P__-border-strong)}.__P__-home-search:focus-visible,.__P__-home-search:focus-within{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-home-search-text{flex:1;color:var(--__P__-fg-muted);font-size:14px}.__P__-home-search-input{flex:1;border:0;background:transparent;font-size:14px;color:var(--__P__-fg);outline:none}.__P__-home-search-icon svg{width:18px;height:18px;color:var(--__P__-accent)}.__P__-list-row{display:flex;align-items:center;gap:var(--__P__-space-3);width:100%;min-height:44px;text-align:left;padding:var(--__P__-space-3) var(--__P__-space-2);border-radius:var(--__P__-radius-sm)}.__P__-list-row:hover{background:var(--__P__-bg-elevated)}.__P__-list-row:active{background:var(--__P__-border)}.__P__-list-row:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:-2px}.__P__-list-row-body{display:flex;flex-direction:column;min-width:0;flex:1}.__P__-list-row-title{font-weight:600;font-size:var(--__P__-text-md);line-height:1.35}.__P__-list-row-sub{color:var(--__P__-fg-muted);font-size:var(--__P__-text-sm);margin-top:var(--__P__-space-1);line-height:1.45;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.__P__-list-row-chevron svg{width:18px;height:18px;color:var(--__P__-accent);flex-shrink:0}.__P__-back-header{display:flex;align-items:center;gap:var(--__P__-space-2);padding:10px 12px;border-bottom:1px solid var(--__P__-border);flex-shrink:0}.__P__-back-title{flex:1;text-align:center;font-size:var(--__P__-text-md);font-weight:700;margin:0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__P__-back-spacer{width:32px;height:1px}.__P__-content{display:flex;flex-direction:column;gap:14px;width:100%;max-width:68ch;margin:0 auto}.__P__-content-hero{width:100%;border-radius:var(--__P__-radius)}.__P__-content-subtitle{color:var(--__P__-fg-muted);margin:0}.__P__-content-frame{flex:1;min-height:0;width:100%;border:0;background:#fff}.__P__-news-list{display:flex;flex-direction:column;gap:var(--__P__-space-3)}.__P__-news-card{display:block;width:100%;text-align:left;border:1px solid var(--__P__-border);border-radius:var(--__P__-radius);overflow:hidden;background:var(--__P__-surface)}.__P__-news-card{transition:background var(--__P__-dur-quick) var(--__P__-ease-out),transform var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-news-card:hover{background:var(--__P__-bg-elevated)}.__P__-news-card:active{transform:translateY(1px)}.__P__-news-card:focus-visible{outline:2px solid var(--__P__-focus);outline-offset:2px}.__P__-news-hero{width:100%;display:block}.__P__-news-body{display:flex;flex-direction:column;gap:6px;padding:14px 16px}.__P__-news-tags{display:flex;gap:6px;flex-wrap:wrap}.__P__-news-tag{font-size:var(--__P__-text-xs);font-weight:600;color:var(--__P__-accent);background:color-mix(in srgb,var(--__P__-accent) 12%,transparent);padding:2px 8px;border-radius:999px}.__P__-news-title{font-weight:700;font-size:var(--__P__-text-md)}.__P__-news-summary{color:var(--__P__-fg-muted);font-size:14px;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.__P__-modules-empty{display:flex;align-items:center;justify-content:center;position:relative}.__P__-modules-empty-close{position:absolute;top:12px;right:12px}.__P__-modules-empty-text{color:var(--__P__-fg-muted);font-size:var(--__P__-text-base)}.__P__-form{display:flex;flex-direction:column;gap:var(--__P__-space-3)}.__P__-field{display:flex;flex-direction:column;gap:4px}.__P__-field-label{font-size:var(--__P__-text-sm);font-weight:600;color:var(--__P__-fg)}.__P__-field-req{color:var(--__P__-danger)}.__P__-field-input{width:100%;box-sizing:border-box;padding:var(--__P__-space-2) var(--__P__-space-3);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius-md);background:var(--__P__-bg);color:var(--__P__-fg);font:inherit;font-size:var(--__P__-text-sm);resize:vertical;transition:border-color var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-field-input:focus-visible{outline:none;border-color:var(--__P__-accent)}.__P__-field[data-invalid=true] .__P__-field-input{border-color:var(--__P__-danger)}.__P__-field-hint{font-size:var(--__P__-text-xs);color:var(--__P__-fg-muted)}.__P__-field-error{font-size:var(--__P__-text-xs);color:var(--__P__-danger)}.__P__-field-choices{display:flex;flex-direction:column;gap:6px}.__P__-choice{display:flex;align-items:flex-start;gap:8px;font-size:var(--__P__-text-sm);color:var(--__P__-fg);cursor:pointer}.__P__-choice input{margin-top:2px;accent-color:var(--__P__-accent)}.__P__-form-actions{display:flex;justify-content:flex-end;gap:var(--__P__-space-2);margin-top:2px}.__P__-form-submit,.__P__-tool-approve{padding:var(--__P__-space-2) var(--__P__-space-4);border:none;border-radius:var(--__P__-radius-md);background:var(--__P__-accent);color:var(--__P__-accent-text, #fff);font:inherit;font-weight:600;font-size:var(--__P__-text-sm);cursor:pointer;transition:filter var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-form-submit:hover:not(:disabled),.__P__-tool-approve:hover:not(:disabled){filter:brightness(1.06)}.__P__-form-submit:disabled{opacity:.6;cursor:default}.__P__-form-skip,.__P__-tool-reject{padding:var(--__P__-space-2) var(--__P__-space-4);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius-md);background:transparent;color:var(--__P__-fg-muted);font:inherit;font-size:var(--__P__-text-sm);cursor:pointer;transition:background var(--__P__-dur-quick) var(--__P__-ease-out)}.__P__-form-skip:hover:not(:disabled),.__P__-tool-reject:hover:not(:disabled){background:var(--__P__-bg-elevated)}.__P__-intake{display:flex;flex-direction:column;gap:var(--__P__-space-2);padding:var(--__P__-space-3) var(--__P__-space-4) var(--__P__-space-4);border-top:1px solid var(--__P__-border);overflow-y:auto}.__P__-intake-title{margin:0;font-size:var(--__P__-text-base);font-weight:700;color:var(--__P__-fg)}.__P__-intake-desc{margin:0 0 var(--__P__-space-1);font-size:var(--__P__-text-sm);color:var(--__P__-fg-muted)}.__P__-tool-ask-input,.__P__-tool-approval{display:flex;flex-direction:column;gap:var(--__P__-space-2);margin-top:6px;padding:var(--__P__-space-3);border:1px solid var(--__P__-border);border-radius:var(--__P__-radius-md);background:var(--__P__-bg-elevated)}.__P__-tool-head{display:flex;align-items:center;flex-wrap:wrap;gap:8px}.__P__-tool-badge{padding:2px 8px;border-radius:999px;background:var(--__P__-warning, #f59e0b);color:#1a1206;font-size:var(--__P__-text-xs);font-weight:600}.__P__-tool-title{font-size:var(--__P__-text-sm);color:var(--__P__-fg)}.__P__-tool-question{margin:0;font-size:var(--__P__-text-sm);font-weight:600;color:var(--__P__-fg)}.__P__-tool-desc{margin:0;font-size:var(--__P__-text-sm);color:var(--__P__-fg-muted)}.__P__-tool-args{margin:0;padding:var(--__P__-space-2);max-height:160px;overflow:auto;border-radius:var(--__P__-radius-sm);background:var(--__P__-bg);border:1px solid var(--__P__-border);color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs);white-space:pre-wrap;word-break:break-word}.__P__-tool-stale-note{margin:0;font-size:var(--__P__-text-xs);color:var(--__P__-fg-muted)}.__P__-tool-decided{flex-direction:row;align-items:center;flex-wrap:wrap;gap:8px}.__P__-tool-decided-label{padding:2px 8px;border-radius:999px;background:var(--__P__-bg);border:1px solid var(--__P__-border);color:var(--__P__-fg-muted);font-size:var(--__P__-text-xs);font-weight:600}.__P__-tool-decided-label[data-approved=true]{color:var(--__P__-success, #16a34a);border-color:var(--__P__-success, #16a34a)}.__P__-tool-decided-label[data-approved=false]{color:var(--__P__-danger);border-color:var(--__P__-danger)}.__P__-tool-decided-value{font-size:var(--__P__-text-sm);color:var(--__P__-fg)}\n';
|
|
771
929
|
|
|
772
930
|
// src/styles/standalone.css
|
|
773
931
|
var standalone_default = ".__P__-standalone-page{margin:0;height:100vh;background:var(--__P__-bg, #fff);display:grid;place-items:stretch}\n";
|
|
@@ -855,22 +1013,22 @@ function attachAdoptedSheet(shadow, doc) {
|
|
|
855
1013
|
}
|
|
856
1014
|
}
|
|
857
1015
|
function applyThemeOverrides(host, overrides) {
|
|
858
|
-
const
|
|
859
|
-
if (overrides.accent) host.style.setProperty(`--${
|
|
860
|
-
if (overrides.accentText) host.style.setProperty(`--${
|
|
861
|
-
if (overrides.radius) host.style.setProperty(`--${
|
|
862
|
-
if (overrides.fontFamily) host.style.setProperty(`--${
|
|
1016
|
+
const p33 = BRAND.cssPrefix;
|
|
1017
|
+
if (overrides.accent) host.style.setProperty(`--${p33}-accent`, overrides.accent);
|
|
1018
|
+
if (overrides.accentText) host.style.setProperty(`--${p33}-accent-text`, overrides.accentText);
|
|
1019
|
+
if (overrides.radius) host.style.setProperty(`--${p33}-radius`, overrides.radius);
|
|
1020
|
+
if (overrides.fontFamily) host.style.setProperty(`--${p33}-font`, overrides.fontFamily);
|
|
863
1021
|
}
|
|
864
1022
|
function applyThemeMode(host, mode) {
|
|
865
1023
|
host.dataset.theme = mode;
|
|
866
1024
|
}
|
|
867
1025
|
function applySize(host, size) {
|
|
868
|
-
const
|
|
869
|
-
if (size.width !== void 0) host.style.setProperty(`--${
|
|
870
|
-
if (size.height !== void 0) host.style.setProperty(`--${
|
|
871
|
-
if (size.expanded?.width !== void 0) host.style.setProperty(`--${
|
|
872
|
-
if (size.expanded?.height !== void 0) host.style.setProperty(`--${
|
|
873
|
-
if (size.inset !== void 0) host.style.setProperty(`--${
|
|
1026
|
+
const p33 = BRAND.cssPrefix;
|
|
1027
|
+
if (size.width !== void 0) host.style.setProperty(`--${p33}-panel-w`, size.width);
|
|
1028
|
+
if (size.height !== void 0) host.style.setProperty(`--${p33}-panel-h`, size.height);
|
|
1029
|
+
if (size.expanded?.width !== void 0) host.style.setProperty(`--${p33}-expanded-w`, size.expanded.width);
|
|
1030
|
+
if (size.expanded?.height !== void 0) host.style.setProperty(`--${p33}-expanded-h`, size.expanded.height);
|
|
1031
|
+
if (size.inset !== void 0) host.style.setProperty(`--${p33}-panel-inset`, size.inset);
|
|
874
1032
|
}
|
|
875
1033
|
function applyPosition(host, pos) {
|
|
876
1034
|
host.dataset.position = pos;
|
|
@@ -1041,11 +1199,11 @@ function toBase64Url(json) {
|
|
|
1041
1199
|
var nonEmpty = (ctx) => ctx && Object.keys(ctx).length > 0 ? ctx : void 0;
|
|
1042
1200
|
function encodeContext(user, page) {
|
|
1043
1201
|
const u = nonEmpty(user);
|
|
1044
|
-
const
|
|
1045
|
-
if (!u && !
|
|
1202
|
+
const p33 = nonEmpty(page);
|
|
1203
|
+
if (!u && !p33) return void 0;
|
|
1046
1204
|
const envelope = {};
|
|
1047
1205
|
if (u) envelope.user = u;
|
|
1048
|
-
if (
|
|
1206
|
+
if (p33) envelope.page = p33;
|
|
1049
1207
|
return toBase64Url(JSON.stringify(envelope));
|
|
1050
1208
|
}
|
|
1051
1209
|
|
|
@@ -1084,7 +1242,15 @@ var DEFAULT_PATHS = {
|
|
|
1084
1242
|
markRead: "/ai/agent/mark-read",
|
|
1085
1243
|
// ── CMS content (unified — Home / Help / News / docs) ─────────────
|
|
1086
1244
|
/** All widget content via one filtered endpoint. `GET /ai/agent/content?tags=…`. */
|
|
1087
|
-
content: "/ai/agent/content"
|
|
1245
|
+
content: "/ai/agent/content",
|
|
1246
|
+
/**
|
|
1247
|
+
* Optional pre-chat intake submission. POST `{ visitorId, sessionId, values,
|
|
1248
|
+
* skipped? }` → record the lead immediately (before/independent of the first
|
|
1249
|
+
* message), keyed by the same visitor + session as the conversation.
|
|
1250
|
+
* Overridable via `endpoints.intake`. Fire-and-forget; 404 on older backends
|
|
1251
|
+
* is ignored.
|
|
1252
|
+
*/
|
|
1253
|
+
intake: "/ai/agent/intake"
|
|
1088
1254
|
};
|
|
1089
1255
|
var CONTEXT_PARAM = "context";
|
|
1090
1256
|
function buildSendMessageRequest(params) {
|
|
@@ -1108,18 +1274,34 @@ function buildSendMessageRequest(params) {
|
|
|
1108
1274
|
if (Object.keys(data).length > 0) body.data = data;
|
|
1109
1275
|
return body;
|
|
1110
1276
|
}
|
|
1277
|
+
function isResolvedToolPart(p33) {
|
|
1278
|
+
return p33.state === "output" || p33.state === "error" || p33.approval?.approved !== void 0;
|
|
1279
|
+
}
|
|
1111
1280
|
function normalizeToolRef(ref) {
|
|
1112
1281
|
if (typeof ref === "string") return ref ? { code: ref } : null;
|
|
1113
1282
|
return ref?.code ? ref : null;
|
|
1114
1283
|
}
|
|
1115
1284
|
function messageToWireParts(m) {
|
|
1116
1285
|
const out = [];
|
|
1117
|
-
for (const
|
|
1118
|
-
if (
|
|
1119
|
-
out.push({ text:
|
|
1286
|
+
for (const p33 of m.parts) {
|
|
1287
|
+
if (p33.kind === "text" && p33.text) {
|
|
1288
|
+
out.push({ text: p33.text, type: "text" });
|
|
1120
1289
|
}
|
|
1121
|
-
if (
|
|
1122
|
-
out.push({ mediaType:
|
|
1290
|
+
if (p33.kind === "file" && p33.url) {
|
|
1291
|
+
out.push({ mediaType: p33.mediaType, type: "file", url: p33.url });
|
|
1292
|
+
}
|
|
1293
|
+
if (p33.kind === "tool" && isResolvedToolPart(p33)) {
|
|
1294
|
+
const part = {
|
|
1295
|
+
type: "tool",
|
|
1296
|
+
toolCallId: p33.toolCallId,
|
|
1297
|
+
toolName: p33.toolName,
|
|
1298
|
+
state: p33.state
|
|
1299
|
+
};
|
|
1300
|
+
if (p33.input !== void 0) part.input = p33.input;
|
|
1301
|
+
if (p33.output !== void 0) part.output = p33.output;
|
|
1302
|
+
if (p33.error !== void 0) part.errorText = p33.error;
|
|
1303
|
+
if (p33.approval && p33.approval.approved !== void 0) part.approval = p33.approval;
|
|
1304
|
+
out.push(part);
|
|
1123
1305
|
}
|
|
1124
1306
|
}
|
|
1125
1307
|
for (const a of m.attachments ?? []) {
|
|
@@ -1366,6 +1548,25 @@ var AgentTransport = class {
|
|
|
1366
1548
|
get transcribePath() {
|
|
1367
1549
|
return this.opts.endpoints?.transcribe ?? "/ai/agent/transcribe-audio";
|
|
1368
1550
|
}
|
|
1551
|
+
get intakePath() {
|
|
1552
|
+
return this.opts.endpoints?.intake ?? DEFAULT_PATHS.intake;
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Record a completed pre-chat intake form. Fire-and-forget — the lead is
|
|
1556
|
+
* captured even if the visitor never sends a message. `sessionId` is explicit
|
|
1557
|
+
* so the record ties to the conversation that follows; `visitorId` + context
|
|
1558
|
+
* ride the envelope. A failure (e.g. 404 on a backend that doesn't implement
|
|
1559
|
+
* the endpoint) is non-fatal — the values still reach the agent as
|
|
1560
|
+
* `userContext` on the next message, so callers don't await this.
|
|
1561
|
+
*/
|
|
1562
|
+
async submitIntake(sessionId, values, skipped = false) {
|
|
1563
|
+
log4.debug("submitIntake \u2192", { sessionId, fields: Object.keys(values).length, skipped });
|
|
1564
|
+
try {
|
|
1565
|
+
await this.postJson(this.intakePath, { sessionId, values, skipped }, "submitIntake");
|
|
1566
|
+
} catch (err) {
|
|
1567
|
+
log4.debug("submitIntake failed (non-fatal)", { err });
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1369
1570
|
sendMessage(body) {
|
|
1370
1571
|
log4.debug("message \u2192", {
|
|
1371
1572
|
sessionId: body.sessionId,
|
|
@@ -1679,8 +1880,21 @@ function fromWireMessage(w) {
|
|
|
1679
1880
|
if (part.type === "file") {
|
|
1680
1881
|
return { kind: "file", url: part.url, mediaType: part.mediaType };
|
|
1681
1882
|
}
|
|
1883
|
+
if (part.type === "tool") {
|
|
1884
|
+
return {
|
|
1885
|
+
kind: "tool",
|
|
1886
|
+
toolCallId: part.toolCallId,
|
|
1887
|
+
toolName: part.toolName,
|
|
1888
|
+
inputPartialSig: signal(""),
|
|
1889
|
+
inputSig: signal(part.input),
|
|
1890
|
+
outputSig: signal(part.output),
|
|
1891
|
+
errorSig: signal(part.errorText),
|
|
1892
|
+
stateSig: signal(part.state),
|
|
1893
|
+
approvalSig: signal(part.approval)
|
|
1894
|
+
};
|
|
1895
|
+
}
|
|
1682
1896
|
return null;
|
|
1683
|
-
}).filter((
|
|
1897
|
+
}).filter((p33) => p33 !== null);
|
|
1684
1898
|
return {
|
|
1685
1899
|
id: w.id,
|
|
1686
1900
|
role: w.role,
|
|
@@ -1710,45 +1924,60 @@ function assistantText(m) {
|
|
|
1710
1924
|
}
|
|
1711
1925
|
return out;
|
|
1712
1926
|
}
|
|
1713
|
-
function partToReactive(
|
|
1714
|
-
if (
|
|
1715
|
-
return { kind:
|
|
1927
|
+
function partToReactive(p33) {
|
|
1928
|
+
if (p33.kind === "text" || p33.kind === "reasoning") {
|
|
1929
|
+
return { kind: p33.kind, id: p33.id, textSig: signal(p33.text), doneSig: signal(p33.done) };
|
|
1716
1930
|
}
|
|
1717
|
-
if (
|
|
1931
|
+
if (p33.kind === "tool") {
|
|
1718
1932
|
return {
|
|
1719
1933
|
kind: "tool",
|
|
1720
|
-
toolCallId:
|
|
1721
|
-
toolName:
|
|
1722
|
-
inputPartialSig: signal(
|
|
1723
|
-
inputSig: signal(
|
|
1724
|
-
outputSig: signal(
|
|
1725
|
-
errorSig: signal(
|
|
1726
|
-
stateSig: signal(
|
|
1934
|
+
toolCallId: p33.toolCallId,
|
|
1935
|
+
toolName: p33.toolName,
|
|
1936
|
+
inputPartialSig: signal(p33.inputPartial),
|
|
1937
|
+
inputSig: signal(p33.input),
|
|
1938
|
+
outputSig: signal(p33.output),
|
|
1939
|
+
errorSig: signal(p33.error),
|
|
1940
|
+
stateSig: signal(p33.state),
|
|
1941
|
+
approvalSig: signal(p33.approval)
|
|
1727
1942
|
};
|
|
1728
1943
|
}
|
|
1729
|
-
return
|
|
1944
|
+
return p33;
|
|
1730
1945
|
}
|
|
1731
|
-
function partFromReactive(
|
|
1732
|
-
if (
|
|
1733
|
-
return { kind:
|
|
1946
|
+
function partFromReactive(p33) {
|
|
1947
|
+
if (p33.kind === "text" || p33.kind === "reasoning") {
|
|
1948
|
+
return { kind: p33.kind, id: p33.id, text: p33.textSig.value, done: p33.doneSig.value };
|
|
1734
1949
|
}
|
|
1735
|
-
if (
|
|
1950
|
+
if (p33.kind === "tool") {
|
|
1736
1951
|
return {
|
|
1737
1952
|
kind: "tool",
|
|
1738
|
-
toolCallId:
|
|
1739
|
-
toolName:
|
|
1740
|
-
inputPartial:
|
|
1741
|
-
input:
|
|
1742
|
-
output:
|
|
1743
|
-
error:
|
|
1744
|
-
state:
|
|
1953
|
+
toolCallId: p33.toolCallId,
|
|
1954
|
+
toolName: p33.toolName,
|
|
1955
|
+
inputPartial: p33.inputPartialSig.value,
|
|
1956
|
+
input: p33.inputSig.value,
|
|
1957
|
+
output: p33.outputSig.value,
|
|
1958
|
+
error: p33.errorSig.value,
|
|
1959
|
+
state: p33.stateSig.value,
|
|
1960
|
+
approval: p33.approvalSig.value
|
|
1745
1961
|
};
|
|
1746
1962
|
}
|
|
1747
|
-
return
|
|
1963
|
+
return p33;
|
|
1748
1964
|
}
|
|
1749
1965
|
|
|
1750
1966
|
// src/stream/reducer.ts
|
|
1751
1967
|
import { signal as signal2 } from "@preact/signals";
|
|
1968
|
+
|
|
1969
|
+
// src/stream/constants.ts
|
|
1970
|
+
var ASK_USER_INPUT_TOOL = "tool:ask-user-input";
|
|
1971
|
+
function isAskUserInputTool(toolName) {
|
|
1972
|
+
return toolName === ASK_USER_INPUT_TOOL;
|
|
1973
|
+
}
|
|
1974
|
+
var TRIGGER = {
|
|
1975
|
+
submitMessage: "submit-message",
|
|
1976
|
+
toolResult: "tool-result",
|
|
1977
|
+
toolApproval: "tool-approval"
|
|
1978
|
+
};
|
|
1979
|
+
|
|
1980
|
+
// src/stream/reducer.ts
|
|
1752
1981
|
var log5 = logger.scope("reducer");
|
|
1753
1982
|
var StreamReducer = class {
|
|
1754
1983
|
constructor(messagesSig) {
|
|
@@ -1786,8 +2015,8 @@ var StreamReducer = class {
|
|
|
1786
2015
|
ensureTextPart(m, "text", chunk.id);
|
|
1787
2016
|
return;
|
|
1788
2017
|
case "text-delta": {
|
|
1789
|
-
const
|
|
1790
|
-
|
|
2018
|
+
const p33 = ensureTextPart(m, "text", chunk.id);
|
|
2019
|
+
p33.textSig.value += chunk.delta;
|
|
1791
2020
|
return;
|
|
1792
2021
|
}
|
|
1793
2022
|
case "text-end":
|
|
@@ -1797,8 +2026,8 @@ var StreamReducer = class {
|
|
|
1797
2026
|
ensureTextPart(m, "reasoning", chunk.id).doneSig.value = false;
|
|
1798
2027
|
return;
|
|
1799
2028
|
case "reasoning-delta": {
|
|
1800
|
-
const
|
|
1801
|
-
|
|
2029
|
+
const p33 = ensureTextPart(m, "reasoning", chunk.id);
|
|
2030
|
+
p33.textSig.value += chunk.delta;
|
|
1802
2031
|
return;
|
|
1803
2032
|
}
|
|
1804
2033
|
case "reasoning-end":
|
|
@@ -1809,6 +2038,7 @@ var StreamReducer = class {
|
|
|
1809
2038
|
case "tool-input-available":
|
|
1810
2039
|
case "tool-output-available":
|
|
1811
2040
|
case "tool-output-error":
|
|
2041
|
+
case "tool-approval-request":
|
|
1812
2042
|
applyTool(m, chunk);
|
|
1813
2043
|
return;
|
|
1814
2044
|
case "file":
|
|
@@ -1816,7 +2046,7 @@ var StreamReducer = class {
|
|
|
1816
2046
|
return;
|
|
1817
2047
|
case "source-url": {
|
|
1818
2048
|
const parts = m.partsSig.value;
|
|
1819
|
-
if (parts.some((
|
|
2049
|
+
if (parts.some((p33) => p33.kind === "source" && p33.sourceId === chunk.sourceId)) return;
|
|
1820
2050
|
appendPart(m, { kind: "source", sourceId: chunk.sourceId, url: chunk.url, title: chunk.title });
|
|
1821
2051
|
return;
|
|
1822
2052
|
}
|
|
@@ -1840,14 +2070,14 @@ var StreamReducer = class {
|
|
|
1840
2070
|
}
|
|
1841
2071
|
};
|
|
1842
2072
|
function ensureTextPart(m, kind, id) {
|
|
1843
|
-
const existing = m.partsSig.value.find((
|
|
2073
|
+
const existing = m.partsSig.value.find((p33) => p33.kind === kind && p33.id === id);
|
|
1844
2074
|
if (existing) return existing;
|
|
1845
2075
|
const part = { kind, id, textSig: signal2(""), doneSig: signal2(false) };
|
|
1846
2076
|
appendPart(m, part);
|
|
1847
2077
|
return part;
|
|
1848
2078
|
}
|
|
1849
2079
|
function ensureToolPart(m, toolCallId, toolName) {
|
|
1850
|
-
const existing = m.partsSig.value.find((
|
|
2080
|
+
const existing = m.partsSig.value.find((p33) => p33.kind === "tool" && p33.toolCallId === toolCallId);
|
|
1851
2081
|
if (existing) return existing;
|
|
1852
2082
|
const part = {
|
|
1853
2083
|
kind: "tool",
|
|
@@ -1857,7 +2087,8 @@ function ensureToolPart(m, toolCallId, toolName) {
|
|
|
1857
2087
|
inputSig: signal2(void 0),
|
|
1858
2088
|
outputSig: signal2(void 0),
|
|
1859
2089
|
errorSig: signal2(void 0),
|
|
1860
|
-
stateSig: signal2("input")
|
|
2090
|
+
stateSig: signal2("input"),
|
|
2091
|
+
approvalSig: signal2(void 0)
|
|
1861
2092
|
};
|
|
1862
2093
|
appendPart(m, part);
|
|
1863
2094
|
return part;
|
|
@@ -1871,26 +2102,32 @@ function applyTool(m, chunk) {
|
|
|
1871
2102
|
ensureToolPart(m, chunk.toolCallId, chunk.toolName);
|
|
1872
2103
|
return;
|
|
1873
2104
|
case "tool-input-delta": {
|
|
1874
|
-
const
|
|
1875
|
-
|
|
2105
|
+
const p33 = ensureToolPart(m, chunk.toolCallId);
|
|
2106
|
+
p33.inputPartialSig.value += chunk.delta;
|
|
1876
2107
|
return;
|
|
1877
2108
|
}
|
|
1878
2109
|
case "tool-input-available": {
|
|
1879
|
-
const
|
|
1880
|
-
|
|
1881
|
-
|
|
2110
|
+
const p33 = ensureToolPart(m, chunk.toolCallId, chunk.toolName);
|
|
2111
|
+
p33.inputSig.value = chunk.input;
|
|
2112
|
+
p33.stateSig.value = isAskUserInputTool(p33.toolName) ? "awaiting-input" : "awaiting";
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
case "tool-approval-request": {
|
|
2116
|
+
const p33 = ensureToolPart(m, chunk.toolCallId, chunk.toolName);
|
|
2117
|
+
p33.approvalSig.value = { id: chunk.approvalId };
|
|
2118
|
+
p33.stateSig.value = "awaiting-approval";
|
|
1882
2119
|
return;
|
|
1883
2120
|
}
|
|
1884
2121
|
case "tool-output-available": {
|
|
1885
|
-
const
|
|
1886
|
-
|
|
1887
|
-
|
|
2122
|
+
const p33 = ensureToolPart(m, chunk.toolCallId);
|
|
2123
|
+
p33.outputSig.value = chunk.output;
|
|
2124
|
+
p33.stateSig.value = "output";
|
|
1888
2125
|
return;
|
|
1889
2126
|
}
|
|
1890
2127
|
case "tool-output-error": {
|
|
1891
|
-
const
|
|
1892
|
-
|
|
1893
|
-
|
|
2128
|
+
const p33 = ensureToolPart(m, chunk.toolCallId);
|
|
2129
|
+
p33.errorSig.value = chunk.errorText;
|
|
2130
|
+
p33.stateSig.value = "error";
|
|
1894
2131
|
return;
|
|
1895
2132
|
}
|
|
1896
2133
|
default:
|
|
@@ -1910,6 +2147,7 @@ function createPersistence(widgetId, storage = defaultStorage) {
|
|
|
1910
2147
|
const KEY_CALLOUT_DISMISSED = `${prefix}.calloutDismissed`;
|
|
1911
2148
|
const KEY_SIDEBAR_COLLAPSED = `${prefix}.sidebarCollapsed`;
|
|
1912
2149
|
const KEY_ACTIVE_MODULE = `${prefix}.activeModule`;
|
|
2150
|
+
const KEY_INTAKE = `${prefix}.intake`;
|
|
1913
2151
|
const persistence = {
|
|
1914
2152
|
getVisitorId() {
|
|
1915
2153
|
const existing = storage.get(KEY_VISITOR);
|
|
@@ -1992,6 +2230,24 @@ function createPersistence(widgetId, storage = defaultStorage) {
|
|
|
1992
2230
|
saveActiveModule(id) {
|
|
1993
2231
|
storage.set(KEY_ACTIVE_MODULE, id);
|
|
1994
2232
|
},
|
|
2233
|
+
loadIntake() {
|
|
2234
|
+
const raw = storage.get(KEY_INTAKE);
|
|
2235
|
+
if (!raw) return null;
|
|
2236
|
+
try {
|
|
2237
|
+
const parsed = JSON.parse(raw);
|
|
2238
|
+
return isPlainObject2(parsed) ? parsed : null;
|
|
2239
|
+
} catch (error) {
|
|
2240
|
+
log6.warn("loadIntake parse failed", { error });
|
|
2241
|
+
return null;
|
|
2242
|
+
}
|
|
2243
|
+
},
|
|
2244
|
+
saveIntake(values) {
|
|
2245
|
+
try {
|
|
2246
|
+
storage.set(KEY_INTAKE, JSON.stringify(values));
|
|
2247
|
+
} catch (error) {
|
|
2248
|
+
log6.warn("saveIntake serialise failed", { error });
|
|
2249
|
+
}
|
|
2250
|
+
},
|
|
1995
2251
|
clearSession() {
|
|
1996
2252
|
storage.remove(KEY_CHAT);
|
|
1997
2253
|
}
|
|
@@ -2533,7 +2789,30 @@ var TID = {
|
|
|
2533
2789
|
/** Help article row — suffix `-{id}`. */
|
|
2534
2790
|
helpArticle: `${p2}-help-article`,
|
|
2535
2791
|
/** News list item — suffix `-{id}`. */
|
|
2536
|
-
newsItem: `${p2}-news-item
|
|
2792
|
+
newsItem: `${p2}-news-item`,
|
|
2793
|
+
// ── Forms + human-in-the-loop (intake / ask-input / approval) ────
|
|
2794
|
+
/** Pre-chat intake form root (blocking gate). */
|
|
2795
|
+
intakeForm: `${p2}-intake-form`,
|
|
2796
|
+
/** Intake submit button. */
|
|
2797
|
+
intakeSubmit: `${p2}-intake-submit`,
|
|
2798
|
+
/** Intake skip button (only when `skippable`). */
|
|
2799
|
+
intakeSkip: `${p2}-intake-skip`,
|
|
2800
|
+
/** A single form field control — suffix `-{name}` at the JSX site. */
|
|
2801
|
+
formField: `${p2}-form-field`,
|
|
2802
|
+
/** Ask-input tool root (inline form in a message bubble). */
|
|
2803
|
+
toolAskInput: `${p2}-tool-ask-input`,
|
|
2804
|
+
/** Ask-input submit button. */
|
|
2805
|
+
toolInputSubmit: `${p2}-tool-input-submit`,
|
|
2806
|
+
/** Ask-input skip button. */
|
|
2807
|
+
toolInputSkip: `${p2}-tool-input-skip`,
|
|
2808
|
+
/** Tool-approval root (approve/reject prompt). */
|
|
2809
|
+
toolApproval: `${p2}-tool-approval`,
|
|
2810
|
+
/** Tool-approval approve button. */
|
|
2811
|
+
toolApprove: `${p2}-tool-approve`,
|
|
2812
|
+
/** Tool-approval reject button. */
|
|
2813
|
+
toolReject: `${p2}-tool-reject`,
|
|
2814
|
+
/** Recorded tool decision summary (after approve/reject/submit). */
|
|
2815
|
+
toolDecision: `${p2}-tool-decision`
|
|
2537
2816
|
};
|
|
2538
2817
|
function tid(base, suffix) {
|
|
2539
2818
|
return `${base}-${suffix}`;
|
|
@@ -2644,24 +2923,24 @@ import { useCallback as useCallback2, useEffect as useEffect10, useRef as useRef
|
|
|
2644
2923
|
import { useEffect as useEffect2, useRef } from "preact/hooks";
|
|
2645
2924
|
import { jsx as jsx3 } from "preact/jsx-runtime";
|
|
2646
2925
|
function ResizeGrip({ panelEl, resize, position, initialSize, onSizeChange, strings }) {
|
|
2647
|
-
const
|
|
2926
|
+
const p33 = BRAND.cssPrefix;
|
|
2648
2927
|
const dragRef = useRef(null);
|
|
2649
2928
|
useEffect2(() => {
|
|
2650
2929
|
if (!panelEl) return;
|
|
2651
2930
|
const style = panelEl.style;
|
|
2652
|
-
if (resize.minWidth) style.setProperty(`--${
|
|
2653
|
-
if (resize.maxWidth) style.setProperty(`--${
|
|
2654
|
-
if (resize.minHeight) style.setProperty(`--${
|
|
2655
|
-
if (resize.maxHeight) style.setProperty(`--${
|
|
2931
|
+
if (resize.minWidth) style.setProperty(`--${p33}-resize-min-w`, resize.minWidth);
|
|
2932
|
+
if (resize.maxWidth) style.setProperty(`--${p33}-resize-max-w`, resize.maxWidth);
|
|
2933
|
+
if (resize.minHeight) style.setProperty(`--${p33}-resize-min-h`, resize.minHeight);
|
|
2934
|
+
if (resize.maxHeight) style.setProperty(`--${p33}-resize-max-h`, resize.maxHeight);
|
|
2656
2935
|
if (initialSize) {
|
|
2657
|
-
style.setProperty(`--${
|
|
2658
|
-
style.setProperty(`--${
|
|
2936
|
+
style.setProperty(`--${p33}-widget-w`, `${initialSize.width}px`);
|
|
2937
|
+
style.setProperty(`--${p33}-widget-h`, `${initialSize.height}px`);
|
|
2659
2938
|
}
|
|
2660
|
-
}, [panelEl, resize.minWidth, resize.maxWidth, resize.minHeight, resize.maxHeight,
|
|
2939
|
+
}, [panelEl, resize.minWidth, resize.maxWidth, resize.minHeight, resize.maxHeight, p33, initialSize]);
|
|
2661
2940
|
if (!panelEl) return null;
|
|
2662
2941
|
const isTop = position.startsWith("top-");
|
|
2663
2942
|
const isRight = position.endsWith("-right");
|
|
2664
|
-
const cornerClass = `${
|
|
2943
|
+
const cornerClass = `${p33}-resize-grip ${p33}-resize-grip--${isTop ? "bottom" : "top"}-${isRight ? "left" : "right"}`;
|
|
2665
2944
|
const onPointerDown = (e) => {
|
|
2666
2945
|
if (!panelEl) return;
|
|
2667
2946
|
const target = e.currentTarget;
|
|
@@ -2685,8 +2964,8 @@ function ResizeGrip({ panelEl, resize, position, initialSize, onSizeChange, stri
|
|
|
2685
2964
|
if (!d || e.pointerId !== d.pointerId || !panelEl) return;
|
|
2686
2965
|
const dx = (e.clientX - d.startX) * d.dirX;
|
|
2687
2966
|
const dy = (e.clientY - d.startY) * d.dirY;
|
|
2688
|
-
panelEl.style.setProperty(`--${
|
|
2689
|
-
panelEl.style.setProperty(`--${
|
|
2967
|
+
panelEl.style.setProperty(`--${p33}-widget-w`, `${d.startW + dx}px`);
|
|
2968
|
+
panelEl.style.setProperty(`--${p33}-widget-h`, `${d.startH + dy}px`);
|
|
2690
2969
|
};
|
|
2691
2970
|
const onPointerUp = (e) => {
|
|
2692
2971
|
const d = dragRef.current;
|
|
@@ -2723,7 +3002,7 @@ var KEEP_VISIBLE = 56;
|
|
|
2723
3002
|
function useDragMove(panelEl, enabled) {
|
|
2724
3003
|
useEffect3(() => {
|
|
2725
3004
|
if (!enabled || !panelEl) return;
|
|
2726
|
-
const
|
|
3005
|
+
const num2 = (v) => Number.parseFloat(v) || 0;
|
|
2727
3006
|
const clamp = (v, max) => Math.min(max, Math.max(-max, v));
|
|
2728
3007
|
let drag = null;
|
|
2729
3008
|
const onDown = (e) => {
|
|
@@ -2734,8 +3013,8 @@ function useDragMove(panelEl, enabled) {
|
|
|
2734
3013
|
id: e.pointerId,
|
|
2735
3014
|
x: e.clientX,
|
|
2736
3015
|
y: e.clientY,
|
|
2737
|
-
dx:
|
|
2738
|
-
dy:
|
|
3016
|
+
dx: num2(panelEl.style.getPropertyValue(`--${p4}-modal-dx`)),
|
|
3017
|
+
dy: num2(panelEl.style.getPropertyValue(`--${p4}-modal-dy`)),
|
|
2739
3018
|
// Centred origin: |offset| ≤ (viewport + panel)/2 − keepVisible keeps a
|
|
2740
3019
|
// strip of the dialog reachable so it can never be lost off-screen.
|
|
2741
3020
|
maxX: (window.innerWidth + rect.width) / 2 - KEEP_VISIBLE,
|
|
@@ -3421,20 +3700,20 @@ function usePopoverMenu({ itemCount, initialFocusIndex }) {
|
|
|
3421
3700
|
// src/ui/overflow-menu.tsx
|
|
3422
3701
|
import { jsx as jsx8, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
3423
3702
|
function OverflowMenu({ items, triggerLabel }) {
|
|
3424
|
-
const
|
|
3703
|
+
const p33 = BRAND.cssPrefix;
|
|
3425
3704
|
const menu = usePopoverMenu({ itemCount: items.length });
|
|
3426
3705
|
const handleSelect = (item) => {
|
|
3427
3706
|
if (item.disabled) return;
|
|
3428
3707
|
item.onSelect();
|
|
3429
3708
|
if (!item.keepOpen) menu.close();
|
|
3430
3709
|
};
|
|
3431
|
-
return /* @__PURE__ */ jsxs6("div", { class: `${
|
|
3710
|
+
return /* @__PURE__ */ jsxs6("div", { class: `${p33}-menu-wrap`, children: [
|
|
3432
3711
|
/* @__PURE__ */ jsx8(
|
|
3433
3712
|
"button",
|
|
3434
3713
|
{
|
|
3435
3714
|
ref: menu.triggerRef,
|
|
3436
3715
|
type: "button",
|
|
3437
|
-
class: `${
|
|
3716
|
+
class: `${p33}-icon-btn`,
|
|
3438
3717
|
"aria-label": triggerLabel,
|
|
3439
3718
|
"aria-haspopup": "menu",
|
|
3440
3719
|
"aria-expanded": menu.open,
|
|
@@ -3448,7 +3727,7 @@ function OverflowMenu({ items, triggerLabel }) {
|
|
|
3448
3727
|
"div",
|
|
3449
3728
|
{
|
|
3450
3729
|
ref: menu.menuRef,
|
|
3451
|
-
class: `${
|
|
3730
|
+
class: `${p33}-menu`,
|
|
3452
3731
|
role: "menu",
|
|
3453
3732
|
"aria-label": triggerLabel,
|
|
3454
3733
|
onKeyDown: menu.onMenuKey,
|
|
@@ -3458,15 +3737,15 @@ function OverflowMenu({ items, triggerLabel }) {
|
|
|
3458
3737
|
{
|
|
3459
3738
|
type: "button",
|
|
3460
3739
|
role: "menuitem",
|
|
3461
|
-
class: `${
|
|
3740
|
+
class: `${p33}-menu-item`,
|
|
3462
3741
|
"aria-pressed": item.type === "switch" ? item.on : void 0,
|
|
3463
3742
|
disabled: item.disabled,
|
|
3464
3743
|
lang: item.lang,
|
|
3465
3744
|
onClick: () => handleSelect(item),
|
|
3466
3745
|
children: [
|
|
3467
|
-
item.icon ? /* @__PURE__ */ jsx8("span", { class: `${
|
|
3468
|
-
/* @__PURE__ */ jsx8("span", { class: `${
|
|
3469
|
-
item.type === "switch" && item.on ? /* @__PURE__ */ jsx8("span", { class: `${
|
|
3746
|
+
item.icon ? /* @__PURE__ */ jsx8("span", { class: `${p33}-menu-icon`, children: item.icon }) : null,
|
|
3747
|
+
/* @__PURE__ */ jsx8("span", { class: `${p33}-menu-label`, children: item.label }),
|
|
3748
|
+
item.type === "switch" && item.on ? /* @__PURE__ */ jsx8("span", { class: `${p33}-menu-check`, "aria-hidden": "true", children: /* @__PURE__ */ jsx8(CheckIcon, {}) }) : null
|
|
3470
3749
|
]
|
|
3471
3750
|
},
|
|
3472
3751
|
item.id
|
|
@@ -3588,18 +3867,360 @@ function HeaderActions({ panelProps, variant }) {
|
|
|
3588
3867
|
] });
|
|
3589
3868
|
}
|
|
3590
3869
|
|
|
3870
|
+
// src/ui/form/dynamic-form.tsx
|
|
3871
|
+
import { useState as useState5 } from "preact/hooks";
|
|
3872
|
+
|
|
3873
|
+
// src/ui/form/validate.ts
|
|
3874
|
+
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3875
|
+
var URL_RE = /^https?:\/\/[^\s.]+\.[^\s]+$/i;
|
|
3876
|
+
var TEL_RE = /^[+]?[\d\s().-]{6,}$/;
|
|
3877
|
+
function fmt(template, vars) {
|
|
3878
|
+
return template.replace(/\{(\w+)\}/g, (_, k) => String(vars[k] ?? `{${k}}`));
|
|
3879
|
+
}
|
|
3880
|
+
function selectionCount(value) {
|
|
3881
|
+
if (Array.isArray(value)) return value.length;
|
|
3882
|
+
return value && value.trim() ? 1 : 0;
|
|
3883
|
+
}
|
|
3884
|
+
function validateField(field, value, strings) {
|
|
3885
|
+
const required = field.required ?? true;
|
|
3886
|
+
const v = field.validation;
|
|
3887
|
+
if (field.type === "multiselect") {
|
|
3888
|
+
const count = selectionCount(value);
|
|
3889
|
+
if (required && count === 0) return strings.formRequired;
|
|
3890
|
+
if (count === 0) return void 0;
|
|
3891
|
+
if (v?.minSelections != null && count < v.minSelections) {
|
|
3892
|
+
return fmt(strings.formChooseAtLeast, { min: v.minSelections });
|
|
3893
|
+
}
|
|
3894
|
+
if (v?.maxSelections != null && count > v.maxSelections) {
|
|
3895
|
+
return fmt(strings.formChooseAtMost, { max: v.maxSelections });
|
|
3896
|
+
}
|
|
3897
|
+
return void 0;
|
|
3898
|
+
}
|
|
3899
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
3900
|
+
if (!text) return required ? strings.formRequired : void 0;
|
|
3901
|
+
switch (field.type) {
|
|
3902
|
+
case "email":
|
|
3903
|
+
if (!EMAIL_RE2.test(text)) return strings.formInvalidEmail;
|
|
3904
|
+
break;
|
|
3905
|
+
case "url":
|
|
3906
|
+
if (!URL_RE.test(text)) return strings.formInvalidUrl;
|
|
3907
|
+
break;
|
|
3908
|
+
case "tel":
|
|
3909
|
+
if (!TEL_RE.test(text)) return strings.formInvalidTel;
|
|
3910
|
+
break;
|
|
3911
|
+
case "number": {
|
|
3912
|
+
const n = Number(text);
|
|
3913
|
+
if (!Number.isFinite(n)) return strings.formInvalidNumber;
|
|
3914
|
+
if (v?.min != null && n < v.min) return fmt(strings.formNumberTooSmall, { min: v.min });
|
|
3915
|
+
if (v?.max != null && n > v.max) return fmt(strings.formNumberTooLarge, { max: v.max });
|
|
3916
|
+
break;
|
|
3917
|
+
}
|
|
3918
|
+
default:
|
|
3919
|
+
break;
|
|
3920
|
+
}
|
|
3921
|
+
if (v?.minLength != null && text.length < v.minLength) return fmt(strings.formTooShort, { min: v.minLength });
|
|
3922
|
+
if (v?.maxLength != null && text.length > v.maxLength) return fmt(strings.formTooLong, { max: v.maxLength });
|
|
3923
|
+
if (v?.pattern) {
|
|
3924
|
+
try {
|
|
3925
|
+
if (!new RegExp(v.pattern).test(text)) return strings.formPatternMismatch;
|
|
3926
|
+
} catch {
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
return void 0;
|
|
3930
|
+
}
|
|
3931
|
+
function validateForm(fields, values, strings) {
|
|
3932
|
+
const errors = {};
|
|
3933
|
+
for (const field of fields) {
|
|
3934
|
+
const err = validateField(field, values[field.name], strings);
|
|
3935
|
+
if (err) errors[field.name] = err;
|
|
3936
|
+
}
|
|
3937
|
+
return errors;
|
|
3938
|
+
}
|
|
3939
|
+
function flattenValues(values) {
|
|
3940
|
+
const out = {};
|
|
3941
|
+
for (const [k, v] of Object.entries(values)) {
|
|
3942
|
+
const flat = Array.isArray(v) ? v.join(", ") : v;
|
|
3943
|
+
if (flat && flat.trim()) out[k] = flat.trim();
|
|
3944
|
+
}
|
|
3945
|
+
return out;
|
|
3946
|
+
}
|
|
3947
|
+
|
|
3948
|
+
// src/ui/form/dynamic-form.tsx
|
|
3949
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
3950
|
+
var p10 = BRAND.cssPrefix;
|
|
3951
|
+
var OTHER = "__other__";
|
|
3952
|
+
function DynamicForm({
|
|
3953
|
+
fields,
|
|
3954
|
+
strings,
|
|
3955
|
+
submitLabel,
|
|
3956
|
+
onSubmit,
|
|
3957
|
+
skipLabel,
|
|
3958
|
+
onSkip,
|
|
3959
|
+
disabled,
|
|
3960
|
+
rootTestId,
|
|
3961
|
+
submitTestId,
|
|
3962
|
+
skipTestId
|
|
3963
|
+
}) {
|
|
3964
|
+
const [values, setValues] = useState5(() => seedValues(fields));
|
|
3965
|
+
const [other, setOther] = useState5({});
|
|
3966
|
+
const [errors, setErrors] = useState5({});
|
|
3967
|
+
const clearError = (name) => {
|
|
3968
|
+
if (errors[name]) setErrors((prev) => ({ ...prev, [name]: "" }));
|
|
3969
|
+
};
|
|
3970
|
+
const setValue = (name, v) => {
|
|
3971
|
+
setValues((prev) => ({ ...prev, [name]: v }));
|
|
3972
|
+
clearError(name);
|
|
3973
|
+
};
|
|
3974
|
+
const setOtherText = (name, t) => {
|
|
3975
|
+
setOther((prev) => ({ ...prev, [name]: t }));
|
|
3976
|
+
clearError(name);
|
|
3977
|
+
};
|
|
3978
|
+
const submit = (e) => {
|
|
3979
|
+
e.preventDefault();
|
|
3980
|
+
if (disabled) return;
|
|
3981
|
+
const resolved = resolveValues(fields, values, other);
|
|
3982
|
+
const errs = validateForm(fields, resolved, strings);
|
|
3983
|
+
if (Object.keys(errs).length > 0) {
|
|
3984
|
+
setErrors(errs);
|
|
3985
|
+
return;
|
|
3986
|
+
}
|
|
3987
|
+
onSubmit(flattenValues(resolved));
|
|
3988
|
+
};
|
|
3989
|
+
return /* @__PURE__ */ jsxs8("form", { class: `${p10}-form`, onSubmit: submit, "data-testid": rootTestId, noValidate: true, children: [
|
|
3990
|
+
fields.map((field) => /* @__PURE__ */ jsx10(
|
|
3991
|
+
Field,
|
|
3992
|
+
{
|
|
3993
|
+
field,
|
|
3994
|
+
value: values[field.name],
|
|
3995
|
+
otherText: other[field.name] ?? "",
|
|
3996
|
+
error: errors[field.name],
|
|
3997
|
+
disabled,
|
|
3998
|
+
strings,
|
|
3999
|
+
onChange: (v) => setValue(field.name, v),
|
|
4000
|
+
onOtherChange: (t) => setOtherText(field.name, t)
|
|
4001
|
+
},
|
|
4002
|
+
field.name
|
|
4003
|
+
)),
|
|
4004
|
+
/* @__PURE__ */ jsxs8("div", { class: `${p10}-form-actions`, children: [
|
|
4005
|
+
skipLabel && onSkip ? /* @__PURE__ */ jsx10("button", { type: "button", class: `${p10}-form-skip`, onClick: onSkip, disabled, "data-testid": skipTestId, children: skipLabel }) : null,
|
|
4006
|
+
/* @__PURE__ */ jsx10("button", { type: "submit", class: `${p10}-form-submit`, disabled, "data-testid": submitTestId, children: submitLabel })
|
|
4007
|
+
] })
|
|
4008
|
+
] });
|
|
4009
|
+
}
|
|
4010
|
+
function Field({
|
|
4011
|
+
field,
|
|
4012
|
+
value,
|
|
4013
|
+
otherText,
|
|
4014
|
+
error,
|
|
4015
|
+
disabled,
|
|
4016
|
+
strings,
|
|
4017
|
+
onChange,
|
|
4018
|
+
onOtherChange
|
|
4019
|
+
}) {
|
|
4020
|
+
const fieldTid = tid(TID.formField, field.name);
|
|
4021
|
+
const control = renderControl({ field, value, otherText, disabled, strings, onChange, onOtherChange, fieldTid });
|
|
4022
|
+
return /* @__PURE__ */ jsxs8("label", { class: `${p10}-field`, "data-field": field.name, "data-invalid": error ? "true" : void 0, children: [
|
|
4023
|
+
/* @__PURE__ */ jsxs8("span", { class: `${p10}-field-label`, children: [
|
|
4024
|
+
field.label,
|
|
4025
|
+
field.required ?? true ? /* @__PURE__ */ jsx10("span", { class: `${p10}-field-req`, "aria-hidden": "true", children: " *" }) : null
|
|
4026
|
+
] }),
|
|
4027
|
+
control,
|
|
4028
|
+
field.validationHint && !error ? /* @__PURE__ */ jsx10("span", { class: `${p10}-field-hint`, children: field.validationHint }) : null,
|
|
4029
|
+
error ? /* @__PURE__ */ jsx10("span", { class: `${p10}-field-error`, role: "alert", children: error }) : null
|
|
4030
|
+
] });
|
|
4031
|
+
}
|
|
4032
|
+
function renderControl(args) {
|
|
4033
|
+
const { field, value, otherText, disabled, strings, onChange, onOtherChange, fieldTid } = args;
|
|
4034
|
+
const str2 = typeof value === "string" ? value : "";
|
|
4035
|
+
switch (field.type) {
|
|
4036
|
+
case "textarea":
|
|
4037
|
+
return /* @__PURE__ */ jsx10(
|
|
4038
|
+
"textarea",
|
|
4039
|
+
{
|
|
4040
|
+
class: `${p10}-field-input`,
|
|
4041
|
+
rows: 3,
|
|
4042
|
+
value: str2,
|
|
4043
|
+
placeholder: field.placeholder,
|
|
4044
|
+
disabled,
|
|
4045
|
+
onInput: (e) => onChange(e.target.value),
|
|
4046
|
+
"data-testid": fieldTid
|
|
4047
|
+
}
|
|
4048
|
+
);
|
|
4049
|
+
case "select":
|
|
4050
|
+
return /* @__PURE__ */ jsxs8(
|
|
4051
|
+
"select",
|
|
4052
|
+
{
|
|
4053
|
+
class: `${p10}-field-input`,
|
|
4054
|
+
value: str2,
|
|
4055
|
+
disabled,
|
|
4056
|
+
onChange: (e) => onChange(e.target.value),
|
|
4057
|
+
"data-testid": fieldTid,
|
|
4058
|
+
children: [
|
|
4059
|
+
/* @__PURE__ */ jsx10("option", { value: "", children: field.placeholder ?? "\u2014" }),
|
|
4060
|
+
(field.options ?? []).map((o) => /* @__PURE__ */ jsx10("option", { value: o.value, children: o.label ?? o.value }, o.value))
|
|
4061
|
+
]
|
|
4062
|
+
}
|
|
4063
|
+
);
|
|
4064
|
+
case "radio": {
|
|
4065
|
+
const isOther = field.allowOther && str2 === OTHER;
|
|
4066
|
+
return /* @__PURE__ */ jsxs8("div", { class: `${p10}-field-choices`, role: "radiogroup", "data-testid": fieldTid, children: [
|
|
4067
|
+
(field.options ?? []).map((o) => /* @__PURE__ */ jsxs8("label", { class: `${p10}-choice`, children: [
|
|
4068
|
+
/* @__PURE__ */ jsx10(
|
|
4069
|
+
"input",
|
|
4070
|
+
{
|
|
4071
|
+
type: "radio",
|
|
4072
|
+
name: `${p10}-${field.name}`,
|
|
4073
|
+
checked: str2 === o.value,
|
|
4074
|
+
disabled,
|
|
4075
|
+
onChange: () => onChange(o.value)
|
|
4076
|
+
}
|
|
4077
|
+
),
|
|
4078
|
+
/* @__PURE__ */ jsx10("span", { children: o.label ?? o.value })
|
|
4079
|
+
] }, o.value)),
|
|
4080
|
+
field.allowOther ? /* @__PURE__ */ jsxs8("label", { class: `${p10}-choice`, children: [
|
|
4081
|
+
/* @__PURE__ */ jsx10(
|
|
4082
|
+
"input",
|
|
4083
|
+
{
|
|
4084
|
+
type: "radio",
|
|
4085
|
+
name: `${p10}-${field.name}`,
|
|
4086
|
+
checked: str2 === OTHER,
|
|
4087
|
+
disabled,
|
|
4088
|
+
onChange: () => onChange(OTHER)
|
|
4089
|
+
}
|
|
4090
|
+
),
|
|
4091
|
+
/* @__PURE__ */ jsx10("span", { children: strings.formOther })
|
|
4092
|
+
] }) : null,
|
|
4093
|
+
isOther ? /* @__PURE__ */ jsx10(
|
|
4094
|
+
"input",
|
|
4095
|
+
{
|
|
4096
|
+
class: `${p10}-field-input`,
|
|
4097
|
+
value: otherText,
|
|
4098
|
+
placeholder: field.placeholder ?? strings.formOtherPlaceholder,
|
|
4099
|
+
disabled,
|
|
4100
|
+
onInput: (e) => onOtherChange(e.target.value)
|
|
4101
|
+
}
|
|
4102
|
+
) : null
|
|
4103
|
+
] });
|
|
4104
|
+
}
|
|
4105
|
+
case "checkbox":
|
|
4106
|
+
return /* @__PURE__ */ jsxs8("label", { class: `${p10}-choice`, children: [
|
|
4107
|
+
/* @__PURE__ */ jsx10(
|
|
4108
|
+
"input",
|
|
4109
|
+
{
|
|
4110
|
+
type: "checkbox",
|
|
4111
|
+
checked: str2 === "true",
|
|
4112
|
+
disabled,
|
|
4113
|
+
onChange: (e) => onChange(e.target.checked ? "true" : ""),
|
|
4114
|
+
"data-testid": fieldTid
|
|
4115
|
+
}
|
|
4116
|
+
),
|
|
4117
|
+
/* @__PURE__ */ jsx10("span", { children: field.placeholder ?? field.label })
|
|
4118
|
+
] });
|
|
4119
|
+
case "multiselect": {
|
|
4120
|
+
const selected = Array.isArray(value) ? value : [];
|
|
4121
|
+
const toggle = (v, on) => onChange(on ? [...selected, v] : selected.filter((x) => x !== v));
|
|
4122
|
+
return /* @__PURE__ */ jsxs8("div", { class: `${p10}-field-choices`, "data-testid": fieldTid, children: [
|
|
4123
|
+
(field.options ?? []).map((o) => /* @__PURE__ */ jsxs8("label", { class: `${p10}-choice`, children: [
|
|
4124
|
+
/* @__PURE__ */ jsx10(
|
|
4125
|
+
"input",
|
|
4126
|
+
{
|
|
4127
|
+
type: "checkbox",
|
|
4128
|
+
checked: selected.includes(o.value),
|
|
4129
|
+
disabled,
|
|
4130
|
+
onChange: (e) => toggle(o.value, e.target.checked)
|
|
4131
|
+
}
|
|
4132
|
+
),
|
|
4133
|
+
/* @__PURE__ */ jsx10("span", { children: o.label ?? o.value })
|
|
4134
|
+
] }, o.value)),
|
|
4135
|
+
field.allowOther || (field.options ?? []).length === 0 ? /* @__PURE__ */ jsx10(
|
|
4136
|
+
"textarea",
|
|
4137
|
+
{
|
|
4138
|
+
class: `${p10}-field-input`,
|
|
4139
|
+
rows: 2,
|
|
4140
|
+
value: otherText,
|
|
4141
|
+
placeholder: field.placeholder ?? strings.formOtherPlaceholder,
|
|
4142
|
+
disabled,
|
|
4143
|
+
onInput: (e) => onOtherChange(e.target.value)
|
|
4144
|
+
}
|
|
4145
|
+
) : null
|
|
4146
|
+
] });
|
|
4147
|
+
}
|
|
4148
|
+
default:
|
|
4149
|
+
return /* @__PURE__ */ jsx10(
|
|
4150
|
+
"input",
|
|
4151
|
+
{
|
|
4152
|
+
class: `${p10}-field-input`,
|
|
4153
|
+
type: inputType(field.type),
|
|
4154
|
+
value: str2,
|
|
4155
|
+
placeholder: field.placeholder,
|
|
4156
|
+
disabled,
|
|
4157
|
+
onInput: (e) => onChange(e.target.value),
|
|
4158
|
+
"data-testid": fieldTid
|
|
4159
|
+
}
|
|
4160
|
+
);
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
function inputType(type) {
|
|
4164
|
+
return type === "number" || type === "email" || type === "tel" || type === "url" ? type : "text";
|
|
4165
|
+
}
|
|
4166
|
+
function seedValues(fields) {
|
|
4167
|
+
const out = {};
|
|
4168
|
+
for (const f of fields) {
|
|
4169
|
+
if (f.defaultValue == null) continue;
|
|
4170
|
+
out[f.name] = f.type === "multiselect" ? f.defaultValue.split(",").map((s) => s.trim()).filter(Boolean) : f.defaultValue;
|
|
4171
|
+
}
|
|
4172
|
+
return out;
|
|
4173
|
+
}
|
|
4174
|
+
function resolveValues(fields, values, other) {
|
|
4175
|
+
const out = { ...values };
|
|
4176
|
+
for (const f of fields) {
|
|
4177
|
+
const otherText = other[f.name]?.trim();
|
|
4178
|
+
if (f.type === "radio" && f.allowOther && values[f.name] === OTHER) {
|
|
4179
|
+
out[f.name] = otherText ?? "";
|
|
4180
|
+
} else if (f.type === "multiselect" && otherText) {
|
|
4181
|
+
const tokens = otherText.split(/[,\n;]+/).map((t) => t.trim()).filter(Boolean);
|
|
4182
|
+
const base = Array.isArray(values[f.name]) ? values[f.name] : [];
|
|
4183
|
+
out[f.name] = [...base, ...tokens];
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
return out;
|
|
4187
|
+
}
|
|
4188
|
+
|
|
4189
|
+
// src/ui/intake-gate.tsx
|
|
4190
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "preact/jsx-runtime";
|
|
4191
|
+
var p11 = BRAND.cssPrefix;
|
|
4192
|
+
function IntakeGate({ intake, strings, onComplete }) {
|
|
4193
|
+
return /* @__PURE__ */ jsxs9("div", { class: `${p11}-intake`, "data-testid": TID.intakeForm, children: [
|
|
4194
|
+
intake.title ? /* @__PURE__ */ jsx11("h3", { class: `${p11}-intake-title`, children: intake.title }) : null,
|
|
4195
|
+
intake.description ? /* @__PURE__ */ jsx11("p", { class: `${p11}-intake-desc`, children: intake.description }) : null,
|
|
4196
|
+
/* @__PURE__ */ jsx11(
|
|
4197
|
+
DynamicForm,
|
|
4198
|
+
{
|
|
4199
|
+
fields: intake.fields,
|
|
4200
|
+
strings,
|
|
4201
|
+
submitLabel: intake.submitLabel ?? strings.intakeSubmit,
|
|
4202
|
+
onSubmit: onComplete,
|
|
4203
|
+
skipLabel: intake.skippable ? strings.intakeSkip : void 0,
|
|
4204
|
+
onSkip: intake.skippable ? () => onComplete({}) : void 0,
|
|
4205
|
+
submitTestId: TID.intakeSubmit,
|
|
4206
|
+
skipTestId: TID.intakeSkip
|
|
4207
|
+
}
|
|
4208
|
+
)
|
|
4209
|
+
] });
|
|
4210
|
+
}
|
|
4211
|
+
|
|
3591
4212
|
// src/ui/message-list.tsx
|
|
3592
|
-
import { useEffect as useEffect8, useLayoutEffect, useRef as useRef5, useState as
|
|
3593
|
-
import { useComputed as
|
|
4213
|
+
import { useEffect as useEffect8, useLayoutEffect, useRef as useRef5, useState as useState6 } from "preact/hooks";
|
|
4214
|
+
import { useComputed as useComputed5 } from "@preact/signals";
|
|
3594
4215
|
|
|
3595
4216
|
// src/ui/message-bubble.tsx
|
|
3596
|
-
import { useComputed as
|
|
4217
|
+
import { useComputed as useComputed4 } from "@preact/signals";
|
|
3597
4218
|
|
|
3598
4219
|
// src/ui/markdown.tsx
|
|
3599
4220
|
import { useEffect as useEffect7, useMemo, useRef as useRef4 } from "preact/hooks";
|
|
3600
4221
|
import { effect, signal as signal4 } from "@preact/signals";
|
|
3601
4222
|
import * as smd from "streaming-markdown";
|
|
3602
|
-
import { jsx as
|
|
4223
|
+
import { jsx as jsx12 } from "preact/jsx-runtime";
|
|
3603
4224
|
function MarkdownView({ textSig, doneSig }) {
|
|
3604
4225
|
const ref = useRef4(null);
|
|
3605
4226
|
useEffect7(() => {
|
|
@@ -3649,12 +4270,12 @@ function MarkdownView({ textSig, doneSig }) {
|
|
|
3649
4270
|
el.removeEventListener("click", onClick);
|
|
3650
4271
|
};
|
|
3651
4272
|
}, [textSig, doneSig]);
|
|
3652
|
-
return /* @__PURE__ */
|
|
4273
|
+
return /* @__PURE__ */ jsx12("div", { ref });
|
|
3653
4274
|
}
|
|
3654
4275
|
function StaticMarkdown({ text }) {
|
|
3655
4276
|
const textSig = useMemo(() => signal4(text), [text]);
|
|
3656
4277
|
const doneSig = useMemo(() => signal4(true), []);
|
|
3657
|
-
return /* @__PURE__ */
|
|
4278
|
+
return /* @__PURE__ */ jsx12(MarkdownView, { textSig, doneSig });
|
|
3658
4279
|
}
|
|
3659
4280
|
function hardenLink(a) {
|
|
3660
4281
|
const href = a.getAttribute("href") ?? "";
|
|
@@ -3666,29 +4287,248 @@ function hardenLink(a) {
|
|
|
3666
4287
|
a.rel = [...tokens].join(" ");
|
|
3667
4288
|
}
|
|
3668
4289
|
|
|
4290
|
+
// src/ui/tool-approval.tsx
|
|
4291
|
+
import { useComputed as useComputed2, useSignal } from "@preact/signals";
|
|
4292
|
+
import { Fragment, jsx as jsx13, jsxs as jsxs10 } from "preact/jsx-runtime";
|
|
4293
|
+
var p12 = BRAND.cssPrefix;
|
|
4294
|
+
function ToolApproval({ part, strings, active, onDecision }) {
|
|
4295
|
+
const approval = useComputed2(() => part.approvalSig.value);
|
|
4296
|
+
const input = useComputed2(() => part.inputSig.value);
|
|
4297
|
+
const reason = useSignal("");
|
|
4298
|
+
const decided = approval.value?.approved !== void 0;
|
|
4299
|
+
if (decided) {
|
|
4300
|
+
const ap = approval.value;
|
|
4301
|
+
return /* @__PURE__ */ jsxs10("div", { class: `${p12}-tool-approval ${p12}-tool-decided`, "data-testid": TID.toolDecision, children: [
|
|
4302
|
+
/* @__PURE__ */ jsx13("span", { class: `${p12}-tool-decided-label`, "data-approved": ap?.approved ? "true" : "false", children: ap?.approved ? strings.approved : strings.rejected }),
|
|
4303
|
+
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: part.toolName }),
|
|
4304
|
+
ap?.reason ? /* @__PURE__ */ jsx13("span", { class: `${p12}-tool-decided-value`, children: ap.reason }) : null
|
|
4305
|
+
] });
|
|
4306
|
+
}
|
|
4307
|
+
const args = summarizeInput(input.value);
|
|
4308
|
+
return /* @__PURE__ */ jsxs10("div", { class: `${p12}-tool-approval`, "data-testid": TID.toolApproval, children: [
|
|
4309
|
+
/* @__PURE__ */ jsxs10("div", { class: `${p12}-tool-head`, children: [
|
|
4310
|
+
/* @__PURE__ */ jsx13("span", { class: `${p12}-tool-badge`, children: strings.approvalRequired }),
|
|
4311
|
+
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: part.toolName })
|
|
4312
|
+
] }),
|
|
4313
|
+
args ? /* @__PURE__ */ jsx13("pre", { class: `${p12}-tool-args`, children: args }) : null,
|
|
4314
|
+
active ? /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
4315
|
+
/* @__PURE__ */ jsx13(
|
|
4316
|
+
"input",
|
|
4317
|
+
{
|
|
4318
|
+
class: `${p12}-field-input`,
|
|
4319
|
+
value: reason.value,
|
|
4320
|
+
placeholder: strings.approvalReason,
|
|
4321
|
+
onInput: (e) => {
|
|
4322
|
+
reason.value = e.target.value;
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
),
|
|
4326
|
+
/* @__PURE__ */ jsxs10("div", { class: `${p12}-form-actions`, children: [
|
|
4327
|
+
/* @__PURE__ */ jsx13(
|
|
4328
|
+
"button",
|
|
4329
|
+
{
|
|
4330
|
+
type: "button",
|
|
4331
|
+
class: `${p12}-tool-reject`,
|
|
4332
|
+
onClick: () => onDecision(part.toolCallId, false, reason.value.trim() || void 0),
|
|
4333
|
+
"data-testid": TID.toolReject,
|
|
4334
|
+
children: strings.reject
|
|
4335
|
+
}
|
|
4336
|
+
),
|
|
4337
|
+
/* @__PURE__ */ jsx13(
|
|
4338
|
+
"button",
|
|
4339
|
+
{
|
|
4340
|
+
type: "button",
|
|
4341
|
+
class: `${p12}-tool-approve`,
|
|
4342
|
+
onClick: () => onDecision(part.toolCallId, true, reason.value.trim() || void 0),
|
|
4343
|
+
"data-testid": TID.toolApprove,
|
|
4344
|
+
children: strings.approve
|
|
4345
|
+
}
|
|
4346
|
+
)
|
|
4347
|
+
] })
|
|
4348
|
+
] }) : /* @__PURE__ */ jsx13("p", { class: `${p12}-tool-stale-note`, children: strings.stepNoLongerActive })
|
|
4349
|
+
] });
|
|
4350
|
+
}
|
|
4351
|
+
function summarizeInput(input) {
|
|
4352
|
+
if (input == null) return "";
|
|
4353
|
+
try {
|
|
4354
|
+
const json = typeof input === "string" ? input : JSON.stringify(input, null, 2);
|
|
4355
|
+
return json.length > 600 ? `${json.slice(0, 600)}\u2026` : json;
|
|
4356
|
+
} catch {
|
|
4357
|
+
return "";
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4361
|
+
// src/ui/tool-ask-input.tsx
|
|
4362
|
+
import { useComputed as useComputed3 } from "@preact/signals";
|
|
4363
|
+
|
|
4364
|
+
// src/ui/form/field.ts
|
|
4365
|
+
function parseAskUserInput(input) {
|
|
4366
|
+
const raw = input && typeof input === "object" ? input : {};
|
|
4367
|
+
const responseType = raw.responseType;
|
|
4368
|
+
return {
|
|
4369
|
+
title: str(raw.title),
|
|
4370
|
+
question: str(raw.question) ?? "Please provide the missing information.",
|
|
4371
|
+
description: str(raw.description),
|
|
4372
|
+
placeholder: str(raw.placeholder),
|
|
4373
|
+
responseType: responseType === "single-choice" || responseType === "multi-choice" || responseType === "confirmation" || responseType === "free-text" ? responseType : "free-text",
|
|
4374
|
+
choices: Array.isArray(raw.choices) ? raw.choices : void 0,
|
|
4375
|
+
allowOther: typeof raw.allowOther === "boolean" ? raw.allowOther : void 0,
|
|
4376
|
+
required: typeof raw.required === "boolean" ? raw.required : true,
|
|
4377
|
+
defaultValues: Array.isArray(raw.defaultValues) ? raw.defaultValues.filter((v) => typeof v === "string") : void 0,
|
|
4378
|
+
minSelections: num(raw.minSelections),
|
|
4379
|
+
maxSelections: num(raw.maxSelections),
|
|
4380
|
+
validationHint: str(raw.validationHint)
|
|
4381
|
+
};
|
|
4382
|
+
}
|
|
4383
|
+
function askInputToFields(req) {
|
|
4384
|
+
if (req.responseType === "confirmation") return [];
|
|
4385
|
+
const options = (req.choices ?? []).map(normalizeChoice).filter((c) => c !== null);
|
|
4386
|
+
let type = "textarea";
|
|
4387
|
+
if (req.responseType === "single-choice" && options.length > 0) type = "radio";
|
|
4388
|
+
else if (req.responseType === "multi-choice") type = "multiselect";
|
|
4389
|
+
const defaultValue = type === "multiselect" ? req.defaultValues?.join(", ") : req.defaultValues?.[0];
|
|
4390
|
+
return [
|
|
4391
|
+
{
|
|
4392
|
+
name: "answer",
|
|
4393
|
+
label: req.question,
|
|
4394
|
+
type,
|
|
4395
|
+
placeholder: req.placeholder,
|
|
4396
|
+
required: req.required ?? true,
|
|
4397
|
+
defaultValue,
|
|
4398
|
+
options: options.length > 0 ? options : void 0,
|
|
4399
|
+
allowOther: req.allowOther,
|
|
4400
|
+
validationHint: req.validationHint,
|
|
4401
|
+
validation: type === "multiselect" ? { minSelections: req.minSelections, maxSelections: req.maxSelections } : void 0
|
|
4402
|
+
}
|
|
4403
|
+
];
|
|
4404
|
+
}
|
|
4405
|
+
function normalizeChoice(c) {
|
|
4406
|
+
if (typeof c === "string") return c ? { value: c, label: c } : null;
|
|
4407
|
+
if (c && typeof c.value === "string" && c.value)
|
|
4408
|
+
return { value: c.value, label: c.label ?? c.value, description: c.description };
|
|
4409
|
+
return null;
|
|
4410
|
+
}
|
|
4411
|
+
function str(v) {
|
|
4412
|
+
return typeof v === "string" && v.trim() ? v.trim() : void 0;
|
|
4413
|
+
}
|
|
4414
|
+
function num(v) {
|
|
4415
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
4416
|
+
}
|
|
4417
|
+
|
|
4418
|
+
// src/ui/tool-ask-input.tsx
|
|
4419
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "preact/jsx-runtime";
|
|
4420
|
+
var p13 = BRAND.cssPrefix;
|
|
4421
|
+
function ToolAskInput({ part, strings, active, onSubmit }) {
|
|
4422
|
+
const state = useComputed3(() => part.stateSig.value);
|
|
4423
|
+
const request = useComputed3(() => parseAskUserInput(part.inputSig.value));
|
|
4424
|
+
const decided = state.value === "output" || state.value === "error";
|
|
4425
|
+
if (decided) {
|
|
4426
|
+
return /* @__PURE__ */ jsx14(DecidedSummary, { part, strings });
|
|
4427
|
+
}
|
|
4428
|
+
if (!active) {
|
|
4429
|
+
return /* @__PURE__ */ jsxs11("div", { class: `${p13}-tool-ask-input ${p13}-tool-stale`, "data-testid": TID.toolAskInput, children: [
|
|
4430
|
+
/* @__PURE__ */ jsx14(Header, { strings, title: request.value.title ?? request.value.question }),
|
|
4431
|
+
/* @__PURE__ */ jsx14("p", { class: `${p13}-tool-stale-note`, children: strings.stepNoLongerActive })
|
|
4432
|
+
] });
|
|
4433
|
+
}
|
|
4434
|
+
const req = request.value;
|
|
4435
|
+
const isConfirmation = req.responseType === "confirmation";
|
|
4436
|
+
return /* @__PURE__ */ jsxs11("div", { class: `${p13}-tool-ask-input`, "data-testid": TID.toolAskInput, children: [
|
|
4437
|
+
/* @__PURE__ */ jsx14(Header, { strings, title: req.title }),
|
|
4438
|
+
req.description ? /* @__PURE__ */ jsx14("p", { class: `${p13}-tool-desc`, children: req.description }) : null,
|
|
4439
|
+
isConfirmation ? /* @__PURE__ */ jsx14("p", { class: `${p13}-tool-question`, children: req.question }) : null,
|
|
4440
|
+
isConfirmation ? /* @__PURE__ */ jsxs11("div", { class: `${p13}-form-actions`, children: [
|
|
4441
|
+
/* @__PURE__ */ jsx14(
|
|
4442
|
+
"button",
|
|
4443
|
+
{
|
|
4444
|
+
type: "button",
|
|
4445
|
+
class: `${p13}-form-skip`,
|
|
4446
|
+
onClick: () => onSubmit(part.toolCallId, { confirmed: false }),
|
|
4447
|
+
"data-testid": TID.toolInputSkip,
|
|
4448
|
+
children: strings.reject
|
|
4449
|
+
}
|
|
4450
|
+
),
|
|
4451
|
+
/* @__PURE__ */ jsx14(
|
|
4452
|
+
"button",
|
|
4453
|
+
{
|
|
4454
|
+
type: "button",
|
|
4455
|
+
class: `${p13}-form-submit`,
|
|
4456
|
+
onClick: () => onSubmit(part.toolCallId, { confirmed: true }),
|
|
4457
|
+
"data-testid": TID.toolInputSubmit,
|
|
4458
|
+
children: strings.approve
|
|
4459
|
+
}
|
|
4460
|
+
)
|
|
4461
|
+
] }) : /* @__PURE__ */ jsx14(
|
|
4462
|
+
DynamicForm,
|
|
4463
|
+
{
|
|
4464
|
+
fields: askInputToFields(req),
|
|
4465
|
+
strings,
|
|
4466
|
+
submitLabel: strings.inputSubmit,
|
|
4467
|
+
onSubmit: (values) => onSubmit(part.toolCallId, values),
|
|
4468
|
+
skipLabel: req.required === false ? strings.inputSkip : void 0,
|
|
4469
|
+
onSkip: req.required === false ? () => onSubmit(part.toolCallId, {}) : void 0,
|
|
4470
|
+
submitTestId: TID.toolInputSubmit,
|
|
4471
|
+
skipTestId: TID.toolInputSkip
|
|
4472
|
+
}
|
|
4473
|
+
)
|
|
4474
|
+
] });
|
|
4475
|
+
}
|
|
4476
|
+
function Header({ strings, title }) {
|
|
4477
|
+
return /* @__PURE__ */ jsxs11("div", { class: `${p13}-tool-head`, children: [
|
|
4478
|
+
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-badge`, children: strings.inputRequired }),
|
|
4479
|
+
title ? /* @__PURE__ */ jsx14("strong", { class: `${p13}-tool-title`, children: title }) : null
|
|
4480
|
+
] });
|
|
4481
|
+
}
|
|
4482
|
+
function DecidedSummary({ part, strings }) {
|
|
4483
|
+
const output = useComputed3(() => part.outputSig.value);
|
|
4484
|
+
const text = summarizeOutput(output.value) || strings.inputSubmitted;
|
|
4485
|
+
return /* @__PURE__ */ jsxs11("div", { class: `${p13}-tool-ask-input ${p13}-tool-decided`, "data-testid": TID.toolDecision, children: [
|
|
4486
|
+
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-label`, children: strings.inputSubmitted }),
|
|
4487
|
+
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-value`, children: text })
|
|
4488
|
+
] });
|
|
4489
|
+
}
|
|
4490
|
+
function summarizeOutput(output) {
|
|
4491
|
+
if (output == null) return "";
|
|
4492
|
+
if (typeof output === "string") return output;
|
|
4493
|
+
if (typeof output === "object") {
|
|
4494
|
+
const rec = output;
|
|
4495
|
+
if ("confirmed" in rec) return rec.confirmed ? "Yes" : "No";
|
|
4496
|
+
return Object.values(rec).filter((v) => typeof v === "string" || typeof v === "number").join(", ");
|
|
4497
|
+
}
|
|
4498
|
+
return String(output);
|
|
4499
|
+
}
|
|
4500
|
+
|
|
3669
4501
|
// src/ui/tool-chip.tsx
|
|
3670
|
-
import { jsx as
|
|
4502
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "preact/jsx-runtime";
|
|
3671
4503
|
function ToolChip({ part, strings }) {
|
|
3672
|
-
const
|
|
3673
|
-
return /* @__PURE__ */
|
|
3674
|
-
/* @__PURE__ */
|
|
4504
|
+
const p33 = BRAND.cssPrefix;
|
|
4505
|
+
return /* @__PURE__ */ jsxs12("span", { class: `${p33}-tool-chip`, role: "status", children: [
|
|
4506
|
+
/* @__PURE__ */ jsxs12("span", { children: [
|
|
3675
4507
|
strings.usedTool,
|
|
3676
4508
|
":"
|
|
3677
4509
|
] }),
|
|
3678
|
-
/* @__PURE__ */
|
|
4510
|
+
/* @__PURE__ */ jsx15("strong", { children: part.toolName })
|
|
3679
4511
|
] });
|
|
3680
4512
|
}
|
|
3681
4513
|
|
|
3682
4514
|
// src/ui/message-bubble.tsx
|
|
3683
|
-
import { jsx as
|
|
3684
|
-
var
|
|
3685
|
-
function MessageBubble({
|
|
3686
|
-
|
|
4515
|
+
import { jsx as jsx16, jsxs as jsxs13 } from "preact/jsx-runtime";
|
|
4516
|
+
var p14 = BRAND.cssPrefix;
|
|
4517
|
+
function MessageBubble({
|
|
4518
|
+
message,
|
|
4519
|
+
strings,
|
|
4520
|
+
responseMode,
|
|
4521
|
+
showReasoning,
|
|
4522
|
+
showToolCalls,
|
|
4523
|
+
interactive = false,
|
|
4524
|
+
tool
|
|
4525
|
+
}) {
|
|
4526
|
+
const parts = useComputed4(() => message.partsSig.value);
|
|
3687
4527
|
const partList = parts.value;
|
|
3688
|
-
const hasAnswerText =
|
|
4528
|
+
const hasAnswerText = useComputed4(
|
|
3689
4529
|
() => message.partsSig.value.some((part) => part.kind === "text" && part.textSig.value.length > 0)
|
|
3690
4530
|
);
|
|
3691
|
-
const reasoningVisible =
|
|
4531
|
+
const reasoningVisible = useComputed4(
|
|
3692
4532
|
() => showReasoning && message.partsSig.value.some((part) => part.kind === "reasoning")
|
|
3693
4533
|
);
|
|
3694
4534
|
const streaming = message.role === "assistant" && message.status === "streaming";
|
|
@@ -3696,23 +4536,25 @@ function MessageBubble({ message, strings, responseMode, showReasoning, showTool
|
|
|
3696
4536
|
const working = streaming && !hasAnswerText.value;
|
|
3697
4537
|
const showStreamDots = streaming && !bufferedHold && !(reasoningVisible.value && working);
|
|
3698
4538
|
const stamp = formatStamp(message.createdAt);
|
|
3699
|
-
return /* @__PURE__ */
|
|
3700
|
-
/* @__PURE__ */
|
|
3701
|
-
bufferedHold ? /* @__PURE__ */
|
|
4539
|
+
return /* @__PURE__ */ jsx16("div", { class: `${p14}-bubble-row`, "data-role": message.role, "data-testid": tid(TID.messageBubble, message.id), children: /* @__PURE__ */ jsxs13("div", { class: `${p14}-bubble-col`, children: [
|
|
4540
|
+
/* @__PURE__ */ jsxs13("div", { class: `${p14}-bubble`, children: [
|
|
4541
|
+
bufferedHold ? /* @__PURE__ */ jsx16(LoadingSpinner, { label: strings.loading }) : partList.map((part) => /* @__PURE__ */ jsx16(
|
|
3702
4542
|
PartView,
|
|
3703
4543
|
{
|
|
3704
4544
|
part,
|
|
3705
4545
|
active: working,
|
|
3706
4546
|
strings,
|
|
3707
4547
|
showReasoning,
|
|
3708
|
-
showToolCalls
|
|
4548
|
+
showToolCalls,
|
|
4549
|
+
interactive,
|
|
4550
|
+
tool
|
|
3709
4551
|
},
|
|
3710
4552
|
partKey(part)
|
|
3711
4553
|
)),
|
|
3712
|
-
showStreamDots && /* @__PURE__ */
|
|
3713
|
-
message.status === "error" && message.errorText ? /* @__PURE__ */
|
|
4554
|
+
showStreamDots && /* @__PURE__ */ jsx16(TypingDots, {}),
|
|
4555
|
+
message.status === "error" && message.errorText ? /* @__PURE__ */ jsx16("div", { class: `${p14}-error`, role: "alert", children: /* @__PURE__ */ jsx16("span", { children: message.errorText }) }) : null
|
|
3714
4556
|
] }),
|
|
3715
|
-
stamp ? /* @__PURE__ */
|
|
4557
|
+
stamp ? /* @__PURE__ */ jsx16("time", { class: `${p14}-bubble-time`, dateTime: stamp.iso, title: stamp.full, children: stamp.short }) : null
|
|
3716
4558
|
] }) });
|
|
3717
4559
|
}
|
|
3718
4560
|
function formatStamp(createdAt) {
|
|
@@ -3733,32 +4575,62 @@ function PartView({
|
|
|
3733
4575
|
active,
|
|
3734
4576
|
strings,
|
|
3735
4577
|
showReasoning,
|
|
3736
|
-
showToolCalls
|
|
4578
|
+
showToolCalls,
|
|
4579
|
+
interactive,
|
|
4580
|
+
tool
|
|
3737
4581
|
}) {
|
|
3738
4582
|
switch (part.kind) {
|
|
3739
4583
|
case "text":
|
|
3740
|
-
return /* @__PURE__ */
|
|
4584
|
+
return /* @__PURE__ */ jsx16(MarkdownView, { textSig: part.textSig, doneSig: part.doneSig });
|
|
3741
4585
|
case "reasoning":
|
|
3742
|
-
return showReasoning ? /* @__PURE__ */
|
|
4586
|
+
return showReasoning ? /* @__PURE__ */ jsx16(ReasoningView, { part, active, strings }) : null;
|
|
3743
4587
|
case "tool":
|
|
3744
|
-
return
|
|
4588
|
+
return /* @__PURE__ */ jsx16(
|
|
4589
|
+
ToolPartView,
|
|
4590
|
+
{
|
|
4591
|
+
part,
|
|
4592
|
+
strings,
|
|
4593
|
+
showToolCalls,
|
|
4594
|
+
interactive,
|
|
4595
|
+
tool
|
|
4596
|
+
}
|
|
4597
|
+
);
|
|
3745
4598
|
case "file":
|
|
3746
4599
|
if (part.mediaType.startsWith("image/")) {
|
|
3747
|
-
return /* @__PURE__ */
|
|
4600
|
+
return /* @__PURE__ */ jsx16("img", { src: part.url, alt: "", loading: "lazy" });
|
|
3748
4601
|
}
|
|
3749
|
-
return /* @__PURE__ */
|
|
4602
|
+
return /* @__PURE__ */ jsx16("a", { href: part.url, target: "_blank", rel: "noreferrer noopener", children: part.url });
|
|
3750
4603
|
case "source":
|
|
3751
4604
|
return null;
|
|
3752
4605
|
}
|
|
3753
4606
|
}
|
|
4607
|
+
function ToolPartView({
|
|
4608
|
+
part,
|
|
4609
|
+
strings,
|
|
4610
|
+
showToolCalls,
|
|
4611
|
+
interactive,
|
|
4612
|
+
tool
|
|
4613
|
+
}) {
|
|
4614
|
+
const state = useComputed4(() => part.stateSig.value);
|
|
4615
|
+
const hasApproval = useComputed4(() => part.approvalSig.value !== void 0);
|
|
4616
|
+
if (tool?.humanInLoop) {
|
|
4617
|
+
if (hasApproval.value || state.value === "awaiting-approval") {
|
|
4618
|
+
return /* @__PURE__ */ jsx16(ToolApproval, { part, strings, active: interactive, onDecision: tool.onDecision });
|
|
4619
|
+
}
|
|
4620
|
+
if (isAskUserInputTool(part.toolName) || state.value === "awaiting-input") {
|
|
4621
|
+
return /* @__PURE__ */ jsx16(ToolAskInput, { part, strings, active: interactive, onSubmit: tool.onResult });
|
|
4622
|
+
}
|
|
4623
|
+
}
|
|
4624
|
+
return showToolCalls ? /* @__PURE__ */ jsx16(ToolChip, { part, strings }) : null;
|
|
4625
|
+
}
|
|
3754
4626
|
function ReasoningView({
|
|
3755
4627
|
part,
|
|
3756
4628
|
active,
|
|
3757
4629
|
strings
|
|
3758
4630
|
}) {
|
|
3759
|
-
return /* @__PURE__ */
|
|
3760
|
-
/* @__PURE__ */
|
|
3761
|
-
/* @__PURE__ */
|
|
4631
|
+
return /* @__PURE__ */ jsxs13("details", { class: `${p14}-reasoning`, open: active, "data-active": active ? "true" : void 0, children: [
|
|
4632
|
+
/* @__PURE__ */ jsx16("summary", { class: `${p14}-reasoning-summary`, children: /* @__PURE__ */ jsx16("span", { class: `${p14}-reasoning-label`, children: active ? strings.thinking : strings.thoughts }) }),
|
|
4633
|
+
/* @__PURE__ */ jsx16("div", { class: `${p14}-reasoning-body`, children: /* @__PURE__ */ jsx16(MarkdownView, { textSig: part.textSig, doneSig: part.doneSig }) })
|
|
3762
4634
|
] });
|
|
3763
4635
|
}
|
|
3764
4636
|
function partKey(part) {
|
|
@@ -3775,29 +4647,38 @@ function partKey(part) {
|
|
|
3775
4647
|
}
|
|
3776
4648
|
}
|
|
3777
4649
|
function TypingDots() {
|
|
3778
|
-
return /* @__PURE__ */
|
|
3779
|
-
/* @__PURE__ */
|
|
3780
|
-
/* @__PURE__ */
|
|
3781
|
-
/* @__PURE__ */
|
|
4650
|
+
return /* @__PURE__ */ jsxs13("span", { class: `${p14}-typing`, "aria-hidden": "true", children: [
|
|
4651
|
+
/* @__PURE__ */ jsx16("span", {}),
|
|
4652
|
+
/* @__PURE__ */ jsx16("span", {}),
|
|
4653
|
+
/* @__PURE__ */ jsx16("span", {})
|
|
3782
4654
|
] });
|
|
3783
4655
|
}
|
|
3784
4656
|
function LoadingSpinner({ label }) {
|
|
3785
|
-
return /* @__PURE__ */
|
|
3786
|
-
/* @__PURE__ */
|
|
3787
|
-
/* @__PURE__ */
|
|
4657
|
+
return /* @__PURE__ */ jsxs13("span", { class: `${p14}-loading`, role: "status", children: [
|
|
4658
|
+
/* @__PURE__ */ jsx16("span", { class: `${p14}-loading-spinner`, "aria-hidden": "true" }),
|
|
4659
|
+
/* @__PURE__ */ jsx16("span", { class: `${p14}-loading-label`, children: label })
|
|
3788
4660
|
] });
|
|
3789
4661
|
}
|
|
3790
4662
|
|
|
3791
4663
|
// src/ui/message-list.tsx
|
|
3792
|
-
import { jsx as
|
|
3793
|
-
var
|
|
4664
|
+
import { jsx as jsx17, jsxs as jsxs14 } from "preact/jsx-runtime";
|
|
4665
|
+
var p15 = BRAND.cssPrefix;
|
|
3794
4666
|
var STICK_THRESHOLD = 120;
|
|
3795
4667
|
var DIVIDER_IDLE_MS = 1200;
|
|
3796
|
-
function MessageList({
|
|
4668
|
+
function MessageList({
|
|
4669
|
+
messagesSig,
|
|
4670
|
+
strings,
|
|
4671
|
+
responseMode,
|
|
4672
|
+
showReasoning,
|
|
4673
|
+
showToolCalls,
|
|
4674
|
+
loading,
|
|
4675
|
+
idle,
|
|
4676
|
+
tool
|
|
4677
|
+
}) {
|
|
3797
4678
|
const ref = useRef5(null);
|
|
3798
|
-
const messages =
|
|
3799
|
-
const [showJump, setShowJump] =
|
|
3800
|
-
const [scrolling, setScrolling] =
|
|
4679
|
+
const messages = useComputed5(() => messagesSig.value);
|
|
4680
|
+
const [showJump, setShowJump] = useState6(false);
|
|
4681
|
+
const [scrolling, setScrolling] = useState6(false);
|
|
3801
4682
|
const hasHydratedRef = useRef5(false);
|
|
3802
4683
|
const firstMessageId = messages.value[0]?.id;
|
|
3803
4684
|
useLayoutEffect(() => {
|
|
@@ -3852,18 +4733,18 @@ function MessageList({ messagesSig, strings, responseMode, showReasoning, showTo
|
|
|
3852
4733
|
const el = ref.current;
|
|
3853
4734
|
if (!el) return;
|
|
3854
4735
|
const syncJump = () => setShowJump(el.scrollHeight - el.scrollTop - el.clientHeight > STICK_THRESHOLD * 2);
|
|
3855
|
-
let
|
|
4736
|
+
let idleTimer;
|
|
3856
4737
|
const onScroll = () => {
|
|
3857
4738
|
syncJump();
|
|
3858
4739
|
setScrolling(true);
|
|
3859
|
-
clearTimeout(
|
|
3860
|
-
|
|
4740
|
+
clearTimeout(idleTimer);
|
|
4741
|
+
idleTimer = setTimeout(() => setScrolling(false), DIVIDER_IDLE_MS);
|
|
3861
4742
|
};
|
|
3862
4743
|
el.addEventListener("scroll", onScroll, { passive: true });
|
|
3863
4744
|
syncJump();
|
|
3864
4745
|
return () => {
|
|
3865
4746
|
el.removeEventListener("scroll", onScroll);
|
|
3866
|
-
clearTimeout(
|
|
4747
|
+
clearTimeout(idleTimer);
|
|
3867
4748
|
};
|
|
3868
4749
|
}, []);
|
|
3869
4750
|
const jumpToBottom = () => {
|
|
@@ -3872,54 +4753,57 @@ function MessageList({ messagesSig, strings, responseMode, showReasoning, showTo
|
|
|
3872
4753
|
};
|
|
3873
4754
|
const rows = [];
|
|
3874
4755
|
let prevDay = "";
|
|
4756
|
+
const lastId = messages.value.at(-1)?.id;
|
|
3875
4757
|
for (const m of messages.value) {
|
|
3876
4758
|
const day = dayKey(m.createdAt);
|
|
3877
4759
|
if (day && day !== prevDay) {
|
|
3878
4760
|
rows.push(
|
|
3879
|
-
/* @__PURE__ */
|
|
4761
|
+
/* @__PURE__ */ jsx17("div", { class: `${p15}-date-divider`, children: /* @__PURE__ */ jsx17("span", { class: `${p15}-date-pill`, title: fullDate(m.createdAt), children: dayLabel(m.createdAt, strings) }) }, `day:${day}`)
|
|
3880
4762
|
);
|
|
3881
4763
|
prevDay = day;
|
|
3882
4764
|
}
|
|
3883
4765
|
rows.push(
|
|
3884
|
-
/* @__PURE__ */
|
|
4766
|
+
/* @__PURE__ */ jsx17(
|
|
3885
4767
|
MessageBubble,
|
|
3886
4768
|
{
|
|
3887
4769
|
message: m,
|
|
3888
4770
|
strings,
|
|
3889
4771
|
responseMode,
|
|
3890
4772
|
showReasoning,
|
|
3891
|
-
showToolCalls
|
|
4773
|
+
showToolCalls,
|
|
4774
|
+
interactive: Boolean(idle) && m.id === lastId,
|
|
4775
|
+
tool
|
|
3892
4776
|
},
|
|
3893
4777
|
m.id
|
|
3894
4778
|
)
|
|
3895
4779
|
);
|
|
3896
4780
|
}
|
|
3897
|
-
return /* @__PURE__ */
|
|
3898
|
-
/* @__PURE__ */
|
|
4781
|
+
return /* @__PURE__ */ jsxs14("div", { class: `${p15}-list-wrap`, children: [
|
|
4782
|
+
/* @__PURE__ */ jsxs14(
|
|
3899
4783
|
"div",
|
|
3900
4784
|
{
|
|
3901
4785
|
ref,
|
|
3902
|
-
class: `${
|
|
4786
|
+
class: `${p15}-list`,
|
|
3903
4787
|
role: "log",
|
|
3904
4788
|
"aria-live": "polite",
|
|
3905
4789
|
"aria-relevant": "additions text",
|
|
3906
4790
|
"data-scrolling": scrolling ? "true" : void 0,
|
|
3907
4791
|
children: [
|
|
3908
|
-
loading && messages.value.length === 0 ? /* @__PURE__ */
|
|
4792
|
+
loading && messages.value.length === 0 ? /* @__PURE__ */ jsx17("div", { class: `${p15}-list-loading`, role: "status", children: strings.messagesLoading }) : null,
|
|
3909
4793
|
rows
|
|
3910
4794
|
]
|
|
3911
4795
|
}
|
|
3912
4796
|
),
|
|
3913
|
-
showJump ? /* @__PURE__ */
|
|
4797
|
+
showJump ? /* @__PURE__ */ jsx17(
|
|
3914
4798
|
"button",
|
|
3915
4799
|
{
|
|
3916
4800
|
type: "button",
|
|
3917
|
-
class: `${
|
|
4801
|
+
class: `${p15}-jump`,
|
|
3918
4802
|
onClick: jumpToBottom,
|
|
3919
4803
|
"aria-label": strings.scrollToBottom,
|
|
3920
4804
|
title: strings.scrollToBottom,
|
|
3921
4805
|
"data-testid": TID.scrollToBottom,
|
|
3922
|
-
children: /* @__PURE__ */
|
|
4806
|
+
children: /* @__PURE__ */ jsx17(ChevronDownIcon, {})
|
|
3923
4807
|
}
|
|
3924
4808
|
) : null
|
|
3925
4809
|
] });
|
|
@@ -3948,7 +4832,7 @@ function dayLabel(createdAt, strings) {
|
|
|
3948
4832
|
}
|
|
3949
4833
|
|
|
3950
4834
|
// src/ui/conversation-list.tsx
|
|
3951
|
-
import { useEffect as useEffect9, useState as
|
|
4835
|
+
import { useEffect as useEffect9, useState as useState7 } from "preact/hooks";
|
|
3952
4836
|
|
|
3953
4837
|
// src/ui/history-groups.ts
|
|
3954
4838
|
var HISTORY_BUCKETS = ["today", "yesterday", "lastWeek", "older"];
|
|
@@ -3978,7 +4862,7 @@ function startOfDay(ms) {
|
|
|
3978
4862
|
}
|
|
3979
4863
|
|
|
3980
4864
|
// src/ui/conversation-list.tsx
|
|
3981
|
-
import { Fragment, jsx as
|
|
4865
|
+
import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs15 } from "preact/jsx-runtime";
|
|
3982
4866
|
var log11 = logger.scope("history");
|
|
3983
4867
|
var BUCKET_TO_STRING = {
|
|
3984
4868
|
today: "dateToday",
|
|
@@ -3987,9 +4871,9 @@ var BUCKET_TO_STRING = {
|
|
|
3987
4871
|
older: "dateOlder"
|
|
3988
4872
|
};
|
|
3989
4873
|
function ConversationList({ transport, strings, visitorId, onSelect, onNewChat }) {
|
|
3990
|
-
const
|
|
3991
|
-
const [state, setState] =
|
|
3992
|
-
const [sessions, setChats] =
|
|
4874
|
+
const p33 = BRAND.cssPrefix;
|
|
4875
|
+
const [state, setState] = useState7("loading");
|
|
4876
|
+
const [sessions, setChats] = useState7([]);
|
|
3993
4877
|
useEffect9(() => {
|
|
3994
4878
|
let cancelled = false;
|
|
3995
4879
|
transport.listSessions({ visitorId }).then((res) => {
|
|
@@ -4005,38 +4889,38 @@ function ConversationList({ transport, strings, visitorId, onSelect, onNewChat }
|
|
|
4005
4889
|
cancelled = true;
|
|
4006
4890
|
};
|
|
4007
4891
|
}, [transport, visitorId]);
|
|
4008
|
-
const newChatButton = onNewChat ? /* @__PURE__ */
|
|
4009
|
-
/* @__PURE__ */
|
|
4892
|
+
const newChatButton = onNewChat ? /* @__PURE__ */ jsx18("div", { class: `${p33}-history-footer`, children: /* @__PURE__ */ jsxs15("button", { type: "button", class: `${p33}-history-new`, onClick: onNewChat, "data-testid": TID.sidebarNewChat, children: [
|
|
4893
|
+
/* @__PURE__ */ jsx18(PlusIcon, {}),
|
|
4010
4894
|
strings.historyNewChat
|
|
4011
4895
|
] }) }) : null;
|
|
4012
4896
|
if (state === "loading") {
|
|
4013
|
-
return /* @__PURE__ */
|
|
4014
|
-
/* @__PURE__ */
|
|
4897
|
+
return /* @__PURE__ */ jsxs15(Fragment2, { children: [
|
|
4898
|
+
/* @__PURE__ */ jsx18("div", { class: `${p33}-history-empty`, children: strings.historyLoading }),
|
|
4015
4899
|
newChatButton
|
|
4016
4900
|
] });
|
|
4017
4901
|
}
|
|
4018
4902
|
if (state === "error" || sessions.length === 0) {
|
|
4019
|
-
return /* @__PURE__ */
|
|
4020
|
-
/* @__PURE__ */
|
|
4903
|
+
return /* @__PURE__ */ jsxs15(Fragment2, { children: [
|
|
4904
|
+
/* @__PURE__ */ jsx18("div", { class: `${p33}-history-empty`, children: strings.historyEmpty }),
|
|
4021
4905
|
newChatButton
|
|
4022
4906
|
] });
|
|
4023
4907
|
}
|
|
4024
4908
|
const groups = groupByBucket(Date.now(), sessions);
|
|
4025
|
-
return /* @__PURE__ */
|
|
4026
|
-
/* @__PURE__ */
|
|
4027
|
-
/* @__PURE__ */
|
|
4028
|
-
group.sessions.map((chat) => /* @__PURE__ */
|
|
4909
|
+
return /* @__PURE__ */ jsxs15(Fragment2, { children: [
|
|
4910
|
+
/* @__PURE__ */ jsx18("div", { class: `${p33}-history`, role: "list", children: groups.map((group) => /* @__PURE__ */ jsxs15("div", { class: `${p33}-history-group`, children: [
|
|
4911
|
+
/* @__PURE__ */ jsx18("div", { class: `${p33}-history-heading`, children: strings[BUCKET_TO_STRING[group.bucket]] }),
|
|
4912
|
+
group.sessions.map((chat) => /* @__PURE__ */ jsxs15(
|
|
4029
4913
|
"button",
|
|
4030
4914
|
{
|
|
4031
4915
|
type: "button",
|
|
4032
4916
|
role: "listitem",
|
|
4033
|
-
class: `${
|
|
4917
|
+
class: `${p33}-history-item`,
|
|
4034
4918
|
onClick: () => onSelect(chat),
|
|
4035
4919
|
"data-closed": chat.canContinue ? void 0 : "true",
|
|
4036
4920
|
"data-testid": tid(TID.historyItem, chat.sessionId),
|
|
4037
4921
|
children: [
|
|
4038
|
-
/* @__PURE__ */
|
|
4039
|
-
chat.preview ? /* @__PURE__ */
|
|
4922
|
+
/* @__PURE__ */ jsx18("span", { class: `${p33}-history-title`, children: chat.title }),
|
|
4923
|
+
chat.preview ? /* @__PURE__ */ jsx18("span", { class: `${p33}-history-preview`, children: chat.preview }) : null
|
|
4040
4924
|
]
|
|
4041
4925
|
},
|
|
4042
4926
|
chat.sessionId
|
|
@@ -4047,21 +4931,21 @@ function ConversationList({ transport, strings, visitorId, onSelect, onNewChat }
|
|
|
4047
4931
|
}
|
|
4048
4932
|
|
|
4049
4933
|
// src/ui/chat-history-pane.tsx
|
|
4050
|
-
import { jsx as
|
|
4934
|
+
import { jsx as jsx19 } from "preact/jsx-runtime";
|
|
4051
4935
|
function ChatHistoryPane(props2) {
|
|
4052
|
-
return /* @__PURE__ */
|
|
4936
|
+
return /* @__PURE__ */ jsx19(ConversationList, { ...props2 });
|
|
4053
4937
|
}
|
|
4054
4938
|
|
|
4055
4939
|
// src/ui/suggestions.tsx
|
|
4056
|
-
import { jsx as
|
|
4057
|
-
var
|
|
4940
|
+
import { jsx as jsx20 } from "preact/jsx-runtime";
|
|
4941
|
+
var p16 = BRAND.cssPrefix;
|
|
4058
4942
|
function Suggestions({ suggestions, onPick }) {
|
|
4059
4943
|
if (suggestions.length === 0) return null;
|
|
4060
|
-
return /* @__PURE__ */
|
|
4944
|
+
return /* @__PURE__ */ jsx20("div", { class: `${p16}-suggestions`, role: "group", "aria-label": "Suggested replies", children: suggestions.map((s, i) => /* @__PURE__ */ jsx20(
|
|
4061
4945
|
"button",
|
|
4062
4946
|
{
|
|
4063
4947
|
type: "button",
|
|
4064
|
-
class: `${
|
|
4948
|
+
class: `${p16}-suggestion`,
|
|
4065
4949
|
onClick: () => onPick(s),
|
|
4066
4950
|
"data-testid": tid(TID.suggestion, i),
|
|
4067
4951
|
children: s.label
|
|
@@ -4071,8 +4955,8 @@ function Suggestions({ suggestions, onPick }) {
|
|
|
4071
4955
|
}
|
|
4072
4956
|
|
|
4073
4957
|
// src/ui/panel.tsx
|
|
4074
|
-
import { Fragment as
|
|
4075
|
-
var
|
|
4958
|
+
import { Fragment as Fragment3, jsx as jsx21, jsxs as jsxs16 } from "preact/jsx-runtime";
|
|
4959
|
+
var p17 = BRAND.cssPrefix;
|
|
4076
4960
|
function Panel(props2) {
|
|
4077
4961
|
const { options, onClose } = props2;
|
|
4078
4962
|
const s = options.strings;
|
|
@@ -4096,18 +4980,18 @@ function Panel(props2) {
|
|
|
4096
4980
|
}, []);
|
|
4097
4981
|
const { visible: dragOver } = useFileDrop({ containerRef, onDrop: onDropItems });
|
|
4098
4982
|
useDragMove(containerRef.current, options.mode === "modal");
|
|
4099
|
-
return /* @__PURE__ */
|
|
4983
|
+
return /* @__PURE__ */ jsxs16(
|
|
4100
4984
|
"div",
|
|
4101
4985
|
{
|
|
4102
4986
|
ref: containerRef,
|
|
4103
|
-
class: `${
|
|
4987
|
+
class: `${p17}-panel`,
|
|
4104
4988
|
role: "dialog",
|
|
4105
4989
|
"aria-modal": "false",
|
|
4106
4990
|
"aria-label": s.panelTitle,
|
|
4107
4991
|
style: { position: "relative" },
|
|
4108
4992
|
"data-testid": TID.panel,
|
|
4109
4993
|
children: [
|
|
4110
|
-
/* @__PURE__ */
|
|
4994
|
+
/* @__PURE__ */ jsx21(
|
|
4111
4995
|
PanelContent,
|
|
4112
4996
|
{
|
|
4113
4997
|
...props2,
|
|
@@ -4116,7 +5000,7 @@ function Panel(props2) {
|
|
|
4116
5000
|
composerAttachApiRef
|
|
4117
5001
|
}
|
|
4118
5002
|
),
|
|
4119
|
-
/* @__PURE__ */
|
|
5003
|
+
/* @__PURE__ */ jsx21(PoweredByBar, { poweredBy: props2.options.poweredBy })
|
|
4120
5004
|
]
|
|
4121
5005
|
}
|
|
4122
5006
|
);
|
|
@@ -4147,13 +5031,39 @@ function PanelContent(props2) {
|
|
|
4147
5031
|
onSend,
|
|
4148
5032
|
onStop,
|
|
4149
5033
|
onSuggestion,
|
|
5034
|
+
intakePending,
|
|
5035
|
+
onIntakeComplete,
|
|
5036
|
+
tool,
|
|
4150
5037
|
containerEl,
|
|
4151
5038
|
dragOver,
|
|
4152
5039
|
composerAttachApiRef
|
|
4153
5040
|
} = props2;
|
|
4154
5041
|
const s = options.strings;
|
|
4155
|
-
|
|
4156
|
-
|
|
5042
|
+
let composerArea;
|
|
5043
|
+
if (intakePending) {
|
|
5044
|
+
composerArea = /* @__PURE__ */ jsx21(IntakeGate, { intake: options.intake, strings: s, onComplete: onIntakeComplete });
|
|
5045
|
+
} else if (canSend) {
|
|
5046
|
+
composerArea = /* @__PURE__ */ jsxs16(Fragment3, { children: [
|
|
5047
|
+
/* @__PURE__ */ jsx21(Suggestions, { suggestions, onPick: onSuggestion }),
|
|
5048
|
+
/* @__PURE__ */ jsx21(
|
|
5049
|
+
Composer,
|
|
5050
|
+
{
|
|
5051
|
+
options,
|
|
5052
|
+
transport,
|
|
5053
|
+
feedback,
|
|
5054
|
+
bus,
|
|
5055
|
+
isStreaming,
|
|
5056
|
+
onSend,
|
|
5057
|
+
onStop,
|
|
5058
|
+
attachApiRef: composerAttachApiRef
|
|
5059
|
+
}
|
|
5060
|
+
)
|
|
5061
|
+
] });
|
|
5062
|
+
} else {
|
|
5063
|
+
composerArea = /* @__PURE__ */ jsx21(ReadOnlyBanner, { label: s.chatClosed, ctaLabel: s.startNewConversation, onNewChat: onClear });
|
|
5064
|
+
}
|
|
5065
|
+
return /* @__PURE__ */ jsxs16(Fragment3, { children: [
|
|
5066
|
+
view === "history" ? /* @__PURE__ */ jsx21(
|
|
4157
5067
|
HistoryHeader,
|
|
4158
5068
|
{
|
|
4159
5069
|
strings: s,
|
|
@@ -4161,22 +5071,22 @@ function PanelContent(props2) {
|
|
|
4161
5071
|
onClose,
|
|
4162
5072
|
showClose: canShowClose(options.mode, panelSize, options.actions)
|
|
4163
5073
|
}
|
|
4164
|
-
) : /* @__PURE__ */
|
|
4165
|
-
onBack ? /* @__PURE__ */
|
|
5074
|
+
) : /* @__PURE__ */ jsxs16("header", { class: `${p17}-header`, "data-testid": TID.panelHeader, children: [
|
|
5075
|
+
onBack ? /* @__PURE__ */ jsx21(
|
|
4166
5076
|
"button",
|
|
4167
5077
|
{
|
|
4168
5078
|
type: "button",
|
|
4169
|
-
class: `${
|
|
5079
|
+
class: `${p17}-icon-btn`,
|
|
4170
5080
|
onClick: onBack,
|
|
4171
5081
|
"aria-label": s.moduleBack,
|
|
4172
5082
|
title: s.moduleBack,
|
|
4173
|
-
children: /* @__PURE__ */
|
|
5083
|
+
children: /* @__PURE__ */ jsx21(BackIcon, {})
|
|
4174
5084
|
}
|
|
4175
5085
|
) : null,
|
|
4176
|
-
agent ? /* @__PURE__ */
|
|
4177
|
-
/* @__PURE__ */
|
|
5086
|
+
agent ? /* @__PURE__ */ jsx21(AgentBadge, { agent }) : /* @__PURE__ */ jsx21("h1", { children: s.panelTitle }),
|
|
5087
|
+
/* @__PURE__ */ jsx21(HeaderActions, { panelProps: props2, variant: "chat" })
|
|
4178
5088
|
] }),
|
|
4179
|
-
view === "history" ? /* @__PURE__ */
|
|
5089
|
+
view === "history" ? /* @__PURE__ */ jsx21(
|
|
4180
5090
|
ChatHistoryPane,
|
|
4181
5091
|
{
|
|
4182
5092
|
transport,
|
|
@@ -4185,9 +5095,9 @@ function PanelContent(props2) {
|
|
|
4185
5095
|
onSelect: (chat) => onSelectHistoryChat(chat.sessionId),
|
|
4186
5096
|
onNewChat
|
|
4187
5097
|
}
|
|
4188
|
-
) : /* @__PURE__ */
|
|
4189
|
-
/* @__PURE__ */
|
|
4190
|
-
/* @__PURE__ */
|
|
5098
|
+
) : /* @__PURE__ */ jsxs16(Fragment3, { children: [
|
|
5099
|
+
/* @__PURE__ */ jsx21(DropZone, { visible: dragOver, strings: s }),
|
|
5100
|
+
/* @__PURE__ */ jsx21(
|
|
4191
5101
|
MessageList,
|
|
4192
5102
|
{
|
|
4193
5103
|
messagesSig,
|
|
@@ -4195,28 +5105,15 @@ function PanelContent(props2) {
|
|
|
4195
5105
|
responseMode: options.responseMode,
|
|
4196
5106
|
showReasoning: options.showReasoning,
|
|
4197
5107
|
showToolCalls: options.showToolCalls,
|
|
4198
|
-
loading: loadingMessages
|
|
5108
|
+
loading: loadingMessages,
|
|
5109
|
+
idle: !isStreaming,
|
|
5110
|
+
tool
|
|
4199
5111
|
}
|
|
4200
5112
|
),
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
/* @__PURE__ */ jsx17(
|
|
4204
|
-
Composer,
|
|
4205
|
-
{
|
|
4206
|
-
options,
|
|
4207
|
-
transport,
|
|
4208
|
-
feedback,
|
|
4209
|
-
bus,
|
|
4210
|
-
isStreaming,
|
|
4211
|
-
onSend,
|
|
4212
|
-
onStop,
|
|
4213
|
-
attachApiRef: composerAttachApiRef
|
|
4214
|
-
}
|
|
4215
|
-
)
|
|
4216
|
-
] }) : /* @__PURE__ */ jsx17(ReadOnlyBanner, { label: s.chatClosed, ctaLabel: s.startNewConversation, onNewChat: onClear }),
|
|
4217
|
-
/* @__PURE__ */ jsx17(ComposerFooter, { disclaimer: options.composerDisclaimer })
|
|
5113
|
+
composerArea,
|
|
5114
|
+
/* @__PURE__ */ jsx21(ComposerFooter, { disclaimer: options.composerDisclaimer })
|
|
4218
5115
|
] }),
|
|
4219
|
-
options.size.resize?.enabled ? /* @__PURE__ */
|
|
5116
|
+
options.size.resize?.enabled ? /* @__PURE__ */ jsx21(
|
|
4220
5117
|
ResizeGrip,
|
|
4221
5118
|
{
|
|
4222
5119
|
panelEl: containerEl,
|
|
@@ -4235,86 +5132,86 @@ function HistoryHeader({
|
|
|
4235
5132
|
onClose,
|
|
4236
5133
|
showClose
|
|
4237
5134
|
}) {
|
|
4238
|
-
return /* @__PURE__ */
|
|
4239
|
-
/* @__PURE__ */
|
|
5135
|
+
return /* @__PURE__ */ jsxs16("header", { class: `${p17}-header`, children: [
|
|
5136
|
+
/* @__PURE__ */ jsx21(
|
|
4240
5137
|
"button",
|
|
4241
5138
|
{
|
|
4242
5139
|
type: "button",
|
|
4243
|
-
class: `${
|
|
5140
|
+
class: `${p17}-icon-btn`,
|
|
4244
5141
|
onClick: onBack,
|
|
4245
5142
|
"aria-label": strings.historyBack,
|
|
4246
5143
|
title: strings.historyBack,
|
|
4247
|
-
children: /* @__PURE__ */
|
|
5144
|
+
children: /* @__PURE__ */ jsx21(BackIcon, {})
|
|
4248
5145
|
}
|
|
4249
5146
|
),
|
|
4250
|
-
/* @__PURE__ */
|
|
4251
|
-
showClose ? /* @__PURE__ */
|
|
5147
|
+
/* @__PURE__ */ jsx21("h1", { children: strings.historyTitle }),
|
|
5148
|
+
showClose ? /* @__PURE__ */ jsx21(
|
|
4252
5149
|
"button",
|
|
4253
5150
|
{
|
|
4254
5151
|
type: "button",
|
|
4255
|
-
class: `${
|
|
5152
|
+
class: `${p17}-icon-btn`,
|
|
4256
5153
|
onClick: onClose,
|
|
4257
5154
|
"aria-label": strings.close,
|
|
4258
5155
|
title: strings.close,
|
|
4259
|
-
children: /* @__PURE__ */
|
|
5156
|
+
children: /* @__PURE__ */ jsx21(CloseIcon, {})
|
|
4260
5157
|
}
|
|
4261
5158
|
) : null
|
|
4262
5159
|
] });
|
|
4263
5160
|
}
|
|
4264
5161
|
function ReadOnlyBanner({ label, ctaLabel, onNewChat }) {
|
|
4265
|
-
return /* @__PURE__ */
|
|
4266
|
-
/* @__PURE__ */
|
|
4267
|
-
/* @__PURE__ */
|
|
5162
|
+
return /* @__PURE__ */ jsxs16("div", { class: `${p17}-readonly-banner`, role: "note", children: [
|
|
5163
|
+
/* @__PURE__ */ jsx21("span", { class: `${p17}-readonly-label`, children: label }),
|
|
5164
|
+
/* @__PURE__ */ jsx21("button", { type: "button", class: `${p17}-readonly-cta`, onClick: onNewChat, children: ctaLabel })
|
|
4268
5165
|
] });
|
|
4269
5166
|
}
|
|
4270
5167
|
function ComposerFooter({ disclaimer }) {
|
|
4271
5168
|
if (!disclaimer) return null;
|
|
4272
|
-
return /* @__PURE__ */
|
|
5169
|
+
return /* @__PURE__ */ jsx21("div", { class: `${p17}-composer-footer`, children: /* @__PURE__ */ jsx21("div", { class: `${p17}-disclaimer`, children: disclaimer }) });
|
|
4273
5170
|
}
|
|
4274
5171
|
function PoweredByBar({ poweredBy }) {
|
|
4275
5172
|
if (!poweredBy) return null;
|
|
4276
|
-
return /* @__PURE__ */
|
|
5173
|
+
return /* @__PURE__ */ jsx21("div", { class: `${p17}-poweredby-bar`, children: /* @__PURE__ */ jsx21(PoweredBy, { logoUrl: poweredBy.logoUrl, text: poweredBy.text, href: poweredBy.href }) });
|
|
4277
5174
|
}
|
|
4278
5175
|
function PoweredBy({ logoUrl, text, href }) {
|
|
4279
|
-
const inner = /* @__PURE__ */
|
|
4280
|
-
logoUrl ? /* @__PURE__ */
|
|
4281
|
-
text ? /* @__PURE__ */
|
|
5176
|
+
const inner = /* @__PURE__ */ jsxs16(Fragment3, { children: [
|
|
5177
|
+
logoUrl ? /* @__PURE__ */ jsx21("img", { class: `${p17}-poweredby-logo`, src: logoUrl, alt: "", loading: "lazy" }) : null,
|
|
5178
|
+
text ? /* @__PURE__ */ jsx21("span", { children: text }) : null
|
|
4282
5179
|
] });
|
|
4283
5180
|
if (href) {
|
|
4284
|
-
return /* @__PURE__ */
|
|
5181
|
+
return /* @__PURE__ */ jsx21("a", { class: `${p17}-poweredby`, href, target: "_blank", rel: "noopener noreferrer", children: inner });
|
|
4285
5182
|
}
|
|
4286
|
-
return /* @__PURE__ */
|
|
5183
|
+
return /* @__PURE__ */ jsx21("span", { class: `${p17}-poweredby`, children: inner });
|
|
4287
5184
|
}
|
|
4288
5185
|
|
|
4289
5186
|
// src/ui/sidebar.tsx
|
|
4290
|
-
import { Fragment as
|
|
5187
|
+
import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs17 } from "preact/jsx-runtime";
|
|
4291
5188
|
function Sidebar(props2) {
|
|
4292
|
-
const
|
|
5189
|
+
const p33 = BRAND.cssPrefix;
|
|
4293
5190
|
const { site, blocks, strings, collapsed } = props2;
|
|
4294
5191
|
const navigation = blocks?.navigation ?? [];
|
|
4295
5192
|
const linkCards = blocks?.linkCards ?? [];
|
|
4296
5193
|
const toggleLabel = collapsed ? strings.expandSidebar : strings.collapseSidebar;
|
|
4297
|
-
return /* @__PURE__ */
|
|
4298
|
-
/* @__PURE__ */
|
|
4299
|
-
/* @__PURE__ */
|
|
4300
|
-
/* @__PURE__ */
|
|
5194
|
+
return /* @__PURE__ */ jsxs17("aside", { class: `${p33}-sidebar`, "data-collapsed": collapsed ? "true" : "false", "data-testid": TID.sidebar, children: [
|
|
5195
|
+
/* @__PURE__ */ jsxs17("div", { class: `${p33}-sidebar-header`, children: [
|
|
5196
|
+
/* @__PURE__ */ jsx22(SidebarBrand, { site }),
|
|
5197
|
+
/* @__PURE__ */ jsx22(
|
|
4301
5198
|
"button",
|
|
4302
5199
|
{
|
|
4303
5200
|
type: "button",
|
|
4304
|
-
class: `${
|
|
5201
|
+
class: `${p33}-sidebar-toggle`,
|
|
4305
5202
|
"aria-label": toggleLabel,
|
|
4306
5203
|
"aria-expanded": collapsed ? "false" : "true",
|
|
4307
5204
|
title: toggleLabel,
|
|
4308
5205
|
onClick: props2.onToggleCollapsed,
|
|
4309
5206
|
"data-testid": TID.sidebarToggle,
|
|
4310
|
-
children: /* @__PURE__ */
|
|
5207
|
+
children: /* @__PURE__ */ jsx22(SidebarToggleIcon, { collapsed })
|
|
4311
5208
|
}
|
|
4312
5209
|
)
|
|
4313
5210
|
] }),
|
|
4314
|
-
collapsed ? null : /* @__PURE__ */
|
|
4315
|
-
navigation.length > 0 ? /* @__PURE__ */
|
|
4316
|
-
linkCards.length > 0 ? /* @__PURE__ */
|
|
4317
|
-
props2.showConversations ? /* @__PURE__ */
|
|
5211
|
+
collapsed ? null : /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
5212
|
+
navigation.length > 0 ? /* @__PURE__ */ jsx22("nav", { class: `${p33}-sidebar-section`, "data-section": "navigation", children: /* @__PURE__ */ jsx22(SidebarNav, { items: navigation }) }) : null,
|
|
5213
|
+
linkCards.length > 0 ? /* @__PURE__ */ jsx22("div", { class: `${p33}-sidebar-section`, "data-section": "link-cards", children: /* @__PURE__ */ jsx22(SidebarCards, { items: linkCards }) }) : null,
|
|
5214
|
+
props2.showConversations ? /* @__PURE__ */ jsx22("div", { class: `${p33}-sidebar-conversations`, children: /* @__PURE__ */ jsx22(
|
|
4318
5215
|
ConversationList,
|
|
4319
5216
|
{
|
|
4320
5217
|
transport: props2.transport,
|
|
@@ -4328,18 +5225,18 @@ function Sidebar(props2) {
|
|
|
4328
5225
|
] });
|
|
4329
5226
|
}
|
|
4330
5227
|
function SidebarBrand({ site }) {
|
|
4331
|
-
const
|
|
5228
|
+
const p33 = BRAND.cssPrefix;
|
|
4332
5229
|
if (site?.logo?.url) {
|
|
4333
5230
|
const alt = site.logo.alt ?? site.title ?? "Logo";
|
|
4334
|
-
return /* @__PURE__ */
|
|
4335
|
-
site.logoDark?.url ? /* @__PURE__ */
|
|
4336
|
-
/* @__PURE__ */
|
|
5231
|
+
return /* @__PURE__ */ jsxs17("picture", { children: [
|
|
5232
|
+
site.logoDark?.url ? /* @__PURE__ */ jsx22("source", { srcset: site.logoDark.url, media: "(prefers-color-scheme: dark)" }) : null,
|
|
5233
|
+
/* @__PURE__ */ jsx22("img", { class: `${p33}-sidebar-logo`, src: site.logo.url, alt })
|
|
4337
5234
|
] });
|
|
4338
5235
|
}
|
|
4339
|
-
return /* @__PURE__ */
|
|
5236
|
+
return /* @__PURE__ */ jsx22("div", { class: `${p33}-sidebar-title`, children: site?.title ?? BRAND.name });
|
|
4340
5237
|
}
|
|
4341
5238
|
function SidebarToggleIcon({ collapsed }) {
|
|
4342
|
-
return /* @__PURE__ */
|
|
5239
|
+
return /* @__PURE__ */ jsx22(
|
|
4343
5240
|
"svg",
|
|
4344
5241
|
{
|
|
4345
5242
|
width: "16",
|
|
@@ -4349,38 +5246,38 @@ function SidebarToggleIcon({ collapsed }) {
|
|
|
4349
5246
|
stroke: "currentColor",
|
|
4350
5247
|
"stroke-width": "2",
|
|
4351
5248
|
"aria-hidden": "true",
|
|
4352
|
-
children: collapsed ? /* @__PURE__ */
|
|
5249
|
+
children: collapsed ? /* @__PURE__ */ jsx22("polyline", { points: "9 6 15 12 9 18" }) : /* @__PURE__ */ jsx22("polyline", { points: "15 6 9 12 15 18" })
|
|
4353
5250
|
}
|
|
4354
5251
|
);
|
|
4355
5252
|
}
|
|
4356
5253
|
function SidebarNav({ items }) {
|
|
4357
|
-
const
|
|
4358
|
-
return /* @__PURE__ */
|
|
5254
|
+
const p33 = BRAND.cssPrefix;
|
|
5255
|
+
return /* @__PURE__ */ jsx22("ul", { class: `${p33}-sidebar-nav`, children: items.map((item) => /* @__PURE__ */ jsx22("li", { children: /* @__PURE__ */ jsxs17(
|
|
4359
5256
|
"a",
|
|
4360
5257
|
{
|
|
4361
|
-
class: `${
|
|
5258
|
+
class: `${p33}-sidebar-nav-item`,
|
|
4362
5259
|
href: item.href,
|
|
4363
5260
|
target: item.href ? "_blank" : void 0,
|
|
4364
5261
|
rel: item.href ? "noreferrer" : void 0,
|
|
4365
5262
|
children: [
|
|
4366
|
-
item.icon ? /* @__PURE__ */
|
|
4367
|
-
/* @__PURE__ */
|
|
5263
|
+
item.icon ? /* @__PURE__ */ jsx22("span", { class: `${p33}-sidebar-nav-icon`, "data-icon": item.icon }) : null,
|
|
5264
|
+
/* @__PURE__ */ jsx22("span", { class: `${p33}-sidebar-nav-label`, children: item.label })
|
|
4368
5265
|
]
|
|
4369
5266
|
}
|
|
4370
5267
|
) }, item.id ?? item.label)) });
|
|
4371
5268
|
}
|
|
4372
5269
|
function SidebarCards({ items }) {
|
|
4373
|
-
const
|
|
4374
|
-
return /* @__PURE__ */
|
|
5270
|
+
const p33 = BRAND.cssPrefix;
|
|
5271
|
+
return /* @__PURE__ */ jsx22("div", { class: `${p33}-sidebar-cards`, children: items.map((item) => /* @__PURE__ */ jsxs17(
|
|
4375
5272
|
"a",
|
|
4376
5273
|
{
|
|
4377
|
-
class: `${
|
|
5274
|
+
class: `${p33}-sidebar-card`,
|
|
4378
5275
|
href: item.href,
|
|
4379
5276
|
target: item.href ? "_blank" : void 0,
|
|
4380
5277
|
rel: item.href ? "noreferrer" : void 0,
|
|
4381
5278
|
children: [
|
|
4382
|
-
/* @__PURE__ */
|
|
4383
|
-
item.description ? /* @__PURE__ */
|
|
5279
|
+
/* @__PURE__ */ jsx22("div", { class: `${p33}-sidebar-card-label`, children: item.label }),
|
|
5280
|
+
item.description ? /* @__PURE__ */ jsx22("div", { class: `${p33}-sidebar-card-desc`, children: item.description }) : null
|
|
4384
5281
|
]
|
|
4385
5282
|
},
|
|
4386
5283
|
item.id ?? item.label
|
|
@@ -4388,11 +5285,11 @@ function SidebarCards({ items }) {
|
|
|
4388
5285
|
}
|
|
4389
5286
|
|
|
4390
5287
|
// src/ui/page-shell.tsx
|
|
4391
|
-
import { jsx as
|
|
4392
|
-
var
|
|
5288
|
+
import { jsx as jsx23, jsxs as jsxs18 } from "preact/jsx-runtime";
|
|
5289
|
+
var p18 = BRAND.cssPrefix;
|
|
4393
5290
|
function PageShell(props2) {
|
|
4394
|
-
return /* @__PURE__ */
|
|
4395
|
-
/* @__PURE__ */
|
|
5291
|
+
return /* @__PURE__ */ jsxs18("main", { class: `${p18}-page-shell`, "data-sidebar-collapsed": props2.sidebarCollapsed ? "true" : "false", children: [
|
|
5292
|
+
/* @__PURE__ */ jsx23(
|
|
4396
5293
|
Sidebar,
|
|
4397
5294
|
{
|
|
4398
5295
|
site: props2.site,
|
|
@@ -4407,7 +5304,7 @@ function PageShell(props2) {
|
|
|
4407
5304
|
onToggleCollapsed: props2.onToggleSidebarCollapsed
|
|
4408
5305
|
}
|
|
4409
5306
|
),
|
|
4410
|
-
/* @__PURE__ */
|
|
5307
|
+
/* @__PURE__ */ jsx23("section", { class: `${p18}-page-chat`, "aria-label": "Chat", children: props2.children })
|
|
4411
5308
|
] });
|
|
4412
5309
|
}
|
|
4413
5310
|
|
|
@@ -4445,7 +5342,7 @@ var atTabRoot = (s) => activeStack(s).length === 0;
|
|
|
4445
5342
|
|
|
4446
5343
|
// src/ui/messenger-home.tsx
|
|
4447
5344
|
import { useCallback as useCallback4, useEffect as useEffect15, useRef as useRef7 } from "preact/hooks";
|
|
4448
|
-
import { useComputed as
|
|
5345
|
+
import { useComputed as useComputed6 } from "@preact/signals";
|
|
4449
5346
|
|
|
4450
5347
|
// src/ui/modules/messages.tsx
|
|
4451
5348
|
var chatLayout = {
|
|
@@ -4454,83 +5351,83 @@ var chatLayout = {
|
|
|
4454
5351
|
};
|
|
4455
5352
|
|
|
4456
5353
|
// src/ui/modules/help.tsx
|
|
4457
|
-
import { useEffect as useEffect11, useMemo as useMemo2, useState as
|
|
5354
|
+
import { useEffect as useEffect11, useMemo as useMemo2, useState as useState8 } from "preact/hooks";
|
|
4458
5355
|
|
|
4459
5356
|
// src/ui/back-header.tsx
|
|
4460
|
-
import { jsx as
|
|
4461
|
-
var
|
|
5357
|
+
import { jsx as jsx24, jsxs as jsxs19 } from "preact/jsx-runtime";
|
|
5358
|
+
var p19 = BRAND.cssPrefix;
|
|
4462
5359
|
function TitleBar({ title, actions }) {
|
|
4463
|
-
return /* @__PURE__ */
|
|
4464
|
-
/* @__PURE__ */
|
|
4465
|
-
/* @__PURE__ */
|
|
4466
|
-
actions ?? /* @__PURE__ */
|
|
5360
|
+
return /* @__PURE__ */ jsxs19("header", { class: `${p19}-back-header`, "data-variant": "title", children: [
|
|
5361
|
+
/* @__PURE__ */ jsx24("span", { class: `${p19}-back-spacer`, "aria-hidden": "true" }),
|
|
5362
|
+
/* @__PURE__ */ jsx24("h1", { class: `${p19}-back-title`, children: title }),
|
|
5363
|
+
actions ?? /* @__PURE__ */ jsx24("span", { class: `${p19}-back-spacer`, "aria-hidden": "true" })
|
|
4467
5364
|
] });
|
|
4468
5365
|
}
|
|
4469
5366
|
function BackHeader({ title, backLabel, onBack, actions, testid }) {
|
|
4470
|
-
return /* @__PURE__ */
|
|
4471
|
-
/* @__PURE__ */
|
|
4472
|
-
/* @__PURE__ */
|
|
4473
|
-
actions ?? /* @__PURE__ */
|
|
5367
|
+
return /* @__PURE__ */ jsxs19("header", { class: `${p19}-back-header`, "data-testid": testid, children: [
|
|
5368
|
+
/* @__PURE__ */ jsx24("button", { type: "button", class: `${p19}-icon-btn`, onClick: onBack, "aria-label": backLabel, title: backLabel, children: /* @__PURE__ */ jsx24(BackIcon, {}) }),
|
|
5369
|
+
/* @__PURE__ */ jsx24("h1", { class: `${p19}-back-title`, children: title }),
|
|
5370
|
+
actions ?? /* @__PURE__ */ jsx24("span", { class: `${p19}-back-spacer`, "aria-hidden": "true" })
|
|
4474
5371
|
] });
|
|
4475
5372
|
}
|
|
4476
5373
|
|
|
4477
5374
|
// src/ui/home-search.tsx
|
|
4478
|
-
import { jsx as
|
|
4479
|
-
var
|
|
5375
|
+
import { jsx as jsx25, jsxs as jsxs20 } from "preact/jsx-runtime";
|
|
5376
|
+
var p20 = BRAND.cssPrefix;
|
|
4480
5377
|
function HomeSearchButton({ placeholder, onActivate }) {
|
|
4481
|
-
return /* @__PURE__ */
|
|
4482
|
-
/* @__PURE__ */
|
|
4483
|
-
/* @__PURE__ */
|
|
5378
|
+
return /* @__PURE__ */ jsxs20("button", { type: "button", class: `${p20}-home-search`, onClick: onActivate, "data-testid": TID.homeSearch, children: [
|
|
5379
|
+
/* @__PURE__ */ jsx25("span", { class: `${p20}-home-search-text`, children: placeholder }),
|
|
5380
|
+
/* @__PURE__ */ jsx25("span", { class: `${p20}-home-search-icon`, "aria-hidden": "true", children: /* @__PURE__ */ jsx25(SearchIcon, {}) })
|
|
4484
5381
|
] });
|
|
4485
5382
|
}
|
|
4486
5383
|
function HelpSearchInput({ placeholder, value, onInput }) {
|
|
4487
|
-
return /* @__PURE__ */
|
|
4488
|
-
/* @__PURE__ */
|
|
5384
|
+
return /* @__PURE__ */ jsxs20("div", { class: `${p20}-home-search`, "data-input": "true", children: [
|
|
5385
|
+
/* @__PURE__ */ jsx25(
|
|
4489
5386
|
"input",
|
|
4490
5387
|
{
|
|
4491
5388
|
type: "search",
|
|
4492
|
-
class: `${
|
|
5389
|
+
class: `${p20}-home-search-input`,
|
|
4493
5390
|
placeholder,
|
|
4494
5391
|
value,
|
|
4495
5392
|
onInput: (e) => onInput(e.currentTarget.value),
|
|
4496
5393
|
"data-testid": TID.helpSearch
|
|
4497
5394
|
}
|
|
4498
5395
|
),
|
|
4499
|
-
/* @__PURE__ */
|
|
5396
|
+
/* @__PURE__ */ jsx25("span", { class: `${p20}-home-search-icon`, "aria-hidden": "true", children: /* @__PURE__ */ jsx25(SearchIcon, {}) })
|
|
4500
5397
|
] });
|
|
4501
5398
|
}
|
|
4502
5399
|
|
|
4503
5400
|
// src/ui/list-row.tsx
|
|
4504
|
-
import { jsx as
|
|
4505
|
-
var
|
|
5401
|
+
import { jsx as jsx26, jsxs as jsxs21 } from "preact/jsx-runtime";
|
|
5402
|
+
var p21 = BRAND.cssPrefix;
|
|
4506
5403
|
function ListRow({ title, subtitle, onClick, testid }) {
|
|
4507
|
-
return /* @__PURE__ */
|
|
4508
|
-
/* @__PURE__ */
|
|
4509
|
-
/* @__PURE__ */
|
|
4510
|
-
subtitle ? /* @__PURE__ */
|
|
5404
|
+
return /* @__PURE__ */ jsxs21("button", { type: "button", class: `${p21}-list-row`, onClick, "data-testid": testid, children: [
|
|
5405
|
+
/* @__PURE__ */ jsxs21("span", { class: `${p21}-list-row-body`, children: [
|
|
5406
|
+
/* @__PURE__ */ jsx26("span", { class: `${p21}-list-row-title`, children: title }),
|
|
5407
|
+
subtitle ? /* @__PURE__ */ jsx26("span", { class: `${p21}-list-row-sub`, children: subtitle }) : null
|
|
4511
5408
|
] }),
|
|
4512
|
-
/* @__PURE__ */
|
|
5409
|
+
/* @__PURE__ */ jsx26("span", { class: `${p21}-list-row-chevron`, "aria-hidden": "true", children: /* @__PURE__ */ jsx26(ChevronRightIcon, {}) })
|
|
4513
5410
|
] });
|
|
4514
5411
|
}
|
|
4515
5412
|
|
|
4516
5413
|
// src/ui/module-state.tsx
|
|
4517
|
-
import { jsx as
|
|
4518
|
-
var
|
|
5414
|
+
import { jsx as jsx27, jsxs as jsxs22 } from "preact/jsx-runtime";
|
|
5415
|
+
var p22 = BRAND.cssPrefix;
|
|
4519
5416
|
function ModuleState({
|
|
4520
5417
|
tone = "info",
|
|
4521
5418
|
message,
|
|
4522
5419
|
onRetry,
|
|
4523
5420
|
strings
|
|
4524
5421
|
}) {
|
|
4525
|
-
return /* @__PURE__ */
|
|
4526
|
-
/* @__PURE__ */
|
|
4527
|
-
onRetry ? /* @__PURE__ */
|
|
5422
|
+
return /* @__PURE__ */ jsxs22("div", { class: `${p22}-module-empty`, role: tone === "error" ? "alert" : "status", "aria-live": "polite", children: [
|
|
5423
|
+
/* @__PURE__ */ jsx27("span", { children: message }),
|
|
5424
|
+
onRetry ? /* @__PURE__ */ jsx27("button", { type: "button", class: `${p22}-module-retry`, onClick: onRetry, children: strings.errorRetry }) : null
|
|
4528
5425
|
] });
|
|
4529
5426
|
}
|
|
4530
5427
|
|
|
4531
5428
|
// src/ui/modules/help.tsx
|
|
4532
|
-
import { jsx as
|
|
4533
|
-
var
|
|
5429
|
+
import { jsx as jsx28, jsxs as jsxs23 } from "preact/jsx-runtime";
|
|
5430
|
+
var p23 = BRAND.cssPrefix;
|
|
4534
5431
|
var log12 = logger.scope("help");
|
|
4535
5432
|
var openArticle = (nav, a) => a.url ? nav.push({ kind: "iframe", url: a.url, title: a.title }) : nav.push({ kind: "content", id: a.id, title: a.title });
|
|
4536
5433
|
function groupByCategory(items) {
|
|
@@ -4559,7 +5456,7 @@ function fuzzySearch(items, query) {
|
|
|
4559
5456
|
return items.map((item) => ({ item, score: Math.max(fuzzyScore(q, item.title) * 2, fuzzyScore(q, item.description ?? "")) })).filter((r) => r.score > 0).toSorted((a, b) => b.score - a.score).map((r) => r.item);
|
|
4560
5457
|
}
|
|
4561
5458
|
function ArticleRow({ article, nav }) {
|
|
4562
|
-
return /* @__PURE__ */
|
|
5459
|
+
return /* @__PURE__ */ jsx28(
|
|
4563
5460
|
ListRow,
|
|
4564
5461
|
{
|
|
4565
5462
|
title: article.title,
|
|
@@ -4571,11 +5468,11 @@ function ArticleRow({ article, nav }) {
|
|
|
4571
5468
|
}
|
|
4572
5469
|
function HelpRoot({ transport, strings, config, nav, panelProps }) {
|
|
4573
5470
|
const tags = config.contentTags;
|
|
4574
|
-
const [state, setState] =
|
|
4575
|
-
const [errorMsg, setErrorMsg] =
|
|
4576
|
-
const [items, setItems] =
|
|
4577
|
-
const [query, setQuery] =
|
|
4578
|
-
const [reloadKey, setReloadKey] =
|
|
5471
|
+
const [state, setState] = useState8("loading");
|
|
5472
|
+
const [errorMsg, setErrorMsg] = useState8(strings.errorGeneric);
|
|
5473
|
+
const [items, setItems] = useState8([]);
|
|
5474
|
+
const [query, setQuery] = useState8("");
|
|
5475
|
+
const [reloadKey, setReloadKey] = useState8(0);
|
|
4579
5476
|
useEffect11(() => {
|
|
4580
5477
|
let cancelled = false;
|
|
4581
5478
|
setState("loading");
|
|
@@ -4596,46 +5493,46 @@ function HelpRoot({ transport, strings, config, nav, panelProps }) {
|
|
|
4596
5493
|
const results = useMemo2(() => fuzzySearch(items, query), [items, query]);
|
|
4597
5494
|
function renderBody() {
|
|
4598
5495
|
if (query.trim().length > 0) {
|
|
4599
|
-
if (results.length === 0) return /* @__PURE__ */
|
|
4600
|
-
return /* @__PURE__ */
|
|
5496
|
+
if (results.length === 0) return /* @__PURE__ */ jsx28(ModuleState, { message: strings.helpSearchEmpty, strings });
|
|
5497
|
+
return /* @__PURE__ */ jsx28("div", { class: `${p23}-help-card`, children: results.map((a) => /* @__PURE__ */ jsx28(ArticleRow, { article: a, nav }, a.id)) });
|
|
4601
5498
|
}
|
|
4602
|
-
if (state === "loading") return /* @__PURE__ */
|
|
5499
|
+
if (state === "loading") return /* @__PURE__ */ jsx28(ModuleState, { message: strings.helpLoading, strings });
|
|
4603
5500
|
if (state === "error") {
|
|
4604
|
-
return /* @__PURE__ */
|
|
5501
|
+
return /* @__PURE__ */ jsx28(ModuleState, { tone: "error", message: errorMsg, onRetry: () => setReloadKey((k) => k + 1), strings });
|
|
4605
5502
|
}
|
|
4606
|
-
if (items.length === 0) return /* @__PURE__ */
|
|
4607
|
-
return groupByCategory(items).map(([category, rows]) => /* @__PURE__ */
|
|
4608
|
-
category ? /* @__PURE__ */
|
|
4609
|
-
/* @__PURE__ */
|
|
5503
|
+
if (items.length === 0) return /* @__PURE__ */ jsx28(ModuleState, { message: strings.helpEmpty, strings });
|
|
5504
|
+
return groupByCategory(items).map(([category, rows]) => /* @__PURE__ */ jsxs23("section", { class: `${p23}-help-group`, children: [
|
|
5505
|
+
category ? /* @__PURE__ */ jsx28("h2", { class: `${p23}-help-section-title`, children: category }) : null,
|
|
5506
|
+
/* @__PURE__ */ jsx28("div", { class: `${p23}-help-card`, children: rows.map((a) => /* @__PURE__ */ jsx28(ArticleRow, { article: a, nav }, a.id)) })
|
|
4610
5507
|
] }, category));
|
|
4611
5508
|
}
|
|
4612
|
-
return /* @__PURE__ */
|
|
4613
|
-
/* @__PURE__ */
|
|
4614
|
-
/* @__PURE__ */
|
|
4615
|
-
/* @__PURE__ */
|
|
5509
|
+
return /* @__PURE__ */ jsxs23("div", { class: `${p23}-module`, children: [
|
|
5510
|
+
/* @__PURE__ */ jsx28(TitleBar, { title: strings.helpTitle, actions: /* @__PURE__ */ jsx28(HeaderActions, { panelProps, variant: "plain" }) }),
|
|
5511
|
+
/* @__PURE__ */ jsx28("div", { class: `${p23}-module-pad`, children: /* @__PURE__ */ jsx28(HelpSearchInput, { placeholder: strings.helpSearchPlaceholder, value: query, onInput: setQuery }) }),
|
|
5512
|
+
/* @__PURE__ */ jsx28("div", { class: `${p23}-help-list`, children: renderBody() })
|
|
4616
5513
|
] });
|
|
4617
5514
|
}
|
|
4618
5515
|
var helpLayout = {
|
|
4619
5516
|
Icon: HelpIcon,
|
|
4620
|
-
Root: (props2) => /* @__PURE__ */
|
|
5517
|
+
Root: (props2) => /* @__PURE__ */ jsx28(HelpRoot, { ...props2 })
|
|
4621
5518
|
};
|
|
4622
5519
|
|
|
4623
5520
|
// src/ui/modules/home.tsx
|
|
4624
|
-
import { useEffect as useEffect12, useState as
|
|
5521
|
+
import { useEffect as useEffect12, useState as useState9 } from "preact/hooks";
|
|
4625
5522
|
|
|
4626
5523
|
// src/ui/home-card.tsx
|
|
4627
|
-
import { jsx as
|
|
4628
|
-
var
|
|
5524
|
+
import { jsx as jsx29 } from "preact/jsx-runtime";
|
|
5525
|
+
var p24 = BRAND.cssPrefix;
|
|
4629
5526
|
function HomeCard({ onClick, children, testid }) {
|
|
4630
5527
|
if (onClick) {
|
|
4631
|
-
return /* @__PURE__ */
|
|
5528
|
+
return /* @__PURE__ */ jsx29("button", { type: "button", class: `${p24}-home-card`, "data-interactive": "true", onClick, "data-testid": testid, children });
|
|
4632
5529
|
}
|
|
4633
|
-
return /* @__PURE__ */
|
|
5530
|
+
return /* @__PURE__ */ jsx29("div", { class: `${p24}-home-card`, "data-testid": testid, children });
|
|
4634
5531
|
}
|
|
4635
5532
|
|
|
4636
5533
|
// src/ui/modules/home.tsx
|
|
4637
|
-
import { Fragment as
|
|
4638
|
-
var
|
|
5534
|
+
import { Fragment as Fragment5, jsx as jsx30, jsxs as jsxs24 } from "preact/jsx-runtime";
|
|
5535
|
+
var p25 = BRAND.cssPrefix;
|
|
4639
5536
|
var log13 = logger.scope("home");
|
|
4640
5537
|
function resolveGreeting(props2) {
|
|
4641
5538
|
const name = props2.options.userContext?.name;
|
|
@@ -4649,8 +5546,8 @@ function resolveGreeting(props2) {
|
|
|
4649
5546
|
var openContent = (nav, item) => item.url ? nav.push({ kind: "iframe", url: item.url, title: item.title }) : nav.push({ kind: "content", id: item.id, title: item.title });
|
|
4650
5547
|
function HomeRoot(props2) {
|
|
4651
5548
|
const { transport, strings, config, nav, panelProps } = props2;
|
|
4652
|
-
const [recent, setRecent] =
|
|
4653
|
-
const [content, setContent] =
|
|
5549
|
+
const [recent, setRecent] = useState9(null);
|
|
5550
|
+
const [content, setContent] = useState9([]);
|
|
4654
5551
|
const tagsKey = config.contentTags?.join(",");
|
|
4655
5552
|
useEffect12(() => {
|
|
4656
5553
|
if (!config.showRecentMessages) return;
|
|
@@ -4672,49 +5569,49 @@ function HomeRoot(props2) {
|
|
|
4672
5569
|
const avatars = config.userAvatars ?? [];
|
|
4673
5570
|
const status = config.status;
|
|
4674
5571
|
const contentTitle = config.contentBlockTitle ? moduleLabel(strings, config.contentBlockTitle) : strings.homeContentTitle;
|
|
4675
|
-
return /* @__PURE__ */
|
|
4676
|
-
/* @__PURE__ */
|
|
4677
|
-
/* @__PURE__ */
|
|
4678
|
-
config.brandName ? /* @__PURE__ */
|
|
4679
|
-
/* @__PURE__ */
|
|
4680
|
-
avatars.length > 0 ? /* @__PURE__ */
|
|
4681
|
-
/* @__PURE__ */
|
|
5572
|
+
return /* @__PURE__ */ jsx30("div", { class: `${p25}-module ${p25}-home`, "data-testid": TID.homeView, children: /* @__PURE__ */ jsxs24("div", { class: `${p25}-home-scroll`, children: [
|
|
5573
|
+
/* @__PURE__ */ jsxs24("div", { class: `${p25}-home-hero`, children: [
|
|
5574
|
+
/* @__PURE__ */ jsxs24("div", { class: `${p25}-home-hero-top`, children: [
|
|
5575
|
+
config.brandName ? /* @__PURE__ */ jsx30("span", { class: `${p25}-home-brand`, "data-testid": TID.homeBrand, children: config.brandName }) : /* @__PURE__ */ jsx30("span", { class: `${p25}-home-brand-spacer`, "aria-hidden": "true" }),
|
|
5576
|
+
/* @__PURE__ */ jsxs24("div", { class: `${p25}-home-hero-actions`, children: [
|
|
5577
|
+
avatars.length > 0 ? /* @__PURE__ */ jsx30("div", { class: `${p25}-home-avatars`, children: avatars.map((a) => /* @__PURE__ */ jsx30("span", { class: `${p25}-home-avatar`, title: a.role ? `${a.name} \xB7 ${a.role}` : a.name, children: a.avatar ? /* @__PURE__ */ jsx30("img", { src: a.avatar, alt: "", loading: "lazy" }) : /* @__PURE__ */ jsx30("span", { children: initials(a.name) }) }, a.name)) }) : null,
|
|
5578
|
+
/* @__PURE__ */ jsx30(HeaderActions, { panelProps, variant: "plain" })
|
|
4682
5579
|
] })
|
|
4683
5580
|
] }),
|
|
4684
|
-
config.showGreeting !== false ? /* @__PURE__ */
|
|
4685
|
-
/* @__PURE__ */
|
|
4686
|
-
greeting.subtitle ? /* @__PURE__ */
|
|
5581
|
+
config.showGreeting !== false ? /* @__PURE__ */ jsxs24(Fragment5, { children: [
|
|
5582
|
+
/* @__PURE__ */ jsx30("h1", { class: `${p25}-home-greeting`, "data-testid": TID.homeGreeting, children: greeting.title }),
|
|
5583
|
+
greeting.subtitle ? /* @__PURE__ */ jsx30("p", { class: `${p25}-home-lead`, children: greeting.subtitle }) : null
|
|
4687
5584
|
] }) : null
|
|
4688
5585
|
] }),
|
|
4689
|
-
/* @__PURE__ */
|
|
4690
|
-
config.showSearchBar !== false ? /* @__PURE__ */
|
|
5586
|
+
/* @__PURE__ */ jsxs24("div", { class: `${p25}-home-cards`, children: [
|
|
5587
|
+
config.showSearchBar !== false ? /* @__PURE__ */ jsx30(
|
|
4691
5588
|
HomeSearchButton,
|
|
4692
5589
|
{
|
|
4693
5590
|
placeholder: strings.homeSearchPlaceholder,
|
|
4694
5591
|
onActivate: () => nav.switchToLayout("help")
|
|
4695
5592
|
}
|
|
4696
5593
|
) : null,
|
|
4697
|
-
recent ? /* @__PURE__ */
|
|
4698
|
-
/* @__PURE__ */
|
|
4699
|
-
/* @__PURE__ */
|
|
4700
|
-
/* @__PURE__ */
|
|
4701
|
-
recent.preview ? /* @__PURE__ */
|
|
5594
|
+
recent ? /* @__PURE__ */ jsx30(HomeCard, { onClick: () => nav.selectSession(recent.sessionId), testid: TID.homeRecent, children: /* @__PURE__ */ jsxs24("div", { class: `${p25}-home-recent-row`, "data-unread": (recent.unreadCount ?? 0) > 0 ? "true" : void 0, children: [
|
|
5595
|
+
/* @__PURE__ */ jsx30("span", { class: `${p25}-home-recent-avatar`, "aria-hidden": "true", children: /* @__PURE__ */ jsx30(BubblesIcon, {}) }),
|
|
5596
|
+
/* @__PURE__ */ jsxs24("span", { class: `${p25}-home-recent-body`, children: [
|
|
5597
|
+
/* @__PURE__ */ jsx30("span", { class: `${p25}-home-recent-title`, children: recent.title }),
|
|
5598
|
+
recent.preview ? /* @__PURE__ */ jsx30("span", { class: `${p25}-home-recent-preview`, children: recent.preview }) : null
|
|
4702
5599
|
] }),
|
|
4703
|
-
(recent.unreadCount ?? 0) > 0 ? /* @__PURE__ */
|
|
5600
|
+
(recent.unreadCount ?? 0) > 0 ? /* @__PURE__ */ jsx30("span", { class: `${p25}-home-recent-dot`, "aria-label": "Unread" }) : null
|
|
4704
5601
|
] }) }) : null,
|
|
4705
|
-
status ? /* @__PURE__ */
|
|
5602
|
+
status ? /* @__PURE__ */ jsx30(
|
|
4706
5603
|
HomeCard,
|
|
4707
5604
|
{
|
|
4708
5605
|
onClick: status.url ? () => nav.push({ kind: "iframe", url: status.url, title: status.text }) : void 0,
|
|
4709
|
-
children: /* @__PURE__ */
|
|
4710
|
-
/* @__PURE__ */
|
|
4711
|
-
/* @__PURE__ */
|
|
5606
|
+
children: /* @__PURE__ */ jsxs24("div", { class: `${p25}-home-status`, "data-level": status.level ?? "operational", children: [
|
|
5607
|
+
/* @__PURE__ */ jsx30("span", { class: `${p25}-home-status-icon`, "aria-hidden": "true", children: /* @__PURE__ */ jsx30(StatusOkIcon, {}) }),
|
|
5608
|
+
/* @__PURE__ */ jsx30("span", { class: `${p25}-home-status-text`, children: status.text })
|
|
4712
5609
|
] })
|
|
4713
5610
|
}
|
|
4714
5611
|
) : null,
|
|
4715
|
-
content.length > 0 ? /* @__PURE__ */
|
|
4716
|
-
/* @__PURE__ */
|
|
4717
|
-
/* @__PURE__ */
|
|
5612
|
+
content.length > 0 ? /* @__PURE__ */ jsxs24("section", { class: `${p25}-home-content`, children: [
|
|
5613
|
+
/* @__PURE__ */ jsx30("div", { class: `${p25}-home-content-title`, children: contentTitle }),
|
|
5614
|
+
/* @__PURE__ */ jsx30("div", { class: `${p25}-home-content-list`, children: content.map((item) => /* @__PURE__ */ jsx30(
|
|
4718
5615
|
ListRow,
|
|
4719
5616
|
{
|
|
4720
5617
|
title: item.title,
|
|
@@ -4730,20 +5627,20 @@ function HomeRoot(props2) {
|
|
|
4730
5627
|
}
|
|
4731
5628
|
var homeLayout = {
|
|
4732
5629
|
Icon: HomeIcon,
|
|
4733
|
-
Root: (props2) => /* @__PURE__ */
|
|
5630
|
+
Root: (props2) => /* @__PURE__ */ jsx30(HomeRoot, { ...props2 })
|
|
4734
5631
|
};
|
|
4735
5632
|
|
|
4736
5633
|
// src/ui/modules/news.tsx
|
|
4737
|
-
import { useEffect as useEffect13, useState as
|
|
4738
|
-
import { jsx as
|
|
4739
|
-
var
|
|
5634
|
+
import { useEffect as useEffect13, useState as useState10 } from "preact/hooks";
|
|
5635
|
+
import { jsx as jsx31, jsxs as jsxs25 } from "preact/jsx-runtime";
|
|
5636
|
+
var p26 = BRAND.cssPrefix;
|
|
4740
5637
|
var log14 = logger.scope("news");
|
|
4741
5638
|
function NewsRoot({ transport, strings, config, nav, panelProps }) {
|
|
4742
5639
|
const tags = config.contentTags;
|
|
4743
|
-
const [state, setState] =
|
|
4744
|
-
const [errorMsg, setErrorMsg] =
|
|
4745
|
-
const [items, setItems] =
|
|
4746
|
-
const [reloadKey, setReloadKey] =
|
|
5640
|
+
const [state, setState] = useState10("loading");
|
|
5641
|
+
const [errorMsg, setErrorMsg] = useState10(strings.errorGeneric);
|
|
5642
|
+
const [items, setItems] = useState10([]);
|
|
5643
|
+
const [reloadKey, setReloadKey] = useState10(0);
|
|
4747
5644
|
useEffect13(() => {
|
|
4748
5645
|
let cancelled = false;
|
|
4749
5646
|
setState("loading");
|
|
@@ -4762,38 +5659,38 @@ function NewsRoot({ transport, strings, config, nav, panelProps }) {
|
|
|
4762
5659
|
};
|
|
4763
5660
|
}, [transport, tags, reloadKey]);
|
|
4764
5661
|
function renderBody() {
|
|
4765
|
-
if (state === "loading") return /* @__PURE__ */
|
|
5662
|
+
if (state === "loading") return /* @__PURE__ */ jsx31(ModuleState, { message: strings.newsLoading, strings });
|
|
4766
5663
|
if (state === "error") {
|
|
4767
|
-
return /* @__PURE__ */
|
|
5664
|
+
return /* @__PURE__ */ jsx31(ModuleState, { tone: "error", message: errorMsg, onRetry: () => setReloadKey((k) => k + 1), strings });
|
|
4768
5665
|
}
|
|
4769
|
-
if (items.length === 0) return /* @__PURE__ */
|
|
4770
|
-
return /* @__PURE__ */
|
|
5666
|
+
if (items.length === 0) return /* @__PURE__ */ jsx31(ModuleState, { message: strings.newsEmpty, strings });
|
|
5667
|
+
return /* @__PURE__ */ jsx31("div", { class: `${p26}-news-list`, children: items.map((item) => /* @__PURE__ */ jsxs25(
|
|
4771
5668
|
"button",
|
|
4772
5669
|
{
|
|
4773
5670
|
type: "button",
|
|
4774
|
-
class: `${
|
|
5671
|
+
class: `${p26}-news-card`,
|
|
4775
5672
|
onClick: () => nav.push({ kind: "content", id: item.id, title: item.title }),
|
|
4776
5673
|
"data-testid": tid(TID.newsItem, item.id),
|
|
4777
5674
|
children: [
|
|
4778
|
-
item.image ? /* @__PURE__ */
|
|
4779
|
-
/* @__PURE__ */
|
|
4780
|
-
item.tags && item.tags.length > 0 ? /* @__PURE__ */
|
|
4781
|
-
/* @__PURE__ */
|
|
4782
|
-
item.description ? /* @__PURE__ */
|
|
5675
|
+
item.image ? /* @__PURE__ */ jsx31("img", { class: `${p26}-news-hero`, src: item.image, alt: "", loading: "lazy" }) : null,
|
|
5676
|
+
/* @__PURE__ */ jsxs25("span", { class: `${p26}-news-body`, children: [
|
|
5677
|
+
item.tags && item.tags.length > 0 ? /* @__PURE__ */ jsx31("span", { class: `${p26}-news-tags`, children: item.tags.map((t) => /* @__PURE__ */ jsx31("span", { class: `${p26}-news-tag`, children: t }, t)) }) : null,
|
|
5678
|
+
/* @__PURE__ */ jsx31("span", { class: `${p26}-news-title`, children: item.title }),
|
|
5679
|
+
item.description ? /* @__PURE__ */ jsx31("span", { class: `${p26}-news-summary`, children: item.description }) : null
|
|
4783
5680
|
] })
|
|
4784
5681
|
]
|
|
4785
5682
|
},
|
|
4786
5683
|
item.id
|
|
4787
5684
|
)) });
|
|
4788
5685
|
}
|
|
4789
|
-
return /* @__PURE__ */
|
|
4790
|
-
/* @__PURE__ */
|
|
4791
|
-
/* @__PURE__ */
|
|
5686
|
+
return /* @__PURE__ */ jsxs25("div", { class: `${p26}-module`, children: [
|
|
5687
|
+
/* @__PURE__ */ jsx31(TitleBar, { title: strings.newsTitle, actions: /* @__PURE__ */ jsx31(HeaderActions, { panelProps, variant: "plain" }) }),
|
|
5688
|
+
/* @__PURE__ */ jsx31("div", { class: `${p26}-module-scroll`, children: renderBody() })
|
|
4792
5689
|
] });
|
|
4793
5690
|
}
|
|
4794
5691
|
var newsLayout = {
|
|
4795
5692
|
Icon: NewsIcon,
|
|
4796
|
-
Root: (props2) => /* @__PURE__ */
|
|
5693
|
+
Root: (props2) => /* @__PURE__ */ jsx31(NewsRoot, { ...props2 })
|
|
4797
5694
|
};
|
|
4798
5695
|
|
|
4799
5696
|
// src/ui/modules/registry.ts
|
|
@@ -4805,28 +5702,28 @@ var LAYOUTS = {
|
|
|
4805
5702
|
};
|
|
4806
5703
|
|
|
4807
5704
|
// src/ui/home-tab-bar.tsx
|
|
4808
|
-
import { jsx as
|
|
4809
|
-
var
|
|
5705
|
+
import { jsx as jsx32, jsxs as jsxs26 } from "preact/jsx-runtime";
|
|
5706
|
+
var p27 = BRAND.cssPrefix;
|
|
4810
5707
|
function HomeTabBar({ modules, activeTab, strings, unreadCount, onSelect }) {
|
|
4811
|
-
return /* @__PURE__ */
|
|
5708
|
+
return /* @__PURE__ */ jsx32("nav", { class: `${p27}-tabbar`, role: "tablist", "aria-label": strings.panelTitle, children: modules.map((m) => {
|
|
4812
5709
|
const Icon = LAYOUTS[m.layout].Icon;
|
|
4813
5710
|
const selected = m.id === activeTab;
|
|
4814
5711
|
const badge = m.layout === "chat" && unreadCount > 0 ? unreadCount > 9 ? "9+" : String(unreadCount) : null;
|
|
4815
|
-
return /* @__PURE__ */
|
|
5712
|
+
return /* @__PURE__ */ jsxs26(
|
|
4816
5713
|
"button",
|
|
4817
5714
|
{
|
|
4818
5715
|
type: "button",
|
|
4819
5716
|
role: "tab",
|
|
4820
5717
|
"aria-selected": selected,
|
|
4821
|
-
class: `${
|
|
5718
|
+
class: `${p27}-tab`,
|
|
4822
5719
|
onClick: () => onSelect(m.id),
|
|
4823
5720
|
"data-testid": tid(TID.tab, m.id),
|
|
4824
5721
|
children: [
|
|
4825
|
-
/* @__PURE__ */
|
|
4826
|
-
/* @__PURE__ */
|
|
4827
|
-
badge ? /* @__PURE__ */
|
|
5722
|
+
/* @__PURE__ */ jsxs26("span", { class: `${p27}-tab-icon`, "aria-hidden": "true", children: [
|
|
5723
|
+
/* @__PURE__ */ jsx32(Icon, {}),
|
|
5724
|
+
badge ? /* @__PURE__ */ jsx32("span", { class: `${p27}-tab-badge`, "data-testid": TID.tabBadge, children: badge }) : null
|
|
4828
5725
|
] }),
|
|
4829
|
-
/* @__PURE__ */
|
|
5726
|
+
/* @__PURE__ */ jsx32("span", { class: `${p27}-tab-label`, children: moduleLabel(strings, m.label) })
|
|
4830
5727
|
]
|
|
4831
5728
|
},
|
|
4832
5729
|
m.id
|
|
@@ -4835,12 +5732,12 @@ function HomeTabBar({ modules, activeTab, strings, unreadCount, onSelect }) {
|
|
|
4835
5732
|
}
|
|
4836
5733
|
|
|
4837
5734
|
// src/ui/iframe-view.tsx
|
|
4838
|
-
import { jsx as
|
|
4839
|
-
var
|
|
5735
|
+
import { jsx as jsx33, jsxs as jsxs27 } from "preact/jsx-runtime";
|
|
5736
|
+
var p28 = BRAND.cssPrefix;
|
|
4840
5737
|
var SANDBOX = "allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads";
|
|
4841
5738
|
function IframeView({ url, title, strings, onBack, actions }) {
|
|
4842
|
-
return /* @__PURE__ */
|
|
4843
|
-
/* @__PURE__ */
|
|
5739
|
+
return /* @__PURE__ */ jsxs27("div", { class: `${p28}-module`, children: [
|
|
5740
|
+
/* @__PURE__ */ jsx33(
|
|
4844
5741
|
BackHeader,
|
|
4845
5742
|
{
|
|
4846
5743
|
title: title || strings.moduleBack,
|
|
@@ -4849,10 +5746,10 @@ function IframeView({ url, title, strings, onBack, actions }) {
|
|
|
4849
5746
|
actions
|
|
4850
5747
|
}
|
|
4851
5748
|
),
|
|
4852
|
-
/* @__PURE__ */
|
|
5749
|
+
/* @__PURE__ */ jsx33(
|
|
4853
5750
|
"iframe",
|
|
4854
5751
|
{
|
|
4855
|
-
class: `${
|
|
5752
|
+
class: `${p28}-content-frame`,
|
|
4856
5753
|
src: url,
|
|
4857
5754
|
title: title || "content",
|
|
4858
5755
|
sandbox: SANDBOX,
|
|
@@ -4865,14 +5762,14 @@ function IframeView({ url, title, strings, onBack, actions }) {
|
|
|
4865
5762
|
}
|
|
4866
5763
|
|
|
4867
5764
|
// src/ui/content-view.tsx
|
|
4868
|
-
import { useCallback as useCallback3, useEffect as useEffect14, useState as
|
|
4869
|
-
import { jsx as
|
|
4870
|
-
var
|
|
5765
|
+
import { useCallback as useCallback3, useEffect as useEffect14, useState as useState11 } from "preact/hooks";
|
|
5766
|
+
import { jsx as jsx34, jsxs as jsxs28 } from "preact/jsx-runtime";
|
|
5767
|
+
var p29 = BRAND.cssPrefix;
|
|
4871
5768
|
var log15 = logger.scope("content");
|
|
4872
5769
|
function ContentView({ id, title, transport, strings, onBack, actions }) {
|
|
4873
|
-
const [item, setItem] =
|
|
4874
|
-
const [failed, setFailed] =
|
|
4875
|
-
const [reloadKey, setReloadKey] =
|
|
5770
|
+
const [item, setItem] = useState11(null);
|
|
5771
|
+
const [failed, setFailed] = useState11(false);
|
|
5772
|
+
const [reloadKey, setReloadKey] = useState11(0);
|
|
4876
5773
|
const retry = useCallback3(() => {
|
|
4877
5774
|
setFailed(false);
|
|
4878
5775
|
setItem(null);
|
|
@@ -4895,17 +5792,17 @@ function ContentView({ id, title, transport, strings, onBack, actions }) {
|
|
|
4895
5792
|
};
|
|
4896
5793
|
}, [transport, id, reloadKey]);
|
|
4897
5794
|
function renderBody() {
|
|
4898
|
-
if (failed) return /* @__PURE__ */
|
|
4899
|
-
if (item === null) return /* @__PURE__ */
|
|
4900
|
-
return /* @__PURE__ */
|
|
4901
|
-
item.image ? /* @__PURE__ */
|
|
4902
|
-
item.description ? /* @__PURE__ */
|
|
4903
|
-
item.tags && item.tags.length > 0 ? /* @__PURE__ */
|
|
4904
|
-
/* @__PURE__ */
|
|
5795
|
+
if (failed) return /* @__PURE__ */ jsx34(ModuleState, { tone: "error", message: strings.errorGeneric, onRetry: retry, strings });
|
|
5796
|
+
if (item === null) return /* @__PURE__ */ jsx34(ModuleState, { message: strings.contentLoading, strings });
|
|
5797
|
+
return /* @__PURE__ */ jsxs28("article", { class: `${p29}-content`, "data-testid": TID.contentView, children: [
|
|
5798
|
+
item.image ? /* @__PURE__ */ jsx34("img", { class: `${p29}-content-hero`, src: item.image, alt: "", loading: "lazy" }) : null,
|
|
5799
|
+
item.description ? /* @__PURE__ */ jsx34("p", { class: `${p29}-content-subtitle`, children: item.description }) : null,
|
|
5800
|
+
item.tags && item.tags.length > 0 ? /* @__PURE__ */ jsx34("span", { class: `${p29}-news-tags`, children: item.tags.map((t) => /* @__PURE__ */ jsx34("span", { class: `${p29}-news-tag`, children: t }, t)) }) : null,
|
|
5801
|
+
/* @__PURE__ */ jsx34(StaticMarkdown, { text: item.content ?? "" })
|
|
4905
5802
|
] });
|
|
4906
5803
|
}
|
|
4907
|
-
return /* @__PURE__ */
|
|
4908
|
-
/* @__PURE__ */
|
|
5804
|
+
return /* @__PURE__ */ jsxs28("div", { class: `${p29}-module`, children: [
|
|
5805
|
+
/* @__PURE__ */ jsx34(
|
|
4909
5806
|
BackHeader,
|
|
4910
5807
|
{
|
|
4911
5808
|
title: item?.title || title || strings.moduleBack,
|
|
@@ -4915,13 +5812,13 @@ function ContentView({ id, title, transport, strings, onBack, actions }) {
|
|
|
4915
5812
|
testid: TID.backHeader
|
|
4916
5813
|
}
|
|
4917
5814
|
),
|
|
4918
|
-
/* @__PURE__ */
|
|
5815
|
+
/* @__PURE__ */ jsx34("div", { class: `${p29}-module-scroll`, "data-testid": TID.contentScroll, children: renderBody() })
|
|
4919
5816
|
] });
|
|
4920
5817
|
}
|
|
4921
5818
|
|
|
4922
5819
|
// src/ui/messenger-home.tsx
|
|
4923
|
-
import { jsx as
|
|
4924
|
-
var
|
|
5820
|
+
import { jsx as jsx35, jsxs as jsxs29 } from "preact/jsx-runtime";
|
|
5821
|
+
var p30 = BRAND.cssPrefix;
|
|
4925
5822
|
function MessengerHome({
|
|
4926
5823
|
panelProps,
|
|
4927
5824
|
enabledModules,
|
|
@@ -4953,7 +5850,7 @@ function MessengerHome({
|
|
|
4953
5850
|
}, []);
|
|
4954
5851
|
const { visible: dragOver } = useFileDrop({ containerRef, onDrop: onDropItems });
|
|
4955
5852
|
useDragMove(containerRef.current, options.mode === "modal");
|
|
4956
|
-
const navState =
|
|
5853
|
+
const navState = useComputed6(() => nav.sig.value).value;
|
|
4957
5854
|
const top = topScreen(navState);
|
|
4958
5855
|
const activeModule = options.modules.byId[navState.activeTab];
|
|
4959
5856
|
const isReader = top?.kind === "iframe" || top?.kind === "content";
|
|
@@ -4989,12 +5886,12 @@ function MessengerHome({
|
|
|
4989
5886
|
nav: moduleNav,
|
|
4990
5887
|
panelProps
|
|
4991
5888
|
});
|
|
4992
|
-
const plainActions = /* @__PURE__ */
|
|
5889
|
+
const plainActions = /* @__PURE__ */ jsx35(HeaderActions, { panelProps, variant: "plain" });
|
|
4993
5890
|
let body;
|
|
4994
5891
|
if (top?.kind === "iframe") {
|
|
4995
|
-
body = /* @__PURE__ */
|
|
5892
|
+
body = /* @__PURE__ */ jsx35(IframeView, { url: top.url, title: top.title, strings, onBack: nav.pop, actions: plainActions });
|
|
4996
5893
|
} else if (top?.kind === "content") {
|
|
4997
|
-
body = /* @__PURE__ */
|
|
5894
|
+
body = /* @__PURE__ */ jsx35(
|
|
4998
5895
|
ContentView,
|
|
4999
5896
|
{
|
|
5000
5897
|
id: top.id,
|
|
@@ -5006,7 +5903,7 @@ function MessengerHome({
|
|
|
5006
5903
|
}
|
|
5007
5904
|
);
|
|
5008
5905
|
} else if (activeModule?.layout === "chat") {
|
|
5009
|
-
body = /* @__PURE__ */
|
|
5906
|
+
body = /* @__PURE__ */ jsx35(
|
|
5010
5907
|
PanelContent,
|
|
5011
5908
|
{
|
|
5012
5909
|
...panelProps,
|
|
@@ -5017,23 +5914,23 @@ function MessengerHome({
|
|
|
5017
5914
|
);
|
|
5018
5915
|
} else if (activeModule) {
|
|
5019
5916
|
const Root = LAYOUTS[activeModule.layout].Root;
|
|
5020
|
-
body = Root ? /* @__PURE__ */
|
|
5917
|
+
body = Root ? /* @__PURE__ */ jsx35(Root, { ...screenProps(activeModule) }, activeModule.id) : null;
|
|
5021
5918
|
} else {
|
|
5022
5919
|
body = null;
|
|
5023
5920
|
}
|
|
5024
|
-
return /* @__PURE__ */
|
|
5921
|
+
return /* @__PURE__ */ jsxs29(
|
|
5025
5922
|
"div",
|
|
5026
5923
|
{
|
|
5027
5924
|
ref: containerRef,
|
|
5028
|
-
class: `${
|
|
5925
|
+
class: `${p30}-panel ${p30}-messenger`,
|
|
5029
5926
|
role: "dialog",
|
|
5030
5927
|
"aria-modal": "false",
|
|
5031
5928
|
"aria-label": strings.panelTitle,
|
|
5032
5929
|
style: { position: "relative" },
|
|
5033
5930
|
"data-testid": TID.messengerHome,
|
|
5034
5931
|
children: [
|
|
5035
|
-
/* @__PURE__ */
|
|
5036
|
-
showTabBar ? /* @__PURE__ */
|
|
5932
|
+
/* @__PURE__ */ jsx35("div", { class: `${p30}-messenger-body`, children: body }),
|
|
5933
|
+
showTabBar ? /* @__PURE__ */ jsx35(
|
|
5037
5934
|
HomeTabBar,
|
|
5038
5935
|
{
|
|
5039
5936
|
modules: enabledModules,
|
|
@@ -5043,8 +5940,8 @@ function MessengerHome({
|
|
|
5043
5940
|
onSelect: nav.switchTab
|
|
5044
5941
|
}
|
|
5045
5942
|
) : null,
|
|
5046
|
-
/* @__PURE__ */
|
|
5047
|
-
options.size.resize?.enabled && !(activeModule?.layout === "chat" && !top) ? /* @__PURE__ */
|
|
5943
|
+
/* @__PURE__ */ jsx35(PoweredByBar, { poweredBy: options.poweredBy }),
|
|
5944
|
+
options.size.resize?.enabled && !(activeModule?.layout === "chat" && !top) ? /* @__PURE__ */ jsx35(
|
|
5048
5945
|
ResizeGrip,
|
|
5049
5946
|
{
|
|
5050
5947
|
panelEl: containerRef.current,
|
|
@@ -5061,29 +5958,29 @@ function MessengerHome({
|
|
|
5061
5958
|
}
|
|
5062
5959
|
|
|
5063
5960
|
// src/ui/modules-empty.tsx
|
|
5064
|
-
import { jsx as
|
|
5065
|
-
var
|
|
5961
|
+
import { jsx as jsx36, jsxs as jsxs30 } from "preact/jsx-runtime";
|
|
5962
|
+
var p31 = BRAND.cssPrefix;
|
|
5066
5963
|
function ModulesEmpty({ strings, onClose }) {
|
|
5067
|
-
return /* @__PURE__ */
|
|
5964
|
+
return /* @__PURE__ */ jsxs30(
|
|
5068
5965
|
"div",
|
|
5069
5966
|
{
|
|
5070
|
-
class: `${
|
|
5967
|
+
class: `${p31}-panel ${p31}-modules-empty`,
|
|
5071
5968
|
role: "dialog",
|
|
5072
5969
|
"aria-label": strings.panelTitle,
|
|
5073
5970
|
"data-testid": TID.modulesEmpty,
|
|
5074
5971
|
children: [
|
|
5075
|
-
onClose ? /* @__PURE__ */
|
|
5972
|
+
onClose ? /* @__PURE__ */ jsx36(
|
|
5076
5973
|
"button",
|
|
5077
5974
|
{
|
|
5078
5975
|
type: "button",
|
|
5079
|
-
class: `${
|
|
5976
|
+
class: `${p31}-icon-btn ${p31}-modules-empty-close`,
|
|
5080
5977
|
onClick: onClose,
|
|
5081
5978
|
"aria-label": strings.close,
|
|
5082
5979
|
title: strings.close,
|
|
5083
|
-
children: /* @__PURE__ */
|
|
5980
|
+
children: /* @__PURE__ */ jsx36(CloseIcon, {})
|
|
5084
5981
|
}
|
|
5085
5982
|
) : null,
|
|
5086
|
-
/* @__PURE__ */
|
|
5983
|
+
/* @__PURE__ */ jsx36("p", { class: `${p31}-modules-empty-text`, children: strings.modulesEmpty })
|
|
5087
5984
|
]
|
|
5088
5985
|
}
|
|
5089
5986
|
);
|
|
@@ -5138,11 +6035,11 @@ function animateTypewriter(msg, text, charsPerSecond, abort) {
|
|
|
5138
6035
|
}
|
|
5139
6036
|
|
|
5140
6037
|
// src/ui/use-launcher-callout.ts
|
|
5141
|
-
import { useCallback as useCallback5, useEffect as useEffect16, useState as
|
|
6038
|
+
import { useCallback as useCallback5, useEffect as useEffect16, useState as useState12 } from "preact/hooks";
|
|
5142
6039
|
function useLauncherCallout({ callout, persistence }) {
|
|
5143
6040
|
const textKey = callout?.text ?? "";
|
|
5144
6041
|
const persistent = callout?.persistent ?? true;
|
|
5145
|
-
const [dismissed, setDismissed] =
|
|
6042
|
+
const [dismissed, setDismissed] = useState12(() => persistent ? false : persistence.loadCalloutDismissed(textKey));
|
|
5146
6043
|
useEffect16(() => {
|
|
5147
6044
|
setDismissed(persistent ? false : persistence.loadCalloutDismissed(textKey));
|
|
5148
6045
|
}, [textKey, persistent, persistence]);
|
|
@@ -5154,21 +6051,21 @@ function useLauncherCallout({ callout, persistence }) {
|
|
|
5154
6051
|
}
|
|
5155
6052
|
|
|
5156
6053
|
// src/ui/app.tsx
|
|
5157
|
-
import { jsx as
|
|
6054
|
+
import { jsx as jsx37, jsxs as jsxs31 } from "preact/jsx-runtime";
|
|
5158
6055
|
var log16 = logger.scope("app");
|
|
5159
|
-
var
|
|
6056
|
+
var p32 = BRAND.cssPrefix;
|
|
5160
6057
|
function App({ options, hostElement, bus }) {
|
|
5161
|
-
const [persistence] =
|
|
5162
|
-
const [visitorId, setVisitorId] =
|
|
6058
|
+
const [persistence] = useState13(() => createPersistence(options.widgetId, options.storage));
|
|
6059
|
+
const [visitorId, setVisitorId] = useState13(() => persistence.getVisitorId());
|
|
5163
6060
|
const initialSettings = persistence.loadUserPrefs();
|
|
5164
|
-
const [activeLocale, setActiveLocale] =
|
|
5165
|
-
const [activeThemeMode, setActiveThemeMode] =
|
|
6061
|
+
const [activeLocale, setActiveLocale] = useState13(() => initialSettings.locale ?? options.locale);
|
|
6062
|
+
const [activeThemeMode, setActiveThemeMode] = useState13(
|
|
5166
6063
|
() => initialSettings.themeMode ?? options.themeMode
|
|
5167
6064
|
);
|
|
5168
|
-
const sessionIdSig =
|
|
5169
|
-
const messagesSig =
|
|
5170
|
-
const unreadCountSig =
|
|
5171
|
-
const [loadingMessages, setLoadingMessages] =
|
|
6065
|
+
const sessionIdSig = useSignal2(persistence.loadSessionId());
|
|
6066
|
+
const messagesSig = useSignal2([]);
|
|
6067
|
+
const unreadCountSig = useSignal2(0);
|
|
6068
|
+
const [loadingMessages, setLoadingMessages] = useState13(false);
|
|
5172
6069
|
function landingTab() {
|
|
5173
6070
|
const list = options.modules.list;
|
|
5174
6071
|
const ids = new Set(list.map((m) => m.id));
|
|
@@ -5187,14 +6084,14 @@ function App({ options, hostElement, bus }) {
|
|
|
5187
6084
|
const homeNav = homeNavRef.current;
|
|
5188
6085
|
const chatTabIdRef = useRef8(void 0);
|
|
5189
6086
|
chatTabIdRef.current = chatTabId();
|
|
5190
|
-
const [sessionReady, setSessionReady] =
|
|
6087
|
+
const [sessionReady, setSessionReady] = useState13(false);
|
|
5191
6088
|
const isInlineLike = options.mode === "standalone" || options.mode === "inline";
|
|
5192
6089
|
const initialPanelRef = useRef8(
|
|
5193
6090
|
resolveInitialPanelState(options, currentViewportWidth(), persistence.loadPanelOpen(), persistence.loadPanelSize())
|
|
5194
6091
|
);
|
|
5195
|
-
const [isOpen, setIsOpen] =
|
|
6092
|
+
const [isOpen, setIsOpen] = useState13(initialPanelRef.current.panelOpen);
|
|
5196
6093
|
const initialPanelApplied = useRef8(false);
|
|
5197
|
-
const [launcherLeaving, setLauncherLeaving] =
|
|
6094
|
+
const [launcherLeaving, setLauncherLeaving] = useState13(false);
|
|
5198
6095
|
const { dismissed: calloutDismissed, dismissCallout: dismissCalloutRaw } = useLauncherCallout({
|
|
5199
6096
|
callout: options.launcher.callout,
|
|
5200
6097
|
persistence
|
|
@@ -5205,19 +6102,20 @@ function App({ options, hostElement, bus }) {
|
|
|
5205
6102
|
bus.emit("calloutDismiss", void 0);
|
|
5206
6103
|
dismissCalloutRaw();
|
|
5207
6104
|
}, [bus, dismissCalloutRaw]);
|
|
5208
|
-
const [panelSize, setPanelSize] =
|
|
6105
|
+
const [panelSize, setPanelSize] = useState13(initialPanelRef.current.panelSize);
|
|
5209
6106
|
const initialSizeApplied = useRef8(false);
|
|
5210
|
-
const [view, setView] =
|
|
5211
|
-
const [canSend, setCanSend] =
|
|
5212
|
-
const [streaming, setStreaming] =
|
|
5213
|
-
const [agent, setAgent] =
|
|
5214
|
-
const [suggestions, setSuggestions] =
|
|
5215
|
-
const [activeCancel, setActiveCancel] =
|
|
6107
|
+
const [view, setView] = useState13("chat");
|
|
6108
|
+
const [canSend, setCanSend] = useState13(true);
|
|
6109
|
+
const [streaming, setStreaming] = useState13(false);
|
|
6110
|
+
const [agent, setAgent] = useState13(null);
|
|
6111
|
+
const [suggestions, setSuggestions] = useState13([]);
|
|
6112
|
+
const [activeCancel, setActiveCancel] = useState13(null);
|
|
5216
6113
|
const welcomeAbortRef = useRef8(null);
|
|
5217
|
-
const [parsedSite, setParsedSite] =
|
|
5218
|
-
const [parsedBlocks, setParsedBlocks] =
|
|
5219
|
-
const [sidebarCollapsed, setSidebarCollapsed] =
|
|
5220
|
-
const [
|
|
6114
|
+
const [parsedSite, setParsedSite] = useState13(void 0);
|
|
6115
|
+
const [parsedBlocks, setParsedBlocks] = useState13(void 0);
|
|
6116
|
+
const [sidebarCollapsed, setSidebarCollapsed] = useState13(() => persistence.loadSidebarCollapsed() ?? false);
|
|
6117
|
+
const [intakeValues, setIntakeValues] = useState13(() => persistence.loadIntake());
|
|
6118
|
+
const [transport] = useState13(
|
|
5221
6119
|
() => new AgentTransport({
|
|
5222
6120
|
baseUrl: options.baseUrl,
|
|
5223
6121
|
auth: createAuth({
|
|
@@ -5228,8 +6126,8 @@ function App({ options, hostElement, bus }) {
|
|
|
5228
6126
|
endpoints: options.endpoints
|
|
5229
6127
|
})
|
|
5230
6128
|
);
|
|
5231
|
-
const [reducer] =
|
|
5232
|
-
const [feedback] =
|
|
6129
|
+
const [reducer] = useState13(() => new StreamReducer(messagesSig));
|
|
6130
|
+
const [feedback] = useState13(() => new FeedbackBus(options.sound, options.haptics));
|
|
5233
6131
|
const patchAndSync = useCallback6(
|
|
5234
6132
|
(patch) => {
|
|
5235
6133
|
persistence.patchUserPrefs(patch);
|
|
@@ -5399,9 +6297,11 @@ function App({ options, hostElement, bus }) {
|
|
|
5399
6297
|
);
|
|
5400
6298
|
const userSig = JSON.stringify(options.userContext ?? null);
|
|
5401
6299
|
const pageSig = JSON.stringify(options.pageContext ?? null);
|
|
6300
|
+
const intakeSig = JSON.stringify(intakeValues ?? null);
|
|
5402
6301
|
useEffect17(() => {
|
|
5403
|
-
|
|
5404
|
-
|
|
6302
|
+
const merged = intakeValues ? { ...intakeValues, ...options.userContext } : options.userContext;
|
|
6303
|
+
transport.setContext(merged, toWirePageContext(options.pageContext));
|
|
6304
|
+
}, [transport, userSig, pageSig, intakeSig]);
|
|
5405
6305
|
const runResume = useCallback6(
|
|
5406
6306
|
async (handle) => {
|
|
5407
6307
|
let bubble = null;
|
|
@@ -5489,24 +6389,8 @@ function App({ options, hostElement, bus }) {
|
|
|
5489
6389
|
document.addEventListener("keydown", onKey);
|
|
5490
6390
|
return () => document.removeEventListener("keydown", onKey);
|
|
5491
6391
|
}, [isOpen, options.mode]);
|
|
5492
|
-
const
|
|
5493
|
-
async (
|
|
5494
|
-
log16.info("send", { textLen: text.length, attachments: attachments.length, streaming });
|
|
5495
|
-
if (streaming) return;
|
|
5496
|
-
bus.emit("send", { text, attachmentCount: attachments.length });
|
|
5497
|
-
if (suggestions.length > 0) setSuggestions([]);
|
|
5498
|
-
const uploaded = await uploadAttachments(transport, attachments, (err) => {
|
|
5499
|
-
log16.warn("upload failed", { err });
|
|
5500
|
-
bus.emit("error", err);
|
|
5501
|
-
options.onError?.(err);
|
|
5502
|
-
});
|
|
5503
|
-
feedback.unlock();
|
|
5504
|
-
feedback.play("messageSent");
|
|
5505
|
-
const userMsg = makeUserMessage(text, uploaded);
|
|
5506
|
-
const assistantMsg = makeAssistantMessage();
|
|
5507
|
-
messagesSig.value = [...messagesSig.value, userMsg, assistantMsg];
|
|
5508
|
-
reducer.attach(assistantMsg);
|
|
5509
|
-
emitMessage(bus, options, "user", text);
|
|
6392
|
+
const streamAssistant = useCallback6(
|
|
6393
|
+
async (assistantMsg, trigger) => {
|
|
5510
6394
|
const activeSessionId = sessionIdSig.value ?? uuid7();
|
|
5511
6395
|
if (!sessionIdSig.value) {
|
|
5512
6396
|
sessionIdSig.value = activeSessionId;
|
|
@@ -5515,10 +6399,10 @@ function App({ options, hostElement, bus }) {
|
|
|
5515
6399
|
const body = buildSendMessageRequest({
|
|
5516
6400
|
messages: messagesSig.value.slice(0, -1).map(fromReactive),
|
|
5517
6401
|
sessionId: activeSessionId,
|
|
5518
|
-
// textModel + imageModel are backend-only — selected per
|
|
5519
|
-
// deployment in the dashboard, never passed up by the widget.
|
|
6402
|
+
// textModel + imageModel are backend-only — selected per deployment.
|
|
5520
6403
|
tools: options.features.tools,
|
|
5521
6404
|
responseMode: options.responseMode,
|
|
6405
|
+
trigger,
|
|
5522
6406
|
// Identity + preferences ride on every message — server may need
|
|
5523
6407
|
// them to route, persist, or reconcile in-flight.
|
|
5524
6408
|
visitorId,
|
|
@@ -5550,19 +6434,95 @@ function App({ options, hostElement, bus }) {
|
|
|
5550
6434
|
messagesSig.value = [...messagesSig.value];
|
|
5551
6435
|
}
|
|
5552
6436
|
},
|
|
5553
|
-
[
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
6437
|
+
[transport, reducer, messagesSig, sessionIdSig, options, bus, feedback, persistence, visitorId]
|
|
6438
|
+
);
|
|
6439
|
+
const resolveTool = useCallback6(
|
|
6440
|
+
(toolCallId, trigger, mutate) => {
|
|
6441
|
+
if (streaming) return;
|
|
6442
|
+
const last = messagesSig.value.at(-1);
|
|
6443
|
+
const part = last?.partsSig.value.find(
|
|
6444
|
+
(pt) => pt.kind === "tool" && pt.toolCallId === toolCallId
|
|
6445
|
+
);
|
|
6446
|
+
if (!part) {
|
|
6447
|
+
log16.warn("resolveTool: tool part not found", { toolCallId });
|
|
6448
|
+
return;
|
|
6449
|
+
}
|
|
6450
|
+
mutate(part);
|
|
6451
|
+
if (last) last.partsSig.value = [...last.partsSig.value];
|
|
6452
|
+
const assistantMsg = makeAssistantMessage();
|
|
6453
|
+
messagesSig.value = [...messagesSig.value, assistantMsg];
|
|
6454
|
+
reducer.attach(assistantMsg);
|
|
6455
|
+
void streamAssistant(assistantMsg, trigger);
|
|
6456
|
+
},
|
|
6457
|
+
[streaming, messagesSig, reducer, streamAssistant]
|
|
6458
|
+
);
|
|
6459
|
+
const handleToolResult = useCallback6(
|
|
6460
|
+
(toolCallId, output) => {
|
|
6461
|
+
log16.info("toolResult", { toolCallId });
|
|
6462
|
+
bus.emit("toolResult", { toolCallId });
|
|
6463
|
+
resolveTool(toolCallId, TRIGGER.toolResult, (part) => {
|
|
6464
|
+
part.outputSig.value = output;
|
|
6465
|
+
part.stateSig.value = "output";
|
|
6466
|
+
});
|
|
6467
|
+
},
|
|
6468
|
+
[bus, resolveTool]
|
|
6469
|
+
);
|
|
6470
|
+
const handleToolDecision = useCallback6(
|
|
6471
|
+
(toolCallId, approved, reason) => {
|
|
6472
|
+
log16.info("toolDecision", { toolCallId, approved });
|
|
6473
|
+
bus.emit("toolDecision", { toolCallId, approved });
|
|
6474
|
+
resolveTool(toolCallId, TRIGGER.toolApproval, (part) => {
|
|
6475
|
+
const id = part.approvalSig.value?.id ?? toolCallId;
|
|
6476
|
+
part.approvalSig.value = { id, approved, reason };
|
|
6477
|
+
part.stateSig.value = "output";
|
|
6478
|
+
});
|
|
6479
|
+
},
|
|
6480
|
+
[bus, resolveTool]
|
|
6481
|
+
);
|
|
6482
|
+
const toolInteraction = useMemo3(
|
|
6483
|
+
() => ({ humanInLoop: options.features.humanInLoop, onResult: handleToolResult, onDecision: handleToolDecision }),
|
|
6484
|
+
[options.features.humanInLoop, handleToolResult, handleToolDecision]
|
|
6485
|
+
);
|
|
6486
|
+
const intakePending = options.intake.enabled && intakeValues === null;
|
|
6487
|
+
const handleIntakeComplete = useCallback6(
|
|
6488
|
+
(values) => {
|
|
6489
|
+
const hasValues = Object.keys(values).length > 0;
|
|
6490
|
+
log16.info("intakeComplete", { fields: Object.keys(values).length, skipped: !hasValues });
|
|
6491
|
+
persistence.saveIntake(values);
|
|
6492
|
+
setIntakeValues(values);
|
|
6493
|
+
bus.emit("intakeSubmit", values);
|
|
6494
|
+
if (!hasValues) return;
|
|
6495
|
+
const activeSessionId = sessionIdSig.value ?? uuid7();
|
|
6496
|
+
if (!sessionIdSig.value) {
|
|
6497
|
+
sessionIdSig.value = activeSessionId;
|
|
6498
|
+
persistence.saveSessionId(activeSessionId);
|
|
6499
|
+
transport.primeIdentity(void 0, activeSessionId);
|
|
6500
|
+
}
|
|
6501
|
+
void transport.submitIntake(activeSessionId, values);
|
|
6502
|
+
},
|
|
6503
|
+
[persistence, bus, sessionIdSig, transport]
|
|
6504
|
+
);
|
|
6505
|
+
const handleSend = useCallback6(
|
|
6506
|
+
async (text, attachments) => {
|
|
6507
|
+
log16.info("send", { textLen: text.length, attachments: attachments.length, streaming });
|
|
6508
|
+
if (streaming) return;
|
|
6509
|
+
bus.emit("send", { text, attachmentCount: attachments.length });
|
|
6510
|
+
if (suggestions.length > 0) setSuggestions([]);
|
|
6511
|
+
const uploaded = await uploadAttachments(transport, attachments, (err) => {
|
|
6512
|
+
log16.warn("upload failed", { err });
|
|
6513
|
+
bus.emit("error", err);
|
|
6514
|
+
options.onError?.(err);
|
|
6515
|
+
});
|
|
6516
|
+
feedback.unlock();
|
|
6517
|
+
feedback.play("messageSent");
|
|
6518
|
+
const userMsg = makeUserMessage(text, uploaded);
|
|
6519
|
+
const assistantMsg = makeAssistantMessage();
|
|
6520
|
+
messagesSig.value = [...messagesSig.value, userMsg, assistantMsg];
|
|
6521
|
+
reducer.attach(assistantMsg);
|
|
6522
|
+
emitMessage(bus, options, "user", text);
|
|
6523
|
+
await streamAssistant(assistantMsg, TRIGGER.submitMessage);
|
|
6524
|
+
},
|
|
6525
|
+
[streaming, transport, bus, options, suggestions.length, messagesSig, reducer, streamAssistant]
|
|
5566
6526
|
);
|
|
5567
6527
|
const handleStop = useCallback6(() => {
|
|
5568
6528
|
log16.info("stop");
|
|
@@ -5766,7 +6726,10 @@ function App({ options, hostElement, bus }) {
|
|
|
5766
6726
|
log16.info("suggestion", { text });
|
|
5767
6727
|
bus.emit("suggestion", { text });
|
|
5768
6728
|
void handleSend(text, []);
|
|
5769
|
-
}
|
|
6729
|
+
},
|
|
6730
|
+
intakePending,
|
|
6731
|
+
onIntakeComplete: handleIntakeComplete,
|
|
6732
|
+
tool: toolInteraction
|
|
5770
6733
|
};
|
|
5771
6734
|
const onSelectSession = (sessionId) => {
|
|
5772
6735
|
void handleSelectHistoryChat(sessionId);
|
|
@@ -5778,12 +6741,12 @@ function App({ options, hostElement, bus }) {
|
|
|
5778
6741
|
const renderSurface = (size) => {
|
|
5779
6742
|
const closeable = isActionVisible("close", effectiveOptions.mode, size);
|
|
5780
6743
|
if (enabledModules.length === 0) {
|
|
5781
|
-
return /* @__PURE__ */
|
|
6744
|
+
return /* @__PURE__ */ jsx37(ModulesEmpty, { strings: effectiveOptions.strings, onClose: closeable ? handleClose : void 0 });
|
|
5782
6745
|
}
|
|
5783
6746
|
if (enabledModules.length === 1 && enabledModules[0]?.layout === "chat") {
|
|
5784
|
-
return /* @__PURE__ */
|
|
6747
|
+
return /* @__PURE__ */ jsx37(Panel, { ...panelProps, panelSize: size });
|
|
5785
6748
|
}
|
|
5786
|
-
return /* @__PURE__ */
|
|
6749
|
+
return /* @__PURE__ */ jsx37(
|
|
5787
6750
|
MessengerHome,
|
|
5788
6751
|
{
|
|
5789
6752
|
panelProps: { ...panelProps, panelSize: size, onClose: closeable ? handleClose : void 0 },
|
|
@@ -5801,7 +6764,7 @@ function App({ options, hostElement, bus }) {
|
|
|
5801
6764
|
void handleSelectHistoryChat(chat.sessionId);
|
|
5802
6765
|
};
|
|
5803
6766
|
const messagesEnabled = enabledModules.some((m) => m.layout === "chat");
|
|
5804
|
-
return /* @__PURE__ */
|
|
6767
|
+
return /* @__PURE__ */ jsx37("div", { class: `${p32}-anchor`, children: /* @__PURE__ */ jsx37(
|
|
5805
6768
|
PageShell,
|
|
5806
6769
|
{
|
|
5807
6770
|
site: parsedSite,
|
|
@@ -5820,15 +6783,15 @@ function App({ options, hostElement, bus }) {
|
|
|
5820
6783
|
}
|
|
5821
6784
|
if (isInlineLike) {
|
|
5822
6785
|
const inlineSize = options.mode === "standalone" ? "fullscreen" : panelSize;
|
|
5823
|
-
return /* @__PURE__ */
|
|
6786
|
+
return /* @__PURE__ */ jsx37("div", { class: `${p32}-anchor`, children: renderSurface(inlineSize) });
|
|
5824
6787
|
}
|
|
5825
6788
|
const drawerEdgeTab = options.mode === "drawer";
|
|
5826
6789
|
const triggerOwnedByPage = options.mode === "modal";
|
|
5827
6790
|
const launcherVisible = !triggerOwnedByPage && !options.launcher.hidden && (!isOpen || launcherLeaving);
|
|
5828
6791
|
const calloutToRender = launcherVisible && !launcherLeaving && !calloutDismissed && !drawerEdgeTab ? effectiveOptions.launcher.callout : null;
|
|
5829
|
-
return /* @__PURE__ */
|
|
6792
|
+
return /* @__PURE__ */ jsxs31("div", { class: `${p32}-anchor`, "data-launcher-size": effectiveOptions.launcher.size, children: [
|
|
5830
6793
|
isOpen ? renderSurface(panelSize) : null,
|
|
5831
|
-
launcherVisible ? /* @__PURE__ */
|
|
6794
|
+
launcherVisible ? /* @__PURE__ */ jsx37(
|
|
5832
6795
|
Launcher,
|
|
5833
6796
|
{
|
|
5834
6797
|
onToggle: handleOpen,
|
|
@@ -5838,7 +6801,7 @@ function App({ options, hostElement, bus }) {
|
|
|
5838
6801
|
edgeTab: drawerEdgeTab
|
|
5839
6802
|
}
|
|
5840
6803
|
) : null,
|
|
5841
|
-
calloutToRender ? /* @__PURE__ */
|
|
6804
|
+
calloutToRender ? /* @__PURE__ */ jsx37(
|
|
5842
6805
|
LauncherCallout,
|
|
5843
6806
|
{
|
|
5844
6807
|
callout: calloutToRender,
|