Feat/upgrade openclaw (#729)
This commit is contained in:
committed by
GitHub
Unverified
parent
bf5b089158
commit
d34a88e629
@@ -20,7 +20,7 @@ export const providerIcons: Record<string, string> = {
|
||||
siliconflow,
|
||||
'minimax-portal': minimaxPortal,
|
||||
'minimax-portal-cn': minimaxPortal,
|
||||
'qwen-portal': qwenPortal,
|
||||
'modelstudio': qwenPortal,
|
||||
ollama,
|
||||
custom,
|
||||
};
|
||||
|
||||
@@ -1134,6 +1134,9 @@ function AddProviderDialog({
|
||||
};
|
||||
|
||||
const availableTypes = PROVIDER_TYPE_INFO.filter((type) => {
|
||||
// Skip providers that are temporarily hidden from the UI.
|
||||
if (type.hidden) return false;
|
||||
|
||||
// MiniMax portal variants are mutually exclusive — hide BOTH variants
|
||||
// when either one already exists (account may have vendorId of either variant).
|
||||
const hasMinimax = existingVendorIds.has('minimax-portal') || existingVendorIds.has('minimax-portal-cn');
|
||||
|
||||
@@ -16,7 +16,7 @@ export const PROVIDER_TYPES = [
|
||||
'siliconflow',
|
||||
'minimax-portal',
|
||||
'minimax-portal-cn',
|
||||
'qwen-portal',
|
||||
'modelstudio',
|
||||
'ollama',
|
||||
'custom',
|
||||
] as const;
|
||||
@@ -32,7 +32,7 @@ export const BUILTIN_PROVIDER_TYPES = [
|
||||
'siliconflow',
|
||||
'minimax-portal',
|
||||
'minimax-portal-cn',
|
||||
'qwen-portal',
|
||||
'modelstudio',
|
||||
'ollama',
|
||||
] as const;
|
||||
|
||||
@@ -79,6 +79,8 @@ export interface ProviderTypeInfo {
|
||||
codePlanPresetBaseUrl?: string;
|
||||
codePlanPresetModelId?: string;
|
||||
codePlanDocsUrl?: string;
|
||||
/** If true, this provider is not shown in the "Add Provider" dialog. */
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
export type ProviderAuthMode =
|
||||
@@ -172,7 +174,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [
|
||||
{ id: 'moonshot', name: 'Moonshot (CN)', icon: '🌙', placeholder: 'sk-...', model: 'Kimi', requiresApiKey: true, defaultBaseUrl: 'https://api.moonshot.cn/v1', defaultModelId: 'kimi-k2.5', docsUrl: 'https://platform.moonshot.cn/' },
|
||||
{ id: 'siliconflow', name: 'SiliconFlow (CN)', icon: '🌊', placeholder: 'sk-...', model: 'Multi-Model', requiresApiKey: true, defaultBaseUrl: 'https://api.siliconflow.cn/v1', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'deepseek-ai/DeepSeek-V3', defaultModelId: 'deepseek-ai/DeepSeek-V3', docsUrl: 'https://docs.siliconflow.cn/cn/userguide/introduction' },
|
||||
{ id: 'minimax-portal', name: 'MiniMax (Global)', icon: '☁️', placeholder: 'sk-...', model: 'MiniMax', requiresApiKey: false, isOAuth: true, supportsApiKey: true, defaultModelId: 'MiniMax-M2.7', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'MiniMax-M2.7', apiKeyUrl: 'https://platform.minimax.io' },
|
||||
{ id: 'qwen-portal', name: 'Qwen (Global)', icon: '☁️', placeholder: 'sk-...', model: 'Qwen', requiresApiKey: false, isOAuth: true, defaultModelId: 'coder-model', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'coder-model' },
|
||||
{ id: 'modelstudio', name: 'Model Studio', icon: '☁️', placeholder: 'sk-...', model: 'Qwen', requiresApiKey: true, defaultBaseUrl: 'https://coding.dashscope.aliyuncs.com/v1', showBaseUrl: true, defaultModelId: 'qwen3.5-plus', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'qwen3.5-plus', apiKeyUrl: 'https://bailian.console.aliyun.com/', hidden: true },
|
||||
{ id: 'ark', name: 'ByteDance Ark', icon: 'A', placeholder: 'your-ark-api-key', model: 'Doubao', requiresApiKey: true, defaultBaseUrl: 'https://ark.cn-beijing.volces.com/api/v3', showBaseUrl: true, showModelId: true, modelIdPlaceholder: 'ep-20260228000000-xxxxx', docsUrl: 'https://www.volcengine.com/', codePlanPresetBaseUrl: 'https://ark.cn-beijing.volces.com/api/coding/v3', codePlanPresetModelId: 'ark-code-latest', codePlanDocsUrl: 'https://www.volcengine.com/docs/82379/1928261?lang=zh' },
|
||||
{ id: 'ollama', name: 'Ollama', icon: '🦙', placeholder: 'Not required', requiresApiKey: false, defaultBaseUrl: 'http://localhost:11434/v1', showBaseUrl: true, showModelId: true, modelIdPlaceholder: 'qwen3:latest' },
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ import type { GatewayStatus } from '../types/gateway';
|
||||
|
||||
let gatewayInitPromise: Promise<void> | null = null;
|
||||
let gatewayEventUnsubscribers: Array<() => void> | null = null;
|
||||
let gatewayReconcileTimer: ReturnType<typeof setInterval> | null = null;
|
||||
const gatewayEventDedupe = new Map<string, number>();
|
||||
const GATEWAY_EVENT_DEDUPE_TTL_MS = 30_000;
|
||||
const LOAD_SESSIONS_MIN_INTERVAL_MS = 1_200;
|
||||
@@ -283,6 +284,45 @@ export const useGatewayStore = create<GatewayState>((set, get) => ({
|
||||
},
|
||||
));
|
||||
gatewayEventUnsubscribers = unsubscribers;
|
||||
|
||||
// Periodic reconciliation safety net: every 30 seconds, check if the
|
||||
// renderer's view of gateway state has drifted from main process truth.
|
||||
// This catches any future one-off IPC delivery failures without adding
|
||||
// a constant polling load (single lightweight IPC invoke per interval).
|
||||
// Clear any previous timer first to avoid leaks during HMR reloads.
|
||||
if (gatewayReconcileTimer !== null) {
|
||||
clearInterval(gatewayReconcileTimer);
|
||||
}
|
||||
gatewayReconcileTimer = setInterval(() => {
|
||||
const ipc = window.electron?.ipcRenderer;
|
||||
if (!ipc) return;
|
||||
ipc.invoke('gateway:status')
|
||||
.then((result: unknown) => {
|
||||
const latest = result as GatewayStatus;
|
||||
const current = get().status;
|
||||
if (latest.state !== current.state) {
|
||||
console.info(
|
||||
`[gateway-store] reconciled stale state: ${current.state} → ${latest.state}`,
|
||||
);
|
||||
set({ status: latest });
|
||||
}
|
||||
})
|
||||
.catch(() => { /* ignore */ });
|
||||
}, 30_000);
|
||||
}
|
||||
|
||||
// Re-fetch status after IPC listeners are registered to close the race
|
||||
// window: if the gateway transitioned (e.g. starting → running) between
|
||||
// the initial fetch and the IPC listener setup, that event was lost.
|
||||
// A second fetch guarantees we pick up the latest state.
|
||||
try {
|
||||
const refreshed = await hostApiFetch<GatewayStatus>('/api/gateway/status');
|
||||
const current = get().status;
|
||||
if (refreshed.state !== current.state) {
|
||||
set({ status: refreshed });
|
||||
}
|
||||
} catch {
|
||||
// Best-effort; the IPC listener will eventually reconcile.
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize Gateway:', error);
|
||||
|
||||
Reference in New Issue
Block a user