@alliance-droid/chat-widget 0.1.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 (42) hide show
  1. package/README.md +102 -0
  2. package/dist/client/connection.d.ts +39 -0
  3. package/dist/client/connection.js +198 -0
  4. package/dist/client/index.d.ts +6 -0
  5. package/dist/client/index.js +6 -0
  6. package/dist/components/ChatInput.svelte +73 -0
  7. package/dist/components/ChatInput.svelte.d.ts +9 -0
  8. package/dist/components/ChatPanel.svelte +117 -0
  9. package/dist/components/ChatPanel.svelte.d.ts +20 -0
  10. package/dist/components/ChatWidget.svelte +160 -0
  11. package/dist/components/ChatWidget.svelte.d.ts +4 -0
  12. package/dist/components/MessageBubble.svelte +60 -0
  13. package/dist/components/MessageBubble.svelte.d.ts +8 -0
  14. package/dist/components/MessageList.svelte +58 -0
  15. package/dist/components/MessageList.svelte.d.ts +10 -0
  16. package/dist/components/SupportChat.svelte +133 -0
  17. package/dist/components/SupportChat.svelte.d.ts +4 -0
  18. package/dist/index.d.ts +15 -0
  19. package/dist/index.js +17 -0
  20. package/dist/server/ai/anthropic.d.ts +16 -0
  21. package/dist/server/ai/anthropic.js +109 -0
  22. package/dist/server/ai/openai.d.ts +16 -0
  23. package/dist/server/ai/openai.js +112 -0
  24. package/dist/server/ai/provider.d.ts +21 -0
  25. package/dist/server/ai/provider.js +6 -0
  26. package/dist/server/ai/xai.d.ts +16 -0
  27. package/dist/server/ai/xai.js +113 -0
  28. package/dist/server/escalation.d.ts +18 -0
  29. package/dist/server/escalation.js +61 -0
  30. package/dist/server/handler.d.ts +8 -0
  31. package/dist/server/handler.js +235 -0
  32. package/dist/server/index.d.ts +11 -0
  33. package/dist/server/index.js +10 -0
  34. package/dist/server/session.d.ts +52 -0
  35. package/dist/server/session.js +115 -0
  36. package/dist/stores/chat.d.ts +18 -0
  37. package/dist/stores/chat.js +40 -0
  38. package/dist/stores/connection.d.ts +20 -0
  39. package/dist/stores/connection.js +52 -0
  40. package/dist/types.d.ts +79 -0
  41. package/dist/types.js +4 -0
  42. package/package.json +73 -0
@@ -0,0 +1,160 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import { IconButton, Badge } from '@alliance-droid/svelte-component-library/components/atoms';
4
+ import ChatPanel from './ChatPanel.svelte';
5
+ import { connect, disconnect, sendMessage, requestEscalation } from '../client/connection.js';
6
+ import { chatStore } from '../stores/chat.js';
7
+ import { connectionStore } from '../stores/connection.js';
8
+ import type { ChatWidgetProps } from '../types.js';
9
+
10
+ const {
11
+ serverUrl,
12
+ apiKey,
13
+ reconnect = true,
14
+ reconnectInterval = 3000,
15
+ theme = 'dark',
16
+ position = 'bottom-right',
17
+ greeting,
18
+ placeholder = 'Type a message...',
19
+ fabIcon = 'comment',
20
+ enableSounds = false,
21
+ enableEscalation = true,
22
+ escalationLabel = 'Talk to a human',
23
+ userId,
24
+ userMeta,
25
+ class: className = ''
26
+ }: ChatWidgetProps = $props();
27
+
28
+ let isOpen = $state(false);
29
+ let unreadCount = $state(0);
30
+
31
+ // Subscribe to stores
32
+ const messages = chatStore.messages;
33
+ const status = chatStore.status;
34
+ const isTyping = chatStore.isTyping;
35
+ const typingSender = chatStore.typingSender;
36
+ const connectionState = connectionStore.state;
37
+
38
+ // Position classes
39
+ const positionClasses = $derived(() => {
40
+ return position === 'bottom-left' ? 'left-4' : 'right-4';
41
+ });
42
+
43
+ // Theme class
44
+ const themeClass = $derived(() => {
45
+ if (theme === 'auto') return '';
46
+ return theme;
47
+ });
48
+
49
+ function toggleOpen() {
50
+ isOpen = !isOpen;
51
+ if (isOpen) {
52
+ unreadCount = 0;
53
+ }
54
+ }
55
+
56
+ function handleMessage(message: string) {
57
+ sendMessage(message);
58
+ }
59
+
60
+ function handleEscalate() {
61
+ requestEscalation();
62
+ }
63
+
64
+ function playNotificationSound() {
65
+ // TODO: Implement sound notification
66
+ }
67
+
68
+ onMount(() => {
69
+ connect({
70
+ serverUrl,
71
+ apiKey,
72
+ reconnect,
73
+ reconnectInterval,
74
+ userId,
75
+ userMeta
76
+ });
77
+
78
+ // Add greeting message if provided
79
+ if (greeting) {
80
+ chatStore.addMessage({
81
+ id: 'greeting',
82
+ content: greeting,
83
+ sender: 'system',
84
+ timestamp: Date.now()
85
+ });
86
+ }
87
+ });
88
+
89
+ onDestroy(() => {
90
+ disconnect();
91
+ });
92
+ </script>
93
+
94
+ <div class="fixed bottom-4 {positionClasses()} z-50 {themeClass()} {className}">
95
+ {#if isOpen}
96
+ <div
97
+ class="w-[380px] h-[600px] max-h-[80vh] mb-4 animate-in fade-in slide-in-from-bottom-4 duration-200"
98
+ >
99
+ <ChatPanel
100
+ messages={$messages}
101
+ status={$status}
102
+ connectionState={$connectionState}
103
+ isTyping={$isTyping}
104
+ typingSender={$typingSender}
105
+ {placeholder}
106
+ {enableEscalation}
107
+ {escalationLabel}
108
+ onmessage={handleMessage}
109
+ onescalate={handleEscalate}
110
+ onclose={toggleOpen}
111
+ />
112
+ </div>
113
+ {/if}
114
+
115
+ <!-- FAB Button -->
116
+ <div class="relative">
117
+ <IconButton
118
+ variant="primary"
119
+ size="lg"
120
+ rounded="full"
121
+ onclick={toggleOpen}
122
+ label={isOpen ? 'Close chat' : 'Open chat'}
123
+ class="w-14 h-14 shadow-lg"
124
+ >
125
+ {#if isOpen}
126
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
127
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
128
+ </svg>
129
+ {:else}
130
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
131
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
132
+ </svg>
133
+ {/if}
134
+ </IconButton>
135
+
136
+ {#if !isOpen && unreadCount > 0}
137
+ <div class="absolute -top-1 -right-1">
138
+ <Badge variant="danger" size="sm">
139
+ {unreadCount > 9 ? '9+' : unreadCount}
140
+ </Badge>
141
+ </div>
142
+ {/if}
143
+ </div>
144
+ </div>
145
+
146
+ <style>
147
+ @keyframes fade-in {
148
+ from { opacity: 0; }
149
+ to { opacity: 1; }
150
+ }
151
+
152
+ @keyframes slide-in-from-bottom-4 {
153
+ from { transform: translateY(1rem); }
154
+ to { transform: translateY(0); }
155
+ }
156
+
157
+ .animate-in {
158
+ animation: fade-in 0.2s ease-out, slide-in-from-bottom-4 0.2s ease-out;
159
+ }
160
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ChatWidgetProps } from '../types.js';
2
+ declare const ChatWidget: import("svelte").Component<ChatWidgetProps, {}, "">;
3
+ type ChatWidget = ReturnType<typeof ChatWidget>;
4
+ export default ChatWidget;
@@ -0,0 +1,60 @@
1
+ <script lang="ts">
2
+ import type { Message } from '../types.js';
3
+
4
+ interface Props {
5
+ message: Message;
6
+ class?: string;
7
+ }
8
+
9
+ const { message, class: className = '' }: Props = $props();
10
+
11
+ const isUser = $derived(message.sender === 'user');
12
+ const isSystem = $derived(message.sender === 'system');
13
+
14
+ const bubbleClasses = $derived(() => {
15
+ if (isSystem) {
16
+ return 'bg-surface text-foreground-secondary text-center text-sm italic mx-auto';
17
+ }
18
+ if (isUser) {
19
+ return 'bg-primary text-white ml-auto';
20
+ }
21
+ return 'bg-surface text-foreground mr-auto';
22
+ });
23
+
24
+ const senderLabel = $derived(() => {
25
+ switch (message.sender) {
26
+ case 'ai':
27
+ return 'AI';
28
+ case 'human':
29
+ return 'Support';
30
+ case 'system':
31
+ return '';
32
+ default:
33
+ return '';
34
+ }
35
+ });
36
+
37
+ function formatTime(timestamp: number): string {
38
+ return new Date(timestamp).toLocaleTimeString([], {
39
+ hour: '2-digit',
40
+ minute: '2-digit'
41
+ });
42
+ }
43
+ </script>
44
+
45
+ <div class="flex flex-col gap-1 {className}" class:items-end={isUser}>
46
+ {#if senderLabel() && !isUser}
47
+ <span class="text-xs text-foreground-tertiary px-1">{senderLabel()}</span>
48
+ {/if}
49
+
50
+ <div class="max-w-[80%] rounded-2xl px-4 py-2 {bubbleClasses()}">
51
+ <p class="whitespace-pre-wrap break-words">{message.content}</p>
52
+ {#if message.streaming}
53
+ <span class="inline-block w-2 h-4 bg-current animate-pulse ml-1">|</span>
54
+ {/if}
55
+ </div>
56
+
57
+ <span class="text-xs text-foreground-tertiary px-1">
58
+ {formatTime(message.timestamp)}
59
+ </span>
60
+ </div>
@@ -0,0 +1,8 @@
1
+ import type { Message } from '../types.js';
2
+ interface Props {
3
+ message: Message;
4
+ class?: string;
5
+ }
6
+ declare const MessageBubble: import("svelte").Component<Props, {}, "">;
7
+ type MessageBubble = ReturnType<typeof MessageBubble>;
8
+ export default MessageBubble;
@@ -0,0 +1,58 @@
1
+ <script lang="ts">
2
+ import { tick } from 'svelte';
3
+ import MessageBubble from './MessageBubble.svelte';
4
+ import { Spinner } from '@alliance-droid/svelte-component-library/components/atoms';
5
+ import type { Message } from '../types.js';
6
+
7
+ interface Props {
8
+ messages: Message[];
9
+ isTyping?: boolean;
10
+ typingSender?: 'ai' | 'human' | null;
11
+ class?: string;
12
+ }
13
+
14
+ const { messages, isTyping = false, typingSender = null, class: className = '' }: Props = $props();
15
+
16
+ let listElement: HTMLDivElement | undefined = $state();
17
+
18
+ // Auto-scroll to bottom when new messages arrive
19
+ $effect(() => {
20
+ if (messages.length > 0) {
21
+ scrollToBottom();
22
+ }
23
+ });
24
+
25
+ async function scrollToBottom() {
26
+ await tick();
27
+ if (listElement) {
28
+ listElement.scrollTop = listElement.scrollHeight;
29
+ }
30
+ }
31
+
32
+ const typingLabel = $derived(() => {
33
+ if (typingSender === 'human') return 'Support is typing...';
34
+ return 'AI is typing...';
35
+ });
36
+ </script>
37
+
38
+ <div
39
+ bind:this={listElement}
40
+ class="flex-1 overflow-y-auto p-4 space-y-4 {className}"
41
+ >
42
+ {#if messages.length === 0}
43
+ <div class="flex items-center justify-center h-full text-foreground-tertiary">
44
+ <p>No messages yet</p>
45
+ </div>
46
+ {:else}
47
+ {#each messages as message (message.id)}
48
+ <MessageBubble {message} />
49
+ {/each}
50
+ {/if}
51
+
52
+ {#if isTyping}
53
+ <div class="flex items-center gap-2 text-foreground-tertiary text-sm">
54
+ <Spinner size="sm" />
55
+ <span>{typingLabel()}</span>
56
+ </div>
57
+ {/if}
58
+ </div>
@@ -0,0 +1,10 @@
1
+ import type { Message } from '../types.js';
2
+ interface Props {
3
+ messages: Message[];
4
+ isTyping?: boolean;
5
+ typingSender?: 'ai' | 'human' | null;
6
+ class?: string;
7
+ }
8
+ declare const MessageList: import("svelte").Component<Props, {}, "">;
9
+ type MessageList = ReturnType<typeof MessageList>;
10
+ export default MessageList;
@@ -0,0 +1,133 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import ChatPanel from './ChatPanel.svelte';
4
+ import { Badge } from '@alliance-droid/svelte-component-library/components/atoms';
5
+ import { chatStore } from '../stores/chat.js';
6
+ import { connectionStore } from '../stores/connection.js';
7
+ import type { SupportChatProps, ClientMessage, ServerMessage } from '../types.js';
8
+
9
+ const { serverUrl, sessionId, class: className = '' }: SupportChatProps = $props();
10
+
11
+ let ws: WebSocket | null = null;
12
+
13
+ const messages = chatStore.messages;
14
+ const status = chatStore.status;
15
+ const isTyping = chatStore.isTyping;
16
+ const typingSender = chatStore.typingSender;
17
+ const connectionState = connectionStore.state;
18
+
19
+ function connect() {
20
+ connectionStore.setConnecting();
21
+
22
+ try {
23
+ ws = new WebSocket(serverUrl);
24
+
25
+ ws.onopen = () => {
26
+ // Join the session as support agent
27
+ send({ type: 'join', sessionId });
28
+ };
29
+
30
+ ws.onmessage = (event) => {
31
+ try {
32
+ const message: ServerMessage = JSON.parse(event.data);
33
+ handleServerMessage(message);
34
+ } catch (err) {
35
+ console.error('[SupportChat] Failed to parse message:', err);
36
+ }
37
+ };
38
+
39
+ ws.onclose = () => {
40
+ connectionStore.setDisconnected();
41
+ };
42
+
43
+ ws.onerror = () => {
44
+ connectionStore.setError('Connection error');
45
+ };
46
+ } catch (err) {
47
+ connectionStore.setDisconnected('Failed to connect');
48
+ }
49
+ }
50
+
51
+ function send(message: ClientMessage) {
52
+ if (ws && ws.readyState === WebSocket.OPEN) {
53
+ ws.send(JSON.stringify(message));
54
+ }
55
+ }
56
+
57
+ function handleServerMessage(message: ServerMessage) {
58
+ switch (message.type) {
59
+ case 'connected':
60
+ connectionStore.setConnected(sessionId);
61
+ chatStore.setStatus('human');
62
+ break;
63
+
64
+ case 'message':
65
+ if (message.id && message.content && message.sender) {
66
+ chatStore.addMessage({
67
+ id: message.id,
68
+ content: message.content,
69
+ sender: message.sender,
70
+ timestamp: message.timestamp || Date.now()
71
+ });
72
+ }
73
+ break;
74
+
75
+ case 'typing':
76
+ chatStore.setTyping(true, 'ai');
77
+ setTimeout(() => chatStore.setTyping(false, null), 3000);
78
+ break;
79
+
80
+ case 'error':
81
+ connectionStore.setError(message.error || 'Unknown error');
82
+ break;
83
+ }
84
+ }
85
+
86
+ function handleMessage(content: string) {
87
+ const id = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
88
+
89
+ // Add to local store
90
+ chatStore.addMessage({
91
+ id,
92
+ content,
93
+ sender: 'human',
94
+ timestamp: Date.now()
95
+ });
96
+
97
+ // Send to server
98
+ send({ type: 'message', content, sessionId });
99
+ }
100
+
101
+ onMount(() => {
102
+ connect();
103
+ });
104
+
105
+ onDestroy(() => {
106
+ if (ws) {
107
+ ws.close();
108
+ ws = null;
109
+ }
110
+ chatStore.clear();
111
+ connectionStore.reset();
112
+ });
113
+ </script>
114
+
115
+ <div class="h-full {className}">
116
+ <ChatPanel
117
+ messages={$messages}
118
+ status={$status}
119
+ connectionState={$connectionState}
120
+ isTyping={$isTyping}
121
+ typingSender={$typingSender}
122
+ placeholder="Reply to customer..."
123
+ enableEscalation={false}
124
+ onmessage={handleMessage}
125
+ >
126
+ {#snippet header()}
127
+ <div class="flex items-center gap-2">
128
+ <span class="font-semibold text-foreground">Support Chat</span>
129
+ <Badge variant="info" size="sm">Session: {sessionId.slice(0, 8)}...</Badge>
130
+ </div>
131
+ {/snippet}
132
+ </ChatPanel>
133
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { SupportChatProps } from '../types.js';
2
+ declare const SupportChat: import("svelte").Component<SupportChatProps, {}, "">;
3
+ type SupportChat = ReturnType<typeof SupportChat>;
4
+ export default SupportChat;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @alliance-droid/chat-widget
3
+ *
4
+ * Svelte chat widget with AI support and human escalation
5
+ */
6
+ export { default as ChatWidget } from './components/ChatWidget.svelte';
7
+ export { default as SupportChat } from './components/SupportChat.svelte';
8
+ export { default as ChatPanel } from './components/ChatPanel.svelte';
9
+ export { default as MessageList } from './components/MessageList.svelte';
10
+ export { default as MessageBubble } from './components/MessageBubble.svelte';
11
+ export { default as ChatInput } from './components/ChatInput.svelte';
12
+ export { chatStore } from './stores/chat.js';
13
+ export { connectionStore } from './stores/connection.js';
14
+ export { connect, disconnect, sendMessage, requestEscalation, sendTyping } from './client/connection.js';
15
+ export type { Message, ClientMessage, ServerMessage, ConnectionState, ChatStatus, ChatWidgetProps, SupportChatProps, ChatServerConfig, AIProviderConfig, EscalationConfig, ChatSession } from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @alliance-droid/chat-widget
3
+ *
4
+ * Svelte chat widget with AI support and human escalation
5
+ */
6
+ // Components
7
+ export { default as ChatWidget } from './components/ChatWidget.svelte';
8
+ export { default as SupportChat } from './components/SupportChat.svelte';
9
+ export { default as ChatPanel } from './components/ChatPanel.svelte';
10
+ export { default as MessageList } from './components/MessageList.svelte';
11
+ export { default as MessageBubble } from './components/MessageBubble.svelte';
12
+ export { default as ChatInput } from './components/ChatInput.svelte';
13
+ // Stores
14
+ export { chatStore } from './stores/chat.js';
15
+ export { connectionStore } from './stores/connection.js';
16
+ // Client utilities
17
+ export { connect, disconnect, sendMessage, requestEscalation, sendTyping } from './client/connection.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Anthropic Provider
3
+ *
4
+ * Fallback AI provider using Anthropic's Claude API
5
+ */
6
+ import type { AIProvider, AIProviderOptions } from './provider.js';
7
+ import type { Message } from '../../types.js';
8
+ export declare class AnthropicProvider implements AIProvider {
9
+ private apiKey;
10
+ private model;
11
+ private maxTokens;
12
+ constructor(options: AIProviderOptions);
13
+ generateResponse(messages: Message[], systemPrompt?: string): AsyncGenerator<string, void, unknown>;
14
+ summarize(messages: Message[]): Promise<string>;
15
+ private formatMessages;
16
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Anthropic Provider
3
+ *
4
+ * Fallback AI provider using Anthropic's Claude API
5
+ */
6
+ const ANTHROPIC_API_URL = 'https://api.anthropic.com/v1/messages';
7
+ export class AnthropicProvider {
8
+ apiKey;
9
+ model;
10
+ maxTokens;
11
+ constructor(options) {
12
+ this.apiKey = options.apiKey;
13
+ this.model = options.model || 'claude-3-haiku-20240307';
14
+ this.maxTokens = options.maxTokens || 1024;
15
+ }
16
+ async *generateResponse(messages, systemPrompt) {
17
+ const apiMessages = this.formatMessages(messages);
18
+ const response = await fetch(ANTHROPIC_API_URL, {
19
+ method: 'POST',
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ 'x-api-key': this.apiKey,
23
+ 'anthropic-version': '2023-06-01'
24
+ },
25
+ body: JSON.stringify({
26
+ model: this.model,
27
+ max_tokens: this.maxTokens,
28
+ system: systemPrompt,
29
+ messages: apiMessages,
30
+ stream: true
31
+ })
32
+ });
33
+ if (!response.ok) {
34
+ const error = await response.text();
35
+ throw new Error(`Anthropic API error: ${response.status} - ${error}`);
36
+ }
37
+ const reader = response.body?.getReader();
38
+ if (!reader)
39
+ throw new Error('No response body');
40
+ const decoder = new TextDecoder();
41
+ let buffer = '';
42
+ while (true) {
43
+ const { done, value } = await reader.read();
44
+ if (done)
45
+ break;
46
+ buffer += decoder.decode(value, { stream: true });
47
+ const lines = buffer.split('\n');
48
+ buffer = lines.pop() || '';
49
+ for (const line of lines) {
50
+ if (line.startsWith('data: ')) {
51
+ const data = line.slice(6);
52
+ try {
53
+ const parsed = JSON.parse(data);
54
+ if (parsed.type === 'content_block_delta') {
55
+ const text = parsed.delta?.text;
56
+ if (text) {
57
+ yield text;
58
+ }
59
+ }
60
+ }
61
+ catch {
62
+ // Skip invalid JSON
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ async summarize(messages) {
69
+ const conversationText = messages
70
+ .map(m => `${m.sender}: ${m.content}`)
71
+ .join('\n');
72
+ const response = await fetch(ANTHROPIC_API_URL, {
73
+ method: 'POST',
74
+ headers: {
75
+ 'Content-Type': 'application/json',
76
+ 'x-api-key': this.apiKey,
77
+ 'anthropic-version': '2023-06-01'
78
+ },
79
+ body: JSON.stringify({
80
+ model: this.model,
81
+ max_tokens: 150,
82
+ system: 'Summarize this customer support conversation in 1-2 sentences. Focus on what the customer needs help with.',
83
+ messages: [
84
+ {
85
+ role: 'user',
86
+ content: conversationText
87
+ }
88
+ ]
89
+ })
90
+ });
91
+ if (!response.ok) {
92
+ return 'Customer requested support assistance.';
93
+ }
94
+ const data = await response.json();
95
+ return data.content?.[0]?.text || 'Customer requested support assistance.';
96
+ }
97
+ formatMessages(messages) {
98
+ const apiMessages = [];
99
+ for (const msg of messages) {
100
+ if (msg.sender === 'user') {
101
+ apiMessages.push({ role: 'user', content: msg.content });
102
+ }
103
+ else if (msg.sender === 'ai') {
104
+ apiMessages.push({ role: 'assistant', content: msg.content });
105
+ }
106
+ }
107
+ return apiMessages;
108
+ }
109
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * OpenAI Provider
3
+ *
4
+ * Fallback AI provider using OpenAI's API
5
+ */
6
+ import type { AIProvider, AIProviderOptions } from './provider.js';
7
+ import type { Message } from '../../types.js';
8
+ export declare class OpenAIProvider implements AIProvider {
9
+ private apiKey;
10
+ private model;
11
+ private maxTokens;
12
+ constructor(options: AIProviderOptions);
13
+ generateResponse(messages: Message[], systemPrompt?: string): AsyncGenerator<string, void, unknown>;
14
+ summarize(messages: Message[]): Promise<string>;
15
+ private formatMessages;
16
+ }