@messenger-box/tailwind-ui-inbox 10.0.3-alpha.71 → 10.0.3-alpha.72

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 (148) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/components/AIAgent/AIAgent.d.ts +14 -0
  3. package/lib/components/AIAgent/AIAgent.d.ts.map +1 -0
  4. package/lib/components/AIAgent/AIAgent.js +1148 -0
  5. package/lib/components/AIAgent/AIAgent.js.map +1 -0
  6. package/lib/components/AIAgent/index.d.ts +2 -0
  7. package/lib/components/AIAgent/index.d.ts.map +1 -0
  8. package/lib/components/InboxMessage/InputComponent.d.ts +9 -0
  9. package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -0
  10. package/lib/components/InboxMessage/InputComponent.js +210 -0
  11. package/lib/components/InboxMessage/InputComponent.js.map +1 -0
  12. package/lib/components/InboxMessage/MessageInput.d.ts.map +1 -1
  13. package/lib/components/InboxMessage/MessageInput.js +14 -10
  14. package/lib/components/InboxMessage/MessageInput.js.map +1 -1
  15. package/lib/components/InboxMessage/MessageInputComponent.d.ts +9 -0
  16. package/lib/components/InboxMessage/MessageInputComponent.d.ts.map +1 -0
  17. package/lib/components/InboxMessage/MessageInputComponent.js +173 -0
  18. package/lib/components/InboxMessage/MessageInputComponent.js.map +1 -0
  19. package/lib/components/InboxMessage/Messages.d.ts.map +1 -1
  20. package/lib/components/InboxMessage/Messages.js +4 -54
  21. package/lib/components/InboxMessage/Messages.js.map +1 -1
  22. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts +17 -0
  23. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts.map +1 -0
  24. package/lib/components/InboxMessage/MessagesBuilderUi.js +162 -0
  25. package/lib/components/InboxMessage/MessagesBuilderUi.js.map +1 -0
  26. package/lib/components/InboxMessage/UploadImageButton.d.ts +1 -0
  27. package/lib/components/InboxMessage/UploadImageButton.d.ts.map +1 -1
  28. package/lib/components/InboxMessage/UploadImageButton.js +3 -3
  29. package/lib/components/InboxMessage/UploadImageButton.js.map +1 -1
  30. package/lib/components/InboxMessage/index.d.ts +3 -0
  31. package/lib/components/InboxMessage/index.d.ts.map +1 -1
  32. package/lib/components/InboxMessage/message-widgets/CommonMessage.d.ts.map +1 -1
  33. package/lib/components/InboxMessage/message-widgets/CommonMessage.js +11 -6
  34. package/lib/components/InboxMessage/message-widgets/CommonMessage.js.map +1 -1
  35. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +14 -0
  36. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -0
  37. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +1525 -0
  38. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -0
  39. package/lib/components/InboxMessage/message-widgets/PlainMessage.d.ts.map +1 -1
  40. package/lib/components/InboxMessage/message-widgets/PlainMessage.js +6 -3
  41. package/lib/components/InboxMessage/message-widgets/PlainMessage.js.map +1 -1
  42. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.d.ts.map +1 -1
  43. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js +207 -12
  44. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js.map +1 -1
  45. package/lib/components/InboxMessage/message-widgets/index.d.ts +1 -0
  46. package/lib/components/InboxMessage/message-widgets/index.d.ts.map +1 -1
  47. package/lib/components/index.d.ts +2 -1
  48. package/lib/components/index.d.ts.map +1 -1
  49. package/lib/compute.d.ts.map +1 -1
  50. package/lib/compute.js +79 -3
  51. package/lib/compute.js.map +1 -1
  52. package/lib/config/env-config.d.ts +6 -0
  53. package/lib/config/env-config.d.ts.map +1 -1
  54. package/lib/config/env-config.js +19 -1
  55. package/lib/config/env-config.js.map +1 -1
  56. package/lib/container/AiInbox.d.ts +15 -0
  57. package/lib/container/AiInbox.d.ts.map +1 -0
  58. package/lib/container/AiInbox.js +1520 -0
  59. package/lib/container/AiInbox.js.map +1 -0
  60. package/lib/container/AiInboxWithLoader.d.ts +36 -0
  61. package/lib/container/AiInboxWithLoader.d.ts.map +1 -0
  62. package/lib/container/AiInboxWithLoader.js +300 -0
  63. package/lib/container/AiInboxWithLoader.js.map +1 -0
  64. package/lib/container/AiLandingInput.d.ts +4 -0
  65. package/lib/container/AiLandingInput.d.ts.map +1 -0
  66. package/lib/container/AiLandingInput.js +164 -0
  67. package/lib/container/AiLandingInput.js.map +1 -0
  68. package/lib/container/Inbox.d.ts.map +1 -1
  69. package/lib/container/Inbox.js +6 -4
  70. package/lib/container/Inbox.js.map +1 -1
  71. package/lib/container/InboxAiMessagesLoader.d.ts +36 -0
  72. package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -0
  73. package/lib/container/InboxAiMessagesLoader.js +47 -0
  74. package/lib/container/InboxAiMessagesLoader.js.map +1 -0
  75. package/lib/container/InboxContainer.d.ts +12 -0
  76. package/lib/container/InboxContainer.d.ts.map +1 -0
  77. package/lib/container/InboxContainer.js +31 -0
  78. package/lib/container/InboxContainer.js.map +1 -0
  79. package/lib/container/InboxTemplate1.d.ts +15 -0
  80. package/lib/container/InboxTemplate1.d.ts.map +1 -0
  81. package/lib/container/InboxTemplate1.js +1375 -0
  82. package/lib/container/InboxTemplate1.js.map +1 -0
  83. package/lib/container/InboxTemplate1WithLoader.d.ts +36 -0
  84. package/lib/container/InboxTemplate1WithLoader.d.ts.map +1 -0
  85. package/lib/container/InboxTemplate2.d.ts +15 -0
  86. package/lib/container/InboxTemplate2.d.ts.map +1 -0
  87. package/lib/container/InboxTemplate2.js +1426 -0
  88. package/lib/container/InboxTemplate2.js.map +1 -0
  89. package/lib/container/InboxWithAiLoader.d.ts +15 -0
  90. package/lib/container/InboxWithAiLoader.d.ts.map +1 -0
  91. package/lib/container/InboxWithAiLoader.js +56 -0
  92. package/lib/container/InboxWithAiLoader.js.map +1 -0
  93. package/lib/container/ServiceInbox.js +1 -1
  94. package/lib/container/ServiceInbox.js.map +1 -1
  95. package/lib/container/ThreadMessages.js +1 -1
  96. package/lib/container/ThreadMessages.js.map +1 -1
  97. package/lib/container/ThreadMessagesInbox.js +1 -1
  98. package/lib/container/ThreadMessagesInbox.js.map +1 -1
  99. package/lib/container/Threads.js +1 -1
  100. package/lib/container/Threads.js.map +1 -1
  101. package/lib/container/index.d.ts +4 -1
  102. package/lib/container/index.d.ts.map +1 -1
  103. package/lib/index.js +1 -1
  104. package/lib/machines/aiAgentMachine.d.ts +3 -0
  105. package/lib/machines/aiAgentMachine.d.ts.map +1 -0
  106. package/lib/machines/aiAgentMachine.js +1040 -0
  107. package/lib/machines/aiAgentMachine.js.map +1 -0
  108. package/lib/machines/types.d.ts +77 -0
  109. package/lib/machines/types.d.ts.map +1 -0
  110. package/lib/routes.json +40 -0
  111. package/lib/templates/InboxWithAi.d.ts +15 -0
  112. package/lib/templates/InboxWithAi.d.ts.map +1 -0
  113. package/lib/templates/InboxWithAi.js +405 -0
  114. package/lib/templates/InboxWithAi.js.map +1 -0
  115. package/lib/templates/InboxWithAi.tsx +502 -0
  116. package/package.json +7 -5
  117. package/src/components/AIAgent/AIAgent.tsx +1351 -0
  118. package/src/components/AIAgent/README.md +82 -0
  119. package/src/components/AIAgent/index.ts +1 -0
  120. package/src/components/InboxMessage/InputComponent.tsx +263 -0
  121. package/src/components/InboxMessage/MessageInput.tsx +73 -66
  122. package/src/components/InboxMessage/MessageInputComponent.tsx +245 -0
  123. package/src/components/InboxMessage/Messages.tsx +2 -56
  124. package/src/components/InboxMessage/MessagesBuilderUi.tsx +205 -0
  125. package/src/components/InboxMessage/UploadImageButton.tsx +3 -2
  126. package/src/components/InboxMessage/index.ts +3 -0
  127. package/src/components/InboxMessage/message-widgets/CommonMessage.tsx +39 -21
  128. package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +1968 -0
  129. package/src/components/InboxMessage/message-widgets/PlainMessage.tsx +6 -2
  130. package/src/components/InboxMessage/message-widgets/SlackLikeMessageGroup.tsx +306 -54
  131. package/src/components/InboxMessage/message-widgets/index.ts +1 -0
  132. package/src/components/index.ts +4 -0
  133. package/src/compute.ts +83 -2
  134. package/src/config/env-config.ts +6 -0
  135. package/src/container/AiInbox.tsx +1796 -0
  136. package/src/container/AiInboxWithLoader.tsx +356 -0
  137. package/src/container/AiLandingInput.tsx +168 -0
  138. package/src/container/Inbox.tsx +8 -5
  139. package/src/container/InboxAiMessagesLoader.tsx +68 -0
  140. package/src/container/InboxContainer.tsx +35 -0
  141. package/src/container/InboxTemplate1.tsx +1542 -0
  142. package/src/container/InboxTemplate1WithLoader.tsx +338 -0
  143. package/src/container/InboxTemplate2.tsx +1606 -0
  144. package/src/container/InboxWithAiLoader.tsx +76 -0
  145. package/src/container/index.ts +15 -1
  146. package/src/machines/aiAgentMachine.ts +1248 -0
  147. package/src/machines/types.ts +59 -0
  148. package/src/templates/InboxWithAi.tsx +502 -0
@@ -0,0 +1,1040 @@
1
+ import {createMachine,assign,fromPromise}from'xstate';import {config}from'../config/env-config.js';const {
2
+ CLIENT_URL,
3
+ VITE_ANTHROPIC_API_KEY,
4
+ VITE_OPENAI_API_KEY,
5
+ ANTHROPIC_API_KEY,
6
+ OPENAI_API_KEY,
7
+ NEWS_API_KEY
8
+ } = config;
9
+ const env = {
10
+ ANTHROPIC_API_KEY: VITE_ANTHROPIC_API_KEY || ANTHROPIC_API_KEY,
11
+ OPENAI_API_KEY: VITE_OPENAI_API_KEY || OPENAI_API_KEY,
12
+ NEWS_API_KEY: NEWS_API_KEY
13
+ };
14
+ // API configuration - using environment variables from dev.env
15
+ const API_CONFIG = {
16
+ // Use environment variables for API keys
17
+ ANTHROPIC_API_KEY: env?.ANTHROPIC_API_KEY,
18
+ OPENAI_API_KEY: env?.OPENAI_API_KEY,
19
+ NEWS_API_KEY: env?.NEWS_API_KEY,
20
+ // Configurable proxy endpoints
21
+ ANTHROPIC_ENDPOINT: '/api/anthropic/messages',
22
+ OPENAI_ENDPOINT: '/api/openai',
23
+ // Direct MCP search APIs (these are public and don't have CORS issues)
24
+ NEWS_API_ENDPOINT: 'https://newsapi.org/v2/everything',
25
+ REDDIT_SEARCH_ENDPOINT: 'https://www.reddit.com/search.json',
26
+ REDDIT_TRENDING_ENDPOINT: 'https://www.reddit.com/r/news/hot.json',
27
+ DUCKDUCKGO_ENDPOINT: 'https://api.duckduckgo.com/',
28
+ // Model configuration
29
+ DEFAULT_MODEL: 'claude-3-5-haiku-20241022',
30
+ OPENAI_MODEL: 'gpt-4o-mini',
31
+ // Check which AI provider is available
32
+ get availableProvider() {
33
+ if (this.ANTHROPIC_API_KEY) return 'anthropic';
34
+ if (this.OPENAI_API_KEY) return 'openai';
35
+ return null;
36
+ },
37
+ // Get the appropriate endpoint based on available provider
38
+ get primaryEndpoint() {
39
+ return this.availableProvider === 'anthropic' ? this.ANTHROPIC_ENDPOINT : this.OPENAI_ENDPOINT;
40
+ },
41
+ // Get the appropriate model based on available provider
42
+ get primaryModel() {
43
+ return this.availableProvider === 'anthropic' ? this.DEFAULT_MODEL : this.OPENAI_MODEL;
44
+ }
45
+ };
46
+ // Log configuration on startup
47
+ console.log('🤖 AI Agent Machine Configuration:');
48
+ console.log(` Available Provider: ${API_CONFIG.availableProvider || 'None'}`);
49
+ console.log(` Primary Endpoint: ${API_CONFIG.primaryEndpoint}`);
50
+ console.log(` Primary Model: ${API_CONFIG.primaryModel}`);
51
+ console.log(` Using Proxy for AI APIs: ✅ (avoids CORS issues)`);
52
+ console.log(` Using Direct APIs for MCP Search: ✅ (public APIs)`);
53
+ console.log(` Anthropic API Key: ${API_CONFIG.ANTHROPIC_API_KEY ? '✅ Configured' : '❌ Not configured'}`);
54
+ console.log(` OpenAI API Key: ${API_CONFIG.OPENAI_API_KEY ? '✅ Configured' : '❌ Not configured'}`);
55
+ console.log(` News API Key: ${API_CONFIG.NEWS_API_KEY ? '✅ Configured' : '❌ Not configured'}`);
56
+ // Test API configuration
57
+ if (!API_CONFIG.availableProvider) {
58
+ console.error('🚨 CRITICAL: No AI API provider configured!');
59
+ console.error('🚨 Please set VITE_ANTHROPIC_API_KEY or VITE_OPENAI_API_KEY in your environment variables.');
60
+ } else {
61
+ console.log(`✅ AI API provider configured: ${API_CONFIG.availableProvider}`);
62
+ }
63
+ // Helper function to get the base URL for proxy calls
64
+ function getProxyBaseUrl() {
65
+ // Use Vite dev server proxy to avoid CORS issues
66
+ return CLIENT_URL || 'http://localhost:3011'; // Vite dev server
67
+ }
68
+ // Log the current proxy configuration
69
+ console.log(`🌐 Proxy Configuration: ${getProxyBaseUrl()}`);
70
+ // Helper function to make API calls through proxy (avoids CORS)
71
+ async function makeApiCall(endpoint, options) {
72
+ try {
73
+ const baseUrl = getProxyBaseUrl();
74
+ const url = `${baseUrl}${endpoint}`;
75
+ console.log(`🌐 Making API call through proxy to: ${url}`);
76
+ console.log(`📤 Request options:`, {
77
+ method: options.method,
78
+ headers: options.headers,
79
+ body: options.body ? JSON.parse(options.body) : undefined
80
+ });
81
+ const response = await fetch(url, options);
82
+ if (!response.ok) {
83
+ const errorData = await response.json().catch(() => ({}));
84
+ console.error('🚨 API Error:', response.status, errorData);
85
+ let errorMessage = 'API request failed';
86
+ if (errorData.error) {
87
+ if (typeof errorData.error === 'string') {
88
+ errorMessage = errorData.error;
89
+ } else if (errorData.error.message) {
90
+ errorMessage = errorData.error.message;
91
+ } else if (errorData.error.type) {
92
+ errorMessage = `${errorData.error.type}: ${errorData.error.message || 'Unknown error'}`;
93
+ }
94
+ }
95
+ throw new Error(errorMessage);
96
+ }
97
+ return response;
98
+ } catch (error) {
99
+ console.error('🚨 API call error:', error);
100
+ throw error;
101
+ }
102
+ }
103
+ // Helper function to fetch news from NewsAPI directly
104
+ async function fetchNewsFromNewsAPI(query) {
105
+ if (!API_CONFIG.NEWS_API_KEY) {
106
+ console.warn('⚠️ News API key not found, skipping NewsAPI');
107
+ return [];
108
+ }
109
+ try {
110
+ const response = await fetch(`${API_CONFIG.NEWS_API_ENDPOINT}?q=${encodeURIComponent(query)}&apiKey=${API_CONFIG.NEWS_API_KEY}&language=en&sortBy=publishedAt&pageSize=5`);
111
+ if (!response.ok) {
112
+ console.error('NewsAPI error:', response.status);
113
+ return [];
114
+ }
115
+ const data = await response.json();
116
+ if (data.articles) {
117
+ return data.articles.map(article => ({
118
+ title: article.title,
119
+ url: article.url,
120
+ description: article.description || article.title,
121
+ publishedAt: article.publishedAt,
122
+ source: {
123
+ name: article.source.name
124
+ }
125
+ }));
126
+ }
127
+ } catch (error) {
128
+ console.error('NewsAPI error:', error);
129
+ }
130
+ return [];
131
+ }
132
+ // Helper function to fetch from Reddit API directly
133
+ async function fetchAlternativeNews(query) {
134
+ try {
135
+ const response = await fetch(`${API_CONFIG.REDDIT_SEARCH_ENDPOINT}?q=${encodeURIComponent(query)}&sort=new&t=day&limit=3&restrict_sr=false&type=link`);
136
+ if (!response.ok) {
137
+ console.error('Reddit API error:', response.status);
138
+ return [];
139
+ }
140
+ const data = await response.json();
141
+ if (data?.data?.children) {
142
+ return data.data.children.filter(post => post.data.url && !post.data.is_self).slice(0, 3).map(post => ({
143
+ title: post.data.title,
144
+ url: post.data.url,
145
+ description: `Discussion: ${post.data.title} (${post.data.score} upvotes)`,
146
+ publishedAt: new Date(post.data.created_utc * 1000).toISOString(),
147
+ source: {
148
+ name: `r/${post.data.subreddit}`
149
+ }
150
+ }));
151
+ }
152
+ } catch (error) {
153
+ console.error('Reddit API error:', error);
154
+ }
155
+ return [];
156
+ }
157
+ // Helper function to search DuckDuckGo directly
158
+ async function searchDuckDuckGo(query) {
159
+ try {
160
+ const response = await fetch(`${API_CONFIG.DUCKDUCKGO_ENDPOINT}?q=${encodeURIComponent(query)}&format=json&no_html=1&skip_disambig=1`);
161
+ if (!response.ok) {
162
+ console.error('DuckDuckGo API error:', response.status);
163
+ return [];
164
+ }
165
+ const data = await response.json();
166
+ const results = [];
167
+ // Add abstract if available
168
+ if (data.Abstract) {
169
+ results.push({
170
+ title: data.Heading || `About ${query}`,
171
+ url: data.AbstractURL || `https://duckduckgo.com/?q=${encodeURIComponent(query)}`,
172
+ snippet: data.Abstract,
173
+ source: 'DuckDuckGo'
174
+ });
175
+ }
176
+ // Add related topics
177
+ if (data.RelatedTopics && data.RelatedTopics.length > 0) {
178
+ data.RelatedTopics.slice(0, 3).forEach(topic => {
179
+ if (topic.Text && topic.FirstURL) {
180
+ results.push({
181
+ title: topic.Text.split(' - ')[0] || topic.Text.substring(0, 60),
182
+ url: topic.FirstURL,
183
+ snippet: topic.Text,
184
+ source: 'DuckDuckGo'
185
+ });
186
+ }
187
+ });
188
+ }
189
+ return results;
190
+ } catch (error) {
191
+ console.error('DuckDuckGo API error:', error);
192
+ return [];
193
+ }
194
+ }
195
+ // Helper function to get trending news from Reddit directly
196
+ async function getTrendingNews() {
197
+ try {
198
+ const response = await fetch(`${API_CONFIG.REDDIT_TRENDING_ENDPOINT}?limit=5`);
199
+ if (!response.ok) {
200
+ console.error('Reddit trending error:', response.status);
201
+ return [];
202
+ }
203
+ const data = await response.json();
204
+ if (data?.data?.children) {
205
+ return data.data.children.filter(post => post.data.url && !post.data.is_self).map(post => ({
206
+ title: post.data.title,
207
+ url: post.data.url,
208
+ description: `Trending: ${post.data.title} (${post.data.score} upvotes, ${post.data.num_comments} comments)`,
209
+ publishedAt: new Date(post.data.created_utc * 1000).toISOString(),
210
+ source: {
211
+ name: 'r/news'
212
+ }
213
+ }));
214
+ }
215
+ } catch (error) {
216
+ console.error('Reddit trending error:', error);
217
+ }
218
+ return [];
219
+ }
220
+ // Direct MCP search function - no more server dependency
221
+ async function performDirectMCPSearch(query, includeNews = true, includeWeb = true) {
222
+ try {
223
+ console.log(`🔍 Performing direct MCP search for: "${query}" (news: ${includeNews}, web: ${includeWeb})`);
224
+ const promises = [];
225
+ // Fetch news if requested
226
+ if (includeNews) {
227
+ // Try multiple news sources
228
+ promises.push(fetchNewsFromNewsAPI(query), fetchAlternativeNews(query));
229
+ // For US news specifically, get trending
230
+ if (query.toLowerCase().includes('us news') || query.toLowerCase().includes('american news')) {
231
+ promises.push(getTrendingNews());
232
+ }
233
+ }
234
+ // Fetch web search if requested
235
+ if (includeWeb) {
236
+ promises.push(searchDuckDuckGo(query));
237
+ }
238
+ // Execute all searches concurrently
239
+ const results = await Promise.allSettled(promises);
240
+ // Combine all successful results
241
+ let searchResults = [];
242
+ let newsArticles = [];
243
+ results.forEach((result, index) => {
244
+ if (result.status === 'fulfilled' && Array.isArray(result.value)) {
245
+ if (includeWeb && index === results.length - 1) {
246
+ // Last promise is web search
247
+ searchResults = result.value;
248
+ } else if (includeNews) {
249
+ // Other promises are news sources
250
+ newsArticles = [...newsArticles, ...result.value];
251
+ }
252
+ }
253
+ });
254
+ // Remove duplicates and limit results
255
+ newsArticles = newsArticles.filter((article, index, self) => index === self.findIndex(a => a.title === article.title)).slice(0, 8);
256
+ searchResults = searchResults.slice(0, 5);
257
+ const response = {
258
+ searchResults: includeWeb ? searchResults : [],
259
+ newsArticles: includeNews ? newsArticles : [],
260
+ summary: `Found ${searchResults.length} web results and ${newsArticles.length} news articles for "${query}"`,
261
+ sources: [...(includeWeb ? ['DuckDuckGo'] : []), ...(includeNews ? ['NewsAPI', 'Reddit', 'Alternative Sources'] : [])].filter(Boolean),
262
+ searchTime: Date.now(),
263
+ realData: true // Flag to indicate this is real data
264
+ };
265
+ console.log(`✅ Direct MCP search completed: ${response.searchResults.length} web + ${response.newsArticles.length} news results`);
266
+ return response;
267
+ } catch (error) {
268
+ console.error('🚨 Direct MCP search error:', error);
269
+ throw error;
270
+ }
271
+ }
272
+ // Helper function to detect if a query needs multi-message response
273
+ function needsMultiMessageResponse(query) {
274
+ const multiMessageKeywords = ['explain step by step', 'break down', 'tutorial', 'guide', 'how to', 'teach me', 'walk me through', 'step-by-step', 'detailed explanation', 'in detail', 'comprehensive', 'thorough', 'complete guide', 'coding', 'programming', 'development', 'build', 'create', 'multiple', 'several', 'various', 'different ways'];
275
+ const lowerQuery = query.toLowerCase();
276
+ return multiMessageKeywords.some(keyword => lowerQuery.includes(keyword)) || query.length > 200; // Long queries often benefit from multi-message responses
277
+ }
278
+ // Helper function to detect if a query needs real-time data
279
+ function needsRealTimeData(query) {
280
+ const realTimeKeywords = ['latest', 'recent', 'news', 'current', 'today', 'yesterday', 'breaking', 'update', 'now', 'price', 'stock', 'weather', 'trending', 'popular', 'search', "what's happening", 'tell me about', 'find', 'look up', 'research'];
281
+ const lowerQuery = query.toLowerCase();
282
+ return realTimeKeywords.some(keyword => lowerQuery.includes(keyword));
283
+ }
284
+ // Helper function to format MCP data for the agent
285
+ function formatMCPDataForAgent(mcpData) {
286
+ let context = '';
287
+ if (mcpData.searchResults && mcpData.searchResults.length > 0) {
288
+ context += 'Current web search results:\n';
289
+ mcpData.searchResults.forEach((result, i) => {
290
+ context += `${i + 1}. **${result.title}**\n ${result.snippet}\n Source: ${result.url}\n\n`;
291
+ });
292
+ }
293
+ if (mcpData.newsArticles && mcpData.newsArticles.length > 0) {
294
+ context += 'Recent news articles:\n';
295
+ mcpData.newsArticles.forEach((article, i) => {
296
+ context += `${i + 1}. **${article.title}**\n ${article.description}\n Published: ${new Date(article.publishedAt).toLocaleDateString()}\n Source: ${article.source.name}\n\n`;
297
+ });
298
+ }
299
+ if (context) {
300
+ context = 'Here is the current information I have access to:\n\n' + context + '\nPlease use this information to provide an accurate, up-to-date response.';
301
+ }
302
+ return context;
303
+ }
304
+ // Helper function to get the appropriate system prompt based on provider
305
+ function getSystemPrompt(provider, includeMCP = false) {
306
+ const basePrompt = includeMCP ? 'You are a helpful AI assistant that can access real-time information through web search and news APIs. When provided with current information, use it to give accurate, up-to-date responses. Always cite your sources when referencing specific information from search results or news articles. You excel at providing comprehensive analysis and insights based on the latest data available.' : 'You are a helpful AI assistant that provides detailed, step-by-step responses. Focus on the specific aspect requested and provide practical, actionable information.';
307
+ if (provider === 'anthropic') {
308
+ return basePrompt;
309
+ } else if (provider === 'openai') {
310
+ return basePrompt;
311
+ }
312
+ return basePrompt;
313
+ }
314
+ // Helper function to get conversation context from regular messages
315
+ function getConversationContext(regularMessages) {
316
+ if (!regularMessages || regularMessages.length === 0) return '';
317
+ // Get the last few messages for context
318
+ const recentMessages = regularMessages.slice(-5);
319
+ let context = 'Recent conversation context:\n';
320
+ recentMessages.forEach((msg, index) => {
321
+ const author = msg.author?.username || msg.author?.givenName || 'User';
322
+ const content = msg.message?.substring(0, 200) || ''; // Limit content length
323
+ if (content.trim()) {
324
+ context += `${index + 1}. ${author}: ${content}\n`;
325
+ }
326
+ });
327
+ return context + '\n';
328
+ }
329
+ const aiAgentMachine = createMachine({
330
+ /** @xstate-layout N4IgpgJg5mDOIC5QEMCWBBGA7ALgOlQgBswBiAZQFEA5AEQH0BZS889AcUoG0AGAXUSgADgHtYqHKhFZBIAB6IA7ACZleAGwBWdYoAsmngA4AzAE5Fi4wBoQAT0S6AjKbzHHy06aO7Du3eoBfAJs0TDBcAmIyAElqAAUAVQAVegBhAAl0ak5eASQQUXFJaVkFBE1dF0dvXx49Q19NG3sEXUUXHz9lRydFA2dNIJCMbHxCElJUgBlKdAAleko5uYB5OdzZQokpGXyyzU1jPFN9ZXVdHmN9dUNmxGNfPB7NRUNnR0N1ZX0hkFDRvDILDIIi2ABeqCwUFIG3yW2Ku1AZXcykUGlMhk0hh4PEcenU5zurV0R16yiupkODV+-3C+CBIPBkOhXEceWEYm2JT2iBRaPUGKxOLx-kJdkQ33UeA8ZnUxiuulRuhpIzpeAAZmAcABjAAWzNoyBwyFIEGkYAIWAAbiIANYWzU63WMVJxQ3G2Ecoo7Uq87FS8lnE6KardInGc54TTKF48bQVE4VQbBP6qiKOvUGo0msAAJ1zIlzeCERCN6sLAFsNVq9S63dnPQVOQjfQgPjwA8Yg21Q44idc8J8LspcapHMYeMqU7SIkIC9q4OIoabzZabfa8Ng80awHM4KIsLAwI34T6eW3-dKuwKezww+LynLjoZVDxPKiu20VWFZ-PF8zSDzAsixLMtK03cJtxwXd92kI8T2bM8kT9Ooo0sN9HEwrpLiJN4nkMSxTEwgjFHUONFG-AEgMLUg5koJI5gATQQ71uWQhByU0KMfDOao3zfZRbgfFQpVqaNtAJTRiMotVqNzCgaAYZhWA4bh+E2RC2PkCVjC4ioX3UPivFMQSiW+HhjlI-xugFD4Xgo6c03wOTSFiRIUgyLIcnUuFNMRbTWmUIlDN0fDsUxPofCMYwZIiFzplmBYllWdYfK9Ll-LKTjuIMoyBKEloEw0KS3zImUzAclMsBECA4FkGccA01jMsQABadQiVarjPB63revaWKxiiJqMtbTQTjwfijH4vxxtMIkXhcF8JzIoi5XaGLHJ-elgVBCEoRGltz2qJxpUcc5elIyk5X7S5Bx0HE4yIypLEG6snSzY1DqQgKehfPBh3ld9cTjawHycQxJq+Ui3wjEy8U24ZtuLP9YCXKBvq0rK4wsr5DhDLwe10fsYyeO930Mkw9HMN65MxlqEEeO9qbleVun8RQiRDULox0GMYwjTFAiCAIgA */
331
+ id: 'aiAgent',
332
+ types: {},
333
+ initial: 'idle',
334
+ context: {
335
+ messages: [],
336
+ currentInput: '',
337
+ error: null,
338
+ isTyping: false,
339
+ multiMessageMode: false,
340
+ currentMultiStep: 0,
341
+ totalMultiSteps: 0,
342
+ multiMessagePlan: [],
343
+ mcpData: undefined,
344
+ regularMessages: [] // Add regular messages from query
345
+ },
346
+ states: {
347
+ idle: {
348
+ on: {
349
+ SEND_MESSAGE: {
350
+ target: 'analyzing',
351
+ guard: 'hasValidMessage',
352
+ actions: 'addUserMessage'
353
+ },
354
+ FORCE_MULTI_MESSAGE: {
355
+ target: 'analyzing',
356
+ guard: 'hasValidMessage',
357
+ actions: 'addUserMessage'
358
+ },
359
+ AUTO_RESPOND_TO_MESSAGE: {
360
+ target: 'processing',
361
+ guard: 'hasValidMessage',
362
+ actions: 'addAutoResponseMessage'
363
+ },
364
+ INPUT_CHANGE: {
365
+ actions: 'updateInput'
366
+ },
367
+ CLEAR_ERROR: {
368
+ actions: 'clearError'
369
+ },
370
+ UPDATE_REGULAR_MESSAGES: {
371
+ actions: 'updateRegularMessages'
372
+ },
373
+ ANALYZE_EXISTING_CONTEXT: {
374
+ target: 'analyzing',
375
+ guard: 'hasExistingContext',
376
+ actions: 'addContextAnalysisMessage'
377
+ },
378
+ CONTINUE_PROCESSING: {
379
+ // Just stay in idle state to trigger the useEffect again
380
+ actions: 'logContinueProcessing'
381
+ }
382
+ }
383
+ },
384
+ analyzing: {
385
+ entry: 'setTyping',
386
+ always: [{
387
+ target: 'planningMultiMessage',
388
+ guard: 'shouldUseMultiMessage'
389
+ }, {
390
+ target: 'fetchingData',
391
+ guard: 'queryNeedsRealTimeData'
392
+ }, {
393
+ target: 'processing'
394
+ }]
395
+ },
396
+ planningMultiMessage: {
397
+ entry: 'setMultiMessageMode',
398
+ invoke: {
399
+ id: 'generateMultiMessagePlan',
400
+ src: 'generateMultiMessagePlan',
401
+ input: ({
402
+ context
403
+ }) => ({
404
+ query: context.messages[context.messages.length - 1]?.content || '',
405
+ regularMessages: context.regularMessages
406
+ }),
407
+ onDone: {
408
+ target: 'multiProcessing',
409
+ actions: 'setMultiMessagePlan'
410
+ },
411
+ onError: {
412
+ target: 'processing' // Fall back to single message
413
+ }
414
+ }
415
+ },
416
+ multiProcessing: {
417
+ invoke: {
418
+ id: 'generateMultiMessage',
419
+ src: 'generateMultiMessage',
420
+ input: ({
421
+ context
422
+ }) => ({
423
+ messages: context.messages,
424
+ plan: context.multiMessagePlan,
425
+ currentStep: context.currentMultiStep,
426
+ mcpData: context.mcpData,
427
+ regularMessages: context.regularMessages
428
+ }),
429
+ onDone: [{
430
+ target: 'waitingBetweenMessages',
431
+ guard: 'hasMoreMultiMessages',
432
+ actions: ['addAIMessage', 'incrementMultiStep']
433
+ }, {
434
+ target: 'idle',
435
+ actions: ['addAIMessage', 'resetMultiMessage']
436
+ }],
437
+ onError: {
438
+ target: 'error',
439
+ actions: 'setError'
440
+ }
441
+ }
442
+ },
443
+ waitingBetweenMessages: {
444
+ entry: 'setTyping',
445
+ after: {
446
+ 1500: 'multiProcessing'
447
+ }
448
+ },
449
+ fetchingData: {
450
+ invoke: {
451
+ id: 'fetchMCPData',
452
+ src: 'fetchMCPData',
453
+ input: ({
454
+ context
455
+ }) => ({
456
+ query: context.messages[context.messages.length - 1]?.content || ''
457
+ }),
458
+ onDone: {
459
+ target: 'processing',
460
+ actions: 'setMCPData'
461
+ },
462
+ onError: {
463
+ target: 'processing'
464
+ }
465
+ }
466
+ },
467
+ processing: {
468
+ entry: () => {
469
+ console.log('🤖 Entering processing state');
470
+ },
471
+ invoke: {
472
+ id: 'generateResponse',
473
+ src: 'generateAIResponse',
474
+ input: ({
475
+ context
476
+ }) => {
477
+ console.log('🤖 generateAIResponse input:', {
478
+ messagesCount: context.messages.length,
479
+ hasMessageToRespondTo: !!context.messageToRespondTo,
480
+ messageToRespondTo: context.messageToRespondTo,
481
+ regularMessagesCount: context.regularMessages?.length || 0
482
+ });
483
+ return {
484
+ messages: context.messages,
485
+ mcpData: context.mcpData,
486
+ regularMessages: context.regularMessages,
487
+ messageToRespondTo: context.messageToRespondTo
488
+ };
489
+ },
490
+ onDone: {
491
+ target: 'idle',
492
+ actions: [assign(({
493
+ context,
494
+ event
495
+ }) => {
496
+ console.log('🤖 🎯 onDone transition triggered with event:', event);
497
+ console.log('🤖 🎯 Event type:', typeof event);
498
+ console.log('🤖 🎯 Event content:', event);
499
+ return context;
500
+ }), 'addAIMessage']
501
+ },
502
+ onError: {
503
+ target: 'error',
504
+ actions: 'setError'
505
+ }
506
+ }
507
+ },
508
+ error: {
509
+ on: {
510
+ RETRY: {
511
+ target: 'processing'
512
+ },
513
+ SEND_MESSAGE: {
514
+ target: 'analyzing',
515
+ guard: 'hasValidMessage',
516
+ actions: 'addUserMessage'
517
+ },
518
+ INPUT_CHANGE: {
519
+ actions: 'updateInput'
520
+ },
521
+ CLEAR_ERROR: {
522
+ target: 'idle',
523
+ actions: 'clearError'
524
+ },
525
+ UPDATE_REGULAR_MESSAGES: {
526
+ actions: 'updateRegularMessages'
527
+ }
528
+ }
529
+ }
530
+ }
531
+ }, {
532
+ guards: {
533
+ hasValidMessage: ({
534
+ event
535
+ }) => {
536
+ console.log('🔍 hasValidMessage guard called with event:', event);
537
+ if (event.type === 'AUTO_RESPOND_TO_MESSAGE') {
538
+ const isValid = event.message?.trim().length > 0;
539
+ console.log('🔍 AUTO_RESPOND_TO_MESSAGE guard result:', isValid, 'message:', event.message);
540
+ return isValid;
541
+ }
542
+ if (event.type === 'SEND_MESSAGE' || event.type === 'FORCE_MULTI_MESSAGE') {
543
+ const isValid = event.message?.trim().length > 0;
544
+ console.log('🔍 SEND_MESSAGE/FORCE_MULTI_MESSAGE guard result:', isValid, 'message:', event.message);
545
+ return isValid;
546
+ }
547
+ console.log('🔍 Unknown event type in hasValidMessage guard:', event.type);
548
+ return false;
549
+ },
550
+ shouldUseMultiMessage: ({
551
+ context,
552
+ event
553
+ }) => {
554
+ if (event.type === 'FORCE_MULTI_MESSAGE') return true;
555
+ const lastMessage = context.messages[context.messages.length - 1];
556
+ if (!lastMessage || lastMessage.sender !== 'user') return false;
557
+ const shouldUse = needsMultiMessageResponse(lastMessage.content);
558
+ console.log('🔄 Should use multi-message:', shouldUse, 'for:', lastMessage.content);
559
+ return shouldUse;
560
+ },
561
+ queryNeedsRealTimeData: ({
562
+ context
563
+ }) => {
564
+ const lastMessage = context.messages[context.messages.length - 1];
565
+ if (!lastMessage || lastMessage.sender !== 'user') return false;
566
+ const needs = needsRealTimeData(lastMessage.content);
567
+ console.log('🔍 Query needs real-time data:', needs, 'for:', lastMessage.content);
568
+ return needs;
569
+ },
570
+ hasMoreMultiMessages: ({
571
+ context
572
+ }) => {
573
+ return context.currentMultiStep < context.totalMultiSteps - 1;
574
+ },
575
+ hasExistingContext: ({
576
+ context
577
+ }) => {
578
+ return context.regularMessages && context.regularMessages.length > 0;
579
+ }
580
+ },
581
+ actions: {
582
+ addUserMessage: assign(({
583
+ context,
584
+ event
585
+ }) => {
586
+ if (event.type !== 'SEND_MESSAGE' && event.type !== 'FORCE_MULTI_MESSAGE') return context;
587
+ const newMessage = {
588
+ id: Date.now().toString(),
589
+ content: event.message,
590
+ sender: 'user',
591
+ timestamp: new Date()
592
+ };
593
+ return {
594
+ ...context,
595
+ messages: [...context.messages, newMessage],
596
+ currentInput: '',
597
+ error: null,
598
+ mcpData: undefined,
599
+ messageToRespondTo: undefined // Clear the message to respond to when adding new user message
600
+ };
601
+ }),
602
+ addAIMessage: assign(({
603
+ context,
604
+ event
605
+ }) => {
606
+ console.log('🤖 addAIMessage called with event:', event);
607
+ // Extract the AI response content from the event
608
+ let aiResponseContent = '';
609
+ // Handle different event formats
610
+ if (event && typeof event === 'object') {
611
+ if ('output' in event) {
612
+ aiResponseContent = event.output;
613
+ } else if ('data' in event) {
614
+ aiResponseContent = event.data;
615
+ } else if (typeof event === 'string') {
616
+ // Direct string response from generateAIResponse actor
617
+ aiResponseContent = event;
618
+ } else {
619
+ console.error('🤖 Could not extract AI response content from event:', event);
620
+ aiResponseContent = 'Sorry, I encountered an error generating the response.';
621
+ }
622
+ } else if (typeof event === 'string') {
623
+ // Direct string response from generateAIResponse actor
624
+ aiResponseContent = event;
625
+ } else {
626
+ console.error('🤖 Could not extract AI response content from event:', event);
627
+ aiResponseContent = 'Sorry, I encountered an error generating the response.';
628
+ }
629
+ console.log('🤖 AI response content:', aiResponseContent.substring(0, 100) + '...');
630
+ const newMessage = {
631
+ id: (Date.now() + 1).toString(),
632
+ content: aiResponseContent,
633
+ sender: 'ai',
634
+ timestamp: new Date()
635
+ };
636
+ console.log('🤖 Adding AI message to context:', newMessage);
637
+ return {
638
+ ...context,
639
+ messages: [...context.messages, newMessage],
640
+ isTyping: false,
641
+ error: null,
642
+ messageToRespondTo: undefined // Clear the message to respond to after processing
643
+ };
644
+ }),
645
+ updateInput: assign(({
646
+ context,
647
+ event
648
+ }) => {
649
+ if (event.type !== 'INPUT_CHANGE') return context;
650
+ return {
651
+ ...context,
652
+ currentInput: event.value
653
+ };
654
+ }),
655
+ updateRegularMessages: assign(({
656
+ context,
657
+ event
658
+ }) => {
659
+ if (event.type !== 'UPDATE_REGULAR_MESSAGES') return context;
660
+ return {
661
+ ...context,
662
+ regularMessages: event.messages || []
663
+ };
664
+ }),
665
+ setMultiMessageMode: assign(({
666
+ context
667
+ }) => ({
668
+ ...context,
669
+ multiMessageMode: true,
670
+ currentMultiStep: 0
671
+ })),
672
+ setMultiMessagePlan: assign(({
673
+ context,
674
+ event
675
+ }) => {
676
+ const plan = event.output;
677
+ console.log('📝 Multi-message plan created:', plan.totalSteps, 'steps');
678
+ return {
679
+ ...context,
680
+ multiMessagePlan: plan.plan,
681
+ totalMultiSteps: plan.totalSteps
682
+ };
683
+ }),
684
+ incrementMultiStep: assign(({
685
+ context
686
+ }) => ({
687
+ ...context,
688
+ currentMultiStep: context.currentMultiStep + 1
689
+ })),
690
+ logContinueProcessing: () => {
691
+ console.log('🤖 Continue processing triggered - machine will stay in idle state');
692
+ },
693
+ resetMultiMessage: assign(({
694
+ context
695
+ }) => ({
696
+ ...context,
697
+ multiMessageMode: false,
698
+ currentMultiStep: 0,
699
+ totalMultiSteps: 0,
700
+ multiMessagePlan: [],
701
+ isTyping: false
702
+ })),
703
+ setTyping: assign(({
704
+ context
705
+ }) => ({
706
+ ...context,
707
+ isTyping: true
708
+ })),
709
+ setMCPData: assign(({
710
+ context,
711
+ event
712
+ }) => {
713
+ console.log('📊 MCP data fetched successfully');
714
+ return {
715
+ ...context,
716
+ mcpData: event.output
717
+ };
718
+ }),
719
+ setError: assign(({
720
+ context,
721
+ event
722
+ }) => {
723
+ console.error('❌ AI processing error:', event);
724
+ let errorMessage = 'An unexpected error occurred';
725
+ const error = event.error;
726
+ if (error instanceof Error) {
727
+ errorMessage = error.message;
728
+ } else if (typeof error === 'string') {
729
+ errorMessage = error;
730
+ }
731
+ if (errorMessage.includes('API key')) {
732
+ errorMessage = 'API key not configured. Please set your Anthropic API key.';
733
+ } else if (errorMessage.includes('rate limit')) {
734
+ errorMessage = 'Rate limit exceeded. Please try again in a moment.';
735
+ } else if (errorMessage.includes('network') || errorMessage.includes('fetch')) {
736
+ errorMessage = 'Network error. Please check your connection and try again.';
737
+ }
738
+ return {
739
+ ...context,
740
+ error: errorMessage,
741
+ isTyping: false
742
+ };
743
+ }),
744
+ clearError: assign(({
745
+ context
746
+ }) => ({
747
+ ...context,
748
+ error: null
749
+ })),
750
+ addContextAnalysisMessage: assign(({
751
+ context
752
+ }) => {
753
+ const newMessage = {
754
+ id: (Date.now() + 2).toString(),
755
+ content: 'Please analyze the existing conversation and provide insights, continue the discussion, or ask relevant follow-up questions based on the context.',
756
+ sender: 'user',
757
+ timestamp: new Date()
758
+ };
759
+ return {
760
+ ...context,
761
+ messages: [...context.messages, newMessage],
762
+ currentInput: '',
763
+ error: null
764
+ };
765
+ }),
766
+ addAutoResponseMessage: assign(({
767
+ context,
768
+ event
769
+ }) => {
770
+ if (event.type !== 'AUTO_RESPOND_TO_MESSAGE') return context;
771
+ console.log('🤖 addAutoResponseMessage called with event:', event);
772
+ console.log('🤖 Current context before update:', {
773
+ messagesCount: context.messages.length,
774
+ hasMessageToRespondTo: !!context.messageToRespondTo,
775
+ messageToRespondTo: context.messageToRespondTo
776
+ });
777
+ // For auto-responses, we store the message content for AI processing
778
+ // but don't add it as a new user message to avoid duplicates
779
+ const updatedContext = {
780
+ ...context,
781
+ currentInput: '',
782
+ error: null,
783
+ mcpData: undefined,
784
+ // Store the message to respond to without adding it to messages array
785
+ messageToRespondTo: event.message
786
+ };
787
+ console.log('🤖 Context updated with messageToRespondTo:', event.message);
788
+ console.log('🤖 Updated context:', {
789
+ messagesCount: updatedContext.messages.length,
790
+ hasMessageToRespondTo: !!updatedContext.messageToRespondTo,
791
+ messageToRespondTo: updatedContext.messageToRespondTo
792
+ });
793
+ return updatedContext;
794
+ })
795
+ },
796
+ actors: {
797
+ generateMultiMessagePlan: fromPromise(async ({
798
+ input
799
+ }) => {
800
+ try {
801
+ console.log('📋 Generating multi-message plan for:', input.query);
802
+ // Check if we have an available AI provider
803
+ if (!API_CONFIG.availableProvider) {
804
+ throw new Error('No AI API key configured. Please set VITE_ANTHROPIC_API_KEY or VITE_OPENAI_API_KEY in your environment.');
805
+ }
806
+ console.log(`🤖 Using ${API_CONFIG.availableProvider} provider for multi-message planning`);
807
+ // Add conversation context if available
808
+ let systemPrompt = `You are a planning assistant. Break down complex queries into 3-5 independent messages that can be sent sequentially.
809
+
810
+ Each message should be a complete, standalone response that builds upon the previous ones.
811
+
812
+ Return ONLY a JSON object in this exact format:
813
+ {
814
+ "plan": ["First message topic/focus", "Second message topic/focus", "Third message topic/focus"],
815
+ "totalSteps": 3
816
+ }
817
+
818
+ Keep each step concise but descriptive. Make sure the breakdown makes sense for step-by-step explanations.`;
819
+ if (input.regularMessages && input.regularMessages.length > 0) {
820
+ const conversationContext = getConversationContext(input.regularMessages);
821
+ systemPrompt = `${systemPrompt}\n\n${conversationContext}`;
822
+ }
823
+ const response = await makeApiCall(API_CONFIG.primaryEndpoint, {
824
+ method: 'POST',
825
+ headers: {
826
+ 'Content-Type': 'application/json'
827
+ },
828
+ body: JSON.stringify({
829
+ model: API_CONFIG.primaryModel,
830
+ max_tokens: 500,
831
+ system: systemPrompt,
832
+ messages: [{
833
+ role: 'user',
834
+ content: `Please create a multi-message plan for this query: "${input.query}"`
835
+ }]
836
+ })
837
+ });
838
+ const data = await response.json();
839
+ const planText = data.content[0]?.text || '';
840
+ // Parse the JSON response
841
+ try {
842
+ const plan = JSON.parse(planText);
843
+ console.log('✅ Multi-message plan created:', plan);
844
+ return plan;
845
+ } catch {
846
+ // Fallback plan if parsing fails
847
+ return {
848
+ plan: ['Introduction and overview', 'Detailed explanation with examples', 'Summary and next steps'],
849
+ totalSteps: 3
850
+ };
851
+ }
852
+ } catch (error) {
853
+ console.error('🚨 Multi-message planning error:', error);
854
+ throw error;
855
+ }
856
+ }),
857
+ generateMultiMessage: fromPromise(async ({
858
+ input
859
+ }) => {
860
+ console.log(`🔄 Generating multi-message ${input.currentStep + 1}/${input.plan?.length || 1}`);
861
+ try {
862
+ // Check if we have an available AI provider
863
+ if (!API_CONFIG.availableProvider) {
864
+ throw new Error('No AI API key configured. Please set VITE_ANTHROPIC_API_KEY or VITE_OPENAI_API_KEY in your environment.');
865
+ }
866
+ console.log(`🤖 Using ${API_CONFIG.availableProvider} provider for multi-message generation`);
867
+ const userMessages = input.messages.filter(msg => msg.sender === 'user');
868
+ const latestUserMessage = userMessages[userMessages.length - 1];
869
+ if (!latestUserMessage) {
870
+ throw new Error('No user message found');
871
+ }
872
+ const currentStepTopic = input.plan?.[input.currentStep] || 'General response';
873
+ const stepNumber = input.currentStep + 1;
874
+ const totalSteps = input.plan?.length || 1;
875
+ let prompt = `User's original question: "${latestUserMessage.content}"
876
+
877
+ This is message ${stepNumber} of ${totalSteps} in a multi-message response.
878
+ Focus specifically on: ${currentStepTopic}
879
+
880
+ Guidelines:
881
+ - Start with a clear indicator like "**Step ${stepNumber}/${totalSteps}: ${currentStepTopic}**"
882
+ - Provide a complete, standalone response for this specific aspect
883
+ - Keep it focused and detailed but not overwhelming
884
+ - Use examples, code snippets, or bullet points where helpful
885
+ - End with a brief transition to what's coming next (unless it's the final message)`;
886
+ // Add conversation context if available
887
+ if (input.regularMessages && input.regularMessages.length > 0) {
888
+ const conversationContext = getConversationContext(input.regularMessages);
889
+ prompt = `${conversationContext}${prompt}`;
890
+ }
891
+ // Add MCP context if available
892
+ if (input.mcpData) {
893
+ const mcpContext = formatMCPDataForAgent(input.mcpData);
894
+ if (mcpContext) {
895
+ prompt = `${mcpContext}\n\n${prompt}`;
896
+ }
897
+ }
898
+ const response = await makeApiCall(API_CONFIG.primaryEndpoint, {
899
+ method: 'POST',
900
+ headers: {
901
+ 'Content-Type': 'application/json'
902
+ },
903
+ body: JSON.stringify({
904
+ model: API_CONFIG.primaryModel,
905
+ max_tokens: 800,
906
+ system: getSystemPrompt(API_CONFIG.availableProvider || 'anthropic', false),
907
+ messages: [...input.messages.slice(-5).map(msg => ({
908
+ role: msg.sender === 'user' ? 'user' : 'assistant',
909
+ content: msg.content
910
+ })), {
911
+ role: 'user',
912
+ content: prompt
913
+ }]
914
+ })
915
+ });
916
+ const data = await response.json();
917
+ return data.content[0]?.text || "Sorry, I couldn't generate a response for this step.";
918
+ } catch (error) {
919
+ console.error('🚨 Multi-message generation error:', error);
920
+ throw error;
921
+ }
922
+ }),
923
+ fetchMCPData: fromPromise(async ({
924
+ input
925
+ }) => {
926
+ try {
927
+ console.log('🌐 Fetching MCP data for query:', input.query);
928
+ const response = await performDirectMCPSearch(input.query, true, true);
929
+ console.log('✅ MCP data fetched:', response.summary);
930
+ return response;
931
+ } catch (error) {
932
+ console.error('🚨 MCP fetch error:', error);
933
+ throw error;
934
+ }
935
+ }),
936
+ generateAIResponse: fromPromise(async ({
937
+ input
938
+ }) => {
939
+ console.log('🤖 Generating response using server-side AI proxy');
940
+ console.log('🤖 Input received:', {
941
+ messagesCount: input.messages.length,
942
+ hasMCPData: !!input.mcpData,
943
+ regularMessagesCount: input.regularMessages?.length || 0,
944
+ messageToRespondTo: input.messageToRespondTo
945
+ });
946
+ try {
947
+ // Check if we have an available AI provider
948
+ if (!API_CONFIG.availableProvider) {
949
+ throw new Error('No AI API key configured. Please set VITE_ANTHROPIC_API_KEY or VITE_OPENAI_API_KEY in your environment.');
950
+ }
951
+ console.log(`🤖 Using ${API_CONFIG.availableProvider} provider for AI response generation`);
952
+ // Get the latest user message or the message to respond to
953
+ let prompt;
954
+ let userMessages = input.messages.filter(msg => msg.sender === 'user');
955
+ if (input.messageToRespondTo) {
956
+ // Use the message to respond to for auto-responses
957
+ prompt = input.messageToRespondTo;
958
+ console.log('🤖 Auto-responding to message:', prompt.substring(0, 50) + '...');
959
+ } else if (userMessages.length > 0) {
960
+ const latestUserMessage = userMessages[userMessages.length - 1];
961
+ prompt = latestUserMessage.content;
962
+ } else {
963
+ // If no user messages, this might be an auto-response
964
+ prompt = 'Please provide a helpful response to the conversation context.';
965
+ }
966
+ // Add conversation context if available
967
+ if (input.regularMessages && input.regularMessages.length > 0) {
968
+ const conversationContext = getConversationContext(input.regularMessages);
969
+ prompt = `${conversationContext}User question: ${prompt}`;
970
+ console.log('🚀 Enhanced prompt with conversation context - Recent messages:', input.regularMessages.length);
971
+ }
972
+ // Add MCP context if available
973
+ if (input.mcpData) {
974
+ const mcpContext = formatMCPDataForAgent(input.mcpData);
975
+ if (mcpContext) {
976
+ prompt = `${mcpContext}\n\nUser question: ${prompt}`;
977
+ console.log('🚀 Enhanced prompt with MCP data - Web results:', input.mcpData.searchResults?.length || 0, 'News articles:', input.mcpData.newsArticles?.length || 0);
978
+ }
979
+ }
980
+ // Use Vite proxy for AI API calls (avoids CORS issues)
981
+ const controller = new AbortController();
982
+ const timeoutId = setTimeout(() => controller.abort(), 15000); // Increased to 15s timeout for better reliability
983
+ try {
984
+ const response = await makeApiCall(API_CONFIG.primaryEndpoint, {
985
+ method: 'POST',
986
+ headers: {
987
+ 'Content-Type': 'application/json'
988
+ },
989
+ body: JSON.stringify({
990
+ model: API_CONFIG.primaryModel,
991
+ max_tokens: 300,
992
+ // Further reduced for faster responses
993
+ system: getSystemPrompt(API_CONFIG.availableProvider || 'anthropic', true),
994
+ messages: [
995
+ // Only include the last 2 messages for faster processing
996
+ ...input.messages.slice(-2).map(msg => ({
997
+ role: msg.sender === 'user' ? 'user' : 'assistant',
998
+ content: msg.content
999
+ })), {
1000
+ role: 'user',
1001
+ content: prompt
1002
+ }]
1003
+ }),
1004
+ signal: controller.signal
1005
+ });
1006
+ clearTimeout(timeoutId);
1007
+ const data = await response.json();
1008
+ console.log('🤖 AI API response received:', data);
1009
+ const aiResponseText = data.content[0]?.text || data.choices?.[0]?.message?.content || "Sorry, I couldn't generate a response.";
1010
+ console.log('🤖 Extracted AI response text:', aiResponseText.substring(0, 100) + '...');
1011
+ console.log('🤖 ✅ generateAIResponse actor completing successfully with text length:', aiResponseText.length);
1012
+ return aiResponseText;
1013
+ } catch (error) {
1014
+ clearTimeout(timeoutId);
1015
+ if (error.name === 'AbortError') {
1016
+ throw new Error('AI response generation timed out. Please try again.');
1017
+ }
1018
+ throw error;
1019
+ }
1020
+ } catch (error) {
1021
+ console.error('🚨 AI generation error:', error);
1022
+ if (error instanceof Error) {
1023
+ if (error.message.includes('API key')) {
1024
+ throw new Error('AI API key is not configured. Please set your API keys in the environment variables.');
1025
+ }
1026
+ if (error.message.includes('rate limit')) {
1027
+ throw new Error('Rate limit exceeded. Please try again in a moment.');
1028
+ }
1029
+ if (error.message.includes('network') || error.message.includes('fetch')) {
1030
+ throw new Error('Network error. Please check your connection and ensure your Vite dev server is running on localhost:3011.');
1031
+ }
1032
+ throw error; // Re-throw the Error instance
1033
+ }
1034
+ // If error is not an Error instance, create a proper Error with string message
1035
+ const errorMessage = typeof error === 'string' ? error : error && typeof error === 'object' && 'message' in error ? String(error.message) : 'An unexpected error occurred while generating the response';
1036
+ throw new Error(errorMessage);
1037
+ }
1038
+ })
1039
+ }
1040
+ });export{aiAgentMachine};//# sourceMappingURL=aiAgentMachine.js.map