@messenger-box/tailwind-ui-inbox 10.0.3-alpha.72 → 10.0.3-alpha.74
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.
- package/CHANGELOG.md +8 -0
- package/lib/components/AIAgent/AIAgent.d.ts +7 -0
- package/lib/components/AIAgent/AIAgent.d.ts.map +1 -1
- package/lib/components/AIAgent/AIAgent.js +362 -615
- package/lib/components/AIAgent/AIAgent.js.map +1 -1
- package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -1
- package/lib/components/InboxMessage/InputComponent.js +143 -140
- package/lib/components/InboxMessage/InputComponent.js.map +1 -1
- package/lib/components/InboxMessage/RightSidebarAi.d.ts +23 -0
- package/lib/components/InboxMessage/RightSidebarAi.d.ts.map +1 -0
- package/lib/components/InboxMessage/RightSidebarAi.js +9 -0
- package/lib/components/InboxMessage/RightSidebarAi.js.map +1 -0
- package/lib/components/InboxMessage/index.d.ts +1 -0
- package/lib/components/InboxMessage/index.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.d.ts +11 -0
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.d.ts.map +1 -0
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.js +194 -0
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.js.map +1 -0
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +5 -1
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +308 -857
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -1
- package/lib/components/ModelConfigPanel.d.ts +12 -0
- package/lib/components/ModelConfigPanel.d.ts.map +1 -0
- package/lib/components/ModelConfigPanel.js +304 -0
- package/lib/components/ModelConfigPanel.js.map +1 -0
- package/lib/components/filler-components/RightSiderBar.d.ts +24 -0
- package/lib/components/filler-components/RightSiderBar.d.ts.map +1 -0
- package/lib/components/filler-components/RightSiderBar.js +335 -0
- package/lib/components/filler-components/RightSiderBar.js.map +1 -0
- package/lib/components/index.d.ts +4 -2
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/live-code-editor/hybrid-live-editor.d.ts +20 -0
- package/lib/components/live-code-editor/hybrid-live-editor.d.ts.map +1 -0
- package/lib/components/live-code-editor/hybrid-live-editor.js +68 -0
- package/lib/components/live-code-editor/hybrid-live-editor.js.map +1 -0
- package/lib/components/live-code-editor/index.d.ts +4 -0
- package/lib/components/live-code-editor/index.d.ts.map +1 -0
- package/lib/components/live-code-editor/live-code-editor.d.ts +14 -0
- package/lib/components/live-code-editor/live-code-editor.d.ts.map +1 -0
- package/lib/components/live-code-editor/live-code-editor.js +207 -0
- package/lib/components/live-code-editor/live-code-editor.js.map +1 -0
- package/lib/components/slot-fill/chat-message-filler.js +1 -1
- package/lib/components/slot-fill/chat-message-filler.js.map +1 -1
- package/lib/components/slot-fill/index.d.ts +1 -0
- package/lib/components/slot-fill/index.d.ts.map +1 -1
- package/lib/components/slot-fill/right-sidebar-filler.d.ts +4 -0
- package/lib/components/slot-fill/right-sidebar-filler.d.ts.map +1 -0
- package/lib/components/slot-fill/right-sidebar-filler.js +13 -0
- package/lib/components/slot-fill/right-sidebar-filler.js.map +1 -0
- package/lib/components/ui/button.d.ts +9 -0
- package/lib/components/ui/button.d.ts.map +1 -0
- package/lib/compute.js +1 -2
- package/lib/container/AiInbox.d.ts.map +1 -1
- package/lib/container/AiLandingInput.d.ts.map +1 -1
- package/lib/container/AiLandingInput.js +46 -119
- package/lib/container/AiLandingInput.js.map +1 -1
- package/lib/container/Inbox.js +1 -1
- package/lib/container/Inbox.js.map +1 -1
- package/lib/container/InboxAiMessagesLoader.d.ts +0 -21
- package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -1
- package/lib/container/InboxAiMessagesLoader.js +18 -35
- package/lib/container/InboxAiMessagesLoader.js.map +1 -1
- package/lib/container/ServiceInbox.js +1 -1
- package/lib/container/ServiceInbox.js.map +1 -1
- package/lib/container/ThreadMessages.js +1 -1
- package/lib/container/ThreadMessages.js.map +1 -1
- package/lib/container/ThreadMessagesInbox.js +1 -1
- package/lib/container/ThreadMessagesInbox.js.map +1 -1
- package/lib/container/Threads.js +1 -1
- package/lib/container/Threads.js.map +1 -1
- package/lib/container/index.d.ts +5 -4
- package/lib/container/index.d.ts.map +1 -1
- package/lib/enums/messenger-slot-fill-name-enum.d.ts +2 -1
- package/lib/enums/messenger-slot-fill-name-enum.d.ts.map +1 -1
- package/lib/enums/messenger-slot-fill-name-enum.js +1 -0
- package/lib/enums/messenger-slot-fill-name-enum.js.map +1 -1
- package/lib/hooks/index.d.ts +3 -0
- package/lib/hooks/index.d.ts.map +1 -0
- package/lib/hooks/use-file-sync.d.ts +16 -0
- package/lib/hooks/use-file-sync.d.ts.map +1 -0
- package/lib/hooks/use-file-sync.js +63 -0
- package/lib/hooks/use-file-sync.js.map +1 -0
- package/lib/hooks/usePersistentModelConfig.d.ts +15 -0
- package/lib/hooks/usePersistentModelConfig.d.ts.map +1 -0
- package/lib/hooks/usePersistentModelConfig.js +46 -0
- package/lib/hooks/usePersistentModelConfig.js.map +1 -0
- package/lib/index.d.ts +5 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/machines/aiAgentMachine.d.ts.map +1 -1
- package/lib/machines/aiAgentMachine.js +64 -21
- package/lib/machines/aiAgentMachine.js.map +1 -1
- package/lib/machines/aiAgentMachine.simple.d.ts +3 -0
- package/lib/machines/aiAgentMachine.simple.d.ts.map +1 -0
- package/lib/machines/aiAgentMachine.simple.js +108 -0
- package/lib/machines/aiAgentMachine.simple.js.map +1 -0
- package/lib/machines/index.d.ts +3 -0
- package/lib/machines/index.d.ts.map +1 -0
- package/lib/module.d.ts +2 -1
- package/lib/module.d.ts.map +1 -1
- package/lib/module.js +11 -3
- package/lib/module.js.map +1 -1
- package/lib/routes.json +1 -2
- package/lib/templates/InboxWithAi.d.ts.map +1 -1
- package/lib/templates/InboxWithAi.js +129 -70
- package/lib/templates/InboxWithAi.js.map +1 -1
- package/lib/templates/InboxWithAi.tsx +151 -90
- package/lib/templates/index.d.ts +2 -0
- package/lib/templates/index.d.ts.map +1 -0
- package/lib/templates/index.ts +1 -0
- package/lib/utils/utils.d.ts +2 -0
- package/lib/utils/utils.d.ts.map +1 -0
- package/lib/utils/utils.js +3 -0
- package/lib/utils/utils.js.map +1 -0
- package/package.json +8 -5
- package/src/components/AIAgent/AIAgent.tsx +469 -731
- package/src/components/AIAgent/AIAgent.tsx.bk +1365 -0
- package/src/components/InboxMessage/InputComponent.tsx +2 -1
- package/src/components/InboxMessage/RightSidebarAi.tsx +37 -0
- package/src/components/InboxMessage/index.ts +1 -0
- package/src/components/InboxMessage/message-widgets/ErrorFixCard.tsx +240 -0
- package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +337 -1116
- package/src/components/ModelConfigPanel.tsx +334 -0
- package/src/components/filler-components/RightSiderBar.tsx +408 -0
- package/src/components/index.ts +4 -1
- package/src/components/live-code-editor/hybrid-live-editor.tsx +105 -0
- package/src/components/live-code-editor/index.ts +3 -0
- package/src/components/live-code-editor/live-code-editor.tsx +257 -0
- package/src/components/slot-fill/index.ts +1 -0
- package/src/components/slot-fill/right-sidebar-filler.tsx +39 -0
- package/src/components/ui/button.tsx +32 -0
- package/src/container/AiInbox.tsx +26 -3
- package/src/container/AiLandingInput.tsx +48 -22
- package/src/container/InboxAiMessagesLoader.tsx +17 -41
- package/src/container/index.ts +14 -6
- package/src/enums/messenger-slot-fill-name-enum.ts +1 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use-file-sync.ts +91 -0
- package/src/hooks/usePersistentModelConfig.ts +63 -0
- package/src/index.ts +19 -1
- package/src/machines/aiAgentMachine.simple.ts +89 -0
- package/src/machines/aiAgentMachine.ts +67 -19
- package/src/machines/aiAgentMachine.ts.bk +1296 -0
- package/src/machines/index.ts +2 -0
- package/src/module.tsx +10 -1
- package/src/templates/InboxWithAi.tsx +151 -90
- package/src/templates/index.ts +1 -0
- package/src/utils/utils.ts +3 -0
- package/lib/components/InboxMessage/MessageInputComponent.js +0 -173
- package/lib/components/InboxMessage/MessageInputComponent.js.map +0 -1
- package/lib/components/InboxMessage/MessagesBuilderUi.js +0 -162
- package/lib/components/InboxMessage/MessagesBuilderUi.js.map +0 -1
- package/lib/container/AiInbox.js +0 -1520
- package/lib/container/AiInbox.js.map +0 -1
- package/lib/container/AiInboxWithLoader.js +0 -300
- package/lib/container/AiInboxWithLoader.js.map +0 -1
- package/lib/container/InboxTemplate1.js +0 -1375
- package/lib/container/InboxTemplate1.js.map +0 -1
- package/lib/container/InboxTemplate2.js +0 -1426
- package/lib/container/InboxTemplate2.js.map +0 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { useUpdateSandboxFileMutation, useFileUpdatedSubscription } from 'common/graphql';
|
|
3
|
+
|
|
4
|
+
export interface FileSyncHookProps {
|
|
5
|
+
projectId: string;
|
|
6
|
+
messageId?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface FileSyncResult {
|
|
10
|
+
updateFile: (filePath: string, content: string) => Promise<void>;
|
|
11
|
+
isUpdating: boolean;
|
|
12
|
+
error: string | null;
|
|
13
|
+
lastUpdate: {
|
|
14
|
+
filePath: string;
|
|
15
|
+
operation: string;
|
|
16
|
+
timestamp: string;
|
|
17
|
+
} | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const useFileSync = ({ projectId, messageId }: FileSyncHookProps): FileSyncResult => {
|
|
21
|
+
const [isUpdating, setIsUpdating] = useState(false);
|
|
22
|
+
const [error, setError] = useState<string | null>(null);
|
|
23
|
+
const [lastUpdate, setLastUpdate] = useState<{
|
|
24
|
+
filePath: string;
|
|
25
|
+
operation: string;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
} | null>(null);
|
|
28
|
+
|
|
29
|
+
// GraphQL mutations
|
|
30
|
+
const [updateSandboxFileMutation] = useUpdateSandboxFileMutation();
|
|
31
|
+
|
|
32
|
+
// Real-time file updates subscription
|
|
33
|
+
const { data: fileUpdateData } = useFileUpdatedSubscription({
|
|
34
|
+
variables: { projectId },
|
|
35
|
+
skip: !projectId,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Handle real-time file updates
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (fileUpdateData?.fileUpdated) {
|
|
41
|
+
const update = fileUpdateData.fileUpdated;
|
|
42
|
+
setLastUpdate({
|
|
43
|
+
filePath: update.filePath,
|
|
44
|
+
operation: update.operation,
|
|
45
|
+
timestamp: update.timestamp,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}, [fileUpdateData]);
|
|
49
|
+
|
|
50
|
+
const updateFile = useCallback(
|
|
51
|
+
async (filePath: string, content: string) => {
|
|
52
|
+
if (!messageId) {
|
|
53
|
+
throw new Error('Fragment ID is required for file operations');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log('useFileSync.updateFile - Using fragmentId:', messageId);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
setIsUpdating(true);
|
|
60
|
+
setError(null);
|
|
61
|
+
|
|
62
|
+
const response = await updateSandboxFileMutation({
|
|
63
|
+
variables: {
|
|
64
|
+
projectId,
|
|
65
|
+
messageId,
|
|
66
|
+
filePath,
|
|
67
|
+
content,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (!response.data?.updateSandboxFile.success) {
|
|
72
|
+
throw new Error(response.data?.updateSandboxFile.message || 'Failed to update file');
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
|
|
76
|
+
setError(errorMessage);
|
|
77
|
+
throw err;
|
|
78
|
+
} finally {
|
|
79
|
+
setIsUpdating(false);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
[updateSandboxFileMutation, projectId, messageId],
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
updateFile,
|
|
87
|
+
isUpdating,
|
|
88
|
+
error,
|
|
89
|
+
lastUpdate,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export type ProviderId = 'openai' | 'anthropic' | 'gemini';
|
|
4
|
+
|
|
5
|
+
export interface ModelConfig {
|
|
6
|
+
provider: ProviderId;
|
|
7
|
+
model: string;
|
|
8
|
+
apiKey: string;
|
|
9
|
+
template: 'react-vite' | 'nextjs' | 'vue' | 'vite-react';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const STORAGE_KEY = 'mbx:model-config';
|
|
13
|
+
|
|
14
|
+
function loadFromStorage(): ModelConfig | null {
|
|
15
|
+
try {
|
|
16
|
+
const raw = typeof window !== 'undefined' ? window.localStorage.getItem(STORAGE_KEY) : null;
|
|
17
|
+
if (!raw) return null;
|
|
18
|
+
const parsed = JSON.parse(raw);
|
|
19
|
+
return parsed as ModelConfig;
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function saveToStorage(config: ModelConfig) {
|
|
26
|
+
try {
|
|
27
|
+
if (typeof window !== 'undefined') {
|
|
28
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
|
|
29
|
+
}
|
|
30
|
+
} catch {
|
|
31
|
+
// ignore
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const DEFAULTS: ModelConfig = {
|
|
36
|
+
provider: 'anthropic',
|
|
37
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
38
|
+
apiKey: '',
|
|
39
|
+
template: 'react-vite',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function usePersistentModelConfig() {
|
|
43
|
+
const [modelConfig, setModelConfig] = useState<ModelConfig>(() => loadFromStorage() || DEFAULTS);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
saveToStorage(modelConfig);
|
|
47
|
+
}, [modelConfig]);
|
|
48
|
+
|
|
49
|
+
const updateModelConfig = useCallback((newConfig: ModelConfig) => {
|
|
50
|
+
setModelConfig(newConfig);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
const hasApiKey = useMemo(() => Boolean(modelConfig.apiKey && modelConfig.apiKey.trim().length > 0), [modelConfig]);
|
|
54
|
+
|
|
55
|
+
const getValidatedConfig = useCallback(() => {
|
|
56
|
+
if (!hasApiKey) return null;
|
|
57
|
+
return modelConfig;
|
|
58
|
+
}, [hasApiKey, modelConfig]);
|
|
59
|
+
|
|
60
|
+
return { modelConfig, updateModelConfig, getValidatedConfig, hasApiKey };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default usePersistentModelConfig;
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
export { default } from './module';
|
|
2
2
|
export { ChatMessageFill } from './module';
|
|
3
|
-
export {
|
|
3
|
+
export {
|
|
4
|
+
Inbox,
|
|
5
|
+
Threads,
|
|
6
|
+
ThreadMessages,
|
|
7
|
+
ServiceInbox,
|
|
8
|
+
InboxWithLoader,
|
|
9
|
+
InboxWithAiLoader,
|
|
10
|
+
InboxAiMessagesLoader,
|
|
11
|
+
InboxContainer,
|
|
12
|
+
AiLandingInput,
|
|
13
|
+
} from './container';
|
|
4
14
|
export {
|
|
5
15
|
MessageSliceRenderer,
|
|
6
16
|
Messages,
|
|
@@ -14,6 +24,14 @@ export {
|
|
|
14
24
|
ConversationItem,
|
|
15
25
|
UserModalContent,
|
|
16
26
|
ServiceInboxItem,
|
|
27
|
+
AIAgent,
|
|
28
|
+
ModelConfigPanel,
|
|
29
|
+
RightSidebarAi,
|
|
30
|
+
InputComponent,
|
|
31
|
+
RightSidebarFillDefault,
|
|
17
32
|
} from './components';
|
|
33
|
+
export { InboxWithAi } from './templates';
|
|
18
34
|
export type { CardMessageAttachmentsInterface, AlertMessageAttachmentsInterface } from './interfaces';
|
|
19
35
|
export * from './enums';
|
|
36
|
+
export * from './machines';
|
|
37
|
+
export * from './hooks';
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { createMachine, assign } from 'xstate';
|
|
2
|
+
import { AIAgentContext, AIAgentEvent, Message } from './types';
|
|
3
|
+
|
|
4
|
+
export const aiAgentMachine = createMachine(
|
|
5
|
+
{
|
|
6
|
+
id: 'aiAgentSimple',
|
|
7
|
+
types: {} as {
|
|
8
|
+
context: AIAgentContext;
|
|
9
|
+
events: AIAgentEvent;
|
|
10
|
+
},
|
|
11
|
+
initial: 'idle',
|
|
12
|
+
context: {
|
|
13
|
+
messages: [],
|
|
14
|
+
currentInput: '',
|
|
15
|
+
error: null,
|
|
16
|
+
isTyping: false,
|
|
17
|
+
regularMessages: [],
|
|
18
|
+
},
|
|
19
|
+
states: {
|
|
20
|
+
idle: {
|
|
21
|
+
on: {
|
|
22
|
+
SEND_MESSAGE: {
|
|
23
|
+
target: 'idle',
|
|
24
|
+
guard: 'hasValidMessage',
|
|
25
|
+
actions: 'addUserMessage',
|
|
26
|
+
},
|
|
27
|
+
INPUT_CHANGE: {
|
|
28
|
+
actions: 'updateInput',
|
|
29
|
+
},
|
|
30
|
+
CLEAR_ERROR: {
|
|
31
|
+
actions: 'clearError',
|
|
32
|
+
},
|
|
33
|
+
UPDATE_REGULAR_MESSAGES: {
|
|
34
|
+
actions: 'updateRegularMessages',
|
|
35
|
+
},
|
|
36
|
+
// Tolerate legacy events as no-ops
|
|
37
|
+
AUTO_RESPOND_TO_MESSAGE: {},
|
|
38
|
+
RETRY: {},
|
|
39
|
+
CONTINUE_PROCESSING: {},
|
|
40
|
+
UPDATE: {
|
|
41
|
+
actions: 'mergeUpdate',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
guards: {
|
|
49
|
+
hasValidMessage: ({ event }) => {
|
|
50
|
+
if (event.type === 'SEND_MESSAGE') {
|
|
51
|
+
return Boolean(event.message && event.message.trim().length > 0);
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
actions: {
|
|
57
|
+
addUserMessage: assign(({ context, event }) => {
|
|
58
|
+
if (event.type !== 'SEND_MESSAGE') return context;
|
|
59
|
+
const newMessage: Message = {
|
|
60
|
+
id: Date.now().toString(),
|
|
61
|
+
content: event.message,
|
|
62
|
+
sender: 'user',
|
|
63
|
+
timestamp: new Date(),
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
...context,
|
|
67
|
+
messages: [...context.messages, newMessage],
|
|
68
|
+
currentInput: '',
|
|
69
|
+
error: null,
|
|
70
|
+
};
|
|
71
|
+
}),
|
|
72
|
+
updateInput: assign(({ context, event }) => {
|
|
73
|
+
if (event.type !== 'INPUT_CHANGE') return context;
|
|
74
|
+
return { ...context, currentInput: event.value };
|
|
75
|
+
}),
|
|
76
|
+
updateRegularMessages: assign(({ context, event }) => {
|
|
77
|
+
if (event.type !== 'UPDATE_REGULAR_MESSAGES') return context;
|
|
78
|
+
return { ...context, regularMessages: event.messages || [] };
|
|
79
|
+
}),
|
|
80
|
+
clearError: assign(({ context }) => ({ ...context, error: null })),
|
|
81
|
+
mergeUpdate: assign(({ context, event }) => {
|
|
82
|
+
// Supports events like { type: 'UPDATE', value: { messages: [] } }
|
|
83
|
+
if (event.type !== 'UPDATE') return context as any;
|
|
84
|
+
const value = (event as any).value || {};
|
|
85
|
+
return { ...context, ...value } as any;
|
|
86
|
+
}),
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
);
|
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
import { createMachine, assign, fromPromise } from 'xstate';
|
|
2
2
|
import { AIAgentContext, AIAgentEvent, Message, MCPData } from './types';
|
|
3
3
|
import { config } from '../config';
|
|
4
|
-
const { CLIENT_URL,
|
|
5
|
-
config;
|
|
4
|
+
const { CLIENT_URL, NEWS_API_KEY } = config;
|
|
6
5
|
const env = {
|
|
7
|
-
ANTHROPIC_API_KEY: VITE_ANTHROPIC_API_KEY || ANTHROPIC_API_KEY,
|
|
8
|
-
OPENAI_API_KEY: VITE_OPENAI_API_KEY || OPENAI_API_KEY,
|
|
9
6
|
NEWS_API_KEY: NEWS_API_KEY,
|
|
10
7
|
};
|
|
11
8
|
|
|
12
9
|
// API configuration - using environment variables from dev.env
|
|
10
|
+
// Read persisted model configuration saved by usePersistentModelConfig
|
|
11
|
+
function getUserModelConfig(): { provider?: 'openai' | 'anthropic' | 'gemini'; model?: string; apiKey?: string } {
|
|
12
|
+
try {
|
|
13
|
+
if (typeof window === 'undefined') return {};
|
|
14
|
+
const raw = window.localStorage.getItem('mbx:model-config');
|
|
15
|
+
if (!raw) return {};
|
|
16
|
+
const parsed = JSON.parse(raw);
|
|
17
|
+
return {
|
|
18
|
+
provider: parsed?.provider,
|
|
19
|
+
model: parsed?.model,
|
|
20
|
+
apiKey: parsed?.apiKey,
|
|
21
|
+
};
|
|
22
|
+
} catch {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const USER_MODEL_CONFIG = getUserModelConfig();
|
|
28
|
+
|
|
13
29
|
const API_CONFIG = {
|
|
14
|
-
//
|
|
15
|
-
ANTHROPIC_API_KEY: env?.ANTHROPIC_API_KEY,
|
|
16
|
-
OPENAI_API_KEY: env?.OPENAI_API_KEY,
|
|
30
|
+
// Only non-AI keys from env (public APIs allowed)
|
|
17
31
|
NEWS_API_KEY: env?.NEWS_API_KEY,
|
|
18
32
|
|
|
19
33
|
// Configurable proxy endpoints
|
|
@@ -30,39 +44,56 @@ const API_CONFIG = {
|
|
|
30
44
|
DEFAULT_MODEL: 'claude-3-5-haiku-20241022',
|
|
31
45
|
OPENAI_MODEL: 'gpt-4o-mini',
|
|
32
46
|
|
|
33
|
-
//
|
|
47
|
+
// User-provided model configuration (from localStorage)
|
|
48
|
+
get userProvider() {
|
|
49
|
+
return USER_MODEL_CONFIG?.provider;
|
|
50
|
+
},
|
|
51
|
+
get userModel() {
|
|
52
|
+
return USER_MODEL_CONFIG?.model;
|
|
53
|
+
},
|
|
54
|
+
get userApiKey() {
|
|
55
|
+
return USER_MODEL_CONFIG?.apiKey;
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Check which AI provider is available (ONLY from user config)
|
|
34
59
|
get availableProvider() {
|
|
35
|
-
if (this.
|
|
36
|
-
|
|
60
|
+
if (this.userApiKey && this.userProvider) {
|
|
61
|
+
if (this.userProvider === 'anthropic') return 'anthropic';
|
|
62
|
+
if (this.userProvider === 'openai') return 'openai';
|
|
63
|
+
}
|
|
37
64
|
return null;
|
|
38
65
|
},
|
|
39
66
|
|
|
40
67
|
// Get the appropriate endpoint based on available provider
|
|
41
68
|
get primaryEndpoint() {
|
|
42
|
-
|
|
69
|
+
if (this.availableProvider === 'anthropic') return this.ANTHROPIC_ENDPOINT;
|
|
70
|
+
if (this.availableProvider === 'openai') return this.OPENAI_ENDPOINT;
|
|
71
|
+
return '';
|
|
43
72
|
},
|
|
44
73
|
|
|
45
74
|
// Get the appropriate model based on available provider
|
|
46
75
|
get primaryModel() {
|
|
47
|
-
|
|
76
|
+
if (this.userModel) return this.userModel;
|
|
77
|
+
if (this.availableProvider === 'anthropic') return this.DEFAULT_MODEL;
|
|
78
|
+
if (this.availableProvider === 'openai') return this.OPENAI_MODEL;
|
|
79
|
+
return this.DEFAULT_MODEL;
|
|
48
80
|
},
|
|
49
81
|
};
|
|
50
82
|
|
|
51
83
|
// Log configuration on startup
|
|
52
84
|
console.log('🤖 AI Agent Machine Configuration:');
|
|
53
|
-
console.log(` Available Provider: ${API_CONFIG.availableProvider || 'None'}`);
|
|
85
|
+
console.log(` Available Provider (user): ${API_CONFIG.availableProvider || 'None'}`);
|
|
54
86
|
console.log(` Primary Endpoint: ${API_CONFIG.primaryEndpoint}`);
|
|
55
87
|
console.log(` Primary Model: ${API_CONFIG.primaryModel}`);
|
|
56
88
|
console.log(` Using Proxy for AI APIs: ✅ (avoids CORS issues)`);
|
|
57
89
|
console.log(` Using Direct APIs for MCP Search: ✅ (public APIs)`);
|
|
58
|
-
console.log(`
|
|
59
|
-
console.log(` OpenAI API Key: ${API_CONFIG.OPENAI_API_KEY ? '✅ Configured' : '❌ Not configured'}`);
|
|
90
|
+
console.log(` User API Key: ${API_CONFIG.userApiKey ? '✅ Configured' : '❌ Not configured'}`);
|
|
60
91
|
console.log(` News API Key: ${API_CONFIG.NEWS_API_KEY ? '✅ Configured' : '❌ Not configured'}`);
|
|
61
92
|
|
|
62
93
|
// Test API configuration
|
|
63
94
|
if (!API_CONFIG.availableProvider) {
|
|
64
95
|
console.error('🚨 CRITICAL: No AI API provider configured!');
|
|
65
|
-
console.error('🚨 Please
|
|
96
|
+
console.error('🚨 Please add your API key in Model Settings.');
|
|
66
97
|
} else {
|
|
67
98
|
console.log(`✅ AI API provider configured: ${API_CONFIG.availableProvider}`);
|
|
68
99
|
}
|
|
@@ -80,7 +111,7 @@ console.log(`🌐 Proxy Configuration: ${getProxyBaseUrl() || 'Relative paths (p
|
|
|
80
111
|
async function makeApiCall(endpoint: string, options: RequestInit) {
|
|
81
112
|
try {
|
|
82
113
|
const baseUrl = getProxyBaseUrl();
|
|
83
|
-
const url = `${baseUrl}${endpoint}
|
|
114
|
+
const url = endpoint ? `${baseUrl}${endpoint}` : '';
|
|
84
115
|
|
|
85
116
|
console.log(`🌐 Making API call through proxy to: ${url}`);
|
|
86
117
|
console.log(`📤 Request options:`, {
|
|
@@ -89,7 +120,24 @@ async function makeApiCall(endpoint: string, options: RequestInit) {
|
|
|
89
120
|
body: options.body ? JSON.parse(options.body as string) : undefined,
|
|
90
121
|
});
|
|
91
122
|
|
|
92
|
-
|
|
123
|
+
// Do not call if no endpoint (no provider configured)
|
|
124
|
+
if (!endpoint) {
|
|
125
|
+
throw new Error('AI provider is not configured. Please add your API key in Model Settings.');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Inject API key headers from user config if available
|
|
129
|
+
const headers = new Headers(options.headers || {});
|
|
130
|
+
if (API_CONFIG.userApiKey) {
|
|
131
|
+
if (API_CONFIG.availableProvider === 'anthropic') {
|
|
132
|
+
headers.set('x-api-key', API_CONFIG.userApiKey);
|
|
133
|
+
headers.set('anthropic-version', '2023-06-01');
|
|
134
|
+
headers.set('anthropic-dangerous-direct-browser-access', 'true');
|
|
135
|
+
} else if (API_CONFIG.availableProvider === 'openai') {
|
|
136
|
+
headers.set('Authorization', `Bearer ${API_CONFIG.userApiKey}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const response = await fetch(url, { ...options, headers });
|
|
93
141
|
|
|
94
142
|
if (!response.ok) {
|
|
95
143
|
const errorData = await response.json().catch(() => ({}));
|
|
@@ -846,7 +894,7 @@ export const aiAgentMachine = createMachine(
|
|
|
846
894
|
}
|
|
847
895
|
|
|
848
896
|
if (errorMessage.includes('API key')) {
|
|
849
|
-
errorMessage = 'API key not configured. Please
|
|
897
|
+
errorMessage = 'API key not configured. Please add your API key in Model Settings.';
|
|
850
898
|
} else if (errorMessage.includes('rate limit')) {
|
|
851
899
|
errorMessage = 'Rate limit exceeded. Please try again in a moment.';
|
|
852
900
|
} else if (errorMessage.includes('network') || errorMessage.includes('fetch')) {
|