@iota-uz/sdk 0.4.23 → 0.4.25

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.
@@ -2,7 +2,7 @@ import React, { createContext, memo, useRef, useEffect, useCallback, useState, u
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import ReactApexChart from 'react-apexcharts';
4
4
  import ApexCharts from 'apexcharts';
5
- import { CaretUp, CaretDown, DotsThreeVertical, Check, Copy, X, Columns, ArrowsIn, ArrowsOut, Warning, ArrowClockwise, Paperclip, PaperPlaneRight, ChartBar, FileText, Lightbulb, CircleNotch, ArrowUUpLeft, PencilSimple, Bookmark, ArrowsClockwise, Archive, Trash, DotsThree, Image, MagnifyingGlass, DownloadSimple, ArrowCounterClockwise, Bug, ArrowUp, ArrowDown, Stack, ImageBroken, CaretLeft, CaretRight, Info, CheckCircle, XCircle, Spinner, WarningCircle, FilePdf, FileXls, FileCsv, FileDoc, FileCode, File as File$1, MagnifyingGlassMinus, MagnifyingGlassPlus, Download, ChatCircleDots, PencilSimpleLine, ArrowLeft, PaperPlaneTilt, ArrowRight, Timer, Lightning, Database, ArrowSquareOut, Wrench, ClockCounterClockwise, Package, Plus, ArrowsCounterClockwise, ChatCircle, Gear, Users, List, CaretLineLeft, CaretLineRight, Code, Table, SpinnerGap, FloppyDisk, Sidebar } from '@phosphor-icons/react';
5
+ import { CaretUp, CaretDown, DotsThreeVertical, Check, Copy, X, Columns, ArrowsIn, ArrowsOut, Warning, ArrowClockwise, Paperclip, PaperPlaneRight, ChartBar, FileText, Lightbulb, CircleNotch, ArrowUUpLeft, PencilSimple, Bookmark, ArrowsClockwise, Archive, Trash, UsersThree, DotsThree, Image, MagnifyingGlass, DownloadSimple, ArrowCounterClockwise, Bug, ArrowUp, ArrowDown, Stack, ImageBroken, CaretLeft, CaretRight, Info, CheckCircle, XCircle, Spinner, WarningCircle, FilePdf, FileXls, FileCsv, FileDoc, FileCode, File as File$1, MagnifyingGlassMinus, MagnifyingGlassPlus, Download, ChatCircleDots, PencilSimpleLine, ArrowLeft, PaperPlaneTilt, ArrowRight, Timer, Lightning, Database, ArrowSquareOut, Wrench, ClockCounterClockwise, Package, Plus, Crown, UserPlus, ArrowsCounterClockwise, ChatCircle, Gear, Users, List, CaretLineLeft, CaretLineRight, Code, Table, SpinnerGap, FloppyDisk, ShareNetwork, Sidebar } from '@phosphor-icons/react';
6
6
  import { Prism } from 'react-syntax-highlighter';
7
7
  import { vscDarkPlus, vs } from 'react-syntax-highlighter/dist/esm/styles/prism';
8
8
  import ReactMarkdown from 'react-markdown';
@@ -12,7 +12,7 @@ import rehypeKatex from 'rehype-katex';
12
12
  import { motion, useMotionValue, useTransform, AnimatePresence, MotionConfig, useReducedMotion } from 'framer-motion';
13
13
  import 'react-dom/client';
14
14
  import { differenceInMinutes, differenceInHours, differenceInDays, format, isSameDay, startOfDay, isToday, isYesterday } from 'date-fns';
15
- import { Menu, MenuButton, MenuItems, MenuItem, Popover, PopoverButton, PopoverPanel, Dialog, DialogBackdrop, DialogPanel, DialogTitle, Description, Transition } from '@headlessui/react';
15
+ import { Menu, MenuButton, MenuItems, MenuItem, Popover, PopoverButton, PopoverPanel, Dialog, DialogBackdrop, DialogPanel, Transition } from '@headlessui/react';
16
16
  import { createPortal } from 'react-dom';
17
17
 
18
18
  var __defProp = Object.defineProperty;
@@ -2442,6 +2442,33 @@ var ChatMachine = class {
2442
2442
  });
2443
2443
  }
2444
2444
  }
2445
+ async _resumeAcceptedRunOrPoll(sessionId, runId) {
2446
+ setRunMarker(sessionId, runId);
2447
+ try {
2448
+ await this._runResumeStream(sessionId, runId);
2449
+ } catch (err) {
2450
+ if (this.disposed) {
2451
+ return;
2452
+ }
2453
+ console.warn("[ChatMachine] resumeStream failed, switching to status polling fallback:", err);
2454
+ const getStreamStatus2 = this.dataSource.getStreamStatus;
2455
+ const status = getStreamStatus2 ? await getStreamStatus2(sessionId).catch(() => null) : null;
2456
+ if (!status?.active) {
2457
+ clearRunMarker(sessionId);
2458
+ await this._syncSessionFromServer(sessionId, true).catch(() => {
2459
+ });
2460
+ this._updateMessaging({ generationInProgress: false });
2461
+ return;
2462
+ }
2463
+ setRunMarker(sessionId, status.runId ?? runId);
2464
+ this._updateMessaging({
2465
+ isStreaming: false,
2466
+ loading: false,
2467
+ generationInProgress: true
2468
+ });
2469
+ this._startPassivePolling(sessionId);
2470
+ }
2471
+ }
2445
2472
  // =====================================================================
2446
2473
  // Private — actions
2447
2474
  // =====================================================================
@@ -2560,20 +2587,28 @@ var ChatMachine = class {
2560
2587
  streamingContent: ""
2561
2588
  });
2562
2589
  try {
2563
- const compactResult = await this.dataSource.compactSessionHistory(curSessionId);
2564
- const summary = compactResult.summary || "";
2590
+ const accepted = await this.dataSource.compactSessionHistory(curSessionId);
2591
+ if (!accepted.runId) {
2592
+ throw new Error("Async compaction run metadata is missing");
2593
+ }
2565
2594
  this._updateMessaging({
2566
- turns: applyTurnLifecycleForPendingQuestion([createCompactedSystemTurn(curSessionId, summary)], null),
2595
+ turns: applyTurnLifecycleForPendingQuestion(
2596
+ [createCompactedSystemTurn(curSessionId, "Compacting conversation history...")],
2597
+ null
2598
+ ),
2567
2599
  pendingQuestion: null
2568
2600
  });
2569
- const result = await this.dataSource.fetchSession(curSessionId);
2570
- if (result) {
2571
- this._updateSession({ session: result.session });
2572
- this._setTurnsFromFetch(result.turns, result.pendingQuestion || null);
2573
- } else {
2574
- this._setTurnsFromFetch([], null);
2601
+ await this._resumeAcceptedRunOrPoll(curSessionId, accepted.runId);
2602
+ if (!this.state.messaging.generationInProgress) {
2603
+ const result = await this.dataSource.fetchSession(curSessionId);
2604
+ if (result) {
2605
+ this._updateSession({ session: result.session });
2606
+ this._setTurnsFromFetch(result.turns, result.pendingQuestion || null);
2607
+ } else {
2608
+ this._setTurnsFromFetch([], null);
2609
+ }
2610
+ this._updateMessaging({ codeOutputs: [] });
2575
2611
  }
2576
- this._updateMessaging({ codeOutputs: [] });
2577
2612
  } catch (err) {
2578
2613
  const normalized = normalizeRPCError(err, "Failed to compact session history");
2579
2614
  this._updateInput({ inputError: normalized.userMessage });
@@ -2738,8 +2773,6 @@ var ChatMachine = class {
2738
2773
  this._notifySessionsUpdated("session_created", targetSessionId);
2739
2774
  if (this.onSessionCreated) {
2740
2775
  this.onSessionCreated(targetSessionId);
2741
- } else {
2742
- this.dataSource.navigateToSession?.(targetSessionId);
2743
2776
  }
2744
2777
  }
2745
2778
  this._clearStreamError();
@@ -3025,9 +3058,24 @@ var ChatMachine = class {
3025
3058
  return;
3026
3059
  }
3027
3060
  if (result.success) {
3061
+ this._updateMessaging({
3062
+ pendingQuestion: null,
3063
+ turns: applyTurnLifecycleForPendingQuestion(this.state.messaging.turns, null)
3064
+ });
3028
3065
  if (result.data) {
3029
- this._updateSession({ session: result.data.session });
3030
- this._setTurnsFromFetch(result.data.turns, result.data.pendingQuestion || null);
3066
+ await this._resumeAcceptedRunOrPoll(curSessionId, result.data.runId);
3067
+ if (!this.state.messaging.generationInProgress) {
3068
+ const fetchResult = await this.dataSource.fetchSession(curSessionId);
3069
+ if (this.disposed) {
3070
+ return;
3071
+ }
3072
+ if (fetchResult) {
3073
+ this._updateSession({ session: fetchResult.session });
3074
+ this._setTurnsFromFetch(fetchResult.turns, fetchResult.pendingQuestion || null);
3075
+ } else {
3076
+ this._updateSession({ error: "Failed to load updated session", errorRetryable: true });
3077
+ }
3078
+ }
3031
3079
  } else if (curSessionId !== "new") {
3032
3080
  const fetchResult = await this.dataSource.fetchSession(curSessionId);
3033
3081
  if (this.disposed) {
@@ -3071,7 +3119,9 @@ var ChatMachine = class {
3071
3119
  pendingQuestion: null,
3072
3120
  turns: applyTurnLifecycleForPendingQuestion(this.state.messaging.turns, null)
3073
3121
  });
3074
- if (curSessionId !== "new") {
3122
+ if (result.data) {
3123
+ await this._resumeAcceptedRunOrPoll(curSessionId, result.data.runId);
3124
+ } else if (curSessionId !== "new") {
3075
3125
  const fetchResult = await this.dataSource.fetchSession(curSessionId);
3076
3126
  if (this.disposed) {
3077
3127
  return;
@@ -3291,12 +3341,151 @@ function useBranding() {
3291
3341
  }, [context.extensions?.branding, t]);
3292
3342
  return branding;
3293
3343
  }
3294
- function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
3344
+ function hashString(str) {
3345
+ let hash = 0;
3346
+ for (let i = 0; i < str.length; i++) {
3347
+ const char = str.charCodeAt(i);
3348
+ hash = (hash << 5) - hash + char;
3349
+ hash = hash & hash;
3350
+ }
3351
+ return Math.abs(hash);
3352
+ }
3353
+ var colorPalette = [
3354
+ { bg: "bg-blue-500", text: "text-white" },
3355
+ { bg: "bg-green-500", text: "text-white" },
3356
+ { bg: "bg-purple-500", text: "text-white" },
3357
+ { bg: "bg-pink-500", text: "text-white" },
3358
+ { bg: "bg-indigo-500", text: "text-white" },
3359
+ { bg: "bg-teal-500", text: "text-white" },
3360
+ { bg: "bg-orange-500", text: "text-white" },
3361
+ { bg: "bg-cyan-500", text: "text-white" },
3362
+ { bg: "bg-amber-500", text: "text-white" },
3363
+ { bg: "bg-lime-500", text: "text-white" }
3364
+ ];
3365
+ var sizeClasses = {
3366
+ xs: "w-6 h-6 text-[10px]",
3367
+ sm: "w-8 h-8 text-xs",
3368
+ md: "w-10 h-10 text-sm",
3369
+ lg: "w-12 h-12 text-base"
3370
+ };
3371
+ function UserAvatar({
3372
+ firstName,
3373
+ lastName,
3374
+ initials: providedInitials,
3375
+ size = "md",
3376
+ className = ""
3377
+ }) {
3378
+ const derivedInitials = (() => {
3379
+ const firstChar = firstName?.trim()?.charAt(0) || "";
3380
+ const lastChar = lastName?.trim()?.charAt(0) || "";
3381
+ const combined = `${firstChar}${lastChar}`.trim();
3382
+ return combined || "U";
3383
+ })();
3384
+ const initials = (providedInitials?.trim() || derivedInitials).toUpperCase();
3385
+ const fullName = `${firstName}${lastName}`;
3386
+ const colorIndex = hashString(fullName) % colorPalette.length;
3387
+ const colors = colorPalette[colorIndex];
3388
+ return /* @__PURE__ */ jsx(
3389
+ "div",
3390
+ {
3391
+ className: `
3392
+ ${sizeClasses[size]}
3393
+ ${colors.bg}
3394
+ ${colors.text}
3395
+ ${className}
3396
+ rounded-full
3397
+ flex
3398
+ items-center
3399
+ justify-center
3400
+ font-semibold
3401
+ flex-shrink-0
3402
+ select-none
3403
+ `,
3404
+ "aria-label": `${firstName} ${lastName}`,
3405
+ title: `${firstName} ${lastName}`,
3406
+ children: initials
3407
+ }
3408
+ );
3409
+ }
3410
+ var MemoizedUserAvatar = memo(UserAvatar);
3411
+ MemoizedUserAvatar.displayName = "UserAvatar";
3412
+ var overlapClasses = {
3413
+ xs: "-ml-1.5",
3414
+ sm: "-ml-2"
3415
+ };
3416
+ var badgeSizeClasses = {
3417
+ xs: "w-6 h-6 text-[10px]",
3418
+ sm: "w-8 h-8 text-xs"
3419
+ };
3420
+ function AvatarStackInner({
3421
+ users,
3422
+ max = 3,
3423
+ size = "sm",
3424
+ onClick,
3425
+ className = ""
3426
+ }) {
3427
+ const visible = users.slice(0, max);
3428
+ const overflow = users.length - max;
3429
+ const interactive = typeof onClick === "function";
3430
+ const overlap = overlapClasses[size];
3431
+ const badgeSize = badgeSizeClasses[size];
3432
+ const handleKeyDown = (e) => {
3433
+ if (interactive && (e.key === "Enter" || e.key === " ")) {
3434
+ e.preventDefault();
3435
+ onClick();
3436
+ }
3437
+ };
3438
+ return /* @__PURE__ */ jsxs(
3439
+ "div",
3440
+ {
3441
+ className: `inline-flex items-center ${interactive ? "cursor-pointer transition-opacity hover:opacity-80" : ""} ${className}`,
3442
+ onClick: interactive ? onClick : void 0,
3443
+ onKeyDown: interactive ? handleKeyDown : void 0,
3444
+ role: interactive ? "button" : void 0,
3445
+ tabIndex: interactive ? 0 : void 0,
3446
+ "aria-label": interactive ? `${users.length} members` : void 0,
3447
+ children: [
3448
+ visible.map((user, i) => /* @__PURE__ */ jsx(
3449
+ "div",
3450
+ {
3451
+ className: `${i > 0 ? overlap : ""} ring-2 ring-white dark:ring-gray-900 rounded-full`,
3452
+ style: { zIndex: visible.length - i },
3453
+ children: /* @__PURE__ */ jsx(
3454
+ MemoizedUserAvatar,
3455
+ {
3456
+ firstName: user.firstName,
3457
+ lastName: user.lastName,
3458
+ initials: user.initials,
3459
+ size
3460
+ }
3461
+ )
3462
+ },
3463
+ `${user.firstName}-${user.lastName}-${i}`
3464
+ )),
3465
+ overflow > 0 && /* @__PURE__ */ jsxs(
3466
+ "div",
3467
+ {
3468
+ className: `${overlap} ${badgeSize} rounded-full bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300 font-medium flex items-center justify-center flex-shrink-0 ring-2 ring-white dark:ring-gray-900`,
3469
+ style: { zIndex: 0 },
3470
+ children: [
3471
+ "+",
3472
+ overflow
3473
+ ]
3474
+ }
3475
+ )
3476
+ ]
3477
+ }
3478
+ );
3479
+ }
3480
+ var AvatarStack = memo(AvatarStackInner);
3481
+ AvatarStack.displayName = "AvatarStack";
3482
+ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot, members, onMembersClick }) {
3295
3483
  const { t } = useTranslation();
3296
3484
  const branding = useBranding();
3297
3485
  const BackButton = onBack ? /* @__PURE__ */ jsx(
3298
3486
  "button",
3299
3487
  {
3488
+ type: "button",
3300
3489
  onClick: onBack,
3301
3490
  className: "cursor-pointer p-2 hover:bg-gray-100 dark:hover:bg-gray-700 active:bg-gray-200 dark:active:bg-gray-600 rounded-lg transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
3302
3491
  "aria-label": t("BiChat.Chat.GoBack"),
@@ -3315,23 +3504,42 @@ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
3315
3504
  ] }) });
3316
3505
  }
3317
3506
  const resolvedSessionTitle = session.title?.trim() || t("BiChat.Chat.NewChat");
3507
+ const isGroupSession = Boolean(session.isGroup || session.memberCount && session.memberCount > 1);
3508
+ const memberCount = session.memberCount ?? 0;
3509
+ const stackUsers = members && members.length > 0 ? members : [];
3318
3510
  return /* @__PURE__ */ jsx("header", { className: "bichat-header border-b border-gray-200 dark:border-gray-700 px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
3319
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
3511
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
3320
3512
  BackButton,
3321
3513
  Logo,
3322
- /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-[var(--bichat-text)]", children: resolvedSessionTitle }),
3323
- session.pinned && /* @__PURE__ */ jsx(
3324
- "svg",
3325
- {
3326
- className: "w-4 h-4 text-[var(--bichat-primary)]",
3327
- fill: "currentColor",
3328
- viewBox: "0 0 20 20",
3329
- "aria-label": t("BiChat.Chat.Pinned"),
3330
- children: /* @__PURE__ */ jsx("path", { d: "M10 2a1 1 0 011 1v1.323l3.954 1.582 1.599-.8a1 1 0 01.894 1.79l-1.233.616 1.738 5.42a1 1 0 01-.285 1.05A3.989 3.989 0 0115 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.715-5.349L11 6.477V16h2a1 1 0 110 2H7a1 1 0 110-2h2V6.477L6.237 7.582l1.715 5.349a1 1 0 01-.285 1.05A3.989 3.989 0 015 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.738-5.42-1.233-.617a1 1 0 01.894-1.788l1.599.799L9 4.323V3a1 1 0 011-1z" })
3331
- }
3332
- )
3514
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
3515
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
3516
+ /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-[var(--bichat-text)] truncate", children: resolvedSessionTitle }),
3517
+ session.pinned && /* @__PURE__ */ jsx(
3518
+ "svg",
3519
+ {
3520
+ className: "w-4 h-4 text-[var(--bichat-primary)] flex-shrink-0",
3521
+ fill: "currentColor",
3522
+ viewBox: "0 0 20 20",
3523
+ role: "img",
3524
+ "aria-label": t("BiChat.Chat.Pinned"),
3525
+ children: /* @__PURE__ */ jsx("path", { d: "M10 2a1 1 0 011 1v1.323l3.954 1.582 1.599-.8a1 1 0 01.894 1.79l-1.233.616 1.738 5.42a1 1 0 01-.285 1.05A3.989 3.989 0 0115 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.715-5.349L11 6.477V16h2a1 1 0 110 2H7a1 1 0 110-2h2V6.477L6.237 7.582l1.715 5.349a1 1 0 01-.285 1.05A3.989 3.989 0 015 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.738-5.42-1.233-.617a1 1 0 01.894-1.788l1.599.799L9 4.323V3a1 1 0 011-1z" })
3526
+ }
3527
+ ),
3528
+ isGroupSession && stackUsers.length > 0 && /* @__PURE__ */ jsx(
3529
+ AvatarStack,
3530
+ {
3531
+ users: stackUsers,
3532
+ max: 3,
3533
+ size: "xs",
3534
+ onClick: onMembersClick,
3535
+ className: "flex-shrink-0"
3536
+ }
3537
+ )
3538
+ ] }),
3539
+ isGroupSession && memberCount > 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-600 dark:text-gray-400 mt-0.5", children: memberCount === 1 ? t("BiChat.Chat.OneMember") : t("BiChat.Chat.MemberCount").replace("{{count}}", String(memberCount)) })
3540
+ ] })
3333
3541
  ] }),
3334
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3542
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
3335
3543
  readOnly && /* @__PURE__ */ jsx("span", { className: "px-2 py-1 text-xs bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-200 rounded", children: t("BiChat.Chat.ReadOnly") }),
3336
3544
  session.status === "archived" && /* @__PURE__ */ jsx("span", { className: "px-2 py-1 text-xs bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded", children: t("BiChat.Chat.Archived") }),
3337
3545
  actionsSlot
@@ -4206,6 +4414,7 @@ function UserMessage({
4206
4414
  turn,
4207
4415
  turnId,
4208
4416
  initials = "U",
4417
+ authorName,
4209
4418
  slots,
4210
4419
  classNames: classNameOverrides,
4211
4420
  onCopy,
@@ -4413,6 +4622,16 @@ function UserMessage({
4413
4622
  };
4414
4623
  return /* @__PURE__ */ jsxs("div", { className: classes.root, children: [
4415
4624
  /* @__PURE__ */ jsxs("div", { className: classes.wrapper, children: [
4625
+ authorName && /* @__PURE__ */ jsx(
4626
+ "span",
4627
+ {
4628
+ id: `${turn.id}-author`,
4629
+ role: "note",
4630
+ "aria-label": authorName,
4631
+ className: "mb-1 px-1 text-[11px] text-right text-gray-500 dark:text-gray-400",
4632
+ children: authorName
4633
+ }
4634
+ ),
4416
4635
  normalizedAttachments.length > 0 && /* @__PURE__ */ jsx("div", { className: classes.attachments, children: renderSlot(
4417
4636
  slots?.attachments,
4418
4637
  attachmentsSlotProps,
@@ -4424,20 +4643,28 @@ function UserMessage({
4424
4643
  }
4425
4644
  )
4426
4645
  ) }),
4427
- turn.content && /* @__PURE__ */ jsx("div", { ref: bubbleRef, className: classes.bubble, children: /* @__PURE__ */ jsx("div", { className: classes.content, children: isEditing ? /* @__PURE__ */ jsx(
4428
- EditForm,
4646
+ turn.content && /* @__PURE__ */ jsx(
4647
+ "div",
4429
4648
  {
4430
- draftContent,
4431
- onDraftChange: handleDraftChange,
4432
- onSave: handleEditSave,
4433
- onCancel: handleEditCancel,
4434
- onKeyDown: handleEditKeyDown,
4435
- textareaRef: editTextareaRef,
4436
- disabled: false,
4437
- originalContent: turn.content,
4438
- t
4649
+ ref: bubbleRef,
4650
+ className: classes.bubble,
4651
+ "aria-describedby": authorName ? `${turn.id}-author` : void 0,
4652
+ children: /* @__PURE__ */ jsx("div", { className: classes.content, children: isEditing ? /* @__PURE__ */ jsx(
4653
+ EditForm,
4654
+ {
4655
+ draftContent,
4656
+ onDraftChange: handleDraftChange,
4657
+ onSave: handleEditSave,
4658
+ onCancel: handleEditCancel,
4659
+ onKeyDown: handleEditKeyDown,
4660
+ textareaRef: editTextareaRef,
4661
+ disabled: false,
4662
+ originalContent: turn.content,
4663
+ t
4664
+ }
4665
+ ) : renderSlot(slots?.content, contentSlotProps, turn.content) })
4439
4666
  }
4440
- ) : renderSlot(slots?.content, contentSlotProps, turn.content) }) }),
4667
+ ),
4441
4668
  !hideActions && /* @__PURE__ */ jsx("div", { className: `${classes.actions} ${isCopied ? "opacity-100" : ""}`, children: renderSlot(
4442
4669
  slots?.actions,
4443
4670
  actionsSlotProps,
@@ -4486,19 +4713,25 @@ function UserTurnView({
4486
4713
  turn,
4487
4714
  slots,
4488
4715
  classNames,
4489
- initials = "U",
4716
+ initials,
4490
4717
  hideAvatar,
4491
4718
  hideActions,
4492
4719
  hideTimestamp,
4493
- allowEdit
4720
+ allowEdit,
4721
+ showAuthorName = false
4494
4722
  }) {
4495
4723
  const { handleEdit, handleCopy } = useChatMessaging();
4724
+ const author = turn.userTurn.author;
4725
+ const fullName = [author?.firstName || "", author?.lastName || ""].join(" ").trim();
4726
+ const authorName = showAuthorName && fullName.length > 0 ? fullName : void 0;
4727
+ const resolvedInitials = initials ?? author?.initials ?? "U";
4496
4728
  return /* @__PURE__ */ jsx(
4497
4729
  UserMessage,
4498
4730
  {
4499
4731
  turn: turn.userTurn,
4500
4732
  turnId: turn.id,
4501
- initials,
4733
+ initials: resolvedInitials,
4734
+ authorName,
4502
4735
  slots,
4503
4736
  classNames,
4504
4737
  onCopy: handleCopy,
@@ -8493,7 +8726,7 @@ function StreamingBubble({ content, normalizedContent }) {
8493
8726
  }
8494
8727
  function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readOnly }) {
8495
8728
  const { t } = useTranslation();
8496
- const { currentSessionId, fetching } = useChatSession();
8729
+ const { session, currentSessionId, fetching } = useChatSession();
8497
8730
  const {
8498
8731
  turns,
8499
8732
  streamingContent,
@@ -8508,6 +8741,7 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
8508
8741
  () => streamingContent ? normalizeStreamingMarkdown(streamingContent) : "",
8509
8742
  [streamingContent]
8510
8743
  );
8744
+ const showAuthorNames = Boolean(session?.isGroup);
8511
8745
  const showEphemeral = showActivityTrace || showTypingIndicator;
8512
8746
  return /* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-h-0", children: [
8513
8747
  /* @__PURE__ */ jsx("div", { ref: containerRef, className: "h-full overflow-y-auto overflow-x-hidden px-4 py-6", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto space-y-6", children: [
@@ -8517,6 +8751,10 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
8517
8751
  const prevDate = index > 0 ? new Date(turns[index - 1].createdAt) : null;
8518
8752
  const showDateSeparator = !!prevDate && !isSameDay(turnDate, prevDate);
8519
8753
  const isLast = index === turns.length - 1;
8754
+ const userTurnProps = {
8755
+ allowEdit: readOnly ? false : isLast,
8756
+ showAuthorName: showAuthorNames
8757
+ };
8520
8758
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
8521
8759
  showDateSeparator && /* @__PURE__ */ jsx(DateSeparator, { date: turnDate }),
8522
8760
  /* @__PURE__ */ jsx(
@@ -8526,7 +8764,7 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
8526
8764
  isLastTurn: isLast,
8527
8765
  renderUserTurn,
8528
8766
  renderAssistantTurn,
8529
- userTurnProps: readOnly ? { allowEdit: false } : { allowEdit: isLast },
8767
+ userTurnProps,
8530
8768
  assistantTurnProps: readOnly ? { allowRegenerate: false } : void 0
8531
8769
  }
8532
8770
  )
@@ -10732,37 +10970,655 @@ function SessionArtifactsPanel({
10732
10970
  }
10733
10971
  );
10734
10972
  }
10973
+ var DialogContext = createContext(null);
10974
+ var FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
10975
+ function InlineDialog({ open, onClose, className, children }) {
10976
+ const containerRef = useRef(null);
10977
+ const previousFocusRef = useRef(null);
10978
+ useEffect(() => {
10979
+ if (!open) {
10980
+ return;
10981
+ }
10982
+ previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
10983
+ const container = containerRef.current;
10984
+ if (!container) {
10985
+ return;
10986
+ }
10987
+ const getFocusable = () => Array.from(
10988
+ container.querySelectorAll(FOCUSABLE_SELECTOR)
10989
+ );
10990
+ const handler = (e) => {
10991
+ if (e.key === "Escape") {
10992
+ onClose();
10993
+ return;
10994
+ }
10995
+ if (e.key !== "Tab") {
10996
+ return;
10997
+ }
10998
+ const focusable = getFocusable();
10999
+ if (focusable.length === 0) {
11000
+ e.preventDefault();
11001
+ container.focus();
11002
+ return;
11003
+ }
11004
+ const first = focusable[0];
11005
+ const last = focusable[focusable.length - 1];
11006
+ if (e.shiftKey && document.activeElement === first) {
11007
+ e.preventDefault();
11008
+ last.focus();
11009
+ } else if (!e.shiftKey && document.activeElement === last) {
11010
+ e.preventDefault();
11011
+ first.focus();
11012
+ }
11013
+ };
11014
+ (getFocusable()[0] ?? container)?.focus();
11015
+ container.addEventListener("keydown", handler);
11016
+ return () => {
11017
+ container.removeEventListener("keydown", handler);
11018
+ previousFocusRef.current?.focus();
11019
+ };
11020
+ }, [open, onClose]);
11021
+ if (!open) {
11022
+ return null;
11023
+ }
11024
+ return /* @__PURE__ */ jsx(DialogContext.Provider, { value: onClose, children: /* @__PURE__ */ jsx(
11025
+ "div",
11026
+ {
11027
+ ref: containerRef,
11028
+ className,
11029
+ onClick: onClose,
11030
+ tabIndex: -1,
11031
+ children
11032
+ }
11033
+ ) });
11034
+ }
11035
+ function InlineDialogBackdrop(props) {
11036
+ return /* @__PURE__ */ jsx("div", { "aria-hidden": "true", ...props });
11037
+ }
11038
+ function InlineDialogPanel({
11039
+ children,
11040
+ onClick,
11041
+ ...rest
11042
+ }) {
11043
+ const ref = useRef(null);
11044
+ useEffect(() => {
11045
+ if (!ref.current) {
11046
+ return;
11047
+ }
11048
+ const target = ref.current.querySelector("[data-autofocus]") ?? ref.current.querySelector(
11049
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
11050
+ );
11051
+ target?.focus();
11052
+ }, []);
11053
+ return /* @__PURE__ */ jsx(
11054
+ "div",
11055
+ {
11056
+ ref,
11057
+ role: "dialog",
11058
+ "aria-modal": "true",
11059
+ onClick: (e) => {
11060
+ e.stopPropagation();
11061
+ onClick?.(e);
11062
+ },
11063
+ ...rest,
11064
+ children
11065
+ }
11066
+ );
11067
+ }
11068
+ function InlineDialogTitle(props) {
11069
+ return /* @__PURE__ */ jsx("h2", { ...props });
11070
+ }
11071
+ function InlineDialogDescription(props) {
11072
+ return /* @__PURE__ */ jsx("p", { ...props });
11073
+ }
10735
11074
 
10736
- // ui/src/bichat/components/StreamError.tsx
11075
+ // ui/src/bichat/components/SessionMembersModal.tsx
10737
11076
  init_useTranslation();
10738
- function StreamError({
10739
- error,
10740
- onRetry,
10741
- onRegenerate,
10742
- onDismiss,
10743
- compact = false
11077
+ init_useTranslation();
11078
+ function ConfirmModalBase({
11079
+ isOpen,
11080
+ title,
11081
+ message,
11082
+ onConfirm,
11083
+ onCancel,
11084
+ confirmText,
11085
+ cancelText,
11086
+ isDanger = false
10744
11087
  }) {
10745
11088
  const { t } = useTranslation();
10746
- return /* @__PURE__ */ jsxs(
10747
- motion.div,
10748
- {
10749
- initial: { opacity: 0, y: 10 },
10750
- animate: { opacity: 1, y: 0 },
10751
- exit: { opacity: 0, y: -10 },
10752
- className: `flex items-start gap-3 ${compact ? "px-3 py-2.5" : "px-4 py-3"} bg-red-50 dark:bg-red-950/40 border border-red-200/80 dark:border-red-900/60 rounded-xl shadow-sm`,
10753
- role: "alert",
10754
- children: [
10755
- /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5 flex items-center justify-center w-7 h-7 rounded-full bg-red-100 dark:bg-red-900/40", children: /* @__PURE__ */ jsx(
10756
- Warning,
10757
- {
10758
- className: "w-4 h-4 text-red-600 dark:text-red-400",
10759
- weight: "fill"
10760
- }
10761
- ) }),
11089
+ const resolvedConfirmText = confirmText?.trim() ? confirmText : t("BiChat.Common.Confirm");
11090
+ const resolvedCancelText = cancelText?.trim() ? cancelText : t("BiChat.Common.Cancel");
11091
+ return /* @__PURE__ */ jsxs(InlineDialog, { open: isOpen, onClose: onCancel, className: "relative z-40", children: [
11092
+ /* @__PURE__ */ jsx(InlineDialogBackdrop, { className: "fixed inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity duration-200" }),
11093
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50 p-4", children: /* @__PURE__ */ jsxs(InlineDialogPanel, { className: "bg-white dark:bg-gray-800 rounded-2xl shadow-xl dark:shadow-2xl dark:shadow-black/30 max-w-sm w-full overflow-hidden", children: [
11094
+ /* @__PURE__ */ jsx("div", { className: "px-6 pt-6 pb-5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-4", children: [
11095
+ isDanger && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 flex items-center justify-center w-10 h-10 rounded-xl bg-red-50 dark:bg-red-950/40 border border-red-200/60 dark:border-red-800/40", children: /* @__PURE__ */ jsx(WarningCircle, { size: 22, weight: "duotone", className: "text-red-600 dark:text-red-400" }) }),
10762
11096
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
10763
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-200 leading-snug", children: t("BiChat.Error.Generic") }),
10764
- /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-red-600/80 dark:text-red-400/70 break-words leading-relaxed", children: error }),
10765
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-2", children: [
11097
+ /* @__PURE__ */ jsx(InlineDialogTitle, { className: "text-base font-semibold text-gray-900 dark:text-gray-100 leading-snug", children: title }),
11098
+ /* @__PURE__ */ jsx(InlineDialogDescription, { className: "mt-2 text-sm text-gray-600 dark:text-gray-400 leading-relaxed", children: message })
11099
+ ] })
11100
+ ] }) }),
11101
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2.5 px-6 pb-5", children: [
11102
+ /* @__PURE__ */ jsx(
11103
+ "button",
11104
+ {
11105
+ type: "button",
11106
+ onClick: onCancel,
11107
+ ...isDanger ? { "data-autofocus": true } : {},
11108
+ className: "cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700/60 hover:bg-gray-200 dark:hover:bg-gray-700 active:bg-gray-250 dark:active:bg-gray-600 transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
11109
+ "data-testid": "confirm-modal-cancel",
11110
+ children: resolvedCancelText
11111
+ }
11112
+ ),
11113
+ /* @__PURE__ */ jsx(
11114
+ "button",
11115
+ {
11116
+ type: "button",
11117
+ ...!isDanger ? { "data-autofocus": true } : {},
11118
+ onClick: onConfirm,
11119
+ className: [
11120
+ "cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-white",
11121
+ "transition-all duration-150 shadow-sm hover:shadow",
11122
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
11123
+ isDanger ? "bg-red-600 hover:bg-red-700 active:bg-red-800 focus-visible:ring-red-500/50" : "bg-primary-600 hover:bg-primary-700 active:bg-primary-800 focus-visible:ring-primary-500/50"
11124
+ ].join(" "),
11125
+ "data-testid": "confirm-modal-confirm",
11126
+ children: resolvedConfirmText
11127
+ }
11128
+ )
11129
+ ] })
11130
+ ] }) })
11131
+ ] });
11132
+ }
11133
+ var ConfirmModal = memo(ConfirmModalBase);
11134
+ ConfirmModal.displayName = "ConfirmModal";
11135
+ var ConfirmModal_default = ConfirmModal;
11136
+ var ROLES = ["editor", "viewer"];
11137
+ function RoleSegmentedControl({
11138
+ value,
11139
+ onChange,
11140
+ disabled,
11141
+ size = "md",
11142
+ t
11143
+ }) {
11144
+ const btnBase = size === "sm" ? "px-2 py-0.5 text-[11px]" : "px-3 py-1 text-xs";
11145
+ const currentIndex = ROLES.indexOf(value);
11146
+ const handleKeyDown = (e) => {
11147
+ if (disabled) {
11148
+ return;
11149
+ }
11150
+ let nextIndex = null;
11151
+ if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
11152
+ e.preventDefault();
11153
+ nextIndex = currentIndex <= 0 ? ROLES.length - 1 : currentIndex - 1;
11154
+ } else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
11155
+ e.preventDefault();
11156
+ nextIndex = currentIndex >= ROLES.length - 1 ? 0 : currentIndex + 1;
11157
+ }
11158
+ if (nextIndex !== null) {
11159
+ const nextRole = ROLES[nextIndex];
11160
+ onChange(nextRole);
11161
+ const target = e.currentTarget.querySelector(`[data-role="${nextRole}"]`);
11162
+ target?.focus();
11163
+ }
11164
+ };
11165
+ return /* @__PURE__ */ jsx(
11166
+ "div",
11167
+ {
11168
+ role: "radiogroup",
11169
+ "aria-label": t("BiChat.Share.RoleLabel"),
11170
+ className: "inline-flex rounded-lg border border-gray-200 dark:border-gray-700 p-0.5 bg-gray-50 dark:bg-gray-800/50",
11171
+ onKeyDown: handleKeyDown,
11172
+ children: ROLES.map((role) => /* @__PURE__ */ jsx(
11173
+ "button",
11174
+ {
11175
+ type: "button",
11176
+ role: "radio",
11177
+ "aria-checked": value === role,
11178
+ tabIndex: value === role ? 0 : -1,
11179
+ "data-role": role,
11180
+ disabled,
11181
+ onClick: () => onChange(role),
11182
+ className: `${btnBase} cursor-pointer rounded-md font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 disabled:opacity-50 disabled:cursor-not-allowed ${value === role ? "bg-primary-600 text-white shadow-sm" : "text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100"}`,
11183
+ children: role === "editor" ? t("BiChat.Share.RoleEditor") : t("BiChat.Share.RoleViewer")
11184
+ },
11185
+ role
11186
+ ))
11187
+ }
11188
+ );
11189
+ }
11190
+ function MemberSkeleton() {
11191
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-xl px-3 py-2.5", "aria-hidden": "true", children: [
11192
+ /* @__PURE__ */ jsx("div", { className: "w-8 h-8 rounded-full bg-gray-200 dark:bg-gray-700 animate-pulse flex-shrink-0" }),
11193
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1.5", children: [
11194
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-28 rounded bg-gray-200 dark:bg-gray-700 animate-pulse" }),
11195
+ /* @__PURE__ */ jsx("div", { className: "h-2.5 w-16 rounded bg-gray-100 dark:bg-gray-800 animate-pulse" })
11196
+ ] }),
11197
+ /* @__PURE__ */ jsx("div", { className: "h-6 w-16 rounded-lg bg-gray-200 dark:bg-gray-700 animate-pulse" })
11198
+ ] });
11199
+ }
11200
+ function SessionMembersModal({ isOpen, sessionId, dataSource, onClose }) {
11201
+ const headingId = useId();
11202
+ const { t } = useTranslation();
11203
+ const statusTimerRef = useRef();
11204
+ const [loading, setLoading] = useState(false);
11205
+ const [saving, setSaving] = useState(false);
11206
+ const [error, setError] = useState(null);
11207
+ const [users, setUsers] = useState([]);
11208
+ const [members, setMembers] = useState([]);
11209
+ const [selectedUser, setSelectedUser] = useState(null);
11210
+ const [selectedRole, setSelectedRole] = useState("editor");
11211
+ const [query, setQuery] = useState("");
11212
+ const [confirmRemove, setConfirmRemove] = useState(null);
11213
+ const [statusMessage, setStatusMessage] = useState(null);
11214
+ const [dropdownOpen, setDropdownOpen] = useState(false);
11215
+ const [dropdownHighlightIndex, setDropdownHighlightIndex] = useState(0);
11216
+ const dropdownOptionRefs = useRef([]);
11217
+ const canManageMembers = Boolean(
11218
+ dataSource.listUsers && dataSource.listSessionMembers && dataSource.addSessionMember && dataSource.updateSessionMemberRole && dataSource.removeSessionMember
11219
+ );
11220
+ const refresh = useCallback(async () => {
11221
+ if (!sessionId || !canManageMembers) {
11222
+ return;
11223
+ }
11224
+ setLoading(true);
11225
+ setError(null);
11226
+ try {
11227
+ const [usersData, membersData] = await Promise.all([
11228
+ dataSource.listUsers(),
11229
+ dataSource.listSessionMembers(sessionId)
11230
+ ]);
11231
+ setUsers(usersData);
11232
+ setMembers(membersData);
11233
+ } catch {
11234
+ setError(t("BiChat.Share.LoadFailed"));
11235
+ } finally {
11236
+ setLoading(false);
11237
+ }
11238
+ }, [canManageMembers, dataSource, sessionId, t]);
11239
+ useEffect(() => {
11240
+ if (!isOpen) {
11241
+ return;
11242
+ }
11243
+ void refresh();
11244
+ }, [isOpen, refresh]);
11245
+ useEffect(() => {
11246
+ if (!isOpen) {
11247
+ setQuery("");
11248
+ setSelectedUser(null);
11249
+ setSelectedRole("editor");
11250
+ setError(null);
11251
+ setConfirmRemove(null);
11252
+ setStatusMessage(null);
11253
+ setDropdownOpen(false);
11254
+ setDropdownHighlightIndex(0);
11255
+ }
11256
+ }, [isOpen]);
11257
+ const memberIDs = useMemo(() => new Set(members.map((m) => m.user.id)), [members]);
11258
+ const availableUsers = useMemo(
11259
+ () => users.filter((user) => !memberIDs.has(user.id)),
11260
+ [users, memberIDs]
11261
+ );
11262
+ const filteredUsers = useMemo(() => {
11263
+ if (!query.trim()) {
11264
+ return availableUsers;
11265
+ }
11266
+ const q = query.toLowerCase();
11267
+ return availableUsers.filter(
11268
+ (u) => u.firstName.toLowerCase().includes(q) || u.lastName.toLowerCase().includes(q) || `${u.firstName} ${u.lastName}`.toLowerCase().includes(q)
11269
+ );
11270
+ }, [availableUsers, query]);
11271
+ useEffect(() => {
11272
+ setDropdownHighlightIndex(
11273
+ (i) => Math.min(Math.max(0, i), Math.max(0, filteredUsers.length - 1))
11274
+ );
11275
+ }, [filteredUsers.length]);
11276
+ useEffect(() => () => clearTimeout(statusTimerRef.current), []);
11277
+ const flashStatus = useCallback((msg) => {
11278
+ clearTimeout(statusTimerRef.current);
11279
+ setStatusMessage(msg);
11280
+ statusTimerRef.current = setTimeout(() => setStatusMessage(null), 3e3);
11281
+ }, []);
11282
+ const handleAdd = useCallback(async () => {
11283
+ if (!sessionId || !selectedUser || !dataSource.addSessionMember) {
11284
+ return;
11285
+ }
11286
+ setSaving(true);
11287
+ setError(null);
11288
+ try {
11289
+ await dataSource.addSessionMember(sessionId, selectedUser.id, selectedRole);
11290
+ setSelectedUser(null);
11291
+ setQuery("");
11292
+ flashStatus(t("BiChat.Share.MemberAdded"));
11293
+ await refresh();
11294
+ } catch {
11295
+ setError(t("BiChat.Share.AddFailed"));
11296
+ } finally {
11297
+ setSaving(false);
11298
+ }
11299
+ }, [sessionId, selectedUser, selectedRole, dataSource.addSessionMember, refresh, t, flashStatus]);
11300
+ const handleUpdateRole = useCallback(async (userId, role) => {
11301
+ if (!sessionId || !dataSource.updateSessionMemberRole) {
11302
+ return;
11303
+ }
11304
+ setSaving(true);
11305
+ setError(null);
11306
+ try {
11307
+ await dataSource.updateSessionMemberRole(sessionId, userId, role);
11308
+ await refresh();
11309
+ } catch {
11310
+ setError(t("BiChat.Share.UpdateFailed"));
11311
+ } finally {
11312
+ setSaving(false);
11313
+ }
11314
+ }, [sessionId, dataSource.updateSessionMemberRole, refresh]);
11315
+ const handleRemove = useCallback(async (userId) => {
11316
+ if (!sessionId || !dataSource.removeSessionMember) {
11317
+ return;
11318
+ }
11319
+ setSaving(true);
11320
+ setError(null);
11321
+ try {
11322
+ await dataSource.removeSessionMember(sessionId, userId);
11323
+ flashStatus(t("BiChat.Share.MemberRemoved"));
11324
+ await refresh();
11325
+ } catch {
11326
+ setError(t("BiChat.Share.RemoveFailed"));
11327
+ } finally {
11328
+ setSaving(false);
11329
+ }
11330
+ }, [sessionId, dataSource.removeSessionMember, refresh, flashStatus]);
11331
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
11332
+ /* @__PURE__ */ jsxs(InlineDialog, { open: isOpen, onClose, className: "relative z-40", children: [
11333
+ /* @__PURE__ */ jsx(InlineDialogBackdrop, { className: "fixed inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity duration-200" }),
11334
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50 p-4", children: /* @__PURE__ */ jsxs(
11335
+ InlineDialogPanel,
11336
+ {
11337
+ "aria-labelledby": headingId,
11338
+ className: "bg-white dark:bg-gray-800 rounded-2xl shadow-xl dark:shadow-2xl dark:shadow-black/30 max-w-md w-full",
11339
+ children: [
11340
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 pt-5 pb-4", children: [
11341
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
11342
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-9 h-9 rounded-xl bg-primary-50 dark:bg-primary-950/40 border border-primary-200/60 dark:border-primary-800/40", children: /* @__PURE__ */ jsx(UsersThree, { size: 18, weight: "duotone", className: "text-primary-600 dark:text-primary-400" }) }),
11343
+ /* @__PURE__ */ jsx(InlineDialogTitle, { id: headingId, className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: t("BiChat.Share.Title") })
11344
+ ] }),
11345
+ /* @__PURE__ */ jsx(
11346
+ "button",
11347
+ {
11348
+ type: "button",
11349
+ onClick: onClose,
11350
+ className: "rounded-lg p-1.5 text-gray-400 hover:text-gray-600 hover:bg-gray-100 dark:hover:text-gray-300 dark:hover:bg-gray-700 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
11351
+ "aria-label": t("BiChat.Common.Close"),
11352
+ children: /* @__PURE__ */ jsx(X, { size: 18 })
11353
+ }
11354
+ )
11355
+ ] }),
11356
+ /* @__PURE__ */ jsxs("div", { className: "px-6 pb-5 space-y-4", children: [
11357
+ !canManageMembers && /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-amber-200 bg-amber-50 px-3 py-2.5 text-xs text-amber-700 dark:border-amber-800/60 dark:bg-amber-900/20 dark:text-amber-300", children: t("BiChat.Share.Unsupported") }),
11358
+ error && /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-red-200 bg-red-50 px-3 py-2.5 text-xs text-red-700 dark:border-red-800/60 dark:bg-red-900/20 dark:text-red-300", children: error }),
11359
+ /* @__PURE__ */ jsx("div", { "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: statusMessage }),
11360
+ /* @__PURE__ */ jsxs("div", { children: [
11361
+ /* @__PURE__ */ jsxs("h3", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400", children: [
11362
+ t("BiChat.Share.Members"),
11363
+ !loading && members.length > 0 ? ` (${members.length})` : ""
11364
+ ] }),
11365
+ /* @__PURE__ */ jsx("div", { className: "max-h-64 overflow-y-auto -mx-1 px-1 space-y-1", children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
11366
+ /* @__PURE__ */ jsx(MemberSkeleton, {}),
11367
+ /* @__PURE__ */ jsx(MemberSkeleton, {}),
11368
+ /* @__PURE__ */ jsx(MemberSkeleton, {})
11369
+ ] }) : members.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-8 text-gray-400 dark:text-gray-500", children: [
11370
+ /* @__PURE__ */ jsx(UsersThree, { size: 32, weight: "thin", className: "mb-2" }),
11371
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: t("BiChat.Share.Empty") })
11372
+ ] }) : members.map((member) => /* @__PURE__ */ jsxs(
11373
+ "div",
11374
+ {
11375
+ className: "flex items-center gap-3 rounded-xl px-3 py-2 transition-colors hover:bg-gray-50 dark:hover:bg-gray-700/40",
11376
+ children: [
11377
+ /* @__PURE__ */ jsx(
11378
+ MemoizedUserAvatar,
11379
+ {
11380
+ firstName: member.user.firstName,
11381
+ lastName: member.user.lastName,
11382
+ initials: member.user.initials,
11383
+ size: "sm"
11384
+ }
11385
+ ),
11386
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "truncate text-sm font-medium text-gray-900 dark:text-gray-100", children: [
11387
+ member.user.firstName,
11388
+ " ",
11389
+ member.user.lastName
11390
+ ] }) }),
11391
+ member.role === "owner" ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-amber-50 dark:bg-amber-900/20 border border-amber-200/60 dark:border-amber-800/40 px-2.5 py-0.5 text-[11px] font-medium text-amber-700 dark:text-amber-300", children: [
11392
+ /* @__PURE__ */ jsx(Crown, { size: 12, weight: "duotone" }),
11393
+ t("BiChat.Share.RoleOwner")
11394
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
11395
+ /* @__PURE__ */ jsx(
11396
+ RoleSegmentedControl,
11397
+ {
11398
+ value: member.role,
11399
+ onChange: (role) => handleUpdateRole(member.user.id, role),
11400
+ disabled: saving,
11401
+ size: "sm",
11402
+ t
11403
+ }
11404
+ ),
11405
+ /* @__PURE__ */ jsx(
11406
+ "button",
11407
+ {
11408
+ type: "button",
11409
+ disabled: saving,
11410
+ onClick: () => setConfirmRemove(member),
11411
+ className: "cursor-pointer rounded-lg p-1.5 text-gray-400 transition-colors hover:bg-red-50 hover:text-red-600 dark:hover:bg-red-900/20 dark:hover:text-red-400 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500/50",
11412
+ "aria-label": `${t("BiChat.Share.Remove")} ${member.user.firstName} ${member.user.lastName}`,
11413
+ children: /* @__PURE__ */ jsx(Trash, { size: 14 })
11414
+ }
11415
+ )
11416
+ ] })
11417
+ ]
11418
+ },
11419
+ member.user.id
11420
+ )) })
11421
+ ] }),
11422
+ canManageMembers && /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-gray-200 dark:border-gray-700 p-3 space-y-3", children: [
11423
+ /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("BiChat.Share.AddMember") }),
11424
+ /* @__PURE__ */ jsxs(
11425
+ "div",
11426
+ {
11427
+ className: "relative",
11428
+ onBlur: (e) => {
11429
+ if (!e.currentTarget.contains(e.relatedTarget)) {
11430
+ setDropdownOpen(false);
11431
+ }
11432
+ },
11433
+ children: [
11434
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
11435
+ /* @__PURE__ */ jsx(
11436
+ MagnifyingGlass,
11437
+ {
11438
+ size: 14,
11439
+ className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 dark:text-gray-500"
11440
+ }
11441
+ ),
11442
+ /* @__PURE__ */ jsx(
11443
+ "input",
11444
+ {
11445
+ type: "text",
11446
+ className: "w-full rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800/60 pl-8 pr-3 py-2 text-sm text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 transition-colors focus:border-primary-400 dark:focus:border-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500/20",
11447
+ placeholder: t("BiChat.Share.SearchUsers"),
11448
+ value: selectedUser ? `${selectedUser.firstName} ${selectedUser.lastName}` : query,
11449
+ onFocus: () => {
11450
+ setDropdownOpen(true);
11451
+ setDropdownHighlightIndex(0);
11452
+ if (selectedUser) {
11453
+ setSelectedUser(null);
11454
+ setQuery("");
11455
+ }
11456
+ },
11457
+ onChange: (e) => {
11458
+ setQuery(e.target.value);
11459
+ setSelectedUser(null);
11460
+ setDropdownOpen(true);
11461
+ setDropdownHighlightIndex(0);
11462
+ },
11463
+ onKeyDown: (e) => {
11464
+ if (!dropdownOpen || filteredUsers.length === 0) {
11465
+ if (e.key === "Escape") {
11466
+ setDropdownOpen(false);
11467
+ }
11468
+ return;
11469
+ }
11470
+ if (e.key === "Escape") {
11471
+ e.preventDefault();
11472
+ setDropdownOpen(false);
11473
+ setDropdownHighlightIndex(0);
11474
+ return;
11475
+ }
11476
+ if (e.key === "ArrowDown") {
11477
+ e.preventDefault();
11478
+ const next = (dropdownHighlightIndex + 1) % filteredUsers.length;
11479
+ setDropdownHighlightIndex(next);
11480
+ setTimeout(() => dropdownOptionRefs.current[next]?.focus(), 0);
11481
+ return;
11482
+ }
11483
+ if (e.key === "ArrowUp") {
11484
+ e.preventDefault();
11485
+ const next = dropdownHighlightIndex <= 0 ? filteredUsers.length - 1 : dropdownHighlightIndex - 1;
11486
+ setDropdownHighlightIndex(next);
11487
+ setTimeout(() => dropdownOptionRefs.current[next]?.focus(), 0);
11488
+ return;
11489
+ }
11490
+ if (e.key === "Enter") {
11491
+ e.preventDefault();
11492
+ const user = filteredUsers[dropdownHighlightIndex];
11493
+ if (user) {
11494
+ setSelectedUser(user);
11495
+ setQuery("");
11496
+ setDropdownOpen(false);
11497
+ }
11498
+ }
11499
+ }
11500
+ }
11501
+ )
11502
+ ] }),
11503
+ dropdownOpen && !selectedUser && /* @__PURE__ */ jsx("div", { className: "absolute z-10 mt-1 max-h-48 w-full overflow-auto rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 shadow-lg py-1", children: filteredUsers.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-sm text-gray-500 dark:text-gray-400", children: availableUsers.length === 0 ? t("BiChat.Share.NoUsersAvailable") : t("BiChat.Share.NoSearchResults") }) : filteredUsers.map((user, index) => /* @__PURE__ */ jsxs(
11504
+ "button",
11505
+ {
11506
+ type: "button",
11507
+ ref: (el) => {
11508
+ dropdownOptionRefs.current[index] = el;
11509
+ },
11510
+ className: `flex w-full items-center gap-2.5 px-3 py-2 cursor-pointer transition-colors hover:bg-primary-50 dark:hover:bg-primary-900/20 ${index === dropdownHighlightIndex ? "bg-primary-50 dark:bg-primary-900/20" : ""}`,
11511
+ onMouseDown: (e) => e.preventDefault(),
11512
+ onClick: () => {
11513
+ setSelectedUser(user);
11514
+ setQuery("");
11515
+ setDropdownOpen(false);
11516
+ },
11517
+ children: [
11518
+ /* @__PURE__ */ jsx(
11519
+ MemoizedUserAvatar,
11520
+ {
11521
+ firstName: user.firstName,
11522
+ lastName: user.lastName,
11523
+ initials: user.initials,
11524
+ size: "xs"
11525
+ }
11526
+ ),
11527
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-900 dark:text-gray-100", children: [
11528
+ user.firstName,
11529
+ " ",
11530
+ user.lastName
11531
+ ] })
11532
+ ]
11533
+ },
11534
+ user.id
11535
+ )) })
11536
+ ]
11537
+ }
11538
+ ),
11539
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
11540
+ /* @__PURE__ */ jsx(
11541
+ RoleSegmentedControl,
11542
+ {
11543
+ value: selectedRole,
11544
+ onChange: setSelectedRole,
11545
+ disabled: saving,
11546
+ t
11547
+ }
11548
+ ),
11549
+ /* @__PURE__ */ jsxs(
11550
+ "button",
11551
+ {
11552
+ type: "button",
11553
+ onClick: handleAdd,
11554
+ disabled: saving || !selectedUser,
11555
+ className: "inline-flex cursor-pointer items-center gap-1.5 rounded-xl bg-primary-600 px-3.5 py-2 text-sm font-medium text-white shadow-sm transition-all duration-150 hover:bg-primary-700 hover:shadow active:bg-primary-800 disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
11556
+ children: [
11557
+ /* @__PURE__ */ jsx(UserPlus, { size: 14 }),
11558
+ t("BiChat.Share.Add")
11559
+ ]
11560
+ }
11561
+ )
11562
+ ] })
11563
+ ] })
11564
+ ] })
11565
+ ]
11566
+ }
11567
+ ) })
11568
+ ] }),
11569
+ /* @__PURE__ */ jsx(
11570
+ ConfirmModal,
11571
+ {
11572
+ isOpen: !!confirmRemove,
11573
+ isDanger: true,
11574
+ title: t("BiChat.Share.RemoveConfirmTitle"),
11575
+ message: confirmRemove ? t("BiChat.Share.RemoveConfirmMessage").replace(
11576
+ "{{name}}",
11577
+ `${confirmRemove.user.firstName} ${confirmRemove.user.lastName}`
11578
+ ) : "",
11579
+ confirmText: t("BiChat.Share.Remove"),
11580
+ onConfirm: () => {
11581
+ if (confirmRemove) {
11582
+ void handleRemove(confirmRemove.user.id);
11583
+ }
11584
+ setConfirmRemove(null);
11585
+ },
11586
+ onCancel: () => setConfirmRemove(null)
11587
+ }
11588
+ )
11589
+ ] });
11590
+ }
11591
+
11592
+ // ui/src/bichat/components/StreamError.tsx
11593
+ init_useTranslation();
11594
+ function StreamError({
11595
+ error,
11596
+ onRetry,
11597
+ onRegenerate,
11598
+ onDismiss,
11599
+ compact = false
11600
+ }) {
11601
+ const { t } = useTranslation();
11602
+ return /* @__PURE__ */ jsxs(
11603
+ motion.div,
11604
+ {
11605
+ initial: { opacity: 0, y: 10 },
11606
+ animate: { opacity: 1, y: 0 },
11607
+ exit: { opacity: 0, y: -10 },
11608
+ className: `flex items-start gap-3 ${compact ? "px-3 py-2.5" : "px-4 py-3"} bg-red-50 dark:bg-red-950/40 border border-red-200/80 dark:border-red-900/60 rounded-xl shadow-sm`,
11609
+ role: "alert",
11610
+ children: [
11611
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5 flex items-center justify-center w-7 h-7 rounded-full bg-red-100 dark:bg-red-900/40", children: /* @__PURE__ */ jsx(
11612
+ Warning,
11613
+ {
11614
+ className: "w-4 h-4 text-red-600 dark:text-red-400",
11615
+ weight: "fill"
11616
+ }
11617
+ ) }),
11618
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
11619
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-200 leading-snug", children: t("BiChat.Error.Generic") }),
11620
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-red-600/80 dark:text-red-400/70 break-words leading-relaxed", children: error }),
11621
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-2", children: [
10766
11622
  onRetry && /* @__PURE__ */ jsxs(
10767
11623
  "button",
10768
11624
  {
@@ -10860,7 +11716,8 @@ function ChatSessionCore({
10860
11716
  updateQueueItem
10861
11717
  } = useChatInput();
10862
11718
  const isArchived = session?.status === "archived";
10863
- const effectiveReadOnly = Boolean(readOnly ?? isReadOnly) || isArchived;
11719
+ const accessReadOnly = session?.access ? !session.access.canWrite : false;
11720
+ const effectiveReadOnly = Boolean(readOnly ?? isReadOnly) || isArchived || accessReadOnly;
10864
11721
  const [restoring, setRestoring] = useState(false);
10865
11722
  const handleRestore = useCallback(async () => {
10866
11723
  if (!session?.id) {
@@ -10881,6 +11738,8 @@ function ChatSessionCore({
10881
11738
  const [artifactsPanelExpanded, setArtifactsPanelExpanded] = useState(
10882
11739
  artifactsPanelDefaultExpanded
10883
11740
  );
11741
+ const [membersModalOpen, setMembersModalOpen] = useState(false);
11742
+ const [headerMembers, setHeaderMembers] = useState(null);
10884
11743
  const [artifactsPanelWidth, setArtifactsPanelWidth] = useState(ARTIFACTS_PANEL_WIDTH_DEFAULT);
10885
11744
  const [isResizingArtifactsPanel, setIsResizingArtifactsPanel] = useState(false);
10886
11745
  const layoutContainerRef = useRef(null);
@@ -10915,6 +11774,25 @@ function ChatSessionCore({
10915
11774
  } catch {
10916
11775
  }
10917
11776
  }, [artifactsPanelStorageKey, showArtifactsPanel]);
11777
+ useEffect(() => {
11778
+ if (!session?.id || !dataSource.listSessionMembers) {
11779
+ setHeaderMembers(null);
11780
+ return;
11781
+ }
11782
+ let cancelled = false;
11783
+ dataSource.listSessionMembers(session.id).then((members) => {
11784
+ if (!cancelled) {
11785
+ setHeaderMembers(members.map((m) => m.user));
11786
+ }
11787
+ }).catch(() => {
11788
+ if (!cancelled) {
11789
+ setHeaderMembers(null);
11790
+ }
11791
+ });
11792
+ return () => {
11793
+ cancelled = true;
11794
+ };
11795
+ }, [session?.id, dataSource.listSessionMembers]);
10918
11796
  const handleArtifactsResizeStart = useCallback(() => {
10919
11797
  setIsResizingArtifactsPanel(true);
10920
11798
  }, []);
@@ -11004,8 +11882,26 @@ function ChatSessionCore({
11004
11882
  }
11005
11883
  }
11006
11884
  };
11007
- const headerActions = showArtifactsControls ? /* @__PURE__ */ jsxs(Fragment, { children: [
11008
- /* @__PURE__ */ jsxs(
11885
+ const canShowShareButton = Boolean(
11886
+ session?.access?.canManageMembers && dataSource.listUsers && dataSource.listSessionMembers && dataSource.addSessionMember && dataSource.updateSessionMemberRole && dataSource.removeSessionMember
11887
+ );
11888
+ const shareButton = canShowShareButton ? /* @__PURE__ */ jsxs(
11889
+ "button",
11890
+ {
11891
+ type: "button",
11892
+ onClick: () => setMembersModalOpen(true),
11893
+ className: "inline-flex cursor-pointer items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium text-gray-500 transition-all duration-150 hover:bg-gray-100 hover:text-gray-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200",
11894
+ "aria-label": t("BiChat.Share.Title"),
11895
+ title: t("BiChat.Share.Title"),
11896
+ children: [
11897
+ /* @__PURE__ */ jsx(ShareNetwork, { className: "h-4 w-4" }),
11898
+ t("BiChat.Share.Button")
11899
+ ]
11900
+ }
11901
+ ) : null;
11902
+ const headerActions = /* @__PURE__ */ jsxs(Fragment, { children: [
11903
+ shareButton,
11904
+ showArtifactsControls && /* @__PURE__ */ jsxs(
11009
11905
  "button",
11010
11906
  {
11011
11907
  type: "button",
@@ -11025,7 +11921,7 @@ function ChatSessionCore({
11025
11921
  }
11026
11922
  ),
11027
11923
  actionsSlot
11028
- ] }) : actionsSlot;
11924
+ ] });
11029
11925
  return /* @__PURE__ */ jsxs(
11030
11926
  "main",
11031
11927
  {
@@ -11038,7 +11934,9 @@ function ChatSessionCore({
11038
11934
  onBack,
11039
11935
  readOnly: effectiveReadOnly,
11040
11936
  logoSlot,
11041
- actionsSlot: headerActions
11937
+ actionsSlot: headerActions,
11938
+ members: headerMembers ?? (session?.owner ? [session.owner] : void 0),
11939
+ onMembersClick: canShowShareButton ? () => setMembersModalOpen(true) : void 0
11042
11940
  }
11043
11941
  ),
11044
11942
  error && /* @__PURE__ */ jsx(
@@ -11235,6 +12133,15 @@ function ChatSessionCore({
11235
12133
  ) })
11236
12134
  ]
11237
12135
  }
12136
+ ),
12137
+ canShowShareButton && /* @__PURE__ */ jsx(
12138
+ SessionMembersModal,
12139
+ {
12140
+ isOpen: membersModalOpen,
12141
+ sessionId: session?.id,
12142
+ dataSource,
12143
+ onClose: () => setMembersModalOpen(false)
12144
+ }
11238
12145
  )
11239
12146
  ]
11240
12147
  }
@@ -11257,7 +12164,7 @@ function ChatSession(props) {
11257
12164
  // ui/src/bichat/index.ts
11258
12165
  init_MarkdownRenderer();
11259
12166
  init_ChartCard();
11260
- var sizeClasses = {
12167
+ var sizeClasses2 = {
11261
12168
  sm: {
11262
12169
  container: "py-6 px-3",
11263
12170
  title: "text-sm",
@@ -11282,7 +12189,7 @@ function EmptyState({
11282
12189
  className = "",
11283
12190
  size = "md"
11284
12191
  }) {
11285
- const sizes = sizeClasses[size];
12192
+ const sizes = sizeClasses2[size];
11286
12193
  const prefersReducedMotion2 = useReducedMotion();
11287
12194
  const duration = prefersReducedMotion2 ? 0 : 0.4;
11288
12195
  return /* @__PURE__ */ jsx(
@@ -11342,7 +12249,7 @@ MemoizedEmptyState.displayName = "EmptyState";
11342
12249
 
11343
12250
  // ui/src/bichat/components/EditableText.tsx
11344
12251
  init_useTranslation();
11345
- var sizeClasses2 = {
12252
+ var sizeClasses3 = {
11346
12253
  sm: "text-sm",
11347
12254
  md: "text-base",
11348
12255
  lg: "text-lg"
@@ -11413,7 +12320,7 @@ var EditableText = forwardRef(
11413
12320
  const handleBlur = () => {
11414
12321
  handleSave();
11415
12322
  };
11416
- const sizeClass = sizeClasses2[size];
12323
+ const sizeClass = sizeClasses3[size];
11417
12324
  if (isEditing) {
11418
12325
  return /* @__PURE__ */ jsx(
11419
12326
  "div",
@@ -11473,7 +12380,7 @@ var MemoizedEditableText = memo(EditableText);
11473
12380
 
11474
12381
  // ui/src/bichat/components/SearchInput.tsx
11475
12382
  init_useTranslation();
11476
- var sizeClasses3 = {
12383
+ var sizeClasses4 = {
11477
12384
  sm: {
11478
12385
  container: "py-1.5 pl-8 pr-8 text-xs",
11479
12386
  icon: 14,
@@ -11506,7 +12413,7 @@ function SearchInput({
11506
12413
  const resolvedPlaceholder = placeholder ?? t("BiChat.Common.Search");
11507
12414
  const resolvedAriaLabel = ariaLabel ?? t("BiChat.Common.Search");
11508
12415
  const inputRef = useRef(null);
11509
- const sizes = sizeClasses3[size];
12416
+ const sizes = sizeClasses4[size];
11510
12417
  useEffect(() => {
11511
12418
  if (autoFocus && inputRef.current) {
11512
12419
  inputRef.current.focus();
@@ -11919,148 +12826,20 @@ function Toast({
11919
12826
 
11920
12827
  // ui/src/bichat/components/ToastContainer.tsx
11921
12828
  init_useTranslation();
11922
- function ToastContainer({ toasts, onDismiss, dismissLabel }) {
11923
- const { t } = useTranslation();
11924
- if (toasts.length === 0) {
11925
- return null;
11926
- }
11927
- return /* @__PURE__ */ jsx(
11928
- "div",
11929
- {
11930
- "aria-label": t("BiChat.Common.Notifications"),
11931
- className: "fixed top-6 right-6 z-[var(--bichat-z-toast,60)] flex flex-col gap-2 pointer-events-none",
11932
- children: toasts.map((toast) => /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(Toast, { ...toast, onDismiss, dismissLabel }) }, toast.id))
11933
- }
11934
- );
11935
- }
11936
-
11937
- // ui/src/bichat/components/ConfirmModal.tsx
11938
- init_useTranslation();
11939
- function ConfirmModalBase({
11940
- isOpen,
11941
- title,
11942
- message,
11943
- onConfirm,
11944
- onCancel,
11945
- confirmText,
11946
- cancelText,
11947
- isDanger = false
11948
- }) {
12829
+ function ToastContainer({ toasts, onDismiss, dismissLabel }) {
11949
12830
  const { t } = useTranslation();
11950
- const resolvedConfirmText = confirmText?.trim() ? confirmText : t("BiChat.Common.Confirm");
11951
- const resolvedCancelText = cancelText?.trim() ? cancelText : t("BiChat.Common.Cancel");
11952
- return /* @__PURE__ */ jsxs(Dialog, { open: isOpen, onClose: onCancel, className: "relative z-40", children: [
11953
- /* @__PURE__ */ jsx(DialogBackdrop, { className: "fixed inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity duration-200" }),
11954
- /* @__PURE__ */ jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50 p-4", children: /* @__PURE__ */ jsxs(DialogPanel, { className: "bg-white dark:bg-gray-800 rounded-2xl shadow-xl dark:shadow-2xl dark:shadow-black/30 max-w-sm w-full overflow-hidden", children: [
11955
- /* @__PURE__ */ jsx("div", { className: "px-6 pt-6 pb-5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3.5", children: [
11956
- isDanger && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 flex items-center justify-center w-10 h-10 rounded-xl bg-red-50 dark:bg-red-950/40 border border-red-200/60 dark:border-red-800/40", children: /* @__PURE__ */ jsx(WarningCircle, { size: 22, weight: "duotone", className: "text-red-600 dark:text-red-400" }) }),
11957
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
11958
- /* @__PURE__ */ jsx(DialogTitle, { className: "text-base font-semibold text-gray-900 dark:text-gray-100 leading-snug", children: title }),
11959
- /* @__PURE__ */ jsx(Description, { className: "mt-2 text-sm text-gray-600 dark:text-gray-400 leading-relaxed", children: message })
11960
- ] })
11961
- ] }) }),
11962
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2.5 px-6 pb-5", children: [
11963
- /* @__PURE__ */ jsx(
11964
- "button",
11965
- {
11966
- type: "button",
11967
- onClick: onCancel,
11968
- ...isDanger ? { "data-autofocus": true } : {},
11969
- className: "cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700/60 hover:bg-gray-200 dark:hover:bg-gray-700 active:bg-gray-250 dark:active:bg-gray-600 transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
11970
- "data-testid": "confirm-modal-cancel",
11971
- children: resolvedCancelText
11972
- }
11973
- ),
11974
- /* @__PURE__ */ jsx(
11975
- "button",
11976
- {
11977
- type: "button",
11978
- ...!isDanger ? { "data-autofocus": true } : {},
11979
- onClick: onConfirm,
11980
- className: [
11981
- "cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-white",
11982
- "transition-all duration-150 shadow-sm hover:shadow",
11983
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
11984
- isDanger ? "bg-red-600 hover:bg-red-700 active:bg-red-800 focus-visible:ring-red-500/50" : "bg-primary-600 hover:bg-primary-700 active:bg-primary-800 focus-visible:ring-primary-500/50"
11985
- ].join(" "),
11986
- "data-testid": "confirm-modal-confirm",
11987
- children: resolvedConfirmText
11988
- }
11989
- )
11990
- ] })
11991
- ] }) })
11992
- ] });
11993
- }
11994
- var ConfirmModal = memo(ConfirmModalBase);
11995
- ConfirmModal.displayName = "ConfirmModal";
11996
- var ConfirmModal_default = ConfirmModal;
11997
- function hashString(str) {
11998
- let hash = 0;
11999
- for (let i = 0; i < str.length; i++) {
12000
- const char = str.charCodeAt(i);
12001
- hash = (hash << 5) - hash + char;
12002
- hash = hash & hash;
12831
+ if (toasts.length === 0) {
12832
+ return null;
12003
12833
  }
12004
- return Math.abs(hash);
12005
- }
12006
- var colorPalette = [
12007
- { bg: "bg-blue-500", text: "text-white" },
12008
- { bg: "bg-green-500", text: "text-white" },
12009
- { bg: "bg-purple-500", text: "text-white" },
12010
- { bg: "bg-pink-500", text: "text-white" },
12011
- { bg: "bg-indigo-500", text: "text-white" },
12012
- { bg: "bg-teal-500", text: "text-white" },
12013
- { bg: "bg-orange-500", text: "text-white" },
12014
- { bg: "bg-cyan-500", text: "text-white" },
12015
- { bg: "bg-amber-500", text: "text-white" },
12016
- { bg: "bg-lime-500", text: "text-white" }
12017
- ];
12018
- var sizeClasses4 = {
12019
- sm: "w-8 h-8 text-xs",
12020
- md: "w-10 h-10 text-sm",
12021
- lg: "w-12 h-12 text-base"
12022
- };
12023
- function UserAvatar({
12024
- firstName,
12025
- lastName,
12026
- initials: providedInitials,
12027
- size = "md",
12028
- className = ""
12029
- }) {
12030
- const derivedInitials = (() => {
12031
- const firstChar = firstName?.trim()?.charAt(0) || "";
12032
- const lastChar = lastName?.trim()?.charAt(0) || "";
12033
- const combined = `${firstChar}${lastChar}`.trim();
12034
- return combined || "U";
12035
- })();
12036
- const initials = (providedInitials?.trim() || derivedInitials).toUpperCase();
12037
- const fullName = `${firstName}${lastName}`;
12038
- const colorIndex = hashString(fullName) % colorPalette.length;
12039
- const colors = colorPalette[colorIndex];
12040
12834
  return /* @__PURE__ */ jsx(
12041
12835
  "div",
12042
12836
  {
12043
- className: `
12044
- ${sizeClasses4[size]}
12045
- ${colors.bg}
12046
- ${colors.text}
12047
- ${className}
12048
- rounded-full
12049
- flex
12050
- items-center
12051
- justify-center
12052
- font-semibold
12053
- flex-shrink-0
12054
- select-none
12055
- `,
12056
- "aria-label": `${firstName} ${lastName}`,
12057
- title: `${firstName} ${lastName}`,
12058
- children: initials
12837
+ "aria-label": t("BiChat.Common.Notifications"),
12838
+ className: "fixed top-6 right-6 z-[var(--bichat-z-toast,60)] flex flex-col gap-2 pointer-events-none",
12839
+ children: toasts.map((toast) => /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(Toast, { ...toast, onDismiss, dismissLabel }) }, toast.id))
12059
12840
  }
12060
12841
  );
12061
12842
  }
12062
- var MemoizedUserAvatar = memo(UserAvatar);
12063
- MemoizedUserAvatar.displayName = "UserAvatar";
12064
12843
  function PermissionGuard({
12065
12844
  permissions,
12066
12845
  mode = "all",
@@ -12502,6 +13281,11 @@ var SessionItem = memo(
12502
13281
  const isTitleGenerating = !session.title?.trim();
12503
13282
  const displayTitle = isTitleGenerating ? t("BiChat.Common.Generating") : session.title ?? t("BiChat.Common.Untitled");
12504
13283
  const lastActivity = formatRelativeTime(session.updatedAt, t);
13284
+ const accessRole = session.access?.role ?? "owner";
13285
+ const roleLabel = accessRole === "editor" ? t("BiChat.Share.RoleEditor") : accessRole === "viewer" ? t("BiChat.Share.RoleViewer") : accessRole === "read_all" ? t("BiChat.Share.RoleReadOnly") : "";
13286
+ const visibilityLabel = session.isGroup ? t("BiChat.Sidebar.GroupChat") : accessRole === "editor" || accessRole === "viewer" ? t("BiChat.Sidebar.SharedWithYou") : "";
13287
+ const isGroupOrShared = Boolean(session.isGroup || session.memberCount && session.memberCount > 1);
13288
+ const metaParts = [lastActivity, visibilityLabel, roleLabel].filter(Boolean);
12505
13289
  const { handlers: longPressHandlers } = useLongPress({
12506
13290
  delay: 500,
12507
13291
  onLongPress: (e) => {
@@ -12643,17 +13427,23 @@ var SessionItem = memo(
12643
13427
  "data-testid": `${testIdPrefix}-session-${session.id}`,
12644
13428
  ...longPressHandlers,
12645
13429
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
12646
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
12647
- /* @__PURE__ */ jsx(
12648
- MemoizedEditableText,
12649
- {
12650
- ref: editableTitleRef,
12651
- value: displayTitle,
12652
- onSave: (newTitle) => onRename?.(newTitle),
12653
- isLoading: isTitleGenerating
12654
- }
12655
- ),
12656
- /* @__PURE__ */ jsx("span", { className: "text-[11px] text-gray-400 dark:text-gray-500 truncate mt-0.5", children: lastActivity })
13430
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 min-w-0 flex-1", children: [
13431
+ isGroupOrShared && /* @__PURE__ */ jsx(UsersThree, { size: 14, weight: "duotone", className: "text-primary-500 dark:text-primary-400 mt-1 flex-shrink-0" }),
13432
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
13433
+ /* @__PURE__ */ jsx(
13434
+ MemoizedEditableText,
13435
+ {
13436
+ ref: editableTitleRef,
13437
+ value: displayTitle,
13438
+ onSave: (newTitle) => onRename?.(newTitle),
13439
+ isLoading: isTitleGenerating
13440
+ }
13441
+ ),
13442
+ /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-gray-400 dark:text-gray-500 truncate mt-0.5", children: [
13443
+ metaParts.join(" \u2022 "),
13444
+ isGroupOrShared && session.memberCount && session.memberCount > 0 && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center ml-1 rounded-full bg-primary-50 dark:bg-primary-900/30 px-1.5 text-[10px] font-medium text-primary-600 dark:text-primary-400", children: session.memberCount })
13445
+ ] })
13446
+ ] })
12657
13447
  ] }),
12658
13448
  !isTouch && hasContextMenu && /* @__PURE__ */ jsxs(Menu, { children: [
12659
13449
  /* @__PURE__ */ jsx(
@@ -13007,24 +13797,23 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
13007
13797
  setOffset((prev) => prev + limit);
13008
13798
  }
13009
13799
  }, [fetching, hasMore]);
13010
- const loadMoreRef = useCallback(
13011
- (node) => {
13012
- if (!node || fetching || !hasMore) {
13013
- return;
13800
+ const loadMoreNodeRef = useRef(null);
13801
+ const loadMoreRef = useCallback((node) => {
13802
+ loadMoreNodeRef.current = node;
13803
+ }, []);
13804
+ useEffect(() => {
13805
+ const node = loadMoreNodeRef.current;
13806
+ if (!node || fetching || !hasMore) {
13807
+ return;
13808
+ }
13809
+ const observer = new IntersectionObserver((entries) => {
13810
+ if (entries[0].isIntersecting) {
13811
+ handleLoadMore();
13014
13812
  }
13015
- const observer = new IntersectionObserver(
13016
- (entries) => {
13017
- if (entries[0].isIntersecting) {
13018
- handleLoadMore();
13019
- }
13020
- },
13021
- { threshold: 0.1 }
13022
- );
13023
- observer.observe(node);
13024
- return () => observer.disconnect();
13025
- },
13026
- [fetching, hasMore, handleLoadMore]
13027
- );
13813
+ }, { threshold: 0.1 });
13814
+ observer.observe(node);
13815
+ return () => observer.disconnect();
13816
+ }, [fetching, hasMore, handleLoadMore]);
13028
13817
  const derivedUsers = useMemo(() => {
13029
13818
  if (dataSource.listUsers) {
13030
13819
  return users;
@@ -13082,57 +13871,61 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
13082
13871
  role: "list",
13083
13872
  "aria-label": t("BiChat.AllChats.OrganizationChatSessions"),
13084
13873
  children: [
13085
- chats.map((chat) => /* @__PURE__ */ jsx(
13086
- motion.div,
13087
- {
13088
- initial: { opacity: 0, y: -10 },
13089
- animate: { opacity: 1, y: 0 },
13090
- exit: { opacity: 0, y: -10 },
13091
- children: /* @__PURE__ */ jsx(
13092
- "div",
13093
- {
13094
- role: "link",
13095
- tabIndex: 0,
13096
- onClick: () => onSessionSelect(chat.id),
13097
- onKeyDown: (e) => {
13098
- if (e.key === "Enter" || e.key === " ") {
13099
- e.preventDefault();
13100
- onSessionSelect(chat.id);
13101
- }
13102
- },
13103
- className: `
13874
+ chats.map((chat) => {
13875
+ const owner = chat.owner ?? {
13876
+ firstName: "",
13877
+ lastName: "",
13878
+ initials: "U"
13879
+ };
13880
+ const ownerName = [owner.firstName, owner.lastName].filter(Boolean).join(" ");
13881
+ return /* @__PURE__ */ jsx(
13882
+ motion.div,
13883
+ {
13884
+ initial: { opacity: 0, y: -10 },
13885
+ animate: { opacity: 1, y: 0 },
13886
+ exit: { opacity: 0, y: -10 },
13887
+ children: /* @__PURE__ */ jsx(
13888
+ "div",
13889
+ {
13890
+ role: "link",
13891
+ tabIndex: 0,
13892
+ onClick: () => onSessionSelect(chat.id),
13893
+ onKeyDown: (e) => {
13894
+ if (e.key === "Enter" || e.key === " ") {
13895
+ e.preventDefault();
13896
+ onSessionSelect(chat.id);
13897
+ }
13898
+ },
13899
+ className: `
13104
13900
  block px-3 py-2 rounded-lg transition-smooth group cursor-pointer
13105
13901
  ${chat.id === activeSessionId ? "bg-primary-50/50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-400 border-l-4 border-primary-400 dark:border-primary-600" : "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 border-l-4 border-transparent"}
13106
13902
  `,
13107
- "aria-current": chat.id === activeSessionId ? "page" : void 0,
13108
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
13109
- /* @__PURE__ */ jsx(
13110
- MemoizedUserAvatar,
13111
- {
13112
- firstName: chat.owner.firstName,
13113
- lastName: chat.owner.lastName,
13114
- initials: chat.owner.initials,
13115
- size: "sm"
13116
- }
13117
- ),
13118
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
13119
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: chat.title || t("BiChat.Common.Untitled") }),
13120
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: [
13121
- chat.owner.firstName,
13122
- " ",
13123
- chat.owner.lastName
13124
- ] }),
13125
- chat.status === "archived" && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 mt-1 px-2 py-0.5 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded-full text-xs", children: [
13126
- /* @__PURE__ */ jsx(Archive, { size: 12, className: "w-3 h-3" }),
13127
- t("BiChat.Chat.Archived")
13903
+ "aria-current": chat.id === activeSessionId ? "page" : void 0,
13904
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
13905
+ /* @__PURE__ */ jsx(
13906
+ MemoizedUserAvatar,
13907
+ {
13908
+ firstName: owner.firstName,
13909
+ lastName: owner.lastName,
13910
+ initials: owner.initials,
13911
+ size: "sm"
13912
+ }
13913
+ ),
13914
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
13915
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: chat.title || t("BiChat.Common.Untitled") }),
13916
+ ownerName && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: ownerName }),
13917
+ chat.status === "archived" && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 mt-1 px-2 py-0.5 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded-full text-xs", children: [
13918
+ /* @__PURE__ */ jsx(Archive, { size: 12, className: "w-3 h-3" }),
13919
+ t("BiChat.Chat.Archived")
13920
+ ] })
13128
13921
  ] })
13129
13922
  ] })
13130
- ] })
13131
- }
13132
- )
13133
- },
13134
- chat.id
13135
- )),
13923
+ }
13924
+ )
13925
+ },
13926
+ chat.id
13927
+ );
13928
+ }),
13136
13929
  hasMore && /* @__PURE__ */ jsx("div", { ref: loadMoreRef, className: "py-4 text-center", children: fetching ? /* @__PURE__ */ jsx(SessionSkeleton, { count: 2 }) : /* @__PURE__ */ jsx(
13137
13930
  "button",
13138
13931
  {
@@ -13902,19 +14695,22 @@ function Sidebar2({
13902
14695
  animate: "visible",
13903
14696
  role: "list",
13904
14697
  "aria-label": t("BiChat.Sidebar.PinnedChats"),
13905
- children: pinnedSessions.map((session) => /* @__PURE__ */ jsx(
13906
- SessionItem_default,
13907
- {
13908
- session,
13909
- isActive: session.id === activeSessionId,
13910
- onSelect: () => handleSessionSelect(session.id),
13911
- onArchive: () => handleSessionArchive(session.id),
13912
- onPin: () => handleSessionPin(session.id, session.pinned),
13913
- onRename: (newTitle) => handleSessionRename(session.id, newTitle),
13914
- onRegenerateTitle: () => handleSessionRegenerateTitle(session.id)
13915
- },
13916
- session.id
13917
- ))
14698
+ children: pinnedSessions.map((session) => {
14699
+ const canWrite = session.access?.canWrite ?? true;
14700
+ return /* @__PURE__ */ jsx(
14701
+ SessionItem_default,
14702
+ {
14703
+ session,
14704
+ isActive: session.id === activeSessionId,
14705
+ onSelect: () => handleSessionSelect(session.id),
14706
+ onArchive: canWrite ? () => handleSessionArchive(session.id) : void 0,
14707
+ onPin: canWrite ? () => handleSessionPin(session.id, session.pinned) : void 0,
14708
+ onRename: canWrite ? (newTitle) => handleSessionRename(session.id, newTitle) : void 0,
14709
+ onRegenerateTitle: canWrite ? () => handleSessionRegenerateTitle(session.id) : void 0
14710
+ },
14711
+ session.id
14712
+ );
14713
+ })
13918
14714
  }
13919
14715
  ),
13920
14716
  /* @__PURE__ */ jsx("div", { className: "border-b border-gray-200 dark:border-gray-700 my-3" })
@@ -13936,19 +14732,22 @@ function Sidebar2({
13936
14732
  animate: "visible",
13937
14733
  role: "list",
13938
14734
  "aria-label": `${group.name} chats`,
13939
- children: group.sessions.map((session) => /* @__PURE__ */ jsx(
13940
- SessionItem_default,
13941
- {
13942
- session,
13943
- isActive: session.id === activeSessionId,
13944
- onSelect: () => handleSessionSelect(session.id),
13945
- onArchive: () => handleSessionArchive(session.id),
13946
- onPin: () => handleSessionPin(session.id, session.pinned),
13947
- onRename: (newTitle) => handleSessionRename(session.id, newTitle),
13948
- onRegenerateTitle: () => handleSessionRegenerateTitle(session.id)
13949
- },
13950
- session.id
13951
- ))
14735
+ children: group.sessions.map((session) => {
14736
+ const canWrite = session.access?.canWrite ?? true;
14737
+ return /* @__PURE__ */ jsx(
14738
+ SessionItem_default,
14739
+ {
14740
+ session,
14741
+ isActive: session.id === activeSessionId,
14742
+ onSelect: () => handleSessionSelect(session.id),
14743
+ onArchive: canWrite ? () => handleSessionArchive(session.id) : void 0,
14744
+ onPin: canWrite ? () => handleSessionPin(session.id, session.pinned) : void 0,
14745
+ onRename: canWrite ? (newTitle) => handleSessionRename(session.id, newTitle) : void 0,
14746
+ onRegenerateTitle: canWrite ? () => handleSessionRegenerateTitle(session.id) : void 0
14747
+ },
14748
+ session.id
14749
+ );
14750
+ })
13952
14751
  }
13953
14752
  )
13954
14753
  ] }, group.name)),
@@ -16109,6 +16908,77 @@ function useScrollToBottom(items) {
16109
16908
  scrollToBottom
16110
16909
  };
16111
16910
  }
16911
+ function useHttpDataSourceConfigFromApplet(options) {
16912
+ return useMemo(() => {
16913
+ const ctx = typeof window !== "undefined" ? window.__APPLET_CONTEXT__ : void 0;
16914
+ if (!ctx) {
16915
+ throw new Error(
16916
+ "Applet context not found. Ensure window.__APPLET_CONTEXT__ is injected by the backend."
16917
+ );
16918
+ }
16919
+ const rpcEndpoint = ctx.config?.rpcUIEndpoint ?? "/rpc";
16920
+ const streamEndpoint = ctx.config?.streamEndpoint ?? "/stream";
16921
+ const csrfToken = ctx.session?.csrfToken ?? (typeof window !== "undefined" ? window.__CSRF_TOKEN__ : void 0) ?? "";
16922
+ const isDev = typeof import.meta.env?.DEV === "boolean" && import.meta.env?.DEV;
16923
+ if (!csrfToken && isDev) {
16924
+ console.warn(
16925
+ "[useHttpDataSourceConfigFromApplet] CSRF token is empty \u2014 requests may be rejected by the server."
16926
+ );
16927
+ }
16928
+ return {
16929
+ baseUrl: "",
16930
+ rpcEndpoint,
16931
+ streamEndpoint,
16932
+ csrfToken,
16933
+ rpcTimeoutMs: options?.rpcTimeoutMs ?? 12e4,
16934
+ streamConnectTimeoutMs: options?.streamConnectTimeoutMs ?? 3e4
16935
+ };
16936
+ }, [options?.rpcTimeoutMs, options?.streamConnectTimeoutMs]);
16937
+ }
16938
+ var SESSION_PATH_REGEX = /\/session\/([^/]+)/;
16939
+ function useBichatRouter({
16940
+ navigate,
16941
+ pathname,
16942
+ onNavigate
16943
+ }) {
16944
+ const activeSessionId = useMemo(
16945
+ () => pathname.match(SESSION_PATH_REGEX)?.[1],
16946
+ [pathname]
16947
+ );
16948
+ const maybeClose = useCallback(() => {
16949
+ onNavigate?.();
16950
+ }, [onNavigate]);
16951
+ const onSessionSelect = useCallback(
16952
+ (sessionId) => {
16953
+ if (sessionId) {
16954
+ navigate(`/session/${sessionId}`);
16955
+ } else {
16956
+ navigate("/");
16957
+ }
16958
+ maybeClose();
16959
+ },
16960
+ [navigate, maybeClose]
16961
+ );
16962
+ const onNewChat = useCallback(() => {
16963
+ navigate("/");
16964
+ maybeClose();
16965
+ }, [navigate, maybeClose]);
16966
+ const onArchivedView = useCallback(() => {
16967
+ navigate("/archived");
16968
+ maybeClose();
16969
+ }, [navigate, maybeClose]);
16970
+ const onBack = useCallback(() => {
16971
+ navigate("/");
16972
+ maybeClose();
16973
+ }, [navigate, maybeClose]);
16974
+ return {
16975
+ activeSessionId,
16976
+ onSessionSelect,
16977
+ onNewChat,
16978
+ onArchivedView,
16979
+ onBack
16980
+ };
16981
+ }
16112
16982
 
16113
16983
  // ui/src/bichat/index.ts
16114
16984
  init_IotaContext();
@@ -16412,10 +17282,59 @@ function resolveArtifactName(artifact) {
16412
17282
  }
16413
17283
  return `${label} artifact`;
16414
17284
  }
17285
+ function mapSessionUser(rawUser) {
17286
+ if (!isRecord2(rawUser)) {
17287
+ return void 0;
17288
+ }
17289
+ const rawId = rawUser.id;
17290
+ const id = readNonEmptyString(rawId) ?? (typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : null);
17291
+ if (!id) {
17292
+ return void 0;
17293
+ }
17294
+ const firstName = readString2(rawUser.firstName);
17295
+ const lastName = readString2(rawUser.lastName);
17296
+ const initials = readNonEmptyString(rawUser.initials) || `${firstName.charAt(0)}${lastName.charAt(0)}`.trim().toUpperCase() || "U";
17297
+ return {
17298
+ id,
17299
+ firstName,
17300
+ lastName,
17301
+ initials
17302
+ };
17303
+ }
17304
+ function mapSessionAccess(rawAccess) {
17305
+ if (!isRecord2(rawAccess)) {
17306
+ return void 0;
17307
+ }
17308
+ const role = readString2(rawAccess.role).toLowerCase();
17309
+ const source = readString2(rawAccess.source).toLowerCase();
17310
+ const normalizedRole = role === "owner" || role === "editor" || role === "viewer" || role === "read_all" ? role : "none";
17311
+ const normalizedSource = source === "owner" || source === "member" || source === "permission" ? source : "none";
17312
+ const canRead = rawAccess.canRead === true || rawAccess.canRead === "true";
17313
+ const canWrite = rawAccess.canWrite === true || rawAccess.canWrite === "true";
17314
+ const canManageMembers = rawAccess.canManageMembers === true || rawAccess.canManageMembers === "true";
17315
+ if (normalizedRole === "none" && normalizedSource === "none" && !canRead && !canWrite && !canManageMembers) {
17316
+ return void 0;
17317
+ }
17318
+ return {
17319
+ role: normalizedRole,
17320
+ source: normalizedSource,
17321
+ canRead,
17322
+ canWrite,
17323
+ canManageMembers
17324
+ };
17325
+ }
16415
17326
  function toSession(session) {
16416
17327
  return {
16417
- ...session,
16418
- status: session.status === "archived" ? "archived" : "active"
17328
+ id: readString2(session.id),
17329
+ title: readString2(session.title),
17330
+ status: session.status === "archived" ? "archived" : "active",
17331
+ pinned: Boolean(session.pinned),
17332
+ createdAt: readString2(session.createdAt),
17333
+ updatedAt: readString2(session.updatedAt),
17334
+ owner: mapSessionUser(session.owner),
17335
+ isGroup: Boolean(session.isGroup),
17336
+ memberCount: typeof session.memberCount === "number" ? session.memberCount : void 0,
17337
+ access: mapSessionAccess(session.access)
16419
17338
  };
16420
17339
  }
16421
17340
  function toSessionArtifact(artifact) {
@@ -16689,6 +17608,7 @@ function sanitizeConversationTurn(rawTurn, index, fallbackSessionID) {
16689
17608
  id: userTurnID,
16690
17609
  content: readString2(rawTurn.userTurn.content),
16691
17610
  attachments: sanitizeUserAttachments(rawTurn.userTurn.attachments, turnID),
17611
+ author: mapSessionUser(rawTurn.userTurn.author),
16692
17612
  createdAt: readString2(rawTurn.userTurn.createdAt, createdAt)
16693
17613
  },
16694
17614
  assistantTurn: sanitizeAssistantTurn(rawTurn.assistantTurn, createdAt, turnID),
@@ -17179,7 +18099,85 @@ async function clearSessionHistory(callRPC, sessionId) {
17179
18099
  return callRPC("bichat.session.clear", { id: sessionId });
17180
18100
  }
17181
18101
  async function compactSessionHistory(callRPC, sessionId) {
17182
- return callRPC("bichat.session.compact", { id: sessionId });
18102
+ const result = await callRPC("bichat.session.compact", { id: sessionId });
18103
+ if (!result.accepted) {
18104
+ throw new Error("Session compact request was not accepted");
18105
+ }
18106
+ if (result.operation !== "session_compact") {
18107
+ throw new Error(`Unexpected async operation: ${result.operation}`);
18108
+ }
18109
+ if (!result.sessionId || !result.runId) {
18110
+ throw new Error("Missing async run metadata");
18111
+ }
18112
+ return {
18113
+ accepted: true,
18114
+ operation: result.operation,
18115
+ sessionId: result.sessionId,
18116
+ runId: result.runId,
18117
+ startedAt: result.startedAt
18118
+ };
18119
+ }
18120
+ async function listUsers(callRPC) {
18121
+ const data = await callRPC("bichat.user.list", {});
18122
+ return data.users.map((user) => ({
18123
+ id: String(user.id),
18124
+ firstName: user.firstName || "",
18125
+ lastName: user.lastName || "",
18126
+ initials: user.initials || ""
18127
+ }));
18128
+ }
18129
+ async function listAllSessions(callRPC, options) {
18130
+ const data = await callRPC("bichat.session.listAll", {
18131
+ limit: options?.limit ?? 50,
18132
+ offset: options?.offset ?? 0,
18133
+ includeArchived: options?.includeArchived ?? false,
18134
+ userId: options?.userId ?? null
18135
+ });
18136
+ return {
18137
+ sessions: data.sessions.map(toSession),
18138
+ total: typeof data.total === "number" ? data.total : data.sessions.length,
18139
+ hasMore: Boolean(data.hasMore)
18140
+ };
18141
+ }
18142
+ async function listSessionMembers(callRPC, sessionId) {
18143
+ const data = await callRPC("bichat.session.members.list", { sessionId });
18144
+ return data.members.map((member) => ({
18145
+ user: {
18146
+ id: String(member.user.id),
18147
+ firstName: member.user.firstName,
18148
+ lastName: member.user.lastName,
18149
+ initials: member.user.initials
18150
+ },
18151
+ role: (() => {
18152
+ const normalizedRole = (member.role || "").toLowerCase();
18153
+ if (normalizedRole === "owner") {
18154
+ return "owner";
18155
+ }
18156
+ if (normalizedRole === "editor") {
18157
+ return "editor";
18158
+ }
18159
+ return "viewer";
18160
+ })(),
18161
+ createdAt: member.createdAt,
18162
+ updatedAt: member.updatedAt
18163
+ }));
18164
+ }
18165
+ async function addSessionMember(callRPC, sessionId, userId, role) {
18166
+ await callRPC("bichat.session.members.add", {
18167
+ sessionId,
18168
+ userId,
18169
+ role: role.toUpperCase()
18170
+ });
18171
+ }
18172
+ async function updateSessionMemberRole(callRPC, sessionId, userId, role) {
18173
+ await callRPC("bichat.session.members.updateRole", {
18174
+ sessionId,
18175
+ userId,
18176
+ role: role.toUpperCase()
18177
+ });
18178
+ }
18179
+ async function removeSessionMember(callRPC, sessionId, userId) {
18180
+ await callRPC("bichat.session.members.remove", { sessionId, userId });
17183
18181
  }
17184
18182
 
17185
18183
  // ui/src/bichat/utils/sseParser.ts
@@ -17236,6 +18234,9 @@ var TERMINAL_TYPES = /* @__PURE__ */ new Set(["done", "error"]);
17236
18234
  async function* parseBichatStream(reader) {
17237
18235
  let yieldedTerminal = false;
17238
18236
  for await (const event of parseSSEStream(reader)) {
18237
+ if (event.type === "ping") {
18238
+ continue;
18239
+ }
17239
18240
  const parsed = event;
17240
18241
  const inferredType = parsed.type || (parsed.content ? "content" : "error");
17241
18242
  const normalized = {
@@ -17573,7 +18574,7 @@ async function* sendMessage(deps, sessionId, content, attachments = [], signal,
17573
18574
  replaceFromMessageId: options?.replaceFromMessageID,
17574
18575
  attachments: streamAttachments
17575
18576
  };
17576
- const timeoutMs = deps.timeout ?? 0;
18577
+ const timeoutMs = deps.streamConnectTimeoutMs ?? 0;
17577
18578
  if (timeoutMs > 0) {
17578
18579
  connectionTimeoutID = setTimeout(() => {
17579
18580
  connectionTimedOut = true;
@@ -17608,7 +18609,7 @@ async function* sendMessage(deps, sessionId, content, attachments = [], signal,
17608
18609
  if (err.name === "AbortError") {
17609
18610
  yield {
17610
18611
  type: "error",
17611
- error: connectionTimedOut ? `Stream request timed out after ${deps.timeout}ms` : "Stream cancelled"
18612
+ error: connectionTimedOut ? `Stream request timed out after ${deps.streamConnectTimeoutMs}ms` : "Stream cancelled"
17612
18613
  };
17613
18614
  } else {
17614
18615
  yield {
@@ -17696,7 +18697,7 @@ async function resumeStream(deps, sessionId, runId, onChunk, signal) {
17696
18697
  const url = buildStreamUrl(deps, "/resume");
17697
18698
  const controller = new AbortController();
17698
18699
  let timeoutId;
17699
- const timeoutMs = deps.timeout;
18700
+ const timeoutMs = deps.connectTimeoutMs;
17700
18701
  if (timeoutMs != null && timeoutMs > 0) {
17701
18702
  timeoutId = setTimeout(() => controller.abort(), timeoutMs);
17702
18703
  }
@@ -17713,6 +18714,10 @@ async function resumeStream(deps, sessionId, runId, onChunk, signal) {
17713
18714
  if (!response.ok) {
17714
18715
  throw new Error(`Resume stream failed: HTTP ${response.status}`);
17715
18716
  }
18717
+ if (timeoutId !== void 0) {
18718
+ clearTimeout(timeoutId);
18719
+ timeoutId = void 0;
18720
+ }
17716
18721
  if (!response.body) {
17717
18722
  throw new Error("Resume response body is null");
17718
18723
  }
@@ -17746,11 +18751,7 @@ async function submitQuestionAnswers(callRPC, sessionId, questionId, answers) {
17746
18751
  });
17747
18752
  return {
17748
18753
  success: true,
17749
- data: {
17750
- session: toSession(result.session),
17751
- turns: normalizeTurns(sanitizeConversationTurns(result.turns, sessionId)),
17752
- pendingQuestion: sanitizePendingQuestion(result.pendingQuestion, sessionId)
17753
- }
18754
+ data: normalizeAsyncRunAccepted(result)
17754
18755
  };
17755
18756
  } catch (err) {
17756
18757
  return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
@@ -17758,12 +18759,33 @@ async function submitQuestionAnswers(callRPC, sessionId, questionId, answers) {
17758
18759
  }
17759
18760
  async function rejectPendingQuestion(callRPC, sessionId) {
17760
18761
  try {
17761
- await callRPC("bichat.question.reject", { sessionId });
17762
- return { success: true };
18762
+ const result = await callRPC("bichat.question.reject", { sessionId });
18763
+ return { success: true, data: normalizeAsyncRunAccepted(result) };
17763
18764
  } catch (err) {
17764
18765
  return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
17765
18766
  }
17766
18767
  }
18768
+ function isAsyncRunOperation(value) {
18769
+ return value === "question_submit" || value === "question_reject" || value === "session_compact";
18770
+ }
18771
+ function normalizeAsyncRunAccepted(input) {
18772
+ if (!input.accepted) {
18773
+ throw new Error("Async run request was not accepted");
18774
+ }
18775
+ if (!isAsyncRunOperation(input.operation)) {
18776
+ throw new Error(`Unexpected async operation: ${input.operation}`);
18777
+ }
18778
+ if (!input.sessionId || !input.runId) {
18779
+ throw new Error("Missing async run metadata");
18780
+ }
18781
+ return {
18782
+ accepted: true,
18783
+ operation: input.operation,
18784
+ sessionId: input.sessionId,
18785
+ runId: input.runId,
18786
+ startedAt: input.startedAt
18787
+ };
18788
+ }
17767
18789
 
17768
18790
  // ui/src/bichat/data/ArtifactManager.ts
17769
18791
  async function fetchSessionArtifacts(callRPC, sessionId, options) {
@@ -17793,7 +18815,12 @@ async function uploadSessionArtifacts(callRPC, sessionId, files, uploadFileFn) {
17793
18815
  const data = await callRPC("bichat.session.uploadArtifacts", {
17794
18816
  sessionId,
17795
18817
  attachments: uploads.map((upload) => ({
17796
- uploadId: upload.id
18818
+ id: String(upload.id),
18819
+ filename: upload.name,
18820
+ uploadId: upload.id,
18821
+ mimeType: upload.mimetype || "application/octet-stream",
18822
+ sizeBytes: upload.size,
18823
+ url: upload.url
17797
18824
  }))
17798
18825
  });
17799
18826
  return {
@@ -17830,15 +18857,13 @@ var HttpDataSource = class {
17830
18857
  this.config = {
17831
18858
  streamEndpoint: "/stream",
17832
18859
  uploadEndpoint: "/api/uploads",
17833
- timeout: 12e4,
17834
- ...config
18860
+ ...config,
18861
+ rpcTimeoutMs: typeof config.rpcTimeoutMs === "number" ? config.rpcTimeoutMs : 12e4,
18862
+ streamConnectTimeoutMs: typeof config.streamConnectTimeoutMs === "number" ? config.streamConnectTimeoutMs : 3e4
17835
18863
  };
17836
- if (config.navigateToSession) {
17837
- this.navigateToSession = config.navigateToSession;
17838
- }
17839
18864
  this.rpc = createAppletRPCClient({
17840
18865
  endpoint: `${this.config.baseUrl}${this.config.rpcEndpoint}`,
17841
- timeoutMs: this.config.timeout
18866
+ timeoutMs: this.config.rpcTimeoutMs
17842
18867
  });
17843
18868
  }
17844
18869
  // -------------------------------------------------------------------------
@@ -17920,6 +18945,24 @@ var HttpDataSource = class {
17920
18945
  async compactSessionHistory(sessionId) {
17921
18946
  return compactSessionHistory(this.boundCallRPC, sessionId);
17922
18947
  }
18948
+ async listUsers() {
18949
+ return listUsers(this.boundCallRPC);
18950
+ }
18951
+ async listAllSessions(options) {
18952
+ return listAllSessions(this.boundCallRPC, options);
18953
+ }
18954
+ async listSessionMembers(sessionId) {
18955
+ return listSessionMembers(this.boundCallRPC, sessionId);
18956
+ }
18957
+ async addSessionMember(sessionId, userId, role) {
18958
+ return addSessionMember(this.boundCallRPC, sessionId, userId, role);
18959
+ }
18960
+ async updateSessionMemberRole(sessionId, userId, role) {
18961
+ return updateSessionMemberRole(this.boundCallRPC, sessionId, userId, role);
18962
+ }
18963
+ async removeSessionMember(sessionId, userId) {
18964
+ return removeSessionMember(this.boundCallRPC, sessionId, userId);
18965
+ }
17923
18966
  // -------------------------------------------------------------------------
17924
18967
  // Message transport (delegates to MessageTransport)
17925
18968
  // -------------------------------------------------------------------------
@@ -17940,7 +18983,7 @@ var HttpDataSource = class {
17940
18983
  baseUrl: this.config.baseUrl,
17941
18984
  streamEndpoint: this.config.streamEndpoint,
17942
18985
  createHeaders: (h) => this.createHeaders(h),
17943
- timeoutMs: this.config.timeout
18986
+ timeoutMs: this.config.rpcTimeoutMs
17944
18987
  },
17945
18988
  sessionId
17946
18989
  );
@@ -17951,7 +18994,7 @@ var HttpDataSource = class {
17951
18994
  baseUrl: this.config.baseUrl,
17952
18995
  streamEndpoint: this.config.streamEndpoint,
17953
18996
  createHeaders: (h) => this.createHeaders(h),
17954
- timeout: this.config.timeout
18997
+ connectTimeoutMs: this.config.streamConnectTimeoutMs
17955
18998
  },
17956
18999
  sessionId,
17957
19000
  runId,
@@ -17975,7 +19018,8 @@ var HttpDataSource = class {
17975
19018
  callRPC: this.boundCallRPC,
17976
19019
  baseUrl: this.config.baseUrl,
17977
19020
  streamEndpoint: this.config.streamEndpoint,
17978
- timeout: this.config.timeout,
19021
+ rpcTimeoutMs: this.config.rpcTimeoutMs,
19022
+ streamConnectTimeoutMs: this.config.streamConnectTimeoutMs,
17979
19023
  createHeaders: (additional) => this.createHeaders(additional),
17980
19024
  uploadFileFn: this.boundUploadFile,
17981
19025
  logAttachmentLifecycle: () => {
@@ -18026,22 +19070,11 @@ var HttpDataSource = class {
18026
19070
  async deleteSessionArtifact(artifactId) {
18027
19071
  return deleteSessionArtifact(this.boundCallRPC, artifactId);
18028
19072
  }
18029
- // -------------------------------------------------------------------------
18030
- // Navigation (optional, deprecated)
18031
- // -------------------------------------------------------------------------
18032
- /**
18033
- * @deprecated Pass `onSessionCreated` to `ChatSessionProvider` instead.
18034
- */
18035
- navigateToSession(sessionId) {
18036
- if (typeof window !== "undefined") {
18037
- window.location.href = `/chat/${sessionId}`;
18038
- }
18039
- }
18040
19073
  };
18041
19074
  function createHttpDataSource(config) {
18042
19075
  return new HttpDataSource(config);
18043
19076
  }
18044
19077
 
18045
- export { ATTACHMENT_ACCEPT_ATTRIBUTE, ActionButton, ActivityTrace, Alert_default as Alert, AllChatsList, ArchiveBanner_default as ArchiveBanner, ArchivedChatList, AssistantMessage, AssistantTurnView, MemoizedAttachmentGrid as AttachmentGrid, AttachmentPreview_default as AttachmentPreview, AttachmentUpload_default as AttachmentUpload, Avatar, BiChatLayout, Bubble, CHART_VISUAL, ChartCard, ChatHeader, ChatMachine, ChatSession, ChatSessionProvider, MemoizedCodeBlock as CodeBlock, CodeOutputsPanel, CompactionDoodle, ConfigProvider, ConfirmModal, ConfirmationStep, DateGroupHeader, DebugPanel, DefaultErrorContent, DownloadCard, MemoizedEditableText as EditableText, MemoizedEmptyState as EmptyState, ErrorBoundary, HttpDataSource, ImageModal, InlineQuestionForm, InteractiveTableCard, IotaContextProvider, ListItemSkeleton, MemoizedLoadingSpinner as LoadingSpinner, MemoizedMarkdownRenderer as MarkdownRenderer, MessageActions, MessageInput, MessageList, MessageRole, PermissionGuard, QuestionForm, QuestionStep, RateLimiter, RetryActionArea, ScreenReaderAnnouncer, ScrollToBottomButton, MemoizedSearchInput as SearchInput, SessionArtifactList, SessionArtifactPreview, SessionArtifactsPanel, SessionItem_default as SessionItem, SessionSkeleton, Sidebar2 as Sidebar, MemoizedSkeleton as Skeleton, SkeletonAvatar, SkeletonCard, SkeletonGroup, SkeletonText, SkipLink, Slot, SourcesPanel, StreamError, StreamingCursor, SystemMessage, TabbedChartGroup, TabbedTableGroup, TableExportButton, TableWithExport, ThemeProvider, Toast, ToastContainer, TouchContextMenu, Turn, TurnBubble, MemoizedTypingIndicator as TypingIndicator, MemoizedUserAvatar as UserAvatar, MemoizedUserFilter as UserFilter, UserMessage, UserTurnView, WelcomeContent, addCSRFHeader, backdropVariants, buttonVariants, convertToBase64, createDataUrl, createHeadersWithCSRF, createHttpDataSource, darkTheme, dropdownVariants, errorMessageVariants, fadeInUpVariants, fadeInVariants, floatingButtonVariants, formatFileSize, getCSRFToken, getFileVisual, getToolLabel, getValidChildren, groupSessionsByDate, groupSteps, hasPermission, isImageMimeType, isPermissionDeniedError, lightTheme, listItemVariants, messageContainerVariants, messageVariants, parseBichatStream, parseBichatStreamEvents, parseSSEStream, scaleFadeVariants, sessionItemVariants, staggerContainerVariants, toErrorDisplay, typingDotVariants, useActionButtonContext, useAttachments, useAutoScroll, useAvatarContext, useBubbleContext, useChatInput, useChatMessaging, useChatSession, useConfig, useDataTable, useFocusTrap, useImageGallery, useIotaContext, useKeyboardShortcuts, useLongPress, useMarkdownCopy, useMessageActions, useModalLock, useOptionalChatMessaging, useRequiredConfig, useScrollToBottom, useSidebarState, useStreaming2 as useStreaming, useTheme, useToast, useTranslation, useTurnContext, validateAttachmentFile, validateFileCount, validateImageFile, verbTransitionVariants };
19078
+ export { ATTACHMENT_ACCEPT_ATTRIBUTE, ActionButton, ActivityTrace, Alert_default as Alert, AllChatsList, ArchiveBanner_default as ArchiveBanner, ArchivedChatList, AssistantMessage, AssistantTurnView, MemoizedAttachmentGrid as AttachmentGrid, AttachmentPreview_default as AttachmentPreview, AttachmentUpload_default as AttachmentUpload, Avatar, AvatarStack, BiChatLayout, Bubble, CHART_VISUAL, ChartCard, ChatHeader, ChatMachine, ChatSession, ChatSessionProvider, MemoizedCodeBlock as CodeBlock, CodeOutputsPanel, CompactionDoodle, ConfigProvider, ConfirmModal, ConfirmationStep, DateGroupHeader, DebugPanel, DefaultErrorContent, DownloadCard, MemoizedEditableText as EditableText, MemoizedEmptyState as EmptyState, ErrorBoundary, HttpDataSource, ImageModal, InlineQuestionForm, InteractiveTableCard, IotaContextProvider, ListItemSkeleton, MemoizedLoadingSpinner as LoadingSpinner, MemoizedMarkdownRenderer as MarkdownRenderer, MessageActions, MessageInput, MessageList, MessageRole, PermissionGuard, QuestionForm, QuestionStep, RateLimiter, RetryActionArea, ScreenReaderAnnouncer, ScrollToBottomButton, MemoizedSearchInput as SearchInput, SessionArtifactList, SessionArtifactPreview, SessionArtifactsPanel, SessionItem_default as SessionItem, SessionMembersModal, SessionSkeleton, Sidebar2 as Sidebar, MemoizedSkeleton as Skeleton, SkeletonAvatar, SkeletonCard, SkeletonGroup, SkeletonText, SkipLink, Slot, SourcesPanel, StreamError, StreamingCursor, SystemMessage, TabbedChartGroup, TabbedTableGroup, TableExportButton, TableWithExport, ThemeProvider, Toast, ToastContainer, TouchContextMenu, Turn, TurnBubble, MemoizedTypingIndicator as TypingIndicator, MemoizedUserAvatar as UserAvatar, MemoizedUserFilter as UserFilter, UserMessage, UserTurnView, WelcomeContent, addCSRFHeader, backdropVariants, buttonVariants, convertToBase64, createDataUrl, createHeadersWithCSRF, createHttpDataSource, darkTheme, dropdownVariants, errorMessageVariants, fadeInUpVariants, fadeInVariants, floatingButtonVariants, formatFileSize, getCSRFToken, getFileVisual, getToolLabel, getValidChildren, groupSessionsByDate, groupSteps, hasPermission, isImageMimeType, isPermissionDeniedError, lightTheme, listItemVariants, messageContainerVariants, messageVariants, parseBichatStream, parseBichatStreamEvents, parseSSEStream, scaleFadeVariants, sessionItemVariants, staggerContainerVariants, toErrorDisplay, typingDotVariants, useActionButtonContext, useAttachments, useAutoScroll, useAvatarContext, useBichatRouter, useBubbleContext, useChatInput, useChatMessaging, useChatSession, useConfig, useDataTable, useFocusTrap, useHttpDataSourceConfigFromApplet, useImageGallery, useIotaContext, useKeyboardShortcuts, useLongPress, useMarkdownCopy, useMessageActions, useModalLock, useOptionalChatMessaging, useRequiredConfig, useScrollToBottom, useSidebarState, useStreaming2 as useStreaming, useTheme, useToast, useTranslation, useTurnContext, validateAttachmentFile, validateFileCount, validateImageFile, verbTransitionVariants };
18046
19079
  //# sourceMappingURL=index.mjs.map
18047
19080
  //# sourceMappingURL=index.mjs.map