@alxxsck/ai-assistant 1.4.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +24 -10
  2. package/dist/App.d.ts +6 -0
  3. package/dist/{Avatar-B6ktAPlH.js → Avatar-_GvrPzkn.js} +296 -295
  4. package/dist/{OrbitControls-BE3BANZi.js → OrbitControls-BCIW0o5s.js} +1 -1
  5. package/dist/api/messages.api.d.ts +1 -1
  6. package/dist/api/messages.api.types.d.ts +6 -0
  7. package/dist/api/voice.api.d.ts +3 -2
  8. package/dist/api/voice.api.types.d.ts +11 -13
  9. package/dist/avatar/AnimationManager.d.ts +0 -2
  10. package/dist/bridge-ai-chat-widget.es.js +7893 -4449
  11. package/dist/domain/command/CommandRuntime.d.ts +1 -1
  12. package/dist/domain/command/command.errors.d.ts +2 -2
  13. package/dist/domain/command/command.types.d.ts +0 -1
  14. package/dist/domain/message/cable/widget-frame.d.ts +1 -1
  15. package/dist/domain/message/cable/widget-message.d.ts +2 -1
  16. package/dist/domain/message/message-stream.d.ts +10 -0
  17. package/dist/domain/message/message.store.d.ts +24 -1
  18. package/dist/domain/voice/voice.store.d.ts +4 -4
  19. package/dist/index.d.ts +7 -0
  20. package/dist/index.types.d.ts +1 -1
  21. package/dist/lib/retrieveContent.d.ts +2 -1
  22. package/dist/ui/components/ChatMessage.d.ts +1 -1
  23. package/dist/ui/components/ChatTypingIndicator.d.ts +4 -2
  24. package/dist/ui/components/OptimisticCustomerMessage.d.ts +6 -0
  25. package/dist/ui/components/PendingAssistantMessage.d.ts +6 -0
  26. package/dist/ui/components/StreamingMessageText.d.ts +10 -0
  27. package/dist/ui/hooks/usePinnedAutoScroll.d.ts +10 -0
  28. package/dist/ui/hooks/useSmoothStreamingText.d.ts +7 -0
  29. package/dist/ui/streaming/smooth-text.d.ts +21 -0
  30. package/package.json +2 -1
@@ -4,7 +4,7 @@ type AckSender = (ack: CommandAck) => Promise<unknown>;
4
4
  type InternalHandlers = {
5
5
  setAssistantVisible?: (visible: boolean) => void;
6
6
  setChatOpen?: (open: boolean) => void;
7
- playAnimation?: (animation: string) => void;
7
+ playAnimation?: (animation: string, expiresAt?: string | null) => void | Promise<void>;
8
8
  showCta?: (context: CtaCommandContext) => void;
9
9
  speakText?: (context: SpeakTextCommandContext) => void | Promise<void>;
10
10
  startVoiceConversation?: (context: StartVoiceConversationCommandContext) => void | Promise<void>;
@@ -1,5 +1,5 @@
1
1
  export declare class CommandExecutionError extends Error {
2
2
  readonly code: string;
3
- readonly status: "failed" | "unsupported";
4
- constructor(code: string, status?: "failed" | "unsupported", options?: ErrorOptions);
3
+ readonly status: "failed" | "expired" | "unsupported";
4
+ constructor(code: string, status?: "failed" | "expired" | "unsupported", options?: ErrorOptions);
5
5
  }
@@ -131,7 +131,6 @@ export type StartVoiceConversationCommandContext = {
131
131
  text: string;
132
132
  voice: string;
133
133
  requiresUserGesture: true;
134
- webrtcPath: string;
135
134
  introAudioPath: string;
136
135
  };
137
136
  export type SpeakTextCommandContext = {
@@ -3,7 +3,7 @@ import type { CommandAck } from "@/domain/command/command.types";
3
3
  import type { CommandRuntime } from "@/domain/command/CommandRuntime";
4
4
  import type { MessageStoreActions } from "@/domain/message/message.store";
5
5
  type WidgetFrameDependencies = {
6
- messageActions: Pick<MessageStoreActions, "handleConversationCreated" | "handleMessagesAgenticSteps" | "handleMessage">;
6
+ messageActions: Pick<MessageStoreActions, "handleConversationCreated" | "handleMessageDelta" | "handleMessagesAgenticSteps" | "handleMessage">;
7
7
  commandRuntime: CommandRuntime;
8
8
  session: CustomerInteractionSession;
9
9
  sendAck: (ack: CommandAck) => Promise<unknown>;
@@ -1,4 +1,5 @@
1
- import type { AgenticStepsAppendedData, ConversationData, MessageData } from "@/api/messages.api.types";
1
+ import type { AgenticStepsAppendedData, ChatMessageDeltaData, ConversationData, MessageData } from "@/api/messages.api.types";
2
2
  export declare const getConversationCreatedFromFrame: (frame: unknown) => ConversationData | null;
3
3
  export declare const getMessageFromFrame: (frame: unknown) => MessageData | null;
4
+ export declare const getMessageDeltaFromFrame: (frame: unknown) => ChatMessageDeltaData | null;
4
5
  export declare const getAgenticStepsFromFrame: (frame: unknown) => AgenticStepsAppendedData | null;
@@ -0,0 +1,10 @@
1
+ import type { ChatMessageDeltaData } from "@/api/messages.api.types";
2
+ export type MessageStreamState = ChatMessageDeltaData & {
3
+ stableText: string;
4
+ incomingText: string;
5
+ };
6
+ export declare const splitStreamingText: (previous: string, current: string) => {
7
+ stableText: string;
8
+ incomingText: string;
9
+ };
10
+ export declare const createMessageStreamState: (previous: MessageStreamState | undefined, delta: ChatMessageDeltaData) => MessageStreamState;
@@ -1,10 +1,21 @@
1
- import { type AgenticStepsAppendedData, type ConversationData, type MessageData } from "@/api/messages.api.types";
1
+ import { type AgenticStepsAppendedData, type ChatMessageDeltaData, type ConversationData, type MessageData } from "@/api/messages.api.types";
2
2
  import type { AppApi } from "@/App";
3
3
  import type { WidgetConfig } from "@/index.types";
4
+ import { type MessageStreamState } from "./message-stream";
4
5
  export interface ThreadSummary {
5
6
  threadId: string;
6
7
  lastMessage: MessageData;
7
8
  }
9
+ export type AgentResponsePhase = "idle" | "awaiting-first-token" | "streaming";
10
+ export type PendingCustomerMessage = {
11
+ id: string;
12
+ text: string;
13
+ createdAt: string;
14
+ conversationId: string | undefined;
15
+ afterMessageId: string | null;
16
+ acknowledged: boolean;
17
+ canonicalMessageId: string | null;
18
+ };
8
19
  export type MessageStore = {
9
20
  currentThreadId: string | undefined;
10
21
  currentThreadMessages: MessageData[];
@@ -18,6 +29,11 @@ export type MessageStore = {
18
29
  api: AppApi | null;
19
30
  latestReadMessageDate: string | null;
20
31
  latestMessageDate: string | null;
32
+ messageStreams: Map<string, MessageStreamState>;
33
+ pendingMessageDeltas: Map<string, ChatMessageDeltaData>;
34
+ pendingCustomerMessage: PendingCustomerMessage | null;
35
+ responsePhase: AgentResponsePhase;
36
+ sendInFlight: boolean;
21
37
  actions: MessageStoreActions;
22
38
  };
23
39
  export type MessageStoreActions = {
@@ -26,6 +42,8 @@ export type MessageStoreActions = {
26
42
  createNewConversation: () => Promise<string>;
27
43
  handleConversationCreated: (conversation: ConversationData) => void;
28
44
  handleMessage: (message: MessageData) => void;
45
+ handleMessageDelta: (delta: ChatMessageDeltaData) => void;
46
+ settleMessageStream: (messageId: string) => void;
29
47
  sendMessage: (message: string) => Promise<MessageData | undefined>;
30
48
  clearSendError: () => void;
31
49
  getThreadsSummaryData: () => ThreadSummary[];
@@ -48,4 +66,9 @@ export declare const useCurrentThreadId: () => string | undefined;
48
66
  export declare const useLatestReadMessageDate: () => string | null;
49
67
  export declare const useLatestMessageDate: () => string | null;
50
68
  export declare const useSendError: () => string | null;
69
+ export declare const useIsAwaitingFirstToken: () => boolean;
70
+ export declare const useIsResponseActive: () => boolean;
71
+ export declare const selectCurrentThreadPendingCustomerMessage: (state: MessageStore) => PendingCustomerMessage | null;
72
+ export declare const usePendingCustomerMessage: () => PendingCustomerMessage | null;
73
+ export declare const useMessageStream: (messageId: string) => MessageStreamState | undefined;
51
74
  export declare const useMessageStoreActions: () => MessageStoreActions;
@@ -1,3 +1,4 @@
1
+ import { type Socket } from "socket.io-client";
1
2
  import type { AppApi } from "@/App";
2
3
  import type { VoiceSessionData } from "@/api/voice.api.types";
3
4
  import type { SpeakTextCommandContext, StartVoiceConversationCommandContext } from "@/domain/command/command.types";
@@ -9,11 +10,10 @@ type VoiceStore = {
9
10
  session: VoiceSessionData | null;
10
11
  status: VoiceStatus;
11
12
  errorMessage: string | null;
12
- connection: RTCPeerConnection | null;
13
- eventsChannel: RTCDataChannel | null;
13
+ socket: Socket | null;
14
14
  localStream: MediaStream | null;
15
- remoteStream: MediaStream | null;
16
- remoteAudioElement: HTMLAudioElement | null;
15
+ inputAudioContext: AudioContext | null;
16
+ inputAudioNode: AudioWorkletNode | null;
17
17
  pendingInvitation: StartVoiceConversationCommandContext | null;
18
18
  customerMessageTranscript: string;
19
19
  customerMessageTranscriptVisible: boolean;
package/dist/index.d.ts CHANGED
@@ -13,6 +13,10 @@ export declare class ChatWidgetInstance extends EventTarget {
13
13
  private pendingOpenState;
14
14
  private sendServiceMessageImpl;
15
15
  private playAnimationImpl;
16
+ private avatarLoadError;
17
+ private avatarLoadGeneration;
18
+ private readonly pendingAvatarAnimations;
19
+ private destroyed;
16
20
  private executeReactionImpl;
17
21
  private resolveAssetPath;
18
22
  private setLocaleImpl;
@@ -23,6 +27,9 @@ export declare class ChatWidgetInstance extends EventTarget {
23
27
  private init;
24
28
  private fetchAndMergeRemoteConfig;
25
29
  private onAvatarReady;
30
+ private onAvatarLoadStarted;
31
+ private onAvatarLoadFailed;
32
+ private playAvatarAnimation;
26
33
  private onSessionExpired;
27
34
  private onCommandStatus;
28
35
  private injectStyles;
@@ -9,7 +9,7 @@ export type WidgetConfig = {
9
9
  customerId?: string;
10
10
  wsUrl: string;
11
11
  apiUrl: string;
12
- /** Optional Lola Realtime voice passed when creating a voice session. */
12
+ /** Optional xAI voice passed to Lola when creating a voice session. */
13
13
  voiceConfig?: {
14
14
  voice: string;
15
15
  };
@@ -3,4 +3,5 @@ import { type MessageData } from "@/api/messages.api.types";
3
3
  * Plain-text preview from HTML for list items etc. Truncation works with CSS (e.g. truncate).
4
4
  */
5
5
  export declare function htmlToPlainPreview(html: string, maxLength?: number): string;
6
- export declare function retrieveContent(m: MessageData): string;
6
+ export declare function getRenderableMessageContent(message: MessageData): MessageData["content"] | null;
7
+ export declare function retrieveContent(message: MessageData): string;
@@ -4,5 +4,5 @@ export type MessageAuthor = "me" | "them";
4
4
  type ChatMessageProps = ComponentProps<"div"> & {
5
5
  message: MessageData;
6
6
  };
7
- export declare function ChatMessage({ message, className, ...props }: ChatMessageProps): import("react/jsx-runtime").JSX.Element | null;
7
+ export declare const ChatMessage: import("react").NamedExoticComponent<ChatMessageProps>;
8
8
  export {};
@@ -1,4 +1,6 @@
1
1
  import type { ComponentProps } from "react";
2
- type ChatTypingIndicatorProps = ComponentProps<"div">;
3
- export declare function ChatTypingIndicator({ className }: ChatTypingIndicatorProps): import("react/jsx-runtime").JSX.Element;
2
+ type ChatTypingIndicatorProps = Omit<ComponentProps<"div">, "children"> & {
3
+ label?: string;
4
+ };
5
+ export declare function ChatTypingIndicator({ className, label, ...props }: ChatTypingIndicatorProps): import("react/jsx-runtime").JSX.Element;
4
6
  export {};
@@ -0,0 +1,6 @@
1
+ import type { PendingCustomerMessage } from "@/domain/message/message.store";
2
+ type OptimisticCustomerMessageProps = {
3
+ message: PendingCustomerMessage;
4
+ };
5
+ export declare function OptimisticCustomerMessage({ message, }: OptimisticCustomerMessageProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { ComponentProps } from "react";
2
+ type PendingAssistantMessageProps = Omit<ComponentProps<"div">, "children"> & {
3
+ label?: string;
4
+ };
5
+ export declare function PendingAssistantMessage({ className, label, ...props }: PendingAssistantMessageProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,10 @@
1
+ type StreamingMessageTextProps = {
2
+ stableText: string;
3
+ incomingText: string;
4
+ sequence: number;
5
+ targetText?: string;
6
+ finished?: boolean;
7
+ onSettled?: () => void;
8
+ };
9
+ export declare function StreamingMessageText({ stableText, incomingText, targetText, finished, onSettled, }: StreamingMessageTextProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,10 @@
1
+ import { type RefObject, type UIEventHandler } from "react";
2
+ type UsePinnedAutoScrollOptions = {
3
+ containerRef: RefObject<HTMLElement | null>;
4
+ contentRef: RefObject<HTMLElement | null>;
5
+ messageCount: number;
6
+ threadId: string | undefined;
7
+ threshold?: number;
8
+ };
9
+ export declare function usePinnedAutoScroll({ containerRef, contentRef, messageCount, threadId, threshold, }: UsePinnedAutoScrollOptions): UIEventHandler<HTMLElement>;
10
+ export {};
@@ -0,0 +1,7 @@
1
+ export declare const useSmoothStreamingText: (targetText: string) => {
2
+ isSettled: boolean;
3
+ displayedText: string;
4
+ stableText: string;
5
+ animatedText: string;
6
+ revision: number;
7
+ };
@@ -0,0 +1,21 @@
1
+ export type SmoothTextFrame = {
2
+ displayedText: string;
3
+ stableText: string;
4
+ animatedText: string;
5
+ revision: number;
6
+ };
7
+ export type SmoothTextController = {
8
+ setTarget: (text: string) => void;
9
+ advance: (timestamp: number) => SmoothTextFrame | null;
10
+ flush: () => SmoothTextFrame | null;
11
+ getSnapshot: () => SmoothTextFrame;
12
+ isSettled: () => boolean;
13
+ };
14
+ type SmoothTextControllerOptions = {
15
+ characterIntervalMs?: number;
16
+ segment?: (text: string) => string[];
17
+ };
18
+ export declare const segmentGraphemesFallback: (text: string) => string[];
19
+ export declare const segmentGraphemes: (text: string) => string[];
20
+ export declare const createSmoothTextController: ({ characterIntervalMs, segment, }?: SmoothTextControllerOptions) => SmoothTextController;
21
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alxxsck/ai-assistant",
3
3
  "private": false,
4
- "version": "1.4.0",
4
+ "version": "1.7.0",
5
5
  "description": "Embeddable chat widget for communication with Bridge AI agent",
6
6
  "type": "module",
7
7
  "main": "dist/bridge-ai-chat-widget.es.js",
@@ -61,6 +61,7 @@
61
61
  "react-error-boundary": "^6.1.1",
62
62
  "react-router-dom": "^7.13.1",
63
63
  "react-use": "^17.6.0",
64
+ "socket.io-client": "^4.8.3",
64
65
  "tailwind-merge": "^3.4.0",
65
66
  "three": "^0.182.0",
66
67
  "vite-plugin-lib-inject-css": "^2.2.2",