refactor/channel & ipc (#349)
Co-authored-by: paisley <8197966+su8su@users.noreply.github.com> Co-authored-by: zuolingxuan <zuolingxuan@bytedance.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
8b45960662
commit
e28eba01e1
@@ -50,6 +50,7 @@ import {
|
||||
} from '../services/providers/provider-runtime-sync';
|
||||
import { validateApiKeyWithProvider } from '../services/providers/provider-validation';
|
||||
import { appUpdater } from './updater';
|
||||
import { PORTS } from '../utils/config';
|
||||
|
||||
type AppRequest = {
|
||||
id?: string;
|
||||
@@ -79,6 +80,7 @@ export function registerIpcHandlers(
|
||||
): void {
|
||||
// Unified request protocol (non-breaking: legacy channels remain available)
|
||||
registerUnifiedRequestHandlers(gatewayManager);
|
||||
registerHostApiProxyHandlers();
|
||||
|
||||
// Gateway handlers
|
||||
registerGatewayHandlers(gatewayManager, mainWindow);
|
||||
@@ -135,6 +137,68 @@ export function registerIpcHandlers(
|
||||
registerFileHandlers();
|
||||
}
|
||||
|
||||
type HostApiFetchRequest = {
|
||||
path: string;
|
||||
method?: string;
|
||||
headers?: Record<string, string>;
|
||||
body?: unknown;
|
||||
};
|
||||
|
||||
function registerHostApiProxyHandlers(): void {
|
||||
ipcMain.handle('hostapi:fetch', async (_, request: HostApiFetchRequest) => {
|
||||
try {
|
||||
const path = typeof request?.path === 'string' ? request.path : '';
|
||||
if (!path || !path.startsWith('/')) {
|
||||
throw new Error(`Invalid host API path: ${String(request?.path)}`);
|
||||
}
|
||||
|
||||
const method = (request.method || 'GET').toUpperCase();
|
||||
const headers: Record<string, string> = { ...(request.headers || {}) };
|
||||
let body: BodyInit | undefined;
|
||||
|
||||
if (request.body !== undefined && request.body !== null) {
|
||||
if (typeof request.body === 'string') {
|
||||
body = request.body;
|
||||
} else {
|
||||
body = JSON.stringify(request.body);
|
||||
if (!headers['Content-Type'] && !headers['content-type']) {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetch(`http://127.0.0.1:${PORTS.CLAWX_HOST_API}${path}`, {
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
|
||||
const data: { status: number; ok: boolean; json?: unknown; text?: string } = {
|
||||
status: response.status,
|
||||
ok: response.ok,
|
||||
};
|
||||
|
||||
if (response.status !== 204) {
|
||||
const contentType = response.headers.get('content-type') || '';
|
||||
if (contentType.includes('application/json')) {
|
||||
data.json = await response.json().catch(() => undefined);
|
||||
} else {
|
||||
data.text = await response.text().catch(() => '');
|
||||
}
|
||||
}
|
||||
|
||||
return { ok: true, data };
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false,
|
||||
error: {
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function mapAppErrorCode(error: unknown): AppResponse['error']['code'] {
|
||||
const msg = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
||||
if (msg.includes('timeout')) return 'TIMEOUT';
|
||||
@@ -156,6 +220,7 @@ function isProxyKey(key: keyof AppSettings): boolean {
|
||||
}
|
||||
|
||||
function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
const providerService = getProviderService();
|
||||
const handleProxySettingsChange = async () => {
|
||||
const settings = await getAllSettings();
|
||||
await applyProxySettings(settings);
|
||||
@@ -194,32 +259,32 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
}
|
||||
case 'provider': {
|
||||
if (request.action === 'list') {
|
||||
data = await getAllProvidersWithKeyInfo();
|
||||
data = await providerService.listLegacyProvidersWithKeyInfo();
|
||||
break;
|
||||
}
|
||||
if (request.action === 'get') {
|
||||
const payload = request.payload as { providerId?: string } | string | undefined;
|
||||
const providerId = typeof payload === 'string' ? payload : payload?.providerId;
|
||||
if (!providerId) throw new Error('Invalid provider.get payload');
|
||||
data = await getProvider(providerId);
|
||||
data = await providerService.getLegacyProvider(providerId);
|
||||
break;
|
||||
}
|
||||
if (request.action === 'getDefault') {
|
||||
data = await getDefaultProvider();
|
||||
data = await providerService.getDefaultLegacyProvider();
|
||||
break;
|
||||
}
|
||||
if (request.action === 'hasApiKey') {
|
||||
const payload = request.payload as { providerId?: string } | string | undefined;
|
||||
const providerId = typeof payload === 'string' ? payload : payload?.providerId;
|
||||
if (!providerId) throw new Error('Invalid provider.hasApiKey payload');
|
||||
data = await hasApiKey(providerId);
|
||||
data = await providerService.hasLegacyProviderApiKey(providerId);
|
||||
break;
|
||||
}
|
||||
if (request.action === 'getApiKey') {
|
||||
const payload = request.payload as { providerId?: string } | string | undefined;
|
||||
const providerId = typeof payload === 'string' ? payload : payload?.providerId;
|
||||
if (!providerId) throw new Error('Invalid provider.getApiKey payload');
|
||||
data = await getApiKey(providerId);
|
||||
data = await providerService.getLegacyProviderApiKey(providerId);
|
||||
break;
|
||||
}
|
||||
if (request.action === 'validateKey') {
|
||||
@@ -234,7 +299,7 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
throw new Error('Invalid provider.validateKey payload');
|
||||
}
|
||||
|
||||
const provider = await getProvider(providerId);
|
||||
const provider = await providerService.getLegacyProvider(providerId);
|
||||
const providerType = provider?.type || providerId;
|
||||
const registryBaseUrl = getProviderConfig(providerType)?.baseUrl;
|
||||
const resolvedBaseUrl = options?.baseUrl || provider?.baseUrl || registryBaseUrl;
|
||||
@@ -251,12 +316,12 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
if (!config) throw new Error('Invalid provider.save payload');
|
||||
|
||||
try {
|
||||
await saveProvider(config);
|
||||
await providerService.saveLegacyProvider(config);
|
||||
|
||||
if (apiKey !== undefined) {
|
||||
const trimmedKey = apiKey.trim();
|
||||
if (trimmedKey) {
|
||||
await storeApiKey(config.id, trimmedKey);
|
||||
await providerService.setLegacyProviderApiKey(config.id, trimmedKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,8 +343,8 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
if (!providerId) throw new Error('Invalid provider.delete payload');
|
||||
|
||||
try {
|
||||
const existing = await getProvider(providerId);
|
||||
await deleteProvider(providerId);
|
||||
const existing = await providerService.getLegacyProvider(providerId);
|
||||
await providerService.deleteLegacyProvider(providerId);
|
||||
if (existing?.type) {
|
||||
try {
|
||||
await syncDeletedProviderToRuntime(existing, providerId, gatewayManager);
|
||||
@@ -303,8 +368,8 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
if (!providerId || typeof apiKey !== 'string') throw new Error('Invalid provider.setApiKey payload');
|
||||
|
||||
try {
|
||||
await storeApiKey(providerId, apiKey);
|
||||
const provider = await getProvider(providerId);
|
||||
await providerService.setLegacyProviderApiKey(providerId, apiKey);
|
||||
const provider = await providerService.getLegacyProvider(providerId);
|
||||
const providerType = provider?.type || providerId;
|
||||
const ock = getOpenClawProviderKey(providerType, providerId);
|
||||
try {
|
||||
@@ -328,13 +393,13 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
const apiKey = Array.isArray(payload) ? payload[2] : payload?.apiKey;
|
||||
if (!providerId || !updates) throw new Error('Invalid provider.updateWithKey payload');
|
||||
|
||||
const existing = await getProvider(providerId);
|
||||
const existing = await providerService.getLegacyProvider(providerId);
|
||||
if (!existing) {
|
||||
data = { success: false, error: 'Provider not found' };
|
||||
break;
|
||||
}
|
||||
|
||||
const previousKey = await getApiKey(providerId);
|
||||
const previousKey = await providerService.getLegacyProviderApiKey(providerId);
|
||||
const previousOck = getOpenClawProviderKey(existing.type, providerId);
|
||||
|
||||
try {
|
||||
@@ -344,15 +409,15 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
const ock = getOpenClawProviderKey(nextConfig.type, providerId);
|
||||
await saveProvider(nextConfig);
|
||||
await providerService.saveLegacyProvider(nextConfig);
|
||||
|
||||
if (apiKey !== undefined) {
|
||||
const trimmedKey = apiKey.trim();
|
||||
if (trimmedKey) {
|
||||
await storeApiKey(providerId, trimmedKey);
|
||||
await providerService.setLegacyProviderApiKey(providerId, trimmedKey);
|
||||
await saveProviderKeyToOpenClaw(ock, trimmedKey);
|
||||
} else {
|
||||
await deleteApiKey(providerId);
|
||||
await providerService.deleteLegacyProviderApiKey(providerId);
|
||||
await removeProviderFromOpenClaw(ock);
|
||||
}
|
||||
}
|
||||
@@ -366,12 +431,12 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
data = { success: true };
|
||||
} catch (error) {
|
||||
try {
|
||||
await saveProvider(existing);
|
||||
await providerService.saveLegacyProvider(existing);
|
||||
if (previousKey) {
|
||||
await storeApiKey(providerId, previousKey);
|
||||
await providerService.setLegacyProviderApiKey(providerId, previousKey);
|
||||
await saveProviderKeyToOpenClaw(previousOck, previousKey);
|
||||
} else {
|
||||
await deleteApiKey(providerId);
|
||||
await providerService.deleteLegacyProviderApiKey(providerId);
|
||||
await removeProviderFromOpenClaw(previousOck);
|
||||
}
|
||||
} catch (rollbackError) {
|
||||
@@ -387,8 +452,8 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
const providerId = typeof payload === 'string' ? payload : payload?.providerId;
|
||||
if (!providerId) throw new Error('Invalid provider.deleteApiKey payload');
|
||||
try {
|
||||
await deleteApiKey(providerId);
|
||||
const provider = await getProvider(providerId);
|
||||
await providerService.deleteLegacyProviderApiKey(providerId);
|
||||
const provider = await providerService.getLegacyProvider(providerId);
|
||||
const providerType = provider?.type || providerId;
|
||||
const ock = getOpenClawProviderKey(providerType, providerId);
|
||||
try {
|
||||
@@ -410,8 +475,8 @@ function registerUnifiedRequestHandlers(gatewayManager: GatewayManager): void {
|
||||
if (!providerId) throw new Error('Invalid provider.setDefault payload');
|
||||
|
||||
try {
|
||||
await setDefaultProvider(providerId);
|
||||
const provider = await getProvider(providerId);
|
||||
await providerService.setDefaultLegacyProvider(providerId);
|
||||
const provider = await providerService.getLegacyProvider(providerId);
|
||||
if (provider) {
|
||||
try {
|
||||
await syncDefaultProviderToRuntime(providerId, gatewayManager);
|
||||
@@ -2422,4 +2487,4 @@ function registerSessionHandlers(): void {
|
||||
return { success: false, error: String(err) };
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
48
electron/main/provider-model-sync.ts
Normal file
48
electron/main/provider-model-sync.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { getProviderConfig } from '../utils/provider-registry';
|
||||
import { getOpenClawProviderKeyForType, isOAuthProviderType } from '../utils/provider-keys';
|
||||
import type { ProviderConfig } from '../utils/secure-storage';
|
||||
|
||||
export interface AgentProviderUpdatePayload {
|
||||
providerKey: string;
|
||||
entry: {
|
||||
baseUrl: string;
|
||||
api: string;
|
||||
apiKey: string | undefined;
|
||||
models: Array<{ id: string; name: string }>;
|
||||
};
|
||||
}
|
||||
|
||||
export function getModelIdFromRef(modelRef: string | undefined, providerKey: string): string | undefined {
|
||||
if (!modelRef) return undefined;
|
||||
if (modelRef.startsWith(`${providerKey}/`)) {
|
||||
return modelRef.slice(providerKey.length + 1);
|
||||
}
|
||||
return modelRef;
|
||||
}
|
||||
|
||||
export function buildNonOAuthAgentProviderUpdate(
|
||||
provider: ProviderConfig,
|
||||
providerId: string,
|
||||
modelRef: string | undefined
|
||||
): AgentProviderUpdatePayload | null {
|
||||
if (provider.type === 'custom' || provider.type === 'ollama' || isOAuthProviderType(provider.type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const providerKey = getOpenClawProviderKeyForType(provider.type, providerId);
|
||||
const meta = getProviderConfig(provider.type);
|
||||
const baseUrl = provider.baseUrl || meta?.baseUrl;
|
||||
const api = meta?.api;
|
||||
if (!baseUrl || !api) return null;
|
||||
|
||||
const modelId = getModelIdFromRef(modelRef, providerKey);
|
||||
return {
|
||||
providerKey,
|
||||
entry: {
|
||||
baseUrl,
|
||||
api,
|
||||
apiKey: meta?.apiKeyEnv,
|
||||
models: modelId ? [{ id: modelId, name: modelId }] : [],
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user