feat(provider): mainly support moonshot / siliconflow on setup (#43)
This commit is contained in:
committed by
GitHub
Unverified
parent
563fcd2f24
commit
1b508d5bde
@@ -283,6 +283,8 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
set({ error: result.error || 'Failed to send message', sending: false });
|
||||
} else if (result.result?.runId) {
|
||||
set({ activeRunId: result.result.runId });
|
||||
} else {
|
||||
// No runId from gateway; keep sending state and wait for events.
|
||||
}
|
||||
} catch (err) {
|
||||
set({ error: String(err), sending: false });
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
import { create } from 'zustand';
|
||||
import type { GatewayStatus } from '../types/gateway';
|
||||
|
||||
let gatewayInitPromise: Promise<void> | null = null;
|
||||
|
||||
interface GatewayHealth {
|
||||
ok: boolean;
|
||||
error?: string;
|
||||
@@ -39,47 +41,79 @@ export const useGatewayStore = create<GatewayState>((set, get) => ({
|
||||
|
||||
init: async () => {
|
||||
if (get().isInitialized) return;
|
||||
|
||||
try {
|
||||
// Get initial status
|
||||
const status = await window.electron.ipcRenderer.invoke('gateway:status') as GatewayStatus;
|
||||
set({ status, isInitialized: true });
|
||||
|
||||
// Listen for status changes
|
||||
window.electron.ipcRenderer.on('gateway:status-changed', (newStatus) => {
|
||||
set({ status: newStatus as GatewayStatus });
|
||||
});
|
||||
|
||||
// Listen for errors
|
||||
window.electron.ipcRenderer.on('gateway:error', (error) => {
|
||||
set({ lastError: String(error) });
|
||||
});
|
||||
|
||||
// Listen for notifications
|
||||
window.electron.ipcRenderer.on('gateway:notification', (notification) => {
|
||||
console.log('Gateway notification:', notification);
|
||||
});
|
||||
|
||||
// Listen for chat events from the gateway and forward to chat store
|
||||
window.electron.ipcRenderer.on('gateway:chat-message', (data) => {
|
||||
try {
|
||||
// Dynamic import to avoid circular dependency
|
||||
import('./chat').then(({ useChatStore }) => {
|
||||
const chatData = data as { message?: Record<string, unknown> } | Record<string, unknown>;
|
||||
const event = ('message' in chatData && typeof chatData.message === 'object')
|
||||
? chatData.message as Record<string, unknown>
|
||||
: chatData as Record<string, unknown>;
|
||||
useChatStore.getState().handleChatEvent(event);
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn('Failed to forward chat event:', err);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize Gateway:', error);
|
||||
set({ lastError: String(error) });
|
||||
if (gatewayInitPromise) {
|
||||
await gatewayInitPromise;
|
||||
return;
|
||||
}
|
||||
|
||||
gatewayInitPromise = (async () => {
|
||||
try {
|
||||
// Get initial status first
|
||||
const status = await window.electron.ipcRenderer.invoke('gateway:status') as GatewayStatus;
|
||||
set({ status, isInitialized: true });
|
||||
|
||||
// Listen for status changes
|
||||
window.electron.ipcRenderer.on('gateway:status-changed', (newStatus) => {
|
||||
set({ status: newStatus as GatewayStatus });
|
||||
});
|
||||
|
||||
// Listen for errors
|
||||
window.electron.ipcRenderer.on('gateway:error', (error) => {
|
||||
set({ lastError: String(error) });
|
||||
});
|
||||
|
||||
// Some Gateway builds stream chat events via generic "agent" notifications.
|
||||
// Normalize and forward them to the chat store.
|
||||
window.electron.ipcRenderer.on('gateway:notification', (notification) => {
|
||||
const payload = notification as { method?: string; params?: Record<string, unknown> } | undefined;
|
||||
if (!payload || payload.method !== 'agent' || !payload.params || typeof payload.params !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
const p = payload.params;
|
||||
const data = (p.data && typeof p.data === 'object') ? (p.data as Record<string, unknown>) : {};
|
||||
const normalizedEvent: Record<string, unknown> = {
|
||||
...data,
|
||||
runId: p.runId ?? data.runId,
|
||||
sessionKey: p.sessionKey ?? data.sessionKey,
|
||||
stream: p.stream ?? data.stream,
|
||||
seq: p.seq ?? data.seq,
|
||||
};
|
||||
|
||||
import('./chat')
|
||||
.then(({ useChatStore }) => {
|
||||
useChatStore.getState().handleChatEvent(normalizedEvent);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn('Failed to forward gateway notification event:', err);
|
||||
});
|
||||
});
|
||||
|
||||
// Listen for chat events from the gateway and forward to chat store
|
||||
window.electron.ipcRenderer.on('gateway:chat-message', (data) => {
|
||||
try {
|
||||
// Dynamic import to avoid circular dependency
|
||||
import('./chat').then(({ useChatStore }) => {
|
||||
const chatData = data as { message?: Record<string, unknown> } | Record<string, unknown>;
|
||||
const event = ('message' in chatData && typeof chatData.message === 'object')
|
||||
? chatData.message as Record<string, unknown>
|
||||
: chatData as Record<string, unknown>;
|
||||
useChatStore.getState().handleChatEvent(event);
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn('Failed to forward chat event:', err);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize Gateway:', error);
|
||||
set({ lastError: String(error) });
|
||||
} finally {
|
||||
gatewayInitPromise = null;
|
||||
}
|
||||
})();
|
||||
|
||||
await gatewayInitPromise;
|
||||
},
|
||||
|
||||
start: async () => {
|
||||
|
||||
@@ -3,28 +3,10 @@
|
||||
* Manages AI provider configurations
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import type { ProviderConfig, ProviderWithKeyInfo } from '@/lib/providers';
|
||||
|
||||
/**
|
||||
* Provider configuration
|
||||
*/
|
||||
export interface ProviderConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
type: 'anthropic' | 'openai' | 'google' | 'openrouter' | 'ollama' | 'custom';
|
||||
baseUrl?: string;
|
||||
model?: string;
|
||||
enabled: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider with key info (for display)
|
||||
*/
|
||||
export interface ProviderWithKeyInfo extends ProviderConfig {
|
||||
hasKey: boolean;
|
||||
keyMasked: string | null;
|
||||
}
|
||||
// Re-export types for consumers that imported from here
|
||||
export type { ProviderConfig, ProviderWithKeyInfo } from '@/lib/providers';
|
||||
|
||||
interface ProviderState {
|
||||
providers: ProviderWithKeyInfo[];
|
||||
@@ -38,6 +20,11 @@ interface ProviderState {
|
||||
updateProvider: (providerId: string, updates: Partial<ProviderConfig>, apiKey?: string) => Promise<void>;
|
||||
deleteProvider: (providerId: string) => Promise<void>;
|
||||
setApiKey: (providerId: string, apiKey: string) => Promise<void>;
|
||||
updateProviderWithKey: (
|
||||
providerId: string,
|
||||
updates: Partial<ProviderConfig>,
|
||||
apiKey?: string
|
||||
) => Promise<void>;
|
||||
deleteApiKey: (providerId: string) => Promise<void>;
|
||||
setDefaultProvider: (providerId: string) => Promise<void>;
|
||||
validateApiKey: (providerId: string, apiKey: string) => Promise<{ valid: boolean; error?: string }>;
|
||||
@@ -95,9 +82,11 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
if (!existing) {
|
||||
throw new Error('Provider not found');
|
||||
}
|
||||
|
||||
const { hasKey: _hasKey, keyMasked: _keyMasked, ...providerConfig } = existing;
|
||||
|
||||
const updatedConfig: ProviderConfig = {
|
||||
...existing,
|
||||
...providerConfig,
|
||||
...updates,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
@@ -147,6 +136,26 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
updateProviderWithKey: async (providerId, updates, apiKey) => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
'provider:updateWithKey',
|
||||
providerId,
|
||||
updates,
|
||||
apiKey
|
||||
) as { success: boolean; error?: string };
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Failed to update provider');
|
||||
}
|
||||
|
||||
await get().fetchProviders();
|
||||
} catch (error) {
|
||||
console.error('Failed to update provider with key:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
deleteApiKey: async (providerId) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user