@elevasis/ui 2.52.1 → 2.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -126,6 +126,22 @@ interface PublicAgentChatConnectionState {
|
|
|
126
126
|
error: string | null;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Context passed to the `renderIntro` render-prop. Provides the start action,
|
|
131
|
+
* loading state, resolved display strings, raw branding, and the agent slug.
|
|
132
|
+
*/
|
|
133
|
+
interface PublicAgentIntroRenderContext {
|
|
134
|
+
/** Begins the authorize → session flow (the same action the default CTA runs). */
|
|
135
|
+
start: () => void;
|
|
136
|
+
/** True while a session is being created — disable the button / show a spinner. */
|
|
137
|
+
starting: boolean;
|
|
138
|
+
/** Resolved display strings (prop/branding-derived), provided for convenience. */
|
|
139
|
+
title: string;
|
|
140
|
+
subtitle?: string;
|
|
141
|
+
/** Raw grant branding record, so a custom intro can still read intro/instructions/etc. if it wants. */
|
|
142
|
+
branding: Record<string, unknown>;
|
|
143
|
+
slug: string;
|
|
144
|
+
}
|
|
129
145
|
interface PublicAgentChatProps {
|
|
130
146
|
apiUrl: string;
|
|
131
147
|
slug: string;
|
|
@@ -142,8 +158,16 @@ interface PublicAgentChatProps {
|
|
|
142
158
|
* a specific public agent.
|
|
143
159
|
*/
|
|
144
160
|
showAgentActivity?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Render the entire pre-session intro screen yourself. When provided, this fully
|
|
163
|
+
* replaces the default branding-driven intro panel (paragraph + instructions + CTA).
|
|
164
|
+
* Compose any header/headline, body, styled callouts (e.g. a yellow Alert), and one or
|
|
165
|
+
* more buttons; wire your button(s) to `ctx.start()`. When omitted, the default
|
|
166
|
+
* branding-driven intro renders unchanged.
|
|
167
|
+
*/
|
|
168
|
+
renderIntro?: (ctx: PublicAgentIntroRenderContext) => React.ReactNode;
|
|
145
169
|
}
|
|
146
|
-
declare function PublicAgentChat({ apiUrl, slug, visitorId, metadata, title, className, style, onSessionReady, showAgentActivity }: PublicAgentChatProps): react_jsx_runtime.JSX.Element;
|
|
170
|
+
declare function PublicAgentChat({ apiUrl, slug, visitorId, metadata, title, className, style, onSessionReady, showAgentActivity, renderIntro }: PublicAgentChatProps): react_jsx_runtime.JSX.Element;
|
|
147
171
|
|
|
148
172
|
interface PublicAgentChatRoutePageProps extends PublicAgentChatProps {
|
|
149
173
|
pageStyle?: React.CSSProperties;
|
|
@@ -172,4 +196,4 @@ declare const publicAgentChatKeys: {
|
|
|
172
196
|
};
|
|
173
197
|
|
|
174
198
|
export { PublicAgentChat, PublicAgentChatRoutePage, publicAgentChatKeys, usePublicAgentChatMessages, usePublicAgentChatWebSocket };
|
|
175
|
-
export type { PublicAgentChatAuthorizeResponse, PublicAgentChatConnectionState, PublicAgentChatGrant, PublicAgentChatMessagesResponse, PublicAgentChatMetadataResponse, PublicAgentChatProps, PublicAgentChatRoutePageProps, PublicAgentChatSessionResponse };
|
|
199
|
+
export type { PublicAgentChatAuthorizeResponse, PublicAgentChatConnectionState, PublicAgentChatGrant, PublicAgentChatMessagesResponse, PublicAgentChatMetadataResponse, PublicAgentChatProps, PublicAgentChatRoutePageProps, PublicAgentChatSessionResponse, PublicAgentIntroRenderContext };
|
|
@@ -3,7 +3,7 @@ import { ChatInterface } from '../../chunk-E6NSKXYN.js';
|
|
|
3
3
|
import { WS_MAX_RETRIES_BEFORE_ERROR, WS_RECONNECT_BASE_DELAY, WS_RECONNECT_MAX_DELAY, validateTokenLimit, TOKEN_LIMITS } from '../../chunk-FVOMKZ7S.js';
|
|
4
4
|
import '../../chunk-TVTSASST.js';
|
|
5
5
|
import '../../chunk-I2KLQ2HA.js';
|
|
6
|
-
import { Center, Loader, Paper, Stack, Group, Title, Alert, PasswordInput, Button, Text, Box, Badge, Divider } from '@mantine/core';
|
|
6
|
+
import { Center, Loader, Paper, Stack, Group, Title, Alert, PasswordInput, Button, Text, List, Box, Badge, Divider } from '@mantine/core';
|
|
7
7
|
import { IconLock, IconAlertCircle, IconSend, IconMessageCircle } from '@tabler/icons-react';
|
|
8
8
|
import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
|
|
9
9
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
@@ -200,7 +200,14 @@ function usePublicAgentChatWebSocket(sessionId, apiUrl, capabilityToken) {
|
|
|
200
200
|
async function fetchJson(url, init) {
|
|
201
201
|
const response = await fetch(url, init);
|
|
202
202
|
if (!response.ok) {
|
|
203
|
-
|
|
203
|
+
let message = `Request failed with status ${response.status}`;
|
|
204
|
+
try {
|
|
205
|
+
const body = await response.json();
|
|
206
|
+
const apiMessage = typeof body.error === "string" && body.error.trim().length > 0 ? body.error : typeof body.message === "string" && body.message.trim().length > 0 ? body.message : null;
|
|
207
|
+
if (apiMessage) message = apiMessage;
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
throw new Error(message);
|
|
204
211
|
}
|
|
205
212
|
return await response.json();
|
|
206
213
|
}
|
|
@@ -221,6 +228,12 @@ function resolveAgentSubtitle(grant) {
|
|
|
221
228
|
const branding = brandingRecord(grant?.branding);
|
|
222
229
|
return brandingText(branding.subtitle) ?? brandingText(branding.description);
|
|
223
230
|
}
|
|
231
|
+
function hasIntroContent(grant) {
|
|
232
|
+
const branding = brandingRecord(grant?.branding);
|
|
233
|
+
const hasIntroText = brandingText(branding.intro) !== void 0;
|
|
234
|
+
const hasInstructions = Array.isArray(branding.instructions) && branding.instructions.length > 0;
|
|
235
|
+
return hasIntroText || hasInstructions;
|
|
236
|
+
}
|
|
224
237
|
function statusStyles(tone) {
|
|
225
238
|
if (tone === "ready") {
|
|
226
239
|
return {
|
|
@@ -373,7 +386,8 @@ function PublicAgentChat({
|
|
|
373
386
|
className,
|
|
374
387
|
style,
|
|
375
388
|
onSessionReady,
|
|
376
|
-
showAgentActivity = false
|
|
389
|
+
showAgentActivity = false,
|
|
390
|
+
renderIntro
|
|
377
391
|
}) {
|
|
378
392
|
const [grant, setGrant] = useState(null);
|
|
379
393
|
const [capabilityToken, setCapabilityToken] = useState(null);
|
|
@@ -383,6 +397,7 @@ function PublicAgentChat({
|
|
|
383
397
|
const [accessCode, setAccessCode] = useState("");
|
|
384
398
|
const [input, setInput] = useState("");
|
|
385
399
|
const autoStartedRef = useRef(false);
|
|
400
|
+
const greetingTimeRef = useRef(/* @__PURE__ */ new Date());
|
|
386
401
|
const displayTitle = resolveAgentTitle(title, slug, grant);
|
|
387
402
|
const displaySubtitle = resolveAgentSubtitle(grant);
|
|
388
403
|
const { data: historyMessages = [] } = usePublicAgentChatMessages(apiUrl, session?.sessionId ?? null, capabilityToken);
|
|
@@ -403,7 +418,13 @@ function PublicAgentChat({
|
|
|
403
418
|
fetchJson(`${apiUrl}/api/public/agent-chat/${encodeURIComponent(slug)}`).then((payload) => {
|
|
404
419
|
if (cancelled) return;
|
|
405
420
|
setGrant(payload.grant);
|
|
406
|
-
|
|
421
|
+
if (payload.grant.requiresCode) {
|
|
422
|
+
setStatus("code-required");
|
|
423
|
+
} else if (renderIntro || hasIntroContent(payload.grant)) {
|
|
424
|
+
setStatus("intro");
|
|
425
|
+
} else {
|
|
426
|
+
setStatus("authorizing");
|
|
427
|
+
}
|
|
407
428
|
}).catch((requestError) => {
|
|
408
429
|
if (cancelled) return;
|
|
409
430
|
setError(requestError instanceof Error ? requestError.message : "Unable to load agent chat");
|
|
@@ -412,7 +433,7 @@ function PublicAgentChat({
|
|
|
412
433
|
return () => {
|
|
413
434
|
cancelled = true;
|
|
414
435
|
};
|
|
415
|
-
}, [apiUrl, slug]);
|
|
436
|
+
}, [apiUrl, slug, renderIntro]);
|
|
416
437
|
const startSession = useCallback(
|
|
417
438
|
async (code) => {
|
|
418
439
|
if (!grant) return;
|
|
@@ -454,23 +475,34 @@ function PublicAgentChat({
|
|
|
454
475
|
[apiUrl, grant, metadata, onSessionReady, slug, visitorId]
|
|
455
476
|
);
|
|
456
477
|
useEffect(() => {
|
|
457
|
-
if (!grant || grant.requiresCode || autoStartedRef.current) {
|
|
478
|
+
if (!grant || grant.requiresCode || renderIntro || hasIntroContent(grant) || autoStartedRef.current) {
|
|
458
479
|
return;
|
|
459
480
|
}
|
|
460
481
|
autoStartedRef.current = true;
|
|
461
482
|
void startSession();
|
|
462
|
-
}, [grant, startSession]);
|
|
463
|
-
const allMessages = useMemo(
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
483
|
+
}, [grant, startSession, renderIntro]);
|
|
484
|
+
const allMessages = useMemo(() => {
|
|
485
|
+
const merged = mergeSessionMessages(historyMessages, liveMessages);
|
|
486
|
+
const greeting = brandingText(brandingRecord(grant?.branding).greeting);
|
|
487
|
+
if (!greeting) return merged;
|
|
488
|
+
const greetingMessage = {
|
|
489
|
+
id: "greeting-bubble",
|
|
490
|
+
role: "assistant",
|
|
491
|
+
messageType: "assistant_message",
|
|
492
|
+
text: greeting,
|
|
493
|
+
turnNumber: 0,
|
|
494
|
+
messageIndex: -1,
|
|
495
|
+
createdAt: greetingTimeRef.current
|
|
496
|
+
};
|
|
497
|
+
return [greetingMessage, ...merged];
|
|
498
|
+
}, [historyMessages, liveMessages, grant]);
|
|
467
499
|
const handleSend = () => {
|
|
468
500
|
const trimmed = input.trim();
|
|
469
501
|
if (!trimmed || state.isProcessing) return;
|
|
470
502
|
sendMessage(trimmed);
|
|
471
503
|
setInput("");
|
|
472
504
|
};
|
|
473
|
-
if (status === "loading" || status === "authorizing") {
|
|
505
|
+
if (status === "loading" || status === "authorizing" && !renderIntro) {
|
|
474
506
|
return /* @__PURE__ */ jsx(
|
|
475
507
|
PublicAgentChatFrame,
|
|
476
508
|
{
|
|
@@ -536,6 +568,75 @@ function PublicAgentChat({
|
|
|
536
568
|
}
|
|
537
569
|
);
|
|
538
570
|
}
|
|
571
|
+
if ((status === "intro" || renderIntro && status === "authorizing") && grant) {
|
|
572
|
+
const branding = brandingRecord(grant.branding);
|
|
573
|
+
if (renderIntro) {
|
|
574
|
+
const ctx = {
|
|
575
|
+
start: () => {
|
|
576
|
+
void startSession();
|
|
577
|
+
},
|
|
578
|
+
starting: status === "authorizing",
|
|
579
|
+
title: displayTitle,
|
|
580
|
+
subtitle: displaySubtitle,
|
|
581
|
+
branding,
|
|
582
|
+
slug
|
|
583
|
+
};
|
|
584
|
+
return /* @__PURE__ */ jsx(
|
|
585
|
+
PublicAgentChatFrame,
|
|
586
|
+
{
|
|
587
|
+
className,
|
|
588
|
+
style,
|
|
589
|
+
title: displayTitle,
|
|
590
|
+
subtitle: displaySubtitle,
|
|
591
|
+
statusTone: "ready",
|
|
592
|
+
children: renderIntro(ctx)
|
|
593
|
+
}
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
const headlineText = brandingText(branding.headline);
|
|
597
|
+
const introText = brandingText(branding.intro);
|
|
598
|
+
const instructions = Array.isArray(branding.instructions) ? branding.instructions.filter((item) => typeof item === "string") : [];
|
|
599
|
+
const ctaLabel = brandingText(branding.ctaLabel) ?? "Start the conversation";
|
|
600
|
+
return /* @__PURE__ */ jsx(
|
|
601
|
+
PublicAgentChatFrame,
|
|
602
|
+
{
|
|
603
|
+
className,
|
|
604
|
+
style,
|
|
605
|
+
title: displayTitle,
|
|
606
|
+
subtitle: displaySubtitle,
|
|
607
|
+
statusTone: "ready",
|
|
608
|
+
children: /* @__PURE__ */ jsx(Center, { style: { height: "100%", padding: 16 }, children: /* @__PURE__ */ jsx(
|
|
609
|
+
Paper,
|
|
610
|
+
{
|
|
611
|
+
withBorder: true,
|
|
612
|
+
p: "xl",
|
|
613
|
+
radius: 8,
|
|
614
|
+
style: {
|
|
615
|
+
width: "min(100%, 480px)",
|
|
616
|
+
background: "var(--color-surface)",
|
|
617
|
+
borderColor: "var(--color-border)",
|
|
618
|
+
boxShadow: "var(--card-shadow)"
|
|
619
|
+
},
|
|
620
|
+
children: /* @__PURE__ */ jsxs(Stack, { gap: "lg", children: [
|
|
621
|
+
headlineText && /* @__PURE__ */ jsx(Title, { order: 2, children: headlineText }),
|
|
622
|
+
introText && /* @__PURE__ */ jsx(Text, { size: "sm", style: { color: "var(--color-text)", lineHeight: 1.6 }, children: introText }),
|
|
623
|
+
instructions.length > 0 && /* @__PURE__ */ jsx(List, { size: "sm", style: { color: "var(--color-text-dimmed)" }, children: instructions.map((item, index) => /* @__PURE__ */ jsx(List.Item, { children: item }, index)) }),
|
|
624
|
+
/* @__PURE__ */ jsx(
|
|
625
|
+
Button,
|
|
626
|
+
{
|
|
627
|
+
onClick: () => {
|
|
628
|
+
void startSession();
|
|
629
|
+
},
|
|
630
|
+
leftSection: /* @__PURE__ */ jsx(IconSend, { size: 16 }),
|
|
631
|
+
children: ctaLabel
|
|
632
|
+
}
|
|
633
|
+
)
|
|
634
|
+
] })
|
|
635
|
+
}
|
|
636
|
+
) })
|
|
637
|
+
}
|
|
638
|
+
);
|
|
639
|
+
}
|
|
539
640
|
if (status === "error") {
|
|
540
641
|
return /* @__PURE__ */ jsx(
|
|
541
642
|
PublicAgentChatFrame,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elevasis/ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.54.0",
|
|
4
4
|
"description": "UI components and platform-aware hooks for building custom frontends on the Elevasis platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -274,11 +274,11 @@
|
|
|
274
274
|
"typescript": "5.9.2",
|
|
275
275
|
"vite": "^7.0.0",
|
|
276
276
|
"vitest": "^3.2.4",
|
|
277
|
-
"@elevasis/sdk": "1.36.
|
|
278
|
-
"@repo/core": "0.
|
|
277
|
+
"@elevasis/sdk": "1.36.4",
|
|
278
|
+
"@repo/core": "0.51.0",
|
|
279
|
+
"@repo/typescript-config": "0.0.0",
|
|
279
280
|
"@repo/elevasis-core": "1.0.0",
|
|
280
|
-
"@repo/eslint-config": "0.0.0"
|
|
281
|
-
"@repo/typescript-config": "0.0.0"
|
|
281
|
+
"@repo/eslint-config": "0.0.0"
|
|
282
282
|
},
|
|
283
283
|
"dependencies": {
|
|
284
284
|
"@dagrejs/dagre": "^1.1.4",
|