@yushaw/sanqian-chat 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,9 @@
1
1
  import { HitlInterruptPayload, HitlResponse, SanqianSDK } from '@yushaw/sanqian-sdk';
2
- export { ChatStreamEvent, HitlInterruptPayload, HitlInterruptType, HitlResponse, HitlRiskLevel, ChatMessage as SdkChatMessage, ConversationDetail as SdkConversationDetail, ConversationInfo as SdkConversationInfo, ToolCall as SdkToolCall } from '@yushaw/sanqian-sdk';
2
+ export { HitlInterruptPayload, HitlInterruptType, HitlResponse, HitlRiskLevel, ChatMessage as SdkChatMessage, ConversationDetail as SdkConversationDetail, ConversationInfo as SdkConversationInfo, ToolCall as SdkToolCall } from '@yushaw/sanqian-sdk';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import * as react from 'react';
5
- import { ReactNode } from 'react';
5
+ import { ReactNode, RefObject, CSSProperties } from 'react';
6
+ export { ChatMessage, ChatStreamEvent, SDKConfig, SanqianSDK, ToolDefinition } from '@yushaw/sanqian-sdk/browser';
6
7
 
7
8
  /**
8
9
  * @yushaw/sanqian-chat Core Types
@@ -10,16 +11,80 @@ import { ReactNode } from 'react';
10
11
  * Re-exports SDK types + chat-specific types
11
12
  */
12
13
 
13
- type MessageRole = 'user' | 'assistant' | 'system';
14
+ type Locale = 'en' | 'zh';
15
+ interface ChatUiStrings {
16
+ inputPlaceholder: string;
17
+ inputSend: string;
18
+ inputStop: string;
19
+ chat: string;
20
+ recentChats: string;
21
+ newChat: string;
22
+ selectConversation: string;
23
+ noHistory: string;
24
+ loadMore: string;
25
+ today: string;
26
+ yesterday: string;
27
+ delete: string;
28
+ dismiss: string;
29
+ close: string;
30
+ pin: string;
31
+ unpin: string;
32
+ conversationUntitled: string;
33
+ conversationDeleteConfirm: string;
34
+ messageThinking: string;
35
+ messageError: string;
36
+ messageLoading: string;
37
+ connectionConnecting: string;
38
+ connectionConnected: string;
39
+ connectionDisconnected: string;
40
+ connectionReconnecting: string;
41
+ connectionError: string;
42
+ steps: string;
43
+ executing: string;
44
+ thinking: string;
45
+ thinkingStreaming: string;
46
+ thinkingPaused: string;
47
+ hitlApprove: string;
48
+ hitlReject: string;
49
+ hitlSubmit: string;
50
+ hitlCancel: string;
51
+ hitlRememberChoice: string;
52
+ hitlRequiredField: string;
53
+ hitlTimeoutIn: string;
54
+ hitlSeconds: string;
55
+ hitlExecuteTool: string;
56
+ hitlToolLabel: string;
57
+ hitlArgsLabel: string;
58
+ hitlDefaultPrefix: string;
59
+ hitlEnterResponse: string;
60
+ hitlApprovalRequest: string;
61
+ hitlInputRequest: string;
62
+ hitlApprovalRequired: string;
63
+ hitlInputRequired: string;
64
+ }
65
+ type ChatThemeMode = 'light' | 'dark' | 'auto';
66
+ type ChatFontSize = 'small' | 'normal' | 'large' | 'extra-large';
67
+ interface ChatUiConfigSerializable {
68
+ logo?: string;
69
+ theme?: ChatThemeMode;
70
+ /** Font size scale: small (13px), normal (14px), large (16px), extra-large (18px) */
71
+ fontSize?: ChatFontSize;
72
+ accentColor?: string;
73
+ locale?: Locale;
74
+ strings?: Partial<ChatUiStrings>;
75
+ alwaysOnTop?: boolean;
76
+ }
77
+ type MessageRole = 'user' | 'assistant' | 'system' | 'tool';
14
78
  type ToolCallStatus = 'pending' | 'running' | 'completed' | 'error' | 'cancelled';
15
79
  type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';
16
80
  type ConnectionErrorCode = 'NOT_FOUND' | 'CONNECTION_FAILED' | 'WEBSOCKET_ERROR' | 'AUTH_ERROR' | 'TIMEOUT' | 'UNKNOWN';
17
81
  /** Tool call for UI rendering (extended from SDK) */
18
82
  interface ToolCall {
19
- id: string;
83
+ id?: string;
20
84
  name: string;
21
- arguments: Record<string, unknown>;
22
- status: ToolCallStatus;
85
+ args?: Record<string, unknown>;
86
+ argsRaw?: string;
87
+ status?: ToolCallStatus;
23
88
  result?: unknown;
24
89
  error?: string;
25
90
  }
@@ -30,9 +95,11 @@ interface MessageBlock {
30
95
  timestamp: number;
31
96
  toolName?: string;
32
97
  toolArgs?: Record<string, unknown>;
98
+ toolArgsRaw?: string;
33
99
  toolCallId?: string;
34
100
  toolStatus?: ToolCallStatus;
35
101
  isIntermediate?: boolean;
102
+ fromSubagent?: boolean;
36
103
  }
37
104
  /** Chat message for UI rendering */
38
105
  interface ChatMessage {
@@ -45,8 +112,12 @@ interface ChatMessage {
45
112
  thinking?: string;
46
113
  currentThinking?: string;
47
114
  isThinkingStreaming?: boolean;
115
+ isThinkingPaused?: boolean;
116
+ isToolCallsStreaming?: boolean;
48
117
  blocks?: MessageBlock[];
118
+ finalContent?: string;
49
119
  isComplete?: boolean;
120
+ filePaths?: string[];
50
121
  }
51
122
  /** Conversation info for UI */
52
123
  interface ConversationInfo {
@@ -55,6 +126,7 @@ interface ConversationInfo {
55
126
  createdAt: string;
56
127
  updatedAt: string;
57
128
  messageCount: number;
129
+ agentId?: string | null;
58
130
  }
59
131
  interface ConversationDetail extends ConversationInfo {
60
132
  messages: ChatMessage[];
@@ -70,9 +142,21 @@ interface FloatingWindowConfig {
70
142
  position?: WindowPosition;
71
143
  width?: number;
72
144
  height?: number;
145
+ /** Minimum window width (default: 320) */
146
+ minWidth?: number;
147
+ /** Minimum window height (default: 420) */
148
+ minHeight?: number;
73
149
  alwaysOnTop?: boolean;
74
150
  showInTaskbar?: boolean;
75
151
  theme?: 'light' | 'dark' | 'system';
152
+ /** Optional UI config for renderer (serializable) */
153
+ uiConfig?: ChatUiConfigSerializable;
154
+ /** Persist size/position across sessions (stored under ~/.sanqian-chat) */
155
+ rememberWindowState?: boolean;
156
+ /** Optional storage key to avoid conflicts between apps */
157
+ windowStateKey?: string;
158
+ /** Optional full path for window state file */
159
+ windowStatePath?: string;
76
160
  }
77
161
 
78
162
  /**
@@ -84,6 +168,10 @@ interface FloatingWindowConfig {
84
168
 
85
169
  /** Stream event callback */
86
170
  type StreamEvent = {
171
+ type: 'start';
172
+ run_id: string;
173
+ conversationId?: string;
174
+ } | {
87
175
  type: 'text';
88
176
  content: string;
89
177
  } | {
@@ -98,6 +186,16 @@ type StreamEvent = {
98
186
  arguments: string;
99
187
  };
100
188
  };
189
+ } | {
190
+ type: 'tool_args_chunk';
191
+ tool_call_id: string;
192
+ tool_name?: string;
193
+ chunk: string;
194
+ } | {
195
+ type: 'tool_args';
196
+ tool_call_id: string;
197
+ tool_name?: string;
198
+ args: Record<string, unknown>;
101
199
  } | {
102
200
  type: 'tool_result';
103
201
  tool_call_id: string;
@@ -114,6 +212,9 @@ type StreamEvent = {
114
212
  interrupt_type: string;
115
213
  interrupt_payload: HitlInterruptData;
116
214
  run_id?: string;
215
+ } | {
216
+ type: 'cancelled';
217
+ run_id?: string;
117
218
  };
118
219
  /** Message to send */
119
220
  interface SendMessage {
@@ -138,7 +239,9 @@ interface ChatAdapter {
138
239
  messageLimit?: number;
139
240
  }): Promise<ConversationDetail>;
140
241
  deleteConversation(id: string): Promise<void>;
141
- chatStream(messages: SendMessage[], conversationId: string | undefined, onEvent: (event: StreamEvent) => void): Promise<{
242
+ chatStream(messages: SendMessage[], conversationId: string | undefined, onEvent: (event: StreamEvent) => void, options?: {
243
+ agentId?: string | null;
244
+ }): Promise<{
142
245
  cancel: () => void;
143
246
  }>;
144
247
  sendHitlResponse?(response: HitlResponse, runId?: string): void;
@@ -151,8 +254,47 @@ interface SdkAdapterConfig {
151
254
  /** Agent ID getter */
152
255
  getAgentId: () => string | null;
153
256
  }
257
+ /** Simple chat adapter config (no SDK knowledge required) */
258
+ interface ChatAdapterConfig {
259
+ /** App name for registration */
260
+ appName: string;
261
+ /** App version */
262
+ appVersion: string;
263
+ /** Agent ID to chat with */
264
+ agentId: string;
265
+ /** Whether to persist conversation history (default: false) */
266
+ persistHistory?: boolean;
267
+ /** Tools to expose to the agent */
268
+ tools?: Array<{
269
+ name: string;
270
+ description: string;
271
+ parameters?: Record<string, unknown>;
272
+ handler?: (args: Record<string, unknown>) => Promise<unknown>;
273
+ }>;
274
+ }
275
+ /**
276
+ * Create a chat adapter with simple config (recommended for most use cases)
277
+ *
278
+ * This is the easiest way to integrate with Sanqian. Just provide your app info
279
+ * and agent ID, and the adapter handles SDK lifecycle automatically.
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * const adapter = createChatAdapter({
284
+ * appName: 'my-app',
285
+ * appVersion: '1.0.0',
286
+ * agentId: 'assistant',
287
+ * });
288
+ *
289
+ * <CompactChat adapter={adapter} />
290
+ * ```
291
+ */
292
+ declare function createChatAdapter(config: ChatAdapterConfig): ChatAdapter;
154
293
  /**
155
294
  * Create adapter that wraps @yushaw/sanqian-sdk
295
+ *
296
+ * Use this when you need more control over the SDK instance.
297
+ * For simpler usage, prefer `createChatAdapter()`.
156
298
  */
157
299
  declare function createSdkAdapter(config: SdkAdapterConfig): ChatAdapter;
158
300
 
@@ -209,7 +351,12 @@ declare function useTheme(): ThemeContextValue;
209
351
  */
210
352
  declare function useStandaloneTheme(defaultTheme?: ThemeMode): ThemeContextValue;
211
353
 
212
- type Locale = 'en' | 'zh';
354
+ interface ChatUiConfig extends Omit<ChatUiConfigSerializable, 'logo'> {
355
+ logo?: string | ReactNode;
356
+ onClose?: () => void;
357
+ onPin?: (pinned: boolean) => void;
358
+ }
359
+
213
360
  interface Translations {
214
361
  hitl: {
215
362
  approvalRequired: string;
@@ -268,6 +415,107 @@ declare function useStandaloneI18n(defaultLocale?: Locale): I18nContextValue;
268
415
  */
269
416
  declare function getTranslations(locale: Locale): Translations;
270
417
 
418
+ /**
419
+ * useConnection Hook
420
+ *
421
+ * Manages connection state with the backend.
422
+ */
423
+
424
+ interface UseConnectionOptions {
425
+ /** Chat adapter */
426
+ adapter: ChatAdapter;
427
+ /** Auto-connect on mount */
428
+ autoConnect?: boolean;
429
+ /** Called when connection status changes */
430
+ onStatusChange?: (status: ConnectionStatus, error?: string, errorCode?: ConnectionErrorCode) => void;
431
+ }
432
+ interface UseConnectionReturn {
433
+ /** Current connection status */
434
+ status: ConnectionStatus;
435
+ /** Connection error message (if any) */
436
+ error: string | undefined;
437
+ /** Connection error code (if any) */
438
+ errorCode: ConnectionErrorCode | undefined;
439
+ /** Whether currently connected */
440
+ isConnected: boolean;
441
+ /** Whether currently connecting/reconnecting */
442
+ isConnecting: boolean;
443
+ /** Connect to the backend */
444
+ connect: () => Promise<void>;
445
+ /** Disconnect from the backend */
446
+ disconnect: () => Promise<void>;
447
+ }
448
+ declare function useConnection(options: UseConnectionOptions): UseConnectionReturn;
449
+
450
+ /**
451
+ * useConversations Hook
452
+ *
453
+ * Manages conversation history list with loading and delete operations.
454
+ */
455
+
456
+ interface UseConversationsOptions {
457
+ /** Chat adapter for backend communication */
458
+ adapter: ChatAdapter;
459
+ /** Number of conversations per page */
460
+ pageSize?: number;
461
+ /** Called when an error occurs */
462
+ onError?: (error: Error) => void;
463
+ }
464
+ interface UseConversationsReturn {
465
+ conversations: ConversationInfo[];
466
+ isLoading: boolean;
467
+ hasMore: boolean;
468
+ total: number;
469
+ error: string | null;
470
+ /** Whether last loadMore failed (for retry button) */
471
+ loadError: boolean;
472
+ loadConversations: () => Promise<void>;
473
+ loadMore: () => Promise<void>;
474
+ deleteConversation: (id: string) => Promise<void>;
475
+ refresh: () => Promise<void>;
476
+ }
477
+ declare function useConversations(options: UseConversationsOptions): UseConversationsReturn;
478
+
479
+ declare function useChatStyles(): void;
480
+
481
+ /**
482
+ * useFocusPersistence Hook
483
+ *
484
+ * Restores focus to input when clicking empty areas in the chat container.
485
+ * Inspired by Slack's forceFocus pattern - always keep input ready for typing.
486
+ */
487
+
488
+ interface UseFocusPersistenceOptions {
489
+ /** Container element ref */
490
+ containerRef: RefObject<HTMLElement | null>;
491
+ /** Input element ref (must have focus method) */
492
+ inputRef: RefObject<{
493
+ focus: () => void;
494
+ } | null>;
495
+ /** Skip focus restoration when this is true (e.g., HITL dialog open, history view) */
496
+ disabled?: boolean;
497
+ }
498
+ /**
499
+ * Hook that restores focus to input when clicking empty areas.
500
+ *
501
+ * @example
502
+ * ```tsx
503
+ * const containerRef = useRef<HTMLDivElement>(null);
504
+ * const inputRef = useRef<ChatInputHandle>(null);
505
+ *
506
+ * useFocusPersistence({
507
+ * containerRef,
508
+ * inputRef,
509
+ * disabled: !!pendingInterrupt || showHistory,
510
+ * });
511
+ * ```
512
+ */
513
+ declare function useFocusPersistence({ containerRef, inputRef, disabled, }: UseFocusPersistenceOptions): void;
514
+
515
+ declare function useIpcUiConfig(): ChatUiConfigSerializable | null;
516
+
517
+ declare function useResolvedUiConfig(config?: ChatUiConfig): ChatUiConfig | undefined;
518
+
271
519
  /**
272
520
  * IPC Adapter
273
521
  *
@@ -296,6 +544,41 @@ interface MessageBubbleProps {
296
544
  }
297
545
  declare const MessageBubble: react.NamedExoticComponent<MessageBubbleProps>;
298
546
 
547
+ interface SanqianChatProps {
548
+ adapter: ChatAdapter;
549
+ placeholder?: string;
550
+ autoConnect?: boolean;
551
+ className?: string;
552
+ emptyState?: ReactNode;
553
+ onError?: (error: Error) => void;
554
+ onConversationChange?: (conversationId: string, title?: string) => void;
555
+ onStateChange?: (state: {
556
+ messages: ChatMessage[];
557
+ conversationId: string | null;
558
+ }) => void;
559
+ config?: ChatUiConfig;
560
+ logo?: string | ReactNode;
561
+ }
562
+ declare const SanqianChat: react.NamedExoticComponent<SanqianChatProps>;
563
+
564
+ interface SanqianMessageListProps {
565
+ messages: ChatMessage[];
566
+ isLoading: boolean;
567
+ className?: string;
568
+ emptyState?: ReactNode;
569
+ onClickEmpty?: () => void;
570
+ onAtBottomChange?: (atBottom: boolean) => void;
571
+ }
572
+ interface SanqianMessageListHandle {
573
+ scrollToBottom: (behavior?: 'smooth' | 'auto', source?: string) => void;
574
+ }
575
+ declare const SanqianMessageList: react.ForwardRefExoticComponent<SanqianMessageListProps & react.RefAttributes<SanqianMessageListHandle>>;
576
+
577
+ interface SanqianChatMessageProps {
578
+ message: ChatMessage;
579
+ }
580
+ declare const SanqianChatMessage: react.NamedExoticComponent<SanqianChatMessageProps>;
581
+
299
582
  interface ChatInputProps {
300
583
  onSend: (content: string) => void;
301
584
  onStop?: () => void;
@@ -303,17 +586,22 @@ interface ChatInputProps {
303
586
  disabled?: boolean;
304
587
  isStreaming?: boolean;
305
588
  isLoading?: boolean;
306
- className?: string;
307
- textareaClassName?: string;
308
- sendButtonClassName?: string;
309
- stopButtonClassName?: string;
310
- sendButtonContent?: ReactNode;
311
- stopButtonContent?: ReactNode;
589
+ sendLabel?: string;
590
+ stopLabel?: string;
312
591
  maxRows?: number;
313
592
  autoFocus?: boolean;
314
- focusRef?: React.MutableRefObject<(() => void) | null>;
593
+ leftSlot?: ReactNode;
594
+ rightSlot?: ReactNode;
595
+ className?: string;
596
+ style?: CSSProperties;
597
+ }
598
+ interface ChatInputHandle {
599
+ focus: () => void;
600
+ setValue: (text: string) => void;
601
+ getValue: () => string;
602
+ clear: () => void;
315
603
  }
316
- declare const ChatInput: react.NamedExoticComponent<ChatInputProps>;
604
+ declare const ChatInput: react.MemoExoticComponent<react.ForwardRefExoticComponent<ChatInputProps & react.RefAttributes<ChatInputHandle>>>;
317
605
 
318
606
  interface FloatingChatProps {
319
607
  messages: ChatMessage[];
@@ -325,10 +613,11 @@ interface FloatingChatProps {
325
613
  onStopStreaming: () => void;
326
614
  onApproveHitl?: (remember?: boolean) => void;
327
615
  onRejectHitl?: (remember?: boolean) => void;
328
- onHide?: () => void;
329
616
  className?: string;
330
617
  placeholder?: string;
331
618
  locale?: Locale;
619
+ config?: ChatUiConfig;
620
+ logo?: string | ReactNode;
332
621
  renderMessage?: (message: ChatMessage, index: number) => ReactNode;
333
622
  renderContent?: (content: string, isStreaming: boolean) => ReactNode;
334
623
  renderHitl?: (interrupt: HitlInterruptData, onApprove: () => void, onReject: () => void) => ReactNode;
@@ -337,4 +626,306 @@ interface FloatingChatProps {
337
626
  }
338
627
  declare const FloatingChat: react.NamedExoticComponent<FloatingChatProps>;
339
628
 
340
- export { type ChatAdapter, ChatInput, type ChatInputProps, type ChatMessage, type ConnectionErrorCode, type ConnectionStatus, type ConversationDetail, type ConversationInfo, FloatingChat, type FloatingChatProps, type FloatingWindowConfig, type HitlInterruptData, I18nProvider, type I18nProviderProps, type Locale, type MessageBlock, MessageBubble, type MessageBubbleProps, MessageList, type MessageListProps, type MessageRole, type ResolvedTheme, type SdkAdapterConfig, type SendMessage, type StreamEvent, type ThemeMode, ThemeProvider, type ThemeProviderProps, type ToolCall, type ToolCallStatus, type Translations, type UseChatOptions, type UseChatReturn, type WindowPosition, createIpcAdapter, createSdkAdapter, getTranslations, useChat, useI18n, useStandaloneI18n, useStandaloneTheme, useTheme };
629
+ interface IntermediateStepsProps {
630
+ /** Message blocks to display */
631
+ blocks: MessageBlock[];
632
+ /** Additional CSS classes */
633
+ className?: string;
634
+ /** Default expanded state (default: false) */
635
+ defaultExpanded?: boolean;
636
+ /** Localized strings */
637
+ strings?: {
638
+ steps?: string;
639
+ };
640
+ }
641
+ interface StreamingTimelineProps {
642
+ blocks: MessageBlock[];
643
+ currentThinking?: string;
644
+ isThinkingStreaming?: boolean;
645
+ isToolCallsStreaming?: boolean;
646
+ isComplete?: boolean;
647
+ className?: string;
648
+ strings?: {
649
+ steps?: string;
650
+ executing?: string;
651
+ };
652
+ }
653
+ interface ThinkingSectionProps {
654
+ thinking: string;
655
+ currentThinking?: string;
656
+ isStreaming?: boolean;
657
+ isPaused?: boolean;
658
+ isComplete?: boolean;
659
+ className?: string;
660
+ strings?: {
661
+ thinkingStreaming?: string;
662
+ thinkingPaused?: string;
663
+ thinking?: string;
664
+ };
665
+ }
666
+ /**
667
+ * Thinking section component with streaming support
668
+ * Three states:
669
+ * 1. Streaming: show currentThinking, auto-expand, animated loading symbol
670
+ * 2. Paused: show currentThinking, stay expanded, "已思考" (waiting for next round)
671
+ * 3. Finished: show full thinking, collapsed by default, "思考过程"
672
+ */
673
+ declare const ThinkingSection: react.NamedExoticComponent<ThinkingSectionProps>;
674
+ declare const IntermediateSteps: react.NamedExoticComponent<IntermediateStepsProps>;
675
+ declare const StreamingTimeline: react.NamedExoticComponent<StreamingTimelineProps>;
676
+
677
+ interface HitlCardProps {
678
+ /** Interrupt data from backend */
679
+ interrupt: HitlInterruptData;
680
+ /** Called when user approves (for approval_request) */
681
+ onApprove?: (remember?: boolean) => void;
682
+ /** Called when user rejects (for approval_request) */
683
+ onReject?: (remember?: boolean) => void;
684
+ /** Called when user submits input (for user_input_request) */
685
+ onSubmit?: (response: HitlResponse) => void;
686
+ /** Called when user cancels */
687
+ onCancel?: () => void;
688
+ /** Whether in dark mode */
689
+ isDarkMode?: boolean;
690
+ /** Custom strings for i18n */
691
+ strings?: {
692
+ approve?: string;
693
+ reject?: string;
694
+ submit?: string;
695
+ cancel?: string;
696
+ rememberChoice?: string;
697
+ requiredField?: string;
698
+ timeoutIn?: string;
699
+ seconds?: string;
700
+ executeTool?: string;
701
+ toolLabel?: string;
702
+ argsLabel?: string;
703
+ defaultPrefix?: string;
704
+ enterResponse?: string;
705
+ approvalRequest?: string;
706
+ inputRequest?: string;
707
+ };
708
+ }
709
+ declare const HitlCard: react.NamedExoticComponent<HitlCardProps>;
710
+
711
+ interface HistoryListProps {
712
+ /** List of conversations */
713
+ conversations: ConversationInfo[];
714
+ /** Currently selected conversation ID */
715
+ selectedId?: string | null;
716
+ /** Whether loading */
717
+ isLoading?: boolean;
718
+ /** Whether there are more items to load */
719
+ hasMore?: boolean;
720
+ /** Whether last load failed */
721
+ loadError?: boolean;
722
+ /** Called when a conversation is selected */
723
+ onSelect: (id: string) => void;
724
+ /** Called when a conversation should be deleted */
725
+ onDelete: (id: string) => void;
726
+ /** Called when load more is triggered */
727
+ onLoadMore?: () => void;
728
+ /** Dark mode */
729
+ isDarkMode?: boolean;
730
+ /** Localized strings */
731
+ strings?: {
732
+ noHistory?: string;
733
+ loadMore?: string;
734
+ today?: string;
735
+ yesterday?: string;
736
+ delete?: string;
737
+ };
738
+ }
739
+ declare const HistoryList: react.NamedExoticComponent<HistoryListProps>;
740
+
741
+ declare function resolveChatStrings(locale?: Locale, overrides?: Partial<ChatUiStrings>): ChatUiStrings;
742
+
743
+ type AlertType = 'warning' | 'error';
744
+ interface AlertAction {
745
+ /** Action label */
746
+ label: string;
747
+ /** Action handler */
748
+ onClick: () => void;
749
+ }
750
+ interface AlertBannerProps {
751
+ /** Alert type - determines styling */
752
+ type: AlertType;
753
+ /** Alert message content */
754
+ message: string | ReactNode;
755
+ /** Optional action button */
756
+ action?: AlertAction;
757
+ /** Optional dismiss handler - shows dismiss button when provided */
758
+ onDismiss?: () => void;
759
+ /** Additional class names */
760
+ className?: string;
761
+ /** Custom icon */
762
+ icon?: ReactNode;
763
+ /** Max lines before truncating (default: 3) */
764
+ maxLines?: number;
765
+ /** Localized strings */
766
+ strings?: {
767
+ collapse?: string;
768
+ expand?: string;
769
+ };
770
+ }
771
+ declare const AlertBanner: react.NamedExoticComponent<AlertBannerProps>;
772
+
773
+ /** Alert configuration for displaying warnings/errors above input */
774
+ interface AlertConfig {
775
+ type: AlertType;
776
+ message: string;
777
+ action?: AlertAction;
778
+ dismissible?: boolean;
779
+ }
780
+ interface CompactChatProps {
781
+ /** Chat adapter for backend communication */
782
+ adapter: ChatAdapter;
783
+ /** UI configuration */
784
+ config?: ChatUiConfig;
785
+ /** Logo override (takes precedence over config.logo) */
786
+ logo?: string | ReactNode;
787
+ /** Input placeholder */
788
+ placeholder?: string;
789
+ /** Whether to auto-connect on mount */
790
+ autoConnect?: boolean;
791
+ /** Called when an error occurs */
792
+ onError?: (error: Error) => void;
793
+ /** Called when a message is received (for session tracking) */
794
+ onMessageReceived?: (message: ChatMessage) => void;
795
+ /** Called when loading state changes */
796
+ onLoadingChange?: (isLoading: boolean) => void;
797
+ /** Called when chat state changes (messages, conversationId) */
798
+ onStateChange?: (state: {
799
+ messages: ChatMessage[];
800
+ conversationId: string | null;
801
+ }) => void;
802
+ /** Header content (left side) */
803
+ headerLeft?: ReactNode;
804
+ /** Header content (right side) */
805
+ headerRight?: ReactNode;
806
+ /** Whether to hide header */
807
+ hideHeader?: boolean;
808
+ /** Whether to hide input area (for custom external input) */
809
+ hideInput?: boolean;
810
+ /** Container element for rendering input via Portal */
811
+ inputPortalContainer?: HTMLElement | null;
812
+ /** Ref to expose sendMessage function for external input */
813
+ sendMessageRef?: React.MutableRefObject<((message: string) => void) | null>;
814
+ /** Ref to expose newConversation function */
815
+ newConversationRef?: React.MutableRefObject<(() => void) | null>;
816
+ /** Ref to expose focusInput function */
817
+ focusInputRef?: React.MutableRefObject<(() => void) | null>;
818
+ /** Ref to expose setText function (for filling input externally) */
819
+ setTextRef?: React.MutableRefObject<((text: string) => void) | null>;
820
+ /** Custom message renderer */
821
+ renderMessage?: (message: ChatMessage) => ReactNode;
822
+ /** Empty state content (when no messages) */
823
+ emptyState?: ReactNode;
824
+ /** Additional class name */
825
+ className?: string;
826
+ /**
827
+ * Dark mode.
828
+ * @deprecated Use config.theme instead.
829
+ */
830
+ isDarkMode?: boolean;
831
+ /** Localized strings */
832
+ strings?: Partial<ChatUiStrings>;
833
+ /** Custom alert to display above input (overrides default connection/error alerts) */
834
+ alert?: AlertConfig | null;
835
+ /** Callback when alert is dismissed */
836
+ onAlertDismiss?: () => void;
837
+ /** Function to get error message from error code (for i18n) */
838
+ getErrorMessage?: (errorCode: string) => string;
839
+ /** Use floating window container style (for transparent Electron windows) */
840
+ floating?: boolean;
841
+ }
842
+ declare const CompactChat: react.NamedExoticComponent<CompactChatProps>;
843
+
844
+ /**
845
+ * Tool Arguments Display Component
846
+ *
847
+ * Displays tool call arguments in a compact, Python kwargs-like format.
848
+ * No JSON braces, uses indentation and bullet points for nested structures.
849
+ *
850
+ * Features:
851
+ * - Python kwargs-style display (key=value)
852
+ * - Recursive nested object/array rendering
853
+ * - Smart inline vs multi-line formatting
854
+ * - Theme-aware using CSS variables
855
+ */
856
+ interface ToolArgumentsDisplayProps {
857
+ /** Arguments object to display */
858
+ args: Record<string, unknown>;
859
+ /** Additional CSS classes */
860
+ className?: string;
861
+ }
862
+ /**
863
+ * Displays tool arguments in Python kwargs style.
864
+ *
865
+ * @example
866
+ * <ToolArgumentsDisplay
867
+ * args={{ file_path: "/path/to/file", content: "Hello" }}
868
+ * />
869
+ * // Renders:
870
+ * // file_path = "/path/to/file"
871
+ * // content = "Hello"
872
+ */
873
+ declare const ToolArgumentsDisplay: react.NamedExoticComponent<ToolArgumentsDisplayProps>;
874
+
875
+ interface MarkdownRendererProps {
876
+ /** Markdown content to render */
877
+ content: string;
878
+ /** Whether content is still streaming */
879
+ isStreaming?: boolean;
880
+ /** Additional CSS classes */
881
+ className?: string;
882
+ /** Custom component overrides */
883
+ components?: {
884
+ /** Custom link renderer */
885
+ a?: React.ComponentType<{
886
+ href?: string;
887
+ children?: ReactNode;
888
+ }>;
889
+ /** Custom code block renderer */
890
+ code?: React.ComponentType<{
891
+ className?: string;
892
+ children?: ReactNode;
893
+ }>;
894
+ /** Custom paragraph renderer */
895
+ p?: React.ComponentType<{
896
+ children?: ReactNode;
897
+ }>;
898
+ };
899
+ /** Callback when a link is clicked */
900
+ onLinkClick?: (href: string, event: React.MouseEvent) => void;
901
+ }
902
+ declare const MarkdownRenderer: react.NamedExoticComponent<MarkdownRendererProps>;
903
+
904
+ /**
905
+ * Inject chat styles into the document.
906
+ *
907
+ * Style modes:
908
+ * - 'safe' (default): CSS variables + component styles + Tailwind utilities.
909
+ * No global resets (preflight). Safe for third-party integration.
910
+ * - 'full': Complete styles including Tailwind CSS preflight.
911
+ * Use this for standalone windows where you control the entire page.
912
+ * - false: Disable all style injection.
913
+ *
914
+ * Configure via:
915
+ * - window.__SANQIAN_CHAT_STYLE_MODE__ = 'full' | 'safe' | false
916
+ * - window.__SANQIAN_CHAT_DISABLE_STYLES__ = true (legacy, same as 'false')
917
+ *
918
+ * Or import CSS directly:
919
+ * - '@yushaw/sanqian-chat/renderer/styles/safe.css' (no preflight)
920
+ * - '@yushaw/sanqian-chat/renderer/styles/chat.css' (full with preflight)
921
+ */
922
+ declare function ensureChatBaseStyles(): void;
923
+ /**
924
+ * Inject full chat styles including Tailwind preflight.
925
+ * Use this for standalone windows where you control the entire page.
926
+ *
927
+ * @deprecated Use window.__SANQIAN_CHAT_STYLE_MODE__ = 'full' instead
928
+ */
929
+ declare function ensureFullChatStyles(): void;
930
+
931
+ export { type AlertAction, AlertBanner, type AlertBannerProps, type AlertConfig, type AlertType, type ChatAdapter, type ChatAdapterConfig, type ChatFontSize, ChatInput, type ChatInputHandle, type ChatInputProps, type ChatThemeMode, type ChatUiConfig, type ChatUiConfigSerializable, type ChatUiStrings, CompactChat, type CompactChatProps, type ConnectionErrorCode, type ConnectionStatus, type ConversationDetail, type ConversationInfo, FloatingChat, type FloatingChatProps, type FloatingWindowConfig, HistoryList, type HistoryListProps, HitlCard, type HitlCardProps, type HitlInterruptData, I18nProvider, type I18nProviderProps, IntermediateSteps, type IntermediateStepsProps, type Locale, MarkdownRenderer, type MarkdownRendererProps, type MessageBlock, MessageBubble, type MessageBubbleProps, MessageList, type MessageListProps, type MessageRole, type ResolvedTheme, SanqianChat, SanqianChatMessage, type SanqianChatMessageProps, type SanqianChatProps, SanqianMessageList, type SanqianMessageListHandle, type SanqianMessageListProps, type SdkAdapterConfig, type SendMessage, type StreamEvent, StreamingTimeline, type StreamingTimelineProps, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThinkingSection, type ThinkingSectionProps, ToolArgumentsDisplay, type ToolArgumentsDisplayProps, type ToolCall, type ToolCallStatus, type Translations, type UseChatOptions, type UseChatReturn, type UseConnectionOptions, type UseConnectionReturn, type UseConversationsOptions, type UseConversationsReturn, type UseFocusPersistenceOptions, type WindowPosition, createChatAdapter, createIpcAdapter, createSdkAdapter, ensureChatBaseStyles, ensureFullChatStyles, getTranslations, resolveChatStrings, useChat, useChatStyles, useConnection, useConversations, useFocusPersistence, useI18n, useIpcUiConfig, useResolvedUiConfig, useStandaloneI18n, useStandaloneTheme, useTheme };